git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit2548e2130f4a4f194cf77fe6e11813e0d29bb279
parent2afcc3f25b
authorIsaac Freund <[email protected]>
date2026-01-15 16:26
XwaylandWindow: send parent event

 river/Window.zig         |  7 ++++++-
 river/XwaylandWindow.zig | 11 +++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/river/Window.zig b/river/Window.zig
index 40f4a03..6c8fea9 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -1001,7 +1001,12 @@ pub fn getParent(window: *Window) ?*Window {
             const parent: *XdgToplevel = @ptrCast(@alignCast(wlr_parent.base.data));
             return parent.window;
         },
-        .xwayland, .destroying => return null,
+        .xwayland => |xwindow| {
+            const parent_xsurface = xwindow.xsurface.parent orelse return null;
+            const parent_xwindow: *XwaylandWindow = @ptrCast(@alignCast(parent_xsurface.data));
+            return parent_xwindow.window;
+        },
+        .destroying => return null,
     }
 }
 
diff --git a/river/XwaylandWindow.zig b/river/XwaylandWindow.zig
index 6b1c738..98a931f 100644
--- a/river/XwaylandWindow.zig
+++ b/river/XwaylandWindow.zig
@@ -34,6 +34,7 @@ associate: wl.Listener(void) = .init(handleAssociate),
 dissociate: wl.Listener(void) = .init(handleDissociate),
 set_title: wl.Listener(void) = .init(handleSetTitle),
 set_class: wl.Listener(void) = .init(handleSetClass),
+set_parent: wl.Listener(void) = .init(handleSetParent),
 set_decorations: wl.Listener(void) = .init(handleSetDecorations),
 request_maximize: wl.Listener(void) = .init(handleRequestMaximize),
 request_fullscreen: wl.Listener(void) = .init(handleRequestFullscreen),
@@ -58,6 +59,8 @@ pub fn create(xsurface: *wlr.XwaylandSurface) error{OutOfMemory}!void {
     const xwindow = &window.impl.xwayland;
     xwindow.window = window;
 
+    xsurface.data = xwindow;
+
     // Add listeners that are active over the window's entire lifetime
     xsurface.events.destroy.add(&xwindow.destroy);
     xsurface.events.associate.add(&xwindow.associate);
@@ -66,6 +69,7 @@ pub fn create(xsurface: *wlr.XwaylandSurface) error{OutOfMemory}!void {
     xsurface.events.set_override_redirect.add(&xwindow.set_override_redirect);
     xsurface.events.set_title.add(&xwindow.set_title);
     xsurface.events.set_class.add(&xwindow.set_class);
+    xsurface.events.set_parent.add(&xwindow.set_parent);
     xsurface.events.set_decorations.add(&xwindow.set_decorations);
     xsurface.events.request_maximize.add(&xwindow.request_maximize);
     xsurface.events.request_fullscreen.add(&xwindow.request_fullscreen);
@@ -147,11 +151,14 @@ fn handleDestroy(listener: *wl.Listener(void)) void {
     xwindow.set_override_redirect.link.remove();
     xwindow.set_title.link.remove();
     xwindow.set_class.link.remove();
+    xwindow.set_parent.link.remove();
     xwindow.set_decorations.link.remove();
     xwindow.request_maximize.link.remove();
     xwindow.request_fullscreen.link.remove();
     xwindow.request_minimize.link.remove();
 
+    xwindow.xsurface.data = null;
+
     const window = xwindow.window;
     window.impl = .destroying;
 }
@@ -268,6 +275,10 @@ fn handleSetClass(listener: *wl.Listener(void)) void {
     xwindow.window.notifyAppId();
 }
 
+fn handleSetParent(_: *wl.Listener(void)) void {
+    server.wm.dirtyWindowing();
+}
+
 fn handleSetDecorations(listener: *wl.Listener(void)) void {
     const xwindow: *XwaylandWindow = @fieldParentPtr("set_decorations", listener);