// SPDX-FileCopyrightText: 2026 Ben Buhse // // SPDX-License-Identifier: GPL-3.0-only 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.gpa.create(InputDevice); errdefer utils.gpa.destroy(input_device); 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.gpa.free(name); } input_device.link.remove(); utils.gpa.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.gpa.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);