beansprout-custom/src/InputDevice.zig
Ben Buhse 296f875993
Implement libinput device configuration
We need to defer config application to the first manage_start event
using a should_manage flag so that all *_support events have arrived
before we try applying the configs

This commit also has two other fixes
- fixes a potential use-after-free by telling InputDevice when a
 LibinputDevice is .removed.
- fix logFn (removed "if (scope != .default) return;")

I used kwm to help figure out the manage pattern for the input config.
Link to kwm: https://github.com/kewuaa/kwm
2026-02-10 20:06:17 -06:00

74 lines
2.2 KiB
Zig

// SPDX-FileCopyrightText: 2026 Ben Buhse <me@benbuhse.email>
//
// SPDX-License-Identifier: GPL-3.0-or-later
const InputDevice = @This();
river_input_device_v1: *river.InputDeviceV1,
/// The LibinputDevice that corresponds to this same InputDevice.
/// This comes later (and from a separate river protocol) and
/// not all InputDevices are necessarily LibinputDevices, too,
/// so it's optional.
libinput_device: ?*LibinputDevice = null,
type: ?Type = null,
name: ?[]const u8 = null,
link: wl.list.Link,
pub fn create(river_input_device_v1: *river.InputDeviceV1) !*InputDevice {
const input_device = try utils.allocator.create(InputDevice);
errdefer input_device.destroy();
input_device.* = .{
.river_input_device_v1 = river_input_device_v1,
.link = undefined, // handled by the wl.List
};
input_device.river_input_device_v1.setListener(
*InputDevice,
riverInputDeviceV1Listener,
input_device,
);
return input_device;
}
pub fn destroy(input_device: *InputDevice) void {
if (input_device.libinput_device) |libinput_device| {
libinput_device.input_device = null;
}
if (input_device.name) |name| {
utils.allocator.free(name);
}
input_device.link.remove();
utils.allocator.destroy(input_device);
}
fn riverInputDeviceV1Listener(river_input_device_v1: *river.InputDeviceV1, event: river.InputDeviceV1.Event, input_device: *InputDevice) void {
assert(input_device.river_input_device_v1 == river_input_device_v1);
switch (event) {
.removed => {
river_input_device_v1.destroy();
input_device.destroy();
},
.type => |ev| input_device.type = ev.type,
.name => |ev| input_device.name = utils.allocator.dupe(u8, mem.span(ev.name)) catch @panic("Out of memory"),
}
}
const std = @import("std");
const assert = std.debug.assert;
const mem = std.mem;
const wayland = @import("wayland");
const wl = wayland.client.wl;
const river = wayland.client.river;
const Type = river.InputDeviceV1.Type;
const utils = @import("utils.zig");
const Context = @import("Context.zig");
const LibinputDevice = @import("LibinputDevice.zig");
const log = std.log.scoped(.InputDevice);