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

commit1ab9423e1f887d06da25d543abd6639ae7e4186f
parentbb0e28812c
authorIsaac Freund <[email protected]>
date2024-02-20 23:01
XdgToplevel: handle timed out state in configure()

If a new transaction is started that calls configure() on an xdg
toplevel with a timed_out/timed_out_acked configure_state we currently
leave the configure_state untouched if no new configure is needed.

This can cause an assertion failure in View.commitTransaction() if the
xdg toplevel still hasn't acked/committed by the time the new
transaction completes.

To fix this, update the configure_state as necessary.

 river/XdgToplevel.zig | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index dbb3340..653b01c 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -118,6 +118,11 @@ pub fn configure(self: *Self) bool {
         .inflight, .acked, .committed => unreachable,
     }
 
+    defer switch (self.configure_state) {
+        .idle, .inflight, .acked => {},
+        .timed_out, .timed_out_acked, .committed => unreachable,
+    };
+
     const inflight = &self.view.inflight;
     const current = &self.view.current;
 
@@ -135,7 +140,20 @@ pub fn configure(self: *Self) bool {
         inflight.ssd == current.ssd and
         inflight.resizing == current.resizing)
     {
-        return false;
+        // If no new configure is required, continue to track a timed out configure
+        // from the previous transaction if any.
+        switch (self.configure_state) {
+            .idle => return false,
+            .timed_out => |serial| {
+                self.configure_state = .{ .inflight = serial };
+                return true;
+            },
+            .timed_out_acked => {
+                self.configure_state = .acked;
+                return true;
+            },
+            .inflight, .acked, .committed => unreachable,
+        }
     }
 
     _ = self.xdg_toplevel.setActivated(inflight.focus != 0);
@@ -160,8 +178,11 @@ pub fn configure(self: *Self) bool {
     const configure_serial = self.xdg_toplevel.setSize(inflight.box.width, inflight.box.height);
 
     // Only track configures with the transaction system if they affect the dimensions of the view.
+    // If the configure state is not idle this means we are currently tracking a timed out
+    // configure from a previous transaction and should instead track the newly sent configure.
     if (inflight.box.width == current.box.width and
-        inflight.box.height == current.box.height)
+        inflight.box.height == current.box.height and
+        self.configure_state == .idle)
     {
         return false;
     }