river: update to wlroots 0.15.0

This commit is contained in:
Isaac Freund 2021-12-21 03:18:03 +00:00
parent c3370afa3d
commit 4d19621f1e
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
14 changed files with 80 additions and 86 deletions

View File

@ -41,7 +41,7 @@ distribution.
- [zig](https://ziglang.org/download/) 0.8 - [zig](https://ziglang.org/download/) 0.8
- wayland - wayland
- wayland-protocols - wayland-protocols
- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.14 - [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.15
- xkbcommon - xkbcommon
- libevdev - libevdev
- pixman - pixman

2
deps/zig-wlroots vendored

@ -1 +1 @@
Subproject commit 9bb6b03f0ea04d4ea6a102ed3e45badba9e8e262 Subproject commit e2be6fbcc25694e111defdd41de9096802bf049a

View File

@ -51,11 +51,7 @@ pub const InputDevice = struct {
const identifier = try std.fmt.allocPrint( const identifier = try std.fmt.allocPrint(
util.gpa, util.gpa,
"{}:{}:{s}", "{}:{}:{s}",
.{ device.vendor, device.product, mem.trim( .{ device.vendor, device.product, mem.trim(u8, mem.span(device.name), &ascii.spaces) },
u8,
mem.sliceTo(device.name, 0),
&ascii.spaces,
) },
); );
for (identifier) |*char| { for (identifier) |*char| {
if (char.* == ' ' or !std.ascii.isPrint(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. // Apply matching input device configuration, if exists.
for (self.input_configs.items) |*input_config| { 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); input_config.apply(&input_device_node.data);
break; // There will only ever be one InputConfig for any unique identifier; break; // There will only ever be one InputConfig for any unique identifier;
} }

View File

@ -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 { fn handleCommit(listener: *wl.Listener(*wlr.Surface), wlr_surface: *wlr.Surface) void {
const self = @fieldParentPtr(Self, "commit", listener); 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); assert(self.wlr_layer_surface.output != null);
// If a surface is committed while it is not mapped, we may need to send a configure. // If a surface is committed while it is not mapped, we may need to send a configure.

View File

@ -100,7 +100,7 @@ fn handleRequestInert(layout: *river.LayoutV3, request: river.LayoutV3.Request,
pub fn startLayoutDemand(self: *Self, views: u32) void { pub fn startLayoutDemand(self: *Self, views: u32) void {
log.debug( log.debug(
"starting layout demand '{s}' on output '{s}'", "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); 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| { .push_view_dimensions => |req| {
log.debug( log.debug(
"layout '{s}' on output '{s}' pushed view dimensions: {} {} {} {}", "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| { if (self.output.layout_demand) |*layout_demand| {
@ -146,7 +146,7 @@ fn handleRequest(layout: *river.LayoutV3, request: river.LayoutV3.Request, self:
.commit => |req| { .commit => |req| {
log.debug( log.debug(
"layout '{s}' on output '{s}' commited", "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| { 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 { pub fn destroy(self: *Self) void {
log.debug( log.debug(
"destroying layout '{s}' on output '{s}'", "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 // Remove layout from the list

View File

@ -72,7 +72,7 @@ pub fn deinit(self: *const Self) void {
fn handleTimeout(layout: *Layout) callconv(.C) c_int { fn handleTimeout(layout: *Layout) callconv(.C) c_int {
log.notice( log.notice(
"layout demand for layout '{s}' on output '{s}' timed out", "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.?.deinit();
layout.output.layout_demand = null; layout.output.layout_demand = null;

View File

@ -67,7 +67,7 @@ fn handleRequest(layout_manager: *river.LayoutManagerV3, request: river.LayoutMa
const wlr_output = wlr.Output.fromWlOutput(req.output) orelse return; const wlr_output = wlr.Output.fromWlOutput(req.output) orelse return;
const output = @intToPtr(*Output, wlr_output.data); 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.create(
layout_manager.getClient(), layout_manager.getClient(),

View File

@ -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), damage_destroy: wl.Listener(*wlr.OutputDamage) = wl.Listener(*wlr.OutputDamage).init(handleDamageDestroy),
pub fn init(self: *Self, wlr_output: *wlr.Output) !void { 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 // 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, // before we can use the output. The mode is a tuple of (width, height,
@ -413,10 +415,10 @@ fn arrangeLayer(
.mapped => { .mapped => {
assert(layer_surface.wlr_layer_surface.mapped); assert(layer_surface.wlr_layer_surface.mapped);
layer_surface.box = new_box; 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) { .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 { fn handleDestroy(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void {
const self = @fieldParentPtr(Self, "destroy", listener); 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 // Remove the destroyed output from root if it wasn't already removed
server.root.removeOutput(self); server.root.removeOutput(self);
@ -499,8 +501,8 @@ pub fn getEffectiveResolution(self: *Self) struct { width: u32, height: u32 } {
} }
fn setTitle(self: Self) void { fn setTitle(self: Self) void {
var buf: ["river - ".len + self.wlr_output.name.len + 1]u8 = undefined; const title = fmt.allocPrintZ(util.gpa, "river - {s}", .{self.wlr_output.name}) catch return;
const title = fmt.bufPrintZ(&buf, "river - {s}", .{mem.sliceTo(&self.wlr_output.name, 0)}) catch unreachable; defer util.gpa.free(title);
if (self.wlr_output.isWl()) { if (self.wlr_output.isWl()) {
self.wlr_output.wlSetTitle(title); self.wlr_output.wlSetTitle(title);
} else if (wlr.config.has_x11_backend and self.wlr_output.isX11()) { } else if (wlr.config.has_x11_backend and self.wlr_output.isX11()) {

View File

@ -94,7 +94,7 @@ pub fn init(self: *Self) !void {
const transaction_timer = try event_loop.addTimer(*Self, handleTransactionTimeout, self); const transaction_timer = try event_loop.addTimer(*Self, handleTransactionTimeout, self);
errdefer transaction_timer.remove(); errdefer transaction_timer.remove();
const noop_wlr_output = try server.noop_backend.noopAddOutput(); const noop_wlr_output = try server.headless_backend.headlessAddOutput();
self.* = .{ self.* = .{
.output_layout = output_layout, .output_layout = output_layout,
.output_manager = try wlr.OutputManagerV1.create(server.wl_server), .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 { fn handleNewOutput(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void {
const self = @fieldParentPtr(Self, "new_output", listener); 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 { const node = util.gpa.create(std.TailQueue(Output).Node) catch {
wlr_output.destroy(); 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 // Since we have done a successful test commit, this will only fail
// due to error in the output's backend implementation. // due to error in the output's backend implementation.
output.wlr_output.commit() catch 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) { if (output.wlr_output.enabled) {
// Moves the output if it is already in the layout // 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) { if (too_small) {
std.log.scoped(.output_manager).info( std.log.scoped(.output_manager).info(
"The requested output resolution {}x{} scaled with {} for {s} would be too small.", "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"; const log_text = if (enable) "Enabling" else "Disabling";
std.log.scoped(.output_manager).debug( std.log.scoped(.output_manager).debug(
"{s} dpms for output {s}", "{s} dpms for output {s}",
.{ log_text, mem.sliceTo(&event.output.name, 0) }, .{ log_text, event.output.name },
); );
event.output.enable(enable); event.output.enable(enable);
event.output.commit() catch { 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});
}; };
} }

View File

@ -47,7 +47,10 @@ sigint_source: *wl.EventSource,
sigterm_source: *wl.EventSource, sigterm_source: *wl.EventSource,
backend: *wlr.Backend, backend: *wlr.Backend,
noop_backend: *wlr.Backend, headless_backend: *wlr.Backend,
renderer: *wlr.Renderer,
allocator: *wlr.Allocator,
xdg_shell: *wlr.XdgShell, xdg_shell: *wlr.XdgShell,
new_xdg_surface: wl.Listener(*wlr.XdgSurface), 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 // This frees itself when the wl.Server is destroyed
self.backend = try wlr.Backend.autocreate(self.wl_server); 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. // 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 self.renderer = try wlr.Renderer.autocreate(self.backend);
const renderer = self.backend.getRenderer().?; errdefer self.renderer.destroy();
try renderer.initServer(self.wl_server); 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.xdg_shell = try wlr.XdgShell.create(self.wl_server);
self.new_xdg_surface.setNotify(handleNewXdgSurface); self.new_xdg_surface.setNotify(handleNewXdgSurface);
self.xdg_shell.events.new_surface.add(&self.new_xdg_surface); 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.layer_shell = try wlr.LayerShellV1.create(self.wl_server);
self.new_layer_surface.setNotify(handleNewLayerSurface); self.new_layer_surface.setNotify(handleNewLayerSurface);
self.layer_shell.events.new_surface.add(&self.new_layer_surface); self.layer_shell.events.new_surface.add(&self.new_layer_surface);
// Set up xwayland if built with support
if (build_options.xwayland) { if (build_options.xwayland) {
self.xwayland = try wlr.Xwayland.create(self.wl_server, compositor, false); self.xwayland = try wlr.Xwayland.create(self.wl_server, compositor, false);
self.new_xwayland_surface.setNotify(handleNewXwaylandSurface); self.new_xwayland_surface.setNotify(handleNewXwaylandSurface);
@ -142,6 +145,8 @@ pub fn deinit(self: *Self) void {
self.wl_server.destroyClients(); self.wl_server.destroyClients();
self.backend.destroy(); self.backend.destroy();
self.renderer.destroy();
self.allocator.destroy();
self.root.deinit(); self.root.deinit();
self.input_manager.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 {}", "new layer surface: namespace {s}, layer {s}, anchor {b:0>4}, size {},{}, margin {},{},{},{}, exclusive_zone {}",
.{ .{
wlr_layer_surface.namespace, wlr_layer_surface.namespace,
@tagName(wlr_layer_surface.client_pending.layer), @tagName(wlr_layer_surface.pending.layer),
@bitCast(u32, wlr_layer_surface.client_pending.anchor), @bitCast(u32, wlr_layer_surface.pending.anchor),
wlr_layer_surface.client_pending.desired_width, wlr_layer_surface.pending.desired_width,
wlr_layer_surface.client_pending.desired_height, wlr_layer_surface.pending.desired_height,
wlr_layer_surface.client_pending.margin.top, wlr_layer_surface.pending.margin.top,
wlr_layer_surface.client_pending.margin.right, wlr_layer_surface.pending.margin.right,
wlr_layer_surface.client_pending.margin.bottom, wlr_layer_surface.pending.margin.bottom,
wlr_layer_surface.client_pending.margin.left, wlr_layer_surface.pending.margin.left,
wlr_layer_surface.client_pending.exclusive_zone, wlr_layer_surface.pending.exclusive_zone,
}, },
); );
@ -218,9 +223,7 @@ fn handleNewLayerSurface(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_
return; return;
} }
log.debug("new layer surface had null output, assigning it to output '{s}'", .{ log.debug("new layer surface had null output, assigning it to output '{s}'", .{output.wlr_output.name});
mem.sliceTo(&output.wlr_output.name, 0),
});
wlr_layer_surface.output = output.wlr_output; wlr_layer_surface.output = output.wlr_output;
} }

View File

@ -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 /// given surface when river becomes aware of the surface as we won't
/// recieve a new_subsurface event for them. /// recieve a new_subsurface event for them.
pub fn handleExisting(surface: *wlr.Surface, parent: Parent) void { pub fn handleExisting(surface: *wlr.Surface, parent: Parent) void {
var below_it = surface.subsurfaces_below.iterator(.forward); var below_it = surface.current.subsurfaces_below.iterator(.forward);
while (below_it.next()) |s| Subsurface.create(s, parent); 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); var above_it = surface.current.subsurfaces_above.iterator(.forward);
while (above_it.next()) |s| Subsurface.create(s, parent); 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 /// 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 { pub fn destroySubsurfaces(surface: *wlr.Surface) void {
var below_it = surface.subsurfaces_below.iterator(.forward); var below_it = surface.current.subsurfaces_below.iterator(.forward);
while (below_it.next()) |wlr_subsurface| { while (below_it.next()) |parent_state| {
const wlr_subsurface = @fieldParentPtr(wlr.Subsurface, "current", parent_state);
if (@intToPtr(?*Subsurface, wlr_subsurface.data)) |s| s.destroy(); if (@intToPtr(?*Subsurface, wlr_subsurface.data)) |s| s.destroy();
} }
var above_it = surface.subsurfaces_above.iterator(.forward); var above_it = surface.current.subsurfaces_above.iterator(.forward);
while (above_it.next()) |wlr_subsurface| { while (above_it.next()) |parent_state| {
const wlr_subsurface = @fieldParentPtr(wlr.Subsurface, "current", parent_state);
if (@intToPtr(?*Subsurface, wlr_subsurface.data)) |s| s.destroy(); if (@intToPtr(?*Subsurface, wlr_subsurface.data)) |s| s.destroy();
} }
} }

View File

@ -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 /// Returns true if a configure must be sent to ensure that the pending
/// dimensions are applied. /// dimensions are applied.
pub fn needsConfigure(self: Self) bool { 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; const state = &self.view.pending;
// Checking server_pending is sufficient here since it will be either in // We avoid a special case for newly mapped views which we have not yet
// sync with the current dimensions or be the dimensions sent with the // configured by setting scheduled.width/height to the initial width/height
// most recent configure. In both cases server_pending has the values we // of the view in handleMap().
// want to check against. return state.box.width != scheduled.width or state.box.height != scheduled.height;
// 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;
} }
/// Send a configure event, applying the pending state of the view. /// 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 // We initialize these to avoid special-casing newly mapped views in
// the check preformed in needsConfigure(). // the check preformed in needsConfigure().
toplevel.server_pending.width = @intCast(u32, initial_box.width); toplevel.scheduled.width = @intCast(u32, initial_box.width);
toplevel.server_pending.height = @intCast(u32, initial_box.height); toplevel.scheduled.height = @intCast(u32, initial_box.height);
view.surface = self.xdg_surface.surface; view.surface = self.xdg_surface.surface;
view.surface_box = Box.fromWlrBox(initial_box); view.surface_box = Box.fromWlrBox(initial_box);

View File

@ -40,7 +40,7 @@ pub fn listInputs(
var it = server.input_manager.input_devices.first; var it = server.input_manager.input_devices.first;
while (it) |node| : (it = node.next) { while (it) |node| : (it = node.next) {
const configured = for (server.input_manager.input_configs.items) |*input_config| { 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; break true;
} }
} else false; } else false;

View File

@ -47,8 +47,6 @@ const SurfaceRenderData = struct {
/// The rendering order in this function must be kept in sync with Cursor.surfaceAt() /// The rendering order in this function must be kept in sync with Cursor.surfaceAt()
pub fn renderOutput(output: *Output) void { pub fn renderOutput(output: *Output) void {
const renderer = output.wlr_output.backend.getRenderer().?;
var now: os.timespec = undefined; var now: os.timespec = undefined;
os.clock_gettime(os.CLOCK_MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported"); os.clock_gettime(os.CLOCK_MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported");
@ -66,7 +64,7 @@ pub fn renderOutput(output: *Output) void {
return; 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 // 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); 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 we have a fullscreen view to render, render it.
if (fullscreen_view) |view| { if (fullscreen_view) |view| {
// Always clear with solid black for fullscreen // 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); renderView(output, view, &now);
if (build_options.xwayland) renderXwaylandUnmanaged(output, &now); if (build_options.xwayland) renderXwaylandUnmanaged(output, &now);
} else { } else {
// No fullscreen view, so render normal layers/views // 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(.background).*, &now, .toplevels);
renderLayer(output, output.getLayer(.bottom).*, &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 // Conclude rendering and swap the buffers, showing the final frame
// on-screen. // on-screen.
renderer.end(); server.renderer.end();
// TODO: handle failure // TODO: handle failure
output.wlr_output.commit() catch 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 { 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 // This takes our matrix, the texture, and an alpha, and performs the actual
// rendering on the GPU. // rendering on the GPU.
const renderer = output.wlr_output.backend.getRenderer().?; server.renderer.renderSubtextureWithMatrix(texture, source_box, &matrix, 1.0) catch return;
renderer.renderSubtextureWithMatrix(texture, source_box, &matrix, 1.0) catch return;
} }
fn renderBorders(output: *const Output, view: *View, now: *os.timespec) void { 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 { fn renderRect(output: *const Output, box: Box, color: *const [4]f32) void {
var wlr_box = box.toWlrBox(); var wlr_box = box.toWlrBox();
scaleBox(&wlr_box, output.wlr_output.scale); scaleBox(&wlr_box, output.wlr_output.scale);
output.wlr_output.backend.getRenderer().?.renderRect( server.renderer.renderRect(&wlr_box, color, &output.wlr_output.transform_matrix);
&wlr_box,
color,
&output.wlr_output.transform_matrix,
);
} }
/// Scale a wlr_box, taking the possibility of fractional scaling into account. /// Scale a wlr_box, taking the possibility of fractional scaling into account.