Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
Seat: fix race on ending resize op
Currently, a race may cause a jump in window position when a resize
operation is ended. This is due to Window.pending.width/height remaining
modified when Window.pending.op is reset to null.
This commit fixes the race.
river/Seat.zig | 14 ++++++++++----
river/WindowManager.zig | 5 +----
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/river/Seat.zig b/river/Seat.zig
index 9881a2f..90a10dc 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -272,10 +272,16 @@ pub fn queueEvent(seat: *Seat, event: Event) void {
pub fn processEvents(seat: *Seat) void {
assert(server.wm.state == .idle);
- // Only process events while there is no pending state to be sent to the window manager.
+ // Only process events while there is no pending state to be sent to the window manager
+ // and no transaction in progress.
+ //
// The window manager might decide to change focus or redefine keyboard/pointer bindings
- // in response to the pending update.
- while (!server.wm.pending.dirty) {
+ // in response to the pending update, which can affect further processing of events.
+ //
+ // Allowing event processing while there is a transaction in progress would require keeping
+ // track of additional state to differentiate pending state modified since the transaction
+ // was started. I don't see an advantage to that additional complexity.
+ while (server.wm.state == .idle and !server.wm.pending.dirty) {
const event = seat.event_queue.readItem() orelse break;
const pg = server.input_manager.pointer_gestures;
@@ -301,8 +307,8 @@ pub fn processEvents(seat: *Seat) void {
if (seat.op) |*op| {
if (op.dirty) {
- server.wm.dirtyPending();
op.dirty = false;
+ server.wm.sendConfigures();
}
}
}
diff --git a/river/WindowManager.zig b/river/WindowManager.zig
index 43a859d..7056497 100644
--- a/river/WindowManager.zig
+++ b/river/WindowManager.zig
@@ -277,19 +277,16 @@ fn sendUpdate(wm: *WindowManager) void {
wm.startTimeoutTimer();
} else {
- // Pretend that the non-existent wm client made an empty commit.
- wm.committed.dirty = true;
wm.sendConfigures();
}
}
-fn sendConfigures(wm: *WindowManager) void {
+pub fn sendConfigures(wm: *WindowManager) void {
switch (wm.state) {
.idle, .update_acked => {},
.update_sent, .inflight_configures => unreachable,
}
- assert(wm.committed.dirty);
wm.committed.dirty = false;
{