From ff53533da05e19a22ed1e17838f2c1681136425d Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Mon, 13 Sep 2021 09:03:38 -0700 Subject: [PATCH] feat(wm): add cmd to id apps that overflow borders Applications like Spotify and Discord draw over the default invisible borders of Windows 10, which means that when komorebi is setting their positions, the offset is always off by the amount of pixels of the invisible borders on each side. This commit makes it possible to identify applications that have overflowing borders so that they can be handled appropriately by the window manager. This commit also takes the opportunity to consolidate the tray and multi window identifiers into a single vector instead of spreading them across multiple vectors by identifier type. resolve #32 --- README.md | 2 ++ komorebi-core/src/lib.rs | 1 + komorebi.sample.ahk | 3 +++ komorebi.sample.with.lib.ahk | 5 +++++ komorebi/src/main.rs | 20 +++++++++--------- komorebi/src/process_command.rs | 28 +++++++++++-------------- komorebi/src/process_event.rs | 12 +++++------ komorebi/src/window.rs | 36 +++++++++++++++++++++++---------- komorebi/src/window_manager.rs | 12 +++++------ komorebic.lib.sample.ahk | 4 ++++ komorebic/src/main.rs | 9 +++++++++ 11 files changed, 83 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 2de67762..1d5474b5 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,7 @@ float-rule Add a rule to always float the specified applicati 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 ahk-library Generate a library of AutoHotKey helper functions @@ -274,6 +275,7 @@ used [is available here](komorebi.sample.with.lib.ahk). - [x] Floating rules based on exe name, window title and class - [x] Workspace rules based on exe name and window class - [x] Additional manage rules based on exe name and window class +- [x] Identify applications which overflow their borders by exe name and class - [x] Identify 'close/minimize to tray' applications by exe name and class - [x] Toggle floating windows - [x] Toggle monocle window diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index 445d6a16..c4cd6e1e 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -66,6 +66,7 @@ pub enum SocketMessage { FloatRule(ApplicationIdentifier, String), ManageRule(ApplicationIdentifier, String), IdentifyTrayApplication(ApplicationIdentifier, String), + IdentifyBorderOverflow(ApplicationIdentifier, String), State, Query(StateQuery), FocusFollowsMouse(FocusFollowsMouseImplementation, bool), diff --git a/komorebi.sample.ahk b/komorebi.sample.ahk index 46e2e2bd..a4ed6ef6 100644 --- a/komorebi.sample.ahk +++ b/komorebi.sample.ahk @@ -52,6 +52,9 @@ Run, komorebic.exe manage-rule exe TIM.exe, , Hide ; Identify applications that close to the tray Run, komorebic.exe identify-tray-application exe Discord.exe, , Hide +; Identify applications that have overflowing borders +Run, komorebic.exe identify-border-overflow exe Discord.exe, , Hide + ; Change the focused window, Alt + Vim direction keys !h:: Run, komorebic.exe focus left, , Hide diff --git a/komorebi.sample.with.lib.ahk b/komorebi.sample.with.lib.ahk index 6f553345..57e194ac 100644 --- a/komorebi.sample.with.lib.ahk +++ b/komorebi.sample.with.lib.ahk @@ -42,6 +42,11 @@ FloatRule("exe", "Wox.exe") IdentifyTrayApplication("exe", "Discord.exe") IdentifyTrayApplication("exe", "Spotify.exe") +; Identify Electron applications with overflowing borders +IdentifyBorderOverflow("exe", "Discord.exe") +IdentifyBorderOverflow("exe", "Spotify.exe") +IdentifyBorderOverflow("class", "ZPFTEWndClass") + ; Change the focused window, Alt + Vim direction keys !h:: Focus("left") diff --git a/komorebi/src/main.rs b/komorebi/src/main.rs index 7a20fa8a..135b692c 100644 --- a/komorebi/src/main.rs +++ b/komorebi/src/main.rs @@ -53,16 +53,15 @@ lazy_static! { static ref HIDDEN_HWNDS: Arc>> = Arc::new(Mutex::new(vec![])); static ref LAYERED_EXE_WHITELIST: Arc>> = Arc::new(Mutex::new(vec!["steam.exe".to_string()])); - static ref TRAY_AND_MULTI_WINDOW_CLASSES: Arc>> = - Arc::new(Mutex::new(vec![])); - static ref TRAY_AND_MULTI_WINDOW_EXES: Arc>> = Arc::new(Mutex::new(vec![ - "explorer.exe".to_string(), - "firefox.exe".to_string(), - "chrome.exe".to_string(), - "idea64.exe".to_string(), - "ApplicationFrameHost.exe".to_string(), - "steam.exe".to_string(), - ])); + static ref TRAY_AND_MULTI_WINDOW_IDENTIFIERS: Arc>> = + Arc::new(Mutex::new(vec![ + "explorer.exe".to_string(), + "firefox.exe".to_string(), + "chrome.exe".to_string(), + "idea64.exe".to_string(), + "ApplicationFrameHost.exe".to_string(), + "steam.exe".to_string(), + ])); static ref OBJECT_NAME_CHANGE_ON_LAUNCH: Arc>> = Arc::new(Mutex::new(vec![ "firefox.exe".to_string(), "idea64.exe".to_string(), @@ -71,6 +70,7 @@ lazy_static! { Arc::new(Mutex::new(HashMap::new())); static ref MANAGE_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![])); static ref FLOAT_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![])); + static ref BORDER_OVERFLOW_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![])); } fn setup() -> Result<(WorkerGuard, WorkerGuard)> { diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 50c321df..ae37147f 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -10,7 +10,6 @@ use color_eyre::Result; use parking_lot::Mutex; use uds_windows::UnixStream; -use komorebi_core::ApplicationIdentifier; use komorebi_core::FocusFollowsMouseImplementation; use komorebi_core::SocketMessage; use komorebi_core::StateQuery; @@ -18,10 +17,10 @@ use komorebi_core::StateQuery; use crate::window_manager; use crate::window_manager::WindowManager; use crate::windows_api::WindowsApi; +use crate::BORDER_OVERFLOW_IDENTIFIERS; use crate::FLOAT_IDENTIFIERS; use crate::MANAGE_IDENTIFIERS; -use crate::TRAY_AND_MULTI_WINDOW_CLASSES; -use crate::TRAY_AND_MULTI_WINDOW_EXES; +use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS; use crate::WORKSPACE_RULES; #[tracing::instrument] @@ -295,21 +294,18 @@ impl WindowManager { SocketMessage::WatchConfiguration(enable) => { self.watch_configuration(enable)?; } - SocketMessage::IdentifyTrayApplication(identifier, id) => match identifier { - ApplicationIdentifier::Exe => { - let mut exes = TRAY_AND_MULTI_WINDOW_EXES.lock(); - if !exes.contains(&id) { - exes.push(id); - } + SocketMessage::IdentifyBorderOverflow(_, id) => { + let mut identifiers = BORDER_OVERFLOW_IDENTIFIERS.lock(); + if !identifiers.contains(&id) { + identifiers.push(id); } - ApplicationIdentifier::Class => { - let mut classes = TRAY_AND_MULTI_WINDOW_CLASSES.lock(); - if !classes.contains(&id) { - classes.push(id); - } + } + SocketMessage::IdentifyTrayApplication(_, id) => { + let mut identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock(); + if !identifiers.contains(&id) { + identifiers.push(id); } - ApplicationIdentifier::Title => {} - }, + } SocketMessage::ManageFocusedWindow => { self.manage_focused_window()?; } diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index 4e28ee0f..1cfe143e 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -15,8 +15,7 @@ use crate::window_manager::WindowManager; use crate::window_manager_event::WindowManagerEvent; use crate::windows_api::WindowsApi; use crate::HIDDEN_HWNDS; -use crate::TRAY_AND_MULTI_WINDOW_CLASSES; -use crate::TRAY_AND_MULTI_WINDOW_EXES; +use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS; #[tracing::instrument] pub fn listen_for_events(wm: Arc>) { @@ -110,15 +109,16 @@ impl WindowManager { // and will have is_window() return true, as the process is still running even if // the window is not visible. { - let tray_and_multi_window_exes = TRAY_AND_MULTI_WINDOW_EXES.lock(); - let tray_and_multi_window_classes = TRAY_AND_MULTI_WINDOW_CLASSES.lock(); + let tray_and_multi_window_identifiers = + TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock(); // We don't want to purge windows that have been deliberately hidden by us, eg. when // they are not on the top of a container stack. let programmatically_hidden_hwnds = HIDDEN_HWNDS.lock(); - if (!window.is_window() || tray_and_multi_window_exes.contains(&window.exe()?)) - || tray_and_multi_window_classes.contains(&window.class()?) + if (!window.is_window() + || tray_and_multi_window_identifiers.contains(&window.exe()?)) + || tray_and_multi_window_identifiers.contains(&window.class()?) && !programmatically_hidden_hwnds.contains(&window.hwnd) { hide = true; diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index 4868333a..253fd501 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -15,6 +15,7 @@ use crate::styles::GwlExStyle; use crate::styles::GwlStyle; use crate::window_manager_event::WindowManagerEvent; use crate::windows_api::WindowsApi; +use crate::BORDER_OVERFLOW_IDENTIFIERS; use crate::FLOAT_IDENTIFIERS; use crate::HIDDEN_HWNDS; use crate::LAYERED_EXE_WHITELIST; @@ -107,18 +108,31 @@ impl Window { // }; let mut rect = *layout; - let border = Rect { - left: 12, - top: 0, - right: 24, - bottom: 12, - }; - // Remove the invisible border - rect.left -= border.left; - rect.top -= border.top; - rect.right += border.right; - rect.bottom += border.bottom; + let mut should_remove_border = true; + + let border_overflows = BORDER_OVERFLOW_IDENTIFIERS.lock(); + if border_overflows.contains(&self.title()?) + || border_overflows.contains(&self.exe()?) + || border_overflows.contains(&self.class()?) + { + should_remove_border = false; + } + + if should_remove_border { + let border = Rect { + left: 12, + top: 0, + right: 24, + bottom: 12, + }; + + // Remove the invisible border + rect.left -= border.left; + rect.top -= border.top; + rect.right += border.right; + rect.bottom += border.bottom; + } WindowsApi::position_window(self.hwnd(), &rect, top) } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 7eb11fbb..43289152 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -32,11 +32,11 @@ use crate::window_manager_event::WindowManagerEvent; use crate::windows_api::WindowsApi; use crate::winevent_listener::WINEVENT_CALLBACK_CHANNEL; use crate::workspace::Workspace; +use crate::BORDER_OVERFLOW_IDENTIFIERS; use crate::FLOAT_IDENTIFIERS; use crate::LAYERED_EXE_WHITELIST; use crate::MANAGE_IDENTIFIERS; -use crate::TRAY_AND_MULTI_WINDOW_CLASSES; -use crate::TRAY_AND_MULTI_WINDOW_EXES; +use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS; use crate::WORKSPACE_RULES; #[derive(Debug)] @@ -60,8 +60,8 @@ pub struct State { pub float_identifiers: Vec, pub manage_identifiers: Vec, pub layered_exe_whitelist: Vec, - pub tray_and_multi_window_exes: Vec, - pub tray_and_multi_window_classes: Vec, + pub tray_and_multi_window_identifiers: Vec, + pub border_overflow_identifiers: Vec, } #[allow(clippy::fallible_impl_from)] @@ -75,8 +75,8 @@ impl From<&mut WindowManager> for State { float_identifiers: FLOAT_IDENTIFIERS.lock().clone(), manage_identifiers: MANAGE_IDENTIFIERS.lock().clone(), layered_exe_whitelist: LAYERED_EXE_WHITELIST.lock().clone(), - tray_and_multi_window_exes: TRAY_AND_MULTI_WINDOW_EXES.lock().clone(), - tray_and_multi_window_classes: TRAY_AND_MULTI_WINDOW_CLASSES.lock().clone(), + tray_and_multi_window_identifiers: TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock().clone(), + border_overflow_identifiers: BORDER_OVERFLOW_IDENTIFIERS.lock().clone(), } } } diff --git a/komorebic.lib.sample.ahk b/komorebic.lib.sample.ahk index 157d836e..b351166f 100644 --- a/komorebic.lib.sample.ahk +++ b/komorebic.lib.sample.ahk @@ -176,6 +176,10 @@ IdentifyTrayApplication(identifier, id) { Run, komorebic.exe identify-tray-application %identifier% %id%, , Hide } +IdentifyBorderOverflow(identifier, id) { + Run, komorebic.exe identify-border-overflow %identifier% %id%, , Hide +} + FocusFollowsMouse(boolean_state, implementation) { Run, komorebic.exe focus-follows-mouse %boolean_state% --implementation %implementation%, , Hide } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 8e8a5532..cf6a4809 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -219,6 +219,7 @@ gen_application_target_subcommand_args! { FloatRule, ManageRule, IdentifyTrayApplication, + IdentifyBorderOverflow, } #[derive(Clap, AhkFunction)] @@ -371,6 +372,9 @@ enum SubCommand { /// Identify an application that closes to the system tray #[clap(setting = AppSettings::ArgRequiredElseHelp)] IdentifyTrayApplication(IdentifyTrayApplication), + /// Identify an application that has overflowing borders + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + IdentifyBorderOverflow(IdentifyBorderOverflow), /// Enable or disable focus follows mouse for the operating system #[clap(setting = AppSettings::ArgRequiredElseHelp)] FocusFollowsMouse(FocusFollowsMouse), @@ -701,6 +705,11 @@ fn main() -> Result<()> { .as_bytes()?, )?; } + SubCommand::IdentifyBorderOverflow(target) => { + send_message( + &*SocketMessage::IdentifyBorderOverflow(target.identifier, target.id).as_bytes()?, + )?; + } SubCommand::Manage => { send_message(&*SocketMessage::ManageFocusedWindow.as_bytes()?)?; }