feat: AR Display Manager — multi-monitor floating app switcher
Adds the AR Display Manager daemon (Task #9): - display_manager/ package with 8 modules: - app_registry.py : static metadata for the 4 bridge apps - config.py : JSON-persisted config + per-screen layout store - win32_utils.py : ctypes wrappers (EnumWindows, SetWindowPos, ShowWindow) - process_manager.py: launch + track app processes, HWND lookup - floating_button.py: always-on-top 52×52 px AR button per monitor with draggable placement + custom-painted popup - display_manager.py: orchestrator (QScreens → buttons → app placement + system tray with Settings/Launch/Quit) - settings_dialog.py: modal dialog for exe paths, button position, and Windows autostart toggle - autostart.py : HKCU Run registry read/write helpers - display_manager_main.py at repo root: launcher script - Studio Overview tab: "Lanzar Display Manager" button - pyproject.toml: display-manager optional dependency group (PySide6) Layout persistence: ~/.ar-autopilot/display_manager/layout.json Config: ~/.ar-autopilot/display_manager/config.json Supports up to 4 monitors (2 HDMI native + 2 USB DisplayLink). Double-click tray icon to toggle button visibility. AR_electronics — AR-Autopilot Project
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"""Register / unregister AR Display Manager as a Windows autostart entry."""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_REG_KEY = r"Software\Microsoft\Windows\CurrentVersion\Run"
|
||||
_APP_NAME = "AR Display Manager"
|
||||
|
||||
|
||||
def _pythonw() -> str:
|
||||
"""Return the pythonw.exe path (no console window on start)."""
|
||||
exe = Path(sys.executable)
|
||||
pw = exe.parent / "pythonw.exe"
|
||||
return str(pw) if pw.exists() else sys.executable
|
||||
|
||||
|
||||
def enable() -> bool:
|
||||
"""Add the autostart registry entry. Returns True on success."""
|
||||
if sys.platform != "win32":
|
||||
return False
|
||||
try:
|
||||
import winreg # type: ignore[import-not-found]
|
||||
launcher = Path(__file__).resolve().parents[1] / "display_manager_main.py"
|
||||
cmd = f'"{_pythonw()}" "{launcher}"'
|
||||
with winreg.OpenKey(
|
||||
winreg.HKEY_CURRENT_USER, _REG_KEY, 0, winreg.KEY_SET_VALUE
|
||||
) as key:
|
||||
winreg.SetValueEx(key, _APP_NAME, 0, winreg.REG_SZ, cmd)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def disable() -> bool:
|
||||
"""Remove the autostart registry entry. Returns True if it existed."""
|
||||
if sys.platform != "win32":
|
||||
return False
|
||||
try:
|
||||
import winreg # type: ignore[import-not-found]
|
||||
with winreg.OpenKey(
|
||||
winreg.HKEY_CURRENT_USER, _REG_KEY, 0, winreg.KEY_SET_VALUE
|
||||
) as key:
|
||||
winreg.DeleteValue(key, _APP_NAME)
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def is_enabled() -> bool:
|
||||
"""Return True if the autostart entry exists."""
|
||||
if sys.platform != "win32":
|
||||
return False
|
||||
try:
|
||||
import winreg # type: ignore[import-not-found]
|
||||
with winreg.OpenKey(
|
||||
winreg.HKEY_CURRENT_USER, _REG_KEY, 0, winreg.KEY_READ
|
||||
) as key:
|
||||
winreg.QueryValueEx(key, _APP_NAME)
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
Reference in New Issue
Block a user