console: Fix resize_to_vm with host fractional scaling

Trying to size the window based on VM desktop resolution does
not do the correct thing when host fractional scaling is enabled
and using spice.

The best we can do here is ask the viewer widget for its
preferred size

Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
Cole Robinson 2024-10-03 12:45:04 -04:00
parent 2ee224193d
commit d231e66a96
3 changed files with 41 additions and 26 deletions

View File

@ -152,15 +152,22 @@ def _checkConsoleStandard(app, dom):
win.find("^View$", "menu").click()
scalemenu = win.find("Scale Display", "menu")
scalemenu.point()
scalemenu.find("Always", "radio menu item").click()
win.find("^View$", "menu").click()
scalemenu = win.find("Scale Display", "menu")
scalemenu.point()
scalemenu.find("Never", "radio menu item").click()
win.find("^View$", "menu").click()
scalemenu = win.find("Scale Display", "menu")
scalemenu.point()
scalemenu.find("Only", "radio menu item").click()
win.find("^View$", "menu").click()
scalemenu = win.find("Scale Display", "menu")
scalemenu.point()
scalemenu.find("Always", "radio menu item").click()
# 'Resize to VM' again, to hit the scaling->always case
oldsize = win.size
win.find("^View$", "menu").click()
win.find("Resize to VM", "menu item").click()
newsize = win.size
lib.utils.check(lambda: oldsize != newsize)
win.window_close()

View File

@ -480,27 +480,22 @@ class vmmConsolePages(vmmGObjectUI):
self._viewer.console_set_resizeguest(val)
def _set_size_to_vm(self):
# Resize the console to best fit the VM resolution
vm_resolution = self._viewer.console_get_desktop_resolution()
if not self._viewer:
if not self._viewer_is_visible():
return # pragma: no cover
if not vm_resolution: # pragma: no cover
log.debug("_set_size_to_vm but no VM desktop resolution set")
return
# Note: gtk3 has no APIs for telling us about fractional scaling.
# without that, we can't reliably figure out how VM dimensions
# should map to host widget dimensions.
w, h = self._viewer.console_get_preferred_size()
if w <= 0 or h <= 0: # pragma: no cover
log.debug("_set_size_to_vm but no valid sizing found")
return
top_w, top_h = self.topwin.get_size()
viewer_alloc = self.widget("console-gfx-scroll").get_allocation()
desktop_w, desktop_h = vm_resolution
valw = desktop_w + (top_w - viewer_alloc.width)
valh = desktop_h + (top_h - viewer_alloc.height)
valw = w + (top_w - viewer_alloc.width)
valh = h + (top_h - viewer_alloc.height)
log.debug("_set_size_to_vm vm=(%s, %s) window=(%s, %s)",
desktop_w, desktop_h, valw, valh)
w, h, valw, valh)
self.topwin.unmaximize()
self.topwin.resize(valw, valh)

View File

@ -76,7 +76,7 @@ class Viewer(vmmGObject):
self._ginfo = ginfo
self._tunnels = SSHTunnels(self._ginfo)
self._keyboard_grab = False
self._desktop_resolution = None
self._desktop_resolution = (0, 0)
self.add_gsettings_handle(
self.config.on_keys_combination_changed(self._refresh_grab_keys))
@ -202,12 +202,6 @@ class Viewer(vmmGObject):
self._desktop_resolution = newres
self.emit("desktop-resolution-changed")
def _get_desktop_resolution(self):
ret = self._desktop_resolution or (0, 0)
if (ret[0] == 0) or (ret[1] == 0):
return None
return ret
#######################################################
# Internal API that will be overwritten by subclasses #
@ -254,6 +248,9 @@ class Viewer(vmmGObject):
def _has_usb_redirection(self):
raise NotImplementedError()
def _get_preferred_size(self):
raise NotImplementedError()
####################################
# APIs accessed by vmmConsolePages #
@ -284,8 +281,8 @@ class Viewer(vmmGObject):
def console_get_grab_keys(self):
return self._get_grab_keys()
def console_get_desktop_resolution(self):
return self._get_desktop_resolution()
def console_get_preferred_size(self):
return self._get_preferred_size()
def console_set_scaling(self, val):
return self._set_scaling(val)
@ -445,6 +442,9 @@ class VNCViewer(Viewer):
def _has_usb_redirection(self):
return False
def _get_preferred_size(self):
return self._desktop_resolution
#######################
# Connection routines #
@ -758,3 +758,16 @@ class SpiceViewer(Viewer):
if not self._spice_session or not self._usbdev_manager:
return False # pragma: no cover
return True
def _get_preferred_size(self):
if (not self._display or
self._get_scaling() or
self._get_resizeguest()):
return self._desktop_resolution
# When scaling and resizeguest disabled, this usually matches the
# VM resolution. But when host desktop scaling is used, spice will
# intentionally have different values here.
w = self._display.get_preferred_width()[1]
h = self._display.get_preferred_height()[1]
return (w, h)