KWin
Loading...
Searching...
No Matches
test_wayland_subsurface.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2014 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#include "wayland/surface.h"
14
15#include "KWayland/Client/compositor.h"
16#include "KWayland/Client/connection_thread.h"
17#include "KWayland/Client/event_queue.h"
18#include "KWayland/Client/region.h"
19#include "KWayland/Client/registry.h"
20#include "KWayland/Client/shm_pool.h"
21#include "KWayland/Client/subcompositor.h"
22#include "KWayland/Client/subsurface.h"
23#include "KWayland/Client/surface.h"
24
25// Wayland
26#include <wayland-client.h>
27
28Q_DECLARE_METATYPE(KWayland::Client::SubSurface::Mode)
29
30class TestSubSurface : public QObject
31{
32 Q_OBJECT
33public:
34 explicit TestSubSurface(QObject *parent = nullptr);
35private Q_SLOTS:
36 void init();
37 void cleanup();
38
39 void testCreate();
40 void testMode();
41 void testPosition_data();
42 void testPosition();
43 void testPlaceAbove();
44 void testPlaceBelow();
45 void testSyncMode();
46 void testDeSyncMode();
47 void testMainSurfaceFromTree();
48 void testRemoveSurface();
49 void testMappingOfSurfaceTree();
50 void testSurfaceAt();
51 void testDestroyAttachedBuffer();
52 void testDestroyParentSurface();
53
54private:
55 KWin::Display *m_display;
56 KWin::CompositorInterface *m_compositorInterface;
57 KWin::SubCompositorInterface *m_subcompositorInterface;
58 KWayland::Client::ConnectionThread *m_connection;
59 KWayland::Client::Compositor *m_compositor;
60 KWayland::Client::ShmPool *m_shm;
61 KWayland::Client::SubCompositor *m_subCompositor;
62 KWayland::Client::EventQueue *m_queue;
63 QThread *m_thread;
64};
65
66static const QString s_socketName = QStringLiteral("kwayland-test-wayland-subsurface-0");
67
69 : QObject(parent)
70 , m_display(nullptr)
71 , m_compositorInterface(nullptr)
72 , m_subcompositorInterface(nullptr)
73 , m_connection(nullptr)
74 , m_compositor(nullptr)
75 , m_shm(nullptr)
76 , m_subCompositor(nullptr)
77 , m_queue(nullptr)
78 , m_thread(nullptr)
79{
80}
81
82void TestSubSurface::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 m_display->createShm();
91
92 // setup connection
93 m_connection = new KWayland::Client::ConnectionThread;
94 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
95 m_connection->setSocketName(s_socketName);
96
97 m_thread = new QThread(this);
98 m_connection->moveToThread(m_thread);
99 m_thread->start();
100
101 m_connection->initConnection();
102 QVERIFY(connectedSpy.wait());
103
104 m_queue = new KWayland::Client::EventQueue(this);
105 QVERIFY(!m_queue->isValid());
106 m_queue->setup(m_connection);
107 QVERIFY(m_queue->isValid());
108
109 KWayland::Client::Registry registry;
110 QSignalSpy compositorSpy(&registry, &KWayland::Client::Registry::compositorAnnounced);
111 QSignalSpy subCompositorSpy(&registry, &KWayland::Client::Registry::subCompositorAnnounced);
112 QVERIFY(!registry.eventQueue());
113 registry.setEventQueue(m_queue);
114 QCOMPARE(registry.eventQueue(), m_queue);
115 registry.create(m_connection->display());
116 QVERIFY(registry.isValid());
117 registry.setup();
118
119 m_compositorInterface = new CompositorInterface(m_display, m_display);
120 m_subcompositorInterface = new SubCompositorInterface(m_display, m_display);
121 QVERIFY(m_subcompositorInterface);
122
123 QVERIFY(subCompositorSpy.wait());
124 m_subCompositor = registry.createSubCompositor(subCompositorSpy.first().first().value<quint32>(), subCompositorSpy.first().last().value<quint32>(), this);
125
126 if (compositorSpy.isEmpty()) {
127 QVERIFY(compositorSpy.wait());
128 }
129 m_compositor = registry.createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
130
131 m_shm = registry.createShmPool(registry.interface(KWayland::Client::Registry::Interface::Shm).name,
132 registry.interface(KWayland::Client::Registry::Interface::Shm).version,
133 this);
134 QVERIFY(m_shm->isValid());
135}
136
137void TestSubSurface::cleanup()
138{
139 if (m_shm) {
140 delete m_shm;
141 m_shm = nullptr;
142 }
143 if (m_subCompositor) {
144 delete m_subCompositor;
145 m_subCompositor = nullptr;
146 }
147 if (m_compositor) {
148 delete m_compositor;
149 m_compositor = nullptr;
150 }
151 if (m_queue) {
152 delete m_queue;
153 m_queue = nullptr;
154 }
155 if (m_thread) {
156 m_thread->quit();
157 m_thread->wait();
158 delete m_thread;
159 m_thread = nullptr;
160 }
161 delete m_connection;
162 m_connection = nullptr;
163
164 delete m_display;
165 m_display = nullptr;
166}
167
168void TestSubSurface::testCreate()
169{
170 using namespace KWin;
171 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
172
173 // create two Surfaces
174 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
175 QVERIFY(surfaceCreatedSpy.wait());
176 SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>();
177 QVERIFY(serverSurface);
178
179 surfaceCreatedSpy.clear();
180 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface());
181 QVERIFY(surfaceCreatedSpy.wait());
182 SurfaceInterface *serverParentSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>();
183 QVERIFY(serverParentSurface);
184
185 QSignalSpy subSurfaceCreatedSpy(m_subcompositorInterface, &KWin::SubCompositorInterface::subSurfaceCreated);
186
187 // create subSurface for surface of parent
188 std::unique_ptr<KWayland::Client::SubSurface> subSurface(m_subCompositor->createSubSurface(surface.get(), parent.get()));
189
190 QVERIFY(subSurfaceCreatedSpy.wait());
191 SubSurfaceInterface *serverSubSurface = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>();
192 QVERIFY(serverSubSurface);
193 QVERIFY(serverSubSurface->parentSurface());
194 QCOMPARE(serverSubSurface->parentSurface(), serverParentSurface);
195 QCOMPARE(serverSubSurface->surface(), serverSurface);
196 QCOMPARE(serverSurface->subSurface(), serverSubSurface);
197 QCOMPARE(serverSubSurface->mainSurface(), serverParentSurface);
198 // children are only added after committing the surface
199 QCOMPARE(serverParentSurface->below().count(), 0);
200 QEXPECT_FAIL("", "Incorrect adding of child windows to workaround QtWayland behavior", Continue);
201 QCOMPARE(serverParentSurface->above().count(), 0);
202 // so let's commit the surface, to apply the stacking change
203 parent->commit(KWayland::Client::Surface::CommitFlag::None);
204 wl_display_flush(m_connection->display());
205 QCoreApplication::processEvents();
206 QCOMPARE(serverParentSurface->below().count(), 0);
207 QCOMPARE(serverParentSurface->above().count(), 1);
208 QCOMPARE(serverParentSurface->above().constFirst(), serverSubSurface);
209
210 // and let's destroy it again
211 QSignalSpy destroyedSpy(serverSubSurface, &QObject::destroyed);
212 subSurface.reset();
213 QVERIFY(destroyedSpy.wait());
214 QCOMPARE(serverSurface->subSurface(), QPointer<SubSurfaceInterface>());
215 // only applied after next commit
216 QCOMPARE(serverParentSurface->below().count(), 0);
217 QEXPECT_FAIL("", "Incorrect removing of child windows to workaround QtWayland behavior", Continue);
218 QCOMPARE(serverParentSurface->above().count(), 1);
219 // but the surface should be invalid
220 if (!serverParentSurface->above().isEmpty()) {
221 QVERIFY(!serverParentSurface->above().constFirst());
222 }
223 // committing the state should solve it
224 parent->commit(KWayland::Client::Surface::CommitFlag::None);
225 wl_display_flush(m_connection->display());
226 QCoreApplication::processEvents();
227 QCOMPARE(serverParentSurface->below().count(), 0);
228 QCOMPARE(serverParentSurface->above().count(), 0);
229}
230
231void TestSubSurface::testMode()
232{
233 using namespace KWin;
234 // create two Surface
235 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
236 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface());
237
238 QSignalSpy subSurfaceCreatedSpy(m_subcompositorInterface, &KWin::SubCompositorInterface::subSurfaceCreated);
239
240 // create the SubSurface for surface of parent
241 std::unique_ptr<KWayland::Client::SubSurface> subSurface(m_subCompositor->createSubSurface(surface.get(), parent.get()));
242 QVERIFY(subSurfaceCreatedSpy.wait());
243 SubSurfaceInterface *serverSubSurface = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>();
244 QVERIFY(serverSubSurface);
245
246 // both client and server subsurface should be in synchronized mode
247 QCOMPARE(subSurface->mode(), KWayland::Client::SubSurface::Mode::Synchronized);
248 QCOMPARE(serverSubSurface->mode(), SubSurfaceInterface::Mode::Synchronized);
249
250 // verify that we can change to desynchronized
251 QSignalSpy modeChangedSpy(serverSubSurface, &KWin::SubSurfaceInterface::modeChanged);
252
253 subSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
254 QCOMPARE(subSurface->mode(), KWayland::Client::SubSurface::Mode::Desynchronized);
255
256 QVERIFY(modeChangedSpy.wait());
257 QCOMPARE(modeChangedSpy.first().first().value<KWin::SubSurfaceInterface::Mode>(), SubSurfaceInterface::Mode::Desynchronized);
258 QCOMPARE(serverSubSurface->mode(), SubSurfaceInterface::Mode::Desynchronized);
259
260 // setting the same again won't change
261 subSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
262 QCOMPARE(subSurface->mode(), KWayland::Client::SubSurface::Mode::Desynchronized);
263 // not testing the signal, we do that after changing to synchronized
264
265 // and change back to synchronized
266 subSurface->setMode(KWayland::Client::SubSurface::Mode::Synchronized);
267 QCOMPARE(subSurface->mode(), KWayland::Client::SubSurface::Mode::Synchronized);
268
269 QVERIFY(modeChangedSpy.wait());
270 QCOMPARE(modeChangedSpy.count(), 2);
271 QCOMPARE(modeChangedSpy.first().first().value<KWin::SubSurfaceInterface::Mode>(), SubSurfaceInterface::Mode::Desynchronized);
272 QCOMPARE(modeChangedSpy.last().first().value<KWin::SubSurfaceInterface::Mode>(), SubSurfaceInterface::Mode::Synchronized);
273 QCOMPARE(serverSubSurface->mode(), SubSurfaceInterface::Mode::Synchronized);
274}
275
276void TestSubSurface::testPosition_data()
277{
278 QTest::addColumn<KWayland::Client::SubSurface::Mode>("commitMode");
279
280 QTest::addRow("sync") << KWayland::Client::SubSurface::Mode::Synchronized;
281 QTest::addRow("desync") << KWayland::Client::SubSurface::Mode::Desynchronized;
282}
283
284void TestSubSurface::testPosition()
285{
286 using namespace KWin;
287 // create two Surface
288 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
289 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface());
290
291 QSignalSpy subSurfaceCreatedSpy(m_subcompositorInterface, &KWin::SubCompositorInterface::subSurfaceCreated);
292
293 // create the SubSurface for surface of parent
294 std::unique_ptr<KWayland::Client::SubSurface> subSurface(m_subCompositor->createSubSurface(surface.get(), parent.get()));
295 QVERIFY(subSurfaceCreatedSpy.wait());
296 SubSurfaceInterface *serverSubSurface = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>();
297 QVERIFY(serverSubSurface);
298
299 // put the subsurface in the desired commit mode
300 QFETCH(KWayland::Client::SubSurface::Mode, commitMode);
301 subSurface->setMode(commitMode);
302
303 // both client and server should have a default position
304 QCOMPARE(subSurface->position(), QPoint());
305 QCOMPARE(serverSubSurface->position(), QPoint());
306
307 QSignalSpy positionChangedSpy(serverSubSurface, &KWin::SubSurfaceInterface::positionChanged);
308
309 // changing the position should not trigger a direct update on server side
310 subSurface->setPosition(QPoint(10, 20));
311 QCOMPARE(subSurface->position(), QPoint(10, 20));
312 // ensure it's processed on server side
313 wl_display_flush(m_connection->display());
314 QCoreApplication::processEvents();
315 QCOMPARE(serverSubSurface->position(), QPoint());
316 // changing once more
317 subSurface->setPosition(QPoint(20, 30));
318 QCOMPARE(subSurface->position(), QPoint(20, 30));
319 // ensure it's processed on server side
320 wl_display_flush(m_connection->display());
321 QCoreApplication::processEvents();
322 QCOMPARE(serverSubSurface->position(), QPoint());
323
324 // committing the parent surface should update the position
325 QSignalSpy parentCommittedSpy(serverSubSurface->parentSurface(), &SurfaceInterface::committed);
326 parent->commit(KWayland::Client::Surface::CommitFlag::None);
327 QVERIFY(parentCommittedSpy.wait());
328 QCOMPARE(positionChangedSpy.count(), 1);
329 QCOMPARE(positionChangedSpy.first().first().toPoint(), QPoint(20, 30));
330 QCOMPARE(serverSubSurface->position(), QPoint(20, 30));
331}
332
333void TestSubSurface::testPlaceAbove()
334{
335 using namespace KWin;
336 // create needed Surfaces (one parent, three client
337 std::unique_ptr<KWayland::Client::Surface> surface1(m_compositor->createSurface());
338 std::unique_ptr<KWayland::Client::Surface> surface2(m_compositor->createSurface());
339 std::unique_ptr<KWayland::Client::Surface> surface3(m_compositor->createSurface());
340 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface());
341
342 QSignalSpy subSurfaceCreatedSpy(m_subcompositorInterface, &KWin::SubCompositorInterface::subSurfaceCreated);
343
344 // create the SubSurfaces for surface of parent
345 std::unique_ptr<KWayland::Client::SubSurface> subSurface1(m_subCompositor->createSubSurface(surface1.get(), parent.get()));
346 QVERIFY(subSurfaceCreatedSpy.wait());
347 SubSurfaceInterface *serverSubSurface1 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>();
348 QVERIFY(serverSubSurface1);
349 subSurfaceCreatedSpy.clear();
350 std::unique_ptr<KWayland::Client::SubSurface> subSurface2(m_subCompositor->createSubSurface(surface2.get(), parent.get()));
351 QVERIFY(subSurfaceCreatedSpy.wait());
352 SubSurfaceInterface *serverSubSurface2 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>();
353 QVERIFY(serverSubSurface2);
354 subSurfaceCreatedSpy.clear();
355 std::unique_ptr<KWayland::Client::SubSurface> subSurface3(m_subCompositor->createSubSurface(surface3.get(), parent.get()));
356 QVERIFY(subSurfaceCreatedSpy.wait());
357 SubSurfaceInterface *serverSubSurface3 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>();
358 QVERIFY(serverSubSurface3);
359 subSurfaceCreatedSpy.clear();
360
361 // so far the stacking order should still be empty
362 QVERIFY(serverSubSurface1->parentSurface()->below().isEmpty());
363 QEXPECT_FAIL("", "Incorrect adding of child windows to workaround QtWayland behavior", Continue);
364 QVERIFY(serverSubSurface1->parentSurface()->above().isEmpty());
365
366 // committing the parent should create the stacking order
367 parent->commit(KWayland::Client::Surface::CommitFlag::None);
368 // ensure it's processed on server side
369 wl_display_flush(m_connection->display());
370 QCoreApplication::processEvents();
371 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 0);
372 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
373 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1);
374 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2);
375 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface3);
376
377 // raising subsurface1 should place it to top of stack
378 subSurface1->placeAbove(subSurface3.get());
379 // ensure it's processed on server side
380 wl_display_flush(m_connection->display());
381 QCoreApplication::processEvents();
382 // but as long as parent is not committed it shouldn't change on server side
383 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1);
384 // after commit it's changed
385 parent->commit(KWayland::Client::Surface::CommitFlag::None);
386 wl_display_flush(m_connection->display());
387 QCoreApplication::processEvents();
388 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
389 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2);
390 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface3);
391 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1);
392
393 // try placing 3 above 1, should result in 2, 1, 3
394 subSurface3->placeAbove(subSurface1.get());
395 parent->commit(KWayland::Client::Surface::CommitFlag::None);
396 wl_display_flush(m_connection->display());
397 QCoreApplication::processEvents();
398 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
399 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2);
400 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface1);
401 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface3);
402
403 // try placing 3 above 2, should result in 2, 3, 1
404 subSurface3->placeAbove(subSurface2.get());
405 parent->commit(KWayland::Client::Surface::CommitFlag::None);
406 wl_display_flush(m_connection->display());
407 QCoreApplication::processEvents();
408 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
409 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2);
410 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface3);
411 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1);
412
413 // try placing 1 above 3 - shouldn't change
414 subSurface1->placeAbove(subSurface3.get());
415 parent->commit(KWayland::Client::Surface::CommitFlag::None);
416 wl_display_flush(m_connection->display());
417 QCoreApplication::processEvents();
418 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
419 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2);
420 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface3);
421 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1);
422
423 // and 2 above 3 - > 3, 2, 1
424 subSurface2->placeAbove(subSurface3.get());
425 parent->commit(KWayland::Client::Surface::CommitFlag::None);
426 wl_display_flush(m_connection->display());
427 QCoreApplication::processEvents();
428 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
429 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface3);
430 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2);
431 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1);
432}
433
434void TestSubSurface::testPlaceBelow()
435{
436 using namespace KWin;
437 // create needed Surfaces (one parent, three client
438 std::unique_ptr<KWayland::Client::Surface> surface1(m_compositor->createSurface());
439 std::unique_ptr<KWayland::Client::Surface> surface2(m_compositor->createSurface());
440 std::unique_ptr<KWayland::Client::Surface> surface3(m_compositor->createSurface());
441 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface());
442
443 QSignalSpy subSurfaceCreatedSpy(m_subcompositorInterface, &KWin::SubCompositorInterface::subSurfaceCreated);
444
445 // create the SubSurfaces for surface of parent
446 std::unique_ptr<KWayland::Client::SubSurface> subSurface1(m_subCompositor->createSubSurface(surface1.get(), parent.get()));
447 QVERIFY(subSurfaceCreatedSpy.wait());
448 SubSurfaceInterface *serverSubSurface1 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>();
449 QVERIFY(serverSubSurface1);
450 subSurfaceCreatedSpy.clear();
451 std::unique_ptr<KWayland::Client::SubSurface> subSurface2(m_subCompositor->createSubSurface(surface2.get(), parent.get()));
452 QVERIFY(subSurfaceCreatedSpy.wait());
453 SubSurfaceInterface *serverSubSurface2 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>();
454 QVERIFY(serverSubSurface2);
455 subSurfaceCreatedSpy.clear();
456 std::unique_ptr<KWayland::Client::SubSurface> subSurface3(m_subCompositor->createSubSurface(surface3.get(), parent.get()));
457 QVERIFY(subSurfaceCreatedSpy.wait());
458 SubSurfaceInterface *serverSubSurface3 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>();
459 QVERIFY(serverSubSurface3);
460 subSurfaceCreatedSpy.clear();
461
462 // so far the stacking order should still be empty
463 QVERIFY(serverSubSurface1->parentSurface()->below().isEmpty());
464 QEXPECT_FAIL("", "Incorrect adding of child windows to workaround QtWayland behavior", Continue);
465 QVERIFY(serverSubSurface1->parentSurface()->above().isEmpty());
466
467 // committing the parent should create the stacking order
468 parent->commit(KWayland::Client::Surface::CommitFlag::None);
469 // ensure it's processed on server side
470 wl_display_flush(m_connection->display());
471 QCoreApplication::processEvents();
472 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
473 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1);
474 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2);
475 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface3);
476
477 // lowering subsurface3 should place it to the bottom of stack
478 subSurface3->lower();
479 // ensure it's processed on server side
480 wl_display_flush(m_connection->display());
481 QCoreApplication::processEvents();
482 // but as long as parent is not committed it shouldn't change on server side
483 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1);
484 // after commit it's changed
485 parent->commit(KWayland::Client::Surface::CommitFlag::None);
486 wl_display_flush(m_connection->display());
487 QCoreApplication::processEvents();
488 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 1);
489 QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface3);
490 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 2);
491 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1);
492 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2);
493
494 // place 1 below 3 -> 1, 3, 2
495 subSurface1->placeBelow(subSurface3.get());
496 parent->commit(KWayland::Client::Surface::CommitFlag::None);
497 wl_display_flush(m_connection->display());
498 QCoreApplication::processEvents();
499 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 2);
500 QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface1);
501 QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface3);
502 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 1);
503 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2);
504
505 // 2 below 3 -> 1, 2, 3
506 subSurface2->placeBelow(subSurface3.get());
507 parent->commit(KWayland::Client::Surface::CommitFlag::None);
508 wl_display_flush(m_connection->display());
509 QCoreApplication::processEvents();
510 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 3);
511 QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface1);
512 QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface2);
513 QCOMPARE(serverSubSurface1->parentSurface()->below().at(2), serverSubSurface3);
514 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 0);
515
516 // 1 below 2 -> shouldn't change
517 subSurface1->placeBelow(subSurface2.get());
518 parent->commit(KWayland::Client::Surface::CommitFlag::None);
519 wl_display_flush(m_connection->display());
520 QCoreApplication::processEvents();
521 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 3);
522 QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface1);
523 QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface2);
524 QCOMPARE(serverSubSurface1->parentSurface()->below().at(2), serverSubSurface3);
525 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 0);
526
527 // and 3 below 1 -> 3, 1, 2
528 subSurface3->placeBelow(subSurface1.get());
529 parent->commit(KWayland::Client::Surface::CommitFlag::None);
530 wl_display_flush(m_connection->display());
531 QCoreApplication::processEvents();
532 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 3);
533 QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface3);
534 QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface1);
535 QCOMPARE(serverSubSurface1->parentSurface()->below().at(2), serverSubSurface2);
536 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 0);
537}
538
539void TestSubSurface::testSyncMode()
540{
541 // this test verifies that state is only applied when the parent surface commits its pending state
542 using namespace KWin;
543
544 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
545
546 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
547 QVERIFY(surfaceCreatedSpy.wait());
548 auto childSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
549 QVERIFY(childSurface);
550
551 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface());
552 QVERIFY(surfaceCreatedSpy.wait());
553 auto parentSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
554 QVERIFY(parentSurface);
555 // create subSurface for surface of parent
556 std::unique_ptr<KWayland::Client::SubSurface> subSurface(m_subCompositor->createSubSurface(surface.get(), parent.get()));
557
558 // let's damage the child surface
559 QSignalSpy childDamagedSpy(childSurface, &SurfaceInterface::damaged);
560
561 QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied);
562 image.fill(Qt::black);
563 surface->attachBuffer(m_shm->createBuffer(image));
564 surface->damage(QRect(0, 0, 200, 200));
565 surface->commit();
566
567 // state should be applied when the parent surface's state gets applied
568 QVERIFY(!childDamagedSpy.wait(100));
569 QVERIFY(!childSurface->buffer());
570
571 QVERIFY(!childSurface->isMapped());
572 QVERIFY(!parentSurface->isMapped());
573
574 QImage image2(QSize(400, 400), QImage::Format_ARGB32_Premultiplied);
575 image2.fill(Qt::red);
576 parent->attachBuffer(m_shm->createBuffer(image2));
577 parent->damage(QRect(0, 0, 400, 400));
578 parent->commit();
579 QVERIFY(childDamagedSpy.wait());
580 QCOMPARE(childDamagedSpy.count(), 1);
581 QVERIFY(childSurface->isMapped());
582 QVERIFY(parentSurface->isMapped());
583}
584
585void TestSubSurface::testDeSyncMode()
586{
587 // this test verifies that state gets applied immediately in desync mode
588 using namespace KWin;
589
590 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
591
592 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
593 QVERIFY(surfaceCreatedSpy.wait());
594 auto childSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
595 QVERIFY(childSurface);
596
597 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface());
598 QVERIFY(surfaceCreatedSpy.wait());
599 auto parentSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
600 QVERIFY(parentSurface);
601 // create subSurface for surface of parent
602 std::unique_ptr<KWayland::Client::SubSurface> subSurface(m_subCompositor->createSubSurface(surface.get(), parent.get()));
603
604 // let's damage the child surface
605 QSignalSpy childDamagedSpy(childSurface, &SurfaceInterface::damaged);
606
607 QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied);
608 image.fill(Qt::black);
609 surface->attachBuffer(m_shm->createBuffer(image));
610 surface->damage(QRect(0, 0, 200, 200));
611 surface->commit(KWayland::Client::Surface::CommitFlag::None);
612
613 // state should be applied when the parent surface's state gets applied or when the subsurface switches to desync
614 QVERIFY(!childDamagedSpy.wait(100));
615 QVERIFY(!childSurface->isMapped());
616 QVERIFY(!parentSurface->isMapped());
617
618 // setting to desync should apply the state directly
619 subSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
620 QVERIFY(childDamagedSpy.wait());
621 QVERIFY(!childSurface->isMapped());
622 QVERIFY(!parentSurface->isMapped());
623
624 // and damaging again, should directly be applied
625 image.fill(Qt::red);
626 surface->attachBuffer(m_shm->createBuffer(image));
627 surface->damage(QRect(0, 0, 200, 200));
628 surface->commit(KWayland::Client::Surface::CommitFlag::None);
629 QVERIFY(childDamagedSpy.wait());
630}
631
632void TestSubSurface::testMainSurfaceFromTree()
633{
634 // this test verifies that in a tree of surfaces every surface has the same main surface
635 using namespace KWin;
636 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
637
638 std::unique_ptr<KWayland::Client::Surface> parentSurface(m_compositor->createSurface());
639 QVERIFY(surfaceCreatedSpy.wait());
640 auto parentServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
641 QVERIFY(parentServerSurface);
642 std::unique_ptr<KWayland::Client::Surface> childLevel1Surface(m_compositor->createSurface());
643 QVERIFY(surfaceCreatedSpy.wait());
644 auto childLevel1ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
645 QVERIFY(childLevel1ServerSurface);
646 std::unique_ptr<KWayland::Client::Surface> childLevel2Surface(m_compositor->createSurface());
647 QVERIFY(surfaceCreatedSpy.wait());
648 auto childLevel2ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
649 QVERIFY(childLevel2ServerSurface);
650 std::unique_ptr<KWayland::Client::Surface> childLevel3Surface(m_compositor->createSurface());
651 QVERIFY(surfaceCreatedSpy.wait());
652 auto childLevel3ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
653 QVERIFY(childLevel3ServerSurface);
654
655 m_subCompositor->createSubSurface(childLevel1Surface.get(), parentSurface.get());
656 m_subCompositor->createSubSurface(childLevel2Surface.get(), childLevel1Surface.get());
657 m_subCompositor->createSubSurface(childLevel3Surface.get(), childLevel2Surface.get());
658
659 QSignalSpy parentCommittedSpy(parentServerSurface, &SurfaceInterface::committed);
660 parentSurface->commit(KWayland::Client::Surface::CommitFlag::None);
661 QVERIFY(parentCommittedSpy.wait());
662
663 QCOMPARE(parentServerSurface->below().count(), 0);
664 QCOMPARE(parentServerSurface->above().count(), 1);
665 auto child = parentServerSurface->above().constFirst();
666 QCOMPARE(child->parentSurface(), parentServerSurface);
667 QCOMPARE(child->mainSurface(), parentServerSurface);
668 QCOMPARE(child->surface()->below().count(), 0);
669 QCOMPARE(child->surface()->above().count(), 1);
670 auto child2 = child->surface()->above().constFirst();
671 QCOMPARE(child2->parentSurface(), child->surface());
672 QCOMPARE(child2->mainSurface(), parentServerSurface);
673 QCOMPARE(child2->surface()->below().count(), 0);
674 QCOMPARE(child2->surface()->above().count(), 1);
675 auto child3 = child2->surface()->above().constFirst();
676 QCOMPARE(child3->parentSurface(), child2->surface());
677 QCOMPARE(child3->mainSurface(), parentServerSurface);
678 QCOMPARE(child3->surface()->below().count(), 0);
679 QCOMPARE(child3->surface()->above().count(), 0);
680}
681
682void TestSubSurface::testRemoveSurface()
683{
684 // this test verifies that removing the surface also removes the sub-surface from the parent
685 using namespace KWin;
686
687 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
688
689 std::unique_ptr<KWayland::Client::Surface> parentSurface(m_compositor->createSurface());
690 QVERIFY(surfaceCreatedSpy.wait());
691 auto parentServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
692 QVERIFY(parentServerSurface);
693 std::unique_ptr<KWayland::Client::Surface> childSurface(m_compositor->createSurface());
694 QVERIFY(surfaceCreatedSpy.wait());
695 auto childServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
696 QVERIFY(childServerSurface);
697
698 QSignalSpy childrenChangedSpy(parentServerSurface, &SurfaceInterface::childSubSurfacesChanged);
699
700 m_subCompositor->createSubSurface(childSurface.get(), parentSurface.get());
701 parentSurface->commit(KWayland::Client::Surface::CommitFlag::None);
702 QVERIFY(childrenChangedSpy.wait());
703
704 QCOMPARE(parentServerSurface->below().count(), 0);
705 QCOMPARE(parentServerSurface->above().count(), 1);
706
707 // destroy surface, takes place immediately
708 childSurface.reset();
709 QVERIFY(childrenChangedSpy.wait());
710 QCOMPARE(parentServerSurface->below().count(), 0);
711 QCOMPARE(parentServerSurface->above().count(), 0);
712}
713
714void TestSubSurface::testMappingOfSurfaceTree()
715{
716 // this test verifies mapping and unmapping of a sub-surface tree
717 using namespace KWin;
718 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
719
720 std::unique_ptr<KWayland::Client::Surface> parentSurface(m_compositor->createSurface());
721 QVERIFY(surfaceCreatedSpy.wait());
722 auto parentServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
723 QVERIFY(parentServerSurface);
724 std::unique_ptr<KWayland::Client::Surface> childLevel1Surface(m_compositor->createSurface());
725 QVERIFY(surfaceCreatedSpy.wait());
726 auto childLevel1ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
727 QVERIFY(childLevel1ServerSurface);
728 std::unique_ptr<KWayland::Client::Surface> childLevel2Surface(m_compositor->createSurface());
729 QVERIFY(surfaceCreatedSpy.wait());
730 auto childLevel2ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
731 QVERIFY(childLevel2ServerSurface);
732 std::unique_ptr<KWayland::Client::Surface> childLevel3Surface(m_compositor->createSurface());
733 QVERIFY(surfaceCreatedSpy.wait());
734 auto childLevel3ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>();
735 QVERIFY(childLevel3ServerSurface);
736
737 auto subSurfaceLevel1 = m_subCompositor->createSubSurface(childLevel1Surface.get(), parentSurface.get());
738 auto subSurfaceLevel2 = m_subCompositor->createSubSurface(childLevel2Surface.get(), childLevel1Surface.get());
739 auto subSurfaceLevel3 = m_subCompositor->createSubSurface(childLevel3Surface.get(), childLevel2Surface.get());
740
741 QSignalSpy parentCommittedSpy(parentServerSurface, &SurfaceInterface::committed);
742 parentSurface->commit(KWayland::Client::Surface::CommitFlag::None);
743 QVERIFY(parentCommittedSpy.wait());
744
745 QCOMPARE(parentServerSurface->below().count(), 0);
746 QCOMPARE(parentServerSurface->above().count(), 1);
747 auto child = parentServerSurface->above().constFirst();
748 QCOMPARE(child->surface()->below().count(), 0);
749 QCOMPARE(child->surface()->above().count(), 1);
750 auto child2 = child->surface()->above().constFirst();
751 QCOMPARE(child2->surface()->below().count(), 0);
752 QCOMPARE(child2->surface()->above().count(), 1);
753 auto child3 = child2->surface()->above().constFirst();
754 QCOMPARE(child3->parentSurface(), child2->surface());
755 QCOMPARE(child3->mainSurface(), parentServerSurface);
756 QCOMPARE(child3->surface()->below().count(), 0);
757 QCOMPARE(child3->surface()->above().count(), 0);
758
759 // so far no surface is mapped
760 QVERIFY(!parentServerSurface->isMapped());
761 QVERIFY(!child->surface()->isMapped());
762 QVERIFY(!child2->surface()->isMapped());
763 QVERIFY(!child3->surface()->isMapped());
764
765 // first set all subsurfaces to desync, to simplify
766 subSurfaceLevel1->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
767 subSurfaceLevel2->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
768 subSurfaceLevel3->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
769
770 // first map the child, should not map it
771 QSignalSpy child3DamageSpy(child3->surface(), &SurfaceInterface::damaged);
772 QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied);
773 image.fill(Qt::black);
774 childLevel3Surface->attachBuffer(m_shm->createBuffer(image));
775 childLevel3Surface->damage(QRect(0, 0, 200, 200));
776 childLevel3Surface->commit(KWayland::Client::Surface::CommitFlag::None);
777 QVERIFY(child3DamageSpy.wait());
778 QVERIFY(child3->surface()->buffer());
779 QVERIFY(!child3->surface()->isMapped());
780
781 // let's map the top level
782 QSignalSpy parentSpy(parentServerSurface, &SurfaceInterface::damaged);
783 parentSurface->attachBuffer(m_shm->createBuffer(image));
784 parentSurface->damage(QRect(0, 0, 200, 200));
785 parentSurface->commit(KWayland::Client::Surface::CommitFlag::None);
786 QVERIFY(parentSpy.wait());
787 QVERIFY(parentServerSurface->isMapped());
788 // children should not yet be mapped
789 QVERIFY(!child->surface()->isMapped());
790 QVERIFY(!child2->surface()->isMapped());
791 QVERIFY(!child3->surface()->isMapped());
792
793 // next level
794 QSignalSpy child2DamageSpy(child2->surface(), &SurfaceInterface::damaged);
795 childLevel2Surface->attachBuffer(m_shm->createBuffer(image));
796 childLevel2Surface->damage(QRect(0, 0, 200, 200));
797 childLevel2Surface->commit(KWayland::Client::Surface::CommitFlag::None);
798 QVERIFY(child2DamageSpy.wait());
799 QVERIFY(parentServerSurface->isMapped());
800 // children should not yet be mapped
801 QVERIFY(!child->surface()->isMapped());
802 QVERIFY(!child2->surface()->isMapped());
803 QVERIFY(!child3->surface()->isMapped());
804
805 // last but not least the first child level, which should map all our subsurfaces
806 QSignalSpy child1DamageSpy(child->surface(), &SurfaceInterface::damaged);
807 childLevel1Surface->attachBuffer(m_shm->createBuffer(image));
808 childLevel1Surface->damage(QRect(0, 0, 200, 200));
809 childLevel1Surface->commit(KWayland::Client::Surface::CommitFlag::None);
810 QVERIFY(child1DamageSpy.wait());
811
812 // everything is mapped
813 QVERIFY(parentServerSurface->isMapped());
814 QVERIFY(child->surface()->isMapped());
815 QVERIFY(child2->surface()->isMapped());
816 QVERIFY(child3->surface()->isMapped());
817
818 // unmapping a parent should unmap the complete tree
819 QSignalSpy unmappedSpy(child->surface(), &SurfaceInterface::unmapped);
820 childLevel1Surface->attachBuffer(KWayland::Client::Buffer::Ptr());
821 childLevel1Surface->damage(QRect(0, 0, 200, 200));
822 childLevel1Surface->commit(KWayland::Client::Surface::CommitFlag::None);
823 QVERIFY(unmappedSpy.wait());
824
825 QVERIFY(parentServerSurface->isMapped());
826 QVERIFY(!child->surface()->isMapped());
827 QVERIFY(!child2->surface()->isMapped());
828 QVERIFY(!child3->surface()->isMapped());
829}
830
831void TestSubSurface::testSurfaceAt()
832{
833 // this test verifies that the correct surface is picked in a sub-surface tree
834 using namespace KWin;
835 // first create a parent surface and map it
836 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
837 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface());
838 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
839 image.fill(Qt::red);
840 parent->attachBuffer(m_shm->createBuffer(image));
841 parent->damage(QRect(0, 0, 100, 100));
842 parent->commit(KWayland::Client::Surface::CommitFlag::None);
843 QVERIFY(serverSurfaceCreated.wait());
844 SurfaceInterface *parentServerSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>();
845
846 // directChild1 occupies the top-left quarter of the parent surface
847 QImage directImage(QSize(50, 50), QImage::Format_ARGB32_Premultiplied);
848 std::unique_ptr<KWayland::Client::Surface> directChild1(m_compositor->createSurface());
849 directChild1->attachBuffer(m_shm->createBuffer(directImage));
850 directChild1->damage(QRect(0, 0, 50, 50));
851 directChild1->commit(KWayland::Client::Surface::CommitFlag::None);
852 QVERIFY(serverSurfaceCreated.wait());
853 SurfaceInterface *directChild1ServerSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>();
854 QVERIFY(directChild1ServerSurface);
855
856 // directChild2 occupies the bottom-right quarter of the parent surface
857 std::unique_ptr<KWayland::Client::Surface> directChild2(m_compositor->createSurface());
858 directChild2->attachBuffer(m_shm->createBuffer(directImage));
859 directChild2->damage(QRect(0, 0, 50, 50));
860 directChild2->commit(KWayland::Client::Surface::CommitFlag::None);
861 QVERIFY(serverSurfaceCreated.wait());
862 SurfaceInterface *directChild2ServerSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>();
863 QVERIFY(directChild2ServerSurface);
864
865 // create the sub surfaces for them
866 std::unique_ptr<KWayland::Client::SubSurface> directChild1SubSurface(m_subCompositor->createSubSurface(directChild1.get(), parent.get()));
867 directChild1SubSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
868 std::unique_ptr<KWayland::Client::SubSurface> directChild2SubSurface(m_subCompositor->createSubSurface(directChild2.get(), parent.get()));
869 directChild2SubSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
870 directChild2SubSurface->setPosition(QPoint(50, 50));
871
872 // unset input regions for direct children
873 QSignalSpy directChild1CommittedSpy(directChild1ServerSurface, &SurfaceInterface::committed);
874 directChild1->setInputRegion(m_compositor->createRegion(QRegion()).get());
875 directChild1->commit(KWayland::Client::Surface::CommitFlag::None);
876 parent->commit(KWayland::Client::Surface::CommitFlag::None);
877 QVERIFY(directChild1CommittedSpy.wait());
878
879 QSignalSpy directChild2CommittedSpy(directChild2ServerSurface, &SurfaceInterface::committed);
880 directChild2->setInputRegion(m_compositor->createRegion(QRegion()).get());
881 directChild2->commit(KWayland::Client::Surface::CommitFlag::None);
882 parent->commit(KWayland::Client::Surface::CommitFlag::None);
883 QVERIFY(directChild2CommittedSpy.wait());
884
885 // each of the children gets a child
886 std::unique_ptr<KWayland::Client::Surface> childFor1(m_compositor->createSurface());
887 QVERIFY(serverSurfaceCreated.wait());
888 SurfaceInterface *childFor1ServerSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>();
889 std::unique_ptr<KWayland::Client::Surface> childFor2(m_compositor->createSurface());
890 QVERIFY(serverSurfaceCreated.wait());
891 SurfaceInterface *childFor2ServerSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>();
892
893 // create sub surfaces for them
894 std::unique_ptr<KWayland::Client::SubSurface> childFor1SubSurface(m_subCompositor->createSubSurface(childFor1.get(), directChild1.get()));
895 childFor1SubSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
896 std::unique_ptr<KWayland::Client::SubSurface> childFor2SubSurface(m_subCompositor->createSubSurface(childFor2.get(), directChild2.get()));
897 childFor2SubSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
898
899 // now let's render both grand children
900 QImage partImage(QSize(50, 50), QImage::Format_ARGB32_Premultiplied);
901 partImage.fill(Qt::green);
902 childFor1->attachBuffer(m_shm->createBuffer(partImage));
903 childFor1->damage(QRect(0, 0, 50, 50));
904 childFor1->commit(KWayland::Client::Surface::CommitFlag::None);
905 partImage.fill(Qt::blue);
906
907 QSignalSpy childFor2CommittedSpy(childFor2ServerSurface, &SurfaceInterface::committed);
908 childFor2->attachBuffer(m_shm->createBuffer(partImage));
909 // child for 2's input region is subdivided into quadrants, with input mask on the top left and bottom right
910 QRegion region;
911 region += QRect(0, 0, 25, 25);
912 region += QRect(25, 25, 25, 25);
913 childFor2->setInputRegion(m_compositor->createRegion(region).get());
914 childFor2->damage(QRect(0, 0, 50, 50));
915 childFor2->commit(KWayland::Client::Surface::CommitFlag::None);
916 QVERIFY(childFor2CommittedSpy.wait());
917
918 QCOMPARE(directChild1ServerSurface->subSurface()->parentSurface(), parentServerSurface);
919 QCOMPARE(directChild2ServerSurface->subSurface()->parentSurface(), parentServerSurface);
920 QCOMPARE(childFor1ServerSurface->subSurface()->parentSurface(), directChild1ServerSurface);
921 QCOMPARE(childFor2ServerSurface->subSurface()->parentSurface(), directChild2ServerSurface);
922
923 // now let's test a few positions
924 QCOMPARE(parentServerSurface->surfaceAt(QPointF(0, 0)), childFor1ServerSurface);
925 QCOMPARE(parentServerSurface->surfaceAt(QPointF(49, 49)), childFor1ServerSurface);
926 QCOMPARE(parentServerSurface->surfaceAt(QPointF(50, 50)), childFor2ServerSurface);
927 QCOMPARE(parentServerSurface->surfaceAt(QPointF(99, 99)), childFor2ServerSurface);
928 QCOMPARE(parentServerSurface->surfaceAt(QPointF(99, 50)), childFor2ServerSurface);
929 QCOMPARE(parentServerSurface->surfaceAt(QPointF(50, 99)), childFor2ServerSurface);
930 QCOMPARE(parentServerSurface->surfaceAt(QPointF(25, 75)), parentServerSurface);
931 QCOMPARE(parentServerSurface->surfaceAt(QPointF(75, 25)), parentServerSurface);
932
933 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(0, 0)), childFor1ServerSurface);
934 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(49, 49)), childFor1ServerSurface);
935 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(50, 50)), childFor2ServerSurface);
936 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(99, 99)), childFor2ServerSurface);
937 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(99, 50)), parentServerSurface);
938 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(50, 99)), parentServerSurface);
939 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(25, 75)), parentServerSurface);
940 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(75, 25)), parentServerSurface);
941
942 // outside the geometries should be no surface
943 QVERIFY(!parentServerSurface->surfaceAt(QPointF(-1, -1)));
944 QVERIFY(!parentServerSurface->surfaceAt(QPointF(101, 101)));
945
946 // on the surface edge right/bottom edges should not trigger as contained
947 QCOMPARE(parentServerSurface->surfaceAt(QPointF(50, 25)), parentServerSurface);
948 QCOMPARE(parentServerSurface->surfaceAt(QPointF(25, 50)), parentServerSurface);
949 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(50, 25)), parentServerSurface);
950 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(25, 50)), parentServerSurface);
951}
952
953void TestSubSurface::testDestroyAttachedBuffer()
954{
955 // this test verifies that destroying of a buffer attached to a sub-surface works
956 using namespace KWin;
957 // create surface
958 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
959 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface());
960 QVERIFY(serverSurfaceCreated.wait());
961 std::unique_ptr<KWayland::Client::Surface> child(m_compositor->createSurface());
962 QVERIFY(serverSurfaceCreated.wait());
963 SurfaceInterface *serverChildSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>();
964 // create sub-surface
965 m_subCompositor->createSubSurface(child.get(), parent.get());
966
967 // let's damage this surface, will be in sub-surface pending state
968 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
969 image.fill(Qt::red);
970 child->attachBuffer(m_shm->createBuffer(image));
971 child->damage(QRect(0, 0, 100, 100));
972 child->commit(KWayland::Client::Surface::CommitFlag::None);
973 m_connection->flush();
974
975 // Let's try to destroy it
976 QSignalSpy destroySpy(serverChildSurface, &QObject::destroyed);
977 delete m_shm;
978 m_shm = nullptr;
979 child.reset();
980 QVERIFY(destroySpy.wait());
981}
982
983void TestSubSurface::testDestroyParentSurface()
984{
985 // this test verifies that destroying a parent surface does not create problems
986 // see BUG 389231
987 using namespace KWin;
988 // create surface
989 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
990 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface());
991 QVERIFY(serverSurfaceCreated.wait());
992 SurfaceInterface *serverParentSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>();
993 std::unique_ptr<KWayland::Client::Surface> child(m_compositor->createSurface());
994 QVERIFY(serverSurfaceCreated.wait());
995 SurfaceInterface *serverChildSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>();
996 std::unique_ptr<KWayland::Client::Surface> grandChild(m_compositor->createSurface());
997 QVERIFY(serverSurfaceCreated.wait());
998 SurfaceInterface *serverGrandChildSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>();
999 // create sub-surface in desynchronized mode as Qt uses them
1000 auto sub1 = m_subCompositor->createSubSurface(child.get(), parent.get());
1001 sub1->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
1002 auto sub2 = m_subCompositor->createSubSurface(grandChild.get(), child.get());
1003 sub2->setMode(KWayland::Client::SubSurface::Mode::Desynchronized);
1004
1005 // let's damage this surface
1006 // and at the same time delete the parent surface
1007 parent.reset();
1008 QSignalSpy parentDestroyedSpy(serverParentSurface, &QObject::destroyed);
1009 QVERIFY(parentDestroyedSpy.wait());
1010 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
1011 image.fill(Qt::red);
1012 grandChild->attachBuffer(m_shm->createBuffer(image));
1013 grandChild->damage(QRect(0, 0, 100, 100));
1014 grandChild->commit(KWayland::Client::Surface::CommitFlag::None);
1015 QSignalSpy damagedSpy(serverGrandChildSurface, &SurfaceInterface::damaged);
1016 QVERIFY(damagedSpy.wait());
1017
1018 // Let's try to destroy it
1019 QSignalSpy destroySpy(serverChildSurface, &QObject::destroyed);
1020 child.reset();
1021 QVERIFY(destroySpy.wait());
1022}
1023
1024QTEST_GUILESS_MAIN(TestSubSurface)
1025#include "test_wayland_subsurface.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
void subSurfaceCreated(KWin::SubSurfaceInterface *subsurface)
SurfaceInterface * parentSurface() const
SurfaceInterface * surface() const
void positionChanged(const QPoint &position)
void modeChanged(KWin::SubSurfaceInterface::Mode mode)
SurfaceInterface * mainSurface() const
Resource representing a wl_surface.
Definition surface.h:80
SurfaceInterface * surfaceAt(const QPointF &position)
Definition surface.cpp:953
SubSurfaceInterface * subSurface() const
Definition surface.cpp:845
QList< SubSurfaceInterface * > above() const
Definition surface.cpp:840
QList< SubSurfaceInterface * > below() const
Definition surface.cpp:835
SurfaceInterface * inputSurfaceAt(const QPointF &position)
Definition surface.cpp:982
TestSubSurface(QObject *parent=nullptr)
Q_DECLARE_METATYPE(KWin::SwitchEvent::State)
KWayland::Client::Registry * registry