mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-14 00:52:54 +02:00
feat(config): add matchers for removing titlebars
This commit adds a new field to the static config file, "remove_titlebar_applications", which allows users to now use the full range of matching strategies to identify applications for which titlebars should be removed. This is heavily discouraged for a number of reasons, and is unlikely to work with a wide range of applications which now draw their own titlebar regions. The previous advice to use in-application configuration settings to hide title bars if they exist is still valid. resolve #805
This commit is contained in:
+1
-1
@@ -215,7 +215,7 @@ lazy_static! {
|
|||||||
|
|
||||||
// Use app-specific titlebar removal options where possible
|
// Use app-specific titlebar removal options where possible
|
||||||
// eg. Windows Terminal, IntelliJ IDEA, Firefox
|
// eg. Windows Terminal, IntelliJ IDEA, Firefox
|
||||||
static ref NO_TITLEBAR: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
|
static ref NO_TITLEBAR: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![]));
|
||||||
|
|
||||||
static ref WINDOWS_BY_BAR_HWNDS: Arc<Mutex<HashMap<isize, VecDeque<isize>>>> =
|
static ref WINDOWS_BY_BAR_HWNDS: Arc<Mutex<HashMap<isize, VecDeque<isize>>>> =
|
||||||
Arc::new(Mutex::new(HashMap::new()));
|
Arc::new(Mutex::new(HashMap::new()));
|
||||||
|
|||||||
@@ -1667,10 +1667,24 @@ impl WindowManager {
|
|||||||
|
|
||||||
reply.write_all(config.as_bytes())?;
|
reply.write_all(config.as_bytes())?;
|
||||||
}
|
}
|
||||||
SocketMessage::RemoveTitleBar(_, ref id) => {
|
SocketMessage::RemoveTitleBar(identifier, ref id) => {
|
||||||
let mut identifiers = NO_TITLEBAR.lock();
|
let mut identifiers = NO_TITLEBAR.lock();
|
||||||
if !identifiers.contains(id) {
|
|
||||||
identifiers.push(id.clone());
|
let mut should_push = true;
|
||||||
|
for i in &*identifiers {
|
||||||
|
if let MatchingRule::Simple(i) = i {
|
||||||
|
if i.id.eq(id) {
|
||||||
|
should_push = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if should_push {
|
||||||
|
identifiers.push(MatchingRule::Simple(IdWithIdentifier {
|
||||||
|
kind: identifier,
|
||||||
|
id: id.clone(),
|
||||||
|
matching_strategy: Option::from(MatchingStrategy::Legacy),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SocketMessage::ToggleTitleBars => {
|
SocketMessage::ToggleTitleBars => {
|
||||||
|
|||||||
@@ -353,10 +353,11 @@ impl WindowManager {
|
|||||||
|
|
||||||
if !workspace_contains_window && !needs_reconciliation {
|
if !workspace_contains_window && !needs_reconciliation {
|
||||||
let floating_applications = FLOATING_APPLICATIONS.lock();
|
let floating_applications = FLOATING_APPLICATIONS.lock();
|
||||||
let regex_identifiers = REGEX_IDENTIFIERS.lock();
|
|
||||||
let mut should_float = false;
|
let mut should_float = false;
|
||||||
|
|
||||||
if !floating_applications.is_empty() {
|
if !floating_applications.is_empty() {
|
||||||
|
let regex_identifiers = REGEX_IDENTIFIERS.lock();
|
||||||
|
|
||||||
if let (Ok(title), Ok(exe_name), Ok(class), Ok(path)) =
|
if let (Ok(title), Ok(exe_name), Ok(class), Ok(path)) =
|
||||||
(window.title(), window.exe(), window.class(), window.path())
|
(window.title(), window.exe(), window.class(), window.path())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ use crate::IGNORE_IDENTIFIERS;
|
|||||||
use crate::LAYERED_WHITELIST;
|
use crate::LAYERED_WHITELIST;
|
||||||
use crate::MANAGE_IDENTIFIERS;
|
use crate::MANAGE_IDENTIFIERS;
|
||||||
use crate::MONITOR_INDEX_PREFERENCES;
|
use crate::MONITOR_INDEX_PREFERENCES;
|
||||||
|
use crate::NO_TITLEBAR;
|
||||||
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
|
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
|
||||||
use crate::REGEX_IDENTIFIERS;
|
use crate::REGEX_IDENTIFIERS;
|
||||||
use crate::SLOW_APPLICATION_COMPENSATION_TIME;
|
use crate::SLOW_APPLICATION_COMPENSATION_TIME;
|
||||||
@@ -373,6 +374,9 @@ pub struct StaticConfig {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
// this option is a little special because it is only consumed by komorebic
|
// this option is a little special because it is only consumed by komorebic
|
||||||
pub bar_configurations: Option<Vec<PathBuf>>,
|
pub bar_configurations: Option<Vec<PathBuf>>,
|
||||||
|
/// HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub remove_titlebar_applications: Option<Vec<MatchingRule>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
@@ -627,6 +631,7 @@ impl From<&WindowManager> for StaticConfig {
|
|||||||
),
|
),
|
||||||
slow_application_identifiers: Option::from(SLOW_APPLICATION_IDENTIFIERS.lock().clone()),
|
slow_application_identifiers: Option::from(SLOW_APPLICATION_IDENTIFIERS.lock().clone()),
|
||||||
bar_configurations: None,
|
bar_configurations: None,
|
||||||
|
remove_titlebar_applications: Option::from(NO_TITLEBAR.lock().clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -773,6 +778,7 @@ impl StaticConfig {
|
|||||||
let mut transparency_blacklist = TRANSPARENCY_BLACKLIST.lock();
|
let mut transparency_blacklist = TRANSPARENCY_BLACKLIST.lock();
|
||||||
let mut slow_application_identifiers = SLOW_APPLICATION_IDENTIFIERS.lock();
|
let mut slow_application_identifiers = SLOW_APPLICATION_IDENTIFIERS.lock();
|
||||||
let mut floating_applications = FLOATING_APPLICATIONS.lock();
|
let mut floating_applications = FLOATING_APPLICATIONS.lock();
|
||||||
|
let mut no_titlebar_applications = NO_TITLEBAR.lock();
|
||||||
|
|
||||||
if let Some(rules) = &mut self.ignore_rules {
|
if let Some(rules) = &mut self.ignore_rules {
|
||||||
populate_rules(rules, &mut ignore_identifiers, &mut regex_identifiers)?;
|
populate_rules(rules, &mut ignore_identifiers, &mut regex_identifiers)?;
|
||||||
@@ -818,6 +824,10 @@ impl StaticConfig {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(rules) = &mut self.remove_titlebar_applications {
|
||||||
|
populate_rules(rules, &mut no_titlebar_applications, &mut regex_identifiers)?;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(stackbar) = &self.stackbar {
|
if let Some(stackbar) = &self.stackbar {
|
||||||
if let Some(height) = &stackbar.height {
|
if let Some(height) = &stackbar.height {
|
||||||
STACKBAR_TAB_HEIGHT.store(*height, Ordering::SeqCst);
|
STACKBAR_TAB_HEIGHT.store(*height, Ordering::SeqCst);
|
||||||
|
|||||||
+14
-4
@@ -784,7 +784,7 @@ pub struct RuleDebug {
|
|||||||
pub matches_layered_whitelist: Option<MatchingRule>,
|
pub matches_layered_whitelist: Option<MatchingRule>,
|
||||||
pub matches_floating_applications: Option<MatchingRule>,
|
pub matches_floating_applications: Option<MatchingRule>,
|
||||||
pub matches_wsl2_gui: Option<String>,
|
pub matches_wsl2_gui: Option<String>,
|
||||||
pub matches_no_titlebar: Option<String>,
|
pub matches_no_titlebar: Option<MatchingRule>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
@@ -889,9 +889,19 @@ fn window_is_eligible(
|
|||||||
allow
|
allow
|
||||||
};
|
};
|
||||||
|
|
||||||
let allow_titlebar_removed = {
|
let titlebars_removed = NO_TITLEBAR.lock();
|
||||||
let titlebars_removed = NO_TITLEBAR.lock();
|
let allow_titlebar_removed = if let Some(rule) = should_act(
|
||||||
titlebars_removed.contains(exe_name)
|
title,
|
||||||
|
exe_name,
|
||||||
|
class,
|
||||||
|
path,
|
||||||
|
&titlebars_removed,
|
||||||
|
®ex_identifiers,
|
||||||
|
) {
|
||||||
|
debug.matches_no_titlebar = Some(rule);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ use crate::current_virtual_desktop;
|
|||||||
use crate::load_configuration;
|
use crate::load_configuration;
|
||||||
use crate::monitor::Monitor;
|
use crate::monitor::Monitor;
|
||||||
use crate::ring::Ring;
|
use crate::ring::Ring;
|
||||||
|
use crate::should_act;
|
||||||
use crate::should_act_individual;
|
use crate::should_act_individual;
|
||||||
use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR;
|
use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR;
|
||||||
use crate::stackbar_manager::STACKBAR_LABEL;
|
use crate::stackbar_manager::STACKBAR_LABEL;
|
||||||
@@ -1430,6 +1431,7 @@ impl WindowManager {
|
|||||||
tracing::info!("restoring all hidden windows");
|
tracing::info!("restoring all hidden windows");
|
||||||
|
|
||||||
let no_titlebar = NO_TITLEBAR.lock();
|
let no_titlebar = NO_TITLEBAR.lock();
|
||||||
|
let regex_identifiers = REGEX_IDENTIFIERS.lock();
|
||||||
let known_transparent_hwnds = transparency_manager::known_hwnds();
|
let known_transparent_hwnds = transparency_manager::known_hwnds();
|
||||||
let border_implementation = border_manager::IMPLEMENTATION.load();
|
let border_implementation = border_manager::IMPLEMENTATION.load();
|
||||||
|
|
||||||
@@ -1445,7 +1447,17 @@ impl WindowManager {
|
|||||||
|
|
||||||
for containers in workspace.containers_mut() {
|
for containers in workspace.containers_mut() {
|
||||||
for window in containers.windows_mut() {
|
for window in containers.windows_mut() {
|
||||||
if no_titlebar.contains(&window.exe()?) {
|
let should_remove_titlebar_for_window = should_act(
|
||||||
|
&window.title().unwrap_or_default(),
|
||||||
|
&window.exe().unwrap_or_default(),
|
||||||
|
&window.class().unwrap_or_default(),
|
||||||
|
&window.path().unwrap_or_default(),
|
||||||
|
&no_titlebar,
|
||||||
|
®ex_identifiers,
|
||||||
|
)
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
if should_remove_titlebar_for_window {
|
||||||
window.add_title_bar()?;
|
window.add_title_bar()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ use crate::border_manager::BORDER_OFFSET;
|
|||||||
use crate::border_manager::BORDER_WIDTH;
|
use crate::border_manager::BORDER_WIDTH;
|
||||||
use crate::container::Container;
|
use crate::container::Container;
|
||||||
use crate::ring::Ring;
|
use crate::ring::Ring;
|
||||||
|
use crate::should_act;
|
||||||
use crate::stackbar_manager;
|
use crate::stackbar_manager;
|
||||||
use crate::stackbar_manager::STACKBAR_TAB_HEIGHT;
|
use crate::stackbar_manager::STACKBAR_TAB_HEIGHT;
|
||||||
use crate::static_config::WorkspaceConfig;
|
use crate::static_config::WorkspaceConfig;
|
||||||
@@ -35,6 +36,7 @@ use crate::DEFAULT_CONTAINER_PADDING;
|
|||||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||||
use crate::INITIAL_CONFIGURATION_LOADED;
|
use crate::INITIAL_CONFIGURATION_LOADED;
|
||||||
use crate::NO_TITLEBAR;
|
use crate::NO_TITLEBAR;
|
||||||
|
use crate::REGEX_IDENTIFIERS;
|
||||||
use crate::REMOVE_TITLEBARS;
|
use crate::REMOVE_TITLEBARS;
|
||||||
|
|
||||||
#[allow(clippy::struct_field_names)]
|
#[allow(clippy::struct_field_names)]
|
||||||
@@ -354,6 +356,7 @@ impl Workspace {
|
|||||||
|
|
||||||
let should_remove_titlebars = REMOVE_TITLEBARS.load(Ordering::SeqCst);
|
let should_remove_titlebars = REMOVE_TITLEBARS.load(Ordering::SeqCst);
|
||||||
let no_titlebar = NO_TITLEBAR.lock().clone();
|
let no_titlebar = NO_TITLEBAR.lock().clone();
|
||||||
|
let regex_identifiers = REGEX_IDENTIFIERS.lock().clone();
|
||||||
|
|
||||||
let container_padding = self.container_padding().unwrap_or(0);
|
let container_padding = self.container_padding().unwrap_or(0);
|
||||||
let containers = self.containers_mut();
|
let containers = self.containers_mut();
|
||||||
@@ -383,9 +386,19 @@ impl Workspace {
|
|||||||
.focused_window()
|
.focused_window()
|
||||||
.is_some_and(|w| w.hwnd == window.hwnd)
|
.is_some_and(|w| w.hwnd == window.hwnd)
|
||||||
{
|
{
|
||||||
if should_remove_titlebars && no_titlebar.contains(&window.exe()?) {
|
let should_remove_titlebar_for_window = should_act(
|
||||||
|
&window.title().unwrap_or_default(),
|
||||||
|
&window.exe().unwrap_or_default(),
|
||||||
|
&window.class().unwrap_or_default(),
|
||||||
|
&window.path().unwrap_or_default(),
|
||||||
|
&no_titlebar,
|
||||||
|
®ex_identifiers,
|
||||||
|
)
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
if should_remove_titlebars && should_remove_titlebar_for_window {
|
||||||
window.remove_title_bar()?;
|
window.remove_title_bar()?;
|
||||||
} else if no_titlebar.contains(&window.exe()?) {
|
} else if should_remove_titlebar_for_window {
|
||||||
window.add_title_bar()?;
|
window.add_title_bar()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1122,6 +1122,11 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"icon_scale": {
|
||||||
|
"description": "Scale of the icons relative to the font_size [[1.0-2.0]]. (default: 1.4)",
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
},
|
||||||
"left_widgets": {
|
"left_widgets": {
|
||||||
"description": "Left side widgets (ordered left-to-right)",
|
"description": "Left side widgets (ordered left-to-right)",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
|||||||
+83
@@ -1448,6 +1448,89 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"remove_titlebar_applications": {
|
||||||
|
"description": "HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Exe",
|
||||||
|
"Class",
|
||||||
|
"Title",
|
||||||
|
"Path"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"matching_strategy": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Legacy",
|
||||||
|
"Equals",
|
||||||
|
"StartsWith",
|
||||||
|
"EndsWith",
|
||||||
|
"Contains",
|
||||||
|
"Regex",
|
||||||
|
"DoesNotEndWith",
|
||||||
|
"DoesNotStartWith",
|
||||||
|
"DoesNotEqual",
|
||||||
|
"DoesNotContain"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Exe",
|
||||||
|
"Class",
|
||||||
|
"Title",
|
||||||
|
"Path"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"matching_strategy": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Legacy",
|
||||||
|
"Equals",
|
||||||
|
"StartsWith",
|
||||||
|
"EndsWith",
|
||||||
|
"Contains",
|
||||||
|
"Regex",
|
||||||
|
"DoesNotEndWith",
|
||||||
|
"DoesNotStartWith",
|
||||||
|
"DoesNotEqual",
|
||||||
|
"DoesNotContain"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"resize_delta": {
|
"resize_delta": {
|
||||||
"description": "Delta to resize windows by (default 50)",
|
"description": "Delta to resize windows by (default 50)",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
|||||||
Reference in New Issue
Block a user