diff --git a/README.md b/README.md index 005696cb..f859d44e 100644 --- a/README.md +++ b/README.md @@ -226,6 +226,8 @@ save Save the current resize layout dimensions to a fil load Load the resize layout dimensions from a file focus Change focus to the window in the specified direction move Move the focused window in the specified direction +cycle-focus Change focus to the window in the specified cycle direction +cycle-move Move the focused window in the specified cycle direction stack Stack the focused window in the specified direction resize Resize the focused window in the specified direction unstack Unstack the focused window @@ -236,6 +238,8 @@ send-to-monitor Send the focused window to the specified monitor send-to-workspace Send the focused window to the specified workspace focus-monitor Focus the specified monitor focus-workspace Focus the specified workspace on the focused monitor +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 adjust-container-padding Adjust container padding on the focused workspace diff --git a/komorebi-core/src/cycle_direction.rs b/komorebi-core/src/cycle_direction.rs index 9b448ec1..2882c586 100644 --- a/komorebi-core/src/cycle_direction.rs +++ b/komorebi-core/src/cycle_direction.rs @@ -1,7 +1,8 @@ +use std::num::NonZeroUsize; + use clap::ArgEnum; use serde::Deserialize; use serde::Serialize; -use std::num::NonZeroUsize; use strum::Display; use strum::EnumString; diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index 2ee01c8d..e1b29666 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -59,6 +59,8 @@ pub enum SocketMessage { QuickLoad, Save(PathBuf), Load(PathBuf), + CycleFocusMonitor(CycleDirection), + CycleFocusWorkspace(CycleDirection), FocusMonitorNumber(usize), FocusWorkspaceNumber(usize), ContainerPadding(usize, usize, i32), diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index ab9cfd21..0dedc6dd 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -3,6 +3,7 @@ use std::fs::OpenOptions; use std::io::BufRead; use std::io::BufReader; use std::io::Write; +use std::num::NonZeroUsize; use std::str::FromStr; use std::sync::atomic::Ordering; use std::sync::Arc; @@ -136,6 +137,16 @@ impl WindowManager { SocketMessage::ToggleTiling => { self.toggle_tiling()?; } + SocketMessage::CycleFocusMonitor(direction) => { + let monitor_idx = direction.next_idx( + self.focused_monitor_idx(), + NonZeroUsize::new(self.monitors().len()) + .ok_or_else(|| anyhow!("there must be at least one monitor"))?, + ); + + self.focus_monitor(monitor_idx)?; + self.update_focused_workspace(true)?; + } SocketMessage::FocusMonitorNumber(monitor_idx) => { self.focus_monitor(monitor_idx)?; self.update_focused_workspace(true)?; @@ -149,6 +160,31 @@ impl WindowManager { SocketMessage::WorkspaceLayout(monitor_idx, workspace_idx, layout) => { self.set_workspace_layout(monitor_idx, workspace_idx, layout)?; } + SocketMessage::CycleFocusWorkspace(direction) => { + // This is to ensure that even on an empty workspace on a secondary monitor, the + // secondary monitor where the cursor is focused will be used as the target for + // the workspace switch op + let monitor_idx = self.monitor_idx_from_current_pos().ok_or_else(|| { + anyhow!("there is no monitor associated with the current cursor position") + })?; + + self.focus_monitor(monitor_idx)?; + + let focused_monitor = self + .focused_monitor() + .ok_or_else(|| anyhow!("there is no monitor"))?; + + let focused_workspace_idx = focused_monitor.focused_workspace_idx(); + let workspaces = focused_monitor.workspaces().len(); + + let workspace_idx = direction.next_idx( + focused_workspace_idx, + NonZeroUsize::new(workspaces) + .ok_or_else(|| anyhow!("there must be at least one workspace"))?, + ); + + self.focus_workspace(workspace_idx)?; + } SocketMessage::FocusWorkspaceNumber(workspace_idx) => { // This is to ensure that even on an empty workspace on a secondary monitor, the // secondary monitor where the cursor is focused will be used as the target for diff --git a/komorebic.lib.sample.ahk b/komorebic.lib.sample.ahk index 97d978d4..870903b2 100644 --- a/komorebic.lib.sample.ahk +++ b/komorebic.lib.sample.ahk @@ -44,6 +44,14 @@ Move(operation_direction) { Run, komorebic.exe move %operation_direction%, , Hide } +CycleFocus(cycle_direction) { + Run, komorebic.exe cycle-focus %cycle_direction%, , Hide +} + +CycleMove(cycle_direction) { + Run, komorebic.exe cycle-move %cycle_direction%, , Hide +} + Stack(operation_direction) { Run, komorebic.exe stack %operation_direction%, , Hide } @@ -84,6 +92,14 @@ FocusWorkspace(target) { Run, komorebic.exe focus-workspace %target%, , Hide } +CycleMonitor(cycle_direction) { + Run, komorebic.exe cycle-monitor %cycle_direction%, , Hide +} + +CycleWorkspace(cycle_direction) { + Run, komorebic.exe cycle-workspace %cycle_direction%, , Hide +} + NewWorkspace() { Run, komorebic.exe new-workspace, , Hide } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 122467f7..bdf0bf65 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -81,6 +81,8 @@ gen_enum_subcommand_args! { Move: OperationDirection, CycleFocus: CycleDirection, CycleMove: CycleDirection, + CycleMonitor: CycleDirection, + CycleWorkspace: CycleDirection, Stack: OperationDirection, CycleStack: CycleDirection, FlipLayout: Flip, @@ -353,6 +355,12 @@ enum SubCommand { /// Focus the specified workspace on the focused monitor #[clap(setting = AppSettings::ArgRequiredElseHelp)] FocusWorkspace(FocusWorkspace), + /// Focus the monitor in the given cycle direction + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + CycleMonitor(CycleMonitor), + /// Focus the workspace in the given cycle direction + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + CycleWorkspace(CycleWorkspace), /// Create and append a new workspace on the focused monitor NewWorkspace, /// Set the invisible border dimensions around each window @@ -668,6 +676,12 @@ fn main() -> Result<()> { SubCommand::FocusWorkspace(arg) => { send_message(&*SocketMessage::FocusWorkspaceNumber(arg.target).as_bytes()?)?; } + SubCommand::CycleMonitor(arg) => { + send_message(&*SocketMessage::CycleFocusMonitor(arg.cycle_direction).as_bytes()?)?; + } + SubCommand::CycleWorkspace(arg) => { + send_message(&*SocketMessage::CycleFocusWorkspace(arg.cycle_direction).as_bytes()?)?; + } SubCommand::NewWorkspace => { send_message(&*SocketMessage::NewWorkspace.as_bytes()?)?; }