From 15b8fbe6044a0fd3cb66af78d7e4e44338be5b58 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 21 Nov 2023 11:22:55 +0200 Subject: [PATCH] Preserve relative order of transient siblings If a constraint indicates that window A must be below window B but it's not the case at the moment, the workspace will move window A right after window B. This can invert the relative order of transient siblings, for example let's say that there are three constraints - A <- B (window A must be below window B) - A <- C - A <- D and the unconstrained stacking order looks as follows: [B, C, D, A]. The final constrained stacking order is expected to look as [A, B, C, D], but currently it's [A, D, C, B] instead: - starting stacking order: [B, C, D, A] - apply A <- B constraint: [C, D, A, B] - apply A <- C constraint: [D, A, C, B] - apply A <- D constraint: [A, D, C, B] In order to fix this issue, this patch makes the workspace traverse the constraint graph in the reverse order. In addition to that, it ensures that the relative order of transient siblings in unconstrained stacking order is preserved in the constrained one. BUG: 477262 --- src/layers.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/layers.cpp b/src/layers.cpp index 5417a002af..f317bc0050 100644 --- a/src/layers.cpp +++ b/src/layers.cpp @@ -82,7 +82,6 @@ #include #include -#include namespace KWin { @@ -541,22 +540,28 @@ QList Workspace::constrainedStackingOrder() // Apply the stacking order constraints. First, we enqueue the root constraints, i.e. // the ones that are not affected by other constraints. - QQueue constraints; + QList constraints; constraints.reserve(m_constraints.count()); for (Constraint *constraint : std::as_const(m_constraints)) { if (constraint->parents.isEmpty()) { constraint->enqueued = true; - constraints.enqueue(constraint); + constraints.append(constraint); } else { constraint->enqueued = false; } } + // Preserve the relative order of transient siblings in the unconstrained stacking order. + auto constraintComparator = [&stacking](Constraint *a, Constraint *b) { + return stacking.indexOf(a->above) > stacking.indexOf(b->above); + }; + std::sort(constraints.begin(), constraints.end(), constraintComparator); + // Once we've enqueued all the root constraints, we traverse the constraints tree in - // the breadth-first search fashion. A constraint is applied only if its condition is + // the reverse breadth-first search fashion. A constraint is applied only if its condition is // not met. while (!constraints.isEmpty()) { - Constraint *constraint = constraints.dequeue(); + Constraint *constraint = constraints.takeFirst(); const int belowIndex = stacking.indexOf(constraint->below); const int aboveIndex = stacking.indexOf(constraint->above); @@ -567,10 +572,14 @@ QList Workspace::constrainedStackingOrder() stacking.insert(belowIndex, constraint->above); } - for (Constraint *child : std::as_const(constraint->children)) { + // Preserve the relative order of transient siblings in the unconstrained stacking order. + QList children = constraint->children; + std::sort(children.begin(), children.end(), constraintComparator); + + for (Constraint *child : std::as_const(children)) { if (!child->enqueued) { child->enqueued = true; - constraints.enqueue(child); + constraints.append(child); } } }