diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index 0cbd08ca..43e0d0a9 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -43,6 +43,8 @@ pub enum SocketMessage { CycleFocusWindow(CycleDirection), CycleMoveWindow(CycleDirection), StackWindow(OperationDirection), + StackAll, + UnstackAll, ResizeWindowEdge(OperationDirection, Sizing), ResizeWindowAxis(Axis, Sizing), UnstackWindow, diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index ad492cf6..dedbfed3 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -205,6 +205,8 @@ impl WindowManager { } SocketMessage::StackWindow(direction) => self.add_window_to_container(direction)?, SocketMessage::UnstackWindow => self.remove_window_from_container()?, + SocketMessage::StackAll => self.stack_all()?, + SocketMessage::UnstackAll => self.unstack_all()?, SocketMessage::CycleStack(direction) => { self.cycle_container_window_in_direction(direction)?; self.focused_window()?.focus(self.mouse_follows_focus)?; diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 6c8bc0d7..d61ea445 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1406,6 +1406,67 @@ impl WindowManager { self.update_focused_workspace(self.mouse_follows_focus, true) } + #[tracing::instrument(skip(self))] + pub fn stack_all(&mut self) -> Result<()> { + self.handle_unmanaged_window_behaviour()?; + tracing::info!("stacking all windows on workspace"); + + let workspace = self.focused_workspace_mut()?; + + let mut focused_hwnd = None; + if let Some(container) = workspace.focused_container() { + if let Some(window) = container.focused_window() { + focused_hwnd = Some(window.hwnd); + } + } + + workspace.focus_container(workspace.containers().len() - 1); + while workspace.focused_container_idx() > 0 { + workspace.move_window_to_container(0)?; + workspace.focus_container(workspace.containers().len() - 1); + } + + if let Some(hwnd) = focused_hwnd { + workspace.focus_container_by_window(hwnd)?; + } + + self.update_focused_workspace(self.mouse_follows_focus, true) + } + + #[tracing::instrument(skip(self))] + pub fn unstack_all(&mut self) -> Result<()> { + self.handle_unmanaged_window_behaviour()?; + tracing::info!("unstacking all windows in container"); + + let workspace = self.focused_workspace_mut()?; + + let mut focused_hwnd = None; + if let Some(container) = workspace.focused_container() { + if let Some(window) = container.focused_window() { + focused_hwnd = Some(window.hwnd); + } + } + + let initial_focused_container_index = workspace.focused_container_idx(); + let mut focused_container = workspace.focused_container().cloned(); + + while let Some(focused) = &focused_container { + if focused.windows().len() > 1 { + workspace.new_container_for_focused_window()?; + workspace.focus_container(initial_focused_container_index); + focused_container = workspace.focused_container().cloned(); + } else { + focused_container = None; + } + } + + if let Some(hwnd) = focused_hwnd { + workspace.focus_container_by_window(hwnd)?; + } + + self.update_focused_workspace(self.mouse_follows_focus, true) + } + #[tracing::instrument(skip(self))] pub fn add_window_to_container(&mut self, direction: OperationDirection) -> Result<()> { self.handle_unmanaged_window_behaviour()?; diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 5610f3bd..70535e57 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -876,6 +876,10 @@ enum SubCommand { /// Stack the focused window in the specified direction #[clap(arg_required_else_help = true)] Stack(Stack), + /// Stack all windows on the focused workspace + StackAll, + /// Unstack all windows in the focused container + UnstackAll, /// Resize the focused window in the specified direction #[clap(arg_required_else_help = true)] #[clap(alias = "resize")] @@ -2016,9 +2020,15 @@ Stop-Process -Name:komorebi -ErrorAction SilentlyContinue SubCommand::Stack(arg) => { send_message(&SocketMessage::StackWindow(arg.operation_direction).as_bytes()?)?; } + SubCommand::StackAll => { + send_message(&SocketMessage::StackAll.as_bytes()?)?; + } SubCommand::Unstack => { send_message(&SocketMessage::UnstackWindow.as_bytes()?)?; } + SubCommand::UnstackAll => { + send_message(&SocketMessage::UnstackAll.as_bytes()?)?; + } SubCommand::CycleStack(arg) => { send_message(&SocketMessage::CycleStack(arg.cycle_direction).as_bytes()?)?; }