Fix crash when wallpaper_image_path is missing

This makes the WM run fine even if wallpaper_image fails to load for any
other reason. Right now, it's still just a black background. At some
point, I plan to add the ability to also just set a color as a
background but that's a fairly low priority.
This commit is contained in:
Ben Buhse 2026-02-07 17:56:05 -06:00
commit 00835cea08
No known key found for this signature in database
GPG key ID: 7916ACFCD38FD0B4
4 changed files with 28 additions and 6 deletions

View file

@ -20,6 +20,10 @@ focus_follows_pointer: bool = true,
/// Should the pointer warp to the center of newly-focused windows
pointer_warp_on_focus_change: bool = true,
// TODO: Implement a color when this is null
/// Path to the wallpaper image
wallpaper_image_path: []const u8 = "",
/// Tag bind entries parsed from config (tag_bind nodes in keybinds block)
tag_binds: std.ArrayList(Keybind) = .{},
keybinds: std.ArrayList(Keybind) = .{},

View file

@ -27,7 +27,7 @@ buffer_pool: BufferPool = .{},
/// Holds a pixman.Image (and its raw pixels) for the wallpaper
/// (same image on all outputs, but scaled separately)
wallpaper_image: *WallpaperImage,
wallpaper_image: ?*WallpaperImage,
// WM Configuration
config: *Config,
@ -60,6 +60,12 @@ pub fn create(options: Options) !*Context {
const context = try utils.allocator.create(Context);
errdefer context.destroy();
// FIXME: TODO: Get this from Config
const wallpaper_image = WallpaperImage.create("FIXME") catch |e| blk: {
log.err("Failed to load wallpaper image from path \"{s}\": {s}", .{ "FIXME", @errorName(e) });
break :blk null;
};
context.* = .{
.initialized = false,
.wl_compositor = options.wl_compositor,
@ -68,7 +74,7 @@ pub fn create(options: Options) !*Context {
.wl_shm = options.wl_shm,
.wl_outputs = options.wl_outputs,
.zwlr_layer_shell_v1 = options.zwlr_layer_shell_v1,
.wallpaper_image = try WallpaperImage.create("FIXME"), // FIXME: TODO: Get this from Config
.wallpaper_image = wallpaper_image,
.wm = try WindowManager.create(context, options.river_window_manager_v1),
.xkb_bindings = try XkbBindings.create(context, options.river_xkb_bindings_v1),
.config = options.config,
@ -81,7 +87,9 @@ pub fn destroy(context: *Context) void {
context.xkb_bindings.destroy();
context.wm.destroy();
context.wallpaper_image.destroy();
if (context.wallpaper_image) |wallpaper_image| {
wallpaper_image.destroy();
}
context.buffer_pool.deinit();
utils.allocator.destroy(context);

View file

@ -208,6 +208,11 @@ fn wlOutputListener(_: *wl.Output, event: wl.Output.Event, output: *Output) void
}
fn initWallpaperLayerSurface(output: *Output) !void {
if (output.context.wallpaper_image == null) {
// No wallpaper image, so we don't need any surfaces
return;
}
if (output.wl_surface) |_| {
log.warn("Skipping adding a second wallpaper surface to {s}", .{output.name orelse "some output"});
return;
@ -319,16 +324,17 @@ fn renderWallpaper(output: *Output) !void {
if (width == 0 or height == 0 or scale == 0) {
return;
}
const buffer: *Buffer = try context.buffer_pool.nextBuffer(context.wl_shm, width * scale, height * scale);
// Scale our loaded image and then copy it into the Buffer's pixman.Image
const image = context.wallpaper_image.image;
const wallpaper_image = context.wallpaper_image orelse return;
const image = wallpaper_image.image;
const image_data = image.getData();
const image_width = image.getWidth();
const image_height = image.getHeight();
const image_stride = image.getStride();
const image_format = image.getFormat();
const buffer: *Buffer = try context.buffer_pool.nextBuffer(context.wl_shm, width * scale, height * scale);
const pix = pixman.Image.createBitsNoClear(image_format, image_width, image_height, image_data, image_stride);
if (pix == null) {
log.err("failed to copy the background image for rendering", .{});

View file

@ -105,6 +105,10 @@ fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, globals: *
globals.wl_shm = registry.bind(ev.name, wl.Shm, 1) catch |e| {
fatal("Failed to bind to wl_shm: {any}", .{@errorName(e)});
};
} else if (mem.orderZ(u8, ev.interface, river.LayerShellV1.interface.name) == .eq) {
globals.river_layer_shell_v1 = registry.bind(ev.name, river.LayerShellV1, 1) catch |e| {
fatal("Failed to bind to river_layer_shell_v1: {any}", .{@errorName(e)});
};
} else if (mem.orderZ(u8, ev.interface, river.WindowManagerV1.interface.name) == .eq) {
globals.river_window_manager_v1 = registry.bind(ev.name, river.WindowManagerV1, 3) catch |e| {
fatal("Failed to bind to river_window_manager_v1: {any}", .{@errorName(e)});