File indexing completed on 2024-06-16 05:05:05

0001 /*
0002     SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include <QSignalSpy>
0008 #include <QTest>
0009 #include <QThread>
0010 
0011 #include "wayland/compositor.h"
0012 #include "wayland/display.h"
0013 #include "wayland/surface.h"
0014 #include "wayland/viewporter.h"
0015 
0016 #include "KWayland/Client/compositor.h"
0017 #include "KWayland/Client/connection_thread.h"
0018 #include "KWayland/Client/event_queue.h"
0019 #include "KWayland/Client/registry.h"
0020 #include "KWayland/Client/shm_pool.h"
0021 #include "KWayland/Client/surface.h"
0022 
0023 #include "qwayland-viewporter.h"
0024 
0025 using namespace KWin;
0026 
0027 class Viewporter : public QtWayland::wp_viewporter
0028 {
0029 };
0030 
0031 class Viewport : public QtWayland::wp_viewport
0032 {
0033 };
0034 
0035 class TestViewporterInterface : public QObject
0036 {
0037     Q_OBJECT
0038 
0039 public:
0040     ~TestViewporterInterface() override;
0041 
0042 private Q_SLOTS:
0043     void initTestCase();
0044     void testCropScale();
0045 
0046 private:
0047     KWayland::Client::ConnectionThread *m_connection;
0048     KWayland::Client::EventQueue *m_queue;
0049     KWayland::Client::Compositor *m_clientCompositor;
0050     KWayland::Client::ShmPool *m_shm;
0051 
0052     QThread *m_thread;
0053     KWin::Display m_display;
0054     CompositorInterface *m_serverCompositor;
0055     Viewporter *m_viewporter;
0056 };
0057 
0058 static const QString s_socketName = QStringLiteral("kwin-wayland-server-viewporter-test-0");
0059 
0060 void TestViewporterInterface::initTestCase()
0061 {
0062     m_display.addSocketName(s_socketName);
0063     m_display.start();
0064     QVERIFY(m_display.isRunning());
0065 
0066     m_display.createShm();
0067     new ViewporterInterface(&m_display);
0068 
0069     m_serverCompositor = new CompositorInterface(&m_display, this);
0070 
0071     m_connection = new KWayland::Client::ConnectionThread;
0072     QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
0073     m_connection->setSocketName(s_socketName);
0074 
0075     m_thread = new QThread(this);
0076     m_connection->moveToThread(m_thread);
0077     m_thread->start();
0078 
0079     m_connection->initConnection();
0080     QVERIFY(connectedSpy.wait());
0081     QVERIFY(!m_connection->connections().isEmpty());
0082 
0083     m_queue = new KWayland::Client::EventQueue(this);
0084     QVERIFY(!m_queue->isValid());
0085     m_queue->setup(m_connection);
0086     QVERIFY(m_queue->isValid());
0087 
0088     auto registry = new KWayland::Client::Registry(this);
0089     connect(registry, &KWayland::Client::Registry::interfaceAnnounced, this, [this, registry](const QByteArray &interface, quint32 id, quint32 version) {
0090         if (interface == QByteArrayLiteral("wp_viewporter")) {
0091             m_viewporter = new Viewporter();
0092             m_viewporter->init(*registry, id, version);
0093         }
0094     });
0095     QSignalSpy allAnnouncedSpy(registry, &KWayland::Client::Registry::interfaceAnnounced);
0096     QSignalSpy compositorSpy(registry, &KWayland::Client::Registry::compositorAnnounced);
0097     QSignalSpy shmSpy(registry, &KWayland::Client::Registry::shmAnnounced);
0098     registry->setEventQueue(m_queue);
0099     registry->create(m_connection->display());
0100     QVERIFY(registry->isValid());
0101     registry->setup();
0102     QVERIFY(allAnnouncedSpy.wait());
0103 
0104     m_clientCompositor = registry->createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
0105     QVERIFY(m_clientCompositor->isValid());
0106 
0107     m_shm = registry->createShmPool(shmSpy.first().first().value<quint32>(), shmSpy.first().last().value<quint32>(), this);
0108     QVERIFY(m_shm->isValid());
0109 }
0110 
0111 TestViewporterInterface::~TestViewporterInterface()
0112 {
0113     if (m_viewporter) {
0114         delete m_viewporter;
0115         m_viewporter = nullptr;
0116     }
0117     if (m_shm) {
0118         delete m_shm;
0119         m_shm = nullptr;
0120     }
0121     if (m_queue) {
0122         delete m_queue;
0123         m_queue = nullptr;
0124     }
0125     if (m_thread) {
0126         m_thread->quit();
0127         m_thread->wait();
0128         delete m_thread;
0129         m_thread = nullptr;
0130     }
0131     m_connection->deleteLater();
0132     m_connection = nullptr;
0133 }
0134 
0135 void TestViewporterInterface::testCropScale()
0136 {
0137     // Create a test surface.
0138     QSignalSpy serverSurfaceCreatedSpy(m_serverCompositor, &CompositorInterface::surfaceCreated);
0139     std::unique_ptr<KWayland::Client::Surface> clientSurface(m_clientCompositor->createSurface(this));
0140     QVERIFY(serverSurfaceCreatedSpy.wait());
0141     SurfaceInterface *serverSurface = serverSurfaceCreatedSpy.first().first().value<SurfaceInterface *>();
0142     QVERIFY(serverSurface);
0143 
0144     QSignalSpy serverSurfaceMappedSpy(serverSurface, &SurfaceInterface::mapped);
0145     QSignalSpy serverSurfaceSizeChangedSpy(serverSurface, &SurfaceInterface::sizeChanged);
0146     QSignalSpy bufferSourceBoxChangedSpy(serverSurface, &SurfaceInterface::bufferSourceBoxChanged);
0147 
0148     // Map the surface.
0149     QImage image(QSize(200, 100), QImage::Format_ARGB32_Premultiplied);
0150     image.fill(Qt::black);
0151     KWayland::Client::Buffer::Ptr buffer = m_shm->createBuffer(image);
0152     clientSurface->attachBuffer(buffer);
0153     clientSurface->setScale(2);
0154     clientSurface->damage(image.rect());
0155     clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
0156     QVERIFY(serverSurfaceMappedSpy.wait());
0157     QCOMPARE(bufferSourceBoxChangedSpy.count(), 1);
0158     QCOMPARE(serverSurface->size(), QSize(100, 50));
0159     QCOMPARE(serverSurface->bufferSourceBox(), QRectF(0, 0, 200, 100));
0160 
0161     // Create a viewport for the surface.
0162     std::unique_ptr<Viewport> clientViewport(new Viewport);
0163     clientViewport->init(m_viewporter->get_viewport(*clientSurface));
0164 
0165     // Crop the surface.
0166     clientViewport->set_source(wl_fixed_from_double(10), wl_fixed_from_double(10), wl_fixed_from_double(30), wl_fixed_from_double(20));
0167     clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
0168     QVERIFY(serverSurfaceSizeChangedSpy.wait());
0169     QCOMPARE(bufferSourceBoxChangedSpy.count(), 2);
0170     QCOMPARE(serverSurface->size(), QSize(30, 20));
0171     QCOMPARE(serverSurface->bufferSourceBox(), QRectF(20, 20, 60, 40));
0172 
0173     // Scale the surface.
0174     clientViewport->set_destination(500, 250);
0175     clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
0176     QVERIFY(serverSurfaceSizeChangedSpy.wait());
0177     QCOMPARE(bufferSourceBoxChangedSpy.count(), 2);
0178     QCOMPARE(serverSurface->size(), QSize(500, 250));
0179     QCOMPARE(serverSurface->bufferSourceBox(), QRectF(20, 20, 60, 40));
0180 
0181     // If the viewport is destroyed, the crop and scale state will be unset on a next commit.
0182     clientViewport->destroy();
0183     clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
0184     QVERIFY(serverSurfaceSizeChangedSpy.wait());
0185     QCOMPARE(bufferSourceBoxChangedSpy.count(), 3);
0186     QCOMPARE(serverSurface->size(), QSize(100, 50));
0187     QCOMPARE(serverSurface->bufferSourceBox(), QRectF(0, 0, 200, 100));
0188 }
0189 
0190 QTEST_GUILESS_MAIN(TestViewporterInterface)
0191 
0192 #include "test_viewporter_interface.moc"