debug scene tree printer, layers are functional again

This commit is contained in:
Harrison DiAmbrosio 2025-12-14 11:33:44 -05:00
parent 44f694f916
commit 42d66ea2b6
6 changed files with 417 additions and 21 deletions

127
src/Debug.zig Normal file
View file

@ -0,0 +1,127 @@
const Debug = @This();
const std = @import("std");
const wlr = @import("wlroots");
const server = &@import("main.zig").server;
const gpa = std.heap.c_allocator;
const Utils = @import("Utils.zig");
const SceneNodeData = @import("SceneNodeData.zig").SceneNodeData;
pub fn debugPrintSceneTree() void {
std.log.debug("=== SCENE TREE DEBUG ===", .{});
printNode(&server.root.scene.tree.node, 0);
std.log.debug("=== END SCENE TREE ===", .{});
}
fn printNode(node: *wlr.SceneNode, depth: usize) void {
errdefer Utils.oomPanic();
var buffer: std.ArrayList(u8) = try .initCapacity(gpa, 512);
defer buffer.deinit(gpa);
const writer = buffer.writer(gpa);
// Add indentation
for (0..depth) |_| {
writer.writeAll(" ") catch unreachable;
}
// Print node type and position
const type_name = switch (node.type) {
.tree => "TREE",
.rect => "RECT",
.buffer => "BUFFER"
};
writer.print("{s} @ ({d}, {d}) enabled={}", .{
type_name,
node.x,
node.y,
node.enabled
}) catch unreachable;
// Add associated data if present
if (node.data) |data| {
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(data));
switch (scene_node_data.*) {
.root => {
writer.print(" → Root Scene Tree", .{}) catch unreachable;
},
.output => |output| {
writer.print(" → Output: {s} (focused={}, id={})", .{
output.wlr_output.name,
output.focused,
output.id,
}) catch unreachable;
},
.output_layer => {
writer.print(" → Output Layer", .{}) catch unreachable;
},
.view => |view| {
writer.print(" → View: id={} mapped={} focused={}", .{
view.id,
view.xdg_toplevel.base.surface.mapped,
view.focused,
}) catch unreachable;
if (view.xdg_toplevel.title) |title| {
writer.print(" title=\"{s}\"", .{title}) catch unreachable;
}
},
.layer_surface => |layer| {
const layer_name = switch (layer.wlr_layer_surface.current.layer) {
.background => "background",
.bottom => "bottom",
.top => "top",
.overlay => "overlay",
else => "unknown",
};
writer.print(" → LayerSurface: layer={s} mapped={}", .{
layer_name,
layer.wlr_layer_surface.surface.mapped,
}) catch unreachable;
const namespace = std.mem.span(layer.wlr_layer_surface.namespace);
if (namespace.len > 0) {
writer.print(" namespace=\"{s}\"", .{namespace}) catch unreachable;
}
}
}
}
// Add buffer-specific info
if (node.type == .buffer) {
const scene_buffer = wlr.SceneBuffer.fromNode(node);
writer.print(" buffer: {d}x{d}", .{
if (scene_buffer.buffer == null) -1 else scene_buffer.buffer.?.width,
if (scene_buffer.buffer == null) -1 else scene_buffer.buffer.?.height,
}) catch unreachable;
// Check if it's a surface
if (wlr.SceneSurface.tryFromBuffer(scene_buffer)) |scene_surface| {
writer.print(" → Surface: {*}", .{scene_surface.surface}) catch unreachable;
}
}
// Print the complete line
std.log.debug("{s}", .{buffer.items});
// Recursively print children if this is a tree
if (node.type == .tree) {
const tree = wlr.SceneTree.fromNode(node);
var it = tree.children.iterator(.forward);
var child_count: usize = 0;
while (it.next()) |child| {
child_count += 1;
printNode(child, depth + 1);
}
if (child_count == 0) {
var empty_buffer: std.ArrayList(u8) = try .initCapacity(gpa, 512);
defer empty_buffer.deinit(gpa);
for (0..depth) |_| {
empty_buffer.writer(gpa).writeAll("\t") catch unreachable;
}
empty_buffer.writer(gpa).writeAll(" (no children)") catch unreachable;
std.log.debug("{s}", .{empty_buffer.items});
}
}
}

View file

@ -47,8 +47,6 @@ pub fn init(wlr_layer_surface: *wlr.LayerSurfaceV1) *LayerSurface {
.scene_node_data = .{ .layer_surface = self }
};
self.wlr_layer_surface.surface.data = &self.scene_node_data;
if(server.seat.focused_output) |output| {
self.scene_layer_surface = switch (wlr_layer_surface.current.layer) {
.background => try output.layers.background.createSceneLayerSurfaceV1(wlr_layer_surface),
@ -62,6 +60,9 @@ pub fn init(wlr_layer_surface: *wlr.LayerSurfaceV1) *LayerSurface {
};
}
self.wlr_layer_surface.surface.data = &self.scene_node_data;
self.scene_layer_surface.tree.node.data = &self.scene_node_data;
self.wlr_layer_surface.events.destroy.add(&self.destroy);
self.wlr_layer_surface.surface.events.map.add(&self.map);
self.wlr_layer_surface.surface.events.unmap.add(&self.unmap);

View file

@ -35,6 +35,15 @@ layers: struct {
overlay: *wlr.SceneTree
},
layer_scene_node_data: struct {
background: SceneNodeData,
bottom: SceneNodeData,
content: SceneNodeData,
top: SceneNodeData,
fullscreen: SceneNodeData,
overlay: SceneNodeData
},
frame: wl.Listener(*wlr.Output) = .init(handleFrame),
request_state: wl.Listener(*wlr.Output.event.RequestState) = .init(handleRequestState),
destroy: wl.Listener(*wlr.Output) = .init(handleDestroy),
@ -61,6 +70,14 @@ pub fn init(wlr_output: *wlr.Output) ?*Output {
.fullscreen = try self.tree.createSceneTree(),
.overlay = try self.tree.createSceneTree(),
},
.layer_scene_node_data = .{
.background = .{ .output_layer = self.layers.background },
.bottom = .{ .output_layer = self.layers.bottom },
.content = .{ .output_layer = self.layers.content },
.top = .{ .output_layer = self.layers.top },
.fullscreen = .{ .output_layer = self.layers.fullscreen },
.overlay = .{ .output_layer = self.layers.overlay }
},
.scene_output = try server.root.scene.createSceneOutput(wlr_output),
.scene_node_data = SceneNodeData{ .output = self },
.state = wlr.Output.State.init()
@ -92,7 +109,15 @@ pub fn init(wlr_output: *wlr.Output) ?*Output {
server.root.scene_output_layout.addOutput(layout_output, self.scene_output);
self.setFocused();
wlr_output.data = &self.scene_node_data;
self.wlr_output.data = &self.scene_node_data;
self.tree.node.data = &self.scene_node_data;
self.layers.background.node.data = &self.layer_scene_node_data.background;
self.layers.bottom.node.data = &self.layer_scene_node_data.bottom;
self.layers.content.node.data = &self.layer_scene_node_data.content;
self.layers.top.node.data = &self.layer_scene_node_data.top;
self.layers.fullscreen.node.data = &self.layer_scene_node_data.fullscreen;
self.layers.overlay.node.data = &self.layer_scene_node_data.overlay;
server.events.exec("OutputInitPost", .{self.id});
@ -280,6 +305,9 @@ fn handleDestroy(
}
pub fn arrangeLayers(self: *Output) void {
const debug = @import("Debug.zig");
debug.debugPrintSceneTree();
var full_box: wlr.Box = .{
.x = 0,
.y = 0,
@ -291,28 +319,30 @@ pub fn arrangeLayers(self: *Output) void {
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(node.data == null) continue;
if (@as(?*SceneNodeData, @alignCast(@ptrCast(node.data)))) |node_data| {
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
const layer_surface: *LayerSurface = switch(scene_node_data.*) {
.layer_surface => @fieldParentPtr("scene_node_data", scene_node_data),
else => continue
};
const layer_surface: *LayerSurface = switch(node_data.*) {
.layer_surface => @fieldParentPtr("scene_node_data", scene_node_data),
else => continue
};
if (!layer_surface.wlr_layer_surface.initialized) continue;
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.
// 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);
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);
// 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);
}
}
}
}

View file

@ -19,6 +19,7 @@ const Utils = @import("Utils.zig");
xdg_toplevel_decoration_manager: *wlr.XdgDecorationManagerV1,
scene: *wlr.Scene,
scene_node_data: SceneNodeData,
waiting_room: *wlr.SceneTree,
scene_output_layout: *wlr.SceneOutputLayout,
@ -38,11 +39,14 @@ pub fn init(self: *Root) void {
self.* = .{
.scene = scene,
.scene_node_data = .{ .root = self },
.waiting_room = try scene.tree.createSceneTree(),
.output_layout = output_layout,
.xdg_toplevel_decoration_manager = try wlr.XdgDecorationManagerV1.create(server.wl_server),
.scene_output_layout = try scene.attachOutputLayout(output_layout),
};
self.scene.tree.node.data = &self.scene_node_data;
}
pub fn deinit(self: *Root) void {

View file

@ -1,10 +1,22 @@
const wlr = @import("wlroots");
const View = @import("View.zig");
const LayerSurface = @import("LayerSurface.zig");
const Output = @import("Output.zig");
const Root = @import("Root.zig");
const SceneNodeType = enum {
view,
layer_surface,
output,
output_layer,
root
};
const SceneNodeType = enum { view, layer_surface, output };
pub const SceneNodeData = union(SceneNodeType) {
view: *View,
layer_surface: *LayerSurface,
output: *Output
output: *Output,
output_layer: *wlr.SceneTree,
root: *Root
};