mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-21 02:01:55 +07:00
Implement is-window-cast-target window rule matcher
This commit is contained in:
@@ -1210,6 +1210,8 @@ pub struct Match {
|
||||
#[knuffel(property)]
|
||||
pub is_floating: Option<bool>,
|
||||
#[knuffel(property)]
|
||||
pub is_window_cast_target: Option<bool>,
|
||||
#[knuffel(property)]
|
||||
pub at_startup: Option<bool>,
|
||||
}
|
||||
|
||||
@@ -3948,6 +3950,7 @@ mod tests {
|
||||
is_focused: None,
|
||||
is_active_in_column: None,
|
||||
is_floating: None,
|
||||
is_window_cast_target: None,
|
||||
at_startup: None,
|
||||
}],
|
||||
excludes: vec![
|
||||
@@ -3958,6 +3961,7 @@ mod tests {
|
||||
is_focused: None,
|
||||
is_active_in_column: None,
|
||||
is_floating: None,
|
||||
is_window_cast_target: None,
|
||||
at_startup: None,
|
||||
},
|
||||
Match {
|
||||
@@ -3967,6 +3971,7 @@ mod tests {
|
||||
is_focused: Some(false),
|
||||
is_active_in_column: None,
|
||||
is_floating: None,
|
||||
is_window_cast_target: None,
|
||||
at_startup: None,
|
||||
},
|
||||
],
|
||||
|
||||
+22
-3
@@ -642,13 +642,18 @@ impl State {
|
||||
self.niri.refresh_idle_inhibit();
|
||||
self.refresh_pointer_contents();
|
||||
foreign_toplevel::refresh(self);
|
||||
|
||||
#[cfg(feature = "xdp-gnome-screencast")]
|
||||
self.niri.refresh_mapped_cast_outputs();
|
||||
// Should happen before refresh_window_rules(), but after anything that can start or stop
|
||||
// screencasts.
|
||||
#[cfg(feature = "xdp-gnome-screencast")]
|
||||
self.niri.refresh_mapped_cast_window_rules();
|
||||
|
||||
self.niri.refresh_window_rules();
|
||||
self.refresh_ipc_outputs();
|
||||
self.ipc_refresh_layout();
|
||||
self.ipc_refresh_keyboard_layout_index();
|
||||
|
||||
#[cfg(feature = "xdp-gnome-screencast")]
|
||||
self.niri.refresh_mapped_cast_outputs();
|
||||
}
|
||||
|
||||
fn notify_blocker_cleared(&mut self) {
|
||||
@@ -3256,6 +3261,20 @@ impl Niri {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "xdp-gnome-screencast")]
|
||||
pub fn refresh_mapped_cast_window_rules(&mut self) {
|
||||
// O(N^2) but should be fine since there aren't many casts usually.
|
||||
self.layout.with_windows_mut(|mapped, _| {
|
||||
let id = mapped.id().get();
|
||||
// Find regardless of cast.is_active.
|
||||
let value = self
|
||||
.casts
|
||||
.iter()
|
||||
.any(|cast| cast.target == (CastTarget::Window { id }));
|
||||
mapped.set_is_window_cast_target(value);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "xdp-gnome-screencast")]
|
||||
pub fn refresh_mapped_cast_outputs(&mut self) {
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
@@ -80,6 +80,9 @@ pub struct Mapped {
|
||||
/// Whether this window is floating.
|
||||
is_floating: bool,
|
||||
|
||||
/// Whether this window is a target of a window cast.
|
||||
is_window_cast_target: bool,
|
||||
|
||||
/// Whether this window should ignore opacity set through window rules.
|
||||
ignore_opacity_window_rule: bool,
|
||||
|
||||
@@ -188,6 +191,7 @@ impl Mapped {
|
||||
is_focused: false,
|
||||
is_active_in_column: true,
|
||||
is_floating: false,
|
||||
is_window_cast_target: false,
|
||||
ignore_opacity_window_rule: false,
|
||||
block_out_buffer: RefCell::new(SolidColorBuffer::new((0., 0.), [0., 0., 0., 1.])),
|
||||
animate_next_configure: false,
|
||||
@@ -260,6 +264,10 @@ impl Mapped {
|
||||
self.is_floating
|
||||
}
|
||||
|
||||
pub fn is_window_cast_target(&self) -> bool {
|
||||
self.is_window_cast_target
|
||||
}
|
||||
|
||||
pub fn toggle_ignore_opacity_window_rule(&mut self) {
|
||||
self.ignore_opacity_window_rule = !self.ignore_opacity_window_rule;
|
||||
}
|
||||
@@ -273,6 +281,15 @@ impl Mapped {
|
||||
self.need_to_recompute_rules = true;
|
||||
}
|
||||
|
||||
pub fn set_is_window_cast_target(&mut self, value: bool) {
|
||||
if self.is_window_cast_target == value {
|
||||
return;
|
||||
}
|
||||
|
||||
self.is_window_cast_target = value;
|
||||
self.need_to_recompute_rules = true;
|
||||
}
|
||||
|
||||
fn render_snapshot(&self, renderer: &mut GlesRenderer) -> LayoutElementRenderSnapshot {
|
||||
let _span = tracy_client::span!("Mapped::render_snapshot");
|
||||
|
||||
|
||||
@@ -146,6 +146,13 @@ impl<'a> WindowRef<'a> {
|
||||
WindowRef::Mapped(mapped) => mapped.is_floating(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_window_cast_target(self) -> bool {
|
||||
match self {
|
||||
WindowRef::Unmapped(_) => false,
|
||||
WindowRef::Mapped(mapped) => mapped.is_window_cast_target(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResolvedWindowRules {
|
||||
@@ -446,5 +453,11 @@ fn window_matches(window: WindowRef, role: &XdgToplevelSurfaceRoleAttributes, m:
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(is_window_cast_target) = m.is_window_cast_target {
|
||||
if window.is_window_cast_target() != is_window_cast_target {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ window-rule {
|
||||
match is-focused=false
|
||||
match is-active-in-column=true
|
||||
match is-floating=true
|
||||
match is-window-cast-target=true
|
||||
match at-startup=true
|
||||
|
||||
// Properties that apply once upon window opening.
|
||||
@@ -239,6 +240,42 @@ window-rule {
|
||||
}
|
||||
```
|
||||
|
||||
#### `is-window-cast-target`
|
||||
|
||||
<sup>Since: next release</sup>
|
||||
|
||||
Can be `true` or `false`.
|
||||
Matches `true` for windows that are target of an ongoing window screencast.
|
||||
|
||||
```kdl
|
||||
// Indicate screencasted windows with red colors.
|
||||
window-rule {
|
||||
match is-window-cast-target=true
|
||||
|
||||
focus-ring {
|
||||
active-color "#f38ba8"
|
||||
inactive-color "#7d0d2d"
|
||||
}
|
||||
|
||||
border {
|
||||
inactive-color "#7d0d2d"
|
||||
}
|
||||
|
||||
shadow {
|
||||
color "#7d0d2d70"
|
||||
}
|
||||
|
||||
tab-indicator {
|
||||
active-color "#f38ba8"
|
||||
inactive-color "#7d0d2d"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||

|
||||
|
||||
#### `at-startup`
|
||||
|
||||
<sup>Since: 0.1.6</sup>
|
||||
|
||||
Reference in New Issue
Block a user