feat(rules): implement all matching strategies

This commit ensures that matching strategies can be used wherever
IdWithIdentifier is used, and that they are respected for users opting
to use the static configuration file format.

Some thought and planning needs to go into how this can be backported to
dynamic configurations via the CLI without breaking existing user
configurations.

re #60
This commit is contained in:
LGUG2Z
2023-10-06 12:14:55 -07:00
parent 3ff3961381
commit b048e7c3aa
12 changed files with 652 additions and 146 deletions
+1
View File
@@ -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"
+15 -8
View File
@@ -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,
&regex_identifiers,
);
if should_expand_border {
rect.left -= invisible_borders.left;
+54 -14
View File
@@ -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<Mutex<Vec<isize>>> = Arc::new(Mutex::new(vec![]));
static ref LAYERED_WHITELIST: Arc<Mutex<Vec<String>>> =
Arc::new(Mutex::new(vec!["steam.exe".to_string()]));
static ref TRAY_AND_MULTI_WINDOW_IDENTIFIERS: Arc<Mutex<Vec<String>>> =
static ref LAYERED_WHITELIST: Arc<Mutex<Vec<IdWithIdentifier>>> = 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<Mutex<Vec<IdWithIdentifier>>> =
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<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
"firefox.exe".to_string(),
"idea64.exe".to_string(),
static ref OBJECT_NAME_CHANGE_ON_LAUNCH: Arc<Mutex<Vec<IdWithIdentifier>>> = 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<Mutex<HashMap<usize, Rect>>> =
Arc::new(Mutex::new(HashMap::new()));
static ref WORKSPACE_RULES: Arc<Mutex<HashMap<String, WorkspaceRule>>> =
Arc::new(Mutex::new(HashMap::new()));
static ref MANAGE_IDENTIFIERS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
static ref REGEX_IDENTIFIERS: Arc<Mutex<HashMap<String, Regex>>> =
Arc::new(Mutex::new(HashMap::new()));
static ref MANAGE_IDENTIFIERS: Arc<Mutex<Vec<IdWithIdentifier>>> = Arc::new(Mutex::new(vec![]));
static ref FLOAT_IDENTIFIERS: Arc<Mutex<Vec<IdWithIdentifier>>> = 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<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
"Chrome_RenderWidgetHostHWND".to_string(),
]));
static ref BORDER_OVERFLOW_IDENTIFIERS: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
static ref BORDER_OVERFLOW_IDENTIFIERS: Arc<Mutex<Vec<IdWithIdentifier>>> = Arc::new(Mutex::new(vec![]));
static ref WSL2_UI_PROCESSES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
"X410.exe".to_string(),
"vcxsrv.exe".to_string(),
+74 -15
View File
@@ -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 => {
+17 -4
View File
@@ -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,
&regex_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;
}
+153 -29
View File
@@ -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);
}
}
}
}
+170 -65
View File
@@ -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,
&regex_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,
&regex_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,
&regex_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,
&regex_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<String, Regex>,
) -> 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
}
+5 -5
View File
@@ -95,11 +95,11 @@ pub struct State {
pub has_pending_raise_op: bool,
pub remove_titlebars: bool,
pub float_identifiers: Vec<IdWithIdentifier>,
pub manage_identifiers: Vec<String>,
pub layered_whitelist: Vec<String>,
pub tray_and_multi_window_identifiers: Vec<String>,
pub border_overflow_identifiers: Vec<String>,
pub name_change_on_launch_identifiers: Vec<String>,
pub manage_identifiers: Vec<IdWithIdentifier>,
pub layered_whitelist: Vec<IdWithIdentifier>,
pub tray_and_multi_window_identifiers: Vec<IdWithIdentifier>,
pub border_overflow_identifiers: Vec<IdWithIdentifier>,
pub name_change_on_launch_identifiers: Vec<IdWithIdentifier>,
pub monitor_index_preferences: HashMap<usize, Rect>,
}
+16 -4
View File
@@ -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,
&regex_identifiers,
);
if should_trigger {
Option::from(Self::Show(winevent, window))
} else {
None