Add minimize to system tray#789
Conversation
|
The issue with all the systray solutions LLM's come up with is that they don't understand Gremlin's constraints well. As a result they always want to use QtWidget's based solutions which will work right now, but once the input viewer is reworked nothing in Gremlin requires QtWidgets and they will be dropped. As such adding new components that requires that won't work. There is a QML system tray icon but that falls back onto QtWidgets, making it not suitable. This effectively leaves a solution that directly uses Window's systray interface via pywin32 which Gremlin requires as a dependency anyway. |
Restores the pre-R14 minimize-to-tray behaviour as an opt-in option. When 'minimize-to-tray' is enabled, minimizing the window hides it to a tray icon instead of the taskbar; clicking the icon restores it. The tray menu offers profile activate/deactivate and quit (via the window's close path so unsaved changes are still flagged), and the icon reflects the active state. Implemented directly against the Win32 Shell_NotifyIcon API via pywin32 (already a Gremlin dependency) rather than QtWidgets' QSystemTrayIcon, so it adds no QtWidgets dependency. Window show/hide goes through the QML QWindow (QtGui). Self-contained in gremlin/ui/tray.py plus the option registration and tray creation in joystick_gremlin.py.
76e91ef to
d508e36
Compare
|
Reworked to use the Win32 A hidden helper window handles the icon's mouse/menu messages (its wndproc is driven by Qt's running event loop), and window show/hide still goes through the QML |
|
Ran it through my usual merge steps, the LLM comes up with these things it thinks may be troublesome: 0. remove() double-deletes the tray icon, and _on_destroy is a confused fallbackremove() calls NIM_DELETE, then DestroyWindow. DestroyWindow sends WM_DESTROY synchronously, which dispatches to _on_destroy, which calls NIM_DELETE again. The second call silently fails (the icon is already gone), but the two methods now share responsibility for the same side-effect. The intent of _on_destroy is clearly a defensive fallback for abnormal window destruction — it should be the only place NIM_DELETE lives, and remove() should just call DestroyWindow. 1. Upgrade to NOTIFYICON_VERSION_4The current code uses the pre-Vista notification protocol. Calling NIM_SETVERSION after NIM_ADD unlocks: Cursor position packed into wparam (eliminates the GetCursorPos call) NIN_SELECT for keyboard-driven activation (accessibility) 2. Make the helper window invisible to the shellThe current CreateWindow uses WS_OVERLAPPED (= 0) at zero size, which works but relies on the window being invisible by accident. A zero-size overlapped window can briefly flicker in the taskbar on some DWM configurations. Use reateWindowEx with WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE to explicitly exclude it from the taskbar and Alt+Tab. 3. Add NIF_SHOWTIP to the notification dataNIF_SHOWTIP (added in Vista) opts into the modern rich tooltip and ensures the tip text shows even when the user has balloon tips suppressed by group policy. Probably giving these files as context to an LLM will make it understand these inputs: |
Restores the pre-R14 minimize-to-tray behaviour as an opt-in option.
What
minimize-to-trayoption (off by default). When enabled, minimizing the main window hides it to a tray icon instead of the taskbar; clicking the icon restores and focuses it.QSystemTrayIcon.isSystemTrayAvailable().Backend.activityChanged) and quit — quit routes through the window's normal close path so the unsaved-changes prompt still fires.Notes
gremlin/ui/tray.py;joystick_gremlin.pyonly registers the option and creates the icon. No behaviour change when the option is off.gfx/icon*.icoassets andBackendsignals; nothing added tosignal.