/* SPDX-FileCopyrightText: 2014 Martin Gräßlin SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "datadevice.h" #include "datasource.h" #include "surface.h" #include "wayland_pointer_p.h" // Qt #include // Wayland #include namespace KWayland { namespace Client { class Q_DECL_HIDDEN DataDevice::Private { public: explicit Private(DataDevice *q); void setup(wl_data_device *d); WaylandPointer device; QScopedPointer selectionOffer; struct Drag { QPointer offer; QPointer surface; }; Drag drag; private: void dataOffer(wl_data_offer *id); void selection(wl_data_offer *id); void dragEnter(quint32 serial, const QPointer &surface, const QPointF &relativeToSurface, wl_data_offer *dataOffer); void dragLeft(); static void dataOfferCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id); static void enterCallback(void *data, wl_data_device *dataDevice, uint32_t serial, wl_surface *surface, wl_fixed_t x, wl_fixed_t y, wl_data_offer *id); static void leaveCallback(void *data, wl_data_device *dataDevice); static void motionCallback(void *data, wl_data_device *dataDevice, uint32_t time, wl_fixed_t x, wl_fixed_t y); static void dropCallback(void *data, wl_data_device *dataDevice); static void selectionCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id); static const struct wl_data_device_listener s_listener; DataDevice *q; DataOffer *lastOffer = nullptr; }; const wl_data_device_listener DataDevice::Private::s_listener = {dataOfferCallback, enterCallback, leaveCallback, motionCallback, dropCallback, selectionCallback}; void DataDevice::Private::dataOfferCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id) { auto d = reinterpret_cast(data); Q_ASSERT(d->device == dataDevice); d->dataOffer(id); } void DataDevice::Private::dataOffer(wl_data_offer *id) { Q_ASSERT(!lastOffer); lastOffer = new DataOffer(q, id); Q_ASSERT(lastOffer->isValid()); } void DataDevice::Private::enterCallback(void *data, wl_data_device *dataDevice, uint32_t serial, wl_surface *surface, wl_fixed_t x, wl_fixed_t y, wl_data_offer *id) { auto d = reinterpret_cast(data); Q_ASSERT(d->device == dataDevice); d->dragEnter(serial, QPointer(Surface::get(surface)), QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), id); } void DataDevice::Private::dragEnter(quint32 serial, const QPointer &surface, const QPointF &relativeToSurface, wl_data_offer *dataOffer) { drag.surface = surface; Q_ASSERT(*lastOffer == dataOffer); drag.offer = lastOffer; lastOffer = nullptr; Q_EMIT q->dragEntered(serial, relativeToSurface); } void DataDevice::Private::leaveCallback(void *data, wl_data_device *dataDevice) { auto d = reinterpret_cast(data); Q_ASSERT(d->device == dataDevice); d->dragLeft(); } void DataDevice::Private::dragLeft() { if (drag.offer) { delete drag.offer; } drag = Drag(); Q_EMIT q->dragLeft(); } void DataDevice::Private::motionCallback(void *data, wl_data_device *dataDevice, uint32_t time, wl_fixed_t x, wl_fixed_t y) { auto d = reinterpret_cast(data); Q_ASSERT(d->device == dataDevice); Q_EMIT d->q->dragMotion(QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), time); } void DataDevice::Private::dropCallback(void *data, wl_data_device *dataDevice) { auto d = reinterpret_cast(data); Q_ASSERT(d->device == dataDevice); Q_EMIT d->q->dropped(); } void DataDevice::Private::selectionCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id) { auto d = reinterpret_cast(data); Q_ASSERT(d->device == dataDevice); d->selection(id); } void DataDevice::Private::selection(wl_data_offer *id) { if (!id) { selectionOffer.reset(); Q_EMIT q->selectionCleared(); return; } Q_ASSERT(*lastOffer == id); selectionOffer.reset(lastOffer); lastOffer = nullptr; Q_EMIT q->selectionOffered(selectionOffer.data()); } DataDevice::Private::Private(DataDevice *q) : q(q) { } void DataDevice::Private::setup(wl_data_device *d) { Q_ASSERT(d); Q_ASSERT(!device.isValid()); device.setup(d); wl_data_device_add_listener(device, &s_listener, this); } DataDevice::DataDevice(QObject *parent) : QObject(parent) , d(new Private(this)) { } DataDevice::~DataDevice() { if (d->drag.offer) { delete d->drag.offer; } release(); } void DataDevice::destroy() { d->device.destroy(); } void DataDevice::release() { d->device.release(); } bool DataDevice::isValid() const { return d->device.isValid(); } void DataDevice::setup(wl_data_device *dataDevice) { d->setup(dataDevice); } void DataDevice::startDragInternally(quint32 serial, Surface *origin, Surface *icon) { startDrag(serial, nullptr, origin, icon); } namespace { static wl_data_source *dataSource(const DataSource *source) { if (!source) { return nullptr; } return *source; } } void DataDevice::startDrag(quint32 serial, DataSource *source, Surface *origin, Surface *icon) { wl_data_device_start_drag(d->device, dataSource(source), *origin, icon ? (wl_surface *)*icon : nullptr, serial); } void DataDevice::setSelection(quint32 serial, DataSource *source) { wl_data_device_set_selection(d->device, dataSource(source), serial); } void DataDevice::clearSelection(quint32 serial) { setSelection(serial); } DataOffer *DataDevice::offeredSelection() const { return d->selectionOffer.data(); } QPointer DataDevice::dragSurface() const { return d->drag.surface; } DataOffer *DataDevice::dragOffer() const { return d->drag.offer; } DataDevice::operator wl_data_device *() { return d->device; } DataDevice::operator wl_data_device *() const { return d->device; } } } #include "moc_datadevice.cpp"