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