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.
This commit is contained in:
Isaac Freund 2024-03-13 12:28:08 +01:00
parent 46dbbe9799
commit b0dc5f7294
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
2 changed files with 24 additions and 20 deletions

View File

@ -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);

View File

@ -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,
}