Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions apps/desktop-tauri/src-tauri/src/floatbar/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,14 @@ pub fn handle_window_event(window: &tauri::Window, event: &tauri::WindowEvent) -
return false;
}
match event {
tauri::WindowEvent::Moved(_)
| tauri::WindowEvent::Resized(_)
| tauri::WindowEvent::CloseRequested { .. } => {
tauri::WindowEvent::Moved(_) | tauri::WindowEvent::Resized(_) => {
let style = Settings::load().float_bar_style;
if window::ensure_visible_on_active_monitor(window, &style) {
return true;
}
window::remember_geometry(window);
}
tauri::WindowEvent::CloseRequested { .. } => window::remember_geometry(window),
_ => {}
}
true
Expand Down Expand Up @@ -84,6 +87,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);
Expand Down
237 changes: 235 additions & 2 deletions apps/desktop-tauri/src-tauri/src/floatbar/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -13,6 +13,118 @@ 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;

/// 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 {
x == WINDOWS_MINIMIZED_COORDINATE && y == WINDOWS_MINIMIZED_COORDINATE
}

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<i32>,
first_size: PhysicalSize<u32>,
second_position: PhysicalPosition<i32>,
second_size: PhysicalSize<u32>,
) -> 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<i32>,
work_area_size: PhysicalSize<u32>,
window_size: PhysicalSize<u32>,
scale_factor: f64,
style: &str,
) -> PhysicalPosition<i32> {
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<R: tauri::Runtime, M: WindowGeometry<R>>(
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
Expand Down Expand Up @@ -49,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);
return Ok(());
Expand Down Expand Up @@ -83,7 +196,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));
Expand All @@ -103,6 +218,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);
Expand Down Expand Up @@ -132,6 +249,10 @@ pub fn remember_geometry<R: tauri::Runtime, M: WindowGeometry<R>>(window: &M) {
let Ok(pos) = window.outer_position() else {
return;
};
let is_minimized = window.is_minimized().unwrap_or(false);
if !should_remember_physical_position(is_minimized, pos.x, pos.y) {
return;
}
let Ok(size) = window.outer_size() else {
return;
};
Expand All @@ -156,6 +277,11 @@ pub trait WindowGeometry<R: tauri::Runtime> {
fn outer_position(&self) -> tauri::Result<tauri::PhysicalPosition<i32>>;
fn outer_size(&self) -> tauri::Result<tauri::PhysicalSize<u32>>;
fn scale_factor(&self) -> tauri::Result<f64>;
fn is_minimized(&self) -> tauri::Result<bool>;
fn primary_monitor(&self) -> tauri::Result<Option<tauri::Monitor>>;
fn available_monitors(&self) -> tauri::Result<Vec<tauri::Monitor>>;
fn unminimize(&self) -> tauri::Result<()>;
fn set_physical_position(&self, position: PhysicalPosition<i32>) -> tauri::Result<()>;
}

impl<R: tauri::Runtime> WindowGeometry<R> for tauri::WebviewWindow<R> {
Expand All @@ -168,6 +294,21 @@ impl<R: tauri::Runtime> WindowGeometry<R> for tauri::WebviewWindow<R> {
fn scale_factor(&self) -> tauri::Result<f64> {
tauri::WebviewWindow::scale_factor(self)
}
fn is_minimized(&self) -> tauri::Result<bool> {
tauri::WebviewWindow::is_minimized(self)
}
fn primary_monitor(&self) -> tauri::Result<Option<tauri::Monitor>> {
tauri::WebviewWindow::primary_monitor(self)
}
fn available_monitors(&self) -> tauri::Result<Vec<tauri::Monitor>> {
tauri::WebviewWindow::available_monitors(self)
}
fn unminimize(&self) -> tauri::Result<()> {
tauri::WebviewWindow::unminimize(self)
}
fn set_physical_position(&self, position: PhysicalPosition<i32>) -> tauri::Result<()> {
tauri::WebviewWindow::set_position(self, position)
}
}

impl<R: tauri::Runtime> WindowGeometry<R> for tauri::Window<R> {
Expand All @@ -180,6 +321,21 @@ impl<R: tauri::Runtime> WindowGeometry<R> for tauri::Window<R> {
fn scale_factor(&self) -> tauri::Result<f64> {
tauri::Window::scale_factor(self)
}
fn is_minimized(&self) -> tauri::Result<bool> {
tauri::Window::is_minimized(self)
}
fn primary_monitor(&self) -> tauri::Result<Option<tauri::Monitor>> {
tauri::Window::primary_monitor(self)
}
fn available_monitors(&self) -> tauri::Result<Vec<tauri::Monitor>> {
tauri::Window::available_monitors(self)
}
fn unminimize(&self) -> tauri::Result<()> {
tauri::Window::unminimize(self)
}
fn set_physical_position(&self, position: PhysicalPosition<i32>) -> tauri::Result<()> {
tauri::Window::set_position(self, position)
}
}

/// Resize the floatbar to the given logical dimensions and re-assert the
Expand Down Expand Up @@ -396,4 +552,81 @@ mod tests {
(FLOATBAR_DEFAULT_WIDTH_H, FLOATBAR_DEFAULT_HEIGHT_H)
);
}

#[test]
fn windows_minimized_position_is_not_restored() {
assert!(is_windows_minimized_position(-32_000, -32_000));
}

#[test]
fn legitimate_negative_monitor_positions_are_preserved() {
assert!(!is_windows_minimized_position(-3_840, 0));
assert!(!is_windows_minimized_position(-8_000, -8_000));
assert!(!is_windows_minimized_position(-16_000, -16_000));
}

#[test]
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));
}

#[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),
);
}
}