Now that we always route Reenable clicks to the Accessibility pane on
macOS 13+ (AX transitively covers Input Monitoring listen-only and
Post Event, and the bundle isn't listed in the separate panes anyway),
the CapturePane / EmulationPane enums and their non-Accessibility
variants are dead weight. Remove them along with:
- `missing_capture_pane` / `missing_emulation_pane`
- `open_input_monitoring_settings` / `open_post_event_settings`
- `input_monitoring_granted` / `post_event_granted` preflight wrappers
- the `CGPreflightListenEventAccess` / `CGPreflightPostEventAccess`
FFI declarations in lan-mouse-gtk (the daemon crates keep their own)
`handle_capture` / `handle_emulation` collapse to a single helper that
opens the Accessibility pane if AX is missing, otherwise just retries.
`ensure_listed_in_input_monitoring` is kept because it still has a
side effect on macOS 13/14, where Input Monitoring is a separately-
granted category.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The daemon subprocess initializes at startup and bails immediately if
Accessibility is missing ("accessibility permission is required"). If
the user then grants AX mid-session via the system prompt, the daemon
has no way to retry from its bailed state — capture and emulation
stay dead until the next restart. Make the GUI watch for the AX
transition and surface a toast with a "Relaunch" button that quits
the app and spawns a fresh instance via Launch Services.
While here:
- Route capture/emulation "missing pane" fallback to the Accessibility
pane instead of the Input Monitoring / Post Event panes when AX is
already granted. On macOS 13+ those separate grants auto-confer via
Accessibility and the bundle typically isn't listed in the IM pane
at all, so the old navigation was a dead end.
- Reword the status-row subtitles so the action is clearer: the user
now sees "click Reenable to grant permission" instead of a generic
"required for outgoing connections".
- Bump libadwaita feature flag to v1_2 for AdwToast button signals.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On macOS the three TCC grants (Accessibility, Input Monitoring, Post
Event) live in separate Privacy panes. Before this change the
"Reenable" row sent the user to Accessibility regardless of which
grant was actually missing, and the daemon's own permission checks
re-fired the Accessibility prompt on every retry.
- lan-mouse-gtk/src/macos_privacy.rs: new module that exposes silent
preflight checks (AXIsProcessTrusted, CGPreflightListenEventAccess,
CGPreflightPostEventAccess), per-pane URL-scheme navigation, and
a Once-guarded fire_initial_prompts() called from build_ui. The
initial-prompt path only fires the Accessibility prompt if AX is
missing and then returns; secondary registrations run only after
AX is granted, which prevents a double Accessibility alert on
Sequoia where Post Event is nested under Accessibility.
- Input Monitoring registration attempts CGEventTapCreate at
kCGSessionEventTap (not kCGHIDEventTap) so a failure surfaces as
an Input Monitoring signal rather than triggering an Accessibility
prompt as a side effect.
- lan-mouse-gtk/src/window/imp.rs: handle_capture / handle_emulation
switch on the missing-pane enum and navigate to the specific pane
via x-apple.systempreferences:... URLs before re-requesting.
- lan-mouse-gtk/resources/window.ui: pill class on the Reenable
buttons so the hover padding matches the rest of libadwaita.
- input-capture/src/macos.rs, input-emulation/src/macos.rs: make
request_*_permission() a silent preflight (AXIsProcessTrusted /
CGPreflightListenEventAccess / CGPreflightPostEventAccess), so the
daemon no longer fires TCC prompts on retry — all prompting is
owned by the GUI.
- input-capture/src/error.rs, input-emulation/src/error.rs: new
error variants so the GUI can distinguish missing-AX from
missing-IM / missing-PostEvent for pane routing.
Verified on macOS 15.5: first launch fires a single AX prompt;
second launch (AX granted) registers under Input Monitoring via the
session-tap attempt and requests Post Event. Sequoia auto-grants the
listen-only path via AX so the IM list may stay empty, which is the
intended OS behavior and no longer blocks capture.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ship Lan Mouse on macOS as an accessory app (no Dock icon, no main
window on launch) with a status-bar item for show/quit. Closing the
window hides it instead of quitting so the menu bar stays the primary
surface.
- build-aux/macos-lsui-element.plist: LSUIElement=true plus
NSInputMonitoringUsageDescription and NSAppleEventsUsageDescription
(merged into Info.plist via cargo-bundle's osx_info_plist_exts).
- lan-mouse-gtk/src/macos_status_item.rs: NSStatusItem setup via raw
objc_msgSend FFI. Loads a bundled 22pt PNG as a template image so
it auto-tints for light/dark menu bars.
- scripts/makeicns.sh: emit Contents/Resources/menubar-template.png
from the existing SVG.
- scripts/copy-macos-dylib.sh: flatten cargo-bundle's preserved
target/ subdir under Resources so NSBundle pathForResource: finds
the template image.
- lan-mouse-gtk/src/lib.rs: register the new modules, set up a
Cmd+Q-wired quit action, configure bundle env vars (schemas,
XDG_DATA_DIRS, GTK_DATA_PREFIX) when running from inside the .app,
and filter the known upstream Gtk theme-parser warning spam.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On macOS the Adwaita icon theme is not installed by default, so
symbolic icons (edit-copy, auth-fingerprint, network-wired,
dialog-warning, etc.) render as the "image-missing" placeholder.
Bundle the symbolic SVGs used by the GTK frontend into the embedded
gresource so the app is self-contained and doesn't depend on any
system-installed icon theme. The existing
`IconTheme::add_resource_path("/de/feschber/LanMouse/icons")` call
already tells GTK to search this prefix, so no code changes are
needed.
Icons are sourced from Adwaita and placed under the standard
`scalable/{actions,devices,places,status}/` hicolor layout.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
*breaking change*
this changes the configuration syntax, allowing for an unlimited amount of configured clients.
Also a first step towards enabling a "save config" feature.
client configuration now applies immediately instead of after enabling / disabling clients.
Also fixes a potential feedback loop when changing settings.