From efbc815a605689bb0c94e0bf4dfb3703505b9aab Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Mon, 2 Sep 2013 11:54:36 -0400 Subject: [PATCH] addhardware: Modernize 'graphics' UI - Drop SDL, it doesn't mesh with modern libvirt - Drop keymap, modern qemu/virt-manager handle this automagically - Drop big text fields - Misc other cleanups and simplifications --- ui/vmm-add-hardware.ui | 560 +++++++++++++------------------------ virtManager/addhardware.py | 116 +++----- virtManager/autodrawer.py | 25 +- virtManager/uihelpers.py | 27 ++ 4 files changed, 274 insertions(+), 454 deletions(-) diff --git a/ui/vmm-add-hardware.ui b/ui/vmm-add-hardware.ui index 8bd2fee37..9921f53b6 100644 --- a/ui/vmm-add-hardware.ui +++ b/ui/vmm-add-hardware.ui @@ -1011,379 +1011,23 @@ False 12 - + True False - 7 - 2 - 6 6 - - - True - False - 1 - _Type: - True - graphics-type - - - GTK_FILL - - - + 6 True False + start 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - False - 1 - _Address: - True - graphics-address - - - 2 - 3 - GTK_FILL - - - - - - True - False - 1 - _Port: - True - graphics-port - - - 3 - 4 - GTK_FILL - - - - - - True - False - 1 - Pa_ssword: - True - graphics-password - - - 5 - 6 - GTK_FILL - - - - - - True - False - 6 - - - True - False - - - True - False - 0 - gtk-dialog-info - - - False - True - 0 - - - - - True - False - 0 - 7 - <small><b>Tip:</b> VNC or Spice server is strongly recommended because it allows the virtual display to be embedded inside this application. It may also be used to allow access to the virtual display from a remote system.</small> - True - True - 50 - - - False - False - 1 - - - - - - - 1 - 2 - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - False - 6 - 20 - - - - - - 1 - 2 - 4 - 5 - GTK_FILL - GTK_FILL - - - - - Listen on all public network interfaces - True - True - False - True - 0.5 - True - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 1 - _Keymap: - True - graphics-keymap-chk - - - 6 - 7 - GTK_FILL - GTK_FILL - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 4 - - - Same as host - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - half - 0.5 - True - - - - GTK_FILL - GTK_FILL - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - 1 - 2 - - - 17 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - _Other: - True - graphics-keymap - - - 2 - 3 - - - 10 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - 3 - 4 - - - - - - 1 - 2 - 6 - 7 - GTK_FILL - GTK_FILL - - - - - True - False - - - - - - 4 - 5 - GTK_FILL - GTK_FILL - - - - - True - False - - - - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - False - 4 - 6 - - - True - False - 1 - _TLS port: - True - graphics-port - - - 1 - 2 - - - - - - True - True - - adjustment5 - 1 - True - True - if-valid - - - GTK_FILL - - - - - A_utomatically allocated - True - True - False - True - 0.5 - True - - - - 3 - 4 - GTK_FILL - - - - - True - True - - adjustment4 - 1 - True - True - if-valid - - - 2 - 3 - GTK_FILL - - - - - 1 - 2 - 3 - 4 - GTK_FILL + 0 + 1 + 1 @@ -1423,9 +1067,195 @@ 1 - 2 - 5 - 6 + 4 + 1 + 1 + + + + + True + False + 1 + _Type: + True + graphics-type + + + 0 + 0 + 1 + 1 + + + + + True + False + 1 + _Address: + True + graphics-address + + + 0 + 1 + 1 + 1 + + + + + True + False + 1 + Pa_ssword: + True + graphics-password + + + 0 + 4 + 1 + 1 + + + + + True + False + 1 + _Port: + True + graphics-port + + + 0 + 2 + 1 + 1 + + + + + True + False + + + + + + 0 + 3 + 1 + 1 + + + + + A_utomatically allocated + True + True + False + True + 0 + True + + + + 1 + 2 + 1 + 1 + + + + + True + False + 12 + + + True + True + + True + adjustment5 + 1 + True + True + if-valid + + + False + True + 0 + + + + + True + False + 6 + + + True + False + 1 + _TLS port: + True + graphics-port + + + False + True + 0 + + + + + True + True + + True + adjustment4 + 1 + True + True + if-valid + + + False + True + 1 + + + + + False + True + 1 + + + + + 1 + 3 + 1 + 1 + + + + + True + False + start + + + 1 + 1 + 1 + 1 diff --git a/virtManager/addhardware.py b/virtManager/addhardware.py index f57523a63..d65151c8e 100644 --- a/virtManager/addhardware.py +++ b/virtManager/addhardware.py @@ -96,7 +96,6 @@ class vmmAddHardware(vmmGObjectUI): "on_graphics_type_changed": self.change_graphics_type, "on_graphics_port_auto_toggled": self.change_port_auto, - "on_graphics_keymap_toggled": self.change_keymap, "on_graphics_use_password": self.change_password_chk, "on_char_device_type_changed": self.change_char_device_type, @@ -274,6 +273,13 @@ class vmmAddHardware(vmmGObjectUI): graphics_list.pack_start(text, True) graphics_list.add_attribute(text, 'text', 0) + # Graphics address + # [label, value] + self.widget("graphics-address").set_model(Gtk.ListStore(str, str)) + text = Gtk.CellRendererText() + self.widget("graphics-address").pack_start(text, True) + self.widget("graphics-address").add_attribute(text, 'text', 0) + # Sound model list sound_list = self.widget("sound-model") uihelpers.build_sound_combo(self.vm, sound_list) @@ -462,17 +468,22 @@ class vmmAddHardware(vmmGObjectUI): input_box.set_active(0) # Graphics init - self.change_port_auto() graphics_box = self.widget("graphics-type") self.populate_graphics_model(graphics_box.get_model()) graphics_box.set_active(0) - self.widget("graphics-address").set_active(False) + + model = self.widget("graphics-address").get_model() + model.clear() + model.append([_("Hypervisor default"), None]) + model.append([_("Localhost only"), "127.0.0.1"]) + model.append([_("All interfaces"), "0.0.0.0"]) + self.widget("graphics-address").set_active(0) + + self.change_port_auto() self.widget("graphics-port-auto").set_active(True) self.widget("graphics-password").set_text("") self.widget("graphics-password").set_sensitive(False) self.widget("graphics-password-chk").set_active(False) - self.widget("graphics-keymap").set_text("") - self.widget("graphics-keymap-chk").set_active(True) # Sound init sound_box = self.widget("sound-model") @@ -563,9 +574,8 @@ class vmmAddHardware(vmmGObjectUI): def populate_graphics_model(self, model): model.clear() - model.append([_("VNC server"), "vnc"]) model.append([_("Spice server"), "spice"]) - model.append([_("Local SDL window"), "sdl"]) + model.append([_("VNC server"), "vnc"]) def populate_host_device_model(self, devtype, devcap, subtype, subcap): devlist = self.widget("host-device") @@ -663,38 +673,25 @@ class vmmAddHardware(vmmGObjectUI): return None return _type.get_model().get_value(_type.get_active_iter(), 1) - def get_config_graphics_port(self): - port = self.widget("graphics-port") - portAuto = self.widget("graphics-port-auto") - if portAuto.get_active(): - return -1 - return int(port.get_value()) + def get_config_graphics_ports(self): + if self.widget("graphics-port-auto").get_active(): + return -1, -1 - def get_config_graphics_tls_port(self): - port = self.widget("graphics-tls-port") - portAuto = self.widget("graphics-port-auto") - if portAuto.get_active(): - return -1 - return int(port.get_value()) + port = self.widget("graphics-port").get_value() + tlsport = self.widget("graphics-tls-port").get_value() + if not self.widget("graphics-tls-port").get_visible(): + tlsport = -1 + return int(port), int(tlsport) def get_config_graphics_address(self): addr = self.widget("graphics-address") - if addr.get_active(): - return "0.0.0.0" - return "127.0.0.1" + return addr.get_model()[addr.get_active()][1] def get_config_graphics_password(self): if not self.widget("graphics-password-chk").get_active(): return None return self.widget("graphics-password").get_text() - def get_config_keymap(self): - g = self.widget("graphics-keymap") - if g.get_sensitive() and g.get_text() != "": - return g.get_text() - else: - return None - # Network getters def get_config_network(self): net_list = self.widget("net-list") @@ -959,44 +956,17 @@ class vmmAddHardware(vmmGObjectUI): # Graphics listeners def change_graphics_type(self, ignore=None): - graphics = self.get_config_graphics() - if graphics in ["vnc", "spice"]: - self.widget("graphics-port-auto").set_sensitive(True) - self.widget("graphics-address").set_sensitive(True) - # Skip this code if the checkbox value is not changed. In this way - # the password field maintains its value. - if not self.widget("graphics-password-chk").get_sensitive(): - self.widget("graphics-password").set_sensitive(False) - self.widget("graphics-password-chk").set_sensitive(True) - self.widget("graphics-password-chk").set_active(False) - self.widget("graphics-keymap-chk").set_sensitive(True) - self.change_port_auto() - else: - self.widget("graphics-port").set_sensitive(False) - self.widget("graphics-tls-port").set_sensitive(False) - self.widget("graphics-port-auto").set_sensitive(False) - self.widget("graphics-address").set_sensitive(False) - self.widget("graphics-password").set_sensitive(False) - self.widget("graphics-password-chk").set_sensitive(False) - self.widget("graphics-password-chk").set_active(False) - self.widget("graphics-keymap-chk").set_sensitive(False) - self.widget("graphics-keymap").set_sensitive(False) + self.change_port_auto() def change_port_auto(self, ignore=None): - graphics = self.get_config_graphics() - tls_enable = graphics == "spice" - if self.widget("graphics-port-auto").get_active(): - self.widget("graphics-port").set_sensitive(False) - self.widget("graphics-tls-port").set_sensitive(False) - else: - self.widget("graphics-port").set_sensitive(True) - self.widget("graphics-tls-port").set_sensitive(tls_enable) + gtype = self.get_config_graphics() + is_auto = self.widget("graphics-port-auto").get_active() + is_spice = (gtype == "spice") - def change_keymap(self, ignore=None): - if self.widget("graphics-keymap-chk").get_active(): - self.widget("graphics-keymap").set_sensitive(False) - else: - self.widget("graphics-keymap").set_sensitive(True) + uihelpers.set_grid_row_visible(self.widget("graphics-port-box"), + not is_auto) + self.widget("graphics-port-box").set_visible(not is_auto) + self.widget("graphics-tlsport-box").set_visible(is_spice) def change_password_chk(self, ignore=None): if self.widget("graphics-password-chk").get_active(): @@ -1154,13 +1124,12 @@ class vmmAddHardware(vmmGObjectUI): show_mode = bool( fsdriver == virtinst.VirtualFilesystem.DRIVER_PATH or fsdriver == virtinst.VirtualFilesystem.DRIVER_DEFAULT) - self.widget("fs-mode-title").set_visible(show_mode) - self.widget("fs-mode-box").set_visible(show_mode) + uihelpers.set_grid_row_visible(self.widget("fs-mode-box"), show_mode) show_wrpol = bool( fsdriver and fsdriver != virtinst.VirtualFilesystem.DRIVER_DEFAULT) - self.widget("fs-wrpolicy-title").set_visible(show_wrpol) - self.widget("fs-wrpolicy-box").set_visible(show_wrpol) + uihelpers.set_grid_row_visible(self.widget("fs-wrpolicy-box"), + show_wrpol) @@ -1437,15 +1406,14 @@ class vmmAddHardware(vmmGObjectUI): gtype = self.get_config_graphics() try: + port, tlsport = self.get_config_graphics_ports() self._dev = virtinst.VirtualGraphics(self.conn.get_backend()) self._dev.type = gtype - if gtype != "sdl": - self._dev.port = self.get_config_graphics_port() - self._dev.passwd = self.get_config_graphics_password() - self._dev.listen = self.get_config_graphics_address() - self._dev.keymap = self.get_config_keymap() + self._dev.port = port + self._dev.passwd = self.get_config_graphics_password() + self._dev.listen = self.get_config_graphics_address() if gtype == "spice": - self._dev.tlsPort = self.get_config_graphics_tls_port() + self._dev.tlsPort = tlsport except ValueError, e: self.err.val_err(_("Graphics device parameter error"), e) diff --git a/virtManager/autodrawer.py b/virtManager/autodrawer.py index 1f6fe4738..b8e181da3 100644 --- a/virtManager/autodrawer.py +++ b/virtManager/autodrawer.py @@ -25,10 +25,11 @@ # pylint: disable=E0611 from gi.repository import Gdk from gi.repository import GLib -from gi.repository import GObject from gi.repository import Gtk # pylint: enable=E0611 +from virtManager import uihelpers + # pylint: disable=E1101 # pylint can't detect functions we inheirit from Gtk, ex: # OverBox.set_over: Instance of 'OverBox' has no 'remove' member @@ -91,9 +92,11 @@ class OverBox(Gtk.Box): actual_min = self._get_actual_min() if self.overWidget: - expand = self.child_get_property(self.overWidget, "expand") - fill = self.child_get_property(self.overWidget, "fill") - padding = self.child_get_property(self.overWidget, "padding") + expand = uihelpers.child_get_property(self, self.overWidget, + "expand") + fill = uihelpers.child_get_property(self, self.overWidget, "fill") + padding = uihelpers.child_get_property(self, self.overWidget, + "padding") # XXX: On Fedora 19 child_get_property isn't working :( expand = True @@ -129,14 +132,6 @@ class OverBox(Gtk.Box): # Custom functionality # ######################## - def child_get_property(self, widget, propname): - # gtk3 bindings are crappy here, make it work like - # gobject.get_property() - value = GObject.Value() - value.init(GObject.TYPE_INT) - Gtk.Box.child_get_property(self, widget, propname, value) - return value.get_int() - def do_set_over(self, widget): self.set_over(widget) @@ -264,9 +259,9 @@ class OverBox(Gtk.Box): self.overWidth = over.width self.overHeight = over.height - expand = self.child_get_property(self.overWidget, "expand") - fill = self.child_get_property(self.overWidget, "fill") - padding = self.child_get_property(self.overWidget, "padding") + expand = uihelpers.child_get_property(self, self.overWidget, "expand") + fill = uihelpers.child_get_property(self, self.overWidget, "fill") + padding = uihelpers.child_get_property(self, self.overWidget, "padding") if expand or fill: wpad = 0 diff --git a/virtManager/uihelpers.py b/virtManager/uihelpers.py index 2682d0719..f40f35908 100644 --- a/virtManager/uihelpers.py +++ b/virtManager/uihelpers.py @@ -23,6 +23,7 @@ import os import statvfs # pylint: disable=E0611 +from gi.repository import GObject from gi.repository import Gtk # pylint: enable=E0611 @@ -1358,6 +1359,32 @@ def set_list_selection(widget, rownum): selection.select_path(path) +def child_get_property(parent, child, propname): + # Wrapper for child_get_property, which pygobject doesn't properly + # introspect + value = GObject.Value() + value.init(GObject.TYPE_INT) + parent.child_get_property(child, propname, value) + return value.get_int() + + +def set_grid_row_visible(child, visible): + # For the passed widget, find its parent GtkGrid, and hide/show all + # elements that are in the same row as it. Simplifies having to name + # every element in a row when we want to dynamically hide things + # based on UI interraction + + parent = child.get_parent() + if not type(parent) is Gtk.Grid: + raise RuntimeError("Programming error, parent must be grid, " + "not %s" % type(parent)) + + row = child_get_property(parent, child, "top-attach") + for child in parent.get_children(): + if child_get_property(parent, child, "top-attach") == row: + child.set_visible(visible) + + def default_uri(always_system=False): if os.path.exists('/var/lib/xend'): if (os.path.exists('/dev/xen/evtchn') or