From 15ec4cf8e72e0f4263bfeea4b857da7212782724 Mon Sep 17 00:00:00 2001 From: Mingwei Zhu Date: Thu, 24 Apr 2025 23:40:35 -0400 Subject: [PATCH 1/3] fix: clamp tiling windows with their working rects --- packages/wm-common/src/rect.rs | 13 +++++++++++++ packages/wm/src/commands/general/platform_sync.rs | 12 +++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/wm-common/src/rect.rs b/packages/wm-common/src/rect.rs index 66308391..26628f18 100644 --- a/packages/wm-common/src/rect.rs +++ b/packages/wm-common/src/rect.rs @@ -109,6 +109,19 @@ impl Rect { ) } + /// Returns a new `Rect` that is clamped *strictly* within the bounds of the + /// given outer rectangle. Attempts to preserve the width and height of the + /// original rectangle, but it truncates the original one if it cannot be fit + /// into the outer rectangle. + #[must_use] + pub fn clamp_strictly(&self, outer_rect: &Rect) -> Self { + let left = self.left.max(outer_rect.left); + let top = self.top.max(outer_rect.top); + let width = self.width().min(outer_rect.right - left); + let height = self.height().min(outer_rect.bottom - top); + Self::from_xy(left, top, width, height) + } + #[must_use] pub fn clamp_size(&self, width: i32, height: i32) -> Self { Self::from_xy( diff --git a/packages/wm/src/commands/general/platform_sync.rs b/packages/wm/src/commands/general/platform_sync.rs index 931a4136..c0066cf1 100644 --- a/packages/wm/src/commands/general/platform_sync.rs +++ b/packages/wm/src/commands/general/platform_sync.rs @@ -257,9 +257,15 @@ fn redraw_containers( }, ); - let rect = window - .to_rect()? - .apply_delta(&window.total_border_delta()?, None); + let rect = { + let native_monitor = + window.monitor().context("No monitor associated.")?.native(); + let window_rect = window + .to_rect()? + .apply_delta(&window.total_border_delta()?, None); + window_rect + .clamp_strictly(native_monitor.working_rect()?) + }; let is_visible = matches!( window.display_state(), From 544eecc791e2d194ea8a38d16d01258f7c1ab9a2 Mon Sep 17 00:00:00 2001 From: lars-berger Date: Fri, 6 Jun 2025 15:41:06 +0800 Subject: [PATCH 2/3] fix: only clamp tiling windows --- packages/wm-common/src/rect.rs | 24 ++++--------------- .../wm/src/commands/general/platform_sync.rs | 17 +++++++++---- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/packages/wm-common/src/rect.rs b/packages/wm-common/src/rect.rs index 26628f18..efdb8577 100644 --- a/packages/wm-common/src/rect.rs +++ b/packages/wm-common/src/rect.rs @@ -101,25 +101,11 @@ impl Rect { /// original 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()), - ) - } - - /// Returns a new `Rect` that is clamped *strictly* within the bounds of the - /// given outer rectangle. Attempts to preserve the width and height of the - /// original rectangle, but it truncates the original one if it cannot be fit - /// into the outer rectangle. - #[must_use] - pub fn clamp_strictly(&self, outer_rect: &Rect) -> Self { - let left = self.left.max(outer_rect.left); - let top = self.top.max(outer_rect.top); - let width = self.width().min(outer_rect.right - left); - let height = self.height().min(outer_rect.bottom - top); - Self::from_xy(left, top, width, height) + let x = self.left.max(outer_rect.left); + let y = self.top.max(outer_rect.top); + let width = self.width().min(outer_rect.right - x); + let height = self.height().min(outer_rect.bottom - y); + Self::from_xy(x, y, width, height) } #[must_use] diff --git a/packages/wm/src/commands/general/platform_sync.rs b/packages/wm/src/commands/general/platform_sync.rs index c0066cf1..1ee935f7 100644 --- a/packages/wm/src/commands/general/platform_sync.rs +++ b/packages/wm/src/commands/general/platform_sync.rs @@ -204,6 +204,8 @@ fn redraw_containers( let workspace = window.workspace().context("Window has no workspace.")?; + let monitor = window.monitor().context("Window has no monitor.")?; + // Whether the window should be shown above all other windows. let z_order = match window.state() { WindowState::Floating(config) if config.shown_on_top => { @@ -258,13 +260,18 @@ fn redraw_containers( ); let rect = { - let native_monitor = - window.monitor().context("No monitor associated.")?.native(); - let window_rect = window + let adjusted_rect = window .to_rect()? .apply_delta(&window.total_border_delta()?, None); - window_rect - .clamp_strictly(native_monitor.working_rect()?) + + // Clamp tiling windows within the bounds of the monitor to handle + // excessive shadow borders. + match window.state() { + WindowState::Tiling => { + adjusted_rect.clamp(monitor.native().working_rect()?) + } + _ => adjusted_rect, + } }; let is_visible = matches!( From 70c193eac8d67ea9749df4d2e8193443117c05e7 Mon Sep 17 00:00:00 2001 From: Mingwei Zhu Date: Sun, 28 Sep 2025 01:13:12 -0400 Subject: [PATCH 3/3] feat: `adjust-borders` by class name --- packages/wm-common/src/app_command.rs | 3 ++ packages/wm/src/wm.rs | 57 +++++++++++++++++---------- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/packages/wm-common/src/app_command.rs b/packages/wm-common/src/app_command.rs index fd89077b..36ee963e 100644 --- a/packages/wm-common/src/app_command.rs +++ b/packages/wm-common/src/app_command.rs @@ -298,6 +298,9 @@ pub struct InvokeAdjustBordersCommand { #[clap(long, allow_hyphen_values = true)] pub left: Option, + + #[clap(long, allow_hyphen_values = true)] + pub class_name: Option, } #[derive(Args, Clone, Debug, PartialEq, Serialize)] diff --git a/packages/wm/src/wm.rs b/packages/wm/src/wm.rs index fd4ada61..9b58c3e6 100644 --- a/packages/wm/src/wm.rs +++ b/packages/wm/src/wm.rs @@ -20,9 +20,9 @@ use crate::{ }, monitor::focus_monitor, window::{ - ignore_window, move_window_in_direction, move_window_to_workspace, - resize_window, set_window_position, set_window_size, - update_window_state, WindowPositionTarget, + ignore_window, move_window_in_direction, + move_window_to_workspace, resize_window, set_window_position, + set_window_size, update_window_state, WindowPositionTarget, }, workspace::{focus_workspace, move_workspace_in_direction}, }, @@ -34,7 +34,7 @@ use crate::{ handle_window_moved_or_resized_start, handle_window_shown, handle_window_title_changed, }, - models::{Container, WorkspaceTarget}, + models::{Container, WindowContainer, WorkspaceTarget}, traits::{CommonGetters, WindowGetters}, user_config::UserConfig, wm_state::WmState, @@ -203,23 +203,40 @@ impl WindowManager { match &command { InvokeCommand::AdjustBorders(args) => { - match subject_container.as_window_container() { - Ok(window) => { - let args = args.clone(); - let border_delta = RectDelta::new( - args.left.unwrap_or(LengthValue::from_px(0)), - args.top.unwrap_or(LengthValue::from_px(0)), - args.right.unwrap_or(LengthValue::from_px(0)), - args.bottom.unwrap_or(LengthValue::from_px(0)), - ); - - window.set_border_delta(border_delta); - state.pending_sync.queue_container_to_redraw(window); - - Ok(()) - } - _ => Ok(()), + let windows: Vec = + if let Some(class_name) = &args.class_name { + state + .windows() + .into_iter() + .filter(|w| { + w.native() + .class_name() + .ok() + .map(|c| c.starts_with(class_name)) + == Some(true) + }) + .collect::>() + } else { + subject_container + .as_window_container() + .into_iter() + .collect::>() + }; + + for window in windows { + let window: WindowContainer = window; + let args = args.clone(); + let border_delta = RectDelta::new( + args.left.unwrap_or(LengthValue::from_px(0)), + args.top.unwrap_or(LengthValue::from_px(0)), + args.right.unwrap_or(LengthValue::from_px(0)), + args.bottom.unwrap_or(LengthValue::from_px(0)), + ); + + window.set_border_delta(border_delta); + state.pending_sync.queue_container_to_redraw(window); } + Ok(()) } InvokeCommand::Close => { match subject_container.as_window_container() {