feat(transparency): add ignore rules to config

This commit adds transparency_ignore_rules to the komorebi.json static
configuration format. Windows that match any rules given in this list
will not have transparency applied when they are unfocused.

For example, to ensure that a browser window is not made transparent
when the focused tab is a YouTube video:

```json
"transparency_ignore_rules": [
  {
    "kind": "Title",
    "id": "YouTube",
    "matching_strategy": "Contains"
  }
]
```
This commit is contained in:
LGUG2Z
2024-09-28 12:19:25 -07:00
parent a1f1be0afe
commit b7198242ff
6 changed files with 135 additions and 10 deletions

View File

@@ -50,5 +50,8 @@ schemagen:
cargo run --package komorebic -- application-specific-configuration-schema > schema.asc.json
cargo run --package komorebi-bar -- --schema > schema.bar.json
generate-schema-doc .\schema.json --config template_name=js_offline --config minify=false .\static-config-docs\
generate-schema-doc .\schema.bar.json --config template_name=js_offline --config minify=false .\bar-config-docs\
rm -Force .\bar-config-docs\schema.html
mv .\bar-config-docs\schema.bar.html .\bar-config-docs\schema.html

View File

@@ -130,6 +130,7 @@ lazy_static! {
matching_strategy: Option::from(MatchingStrategy::Equals),
}),
]));
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()));
static ref DISPLAY_INDEX_PREFERENCES: Arc<Mutex<HashMap<usize, String>>> =

View File

@@ -42,6 +42,7 @@ use crate::MANAGE_IDENTIFIERS;
use crate::MONITOR_INDEX_PREFERENCES;
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
use crate::REGEX_IDENTIFIERS;
use crate::TRANSPARENCY_BLACKLIST;
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
use crate::WINDOWS_11;
use crate::WORKSPACE_RULES;
@@ -313,6 +314,9 @@ pub struct StaticConfig {
/// Alpha value for unfocused window transparency [[0-255]] (default: 200)
#[serde(skip_serializing_if = "Option::is_none")]
pub transparency_alpha: Option<u8>,
/// Individual window transparency ignore rules
#[serde(skip_serializing_if = "Option::is_none")]
pub transparency_ignore_rules: Option<Vec<MatchingRule>>,
/// Global default workspace padding (default: 10)
#[serde(skip_serializing_if = "Option::is_none")]
pub default_workspace_padding: Option<i32>,
@@ -637,6 +641,7 @@ impl From<&WindowManager> for StaticConfig {
transparency_alpha: Option::from(
transparency_manager::TRANSPARENCY_ALPHA.load(Ordering::SeqCst),
),
transparency_ignore_rules: None,
border_style: Option::from(STYLE.load()),
border_z_order: Option::from(Z_ORDER.load()),
border_implementation: Option::from(IMPLEMENTATION.load()),
@@ -767,6 +772,7 @@ impl StaticConfig {
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 layered_identifiers = LAYERED_WHITELIST.lock();
let mut transparency_blacklist = TRANSPARENCY_BLACKLIST.lock();
if let Some(rules) = &mut self.float_rules {
populate_rules(rules, &mut float_identifiers, &mut regex_identifiers)?;
@@ -796,6 +802,10 @@ impl StaticConfig {
)?;
}
if let Some(rules) = &mut self.transparency_ignore_rules {
populate_rules(rules, &mut transparency_blacklist, &mut regex_identifiers)?;
}
if let Some(stackbar) = &self.stackbar {
if let Some(height) = &stackbar.height {
STACKBAR_TAB_HEIGHT.store(*height, Ordering::SeqCst);

View File

@@ -9,9 +9,12 @@ use std::sync::atomic::AtomicU8;
use std::sync::Arc;
use std::sync::OnceLock;
use crate::should_act;
use crate::Window;
use crate::WindowManager;
use crate::WindowsApi;
use crate::REGEX_IDENTIFIERS;
use crate::TRANSPARENCY_BLACKLIST;
pub static TRANSPARENCY_ENABLED: AtomicBool = AtomicBool::new(false);
pub static TRANSPARENCY_ALPHA: AtomicU8 = AtomicU8::new(200);
@@ -133,6 +136,9 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
continue 'monitors;
}
let transparency_blacklist = TRANSPARENCY_BLACKLIST.lock();
let regex_identifiers = REGEX_IDENTIFIERS.lock();
for (idx, c) in ws.containers().iter().enumerate() {
// Update the transparency for all containers on this workspace
@@ -143,15 +149,37 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
let focused_window_idx = c.focused_window_idx();
for (window_idx, window) in c.windows().iter().enumerate() {
if window_idx == focused_window_idx {
match window.transparent() {
Err(error) => {
let hwnd = foreground_hwnd;
tracing::error!(
"failed to make unfocused window {hwnd} transparent: {error}"
)
let mut should_make_transparent = true;
if !transparency_blacklist.is_empty() {
if let (Ok(title), Ok(exe_name), Ok(class), Ok(path)) = (
window.title(),
window.exe(),
window.class(),
window.path(),
) {
let is_blacklisted = should_act(
&title,
&exe_name,
&class,
&path,
&transparency_blacklist,
&regex_identifiers,
)
.is_some();
should_make_transparent = !is_blacklisted;
}
Ok(..) => {
known_hwnds.lock().push(window.hwnd);
}
if should_make_transparent {
match window.transparent() {
Err(error) => {
let hwnd = foreground_hwnd;
tracing::error!("failed to make unfocused window {hwnd} transparent: {error}" )
}
Ok(..) => {
known_hwnds.lock().push(window.hwnd);
}
}
}
} else {

View File

@@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "KomobarConfig",
"description": "The `komorebi.bar.json` configuration file reference for `v0.1.29`",
"description": "The `komorebi.bar.json` configuration file reference for `v0.1.30`",
"type": "object",
"required": [
"left_widgets",

View File

@@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "StaticConfig",
"description": "The `komorebi.json` static configuration file reference for `v0.1.29`",
"description": "The `komorebi.json` static configuration file reference for `v0.1.30`",
"type": "object",
"properties": {
"animation": {
@@ -2076,6 +2076,89 @@
"format": "uint8",
"minimum": 0.0
},
"transparency_ignore_rules": {
"description": "Individual window transparency ignore rules",
"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"
]
}
}
}
}
]
}
},
"tray_and_multi_window_applications": {
"description": "Identify tray and multi-window applications",
"type": "array",