From 2f841f3d727f605c651e107de718b89b55229229 Mon Sep 17 00:00:00 2001 From: juafeis Date: Tue, 14 Jul 2026 16:29:41 +0200 Subject: [PATCH 1/5] Fix FloatBar minimized geometry restore --- .../src-tauri/src/floatbar/window.rs | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/apps/desktop-tauri/src-tauri/src/floatbar/window.rs b/apps/desktop-tauri/src-tauri/src/floatbar/window.rs index d498cbf046..bdecd146fc 100644 --- a/apps/desktop-tauri/src-tauri/src/floatbar/window.rs +++ b/apps/desktop-tauri/src-tauri/src/floatbar/window.rs @@ -13,6 +13,22 @@ const FLOATBAR_DEFAULT_WIDTH_H: f64 = 360.0; const FLOATBAR_DEFAULT_HEIGHT_H: f64 = 36.0; const FLOATBAR_DEFAULT_WIDTH_V: f64 = 80.0; const FLOATBAR_DEFAULT_HEIGHT_V: f64 = 280.0; +const WINDOWS_MINIMIZED_COORDINATE: i32 = -32_000; +const WINDOWS_MAX_SCALE_FACTOR: i32 = 5; + +/// Windows parks minimized windows at (-32000, -32000). Geometry is stored in +/// logical pixels, so HiDPI scaling can turn that sentinel into an equal pair +/// as small as (-6400, -6400) at the maximum supported 500% scale. +fn is_windows_minimized_position(x: i32, y: i32) -> bool { + let scaled_limit = WINDOWS_MINIMIZED_COORDINATE / WINDOWS_MAX_SCALE_FACTOR; + (WINDOWS_MINIMIZED_COORDINATE..=scaled_limit).contains(&x) + && (WINDOWS_MINIMIZED_COORDINATE..=scaled_limit).contains(&y) + && x.abs_diff(y) <= 1 +} + +fn should_remember_position(is_minimized: bool, x: i32, y: i32) -> bool { + !is_minimized && !is_windows_minimized_position(x, y) +} /// Initial dimensions (logical pixels) for the floating bar given an /// orientation string. Unknown values fall back to horizontal so callers @@ -84,7 +100,9 @@ pub fn show( // Restore prior geometry if we have one. Otherwise, taskbar style opens // near the bottom while the original floating style keeps its top-center // placement. - if let Some(g) = geometry_store::load_entry(FLOATBAR_LABEL) { + if let Some(g) = geometry_store::load_entry(FLOATBAR_LABEL) + .filter(|g| !is_windows_minimized_position(g.x, g.y)) + { let _ = win.set_position(LogicalPosition::new(g.x as f64, g.y as f64)); if let (Some(w), Some(h)) = (g.width, g.height) { let _ = win.set_size(LogicalSize::new(w as f64, h as f64)); @@ -138,6 +156,10 @@ pub fn remember_geometry>(window: &M) { let Ok(pos) = window.outer_position() else { return; }; + let is_minimized = window.is_minimized().unwrap_or(false); + if !should_remember_position(is_minimized, pos.x, pos.y) { + return; + } let Ok(size) = window.outer_size() else { return; }; @@ -162,6 +184,7 @@ pub trait WindowGeometry { fn outer_position(&self) -> tauri::Result>; fn outer_size(&self) -> tauri::Result>; fn scale_factor(&self) -> tauri::Result; + fn is_minimized(&self) -> tauri::Result; } impl WindowGeometry for tauri::WebviewWindow { @@ -174,6 +197,9 @@ impl WindowGeometry for tauri::WebviewWindow { fn scale_factor(&self) -> tauri::Result { tauri::WebviewWindow::scale_factor(self) } + fn is_minimized(&self) -> tauri::Result { + tauri::WebviewWindow::is_minimized(self) + } } impl WindowGeometry for tauri::Window { @@ -186,6 +212,9 @@ impl WindowGeometry for tauri::Window { fn scale_factor(&self) -> tauri::Result { tauri::Window::scale_factor(self) } + fn is_minimized(&self) -> tauri::Result { + tauri::Window::is_minimized(self) + } } /// Resize the floatbar to the given logical dimensions and re-assert the @@ -407,4 +436,25 @@ mod tests { (FLOATBAR_DEFAULT_WIDTH_H, FLOATBAR_DEFAULT_HEIGHT_H) ); } + + #[test] + fn windows_minimized_positions_are_not_restored() { + assert!(is_windows_minimized_position(-32_000, -32_000)); + assert!(is_windows_minimized_position(-16_000, -16_000)); + assert!(is_windows_minimized_position(-6_400, -6_400)); + } + + #[test] + fn legitimate_negative_monitor_positions_are_preserved() { + assert!(!is_windows_minimized_position(-3_840, 0)); + assert!(!is_windows_minimized_position(-8_000, -4_000)); + assert!(!is_windows_minimized_position(-5_000, -5_000)); + } + + #[test] + fn minimized_or_parked_positions_are_not_remembered() { + assert!(!should_remember_position(true, 100, 100)); + assert!(!should_remember_position(false, -32_000, -32_000)); + assert!(should_remember_position(false, -3_840, 100)); + } } From 93933504606516a084f85826ed8544ab389b57b2 Mon Sep 17 00:00:00 2001 From: juafeis Date: Tue, 14 Jul 2026 23:49:49 +0200 Subject: [PATCH 2/5] Use physical coordinates for FloatBar guard --- .../src-tauri/src/floatbar/window.rs | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/apps/desktop-tauri/src-tauri/src/floatbar/window.rs b/apps/desktop-tauri/src-tauri/src/floatbar/window.rs index bdecd146fc..86af461f54 100644 --- a/apps/desktop-tauri/src-tauri/src/floatbar/window.rs +++ b/apps/desktop-tauri/src-tauri/src/floatbar/window.rs @@ -14,19 +14,15 @@ const FLOATBAR_DEFAULT_HEIGHT_H: f64 = 36.0; const FLOATBAR_DEFAULT_WIDTH_V: f64 = 80.0; const FLOATBAR_DEFAULT_HEIGHT_V: f64 = 280.0; const WINDOWS_MINIMIZED_COORDINATE: i32 = -32_000; -const WINDOWS_MAX_SCALE_FACTOR: i32 = 5; -/// Windows parks minimized windows at (-32000, -32000). Geometry is stored in -/// logical pixels, so HiDPI scaling can turn that sentinel into an equal pair -/// as small as (-6400, -6400) at the maximum supported 500% scale. +/// Windows parks minimized windows at the exact physical coordinate pair +/// (-32000, -32000). Keep this strict so legitimate negative monitor origins +/// are never mistaken for minimized geometry. fn is_windows_minimized_position(x: i32, y: i32) -> bool { - let scaled_limit = WINDOWS_MINIMIZED_COORDINATE / WINDOWS_MAX_SCALE_FACTOR; - (WINDOWS_MINIMIZED_COORDINATE..=scaled_limit).contains(&x) - && (WINDOWS_MINIMIZED_COORDINATE..=scaled_limit).contains(&y) - && x.abs_diff(y) <= 1 + x == WINDOWS_MINIMIZED_COORDINATE && y == WINDOWS_MINIMIZED_COORDINATE } -fn should_remember_position(is_minimized: bool, x: i32, y: i32) -> bool { +fn should_remember_physical_position(is_minimized: bool, x: i32, y: i32) -> bool { !is_minimized && !is_windows_minimized_position(x, y) } @@ -157,7 +153,7 @@ pub fn remember_geometry>(window: &M) { return; }; let is_minimized = window.is_minimized().unwrap_or(false); - if !should_remember_position(is_minimized, pos.x, pos.y) { + if !should_remember_physical_position(is_minimized, pos.x, pos.y) { return; } let Ok(size) = window.outer_size() else { @@ -438,23 +434,26 @@ mod tests { } #[test] - fn windows_minimized_positions_are_not_restored() { + fn windows_minimized_position_is_not_restored() { assert!(is_windows_minimized_position(-32_000, -32_000)); - assert!(is_windows_minimized_position(-16_000, -16_000)); - assert!(is_windows_minimized_position(-6_400, -6_400)); } #[test] fn legitimate_negative_monitor_positions_are_preserved() { assert!(!is_windows_minimized_position(-3_840, 0)); - assert!(!is_windows_minimized_position(-8_000, -4_000)); - assert!(!is_windows_minimized_position(-5_000, -5_000)); + assert!(!is_windows_minimized_position(-8_000, -8_000)); + assert!(!is_windows_minimized_position(-16_000, -16_000)); } #[test] - fn minimized_or_parked_positions_are_not_remembered() { - assert!(!should_remember_position(true, 100, 100)); - assert!(!should_remember_position(false, -32_000, -32_000)); - assert!(should_remember_position(false, -3_840, 100)); + fn minimized_or_parked_physical_positions_are_not_remembered() { + assert!(!should_remember_physical_position(true, 100, 100)); + assert!(!should_remember_physical_position(false, -32_000, -32_000)); + assert!(should_remember_physical_position(false, -3_840, 100)); + } + + #[test] + fn physical_multi_monitor_origin_is_remembered() { + assert!(should_remember_physical_position(false, -8_000, -8_000)); } } From 3f1f37b90bf4647a249e64704aea96bb087ddbb8 Mon Sep 17 00:00:00 2001 From: juafeis Date: Wed, 15 Jul 2026 01:57:03 +0200 Subject: [PATCH 3/5] Recover FloatBar after monitor disconnect --- .../src-tauri/src/floatbar/mod.rs | 12 +- .../src-tauri/src/floatbar/window.rs | 186 +++++++++++++++++- 2 files changed, 196 insertions(+), 2 deletions(-) diff --git a/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs b/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs index da80e4f91b..1a45d19255 100644 --- a/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs +++ b/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs @@ -46,8 +46,17 @@ pub fn handle_window_event(window: &tauri::Window, event: &tauri::WindowEvent) - } match event { tauri::WindowEvent::Moved(_) | tauri::WindowEvent::Resized(_) => { - window::remember_geometry(window); + // Visibility recovery loads style only if it actually relocates. + // Always reassert topmost on geometry change; shell-event path + // in topmost_guard stays overlap-gated. + let relocated = window::ensure_visible_on_active_monitor(window, None); + if !relocated { + window::remember_geometry(window); + } if let Some(floatbar) = window.app_handle().get_webview_window(FLOATBAR_LABEL) { + if relocated { + window::apply_no_activate(&floatbar); + } window::apply_always_on_top(&floatbar); } } @@ -92,6 +101,7 @@ pub fn apply_state(app: &tauri::AppHandle, settings: &Settings) { } else if !settings.float_bar_enabled && open { let _ = window::hide(app); } else if let Some(w) = app.get_webview_window(FLOATBAR_LABEL) { + window::ensure_visible_on_active_monitor(&w, &settings.float_bar_style); window::apply_no_activate(&w); window::apply_opacity(&w, settings.float_bar_opacity); window::apply_click_through(&w, settings.float_bar_click_through); diff --git a/apps/desktop-tauri/src-tauri/src/floatbar/window.rs b/apps/desktop-tauri/src-tauri/src/floatbar/window.rs index 86af461f54..d528dfcd8a 100644 --- a/apps/desktop-tauri/src-tauri/src/floatbar/window.rs +++ b/apps/desktop-tauri/src-tauri/src/floatbar/window.rs @@ -3,7 +3,7 @@ //! Tauri window labeled `floatbar`, independent of the main surface //! state machine. -use tauri::{LogicalPosition, LogicalSize, Manager, WebviewUrl}; +use tauri::{LogicalPosition, LogicalSize, Manager, PhysicalPosition, PhysicalSize, WebviewUrl}; use crate::geometry_store; @@ -26,6 +26,106 @@ fn should_remember_physical_position(is_minimized: bool, x: i32, y: i32) -> bool !is_minimized && !is_windows_minimized_position(x, y) } +fn physical_rects_intersect( + first_position: PhysicalPosition, + first_size: PhysicalSize, + second_position: PhysicalPosition, + second_size: PhysicalSize, +) -> bool { + let first_left = i64::from(first_position.x); + let first_top = i64::from(first_position.y); + let first_right = first_left + i64::from(first_size.width); + let first_bottom = first_top + i64::from(first_size.height); + let second_left = i64::from(second_position.x); + let second_top = i64::from(second_position.y); + let second_right = second_left + i64::from(second_size.width); + let second_bottom = second_top + i64::from(second_size.height); + + first_left < second_right + && first_right > second_left + && first_top < second_bottom + && first_bottom > second_top +} + +fn fallback_physical_position( + work_area_position: PhysicalPosition, + work_area_size: PhysicalSize, + window_size: PhysicalSize, + scale_factor: f64, + style: &str, +) -> PhysicalPosition { + let available_width = work_area_size.width.saturating_sub(window_size.width); + let available_height = work_area_size.height.saturating_sub(window_size.height); + let scale_factor = if scale_factor.is_finite() && scale_factor > 0.0 { + scale_factor + } else { + 1.0 + }; + let edge_padding = (8.0 * scale_factor).round() as u32; + let x = work_area_position + .x + .saturating_add((available_width / 2).min(i32::MAX as u32) as i32); + let y_offset = if style == "taskbar" { + available_height.saturating_sub(edge_padding) + } else { + edge_padding.min(available_height) + }; + let y = work_area_position + .y + .saturating_add(y_offset.min(i32::MAX as u32) as i32); + + PhysicalPosition::new(x, y) +} + +/// Move a FloatBar that no longer intersects an active monitor onto the +/// primary monitor. This covers both stale geometry from a disconnected +/// display and Windows parking the live window at (-32000, -32000) when a +/// monitor is powered off. +pub(super) fn ensure_visible_on_active_monitor>( + window: &M, + style: &str, +) -> bool { + let Ok(position) = window.outer_position() else { + return false; + }; + let Ok(size) = window.outer_size() else { + return false; + }; + let Ok(monitors) = window.available_monitors() else { + return false; + }; + if monitors.iter().any(|monitor| { + let work_area = monitor.work_area(); + physical_rects_intersect(position, size, work_area.position, work_area.size) + }) { + return false; + } + + let target_monitor = window + .primary_monitor() + .ok() + .flatten() + .or_else(|| monitors.into_iter().next()); + let Some(target_monitor) = target_monitor else { + return false; + }; + let work_area = target_monitor.work_area(); + let target = fallback_physical_position( + work_area.position, + work_area.size, + size, + target_monitor.scale_factor(), + style, + ); + + if window.is_minimized().unwrap_or(false) + || is_windows_minimized_position(position.x, position.y) + { + let _ = window.unminimize(); + } + window.set_physical_position(target).is_ok() +} + /// Initial dimensions (logical pixels) for the floating bar given an /// orientation string. Unknown values fall back to horizontal so callers /// don't have to pre-validate. @@ -61,6 +161,7 @@ pub fn show( apply_opacity(&window, opacity); apply_click_through(&window, click_through); apply_always_on_top(&window); + ensure_visible_on_active_monitor(&window, style); window.show().map_err(|e| e.to_string())?; apply_always_on_top(&window); super::topmost_guard::set_active(true); @@ -118,6 +219,8 @@ pub fn show( let _ = win.set_position(LogicalPosition::new(x.max(mon_x), y.max(mon_y))); } + ensure_visible_on_active_monitor(&win, style); + apply_no_activate(&win); apply_opacity(&win, opacity); apply_click_through(&win, click_through); @@ -181,6 +284,10 @@ pub trait WindowGeometry { fn outer_size(&self) -> tauri::Result>; fn scale_factor(&self) -> tauri::Result; fn is_minimized(&self) -> tauri::Result; + fn primary_monitor(&self) -> tauri::Result>; + fn available_monitors(&self) -> tauri::Result>; + fn unminimize(&self) -> tauri::Result<()>; + fn set_physical_position(&self, position: PhysicalPosition) -> tauri::Result<()>; } impl WindowGeometry for tauri::WebviewWindow { @@ -196,6 +303,18 @@ impl WindowGeometry for tauri::WebviewWindow { fn is_minimized(&self) -> tauri::Result { tauri::WebviewWindow::is_minimized(self) } + fn primary_monitor(&self) -> tauri::Result> { + tauri::WebviewWindow::primary_monitor(self) + } + fn available_monitors(&self) -> tauri::Result> { + tauri::WebviewWindow::available_monitors(self) + } + fn unminimize(&self) -> tauri::Result<()> { + tauri::WebviewWindow::unminimize(self) + } + fn set_physical_position(&self, position: PhysicalPosition) -> tauri::Result<()> { + tauri::WebviewWindow::set_position(self, position) + } } impl WindowGeometry for tauri::Window { @@ -211,6 +330,18 @@ impl WindowGeometry for tauri::Window { fn is_minimized(&self) -> tauri::Result { tauri::Window::is_minimized(self) } + fn primary_monitor(&self) -> tauri::Result> { + tauri::Window::primary_monitor(self) + } + fn available_monitors(&self) -> tauri::Result> { + tauri::Window::available_monitors(self) + } + fn unminimize(&self) -> tauri::Result<()> { + tauri::Window::unminimize(self) + } + fn set_physical_position(&self, position: PhysicalPosition) -> tauri::Result<()> { + tauri::Window::set_position(self, position) + } } /// Resize the floatbar to the given logical dimensions and re-assert the @@ -456,4 +587,57 @@ mod tests { fn physical_multi_monitor_origin_is_remembered() { assert!(should_remember_physical_position(false, -8_000, -8_000)); } + + #[test] + fn window_must_intersect_an_active_monitor_to_be_visible() { + let window_size = PhysicalSize::new(211, 40); + let monitor_size = PhysicalSize::new(1_920, 1_032); + + assert!(physical_rects_intersect( + PhysicalPosition::new(780, 8), + window_size, + PhysicalPosition::new(0, 0), + monitor_size, + )); + assert!(!physical_rects_intersect( + PhysicalPosition::new(-32_000, -32_000), + window_size, + PhysicalPosition::new(0, 0), + monitor_size, + )); + assert!(physical_rects_intersect( + PhysicalPosition::new(-3_840, 8), + window_size, + PhysicalPosition::new(-3_840, 0), + monitor_size, + )); + } + + #[test] + fn disconnected_monitor_position_falls_back_to_primary_work_area() { + let work_area_position = PhysicalPosition::new(0, 0); + let work_area_size = PhysicalSize::new(1_920, 1_032); + let window_size = PhysicalSize::new(211, 40); + + assert_eq!( + fallback_physical_position( + work_area_position, + work_area_size, + window_size, + 1.0, + "floating", + ), + PhysicalPosition::new(854, 8), + ); + assert_eq!( + fallback_physical_position( + work_area_position, + work_area_size, + window_size, + 1.0, + "taskbar", + ), + PhysicalPosition::new(854, 984), + ); + } } From c72560b51863188e92a1198a1e18ac055f89d67b Mon Sep 17 00:00:00 2001 From: NessZerra Date: Fri, 17 Jul 2026 10:45:25 +0700 Subject: [PATCH 4/5] Address FloatBar geometry review blockers Use full monitor bounds for on-screen checks so taskbar-style bars are not yanked; load style only when relocating; reject HiDPI-scaled park coords in stored geometry; persist recovered position atomically and reassert no-activate after recovery. --- .../src-tauri/src/floatbar/mod.rs | 2 +- .../src-tauri/src/floatbar/window.rs | 170 ++++++++++++++---- 2 files changed, 138 insertions(+), 34 deletions(-) diff --git a/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs b/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs index 1a45d19255..1e1ede717a 100644 --- a/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs +++ b/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs @@ -101,7 +101,7 @@ pub fn apply_state(app: &tauri::AppHandle, settings: &Settings) { } else if !settings.float_bar_enabled && open { let _ = window::hide(app); } else if let Some(w) = app.get_webview_window(FLOATBAR_LABEL) { - window::ensure_visible_on_active_monitor(&w, &settings.float_bar_style); + window::ensure_visible_on_active_monitor(&w, Some(&settings.float_bar_style)); window::apply_no_activate(&w); window::apply_opacity(&w, settings.float_bar_opacity); window::apply_click_through(&w, settings.float_bar_click_through); diff --git a/apps/desktop-tauri/src-tauri/src/floatbar/window.rs b/apps/desktop-tauri/src-tauri/src/floatbar/window.rs index d528dfcd8a..ce61f8d84e 100644 --- a/apps/desktop-tauri/src-tauri/src/floatbar/window.rs +++ b/apps/desktop-tauri/src-tauri/src/floatbar/window.rs @@ -14,6 +14,11 @@ const FLOATBAR_DEFAULT_HEIGHT_H: f64 = 36.0; const FLOATBAR_DEFAULT_WIDTH_V: f64 = 80.0; const FLOATBAR_DEFAULT_HEIGHT_V: f64 = 280.0; const WINDOWS_MINIMIZED_COORDINATE: i32 = -32_000; +/// Stored geometry is logical. Physical park (-32000,-32000) becomes about +/// -25600 @1.25x or -16000 @2x after scale divide. Both axes at/below this +/// threshold are treated as unusable while multi-monitor origins like +/// (-3840, 0) or (-8000, -8000) still restore. +const STORED_LOGICAL_PARK_THRESHOLD: i32 = -15_000; /// Windows parks minimized windows at the exact physical coordinate pair /// (-32000, -32000). Keep this strict so legitimate negative monitor origins @@ -22,6 +27,15 @@ fn is_windows_minimized_position(x: i32, y: i32) -> bool { x == WINDOWS_MINIMIZED_COORDINATE && y == WINDOWS_MINIMIZED_COORDINATE } +/// Reject stored (logical) positions that came from a Windows park coordinate +/// at any common DPI scale, not only exact logical (-32000, -32000). +fn is_unusable_stored_logical_position(x: i32, y: i32) -> bool { + if is_windows_minimized_position(x, y) { + return true; + } + x <= STORED_LOGICAL_PARK_THRESHOLD && y <= STORED_LOGICAL_PARK_THRESHOLD +} + fn should_remember_physical_position(is_minimized: bool, x: i32, y: i32) -> bool { !is_minimized && !is_windows_minimized_position(x, y) } @@ -47,6 +61,27 @@ fn physical_rects_intersect( && first_bottom > second_top } +/// Default first-open / recovery placement: center-X, taskbar bottom or +/// floating top, with 8 logical px edge padding. `mon_*` and size are logical. +fn default_logical_origin( + mon_x: f64, + mon_y: f64, + mon_w: f64, + mon_h: f64, + window_w: f64, + window_h: f64, + style: &str, +) -> (f64, f64) { + let x = mon_x + (mon_w - window_w) / 2.0; + let y = if style == "taskbar" { + mon_y + mon_h - window_h - 8.0 + } else { + mon_y + 8.0 + }; + (x.max(mon_x), y.max(mon_y)) +} + +/// Physical fallback placement on a monitor work area (safe recovery target). fn fallback_physical_position( work_area_position: PhysicalPosition, work_area_size: PhysicalSize, @@ -54,36 +89,46 @@ fn fallback_physical_position( scale_factor: f64, style: &str, ) -> PhysicalPosition { - let available_width = work_area_size.width.saturating_sub(window_size.width); - let available_height = work_area_size.height.saturating_sub(window_size.height); let scale_factor = if scale_factor.is_finite() && scale_factor > 0.0 { scale_factor } else { 1.0 }; - let edge_padding = (8.0 * scale_factor).round() as u32; - let x = work_area_position - .x - .saturating_add((available_width / 2).min(i32::MAX as u32) as i32); - let y_offset = if style == "taskbar" { - available_height.saturating_sub(edge_padding) - } else { - edge_padding.min(available_height) - }; - let y = work_area_position - .y - .saturating_add(y_offset.min(i32::MAX as u32) as i32); + let mon_x = work_area_position.x as f64 / scale_factor; + let mon_y = work_area_position.y as f64 / scale_factor; + let mon_w = work_area_size.width as f64 / scale_factor; + let mon_h = work_area_size.height as f64 / scale_factor; + let window_w = window_size.width as f64 / scale_factor; + let window_h = window_size.height as f64 / scale_factor; + let (x, y) = default_logical_origin(mon_x, mon_y, mon_w, mon_h, window_w, window_h, style); + PhysicalPosition::new((x * scale_factor).round() as i32, (y * scale_factor).round() as i32) +} - PhysicalPosition::new(x, y) +/// True when the window rectangle intersects any connected display's full +/// bounds (not just the work area). Taskbar-style bars may sit in the +/// reserved taskbar strip and must still count as on-screen. +fn intersects_any_monitor( + position: PhysicalPosition, + size: PhysicalSize, + monitors: &[tauri::Monitor], +) -> bool { + monitors.iter().any(|monitor| { + physical_rects_intersect(position, size, *monitor.position(), *monitor.size()) + }) } /// Move a FloatBar that no longer intersects an active monitor onto the /// primary monitor. This covers both stale geometry from a disconnected /// display and Windows parking the live window at (-32000, -32000) when a /// monitor is powered off. +/// +/// `style` is only needed when relocation runs. Pass `Some` when the caller +/// already has settings; pass `None` on hot event paths so settings are loaded +/// only if a move is required. Returns `true` when the window was relocated +/// (and good geometry was persisted). pub(super) fn ensure_visible_on_active_monitor>( window: &M, - style: &str, + style: Option<&str>, ) -> bool { let Ok(position) = window.outer_position() else { return false; @@ -94,10 +139,7 @@ pub(super) fn ensure_visible_on_active_monitor s, + None => { + style_owned = codexbar::settings::Settings::load().float_bar_style; + style_owned.as_str() + } + }; + let work_area = target_monitor.work_area(); let target = fallback_physical_position( work_area.position, @@ -123,7 +176,13 @@ pub(super) fn ensure_visible_on_active_monitor Date: Fri, 17 Jul 2026 10:48:24 +0700 Subject: [PATCH 5/5] Thermo-nuclear cleanup for FloatBar monitor recovery Split probe vs recover so settings stay out of the window module; load style only when recovery runs; refuse to persist off-monitor geometry; reassert no-activate after unminimize/relocate. --- .../src-tauri/src/floatbar/mod.rs | 16 ++-- .../src-tauri/src/floatbar/window.rs | 85 ++++++++++++------- 2 files changed, 65 insertions(+), 36 deletions(-) diff --git a/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs b/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs index 1e1ede717a..52fa8cc3f5 100644 --- a/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs +++ b/apps/desktop-tauri/src-tauri/src/floatbar/mod.rs @@ -46,13 +46,16 @@ pub fn handle_window_event(window: &tauri::Window, event: &tauri::WindowEvent) - } match event { tauri::WindowEvent::Moved(_) | tauri::WindowEvent::Resized(_) => { - // Visibility recovery loads style only if it actually relocates. + // Probe first (no I/O). Load style only when recovery runs. // Always reassert topmost on geometry change; shell-event path // in topmost_guard stays overlap-gated. - let relocated = window::ensure_visible_on_active_monitor(window, None); - if !relocated { + let relocated = if window::is_off_all_monitors(window) { + let style = Settings::load().float_bar_style; + window::recover_onto_primary(window, &style) + } else { window::remember_geometry(window); - } + false + }; if let Some(floatbar) = window.app_handle().get_webview_window(FLOATBAR_LABEL) { if relocated { window::apply_no_activate(&floatbar); @@ -101,10 +104,11 @@ pub fn apply_state(app: &tauri::AppHandle, settings: &Settings) { } else if !settings.float_bar_enabled && open { let _ = window::hide(app); } else if let Some(w) = app.get_webview_window(FLOATBAR_LABEL) { - window::ensure_visible_on_active_monitor(&w, Some(&settings.float_bar_style)); - window::apply_no_activate(&w); + let _ = window::ensure_visible_on_active_monitor(&w, &settings.float_bar_style); window::apply_opacity(&w, settings.float_bar_opacity); window::apply_click_through(&w, settings.float_bar_click_through); + // After possible unminimize/relocate, re-assert widget interaction flags. + window::apply_no_activate(&w); window::apply_always_on_top(&w); } } diff --git a/apps/desktop-tauri/src-tauri/src/floatbar/window.rs b/apps/desktop-tauri/src-tauri/src/floatbar/window.rs index ce61f8d84e..2453e0e442 100644 --- a/apps/desktop-tauri/src-tauri/src/floatbar/window.rs +++ b/apps/desktop-tauri/src-tauri/src/floatbar/window.rs @@ -117,19 +117,10 @@ fn intersects_any_monitor( }) } -/// Move a FloatBar that no longer intersects an active monitor onto the -/// primary monitor. This covers both stale geometry from a disconnected -/// display and Windows parking the live window at (-32000, -32000) when a -/// monitor is powered off. -/// -/// `style` is only needed when relocation runs. Pass `Some` when the caller -/// already has settings; pass `None` on hot event paths so settings are loaded -/// only if a move is required. Returns `true` when the window was relocated -/// (and good geometry was persisted). -pub(super) fn ensure_visible_on_active_monitor>( - window: &M, - style: Option<&str>, -) -> bool { +/// Probe: live window sits on no connected display (parked, disconnected +/// monitor, etc.). Returns `false` when geometry cannot be read so callers +/// do not treat "unknown" as recovery-needed. +pub(super) fn is_off_all_monitors>(window: &M) -> bool { let Ok(position) = window.outer_position() else { return false; }; @@ -139,10 +130,28 @@ pub(super) fn ensure_visible_on_active_monitor>( + window: &M, + style: &str, +) -> bool { + let Ok(position) = window.outer_position() else { + return false; + }; + let Ok(size) = window.outer_size() else { + return false; + }; + let Ok(monitors) = window.available_monitors() else { + return false; + }; let target_monitor = window .primary_monitor() .ok() @@ -152,16 +161,9 @@ pub(super) fn ensure_visible_on_active_monitor s, - None => { - style_owned = codexbar::settings::Settings::load().float_bar_style; - style_owned.as_str() - } - }; - + // Placement uses the work area so recovery lands in a usable desktop + // region; visibility probes use full monitor bounds (see + // `intersects_any_monitor`). let work_area = target_monitor.work_area(); let target = fallback_physical_position( work_area.position, @@ -179,12 +181,27 @@ pub(super) fn ensure_visible_on_active_monitor>( + window: &M, + style: &str, +) -> bool { + if !is_off_all_monitors(window) { + return false; + } + recover_onto_primary(window, style) +} + /// Initial dimensions (logical pixels) for the floating bar given an /// orientation string. Unknown values fall back to horizontal so callers /// don't have to pre-validate. @@ -216,11 +233,12 @@ pub fn show( click_through: bool, ) -> Result<(), String> { if let Some(window) = app.get_webview_window(FLOATBAR_LABEL) { - apply_no_activate(&window); apply_opacity(&window, opacity); apply_click_through(&window, click_through); + let _ = ensure_visible_on_active_monitor(&window, style); + // Re-assert after possible unminimize/relocate so focus stays off. + apply_no_activate(&window); apply_always_on_top(&window); - ensure_visible_on_active_monitor(&window, Some(style)); window.show().map_err(|e| e.to_string())?; apply_always_on_top(&window); super::topmost_guard::set_active(true); @@ -273,11 +291,11 @@ pub fn show( let _ = win.set_position(LogicalPosition::new(x, y)); } - ensure_visible_on_active_monitor(&win, Some(style)); + let _ = ensure_visible_on_active_monitor(&win, style); - apply_no_activate(&win); apply_opacity(&win, opacity); apply_click_through(&win, click_through); + apply_no_activate(&win); apply_always_on_top(&win); win.show().map_err(|e| e.to_string())?; apply_always_on_top(&win); @@ -316,6 +334,13 @@ pub fn remember_geometry>(window: &M) { let Ok(size) = window.outer_size() else { return; }; + // Never re-poison the store with a position that is off every display + // (failed recovery, transient shell state, etc.). + if let Ok(monitors) = window.available_monitors() { + if !monitors.is_empty() && !intersects_any_monitor(pos, size, &monitors) { + return; + } + } let scale = window.scale_factor().unwrap_or(1.0); geometry_store::save_entry( FLOATBAR_LABEL,