KWin
Loading...
Searching...
No Matches
test_server_side_decoration.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6// Qt
7#include <QSignalSpy>
8#include <QTest>
9// KWin
10#include "wayland/compositor.h"
11#include "wayland/display.h"
13
14#include "qwayland-server-decoration.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/surface.h"
21
22class ServerSideDecorationManager : public QtWayland::org_kde_kwin_server_decoration_manager
23{
24};
25
26class ServerSideDecoration : public QObject, public QtWayland::org_kde_kwin_server_decoration
27{
28 Q_OBJECT
29
30public:
32 {
33 release();
34 }
35
36Q_SIGNALS:
37 void modeChanged(ServerSideDecorationManager::mode mode);
38
39protected:
40 void org_kde_kwin_server_decoration_mode(uint32_t mode) override
41 {
42 Q_EMIT modeChanged(ServerSideDecorationManager::mode(mode));
43 }
44};
45
46class TestServerSideDecoration : public QObject
47{
48 Q_OBJECT
49public:
50 explicit TestServerSideDecoration(QObject *parent = nullptr);
51private Q_SLOTS:
52 void init();
53 void cleanup();
54
55 void testCreate_data();
56 void testCreate();
57
58 void testRequest_data();
59 void testRequest();
60
61 void testSurfaceDestroy();
62
63private:
64 KWin::Display *m_display = nullptr;
65 KWin::CompositorInterface *m_compositorInterface = nullptr;
66 KWin::ServerSideDecorationManagerInterface *m_serverSideDecorationManagerInterface = nullptr;
67 KWayland::Client::ConnectionThread *m_connection = nullptr;
68 KWayland::Client::Compositor *m_compositor = nullptr;
69 KWayland::Client::EventQueue *m_queue = nullptr;
70 ServerSideDecorationManager *m_serverSideDecorationManager = nullptr;
71 QThread *m_thread = nullptr;
72 KWayland::Client::Registry *m_registry = nullptr;
73};
74
75static const QString s_socketName = QStringLiteral("kwayland-test-wayland-server-side-decoration-0");
76
78 : QObject(parent)
79{
80}
81
82void TestServerSideDecoration::init()
83{
84 using namespace KWin;
85 delete m_display;
86 m_display = new KWin::Display(this);
87 m_display->addSocketName(s_socketName);
88 m_display->start();
89 QVERIFY(m_display->isRunning());
90
91 // setup connection
92 m_connection = new KWayland::Client::ConnectionThread;
93 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
94 m_connection->setSocketName(s_socketName);
95
96 m_thread = new QThread(this);
97 m_connection->moveToThread(m_thread);
98 m_thread->start();
99
100 m_connection->initConnection();
101 QVERIFY(connectedSpy.wait());
102
103 m_queue = new KWayland::Client::EventQueue(this);
104 QVERIFY(!m_queue->isValid());
105 m_queue->setup(m_connection);
106 QVERIFY(m_queue->isValid());
107
108 m_compositorInterface = new CompositorInterface(m_display, m_display);
109 m_serverSideDecorationManagerInterface = new ServerSideDecorationManagerInterface(m_display, m_display);
110
111 m_registry = new KWayland::Client::Registry();
112 connect(m_registry, &KWayland::Client::Registry::interfaceAnnounced, this, [this](const QByteArray &interfaceName, quint32 name, quint32 version) {
113 if (interfaceName == org_kde_kwin_server_decoration_manager_interface.name) {
114 m_serverSideDecorationManager = new ServerSideDecorationManager();
115 m_serverSideDecorationManager->init(*m_registry, name, version);
116 }
117 });
118
119 QSignalSpy interfacesAnnouncedSpy(m_registry, &KWayland::Client::Registry::interfacesAnnounced);
120 QSignalSpy compositorSpy(m_registry, &KWayland::Client::Registry::compositorAnnounced);
121
122 QVERIFY(!m_registry->eventQueue());
123 m_registry->setEventQueue(m_queue);
124 QCOMPARE(m_registry->eventQueue(), m_queue);
125 m_registry->create(m_connection);
126 QVERIFY(m_registry->isValid());
127 m_registry->setup();
128 QVERIFY(interfacesAnnouncedSpy.wait());
129
130 m_compositor = m_registry->createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
131
132 QVERIFY(m_compositor);
133 QVERIFY(m_serverSideDecorationManager);
134}
135
136void TestServerSideDecoration::cleanup()
137{
138 if (m_compositor) {
139 delete m_compositor;
140 m_compositor = nullptr;
141 }
142 if (m_serverSideDecorationManager) {
143 delete m_serverSideDecorationManager;
144 m_serverSideDecorationManager = nullptr;
145 }
146 if (m_registry) {
147 delete m_registry;
148 m_registry = nullptr;
149 }
150
151 if (m_queue) {
152 delete m_queue;
153 m_queue = nullptr;
154 }
155
156 if (m_thread) {
157 m_thread->quit();
158 m_thread->wait();
159 delete m_thread;
160 m_thread = nullptr;
161 }
162 delete m_connection;
163 m_connection = nullptr;
164
165 delete m_display;
166 m_display = nullptr;
167}
168
169void TestServerSideDecoration::testCreate_data()
170{
171 using namespace KWin;
172 QTest::addColumn<ServerSideDecorationManagerInterface::Mode>("serverMode");
173 QTest::addColumn<ServerSideDecorationManager::mode>("clientMode");
174
175 QTest::newRow("none") << ServerSideDecorationManagerInterface::Mode::None << ServerSideDecorationManager::mode_None;
176 QTest::newRow("client") << ServerSideDecorationManagerInterface::Mode::Client << ServerSideDecorationManager::mode_Client;
177 QTest::newRow("server") << ServerSideDecorationManagerInterface::Mode::Server << ServerSideDecorationManager::mode_Server;
178}
179
180void TestServerSideDecoration::testCreate()
181{
182 using namespace KWin;
184 m_serverSideDecorationManagerInterface->setDefaultMode(serverMode);
185 QCOMPARE(m_serverSideDecorationManagerInterface->defaultMode(), serverMode);
186
187 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
188 QSignalSpy decorationCreated(m_serverSideDecorationManagerInterface, &ServerSideDecorationManagerInterface::decorationCreated);
189
190 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
191 QVERIFY(serverSurfaceCreated.wait());
192
193 auto serverSurface = serverSurfaceCreated.first().first().value<SurfaceInterface *>();
194 QVERIFY(!ServerSideDecorationInterface::get(serverSurface));
195
196 // create server side deco
197 auto serverSideDecoration = std::make_unique<ServerSideDecoration>();
198 serverSideDecoration->init(m_serverSideDecorationManager->create(*surface.get()));
199 QSignalSpy modeChangedSpy(serverSideDecoration.get(), &ServerSideDecoration::modeChanged);
200
201 QVERIFY(decorationCreated.wait());
202
203 auto serverDeco = decorationCreated.first().first().value<ServerSideDecorationInterface *>();
204 QVERIFY(serverDeco);
205 QCOMPARE(serverDeco, ServerSideDecorationInterface::get(serverSurface));
206 QCOMPARE(serverDeco->surface(), serverSurface);
207
208 // after binding the client should get the default mode
209 QVERIFY(modeChangedSpy.wait());
210 QCOMPARE(modeChangedSpy.count(), 1);
211 QTEST(modeChangedSpy.last().at(0).value<ServerSideDecorationManager::mode>(), "clientMode");
212
213 // and destroy
214 QSignalSpy destroyedSpy(serverDeco, &QObject::destroyed);
215 serverSideDecoration.reset();
216 QVERIFY(destroyedSpy.wait());
217}
218
219void TestServerSideDecoration::testRequest_data()
220{
221 using namespace KWin;
222 QTest::addColumn<ServerSideDecorationManagerInterface::Mode>("defaultMode");
223 QTest::addColumn<ServerSideDecorationManager::mode>("clientMode");
224 QTest::addColumn<ServerSideDecorationManager::mode>("clientRequestMode");
225 QTest::addColumn<ServerSideDecorationManagerInterface::Mode>("serverRequestedMode");
226
227 const auto serverNone = ServerSideDecorationManagerInterface::Mode::None;
228 const auto serverClient = ServerSideDecorationManagerInterface::Mode::Client;
229 const auto serverServer = ServerSideDecorationManagerInterface::Mode::Server;
230 const auto clientNone = ServerSideDecorationManager::mode_None;
231 const auto clientClient = ServerSideDecorationManager::mode_Client;
232 const auto clientServer = ServerSideDecorationManager::mode_Server;
233
234 QTest::newRow("none->none") << serverNone << clientNone << clientNone << serverNone;
235 QTest::newRow("none->client") << serverNone << clientNone << clientClient << serverClient;
236 QTest::newRow("none->server") << serverNone << clientNone << clientServer << serverServer;
237 QTest::newRow("client->none") << serverClient << clientClient << clientNone << serverNone;
238 QTest::newRow("client->client") << serverClient << clientClient << clientClient << serverClient;
239 QTest::newRow("client->server") << serverClient << clientClient << clientServer << serverServer;
240 QTest::newRow("server->none") << serverServer << clientServer << clientNone << serverNone;
241 QTest::newRow("server->client") << serverServer << clientServer << clientClient << serverClient;
242 QTest::newRow("server->server") << serverServer << clientServer << clientServer << serverServer;
243}
244
245void TestServerSideDecoration::testRequest()
246{
247 using namespace KWin;
249 m_serverSideDecorationManagerInterface->setDefaultMode(defaultMode);
250 QCOMPARE(m_serverSideDecorationManagerInterface->defaultMode(), defaultMode);
251
252 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
253 QSignalSpy decorationCreated(m_serverSideDecorationManagerInterface, &ServerSideDecorationManagerInterface::decorationCreated);
254
255 // create server side deco
256 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
257
258 auto serverSideDecoration = std::make_unique<ServerSideDecoration>();
259 serverSideDecoration->init(m_serverSideDecorationManager->create(*surface.get()));
260 QSignalSpy modeChangedSpy(serverSideDecoration.get(), &ServerSideDecoration::modeChanged);
261 QVERIFY(decorationCreated.wait());
262
263 auto serverDeco = decorationCreated.first().first().value<ServerSideDecorationInterface *>();
264 QVERIFY(serverDeco);
265 QSignalSpy preferredModeChangedSpy(serverDeco, &ServerSideDecorationInterface::preferredModeChanged);
266
267 // after binding the client should get the default mode
268 QVERIFY(modeChangedSpy.wait());
269 QCOMPARE(modeChangedSpy.count(), 1);
270 QTEST(modeChangedSpy.last().at(0).value<ServerSideDecorationManager::mode>(), "clientMode");
271
272 // request a change
273 QFETCH(ServerSideDecorationManager::mode, clientRequestMode);
274 serverSideDecoration->request_mode(clientRequestMode);
275 // mode not yet changed
276 QCOMPARE(modeChangedSpy.count(), 1);
277
278 QVERIFY(preferredModeChangedSpy.wait());
279 QCOMPARE(preferredModeChangedSpy.count(), 1);
280 QFETCH(ServerSideDecorationManagerInterface::Mode, serverRequestedMode);
281 QCOMPARE(serverDeco->preferredMode(), serverRequestedMode);
282
283 // mode not yet changed
284 QCOMPARE(serverDeco->mode(), defaultMode);
285 serverDeco->setMode(serverRequestedMode);
286 QCOMPARE(serverDeco->mode(), serverRequestedMode);
287
288 // should be sent to client
289 QVERIFY(modeChangedSpy.wait());
290 QCOMPARE(modeChangedSpy.count(), 2);
291 QCOMPARE(modeChangedSpy.last().at(0).value<ServerSideDecorationManager::mode>(), clientRequestMode);
292}
293
294void TestServerSideDecoration::testSurfaceDestroy()
295{
296 using namespace KWin;
297 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
298 QSignalSpy decorationCreated(m_serverSideDecorationManagerInterface, &ServerSideDecorationManagerInterface::decorationCreated);
299
300 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
301 QVERIFY(serverSurfaceCreated.wait());
302
303 auto serverSurface = serverSurfaceCreated.first().first().value<SurfaceInterface *>();
304 auto serverSideDecoration = std::make_unique<ServerSideDecoration>();
305 serverSideDecoration->init(m_serverSideDecorationManager->create(*surface.get()));
306 QSignalSpy modeChangedSpy(serverSideDecoration.get(), &ServerSideDecoration::modeChanged);
307 QVERIFY(decorationCreated.wait());
308 auto serverDeco = decorationCreated.first().first().value<ServerSideDecorationInterface *>();
309 QVERIFY(serverDeco);
310
311 // destroy the parent surface
312 QSignalSpy surfaceDestroyedSpy(serverSurface, &QObject::destroyed);
313 QSignalSpy decorationDestroyedSpy(serverDeco, &QObject::destroyed);
314 surface.reset();
315 QVERIFY(surfaceDestroyedSpy.wait());
316 QVERIFY(decorationDestroyedSpy.isEmpty());
317 // destroy the blur
318 serverSideDecoration.reset();
319 QVERIFY(decorationDestroyedSpy.wait());
320}
321
322QTEST_GUILESS_MAIN(TestServerSideDecoration)
323#include "test_server_side_decoration.moc"
Class holding the Wayland server display loop.
Definition display.h:34
bool addSocketName(const QString &name=QString())
Definition display.cpp:68
bool isRunning() const
Definition display.cpp:144
bool start()
Definition display.cpp:92
Representing how a SurfaceInterface should be decorated.
Manager to create ServerSideDecorationInterface.
Resource representing a wl_surface.
Definition surface.h:80
static SurfaceInterface * get(wl_resource *native)
Definition surface.cpp:819
void org_kde_kwin_server_decoration_mode(uint32_t mode) override
void modeChanged(ServerSideDecorationManager::mode mode)
TestServerSideDecoration(QObject *parent=nullptr)
constexpr int version