Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
Seat: ignore virtual keyboards until keymap set
The wlr-virtual-keyboard-v1 protocol fails to make keyboard creation
atomic. There is nothing a client can do with a virtual keyboard that
has no keymap except for destroy it, so we can completely ignore them
until a keymap is set.
This fixes a regression with fcitx caused by river sending the null
keymap of a new virtual keyboard to fcitx.
(cherry picked from commit d08c170571722348eca3c665612704c6e7e3d800)
river/InputManager.zig | 40 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/river/InputManager.zig b/river/InputManager.zig
index ec8ea50..c8c2102 100644
--- a/river/InputManager.zig
+++ b/river/InputManager.zig
@@ -176,10 +176,46 @@ fn handleNewVirtualKeyboard(
_: *wl.Listener(*wlr.VirtualKeyboardV1),
virtual_keyboard: *wlr.VirtualKeyboardV1,
) void {
- const seat: *Seat = @alignCast(@ptrCast(virtual_keyboard.seat.data));
- seat.addDevice(&virtual_keyboard.keyboard.base, true);
+ const no_keymap = util.gpa.create(NoKeymapVirtKeyboard) catch {
+ log.err("out of memory", .{});
+ return;
+ };
+ errdefer util.gpa.destroy(no_keymap);
+
+ no_keymap.* = .{
+ .virtual_keyboard = virtual_keyboard,
+ };
+ virtual_keyboard.keyboard.base.events.destroy.add(&no_keymap.destroy);
+ virtual_keyboard.keyboard.events.keymap.add(&no_keymap.keymap);
}
+/// Ignore virtual keyboards completely until the client sets a keymap
+/// Yes, wlroots should probably do this for us.
+const NoKeymapVirtKeyboard = struct {
+ virtual_keyboard: *wlr.VirtualKeyboardV1,
+ destroy: wl.Listener(*wlr.InputDevice) = .init(handleDestroy),
+ keymap: wl.Listener(*wlr.Keyboard) = .init(handleKeymap),
+
+ fn handleDestroy(listener: *wl.Listener(*wlr.InputDevice), _: *wlr.InputDevice) void {
+ const no_keymap: *NoKeymapVirtKeyboard = @fieldParentPtr("destroy", listener);
+
+ no_keymap.destroy.link.remove();
+ no_keymap.keymap.link.remove();
+
+ util.gpa.destroy(no_keymap);
+ }
+
+ fn handleKeymap(listener: *wl.Listener(*wlr.Keyboard), _: *wlr.Keyboard) void {
+ const no_keymap: *NoKeymapVirtKeyboard = @fieldParentPtr("keymap", listener);
+ const virtual_keyboard = no_keymap.virtual_keyboard;
+
+ handleDestroy(&no_keymap.destroy, &virtual_keyboard.keyboard.base);
+
+ const seat: *Seat = @alignCast(@ptrCast(virtual_keyboard.seat.data));
+ seat.addDevice(&virtual_keyboard.keyboard.base, true);
+ }
+};
+
fn handleNewConstraint(
_: *wl.Listener(*wlr.PointerConstraintV1),
wlr_constraint: *wlr.PointerConstraintV1,