diff --git a/autotests/client/test_plasmashell.cpp b/autotests/client/test_plasmashell.cpp --- a/autotests/client/test_plasmashell.cpp +++ b/autotests/client/test_plasmashell.cpp @@ -45,6 +45,7 @@ void testRole_data(); void testRole(); + void testDisconnect(); private: Display *m_display = nullptr; @@ -190,5 +191,43 @@ QTEST(sps->role(), "serverRole"); } +void TestPlasmaShell::testDisconnect() +{ + // this test verifies that a disconnect cleans up + QSignalSpy plasmaSurfaceCreatedSpy(m_plasmaShellInterface, &PlasmaShellInterface::surfaceCreated); + QVERIFY(plasmaSurfaceCreatedSpy.isValid()); + // create the surface + QScopedPointer s(m_compositor->createSurface()); + QScopedPointer ps(m_plasmaShell->createSurface(s.data())); + + // and get them on the server + QVERIFY(plasmaSurfaceCreatedSpy.wait()); + QCOMPARE(plasmaSurfaceCreatedSpy.count(), 1); + auto sps = plasmaSurfaceCreatedSpy.first().first().value(); + QVERIFY(sps); + + // disconnect + QSignalSpy clientDisconnectedSpy(sps->client(), &ClientConnection::disconnected); + QVERIFY(clientDisconnectedSpy.isValid()); + QSignalSpy surfaceDestroyedSpy(sps, &QObject::destroyed); + QVERIFY(surfaceDestroyedSpy.isValid()); + if (m_connection) { + m_connection->deleteLater(); + m_connection = nullptr; + } + QVERIFY(clientDisconnectedSpy.wait()); + QCOMPARE(clientDisconnectedSpy.count(), 1); + QCOMPARE(surfaceDestroyedSpy.count(), 0); + QVERIFY(surfaceDestroyedSpy.wait()); + QCOMPARE(surfaceDestroyedSpy.count(), 1); + + s->destroy(); + ps->destroy(); + m_plasmaShell->destroy(); + m_compositor->destroy(); + m_registry->destroy(); + m_queue->destroy(); +} + QTEST_GUILESS_MAIN(TestPlasmaShell) #include "test_plasmashell.moc" diff --git a/autotests/client/test_wayland_region.cpp b/autotests/client/test_wayland_region.cpp --- a/autotests/client/test_wayland_region.cpp +++ b/autotests/client/test_wayland_region.cpp @@ -44,6 +44,7 @@ void testAdd(); void testRemove(); void testDestroy(); + void testDisconnect(); private: KWayland::Server::Display *m_display; @@ -281,5 +282,38 @@ region->destroy(); } +void TestRegion::testDisconnect() +{ + // this test verifies that the server side correctly tears down the resources when the client disconnects + using namespace KWayland::Client; + using namespace KWayland::Server; + QScopedPointer r(m_compositor->createRegion()); + QVERIFY(!r.isNull()); + QVERIFY(r->isValid()); + QSignalSpy regionCreatedSpy(m_compositorInterface, &CompositorInterface::regionCreated); + QVERIFY(regionCreatedSpy.isValid()); + QVERIFY(regionCreatedSpy.wait()); + auto serverRegion = regionCreatedSpy.first().first().value(); + + // destroy client + QSignalSpy clientDisconnectedSpy(serverRegion->client(), &ClientConnection::disconnected); + QVERIFY(clientDisconnectedSpy.isValid()); + QSignalSpy regionDestroyedSpy(serverRegion, &QObject::destroyed); + QVERIFY(regionDestroyedSpy.isValid()); + if (m_connection) { + m_connection->deleteLater(); + m_connection = nullptr; + } + QVERIFY(clientDisconnectedSpy.wait()); + QCOMPARE(clientDisconnectedSpy.count(), 1); + QCOMPARE(regionDestroyedSpy.count(), 0); + QVERIFY(regionDestroyedSpy.wait()); + QCOMPARE(regionDestroyedSpy.count(), 1); + + r->destroy(); + m_compositor->destroy(); + m_queue->destroy(); +} + QTEST_GUILESS_MAIN(TestRegion) #include "test_wayland_region.moc" diff --git a/autotests/client/test_wayland_seat.cpp b/autotests/client/test_wayland_seat.cpp --- a/autotests/client/test_wayland_seat.cpp +++ b/autotests/client/test_wayland_seat.cpp @@ -75,6 +75,7 @@ void testDestroy(); void testSelection(); void testTouch(); + void testDisconnect(); // TODO: add test for keymap private: @@ -1535,5 +1536,77 @@ QCOMPARE(touch->sequence().first()->position(), QPointF(0, 0)); } +void TestWaylandSeat::testDisconnect() +{ + // this test verifies that disconnecting the client cleans up correctly + using namespace KWayland::Client; + using namespace KWayland::Server; + QSignalSpy keyboardCreatedSpy(m_seatInterface, &SeatInterface::keyboardCreated); + QVERIFY(keyboardCreatedSpy.isValid()); + QSignalSpy pointerCreatedSpy(m_seatInterface, &SeatInterface::pointerCreated); + QVERIFY(pointerCreatedSpy.isValid()); + QSignalSpy touchCreatedSpy(m_seatInterface, &SeatInterface::touchCreated); + QVERIFY(touchCreatedSpy.isValid()); + + // create the things we need + m_seatInterface->setHasKeyboard(true); + m_seatInterface->setHasPointer(true); + m_seatInterface->setHasTouch(true); + QSignalSpy touchSpy(m_seat, &Seat::hasTouchChanged); + QVERIFY(touchSpy.isValid()); + QVERIFY(touchSpy.wait()); + + QScopedPointer keyboard(m_seat->createKeyboard()); + QVERIFY(!keyboard.isNull()); + QVERIFY(keyboardCreatedSpy.wait()); + auto serverKeyboard = keyboardCreatedSpy.first().first().value(); + QVERIFY(serverKeyboard); + + QScopedPointer pointer(m_seat->createPointer()); + QVERIFY(!pointer.isNull()); + QVERIFY(pointerCreatedSpy.wait()); + auto serverPointer = pointerCreatedSpy.first().first().value(); + QVERIFY(serverPointer); + + QScopedPointer touch(m_seat->createTouch()); + QVERIFY(!touch.isNull()); + QVERIFY(touchCreatedSpy.wait()); + auto serverTouch = touchCreatedSpy.first().first().value(); + QVERIFY(serverTouch); + + // setup destroys + QSignalSpy keyboardDestroyedSpy(serverKeyboard, &QObject::destroyed); + QVERIFY(keyboardDestroyedSpy.isValid()); + QSignalSpy pointerDestroyedSpy(serverPointer, &QObject::destroyed); + QVERIFY(pointerDestroyedSpy.isValid()); + QSignalSpy touchDestroyedSpy(serverTouch, &QObject::destroyed); + QVERIFY(touchDestroyedSpy.isValid()); + QSignalSpy clientDisconnectedSpy(serverKeyboard->client(), &ClientConnection::disconnected); + QVERIFY(clientDisconnectedSpy.isValid()); + + if (m_connection) { + m_connection->deleteLater(); + m_connection = nullptr; + } + QVERIFY(clientDisconnectedSpy.wait()); + QCOMPARE(clientDisconnectedSpy.count(), 1); + QCOMPARE(keyboardDestroyedSpy.count(), 0); + QCOMPARE(pointerDestroyedSpy.count(), 0); + QCOMPARE(touchDestroyedSpy.count(), 0); + QVERIFY(keyboardDestroyedSpy.wait()); + QCOMPARE(keyboardDestroyedSpy.count(), 1); + QCOMPARE(pointerDestroyedSpy.count(), 1); + QCOMPARE(touchDestroyedSpy.count(), 1); + + keyboard->destroy(); + pointer->destroy(); + touch->destroy(); + m_compositor->destroy(); + m_seat->destroy(); + m_shm->destroy(); + m_subCompositor->destroy(); + m_queue->destroy(); +} + QTEST_GUILESS_MAIN(TestWaylandSeat) #include "test_wayland_seat.moc" diff --git a/autotests/client/test_wayland_shell.cpp b/autotests/client/test_wayland_shell.cpp --- a/autotests/client/test_wayland_shell.cpp +++ b/autotests/client/test_wayland_shell.cpp @@ -63,6 +63,7 @@ void testMove(); void testResize_data(); void testResize(); + void testDisconnect(); private: KWayland::Server::Display *m_display; @@ -701,5 +702,44 @@ QTEST(resizeRequestedSpy.first().at(2).value(), "expectedEdge"); } +void TestWaylandShell::testDisconnect() +{ + // this test verifies that the server side correctly tears down the resources when the client disconnects + using namespace KWayland::Client; + using namespace KWayland::Server; + QScopedPointer s(m_compositor->createSurface()); + QVERIFY(!s.isNull()); + QVERIFY(s->isValid()); + QScopedPointer surface(m_shell->createSurface(s.data(), m_shell)); + QSignalSpy serverSurfaceSpy(m_shellInterface, &ShellInterface::surfaceCreated); + QVERIFY(serverSurfaceSpy.isValid()); + QVERIFY(serverSurfaceSpy.wait()); + ShellSurfaceInterface *serverSurface = serverSurfaceSpy.first().first().value(); + QVERIFY(serverSurface); + + // destroy client + QSignalSpy clientDisconnectedSpy(serverSurface->client(), &ClientConnection::disconnected); + QVERIFY(clientDisconnectedSpy.isValid()); + QSignalSpy shellSurfaceDestroyedSpy(serverSurface, &QObject::destroyed); + QVERIFY(shellSurfaceDestroyedSpy.isValid()); + if (m_connection) { + m_connection->deleteLater(); + m_connection = nullptr; + } + QVERIFY(clientDisconnectedSpy.wait()); + QCOMPARE(clientDisconnectedSpy.count(), 1); + QCOMPARE(shellSurfaceDestroyedSpy.count(), 0); + QVERIFY(shellSurfaceDestroyedSpy.wait()); + QCOMPARE(shellSurfaceDestroyedSpy.count(), 1); + + s->destroy(); + surface->destroy(); + m_shell->destroy(); + m_compositor->destroy(); + m_pointer->destroy(); + m_seat->destroy(); + m_queue->destroy(); +} + QTEST_GUILESS_MAIN(TestWaylandShell) #include "test_wayland_shell.moc" 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 @@ -58,6 +58,7 @@ void testDamageTracking(); void testSurfaceAt(); void testDestroyAttachedBuffer(); + void testDisconnect(); private: KWayland::Server::Display *m_display; @@ -873,5 +874,40 @@ QVERIFY(!serverSurface->buffer()); } +void TestWaylandSurface::testDisconnect() +{ + // this test verifies that the server side correctly tears down the resources when the client disconnects + using namespace KWayland::Client; + using namespace KWayland::Server; + QScopedPointer s(m_compositor->createSurface()); + QVERIFY(!s.isNull()); + QVERIFY(s->isValid()); + QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); + QVERIFY(surfaceCreatedSpy.isValid()); + QVERIFY(surfaceCreatedSpy.wait()); + auto serverSurface = surfaceCreatedSpy.first().first().value(); + QVERIFY(serverSurface); + + // destroy client + QSignalSpy clientDisconnectedSpy(serverSurface->client(), &ClientConnection::disconnected); + QVERIFY(clientDisconnectedSpy.isValid()); + QSignalSpy surfaceDestroyedSpy(serverSurface, &QObject::destroyed); + QVERIFY(surfaceDestroyedSpy.isValid()); + if (m_connection) { + m_connection->deleteLater(); + m_connection = nullptr; + } + QVERIFY(clientDisconnectedSpy.wait()); + QCOMPARE(clientDisconnectedSpy.count(), 1); + QCOMPARE(surfaceDestroyedSpy.count(), 0); + QVERIFY(surfaceDestroyedSpy.wait()); + QCOMPARE(surfaceDestroyedSpy.count(), 1); + + s->destroy(); + m_shm->destroy(); + m_compositor->destroy(); + m_queue->destroy(); +} + QTEST_GUILESS_MAIN(TestWaylandSurface) #include "test_wayland_surface.moc" diff --git a/autotests/server/test_qt_surface_extension.cpp b/autotests/server/test_qt_surface_extension.cpp --- a/autotests/server/test_qt_surface_extension.cpp +++ b/autotests/server/test_qt_surface_extension.cpp @@ -84,13 +84,19 @@ QCOMPARE(surfaceExtensionSpy.count(), 1); auto *extension = surfaceExtensionSpy.first().first().value(); QVERIFY(extension); + QSignalSpy surfaceExtensionDestroyedSpy(extension, &QObject::destroyed); + QVERIFY(surfaceExtensionSpy.isValid()); QSignalSpy processStateChangedSpy(&process, &QProcess::stateChanged); QVERIFY(processStateChangedSpy.isValid()); extension->close(); extension->client()->flush(); QVERIFY(processStateChangedSpy.wait()); QCOMPARE(process.exitStatus(), QProcess::NormalExit); + if (surfaceExtensionDestroyedSpy.count() == 0) { + QVERIFY(surfaceExtensionDestroyedSpy.wait()); + } + QCOMPARE(surfaceExtensionSpy.count(), 1); } QTEST_GUILESS_MAIN(TestQtSurfaceExtension) diff --git a/src/server/compositor_interface.cpp b/src/server/compositor_interface.cpp --- a/src/server/compositor_interface.cpp +++ b/src/server/compositor_interface.cpp @@ -105,14 +105,6 @@ delete surface; return; } - QObject::connect(surface->client(), &ClientConnection::disconnected, surface, - [surface] { - if (surface->resource()) { - wl_resource_destroy(surface->resource()); - delete surface; - } - } - ); emit q->surfaceCreated(surface); } @@ -130,14 +122,6 @@ delete region; return; } - QObject::connect(region->client(), &ClientConnection::disconnected, region, - [region] { - if (region->resource()) { - wl_resource_destroy(region->resource()); - delete region; - } - } - ); emit q->regionCreated(region); } diff --git a/src/server/dataoffer_interface.cpp b/src/server/dataoffer_interface.cpp --- a/src/server/dataoffer_interface.cpp +++ b/src/server/dataoffer_interface.cpp @@ -98,7 +98,7 @@ } DataOfferInterface::DataOfferInterface(DataSourceInterface *source, DataDeviceInterface *parentInterface, wl_resource *parentResource) - : Resource(new Private(source, parentInterface, this, parentResource), parentInterface) + : Resource(new Private(source, parentInterface, this, parentResource)) { connect(source, &DataSourceInterface::mimeTypeOffered, this, [this](const QString &mimeType) { diff --git a/src/server/dpms_interface.cpp b/src/server/dpms_interface.cpp --- a/src/server/dpms_interface.cpp +++ b/src/server/dpms_interface.cpp @@ -120,7 +120,7 @@ } DpmsInterface::DpmsInterface(OutputInterface *output, wl_resource *parentResource, DpmsManagerInterface *manager) - : Resource(new Private(this, manager, parentResource, output), manager) + : Resource(new Private(this, manager, parentResource, output)) { connect(output, &OutputInterface::dpmsSupportedChanged, this, [this] { diff --git a/src/server/keyboard_interface.cpp b/src/server/keyboard_interface.cpp --- a/src/server/keyboard_interface.cpp +++ b/src/server/keyboard_interface.cpp @@ -81,7 +81,7 @@ #endif KeyboardInterface::KeyboardInterface(SeatInterface *parent, wl_resource *parentResource) - : Resource(new Private(parent, parentResource, this), parent) + : Resource(new Private(parent, parentResource, this)) { } diff --git a/src/server/plasmashell_interface.cpp b/src/server/plasmashell_interface.cpp --- a/src/server/plasmashell_interface.cpp +++ b/src/server/plasmashell_interface.cpp @@ -164,7 +164,7 @@ #endif PlasmaShellSurfaceInterface::PlasmaShellSurfaceInterface(PlasmaShellInterface *shell, SurfaceInterface *parent, wl_resource *parentResource) - : Resource(new Private(this, shell, parent, parentResource), parent) + : Resource(new Private(this, shell, parent, parentResource)) { } diff --git a/src/server/pointer_interface.cpp b/src/server/pointer_interface.cpp --- a/src/server/pointer_interface.cpp +++ b/src/server/pointer_interface.cpp @@ -105,7 +105,7 @@ #endif PointerInterface::PointerInterface(SeatInterface *parent, wl_resource *parentResource) - : Resource(new Private(parent, parentResource, this), parent) + : Resource(new Private(parent, parentResource, this)) { // TODO: handle touch connect(parent, &SeatInterface::pointerPosChanged, this, [this] { diff --git a/src/server/qtsurfaceextension_interface.cpp b/src/server/qtsurfaceextension_interface.cpp --- a/src/server/qtsurfaceextension_interface.cpp +++ b/src/server/qtsurfaceextension_interface.cpp @@ -187,7 +187,7 @@ } QtExtendedSurfaceInterface::QtExtendedSurfaceInterface(QtSurfaceExtensionInterface *shell, SurfaceInterface *parent, wl_resource *parentResource) - : Resource(new Private(this, shell, parent, parentResource), parent) + : Resource(new Private(this, shell, parent, parentResource)) { } diff --git a/src/server/region_interface.cpp b/src/server/region_interface.cpp --- a/src/server/region_interface.cpp +++ b/src/server/region_interface.cpp @@ -100,7 +100,7 @@ } RegionInterface::RegionInterface(CompositorInterface *parent, wl_resource *parentResource) - : Resource(new Private(parent, this, parentResource), parent) + : Resource(new Private(parent, this, parentResource)) { } diff --git a/src/server/shell_interface.cpp b/src/server/shell_interface.cpp --- a/src/server/shell_interface.cpp +++ b/src/server/shell_interface.cpp @@ -189,7 +189,7 @@ #endif ShellSurfaceInterface::ShellSurfaceInterface(ShellInterface *shell, SurfaceInterface *parent, wl_resource *parentResource) - : Resource(new Private(this, shell, parent, parentResource), parent) + : Resource(new Private(this, shell, parent, parentResource)) { Q_D(); connect(d->pingTimer.data(), &QTimer::timeout, this, &ShellSurfaceInterface::pingTimeout); diff --git a/src/server/touch_interface.cpp b/src/server/touch_interface.cpp --- a/src/server/touch_interface.cpp +++ b/src/server/touch_interface.cpp @@ -70,7 +70,7 @@ } TouchInterface::TouchInterface(SeatInterface *parent, wl_resource *parentResource) - : Resource(new Private(parent, parentResource, this), parent) + : Resource(new Private(parent, parentResource, this)) { }