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

0001 /*
0002     SPDX-FileCopyrightText: 2020 Benjamin Port <benjamin.port@enioka.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 // Qt
0008 #include <QHash>
0009 #include <QSignalSpy>
0010 #include <QTest>
0011 #include <QThread>
0012 // WaylandServer
0013 #include "wayland/compositor.h"
0014 #include "wayland/display.h"
0015 #include "wayland/keyboard_shortcuts_inhibit_v1.h"
0016 #include "wayland/seat.h"
0017 
0018 #include "KWayland/Client/compositor.h"
0019 #include "KWayland/Client/connection_thread.h"
0020 #include "KWayland/Client/event_queue.h"
0021 #include "KWayland/Client/registry.h"
0022 #include "KWayland/Client/seat.h"
0023 #include "KWayland/Client/surface.h"
0024 
0025 #include "qwayland-keyboard-shortcuts-inhibit-unstable-v1.h"
0026 
0027 using namespace KWin;
0028 
0029 class KeyboardShortcutsInhibitManager : public QObject, public QtWayland::zwp_keyboard_shortcuts_inhibit_manager_v1
0030 {
0031     Q_OBJECT
0032 public:
0033     KeyboardShortcutsInhibitManager(wl_registry *registry, quint32 id, quint32 version)
0034         : QtWayland::zwp_keyboard_shortcuts_inhibit_manager_v1(registry, id, version)
0035     {
0036     }
0037 };
0038 
0039 class KeyboardShortcutsInhibitor : public QObject, public QtWayland::zwp_keyboard_shortcuts_inhibitor_v1
0040 {
0041     Q_OBJECT
0042 public:
0043     KeyboardShortcutsInhibitor(::zwp_keyboard_shortcuts_inhibitor_v1 *inhibitorV1)
0044         : QtWayland::zwp_keyboard_shortcuts_inhibitor_v1(inhibitorV1)
0045     {
0046     }
0047 
0048     void zwp_keyboard_shortcuts_inhibitor_v1_active() override
0049     {
0050         Q_EMIT inhibitorActive();
0051     }
0052 
0053     void zwp_keyboard_shortcuts_inhibitor_v1_inactive() override
0054     {
0055         Q_EMIT inhibitorInactive();
0056     }
0057 
0058 Q_SIGNALS:
0059     void inhibitorActive();
0060     void inhibitorInactive();
0061 };
0062 
0063 class TestKeyboardShortcutsInhibitorInterface : public QObject
0064 {
0065     Q_OBJECT
0066 public:
0067     TestKeyboardShortcutsInhibitorInterface()
0068     {
0069     }
0070     ~TestKeyboardShortcutsInhibitorInterface() override;
0071 
0072 private Q_SLOTS:
0073     void initTestCase();
0074     void testKeyboardShortcuts();
0075 
0076 private:
0077     KWayland::Client::ConnectionThread *m_connection;
0078     KWayland::Client::EventQueue *m_queue;
0079     KWayland::Client::Compositor *m_clientCompositor;
0080     KWayland::Client::Seat *m_clientSeat = nullptr;
0081 
0082     QThread *m_thread;
0083     KWin::Display m_display;
0084     SeatInterface *m_seat;
0085     CompositorInterface *m_serverCompositor;
0086 
0087     KeyboardShortcutsInhibitManagerV1Interface *m_manager;
0088     QList<SurfaceInterface *> m_surfaces;
0089     QList<wl_surface *> m_clientSurfaces;
0090     KeyboardShortcutsInhibitManager *m_inhibitManagerClient = nullptr;
0091 };
0092 
0093 static const QString s_socketName = QStringLiteral("kwin-wayland-server-keyboard-shortcuts-inhibitor-test-0");
0094 
0095 void TestKeyboardShortcutsInhibitorInterface::initTestCase()
0096 {
0097     m_display.addSocketName(s_socketName);
0098     m_display.start();
0099     QVERIFY(m_display.isRunning());
0100 
0101     m_seat = new SeatInterface(&m_display, this);
0102     m_serverCompositor = new CompositorInterface(&m_display, this);
0103     m_manager = new KeyboardShortcutsInhibitManagerV1Interface(&m_display, this);
0104 
0105     connect(m_serverCompositor, &CompositorInterface::surfaceCreated, this, [this](SurfaceInterface *surface) {
0106         m_surfaces += surface;
0107     });
0108 
0109     // setup connection
0110     m_connection = new KWayland::Client::ConnectionThread;
0111     QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
0112     m_connection->setSocketName(s_socketName);
0113 
0114     m_thread = new QThread(this);
0115     m_connection->moveToThread(m_thread);
0116     m_thread->start();
0117 
0118     m_connection->initConnection();
0119     QVERIFY(connectedSpy.wait());
0120     QVERIFY(!m_connection->connections().isEmpty());
0121 
0122     m_queue = new KWayland::Client::EventQueue(this);
0123     QVERIFY(!m_queue->isValid());
0124     m_queue->setup(m_connection);
0125     QVERIFY(m_queue->isValid());
0126 
0127     auto registry = new KWayland::Client::Registry(this);
0128     connect(registry, &KWayland::Client::Registry::interfaceAnnounced, this, [this, registry](const QByteArray &interface, quint32 id, quint32 version) {
0129         if (interface == "zwp_keyboard_shortcuts_inhibit_manager_v1") {
0130             m_inhibitManagerClient = new KeyboardShortcutsInhibitManager(registry->registry(), id, version);
0131         }
0132     });
0133     connect(registry, &KWayland::Client::Registry::seatAnnounced, this, [this, registry](quint32 name, quint32 version) {
0134         m_clientSeat = registry->createSeat(name, version);
0135     });
0136     registry->setEventQueue(m_queue);
0137     QSignalSpy compositorSpy(registry, &KWayland::Client::Registry::compositorAnnounced);
0138     registry->create(m_connection->display());
0139     QVERIFY(registry->isValid());
0140     registry->setup();
0141     wl_display_flush(m_connection->display());
0142 
0143     QVERIFY(compositorSpy.wait());
0144     m_clientCompositor = registry->createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
0145     QVERIFY(m_clientCompositor->isValid());
0146 
0147     QSignalSpy surfaceSpy(m_serverCompositor, &CompositorInterface::surfaceCreated);
0148     for (int i = 0; i < 3; ++i) {
0149         KWayland::Client::Surface *s = m_clientCompositor->createSurface(this);
0150         m_clientSurfaces += s->operator wl_surface *();
0151     }
0152     QVERIFY(surfaceSpy.count() < 3 && surfaceSpy.wait(200));
0153     QVERIFY(m_surfaces.count() == 3);
0154     QVERIFY(m_inhibitManagerClient);
0155 }
0156 
0157 TestKeyboardShortcutsInhibitorInterface::~TestKeyboardShortcutsInhibitorInterface()
0158 {
0159     if (m_queue) {
0160         delete m_queue;
0161         m_queue = nullptr;
0162     }
0163     if (m_thread) {
0164         m_thread->quit();
0165         m_thread->wait();
0166         delete m_thread;
0167         m_thread = nullptr;
0168     }
0169     m_connection->deleteLater();
0170     m_connection = nullptr;
0171 }
0172 
0173 void TestKeyboardShortcutsInhibitorInterface::testKeyboardShortcuts()
0174 {
0175     auto clientSurface = m_clientSurfaces[0];
0176     auto surface = m_surfaces[0];
0177 
0178     // Test creation
0179     auto inhibitorClientV1 = m_inhibitManagerClient->inhibit_shortcuts(clientSurface, m_clientSeat->operator wl_seat *());
0180     auto inhibitorClient = new KeyboardShortcutsInhibitor(inhibitorClientV1);
0181     QSignalSpy inhibitorActiveSpy(inhibitorClient, &KeyboardShortcutsInhibitor::inhibitorActive);
0182     QSignalSpy inhibitorInactiveSpy(inhibitorClient, &KeyboardShortcutsInhibitor::inhibitorInactive);
0183     QSignalSpy inhibitorCreatedSpy(m_manager, &KeyboardShortcutsInhibitManagerV1Interface::inhibitorCreated);
0184     QVERIFY(inhibitorCreatedSpy.wait() || inhibitorCreatedSpy.count() == 1);
0185     auto inhibitorServer = m_manager->findInhibitor(surface, m_seat);
0186 
0187     // Test deactivate
0188     inhibitorServer->setActive(false);
0189     QVERIFY(inhibitorInactiveSpy.wait() || inhibitorInactiveSpy.count() == 1);
0190 
0191     // Test activate
0192     inhibitorServer->setActive(true);
0193     QVERIFY(inhibitorActiveSpy.wait() || inhibitorActiveSpy.count() == 1);
0194 
0195     // Test creating for another surface
0196     m_inhibitManagerClient->inhibit_shortcuts(m_clientSurfaces[1], m_clientSeat->operator wl_seat *());
0197     QVERIFY(inhibitorCreatedSpy.wait() || inhibitorCreatedSpy.count() == 2);
0198 
0199     // Test destroy is working
0200     inhibitorClient->destroy();
0201     m_inhibitManagerClient->inhibit_shortcuts(clientSurface, m_clientSeat->operator wl_seat *());
0202     QVERIFY(inhibitorCreatedSpy.wait() || inhibitorCreatedSpy.count() == 3);
0203 
0204     // Test creating with same surface / seat (expect error)
0205     QSignalSpy errorOccured(m_connection, &KWayland::Client::ConnectionThread::errorOccurred);
0206     m_inhibitManagerClient->inhibit_shortcuts(m_clientSurfaces[0], m_clientSeat->operator wl_seat *());
0207     QVERIFY(errorOccured.wait() || errorOccured.count() == 1);
0208 }
0209 
0210 QTEST_GUILESS_MAIN(TestKeyboardShortcutsInhibitorInterface)
0211 
0212 #include "test_keyboard_shortcuts_inhibitor_interface.moc"