mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-04-25 01:58:51 +02:00
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
This commit is contained in:
@@ -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
|
manage-rule Add a rule to always manage the specified application
|
||||||
workspace-rule Add a rule to associate an application with a workspace
|
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-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
|
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
|
toggle-focus-follows-mouse Toggle focus follows mouse for the operating system
|
||||||
ahk-library Generate a library of AutoHotKey helper functions
|
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] Floating rules based on exe name, window title and class
|
||||||
- [x] Workspace rules based on exe name and window class
|
- [x] Workspace rules based on exe name and window class
|
||||||
- [x] Additional manage 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] Identify 'close/minimize to tray' applications by exe name and class
|
||||||
- [x] Toggle floating windows
|
- [x] Toggle floating windows
|
||||||
- [x] Toggle monocle window
|
- [x] Toggle monocle window
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ pub enum SocketMessage {
|
|||||||
FloatRule(ApplicationIdentifier, String),
|
FloatRule(ApplicationIdentifier, String),
|
||||||
ManageRule(ApplicationIdentifier, String),
|
ManageRule(ApplicationIdentifier, String),
|
||||||
IdentifyTrayApplication(ApplicationIdentifier, String),
|
IdentifyTrayApplication(ApplicationIdentifier, String),
|
||||||
|
IdentifyBorderOverflow(ApplicationIdentifier, String),
|
||||||
State,
|
State,
|
||||||
Query(StateQuery),
|
Query(StateQuery),
|
||||||
FocusFollowsMouse(FocusFollowsMouseImplementation, bool),
|
FocusFollowsMouse(FocusFollowsMouseImplementation, bool),
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ Run, komorebic.exe manage-rule exe TIM.exe, , Hide
|
|||||||
; Identify applications that close to the tray
|
; Identify applications that close to the tray
|
||||||
Run, komorebic.exe identify-tray-application exe Discord.exe, , Hide
|
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
|
; Change the focused window, Alt + Vim direction keys
|
||||||
!h::
|
!h::
|
||||||
Run, komorebic.exe focus left, , Hide
|
Run, komorebic.exe focus left, , Hide
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ FloatRule("exe", "Wox.exe")
|
|||||||
IdentifyTrayApplication("exe", "Discord.exe")
|
IdentifyTrayApplication("exe", "Discord.exe")
|
||||||
IdentifyTrayApplication("exe", "Spotify.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
|
; Change the focused window, Alt + Vim direction keys
|
||||||
!h::
|
!h::
|
||||||
Focus("left")
|
Focus("left")
|
||||||
|
|||||||
@@ -53,16 +53,15 @@ lazy_static! {
|
|||||||
static ref HIDDEN_HWNDS: Arc<Mutex<Vec<isize>>> = Arc::new(Mutex::new(vec![]));
|
static ref HIDDEN_HWNDS: Arc<Mutex<Vec<isize>>> = Arc::new(Mutex::new(vec![]));
|
||||||
static ref LAYERED_EXE_WHITELIST: Arc<Mutex<Vec<String>>> =
|
static ref LAYERED_EXE_WHITELIST: Arc<Mutex<Vec<String>>> =
|
||||||
Arc::new(Mutex::new(vec!["steam.exe".to_string()]));
|
Arc::new(Mutex::new(vec!["steam.exe".to_string()]));
|
||||||
static ref TRAY_AND_MULTI_WINDOW_CLASSES: Arc<Mutex<Vec<String>>> =
|
static ref TRAY_AND_MULTI_WINDOW_IDENTIFIERS: Arc<Mutex<Vec<String>>> =
|
||||||
Arc::new(Mutex::new(vec![]));
|
Arc::new(Mutex::new(vec![
|
||||||
static ref TRAY_AND_MULTI_WINDOW_EXES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
|
"explorer.exe".to_string(),
|
||||||
"explorer.exe".to_string(),
|
"firefox.exe".to_string(),
|
||||||
"firefox.exe".to_string(),
|
"chrome.exe".to_string(),
|
||||||
"chrome.exe".to_string(),
|
"idea64.exe".to_string(),
|
||||||
"idea64.exe".to_string(),
|
"ApplicationFrameHost.exe".to_string(),
|
||||||
"ApplicationFrameHost.exe".to_string(),
|
"steam.exe".to_string(),
|
||||||
"steam.exe".to_string(),
|
]));
|
||||||
]));
|
|
||||||
static ref OBJECT_NAME_CHANGE_ON_LAUNCH: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
|
static ref OBJECT_NAME_CHANGE_ON_LAUNCH: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
|
||||||
"firefox.exe".to_string(),
|
"firefox.exe".to_string(),
|
||||||
"idea64.exe".to_string(),
|
"idea64.exe".to_string(),
|
||||||
@@ -71,6 +70,7 @@ lazy_static! {
|
|||||||
Arc::new(Mutex::new(HashMap::new()));
|
Arc::new(Mutex::new(HashMap::new()));
|
||||||
static ref MANAGE_IDENTIFIERS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
|
static ref MANAGE_IDENTIFIERS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
|
||||||
static ref FLOAT_IDENTIFIERS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
|
static ref FLOAT_IDENTIFIERS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
|
||||||
|
static ref BORDER_OVERFLOW_IDENTIFIERS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup() -> Result<(WorkerGuard, WorkerGuard)> {
|
fn setup() -> Result<(WorkerGuard, WorkerGuard)> {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ use color_eyre::Result;
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use uds_windows::UnixStream;
|
use uds_windows::UnixStream;
|
||||||
|
|
||||||
use komorebi_core::ApplicationIdentifier;
|
|
||||||
use komorebi_core::FocusFollowsMouseImplementation;
|
use komorebi_core::FocusFollowsMouseImplementation;
|
||||||
use komorebi_core::SocketMessage;
|
use komorebi_core::SocketMessage;
|
||||||
use komorebi_core::StateQuery;
|
use komorebi_core::StateQuery;
|
||||||
@@ -18,10 +17,10 @@ use komorebi_core::StateQuery;
|
|||||||
use crate::window_manager;
|
use crate::window_manager;
|
||||||
use crate::window_manager::WindowManager;
|
use crate::window_manager::WindowManager;
|
||||||
use crate::windows_api::WindowsApi;
|
use crate::windows_api::WindowsApi;
|
||||||
|
use crate::BORDER_OVERFLOW_IDENTIFIERS;
|
||||||
use crate::FLOAT_IDENTIFIERS;
|
use crate::FLOAT_IDENTIFIERS;
|
||||||
use crate::MANAGE_IDENTIFIERS;
|
use crate::MANAGE_IDENTIFIERS;
|
||||||
use crate::TRAY_AND_MULTI_WINDOW_CLASSES;
|
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||||
use crate::TRAY_AND_MULTI_WINDOW_EXES;
|
|
||||||
use crate::WORKSPACE_RULES;
|
use crate::WORKSPACE_RULES;
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
@@ -295,21 +294,18 @@ impl WindowManager {
|
|||||||
SocketMessage::WatchConfiguration(enable) => {
|
SocketMessage::WatchConfiguration(enable) => {
|
||||||
self.watch_configuration(enable)?;
|
self.watch_configuration(enable)?;
|
||||||
}
|
}
|
||||||
SocketMessage::IdentifyTrayApplication(identifier, id) => match identifier {
|
SocketMessage::IdentifyBorderOverflow(_, id) => {
|
||||||
ApplicationIdentifier::Exe => {
|
let mut identifiers = BORDER_OVERFLOW_IDENTIFIERS.lock();
|
||||||
let mut exes = TRAY_AND_MULTI_WINDOW_EXES.lock();
|
if !identifiers.contains(&id) {
|
||||||
if !exes.contains(&id) {
|
identifiers.push(id);
|
||||||
exes.push(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ApplicationIdentifier::Class => {
|
}
|
||||||
let mut classes = TRAY_AND_MULTI_WINDOW_CLASSES.lock();
|
SocketMessage::IdentifyTrayApplication(_, id) => {
|
||||||
if !classes.contains(&id) {
|
let mut identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock();
|
||||||
classes.push(id);
|
if !identifiers.contains(&id) {
|
||||||
}
|
identifiers.push(id);
|
||||||
}
|
}
|
||||||
ApplicationIdentifier::Title => {}
|
}
|
||||||
},
|
|
||||||
SocketMessage::ManageFocusedWindow => {
|
SocketMessage::ManageFocusedWindow => {
|
||||||
self.manage_focused_window()?;
|
self.manage_focused_window()?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ use crate::window_manager::WindowManager;
|
|||||||
use crate::window_manager_event::WindowManagerEvent;
|
use crate::window_manager_event::WindowManagerEvent;
|
||||||
use crate::windows_api::WindowsApi;
|
use crate::windows_api::WindowsApi;
|
||||||
use crate::HIDDEN_HWNDS;
|
use crate::HIDDEN_HWNDS;
|
||||||
use crate::TRAY_AND_MULTI_WINDOW_CLASSES;
|
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||||
use crate::TRAY_AND_MULTI_WINDOW_EXES;
|
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) {
|
pub fn listen_for_events(wm: Arc<Mutex<WindowManager>>) {
|
||||||
@@ -110,15 +109,16 @@ impl WindowManager {
|
|||||||
// and will have is_window() return true, as the process is still running even if
|
// and will have is_window() return true, as the process is still running even if
|
||||||
// the window is not visible.
|
// the window is not visible.
|
||||||
{
|
{
|
||||||
let tray_and_multi_window_exes = TRAY_AND_MULTI_WINDOW_EXES.lock();
|
let tray_and_multi_window_identifiers =
|
||||||
let tray_and_multi_window_classes = TRAY_AND_MULTI_WINDOW_CLASSES.lock();
|
TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock();
|
||||||
|
|
||||||
// We don't want to purge windows that have been deliberately hidden by us, eg. when
|
// 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.
|
// they are not on the top of a container stack.
|
||||||
let programmatically_hidden_hwnds = HIDDEN_HWNDS.lock();
|
let programmatically_hidden_hwnds = HIDDEN_HWNDS.lock();
|
||||||
|
|
||||||
if (!window.is_window() || tray_and_multi_window_exes.contains(&window.exe()?))
|
if (!window.is_window()
|
||||||
|| tray_and_multi_window_classes.contains(&window.class()?)
|
|| tray_and_multi_window_identifiers.contains(&window.exe()?))
|
||||||
|
|| tray_and_multi_window_identifiers.contains(&window.class()?)
|
||||||
&& !programmatically_hidden_hwnds.contains(&window.hwnd)
|
&& !programmatically_hidden_hwnds.contains(&window.hwnd)
|
||||||
{
|
{
|
||||||
hide = true;
|
hide = true;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use crate::styles::GwlExStyle;
|
|||||||
use crate::styles::GwlStyle;
|
use crate::styles::GwlStyle;
|
||||||
use crate::window_manager_event::WindowManagerEvent;
|
use crate::window_manager_event::WindowManagerEvent;
|
||||||
use crate::windows_api::WindowsApi;
|
use crate::windows_api::WindowsApi;
|
||||||
|
use crate::BORDER_OVERFLOW_IDENTIFIERS;
|
||||||
use crate::FLOAT_IDENTIFIERS;
|
use crate::FLOAT_IDENTIFIERS;
|
||||||
use crate::HIDDEN_HWNDS;
|
use crate::HIDDEN_HWNDS;
|
||||||
use crate::LAYERED_EXE_WHITELIST;
|
use crate::LAYERED_EXE_WHITELIST;
|
||||||
@@ -107,18 +108,31 @@ impl Window {
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
let mut rect = *layout;
|
let mut rect = *layout;
|
||||||
let border = Rect {
|
|
||||||
left: 12,
|
|
||||||
top: 0,
|
|
||||||
right: 24,
|
|
||||||
bottom: 12,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove the invisible border
|
let mut should_remove_border = true;
|
||||||
rect.left -= border.left;
|
|
||||||
rect.top -= border.top;
|
let border_overflows = BORDER_OVERFLOW_IDENTIFIERS.lock();
|
||||||
rect.right += border.right;
|
if border_overflows.contains(&self.title()?)
|
||||||
rect.bottom += border.bottom;
|
|| 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)
|
WindowsApi::position_window(self.hwnd(), &rect, top)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ use crate::window_manager_event::WindowManagerEvent;
|
|||||||
use crate::windows_api::WindowsApi;
|
use crate::windows_api::WindowsApi;
|
||||||
use crate::winevent_listener::WINEVENT_CALLBACK_CHANNEL;
|
use crate::winevent_listener::WINEVENT_CALLBACK_CHANNEL;
|
||||||
use crate::workspace::Workspace;
|
use crate::workspace::Workspace;
|
||||||
|
use crate::BORDER_OVERFLOW_IDENTIFIERS;
|
||||||
use crate::FLOAT_IDENTIFIERS;
|
use crate::FLOAT_IDENTIFIERS;
|
||||||
use crate::LAYERED_EXE_WHITELIST;
|
use crate::LAYERED_EXE_WHITELIST;
|
||||||
use crate::MANAGE_IDENTIFIERS;
|
use crate::MANAGE_IDENTIFIERS;
|
||||||
use crate::TRAY_AND_MULTI_WINDOW_CLASSES;
|
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||||
use crate::TRAY_AND_MULTI_WINDOW_EXES;
|
|
||||||
use crate::WORKSPACE_RULES;
|
use crate::WORKSPACE_RULES;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -60,8 +60,8 @@ pub struct State {
|
|||||||
pub float_identifiers: Vec<String>,
|
pub float_identifiers: Vec<String>,
|
||||||
pub manage_identifiers: Vec<String>,
|
pub manage_identifiers: Vec<String>,
|
||||||
pub layered_exe_whitelist: Vec<String>,
|
pub layered_exe_whitelist: Vec<String>,
|
||||||
pub tray_and_multi_window_exes: Vec<String>,
|
pub tray_and_multi_window_identifiers: Vec<String>,
|
||||||
pub tray_and_multi_window_classes: Vec<String>,
|
pub border_overflow_identifiers: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::fallible_impl_from)]
|
#[allow(clippy::fallible_impl_from)]
|
||||||
@@ -75,8 +75,8 @@ impl From<&mut WindowManager> for State {
|
|||||||
float_identifiers: FLOAT_IDENTIFIERS.lock().clone(),
|
float_identifiers: FLOAT_IDENTIFIERS.lock().clone(),
|
||||||
manage_identifiers: MANAGE_IDENTIFIERS.lock().clone(),
|
manage_identifiers: MANAGE_IDENTIFIERS.lock().clone(),
|
||||||
layered_exe_whitelist: LAYERED_EXE_WHITELIST.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_identifiers: TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock().clone(),
|
||||||
tray_and_multi_window_classes: TRAY_AND_MULTI_WINDOW_CLASSES.lock().clone(),
|
border_overflow_identifiers: BORDER_OVERFLOW_IDENTIFIERS.lock().clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,6 +176,10 @@ IdentifyTrayApplication(identifier, id) {
|
|||||||
Run, komorebic.exe identify-tray-application %identifier% %id%, , Hide
|
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) {
|
FocusFollowsMouse(boolean_state, implementation) {
|
||||||
Run, komorebic.exe focus-follows-mouse %boolean_state% --implementation %implementation%, , Hide
|
Run, komorebic.exe focus-follows-mouse %boolean_state% --implementation %implementation%, , Hide
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ gen_application_target_subcommand_args! {
|
|||||||
FloatRule,
|
FloatRule,
|
||||||
ManageRule,
|
ManageRule,
|
||||||
IdentifyTrayApplication,
|
IdentifyTrayApplication,
|
||||||
|
IdentifyBorderOverflow,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clap, AhkFunction)]
|
#[derive(Clap, AhkFunction)]
|
||||||
@@ -371,6 +372,9 @@ enum SubCommand {
|
|||||||
/// Identify an application that closes to the system tray
|
/// Identify an application that closes to the system tray
|
||||||
#[clap(setting = AppSettings::ArgRequiredElseHelp)]
|
#[clap(setting = AppSettings::ArgRequiredElseHelp)]
|
||||||
IdentifyTrayApplication(IdentifyTrayApplication),
|
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
|
/// Enable or disable focus follows mouse for the operating system
|
||||||
#[clap(setting = AppSettings::ArgRequiredElseHelp)]
|
#[clap(setting = AppSettings::ArgRequiredElseHelp)]
|
||||||
FocusFollowsMouse(FocusFollowsMouse),
|
FocusFollowsMouse(FocusFollowsMouse),
|
||||||
@@ -701,6 +705,11 @@ fn main() -> Result<()> {
|
|||||||
.as_bytes()?,
|
.as_bytes()?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
SubCommand::IdentifyBorderOverflow(target) => {
|
||||||
|
send_message(
|
||||||
|
&*SocketMessage::IdentifyBorderOverflow(target.identifier, target.id).as_bytes()?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
SubCommand::Manage => {
|
SubCommand::Manage => {
|
||||||
send_message(&*SocketMessage::ManageFocusedWindow.as_bytes()?)?;
|
send_message(&*SocketMessage::ManageFocusedWindow.as_bytes()?)?;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user