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

0001 /*
0002     SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
0003     SPDX-FileCopyrightText: 2021 David Redondo <kde@david-redondo.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 // Qt
0009 #include <QHash>
0010 #include <QSignalSpy>
0011 #include <QTest>
0012 #include <QThread>
0013 
0014 // WaylandServer
0015 #include "wayland/compositor.h"
0016 #include "wayland/datacontroldevice_v1.h"
0017 #include "wayland/datacontroldevicemanager_v1.h"
0018 #include "wayland/datacontrolsource_v1.h"
0019 #include "wayland/display.h"
0020 #include "wayland/seat.h"
0021 
0022 #include <KWayland/Client/compositor.h>
0023 #include <KWayland/Client/connection_thread.h>
0024 #include <KWayland/Client/event_queue.h>
0025 #include <KWayland/Client/registry.h>
0026 #include <KWayland/Client/seat.h>
0027 
0028 #include "qwayland-wlr-data-control-unstable-v1.h"
0029 
0030 using namespace KWin;
0031 
0032 // Faux-client API for tests
0033 
0034 Q_DECLARE_OPAQUE_POINTER(::zwlr_data_control_offer_v1 *)
0035 Q_DECLARE_METATYPE(::zwlr_data_control_offer_v1 *)
0036 
0037 class DataControlDeviceManager : public QObject, public QtWayland::zwlr_data_control_manager_v1
0038 {
0039     Q_OBJECT
0040 };
0041 
0042 class DataControlOffer : public QObject, public QtWayland::zwlr_data_control_offer_v1
0043 {
0044     Q_OBJECT
0045 public:
0046     ~DataControlOffer()
0047     {
0048         destroy();
0049     }
0050     QStringList receivedOffers()
0051     {
0052         return m_receivedOffers;
0053     }
0054 
0055 protected:
0056     virtual void zwlr_data_control_offer_v1_offer(const QString &mime_type) override
0057     {
0058         m_receivedOffers << mime_type;
0059     }
0060 
0061 private:
0062     QStringList m_receivedOffers;
0063 };
0064 
0065 class DataControlDevice : public QObject, public QtWayland::zwlr_data_control_device_v1
0066 {
0067     Q_OBJECT
0068 public:
0069     ~DataControlDevice()
0070     {
0071         destroy();
0072     }
0073 Q_SIGNALS:
0074     void dataControlOffer(DataControlOffer *offer); // our event receives a new ID, so we make a new object
0075     void selection(struct ::zwlr_data_control_offer_v1 *id);
0076     void primary_selection(struct ::zwlr_data_control_offer_v1 *id);
0077 
0078 protected:
0079     void zwlr_data_control_device_v1_data_offer(struct ::zwlr_data_control_offer_v1 *id) override
0080     {
0081         auto offer = new DataControlOffer;
0082         offer->init(id);
0083         Q_EMIT dataControlOffer(offer);
0084     }
0085 
0086     void zwlr_data_control_device_v1_selection(struct ::zwlr_data_control_offer_v1 *id) override
0087     {
0088         Q_EMIT selection(id);
0089     }
0090 
0091     void zwlr_data_control_device_v1_primary_selection(struct ::zwlr_data_control_offer_v1 *id) override
0092     {
0093         Q_EMIT primary_selection(id);
0094     }
0095 };
0096 
0097 class DataControlSource : public QObject, public QtWayland::zwlr_data_control_source_v1
0098 {
0099     Q_OBJECT
0100 public:
0101     ~DataControlSource()
0102     {
0103         destroy();
0104     }
0105 
0106 public:
0107 };
0108 
0109 class TestDataSource : public AbstractDataSource
0110 {
0111     Q_OBJECT
0112 public:
0113     TestDataSource()
0114         : AbstractDataSource(nullptr)
0115     {
0116     }
0117     ~TestDataSource()
0118     {
0119         Q_EMIT aboutToBeDestroyed();
0120     }
0121     void requestData(const QString &mimeType, qint32 fd) override
0122     {
0123     };
0124     void cancel() override{};
0125     QStringList mimeTypes() const override
0126     {
0127         return {"text/test1", "text/test2"};
0128     }
0129 };
0130 
0131 // The test itself
0132 
0133 class DataControlInterfaceTest : public QObject
0134 {
0135     Q_OBJECT
0136 
0137 private Q_SLOTS:
0138     void init();
0139     void cleanup();
0140     void testCopyToControl();
0141     void testCopyToControlPrimarySelection();
0142     void testCopyFromControl();
0143     void testCopyFromControlPrimarySelection();
0144     void testKlipperCase();
0145 
0146 private:
0147     KWayland::Client::ConnectionThread *m_connection;
0148     KWayland::Client::EventQueue *m_queue;
0149     KWayland::Client::Compositor *m_clientCompositor;
0150     KWayland::Client::Seat *m_clientSeat = nullptr;
0151 
0152     QThread *m_thread;
0153     KWin::Display *m_display;
0154     SeatInterface *m_seat;
0155     CompositorInterface *m_serverCompositor;
0156 
0157     DataControlDeviceManagerV1Interface *m_dataControlDeviceManagerInterface;
0158 
0159     DataControlDeviceManager *m_dataControlDeviceManager;
0160 
0161     QList<SurfaceInterface *> m_surfaces;
0162 };
0163 
0164 static const QString s_socketName = QStringLiteral("kwin-wayland-datacontrol-test-0");
0165 
0166 void DataControlInterfaceTest::init()
0167 {
0168     m_display = new KWin::Display();
0169     m_display->addSocketName(s_socketName);
0170     m_display->start();
0171     QVERIFY(m_display->isRunning());
0172 
0173     m_seat = new SeatInterface(m_display, this);
0174     m_serverCompositor = new CompositorInterface(m_display, this);
0175     m_dataControlDeviceManagerInterface = new DataControlDeviceManagerV1Interface(m_display, this);
0176 
0177     // setup connection
0178     m_connection = new KWayland::Client::ConnectionThread;
0179     QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
0180     m_connection->setSocketName(s_socketName);
0181 
0182     m_thread = new QThread(this);
0183     m_connection->moveToThread(m_thread);
0184     m_thread->start();
0185 
0186     m_connection->initConnection();
0187     QVERIFY(connectedSpy.wait());
0188     QVERIFY(!m_connection->connections().isEmpty());
0189 
0190     m_queue = new KWayland::Client::EventQueue(this);
0191     QVERIFY(!m_queue->isValid());
0192     m_queue->setup(m_connection);
0193     QVERIFY(m_queue->isValid());
0194 
0195     KWayland::Client::Registry registry;
0196     connect(&registry, &KWayland::Client::Registry::interfaceAnnounced, this, [this, &registry](const QByteArray &interface, quint32 name, quint32 version) {
0197         if (interface == "zwlr_data_control_manager_v1") {
0198             m_dataControlDeviceManager = new DataControlDeviceManager;
0199             m_dataControlDeviceManager->init(registry.registry(), name, version);
0200         }
0201     });
0202     connect(&registry, &KWayland::Client::Registry::seatAnnounced, this, [this, &registry](quint32 name, quint32 version) {
0203         m_clientSeat = registry.createSeat(name, version);
0204     });
0205     registry.setEventQueue(m_queue);
0206     QSignalSpy compositorSpy(&registry, &KWayland::Client::Registry::compositorAnnounced);
0207     registry.create(m_connection->display());
0208     QVERIFY(registry.isValid());
0209     registry.setup();
0210     wl_display_flush(m_connection->display());
0211 
0212     QVERIFY(compositorSpy.wait());
0213     m_clientCompositor = registry.createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
0214     QVERIFY(m_clientCompositor->isValid());
0215 
0216     QVERIFY(m_dataControlDeviceManager);
0217 }
0218 
0219 void DataControlInterfaceTest::cleanup()
0220 {
0221 #define CLEANUP(variable)   \
0222     if (variable) {         \
0223         delete variable;    \
0224         variable = nullptr; \
0225     }
0226     CLEANUP(m_dataControlDeviceManager)
0227     CLEANUP(m_clientSeat)
0228     CLEANUP(m_clientCompositor)
0229     CLEANUP(m_queue)
0230     if (m_connection) {
0231         m_connection->deleteLater();
0232         m_connection = nullptr;
0233     }
0234     if (m_thread) {
0235         m_thread->quit();
0236         m_thread->wait();
0237         delete m_thread;
0238         m_thread = nullptr;
0239     }
0240     CLEANUP(m_display)
0241 #undef CLEANUP
0242 
0243     // these are the children of the display
0244     m_seat = nullptr;
0245     m_serverCompositor = nullptr;
0246 }
0247 
0248 void DataControlInterfaceTest::testCopyToControl()
0249 {
0250     // we set a dummy data source on the seat using abstract client directly
0251     // then confirm we receive the offer despite not having a surface
0252 
0253     std::unique_ptr<DataControlDevice> dataControlDevice(new DataControlDevice);
0254     dataControlDevice->init(m_dataControlDeviceManager->get_data_device(*m_clientSeat));
0255 
0256     QSignalSpy newOfferSpy(dataControlDevice.get(), &DataControlDevice::dataControlOffer);
0257     QSignalSpy selectionSpy(dataControlDevice.get(), &DataControlDevice::selection);
0258 
0259     std::unique_ptr<TestDataSource> testSelection(new TestDataSource);
0260     m_seat->setSelection(testSelection.get());
0261 
0262     // selection will be sent after we've been sent a new offer object and the mimes have been sent to that object
0263     selectionSpy.wait();
0264 
0265     QCOMPARE(newOfferSpy.count(), 1);
0266     std::unique_ptr<DataControlOffer> offer(newOfferSpy.first().first().value<DataControlOffer *>());
0267     QCOMPARE(selectionSpy.first().first().value<struct ::zwlr_data_control_offer_v1 *>(), offer->object());
0268 
0269     QCOMPARE(offer->receivedOffers().count(), 2);
0270     QCOMPARE(offer->receivedOffers()[0], "text/test1");
0271     QCOMPARE(offer->receivedOffers()[1], "text/test2");
0272 }
0273 
0274 void DataControlInterfaceTest::testCopyToControlPrimarySelection()
0275 {
0276     // we set a dummy data source on the seat using abstract client directly
0277     // then confirm we receive the offer despite not having a surface
0278 
0279     std::unique_ptr<DataControlDevice> dataControlDevice(new DataControlDevice);
0280     dataControlDevice->init(m_dataControlDeviceManager->get_data_device(*m_clientSeat));
0281 
0282     QSignalSpy newOfferSpy(dataControlDevice.get(), &DataControlDevice::dataControlOffer);
0283     QSignalSpy selectionSpy(dataControlDevice.get(), &DataControlDevice::primary_selection);
0284 
0285     std::unique_ptr<TestDataSource> testSelection(new TestDataSource);
0286     m_seat->setPrimarySelection(testSelection.get());
0287 
0288     // selection will be sent after we've been sent a new offer object and the mimes have been sent to that object
0289     selectionSpy.wait();
0290 
0291     QCOMPARE(newOfferSpy.count(), 1);
0292     std::unique_ptr<DataControlOffer> offer(newOfferSpy.first().first().value<DataControlOffer *>());
0293     QCOMPARE(selectionSpy.first().first().value<struct ::zwlr_data_control_offer_v1 *>(), offer->object());
0294 
0295     QCOMPARE(offer->receivedOffers().count(), 2);
0296     QCOMPARE(offer->receivedOffers()[0], "text/test1");
0297     QCOMPARE(offer->receivedOffers()[1], "text/test2");
0298 }
0299 
0300 void DataControlInterfaceTest::testCopyFromControl()
0301 {
0302     // we create a data device and set a selection
0303     // then confirm the server sees the new selection
0304     QSignalSpy serverSelectionChangedSpy(m_seat, &SeatInterface::selectionChanged);
0305 
0306     std::unique_ptr<DataControlDevice> dataControlDevice(new DataControlDevice);
0307     dataControlDevice->init(m_dataControlDeviceManager->get_data_device(*m_clientSeat));
0308 
0309     std::unique_ptr<DataControlSource> source(new DataControlSource);
0310     source->init(m_dataControlDeviceManager->create_data_source());
0311     source->offer("cheese/test1");
0312     source->offer("cheese/test2");
0313 
0314     dataControlDevice->set_selection(source->object());
0315 
0316     serverSelectionChangedSpy.wait();
0317     QVERIFY(m_seat->selection());
0318     QCOMPARE(m_seat->selection()->mimeTypes(), QStringList({"cheese/test1", "cheese/test2"}));
0319 }
0320 
0321 void DataControlInterfaceTest::testCopyFromControlPrimarySelection()
0322 {
0323     // we create a data device and set a selection
0324     // then confirm the server sees the new selection
0325     QSignalSpy serverSelectionChangedSpy(m_seat, &SeatInterface::primarySelectionChanged);
0326 
0327     std::unique_ptr<DataControlDevice> dataControlDevice(new DataControlDevice);
0328     dataControlDevice->init(m_dataControlDeviceManager->get_data_device(*m_clientSeat));
0329 
0330     std::unique_ptr<DataControlSource> source(new DataControlSource);
0331     source->init(m_dataControlDeviceManager->create_data_source());
0332     source->offer("cheese/test1");
0333     source->offer("cheese/test2");
0334 
0335     dataControlDevice->set_primary_selection(source->object());
0336 
0337     serverSelectionChangedSpy.wait();
0338     QVERIFY(m_seat->primarySelection());
0339     QCOMPARE(m_seat->primarySelection()->mimeTypes(), QStringList({"cheese/test1", "cheese/test2"}));
0340 }
0341 
0342 void DataControlInterfaceTest::testKlipperCase()
0343 {
0344     // This tests the setup of klipper's real world operation and a race with a common pattern seen between clients and klipper
0345     // The client's behaviour is faked with direct access to the seat
0346 
0347     std::unique_ptr<DataControlDevice> dataControlDevice(new DataControlDevice);
0348     dataControlDevice->init(m_dataControlDeviceManager->get_data_device(*m_clientSeat));
0349 
0350     QSignalSpy newOfferSpy(dataControlDevice.get(), &DataControlDevice::dataControlOffer);
0351     QSignalSpy selectionSpy(dataControlDevice.get(), &DataControlDevice::selection);
0352     QSignalSpy serverSelectionChangedSpy(m_seat, &SeatInterface::selectionChanged);
0353 
0354     // Client A has a data source
0355     std::unique_ptr<TestDataSource> testSelection(new TestDataSource);
0356     m_seat->setSelection(testSelection.get());
0357 
0358     // klipper gets it
0359     selectionSpy.wait();
0360 
0361     // Client A deletes it
0362     testSelection.reset();
0363 
0364     // klipper gets told
0365     selectionSpy.wait();
0366 
0367     // Client A sets something else
0368     std::unique_ptr<TestDataSource> testSelection2(new TestDataSource);
0369     m_seat->setSelection(testSelection2.get());
0370 
0371     // Meanwhile klipper updates with the old content
0372     std::unique_ptr<DataControlSource> source(new DataControlSource);
0373     source->init(m_dataControlDeviceManager->create_data_source());
0374     source->offer("fromKlipper/test1");
0375     source->offer("application/x-kde-onlyReplaceEmpty");
0376 
0377     dataControlDevice->set_selection(source->object());
0378 
0379     QVERIFY(!serverSelectionChangedSpy.wait(10));
0380     QCOMPARE(m_seat->selection(), testSelection2.get());
0381 }
0382 
0383 QTEST_GUILESS_MAIN(DataControlInterfaceTest)
0384 
0385 #include "test_datacontrol_interface.moc"