1 /*
2 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3 SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7 #include "datasource_interface.h"
8 #include "clientconnection.h"
9 #include "datadevicemanager_interface.h"
10 #include "utils.h"
11 // Qt
12 #include <QStringList>
13 // Wayland
14 #include <qwayland-server-wayland.h>
15 // system
16 #include <unistd.h>
17
18 namespace KWaylandServer
19 {
20 class DataSourceInterfacePrivate : public QtWaylandServer::wl_data_source
21 {
22 public:
23 DataSourceInterfacePrivate(DataSourceInterface *_q, ::wl_resource *resource);
24
25 DataSourceInterface *q;
26 QStringList mimeTypes;
27 DataDeviceManagerInterface::DnDActions supportedDnDActions = DataDeviceManagerInterface::DnDAction::None;
28 bool isAccepted = false;
29
30 protected:
31 void data_source_destroy_resource(Resource *resource) override;
32 void data_source_offer(Resource *resource, const QString &mime_type) override;
33 void data_source_destroy(Resource *resource) override;
34 void data_source_set_actions(Resource *resource, uint32_t dnd_actions) override;
35
36 private:
37 void offer(const QString &mimeType);
38 };
39
DataSourceInterfacePrivate(DataSourceInterface * _q,::wl_resource * resource)40 DataSourceInterfacePrivate::DataSourceInterfacePrivate(DataSourceInterface *_q, ::wl_resource *resource)
41 : QtWaylandServer::wl_data_source(resource)
42 , q(_q)
43 {
44 }
45
data_source_destroy_resource(Resource * resource)46 void DataSourceInterfacePrivate::data_source_destroy_resource(Resource *resource)
47 {
48 Q_UNUSED(resource)
49 Q_EMIT q->aboutToBeDestroyed();
50 delete q;
51 }
52
data_source_offer(QtWaylandServer::wl_data_source::Resource * resource,const QString & mime_type)53 void DataSourceInterfacePrivate::data_source_offer(QtWaylandServer::wl_data_source::Resource *resource, const QString &mime_type)
54 {
55 Q_UNUSED(resource)
56 mimeTypes << mime_type;
57 Q_EMIT q->mimeTypeOffered(mime_type);
58 }
59
data_source_destroy(QtWaylandServer::wl_data_source::Resource * resource)60 void DataSourceInterfacePrivate::data_source_destroy(QtWaylandServer::wl_data_source::Resource *resource)
61 {
62 wl_resource_destroy(resource->handle);
63 }
64
offer(const QString & mimeType)65 void DataSourceInterfacePrivate::offer(const QString &mimeType)
66 {
67 mimeTypes << mimeType;
68 Q_EMIT q->mimeTypeOffered(mimeType);
69 }
70
data_source_set_actions(Resource * resource,uint32_t dnd_actions)71 void DataSourceInterfacePrivate::data_source_set_actions(Resource *resource, uint32_t dnd_actions)
72 {
73 // verify that the no other actions are sent
74 if (dnd_actions
75 & ~(QtWaylandServer::wl_data_device_manager::dnd_action_copy | QtWaylandServer::wl_data_device_manager::dnd_action_move
76 | QtWaylandServer::wl_data_device_manager::dnd_action_ask)) {
77 wl_resource_post_error(resource->handle, error_invalid_action_mask, "Invalid action mask");
78 return;
79 }
80 DataDeviceManagerInterface::DnDActions supportedActions;
81 if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_copy) {
82 supportedActions |= DataDeviceManagerInterface::DnDAction::Copy;
83 }
84 if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_move) {
85 supportedActions |= DataDeviceManagerInterface::DnDAction::Move;
86 }
87 if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_ask) {
88 supportedActions |= DataDeviceManagerInterface::DnDAction::Ask;
89 }
90 if (supportedDnDActions != supportedActions) {
91 supportedDnDActions = supportedActions;
92 Q_EMIT q->supportedDragAndDropActionsChanged();
93 }
94 }
95
DataSourceInterface(DataDeviceManagerInterface * parent,wl_resource * resource)96 DataSourceInterface::DataSourceInterface(DataDeviceManagerInterface *parent, wl_resource *resource)
97 : AbstractDataSource(parent)
98 , d(new DataSourceInterfacePrivate(this, resource))
99 {
100 if (d->resource()->version() < WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
101 d->supportedDnDActions = DataDeviceManagerInterface::DnDAction::Copy;
102 }
103 }
104
105 DataSourceInterface::~DataSourceInterface() = default;
106
accept(const QString & mimeType)107 void DataSourceInterface::accept(const QString &mimeType)
108 {
109 d->send_target(mimeType);
110 d->isAccepted = !mimeType.isNull();
111 }
112
requestData(const QString & mimeType,qint32 fd)113 void DataSourceInterface::requestData(const QString &mimeType, qint32 fd)
114 {
115 d->send_send(mimeType, int32_t(fd));
116 close(fd);
117 }
118
cancel()119 void DataSourceInterface::cancel()
120 {
121 d->send_cancelled();
122 }
123
mimeTypes() const124 QStringList DataSourceInterface::mimeTypes() const
125 {
126 return d->mimeTypes;
127 }
128
get(wl_resource * native)129 DataSourceInterface *DataSourceInterface::get(wl_resource *native)
130 {
131 if (auto sourcePrivate = resource_cast<DataSourceInterfacePrivate *>(native)) {
132 return sourcePrivate->q;
133 }
134 return nullptr;
135 }
136
supportedDragAndDropActions() const137 DataDeviceManagerInterface::DnDActions DataSourceInterface::supportedDragAndDropActions() const
138 {
139 return d->supportedDnDActions;
140 }
141
dropPerformed()142 void DataSourceInterface::dropPerformed()
143 {
144 if (d->resource()->version() < WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) {
145 return;
146 }
147 d->send_dnd_drop_performed();
148 }
149
dndFinished()150 void DataSourceInterface::dndFinished()
151 {
152 if (d->resource()->version() < WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
153 return;
154 }
155 d->send_dnd_finished();
156 }
157
dndAction(DataDeviceManagerInterface::DnDAction action)158 void DataSourceInterface::dndAction(DataDeviceManagerInterface::DnDAction action)
159 {
160 if (d->resource()->version() < WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
161 return;
162 }
163 uint32_t wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_none;
164 if (action == DataDeviceManagerInterface::DnDAction::Copy) {
165 wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_copy;
166 } else if (action == DataDeviceManagerInterface::DnDAction::Move) {
167 wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_move;
168 } else if (action == DataDeviceManagerInterface::DnDAction::Ask) {
169 wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_ask;
170 }
171 d->send_action(wlAction);
172 }
173
dndCancelled()174 void DataSourceInterface::dndCancelled()
175 {
176 // for v3 or less, cancel should not be called after a failed drag operation
177 if (wl_resource_get_version(resource()) < 3) {
178 return;
179 }
180 d->send_cancelled();
181 }
182
resource() const183 wl_resource *DataSourceInterface::resource() const
184 {
185 return d->resource()->handle;
186 }
187
client() const188 wl_client *DataSourceInterface::client() const
189 {
190 return d->resource()->client();
191 }
192
isAccepted() const193 bool DataSourceInterface::isAccepted() const
194 {
195 return d->isAccepted;
196 }
197
setAccepted(bool accepted)198 void DataSourceInterface::setAccepted(bool accepted)
199 {
200 d->isAccepted = accepted;
201 }
202
203 }
204