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-common/src/rect.rs b/packages/wm-common/src/rect.rs index 66308391..efdb8577 100644 --- a/packages/wm-common/src/rect.rs +++ b/packages/wm-common/src/rect.rs @@ -101,12 +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()), - ) + 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 5e1d6818..99e7a6c5 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 => { @@ -257,9 +259,20 @@ fn redraw_containers( }, ); - let rect = window - .to_rect()? - .apply_delta(&window.total_border_delta()?, None); + let rect = { + let adjusted_rect = window + .to_rect()? + .apply_delta(&window.total_border_delta()?, None); + + // 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!( window.display_state(), 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() {