def add_top_bar_widgets(self, hbox): #use an event box so we can style it: b = gtk.HBox() eb = gtk.EventBox() eb.add(b) eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(red=0, green=0, blue=0)) white = gtk.gdk.Color(red=60000, green=63000, blue=65000) hbox.pack_start(eb, expand=True, fill=True) for i, l in { "encoding.png": "Encoding", "speed.png": "Speed", "information.png": "Information", "keyboard.png": "Keyboard", "clipboard.png": "Clipboard" }.items(): icon = self._client.get_pixbuf(i) def clicked(*args): self.info("clicked(%s)", args) button = imagebutton(l, icon, clicked_callback=clicked, label_color=white) button.set_relief(gtk.RELIEF_NONE) b.add(button) icon = self._client.get_pixbuf("xpra.png") submenu = gtk.Menu() for l, a, s, r in ( ("Check Option 1", True, True, False), ("Disabled Option", True, False, False), ("Radio 1", True, True, True), ("Radio 2", False, True, True), ): item = CheckMenuItem(l) def item_changed(item): self.info("item_changed(%s)", item) item.set_active(a) item.set_sensitive(s) item.set_draw_as_radio(r) item.connect("toggled", item_changed) submenu.append(item) submenu.show_all() def show_menu(btn, *args): self.info("show_menu(%s, %s)", btn, args) submenu.popup(None, None, None, 1, 0) menu_button = imagebutton("Xpra", icon, clicked_callback=show_menu, label_color=white) menu_button.set_relief(gtk.RELIEF_NONE) menu_button.show_all() b.add(menu_button)
def make_connect_widgets(self, recs, address, port, display): icon = self.get_pixbuf("connect.png") if len(recs) == 1: #single record, single uri: uri = self.get_uri(None, *recs[0]) def clicked(*_args): password = self.password_entry.get_text() uri = self.get_uri(password, *recs[0]) self.attach(uri) btn = imagebutton("Connect", icon, clicked_callback=clicked) return gtk.Label(uri), btn #multiple modes / uris uri_menu = gtk.combo_box_new_text() d = {} #sort by protocol so TCP comes first order = {"socket": 0, "ssl": 2, "tcp": 4, "ssh": 6} if WIN32: #on MS Windows, prefer ssh which has a GUI for accepting keys #and entering the password: order["ssh"] = 0 def cmp_key(v): text = v[-1] #the text record mode = (text or {}).get("mode", "") host = v[6] host_len = len(host) #log("cmp_key(%s) text=%s, mode=%s, host=%s, host_len=%s", v, text, mode, host, host_len) #prefer order (from mode), then shorter host string: return "%s-%s" % (order.get(mode, mode), host_len) srecs = sorted(recs, key=cmp_key) for rec in srecs: uri = self.get_uri(None, *rec) uri_menu.append_text(uri) d[uri] = rec def connect(*_args): uri = uri_menu.get_active_text() rec = d[uri] password = self.password_entry.get_text() uri = self.get_uri(password, *rec) self.attach(uri) uri_menu.set_active(0) btn = imagebutton("Connect", icon, clicked_callback=connect) #btn = gtk.Button(">") #btn.connect("clicked", connect) return uri_menu, btn
def image_button(self, label="", tooltip="", icon_pixbuf=None, clicked_cb=None): icon = Gtk.Image() icon.set_from_pixbuf(icon_pixbuf) return imagebutton(label, icon, tooltip, clicked_cb, icon_size=None)
def add_tab(self, icon_filename, title, populate_cb, contents): icon = self.get_pixbuf(icon_filename) def show_tab(*args): self.show_tab(contents) button = imagebutton(title, icon, clicked_callback=show_tab) button.connect("clicked", show_tab) button.set_relief(RELIEF_NONE) self.tab_button_box.add(button) self.tabs.append((title, button, contents, populate_cb))
def btn(label, tooltip, callback, default=False): btn = imagebutton(label, tooltip=tooltip, clicked_callback=callback, icon_size=32, default=default, label_font=Pango.FontDescription("sans 16")) hbox.pack_start(btn) return btn
def link_btn(link, label=None, icon_name="question.png"): def open_link(): import webbrowser webbrowser.open(link) def help_clicked(*args): log("help_clicked%s opening '%s'", args, link) start_thread(open_link, "open-link", True) icon = get_icon_pixbuf(icon_name) btn = imagebutton("" if icon else label, icon, label, help_clicked, 12, False) return btn
def add_top_bar_widgets(self, hbox): #use an event box so we can style it: b = gtk.HBox() eb = gtk.EventBox() eb.add(b) eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(red=0, green=0, blue=0)) white = gtk.gdk.Color(red=60000, green=63000, blue=65000) hbox.pack_start(eb, expand=True, fill=True) for i,l in {"encoding.png" : "Encoding", "speed.png" : "Speed", "information.png" : "Information", "keyboard.png" : "Keyboard", "clipboard.png" : "Clipboard"}.items(): icon = self._client.get_pixbuf(i) def clicked(*args): self.info("clicked(%s)", args) button = imagebutton(l, icon, clicked_callback=clicked, label_color=white) button.set_relief(gtk.RELIEF_NONE) b.add(button) icon = self._client.get_pixbuf("xpra.png") submenu = gtk.Menu() for l, a, s, r in ( ("Check Option 1", True, True, False), ("Disabled Option", True, False, False), ("Radio 1", True, True, True), ("Radio 2", False, True, True), ): item = CheckMenuItem(l) def item_changed(item): self.info("item_changed(%s)", item) item.set_active(a) item.set_sensitive(s) item.set_draw_as_radio(r) item.connect("toggled", item_changed) submenu.append(item) submenu.show_all() def show_menu(btn, *args): self.info("show_menu(%s, %s)", btn, args) submenu.popup(None, None, None, 1, 0) menu_button = imagebutton("Xpra", icon, clicked_callback=show_menu, label_color=white) menu_button.set_relief(gtk.RELIEF_NONE) menu_button.show_all() b.add(menu_button)
def button(self, label_str, tooltip, relpath): def cb(_btn): cp = os.path.dirname(__file__) script = os.path.join(cp, relpath) if WIN32 and os.path.sep=="/": script = script.replace("/", "\\") if not os.path.exists(script): if os.path.exists(script+"c"): script += "c" else: log.warn("Warning: cannot find '%s'", os.path.basename(relpath)) return cmd = get_python_execfile_command()+[script] exec_command(cmd) return imagebutton(label_str, None, tooltip, clicked_callback=cb, icon_size=48)
def __init__(self, title="Xpra"): self.exit_code = 0 self.start_session = None gtk.Window.__init__(self) self.set_title(title) self.set_border_width(10) self.set_resizable(True) self.set_decorated(True) self.set_position(WIN_POS_CENTER) icon = get_pixbuf("xpra") if icon: self.set_icon(icon) add_close_accel(self, self.quit) add_window_accel(self, 'F1', self.show_about) self.connect("delete_event", self.quit) self.vbox = gtk.VBox(False, 10) self.add(self.vbox) #with most window managers, #the window's title bar already shows "Xpra" #title_label = gtk.Label(title) #title_label.modify_font(pango.FontDescription("sans 14")) #self.vbox.add(title_label) self.widgets = [] label_font = pango.FontDescription("sans 16") if has_client: icon = get_pixbuf("browse.png") self.browse_button = imagebutton( "Browse", icon, "Browse and connect to local sessions", clicked_callback=self.browse, icon_size=48, label_font=label_font) self.widgets.append(self.browse_button) icon = get_pixbuf("connect.png") self.connect_button = imagebutton( "Connect", icon, "Connect to a session", clicked_callback=self.show_launcher, icon_size=48, label_font=label_font) self.widgets.append(self.connect_button) if has_server: icon = get_pixbuf("server-connected.png") self.shadow_button = imagebutton( "Shadow", icon, "Start a shadow server", clicked_callback=self.start_shadow, icon_size=48, label_font=label_font) if not has_shadow: set_tooltip_text( self.shadow_button, "This build of Xpra does not support starting sessions") self.shadow_button.set_sensitive(False) self.widgets.append(self.shadow_button) icon = get_pixbuf("windows.png") self.start_button = imagebutton("Start", icon, "Start a session", clicked_callback=self.start, icon_size=48, label_font=label_font) #not all builds and platforms can start sessions: if OSX or WIN32: set_tooltip_text( self.start_button, "Starting sessions is not supported on %s" % platform_name(sys.platform)) self.start_button.set_sensitive(False) elif not has_server: set_tooltip_text( self.start_button, "This build of Xpra does not support starting sessions") self.start_button.set_sensitive(False) self.widgets.append(self.start_button) assert len(self.widgets) % 2 == 0 table = gtk.Table(len(self.widgets) // 2, 2, True) for i, widget in enumerate(self.widgets): table.attach(widget, i % 2, i % 2 + 1, i // 2, i // 2 + 1, xpadding=10, ypadding=10) self.vbox.add(table) self.vbox.show_all() self.set_size_request(640, 100 + 100 * len(self.widgets) // 2) def focus_in(window, event): log("focus_in(%s, %s)", window, event) def focus_out(window, event): log("focus_out(%s, %s)", window, event) self.reset_cursors() self.connect("focus-in-event", focus_in) self.connect("focus-out-event", focus_out)
def make_connect_widgets(self, key, recs, address, port, display): d = {} proc = self.clients.get(key) if proc and proc.poll() is None: icon = self.get_pixbuf("disconnected.png") def disconnect_client(btn): log("disconnect_client(%s) proc=%s", btn, proc) self.clients_disconnecting.add(key) proc.terminate() self.populate() btn = imagebutton("Disconnect", icon, clicked_callback=disconnect_client) return gtk.Label("Already connected with pid=%i" % proc.pid), btn, gtk.Label("") icon = self.get_pixbuf("browser.png") bopen = imagebutton("Open", icon) icon = self.get_pixbuf("connect.png") if len(recs)==1: #single record, single uri: rec = recs[0] uri = self.get_uri(None, *rec) bopen.set_sensitive(uri.startswith("ws")) def browser_open(*_args): self.browser_open(rec) bopen.connect("clicked", browser_open) d[uri] = rec def clicked(*_args): password = self.password_entry.get_text() uri = self.get_uri(password, *rec) self.attach(key, uri) btn = imagebutton("Connect", icon, clicked_callback=clicked) return gtk.Label(uri), btn, bopen #multiple modes / uris uri_menu = gtk.combo_box_new_text() uri_menu.set_size_request(340, 48) #sort by protocol so TCP comes first order = {"socket" : 0, "ssl" :2, "wss" : 3, "tcp" : 4, "ssh" : 6, "ws" : 8} if WIN32: #on MS Windows, prefer ssh which has a GUI for accepting keys #and entering the password: order["ssh"] = 0 def cmp_key(v): text = v[-1] #the text record mode = (text or {}).get("mode", "") host = v[6] host_len = len(host) #log("cmp_key(%s) text=%s, mode=%s, host=%s, host_len=%s", v, text, mode, host, host_len) #prefer order (from mode), then shorter host string: return "%s-%s" % (order.get(mode, mode), host_len) srecs = sorted(recs, key=cmp_key) for rec in srecs: uri = self.get_uri(None, *rec) uri_menu.append_text(uri) d[uri] = rec def connect(*_args): uri = uri_menu.get_active_text() rec = d[uri] password = self.password_entry.get_text() uri = self.get_uri(password, *rec) self.attach(key, uri) uri_menu.set_active(0) btn = imagebutton("Connect", icon, clicked_callback=connect) def uri_changed(*_args): uri = uri_menu.get_active_text() bopen.set_sensitive(uri.startswith("ws")) uri_menu.connect("changed", uri_changed) uri_changed() def browser_open_option(*_args): uri = uri_menu.get_active_text() rec = d[uri] self.browser_open(rec) bopen.connect("clicked", browser_open_option) return uri_menu, btn, bopen
def __init__(self, options): self.set_options(options) self.exit_code = None self.options_window = None self.default_config = get_defaults() #log("default_config=%s", self.default_config) #log("options=%s (%s)", options, type(options)) super().__init__() self.set_border_width(20) self.set_title("Start Xpra Session") self.set_position(Gtk.WindowPosition.CENTER) self.set_size_request(640, 300) icon = get_icon_pixbuf("xpra.png") if icon: self.set_icon(icon) self.connect("delete-event", self.quit) add_close_accel(self, self.quit) vbox = Gtk.VBox(False, 0) vbox.set_spacing(10) # choose the session type: hbox = Gtk.HBox(True, 40) def rb(sibling=None, label="", cb=None, tooltip_text=None): btn = Gtk.RadioButton.new_with_label_from_widget(sibling, label) if cb: btn.connect("toggled", cb) if tooltip_text: btn.set_tooltip_text(tooltip_text) sf(btn, "sans 16") hbox.add(btn) return btn self.seamless_btn = rb(None, "Seamless Session", self.session_toggled, "Forward an application window(s) individually, seamlessly") self.desktop_btn = rb(self.seamless_btn, "Desktop Session", self.session_toggled, "Forward a full desktop environment, contained in a window") self.shadow_btn = rb(self.seamless_btn, "Shadow Session", self.session_toggled, "Forward an existing desktop session, shown in a window") vbox.pack_start(hbox, False) vbox.pack_start(Gtk.HSeparator(), True, False) options_box = Gtk.VBox(False, 10) vbox.pack_start(options_box, True, False, 20) # select host: host_box = Gtk.HBox(True, 20) options_box.pack_start(host_box, False) self.host_label = l("Host:") hbox = Gtk.HBox(True, 0) host_box.pack_start(self.host_label, True) host_box.pack_start(hbox, True, True) self.localhost_btn = rb(None, "Local System", self.host_toggled) self.remote_btn = rb(self.localhost_btn, "Remote") self.remote_btn.set_tooltip_text("Start sessions on a remote system") self.address_box = Gtk.HBox(False, 0) options_box.pack_start(xal(self.address_box), True, True) self.mode_combo = sf(Gtk.ComboBoxText()) self.address_box.pack_start(xal(self.mode_combo), False) for mode in ("SSH", "TCP", "SSL", "WS", "WSS"): self.mode_combo.append_text(mode) self.mode_combo.set_active(0) self.mode_combo.connect("changed", self.mode_changed) self.username_entry = sf(Gtk.Entry()) self.username_entry.set_width_chars(12) self.username_entry.set_placeholder_text("Username") self.username_entry.set_max_length(255) self.address_box.pack_start(xal(self.username_entry), False) self.address_box.pack_start(l("@"), False) self.host_entry = sf(Gtk.Entry()) self.host_entry.set_width_chars(24) self.host_entry.set_placeholder_text("Hostname or IP address") self.host_entry.set_max_length(255) self.address_box.pack_start(xal(self.host_entry), False) self.address_box.pack_start(Gtk.Label(":"), False) self.port_entry = sf(Gtk.Entry()) self.port_entry.set_text("22") self.port_entry.set_width_chars(5) self.port_entry.set_placeholder_text("Port") self.port_entry.set_max_length(5) self.address_box.pack_start(xal(self.port_entry, 0), False) self.display_box = Gtk.HBox(True, 20) options_box.pack_start(self.display_box, False, True, 20) self.display_label = l("Display:") self.display_entry = sf(Gtk.Entry()) self.display_entry.connect('changed', self.display_changed) self.display_entry.set_width_chars(10) self.display_entry.set_placeholder_text("optional") self.display_entry.set_max_length(10) self.display_entry.set_tooltip_text("To use a specific X11 display number") self.display_combo = sf(Gtk.ComboBoxText()) self.display_box.pack_start(self.display_label, True) self.display_box.pack_start(self.display_entry, True, False) self.display_box.pack_start(self.display_combo, True, False) # Label: self.entry_box = Gtk.HBox(True, 20) options_box.pack_start(self.entry_box, False, True, 20) self.entry_label = l("Command:") self.entry = sf(Gtk.Entry()) self.entry.set_max_length(255) self.entry.set_width_chars(32) #self.entry.connect('activate', self.run_command) self.entry.connect('changed', self.entry_changed) self.entry_box.pack_start(self.entry_label, True) self.entry_box.pack_start(self.entry, True, False) # or use menus if we have xdg data: self.category_box = Gtk.HBox(True, 20) options_box.pack_start(self.category_box, False) self.category_label = l("Category:") self.category_combo = sf(Gtk.ComboBoxText()) self.category_box.pack_start(self.category_label, True) self.category_box.pack_start(self.category_combo, True, True) self.category_combo.connect("changed", self.category_changed) self.categories = {} self.command_box = Gtk.HBox(True, 20) options_box.pack_start(self.command_box, False) self.command_label = l("Command:") self.command_combo = sf(Gtk.ComboBoxText()) self.command_box.pack_start(self.command_label, True) self.command_box.pack_start(self.command_combo, True, True) self.command_combo.connect("changed", self.command_changed) self.commands = {} self.xsessions = None self.desktop_entry = None # start options: hbox = Gtk.HBox(False, 20) options_box.pack_start(hbox, False) self.exit_with_children_cb = sf(Gtk.CheckButton()) self.exit_with_children_cb.set_label("exit with application") hbox.add(xal(self.exit_with_children_cb, 0.5)) self.exit_with_children_cb.set_active(True) self.exit_with_client_cb = sf(Gtk.CheckButton()) self.exit_with_client_cb.set_label("exit with client") hbox.add(xal(self.exit_with_client_cb, 0.5)) self.exit_with_client_cb.set_active(False) # session options: hbox = Gtk.HBox(False, 12) hbox.pack_start(l("Options:"), True, False) for label_text, icon_name, tooltip_text, cb in ( ("Features", "features.png", "Session features", self.configure_features), ("Network", "connect.png", "Network options", self.configure_network), ("Display", "display.png", "Display settings", self.configure_display), ("Encodings", "encoding.png", "Picture compression", self.configure_encoding), ("Keyboard", "keyboard.png", "Keyboard layout and options", self.configure_keyboard), ("Audio", "speaker.png", "Audio forwarding options", self.configure_audio), ("Webcam", "webcam.png", "Webcam forwarding options", self.configure_webcam), ("Printing", "printer.png", "Printer forwarding options", self.configure_printing), ): icon = get_icon_pixbuf(icon_name) ib = imagebutton("", icon=icon, tooltip=label_text or tooltip_text, clicked_callback=cb, icon_size=32, label_font=Pango.FontDescription("sans 14")) hbox.pack_start(ib, True, False) options_box.pack_start(hbox, True, False) # Action buttons: hbox = Gtk.HBox(False, 20) vbox.pack_start(hbox, False, True, 20) def btn(label, tooltip, callback, default=False): ib = imagebutton(label, tooltip=tooltip, clicked_callback=callback, icon_size=32, default=default, label_font=Pango.FontDescription("sans 16")) hbox.pack_start(ib) return ib self.cancel_btn = btn("Cancel", "", self.quit) self.run_btn = btn("Start", "Start the xpra session", self.run_command) self.runattach_btn = btn("Start & Attach", "Start the xpra session and attach to it", self.runattach_command, True) self.runattach_btn.set_sensitive(False) vbox.show_all() self.display_combo.hide() self.add(vbox) #load encodings in the background: self.load_codecs_thread = start_thread(self.load_codecs, "load-codecs", daemon=True) #poll the list of X11 displays in the background: self.display_list = () if not OSX: self.load_displays_thread = start_thread(self.load_displays, "load-displays", daemon=True)
def __init__(self, title="Xpra"): self.exit_code = 0 self.start_session = None Gtk.Window.__init__(self) hb = Gtk.HeaderBar() hb.set_show_close_button(True) hb.props.title = "Xpra" self.set_titlebar(hb) hb.add(self.button("About", "help-about", about)) try: from xpra.client.gtk_base.toolbox import ToolboxGUI except ImportError: pass else: def show(): w = None def hide(*_args): w.hide() ToolboxGUI.quit = hide w = ToolboxGUI() w.show() hb.add(self.button("Toolbox", "applications-utilities", show)) hb.show_all() self.set_title(title) self.set_border_width(10) self.set_resizable(True) self.set_decorated(True) self.set_position(Gtk.WindowPosition.CENTER) icon = get_icon_pixbuf("xpra.png") if icon: self.set_icon(icon) add_close_accel(self, self.quit) add_window_accel(self, 'F1', self.show_about) self.connect("delete_event", self.quit) self.set_wmclass("xpra-gui", "Xpra-GUI") self.vbox = Gtk.VBox(False, 10) self.add(self.vbox) #with most window managers, #the window's title bar already shows "Xpra" #title_label = Gtk.Label(title) #title_label.modify_font(pango.FontDescription("sans 14")) #self.vbox.add(title_label) self.widgets = [] label_font = Pango.FontDescription("sans 16") if has_client: icon = get_icon_pixbuf("browse.png") self.browse_button = imagebutton( "Browse", icon, "Browse and connect to local sessions", clicked_callback=self.browse, icon_size=48, label_font=label_font) self.widgets.append(self.browse_button) icon = get_icon_pixbuf("connect.png") self.connect_button = imagebutton( "Connect", icon, "Connect to a session", clicked_callback=self.show_launcher, icon_size=48, label_font=label_font) self.widgets.append(self.connect_button) if has_server: icon = get_icon_pixbuf("server-connected.png") self.shadow_button = imagebutton( "Shadow", icon, "Start a shadow server", clicked_callback=self.start_shadow, icon_size=48, label_font=label_font) if not has_shadow: self.shadow_button.set_tooltip_text( "This build of Xpra does not support starting sessions") self.shadow_button.set_sensitive(False) self.widgets.append(self.shadow_button) icon = get_icon_pixbuf("windows.png") self.start_button = imagebutton("Start", icon, "Start a session", clicked_callback=self.start, icon_size=48, label_font=label_font) #not all builds and platforms can start sessions: if OSX or WIN32: self.start_button.set_tooltip_text( "Starting sessions is not supported on %s" % platform_name(sys.platform)) self.start_button.set_sensitive(False) elif not has_server: self.start_button.set_tooltip_text( "This build of Xpra does not support starting sessions") self.start_button.set_sensitive(False) self.widgets.append(self.start_button) assert len(self.widgets) % 2 == 0 table = Gtk.Table(len(self.widgets) // 2, 2, True) for i, widget in enumerate(self.widgets): table.attach(widget, i % 2, i % 2 + 1, i // 2, i // 2 + 1, xpadding=10, ypadding=10) self.vbox.add(table) self.vbox.show_all() self.set_size_request(640, 100 + 100 * len(self.widgets) // 2) def focus_in(window, event): log("focus_in(%s, %s)", window, event) def focus_out(window, event): log("focus_out(%s, %s)", window, event) self.reset_cursors() self.connect("focus-in-event", focus_in) self.connect("focus-out-event", focus_out)