From 7763cd94a718e7e979d4ee19e12eeddea7d7f444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Thu, 6 Nov 2014 16:56:50 +0100 Subject: [PATCH] Add wl_data_offer on Client and Server side Only selection part is implemented, drag'n'drop still needs to be implemented. Unit test is not properly testing whether the data can be transferred. This needs some better architecture to have multiple processes which perform the source and target part. --- src/wayland/CMakeLists.txt | 2 + .../autotests/client/test_datadevice.cpp | 23 +++ src/wayland/datadevice_interface.cpp | 25 +++ src/wayland/datadevice_interface.h | 2 + src/wayland/dataoffer_interface.cpp | 155 ++++++++++++++++++ src/wayland/dataoffer_interface.h | 63 +++++++ 6 files changed, 270 insertions(+) create mode 100644 src/wayland/dataoffer_interface.cpp create mode 100644 src/wayland/dataoffer_interface.h diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index 3cd37cfdae..0da74dd772 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -3,6 +3,7 @@ set(SERVER_LIB_SRCS compositor_interface.cpp datadevice_interface.cpp datadevicemanager_interface.cpp + dataoffer_interface.cpp datasource_interface.cpp display.cpp output_interface.cpp @@ -50,6 +51,7 @@ set_target_properties(KF5WaylandServer PROPERTIES VERSION ${KWAYLAND_VERSION_S # compositor_interface.h # datadevice_interface.h # datadevicemanager_interface.h +# dataoffer_interface.h # datasource_interface.h # display.h # output_interface.h diff --git a/src/wayland/autotests/client/test_datadevice.cpp b/src/wayland/autotests/client/test_datadevice.cpp index 5f664a2841..a5bff84581 100644 --- a/src/wayland/autotests/client/test_datadevice.cpp +++ b/src/wayland/autotests/client/test_datadevice.cpp @@ -321,6 +321,7 @@ void TestDataDevice::testSetSelection() QScopedPointer dataSource(m_dataDeviceManager->createDataSource()); QVERIFY(dataSource->isValid()); + dataSource->offer(QStringLiteral("text/plain")); QVERIFY(dataSourceCreatedSpy.wait()); QCOMPARE(dataSourceCreatedSpy.count(), 1); @@ -341,6 +342,28 @@ void TestDataDevice::testSetSelection() QCOMPARE(selectionChangedSpy.first().first().value(), sourceInterface); QCOMPARE(deviceInterface->selection(), sourceInterface); + // send selection to datadevice + QSignalSpy selectionOfferedSpy(dataDevice.data(), SIGNAL(selectionOffered(KWayland::Client::DataOffer*))); + QVERIFY(selectionOfferedSpy.isValid()); + deviceInterface->sendSelection(deviceInterface); + QVERIFY(selectionOfferedSpy.wait()); + QCOMPARE(selectionOfferedSpy.count(), 1); + auto dataOffer = selectionOfferedSpy.first().first().value(); + QVERIFY(dataOffer); + QCOMPARE(dataOffer->offeredMimeTypes().count(), 1); + QCOMPARE(dataOffer->offeredMimeTypes().first().name(), QStringLiteral("text/plain")); + + // sending a new mimetype to the selection, should be announced in the offer + QSignalSpy mimeTypeAddedSpy(dataOffer, SIGNAL(mimeTypeOffered(QString))); + QVERIFY(mimeTypeAddedSpy.isValid()); + dataSource->offer(QStringLiteral("text/html")); + QVERIFY(mimeTypeAddedSpy.wait()); + QCOMPARE(mimeTypeAddedSpy.count(), 1); + QCOMPARE(mimeTypeAddedSpy.first().first().toString(), QStringLiteral("text/html")); + QCOMPARE(dataOffer->offeredMimeTypes().count(), 2); + QCOMPARE(dataOffer->offeredMimeTypes().first().name(), QStringLiteral("text/plain")); + QCOMPARE(dataOffer->offeredMimeTypes().last().name(), QStringLiteral("text/html")); + // now clear the selection dataDevice->clearSelection(1); QVERIFY(selectionClearedSpy.wait()); diff --git a/src/wayland/datadevice_interface.cpp b/src/wayland/datadevice_interface.cpp index f5159a9f6c..3992eafc43 100644 --- a/src/wayland/datadevice_interface.cpp +++ b/src/wayland/datadevice_interface.cpp @@ -18,6 +18,7 @@ You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "datadevice_interface.h" +#include "dataoffer_interface.h" #include "datasource_interface.h" #include "seat_interface.h" #include "surface_interface.h" @@ -37,6 +38,8 @@ public: void create(wl_client *client, quint32 version, quint32 id); + DataOfferInterface *createDataOffer(DataSourceInterface *source); + SeatInterface *seat; wl_resource *device = nullptr; DataSourceInterface *source = nullptr; @@ -133,6 +136,19 @@ void DataDeviceInterface::Private::create(wl_client *client, quint32 version, qu wl_resource_set_implementation(device, &s_interface, this, unbind); } +DataOfferInterface *DataDeviceInterface::Private::createDataOffer(DataSourceInterface *source) +{ + DataOfferInterface *offer = new DataOfferInterface(source, q); + offer->create(wl_resource_get_client(device), wl_resource_get_version(device), 0); + if (!offer->resource()) { + // TODO: send error? + delete offer; + return nullptr; + } + wl_data_device_send_data_offer(device, offer->resource()); + offer->sendAllOffers(); + return offer; +} DataDeviceInterface::DataDeviceInterface(SeatInterface *seat, DataDeviceManagerInterface *parent) : QObject(/*parent*/) @@ -177,5 +193,14 @@ DataSourceInterface *DataDeviceInterface::selection() const return d->selection; } +void DataDeviceInterface::sendSelection(DataDeviceInterface *other) +{ + auto r = d->createDataOffer(other->selection()); + if (!r) { + return; + } + wl_data_device_send_selection(d->device, r->resource()); +} + } } diff --git a/src/wayland/datadevice_interface.h b/src/wayland/datadevice_interface.h index a89bdcbaf7..3e49f6ec3b 100644 --- a/src/wayland/datadevice_interface.h +++ b/src/wayland/datadevice_interface.h @@ -52,6 +52,8 @@ public: DataSourceInterface *selection() const; + void sendSelection(DataDeviceInterface *other); + wl_resource *resource() const; Q_SIGNALS: diff --git a/src/wayland/dataoffer_interface.cpp b/src/wayland/dataoffer_interface.cpp new file mode 100644 index 0000000000..848f3e9417 --- /dev/null +++ b/src/wayland/dataoffer_interface.cpp @@ -0,0 +1,155 @@ +/******************************************************************** +Copyright 2014 Martin Gräßlin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +#include "dataoffer_interface.h" +#include "datadevice_interface.h" +#include "datasource_interface.h" +// Qt +#include +// Wayland +#include + +namespace KWayland +{ +namespace Server +{ + +class DataOfferInterface::Private +{ +public: + Private(DataSourceInterface *source, DataDeviceInterface *parentInterface, DataOfferInterface *q); + ~Private(); + void create(wl_client *client, quint32 version, quint32 id); + wl_resource *offer = nullptr; + DataSourceInterface *source; + DataDeviceInterface *dataDevice; + +private: + void receive(const QString &mimeType, qint32 fd); + static void acceptCallback(wl_client *client, wl_resource *resource, uint32_t serial, const char *mimeType); + static void receiveCallback(wl_client *client, wl_resource *resource, const char *mimeType, int32_t fd); + static void destroyCallback(wl_client *client, wl_resource *resource); + static void unbind(wl_resource *resource); + static Private *cast(wl_resource *r) { + return reinterpret_cast(wl_resource_get_user_data(r)); + } + + DataOfferInterface *q; + + static const struct wl_data_offer_interface s_interface; +}; + +const struct wl_data_offer_interface DataOfferInterface::Private::s_interface = { + acceptCallback, + receiveCallback, + destroyCallback +}; + +DataOfferInterface::Private::Private(DataSourceInterface *source, DataDeviceInterface *parentInterface, DataOfferInterface *q) + : source(source) + , dataDevice(parentInterface) + , q(q) +{ + // TODO: connect to new selections +} + +DataOfferInterface::Private::~Private() +{ + if (offer) { + wl_resource_destroy(offer); + } +} + +void DataOfferInterface::Private::create(wl_client *client, quint32 version, quint32 id) +{ + Q_ASSERT(!offer); + offer = wl_resource_create(client, &wl_data_offer_interface, version, id); + if (!offer) { + return; + } + wl_resource_set_implementation(offer, &s_interface, this, unbind); +} + +void DataOfferInterface::Private::acceptCallback(wl_client *client, wl_resource *resource, uint32_t serial, const char *mimeType) +{ + Q_UNUSED(client) + Q_UNUSED(resource) + Q_UNUSED(serial) + Q_UNUSED(mimeType) +} + +void DataOfferInterface::Private::destroyCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + cast(resource)->q->deleteLater(); +} + +void DataOfferInterface::Private::receiveCallback(wl_client *client, wl_resource *resource, const char *mimeType, int32_t fd) +{ + Q_UNUSED(client) + cast(resource)->receive(QString::fromUtf8(mimeType), fd); +} + +void DataOfferInterface::Private::receive(const QString &mimeType, qint32 fd) +{ + source->requestData(mimeType, fd); +} + +void DataOfferInterface::Private::unbind(wl_resource *resource) +{ + auto o = cast(resource); + o->offer = nullptr; + o->q->deleteLater(); +} + +DataOfferInterface::DataOfferInterface(DataSourceInterface *source, DataDeviceInterface *parentInterface) + : QObject(parentInterface) + , d(new Private(source, parentInterface, this)) +{ + connect(source, &DataSourceInterface::mimeTypeOffered, this, + [this](const QString &mimeType) { + if (!d->offer) { + return; + } + wl_data_offer_send_offer(d->offer, mimeType.toUtf8().constData()); + } + ); +} + +DataOfferInterface::~DataOfferInterface() = default; + +void DataOfferInterface::create(wl_client *client, quint32 version, quint32 id) +{ + d->create(client, version, id); +} + +void DataOfferInterface::sendAllOffers() +{ + for (const QString &mimeType : d->source->mimeTypes()) { + wl_data_offer_send_offer(d->offer, mimeType.toUtf8().constData()); + } +} + +wl_resource *DataOfferInterface::resource() const +{ + return d->offer; +} + +} +} diff --git a/src/wayland/dataoffer_interface.h b/src/wayland/dataoffer_interface.h new file mode 100644 index 0000000000..c9402796f9 --- /dev/null +++ b/src/wayland/dataoffer_interface.h @@ -0,0 +1,63 @@ +/******************************************************************** +Copyright 2014 Martin Gräßlin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +#ifndef WAYLAND_SERVER_DATA_OFFER_INTERFACE_H +#define WAYLAND_SERVER_DATA_OFFER_INTERFACE_H + +#include + +#include + +struct wl_client; +struct wl_resource; + +namespace KWayland +{ +namespace Server +{ + +class DataDeviceInterface; +class DataSourceInterface; + +class KWAYLANDSERVER_EXPORT DataOfferInterface : public QObject +{ + Q_OBJECT +public: + virtual ~DataOfferInterface(); + + void create(wl_client *client, quint32 version, quint32 id); + + void sendAllOffers(); + + wl_resource *resource() const; + +private: + friend class DataDeviceInterface; + explicit DataOfferInterface(DataSourceInterface *source, DataDeviceInterface *parentInterface); + + class Private; + QScopedPointer d; +}; + +} +} + +Q_DECLARE_METATYPE(KWayland::Server::DataOfferInterface*) + +#endif