Preserve stacking order constraints when closing a window

When closing a window, we may need to change parent-child relationship
between windows, but we need to preserve stacking order constraints so
dialogs are placed above their parents when they're closed.
This commit is contained in:
Vlad Zahorodnii 2023-03-23 10:19:12 +02:00
parent 2510bf0439
commit 5454cc47c3
3 changed files with 31 additions and 22 deletions

View file

@ -221,16 +221,18 @@ void WaylandWindow::doSetActive()
void WaylandWindow::cleanGrouping() void WaylandWindow::cleanGrouping()
{ {
// We want to break parent-child relationships, but preserve stacking
// order constraints at the same time for window closing animations.
if (transientFor()) { if (transientFor()) {
transientFor()->removeTransient(this); transientFor()->removeTransientFromList(this);
setTransientFor(nullptr);
} }
for (auto it = transients().constBegin(); it != transients().constEnd();) {
if ((*it)->transientFor() == this) { const auto children = transients();
removeTransient(*it); for (Window *transient : children) {
it = transients().constBegin(); // restart, just in case something more has changed with the list removeTransientFromList(transient);
} else { transient->setTransientFor(nullptr);
++it;
}
} }
} }

View file

@ -925,6 +925,7 @@ public:
virtual QRectF transientPlacement(const QRectF &bounds) const; virtual QRectF transientPlacement(const QRectF &bounds) const;
const Window *transientFor() const; const Window *transientFor() const;
Window *transientFor(); Window *transientFor();
void setTransientFor(Window *transientFor);
/** /**
* @returns @c true if transient is the transient_for window for this window, * @returns @c true if transient is the transient_for window for this window,
* or recursively the transient_for window * or recursively the transient_for window
@ -934,6 +935,7 @@ public:
const QList<Window *> &transients() const; // Is not indirect const QList<Window *> &transients() const; // Is not indirect
virtual void addTransient(Window *transient); virtual void addTransient(Window *transient);
virtual void removeTransient(Window *transient); virtual void removeTransient(Window *transient);
void removeTransientFromList(Window *cl);
virtual QList<Window *> mainWindows() const; // Call once before loop , is not indirect virtual QList<Window *> mainWindows() const; // Call once before loop , is not indirect
QList<Window *> allMainWindows() const; // Call once before loop , is indirect QList<Window *> allMainWindows() const; // Call once before loop , is indirect
/** /**
@ -1623,11 +1625,6 @@ protected:
void setupWindowManagementInterface(); void setupWindowManagementInterface();
void updateColorScheme(); void updateColorScheme();
void ensurePalette(); void ensurePalette();
void setTransientFor(Window *transientFor);
/**
* Just removes the @p cl from the transients without any further checks.
*/
void removeTransientFromList(Window *cl);
virtual Layer belongsToLayer() const; virtual Layer belongsToLayer() const;
virtual bool belongsToDesktop() const; virtual bool belongsToDesktop() const;

View file

@ -3076,19 +3076,29 @@ void X11Window::removeFromMainClients()
// related lists. // related lists.
void X11Window::cleanGrouping() void X11Window::cleanGrouping()
{ {
removeFromMainClients(); // We want to break parent-child relationships, but preserve stacking
group()->removeMember(this); // order constraints at the same time for window closing animations.
in_group = nullptr;
for (auto it = transients().constBegin(); it != transients().constEnd();) { if (transientFor()) {
if ((*it)->transientFor() == this) { transientFor()->removeTransientFromList(this);
removeTransient(*it); setTransientFor(nullptr);
it = transients().constBegin(); // restart, just in case something more has changed with the list }
} else {
++it; if (groupTransient()) {
const auto members = group()->members();
for (Window *member : members) {
member->removeTransientFromList(this);
} }
} }
const auto children = transients();
for (Window *transient : children) {
removeTransientFromList(transient);
transient->setTransientFor(nullptr);
}
group()->removeMember(this);
in_group = nullptr;
m_transientForId = XCB_WINDOW_NONE; m_transientForId = XCB_WINDOW_NONE;
} }