diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index 3f2a23997..779bf33ff 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -49,6 +49,7 @@ pub enum SocketMessage { StackWindow(OperationDirection), UnstackWindow, CycleStack(CycleDirection), + CycleStackIndex(CycleDirection), FocusStackWindow(usize), StackAll, UnstackAll, diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 117b19f0d..a4072064d 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -247,6 +247,10 @@ impl WindowManager { self.cycle_container_window_in_direction(direction)?; self.focused_window()?.focus(self.mouse_follows_focus)?; } + SocketMessage::CycleStackIndex(direction) => { + self.cycle_container_window_index_in_direction(direction)?; + self.focused_window()?.focus(self.mouse_follows_focus)?; + } SocketMessage::FocusStackWindow(idx) => { // In case you are using this command on a bar on a monitor // different from the currently focused one, you'd want that diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 9f4916b39..d4cb04630 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -2022,6 +2022,39 @@ impl WindowManager { self.update_focused_workspace(self.mouse_follows_focus, true) } + #[tracing::instrument(skip(self))] + pub fn cycle_container_window_index_in_direction( + &mut self, + direction: CycleDirection, + ) -> Result<()> { + self.handle_unmanaged_window_behaviour()?; + + tracing::info!("cycling container window index"); + + let container = + if let Some(container) = self.focused_workspace_mut()?.monocle_container_mut() { + container + } else { + self.focused_container_mut()? + }; + + let len = NonZeroUsize::new(container.windows().len()) + .ok_or_else(|| anyhow!("there must be at least one window in a container"))?; + + if len.get() == 1 { + bail!("there is only one window in this container"); + } + + let current_idx = container.focused_window_idx(); + let next_idx = direction.next_idx(current_idx, len); + container.windows_mut().swap(current_idx, next_idx); + + container.focus_window(next_idx); + container.load_focused_window(); + + self.update_focused_workspace(self.mouse_follows_focus, true) + } + #[tracing::instrument(skip(self))] pub fn focus_container_window(&mut self, idx: usize) -> Result<()> { self.handle_unmanaged_window_behaviour()?; diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 7c60031e1..245c2c391 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -160,6 +160,7 @@ gen_enum_subcommand_args! { CycleMoveWorkspaceToMonitor: CycleDirection, Stack: OperationDirection, CycleStack: CycleDirection, + CycleStackIndex: CycleDirection, FlipLayout: Axis, ChangeLayout: DefaultLayout, CycleLayout: CycleDirection, @@ -985,6 +986,9 @@ enum SubCommand { /// Cycle the focused stack in the specified cycle direction #[clap(arg_required_else_help = true)] CycleStack(CycleStack), + /// Cycle the index of the focused window in the focused stack in the specified cycle direction + #[clap(arg_required_else_help = true)] + CycleStackIndex(CycleStackIndex), /// Focus the specified window index in the focused stack #[clap(arg_required_else_help = true)] FocusStackWindow(FocusStackWindow), @@ -2305,6 +2309,9 @@ Stop-Process -Name:komorebi -ErrorAction SilentlyContinue SubCommand::CycleStack(arg) => { send_message(&SocketMessage::CycleStack(arg.cycle_direction))?; } + SubCommand::CycleStackIndex(arg) => { + send_message(&SocketMessage::CycleStackIndex(arg.cycle_direction))?; + } SubCommand::ChangeLayout(arg) => { send_message(&SocketMessage::ChangeLayout(arg.default_layout))?; }