The cut-off toast UX ("Accessibility granted. Relaunch Lan Mouse so
capture and emulat…") was unreadable in a compact window and split
the "grant" and "relaunch" flows into two disconnected surfaces. Fold
everything into the existing warning row with state-dependent content:
- AX missing:
title = "input capture is disabled"
subtitle = "grant Accessibility permission to enable"
button = "Grant" → opens System Settings → Accessibility
- AX granted, daemon still bailed:
title = "relaunch required"
subtitle = "Accessibility granted — restart to activate capture
and emulation"
button = "Relaunch" → spawns a fresh bundle via `open` after
a 1s delay, then quits.
- Both active: row hidden.
The emulation_status_row is kept hidden on macOS because capture and
emulation share the same TCC gate — a single row is sufficient and
two identical-looking warnings were noisy. `handle_emulation` still
exists for the non-macOS platforms where the rows are distinct.
Side effects:
- `relaunch_bundle` moved from lib.rs to macos_privacy so imp.rs can
call it from the row button handler.
- AX watcher callback shrinks to `window.present()` +
`refresh_capture_emulation_status()`; the toast-based dialog is
gone along with its helper.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
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>