File indexing completed on 2024-11-10 04:56:20
0001 /* 0002 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 // Qt 0007 #include <QSignalSpy> 0008 #include <QTest> 0009 // KWin 0010 #include "wayland/compositor.h" 0011 #include "wayland/display.h" 0012 #include "wayland/subcompositor.h" 0013 #include "wayland/surface.h" 0014 0015 #include "KWayland/Client/compositor.h" 0016 #include "KWayland/Client/connection_thread.h" 0017 #include "KWayland/Client/event_queue.h" 0018 #include "KWayland/Client/region.h" 0019 #include "KWayland/Client/registry.h" 0020 #include "KWayland/Client/shm_pool.h" 0021 #include "KWayland/Client/subcompositor.h" 0022 #include "KWayland/Client/subsurface.h" 0023 #include "KWayland/Client/surface.h" 0024 0025 // Wayland 0026 #include <wayland-client.h> 0027 0028 Q_DECLARE_METATYPE(KWayland::Client::SubSurface::Mode) 0029 0030 class TestSubSurface : public QObject 0031 { 0032 Q_OBJECT 0033 public: 0034 explicit TestSubSurface(QObject *parent = nullptr); 0035 private Q_SLOTS: 0036 void init(); 0037 void cleanup(); 0038 0039 void testCreate(); 0040 void testMode(); 0041 void testPosition_data(); 0042 void testPosition(); 0043 void testPlaceAbove(); 0044 void testPlaceBelow(); 0045 void testSyncMode(); 0046 void testDeSyncMode(); 0047 void testMainSurfaceFromTree(); 0048 void testRemoveSurface(); 0049 void testMappingOfSurfaceTree(); 0050 void testSurfaceAt(); 0051 void testDestroyAttachedBuffer(); 0052 void testDestroyParentSurface(); 0053 0054 private: 0055 KWin::Display *m_display; 0056 KWin::CompositorInterface *m_compositorInterface; 0057 KWin::SubCompositorInterface *m_subcompositorInterface; 0058 KWayland::Client::ConnectionThread *m_connection; 0059 KWayland::Client::Compositor *m_compositor; 0060 KWayland::Client::ShmPool *m_shm; 0061 KWayland::Client::SubCompositor *m_subCompositor; 0062 KWayland::Client::EventQueue *m_queue; 0063 QThread *m_thread; 0064 }; 0065 0066 static const QString s_socketName = QStringLiteral("kwayland-test-wayland-subsurface-0"); 0067 0068 TestSubSurface::TestSubSurface(QObject *parent) 0069 : QObject(parent) 0070 , m_display(nullptr) 0071 , m_compositorInterface(nullptr) 0072 , m_subcompositorInterface(nullptr) 0073 , m_connection(nullptr) 0074 , m_compositor(nullptr) 0075 , m_shm(nullptr) 0076 , m_subCompositor(nullptr) 0077 , m_queue(nullptr) 0078 , m_thread(nullptr) 0079 { 0080 } 0081 0082 void TestSubSurface::init() 0083 { 0084 using namespace KWin; 0085 delete m_display; 0086 m_display = new KWin::Display(this); 0087 m_display->addSocketName(s_socketName); 0088 m_display->start(); 0089 QVERIFY(m_display->isRunning()); 0090 m_display->createShm(); 0091 0092 // setup connection 0093 m_connection = new KWayland::Client::ConnectionThread; 0094 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected); 0095 m_connection->setSocketName(s_socketName); 0096 0097 m_thread = new QThread(this); 0098 m_connection->moveToThread(m_thread); 0099 m_thread->start(); 0100 0101 m_connection->initConnection(); 0102 QVERIFY(connectedSpy.wait()); 0103 0104 m_queue = new KWayland::Client::EventQueue(this); 0105 QVERIFY(!m_queue->isValid()); 0106 m_queue->setup(m_connection); 0107 QVERIFY(m_queue->isValid()); 0108 0109 KWayland::Client::Registry registry; 0110 QSignalSpy compositorSpy(®istry, &KWayland::Client::Registry::compositorAnnounced); 0111 QSignalSpy subCompositorSpy(®istry, &KWayland::Client::Registry::subCompositorAnnounced); 0112 QVERIFY(!registry.eventQueue()); 0113 registry.setEventQueue(m_queue); 0114 QCOMPARE(registry.eventQueue(), m_queue); 0115 registry.create(m_connection->display()); 0116 QVERIFY(registry.isValid()); 0117 registry.setup(); 0118 0119 m_compositorInterface = new CompositorInterface(m_display, m_display); 0120 m_subcompositorInterface = new SubCompositorInterface(m_display, m_display); 0121 QVERIFY(m_subcompositorInterface); 0122 0123 QVERIFY(subCompositorSpy.wait()); 0124 m_subCompositor = registry.createSubCompositor(subCompositorSpy.first().first().value<quint32>(), subCompositorSpy.first().last().value<quint32>(), this); 0125 0126 if (compositorSpy.isEmpty()) { 0127 QVERIFY(compositorSpy.wait()); 0128 } 0129 m_compositor = registry.createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this); 0130 0131 m_shm = registry.createShmPool(registry.interface(KWayland::Client::Registry::Interface::Shm).name, 0132 registry.interface(KWayland::Client::Registry::Interface::Shm).version, 0133 this); 0134 QVERIFY(m_shm->isValid()); 0135 } 0136 0137 void TestSubSurface::cleanup() 0138 { 0139 if (m_shm) { 0140 delete m_shm; 0141 m_shm = nullptr; 0142 } 0143 if (m_subCompositor) { 0144 delete m_subCompositor; 0145 m_subCompositor = nullptr; 0146 } 0147 if (m_compositor) { 0148 delete m_compositor; 0149 m_compositor = nullptr; 0150 } 0151 if (m_queue) { 0152 delete m_queue; 0153 m_queue = nullptr; 0154 } 0155 if (m_thread) { 0156 m_thread->quit(); 0157 m_thread->wait(); 0158 delete m_thread; 0159 m_thread = nullptr; 0160 } 0161 delete m_connection; 0162 m_connection = nullptr; 0163 0164 delete m_display; 0165 m_display = nullptr; 0166 } 0167 0168 void TestSubSurface::testCreate() 0169 { 0170 using namespace KWin; 0171 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated); 0172 0173 // create two Surfaces 0174 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0175 QVERIFY(surfaceCreatedSpy.wait()); 0176 SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>(); 0177 QVERIFY(serverSurface); 0178 0179 surfaceCreatedSpy.clear(); 0180 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface()); 0181 QVERIFY(surfaceCreatedSpy.wait()); 0182 SurfaceInterface *serverParentSurface = surfaceCreatedSpy.first().first().value<KWin::SurfaceInterface *>(); 0183 QVERIFY(serverParentSurface); 0184 0185 QSignalSpy subSurfaceCreatedSpy(m_subcompositorInterface, &KWin::SubCompositorInterface::subSurfaceCreated); 0186 0187 // create subSurface for surface of parent 0188 std::unique_ptr<KWayland::Client::SubSurface> subSurface(m_subCompositor->createSubSurface(surface.get(), parent.get())); 0189 0190 QVERIFY(subSurfaceCreatedSpy.wait()); 0191 SubSurfaceInterface *serverSubSurface = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>(); 0192 QVERIFY(serverSubSurface); 0193 QVERIFY(serverSubSurface->parentSurface()); 0194 QCOMPARE(serverSubSurface->parentSurface(), serverParentSurface); 0195 QCOMPARE(serverSubSurface->surface(), serverSurface); 0196 QCOMPARE(serverSurface->subSurface(), serverSubSurface); 0197 QCOMPARE(serverSubSurface->mainSurface(), serverParentSurface); 0198 // children are only added after committing the surface 0199 QCOMPARE(serverParentSurface->below().count(), 0); 0200 QEXPECT_FAIL("", "Incorrect adding of child windows to workaround QtWayland behavior", Continue); 0201 QCOMPARE(serverParentSurface->above().count(), 0); 0202 // so let's commit the surface, to apply the stacking change 0203 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0204 wl_display_flush(m_connection->display()); 0205 QCoreApplication::processEvents(); 0206 QCOMPARE(serverParentSurface->below().count(), 0); 0207 QCOMPARE(serverParentSurface->above().count(), 1); 0208 QCOMPARE(serverParentSurface->above().constFirst(), serverSubSurface); 0209 0210 // and let's destroy it again 0211 QSignalSpy destroyedSpy(serverSubSurface, &QObject::destroyed); 0212 subSurface.reset(); 0213 QVERIFY(destroyedSpy.wait()); 0214 QCOMPARE(serverSurface->subSurface(), QPointer<SubSurfaceInterface>()); 0215 // only applied after next commit 0216 QCOMPARE(serverParentSurface->below().count(), 0); 0217 QEXPECT_FAIL("", "Incorrect removing of child windows to workaround QtWayland behavior", Continue); 0218 QCOMPARE(serverParentSurface->above().count(), 1); 0219 // but the surface should be invalid 0220 if (!serverParentSurface->above().isEmpty()) { 0221 QVERIFY(!serverParentSurface->above().constFirst()); 0222 } 0223 // committing the state should solve it 0224 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0225 wl_display_flush(m_connection->display()); 0226 QCoreApplication::processEvents(); 0227 QCOMPARE(serverParentSurface->below().count(), 0); 0228 QCOMPARE(serverParentSurface->above().count(), 0); 0229 } 0230 0231 void TestSubSurface::testMode() 0232 { 0233 using namespace KWin; 0234 // create two Surface 0235 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0236 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface()); 0237 0238 QSignalSpy subSurfaceCreatedSpy(m_subcompositorInterface, &KWin::SubCompositorInterface::subSurfaceCreated); 0239 0240 // create the SubSurface for surface of parent 0241 std::unique_ptr<KWayland::Client::SubSurface> subSurface(m_subCompositor->createSubSurface(surface.get(), parent.get())); 0242 QVERIFY(subSurfaceCreatedSpy.wait()); 0243 SubSurfaceInterface *serverSubSurface = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>(); 0244 QVERIFY(serverSubSurface); 0245 0246 // both client and server subsurface should be in synchronized mode 0247 QCOMPARE(subSurface->mode(), KWayland::Client::SubSurface::Mode::Synchronized); 0248 QCOMPARE(serverSubSurface->mode(), SubSurfaceInterface::Mode::Synchronized); 0249 0250 // verify that we can change to desynchronized 0251 QSignalSpy modeChangedSpy(serverSubSurface, &KWin::SubSurfaceInterface::modeChanged); 0252 0253 subSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 0254 QCOMPARE(subSurface->mode(), KWayland::Client::SubSurface::Mode::Desynchronized); 0255 0256 QVERIFY(modeChangedSpy.wait()); 0257 QCOMPARE(modeChangedSpy.first().first().value<KWin::SubSurfaceInterface::Mode>(), SubSurfaceInterface::Mode::Desynchronized); 0258 QCOMPARE(serverSubSurface->mode(), SubSurfaceInterface::Mode::Desynchronized); 0259 0260 // setting the same again won't change 0261 subSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 0262 QCOMPARE(subSurface->mode(), KWayland::Client::SubSurface::Mode::Desynchronized); 0263 // not testing the signal, we do that after changing to synchronized 0264 0265 // and change back to synchronized 0266 subSurface->setMode(KWayland::Client::SubSurface::Mode::Synchronized); 0267 QCOMPARE(subSurface->mode(), KWayland::Client::SubSurface::Mode::Synchronized); 0268 0269 QVERIFY(modeChangedSpy.wait()); 0270 QCOMPARE(modeChangedSpy.count(), 2); 0271 QCOMPARE(modeChangedSpy.first().first().value<KWin::SubSurfaceInterface::Mode>(), SubSurfaceInterface::Mode::Desynchronized); 0272 QCOMPARE(modeChangedSpy.last().first().value<KWin::SubSurfaceInterface::Mode>(), SubSurfaceInterface::Mode::Synchronized); 0273 QCOMPARE(serverSubSurface->mode(), SubSurfaceInterface::Mode::Synchronized); 0274 } 0275 0276 void TestSubSurface::testPosition_data() 0277 { 0278 QTest::addColumn<KWayland::Client::SubSurface::Mode>("commitMode"); 0279 0280 QTest::addRow("sync") << KWayland::Client::SubSurface::Mode::Synchronized; 0281 QTest::addRow("desync") << KWayland::Client::SubSurface::Mode::Desynchronized; 0282 } 0283 0284 void TestSubSurface::testPosition() 0285 { 0286 using namespace KWin; 0287 // create two Surface 0288 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0289 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface()); 0290 0291 QSignalSpy subSurfaceCreatedSpy(m_subcompositorInterface, &KWin::SubCompositorInterface::subSurfaceCreated); 0292 0293 // create the SubSurface for surface of parent 0294 std::unique_ptr<KWayland::Client::SubSurface> subSurface(m_subCompositor->createSubSurface(surface.get(), parent.get())); 0295 QVERIFY(subSurfaceCreatedSpy.wait()); 0296 SubSurfaceInterface *serverSubSurface = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>(); 0297 QVERIFY(serverSubSurface); 0298 0299 // put the subsurface in the desired commit mode 0300 QFETCH(KWayland::Client::SubSurface::Mode, commitMode); 0301 subSurface->setMode(commitMode); 0302 0303 // both client and server should have a default position 0304 QCOMPARE(subSurface->position(), QPoint()); 0305 QCOMPARE(serverSubSurface->position(), QPoint()); 0306 0307 QSignalSpy positionChangedSpy(serverSubSurface, &KWin::SubSurfaceInterface::positionChanged); 0308 0309 // changing the position should not trigger a direct update on server side 0310 subSurface->setPosition(QPoint(10, 20)); 0311 QCOMPARE(subSurface->position(), QPoint(10, 20)); 0312 // ensure it's processed on server side 0313 wl_display_flush(m_connection->display()); 0314 QCoreApplication::processEvents(); 0315 QCOMPARE(serverSubSurface->position(), QPoint()); 0316 // changing once more 0317 subSurface->setPosition(QPoint(20, 30)); 0318 QCOMPARE(subSurface->position(), QPoint(20, 30)); 0319 // ensure it's processed on server side 0320 wl_display_flush(m_connection->display()); 0321 QCoreApplication::processEvents(); 0322 QCOMPARE(serverSubSurface->position(), QPoint()); 0323 0324 // committing the parent surface should update the position 0325 QSignalSpy parentCommittedSpy(serverSubSurface->parentSurface(), &SurfaceInterface::committed); 0326 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0327 QVERIFY(parentCommittedSpy.wait()); 0328 QCOMPARE(positionChangedSpy.count(), 1); 0329 QCOMPARE(positionChangedSpy.first().first().toPoint(), QPoint(20, 30)); 0330 QCOMPARE(serverSubSurface->position(), QPoint(20, 30)); 0331 } 0332 0333 void TestSubSurface::testPlaceAbove() 0334 { 0335 using namespace KWin; 0336 // create needed Surfaces (one parent, three client 0337 std::unique_ptr<KWayland::Client::Surface> surface1(m_compositor->createSurface()); 0338 std::unique_ptr<KWayland::Client::Surface> surface2(m_compositor->createSurface()); 0339 std::unique_ptr<KWayland::Client::Surface> surface3(m_compositor->createSurface()); 0340 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface()); 0341 0342 QSignalSpy subSurfaceCreatedSpy(m_subcompositorInterface, &KWin::SubCompositorInterface::subSurfaceCreated); 0343 0344 // create the SubSurfaces for surface of parent 0345 std::unique_ptr<KWayland::Client::SubSurface> subSurface1(m_subCompositor->createSubSurface(surface1.get(), parent.get())); 0346 QVERIFY(subSurfaceCreatedSpy.wait()); 0347 SubSurfaceInterface *serverSubSurface1 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>(); 0348 QVERIFY(serverSubSurface1); 0349 subSurfaceCreatedSpy.clear(); 0350 std::unique_ptr<KWayland::Client::SubSurface> subSurface2(m_subCompositor->createSubSurface(surface2.get(), parent.get())); 0351 QVERIFY(subSurfaceCreatedSpy.wait()); 0352 SubSurfaceInterface *serverSubSurface2 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>(); 0353 QVERIFY(serverSubSurface2); 0354 subSurfaceCreatedSpy.clear(); 0355 std::unique_ptr<KWayland::Client::SubSurface> subSurface3(m_subCompositor->createSubSurface(surface3.get(), parent.get())); 0356 QVERIFY(subSurfaceCreatedSpy.wait()); 0357 SubSurfaceInterface *serverSubSurface3 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>(); 0358 QVERIFY(serverSubSurface3); 0359 subSurfaceCreatedSpy.clear(); 0360 0361 // so far the stacking order should still be empty 0362 QVERIFY(serverSubSurface1->parentSurface()->below().isEmpty()); 0363 QEXPECT_FAIL("", "Incorrect adding of child windows to workaround QtWayland behavior", Continue); 0364 QVERIFY(serverSubSurface1->parentSurface()->above().isEmpty()); 0365 0366 // committing the parent should create the stacking order 0367 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0368 // ensure it's processed on server side 0369 wl_display_flush(m_connection->display()); 0370 QCoreApplication::processEvents(); 0371 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 0); 0372 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3); 0373 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1); 0374 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2); 0375 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface3); 0376 0377 // raising subsurface1 should place it to top of stack 0378 subSurface1->placeAbove(subSurface3.get()); 0379 // ensure it's processed on server side 0380 wl_display_flush(m_connection->display()); 0381 QCoreApplication::processEvents(); 0382 // but as long as parent is not committed it shouldn't change on server side 0383 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1); 0384 // after commit it's changed 0385 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0386 wl_display_flush(m_connection->display()); 0387 QCoreApplication::processEvents(); 0388 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3); 0389 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2); 0390 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface3); 0391 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1); 0392 0393 // try placing 3 above 1, should result in 2, 1, 3 0394 subSurface3->placeAbove(subSurface1.get()); 0395 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0396 wl_display_flush(m_connection->display()); 0397 QCoreApplication::processEvents(); 0398 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3); 0399 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2); 0400 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface1); 0401 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface3); 0402 0403 // try placing 3 above 2, should result in 2, 3, 1 0404 subSurface3->placeAbove(subSurface2.get()); 0405 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0406 wl_display_flush(m_connection->display()); 0407 QCoreApplication::processEvents(); 0408 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3); 0409 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2); 0410 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface3); 0411 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1); 0412 0413 // try placing 1 above 3 - shouldn't change 0414 subSurface1->placeAbove(subSurface3.get()); 0415 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0416 wl_display_flush(m_connection->display()); 0417 QCoreApplication::processEvents(); 0418 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3); 0419 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2); 0420 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface3); 0421 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1); 0422 0423 // and 2 above 3 - > 3, 2, 1 0424 subSurface2->placeAbove(subSurface3.get()); 0425 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0426 wl_display_flush(m_connection->display()); 0427 QCoreApplication::processEvents(); 0428 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3); 0429 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface3); 0430 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2); 0431 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1); 0432 } 0433 0434 void TestSubSurface::testPlaceBelow() 0435 { 0436 using namespace KWin; 0437 // create needed Surfaces (one parent, three client 0438 std::unique_ptr<KWayland::Client::Surface> surface1(m_compositor->createSurface()); 0439 std::unique_ptr<KWayland::Client::Surface> surface2(m_compositor->createSurface()); 0440 std::unique_ptr<KWayland::Client::Surface> surface3(m_compositor->createSurface()); 0441 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface()); 0442 0443 QSignalSpy subSurfaceCreatedSpy(m_subcompositorInterface, &KWin::SubCompositorInterface::subSurfaceCreated); 0444 0445 // create the SubSurfaces for surface of parent 0446 std::unique_ptr<KWayland::Client::SubSurface> subSurface1(m_subCompositor->createSubSurface(surface1.get(), parent.get())); 0447 QVERIFY(subSurfaceCreatedSpy.wait()); 0448 SubSurfaceInterface *serverSubSurface1 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>(); 0449 QVERIFY(serverSubSurface1); 0450 subSurfaceCreatedSpy.clear(); 0451 std::unique_ptr<KWayland::Client::SubSurface> subSurface2(m_subCompositor->createSubSurface(surface2.get(), parent.get())); 0452 QVERIFY(subSurfaceCreatedSpy.wait()); 0453 SubSurfaceInterface *serverSubSurface2 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>(); 0454 QVERIFY(serverSubSurface2); 0455 subSurfaceCreatedSpy.clear(); 0456 std::unique_ptr<KWayland::Client::SubSurface> subSurface3(m_subCompositor->createSubSurface(surface3.get(), parent.get())); 0457 QVERIFY(subSurfaceCreatedSpy.wait()); 0458 SubSurfaceInterface *serverSubSurface3 = subSurfaceCreatedSpy.first().first().value<KWin::SubSurfaceInterface *>(); 0459 QVERIFY(serverSubSurface3); 0460 subSurfaceCreatedSpy.clear(); 0461 0462 // so far the stacking order should still be empty 0463 QVERIFY(serverSubSurface1->parentSurface()->below().isEmpty()); 0464 QEXPECT_FAIL("", "Incorrect adding of child windows to workaround QtWayland behavior", Continue); 0465 QVERIFY(serverSubSurface1->parentSurface()->above().isEmpty()); 0466 0467 // committing the parent should create the stacking order 0468 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0469 // ensure it's processed on server side 0470 wl_display_flush(m_connection->display()); 0471 QCoreApplication::processEvents(); 0472 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3); 0473 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1); 0474 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2); 0475 QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface3); 0476 0477 // lowering subsurface3 should place it to the bottom of stack 0478 subSurface3->lower(); 0479 // ensure it's processed on server side 0480 wl_display_flush(m_connection->display()); 0481 QCoreApplication::processEvents(); 0482 // but as long as parent is not committed it shouldn't change on server side 0483 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1); 0484 // after commit it's changed 0485 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0486 wl_display_flush(m_connection->display()); 0487 QCoreApplication::processEvents(); 0488 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 1); 0489 QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface3); 0490 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 2); 0491 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1); 0492 QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2); 0493 0494 // place 1 below 3 -> 1, 3, 2 0495 subSurface1->placeBelow(subSurface3.get()); 0496 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0497 wl_display_flush(m_connection->display()); 0498 QCoreApplication::processEvents(); 0499 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 2); 0500 QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface1); 0501 QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface3); 0502 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 1); 0503 QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2); 0504 0505 // 2 below 3 -> 1, 2, 3 0506 subSurface2->placeBelow(subSurface3.get()); 0507 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0508 wl_display_flush(m_connection->display()); 0509 QCoreApplication::processEvents(); 0510 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 3); 0511 QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface1); 0512 QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface2); 0513 QCOMPARE(serverSubSurface1->parentSurface()->below().at(2), serverSubSurface3); 0514 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 0); 0515 0516 // 1 below 2 -> shouldn't change 0517 subSurface1->placeBelow(subSurface2.get()); 0518 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0519 wl_display_flush(m_connection->display()); 0520 QCoreApplication::processEvents(); 0521 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 3); 0522 QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface1); 0523 QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface2); 0524 QCOMPARE(serverSubSurface1->parentSurface()->below().at(2), serverSubSurface3); 0525 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 0); 0526 0527 // and 3 below 1 -> 3, 1, 2 0528 subSurface3->placeBelow(subSurface1.get()); 0529 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0530 wl_display_flush(m_connection->display()); 0531 QCoreApplication::processEvents(); 0532 QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 3); 0533 QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface3); 0534 QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface1); 0535 QCOMPARE(serverSubSurface1->parentSurface()->below().at(2), serverSubSurface2); 0536 QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 0); 0537 } 0538 0539 void TestSubSurface::testSyncMode() 0540 { 0541 // this test verifies that state is only applied when the parent surface commits its pending state 0542 using namespace KWin; 0543 0544 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); 0545 0546 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0547 QVERIFY(surfaceCreatedSpy.wait()); 0548 auto childSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>(); 0549 QVERIFY(childSurface); 0550 0551 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface()); 0552 QVERIFY(surfaceCreatedSpy.wait()); 0553 auto parentSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0554 QVERIFY(parentSurface); 0555 // create subSurface for surface of parent 0556 std::unique_ptr<KWayland::Client::SubSurface> subSurface(m_subCompositor->createSubSurface(surface.get(), parent.get())); 0557 0558 // let's damage the child surface 0559 QSignalSpy childDamagedSpy(childSurface, &SurfaceInterface::damaged); 0560 0561 QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied); 0562 image.fill(Qt::black); 0563 surface->attachBuffer(m_shm->createBuffer(image)); 0564 surface->damage(QRect(0, 0, 200, 200)); 0565 surface->commit(); 0566 0567 // state should be applied when the parent surface's state gets applied 0568 QVERIFY(!childDamagedSpy.wait(100)); 0569 QVERIFY(!childSurface->buffer()); 0570 0571 QVERIFY(!childSurface->isMapped()); 0572 QVERIFY(!parentSurface->isMapped()); 0573 0574 QImage image2(QSize(400, 400), QImage::Format_ARGB32_Premultiplied); 0575 image2.fill(Qt::red); 0576 parent->attachBuffer(m_shm->createBuffer(image2)); 0577 parent->damage(QRect(0, 0, 400, 400)); 0578 parent->commit(); 0579 QVERIFY(childDamagedSpy.wait()); 0580 QCOMPARE(childDamagedSpy.count(), 1); 0581 QVERIFY(childSurface->isMapped()); 0582 QVERIFY(parentSurface->isMapped()); 0583 } 0584 0585 void TestSubSurface::testDeSyncMode() 0586 { 0587 // this test verifies that state gets applied immediately in desync mode 0588 using namespace KWin; 0589 0590 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); 0591 0592 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0593 QVERIFY(surfaceCreatedSpy.wait()); 0594 auto childSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>(); 0595 QVERIFY(childSurface); 0596 0597 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface()); 0598 QVERIFY(surfaceCreatedSpy.wait()); 0599 auto parentSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0600 QVERIFY(parentSurface); 0601 // create subSurface for surface of parent 0602 std::unique_ptr<KWayland::Client::SubSurface> subSurface(m_subCompositor->createSubSurface(surface.get(), parent.get())); 0603 0604 // let's damage the child surface 0605 QSignalSpy childDamagedSpy(childSurface, &SurfaceInterface::damaged); 0606 0607 QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied); 0608 image.fill(Qt::black); 0609 surface->attachBuffer(m_shm->createBuffer(image)); 0610 surface->damage(QRect(0, 0, 200, 200)); 0611 surface->commit(KWayland::Client::Surface::CommitFlag::None); 0612 0613 // state should be applied when the parent surface's state gets applied or when the subsurface switches to desync 0614 QVERIFY(!childDamagedSpy.wait(100)); 0615 QVERIFY(!childSurface->isMapped()); 0616 QVERIFY(!parentSurface->isMapped()); 0617 0618 // setting to desync should apply the state directly 0619 subSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 0620 QVERIFY(childDamagedSpy.wait()); 0621 QVERIFY(!childSurface->isMapped()); 0622 QVERIFY(!parentSurface->isMapped()); 0623 0624 // and damaging again, should directly be applied 0625 image.fill(Qt::red); 0626 surface->attachBuffer(m_shm->createBuffer(image)); 0627 surface->damage(QRect(0, 0, 200, 200)); 0628 surface->commit(KWayland::Client::Surface::CommitFlag::None); 0629 QVERIFY(childDamagedSpy.wait()); 0630 } 0631 0632 void TestSubSurface::testMainSurfaceFromTree() 0633 { 0634 // this test verifies that in a tree of surfaces every surface has the same main surface 0635 using namespace KWin; 0636 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); 0637 0638 std::unique_ptr<KWayland::Client::Surface> parentSurface(m_compositor->createSurface()); 0639 QVERIFY(surfaceCreatedSpy.wait()); 0640 auto parentServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0641 QVERIFY(parentServerSurface); 0642 std::unique_ptr<KWayland::Client::Surface> childLevel1Surface(m_compositor->createSurface()); 0643 QVERIFY(surfaceCreatedSpy.wait()); 0644 auto childLevel1ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0645 QVERIFY(childLevel1ServerSurface); 0646 std::unique_ptr<KWayland::Client::Surface> childLevel2Surface(m_compositor->createSurface()); 0647 QVERIFY(surfaceCreatedSpy.wait()); 0648 auto childLevel2ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0649 QVERIFY(childLevel2ServerSurface); 0650 std::unique_ptr<KWayland::Client::Surface> childLevel3Surface(m_compositor->createSurface()); 0651 QVERIFY(surfaceCreatedSpy.wait()); 0652 auto childLevel3ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0653 QVERIFY(childLevel3ServerSurface); 0654 0655 m_subCompositor->createSubSurface(childLevel1Surface.get(), parentSurface.get()); 0656 m_subCompositor->createSubSurface(childLevel2Surface.get(), childLevel1Surface.get()); 0657 m_subCompositor->createSubSurface(childLevel3Surface.get(), childLevel2Surface.get()); 0658 0659 QSignalSpy parentCommittedSpy(parentServerSurface, &SurfaceInterface::committed); 0660 parentSurface->commit(KWayland::Client::Surface::CommitFlag::None); 0661 QVERIFY(parentCommittedSpy.wait()); 0662 0663 QCOMPARE(parentServerSurface->below().count(), 0); 0664 QCOMPARE(parentServerSurface->above().count(), 1); 0665 auto child = parentServerSurface->above().constFirst(); 0666 QCOMPARE(child->parentSurface(), parentServerSurface); 0667 QCOMPARE(child->mainSurface(), parentServerSurface); 0668 QCOMPARE(child->surface()->below().count(), 0); 0669 QCOMPARE(child->surface()->above().count(), 1); 0670 auto child2 = child->surface()->above().constFirst(); 0671 QCOMPARE(child2->parentSurface(), child->surface()); 0672 QCOMPARE(child2->mainSurface(), parentServerSurface); 0673 QCOMPARE(child2->surface()->below().count(), 0); 0674 QCOMPARE(child2->surface()->above().count(), 1); 0675 auto child3 = child2->surface()->above().constFirst(); 0676 QCOMPARE(child3->parentSurface(), child2->surface()); 0677 QCOMPARE(child3->mainSurface(), parentServerSurface); 0678 QCOMPARE(child3->surface()->below().count(), 0); 0679 QCOMPARE(child3->surface()->above().count(), 0); 0680 } 0681 0682 void TestSubSurface::testRemoveSurface() 0683 { 0684 // this test verifies that removing the surface also removes the sub-surface from the parent 0685 using namespace KWin; 0686 0687 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); 0688 0689 std::unique_ptr<KWayland::Client::Surface> parentSurface(m_compositor->createSurface()); 0690 QVERIFY(surfaceCreatedSpy.wait()); 0691 auto parentServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0692 QVERIFY(parentServerSurface); 0693 std::unique_ptr<KWayland::Client::Surface> childSurface(m_compositor->createSurface()); 0694 QVERIFY(surfaceCreatedSpy.wait()); 0695 auto childServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0696 QVERIFY(childServerSurface); 0697 0698 QSignalSpy childrenChangedSpy(parentServerSurface, &SurfaceInterface::childSubSurfacesChanged); 0699 0700 m_subCompositor->createSubSurface(childSurface.get(), parentSurface.get()); 0701 parentSurface->commit(KWayland::Client::Surface::CommitFlag::None); 0702 QVERIFY(childrenChangedSpy.wait()); 0703 0704 QCOMPARE(parentServerSurface->below().count(), 0); 0705 QCOMPARE(parentServerSurface->above().count(), 1); 0706 0707 // destroy surface, takes place immediately 0708 childSurface.reset(); 0709 QVERIFY(childrenChangedSpy.wait()); 0710 QCOMPARE(parentServerSurface->below().count(), 0); 0711 QCOMPARE(parentServerSurface->above().count(), 0); 0712 } 0713 0714 void TestSubSurface::testMappingOfSurfaceTree() 0715 { 0716 // this test verifies mapping and unmapping of a sub-surface tree 0717 using namespace KWin; 0718 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); 0719 0720 std::unique_ptr<KWayland::Client::Surface> parentSurface(m_compositor->createSurface()); 0721 QVERIFY(surfaceCreatedSpy.wait()); 0722 auto parentServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0723 QVERIFY(parentServerSurface); 0724 std::unique_ptr<KWayland::Client::Surface> childLevel1Surface(m_compositor->createSurface()); 0725 QVERIFY(surfaceCreatedSpy.wait()); 0726 auto childLevel1ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0727 QVERIFY(childLevel1ServerSurface); 0728 std::unique_ptr<KWayland::Client::Surface> childLevel2Surface(m_compositor->createSurface()); 0729 QVERIFY(surfaceCreatedSpy.wait()); 0730 auto childLevel2ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0731 QVERIFY(childLevel2ServerSurface); 0732 std::unique_ptr<KWayland::Client::Surface> childLevel3Surface(m_compositor->createSurface()); 0733 QVERIFY(surfaceCreatedSpy.wait()); 0734 auto childLevel3ServerSurface = surfaceCreatedSpy.last().first().value<SurfaceInterface *>(); 0735 QVERIFY(childLevel3ServerSurface); 0736 0737 auto subSurfaceLevel1 = m_subCompositor->createSubSurface(childLevel1Surface.get(), parentSurface.get()); 0738 auto subSurfaceLevel2 = m_subCompositor->createSubSurface(childLevel2Surface.get(), childLevel1Surface.get()); 0739 auto subSurfaceLevel3 = m_subCompositor->createSubSurface(childLevel3Surface.get(), childLevel2Surface.get()); 0740 0741 QSignalSpy parentCommittedSpy(parentServerSurface, &SurfaceInterface::committed); 0742 parentSurface->commit(KWayland::Client::Surface::CommitFlag::None); 0743 QVERIFY(parentCommittedSpy.wait()); 0744 0745 QCOMPARE(parentServerSurface->below().count(), 0); 0746 QCOMPARE(parentServerSurface->above().count(), 1); 0747 auto child = parentServerSurface->above().constFirst(); 0748 QCOMPARE(child->surface()->below().count(), 0); 0749 QCOMPARE(child->surface()->above().count(), 1); 0750 auto child2 = child->surface()->above().constFirst(); 0751 QCOMPARE(child2->surface()->below().count(), 0); 0752 QCOMPARE(child2->surface()->above().count(), 1); 0753 auto child3 = child2->surface()->above().constFirst(); 0754 QCOMPARE(child3->parentSurface(), child2->surface()); 0755 QCOMPARE(child3->mainSurface(), parentServerSurface); 0756 QCOMPARE(child3->surface()->below().count(), 0); 0757 QCOMPARE(child3->surface()->above().count(), 0); 0758 0759 // so far no surface is mapped 0760 QVERIFY(!parentServerSurface->isMapped()); 0761 QVERIFY(!child->surface()->isMapped()); 0762 QVERIFY(!child2->surface()->isMapped()); 0763 QVERIFY(!child3->surface()->isMapped()); 0764 0765 // first set all subsurfaces to desync, to simplify 0766 subSurfaceLevel1->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 0767 subSurfaceLevel2->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 0768 subSurfaceLevel3->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 0769 0770 // first map the child, should not map it 0771 QSignalSpy child3DamageSpy(child3->surface(), &SurfaceInterface::damaged); 0772 QImage image(QSize(200, 200), QImage::Format_ARGB32_Premultiplied); 0773 image.fill(Qt::black); 0774 childLevel3Surface->attachBuffer(m_shm->createBuffer(image)); 0775 childLevel3Surface->damage(QRect(0, 0, 200, 200)); 0776 childLevel3Surface->commit(KWayland::Client::Surface::CommitFlag::None); 0777 QVERIFY(child3DamageSpy.wait()); 0778 QVERIFY(child3->surface()->buffer()); 0779 QVERIFY(!child3->surface()->isMapped()); 0780 0781 // let's map the top level 0782 QSignalSpy parentSpy(parentServerSurface, &SurfaceInterface::damaged); 0783 parentSurface->attachBuffer(m_shm->createBuffer(image)); 0784 parentSurface->damage(QRect(0, 0, 200, 200)); 0785 parentSurface->commit(KWayland::Client::Surface::CommitFlag::None); 0786 QVERIFY(parentSpy.wait()); 0787 QVERIFY(parentServerSurface->isMapped()); 0788 // children should not yet be mapped 0789 QVERIFY(!child->surface()->isMapped()); 0790 QVERIFY(!child2->surface()->isMapped()); 0791 QVERIFY(!child3->surface()->isMapped()); 0792 0793 // next level 0794 QSignalSpy child2DamageSpy(child2->surface(), &SurfaceInterface::damaged); 0795 childLevel2Surface->attachBuffer(m_shm->createBuffer(image)); 0796 childLevel2Surface->damage(QRect(0, 0, 200, 200)); 0797 childLevel2Surface->commit(KWayland::Client::Surface::CommitFlag::None); 0798 QVERIFY(child2DamageSpy.wait()); 0799 QVERIFY(parentServerSurface->isMapped()); 0800 // children should not yet be mapped 0801 QVERIFY(!child->surface()->isMapped()); 0802 QVERIFY(!child2->surface()->isMapped()); 0803 QVERIFY(!child3->surface()->isMapped()); 0804 0805 // last but not least the first child level, which should map all our subsurfaces 0806 QSignalSpy child1DamageSpy(child->surface(), &SurfaceInterface::damaged); 0807 childLevel1Surface->attachBuffer(m_shm->createBuffer(image)); 0808 childLevel1Surface->damage(QRect(0, 0, 200, 200)); 0809 childLevel1Surface->commit(KWayland::Client::Surface::CommitFlag::None); 0810 QVERIFY(child1DamageSpy.wait()); 0811 0812 // everything is mapped 0813 QVERIFY(parentServerSurface->isMapped()); 0814 QVERIFY(child->surface()->isMapped()); 0815 QVERIFY(child2->surface()->isMapped()); 0816 QVERIFY(child3->surface()->isMapped()); 0817 0818 // unmapping a parent should unmap the complete tree 0819 QSignalSpy unmappedSpy(child->surface(), &SurfaceInterface::unmapped); 0820 childLevel1Surface->attachBuffer(KWayland::Client::Buffer::Ptr()); 0821 childLevel1Surface->damage(QRect(0, 0, 200, 200)); 0822 childLevel1Surface->commit(KWayland::Client::Surface::CommitFlag::None); 0823 QVERIFY(unmappedSpy.wait()); 0824 0825 QVERIFY(parentServerSurface->isMapped()); 0826 QVERIFY(!child->surface()->isMapped()); 0827 QVERIFY(!child2->surface()->isMapped()); 0828 QVERIFY(!child3->surface()->isMapped()); 0829 } 0830 0831 void TestSubSurface::testSurfaceAt() 0832 { 0833 // this test verifies that the correct surface is picked in a sub-surface tree 0834 using namespace KWin; 0835 // first create a parent surface and map it 0836 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); 0837 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface()); 0838 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); 0839 image.fill(Qt::red); 0840 parent->attachBuffer(m_shm->createBuffer(image)); 0841 parent->damage(QRect(0, 0, 100, 100)); 0842 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0843 QVERIFY(serverSurfaceCreated.wait()); 0844 SurfaceInterface *parentServerSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>(); 0845 0846 // directChild1 occupies the top-left quarter of the parent surface 0847 QImage directImage(QSize(50, 50), QImage::Format_ARGB32_Premultiplied); 0848 std::unique_ptr<KWayland::Client::Surface> directChild1(m_compositor->createSurface()); 0849 directChild1->attachBuffer(m_shm->createBuffer(directImage)); 0850 directChild1->damage(QRect(0, 0, 50, 50)); 0851 directChild1->commit(KWayland::Client::Surface::CommitFlag::None); 0852 QVERIFY(serverSurfaceCreated.wait()); 0853 SurfaceInterface *directChild1ServerSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>(); 0854 QVERIFY(directChild1ServerSurface); 0855 0856 // directChild2 occupies the bottom-right quarter of the parent surface 0857 std::unique_ptr<KWayland::Client::Surface> directChild2(m_compositor->createSurface()); 0858 directChild2->attachBuffer(m_shm->createBuffer(directImage)); 0859 directChild2->damage(QRect(0, 0, 50, 50)); 0860 directChild2->commit(KWayland::Client::Surface::CommitFlag::None); 0861 QVERIFY(serverSurfaceCreated.wait()); 0862 SurfaceInterface *directChild2ServerSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>(); 0863 QVERIFY(directChild2ServerSurface); 0864 0865 // create the sub surfaces for them 0866 std::unique_ptr<KWayland::Client::SubSurface> directChild1SubSurface(m_subCompositor->createSubSurface(directChild1.get(), parent.get())); 0867 directChild1SubSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 0868 std::unique_ptr<KWayland::Client::SubSurface> directChild2SubSurface(m_subCompositor->createSubSurface(directChild2.get(), parent.get())); 0869 directChild2SubSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 0870 directChild2SubSurface->setPosition(QPoint(50, 50)); 0871 0872 // unset input regions for direct children 0873 QSignalSpy directChild1CommittedSpy(directChild1ServerSurface, &SurfaceInterface::committed); 0874 directChild1->setInputRegion(m_compositor->createRegion(QRegion()).get()); 0875 directChild1->commit(KWayland::Client::Surface::CommitFlag::None); 0876 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0877 QVERIFY(directChild1CommittedSpy.wait()); 0878 0879 QSignalSpy directChild2CommittedSpy(directChild2ServerSurface, &SurfaceInterface::committed); 0880 directChild2->setInputRegion(m_compositor->createRegion(QRegion()).get()); 0881 directChild2->commit(KWayland::Client::Surface::CommitFlag::None); 0882 parent->commit(KWayland::Client::Surface::CommitFlag::None); 0883 QVERIFY(directChild2CommittedSpy.wait()); 0884 0885 // each of the children gets a child 0886 std::unique_ptr<KWayland::Client::Surface> childFor1(m_compositor->createSurface()); 0887 QVERIFY(serverSurfaceCreated.wait()); 0888 SurfaceInterface *childFor1ServerSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>(); 0889 std::unique_ptr<KWayland::Client::Surface> childFor2(m_compositor->createSurface()); 0890 QVERIFY(serverSurfaceCreated.wait()); 0891 SurfaceInterface *childFor2ServerSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>(); 0892 0893 // create sub surfaces for them 0894 std::unique_ptr<KWayland::Client::SubSurface> childFor1SubSurface(m_subCompositor->createSubSurface(childFor1.get(), directChild1.get())); 0895 childFor1SubSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 0896 std::unique_ptr<KWayland::Client::SubSurface> childFor2SubSurface(m_subCompositor->createSubSurface(childFor2.get(), directChild2.get())); 0897 childFor2SubSurface->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 0898 0899 // now let's render both grand children 0900 QImage partImage(QSize(50, 50), QImage::Format_ARGB32_Premultiplied); 0901 partImage.fill(Qt::green); 0902 childFor1->attachBuffer(m_shm->createBuffer(partImage)); 0903 childFor1->damage(QRect(0, 0, 50, 50)); 0904 childFor1->commit(KWayland::Client::Surface::CommitFlag::None); 0905 partImage.fill(Qt::blue); 0906 0907 QSignalSpy childFor2CommittedSpy(childFor2ServerSurface, &SurfaceInterface::committed); 0908 childFor2->attachBuffer(m_shm->createBuffer(partImage)); 0909 // child for 2's input region is subdivided into quadrants, with input mask on the top left and bottom right 0910 QRegion region; 0911 region += QRect(0, 0, 25, 25); 0912 region += QRect(25, 25, 25, 25); 0913 childFor2->setInputRegion(m_compositor->createRegion(region).get()); 0914 childFor2->damage(QRect(0, 0, 50, 50)); 0915 childFor2->commit(KWayland::Client::Surface::CommitFlag::None); 0916 QVERIFY(childFor2CommittedSpy.wait()); 0917 0918 QCOMPARE(directChild1ServerSurface->subSurface()->parentSurface(), parentServerSurface); 0919 QCOMPARE(directChild2ServerSurface->subSurface()->parentSurface(), parentServerSurface); 0920 QCOMPARE(childFor1ServerSurface->subSurface()->parentSurface(), directChild1ServerSurface); 0921 QCOMPARE(childFor2ServerSurface->subSurface()->parentSurface(), directChild2ServerSurface); 0922 0923 // now let's test a few positions 0924 QCOMPARE(parentServerSurface->surfaceAt(QPointF(0, 0)), childFor1ServerSurface); 0925 QCOMPARE(parentServerSurface->surfaceAt(QPointF(49, 49)), childFor1ServerSurface); 0926 QCOMPARE(parentServerSurface->surfaceAt(QPointF(50, 50)), childFor2ServerSurface); 0927 QCOMPARE(parentServerSurface->surfaceAt(QPointF(99, 99)), childFor2ServerSurface); 0928 QCOMPARE(parentServerSurface->surfaceAt(QPointF(99, 50)), childFor2ServerSurface); 0929 QCOMPARE(parentServerSurface->surfaceAt(QPointF(50, 99)), childFor2ServerSurface); 0930 QCOMPARE(parentServerSurface->surfaceAt(QPointF(25, 75)), parentServerSurface); 0931 QCOMPARE(parentServerSurface->surfaceAt(QPointF(75, 25)), parentServerSurface); 0932 0933 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(0, 0)), childFor1ServerSurface); 0934 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(49, 49)), childFor1ServerSurface); 0935 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(50, 50)), childFor2ServerSurface); 0936 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(99, 99)), childFor2ServerSurface); 0937 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(99, 50)), parentServerSurface); 0938 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(50, 99)), parentServerSurface); 0939 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(25, 75)), parentServerSurface); 0940 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(75, 25)), parentServerSurface); 0941 0942 // outside the geometries should be no surface 0943 QVERIFY(!parentServerSurface->surfaceAt(QPointF(-1, -1))); 0944 QVERIFY(!parentServerSurface->surfaceAt(QPointF(101, 101))); 0945 0946 // on the surface edge right/bottom edges should not trigger as contained 0947 QCOMPARE(parentServerSurface->surfaceAt(QPointF(50, 25)), parentServerSurface); 0948 QCOMPARE(parentServerSurface->surfaceAt(QPointF(25, 50)), parentServerSurface); 0949 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(50, 25)), parentServerSurface); 0950 QCOMPARE(parentServerSurface->inputSurfaceAt(QPointF(25, 50)), parentServerSurface); 0951 } 0952 0953 void TestSubSurface::testDestroyAttachedBuffer() 0954 { 0955 // this test verifies that destroying of a buffer attached to a sub-surface works 0956 using namespace KWin; 0957 // create surface 0958 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); 0959 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface()); 0960 QVERIFY(serverSurfaceCreated.wait()); 0961 std::unique_ptr<KWayland::Client::Surface> child(m_compositor->createSurface()); 0962 QVERIFY(serverSurfaceCreated.wait()); 0963 SurfaceInterface *serverChildSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>(); 0964 // create sub-surface 0965 m_subCompositor->createSubSurface(child.get(), parent.get()); 0966 0967 // let's damage this surface, will be in sub-surface pending state 0968 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); 0969 image.fill(Qt::red); 0970 child->attachBuffer(m_shm->createBuffer(image)); 0971 child->damage(QRect(0, 0, 100, 100)); 0972 child->commit(KWayland::Client::Surface::CommitFlag::None); 0973 m_connection->flush(); 0974 0975 // Let's try to destroy it 0976 QSignalSpy destroySpy(serverChildSurface, &QObject::destroyed); 0977 delete m_shm; 0978 m_shm = nullptr; 0979 child.reset(); 0980 QVERIFY(destroySpy.wait()); 0981 } 0982 0983 void TestSubSurface::testDestroyParentSurface() 0984 { 0985 // this test verifies that destroying a parent surface does not create problems 0986 // see BUG 389231 0987 using namespace KWin; 0988 // create surface 0989 QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); 0990 std::unique_ptr<KWayland::Client::Surface> parent(m_compositor->createSurface()); 0991 QVERIFY(serverSurfaceCreated.wait()); 0992 SurfaceInterface *serverParentSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>(); 0993 std::unique_ptr<KWayland::Client::Surface> child(m_compositor->createSurface()); 0994 QVERIFY(serverSurfaceCreated.wait()); 0995 SurfaceInterface *serverChildSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>(); 0996 std::unique_ptr<KWayland::Client::Surface> grandChild(m_compositor->createSurface()); 0997 QVERIFY(serverSurfaceCreated.wait()); 0998 SurfaceInterface *serverGrandChildSurface = serverSurfaceCreated.last().first().value<KWin::SurfaceInterface *>(); 0999 // create sub-surface in desynchronized mode as Qt uses them 1000 auto sub1 = m_subCompositor->createSubSurface(child.get(), parent.get()); 1001 sub1->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 1002 auto sub2 = m_subCompositor->createSubSurface(grandChild.get(), child.get()); 1003 sub2->setMode(KWayland::Client::SubSurface::Mode::Desynchronized); 1004 1005 // let's damage this surface 1006 // and at the same time delete the parent surface 1007 parent.reset(); 1008 QSignalSpy parentDestroyedSpy(serverParentSurface, &QObject::destroyed); 1009 QVERIFY(parentDestroyedSpy.wait()); 1010 QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); 1011 image.fill(Qt::red); 1012 grandChild->attachBuffer(m_shm->createBuffer(image)); 1013 grandChild->damage(QRect(0, 0, 100, 100)); 1014 grandChild->commit(KWayland::Client::Surface::CommitFlag::None); 1015 QSignalSpy damagedSpy(serverGrandChildSurface, &SurfaceInterface::damaged); 1016 QVERIFY(damagedSpy.wait()); 1017 1018 // Let's try to destroy it 1019 QSignalSpy destroySpy(serverChildSurface, &QObject::destroyed); 1020 child.reset(); 1021 QVERIFY(destroySpy.wait()); 1022 } 1023 1024 QTEST_GUILESS_MAIN(TestSubSurface) 1025 #include "test_wayland_subsurface.moc"