KWin
Loading...
Searching...
No Matches
test_viewporter_interface.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include <QSignalSpy>
8#include <QTest>
9#include <QThread>
10
11#include "wayland/compositor.h"
12#include "wayland/display.h"
13#include "wayland/surface.h"
14#include "wayland/viewporter.h"
15
16#include "KWayland/Client/compositor.h"
17#include "KWayland/Client/connection_thread.h"
18#include "KWayland/Client/event_queue.h"
19#include "KWayland/Client/registry.h"
20#include "KWayland/Client/shm_pool.h"
21#include "KWayland/Client/surface.h"
22
23#include "qwayland-viewporter.h"
24
25using namespace KWin;
26
27class Viewporter : public QtWayland::wp_viewporter
28{
29};
30
31class Viewport : public QtWayland::wp_viewport
32{
33};
34
35class TestViewporterInterface : public QObject
36{
37 Q_OBJECT
38
39public:
40 ~TestViewporterInterface() override;
41
42private Q_SLOTS:
43 void initTestCase();
44 void testCropScale();
45
46private:
47 KWayland::Client::ConnectionThread *m_connection;
48 KWayland::Client::EventQueue *m_queue;
49 KWayland::Client::Compositor *m_clientCompositor;
50 KWayland::Client::ShmPool *m_shm;
51
52 QThread *m_thread;
53 KWin::Display m_display;
54 CompositorInterface *m_serverCompositor;
55 Viewporter *m_viewporter;
56};
57
58static const QString s_socketName = QStringLiteral("kwin-wayland-server-viewporter-test-0");
59
60void TestViewporterInterface::initTestCase()
61{
62 m_display.addSocketName(s_socketName);
63 m_display.start();
64 QVERIFY(m_display.isRunning());
65
66 m_display.createShm();
67 new ViewporterInterface(&m_display);
68
69 m_serverCompositor = new CompositorInterface(&m_display, this);
70
71 m_connection = new KWayland::Client::ConnectionThread;
72 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
73 m_connection->setSocketName(s_socketName);
74
75 m_thread = new QThread(this);
76 m_connection->moveToThread(m_thread);
77 m_thread->start();
78
79 m_connection->initConnection();
80 QVERIFY(connectedSpy.wait());
81 QVERIFY(!m_connection->connections().isEmpty());
82
83 m_queue = new KWayland::Client::EventQueue(this);
84 QVERIFY(!m_queue->isValid());
85 m_queue->setup(m_connection);
86 QVERIFY(m_queue->isValid());
87
88 auto registry = new KWayland::Client::Registry(this);
89 connect(registry, &KWayland::Client::Registry::interfaceAnnounced, this, [this, registry](const QByteArray &interface, quint32 id, quint32 version) {
90 if (interface == QByteArrayLiteral("wp_viewporter")) {
91 m_viewporter = new Viewporter();
92 m_viewporter->init(*registry, id, version);
93 }
94 });
95 QSignalSpy allAnnouncedSpy(registry, &KWayland::Client::Registry::interfaceAnnounced);
96 QSignalSpy compositorSpy(registry, &KWayland::Client::Registry::compositorAnnounced);
97 QSignalSpy shmSpy(registry, &KWayland::Client::Registry::shmAnnounced);
98 registry->setEventQueue(m_queue);
99 registry->create(m_connection->display());
100 QVERIFY(registry->isValid());
101 registry->setup();
102 QVERIFY(allAnnouncedSpy.wait());
103
104 m_clientCompositor = registry->createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
105 QVERIFY(m_clientCompositor->isValid());
106
107 m_shm = registry->createShmPool(shmSpy.first().first().value<quint32>(), shmSpy.first().last().value<quint32>(), this);
108 QVERIFY(m_shm->isValid());
109}
110
112{
113 if (m_viewporter) {
114 delete m_viewporter;
115 m_viewporter = nullptr;
116 }
117 if (m_shm) {
118 delete m_shm;
119 m_shm = nullptr;
120 }
121 if (m_queue) {
122 delete m_queue;
123 m_queue = nullptr;
124 }
125 if (m_thread) {
126 m_thread->quit();
127 m_thread->wait();
128 delete m_thread;
129 m_thread = nullptr;
130 }
131 m_connection->deleteLater();
132 m_connection = nullptr;
133}
134
135void TestViewporterInterface::testCropScale()
136{
137 // Create a test surface.
138 QSignalSpy serverSurfaceCreatedSpy(m_serverCompositor, &CompositorInterface::surfaceCreated);
139 std::unique_ptr<KWayland::Client::Surface> clientSurface(m_clientCompositor->createSurface(this));
140 QVERIFY(serverSurfaceCreatedSpy.wait());
141 SurfaceInterface *serverSurface = serverSurfaceCreatedSpy.first().first().value<SurfaceInterface *>();
142 QVERIFY(serverSurface);
143
144 QSignalSpy serverSurfaceMappedSpy(serverSurface, &SurfaceInterface::mapped);
145 QSignalSpy serverSurfaceSizeChangedSpy(serverSurface, &SurfaceInterface::sizeChanged);
146 QSignalSpy bufferSourceBoxChangedSpy(serverSurface, &SurfaceInterface::bufferSourceBoxChanged);
147
148 // Map the surface.
149 QImage image(QSize(200, 100), QImage::Format_ARGB32_Premultiplied);
150 image.fill(Qt::black);
151 KWayland::Client::Buffer::Ptr buffer = m_shm->createBuffer(image);
152 clientSurface->attachBuffer(buffer);
153 clientSurface->setScale(2);
154 clientSurface->damage(image.rect());
155 clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
156 QVERIFY(serverSurfaceMappedSpy.wait());
157 QCOMPARE(bufferSourceBoxChangedSpy.count(), 1);
158 QCOMPARE(serverSurface->size(), QSize(100, 50));
159 QCOMPARE(serverSurface->bufferSourceBox(), QRectF(0, 0, 200, 100));
160
161 // Create a viewport for the surface.
162 std::unique_ptr<Viewport> clientViewport(new Viewport);
163 clientViewport->init(m_viewporter->get_viewport(*clientSurface));
164
165 // Crop the surface.
166 clientViewport->set_source(wl_fixed_from_double(10), wl_fixed_from_double(10), wl_fixed_from_double(30), wl_fixed_from_double(20));
167 clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
168 QVERIFY(serverSurfaceSizeChangedSpy.wait());
169 QCOMPARE(bufferSourceBoxChangedSpy.count(), 2);
170 QCOMPARE(serverSurface->size(), QSize(30, 20));
171 QCOMPARE(serverSurface->bufferSourceBox(), QRectF(20, 20, 60, 40));
172
173 // Scale the surface.
174 clientViewport->set_destination(500, 250);
175 clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
176 QVERIFY(serverSurfaceSizeChangedSpy.wait());
177 QCOMPARE(bufferSourceBoxChangedSpy.count(), 2);
178 QCOMPARE(serverSurface->size(), QSize(500, 250));
179 QCOMPARE(serverSurface->bufferSourceBox(), QRectF(20, 20, 60, 40));
180
181 // If the viewport is destroyed, the crop and scale state will be unset on a next commit.
182 clientViewport->destroy();
183 clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
184 QVERIFY(serverSurfaceSizeChangedSpy.wait());
185 QCOMPARE(bufferSourceBoxChangedSpy.count(), 3);
186 QCOMPARE(serverSurface->size(), QSize(100, 50));
187 QCOMPARE(serverSurface->bufferSourceBox(), QRectF(0, 0, 200, 100));
188}
189
190QTEST_GUILESS_MAIN(TestViewporterInterface)
191
192#include "test_viewporter_interface.moc"
void surfaceCreated(KWin::SurfaceInterface *surface)
Class holding the Wayland server display loop.
Definition display.h:34
void createShm()
Definition display.cpp:128
bool addSocketName(const QString &name=QString())
Definition display.cpp:68
bool isRunning() const
Definition display.cpp:144
bool start()
Definition display.cpp:92
Resource representing a wl_surface.
Definition surface.h:80
QRectF bufferSourceBox() const
Definition surface.cpp:799
KWayland::Client::Registry * registry
constexpr int version