From 7db5edbf9b12a409a4e4a99de54613f12d912977 Mon Sep 17 00:00:00 2001 From: Ayush Rawat Date: Tue, 24 Jun 2025 19:12:31 -0400 Subject: [PATCH 1/3] fix: window size across multiple monitors with different scaling --- packages/wm-common/src/rect.rs | 19 +++++++++++++++++++ .../wm/src/commands/general/platform_sync.rs | 10 +++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/wm-common/src/rect.rs b/packages/wm-common/src/rect.rs index 66308391..48a40d24 100644 --- a/packages/wm-common/src/rect.rs +++ b/packages/wm-common/src/rect.rs @@ -119,6 +119,25 @@ impl Rect { ) } + /// Contrains this rectangle to fit entirely within the given outer + /// rectangle. Unlike `clamp`, this method adjusts both the position and + /// size to ensure the rectangle doesn't extend beyond the boundaries. + #[must_use] + pub fn constrain_within(&self, outer_rect: &Rect) -> Self { + let clamped_x = self.x().max(outer_rect.x()); + let clamped_y = self.y().max(outer_rect.y()); + + let max_width = outer_rect.right - clamped_x; + let max_height = outer_rect.bottom - clamped_y; + + Self::from_xy( + clamped_x, + clamped_y, + self.width().min(max_width), + self.height().min(max_height), + ) + } + #[must_use] pub fn center_point(&self) -> Point { Point { diff --git a/packages/wm/src/commands/general/platform_sync.rs b/packages/wm/src/commands/general/platform_sync.rs index 5e1d6818..84578bb4 100644 --- a/packages/wm/src/commands/general/platform_sync.rs +++ b/packages/wm/src/commands/general/platform_sync.rs @@ -257,10 +257,18 @@ fn redraw_containers( }, ); - let rect = window + let mut rect = window .to_rect()? .apply_delta(&window.total_border_delta()?, None); + // Constrain tiling windows to their workspace's bounds to prevent + // overflow on multi-monitor setup with different scaling factors. + if window.is_tiling_window() { + if let Some(workspace) = window.workspace() { + rect = rect.constrain_within(&workspace.to_rect()?); + } + } + let is_visible = matches!( window.display_state(), DisplayState::Showing | DisplayState::Shown From cfd24da278457fd99d5eef14a3f34abbcbe3300c Mon Sep 17 00:00:00 2001 From: Ayush Rawat Date: Wed, 25 Jun 2025 06:08:19 -0400 Subject: [PATCH 2/3] fix: window size on creation/move to monitor with different scaling --- packages/wm/src/commands/general/platform_sync.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/wm/src/commands/general/platform_sync.rs b/packages/wm/src/commands/general/platform_sync.rs index 84578bb4..a57c13dd 100644 --- a/packages/wm/src/commands/general/platform_sync.rs +++ b/packages/wm/src/commands/general/platform_sync.rs @@ -257,9 +257,13 @@ fn redraw_containers( }, ); + let scale_factor = window + .monitor() + .and_then(|monitor| monitor.native().scale_factor().ok()); + let mut rect = window .to_rect()? - .apply_delta(&window.total_border_delta()?, None); + .apply_delta(&window.total_border_delta()?, scale_factor); // Constrain tiling windows to their workspace's bounds to prevent // overflow on multi-monitor setup with different scaling factors. From fcf0d8773b7bdc7b928049ac6944f0de86a623af Mon Sep 17 00:00:00 2001 From: Ayush Rawat Date: Sun, 17 Aug 2025 10:52:45 -0400 Subject: [PATCH 3/3] fix: pass scale factor to calculate border delta --- packages/wm-common/src/rect.rs | 37 ++++++------------- .../wm/src/commands/general/platform_sync.rs | 11 +++--- packages/wm/src/traits/window_getters.rs | 21 ++++++----- 3 files changed, 29 insertions(+), 40 deletions(-) diff --git a/packages/wm-common/src/rect.rs b/packages/wm-common/src/rect.rs index 48a40d24..1c3e635b 100644 --- a/packages/wm-common/src/rect.rs +++ b/packages/wm-common/src/rect.rs @@ -97,33 +97,10 @@ impl Rect { } /// Returns a new `Rect` that is clamped within the bounds of the given - /// outer rectangle. Attempts to preserve the width and height of the - /// original rectangle. + /// outer rectangle. Adjusts the position and size of the + /// rectangle to ensure it fits entirely within the outer rectangle. #[must_use] pub fn clamp(&self, outer_rect: &Rect) -> Self { - Self::from_xy( - self.left.max(outer_rect.left), - self.top.max(outer_rect.top), - self.width().min(outer_rect.width()), - self.height().min(outer_rect.height()), - ) - } - - #[must_use] - pub fn clamp_size(&self, width: i32, height: i32) -> Self { - Self::from_xy( - self.x(), - self.y(), - self.width().min(width), - self.height().min(height), - ) - } - - /// Contrains this rectangle to fit entirely within the given outer - /// rectangle. Unlike `clamp`, this method adjusts both the position and - /// size to ensure the rectangle doesn't extend beyond the boundaries. - #[must_use] - pub fn constrain_within(&self, outer_rect: &Rect) -> Self { let clamped_x = self.x().max(outer_rect.x()); let clamped_y = self.y().max(outer_rect.y()); @@ -138,6 +115,16 @@ impl Rect { ) } + #[must_use] + pub fn clamp_size(&self, width: i32, height: i32) -> Self { + Self::from_xy( + self.x(), + self.y(), + self.width().min(width), + self.height().min(height), + ) + } + #[must_use] pub fn center_point(&self) -> Point { Point { diff --git a/packages/wm/src/commands/general/platform_sync.rs b/packages/wm/src/commands/general/platform_sync.rs index a57c13dd..1f394779 100644 --- a/packages/wm/src/commands/general/platform_sync.rs +++ b/packages/wm/src/commands/general/platform_sync.rs @@ -261,16 +261,15 @@ fn redraw_containers( .monitor() .and_then(|monitor| monitor.native().scale_factor().ok()); - let mut rect = window - .to_rect()? - .apply_delta(&window.total_border_delta()?, scale_factor); + let mut rect = window.to_rect()?.apply_delta( + &window.total_border_delta(scale_factor)?, + scale_factor, + ); // Constrain tiling windows to their workspace's bounds to prevent // overflow on multi-monitor setup with different scaling factors. if window.is_tiling_window() { - if let Some(workspace) = window.workspace() { - rect = rect.constrain_within(&workspace.to_rect()?); - } + rect = rect.clamp(&workspace.to_rect()?); } let is_visible = matches!( diff --git a/packages/wm/src/traits/window_getters.rs b/packages/wm/src/traits/window_getters.rs index 80fa7e0c..eb7afad7 100644 --- a/packages/wm/src/traits/window_getters.rs +++ b/packages/wm/src/traits/window_getters.rs @@ -61,27 +61,30 @@ pub trait WindowGetters { fn set_border_delta(&self, border_delta: RectDelta); - fn total_border_delta(&self) -> anyhow::Result { + fn total_border_delta( + &self, + scale_factor: Option, + ) -> anyhow::Result { let border_delta = self.border_delta(); let shadow_border_delta = self.native().shadow_border_delta()?; // TODO: Allow percentage length values. Ok(RectDelta { left: LengthValue::from_px( - border_delta.left.to_px(0, None) - + shadow_border_delta.left.to_px(0, None), + border_delta.left.to_px(0, scale_factor) + + shadow_border_delta.left.to_px(0, scale_factor), ), right: LengthValue::from_px( - border_delta.right.to_px(0, None) - + shadow_border_delta.right.to_px(0, None), + border_delta.right.to_px(0, scale_factor) + + shadow_border_delta.right.to_px(0, scale_factor), ), top: LengthValue::from_px( - border_delta.top.to_px(0, None) - + shadow_border_delta.top.to_px(0, None), + border_delta.top.to_px(0, scale_factor) + + shadow_border_delta.top.to_px(0, scale_factor), ), bottom: LengthValue::from_px( - border_delta.bottom.to_px(0, None) - + shadow_border_delta.bottom.to_px(0, None), + border_delta.bottom.to_px(0, scale_factor) + + shadow_border_delta.bottom.to_px(0, scale_factor), ), }) }