1/*
2 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6#include "datadevice.h"
7#include "datasource.h"
8#include "surface.h"
9#include "wayland_pointer_p.h"
10// Qt
11#include <QPointer>
12// Wayland
13#include <wayland-client-protocol.h>
14
15namespace KWayland
16{
17namespace Client
18{
19class Q_DECL_HIDDEN DataDevice::Private
20{
21public:
22 explicit Private(DataDevice *q);
23 void setup(wl_data_device *d);
24
25 WaylandPointer<wl_data_device, wl_data_device_release> device;
26 QScopedPointer<DataOffer> selectionOffer;
27 struct Drag {
28 QPointer<DataOffer> offer;
29 QPointer<Surface> surface;
30 };
31 Drag drag;
32
33private:
34 void dataOffer(wl_data_offer *id);
35 void selection(wl_data_offer *id);
36 void dragEnter(quint32 serial, const QPointer<Surface> &surface, const QPointF &relativeToSurface, wl_data_offer *dataOffer);
37 void dragLeft();
38 static void dataOfferCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id);
39 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);
40 static void leaveCallback(void *data, wl_data_device *dataDevice);
41 static void motionCallback(void *data, wl_data_device *dataDevice, uint32_t time, wl_fixed_t x, wl_fixed_t y);
42 static void dropCallback(void *data, wl_data_device *dataDevice);
43 static void selectionCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id);
44
45 static const struct wl_data_device_listener s_listener;
46
47 DataDevice *q;
48 DataOffer *lastOffer = nullptr;
49};
50
51const wl_data_device_listener DataDevice::Private::s_listener =
52 {.data_offer: dataOfferCallback, .enter: enterCallback, .leave: leaveCallback, .motion: motionCallback, .drop: dropCallback, .selection: selectionCallback};
53
54void DataDevice::Private::dataOfferCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id)
55{
56 auto d = reinterpret_cast<Private *>(data);
57 Q_ASSERT(d->device == dataDevice);
58 d->dataOffer(id);
59}
60
61void DataDevice::Private::dataOffer(wl_data_offer *id)
62{
63 Q_ASSERT(!lastOffer);
64 lastOffer = new DataOffer(q, id);
65 Q_ASSERT(lastOffer->isValid());
66}
67
68void DataDevice::Private::enterCallback(void *data,
69 wl_data_device *dataDevice,
70 uint32_t serial,
71 wl_surface *surface,
72 wl_fixed_t x,
73 wl_fixed_t y,
74 wl_data_offer *id)
75{
76 auto d = reinterpret_cast<Private *>(data);
77 Q_ASSERT(d->device == dataDevice);
78 d->dragEnter(serial, surface: QPointer<Surface>(Surface::get(native: surface)), relativeToSurface: QPointF(wl_fixed_to_double(f: x), wl_fixed_to_double(f: y)), dataOffer: id);
79}
80
81void DataDevice::Private::dragEnter(quint32 serial, const QPointer<Surface> &surface, const QPointF &relativeToSurface, wl_data_offer *dataOffer)
82{
83 drag.surface = surface;
84 Q_ASSERT(*lastOffer == dataOffer);
85 drag.offer = lastOffer;
86 lastOffer = nullptr;
87 Q_EMIT q->dragEntered(serial, relativeToSurface);
88}
89
90void DataDevice::Private::leaveCallback(void *data, wl_data_device *dataDevice)
91{
92 auto d = reinterpret_cast<Private *>(data);
93 Q_ASSERT(d->device == dataDevice);
94 d->dragLeft();
95}
96
97void DataDevice::Private::dragLeft()
98{
99 if (drag.offer) {
100 delete drag.offer;
101 }
102 drag = Drag();
103 Q_EMIT q->dragLeft();
104}
105
106void DataDevice::Private::motionCallback(void *data, wl_data_device *dataDevice, uint32_t time, wl_fixed_t x, wl_fixed_t y)
107{
108 auto d = reinterpret_cast<Private *>(data);
109 Q_ASSERT(d->device == dataDevice);
110 Q_EMIT d->q->dragMotion(relativeToSurface: QPointF(wl_fixed_to_double(f: x), wl_fixed_to_double(f: y)), time);
111}
112
113void DataDevice::Private::dropCallback(void *data, wl_data_device *dataDevice)
114{
115 auto d = reinterpret_cast<Private *>(data);
116 Q_ASSERT(d->device == dataDevice);
117 Q_EMIT d->q->dropped();
118}
119
120void DataDevice::Private::selectionCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id)
121{
122 auto d = reinterpret_cast<Private *>(data);
123 Q_ASSERT(d->device == dataDevice);
124 d->selection(id);
125}
126
127void DataDevice::Private::selection(wl_data_offer *id)
128{
129 if (!id) {
130 selectionOffer.reset();
131 Q_EMIT q->selectionCleared();
132 return;
133 }
134 Q_ASSERT(*lastOffer == id);
135 selectionOffer.reset(other: lastOffer);
136 lastOffer = nullptr;
137 Q_EMIT q->selectionOffered(selectionOffer.data());
138}
139
140DataDevice::Private::Private(DataDevice *q)
141 : q(q)
142{
143}
144
145void DataDevice::Private::setup(wl_data_device *d)
146{
147 Q_ASSERT(d);
148 Q_ASSERT(!device.isValid());
149 device.setup(pointer: d);
150 wl_data_device_add_listener(wl_data_device: device, listener: &s_listener, data: this);
151}
152
153DataDevice::DataDevice(QObject *parent)
154 : QObject(parent)
155 , d(new Private(this))
156{
157}
158
159DataDevice::~DataDevice()
160{
161 if (d->drag.offer) {
162 delete d->drag.offer;
163 }
164 release();
165}
166
167void DataDevice::destroy()
168{
169 d->device.destroy();
170}
171
172void DataDevice::release()
173{
174 d->device.release();
175}
176
177bool DataDevice::isValid() const
178{
179 return d->device.isValid();
180}
181
182void DataDevice::setup(wl_data_device *dataDevice)
183{
184 d->setup(dataDevice);
185}
186
187void DataDevice::startDragInternally(quint32 serial, Surface *origin, Surface *icon)
188{
189 startDrag(serial, source: nullptr, origin, icon);
190}
191
192namespace
193{
194static wl_data_source *dataSource(const DataSource *source)
195{
196 if (!source) {
197 return nullptr;
198 }
199 return *source;
200}
201}
202
203void DataDevice::startDrag(quint32 serial, DataSource *source, Surface *origin, Surface *icon)
204{
205 wl_data_device_start_drag(wl_data_device: d->device, source: dataSource(source), origin: *origin, icon: icon ? (wl_surface *)*icon : nullptr, serial);
206}
207
208void DataDevice::setSelection(quint32 serial, DataSource *source)
209{
210 wl_data_device_set_selection(wl_data_device: d->device, source: dataSource(source), serial);
211}
212
213void DataDevice::clearSelection(quint32 serial)
214{
215 setSelection(serial);
216}
217
218DataOffer *DataDevice::offeredSelection() const
219{
220 return d->selectionOffer.data();
221}
222
223QPointer<Surface> DataDevice::dragSurface() const
224{
225 return d->drag.surface;
226}
227
228DataOffer *DataDevice::dragOffer() const
229{
230 return d->drag.offer;
231}
232
233DataDevice::operator wl_data_device *()
234{
235 return d->device;
236}
237
238DataDevice::operator wl_data_device *() const
239{
240 return d->device;
241}
242
243}
244}
245
246#include "moc_datadevice.cpp"
247

source code of kwayland/src/client/datadevice.cpp