From 62df4a9904a4a4a137536ab8f69f4d37fc3091dd Mon Sep 17 00:00:00 2001 From: lars-berger Date: Fri, 4 Oct 2024 09:06:00 +0100 Subject: [PATCH] feat: account for window size in anchor position (#122) --- packages/desktop/src/monitor_state.rs | 4 +- packages/desktop/src/widget_factory.rs | 110 +++++++++++++------------ 2 files changed, 59 insertions(+), 55 deletions(-) diff --git a/packages/desktop/src/monitor_state.rs b/packages/desktop/src/monitor_state.rs index fce54c2e..936df6ae 100644 --- a/packages/desktop/src/monitor_state.rs +++ b/packages/desktop/src/monitor_state.rs @@ -28,7 +28,7 @@ pub struct Monitor { pub y: i32, pub width: u32, pub height: u32, - pub scale_factor: f64, + pub scale_factor: f32, } impl MonitorState { @@ -107,7 +107,7 @@ impl MonitorState { y: monitor.position().y, width: monitor.size().width, height: monitor.size().height, - scale_factor: monitor.scale_factor(), + scale_factor: monitor.scale_factor() as f32, }) .collect() }) diff --git a/packages/desktop/src/widget_factory.rs b/packages/desktop/src/widget_factory.rs index 1380ffa1..0a23ce93 100644 --- a/packages/desktop/src/widget_factory.rs +++ b/packages/desktop/src/widget_factory.rs @@ -139,8 +139,6 @@ impl WidgetFactory { webview_url, ) .title("Zebar") - .inner_size(size.width, size.height) - .position(position.x, position.y) .focused(config.focused) .skip_taskbar(!config.shown_in_taskbar) .visible_on_all_workspaces(true) @@ -150,6 +148,18 @@ impl WidgetFactory { .resizable(config.resizable) .build()?; + info!("Positioning widget to {:?} {:?}", size, position); + let _ = window.set_size(size); + let _ = window.set_position(position); + + // On Windows, we need to set the position twice to account for + // different monitor scale factors. + #[cfg(target_os = "windows")] + { + let _ = window.set_size(size); + let _ = window.set_position(position); + } + let state = WidgetState { id: widget_id.clone(), config: config.clone(), @@ -170,18 +180,6 @@ impl WidgetFactory { .window() .set_tool_window(!config.shown_in_taskbar); - // On Windows, there's an issue where the window size is constrained - // when initially created. To work around this, apply the size and - // position settings again after launch. - #[cfg(target_os = "windows")] - { - let _ = window.set_size(size); - let _ = window.set_position(position); - let _ = window.set_size(size); - // Is it also required to set the position twice or only the size? - let _ = window.set_position(position); - } - let mut widget_states = self.widget_states.lock().await; widget_states.insert(state.id.clone(), state.clone()); @@ -236,7 +234,7 @@ impl WidgetFactory { async fn widget_placements( &self, config: &WidgetConfig, - ) -> Vec<(PhysicalSize, PhysicalPosition)> { + ) -> Vec<(PhysicalSize, PhysicalPosition)> { let mut placements = vec![]; for placement in config.default_placements.iter() { @@ -246,63 +244,69 @@ impl WidgetFactory { .await; for monitor in monitors { + let monitor_width = monitor.width as i32; + let monitor_height = monitor.height as i32; + + // Pixel values should be scaled by the monitor's scale factor, + // whereas percentage values are left as-is. This is + // because the percentage values are already relative to + // the monitor's size. + let window_width = placement + .width + .to_px_scaled(monitor_width, monitor.scale_factor); + + let window_height = placement + .height + .to_px_scaled(monitor_height, monitor.scale_factor); + + let window_size = PhysicalSize::new(window_width, window_height); + let (anchor_x, anchor_y) = match placement.anchor { AnchorPoint::TopLeft => (monitor.x, monitor.y), - AnchorPoint::TopCenter => { - (monitor.x + (monitor.width as i32 / 2), monitor.y) - } + AnchorPoint::TopCenter => ( + monitor.x + (monitor_width / 2) - (window_size.width / 2), + monitor.y, + ), AnchorPoint::TopRight => { - (monitor.x + monitor.width as i32, monitor.y) - } - AnchorPoint::CenterLeft => { - (monitor.x, monitor.y + (monitor.height as i32 / 2)) + (monitor.x + monitor_width - window_size.width, monitor.y) } + AnchorPoint::CenterLeft => ( + monitor.x, + monitor.y + (monitor_height / 2) - (window_size.height / 2), + ), AnchorPoint::Center => ( - monitor.x + (monitor.width as i32 / 2), - monitor.y + (monitor.height as i32 / 2), + monitor.x + (monitor_width / 2) - (window_size.width / 2), + monitor.y + (monitor_height / 2) - (window_size.height / 2), ), AnchorPoint::CenterRight => ( - monitor.x + monitor.width as i32, - monitor.y + (monitor.height as i32 / 2), + monitor.x + monitor_width - window_size.width, + monitor.y + (monitor_height / 2) - (window_size.height / 2), ), AnchorPoint::BottomLeft => { - (monitor.x, monitor.y + monitor.height as i32) + (monitor.x, monitor.y + monitor_height - window_size.height) } AnchorPoint::BottomCenter => ( - monitor.x + (monitor.width as i32 / 2), - monitor.y + monitor.height as i32, + monitor.x + (monitor_width / 2) - (window_size.width / 2), + monitor.y + monitor_height - window_size.height, ), AnchorPoint::BottomRight => ( - monitor.x + monitor.width as i32, - monitor.y + monitor.height as i32, + monitor.x + monitor_width - window_size.width, + monitor.y + monitor_height - window_size.height, ), }; - let width = placement - .width - .to_px_scaled(monitor.width as i32, monitor.scale_factor as f32); - let height = placement.height.to_px_scaled( - monitor.height as i32, - monitor.scale_factor as f32, - ); - let size = PhysicalSize::::new( - i32::min(width, monitor.width as i32) as f64, - i32::min(height, monitor.height as i32) as f64, - ); - let offset_x = placement .offset_x - .to_px_scaled(monitor.width as i32, monitor.scale_factor as f32); - let offset_y = placement.offset_y.to_px_scaled( - monitor.height as i32, - monitor.scale_factor as f32, - ); - let position = PhysicalPosition::::new( - (anchor_x + offset_x) as f64, - (anchor_y + offset_y) as f64, - ); + .to_px_scaled(monitor_width, monitor.scale_factor); + + let offset_y = placement + .offset_y + .to_px_scaled(monitor_height, monitor.scale_factor); + + let window_position = + PhysicalPosition::new(anchor_x + offset_x, anchor_y + offset_y); - placements.push((size, position)); + placements.push((window_size, window_position)); } }