From 65bc1a966e7ff9abdd43a073da36c13aef14e1f6 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Tue, 12 Oct 2021 08:38:35 -0700 Subject: [PATCH] feat(wm): add cmd to specify work area offsets This commit adds a new komorebic command to specify offsets for work areas to be applied across all monitors. The areas covered by these offsets will be excluded from the tiling area, and can be used for custom task bars, Rainmeter desktop widgets etc. When setting an offset at the top, the same offset will need to be applied to the bottom to ensure that the tiling area is not pushed off of the screen, but this is not necessary when applying an offset to the bottom as the top of the work area will never go lower than 0. resolve #46 --- Cargo.lock | 4 ++-- README.md | 2 ++ komorebi-core/src/lib.rs | 1 + komorebi/src/monitor.rs | 8 ++++++-- komorebi/src/process_command.rs | 4 ++++ komorebi/src/process_event.rs | 3 ++- komorebi/src/window_manager.rs | 20 +++++++++++++++----- komorebi/src/workspace.rs | 21 +++++++++++++++++++-- komorebic.lib.sample.ahk | 4 ++++ komorebic/src/main.rs | 26 ++++++++++++++++++++++++++ 10 files changed, 81 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19637e89..c3717904 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1172,9 +1172,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.20.4" +version = "0.20.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffff4a02fa61eee51f95210fc9c98ea6eeb46bb071adeafd61e1a0b9b22c6a6d" +checksum = "e223c65cd36b485a34c2ce6e38efa40777d31c4166d9076030c74cdcf971679f" dependencies = [ "cfg-if 1.0.0", "core-foundation-sys", diff --git a/README.md b/README.md index f859d44e..c5836483 100644 --- a/README.md +++ b/README.md @@ -242,6 +242,7 @@ cycle-monitor Focus the monitor in the given cycle direction cycle-workspace Focus the workspace in the given cycle direction new-workspace Create and append a new workspace on the focused monitor invisible-borders Set the invisible border dimensions around each window +work-area-offset Set offsets to exclude parts of the work area from tiling adjust-container-padding Adjust container padding on the focused workspace adjust-workspace-padding Adjust workspace padding on the focused workspace change-layout Set the layout on the focused workspace @@ -313,6 +314,7 @@ used [is available here](komorebi.sample.with.lib.ahk). - [x] Additional manage rules based on exe name and window class - [x] Identify applications which overflow their borders by exe name and class - [x] Identify 'close/minimize to tray' applications by exe name and class +- [x] Configure work area offsets to preserve space for custom taskbars - [x] Configure and compensate for the size of Windows 10's invisible borders - [x] Toggle floating windows - [x] Toggle monocle window diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index e1b29666..8755acce 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -72,6 +72,7 @@ pub enum SocketMessage { ReloadConfiguration, WatchConfiguration(bool), InvisibleBorders(Rect), + WorkAreaOffset(Rect), WorkspaceRule(ApplicationIdentifier, String, usize, usize), FloatRule(ApplicationIdentifier, String), ManageRule(ApplicationIdentifier, String), diff --git a/komorebi/src/monitor.rs b/komorebi/src/monitor.rs index c6bd33e8..f459f24a 100644 --- a/komorebi/src/monitor.rs +++ b/komorebi/src/monitor.rs @@ -146,12 +146,16 @@ impl Monitor { self.workspaces().len() } - pub fn update_focused_workspace(&mut self, invisible_borders: &Rect) -> Result<()> { + pub fn update_focused_workspace( + &mut self, + offset: Option, + invisible_borders: &Rect, + ) -> Result<()> { let work_area = *self.work_area_size(); self.focused_workspace_mut() .ok_or_else(|| anyhow!("there is no workspace"))? - .update(&work_area, invisible_borders)?; + .update(&work_area, offset, invisible_borders)?; Ok(()) } diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 0dedc6dd..6a86706e 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -371,6 +371,10 @@ impl WindowManager { self.invisible_borders = rect; self.retile_all()?; } + SocketMessage::WorkAreaOffset(rect) => { + self.work_area_offset = Option::from(rect); + self.retile_all()?; + } SocketMessage::QuickSave => { let workspace = self.focused_workspace()?; let resize = workspace.resize_dimensions(); diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index e9f94aab..4d6c9ad2 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -66,13 +66,14 @@ impl WindowManager { } let invisible_borders = self.invisible_borders; + let offset = self.work_area_offset; for (i, monitor) in self.monitors_mut().iter_mut().enumerate() { let work_area = *monitor.work_area_size(); for (j, workspace) in monitor.workspaces_mut().iter_mut().enumerate() { let reaped_orphans = workspace.reap_orphans()?; if reaped_orphans.0 > 0 || reaped_orphans.1 > 0 { - workspace.update(&work_area, &invisible_borders)?; + workspace.update(&work_area, offset, &invisible_borders)?; tracing::info!( "reaped {} orphan window(s) and {} orphaned container(s) on monitor: {}, workspace: {}", reaped_orphans.0, diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 251057e5..7697ea6b 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -45,6 +45,7 @@ pub struct WindowManager { pub command_listener: UnixListener, pub is_paused: bool, pub invisible_borders: Rect, + pub work_area_offset: Option, pub focus_follows_mouse: Option, pub hotwatch: Hotwatch, pub virtual_desktop_id: Option, @@ -56,6 +57,7 @@ pub struct State { pub monitors: Ring, pub is_paused: bool, pub invisible_borders: Rect, + pub work_area_offset: Option, pub focus_follows_mouse: Option, pub has_pending_raise_op: bool, pub float_identifiers: Vec, @@ -72,6 +74,7 @@ impl From<&mut WindowManager> for State { monitors: wm.monitors.clone(), is_paused: wm.is_paused, invisible_borders: wm.invisible_borders, + work_area_offset: wm.work_area_offset, focus_follows_mouse: wm.focus_follows_mouse.clone(), has_pending_raise_op: wm.has_pending_raise_op, float_identifiers: FLOAT_IDENTIFIERS.lock().clone(), @@ -143,6 +146,7 @@ impl WindowManager { right: 14, bottom: 7, }, + work_area_offset: None, focus_follows_mouse: None, hotwatch: Hotwatch::new()?, virtual_desktop_id, @@ -265,6 +269,7 @@ impl WindowManager { self.monitors_mut().retain(|m| !invalid.contains(&m.id())); let invisible_borders = self.invisible_borders; + let offset = self.work_area_offset; for monitor in self.monitors_mut() { let mut should_update = false; @@ -293,7 +298,7 @@ impl WindowManager { } if should_update { - monitor.update_focused_workspace(&invisible_borders)?; + monitor.update_focused_workspace(offset, &invisible_borders)?; } } @@ -423,6 +428,8 @@ impl WindowManager { #[tracing::instrument(skip(self))] pub fn retile_all(&mut self) -> Result<()> { let invisible_borders = self.invisible_borders; + let offset = self.work_area_offset; + for monitor in self.monitors_mut() { let work_area = *monitor.work_area_size(); let workspace = monitor @@ -434,7 +441,7 @@ impl WindowManager { *resize = None; } - workspace.update(&work_area, &invisible_borders)?; + workspace.update(&work_area, offset, &invisible_borders)?; } Ok(()) @@ -534,10 +541,11 @@ impl WindowManager { tracing::info!("updating"); let invisible_borders = self.invisible_borders; + let offset = self.work_area_offset; self.focused_monitor_mut() .ok_or_else(|| anyhow!("there is no monitor"))? - .update_focused_workspace(&invisible_borders)?; + .update_focused_workspace(offset, &invisible_borders)?; if mouse_follows_focus { if let Some(window) = self.focused_workspace()?.maximized_window() { @@ -660,6 +668,7 @@ impl WindowManager { tracing::info!("moving container"); let invisible_borders = self.invisible_borders; + let offset = self.work_area_offset; let monitor = self .focused_monitor_mut() @@ -685,7 +694,7 @@ impl WindowManager { target_monitor.add_container(container)?; target_monitor.load_focused_workspace()?; - target_monitor.update_focused_workspace(&invisible_borders)?; + target_monitor.update_focused_workspace(offset, &invisible_borders)?; if follow { self.focus_monitor(idx)?; @@ -1075,6 +1084,7 @@ impl WindowManager { tracing::info!("setting workspace layout"); let invisible_borders = self.invisible_borders; + let offset = self.work_area_offset; let focused_monitor_idx = self.focused_monitor_idx(); let monitor = self @@ -1094,7 +1104,7 @@ impl WindowManager { // If this is the focused workspace on a non-focused screen, let's update it if focused_monitor_idx != monitor_idx && focused_workspace_idx == workspace_idx { - workspace.update(&work_area, &invisible_borders)?; + workspace.update(&work_area, offset, &invisible_borders)?; Ok(()) } else { Ok(self.update_focused_workspace(false)?) diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 83c005c2..fa6840ed 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -138,8 +138,25 @@ impl Workspace { Ok(()) } - pub fn update(&mut self, work_area: &Rect, invisible_borders: &Rect) -> Result<()> { - let mut adjusted_work_area = *work_area; + pub fn update( + &mut self, + work_area: &Rect, + offset: Option, + invisible_borders: &Rect, + ) -> Result<()> { + let mut adjusted_work_area = offset.map_or_else( + || *work_area, + |offset| { + let mut with_offset = *work_area; + with_offset.left += offset.left; + with_offset.top += offset.top; + with_offset.right -= offset.right; + with_offset.bottom -= offset.bottom; + + with_offset + }, + ); + adjusted_work_area.add_padding(self.workspace_padding()); self.enforce_resize_constraints(); diff --git a/komorebic.lib.sample.ahk b/komorebic.lib.sample.ahk index 870903b2..75dbd8be 100644 --- a/komorebic.lib.sample.ahk +++ b/komorebic.lib.sample.ahk @@ -108,6 +108,10 @@ InvisibleBorders(left, top, right, bottom) { Run, komorebic.exe invisible-borders %left% %top% %right% %bottom%, , Hide } +WorkAreaOffset(left, top, right, bottom) { + Run, komorebic.exe work-area-offset %left% %top% %right% %bottom%, , Hide +} + AdjustContainerPadding(sizing, adjustment) { Run, komorebic.exe adjust-container-padding %sizing% %adjustment%, , Hide } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index bdf0bf65..31dd3f11 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -167,6 +167,18 @@ struct InvisibleBorders { bottom: i32, } +#[derive(Clap, AhkFunction)] +struct WorkAreaOffset { + /// Size of the left work area offset (set right to left * 2 to maintain right padding) + left: i32, + /// Size of the top work area offset (set bottom to the same value to maintain bottom padding) + top: i32, + /// Size of the right work area offset + right: i32, + /// Size of the bottom work area offset + bottom: i32, +} + #[derive(Clap, AhkFunction)] struct EnsureWorkspaces { /// Monitor index (zero-indexed) @@ -366,6 +378,9 @@ enum SubCommand { /// Set the invisible border dimensions around each window #[clap(setting = AppSettings::ArgRequiredElseHelp)] InvisibleBorders(InvisibleBorders), + /// Set offsets to exclude parts of the work area from tiling + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + WorkAreaOffset(WorkAreaOffset), /// Adjust container padding on the focused workspace #[clap(setting = AppSettings::ArgRequiredElseHelp)] AdjustContainerPadding(AdjustContainerPadding), @@ -538,6 +553,17 @@ fn main() -> Result<()> { .as_bytes()?, )?; } + SubCommand::WorkAreaOffset(arg) => { + send_message( + &*SocketMessage::WorkAreaOffset(Rect { + left: arg.left, + top: arg.top, + right: arg.right, + bottom: arg.bottom, + }) + .as_bytes()?, + )?; + } SubCommand::ContainerPadding(arg) => { send_message( &*SocketMessage::ContainerPadding(arg.monitor, arg.workspace, arg.size)