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

0001 /*
0002     SPDX-FileCopyrightText: 2016 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 
0010 // server
0011 #include "wayland/compositor.h"
0012 #include "wayland/display.h"
0013 #include "wayland/plasmashell.h"
0014 
0015 // client
0016 #include "KWayland/Client/compositor.h"
0017 #include "KWayland/Client/connection_thread.h"
0018 #include "KWayland/Client/event_queue.h"
0019 #include "KWayland/Client/plasmashell.h"
0020 #include "KWayland/Client/registry.h"
0021 #include "KWayland/Client/surface.h"
0022 
0023 #include <wayland-client-protocol.h>
0024 
0025 #include <cerrno> // For EPROTO
0026 
0027 using namespace KWin;
0028 
0029 class ErrorTest : public QObject
0030 {
0031     Q_OBJECT
0032 private Q_SLOTS:
0033     void init();
0034     void cleanup();
0035 
0036     void testMultiplePlasmaShellSurfacesForSurface();
0037 
0038 private:
0039     KWin::Display *m_display = nullptr;
0040     CompositorInterface *m_ci = nullptr;
0041     PlasmaShellInterface *m_psi = nullptr;
0042     KWayland::Client::ConnectionThread *m_connection = nullptr;
0043     QThread *m_thread = nullptr;
0044     KWayland::Client::EventQueue *m_queue = nullptr;
0045     KWayland::Client::Compositor *m_compositor = nullptr;
0046     KWayland::Client::PlasmaShell *m_plasmaShell = nullptr;
0047 };
0048 
0049 static const QString s_socketName = QStringLiteral("kwayland-test-error-0");
0050 
0051 void ErrorTest::init()
0052 {
0053     delete m_display;
0054     m_display = new KWin::Display(this);
0055     m_display->addSocketName(s_socketName);
0056     m_display->start();
0057     QVERIFY(m_display->isRunning());
0058     m_display->createShm();
0059     m_ci = new CompositorInterface(m_display, m_display);
0060     m_psi = new PlasmaShellInterface(m_display, m_display);
0061 
0062     // setup connection
0063     m_connection = new KWayland::Client::ConnectionThread;
0064     QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
0065     m_connection->setSocketName(s_socketName);
0066 
0067     m_thread = new QThread(this);
0068     m_connection->moveToThread(m_thread);
0069     m_thread->start();
0070 
0071     m_connection->initConnection();
0072     QVERIFY(connectedSpy.wait());
0073 
0074     m_queue = new KWayland::Client::EventQueue(this);
0075     m_queue->setup(m_connection);
0076 
0077     KWayland::Client::Registry registry;
0078     QSignalSpy interfacesAnnouncedSpy(&registry, &KWayland::Client::Registry::interfacesAnnounced);
0079     registry.setEventQueue(m_queue);
0080     registry.create(m_connection);
0081     QVERIFY(registry.isValid());
0082     registry.setup();
0083     QVERIFY(interfacesAnnouncedSpy.wait());
0084 
0085     m_compositor =
0086         registry.createCompositor(registry.interface(KWayland::Client::Registry::Interface::Compositor).name, registry.interface(KWayland::Client::Registry::Interface::Compositor).version, this);
0087     QVERIFY(m_compositor);
0088     m_plasmaShell = registry.createPlasmaShell(registry.interface(KWayland::Client::Registry::Interface::PlasmaShell).name,
0089                                                registry.interface(KWayland::Client::Registry::Interface::PlasmaShell).version,
0090                                                this);
0091     QVERIFY(m_plasmaShell);
0092 }
0093 
0094 void ErrorTest::cleanup()
0095 {
0096 #define CLEANUP(variable)   \
0097     if (variable) {         \
0098         delete variable;    \
0099         variable = nullptr; \
0100     }
0101     CLEANUP(m_plasmaShell)
0102     CLEANUP(m_compositor)
0103     CLEANUP(m_queue)
0104     if (m_connection) {
0105         m_connection->deleteLater();
0106         m_connection = nullptr;
0107     }
0108     if (m_thread) {
0109         m_thread->quit();
0110         m_thread->wait();
0111         delete m_thread;
0112         m_thread = nullptr;
0113     }
0114     CLEANUP(m_display)
0115 #undef CLEANUP
0116     // these are the children of the display
0117     m_psi = nullptr;
0118     m_ci = nullptr;
0119 }
0120 
0121 void ErrorTest::testMultiplePlasmaShellSurfacesForSurface()
0122 {
0123     // this test verifies that creating two ShellSurfaces for the same Surface triggers a protocol error
0124     QSignalSpy errorSpy(m_connection, &KWayland::Client::ConnectionThread::errorOccurred);
0125     // PlasmaShell is too smart and doesn't allow us to create a second PlasmaShellSurface
0126     // thus we need to cheat by creating a surface manually
0127     auto surface = wl_compositor_create_surface(*m_compositor);
0128     std::unique_ptr<KWayland::Client::PlasmaShellSurface> shellSurface1(m_plasmaShell->createSurface(surface));
0129     std::unique_ptr<KWayland::Client::PlasmaShellSurface> shellSurface2(m_plasmaShell->createSurface(surface));
0130     QVERIFY(!m_connection->hasError());
0131     QVERIFY(errorSpy.wait());
0132     QVERIFY(m_connection->hasError());
0133     QCOMPARE(m_connection->errorCode(), EPROTO);
0134     wl_surface_destroy(surface);
0135 }
0136 
0137 QTEST_GUILESS_MAIN(ErrorTest)
0138 #include "test_error.moc"