Handle finished events in WM and IM

I was silently ignoring these before, which wasn't bad, but mostly meant
we wouldn't close them if the compositor ever finished. For WM, we just
send SIGINT and exit the WM in main(). For IM, we destroy() and clean up
like we do in XkbConfig.
This commit is contained in:
Ben Buhse 2026-03-17 20:10:20 -05:00
commit 52785078b7
No known key found for this signature in database
GPG key ID: 7916ACFCD38FD0B4
2 changed files with 26 additions and 25 deletions

View file

@ -6,8 +6,8 @@ const InputManager = @This();
context: *Context,
river_input_manager_v1: *river.InputManagerV1,
river_libinput_config_v1: *river.LibinputConfigV1,
river_input_manager_v1: ?*river.InputManagerV1,
river_libinput_config_v1: ?*river.LibinputConfigV1,
/// All input devices that we've been advertised
input_devices: wl.list.Head(InputDevice, .link),
@ -31,58 +31,54 @@ pub fn create(context: *Context, river_input_manager_v1: *river.InputManagerV1,
im.input_devices.init();
im.libinput_devices.init();
im.river_input_manager_v1.setListener(*InputManager, inputManagerV1Listener, im);
im.river_libinput_config_v1.setListener(*InputManager, libinputConfigV1Listener, im);
river_input_manager_v1.setListener(*InputManager, inputManagerV1Listener, im);
river_libinput_config_v1.setListener(*InputManager, libinputConfigV1Listener, im);
return im;
}
pub fn destroy(im: *InputManager) void {
{
var it = im.input_devices.iterator(.forward);
while (it.next()) |input_device| {
input_device.destroy();
}
var it = im.input_devices.safeIterator(.forward);
while (it.next()) |input_device| input_device.destroy();
}
{
var it = im.libinput_devices.iterator(.forward);
while (it.next()) |libinput_device| {
libinput_device.destroy();
}
var it = im.libinput_devices.safeIterator(.forward);
while (it.next()) |libinput_device| libinput_device.destroy();
}
if (im.river_input_manager_v1) |river_input_manager_v1| {
river_input_manager_v1.destroy();
}
if (im.river_libinput_config_v1) |river_libinput_config_v1| {
river_libinput_config_v1.destroy();
}
im.river_input_manager_v1.destroy();
im.river_libinput_config_v1.destroy();
utils.gpa.destroy(im);
}
pub fn inputManagerV1Listener(river_input_manager_v1: *river.InputManagerV1, event: river.InputManagerV1.Event, im: *InputManager) void {
assert(im.river_input_manager_v1 == river_input_manager_v1);
assert(im.river_input_manager_v1.? == river_input_manager_v1);
switch (event) {
.input_device => |ev| {
const input_device = InputDevice.create(ev.id) catch @panic("Out of memory");
im.input_devices.append(input_device);
},
.finished => {
// TODO: Should call destroy on the river_input_manager_v1 and on this device,
// but might need to make the globals optional so that we know when we can destroy this
// object.
log.debug("unhandled event: finished", .{});
river_input_manager_v1.destroy();
im.river_input_manager_v1 = null;
},
}
}
pub fn libinputConfigV1Listener(river_libinput_config_v1: *river.LibinputConfigV1, event: river.LibinputConfigV1.Event, im: *InputManager) void {
assert(im.river_libinput_config_v1 == river_libinput_config_v1);
assert(im.river_libinput_config_v1.? == river_libinput_config_v1);
switch (event) {
.libinput_device => |ev| {
const libinput_device = LibinputDevice.create(im.context, ev.id) catch @panic("Out of memory");
im.libinput_devices.append(libinput_device);
},
.finished => {
// TODO: Should call destroy on the river_libinput_config_v1 and on this device,
// but might need to make the globals optional so that we know when we can destroy this
// object.
log.debug("unhandled event: finished", .{});
river_libinput_config_v1.destroy();
im.river_libinput_config_v1 = null;
},
}
}

View file

@ -284,6 +284,10 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv
s.pending_manage.should_warp_pointer = true;
}
},
.finished => {
log.info("river_window_manager_v1 finished, exiting.", .{});
posix.raise(posix.SIG.INT) catch |err| log.err("Failed to raise SIGINT: {}", .{err});
},
else => |ev| {
log.debug("unhandled event: {s}", .{@tagName(ev)});
},
@ -293,6 +297,7 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv
const std = @import("std");
const assert = std.debug.assert;
const fatal = std.process.fatal;
const posix = std.posix;
const wayland = @import("wayland");
const wl = wayland.client.wl;