blob: d12b16c89596424e0ee1c9e6a9f806abf2d7f88b [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
Kristian Høgsberg2158a882013-04-18 15:07:39 -040059static void
60data_offer_accept(struct wl_client *client, struct wl_resource *resource,
61 uint32_t serial, const char *mime_type)
62{
Kristian Høgsberg5e76a492013-07-25 16:09:37 -070063 struct weston_data_offer *offer = wl_resource_get_user_data(resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -040064
Carlos Garnacho78d4bf92016-01-15 21:14:23 +010065 /* Protect against untimely calls from older data offers */
66 if (!offer->source || offer != offer->source->offer)
67 return;
68
Kristian Høgsberg2158a882013-04-18 15:07:39 -040069 /* FIXME: Check that client is currently focused by the input
70 * device that is currently dragging this data source. Should
71 * this be a wl_data_device request? */
72
Carlos Garnacho78d4bf92016-01-15 21:14:23 +010073 offer->source->accept(offer->source, serial, mime_type);
74 offer->source->accepted = mime_type != NULL;
Kristian Høgsberg2158a882013-04-18 15:07:39 -040075}
76
77static void
78data_offer_receive(struct wl_client *client, struct wl_resource *resource,
79 const char *mime_type, int32_t fd)
80{
Kristian Høgsberg5e76a492013-07-25 16:09:37 -070081 struct weston_data_offer *offer = wl_resource_get_user_data(resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -040082
Carlos Garnacho78d4bf92016-01-15 21:14:23 +010083 if (offer->source && offer == offer->source->offer)
Kristian Høgsberg2158a882013-04-18 15:07:39 -040084 offer->source->send(offer->source, mime_type, fd);
85 else
86 close(fd);
87}
88
89static void
90data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
91{
92 wl_resource_destroy(resource);
93}
94
Carlos Garnacho78d4bf92016-01-15 21:14:23 +010095static void
96data_source_notify_finish(struct weston_data_source *source)
97{
98 if (wl_resource_get_version(source->resource) >=
99 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
100 wl_data_source_send_dnd_finished(source->resource);
101 }
102
103 source->offer = NULL;
104}
105
106static void
107data_offer_finish(struct wl_client *client, struct wl_resource *resource)
108{
109 struct weston_data_offer *offer = wl_resource_get_user_data(resource);
110
111 if (!offer->source || offer->source->offer != offer)
112 return;
113
114 /* Disallow finish while we have a grab driving drag-and-drop, or
115 * if the negotiation is not at the right stage
116 */
117 if (offer->source->seat ||
118 !offer->source->accepted) {
119 wl_resource_post_error(offer->resource,
120 WL_DATA_OFFER_ERROR_INVALID_FINISH,
121 "premature finish request");
122 return;
123 }
124
125 data_source_notify_finish(offer->source);
126}
127
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400128static const struct wl_data_offer_interface data_offer_interface = {
129 data_offer_accept,
130 data_offer_receive,
131 data_offer_destroy,
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100132 data_offer_finish,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400133};
134
135static void
136destroy_data_offer(struct wl_resource *resource)
137{
Kristian Høgsberg5e76a492013-07-25 16:09:37 -0700138 struct weston_data_offer *offer = wl_resource_get_user_data(resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400139
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100140 if (!offer->source)
141 goto out;
142
143 wl_list_remove(&offer->source_destroy_listener.link);
144
145 if (offer->source->offer != offer)
146 goto out;
147
148 /* If the drag destination has version < 3, wl_data_offer.finish
149 * won't be called, so do this here as a safety net, because
150 * we still want the version >=3 drag source to be happy.
151 */
152 if (wl_resource_get_version(offer->resource) <
153 WL_DATA_OFFER_ACTION_SINCE_VERSION) {
154 data_source_notify_finish(offer->source);
155 } else if (wl_resource_get_version(offer->source->resource) >=
156 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
157 wl_data_source_send_cancelled(offer->source->resource);
158 }
159
160 offer->source->offer = NULL;
161out:
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400162 free(offer);
163}
164
165static void
166destroy_offer_data_source(struct wl_listener *listener, void *data)
167{
Kristian Høgsberg5e76a492013-07-25 16:09:37 -0700168 struct weston_data_offer *offer;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400169
Kristian Høgsberg5e76a492013-07-25 16:09:37 -0700170 offer = container_of(listener, struct weston_data_offer,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400171 source_destroy_listener);
172
173 offer->source = NULL;
174}
175
176static struct wl_resource *
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700177weston_data_source_send_offer(struct weston_data_source *source,
178 struct wl_resource *target)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400179{
Kristian Høgsberg5e76a492013-07-25 16:09:37 -0700180 struct weston_data_offer *offer;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400181 char **p;
182
183 offer = malloc(sizeof *offer);
184 if (offer == NULL)
185 return NULL;
186
Jason Ekstranda85118c2013-06-27 20:17:02 -0500187 offer->resource =
188 wl_resource_create(wl_resource_get_client(target),
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100189 &wl_data_offer_interface,
190 wl_resource_get_version(target), 0);
Kristian Høgsberg3c30f0f2013-08-06 10:24:04 -0700191 if (offer->resource == NULL) {
192 free(offer);
193 return NULL;
194 }
195
Jason Ekstranda85118c2013-06-27 20:17:02 -0500196 wl_resource_set_implementation(offer->resource, &data_offer_interface,
197 offer, destroy_data_offer);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400198
199 offer->source = source;
200 offer->source_destroy_listener.notify = destroy_offer_data_source;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500201 wl_signal_add(&source->destroy_signal,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400202 &offer->source_destroy_listener);
203
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500204 wl_data_device_send_data_offer(target, offer->resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400205
206 wl_array_for_each(p, &source->mime_types)
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500207 wl_data_offer_send_offer(offer->resource, *p);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400208
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100209 source->offer = offer;
210 source->accepted = false;
211
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500212 return offer->resource;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400213}
214
215static void
216data_source_offer(struct wl_client *client,
217 struct wl_resource *resource,
218 const char *type)
219{
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700220 struct weston_data_source *source =
221 wl_resource_get_user_data(resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400222 char **p;
223
224 p = wl_array_add(&source->mime_types, sizeof *p);
225 if (p)
226 *p = strdup(type);
227 if (!p || !*p)
228 wl_resource_post_no_memory(resource);
229}
230
231static void
232data_source_destroy(struct wl_client *client, struct wl_resource *resource)
233{
234 wl_resource_destroy(resource);
235}
236
237static struct wl_data_source_interface data_source_interface = {
238 data_source_offer,
239 data_source_destroy
240};
241
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400242static void
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800243drag_surface_configure(struct weston_drag *drag,
Jonas Ådahl767d8912013-12-03 22:30:17 +0100244 struct weston_pointer *pointer,
245 struct weston_touch *touch,
246 struct weston_surface *es,
247 int32_t sx, int32_t sy)
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400248{
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300249 struct weston_layer_entry *list;
Kristian Høgsbergaad80992013-05-07 22:53:43 -0400250 float fx, fy;
Kristian Høgsberg415f30c2013-05-07 22:42:28 -0400251
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800252 assert((pointer != NULL && touch == NULL) ||
253 (pointer == NULL && touch != NULL));
Jason Ekstranda7af7042013-10-12 22:38:11 -0500254
Kristian Høgsberg415f30c2013-05-07 22:42:28 -0400255 if (!weston_surface_is_mapped(es) && es->buffer_ref.buffer) {
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800256 if (pointer && pointer->sprite &&
257 weston_view_is_mapped(pointer->sprite))
Kristian Høgsberg195b8692013-05-08 15:02:05 -0400258 list = &pointer->sprite->layer_link;
Kristian Høgsberg415f30c2013-05-07 22:42:28 -0400259 else
Jason Ekstranda7af7042013-10-12 22:38:11 -0500260 list = &es->compositor->cursor_layer.view_list;
Kristian Høgsberg415f30c2013-05-07 22:42:28 -0400261
Giulio Camuffo412e6a52014-07-09 22:12:56 +0300262 weston_layer_entry_remove(&drag->icon->layer_link);
263 weston_layer_entry_insert(list, &drag->icon->layer_link);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500264 weston_view_update_transform(drag->icon);
Jason Ekstrandef540082014-06-26 10:37:36 -0700265 pixman_region32_clear(&es->pending.input);
Kristian Høgsberg415f30c2013-05-07 22:42:28 -0400266 }
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400267
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400268 drag->dx += sx;
269 drag->dy += sy;
Kristian Høgsbergaad80992013-05-07 22:53:43 -0400270
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800271 /* init to 0 for avoiding a compile warning */
272 fx = fy = 0;
273 if (pointer) {
274 fx = wl_fixed_to_double(pointer->x) + drag->dx;
275 fy = wl_fixed_to_double(pointer->y) + drag->dy;
276 } else if (touch) {
277 fx = wl_fixed_to_double(touch->grab_x) + drag->dx;
278 fy = wl_fixed_to_double(touch->grab_y) + drag->dy;
279 }
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600280 weston_view_set_position(drag->icon, fx, fy);
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400281}
282
Pekka Paalanen8274d902014-08-06 19:36:51 +0300283static int
284pointer_drag_surface_get_label(struct weston_surface *surface,
285 char *buf, size_t len)
286{
287 return snprintf(buf, len, "pointer drag icon");
288}
289
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400290static void
Jonas Ådahl767d8912013-12-03 22:30:17 +0100291pointer_drag_surface_configure(struct weston_surface *es,
292 int32_t sx, int32_t sy)
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800293{
294 struct weston_pointer_drag *drag = es->configure_private;
295 struct weston_pointer *pointer = drag->grab.pointer;
296
297 assert(es->configure == pointer_drag_surface_configure);
298
Jonas Ådahl767d8912013-12-03 22:30:17 +0100299 drag_surface_configure(&drag->base, pointer, NULL, es, sx, sy);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800300}
301
Pekka Paalanen8274d902014-08-06 19:36:51 +0300302static int
303touch_drag_surface_get_label(struct weston_surface *surface,
304 char *buf, size_t len)
305{
306 return snprintf(buf, len, "touch drag icon");
307}
308
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800309static void
Jonas Ådahl767d8912013-12-03 22:30:17 +0100310touch_drag_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800311{
312 struct weston_touch_drag *drag = es->configure_private;
313 struct weston_touch *touch = drag->grab.touch;
314
315 assert(es->configure == touch_drag_surface_configure);
316
Jonas Ådahl767d8912013-12-03 22:30:17 +0100317 drag_surface_configure(&drag->base, NULL, touch, es, sx, sy);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800318}
319
320static void
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400321destroy_drag_focus(struct wl_listener *listener, void *data)
322{
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400323 struct weston_drag *drag =
324 container_of(listener, struct weston_drag, focus_listener);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400325
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400326 drag->focus_resource = NULL;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400327}
328
329static void
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800330weston_drag_set_focus(struct weston_drag *drag,
331 struct weston_seat *seat,
332 struct weston_view *view,
333 wl_fixed_t sx, wl_fixed_t sy)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400334{
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100335 struct wl_resource *resource, *offer_resource = NULL;
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800336 struct wl_display *display = seat->compositor->wl_display;
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100337 struct weston_data_offer *offer;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400338 uint32_t serial;
339
Jason Ekstranda7af7042013-10-12 22:38:11 -0500340 if (drag->focus && view && drag->focus->surface == view->surface) {
341 drag->focus = view;
342 return;
343 }
344
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400345 if (drag->focus_resource) {
346 wl_data_device_send_leave(drag->focus_resource);
347 wl_list_remove(&drag->focus_listener.link);
348 drag->focus_resource = NULL;
349 drag->focus = NULL;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400350 }
351
Jason Ekstranda7af7042013-10-12 22:38:11 -0500352 if (!view || !view->surface->resource)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400353 return;
354
Jason Ekstrand26ed73c2013-06-06 22:34:41 -0500355 if (!drag->data_source &&
Jason Ekstranda7af7042013-10-12 22:38:11 -0500356 wl_resource_get_client(view->surface->resource) != drag->client)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400357 return;
358
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100359 if (drag->data_source &&
360 drag->data_source->offer) {
361 /* Unlink the offer from the source */
362 offer = drag->data_source->offer;
363 offer->source = NULL;
364 drag->data_source->offer = NULL;
365 wl_list_remove(&offer->source_destroy_listener.link);
366 }
367
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800368 resource = wl_resource_find_for_client(&seat->drag_resource_list,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500369 wl_resource_get_client(view->surface->resource));
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400370 if (!resource)
371 return;
372
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400373 serial = wl_display_next_serial(display);
374
Kristian Høgsberga34e2f22013-08-20 15:58:25 -0700375 if (drag->data_source) {
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100376 drag->data_source->accepted = false;
377 offer_resource = weston_data_source_send_offer(drag->data_source,
378 resource);
379 if (offer_resource == NULL)
Kristian Høgsberga34e2f22013-08-20 15:58:25 -0700380 return;
381 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400382
Jason Ekstranda7af7042013-10-12 22:38:11 -0500383 wl_data_device_send_enter(resource, serial, view->surface->resource,
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100384 sx, sy, offer_resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400385
Jason Ekstranda7af7042013-10-12 22:38:11 -0500386 drag->focus = view;
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400387 drag->focus_listener.notify = destroy_drag_focus;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500388 wl_resource_add_destroy_listener(resource, &drag->focus_listener);
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400389 drag->focus_resource = resource;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400390}
391
392static void
Kristian Høgsberg6848c252013-05-08 22:02:59 -0400393drag_grab_focus(struct weston_pointer_grab *grab)
394{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800395 struct weston_pointer_drag *drag =
396 container_of(grab, struct weston_pointer_drag, grab);
Kristian Høgsberg6848c252013-05-08 22:02:59 -0400397 struct weston_pointer *pointer = grab->pointer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500398 struct weston_view *view;
Kristian Høgsberg6848c252013-05-08 22:02:59 -0400399 wl_fixed_t sx, sy;
400
Jason Ekstranda7af7042013-10-12 22:38:11 -0500401 view = weston_compositor_pick_view(pointer->seat->compositor,
402 pointer->x, pointer->y,
403 &sx, &sy);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800404 if (drag->base.focus != view)
405 weston_drag_set_focus(&drag->base, pointer->seat, view, sx, sy);
Kristian Høgsberg6848c252013-05-08 22:02:59 -0400406}
407
408static void
Giulio Camuffo1959ab82013-11-14 23:42:52 +0100409drag_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
Jonas Ådahld2510102014-10-05 21:39:14 +0200410 struct weston_pointer_motion_event *event)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400411{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800412 struct weston_pointer_drag *drag =
413 container_of(grab, struct weston_pointer_drag, grab);
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400414 struct weston_pointer *pointer = drag->grab.pointer;
Kristian Høgsbergaad80992013-05-07 22:53:43 -0400415 float fx, fy;
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -0400416 wl_fixed_t sx, sy;
Kristian Høgsbergaad80992013-05-07 22:53:43 -0400417
Jonas Ådahld2510102014-10-05 21:39:14 +0200418 weston_pointer_move(pointer, event);
Giulio Camuffo1959ab82013-11-14 23:42:52 +0100419
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800420 if (drag->base.icon) {
421 fx = wl_fixed_to_double(pointer->x) + drag->base.dx;
422 fy = wl_fixed_to_double(pointer->y) + drag->base.dy;
423 weston_view_set_position(drag->base.icon, fx, fy);
424 weston_view_schedule_repaint(drag->base.icon);
Kristian Høgsbergaad80992013-05-07 22:53:43 -0400425 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400426
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800427 if (drag->base.focus_resource) {
428 weston_view_from_global_fixed(drag->base.focus,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500429 pointer->x, pointer->y,
430 &sx, &sy);
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -0400431
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800432 wl_data_device_send_motion(drag->base.focus_resource, time, sx, sy);
Kristian Høgsbergbe6403e2013-05-08 21:03:21 -0400433 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400434}
435
436static void
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800437data_device_end_drag_grab(struct weston_drag *drag,
438 struct weston_seat *seat)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400439{
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400440 if (drag->icon) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500441 if (weston_view_is_mapped(drag->icon))
442 weston_view_unmap(drag->icon);
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400443
Jason Ekstranda7af7042013-10-12 22:38:11 -0500444 drag->icon->surface->configure = NULL;
Pekka Paalanen8274d902014-08-06 19:36:51 +0300445 weston_surface_set_label_func(drag->icon->surface, NULL);
Jason Ekstrandef540082014-06-26 10:37:36 -0700446 pixman_region32_clear(&drag->icon->surface->pending.input);
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400447 wl_list_remove(&drag->icon_destroy_listener.link);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500448 weston_view_destroy(drag->icon);
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400449 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400450
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800451 weston_drag_set_focus(drag, seat, NULL, 0, 0);
452}
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400453
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800454static void
455data_device_end_pointer_drag_grab(struct weston_pointer_drag *drag)
456{
457 struct weston_pointer *pointer = drag->grab.pointer;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400458
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800459 data_device_end_drag_grab(&drag->base, pointer->seat);
460 weston_pointer_end_grab(pointer);
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400461 free(drag);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400462}
463
464static void
Kristian Høgsberg02bbabb2013-05-06 22:15:05 -0400465drag_grab_button(struct weston_pointer_grab *grab,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400466 uint32_t time, uint32_t button, uint32_t state_w)
467{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800468 struct weston_pointer_drag *drag =
469 container_of(grab, struct weston_pointer_drag, grab);
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400470 struct weston_pointer *pointer = drag->grab.pointer;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400471 enum wl_pointer_button_state state = state_w;
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100472 struct weston_data_source *data_source = drag->base.data_source;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400473
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100474 if (data_source &&
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400475 pointer->grab_button == button &&
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100476 state == WL_POINTER_BUTTON_STATE_RELEASED) {
477 if (drag->base.focus_resource &&
478 data_source->accepted) {
479 wl_data_device_send_drop(drag->base.focus_resource);
480
481 if (wl_resource_get_version(data_source->resource) >=
482 WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
483 wl_data_source_send_dnd_drop_performed(data_source->resource);
484
485 data_source->seat = NULL;
486 } else if (wl_resource_get_version(data_source->resource) >=
487 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
488 wl_data_source_send_cancelled(data_source->resource);
489 }
490 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400491
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400492 if (pointer->button_count == 0 &&
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400493 state == WL_POINTER_BUTTON_STATE_RELEASED) {
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800494 if (drag->base.data_source)
495 wl_list_remove(&drag->base.data_source_listener.link);
496 data_device_end_pointer_drag_grab(drag);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400497 }
498}
499
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200500static void
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200501drag_grab_axis(struct weston_pointer_grab *grab,
Peter Hutterer89b6a492016-01-18 15:58:17 +1000502 uint32_t time, struct weston_pointer_axis_event *event)
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200503{
504}
505
506static void
Peter Hutterer87743e92016-01-18 16:38:22 +1000507drag_grab_axis_source(struct weston_pointer_grab *grab, uint32_t source)
508{
509}
510
511static void
512drag_grab_frame(struct weston_pointer_grab *grab)
513{
514}
515
516static void
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200517drag_grab_cancel(struct weston_pointer_grab *grab)
518{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800519 struct weston_pointer_drag *drag =
520 container_of(grab, struct weston_pointer_drag, grab);
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200521
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800522 if (drag->base.data_source)
523 wl_list_remove(&drag->base.data_source_listener.link);
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200524
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800525 data_device_end_pointer_drag_grab(drag);
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200526}
527
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800528static const struct weston_pointer_grab_interface pointer_drag_grab_interface = {
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400529 drag_grab_focus,
530 drag_grab_motion,
531 drag_grab_button,
Jonas Ådahl0336ca02014-10-04 16:28:29 +0200532 drag_grab_axis,
Peter Hutterer87743e92016-01-18 16:38:22 +1000533 drag_grab_axis_source,
534 drag_grab_frame,
Jonas Ådahl1ea343e2013-10-25 23:18:05 +0200535 drag_grab_cancel,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400536};
537
538static void
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800539drag_grab_touch_down(struct weston_touch_grab *grab, uint32_t time,
540 int touch_id, wl_fixed_t sx, wl_fixed_t sy)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400541{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800542}
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400543
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800544static void
545data_device_end_touch_drag_grab(struct weston_touch_drag *drag)
546{
547 struct weston_touch *touch = drag->grab.touch;
548
549 data_device_end_drag_grab(&drag->base, touch->seat);
550 weston_touch_end_grab(touch);
551 free(drag);
552}
553
554static void
555drag_grab_touch_up(struct weston_touch_grab *grab,
556 uint32_t time, int touch_id)
557{
558 struct weston_touch_drag *touch_drag =
559 container_of(grab, struct weston_touch_drag, grab);
560 struct weston_touch *touch = grab->touch;
561
562 if (touch_id != touch->grab_touch_id)
563 return;
564
565 if (touch_drag->base.focus_resource)
566 wl_data_device_send_drop(touch_drag->base.focus_resource);
567 if (touch_drag->base.data_source)
568 wl_list_remove(&touch_drag->base.data_source_listener.link);
569 data_device_end_touch_drag_grab(touch_drag);
570}
571
572static void
573drag_grab_touch_focus(struct weston_touch_drag *drag)
574{
575 struct weston_touch *touch = drag->grab.touch;
576 struct weston_view *view;
577 wl_fixed_t view_x, view_y;
578
579 view = weston_compositor_pick_view(touch->seat->compositor,
580 touch->grab_x, touch->grab_y,
581 &view_x, &view_y);
582 if (drag->base.focus != view)
583 weston_drag_set_focus(&drag->base, touch->seat,
584 view, view_x, view_y);
585}
586
587static void
588drag_grab_touch_motion(struct weston_touch_grab *grab, uint32_t time,
Giulio Camuffo61ed7b62015-07-08 11:55:28 +0300589 int touch_id, wl_fixed_t x, wl_fixed_t y)
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800590{
591 struct weston_touch_drag *touch_drag =
592 container_of(grab, struct weston_touch_drag, grab);
593 struct weston_touch *touch = grab->touch;
594 wl_fixed_t view_x, view_y;
595 float fx, fy;
596
597 if (touch_id != touch->grab_touch_id)
598 return;
599
600 drag_grab_touch_focus(touch_drag);
601 if (touch_drag->base.icon) {
602 fx = wl_fixed_to_double(touch->grab_x) + touch_drag->base.dx;
603 fy = wl_fixed_to_double(touch->grab_y) + touch_drag->base.dy;
604 weston_view_set_position(touch_drag->base.icon, fx, fy);
605 weston_view_schedule_repaint(touch_drag->base.icon);
606 }
607
608 if (touch_drag->base.focus_resource) {
609 weston_view_from_global_fixed(touch_drag->base.focus,
610 touch->grab_x, touch->grab_y,
611 &view_x, &view_y);
612 wl_data_device_send_motion(touch_drag->base.focus_resource, time,
613 view_x, view_y);
614 }
615}
616
617static void
Jonas Ådahl1679f232014-04-12 09:39:51 +0200618drag_grab_touch_frame(struct weston_touch_grab *grab)
619{
620}
621
622static void
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800623drag_grab_touch_cancel(struct weston_touch_grab *grab)
624{
625 struct weston_touch_drag *touch_drag =
626 container_of(grab, struct weston_touch_drag, grab);
627
628 if (touch_drag->base.data_source)
629 wl_list_remove(&touch_drag->base.data_source_listener.link);
630 data_device_end_touch_drag_grab(touch_drag);
631}
632
633static const struct weston_touch_grab_interface touch_drag_grab_interface = {
634 drag_grab_touch_down,
635 drag_grab_touch_up,
636 drag_grab_touch_motion,
Jonas Ådahl1679f232014-04-12 09:39:51 +0200637 drag_grab_touch_frame,
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800638 drag_grab_touch_cancel
639};
640
641static void
642destroy_pointer_data_device_source(struct wl_listener *listener, void *data)
643{
644 struct weston_pointer_drag *drag = container_of(listener,
645 struct weston_pointer_drag, base.data_source_listener);
646
647 data_device_end_pointer_drag_grab(drag);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400648}
649
650static void
Kristian Høgsbergc43aad12013-05-08 15:30:42 -0400651handle_drag_icon_destroy(struct wl_listener *listener, void *data)
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400652{
Kristian Høgsberg054c50a2013-05-08 15:27:47 -0400653 struct weston_drag *drag = container_of(listener, struct weston_drag,
Kristian Høgsbergc43aad12013-05-08 15:30:42 -0400654 icon_destroy_listener);
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400655
Kristian Høgsbergc43aad12013-05-08 15:30:42 -0400656 drag->icon = NULL;
Kristian Høgsberg7848bb62013-05-07 11:18:46 -0400657}
658
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700659WL_EXPORT int
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800660weston_pointer_start_drag(struct weston_pointer *pointer,
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700661 struct weston_data_source *source,
662 struct weston_surface *icon,
663 struct wl_client *client)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400664{
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800665 struct weston_pointer_drag *drag;
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400666
Peter Huttererf3d62272013-08-08 11:57:05 +1000667 drag = zalloc(sizeof *drag);
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700668 if (drag == NULL)
669 return -1;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400670
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800671 drag->grab.interface = &pointer_drag_grab_interface;
672 drag->base.client = client;
673 drag->base.data_source = source;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400674
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400675 if (icon) {
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800676 drag->base.icon = weston_view_create(icon);
677 if (drag->base.icon == NULL) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500678 free(drag);
679 return -1;
680 }
681
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800682 drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
Jason Ekstrand26ed73c2013-06-06 22:34:41 -0500683 wl_signal_add(&icon->destroy_signal,
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800684 &drag->base.icon_destroy_listener);
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400685
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800686 icon->configure = pointer_drag_surface_configure;
Kristian Høgsberg5a9fb352013-05-08 15:47:52 -0400687 icon->configure_private = drag;
Pekka Paalanen8274d902014-08-06 19:36:51 +0300688 weston_surface_set_label_func(icon,
689 pointer_drag_surface_get_label);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500690 } else {
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800691 drag->base.icon = NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500692 }
693
694 if (source) {
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800695 drag->base.data_source_listener.notify = destroy_pointer_data_device_source;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500696 wl_signal_add(&source->destroy_signal,
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800697 &drag->base.data_source_listener);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400698 }
699
Derek Foremanf9318d12015-05-11 15:40:11 -0500700 weston_pointer_clear_focus(pointer);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800701 weston_pointer_start_grab(pointer, &drag->grab);
702
703 return 0;
704}
705
706static void
707destroy_touch_data_device_source(struct wl_listener *listener, void *data)
708{
709 struct weston_touch_drag *drag = container_of(listener,
710 struct weston_touch_drag, base.data_source_listener);
711
712 data_device_end_touch_drag_grab(drag);
713}
714
715WL_EXPORT int
716weston_touch_start_drag(struct weston_touch *touch,
717 struct weston_data_source *source,
718 struct weston_surface *icon,
719 struct wl_client *client)
720{
721 struct weston_touch_drag *drag;
722
723 drag = zalloc(sizeof *drag);
724 if (drag == NULL)
725 return -1;
726
727 drag->grab.interface = &touch_drag_grab_interface;
728 drag->base.client = client;
729 drag->base.data_source = source;
730
731 if (icon) {
732 drag->base.icon = weston_view_create(icon);
733 if (drag->base.icon == NULL) {
734 free(drag);
735 return -1;
736 }
737
738 drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
739 wl_signal_add(&icon->destroy_signal,
740 &drag->base.icon_destroy_listener);
741
742 icon->configure = touch_drag_surface_configure;
743 icon->configure_private = drag;
Pekka Paalanen8274d902014-08-06 19:36:51 +0300744 weston_surface_set_label_func(icon,
745 touch_drag_surface_get_label);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800746 } else {
747 drag->base.icon = NULL;
748 }
749
750 if (source) {
751 drag->base.data_source_listener.notify = destroy_touch_data_device_source;
752 wl_signal_add(&source->destroy_signal,
753 &drag->base.data_source_listener);
754 }
755
756 weston_touch_start_grab(touch, &drag->grab);
757
758 drag_grab_touch_focus(drag);
Kristian Høgsberg0abad072013-09-11 09:42:26 -0700759
760 return 0;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400761}
762
763static void
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700764data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
765 struct wl_resource *source_resource,
766 struct wl_resource *origin_resource,
767 struct wl_resource *icon_resource, uint32_t serial)
768{
769 struct weston_seat *seat = wl_resource_get_user_data(resource);
Derek Foreman1281a362015-07-31 16:55:32 -0500770 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
771 struct weston_touch *touch = weston_seat_get_touch(seat);
Jason Ekstrand8202d722014-06-24 21:19:24 -0700772 struct weston_surface *origin = wl_resource_get_user_data(origin_resource);
Kristian Høgsberg1702d4c2013-09-11 09:45:03 -0700773 struct weston_data_source *source = NULL;
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700774 struct weston_surface *icon = NULL;
Jason Ekstrand8202d722014-06-24 21:19:24 -0700775 int is_pointer_grab, is_touch_grab;
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800776 int32_t ret = 0;
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700777
Derek Foreman1281a362015-07-31 16:55:32 -0500778 is_pointer_grab = pointer &&
779 pointer->button_count == 1 &&
780 pointer->grab_serial == serial &&
781 pointer->focus &&
782 pointer->focus->surface == origin;
Jason Ekstrand8202d722014-06-24 21:19:24 -0700783
Derek Foreman1281a362015-07-31 16:55:32 -0500784 is_touch_grab = touch &&
785 touch->num_tp == 1 &&
786 touch->grab_serial == serial &&
787 touch->focus &&
788 touch->focus->surface == origin;
Jason Ekstrand8202d722014-06-24 21:19:24 -0700789
790 if (!is_pointer_grab && !is_touch_grab)
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700791 return;
792
793 /* FIXME: Check that the data source type array isn't empty. */
794
795 if (source_resource)
796 source = wl_resource_get_user_data(source_resource);
797 if (icon_resource)
798 icon = wl_resource_get_user_data(icon_resource);
Pekka Paalanen50b67472014-10-01 15:02:41 +0300799
800 if (icon) {
801 if (weston_surface_set_role(icon, "wl_data_device-icon",
802 resource,
803 WL_DATA_DEVICE_ERROR_ROLE) < 0)
804 return;
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700805 }
806
Jason Ekstrand8202d722014-06-24 21:19:24 -0700807 if (is_pointer_grab)
Derek Foreman1281a362015-07-31 16:55:32 -0500808 ret = weston_pointer_start_drag(pointer, source, icon, client);
Jason Ekstrand8202d722014-06-24 21:19:24 -0700809 else if (is_touch_grab)
Derek Foreman1281a362015-07-31 16:55:32 -0500810 ret = weston_touch_start_drag(touch, source, icon, client);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800811
812 if (ret < 0)
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700813 wl_resource_post_no_memory(resource);
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100814 else
815 source->seat = seat;
Kristian Høgsberg85de9c22013-09-04 20:44:26 -0700816}
817
818static void
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400819destroy_selection_data_source(struct wl_listener *listener, void *data)
820{
Kristian Høgsberge3148752013-05-06 23:19:49 -0400821 struct weston_seat *seat = container_of(listener, struct weston_seat,
822 selection_data_source_listener);
Derek Foreman1281a362015-07-31 16:55:32 -0500823 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400824 struct wl_resource *data_device;
Neil Roberts96d790e2013-09-19 17:32:00 +0100825 struct weston_surface *focus = NULL;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400826
827 seat->selection_data_source = NULL;
828
Derek Foreman1281a362015-07-31 16:55:32 -0500829 if (keyboard)
830 focus = keyboard->focus;
Neil Roberts96d790e2013-09-19 17:32:00 +0100831 if (focus && focus->resource) {
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500832 data_device = wl_resource_find_for_client(&seat->drag_resource_list,
Neil Roberts96d790e2013-09-19 17:32:00 +0100833 wl_resource_get_client(focus->resource));
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400834 if (data_device)
835 wl_data_device_send_selection(data_device, NULL);
836 }
837
838 wl_signal_emit(&seat->selection_signal, seat);
839}
840
Giulio Camuffodddf9e62015-05-01 12:59:35 +0300841/** \brief Send the selection to the specified client
842 *
843 * This function creates a new wl_data_offer if there is a wl_data_source
844 * currently set as the selection and sends it to the specified client,
845 * followed by the wl_data_device.selection() event.
846 * If there is no current selection the wl_data_device.selection() event
847 * will carry a NULL wl_data_offer.
848 *
849 * If the client does not have a wl_data_device for the specified seat
850 * nothing will be done.
851 *
852 * \param seat The seat owning the wl_data_device used to send the events.
853 * \param client The client to which to send the selection.
854 */
855WL_EXPORT void
856weston_seat_send_selection(struct weston_seat *seat, struct wl_client *client)
857{
858 struct wl_resource *data_device, *offer;
859
Giulio Camuffod46bb012015-05-01 12:59:36 +0300860 wl_resource_for_each(data_device, &seat->drag_resource_list) {
861 if (wl_resource_get_client(data_device) != client)
862 continue;
863
864 if (seat->selection_data_source) {
865 offer = weston_data_source_send_offer(seat->selection_data_source,
866 data_device);
867 wl_data_device_send_selection(data_device, offer);
868 } else {
869 wl_data_device_send_selection(data_device, NULL);
870 }
Giulio Camuffodddf9e62015-05-01 12:59:35 +0300871 }
872}
873
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400874WL_EXPORT void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400875weston_seat_set_selection(struct weston_seat *seat,
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700876 struct weston_data_source *source, uint32_t serial)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400877{
Neil Roberts96d790e2013-09-19 17:32:00 +0100878 struct weston_surface *focus = NULL;
Derek Foreman1281a362015-07-31 16:55:32 -0500879 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400880
881 if (seat->selection_data_source &&
882 seat->selection_serial - serial < UINT32_MAX / 2)
883 return;
884
885 if (seat->selection_data_source) {
886 seat->selection_data_source->cancel(seat->selection_data_source);
887 wl_list_remove(&seat->selection_data_source_listener.link);
888 seat->selection_data_source = NULL;
889 }
890
891 seat->selection_data_source = source;
892 seat->selection_serial = serial;
893
Derek Foreman1281a362015-07-31 16:55:32 -0500894 if (keyboard)
895 focus = keyboard->focus;
Neil Roberts96d790e2013-09-19 17:32:00 +0100896 if (focus && focus->resource) {
Giulio Camuffodddf9e62015-05-01 12:59:35 +0300897 weston_seat_send_selection(seat, wl_resource_get_client(focus->resource));
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400898 }
899
900 wl_signal_emit(&seat->selection_signal, seat);
901
902 if (source) {
903 seat->selection_data_source_listener.notify =
904 destroy_selection_data_source;
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500905 wl_signal_add(&source->destroy_signal,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400906 &seat->selection_data_source_listener);
907 }
908}
909
910static void
911data_device_set_selection(struct wl_client *client,
912 struct wl_resource *resource,
913 struct wl_resource *source_resource, uint32_t serial)
914{
915 if (!source_resource)
916 return;
917
918 /* FIXME: Store serial and check against incoming serial here. */
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500919 weston_seat_set_selection(wl_resource_get_user_data(resource),
920 wl_resource_get_user_data(source_resource),
Kristian Høgsberge3148752013-05-06 23:19:49 -0400921 serial);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400922}
kabeer khan3a510d82014-10-20 11:47:15 +0530923static void
924data_device_release(struct wl_client *client, struct wl_resource *resource)
925{
926 wl_resource_destroy(resource);
927}
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400928
929static const struct wl_data_device_interface data_device_interface = {
930 data_device_start_drag,
931 data_device_set_selection,
kabeer khan3a510d82014-10-20 11:47:15 +0530932 data_device_release
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400933};
934
935static void
936destroy_data_source(struct wl_resource *resource)
937{
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700938 struct weston_data_source *source =
939 wl_resource_get_user_data(resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400940 char **p;
941
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500942 wl_signal_emit(&source->destroy_signal, source);
943
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400944 wl_array_for_each(p, &source->mime_types)
945 free(*p);
946
947 wl_array_release(&source->mime_types);
948
Kristian Høgsberg489b2792013-06-25 11:26:31 -0400949 free(source);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400950}
951
952static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700953client_source_accept(struct weston_data_source *source,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400954 uint32_t time, const char *mime_type)
955{
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500956 wl_data_source_send_target(source->resource, mime_type);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400957}
958
959static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700960client_source_send(struct weston_data_source *source,
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400961 const char *mime_type, int32_t fd)
962{
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500963 wl_data_source_send_send(source->resource, mime_type, fd);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400964 close(fd);
965}
966
967static void
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700968client_source_cancel(struct weston_data_source *source)
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400969{
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500970 wl_data_source_send_cancelled(source->resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400971}
972
973static void
974create_data_source(struct wl_client *client,
975 struct wl_resource *resource, uint32_t id)
976{
Kristian Høgsberg7ff3bdb2013-07-25 15:52:14 -0700977 struct weston_data_source *source;
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400978
979 source = malloc(sizeof *source);
980 if (source == NULL) {
981 wl_resource_post_no_memory(resource);
982 return;
983 }
984
cpaul@redhat.comc9f8f8a2016-01-05 11:18:30 -0500985 source->resource =
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100986 wl_resource_create(client, &wl_data_source_interface,
987 wl_resource_get_version(resource), id);
cpaul@redhat.comc9f8f8a2016-01-05 11:18:30 -0500988 if (source->resource == NULL) {
989 free(source);
990 wl_resource_post_no_memory(resource);
991 return;
992 }
993
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -0500994 wl_signal_init(&source->destroy_signal);
Kristian Høgsberg2158a882013-04-18 15:07:39 -0400995 source->accept = client_source_accept;
996 source->send = client_source_send;
997 source->cancel = client_source_cancel;
Carlos Garnacho78d4bf92016-01-15 21:14:23 +0100998 source->offer = NULL;
999 source->accepted = false;
1000 source->seat = NULL;
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001001
1002 wl_array_init(&source->mime_types);
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -05001003
Jason Ekstranda85118c2013-06-27 20:17:02 -05001004 wl_resource_set_implementation(source->resource, &data_source_interface,
1005 source, destroy_data_source);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001006}
1007
1008static void unbind_data_device(struct wl_resource *resource)
1009{
Jason Ekstrand8a4a9eb2013-06-14 10:07:55 -05001010 wl_list_remove(wl_resource_get_link(resource));
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001011}
1012
1013static void
1014get_data_device(struct wl_client *client,
1015 struct wl_resource *manager_resource,
1016 uint32_t id, struct wl_resource *seat_resource)
1017{
Jason Ekstranda0d2dde2013-06-14 10:08:01 -05001018 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001019 struct wl_resource *resource;
1020
Jason Ekstranda85118c2013-06-27 20:17:02 -05001021 resource = wl_resource_create(client,
kabeer khan3a510d82014-10-20 11:47:15 +05301022 &wl_data_device_interface,
1023 wl_resource_get_version(manager_resource),
1024 id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07001025 if (resource == NULL) {
1026 wl_resource_post_no_memory(manager_resource);
1027 return;
1028 }
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001029
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07001030 wl_list_insert(&seat->drag_resource_list,
1031 wl_resource_get_link(resource));
Jason Ekstranda85118c2013-06-27 20:17:02 -05001032 wl_resource_set_implementation(resource, &data_device_interface,
1033 seat, unbind_data_device);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001034}
1035
1036static const struct wl_data_device_manager_interface manager_interface = {
1037 create_data_source,
1038 get_data_device
1039};
1040
1041static void
1042bind_manager(struct wl_client *client,
1043 void *data, uint32_t version, uint32_t id)
1044{
Jason Ekstranda85118c2013-06-27 20:17:02 -05001045 struct wl_resource *resource;
1046
kabeer khan3a510d82014-10-20 11:47:15 +05301047 resource = wl_resource_create(client,
1048 &wl_data_device_manager_interface,
1049 version, id);
Kristian Høgsberg0ff79082013-08-06 16:46:25 -07001050 if (resource == NULL) {
1051 wl_client_post_no_memory(client);
1052 return;
1053 }
1054
1055 wl_resource_set_implementation(resource, &manager_interface,
1056 NULL, NULL);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001057}
1058
1059WL_EXPORT void
Kristian Høgsberge3148752013-05-06 23:19:49 -04001060wl_data_device_set_keyboard_focus(struct weston_seat *seat)
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001061{
Neil Roberts96d790e2013-09-19 17:32:00 +01001062 struct weston_surface *focus;
Derek Foreman1281a362015-07-31 16:55:32 -05001063 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001064
Derek Foreman1281a362015-07-31 16:55:32 -05001065 if (!keyboard)
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001066 return;
1067
Derek Foreman1281a362015-07-31 16:55:32 -05001068 focus = keyboard->focus;
Neil Roberts96d790e2013-09-19 17:32:00 +01001069 if (!focus || !focus->resource)
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001070 return;
1071
Giulio Camuffodddf9e62015-05-01 12:59:35 +03001072 weston_seat_send_selection(seat, wl_resource_get_client(focus->resource));
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001073}
1074
1075WL_EXPORT int
1076wl_data_device_manager_init(struct wl_display *display)
1077{
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04001078 if (wl_global_create(display,
Carlos Garnacho78d4bf92016-01-15 21:14:23 +01001079 &wl_data_device_manager_interface, 3,
Kristian Høgsberg919cddb2013-07-08 19:03:57 -04001080 NULL, bind_manager) == NULL)
Kristian Høgsberg2158a882013-04-18 15:07:39 -04001081 return -1;
1082
1083 return 0;
1084}