363a90d95693dfad4784293cb98a7e3dc7a64568
[profile/ivi/wayland.git] / src / data-device.c
1 /*
2  * Copyright © 2011 Kristian Høgsberg
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <stdio.h>
27
28 #include "wayland-server.h"
29
30 static void
31 data_offer_accept(struct wl_client *client, struct wl_resource *resource,
32                   uint32_t serial, const char *mime_type)
33 {
34         struct wl_data_offer *offer = resource->data;
35
36         /* FIXME: Check that client is currently focused by the input
37          * device that is currently dragging this data source.  Should
38          * this be a wl_data_device request? */
39
40         if (offer->source)
41                 offer->source->accept(offer->source, serial, mime_type);
42 }
43
44 static void
45 data_offer_receive(struct wl_client *client, struct wl_resource *resource,
46                    const char *mime_type, int32_t fd)
47 {
48         struct wl_data_offer *offer = resource->data;
49
50         if (offer->source)
51                 offer->source->send(offer->source, mime_type, fd);
52         else
53                 close(fd);
54 }
55
56 static void
57 data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
58 {
59         wl_resource_destroy(resource);
60 }
61
62 static const struct wl_data_offer_interface data_offer_interface = {
63         data_offer_accept,
64         data_offer_receive,
65         data_offer_destroy,
66 };
67
68 static void
69 destroy_data_offer(struct wl_resource *resource)
70 {
71         struct wl_data_offer *offer = resource->data;
72
73         if (offer->source)
74                 wl_list_remove(&offer->source_destroy_listener.link);
75         free(offer);
76 }
77
78 static void
79 destroy_offer_data_source(struct wl_listener *listener, void *data)
80 {
81         struct wl_data_offer *offer;
82
83         offer = container_of(listener, struct wl_data_offer,
84                              source_destroy_listener);
85
86         offer->source = NULL;
87 }
88
89 static struct wl_resource *
90 wl_data_source_send_offer(struct wl_data_source *source,
91                           struct wl_resource *target)
92 {
93         struct wl_data_offer *offer;
94         char **p;
95
96         offer = malloc(sizeof *offer);
97         if (offer == NULL)
98                 return NULL;
99
100         offer->resource.destroy = destroy_data_offer;
101         offer->resource.object.id = 0;
102         offer->resource.object.interface = &wl_data_offer_interface;
103         offer->resource.object.implementation =
104                 (void (**)(void)) &data_offer_interface;
105         offer->resource.data = offer;
106         wl_signal_init(&offer->resource.destroy_signal);
107
108         offer->source = source;
109         offer->source_destroy_listener.notify = destroy_offer_data_source;
110         wl_signal_add(&source->resource.destroy_signal,
111                       &offer->source_destroy_listener);
112
113         wl_client_add_resource(target->client, &offer->resource);
114
115         wl_data_device_send_data_offer(target, &offer->resource);
116
117         wl_array_for_each(p, &source->mime_types)
118                 wl_data_offer_send_offer(&offer->resource, *p);
119
120         return &offer->resource;
121 }
122
123 static void
124 data_source_offer(struct wl_client *client,
125                   struct wl_resource *resource,
126                   const char *type)
127 {
128         struct wl_data_source *source = resource->data;
129         char **p;
130
131         p = wl_array_add(&source->mime_types, sizeof *p);
132         if (p)
133                 *p = strdup(type);
134         if (!p || !*p)
135                 wl_resource_post_no_memory(resource);
136 }
137
138 static void
139 data_source_destroy(struct wl_client *client, struct wl_resource *resource)
140 {
141         wl_resource_destroy(resource);
142 }
143
144 static struct wl_data_source_interface data_source_interface = {
145         data_source_offer,
146         data_source_destroy
147 };
148
149 static struct wl_resource *
150 find_resource(struct wl_list *list, struct wl_client *client)
151 {
152         struct wl_resource *r;
153
154         wl_list_for_each(r, list, link) {
155                 if (r->client == client)
156                         return r;
157         }
158
159         return NULL;
160 }
161
162 static void
163 destroy_drag_focus(struct wl_listener *listener, void *data)
164 {
165         struct wl_seat *seat =
166                 container_of(listener, struct wl_seat, drag_focus_listener);
167
168         seat->drag_focus_resource = NULL;
169 }
170
171 static void
172 drag_grab_focus(struct wl_pointer_grab *grab,
173                 struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
174 {
175         struct wl_seat *seat = container_of(grab, struct wl_seat, drag_grab);
176         struct wl_resource *resource, *offer = NULL;
177         struct wl_display *display;
178         uint32_t serial;
179
180         if (seat->drag_focus_resource) {
181                 wl_data_device_send_leave(seat->drag_focus_resource);
182                 wl_list_remove(&seat->drag_focus_listener.link);
183                 seat->drag_focus_resource = NULL;
184                 seat->drag_focus = NULL;
185         }
186
187         if (!surface)
188                 return;
189
190         if (!seat->drag_data_source &&
191             surface->resource.client != seat->drag_client)
192                 return;
193
194         resource = find_resource(&seat->drag_resource_list,
195                                  surface->resource.client);
196         if (!resource)
197                 return;
198
199         display = wl_client_get_display(resource->client);
200         serial = wl_display_next_serial(display);
201
202         if (seat->drag_data_source)
203                 offer = wl_data_source_send_offer(seat->drag_data_source,
204                                                   resource);
205
206         wl_data_device_send_enter(resource, serial, &surface->resource,
207                                   x, y, offer);
208
209         seat->drag_focus = surface;
210         seat->drag_focus_listener.notify = destroy_drag_focus;
211         wl_signal_add(&resource->destroy_signal,
212                       &seat->drag_focus_listener);
213         seat->drag_focus_resource = resource;
214         grab->focus = surface;
215 }
216
217 static void
218 drag_grab_motion(struct wl_pointer_grab *grab,
219                  uint32_t time, wl_fixed_t x, wl_fixed_t y)
220 {
221         struct wl_seat *seat = container_of(grab, struct wl_seat, drag_grab);
222
223         if (seat->drag_focus_resource)
224                 wl_data_device_send_motion(seat->drag_focus_resource,
225                                            time, x, y);
226 }
227
228 static void
229 data_device_end_drag_grab(struct wl_seat *seat)
230 {
231         if (seat->drag_surface) {
232                 seat->drag_surface = NULL;
233                 wl_signal_emit(&seat->drag_icon_signal, NULL);
234                 wl_list_remove(&seat->drag_icon_listener.link);
235         }
236
237         drag_grab_focus(&seat->drag_grab, NULL,
238                         wl_fixed_from_int(0), wl_fixed_from_int(0));
239
240         wl_pointer_end_grab(seat->pointer);
241
242         seat->drag_data_source = NULL;
243         seat->drag_client = NULL;
244 }
245
246 static void
247 drag_grab_button(struct wl_pointer_grab *grab,
248                  uint32_t time, uint32_t button, uint32_t state_w)
249 {
250         struct wl_seat *seat = container_of(grab, struct wl_seat, drag_grab);
251         enum wl_pointer_button_state state = state_w;
252
253         if (seat->drag_focus_resource &&
254             seat->pointer->grab_button == button &&
255             state == WL_POINTER_BUTTON_STATE_RELEASED)
256                 wl_data_device_send_drop(seat->drag_focus_resource);
257
258         if (seat->pointer->button_count == 0 &&
259             state == WL_POINTER_BUTTON_STATE_RELEASED) {
260                 if (seat->drag_data_source)
261                         wl_list_remove(&seat->drag_data_source_listener.link);
262                 data_device_end_drag_grab(seat);
263         }
264 }
265
266 static const struct wl_pointer_grab_interface drag_grab_interface = {
267         drag_grab_focus,
268         drag_grab_motion,
269         drag_grab_button,
270 };
271
272 static void
273 destroy_data_device_source(struct wl_listener *listener, void *data)
274 {
275         struct wl_seat *seat = container_of(listener, struct wl_seat,
276                                             drag_data_source_listener);
277
278         data_device_end_drag_grab(seat);
279 }
280
281 static void
282 destroy_data_device_icon(struct wl_listener *listener, void *data)
283 {
284         struct wl_seat *seat = container_of(listener, struct wl_seat,
285                                             drag_icon_listener);
286
287         seat->drag_surface = NULL;
288 }
289
290 static void
291 data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
292                        struct wl_resource *source_resource,
293                        struct wl_resource *origin_resource,
294                        struct wl_resource *icon_resource, uint32_t serial)
295 {
296         struct wl_seat *seat = resource->data;
297
298         /* FIXME: Check that client has implicit grab on the origin
299          * surface that matches the given time. */
300
301         /* FIXME: Check that the data source type array isn't empty. */
302
303         seat->drag_grab.interface = &drag_grab_interface;
304
305         seat->drag_client = client;
306         seat->drag_data_source = NULL;
307
308         if (source_resource) {
309                 seat->drag_data_source = source_resource->data;
310                 seat->drag_data_source_listener.notify =
311                         destroy_data_device_source;
312                 wl_signal_add(&source_resource->destroy_signal,
313                               &seat->drag_data_source_listener);
314         }
315
316         if (icon_resource) {
317                 seat->drag_surface = icon_resource->data;
318                 seat->drag_icon_listener.notify = destroy_data_device_icon;
319                 wl_signal_add(&icon_resource->destroy_signal,
320                               &seat->drag_icon_listener);
321                 wl_signal_emit(&seat->drag_icon_signal, icon_resource);
322         }
323
324         wl_pointer_set_focus(seat->pointer, NULL,
325                              wl_fixed_from_int(0), wl_fixed_from_int(0));
326         wl_pointer_start_grab(seat->pointer, &seat->drag_grab);
327 }
328
329 static void
330 destroy_selection_data_source(struct wl_listener *listener, void *data)
331 {
332         struct wl_seat *seat = container_of(listener, struct wl_seat,
333                                             selection_data_source_listener);
334         struct wl_resource *data_device;
335         struct wl_resource *focus = NULL;
336
337         seat->selection_data_source = NULL;
338
339         if (seat->keyboard)
340                 focus = seat->keyboard->focus_resource;
341         if (focus) {
342                 data_device = find_resource(&seat->drag_resource_list,
343                                             focus->client);
344                 if (data_device)
345                         wl_data_device_send_selection(data_device, NULL);
346         }
347
348         wl_signal_emit(&seat->selection_signal, seat);
349 }
350
351 WL_EXPORT void
352 wl_seat_set_selection(struct wl_seat *seat, struct wl_data_source *source,
353                       uint32_t serial)
354 {
355         struct wl_resource *data_device, *offer;
356         struct wl_resource *focus = NULL;
357
358         if (seat->selection_data_source &&
359             seat->selection_serial - serial < UINT32_MAX / 2)
360                 return;
361
362         if (seat->selection_data_source) {
363                 seat->selection_data_source->cancel(seat->selection_data_source);
364                 wl_list_remove(&seat->selection_data_source_listener.link);
365                 seat->selection_data_source = NULL;
366         }
367
368         seat->selection_data_source = source;
369         seat->selection_serial = serial;
370
371         if (seat->keyboard)
372                 focus = seat->keyboard->focus_resource;
373         if (focus) {
374                 data_device = find_resource(&seat->drag_resource_list,
375                                             focus->client);
376                 if (data_device && source) {
377                         offer = wl_data_source_send_offer(seat->selection_data_source,
378                                                           data_device);
379                         wl_data_device_send_selection(data_device, offer);
380                 } else if (data_device) {
381                         wl_data_device_send_selection(data_device, NULL);
382                 }
383         }
384
385         wl_signal_emit(&seat->selection_signal, seat);
386
387         if (source) {
388                 seat->selection_data_source_listener.notify =
389                         destroy_selection_data_source;
390                 wl_signal_add(&source->resource.destroy_signal,
391                               &seat->selection_data_source_listener);
392         }
393 }
394
395 static void
396 data_device_set_selection(struct wl_client *client,
397                           struct wl_resource *resource,
398                           struct wl_resource *source_resource, uint32_t serial)
399 {
400         if (!source_resource)
401                 return;
402
403         /* FIXME: Store serial and check against incoming serial here. */
404         wl_seat_set_selection(resource->data, source_resource->data,
405                               serial);
406 }
407
408 static const struct wl_data_device_interface data_device_interface = {
409         data_device_start_drag,
410         data_device_set_selection,
411 };
412
413 static void
414 destroy_data_source(struct wl_resource *resource)
415 {
416         struct wl_data_source *source =
417                 container_of(resource, struct wl_data_source, resource);
418         char **p;
419
420         wl_array_for_each(p, &source->mime_types)
421                 free(*p);
422
423         wl_array_release(&source->mime_types);
424
425         source->resource.object.id = 0;
426 }
427
428 static void
429 client_source_accept(struct wl_data_source *source,
430                      uint32_t time, const char *mime_type)
431 {
432         wl_data_source_send_target(&source->resource, mime_type);
433 }
434
435 static void
436 client_source_send(struct wl_data_source *source,
437                    const char *mime_type, int32_t fd)
438 {
439         wl_data_source_send_send(&source->resource, mime_type, fd);
440         close(fd);
441 }
442
443 static void
444 client_source_cancel(struct wl_data_source *source)
445 {
446         wl_data_source_send_cancelled(&source->resource);
447 }
448
449 static void
450 create_data_source(struct wl_client *client,
451                    struct wl_resource *resource, uint32_t id)
452 {
453         struct wl_data_source *source;
454
455         source = malloc(sizeof *source);
456         if (source == NULL) {
457                 wl_resource_post_no_memory(resource);
458                 return;
459         }
460
461         source->resource.destroy = destroy_data_source;
462         source->resource.object.id = id;
463         source->resource.object.interface = &wl_data_source_interface;
464         source->resource.object.implementation =
465                 (void (**)(void)) &data_source_interface;
466         source->resource.data = source;
467         wl_signal_init(&source->resource.destroy_signal);
468
469         source->accept = client_source_accept;
470         source->send = client_source_send;
471         source->cancel = client_source_cancel;
472
473         wl_array_init(&source->mime_types);
474         wl_client_add_resource(client, &source->resource);
475 }
476
477 static void unbind_data_device(struct wl_resource *resource)
478 {
479         wl_list_remove(&resource->link);
480         free(resource);
481 }
482
483 static void
484 get_data_device(struct wl_client *client,
485                 struct wl_resource *manager_resource,
486                 uint32_t id, struct wl_resource *seat_resource)
487 {
488         struct wl_seat *seat = seat_resource->data;
489         struct wl_resource *resource;
490
491         resource = wl_client_add_object(client, &wl_data_device_interface,
492                                         &data_device_interface, id,
493                                         seat);
494
495         wl_list_insert(&seat->drag_resource_list, &resource->link);
496         resource->destroy = unbind_data_device;
497 }
498
499 static const struct wl_data_device_manager_interface manager_interface = {
500         create_data_source,
501         get_data_device
502 };
503
504 static void
505 bind_manager(struct wl_client *client,
506              void *data, uint32_t version, uint32_t id)
507 {
508         wl_client_add_object(client, &wl_data_device_manager_interface,
509                              &manager_interface, id, NULL);
510 }
511
512 WL_EXPORT void
513 wl_data_device_set_keyboard_focus(struct wl_seat *seat)
514 {
515         struct wl_resource *data_device, *focus, *offer;
516         struct wl_data_source *source;
517
518         if (!seat->keyboard)
519                 return;
520
521         focus = seat->keyboard->focus_resource;
522         if (!focus)
523                 return;
524
525         data_device = find_resource(&seat->drag_resource_list,
526                                     focus->client);
527         if (!data_device)
528                 return;
529
530         source = seat->selection_data_source;
531         if (source) {
532                 offer = wl_data_source_send_offer(source, data_device);
533                 wl_data_device_send_selection(data_device, offer);
534         }
535 }
536
537 WL_EXPORT int
538 wl_data_device_manager_init(struct wl_display *display)
539 {
540         if (wl_display_add_global(display,
541                                   &wl_data_device_manager_interface,
542                                   NULL, bind_manager) == NULL)
543                 return -1;
544
545         return 0;
546 }