def speaker_state(*args): if not self.client.server_sound_send: speaker.set_sensitive(False) set_tooltip_text(speaker, "Server does not support speaker forwarding") return speaker.set_sensitive(True) speaker.set_submenu(self.make_soundsubmenu(is_speaker_on, self.spk_on, self.spk_off, "speaker-changed"))
def microphone_state(*args): if not self.client.server_sound_receive: microphone.set_sensitive(False) set_tooltip_text(microphone, "Server does not support microphone forwarding") return microphone.set_sensitive(True) microphone.set_submenu(self.make_soundsubmenu(is_microphone_on, self.mic_on, self.mic_off, "microphone-changed"))
def populate_encodingsmenu(encodings_submenu, get_current_encoding, set_encoding, encodings, server_encodings): encodings_submenu.get_current_encoding = get_current_encoding encodings_submenu.set_encoding = set_encoding encodings_submenu.encodings = encodings encodings_submenu.server_encodings = server_encodings encodings_submenu.index_to_encoding = {} encodings_submenu.encoding_to_index = {} NAME_TO_ENCODING = {} i = 0 for encoding in encodings: name = ENCODINGS_TO_NAME.get(encoding, encoding) descr = ENCODINGS_HELP.get(encoding) NAME_TO_ENCODING[name] = encoding encoding_item = CheckMenuItem(name) if descr: if encoding not in server_encodings: descr += "\n(not available on this server)" set_tooltip_text(encoding_item, descr) def encoding_changed(oitem): log("encoding_changed(%s)", oitem) item = ensure_item_selected(encodings_submenu, oitem) enc = NAME_TO_ENCODING.get(item.get_label()) log("encoding_changed(%s) item=%s, enc=%s, current=%s", oitem, item, enc, encodings_submenu.get_current_encoding()) if enc is not None and encodings_submenu.get_current_encoding()!=enc: encodings_submenu.set_encoding(enc) log("make_encodingsmenu(..) encoding=%s, current=%s, active=%s", encoding, get_current_encoding(), encoding==get_current_encoding()) encoding_item.set_active(encoding==get_current_encoding()) encoding_item.set_sensitive(encoding in server_encodings) encoding_item.set_draw_as_radio(True) encoding_item.connect("toggled", encoding_changed) encodings_submenu.append(encoding_item) encodings_submenu.index_to_encoding[i] = encoding encodings_submenu.encoding_to_index[encoding] = i i += 1 encodings_submenu.show_all()
def set_encodingsmenuitem(*args): encodings.set_sensitive(not self.client.mmap_enabled) if self.client.mmap_enabled: #mmap disables encoding and uses raw rgb24 encodings.set_label("Encoding") set_tooltip_text(encodings, "memory mapped transfers are in use so picture encoding is disabled") else: encodings.set_submenu(self.make_encodingssubmenu())
def set_cursors_menuitem(*args): self.cursors_menuitem.set_active(self.client.cursors_enabled) c = self.client can_toggle_cursors = c.toggle_cursors_bell_notify and c.server_supports_cursors and c.client_supports_cursors self.cursors_menuitem.set_sensitive(can_toggle_cursors) if can_toggle_cursors: set_tooltip_text(self.cursors_menuitem, "Forward custom mouse cursors") else: set_tooltip_text(self.cursors_menuitem, "Cannot forward mouse cursors: the feature has been disabled")
def set_bell_menuitem(*args): self.bell_menuitem.set_active(self.client.bell_enabled) c = self.client can_toggle_bell = c.toggle_cursors_bell_notify and c.server_supports_bell and c.client_supports_bell self.bell_menuitem.set_sensitive(can_toggle_bell) if can_toggle_bell: set_tooltip_text(self.bell_menuitem, "Forward system bell") else: set_tooltip_text(self.bell_menuitem, "Cannot forward the system bell: the feature has been disabled")
def set_notifications_menuitem(*args): self.notifications_menuitem.set_active(self.client.notifications_enabled) c = self.client can_notify = c.toggle_cursors_bell_notify and c.server_supports_notifications and c.client_supports_notifications self.notifications_menuitem.set_sensitive(can_notify) if can_notify: set_tooltip_text(self.notifications_menuitem, "Forward system notifications") else: set_tooltip_text(self.notifications_menuitem, "Cannot forward system notifications: the feature has been disabled")
def set_clipboard_menuitem(*args): self.clipboard_menuitem.set_active(self.client.clipboard_enabled) c = self.client can_clipboard = c.server_supports_clipboard and c.client_supports_clipboard self.clipboard_menuitem.set_sensitive(can_clipboard) if can_clipboard: set_tooltip_text(self.clipboard_menuitem, "Enable clipboard synchronization") else: set_tooltip_text(self.clipboard_menuitem, "Clipboard synchronization cannot be enabled: disabled by server")
def btn(label, tooltip, callback, icon_name=None): btn = gtk.Button(label) set_tooltip_text(btn, tooltip) btn.connect("clicked", callback) if icon_name: icon = get_pixbuf(icon_name) if icon: btn.set_image(scaled_image(icon, 24)) hbox.pack_start(btn) return btn
def gl_set(*args): debug("gl_set(%s) opengl_enabled=%s, window_unmap=%s", args, self.client.opengl_enabled, self.client.window_unmap) gl.set_active(self.client.opengl_enabled) gl.set_sensitive(self.client.window_unmap) if not self.client.window_unmap: set_tooltip_text(gl, "no server support for runtime switching") return def opengl_toggled(*args): self.client.toggle_opengl() gl.connect("toggled", opengl_toggled)
def speaker_state(*args): if not self.client.server_sound_send: speaker.set_sensitive(False) set_tooltip_text(speaker, "Server does not support speaker forwarding") return speaker.set_sensitive(True) speaker.set_submenu( self.make_soundsubmenu(is_speaker_on, self.spk_on, self.spk_off, "speaker-changed"))
def __init__(self, *args): TrayBase.__init__(self, *args) self.tray_widget = gtk.StatusIcon() set_tooltip_text(self.tray_widget, self.tooltip or "Xpra") self.tray_widget.connect('activate', self.activate_menu) self.tray_widget.connect('popup-menu', self.popup_menu) if self.size_changed_cb: self.tray_widget.connect('size-changed', self.size_changed_cb) filename = self.get_tray_icon_filename(self.default_icon_filename) if filename: self.set_icon_from_file(filename)
def microphone_state(*args): if not self.client.server_sound_receive: microphone.set_sensitive(False) set_tooltip_text( microphone, "Server does not support microphone forwarding") return microphone.set_sensitive(True) microphone.set_submenu( self.make_soundsubmenu(is_microphone_on, self.mic_on, self.mic_off, "microphone-changed"))
def set_encodingsmenuitem(*args): encodings.set_sensitive(not self.client.mmap_enabled) if self.client.mmap_enabled: #mmap disables encoding and uses raw rgb24 encodings.set_label("Encoding") set_tooltip_text( encodings, "memory mapped transfers are in use so picture encoding is disabled" ) else: encodings.set_submenu(self.make_encodingssubmenu())
def set_bell_menuitem(*args): self.bell_menuitem.set_active(self.client.bell_enabled) c = self.client can_toggle_bell = c.toggle_cursors_bell_notify and c.server_supports_bell and c.client_supports_bell self.bell_menuitem.set_sensitive(can_toggle_bell) if can_toggle_bell: set_tooltip_text(self.bell_menuitem, "Forward system bell") else: set_tooltip_text( self.bell_menuitem, "Cannot forward the system bell: the feature has been disabled" )
def add_graph_button(self, tooltip, click_cb): button = gtk.EventBox() def set_cursor(widget): widget.window.set_cursor(gdk.Cursor(gdk.BASED_ARROW_DOWN)) button.connect("realize", set_cursor) graph = gtk.Image() graph.set_size_request(0, 0) button.connect("button_press_event", click_cb) button.add(graph) set_tooltip_text(graph, tooltip) self.graph_box.add(button) return graph
def gl_set(*args): log("gl_set(%s) opengl_enabled=%s, window_unmap=%s", args, self.client.opengl_enabled, self.client.window_unmap) gl.set_active(self.client.opengl_enabled) gl.set_sensitive(self.client.window_unmap) if not self.client.window_unmap: set_tooltip_text(gl, "no server support for runtime switching") return def opengl_toggled(*args): self.client.toggle_opengl() gl.connect("toggled", opengl_toggled)
def add_graph_button(self, tooltip, click_cb): button = gtk.EventBox() def set_cursor(widget): widget.window.set_cursor(gdk.Cursor(gdk.BASED_ARROW_DOWN)) button.connect("realize", set_cursor) graph = gtk.Image() graph.set_size_request(0, 0) button.connect("button_press_event", click_cb) button.add(graph) if tooltip: set_tooltip_text(graph, tooltip) self.graph_box.add(button) return graph
def __init__(self, menu, tooltip, icon_filename, size_changed_cb, click_cb, mouseover_cb, exit_cb): TrayBase.__init__(self, menu, tooltip, icon_filename, size_changed_cb, click_cb, mouseover_cb, exit_cb) self.tray_widget = gtk.StatusIcon() set_tooltip_text(self.tray_widget, tooltip or "Xpra") self.tray_widget.connect('activate', self.activate_menu) self.tray_widget.connect('popup-menu', self.popup_menu) if self.size_changed_cb: self.tray_widget.connect('size-changed', self.size_changed_cb) filename = self.get_tray_icon_filename(icon_filename) if filename: self.set_icon_from_file(filename)
def set_clipboard_menuitem(*args): self.clipboard_menuitem.set_active(self.client.clipboard_enabled) c = self.client can_clipboard = c.server_supports_clipboard and c.client_supports_clipboard self.clipboard_menuitem.set_sensitive(can_clipboard) if can_clipboard: set_tooltip_text(self.clipboard_menuitem, "Enable clipboard synchronization") else: set_tooltip_text( self.clipboard_menuitem, "Clipboard synchronization cannot be enabled: disabled by server" )
def set_cursors_menuitem(*args): self.cursors_menuitem.set_active(self.client.cursors_enabled) c = self.client can_toggle_cursors = c.toggle_cursors_bell_notify and c.server_supports_cursors and c.client_supports_cursors self.cursors_menuitem.set_sensitive(can_toggle_cursors) if can_toggle_cursors: set_tooltip_text(self.cursors_menuitem, "Forward custom mouse cursors") else: set_tooltip_text( self.cursors_menuitem, "Cannot forward mouse cursors: the feature has been disabled" )
def set_qualitymenu(self, *args): if self.quality: can_use = not self.client.mmap_enabled and self.client.encoding in self.client.server_encodings_with_quality self.quality.set_sensitive(can_use) if not can_use: set_tooltip_text(self.quality, "Not supported with %s encoding" % self.client.encoding) return set_tooltip_text(self.quality, "Minimum picture quality") #now check if lossless is supported: if self.quality.get_submenu(): can_lossless = self.client.encoding in self.client.server_encodings_with_lossless_mode for q,item in self.quality.get_submenu().menu_items.items(): item.set_sensitive(q<100 or can_lossless)
def set_notifications_menuitem(*args): self.notifications_menuitem.set_active( self.client.notifications_enabled) c = self.client can_notify = c.toggle_cursors_bell_notify and c.server_supports_notifications and c.client_supports_notifications self.notifications_menuitem.set_sensitive(can_notify) if can_notify: set_tooltip_text(self.notifications_menuitem, "Forward system notifications") else: set_tooltip_text( self.notifications_menuitem, "Cannot forward system notifications: the feature has been disabled" )
def mode_changed(self, *args): ssh = self.mode_combo.get_active_text()=="SSH" self.port_entry.set_text("") if ssh: self.ssh_port_entry.show() set_tooltip_text(self.port_entry, "Display number (optional)") set_tooltip_text(self.password_entry, "SSH Password") self.username_entry.show() self.username_label.show() else: self.ssh_port_entry.hide() set_tooltip_text(self.port_entry, "port number") set_tooltip_text(self.password_entry, "Session Password") self.username_entry.hide() self.username_label.hide() if self.config.port>0: self.port_entry.set_text("%s" % self.config.port) if not ssh or sys.platform.startswith("win") or sys.platform.startswith("darwin"): #password cannot be used with ssh #(except on win32 with plink, and on osx via the SSH_ASKPASS hack) self.password_label.show() self.password_entry.show() else: self.password_label.hide() self.password_entry.hide() self.validate()
def set_qualitymenu(self, *args): if self.quality: can_use = not self.client.mmap_enabled and self.client.encoding in self.client.server_encodings_with_quality self.quality.set_sensitive(can_use) if not can_use: set_tooltip_text( self.quality, "Not supported with %s encoding" % self.client.encoding) return set_tooltip_text(self.quality, "Minimum picture quality") #now check if lossless is supported: if self.quality.get_submenu(): can_lossless = self.client.encoding in self.client.server_encodings_with_lossless_mode for q, item in self.quality.get_submenu().menu_items.items(): item.set_sensitive(q < 100 or can_lossless)
def set_keyboard_sync_tooltip(): if not self.client.keyboard_helper: set_tooltip_text(self.keyboard_sync_menuitem, "Keyboard support is not loaded") elif not self.client.toggle_keyboard_sync: set_tooltip_text(self.keyboard_sync_menuitem, "This server does not support changes to keyboard synchronization") elif self.client.keyboard_helper.keyboard_sync: set_tooltip_text(self.keyboard_sync_menuitem, "Disable keyboard synchronization (prevents spurious key repeats on high latency connections)") else: set_tooltip_text(self.keyboard_sync_menuitem, "Enable keyboard state synchronization")
def make_encodingsmenu(get_current_encoding, set_encoding, encodings, server_encodings): encodings_submenu = gtk.Menu() encodings_submenu.get_current_encoding = get_current_encoding encodings_submenu.set_encoding = set_encoding encodings_submenu.encodings = encodings encodings_submenu.server_encodings = server_encodings encodings_submenu.index_to_encoding = {} encodings_submenu.encoding_to_index = {} NAME_TO_ENCODING = {} i = 0 cur = get_current_encoding() cur = {"h264": "x264", "vp8": "vpx"}.get(cur, cur) for encoding in encodings: name = ENCODINGS_TO_NAME.get(encoding, encoding) descr = ENCODINGS_HELP.get(encoding) NAME_TO_ENCODING[name] = encoding encoding_item = CheckMenuItem(name) if descr: if encoding not in server_encodings: descr += "\n(not available on this server)" set_tooltip_text(encoding_item, descr) def encoding_changed(oitem): item = ensure_item_selected(encodings_submenu, oitem) enc = NAME_TO_ENCODING.get(item.get_label()) debug("encoding_changed(%s) item=%s, enc=%s, current=%s", oitem, item, enc, encodings_submenu.get_current_encoding()) if enc is not None and encodings_submenu.get_current_encoding( ) != enc: encodings_submenu.set_encoding(enc) debug("make_encodingsmenu(..) encoding=%s, current=%s, active=%s", encoding, get_current_encoding(), encoding == get_current_encoding()) encoding_item.set_active(encoding == cur) encoding_item.set_sensitive(encoding in server_encodings) encoding_item.set_draw_as_radio(True) encoding_item.connect("toggled", encoding_changed) encodings_submenu.append(encoding_item) encodings_submenu.index_to_encoding[i] = encoding encodings_submenu.encoding_to_index[encoding] = i i += 1 encodings_submenu.show_all() return encodings_submenu
def populate_menu(options, value, set_fn): found_match = False items = {} if value and value > 0 and value not in options: options[value] = "%s%%" % value for s in sorted(options.keys()): t = options.get(s) qi = CheckMenuItem(t) qi.set_draw_as_radio(True) candidate_match = s >= max(0, value) qi.set_active(not found_match and candidate_match) found_match |= candidate_match qi.connect('activate', set_fn, submenu) if s > 0: set_tooltip_text(qi, "%s%%" % s) submenu.append(qi) items[s] = qi return items
def populate_menu(options, value, set_fn): found_match = False items = {} if value and value>0 and value not in options: options[value] = "%s%%" % value for s in sorted(options.keys()): t = options.get(s) qi = CheckMenuItem(t) qi.set_draw_as_radio(True) candidate_match = s>=max(0, value) qi.set_active(not found_match and candidate_match) found_match |= candidate_match qi.connect('activate', set_fn, submenu) if s>0: set_tooltip_text(qi, "%s%%" % s) submenu.append(qi) items[s] = qi return items
def populate_encodingsmenu(encodings_submenu, get_current_encoding, set_encoding, encodings, server_encodings): encodings_submenu.get_current_encoding = get_current_encoding encodings_submenu.set_encoding = set_encoding encodings_submenu.encodings = encodings encodings_submenu.server_encodings = server_encodings encodings_submenu.index_to_encoding = {} encodings_submenu.encoding_to_index = {} NAME_TO_ENCODING = {} i = 0 for encoding in encodings: name = ENCODINGS_TO_NAME.get(encoding, encoding) descr = ENCODINGS_HELP.get(encoding) NAME_TO_ENCODING[name] = encoding encoding_item = CheckMenuItem(name) if descr: if encoding not in server_encodings: descr += "\n(not available on this server)" set_tooltip_text(encoding_item, descr) def encoding_changed(item): ensure_item_selected(encodings_submenu, item) enc = NAME_TO_ENCODING.get(item.get_label()) log("encoding_changed(%s) enc=%s, current=%s", item, enc, encodings_submenu.get_current_encoding()) if enc is not None and encodings_submenu.get_current_encoding( ) != enc: encodings_submenu.set_encoding(enc) log("make_encodingsmenu(..) encoding=%s, current=%s, active=%s", encoding, get_current_encoding(), encoding == get_current_encoding()) encoding_item.set_active(encoding == get_current_encoding()) sensitive = encoding in server_encodings if not sensitive and HIDE_DISABLED_MENU_ENTRIES: continue set_sensitive(encoding_item, encoding in server_encodings) encoding_item.set_draw_as_radio(True) encoding_item.connect("toggled", encoding_changed) encodings_submenu.append(encoding_item) encodings_submenu.index_to_encoding[i] = encoding encodings_submenu.encoding_to_index[encoding] = i i += 1 encodings_submenu.show_all()
def set_speedmenu(self, *args): if self.speed: can_use = not self.client.mmap_enabled and self.client.encoding in self.client.server_encodings_with_speed and self.client.change_speed self.speed.set_sensitive(can_use) if self.client.mmap_enabled: set_tooltip_text(self.speed, "Quality is always 100% with mmap") elif not self.client.change_speed: set_tooltip_text(self.speed, "Server does not support changing speed") elif self.client.encoding!="x264": set_tooltip_text(self.speed, "Not supported with %s encoding" % self.client.encoding) else: set_tooltip_text(self.speed, "Encoding latency vs size")
def set_speedmenu(self, *args): if self.speed: can_use = not self.client.mmap_enabled and self.client.encoding in self.client.server_encodings_with_speed and self.client.change_speed self.speed.set_sensitive(can_use) if self.client.mmap_enabled: set_tooltip_text(self.speed, "Quality is always 100% with mmap") elif not self.client.change_speed: set_tooltip_text(self.speed, "Server does not support changing speed") elif self.client.encoding != "h264": set_tooltip_text( self.speed, "Not supported with %s encoding" % self.client.encoding) else: set_tooltip_text(self.speed, "Encoding latency vs size")
def set_keyboard_sync_tooltip(): if not self.client.keyboard_helper: set_tooltip_text(self.keyboard_sync_menuitem, "Keyboard support is not loaded") elif not self.client.toggle_keyboard_sync: set_tooltip_text( self.keyboard_sync_menuitem, "This server does not support changes to keyboard synchronization" ) elif self.client.keyboard_helper.keyboard_sync: set_tooltip_text( self.keyboard_sync_menuitem, "Disable keyboard synchronization (prevents spurious key repeats on high latency connections)" ) else: set_tooltip_text(self.keyboard_sync_menuitem, "Enable keyboard state synchronization")
def set_tooltip(self, text=None): set_tooltip_text(self.tray_widget, text or "Xpra")
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 create_window(self): self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("destroy", self.destroy) self.window.set_default_size(400, 300) self.window.set_border_width(20) self.window.set_title("Xpra Launcher") self.window.modify_bg(gtk.STATE_NORMAL, gdk.Color(red=65535, green=65535, blue=65535)) icon_pixbuf = self.get_icon("xpra.png") if icon_pixbuf: self.window.set_icon(icon_pixbuf) self.window.set_position(gtk.WIN_POS_CENTER) vbox = gtk.VBox(False, 0) vbox.set_spacing(15) # Title hbox = gtk.HBox(False, 0) if icon_pixbuf: logo_button = gtk.Button("") settings = logo_button.get_settings() settings.set_property('gtk-button-images', True) logo_button.connect("clicked", about) set_tooltip_text(logo_button, "About") image = gtk.Image() image.set_from_pixbuf(icon_pixbuf) logo_button.set_image(image) hbox.pack_start(logo_button, expand=False, fill=False) label = gtk.Label("Connect to xpra server") label.modify_font(pango.FontDescription("sans 14")) hbox.pack_start(label, expand=True, fill=True) vbox.pack_start(hbox) # Mode: hbox = gtk.HBox(False, 20) hbox.set_spacing(20) hbox.pack_start(gtk.Label("Mode: ")) self.mode_combo = gtk.combo_box_new_text() self.mode_combo.get_model().clear() self.mode_combo.append_text("TCP") self.mode_combo.append_text("TCP + AES") self.mode_combo.append_text("SSH") self.mode_combo.connect("changed", self.mode_changed) hbox.pack_start(self.mode_combo) vbox.pack_start(hbox) # Encoding: hbox = gtk.HBox(False, 20) hbox.set_spacing(20) hbox.pack_start(gtk.Label("Encoding: ")) self.encoding_combo = gtk.OptionMenu() def get_current_encoding(): return self.config.encoding def set_new_encoding(e): self.config.encoding = e encodings = [x for x in PREFERED_ENCODING_ORDER if x in self.client.get_encodings()] server_encodings = encodings es = make_encodingsmenu(get_current_encoding, set_new_encoding, encodings, server_encodings) self.encoding_combo.set_menu(es) set_history_from_active(self.encoding_combo) hbox.pack_start(self.encoding_combo) vbox.pack_start(hbox) self.encoding_combo.connect("changed", self.encoding_changed) # Quality hbox = gtk.HBox(False, 20) hbox.set_spacing(20) self.quality_label = gtk.Label("Quality: ") hbox.pack_start(self.quality_label) self.quality_combo = gtk.OptionMenu() def set_min_quality(q): self.config.min_quality = q def set_quality(q): self.config.quality = q def get_min_quality(): return self.config.min_quality def get_quality(): return self.config.quality sq = make_min_auto_menu("Quality", MIN_QUALITY_OPTIONS, QUALITY_OPTIONS, get_min_quality, get_quality, set_min_quality, set_quality) self.quality_combo.set_menu(sq) set_history_from_active(self.quality_combo) hbox.pack_start(self.quality_combo) vbox.pack_start(hbox) # Speed hbox = gtk.HBox(False, 20) hbox.set_spacing(20) self.speed_label = gtk.Label("Speed: ") hbox.pack_start(self.speed_label) self.speed_combo = gtk.OptionMenu() def set_min_speed(s): self.config.min_speed = s def set_speed(s): self.config.speed = s def get_min_speed(): return self.config.min_speed def get_speed(): return self.config.speed ss = make_min_auto_menu("Speed", MIN_SPEED_OPTIONS, SPEED_OPTIONS, get_min_speed, get_speed, set_min_speed, set_speed) self.speed_combo.set_menu(ss) set_history_from_active(self.speed_combo) hbox.pack_start(self.speed_combo) vbox.pack_start(hbox) # Username@Host:Port hbox = gtk.HBox(False, 0) hbox.set_spacing(5) self.username_entry = gtk.Entry(max=128) self.username_entry.set_width_chars(16) self.username_entry.connect("changed", self.validate) set_tooltip_text(self.username_entry, "SSH username") self.username_label = gtk.Label("@") self.host_entry = gtk.Entry(max=128) self.host_entry.set_width_chars(24) self.host_entry.connect("changed", self.validate) set_tooltip_text(self.host_entry, "hostname") self.port_entry = gtk.Entry(max=5) self.port_entry.set_width_chars(5) self.port_entry.connect("changed", self.validate) hbox.pack_start(self.username_entry) hbox.pack_start(self.username_label) hbox.pack_start(self.host_entry) hbox.pack_start(gtk.Label(":")) hbox.pack_start(self.port_entry) vbox.pack_start(hbox) # Password hbox = gtk.HBox(False, 0) hbox.set_spacing(20) self.password_entry = gtk.Entry(max=128) self.password_entry.set_width_chars(30) self.password_entry.set_text("") self.password_entry.set_visibility(False) self.password_entry.connect("changed", self.password_ok) self.password_entry.connect("changed", self.validate) self.password_label = gtk.Label("Password: "******"Save") set_tooltip_text(self.save_btn, "Save settings to a session file") self.save_btn.connect("clicked", self.save_clicked) hbox.pack_start(self.save_btn) #Load: self.load_btn = gtk.Button("Load") set_tooltip_text(self.load_btn, "Load settings from a session file") self.load_btn.connect("clicked", self.load_clicked) hbox.pack_start(self.load_btn) # Connect button: self.button = gtk.Button("Connect") self.button.connect("clicked", self.connect_clicked) connect_icon = self.get_icon("retry.png") if connect_icon: self.button.set_image(scaled_image(connect_icon, 24)) hbox.pack_start(self.button) def accel_close(*args): gtk.main_quit() add_close_accel(self.window, accel_close) vbox.show_all() self.window.vbox = vbox self.window.add(vbox)
def populate_statistics(self): log("populate_statistics()") if time.time()-self.last_populate_statistics<1.0: #don't repopulate more than every second return True self.last_populate_statistics = time.time() if self.client.server_info_request: self.client.send_info_request() def setall(labels, values): assert len(labels)==len(values), "%s labels and %s values (%s vs %s)" % (len(labels), len(values), labels, values) for i in range(len(labels)): l = labels[i] v = values[i] l.set_text(str(v)) def setlabels(labels, values, rounding=int): if len(values)==0: return avg = sum(values)/len(values) svalues = sorted(values) l = len(svalues) assert l>0 if l<10: index = l-1 else: index = int(l*90/100) index = max(0, min(l-1, index)) pct = svalues[index] disp = values[-1], min(values), avg, pct, max(values) rounded_values = [rounding(v) for v in disp] setall(labels, rounded_values) if len(self.client.server_ping_latency)>0: spl = [1000.0*x for _,x in list(self.client.server_ping_latency)] setlabels(self.server_latency_labels, spl) if len(self.client.client_ping_latency)>0: cpl = [1000.0*x for _,x in list(self.client.client_ping_latency)] setlabels(self.client_latency_labels, cpl) if self.client.windows_enabled: if self.client.server_info_request: setall(self.batch_labels, self.values_from_info("batch_delay", "batch.delay")) setall(self.damage_labels, self.values_from_info("damage_out_latency", "damage.out_latency")) setall(self.quality_labels, self.all_values_from_info("quality", "encoding.quality")) setall(self.speed_labels, self.all_values_from_info("speed", "encoding.speed")) region_sizes = [] rps = [] pps = [] decoding_latency = [] if len(self.client.pixel_counter)>0: min_time = None max_time = None regions_per_second = {} pixels_per_second = {} for start_time, end_time, size in self.client.pixel_counter: decoding_latency.append(int(1000.0*(end_time-start_time))) region_sizes.append(size) if min_time is None or min_time>end_time: min_time = end_time if max_time is None or max_time<end_time: max_time = end_time time_in_seconds = int(end_time) regions = regions_per_second.get(time_in_seconds, 0) regions_per_second[time_in_seconds] = regions+1 pixels = pixels_per_second.get(time_in_seconds, 0) pixels_per_second[time_in_seconds] = pixels + size if int(min_time)+1 < int(max_time): for t in range(int(min_time)+1, int(max_time)): rps.append(regions_per_second.get(t, 0)) pps.append(pixels_per_second.get(t, 0)) setlabels(self.decoding_labels, decoding_latency) setlabels(self.regions_per_second_labels, rps) setlabels(self.regions_sizes_labels, region_sizes, rounding=std_unit_dec) setlabels(self.pixels_per_second_labels, pps, rounding=std_unit_dec) windows, gl, transient, trays = 0, 0, 0, 0 for w in self.client._window_to_id.keys(): if w.is_tray(): trays += 1 elif w.is_OR(): transient +=1 else: windows += 1 if w.is_GL(): gl += 1 self.windows_managed_label.set_text(str(windows)) self.transient_managed_label.set_text(str(transient)) self.trays_managed_label.set_text(str(trays)) if self.client.client_supports_opengl: self.opengl_label.set_text(str(gl)) #remove all the current labels: for x in self.encoder_info_box.get_children(): self.encoder_info_box.remove(x) window_encoder_stats = {} if self.client.server_last_info: #We are interested in data like: #window[1].encoder=x264 #window[1].encoder.frames=1 for k,v in self.client.server_last_info.items(): k = bytestostr(k) pos = k.find("].encoder") if k.startswith("window[") and pos>0: wid_str = k[len("window["):pos] #ie: "1" ekey = k[(pos+len("].encoder")):] #ie: "" or ".frames" if ekey.startswith("."): ekey = ekey[1:] try: wid = int(wid_str) props = window_encoder_stats.setdefault(wid, {}) props[ekey] = v except: #wid_str may be invalid, ie: #window[1].pipeline_option[1].encoder=codec_spec(xpra.codecs.enc_x264.encoder.Encoder) # -> wid_str= "1].pipeline_option[1" pass #print("window_encoder_stats=%s" % window_encoder_stats) for wid, props in window_encoder_stats.items(): l = label("%s (%s)" % (wid, props.get(""))) l.show() info = ["%s=%s" % (k,v) for k,v in props.items() if k!=""] set_tooltip_text(l, " ".join(info)) self.encoder_info_box.add(l) return True
def create_window(self): self.window = gtk.Window() self.window.connect("destroy", self.destroy) self.window.set_default_size(400, 300) self.window.set_border_width(20) self.window.set_title("Xpra Launcher") self.window.modify_bg(STATE_NORMAL, gdk.Color(red=65535, green=65535, blue=65535)) icon_pixbuf = self.get_icon("xpra.png") if icon_pixbuf: self.window.set_icon(icon_pixbuf) self.window.set_position(WIN_POS_CENTER) vbox = gtk.VBox(False, 0) vbox.set_spacing(15) # Title hbox = gtk.HBox(False, 0) if icon_pixbuf: logo_button = gtk.Button("") settings = logo_button.get_settings() settings.set_property('gtk-button-images', True) logo_button.connect("clicked", about) set_tooltip_text(logo_button, "About") image = gtk.Image() image.set_from_pixbuf(icon_pixbuf) logo_button.set_image(image) hbox.pack_start(logo_button, expand=False, fill=False) label = gtk.Label("Connect to xpra server") label.modify_font(pango.FontDescription("sans 14")) hbox.pack_start(label, expand=True, fill=True) vbox.pack_start(hbox) # Mode: hbox = gtk.HBox(False, 20) hbox.set_spacing(20) hbox.pack_start(gtk.Label("Mode: ")) self.mode_combo = gtk.combo_box_new_text() self.mode_combo.get_model().clear() self.mode_combo.append_text("TCP") if "AES" in ENCRYPTION_CIPHERS: self.mode_combo.append_text("TCP + AES") self.mode_combo.append_text("SSH") self.mode_combo.connect("changed", self.mode_changed) hbox.pack_start(self.mode_combo) vbox.pack_start(hbox) # Encoding: hbox = gtk.HBox(False, 20) hbox.set_spacing(20) hbox.pack_start(gtk.Label("Encoding: ")) self.encoding_combo = OptionMenu() def get_current_encoding(): return self.config.encoding def set_new_encoding(e): self.config.encoding = e encodings = [x for x in PREFERED_ENCODING_ORDER if x in self.client.get_encodings()] server_encodings = encodings es = make_encodingsmenu(get_current_encoding, set_new_encoding, encodings, server_encodings) self.encoding_combo.set_menu(es) set_history_from_active(self.encoding_combo) hbox.pack_start(self.encoding_combo) vbox.pack_start(hbox) self.encoding_combo.connect("changed", self.encoding_changed) # Quality hbox = gtk.HBox(False, 20) hbox.set_spacing(20) self.quality_label = gtk.Label("Quality: ") hbox.pack_start(self.quality_label) self.quality_combo = OptionMenu() def set_min_quality(q): self.config.min_quality = q def set_quality(q): self.config.quality = q def get_min_quality(): return self.config.min_quality def get_quality(): return self.config.quality sq = make_min_auto_menu("Quality", MIN_QUALITY_OPTIONS, QUALITY_OPTIONS, get_min_quality, get_quality, set_min_quality, set_quality) self.quality_combo.set_menu(sq) set_history_from_active(self.quality_combo) hbox.pack_start(self.quality_combo) vbox.pack_start(hbox) # Speed hbox = gtk.HBox(False, 20) hbox.set_spacing(20) self.speed_label = gtk.Label("Speed: ") hbox.pack_start(self.speed_label) self.speed_combo = OptionMenu() def set_min_speed(s): self.config.min_speed = s def set_speed(s): self.config.speed = s def get_min_speed(): return self.config.min_speed def get_speed(): return self.config.speed ss = make_min_auto_menu("Speed", MIN_SPEED_OPTIONS, SPEED_OPTIONS, get_min_speed, get_speed, set_min_speed, set_speed) self.speed_combo.set_menu(ss) set_history_from_active(self.speed_combo) hbox.pack_start(self.speed_combo) vbox.pack_start(hbox) # Username@Host:Port hbox = gtk.HBox(False, 0) hbox.set_spacing(5) self.username_entry = gtk.Entry(max=128) self.username_entry.set_width_chars(16) self.username_entry.connect("changed", self.validate) set_tooltip_text(self.username_entry, "SSH username") self.username_label = gtk.Label("@") self.host_entry = gtk.Entry(max=128) self.host_entry.set_width_chars(24) self.host_entry.connect("changed", self.validate) set_tooltip_text(self.host_entry, "hostname") self.ssh_port_entry = gtk.Entry(max=5) self.ssh_port_entry.set_width_chars(5) self.ssh_port_entry.connect("changed", self.validate) set_tooltip_text(self.ssh_port_entry, "SSH port") self.port_entry = gtk.Entry(max=5) self.port_entry.set_width_chars(5) self.port_entry.connect("changed", self.validate) set_tooltip_text(self.port_entry, "port/display") hbox.pack_start(self.username_entry) hbox.pack_start(self.username_label) hbox.pack_start(self.host_entry) hbox.pack_start(self.ssh_port_entry) hbox.pack_start(gtk.Label(":")) hbox.pack_start(self.port_entry) vbox.pack_start(hbox) # Password hbox = gtk.HBox(False, 0) hbox.set_spacing(20) self.password_entry = gtk.Entry(max=128) self.password_entry.set_width_chars(30) self.password_entry.set_text("") self.password_entry.set_visibility(False) self.password_entry.connect("changed", self.password_ok) self.password_entry.connect("changed", self.validate) self.password_label = gtk.Label("Password: "******"Save") set_tooltip_text(self.save_btn, "Save settings to a session file") self.save_btn.connect("clicked", self.save_clicked) hbox.pack_start(self.save_btn) #Load: self.load_btn = gtk.Button("Load") set_tooltip_text(self.load_btn, "Load settings from a session file") self.load_btn.connect("clicked", self.load_clicked) hbox.pack_start(self.load_btn) # Connect button: self.button = gtk.Button("Connect") self.button.connect("clicked", self.connect_clicked) connect_icon = self.get_icon("retry.png") if connect_icon: self.button.set_image(scaled_image(connect_icon, 24)) hbox.pack_start(self.button) def accel_close(*args): gtk.main_quit() add_close_accel(self.window, accel_close) vbox.show_all() self.window.vbox = vbox self.window.add(vbox)
def setup_window(self): self.window = gtk.Window() self.window.connect("destroy", self.close) self.window.set_default_size(400, 300) self.window.set_border_width(20) self.window.set_title("Xpra Bug Report") self.window.modify_bg(STATE_NORMAL, gdk.Color(red=65535, green=65535, blue=65535)) icon_pixbuf = self.get_icon("bugs.png") if icon_pixbuf: self.window.set_icon(icon_pixbuf) self.window.set_position(WIN_POS_CENTER) vbox = gtk.VBox(False, 0) vbox.set_spacing(15) # Title hbox = gtk.HBox(False, 0) icon_pixbuf = self.get_icon("xpra.png") if icon_pixbuf and self.show_about: logo_button = gtk.Button("") settings = logo_button.get_settings() settings.set_property('gtk-button-images', True) logo_button.connect("clicked", about) set_tooltip_text(logo_button, "About") image = gtk.Image() image.set_from_pixbuf(icon_pixbuf) logo_button.set_image(image) hbox.pack_start(logo_button, expand=False, fill=False) label = gtk.Label("Xpra Bug Report Tool") label.modify_font(pango.FontDescription("sans 14")) hbox.pack_start(label, expand=True, fill=True) vbox.pack_start(hbox) #the box containing all the input: ibox = gtk.VBox(False, 0) ibox.set_spacing(3) vbox.pack_start(ibox) # Description al = gtk.Alignment(xalign=0, yalign=0.5, xscale=0.0, yscale=0) al.add(gtk.Label("Please describe the problem:")) ibox.pack_start(al) #self.description = gtk.Entry(max=128) #self.description.set_width_chars(40) self.description = gtk.TextView() self.description.set_accepts_tab(True) self.description.set_justification(JUSTIFY_LEFT) self.description.set_border_width(2) self.description.set_size_request(300, 80) self.description.modify_bg( STATE_NORMAL, gdk.Color(red=32768, green=32768, blue=32768)) ibox.pack_start(self.description, expand=False, fill=False) # Toggles: al = gtk.Alignment(xalign=0, yalign=0.5, xscale=0.0, yscale=0) al.add(gtk.Label("Include:")) ibox.pack_start(al) #generic toggles: from xpra.gtk_common.keymap import get_gtk_keymap from xpra.codecs.loader import codec_versions, load_codecs load_codecs() try: from xpra.sound.gstreamer_util import get_info as get_sound_info except: get_sound_info = None if self.opengl_info: def get_gl_info(): return self.opengl_info else: try: from xpra.client.gl.gl_check import check_support def get_gl_info(): return check_support(force_enable=True) except: get_gl_info = None from xpra.net.net_util import get_info as get_net_info from xpra.platform.paths import get_info as get_path_info from xpra.version_util import get_version_info, get_platform_info, get_host_info def get_sys_info(): d = {} for k, v in { "version": get_version_info(), "platform": get_platform_info(), "host": get_host_info(), "paths": get_path_info(), "gtk": get_gtk_version_info(), "user": get_user_info(), "env": os.environ, }.items(): updict(d, k, v) return d get_screenshot, take_screenshot_fn = None, None #screenshot: may have OS-specific code try: from xpra.platform.gui import take_screenshot take_screenshot_fn = take_screenshot except: log("failed to load platfrom specific screenshot code", exc_info=True) if not take_screenshot_fn: #default: gtk screen capture try: from xpra.server.gtk_root_window_model import GTKRootWindowModel rwm = GTKRootWindowModel(gtk.gdk.get_default_root_window()) take_screenshot_fn = rwm.take_screenshot except: log("failed to load gtk screenshot code", exc_info=True) log("take_screenshot_fn=%s", take_screenshot_fn) if take_screenshot_fn: def get_screenshot(): #take_screenshot() returns: w, h, "png", rowstride, data return take_screenshot_fn()[4] self.toggles = ( ("system", "txt", "System", get_sys_info, "Xpra version, platform and host information"), ("network", "txt", "Network", get_net_info, "Compression, packet encoding and encryption"), ("encoding", "txt", "Encodings", codec_versions, "Picture encodings supported"), ("opengl", "txt", "OpenGL", get_gl_info, "OpenGL driver and features"), ("sound", "txt", "Sound", get_sound_info, "Sound codecs and GStreamer version information"), ("keyboard", "txt", "Keyboard Mapping", get_gtk_keymap, "Keyboard layout and key mapping"), ("xpra-info", "txt", "Server Info", self.xpra_info, "Full server information from 'xpra info'"), ("screenshot", "png", "Screenshot", get_screenshot, ""), ) for name, _, title, value_cb, tooltip in self.toggles: cb = gtk.CheckButton(title + [" (not available)", ""][bool(value_cb)]) cb.set_active(self.includes.get(name, True)) cb.set_sensitive(bool(value_cb)) set_tooltip_text(cb, tooltip) ibox.pack_start(cb) setattr(self, name, cb) # Buttons: hbox = gtk.HBox(False, 20) vbox.pack_start(hbox) def btn(label, tooltip, callback, icon_name=None): btn = gtk.Button(label) set_tooltip_text(btn, tooltip) btn.connect("clicked", callback) if icon_name: icon = self.get_icon(icon_name) if icon: btn.set_image(scaled_image(icon, 24)) hbox.pack_start(btn) return btn #Copy: btn("Copy to clipboard", "Copy all data to clipboard", self.copy_clicked, "clipboard.png") btn("Save", "Save Bug Report", self.save_clicked, "download.png") btn("Cancel", "", self.close, "quit.png") def accel_close(*args): self.close() add_close_accel(self.window, accel_close) vbox.show_all() self.window.vbox = vbox self.window.add(vbox)