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).
This commit is contained in:
LGUG2Z
2024-01-11 18:51:39 -08:00
parent 8f30612220
commit d6e83e1778
5 changed files with 70 additions and 12 deletions

View File

@@ -99,6 +99,7 @@ pub enum SocketMessage {
CycleFocusMonitor(CycleDirection),
CycleFocusWorkspace(CycleDirection),
FocusMonitorNumber(usize),
FocusLastWorkspace,
FocusWorkspaceNumber(usize),
FocusWorkspaceNumbers(usize),
FocusMonitorWorkspaceNumber(usize, usize),

View File

@@ -35,6 +35,9 @@ pub struct Monitor {
work_area_offset: Option<Rect>,
workspaces: Ring<Workspace>,
#[serde(skip_serializing)]
#[getset(get_copy = "pub", set = "pub")]
last_focused_workspace: Option<usize>,
#[serde(skip_serializing)]
#[getset(get_mut = "pub")]
workspace_names: HashMap<usize, String>,
}
@@ -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(),
}
}

View File

@@ -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));

View File

@@ -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<usize> {
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)

View File

@@ -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()?)?;
}