Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore_wayland / ecore_wl_dnd.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <fcntl.h>
6 #include <sys/epoll.h>
7 #include "ecore_wl_private.h"
8
9 struct _dnd_task
10 {
11    void *data;
12    Ecore_Fd_Cb cb;
13 };
14
15 struct _dnd_read_ctx
16 {
17    int epoll_fd;
18    struct epoll_event *ep;
19 };
20
21 /* local function prototypes */
22 static void _ecore_wl_dnd_offer(void *data, struct wl_data_offer *wl_data_offer __UNUSED__, const char *type);
23 static void _ecore_wl_dnd_cb_enter_free(void *data __UNUSED__, void *event);
24
25 static void _ecore_wl_dnd_data_source_target(void *data, struct wl_data_source *source, const char *mime_type);
26 static void _ecore_wl_dnd_data_source_send(void *data, struct wl_data_source *source, const char *mime_type, int32_t fd);
27 static void _ecore_wl_dnd_data_source_cancelled(void *data, struct wl_data_source *source);
28 static void _ecore_wl_dnd_source_receive_data(Ecore_Wl_Dnd_Source *source, const char *type);
29
30 /* wayland listeners */
31 static const struct wl_data_offer_listener _ecore_wl_data_offer_listener = 
32 {
33    _ecore_wl_dnd_offer,
34 };
35
36 static const struct wl_data_source_listener _ecore_wl_data_source_listener = 
37 {
38    _ecore_wl_dnd_data_source_target,
39    _ecore_wl_dnd_data_source_send,
40    _ecore_wl_dnd_data_source_cancelled
41 };
42
43 extern Ecore_Wl_Dnd *glb_dnd;
44
45 EAPI Ecore_Wl_Dnd *
46 ecore_wl_dnd_get()
47 {
48    return glb_dnd;
49 }
50
51 EAPI Eina_Bool
52 ecore_wl_dnd_start_drag(Ecore_Wl_Dnd *dnd __UNUSED__)
53 {
54    //TODO:
55    return EINA_TRUE;
56 }
57
58 EAPI Eina_Bool
59 ecore_wl_dnd_set_selection(Ecore_Wl_Dnd *dnd, const char **types_offered)
60 {
61    char **p;
62    const char **type;
63
64    dnd->data_source = _ecore_wl_create_data_source(dnd->ewd);
65
66    /* free old types */
67    if (dnd->types_offered.data)
68      {
69         wl_array_for_each(p, &dnd->types_offered)
70           free(*p);
71         wl_array_release(&dnd->types_offered);
72         wl_array_init(&dnd->types_offered);
73      }
74
75    for (type = types_offered; *type; type++) 
76      {
77         p = wl_array_add(&dnd->types_offered, sizeof(*p));
78         *p = strdup(*type);
79         wl_data_source_offer(dnd->data_source, *p);
80      }
81
82    wl_data_source_add_listener(dnd->data_source, &_ecore_wl_data_source_listener, dnd);
83
84    _ecore_wl_input_set_selection(dnd->input, dnd->data_source);
85
86    return EINA_TRUE;
87 }
88
89 EAPI Eina_Bool
90 ecore_wl_dnd_get_selection(Ecore_Wl_Dnd *dnd, const char *type)
91 {
92    char **p;
93    Ecore_Wl_Input *input;
94
95    input = dnd->input;
96
97    if (!input->selection_source) return EINA_FALSE;
98
99    wl_array_for_each(p, &input->selection_source->types)
100      if (strcmp(type, *p) == 0) break;
101
102    if (!*p) return EINA_FALSE;
103
104    _ecore_wl_dnd_source_receive_data(input->selection_source, type);
105
106    return EINA_TRUE;
107 }
108
109 EAPI Eina_Bool
110 ecore_wl_dnd_selection_has_owner(Ecore_Wl_Dnd *dnd)
111 {
112    Ecore_Wl_Input *input;
113
114    input = dnd->input;
115    return (input->selection_source != NULL);
116 }
117
118 /* local functions */
119 static void
120 _ecore_wl_dnd_data_source_target(void *data __UNUSED__, struct wl_data_source *source __UNUSED__, const char *mime_type __UNUSED__)
121 {
122    //TODO:
123 }
124
125 static void 
126 _ecore_wl_dnd_cb_data_source_send_free(void *data __UNUSED__, void *event)
127 {
128    Ecore_Wl_Event_Data_Source_Send *ev;
129
130    LOGFN(__FILE__, __LINE__, __FUNCTION__);
131
132    if (!(ev = event)) return;
133
134    free(ev->type);
135    free(ev);
136 }
137
138 static void
139 _ecore_wl_dnd_data_source_send(void *data, struct wl_data_source *source __UNUSED__, const char *mime_type, int32_t fd)
140 {
141    Ecore_Wl_Event_Data_Source_Send *event;
142
143    LOGFN(__FILE__, __LINE__, __FUNCTION__);
144
145    if (!data) return;
146
147    if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Data_Source_Send)))) return;
148
149    event->type = strdup(mime_type);
150    event->fd = fd;
151
152    ecore_event_add(ECORE_WL_EVENT_DATA_SOURCE_SEND, event, _ecore_wl_dnd_cb_data_source_send_free, NULL);
153 }
154
155 static void
156 _ecore_wl_dnd_data_source_cancelled(void *data __UNUSED__, struct wl_data_source *source)
157 {
158    wl_data_source_destroy(source);
159 }
160
161 void 
162 _ecore_wl_dnd_add(Ecore_Wl_Input *input, struct wl_data_device *data_device __UNUSED__, struct wl_data_offer *offer)
163 {
164    Ecore_Wl_Dnd_Source *source;
165
166    LOGFN(__FILE__, __LINE__, __FUNCTION__);
167
168    if (!(source = malloc(sizeof(Ecore_Wl_Dnd_Source)))) return;
169    wl_array_init(&source->types);
170    source->refcount = 1;
171    source->input = input;
172    source->offer = offer;
173    wl_data_offer_add_listener(source->offer, 
174                               &_ecore_wl_data_offer_listener, source);
175 }
176
177 void 
178 _ecore_wl_dnd_enter(void *data, struct wl_data_device *data_device __UNUSED__, unsigned int timestamp __UNUSED__, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *offer)
179 {
180    Ecore_Wl_Event_Dnd_Enter *event;
181    Ecore_Wl_Input *input;
182    Ecore_Wl_Window *win;
183    char **p;
184
185    LOGFN(__FILE__, __LINE__, __FUNCTION__);
186
187    if ((!(input = data)) || (!offer)) return;
188
189    if (!(input->drag_source = wl_data_offer_get_user_data(offer)))
190      return;
191
192    win = wl_surface_get_user_data(surface);
193 //   input->pointer_focus = win;
194
195    p = wl_array_add(&input->drag_source->types, sizeof(*p));
196    *p = NULL;
197
198    if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Dnd_Enter)))) return;
199
200    event->win = win->id;
201    if (input->drag_source->input)
202      {
203         if (input->drag_source->input->keyboard_focus)
204           event->source = input->drag_source->input->keyboard_focus->id;
205      }
206
207    event->position.x = wl_fixed_to_int(x);
208    event->position.y = wl_fixed_to_int(y);
209    event->num_types = input->drag_source->types.size;
210    event->types = input->drag_source->types.data;
211
212    ecore_event_add(ECORE_WL_EVENT_DND_ENTER, event, 
213                    _ecore_wl_dnd_cb_enter_free, NULL);
214 }
215
216 void 
217 _ecore_wl_dnd_leave(void *data, struct wl_data_device *data_device __UNUSED__)
218 {
219    Ecore_Wl_Input *input;
220
221    LOGFN(__FILE__, __LINE__, __FUNCTION__);
222
223    if (!(input = data)) return;
224    /* FIXME: NB: This MAY need to raise a wl_event_dnd_leave for the 
225     * source window */
226    _ecore_wl_dnd_del(input->drag_source);
227    input->drag_source = NULL;
228 }
229
230 void 
231 _ecore_wl_dnd_motion(void *data, struct wl_data_device *data_device __UNUSED__, unsigned int timestamp __UNUSED__, wl_fixed_t x, wl_fixed_t y)
232 {
233    Ecore_Wl_Event_Dnd_Position *event;
234    Ecore_Wl_Input *input;
235
236    LOGFN(__FILE__, __LINE__, __FUNCTION__);
237
238    if (!(input = data)) return;
239
240    input->sx = wl_fixed_to_int(x);
241    input->sy = wl_fixed_to_int(y);
242
243    if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Dnd_Position)))) return;
244
245    if (input->drag_source)
246      {
247         if (input->drag_source->input)
248           {
249              if (input->drag_source->input->pointer_focus)
250                event->win = input->drag_source->input->pointer_focus->id;
251              if (input->drag_source->input->keyboard_focus)
252                event->source = input->drag_source->input->keyboard_focus->id;
253           }
254      }
255
256    event->position.x = input->sx;
257    event->position.y = input->sy;
258
259    ecore_event_add(ECORE_WL_EVENT_DND_POSITION, event, NULL, NULL);
260 }
261
262 void 
263 _ecore_wl_dnd_drop(void *data, struct wl_data_device *data_device __UNUSED__)
264 {
265    Ecore_Wl_Event_Dnd_Drop *event;
266    Ecore_Wl_Input *input;
267
268    LOGFN(__FILE__, __LINE__, __FUNCTION__);
269
270    if (!(input = data)) return;
271
272    if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Dnd_Drop)))) return;
273
274    if (input->drag_source)
275      {
276         if (input->drag_source->input)
277           {
278              if (input->drag_source->input->pointer_focus)
279                event->win = input->drag_source->input->pointer_focus->id;
280              if (input->drag_source->input->keyboard_focus)
281                event->source = input->drag_source->input->keyboard_focus->id;
282           }
283      }
284
285    event->position.x = input->sx;
286    event->position.y = input->sy;
287
288    ecore_event_add(ECORE_WL_EVENT_DND_DROP, event, NULL, NULL);
289 }
290
291 void 
292 _ecore_wl_dnd_selection(void *data, struct wl_data_device *data_device __UNUSED__, struct wl_data_offer *offer)
293 {
294    Ecore_Wl_Input *input;
295
296    LOGFN(__FILE__, __LINE__, __FUNCTION__);
297
298    if (!(input = data)) return;
299    if (input->selection_source) _ecore_wl_dnd_del(input->selection_source);
300    input->selection_source = NULL;
301    if (offer)
302      {
303         char **p;
304
305         input->selection_source = wl_data_offer_get_user_data(offer);
306         p = wl_array_add(&input->selection_source->types, sizeof(*p));
307         *p = NULL;
308      }
309 }
310
311 void 
312 _ecore_wl_dnd_del(Ecore_Wl_Dnd_Source *source)
313 {
314    LOGFN(__FILE__, __LINE__, __FUNCTION__);
315
316    if (!source) return;
317    source->refcount--;
318    if (source->refcount == 0)
319      {
320         char **p;
321
322         wl_data_offer_destroy(source->offer);
323         for (p = source->types.data; *p; p++)
324           free(*p);
325         wl_array_release(&source->types);
326         free(source);
327      }
328 }
329
330 /* local functions */
331 static void 
332 _ecore_wl_dnd_offer(void *data, struct wl_data_offer *wl_data_offer __UNUSED__, const char *type)
333 {
334    Ecore_Wl_Dnd_Source *source;
335    char **p;
336
337    LOGFN(__FILE__, __LINE__, __FUNCTION__);
338
339    if (!(source = data)) return;
340    p = wl_array_add(&source->types, sizeof(*p));
341    *p = strdup(type);
342 }
343
344 static void 
345 _ecore_wl_dnd_cb_enter_free(void *data __UNUSED__, void *event)
346 {
347    Ecore_Wl_Event_Dnd_Enter *ev;
348
349    LOGFN(__FILE__, __LINE__, __FUNCTION__);
350
351    if (!(ev = event)) return;
352    free(ev);
353 }
354
355 static void 
356 _ecore_wl_dnd_cb_selection_data_ready_free(void *data __UNUSED__, void *event)
357 {
358    Ecore_Wl_Event_Selection_Data_Ready *ev;
359
360    LOGFN(__FILE__, __LINE__, __FUNCTION__);
361
362    if (!(ev = event)) return;
363
364    free(ev->data);
365    free(ev);
366 }
367
368 static Eina_Bool 
369 _ecore_wl_dnd_read_data(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__)
370 {
371    int len;
372    char buffer[4096];
373    Ecore_Wl_Dnd_Source *source;
374    Ecore_Wl_Event_Selection_Data_Ready *event;
375    Eina_Bool ret;
376
377    source = data;
378
379    len = read(source->fd, buffer, sizeof buffer);
380
381    if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Selection_Data_Ready)))) 
382      return ECORE_CALLBACK_CANCEL;
383
384    if (len <= 0)
385      {
386         close(source->fd);
387         _ecore_wl_dnd_del(source);
388         event->done = EINA_TRUE;
389         event->data = NULL;
390         event->len = 0;
391         ret = ECORE_CALLBACK_CANCEL;
392      }
393    else
394      {
395         event->data = malloc(len + 1);
396         if (!event->data) return ECORE_CALLBACK_CANCEL;
397         strncpy(event->data, buffer, len);
398         event->data[len] = '\0';
399         event->len = len;
400         event->done = EINA_FALSE;
401         ret = ECORE_CALLBACK_RENEW;
402      }
403
404    ecore_event_add(ECORE_WL_EVENT_SELECTION_DATA_READY, event, 
405                    _ecore_wl_dnd_cb_selection_data_ready_free, NULL);
406    return ret;
407 }
408
409
410 static Eina_Bool
411 _ecore_wl_dnd_idler_cb(void *data)
412 {
413    struct _dnd_read_ctx *ctx;
414    struct _dnd_task *task;
415    int count, i;
416
417    ctx = data;
418    count = epoll_wait(ctx->epoll_fd, ctx->ep, 1, 0);
419    for (i = 0; i < count; i++)
420      {
421         task = ctx->ep->data.ptr;
422         if (task->cb(task->data, NULL) == ECORE_CALLBACK_CANCEL)
423           {
424              free(ctx->ep);
425              free(task);
426              free(ctx);
427              return ECORE_CALLBACK_CANCEL;
428           }
429      } 
430    return ECORE_CALLBACK_RENEW;
431 }
432
433 static void
434 _ecore_wl_dnd_source_receive_data(Ecore_Wl_Dnd_Source *source, const char *type)
435 {
436    int epoll_fd;
437    struct epoll_event *ep = NULL;
438    struct _dnd_task *task = NULL;
439    struct _dnd_read_ctx *read_ctx = NULL;
440    int p[2];
441
442    if (pipe2(p, O_CLOEXEC) == -1)
443      return;
444
445    wl_data_offer_receive(source->offer, type, p[1]);
446    close(p[1]);
447
448    /* Due to http://trac.enlightenment.org/e/ticket/1208,
449     * use epoll and idle handler instead of ecore_main_fd_handler_add() */
450
451    ep = calloc(1, sizeof(struct epoll_event));
452    if (!ep) goto err;
453
454    task = calloc(1, sizeof(struct _dnd_task));
455    if (!task) goto err;
456
457    read_ctx = calloc(1, sizeof(struct _dnd_read_ctx));
458    if (!read_ctx) goto err;
459
460    epoll_fd  = epoll_create1(0);
461    if (epoll_fd < 0) goto err;
462
463    task->data = source;
464    task->cb = _ecore_wl_dnd_read_data;
465    ep->events = EPOLLIN;
466    ep->data.ptr = task;
467
468    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, p[0], ep) < 0) goto err;
469
470    read_ctx->epoll_fd = epoll_fd;
471    read_ctx->ep = ep;
472
473    if (!ecore_idler_add(_ecore_wl_dnd_idler_cb, read_ctx)) goto err;
474
475    source->refcount++;
476    source->fd = p[0];
477    return;
478
479 err:
480    if (ep) free(ep);
481    if (task) free(task);
482    if (read_ctx) free(read_ctx);
483    close(p[0]);
484    return;
485 }