diff --git a/autotests/client/test_wayland_blur.cpp b/autotests/client/test_wayland_blur.cpp index b2010a1..f6cd202 100644 --- a/autotests/client/test_wayland_blur.cpp +++ b/autotests/client/test_wayland_blur.cpp @@ -1,238 +1,201 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ // Qt #include // KWin #include "../../src/client/compositor.h" #include "../../src/client/connection_thread.h" #include "../../src/client/event_queue.h" #include "../../src/client/region.h" #include "../../src/client/registry.h" #include "../../src/client/surface.h" #include "../../src/client/blur.h" #include "../../src/server/display.h" #include "../../src/server/compositor_interface.h" #include "../../src/server/region_interface.h" #include "../../src/server/blur_interface.h" using namespace KWayland::Client; class TestBlur : public QObject { Q_OBJECT public: explicit TestBlur(QObject *parent = nullptr); private Q_SLOTS: void init(); void cleanup(); void testCreate(); void testSurfaceDestroy(); - void testGlobalDestroy(); private: KWayland::Server::Display *m_display; KWayland::Server::CompositorInterface *m_compositorInterface; KWayland::Server::BlurManagerInterface *m_blurManagerInterface; KWayland::Client::ConnectionThread *m_connection; KWayland::Client::Compositor *m_compositor; KWayland::Client::BlurManager *m_blurManager; KWayland::Client::EventQueue *m_queue; QThread *m_thread; }; static const QString s_socketName = QStringLiteral("kwayland-test-wayland-blur-0"); TestBlur::TestBlur(QObject *parent) : QObject(parent) , m_display(nullptr) , m_compositorInterface(nullptr) , m_connection(nullptr) , m_compositor(nullptr) , m_queue(nullptr) , m_thread(nullptr) { } void TestBlur::init() { using namespace KWayland::Server; delete m_display; m_display = new Display(this); m_display->setSocketName(s_socketName); m_display->start(); QVERIFY(m_display->isRunning()); // setup connection m_connection = new KWayland::Client::ConnectionThread; QSignalSpy connectedSpy(m_connection, &ConnectionThread::connected); QVERIFY(connectedSpy.isValid()); m_connection->setSocketName(s_socketName); m_thread = new QThread(this); m_connection->moveToThread(m_thread); m_thread->start(); m_connection->initConnection(); QVERIFY(connectedSpy.wait()); m_queue = new KWayland::Client::EventQueue(this); QVERIFY(!m_queue->isValid()); m_queue->setup(m_connection); QVERIFY(m_queue->isValid()); Registry registry; QSignalSpy compositorSpy(®istry, &Registry::compositorAnnounced); QVERIFY(compositorSpy.isValid()); QSignalSpy blurSpy(®istry, &Registry::blurAnnounced); QVERIFY(blurSpy.isValid()); QVERIFY(!registry.eventQueue()); registry.setEventQueue(m_queue); QCOMPARE(registry.eventQueue(), m_queue); registry.create(m_connection->display()); QVERIFY(registry.isValid()); registry.setup(); m_compositorInterface = m_display->createCompositor(m_display); m_compositorInterface->create(); QVERIFY(m_compositorInterface->isValid()); QVERIFY(compositorSpy.wait()); m_compositor = registry.createCompositor(compositorSpy.first().first().value(), compositorSpy.first().last().value(), this); m_blurManagerInterface = m_display->createBlurManager(m_display); m_blurManagerInterface->create(); QVERIFY(m_blurManagerInterface->isValid()); QVERIFY(blurSpy.wait()); m_blurManager = registry.createBlurManager(blurSpy.first().first().value(), blurSpy.first().last().value(), this); } void TestBlur::cleanup() { #define CLEANUP(variable) \ if (variable) { \ delete variable; \ variable = nullptr; \ } CLEANUP(m_compositor) CLEANUP(m_blurManager) CLEANUP(m_queue) if (m_connection) { m_connection->deleteLater(); m_connection = nullptr; } if (m_thread) { m_thread->quit(); m_thread->wait(); delete m_thread; m_thread = nullptr; } CLEANUP(m_compositorInterface) CLEANUP(m_blurManagerInterface) CLEANUP(m_display) #undef CLEANUP } void TestBlur::testCreate() { QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); QVERIFY(serverSurfaceCreated.isValid()); QScopedPointer surface(m_compositor->createSurface()); QVERIFY(serverSurfaceCreated.wait()); auto serverSurface = serverSurfaceCreated.first().first().value(); QSignalSpy blurChanged(serverSurface, SIGNAL(blurChanged())); auto blur = m_blurManager->createBlur(surface.data(), surface.data()); blur->setRegion(m_compositor->createRegion(QRegion(0, 0, 10, 20), nullptr)); blur->commit(); surface->commit(KWayland::Client::Surface::CommitFlag::None); QVERIFY(blurChanged.wait()); QCOMPARE(serverSurface->blur()->region(), QRegion(0, 0, 10, 20)); // and destroy QSignalSpy destroyedSpy(serverSurface->blur().data(), &QObject::destroyed); QVERIFY(destroyedSpy.isValid()); delete blur; QVERIFY(destroyedSpy.wait()); } void TestBlur::testSurfaceDestroy() { QSignalSpy serverSurfaceCreated(m_compositorInterface, &KWayland::Server::CompositorInterface::surfaceCreated); QVERIFY(serverSurfaceCreated.isValid()); QScopedPointer surface(m_compositor->createSurface()); QVERIFY(serverSurfaceCreated.wait()); auto serverSurface = serverSurfaceCreated.first().first().value(); QSignalSpy blurChanged(serverSurface, &KWayland::Server::SurfaceInterface::blurChanged); QVERIFY(blurChanged.isValid()); QScopedPointer blur(m_blurManager->createBlur(surface.data())); blur->setRegion(m_compositor->createRegion(QRegion(0, 0, 10, 20), nullptr)); blur->commit(); surface->commit(KWayland::Client::Surface::CommitFlag::None); QVERIFY(blurChanged.wait()); QCOMPARE(serverSurface->blur()->region(), QRegion(0, 0, 10, 20)); // destroy the parent surface QSignalSpy surfaceDestroyedSpy(serverSurface, &QObject::destroyed); QVERIFY(surfaceDestroyedSpy.isValid()); QSignalSpy blurDestroyedSpy(serverSurface->blur().data(), &QObject::destroyed); QVERIFY(blurDestroyedSpy.isValid()); surface.reset(); QVERIFY(surfaceDestroyedSpy.wait()); QVERIFY(blurDestroyedSpy.isEmpty()); // destroy the blur blur.reset(); QVERIFY(blurDestroyedSpy.wait()); } - -void TestBlur::testGlobalDestroy() -{ - Registry registry; - QSignalSpy blurAnnouncedSpy(®istry, &Registry::blurAnnounced); - QSignalSpy blurRemovedSpy(®istry, &Registry::blurRemoved); - - registry.setEventQueue(m_queue); - - registry.create(m_connection->display()); - QVERIFY(registry.isValid()); - registry.setup(); - - QVERIFY(blurAnnouncedSpy.wait()); - - QSignalSpy serverSurfaceCreated(m_compositorInterface, &KWayland::Server::CompositorInterface::surfaceCreated); - QScopedPointer surface(m_compositor->createSurface()); - QVERIFY(serverSurfaceCreated.wait()); - - auto serverSurface = serverSurfaceCreated.first().first().value(); - QSignalSpy blurChanged(serverSurface, &KWayland::Server::SurfaceInterface::blurChanged); - - m_blurManagerInterface->remove(); - - // we've deleted our global, but the clients have some operations in flight as they haven't processed this yet - // when we process them, we should not throw an error and kill the client - - QScopedPointer blur(m_blurManager->createBlur(surface.data())); - blur->setRegion(m_compositor->createRegion(QRegion(0, 0, 10, 20), nullptr)); - blur->commit(); - surface->commit(KWayland::Client::Surface::CommitFlag::None); - - // client finally sees the blur is gone - QVERIFY(blurRemovedSpy.wait()); -} - QTEST_GUILESS_MAIN(TestBlur) #include "test_wayland_blur.moc" diff --git a/src/server/global.cpp b/src/server/global.cpp index 38da712..2bbf79a 100644 --- a/src/server/global.cpp +++ b/src/server/global.cpp @@ -1,95 +1,85 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "global.h" #include "global_p.h" #include "display.h" // wayland #include namespace KWayland { namespace Server { Global::Private::Private(Display *d, const wl_interface *interface, quint32 version) : display(d) , m_interface(interface) , m_version(version) { } Global::Private::~Private() = default; void Global::Private::bind(wl_client *client, void *data, uint32_t version, uint32_t id) { auto d = reinterpret_cast(data); - if (!d) { - return; - } d->bind(client, version, id); } void Global::Private::create() { + Q_ASSERT(!global); global = wl_global_create(*display, m_interface, m_version, this, bind); } Global::Global(Global::Private *d, QObject *parent) : QObject(parent) , d(d) { } Global::~Global() { destroy(); } void Global::create() { d->create(); } -void Global::remove() -{ - if (!d->global) { - return; - } - wl_global_remove(d->global); -} - void Global::destroy() { if (!d->global) { return; } emit aboutToDestroyGlobal(); wl_global_destroy(d->global); d->global = nullptr; } bool Global::isValid() const { return d->global != nullptr; } Global::operator wl_global*() const { return d->global; } Global::operator wl_global*() { return d->global; } Display *Global::display() { return d->display; } } } diff --git a/src/server/global.h b/src/server/global.h index 4a7b039..e156ded 100644 --- a/src/server/global.h +++ b/src/server/global.h @@ -1,114 +1,96 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef WAYLAND_SERVER_GLOBAL_H #define WAYLAND_SERVER_GLOBAL_H #include #include struct wl_global; namespace KWayland { namespace Server { class Display; /** * @brief Base class for all Globals. * * Any class representing a Global should be derived from this base class. * This class provides common functionality for all globals. A global is an * object listed as an interface on the registry on client side. * * Normally a Global gets factored by the Display. For each Global-derived class there * is a dedicated factory method. After creating an instance through the factory method * it is not yet announced on the registry. One needs to call ::create on it. This allows * to setup the Global before it gets announced, ensuring that the client's state is correct * from the start. * * As an example shown for @link OutputInterface @endlink: * @code * Display *display; // The existing display * auto o = display->createOutput(); * o->setManufacturer(QStringLiteral("The KDE Community")); * // setup further data on the OutputInterface * o->create(); // announces OutputInterface * @endcode * * @see Display * **/ class KWAYLANDSERVER_EXPORT Global : public QObject { Q_OBJECT public: virtual ~Global(); /** * Creates the global by creating a native wl_global and by that announcing it * to the clients. **/ void create(); - - /** - * Removes the Global from the registry, but does not delete the underlying wl_global - * - * Removal of a global is racey. A client could be trying to bind at that moment. - * Typically globals are static for the lifespan of the compositor, however there are exceptions - * - * For those cases this call will remove the global from the registry, but keep the wl_global instance alive - * and handling bind requests. - * - * The compositor can then remove the Global wrapper (this object) deleting the wl_global after an arbitrary delay or - * keep it around for re-use for the duration of the compositor. - * - * See https://gitlab.freedesktop.org/wayland/wayland/issues/10 - * - * @since 5.70 - */ - void remove(); /** * Destroys the low level wl_global. Afterwards the Global is no longer shown to clients. **/ void destroy(); /** * @returns whether the Global got created **/ bool isValid() const; /** * @returns the Display the Global got created on. */ Display *display(); /** * Cast operator to the native wl_global this Global represents. **/ operator wl_global*(); /** * Cast operator to the native wl_global this Global represents. **/ 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); QScopedPointer d; }; } } #endif