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
- wayland
- wayland-protocols
- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.14
- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.15
- xkbcommon
- libevdev
- 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(
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;
}

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 {
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.

View File

@ -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

View File

@ -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;

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 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(),

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),
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()) {

View File

@ -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});
};
}

View File

@ -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;
}

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
/// 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();
}
}

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
/// 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);

View File

@ -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;

View File

@ -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.