xdg_activation works

This commit is contained in:
Harrison DiAmbrosio 2025-12-14 11:48:05 -05:00
parent 42d66ea2b6
commit 209cd8a540
3 changed files with 20 additions and 237 deletions

222
'
View file

@ -1,222 +0,0 @@
/// The root of Mezzaluna is, you guessed it, the root of many of the systems mez needs:
const Root = @This();
const std = @import("std");
const wl = @import("wayland").server.wl;
const wlr = @import("wlroots");
const server = &@import("main.zig").server;
const gpa = std.heap.c_allocator;
const Output = @import("Output.zig");
const View = @import("View.zig");
const LayerSurface = @import("LayerSurface.zig");
const SceneNodeData = @import("SceneNodeData.zig").SceneNodeData;
const Utils = @import("Utils.zig");
xdg_toplevel_decoration_manager: *wlr.XdgDecorationManagerV1,
scene: *wlr.Scene,
waiting_room: *wlr.SceneTree,
scene_output_layout: *wlr.SceneOutputLayout,
output_layout: *wlr.OutputLayout,
pub fn init(self: *Root) void {
std.log.info("Creating root of mezzaluna\n", .{});
errdefer Utils.oomPanic();
const output_layout = try wlr.OutputLayout.create(server.wl_server);
errdefer output_layout.destroy();
const scene = try wlr.Scene.create();
errdefer scene.tree.node.destroy();
self.* = .{
.scene = scene,
.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),
};
}
pub fn deinit(self: *Root) void {
var it = self.scene.tree.children.iterator(.forward);
while(it.next()) |node| {
if(node.data == null) continue;
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
switch(scene_node_data.*) {
.output => {
scene_node_data.output.deinit();
},
else => {
std.log.debug("The root has a child that is not an output", .{});
unreachable;
}
}
}
self.output_layout.destroy();
self.scene.tree.node.destroy();
}
// Search output_layout's ouputs, and each outputs views
pub fn viewById(self: *Root, id: u64) ?*View {
var output_it = self.output_layout.outputs.iterator(.forward);
while(output_it.next()) |o| {
if(o.output.data == null) continue;
const output_snd: *SceneNodeData = @ptrCast(@alignCast(o.output.data.?));
const output: *Output = switch (output_snd.*) {
.output => |output_ptr| output_ptr,
else => {
std.log.err("Incorrect scene node type found", .{});
unreachable;
}
};
var node_it = output.layers.content.children.iterator(.forward);
while(node_it.next()) |node| {
if(node.data == null) continue;
const view_snd: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
// TODO: Should we assert that we want only views to be here
// -- Basically should we use switch statements for snd interactions
// -- Or if statements, for simplicity
if(view_snd.* == .view and view_snd.view.id == id) {
return view_snd.view;
}
}
}
return null;
}
pub fn outputById(self: *Root, id: u64) ?*Output {
var it = self.scene.outputs.iterator(.forward);
while(it.next()) |scene_output| {
if(scene_output.output.data == null) continue;
const output: *Output = @as(*Output, @ptrCast(@alignCast(scene_output.output.data.?)));
if(output.id == id) return output;
}
return null;
}
pub fn debugPrintSceneTree(self: *Root) void {
std.log.debug("=== SCENE TREE DEBUG ===", .{});
printNode(&self.scene.tree.node, 0);
std.log.debug("=== END SCENE TREE ===", .{});
}
fn printNode(node: *wlr.SceneNode, depth: usize) void {
errdefer Utils.oomPanic();
var indent = gpa.alloc(u8, depth);
for(0..indent.len) |i| {
}
// Print node type and position
const type_name = switch (node.type) {
.tree => "TREE",
.rect => "RECT",
.buffer => "BUFFER",
};
std.log.debug("{s}{s} @ ({d}, {d}) enabled={} visible={}", .{
indent,
type_name,
node.x,
node.y,
node.enabled,
node.state.pending.enabled,
});
// Print associated data if present
if (node.data) |data| {
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(data));
switch (scene_node_data.*) {
.output => |output| {
std.log.debug("{s} → Output: {s} (focused={}, id={})", .{
indent,
output.wlr_output.name,
output.focused,
output.id,
});
},
.view => |view| {
std.log.debug("{s} → View: id={} mapped={} focused={}", .{
indent,
view.id,
view.xdg_toplevel.base.surface.mapped,
view.focused,
});
if (view.xdg_toplevel.title) |title| {
std.log.debug("{s} title=\"{s}\"", .{ indent, title });
}
},
.layer_surface => |layer| {
const layer_name = switch (layer.wlr_layer_surface.current.layer) {
.background => "background",
.bottom => "bottom",
.top => "top",
.overlay => "overlay",
else => "unknown",
};
std.log.debug("{s} → LayerSurface: layer={s} mapped={}", .{
indent,
layer_name,
layer.wlr_layer_surface.surface.mapped,
});
if (layer.wlr_layer_surface.namespace.len > 0) {
std.log.debug("{s} namespace=\"{s}\"", .{
indent,
layer.wlr_layer_surface.namespace,
});
}
},
}
}
// Print buffer-specific info
if (node.type == .buffer) {
const scene_buffer = wlr.SceneBuffer.fromNode(node);
std.log.debug("{s} buffer: {d}x{d}", .{
indent,
scene_buffer.buffer.?.width,
scene_buffer.buffer.?.height,
});
// Check if it's a surface
if (wlr.SceneSurface.tryFromBuffer(scene_buffer)) |scene_surface| {
std.log.debug("{s} → Surface: {*}", .{ indent, scene_surface.surface });
}
}
// 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) {
std.log.debug("{s} (no children)", .{indent});
}
}
}

View file

@ -305,9 +305,6 @@ fn handleDestroy(
} }
pub fn arrangeLayers(self: *Output) void { pub fn arrangeLayers(self: *Output) void {
const debug = @import("Debug.zig");
debug.debugPrintSceneTree();
var full_box: wlr.Box = .{ var full_box: wlr.Box = .{
.x = 0, .x = 0,
.y = 0, .y = 0,

View file

@ -11,13 +11,14 @@ const Keyboard = @import("Keyboard.zig");
const LayerSurface = @import("LayerSurface.zig"); const LayerSurface = @import("LayerSurface.zig");
const Output = @import("Output.zig"); const Output = @import("Output.zig");
const View = @import("View.zig"); const View = @import("View.zig");
const Utils = @import("Utils.zig");
const Keymap = @import("types/Keymap.zig"); const Keymap = @import("types/Keymap.zig");
const Hook = @import("types/Hook.zig"); const Hook = @import("types/Hook.zig");
const Events = @import("types/Events.zig"); const Events = @import("types/Events.zig");
const Popup = @import("Popup.zig"); const Popup = @import("Popup.zig");
const RemoteLua = @import("RemoteLua.zig"); const RemoteLua = @import("RemoteLua.zig");
const RemoteLuaManager = @import("RemoteLuaManager.zig"); const RemoteLuaManager = @import("RemoteLuaManager.zig");
const Utils = @import("Utils.zig");
const SceneNodeData = @import("SceneNodeData.zig").SceneNodeData;
const gpa = std.heap.c_allocator; const gpa = std.heap.c_allocator;
const server = &@import("main.zig").server; const server = &@import("main.zig").server;
@ -34,6 +35,7 @@ shm: *wlr.Shm,
xdg_shell: *wlr.XdgShell, xdg_shell: *wlr.XdgShell,
layer_shell: *wlr.LayerShellV1, layer_shell: *wlr.LayerShellV1,
xdg_toplevel_decoration_manager: *wlr.XdgDecorationManagerV1, xdg_toplevel_decoration_manager: *wlr.XdgDecorationManagerV1,
xdg_activation: *wlr.XdgActivationV1,
allocator: *wlr.Allocator, allocator: *wlr.Allocator,
@ -51,14 +53,11 @@ remote_lua_clients: std.DoublyLinkedList,
new_input: wl.Listener(*wlr.InputDevice) = .init(handleNewInput), new_input: wl.Listener(*wlr.InputDevice) = .init(handleNewInput),
new_output: wl.Listener(*wlr.Output) = .init(handleNewOutput), new_output: wl.Listener(*wlr.Output) = .init(handleNewOutput),
// backend.events.destroy // backend.events.destroy
// XdgShell listeners
new_xdg_toplevel: wl.Listener(*wlr.XdgToplevel) = .init(handleNewXdgToplevel), new_xdg_toplevel: wl.Listener(*wlr.XdgToplevel) = .init(handleNewXdgToplevel),
new_xdg_popup: wl.Listener(*wlr.XdgPopup) = .init(handleNewXdgPopup), new_xdg_popup: wl.Listener(*wlr.XdgPopup) = .init(handleNewXdgPopup),
new_xdg_toplevel_decoration: wl.Listener(*wlr.XdgToplevelDecorationV1) = .init(handleNewXdgToplevelDecoration), new_xdg_toplevel_decoration: wl.Listener(*wlr.XdgToplevelDecorationV1) = .init(handleNewXdgToplevelDecoration),
// LayerShell Listeners
new_layer_surface: wl.Listener(*wlr.LayerSurfaceV1) = .init(handleNewLayerSurface), new_layer_surface: wl.Listener(*wlr.LayerSurfaceV1) = .init(handleNewLayerSurface),
request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate) = .init(handleRequestActivate),
pub fn init(self: *Server) void { pub fn init(self: *Server) void {
errdefer Utils.oomPanic(); errdefer Utils.oomPanic();
@ -92,6 +91,7 @@ pub fn init(self: *Server) void {
.xdg_shell = try wlr.XdgShell.create(wl_server, 2), .xdg_shell = try wlr.XdgShell.create(wl_server, 2),
.layer_shell = try wlr.LayerShellV1.create(wl_server, 4), .layer_shell = try wlr.LayerShellV1.create(wl_server, 4),
.xdg_toplevel_decoration_manager = try wlr.XdgDecorationManagerV1.create(self.wl_server), .xdg_toplevel_decoration_manager = try wlr.XdgDecorationManagerV1.create(self.wl_server),
.xdg_activation = try wlr.XdgActivationV1.create(self.wl_server),
.event_loop = event_loop, .event_loop = event_loop,
.session = session, .session = session,
.compositor = try wlr.Compositor.create(wl_server, 6, renderer), .compositor = try wlr.Compositor.create(wl_server, 6, renderer),
@ -131,19 +131,13 @@ pub fn init(self: *Server) void {
self.root.scene.setGammaControlManagerV1(try wlr.GammaControlManagerV1.create(self.wl_server)); self.root.scene.setGammaControlManagerV1(try wlr.GammaControlManagerV1.create(self.wl_server));
// Add event listeners to events // Add event listeners to events
// Backend events
self.backend.events.new_input.add(&self.new_input); self.backend.events.new_input.add(&self.new_input);
self.backend.events.new_output.add(&self.new_output); self.backend.events.new_output.add(&self.new_output);
// XdgShell events
self.xdg_shell.events.new_toplevel.add(&self.new_xdg_toplevel); self.xdg_shell.events.new_toplevel.add(&self.new_xdg_toplevel);
self.xdg_shell.events.new_popup.add(&self.new_xdg_popup); self.xdg_shell.events.new_popup.add(&self.new_xdg_popup);
// XdgDecorationManagerV1 events
self.xdg_toplevel_decoration_manager.events.new_toplevel_decoration.add(&self.new_xdg_toplevel_decoration); self.xdg_toplevel_decoration_manager.events.new_toplevel_decoration.add(&self.new_xdg_toplevel_decoration);
// LayerShell events
self.layer_shell.events.new_surface.add(&self.new_layer_surface); self.layer_shell.events.new_surface.add(&self.new_layer_surface);
self.xdg_activation.events.request_activate.add(&self.request_activate);
self.events.exec("ServerStartPost", .{}); self.events.exec("ServerStartPost", .{});
} }
@ -236,3 +230,17 @@ fn handleNewLayerSurface(
_ = LayerSurface.init(layer_surface); _ = LayerSurface.init(layer_surface);
} }
fn handleRequestActivate(
_: *wl.Listener(*wlr.XdgActivationV1.event.RequestActivate),
event: *wlr.XdgActivationV1.event.RequestActivate,
) void {
if(event.surface.data == null) return;
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(event.surface.data.?));
if(scene_node_data.* == .view) {
scene_node_data.view.setFocused();
} else {
std.log.warn("Ignoring request to activate non-view", .{});
}
}