Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
protocol: add xkb_binding_v1.stop_repeat
protocol/river-xkb-bindings-v1.xml | 15 +++++++++++++++
river/KeyboardGroup.zig | 11 +++++++++++
river/Seat.zig | 6 ++++++
river/XkbBinding.zig | 15 ++++++++++++---
4 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/protocol/river-xkb-bindings-v1.xml b/protocol/river-xkb-bindings-v1.xml
index 888eeea..bc41dea 100644
--- a/protocol/river-xkb-bindings-v1.xml
+++ b/protocol/river-xkb-bindings-v1.xml
@@ -188,6 +188,21 @@
input events is finite.
</description>
</event>
+
+ <event name="stop_repeat" since="2">
+ <description summary="repeating should be stopped">
+ This event indicates that repeating should be stopped for the binding if
+ the window manager has been repeating some action since the pressed
+ event.
+
+ This event is generally sent when some other (possible unbound) key is
+ pressed after the pressed event is sent and before the released event
+ is sent for this binding.
+
+ This event will be followed by a manage_start event after all other new
+ state has been sent by the server.
+ </description>
+ </event>
</interface>
<interface name="river_xkb_bindings_seat_v1" version="2">
diff --git a/river/KeyboardGroup.zig b/river/KeyboardGroup.zig
index 0a9f06b..f079ebc 100644
--- a/river/KeyboardGroup.zig
+++ b/river/KeyboardGroup.zig
@@ -176,6 +176,17 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa
return;
};
+ {
+ var it = group.seat.keyboard_groups.iterator(.forward);
+ while (it.next()) |g| {
+ for (g.pressed.values()) |press| {
+ if (press.consumer != .binding) continue;
+ const binding = press.consumer.binding orelse continue;
+ binding.stopRepeat();
+ }
+ }
+ }
+
// Every sent press event, to a regular client or the input method, should have
// the corresponding release event sent to the same client.
// Similarly, no press event means no release event.
diff --git a/river/Seat.zig b/river/Seat.zig
index 48c906e..2580a26 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -435,6 +435,12 @@ pub fn manageStart(seat: *Seat) void {
binding.sent_pressed = true;
binding.object.sendPressed();
},
+ .stop_repeat => {
+ assert(binding.sent_pressed);
+ if (binding.object.getVersion() >= 2) {
+ binding.object.sendStopRepeat();
+ }
+ },
.released => {
assert(binding.sent_pressed);
binding.sent_pressed = false;
diff --git a/river/XkbBinding.zig b/river/XkbBinding.zig
index 943924c..0ba1ebb 100644
--- a/river/XkbBinding.zig
+++ b/river/XkbBinding.zig
@@ -29,6 +29,7 @@ wm_scheduled: struct {
state_change: enum {
none,
pressed,
+ stop_repeat,
released,
} = .none,
} = .{},
@@ -136,18 +137,26 @@ fn handleRequest(
pub fn pressed(binding: *XkbBinding) void {
assert(!binding.sent_pressed);
- // Input event processing should not continue after a press/release event
+ // Input event processing should not continue after a state_change
// until that event is sent to the window manager in an update and acked.
assert(binding.wm_scheduled.state_change == .none);
binding.wm_scheduled.state_change = .pressed;
server.wm.dirtyWindowing();
}
-pub fn released(binding: *XkbBinding) void {
+pub fn stopRepeat(binding: *XkbBinding) void {
assert(binding.sent_pressed);
- // Input event processing should not continue after a press/release event
+ // Input event processing should not continue after a state change
// until that event is sent to the window manager in an update and acked.
assert(binding.wm_scheduled.state_change == .none);
+ binding.wm_scheduled.state_change = .stop_repeat;
+ server.wm.dirtyWindowing();
+}
+
+pub fn released(binding: *XkbBinding) void {
+ assert(binding.sent_pressed);
+ // stopRepeat() should always be called before released() by KeyboardGroup
+ assert(binding.wm_scheduled.state_change == .stop_repeat);
binding.wm_scheduled.state_change = .released;
server.wm.dirtyWindowing();
}