srdusr
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-08-14 16:55:00 +0200
committersrdusr <[email protected]>2024-08-14 16:55:00 +0200
commit380c4d90f63ac9c82455206072c2deac246a4fdc (patch)
treed69026e4764a4e34f2002e08c384fa7fc331ac80
parent09e63d204132f767cee7d0846e291d659f79fe90 (diff)
downloadsrdwm-380c4d90f63ac9c82455206072c2deac246a4fdc.tar.gz
srdwm-380c4d90f63ac9c82455206072c2deac246a4fdc.zip
Handle late title/class updates on XWayland windows
map_window_request only ever read window.title()/.class() once, at MapRequest - for a client whose managed window doesn't carry WM_NAME/WM_CLASS at that exact moment (or the properties simply arrive later), Window.title/app_id stayed permanently empty. That reaches srd.rule's class matching, this compositor's own titlebar text, and every wlr-foreign-toplevel-management listener (a dock's running indicator, an app switcher, icon lookup) - confirmed live via a peer session's AGS instance rendering blank rows for Spotify and OpenSnitch. Implements XwmHandler::property_notify (previously unhandled, a no-op default) to re-read title/class on WmWindowProperty::Title/Class and update Window plus notify rule/decoration/foreign-toplevel listeners on an actual change - the XWayland-side mirror of sync_toplevel_metadata, which already exists for exactly this problem on the native xdg-shell path (see its own doc comment). Not fully verified against the specific live case that surfaced this: whether XWayland's X11Wm delivers property_notify for a *managed* window whose real WM_NAME/WM_CLASS live only on an unmanaged sibling/ child (rather than arriving late on the same window) is still an open question - this fixes the well-documented "arrives late" case with certainty, and may or may not cover that harder case too.
-rw-r--r--crates/wayland/src/xwayland.rs49
1 files changed, 48 insertions, 1 deletions
diff --git a/crates/wayland/src/xwayland.rs b/crates/wayland/src/xwayland.rs
index d0d9641..cf11570 100644
--- a/crates/wayland/src/xwayland.rs
+++ b/crates/wayland/src/xwayland.rs
@@ -25,7 +25,7 @@
use smithay::reexports::calloop::LoopHandle;
use smithay::utils::{Logical, Rectangle};
use smithay::wayland::xwayland_shell::{XWaylandShellHandler, XWaylandShellState};
-use smithay::xwayland::xwm::{Reorder, ResizeEdge as X11ResizeEdge, XwmId};
+use smithay::xwayland::xwm::{Reorder, ResizeEdge as X11ResizeEdge, WmWindowProperty, XwmId};
use smithay::xwayland::{X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler};
use smithay::{delegate_xwayland_shell, desktop::Window as DWindow};
@@ -611,6 +611,53 @@ impl XwmHandler for CompState {
self.xwayland_windows.remove(&xid);
}
+ /// Re-reads title/class after either changes post-map and updates
+ /// `Window`/foreign-toplevel listeners if either actually did - the
+ /// XWayland equivalent of `sync_toplevel_metadata` (see its own doc
+ /// comment for the identical xdg-shell-side problem this mirrors).
+ ///
+ /// `map_window_request` only ever reads `window.title()`/`.class()`
+ /// once, at `MapRequest` - but for some real clients (confirmed live:
+ /// Spotify, OpenSnitch's tray-prompt window) the *managed* X11 window
+ /// never carries `WM_NAME`/`WM_CLASS` at all at that moment, or ever;
+ /// the properties land on a separately-reparented child window instead,
+ /// and XWayland's own X11Wm surfaces that as a `property_notify` on
+ /// *this* window once it observes the change. Without handling it here,
+ /// `Window.title`/`app_id` stay permanently empty for such a window --
+ /// which reaches `srd.rule` (class matching), the compositor's own
+ /// titlebar text, and every `wlr-foreign-toplevel-management` listener
+ /// (a dock's running-indicator, an app switcher, icon lookup), not just
+ /// this compositor's own UI.
+ fn property_notify(&mut self, _xwm: XwmId, window: X11Surface, property: WmWindowProperty) {
+ if !matches!(property, WmWindowProperty::Title | WmWindowProperty::Class) {
+ return;
+ }
+ let Some(&id) = self.xwayland_windows.get(&window.window_id()) else { return };
+ let title = window.title();
+ let app_id = window.class();
+ let changed = {
+ let mut wm = self.wm.borrow_mut();
+ let Some(w) = wm.window_mut(id) else { return };
+ let changed = w.title != title || w.app_id != app_id;
+ w.title = title;
+ w.app_id = app_id;
+ changed
+ };
+ if changed {
+ // Same reasoning as `sync_toplevel_metadata`: only a rule
+ // actually matching for the first time warrants a decoration/
+ // geometry refresh, since `sync_geometry` re-stacks the window
+ // to the top of `Space` as an unconditional side effect of
+ // `map_element` - calling it on every later title change would
+ // silently yank an unrelated, unfocused window back to front.
+ if self.wm.borrow_mut().reapply_rules_if_pending(id) {
+ self.redraw_decoration_buffer(id);
+ self.sync_geometry(id);
+ }
+ crate::foreign_toplevel::send_state(self, id);
+ }
+ }
+
fn configure_request(&mut self, _xwm: XwmId, _window: X11Surface, _x: Option<i32>, _y: Option<i32>, _w: Option<u32>, _h: Option<u32>, _reorder: Option<Reorder>) {
// We own layout for managed windows; smithay always sends back a
// synthetic configure with the window's actual current geometry