placement: don't cascade for the sake of windows that are already covered

When checking for overlap with other windows when placing a new window and cascading to avoid complete overlap, ignore those windows that are already covered by other windows further on the top anyway.

The computation of the covered area is not entirely accurate as it uses the bounding rect rather than the combined rects of the windows, but okay enough for our use case imo.

BUG: 466135
This commit is contained in:
Natalie Clarius 2023-03-06 17:58:31 +01:00 committed by Vlad Zahorodnii
parent a2bf59005e
commit 39cea49a8f

View file

@ -602,23 +602,35 @@ void Placement::cascadeIfCovering(Window *window, const QRectF &area)
// cascade until confirmed no total overlap or not enough space to cascade
while (!noOverlap) {
noOverlap = true;
QRectF coveredArea;
// check current position candidate for overlaps with other windows
for (auto l = workspace()->stackingOrder().crbegin(); l != workspace()->stackingOrder().crend(); ++l) {
auto other = *l;
if (isIrrelevant(other, window, desktop)) {
if (isIrrelevant(other, window, desktop) || !other->frameGeometry().intersects(possibleGeo)) {
continue;
}
if (possibleGeo.contains(other->frameGeometry())) {
// placed window would completely overlap the other window: try to cascade it from the topleft of that other window
if (possibleGeo.contains(other->frameGeometry()) && !coveredArea.contains(other->frameGeometry())) {
// placed window would completely overlap another window which is not already
// covered by other windows: try to cascade it from the topleft of that other
// window
noOverlap = false;
possibleGeo.moveTopLeft(other->pos() + offset);
if (possibleGeo.right() > area.right() || possibleGeo.bottom() > area.bottom()) {
// new cascaded geometry would be out of the bounds of the placement area: abort the cascading and keep the window in the original position
// new cascaded geometry would be out of the bounds of the placement area:
// abort the cascading and keep the window in the original position
return;
}
break;
}
// keep track of the area occupied by other windows as we go from top to bottom
// in the stacking order, so we don't need to bother trying to avoid overlap with
// windows which are already covered up by other windows anyway
coveredArea |= other->frameGeometry();
if (coveredArea.contains(area)) {
break;
}
}
}