File indexing completed on 2024-11-10 04:56:16

0001 /*
0002     SPDX-FileCopyrightText: 2015 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/server_decoration.h"
0013 
0014 #include "qwayland-server-decoration.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/surface.h"
0021 
0022 class ServerSideDecorationManager : public QtWayland::org_kde_kwin_server_decoration_manager
0023 {
0024 };
0025 
0026 class ServerSideDecoration : public QObject, public QtWayland::org_kde_kwin_server_decoration
0027 {
0028     Q_OBJECT
0029 
0030 public:
0031     ~ServerSideDecoration() override
0032     {
0033         release();
0034     }
0035 
0036 Q_SIGNALS:
0037     void modeChanged(ServerSideDecorationManager::mode mode);
0038 
0039 protected:
0040     void org_kde_kwin_server_decoration_mode(uint32_t mode) override
0041     {
0042         Q_EMIT modeChanged(ServerSideDecorationManager::mode(mode));
0043     }
0044 };
0045 
0046 class TestServerSideDecoration : public QObject
0047 {
0048     Q_OBJECT
0049 public:
0050     explicit TestServerSideDecoration(QObject *parent = nullptr);
0051 private Q_SLOTS:
0052     void init();
0053     void cleanup();
0054 
0055     void testCreate_data();
0056     void testCreate();
0057 
0058     void testRequest_data();
0059     void testRequest();
0060 
0061     void testSurfaceDestroy();
0062 
0063 private:
0064     KWin::Display *m_display = nullptr;
0065     KWin::CompositorInterface *m_compositorInterface = nullptr;
0066     KWin::ServerSideDecorationManagerInterface *m_serverSideDecorationManagerInterface = nullptr;
0067     KWayland::Client::ConnectionThread *m_connection = nullptr;
0068     KWayland::Client::Compositor *m_compositor = nullptr;
0069     KWayland::Client::EventQueue *m_queue = nullptr;
0070     ServerSideDecorationManager *m_serverSideDecorationManager = nullptr;
0071     QThread *m_thread = nullptr;
0072     KWayland::Client::Registry *m_registry = nullptr;
0073 };
0074 
0075 static const QString s_socketName = QStringLiteral("kwayland-test-wayland-server-side-decoration-0");
0076 
0077 TestServerSideDecoration::TestServerSideDecoration(QObject *parent)
0078     : QObject(parent)
0079 {
0080 }
0081 
0082 void TestServerSideDecoration::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 
0091     // setup connection
0092     m_connection = new KWayland::Client::ConnectionThread;
0093     QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
0094     m_connection->setSocketName(s_socketName);
0095 
0096     m_thread = new QThread(this);
0097     m_connection->moveToThread(m_thread);
0098     m_thread->start();
0099 
0100     m_connection->initConnection();
0101     QVERIFY(connectedSpy.wait());
0102 
0103     m_queue = new KWayland::Client::EventQueue(this);
0104     QVERIFY(!m_queue->isValid());
0105     m_queue->setup(m_connection);
0106     QVERIFY(m_queue->isValid());
0107 
0108     m_compositorInterface = new CompositorInterface(m_display, m_display);
0109     m_serverSideDecorationManagerInterface = new ServerSideDecorationManagerInterface(m_display, m_display);
0110 
0111     m_registry = new KWayland::Client::Registry();
0112     connect(m_registry, &KWayland::Client::Registry::interfaceAnnounced, this, [this](const QByteArray &interfaceName, quint32 name, quint32 version) {
0113         if (interfaceName == org_kde_kwin_server_decoration_manager_interface.name) {
0114             m_serverSideDecorationManager = new ServerSideDecorationManager();
0115             m_serverSideDecorationManager->init(*m_registry, name, version);
0116         }
0117     });
0118 
0119     QSignalSpy interfacesAnnouncedSpy(m_registry, &KWayland::Client::Registry::interfacesAnnounced);
0120     QSignalSpy compositorSpy(m_registry, &KWayland::Client::Registry::compositorAnnounced);
0121 
0122     QVERIFY(!m_registry->eventQueue());
0123     m_registry->setEventQueue(m_queue);
0124     QCOMPARE(m_registry->eventQueue(), m_queue);
0125     m_registry->create(m_connection);
0126     QVERIFY(m_registry->isValid());
0127     m_registry->setup();
0128     QVERIFY(interfacesAnnouncedSpy.wait());
0129 
0130     m_compositor = m_registry->createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
0131 
0132     QVERIFY(m_compositor);
0133     QVERIFY(m_serverSideDecorationManager);
0134 }
0135 
0136 void TestServerSideDecoration::cleanup()
0137 {
0138     if (m_compositor) {
0139         delete m_compositor;
0140         m_compositor = nullptr;
0141     }
0142     if (m_serverSideDecorationManager) {
0143         delete m_serverSideDecorationManager;
0144         m_serverSideDecorationManager = nullptr;
0145     }
0146     if (m_registry) {
0147         delete m_registry;
0148         m_registry = nullptr;
0149     }
0150 
0151     if (m_queue) {
0152         delete m_queue;
0153         m_queue = nullptr;
0154     }
0155 
0156     if (m_thread) {
0157         m_thread->quit();
0158         m_thread->wait();
0159         delete m_thread;
0160         m_thread = nullptr;
0161     }
0162     delete m_connection;
0163     m_connection = nullptr;
0164 
0165     delete m_display;
0166     m_display = nullptr;
0167 }
0168 
0169 void TestServerSideDecoration::testCreate_data()
0170 {
0171     using namespace KWin;
0172     QTest::addColumn<ServerSideDecorationManagerInterface::Mode>("serverMode");
0173     QTest::addColumn<ServerSideDecorationManager::mode>("clientMode");
0174 
0175     QTest::newRow("none") << ServerSideDecorationManagerInterface::Mode::None << ServerSideDecorationManager::mode_None;
0176     QTest::newRow("client") << ServerSideDecorationManagerInterface::Mode::Client << ServerSideDecorationManager::mode_Client;
0177     QTest::newRow("server") << ServerSideDecorationManagerInterface::Mode::Server << ServerSideDecorationManager::mode_Server;
0178 }
0179 
0180 void TestServerSideDecoration::testCreate()
0181 {
0182     using namespace KWin;
0183     QFETCH(KWin::ServerSideDecorationManagerInterface::Mode, serverMode);
0184     m_serverSideDecorationManagerInterface->setDefaultMode(serverMode);
0185     QCOMPARE(m_serverSideDecorationManagerInterface->defaultMode(), serverMode);
0186 
0187     QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
0188     QSignalSpy decorationCreated(m_serverSideDecorationManagerInterface, &ServerSideDecorationManagerInterface::decorationCreated);
0189 
0190     std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
0191     QVERIFY(serverSurfaceCreated.wait());
0192 
0193     auto serverSurface = serverSurfaceCreated.first().first().value<SurfaceInterface *>();
0194     QVERIFY(!ServerSideDecorationInterface::get(serverSurface));
0195 
0196     // create server side deco
0197     auto serverSideDecoration = std::make_unique<ServerSideDecoration>();
0198     serverSideDecoration->init(m_serverSideDecorationManager->create(*surface.get()));
0199     QSignalSpy modeChangedSpy(serverSideDecoration.get(), &ServerSideDecoration::modeChanged);
0200 
0201     QVERIFY(decorationCreated.wait());
0202 
0203     auto serverDeco = decorationCreated.first().first().value<ServerSideDecorationInterface *>();
0204     QVERIFY(serverDeco);
0205     QCOMPARE(serverDeco, ServerSideDecorationInterface::get(serverSurface));
0206     QCOMPARE(serverDeco->surface(), serverSurface);
0207 
0208     // after binding the client should get the default mode
0209     QVERIFY(modeChangedSpy.wait());
0210     QCOMPARE(modeChangedSpy.count(), 1);
0211     QTEST(modeChangedSpy.last().at(0).value<ServerSideDecorationManager::mode>(), "clientMode");
0212 
0213     // and destroy
0214     QSignalSpy destroyedSpy(serverDeco, &QObject::destroyed);
0215     serverSideDecoration.reset();
0216     QVERIFY(destroyedSpy.wait());
0217 }
0218 
0219 void TestServerSideDecoration::testRequest_data()
0220 {
0221     using namespace KWin;
0222     QTest::addColumn<ServerSideDecorationManagerInterface::Mode>("defaultMode");
0223     QTest::addColumn<ServerSideDecorationManager::mode>("clientMode");
0224     QTest::addColumn<ServerSideDecorationManager::mode>("clientRequestMode");
0225     QTest::addColumn<ServerSideDecorationManagerInterface::Mode>("serverRequestedMode");
0226 
0227     const auto serverNone = ServerSideDecorationManagerInterface::Mode::None;
0228     const auto serverClient = ServerSideDecorationManagerInterface::Mode::Client;
0229     const auto serverServer = ServerSideDecorationManagerInterface::Mode::Server;
0230     const auto clientNone = ServerSideDecorationManager::mode_None;
0231     const auto clientClient = ServerSideDecorationManager::mode_Client;
0232     const auto clientServer = ServerSideDecorationManager::mode_Server;
0233 
0234     QTest::newRow("none->none") << serverNone << clientNone << clientNone << serverNone;
0235     QTest::newRow("none->client") << serverNone << clientNone << clientClient << serverClient;
0236     QTest::newRow("none->server") << serverNone << clientNone << clientServer << serverServer;
0237     QTest::newRow("client->none") << serverClient << clientClient << clientNone << serverNone;
0238     QTest::newRow("client->client") << serverClient << clientClient << clientClient << serverClient;
0239     QTest::newRow("client->server") << serverClient << clientClient << clientServer << serverServer;
0240     QTest::newRow("server->none") << serverServer << clientServer << clientNone << serverNone;
0241     QTest::newRow("server->client") << serverServer << clientServer << clientClient << serverClient;
0242     QTest::newRow("server->server") << serverServer << clientServer << clientServer << serverServer;
0243 }
0244 
0245 void TestServerSideDecoration::testRequest()
0246 {
0247     using namespace KWin;
0248     QFETCH(KWin::ServerSideDecorationManagerInterface::Mode, defaultMode);
0249     m_serverSideDecorationManagerInterface->setDefaultMode(defaultMode);
0250     QCOMPARE(m_serverSideDecorationManagerInterface->defaultMode(), defaultMode);
0251 
0252     QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
0253     QSignalSpy decorationCreated(m_serverSideDecorationManagerInterface, &ServerSideDecorationManagerInterface::decorationCreated);
0254 
0255     // create server side deco
0256     std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
0257 
0258     auto serverSideDecoration = std::make_unique<ServerSideDecoration>();
0259     serverSideDecoration->init(m_serverSideDecorationManager->create(*surface.get()));
0260     QSignalSpy modeChangedSpy(serverSideDecoration.get(), &ServerSideDecoration::modeChanged);
0261     QVERIFY(decorationCreated.wait());
0262 
0263     auto serverDeco = decorationCreated.first().first().value<ServerSideDecorationInterface *>();
0264     QVERIFY(serverDeco);
0265     QSignalSpy preferredModeChangedSpy(serverDeco, &ServerSideDecorationInterface::preferredModeChanged);
0266 
0267     // after binding the client should get the default mode
0268     QVERIFY(modeChangedSpy.wait());
0269     QCOMPARE(modeChangedSpy.count(), 1);
0270     QTEST(modeChangedSpy.last().at(0).value<ServerSideDecorationManager::mode>(), "clientMode");
0271 
0272     // request a change
0273     QFETCH(ServerSideDecorationManager::mode, clientRequestMode);
0274     serverSideDecoration->request_mode(clientRequestMode);
0275     // mode not yet changed
0276     QCOMPARE(modeChangedSpy.count(), 1);
0277 
0278     QVERIFY(preferredModeChangedSpy.wait());
0279     QCOMPARE(preferredModeChangedSpy.count(), 1);
0280     QFETCH(ServerSideDecorationManagerInterface::Mode, serverRequestedMode);
0281     QCOMPARE(serverDeco->preferredMode(), serverRequestedMode);
0282 
0283     // mode not yet changed
0284     QCOMPARE(serverDeco->mode(), defaultMode);
0285     serverDeco->setMode(serverRequestedMode);
0286     QCOMPARE(serverDeco->mode(), serverRequestedMode);
0287 
0288     // should be sent to client
0289     QVERIFY(modeChangedSpy.wait());
0290     QCOMPARE(modeChangedSpy.count(), 2);
0291     QCOMPARE(modeChangedSpy.last().at(0).value<ServerSideDecorationManager::mode>(), clientRequestMode);
0292 }
0293 
0294 void TestServerSideDecoration::testSurfaceDestroy()
0295 {
0296     using namespace KWin;
0297     QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
0298     QSignalSpy decorationCreated(m_serverSideDecorationManagerInterface, &ServerSideDecorationManagerInterface::decorationCreated);
0299 
0300     std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
0301     QVERIFY(serverSurfaceCreated.wait());
0302 
0303     auto serverSurface = serverSurfaceCreated.first().first().value<SurfaceInterface *>();
0304     auto serverSideDecoration = std::make_unique<ServerSideDecoration>();
0305     serverSideDecoration->init(m_serverSideDecorationManager->create(*surface.get()));
0306     QSignalSpy modeChangedSpy(serverSideDecoration.get(), &ServerSideDecoration::modeChanged);
0307     QVERIFY(decorationCreated.wait());
0308     auto serverDeco = decorationCreated.first().first().value<ServerSideDecorationInterface *>();
0309     QVERIFY(serverDeco);
0310 
0311     // destroy the parent surface
0312     QSignalSpy surfaceDestroyedSpy(serverSurface, &QObject::destroyed);
0313     QSignalSpy decorationDestroyedSpy(serverDeco, &QObject::destroyed);
0314     surface.reset();
0315     QVERIFY(surfaceDestroyedSpy.wait());
0316     QVERIFY(decorationDestroyedSpy.isEmpty());
0317     // destroy the blur
0318     serverSideDecoration.reset();
0319     QVERIFY(decorationDestroyedSpy.wait());
0320 }
0321 
0322 QTEST_GUILESS_MAIN(TestServerSideDecoration)
0323 #include "test_server_side_decoration.moc"