From 398bc78ea073e0e61c6ba67ddcbaad0a5d574eeb Mon Sep 17 00:00:00 2001 From: Duncan Overbruck Date: Sat, 22 Mar 2025 19:04:24 +0100 Subject: add urgent border color and gradient --- niri-config/src/lib.rs | 53 ++++++++++++++++++++++++++++ niri-visual-tests/src/cases/gradient_area.rs | 3 ++ niri-visual-tests/src/cases/layout.rs | 2 ++ resources/default-config.kdl | 3 ++ src/layout/focus_ring.rs | 9 +++-- src/layout/insert_hint_element.rs | 6 +++- src/layout/tile.rs | 2 ++ src/window/mod.rs | 4 +++ 8 files changed, 79 insertions(+), 3 deletions(-) diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index 257c78ed..287b630d 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -583,10 +583,14 @@ pub struct FocusRing { pub active_color: Color, #[knuffel(child, default = Self::default().inactive_color)] pub inactive_color: Color, + #[knuffel(child, default = Self::default().urgent_color)] + pub urgent_color: Color, #[knuffel(child)] pub active_gradient: Option, #[knuffel(child)] pub inactive_gradient: Option, + #[knuffel(child)] + pub urgent_gradient: Option, } impl Default for FocusRing { @@ -596,8 +600,10 @@ impl Default for FocusRing { width: FloatOrInt(4.), active_color: Color::from_rgba8_unpremul(127, 200, 255, 255), inactive_color: Color::from_rgba8_unpremul(80, 80, 80, 255), + urgent_color: Color::from_rgba8_unpremul(155, 0, 0, 255), active_gradient: None, inactive_gradient: None, + urgent_gradient: None, } } } @@ -669,10 +675,14 @@ pub struct Border { pub active_color: Color, #[knuffel(child, default = Self::default().inactive_color)] pub inactive_color: Color, + #[knuffel(child, default = Self::default().urgent_color)] + pub urgent_color: Color, #[knuffel(child)] pub active_gradient: Option, #[knuffel(child)] pub inactive_gradient: Option, + #[knuffel(child)] + pub urgent_gradient: Option, } impl Default for Border { @@ -682,8 +692,10 @@ impl Default for Border { width: FloatOrInt(4.), active_color: Color::from_rgba8_unpremul(255, 200, 127, 255), inactive_color: Color::from_rgba8_unpremul(80, 80, 80, 255), + urgent_color: Color::from_rgba8_unpremul(155, 0, 0, 255), active_gradient: None, inactive_gradient: None, + urgent_gradient: None, } } } @@ -695,8 +707,10 @@ impl From for FocusRing { width: value.width, active_color: value.active_color, inactive_color: value.inactive_color, + urgent_color: value.urgent_color, active_gradient: value.active_gradient, inactive_gradient: value.inactive_gradient, + urgent_gradient: value.urgent_gradient, } } } @@ -708,8 +722,10 @@ impl From for Border { width: value.width, active_color: value.active_color, inactive_color: value.inactive_color, + urgent_color: value.urgent_color, active_gradient: value.active_gradient, inactive_gradient: value.inactive_gradient, + urgent_gradient: value.urgent_gradient, } } } @@ -1487,9 +1503,13 @@ pub struct BorderRule { #[knuffel(child)] pub inactive_color: Option, #[knuffel(child)] + pub urgent_color: Option, + #[knuffel(child)] pub active_gradient: Option, #[knuffel(child)] pub inactive_gradient: Option, + #[knuffel(child)] + pub urgent_gradient: Option, } #[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq)] @@ -2353,12 +2373,18 @@ impl BorderRule { if let Some(x) = other.inactive_color { self.inactive_color = Some(x); } + if let Some(x) = other.urgent_color { + self.urgent_color = Some(x); + } if let Some(x) = other.active_gradient { self.active_gradient = Some(x); } if let Some(x) = other.inactive_gradient { self.inactive_gradient = Some(x); } + if let Some(x) = other.urgent_gradient { + self.urgent_gradient = Some(x); + } } pub fn resolve_against(&self, mut config: Border) -> Border { @@ -2378,12 +2404,19 @@ impl BorderRule { config.inactive_color = x; config.inactive_gradient = None; } + if let Some(x) = self.urgent_color { + config.urgent_color = x; + config.urgent_gradient = None; + } if let Some(x) = self.active_gradient { config.active_gradient = Some(x); } if let Some(x) = self.inactive_gradient { config.inactive_gradient = Some(x); } + if let Some(x) = self.urgent_gradient { + config.urgent_gradient = Some(x); + } config } @@ -4321,6 +4354,12 @@ mod tests { b: 0.39215687, a: 0.0, }, + urgent_color: Color { + r: 0.60784316, + g: 0.0, + b: 0.0, + a: 1.0, + }, active_gradient: Some( Gradient { from: Color { @@ -4344,6 +4383,7 @@ mod tests { }, ), inactive_gradient: None, + urgent_gradient: None, }, border: Border { off: false, @@ -4362,8 +4402,15 @@ mod tests { b: 0.39215687, a: 0.0, }, + urgent_color: Color { + r: 0.60784316, + g: 0.0, + b: 0.0, + a: 1.0, + }, active_gradient: None, inactive_gradient: None, + urgent_gradient: None, }, shadow: Shadow { on: false, @@ -4805,8 +4852,10 @@ mod tests { ), active_color: None, inactive_color: None, + urgent_color: None, active_gradient: None, inactive_gradient: None, + urgent_gradient: None, }, border: BorderRule { off: false, @@ -4818,8 +4867,10 @@ mod tests { ), active_color: None, inactive_color: None, + urgent_color: None, active_gradient: None, inactive_gradient: None, + urgent_gradient: None, }, shadow: ShadowRule { off: false, @@ -5552,8 +5603,10 @@ mod tests { width: None, active_color: None, inactive_color: None, + urgent_color: None, active_gradient: None, inactive_gradient: None, + urgent_gradient: None, }; for rule in rules.iter().copied() { diff --git a/niri-visual-tests/src/cases/gradient_area.rs b/niri-visual-tests/src/cases/gradient_area.rs index 290e0a82..03f206c3 100644 --- a/niri-visual-tests/src/cases/gradient_area.rs +++ b/niri-visual-tests/src/cases/gradient_area.rs @@ -23,8 +23,10 @@ impl GradientArea { width: FloatOrInt(1.), active_color: Color::from_rgba8_unpremul(255, 255, 255, 128), inactive_color: Color::default(), + urgent_color: Color::default(), active_gradient: None, inactive_gradient: None, + urgent_gradient: None, }); Self { @@ -81,6 +83,7 @@ impl TestCase for GradientArea { g_size, true, true, + false, Rectangle::default(), CornerRadius::default(), 1., diff --git a/niri-visual-tests/src/cases/layout.rs b/niri-visual-tests/src/cases/layout.rs index 81748e8c..879af48b 100644 --- a/niri-visual-tests/src/cases/layout.rs +++ b/niri-visual-tests/src/cases/layout.rs @@ -60,8 +60,10 @@ impl Layout { width: FloatOrInt(4.), active_color: Color::from_rgba8_unpremul(255, 163, 72, 255), inactive_color: Color::from_rgba8_unpremul(50, 50, 50, 255), + urgent_color: Color::from_rgba8_unpremul(155, 0, 0, 255), active_gradient: None, inactive_gradient: None, + urgent_gradient: None, }, ..Default::default() }; diff --git a/resources/default-config.kdl b/resources/default-config.kdl index 213a8ba1..d1cc8b45 100644 --- a/resources/default-config.kdl +++ b/resources/default-config.kdl @@ -192,6 +192,9 @@ layout { active-color "#ffc87f" inactive-color "#505050" + // Color of the border around windows that request your attention. + urgent-color "#9b0000" + // active-gradient from="#ffbb66" to="#ffc880" angle=45 relative-to="workspace-view" // inactive-gradient from="#505050" to="#808080" angle=45 relative-to="workspace-view" } diff --git a/src/layout/focus_ring.rs b/src/layout/focus_ring.rs index 047fc3b7..5cb797e0 100644 --- a/src/layout/focus_ring.rs +++ b/src/layout/focus_ring.rs @@ -59,6 +59,7 @@ impl FocusRing { win_size: Size, is_active: bool, is_border: bool, + is_urgent: bool, view_rect: Rectangle, radius: CornerRadius, scale: f64, @@ -67,7 +68,9 @@ impl FocusRing { let width = self.config.width.0; self.full_size = win_size + Size::from((width, width)).upscale(2.); - let color = if is_active { + let color = if is_urgent { + self.config.urgent_color + } else if is_active { self.config.active_color } else { self.config.inactive_color @@ -79,7 +82,9 @@ impl FocusRing { let radius = radius.fit_to(self.full_size.w as f32, self.full_size.h as f32); - let gradient = if is_active { + let gradient = if is_urgent { + self.config.urgent_gradient + } else if is_active { self.config.active_gradient } else { self.config.inactive_gradient diff --git a/src/layout/insert_hint_element.rs b/src/layout/insert_hint_element.rs index 89dfcd14..92f9b480 100644 --- a/src/layout/insert_hint_element.rs +++ b/src/layout/insert_hint_element.rs @@ -19,8 +19,10 @@ impl InsertHintElement { width: FloatOrInt(0.), active_color: config.color, inactive_color: config.color, + urgent_color: config.color, active_gradient: config.gradient, inactive_gradient: config.gradient, + urgent_gradient: config.gradient, }), } } @@ -31,8 +33,10 @@ impl InsertHintElement { width: FloatOrInt(0.), active_color: config.color, inactive_color: config.color, + urgent_color: config.color, active_gradient: config.gradient, inactive_gradient: config.gradient, + urgent_gradient: config.gradient, }); } @@ -48,7 +52,7 @@ impl InsertHintElement { scale: f64, ) { self.inner - .update_render_elements(size, true, false, view_rect, radius, scale, 1.); + .update_render_elements(size, true, false, false, view_rect, radius, scale, 1.); } pub fn render( diff --git a/src/layout/tile.rs b/src/layout/tile.rs index 1b423c07..454b109c 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -366,6 +366,7 @@ impl Tile { self.animated_window_size(), is_active, !draw_border_with_background, + self.window.is_urgent(), Rectangle::new( view_rect.loc - Point::from((border_width, border_width)), view_rect.size, @@ -400,6 +401,7 @@ impl Tile { self.animated_tile_size(), is_active, !draw_focus_ring_with_background, + self.window.is_urgent(), view_rect, radius, self.scale, diff --git a/src/window/mod.rs b/src/window/mod.rs index 70759def..4410febc 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -191,8 +191,10 @@ impl ResolvedWindowRules { width: None, active_color: None, inactive_color: None, + urgent_color: None, active_gradient: None, inactive_gradient: None, + urgent_gradient: None, }, border: BorderRule { off: false, @@ -200,8 +202,10 @@ impl ResolvedWindowRules { width: None, active_color: None, inactive_color: None, + urgent_color: None, active_gradient: None, inactive_gradient: None, + urgent_gradient: None, }, shadow: ShadowRule { off: false, -- cgit