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 "dataoffer.h"
7#include "datadevice.h"
8#include "wayland_pointer_p.h"
9// Qt
10#include <QMimeDatabase>
11#include <QMimeType>
12// Wayland
13#include <wayland-client-protocol.h>
14
15namespace KWayland
16{
17namespace Client
18{
19class Q_DECL_HIDDEN DataOffer::Private
20{
21public:
22 Private(wl_data_offer *offer, DataOffer *q);
23 WaylandPointer<wl_data_offer, wl_data_offer_destroy> dataOffer;
24 QList<QMimeType> mimeTypes;
25 DataDeviceManager::DnDActions sourceActions = DataDeviceManager::DnDAction::None;
26 DataDeviceManager::DnDAction selectedAction = DataDeviceManager::DnDAction::None;
27
28private:
29 void offer(const QString &mimeType);
30 void setAction(DataDeviceManager::DnDAction action);
31 static void offerCallback(void *data, wl_data_offer *dataOffer, const char *mimeType);
32 static void sourceActionsCallback(void *data, wl_data_offer *wl_data_offer, uint32_t source_actions);
33 static void actionCallback(void *data, wl_data_offer *wl_data_offer, uint32_t dnd_action);
34 DataOffer *q;
35
36 static const struct wl_data_offer_listener s_listener;
37};
38
39#ifndef K_DOXYGEN
40const struct wl_data_offer_listener DataOffer::Private::s_listener = {.offer: offerCallback, .source_actions: sourceActionsCallback, .action: actionCallback};
41#endif
42
43DataOffer::Private::Private(wl_data_offer *offer, DataOffer *q)
44 : q(q)
45{
46 dataOffer.setup(pointer: offer);
47 wl_data_offer_add_listener(wl_data_offer: offer, listener: &s_listener, data: this);
48}
49
50void DataOffer::Private::offerCallback(void *data, wl_data_offer *dataOffer, const char *mimeType)
51{
52 auto d = reinterpret_cast<Private *>(data);
53 Q_ASSERT(d->dataOffer == dataOffer);
54 d->offer(mimeType: QString::fromUtf8(utf8: mimeType));
55}
56
57void DataOffer::Private::offer(const QString &mimeType)
58{
59 QMimeDatabase db;
60 const auto &m = db.mimeTypeForName(nameOrAlias: mimeType);
61 if (m.isValid()) {
62 mimeTypes << m;
63 Q_EMIT q->mimeTypeOffered(m.name());
64 }
65}
66
67void DataOffer::Private::sourceActionsCallback(void *data, wl_data_offer *wl_data_offer, uint32_t source_actions)
68{
69 Q_UNUSED(wl_data_offer)
70 DataDeviceManager::DnDActions actions;
71 if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) {
72 actions |= DataDeviceManager::DnDAction::Copy;
73 }
74 if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) {
75 actions |= DataDeviceManager::DnDAction::Move;
76 }
77 if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) {
78 actions |= DataDeviceManager::DnDAction::Ask;
79 }
80 auto d = reinterpret_cast<Private *>(data);
81 if (d->sourceActions != actions) {
82 d->sourceActions = actions;
83 Q_EMIT d->q->sourceDragAndDropActionsChanged();
84 }
85}
86
87void DataOffer::Private::actionCallback(void *data, wl_data_offer *wl_data_offer, uint32_t dnd_action)
88{
89 Q_UNUSED(wl_data_offer)
90 auto d = reinterpret_cast<Private *>(data);
91 switch (dnd_action) {
92 case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY:
93 d->setAction(DataDeviceManager::DnDAction::Copy);
94 break;
95 case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE:
96 d->setAction(DataDeviceManager::DnDAction::Move);
97 break;
98 case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
99 d->setAction(DataDeviceManager::DnDAction::Ask);
100 break;
101 case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
102 d->setAction(DataDeviceManager::DnDAction::None);
103 break;
104 default:
105 Q_UNREACHABLE();
106 }
107}
108
109void DataOffer::Private::setAction(DataDeviceManager::DnDAction action)
110{
111 if (action == selectedAction) {
112 return;
113 }
114 selectedAction = action;
115 Q_EMIT q->selectedDragAndDropActionChanged();
116}
117
118DataOffer::DataOffer(DataDevice *parent, wl_data_offer *dataOffer)
119 : QObject(parent)
120 , d(new Private(dataOffer, this))
121{
122}
123
124DataOffer::~DataOffer()
125{
126 release();
127}
128
129void DataOffer::release()
130{
131 d->dataOffer.release();
132}
133
134void DataOffer::destroy()
135{
136 d->dataOffer.destroy();
137}
138
139bool DataOffer::isValid() const
140{
141 return d->dataOffer.isValid();
142}
143
144QList<QMimeType> DataOffer::offeredMimeTypes() const
145{
146 return d->mimeTypes;
147}
148
149void DataOffer::accept(const QMimeType &mimeType, quint32 serial)
150{
151 accept(mimeType: mimeType.name(), serial);
152}
153
154void DataOffer::accept(const QString &mimeType, quint32 serial)
155{
156 wl_data_offer_accept(wl_data_offer: d->dataOffer, serial, mime_type: mimeType.toUtf8().constData());
157}
158
159void DataOffer::receive(const QMimeType &mimeType, qint32 fd)
160{
161 receive(mimeType: mimeType.name(), fd);
162}
163
164void DataOffer::receive(const QString &mimeType, qint32 fd)
165{
166 Q_ASSERT(isValid());
167 wl_data_offer_receive(wl_data_offer: d->dataOffer, mime_type: mimeType.toUtf8().constData(), fd);
168}
169
170DataOffer::operator wl_data_offer *()
171{
172 return d->dataOffer;
173}
174
175DataOffer::operator wl_data_offer *() const
176{
177 return d->dataOffer;
178}
179
180void DataOffer::dragAndDropFinished()
181{
182 Q_ASSERT(isValid());
183 if (wl_proxy_get_version(proxy: d->dataOffer) < WL_DATA_OFFER_FINISH_SINCE_VERSION) {
184 return;
185 }
186 wl_data_offer_finish(wl_data_offer: d->dataOffer);
187}
188
189DataDeviceManager::DnDActions DataOffer::sourceDragAndDropActions() const
190{
191 return d->sourceActions;
192}
193
194void DataOffer::setDragAndDropActions(DataDeviceManager::DnDActions supported, DataDeviceManager::DnDAction preferred)
195{
196 if (wl_proxy_get_version(proxy: d->dataOffer) < WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) {
197 return;
198 }
199 auto toWayland = [](DataDeviceManager::DnDAction action) {
200 switch (action) {
201 case DataDeviceManager::DnDAction::Copy:
202 return WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
203 case DataDeviceManager::DnDAction::Move:
204 return WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
205 case DataDeviceManager::DnDAction::Ask:
206 return WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
207 case DataDeviceManager::DnDAction::None:
208 return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
209 default:
210 Q_UNREACHABLE();
211 }
212 };
213 uint32_t wlSupported = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
214 if (supported.testFlag(flag: DataDeviceManager::DnDAction::Copy)) {
215 wlSupported |= toWayland(DataDeviceManager::DnDAction::Copy);
216 }
217 if (supported.testFlag(flag: DataDeviceManager::DnDAction::Move)) {
218 wlSupported |= toWayland(DataDeviceManager::DnDAction::Move);
219 }
220 if (supported.testFlag(flag: DataDeviceManager::DnDAction::Ask)) {
221 wlSupported |= toWayland(DataDeviceManager::DnDAction::Ask);
222 }
223 wl_data_offer_set_actions(wl_data_offer: d->dataOffer, dnd_actions: wlSupported, preferred_action: toWayland(preferred));
224}
225
226DataDeviceManager::DnDAction DataOffer::selectedDragAndDropAction() const
227{
228 return d->selectedAction;
229}
230
231}
232}
233
234#include "moc_dataoffer.cpp"
235

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