[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[virt-tools-list] [PATCH] virt-manager: Add system tray icon



The attached patch adds an option for a virt-manager system tray icon. Here's
a screenshot:

http://fedorapeople.org/~crobinso/virt-manager/vmm-systray.png

The icon can be used to quit the app, or start, stop, pause, or open a VM.
Showing the icon needs to be opted in via Edit->Preferences. This should be
handy for people that keep virt-manager running for a long time, and just need
a simple interface to start/stop a VM, or open a graphical console.

Questions or comments appreciated.

Thanks,
Cole
# HG changeset patch
# User Cole Robinson <crobinso redhat com>
# Date 1248640996 14400
# Node ID 0a08550c10feaf20878cf6100119af0307872fc1
# Parent  860d7c2bfb8c22450e9028189f88c63fb13b3338
Add a system tray icon.

The behavior is opt in via preferences, off by default. The icon allows
starting, stopping, and pausing VMs, opening console/details, and quiting the
entire app.

diff -r 860d7c2bfb8c -r 0a08550c10fe src/virt-manager.schemas.in
--- a/src/virt-manager.schemas.in	Sun Jul 26 16:25:01 2009 -0400
+++ b/src/virt-manager.schemas.in	Sun Jul 26 16:43:16 2009 -0400
@@ -170,6 +170,19 @@
     </schema>
 
     <schema>
+      <key>/schemas/apps/::PACKAGE::/system-tray</key>
+      <applyto>/apps/::PACKAGE::/system-tray</applyto>
+      <owner>::PACKAGE::</owner>
+      <type>bool</type>
+      <default>0</default>
+
+      <locale name="C">
+        <short>Show system tray icon</short>
+        <long>Show system tray icon while app is running</long>
+      </locale>
+    </schema>
+
+    <schema>
       <key>/schemas/apps/::PACKAGE::/paths/default-image-path</key>
       <applyto>/apps/::PACKAGE::/paths/default-image-path</applyto>
       <owner>::PACKAGE::</owner>
diff -r 860d7c2bfb8c -r 0a08550c10fe src/virtManager/config.py
--- a/src/virtManager/config.py	Sun Jul 26 16:25:01 2009 -0400
+++ b/src/virtManager/config.py	Sun Jul 26 16:43:16 2009 -0400
@@ -271,6 +271,13 @@
         self.conf.set_value(self.conf_dir + "/paths/default-%s-path" % _type,
                                                                       folder)
 
+    def on_view_system_tray_changed(self, callback):
+        self.conf.notify_add(self.conf_dir + "/system-tray", callback)
+    def get_view_system_tray(self):
+        return self.conf.get_bool(self.conf_dir + "/system-tray")
+    def set_view_system_tray(self, val):
+        self.conf.set_bool(self.conf_dir + "/system-tray", val)
+
     def on_vmlist_stats_type_changed(self, callback):
         self.conf.notify_add(self.conf_dir + "/vmlist-fields/stats_type",
                              callback)
diff -r 860d7c2bfb8c -r 0a08550c10fe src/virtManager/engine.py
--- a/src/virtManager/engine.py	Sun Jul 26 16:25:01 2009 -0400
+++ b/src/virtManager/engine.py	Sun Jul 26 16:43:16 2009 -0400
@@ -40,6 +40,7 @@
 from virtManager.create import vmmCreate
 from virtManager.host import vmmHost
 from virtManager.error import vmmErrorDialog
+from virtManager.systray import vmmSystray
 import virtManager.util as util
 
 class vmmEngine(gobject.GObject):
@@ -68,6 +69,8 @@
         self.timer = None
         self.last_timeout = 0
 
+        self.systray = None
+
         self._tick_thread = None
         self._tick_thread_slow = False
         self._libvirt_support_threading = (libvirt.getVersion() >= 6000)
@@ -79,6 +82,7 @@
         self.windows = 0
 
         self.netdevHelper = vmmNetDevHelper(self.config)
+        self.init_systray()
 
         self.config.on_stats_update_interval_changed(self.reschedule_timer)
 
@@ -86,6 +90,22 @@
         self.load_stored_uris()
         self.tick()
 
+    def init_systray(self):
+        if self.systray:
+            return
+
+        self.systray = vmmSystray(self.config, self)
+        self.systray.connect("action-view-manager", self._do_show_manager)
+        self.systray.connect("action-suspend-domain", self._do_suspend_domain)
+        self.systray.connect("action-resume-domain", self._do_resume_domain)
+        self.systray.connect("action-run-domain", self._do_run_domain)
+        self.systray.connect("action-shutdown-domain", self._do_shutdown_domain)
+        self.systray.connect("action-reboot-domain", self._do_reboot_domain)
+        self.systray.connect("action-destroy-domain", self._do_destroy_domain)
+        self.systray.connect("action-show-console", self._do_show_console)
+        self.systray.connect("action-show-details", self._do_show_details)
+        self.systray.connect("action-exit-app", self._do_exit_app)
+
     def load_stored_uris(self):
         uris = self.config.get_connections()
         if uris != None:
diff -r 860d7c2bfb8c -r 0a08550c10fe src/virtManager/preferences.py
--- a/src/virtManager/preferences.py	Sun Jul 26 16:25:01 2009 -0400
+++ b/src/virtManager/preferences.py	Sun Jul 26 16:43:16 2009 -0400
@@ -37,6 +37,7 @@
         self.topwin = self.window.get_widget("vmm-preferences")
         self.topwin.hide()
 
+        self.config.on_view_system_tray_changed(self.refresh_view_system_tray)
         self.config.on_console_popup_changed(self.refresh_console_popup)
         self.config.on_console_keygrab_changed(self.refresh_console_keygrab)
         self.config.on_console_scaling_changed(self.refresh_console_scaling)
@@ -47,6 +48,7 @@
         self.config.on_stats_enable_disk_poll_changed(self.refresh_disk_poll)
         self.config.on_stats_enable_net_poll_changed(self.refresh_net_poll)
 
+        self.refresh_view_system_tray()
         self.refresh_update_interval()
         self.refresh_history_length()
         self.refresh_console_popup()
@@ -58,6 +60,7 @@
         self.refresh_net_poll()
 
         self.window.signal_autoconnect({
+            "on_prefs_system_tray_toggled" : self.change_view_system_tray,
             "on_prefs_stats_update_interval_changed": self.change_update_interval,
             "on_prefs_stats_history_length_changed": self.change_history_length,
             "on_prefs_console_popup_changed": self.change_console_popup,
@@ -84,6 +87,11 @@
     # Config Change Options #
     #########################
 
+    def refresh_view_system_tray(self, ignore1=None, ignore2=None,
+                                 ignore3=None, ignore4=None):
+        val = self.config.get_view_system_tray()
+        self.window.get_widget("prefs-system-tray").set_active(bool(val))
+
     def refresh_update_interval(self, ignore1=None,ignore2=None,ignore3=None,ignore4=None):
         self.window.get_widget("prefs-stats-update-interval").set_value(self.config.get_stats_update_interval())
     def refresh_history_length(self, ignore1=None,ignore2=None,ignore3=None,ignore4=None):
@@ -116,6 +124,9 @@
                          ignore4=None):
         self.window.get_widget("prefs-stats-enable-net").set_active(self.config.get_stats_enable_net_poll())
 
+    def change_view_system_tray(self, src):
+        self.config.set_view_system_tray(src.get_active())
+
     def change_update_interval(self, src):
         self.config.set_stats_update_interval(src.get_value_as_int())
     def change_history_length(self, src):
diff -r 860d7c2bfb8c -r 0a08550c10fe src/virtManager/systray.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManager/systray.py	Sun Jul 26 16:43:16 2009 -0400
@@ -0,0 +1,367 @@
+#
+# Copyright (C) 2009 Red Hat, Inc.
+# Copyright (C) 2009 Cole Robinson <crobinso redhat com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA.
+#
+
+import gobject
+import gtk
+import gtk.glade
+
+class vmmSystray(gobject.GObject):
+    __gsignals__ = {
+        "action-view-manager": (gobject.SIGNAL_RUN_FIRST,
+                                gobject.TYPE_NONE, []),
+        "action-suspend-domain": (gobject.SIGNAL_RUN_FIRST,
+                                  gobject.TYPE_NONE, (str, str)),
+        "action-resume-domain": (gobject.SIGNAL_RUN_FIRST,
+                                 gobject.TYPE_NONE, (str, str)),
+        "action-run-domain": (gobject.SIGNAL_RUN_FIRST,
+                              gobject.TYPE_NONE, (str, str)),
+        "action-shutdown-domain": (gobject.SIGNAL_RUN_FIRST,
+                                   gobject.TYPE_NONE, (str, str)),
+        "action-reboot-domain": (gobject.SIGNAL_RUN_FIRST,
+                                 gobject.TYPE_NONE, (str, str)),
+        "action-destroy-domain": (gobject.SIGNAL_RUN_FIRST,
+                                  gobject.TYPE_NONE, (str, str)),
+        "action-show-host": (gobject.SIGNAL_RUN_FIRST,
+                              gobject.TYPE_NONE, [str]),
+        "action-show-details": (gobject.SIGNAL_RUN_FIRST,
+                                gobject.TYPE_NONE, (str,str)),
+        "action-show-console": (gobject.SIGNAL_RUN_FIRST,
+                                gobject.TYPE_NONE, (str,str)),
+        "action-exit-app": (gobject.SIGNAL_RUN_FIRST,
+                            gobject.TYPE_NONE, []),
+    }
+
+    def __init__(self, config, engine):
+        self.__gobject_init__()
+
+        self.config = config
+        self.engine = engine
+
+        self.conn_menuitems = {}
+        self.conn_vm_menuitems = {}
+        self.vm_action_dict = {}
+        self.systray_menu = None
+        self.systray_icon = None
+
+        self.init_systray_menu()
+
+        self.engine.connect("connection-added", self.conn_added)
+        self.engine.connect("connection-removed", self.conn_removed)
+
+        self.config.on_view_system_tray_changed(self.show_systray)
+        self.show_systray()
+
+
+    # Initialization routines
+
+    def init_systray_menu(self):
+        """
+        Do we want notifications?
+
+        Close App
+        Hide app? As in, only have systray active? is that possible?
+            Have one of those 'minimize to tray' notifications?
+
+        """
+        self.systray_menu = gtk.Menu()
+
+        self.systray_menu.add(gtk.SeparatorMenuItem())
+        exit_item = gtk.ImageMenuItem(gtk.STOCK_QUIT)
+        exit_item.connect("activate", self.exit_app)
+        self.systray_menu.add(exit_item)
+        self.systray_menu.show_all()
+
+    def init_systray(self, show):
+        # Build the systray icon
+        if self.systray_icon:
+            return
+
+        iconfile = self.config.get_icon_dir() + "/virt-manager-icon.svg"
+        self.systray_icon = gtk.StatusIcon()
+        self.systray_icon.set_visible(show)
+        self.systray_icon.set_property("file", iconfile)
+        self.systray_icon.connect("activate", self.systray_activate)
+        self.systray_icon.connect("popup-menu", self.systray_popup)
+        self.systray_icon.set_tooltip(_("Virtual Machine Manager"))
+
+    def show_systray(self, ignore1=None, ignore2=None, ignore3=None,
+                     ignore4=None):
+        do_show = self.config.get_view_system_tray()
+
+        if not self.systray_icon:
+            self.init_systray(show=do_show)
+        else:
+            self.systray_icon.set_visible(do_show)
+
+    def build_vm_menu(self, vm):
+        icon_size = gtk.ICON_SIZE_MENU
+        stop_icon = self.config.get_shutdown_icon_name()
+
+        pause_item = gtk.ImageMenuItem(_("_Pause"))
+        pause_img  = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE, icon_size)
+        pause_item.set_image(pause_img)
+        pause_item.connect("activate", self.run_vm_action,
+                           "action-suspend-domain", vm.get_uuid())
+
+        resume_item = gtk.ImageMenuItem(_("_Resume"))
+        resume_img  = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE,
+                                               icon_size)
+        resume_item.set_image(resume_img)
+        resume_item.connect("activate", self.run_vm_action,
+                            "action-resume-domain", vm.get_uuid())
+
+        run_item = gtk.ImageMenuItem(_("_Run"))
+        run_img  = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY, icon_size)
+        run_item.set_image(run_img)
+        run_item.connect("activate", self.run_vm_action,
+                         "action-run-domain", vm.get_uuid())
+
+        # Shutdown menu
+        reboot_item = gtk.ImageMenuItem(_("_Reboot"))
+        reboot_img = gtk.image_new_from_icon_name(stop_icon, icon_size)
+        reboot_item.set_image(reboot_img)
+        reboot_item.connect("activate", self.run_vm_action,
+                            "action-reboot-domain", vm.get_uuid())
+        reboot_item.show()
+
+        shutdown_item = gtk.ImageMenuItem(_("_Shut Down"))
+        shutdown_img = gtk.image_new_from_icon_name(stop_icon, icon_size)
+        shutdown_item.set_image(shutdown_img)
+        shutdown_item.connect("activate", self.run_vm_action,
+                              "action-shutdown-domain", vm.get_uuid())
+        shutdown_item.show()
+
+        destroy_item = gtk.ImageMenuItem(_("_Force Off"))
+        destroy_img = gtk.image_new_from_icon_name(stop_icon, icon_size)
+        destroy_item.set_image(destroy_img)
+        destroy_item.show()
+        destroy_item.connect("activate", self.run_vm_action,
+                             "action-destroy-domain", vm.get_uuid())
+
+        shutdown_menu = gtk.Menu()
+        shutdown_menu.add(reboot_item)
+        shutdown_menu.add(shutdown_item)
+        shutdown_menu.add(destroy_item)
+        shutdown_menu_item = gtk.ImageMenuItem(_("_Shut Down"))
+        shutdown_menu_img = gtk.image_new_from_icon_name(stop_icon, icon_size)
+        shutdown_menu_item.set_image(shutdown_menu_img)
+        shutdown_menu_item.set_submenu(shutdown_menu)
+
+        sep = gtk.SeparatorMenuItem()
+
+        open_item = gtk.ImageMenuItem("gtk-open")
+        open_item.show()
+        open_item.connect("activate", self.run_vm_action,
+                          "action-show-console", vm.get_uuid())
+
+        vm_action_dict = {}
+        vm_action_dict["run"] = run_item
+        vm_action_dict["pause"] = pause_item
+        vm_action_dict["resume"] = resume_item
+        vm_action_dict["shutdown_menu"] = shutdown_menu_item
+        vm_action_dict["reboot"] = reboot_item
+        vm_action_dict["shutdown"] = shutdown_item
+        vm_action_dict["destroy"] = destroy_item
+        vm_action_dict["sep"] = sep
+        vm_action_dict["open"] = open_item
+
+        menu = gtk.Menu()
+
+        for key in ["run", "pause", "resume", "shutdown_menu", "sep", "open"]:
+            item = vm_action_dict[key]
+            item.show_all()
+            menu.add(vm_action_dict[key])
+
+        return menu, vm_action_dict
+
+    # Helper functions
+    def _get_vm_menu_item(self, vm):
+        uuid = vm.get_uuid()
+        uri = vm.get_connection().get_uri()
+
+        if self.conn_vm_menuitems.has_key(uri):
+            if self.conn_vm_menuitems[uri].has_key(uuid):
+                return self.conn_vm_menuitems[uri][uuid]
+        return None
+
+    def _set_vm_status_icon(self, vm, menu_item):
+        image = gtk.image_new_from_pixbuf(vm.run_status_icon())
+        image.set_sensitive(vm.is_active())
+        menu_item.set_image(image)
+
+    # Listeners
+
+    def systray_activate(self, widget):
+        self.emit("action-view-manager")
+
+    def systray_popup(self, widget, button, event_time):
+        if button != 3:
+            return
+
+        self.systray_menu.popup(None, None, None, 0, event_time)
+
+    def conn_added(self, engine, conn):
+        conn.connect("vm-added", self.vm_added)
+        conn.connect("vm-removed", self.vm_removed)
+        conn.connect("state-changed", self.conn_state_changed)
+
+        if self.conn_menuitems.has_key(conn.get_uri()):
+            return
+
+        menu_item = gtk.MenuItem(conn.get_pretty_desc_inactive())
+        menu_item.show()
+        vm_submenu = gtk.Menu()
+        vm_submenu.show()
+        menu_item.set_submenu(vm_submenu)
+
+        self.conn_menuitems[conn.get_uri()] = menu_item
+        self.conn_vm_menuitems[conn.get_uri()] = {}
+
+        # Insert conn in list before 'Quit' item
+        idx = len(self.systray_menu) - 2
+        self.systray_menu.insert(menu_item, idx)
+
+        self.conn_state_changed(conn)
+        self.populate_vm_list(conn)
+
+    def conn_removed(self, engine, conn):
+        if not self.conn_menuitems.has_key(conn.get_uri()):
+            return
+
+        menu_item = self.conn_menuitems[conn.get_uri()]
+        self.systray_menu.remove(menu_item)
+        del(self.conn_menuitems[conn.get_uri()])
+        self.conn_vm_menuitems[conn.get_uri()] = {}
+
+    def conn_state_changed(self, conn):
+        # XXX: Even 'paused' conn?
+        sensitive = conn.is_active()
+        menu_item = self.conn_menuitems[conn.get_uri()]
+        menu_item.set_sensitive(sensitive)
+
+    def populate_vm_list(self, conn):
+        uri = conn.get_uri()
+        conn_menu_item = self.conn_menuitems[uri]
+        vm_submenu = conn_menu_item.get_submenu()
+
+        # Empty conn menu
+        for c in vm_submenu.get_children():
+            vm_submenu.remove(c)
+
+        vm_mappings = {}
+        for vm in conn.vms.values():
+            vm_mappings[vm.get_name()] = vm.get_uuid()
+
+        vm_names = vm_mappings.keys()
+        vm_names.sort()
+
+        if len(vm_names) == 0:
+            menu_item = gtk.MenuItem(_("No virtual machines"))
+            menu_item.set_sensitive(False)
+            vm_submenu.insert(menu_item, 0)
+            return
+
+        for i in range(0, len(vm_names)):
+            name = vm_names[i]
+            uuid = vm_mappings[name]
+            if self.conn_vm_menuitems[uri].has_key(uuid):
+                vm_item = self.conn_vm_menuitems[uri][uuid]
+                vm_submenu.insert(vm_item, i)
+
+    def vm_added(self, conn, uri, uuid):
+        vm = conn.get_vm(uuid)
+        if not vm:
+            return
+        vm.connect("status-changed", self.vm_state_changed)
+
+        vm_mappings = self.conn_vm_menuitems[uri]
+        if vm_mappings.has_key(uuid):
+            return
+
+        # Build VM list entry
+        menu_item = gtk.ImageMenuItem(vm.get_name())
+        vm_mappings[uuid] = menu_item
+        vm_action_menu, vm_action_dict = self.build_vm_menu(vm)
+        menu_item.set_submenu(vm_action_menu)
+        self.vm_action_dict[uuid] = vm_action_dict
+
+        # Add VM to menu list
+        self.populate_vm_list(conn)
+
+        # Update state
+        self.vm_state_changed(vm)
+        menu_item.show()
+
+    def vm_removed(self, conn, uri, uuid):
+        vm_mappings = self.conn_vm_menuitems[uri]
+        if not vm_mappings:
+            return
+
+        if vm_mappings.has_key(uuid):
+            conn_item = self.conn_menuitems[uri]
+            vm_menu_item = vm_mappings[uuid]
+            vm_menu = conn_item.get_submenu()
+            vm_menu.remove(vm_menu_item)
+            del(vm_mappings[uuid])
+
+            if len(vm_menu.get_children()) == 0:
+                placeholder = gtk.MenuItem(_("No VMs available"))
+                placeholder.show()
+                placeholder.set_sensitive(False)
+                vm_menu.add(placeholder)
+
+    def vm_state_changed(self, vm, ignore=None):
+        menu_item = self._get_vm_menu_item(vm)
+        if not menu_item:
+            return
+
+        self._set_vm_status_icon(vm, menu_item)
+
+        # Update action widget states
+        actions = self.vm_action_dict[vm.get_uuid()]
+
+        is_paused = vm.is_paused()
+        actions["run"].set_sensitive(vm.is_runable())
+        actions["pause"].set_sensitive(vm.is_pauseable())
+        actions["resume"].set_sensitive(vm.is_paused())
+        actions["shutdown_menu"].set_sensitive(vm.is_active())
+        actions["shutdown"].set_sensitive(vm.is_stoppable())
+        actions["reboot"].set_sensitive(vm.is_stoppable())
+        actions["destroy"].set_sensitive(vm.is_destroyable())
+
+        actions["pause"].set_property("visible", not is_paused)
+        actions["resume"].set_property("visible", is_paused)
+
+    def run_vm_action(self, ignore, signal_name, uuid):
+        uri = None
+        for tmpuri, vm_mappings in self.conn_vm_menuitems.items():
+            if vm_mappings.get(uuid):
+                uri = tmpuri
+                break
+
+        if not uri:
+            return
+
+        self.emit(signal_name, uri, uuid)
+
+    def exit_app(self, ignore):
+        self.emit("action-exit-app")
+
+gobject.type_register(vmmSystray)
diff -r 860d7c2bfb8c -r 0a08550c10fe src/vmm-preferences.glade
--- a/src/vmm-preferences.glade	Sun Jul 26 16:25:01 2009 -0400
+++ b/src/vmm-preferences.glade	Sun Jul 26 16:43:16 2009 -0400
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.4.5 on Wed Jul 22 23:26:58 2009 -->
+<!--Generated with glade3 3.4.5 on Fri Jul 24 11:42:36 2009 -->
 <glade-interface>
   <widget class="GtkWindow" id="vmm-preferences">
     <property name="title" translatable="yes">Preferences</property>
@@ -17,6 +17,70 @@
             <property name="can_focus">True</property>
             <property name="border_width">3</property>
             <child>
+              <widget class="GtkVBox" id="vbox5">
+                <property name="visible">True</property>
+                <property name="border_width">6</property>
+                <child>
+                  <widget class="GtkFrame" id="frame5">
+                    <property name="visible">True</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">GTK_SHADOW_NONE</property>
+                    <child>
+                      <widget class="GtkAlignment" id="alignment7">
+                        <property name="visible">True</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <widget class="GtkTable" id="table5">
+                            <property name="visible">True</property>
+                            <property name="n_rows">2</property>
+                            <property name="column_spacing">6</property>
+                            <property name="row_spacing">6</property>
+                            <child>
+                              <placeholder/>
+                            </child>
+                            <child>
+                              <widget class="GtkCheckButton" id="prefs-system-tray">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="label" translatable="yes">Enable system tray icon</property>
+                                <property name="response_id">0</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="on_prefs_system_tray_toggled"/>
+                              </widget>
+                              <packing>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label12">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="type">label_item</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label11">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">General</property>
+              </widget>
+              <packing>
+                <property name="type">tab</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
               <widget class="GtkVBox" id="vbox2">
                 <property name="visible">True</property>
                 <property name="border_width">6</property>
@@ -38,34 +102,27 @@
                             <property name="column_spacing">3</property>
                             <property name="row_spacing">3</property>
                             <child>
-                              <widget class="GtkLabel" id="label6">
+                              <widget class="GtkLabel" id="label9">
                                 <property name="visible">True</property>
                                 <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Update status every</property>
-                              </widget>
-                            </child>
-                            <child>
-                              <widget class="GtkLabel" id="label7">
-                                <property name="visible">True</property>
-                                <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Maintain history of</property>
+                                <property name="label" translatable="yes">samples</property>
                               </widget>
                               <packing>
+                                <property name="left_attach">2</property>
+                                <property name="right_attach">3</property>
                                 <property name="top_attach">1</property>
                                 <property name="bottom_attach">2</property>
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkSpinButton" id="prefs-stats-update-interval">
+                              <widget class="GtkLabel" id="label8">
                                 <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="adjustment">0 0 60 1 5 0</property>
-                                <signal name="value_changed" handler="on_prefs_stats_update_interval_changed"/>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">seconds</property>
                               </widget>
                               <packing>
-                                <property name="left_attach">1</property>
-                                <property name="right_attach">2</property>
-                                <property name="x_options">GTK_FILL</property>
+                                <property name="left_attach">2</property>
+                                <property name="right_attach">3</property>
                               </packing>
                             </child>
                             <child>
@@ -85,29 +142,36 @@
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkLabel" id="label8">
+                              <widget class="GtkSpinButton" id="prefs-stats-update-interval">
                                 <property name="visible">True</property>
-                                <property name="xalign">0</property>
-                                <property name="label" translatable="yes">seconds</property>
+                                <property name="can_focus">True</property>
+                                <property name="adjustment">0 0 60 1 5 0</property>
+                                <signal name="value_changed" handler="on_prefs_stats_update_interval_changed"/>
                               </widget>
                               <packing>
-                                <property name="left_attach">2</property>
-                                <property name="right_attach">3</property>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="x_options">GTK_FILL</property>
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkLabel" id="label9">
+                              <widget class="GtkLabel" id="label7">
                                 <property name="visible">True</property>
                                 <property name="xalign">0</property>
-                                <property name="label" translatable="yes">samples</property>
+                                <property name="label" translatable="yes">Maintain history of</property>
                               </widget>
                               <packing>
-                                <property name="left_attach">2</property>
-                                <property name="right_attach">3</property>
                                 <property name="top_attach">1</property>
                                 <property name="bottom_attach">2</property>
                               </packing>
                             </child>
+                            <child>
+                              <widget class="GtkLabel" id="label6">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Update status every</property>
+                              </widget>
+                            </child>
                           </widget>
                         </child>
                       </widget>
@@ -156,25 +220,19 @@
                               <placeholder/>
                             </child>
                             <child>
-                              <widget class="GtkLabel" id="label13">
+                              <widget class="GtkCheckButton" id="prefs-stats-enable-net">
                                 <property name="visible">True</property>
-                                <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Disk I/O</property>
+                                <property name="can_focus">True</property>
+                                <property name="response_id">0</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="on_prefs_stats_enable_net_toggled"/>
                               </widget>
                               <packing>
-                                <property name="x_options">GTK_FILL</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <widget class="GtkLabel" id="label14">
-                                <property name="visible">True</property>
-                                <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Network I/O</property>
-                              </widget>
-                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
                                 <property name="top_attach">1</property>
                                 <property name="bottom_attach">2</property>
-                                <property name="x_options">GTK_FILL</property>
+                                <property name="x_options">GTK_EXPAND</property>
                               </packing>
                             </child>
                             <child>
@@ -192,19 +250,25 @@
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkCheckButton" id="prefs-stats-enable-net">
+                              <widget class="GtkLabel" id="label14">
                                 <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="response_id">0</property>
-                                <property name="draw_indicator">True</property>
-                                <signal name="toggled" handler="on_prefs_stats_enable_net_toggled"/>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Network I/O</property>
                               </widget>
                               <packing>
-                                <property name="left_attach">1</property>
-                                <property name="right_attach">2</property>
                                 <property name="top_attach">1</property>
                                 <property name="bottom_attach">2</property>
-                                <property name="x_options">GTK_EXPAND</property>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkLabel" id="label13">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Disk I/O</property>
+                              </widget>
+                              <packing>
+                                <property name="x_options">GTK_FILL</property>
                               </packing>
                             </child>
                           </widget>
@@ -228,6 +292,9 @@
                   </packing>
                 </child>
               </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
             </child>
             <child>
               <widget class="GtkLabel" id="label2">
@@ -236,6 +303,7 @@
               </widget>
               <packing>
                 <property name="type">tab</property>
+                <property name="position">1</property>
                 <property name="tab_fill">False</property>
               </packing>
             </child>
@@ -259,35 +327,28 @@
                             <property name="n_rows">6</property>
                             <property name="row_spacing">3</property>
                             <child>
-                              <widget class="GtkComboBox" id="prefs-console-popup">
+                              <widget class="GtkComboBox" id="prefs-console-scaling">
                                 <property name="visible">True</property>
                                 <property name="items" translatable="yes">Never
-For all new domains
-For all domains</property>
-                                <signal name="changed" handler="on_prefs_console_popup_changed"/>
+Fullscreen only
+Always</property>
+                                <signal name="changed" handler="on_prefs_console_scaling_changed"/>
                               </widget>
                               <packing>
-                                <property name="top_attach">1</property>
-                                <property name="bottom_attach">2</property>
+                                <property name="top_attach">5</property>
+                                <property name="bottom_attach">6</property>
                                 <property name="x_padding">5</property>
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkLabel" id="label5">
+                              <widget class="GtkLabel" id="label17">
                                 <property name="visible">True</property>
                                 <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Automatically open consoles:</property>
-                              </widget>
-                            </child>
-                            <child>
-                              <widget class="GtkLabel" id="label15">
-                                <property name="visible">True</property>
-                                <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Grab keyboard input:</property>
+                                <property name="label" translatable="yes">Graphical Console Scaling:</property>
                               </widget>
                               <packing>
-                                <property name="top_attach">2</property>
-                                <property name="bottom_attach">3</property>
+                                <property name="top_attach">4</property>
+                                <property name="bottom_attach">5</property>
                               </packing>
                             </child>
                             <child>
@@ -305,27 +366,34 @@
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkLabel" id="label17">
+                              <widget class="GtkLabel" id="label15">
                                 <property name="visible">True</property>
                                 <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Graphical Console Scaling:</property>
+                                <property name="label" translatable="yes">Grab keyboard input:</property>
                               </widget>
                               <packing>
-                                <property name="top_attach">4</property>
-                                <property name="bottom_attach">5</property>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkComboBox" id="prefs-console-scaling">
+                              <widget class="GtkLabel" id="label5">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Automatically open consoles:</property>
+                              </widget>
+                            </child>
+                            <child>
+                              <widget class="GtkComboBox" id="prefs-console-popup">
                                 <property name="visible">True</property>
                                 <property name="items" translatable="yes">Never
-Fullscreen only
-Always</property>
-                                <signal name="changed" handler="on_prefs_console_scaling_changed"/>
+For all new domains
+For all domains</property>
+                                <signal name="changed" handler="on_prefs_console_popup_changed"/>
                               </widget>
                               <packing>
-                                <property name="top_attach">5</property>
-                                <property name="bottom_attach">6</property>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
                                 <property name="x_padding">5</property>
                               </packing>
                             </child>
@@ -363,13 +431,6 @@
                             <property name="n_rows">2</property>
                             <property name="column_spacing">8</property>
                             <child>
-                              <widget class="GtkLabel" id="label16">
-                                <property name="visible">True</property>
-                                <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Install Audio Device:</property>
-                              </widget>
-                            </child>
-                            <child>
                               <widget class="GtkAlignment" id="alignment6">
                                 <property name="visible">True</property>
                                 <property name="left_padding">12</property>
@@ -407,6 +468,13 @@
                                 <property name="bottom_attach">2</property>
                               </packing>
                             </child>
+                            <child>
+                              <widget class="GtkLabel" id="label16">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Install Audio Device:</property>
+                              </widget>
+                            </child>
                           </widget>
                         </child>
                       </widget>
@@ -429,7 +497,7 @@
                 </child>
               </widget>
               <packing>
-                <property name="position">1</property>
+                <property name="position">2</property>
               </packing>
             </child>
             <child>
@@ -439,7 +507,7 @@
               </widget>
               <packing>
                 <property name="type">tab</property>
-                <property name="position">1</property>
+                <property name="position">2</property>
                 <property name="tab_fill">False</property>
               </packing>
             </child>

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]