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

commit9a5a49a4c9004e8caa99d98be45cb69c9801a381
parent600d2afd79
authorIsaac Freund <[email protected]>
date2025-03-23 15:30
Decoration: make frame perfect on window close

 river/Decoration.zig   | 21 ++++++++++++++++-----
 river/Window.zig       |  9 +++++++--
 rivercompat/Window.zig |  4 ++++
 3 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/river/Decoration.zig b/river/Decoration.zig
index 1b91c5f..32086e1 100644
--- a/river/Decoration.zig
+++ b/river/Decoration.zig
@@ -38,7 +38,7 @@ const role: wlr.Surface.Role = .{
     .destroy = null,
 };
 
-object: *river.DecorationV1,
+object: ?*river.DecorationV1,
 surface: *wlr.Surface,
 tree: *wlr.SceneTree,
 surfaces: Scene.SaveableSurfaces,
@@ -88,12 +88,20 @@ pub fn create(
 }
 
 pub fn destroy(decoration: *Decoration) void {
-    decoration.object.setHandler(?*anyopaque, handleRequestInert, null, null);
+    assert(decoration.object == null);
     decoration.tree.node.destroy();
     decoration.link.remove();
     util.gpa.destroy(decoration);
 }
 
+pub fn makeInert(decoration: *Decoration) void {
+    if (decoration.object) |object| {
+        object.setHandler(?*anyopaque, handleRequestInert, null, null);
+        decoration.object = null;
+    }
+    decoration.surfaces.save();
+}
+
 fn handleRequestInert(
     node_v1: *river.DecorationV1,
     request: river.DecorationV1.Request,
@@ -103,6 +111,7 @@ fn handleRequestInert(
 }
 
 fn handleDestroy(_: *river.DecorationV1, decoration: *Decoration) void {
+    decoration.object = null;
     decoration.destroy();
 }
 
@@ -149,9 +158,11 @@ pub fn updateRenderingFinish(decoration: *Decoration) void {
         rendering_requested.sync_next_commit = false;
 
         if (!decoration.surfaces.saved.node.enabled) {
-            decoration.object.postError(.no_commit,
-                \\no wl_surface.commit after sync_next_commit and before update_rendering_finish
-            );
+            if (decoration.object) |object| {
+                object.postError(.no_commit,
+                    \\no wl_surface.commit after sync_next_commit and before update_rendering_finish
+                );
+            }
         }
     }
 
diff --git a/river/Window.zig b/river/Window.zig
index 960eb7c..da57a10 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -304,6 +304,11 @@ pub fn destroy(window: *Window) void {
         }
     }
 
+    inline for (.{ &window.decorations_above, &window.decorations_below }) |decorations| {
+        var it = decorations.safeIterator(.forward);
+        while (it.next()) |decoration| decoration.destroy();
+    }
+
     window.tree.node.destroy();
     window.popup_tree.node.destroy();
 
@@ -427,8 +432,8 @@ fn makeInert(window: *Window) void {
         window_v1.setHandler(?*anyopaque, handleRequestInert, null, null);
         window.node.makeInert();
         inline for (.{ &window.decorations_above, &window.decorations_below }) |decorations| {
-            var it = decorations.safeIterator(.forward);
-            while (it.next()) |decoration| decoration.destroy();
+            var it = decorations.iterator(.forward);
+            while (it.next()) |decoration| decoration.makeInert();
         }
     } else {
         assert(window.node.object == null);
diff --git a/rivercompat/Window.zig b/rivercompat/Window.zig
index 6d35380..4a30d3e 100644
--- a/rivercompat/Window.zig
+++ b/rivercompat/Window.zig
@@ -123,6 +123,10 @@ pub fn updateWindowing(window: *Window) void {
                 }
             }
         }
+        window.shadow_decoration.destroy();
+        window.shadow_viewport.destroy();
+        window.shadow_surface.destroy();
+        window.shadow_buffer.destroy();
         gpa.destroy(window);
         return;
     }