windows: run as tray icon app in the notification area#467
Open
inaiii wants to merge 1 commit into
Open
Conversation
Keep Lan Mouse running in the notification area after its window closes, use the GUI subsystem without breaking CLI output, and bundle reliable window, tray, and executable icons for distributed builds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Co-Authored-By: Codex (GPT-5) <noreply@openai.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add Windows notification-area (system tray) support, mirroring the existing macOS menu-bar application behavior and the Linux StatusNotifierItem support proposed in #466:
LAN_MOUSE_HIDDEN=1starts the application quietly in the tray;Related to #291. Together with #466, this covers the platforms requested there.
Behavior
Unlike the Linux PR, there is no external-daemon probe and the tray is set up unconditionally, matching the macOS status item: on Windows the GUI always spawns the service as a child process (a child finding the IPC socket already bound exits gracefully with
service already running!). In the uncommon case where the service was started externally (lan-mouse daemonin a terminal), the GUI still creates a tray icon and quitting from it exits only the GUI, leaving the external daemon running.A single left click on the tray icon presents the window; the menu (
Open Lan Mouse,Quit Lan Mouse) stays on right click. Thetray-iconcrate re-adds the icon after anexplorer.exerestart (TaskbarCreatedbroadcast).Implementation
tray-iconcrate (Shell_NotifyIconWunder the hood) with default features disabled; the defaults (gtk, libxdo) only apply to its Linux backend, which is unreachable behind the windows-only target dependency.cfg(windows).Send + Syncand cannot capture GTK objects.gio::Applicationwhile the window is hidden so the frontend stays alive.IconTheme::add_resource_pathon platforms without a system-installed icon theme.windowssubsystem so a GUI launch neither opens a console window nor dies with it (closing an attached console wouldCTRL_CLOSE_EVENT-terminate the frontend and service child alike, bypassing the tray). Terminal subcommands (daemon,cli,test-*,--help) re-attach to the parent console viaAttachConsole(ATTACH_PARENT_PROCESS)whenever command-line arguments are present, so their output keeps working; shell redirection takes precedence over the attached console and keeps working as well.build-aux/windows/lan-mouse.icointo the executable viawinresourceso Explorer, the Start menu, and pinned taskbar shortcuts display the application icon.LAN_MOUSE_HIDDENin the README.Fallback behavior
Registration failure is intentionally non-fatal. If the tray icon cannot be rendered or registered, the window is always shown and closing it quits the application, preventing an unreachable hidden process.
Relationship to #466, #407 and #373
lan-mouse-gtk/src/lib.rs,lan-mouse-gtk/Cargo.toml,src/main.rs, and the README; whichever lands second will be rebased, keeping the per-platform behavior unchanged.lan-mouse-gtk/src/lib.rsandsrc/main.rs. This PR does not change activation or instance handling —GApplicationalready provides single-instance behavior on Windows through its win32 session bus — so the overlap is textual and can be reconciled during rebase.src/main.rsandCargo.tomlfor its Windows service support. Thewindowssubsystem change here affects console behavior of the same binary; both changes are compatible (a service process has no interactive console either way) but will need a textual rebase.Test plan
Automated checks completed locally on Windows:
cargo fmt --all -- --checkcargo clippy --workspace --all-targets --all-features -- -D warningscargo test --workspace --all-featurescargo build/cargo build --releasemainbranch, and its source jobs checked outfeature/windows-tray-iconatf55e74b.Manual smoke test environment:
SendInputemulation)cargo build --releaseoff55e74b; single-instance handoff exercised against an installed build of the same branch running as primarySmoke tests completed on this environment:
windows_status_item registeredat debug level; the icon and tooltip render in the notification area).WM_CLOSE) hides it while the frontend and tray registration remain alive.LAN_MOUSE_HIDDEN=1starts the frontend without showing a window; the tray icon still registers.daemonprocess; a child that finds the service already running exits gracefully.WINDOWS_GUIsubsystem (no console window on GUI launch);--helpand thedaemonsubcommand print to redirected output as before.Open Lan MouseandQuit Lan Mouseactions; Open presents the hidden window.explorer.exere-adds the tray icon.ExtractIconExreports it; Explorer, Start menu, and pinned shortcuts display it).All manual smoke-test cases above were completed successfully.
No protocol or serialization changes are included, so no protocol version bump is required.