Seat: refactor InputDevice handling

- The lifetimes of the Keyboard and Switch structs are now directly
tied to the corresponding InputDevice, which has become a field of
those structs.

- Seat capabilities are now properly updated on removing a keyboard.

These changes align with input device refactoring in upstream wlroots
which will make updating to easier 0.16.0.
This commit is contained in:
Isaac Freund 2022-06-21 16:25:37 +02:00
parent 67d07e84b0
commit 5cce49095a
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
8 changed files with 208 additions and 197 deletions

View File

@ -288,7 +288,7 @@ pub fn deinit(self: *Self) void {
pub fn apply(self: *Self, device: *InputDevice) void {
const libinput_device = @ptrCast(
*c.libinput_device,
device.device.getLibinputDevice() orelse return,
device.wlr_device.getLibinputDevice() orelse return,
);
log.debug("applying input configuration to device: {s}", .{device.identifier});
if (self.event_state) |setting| setting.apply(libinput_device);

View File

@ -25,9 +25,15 @@ const wl = @import("wayland").server.wl;
const server = &@import("main.zig").server;
const util = @import("util.zig");
const Seat = @import("Seat.zig");
const Keyboard = @import("Keyboard.zig");
const Switch = @import("Switch.zig");
const log = std.log.scoped(.input_manager);
device: *wlr.InputDevice,
seat: *Seat,
wlr_device: *wlr.InputDevice,
destroy: wl.Listener(*wlr.InputDevice) = wl.Listener(*wlr.InputDevice).init(handleDestroy),
/// Careful: The identifier is not unique! A physical input device may have
@ -35,10 +41,13 @@ destroy: wl.Listener(*wlr.InputDevice) = wl.Listener(*wlr.InputDevice).init(hand
/// and name. However identifiers of InputConfigs are unique.
identifier: []const u8,
pub fn init(self: *InputDevice, device: *wlr.InputDevice) !void {
const device_type: []const u8 = switch (device.type) {
/// InputManager.devices
link: wl.list.Link,
pub fn init(device: *InputDevice, seat: *Seat, wlr_device: *wlr.InputDevice) !void {
const device_type: []const u8 = switch (wlr_device.type) {
.switch_device => "switch",
else => @tagName(device.type),
else => @tagName(wlr_device.type),
};
const identifier = try std.fmt.allocPrint(
@ -46,35 +55,72 @@ pub fn init(self: *InputDevice, device: *wlr.InputDevice) !void {
"{s}-{}-{}-{s}",
.{
device_type,
device.vendor,
device.product,
mem.trim(u8, mem.span(device.name), &ascii.spaces),
wlr_device.vendor,
wlr_device.product,
mem.trim(u8, mem.span(wlr_device.name), &ascii.spaces),
},
);
errdefer util.gpa.free(identifier);
for (identifier) |*char| {
if (!ascii.isGraph(char.*)) {
char.* = '_';
}
}
self.* = .{
.device = device,
device.* = .{
.seat = seat,
.wlr_device = wlr_device,
.identifier = identifier,
.link = undefined,
};
log.debug("new input device: {s}", .{self.identifier});
device.events.destroy.add(&self.destroy);
wlr_device.events.destroy.add(&device.destroy);
// Apply any matching input device configuration.
for (server.input_manager.configs.items) |*input_config| {
if (mem.eql(u8, input_config.identifier, identifier)) {
input_config.apply(device);
}
}
server.input_manager.devices.append(device);
seat.updateCapabilities();
log.debug("new input device: {s}", .{identifier});
}
pub fn deinit(self: *InputDevice) void {
util.gpa.free(self.identifier);
self.destroy.link.remove();
pub fn deinit(device: *InputDevice) void {
device.destroy.link.remove();
util.gpa.free(device.identifier);
device.link.remove();
device.seat.updateCapabilities();
device.* = undefined;
}
fn handleDestroy(listener: *wl.Listener(*wlr.InputDevice), _: *wlr.InputDevice) void {
const self = @fieldParentPtr(InputDevice, "destroy", listener);
log.debug("removed input device: {s}", .{self.identifier});
self.deinit();
const device = @fieldParentPtr(InputDevice, "destroy", listener);
const node = @fieldParentPtr(std.TailQueue(InputDevice).Node, "data", self);
server.input_manager.input_devices.remove(node);
util.gpa.destroy(node);
log.debug("removed input device: {s}", .{device.identifier});
switch (device.wlr_device.type) {
.keyboard => {
const keyboard = @fieldParentPtr(Keyboard, "device", device);
keyboard.deinit();
util.gpa.destroy(keyboard);
},
.pointer => {
device.deinit();
util.gpa.destroy(device);
},
.switch_device => {
const switch_device = @fieldParentPtr(Switch, "device", device);
switch_device.deinit();
util.gpa.destroy(switch_device);
},
.touch, .tablet_tool, .tablet_pad => unreachable,
}
}

View File

@ -18,6 +18,7 @@ const Self = @This();
const build_options = @import("build_options");
const std = @import("std");
const assert = std.debug.assert;
const mem = std.mem;
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;
@ -27,8 +28,10 @@ const util = @import("util.zig");
const InputConfig = @import("InputConfig.zig");
const InputDevice = @import("InputDevice.zig");
const Seat = @import("Seat.zig");
const Keyboard = @import("Keyboard.zig");
const PointerConstraint = @import("PointerConstraint.zig");
const Seat = @import("Seat.zig");
const Switch = @import("Switch.zig");
const default_seat_name = "default";
@ -43,8 +46,8 @@ relative_pointer_manager: *wlr.RelativePointerManagerV1,
virtual_pointer_manager: *wlr.VirtualPointerManagerV1,
virtual_keyboard_manager: *wlr.VirtualKeyboardManagerV1,
input_configs: std.ArrayList(InputConfig),
input_devices: std.TailQueue(InputDevice) = .{},
configs: std.ArrayList(InputConfig),
devices: wl.list.Head(InputDevice, "link"),
seats: std.TailQueue(Seat) = .{},
exclusive_client: ?*wl.Client = null,
@ -72,8 +75,11 @@ pub fn init(self: *Self) !void {
.relative_pointer_manager = try wlr.RelativePointerManagerV1.create(server.wl_server),
.virtual_pointer_manager = try wlr.VirtualPointerManagerV1.create(server.wl_server),
.virtual_keyboard_manager = try wlr.VirtualKeyboardManagerV1.create(server.wl_server),
.input_configs = std.ArrayList(InputConfig).init(util.gpa),
.configs = std.ArrayList(InputConfig).init(util.gpa),
.devices = undefined,
};
self.devices.init();
self.seats.prepend(seat_node);
try seat_node.data.init(default_seat_name);
@ -89,20 +95,18 @@ pub fn init(self: *Self) !void {
}
pub fn deinit(self: *Self) void {
// This function must be called after the backend has been destroyed
assert(self.devices.empty());
while (self.seats.pop()) |seat_node| {
seat_node.data.deinit();
util.gpa.destroy(seat_node);
}
while (self.input_devices.pop()) |input_device_node| {
input_device_node.data.deinit();
util.gpa.destroy(input_device_node);
for (self.configs.items) |*config| {
config.deinit();
}
for (self.input_configs.items) |*input_config| {
input_config.deinit();
}
self.input_configs.deinit();
self.configs.deinit();
}
pub fn defaultSeat(self: Self) *Seat {
@ -172,25 +176,10 @@ fn handleInhibitDeactivate(
server.root.startTransaction();
}
/// This event is raised by the backend when a new input device becomes available.
fn handleNewInput(listener: *wl.Listener(*wlr.InputDevice), device: *wlr.InputDevice) void {
fn handleNewInput(listener: *wl.Listener(*wlr.InputDevice), wlr_device: *wlr.InputDevice) void {
const self = @fieldParentPtr(Self, "new_input", listener);
// TODO: support multiple seats
const input_device_node = util.gpa.create(std.TailQueue(InputDevice).Node) catch return;
input_device_node.data.init(device) catch {
util.gpa.destroy(input_device_node);
return;
};
self.input_devices.append(input_device_node);
self.defaultSeat().addDevice(device);
// Apply matching input device configuration, if exists.
for (self.input_configs.items) |*input_config| {
if (mem.eql(u8, input_config.identifier, input_device_node.data.identifier)) {
input_config.apply(&input_device_node.data);
}
}
self.defaultSeat().addDevice(wlr_device);
}
fn handleNewPointerConstraint(

View File

@ -27,41 +27,34 @@ const util = @import("util.zig");
const KeycodeSet = @import("KeycodeSet.zig");
const Seat = @import("Seat.zig");
const InputDevice = @import("InputDevice.zig");
const log = std.log.scoped(.keyboard);
seat: *Seat,
input_device: *wlr.InputDevice,
device: InputDevice,
/// Pressed keys for which a mapping was triggered on press
eaten_keycodes: KeycodeSet = .{},
key: wl.Listener(*wlr.Keyboard.event.Key) = wl.Listener(*wlr.Keyboard.event.Key).init(handleKey),
modifiers: wl.Listener(*wlr.Keyboard) = wl.Listener(*wlr.Keyboard).init(handleModifiers),
destroy: wl.Listener(*wlr.Keyboard) = wl.Listener(*wlr.Keyboard).init(handleDestroy),
pub fn init(self: *Self, seat: *Seat, input_device: *wlr.InputDevice) !void {
pub fn init(self: *Self, seat: *Seat, wlr_device: *wlr.InputDevice) !void {
self.* = .{
.seat = seat,
.input_device = input_device,
.device = undefined,
};
try self.device.init(seat, wlr_device);
errdefer self.device.deinit();
// We need to prepare an XKB keymap and assign it to the keyboard. This
// assumes the defaults (e.g. layout = "us").
const rules = xkb.RuleNames{
.rules = null,
.model = null,
.layout = null,
.variant = null,
.options = null,
};
const context = xkb.Context.new(.no_flags) orelse return error.XkbContextFailed;
defer context.unref();
const keymap = xkb.Keymap.newFromNames(context, &rules, .no_flags) orelse return error.XkbKeymapFailed;
// Passing null here indicates that defaults from libxkbcommon and
// its XKB_DEFAULT_LAYOUT, XKB_DEFAULT_OPTIONS, etc. should be used.
const keymap = xkb.Keymap.newFromNames(context, null, .no_flags) orelse return error.XkbKeymapFailed;
defer keymap.unref();
const wlr_keyboard = self.input_device.device.keyboard;
const wlr_keyboard = self.device.wlr_device.device.keyboard;
wlr_keyboard.data = @ptrToInt(self);
if (!wlr_keyboard.setKeymap(keymap)) return error.SetKeymapFailed;
@ -70,23 +63,25 @@ pub fn init(self: *Self, seat: *Seat, input_device: *wlr.InputDevice) !void {
wlr_keyboard.events.key.add(&self.key);
wlr_keyboard.events.modifiers.add(&self.modifiers);
wlr_keyboard.events.destroy.add(&self.destroy);
}
pub fn deinit(self: *Self) void {
self.key.link.remove();
self.modifiers.link.remove();
self.destroy.link.remove();
self.device.deinit();
self.* = undefined;
}
fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboard.event.Key) void {
// This event is raised when a key is pressed or released.
const self = @fieldParentPtr(Self, "key", listener);
const wlr_keyboard = self.input_device.device.keyboard;
const wlr_keyboard = self.device.wlr_device.device.keyboard;
self.seat.handleActivity();
self.device.seat.handleActivity();
self.seat.clearRepeatingMapping();
self.device.seat.clearRepeatingMapping();
// Translate libinput keycode -> xkbcommon
const keycode = event.keycode + 8;
@ -103,7 +98,7 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa
!released and
!isModifier(sym))
{
self.seat.cursor.hide();
self.device.seat.cursor.hide();
break;
}
}
@ -114,11 +109,11 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa
}
// Handle user-defined mappings
const mapped = self.seat.hasMapping(keycode, modifiers, released, xkb_state);
const mapped = self.device.seat.hasMapping(keycode, modifiers, released, xkb_state);
if (mapped) {
if (!released) self.eaten_keycodes.add(event.keycode);
const handled = self.seat.handleMapping(keycode, modifiers, released, xkb_state);
const handled = self.device.seat.handleMapping(keycode, modifiers, released, xkb_state);
assert(handled);
}
@ -126,8 +121,8 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa
if (!eaten) {
// If key was not handled, we pass it along to the client.
const wlr_seat = self.seat.wlr_seat;
wlr_seat.setKeyboard(self.input_device);
const wlr_seat = self.device.seat.wlr_seat;
wlr_seat.setKeyboard(self.device.wlr_device);
wlr_seat.keyboardNotifyKey(event.time_msec, event.keycode, event.state);
}
}
@ -140,17 +135,8 @@ fn isModifier(keysym: xkb.Keysym) bool {
fn handleModifiers(listener: *wl.Listener(*wlr.Keyboard), _: *wlr.Keyboard) void {
const self = @fieldParentPtr(Self, "modifiers", listener);
self.seat.wlr_seat.setKeyboard(self.input_device);
self.seat.wlr_seat.keyboardNotifyModifiers(&self.input_device.device.keyboard.modifiers);
}
fn handleDestroy(listener: *wl.Listener(*wlr.Keyboard), _: *wlr.Keyboard) void {
const self = @fieldParentPtr(Self, "destroy", listener);
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
self.seat.keyboards.remove(node);
self.deinit();
util.gpa.destroy(node);
self.device.seat.wlr_seat.setKeyboard(self.device.wlr_device);
self.device.seat.wlr_seat.keyboardNotifyModifiers(&self.device.wlr_device.device.keyboard.modifiers);
}
/// Handle any builtin, harcoded compsitor mappings such as VT switching.

View File

@ -27,16 +27,17 @@ const command = @import("command.zig");
const server = &@import("main.zig").server;
const util = @import("util.zig");
const DragIcon = @import("DragIcon.zig");
const Cursor = @import("Cursor.zig");
const DragIcon = @import("DragIcon.zig");
const InputDevice = @import("InputDevice.zig");
const InputManager = @import("InputManager.zig");
const Keyboard = @import("Keyboard.zig");
const KeycodeSet = @import("KeycodeSet.zig");
const Switch = @import("Switch.zig");
const Mapping = @import("Mapping.zig");
const LayerSurface = @import("LayerSurface.zig");
const Mapping = @import("Mapping.zig");
const Output = @import("Output.zig");
const SeatStatus = @import("SeatStatus.zig");
const Switch = @import("Switch.zig");
const View = @import("View.zig");
const ViewStack = @import("view_stack.zig").ViewStack;
const XwaylandOverrideRedirect = @import("XwaylandOverrideRedirect.zig");
@ -56,12 +57,6 @@ wlr_seat: *wlr.Seat,
/// Multiple mice are handled by the same Cursor
cursor: Cursor = undefined,
/// Mulitple keyboards are handled separately
keyboards: std.TailQueue(Keyboard) = .{},
/// There are two kind of switches: lid switches and tablet mode switches
switches: std.TailQueue(Switch) = .{},
/// ID of the current keymap mode
mode_id: u32 = 0,
@ -122,19 +117,14 @@ pub fn init(self: *Self, name: [*:0]const u8) !void {
}
pub fn deinit(self: *Self) void {
{
var it = server.input_manager.devices.iterator(.forward);
while (it.next()) |device| assert(device.seat != self);
}
self.cursor.deinit();
self.mapping_repeat_timer.remove();
while (self.keyboards.pop()) |node| {
node.data.deinit();
util.gpa.destroy(node);
}
while (self.switches.pop()) |node| {
node.data.deinit();
util.gpa.destroy(node);
}
while (self.focus_stack.first) |node| {
self.focus_stack.remove(node);
util.gpa.destroy(node);
@ -464,52 +454,60 @@ fn handleMappingRepeatTimeout(self: *Self) callconv(.C) c_int {
return 0;
}
/// Add a newly created input device to the seat and update the reported
/// capabilities.
pub fn addDevice(self: *Self, device: *wlr.InputDevice) void {
switch (device.type) {
.keyboard => self.addKeyboard(device) catch return,
.pointer => self.addPointer(device),
.switch_device => self.addSwitch(device) catch return,
else => return,
pub fn addDevice(self: *Self, wlr_device: *wlr.InputDevice) void {
self.tryAddDevice(wlr_device) catch |err| switch (err) {
error.OutOfMemory => log.err("out of memory", .{}),
error.XkbContextFailed => log.err("failed to create xkbcommon context", .{}),
error.XkbKeymapFailed => log.err("failed to create xkbcommon keymap", .{}),
error.SetKeymapFailed => log.err("failed to set wlroots keymap", .{}),
};
}
fn tryAddDevice(self: *Self, wlr_device: *wlr.InputDevice) !void {
switch (wlr_device.type) {
.keyboard => {
const keyboard = try util.gpa.create(Keyboard);
errdefer util.gpa.destroy(keyboard);
try keyboard.init(self, wlr_device);
},
.pointer => {
const device = try util.gpa.create(InputDevice);
errdefer util.gpa.destroy(device);
try device.init(self, wlr_device);
self.cursor.wlr_cursor.attachInputDevice(wlr_device);
},
.switch_device => {
const switch_device = try util.gpa.create(Switch);
errdefer util.gpa.destroy(switch_device);
try switch_device.init(self, wlr_device);
},
// TODO Support these types of input devices.
.touch, .tablet_tool, .tablet_pad => return,
}
}
pub fn updateCapabilities(self: *Self) void {
// Currently a cursor is always drawn even if there are no pointer input devices.
// TODO Don't draw a cursor if there are no input devices.
var capabilities: wl.Seat.Capability = .{ .pointer = true };
var it = server.input_manager.devices.iterator(.forward);
while (it.next()) |device| {
if (device.seat == self) {
switch (device.wlr_device.type) {
.keyboard => capabilities.keyboard = true,
.pointer, .switch_device => {},
.touch, .tablet_tool, .tablet_pad => unreachable,
}
}
}
// We need to let the wlr_seat know what our capabilities are, which is
// communiciated to the client. We always have a cursor, even if
// there are no pointer devices, so we always include that capability.
self.wlr_seat.setCapabilities(.{
.pointer = true,
.keyboard = self.keyboards.len > 0,
});
}
fn addKeyboard(self: *Self, device: *wlr.InputDevice) !void {
const node = try util.gpa.create(std.TailQueue(Keyboard).Node);
node.data.init(self, device) catch |err| {
const log_keyboard = std.log.scoped(.keyboard);
switch (err) {
error.XkbContextFailed => log_keyboard.err("Failed to create XKB context", .{}),
error.XkbKeymapFailed => log_keyboard.err("Failed to create XKB keymap", .{}),
error.SetKeymapFailed => log_keyboard.err("Failed to set wlr keyboard keymap", .{}),
}
return;
};
self.keyboards.append(node);
self.wlr_seat.setKeyboard(device);
}
fn addPointer(self: Self, device: *wlr.InputDevice) void {
// We don't do anything special with pointers. All of our pointer handling
// is proxied through wlr_cursor. On another compositor, you might take this
// opportunity to do libinput configuration on the device to set
// acceleration, etc.
self.cursor.wlr_cursor.attachInputDevice(device);
}
fn addSwitch(self: *Self, device: *wlr.InputDevice) !void {
const node = try util.gpa.create(std.TailQueue(Switch).Node);
node.data.init(self, device);
self.switches.append(node);
self.wlr_seat.setCapabilities(capabilities);
}
fn handleRequestSetSelection(

View File

@ -24,6 +24,7 @@ const server = &@import("main.zig").server;
const util = @import("util.zig");
const Seat = @import("Seat.zig");
const InputDevice = @import("InputDevice.zig");
const log = std.log.scoped(.switch_device);
@ -47,33 +48,32 @@ pub const TabletState = enum {
on,
};
seat: *Seat,
input_device: *wlr.InputDevice,
device: InputDevice,
switch_device: wl.Listener(*wlr.Switch.event.Toggle) = wl.Listener(*wlr.Switch.event.Toggle).init(handleToggle),
destroy: wl.Listener(*wlr.InputDevice) = wl.Listener(*wlr.InputDevice).init(handleDestroy),
toggle: wl.Listener(*wlr.Switch.event.Toggle) = wl.Listener(*wlr.Switch.event.Toggle).init(handleToggle),
pub fn init(self: *Self, seat: *Seat, input_device: *wlr.InputDevice) void {
pub fn init(self: *Self, seat: *Seat, wlr_device: *wlr.InputDevice) !void {
self.* = .{
.seat = seat,
.input_device = input_device,
.device = undefined,
};
try self.device.init(seat, wlr_device);
errdefer self.device.deinit();
const wlr_switch = self.input_device.device.switch_device;
wlr_switch.events.toggle.add(&self.switch_device);
self.input_device.events.destroy.add(&self.destroy);
wlr_device.device.switch_device.events.toggle.add(&self.toggle);
}
pub fn deinit(self: *Self) void {
self.destroy.link.remove();
self.toggle.link.remove();
self.device.deinit();
self.* = undefined;
}
fn handleToggle(listener: *wl.Listener(*wlr.Switch.event.Toggle), event: *wlr.Switch.event.Toggle) void {
// This event is raised when the lid witch or the tablet mode switch is toggled.
const self = @fieldParentPtr(Self, "switch_device", listener);
const self = @fieldParentPtr(Self, "toggle", listener);
self.seat.handleActivity();
self.device.seat.handleActivity();
var switch_type: Type = undefined;
var switch_state: State = undefined;
@ -96,14 +96,5 @@ fn handleToggle(listener: *wl.Listener(*wlr.Switch.event.Toggle), event: *wlr.Sw
},
}
self.seat.handleSwitchMapping(switch_type, switch_state);
}
fn handleDestroy(listener: *wl.Listener(*wlr.InputDevice), _: *wlr.InputDevice) void {
const self = @fieldParentPtr(Self, "destroy", listener);
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
self.seat.switches.remove(node);
self.deinit();
util.gpa.destroy(node);
self.device.seat.handleSwitchMapping(switch_type, switch_state);
}

View File

@ -38,10 +38,10 @@ pub fn listInputs(
const writer = input_list.writer();
var prev = false;
var it = server.input_manager.input_devices.first;
while (it) |node| : (it = node.next) {
const configured = for (server.input_manager.input_configs.items) |*input_config| {
if (mem.eql(u8, input_config.identifier, node.data.identifier)) {
var it = server.input_manager.devices.iterator(.forward);
while (it.next()) |device| {
const configured = for (server.input_manager.configs.items) |*input_config| {
if (mem.eql(u8, input_config.identifier, device.identifier)) {
break true;
}
} else false;
@ -49,9 +49,8 @@ pub fn listInputs(
if (prev) try input_list.appendSlice("\n");
prev = true;
try writer.print("{s}\n\ttype: {s}\n\tconfigured: {s}\n", .{
node.data.identifier,
@tagName(node.data.device.type),
try writer.print("{s}\n\tconfigured: {s}\n", .{
device.identifier,
configured,
});
}
@ -69,7 +68,7 @@ pub fn listInputConfigs(
var input_list = std.ArrayList(u8).init(util.gpa);
const writer = input_list.writer();
for (server.input_manager.input_configs.items) |*input_config, i| {
for (server.input_manager.configs.items) |*input_config, i| {
if (i > 0) try input_list.appendSlice("\n");
try writer.print("{s}\n", .{input_config.identifier});
@ -134,19 +133,19 @@ pub fn input(
// Try to find an existing InputConfig with matching identifier, or create
// a new one if none was found.
var new = false;
const input_config = for (server.input_manager.input_configs.items) |*input_config| {
const input_config = for (server.input_manager.configs.items) |*input_config| {
if (mem.eql(u8, input_config.identifier, args[1])) break input_config;
} else blk: {
try server.input_manager.input_configs.ensureUnusedCapacity(1);
server.input_manager.input_configs.appendAssumeCapacity(.{
try server.input_manager.configs.ensureUnusedCapacity(1);
server.input_manager.configs.appendAssumeCapacity(.{
.identifier = try util.gpa.dupe(u8, args[1]),
});
new = true;
break :blk &server.input_manager.input_configs.items[server.input_manager.input_configs.items.len - 1];
break :blk &server.input_manager.configs.items[server.input_manager.configs.items.len - 1];
};
errdefer {
if (new) {
var cfg = server.input_manager.input_configs.pop();
var cfg = server.input_manager.configs.pop();
cfg.deinit();
}
}
@ -204,10 +203,10 @@ pub fn input(
}
// Update matching existing input devices.
var it = server.input_manager.input_devices.first;
while (it) |device_node| : (it = device_node.next) {
if (mem.eql(u8, device_node.data.identifier, args[1])) {
input_config.apply(&device_node.data);
var it = server.input_manager.devices.iterator(.forward);
while (it.next()) |device| {
if (mem.eql(u8, device.identifier, args[1])) {
input_config.apply(device);
// We don't break here because it is common to have multiple input
// devices with the same identifier.
}

View File

@ -23,7 +23,7 @@ const Seat = @import("../Seat.zig");
/// Set the repeat rate and delay for all keyboards.
pub fn setRepeat(
seat: *Seat,
_: *Seat,
args: []const [:0]const u8,
_: *?[]const u8,
) Error!void {
@ -36,8 +36,10 @@ pub fn setRepeat(
server.config.repeat_rate = rate;
server.config.repeat_delay = delay;
var it = seat.keyboards.first;
while (it) |node| : (it = node.next) {
node.data.input_device.device.keyboard.setRepeatInfo(rate, delay);
var it = server.input_manager.devices.iterator(.forward);
while (it.next()) |device| {
if (device.wlr_device.type == .keyboard) {
device.wlr_device.device.keyboard.setRepeatInfo(rate, delay);
}
}
}