Skip to content

feat: add configurable close behavior (hide to tray / exit) with settings UI - #421

Open
LeonardW-sl wants to merge 2 commits into
xintaofei:mainfrom
LeonardW-sl:fix/linux-tray-hide-on-close
Open

feat: add configurable close behavior (hide to tray / exit) with settings UI#421
LeonardW-sl wants to merge 2 commits into
xintaofei:mainfrom
LeonardW-sl:fix/linux-tray-hide-on-close

Conversation

@LeonardW-sl

@LeonardW-sl LeonardW-sl commented Aug 7, 2026

Copy link
Copy Markdown

Problem

On Linux (and other platforms), clicking the main window's close button always exits the entire application. There is no way to minimize to the system tray and keep the app running in the background.

The existing can_hide_to_tray() check was already able to detect tray availability, but the close button simply checked can_hide_to_tray() without consulting any user preference — if the tray was available, it always hid; if not, it always exited. There was no UI for the user to choose their preferred behavior.

Solution

Add a configurable close-behavior setting with two options:

  1. Hide to tray (background) — default. When the close button is clicked and tray is available, the window hides to the system tray. The app keeps running, and the tray icon restores the window. When tray is not available (e.g., GNOME 45+ without AppIndicator), this falls back to exiting.
  2. Exit application — always exits the app on close button click, regardless of tray availability.

Changes

Backend (Rust):

  • models/system.rs: New CloseAction enum (HideToTray / Exit) and SystemCloseSettings struct, persisted via app_metadata_service.
  • commands/system_settings.rs: load_system_close_settings, get_system_close_settings, update_system_close_settings — all gated behind tauri-runtime to avoid dead_code warnings in sidecar builds.
  • lib.rs: Close button handler reads the stored setting and uses CloseAction::HideToTray && can_hide_to_tray() instead of can_hide_to_tray() alone.

Frontend (TypeScript/React):

  • lib/types.ts: CloseAction type and SystemCloseSettings interface.
  • lib/api.ts: getSystemCloseSettings() / updateSystemCloseSettings() transport wrappers.
  • components/settings/close-behavior-settings.tsx: Radio-button UI with loading/saving states and error toast.
  • components/settings/general-settings.tsx: Integrates the new section.
  • i18n/messages/*.json: All 10 locales updated with the 4 new strings.

Testing

  • 3,479 existing frontend tests pass (no regression).
  • Sidecar compiles cleanly (cargo build --no-default-features --bin codeg-mcp).
  • Main binary compiles cleanly (cargo build --release --bin codeg).
  • Setting persists across app restarts.
  • "Hide to tray" → close button hides window; tray icon restores it.
  • "Exit" → close button exits the app.
  • Default is "Hide to tray" (backward-compatible with existing behavior on tray-capable platforms).
  • Linux without tray: can_hide_to_tray() returns false, so both settings exit the app (no stranded process).

On Linux, Tauri's tray build() succeeds even when the desktop session
does not provide a StatusNotifierWatcher (notably GNOME 45+ without an
AppIndicator extension). In that case the tray icon is silently invisible
and hiding the main window would leave the user with no way to recover it.

Previously codeg avoided this by unconditionally returning false from
can_hide_to_tray() on Linux, which prevented hide-to-tray even on KDE,
XFCE, Cinnamon, Budgie, and GNOME-with-AppIndicator — all of which
have a working tray.

Fix: detect the actual tray availability at install_tray_icon() time
by querying D-Bus for org.kde.StatusNotifierWatcher. Only set
TRAY_AVAILABLE when the service is present, so the close handler hides
the window on fully capable desktops and exits otherwise.
Copilot AI lite review requested due to automatic review settings August 7, 2026 00:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Tauri (desktop) tray-availability logic so Linux sessions with a real, usable system tray can safely “hide to tray” on window close, while preserving the existing fail-safe behavior on desktops where the tray icon would be invisible.

Changes:

  • Add a Linux-only D-Bus check (via gdbus call org.freedesktop.DBus.NameHasOwner) to detect whether org.kde.StatusNotifierWatcher is present.
  • Stop unconditionally disabling hide-to-tray on Linux; instead, set TRAY_AVAILABLE only when the watcher is detected.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…ings UI

Add a new setting to let users choose what happens when the main window
close button is clicked:

- Hide to tray (background) — default. Window hides to system tray if
  available; falls back to exit if no tray is present.
- Exit application — always exits on close, regardless of tray.

Backend changes:
- New CloseAction enum + SystemCloseSettings model
- load_system_close_settings/get_system_close_settings/update_system_close_settings
- Close button handler reads stored setting instead of checking
  can_hide_to_tray() alone

Frontend changes:
- CloseBehaviorSettings component with radio-button UI
- Integrated into GeneralSettings page
- All 10 locales updated with 4 new strings
- 3 new unit tests covering load, save, and save-failure revert

All new items gated behind tauri-runtime feature to keep sidecar builds
clean. 3482 existing tests pass, no lint warnings.
@LeonardW-sl LeonardW-sl changed the title fix(linux): allow hide-to-tray when StatusNotifierWatcher is available feat: add configurable close behavior (hide to tray / exit) with settings UI Aug 7, 2026
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.

3 participants