From b0dc5f7294e31e937709af8fe70d6dae9a27dec0 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Wed, 13 Mar 2024 12:28:08 +0100 Subject: [PATCH] View: improve transaction timeout handling This fixes a possible assertion failure in Cursor.updateState() when trying to start move/resize of a xdg toplevel with the timed_out or timed_out_acked configure_state. This also generally improves the UX of transaction timeouts as all state except for the size change is now applied immediately. --- river/View.zig | 34 ++++++++++++++++++---------------- river/XdgToplevel.zig | 10 ++++++---- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/river/View.zig b/river/View.zig index ed7441a..9f7d4bc 100644 --- a/river/View.zig +++ b/river/View.zig @@ -285,26 +285,28 @@ pub fn commitTransaction(view: *Self) void { view.foreign_toplevel_handle.update(); - // Tag and output changes must be applied immediately even if the configure sequence times out. - // This allows Root.commitTransaction() to rely on the fact that all tag and output changes - // are applied directly by this function. - view.current.tags = view.inflight.tags; - view.current.output = view.inflight.output; - view.dropSavedSurfaceTree(); switch (view.impl) { .xdg_toplevel => |*xdg_toplevel| { switch (xdg_toplevel.configure_state) { - .inflight => |serial| { - xdg_toplevel.configure_state = .{ .timed_out = serial }; - }, - .acked => { - xdg_toplevel.configure_state = .timed_out_acked; + .inflight, .acked => { + switch (xdg_toplevel.configure_state) { + .inflight => |serial| xdg_toplevel.configure_state = .{ .timed_out = serial }, + .acked => xdg_toplevel.configure_state = .timed_out_acked, + else => unreachable, + } + // The width and height cannot be updated until the client has + // committed a new buffer in response to the configure. + const old_width = view.current.box.width; + const old_height = view.current.box.height; + view.current = view.inflight; + view.current.box.width = old_width; + view.current.box.height = old_height; }, .idle, .committed => { xdg_toplevel.configure_state = .idle; - view.updateCurrent(); + view.current = view.inflight; }, .timed_out, .timed_out_acked => unreachable, } @@ -322,15 +324,15 @@ pub fn commitTransaction(view: *Self) void { view.pending.box.width = xwayland_view.xwayland_surface.width; view.pending.box.height = xwayland_view.xwayland_surface.height; - view.updateCurrent(); + view.current = view.inflight; }, .none => {}, } + + view.updateSceneState(); } -pub fn updateCurrent(view: *Self) void { - view.current = view.inflight; - +pub fn updateSceneState(view: *Self) void { const box = &view.current.box; view.tree.node.setPosition(box.x, box.y); view.popup_tree.node.setPosition(box.x, box.y); diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig index 0ae9f5b..6382fb6 100644 --- a/river/XdgToplevel.zig +++ b/river/XdgToplevel.zig @@ -369,7 +369,8 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void { view.inflight.box.height = self.geometry.height; view.pending.box.width = self.geometry.width; view.pending.box.height = self.geometry.height; - view.updateCurrent(); + view.current = view.inflight; + view.updateSceneState(); } }, // If the client has not yet acked our configure, we need to send a @@ -377,7 +378,7 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void { // buffers won't be rendered since we are still rendering our // stashed buffer from when the transaction started. .inflight => view.sendFrameDone(), - inline .acked, .timed_out_acked => |_, tag| { + .acked, .timed_out_acked => { if (view.inflight.resizing) { view.resizeUpdatePosition(self.geometry.width, self.geometry.height); } @@ -387,14 +388,15 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void { view.pending.box.width = self.geometry.width; view.pending.box.height = self.geometry.height; - switch (tag) { + switch (self.configure_state) { .acked => { self.configure_state = .committed; server.root.notifyConfigured(); }, .timed_out_acked => { self.configure_state = .idle; - view.updateCurrent(); + view.current = view.inflight; + view.updateSceneState(); }, else => unreachable, }