diff --git a/display_manager/config.py b/display_manager/config.py index bbdc640..b77da9b 100644 --- a/display_manager/config.py +++ b/display_manager/config.py @@ -38,7 +38,7 @@ class DisplayManagerConfig: apps: dict[str, AppExeConfig] = field(default_factory=dict) button_position: str = "top-right" # top-right | top-left | bottom-right | bottom-left button_margin: int = 12 # px from screen edge - autolaunch: bool = True # launch apps on startup if exe exists + autolaunch: bool = False # launch all apps on startup (False = on-demand only) # ------------------------------------------------------------------ I/O @classmethod diff --git a/display_manager/display_manager.py b/display_manager/display_manager.py index 5e34b41..d0970b9 100644 --- a/display_manager/display_manager.py +++ b/display_manager/display_manager.py @@ -106,6 +106,18 @@ class DisplayManager(QObject): self._bring_app(app_id, screen_geo) self._layout.set(screen_serial, app_id) + # Minimize apps not assigned to any screen (free GPU) + self._minimize_unassigned() + + def _minimize_unassigned(self) -> None: + """Minimize every running app that is not currently assigned to any screen.""" + assigned = set( + self._layout.get(self._screen_serial(s)) + for s in self._app.screens() + ) - {None} + for app_id in self._proc_mgr.running_ids(): + if app_id not in assigned: + self._proc_mgr.minimize(app_id) def _bring_app(self, app_id: str, geo: QRect) -> None: self._proc_mgr.bring_to_screen(app_id, geo.x(), geo.y(), geo.width(), geo.height()) diff --git a/display_manager/process_manager.py b/display_manager/process_manager.py index 892e032..708ab45 100644 --- a/display_manager/process_manager.py +++ b/display_manager/process_manager.py @@ -90,6 +90,16 @@ class ProcessManager(QObject): win32_utils.move_and_maximize(hwnd, x, y, w, h) return True + def minimize(self, app_id: str) -> None: + """Minimize *app_id*'s window to free GPU resources.""" + handle = self._handles.get(app_id) + if handle is None or not handle.is_running(): + return + title_hint = self._config.apps.get(app_id, AppExeConfig()).title_hint + hwnd = handle.find_hwnd(title_hint) + if hwnd is not None: + win32_utils.minimize_window(hwnd) + def is_running(self, app_id: str) -> bool: h = self._handles.get(app_id) return h is not None and h.is_running() diff --git a/display_manager/win32_utils.py b/display_manager/win32_utils.py index 16b5c8a..9bd6d7e 100644 --- a/display_manager/win32_utils.py +++ b/display_manager/win32_utils.py @@ -80,5 +80,10 @@ else: _user32.ShowWindow(hwnd, _SW_MAXIMIZE) _user32.SetForegroundWindow(hwnd) + def minimize_window(hwnd: int) -> None: + """Minimize a window to taskbar to free GPU resources.""" + _SW_MINIMIZE = 6 + _user32.ShowWindow(hwnd, _SW_MINIMIZE) + def is_window_alive(hwnd: int) -> bool: return bool(_user32.IsWindow(hwnd))