From 85630236fabafcede5b17ddd363038f1a058d02a Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Mon, 18 May 2026 17:28:27 +0200 Subject: [PATCH] xwm: Support sticky requests for unmapped windows --- src/shell/mod.rs | 32 +++++++++++++-------------- src/wayland/handlers/xdg_shell/mod.rs | 1 + src/xwayland.rs | 23 +++++++++++++++++++ 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index bdc093ec..e1a48567 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -249,6 +249,7 @@ pub struct PendingWindow { pub seat: Seat, pub fullscreen: Option, pub maximized: bool, + pub sticky: bool, } #[derive(Debug)] @@ -2684,23 +2685,19 @@ impl Shell { seat, fullscreen: output, maximized: should_be_maximized, + sticky: mut should_be_sticky, } = self.pending_windows.remove(pos); - let parent_is_sticky = if let Some(toplevel) = window.0.toplevel() { - if let Some(parent) = toplevel.parent() { - if let Some(elem) = self.element_for_surface(&parent) { - self.workspaces - .sets - .values() - .any(|set| set.sticky_layer.mapped().any(|m| m == elem)) - } else { - false - } - } else { - false - } - } else { - false + if !should_be_sticky + && let Some(toplevel) = window.0.toplevel() + && let Some(parent) = toplevel.parent() + && let Some(elem) = self.element_for_surface(&parent) + { + should_be_sticky = self + .workspaces + .sets + .values() + .any(|set| set.sticky_layer.mapped().any(|m| m == elem)); }; let pending_activation = self.pending_activations.remove(&(&window).into()); @@ -2814,7 +2811,7 @@ impl Shell { .map(mapped.clone(), Some(focus_stack.iter()), None); } - if parent_is_sticky { + if should_be_sticky { self.toggle_sticky(&seat, &mapped); } @@ -2824,7 +2821,7 @@ impl Shell { let new_target = if (workspace_output == seat.active_output() && active_handle == workspace_handle) - || parent_is_sticky + || should_be_sticky { // TODO: enforce focus stealing prevention by also checking the same rules as for the else case. Some(KeyboardFocusTarget::from(mapped.clone())) @@ -2955,6 +2952,7 @@ impl Shell { seat: seat.clone(), fullscreen: None, maximized: false, + sticky: false, }); } } diff --git a/src/wayland/handlers/xdg_shell/mod.rs b/src/wayland/handlers/xdg_shell/mod.rs index bd75e4d7..98b8acf6 100644 --- a/src/wayland/handlers/xdg_shell/mod.rs +++ b/src/wayland/handlers/xdg_shell/mod.rs @@ -51,6 +51,7 @@ impl XdgShellHandler for State { seat, fullscreen: None, maximized: false, + sticky: false, }) } // We will position the window after the first commit, when we know its size hints diff --git a/src/xwayland.rs b/src/xwayland.rs index 4b48667d..c4549c9e 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -815,6 +815,7 @@ impl XwmHandler for State { seat, fullscreen: None, maximized: false, + sticky: false, }) } } @@ -1167,6 +1168,28 @@ impl XwmHandler for State { } } + fn stick_request(&mut self, _xwm: XwmId, window: X11Surface) { + let mut shell = self.common.shell.write(); + if let Some(pending) = shell + .pending_windows + .iter_mut() + .find(|pending| pending.surface.x11_surface() == Some(&window)) + { + pending.sticky = true; + } + } + + fn unstick_request(&mut self, _xwm: XwmId, window: X11Surface) { + let mut shell = self.common.shell.write(); + if let Some(pending) = shell + .pending_windows + .iter_mut() + .find(|pending| pending.surface.x11_surface() == Some(&window)) + { + pending.sticky = false; + } + } + fn active_window_request( &mut self, _xwm: XwmId,