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

commitbf4acd27730aa2ec6e4de85dbf8a14aec25e16b5
parentc5852b72b7
authorIsaac Freund <[email protected]>
date2021-06-09 20:03
output: destroy Layouts on Output removal

The Layout struct holds a pointer to the Output which becomes invalid
when the Output is destroyed so we must ensure all the layouts of an
Output are destroyed first.

 river/Layout.zig | 6 ++++++
 river/Output.zig | 6 ++++--
 river/Root.zig   | 3 +++
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/river/Layout.zig b/river/Layout.zig
index 9b607ac..3682ec1 100644
--- a/river/Layout.zig
+++ b/river/Layout.zig
@@ -169,6 +169,10 @@ fn handleRequest(layout: *river.LayoutV2, request: river.LayoutV2.Request, self:
 }
 
 fn handleDestroy(layout: *river.LayoutV2, self: *Self) void {
+    self.destroy();
+}
+
+pub fn destroy(self: *Self) void {
     log.debug(
         "destroying layout '{s}' on output '{s}'",
         .{ self.namespace, mem.sliceTo(&self.output.wlr_output.name, 0) },
@@ -189,4 +193,6 @@ fn handleDestroy(layout: *river.LayoutV2, self: *Self) void {
 
     util.gpa.free(self.namespace);
     util.gpa.destroy(node);
+
+    self.layout.setHandler(?*c_void, handleRequestInert, null, null);
 }
diff --git a/river/Output.zig b/river/Output.zig
index 38fc13e..010e6d4 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -18,6 +18,7 @@
 const Self = @This();
 
 const std = @import("std");
+const assert = std.debug.assert;
 const mem = std.mem;
 const fmt = std.fmt;
 const wlr = @import("wlroots");
@@ -410,8 +411,6 @@ fn arrangeLayer(
     }
 }
 
-/// Called when the output is destroyed. Evacuate all views from the output
-/// and then remove it from the list of outputs.
 fn handleDestroy(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void {
     const self = @fieldParentPtr(Self, "destroy", listener);
 
@@ -419,6 +418,9 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) v
 
     // Remove the destroyed output from root if it wasn't already removed
     server.root.removeOutput(self);
+    assert(self.views.first == null and self.views.last == null);
+    for (self.layers) |layer| assert(layer.len == 0);
+    assert(self.layouts.len == 0);
 
     var it = server.root.all_outputs.first;
     while (it) |all_node| : (it = all_node.next) {
diff --git a/river/Root.zig b/river/Root.zig
index 5f600e2..3d443b0 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -206,6 +206,9 @@ pub fn removeOutput(self: *Self, output: *Output) void {
         }
     }
 
+    // Destroy all layouts of the output
+    while (output.layouts.first) |layout_node| layout_node.data.destroy();
+
     // Arrange the root in case evacuated views affect the layout
     fallback_output.arrangeViews();
     self.startTransaction();