diff --git a/src/LayerSurface.zig b/src/LayerSurface.zig index fd37c9e..79f3326 100644 --- a/src/LayerSurface.zig +++ b/src/LayerSurface.zig @@ -6,6 +6,7 @@ const wlr = @import("wlroots"); const Utils = @import("Utils.zig"); const Output = @import("Output.zig"); +const SceneNodeData = @import("SceneNodeData.zig"); const gpa = std.heap.c_allocator; const server = &@import("main.zig").server; @@ -44,6 +45,10 @@ pub fn init(wlr_layer_surface: *wlr.LayerSurfaceV1) *LayerSurface { }; } + try SceneNodeData.setData( + &self.scene_layer_surface.tree.node, + .{ .layer_surface = self }, + ); self.wlr_layer_surface.surface.data = &self.scene_layer_surface.tree.node; self.wlr_layer_surface.events.destroy.add(&self.destroy); @@ -88,10 +93,12 @@ fn handleMap( std.log.debug("Unimplemented layer surface map", .{}); } -fn handleUnmap( - _: *wl.Listener(void) -) void { - std.log.debug("Unimplemented layer surface unmap", .{}); +fn handleUnmap(listener: *wl.Listener(void)) void { + const layer_surface: *LayerSurface = @fieldParentPtr("unmap", listener); + + // FIXME: this crashes mez when killing mez + layer_surface.output.arrangeLayers(); + layer_surface.deinit(); } fn handleCommit( @@ -100,10 +107,6 @@ fn handleCommit( ) void { const layer_surface: *LayerSurface = @fieldParentPtr("commit", listener); - var width: c_int = undefined; - var height: c_int = undefined; - layer_surface.output.wlr_output.effectiveResolution(&width, &height); - _ = layer_surface.wlr_layer_surface.configure(@intCast(width), @intCast(height)); - - layer_surface.scene_layer_surface.tree.node.reparent(layer_surface.output.layers.background); + if (!layer_surface.wlr_layer_surface.initial_commit) return; + layer_surface.output.arrangeLayers(); } diff --git a/src/Output.zig b/src/Output.zig index 0a883cb..14b16b3 100644 --- a/src/Output.zig +++ b/src/Output.zig @@ -8,6 +8,8 @@ const std = @import("std"); const Server = @import("Server.zig"); const Utils = @import("Utils.zig"); const View = @import("View.zig"); +const LayerSurface = @import("LayerSurface.zig"); +const SceneNodeData = @import("SceneNodeData.zig"); const posix = std.posix; const gpa = std.heap.c_allocator; @@ -223,3 +225,37 @@ fn handleDestroy( gpa.destroy(output); } + +pub fn arrangeLayers(self: *Output) void { + var full_box: wlr.Box = .{ + .x = 0, + .y = 0, + .width = undefined, + .height = undefined, + }; + self.wlr_output.effectiveResolution(&full_box.width, &full_box.height); + + inline for (@typeInfo(zwlr.LayerShellV1.Layer).@"enum".fields) |comptime_layer| { + const layer: *wlr.SceneTree = @field(self.layers, comptime_layer.name); + var it = layer.children.safeIterator(.forward); + while (it.next()) |node| { + if (@as(?*SceneNodeData, @alignCast(@ptrCast(node.data)))) |node_data| { + const layer_surface = node_data.data.layer_surface; + + if (!layer_surface.wlr_layer_surface.initialized) continue; + + // TEST: river seems to try and prevent clients from taking an + // exclusive size greater than half the screen by killing them. Do we + // need to? Clients can do quite a bit of nasty stuff and taking + // exclusive focus isn't even that bad. + + layer_surface.scene_layer_surface.configure(&full_box, &full_box); + + // TEST: are these calls useless? + // const x = layer_surface.scene_layer_surface.tree.node.x; + // const y = layer_surface.scene_layer_surface.tree.node.y; + // layer_surface.scene_layer_surface.tree.node.setPosition(x, y); + } + } + } +} diff --git a/src/SceneNodeData.zig b/src/SceneNodeData.zig new file mode 100644 index 0000000..5a2c69d --- /dev/null +++ b/src/SceneNodeData.zig @@ -0,0 +1,40 @@ +const SceneNodeData = @This(); + +const std = @import("std"); +const wlr = @import("wlroots"); +const wl = @import("wayland").server.wl; + +const View = @import("View.zig"); +const LayerSurface = @import("LayerSurface.zig"); + +const gpa = std.heap.c_allocator; + +pub const Data = union(enum) { + view: *View, + layer_surface: *LayerSurface, +}; + +node: *wlr.SceneNode, +data: Data, +destroy: wl.Listener(void) = wl.Listener(void).init(handleDestroy), + +pub fn setData(node: *wlr.SceneNode, data: Data) !void { + const scene_node_data = try gpa.create(SceneNodeData); + + scene_node_data.* = .{ + .node = node, + .data = data, + }; + node.data = scene_node_data; + + node.events.destroy.add(&scene_node_data.destroy); +} + +fn handleDestroy(listener: *wl.Listener(void)) void { + const scene_node_data: *SceneNodeData = @fieldParentPtr("destroy", listener); + + scene_node_data.destroy.link.remove(); + scene_node_data.node.data = null; + + gpa.destroy(scene_node_data); +}