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