diff --git a/README.md b/README.md index f1842e6..3695acd 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ Options: -n, --no-dim-when-only Don't dim when switching to a workspace that only has one visible window -i, --ignore-entering-special Don't dim when opening a special workspace -I, --ignore-leaving-special Don't dim when closing a special workspace + -D, --dialog-dim [] Dim windows if they're the same class and floating (strength_default: 0.7) -v, --verbose Show information about what hyprdim is doing -h, --help Print help (see more with '--help') -V, --version Print version diff --git a/completions/_hyprdim b/completions/_hyprdim index e3b0555..b2cbbe2 100644 --- a/completions/_hyprdim +++ b/completions/_hyprdim @@ -23,6 +23,8 @@ _hyprdim() { '--fade=[Fade animation speed from 0 (instantaneous) to 255 (very slow)]:FADE: ' \ '-b+[Bezier curve used for the animation]:BEZIER: ' \ '--bezier=[Bezier curve used for the animation]:BEZIER: ' \ +'-D+[Dim windows if they'\''re the same class and floating (strength_default\: 0.7)]' \ +'--dialog-dim=[Dim windows if they'\''re the same class and floating (strength_default\: 0.7)]' \ '-p[Prevent dim_inactive from being disabled by \`hyprctl reload\` etc]' \ '--persist[Prevent dim_inactive from being disabled by \`hyprctl reload\` etc]' \ '-n[Don'\''t dim when switching to a workspace that only has one visible window]' \ diff --git a/completions/hyprdim.bash b/completions/hyprdim.bash index c6912b1..9b31880 100644 --- a/completions/hyprdim.bash +++ b/completions/hyprdim.bash @@ -19,7 +19,7 @@ _hyprdim() { case "${cmd}" in hyprdim) - opts="-s -d -f -b -p -n -i -I -v -h -V --strength --duration --fade --bezier --persist --no-dim-when-only --ignore-entering-special --ignore-leaving-special --verbose --help --version" + opts="-s -d -f -b -p -n -i -I -D -v -h -V --strength --duration --fade --bezier --persist --no-dim-when-only --ignore-entering-special --ignore-leaving-special --dialog-dim --verbose --help --version" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -57,6 +57,14 @@ _hyprdim() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --dialog-dim) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -D) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; diff --git a/completions/hyprdim.fish b/completions/hyprdim.fish index 2217ddb..6d2406f 100644 --- a/completions/hyprdim.fish +++ b/completions/hyprdim.fish @@ -2,6 +2,7 @@ complete -c hyprdim -s s -l strength -d 'A value from 0 (no dim) to 1 (maximum d complete -c hyprdim -s d -l duration -d 'How many milliseconds to wait before removing dim' -r complete -c hyprdim -s f -l fade -d 'Fade animation speed from 0 (instantaneous) to 255 (very slow)' -r complete -c hyprdim -s b -l bezier -d 'Bezier curve used for the animation' -r +complete -c hyprdim -s D -l dialog-dim -d 'Dim windows if they\'re the same class and floating (strength_default: 0.7)' -r complete -c hyprdim -s p -l persist -d 'Prevent dim_inactive from being disabled by `hyprctl reload` etc' complete -c hyprdim -s n -l no-dim-when-only -d 'Don\'t dim when switching to a workspace that only has one visible window' complete -c hyprdim -s i -l ignore-entering-special -d 'Don\'t dim when opening a special workspace' diff --git a/man/hyprdim.1 b/man/hyprdim.1 index 27a610f..fad998e 100644 --- a/man/hyprdim.1 +++ b/man/hyprdim.1 @@ -4,7 +4,7 @@ .SH NAME hyprdim \- Automatically dim windows in Hyprland when switching between them. .SH SYNOPSIS -\fBhyprdim\fR [\fB\-s\fR|\fB\-\-strength\fR] [\fB\-d\fR|\fB\-\-duration\fR] [\fB\-f\fR|\fB\-\-fade\fR] [\fB\-b\fR|\fB\-\-bezier\fR] [\fB\-p\fR|\fB\-\-persist\fR] [\fB\-n\fR|\fB\-\-no\-dim\-when\-only\fR] [\fB\-i\fR|\fB\-\-ignore\-entering\-special\fR] [\fB\-I\fR|\fB\-\-ignore\-leaving\-special\fR] [\fB\-v\fR|\fB\-\-verbose\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] +\fBhyprdim\fR [\fB\-s\fR|\fB\-\-strength\fR] [\fB\-d\fR|\fB\-\-duration\fR] [\fB\-f\fR|\fB\-\-fade\fR] [\fB\-b\fR|\fB\-\-bezier\fR] [\fB\-p\fR|\fB\-\-persist\fR] [\fB\-n\fR|\fB\-\-no\-dim\-when\-only\fR] [\fB\-i\fR|\fB\-\-ignore\-entering\-special\fR] [\fB\-I\fR|\fB\-\-ignore\-leaving\-special\fR] [\fB\-D\fR|\fB\-\-dialog\-dim\fR] [\fB\-v\fR|\fB\-\-verbose\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] .SH DESCRIPTION .PP hyprdim is a daemon that automatically dims windows in Hyprland[1] when @@ -74,6 +74,17 @@ Don\*(Aqt dim when closing a special workspace This is useful if you have multiple windows in your main workspace and usually don\*(Aqt switch between them. .TP +\fB\-D\fR, \fB\-\-dialog\-dim\fR=\fISTRENGTH\fR +Dim windows if they\*(Aqre the same class and floating (strength_default: 0.7) + +This option is particularly useful for dimming dialog boxes started by applications since those tend to have the same class and be floating. + +The dim is a permanent dim while working in the floating window of the same class. + +Note that the dim is removed when switching workspaces or doing any other event. + +Optionally specify a strength value to change how much dim is applied to dialog windows. The default strength value is 0.7. +.TP \fB\-v\fR, \fB\-\-verbose\fR Show information about what hyprdim is doing .TP diff --git a/src/cli.rs b/src/cli.rs index 804897b..6cf4e86 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -91,6 +91,20 @@ pub struct Cli { #[arg(short = 'I', long, default_value_t = false)] pub ignore_leaving_special: bool, + /// Dim windows if they're the same class and floating (strength_default: 0.7) + /// + /// This option is particularly useful for dimming dialog boxes started by applications + /// since those tend to have the same class and be floating. + /// + /// The dim is a permanent dim while working in the floating window of the same class. + /// + /// Note that the dim is removed when switching workspaces or doing any other event. + /// + /// Optionally specify a strength value to change how much dim is applied to dialog windows. + /// The default strength value is 0.7. + #[arg(short = 'D', long, value_name = "STRENGTH", default_value = None, default_missing_value = "0.7", num_args = 0..=1)] + pub dialog_dim: Option, + /// Show information about what hyprdim is doing #[arg(short, long, default_value_t = false)] pub verbose: bool, diff --git a/src/lib.rs b/src/lib.rs index 00d39f9..0ff2baf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ pub fn log(text: &str) { /// enough, dimming is disabled. pub fn spawn_dim_thread( num_threads: Arc>, + is_set_dim: Arc>, strength: f64, persist: bool, duration: u64, @@ -43,17 +44,33 @@ pub fn spawn_dim_thread( thread::sleep(time::Duration::from_millis(duration)); *num_threads.lock().unwrap() -= 1; - // If this is the last thread, remove dim + // If this is the last thread and we're not setting dim, remove dim if *num_threads.lock().unwrap() == 0 { - Keyword::set("decoration:dim_strength", 0)?; + if *is_set_dim.lock().unwrap() { + log("info: Last thread, but not removing dim since permanent dim is active"); + } else { + Keyword::set("decoration:dim_strength", 0)?; - log("info: Removed dim (last thread)"); + log("info: Removed dim (last thread)"); + } } Ok(()) }); } +pub fn set_dim(strength: f64, persist: bool) -> hyprland::Result<()> { + if persist { + Keyword::set("decoration:dim_inactive", "yes")?; + }; + + Keyword::set("decoration:dim_strength", strength)?; + + log("info: Set a permanent dim (until next event) without spawning thread"); + + Ok(()) +} + /// Gets whether the current workspace is a special workspace or not. /// /// This function works by getting which workspace the active window is in. @@ -89,3 +106,12 @@ pub fn special_only_has_one_visible_window() -> bool { false } + +pub fn is_floating() -> bool { + if let Some(client) = Client::get_active().unwrap() { + let Client { floating, .. } = client; + return floating; + } + + false +} diff --git a/src/main.rs b/src/main.rs index 4496aa5..bc7d679 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,9 @@ use clap::Parser; use cli::Cli; +use hyprdim::is_floating; use hyprdim::is_special; use hyprdim::log; +use hyprdim::set_dim; use hyprdim::spawn_dim_thread; use hyprdim::special_only_has_one_visible_window; use hyprland::data::Workspace; @@ -47,6 +49,7 @@ fn main() -> hyprland::Result<()> { no_dim_when_only, ignore_entering_special, ignore_leaving_special, + dialog_dim, .. } = Cli::parse(); @@ -58,6 +61,8 @@ fn main() -> hyprland::Result<()> { // Keep track of state let num_threads: Arc> = Arc::new(Mutex::new(0)); let last_address: Arc>> = Arc::new(Mutex::new(None)); + let last_class: Arc>> = Arc::new(Mutex::new(None)); + let is_set_dim: Arc> = Arc::new(Mutex::new(false)); let in_special_workspace: Arc> = Arc::new(Mutex::new(is_special())); // Initialize with dim so the user sees something, but only if the user wants dim @@ -68,16 +73,17 @@ fn main() -> hyprland::Result<()> { Keyword::set("decoration:dim_strength", 0)?; Keyword::set("decoration:dim_inactive", "yes")?; } else { - spawn_dim_thread(num_threads.clone(), strength, persist, duration, true); + spawn_dim_thread(num_threads.clone(), is_set_dim.clone(), strength, persist, duration, true); } // On active window changes event_listener.add_active_window_change_handler(move |data| { // Ignore the event if no window_address was given - let Some(WindowEventData { window_address, .. }) = data else { return }; + let Some(WindowEventData { window_address, window_class, .. }) = data else { return }; - // Clone inside since u16 does not implement copy + // Clone inside since primitives don't implement copy let num_threads = num_threads.clone(); + let is_set_dim = is_set_dim.clone(); // If the last address is the same as the new window, don't dim if let Some(ref old_address) = *last_address.lock().unwrap() { @@ -86,7 +92,16 @@ fn main() -> hyprland::Result<()> { } } + let mut same_class = false; + + if let Some(ref old_class) = *last_class.lock().unwrap() { + if format!("{old_class}") == format!("{window_class}") { + same_class = true; + } + } + *last_address.lock().unwrap() = Some(window_address.clone()); + *last_class.lock().unwrap() = Some(window_class.clone()); // Get the state of the current parent workspace let parent_workspace = Workspace::get_active().unwrap(); @@ -118,6 +133,16 @@ fn main() -> hyprland::Result<()> { } } + // Enable dim when using a floating windows with the same class as the last window, + // but only if the user specified the argument to do so. + if let Some(dialog_strength) = dialog_dim { + if same_class && is_floating() { + *is_set_dim.lock().unwrap() = true; + set_dim(dialog_strength, persist).unwrap(); + return; + } + } + // Don't dim when switching to another workspace with only one window if no_dim_when_only { if (parent_workspace.windows == 1 || parent_workspace.fullscreen) @@ -133,7 +158,8 @@ fn main() -> hyprland::Result<()> { } } - spawn_dim_thread(num_threads, strength, persist, duration, false); + *is_set_dim.lock().unwrap() = false; + spawn_dim_thread(num_threads, is_set_dim, strength, persist, duration, false); }); thread::spawn(move || -> hyprland::Result<()> {