Skip to content

feat(desktop): make macOS close behavior a user preference (#4024) - #5031

Open
iroiro147 wants to merge 1 commit into
block:mainfrom
iroiro147:fix/4045-rebase
Open

feat(desktop): make macOS close behavior a user preference (#4024)#5031
iroiro147 wants to merge 1 commit into
block:mainfrom
iroiro147:fix/4045-rebase

Conversation

@iroiro147

Copy link
Copy Markdown
Contributor

Supersedes #4045 (rebased onto current main; merged invoke_handler registration block — huddle::agent_voice handlers from #5004 + our close_to_tray handlers both preserved).

Summary

On macOS, closing Buzz's main window unconditionally prevented the close and hid the window, keeping the app running with no visible window. That suits background local-agent work but breaks users on window switchers70 2026-08-06 (like BetterTouchTool): Buzz vanishes from the switcher while still running, with no way back through normal window switching.

Add a persisted close-to-tray preference with three modes:

  • keepRunning (default): unchanged behavior — close hides the window and Buzz keeps running for background agent work (reopen via the tray icon).
  • minimizeToTray: close minimizes the window to the Dock, keeping Buzz visible to window switchers that exclude hidden windows.
  • quitWhenClosed: close quits Buzz like a conventional app.

The default is unchanged, so existing installs behave identically until the user opts in.

Changes

Backend (desktop/src-tauri)

  • New close_to_tray module: versioned JSON settings (close-to-tray.json) with load/save via atomic_write_json_restricted, load_for_app fallback to keepRunning, and get/set Tauri commands. 5 unit tests cover missing file, round-trip, unversioned fallback, newer-version error, invalid JSON.
  • AppState gains close_to_tray_behavior (resolved once in setup from load_for_app); the macOS WindowEvent::CloseRequested handler branches on it.
  • Commands registered in invoke_handler.

Frontend (desktop/src)

  • closeToTrayLogic: behavior union + options + validation (node-tested); invoke lazy so validation is unit-testable without the Tauri bridge.
  • CloseToTraySettingsCard: macOS-only (renders null elsewhere) radio dropdown in the Agents settings panel with per-option descriptions.

Verification

  • pnpm test (entire desktop suite): 4392/4392 pass.
  • pnpm typecheck: clean.
  • cargo check -p buzz-db: clean (relevant Rust regression surface; full Tauri build blocked by missing pre-built agent binaries — hermit bootstrap — pre-existing gap, no new warnings).

Signed-off

Signed-off-by: iroiro147 sarthak.singh@juspay.in

On macOS, closing Buzz's main window unconditionally prevented the close
and hid the window, keeping the app running with no visible window. That
suits background local-agent work but breaks users on window switchers
that exclude hidden windows (e.g. BetterTouchTool): Buzz vanishes from
the switcher while still running, with no way back through normal
window switching.

Add a persisted close-to-tray preference with three modes:

- keepRunning (default): unchanged behavior — close hides the window and
  Buzz keeps running for background agent work (reopen via the tray icon).
- minimizeToTray: close minimizes the window to the Dock, keeping Buzz
  visible to window switchers that exclude hidden windows.
- quitWhenClosed: close quits Buzz like a conventional app.

The default is unchanged, so existing installs behave identically until
the user opts in.

Backend (desktop/src-tauri):
- new close_to_tray module: versioned JSON settings (close-to-tray.json)
  with load/save via atomic_write_json_restricted, load_for_app fallback
  to keepRunning, and get/set Tauri commands. 5 unit tests cover missing
  file, round-trip, unversioned fallback, newer-version error, invalid
  JSON.
- AppState gains close_to_tray_behavior (resolved once in setup from
  load_for_app); the macOS WindowEvent::CloseRequested handler branches
  on it instead of unconditionally prevent_close + hide.
- commands registered in invoke_handler.

Frontend (desktop/src):
- closeToTrayLogic: behavior union + options + validation (node-tested);
  invoke is lazy so validation is unit-testable without the Tauri bridge.
- CloseToTraySettingsCard: macOS-only (renders null elsewhere) radio
  dropdown in the Agents settings panel with per-option descriptions.

Verification:
- cargo check (desktop src-tauri): 0 warnings.
- cargo test close_to_tray: 5/5 pass.
- clippy clean.
- Frontend validation logic run under node --experimental-strip-types.
- Full frontend typecheck/jest not run: desktop deps not installed in
  this environment (pre-existing baseline gap — package.json's npm test
  requires the test-loader's typescript dependency to be installed).

Signed-off-by: iroiro147 <sarthak.singh@juspay.in>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant