diff --git a/Cargo.lock b/Cargo.lock index 2f13512b..00bd202d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -813,6 +813,7 @@ dependencies = [ "os_info", "parking_lot", "paste", + "regex", "schemars", "serde", "serde_json", diff --git a/komorebi.generated.ahk b/komorebi.generated.ahk index 79ca7717..aeb8fcbc 100644 --- a/komorebi.generated.ahk +++ b/komorebi.generated.ahk @@ -27,6 +27,10 @@ RunWait('komorebic.exe identify-tray-application exe "Akiflow.exe"', , "Hide") ; Android Studio RunWait('komorebic.exe identify-object-name-change-application exe "studio64.exe"', , "Hide") +; Anki +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "anki.exe"', , "Hide") + ; ArmCord RunWait('komorebic.exe identify-border-overflow-application exe "ArmCord.exe"', , "Hide") ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line @@ -36,6 +40,7 @@ RunWait('komorebic.exe identify-tray-application exe "ArmCord.exe"', , "Hide") ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line RunWait('komorebic.exe identify-tray-application exe "AutoHotkeyU64.exe"', , "Hide") RunWait('komorebic.exe float-rule title "Window Spy"', , "Hide") +RunWait('komorebic.exe float-rule exe "AutoHotkeyUX.exe"', , "Hide") ; Beeper RunWait('komorebic.exe identify-border-overflow-application exe "Beeper.exe"', , "Hide") @@ -52,6 +57,19 @@ RunWait('komorebic.exe float-rule exe "Bloxstrap.exe"', , "Hide") ; Calculator RunWait('komorebic.exe float-rule title "Calculator"', , "Hide") +; Clash Verge +RunWait('komorebic.exe identify-border-overflow-application exe "Clash Verge.exe"', , "Hide") +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "Clash Verge.exe"', , "Hide") + +; Clementine +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "clementine.exe"', , "Hide") + +; CopyQ +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "copyq.exe"', , "Hide") + ; Credential Manager UI Host ; Targets the Windows popup prompting you for a PIN instead of a password on 1Password etc. RunWait('komorebic.exe float-rule exe "CredentialUIBroker.exe"', , "Hide") @@ -91,6 +109,9 @@ RunWait('komorebic.exe identify-border-overflow-application exe "DiscordPTB.exe" ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line RunWait('komorebic.exe identify-tray-application exe "DiscordPTB.exe"', , "Hide") +; Docker Desktop +RunWait('komorebic.exe identify-border-overflow-application exe "Docker Desktop.exe"', , "Hide") + ; Dropbox RunWait('komorebic.exe float-rule exe "Dropbox.exe"', , "Hide") @@ -123,6 +144,13 @@ RunWait('komorebic.exe identify-border-overflow-application exe "EpicGamesLaunch ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line RunWait('komorebic.exe identify-tray-application exe "EpicGamesLauncher.exe"', , "Hide") +; Everything +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "Everything.exe"', , "Hide") + +; Figma +RunWait('komorebic.exe identify-border-overflow-application exe "Figma.exe"', , "Hide") + ; Flow Launcher RunWait('komorebic.exe identify-border-overflow-application exe "Flow.Launcher.exe"', , "Hide") @@ -143,11 +171,17 @@ RunWait('komorebic.exe identify-border-overflow-application exe "GodotManager.ex RunWait('komorebic.exe manage-rule exe "GodotManager.exe"', , "Hide") RunWait('komorebic.exe identify-object-name-change-application exe "GodotManager.exe"', , "Hide") +; Golden Dict +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "GoldenDict.exe"', , "Hide") + ; Google Chrome ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line RunWait('komorebic.exe identify-tray-application exe "chrome.exe"', , "Hide") ; Google Drive +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "GoogleDriveFS.exe"', , "Hide") RunWait('komorebic.exe float-rule exe "GoogleDriveFS.exe"', , "Hide") ; Houdoku @@ -256,6 +290,10 @@ RunWait('komorebic.exe identify-border-overflow-application exe "NVIDIA GeForce ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line RunWait('komorebic.exe identify-tray-application exe "NZXT CAM.exe"', , "Hide") +; NetEase Cloud Music +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "cloudmusic.exe"', , "Hide") + ; NiceHash Miner RunWait('komorebic.exe identify-border-overflow-application exe "nhm_app.exe"', , "Hide") RunWait('komorebic.exe manage-rule exe "nhm_app.exe"', , "Hide") @@ -288,6 +326,10 @@ RunWait('komorebic.exe manage-rule exe "Obsidian.exe"', , "Hide") ; OneDrive RunWait('komorebic.exe float-rule class "OneDriveReactNativeWin32WindowClass"', , "Hide") +; OneQuick +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "OneQuick.exe"', , "Hide") + ; OpenRGB ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line RunWait('komorebic.exe identify-tray-application exe "OpenRGB.exe"', , "Hide") @@ -295,6 +337,13 @@ RunWait('komorebic.exe identify-tray-application exe "OpenRGB.exe"', , "Hide") ; Paradox Launcher RunWait('komorebic.exe float-rule exe "Paradox Launcher.exe"', , "Hide") +; Playnite +RunWait('komorebic.exe identify-border-overflow-application exe "Playnite.DesktopApp.exe"', , "Hide") +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "Playnite.DesktopApp.exe"', , "Hide") +; Target fullscreen app +RunWait('komorebic.exe float-rule exe "Playnite.FullscreenApp.exe"', , "Hide") + ; Plexamp RunWait('komorebic.exe identify-border-overflow-application exe "Plexamp.exe"', , "Hide") @@ -321,6 +370,13 @@ RunWait('komorebic.exe identify-object-name-change-application exe "pycharm64.ex ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line RunWait('komorebic.exe identify-tray-application exe "pycharm64.exe"', , "Hide") +; QQ +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "QQ.exe"', , "Hide") +RunWait('komorebic.exe float-rule title "图片查看器"', , "Hide") +RunWait('komorebic.exe float-rule title "群聊的聊天记录"', , "Hide") +RunWait('komorebic.exe float-rule title "语音通话"', , "Hide") + ; QtScrcpy ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line RunWait('komorebic.exe identify-tray-application exe "QtScrcpy.exe"', , "Hide") @@ -348,6 +404,15 @@ RunWait('komorebic.exe identify-border-overflow-application exe "RoundedTB.exe"' ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line RunWait('komorebic.exe identify-tray-application exe "RoundedTB.exe"', , "Hide") +; RustRover +RunWait('komorebic.exe identify-object-name-change-application exe "rustrover64.exe"', , "Hide") +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "rustrover64.exe"', , "Hide") + +; Sandboxie Plus +; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +RunWait('komorebic.exe identify-tray-application exe "SandMan.exe"', , "Hide") + ; ShareX RunWait('komorebic.exe identify-border-overflow-application exe "ShareX.exe"', , "Hide") ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line @@ -358,7 +423,7 @@ RunWait('komorebic.exe float-rule exe "sideloadly.exe"', , "Hide") ; Signal ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line -RunWait('komorebic.exe identify-tray-application exe "signal.exe"', , "Hide") +RunWait('komorebic.exe identify-tray-application exe "Signal.exe"', , "Hide") ; SiriKali ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line @@ -484,6 +549,10 @@ RunWait('komorebic.exe float-rule title "Control Panel"', , "Hide") ; Windows Installer RunWait('komorebic.exe float-rule exe "msiexec.exe"', , "Hide") +; Windows Subsystem for Android +; Targets splash/startup screen +RunWait('komorebic.exe float-rule class "android(splash)"', , "Hide") + ; WingetUI ; If you have disabled minimize/close to tray for this application, you can delete/comment out the next line RunWait('komorebic.exe identify-tray-application exe "WingetUI.exe"', , "Hide") @@ -503,6 +572,9 @@ RunWait('komorebic.exe identify-tray-application exe "xampp-control.exe"', , "Hi ; Zoom RunWait('komorebic.exe float-rule exe "Zoom.exe"', , "Hide") +; mpv +RunWait('komorebic.exe identify-object-name-change-application class "mpv"', , "Hide") + ; mpv.net RunWait('komorebic.exe identify-object-name-change-application exe "mpvnet.exe"', , "Hide") diff --git a/komorebi.generated.ps1 b/komorebi.generated.ps1 index b3046c46..8787a5c4 100644 --- a/komorebi.generated.ps1 +++ b/komorebi.generated.ps1 @@ -27,6 +27,10 @@ komorebic.exe identify-tray-application exe "Akiflow.exe" # Android Studio komorebic.exe identify-object-name-change-application exe "studio64.exe" +# Anki +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "anki.exe" + # ArmCord komorebic.exe identify-border-overflow-application exe "ArmCord.exe" # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line @@ -36,6 +40,7 @@ komorebic.exe identify-tray-application exe "ArmCord.exe" # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line komorebic.exe identify-tray-application exe "AutoHotkeyU64.exe" komorebic.exe float-rule title "Window Spy" +komorebic.exe float-rule exe "AutoHotkeyUX.exe" # Beeper komorebic.exe identify-border-overflow-application exe "Beeper.exe" @@ -52,6 +57,19 @@ komorebic.exe float-rule exe "Bloxstrap.exe" # Calculator komorebic.exe float-rule title "Calculator" +# Clash Verge +komorebic.exe identify-border-overflow-application exe "Clash Verge.exe" +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "Clash Verge.exe" + +# Clementine +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "clementine.exe" + +# CopyQ +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "copyq.exe" + # Credential Manager UI Host # Targets the Windows popup prompting you for a PIN instead of a password on 1Password etc. komorebic.exe float-rule exe "CredentialUIBroker.exe" @@ -91,6 +109,9 @@ komorebic.exe identify-border-overflow-application exe "DiscordPTB.exe" # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line komorebic.exe identify-tray-application exe "DiscordPTB.exe" +# Docker Desktop +komorebic.exe identify-border-overflow-application exe "Docker Desktop.exe" + # Dropbox komorebic.exe float-rule exe "Dropbox.exe" @@ -123,6 +144,13 @@ komorebic.exe identify-border-overflow-application exe "EpicGamesLauncher.exe" # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line komorebic.exe identify-tray-application exe "EpicGamesLauncher.exe" +# Everything +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "Everything.exe" + +# Figma +komorebic.exe identify-border-overflow-application exe "Figma.exe" + # Flow Launcher komorebic.exe identify-border-overflow-application exe "Flow.Launcher.exe" @@ -143,11 +171,17 @@ komorebic.exe identify-border-overflow-application exe "GodotManager.exe" komorebic.exe manage-rule exe "GodotManager.exe" komorebic.exe identify-object-name-change-application exe "GodotManager.exe" +# Golden Dict +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "GoldenDict.exe" + # Google Chrome # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line komorebic.exe identify-tray-application exe "chrome.exe" # Google Drive +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "GoogleDriveFS.exe" komorebic.exe float-rule exe "GoogleDriveFS.exe" # Houdoku @@ -256,6 +290,10 @@ komorebic.exe identify-border-overflow-application exe "NVIDIA GeForce Experienc # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line komorebic.exe identify-tray-application exe "NZXT CAM.exe" +# NetEase Cloud Music +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "cloudmusic.exe" + # NiceHash Miner komorebic.exe identify-border-overflow-application exe "nhm_app.exe" komorebic.exe manage-rule exe "nhm_app.exe" @@ -288,6 +326,10 @@ komorebic.exe manage-rule exe "Obsidian.exe" # OneDrive komorebic.exe float-rule class "OneDriveReactNativeWin32WindowClass" +# OneQuick +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "OneQuick.exe" + # OpenRGB # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line komorebic.exe identify-tray-application exe "OpenRGB.exe" @@ -295,6 +337,13 @@ komorebic.exe identify-tray-application exe "OpenRGB.exe" # Paradox Launcher komorebic.exe float-rule exe "Paradox Launcher.exe" +# Playnite +komorebic.exe identify-border-overflow-application exe "Playnite.DesktopApp.exe" +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "Playnite.DesktopApp.exe" +# Target fullscreen app +komorebic.exe float-rule exe "Playnite.FullscreenApp.exe" + # Plexamp komorebic.exe identify-border-overflow-application exe "Plexamp.exe" @@ -321,6 +370,13 @@ komorebic.exe identify-object-name-change-application exe "pycharm64.exe" # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line komorebic.exe identify-tray-application exe "pycharm64.exe" +# QQ +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "QQ.exe" +komorebic.exe float-rule title "图片查看器" +komorebic.exe float-rule title "群聊的聊天记录" +komorebic.exe float-rule title "语音通话" + # QtScrcpy # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line komorebic.exe identify-tray-application exe "QtScrcpy.exe" @@ -348,6 +404,15 @@ komorebic.exe identify-border-overflow-application exe "RoundedTB.exe" # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line komorebic.exe identify-tray-application exe "RoundedTB.exe" +# RustRover +komorebic.exe identify-object-name-change-application exe "rustrover64.exe" +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "rustrover64.exe" + +# Sandboxie Plus +# If you have disabled minimize/close to tray for this application, you can delete/comment out the next line +komorebic.exe identify-tray-application exe "SandMan.exe" + # ShareX komorebic.exe identify-border-overflow-application exe "ShareX.exe" # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line @@ -358,7 +423,7 @@ komorebic.exe float-rule exe "sideloadly.exe" # Signal # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line -komorebic.exe identify-tray-application exe "signal.exe" +komorebic.exe identify-tray-application exe "Signal.exe" # SiriKali # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line @@ -484,6 +549,10 @@ komorebic.exe float-rule title "Control Panel" # Windows Installer komorebic.exe float-rule exe "msiexec.exe" +# Windows Subsystem for Android +# Targets splash/startup screen +komorebic.exe float-rule class "android(splash)" + # WingetUI # If you have disabled minimize/close to tray for this application, you can delete/comment out the next line komorebic.exe identify-tray-application exe "WingetUI.exe" @@ -503,6 +572,9 @@ komorebic.exe identify-tray-application exe "xampp-control.exe" # Zoom komorebic.exe float-rule exe "Zoom.exe" +# mpv +komorebic.exe identify-object-name-change-application class "mpv" + # mpv.net komorebic.exe identify-object-name-change-application exe "mpvnet.exe" diff --git a/komorebi/Cargo.toml b/komorebi/Cargo.toml index 08162b4f..206bf416 100644 --- a/komorebi/Cargo.toml +++ b/komorebi/Cargo.toml @@ -29,6 +29,7 @@ net2 = "0.2" os_info = "3.7" parking_lot = { version = "0.12", features = ["deadlock_detection"] } paste = "1" +regex = "1" schemars = "0.8" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/komorebi/src/border.rs b/komorebi/src/border.rs index f39bd5c6..466cf8ca 100644 --- a/komorebi/src/border.rs +++ b/komorebi/src/border.rs @@ -14,6 +14,7 @@ use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA; use komorebi_core::Rect; +use crate::window::should_act; use crate::window::Window; use crate::windows_callbacks; use crate::WindowsApi; @@ -21,6 +22,7 @@ use crate::BORDER_HWND; use crate::BORDER_OFFSET; use crate::BORDER_OVERFLOW_IDENTIFIERS; use crate::BORDER_RECT; +use crate::REGEX_IDENTIFIERS; use crate::TRANSPARENCY_COLOUR; use crate::WINDOWS_11; @@ -108,19 +110,24 @@ impl Border { Self::create("komorebi-border-window")?; } - let mut should_expand_border = false; - let mut rect = WindowsApi::window_rect(window.hwnd())?; rect.top -= invisible_borders.bottom; rect.bottom += invisible_borders.bottom; let border_overflows = BORDER_OVERFLOW_IDENTIFIERS.lock(); - if border_overflows.contains(&window.title()?) - || border_overflows.contains(&window.exe()?) - || border_overflows.contains(&window.class()?) - { - should_expand_border = true; - } + let regex_identifiers = REGEX_IDENTIFIERS.lock(); + + let title = &window.title()?; + let exe_name = &window.exe()?; + let class = &window.class()?; + + let should_expand_border = should_act( + title, + exe_name, + class, + &border_overflows, + ®ex_identifiers, + ); if should_expand_border { rect.left -= invisible_borders.left; diff --git a/komorebi/src/main.rs b/komorebi/src/main.rs index 96464577..5f402c69 100644 --- a/komorebi/src/main.rs +++ b/komorebi/src/main.rs @@ -32,6 +32,7 @@ use os_info::Version; #[cfg(feature = "deadlock_detection")] use parking_lot::deadlock; use parking_lot::Mutex; +use regex::Regex; use schemars::JsonSchema; use serde::Serialize; use sysinfo::Process; @@ -89,26 +90,65 @@ type WorkspaceRule = (usize, usize, bool); lazy_static! { static ref HIDDEN_HWNDS: Arc>> = Arc::new(Mutex::new(vec![])); - static ref LAYERED_WHITELIST: Arc>> = - Arc::new(Mutex::new(vec!["steam.exe".to_string()])); - static ref TRAY_AND_MULTI_WINDOW_IDENTIFIERS: Arc>> = + static ref LAYERED_WHITELIST: Arc>> = Arc::new(Mutex::new(vec![ + IdWithIdentifier { + kind: ApplicationIdentifier::Exe, + id: String::from("steam.exe"), + matching_strategy: Option::from(MatchingStrategy::Equals), + }, + ])); + 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(), + IdWithIdentifier { + kind: ApplicationIdentifier::Exe, + id: String::from("explorer.exe"), + matching_strategy: Option::from(MatchingStrategy::Equals), + }, + IdWithIdentifier { + kind: ApplicationIdentifier::Exe, + id: String::from("firefox.exe"), + matching_strategy: Option::from(MatchingStrategy::Equals), + }, + IdWithIdentifier { + kind: ApplicationIdentifier::Exe, + id: String::from("chrome.exe"), + matching_strategy: Option::from(MatchingStrategy::Equals), + }, + IdWithIdentifier { + kind: ApplicationIdentifier::Exe, + id: String::from("idea64.exe"), + matching_strategy: Option::from(MatchingStrategy::Equals), + }, + IdWithIdentifier { + kind: ApplicationIdentifier::Exe, + id: String::from("ApplicationFrameHost.exe"), + matching_strategy: Option::from(MatchingStrategy::Equals), + }, + IdWithIdentifier { + kind: ApplicationIdentifier::Exe, + id: String::from("steam.exe"), + matching_strategy: Option::from(MatchingStrategy::Equals), + } ])); - static ref OBJECT_NAME_CHANGE_ON_LAUNCH: Arc>> = Arc::new(Mutex::new(vec![ - "firefox.exe".to_string(), - "idea64.exe".to_string(), + static ref OBJECT_NAME_CHANGE_ON_LAUNCH: Arc>> = Arc::new(Mutex::new(vec![ + IdWithIdentifier { + kind: ApplicationIdentifier::Exe, + id: String::from("firefox.exe"), + matching_strategy: Option::from(MatchingStrategy::Equals), + }, + IdWithIdentifier { + kind: ApplicationIdentifier::Exe, + id: String::from("idea64.exe"), + matching_strategy: Option::from(MatchingStrategy::Equals), + }, ])); static ref MONITOR_INDEX_PREFERENCES: Arc>> = Arc::new(Mutex::new(HashMap::new())); static ref WORKSPACE_RULES: Arc>> = Arc::new(Mutex::new(HashMap::new())); - static ref MANAGE_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![])); + static ref REGEX_IDENTIFIERS: Arc>> = + 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![ // mstsc.exe creates these on Windows 11 when a WSL process is launched // https://github.com/LGUG2Z/komorebi/issues/74 @@ -126,7 +166,7 @@ lazy_static! { static ref PERMAIGNORE_CLASSES: Arc>> = Arc::new(Mutex::new(vec![ "Chrome_RenderWidgetHostHWND".to_string(), ])); - static ref BORDER_OVERFLOW_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![])); + static ref BORDER_OVERFLOW_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![])); static ref WSL2_UI_PROCESSES: Arc>> = Arc::new(Mutex::new(vec![ "X410.exe".to_string(), "vcxsrv.exe".to_string(), diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 6738c46e..1a0539b1 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -240,10 +240,22 @@ impl WindowManager { self.handle_definitive_workspace_rules(id, monitor_idx, workspace_idx)?; } } - SocketMessage::ManageRule(_, ref id) => { + SocketMessage::ManageRule(identifier, ref id) => { let mut manage_identifiers = MANAGE_IDENTIFIERS.lock(); - if !manage_identifiers.contains(id) { - manage_identifiers.push(id.to_string()); + + let mut should_push = true; + for m in &*manage_identifiers { + if m.id.eq(id) { + should_push = false; + } + } + + if should_push { + manage_identifiers.push(IdWithIdentifier { + kind: identifier, + id: id.clone(), + matching_strategy: Option::from(MatchingStrategy::Legacy), + }); } } SocketMessage::FloatRule(identifier, ref id) => { @@ -904,28 +916,75 @@ impl WindowManager { SocketMessage::WatchConfiguration(enable) => { self.watch_configuration(enable)?; } - SocketMessage::IdentifyBorderOverflowApplication(_, ref id) => { + SocketMessage::IdentifyBorderOverflowApplication(identifier, ref id) => { let mut identifiers = BORDER_OVERFLOW_IDENTIFIERS.lock(); - if !identifiers.contains(id) { - identifiers.push(id.to_string()); + + let mut should_push = true; + for i in &*identifiers { + if i.id.eq(id) { + should_push = false; + } + } + + if should_push { + identifiers.push(IdWithIdentifier { + kind: identifier, + id: id.clone(), + matching_strategy: Option::from(MatchingStrategy::Legacy), + }); } } - SocketMessage::IdentifyObjectNameChangeApplication(_, ref id) => { + SocketMessage::IdentifyObjectNameChangeApplication(identifier, ref id) => { let mut identifiers = OBJECT_NAME_CHANGE_ON_LAUNCH.lock(); - if !identifiers.contains(id) { - identifiers.push(id.to_string()); + + let mut should_push = true; + for i in &*identifiers { + if i.id.eq(id) { + should_push = false; + } + } + + if should_push { + identifiers.push(IdWithIdentifier { + kind: identifier, + id: id.clone(), + matching_strategy: Option::from(MatchingStrategy::Legacy), + }); } } - SocketMessage::IdentifyTrayApplication(_, ref id) => { + SocketMessage::IdentifyTrayApplication(identifier, ref id) => { let mut identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock(); - if !identifiers.contains(id) { - identifiers.push(id.to_string()); + let mut should_push = true; + for i in &*identifiers { + if i.id.eq(id) { + should_push = false; + } + } + + if should_push { + identifiers.push(IdWithIdentifier { + kind: identifier, + id: id.clone(), + matching_strategy: Option::from(MatchingStrategy::Legacy), + }); } } - SocketMessage::IdentifyLayeredApplication(_, ref id) => { + SocketMessage::IdentifyLayeredApplication(identifier, ref id) => { let mut identifiers = LAYERED_WHITELIST.lock(); - if !identifiers.contains(id) { - identifiers.push(id.to_string()); + + let mut should_push = true; + for i in &*identifiers { + if i.id.eq(id) { + should_push = false; + } + } + + if should_push { + identifiers.push(IdWithIdentifier { + kind: identifier, + id: id.clone(), + matching_strategy: Option::from(MatchingStrategy::Legacy), + }); } } SocketMessage::ManageFocusedWindow => { diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index 522cbb63..f3ac58d7 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -15,6 +15,7 @@ use komorebi_core::WindowContainerBehaviour; use crate::border::Border; use crate::current_virtual_desktop; use crate::notify_subscribers; +use crate::window::should_act; use crate::window_manager::WindowManager; use crate::window_manager_event::WindowManagerEvent; use crate::windows_api::WindowsApi; @@ -29,6 +30,7 @@ use crate::BORDER_HIDDEN; use crate::BORDER_HWND; use crate::DATA_DIR; use crate::HIDDEN_HWNDS; +use crate::REGEX_IDENTIFIERS; use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS; #[tracing::instrument] @@ -179,15 +181,26 @@ impl WindowManager { { let tray_and_multi_window_identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock(); + let regex_identifiers = REGEX_IDENTIFIERS.lock(); + + let title = &window.title()?; + let exe_name = &window.exe()?; + let class = &window.class()?; // 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(); + let should_act = should_act( + title, + exe_name, + class, + &tray_and_multi_window_identifiers, + ®ex_identifiers, + ); - 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) + if !window.is_window() + || should_act + || !programmatically_hidden_hwnds.contains(&window.hwnd) { hide = true; } diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 13bc869c..b21a28e2 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -24,6 +24,7 @@ use crate::LAYERED_WHITELIST; use crate::MANAGE_IDENTIFIERS; use crate::MONITOR_INDEX_PREFERENCES; use crate::OBJECT_NAME_CHANGE_ON_LAUNCH; +use crate::REGEX_IDENTIFIERS; use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS; use crate::WORKSPACE_RULES; use color_eyre::Result; @@ -46,6 +47,7 @@ use komorebi_core::Rect; use komorebi_core::SocketMessage; use komorebi_core::WindowContainerBehaviour; use parking_lot::Mutex; +use regex::Regex; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; @@ -504,6 +506,7 @@ impl StaticConfig { } let mut float_identifiers = FLOAT_IDENTIFIERS.lock(); + let mut regex_identifiers = REGEX_IDENTIFIERS.lock(); let mut manage_identifiers = MANAGE_IDENTIFIERS.lock(); let mut tray_and_multi_window_identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock(); let mut border_overflow_identifiers = BORDER_OVERFLOW_IDENTIFIERS.lock(); @@ -518,46 +521,96 @@ impl StaticConfig { if !float_identifiers.contains(identifier) { float_identifiers.push(identifier.clone()); + + if matches!(identifier.matching_strategy, Some(MatchingStrategy::Regex)) { + let re = Regex::new(&identifier.id)?; + regex_identifiers.insert(identifier.id.clone(), re); + } } } } - if let Some(float) = &self.manage_rules { - for identifier in float { - if !manage_identifiers.contains(&identifier.id) { - manage_identifiers.push(identifier.id.clone()); + if let Some(manage) = &mut self.manage_rules { + for identifier in manage { + if identifier.matching_strategy.is_none() { + identifier.matching_strategy = Option::from(MatchingStrategy::Legacy); + } + + if !manage_identifiers.contains(identifier) { + manage_identifiers.push(identifier.clone()); + + if matches!(identifier.matching_strategy, Some(MatchingStrategy::Regex)) { + let re = Regex::new(&identifier.id)?; + regex_identifiers.insert(identifier.id.clone(), re); + } } } } - if let Some(identifiers) = &self.object_name_change_applications { + if let Some(identifiers) = &mut self.object_name_change_applications { for identifier in identifiers { - if !object_name_change_identifiers.contains(&identifier.id) { - object_name_change_identifiers.push(identifier.id.clone()); + if identifier.matching_strategy.is_none() { + identifier.matching_strategy = Option::from(MatchingStrategy::Legacy); + } + + if !object_name_change_identifiers.contains(identifier) { + object_name_change_identifiers.push(identifier.clone()); + + if matches!(identifier.matching_strategy, Some(MatchingStrategy::Regex)) { + let re = Regex::new(&identifier.id)?; + regex_identifiers.insert(identifier.id.clone(), re); + } } } } - if let Some(identifiers) = &self.layered_applications { + if let Some(identifiers) = &mut self.layered_applications { for identifier in identifiers { - if !layered_identifiers.contains(&identifier.id) { - layered_identifiers.push(identifier.id.clone()); + if identifier.matching_strategy.is_none() { + identifier.matching_strategy = Option::from(MatchingStrategy::Legacy); + } + + if !border_overflow_identifiers.contains(identifier) { + border_overflow_identifiers.push(identifier.clone()); + + if matches!(identifier.matching_strategy, Some(MatchingStrategy::Regex)) { + let re = Regex::new(&identifier.id)?; + regex_identifiers.insert(identifier.id.clone(), re); + } } } } - if let Some(identifiers) = &self.border_overflow_applications { + if let Some(identifiers) = &mut self.border_overflow_applications { for identifier in identifiers { - if !border_overflow_identifiers.contains(&identifier.id) { - border_overflow_identifiers.push(identifier.id.clone()); + if identifier.matching_strategy.is_none() { + identifier.matching_strategy = Option::from(MatchingStrategy::Legacy); + } + + if !border_overflow_identifiers.contains(identifier) { + border_overflow_identifiers.push(identifier.clone()); + + if matches!(identifier.matching_strategy, Some(MatchingStrategy::Regex)) { + let re = Regex::new(&identifier.id)?; + regex_identifiers.insert(identifier.id.clone(), re); + } } } } - if let Some(identifiers) = &self.tray_and_multi_window_applications { + if let Some(identifiers) = &mut self.tray_and_multi_window_applications { for identifier in identifiers { - if !tray_and_multi_window_identifiers.contains(&identifier.id) { - tray_and_multi_window_identifiers.push(identifier.id.clone()); + if identifier.matching_strategy.is_none() { + identifier.matching_strategy = Option::from(MatchingStrategy::Legacy); + } + + if !tray_and_multi_window_identifiers.contains(identifier) { + tray_and_multi_window_identifiers.push(identifier.clone()); + + if matches!(identifier.matching_strategy, Some(MatchingStrategy::Regex)) { + let re = Regex::new(&identifier.id)?; + regex_identifiers.insert(identifier.id.clone(), re); + } } } } @@ -572,7 +625,7 @@ impl StaticConfig { let content = std::fs::read_to_string(stringified)?; let asc = ApplicationConfigurationGenerator::load(&content)?; - for entry in asc { + for mut entry in asc { if let Some(float) = entry.float_identifiers { for f in float { let mut without_comment: IdWithIdentifier = f.into(); @@ -583,6 +636,14 @@ impl StaticConfig { if !float_identifiers.contains(&without_comment) { float_identifiers.push(without_comment.clone()); + + if matches!( + without_comment.matching_strategy, + Some(MatchingStrategy::Regex) + ) { + let re = Regex::new(&without_comment.id)?; + regex_identifiers.insert(without_comment.id.clone(), re); + } } } } @@ -590,31 +651,94 @@ impl StaticConfig { for o in options { match o { ApplicationOptions::ObjectNameChange => { - if !object_name_change_identifiers.contains(&entry.identifier.id) { - object_name_change_identifiers - .push(entry.identifier.id.clone()); + if entry.identifier.matching_strategy.is_none() { + entry.identifier.matching_strategy = + Option::from(MatchingStrategy::Legacy); + } + + if !object_name_change_identifiers.contains(&entry.identifier) { + object_name_change_identifiers.push(entry.identifier.clone()); + + if matches!( + entry.identifier.matching_strategy, + Some(MatchingStrategy::Regex) + ) { + let re = Regex::new(&entry.identifier.id)?; + regex_identifiers.insert(entry.identifier.id.clone(), re); + } } } ApplicationOptions::Layered => { - if !layered_identifiers.contains(&entry.identifier.id) { - layered_identifiers.push(entry.identifier.id.clone()); + if entry.identifier.matching_strategy.is_none() { + entry.identifier.matching_strategy = + Option::from(MatchingStrategy::Legacy); + } + + if !layered_identifiers.contains(&entry.identifier) { + layered_identifiers.push(entry.identifier.clone()); + + if matches!( + entry.identifier.matching_strategy, + Some(MatchingStrategy::Regex) + ) { + let re = Regex::new(&entry.identifier.id)?; + regex_identifiers.insert(entry.identifier.id.clone(), re); + } } } ApplicationOptions::BorderOverflow => { - if !border_overflow_identifiers.contains(&entry.identifier.id) { - border_overflow_identifiers.push(entry.identifier.id.clone()); + if entry.identifier.matching_strategy.is_none() { + entry.identifier.matching_strategy = + Option::from(MatchingStrategy::Legacy); + } + + if !border_overflow_identifiers.contains(&entry.identifier) { + border_overflow_identifiers.push(entry.identifier.clone()); + + if matches!( + entry.identifier.matching_strategy, + Some(MatchingStrategy::Regex) + ) { + let re = Regex::new(&entry.identifier.id)?; + regex_identifiers.insert(entry.identifier.id.clone(), re); + } } } ApplicationOptions::TrayAndMultiWindow => { - if !tray_and_multi_window_identifiers.contains(&entry.identifier.id) - { + if entry.identifier.matching_strategy.is_none() { + entry.identifier.matching_strategy = + Option::from(MatchingStrategy::Legacy); + } + + if !tray_and_multi_window_identifiers.contains(&entry.identifier) { tray_and_multi_window_identifiers - .push(entry.identifier.id.clone()); + .push(entry.identifier.clone()); + + if matches!( + entry.identifier.matching_strategy, + Some(MatchingStrategy::Regex) + ) { + let re = Regex::new(&entry.identifier.id)?; + regex_identifiers.insert(entry.identifier.id.clone(), re); + } } } ApplicationOptions::Force => { - if !manage_identifiers.contains(&entry.identifier.id) { - manage_identifiers.push(entry.identifier.id.clone()); + if entry.identifier.matching_strategy.is_none() { + entry.identifier.matching_strategy = + Option::from(MatchingStrategy::Legacy); + } + + if !manage_identifiers.contains(&entry.identifier) { + manage_identifiers.push(entry.identifier.clone()); + + if matches!( + entry.identifier.matching_strategy, + Some(MatchingStrategy::Regex) + ) { + let re = Regex::new(&entry.identifier.id)?; + regex_identifiers.insert(entry.identifier.id.clone(), re); + } } } } diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index 26918321..b08760ef 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -1,4 +1,5 @@ use crate::com::SetCloak; +use std::collections::HashMap; use std::convert::TryFrom; use std::fmt::Display; use std::fmt::Formatter; @@ -7,7 +8,9 @@ use std::sync::atomic::Ordering; use color_eyre::eyre::anyhow; use color_eyre::Result; +use komorebi_core::config_generation::IdWithIdentifier; use komorebi_core::config_generation::MatchingStrategy; +use regex::Regex; use schemars::JsonSchema; use serde::ser::Error; use serde::ser::SerializeStruct; @@ -35,6 +38,7 @@ use crate::LAYERED_WHITELIST; use crate::MANAGE_IDENTIFIERS; use crate::NO_TITLEBAR; use crate::PERMAIGNORE_CLASSES; +use crate::REGEX_IDENTIFIERS; use crate::WSL2_UI_PROCESSES; #[derive(Debug, Clone, Copy, JsonSchema)] @@ -126,15 +130,21 @@ impl Window { top: bool, ) -> Result<()> { let mut rect = *layout; - 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; - } + let regex_identifiers = REGEX_IDENTIFIERS.lock(); + + let title = &self.title()?; + let class = &self.class()?; + let exe_name = &self.exe()?; + + let should_remove_border = should_act( + title, + exe_name, + class, + &border_overflows, + ®ex_identifiers, + ); if should_remove_border { // Remove the invisible borders @@ -471,71 +481,38 @@ fn window_is_eligible( } } - let mut should_float = false; + let regex_identifiers = REGEX_IDENTIFIERS.lock(); - { - let float_identifiers = FLOAT_IDENTIFIERS.lock(); - for identifier in float_identifiers.iter() { - match identifier.matching_strategy { - None => { - panic!("there is no matching strategy identified for this rule"); - } - Some(MatchingStrategy::Equals) => match identifier.kind { - ApplicationIdentifier::Title => { - if title.eq(&identifier.id) { - should_float = true; - } - } - ApplicationIdentifier::Class => { - if class.eq(&identifier.id) { - should_float = true; - } - } - ApplicationIdentifier::Exe => { - if exe_name.eq(&identifier.id) { - should_float = true; - } - } - }, - Some(MatchingStrategy::Legacy) => match identifier.kind { - ApplicationIdentifier::Title => { - if title.starts_with(&identifier.id) || title.ends_with(&identifier.id) { - should_float = true; - } - } - ApplicationIdentifier::Class => { - if class.starts_with(&identifier.id) || class.ends_with(&identifier.id) { - should_float = true; - } - } - ApplicationIdentifier::Exe => { - if exe_name.eq(&identifier.id) { - should_float = true; - } - } - }, - _ => unimplemented!(), - } - } - }; + let float_identifiers = FLOAT_IDENTIFIERS.lock(); + let should_float = should_act( + title, + exe_name, + class, + &float_identifiers, + ®ex_identifiers, + ); - let managed_override = { - let manage_identifiers = MANAGE_IDENTIFIERS.lock(); - manage_identifiers.contains(exe_name) - || manage_identifiers.contains(class) - || manage_identifiers.contains(title) - }; + let manage_identifiers = MANAGE_IDENTIFIERS.lock(); + let managed_override = should_act( + title, + exe_name, + class, + &manage_identifiers, + ®ex_identifiers, + ); if should_float && !managed_override { return false; } - let allow_layered = { - let layered_whitelist = LAYERED_WHITELIST.lock(); - layered_whitelist.contains(exe_name) - || layered_whitelist.contains(class) - || layered_whitelist.contains(title) - }; + let layered_whitelist = LAYERED_WHITELIST.lock(); + let allow_layered = should_act( + title, + exe_name, + class, + &layered_whitelist, + ®ex_identifiers, + ); // TODO: might need this for transparency // let allow_layered = true; @@ -566,3 +543,131 @@ fn window_is_eligible( false } + +#[allow(clippy::cognitive_complexity, clippy::too_many_lines)] +pub fn should_act( + title: &str, + exe_name: &str, + class: &str, + identifiers: &[IdWithIdentifier], + regex_identifiers: &HashMap, +) -> bool { + let mut should_act = false; + for identifier in identifiers { + match identifier.matching_strategy { + None => { + panic!("there is no matching strategy identified for this rule"); + } + Some(MatchingStrategy::Legacy) => match identifier.kind { + ApplicationIdentifier::Title => { + if title.starts_with(&identifier.id) || title.ends_with(&identifier.id) { + should_act = true; + } + } + ApplicationIdentifier::Class => { + if class.starts_with(&identifier.id) || class.ends_with(&identifier.id) { + should_act = true; + } + } + ApplicationIdentifier::Exe => { + if exe_name.eq(&identifier.id) { + should_act = true; + } + } + }, + Some(MatchingStrategy::Equals) => match identifier.kind { + ApplicationIdentifier::Title => { + if title.eq(&identifier.id) { + should_act = true; + } + } + ApplicationIdentifier::Class => { + if class.eq(&identifier.id) { + should_act = true; + } + } + ApplicationIdentifier::Exe => { + if exe_name.eq(&identifier.id) { + should_act = true; + } + } + }, + Some(MatchingStrategy::StartsWith) => match identifier.kind { + ApplicationIdentifier::Title => { + if title.starts_with(&identifier.id) { + should_act = true; + } + } + ApplicationIdentifier::Class => { + if class.starts_with(&identifier.id) { + should_act = true; + } + } + ApplicationIdentifier::Exe => { + if exe_name.starts_with(&identifier.id) { + should_act = true; + } + } + }, + Some(MatchingStrategy::EndsWith) => match identifier.kind { + ApplicationIdentifier::Title => { + if title.ends_with(&identifier.id) { + should_act = true; + } + } + ApplicationIdentifier::Class => { + if class.ends_with(&identifier.id) { + should_act = true; + } + } + ApplicationIdentifier::Exe => { + if exe_name.ends_with(&identifier.id) { + should_act = true; + } + } + }, + Some(MatchingStrategy::Contains) => match identifier.kind { + ApplicationIdentifier::Title => { + if title.contains(&identifier.id) { + should_act = true; + } + } + ApplicationIdentifier::Class => { + if class.contains(&identifier.id) { + should_act = true; + } + } + ApplicationIdentifier::Exe => { + if exe_name.contains(&identifier.id) { + should_act = true; + } + } + }, + Some(MatchingStrategy::Regex) => match identifier.kind { + ApplicationIdentifier::Title => { + if let Some(re) = regex_identifiers.get(&identifier.id) { + if re.is_match(title) { + should_act = true; + } + } + } + ApplicationIdentifier::Class => { + if let Some(re) = regex_identifiers.get(&identifier.id) { + if re.is_match(class) { + should_act = true; + } + } + } + ApplicationIdentifier::Exe => { + if let Some(re) = regex_identifiers.get(&identifier.id) { + if re.is_match(exe_name) { + should_act = true; + } + } + } + }, + } + } + + should_act +} diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 3ca48817..87af1eb8 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -95,11 +95,11 @@ pub struct State { pub has_pending_raise_op: bool, pub remove_titlebars: bool, pub float_identifiers: Vec, - pub manage_identifiers: Vec, - pub layered_whitelist: Vec, - pub tray_and_multi_window_identifiers: Vec, - pub border_overflow_identifiers: Vec, - pub name_change_on_launch_identifiers: Vec, + pub manage_identifiers: Vec, + pub layered_whitelist: Vec, + pub tray_and_multi_window_identifiers: Vec, + pub border_overflow_identifiers: Vec, + pub name_change_on_launch_identifiers: Vec, pub monitor_index_preferences: HashMap, } diff --git a/komorebi/src/window_manager_event.rs b/komorebi/src/window_manager_event.rs index af9cdbe4..ae6d19bd 100644 --- a/komorebi/src/window_manager_event.rs +++ b/komorebi/src/window_manager_event.rs @@ -4,9 +4,11 @@ use std::fmt::Formatter; use schemars::JsonSchema; use serde::Serialize; +use crate::window::should_act; use crate::window::Window; use crate::winevent::WinEvent; use crate::OBJECT_NAME_CHANGE_ON_LAUNCH; +use crate::REGEX_IDENTIFIERS; #[derive(Debug, Copy, Clone, Serialize, JsonSchema)] #[serde(tag = "type", content = "content")] @@ -131,11 +133,21 @@ impl WindowManagerEvent { // [yatta\src\windows_event.rs:110] event = 32779 ObjectLocationChange let object_name_change_on_launch = OBJECT_NAME_CHANGE_ON_LAUNCH.lock(); + let regex_identifiers = REGEX_IDENTIFIERS.lock(); - if object_name_change_on_launch.contains(&window.exe().ok()?) - || object_name_change_on_launch.contains(&window.class().ok()?) - || object_name_change_on_launch.contains(&window.title().ok()?) - { + let title = &window.title().ok()?; + let exe_name = &window.exe().ok()?; + let class = &window.class().ok()?; + + let should_trigger = should_act( + title, + exe_name, + class, + &object_name_change_on_launch, + ®ex_identifiers, + ); + + if should_trigger { Option::from(Self::Show(winevent, window)) } else { None