From 242e2806ca0e3295f9fa46833a6e8142503b3122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Thu, 1 Oct 2015 14:12:46 +0200 Subject: [PATCH] [wayland] Properly support add/remove transient on ShellClient Whenever we set a transient we must register it with the parent and remove it again. Also if a parent gets destroyed we must inform the transients. This fixes a crash in Deleted::copyToDeleted when connecting the main clients. The crash condition was hit if the parent got destroyed before the transient. Reviewed-By: Marco Martin --- abstract_client.cpp | 3 +++ shell_client.cpp | 24 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/abstract_client.cpp b/abstract_client.cpp index 0fc0f088d7..0a35021589 100644 --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -972,6 +972,9 @@ void AbstractClient::addTransient(AbstractClient *cl) void AbstractClient::removeTransient(AbstractClient *cl) { m_transients.removeAll(cl); + if (cl->transientFor() == this) { + cl->setTransientFor(nullptr); + } } void AbstractClient::removeTransientFromList(AbstractClient *cl) diff --git a/shell_client.cpp b/shell_client.cpp index bfc2122829..ded4c0c057 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -113,6 +113,19 @@ void ShellClient::destroyClient() m_closing = true; Deleted *del = Deleted::create(this); emit windowClosed(this, del); + + StackingUpdatesBlocker blocker(workspace()); + if (transientFor()) { + transientFor()->removeTransient(this); + } + for (auto it = transients().constBegin(); it != transients().constEnd();) { + if ((*it)->transientFor() == this) { + removeTransient(*it); + it = transients().constBegin(); // restart, just in case something more has changed with the list + } else { + ++it; + } + } waylandServer()->removeClient(this); del->unrefWindow(); @@ -722,7 +735,16 @@ bool ShellClient::isTransient() const void ShellClient::setTransient() { const auto s = m_shellSurface->transientFor(); - setTransientFor(waylandServer()->findClient(s.data())); + auto t = waylandServer()->findClient(s.data()); + if (t != transientFor()) { + // remove from main client + if (transientFor()) + transientFor()->removeTransient(this); + setTransientFor(t); + if (t) { + t->addTransient(this); + } + } } bool ShellClient::hasTransientPlacementHint() const