1 /********************************************************************
2 Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
20 #include "datasource.h"
21 #include "selection_source_p.h"
22 #include "wayland_pointer_p.h"
23 // Qt
24 #include <QMimeType>
25 // Wayland
26 #include <wayland-client-protocol.h>
27
28 namespace Wrapland
29 {
30 namespace Client
31 {
32
33 class Q_DECL_HIDDEN DataSource::Private
34 {
35 public:
36 explicit Private(DataSource* q);
37 void setup(wl_data_source* s);
38
39 WaylandPointer<wl_data_source, wl_data_source_destroy> source;
40 DataDeviceManager::DnDAction selectedAction = DataDeviceManager::DnDAction::None;
41
42 void setAction(DataDeviceManager::DnDAction action);
43 static void targetCallback(void* data, wl_data_source* dataSource, const char* mimeType);
44 static void dndDropPerformedCallback(void* data, wl_data_source* wl_data_source);
45 static void dndFinishedCallback(void* data, wl_data_source* wl_data_source);
46 static void actionCallback(void* data, wl_data_source* wl_data_source, uint32_t dnd_action);
47
48 static const struct wl_data_source_listener s_listener;
49
50 DataSource* q;
51 };
52
53 const wl_data_source_listener DataSource::Private::s_listener = {
54 targetCallback,
55 send_callback<Private>,
56 cancelled_callback<Private>,
57 dndDropPerformedCallback,
58 dndFinishedCallback,
59 actionCallback,
60 };
61
Private(DataSource * q)62 DataSource::Private::Private(DataSource* q)
63 : q(q)
64 {
65 }
66
targetCallback(void * data,wl_data_source * dataSource,const char * mimeType)67 void DataSource::Private::targetCallback(void* data,
68 wl_data_source* dataSource,
69 const char* mimeType)
70 {
71 auto d = reinterpret_cast<DataSource::Private*>(data);
72 Q_ASSERT(d->source == dataSource);
73 emit d->q->targetAccepts(QString::fromUtf8(mimeType));
74 }
75
dndDropPerformedCallback(void * data,wl_data_source * wl_data_source)76 void DataSource::Private::dndDropPerformedCallback(void* data, wl_data_source* wl_data_source)
77 {
78 Q_UNUSED(wl_data_source)
79 auto d = reinterpret_cast<DataSource::Private*>(data);
80 emit d->q->dragAndDropPerformed();
81 }
82
dndFinishedCallback(void * data,wl_data_source * wl_data_source)83 void DataSource::Private::dndFinishedCallback(void* data, wl_data_source* wl_data_source)
84 {
85 Q_UNUSED(wl_data_source)
86 auto d = reinterpret_cast<DataSource::Private*>(data);
87 emit d->q->dragAndDropFinished();
88 }
89
actionCallback(void * data,wl_data_source * wl_data_source,uint32_t dnd_action)90 void DataSource::Private::actionCallback(void* data,
91 wl_data_source* wl_data_source,
92 uint32_t dnd_action)
93 {
94 Q_UNUSED(wl_data_source)
95 auto d = reinterpret_cast<Private*>(data);
96 switch (dnd_action) {
97 case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY:
98 d->setAction(DataDeviceManager::DnDAction::Copy);
99 break;
100 case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE:
101 d->setAction(DataDeviceManager::DnDAction::Move);
102 break;
103 case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
104 d->setAction(DataDeviceManager::DnDAction::Ask);
105 break;
106 case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
107 d->setAction(DataDeviceManager::DnDAction::None);
108 break;
109 default:
110 Q_UNREACHABLE();
111 }
112 }
113
setAction(DataDeviceManager::DnDAction action)114 void DataSource::Private::setAction(DataDeviceManager::DnDAction action)
115 {
116 if (action == selectedAction) {
117 return;
118 }
119 selectedAction = action;
120 emit q->selectedDragAndDropActionChanged();
121 }
122
setup(wl_data_source * s)123 void DataSource::Private::setup(wl_data_source* s)
124 {
125 Q_ASSERT(!source.isValid());
126 Q_ASSERT(s);
127 source.setup(s);
128 wl_data_source_add_listener(s, &s_listener, this);
129 }
130
DataSource(QObject * parent)131 DataSource::DataSource(QObject* parent)
132 : QObject(parent)
133 , d(new Private(this))
134 {
135 }
136
~DataSource()137 DataSource::~DataSource()
138 {
139 release();
140 }
141
release()142 void DataSource::release()
143 {
144 d->source.release();
145 }
146
isValid() const147 bool DataSource::isValid() const
148 {
149 return d->source.isValid();
150 }
151
setup(wl_data_source * dataSource)152 void DataSource::setup(wl_data_source* dataSource)
153 {
154 d->setup(dataSource);
155 }
156
offer(const QString & mimeType)157 void DataSource::offer(const QString& mimeType)
158 {
159 wl_data_source_offer(d->source, mimeType.toUtf8().constData());
160 }
161
offer(const QMimeType & mimeType)162 void DataSource::offer(const QMimeType& mimeType)
163 {
164 if (!mimeType.isValid()) {
165 return;
166 }
167 offer(mimeType.name());
168 }
169
operator wl_data_source*() const170 DataSource::operator wl_data_source*() const
171 {
172 return d->source;
173 }
174
operator wl_data_source*()175 DataSource::operator wl_data_source*()
176 {
177 return d->source;
178 }
179
setDragAndDropActions(DataDeviceManager::DnDActions actions)180 void DataSource::setDragAndDropActions(DataDeviceManager::DnDActions actions)
181 {
182 uint32_t wlActions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
183 if (actions.testFlag(DataDeviceManager::DnDAction::Copy)) {
184 wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
185 }
186 if (actions.testFlag(DataDeviceManager::DnDAction::Move)) {
187 wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
188 }
189 if (actions.testFlag(DataDeviceManager::DnDAction::Ask)) {
190 wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
191 }
192 wl_data_source_set_actions(d->source, wlActions);
193 }
194
selectedDragAndDropAction() const195 DataDeviceManager::DnDAction DataSource::selectedDragAndDropAction() const
196 {
197 return d->selectedAction;
198 }
199
200 }
201 }
202