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 <QImage>
0008 #include <QPainter>
0009 #include <QSignalSpy>
0010 #include <QTest>
0011 // KWin
0012 #include "core/graphicsbuffer.h"
0013 #include "core/graphicsbufferview.h"
0014 #include "wayland/clientconnection.h"
0015 #include "wayland/compositor.h"
0016 #include "wayland/display.h"
0017 #include "wayland/idleinhibit_v1.h"
0018 #include "wayland/output.h"
0019 #include "wayland/surface.h"
0020 
0021 #include "KWayland/Client/compositor.h"
0022 #include "KWayland/Client/connection_thread.h"
0023 #include "KWayland/Client/event_queue.h"
0024 #include "KWayland/Client/idleinhibit.h"
0025 #include "KWayland/Client/output.h"
0026 #include "KWayland/Client/region.h"
0027 #include "KWayland/Client/registry.h"
0028 #include "KWayland/Client/shm_pool.h"
0029 #include "KWayland/Client/surface.h"
0030 
0031 #include "../../../tests/fakeoutput.h"
0032 
0033 // Wayland
0034 #include <wayland-client-protocol.h>
0035 
0036 class TestWaylandSurface : public QObject
0037 {
0038     Q_OBJECT
0039 public:
0040     explicit TestWaylandSurface(QObject *parent = nullptr);
0041 private Q_SLOTS:
0042     void init();
0043     void cleanup();
0044 
0045     void testStaticAccessor();
0046     void testDamage();
0047     void testFrameCallback();
0048     void testAttachBuffer();
0049     void testOpaque();
0050     void testInput();
0051     void testScale();
0052     void testUnmapOfNotMappedSurface();
0053     void testSurfaceAt();
0054     void testDestroyAttachedBuffer();
0055     void testDestroyWithPendingCallback();
0056     void testOutput();
0057     void testDisconnect();
0058     void testInhibit();
0059 
0060 private:
0061     KWin::Display *m_display;
0062     KWin::CompositorInterface *m_compositorInterface;
0063     KWin::IdleInhibitManagerV1Interface *m_idleInhibitInterface;
0064     KWayland::Client::ConnectionThread *m_connection;
0065     KWayland::Client::Compositor *m_compositor;
0066     KWayland::Client::ShmPool *m_shm;
0067     KWayland::Client::EventQueue *m_queue;
0068     KWayland::Client::IdleInhibitManager *m_idleInhibitManager;
0069     QThread *m_thread;
0070 };
0071 
0072 static const QString s_socketName = QStringLiteral("kwin-test-wayland-surface-0");
0073 
0074 TestWaylandSurface::TestWaylandSurface(QObject *parent)
0075     : QObject(parent)
0076     , m_display(nullptr)
0077     , m_compositorInterface(nullptr)
0078     , m_connection(nullptr)
0079     , m_compositor(nullptr)
0080     , m_thread(nullptr)
0081 {
0082 }
0083 
0084 void TestWaylandSurface::init()
0085 {
0086     using namespace KWin;
0087     delete m_display;
0088     m_display = new KWin::Display(this);
0089     m_display->addSocketName(s_socketName);
0090     m_display->start();
0091     QVERIFY(m_display->isRunning());
0092     m_display->createShm();
0093 
0094     m_compositorInterface = new CompositorInterface(m_display, m_display);
0095     QVERIFY(m_compositorInterface);
0096 
0097     m_idleInhibitInterface = new IdleInhibitManagerV1Interface(m_display, m_display);
0098     QVERIFY(m_idleInhibitInterface);
0099 
0100     // setup connection
0101     m_connection = new KWayland::Client::ConnectionThread;
0102     QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
0103     m_connection->setSocketName(s_socketName);
0104 
0105     m_thread = new QThread(this);
0106     m_connection->moveToThread(m_thread);
0107     m_thread->start();
0108 
0109     /*connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, m_connection,
0110         [this]() {
0111             if (m_connection->display()) {
0112                 wl_display_flush(m_connection->display());
0113             }
0114         }
0115     );*/
0116 
0117     m_connection->initConnection();
0118     QVERIFY(connectedSpy.wait());
0119 
0120     m_queue = new KWayland::Client::EventQueue(this);
0121     QVERIFY(!m_queue->isValid());
0122     m_queue->setup(m_connection);
0123     QVERIFY(m_queue->isValid());
0124 
0125     KWayland::Client::Registry registry;
0126     registry.setEventQueue(m_queue);
0127     QSignalSpy compositorSpy(&registry, &KWayland::Client::Registry::compositorAnnounced);
0128     QSignalSpy shmSpy(&registry, &KWayland::Client::Registry::shmAnnounced);
0129     QSignalSpy allAnnounced(&registry, &KWayland::Client::Registry::interfacesAnnounced);
0130     registry.create(m_connection->display());
0131     QVERIFY(registry.isValid());
0132     registry.setup();
0133     QVERIFY(allAnnounced.wait());
0134     QVERIFY(!compositorSpy.isEmpty());
0135     QVERIFY(!shmSpy.isEmpty());
0136 
0137     m_compositor = registry.createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
0138     QVERIFY(m_compositor->isValid());
0139     m_shm = registry.createShmPool(shmSpy.first().first().value<quint32>(), shmSpy.first().last().value<quint32>(), this);
0140     QVERIFY(m_shm->isValid());
0141 
0142     m_idleInhibitManager = registry.createIdleInhibitManager(registry.interface(KWayland::Client::Registry::Interface::IdleInhibitManagerUnstableV1).name,
0143                                                              registry.interface(KWayland::Client::Registry::Interface::IdleInhibitManagerUnstableV1).version,
0144                                                              this);
0145     QVERIFY(m_idleInhibitManager->isValid());
0146 }
0147 
0148 void TestWaylandSurface::cleanup()
0149 {
0150     if (m_compositor) {
0151         delete m_compositor;
0152         m_compositor = nullptr;
0153     }
0154     if (m_idleInhibitManager) {
0155         delete m_idleInhibitManager;
0156         m_idleInhibitManager = nullptr;
0157     }
0158     if (m_shm) {
0159         delete m_shm;
0160         m_shm = nullptr;
0161     }
0162     if (m_queue) {
0163         delete m_queue;
0164         m_queue = nullptr;
0165     }
0166     if (m_thread) {
0167         m_thread->quit();
0168         m_thread->wait();
0169         delete m_thread;
0170         m_thread = nullptr;
0171     }
0172     delete m_connection;
0173     m_connection = nullptr;
0174 
0175     delete m_display;
0176     m_display = nullptr;
0177 
0178     // these are the children of the display
0179     m_compositorInterface = nullptr;
0180     m_idleInhibitInterface = nullptr;
0181 }
0182 
0183 void TestWaylandSurface::testStaticAccessor()
0184 {
0185     QSignalSpy serverSurfaceCreated(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
0186 
0187     QVERIFY(!KWin::SurfaceInterface::get(nullptr));
0188     QVERIFY(!KWin::SurfaceInterface::get(1, nullptr));
0189     QVERIFY(KWayland::Client::Surface::all().isEmpty());
0190     std::unique_ptr<KWayland::Client::Surface> s1(m_compositor->createSurface());
0191     QVERIFY(s1->isValid());
0192     QCOMPARE(KWayland::Client::Surface::all().count(), 1);
0193     QCOMPARE(KWayland::Client::Surface::all().first(), s1.get());
0194     QCOMPARE(KWayland::Client::Surface::get(*s1), s1.get());
0195     QVERIFY(serverSurfaceCreated.wait());
0196     auto serverSurface1 = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>();
0197     QVERIFY(serverSurface1);
0198     QCOMPARE(KWin::SurfaceInterface::get(serverSurface1->resource()), serverSurface1);
0199     QCOMPARE(KWin::SurfaceInterface::get(serverSurface1->id(), serverSurface1->client()), serverSurface1);
0200 
0201     QVERIFY(!s1->size().isValid());
0202     QSignalSpy sizeChangedSpy(s1.get(), &KWayland::Client::Surface::sizeChanged);
0203     const QSize testSize(200, 300);
0204     s1->setSize(testSize);
0205     QCOMPARE(s1->size(), testSize);
0206     QCOMPARE(sizeChangedSpy.count(), 1);
0207     QCOMPARE(sizeChangedSpy.first().first().toSize(), testSize);
0208 
0209     // add another surface
0210     std::unique_ptr<KWayland::Client::Surface> s2(m_compositor->createSurface());
0211     QVERIFY(s2->isValid());
0212     QCOMPARE(KWayland::Client::Surface::all().count(), 2);
0213     QCOMPARE(KWayland::Client::Surface::all().first(), s1.get());
0214     QCOMPARE(KWayland::Client::Surface::all().last(), s2.get());
0215     QCOMPARE(KWayland::Client::Surface::get(*s1), s1.get());
0216     QCOMPARE(KWayland::Client::Surface::get(*s2), s2.get());
0217     serverSurfaceCreated.clear();
0218     QVERIFY(serverSurfaceCreated.wait());
0219     auto serverSurface2 = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>();
0220     QVERIFY(serverSurface2);
0221     QCOMPARE(KWin::SurfaceInterface::get(serverSurface1->resource()), serverSurface1);
0222     QCOMPARE(KWin::SurfaceInterface::get(serverSurface1->id(), serverSurface1->client()), serverSurface1);
0223     QCOMPARE(KWin::SurfaceInterface::get(serverSurface2->resource()), serverSurface2);
0224     QCOMPARE(KWin::SurfaceInterface::get(serverSurface2->id(), serverSurface2->client()), serverSurface2);
0225 
0226     const quint32 surfaceId1 = serverSurface1->id();
0227     const quint32 surfaceId2 = serverSurface2->id();
0228 
0229     // delete s2 again
0230     s2.reset();
0231     QCOMPARE(KWayland::Client::Surface::all().count(), 1);
0232     QCOMPARE(KWayland::Client::Surface::all().first(), s1.get());
0233     QCOMPARE(KWayland::Client::Surface::get(*s1), s1.get());
0234 
0235     // and finally delete the last one
0236     s1.reset();
0237     QVERIFY(KWayland::Client::Surface::all().isEmpty());
0238     QVERIFY(!KWayland::Client::Surface::get(nullptr));
0239     QSignalSpy destroyedSpy(serverSurface1, &KWin::SurfaceInterface::destroyed);
0240     QVERIFY(destroyedSpy.wait());
0241     QVERIFY(!KWin::SurfaceInterface::get(nullptr));
0242     QVERIFY(!KWin::SurfaceInterface::get(surfaceId1, nullptr));
0243     QVERIFY(!KWin::SurfaceInterface::get(surfaceId2, nullptr));
0244 }
0245 
0246 void TestWaylandSurface::testDamage()
0247 {
0248     QSignalSpy serverSurfaceCreated(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
0249     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0250     s->setScale(2);
0251     QVERIFY(serverSurfaceCreated.wait());
0252     KWin::SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>();
0253     QVERIFY(serverSurface);
0254     QCOMPARE(serverSurface->bufferDamage(), QRegion());
0255     QVERIFY(!serverSurface->isMapped());
0256 
0257     QSignalSpy committedSpy(serverSurface, &KWin::SurfaceInterface::committed);
0258     QSignalSpy damageSpy(serverSurface, &KWin::SurfaceInterface::damaged);
0259 
0260     // send damage without a buffer
0261     {
0262         s->damage(QRect(0, 0, 100, 100));
0263         s->commit(KWayland::Client::Surface::CommitFlag::None);
0264         wl_display_flush(m_connection->display());
0265         QCoreApplication::processEvents();
0266         QCoreApplication::processEvents();
0267         QVERIFY(damageSpy.isEmpty());
0268         QVERIFY(!serverSurface->isMapped());
0269         QCOMPARE(committedSpy.count(), 1);
0270     }
0271 
0272     // surface damage
0273     {
0274         QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
0275         img.fill(Qt::black);
0276         auto b = m_shm->createBuffer(img);
0277         s->attachBuffer(b, QPoint(55, 55));
0278         s->damage(QRect(0, 0, 10, 10));
0279         s->commit(KWayland::Client::Surface::CommitFlag::None);
0280         QVERIFY(damageSpy.wait());
0281         QCOMPARE(serverSurface->offset(), QPoint(55, 55)); // offset is surface local so scale doesn't change this
0282         QCOMPARE(serverSurface->bufferDamage(), QRegion(0, 0, 10, 10));
0283         QCOMPARE(damageSpy.first().first().value<QRegion>(), QRegion(0, 0, 10, 10));
0284         QVERIFY(serverSurface->isMapped());
0285         QCOMPARE(committedSpy.count(), 2);
0286     }
0287 
0288     // damage multiple times
0289     {
0290         const QRegion surfaceDamage = QRegion(5, 8, 3, 6).united(QRect(10, 11, 6, 1));
0291         const QRegion expectedDamage = QRegion(10, 16, 6, 12).united(QRect(20, 22, 12, 2));
0292         QImage img(QSize(80, 70), QImage::Format_ARGB32_Premultiplied);
0293         img.fill(Qt::black);
0294         auto b = m_shm->createBuffer(img);
0295         s->attachBuffer(b);
0296         s->damage(surfaceDamage);
0297         damageSpy.clear();
0298         s->commit(KWayland::Client::Surface::CommitFlag::None);
0299         QVERIFY(damageSpy.wait());
0300         QCOMPARE(serverSurface->bufferDamage(), expectedDamage);
0301         QCOMPARE(damageSpy.first().first().value<QRegion>(), expectedDamage);
0302         QVERIFY(serverSurface->isMapped());
0303         QCOMPARE(committedSpy.count(), 3);
0304     }
0305 
0306     // damage buffer
0307     {
0308         const QRegion damage(30, 40, 22, 4);
0309         QImage img(QSize(80, 70), QImage::Format_ARGB32_Premultiplied);
0310         img.fill(Qt::black);
0311         auto b = m_shm->createBuffer(img);
0312         s->attachBuffer(b);
0313         s->damageBuffer(damage);
0314         damageSpy.clear();
0315         s->commit(KWayland::Client::Surface::CommitFlag::None);
0316         QVERIFY(damageSpy.wait());
0317         QCOMPARE(serverSurface->bufferDamage(), damage);
0318         QCOMPARE(damageSpy.first().first().value<QRegion>(), damage);
0319         QVERIFY(serverSurface->isMapped());
0320     }
0321 
0322     // combined regular damage and damaged buffer
0323     {
0324         const QRegion surfaceDamage(10, 20, 5, 5);
0325         const QRegion bufferDamage(30, 50, 50, 20);
0326         const QRegion expectedDamage = QRegion(20, 40, 10, 10).united(QRect(30, 50, 50, 20));
0327         QImage img(QSize(80, 70), QImage::Format_ARGB32_Premultiplied);
0328         img.fill(Qt::black);
0329         auto b = m_shm->createBuffer(img);
0330         s->attachBuffer(b);
0331         s->damage(surfaceDamage);
0332         s->damageBuffer(bufferDamage);
0333         damageSpy.clear();
0334         s->commit(KWayland::Client::Surface::CommitFlag::None);
0335         QVERIFY(damageSpy.wait());
0336         QCOMPARE(serverSurface->bufferDamage(), expectedDamage);
0337         QCOMPARE(damageSpy.first().first().value<QRegion>(), expectedDamage);
0338         QVERIFY(serverSurface->isMapped());
0339     }
0340 }
0341 
0342 void TestWaylandSurface::testFrameCallback()
0343 {
0344     QSignalSpy serverSurfaceCreated(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
0345     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0346     QVERIFY(serverSurfaceCreated.wait());
0347     KWin::SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>();
0348     QVERIFY(serverSurface);
0349 
0350     QSignalSpy damageSpy(serverSurface, &KWin::SurfaceInterface::damaged);
0351 
0352     QSignalSpy frameRenderedSpy(s.get(), &KWayland::Client::Surface::frameRendered);
0353     QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
0354     img.fill(Qt::black);
0355     auto b = m_shm->createBuffer(img);
0356     s->attachBuffer(b);
0357     s->damage(QRect(0, 0, 10, 10));
0358     s->commit();
0359     QVERIFY(damageSpy.wait());
0360     serverSurface->frameRendered(10);
0361     QVERIFY(frameRenderedSpy.isEmpty());
0362     QVERIFY(frameRenderedSpy.wait());
0363     QVERIFY(!frameRenderedSpy.isEmpty());
0364 }
0365 
0366 void TestWaylandSurface::testAttachBuffer()
0367 {
0368     // create the surface
0369     QSignalSpy serverSurfaceCreated(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
0370     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0371     QVERIFY(serverSurfaceCreated.wait());
0372     KWin::SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>();
0373     QVERIFY(serverSurface);
0374 
0375     // create three images
0376     QImage black(24, 24, QImage::Format_RGB32);
0377     black.fill(Qt::black);
0378     QImage red(24, 24, QImage::Format_ARGB32); // Note - deliberately not premultiplied
0379     red.fill(QColor(255, 0, 0, 128));
0380     QImage blue(24, 24, QImage::Format_ARGB32_Premultiplied);
0381     blue.fill(QColor(0, 0, 255, 128));
0382 
0383     QSharedPointer<KWayland::Client::Buffer> blackBufferPtr = m_shm->createBuffer(black).toStrongRef();
0384     QVERIFY(blackBufferPtr);
0385     wl_buffer *blackBuffer = *(blackBufferPtr.data());
0386     QSharedPointer<KWayland::Client::Buffer> redBuffer = m_shm->createBuffer(red).toStrongRef();
0387     QVERIFY(redBuffer);
0388     QSharedPointer<KWayland::Client::Buffer> blueBuffer = m_shm->createBuffer(blue).toStrongRef();
0389     QVERIFY(blueBuffer);
0390 
0391     QCOMPARE(blueBuffer->format(), KWayland::Client::Buffer::Format::ARGB32);
0392     QCOMPARE(blueBuffer->size(), blue.size());
0393     QVERIFY(!blueBuffer->isReleased());
0394     QVERIFY(!blueBuffer->isUsed());
0395     QCOMPARE(blueBuffer->stride(), blue.bytesPerLine());
0396 
0397     s->attachBuffer(redBuffer.data());
0398     s->attachBuffer(blackBuffer);
0399     s->damage(QRect(0, 0, 24, 24));
0400     s->commit(KWayland::Client::Surface::CommitFlag::None);
0401     QSignalSpy damageSpy(serverSurface, &KWin::SurfaceInterface::damaged);
0402     QSignalSpy mappedSpy(serverSurface, &KWin::SurfaceInterface::mapped);
0403     QSignalSpy unmappedSpy(serverSurface, &KWin::SurfaceInterface::unmapped);
0404     QVERIFY(damageSpy.wait());
0405     QCOMPARE(mappedSpy.count(), 1);
0406     QVERIFY(unmappedSpy.isEmpty());
0407 
0408     // now the ServerSurface should have the black image attached as a buffer
0409     KWin::GraphicsBuffer *buffer = serverSurface->buffer();
0410     buffer->ref();
0411     {
0412         KWin::GraphicsBufferView view(buffer);
0413         QVERIFY(view.image());
0414         QCOMPARE(*view.image(), black);
0415         QCOMPARE(view.image()->format(), QImage::Format_RGB32);
0416         QCOMPARE(view.image()->size(), QSize(24, 24));
0417     }
0418 
0419     // render another frame
0420     s->attachBuffer(redBuffer);
0421     s->damage(QRect(0, 0, 24, 24));
0422     s->commit(KWayland::Client::Surface::CommitFlag::None);
0423     damageSpy.clear();
0424     QVERIFY(damageSpy.wait());
0425     QCOMPARE(mappedSpy.count(), 1);
0426     QVERIFY(unmappedSpy.isEmpty());
0427     KWin::GraphicsBuffer *buffer2 = serverSurface->buffer();
0428     buffer2->ref();
0429     {
0430         KWin::GraphicsBufferView view(buffer2);
0431         QVERIFY(view.image());
0432         QCOMPARE(view.image()->format(), QImage::Format_ARGB32_Premultiplied);
0433         QCOMPARE(view.image()->size(), QSize(24, 24));
0434         for (int i = 0; i < 24; ++i) {
0435             for (int j = 0; j < 24; ++j) {
0436                 // it's premultiplied in the format
0437                 QCOMPARE(view.image()->pixel(i, j), qRgba(128, 0, 0, 128));
0438             }
0439         }
0440     }
0441     buffer2->unref();
0442     QVERIFY(buffer2->isReferenced());
0443     QVERIFY(!redBuffer.data()->isReleased());
0444 
0445     // render another frame
0446     blueBuffer->setUsed(true);
0447     QVERIFY(blueBuffer->isUsed());
0448     s->attachBuffer(blueBuffer.data());
0449     s->damage(QRect(0, 0, 24, 24));
0450     QSignalSpy frameRenderedSpy(s.get(), &KWayland::Client::Surface::frameRendered);
0451     s->commit();
0452     damageSpy.clear();
0453     QVERIFY(damageSpy.wait());
0454     QCOMPARE(mappedSpy.count(), 1);
0455     QVERIFY(unmappedSpy.isEmpty());
0456     QVERIFY(!buffer2->isReferenced());
0457     // TODO: we should have a signal on when the Buffer gets released
0458     QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
0459     if (!redBuffer.data()->isReleased()) {
0460         QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
0461     }
0462     QVERIFY(redBuffer.data()->isReleased());
0463 
0464     KWin::GraphicsBuffer *buffer3 = serverSurface->buffer();
0465     buffer3->ref();
0466     {
0467         KWin::GraphicsBufferView view(buffer3);
0468         QVERIFY(view.image());
0469         QCOMPARE(view.image()->format(), QImage::Format_ARGB32_Premultiplied);
0470         QCOMPARE(view.image()->size(), QSize(24, 24));
0471         for (int i = 0; i < 24; ++i) {
0472             for (int j = 0; j < 24; ++j) {
0473                 // it's premultiplied in the format
0474                 QCOMPARE(view.image()->pixel(i, j), qRgba(0, 0, 128, 128));
0475             }
0476         }
0477     }
0478     buffer3->unref();
0479     QVERIFY(buffer3->isReferenced());
0480 
0481     serverSurface->frameRendered(1);
0482     QVERIFY(frameRenderedSpy.wait());
0483 
0484     // commit a different value shouldn't change our buffer
0485     QCOMPARE(serverSurface->buffer(), buffer3);
0486     damageSpy.clear();
0487     s->setInputRegion(m_compositor->createRegion(QRegion(0, 0, 24, 24)).get());
0488     s->commit(KWayland::Client::Surface::CommitFlag::None);
0489     wl_display_flush(m_connection->display());
0490     QCoreApplication::processEvents();
0491     QCoreApplication::processEvents();
0492     QCOMPARE(serverSurface->buffer(), buffer3);
0493     QVERIFY(damageSpy.isEmpty());
0494     QCOMPARE(mappedSpy.count(), 1);
0495     QVERIFY(unmappedSpy.isEmpty());
0496     QVERIFY(serverSurface->isMapped());
0497 
0498     // clear the surface
0499     s->attachBuffer(blackBuffer);
0500     s->damage(QRect(0, 0, 1, 1));
0501     // TODO: better method
0502     s->attachBuffer((wl_buffer *)nullptr);
0503     s->damage(QRect(0, 0, 10, 10));
0504     s->commit(KWayland::Client::Surface::CommitFlag::None);
0505     QVERIFY(unmappedSpy.wait());
0506     QCOMPARE(mappedSpy.count(), 1);
0507     QCOMPARE(unmappedSpy.count(), 1);
0508     QVERIFY(damageSpy.isEmpty());
0509     QVERIFY(!serverSurface->isMapped());
0510 
0511     // TODO: add signal test on release
0512     buffer->unref();
0513 }
0514 
0515 void TestWaylandSurface::testOpaque()
0516 {
0517     using namespace KWin;
0518     QSignalSpy serverSurfaceCreated(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
0519     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0520     QVERIFY(serverSurfaceCreated.wait());
0521     SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>();
0522     QVERIFY(serverSurface);
0523     QSignalSpy opaqueRegionChangedSpy(serverSurface, &KWin::SurfaceInterface::opaqueChanged);
0524 
0525     // by default there should be an empty opaque region
0526     QCOMPARE(serverSurface->opaque(), QRegion());
0527 
0528     // let's install an opaque region
0529     s->setOpaqueRegion(m_compositor->createRegion(QRegion(0, 10, 20, 30)).get());
0530     // the region should only be applied after the surface got committed
0531     wl_display_flush(m_connection->display());
0532     QCoreApplication::processEvents();
0533     QCOMPARE(serverSurface->opaque(), QRegion());
0534     QCOMPARE(opaqueRegionChangedSpy.count(), 0);
0535 
0536     // so let's commit to get the new region
0537     QImage black(20, 40, QImage::Format_ARGB32_Premultiplied);
0538     black.fill(Qt::black);
0539     QSharedPointer<KWayland::Client::Buffer> buffer1 = m_shm->createBuffer(black).toStrongRef();
0540     s->attachBuffer(buffer1);
0541     s->commit(KWayland::Client::Surface::CommitFlag::None);
0542     QVERIFY(opaqueRegionChangedSpy.wait());
0543     QCOMPARE(opaqueRegionChangedSpy.count(), 1);
0544     QCOMPARE(opaqueRegionChangedSpy.last().first().value<QRegion>(), QRegion(0, 10, 20, 30));
0545     QCOMPARE(serverSurface->opaque(), QRegion(0, 10, 20, 30));
0546 
0547     // committing without setting a new region shouldn't change
0548     s->commit(KWayland::Client::Surface::CommitFlag::None);
0549     wl_display_flush(m_connection->display());
0550     QCoreApplication::processEvents();
0551     QCOMPARE(opaqueRegionChangedSpy.count(), 1);
0552     QCOMPARE(serverSurface->opaque(), QRegion(0, 10, 20, 30));
0553 
0554     // let's change the opaque region, it will be clipped with rect(0, 0, 20, 40)
0555     s->setOpaqueRegion(m_compositor->createRegion(QRegion(10, 20, 30, 40)).get());
0556     s->commit(KWayland::Client::Surface::CommitFlag::None);
0557     QVERIFY(opaqueRegionChangedSpy.wait());
0558     QCOMPARE(opaqueRegionChangedSpy.count(), 2);
0559     QCOMPARE(opaqueRegionChangedSpy.last().first().value<QRegion>(), QRegion(10, 20, 10, 20));
0560     QCOMPARE(serverSurface->opaque(), QRegion(10, 20, 10, 20));
0561 
0562     // and let's go back to an empty region
0563     s->setOpaqueRegion();
0564     s->commit(KWayland::Client::Surface::CommitFlag::None);
0565     QVERIFY(opaqueRegionChangedSpy.wait());
0566     QCOMPARE(opaqueRegionChangedSpy.count(), 3);
0567     QCOMPARE(opaqueRegionChangedSpy.last().first().value<QRegion>(), QRegion());
0568     QCOMPARE(serverSurface->opaque(), QRegion());
0569 }
0570 
0571 void TestWaylandSurface::testInput()
0572 {
0573     using namespace KWin;
0574     QSignalSpy serverSurfaceCreated(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated);
0575     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0576     QVERIFY(serverSurfaceCreated.wait());
0577     SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>();
0578     QVERIFY(serverSurface);
0579     QSignalSpy inputRegionChangedSpy(serverSurface, &KWin::SurfaceInterface::inputChanged);
0580     QSignalSpy committedSpy(serverSurface, &SurfaceInterface::committed);
0581 
0582     // the input region should be empty if the surface has no buffer
0583     QVERIFY(!serverSurface->isMapped());
0584     QCOMPARE(serverSurface->input(), QRegion());
0585 
0586     // the default input region is infinite
0587     QImage black(100, 50, QImage::Format_RGB32);
0588     black.fill(Qt::black);
0589     QSharedPointer<KWayland::Client::Buffer> buffer1 = m_shm->createBuffer(black).toStrongRef();
0590     QVERIFY(buffer1);
0591     s->attachBuffer(buffer1);
0592     s->commit(KWayland::Client::Surface::CommitFlag::None);
0593     QVERIFY(committedSpy.wait());
0594     QVERIFY(serverSurface->isMapped());
0595     QCOMPARE(inputRegionChangedSpy.count(), 1);
0596     QCOMPARE(serverSurface->input(), QRegion(0, 0, 100, 50));
0597 
0598     // let's install an input region
0599     s->setInputRegion(m_compositor->createRegion(QRegion(0, 10, 20, 30)).get());
0600     // the region should only be applied after the surface got committed
0601     wl_display_flush(m_connection->display());
0602     QCoreApplication::processEvents();
0603     QCOMPARE(inputRegionChangedSpy.count(), 1);
0604     QCOMPARE(serverSurface->input(), QRegion(0, 0, 100, 50));
0605 
0606     // so let's commit to get the new region
0607     s->commit(KWayland::Client::Surface::CommitFlag::None);
0608     QVERIFY(committedSpy.wait());
0609     QCOMPARE(inputRegionChangedSpy.count(), 2);
0610     QCOMPARE(serverSurface->input(), QRegion(0, 10, 20, 30));
0611 
0612     // committing without setting a new region shouldn't change
0613     s->commit(KWayland::Client::Surface::CommitFlag::None);
0614     wl_display_flush(m_connection->display());
0615     QCoreApplication::processEvents();
0616     QCOMPARE(inputRegionChangedSpy.count(), 2);
0617     QCOMPARE(serverSurface->input(), QRegion(0, 10, 20, 30));
0618 
0619     // let's change the input region, note that the new input region is cropped
0620     s->setInputRegion(m_compositor->createRegion(QRegion(10, 20, 30, 40)).get());
0621     s->commit(KWayland::Client::Surface::CommitFlag::None);
0622     QVERIFY(committedSpy.wait());
0623     QCOMPARE(inputRegionChangedSpy.count(), 3);
0624     QCOMPARE(serverSurface->input(), QRegion(10, 20, 30, 30));
0625 
0626     // and let's go back to an empty region
0627     s->setInputRegion();
0628     s->commit(KWayland::Client::Surface::CommitFlag::None);
0629     QVERIFY(committedSpy.wait());
0630     QCOMPARE(inputRegionChangedSpy.count(), 4);
0631     QCOMPARE(serverSurface->input(), QRegion(0, 0, 100, 50));
0632 }
0633 
0634 void TestWaylandSurface::testScale()
0635 {
0636     // this test verifies that updating the scale factor is correctly passed to the Wayland server
0637     using namespace KWin;
0638     // create surface
0639     QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
0640     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0641     QCOMPARE(s->scale(), 1);
0642     QVERIFY(serverSurfaceCreated.wait());
0643     SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>();
0644     QVERIFY(serverSurface);
0645 
0646     // changing the scale implicitly changes the size
0647     QSignalSpy sizeChangedSpy(serverSurface, &SurfaceInterface::sizeChanged);
0648 
0649     // attach a buffer of 100x100
0650     QImage red(100, 100, QImage::Format_ARGB32_Premultiplied);
0651     red.fill(QColor(255, 0, 0, 128));
0652     QSharedPointer<KWayland::Client::Buffer> redBuffer = m_shm->createBuffer(red).toStrongRef();
0653     QVERIFY(redBuffer);
0654     s->attachBuffer(redBuffer.data());
0655     s->damageBuffer(QRect(0, 0, 100, 100));
0656     s->commit(KWayland::Client::Surface::CommitFlag::None);
0657     QVERIFY(sizeChangedSpy.wait());
0658     QCOMPARE(sizeChangedSpy.count(), 1);
0659     QCOMPARE(serverSurface->size(), QSize(100, 100));
0660 
0661     // set the scale to 2, buffer is still 100x100 so size should change to 50x50
0662     s->setScale(2);
0663     s->commit(KWayland::Client::Surface::CommitFlag::None);
0664     QVERIFY(sizeChangedSpy.wait());
0665     QCOMPARE(sizeChangedSpy.count(), 2);
0666     QCOMPARE(serverSurface->size(), QSize(50, 50));
0667 
0668     // set scale and size in one commit, buffer is 60x60 at scale 3 so size should be 20x20
0669     QImage blue(60, 60, QImage::Format_ARGB32_Premultiplied);
0670     red.fill(QColor(255, 0, 0, 128));
0671     QSharedPointer<KWayland::Client::Buffer> blueBuffer = m_shm->createBuffer(blue).toStrongRef();
0672     QVERIFY(blueBuffer);
0673     s->attachBuffer(blueBuffer.data());
0674     s->setScale(3);
0675     s->commit(KWayland::Client::Surface::CommitFlag::None);
0676     QVERIFY(sizeChangedSpy.wait());
0677     QCOMPARE(sizeChangedSpy.count(), 3);
0678     QCOMPARE(serverSurface->size(), QSize(20, 20));
0679 }
0680 
0681 void TestWaylandSurface::testUnmapOfNotMappedSurface()
0682 {
0683     // this test verifies that a surface which doesn't have a buffer attached doesn't trigger the unmapped signal
0684     using namespace KWin;
0685     // create surface
0686     QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
0687     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0688     QVERIFY(serverSurfaceCreated.wait());
0689     SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>();
0690 
0691     QSignalSpy unmappedSpy(serverSurface, &SurfaceInterface::unmapped);
0692     QSignalSpy committedSpy(serverSurface, &SurfaceInterface::committed);
0693 
0694     // let's map a null buffer and change scale to trigger a signal we can wait for
0695     s->attachBuffer(KWayland::Client::Buffer::Ptr());
0696     s->commit(KWayland::Client::Surface::CommitFlag::None);
0697 
0698     QVERIFY(committedSpy.wait());
0699     QVERIFY(unmappedSpy.isEmpty());
0700 }
0701 
0702 void TestWaylandSurface::testSurfaceAt()
0703 {
0704     // this test verifies that surfaceAt(const QPointF&) works as expected for the case of no children
0705     using namespace KWin;
0706     // create surface
0707     QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
0708     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0709     QVERIFY(serverSurfaceCreated.wait());
0710     SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>();
0711 
0712     // a newly created surface should not be mapped and not provide a surface at a position
0713     QVERIFY(!serverSurface->isMapped());
0714     QVERIFY(!serverSurface->surfaceAt(QPointF(0, 0)));
0715 
0716     // let's damage this surface
0717     QSignalSpy sizeChangedSpy(serverSurface, &SurfaceInterface::sizeChanged);
0718     QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
0719     image.fill(Qt::red);
0720     s->attachBuffer(m_shm->createBuffer(image));
0721     s->damage(QRect(0, 0, 100, 100));
0722     s->commit(KWayland::Client::Surface::CommitFlag::None);
0723     QVERIFY(sizeChangedSpy.wait());
0724 
0725     // now the surface is mapped and surfaceAt should give the surface
0726     QVERIFY(serverSurface->isMapped());
0727     QCOMPARE(serverSurface->surfaceAt(QPointF(0, 0)), serverSurface);
0728     QCOMPARE(serverSurface->surfaceAt(QPointF(99, 99)), serverSurface);
0729     // outside the geometry it should not give a surface
0730     QVERIFY(!serverSurface->surfaceAt(QPointF(100, 100)));
0731     QVERIFY(!serverSurface->surfaceAt(QPointF(-1, -1)));
0732 }
0733 
0734 void TestWaylandSurface::testDestroyAttachedBuffer()
0735 {
0736     // this test verifies that destroying of a buffer attached to a surface works
0737     using namespace KWin;
0738     // create surface
0739     QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
0740     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0741     QVERIFY(serverSurfaceCreated.wait());
0742     SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>();
0743 
0744     // let's damage this surface
0745     QSignalSpy damagedSpy(serverSurface, &SurfaceInterface::damaged);
0746     QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
0747     image.fill(Qt::red);
0748     s->attachBuffer(m_shm->createBuffer(image));
0749     s->damage(QRect(0, 0, 100, 100));
0750     s->commit(KWayland::Client::Surface::CommitFlag::None);
0751     QVERIFY(damagedSpy.wait());
0752     QVERIFY(serverSurface->buffer());
0753 
0754     // attach another buffer
0755     image.fill(Qt::blue);
0756     s->attachBuffer(m_shm->createBuffer(image));
0757     m_connection->flush();
0758 
0759     // Let's try to destroy it
0760     delete m_shm;
0761     m_shm = nullptr;
0762     QTRY_VERIFY(serverSurface->buffer()->isDropped());
0763 }
0764 
0765 void TestWaylandSurface::testDestroyWithPendingCallback()
0766 {
0767     // this test tries to verify that destroying a surface with a pending callback works correctly
0768     // first create surface
0769     using namespace KWin;
0770     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0771     QVERIFY(s != nullptr);
0772     QVERIFY(s->isValid());
0773     QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
0774     QVERIFY(surfaceCreatedSpy.wait());
0775     auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
0776     QVERIFY(serverSurface);
0777 
0778     // now render to it
0779     QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
0780     img.fill(Qt::black);
0781     auto b = m_shm->createBuffer(img);
0782     s->attachBuffer(b);
0783     s->damage(QRect(0, 0, 10, 10));
0784     // add some frame callbacks
0785     for (int i = 0; i < 1000; i++) {
0786         wl_surface_frame(*s);
0787     }
0788     s->commit(KWayland::Client::Surface::CommitFlag::FrameCallback);
0789     QSignalSpy damagedSpy(serverSurface, &SurfaceInterface::damaged);
0790     QVERIFY(damagedSpy.wait());
0791 
0792     // now try to destroy the Surface again
0793     QSignalSpy destroyedSpy(serverSurface, &QObject::destroyed);
0794     s.reset();
0795     QVERIFY(destroyedSpy.wait());
0796 }
0797 
0798 void TestWaylandSurface::testDisconnect()
0799 {
0800     // this test verifies that the server side correctly tears down the resources when the client disconnects
0801     using namespace KWin;
0802     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0803     QVERIFY(s != nullptr);
0804     QVERIFY(s->isValid());
0805     QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
0806     QVERIFY(surfaceCreatedSpy.wait());
0807     auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
0808     QVERIFY(serverSurface);
0809 
0810     // destroy client
0811     QSignalSpy clientDisconnectedSpy(serverSurface->client(), &ClientConnection::disconnected);
0812     QSignalSpy surfaceDestroyedSpy(serverSurface, &QObject::destroyed);
0813     if (m_connection) {
0814         m_connection->deleteLater();
0815         m_connection = nullptr;
0816     }
0817     QVERIFY(clientDisconnectedSpy.wait());
0818     QCOMPARE(clientDisconnectedSpy.count(), 1);
0819     if (surfaceDestroyedSpy.isEmpty()) {
0820         QVERIFY(surfaceDestroyedSpy.wait());
0821     }
0822     QTRY_COMPARE(surfaceDestroyedSpy.count(), 1);
0823 
0824     s->destroy();
0825     m_shm->destroy();
0826     m_compositor->destroy();
0827     m_queue->destroy();
0828     m_idleInhibitManager->destroy();
0829 }
0830 
0831 void TestWaylandSurface::testOutput()
0832 {
0833     // This test verifies that the enter/leave are sent correctly to the Client
0834     using namespace KWin;
0835     qRegisterMetaType<KWayland::Client::Output *>();
0836     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0837     QVERIFY(s != nullptr);
0838     QVERIFY(s->isValid());
0839     QVERIFY(s->outputs().isEmpty());
0840     QSignalSpy enteredSpy(s.get(), &KWayland::Client::Surface::outputEntered);
0841     QSignalSpy leftSpy(s.get(), &KWayland::Client::Surface::outputLeft);
0842     // wait for the surface on the Server side
0843     QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
0844     QVERIFY(surfaceCreatedSpy.wait());
0845     auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
0846     QVERIFY(serverSurface);
0847     QCOMPARE(serverSurface->outputs(), QList<OutputInterface *>());
0848 
0849     // create another registry to get notified about added outputs
0850     KWayland::Client::Registry registry;
0851     registry.setEventQueue(m_queue);
0852     QSignalSpy allAnnounced(&registry, &KWayland::Client::Registry::interfacesAnnounced);
0853     registry.create(m_connection);
0854     QVERIFY(registry.isValid());
0855     registry.setup();
0856     QVERIFY(allAnnounced.wait());
0857     QSignalSpy outputAnnouncedSpy(&registry, &KWayland::Client::Registry::outputAnnounced);
0858 
0859     auto outputHandle = std::make_unique<FakeOutput>();
0860     auto serverOutput = std::make_unique<OutputInterface>(m_display, outputHandle.get());
0861     QVERIFY(outputAnnouncedSpy.wait());
0862     std::unique_ptr<KWayland::Client::Output> clientOutput(
0863         registry.createOutput(outputAnnouncedSpy.first().first().value<quint32>(), outputAnnouncedSpy.first().last().value<quint32>()));
0864     QVERIFY(clientOutput->isValid());
0865     m_connection->flush();
0866     m_display->dispatchEvents();
0867 
0868     // now enter it
0869     serverSurface->setOutputs(QList<OutputInterface *>{serverOutput.get()}, serverOutput.get());
0870     QCOMPARE(serverSurface->outputs(), QList<OutputInterface *>{serverOutput.get()});
0871     QVERIFY(enteredSpy.wait());
0872     QCOMPARE(enteredSpy.count(), 1);
0873     QCOMPARE(enteredSpy.first().first().value<KWayland::Client::Output *>(), clientOutput.get());
0874     QCOMPARE(s->outputs(), QList<KWayland::Client::Output *>{clientOutput.get()});
0875 
0876     // adding to same should not trigger
0877     serverSurface->setOutputs(QList<OutputInterface *>{serverOutput.get()}, serverOutput.get());
0878 
0879     // leave again
0880     serverSurface->setOutputs(QList<OutputInterface *>(), nullptr);
0881     QCOMPARE(serverSurface->outputs(), QList<OutputInterface *>());
0882     QVERIFY(leftSpy.wait());
0883     QCOMPARE(enteredSpy.count(), 1);
0884     QCOMPARE(leftSpy.count(), 1);
0885     QCOMPARE(leftSpy.first().first().value<KWayland::Client::Output *>(), clientOutput.get());
0886     QCOMPARE(s->outputs(), QList<KWayland::Client::Output *>());
0887 
0888     // leave again should not trigger
0889     serverSurface->setOutputs(QList<OutputInterface *>(), nullptr);
0890 
0891     // and enter again, just to verify
0892     serverSurface->setOutputs(QList<OutputInterface *>{serverOutput.get()}, serverOutput.get());
0893     QCOMPARE(serverSurface->outputs(), QList<OutputInterface *>{serverOutput.get()});
0894     QVERIFY(enteredSpy.wait());
0895     QCOMPARE(enteredSpy.count(), 2);
0896     QCOMPARE(leftSpy.count(), 1);
0897 
0898     // delete output client is on.
0899     // client should get an exit and be left on no outputs (which is allowed)
0900     serverOutput.reset();
0901     outputHandle.reset();
0902     QVERIFY(leftSpy.wait());
0903     QCOMPARE(serverSurface->outputs(), QList<OutputInterface *>());
0904 }
0905 
0906 void TestWaylandSurface::testInhibit()
0907 {
0908     using namespace KWin;
0909     std::unique_ptr<KWayland::Client::Surface> s(m_compositor->createSurface());
0910     // wait for the surface on the Server side
0911     QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
0912     QVERIFY(surfaceCreatedSpy.wait());
0913     auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>();
0914     QVERIFY(serverSurface);
0915     QCOMPARE(serverSurface->inhibitsIdle(), false);
0916 
0917     QSignalSpy inhibitsChangedSpy(serverSurface, &SurfaceInterface::inhibitsIdleChanged);
0918 
0919     // now create an idle inhibition
0920     std::unique_ptr<KWayland::Client::IdleInhibitor> inhibitor1(m_idleInhibitManager->createInhibitor(s.get()));
0921     QVERIFY(inhibitsChangedSpy.wait());
0922     QCOMPARE(serverSurface->inhibitsIdle(), true);
0923 
0924     // creating a second idle inhibition should not trigger the signal
0925     std::unique_ptr<KWayland::Client::IdleInhibitor> inhibitor2(m_idleInhibitManager->createInhibitor(s.get()));
0926     QVERIFY(!inhibitsChangedSpy.wait(500));
0927     QCOMPARE(serverSurface->inhibitsIdle(), true);
0928 
0929     // and also deleting the first inhibitor should not yet change the inhibition
0930     inhibitor1.reset();
0931     QVERIFY(!inhibitsChangedSpy.wait(500));
0932     QCOMPARE(serverSurface->inhibitsIdle(), true);
0933 
0934     // but deleting also the second inhibitor should trigger
0935     inhibitor2.reset();
0936     QVERIFY(inhibitsChangedSpy.wait());
0937     QCOMPARE(serverSurface->inhibitsIdle(), false);
0938     QCOMPARE(inhibitsChangedSpy.count(), 2);
0939 
0940     // recreate inhibitor1 should inhibit again
0941     inhibitor1.reset(m_idleInhibitManager->createInhibitor(s.get()));
0942     QVERIFY(inhibitsChangedSpy.wait());
0943     QCOMPARE(serverSurface->inhibitsIdle(), true);
0944     // and destroying should uninhibit
0945     inhibitor1.reset();
0946     QVERIFY(inhibitsChangedSpy.wait());
0947     QCOMPARE(serverSurface->inhibitsIdle(), false);
0948     QCOMPARE(inhibitsChangedSpy.count(), 4);
0949 }
0950 
0951 QTEST_GUILESS_MAIN(TestWaylandSurface)
0952 #include "test_wayland_surface.moc"