blob: 30f0438ab3eabd8badc64ffef02531462c51f0b6 [file] [log] [blame]
Daniel Nicoaraa2b23512019-01-28 16:42:081// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/exo/wayland/wl_data_device_manager.h"
6
7#include <wayland-server-protocol-core.h>
8
9#include <algorithm>
10#include <memory>
11#include <string>
12#include <utility>
13
14#include "components/exo/data_device.h"
15#include "components/exo/data_device_delegate.h"
16#include "components/exo/data_offer.h"
17#include "components/exo/data_offer_delegate.h"
18#include "components/exo/data_source.h"
19#include "components/exo/data_source_delegate.h"
20#include "components/exo/display.h"
Fergus Dalldabc0b62019-07-26 07:16:2121#include "components/exo/wayland/serial_tracker.h"
Daniel Nicoaraa2b23512019-01-28 16:42:0822#include "components/exo/wayland/server_util.h"
Henrique Ferreiro1748fd12020-08-04 12:51:4623#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
Daniel Nicoaraa2b23512019-01-28 16:42:0824
25namespace exo {
26namespace wayland {
27namespace {
28
29uint32_t WaylandDataDeviceManagerDndAction(DndAction action) {
30 switch (action) {
31 case DndAction::kNone:
32 return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
33 case DndAction::kCopy:
34 return WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
35 case DndAction::kMove:
36 return WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
37 case DndAction::kAsk:
38 return WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
39 }
40 NOTREACHED();
41}
42
43uint32_t WaylandDataDeviceManagerDndActions(
44 const base::flat_set<DndAction>& dnd_actions) {
45 uint32_t actions = 0;
46 for (DndAction action : dnd_actions)
47 actions |= WaylandDataDeviceManagerDndAction(action);
48 return actions;
49}
50
51DndAction DataDeviceManagerDndAction(uint32_t value) {
52 switch (value) {
53 case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
54 return DndAction::kNone;
55 case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY:
56 return DndAction::kCopy;
57 case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE:
58 return DndAction::kMove;
59 case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
60 return DndAction::kAsk;
61 default:
62 NOTREACHED();
63 return DndAction::kNone;
64 }
65}
66
67base::flat_set<DndAction> DataDeviceManagerDndActions(uint32_t value) {
68 base::flat_set<DndAction> actions;
69 if (value & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
70 actions.insert(DndAction::kCopy);
71 if (value & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
72 actions.insert(DndAction::kMove);
73 if (value & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
74 actions.insert(DndAction::kAsk);
75 return actions;
76}
77
78////////////////////////////////////////////////////////////////////////////////
79// wl_data_source_interface:
80
81class WaylandDataSourceDelegate : public DataSourceDelegate {
82 public:
matterchen43431472019-12-16 01:43:1083 explicit WaylandDataSourceDelegate(wl_client* client,
84 wl_resource* source)
85 : client_(client),
86 data_source_resource_(source) {}
Daniel Nicoaraa2b23512019-01-28 16:42:0887
88 // Overridden from DataSourceDelegate:
89 void OnDataSourceDestroying(DataSource* device) override { delete this; }
matterchen43431472019-12-16 01:43:1090 bool CanAcceptDataEventsForSurface(Surface* surface) const override {
91 return surface &&
92 wl_resource_get_client(GetSurfaceResource(surface)) == client_;
93 }
Fergus Dall2bcca7c72019-08-21 04:22:4194 void OnTarget(const base::Optional<std::string>& mime_type) override {
95 wl_data_source_send_target(data_source_resource_,
96 mime_type ? mime_type->c_str() : nullptr);
Daniel Nicoaraa2b23512019-01-28 16:42:0897 wl_client_flush(wl_resource_get_client(data_source_resource_));
98 }
99 void OnSend(const std::string& mime_type, base::ScopedFD fd) override {
100 wl_data_source_send_send(data_source_resource_, mime_type.c_str(),
101 fd.get());
102 wl_client_flush(wl_resource_get_client(data_source_resource_));
103 }
104 void OnCancelled() override {
105 wl_data_source_send_cancelled(data_source_resource_);
106 wl_client_flush(wl_resource_get_client(data_source_resource_));
107 }
108 void OnDndDropPerformed() override {
109 if (wl_resource_get_version(data_source_resource_) >=
110 WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) {
111 wl_data_source_send_dnd_drop_performed(data_source_resource_);
112 wl_client_flush(wl_resource_get_client(data_source_resource_));
113 }
114 }
115 void OnDndFinished() override {
116 if (wl_resource_get_version(data_source_resource_) >=
117 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
118 wl_data_source_send_dnd_finished(data_source_resource_);
119 wl_client_flush(wl_resource_get_client(data_source_resource_));
120 }
121 }
122 void OnAction(DndAction dnd_action) override {
123 if (wl_resource_get_version(data_source_resource_) >=
124 WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
125 wl_data_source_send_action(data_source_resource_,
126 WaylandDataDeviceManagerDndAction(dnd_action));
127 wl_client_flush(wl_resource_get_client(data_source_resource_));
128 }
129 }
130
131 private:
matterchen43431472019-12-16 01:43:10132 wl_client* const client_;
Daniel Nicoaraa2b23512019-01-28 16:42:08133 wl_resource* const data_source_resource_;
134
135 DISALLOW_COPY_AND_ASSIGN(WaylandDataSourceDelegate);
136};
137
138void data_source_offer(wl_client* client,
139 wl_resource* resource,
140 const char* mime_type) {
141 GetUserDataAs<DataSource>(resource)->Offer(mime_type);
142}
143
144void data_source_destroy(wl_client* client, wl_resource* resource) {
145 wl_resource_destroy(resource);
146}
147
148void data_source_set_actions(wl_client* client,
149 wl_resource* resource,
150 uint32_t dnd_actions) {
151 GetUserDataAs<DataSource>(resource)->SetActions(
152 DataDeviceManagerDndActions(dnd_actions));
153}
154
155const struct wl_data_source_interface data_source_implementation = {
156 data_source_offer, data_source_destroy, data_source_set_actions};
157
158////////////////////////////////////////////////////////////////////////////////
159// wl_data_offer_interface:
160
161class WaylandDataOfferDelegate : public DataOfferDelegate {
162 public:
163 explicit WaylandDataOfferDelegate(wl_resource* offer)
164 : data_offer_resource_(offer) {}
165
166 // Overridden from DataOfferDelegate:
167 void OnDataOfferDestroying(DataOffer* device) override { delete this; }
168 void OnOffer(const std::string& mime_type) override {
169 wl_data_offer_send_offer(data_offer_resource_, mime_type.c_str());
170 wl_client_flush(wl_resource_get_client(data_offer_resource_));
171 }
Henrique Ferreiro1c1052b2021-03-03 21:43:31172 void OnActions(const base::flat_set<DndAction>& source_actions,
173 DndAction action) override {
174 bool should_flush = false;
Daniel Nicoaraa2b23512019-01-28 16:42:08175 if (wl_resource_get_version(data_offer_resource_) >=
176 WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
177 wl_data_offer_send_source_actions(
178 data_offer_resource_,
179 WaylandDataDeviceManagerDndActions(source_actions));
Henrique Ferreiro1c1052b2021-03-03 21:43:31180 should_flush = true;
Daniel Nicoaraa2b23512019-01-28 16:42:08181 }
Daniel Nicoaraa2b23512019-01-28 16:42:08182 if (wl_resource_get_version(data_offer_resource_) >=
183 WL_DATA_OFFER_ACTION_SINCE_VERSION) {
184 wl_data_offer_send_action(data_offer_resource_,
185 WaylandDataDeviceManagerDndAction(action));
Henrique Ferreiro1c1052b2021-03-03 21:43:31186 should_flush = true;
Daniel Nicoaraa2b23512019-01-28 16:42:08187 }
Henrique Ferreiro1c1052b2021-03-03 21:43:31188 if (should_flush)
189 wl_client_flush(wl_resource_get_client(data_offer_resource_));
Daniel Nicoaraa2b23512019-01-28 16:42:08190 }
191
192 private:
193 wl_resource* const data_offer_resource_;
194
195 DISALLOW_COPY_AND_ASSIGN(WaylandDataOfferDelegate);
196};
197
198void data_offer_accept(wl_client* client,
199 wl_resource* resource,
200 uint32_t serial,
201 const char* mime_type) {
Daichi Hironof29748c72019-02-07 22:02:04202 if (mime_type == nullptr) {
203 GetUserDataAs<DataOffer>(resource)->Accept(nullptr);
204 return;
205 }
206 const std::string mime_type_string(mime_type);
207 GetUserDataAs<DataOffer>(resource)->Accept(&mime_type_string);
Daniel Nicoaraa2b23512019-01-28 16:42:08208}
209
210void data_offer_receive(wl_client* client,
211 wl_resource* resource,
212 const char* mime_type,
213 int fd) {
214 GetUserDataAs<DataOffer>(resource)->Receive(mime_type, base::ScopedFD(fd));
215}
216
217void data_offer_destroy(wl_client* client, wl_resource* resource) {
218 wl_resource_destroy(resource);
219}
220
221void data_offer_finish(wl_client* client, wl_resource* resource) {
222 GetUserDataAs<DataOffer>(resource)->Finish();
223}
224
225void data_offer_set_actions(wl_client* client,
226 wl_resource* resource,
227 uint32_t dnd_actions,
228 uint32_t preferred_action) {
229 GetUserDataAs<DataOffer>(resource)->SetActions(
230 DataDeviceManagerDndActions(dnd_actions),
231 DataDeviceManagerDndAction(preferred_action));
232}
233
234const struct wl_data_offer_interface data_offer_implementation = {
Nicholas Hollingum3fcb1ef72019-07-28 08:03:49235 data_offer_accept, data_offer_receive, data_offer_destroy,
236 data_offer_finish, data_offer_set_actions};
Daniel Nicoaraa2b23512019-01-28 16:42:08237
238////////////////////////////////////////////////////////////////////////////////
239// wl_data_device_interface:
240
241class WaylandDataDeviceDelegate : public DataDeviceDelegate {
242 public:
Fergus Dalldabc0b62019-07-26 07:16:21243 WaylandDataDeviceDelegate(wl_client* client,
244 wl_resource* device_resource,
245 SerialTracker* serial_tracker)
246 : client_(client),
247 data_device_resource_(device_resource),
248 serial_tracker_(serial_tracker) {}
Daniel Nicoaraa2b23512019-01-28 16:42:08249
250 // Overridden from DataDeviceDelegate:
251 void OnDataDeviceDestroying(DataDevice* device) override { delete this; }
matterchen43431472019-12-16 01:43:10252 bool CanAcceptDataEventsForSurface(Surface* surface) const override {
Daniel Nicoaraa2b23512019-01-28 16:42:08253 return surface &&
254 wl_resource_get_client(GetSurfaceResource(surface)) == client_;
255 }
Joel Hockeyca98ffa42020-11-04 22:09:59256 DataOffer* OnDataOffer() override {
Daniel Nicoaraa2b23512019-01-28 16:42:08257 wl_resource* data_offer_resource =
258 wl_resource_create(client_, &wl_data_offer_interface,
259 wl_resource_get_version(data_device_resource_), 0);
260 std::unique_ptr<DataOffer> data_offer = std::make_unique<DataOffer>(
Joel Hockeyca98ffa42020-11-04 22:09:59261 new WaylandDataOfferDelegate(data_offer_resource));
Daniel Nicoaraa2b23512019-01-28 16:42:08262 SetDataOfferResource(data_offer.get(), data_offer_resource);
263 SetImplementation(data_offer_resource, &data_offer_implementation,
264 std::move(data_offer));
265
266 wl_data_device_send_data_offer(data_device_resource_, data_offer_resource);
267 wl_client_flush(client_);
268
269 return GetUserDataAs<DataOffer>(data_offer_resource);
270 }
271 void OnEnter(Surface* surface,
272 const gfx::PointF& point,
273 const DataOffer& data_offer) override {
274 wl_data_device_send_enter(
275 data_device_resource_,
Fergus Dalldabc0b62019-07-26 07:16:21276 serial_tracker_->GetNextSerial(SerialTracker::EventType::OTHER_EVENT),
Daniel Nicoaraa2b23512019-01-28 16:42:08277 GetSurfaceResource(surface), wl_fixed_from_double(point.x()),
278 wl_fixed_from_double(point.y()), GetDataOfferResource(&data_offer));
279 wl_client_flush(client_);
280 }
281 void OnLeave() override {
282 wl_data_device_send_leave(data_device_resource_);
283 wl_client_flush(client_);
284 }
285 void OnMotion(base::TimeTicks time_stamp, const gfx::PointF& point) override {
286 wl_data_device_send_motion(
287 data_device_resource_, TimeTicksToMilliseconds(time_stamp),
288 wl_fixed_from_double(point.x()), wl_fixed_from_double(point.y()));
289 wl_client_flush(client_);
290 }
291 void OnDrop() override {
292 wl_data_device_send_drop(data_device_resource_);
293 wl_client_flush(client_);
294 }
295 void OnSelection(const DataOffer& data_offer) override {
296 wl_data_device_send_selection(data_device_resource_,
297 GetDataOfferResource(&data_offer));
298 wl_client_flush(client_);
299 }
300
Fergus Dall4466e9782019-07-26 08:04:13301 void StartDrag(DataDevice* data_device,
302 DataSource* source,
303 Surface* origin,
304 Surface* icon,
305 uint32_t serial) {
306 base::Optional<wayland::SerialTracker::EventType> event_type =
307 serial_tracker_->GetEventType(serial);
Tetsui Ohkubo541b75962020-06-23 04:24:37308 if (event_type == base::nullopt) {
309 LOG(ERROR) << "The serial passed to StartDrag does not exist.";
Tetsui Ohkubo541b75962020-06-23 04:24:37310 return;
311 }
Fergus Dall8c755bb2019-08-05 02:26:51312 if (event_type == wayland::SerialTracker::EventType::POINTER_BUTTON_DOWN &&
313 serial_tracker_->GetPointerDownSerial() == serial) {
David Munroe23c00e2020-10-22 23:34:06314 DCHECK(data_device);
Henrique Ferreiro1748fd12020-08-04 12:51:46315 data_device->StartDrag(source, origin, icon,
316 ui::mojom::DragEventSource::kMouse);
Fergus Dall8c755bb2019-08-05 02:26:51317 } else if (event_type == wayland::SerialTracker::EventType::TOUCH_DOWN &&
318 serial_tracker_->GetTouchDownSerial() == serial) {
David Munroe23c00e2020-10-22 23:34:06319 DCHECK(data_device);
Henrique Ferreiro1748fd12020-08-04 12:51:46320 data_device->StartDrag(source, origin, icon,
321 ui::mojom::DragEventSource::kTouch);
Fergus Dall4466e9782019-07-26 08:04:13322 } else {
Tetsui Ohkubo541b75962020-06-23 04:24:37323 LOG(ERROR) << "The serial passed to StartDrag does not match its "
324 "expected types.";
Fergus Dall4466e9782019-07-26 08:04:13325 }
326 }
327
Tetsui Ohkubo541b75962020-06-23 04:24:37328 void SetSelection(DataDevice* data_device,
329 DataSource* source,
330 uint32_t serial) {
331 base::Optional<wayland::SerialTracker::EventType> event_type =
332 serial_tracker_->GetEventType(serial);
333 if (event_type == base::nullopt) {
334 LOG(ERROR) << "The serial passed to SetSelection does not exist.";
Tetsui Ohkubo541b75962020-06-23 04:24:37335 return;
336 }
David Munroe23c00e2020-10-22 23:34:06337 DCHECK(data_device);
Tetsui Ohkubo541b75962020-06-23 04:24:37338 data_device->SetSelection(source);
339 }
340
Daniel Nicoaraa2b23512019-01-28 16:42:08341 private:
342 wl_client* const client_;
343 wl_resource* const data_device_resource_;
344
Fergus Dalldabc0b62019-07-26 07:16:21345 // Owned by Server, which always outlives this delegate.
346 SerialTracker* const serial_tracker_;
347
Daniel Nicoaraa2b23512019-01-28 16:42:08348 DISALLOW_COPY_AND_ASSIGN(WaylandDataDeviceDelegate);
349};
350
351void data_device_start_drag(wl_client* client,
352 wl_resource* resource,
353 wl_resource* source_resource,
354 wl_resource* origin_resource,
355 wl_resource* icon_resource,
356 uint32_t serial) {
Fergus Dall4466e9782019-07-26 08:04:13357 DataDevice* data_device = GetUserDataAs<DataDevice>(resource);
358 static_cast<WaylandDataDeviceDelegate*>(data_device->get_delegate())
359 ->StartDrag(
360 data_device,
361 source_resource ? GetUserDataAs<DataSource>(source_resource)
362 : nullptr,
363 GetUserDataAs<Surface>(origin_resource),
364 icon_resource ? GetUserDataAs<Surface>(icon_resource) : nullptr,
365 serial);
Daniel Nicoaraa2b23512019-01-28 16:42:08366}
367
368void data_device_set_selection(wl_client* client,
369 wl_resource* resource,
Tetsui Ohkubo541b75962020-06-23 04:24:37370 wl_resource* source_resource,
Daniel Nicoaraa2b23512019-01-28 16:42:08371 uint32_t serial) {
Tetsui Ohkubo541b75962020-06-23 04:24:37372 DataDevice* data_device = GetUserDataAs<DataDevice>(resource);
373 static_cast<WaylandDataDeviceDelegate*>(data_device->get_delegate())
374 ->SetSelection(data_device,
375 source_resource
376 ? GetUserDataAs<DataSource>(source_resource)
377 : nullptr,
378 serial);
Daniel Nicoaraa2b23512019-01-28 16:42:08379}
380
381void data_device_release(wl_client* client, wl_resource* resource) {
382 wl_resource_destroy(resource);
383}
384
385const struct wl_data_device_interface data_device_implementation = {
386 data_device_start_drag, data_device_set_selection, data_device_release};
387
388////////////////////////////////////////////////////////////////////////////////
389// wl_data_device_manager_interface:
390
391void data_device_manager_create_data_source(wl_client* client,
392 wl_resource* resource,
393 uint32_t id) {
394 wl_resource* data_source_resource = wl_resource_create(
395 client, &wl_data_source_interface, wl_resource_get_version(resource), id);
396 SetImplementation(data_source_resource, &data_source_implementation,
matterchen43431472019-12-16 01:43:10397 std::make_unique<DataSource>(new WaylandDataSourceDelegate(
398 client, data_source_resource)));
Daniel Nicoaraa2b23512019-01-28 16:42:08399}
400
401void data_device_manager_get_data_device(wl_client* client,
402 wl_resource* resource,
403 uint32_t id,
404 wl_resource* seat_resource) {
Fergus Dalldabc0b62019-07-26 07:16:21405 auto* data = GetUserDataAs<WaylandDataDeviceManager>(resource);
Daniel Nicoaraa2b23512019-01-28 16:42:08406 wl_resource* data_device_resource = wl_resource_create(
407 client, &wl_data_device_interface, wl_resource_get_version(resource), id);
Fergus Dalldabc0b62019-07-26 07:16:21408 SetImplementation(
409 data_device_resource, &data_device_implementation,
410 data->display->CreateDataDevice(new WaylandDataDeviceDelegate(
411 client, data_device_resource, data->serial_tracker)));
Daniel Nicoaraa2b23512019-01-28 16:42:08412}
413
414const struct wl_data_device_manager_interface
415 data_device_manager_implementation = {
416 data_device_manager_create_data_source,
417 data_device_manager_get_data_device};
418
419} // namespace
420
421void bind_data_device_manager(wl_client* client,
422 void* data,
423 uint32_t version,
424 uint32_t id) {
425 wl_resource* resource =
426 wl_resource_create(client, &wl_data_device_manager_interface,
427 std::min(version, kWlDataDeviceManagerVersion), id);
428 wl_resource_set_implementation(resource, &data_device_manager_implementation,
429 data, nullptr);
430}
431
432} // namespace wayland
433} // namespace exo