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(®istry, SIGNAL(compositorAnnounced(quint32, quint32)));
125 QVERIFY(compositorSpy.isValid());
126 QSignalSpy subCompositorSpy(®istry, 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