Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
Window: fix frame perfection on close
river/Window.zig | 21 +++++++++------------
river/WindowManager.zig | 11 +++++++++--
river/XdgToplevel.zig | 2 +-
3 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/river/Window.zig b/river/Window.zig
index 9373195..adc6737 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -274,10 +274,11 @@ pub fn create(impl: Impl) error{OutOfMemory}!*Window {
return window;
}
-/// If saved buffers of the window are currently in use by a transaction,
-/// mark this window for destruction when the transaction completes. Otherwise
-/// destroy immediately.
-pub fn destroy(window: *Window, when: enum { lazy, assert }) void {
+/// It's safe to destroy the window after we no longer need the saved buffers for frame perfection.
+/// We no longer need the saved buffers after the windowing update sequence in
+/// which the closed event was sent is completed and the following rendering update
+/// sequence is completed as well.
+pub fn destroy(window: *Window, when: enum { lazy, force }) void {
assert(window.impl == .none);
assert(!window.mapped);
@@ -305,9 +306,10 @@ pub fn destroy(window: *Window, when: enum { lazy, assert }) void {
}
}
- // If there are still saved buffers, then this window needs to be kept
- // around until the current transaction completes. This function will be
- // called again in WindowManager.commitTransaction()
+ if (when == .force) {
+ window.surfaces.dropSaved();
+ }
+
if (!window.surfaces.saved.node.enabled) {
window.tree.node.destroy();
window.popup_tree.node.destroy();
@@ -317,11 +319,6 @@ pub fn destroy(window: *Window, when: enum { lazy, assert }) void {
window.node.deinit();
util.gpa.destroy(window);
- } else {
- switch (when) {
- .lazy => {},
- .assert => unreachable,
- }
}
}
diff --git a/river/WindowManager.zig b/river/WindowManager.zig
index 674259d..6f2efb9 100644
--- a/river/WindowManager.zig
+++ b/river/WindowManager.zig
@@ -399,8 +399,15 @@ fn updateRenderingFinish(wm: *WindowManager) void {
{
var it = wm.windows.safeIterator(.forward);
while (it.next()) |window| {
- window.surfaces.dropSaved();
- if (window.destroying) window.destroy(.assert);
+ // If a window is unmapped during a rendering update, we need to retain the saved
+ // buffers until after the next windowing update (in which the closed event will
+ // be sent) for frame perfection.
+ if (window.windowing_scheduled.state != .closing) {
+ window.surfaces.dropSaved();
+ }
+ if (window.destroying) {
+ window.destroy(.force);
+ }
}
}
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 411b530..b781c19 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -81,7 +81,7 @@ pub fn create(wlr_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
.window = undefined,
.wlr_toplevel = wlr_toplevel,
} });
- errdefer window.destroy(.assert);
+ errdefer window.destroy(.force);
const toplevel = &window.impl.toplevel;