1 /********************************************************************
2 Copyright 2014  Martin Gräßlin <mgraesslin@kde.org>
3 
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11 
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 Lesser General Public License for more details.
16 
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library.  If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
20 #include <QtTest>
21 
22 #include "../../src/client/compositor.h"
23 #include "../../src/client/connection_thread.h"
24 #include "../../src/client/event_queue.h"
25 #include "../../src/client/region.h"
26 #include "../../src/client/registry.h"
27 #include "../../src/client/shm_pool.h"
28 #include "../../src/client/subcompositor.h"
29 #include "../../src/client/subsurface.h"
30 #include "../../src/client/surface.h"
31 
32 #include "../../server/buffer.h"
33 #include "../../server/compositor.h"
34 #include "../../server/display.h"
35 #include "../../server/subcompositor.h"
36 #include "../../server/surface.h"
37 
38 #include "../../tests/helpers.h"
39 
40 #include <wayland-client.h>
41 
42 class TestSubsurface : public QObject
43 {
44     Q_OBJECT
45 public:
46     explicit TestSubsurface(QObject* parent = nullptr);
47 private Q_SLOTS:
48     void init();
49     void cleanup();
50 
51     void testCreate();
52     void testMode();
53     void testPosition();
54     void testPlaceAbove();
55     void testPlaceBelow();
56     void testDestroy();
57     void testCast();
58     void testSyncMode();
59     void testDeSyncMode();
60     void testMainSurfaceFromTree();
61     void testRemoveSurface();
62     void testMappingOfSurfaceTree();
63     void testSurfaceAt();
64     void testDestroyAttachedBuffer();
65     void testDestroyParentSurface();
66 
67 private:
68     Wrapland::Server::Display* m_display;
69     Wrapland::Server::Compositor* m_serverCompositor;
70     Wrapland::Server::Subcompositor* m_serverSubcompositor;
71     Wrapland::Client::ConnectionThread* m_connection;
72     Wrapland::Client::Compositor* m_compositor;
73     Wrapland::Client::ShmPool* m_shm;
74     Wrapland::Client::SubCompositor* m_subCompositor;
75     Wrapland::Client::EventQueue* m_queue;
76     QThread* m_thread;
77 };
78 
79 static const QString s_socketName = QStringLiteral("wrapland-test-wayland-subsurface-0");
80 
TestSubsurface(QObject * parent)81 TestSubsurface::TestSubsurface(QObject* parent)
82     : QObject(parent)
83     , m_display(nullptr)
84     , m_serverCompositor(nullptr)
85     , m_serverSubcompositor(nullptr)
86     , m_connection(nullptr)
87     , m_compositor(nullptr)
88     , m_shm(nullptr)
89     , m_subCompositor(nullptr)
90     , m_queue(nullptr)
91     , m_thread(nullptr)
92 {
93 }
94 
init()95 void TestSubsurface::init()
96 {
97     qRegisterMetaType<Wrapland::Server::Surface*>();
98 
99     m_display = new Wrapland::Server::Display(this);
100     m_display->setSocketName(s_socketName);
101     m_display->start();
102 
103     m_display->createShm();
104 
105     // setup connection
106     m_connection = new Wrapland::Client::ConnectionThread;
107     QSignalSpy connectedSpy(m_connection, &Wrapland::Client::ConnectionThread::establishedChanged);
108     m_connection->setSocketName(s_socketName);
109 
110     m_thread = new QThread(this);
111     m_connection->moveToThread(m_thread);
112     m_thread->start();
113 
114     m_connection->establishConnection();
115     QVERIFY(connectedSpy.count() || connectedSpy.wait());
116     QCOMPARE(connectedSpy.count(), 1);
117 
118     m_queue = new Wrapland::Client::EventQueue(this);
119     QVERIFY(!m_queue->isValid());
120     m_queue->setup(m_connection);
121     QVERIFY(m_queue->isValid());
122 
123     Wrapland::Client::Registry registry;
124     QSignalSpy compositorSpy(&registry, SIGNAL(compositorAnnounced(quint32, quint32)));
125     QVERIFY(compositorSpy.isValid());
126     QSignalSpy subCompositorSpy(&registry, SIGNAL(subCompositorAnnounced(quint32, quint32)));
127     QVERIFY(subCompositorSpy.isValid());
128     QVERIFY(!registry.eventQueue());
129     registry.setEventQueue(m_queue);
130     QCOMPARE(registry.eventQueue(), m_queue);
131     registry.create(m_connection->display());
132     QVERIFY(registry.isValid());
133     registry.setup();
134 
135     m_serverCompositor = m_display->createCompositor(m_display);
136 
137     m_serverSubcompositor = m_display->createSubCompositor(m_display);
138     QVERIFY(m_serverSubcompositor);
139 
140     QVERIFY(subCompositorSpy.wait());
141     m_subCompositor
142         = registry.createSubCompositor(subCompositorSpy.first().first().value<quint32>(),
143                                        subCompositorSpy.first().last().value<quint32>(),
144                                        this);
145 
146     if (compositorSpy.isEmpty()) {
147         QVERIFY(compositorSpy.wait());
148     }
149     m_compositor = registry.createCompositor(compositorSpy.first().first().value<quint32>(),
150                                              compositorSpy.first().last().value<quint32>(),
151                                              this);
152 
153     m_shm = registry.createShmPool(
154         registry.interface(Wrapland::Client::Registry::Interface::Shm).name,
155         registry.interface(Wrapland::Client::Registry::Interface::Shm).version,
156         this);
157     QVERIFY(m_shm->isValid());
158 }
159 
cleanup()160 void TestSubsurface::cleanup()
161 {
162     if (m_shm) {
163         delete m_shm;
164         m_shm = nullptr;
165     }
166     if (m_subCompositor) {
167         delete m_subCompositor;
168         m_subCompositor = nullptr;
169     }
170     if (m_compositor) {
171         delete m_compositor;
172         m_compositor = nullptr;
173     }
174     if (m_queue) {
175         delete m_queue;
176         m_queue = nullptr;
177     }
178     if (m_thread) {
179         m_thread->quit();
180         m_thread->wait();
181         delete m_thread;
182         m_thread = nullptr;
183     }
184     delete m_connection;
185     m_connection = nullptr;
186 
187     delete m_display;
188     m_display = nullptr;
189 }
190 
testCreate()191 void TestSubsurface::testCreate()
192 {
193     QSignalSpy surfaceCreatedSpy(m_serverCompositor,
194                                  SIGNAL(surfaceCreated(Wrapland::Server::Surface*)));
195     QVERIFY(surfaceCreatedSpy.isValid());
196 
197     // create two Surfaces
198     std::unique_ptr<Wrapland::Client::Surface> surface(m_compositor->createSurface());
199     QVERIFY(surfaceCreatedSpy.wait());
200     auto serverSurface = surfaceCreatedSpy.first().first().value<Wrapland::Server::Surface*>();
201     QVERIFY(serverSurface);
202 
203     surfaceCreatedSpy.clear();
204     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
205     QVERIFY(surfaceCreatedSpy.wait());
206     auto serverParentSurface
207         = surfaceCreatedSpy.first().first().value<Wrapland::Server::Surface*>();
208     QVERIFY(serverParentSurface);
209 
210     QSignalSpy subsurfaceCreatedSpy(m_serverSubcompositor,
211                                     SIGNAL(subsurfaceCreated(Wrapland::Server::Subsurface*)));
212     QVERIFY(subsurfaceCreatedSpy.isValid());
213 
214     // create subsurface for surface of parent
215     std::unique_ptr<Wrapland::Client::SubSurface> subsurface(
216         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface.get()),
217                                           QPointer<Wrapland::Client::Surface>(parent.get())));
218 
219     QVERIFY(subsurfaceCreatedSpy.wait());
220 
221     auto serverSubsurface
222         = subsurfaceCreatedSpy.first().first().value<Wrapland::Server::Subsurface*>();
223     QVERIFY(serverSubsurface);
224     QVERIFY(serverSubsurface->parentSurface());
225     QCOMPARE(serverSubsurface->parentSurface(), serverParentSurface);
226     QCOMPARE(serverSubsurface->surface(), serverSurface);
227     QCOMPARE(serverSurface->subsurface(), serverSubsurface);
228     QCOMPARE(serverSubsurface->mainSurface(), serverParentSurface);
229 
230     // children are only added after committing the surface
231     QCOMPARE(serverParentSurface->state().children.size(), 0);
232 
233     // so let's commit the surface, to apply the stacking change
234     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
235     wl_display_flush(m_connection->display());
236 
237     QCoreApplication::processEvents();
238     QCOMPARE(serverParentSurface->state().children.size(), 1);
239     QCOMPARE(serverParentSurface->state().children.front(), serverSubsurface);
240 
241     // and let's destroy it again
242     QSignalSpy destroyedSpy(serverSubsurface, SIGNAL(destroyed(QObject*)));
243     QVERIFY(destroyedSpy.isValid());
244     subsurface.reset();
245     QVERIFY(destroyedSpy.wait());
246     QCOMPARE(serverSurface->subsurface(), QPointer<Wrapland::Server::Subsurface>());
247 
248     // Applied immediately.
249     QCOMPARE(serverParentSurface->state().children.size(), 0);
250 
251     // Make sure committing on parent still works.
252     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
253     wl_display_flush(m_connection->display());
254     QCoreApplication::processEvents();
255     QCOMPARE(serverParentSurface->state().children.size(), 0);
256 }
257 
testMode()258 void TestSubsurface::testMode()
259 {
260     // create two Surface
261     std::unique_ptr<Wrapland::Client::Surface> surface(m_compositor->createSurface());
262     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
263 
264     QSignalSpy subsurfaceCreatedSpy(m_serverSubcompositor,
265                                     SIGNAL(subsurfaceCreated(Wrapland::Server::Subsurface*)));
266     QVERIFY(subsurfaceCreatedSpy.isValid());
267 
268     // create the Subsurface for surface of parent
269     std::unique_ptr<Wrapland::Client::SubSurface> subsurface(
270         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface.get()),
271                                           QPointer<Wrapland::Client::Surface>(parent.get())));
272     QVERIFY(subsurfaceCreatedSpy.wait());
273     auto serverSubsurface
274         = subsurfaceCreatedSpy.first().first().value<Wrapland::Server::Subsurface*>();
275     QVERIFY(serverSubsurface);
276 
277     // both client and server subsurface should be in synchronized mode
278     QCOMPARE(subsurface->mode(), Wrapland::Client::SubSurface::Mode::Synchronized);
279     QCOMPARE(serverSubsurface->mode(), Wrapland::Server::Subsurface::Mode::Synchronized);
280 
281     // verify that we can change to desynchronized
282     QSignalSpy modeChangedSpy(serverSubsurface,
283                               SIGNAL(modeChanged(Wrapland::Server::Subsurface::Mode)));
284     QVERIFY(modeChangedSpy.isValid());
285 
286     subsurface->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
287     QCOMPARE(subsurface->mode(), Wrapland::Client::SubSurface::Mode::Desynchronized);
288 
289     QVERIFY(modeChangedSpy.wait());
290     QCOMPARE(modeChangedSpy.first().first().value<Wrapland::Server::Subsurface::Mode>(),
291              Wrapland::Server::Subsurface::Mode::Desynchronized);
292     QCOMPARE(serverSubsurface->mode(), Wrapland::Server::Subsurface::Mode::Desynchronized);
293 
294     // setting the same again won't change
295     subsurface->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
296     QCOMPARE(subsurface->mode(), Wrapland::Client::SubSurface::Mode::Desynchronized);
297     // not testing the signal, we do that after changing to synchronized
298 
299     // and change back to synchronized
300     subsurface->setMode(Wrapland::Client::SubSurface::Mode::Synchronized);
301     QCOMPARE(subsurface->mode(), Wrapland::Client::SubSurface::Mode::Synchronized);
302 
303     QVERIFY(modeChangedSpy.wait());
304     QCOMPARE(modeChangedSpy.count(), 2);
305     QCOMPARE(modeChangedSpy.first().first().value<Wrapland::Server::Subsurface::Mode>(),
306              Wrapland::Server::Subsurface::Mode::Desynchronized);
307     QCOMPARE(modeChangedSpy.last().first().value<Wrapland::Server::Subsurface::Mode>(),
308              Wrapland::Server::Subsurface::Mode::Synchronized);
309     QCOMPARE(serverSubsurface->mode(), Wrapland::Server::Subsurface::Mode::Synchronized);
310 }
311 
testPosition()312 void TestSubsurface::testPosition()
313 {
314     // create two Surface
315     std::unique_ptr<Wrapland::Client::Surface> surface(m_compositor->createSurface());
316     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
317 
318     QSignalSpy subsurfaceCreatedSpy(m_serverSubcompositor,
319                                     SIGNAL(subsurfaceCreated(Wrapland::Server::Subsurface*)));
320     QVERIFY(subsurfaceCreatedSpy.isValid());
321 
322     // create the Subsurface for surface of parent
323     std::unique_ptr<Wrapland::Client::SubSurface> subsurface(
324         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface.get()),
325                                           QPointer<Wrapland::Client::Surface>(parent.get())));
326     QVERIFY(subsurfaceCreatedSpy.wait());
327     auto serverSubsurface
328         = subsurfaceCreatedSpy.first().first().value<Wrapland::Server::Subsurface*>();
329     QVERIFY(serverSubsurface);
330 
331     // create a signalspy
332     QSignalSpy subsurfaceTreeChanged(serverSubsurface->parentSurface(),
333                                      &Wrapland::Server::Surface::subsurfaceTreeChanged);
334     QVERIFY(subsurfaceTreeChanged.isValid());
335 
336     // both client and server should have a default position
337     QCOMPARE(subsurface->position(), QPoint());
338     QCOMPARE(serverSubsurface->position(), QPoint());
339 
340     QSignalSpy positionChangedSpy(serverSubsurface, SIGNAL(positionChanged(QPoint)));
341     QVERIFY(positionChangedSpy.isValid());
342 
343     // changing the position should not trigger a direct update on server side
344     subsurface->setPosition(QPoint(10, 20));
345     QCOMPARE(subsurface->position(), QPoint(10, 20));
346     // ensure it's processed on server side
347     wl_display_flush(m_connection->display());
348     QCoreApplication::processEvents();
349     QCOMPARE(serverSubsurface->position(), QPoint());
350     // changing once more
351     subsurface->setPosition(QPoint(20, 30));
352     QCOMPARE(subsurface->position(), QPoint(20, 30));
353     // ensure it's processed on server side
354     wl_display_flush(m_connection->display());
355     QCoreApplication::processEvents();
356     QCOMPARE(serverSubsurface->position(), QPoint());
357 
358     // committing the parent surface should update the position
359     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
360     QCOMPARE(subsurfaceTreeChanged.count(), 0);
361     QVERIFY(positionChangedSpy.wait());
362     QCOMPARE(positionChangedSpy.count(), 1);
363     QCOMPARE(positionChangedSpy.first().first().toPoint(), QPoint(20, 30));
364     QCOMPARE(serverSubsurface->position(), QPoint(20, 30));
365     QCOMPARE(subsurfaceTreeChanged.count(), 0);
366 }
367 
testPlaceAbove()368 void TestSubsurface::testPlaceAbove()
369 {
370     // Create needed Surfaces (one parent, three children).
371     std::unique_ptr<Wrapland::Client::Surface> surface1(m_compositor->createSurface());
372     std::unique_ptr<Wrapland::Client::Surface> surface2(m_compositor->createSurface());
373     std::unique_ptr<Wrapland::Client::Surface> surface3(m_compositor->createSurface());
374     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
375 
376     QSignalSpy subsurfaceCreatedSpy(m_serverSubcompositor,
377                                     &Wrapland::Server::Subcompositor::subsurfaceCreated);
378     QVERIFY(subsurfaceCreatedSpy.isValid());
379 
380     // Create the Subsurfaces for surface of parent.
381     std::unique_ptr<Wrapland::Client::SubSurface> subsurface1(
382         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface1.get()),
383                                           QPointer<Wrapland::Client::Surface>(parent.get())));
384     QVERIFY(subsurfaceCreatedSpy.wait());
385 
386     auto serverSubsurface1
387         = subsurfaceCreatedSpy.first().first().value<Wrapland::Server::Subsurface*>();
388     QVERIFY(serverSubsurface1);
389 
390     subsurfaceCreatedSpy.clear();
391     std::unique_ptr<Wrapland::Client::SubSurface> subsurface2(
392         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface2.get()),
393                                           QPointer<Wrapland::Client::Surface>(parent.get())));
394     QVERIFY(subsurfaceCreatedSpy.wait());
395 
396     auto serverSubsurface2
397         = subsurfaceCreatedSpy.first().first().value<Wrapland::Server::Subsurface*>();
398     QVERIFY(serverSubsurface2);
399 
400     subsurfaceCreatedSpy.clear();
401     std::unique_ptr<Wrapland::Client::SubSurface> subsurface3(
402         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface3.get()),
403                                           QPointer<Wrapland::Client::Surface>(parent.get())));
404     QVERIFY(subsurfaceCreatedSpy.wait());
405 
406     auto serverSubsurface3
407         = subsurfaceCreatedSpy.first().first().value<Wrapland::Server::Subsurface*>();
408     QVERIFY(serverSubsurface3);
409     subsurfaceCreatedSpy.clear();
410 
411     // So far the stacking order should still be empty.
412     QVERIFY(serverSubsurface1->parentSurface()->state().children.empty());
413 
414     // Committing the parent should create the stacking order.
415     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
416 
417     // Ensure it's processed on server side.
418     wl_display_flush(m_connection->display());
419     QCoreApplication::processEvents();
420 
421     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
422     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface1);
423     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface2);
424     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface3);
425 
426     // Raising subsurface1 should place it to top of stack.
427     subsurface1->raise();
428 
429     // Ensure it's processed on server side.
430     wl_display_flush(m_connection->display());
431     QCoreApplication::processEvents();
432 
433     // But as long as parent is not committed it shouldn't change on server side.
434     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface1);
435 
436     // After commit it's changed.
437     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
438     wl_display_flush(m_connection->display());
439     QCoreApplication::processEvents();
440     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
441     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface2);
442     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface3);
443     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface1);
444 
445     // Try placing 3 above 1, should result in 2, 1, 3.
446     subsurface3->placeAbove(QPointer<Wrapland::Client::SubSurface>(subsurface1.get()));
447     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
448     wl_display_flush(m_connection->display());
449     QCoreApplication::processEvents();
450     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
451     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface2);
452     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface1);
453     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface3);
454 
455     // try placing 3 above 2, should result in 2, 3, 1
456     subsurface3->placeAbove(QPointer<Wrapland::Client::SubSurface>(subsurface2.get()));
457     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
458     wl_display_flush(m_connection->display());
459     QCoreApplication::processEvents();
460     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
461     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface2);
462     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface3);
463     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface1);
464 
465     // try placing 1 above 3 - shouldn't change
466     subsurface1->placeAbove(QPointer<Wrapland::Client::SubSurface>(subsurface3.get()));
467     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
468     wl_display_flush(m_connection->display());
469     QCoreApplication::processEvents();
470     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
471     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface2);
472     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface3);
473     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface1);
474 
475     // and 2 above 3 - > 3, 2, 1
476     subsurface2->placeAbove(QPointer<Wrapland::Client::SubSurface>(subsurface3.get()));
477     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
478     wl_display_flush(m_connection->display());
479     QCoreApplication::processEvents();
480     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
481     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface3);
482     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface2);
483     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface1);
484 }
485 
testPlaceBelow()486 void TestSubsurface::testPlaceBelow()
487 {
488     using namespace Wrapland::Server;
489     // create needed Surfaces (one parent, three client
490     std::unique_ptr<Wrapland::Client::Surface> surface1(m_compositor->createSurface());
491     std::unique_ptr<Wrapland::Client::Surface> surface2(m_compositor->createSurface());
492     std::unique_ptr<Wrapland::Client::Surface> surface3(m_compositor->createSurface());
493     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
494 
495     QSignalSpy subsurfaceCreatedSpy(m_serverSubcompositor,
496                                     SIGNAL(subsurfaceCreated(Wrapland::Server::Subsurface*)));
497     QVERIFY(subsurfaceCreatedSpy.isValid());
498 
499     // create the Subsurfaces for surface of parent
500     std::unique_ptr<Wrapland::Client::SubSurface> subsurface1(
501         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface1.get()),
502                                           QPointer<Wrapland::Client::Surface>(parent.get())));
503     QVERIFY(subsurfaceCreatedSpy.wait());
504     auto serverSubsurface1
505         = subsurfaceCreatedSpy.first().first().value<Wrapland::Server::Subsurface*>();
506     QVERIFY(serverSubsurface1);
507     subsurfaceCreatedSpy.clear();
508     std::unique_ptr<Wrapland::Client::SubSurface> subsurface2(
509         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface2.get()),
510                                           QPointer<Wrapland::Client::Surface>(parent.get())));
511     QVERIFY(subsurfaceCreatedSpy.wait());
512     auto serverSubsurface2
513         = subsurfaceCreatedSpy.first().first().value<Wrapland::Server::Subsurface*>();
514     QVERIFY(serverSubsurface2);
515     subsurfaceCreatedSpy.clear();
516     std::unique_ptr<Wrapland::Client::SubSurface> subsurface3(
517         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface3.get()),
518                                           QPointer<Wrapland::Client::Surface>(parent.get())));
519     QVERIFY(subsurfaceCreatedSpy.wait());
520     auto serverSubsurface3
521         = subsurfaceCreatedSpy.first().first().value<Wrapland::Server::Subsurface*>();
522     QVERIFY(serverSubsurface3);
523     subsurfaceCreatedSpy.clear();
524 
525     // so far the stacking order should still be empty
526     QVERIFY(serverSubsurface1->parentSurface()->state().children.empty());
527 
528     // committing the parent should create the stacking order
529     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
530     // ensure it's processed on server side
531     wl_display_flush(m_connection->display());
532     QCoreApplication::processEvents();
533     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
534     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface1);
535     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface2);
536     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface3);
537 
538     // lowering subsurface3 should place it to the bottom of stack
539     subsurface3->lower();
540     // ensure it's processed on server side
541     wl_display_flush(m_connection->display());
542     QCoreApplication::processEvents();
543     // but as long as parent is not committed it shouldn't change on server side
544     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface1);
545     // after commit it's changed
546     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
547     wl_display_flush(m_connection->display());
548     QCoreApplication::processEvents();
549     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
550     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface3);
551     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface1);
552     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface2);
553 
554     // place 1 below 3 -> 1, 3, 2
555     subsurface1->placeBelow(QPointer<Wrapland::Client::SubSurface>(subsurface3.get()));
556     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
557     wl_display_flush(m_connection->display());
558     QCoreApplication::processEvents();
559     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
560     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface1);
561     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface3);
562     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface2);
563 
564     // 2 below 3 -> 1, 2, 3
565     subsurface2->placeBelow(QPointer<Wrapland::Client::SubSurface>(subsurface3.get()));
566     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
567     wl_display_flush(m_connection->display());
568     QCoreApplication::processEvents();
569     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
570     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface1);
571     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface2);
572     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface3);
573 
574     // 1 below 2 -> shouldn't change
575     subsurface1->placeBelow(QPointer<Wrapland::Client::SubSurface>(subsurface2.get()));
576     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
577     wl_display_flush(m_connection->display());
578     QCoreApplication::processEvents();
579     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
580     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface1);
581     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface2);
582     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface3);
583 
584     // and 3 below 1 -> 3, 1, 2
585     subsurface3->placeBelow(QPointer<Wrapland::Client::SubSurface>(subsurface1.get()));
586     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
587     wl_display_flush(m_connection->display());
588     QCoreApplication::processEvents();
589     QCOMPARE(serverSubsurface1->parentSurface()->state().children.size(), 3);
590     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(0), serverSubsurface3);
591     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(1), serverSubsurface1);
592     QCOMPARE(serverSubsurface1->parentSurface()->state().children.at(2), serverSubsurface2);
593 }
594 
testDestroy()595 void TestSubsurface::testDestroy()
596 {
597     // create two Surfaces
598     std::unique_ptr<Wrapland::Client::Surface> surface(m_compositor->createSurface());
599     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
600     // create subsurface for surface of parent
601     std::unique_ptr<Wrapland::Client::SubSurface> subsurface(
602         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface.get()),
603                                           QPointer<Wrapland::Client::Surface>(parent.get())));
604 
605     connect(m_connection,
606             &Wrapland::Client::ConnectionThread::establishedChanged,
607             m_compositor,
608             &Wrapland::Client::Compositor::release);
609     connect(m_connection,
610             &Wrapland::Client::ConnectionThread::establishedChanged,
611             m_subCompositor,
612             &Wrapland::Client::SubCompositor::release);
613     connect(m_connection,
614             &Wrapland::Client::ConnectionThread::establishedChanged,
615             m_shm,
616             &Wrapland::Client::ShmPool::release);
617     connect(m_connection,
618             &Wrapland::Client::ConnectionThread::establishedChanged,
619             m_queue,
620             &Wrapland::Client::EventQueue::release);
621     connect(m_connection,
622             &Wrapland::Client::ConnectionThread::establishedChanged,
623             surface.get(),
624             &Wrapland::Client::Surface::release);
625     connect(m_connection,
626             &Wrapland::Client::ConnectionThread::establishedChanged,
627             parent.get(),
628             &Wrapland::Client::Surface::release);
629     connect(m_connection,
630             &Wrapland::Client::ConnectionThread::establishedChanged,
631             subsurface.get(),
632             &Wrapland::Client::SubSurface::release);
633     QVERIFY(subsurface->isValid());
634 
635     delete m_display;
636     m_display = nullptr;
637     QTRY_VERIFY(!m_connection->established());
638 
639     // Now the pool should be destroyed.
640     QTRY_VERIFY(!subsurface->isValid());
641 
642     // Calling destroy again should not fail.
643     subsurface->release();
644 }
645 
testCast()646 void TestSubsurface::testCast()
647 {
648     // Create two Surfaces.
649     std::unique_ptr<Wrapland::Client::Surface> surface(m_compositor->createSurface());
650     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
651 
652     // Create subsurface for surface with parent.
653     std::unique_ptr<Wrapland::Client::SubSurface> subsurface(
654         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface.get()),
655                                           QPointer<Wrapland::Client::Surface>(parent.get())));
656 
657     QCOMPARE(Wrapland::Client::SubSurface::get(*(subsurface.get())),
658              QPointer<Wrapland::Client::SubSurface>(subsurface.get()));
659 }
660 
testSyncMode()661 void TestSubsurface::testSyncMode()
662 {
663     // this test verifies that state is only applied when the parent surface commits its pending
664     // state
665 
666     QSignalSpy surfaceCreatedSpy(m_serverCompositor, &Wrapland::Server::Compositor::surfaceCreated);
667     QVERIFY(surfaceCreatedSpy.isValid());
668 
669     std::unique_ptr<Wrapland::Client::Surface> surface(m_compositor->createSurface());
670     QVERIFY(surfaceCreatedSpy.wait());
671     auto childSurface = surfaceCreatedSpy.first().first().value<Wrapland::Server::Surface*>();
672     QVERIFY(childSurface);
673 
674     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
675     QVERIFY(surfaceCreatedSpy.wait());
676     auto parentSurface = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
677     QVERIFY(parentSurface);
678 
679     QSignalSpy parent_commit_spy(parentSurface, &Wrapland::Server::Surface::committed);
680     QVERIFY(parent_commit_spy.isValid());
681     QSignalSpy subsurfaceTreeChangedSpy(parentSurface,
682                                         &Wrapland::Server::Surface::subsurfaceTreeChanged);
683     QVERIFY(subsurfaceTreeChangedSpy.isValid());
684 
685     // create subsurface for surface of parent
686     std::unique_ptr<Wrapland::Client::SubSurface> subsurface(
687         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface.get()),
688                                           QPointer<Wrapland::Client::Surface>(parent.get())));
689     QVERIFY(!subsurfaceTreeChangedSpy.wait(100));
690 
691     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
692     QVERIFY(parent_commit_spy.wait());
693     QCOMPARE(subsurfaceTreeChangedSpy.count(), 0);
694     QVERIFY(parentSurface->state().updates & Wrapland::Server::surface_change::children);
695 
696     // let's damage the child surface
697     QSignalSpy child_commit_spy(childSurface, &Wrapland::Server::Surface::committed);
698     QVERIFY(child_commit_spy.isValid());
699 
700     QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied);
701     image.fill(Qt::black);
702     surface->attachBuffer(m_shm->createBuffer(image));
703     surface->damage(QRect(0, 0, 200, 200));
704     surface->commit();
705 
706     // state should be applied when the parent surface's state gets applied
707     QVERIFY(!child_commit_spy.wait(100));
708     QVERIFY(!childSurface->state().buffer);
709 
710     QVERIFY(!childSurface->isMapped());
711     QVERIFY(!parentSurface->isMapped());
712 
713     QImage image2(QSize(400, 400), QImage::Format_ARGB32_Premultiplied);
714     image2.fill(Qt::red);
715     parent->attachBuffer(m_shm->createBuffer(image2));
716     parent->damage(QRect(0, 0, 400, 400));
717     parent->commit();
718 
719     QVERIFY(child_commit_spy.wait());
720     QCOMPARE(child_commit_spy.count(), 1);
721     QCOMPARE(subsurfaceTreeChangedSpy.count(), 0);
722     QCOMPARE(childSurface->state().buffer->shmImage()->createQImage(), image);
723     QCOMPARE(parentSurface->state().buffer->shmImage()->createQImage(), image2);
724     QVERIFY(childSurface->isMapped());
725     QVERIFY(parentSurface->isMapped());
726 
727     // sending frame rendered to parent should also send it to child
728     QSignalSpy frameRenderedSpy(surface.get(), &Wrapland::Client::Surface::frameRendered);
729     QVERIFY(frameRenderedSpy.isValid());
730     parentSurface->frameRendered(100);
731     QVERIFY(frameRenderedSpy.wait());
732 
733     // Unmapping the child is applied on parent surface commit.
734     surface->attachBuffer(Wrapland::Client::Buffer::Ptr());
735     surface->commit();
736     QVERIFY(!child_commit_spy.wait(100));
737     QVERIFY(childSurface->state().buffer);
738     QCOMPARE(subsurfaceTreeChangedSpy.count(), 0);
739 
740     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
741     QVERIFY(parent_commit_spy.wait());
742     QVERIFY(parentSurface->state().updates & Wrapland::Server::surface_change::children);
743     QVERIFY(!childSurface->state().buffer);
744     QCOMPARE(subsurfaceTreeChangedSpy.count(), 0);
745 
746     // Destroying the child on the other side is applied immediately.
747     subsurface.reset();
748     QVERIFY(subsurfaceTreeChangedSpy.wait());
749 }
750 
testDeSyncMode()751 void TestSubsurface::testDeSyncMode()
752 {
753     // this test verifies that state gets applied immediately in desync mode
754 
755     QSignalSpy surfaceCreatedSpy(m_serverCompositor, &Wrapland::Server::Compositor::surfaceCreated);
756     QVERIFY(surfaceCreatedSpy.isValid());
757 
758     std::unique_ptr<Wrapland::Client::Surface> surface(m_compositor->createSurface());
759     QVERIFY(surfaceCreatedSpy.wait());
760     auto childSurface = surfaceCreatedSpy.first().first().value<Wrapland::Server::Surface*>();
761     QVERIFY(childSurface);
762 
763     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
764     QVERIFY(surfaceCreatedSpy.wait());
765     auto parentSurface = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
766     QVERIFY(parentSurface);
767 
768     QSignalSpy parent_commit_spy(parentSurface, &Wrapland::Server::Surface::committed);
769     QVERIFY(parent_commit_spy.isValid());
770     QSignalSpy subsurfaceTreeChangedSpy(parentSurface,
771                                         &Wrapland::Server::Surface::subsurfaceTreeChanged);
772     QVERIFY(subsurfaceTreeChangedSpy.isValid());
773 
774     // create subsurface for surface of parent
775     std::unique_ptr<Wrapland::Client::SubSurface> subsurface(
776         m_subCompositor->createSubSurface(QPointer<Wrapland::Client::Surface>(surface.get()),
777                                           QPointer<Wrapland::Client::Surface>(parent.get())));
778     QVERIFY(!subsurfaceTreeChangedSpy.wait(100));
779 
780     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
781     QVERIFY(parent_commit_spy.wait());
782     QCOMPARE(subsurfaceTreeChangedSpy.count(), 0);
783     QVERIFY(parentSurface->state().updates & Wrapland::Server::surface_change::children);
784 
785     // let's damage the child surface
786     QSignalSpy child_commit_spy(childSurface, &Wrapland::Server::Surface::committed);
787     QVERIFY(child_commit_spy.isValid());
788 
789     QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied);
790     image.fill(Qt::black);
791     surface->attachBuffer(m_shm->createBuffer(image));
792     surface->damage(QRect(0, 0, 200, 200));
793     surface->commit(Wrapland::Client::Surface::CommitFlag::None);
794 
795     // state should be applied when the parent surface's state gets applied or when the subsurface
796     // switches to desync
797     QVERIFY(!child_commit_spy.wait(100));
798     QVERIFY(!childSurface->isMapped());
799     QVERIFY(!parentSurface->isMapped());
800 
801     // setting to desync should apply the state directly
802     QVERIFY(child_commit_spy.isEmpty());
803     subsurface->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
804 
805     QVERIFY(child_commit_spy.count() || child_commit_spy.wait());
806     QCOMPARE(child_commit_spy.count(), 1);
807     QCOMPARE(subsurfaceTreeChangedSpy.count(), 0);
808     QCOMPARE(childSurface->state().buffer->shmImage()->createQImage(), image);
809     QVERIFY(!childSurface->isMapped());
810     QVERIFY(!parentSurface->isMapped());
811 
812     // and damaging again, should directly be applied
813     image.fill(Qt::red);
814     surface->attachBuffer(m_shm->createBuffer(image));
815     surface->damage(QRect(0, 0, 200, 200));
816     surface->commit(Wrapland::Client::Surface::CommitFlag::None);
817 
818     QVERIFY(child_commit_spy.wait());
819     QCOMPARE(child_commit_spy.count(), 2);
820     QCOMPARE(subsurfaceTreeChangedSpy.count(), 0);
821     QCOMPARE(childSurface->state().buffer->shmImage()->createQImage(), image);
822 
823     // Destroying the child is applied immediately.
824     surface.reset();
825     QVERIFY(subsurfaceTreeChangedSpy.wait());
826 }
827 
testMainSurfaceFromTree()828 void TestSubsurface::testMainSurfaceFromTree()
829 {
830     // this test verifies that in a tree of surfaces every surface has the same main surface
831     using namespace Wrapland::Client;
832     using namespace Wrapland::Server;
833     QSignalSpy surfaceCreatedSpy(m_serverCompositor, &Wrapland::Server::Compositor::surfaceCreated);
834     QVERIFY(surfaceCreatedSpy.isValid());
835 
836     std::unique_ptr<Wrapland::Client::Surface> parentSurface(m_compositor->createSurface());
837     QVERIFY(surfaceCreatedSpy.wait());
838 
839     auto parentServerSurface = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
840     QVERIFY(parentServerSurface);
841     std::unique_ptr<Wrapland::Client::Surface> childLevel1Surface(m_compositor->createSurface());
842     QVERIFY(surfaceCreatedSpy.wait());
843 
844     auto childLevel1ServerSurface
845         = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
846     QVERIFY(childLevel1ServerSurface);
847     std::unique_ptr<Wrapland::Client::Surface> childLevel2Surface(m_compositor->createSurface());
848     QVERIFY(surfaceCreatedSpy.wait());
849 
850     auto childLevel2ServerSurface
851         = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
852     QVERIFY(childLevel2ServerSurface);
853     std::unique_ptr<Wrapland::Client::Surface> childLevel3Surface(m_compositor->createSurface());
854     QVERIFY(surfaceCreatedSpy.wait());
855 
856     auto childLevel3ServerSurface
857         = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
858     QVERIFY(childLevel3ServerSurface);
859 
860     QSignalSpy parent_commit_spy(parentServerSurface, &Wrapland::Server::Surface::committed);
861     QVERIFY(parent_commit_spy.isValid());
862     QSignalSpy subsurfaceTreeChangedSpy(parentServerSurface,
863                                         &Wrapland::Server::Surface::subsurfaceTreeChanged);
864     QVERIFY(subsurfaceTreeChangedSpy.isValid());
865 
866     auto* sub1 = m_subCompositor->createSubSurface(childLevel1Surface.get(), parentSurface.get());
867     auto* sub2
868         = m_subCompositor->createSubSurface(childLevel2Surface.get(), childLevel1Surface.get());
869     auto* sub3
870         = m_subCompositor->createSubSurface(childLevel3Surface.get(), childLevel2Surface.get());
871 
872     childLevel2Surface->commit(Wrapland::Client::Surface::CommitFlag::None);
873     childLevel1Surface->commit(Wrapland::Client::Surface::CommitFlag::None);
874     parentSurface->commit(Wrapland::Client::Surface::CommitFlag::None);
875 
876     QVERIFY(parent_commit_spy.wait());
877     QCOMPARE(subsurfaceTreeChangedSpy.count(), 0);
878     QVERIFY(parentServerSurface->state().updates & Wrapland::Server::surface_change::children);
879 
880     QCOMPARE(parentServerSurface->state().children.size(), 1);
881 
882     auto child = parentServerSurface->state().children.front();
883     QCOMPARE(child->parentSurface(), parentServerSurface);
884     QCOMPARE(child->mainSurface(), parentServerSurface);
885     QCOMPARE(child->surface()->state().children.size(), 1);
886 
887     auto child2 = child->surface()->state().children.front();
888     QCOMPARE(child2->parentSurface(), child->surface());
889     QCOMPARE(child2->mainSurface(), parentServerSurface);
890     QCOMPARE(child2->surface()->state().children.size(), 1);
891 
892     auto child3 = child2->surface()->state().children.front();
893     QCOMPARE(child3->parentSurface(), child2->surface());
894     QCOMPARE(child3->mainSurface(), parentServerSurface);
895     QCOMPARE(child3->surface()->state().children.size(), 0);
896 
897     delete sub1;
898     delete sub2;
899     delete sub3;
900 }
901 
testRemoveSurface()902 void TestSubsurface::testRemoveSurface()
903 {
904     // this test verifies that removing the surface also removes the sub-surface from the parent
905     using namespace Wrapland::Client;
906     using namespace Wrapland::Server;
907 
908     QSignalSpy surfaceCreatedSpy(m_serverCompositor, &Wrapland::Server::Compositor::surfaceCreated);
909     QVERIFY(surfaceCreatedSpy.isValid());
910 
911     std::unique_ptr<Wrapland::Client::Surface> parentSurface(m_compositor->createSurface());
912     QVERIFY(surfaceCreatedSpy.wait());
913     auto parentServerSurface = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
914     QVERIFY(parentServerSurface);
915     std::unique_ptr<Wrapland::Client::Surface> childSurface(m_compositor->createSurface());
916     QVERIFY(surfaceCreatedSpy.wait());
917     auto childServerSurface = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
918     QVERIFY(childServerSurface);
919 
920     QSignalSpy parent_commit_spy(parentServerSurface, &Wrapland::Server::Surface::committed);
921     QVERIFY(parent_commit_spy.isValid());
922     QSignalSpy subsurfaceTreeChangedSpy(parentServerSurface,
923                                         &Wrapland::Server::Surface::subsurfaceTreeChanged);
924     QVERIFY(subsurfaceTreeChangedSpy.isValid());
925 
926     std::unique_ptr<Wrapland::Client::SubSurface> sub(
927         m_subCompositor->createSubSurface(childSurface.get(), parentSurface.get()));
928 
929     parentSurface->commit(Wrapland::Client::Surface::CommitFlag::None);
930     QVERIFY(parent_commit_spy.wait());
931     QCOMPARE(subsurfaceTreeChangedSpy.count(), 0);
932     QVERIFY(parentServerSurface->state().updates & Wrapland::Server::surface_change::children);
933     QCOMPARE(parentServerSurface->state().children.size(), 1);
934 
935     // destroy surface, takes place immediately
936     childSurface.reset();
937     QVERIFY(subsurfaceTreeChangedSpy.wait());
938     QCOMPARE(parentServerSurface->state().children.size(), 0);
939 }
940 
testMappingOfSurfaceTree()941 void TestSubsurface::testMappingOfSurfaceTree()
942 {
943     // this test verifies mapping and unmapping of a sub-surface tree
944     using namespace Wrapland::Client;
945     using namespace Wrapland::Server;
946     QSignalSpy surfaceCreatedSpy(m_serverCompositor, &Wrapland::Server::Compositor::surfaceCreated);
947     QVERIFY(surfaceCreatedSpy.isValid());
948 
949     std::unique_ptr<Wrapland::Client::Surface> parentSurface(m_compositor->createSurface());
950     QVERIFY(surfaceCreatedSpy.wait());
951     auto parentServerSurface = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
952     QVERIFY(parentServerSurface);
953     std::unique_ptr<Wrapland::Client::Surface> childLevel1Surface(m_compositor->createSurface());
954     QVERIFY(surfaceCreatedSpy.wait());
955     auto childLevel1ServerSurface
956         = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
957     QVERIFY(childLevel1ServerSurface);
958     std::unique_ptr<Wrapland::Client::Surface> childLevel2Surface(m_compositor->createSurface());
959     QVERIFY(surfaceCreatedSpy.wait());
960     auto childLevel2ServerSurface
961         = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
962     QVERIFY(childLevel2ServerSurface);
963     std::unique_ptr<Wrapland::Client::Surface> childLevel3Surface(m_compositor->createSurface());
964     QVERIFY(surfaceCreatedSpy.wait());
965     auto childLevel3ServerSurface
966         = surfaceCreatedSpy.last().first().value<Wrapland::Server::Surface*>();
967     QVERIFY(childLevel3ServerSurface);
968 
969     QSignalSpy parent_commit_spy(parentServerSurface, &Wrapland::Server::Surface::committed);
970     QVERIFY(parent_commit_spy.isValid());
971     QSignalSpy subsurfaceTreeChangedSpy(parentServerSurface,
972                                         &Wrapland::Server::Surface::subsurfaceTreeChanged);
973     QVERIFY(subsurfaceTreeChangedSpy.isValid());
974 
975     auto subsurfaceLevel1
976         = m_subCompositor->createSubSurface(childLevel1Surface.get(), parentSurface.get());
977     auto subsurfaceLevel2
978         = m_subCompositor->createSubSurface(childLevel2Surface.get(), childLevel1Surface.get());
979     auto subsurfaceLevel3
980         = m_subCompositor->createSubSurface(childLevel3Surface.get(), childLevel2Surface.get());
981 
982     childLevel3Surface->commit(Wrapland::Client::Surface::CommitFlag::None);
983     childLevel2Surface->commit(Wrapland::Client::Surface::CommitFlag::None);
984     childLevel1Surface->commit(Wrapland::Client::Surface::CommitFlag::None);
985     parentSurface->commit(Wrapland::Client::Surface::CommitFlag::None);
986 
987     QVERIFY(parent_commit_spy.wait());
988     QCOMPARE(subsurfaceTreeChangedSpy.count(), 0);
989     QVERIFY(parentServerSurface->state().updates & Wrapland::Server::surface_change::children);
990     QCOMPARE(parentServerSurface->state().children.size(), 1);
991 
992     QCOMPARE(parentServerSurface->state().children.size(), 1);
993     auto child = parentServerSurface->state().children.front();
994     QCOMPARE(child->surface()->state().children.size(), 1);
995     auto child2 = child->surface()->state().children.front();
996     QCOMPARE(child2->surface()->state().children.size(), 1);
997     auto child3 = child2->surface()->state().children.front();
998     QCOMPARE(child3->parentSurface(), child2->surface());
999     QCOMPARE(child3->mainSurface(), parentServerSurface);
1000     QCOMPARE(child3->surface()->state().children.size(), 0);
1001 
1002     // So far no surface is mapped.
1003     QVERIFY(!parentServerSurface->isMapped());
1004     QVERIFY(!child->surface()->isMapped());
1005     QVERIFY(!child2->surface()->isMapped());
1006     QVERIFY(!child3->surface()->isMapped());
1007 
1008     // First set all subsurfaces to desync to simplify.
1009     subsurfaceLevel1->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
1010     subsurfaceLevel2->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
1011     subsurfaceLevel3->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
1012 
1013     QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied);
1014     image.fill(Qt::black);
1015 
1016     // Attach a buffer to the first child. Should not map.
1017     QSignalSpy child1_commit_spy(child->surface(), &Wrapland::Server::Surface::committed);
1018     QVERIFY(child1_commit_spy.isValid());
1019     childLevel1Surface->attachBuffer(m_shm->createBuffer(image));
1020     childLevel1Surface->damage(QRect(0, 0, 200, 200));
1021     childLevel1Surface->commit(Wrapland::Client::Surface::CommitFlag::None);
1022     QVERIFY(child1_commit_spy.wait());
1023     QVERIFY(child->surface()->state().buffer);
1024     QVERIFY(!child->surface()->isMapped());
1025 
1026     // Attach a buffer to the third child. Should not map.
1027     QSignalSpy child3_commit_spy(child3->surface(), &Wrapland::Server::Surface::committed);
1028     QVERIFY(child3_commit_spy.isValid());
1029     childLevel3Surface->attachBuffer(m_shm->createBuffer(image));
1030     childLevel3Surface->damage(QRect(0, 0, 200, 200));
1031     childLevel3Surface->commit(Wrapland::Client::Surface::CommitFlag::None);
1032     QVERIFY(child3_commit_spy.wait());
1033     QVERIFY(child3->surface()->state().buffer);
1034     QVERIFY(!child3->surface()->isMapped());
1035 
1036     // Map the top level.
1037     QSignalSpy commit_spy(parentServerSurface, &Wrapland::Server::Surface::committed);
1038     QVERIFY(commit_spy.isValid());
1039     parentSurface->attachBuffer(m_shm->createBuffer(image));
1040     parentSurface->damage(QRect(0, 0, 200, 200));
1041     parentSurface->commit(Wrapland::Client::Surface::CommitFlag::None);
1042     QVERIFY(commit_spy.wait());
1043     QVERIFY(parentServerSurface->isMapped());
1044 
1045     // First child should now be mapped automatically too but not second or third one.
1046     QVERIFY(child->surface()->isMapped());
1047     QVERIFY(!child2->surface()->isMapped());
1048     QVERIFY(!child3->surface()->isMapped());
1049 
1050     // Now map the second level. This should automatically also map the thrid one.
1051     QSignalSpy child2_commit_spy(child2->surface(), &Wrapland::Server::Surface::committed);
1052     QVERIFY(child2_commit_spy.isValid());
1053     childLevel2Surface->attachBuffer(m_shm->createBuffer(image));
1054     childLevel2Surface->damage(QRect(0, 0, 200, 200));
1055     childLevel2Surface->commit(Wrapland::Client::Surface::CommitFlag::None);
1056     QVERIFY(child2_commit_spy.wait());
1057     QVERIFY(parentServerSurface->isMapped());
1058 
1059     // Everything is mapped now.
1060     QVERIFY(parentServerSurface->isMapped());
1061     QVERIFY(child->surface()->isMapped());
1062     QVERIFY(child2->surface()->isMapped());
1063     QVERIFY(child3->surface()->isMapped());
1064 
1065     // Unmapping a parent should unmap the complete tree.
1066     childLevel2Surface->attachBuffer(Wrapland::Client::Buffer::Ptr());
1067     childLevel2Surface->damage(QRect(0, 0, 200, 200));
1068     childLevel2Surface->commit(Wrapland::Client::Surface::CommitFlag::None);
1069     QVERIFY(child2_commit_spy.wait());
1070 
1071     QVERIFY(parentServerSurface->isMapped());
1072     QVERIFY(child->surface()->isMapped());
1073     QVERIFY(!child2->surface()->isMapped());
1074     QVERIFY(!child3->surface()->isMapped());
1075 
1076     delete subsurfaceLevel1;
1077     delete subsurfaceLevel2;
1078     delete subsurfaceLevel3;
1079 }
1080 
testSurfaceAt()1081 void TestSubsurface::testSurfaceAt()
1082 {
1083     // This test verifies that the correct surface is picked in a subsurface tree.
1084     //
1085     //     -----------------------------
1086     //    |                             |
1087     //    |      grandchild1(50x50)     |
1088     //    |                             |
1089     //    |                             |
1090     //    |                             |-----------------------------------------
1091     //    |                             |                          |              |
1092     //    |                             |                          |              |
1093     //    |                             |                          |              |
1094     //    |                             |                          |              |
1095     //     -----------------------------                           |              |
1096     //                   |                                         |              |
1097     //                   |              child1(75x75)              |              |
1098     //                   |                                         |              |
1099     //                   |                                         |              |
1100     //                   |                             ------------------------------------------
1101     //                   |                            |                                          |
1102     //                   |                            |              child2(75x75)               |
1103     //                   |                            |                                          |
1104     //                   |----------------------------|             -----------------------------|
1105     //                   |                            |            |              |              |
1106     //                   |                            |            |    input1    | grandhchild2 |
1107     //                   |       parent(100x100)      |            |    (25x25)   |   (50x50)    |
1108     //                   |                            |            |              |              |
1109     //                    ----------------------------|            |--------------+--------------|
1110     //                                                |            |              |              |
1111     //                                                |            |              |    input2    |
1112     //                                                |            |              |    (25x25)   |
1113     //                                                |            |              |              |
1114     //                                                 ------------------------------------------
1115     //
1116 
1117     QImage parentimage(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
1118     parentimage.fill(Qt::red);
1119     QImage childImage(QSize(75, 75), QImage::Format_ARGB32_Premultiplied);
1120     childImage.fill(Qt::green);
1121     QImage grandchildImage(QSize(50, 50), QImage::Format_ARGB32_Premultiplied);
1122     childImage.fill(Qt::blue);
1123 
1124     // First create a parent surface and map it.
1125     QSignalSpy serverSurfaceCreated(m_serverCompositor,
1126                                     &Wrapland::Server::Compositor::surfaceCreated);
1127     QVERIFY(serverSurfaceCreated.isValid());
1128     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
1129     parent->attachBuffer(m_shm->createBuffer(parentimage));
1130     parent->damage(QRect(0, 0, 100, 100));
1131     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
1132     QVERIFY(serverSurfaceCreated.wait());
1133     auto serverParent = serverSurfaceCreated.last().first().value<Wrapland::Server::Surface*>();
1134 
1135     // Create two child subsurfaces, just added to the parent this is to simulate the behavior of
1136     // QtWayland (might have changed in the meantime).
1137     std::unique_ptr<Wrapland::Client::Surface> child1(m_compositor->createSurface());
1138     QVERIFY(serverSurfaceCreated.wait());
1139     auto serverChild1 = serverSurfaceCreated.last().first().value<Wrapland::Server::Surface*>();
1140     QVERIFY(serverChild1);
1141 
1142     std::unique_ptr<Wrapland::Client::Surface> child2(m_compositor->createSurface());
1143     QVERIFY(serverSurfaceCreated.wait());
1144     auto serverChild2 = serverSurfaceCreated.last().first().value<Wrapland::Server::Surface*>();
1145     QVERIFY(serverChild2);
1146 
1147     // Create the subsurfaces for the children.
1148     std::unique_ptr<Wrapland::Client::SubSurface> child1Sub(
1149         m_subCompositor->createSubSurface(child1.get(), parent.get()));
1150     child1Sub->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
1151 
1152     child1->attachBuffer(m_shm->createBuffer(childImage));
1153     child1->damage(QRect(0, 0, 75, 75));
1154     child1->commit(Wrapland::Client::Surface::CommitFlag::None);
1155 
1156     // Note: child2Sub is initially above child1Sub since it is added after.
1157     std::unique_ptr<Wrapland::Client::SubSurface> child2Sub(
1158         m_subCompositor->createSubSurface(child2.get(), parent.get()));
1159     child2Sub->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
1160     child2Sub->setPosition(QPoint(50, 50));
1161 
1162     child2->attachBuffer(m_shm->createBuffer(childImage));
1163     child2->damage(QRect(0, 0, 75, 75));
1164     child2->commit(Wrapland::Client::Surface::CommitFlag::None);
1165 
1166     // Each of the children gets a child.
1167     std::unique_ptr<Wrapland::Client::Surface> grandchild1(m_compositor->createSurface());
1168     QVERIFY(serverSurfaceCreated.wait());
1169     auto serverGrandchild1
1170         = serverSurfaceCreated.last().first().value<Wrapland::Server::Surface*>();
1171 
1172     std::unique_ptr<Wrapland::Client::Surface> grandchild2(m_compositor->createSurface());
1173     QVERIFY(serverSurfaceCreated.wait());
1174     auto serverGrandchild2
1175         = serverSurfaceCreated.last().first().value<Wrapland::Server::Surface*>();
1176 
1177     // Create subsurfaces for the grandchildren.
1178     std::unique_ptr<Wrapland::Client::SubSurface> grandchild1Sub(
1179         m_subCompositor->createSubSurface(grandchild1.get(), child1.get()));
1180     grandchild1Sub->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
1181     grandchild1Sub->setPosition(QPoint(-25, -25));
1182 
1183     std::unique_ptr<Wrapland::Client::SubSurface> grandchild2Sub(
1184         m_subCompositor->createSubSurface(grandchild2.get(), child2.get()));
1185     grandchild2Sub->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
1186     grandchild2Sub->setPosition(QPoint(25, 25));
1187 
1188     // Now let's render both grandchildren.
1189     grandchild1->attachBuffer(m_shm->createBuffer(grandchildImage));
1190     grandchild1->damage(QRect(0, 0, 50, 50));
1191     grandchild1->commit(Wrapland::Client::Surface::CommitFlag::None);
1192 
1193     // Second grandchild's input region is subdivided into quadrants, with input mask on the top
1194     // left and bottom right.
1195     QRegion region;
1196     region += QRect(0, 0, 25, 25);
1197     region += QRect(25, 25, 25, 25);
1198     grandchild2->setInputRegion(m_compositor->createRegion(region).get());
1199 
1200     grandchild2->attachBuffer(m_shm->createBuffer(grandchildImage));
1201     grandchild2->damage(QRect(0, 0, 50, 50));
1202     grandchild2->commit(Wrapland::Client::Surface::CommitFlag::None);
1203 
1204     QSignalSpy parent_commit_spy(serverParent, &Wrapland::Server::Surface::committed);
1205     QVERIFY(parent_commit_spy.isValid());
1206     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
1207     QVERIFY(parent_commit_spy.wait());
1208 
1209     QCOMPARE(serverChild1->subsurface()->parentSurface(), serverParent);
1210     QCOMPARE(serverChild2->subsurface()->parentSurface(), serverParent);
1211     QCOMPARE(serverGrandchild1->subsurface()->parentSurface(), serverChild1);
1212     QCOMPARE(serverGrandchild2->subsurface()->parentSurface(), serverChild2);
1213 
1214     QVERIFY(serverChild1->isMapped());
1215     QVERIFY(serverChild2->isMapped());
1216     QVERIFY(serverGrandchild1->isMapped());
1217     QVERIFY(serverGrandchild2->isMapped());
1218 
1219     QSignalSpy commit_spy(serverParent, &Wrapland::Server::Surface::committed);
1220     QVERIFY(commit_spy.isValid());
1221     parent->commit(Wrapland::Client::Surface::CommitFlag::None);
1222     QVERIFY(commit_spy.wait());
1223 
1224     namespace WST = Wrapland::Server::Test;
1225 
1226     // Now test some positions.
1227     // Around top-left.
1228     QVERIFY(!WST::surface_at(serverParent, QPointF(-26, -25)));
1229     QVERIFY(!WST::surface_at(serverParent, QPointF(-25, -26)));
1230     QCOMPARE(WST::surface_at(serverParent, QPointF(-25, -25)), serverGrandchild1);
1231     QCOMPARE(WST::surface_at(serverParent, QPointF(0, 0)), serverGrandchild1);
1232 
1233     // Around middle.
1234     QCOMPARE(WST::surface_at(serverParent, QPointF(49, 49)), serverChild1);
1235     QCOMPARE(WST::surface_at(serverParent, QPointF(49, 75)), serverChild1);
1236     QCOMPARE(WST::surface_at(serverParent, QPointF(75, 49)), serverChild1);
1237     QCOMPARE(WST::surface_at(serverParent, QPointF(76, 49)), serverParent);
1238     QCOMPARE(WST::surface_at(serverParent, QPointF(49, 76)), serverParent);
1239     QCOMPARE(WST::surface_at(serverParent, QPointF(49, 100)), serverParent);
1240     QCOMPARE(WST::surface_at(serverParent, QPointF(100, 49)), serverParent);
1241     QCOMPARE(WST::surface_at(serverParent, QPointF(50, 50)), serverChild2);
1242     QCOMPARE(WST::surface_at(serverParent, QPointF(100, 50)), serverChild2);
1243     QCOMPARE(WST::surface_at(serverParent, QPointF(50, 100)), serverChild2);
1244     QCOMPARE(WST::surface_at(serverParent, QPointF(75, 75)), serverGrandchild2);
1245 
1246     // Around bottom-right.
1247     QCOMPARE(WST::surface_at(serverParent, QPointF(100, 100)), serverGrandchild2);
1248     QCOMPARE(WST::surface_at(serverParent, QPointF(125, 100)), serverGrandchild2);
1249     QCOMPARE(WST::surface_at(serverParent, QPointF(100, 125)), serverGrandchild2);
1250     QVERIFY(!WST::surface_at(serverParent, QPointF(126, 125)));
1251     QVERIFY(!WST::surface_at(serverParent, QPointF(125, 126)));
1252 
1253     // Now test some input positions.
1254     // Around top-left.
1255     QVERIFY(!WST::input_surface_at(serverParent, QPointF(-26, -25)));
1256     QVERIFY(!WST::input_surface_at(serverParent, QPointF(-25, -26)));
1257     QCOMPARE(WST::input_surface_at(serverParent, QPointF(-25, -25)), serverGrandchild1);
1258     QCOMPARE(WST::input_surface_at(serverParent, QPointF(0, 0)), serverGrandchild1);
1259 
1260     // Around middle.
1261     QCOMPARE(WST::input_surface_at(serverParent, QPointF(49, 49)), serverChild1);
1262     QCOMPARE(WST::input_surface_at(serverParent, QPointF(49, 75)), serverChild1);
1263     QCOMPARE(WST::input_surface_at(serverParent, QPointF(75, 49)), serverChild1);
1264     QCOMPARE(WST::input_surface_at(serverParent, QPointF(76, 49)), serverParent);
1265     QCOMPARE(WST::input_surface_at(serverParent, QPointF(49, 76)), serverParent);
1266     QCOMPARE(WST::input_surface_at(serverParent, QPointF(49, 100)), serverParent);
1267     QCOMPARE(WST::input_surface_at(serverParent, QPointF(100, 49)), serverParent);
1268     QCOMPARE(WST::input_surface_at(serverParent, QPointF(50, 50)), serverChild2);
1269     QCOMPARE(WST::input_surface_at(serverParent, QPointF(100, 50)), serverChild2);
1270     QCOMPARE(WST::input_surface_at(serverParent, QPointF(50, 100)), serverChild2);
1271     QCOMPARE(WST::input_surface_at(serverParent, QPointF(75, 75)), serverGrandchild2);
1272 
1273     // Around bottom-right.
1274     QCOMPARE(WST::input_surface_at(serverParent, QPointF(99, 99)), serverGrandchild2);
1275 
1276     // In Qt QRegions do not contain the right and bottom edge.
1277     QCOMPARE(WST::input_surface_at(serverParent, QPointF(99, 100)), serverChild2);
1278     QCOMPARE(WST::input_surface_at(serverParent, QPointF(100, 99)), serverChild2);
1279     QCOMPARE(WST::input_surface_at(serverParent, QPointF(125, 100)), serverChild2);
1280     QCOMPARE(WST::input_surface_at(serverParent, QPointF(100, 125)), serverChild2);
1281     QCOMPARE(WST::input_surface_at(serverParent, QPointF(125, 125)), serverChild2);
1282 
1283     QCOMPARE(WST::input_surface_at(serverParent, QPointF(99, 101)), serverChild2);
1284     QCOMPARE(WST::input_surface_at(serverParent, QPointF(101, 99)), serverChild2);
1285 
1286     QCOMPARE(WST::input_surface_at(serverParent, QPointF(75, 75)), serverGrandchild2);
1287     QCOMPARE(WST::input_surface_at(serverParent, QPointF(100, 100)), serverGrandchild2);
1288     QCOMPARE(WST::input_surface_at(serverParent, QPointF(101, 100)), serverGrandchild2);
1289     QCOMPARE(WST::input_surface_at(serverParent, QPointF(100, 101)), serverGrandchild2);
1290     QCOMPARE(WST::input_surface_at(serverParent, QPointF(101, 101)), serverGrandchild2);
1291     QCOMPARE(WST::input_surface_at(serverParent, QPointF(124, 124)), serverGrandchild2);
1292 
1293     QVERIFY(!WST::input_surface_at(serverParent, QPointF(126, 125)));
1294     QVERIFY(!WST::input_surface_at(serverParent, QPointF(125, 126)));
1295 }
1296 
testDestroyAttachedBuffer()1297 void TestSubsurface::testDestroyAttachedBuffer()
1298 {
1299     // this test verifies that destroying of a buffer attached to a sub-surface works
1300     using namespace Wrapland::Client;
1301     using namespace Wrapland::Server;
1302     // create surface
1303     QSignalSpy serverSurfaceCreated(m_serverCompositor,
1304                                     &Wrapland::Server::Compositor::surfaceCreated);
1305     QVERIFY(serverSurfaceCreated.isValid());
1306     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
1307     QVERIFY(serverSurfaceCreated.wait());
1308     std::unique_ptr<Wrapland::Client::Surface> child(m_compositor->createSurface());
1309     QVERIFY(serverSurfaceCreated.wait());
1310     auto serverChildSurface
1311         = serverSurfaceCreated.last().first().value<Wrapland::Server::Surface*>();
1312     // create sub-surface
1313     auto* sub = m_subCompositor->createSubSurface(child.get(), parent.get());
1314 
1315     // let's damage this surface, will be in sub-surface pending state
1316     QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
1317     image.fill(Qt::red);
1318     child->attachBuffer(m_shm->createBuffer(image));
1319     child->damage(QRect(0, 0, 100, 100));
1320     child->commit(Wrapland::Client::Surface::CommitFlag::None);
1321     m_connection->flush();
1322 
1323     // Let's try to destroy it
1324     QSignalSpy destroySpy(serverChildSurface, &QObject::destroyed);
1325     QVERIFY(destroySpy.isValid());
1326     delete m_shm;
1327     m_shm = nullptr;
1328     child.reset();
1329     QVERIFY(destroySpy.wait());
1330 
1331     delete sub;
1332 }
1333 
testDestroyParentSurface()1334 void TestSubsurface::testDestroyParentSurface()
1335 {
1336     // this test verifies that destroying a parent surface does not create problems
1337     // see BUG 389231
1338     using namespace Wrapland::Client;
1339     using namespace Wrapland::Server;
1340     // create surface
1341     QSignalSpy serverSurfaceCreated(m_serverCompositor,
1342                                     &Wrapland::Server::Compositor::surfaceCreated);
1343     QVERIFY(serverSurfaceCreated.isValid());
1344     std::unique_ptr<Wrapland::Client::Surface> parent(m_compositor->createSurface());
1345     QVERIFY(serverSurfaceCreated.wait());
1346     auto serverParentSurface
1347         = serverSurfaceCreated.last().first().value<Wrapland::Server::Surface*>();
1348     std::unique_ptr<Wrapland::Client::Surface> child(m_compositor->createSurface());
1349     QVERIFY(serverSurfaceCreated.wait());
1350     auto serverChildSurface
1351         = serverSurfaceCreated.last().first().value<Wrapland::Server::Surface*>();
1352     std::unique_ptr<Wrapland::Client::Surface> grandChild(m_compositor->createSurface());
1353     QVERIFY(serverSurfaceCreated.wait());
1354     auto serverGrandChildSurface
1355         = serverSurfaceCreated.last().first().value<Wrapland::Server::Surface*>();
1356     // create sub-surface in desynchronized mode as Qt uses them
1357     auto sub1 = m_subCompositor->createSubSurface(child.get(), parent.get());
1358     sub1->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
1359     auto sub2 = m_subCompositor->createSubSurface(grandChild.get(), child.get());
1360     sub2->setMode(Wrapland::Client::SubSurface::Mode::Desynchronized);
1361 
1362     // let's damage this surface
1363     // and at the same time delete the parent surface
1364     parent.reset();
1365     QSignalSpy parentDestroyedSpy(serverParentSurface, &QObject::destroyed);
1366     QVERIFY(parentDestroyedSpy.isValid());
1367     QVERIFY(parentDestroyedSpy.wait());
1368     QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
1369     image.fill(Qt::red);
1370     grandChild->attachBuffer(m_shm->createBuffer(image));
1371     grandChild->damage(QRect(0, 0, 100, 100));
1372     grandChild->commit(Wrapland::Client::Surface::CommitFlag::None);
1373     QSignalSpy commit_spy(serverGrandChildSurface, &Wrapland::Server::Surface::committed);
1374     QVERIFY(commit_spy.isValid());
1375     QVERIFY(commit_spy.wait());
1376 
1377     // Let's try to destroy it
1378     QSignalSpy destroySpy(serverChildSurface, &QObject::destroyed);
1379     QVERIFY(destroySpy.isValid());
1380     child.reset();
1381     QVERIFY(destroySpy.wait());
1382 
1383     delete sub1;
1384     delete sub2;
1385 }
1386 
1387 QTEST_GUILESS_MAIN(TestSubsurface)
1388 #include "subsurface.moc"
1389