From 6fe2290d74ee27231ff21ceb678e069027e03efe Mon Sep 17 00:00:00 2001 From: Yusuf007R Date: Thu, 8 Jun 2023 21:37:04 -0500 Subject: [PATCH] feat(swap-workspaces-monitor): command to swap focused monitor workspaces with another monitor Basically this commit adds a command that allows you to swap two monitors, well it actually swaps the workspaces between the monitors. --- komorebi-core/src/lib.rs | 1 + komorebi/src/monitor.rs | 4 ++ komorebi/src/process_command.rs | 3 ++ komorebi/src/window_manager.rs | 86 +++++++++++++++++++++++++++++++++ komorebic/src/main.rs | 7 +++ 5 files changed, 101 insertions(+) diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index bfa6bbae..79ee38dd 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -57,6 +57,7 @@ pub enum SocketMessage { SendContainerToMonitorWorkspaceNumber(usize, usize), SendContainerToNamedWorkspace(String), MoveWorkspaceToMonitorNumber(usize), + SwapWorkspacesToMonitorNumber(usize), ForceFocus, Close, Minimize, diff --git a/komorebi/src/monitor.rs b/komorebi/src/monitor.rs index da26bb81..a649013e 100644 --- a/komorebi/src/monitor.rs +++ b/komorebi/src/monitor.rs @@ -105,6 +105,10 @@ impl Monitor { } } + pub fn remove_workspaces(&mut self) -> VecDeque { + self.workspaces_mut().drain(..).collect() + } + #[tracing::instrument(skip(self))] pub fn move_container_to_workspace( &mut self, diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 4b59335a..7eab95c5 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -324,6 +324,9 @@ impl WindowManager { SocketMessage::MoveContainerToMonitorNumber(monitor_idx) => { self.move_container_to_monitor(monitor_idx, None, true)?; } + SocketMessage::SwapWorkspacesToMonitorNumber(monitor_idx) => { + self.swap_focused_monitor(monitor_idx)?; + } SocketMessage::CycleMoveContainerToMonitor(direction) => { let monitor_idx = direction.next_idx( self.focused_monitor_idx(), diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index a86ac905..c7fb1f5e 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1000,6 +1000,92 @@ impl WindowManager { Ok(()) } + pub fn update_focused_workspace_by_monitor_idx(&mut self, idx: usize) -> Result<()> { + let invisible_borders = self.invisible_borders; + let offset = self.work_area_offset; + + self.monitors_mut() + .get_mut(idx) + .ok_or_else(|| anyhow!("there is no monitor"))? + .update_focused_workspace(offset, &invisible_borders) + } + + #[tracing::instrument(skip(self))] + pub fn swap_monitor_workspaces(&mut self, first_idx: usize, second_idx: usize) -> Result<()> { + tracing::info!("swaping monitors"); + if first_idx == second_idx { + return Ok(()); + } + let mouse_follows_focus = self.mouse_follows_focus; + let first_focused_workspace = { + let first_monitor = self + .monitors() + .get(first_idx) + .ok_or_else(|| anyhow!("There is no monitor"))?; + first_monitor.focused_workspace_idx() + }; + + let second_focused_workspace = { + let second_monitor = self + .monitors() + .get(second_idx) + .ok_or_else(|| anyhow!("There is no monitor"))?; + second_monitor.focused_workspace_idx() + }; + + // Swap workspaces between the first and second monitors + + let first_workspaces = self + .monitors_mut() + .get_mut(first_idx) + .ok_or_else(|| anyhow!("There is no monitor"))? + .remove_workspaces(); + + let second_workspaces = self + .monitors_mut() + .get_mut(second_idx) + .ok_or_else(|| anyhow!("There is no monitor"))? + .remove_workspaces(); + + self.monitors_mut() + .get_mut(first_idx) + .ok_or_else(|| anyhow!("There is no monitor"))? + .workspaces_mut() + .extend(second_workspaces); + + self.monitors_mut() + .get_mut(second_idx) + .ok_or_else(|| anyhow!("There is no monitor"))? + .workspaces_mut() + .extend(first_workspaces); + + // Set the focused workspaces for the first and second monitors + if let Some(first_monitor) = self.monitors_mut().get_mut(first_idx) { + first_monitor.focus_workspace(second_focused_workspace)?; + first_monitor.load_focused_workspace(mouse_follows_focus)?; + } + + if let Some(second_monitor) = self.monitors_mut().get_mut(second_idx) { + second_monitor.focus_workspace(first_focused_workspace)?; + second_monitor.load_focused_workspace(mouse_follows_focus)?; + } + + self.update_focused_workspace_by_monitor_idx(second_idx)?; + self.update_focused_workspace_by_monitor_idx(first_idx) + } + + #[tracing::instrument(skip(self))] + pub fn swap_focused_monitor(&mut self, idx: usize) -> Result<()> { + tracing::info!("swapping focused monitor"); + + let focused_monitor_idx = self.focused_monitor_idx(); + let mouse_follows_focus = self.mouse_follows_focus; + + self.swap_monitor_workspaces(focused_monitor_idx, idx)?; + + self.update_focused_workspace(mouse_follows_focus) + } + #[tracing::instrument(skip(self))] pub fn move_container_to_monitor( &mut self, diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 364cc7ed..14bf3385 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -154,6 +154,7 @@ gen_target_subcommand_args! { FocusWorkspace, FocusWorkspaces, MoveWorkspaceToMonitor, + SwapWorkspacesToMonitor, } macro_rules! gen_named_target_subcommand_args { @@ -807,6 +808,9 @@ enum SubCommand { /// Move the focused workspace to the specified monitor #[clap(arg_required_else_help = true)] MoveWorkspaceToMonitor(MoveWorkspaceToMonitor), + /// Swap focused monitior workspaces with specified monitor + #[clap(arg_required_else_help = true)] + SwapWorkspacesToMonitor(SwapWorkspacesToMonitor), /// Create and append a new workspace on the focused monitor NewWorkspace, /// Set the resize delta (used by resize-edge and resize-axis) @@ -1192,6 +1196,9 @@ fn main() -> Result<()> { SubCommand::MoveWorkspaceToMonitor(arg) => { send_message(&SocketMessage::MoveWorkspaceToMonitorNumber(arg.target).as_bytes()?)?; } + SubCommand::SwapWorkspacesToMonitor(arg) => { + send_message(&SocketMessage::SwapWorkspacesToMonitorNumber(arg.target).as_bytes()?)?; + } SubCommand::InvisibleBorders(arg) => { send_message( &SocketMessage::InvisibleBorders(Rect {