diff options
Diffstat (limited to 'tests/auto/qml/windowproperties/apps/wp-app-native')
5 files changed, 237 insertions, 0 deletions
diff --git a/tests/auto/qml/windowproperties/apps/wp-app-native/CMakeLists.txt b/tests/auto/qml/windowproperties/apps/wp-app-native/CMakeLists.txt new file mode 100644 index 00000000..8bc20ddf --- /dev/null +++ b/tests/auto/qml/windowproperties/apps/wp-app-native/CMakeLists.txt @@ -0,0 +1,26 @@ + +qt_internal_add_executable(wp-app-native + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/" + SOURCES + wp-app.cpp + waylandqtamclientextension_v2.cpp + waylandqtamclientextension_v2_p.h + LIBRARIES + Qt::Core + Qt::Gui + Qt::Quick + Qt::Qml + Qt::WaylandClient + Qt::WaylandClientPrivate +) + +qt_internal_set_exceptions_flags(wp-app-native TRUE) + +qt_autogen_tools_initial_setup(wp-app-native) + +qt6_generate_wayland_protocol_client_sources(wp-app-native + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/wayland-extensions/qtam-extension.xml +) + +qt_internal_add_autogen_sync_header_dependencies(wp-app-native WaylandClient) diff --git a/tests/auto/qml/windowproperties/apps/wp-app-native/info.yaml b/tests/auto/qml/windowproperties/apps/wp-app-native/info.yaml new file mode 100644 index 00000000..c145f0c1 --- /dev/null +++ b/tests/auto/qml/windowproperties/apps/wp-app-native/info.yaml @@ -0,0 +1,6 @@ +formatVersion: 1 +formatType: am-application +--- +id: 'wp-app-native' +code: 'wp-app-native' +runtime: 'native' diff --git a/tests/auto/qml/windowproperties/apps/wp-app-native/waylandqtamclientextension_v2.cpp b/tests/auto/qml/windowproperties/apps/wp-app-native/waylandqtamclientextension_v2.cpp new file mode 100644 index 00000000..62f122da --- /dev/null +++ b/tests/auto/qml/windowproperties/apps/wp-app-native/waylandqtamclientextension_v2.cpp @@ -0,0 +1,127 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "waylandqtamclientextension_v2_p.h" + +#include <QWindow> +#include <QGuiApplication> +#include <QEvent> +#include <QExposeEvent> +#include <qpa/qplatformnativeinterface.h> +#include <QJSValue> +#include <QCborValue> + + +// This is a copy of the built-in class WaylandQtAMClientExtension (version 1). Not all +// functionality is actually used for the test, but it makes it easier to keep the code in sync +// this way, as they share ~90% of the implementation. + +WaylandQtAMClientExtensionV2::WaylandQtAMClientExtensionV2() + : QWaylandClientExtensionTemplate(2) +{ + qApp->installEventFilter(this); +} + +WaylandQtAMClientExtensionV2::~WaylandQtAMClientExtensionV2() +{ + qApp->removeEventFilter(this); +} + +bool WaylandQtAMClientExtensionV2::eventFilter(QObject *o, QEvent *e) +{ + if (e->type() == QEvent::Expose) { + if (!isActive()) { + qWarning() << "WaylandQtAMClientExtensionV2 is not active"; + } else { + QWindow *window = qobject_cast<QWindow *>(o); + Q_ASSERT(window); + + // we're only interested in the first expose to setup our mapping + if (!m_windowToSurface.contains(window)) { + auto surface = static_cast<struct ::wl_surface *> + (QGuiApplication::platformNativeInterface()->nativeResourceForWindow("surface", window)); + if (surface) { + m_windowToSurface.insert(window, surface); + const QVariantMap wp = windowProperties(window); + for (auto it = wp.cbegin(); it != wp.cend(); ++it) + sendPropertyToServer(surface, it.key(), it.value()); + } + // pointers can be reused, so we have to remove the old mappings + connect(window, &QObject::destroyed, this, [this, window]() { + m_windowToSurface.remove(window); + m_windowProperties.remove(window); + }); + } + } + } else if (e->type() == QEvent::Hide) { + m_windowToSurface.remove(qobject_cast<QWindow *>(o)); + } + + return QWaylandClientExtensionTemplate<WaylandQtAMClientExtensionV2>::eventFilter(o, e); +} + +QVariantMap WaylandQtAMClientExtensionV2::windowProperties(QWindow *window) const +{ + return m_windowProperties.value(window); +} + +void WaylandQtAMClientExtensionV2::sendPropertyToServer(struct ::wl_surface *surface, const QString &name, + const QVariant &value) +{ + if (int(qtam_extension::version()) != QWaylandClientExtension::version()) { + qWarning() << "Unsupported qtam_extension version:" << qtam_extension::version(); + return; + } + const QByteArray data = QCborValue::fromVariant(value).toCbor(); + set_window_property(surface, name, data); +} + +bool WaylandQtAMClientExtensionV2::setWindowProperty(QWindow *window, const QString &name, const QVariant &value) +{ + if (setWindowPropertyHelper(window, name, value) && m_windowToSurface.contains(window)) { + auto surface = static_cast<struct ::wl_surface *> + (QGuiApplication::platformNativeInterface()->nativeResourceForWindow("surface", window)); + if (surface) { + sendPropertyToServer(surface, name, value); + return true; + } + } + return false; +} + +bool WaylandQtAMClientExtensionV2::setWindowPropertyHelper(QWindow *window, const QString &name, const QVariant &value) +{ + auto it = m_windowProperties.find(window); + if ((it == m_windowProperties.end()) || (it.value().value(name) != value)) { + if (it == m_windowProperties.end()) + m_windowProperties[window].insert(name, value); + else + it.value().insert(name, value); + + emit windowPropertyChanged(window, name, value); + return true; + } + return false; +} + +void WaylandQtAMClientExtensionV2::clearWindowPropertyCache(QWindow *window) +{ + m_windowProperties.remove(window); +} + +void WaylandQtAMClientExtensionV2::qtam_extension_window_property_changed(wl_surface *surface, const QString &name, + wl_array *value) +{ + if (int(qtam_extension::version()) != QWaylandClientExtension::version()) { + qWarning() << "Unsupported qtam_extension version:" << qtam_extension::version(); + return; + } + + if (QWindow *window = m_windowToSurface.key(surface)) { + const auto data = QByteArray::fromRawData(static_cast<const char *>(value->data), qsizetype(value->size)); + const QVariant variantValue = QCborValue::fromCbor(data).toVariant(); + setWindowPropertyHelper(window, name, variantValue); + } +} + +#include "moc_waylandqtamclientextension_v2_p.cpp" diff --git a/tests/auto/qml/windowproperties/apps/wp-app-native/waylandqtamclientextension_v2_p.h b/tests/auto/qml/windowproperties/apps/wp-app-native/waylandqtamclientextension_v2_p.h new file mode 100644 index 00000000..04251073 --- /dev/null +++ b/tests/auto/qml/windowproperties/apps/wp-app-native/waylandqtamclientextension_v2_p.h @@ -0,0 +1,45 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef WAYLANDQTAMCLIENTEXTENSION_V2_P_H +#define WAYLANDQTAMCLIENTEXTENSION_V2_P_H + +#include <QVariantMap> +#include <QtWaylandClient/QWaylandClientExtensionTemplate> +#include "qwayland-qtam-extension.h" + +QT_FORWARD_DECLARE_CLASS(QWindow) + +// This is a copy of the built-in class WaylandQtAMClientExtension (version 1). Not all +// functionality is actually used for the test, but it makes it easier to keep the code in sync +// this way, as they share ~90% of the implementation. + +class WaylandQtAMClientExtensionV2 : public QWaylandClientExtensionTemplate<WaylandQtAMClientExtensionV2>, + public ::QtWayland::qtam_extension +{ + Q_OBJECT + +public: + WaylandQtAMClientExtensionV2(); + ~WaylandQtAMClientExtensionV2() override; + + QVariantMap windowProperties(QWindow *window) const; + bool setWindowProperty(QWindow *window, const QString &name, const QVariant &value); + void clearWindowPropertyCache(QWindow *window); + +signals: + void windowPropertyChanged(QWindow *window, const QString &name, const QVariant &value); + +protected: + bool eventFilter(QObject *o, QEvent *e) override; + +private: + bool setWindowPropertyHelper(QWindow *window, const QString &name, const QVariant &value); + void sendPropertyToServer(::wl_surface *surface, const QString &name, const QVariant &value); + void qtam_extension_window_property_changed(wl_surface *surface, const QString &name, wl_array *value) override; + + QMap<QWindow *, QVariantMap> m_windowProperties; // AXIVION Line Qt-QMapWithPointerKey: cleared on destroyed signal + QMap<QWindow *, ::wl_surface *> m_windowToSurface; // AXIVION Line Qt-QMapWithPointerKey: cleared on destroyed signal +}; + +#endif // WAYLANDQTAMCLIENTEXTENSION_V2_P_H diff --git a/tests/auto/qml/windowproperties/apps/wp-app-native/wp-app.cpp b/tests/auto/qml/windowproperties/apps/wp-app-native/wp-app.cpp new file mode 100644 index 00000000..207aef6b --- /dev/null +++ b/tests/auto/qml/windowproperties/apps/wp-app-native/wp-app.cpp @@ -0,0 +1,33 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QGuiApplication> +#include <QQuickView> + +#include "waylandqtamclientextension_v2_p.h" + +using namespace Qt::StringLiterals; + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + auto qtamExtension = new WaylandQtAMClientExtensionV2(); + QQuickView w; + w.setGeometry(0, 0, 100, 100); + w.show(); + + qsizetype expectedSize = 0; + + const auto args = app.arguments(); + if (auto pos = args.indexOf(u"--start-argument"_s); pos >= 0) + expectedSize = args.at(pos + 1).toInt(); + + QObject::connect(qtamExtension, &WaylandQtAMClientExtensionV2::windowPropertyChanged, + &app, [&](QWindow *, const QString &, const QVariant &) { + auto allProperties = qtamExtension->windowProperties(&w); + if (allProperties.size() == expectedSize) + qtamExtension->setWindowProperty(&w, u"BACKCHANNEL"_s, allProperties); + }); + + return app.exec(); +} |