diff --git a/autotests/client/test_wayland_registry.cpp b/autotests/client/test_wayland_registry.cpp --- a/autotests/client/test_wayland_registry.cpp +++ b/autotests/client/test_wayland_registry.cpp @@ -20,6 +20,7 @@ // Qt #include // KWin +#include "../../src/client/blur.h" #include "../../src/client/compositor.h" #include "../../src/client/connection_thread.h" #include "../../src/client/dpms.h" @@ -32,6 +33,7 @@ #include "../../src/client/relativepointer.h" #include "../../src/client/server_decoration.h" #include "../../src/client/shell.h" +#include "../../src/client/surface.h" #include "../../src/client/subcompositor.h" #include "../../src/client/xdgshell.h" #include "../../src/server/compositor_interface.h" @@ -95,6 +97,7 @@ void testGlobalSync(); void testGlobalSyncThreaded(); void testRemoval(); + void testOutOfSyncRemoval(); void testDestroy(); void testAnnounceMultiple(); void testAnnounceMultipleOutputDevices(); @@ -116,6 +119,7 @@ KWayland::Server::RelativePointerManagerInterface *m_relativePointerV1; KWayland::Server::PointerGesturesInterface *m_pointerGesturesV1; KWayland::Server::PointerConstraintsInterface *m_pointerConstraintsV1; + KWayland::Server::BlurManagerInterface *m_blur; }; static const QString s_socketName = QStringLiteral("kwin-test-wayland-registry-0"); @@ -138,6 +142,7 @@ , m_relativePointerV1(nullptr) , m_pointerGesturesV1(nullptr) , m_pointerConstraintsV1(nullptr) + , m_blur(nullptr) { } @@ -164,7 +169,8 @@ m_outputDevice = m_display->createOutputDevice(); m_outputDevice->create(); QVERIFY(m_outputManagement->isValid()); - m_display->createBlurManager(this)->create(); + m_blur = m_display->createBlurManager(this); + m_blur->create(); m_display->createContrastManager(this)->create(); m_display->createSlideManager(this)->create(); m_display->createDpmsManager()->create(); @@ -380,6 +386,8 @@ QVERIFY(outputManagementAnnouncedSpy.isValid()); QSignalSpy serverSideDecorationManagerAnnouncedSpy(®istry, &Registry::serverSideDecorationManagerAnnounced); QVERIFY(serverSideDecorationManagerAnnouncedSpy.isValid()); + QSignalSpy blurAnnouncedSpy(®istry, &Registry::blurAnnounced); + QVERIFY(blurAnnouncedSpy.isValid()); QVERIFY(!registry.isValid()); registry.create(connection.display()); @@ -394,6 +402,8 @@ QVERIFY(!subCompositorAnnouncedSpy.isEmpty()); QVERIFY(!outputManagementAnnouncedSpy.isEmpty()); QVERIFY(!serverSideDecorationManagerAnnouncedSpy.isEmpty()); + QVERIFY(!blurAnnouncedSpy.isEmpty()); + QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::Compositor)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::Output)); @@ -405,6 +415,7 @@ QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::FullscreenShell)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::OutputManagement)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::ServerSideDecorationManager)); + QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::Blur)); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::Compositor).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::Output).isEmpty()); @@ -416,6 +427,7 @@ QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::FullscreenShell).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::OutputManagement).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::ServerSideDecorationManager).isEmpty()); + QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::Blur).isEmpty()); QSignalSpy seatRemovedSpy(®istry, SIGNAL(seatRemoved(quint32))); QVERIFY(seatRemovedSpy.isValid()); @@ -426,6 +438,8 @@ Compositor *compositor = registry.createCompositor(registry.interface(Registry::Interface::Compositor).name, registry.interface(Registry::Interface::Compositor).version, ®istry); SubCompositor *subcompositor = registry.createSubCompositor(registry.interface(Registry::Interface::SubCompositor).name, registry.interface(Registry::Interface::SubCompositor).version, ®istry); ServerSideDecorationManager *serverSideDeco = registry.createServerSideDecorationManager(registry.interface(Registry::Interface::ServerSideDecorationManager).name, registry.interface(Registry::Interface::ServerSideDecorationManager).version, ®istry); + BlurManager *blurManager = registry.createBlurManager(registry.interface(Registry::Interface::Blur).name, registry.interface(Registry::Interface::Blur).version, ®istry); + connection.flush(); m_display->dispatchEvents(); QSignalSpy seatObjectRemovedSpy(seat, &Seat::removed); @@ -516,6 +530,18 @@ QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::ServerSideDecorationManager).isEmpty()); QCOMPARE(serverSideDecoManagerObjectRemovedSpy.count(), 1); + QSignalSpy blurRemovedSpy(®istry, &Registry::blurRemoved); + QVERIFY(blurRemovedSpy.isValid()); + QSignalSpy blurObjectRemovedSpy(blurManager, &BlurManager::removed); + QVERIFY(blurObjectRemovedSpy.isValid()); + + delete m_blur; + QVERIFY(blurRemovedSpy.wait()); + QCOMPARE(blurRemovedSpy.first().first(), blurRemovedSpy.first().first()); + QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::Blur)); + QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::Blur).isEmpty()); + QCOMPARE(blurObjectRemovedSpy.count(), 1); + // cannot test shmRemoved as there is no functionality for it // verify everything has been removed only once @@ -525,6 +551,63 @@ QCOMPARE(compositorObjectRemovedSpy.count(), 1); QCOMPARE(subcompositorObjectRemovedSpy.count(), 1); QCOMPARE(serverSideDecoManagerObjectRemovedSpy.count(), 1); + QCOMPARE(blurObjectRemovedSpy.count(), 1); +} + +void TestWaylandRegistry::testOutOfSyncRemoval() +{ + //This tests the following sequence of events + //server announces global + //client binds to that global + + //server removes the global + //(simultaneously) the client legimitely uses the bound resource to the global + //client then gets the server events...it should no-op, not be a protcol error + + using namespace KWayland::Client; + KWayland::Client::ConnectionThread connection; + QSignalSpy connectedSpy(&connection, SIGNAL(connected())); + connection.setSocketName(s_socketName); + connection.initConnection(); + QVERIFY(connectedSpy.wait()); + connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, &connection, + [&connection] { + wl_display_flush(connection.display()); + } + ); + + KWayland::Client::Registry registry; + QVERIFY(!registry.isValid()); + registry.create(connection.display()); + registry.setup(); + QSignalSpy blurAnnouncedSpy(®istry, &Registry::blurAnnounced); + blurAnnouncedSpy.wait(); + BlurManager *blurManager = registry.createBlurManager(registry.interface(Registry::Interface::Blur).name, registry.interface(Registry::Interface::Blur).version, ®istry); + + connection.flush(); + m_display->dispatchEvents(); + + + QScopedPointer compositor(registry.createCompositor(registry.interface(Registry::Interface::Compositor).name, + registry.interface(Registry::Interface::Compositor).version)); + QScopedPointer surface(compositor->createSurface()); + QVERIFY(surface); + + QSignalSpy blurRemovedSpy(®istry, &Registry::blurRemoved); + + delete m_blur; + + //client hasn't processed the event yet + QVERIFY(blurRemovedSpy.count() == 0); + + //use the in the client + blurManager->createBlur(surface.data(), 0); + + //now process events, + QVERIFY(blurRemovedSpy.wait()); + QVERIFY(blurRemovedSpy.count() == 1); + + } void TestWaylandRegistry::testDestroy() diff --git a/src/server/blur_interface.cpp b/src/server/blur_interface.cpp --- a/src/server/blur_interface.cpp +++ b/src/server/blur_interface.cpp @@ -46,9 +46,12 @@ static void unsetCallback(wl_client *client, wl_resource *resource, wl_resource *surface); static void unbind(wl_resource *resource); static Private *cast(wl_resource *r) { - return reinterpret_cast(wl_resource_get_user_data(r)); + auto blurManager = reinterpret_cast*>(wl_resource_get_user_data(r))->data(); + if (blurManager) { + return static_cast(blurManager->d.data()); + } + return nullptr; } - BlurManagerInterface *q; static const struct org_kde_kwin_blur_manager_interface s_interface; static const quint32 s_version; @@ -77,19 +80,22 @@ wl_client_post_no_memory(client); return; } - wl_resource_set_implementation(resource, &s_interface, this, unbind); - // TODO: should we track? + auto ref = new QPointer(q);//deleted in unbind + wl_resource_set_implementation(resource, &s_interface, ref, unbind); } -void BlurManagerInterface::Private::unbind(wl_resource *resource) +void BlurManagerInterface::Private::unbind(wl_resource *r) { - Q_UNUSED(resource) - // TODO: implement? + delete reinterpret_cast*>(wl_resource_get_user_data(r)); } void BlurManagerInterface::Private::createCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface) { - cast(resource)->createBlur(client, resource, id, surface); + auto m = cast(resource); + if (!m) { + return;// will happen if global is deleted + } + m->createBlur(client, resource, id, surface); } void BlurManagerInterface::Private::createBlur(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface)