Repository navigation
Let the tray panel be moved and resized again - #758
Conversation
Since 0.70.0 the tray-panel flyout is the only dashboard and it could not be moved. Resizing from its outer frame (Tauri's built-in undecorated resize border) blurred the WebView before the native size loop started, so the blur-dismiss handler hid the panel; only the hidden 10px top/left grips worked. - Add a move strip along the top (startDragging). The spot the user drags the panel to is recorded when the Win32 move/size loop ends (WM_EXITSIZEMOVE, with WM_SIZING telling resizes from moves) and every later open or content-driven resize keeps it there, clamped into the monitor's work area. Double-clicking the strip anchors the panel to the tray again. - Add resize grips on every edge and corner. - Keep the panel open on blur while a mouse button is held with the cursor inside it, which covers native frame moves/resizes. - Re-clamp a placed panel after a DPI change rescales it. - Store the remembered panel size in logical px (new key) so it fits monitors with different scaling; the old physical-px size is ignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Treat a DPI rescale as programmatic so moving an auto-fit panel onto a monitor with other scaling doesn't freeze it at a fixed size. - Build the flyout without a maximize box so dragging it to a screen edge can't snap or maximize it. - Pick the monitor for a remembered spot by the panel's overlap with each work area (nearest one when it overlaps none) instead of its corner. - Re-clamp a placed panel on the Resized that follows a DPI change, when the new size is in place, and never reposition it during a user drag. - Check the window under the cursor rather than the panel's bounds, so a click on another topmost window covering the panel still dismisses it. - Stop arming the 15s gesture blur guard from the move strip and grips; the held-button check covers them and the guard swallowed the next real outside click. - Re-anchor after every settled user resize, react to primary presses only on the grips, and remove the subclass on WM_NCDESTROY. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (26)
Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review. 📝 WalkthroughWalkthroughThe tray panel now supports dragging, resizing from all edges and corners, and remembering its position and size. Saved sizes use logical pixels. Users can double-click the move strip to reset the panel beside the tray. ChangesTray panel geometry
Priority: ⬇️ Low Estimated code review effort: 4 (Complex) | ~60 minutes Change: Bug fix Sequence Diagram(s)sequenceDiagram
actor User
participant TrayPanel
participant TauriWindow
participant flyout_placement
participant geometry_store
User->>TrayPanel: Drag the move strip
TrayPanel->>TauriWindow: Start native window drag
TauriWindow->>flyout_placement: Report end of move/size loop
flyout_placement->>geometry_store: Save eligible position
User->>TrayPanel: Double-click the move strip
TrayPanel->>geometry_store: Reset saved position through Tauri command
Suggested reviewers: Merge Risk: ⚪ Minimal · up to No actionable issue is established that should block merging. Native move and reset interactions still warrant normal Windows validation. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The reviewed effects are limited to panel placement, sizing, and remembered window geometry. No increased access to sensitive data or privileges was identified. Interrupted or overlapping window actions still need runtime validation. Retained concerns Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
🚥 Pre-merge checks | ✅ 7 | ❓ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (7 passed)
Full details: Ui Changes Include Windows ProofExplanation The PR changes visible tray-panel UI. The diff adds a move handle and resize grips in ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
|
Maintainer validation at head Local CI ( UI proof: a fresh debug build of this head, driven over WebView2 CDP with a synthetic Codex-only profile (Hide Personal Info on), on a two-monitor setup. 19 of 19 checks pass.
Not re-proven here: a real mouse drag or edge resize (recording on Note for later, not caused by this PR: with no tray anchor (as in proof mode), re-anchoring falls back to the window's current monitor. Main has the same fallback chain. |
Summary
Since 0.70.0 (#712) the tray-panel flyout is the only dashboard, and it can no longer be moved or (in practice) resized:
TAURI_DRAG_RESIZE_BORDERS,tauri-runtime-wry/src/undecorated_resizing.rs). Pressing it starts a native size loop, Windows moves focus off the WebView, and the flyout's blur-dismiss hides the panel instantly. Only the hidden 10 px top/left grips worked, because they arm the gesture guard first.This PR makes the panel movable and resizable again:
startDragging). The spot is recorded when the Win32 move/size loop ends (WM_EXITSIZEMOVE). Windows only runs that loop for user drags, never forSetWindowPos, so the flyout's own re-anchoring is never mistaken for a move.WM_SIZINGtells a resize from a move; comparing bounds can't, because a move onto a monitor with another DPI rescales the window. After that, opens and content-driven resizes keep the panel at the spot, clamped into the work area it overlaps most. Double-clicking the strip forgets the spot and anchors the panel to the tray again (reset_flyout_position).Focused(false), the backend checks whether a mouse button is held and the window under the cursor belongs to the flyout. That covers native frame resizes and the strip/grips. The strip and grips therefore no longer arm the 15 s gesture guard, which also swallowed the next real outside click after a resize. A click on another topmost window covering the panel still dismisses it.flyoutLogical). The old physical-pxflyoutsize only fit the monitor it was taken on. It is ignored, so users who resized fall back to the legacytrayPanelsize or auto-fit once, following the precedent ofgeometry_store::migratedropping physical sizes. A DPI rescale is no longer treated as a user resize, which would have frozen an auto-fit panel. A placed panel is re-clamped once a rescale has been applied.maximizable(false), so dragging it to a screen edge doesn't snap or maximize it.Related issue
No issue filed; reported directly by a user on 0.70.0.
Affected areas
window_geometry.json: newentries.flyoutposition andsize_entries.flyoutLogical)docs/ARCHITECTURE.md,CHANGELOG.md)TrayMoveHandleHint(all 9 locales)Validation
cargo fmt --all --checkcargo clippy --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml --all-targets -- -D warnings: cleancargo test --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml: 633 passed (newshell::flyout_placementtests cover move vs resize, the cross-DPI move, and work-area choice)cargo test --manifest-path rust/Cargo.toml: 3691 passed, 1 failed (providers::codex::api::tests::external_oauth_gate_fails_closed_without_last_refresh). It reads the real user settings, and this machine hascodex_external_oauth_sources_allowed = true. Unrelated to this diff, which doesn't touchrust/src/providers.pnpm test: 666 passed, 1 failed (QuotaBurndownChartexpectsSep; this machine's OS locale is ja-JP). The full-suite runs also show the existing intermittentTrayPanel.test.tsxfailures. Upstreammainshows them too (density tests): a component's unmount cleanup runs after the describe-levelvi.restoreAllMocks(), and the error is attributed to the next test. The new tests unmount explicitly so they don't add to it. A mutation check confirmed the new DPI-rescale test fails without the fix.pnpm run lint,pnpm run check-locale(994 keys match),tsc --noEmit,pnpm run check:anti-slopscripts\local-check.ps1: not run as a whole; the steps above cover the Rust and frontend parts of the sliceUI / tray proof
The CUA
dragtool posts window messages, so it never enters the native move/size loop these fixes depend on. Instead I drove the real cursor from a per-monitor-DPI-aware PowerShell script (SetCursorPos+mouse_event) against freshtauri:build:debugbuilds, and read the window rect withGetWindowRectbefore and after. Setup: Windows 11, primary 2560×1440 @100% with a bottom taskbar, second monitor above it at 3840×2560 @225%.mainvisible=False)entries.flyout= new top-leftentries.flyoutremovedNotes for reviewers
shell/flyout_placement.rsinstalls a second comctl32 subclass on the flyout HWND. It goes throughrun_on_main_thread, becauseSetWindowSubclassfails across threads. Side note: the existingdwm::force_dark_caption_resizablecall for the flyout runs off-thread too, and the log showsdwm: subclass installed=0for it. I left that alone.stored_position()readswindow_geometry.jsonon eachreanchor, the same file-read pattern the size store already uses. Happy to cache it if you prefer.🤖 Generated with Claude Code
Summary by CodeRabbit