mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-06 21:15:13 +02:00
feat(config): add support for composite rules
This commit adds support for composite rules in the static configuration file, and for float_identifiers in the applications.yaml file. A new enum, MatchingRule provides two variants, Simple and Composite, and is now used in place of IdWithIdentifier throughout komorebi. In order to keep this new enum lean, a variant for IdWithIdentifierAndComment has not been added, and references to it in the old config generation code have been replaced with MatchingRule. resolve #462, resolve #715, resolve #237
This commit is contained in:
@@ -8,7 +8,9 @@ use strum::EnumString;
|
|||||||
|
|
||||||
use crate::ApplicationIdentifier;
|
use crate::ApplicationIdentifier;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema)]
|
#[derive(
|
||||||
|
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||||
|
)]
|
||||||
#[strum(serialize_all = "snake_case")]
|
#[strum(serialize_all = "snake_case")]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ApplicationOptions {
|
pub enum ApplicationOptions {
|
||||||
@@ -50,6 +52,13 @@ impl ApplicationOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum MatchingRule {
|
||||||
|
Simple(IdWithIdentifier),
|
||||||
|
Composite(Vec<IdWithIdentifier>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct IdWithIdentifier {
|
pub struct IdWithIdentifier {
|
||||||
pub kind: ApplicationIdentifier,
|
pub kind: ApplicationIdentifier,
|
||||||
@@ -95,7 +104,7 @@ pub struct ApplicationConfiguration {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub options: Option<Vec<ApplicationOptions>>,
|
pub options: Option<Vec<ApplicationOptions>>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub float_identifiers: Option<Vec<IdWithIdentifierAndComment>>,
|
pub float_identifiers: Option<Vec<MatchingRule>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationConfiguration {
|
impl ApplicationConfiguration {
|
||||||
@@ -181,19 +190,21 @@ impl ApplicationConfigurationGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(float_identifiers) = app.float_identifiers {
|
if let Some(float_identifiers) = app.float_identifiers {
|
||||||
for float in float_identifiers {
|
for matching_rule in float_identifiers {
|
||||||
let float_rule =
|
if let MatchingRule::Simple(float) = matching_rule {
|
||||||
format!("komorebic.exe float-rule {} \"{}\"", float.kind, float.id);
|
let float_rule =
|
||||||
|
format!("komorebic.exe float-rule {} \"{}\"", float.kind, float.id);
|
||||||
|
|
||||||
// Don't want to send duped signals especially as configs get larger
|
// Don't want to send duped signals especially as configs get larger
|
||||||
if !float_rules.contains(&float_rule) {
|
if !float_rules.contains(&float_rule) {
|
||||||
float_rules.push(float_rule.clone());
|
float_rules.push(float_rule.clone());
|
||||||
|
|
||||||
if let Some(comment) = float.comment {
|
// if let Some(comment) = float.comment {
|
||||||
lines.push(format!("# {comment}"));
|
// lines.push(format!("# {comment}"));
|
||||||
};
|
// };
|
||||||
|
|
||||||
lines.push(float_rule);
|
lines.push(float_rule);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,21 +241,23 @@ impl ApplicationConfigurationGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(float_identifiers) = app.float_identifiers {
|
if let Some(float_identifiers) = app.float_identifiers {
|
||||||
for float in float_identifiers {
|
for matching_rule in float_identifiers {
|
||||||
let float_rule = format!(
|
if let MatchingRule::Simple(float) = matching_rule {
|
||||||
"RunWait('komorebic.exe float-rule {} \"{}\"', , \"Hide\")",
|
let float_rule = format!(
|
||||||
float.kind, float.id
|
"RunWait('komorebic.exe float-rule {} \"{}\"', , \"Hide\")",
|
||||||
);
|
float.kind, float.id
|
||||||
|
);
|
||||||
|
|
||||||
// Don't want to send duped signals especially as configs get larger
|
// Don't want to send duped signals especially as configs get larger
|
||||||
if !float_rules.contains(&float_rule) {
|
if !float_rules.contains(&float_rule) {
|
||||||
float_rules.push(float_rule.clone());
|
float_rules.push(float_rule.clone());
|
||||||
|
|
||||||
if let Some(comment) = float.comment {
|
// if let Some(comment) = float.comment {
|
||||||
lines.push(format!("; {comment}"));
|
// lines.push(format!("; {comment}"));
|
||||||
};
|
// };
|
||||||
|
|
||||||
lines.push(float_rule);
|
lines.push(float_rule);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-28
@@ -46,6 +46,7 @@ pub use windows_api::*;
|
|||||||
|
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use komorebi_core::config_generation::IdWithIdentifier;
|
use komorebi_core::config_generation::IdWithIdentifier;
|
||||||
|
use komorebi_core::config_generation::MatchingRule;
|
||||||
use komorebi_core::config_generation::MatchingStrategy;
|
use komorebi_core::config_generation::MatchingStrategy;
|
||||||
use komorebi_core::ApplicationIdentifier;
|
use komorebi_core::ApplicationIdentifier;
|
||||||
use komorebi_core::HidingBehaviour;
|
use komorebi_core::HidingBehaviour;
|
||||||
@@ -66,57 +67,57 @@ type WorkspaceRule = (usize, usize, bool);
|
|||||||
|
|
||||||
lazy_static! {
|
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_WHITELIST: Arc<Mutex<Vec<IdWithIdentifier>>> = Arc::new(Mutex::new(vec![
|
static ref LAYERED_WHITELIST: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![
|
||||||
IdWithIdentifier {
|
MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: ApplicationIdentifier::Exe,
|
kind: ApplicationIdentifier::Exe,
|
||||||
id: String::from("steam.exe"),
|
id: String::from("steam.exe"),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||||
},
|
}),
|
||||||
]));
|
]));
|
||||||
static ref TRAY_AND_MULTI_WINDOW_IDENTIFIERS: Arc<Mutex<Vec<IdWithIdentifier>>> =
|
static ref TRAY_AND_MULTI_WINDOW_IDENTIFIERS: Arc<Mutex<Vec<MatchingRule>>> =
|
||||||
Arc::new(Mutex::new(vec![
|
Arc::new(Mutex::new(vec![
|
||||||
IdWithIdentifier {
|
MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: ApplicationIdentifier::Exe,
|
kind: ApplicationIdentifier::Exe,
|
||||||
id: String::from("explorer.exe"),
|
id: String::from("explorer.exe"),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||||
},
|
}),
|
||||||
IdWithIdentifier {
|
MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: ApplicationIdentifier::Exe,
|
kind: ApplicationIdentifier::Exe,
|
||||||
id: String::from("firefox.exe"),
|
id: String::from("firefox.exe"),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||||
},
|
}),
|
||||||
IdWithIdentifier {
|
MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: ApplicationIdentifier::Exe,
|
kind: ApplicationIdentifier::Exe,
|
||||||
id: String::from("chrome.exe"),
|
id: String::from("chrome.exe"),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||||
},
|
}),
|
||||||
IdWithIdentifier {
|
MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: ApplicationIdentifier::Exe,
|
kind: ApplicationIdentifier::Exe,
|
||||||
id: String::from("idea64.exe"),
|
id: String::from("idea64.exe"),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||||
},
|
}),
|
||||||
IdWithIdentifier {
|
MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: ApplicationIdentifier::Exe,
|
kind: ApplicationIdentifier::Exe,
|
||||||
id: String::from("ApplicationFrameHost.exe"),
|
id: String::from("ApplicationFrameHost.exe"),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||||
},
|
}),
|
||||||
IdWithIdentifier {
|
MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: ApplicationIdentifier::Exe,
|
kind: ApplicationIdentifier::Exe,
|
||||||
id: String::from("steam.exe"),
|
id: String::from("steam.exe"),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||||
}
|
})
|
||||||
]));
|
]));
|
||||||
static ref OBJECT_NAME_CHANGE_ON_LAUNCH: Arc<Mutex<Vec<IdWithIdentifier>>> = Arc::new(Mutex::new(vec![
|
static ref OBJECT_NAME_CHANGE_ON_LAUNCH: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![
|
||||||
IdWithIdentifier {
|
MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: ApplicationIdentifier::Exe,
|
kind: ApplicationIdentifier::Exe,
|
||||||
id: String::from("firefox.exe"),
|
id: String::from("firefox.exe"),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||||
},
|
}),
|
||||||
IdWithIdentifier {
|
MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: ApplicationIdentifier::Exe,
|
kind: ApplicationIdentifier::Exe,
|
||||||
id: String::from("idea64.exe"),
|
id: String::from("idea64.exe"),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||||
},
|
}),
|
||||||
]));
|
]));
|
||||||
static ref MONITOR_INDEX_PREFERENCES: Arc<Mutex<HashMap<usize, Rect>>> =
|
static ref MONITOR_INDEX_PREFERENCES: Arc<Mutex<HashMap<usize, Rect>>> =
|
||||||
Arc::new(Mutex::new(HashMap::new()));
|
Arc::new(Mutex::new(HashMap::new()));
|
||||||
@@ -126,25 +127,26 @@ lazy_static! {
|
|||||||
Arc::new(Mutex::new(HashMap::new()));
|
Arc::new(Mutex::new(HashMap::new()));
|
||||||
static ref REGEX_IDENTIFIERS: Arc<Mutex<HashMap<String, Regex>>> =
|
static ref REGEX_IDENTIFIERS: Arc<Mutex<HashMap<String, Regex>>> =
|
||||||
Arc::new(Mutex::new(HashMap::new()));
|
Arc::new(Mutex::new(HashMap::new()));
|
||||||
static ref MANAGE_IDENTIFIERS: Arc<Mutex<Vec<IdWithIdentifier>>> = Arc::new(Mutex::new(vec![]));
|
static ref MANAGE_IDENTIFIERS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![]));
|
||||||
static ref FLOAT_IDENTIFIERS: Arc<Mutex<Vec<IdWithIdentifier>>> = Arc::new(Mutex::new(vec![
|
static ref FLOAT_IDENTIFIERS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![
|
||||||
// mstsc.exe creates these on Windows 11 when a WSL process is launched
|
// mstsc.exe creates these on Windows 11 when a WSL process is launched
|
||||||
// https://github.com/LGUG2Z/komorebi/issues/74
|
// https://github.com/LGUG2Z/komorebi/issues/74
|
||||||
IdWithIdentifier {
|
MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: ApplicationIdentifier::Class,
|
kind: ApplicationIdentifier::Class,
|
||||||
id: String::from("OPContainerClass"),
|
id: String::from("OPContainerClass"),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||||
},
|
}),
|
||||||
IdWithIdentifier {
|
MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: ApplicationIdentifier::Class,
|
kind: ApplicationIdentifier::Class,
|
||||||
id: String::from("IHWindowClass"),
|
id: String::from("IHWindowClass"),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||||
}
|
})
|
||||||
]));
|
]));
|
||||||
|
|
||||||
static ref PERMAIGNORE_CLASSES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
|
static ref PERMAIGNORE_CLASSES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
|
||||||
"Chrome_RenderWidgetHostHWND".to_string(),
|
"Chrome_RenderWidgetHostHWND".to_string(),
|
||||||
]));
|
]));
|
||||||
static ref BORDER_OVERFLOW_IDENTIFIERS: Arc<Mutex<Vec<IdWithIdentifier>>> = Arc::new(Mutex::new(vec![]));
|
static ref BORDER_OVERFLOW_IDENTIFIERS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![]));
|
||||||
static ref WSL2_UI_PROCESSES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
|
static ref WSL2_UI_PROCESSES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
|
||||||
"X410.exe".to_string(),
|
"X410.exe".to_string(),
|
||||||
"vcxsrv.exe".to_string(),
|
"vcxsrv.exe".to_string(),
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ use uds_windows::UnixStream;
|
|||||||
|
|
||||||
use komorebi_core::config_generation::ApplicationConfiguration;
|
use komorebi_core::config_generation::ApplicationConfiguration;
|
||||||
use komorebi_core::config_generation::IdWithIdentifier;
|
use komorebi_core::config_generation::IdWithIdentifier;
|
||||||
|
use komorebi_core::config_generation::MatchingRule;
|
||||||
use komorebi_core::config_generation::MatchingStrategy;
|
use komorebi_core::config_generation::MatchingStrategy;
|
||||||
use komorebi_core::ApplicationIdentifier;
|
use komorebi_core::ApplicationIdentifier;
|
||||||
use komorebi_core::Axis;
|
use komorebi_core::Axis;
|
||||||
@@ -273,17 +274,19 @@ impl WindowManager {
|
|||||||
|
|
||||||
let mut should_push = true;
|
let mut should_push = true;
|
||||||
for m in &*manage_identifiers {
|
for m in &*manage_identifiers {
|
||||||
if m.id.eq(id) {
|
if let MatchingRule::Simple(m) = m {
|
||||||
should_push = false;
|
if m.id.eq(id) {
|
||||||
|
should_push = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_push {
|
if should_push {
|
||||||
manage_identifiers.push(IdWithIdentifier {
|
manage_identifiers.push(MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: identifier,
|
kind: identifier,
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SocketMessage::FloatRule(identifier, ref id) => {
|
SocketMessage::FloatRule(identifier, ref id) => {
|
||||||
@@ -291,17 +294,19 @@ impl WindowManager {
|
|||||||
|
|
||||||
let mut should_push = true;
|
let mut should_push = true;
|
||||||
for f in &*float_identifiers {
|
for f in &*float_identifiers {
|
||||||
if f.id.eq(id) {
|
if let MatchingRule::Simple(f) = f {
|
||||||
should_push = false;
|
if f.id.eq(id) {
|
||||||
|
should_push = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_push {
|
if should_push {
|
||||||
float_identifiers.push(IdWithIdentifier {
|
float_identifiers.push(MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: identifier,
|
kind: identifier,
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
let offset = self.work_area_offset;
|
let offset = self.work_area_offset;
|
||||||
@@ -1025,17 +1030,19 @@ impl WindowManager {
|
|||||||
|
|
||||||
let mut should_push = true;
|
let mut should_push = true;
|
||||||
for i in &*identifiers {
|
for i in &*identifiers {
|
||||||
if i.id.eq(id) {
|
if let MatchingRule::Simple(i) = i {
|
||||||
should_push = false;
|
if i.id.eq(id) {
|
||||||
|
should_push = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_push {
|
if should_push {
|
||||||
identifiers.push(IdWithIdentifier {
|
identifiers.push(MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: identifier,
|
kind: identifier,
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SocketMessage::IdentifyObjectNameChangeApplication(identifier, ref id) => {
|
SocketMessage::IdentifyObjectNameChangeApplication(identifier, ref id) => {
|
||||||
@@ -1043,34 +1050,38 @@ impl WindowManager {
|
|||||||
|
|
||||||
let mut should_push = true;
|
let mut should_push = true;
|
||||||
for i in &*identifiers {
|
for i in &*identifiers {
|
||||||
if i.id.eq(id) {
|
if let MatchingRule::Simple(i) = i {
|
||||||
should_push = false;
|
if i.id.eq(id) {
|
||||||
|
should_push = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_push {
|
if should_push {
|
||||||
identifiers.push(IdWithIdentifier {
|
identifiers.push(MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: identifier,
|
kind: identifier,
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SocketMessage::IdentifyTrayApplication(identifier, ref id) => {
|
SocketMessage::IdentifyTrayApplication(identifier, ref id) => {
|
||||||
let mut identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock();
|
let mut identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock();
|
||||||
let mut should_push = true;
|
let mut should_push = true;
|
||||||
for i in &*identifiers {
|
for i in &*identifiers {
|
||||||
if i.id.eq(id) {
|
if let MatchingRule::Simple(i) = i {
|
||||||
should_push = false;
|
if i.id.eq(id) {
|
||||||
|
should_push = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_push {
|
if should_push {
|
||||||
identifiers.push(IdWithIdentifier {
|
identifiers.push(MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: identifier,
|
kind: identifier,
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SocketMessage::IdentifyLayeredApplication(identifier, ref id) => {
|
SocketMessage::IdentifyLayeredApplication(identifier, ref id) => {
|
||||||
@@ -1078,17 +1089,19 @@ impl WindowManager {
|
|||||||
|
|
||||||
let mut should_push = true;
|
let mut should_push = true;
|
||||||
for i in &*identifiers {
|
for i in &*identifiers {
|
||||||
if i.id.eq(id) {
|
if let MatchingRule::Simple(i) = i {
|
||||||
should_push = false;
|
if i.id.eq(id) {
|
||||||
|
should_push = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_push {
|
if should_push {
|
||||||
identifiers.push(IdWithIdentifier {
|
identifiers.push(MatchingRule::Simple(IdWithIdentifier {
|
||||||
kind: identifier,
|
kind: identifier,
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SocketMessage::ManageFocusedWindow => {
|
SocketMessage::ManageFocusedWindow => {
|
||||||
|
|||||||
+126
-198
@@ -34,9 +34,11 @@ use color_eyre::Result;
|
|||||||
use crossbeam_channel::Receiver;
|
use crossbeam_channel::Receiver;
|
||||||
use hotwatch::EventKind;
|
use hotwatch::EventKind;
|
||||||
use hotwatch::Hotwatch;
|
use hotwatch::Hotwatch;
|
||||||
|
use komorebi_core::config_generation::ApplicationConfiguration;
|
||||||
use komorebi_core::config_generation::ApplicationConfigurationGenerator;
|
use komorebi_core::config_generation::ApplicationConfigurationGenerator;
|
||||||
use komorebi_core::config_generation::ApplicationOptions;
|
use komorebi_core::config_generation::ApplicationOptions;
|
||||||
use komorebi_core::config_generation::IdWithIdentifier;
|
use komorebi_core::config_generation::IdWithIdentifier;
|
||||||
|
use komorebi_core::config_generation::MatchingRule;
|
||||||
use komorebi_core::config_generation::MatchingStrategy;
|
use komorebi_core::config_generation::MatchingStrategy;
|
||||||
use komorebi_core::resolve_home_path;
|
use komorebi_core::resolve_home_path;
|
||||||
use komorebi_core::ApplicationIdentifier;
|
use komorebi_core::ApplicationIdentifier;
|
||||||
@@ -269,22 +271,22 @@ pub struct StaticConfig {
|
|||||||
pub global_work_area_offset: Option<Rect>,
|
pub global_work_area_offset: Option<Rect>,
|
||||||
/// Individual window floating rules
|
/// Individual window floating rules
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub float_rules: Option<Vec<IdWithIdentifier>>,
|
pub float_rules: Option<Vec<MatchingRule>>,
|
||||||
/// Individual window force-manage rules
|
/// Individual window force-manage rules
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub manage_rules: Option<Vec<IdWithIdentifier>>,
|
pub manage_rules: Option<Vec<MatchingRule>>,
|
||||||
/// Identify border overflow applications
|
/// Identify border overflow applications
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub border_overflow_applications: Option<Vec<IdWithIdentifier>>,
|
pub border_overflow_applications: Option<Vec<MatchingRule>>,
|
||||||
/// Identify tray and multi-window applications
|
/// Identify tray and multi-window applications
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub tray_and_multi_window_applications: Option<Vec<IdWithIdentifier>>,
|
pub tray_and_multi_window_applications: Option<Vec<MatchingRule>>,
|
||||||
/// Identify applications that have the WS_EX_LAYERED extended window style
|
/// Identify applications that have the WS_EX_LAYERED extended window style
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub layered_applications: Option<Vec<IdWithIdentifier>>,
|
pub layered_applications: Option<Vec<MatchingRule>>,
|
||||||
/// Identify applications that send EVENT_OBJECT_NAMECHANGE on launch (very rare)
|
/// Identify applications that send EVENT_OBJECT_NAMECHANGE on launch (very rare)
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub object_name_change_applications: Option<Vec<IdWithIdentifier>>,
|
pub object_name_change_applications: Option<Vec<MatchingRule>>,
|
||||||
/// Set monitor index preferences
|
/// Set monitor index preferences
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub monitor_index_preferences: Option<HashMap<usize, Rect>>,
|
pub monitor_index_preferences: Option<HashMap<usize, Rect>>,
|
||||||
@@ -452,106 +454,40 @@ impl StaticConfig {
|
|||||||
let mut object_name_change_identifiers = OBJECT_NAME_CHANGE_ON_LAUNCH.lock();
|
let mut object_name_change_identifiers = OBJECT_NAME_CHANGE_ON_LAUNCH.lock();
|
||||||
let mut layered_identifiers = LAYERED_WHITELIST.lock();
|
let mut layered_identifiers = LAYERED_WHITELIST.lock();
|
||||||
|
|
||||||
if let Some(float) = &mut self.float_rules {
|
if let Some(rules) = &mut self.float_rules {
|
||||||
for identifier in float {
|
populate_rules(rules, &mut float_identifiers, &mut regex_identifiers)?;
|
||||||
if identifier.matching_strategy.is_none() {
|
|
||||||
identifier.matching_strategy = Option::from(MatchingStrategy::Legacy);
|
|
||||||
}
|
|
||||||
|
|
||||||
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(manage) = &mut self.manage_rules {
|
if let Some(rules) = &mut self.manage_rules {
|
||||||
for identifier in manage {
|
populate_rules(rules, &mut manage_identifiers, &mut regex_identifiers)?;
|
||||||
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) = &mut self.object_name_change_applications {
|
if let Some(rules) = &mut self.object_name_change_applications {
|
||||||
for identifier in identifiers {
|
populate_rules(
|
||||||
if identifier.matching_strategy.is_none() {
|
rules,
|
||||||
identifier.matching_strategy = Option::from(MatchingStrategy::Legacy);
|
&mut object_name_change_identifiers,
|
||||||
}
|
&mut regex_identifiers,
|
||||||
|
)?;
|
||||||
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) = &mut self.layered_applications {
|
if let Some(rules) = &mut self.layered_applications {
|
||||||
for identifier in identifiers {
|
populate_rules(rules, &mut layered_identifiers, &mut regex_identifiers)?;
|
||||||
if identifier.matching_strategy.is_none() {
|
|
||||||
identifier.matching_strategy = Option::from(MatchingStrategy::Legacy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !layered_identifiers.contains(identifier) {
|
|
||||||
layered_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) = &mut self.border_overflow_applications {
|
if let Some(rules) = &mut self.border_overflow_applications {
|
||||||
for identifier in identifiers {
|
populate_rules(
|
||||||
if identifier.matching_strategy.is_none() {
|
rules,
|
||||||
identifier.matching_strategy = Option::from(MatchingStrategy::Legacy);
|
&mut border_overflow_identifiers,
|
||||||
}
|
&mut regex_identifiers,
|
||||||
|
)?;
|
||||||
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) = &mut self.tray_and_multi_window_applications {
|
if let Some(rules) = &mut self.tray_and_multi_window_applications {
|
||||||
for identifier in identifiers {
|
populate_rules(
|
||||||
if identifier.matching_strategy.is_none() {
|
rules,
|
||||||
identifier.matching_strategy = Option::from(MatchingStrategy::Legacy);
|
&mut tray_and_multi_window_identifiers,
|
||||||
}
|
&mut regex_identifiers,
|
||||||
|
)?;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(path) = &self.app_specific_configuration_path {
|
if let Some(path) = &self.app_specific_configuration_path {
|
||||||
@@ -560,120 +496,48 @@ impl StaticConfig {
|
|||||||
let asc = ApplicationConfigurationGenerator::load(&content)?;
|
let asc = ApplicationConfigurationGenerator::load(&content)?;
|
||||||
|
|
||||||
for mut entry in asc {
|
for mut entry in asc {
|
||||||
if let Some(float) = entry.float_identifiers {
|
if let Some(rules) = &mut entry.float_identifiers {
|
||||||
for f in float {
|
populate_rules(rules, &mut float_identifiers, &mut regex_identifiers)?;
|
||||||
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());
|
|
||||||
|
|
||||||
if matches!(
|
|
||||||
without_comment.matching_strategy,
|
|
||||||
Some(MatchingStrategy::Regex)
|
|
||||||
) {
|
|
||||||
let re = Regex::new(&without_comment.id)?;
|
|
||||||
regex_identifiers.insert(without_comment.id.clone(), re);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(options) = entry.options {
|
|
||||||
|
if let Some(ref options) = entry.options {
|
||||||
|
let options = options.clone();
|
||||||
for o in options {
|
for o in options {
|
||||||
match o {
|
match o {
|
||||||
ApplicationOptions::ObjectNameChange => {
|
ApplicationOptions::ObjectNameChange => {
|
||||||
if entry.identifier.matching_strategy.is_none() {
|
populate_option(
|
||||||
entry.identifier.matching_strategy =
|
&mut entry,
|
||||||
Option::from(MatchingStrategy::Legacy);
|
&mut object_name_change_identifiers,
|
||||||
}
|
&mut regex_identifiers,
|
||||||
|
)?;
|
||||||
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 => {
|
ApplicationOptions::Layered => {
|
||||||
if entry.identifier.matching_strategy.is_none() {
|
populate_option(
|
||||||
entry.identifier.matching_strategy =
|
&mut entry,
|
||||||
Option::from(MatchingStrategy::Legacy);
|
&mut layered_identifiers,
|
||||||
}
|
&mut regex_identifiers,
|
||||||
|
)?;
|
||||||
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 => {
|
ApplicationOptions::BorderOverflow => {
|
||||||
if entry.identifier.matching_strategy.is_none() {
|
populate_option(
|
||||||
entry.identifier.matching_strategy =
|
&mut entry,
|
||||||
Option::from(MatchingStrategy::Legacy);
|
&mut border_overflow_identifiers,
|
||||||
}
|
&mut regex_identifiers,
|
||||||
|
)?;
|
||||||
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 => {
|
ApplicationOptions::TrayAndMultiWindow => {
|
||||||
if entry.identifier.matching_strategy.is_none() {
|
populate_option(
|
||||||
entry.identifier.matching_strategy =
|
&mut entry,
|
||||||
Option::from(MatchingStrategy::Legacy);
|
&mut tray_and_multi_window_identifiers,
|
||||||
}
|
&mut regex_identifiers,
|
||||||
|
)?;
|
||||||
if !tray_and_multi_window_identifiers.contains(&entry.identifier) {
|
|
||||||
tray_and_multi_window_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::Force => {
|
ApplicationOptions::Force => {
|
||||||
if entry.identifier.matching_strategy.is_none() {
|
populate_option(
|
||||||
entry.identifier.matching_strategy =
|
&mut entry,
|
||||||
Option::from(MatchingStrategy::Legacy);
|
&mut manage_identifiers,
|
||||||
}
|
&mut regex_identifiers,
|
||||||
|
)?;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -901,3 +765,67 @@ impl StaticConfig {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn populate_option(
|
||||||
|
entry: &mut ApplicationConfiguration,
|
||||||
|
identifiers: &mut Vec<MatchingRule>,
|
||||||
|
regex_identifiers: &mut HashMap<String, Regex>,
|
||||||
|
) -> Result<()> {
|
||||||
|
if entry.identifier.matching_strategy.is_none() {
|
||||||
|
entry.identifier.matching_strategy = Option::from(MatchingStrategy::Legacy);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rule = MatchingRule::Simple(entry.identifier.clone());
|
||||||
|
|
||||||
|
if !identifiers.contains(&rule) {
|
||||||
|
identifiers.push(rule);
|
||||||
|
|
||||||
|
if matches!(
|
||||||
|
entry.identifier.matching_strategy,
|
||||||
|
Some(MatchingStrategy::Regex)
|
||||||
|
) {
|
||||||
|
let re = Regex::new(&entry.identifier.id)?;
|
||||||
|
regex_identifiers.insert(entry.identifier.id.clone(), re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn populate_rules(
|
||||||
|
matching_rules: &mut Vec<MatchingRule>,
|
||||||
|
identifiers: &mut Vec<MatchingRule>,
|
||||||
|
regex_identifiers: &mut HashMap<String, Regex>,
|
||||||
|
) -> Result<()> {
|
||||||
|
for matching_rule in matching_rules {
|
||||||
|
if !identifiers.contains(matching_rule) {
|
||||||
|
match matching_rule {
|
||||||
|
MatchingRule::Simple(simple) => {
|
||||||
|
if simple.matching_strategy.is_none() {
|
||||||
|
simple.matching_strategy = Option::from(MatchingStrategy::Legacy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(simple.matching_strategy, Some(MatchingStrategy::Regex)) {
|
||||||
|
let re = Regex::new(&simple.id)?;
|
||||||
|
regex_identifiers.insert(simple.id.clone(), re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MatchingRule::Composite(composite) => {
|
||||||
|
for rule in composite {
|
||||||
|
if rule.matching_strategy.is_none() {
|
||||||
|
rule.matching_strategy = Option::from(MatchingStrategy::Legacy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(rule.matching_strategy, Some(MatchingStrategy::Regex)) {
|
||||||
|
let re = Regex::new(&rule.id)?;
|
||||||
|
regex_identifiers.insert(rule.id.clone(), re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
identifiers.push(matching_rule.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
+189
-142
@@ -10,6 +10,7 @@ use color_eyre::eyre;
|
|||||||
use color_eyre::eyre::anyhow;
|
use color_eyre::eyre::anyhow;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use komorebi_core::config_generation::IdWithIdentifier;
|
use komorebi_core::config_generation::IdWithIdentifier;
|
||||||
|
use komorebi_core::config_generation::MatchingRule;
|
||||||
use komorebi_core::config_generation::MatchingStrategy;
|
use komorebi_core::config_generation::MatchingStrategy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
@@ -506,157 +507,203 @@ pub fn should_act(
|
|||||||
exe_name: &str,
|
exe_name: &str,
|
||||||
class: &str,
|
class: &str,
|
||||||
path: &str,
|
path: &str,
|
||||||
identifiers: &[IdWithIdentifier],
|
identifiers: &[MatchingRule],
|
||||||
regex_identifiers: &HashMap<String, Regex>,
|
regex_identifiers: &HashMap<String, Regex>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut should_act = false;
|
let mut should_act = false;
|
||||||
for identifier in identifiers {
|
for identifier in identifiers {
|
||||||
match identifier.matching_strategy {
|
match identifier {
|
||||||
None => {
|
MatchingRule::Simple(identifier) => {
|
||||||
panic!("there is no matching strategy identified for this rule");
|
if should_act_individual(
|
||||||
|
title,
|
||||||
|
exe_name,
|
||||||
|
class,
|
||||||
|
path,
|
||||||
|
identifier,
|
||||||
|
regex_identifiers,
|
||||||
|
) {
|
||||||
|
should_act = true
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Some(MatchingStrategy::Legacy) => match identifier.kind {
|
MatchingRule::Composite(identifiers) => {
|
||||||
ApplicationIdentifier::Title => {
|
let mut composite_results = vec![];
|
||||||
if title.starts_with(&identifier.id) || title.ends_with(&identifier.id) {
|
for identifier in identifiers {
|
||||||
should_act = true;
|
composite_results.push(should_act_individual(
|
||||||
}
|
title,
|
||||||
|
exe_name,
|
||||||
|
class,
|
||||||
|
path,
|
||||||
|
identifier,
|
||||||
|
regex_identifiers,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
ApplicationIdentifier::Class => {
|
|
||||||
if class.starts_with(&identifier.id) || class.ends_with(&identifier.id) {
|
if composite_results.iter().all(|&x| x) {
|
||||||
should_act = true;
|
should_act = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ApplicationIdentifier::Exe => {
|
}
|
||||||
if exe_name.eq(&identifier.id) {
|
|
||||||
should_act = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ApplicationIdentifier::Path => {
|
|
||||||
if path.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ApplicationIdentifier::Path => {
|
|
||||||
if path.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ApplicationIdentifier::Path => {
|
|
||||||
if path.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ApplicationIdentifier::Path => {
|
|
||||||
if path.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ApplicationIdentifier::Path => {
|
|
||||||
if path.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ApplicationIdentifier::Path => {
|
|
||||||
if let Some(re) = regex_identifiers.get(&identifier.id) {
|
|
||||||
if re.is_match(path) {
|
|
||||||
should_act = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
should_act
|
should_act
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cognitive_complexity, clippy::too_many_lines)]
|
||||||
|
pub fn should_act_individual(
|
||||||
|
title: &str,
|
||||||
|
exe_name: &str,
|
||||||
|
class: &str,
|
||||||
|
path: &str,
|
||||||
|
identifier: &IdWithIdentifier,
|
||||||
|
regex_identifiers: &HashMap<String, Regex>,
|
||||||
|
) -> bool {
|
||||||
|
let mut should_act = false;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ApplicationIdentifier::Path => {
|
||||||
|
if path.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ApplicationIdentifier::Path => {
|
||||||
|
if path.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ApplicationIdentifier::Path => {
|
||||||
|
if path.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ApplicationIdentifier::Path => {
|
||||||
|
if path.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ApplicationIdentifier::Path => {
|
||||||
|
if path.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ApplicationIdentifier::Path => {
|
||||||
|
if let Some(re) = regex_identifiers.get(&identifier.id) {
|
||||||
|
if re.is_match(path) {
|
||||||
|
should_act = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
should_act
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use serde::Deserialize;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use uds_windows::UnixListener;
|
use uds_windows::UnixListener;
|
||||||
|
|
||||||
use komorebi_core::config_generation::IdWithIdentifier;
|
use komorebi_core::config_generation::MatchingRule;
|
||||||
use komorebi_core::custom_layout::CustomLayout;
|
use komorebi_core::custom_layout::CustomLayout;
|
||||||
use komorebi_core::Arrangement;
|
use komorebi_core::Arrangement;
|
||||||
use komorebi_core::Axis;
|
use komorebi_core::Axis;
|
||||||
@@ -97,12 +97,12 @@ pub struct State {
|
|||||||
pub mouse_follows_focus: bool,
|
pub mouse_follows_focus: bool,
|
||||||
pub has_pending_raise_op: bool,
|
pub has_pending_raise_op: bool,
|
||||||
pub remove_titlebars: bool,
|
pub remove_titlebars: bool,
|
||||||
pub float_identifiers: Vec<IdWithIdentifier>,
|
pub float_identifiers: Vec<MatchingRule>,
|
||||||
pub manage_identifiers: Vec<IdWithIdentifier>,
|
pub manage_identifiers: Vec<MatchingRule>,
|
||||||
pub layered_whitelist: Vec<IdWithIdentifier>,
|
pub layered_whitelist: Vec<MatchingRule>,
|
||||||
pub tray_and_multi_window_identifiers: Vec<IdWithIdentifier>,
|
pub tray_and_multi_window_identifiers: Vec<MatchingRule>,
|
||||||
pub border_overflow_identifiers: Vec<IdWithIdentifier>,
|
pub border_overflow_identifiers: Vec<MatchingRule>,
|
||||||
pub name_change_on_launch_identifiers: Vec<IdWithIdentifier>,
|
pub name_change_on_launch_identifiers: Vec<MatchingRule>,
|
||||||
pub monitor_index_preferences: HashMap<usize, Rect>,
|
pub monitor_index_preferences: HashMap<usize, Rect>,
|
||||||
pub display_index_preferences: HashMap<usize, String>,
|
pub display_index_preferences: HashMap<usize, String>,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user