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 | |
15 | namespace KWayland |
16 | { |
17 | namespace Client |
18 | { |
19 | class Q_DECL_HIDDEN DataDevice::Private |
20 | { |
21 | public: |
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 | |
33 | private: |
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 | |
51 | const wl_data_device_listener DataDevice::Private::s_listener = |
52 | {.data_offer: dataOfferCallback, .enter: enterCallback, .leave: leaveCallback, .motion: motionCallback, .drop: dropCallback, .selection: selectionCallback}; |
53 | |
54 | void 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 | |
61 | void 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 | |
68 | void 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 | |
81 | void 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 | |
90 | void 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 | |
97 | void DataDevice::Private::dragLeft() |
98 | { |
99 | if (drag.offer) { |
100 | delete drag.offer; |
101 | } |
102 | drag = Drag(); |
103 | Q_EMIT q->dragLeft(); |
104 | } |
105 | |
106 | void 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 | |
113 | void 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 | |
120 | void 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 | |
127 | void 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 | |
140 | DataDevice::Private::Private(DataDevice *q) |
141 | : q(q) |
142 | { |
143 | } |
144 | |
145 | void 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 | |
153 | DataDevice::DataDevice(QObject *parent) |
154 | : QObject(parent) |
155 | , d(new Private(this)) |
156 | { |
157 | } |
158 | |
159 | DataDevice::~DataDevice() |
160 | { |
161 | if (d->drag.offer) { |
162 | delete d->drag.offer; |
163 | } |
164 | release(); |
165 | } |
166 | |
167 | void DataDevice::destroy() |
168 | { |
169 | d->device.destroy(); |
170 | } |
171 | |
172 | void DataDevice::release() |
173 | { |
174 | d->device.release(); |
175 | } |
176 | |
177 | bool DataDevice::isValid() const |
178 | { |
179 | return d->device.isValid(); |
180 | } |
181 | |
182 | void DataDevice::setup(wl_data_device *dataDevice) |
183 | { |
184 | d->setup(dataDevice); |
185 | } |
186 | |
187 | void DataDevice::startDragInternally(quint32 serial, Surface *origin, Surface *icon) |
188 | { |
189 | startDrag(serial, source: nullptr, origin, icon); |
190 | } |
191 | |
192 | namespace |
193 | { |
194 | static wl_data_source *dataSource(const DataSource *source) |
195 | { |
196 | if (!source) { |
197 | return nullptr; |
198 | } |
199 | return *source; |
200 | } |
201 | } |
202 | |
203 | void 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 | |
208 | void DataDevice::setSelection(quint32 serial, DataSource *source) |
209 | { |
210 | wl_data_device_set_selection(wl_data_device: d->device, source: dataSource(source), serial); |
211 | } |
212 | |
213 | void DataDevice::clearSelection(quint32 serial) |
214 | { |
215 | setSelection(serial); |
216 | } |
217 | |
218 | DataOffer *DataDevice::offeredSelection() const |
219 | { |
220 | return d->selectionOffer.data(); |
221 | } |
222 | |
223 | QPointer<Surface> DataDevice::dragSurface() const |
224 | { |
225 | return d->drag.surface; |
226 | } |
227 | |
228 | DataOffer *DataDevice::dragOffer() const |
229 | { |
230 | return d->drag.offer; |
231 | } |
232 | |
233 | DataDevice::operator wl_data_device *() |
234 | { |
235 | return d->device; |
236 | } |
237 | |
238 | DataDevice::operator wl_data_device *() const |
239 | { |
240 | return d->device; |
241 | } |
242 | |
243 | } |
244 | } |
245 | |
246 | #include "moc_datadevice.cpp" |
247 | |