Conversation
The window-state plugin was crashing when trying to call is_maximized() on the NSPanel (quick-pane), causing the app to panic on close. Changes: - Add explicit "main" label to window config for reliable state tracking - Increase default window size to 1200x800 - Exclude quick-pane from window-state plugin via with_denylist() - Add close handler to save window state and cleanup before exit See: tauri-apps/plugins-workspace#1546 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
WalkthroughThe changes add lifecycle management for the main window, implementing cleanup operations on close including window state persistence, panel hiding on macOS, and global shortcut unregistration. Window configuration is also updated with a new label identifier and increased dimensions. Changes
Sequence DiagramsequenceDiagram
participant MainWindow as Main Window
participant Runtime as Tauri Runtime
participant StatePlugin as Window State Plugin
participant Panel as tauri_nspanel
participant Shortcuts as Global Shortcuts
MainWindow->>Runtime: close request triggered
Runtime->>StatePlugin: save window state (desktop only)
StatePlugin-->>Runtime: state persisted
Runtime->>Panel: hide quick-pane (macOS only)
Panel-->>Runtime: panel hidden
Runtime->>Shortcuts: unregister all shortcuts (desktop only)
Shortcuts-->>Runtime: shortcuts unregistered
Runtime->>Runtime: emit cleanup logs
Runtime-->>MainWindow: close allowed
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src-tauri/src/lib.rs`:
- Around line 140-187: The call to panel.hide() uses a removed/nonexistent API;
update calls obtained via app_handle.get_webview_panel("quick-pane") to use the
v2.1 API by converting the panel to a Window and closing it (e.g., replace
panel.hide() with panel.to_window().close() or panel.close() per tauri_nspanel
v2.1 semantics), and make the same replacement for all occurrences (e.g., the
panel.hide() uses in the RunEvent handler and in the quick_pane command
functions).
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src-tauri/src/lib.rssrc-tauri/tauri.conf.json
🧰 Additional context used
📓 Path-based instructions (3)
{src-tauri/**/*.rs,src/**/*tauri*,vite.config.ts,tauri.conf.json}
📄 CodeRabbit inference engine (AGENTS.md)
Use only Tauri v2 documentation; avoid outdated v1 patterns
Files:
src-tauri/src/lib.rs
src-tauri/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Use modern Rust formatting:
format!("{variable}")instead of concatenation orprintln!macros
Files:
src-tauri/src/lib.rs
{src-tauri/**/*.rs,src/**/*.{ts,tsx}@(!(test|spec))}
📄 CodeRabbit inference engine (AGENTS.md)
Emit events from Rust to React using
app.emit("event-name", data)and listen in React withlisten("event-name", handler)
Files:
src-tauri/src/lib.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (rust)
🔇 Additional comments (3)
src-tauri/tauri.conf.json (1)
16-19: LGTM! Window configuration properly aligns with the Rust close handler.The explicit
"main"label is correctly referenced inlib.rsfor single-instance focus handling (line 34) and close cleanup (line 149). The increased dimensions remain within valid bounds relative tominWidth/minHeight.src-tauri/src/lib.rs (2)
12-12: LGTM! Correct imports for run loop event handling.The
RunEventandWindowEventimports are required for the.build(...).run(...)pattern introduced below.
42-51: Good fix with proper documentation.The denylist correctly excludes the
quick-paneNSPanel from window-state tracking, preventing the crash when the plugin iterates windows and callsis_maximized(). The issue reference is helpful for future maintainers.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| .build(tauri::generate_context!()) | ||
| .expect("error while building tauri application") | ||
| .run(|app_handle, event| { | ||
| if let RunEvent::WindowEvent { | ||
| label, | ||
| event: WindowEvent::CloseRequested { .. }, | ||
| .. | ||
| } = &event | ||
| { | ||
| if label == "main" { | ||
| log::info!("Main window close requested - performing cleanup"); | ||
|
|
||
| // Save window state before closing | ||
| #[cfg(desktop)] | ||
| { | ||
| use tauri_plugin_window_state::{AppHandleExt, StateFlags}; | ||
| if let Err(e) = app_handle.save_window_state(StateFlags::all()) { | ||
| log::warn!("Failed to save window state: {e}"); | ||
| } else { | ||
| log::info!("Window state saved successfully"); | ||
| } | ||
| } | ||
|
|
||
| // Hide the quick-pane panel before main window closes | ||
| #[cfg(target_os = "macos")] | ||
| { | ||
| use tauri_nspanel::ManagerExt; | ||
| if let Ok(panel) = app_handle.get_webview_panel("quick-pane") { | ||
| log::debug!("Hiding quick-pane panel before close"); | ||
| panel.hide(); | ||
| } | ||
| } | ||
|
|
||
| // Unregister global shortcuts | ||
| #[cfg(desktop)] | ||
| { | ||
| use tauri_plugin_global_shortcut::GlobalShortcutExt; | ||
| if let Err(e) = app_handle.global_shortcut().unregister_all() { | ||
| log::warn!("Failed to unregister global shortcuts: {e}"); | ||
| } else { | ||
| log::debug!("Global shortcuts unregistered"); | ||
| } | ||
| } | ||
|
|
||
| log::info!("Cleanup complete, allowing close to proceed"); | ||
| } | ||
| } | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check the actual file to see imports and context
cat -n src-tauri/src/lib.rs | head -50Repository: dannysmith/tauri-template
Length of output: 2202
🌐 Web query:
tauri_nspanel v2.1 panel hide method API
💡 Result:
Short answer: tauri-nspanel v2.1 doesn't expose a dedicated panel.hide() — use panel.show()/show_and_make_key() to show, and close() (via the panel -> window conversion) to hide/close the panel. If you need the panel fully released, call panel.set_released_when_closed(true) before closing. See README/docs. [1][2]
Sources:
- README usage (show, show_and_make_key, close via to_window()). [1]
- PanelBuilder API docs (builder options including released_when_closed). [2]
🏁 Script executed:
# Search for tauri_nspanel usage in the codebase
rg -n "tauri_nspanel" --type rust -A 3 -B 3Repository: dannysmith/tauri-template
Length of output: 1513
🏁 Script executed:
# Check for panel.hide() or alternative methods in the codebase
rg -n "panel\.(hide|order_out|close|order_front)" --type rust -B 2 -A 2Repository: dannysmith/tauri-template
Length of output: 1230
🌐 Web query:
Tauri v2 .build().run() event loop pattern documentation
💡 Result:
Short answer — use the Builder::build(...).run(...) callback which receives the AppHandle and RunEvent and matches on RunEvent variants (ExitRequested, WindowEvent, Ready, etc.). Typical pattern:
- Configure with tauri::Builder::default().setup(...) (and other builders).
- Call .build(tauri::generate_context!()).
- Call .run(|app_handle, event| match event { ... }) to handle the event loop synchronously in-process (or use run_return / run_iteration variants when appropriate).
Examples and docs:
- Official Tauri v2 "Calling Rust from the Frontend" / event-listening examples (setup + listen + .run usage). (v2.tauri.app)
- tauri crate docs (App.run / run_return / run_iteration and RunEvent API). (docs.rs)
- Plugin Builder.on_event example showing on_event callbacks for the same RunEvent variants. (docs.rs)
If you want, I can paste a minimal example main.rs using the .build().run(|app_handle, event| ...) pattern.
Citations:
- 1: https://v2.tauri.app/fr/develop/calling-rust/?utm_source=openai
- 2: https://docs.rs/tauri/latest/tauri/struct.App.html?utm_source=openai
- 3: https://docs.rs/tauri/latest/tauri/plugin/struct.Builder.html?utm_source=openai
Replace panel.hide() with the correct tauri_nspanel v2.1 API
The panel.hide() call does not exist in tauri_nspanel v2.1 documentation. According to the official API, hiding a panel should use panel.close() (via to_window() conversion if needed) or another supported method. This affects lines 169 in this file and also lines 99 and 281 in src-tauri/src/commands/quick_pane.rs. Replace all panel.hide() calls with the correct API method from the tauri_nspanel documentation.
The .build(...).run(...) pattern is correct for Tauri v2, and the cleanup sequence (state → panel → shortcuts) is logically sound.
🤖 Prompt for AI Agents
In `@src-tauri/src/lib.rs` around lines 140 - 187, The call to panel.hide() uses a
removed/nonexistent API; update calls obtained via
app_handle.get_webview_panel("quick-pane") to use the v2.1 API by converting the
panel to a Window and closing it (e.g., replace panel.hide() with
panel.to_window().close() or panel.close() per tauri_nspanel v2.1 semantics),
and make the same replacement for all occurrences (e.g., the panel.hide() uses
in the RunEvent handler and in the quick_pane command functions).
Summary
is_maximized()on NSPanelDetails
The
tauri-plugin-window-statecrashes when it iterates all windows on close and tries to callis_maximized()on the quick-pane NSPanel. This causes a "panic in a function that cannot unwind" error.Fix: Use
with_denylist(&["quick-pane"])to exclude the NSPanel from window-state tracking.See: tauri-apps/plugins-workspace#1546
Test plan
bun run tauri:dev🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
Bug Fixes
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.