summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDavid Edmundson <davidedmundson@kde.org>2023-05-11 12:26:15 +0300
committerDavid Edmundson <davidedmundson@kde.org>2023-06-01 14:57:20 +0000
commitb1cae06cb65658dcddf01a596ea95cfd7c0ebdc2 (patch)
tree6b669599ad016d93a5f8b46613ed512f5672f474 /tests
parent9b3a347d6cc3bbc40071f245344b7bff9e6c2d96 (diff)
client: Implement cursor_shape_v1
A new wayland protocol allows clients to specify the cursor being used rather than load themes and attach buffers. Short term this has better behavior for scaling. Long term when this has universal compositor support we can drop the theme loading code. Change-Id: I119e1ca44d351e7b13b8ec56f2218d94b7da0705 Reviewed-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org> Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/client/CMakeLists.txt1
-rw-r--r--tests/auto/client/cursor/CMakeLists.txt11
-rw-r--r--tests/auto/client/cursor/cursorshapev1.cpp47
-rw-r--r--tests/auto/client/cursor/cursorshapev1.h44
-rw-r--r--tests/auto/client/cursor/tst_cursor.cpp89
-rw-r--r--tests/auto/client/shared/CMakeLists.txt1
-rw-r--r--tests/auto/client/shared/coreprotocol.cpp18
7 files changed, 204 insertions, 7 deletions
diff --git a/tests/auto/client/CMakeLists.txt b/tests/auto/client/CMakeLists.txt
index 5ae005eaa..79bcd442e 100644
--- a/tests/auto/client/CMakeLists.txt
+++ b/tests/auto/client/CMakeLists.txt
@@ -10,6 +10,7 @@ add_subdirectory(shared)
if (NOT WEBOS)
add_subdirectory(client)
add_subdirectory(clientextension)
+ add_subdirectory(cursor)
add_subdirectory(datadevicev1)
add_subdirectory(fullscreenshellv1)
add_subdirectory(iviapplication)
diff --git a/tests/auto/client/cursor/CMakeLists.txt b/tests/auto/client/cursor/CMakeLists.txt
new file mode 100644
index 000000000..93783994e
--- /dev/null
+++ b/tests/auto/client/cursor/CMakeLists.txt
@@ -0,0 +1,11 @@
+#####################################################################
+## tst_cursor Test:
+#####################################################################
+
+qt_internal_add_test(tst_cursor
+ SOURCES
+ tst_cursor.cpp
+ cursorshapev1.cpp
+ LIBRARIES
+ SharedClientTest
+)
diff --git a/tests/auto/client/cursor/cursorshapev1.cpp b/tests/auto/client/cursor/cursorshapev1.cpp
new file mode 100644
index 000000000..7fd93ed1d
--- /dev/null
+++ b/tests/auto/client/cursor/cursorshapev1.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "cursorshapev1.h"
+
+namespace MockCompositor {
+
+CursorShapeManager::CursorShapeManager(CoreCompositor *compositor, int version)
+ : QtWaylandServer::wp_cursor_shape_manager_v1(compositor->m_display, version)
+{
+}
+
+void CursorShapeManager::wp_cursor_shape_manager_v1_get_pointer(Resource *resource, uint32_t id, wl_resource *pointer)
+{
+ auto *p = fromResource<Pointer>(pointer);
+ auto *cursorShape = new CursorShapeDevice(p, resource->client(), id, resource->version());
+ connect(cursorShape, &QObject::destroyed, this, [this, cursorShape]() {
+ m_cursorDevices.removeOne(cursorShape);
+ });
+ m_cursorDevices << cursorShape;
+}
+
+CursorShapeDevice::CursorShapeDevice(Pointer *pointer, wl_client *client, int id, int version)
+ : QtWaylandServer::wp_cursor_shape_device_v1(client, id, version)
+ , m_pointer(pointer)
+{
+}
+
+void CursorShapeDevice::wp_cursor_shape_device_v1_destroy_resource(Resource *resource)
+{
+ Q_UNUSED(resource)
+ delete this;
+}
+
+void CursorShapeDevice::wp_cursor_shape_device_v1_destroy(Resource *resource)
+{
+ wl_resource_destroy(resource->handle);
+}
+
+void CursorShapeDevice::wp_cursor_shape_device_v1_set_shape(Resource *resource, uint32_t serial, uint32_t shape)
+{
+ Q_UNUSED(resource);
+ m_currentShape = static_cast<CursorShapeDevice::shape>(shape);
+ emit setCursor(serial);
+}
+
+}
diff --git a/tests/auto/client/cursor/cursorshapev1.h b/tests/auto/client/cursor/cursorshapev1.h
new file mode 100644
index 000000000..a8c2376ae
--- /dev/null
+++ b/tests/auto/client/cursor/cursorshapev1.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef MOCKCOMPOSITOR_CURSORSHAPE_H
+#define MOCKCOMPOSITOR_CURSORSHAPE_H
+
+#include "coreprotocol.h"
+#include <qwayland-server-cursor-shape-v1.h>
+
+namespace MockCompositor {
+
+class CursorShapeDevice;
+
+class CursorShapeManager : public Global, public QtWaylandServer::wp_cursor_shape_manager_v1
+{
+ Q_OBJECT
+public:
+ explicit CursorShapeManager(CoreCompositor *compositor, int version = 1);
+ QList<CursorShapeDevice *> m_cursorDevices;
+
+protected:
+ void wp_cursor_shape_manager_v1_get_pointer(Resource *resource, uint32_t id, wl_resource *pointer) override;
+};
+
+class CursorShapeDevice : public QObject, public QtWaylandServer::wp_cursor_shape_device_v1
+{
+ Q_OBJECT
+public:
+ explicit CursorShapeDevice(Pointer *pointer, wl_client *client, int id, int version);
+ Pointer *m_pointer;
+ shape m_currentShape = shape_default;
+
+Q_SIGNALS:
+ void setCursor(uint serial);
+
+protected:
+ void wp_cursor_shape_device_v1_destroy_resource(Resource *resource) override;
+ void wp_cursor_shape_device_v1_destroy(Resource *resource) override;
+ void wp_cursor_shape_device_v1_set_shape(Resource *resource, uint32_t serial, uint32_t shape) override;
+};
+
+}
+
+#endif
diff --git a/tests/auto/client/cursor/tst_cursor.cpp b/tests/auto/client/cursor/tst_cursor.cpp
new file mode 100644
index 000000000..65bafb23e
--- /dev/null
+++ b/tests/auto/client/cursor/tst_cursor.cpp
@@ -0,0 +1,89 @@
+// Copyright (C) 2023 David Edmundson <davidedmundson@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "mockcompositor.h"
+#include <QtGui/QRasterWindow>
+#include <QtGui/qpa/qplatformnativeinterface.h>
+#include <QtWaylandClient/private/wayland-wayland-client-protocol.h>
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
+
+#include "cursorshapev1.h"
+
+using namespace MockCompositor;
+
+class tst_cursor : public QObject, private DefaultCompositor
+{
+ Q_OBJECT
+public:
+ tst_cursor();
+ CursorShapeDevice* cursorShape();
+private slots:
+ void init();
+ void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
+ void setCursor();
+};
+
+tst_cursor::tst_cursor()
+{
+ exec([this] {
+ m_config.autoConfigure = true;
+ add<CursorShapeManager>(1);
+ });
+}
+
+CursorShapeDevice* tst_cursor::cursorShape()
+{
+ auto manager = get<CursorShapeManager>();
+ if (!manager->m_cursorDevices.count())
+ return nullptr;
+ return manager->m_cursorDevices[0];
+}
+
+void tst_cursor::init()
+{
+ setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1);
+}
+
+void tst_cursor::setCursor()
+{
+ QCOMPOSITOR_TRY_VERIFY(cursorShape());
+ QSignalSpy setCursorSpy(exec([&] { return pointer(); }), &Pointer::setCursor);
+ QSignalSpy setCursorShapeSpy(exec([&] { return cursorShape(); }), &CursorShapeDevice::setCursor);
+
+ QRasterWindow window;
+ window.resize(64, 64);
+ window.show();
+ QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
+
+ uint enterSerial = exec([&] {
+ return pointer()->sendEnter(xdgSurface()->m_surface, {32, 32});
+ });
+ setCursorShapeSpy.wait();
+ // verify we got given a cursor on enter
+ QCOMPOSITOR_COMPARE(cursorShape()->m_currentShape, CursorShapeDevice::shape_default);
+ QVERIFY(setCursorSpy.isEmpty());
+ QCOMPARE(setCursorShapeSpy.takeFirst().at(0).toUInt(), enterSerial);
+
+ // client sets a different shape
+ window.setCursor(QCursor(Qt::BusyCursor));
+ QCOMPOSITOR_TRY_COMPARE(cursorShape()->m_currentShape, CursorShapeDevice::shape_wait);
+
+ setCursorShapeSpy.clear();
+
+ // client hides the cursor
+ // CursorShape will not be used, instead, it uses the old path
+ window.setCursor(QCursor(Qt::BlankCursor));
+ QVERIFY(setCursorSpy.wait());
+ QVERIFY(setCursorShapeSpy.isEmpty());
+ QCOMPOSITOR_VERIFY(!pointer()->cursorSurface());
+
+ // same for bitmaps
+ QPixmap myCustomPixmap(10, 10);
+ myCustomPixmap.fill(Qt::red);
+ window.setCursor(QCursor(myCustomPixmap));
+ QVERIFY(setCursorSpy.wait());
+ QVERIFY(setCursorShapeSpy.isEmpty());
+}
+
+QCOMPOSITOR_TEST_MAIN(tst_cursor)
+#include "tst_cursor.moc"
diff --git a/tests/auto/client/shared/CMakeLists.txt b/tests/auto/client/shared/CMakeLists.txt
index a1f150c22..ee81b4d68 100644
--- a/tests/auto/client/shared/CMakeLists.txt
+++ b/tests/auto/client/shared/CMakeLists.txt
@@ -39,6 +39,7 @@ add_library(SharedClientTest
qt6_generate_wayland_protocol_server_sources(SharedClientTest
FILES
+ ${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/cursor-shape-v1.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/fullscreen-shell-unstable-v1.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/ivi-application.xml
${PROJECT_SOURCE_DIR}/src/3rdparty/protocol/wp-primary-selection-unstable-v1.xml
diff --git a/tests/auto/client/shared/coreprotocol.cpp b/tests/auto/client/shared/coreprotocol.cpp
index 15be62ccb..64586d413 100644
--- a/tests/auto/client/shared/coreprotocol.cpp
+++ b/tests/auto/client/shared/coreprotocol.cpp
@@ -435,15 +435,19 @@ void Pointer::sendAxisValue120(wl_client *client, QtWaylandServer::wl_pointer::a
void Pointer::pointer_set_cursor(Resource *resource, uint32_t serial, wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y)
{
Q_UNUSED(resource);
- auto *s = fromResource<Surface>(surface);
- QVERIFY(s);
- if (s->m_role) {
- m_cursorRole = CursorRole::fromSurface(s);
- QVERIFY(m_cursorRole);
+ if (!surface) {
+ m_cursorRole = nullptr;
} else {
- m_cursorRole = new CursorRole(s); //TODO: make sure we don't leak CursorRole
- s->m_role = m_cursorRole;
+ auto *s = fromResource<Surface>(surface);
+ QVERIFY(s);
+ if (s->m_role) {
+ m_cursorRole = CursorRole::fromSurface(s);
+ QVERIFY(m_cursorRole);
+ } else {
+ m_cursorRole = new CursorRole(s); //TODO: make sure we don't leak CursorRole
+ s->m_role = m_cursorRole;
+ }
}
// Directly checking the last serial would be racy, we may just have sent leaves/enters which