atagen

monolith

public
Star0
Watch0

Commit 53ecd62e39ea

tarball

atagen <boss@atagen.co>2026-10-22 06:14 UTC

2 files changed+40-7
xwayland: honour _NET_WM_STATE_DEMANDS_ATTENTION

EWMH clients ask for attention through this state rather than the ICCCM hint, and smithay forwarded the requests to empty default handlers. Both flags are also read at map, since clients may set them beforehand. Focusing the window clears the state as EWMH asks, so clients stop flashing their taskbar entry.
Modified file: crates/monolith/src/state.rs+6 additions
@@ -520,6 +520,12 @@ impl State {
520520 let focused = self.wm.layout.focused();
521521 for (id, s) in self.wm.iter() {
522522 let window = &s.window;
523+ if Some(id) == focused
524+ && let Some(x) = window.x11_surface()
525+ && x.demands_attention()
526+ {
527+ crate::xwayland::logged("drop attention", x.set_demands_attention(false));
528+ }
523529 if window.set_activated(Some(id) == focused)
524530 && let Some(t) = window.toplevel()
525531 && t.is_initial_configure_sent()
Modified file: crates/monolith/src/xwayland.rs+34 additions−7 deletions
@@ -428,7 +428,11 @@ impl XwmHandler for State {
428428 return;
429429 }
430430 let float = floats(&window).then(|| window.geometry());
431- self.map_window(Window::new_x11_window(window), float);
431+ let attention = wants_attention(&window);
432+ self.map_window(Window::new_x11_window(window.clone()), float);
433+ if attention {
434+ self.x11_attention(&window);
435+ }
432436 }
433437
434438 fn mapped_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) {
@@ -506,15 +510,25 @@ impl XwmHandler for State {
506510 {
507511 self.refresh_identity(id);
508512 }
509- if property == WmWindowProperty::Hints
510- && window.hints().is_some_and(|h| h.urgent)
511- && let Some(id) = self.x11_window_id(&window)
512- {
513- self.wm.layout.mark_urgent(id);
514- self.apply_layout();
513+ if property == WmWindowProperty::Hints && window.hints().is_some_and(|h| h.urgent) {
514+ self.x11_attention(&window);
515515 }
516516 }
517517
518+ fn demands_attention_request(&mut self, _xwm: XwmId, window: X11Surface) {
519+ let focused = self
520+ .x11_window_id(&window)
521+ .is_some_and(|id| self.wm.layout.is_focused(id));
522+ if !focused {
523+ logged("demand attention", window.set_demands_attention(true));
524+ self.x11_attention(&window);
525+ }
526+ }
527+
528+ fn undemands_attention_request(&mut self, _xwm: XwmId, window: X11Surface) {
529+ logged("drop attention", window.set_demands_attention(false));
530+ }
531+
518532 fn modal_request(&mut self, _xwm: XwmId, window: X11Surface) {
519533 self.x11_modal(&window, true);
520534 }
@@ -656,6 +670,13 @@ impl State {
656670 }
657671 }
658672
673+ fn x11_attention(&mut self, window: &X11Surface) {
674+ if let Some(id) = self.x11_window_id(window) {
675+ self.wm.layout.mark_urgent(id);
676+ self.apply_layout();
677+ }
678+ }
679+
659680 pub fn x11_window_id(&self, window: &X11Surface) -> Option<monolith_layout::WindowId> {
660681 self.wm
661682 .iter()
@@ -712,6 +733,12 @@ impl State {
712733 }
713734 }
714735
736+/// Either the ICCCM urgency hint or the EWMH demands-attention state, which
737+/// clients may set before mapping.
738+fn wants_attention(window: &X11Surface) -> bool {
739+ window.demands_attention() || window.hints().is_some_and(|h| h.urgent)
740+}
741+
715742 /// X11 requests fail when the window is already gone, which is routine, but
716743 /// a failure on a live window means it never got the geometry we chose.
717744 pub fn logged<E: std::fmt::Display>(what: &str, result: Result<(), E>) {