Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
WindowManager: fix possible assertion failure
It's possible for renderStart() to be called due to all tracked
configures being completed while at the same time a dirtyIdle() callback
from a dirtyRendering() call is waiting to be run. This results in the
assertion in dirtyIdle() failing.
river/WindowManager.zig | 43 +++++++++++++++++++++++++++++--------------
1 file changed, 29 insertions(+), 14 deletions(-)
diff --git a/river/WindowManager.zig b/river/WindowManager.zig
index f3a2c12..e2cca60 100644
--- a/river/WindowManager.zig
+++ b/river/WindowManager.zig
@@ -227,19 +227,26 @@ pub fn ensureRendering(wm: *WindowManager) bool {
pub fn dirtyWindowing(wm: *WindowManager) void {
wm.scheduled.dirty = true;
+ wm.addDirtyIdle();
+}
- if (wm.dirty_idle == null) {
- const event_loop = server.wl_server.getEventLoop();
- wm.dirty_idle = event_loop.addIdle(*WindowManager, dirtyIdle, wm) catch {
- log.err("out of memory", .{});
- return;
- };
- }
+pub fn cleanWindowing(wm: *WindowManager) void {
+ wm.scheduled.dirty = false;
+ wm.removeDirtyIdle();
}
pub fn dirtyRendering(wm: *WindowManager) void {
wm.rendering_scheduled.dirty = true;
+ wm.addDirtyIdle();
+}
+
+pub fn cleanRendering(wm: *WindowManager) void {
+ wm.rendering_scheduled.dirty = false;
+ wm.removeDirtyIdle();
+}
+fn addDirtyIdle(wm: *WindowManager) void {
+ assert(wm.scheduled.dirty or wm.rendering_scheduled.dirty);
if (wm.dirty_idle == null) {
const event_loop = server.wl_server.getEventLoop();
wm.dirty_idle = event_loop.addIdle(*WindowManager, dirtyIdle, wm) catch {
@@ -249,6 +256,15 @@ pub fn dirtyRendering(wm: *WindowManager) void {
}
}
+fn removeDirtyIdle(wm: *WindowManager) void {
+ if (!wm.scheduled.dirty and !wm.rendering_scheduled.dirty) {
+ if (wm.dirty_idle) |event_source| {
+ event_source.remove();
+ wm.dirty_idle = null;
+ }
+ }
+}
+
fn dirtyIdle(wm: *WindowManager) void {
assert(wm.scheduled.dirty or wm.rendering_scheduled.dirty);
wm.dirty_idle = null;
@@ -267,6 +283,8 @@ fn dirtyIdle(wm: *WindowManager) void {
fn manageStart(wm: *WindowManager) void {
assert(wm.state == .idle);
assert(wm.scheduled.dirty);
+ wm.cleanWindowing();
+ wm.state = .manage;
log.debug("manage sequence start", .{});
@@ -302,9 +320,6 @@ fn manageStart(wm: *WindowManager) void {
while (it.next()) |seat| seat.manageStart();
}
- wm.scheduled.dirty = false;
- wm.state = .manage;
-
if (wm.object) |wm_v1| {
wm_v1.sendManageStart();
} else {
@@ -379,7 +394,10 @@ pub fn notifyConfigured(wm: *WindowManager) void {
}
fn renderStart(wm: *WindowManager) void {
- assert(wm.state == .idle or wm.state.inflight_configures == 0);
+ assert((wm.state == .idle and wm.rendering_scheduled.dirty) or
+ wm.state.inflight_configures == 0);
+ wm.state = .render;
+ wm.cleanRendering();
log.debug("render sequence start", .{});
@@ -393,9 +411,6 @@ fn renderStart(wm: *WindowManager) void {
}
}
- wm.state = .render;
- wm.rendering_scheduled.dirty = false;
-
if (wm.object) |wm_v1| {
wm_v1.sendRenderStart();
} else {