srdusr
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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