[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
icc-effect-5.14.5
Martin Gräßlin 2015-10-01 14:12:46 +02:00
parent 48a6272916
commit 242e2806ca
2 changed files with 26 additions and 1 deletions

View File

@ -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)

View File

@ -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