blob: 75a4424a3d4548f45e24a4877b403b285571a515 [file] [log] [blame]
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001/*
2 * Copyright © 2011 Kristian Høgsberg
3 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07004 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
Kristian Høgsberg2158a882013-04-18 15:07:39 -040011 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070012 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
Kristian Høgsberg2158a882013-04-18 15:07:39 -040024 */
25
Daniel Stone8e7a8bd2013-08-15 01:10:24 +010026#include "config.h"
27
Kristian Høgsberg2158a882013-04-18 15:07:39 -040028#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31#include <stdio.h>
Jason Ekstranda7af7042013-10-12 22:38:11 -050032#include <assert.h>
Kristian Høgsberg2158a882013-04-18 15:07:39 -040033
34#include "compositor.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070035#include "shared/helpers.h"
Kristian Høgsberg2158a882013-04-18 15:07:39 -040036
Kristian Høgsberg054c50a2013-05-08 15:27:47 -040037struct weston_drag {
38 struct wl_client *client;
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -070039 struct weston_data_source *data_source;
Kristian Høgsberg054c50a2013-05-08 15:27:47 -040040 struct wl_listener data_source_listener;
Jason Ekstranda7af7042013-10-12 22:38:11 -050041 struct weston_view *focus;
Kristian Høgsberg054c50a2013-05-08 15:27:47 -040042 struct wl_resource *focus_resource;
43 struct wl_listener focus_listener;
Jason Ekstranda7af7042013-10-12 22:38:11 -050044 struct weston_view *icon;
Kristian Høgsbergc43aad12013-05-08 15:30:42 -040045 struct wl_listener icon_destroy_listener;
Kristian Høgsberg054c50a2013-05-08 15:27:47 -040046 int32_t dx, dy;
47};
48
Xiong Zhangfd51e7b2013-11-25 18:42:49 +080049struct weston_pointer_drag {
50 struct weston_drag base;
51 struct weston_pointer_grab grab;
52};
53
54struct weston_touch_drag {
55 struct weston_drag base;
56 struct weston_touch_grab grab;
57};
58
Carlos Garnacho9c931792016-01-18 23:52:12 +010059#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
60 WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
61 WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
62
Kristian Høgsberg2158a882013-04-18 15:07:39 -040063static void
64data_offer_accept(struct wl_client *client, struct wl_resource *resource,
65 uint32_t serial, const char *mime_type)
66{
Kristian Høgsberg5e76a492013-07-25 16:09:37 -070067 struct weston_data_offer *offer = wl_resource_get_user_data(resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -040068
Carlos Garnacho78d4bf92016-01-15 21:14:23 +010069 /* Protect against untimely calls from older data offers */
70 if (!offer->source || offer != offer->source->offer)
71 return;
72
Kristian Høgsberg2158a882013-04-18 15:07:39 -040073 /* FIXME: Check that client is currently focused by the input
74 * device that is currently dragging this data source. Should
75 * this be a wl_data_device request? */
76
Carlos Garnacho78d4bf92016-01-15 21:14:23 +010077 offer->source->accept(offer->source, serial, mime_type);
78 offer->source->accepted = mime_type != NULL;
Kristian Høgsberg2158a882013-04-18 15:07:39 -040079}
80
81static void
82data_offer_receive(struct wl_client *client, struct wl_resource *resource,
83 const char *mime_type, int32_t fd)
84{
Kristian Høgsberg5e76a492013-07-25 16:09:37 -070085 struct weston_data_offer *offer = wl_resource_get_user_data(resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -040086
Carlos Garnacho78d4bf92016-01-15 21:14:23 +010087 if (offer->source && offer == offer->source->offer)
Kristian Høgsberg2158a882013-04-18 15:07:39 -040088 offer->source->send(offer->source, mime_type, fd);
89 else
90 close(fd);
91}
92
93static void
94data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
95{
96 wl_resource_destroy(resource);
97}
98
Carlos Garnacho78d4bf92016-01-15 21:14:23 +010099static void
100data_source_notify_finish(struct weston_data_source *source)
101{
Carlos Garnacho9c931792016-01-18 23:52:12 +0100102 if (source->offer->in_ask &&
103 wl_resource_get_version(source->resource) >=
104 WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
105 wl_data_source_send_action(source->resource,
106 source->current_dnd_action);
107 }
108
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100109 if (wl_resource_get_version(source->resource) >=
110 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
111 wl_data_source_send_dnd_finished(source->resource);
112 }
113
114 source->offer = NULL;
115}
116
Carlos Garnacho9c931792016-01-18 23:52:12 +0100117static uint32_t
118data_offer_choose_action(struct weston_data_offer *offer)
119{
120 uint32_t available_actions, preferred_action = 0;
121 uint32_t source_actions, offer_actions;
122
123 if (wl_resource_get_version(offer->resource) >=
124 WL_DATA_OFFER_ACTION_SINCE_VERSION) {
125 offer_actions = offer->dnd_actions;
126 preferred_action = offer->preferred_dnd_action;
127 } else {
128 offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
129 }
130
131 if (wl_resource_get_version(offer->source->resource) >=
132 WL_DATA_SOURCE_ACTION_SINCE_VERSION)
133 source_actions = offer->source->dnd_actions;
134 else
135 source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
136
137 available_actions = offer_actions & source_actions;
138
139 if (!available_actions)
140 return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
141
142 /* If the dest side has a preferred DnD action, use it */
143 if ((preferred_action & available_actions) != 0)
144 return preferred_action;
145
146 /* Use the first found action, in bit order */
147 return 1 << (ffs(available_actions) - 1);
148}
149
150static void
151data_offer_update_action(struct weston_data_offer *offer)
152{
153 uint32_t action;
154
155 if (!offer->source)
156 return;
157
158 action = data_offer_choose_action(offer);
159
160 if (offer->source->current_dnd_action == action)
161 return;
162
163 offer->source->current_dnd_action = action;
164
165 if (offer->in_ask)
166 return;
167
168 if (wl_resource_get_version(offer->source->resource) >=
169 WL_DATA_SOURCE_ACTION_SINCE_VERSION)
170 wl_data_source_send_action(offer->source->resource, action);
171
172 if (wl_resource_get_version(offer->resource) >=
173 WL_DATA_OFFER_ACTION_SINCE_VERSION)
174 wl_data_offer_send_action(offer->resource, action);
175}
176
177static void
178data_offer_set_actions(struct wl_client *client,
179 struct wl_resource *resource,
180 uint32_t dnd_actions, uint32_t preferred_action)
181{
182 struct weston_data_offer *offer = wl_resource_get_user_data(resource);
183
184 if (dnd_actions & ~ALL_ACTIONS) {
185 wl_resource_post_error(offer->resource,
186 WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
187 "invalid action mask %x", dnd_actions);
188 return;
189 }
190
191 if (preferred_action &&
192 (!(preferred_action & dnd_actions) ||
193 __builtin_popcount(preferred_action) > 1)) {
194 wl_resource_post_error(offer->resource,
195 WL_DATA_OFFER_ERROR_INVALID_ACTION,
196 "invalid action %x", preferred_action);
197 return;
198 }
199
200 offer->dnd_actions = dnd_actions;
201 offer->preferred_dnd_action = preferred_action;
202 data_offer_update_action(offer);
203}
204
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100205static void
206data_offer_finish(struct wl_client *client, struct wl_resource *resource)
207{
208 struct weston_data_offer *offer = wl_resource_get_user_data(resource);
209
210 if (!offer->source || offer->source->offer != offer)
211 return;
212
213 /* Disallow finish while we have a grab driving drag-and-drop, or
214 * if the negotiation is not at the right stage
215 */
216 if (offer->source->seat ||
217 !offer->source->accepted) {
218 wl_resource_post_error(offer->resource,
219 WL_DATA_OFFER_ERROR_INVALID_FINISH,
220 "premature finish request");
221 return;
222 }
223
Carlos Garnacho9c931792016-01-18 23:52:12 +0100224 switch (offer->source->current_dnd_action) {
225 case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
226 case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
227 wl_resource_post_error(offer->resource,
228 WL_DATA_OFFER_ERROR_INVALID_OFFER,
229 "offer finished with an invalid action");
230 return;
231 default:
232 break;
233 }
234
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100235 data_source_notify_finish(offer->source);
236}
237
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400238static const struct wl_data_offer_interface data_offer_interface = {
239 data_offer_accept,
240 data_offer_receive,
241 data_offer_destroy,
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100242 data_offer_finish,
Carlos Garnacho9c931792016-01-18 23:52:12 +0100243 data_offer_set_actions,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400244};
245
246static void
247destroy_data_offer(struct wl_resource *resource)
248{
Kristian Høgsberg5e76a492013-07-25 16:09:37 -0700249 struct weston_data_offer *offer = wl_resource_get_user_data(resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400250
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100251 if (!offer->source)
252 goto out;
253
254 wl_list_remove(&offer->source_destroy_listener.link);
255
256 if (offer->source->offer != offer)
257 goto out;
258
259 /* If the drag destination has version < 3, wl_data_offer.finish
260 * won't be called, so do this here as a safety net, because
261 * we still want the version >=3 drag source to be happy.
262 */
263 if (wl_resource_get_version(offer->resource) <
264 WL_DATA_OFFER_ACTION_SINCE_VERSION) {
265 data_source_notify_finish(offer->source);
266 } else if (wl_resource_get_version(offer->source->resource) >=
267 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
268 wl_data_source_send_cancelled(offer->source->resource);
269 }
270
271 offer->source->offer = NULL;
272out:
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400273 free(offer);
274}
275
276static void
277destroy_offer_data_source(struct wl_listener *listener, void *data)
278{
Kristian Høgsberg5e76a492013-07-25 16:09:37 -0700279 struct weston_data_offer *offer;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400280
Kristian Høgsberg5e76a492013-07-25 16:09:37 -0700281 offer = container_of(listener, struct weston_data_offer,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400282 source_destroy_listener);
283
284 offer->source = NULL;
285}
286
287static struct wl_resource *
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700288weston_data_source_send_offer(struct weston_data_source *source,
289 struct wl_resource *target)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400290{
Kristian Høgsberg5e76a492013-07-25 16:09:37 -0700291 struct weston_data_offer *offer;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400292 char **p;
293
294 offer = malloc(sizeof *offer);
295 if (offer == NULL)
296 return NULL;
297
Jason Ekstranda85118c2013-06-27 20:17:02 -0500298 offer->resource =
299 wl_resource_create(wl_resource_get_client(target),
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100300 &wl_data_offer_interface,
301 wl_resource_get_version(target), 0);
Kristian Høgsberg3c30f0f2013-08-06 10:24:04 -0700302 if (offer->resource == NULL) {
303 free(offer);
304 return NULL;
305 }
306
Jason Ekstranda85118c2013-06-27 20:17:02 -0500307 wl_resource_set_implementation(offer->resource, &data_offer_interface,
308 offer, destroy_data_offer);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400309
Carlos Garnacho9c931792016-01-18 23:52:12 +0100310 offer->in_ask = false;
311 offer->dnd_actions = 0;
312 offer->preferred_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400313 offer->source = source;
314 offer->source_destroy_listener.notify = destroy_offer_data_source;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500315 wl_signal_add(&source->destroy_signal,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400316 &offer->source_destroy_listener);
317
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500318 wl_data_device_send_data_offer(target, offer->resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400319
320 wl_array_for_each(p, &source->mime_types)
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500321 wl_data_offer_send_offer(offer->resource, *p);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400322
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100323 source->offer = offer;
324 source->accepted = false;
Carlos Garnacho9c931792016-01-18 23:52:12 +0100325 data_offer_update_action(offer);
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100326
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500327 return offer->resource;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400328}
329
330static void
331data_source_offer(struct wl_client *client,
332 struct wl_resource *resource,
333 const char *type)
334{
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700335 struct weston_data_source *source =
336 wl_resource_get_user_data(resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400337 char **p;
338
339 p = wl_array_add(&source->mime_types, sizeof *p);
340 if (p)
341 *p = strdup(type);
342 if (!p || !*p)
343 wl_resource_post_no_memory(resource);
344}
345
346static void
347data_source_destroy(struct wl_client *client, struct wl_resource *resource)
348{
349 wl_resource_destroy(resource);
350}
351
Carlos Garnacho9c931792016-01-18 23:52:12 +0100352static void
353data_source_set_actions(struct wl_client *client,
354 struct wl_resource *resource,
355 uint32_t dnd_actions)
356{
357 struct weston_data_source *source =
358 wl_resource_get_user_data(resource);
359
360 if (source->actions_set) {
361 wl_resource_post_error(source->resource,
362 WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
363 "cannot set actions more than once");
364 return;
365 }
366
367 if (dnd_actions & ~ALL_ACTIONS) {
368 wl_resource_post_error(source->resource,
369 WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
370 "invalid action mask %x", dnd_actions);
371 return;
372 }
373
374 if (source->seat) {
375 wl_resource_post_error(source->resource,
376 WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
377 "invalid action change after "
378 "wl_data_device.start_drag");
379 return;
380 }
381
382 source->dnd_actions = dnd_actions;
383 source->actions_set = true;
384}
385
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400386static struct wl_data_source_interface data_source_interface = {
387 data_source_offer,
Carlos Garnacho9c931792016-01-18 23:52:12 +0100388 data_source_destroy,
389 data_source_set_actions
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400390};
391
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400392static void
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800393drag_surface_configure(struct weston_drag *drag,
Jonas Ådahl767d8912013-12-03 22:30:17 +0100394 struct weston_pointer *pointer,
395 struct weston_touch *touch,
396 struct weston_surface *es,
397 int32_t sx, int32_t sy)
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400398{
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300399 struct weston_layer_entry *list;
Kristian Høgsbergaad80992013-05-07 22:53:43 -0400400 float fx, fy;
Kristian Høgsberg415f30c2013-05-07 22:42:28 -0400401
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800402 assert((pointer != NULL && touch == NULL) ||
403 (pointer == NULL && touch != NULL));
Jason Ekstranda7af7042013-10-12 22:38:11 -0500404
Kristian Høgsberg415f30c2013-05-07 22:42:28 -0400405 if (!weston_surface_is_mapped(es) && es->buffer_ref.buffer) {
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800406 if (pointer && pointer->sprite &&
407 weston_view_is_mapped(pointer->sprite))
Kristian Høgsberg195b8692013-05-08 15:02:05 -0400408 list = &pointer->sprite->layer_link;
Kristian Høgsberg415f30c2013-05-07 22:42:28 -0400409 else
Jason Ekstranda7af7042013-10-12 22:38:11 -0500410 list = &es->compositor->cursor_layer.view_list;
Kristian Høgsberg415f30c2013-05-07 22:42:28 -0400411
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300412 weston_layer_entry_remove(&drag->icon->layer_link);
413 weston_layer_entry_insert(list, &drag->icon->layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500414 weston_view_update_transform(drag->icon);
Jason Ekstrandef540082014-06-26 10:37:36 -0700415 pixman_region32_clear(&es->pending.input);
Kristian Høgsberg415f30c2013-05-07 22:42:28 -0400416 }
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400417
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400418 drag->dx += sx;
419 drag->dy += sy;
Kristian Høgsbergaad80992013-05-07 22:53:43 -0400420
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800421 /* init to 0 for avoiding a compile warning */
422 fx = fy = 0;
423 if (pointer) {
424 fx = wl_fixed_to_double(pointer->x) + drag->dx;
425 fy = wl_fixed_to_double(pointer->y) + drag->dy;
426 } else if (touch) {
427 fx = wl_fixed_to_double(touch->grab_x) + drag->dx;
428 fy = wl_fixed_to_double(touch->grab_y) + drag->dy;
429 }
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600430 weston_view_set_position(drag->icon, fx, fy);
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400431}
432
Pekka Paalanen8274d902014-08-06 19:36:51 +0300433static int
434pointer_drag_surface_get_label(struct weston_surface *surface,
435 char *buf, size_t len)
436{
437 return snprintf(buf, len, "pointer drag icon");
438}
439
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400440static void
Jonas Ådahl767d8912013-12-03 22:30:17 +0100441pointer_drag_surface_configure(struct weston_surface *es,
442 int32_t sx, int32_t sy)
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800443{
444 struct weston_pointer_drag *drag = es->configure_private;
445 struct weston_pointer *pointer = drag->grab.pointer;
446
447 assert(es->configure == pointer_drag_surface_configure);
448
Jonas Ådahl767d8912013-12-03 22:30:17 +0100449 drag_surface_configure(&drag->base, pointer, NULL, es, sx, sy);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800450}
451
Pekka Paalanen8274d902014-08-06 19:36:51 +0300452static int
453touch_drag_surface_get_label(struct weston_surface *surface,
454 char *buf, size_t len)
455{
456 return snprintf(buf, len, "touch drag icon");
457}
458
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800459static void
Jonas Ådahl767d8912013-12-03 22:30:17 +0100460touch_drag_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800461{
462 struct weston_touch_drag *drag = es->configure_private;
463 struct weston_touch *touch = drag->grab.touch;
464
465 assert(es->configure == touch_drag_surface_configure);
466
Jonas Ådahl767d8912013-12-03 22:30:17 +0100467 drag_surface_configure(&drag->base, NULL, touch, es, sx, sy);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800468}
469
470static void
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400471destroy_drag_focus(struct wl_listener *listener, void *data)
472{
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400473 struct weston_drag *drag =
474 container_of(listener, struct weston_drag, focus_listener);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400475
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400476 drag->focus_resource = NULL;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400477}
478
479static void
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800480weston_drag_set_focus(struct weston_drag *drag,
481 struct weston_seat *seat,
482 struct weston_view *view,
483 wl_fixed_t sx, wl_fixed_t sy)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400484{
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100485 struct wl_resource *resource, *offer_resource = NULL;
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800486 struct wl_display *display = seat->compositor->wl_display;
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100487 struct weston_data_offer *offer;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400488 uint32_t serial;
489
Jason Ekstranda7af7042013-10-12 22:38:11 -0500490 if (drag->focus && view && drag->focus->surface == view->surface) {
491 drag->focus = view;
492 return;
493 }
494
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400495 if (drag->focus_resource) {
496 wl_data_device_send_leave(drag->focus_resource);
497 wl_list_remove(&drag->focus_listener.link);
498 drag->focus_resource = NULL;
499 drag->focus = NULL;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400500 }
501
Jason Ekstranda7af7042013-10-12 22:38:11 -0500502 if (!view || !view->surface->resource)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400503 return;
504
Jason Ekstrand26ed73c2013-06-06 22:34:41 -0500505 if (!drag->data_source &&
Jason Ekstranda7af7042013-10-12 22:38:11 -0500506 wl_resource_get_client(view->surface->resource) != drag->client)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400507 return;
508
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100509 if (drag->data_source &&
510 drag->data_source->offer) {
511 /* Unlink the offer from the source */
512 offer = drag->data_source->offer;
513 offer->source = NULL;
514 drag->data_source->offer = NULL;
515 wl_list_remove(&offer->source_destroy_listener.link);
516 }
517
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800518 resource = wl_resource_find_for_client(&seat->drag_resource_list,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500519 wl_resource_get_client(view->surface->resource));
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400520 if (!resource)
521 return;
522
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400523 serial = wl_display_next_serial(display);
524
Kristian Høgsberga34e2f22013-08-20 15:58:25 -0700525 if (drag->data_source) {
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100526 drag->data_source->accepted = false;
527 offer_resource = weston_data_source_send_offer(drag->data_source,
528 resource);
529 if (offer_resource == NULL)
Kristian Høgsberga34e2f22013-08-20 15:58:25 -0700530 return;
Carlos Garnacho9c931792016-01-18 23:52:12 +0100531
532 if (wl_resource_get_version (offer_resource) >=
533 WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
534 wl_data_offer_send_source_actions (offer_resource,
535 drag->data_source->dnd_actions);
536 }
Kristian Høgsberga34e2f22013-08-20 15:58:25 -0700537 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400538
Jason Ekstranda7af7042013-10-12 22:38:11 -0500539 wl_data_device_send_enter(resource, serial, view->surface->resource,
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100540 sx, sy, offer_resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400541
Jason Ekstranda7af7042013-10-12 22:38:11 -0500542 drag->focus = view;
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400543 drag->focus_listener.notify = destroy_drag_focus;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500544 wl_resource_add_destroy_listener(resource, &drag->focus_listener);
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400545 drag->focus_resource = resource;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400546}
547
548static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -0400549drag_grab_focus(struct weston_pointer_grab *grab)
550{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800551 struct weston_pointer_drag *drag =
552 container_of(grab, struct weston_pointer_drag, grab);
Kristian Høgsberg6848c252013-05-08 22:02:59 -0400553 struct weston_pointer *pointer = grab->pointer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500554 struct weston_view *view;
Kristian Høgsberg6848c252013-05-08 22:02:59 -0400555 wl_fixed_t sx, sy;
556
Jason Ekstranda7af7042013-10-12 22:38:11 -0500557 view = weston_compositor_pick_view(pointer->seat->compositor,
558 pointer->x, pointer->y,
559 &sx, &sy);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800560 if (drag->base.focus != view)
561 weston_drag_set_focus(&drag->base, pointer->seat, view, sx, sy);
Kristian Høgsberg6848c252013-05-08 22:02:59 -0400562}
563
564static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +0100565drag_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
Jonas Ådahld2510102014-10-05 21:39:14 +0200566 struct weston_pointer_motion_event *event)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400567{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800568 struct weston_pointer_drag *drag =
569 container_of(grab, struct weston_pointer_drag, grab);
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400570 struct weston_pointer *pointer = drag->grab.pointer;
Kristian Høgsbergaad80992013-05-07 22:53:43 -0400571 float fx, fy;
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -0400572 wl_fixed_t sx, sy;
Kristian Høgsbergaad80992013-05-07 22:53:43 -0400573
Jonas Ådahld2510102014-10-05 21:39:14 +0200574 weston_pointer_move(pointer, event);
Giulio Camuffo1959ab82013-11-14 23:42:52 +0100575
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800576 if (drag->base.icon) {
577 fx = wl_fixed_to_double(pointer->x) + drag->base.dx;
578 fy = wl_fixed_to_double(pointer->y) + drag->base.dy;
579 weston_view_set_position(drag->base.icon, fx, fy);
580 weston_view_schedule_repaint(drag->base.icon);
Kristian Høgsbergaad80992013-05-07 22:53:43 -0400581 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400582
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800583 if (drag->base.focus_resource) {
584 weston_view_from_global_fixed(drag->base.focus,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500585 pointer->x, pointer->y,
586 &sx, &sy);
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -0400587
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800588 wl_data_device_send_motion(drag->base.focus_resource, time, sx, sy);
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -0400589 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400590}
591
592static void
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800593data_device_end_drag_grab(struct weston_drag *drag,
594 struct weston_seat *seat)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400595{
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400596 if (drag->icon) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500597 if (weston_view_is_mapped(drag->icon))
598 weston_view_unmap(drag->icon);
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400599
Jason Ekstranda7af7042013-10-12 22:38:11 -0500600 drag->icon->surface->configure = NULL;
Pekka Paalanen8274d902014-08-06 19:36:51 +0300601 weston_surface_set_label_func(drag->icon->surface, NULL);
Jason Ekstrandef540082014-06-26 10:37:36 -0700602 pixman_region32_clear(&drag->icon->surface->pending.input);
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400603 wl_list_remove(&drag->icon_destroy_listener.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500604 weston_view_destroy(drag->icon);
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400605 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400606
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800607 weston_drag_set_focus(drag, seat, NULL, 0, 0);
608}
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400609
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800610static void
611data_device_end_pointer_drag_grab(struct weston_pointer_drag *drag)
612{
613 struct weston_pointer *pointer = drag->grab.pointer;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400614
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800615 data_device_end_drag_grab(&drag->base, pointer->seat);
616 weston_pointer_end_grab(pointer);
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400617 free(drag);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400618}
619
620static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400621drag_grab_button(struct weston_pointer_grab *grab,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400622 uint32_t time, uint32_t button, uint32_t state_w)
623{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800624 struct weston_pointer_drag *drag =
625 container_of(grab, struct weston_pointer_drag, grab);
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400626 struct weston_pointer *pointer = drag->grab.pointer;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400627 enum wl_pointer_button_state state = state_w;
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100628 struct weston_data_source *data_source = drag->base.data_source;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400629
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100630 if (data_source &&
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400631 pointer->grab_button == button &&
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100632 state == WL_POINTER_BUTTON_STATE_RELEASED) {
633 if (drag->base.focus_resource &&
Carlos Garnacho9c931792016-01-18 23:52:12 +0100634 data_source->accepted &&
635 data_source->current_dnd_action) {
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100636 wl_data_device_send_drop(drag->base.focus_resource);
637
638 if (wl_resource_get_version(data_source->resource) >=
639 WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
640 wl_data_source_send_dnd_drop_performed(data_source->resource);
641
Carlos Garnacho9c931792016-01-18 23:52:12 +0100642 data_source->offer->in_ask =
643 data_source->current_dnd_action ==
644 WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
645
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100646 data_source->seat = NULL;
647 } else if (wl_resource_get_version(data_source->resource) >=
648 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
649 wl_data_source_send_cancelled(data_source->resource);
650 }
651 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400652
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400653 if (pointer->button_count == 0 &&
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400654 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800655 if (drag->base.data_source)
656 wl_list_remove(&drag->base.data_source_listener.link);
657 data_device_end_pointer_drag_grab(drag);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400658 }
659}
660
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200661static void
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200662drag_grab_axis(struct weston_pointer_grab *grab,
Peter Hutterer89b6a492016-01-18 15:58:17 +1000663 uint32_t time, struct weston_pointer_axis_event *event)
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200664{
665}
666
667static void
Peter Hutterer87743e92016-01-18 16:38:22 +1000668drag_grab_axis_source(struct weston_pointer_grab *grab, uint32_t source)
669{
670}
671
672static void
673drag_grab_frame(struct weston_pointer_grab *grab)
674{
675}
676
677static void
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200678drag_grab_cancel(struct weston_pointer_grab *grab)
679{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800680 struct weston_pointer_drag *drag =
681 container_of(grab, struct weston_pointer_drag, grab);
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200682
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800683 if (drag->base.data_source)
684 wl_list_remove(&drag->base.data_source_listener.link);
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200685
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800686 data_device_end_pointer_drag_grab(drag);
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200687}
688
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800689static const struct weston_pointer_grab_interface pointer_drag_grab_interface = {
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400690 drag_grab_focus,
691 drag_grab_motion,
692 drag_grab_button,
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200693 drag_grab_axis,
Peter Hutterer87743e92016-01-18 16:38:22 +1000694 drag_grab_axis_source,
695 drag_grab_frame,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200696 drag_grab_cancel,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400697};
698
699static void
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800700drag_grab_touch_down(struct weston_touch_grab *grab, uint32_t time,
701 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400702{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800703}
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400704
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800705static void
706data_device_end_touch_drag_grab(struct weston_touch_drag *drag)
707{
708 struct weston_touch *touch = drag->grab.touch;
709
710 data_device_end_drag_grab(&drag->base, touch->seat);
711 weston_touch_end_grab(touch);
712 free(drag);
713}
714
715static void
716drag_grab_touch_up(struct weston_touch_grab *grab,
717 uint32_t time, int touch_id)
718{
719 struct weston_touch_drag *touch_drag =
720 container_of(grab, struct weston_touch_drag, grab);
721 struct weston_touch *touch = grab->touch;
722
723 if (touch_id != touch->grab_touch_id)
724 return;
725
726 if (touch_drag->base.focus_resource)
727 wl_data_device_send_drop(touch_drag->base.focus_resource);
728 if (touch_drag->base.data_source)
729 wl_list_remove(&touch_drag->base.data_source_listener.link);
730 data_device_end_touch_drag_grab(touch_drag);
731}
732
733static void
734drag_grab_touch_focus(struct weston_touch_drag *drag)
735{
736 struct weston_touch *touch = drag->grab.touch;
737 struct weston_view *view;
738 wl_fixed_t view_x, view_y;
739
740 view = weston_compositor_pick_view(touch->seat->compositor,
741 touch->grab_x, touch->grab_y,
742 &view_x, &view_y);
743 if (drag->base.focus != view)
744 weston_drag_set_focus(&drag->base, touch->seat,
745 view, view_x, view_y);
746}
747
748static void
749drag_grab_touch_motion(struct weston_touch_grab *grab, uint32_t time,
Giulio Camuffo61ed7b62015-07-08 11:55:28 +0300750 int touch_id, wl_fixed_t x, wl_fixed_t y)
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800751{
752 struct weston_touch_drag *touch_drag =
753 container_of(grab, struct weston_touch_drag, grab);
754 struct weston_touch *touch = grab->touch;
755 wl_fixed_t view_x, view_y;
756 float fx, fy;
757
758 if (touch_id != touch->grab_touch_id)
759 return;
760
761 drag_grab_touch_focus(touch_drag);
762 if (touch_drag->base.icon) {
763 fx = wl_fixed_to_double(touch->grab_x) + touch_drag->base.dx;
764 fy = wl_fixed_to_double(touch->grab_y) + touch_drag->base.dy;
765 weston_view_set_position(touch_drag->base.icon, fx, fy);
766 weston_view_schedule_repaint(touch_drag->base.icon);
767 }
768
769 if (touch_drag->base.focus_resource) {
770 weston_view_from_global_fixed(touch_drag->base.focus,
771 touch->grab_x, touch->grab_y,
772 &view_x, &view_y);
773 wl_data_device_send_motion(touch_drag->base.focus_resource, time,
774 view_x, view_y);
775 }
776}
777
778static void
Jonas Ådahl1679f232014-04-12 09:39:51 +0200779drag_grab_touch_frame(struct weston_touch_grab *grab)
780{
781}
782
783static void
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800784drag_grab_touch_cancel(struct weston_touch_grab *grab)
785{
786 struct weston_touch_drag *touch_drag =
787 container_of(grab, struct weston_touch_drag, grab);
788
789 if (touch_drag->base.data_source)
790 wl_list_remove(&touch_drag->base.data_source_listener.link);
791 data_device_end_touch_drag_grab(touch_drag);
792}
793
794static const struct weston_touch_grab_interface touch_drag_grab_interface = {
795 drag_grab_touch_down,
796 drag_grab_touch_up,
797 drag_grab_touch_motion,
Jonas Ådahl1679f232014-04-12 09:39:51 +0200798 drag_grab_touch_frame,
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800799 drag_grab_touch_cancel
800};
801
802static void
803destroy_pointer_data_device_source(struct wl_listener *listener, void *data)
804{
805 struct weston_pointer_drag *drag = container_of(listener,
806 struct weston_pointer_drag, base.data_source_listener);
807
808 data_device_end_pointer_drag_grab(drag);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400809}
810
811static void
Kristian Høgsbergc43aad12013-05-08 15:30:42 -0400812handle_drag_icon_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400813{
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400814 struct weston_drag *drag = container_of(listener, struct weston_drag,
Kristian Høgsbergc43aad12013-05-08 15:30:42 -0400815 icon_destroy_listener);
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400816
Kristian Høgsbergc43aad12013-05-08 15:30:42 -0400817 drag->icon = NULL;
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400818}
819
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700820WL_EXPORT int
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800821weston_pointer_start_drag(struct weston_pointer *pointer,
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700822 struct weston_data_source *source,
823 struct weston_surface *icon,
824 struct wl_client *client)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400825{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800826 struct weston_pointer_drag *drag;
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400827
Peter Huttererf3d62272013-08-08 11:57:05 +1000828 drag = zalloc(sizeof *drag);
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700829 if (drag == NULL)
830 return -1;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400831
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800832 drag->grab.interface = &pointer_drag_grab_interface;
833 drag->base.client = client;
834 drag->base.data_source = source;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400835
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400836 if (icon) {
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800837 drag->base.icon = weston_view_create(icon);
838 if (drag->base.icon == NULL) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500839 free(drag);
840 return -1;
841 }
842
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800843 drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -0500844 wl_signal_add(&icon->destroy_signal,
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800845 &drag->base.icon_destroy_listener);
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400846
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800847 icon->configure = pointer_drag_surface_configure;
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400848 icon->configure_private = drag;
Pekka Paalanen8274d902014-08-06 19:36:51 +0300849 weston_surface_set_label_func(icon,
850 pointer_drag_surface_get_label);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500851 } else {
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800852 drag->base.icon = NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500853 }
854
855 if (source) {
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800856 drag->base.data_source_listener.notify = destroy_pointer_data_device_source;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500857 wl_signal_add(&source->destroy_signal,
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800858 &drag->base.data_source_listener);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400859 }
860
Derek Foremanf9318d12015-05-11 15:40:11 -0500861 weston_pointer_clear_focus(pointer);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800862 weston_pointer_start_grab(pointer, &drag->grab);
863
864 return 0;
865}
866
867static void
868destroy_touch_data_device_source(struct wl_listener *listener, void *data)
869{
870 struct weston_touch_drag *drag = container_of(listener,
871 struct weston_touch_drag, base.data_source_listener);
872
873 data_device_end_touch_drag_grab(drag);
874}
875
876WL_EXPORT int
877weston_touch_start_drag(struct weston_touch *touch,
878 struct weston_data_source *source,
879 struct weston_surface *icon,
880 struct wl_client *client)
881{
882 struct weston_touch_drag *drag;
883
884 drag = zalloc(sizeof *drag);
885 if (drag == NULL)
886 return -1;
887
888 drag->grab.interface = &touch_drag_grab_interface;
889 drag->base.client = client;
890 drag->base.data_source = source;
891
892 if (icon) {
893 drag->base.icon = weston_view_create(icon);
894 if (drag->base.icon == NULL) {
895 free(drag);
896 return -1;
897 }
898
899 drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
900 wl_signal_add(&icon->destroy_signal,
901 &drag->base.icon_destroy_listener);
902
903 icon->configure = touch_drag_surface_configure;
904 icon->configure_private = drag;
Pekka Paalanen8274d902014-08-06 19:36:51 +0300905 weston_surface_set_label_func(icon,
906 touch_drag_surface_get_label);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800907 } else {
908 drag->base.icon = NULL;
909 }
910
911 if (source) {
912 drag->base.data_source_listener.notify = destroy_touch_data_device_source;
913 wl_signal_add(&source->destroy_signal,
914 &drag->base.data_source_listener);
915 }
916
917 weston_touch_start_grab(touch, &drag->grab);
918
919 drag_grab_touch_focus(drag);
Kristian Høgsberg0abad072013-09-11 09:42:26 -0700920
921 return 0;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400922}
923
924static void
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700925data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
926 struct wl_resource *source_resource,
927 struct wl_resource *origin_resource,
928 struct wl_resource *icon_resource, uint32_t serial)
929{
930 struct weston_seat *seat = wl_resource_get_user_data(resource);
Derek Foreman1281a362015-07-31 16:55:32 -0500931 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
932 struct weston_touch *touch = weston_seat_get_touch(seat);
Jason Ekstrand8202d722014-06-24 21:19:24 -0700933 struct weston_surface *origin = wl_resource_get_user_data(origin_resource);
Kristian Høgsberg1702d4c2013-09-11 09:45:03 -0700934 struct weston_data_source *source = NULL;
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700935 struct weston_surface *icon = NULL;
Jason Ekstrand8202d722014-06-24 21:19:24 -0700936 int is_pointer_grab, is_touch_grab;
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800937 int32_t ret = 0;
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700938
Derek Foreman1281a362015-07-31 16:55:32 -0500939 is_pointer_grab = pointer &&
940 pointer->button_count == 1 &&
941 pointer->grab_serial == serial &&
942 pointer->focus &&
943 pointer->focus->surface == origin;
Jason Ekstrand8202d722014-06-24 21:19:24 -0700944
Derek Foreman1281a362015-07-31 16:55:32 -0500945 is_touch_grab = touch &&
946 touch->num_tp == 1 &&
947 touch->grab_serial == serial &&
948 touch->focus &&
949 touch->focus->surface == origin;
Jason Ekstrand8202d722014-06-24 21:19:24 -0700950
951 if (!is_pointer_grab && !is_touch_grab)
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700952 return;
953
954 /* FIXME: Check that the data source type array isn't empty. */
955
956 if (source_resource)
957 source = wl_resource_get_user_data(source_resource);
958 if (icon_resource)
959 icon = wl_resource_get_user_data(icon_resource);
Pekka Paalanen50b67472014-10-01 15:02:41 +0300960
961 if (icon) {
962 if (weston_surface_set_role(icon, "wl_data_device-icon",
963 resource,
964 WL_DATA_DEVICE_ERROR_ROLE) < 0)
965 return;
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700966 }
967
Jason Ekstrand8202d722014-06-24 21:19:24 -0700968 if (is_pointer_grab)
Derek Foreman1281a362015-07-31 16:55:32 -0500969 ret = weston_pointer_start_drag(pointer, source, icon, client);
Jason Ekstrand8202d722014-06-24 21:19:24 -0700970 else if (is_touch_grab)
Derek Foreman1281a362015-07-31 16:55:32 -0500971 ret = weston_touch_start_drag(touch, source, icon, client);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800972
973 if (ret < 0)
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700974 wl_resource_post_no_memory(resource);
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100975 else
976 source->seat = seat;
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700977}
978
979static void
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400980destroy_selection_data_source(struct wl_listener *listener, void *data)
981{
Kristian Høgsberge3148752013-05-06 23:19:49 -0400982 struct weston_seat *seat = container_of(listener, struct weston_seat,
983 selection_data_source_listener);
Derek Foreman1281a362015-07-31 16:55:32 -0500984 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400985 struct wl_resource *data_device;
Neil Roberts96d790e2013-09-19 17:32:00 +0100986 struct weston_surface *focus = NULL;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400987
988 seat->selection_data_source = NULL;
989
Derek Foreman1281a362015-07-31 16:55:32 -0500990 if (keyboard)
991 focus = keyboard->focus;
Neil Roberts96d790e2013-09-19 17:32:00 +0100992 if (focus && focus->resource) {
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500993 data_device = wl_resource_find_for_client(&seat->drag_resource_list,
Neil Roberts96d790e2013-09-19 17:32:00 +0100994 wl_resource_get_client(focus->resource));
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400995 if (data_device)
996 wl_data_device_send_selection(data_device, NULL);
997 }
998
999 wl_signal_emit(&seat->selection_signal, seat);
1000}
1001
Giulio Camuffodddf9e62015-05-01 12:59:35 +03001002/** \brief Send the selection to the specified client
1003 *
1004 * This function creates a new wl_data_offer if there is a wl_data_source
1005 * currently set as the selection and sends it to the specified client,
1006 * followed by the wl_data_device.selection() event.
1007 * If there is no current selection the wl_data_device.selection() event
1008 * will carry a NULL wl_data_offer.
1009 *
1010 * If the client does not have a wl_data_device for the specified seat
1011 * nothing will be done.
1012 *
1013 * \param seat The seat owning the wl_data_device used to send the events.
1014 * \param client The client to which to send the selection.
1015 */
1016WL_EXPORT void
1017weston_seat_send_selection(struct weston_seat *seat, struct wl_client *client)
1018{
1019 struct wl_resource *data_device, *offer;
1020
Giulio Camuffod46bb012015-05-01 12:59:36 +03001021 wl_resource_for_each(data_device, &seat->drag_resource_list) {
1022 if (wl_resource_get_client(data_device) != client)
1023 continue;
1024
1025 if (seat->selection_data_source) {
1026 offer = weston_data_source_send_offer(seat->selection_data_source,
1027 data_device);
1028 wl_data_device_send_selection(data_device, offer);
1029 } else {
1030 wl_data_device_send_selection(data_device, NULL);
1031 }
Giulio Camuffodddf9e62015-05-01 12:59:35 +03001032 }
1033}
1034
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001035WL_EXPORT void
Kristian Høgsberge3148752013-05-06 23:19:49 -04001036weston_seat_set_selection(struct weston_seat *seat,
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -07001037 struct weston_data_source *source, uint32_t serial)
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001038{
Neil Roberts96d790e2013-09-19 17:32:00 +01001039 struct weston_surface *focus = NULL;
Derek Foreman1281a362015-07-31 16:55:32 -05001040 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001041
1042 if (seat->selection_data_source &&
1043 seat->selection_serial - serial < UINT32_MAX / 2)
1044 return;
1045
1046 if (seat->selection_data_source) {
1047 seat->selection_data_source->cancel(seat->selection_data_source);
1048 wl_list_remove(&seat->selection_data_source_listener.link);
1049 seat->selection_data_source = NULL;
1050 }
1051
1052 seat->selection_data_source = source;
1053 seat->selection_serial = serial;
1054
Derek Foreman1281a362015-07-31 16:55:32 -05001055 if (keyboard)
1056 focus = keyboard->focus;
Neil Roberts96d790e2013-09-19 17:32:00 +01001057 if (focus && focus->resource) {
Giulio Camuffodddf9e62015-05-01 12:59:35 +03001058 weston_seat_send_selection(seat, wl_resource_get_client(focus->resource));
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001059 }
1060
1061 wl_signal_emit(&seat->selection_signal, seat);
1062
1063 if (source) {
1064 seat->selection_data_source_listener.notify =
1065 destroy_selection_data_source;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -05001066 wl_signal_add(&source->destroy_signal,
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001067 &seat->selection_data_source_listener);
1068 }
1069}
1070
1071static void
1072data_device_set_selection(struct wl_client *client,
1073 struct wl_resource *resource,
1074 struct wl_resource *source_resource, uint32_t serial)
1075{
Carlos Garnacho9c931792016-01-18 23:52:12 +01001076 struct weston_data_source *source;
1077
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001078 if (!source_resource)
1079 return;
1080
Carlos Garnacho9c931792016-01-18 23:52:12 +01001081 source = wl_resource_get_user_data(source_resource);
1082
1083 if (source->actions_set) {
1084 wl_resource_post_error(source_resource,
1085 WL_DATA_SOURCE_ERROR_INVALID_SOURCE,
1086 "cannot set drag-and-drop source as selection");
1087 return;
1088 }
1089
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001090 /* FIXME: Store serial and check against incoming serial here. */
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -05001091 weston_seat_set_selection(wl_resource_get_user_data(resource),
Carlos Garnacho9c931792016-01-18 23:52:12 +01001092 source, serial);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001093}
kabeer khan3a510d82014-10-20 11:47:15 +05301094static void
1095data_device_release(struct wl_client *client, struct wl_resource *resource)
1096{
1097 wl_resource_destroy(resource);
1098}
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001099
1100static const struct wl_data_device_interface data_device_interface = {
1101 data_device_start_drag,
1102 data_device_set_selection,
kabeer khan3a510d82014-10-20 11:47:15 +05301103 data_device_release
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001104};
1105
1106static void
1107destroy_data_source(struct wl_resource *resource)
1108{
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -07001109 struct weston_data_source *source =
1110 wl_resource_get_user_data(resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001111 char **p;
1112
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -05001113 wl_signal_emit(&source->destroy_signal, source);
1114
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001115 wl_array_for_each(p, &source->mime_types)
1116 free(*p);
1117
1118 wl_array_release(&source->mime_types);
1119
Kristian Høgsberg489b2792013-06-25 11:26:31 -04001120 free(source);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001121}
1122
1123static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -07001124client_source_accept(struct weston_data_source *source,
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001125 uint32_t time, const char *mime_type)
1126{
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -05001127 wl_data_source_send_target(source->resource, mime_type);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001128}
1129
1130static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -07001131client_source_send(struct weston_data_source *source,
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001132 const char *mime_type, int32_t fd)
1133{
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -05001134 wl_data_source_send_send(source->resource, mime_type, fd);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001135 close(fd);
1136}
1137
1138static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -07001139client_source_cancel(struct weston_data_source *source)
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001140{
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -05001141 wl_data_source_send_cancelled(source->resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001142}
1143
1144static void
1145create_data_source(struct wl_client *client,
1146 struct wl_resource *resource, uint32_t id)
1147{
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -07001148 struct weston_data_source *source;
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001149
1150 source = malloc(sizeof *source);
1151 if (source == NULL) {
1152 wl_resource_post_no_memory(resource);
1153 return;
1154 }
1155
cpaul@redhat.comc9f8f8a2016-01-05 11:18:30 -05001156 source->resource =
Carlos Garnacho78d4bf92016-01-15 21:14:23 +01001157 wl_resource_create(client, &wl_data_source_interface,
1158 wl_resource_get_version(resource), id);
cpaul@redhat.comc9f8f8a2016-01-05 11:18:30 -05001159 if (source->resource == NULL) {
1160 free(source);
1161 wl_resource_post_no_memory(resource);
1162 return;
1163 }
1164
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -05001165 wl_signal_init(&source->destroy_signal);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001166 source->accept = client_source_accept;
1167 source->send = client_source_send;
1168 source->cancel = client_source_cancel;
Carlos Garnacho78d4bf92016-01-15 21:14:23 +01001169 source->offer = NULL;
1170 source->accepted = false;
1171 source->seat = NULL;
Carlos Garnacho9c931792016-01-18 23:52:12 +01001172 source->actions_set = false;
1173 source->dnd_actions = 0;
1174 source->current_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001175
1176 wl_array_init(&source->mime_types);
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -05001177
Jason Ekstranda85118c2013-06-27 20:17:02 -05001178 wl_resource_set_implementation(source->resource, &data_source_interface,
1179 source, destroy_data_source);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001180}
1181
1182static void unbind_data_device(struct wl_resource *resource)
1183{
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -05001184 wl_list_remove(wl_resource_get_link(resource));
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001185}
1186
1187static void
1188get_data_device(struct wl_client *client,
1189 struct wl_resource *manager_resource,
1190 uint32_t id, struct wl_resource *seat_resource)
1191{
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05001192 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001193 struct wl_resource *resource;
1194
Jason Ekstranda85118c2013-06-27 20:17:02 -05001195 resource = wl_resource_create(client,
kabeer khan3a510d82014-10-20 11:47:15 +05301196 &wl_data_device_interface,
1197 wl_resource_get_version(manager_resource),
1198 id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07001199 if (resource == NULL) {
1200 wl_resource_post_no_memory(manager_resource);
1201 return;
1202 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001203
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07001204 wl_list_insert(&seat->drag_resource_list,
1205 wl_resource_get_link(resource));
Jason Ekstranda85118c2013-06-27 20:17:02 -05001206 wl_resource_set_implementation(resource, &data_device_interface,
1207 seat, unbind_data_device);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001208}
1209
1210static const struct wl_data_device_manager_interface manager_interface = {
1211 create_data_source,
1212 get_data_device
1213};
1214
1215static void
1216bind_manager(struct wl_client *client,
1217 void *data, uint32_t version, uint32_t id)
1218{
Jason Ekstranda85118c2013-06-27 20:17:02 -05001219 struct wl_resource *resource;
1220
kabeer khan3a510d82014-10-20 11:47:15 +05301221 resource = wl_resource_create(client,
1222 &wl_data_device_manager_interface,
1223 version, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07001224 if (resource == NULL) {
1225 wl_client_post_no_memory(client);
1226 return;
1227 }
1228
1229 wl_resource_set_implementation(resource, &manager_interface,
1230 NULL, NULL);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001231}
1232
1233WL_EXPORT void
Kristian Høgsberge3148752013-05-06 23:19:49 -04001234wl_data_device_set_keyboard_focus(struct weston_seat *seat)
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001235{
Neil Roberts96d790e2013-09-19 17:32:00 +01001236 struct weston_surface *focus;
Derek Foreman1281a362015-07-31 16:55:32 -05001237 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001238
Derek Foreman1281a362015-07-31 16:55:32 -05001239 if (!keyboard)
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001240 return;
1241
Derek Foreman1281a362015-07-31 16:55:32 -05001242 focus = keyboard->focus;
Neil Roberts96d790e2013-09-19 17:32:00 +01001243 if (!focus || !focus->resource)
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001244 return;
1245
Giulio Camuffodddf9e62015-05-01 12:59:35 +03001246 weston_seat_send_selection(seat, wl_resource_get_client(focus->resource));
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001247}
1248
1249WL_EXPORT int
1250wl_data_device_manager_init(struct wl_display *display)
1251{
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04001252 if (wl_global_create(display,
Carlos Garnacho78d4bf92016-01-15 21:14:23 +01001253 &wl_data_device_manager_interface, 3,
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04001254 NULL, bind_manager) == NULL)
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001255 return -1;
1256
1257 return 0;
1258}