diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-12-27 11:20:03 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-12-30 20:12:37 +0300 |
| commit | a24a6e4e3c441389fd7731320f47e61e567e237f (patch) | |
| tree | 0f93350f38a83af27ccb5549191323dc56cf9b4e | |
| parent | 6fba4c371e7868f8d581cf3d49d611cdbb590ad4 (diff) | |
| download | niri-a24a6e4e3c441389fd7731320f47e61e567e237f.tar.gz niri-a24a6e4e3c441389fd7731320f47e61e567e237f.tar.bz2 niri-a24a6e4e3c441389fd7731320f47e61e567e237f.zip | |
Implement is-floating window rule matcher
| -rw-r--r-- | niri-config/src/lib.rs | 5 | ||||
| -rw-r--r-- | niri-visual-tests/src/test_window.rs | 2 | ||||
| -rw-r--r-- | src/layout/floating.rs | 1 | ||||
| -rw-r--r-- | src/layout/mod.rs | 4 | ||||
| -rw-r--r-- | src/layout/scrolling.rs | 1 | ||||
| -rw-r--r-- | src/window/mapped.rs | 14 | ||||
| -rw-r--r-- | src/window/mod.rs | 21 | ||||
| -rw-r--r-- | wiki/Configuration:-Window-Rules.md | 18 |
8 files changed, 66 insertions, 0 deletions
diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index b1543b56..2437fe66 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -1031,6 +1031,8 @@ pub struct Match { #[knuffel(property)] pub is_active_in_column: Option<bool>, #[knuffel(property)] + pub is_floating: Option<bool>, + #[knuffel(property)] pub at_startup: Option<bool>, } @@ -3403,6 +3405,7 @@ mod tests { is_active: None, is_focused: None, is_active_in_column: None, + is_floating: None, at_startup: None, }], excludes: vec![ @@ -3412,6 +3415,7 @@ mod tests { is_active: None, is_focused: None, is_active_in_column: None, + is_floating: None, at_startup: None, }, Match { @@ -3420,6 +3424,7 @@ mod tests { is_active: Some(true), is_focused: Some(false), is_active_in_column: None, + is_floating: None, at_startup: None, }, ], diff --git a/niri-visual-tests/src/test_window.rs b/niri-visual-tests/src/test_window.rs index 896ac5ea..51f9d11f 100644 --- a/niri-visual-tests/src/test_window.rs +++ b/niri-visual-tests/src/test_window.rs @@ -220,6 +220,8 @@ impl LayoutElement for TestWindow { fn set_active_in_column(&mut self, _active: bool) {} + fn set_floating(&mut self, _floating: bool) {} + fn set_bounds(&self, _bounds: Size<i32, Logical>) {} fn configure_intent(&self) -> ConfigureIntent { diff --git a/src/layout/floating.rs b/src/layout/floating.rs index a04c9b94..b3647844 100644 --- a/src/layout/floating.rs +++ b/src/layout/floating.rs @@ -1029,6 +1029,7 @@ impl<W: LayoutElement> FloatingSpace<W> { let win = tile.window_mut(); win.set_active_in_column(true); + win.set_floating(true); let is_active = is_active && Some(win.id()) == active.as_ref(); win.set_activated(is_active); diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 8f512c3b..2b12c7bb 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -186,6 +186,7 @@ pub trait LayoutElement { fn set_offscreen_element_id(&self, id: Option<Id>); fn set_activated(&mut self, active: bool); fn set_active_in_column(&mut self, active: bool); + fn set_floating(&mut self, floating: bool); fn set_bounds(&self, bounds: Size<i32, Logical>); fn configure_intent(&self) -> ConfigureIntent; @@ -3746,6 +3747,7 @@ impl<W: LayoutElement> Layout<W> { let win = move_.tile.window_mut(); win.set_active_in_column(true); + win.set_floating(move_.is_floating); win.set_activated(true); win.set_interactive_resize(None); @@ -4074,6 +4076,8 @@ mod tests { fn set_active_in_column(&mut self, _active: bool) {} + fn set_floating(&mut self, _floating: bool) {} + fn is_fullscreen(&self) -> bool { false } diff --git a/src/layout/scrolling.rs b/src/layout/scrolling.rs index 5b13d0c6..5d1b8234 100644 --- a/src/layout/scrolling.rs +++ b/src/layout/scrolling.rs @@ -2614,6 +2614,7 @@ impl<W: LayoutElement> ScrollingSpace<W> { let active_in_column = col.active_tile_idx == tile_idx; win.set_active_in_column(active_in_column); + win.set_floating(false); let active = is_active && self.active_column_idx == col_idx && active_in_column; win.set_activated(active); diff --git a/src/window/mapped.rs b/src/window/mapped.rs index 022a57a0..75551ef1 100644 --- a/src/window/mapped.rs +++ b/src/window/mapped.rs @@ -66,6 +66,9 @@ pub struct Mapped { /// Whether this window is the active window in its column. is_active_in_column: bool, + /// Whether this window is floating. + is_floating: bool, + /// Buffer to draw instead of the window when it should be blocked out. block_out_buffer: RefCell<SolidColorBuffer>, @@ -163,6 +166,7 @@ impl Mapped { need_to_recompute_rules: false, is_focused: false, is_active_in_column: false, + is_floating: false, block_out_buffer: RefCell::new(SolidColorBuffer::new((0., 0.), [0., 0., 0., 1.])), animate_next_configure: false, animate_serials: Vec::new(), @@ -220,6 +224,10 @@ impl Mapped { self.is_active_in_column } + pub fn is_floating(&self) -> bool { + self.is_floating + } + pub fn set_is_focused(&mut self, is_focused: bool) { if self.is_focused == is_focused { return; @@ -690,6 +698,12 @@ impl LayoutElement for Mapped { self.need_to_recompute_rules |= changed; } + fn set_floating(&mut self, floating: bool) { + let changed = self.is_floating != floating; + self.is_floating = floating; + self.need_to_recompute_rules |= changed; + } + fn set_bounds(&self, bounds: Size<i32, Logical>) { self.toplevel().with_pending_state(|state| { state.bounds = Some(bounds); diff --git a/src/window/mod.rs b/src/window/mod.rs index 44d5359e..1cf576df 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -115,6 +115,21 @@ impl<'a> WindowRef<'a> { WindowRef::Mapped(mapped) => mapped.is_active_in_column(), } } + + pub fn is_floating(self) -> bool { + match self { + // FIXME: This means you cannot set initial configure rules based on is-floating. I'm + // not sure there's a good way to support it, since this matcher makes a cycle with the + // open-floating rule. + // + // That said, I don't think there are a lot of useful initial configure properties you + // may want to set through an is-floating matcher? Like, if you're configuring a + // specific window to open as floating, you can also set those properties in that same + // window rule, rather than relying on a different is-floating rule. + WindowRef::Unmapped(_) => false, + WindowRef::Mapped(mapped) => mapped.is_floating(), + } + } } impl ResolvedWindowRules { @@ -381,5 +396,11 @@ fn window_matches(window: WindowRef, role: &XdgToplevelSurfaceRoleAttributes, m: } } + if let Some(is_floating) = m.is_floating { + if window.is_floating() != is_floating { + return false; + } + } + true } diff --git a/wiki/Configuration:-Window-Rules.md b/wiki/Configuration:-Window-Rules.md index bb1b1821..d39140ff 100644 --- a/wiki/Configuration:-Window-Rules.md +++ b/wiki/Configuration:-Window-Rules.md @@ -33,6 +33,7 @@ window-rule { match is-active=true match is-focused=false match is-active-in-column=true + match is-floating=true match at-startup=true // Properties that apply once upon window opening. @@ -198,6 +199,23 @@ window-rule { } ``` +#### `is-floating` + +<sup>Since: next release</sup> + +Can be `true` or `false`. +Matches floating windows. + +> [!NOTE] +> This matcher will apply only after the window is already open. +> This means that you cannot use it to change the window opening properties like `default-window-height` or `open-on-workspace`. + +```kdl +window-rule { + match is-floating=true +} +``` + #### `at-startup` <sup>Since: 0.1.6</sup> |
