diff --git a/README.md b/README.md index 2b93ab56..8c4a945a 100644 --- a/README.md +++ b/README.md @@ -282,74 +282,75 @@ keybindings with. You can run `komorebic.exe --help` to get a full exp each command. ``` -start Start komorebi.exe as a background process -stop Stop the komorebi.exe process and restore all hidden windows -state Show a JSON representation of the current window manager state -query Query the current window manager state -subscribe Subscribe to komorebi events -unsubscribe Unsubscribe from komorebi events -log Tail komorebi.exe's process logs (cancel with Ctrl-C) -quick-save-resize Quicksave the current resize layout dimensions -quick-load-resize Load the last quicksaved resize layout dimensions -save-resize Save the current resize layout dimensions to a file -load-resize Load the resize layout dimensions from a file -focus Change focus to the window in the specified direction -move Move the focused window in the specified direction -cycle-focus Change focus to the window in the specified cycle direction -cycle-move Move the focused window in the specified cycle direction -stack Stack the focused window in the specified direction -resize-edge Resize the focused window in the specified direction -resize-axis Resize the focused window or primary column along the specified axis -unstack Unstack the focused window -cycle-stack Cycle the focused stack in the specified cycle direction -move-to-monitor Move the focused window to the specified monitor -move-to-workspace Move the focused window to the specified workspace -send-to-monitor Send the focused window to the specified monitor -send-to-workspace Send the focused window to the specified workspace -focus-monitor Focus the specified monitor -focus-workspace Focus the specified workspace on the focused monitor -cycle-monitor Focus the monitor in the given cycle direction -cycle-workspace Focus the workspace in the given cycle direction -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 -work-area-offset Set offsets to exclude parts of the work area from tiling -adjust-container-padding Adjust container padding on the focused workspace -adjust-workspace-padding Adjust workspace padding on the focused workspace -change-layout Set the layout on the focused workspace -load-custom-layout Load a custom layout from file for the focused workspace -flip-layout Flip the layout on the focused workspace (BSP only) -promote Promote the focused window to the top of the tree -retile Force the retiling of all managed windows -ensure-workspaces Create at least this many workspaces for the specified monitor -container-padding Set the container padding for the specified workspace -workspace-padding Set the workspace padding for the specified workspace -workspace-layout Set the layout for the specified workspace -workspace-custom-layout Set a custom layout for the specified workspace -workspace-tiling Enable or disable window tiling for the specified workspace -workspace-name Set the workspace name for the specified workspace -toggle-new-window-behaviour Toggle the behaviour for new windows (stacking or dynamic tiling) -toggle-pause Toggle window tiling on the focused workspace -toggle-tiling Toggle window tiling on the focused workspace -toggle-float Toggle floating mode for the focused window -toggle-monocle Toggle monocle mode for the focused container -toggle-maximize Toggle native maximization for the focused window -restore-windows Restore all hidden windows (debugging command) -manage Force komorebi to manage the focused window -unmanage Unmanage a window that was forcibly managed -reload-configuration Reload ~/komorebi.ahk (if it exists) -watch-configuration Enable or disable watching of ~/komorebi.ahk (if it exists) -float-rule Add a rule to always float the specified application -manage-rule Add a rule to always manage the specified application -workspace-rule Add a rule to associate an application with a workspace -identify-tray-application Identify an application that closes to the system tray -identify-border-overflow Identify an application that has overflowing borders -focus-follows-mouse Enable or disable focus follows mouse for the operating system -toggle-focus-follows-mouse Toggle focus follows mouse for the operating system -mouse-follows-focus Enable or disable mouse follows focus on all workspaces -toggle-mouse-follows-focus Toggle mouse follows focus on all workspaces -ahk-library Generate a library of AutoHotKey helper functions -help Print this message or the help of the given subcommand(s) +start Start komorebi.exe as a background process +stop Stop the komorebi.exe process and restore all hidden windows +state Show a JSON representation of the current window manager state +query Query the current window manager state +subscribe Subscribe to komorebi events +unsubscribe Unsubscribe from komorebi events +log Tail komorebi.exe's process logs (cancel with Ctrl-C) +quick-save-resize Quicksave the current resize layout dimensions +quick-load-resize Load the last quicksaved resize layout dimensions +save-resize Save the current resize layout dimensions to a file +load-resize Load the resize layout dimensions from a file +focus Change focus to the window in the specified direction +move Move the focused window in the specified direction +cycle-focus Change focus to the window in the specified cycle direction +cycle-move Move the focused window in the specified cycle direction +stack Stack the focused window in the specified direction +resize-edge Resize the focused window in the specified direction +resize-axis Resize the focused window or primary column along the specified axis +unstack Unstack the focused window +cycle-stack Cycle the focused stack in the specified cycle direction +move-to-monitor Move the focused window to the specified monitor +move-to-workspace Move the focused window to the specified workspace +send-to-monitor Send the focused window to the specified monitor +send-to-workspace Send the focused window to the specified workspace +focus-monitor Focus the specified monitor +focus-workspace Focus the specified workspace on the focused monitor +cycle-monitor Focus the monitor in the given cycle direction +cycle-workspace Focus the workspace in the given cycle direction +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 +work-area-offset Set offsets to exclude parts of the work area from tiling +adjust-container-padding Adjust container padding on the focused workspace +adjust-workspace-padding Adjust workspace padding on the focused workspace +change-layout Set the layout on the focused workspace +load-custom-layout Load a custom layout from file for the focused workspace +flip-layout Flip the layout on the focused workspace (BSP only) +promote Promote the focused window to the top of the tree +retile Force the retiling of all managed windows +ensure-workspaces Create at least this many workspaces for the specified monitor +container-padding Set the container padding for the specified workspace +workspace-padding Set the workspace padding for the specified workspace +workspace-layout Set the layout for the specified workspace +workspace-custom-layout Set a custom layout for the specified workspace +workspace-tiling Enable or disable window tiling for the specified workspace +workspace-name Set the workspace name for the specified workspace +toggle-window-container-behaviour Toggle the behaviour for new windows (stacking or dynamic tiling) +toggle-pause Toggle window tiling on the focused workspace +toggle-tiling Toggle window tiling on the focused workspace +toggle-float Toggle floating mode for the focused window +toggle-monocle Toggle monocle mode for the focused container +toggle-maximize Toggle native maximization for the focused window +restore-windows Restore all hidden windows (debugging command) +manage Force komorebi to manage the focused window +unmanage Unmanage a window that was forcibly managed +reload-configuration Reload ~/komorebi.ahk (if it exists) +watch-configuration Enable or disable watching of ~/komorebi.ahk (if it exists) +window-hiding-behaviour Set the window behaviour when switching workspaces / cycling stacks +float-rule Add a rule to always float the specified application +manage-rule Add a rule to always manage the specified application +workspace-rule Add a rule to associate an application with a workspace +identify-tray-application Identify an application that closes to the system tray +identify-border-overflow Identify an application that has overflowing borders +focus-follows-mouse Enable or disable focus follows mouse for the operating system +toggle-focus-follows-mouse Toggle focus follows mouse for the operating system +mouse-follows-focus Enable or disable mouse follows focus on all workspaces +toggle-mouse-follows-focus Toggle mouse follows focus on all workspaces +ahk-library Generate a library of AutoHotKey helper functions +help Print this message or the help of the given subcommand(s) ``` ### AutoHotKey Helper Library for `komorebic` diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index 99830104..bfa0e2e1 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -52,6 +52,7 @@ pub enum SocketMessage { ToggleMonocle, ToggleMaximize, ToggleWindowContainerBehaviour, + WindowHidingBehaviour(HidingBehaviour), // Current Workspace Commands ManageFocusedWindow, UnmanageFocusedWindow, @@ -147,6 +148,13 @@ pub enum WindowContainerBehaviour { Append, } +#[derive(Clone, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)] +#[strum(serialize_all = "snake_case")] +pub enum HidingBehaviour { + Hide, + Minimize, +} + #[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)] #[strum(serialize_all = "snake_case")] pub enum Sizing { diff --git a/komorebi.sample.with.lib.ahk b/komorebi.sample.with.lib.ahk index 8e09a196..146347e0 100644 --- a/komorebi.sample.with.lib.ahk +++ b/komorebi.sample.with.lib.ahk @@ -1,6 +1,9 @@ #SingleInstance Force #Include %A_ScriptDir%\komorebic.lib.ahk +; Default to minimizing windows when switching workspaces +WindowHidingBehaviour("minimize") + ; Enable hot reloading of changes to this file WatchConfiguration("enable") diff --git a/komorebi/src/main.rs b/komorebi/src/main.rs index 04b22308..0da33069 100644 --- a/komorebi/src/main.rs +++ b/komorebi/src/main.rs @@ -29,6 +29,7 @@ use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::EnvFilter; use which::which; +use komorebi_core::HidingBehaviour; use komorebi_core::SocketMessage; use crate::process_command::listen_for_commands; @@ -92,6 +93,8 @@ lazy_static! { ])); static ref SUBSCRIPTION_PIPES: Arc>> = Arc::new(Mutex::new(HashMap::new())); + static ref HIDING_BEHAVIOUR: Arc> = + Arc::new(Mutex::new(HidingBehaviour::Minimize)); } pub static CUSTOM_FFM: AtomicBool = AtomicBool::new(false); diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index b66eeecb..78f3f41d 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -34,6 +34,7 @@ use crate::NotificationEvent; use crate::BORDER_OVERFLOW_IDENTIFIERS; use crate::CUSTOM_FFM; use crate::FLOAT_IDENTIFIERS; +use crate::HIDING_BEHAVIOUR; use crate::MANAGE_IDENTIFIERS; use crate::SUBSCRIPTION_PIPES; use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS; @@ -559,6 +560,10 @@ impl WindowManager { } } } + SocketMessage::WindowHidingBehaviour(behaviour) => { + let mut hiding_behaviour = HIDING_BEHAVIOUR.lock(); + *hiding_behaviour = behaviour; + } }; tracing::info!("processed"); diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index 91c0860a..cac1339b 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -103,13 +103,25 @@ impl WindowManager { window.raise()?; self.has_pending_raise_op = false; } - WindowManagerEvent::Minimize(_, window) - | WindowManagerEvent::Destroy(_, window) - | WindowManagerEvent::Unmanage(window) => { + WindowManagerEvent::Destroy(_, window) | WindowManagerEvent::Unmanage(window) => { self.focused_workspace_mut()?.remove_window(window.hwnd)?; self.update_focused_workspace(false)?; } + WindowManagerEvent::Minimize(_, window) => { + let mut hide = false; + { + let programmatically_hidden_hwnds = HIDDEN_HWNDS.lock(); + if !programmatically_hidden_hwnds.contains(&window.hwnd) { + hide = true; + } + } + + if hide { + self.focused_workspace_mut()?.remove_window(window.hwnd)?; + self.update_focused_workspace(false)?; + } + } WindowManagerEvent::Hide(_, window) => { let mut hide = false; // Some major applications unfortunately send the HIDE signal when they are being diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index 5dea60a4..f56bf321 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -10,6 +10,7 @@ use serde::Serialize; use serde::Serializer; use windows::Win32::Foundation::HWND; +use komorebi_core::HidingBehaviour; use komorebi_core::Rect; use crate::styles::ExtendedWindowStyle; @@ -19,6 +20,7 @@ use crate::windows_api::WindowsApi; use crate::BORDER_OVERFLOW_IDENTIFIERS; use crate::FLOAT_IDENTIFIERS; use crate::HIDDEN_HWNDS; +use crate::HIDING_BEHAVIOUR; use crate::LAYERED_EXE_WHITELIST; use crate::MANAGE_IDENTIFIERS; use crate::WSL2_UI_PROCESSES; @@ -139,7 +141,11 @@ impl Window { programmatically_hidden_hwnds.push(self.hwnd); } - WindowsApi::hide_window(self.hwnd()); + let hiding_behaviour = HIDING_BEHAVIOUR.lock(); + match *hiding_behaviour { + HidingBehaviour::Hide => WindowsApi::hide_window(self.hwnd()), + HidingBehaviour::Minimize => WindowsApi::minimize_window(self.hwnd()), + } } pub fn restore(self) { diff --git a/komorebi/src/windows_api.rs b/komorebi/src/windows_api.rs index bb394733..85898e12 100644 --- a/komorebi/src/windows_api.rs +++ b/komorebi/src/windows_api.rs @@ -74,6 +74,7 @@ use windows::Win32::UI::WindowsAndMessaging::SPI_GETACTIVEWINDOWTRACKING; use windows::Win32::UI::WindowsAndMessaging::SPI_SETACTIVEWINDOWTRACKING; use windows::Win32::UI::WindowsAndMessaging::SW_HIDE; use windows::Win32::UI::WindowsAndMessaging::SW_MAXIMIZE; +use windows::Win32::UI::WindowsAndMessaging::SW_MINIMIZE; use windows::Win32::UI::WindowsAndMessaging::SW_RESTORE; use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_ACTION; use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS; @@ -279,6 +280,10 @@ impl WindowsApi { unsafe { ShowWindow(hwnd, command) }; } + pub fn minimize_window(hwnd: HWND) { + Self::show_window(hwnd, SW_MINIMIZE); + } + pub fn hide_window(hwnd: HWND) { Self::show_window(hwnd, SW_HIDE); } diff --git a/komorebic.lib.sample.ahk b/komorebic.lib.sample.ahk index f5d464a5..e5f80c9d 100644 --- a/komorebic.lib.sample.ahk +++ b/komorebic.lib.sample.ahk @@ -228,6 +228,10 @@ WatchConfiguration(boolean_state) { Run, komorebic.exe watch-configuration %boolean_state%, , Hide } +WindowHidingBehaviour(hiding_behaviour) { + Run, komorebic.exe window-hiding-behaviour %hiding_behaviour%, , Hide +} + FloatRule(identifier, id) { Run, komorebic.exe float-rule %identifier% %id%, , Hide } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 60044e06..d2f38088 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -32,6 +32,7 @@ use komorebi_core::Axis; use komorebi_core::CycleDirection; use komorebi_core::DefaultLayout; use komorebi_core::FocusFollowsMouseImplementation; +use komorebi_core::HidingBehaviour; use komorebi_core::OperationDirection; use komorebi_core::Rect; use komorebi_core::Sizing; @@ -90,6 +91,7 @@ gen_enum_subcommand_args! { WatchConfiguration: BooleanState, MouseFollowsFocus: BooleanState, Query: StateQuery, + WindowHidingBehaviour: HidingBehaviour, } macro_rules! gen_target_subcommand_args { @@ -506,6 +508,9 @@ enum SubCommand { /// Enable or disable watching of ~/komorebi.ahk (if it exists) #[clap(setting = AppSettings::ArgRequiredElseHelp)] WatchConfiguration(WatchConfiguration), + /// Set the window behaviour when switching workspaces / cycling stacks + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + WindowHidingBehaviour(WindowHidingBehaviour), /// Add a rule to always float the specified application #[clap(setting = AppSettings::ArgRequiredElseHelp)] FloatRule(FloatRule), @@ -963,6 +968,9 @@ fn main() -> Result<()> { SubCommand::ToggleWindowContainerBehaviour => { send_message(&*SocketMessage::ToggleWindowContainerBehaviour.as_bytes()?)?; } + SubCommand::WindowHidingBehaviour(arg) => { + send_message(&*SocketMessage::WindowHidingBehaviour(arg.hiding_behaviour).as_bytes()?)?; + } } Ok(())