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,45 @@
|
||||
"""AR Display Manager entry point."""
|
||||
from __future__ import annotations
|
||||
|
||||
import signal
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def run(argv: list[str] | None = None) -> int:
|
||||
"""Launch the AR Display Manager daemon."""
|
||||
try:
|
||||
from PySide6.QtWidgets import QApplication
|
||||
except ImportError:
|
||||
sys.stderr.write(
|
||||
"PySide6 is not installed. Run:\n\n"
|
||||
" pip install PySide6\n"
|
||||
)
|
||||
return 2
|
||||
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL) # Ctrl+C kills the process
|
||||
|
||||
app = QApplication(argv if argv is not None else sys.argv)
|
||||
app.setApplicationName("AR Display Manager")
|
||||
app.setQuitOnLastWindowClosed(False) # keep running when popup closes
|
||||
|
||||
# Brand icon
|
||||
from PySide6.QtGui import QIcon
|
||||
_logo = REPO_ROOT / "display" / "assets" / "images" / "ar_logo_full.png"
|
||||
if _logo.exists():
|
||||
app.setWindowIcon(QIcon(str(_logo)))
|
||||
|
||||
# Apply brand stylesheet
|
||||
from arautopilot.studio.ar_style import apply_ar_style
|
||||
apply_ar_style(app)
|
||||
|
||||
from display_manager.display_manager import DisplayManager
|
||||
_mgr = DisplayManager(app) # noqa: F841 — kept alive via QObject parent=None
|
||||
|
||||
return app.exec()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run())
|
||||
Reference in New Issue
Block a user