From 39685dd6155a88006a78583112f226156244b66e Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 31 Dec 2021 09:21:47 -0800 Subject: [PATCH] feat(wm): add cmd to move ws to other monitors This commit adds a new komorebic command to move the entire focused workspace and all managed windows and containers to a target monitor index. Windows that have been excluded from management using various rules will not be moved as they are not tracked in the window manager state. resolve #88 --- README.md | 2 ++ komorebi-core/src/lib.rs | 1 + komorebi/src/monitor.rs | 14 ++++++++++++++ komorebi/src/process_command.rs | 3 +++ komorebi/src/window_manager.rs | 28 ++++++++++++++++++++++++++++ komorebic.lib.sample.ahk | 4 ++++ komorebic/src/main.rs | 7 +++++++ 7 files changed, 59 insertions(+) diff --git a/README.md b/README.md index f29cc6c9..eddca1d8 100644 --- a/README.md +++ b/README.md @@ -311,6 +311,7 @@ focus-workspace Focus the specified workspace on the focuse focus-monitor-workspace Focus the specified workspace on the target monitor cycle-monitor Focus the monitor in the given cycle direction cycle-workspace Focus the workspace in the given cycle direction +move-workspace-to-monitor Move the focused workspace to the specified monitor new-workspace Create and append a new workspace on the focused monitor resize-delta Set the resize delta (used by resize-edge and resize-axis) invisible-borders Set the invisible border dimensions around each window @@ -376,6 +377,7 @@ used [is available here](komorebi.sample.with.lib.ahk). - [x] Move focused window container to workspace follow - [x] Send focused window container to monitor - [x] Send focused window container to workspace +- [x] Move focused workspace to monitor - [x] Mouse follows focused container - [x] Resize window container in direction - [x] Resize window container on axis diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index 22b069c1..03badd28 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -47,6 +47,7 @@ pub enum SocketMessage { MoveContainerToWorkspaceNumber(usize), SendContainerToMonitorNumber(usize), SendContainerToWorkspaceNumber(usize), + MoveWorkspaceToMonitorNumber(usize), Promote, ToggleFloat, ToggleMonocle, diff --git a/komorebi/src/monitor.rs b/komorebi/src/monitor.rs index 6c6bbc08..298ff8c2 100644 --- a/komorebi/src/monitor.rs +++ b/komorebi/src/monitor.rs @@ -68,6 +68,20 @@ impl Monitor { Ok(()) } + pub fn remove_workspace_by_idx(&mut self, idx: usize) -> Option { + if idx < self.workspaces().len() { + return self.workspaces_mut().remove(idx); + } + + if idx == 0 { + self.workspaces_mut().push_back(Workspace::default()); + } else { + self.focus_workspace(idx - 1).ok()?; + }; + + None + } + pub fn ensure_workspace_count(&mut self, ensure_count: usize) { if self.workspaces().len() < ensure_count { self.workspaces_mut() diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 495a7502..04033dca 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -147,6 +147,9 @@ impl WindowManager { SocketMessage::SendContainerToMonitorNumber(monitor_idx) => { self.move_container_to_monitor(monitor_idx, false)?; } + SocketMessage::MoveWorkspaceToMonitorNumber(monitor_idx) => { + self.move_workspace_to_monitor(monitor_idx)?; + } SocketMessage::TogglePause => { if self.is_paused { tracing::info!("resuming"); diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index aebbf2ba..e8a4b4ad 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -828,6 +828,34 @@ impl WindowManager { self.update_focused_workspace(mouse_follows_focus) } + pub fn remove_focused_workspace(&mut self) -> Option { + let focused_monitor: &mut Monitor = self.focused_monitor_mut()?; + let focused_workspace_idx = focused_monitor.focused_workspace_idx(); + focused_monitor.remove_workspace_by_idx(focused_workspace_idx) + } + + #[tracing::instrument(skip(self))] + pub fn move_workspace_to_monitor(&mut self, idx: usize) -> Result<()> { + tracing::info!("moving workspace"); + let mouse_follows_focus = self.mouse_follows_focus; + let workspace = self + .remove_focused_workspace() + .ok_or_else(|| anyhow!("there is no workspace"))?; + + { + let target_monitor: &mut Monitor = self + .monitors_mut() + .get_mut(idx) + .ok_or_else(|| anyhow!("there is no monitor"))?; + + target_monitor.workspaces_mut().push_back(workspace); + target_monitor.focus_workspace(target_monitor.workspaces().len() - 1)?; + target_monitor.load_focused_workspace(mouse_follows_focus)?; + } + + self.focus_monitor(idx)?; + self.update_focused_workspace(mouse_follows_focus) + } #[tracing::instrument(skip(self))] pub fn focus_container_in_direction(&mut self, direction: OperationDirection) -> Result<()> { diff --git a/komorebic.lib.sample.ahk b/komorebic.lib.sample.ahk index 04f519c8..d3620db7 100644 --- a/komorebic.lib.sample.ahk +++ b/komorebic.lib.sample.ahk @@ -116,6 +116,10 @@ CycleWorkspace(cycle_direction) { Run, komorebic.exe cycle-workspace %cycle_direction%, , Hide } +MoveWorkspaceToMonitor(target) { + Run, komorebic.exe move-workspace-to-monitor %target%, , Hide +} + NewWorkspace() { Run, komorebic.exe new-workspace, , Hide } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 4a77890e..c5622bdb 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -114,6 +114,7 @@ gen_target_subcommand_args! { SendToWorkspace, FocusMonitor, FocusWorkspace, + MoveWorkspaceToMonitor, } // Thanks to @danielhenrymantilla for showing me how to use cfg_attr with an optional argument like @@ -445,6 +446,9 @@ enum SubCommand { /// Focus the workspace in the given cycle direction #[clap(setting = AppSettings::ArgRequiredElseHelp)] CycleWorkspace(CycleWorkspace), + /// Move the focused workspace to the specified monitor + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + MoveWorkspaceToMonitor(MoveWorkspaceToMonitor), /// Create and append a new workspace on the focused monitor NewWorkspace, /// Set the resize delta (used by resize-edge and resize-axis) @@ -633,6 +637,9 @@ fn main() -> Result<()> { SubCommand::SendToWorkspace(arg) => { send_message(&*SocketMessage::SendContainerToWorkspaceNumber(arg.target).as_bytes()?)?; } + SubCommand::MoveWorkspaceToMonitor(arg) => { + send_message(&*SocketMessage::MoveWorkspaceToMonitorNumber(arg.target).as_bytes()?)?; + } SubCommand::InvisibleBorders(arg) => { send_message( &*SocketMessage::InvisibleBorders(Rect {