fix(display-manager): lazy launch by default + minimize unassigned apps
- autolaunch default: True → False (on-demand only, saves GPU on startup) - add ProcessManager.minimize() to minimize a window to taskbar - add win32_utils.minimize_window() (SW_MINIMIZE via user32) - DisplayManager._minimize_unassigned(): after each app switch, minimize every running app not currently assigned to any screen, freeing iGPU resources (critical on J6412 UHD 600 with limited EUs) Background: J6412 Intel UHD 600 has only 16 EUs @ 800 MHz. Running AR-ECDIS (MapLibre GL) and GPS (OpenLayers) simultaneously consumes ~60% iGPU. By minimizing inactive apps Windows suspends their GPU presentation chain, dropping idle GPU load near zero. AR_electronics — AR-Autopilot Project
This commit is contained in:
@@ -38,7 +38,7 @@ class DisplayManagerConfig:
|
|||||||
apps: dict[str, AppExeConfig] = field(default_factory=dict)
|
apps: dict[str, AppExeConfig] = field(default_factory=dict)
|
||||||
button_position: str = "top-right" # top-right | top-left | bottom-right | bottom-left
|
button_position: str = "top-right" # top-right | top-left | bottom-right | bottom-left
|
||||||
button_margin: int = 12 # px from screen edge
|
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
|
# ------------------------------------------------------------------ I/O
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -106,6 +106,18 @@ class DisplayManager(QObject):
|
|||||||
self._bring_app(app_id, screen_geo)
|
self._bring_app(app_id, screen_geo)
|
||||||
|
|
||||||
self._layout.set(screen_serial, app_id)
|
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:
|
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())
|
self._proc_mgr.bring_to_screen(app_id, geo.x(), geo.y(), geo.width(), geo.height())
|
||||||
|
|||||||
@@ -90,6 +90,16 @@ class ProcessManager(QObject):
|
|||||||
win32_utils.move_and_maximize(hwnd, x, y, w, h)
|
win32_utils.move_and_maximize(hwnd, x, y, w, h)
|
||||||
return True
|
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:
|
def is_running(self, app_id: str) -> bool:
|
||||||
h = self._handles.get(app_id)
|
h = self._handles.get(app_id)
|
||||||
return h is not None and h.is_running()
|
return h is not None and h.is_running()
|
||||||
|
|||||||
@@ -80,5 +80,10 @@ else:
|
|||||||
_user32.ShowWindow(hwnd, _SW_MAXIMIZE)
|
_user32.ShowWindow(hwnd, _SW_MAXIMIZE)
|
||||||
_user32.SetForegroundWindow(hwnd)
|
_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:
|
def is_window_alive(hwnd: int) -> bool:
|
||||||
return bool(_user32.IsWindow(hwnd))
|
return bool(_user32.IsWindow(hwnd))
|
||||||
|
|||||||
Reference in New Issue
Block a user