From 4d19621f1ecb2f41b4d117ad42a2003b70a31262 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 21 Dec 2021 03:18:03 +0000 Subject: [PATCH] river: update to wlroots 0.15.0 --- README.md | 2 +- deps/zig-wlroots | 2 +- river/InputManager.zig | 8 ++----- river/LayerSurface.zig | 3 --- river/Layout.zig | 8 +++---- river/LayoutDemand.zig | 2 +- river/LayoutManager.zig | 2 +- river/Output.zig | 14 ++++++------ river/Root.zig | 12 +++++------ river/Server.zig | 47 ++++++++++++++++++++++------------------- river/Subsurface.zig | 24 ++++++++++++++------- river/XdgToplevel.zig | 19 ++++++----------- river/command/input.zig | 2 +- river/render.zig | 21 ++++++------------ 14 files changed, 80 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index 48a4304..c16be80 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ distribution. - [zig](https://ziglang.org/download/) 0.8 - wayland - wayland-protocols -- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.14 +- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.15 - xkbcommon - libevdev - pixman diff --git a/deps/zig-wlroots b/deps/zig-wlroots index 9bb6b03..e2be6fb 160000 --- a/deps/zig-wlroots +++ b/deps/zig-wlroots @@ -1 +1 @@ -Subproject commit 9bb6b03f0ea04d4ea6a102ed3e45badba9e8e262 +Subproject commit e2be6fbcc25694e111defdd41de9096802bf049a diff --git a/river/InputManager.zig b/river/InputManager.zig index 85e4dae..d6a554f 100644 --- a/river/InputManager.zig +++ b/river/InputManager.zig @@ -51,11 +51,7 @@ pub const InputDevice = struct { const identifier = try std.fmt.allocPrint( util.gpa, "{}:{}:{s}", - .{ device.vendor, device.product, mem.trim( - u8, - mem.sliceTo(device.name, 0), - &ascii.spaces, - ) }, + .{ device.vendor, device.product, mem.trim(u8, mem.span(device.name), &ascii.spaces) }, ); for (identifier) |*char| { if (char.* == ' ' or !std.ascii.isPrint(char.*)) { @@ -238,7 +234,7 @@ fn handleNewInput(listener: *wl.Listener(*wlr.InputDevice), device: *wlr.InputDe // Apply matching input device configuration, if exists. for (self.input_configs.items) |*input_config| { - if (mem.eql(u8, input_config.identifier, mem.sliceTo(input_device_node.data.identifier, 0))) { + if (mem.eql(u8, input_config.identifier, input_device_node.data.identifier)) { input_config.apply(&input_device_node.data); break; // There will only ever be one InputConfig for any unique identifier; } diff --git a/river/LayerSurface.zig b/river/LayerSurface.zig index 37f2c69..68f2dc8 100644 --- a/river/LayerSurface.zig +++ b/river/LayerSurface.zig @@ -139,9 +139,6 @@ fn handleUnmap(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: * fn handleCommit(listener: *wl.Listener(*wlr.Surface), wlr_surface: *wlr.Surface) void { const self = @fieldParentPtr(Self, "commit", listener); - // Ignore commits if the surface has been closed. - if (self.wlr_layer_surface.closed) return; - assert(self.wlr_layer_surface.output != null); // If a surface is committed while it is not mapped, we may need to send a configure. diff --git a/river/Layout.zig b/river/Layout.zig index a8fe83b..04e8ef6 100644 --- a/river/Layout.zig +++ b/river/Layout.zig @@ -100,7 +100,7 @@ fn handleRequestInert(layout: *river.LayoutV3, request: river.LayoutV3.Request, pub fn startLayoutDemand(self: *Self, views: u32) void { log.debug( "starting layout demand '{s}' on output '{s}'", - .{ self.namespace, mem.sliceTo(&self.output.wlr_output.name, 0) }, + .{ self.namespace, self.output.wlr_output.name }, ); std.debug.assert(self.output.layout_demand == null); @@ -129,7 +129,7 @@ fn handleRequest(layout: *river.LayoutV3, request: river.LayoutV3.Request, self: .push_view_dimensions => |req| { log.debug( "layout '{s}' on output '{s}' pushed view dimensions: {} {} {} {}", - .{ self.namespace, mem.sliceTo(&self.output.wlr_output.name, 0), req.x, req.y, req.width, req.height }, + .{ self.namespace, self.output.wlr_output.name, req.x, req.y, req.width, req.height }, ); if (self.output.layout_demand) |*layout_demand| { @@ -146,7 +146,7 @@ fn handleRequest(layout: *river.LayoutV3, request: river.LayoutV3.Request, self: .commit => |req| { log.debug( "layout '{s}' on output '{s}' commited", - .{ self.namespace, mem.sliceTo(&self.output.wlr_output.name, 0) }, + .{ self.namespace, self.output.wlr_output.name }, ); if (self.output.layout_demand) |*layout_demand| { @@ -166,7 +166,7 @@ fn handleDestroy(layout: *river.LayoutV3, self: *Self) void { pub fn destroy(self: *Self) void { log.debug( "destroying layout '{s}' on output '{s}'", - .{ self.namespace, mem.sliceTo(&self.output.wlr_output.name, 0) }, + .{ self.namespace, self.output.wlr_output.name }, ); // Remove layout from the list diff --git a/river/LayoutDemand.zig b/river/LayoutDemand.zig index 226a40c..eda4ba7 100644 --- a/river/LayoutDemand.zig +++ b/river/LayoutDemand.zig @@ -72,7 +72,7 @@ pub fn deinit(self: *const Self) void { fn handleTimeout(layout: *Layout) callconv(.C) c_int { log.notice( "layout demand for layout '{s}' on output '{s}' timed out", - .{ layout.namespace, mem.sliceTo(&layout.output.wlr_output.name, 0) }, + .{ layout.namespace, layout.output.wlr_output.name }, ); layout.output.layout_demand.?.deinit(); layout.output.layout_demand = null; diff --git a/river/LayoutManager.zig b/river/LayoutManager.zig index 168a0e5..b77ace6 100644 --- a/river/LayoutManager.zig +++ b/river/LayoutManager.zig @@ -67,7 +67,7 @@ fn handleRequest(layout_manager: *river.LayoutManagerV3, request: river.LayoutMa const wlr_output = wlr.Output.fromWlOutput(req.output) orelse return; const output = @intToPtr(*Output, wlr_output.data); - log.debug("bind layout '{s}' on output '{s}'", .{ req.namespace, mem.sliceTo(&output.wlr_output.name, 0) }); + log.debug("bind layout '{s}' on output '{s}'", .{ req.namespace, output.wlr_output.name }); Layout.create( layout_manager.getClient(), diff --git a/river/Output.zig b/river/Output.zig index 6cde2b3..e00624a 100644 --- a/river/Output.zig +++ b/river/Output.zig @@ -99,7 +99,9 @@ frame: wl.Listener(*wlr.OutputDamage) = wl.Listener(*wlr.OutputDamage).init(hand damage_destroy: wl.Listener(*wlr.OutputDamage) = wl.Listener(*wlr.OutputDamage).init(handleDamageDestroy), pub fn init(self: *Self, wlr_output: *wlr.Output) !void { - assert(!wlr_output.isNoop()); + assert(!wlr_output.isHeadless()); + + if (!wlr_output.initRender(server.allocator, server.renderer)) return; // Some backends don't have modes. DRM+KMS does, and we need to set a mode // before we can use the output. The mode is a tuple of (width, height, @@ -413,10 +415,10 @@ fn arrangeLayer( .mapped => { assert(layer_surface.wlr_layer_surface.mapped); layer_surface.box = new_box; - layer_surface.wlr_layer_surface.configure(new_box.width, new_box.height); + _ = layer_surface.wlr_layer_surface.configure(new_box.width, new_box.height); }, .unmapped => if (!layer_surface.wlr_layer_surface.mapped) { - layer_surface.wlr_layer_surface.configure(new_box.width, new_box.height); + _ = layer_surface.wlr_layer_surface.configure(new_box.width, new_box.height); }, } } @@ -434,7 +436,7 @@ fn handleDamageDestroy(listener: *wl.Listener(*wlr.OutputDamage), wlr_output: *w fn handleDestroy(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void { const self = @fieldParentPtr(Self, "destroy", listener); - std.log.scoped(.server).debug("output '{s}' destroyed", .{mem.sliceTo(&self.wlr_output.name, 0)}); + std.log.scoped(.server).debug("output '{s}' destroyed", .{self.wlr_output.name}); // Remove the destroyed output from root if it wasn't already removed server.root.removeOutput(self); @@ -499,8 +501,8 @@ pub fn getEffectiveResolution(self: *Self) struct { width: u32, height: u32 } { } fn setTitle(self: Self) void { - var buf: ["river - ".len + self.wlr_output.name.len + 1]u8 = undefined; - const title = fmt.bufPrintZ(&buf, "river - {s}", .{mem.sliceTo(&self.wlr_output.name, 0)}) catch unreachable; + const title = fmt.allocPrintZ(util.gpa, "river - {s}", .{self.wlr_output.name}) catch return; + defer util.gpa.free(title); if (self.wlr_output.isWl()) { self.wlr_output.wlSetTitle(title); } else if (wlr.config.has_x11_backend and self.wlr_output.isX11()) { diff --git a/river/Root.zig b/river/Root.zig index e1a556d..732b661 100644 --- a/river/Root.zig +++ b/river/Root.zig @@ -94,7 +94,7 @@ pub fn init(self: *Self) !void { const transaction_timer = try event_loop.addTimer(*Self, handleTransactionTimeout, self); errdefer transaction_timer.remove(); - const noop_wlr_output = try server.noop_backend.noopAddOutput(); + const noop_wlr_output = try server.headless_backend.headlessAddOutput(); self.* = .{ .output_layout = output_layout, .output_manager = try wlr.OutputManagerV1.create(server.wl_server), @@ -123,7 +123,7 @@ pub fn deinit(self: *Self) void { fn handleNewOutput(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void { const self = @fieldParentPtr(Self, "new_output", listener); - std.log.scoped(.output_manager).debug("new output {s}", .{mem.sliceTo(&wlr_output.name, 0)}); + std.log.scoped(.output_manager).debug("new output {s}", .{wlr_output.name}); const node = util.gpa.create(std.TailQueue(Output).Node) catch { wlr_output.destroy(); @@ -480,7 +480,7 @@ fn applyOutputConfig(self: *Self, config: *wlr.OutputConfigurationV1) bool { // Since we have done a successful test commit, this will only fail // due to error in the output's backend implementation. output.wlr_output.commit() catch - std.log.scoped(.output_manager).err("output commit failed for {s}", .{mem.sliceTo(&output.wlr_output.name, 0)}); + std.log.scoped(.output_manager).err("output commit failed for {s}", .{output.wlr_output.name}); if (output.wlr_output.enabled) { // Moves the output if it is already in the layout @@ -520,7 +520,7 @@ fn testOutputConfig(config: *wlr.OutputConfigurationV1, rollback: bool) bool { if (too_small) { std.log.scoped(.output_manager).info( "The requested output resolution {}x{} scaled with {} for {s} would be too small.", - .{ width, height, scale, mem.sliceTo(&wlr_output.name, 0) }, + .{ width, height, scale, wlr_output.name }, ); } @@ -592,11 +592,11 @@ fn handlePowerManagerSetMode( const log_text = if (enable) "Enabling" else "Disabling"; std.log.scoped(.output_manager).debug( "{s} dpms for output {s}", - .{ log_text, mem.sliceTo(&event.output.name, 0) }, + .{ log_text, event.output.name }, ); event.output.enable(enable); event.output.commit() catch { - std.log.scoped(.server).err("output commit failed for {s}", .{mem.sliceTo(&event.output.name, 0)}); + std.log.scoped(.server).err("output commit failed for {s}", .{event.output.name}); }; } diff --git a/river/Server.zig b/river/Server.zig index 951ba9e..f233546 100644 --- a/river/Server.zig +++ b/river/Server.zig @@ -47,7 +47,10 @@ sigint_source: *wl.EventSource, sigterm_source: *wl.EventSource, backend: *wlr.Backend, -noop_backend: *wlr.Backend, +headless_backend: *wlr.Backend, + +renderer: *wlr.Renderer, +allocator: *wlr.Allocator, xdg_shell: *wlr.XdgShell, new_xdg_surface: wl.Listener(*wlr.XdgSurface), @@ -82,27 +85,27 @@ pub fn init(self: *Self) !void { // This frees itself when the wl.Server is destroyed self.backend = try wlr.Backend.autocreate(self.wl_server); - // This backend is used to create a noop output for use when no actual + // This backend is used to create a headless output for use when no actual // outputs are available. This frees itself when the wl.Server is destroyed. - self.noop_backend = try wlr.Backend.createNoop(self.wl_server); + self.headless_backend = try wlr.Backend.createHeadless(self.wl_server); - // This will never be null for the non-custom backends in wlroots - const renderer = self.backend.getRenderer().?; - try renderer.initServer(self.wl_server); + self.renderer = try wlr.Renderer.autocreate(self.backend); + errdefer self.renderer.destroy(); + try self.renderer.initServer(self.wl_server); - const compositor = try wlr.Compositor.create(self.wl_server, renderer); + self.allocator = try wlr.Allocator.autocreate(self.backend, self.renderer); + errdefer self.allocator.destroy(); + + const compositor = try wlr.Compositor.create(self.wl_server, self.renderer); - // Set up xdg shell self.xdg_shell = try wlr.XdgShell.create(self.wl_server); self.new_xdg_surface.setNotify(handleNewXdgSurface); self.xdg_shell.events.new_surface.add(&self.new_xdg_surface); - // Set up layer shell self.layer_shell = try wlr.LayerShellV1.create(self.wl_server); self.new_layer_surface.setNotify(handleNewLayerSurface); self.layer_shell.events.new_surface.add(&self.new_layer_surface); - // Set up xwayland if built with support if (build_options.xwayland) { self.xwayland = try wlr.Xwayland.create(self.wl_server, compositor, false); self.new_xwayland_surface.setNotify(handleNewXwaylandSurface); @@ -142,6 +145,8 @@ pub fn deinit(self: *Self) void { self.wl_server.destroyClients(); self.backend.destroy(); + self.renderer.destroy(); + self.allocator.destroy(); self.root.deinit(); self.input_manager.deinit(); @@ -196,15 +201,15 @@ fn handleNewLayerSurface(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_ "new layer surface: namespace {s}, layer {s}, anchor {b:0>4}, size {},{}, margin {},{},{},{}, exclusive_zone {}", .{ wlr_layer_surface.namespace, - @tagName(wlr_layer_surface.client_pending.layer), - @bitCast(u32, wlr_layer_surface.client_pending.anchor), - wlr_layer_surface.client_pending.desired_width, - wlr_layer_surface.client_pending.desired_height, - wlr_layer_surface.client_pending.margin.top, - wlr_layer_surface.client_pending.margin.right, - wlr_layer_surface.client_pending.margin.bottom, - wlr_layer_surface.client_pending.margin.left, - wlr_layer_surface.client_pending.exclusive_zone, + @tagName(wlr_layer_surface.pending.layer), + @bitCast(u32, wlr_layer_surface.pending.anchor), + wlr_layer_surface.pending.desired_width, + wlr_layer_surface.pending.desired_height, + wlr_layer_surface.pending.margin.top, + wlr_layer_surface.pending.margin.right, + wlr_layer_surface.pending.margin.bottom, + wlr_layer_surface.pending.margin.left, + wlr_layer_surface.pending.exclusive_zone, }, ); @@ -218,9 +223,7 @@ fn handleNewLayerSurface(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_ return; } - log.debug("new layer surface had null output, assigning it to output '{s}'", .{ - mem.sliceTo(&output.wlr_output.name, 0), - }); + log.debug("new layer surface had null output, assigning it to output '{s}'", .{output.wlr_output.name}); wlr_layer_surface.output = output.wlr_output; } diff --git a/river/Subsurface.zig b/river/Subsurface.zig index bf7c341..92328f5 100644 --- a/river/Subsurface.zig +++ b/river/Subsurface.zig @@ -81,11 +81,17 @@ pub fn create(wlr_subsurface: *wlr.Subsurface, parent: Parent) void { /// given surface when river becomes aware of the surface as we won't /// recieve a new_subsurface event for them. pub fn handleExisting(surface: *wlr.Surface, parent: Parent) void { - var below_it = surface.subsurfaces_below.iterator(.forward); - while (below_it.next()) |s| Subsurface.create(s, parent); + var below_it = surface.current.subsurfaces_below.iterator(.forward); + while (below_it.next()) |parent_state| { + const subsurface = @fieldParentPtr(wlr.Subsurface, "current", parent_state); + Subsurface.create(subsurface, parent); + } - var above_it = surface.subsurfaces_above.iterator(.forward); - while (above_it.next()) |s| Subsurface.create(s, parent); + var above_it = surface.current.subsurfaces_above.iterator(.forward); + while (above_it.next()) |parent_state| { + const subsurface = @fieldParentPtr(wlr.Subsurface, "current", parent_state); + Subsurface.create(subsurface, parent); + } } /// Destroy this Subsurface and all of its children @@ -104,13 +110,15 @@ pub fn destroy(subsurface: *Subsurface) void { } pub fn destroySubsurfaces(surface: *wlr.Surface) void { - var below_it = surface.subsurfaces_below.iterator(.forward); - while (below_it.next()) |wlr_subsurface| { + var below_it = surface.current.subsurfaces_below.iterator(.forward); + while (below_it.next()) |parent_state| { + const wlr_subsurface = @fieldParentPtr(wlr.Subsurface, "current", parent_state); if (@intToPtr(?*Subsurface, wlr_subsurface.data)) |s| s.destroy(); } - var above_it = surface.subsurfaces_above.iterator(.forward); - while (above_it.next()) |wlr_subsurface| { + var above_it = surface.current.subsurfaces_above.iterator(.forward); + while (above_it.next()) |parent_state| { + const wlr_subsurface = @fieldParentPtr(wlr.Subsurface, "current", parent_state); if (@intToPtr(?*Subsurface, wlr_subsurface.data)) |s| s.destroy(); } } diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig index fc8c38e..986f881 100644 --- a/river/XdgToplevel.zig +++ b/river/XdgToplevel.zig @@ -80,18 +80,13 @@ pub fn init(self: *Self, view: *View, xdg_surface: *wlr.XdgSurface) void { /// Returns true if a configure must be sent to ensure that the pending /// dimensions are applied. pub fn needsConfigure(self: Self) bool { - const server_pending = &self.xdg_surface.role_data.toplevel.server_pending; + const scheduled = &self.xdg_surface.role_data.toplevel.scheduled; const state = &self.view.pending; - // Checking server_pending is sufficient here since it will be either in - // sync with the current dimensions or be the dimensions sent with the - // most recent configure. In both cases server_pending has the values we - // want to check against. - // Furthermore, we avoid a special case for newly mapped views which we - // have not yet configured by setting server_pending.width/height to the - // initial width/height of the view in handleMap(). - return state.box.width != server_pending.width or - state.box.height != server_pending.height; + // We avoid a special case for newly mapped views which we have not yet + // configured by setting scheduled.width/height to the initial width/height + // of the view in handleMap(). + return state.box.width != scheduled.width or state.box.height != scheduled.height; } /// Send a configure event, applying the pending state of the view. @@ -196,8 +191,8 @@ fn handleMap(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSurfa // We initialize these to avoid special-casing newly mapped views in // the check preformed in needsConfigure(). - toplevel.server_pending.width = @intCast(u32, initial_box.width); - toplevel.server_pending.height = @intCast(u32, initial_box.height); + toplevel.scheduled.width = @intCast(u32, initial_box.width); + toplevel.scheduled.height = @intCast(u32, initial_box.height); view.surface = self.xdg_surface.surface; view.surface_box = Box.fromWlrBox(initial_box); diff --git a/river/command/input.zig b/river/command/input.zig index 6aa91bf..02c96bd 100644 --- a/river/command/input.zig +++ b/river/command/input.zig @@ -40,7 +40,7 @@ pub fn listInputs( var it = server.input_manager.input_devices.first; while (it) |node| : (it = node.next) { const configured = for (server.input_manager.input_configs.items) |*input_config| { - if (mem.eql(u8, input_config.identifier, mem.sliceTo(node.data.identifier, 0))) { + if (mem.eql(u8, input_config.identifier, node.data.identifier)) { break true; } } else false; diff --git a/river/render.zig b/river/render.zig index 3178986..b6885d4 100644 --- a/river/render.zig +++ b/river/render.zig @@ -47,8 +47,6 @@ const SurfaceRenderData = struct { /// The rendering order in this function must be kept in sync with Cursor.surfaceAt() pub fn renderOutput(output: *Output) void { - const renderer = output.wlr_output.backend.getRenderer().?; - var now: os.timespec = undefined; os.clock_gettime(os.CLOCK_MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported"); @@ -66,7 +64,7 @@ pub fn renderOutput(output: *Output) void { return; } - renderer.begin(@intCast(u32, output.wlr_output.width), @intCast(u32, output.wlr_output.height)); + server.renderer.begin(@intCast(u32, output.wlr_output.width), @intCast(u32, output.wlr_output.height)); // Find the first visible fullscreen view in the stack if there is one var it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, renderFilter); @@ -77,12 +75,12 @@ pub fn renderOutput(output: *Output) void { // If we have a fullscreen view to render, render it. if (fullscreen_view) |view| { // Always clear with solid black for fullscreen - renderer.clear(&[_]f32{ 0, 0, 0, 1 }); + server.renderer.clear(&[_]f32{ 0, 0, 0, 1 }); renderView(output, view, &now); if (build_options.xwayland) renderXwaylandUnmanaged(output, &now); } else { // No fullscreen view, so render normal layers/views - renderer.clear(&server.config.background_color); + server.renderer.clear(&server.config.background_color); renderLayer(output, output.getLayer(.background).*, &now, .toplevels); renderLayer(output, output.getLayer(.bottom).*, &now, .toplevels); @@ -146,11 +144,11 @@ pub fn renderOutput(output: *Output) void { // Conclude rendering and swap the buffers, showing the final frame // on-screen. - renderer.end(); + server.renderer.end(); // TODO: handle failure output.wlr_output.commit() catch - log.err("output commit failed for {s}", .{mem.sliceTo(&output.wlr_output.name, 0)}); + log.err("output commit failed for {s}", .{output.wlr_output.name}); } fn renderFilter(view: *View, filter_tags: u32) bool { @@ -315,8 +313,7 @@ fn renderTexture( // This takes our matrix, the texture, and an alpha, and performs the actual // rendering on the GPU. - const renderer = output.wlr_output.backend.getRenderer().?; - renderer.renderSubtextureWithMatrix(texture, source_box, &matrix, 1.0) catch return; + server.renderer.renderSubtextureWithMatrix(texture, source_box, &matrix, 1.0) catch return; } fn renderBorders(output: *const Output, view: *View, now: *os.timespec) void { @@ -361,11 +358,7 @@ fn renderBorders(output: *const Output, view: *View, now: *os.timespec) void { fn renderRect(output: *const Output, box: Box, color: *const [4]f32) void { var wlr_box = box.toWlrBox(); scaleBox(&wlr_box, output.wlr_output.scale); - output.wlr_output.backend.getRenderer().?.renderRect( - &wlr_box, - color, - &output.wlr_output.transform_matrix, - ); + server.renderer.renderRect(&wlr_box, color, &output.wlr_output.transform_matrix); } /// Scale a wlr_box, taking the possibility of fractional scaling into account.