mirror of
https://github.com/virt-manager/virt-manager.git
synced 2024-12-22 13:34:07 +03:00
viewers: Enable window modifiers when viewer doesn't have keyboard
Right now this is tied to widget focus, which is too strong. This changes it so that say clicking on the window title or toolbar then allows the user to use Alt+F to trigger the File menu for example. This roughly matches how virt-viewer works https://bugzilla.redhat.com/show_bug.cgi?id=1824480 Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
parent
33a61f7f30
commit
aafb874c85
@ -53,6 +53,15 @@ class Console(uiutils.UITestCase):
|
|||||||
conn = None
|
conn = None
|
||||||
extraopts = None
|
extraopts = None
|
||||||
|
|
||||||
|
def _destroy(self, win):
|
||||||
|
smenu = win.find("Menu", "toggle button")
|
||||||
|
smenu.click()
|
||||||
|
smenu.find("Force Off", "menu item").click()
|
||||||
|
self._click_alert_button("you sure", "Yes")
|
||||||
|
run = win.find("Run", "push button")
|
||||||
|
uiutils.check(lambda: run.sensitive)
|
||||||
|
|
||||||
|
|
||||||
##############
|
##############
|
||||||
# Test cases #
|
# Test cases #
|
||||||
##############
|
##############
|
||||||
@ -134,8 +143,17 @@ class Console(uiutils.UITestCase):
|
|||||||
scalemenu.point()
|
scalemenu.point()
|
||||||
scalemenu.find("Only", "radio menu item").click()
|
scalemenu.find("Only", "radio menu item").click()
|
||||||
|
|
||||||
|
# Check that modifiers don't work
|
||||||
|
win.click()
|
||||||
|
self.sleep(1)
|
||||||
|
win.keyCombo("<ctrl>w")
|
||||||
|
uiutils.check(lambda: win.showing)
|
||||||
dom.destroy()
|
dom.destroy()
|
||||||
win.find("Guest is not running.")
|
win.find("Guest is not running.")
|
||||||
|
win.click_title()
|
||||||
|
self.sleep(1)
|
||||||
|
win.keyCombo("<ctrl>w")
|
||||||
|
uiutils.check(lambda: not win.showing)
|
||||||
|
|
||||||
@_vm_wrapper("uitests-vnc-standard")
|
@_vm_wrapper("uitests-vnc-standard")
|
||||||
def testConsoleVNCStandard(self, dom):
|
def testConsoleVNCStandard(self, dom):
|
||||||
@ -172,10 +190,7 @@ class Console(uiutils.UITestCase):
|
|||||||
uiutils.check(lambda: con.showing)
|
uiutils.check(lambda: con.showing)
|
||||||
|
|
||||||
# Restart VM to retrigger console connect
|
# Restart VM to retrigger console connect
|
||||||
smenu = win.find("Menu", "toggle button")
|
self._destroy(win)
|
||||||
smenu.click()
|
|
||||||
smenu.find("Force Off", "menu item").click()
|
|
||||||
self._click_alert_button("you sure", "Yes")
|
|
||||||
win.find("Run", "push button").click()
|
win.find("Run", "push button").click()
|
||||||
uiutils.check(lambda: passwd.showing)
|
uiutils.check(lambda: passwd.showing)
|
||||||
# Password should be filled in
|
# Password should be filled in
|
||||||
@ -186,10 +201,7 @@ class Console(uiutils.UITestCase):
|
|||||||
uiutils.check(lambda: con.showing)
|
uiutils.check(lambda: con.showing)
|
||||||
|
|
||||||
# Restart VM to retrigger console connect
|
# Restart VM to retrigger console connect
|
||||||
smenu = win.find("Menu", "toggle button")
|
self._destroy(win)
|
||||||
smenu.click()
|
|
||||||
smenu.find("Force Off", "menu item").click()
|
|
||||||
self._click_alert_button("you sure", "Yes")
|
|
||||||
win.find("Run", "push button").click()
|
win.find("Run", "push button").click()
|
||||||
uiutils.check(lambda: passwd.showing)
|
uiutils.check(lambda: passwd.showing)
|
||||||
# Password should be empty now
|
# Password should be empty now
|
||||||
@ -267,10 +279,7 @@ class Console(uiutils.UITestCase):
|
|||||||
|
|
||||||
win.find("Details", "radio button").click()
|
win.find("Details", "radio button").click()
|
||||||
win.find("Console", "radio button").click()
|
win.find("Console", "radio button").click()
|
||||||
smenu = win.find("Menu", "toggle button")
|
self._destroy(win)
|
||||||
smenu.click()
|
|
||||||
smenu.find("Force Off", "menu item").click()
|
|
||||||
self._click_alert_button("you sure", "Yes")
|
|
||||||
view = self.app.root.find("^View$", "menu")
|
view = self.app.root.find("^View$", "menu")
|
||||||
view.click()
|
view.click()
|
||||||
# Triggers some tooltip cases
|
# Triggers some tooltip cases
|
||||||
@ -286,6 +295,18 @@ class Console(uiutils.UITestCase):
|
|||||||
term = win.find("Serial Terminal")
|
term = win.find("Serial Terminal")
|
||||||
uiutils.check(lambda: term.showing)
|
uiutils.check(lambda: term.showing)
|
||||||
|
|
||||||
|
# Ensure ctrl+w doesn't close the window, modifiers are disabled
|
||||||
|
term.click()
|
||||||
|
win.keyCombo("<ctrl>w")
|
||||||
|
uiutils.check(lambda: win.showing)
|
||||||
|
# Shut it down, ensure <ctrl>w works again
|
||||||
|
self._destroy(win)
|
||||||
|
win.click_title()
|
||||||
|
self.sleep(1)
|
||||||
|
win.keyCombo("<ctrl>w")
|
||||||
|
uiutils.check(lambda: not win.showing)
|
||||||
|
|
||||||
|
|
||||||
@_vm_wrapper("uitests-spice-specific",
|
@_vm_wrapper("uitests-spice-specific",
|
||||||
opts=["--test-options=spice-agent",
|
opts=["--test-options=spice-agent",
|
||||||
"--test-options=fake-console-resolution"])
|
"--test-options=fake-console-resolution"])
|
||||||
|
@ -396,16 +396,6 @@ class vmmConsolePages(vmmGObjectUI):
|
|||||||
|
|
||||||
self.topwin.set_title(title)
|
self.topwin.set_title(title)
|
||||||
|
|
||||||
def _someone_has_focus(self):
|
|
||||||
if (self._viewer and
|
|
||||||
self._viewer.console_has_focus() and
|
|
||||||
self._viewer.console_is_open()):
|
|
||||||
return True
|
|
||||||
|
|
||||||
for serial in self._serial_consoles:
|
|
||||||
if serial.has_focus():
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _disable_modifiers(self):
|
def _disable_modifiers(self):
|
||||||
if self._gtk_settings_accel is not None:
|
if self._gtk_settings_accel is not None:
|
||||||
return
|
return
|
||||||
@ -876,8 +866,18 @@ class vmmConsolePages(vmmGObjectUI):
|
|||||||
def _viewer_allocate_cb(self, src, ignore):
|
def _viewer_allocate_cb(self, src, ignore):
|
||||||
self.widget("console-gfx-scroll").queue_resize()
|
self.widget("console-gfx-scroll").queue_resize()
|
||||||
|
|
||||||
def _viewer_focus_changed(self, ignore1=None, ignore2=None):
|
def _viewer_keyboard_grab_cb(self, src):
|
||||||
if self._someone_has_focus():
|
self._viewer_sync_modifiers()
|
||||||
|
|
||||||
|
def _serial_focus_changed_cb(self, src, event):
|
||||||
|
self._viewer_sync_modifiers()
|
||||||
|
|
||||||
|
def _viewer_sync_modifiers(self):
|
||||||
|
serial_has_focus = any([s.has_focus() for s in self._serial_consoles])
|
||||||
|
viewer_keyboard_grab = (self._viewer and
|
||||||
|
self._viewer.console_has_keyboard_grab())
|
||||||
|
|
||||||
|
if serial_has_focus or viewer_keyboard_grab:
|
||||||
self._disable_modifiers()
|
self._disable_modifiers()
|
||||||
else:
|
else:
|
||||||
self._enable_modifiers()
|
self._enable_modifiers()
|
||||||
@ -926,7 +926,7 @@ class vmmConsolePages(vmmGObjectUI):
|
|||||||
log.debug("Viewer disconnected")
|
log.debug("Viewer disconnected")
|
||||||
|
|
||||||
# Make sure modifiers are set correctly
|
# Make sure modifiers are set correctly
|
||||||
self._viewer_focus_changed()
|
self._viewer_sync_modifiers()
|
||||||
|
|
||||||
self._viewer_disconnected_set_page(errdetails, ssherr)
|
self._viewer_disconnected_set_page(errdetails, ssherr)
|
||||||
self._refresh_resizeguest_from_settings()
|
self._refresh_resizeguest_from_settings()
|
||||||
@ -936,15 +936,15 @@ class vmmConsolePages(vmmGObjectUI):
|
|||||||
self._activate_viewer_page()
|
self._activate_viewer_page()
|
||||||
|
|
||||||
# Make sure modifiers are set correctly
|
# Make sure modifiers are set correctly
|
||||||
self._viewer_focus_changed()
|
self._viewer_sync_modifiers()
|
||||||
|
|
||||||
def _connect_viewer_signals(self):
|
def _connect_viewer_signals(self):
|
||||||
self._viewer.connect("add-display-widget", self._viewer_add_display)
|
self._viewer.connect("add-display-widget", self._viewer_add_display)
|
||||||
self._viewer.connect("pointer-grab", self._pointer_grabbed)
|
self._viewer.connect("pointer-grab", self._pointer_grabbed)
|
||||||
self._viewer.connect("pointer-ungrab", self._pointer_ungrabbed)
|
self._viewer.connect("pointer-ungrab", self._pointer_ungrabbed)
|
||||||
self._viewer.connect("size-allocate", self._viewer_allocate_cb)
|
self._viewer.connect("size-allocate", self._viewer_allocate_cb)
|
||||||
self._viewer.connect("focus-in-event", self._viewer_focus_changed)
|
self._viewer.connect("keyboard-grab", self._viewer_keyboard_grab_cb)
|
||||||
self._viewer.connect("focus-out-event", self._viewer_focus_changed)
|
self._viewer.connect("keyboard-ungrab", self._viewer_keyboard_grab_cb)
|
||||||
self._viewer.connect("connected", self._viewer_connected)
|
self._viewer.connect("connected", self._viewer_connected)
|
||||||
self._viewer.connect("disconnected", self._viewer_disconnected)
|
self._viewer.connect("disconnected", self._viewer_disconnected)
|
||||||
self._viewer.connect("auth-error", self._viewer_auth_error)
|
self._viewer.connect("auth-error", self._viewer_auth_error)
|
||||||
@ -985,8 +985,8 @@ class vmmConsolePages(vmmGObjectUI):
|
|||||||
|
|
||||||
if not serial:
|
if not serial:
|
||||||
serial = vmmSerialConsole(self.vm, target_port, name)
|
serial = vmmSerialConsole(self.vm, target_port, name)
|
||||||
serial.set_focus_callbacks(self._viewer_focus_changed,
|
serial.set_focus_callbacks(self._serial_focus_changed_cb,
|
||||||
self._viewer_focus_changed)
|
self._serial_focus_changed_cb)
|
||||||
|
|
||||||
title = Gtk.Label(label=name)
|
title = Gtk.Label(label=name)
|
||||||
self.widget("serial-pages").append_page(serial.get_box(), title)
|
self.widget("serial-pages").append_page(serial.get_box(), title)
|
||||||
|
@ -36,10 +36,10 @@ class Viewer(vmmGObject):
|
|||||||
__gsignals__ = {
|
__gsignals__ = {
|
||||||
"add-display-widget": (vmmGObject.RUN_FIRST, None, [object]),
|
"add-display-widget": (vmmGObject.RUN_FIRST, None, [object]),
|
||||||
"size-allocate": (vmmGObject.RUN_FIRST, None, [object]),
|
"size-allocate": (vmmGObject.RUN_FIRST, None, [object]),
|
||||||
"focus-in-event": (vmmGObject.RUN_FIRST, None, [object]),
|
|
||||||
"focus-out-event": (vmmGObject.RUN_FIRST, None, [object]),
|
|
||||||
"pointer-grab": (vmmGObject.RUN_FIRST, None, []),
|
"pointer-grab": (vmmGObject.RUN_FIRST, None, []),
|
||||||
"pointer-ungrab": (vmmGObject.RUN_FIRST, None, []),
|
"pointer-ungrab": (vmmGObject.RUN_FIRST, None, []),
|
||||||
|
"keyboard-grab": (vmmGObject.RUN_FIRST, None, []),
|
||||||
|
"keyboard-ungrab": (vmmGObject.RUN_FIRST, None, []),
|
||||||
"connected": (vmmGObject.RUN_FIRST, None, []),
|
"connected": (vmmGObject.RUN_FIRST, None, []),
|
||||||
"disconnected": (vmmGObject.RUN_FIRST, None, [str, str]),
|
"disconnected": (vmmGObject.RUN_FIRST, None, [str, str]),
|
||||||
"auth-error": (vmmGObject.RUN_FIRST, None, [str, bool]),
|
"auth-error": (vmmGObject.RUN_FIRST, None, [str, bool]),
|
||||||
@ -54,6 +54,7 @@ class Viewer(vmmGObject):
|
|||||||
self._vm = vm
|
self._vm = vm
|
||||||
self._ginfo = ginfo
|
self._ginfo = ginfo
|
||||||
self._tunnels = SSHTunnels(self._ginfo)
|
self._tunnels = SSHTunnels(self._ginfo)
|
||||||
|
self._keyboard_grab = False
|
||||||
|
|
||||||
self.add_gsettings_handle(
|
self.add_gsettings_handle(
|
||||||
self.config.on_keys_combination_changed(self._refresh_grab_keys))
|
self.config.on_keys_combination_changed(self._refresh_grab_keys))
|
||||||
@ -90,10 +91,6 @@ class Viewer(vmmGObject):
|
|||||||
|
|
||||||
self._display.connect("size-allocate",
|
self._display.connect("size-allocate",
|
||||||
self._make_signal_proxy("size-allocate"))
|
self._make_signal_proxy("size-allocate"))
|
||||||
self._display.connect("focus-in-event",
|
|
||||||
self._make_signal_proxy("focus-in-event"))
|
|
||||||
self._display.connect("focus-out-event",
|
|
||||||
self._make_signal_proxy("focus-out-event"))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -210,6 +207,8 @@ class Viewer(vmmGObject):
|
|||||||
return self._grab_focus()
|
return self._grab_focus()
|
||||||
def console_has_focus(self):
|
def console_has_focus(self):
|
||||||
return self._has_focus()
|
return self._has_focus()
|
||||||
|
def console_has_keyboard_grab(self):
|
||||||
|
return bool(self._display and self._keyboard_grab)
|
||||||
def console_set_size_request(self, *args, **kwargs):
|
def console_set_size_request(self, *args, **kwargs):
|
||||||
return self._set_size_request(*args, **kwargs)
|
return self._set_size_request(*args, **kwargs)
|
||||||
def console_size_allocate(self, *args, **kwargs):
|
def console_size_allocate(self, *args, **kwargs):
|
||||||
@ -297,6 +296,8 @@ class VNCViewer(Viewer):
|
|||||||
self._make_signal_proxy("pointer-grab"))
|
self._make_signal_proxy("pointer-grab"))
|
||||||
self._display.connect("vnc-pointer-ungrab",
|
self._display.connect("vnc-pointer-ungrab",
|
||||||
self._make_signal_proxy("pointer-ungrab"))
|
self._make_signal_proxy("pointer-ungrab"))
|
||||||
|
self._display.connect("vnc-keyboard-grab", self._keyboard_grab_cb)
|
||||||
|
self._display.connect("vnc-keyboard-ungrab", self._keyboard_ungrab_cb)
|
||||||
|
|
||||||
self._display.connect("vnc-auth-credential", self._auth_credential)
|
self._display.connect("vnc-auth-credential", self._auth_credential)
|
||||||
self._display.connect("vnc-auth-failure", self._auth_failure_cb)
|
self._display.connect("vnc-auth-failure", self._auth_failure_cb)
|
||||||
@ -306,6 +307,14 @@ class VNCViewer(Viewer):
|
|||||||
|
|
||||||
self._display.show()
|
self._display.show()
|
||||||
|
|
||||||
|
def _keyboard_grab_cb(self, src):
|
||||||
|
self._keyboard_grab = True
|
||||||
|
self.emit("keyboard-grab")
|
||||||
|
|
||||||
|
def _keyboard_ungrab_cb(self, src):
|
||||||
|
self._keyboard_grab = False
|
||||||
|
self.emit("keyboard-ungrab")
|
||||||
|
|
||||||
def _connected_cb(self, ignore):
|
def _connected_cb(self, ignore):
|
||||||
self._tunnels.unlock()
|
self._tunnels.unlock()
|
||||||
self.emit("connected")
|
self.emit("connected")
|
||||||
@ -485,20 +494,28 @@ class SpiceViewer(Viewer):
|
|||||||
# Private helpers #
|
# Private helpers #
|
||||||
###################
|
###################
|
||||||
|
|
||||||
def _init_widget(self):
|
def _mouse_grab_cb(self, src, grab):
|
||||||
self.emit("add-display-widget", self._display)
|
|
||||||
self._display.realize()
|
|
||||||
|
|
||||||
self._display.connect("mouse-grab", self._mouse_grab_event)
|
|
||||||
|
|
||||||
self._display.show()
|
|
||||||
|
|
||||||
def _mouse_grab_event(self, ignore, grab):
|
|
||||||
if grab:
|
if grab:
|
||||||
self.emit("pointer-grab")
|
self.emit("pointer-grab")
|
||||||
else:
|
else:
|
||||||
self.emit("pointer-ungrab")
|
self.emit("pointer-ungrab")
|
||||||
|
|
||||||
|
def _keyboard_grab_cb(self, src, grab):
|
||||||
|
self._keyboard_grab = grab
|
||||||
|
if grab:
|
||||||
|
self.emit("keyboard-grab")
|
||||||
|
else:
|
||||||
|
self.emit("keyboard-ungrab")
|
||||||
|
|
||||||
|
def _init_widget(self):
|
||||||
|
self.emit("add-display-widget", self._display)
|
||||||
|
self._display.realize()
|
||||||
|
|
||||||
|
self._display.connect("mouse-grab", self._mouse_grab_cb)
|
||||||
|
self._display.connect("keyboard-grab", self._keyboard_grab_cb)
|
||||||
|
|
||||||
|
self._display.show()
|
||||||
|
|
||||||
def _create_spice_session(self):
|
def _create_spice_session(self):
|
||||||
self._spice_session = SpiceClientGLib.Session()
|
self._spice_session = SpiceClientGLib.Session()
|
||||||
SpiceClientGLib.set_session_option(self._spice_session)
|
SpiceClientGLib.set_session_option(self._spice_session)
|
||||||
|
Loading…
Reference in New Issue
Block a user