aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-12-27 11:20:03 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2024-12-30 20:12:37 +0300
commita24a6e4e3c441389fd7731320f47e61e567e237f (patch)
tree0f93350f38a83af27ccb5549191323dc56cf9b4e
parent6fba4c371e7868f8d581cf3d49d611cdbb590ad4 (diff)
downloadniri-a24a6e4e3c441389fd7731320f47e61e567e237f.tar.gz
niri-a24a6e4e3c441389fd7731320f47e61e567e237f.tar.bz2
niri-a24a6e4e3c441389fd7731320f47e61e567e237f.zip
Implement is-floating window rule matcher
-rw-r--r--niri-config/src/lib.rs5
-rw-r--r--niri-visual-tests/src/test_window.rs2
-rw-r--r--src/layout/floating.rs1
-rw-r--r--src/layout/mod.rs4
-rw-r--r--src/layout/scrolling.rs1
-rw-r--r--src/window/mapped.rs14
-rw-r--r--src/window/mod.rs21
-rw-r--r--wiki/Configuration:-Window-Rules.md18
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>