File indexing completed on 2024-06-02 05:36:46

0001 /*
0002     SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@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/xdgdecoration_v1.h"
0013 #include "wayland/xdgshell.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/registry.h"
0019 #include "KWayland/Client/surface.h"
0020 #include "KWayland/Client/xdgdecoration.h"
0021 #include "KWayland/Client/xdgshell.h"
0022 
0023 class TestXdgDecoration : public QObject
0024 {
0025     Q_OBJECT
0026 public:
0027     explicit TestXdgDecoration(QObject *parent = nullptr);
0028 private Q_SLOTS:
0029     void init();
0030     void cleanup();
0031 
0032     void testDecoration_data();
0033     void testDecoration();
0034 
0035 private:
0036     KWin::Display *m_display = nullptr;
0037     KWin::CompositorInterface *m_compositorInterface = nullptr;
0038     KWin::XdgShellInterface *m_xdgShellInterface = nullptr;
0039     KWin::XdgDecorationManagerV1Interface *m_xdgDecorationManagerInterface = nullptr;
0040 
0041     KWayland::Client::ConnectionThread *m_connection = nullptr;
0042     KWayland::Client::Compositor *m_compositor = nullptr;
0043     KWayland::Client::EventQueue *m_queue = nullptr;
0044     KWayland::Client::XdgShell *m_xdgShell = nullptr;
0045     KWayland::Client::XdgDecorationManager *m_xdgDecorationManager = nullptr;
0046 
0047     QThread *m_thread = nullptr;
0048     KWayland::Client::Registry *m_registry = nullptr;
0049 };
0050 
0051 static const QString s_socketName = QStringLiteral("kwayland-test-wayland-server-side-decoration-0");
0052 
0053 TestXdgDecoration::TestXdgDecoration(QObject *parent)
0054     : QObject(parent)
0055 {
0056 }
0057 
0058 void TestXdgDecoration::init()
0059 {
0060     using namespace KWin;
0061 
0062     qRegisterMetaType<KWayland::Client::XdgDecoration::Mode>();
0063     qRegisterMetaType<XdgToplevelDecorationV1Interface::Mode>();
0064 
0065     delete m_display;
0066     m_display = new KWin::Display(this);
0067     m_display->addSocketName(s_socketName);
0068     m_display->start();
0069     QVERIFY(m_display->isRunning());
0070 
0071     // setup connection
0072     m_connection = new KWayland::Client::ConnectionThread;
0073     QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
0074     m_connection->setSocketName(s_socketName);
0075 
0076     m_thread = new QThread(this);
0077     m_connection->moveToThread(m_thread);
0078     m_thread->start();
0079 
0080     m_connection->initConnection();
0081     QVERIFY(connectedSpy.wait());
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     m_registry = new KWayland::Client::Registry();
0089     QSignalSpy compositorSpy(m_registry, &KWayland::Client::Registry::compositorAnnounced);
0090     QSignalSpy xdgShellSpy(m_registry, &KWayland::Client::Registry::xdgShellStableAnnounced);
0091     QSignalSpy xdgDecorationManagerSpy(m_registry, &KWayland::Client::Registry::xdgDecorationAnnounced);
0092 
0093     QVERIFY(!m_registry->eventQueue());
0094     m_registry->setEventQueue(m_queue);
0095     QCOMPARE(m_registry->eventQueue(), m_queue);
0096     m_registry->create(m_connection);
0097     QVERIFY(m_registry->isValid());
0098     m_registry->setup();
0099 
0100     m_compositorInterface = new CompositorInterface(m_display, m_display);
0101     QVERIFY(compositorSpy.wait());
0102     m_compositor = m_registry->createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
0103 
0104     m_xdgShellInterface = new XdgShellInterface(m_display, m_display);
0105     QVERIFY(xdgShellSpy.wait());
0106     m_xdgShell = m_registry->createXdgShell(xdgShellSpy.first().first().value<quint32>(), xdgShellSpy.first().last().value<quint32>(), this);
0107 
0108     m_xdgDecorationManagerInterface = new XdgDecorationManagerV1Interface(m_display, m_display);
0109 
0110     QVERIFY(xdgDecorationManagerSpy.wait());
0111     m_xdgDecorationManager = m_registry->createXdgDecorationManager(xdgDecorationManagerSpy.first().first().value<quint32>(),
0112                                                                     xdgDecorationManagerSpy.first().last().value<quint32>(),
0113                                                                     this);
0114 }
0115 
0116 void TestXdgDecoration::cleanup()
0117 {
0118     if (m_compositor) {
0119         delete m_compositor;
0120         m_compositor = nullptr;
0121     }
0122     if (m_xdgShell) {
0123         delete m_xdgShell;
0124         m_xdgShell = nullptr;
0125     }
0126     if (m_xdgDecorationManager) {
0127         delete m_xdgDecorationManager;
0128         m_xdgDecorationManager = nullptr;
0129     }
0130     if (m_queue) {
0131         delete m_queue;
0132         m_queue = nullptr;
0133     }
0134     if (m_registry) {
0135         delete m_registry;
0136         m_registry = nullptr;
0137     }
0138     if (m_thread) {
0139         m_thread->quit();
0140         m_thread->wait();
0141         delete m_thread;
0142         m_thread = nullptr;
0143     }
0144     delete m_connection;
0145     m_connection = nullptr;
0146 
0147     delete m_display;
0148     m_display = nullptr;
0149 }
0150 
0151 void TestXdgDecoration::testDecoration_data()
0152 {
0153     using namespace KWin;
0154     QTest::addColumn<KWin::XdgToplevelDecorationV1Interface::Mode>("configuredMode");
0155     QTest::addColumn<KWayland::Client::XdgDecoration::Mode>("configuredModeExp");
0156     QTest::addColumn<KWayland::Client::XdgDecoration::Mode>("setMode");
0157     QTest::addColumn<KWin::XdgToplevelDecorationV1Interface::Mode>("setModeExp");
0158 
0159     const auto serverClient = XdgToplevelDecorationV1Interface::Mode::Client;
0160     const auto serverServer = XdgToplevelDecorationV1Interface::Mode::Server;
0161     const auto clientClient = KWayland::Client::XdgDecoration::Mode::ClientSide;
0162     const auto clientServer = KWayland::Client::XdgDecoration::Mode::ServerSide;
0163 
0164     QTest::newRow("client->client") << serverClient << clientClient << clientClient << serverClient;
0165     QTest::newRow("client->server") << serverClient << clientClient << clientServer << serverServer;
0166     QTest::newRow("server->client") << serverServer << clientServer << clientClient << serverClient;
0167     QTest::newRow("server->server") << serverServer << clientServer << clientServer << serverServer;
0168 }
0169 
0170 void TestXdgDecoration::testDecoration()
0171 {
0172     using namespace KWin;
0173 
0174     QFETCH(KWin::XdgToplevelDecorationV1Interface::Mode, configuredMode);
0175     QFETCH(KWayland::Client::XdgDecoration::Mode, configuredModeExp);
0176     QFETCH(KWayland::Client::XdgDecoration::Mode, setMode);
0177     QFETCH(KWin::XdgToplevelDecorationV1Interface::Mode, setModeExp);
0178 
0179     QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
0180     QSignalSpy shellSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::toplevelCreated);
0181     QSignalSpy decorationCreatedSpy(m_xdgDecorationManagerInterface, &XdgDecorationManagerV1Interface::decorationCreated);
0182 
0183     // create shell surface and deco object
0184     std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface());
0185     std::unique_ptr<KWayland::Client::XdgShellSurface> shellSurface(m_xdgShell->createSurface(surface.get()));
0186     std::unique_ptr<KWayland::Client::XdgDecoration> decoration(m_xdgDecorationManager->getToplevelDecoration(shellSurface.get()));
0187 
0188     // and receive all these on the "server"
0189     QVERIFY(surfaceCreatedSpy.count() || surfaceCreatedSpy.wait());
0190     QVERIFY(shellSurfaceCreatedSpy.count() || shellSurfaceCreatedSpy.wait());
0191     QVERIFY(decorationCreatedSpy.count() || decorationCreatedSpy.wait());
0192 
0193     auto shellSurfaceIface = shellSurfaceCreatedSpy.first().first().value<XdgToplevelInterface *>();
0194     auto decorationIface = decorationCreatedSpy.first().first().value<XdgToplevelDecorationV1Interface *>();
0195 
0196     QVERIFY(decorationIface);
0197     QVERIFY(shellSurfaceIface);
0198     QCOMPARE(decorationIface->toplevel(), shellSurfaceIface);
0199     QCOMPARE(decorationIface->preferredMode(), XdgToplevelDecorationV1Interface::Mode::Undefined);
0200 
0201     QSignalSpy clientConfiguredSpy(decoration.get(), &KWayland::Client::XdgDecoration::modeChanged);
0202     QSignalSpy modeRequestedSpy(decorationIface, &XdgToplevelDecorationV1Interface::preferredModeChanged);
0203 
0204     // server configuring a client
0205     decorationIface->sendConfigure(configuredMode);
0206     quint32 serial = shellSurfaceIface->sendConfigure(QSize(0, 0), {});
0207     QVERIFY(clientConfiguredSpy.wait());
0208     QCOMPARE(clientConfiguredSpy.first().first().value<KWayland::Client::XdgDecoration::Mode>(), configuredModeExp);
0209 
0210     shellSurface->ackConfigure(serial);
0211 
0212     // client requesting another mode
0213     decoration->setMode(setMode);
0214     QVERIFY(modeRequestedSpy.wait());
0215     QCOMPARE(modeRequestedSpy.first().first().value<XdgToplevelDecorationV1Interface::Mode>(), setModeExp);
0216     QCOMPARE(decorationIface->preferredMode(), setModeExp);
0217     modeRequestedSpy.clear();
0218 
0219     decoration->unsetMode();
0220     QVERIFY(modeRequestedSpy.wait());
0221     QCOMPARE(modeRequestedSpy.first().first().value<XdgToplevelDecorationV1Interface::Mode>(), XdgToplevelDecorationV1Interface::Mode::Undefined);
0222 }
0223 
0224 QTEST_GUILESS_MAIN(TestXdgDecoration)
0225 #include "test_xdg_decoration.moc"