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

commite778e87364f0d2ea0bba1f2174b8c4b856d2ae56
parentd4bffd61e6
authorIsaac Freund <[email protected]>
date2024-02-06 12:59
xdg-toplevel: handle destroy before xdg-decoration

 river/XdgDecoration.zig | 15 ++++++++++-----
 river/XdgToplevel.zig   |  5 +++++
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/river/XdgDecoration.zig b/river/XdgDecoration.zig
index 91ab481..cfbb0e8 100644
--- a/river/XdgDecoration.zig
+++ b/river/XdgDecoration.zig
@@ -52,11 +52,7 @@ pub fn init(wlr_decoration: *wlr.XdgToplevelDecorationV1) void {
     xdg_toplevel.view.pending.ssd = ssd;
 }
 
-fn handleDestroy(
-    listener: *wl.Listener(*wlr.XdgToplevelDecorationV1),
-    _: *wlr.XdgToplevelDecorationV1,
-) void {
-    const decoration = @fieldParentPtr(XdgDecoration, "destroy", listener);
+pub fn deinit(decoration: *XdgDecoration) void {
     const xdg_toplevel: *XdgToplevel = @ptrFromInt(decoration.wlr_decoration.toplevel.base.data);
 
     decoration.destroy.link.remove();
@@ -66,6 +62,15 @@ fn handleDestroy(
     xdg_toplevel.decoration = null;
 }
 
+fn handleDestroy(
+    listener: *wl.Listener(*wlr.XdgToplevelDecorationV1),
+    _: *wlr.XdgToplevelDecorationV1,
+) void {
+    const decoration = @fieldParentPtr(XdgDecoration, "destroy", listener);
+
+    decoration.deinit();
+}
+
 fn handleRequestMode(
     listener: *wl.Listener(*wlr.XdgToplevelDecorationV1),
     _: *wlr.XdgToplevelDecorationV1,
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 7560e25..e2105c3 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -193,6 +193,11 @@ pub fn destroyPopups(self: Self) void {
 fn handleDestroy(listener: *wl.Listener(void)) void {
     const self = @fieldParentPtr(Self, "destroy", listener);
 
+    // This can be be non-null here if the client commits a protocol error or
+    // if it exits without destroying its wayland objects.
+    if (self.decoration) |*decoration| {
+        decoration.deinit();
+    }
     assert(self.decoration == null);
 
     // Remove listeners that are active for the entire lifetime of the view