diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/handlers/mod.rs | 20 | ||||
| -rw-r--r-- | src/layout/mod.rs | 2 | ||||
| -rw-r--r-- | src/layout/tests.rs | 4 | ||||
| -rw-r--r-- | src/window/mapped.rs | 22 | ||||
| -rw-r--r-- | src/window/mod.rs | 7 |
5 files changed, 48 insertions, 7 deletions
diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index f2613d19..ffbf2439 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -707,6 +707,8 @@ impl GammaControlHandler for State { } delegate_gamma_control!(State); +struct UrgentOnlyMarker; + impl XdgActivationHandler for State { fn activation_state(&mut self) -> &mut XdgActivationState { &mut self.niri.activation_state @@ -716,11 +718,10 @@ impl XdgActivationHandler for State { // Tokens without a serial are urgency-only. This is not specified, but it seems to be the // common client behavior. // - // We don't have urgency yet, so just ignore such tokens. - // // See also: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/150 let Some((serial, seat)) = data.serial else { - return false; + data.user_data.insert_if_missing(|| UrgentOnlyMarker); + return true; }; let Some(seat) = Seat::<State>::from_resource(&seat) else { return false; @@ -760,11 +761,16 @@ impl XdgActivationHandler for State { surface: WlSurface, ) { if token_data.timestamp.elapsed() < XDG_ACTIVATION_TOKEN_TIMEOUT { - if let Some((mapped, _)) = self.niri.layout.find_window_and_output(&surface) { + if let Some((mapped, _)) = self.niri.layout.find_window_and_output_mut(&surface) { let window = mapped.window.clone(); - self.niri.layout.activate_window(&window); - self.niri.layer_shell_on_demand_focus = None; - self.niri.queue_redraw_all(); + if token_data.user_data.get::<UrgentOnlyMarker>().is_some() { + mapped.set_urgent(true); + self.niri.queue_redraw_all(); + } else { + self.niri.layout.activate_window(&window); + self.niri.layer_shell_on_demand_focus = None; + self.niri.queue_redraw_all(); + } } else if let Some(unmapped) = self.niri.unmapped_windows.get_mut(&surface) { unmapped.activation_token_data = Some(token_data); } diff --git a/src/layout/mod.rs b/src/layout/mod.rs index d42f05a5..b2726bef 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -210,6 +210,8 @@ pub trait LayoutElement { fn set_bounds(&self, bounds: Size<i32, Logical>); fn is_ignoring_opacity_window_rule(&self) -> bool; + fn is_urgent(&self) -> bool; + fn configure_intent(&self) -> ConfigureIntent; fn send_pending_configure(&mut self); diff --git a/src/layout/tests.rs b/src/layout/tests.rs index 4ac5aaf7..a02d1120 100644 --- a/src/layout/tests.rs +++ b/src/layout/tests.rs @@ -261,6 +261,10 @@ impl LayoutElement for TestWindow { fn interactive_resize_data(&self) -> Option<InteractiveResizeData> { None } + + fn is_urgent(&self) -> bool { + false + } } fn arbitrary_bbox() -> impl Strategy<Value = Rectangle<i32, Logical>> { diff --git a/src/window/mapped.rs b/src/window/mapped.rs index 82734220..da6caf54 100644 --- a/src/window/mapped.rs +++ b/src/window/mapped.rs @@ -77,6 +77,9 @@ pub struct Mapped { /// If `None`, then the window is not offscreened. offscreen_data: RefCell<Option<OffscreenData>>, + /// Whether this has an urgent indicator. + is_urgent: bool, + /// Whether this window has the keyboard focus. is_focused: bool, @@ -231,6 +234,7 @@ impl Mapped { needs_configure: false, needs_frame_callback: false, offscreen_data: RefCell::new(None), + is_urgent: false, is_focused: false, is_active_in_column: true, is_floating: false, @@ -328,6 +332,7 @@ impl Mapped { } self.is_focused = is_focused; + self.is_urgent = false; self.need_to_recompute_rules = true; } @@ -510,6 +515,19 @@ impl Mapped { pub fn is_windowed_fullscreen(&self) -> bool { self.is_windowed_fullscreen } + + pub fn set_urgent(&mut self, urgent: bool) { + if self.is_focused && urgent { + return; + } + let changed = self.is_urgent != urgent; + self.is_urgent = urgent; + self.need_to_recompute_rules |= changed; + } + + pub fn is_urgent(&self) -> bool { + self.is_urgent + } } impl Drop for Mapped { @@ -830,6 +848,10 @@ impl LayoutElement for Mapped { } } + fn is_urgent(&self) -> bool { + self.is_urgent + } + fn set_activated(&mut self, active: bool) { let changed = self.toplevel().with_pending_state(|state| { if active { diff --git a/src/window/mod.rs b/src/window/mod.rs index 7c0da71b..70759def 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -131,6 +131,13 @@ impl<'a> WindowRef<'a> { } } + pub fn is_urgent(self) -> bool { + match self { + WindowRef::Unmapped(_) => false, + WindowRef::Mapped(mapped) => mapped.is_urgent(), + } + } + pub fn is_active_in_column(self) -> bool { match self { WindowRef::Unmapped(_) => true, |
