Switch Wallpaper to use river_shell_surface_v1
This changes it from using zwlr_layer_surface's to river shell surfaces just so that the manage/render cycle matches as much of the rest of the wm as possible. I also made a few small fixes to Bar that I noticed while working on the wallpaper change
This commit is contained in:
parent
ce01eeefe2
commit
8b8efe2186
4 changed files with 114 additions and 119 deletions
35
src/Bar.zig
35
src/Bar.zig
|
|
@ -25,17 +25,15 @@ output: *Output,
|
||||||
// Bar geometry
|
// Bar geometry
|
||||||
geometry: Rect = .{},
|
geometry: Rect = .{},
|
||||||
|
|
||||||
surfaces: ?struct {
|
surfaces: struct {
|
||||||
wl_surface: *wl.Surface,
|
wl_surface: *wl.Surface,
|
||||||
river_shell_surface: *river.ShellSurfaceV1,
|
river_shell_surface: *river.ShellSurfaceV1,
|
||||||
node: *river.NodeV1,
|
node: *river.NodeV1,
|
||||||
} = null,
|
},
|
||||||
|
|
||||||
pending_manage: PendingManage = .{},
|
pending_manage: PendingManage = .{},
|
||||||
pending_render: PendingRender = .{},
|
pending_render: PendingRender = .{},
|
||||||
|
|
||||||
configured: bool = false,
|
|
||||||
|
|
||||||
pub const PendingManage = struct {
|
pub const PendingManage = struct {
|
||||||
output_geometry: bool = false,
|
output_geometry: bool = false,
|
||||||
};
|
};
|
||||||
|
|
@ -116,21 +114,20 @@ pub fn init(context: *Context, output: *Output, options: Options) !Bar {
|
||||||
.river_shell_surface = river_shell_surface,
|
.river_shell_surface = river_shell_surface,
|
||||||
.node = node,
|
.node = node,
|
||||||
},
|
},
|
||||||
.configured = true,
|
|
||||||
.pending_manage = .{ .output_geometry = true },
|
.pending_manage = .{ .output_geometry = true },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(bar: *Bar) void {
|
pub fn deinit(bar: *Bar) void {
|
||||||
bar.configured = false;
|
bar.output.bar = null;
|
||||||
|
|
||||||
bar.timezone.deinit();
|
bar.timezone.deinit();
|
||||||
bar.fcft_fonts.destroy();
|
bar.fcft_fonts.destroy();
|
||||||
if (bar.surfaces) |surfaces| {
|
|
||||||
surfaces.node.destroy();
|
bar.surfaces.node.destroy();
|
||||||
surfaces.river_shell_surface.destroy();
|
bar.surfaces.river_shell_surface.destroy();
|
||||||
surfaces.wl_surface.destroy();
|
bar.surfaces.wl_surface.destroy();
|
||||||
bar.context.buffer_pool.surface_count -= 1;
|
bar.context.buffer_pool.surface_count -= 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update bar options in-place without destroying/recreating Wayland surfaces
|
/// Update bar options in-place without destroying/recreating Wayland surfaces
|
||||||
|
|
@ -144,12 +141,10 @@ pub fn reconfigure(bar: *Bar, options: Options) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn manage(bar: *Bar) !void {
|
pub fn manage(bar: *Bar) !void {
|
||||||
if (!bar.configured) return;
|
|
||||||
defer bar.pending_manage = .{};
|
defer bar.pending_manage = .{};
|
||||||
|
|
||||||
// The only manage actions we need to do are when the output changes geometry
|
// Need to adjust for new output dimensions
|
||||||
if (!bar.pending_manage.output_geometry) return;
|
if (bar.pending_manage.output_geometry) {
|
||||||
|
|
||||||
const output = bar.output;
|
const output = bar.output;
|
||||||
const options = bar.options;
|
const options = bar.options;
|
||||||
|
|
||||||
|
|
@ -173,7 +168,7 @@ pub fn manage(bar: *Bar) !void {
|
||||||
const opaque_region = try bar.context.wl_compositor.createRegion();
|
const opaque_region = try bar.context.wl_compositor.createRegion();
|
||||||
defer opaque_region.destroy();
|
defer opaque_region.destroy();
|
||||||
opaque_region.add(0, 0, width, height);
|
opaque_region.add(0, 0, width, height);
|
||||||
bar.surfaces.?.wl_surface.setOpaqueRegion(opaque_region);
|
bar.surfaces.wl_surface.setOpaqueRegion(opaque_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
const x = output.geometry.x + options.margins.left;
|
const x = output.geometry.x + options.margins.left;
|
||||||
|
|
@ -183,13 +178,13 @@ pub fn manage(bar: *Bar) !void {
|
||||||
};
|
};
|
||||||
bar.pending_render.position = .{ .x = x, .y = y };
|
bar.pending_render.position = .{ .x = x, .y = y };
|
||||||
bar.pending_render.draw = true;
|
bar.pending_render.draw = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(bar: *Bar) void {
|
pub fn render(bar: *Bar) void {
|
||||||
if (!bar.configured) return;
|
|
||||||
defer bar.pending_render = .{};
|
defer bar.pending_render = .{};
|
||||||
|
|
||||||
const surfaces = bar.surfaces orelse return;
|
const surfaces = bar.surfaces;
|
||||||
|
|
||||||
if (bar.pending_render.position) |position| {
|
if (bar.pending_render.position) |position| {
|
||||||
surfaces.node.setPosition(position.x, position.y);
|
surfaces.node.setPosition(position.x, position.y);
|
||||||
|
|
@ -204,7 +199,7 @@ pub fn render(bar: *Bar) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the bar and its components (clock, title, etc.)
|
/// Draw the bar and its components (clock, title, etc.)
|
||||||
pub fn draw(bar: *Bar) !void {
|
fn draw(bar: *Bar) !void {
|
||||||
const context = bar.context;
|
const context = bar.context;
|
||||||
const options = bar.options;
|
const options = bar.options;
|
||||||
|
|
||||||
|
|
@ -317,7 +312,7 @@ pub fn draw(bar: *Bar) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach the buffer to the surface
|
// Attach the buffer to the surface
|
||||||
const surfaces = bar.surfaces orelse return error.NoSurfaces;
|
const surfaces = bar.surfaces;
|
||||||
const wl_surface = surfaces.wl_surface;
|
const wl_surface = surfaces.wl_surface;
|
||||||
wl_surface.setBufferScale(scale);
|
wl_surface.setBufferScale(scale);
|
||||||
wl_surface.attach(buffer.wl_buffer, 0, 0);
|
wl_surface.attach(buffer.wl_buffer, 0, 0);
|
||||||
|
|
|
||||||
|
|
@ -241,9 +241,7 @@ pub fn manage(context: *Context) void {
|
||||||
if (output.wallpaper) |*wp| wp.deinit();
|
if (output.wallpaper) |*wp| wp.deinit();
|
||||||
output.wallpaper = null;
|
output.wallpaper = null;
|
||||||
} else if (output.wallpaper) |*wp| {
|
} else if (output.wallpaper) |*wp| {
|
||||||
wp.render() catch |err| {
|
wp.pending_render.draw = true;
|
||||||
log.err("Wallpaper re-render failed: {}", .{err});
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
output.wallpaper = Wallpaper.init(context, output) catch |err| {
|
output.wallpaper = Wallpaper.init(context, output) catch |err| {
|
||||||
log.err("Failed to init wallpaper surface: {}", .{err});
|
log.err("Failed to init wallpaper surface: {}", .{err});
|
||||||
|
|
|
||||||
|
|
@ -273,14 +273,6 @@ fn wlOutputListener(_: *wl.Output, event: wl.Output.Event, output: *Output) void
|
||||||
bar.pending_manage.output_geometry = true;
|
bar.pending_manage.output_geometry = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Re-render wallpaper if scale changed
|
|
||||||
if (output.wallpaper) |*wp| {
|
|
||||||
if (wp.configured and output.scale != wp.render_scale) {
|
|
||||||
wp.render() catch |err| {
|
|
||||||
log.err("Wallpaper render failed: {}", .{err});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.scale => |ev| {
|
.scale => |ev| {
|
||||||
if (ev.factor < 0) {
|
if (ev.factor < 0) {
|
||||||
|
|
@ -288,7 +280,13 @@ fn wlOutputListener(_: *wl.Output, event: wl.Output.Event, output: *Output) void
|
||||||
log.warn("Received wl_output.scale event with a negative factor ({d})", .{ev.factor});
|
log.warn("Received wl_output.scale event with a negative factor ({d})", .{ev.factor});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
output.scale = @intCast(ev.factor);
|
const new_scale: u31 = @intCast(ev.factor);
|
||||||
|
if (new_scale != output.scale) {
|
||||||
|
output.scale = new_scale;
|
||||||
|
if (output.wallpaper) |*wallpaper| {
|
||||||
|
wallpaper.pending_render.draw = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.name => |ev| {
|
.name => |ev| {
|
||||||
if (output.name) |old_name| utils.gpa.free(old_name);
|
if (output.name) |old_name| utils.gpa.free(old_name);
|
||||||
|
|
@ -311,6 +309,9 @@ pub fn manage(output: *Output) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output.pending_manage.position != null or output.pending_manage.dimensions != null) {
|
if (output.pending_manage.position != null or output.pending_manage.dimensions != null) {
|
||||||
|
if (output.wallpaper) |*wallpaper| {
|
||||||
|
wallpaper.pending_render.draw = true;
|
||||||
|
}
|
||||||
if (output.bar) |*bar| {
|
if (output.bar) |*bar| {
|
||||||
bar.pending_manage.output_geometry = true;
|
bar.pending_manage.output_geometry = true;
|
||||||
}
|
}
|
||||||
|
|
@ -459,6 +460,10 @@ pub fn manage(output: *Output) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(output: *Output) void {
|
pub fn render(output: *Output) void {
|
||||||
|
if (output.wallpaper) |*wallpaper| {
|
||||||
|
wallpaper.render();
|
||||||
|
}
|
||||||
|
|
||||||
if (output.bar) |*bar| {
|
if (output.bar) |*bar| {
|
||||||
bar.render();
|
bar.render();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,17 @@ const Wallpaper = @This();
|
||||||
context: *Context,
|
context: *Context,
|
||||||
output: *Output,
|
output: *Output,
|
||||||
|
|
||||||
wl_surface: *wl.Surface,
|
surfaces: struct {
|
||||||
layer_surface: *zwlr.LayerSurfaceV1,
|
wl_surface: *wl.Surface,
|
||||||
|
river_shell_surface: *river.ShellSurfaceV1,
|
||||||
|
node: *river.NodeV1,
|
||||||
|
},
|
||||||
|
|
||||||
render_scale: u31 = 0,
|
pending_render: PendingRender = .{},
|
||||||
render_width: u31 = 0,
|
|
||||||
render_height: u31 = 0,
|
pub const PendingRender = struct {
|
||||||
configured: bool = false,
|
draw: bool = false,
|
||||||
|
};
|
||||||
|
|
||||||
/// Decoded image data shared across all outputs.
|
/// Decoded image data shared across all outputs.
|
||||||
/// Stored on Context; each output's Wallpaper references it for rendering.
|
/// Stored on Context; each output's Wallpaper references it for rendering.
|
||||||
|
|
@ -98,74 +102,73 @@ pub fn init(context: *Context, output: *Output) !Wallpaper {
|
||||||
const wl_surface = try context.wl_compositor.createSurface();
|
const wl_surface = try context.wl_compositor.createSurface();
|
||||||
errdefer wl_surface.destroy();
|
errdefer wl_surface.destroy();
|
||||||
|
|
||||||
const layer_surface = try context.zwlr_layer_shell_v1.getLayerSurface(wl_surface, output.wl_output, .background, "beansprout-wallpaper");
|
const river_shell_surface = try context
|
||||||
errdefer layer_surface.destroy();
|
.wm
|
||||||
|
.river_window_manager_v1
|
||||||
|
.getShellSurface(wl_surface);
|
||||||
|
errdefer river_shell_surface.destroy();
|
||||||
|
|
||||||
|
const node = try river_shell_surface.getNode();
|
||||||
|
errdefer node.destroy();
|
||||||
|
|
||||||
// We don't want our surface to have any input region (default is infinite)
|
// We don't want our surface to have any input region (default is infinite)
|
||||||
const empty_region = try context.wl_compositor.createRegion();
|
const empty_region = try context.wl_compositor.createRegion();
|
||||||
defer empty_region.destroy();
|
defer empty_region.destroy();
|
||||||
wl_surface.setInputRegion(empty_region);
|
wl_surface.setInputRegion(empty_region);
|
||||||
|
|
||||||
|
context.buffer_pool.surface_count += 1;
|
||||||
|
|
||||||
// Full surface should be opaque
|
// Full surface should be opaque
|
||||||
const opaque_region = try context.wl_compositor.createRegion();
|
const opaque_region = try context.wl_compositor.createRegion();
|
||||||
opaque_region.add(0, 0, output.geometry.width, output.geometry.height);
|
opaque_region.add(0, 0, output.geometry.width, output.geometry.height);
|
||||||
defer opaque_region.destroy();
|
defer opaque_region.destroy();
|
||||||
wl_surface.setOpaqueRegion(opaque_region);
|
wl_surface.setOpaqueRegion(opaque_region);
|
||||||
|
|
||||||
layer_surface.setExclusiveZone(-1);
|
|
||||||
layer_surface.setAnchor(.{ .top = true, .right = true, .bottom = true, .left = true });
|
|
||||||
|
|
||||||
context.buffer_pool.surface_count += 1;
|
|
||||||
|
|
||||||
layer_surface.setListener(*Output, layerSurfaceListener, output);
|
|
||||||
wl_surface.commit();
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.context = context,
|
.context = context,
|
||||||
.output = output,
|
.output = output,
|
||||||
|
.surfaces = .{
|
||||||
.wl_surface = wl_surface,
|
.wl_surface = wl_surface,
|
||||||
.layer_surface = layer_surface,
|
.river_shell_surface = river_shell_surface,
|
||||||
|
.node = node,
|
||||||
|
},
|
||||||
|
.pending_render = .{ .draw = true },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(wallpaper: *Wallpaper) void {
|
pub fn deinit(wallpaper: *Wallpaper) void {
|
||||||
wallpaper.layer_surface.destroy();
|
wallpaper.output.wallpaper = null;
|
||||||
wallpaper.wl_surface.destroy();
|
|
||||||
|
wallpaper.surfaces.node.destroy();
|
||||||
|
wallpaper.surfaces.river_shell_surface.destroy();
|
||||||
|
wallpaper.surfaces.wl_surface.destroy();
|
||||||
wallpaper.context.buffer_pool.surface_count -= 1;
|
wallpaper.context.buffer_pool.surface_count -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layerSurfaceListener(layer_surface: *zwlr.LayerSurfaceV1, event: zwlr.LayerSurfaceV1.Event, output: *Output) void {
|
pub fn render(wallpaper: *Wallpaper) void {
|
||||||
switch (event) {
|
defer wallpaper.pending_render = .{};
|
||||||
.configure => |ev| {
|
|
||||||
layer_surface.ackConfigure(ev.serial);
|
|
||||||
|
|
||||||
const wallpaper = &(output.wallpaper orelse return);
|
// We draw whenever the output's dimensions or scale change
|
||||||
|
if (wallpaper.pending_render.draw) {
|
||||||
|
const output = wallpaper.output;
|
||||||
|
const geometry = output.geometry;
|
||||||
|
const width = geometry.width;
|
||||||
|
const height = geometry.height;
|
||||||
|
const scale = output.scale;
|
||||||
|
|
||||||
const width: u31 = @intCast(ev.width);
|
const opaque_region = wallpaper.context.wl_compositor.createRegion() catch |err| {
|
||||||
const height: u31 = @intCast(ev.height);
|
log.err("Failed to create opaque region: {}", .{err});
|
||||||
|
|
||||||
if (wallpaper.configured and
|
|
||||||
wallpaper.render_width == width and
|
|
||||||
wallpaper.render_height == height and
|
|
||||||
output.scale == wallpaper.render_scale)
|
|
||||||
{
|
|
||||||
wallpaper.wl_surface.commit();
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("configuring wallpaper surface with width {} and height {}", .{ width, height });
|
|
||||||
wallpaper.render_width = width;
|
|
||||||
wallpaper.render_height = height;
|
|
||||||
wallpaper.configured = true;
|
|
||||||
|
|
||||||
wallpaper.render() catch |err| {
|
|
||||||
log.err("Wallpaper render failed: {}", .{err});
|
|
||||||
};
|
};
|
||||||
},
|
defer opaque_region.destroy();
|
||||||
.closed => {
|
opaque_region.add(0, 0, width, height);
|
||||||
if (output.wallpaper) |*wp| wp.deinit();
|
|
||||||
output.wallpaper = null;
|
wallpaper.surfaces.node.placeBottom();
|
||||||
},
|
|
||||||
|
wallpaper.surfaces.wl_surface.setOpaqueRegion(opaque_region);
|
||||||
|
wallpaper.draw(width, height, scale) catch |err| {
|
||||||
|
log.err("Wallpaper draw failed: {}", .{err});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,12 +191,8 @@ fn calculateTransform(image_dimension: c_int, output_dimension: u31, dimension_s
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render the wallpaper image onto the layer surface
|
/// Render the wallpaper image onto the layer surface
|
||||||
pub fn render(wallpaper: *Wallpaper) !void {
|
fn draw(wallpaper: *Wallpaper, width: u31, height: u31, scale: u31) !void {
|
||||||
const context = wallpaper.context;
|
const context = wallpaper.context;
|
||||||
const output = wallpaper.output;
|
|
||||||
const width = wallpaper.render_width;
|
|
||||||
const height = wallpaper.render_height;
|
|
||||||
const scale = output.scale;
|
|
||||||
|
|
||||||
// Don't have anything to render
|
// Don't have anything to render
|
||||||
if (width == 0 or height == 0 or scale == 0) {
|
if (width == 0 or height == 0 or scale == 0) {
|
||||||
|
|
@ -253,13 +252,11 @@ pub fn render(wallpaper: *Wallpaper) !void {
|
||||||
log.info("render: {}x{} (scaled from {}x{})", .{ width * scale, height * scale, image_width, image_height });
|
log.info("render: {}x{} (scaled from {}x{})", .{ width * scale, height * scale, image_width, image_height });
|
||||||
|
|
||||||
// Attach the buffer to the surface
|
// Attach the buffer to the surface
|
||||||
const wl_surface = wallpaper.wl_surface;
|
const wl_surface = wallpaper.surfaces.wl_surface;
|
||||||
wl_surface.setBufferScale(scale);
|
wl_surface.setBufferScale(scale);
|
||||||
wl_surface.attach(buffer.wl_buffer, 0, 0);
|
wl_surface.attach(buffer.wl_buffer, 0, 0);
|
||||||
wl_surface.damageBuffer(0, 0, width * scale, height * scale);
|
wl_surface.damageBuffer(0, 0, width * scale, height * scale);
|
||||||
wl_surface.commit();
|
wl_surface.commit();
|
||||||
|
|
||||||
wallpaper.render_scale = scale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
@ -268,7 +265,7 @@ const native_endian = builtin.cpu.arch.endian();
|
||||||
|
|
||||||
const wayland = @import("wayland");
|
const wayland = @import("wayland");
|
||||||
const wl = wayland.client.wl;
|
const wl = wayland.client.wl;
|
||||||
const zwlr = wayland.client.zwlr;
|
const river = wayland.client.river;
|
||||||
const pixman = @import("pixman");
|
const pixman = @import("pixman");
|
||||||
const zigimg = @import("zigimg");
|
const zigimg = @import("zigimg");
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue