From 820432f9d46efec9884ae6616f3f64e00bb4834e Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 14 Aug 2021 10:17:54 -0700 Subject: [PATCH] feat(wm): add per-workspace tiling config + toggle Added two commands, 'komorebic toggle-tiling' and 'komorebic workspace-tiling MONITOR_IDX WORKSPACE_IDX on|off' which allow for tiling on the currently focused workspace to be toggled on and off, and for the tiling for a specific workspace to be set to on or off (useful if you want a specific workspace to always have tiling set to off at startup). resolve #5 --- komorebi-core/src/lib.rs | 2 ++ komorebi/src/process_command.rs | 6 ++++ komorebi/src/window_manager.rs | 29 ++++++++++++++++++ komorebi/src/workspace.rs | 53 +++++++++++++++++++-------------- komorebic/src/main.rs | 27 +++++++++++++++++ 5 files changed, 94 insertions(+), 23 deletions(-) diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index dfa5b271..fe642760 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -40,6 +40,7 @@ pub enum SocketMessage { // Monitor and Workspace Commands EnsureWorkspaces(usize, usize), NewWorkspace, + ToggleTiling, Stop, TogglePause, Retile, @@ -47,6 +48,7 @@ pub enum SocketMessage { FocusWorkspaceNumber(usize), ContainerPadding(usize, usize, i32), WorkspacePadding(usize, usize, i32), + WorkspaceTiling(usize, usize, bool), WorkspaceName(usize, usize, String), WorkspaceLayout(usize, usize, Layout), // Configuration diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 0d347f1a..6a13c4fc 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -102,6 +102,9 @@ impl WindowManager { tracing::info!("pausing"); self.is_paused = !self.is_paused; } + SocketMessage::ToggleTiling => { + self.toggle_tiling()?; + } SocketMessage::FocusMonitorNumber(monitor_idx) => { self.focus_monitor(monitor_idx)?; self.update_focused_workspace(true)?; @@ -123,6 +126,9 @@ impl WindowManager { } SocketMessage::FlipLayout(layout_flip) => self.flip_layout(layout_flip)?, SocketMessage::ChangeLayout(layout) => self.change_workspace_layout(layout)?, + SocketMessage::WorkspaceTiling(monitor_idx, workspace_idx, tile) => { + self.set_workspace_tiling(monitor_idx, workspace_idx, tile)?; + } SocketMessage::WorkspaceLayout(monitor_idx, workspace_idx, layout) => { self.set_workspace_layout(monitor_idx, workspace_idx, layout)?; } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index c93842eb..d1097b68 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -326,6 +326,13 @@ impl WindowManager { self.update_focused_workspace(true) } + #[tracing::instrument(skip(self))] + pub fn toggle_tiling(&mut self) -> Result<()> { + let workspace = self.focused_workspace_mut()?; + workspace.set_tile(!workspace.tile()); + self.update_focused_workspace(false) + } + #[tracing::instrument(skip(self))] pub fn toggle_float(&mut self) -> Result<()> { let hwnd = WindowsApi::top_visible_window()?; @@ -496,6 +503,28 @@ impl WindowManager { self.update_focused_workspace(false) } + #[tracing::instrument(skip(self))] + pub fn set_workspace_tiling( + &mut self, + monitor_idx: usize, + workspace_idx: usize, + tile: bool, + ) -> Result<()> { + let monitor = self + .monitors_mut() + .get_mut(monitor_idx) + .context("there is no monitor")?; + + let workspace = monitor + .workspaces_mut() + .get_mut(workspace_idx) + .context("there is no monitor")?; + + workspace.set_tile(tile); + + self.update_focused_workspace(false) + } + #[tracing::instrument(skip(self))] pub fn set_workspace_layout( &mut self, diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 569635e6..7d9f85d6 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -44,6 +44,8 @@ pub struct Workspace { #[serde(skip_serializing)] #[getset(get = "pub", get_mut = "pub")] resize_dimensions: Vec>, + #[getset(get = "pub", set = "pub")] + tile: bool, } impl_ring_elements!(Workspace, Container); @@ -62,6 +64,7 @@ impl Default for Workspace { container_padding: Option::from(10), latest_layout: vec![], resize_dimensions: vec![], + tile: true, } } } @@ -102,33 +105,37 @@ impl Workspace { self.enforce_resize_constraints(); - if let Some(container) = self.monocle_container_mut() { - if let Some(window) = container.focused_window_mut() { - window.set_position(&adjusted_work_area, true)?; - } - } else { - let layouts = self.layout().calculate( - &adjusted_work_area, - self.containers().len(), - self.container_padding(), - self.layout_flip(), - self.resize_dimensions(), - ); - - let windows = self.visible_windows_mut(); - for (i, window) in windows.into_iter().enumerate() { - if let (Some(window), Some(layout)) = (window, layouts.get(i)) { - window.set_position(layout, false)?; + if *self.tile() { + if let Some(container) = self.monocle_container_mut() { + if let Some(window) = container.focused_window_mut() { + window.set_position(&adjusted_work_area, true)?; } - } + } else { + let layouts = self.layout().calculate( + &adjusted_work_area, + self.containers().len(), + self.container_padding(), + self.layout_flip(), + self.resize_dimensions(), + ); - // Always make sure that the length of the resize dimensions vec is the same as the - // number of layouts / containers. This should never actually truncate as the remove_window - // function takes care of cleaning up resize dimensions when destroying empty containers - self.resize_dimensions_mut().resize(layouts.len(), None); - self.set_latest_layout(layouts); + let windows = self.visible_windows_mut(); + for (i, window) in windows.into_iter().enumerate() { + if let (Some(window), Some(layout)) = (window, layouts.get(i)) { + window.set_position(layout, false)?; + } + } + + self.set_latest_layout(layouts); + } } + // Always make sure that the length of the resize dimensions vec is the same as the + // number of layouts / containers. This should never actually truncate as the remove_window + // function takes care of cleaning up resize dimensions when destroying empty containers + let container_count = self.containers().len(); + self.resize_dimensions_mut().resize(container_count, None); + Ok(()) } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 34f3eebe..123fd5be 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -47,7 +47,9 @@ enum SubCommand { ContainerPadding(SizeForMonitorWorkspace), WorkspacePadding(SizeForMonitorWorkspace), WorkspaceLayout(LayoutForMonitorWorkspace), + WorkspaceTiling(TilingForMonitorWorkspace), WorkspaceName(NameForMonitorWorkspace), + ToggleTiling, ToggleFloat, TogglePause, ToggleMonocle, @@ -91,6 +93,22 @@ struct LayoutForMonitorWorkspace { layout: Layout, } +fn on_or_off(s: &str) -> Result { + match s { + "on" => Ok(true), + "off" => Ok(false), + _ => Err("expected `on` or `off`"), + } +} + +#[derive(Clap)] +struct TilingForMonitorWorkspace { + monitor: usize, + workspace: usize, + #[clap(parse(try_from_str = on_or_off))] + tile: bool, +} + #[derive(Clap)] struct Target { number: usize, @@ -187,6 +205,9 @@ fn main() -> Result<()> { .as_bytes()?, )?; } + SubCommand::ToggleTiling => { + send_message(&*SocketMessage::ToggleTiling.as_bytes()?)?; + } SubCommand::ToggleFloat => { send_message(&*SocketMessage::ToggleFloat.as_bytes()?)?; } @@ -199,6 +220,12 @@ fn main() -> Result<()> { .as_bytes()?, )?; } + SubCommand::WorkspaceTiling(layout) => { + send_message( + &*SocketMessage::WorkspaceTiling(layout.monitor, layout.workspace, layout.tile) + .as_bytes()?, + )?; + } SubCommand::Start => { let script = r#"Start-Process komorebi -WindowStyle hidden"#; match powershell_script::run(script, true) {