diff --git a/autotests/client/test_wayland_surface.cpp b/autotests/client/test_wayland_surface.cpp --- a/autotests/client/test_wayland_surface.cpp +++ b/autotests/client/test_wayland_surface.cpp @@ -1077,11 +1077,11 @@ QCOMPARE(enteredSpy.count(), 2); QCOMPARE(leftSpy.count(), 1); - //test the client handles a misbehaving server that removes a display before updating clients - m_display->removeOutput(serverOutput); - QCOMPARE(leftSpy.count(), 1); - QVERIFY(s->outputs().isEmpty()); - + //delete output client is on. + //client should get an exit and be left on no outputs (which is allowed) + serverOutput->deleteLater(); + QVERIFY(leftSpy.wait()); + QCOMPARE(serverSurface->outputs(), QVector()); } QTEST_GUILESS_MAIN(TestWaylandSurface) diff --git a/src/server/global.h b/src/server/global.h --- a/src/server/global.h +++ b/src/server/global.h @@ -90,6 +90,14 @@ **/ operator wl_global*() const; +Q_SIGNALS: + /** + * This signal is emitted when the client is in the process of removing the wl_global. + * At the time the signal is emitted the global is still valid and allows to perform + * cleanup tasks. + */ + void aboutToDestroyGlobal(); + protected: class Private; explicit Global(Private *d, QObject *parent = nullptr); diff --git a/src/server/global.cpp b/src/server/global.cpp --- a/src/server/global.cpp +++ b/src/server/global.cpp @@ -70,6 +70,7 @@ if (!d->global) { return; } + emit aboutToDestroyGlobal(); wl_global_destroy(d->global); d->global = nullptr; } diff --git a/src/server/surface_interface.cpp b/src/server/surface_interface.cpp --- a/src/server/surface_interface.cpp +++ b/src/server/surface_interface.cpp @@ -793,19 +793,25 @@ for (wl_resource *r : resources) { wl_surface_send_leave(d->resource, r); } + disconnect(d->outputDestroyedConnections.take(*it)); } - // TODO: send leave when OutputInterface gets destroyed - QVector addedOutputsOutputs = outputs; for (auto it = d->outputs.constBegin(), end = d->outputs.constEnd(); it != end; ++it) { const auto o = *it; addedOutputsOutputs.removeOne(o); } for (auto it = addedOutputsOutputs.constBegin(), end = addedOutputsOutputs.constEnd(); it != end; ++it) { - const auto resources = (*it)->clientResources(client()); + const auto o = *it; + const auto resources = o->clientResources(client()); for (wl_resource *r : resources) { wl_surface_send_enter(d->resource, r); } + d->outputDestroyedConnections[o] = connect(o, &Global::aboutToDestroyGlobal, this, [this, o] { + Q_D(); + auto outputs = d->outputs; + if (outputs.removeOne(o)) { + setOutputs(outputs); + }}); } // TODO: send enter when the client binds the OutputInterface another time diff --git a/src/server/surface_interface_p.h b/src/server/surface_interface_p.h --- a/src/server/surface_interface_p.h +++ b/src/server/surface_interface_p.h @@ -97,6 +97,7 @@ QPointer lockedPointer; QPointer confinedPointer; + QHash outputDestroyedConnections; private: QMetaObject::Connection constrainsOneShotConnection;