git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit2f6e25fa66f7d784369866827e8f1cbd287a9678
parentf8b5c9abdb
authorIsaac Freund <[email protected]>
date2024-01-03 12:39
XdgToplevel: fix frame perfection on unmap

It looks like the old workaround for this wlroots API wart is no longer
sufficient for wlroots 0.17.

 river/XdgToplevel.zig | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 4d28ffe..7560e25 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -79,10 +79,21 @@ pub fn create(xdg_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
     } });
     errdefer view.destroy();
 
-    _ = try view.surface_tree.createSceneXdgSurface(xdg_toplevel.base);
-
     const self = &view.impl.xdg_toplevel;
 
+    // This listener must be added before the scene xdg surface is created.
+    // Otherwise, the scene surface nodes will already be disabled by the unmap
+    // listeners in the scene xdg surface and scene subsurface tree helpers
+    // before our unmap listener is called.
+    // However, we need the surface tree to be unchanged in our unmap listener
+    // so that we can save the buffers for frame perfection.
+    // TODO(wlroots) This is fragile, it would be good if wlroots gave us a
+    // better alternative here.
+    xdg_toplevel.base.surface.events.unmap.add(&self.unmap);
+    errdefer self.unmap.link.remove();
+
+    _ = try view.surface_tree.createSceneXdgSurface(xdg_toplevel.base);
+
     self.view = view;
 
     xdg_toplevel.base.data = @intFromPtr(self);
@@ -91,7 +102,6 @@ pub fn create(xdg_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
     // Add listeners that are active over the toplevel's entire lifetime
     xdg_toplevel.base.events.destroy.add(&self.destroy);
     xdg_toplevel.base.surface.events.map.add(&self.map);
-    xdg_toplevel.base.surface.events.unmap.add(&self.unmap);
     xdg_toplevel.base.events.new_popup.add(&self.new_popup);
 
     _ = xdg_toplevel.setWmCapabilities(.{ .fullscreen = true });
@@ -253,17 +263,7 @@ fn handleUnmap(listener: *wl.Listener(void)) void {
     self.set_title.link.remove();
     self.set_app_id.link.remove();
 
-    // TODO(wlroots): This enable/disable dance is a workaround for an signal
-    // ordering issue with the scene xdg surface helper's unmap handler that
-    // disables the node. We however need the node enabled for View.unmap()
-    // so that we can save buffers for frame perfection.
-    var it = self.view.surface_tree.children.iterator(.forward);
-    const xdg_surface_tree_node = it.next().?;
-    xdg_surface_tree_node.setEnabled(true);
-
     self.view.unmap();
-
-    xdg_surface_tree_node.setEnabled(false);
 }
 
 fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), wlr_xdg_popup: *wlr.XdgPopup) void {