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

commitd2dc535d7260825b72778197ca31941f84ce2c1c
parent3f25957c6b
authorIsaac Freund <[email protected]>
date2024-04-16 12:18
layer-surface: close if exclusive zones too large

It seems layer-shell clients such as waybar can commit bogus exclusive
zones larger than the width/height of the output. While this client
behavior is questionable at best, it must not cause river to crash or
otherwise misbehave.

Therefore, close layer surfaces causing the usable (not exclusive zone)
area of an output to be reduced below half of the width/height.

 river/Output.zig | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/river/Output.zig b/river/Output.zig
index 6207588..3230fa3 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -360,16 +360,36 @@ fn sendLayerConfigures(
 ) void {
     for ([_]zwlr.LayerShellV1.Layer{ .background, .bottom, .top, .overlay }) |layer| {
         const tree = output.layerSurfaceTree(layer);
-        var it = tree.children.iterator(.forward);
+        var it = tree.children.safeIterator(.forward);
         while (it.next()) |node| {
             assert(node.type == .tree);
             if (@as(?*SceneNodeData, @ptrFromInt(node.data))) |node_data| {
                 const layer_surface = node_data.data.layer_surface;
 
                 const exclusive = layer_surface.wlr_layer_surface.current.exclusive_zone > 0;
-                if (exclusive != (mode == .exclusive)) continue;
+                if (exclusive != (mode == .exclusive)) {
+                    continue;
+                }
+
+                {
+                    var new_usable_box = usable_box.*;
+
+                    layer_surface.scene_layer_surface.configure(&full_box, &new_usable_box);
+
+                    // Clients can request bogus exclusive zones larger than the output
+                    // dimensions and river must handle this gracefully. It seems reasonable
+                    // to close layer shell clients that would cause the usable area of the
+                    // output to become less than half the width/height of its full dimensions.
+                    if (new_usable_box.width < @divTrunc(full_box.width, 2) or
+                        new_usable_box.height < @divTrunc(full_box.height, 2))
+                    {
+                        layer_surface.wlr_layer_surface.destroy();
+                        continue;
+                    }
+
+                    usable_box.* = new_usable_box;
+                }
 
-                layer_surface.scene_layer_surface.configure(&full_box, usable_box);
                 layer_surface.popup_tree.node.setPosition(
                     layer_surface.scene_layer_surface.tree.node.x,
                     layer_surface.scene_layer_surface.tree.node.y,