From ac265de1e39aebd2377c8d2e59a1a2dafd51fd8a Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Wed, 28 Oct 2026 03:11:38 -0700 Subject: [PATCH] feat(wm): padding for named workspaces workspace-padding and container-padding take the index of a workspace's monitor and its own index, so a script that names its workspaces still has to count them to pad one, while focus-named-workspace, named-workspace-layout and named-workspace-tiling already take the name. named-workspace-padding and named-workspace-container-padding take the name instead. They look the workspace up on every monitor the way the other named commands do, set the same padding the commands by index set, and change nothing for a name no workspace has. The tests check the messages the subcommands send, that a named workspace takes its paddings and the tile in front follows, and that a name nobody has changes nothing. The commands sweep of the VM suite sends both commands to a real session. --- docs/cli/named-workspace-container-padding.md | 17 +++++ docs/cli/named-workspace-padding.md | 17 +++++ docs/dev/ARCHITECTURE.md | 16 +++-- docs/usage/padding-and-offsets.md | 7 ++ komorebi/src/core/mod.rs | 2 + komorebi/src/process_command.rs | 24 +++++-- komorebi/tests/padding.rs | 68 +++++++++++++++++++ komorebic/src/main.rs | 48 +++++++++++-- komorebic/tests/cli.rs | 10 +++ nix/tests/vm/suites/commands/test.py | 4 ++ 10 files changed, 198 insertions(+), 15 deletions(-) create mode 100644 docs/cli/named-workspace-container-padding.md create mode 100644 docs/cli/named-workspace-padding.md diff --git a/docs/cli/named-workspace-container-padding.md b/docs/cli/named-workspace-container-padding.md new file mode 100644 index 00000000..e938ec60 --- /dev/null +++ b/docs/cli/named-workspace-container-padding.md @@ -0,0 +1,17 @@ +```text +Set the container padding for the specified workspace + +Usage: named-workspace-container-padding + +Arguments: + + Target workspace name + + + Pixels to pad with as an integer + +Options: + -h, --help + Print help + +``` diff --git a/docs/cli/named-workspace-padding.md b/docs/cli/named-workspace-padding.md new file mode 100644 index 00000000..dce5962a --- /dev/null +++ b/docs/cli/named-workspace-padding.md @@ -0,0 +1,17 @@ +```text +Set the workspace padding for the specified workspace + +Usage: named-workspace-padding + +Arguments: + + Target workspace name + + + Pixels to pad with as an integer + +Options: + -h, --help + Print help + +``` diff --git a/docs/dev/ARCHITECTURE.md b/docs/dev/ARCHITECTURE.md index 07dc1607..d5a8442e 100644 --- a/docs/dev/ARCHITECTURE.md +++ b/docs/dev/ARCHITECTURE.md @@ -405,13 +405,15 @@ focused is in no container of the focused workspace ([`WindowManager::handle_unmanaged_window_behaviour`]). `WorkspacePadding`, `ContainerPadding` and their `FocusedWorkspace` forms set a workspace's own -padding, and `AdjustWorkspacePadding` and `AdjustContainerPadding` change the focused -workspace's by a number of pixels, which needs a padding of its own to change -([`WindowManager::adjust_workspace_padding`]). `WorkAreaOffset`, `MonitorWorkAreaOffset` and -`WorkspaceWorkAreaOffset` set the offset of the window manager, of a monitor or of a workspace, -and `ToggleWindowBasedWorkAreaOffset` sets whether the focused workspace takes its monitor's -window-based offset ([`Workspace::apply_window_based_work_area_offset`]). Each tiles the -workspace in front again, or every monitor. +padding, and `NamedWorkspacePadding` and `NamedWorkspaceContainerPadding` do the same for the +workspace with a name, which they look up like `NamedWorkspaceLayout` does +([`WindowManager::monitor_workspace_index_by_name`]). `AdjustWorkspacePadding` and +`AdjustContainerPadding` change the focused workspace's by a number of pixels, which needs a padding +of its own to change ([`WindowManager::adjust_workspace_padding`]). `WorkAreaOffset`, +`MonitorWorkAreaOffset` and `WorkspaceWorkAreaOffset` set the offset of the window manager, of a +monitor or of a workspace, and `ToggleWindowBasedWorkAreaOffset` sets whether the focused workspace +takes its monitor's window-based offset ([`Workspace::apply_window_based_work_area_offset`]). Each +tiles the workspace in front again, or every monitor. `ResizeWindowEdge` and `ResizeWindowAxis` resize the focused container ([`WindowManager::resize_window`]). A resize is an adjustment of the container's tile, kept in diff --git a/docs/usage/padding-and-offsets.md b/docs/usage/padding-and-offsets.md index a058c9a6..77e1cdd2 100644 --- a/docs/usage/padding-and-offsets.md +++ b/docs/usage/padding-and-offsets.md @@ -21,11 +21,18 @@ set the paddings of the focused workspace, and [`komorebic container-padding`](../cli/container-padding.md) those of a workspace given by the index of its monitor and its own, counted from 0. +[`komorebic named-workspace-padding`](../cli/named-workspace-padding.md) and +[`komorebic named-workspace-container-padding`](../cli/named-workspace-container-padding.md) find +the workspace by the [name](workspaces.md#names) it was given instead, on whichever monitor has +it. A name no workspace has changes nothing. + ```sh komorebic focused-workspace-padding 20 komorebic focused-workspace-container-padding 10 komorebic workspace-padding 0 1 0 komorebic container-padding 0 1 0 +komorebic named-workspace-padding mail 0 +komorebic named-workspace-container-padding mail 0 ``` [`komorebic adjust-workspace-padding`](../cli/adjust-workspace-padding.md) and diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index f33eae60..2e6b1622 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -419,8 +419,10 @@ pub enum SocketMessage { FocusMonitorWorkspaceNumber(usize, usize), FocusNamedWorkspace(String), ContainerPadding(usize, usize, i32), + NamedWorkspaceContainerPadding(String, i32), FocusedWorkspaceContainerPadding(i32), WorkspacePadding(usize, usize, i32), + NamedWorkspacePadding(String, i32), FocusedWorkspacePadding(i32), WorkspaceTiling(usize, usize, bool), NamedWorkspaceTiling(String, bool), diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 08b3624a..5e242d99 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -53,10 +53,12 @@ //! workspace, which komorebi does not move, or puts a floating window back //! ([`WindowManager::toggle_float`]). //! - **WorkspacePadding** and **ContainerPadding** set the paddings of a workspace given by the -//! index of its monitor and its own, **FocusedWorkspacePadding** and -//! **FocusedWorkspaceContainerPadding** those of the focused workspace, and -//! **AdjustWorkspacePadding** and **AdjustContainerPadding** make the focused workspace's larger -//! or smaller ([`WindowManager::set_workspace_padding`], +//! index of its monitor and its own, **NamedWorkspacePadding** and +//! **NamedWorkspaceContainerPadding** those of the workspace with a name +//! ([`WindowManager::monitor_workspace_index_by_name`]; a name no workspace has changes +//! nothing), **FocusedWorkspacePadding** and **FocusedWorkspaceContainerPadding** those of the +//! focused workspace, and **AdjustWorkspacePadding** and **AdjustContainerPadding** make the +//! focused workspace's larger or smaller ([`WindowManager::set_workspace_padding`], //! [`WindowManager::set_container_padding`], [`WindowManager::adjust_workspace_padding`], //! [`WindowManager::adjust_container_padding`]). //! - **WorkAreaOffset**, **MonitorWorkAreaOffset** and **WorkspaceWorkAreaOffset** set the work @@ -1140,9 +1142,23 @@ impl WindowManager { SocketMessage::ContainerPadding(monitor_idx, workspace_idx, size) => { self.set_container_padding(monitor_idx, workspace_idx, size)?; } + SocketMessage::NamedWorkspaceContainerPadding(ref workspace, size) => { + if let Some((monitor_idx, workspace_idx)) = + self.monitor_workspace_index_by_name(workspace) + { + self.set_container_padding(monitor_idx, workspace_idx, size)?; + } + } SocketMessage::WorkspacePadding(monitor_idx, workspace_idx, size) => { self.set_workspace_padding(monitor_idx, workspace_idx, size)?; } + SocketMessage::NamedWorkspacePadding(ref workspace, size) => { + if let Some((monitor_idx, workspace_idx)) = + self.monitor_workspace_index_by_name(workspace) + { + self.set_workspace_padding(monitor_idx, workspace_idx, size)?; + } + } SocketMessage::FocusedWorkspaceContainerPadding(adjustment) => { let focused_monitor_idx = self.focused_monitor_idx(); diff --git a/komorebi/tests/padding.rs b/komorebi/tests/padding.rs index 92c5c936..3abf9d4f 100644 --- a/komorebi/tests/padding.rs +++ b/komorebi/tests/padding.rs @@ -88,6 +88,17 @@ fn one_window_without_padding(id: u32) -> (Arc, WindowManager) { (fake, wm) } +/// The workspace padding and the container padding each workspace of the focused monitor has of +/// its own +fn paddings(wm: &WindowManager) -> Vec<(Option, Option)> { + wm.focused_monitor() + .unwrap() + .workspaces() + .iter() + .map(|workspace| (workspace.workspace_padding, workspace.container_padding)) + .collect() +} + #[test] fn the_paddings_of_the_focused_workspace_are_set_and_adjusted() { let (fake, mut wm) = desktop_with(&[28_001]); @@ -156,6 +167,63 @@ fn the_paddings_of_a_workspace_are_set_by_its_indices() { ); } +#[test] +fn the_paddings_of_a_workspace_are_set_by_its_name_and_a_name_nobody_has_changes_nothing() { + let (fake, mut wm) = desktop_with(&[28_041]); + send( + &fake, + &mut wm, + SocketMessage::EnsureNamedWorkspaces(0, vec![String::from("main"), String::from("side")]), + ) + .unwrap(); + + // the workspace in front is tiled again at once + send( + &fake, + &mut wm, + SocketMessage::NamedWorkspacePadding(String::from("main"), 20), + ) + .unwrap(); + assert_eq!(fake.rect_of(28_041), Some(rect(25, 25, 1870, 1000))); + send( + &fake, + &mut wm, + SocketMessage::NamedWorkspaceContainerPadding(String::from("main"), 0), + ) + .unwrap(); + assert_eq!(fake.rect_of(28_041), Some(rect(20, 20, 1880, 1010))); + + // another workspace takes its own paddings, and the one in front keeps its tile + send( + &fake, + &mut wm, + SocketMessage::NamedWorkspacePadding(String::from("side"), 7), + ) + .unwrap(); + send( + &fake, + &mut wm, + SocketMessage::NamedWorkspaceContainerPadding(String::from("side"), 3), + ) + .unwrap(); + assert_eq!(fake.rect_of(28_041), Some(rect(20, 20, 1880, 1010))); + assert_eq!(paddings(&wm), [(Some(20), Some(0)), (Some(7), Some(3))]); + + send( + &fake, + &mut wm, + SocketMessage::NamedWorkspacePadding(String::from("nowhere"), 99), + ) + .unwrap(); + send( + &fake, + &mut wm, + SocketMessage::NamedWorkspaceContainerPadding(String::from("nowhere"), 99), + ) + .unwrap(); + assert_eq!(paddings(&wm), [(Some(20), Some(0)), (Some(7), Some(3))]); +} + #[test] fn the_workspaces_offset_wins_over_the_monitors_which_wins_over_the_global_one() { let (fake, mut wm) = one_window_without_padding(28_021); diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 08a85caf..082a3529 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -47,10 +47,11 @@ //! `cross-monitor-move-behaviour` and `toggle-cross-monitor-move-behaviour` set what `move` does //! at the edge of a monitor, and `display-index-preference` gives a monitor an index. //! `eager-focus` focuses the first window of an executable, on any workspace of any monitor. -//! - `workspace-name` names a workspace, which `focus-named-workspace`, `named-workspace-layout` -//! and `named-workspace-tiling` find by its name; `workspace-layout` and `workspace-tiling` set -//! the layout and the tiling of a workspace by its index, and `ensure-workspaces` and -//! `ensure-named-workspaces` give a monitor workspaces up to a number, or with names. +//! - `workspace-name` names a workspace, which `focus-named-workspace`, `named-workspace-layout`, +//! `named-workspace-tiling`, `named-workspace-padding` and `named-workspace-container-padding` +//! find by its name; `workspace-layout` and `workspace-tiling` set the layout and the tiling of +//! a workspace by its index, and `ensure-workspaces` and `ensure-named-workspaces` give a +//! monitor workspaces up to a number, or with names. //! //! `ignore-rule` and `manage-rule` add a rule that keeps an application out of the layout or //! always in it, `session-float-rule` floats the focused window and every window like it until the @@ -297,6 +298,27 @@ gen_padding_subcommand_args! { WorkspacePadding, } +macro_rules! gen_named_padding_subcommand_args { + // SubCommand Pattern + ( $( $name:ident ),+ $(,)? ) => { + $( + #[derive(clap::Parser)] + pub struct $name { + /// Target workspace name + workspace: String, + + /// Pixels to pad with as an integer + size: i32, + } + )+ + }; +} + +gen_named_padding_subcommand_args! { + NamedWorkspaceContainerPadding, + NamedWorkspacePadding, +} + macro_rules! gen_padding_adjustment_subcommand_args { // SubCommand Pattern ( $( $name:ident ),+ $(,)? ) => { @@ -773,9 +795,15 @@ enum SubCommand { /// Set the container padding for the specified workspace #[clap(arg_required_else_help = true)] ContainerPadding(ContainerPadding), + /// Set the container padding for the specified workspace + #[clap(arg_required_else_help = true)] + NamedWorkspaceContainerPadding(NamedWorkspaceContainerPadding), /// Set the workspace padding for the specified workspace #[clap(arg_required_else_help = true)] WorkspacePadding(WorkspacePadding), + /// Set the workspace padding for the specified workspace + #[clap(arg_required_else_help = true)] + NamedWorkspacePadding(NamedWorkspacePadding), /// Set the layout for the specified workspace #[clap(arg_required_else_help = true)] WorkspaceLayout(WorkspaceLayout), @@ -1223,6 +1251,12 @@ fn main() -> eyre::Result<()> { args.size, ))?; } + SubCommand::NamedWorkspaceContainerPadding(args) => { + send_message(&SocketMessage::NamedWorkspaceContainerPadding( + args.workspace, + args.size, + ))?; + } SubCommand::WorkspacePadding(args) => { send_message(&SocketMessage::WorkspacePadding( args.monitor, @@ -1230,6 +1264,12 @@ fn main() -> eyre::Result<()> { args.size, ))?; } + SubCommand::NamedWorkspacePadding(args) => { + send_message(&SocketMessage::NamedWorkspacePadding( + args.workspace, + args.size, + ))?; + } SubCommand::FocusedWorkspacePadding(args) => { send_message(&SocketMessage::FocusedWorkspacePadding(args.size))?; } diff --git a/komorebic/tests/cli.rs b/komorebic/tests/cli.rs index 747317dc..e2ce00c2 100644 --- a/komorebic/tests/cli.rs +++ b/komorebic/tests/cli.rs @@ -315,6 +315,14 @@ fn the_padding_subcommands_send_the_workspace_and_the_pixels_they_are_given() { &["container-padding", "1", "0", "8"], r#"{"type":"ContainerPadding","content":[1,0,8]}"#, ); + sends( + &["named-workspace-padding", "mail", "12"], + r#"{"type":"NamedWorkspacePadding","content":["mail",12]}"#, + ); + sends( + &["named-workspace-container-padding", "mail", "8"], + r#"{"type":"NamedWorkspaceContainerPadding","content":["mail",8]}"#, + ); sends( &["adjust-workspace-padding", "increase", "5"], r#"{"type":"AdjustWorkspacePadding","content":["Increase",5]}"#, @@ -689,7 +697,9 @@ fn docgen_writes_the_help_of_every_subcommand_in_a_text_fence() { "move-to-workspace.md", "move-workspace-to-monitor.md", "move.md", + "named-workspace-container-padding.md", "named-workspace-layout.md", + "named-workspace-padding.md", "named-workspace-tiling.md", "new-workspace.md", "preselect-direction.md", diff --git a/nix/tests/vm/suites/commands/test.py b/nix/tests/vm/suites/commands/test.py index d2d3a711..64960b8a 100644 --- a/nix/tests/vm/suites/commands/test.py +++ b/nix/tests/vm/suites/commands/test.py @@ -278,6 +278,10 @@ container-padding 0 0 12 container-padding 0 0 10 workspace-padding 0 0 12 workspace-padding 0 0 10 +named-workspace-container-padding one 12 +named-workspace-container-padding one 10 +named-workspace-padding one 12 +named-workspace-padding one 10 cross-monitor-move-behaviour insert cross-monitor-move-behaviour swap toggle-cross-monitor-move-behaviour