diff --git a/src/main.zig b/src/main.zig index c0aa561..dc0a6d0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -5,11 +5,14 @@ const Server = @import("server.zig"); const gpa = std.heap.c_allocator; + +pub var server: Server = undefined; + pub fn main() !void { wlr.log.init(.debug, null); - std.debug.print("Starting mezzaluna", .{}); - var server: Server = undefined; + std.log.info("Starting mezzaluna", .{}); + try server.init(); defer server.deinit(); @@ -26,10 +29,12 @@ pub fn main() !void { try child.spawn(); } + std.log.info("Starting backend", .{}); server.backend.start() catch |err| { std.debug.panic("Failed to start backend: {}", .{err}); return; }; + std.log.info("Starting server", .{}); server.wl_server.run(); } diff --git a/src/output.zig b/src/output.zig index 1a271d3..48a4b67 100644 --- a/src/output.zig +++ b/src/output.zig @@ -17,7 +17,7 @@ request_state: wl.Listener(*wlr.Output.event.RequestState) = .init(handleRequest destroy: wl.Listener(*wlr.Output) = .init(handleDestroy), // The wlr.Output should be destroyed by the caller on failure to trigger cleanup. -pub fn create(server: *Server, wlr_output: *wlr.Output) !void { +pub fn create(server: *Server, wlr_output: *wlr.Output) !*Output { const output = try gpa.create(Output); output.* = .{ @@ -34,6 +34,8 @@ pub fn create(server: *Server, wlr_output: *wlr.Output) !void { const scene_output = try server.scene.createSceneOutput(wlr_output); server.scene_output_layout.addOutput(layout_output, scene_output); + + return output; } pub fn handleFrame(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void { diff --git a/src/root.zig b/src/root.zig new file mode 100644 index 0000000..466ce08 --- /dev/null +++ b/src/root.zig @@ -0,0 +1,71 @@ +const std = @import("std"); + +const wl = @import("wayland").server.wl; +const wlr = @import("wlroots"); + +const Output = @import("output.zig"); + +const server = &@import("main.zig").server; + +pub const Root = struct { + scene: *wlr.Scene, + + output_layout: *wlr.OutputLayout, + + new_output: wl.Listener(*wlr.Output), + + pub fn init(root: *Root) !void { + std.log.info("Creating root of mezzaluna", .{}); + + 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(); + + root.* = .{ + .scene = scene, + .output_layout = output_layout, + + .new_output = .init(handleNewOutput), + }; + + server.backend.events.new_output.add(&root.new_output); + } + + pub fn addOutput(self: *Root, new_output: *Output) void { + _ = self.output_layout.addAuto(new_output.wlr_output) catch { + std.log.err("failed to add new output to output layout\n", .{}); + return; + }; + + _ = self.scene.createSceneOutput(new_output.wlr_output) catch { + std.log.err("failed to create scene output for new output", .{}); + return; + }; + } +}; + +fn handleNewOutput(_: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void { + std.log.info("Handling a new output - {s}", .{wlr_output.name}); + + if (!wlr_output.initRender(server.allocator, server.renderer)) return; + + var state = wlr.Output.State.init(); + defer state.finish(); + + state.setEnabled(true); + + if (wlr_output.preferredMode()) |mode| { + state.setMode(mode); + } + if (!wlr_output.commitState(&state)) return; + + const new_output = Output.create(server, wlr_output) catch { + std.log.err("failed to allocate new output", .{}); + wlr_output.destroy(); + return; + }; + + server.root.addOutput(new_output); +} diff --git a/src/scene.zig b/src/scene.zig deleted file mode 100644 index da3dd3f..0000000 --- a/src/scene.zig +++ /dev/null @@ -1,50 +0,0 @@ -const wl = @import("wayland").server.wl; -const wlr = @import("wlroots"); - -// server owns -// - compositor -// -// wlr_compositor owms -// - a list of wlr_surfaces -// -// wlr_surfaces own_buffers -// -// struct wl_resource *_surface; -// wl_resource_for_each(_surface, &server->compositor->surfaces) { -// struct wlr_surface *surface = wlr_surface_from_resource(_surface); -// if (!wlr_surface_has_buffer(surface)) { -// continue; -// } -// struct wlr_box render_box = { -// .x = 20, .y = 20, -// .width = surface->current->width, -// .height = surface->current->height -// }; -// float matrix[16]; -// wlr_matrix_project_box(&matrix, &render_box, -// surface->current->transform, -// 0, &wlr_output->transform_matrix); -// wlr_render_with_matrix(renderer, surface->texture, &matrix, 1.0f); -// wlr_surface_send_frame_done(surface, &now); -// } -// -// -// -// wlr_scene owns -// - list of outputs -// - wlr_scene_tree -// -// wlr_scene_tree owns -// - its own wlr_scene_node -// - list of its children wlr_scene_node -// -// wlr_scene_node can be TREE, RECT or BUFFER and owns -// - its own type -// - a pointer to its parent wlr_scene_tree -// - a list of children as wlr_scene_trees -// - boolean if enabled -// - x, y position relative to parent -// - wl signal for destroy -// - *void arbitrary data - - diff --git a/src/server.zig b/src/server.zig index f81a198..13b917d 100644 --- a/src/server.zig +++ b/src/server.zig @@ -8,6 +8,7 @@ const wlr = @import("wlroots"); const Output = @import("output.zig"); const Keyboard = @import("keyboard.zig"); +const Root = @import("root.zig").Root; allocator: *wlr.Allocator, backend: *wlr.Backend, @@ -21,6 +22,7 @@ session: ?*wlr.Session, shm: *wlr.Shm, wl_server: *wl.Server, xdg_shell: *wlr.XdgShell, +root: Root, // Input things seat: *wlr.Seat, @@ -29,7 +31,6 @@ cursor: *wlr.Cursor, cursor_mgr: *wlr.XcursorManager, // Listeners -new_output: wl.Listener(*wlr.Output) = .init(newOutput), new_input: wl.Listener(*wlr.InputDevice) = .init(newInput), cursor_motion: wl.Listener(*wlr.Pointer.event.Motion) = .init(cursorMotion), cursor_motion_absolute: wl.Listener(*wlr.Pointer.event.MotionAbsolute) = .init(cursorMotionAbsolute), @@ -68,11 +69,11 @@ pub fn init(server: *Server) !void { .cursor = try wlr.Cursor.create(), // TODO: let the user configure a cursor theme and side lua .cursor_mgr = try wlr.XcursorManager.create(null, 24), + .root = undefined, }; try server.renderer.initServer(wl_server); - - server.backend.events.new_output.add(&server.new_output); + try Root.init(&server.root); server.backend.events.new_input.add(&server.new_input); server.seat.events.request_set_cursor.add(&server.request_set_cursor); @@ -95,7 +96,6 @@ pub fn deinit(server: *Server) void { server.cursor_mgr.destroy(); server.new_input.link.remove(); - server.new_output.link.remove(); server.cursor_motion.link.remove(); server.cursor_motion_absolute.link.remove(); server.cursor_button.link.remove(); @@ -109,27 +109,6 @@ pub fn deinit(server: *Server) void { server.wl_server.destroy(); } -fn newOutput(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void { - const server: *Server = @fieldParentPtr("new_output", listener); - - if (!wlr_output.initRender(server.allocator, server.renderer)) return; - - var state = wlr.Output.State.init(); - defer state.finish(); - - state.setEnabled(true); - if (wlr_output.preferredMode()) |mode| { - state.setMode(mode); - } - if (!wlr_output.commitState(&state)) return; - - Output.create(server, wlr_output) catch { - std.log.err("failed to allocate new output", .{}); - wlr_output.destroy(); - return; - }; -} - fn newInput(listener: *wl.Listener(*wlr.InputDevice), device: *wlr.InputDevice) void { const server: *Server = @fieldParentPtr("new_input", listener); switch (device.type) {