From 0797316ee69b8d2ca612d1d740581ab4a50fa12f Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 22 Sep 2023 15:05:17 -0700 Subject: [PATCH] feat(rules): add explicit matching strategies This commit is the first in a series of commits which will pave the way for regex rule matching support in komorebi. For now, in order to maintain backwards compat and not break anything, all rules without a matching strategy will get assigned as using the "Legacy" strategy. This and the "Equals" strategy are the only two which have been implemented so far. There should not be any breaking changes in this commit, not any functionality lost for users with pre-existing configurations. re #60 --- komorebi-core/src/config_generation.rs | 26 ++++++++++++- komorebi-core/src/lib.rs | 12 +++++- komorebi/src/main.rs | 17 +++++++-- komorebi/src/process_command.rs | 18 ++++++++- komorebi/src/static_config.rs | 28 ++++++++++---- komorebi/src/window.rs | 51 +++++++++++++++++++++----- komorebi/src/window_manager.rs | 3 +- 7 files changed, 129 insertions(+), 26 deletions(-) diff --git a/komorebi-core/src/config_generation.rs b/komorebi-core/src/config_generation.rs index 2a370a5c..9566bf51 100644 --- a/komorebi-core/src/config_generation.rs +++ b/komorebi-core/src/config_generation.rs @@ -50,10 +50,22 @@ impl ApplicationOptions { } } -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] pub struct IdWithIdentifier { pub kind: ApplicationIdentifier, pub id: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub matching_strategy: Option, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] +pub enum MatchingStrategy { + Legacy, + Equals, + StartsWith, + EndsWith, + Contains, + Regex, } #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] @@ -62,6 +74,18 @@ pub struct IdWithIdentifierAndComment { pub id: String, #[serde(skip_serializing_if = "Option::is_none")] pub comment: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub matching_strategy: Option, +} + +impl From for IdWithIdentifier { + fn from(value: IdWithIdentifierAndComment) -> Self { + Self { + kind: value.kind, + id: value.id.clone(), + matching_strategy: value.matching_strategy, + } + } } #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index cf686a53..a06a73b3 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -192,7 +192,17 @@ pub enum StateQuery { } #[derive( - Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema, + Copy, + Clone, + Debug, + Eq, + PartialEq, + Serialize, + Deserialize, + Display, + EnumString, + ValueEnum, + JsonSchema, )] #[strum(serialize_all = "snake_case")] pub enum ApplicationIdentifier { diff --git a/komorebi/src/main.rs b/komorebi/src/main.rs index b05b90f8..96464577 100644 --- a/komorebi/src/main.rs +++ b/komorebi/src/main.rs @@ -45,6 +45,9 @@ use winreg::enums::HKEY_CURRENT_USER; use winreg::RegKey; use crate::hidden::Hidden; +use komorebi_core::config_generation::IdWithIdentifier; +use komorebi_core::config_generation::MatchingStrategy; +use komorebi_core::ApplicationIdentifier; use komorebi_core::HidingBehaviour; use komorebi_core::Rect; use komorebi_core::SocketMessage; @@ -106,11 +109,19 @@ lazy_static! { static ref WORKSPACE_RULES: 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![ + 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 - "OPContainerClass".to_string(), - "IHWindowClass".to_string() + IdWithIdentifier { + kind: ApplicationIdentifier::Class, + id: String::from("OPContainerClass"), + matching_strategy: Option::from(MatchingStrategy::Equals), + }, + IdWithIdentifier { + kind: ApplicationIdentifier::Class, + id: String::from("IHWindowClass"), + matching_strategy: Option::from(MatchingStrategy::Equals), + } ])); static ref PERMAIGNORE_CLASSES: Arc>> = Arc::new(Mutex::new(vec![ "Chrome_RenderWidgetHostHWND".to_string(), diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index f4944e22..6738c46e 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -20,6 +20,8 @@ use parking_lot::Mutex; use schemars::schema_for; use uds_windows::UnixStream; +use komorebi_core::config_generation::IdWithIdentifier; +use komorebi_core::config_generation::MatchingStrategy; use komorebi_core::ApplicationIdentifier; use komorebi_core::Axis; use komorebi_core::FocusFollowsMouseImplementation; @@ -246,8 +248,20 @@ impl WindowManager { } SocketMessage::FloatRule(identifier, ref id) => { let mut float_identifiers = FLOAT_IDENTIFIERS.lock(); - if !float_identifiers.contains(id) { - float_identifiers.push(id.to_string()); + + let mut should_push = true; + for f in &*float_identifiers { + if f.id.eq(id) { + should_push = false; + } + } + + if should_push { + float_identifiers.push(IdWithIdentifier { + kind: identifier, + id: id.clone(), + matching_strategy: Option::from(MatchingStrategy::Legacy), + }); } let invisible_borders = self.invisible_borders; diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index 34fb5d69..13bc869c 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -34,6 +34,7 @@ use hotwatch::Hotwatch; use komorebi_core::config_generation::ApplicationConfigurationGenerator; use komorebi_core::config_generation::ApplicationOptions; use komorebi_core::config_generation::IdWithIdentifier; +use komorebi_core::config_generation::MatchingStrategy; use komorebi_core::ApplicationIdentifier; use komorebi_core::DefaultLayout; use komorebi_core::FocusFollowsMouseImplementation; @@ -139,6 +140,7 @@ impl From<&Workspace> for WorkspaceConfig { let rule = IdWithIdentifier { kind: ApplicationIdentifier::Exe, id: identifier.clone(), + matching_strategy: None, }; if *is_initial { @@ -433,7 +435,7 @@ impl From<&WindowManager> for StaticConfig { impl StaticConfig { #[allow(clippy::cognitive_complexity, clippy::too_many_lines)] - fn apply_globals(&self) -> Result<()> { + fn apply_globals(&mut self) -> Result<()> { if let Some(monitor_index_preferences) = &self.monitor_index_preferences { let mut preferences = MONITOR_INDEX_PREFERENCES.lock(); *preferences = monitor_index_preferences.clone(); @@ -508,10 +510,14 @@ impl StaticConfig { let mut object_name_change_identifiers = OBJECT_NAME_CHANGE_ON_LAUNCH.lock(); let mut layered_identifiers = LAYERED_WHITELIST.lock(); - if let Some(float) = &self.float_rules { + if let Some(float) = &mut self.float_rules { for identifier in float { - if !float_identifiers.contains(&identifier.id) { - float_identifiers.push(identifier.id.clone()); + if identifier.matching_strategy.is_none() { + identifier.matching_strategy = Option::from(MatchingStrategy::Legacy); + } + + if !float_identifiers.contains(identifier) { + float_identifiers.push(identifier.clone()); } } } @@ -569,8 +575,14 @@ impl StaticConfig { for entry in asc { if let Some(float) = entry.float_identifiers { for f in float { - if !float_identifiers.contains(&f.id) { - float_identifiers.push(f.id.clone()); + let mut without_comment: IdWithIdentifier = f.into(); + if without_comment.matching_strategy.is_none() { + without_comment.matching_strategy = + Option::from(MatchingStrategy::Legacy); + } + + if !float_identifiers.contains(&without_comment) { + float_identifiers.push(without_comment.clone()); } } } @@ -620,7 +632,7 @@ impl StaticConfig { incoming: Arc>>, ) -> Result { let content = std::fs::read_to_string(path)?; - let value: Self = serde_json::from_str(&content)?; + let mut value: Self = serde_json::from_str(&content)?; value.apply_globals()?; let socket = DATA_DIR.join("komorebi.sock"); @@ -740,7 +752,7 @@ impl StaticConfig { pub fn reload(path: &PathBuf, wm: &mut WindowManager) -> Result<()> { let content = std::fs::read_to_string(path)?; - let value: Self = serde_json::from_str(&content)?; + let mut value: Self = serde_json::from_str(&content)?; value.apply_globals()?; diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index 9539599a..26918321 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -7,6 +7,7 @@ use std::sync::atomic::Ordering; use color_eyre::eyre::anyhow; use color_eyre::Result; +use komorebi_core::config_generation::MatchingStrategy; use schemars::JsonSchema; use serde::ser::Error; use serde::ser::SerializeStruct; @@ -17,6 +18,7 @@ use winput::press; use winput::release; use winput::Vk; +use komorebi_core::ApplicationIdentifier; use komorebi_core::HidingBehaviour; use komorebi_core::Rect; @@ -474,16 +476,45 @@ fn window_is_eligible( { let float_identifiers = FLOAT_IDENTIFIERS.lock(); for identifier in float_identifiers.iter() { - if title.starts_with(identifier) || title.ends_with(identifier) { - should_float = true; - } - - if class.starts_with(identifier) || class.ends_with(identifier) { - should_float = true; - } - - if identifier == exe_name { - should_float = true; + 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!(), } } }; diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 3ac0eb1b..3ca48817 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -17,6 +17,7 @@ use schemars::JsonSchema; use serde::Serialize; use uds_windows::UnixListener; +use komorebi_core::config_generation::IdWithIdentifier; use komorebi_core::custom_layout::CustomLayout; use komorebi_core::Arrangement; use komorebi_core::Axis; @@ -93,7 +94,7 @@ pub struct State { pub mouse_follows_focus: bool, pub has_pending_raise_op: bool, pub remove_titlebars: bool, - pub float_identifiers: Vec, + pub float_identifiers: Vec, pub manage_identifiers: Vec, pub layered_whitelist: Vec, pub tray_and_multi_window_identifiers: Vec,