summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/global/qwaylandclientextension.cpp53
-rw-r--r--src/client/global/qwaylandclientextension_p.h9
-rw-r--r--src/client/qwaylanddisplay.cpp3
-rw-r--r--src/client/qwaylanddisplay_p.h4
-rw-r--r--tests/auto/client/CMakeLists.txt1
-rw-r--r--tests/auto/client/clientextension/CMakeLists.txt14
-rw-r--r--tests/auto/client/clientextension/test.xml6
-rw-r--r--tests/auto/client/clientextension/tst_clientextension.cpp152
8 files changed, 221 insertions, 21 deletions
diff --git a/src/client/global/qwaylandclientextension.cpp b/src/client/global/qwaylandclientextension.cpp
index f0bc950c..200dad07 100644
--- a/src/client/global/qwaylandclientextension.cpp
+++ b/src/client/global/qwaylandclientextension.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2017 Erik Larsson.
+** Copyright (C) 2021 David Redondo <qt@david-redondo.de>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
@@ -48,6 +49,8 @@
QT_BEGIN_NAMESPACE
+using RegistryGlobal = QtWaylandClient::QWaylandDisplay::RegistryGlobal;
+
QWaylandClientExtensionPrivate::QWaylandClientExtensionPrivate()
{
// Keep the possibility to use a custom waylandIntegration as a plugin,
@@ -60,23 +63,41 @@ QWaylandClientExtensionPrivate::QWaylandClientExtensionPrivate()
qWarning() << "This application requires a Wayland platform plugin";
}
-void QWaylandClientExtensionPrivate::handleRegistryGlobal(void *data, ::wl_registry *registry, uint32_t id,
- const QString &interface, uint32_t version)
+void QWaylandClientExtensionPrivate::globalAdded(const RegistryGlobal &global)
+{
+ Q_Q(QWaylandClientExtension);
+ if (!active && global.interface == QLatin1String(q->extensionInterface()->name)) {
+ q->bind(global.registry, global.id, global.version);
+ active = true;
+ emit q->activeChanged();
+ }
+}
+
+void QWaylandClientExtensionPrivate::globalRemoved(const RegistryGlobal &global)
{
- QWaylandClientExtension *extension = static_cast<QWaylandClientExtension *>(data);
- if (interface == QLatin1String(extension->extensionInterface()->name) && !extension->d_func()->active) {
- extension->bind(registry, id, version);
- extension->d_func()->active = true;
- emit extension->activeChanged();
+ Q_Q(QWaylandClientExtension);
+ if (active && global.interface == QLatin1String(q->extensionInterface()->name)) {
+ active = false;
+ emit q->activeChanged();
}
}
void QWaylandClientExtension::initialize()
{
Q_D(QWaylandClientExtension);
- if (!d->registered) {
- d->waylandIntegration->display()->addRegistryListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
- d->registered = true;
+ if (d->active) {
+ return;
+ }
+ const QtWaylandClient::QWaylandDisplay *display = d->waylandIntegration->display();
+ const auto globals = display->globals();
+ auto global =
+ std::find_if(globals.cbegin(), globals.cend(), [this](const RegistryGlobal &global) {
+ return global.interface == QLatin1String(extensionInterface()->name);
+ });
+ if (global != globals.cend()) {
+ bind(global->registry, global->id, global->version);
+ d->active = true;
+ emit activeChanged();
}
}
@@ -85,17 +106,17 @@ QWaylandClientExtension::QWaylandClientExtension(const int ver)
{
Q_D(QWaylandClientExtension);
d->version = ver;
-
- // The registry listener uses virtual functions and we don't want it to be called from
- // the constructor.
+ auto display = d->waylandIntegration->display();
+ QObjectPrivate::connect(display, &QtWaylandClient::QWaylandDisplay::globalAdded, d,
+ &QWaylandClientExtensionPrivate::globalAdded);
+ QObjectPrivate::connect(display, &QtWaylandClient::QWaylandDisplay::globalRemoved, d,
+ &QWaylandClientExtensionPrivate::globalRemoved);
+ // This function uses virtual functions and we don't want it to be called from the constructor.
QMetaObject::invokeMethod(this, "initialize", Qt::QueuedConnection);
}
QWaylandClientExtension::~QWaylandClientExtension()
{
- Q_D(QWaylandClientExtension);
- if (d->registered && !QCoreApplication::closingDown())
- d->waylandIntegration->display()->removeListener(&QWaylandClientExtensionPrivate::handleRegistryGlobal, this);
}
QtWaylandClient::QWaylandIntegration *QWaylandClientExtension::integration() const
diff --git a/src/client/global/qwaylandclientextension_p.h b/src/client/global/qwaylandclientextension_p.h
index 9091efbe..621c14b7 100644
--- a/src/client/global/qwaylandclientextension_p.h
+++ b/src/client/global/qwaylandclientextension_p.h
@@ -53,22 +53,23 @@
#include <QtCore/private/qobject_p.h>
#include <QtWaylandClient/QWaylandClientExtension>
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandintegration_p.h>
QT_BEGIN_NAMESPACE
class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtensionPrivate : public QObjectPrivate
{
- Q_DECLARE_PUBLIC(QWaylandClientExtension)
public:
+ Q_DECLARE_PUBLIC(QWaylandClientExtension)
QWaylandClientExtensionPrivate();
- static void handleRegistryGlobal(void *data, ::wl_registry *registry, uint32_t id,
- const QString &interface, uint32_t version);
+
+ void globalAdded(const QtWaylandClient::QWaylandDisplay::RegistryGlobal &global);
+ void globalRemoved(const QtWaylandClient::QWaylandDisplay::RegistryGlobal &global);
QtWaylandClient::QWaylandIntegration *waylandIntegration = nullptr;
int version = -1;
bool active = false;
- bool registered = false;
};
class Q_WAYLAND_CLIENT_EXPORT QWaylandClientExtensionTemplatePrivate : public QWaylandClientExtensionPrivate
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index f8cb75e9..79c68a93 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -634,6 +634,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
}
mGlobals.append(RegistryGlobal(id, interface, version, registry));
+ emit globalAdded(mGlobals.back());
const auto copy = mRegistryListeners; // be prepared for listeners unregistering on notification
for (Listener l : copy)
@@ -690,7 +691,7 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
inputDevice->setTextInputMethod(nullptr);
mWaylandIntegration->reconfigureInputContext();
}
- mGlobals.removeAt(i);
+ emit globalRemoved(mGlobals.takeAt(i));
break;
}
}
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index cf123cba..5a83c324 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -228,6 +228,10 @@ public slots:
void blockingReadEvents();
void flushRequests();
+signals:
+ void globalAdded(const RegistryGlobal &global);
+ void globalRemoved(const RegistryGlobal &global);
+
private:
void handleWaylandSync();
void requestWaylandSync();
diff --git a/tests/auto/client/CMakeLists.txt b/tests/auto/client/CMakeLists.txt
index accac45f..e187d1da 100644
--- a/tests/auto/client/CMakeLists.txt
+++ b/tests/auto/client/CMakeLists.txt
@@ -3,6 +3,7 @@
add_subdirectory(shared)
add_subdirectory(client)
+add_subdirectory(clientextension)
add_subdirectory(datadevicev1)
add_subdirectory(fullscreenshellv1)
add_subdirectory(iviapplication)
diff --git a/tests/auto/client/clientextension/CMakeLists.txt b/tests/auto/client/clientextension/CMakeLists.txt
new file mode 100644
index 00000000..efcd575d
--- /dev/null
+++ b/tests/auto/client/clientextension/CMakeLists.txt
@@ -0,0 +1,14 @@
+qt_internal_add_test(tst_clientextension
+ SOURCES
+ tst_clientextension.cpp
+ PUBLIC_LIBRARIES
+ SharedClientTest
+)
+
+qt6_generate_wayland_protocol_client_sources(tst_clientextension
+ FILES ${CMAKE_CURRENT_SOURCE_DIR}/test.xml
+)
+
+qt6_generate_wayland_protocol_server_sources(tst_clientextension
+ FILES ${CMAKE_CURRENT_SOURCE_DIR}/test.xml
+)
diff --git a/tests/auto/client/clientextension/test.xml b/tests/auto/client/clientextension/test.xml
new file mode 100644
index 00000000..f8d5b4ea
--- /dev/null
+++ b/tests/auto/client/clientextension/test.xml
@@ -0,0 +1,6 @@
+<protocol name="test">
+ <interface name="test_interface" version="1">
+ <request name="release" type="destructor" />
+ </interface>
+</protocol>
+
diff --git a/tests/auto/client/clientextension/tst_clientextension.cpp b/tests/auto/client/clientextension/tst_clientextension.cpp
new file mode 100644
index 00000000..ea7ef361
--- /dev/null
+++ b/tests/auto/client/clientextension/tst_clientextension.cpp
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 David Redondo <qt@david-redondo.de>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QSignalSpy>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtWaylandClient/private/qwayland-wayland.h>
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
+#include <QtWaylandClient/private/qwaylandintegration_p.h>
+#include <QtWaylandClient/qwaylandclientextension.h>
+#include <qwayland-server-test.h>
+#include <qwayland-test.h>
+#include "mockcompositor.h"
+#include "coreprotocol.h"
+
+using namespace MockCompositor;
+
+class TestExtension : public QWaylandClientExtensionTemplate<TestExtension>,
+ public QtWayland::test_interface
+{
+public:
+ TestExtension() : QWaylandClientExtensionTemplate<TestExtension>(1) { }
+ ~TestExtension()
+ {
+ if (object()) {
+ release();
+ }
+ }
+ void initialize() { QWaylandClientExtension::initialize(); }
+};
+
+class TestGlobal : public Global, public QtWaylandServer::test_interface
+{
+ Q_OBJECT
+public:
+ explicit TestGlobal(CoreCompositor *compositor)
+ : QtWaylandServer::test_interface(compositor->m_display, 1)
+ {
+ }
+};
+
+class tst_clientextension : public QObject, private CoreCompositor
+{
+ Q_OBJECT
+private:
+ QtWaylandClient::QWaylandDisplay *display()
+ {
+ return static_cast<QtWaylandClient::QWaylandIntegration *>(
+ QGuiApplicationPrivate::platformIntegration())
+ ->display();
+ }
+private slots:
+ void cleanup()
+ {
+ display()->flushRequests();
+ dispatch();
+ exec([this] { removeAll<TestGlobal>(); });
+ QTRY_COMPARE(display()->globals().size(), 0);
+ }
+ void createWithoutGlobal();
+ void createWithGlobalAutomatic();
+ void createWithGlobalManual();
+ void globalBecomesAvailable();
+ void globalRemoved();
+};
+
+void tst_clientextension::createWithoutGlobal()
+{
+ TestExtension extension;
+ QSignalSpy spy(&extension, &QWaylandClientExtension::activeChanged);
+ QVERIFY(spy.isValid());
+ QVERIFY(!extension.isActive());
+ QCOMPARE(spy.count(), 0);
+ extension.initialize();
+ QVERIFY(!extension.isActive());
+ QCOMPARE(spy.count(), 0);
+}
+
+void tst_clientextension::createWithGlobalAutomatic()
+{
+ exec([this] { add<TestGlobal>(); });
+ QTRY_COMPARE(display()->globals().size(), 1);
+ TestExtension extension;
+ QSignalSpy spy(&extension, &QWaylandClientExtension::activeChanged);
+ QVERIFY(spy.isValid());
+ QTRY_VERIFY(extension.isActive());
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_clientextension::createWithGlobalManual()
+{
+ exec([this] { add<TestGlobal>(); });
+ QTRY_COMPARE(display()->globals().size(), 1);
+ // Wait for the display to have the global
+ TestExtension extension;
+ QSignalSpy spy(&extension, &QWaylandClientExtension::activeChanged);
+ QVERIFY(spy.isValid());
+ extension.initialize();
+ QVERIFY(extension.isActive());
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_clientextension::globalBecomesAvailable()
+{
+ TestExtension extension;
+ QSignalSpy spy(&extension, &QWaylandClientExtension::activeChanged);
+ QVERIFY(spy.isValid());
+ exec([this] { add<TestGlobal>(); });
+ QTRY_VERIFY(extension.isActive());
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_clientextension::globalRemoved()
+{
+ exec([this] { add<TestGlobal>(); });
+ TestExtension extension;
+ QTRY_VERIFY(extension.isActive());
+ QSignalSpy spy(&extension, &QWaylandClientExtension::activeChanged);
+ QVERIFY(spy.isValid());
+ QCOMPOSITOR_TRY_COMPARE(get<TestGlobal>()->resourceMap().size(), 1);
+
+ exec([this] { removeAll<TestGlobal>(); });
+ QTRY_VERIFY(!extension.isActive());
+ QCOMPARE(spy.count(), 1);
+}
+
+QCOMPOSITOR_TEST_MAIN(tst_clientextension)
+#include "tst_clientextension.moc"