Пример #1
0
 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"))
Пример #2
0
 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"))
Пример #3
0
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()
Пример #4
0
 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())
Пример #5
0
 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")
Пример #6
0
 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")
Пример #7
0
 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")
Пример #8
0
 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")
Пример #9
0
 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
Пример #10
0
 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)
Пример #11
0
 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"))
Пример #12
0
 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)
Пример #13
0
 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"))
Пример #14
0
 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())
Пример #15
0
 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)
Пример #16
0
 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"
         )
Пример #17
0
 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
Пример #18
0
        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)
Пример #19
0
 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
Пример #20
0
 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)
Пример #21
0
 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"
         )
Пример #22
0
 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"
         )
Пример #23
0
 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)
Пример #24
0
 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"
         )
Пример #25
0
 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()
Пример #26
0
 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)
Пример #27
0
 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")
Пример #28
0
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
Пример #29
0
 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
Пример #30
0
 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
Пример #31
0
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()
Пример #32
0
 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")
Пример #33
0
 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")
Пример #34
0
 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")
Пример #35
0
 def set_tooltip(self, text=None):
     set_tooltip_text(self.tray_widget, text or "Xpra")
Пример #36
0
    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)
Пример #37
0
 def set_tooltip(self, text=None):
     set_tooltip_text(self.tray_widget, text or "Xpra")
Пример #38
0
    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)
Пример #39
0
    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
Пример #40
0
    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)
Пример #41
0
    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)