diff --git a/tests/uitests/test_details.py b/tests/uitests/test_details.py index 0292ac69..71fcef91 100644 --- a/tests/uitests/test_details.py +++ b/tests/uitests/test_details.py @@ -472,6 +472,7 @@ class Details(uiutils.UITestCase): tab.combo_select("Type:", "VNC") tab.combo_select("Listen type:", "Address") tab.find("graphics-port-auto", "check").click() + tab.find("graphics-port-auto", "check").click() tab.find("graphics-port", "spin button").set_text("6001") tab.find("Password:", "check").click() passwd = tab.find_fuzzy("graphics-password", "text") diff --git a/ui/gfxdetails.ui b/ui/gfxdetails.ui index f8711025..b55c7202 100644 --- a/ui/gfxdetails.ui +++ b/ui/gfxdetails.ui @@ -53,6 +53,7 @@ True True + start False @@ -297,45 +298,34 @@ - + True False - vertical - 3 + start + 6 + 6 - + True False - 3 - - - True - True - False - True - - - - False - True - 0 - - - - - False - gtk-dialog-warning - - - False - True - 1 - - + start + gtk-dialog-warning 0 - 0 + 1 + + + + + True + False + start + gtk-dialog-warning + + + 0 + 2 @@ -360,14 +350,63 @@ 0 + 0 + 2 + + + + + True + False + start + OpenGL only works with 'virtio' graphics with '3D acceleration' enabled + True + + + + + + 1 1 + + + True + False + start + OpenGL only works with 'Listen type' value 'none' + True + + + + + + 1 + 2 + + + + + 1 + 6 + + + + + True + True + False + True + 1 5 + + + diff --git a/virtManager/details/details.py b/virtManager/details/details.py index 5557b08a..9ed6923d 100644 --- a/virtManager/details/details.py +++ b/virtManager/details/details.py @@ -2096,7 +2096,9 @@ class vmmDetails(vmmGObjectUI): _("Hypervisor does not support removing this device")) def _refresh_graphics_page(self, gfx): - title = self.gfxdetails.set_dev(gfx) + pretty_type = vmmGraphicsDetails.graphics_pretty_type_simple(gfx.type) + title = (_("%(graphicstype)s Server") % {"graphicstype": pretty_type}) + self.gfxdetails.set_dev(gfx) self.widget("graphics-title").set_markup("%s" % title) def _refresh_sound_page(self, sound): diff --git a/virtManager/device/gfxdetails.py b/virtManager/device/gfxdetails.py index 13ba7367..9f88eab9 100644 --- a/virtManager/device/gfxdetails.py +++ b/virtManager/device/gfxdetails.py @@ -33,8 +33,8 @@ class vmmGraphicsDetails(vmmGObjectUI): self.builder.connect_signals({ "on_graphics_type_changed": self._change_graphics_type, "on_graphics_port_auto_toggled": self._change_port_auto, - "on_graphics_use_password": self._change_password_chk, - "on_graphics_show_password": self._show_password_chk, + "on_graphics_use_password": self._change_password_cb, + "on_graphics_show_password": self._show_password_cb, "on_graphics_listen_type_changed": self._change_graphics_listen, "on_graphics_password_changed": lambda ignore: self.emit("changed-password"), @@ -114,6 +114,69 @@ class vmmGraphicsDetails(vmmGObjectUI): port = -1 return port + ############## + # UI syncing # + ############## + + def _sync_ui(self): + gtype = uiutil.get_list_selection(self.widget("graphics-type")) + is_vnc = gtype == "vnc" + is_spice = gtype == "spice" + + listen = uiutil.get_list_selection(self.widget("graphics-listen-type")) + has_listen_none = (listen in ["none", "socket"]) + + has_virtio_3d = bool([ + v for v in self.vm.xmlobj.devices.video if + (v.model == "virtio" and v.accel3d)]) + + uiutil.set_grid_row_visible( + self.widget("graphics-warn-virtio"), + not has_virtio_3d) + uiutil.set_grid_row_visible( + self.widget("graphics-warn-listen"), + not has_listen_none) + + passwd_enabled = self.widget("graphics-password-chk").get_active() + self.widget("graphics-password").set_sensitive(passwd_enabled) + if not passwd_enabled: + self.widget("graphics-password").set_text("") + passwd_visible = self.widget("graphics-visiblity-chk").get_active() + self.widget("graphics-password").set_visibility(passwd_visible) + + glval = self.widget("graphics-opengl").get_active() + uiutil.set_grid_row_visible( + self.widget("graphics-opengl-subopts-box"), + glval and is_spice) + + all_rows = [ + "graphics-listen-type", + "graphics-address", + "graphics-password-box", + "graphics-port-box", + "graphics-opengl", + "graphics-opengl-subopts-box", + ] + + is_auto = (self.widget("graphics-port-auto").get_active() or + self.widget("graphics-port-auto").get_inconsistent()) + self.widget("graphics-port").set_visible(not is_auto) + + rows = ["graphics-password-box", "graphics-listen-type"] + if listen == 'address': + rows.extend(["graphics-port-box", "graphics-address"]) + if is_spice: + rows.append("graphics-opengl") + if glval: + rows.append("graphics-opengl-subopts-box") + + if not is_vnc and not is_spice: + rows = [] + + for row in all_rows: + uiutil.set_grid_row_visible(self.widget(row), row in rows) + + ############## # Public API # @@ -128,13 +191,12 @@ class vmmGraphicsDetails(vmmGObjectUI): rendermodel = self.widget("graphics-rendernode").get_model() self.widget("graphics-rendernode").set_active_iter(rendermodel[-1].iter) - self._change_ports() 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-opengl").set_active(False) - self._sync_opengl_ui() + self._sync_ui() def get_values(self): gtype = uiutil.get_list_selection(self.widget("graphics-type")) @@ -146,156 +208,88 @@ class vmmGraphicsDetails(vmmGObjectUI): if not self.widget("graphics-password-chk").get_active(): passwd = None - gl = self.widget("graphics-opengl").get_active() + glval = self.widget("graphics-opengl").get_active() + if not self.widget("graphics-opengl").is_visible(): + glval = None + rendernode = uiutil.get_list_selection(self.widget("graphics-rendernode")) - if not self.widget("graphics-rendernode").get_visible(): + if not self.widget("graphics-rendernode").is_visible(): rendernode = None - return gtype, port, listen, addr, passwd, gl, rendernode + return gtype, port, listen, addr, passwd, glval, rendernode def set_dev(self, gfx): self.reset_state() - def set_port(basename, val): - auto = self.widget(basename + "-auto") - widget = self.widget(basename) - auto.set_inconsistent(False) - label = _("A_uto") + portval = gfx.port + portautolabel = _("A_uto") - if val == -1 or gfx.autoport: - auto.set_active(True) - if val and val != -1: # pragma: no cover - # Triggering this with the test driver is tough - # because it doesn't fill in runtime port values - label = _("A_uto (Port %(port)d)") % {"port": val} - elif val is None: - auto.set_inconsistent(True) - else: - auto.set_active(False) - widget.set_value(val) + if portval == -1 or gfx.autoport: + portauto = True + if portval and portval != -1: # pragma: no cover + # Triggering this with the test driver is tough + # because it doesn't fill in runtime port values + portautolabel = _("A_uto (Port %(port)d)") % {"port": portval} + elif portval is None: + portauto = None + else: + portauto = False - auto.set_label(label) + self.widget("graphics-port").set_value(portval or 0) + self.widget("graphics-port-auto").set_label(portautolabel) + self.widget("graphics-port-auto").set_active(bool(portauto)) + self.widget("graphics-port-auto").set_inconsistent(portauto is None) gtype = gfx.type - is_vnc = (gtype == "vnc") - is_spice = (gtype == "spice") - pretty_type = vmmGraphicsDetails.graphics_pretty_type_simple(gtype) - title = (_("%(graphicstype)s Server") % {"graphicstype": pretty_type}) - - if is_vnc or is_spice: - use_passwd = gfx.passwd is not None - - set_port("graphics-port", gfx.port) - listentype = gfx.get_first_listen_type() - if listentype and listentype == 'none': - uiutil.set_list_selection(self.widget("graphics-listen-type"), 'none') - else: - uiutil.set_list_selection(self.widget("graphics-listen-type"), 'address') - uiutil.set_list_selection( - self.widget("graphics-address"), gfx.listen) - - self.widget("graphics-password").set_text(gfx.passwd or "") - self.widget("graphics-password-chk").set_active(use_passwd) - self.widget("graphics-password").set_sensitive(use_passwd) - - if is_spice: - opengl_warning = "" - glval = bool(gfx.gl) - renderval = gfx.rendernode or None - - # If the config doesn't support spice GL, show a warning - # but still let the user set the value in case we are wrong - if not [v for v in self.vm.xmlobj.devices.video if - (v.model == "virtio" and v.accel3d)]: - opengl_warning = _("Spice GL requires " - "VirtIO graphics configured with accel3d.") - elif gfx.get_first_listen_type() not in ["none", "socket"]: - opengl_warning = _("Graphics listen type does not support " - "spice GL.") - - self.widget("graphics-opengl").set_active(glval) - if glval: - # Only sync rendernode UI with XML, if gl=on, otherwise - # we want to preserve the suggested rendernode already - # selected in the UI - uiutil.set_list_selection( - self.widget("graphics-rendernode"), renderval) - - self.widget("graphics-opengl-warn").set_tooltip_text( - opengl_warning or None) - self.widget("graphics-opengl-warn").set_visible( - bool(opengl_warning)) - uiutil.set_list_selection(self.widget("graphics-type"), gtype) - return title + + use_passwd = gfx.passwd is not None + self.widget("graphics-password").set_text(gfx.passwd or "") + self.widget("graphics-password-chk").set_active(use_passwd) + + listentype = gfx.get_first_listen_type() + uiutil.set_list_selection( + self.widget("graphics-listen-type"), listentype) + uiutil.set_list_selection( + self.widget("graphics-address"), gfx.listen) + + glval = bool(gfx.gl) + renderval = gfx.rendernode or None + self.widget("graphics-opengl").set_active(glval) + + if glval: + # Only sync rendernode UI with XML, if gl=on, otherwise + # we want to preserve the suggested rendernode already + # selected in the UI + uiutil.set_list_selection( + self.widget("graphics-rendernode"), renderval) ############# # Listeners # ############# - def _show_rows_from_type(self): - hide_all = ["graphics-address", - "graphics-password-box", "graphics-port-box", - "graphics-opengl-box"] - - gtype = uiutil.get_list_selection(self.widget("graphics-type")) - listen = uiutil.get_list_selection(self.widget("graphics-listen-type")) - - vnc_rows = ["graphics-password-box"] - if listen == 'address': - vnc_rows.extend(["graphics-port-box", "graphics-address"]) - spice_rows = vnc_rows[:] - spice_rows.extend(["graphics-opengl-box"]) - - rows = [] - if gtype == "vnc": - rows = vnc_rows - elif gtype == "spice": - rows = spice_rows - - for row in hide_all: - uiutil.set_grid_row_visible(self.widget(row), row in rows) - def _change_graphics_type(self, ignore): - self._show_rows_from_type() + self._sync_ui() self.emit("changed-type") def _change_graphics_listen(self, ignore): - self._show_rows_from_type() + self._sync_ui() self.emit("changed-listen") - def _sync_opengl_ui(self): - uiutil.set_grid_row_visible( - self.widget("graphics-rendernode"), - self.widget("graphics-opengl").get_active()) - def _change_opengl(self, ignore): - self._sync_opengl_ui() + self._sync_ui() self.emit("changed-opengl") self.emit("changed-rendernode") def _change_port_auto(self, ignore): self.widget("graphics-port-auto").set_inconsistent(False) - self._change_ports() + self._sync_ui() self.emit("changed-port") - def _change_ports(self): - is_auto = (self.widget("graphics-port-auto").get_active() or - self.widget("graphics-port-auto").get_inconsistent()) - - self.widget("graphics-port").set_visible(not is_auto) - - def _change_password_chk(self, ignore=None): - if self.widget("graphics-password-chk").get_active(): - self.widget("graphics-password").set_sensitive(True) - else: - self.widget("graphics-password").set_text("") - self.widget("graphics-password").set_sensitive(False) + def _change_password_cb(self, src): + self._sync_ui() self.emit("changed-password") - def _show_password_chk(self, ignore=None): - if self.widget("graphics-visiblity-chk").get_active(): - self.widget("graphics-password").set_visibility(True) - else: - self.widget("graphics-password").set_visibility(False) + def _show_password_cb(self, src): + self._sync_ui()