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
74 lines
2.2 KiB
Zig
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);
|