Skip to content

fix(tauri): hide instead of destroy main window on Windows close (OPENHUMAN-TAURI-2X)#1548

Merged
senamakel merged 3 commits into
tinyhumansai:mainfrom
oxoxDev:fix/2x-tray-window-missing
May 13, 2026
Merged

fix(tauri): hide instead of destroy main window on Windows close (OPENHUMAN-TAURI-2X)#1548
senamakel merged 3 commits into
tinyhumansai:mainfrom
oxoxDev:fix/2x-tray-window-missing

Conversation

@oxoxDev
Copy link
Copy Markdown
Contributor

@oxoxDev oxoxDev commented May 12, 2026

Summary

  • On Windows, intercept the main window's close request and hide instead of destroy, matching the existing macOS behavior.
  • Fixes Sentry OPENHUMAN-TAURI-2X (~21 events, Windows-only): [tray] failed to show main window from tray click: main window not found.
  • Linux left out — setup_tray early-returns on Linux because tray creation panics in GTK during packaged runs.

Problem

Pre-fix: clicking the X close button on Windows destroys the main webview window. Subsequent tray-icon clicks call show_main_window → app.get_webview_window("main"), which returns None, surfacing the warn-level log [tray] failed to show main window from tray click: main window not found (app/src-tauri/src/lib.rs:939).

That log is captured by Sentry and shows up as OPENHUMAN-TAURI-2X — ~21 events from the China + Thailand Windows users observed in the last 72h. More importantly, the user loses the only re-entry point into the app: tray click is a no-op.

The macOS path already does the right thing (app/src-tauri/src/lib.rs:2081-2094CloseRequested → prevent_close → hide), but the #[cfg(target_os = "macos")] arm excluded Windows. macOS users got the canonical "close-button-hides" UX that pairs with the tray icon; Windows users got the standard destroy-on-close that breaks the tray-icon re-entry path.

Solution

Single-line cfg extension. The CloseRequested handler at app/src-tauri/src/lib.rs:2081 now matches #[cfg(any(target_os = "macos", target_os = "windows"))]. Same body — api.prevent_close() then window.hide(). Comment expanded to explain why Linux is intentionally excluded.

Linux exclusion preserved: setup_tray returns early on Linux today (GTK packaged-run panic, see existing code at app/src-tauri/src/lib.rs:861-867). Hide-on-close without a tray would strand the Linux user with no way to surface the window again, so the standard destroy-on-close behavior is the right default there.

The tray-click recovery path (show_main_window at app/src-tauri/src/lib.rs:825-859) is unchanged — once the window is merely hidden rather than destroyed, get_webview_window("main").show().unminimize().set_focus() works exactly as on macOS.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) — N/A: pure cfg-attribute extension; the macOS arm is already covered by the manual smoke checklist and there is no Rust-side unit harness for RunEvent::WindowEventhandlers inapp/src-tauri/`. Manual smoke step (Windows close → tray click → window reappears) is the canonical verification.
  • Diff coverage ≥ 80%N/A: behavioral parity with the already-shipped macOS branch; the touched lines are an existing handler getting an additional target platform.
  • Coverage matrix updated — N/A: no new user-visible feature row.
  • All affected feature IDs from the matrix are listed in the PR description under ## RelatedN/A: behaviour-only platform parity fix.
  • No new external network dependencies introduced (mock backend used per Testing Strategy)
  • Manual smoke checklist updated if this touches release-cut surfaces — N/A: no new smoke step (this restores the existing tray-click recovery path on Windows; verify on the next Windows release build per the standard tray smoke step).
  • Linked issue closed via Closes in the ## Related section

Impact

  • Runtime/platform: Windows desktop only (and macOS, unchanged). Linux unchanged. Pure Tauri-shell RunEvent handler change.
  • UX: Close button on Windows now hides the window instead of destroying it. To fully quit, users now use the tray menu's Quit item (already present at app/src-tauri/src/lib.rs:924-927) or File → Quit if present. This matches the established macOS pattern and matches the typical Win11 tray-app convention (Spotify / Slack / Discord all do this).
  • Observability: Sentry event volume drops on OPENHUMAN-TAURI-2X (~21 events / 72h). No follow-up filter needed — the warn log at app/src-tauri/src/lib.rs:939 stops firing once the window survives close.
  • Compatibility: no IPC / API / RPC surface change. macOS path identical (same arm, same body).
  • Security: no new surface.
  • Performance: negligible — runtime check is a constant per platform.

Related

  • Closes OPENHUMAN-TAURI-2X
  • Follow-up PR(s)/TODOs: consider surfacing a one-time toast/notification on first Windows close ("OpenHuman is still running in the tray — right-click the icon to quit") if user-research shows close-quits is the expectation here. Out of scope for this PR.

AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A — Sentry-driven, not Linear
  • URL: N/A

Commit & Branch

  • Branch: fix/2x-tray-window-missing
  • Commit SHA: see git log on PR

Validation Run

  • pnpm --filter openhuman-app format:check — N/A: no app/src/ changes
  • pnpm typecheck — N/A: no TS changes
  • Focused tests: N/A: no Rust-side test harness for RunEvent::WindowEvent handlers — manual smoke is the verification path.
  • Rust fmt/check (if changed): cargo check --manifest-path app/src-tauri/Cargo.toml clean (2m22s, 26 pre-existing warnings unrelated to this change)
  • Tauri fmt/check (if changed): part of the same app/src-tauri/Cargo.toml build — clean

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: Windows close-button now hides the main window instead of destroying it; tray-click recovery path stays functional after close.
  • User-visible effect: Windows users see the app stay in the tray when they hit the close button. Re-entry via tray click works as expected (no more silent failure).

Parity Contract

  • Legacy behavior preserved: macOS path identical to before; tray-icon menu items (tray_show_window, tray_quit) unchanged; show_main_window unchanged; Linux unchanged.
  • Guard/fallback/dispatch parity checks: cfg arm now mirrors the documented platform set where tray UX is enabled.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): N/A
  • Canonical PR: this PR
  • Resolution: N/A

Summary by CodeRabbit

  • Bug Fixes
    • Updated window close behavior on macOS and Windows so closing the main window hides it instead of fully terminating the app, allowing reopening from the system tray. Linux behavior remains unchanged.

Review Change Stack

…NHUMAN-TAURI-2X)

Extend the macOS-only CloseRequested→hide handler at lib.rs to also
include Windows. Without this, the OS destroys the webview when the
user clicks the close button; subsequent tray-icon clicks then call
`show_main_window` which calls `get_webview_window("main")`, returns
None, and emits the warn log that flooded Sentry as OPENHUMAN-TAURI-2X
(21 events, Windows-only).

Linux is left out: `setup_tray` early-returns on Linux because tray
creation panics inside GTK during packaged runs (existing behavior),
so hide-on-close there would strand the user with no way back. The
Linux close path keeps the standard destroy-on-close behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@oxoxDev oxoxDev requested a review from a team May 12, 2026 12:27
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 72fda51f-c5f4-468b-91b3-f07289c5d723

📥 Commits

Reviewing files that changed from the base of the PR and between 85d4611 and bd75ce0.

📒 Files selected for processing (1)
  • app/src-tauri/src/lib.rs

📝 Walkthrough

Walkthrough

The Tauri app event loop now expands close event interception from macOS-only to both macOS and Windows, preventing the webview from being destroyed on window close and enabling tray-based reopen behavior on Windows. Linux remains unchanged.

Changes

Tray Reopen on Windows

Layer / File(s) Summary
mascot_native_window platform gate
app/src-tauri/src/lib.rs
Widened the mascot_native_window module's #[cfg] from macOS-only to include Windows.
Platform-gated close event interception
app/src-tauri/src/lib.rs
Main window CloseRequested handler is now under #[cfg(any(target_os = "macos", target_os = "windows"))], calling api.prevent_close() and hiding the window to preserve the webview for tray-based reopen on those platforms.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • tinyhumansai/openhuman#610: Prior PR that introduced macOS-only close event interception for tray reopen; this PR generalizes that behavior to also apply on Windows.

Suggested reviewers

  • M3gA-Mind

Poem

🐰 A cozy hop, a tiny tweak,
Now Windows wakes where macOS speaks,
Close the pane, don't let it go—
Hidden, waiting, soft and slow,
Reopen from the tray's warm glow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: hiding instead of destroying the main window on Windows close, which directly matches the PR's core objective of extending macOS behavior to Windows.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src-tauri/src/lib.rs`:
- Around line 2090-2093: The Windows compile error is caused because WindowEvent
is only imported behind a macOS cfg while the RunEvent arm references
WindowEvent::CloseRequested for both macOS and Windows; fix it by ensuring
WindowEvent is available for that cfg path—either move or duplicate the use
tauri::WindowEvent import so it’s compiled for cfg(any(target_os = "macos",
target_os = "windows")), or change the match arm to reference the
fully-qualified tauri::WindowEvent::CloseRequested; update the RunEvent match
arm that currently mentions WindowEvent::CloseRequested accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d3675324-4113-4ac4-83ac-9f7ffcad9630

📥 Commits

Reviewing files that changed from the base of the PR and between 15c7442 and 85d4611.

📒 Files selected for processing (1)
  • app/src-tauri/src/lib.rs

Comment thread app/src-tauri/src/lib.rs
…ows too (OPENHUMAN-TAURI-2X)

Per CodeRabbit critical review on PR tinyhumansai#1548: the prior commit extended
the `RunEvent::WindowEvent { … }` match arm to also fire on Windows,
but the `use tauri::WindowEvent;` line was left at
`#[cfg(target_os = "macos")]`. On Windows builds the match arm
references `WindowEvent::CloseRequested` without the symbol in scope,
which is a hard compile error.

Extend the import cfg to match the arm cfg.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

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

Review — fix(tauri): hide instead of destroy main window on Windows close

Overall: Clean, well-scoped fix. The cfg widening is mechanically correct, Linux exclusion is justified, and the existing macOS handler body is correct for Windows too. Two minor items and one question below.

Verified ✅

  • #[cfg] on import and handler match — no compile-time mismatch
  • Linux exclusion intentional, documented, consistent with setup_tray early-return
  • No new JS injection, deps, secrets, or unwraps
  • Existing log::info! satisfies debug logging requirement
  • show_main_window is unconditional — correctly finds hidden window on tray click

Comment thread app/src-tauri/src/lib.rs
#[cfg(any(target_os = "macos", target_os = "windows"))]
RunEvent::WindowEvent {
label,
event: WindowEvent::CloseRequested { api, .. },
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[minor] With hide-on-close now active on Windows, the only way to fully quit is the tray's "Quit" menu item. Worth confirming that the tray quit path on Windows:

  1. Calls app.exit(0) (or equivalent) — not just window.close()
  2. Cleanly terminates the openhuman sidecar process (no orphaned core process after "quit")

If the tray quit item already calls app.exit(), this is a non-issue. A brief note confirming manual Windows testing would close the loop.

Not a code defect in the diff — the behavioral contract just changed for Windows users (X no longer exits the process), so the quit path becomes the sole shutdown vector.

Comment thread app/src-tauri/src/lib.rs
// None on the next tray-click and surfaces as
// `[tray] failed to show main window from tray click: main window
// not found` (OPENHUMAN-TAURI-2X — 21 events, Windows only).
// Linux is left out: `setup_tray` early-returns on Linux because
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[nitpick] The parenthetical (OPENHUMAN-TAURI-2X — 21 events, Windows only) embeds a point-in-time event count that will go stale. Consider simplifying to (OPENHUMAN-TAURI-2X, Windows-only) — the issue tracker has the live count.

@senamakel senamakel merged commit 3bfe53a into tinyhumansai:main May 13, 2026
17 checks passed
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