aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/handlers/mod.rs20
-rw-r--r--src/layout/mod.rs2
-rw-r--r--src/layout/tests.rs4
-rw-r--r--src/window/mapped.rs22
-rw-r--r--src/window/mod.rs7
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,