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