From d6e83e177830450556565e4056a02254f6a66d86 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Thu, 11 Jan 2024 18:51:39 -0800 Subject: [PATCH] feat(cli): add last focused workspace cmd This commit adds a new komorebic command, focus-last-workspace, which switches to the last focused workspace on the focused monitor (if there is one). --- komorebi-core/src/lib.rs | 1 + komorebi/src/monitor.rs | 4 +++ komorebi/src/process_command.rs | 64 ++++++++++++++++++++++++++------- komorebi/src/window_manager.rs | 8 +++++ komorebic/src/main.rs | 5 +++ 5 files changed, 70 insertions(+), 12 deletions(-) diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index 7905bb59..3a7ba4ec 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -99,6 +99,7 @@ pub enum SocketMessage { CycleFocusMonitor(CycleDirection), CycleFocusWorkspace(CycleDirection), FocusMonitorNumber(usize), + FocusLastWorkspace, FocusWorkspaceNumber(usize), FocusWorkspaceNumbers(usize), FocusMonitorWorkspaceNumber(usize, usize), diff --git a/komorebi/src/monitor.rs b/komorebi/src/monitor.rs index 1d320c3c..225264f9 100644 --- a/komorebi/src/monitor.rs +++ b/komorebi/src/monitor.rs @@ -35,6 +35,9 @@ pub struct Monitor { work_area_offset: Option, workspaces: Ring, #[serde(skip_serializing)] + #[getset(get_copy = "pub", set = "pub")] + last_focused_workspace: Option, + #[serde(skip_serializing)] #[getset(get_mut = "pub")] workspace_names: HashMap, } @@ -54,6 +57,7 @@ pub fn new(id: isize, size: Rect, work_area_size: Rect, name: String) -> Monitor work_area_size, work_area_offset: None, workspaces, + last_focused_workspace: None, workspace_names: HashMap::default(), } } diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index b0380507..197115f1 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -172,6 +172,23 @@ impl WindowManager { _ => {} }; + match message { + SocketMessage::CycleFocusWorkspace(_) | SocketMessage::FocusWorkspaceNumber(_) => { + if let Some(monitor) = self.focused_monitor_mut() { + let idx = monitor.focused_workspace_idx(); + monitor.set_last_focused_workspace(Option::from(idx)); + } + } + SocketMessage::FocusMonitorWorkspaceNumber(target_monitor_idx, _) => { + let idx = self.focused_workspace_idx_for_monitor_idx(target_monitor_idx)?; + if let Some(monitor) = self.monitors_mut().get_mut(target_monitor_idx) { + monitor.set_last_focused_workspace(Option::from(idx)); + } + } + + _ => {} + }; + match message { SocketMessage::Promote => self.promote_container_to_front()?, SocketMessage::PromoteFocus => self.promote_focus_to_front()?, @@ -598,6 +615,33 @@ impl WindowManager { self.show_border()?; }; } + SocketMessage::FocusLastWorkspace => { + // 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 + if let Some(monitor_idx) = self.monitor_idx_from_current_pos() { + self.focus_monitor(monitor_idx)?; + } + + let idx = self + .focused_monitor() + .ok_or_else(|| anyhow!("there is no monitor"))? + .focused_workspace_idx(); + + if let Some(monitor) = self.focused_monitor_mut() { + if let Some(last_focused_workspace) = monitor.last_focused_workspace() { + self.focus_workspace(last_focused_workspace)?; + } + } + + self.focused_monitor_mut() + .ok_or_else(|| anyhow!("there is no monitor"))? + .set_last_focused_workspace(Option::from(idx)); + + if BORDER_ENABLED.load(Ordering::SeqCst) { + self.show_border()?; + }; + } 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 @@ -1338,21 +1382,17 @@ impl WindowManager { rect.bottom += self.invisible_borders.bottom; let monocle = BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst); - if monocle != 0 { - if self.focused_workspace()?.monocle_container().is_some() { - BORDER_COLOUR_CURRENT.store( - monocle, - Ordering::SeqCst, - ); - } + if monocle != 0 && self.focused_workspace()?.monocle_container().is_some() { + BORDER_COLOUR_CURRENT.store( + monocle, + Ordering::SeqCst, + ); } let stack = BORDER_COLOUR_STACK.load(Ordering::SeqCst); - if stack != 0 { - if self.focused_container()?.windows().len() > 1 { - BORDER_COLOUR_CURRENT - .store(stack, Ordering::SeqCst); - } + if stack != 0 && self.focused_container()?.windows().len() > 1 { + BORDER_COLOUR_CURRENT + .store(stack, Ordering::SeqCst); } let border = Border::from(BORDER_HWND.load(Ordering::SeqCst)); diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 6ddebf72..02a704fb 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -2198,6 +2198,14 @@ impl WindowManager { .ok_or_else(|| anyhow!("there is no workspace")) } + pub fn focused_workspace_idx_for_monitor_idx(&self, idx: usize) -> Result { + Ok(self + .monitors() + .get(idx) + .ok_or_else(|| anyhow!("there is no monitor at this index"))? + .focused_workspace_idx()) + } + pub fn focused_workspace_for_monitor_idx(&self, idx: usize) -> Result<&Workspace> { self.monitors() .get(idx) diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index d232417e..8bdd62d6 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -868,6 +868,8 @@ enum SubCommand { /// Focus the specified monitor #[clap(arg_required_else_help = true)] FocusMonitor(FocusMonitor), + /// Focus the last focused workspace on the focused monitor + FocusLastWorkspace, /// Focus the specified workspace on the focused monitor #[clap(arg_required_else_help = true)] FocusWorkspace(FocusWorkspace), @@ -1857,6 +1859,9 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue SubCommand::FocusMonitor(arg) => { send_message(&SocketMessage::FocusMonitorNumber(arg.target).as_bytes()?)?; } + SubCommand::FocusLastWorkspace => { + send_message(&SocketMessage::FocusLastWorkspace.as_bytes()?)?; + } SubCommand::FocusWorkspace(arg) => { send_message(&SocketMessage::FocusWorkspaceNumber(arg.target).as_bytes()?)?; }