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:
parent
67d07e84b0
commit
5cce49095a
@ -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);
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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.
|
||||
|
124
river/Seat.zig
124
river/Seat.zig
@ -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(
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user