Root: fix crash on output disable

If there is a transaction inflight when an output is disabled then we
must call View.commitTransaction() for any views evacuated from the
disabled output to ensure transaction state remains consistent.

Root.commitTransaction() will not call View.commitTransaction()
for these evacuated views as their output is no longer around.
This commit is contained in:
Isaac Freund 2024-02-20 23:06:55 +01:00
parent fa5a1e5da0
commit a04c18819b
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
2 changed files with 14 additions and 2 deletions

View File

@ -280,6 +280,10 @@ pub fn deactivateOutput(root: *Self, output: *Output) void {
view.inflight_wm_stack_link.remove();
view.inflight_wm_stack_link.init();
if (view.inflight_transaction) {
view.commitTransaction();
}
}
}
// Use the first output in the list as fallback. If the last real output
@ -552,11 +556,16 @@ fn sendConfigures(root: *Self) void {
while (output_it.next()) |output| {
var focus_stack_it = output.inflight.focus_stack.iterator(.forward);
while (focus_stack_it.next()) |view| {
assert(!view.inflight_transaction);
view.inflight_transaction = true;
// This can happen if a view is unmapped while a layout demand including it is inflight
// If a view has been unmapped, don't send it a configure.
if (!view.mapped) continue;
if (view.configure()) {
root.inflight_configures += 1;
view.saveSurfaceTree();
view.sendFrameDone();
}
@ -617,8 +626,6 @@ fn commitTransaction(root: *Self) void {
view.tree.node.reparent(root.hidden.tree);
view.popup_tree.node.reparent(root.hidden.tree);
view.commitTransaction();
}
}

View File

@ -131,6 +131,8 @@ popup_tree: *wlr.SceneTree,
constraints: Constraints = .{},
mapped: bool = false,
/// This is true if the View is involved in the currently inflight transaction.
inflight_transaction: bool = false,
/// This indicates that the view should be destroyed when the current
/// transaction completes. See View.destroy()
destroying: bool = false,
@ -273,6 +275,9 @@ pub fn resizeUpdatePosition(view: *Self, width: i32, height: i32) void {
}
pub fn commitTransaction(view: *Self) void {
assert(view.inflight_transaction);
view.inflight_transaction = false;
view.foreign_toplevel_handle.update();
// Tag and output changes must be applied immediately even if the configure sequence times out.