From 0561f520a8642d88119f640517aa9c6641e4d20e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 12 Oct 2022 20:58:21 +0530 Subject: [PATCH] More work on custom widget geometry restore --- src/calibre/gui2/geometry.py | 94 ++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 25 deletions(-) diff --git a/src/calibre/gui2/geometry.py b/src/calibre/gui2/geometry.py index ac1d0652a5..3744c73ac8 100644 --- a/src/calibre/gui2/geometry.py +++ b/src/calibre/gui2/geometry.py @@ -8,6 +8,13 @@ from qt.core import QRect, QScreen, QSize, QWidget, QApplication, Qt +from calibre.constants import DEBUG + + +def debug(*a, **kw): + if DEBUG: + from pprint import pprint + pprint(*a, **kw) def size_as_dict(self: QSize): @@ -32,6 +39,7 @@ def screen_as_dict(self: QScreen): 'device_pixel_ratio': self.devicePixelRatio(), 'size_in_logical_pixels': size_as_dict(self.size()), 'geometry_in_logical_pixels': rect_as_dict(self.geometry()), + 'virtual_geometry': rect_as_dict(self.virtualGeometry()), 'index_in_screens_list': num, } @@ -40,7 +48,7 @@ def geometry_for_restore_as_dict(self: QWidget): s = self.screen() if s is None: return {} - return { + ans = { 'screen': screen_as_dict(s), 'geometry': rect_as_dict(self.geometry()), 'frame_geometry': rect_as_dict(self.frameGeometry()), @@ -48,20 +56,25 @@ def geometry_for_restore_as_dict(self: QWidget): 'maximized': self.isMaximized(), 'full_screened': self.isFullScreen(), } + return ans def save_geometry(self: QWidget, prefs: dict, name: str): x = geometry_for_restore_as_dict(self) if x: + if DEBUG: + debug('Saving geometry for:', name) + debug(x) prefs.set(f'geometry-of-{name}', x) def find_matching_screen(screen_as_dict): screens = QApplication.instance().screens() size = QSize(**screen_as_dict['size']) + vg = QRect(**screen_as_dict['virtual_geometry']) screens_of_matching_size = tuple( s for s in screens if - s.size() == size and s.devicePixelRatio() == screen_as_dict['device_pixel_ratio']) + s.size() == size and vg == s.virtualGeometry() and s.devicePixelRatio() == screen_as_dict['device_pixel_ratio']) if screen_as_dict['serial']: for q in screens_of_matching_size: if q.serialNumber() == screen_as_dict['serial']: @@ -76,21 +89,33 @@ def find_matching_screen(screen_as_dict): return q -def _restore_geometry(self: QWidget, prefs: dict, name: str) -> bool: - x = prefs.get(f'geometry-of-{name}') - if not x: - return False - s = find_matching_screen(x['screen']) - if s is None: - p = self.nativeParentWidget() - if p is not None: - s = p.screen() - if s is None: - s = self.screen() - if s is None: - s = QApplication.instance().primaryScreen() - if s is None: - return False +def _do_restore(self: QWidget, s: QScreen, geometry: QRect, x: dict): + ws = self.windowState() + if ws & (Qt.WindowState.WindowFullScreen | Qt.WindowState.WindowMaximized): + debug('Not restoring geometry as widget is already maximized or fullscreen') + return True + if self.screen() is not s: + debug('Moving widget to saved screen') + self.setScreen(s) + debug('Setting widget geometry to:', geometry) + self.setGeometry(geometry) + if x['full_screened']: + debug('Restoring widget to full screen') + self.showFullScreen() + elif x['maximized']: + debug('Restoring widget to maximized') + self.showMaximized() + return True + + +def _restore_to_matching_screen(self: QWidget, s: QScreen, saved_data: dict) -> bool: + x = saved_data + saved_geometry = QRect(**x['geometry']) + return _do_restore(self, s, saved_geometry, x) + + +def _restore_to_new_screen(self: QWidget, s: QScreen, saved_data: dict) -> bool: + x = saved_data saved_geometry = QRect(**x['geometry']) saved_frame_geometry = QRect(**x['frame_geometry']) if not saved_geometry.isValid() or not saved_frame_geometry.isValid(): @@ -105,14 +130,33 @@ def _restore_geometry(self: QWidget, prefs: dict, name: str) -> bool: max_left = available_geometry.left() + (available_size.width() - sz.width()) max_top = available_geometry.top() + (available_size.height() - sz.height()) geometry = QRect(min(saved_geometry.left(), max_left), min(saved_geometry.top(), max_top), sz.width(), sz.height()) - ws = self.windowState() - if ws & (Qt.WindowState.WindowFullScreen | Qt.WindowState.WindowMaximized): - return True - self.setGeometry(geometry) - if x['full_screened']: - self.showFullScreen() - elif x['maximized']: - self.showMaximized() + return _do_restore(self, s, geometry, x) + + +def _restore_geometry(self: QWidget, prefs: dict, name: str) -> bool: + x = prefs.get(f'geometry-of-{name}') + if not x: + return False + if DEBUG: + debug('Restoring geometry for:', name) + debug(x) + s = find_matching_screen(x['screen']) + debug('Matching screen:', screen_as_dict(s) if s else None) + if s is None: + if DEBUG: + debug('No screens matched saved screen. Available screens:', tuple(map(screen_as_dict, QApplication.instance().screens()))) + p = self.nativeParentWidget() + if p is not None: + s = p.screen() + if s is None: + s = self.screen() + if s is None: + s = QApplication.instance().primaryScreen() + else: + return _restore_to_matching_screen(self, s, x) + if s is None: + return False + return _restore_to_new_screen(self, s, x) def restore_geometry(self: QWidget, prefs: dict, name: str) -> bool: