feat(config): add object name change title ignore list

This commit adds a title regex-based ignore list for applications
identified in object_name_change_applications. When a title change on an
EVENT_OBJECT_NAMECHANGE matches one of these regexes, the event will
never be processed as a Show.

This is an edge case workaround specifically targeting the issue of web
apps in Gecko-based browsers which update their page titles at a fixed
regular interval, which was highlighted in #1235.

resolve #1235
This commit is contained in:
LGUG2Z
2025-01-24 15:50:43 -08:00
parent fcd1c9dcbe
commit 81c143d7c2
4 changed files with 71 additions and 12 deletions

View File

@@ -128,6 +128,7 @@ lazy_static! {
matching_strategy: Option::from(MatchingStrategy::Equals),
}),
]));
static ref OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST: Arc<Mutex<Vec<Regex>>> = Arc::new(Mutex::new(Vec::new()));
static ref TRANSPARENCY_BLACKLIST: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(Vec::new()));
static ref MONITOR_INDEX_PREFERENCES: Arc<Mutex<HashMap<usize, Rect>>> =
Arc::new(Mutex::new(HashMap::new()));

View File

@@ -52,6 +52,7 @@ use crate::MANAGE_IDENTIFIERS;
use crate::MONITOR_INDEX_PREFERENCES;
use crate::NO_TITLEBAR;
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
use crate::OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST;
use crate::REGEX_IDENTIFIERS;
use crate::SLOW_APPLICATION_COMPENSATION_TIME;
use crate::SLOW_APPLICATION_IDENTIFIERS;
@@ -357,6 +358,9 @@ pub struct StaticConfig {
/// Identify applications that send EVENT_OBJECT_NAMECHANGE on launch (very rare)
#[serde(skip_serializing_if = "Option::is_none")]
pub object_name_change_applications: Option<Vec<MatchingRule>>,
/// Do not process EVENT_OBJECT_NAMECHANGE events as Show events for identified applications matching these title regexes
#[serde(skip_serializing_if = "Option::is_none")]
pub object_name_change_title_ignore_list: Option<Vec<String>>,
/// Set monitor index preferences
#[serde(skip_serializing_if = "Option::is_none")]
pub monitor_index_preferences: Option<HashMap<usize, Rect>>,
@@ -631,7 +635,17 @@ impl From<&WindowManager> for StaticConfig {
border_overflow_applications: None,
tray_and_multi_window_applications: None,
layered_applications: None,
object_name_change_applications: None,
object_name_change_applications: Option::from(
OBJECT_NAME_CHANGE_ON_LAUNCH.lock().clone(),
),
object_name_change_title_ignore_list: Option::from(
OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST
.lock()
.clone()
.iter()
.map(|r| r.to_string())
.collect::<Vec<_>>(),
),
monitor_index_preferences: Option::from(MONITOR_INDEX_PREFERENCES.lock().clone()),
display_index_preferences: Option::from(DISPLAY_INDEX_PREFERENCES.lock().clone()),
stackbar: None,
@@ -790,6 +804,7 @@ impl StaticConfig {
let mut manage_identifiers = MANAGE_IDENTIFIERS.lock();
let mut tray_and_multi_window_identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock();
let mut object_name_change_identifiers = OBJECT_NAME_CHANGE_ON_LAUNCH.lock();
let mut object_name_change_title_ignore_list = OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST.lock();
let mut layered_identifiers = LAYERED_WHITELIST.lock();
let mut transparency_blacklist = TRANSPARENCY_BLACKLIST.lock();
let mut slow_application_identifiers = SLOW_APPLICATION_IDENTIFIERS.lock();
@@ -816,6 +831,17 @@ impl StaticConfig {
)?;
}
if let Some(regexes) = &mut self.object_name_change_title_ignore_list {
let mut updated = vec![];
for r in regexes {
if let Ok(regex) = Regex::new(r) {
updated.push(regex);
}
}
*object_name_change_title_ignore_list = updated;
}
if let Some(rules) = &mut self.layered_applications {
populate_rules(rules, &mut layered_identifiers, &mut regex_identifiers)?;
}

View File

@@ -9,6 +9,7 @@ use crate::window::should_act;
use crate::window::Window;
use crate::winevent::WinEvent;
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
use crate::OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST;
use crate::REGEX_IDENTIFIERS;
#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)]
@@ -176,6 +177,8 @@ impl WindowManagerEvent {
// [yatta\src\windows_event.rs:110] event = 32779 ObjectLocationChange
let object_name_change_on_launch = OBJECT_NAME_CHANGE_ON_LAUNCH.lock();
let object_name_change_title_ignore_list =
OBJECT_NAME_CHANGE_TITLE_IGNORE_LIST.lock();
let regex_identifiers = REGEX_IDENTIFIERS.lock();
let title = &window.title().ok()?;
@@ -183,7 +186,7 @@ impl WindowManagerEvent {
let class = &window.class().ok()?;
let path = &window.path().ok()?;
let should_trigger_show = should_act(
let mut should_trigger_show = should_act(
title,
exe_name,
class,
@@ -193,6 +196,14 @@ impl WindowManagerEvent {
)
.is_some();
if should_trigger_show {
for r in &*object_name_change_title_ignore_list {
if r.is_match(title) {
should_trigger_show = false;
}
}
}
// should not trigger show on minimized windows, for example when firefox sends
// this message due to youtube autoplay changing the window title
// https://github.com/LGUG2Z/komorebi/issues/941

View File

@@ -646,16 +646,30 @@
"description": "Aspect ratio to resize with when toggling floating mode for a window",
"anyOf": [
{
"description": "21:9",
"type": "null"
},
{
"description": "16:9",
"type": "null"
},
{
"description": "4:3",
"type": "null"
"description": "A predefined aspect ratio",
"oneOf": [
{
"description": "21:9",
"type": "string",
"enum": [
"Ultrawide"
]
},
{
"description": "16:9",
"type": "string",
"enum": [
"Widescreen"
]
},
{
"description": "4:3",
"type": "string",
"enum": [
"Standard"
]
}
]
},
{
"description": "A custom W:H aspect ratio",
@@ -1490,6 +1504,13 @@
]
}
},
"object_name_change_title_ignore_list": {
"description": "Do not process EVENT_OBJECT_NAMECHANGE events as Show events for identified applications matching these title regexes",
"type": "array",
"items": {
"type": "string"
}
},
"remove_titlebar_applications": {
"description": "HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars",
"type": "array",