Add wrapper for wl_global_remove

Summary:
Removes the Global from the registry, but does not delete the underlying
wl_global

Removal of a global is racey in wayland.
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 can remove the global from the registry,
but still 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.

Test Plan:
Unit test
Made blur global outlive BlurEffect - no longer disconnects plasma on config changes

Reviewers: #plasma, apol

Reviewed By: apol

Subscribers: kde-frameworks-devel

Tags: #frameworks

Differential Revision: https://phabricator.kde.org/D28883
This commit is contained in:
David Edmundson 2020-04-24 15:45:39 +01:00
parent ad44b0f08c
commit 78a8b6877c
3 changed files with 66 additions and 1 deletions

View file

@ -31,6 +31,7 @@ private Q_SLOTS:
void testCreate(); void testCreate();
void testSurfaceDestroy(); void testSurfaceDestroy();
void testGlobalDestroy();
private: private:
KWayland::Server::Display *m_display; KWayland::Server::Display *m_display;
@ -197,5 +198,41 @@ void TestBlur::testSurfaceDestroy()
QVERIFY(blurDestroyedSpy.wait()); QVERIFY(blurDestroyedSpy.wait());
} }
void TestBlur::testGlobalDestroy()
{
Registry registry;
QSignalSpy blurAnnouncedSpy(&registry, &Registry::blurAnnounced);
QSignalSpy blurRemovedSpy(&registry, &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<KWayland::Client::Surface> surface(m_compositor->createSurface());
QVERIFY(serverSurfaceCreated.wait());
auto serverSurface = serverSurfaceCreated.first().first().value<KWayland::Server::SurfaceInterface*>();
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<KWayland::Client::Blur> 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) QTEST_GUILESS_MAIN(TestBlur)
#include "test_wayland_blur.moc" #include "test_wayland_blur.moc"

View file

@ -26,12 +26,14 @@ Global::Private::~Private() = default;
void Global::Private::bind(wl_client *client, void *data, uint32_t version, uint32_t id) void Global::Private::bind(wl_client *client, void *data, uint32_t version, uint32_t id)
{ {
auto d = reinterpret_cast<Private*>(data); auto d = reinterpret_cast<Private*>(data);
if (!d) {
return;
}
d->bind(client, version, id); d->bind(client, version, id);
} }
void Global::Private::create() void Global::Private::create()
{ {
Q_ASSERT(!global);
global = wl_global_create(*display, m_interface, m_version, this, bind); global = wl_global_create(*display, m_interface, m_version, this, bind);
} }
@ -51,6 +53,14 @@ void Global::create()
d->create(); d->create();
} }
void Global::remove()
{
if (!d->global) {
return;
}
wl_global_remove(d->global);
}
void Global::destroy() void Global::destroy()
{ {
if (!d->global) { if (!d->global) {

View file

@ -53,6 +53,24 @@ public:
* to the clients. * to the clients.
**/ **/
void create(); 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. * Destroys the low level wl_global. Afterwards the Global is no longer shown to clients.
**/ **/