Tizen 2.1 release
[platform/core/uifw/e17.git] / src / bin / e_dnd.c
1 #include "e.h"
2
3 /* FIXME: broken when drop areas intersect
4  * (sub window has drop area on top of lower window or desktop)
5  */
6 /*
7  * TODO:
8  * - Let an internal drag work with several types.
9  * - Let a drag be both internal and external, or allow internal xdnd
10  *   (internal xdnd is unnecessary load)
11  */
12
13 /* local subsystem functions */
14
15 static void           _e_drag_show(E_Drag *drag);
16 static void           _e_drag_hide(E_Drag *drag);
17 static void           _e_drag_move(E_Drag *drag, int x, int y);
18 static void           _e_drag_coords_update(const E_Drop_Handler *h, int *dx, int *dy);
19 static Ecore_X_Window _e_drag_win_get(const E_Drop_Handler *h, int xdnd);
20 static int            _e_drag_win_matches(E_Drop_Handler *h, Ecore_X_Window win, int xdnd);
21 static void           _e_drag_win_show(E_Drop_Handler *h);
22 static void           _e_drag_win_hide(E_Drop_Handler *h);
23 static int            _e_drag_update(Ecore_X_Window root, int x, int y, Ecore_X_Atom action);
24 static void           _e_drag_end(Ecore_X_Window root, int x, int y);
25 static void           _e_drag_xdnd_end(Ecore_X_Window root, int x, int y);
26 static void           _e_drag_free(E_Drag *drag);
27
28 static Eina_Bool      _e_dnd_cb_window_shape(void *data, int type, void *event);
29
30 static Eina_Bool      _e_dnd_cb_key_down(void *data, int type, void *event);
31 static Eina_Bool      _e_dnd_cb_key_up(void *data, int type, void *event);
32 static Eina_Bool      _e_dnd_cb_mouse_up(void *data, int type, void *event);
33 static Eina_Bool      _e_dnd_cb_mouse_move(void *data, int type, void *event);
34 static Eina_Bool      _e_dnd_cb_event_dnd_enter(void *data, int type, void *event);
35 static Eina_Bool      _e_dnd_cb_event_dnd_leave(void *data, int type, void *event);
36 static Eina_Bool      _e_dnd_cb_event_dnd_position(void *data, int type, void *event);
37 static Eina_Bool      _e_dnd_cb_event_dnd_status(void *data, int type, void *event);
38 static Eina_Bool      _e_dnd_cb_event_dnd_finished(void *data, int type, void *event);
39 static Eina_Bool      _e_dnd_cb_event_dnd_drop(void *data, int type, void *event);
40 static Eina_Bool      _e_dnd_cb_event_dnd_selection(void *data, int type, void *event);
41
42 /* local subsystem globals */
43
44 typedef struct _XDnd XDnd;
45
46 struct _XDnd
47 {
48    int         x, y;
49    const char *type;
50    void       *data;
51 };
52
53 static Eina_List *_event_handlers = NULL;
54 static Eina_List *_drop_handlers = NULL;
55 static Eina_Hash *_drop_win_hash = NULL;
56
57 static Ecore_X_Window _drag_win = 0;
58 static Ecore_X_Window _drag_win_root = 0;
59
60 static Eina_List *_drag_list = NULL;
61 static E_Drag *_drag_current = NULL;
62
63 static XDnd *_xdnd = NULL;
64 #define XDS_ATOM "XdndDirectSave0"
65 static Ecore_X_Atom _xds_atom = 0;
66 static Ecore_X_Atom _text_atom = 0;
67 static const char *_type_text_uri_list = NULL;
68 static const char *_type_xds = NULL;
69 static const char *_type_text_x_moz_url = NULL;
70 static const char *_type_enlightenment_x_file = NULL;
71
72 static Eina_Hash *_drop_handlers_responsives;
73 static Ecore_X_Atom _action;
74
75 /* externally accessible functions */
76
77 EINTERN int
78 e_dnd_init(void)
79 {
80    _type_text_uri_list = eina_stringshare_add("text/uri-list");
81    _type_xds = eina_stringshare_add(XDS_ATOM);
82    _type_text_x_moz_url = eina_stringshare_add("text/x-moz-url");
83    _type_enlightenment_x_file = eina_stringshare_add("enlightenment/x-file");
84    _xds_atom = ecore_x_atom_get(XDS_ATOM);
85    _text_atom = ecore_x_atom_get("text/plain");
86
87    _drop_win_hash = eina_hash_string_superfast_new(NULL);
88    _drop_handlers_responsives = eina_hash_string_superfast_new(NULL);
89
90    _event_handlers = eina_list_append(_event_handlers,
91                                       ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
92                                                               _e_dnd_cb_mouse_up, NULL));
93    _event_handlers = eina_list_append(_event_handlers,
94                                       ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
95                                                               _e_dnd_cb_mouse_move, NULL));
96    _event_handlers = eina_list_append(_event_handlers,
97                                       ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHAPE,
98                                                               _e_dnd_cb_window_shape, NULL));
99
100    _event_handlers = eina_list_append(_event_handlers,
101                                       ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
102                                                               _e_dnd_cb_event_dnd_enter, NULL));
103    _event_handlers = eina_list_append(_event_handlers,
104                                       ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE,
105                                                               _e_dnd_cb_event_dnd_leave, NULL));
106    _event_handlers = eina_list_append(_event_handlers,
107                                       ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
108                                                               _e_dnd_cb_event_dnd_position, NULL));
109    _event_handlers = eina_list_append(_event_handlers,
110                                       ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
111                                                               _e_dnd_cb_event_dnd_status, NULL));
112    _event_handlers = eina_list_append(_event_handlers,
113                                       ecore_event_handler_add(ECORE_X_EVENT_XDND_FINISHED,
114                                                               _e_dnd_cb_event_dnd_finished, NULL));
115    _event_handlers = eina_list_append(_event_handlers,
116                                       ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
117                                                               _e_dnd_cb_event_dnd_drop, NULL));
118    _event_handlers = eina_list_append(_event_handlers,
119                                       ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY,
120                                                               _e_dnd_cb_event_dnd_selection, NULL));
121    _event_handlers = eina_list_append(_event_handlers,
122                                       ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
123                                                               _e_dnd_cb_key_down, NULL));
124    _event_handlers = eina_list_append(_event_handlers,
125                                       ecore_event_handler_add(ECORE_EVENT_KEY_UP,
126                                                               _e_dnd_cb_key_up, NULL));
127
128    _action = ECORE_X_ATOM_XDND_ACTION_PRIVATE;
129    return 1;
130 }
131
132 EINTERN int
133 e_dnd_shutdown(void)
134 {
135    E_FREE_LIST(_drag_list, e_object_del);
136
137    E_FREE_LIST(_drop_handlers, e_drop_handler_del);
138
139    E_FREE_LIST(_event_handlers, ecore_event_handler_del);
140
141    eina_hash_free(_drop_win_hash);
142
143    eina_hash_free(_drop_handlers_responsives);
144
145    eina_stringshare_del(_type_text_uri_list);
146    eina_stringshare_del(_type_xds);
147    eina_stringshare_del(_type_text_x_moz_url);
148    eina_stringshare_del(_type_enlightenment_x_file);
149    _type_text_uri_list = NULL;
150    _type_xds = NULL;
151    _type_text_x_moz_url = NULL;
152    _type_enlightenment_x_file = NULL;
153    _text_atom = _xds_atom = 0;
154
155    return 1;
156 }
157
158 EAPI E_Drag *
159 e_drag_new(E_Container *container, int x, int y,
160            const char **types, unsigned int num_types,
161            void *data, int size,
162            void *(*convert_cb)(E_Drag * drag, const char *type),
163            void (*finished_cb)(E_Drag *drag, int dropped))
164 {
165    E_Drag *drag;
166    unsigned int i;
167
168    /* No need to create a drag object without type */
169    if ((!types) || (!num_types)) return NULL;
170    drag = e_object_alloc(sizeof(E_Drag) + num_types * sizeof(char *),
171                          E_DRAG_TYPE, E_OBJECT_CLEANUP_FUNC(_e_drag_free));
172    if (!drag) return NULL;
173
174    drag->x = x;
175    drag->y = y;
176    drag->w = 24;
177    drag->h = 24;
178    drag->layer = 250;
179    drag->container = container;
180    e_object_ref(E_OBJECT(drag->container));
181    drag->ecore_evas = e_canvas_new(drag->container->win,
182                                    drag->x, drag->y, drag->w, drag->h, 1, 1,
183                                    &(drag->evas_win));
184    if (e_config->use_composite)
185      ecore_evas_alpha_set(drag->ecore_evas, 1);
186    else
187      {
188         /* avoid excess exposes when shaped - set damage avoid to 1 */
189         ecore_evas_avoid_damage_set(drag->ecore_evas, 1);
190         ecore_evas_shaped_set(drag->ecore_evas, 1);
191         ecore_x_window_shape_events_select(drag->evas_win, 1);
192      }
193
194    e_canvas_add(drag->ecore_evas);
195    drag->shape = e_container_shape_add(drag->container);
196    e_container_shape_move(drag->shape, drag->x, drag->y);
197    e_container_shape_resize(drag->shape, drag->w, drag->h);
198
199    drag->evas = ecore_evas_get(drag->ecore_evas);
200    e_container_window_raise(drag->container, drag->evas_win, drag->layer);
201
202    ecore_evas_name_class_set(drag->ecore_evas, "E", "_e_drag_window");
203    ecore_evas_title_set(drag->ecore_evas, "E Drag");
204    ecore_evas_ignore_events_set(drag->ecore_evas, 1);
205
206    drag->object = evas_object_rectangle_add(drag->evas);
207    evas_object_color_set(drag->object, 255, 0, 0, 255);
208    evas_object_show(drag->object);
209
210    evas_object_move(drag->object, 0, 0);
211    evas_object_resize(drag->object, drag->w, drag->h);
212    ecore_evas_resize(drag->ecore_evas, drag->w, drag->h);
213
214    drag->type = E_DRAG_NONE;
215
216    for (i = 0; i < num_types; i++)
217      drag->types[i] = eina_stringshare_add(types[i]);
218    drag->num_types = num_types;
219    drag->data = data;
220    drag->data_size = size;
221    drag->cb.convert = convert_cb;
222    drag->cb.finished = finished_cb;
223
224    _drag_list = eina_list_append(_drag_list, drag);
225
226    ecore_x_window_shadow_tree_flush();
227
228    _drag_win_root = drag->container->manager->root;
229
230    drag->cb.key_down = NULL;
231    drag->cb.key_up = NULL;
232
233    return drag;
234 }
235
236 EAPI Evas *
237 e_drag_evas_get(const E_Drag *drag)
238 {
239    return drag->evas;
240 }
241
242 EAPI void
243 e_drag_object_set(E_Drag *drag, Evas_Object *object)
244 {
245    if (drag->object) evas_object_del(drag->object);
246    drag->object = object;
247    evas_object_resize(drag->object, drag->w, drag->h);
248 }
249
250 EAPI void
251 e_drag_move(E_Drag *drag, int x, int y)
252 {
253    if ((drag->x == x) && (drag->y == y)) return;
254    drag->x = x;
255    drag->y = y;
256    drag->xy_update = 1;
257 }
258
259 EAPI void
260 e_drag_resize(E_Drag *drag, int w, int h)
261 {
262    if ((drag->w == w) && (drag->h == h)) return;
263    drag->h = h;
264    drag->w = w;
265    evas_object_resize(drag->object, drag->w, drag->h);
266    ecore_evas_resize(drag->ecore_evas, drag->w, drag->h);
267    e_container_shape_resize(drag->shape, drag->w, drag->h);
268 }
269
270 EAPI int
271 e_dnd_active(void)
272 {
273    return _drag_win != 0;
274 }
275
276 EAPI int
277 e_drag_start(E_Drag *drag, int x, int y)
278 {
279    const Eina_List *l;
280    E_Drop_Handler *h;
281
282    if (_drag_win) return 0;
283    _drag_win = ecore_x_window_input_new(drag->container->win,
284                                         drag->container->x, drag->container->y,
285                                         drag->container->w, drag->container->h);
286    _drag_win_root = drag->container->manager->root;
287    ecore_x_window_show(_drag_win);
288    if (!e_grabinput_get(_drag_win, 1, _drag_win))
289      {
290         ecore_x_window_free(_drag_win);
291         return 0;
292      }
293
294    drag->type = E_DRAG_INTERNAL;
295
296    drag->dx = x - drag->x;
297    drag->dy = y - drag->y;
298
299    EINA_LIST_FOREACH(_drop_handlers, l, h)
300      {
301         unsigned int i, j;
302
303         h->active = 0;
304         eina_stringshare_del(h->active_type);
305         h->active_type = NULL;
306         for (i = 0; i < h->num_types; i++)
307           {
308              for (j = 0; j < drag->num_types; j++)
309                {
310                   if (h->types[i] == drag->types[j])
311                     {
312                        h->active = 1;
313                        h->active_type = eina_stringshare_ref(h->types[i]);
314                        break;
315                     }
316                }
317              if (h->active) break;
318           }
319         h->entered = 0;
320      }
321
322    _drag_current = drag;
323    return 1;
324 }
325
326 EAPI int
327 e_drag_xdnd_start(E_Drag *drag, int x, int y)
328 {
329    Ecore_X_Atom actions[] = {
330       ECORE_X_DND_ACTION_MOVE, ECORE_X_DND_ACTION_PRIVATE,
331       ECORE_X_DND_ACTION_COPY, ECORE_X_DND_ACTION_ASK,
332       ECORE_X_DND_ACTION_LINK
333    };
334    if (_drag_win) return 0;
335    _drag_win = ecore_x_window_input_new(drag->container->win,
336                                         drag->container->x, drag->container->y,
337                                         drag->container->w, drag->container->h);
338
339    ecore_x_window_show(_drag_win);
340    if (!e_grabinput_get(_drag_win, 1, _drag_win))
341      {
342         ecore_x_window_free(_drag_win);
343         return 0;
344      }
345
346    drag->type = E_DRAG_XDND;
347
348    drag->dx = x - drag->x;
349    drag->dy = y - drag->y;
350
351    ecore_x_dnd_aware_set(_drag_win, 1);
352    ecore_x_dnd_types_set(_drag_win, drag->types, drag->num_types);
353    ecore_x_dnd_actions_set(_drag_win, actions, 5);
354    ecore_x_dnd_begin(_drag_win, drag->data, drag->data_size);
355
356    _drag_current = drag;
357    return 1;
358 }
359
360 EAPI void
361 e_drop_handler_xds_set(E_Drop_Handler *handler, Ecore_Task_Cb cb)
362 {
363    handler->cb.xds = cb;
364 }
365
366 /* should only be used for windows */
367 EAPI void
368 e_drop_xds_update(Eina_Bool enable, const char *value)
369 {
370    Ecore_X_Window xwin;
371    char buf[PATH_MAX + 8];
372    char *file;
373    int size;
374    size_t len;
375
376    enable = !!enable;
377      
378    xwin = ecore_x_selection_owner_get(ECORE_X_ATOM_SELECTION_XDND);
379    if (enable)
380      {
381         if (!ecore_x_window_prop_property_get(xwin, _xds_atom, _text_atom, 8, (unsigned char **)&file, &size))
382           return;
383         len = strlen(value);
384         if (size + len + 8 + 1 > sizeof(buf))
385           {
386              free(file);
387              return;
388           }
389         snprintf(buf, sizeof(buf), "file://%s/", value);
390         strncat(buf, file, size);
391         free(file);
392         ecore_x_window_prop_property_set(xwin, _xds_atom, _text_atom, 8, (void*)buf, size + len + 8);
393      }
394    else
395      ecore_x_window_prop_property_del(xwin, _xds_atom);
396 }
397
398 EAPI E_Drop_Handler *
399 e_drop_handler_add(E_Object *obj,
400                    void *data,
401                    void (*enter_cb)(void *data, const char *type, void *event),
402                    void (*move_cb)(void *data, const char *type, void *event),
403                    void (*leave_cb)(void *data, const char *type, void *event),
404                    void (*drop_cb)(void *data, const char *type, void *event),
405                    const char **types, unsigned int num_types, int x, int y, int w, int h)
406 {
407    E_Drop_Handler *handler;
408    unsigned int i;
409
410    handler = calloc(1, sizeof(E_Drop_Handler) + num_types * sizeof(char *));
411    if (!handler) return NULL;
412
413    handler->cb.data = data;
414    handler->cb.enter = enter_cb;
415    handler->cb.move = move_cb;
416    handler->cb.leave = leave_cb;
417    handler->cb.drop = drop_cb;
418    handler->num_types = num_types;
419    for (i = 0; i < num_types; i++)
420      handler->types[i] = eina_stringshare_add(types[i]);
421    handler->x = x;
422    handler->y = y;
423    handler->w = w;
424    handler->h = h;
425
426    handler->obj = obj;
427    handler->entered = 0;
428
429    _drop_handlers = eina_list_append(_drop_handlers, handler);
430
431    return handler;
432 }
433
434 EAPI void
435 e_drop_handler_geometry_set(E_Drop_Handler *handler, int x, int y, int w, int h)
436 {
437    handler->x = x;
438    handler->y = y;
439    handler->w = w;
440    handler->h = h;
441 }
442
443 EAPI int
444 e_drop_inside(const E_Drop_Handler *handler, int x, int y)
445 {
446    int dx, dy;
447
448    _e_drag_coords_update(handler, &dx, &dy);
449    x -= dx;
450    y -= dy;
451    return E_INSIDE(x, y, handler->x, handler->y, handler->w, handler->h);
452 }
453
454 EAPI void
455 e_drop_handler_del(E_Drop_Handler *handler)
456 {
457    unsigned int i;
458
459    if (!handler)
460      return;
461
462    _drop_handlers = eina_list_remove(_drop_handlers, handler);
463    for (i = 0; i < handler->num_types; i++)
464      eina_stringshare_del(handler->types[i]);
465    eina_stringshare_del(handler->active_type);
466    free(handler);
467 }
468
469 EAPI int
470 e_drop_xdnd_register_set(Ecore_X_Window win, int reg)
471 {
472    const char *id;
473
474    id = e_util_winid_str_get(win);
475    if (reg)
476      {
477         if (!eina_hash_find(_drop_win_hash, id))
478           {
479              ecore_x_dnd_aware_set(win, 1);
480              eina_hash_add(_drop_win_hash, id, (void *)1);
481           }
482      }
483    else
484      {
485         ecore_x_dnd_aware_set(win, 0);
486         eina_hash_del(_drop_win_hash, id, (void *)1);
487      }
488    return 1;
489 }
490
491 EAPI void
492 e_drag_idler_before(void)
493 {
494    const Eina_List *l;
495    E_Drag *drag;
496
497    EINA_LIST_FOREACH(_drag_list, l, drag)
498      {
499         if (drag->need_shape_export)
500           {
501              Ecore_X_Rectangle *rects, *orects;
502              int num;
503
504              rects = ecore_x_window_shape_rectangles_get(drag->evas_win, &num);
505              if (rects)
506                {
507                   int changed;
508
509                   changed = 1;
510                   if ((num == drag->shape_rects_num) && (drag->shape_rects))
511                     {
512                        int i;
513
514                        orects = drag->shape_rects;
515                        for (i = 0; i < num; i++)
516                          {
517                             if ((orects[i].x != rects[i].x) ||
518                                 (orects[i].y != rects[i].y) ||
519                                 (orects[i].width != rects[i].width) ||
520                                 (orects[i].height != rects[i].height))
521                               {
522                                  changed = 1;
523                                  break;
524                               }
525                          }
526                        // TODO: This is meaningless
527                        changed = 0;
528                     }
529                   if (changed)
530                     {
531                        E_FREE(drag->shape_rects);
532                        drag->shape_rects = rects;
533                        drag->shape_rects_num = num;
534                        e_container_shape_rects_set(drag->shape, rects, num);
535                     }
536                   else
537                     free(rects);
538                }
539              else
540                {
541                   E_FREE(drag->shape_rects);
542                   drag->shape_rects = NULL;
543                   drag->shape_rects_num = 0;
544                   e_container_shape_rects_set(drag->shape, NULL, 0);
545                }
546              drag->need_shape_export = 0;
547              if (drag->visible)
548                e_container_shape_show(drag->shape);
549           }
550         if (drag->xy_update)
551           {
552              ecore_evas_move(drag->ecore_evas, drag->x, drag->y);
553              e_container_shape_move(drag->shape, drag->x, drag->y);
554              drag->xy_update = 0;
555           }
556      }
557 }
558
559 EAPI void
560 e_drop_handler_responsive_set(E_Drop_Handler *handler)
561 {
562    Ecore_X_Window hwin = _e_drag_win_get(handler, 1);
563    const char *wid = e_util_winid_str_get(hwin);
564
565    eina_hash_add(_drop_handlers_responsives, wid, (void *)handler);
566 }
567
568 EAPI int
569 e_drop_handler_responsive_get(const E_Drop_Handler *handler)
570 {
571    Ecore_X_Window hwin = _e_drag_win_get(handler, 1);
572    const char *wid = e_util_winid_str_get(hwin);
573
574    return eina_hash_find(_drop_handlers_responsives, wid) == (void *)handler;
575 }
576
577 EAPI void
578 e_drop_handler_action_set(Ecore_X_Atom action)
579 {
580    _action = action;
581 }
582
583 EAPI Ecore_X_Atom
584 e_drop_handler_action_get(void)
585 {
586    return _action;
587 }
588
589 EAPI void
590 e_drag_key_down_cb_set(E_Drag *drag, void (*func)(E_Drag *drag, Ecore_Event_Key *e))
591 {
592    drag->cb.key_down = func;
593 }
594
595 EAPI void
596 e_drag_key_up_cb_set(E_Drag *drag, void (*func)(E_Drag *drag, Ecore_Event_Key *e))
597 {
598    drag->cb.key_up = func;
599 }
600
601 /* local subsystem functions */
602
603 static void
604 _e_drag_show(E_Drag *drag)
605 {
606    if (drag->visible) return;
607    drag->visible = 1;
608    evas_object_show(drag->object);
609    ecore_evas_show(drag->ecore_evas);
610    e_container_shape_show(drag->shape);
611 }
612
613 static void
614 _e_drag_hide(E_Drag *drag)
615 {
616    if (!drag->visible) return;
617    drag->visible = 0;
618    evas_object_hide(drag->object);
619    ecore_evas_hide(drag->ecore_evas);
620    e_container_shape_hide(drag->shape);
621 }
622
623 static void
624 _e_drag_move(E_Drag *drag, int x, int y)
625 {
626    E_Zone *zone;
627
628    if (((drag->x + drag->dx) == x) && ((drag->y + drag->dy) == y)) return;
629
630    zone = e_container_zone_at_point_get(drag->container, x, y);
631    if (zone) e_zone_flip_coords_handle(zone, x, y);
632
633    drag->x = x - drag->dx;
634    drag->y = y - drag->dy;
635    drag->xy_update = 1;
636 }
637
638 static void
639 _e_drag_coords_update(const E_Drop_Handler *h, int *dx, int *dy)
640 {
641    int px = 0, py = 0;
642
643    *dx = 0;
644    *dy = 0;
645    if (h->obj)
646      {
647         switch (h->obj->type)
648           {
649            case E_GADCON_TYPE:
650              e_gadcon_canvas_zone_geometry_get((E_Gadcon *)(h->obj), &px, &py, NULL, NULL);
651              break;
652
653            case E_GADCON_CLIENT_TYPE:
654              e_gadcon_canvas_zone_geometry_get(((E_Gadcon_Client *)(h->obj))->gadcon, &px, &py, NULL, NULL);
655              break;
656
657            case E_WIN_TYPE:
658              px = ((E_Win *)(h->obj))->x;
659              py = ((E_Win *)(h->obj))->y;
660              break;
661
662            case E_ZONE_TYPE:
663 // zone based drag targets are in a container thus their coords should be
664 // screen-relative as containers just cover the screen
665 //           px = ((E_Zone *)(h->obj))->x;
666 //           py = ((E_Zone *)(h->obj))->y;
667              break;
668
669            case E_BORDER_TYPE:
670              px = ((E_Border *)(h->obj))->x + ((E_Border *)(h->obj))->fx.x;
671              py = ((E_Border *)(h->obj))->y + ((E_Border *)(h->obj))->fx.y;
672              break;
673
674            case E_POPUP_TYPE:
675              px = ((E_Popup *)(h->obj))->x;
676              py = ((E_Popup *)(h->obj))->y;
677              break;
678
679            /* FIXME: add more types as needed */
680            default:
681              break;
682           }
683      }
684    *dx += px;
685    *dy += py;
686 }
687
688 static Ecore_X_Window
689 _e_drag_win_get(const E_Drop_Handler *h, int xdnd)
690 {
691    Ecore_X_Window hwin = 0;
692
693    if (h->obj)
694      {
695         switch (h->obj->type)
696           {
697            case E_GADCON_TYPE:
698              if (xdnd) hwin = e_gadcon_xdnd_window_get((E_Gadcon *)(h->obj));
699              else hwin = e_gadcon_dnd_window_get((E_Gadcon *)(h->obj));
700              break;
701
702            case E_GADCON_CLIENT_TYPE:
703              if (xdnd) hwin = e_gadcon_xdnd_window_get(((E_Gadcon_Client *)(h->obj))->gadcon);
704              else hwin = e_gadcon_dnd_window_get(((E_Gadcon_Client *)(h->obj))->gadcon);
705              break;
706
707            case E_WIN_TYPE:
708              hwin = ((E_Win *)(h->obj))->evas_win;
709              break;
710
711            case E_ZONE_TYPE:
712              /* Not quite sure about this, probably need to set up
713               * E_Container to pass DND events from event_win to bg_win. */
714              // hwin = ((E_Zone *)(h->obj))->container->event_win;
715              hwin = ((E_Zone *)(h->obj))->container->event_win;
716              break;
717
718            case E_BORDER_TYPE:
719              hwin = ((E_Border *)(h->obj))->event_win;
720              break;
721
722            case E_POPUP_TYPE:
723              hwin = ((E_Popup *)(h->obj))->evas_win;
724              break;
725
726            /* FIXME: add more types as needed */
727            default:
728              break;
729           }
730      }
731
732    return hwin;
733 }
734
735 static int
736 _e_drag_win_matches(E_Drop_Handler *h, Ecore_X_Window win, int xdnd)
737 {
738    Ecore_X_Window hwin = _e_drag_win_get(h, xdnd);
739
740    if (win == hwin) return 1;
741    return 0;
742 }
743
744 static void
745 _e_drag_win_show(E_Drop_Handler *h)
746 {
747    E_Shelf *shelf;
748
749    if (h->obj)
750      {
751         switch (h->obj->type)
752           {
753            case E_GADCON_TYPE:
754              shelf = e_gadcon_shelf_get((E_Gadcon *)(h->obj));
755              if (shelf) e_shelf_toggle(shelf, 1);
756              break;
757
758            case E_GADCON_CLIENT_TYPE:
759              shelf = e_gadcon_shelf_get(((E_Gadcon_Client *)(h->obj))->gadcon);
760              if (shelf) e_shelf_toggle(shelf, 1);
761              break;
762
763            /* FIXME: add more types as needed */
764            default:
765              break;
766           }
767      }
768 }
769
770 static void
771 _e_drag_win_hide(E_Drop_Handler *h)
772 {
773    E_Shelf *shelf;
774
775    if (h->obj)
776      {
777         switch (h->obj->type)
778           {
779            case E_GADCON_TYPE:
780              shelf = e_gadcon_shelf_get((E_Gadcon *)(h->obj));
781              if (shelf) e_shelf_toggle(shelf, 0);
782              break;
783
784            case E_GADCON_CLIENT_TYPE:
785              shelf = e_gadcon_shelf_get(((E_Gadcon_Client *)(h->obj))->gadcon);
786              if (shelf) e_shelf_toggle(shelf, 0);
787              break;
788
789            /* FIXME: add more types as needed */
790            default:
791              break;
792           }
793      }
794 }
795
796 static int
797 _e_drag_update(Ecore_X_Window root, int x, int y, Ecore_X_Atom action)
798 {
799    const Eina_List *l;
800    E_Event_Dnd_Enter enter_ev;
801    E_Event_Dnd_Move move_ev;
802    E_Event_Dnd_Leave leave_ev;
803    int dx, dy;
804    Ecore_X_Window win, ignore_win[2];
805    int responsive = 0;
806
807 //   double t1 = ecore_time_get(); ////
808    if (_drag_current && !_xdnd)
809      {
810         ignore_win[0] = _drag_current->evas_win;
811         ignore_win[1] = _drag_win;
812         /* FIXME: this is nasty. every x mouse event we go back to x and do
813          * a whole bunch of round-trips narrowing down the toplevel window
814          * which contains the mouse */
815         win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, ignore_win, 2);
816 //      win = ecore_x_window_at_xy_with_skip_get(x, y, ignore_win, 2);
817      }
818    else
819      win = root;
820
821    if (_drag_current)
822      {
823         _e_drag_show(_drag_current);
824         _e_drag_move(_drag_current, x, y);
825      }
826
827    if (_drag_current)
828      {
829         E_Drop_Handler *h;
830
831         EINA_LIST_FOREACH(_drop_handlers, l, h)
832           {
833              if (!h->active) continue;
834              _e_drag_coords_update(h, &dx, &dy);
835              enter_ev.x = x - dx;
836              enter_ev.y = y - dy;
837              enter_ev.data = NULL;
838              enter_ev.action = action;
839              move_ev.x = x - dx;
840              move_ev.y = y - dy;
841              move_ev.action = action;
842              leave_ev.x = x - dx;
843              leave_ev.y = y - dy;
844
845              if (E_INSIDE(enter_ev.x, enter_ev.y, h->x, h->y, h->w, h->h) &&
846                  _e_drag_win_matches(h, win, 0))
847                {
848                   if (e_drop_handler_responsive_get(h)) responsive = 1;
849
850                   if (!h->entered)
851                     {
852                        _e_drag_win_show(h);
853                        if (h->cb.enter)
854                          {
855                             if (_drag_current->cb.convert)
856                               {
857                                  enter_ev.data = _drag_current->cb.convert(_drag_current,
858                                                                            h->active_type);
859                               }
860                             else
861                               enter_ev.data = _drag_current->data;
862                             h->cb.enter(h->cb.data, h->active_type, &enter_ev);
863                          }
864                        h->entered = 1;
865                     }
866                   if (h->cb.move)
867                     h->cb.move(h->cb.data, h->active_type, &move_ev);
868                }
869              else
870                {
871                   if (h->entered)
872                     {
873                        if (h->cb.leave)
874                          h->cb.leave(h->cb.data, h->active_type, &leave_ev);
875                        _e_drag_win_hide(h);
876                        h->entered = 0;
877                     }
878                }
879           }
880      }
881    else if (_xdnd)
882      {
883         E_Drop_Handler *h;
884
885         EINA_LIST_FOREACH(_drop_handlers, l, h)
886           {
887              if (!h->active) continue;
888              _e_drag_coords_update(h, &dx, &dy);
889              enter_ev.x = x - dx;
890              enter_ev.y = y - dy;
891              enter_ev.action = action;
892              move_ev.x = x - dx;
893              move_ev.y = y - dy;
894              move_ev.action = action;
895              leave_ev.x = x - dx;
896              leave_ev.y = y - dy;
897              if (E_INSIDE(enter_ev.x, enter_ev.y, h->x, h->y, h->w, h->h) && _e_drag_win_matches(h, win, 1))
898                {
899                   if (e_drop_handler_responsive_get(h)) responsive = 1;
900
901                   if (!h->entered)
902                     {
903                        if (h->cb.enter)
904                          h->cb.enter(h->cb.data, h->active_type, &enter_ev);
905                        h->entered = 1;
906                     }
907                   if (h->cb.move)
908                     h->cb.move(h->cb.data, h->active_type, &move_ev);
909                }
910              else
911                {
912                   if (h->entered)
913                     {
914                        if (h->cb.leave)
915                          h->cb.leave(h->cb.data, h->active_type, &leave_ev);
916                        h->entered = 0;
917                     }
918                }
919           }
920      }
921
922    return responsive;
923 //   double t2 = ecore_time_get() - t1; ////
924 //   printf("DND UPDATE %3.7f\n", t2); ////
925 }
926
927 static void
928 _e_drag_end(Ecore_X_Window root, int x, int y)
929 {
930    E_Zone *zone;
931    const Eina_List *l;
932    E_Event_Dnd_Drop ev;
933    int dx, dy;
934    Ecore_X_Window win, ignore_win[2];
935    E_Drag *tmp;
936
937    if (!_drag_current) return;
938    ignore_win[0] = _drag_current->evas_win;
939    ignore_win[1] = _drag_win;
940    /* this is nasty - but necessary to get the window stacking */
941    win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, ignore_win, 2);
942 //   win = ecore_x_window_at_xy_with_skip_get(x, y, ignore_win, 2);
943    zone = e_container_zone_at_point_get(_drag_current->container, x, y);
944    /* Pass -1, -1, so that it is possible to drop at the edge. */
945    if (zone) e_zone_flip_coords_handle(zone, -1, -1);
946
947    _e_drag_hide(_drag_current);
948
949    e_grabinput_release(_drag_win, _drag_win);
950    if (_drag_current->type == E_DRAG_XDND)
951      {
952         int dropped;
953
954         if (!(dropped = ecore_x_dnd_drop()))
955           {
956              ecore_x_window_free(_drag_win);
957              _drag_win = 0;
958           }
959         if (_drag_current->cb.finished)
960           _drag_current->cb.finished(_drag_current, dropped);
961
962         if (_drag_current && !_xdnd)
963           {
964              tmp = _drag_current;
965              _drag_current = NULL;
966              e_object_del(E_OBJECT(tmp));
967           }
968         //e_grabinput_release(_drag_win, _drag_win);
969         ecore_x_window_hide(_drag_win);
970         return;
971      }
972
973    ecore_x_window_free(_drag_win);
974    _drag_win = 0;
975
976    if (_drag_current->data)
977      {
978         E_Drop_Handler *h;
979         int dropped = 0;
980
981         EINA_LIST_FOREACH(_drop_handlers, l, h)
982           {
983              if (!h->active) continue;
984              _e_drag_coords_update(h, &dx, &dy);
985              ev.x = x - dx;
986              ev.y = y - dy;
987              if ((_e_drag_win_matches(h, win, 0)) &&
988                  ((h->cb.drop) && (E_INSIDE(ev.x, ev.y, h->x, h->y, h->w, h->h))))
989                {
990                   if (_drag_current->cb.convert)
991                     {
992                        ev.data = _drag_current->cb.convert(_drag_current,
993                                                            h->active_type);
994                     }
995                   else
996                     ev.data = _drag_current->data;
997                   h->cb.drop(h->cb.data, h->active_type, &ev);
998                   dropped = 1;
999                }
1000              h->entered = 0;
1001              if (dropped) break;
1002           }
1003         if (_drag_current->cb.finished)
1004           _drag_current->cb.finished(_drag_current, dropped);
1005
1006         tmp = _drag_current;
1007         _drag_current = NULL;
1008         e_object_del(E_OBJECT(tmp));
1009      }
1010    else
1011      {
1012         /* Just leave */
1013         E_Event_Dnd_Leave leave_ev;
1014         E_Drop_Handler *h;
1015
1016         /* FIXME: We don't need x and y in leave */
1017         leave_ev.x = 0;
1018         leave_ev.y = 0;
1019
1020         EINA_LIST_FOREACH(_drop_handlers, l, h)
1021           {
1022              if (!h->active) continue;
1023
1024              if (h->entered)
1025                {
1026                   if (h->cb.leave)
1027                     h->cb.leave(h->cb.data, h->active_type, &leave_ev);
1028                   h->entered = 0;
1029                }
1030           }
1031      }
1032 }
1033
1034 static void
1035 _e_drag_xdnd_end(Ecore_X_Window win, int x, int y)
1036 {
1037    const Eina_List *l;
1038    E_Event_Dnd_Drop ev;
1039    int dx, dy;
1040
1041    if (!_xdnd) return;
1042
1043    ev.data = _xdnd->data;
1044
1045    if (ev.data)
1046      {
1047         E_Drop_Handler *h;
1048
1049         EINA_LIST_FOREACH(_drop_handlers, l, h)
1050           {
1051              if (!h->active) continue;
1052              _e_drag_coords_update(h, &dx, &dy);
1053              ev.x = x - dx;
1054              ev.y = y - dy;
1055              if (_e_drag_win_matches(h, win, 1) && h->cb.drop
1056                  && E_INSIDE(ev.x, ev.y, h->x, h->y, h->w, h->h))
1057                {
1058                   h->cb.drop(h->cb.data, h->active_type, &ev);
1059                }
1060           }
1061      }
1062    else
1063      {
1064         /* Just leave */
1065         E_Event_Dnd_Leave leave_ev;
1066         E_Drop_Handler *h;
1067
1068         /* FIXME: We don't need x and y in leave */
1069         leave_ev.x = 0;
1070         leave_ev.y = 0;
1071
1072         EINA_LIST_FOREACH(_drop_handlers, l, h)
1073           {
1074              if (!h->active) continue;
1075
1076              if (h->entered)
1077                {
1078                   if (h->cb.leave)
1079                     h->cb.leave(h->cb.data, h->active_type, &leave_ev);
1080                   h->entered = 0;
1081                }
1082           }
1083      }
1084 }
1085
1086 static void
1087 _e_drag_free(E_Drag *drag)
1088 {
1089    unsigned int i;
1090
1091    if (drag == _drag_current)
1092      {
1093         const Eina_List *l;
1094         E_Event_Dnd_Leave leave_ev;
1095         E_Drop_Handler *h;
1096
1097         e_grabinput_release(_drag_win, _drag_win);
1098         ecore_x_window_free(_drag_win);
1099         _drag_win = 0;
1100         _drag_win_root = 0;
1101
1102         leave_ev.x = 0;
1103         leave_ev.y = 0;
1104         EINA_LIST_FOREACH(_drop_handlers, l, h)
1105           {
1106              if ((h->active) && (h->entered))
1107                {
1108                   if (h->cb.leave)
1109                     h->cb.leave(h->cb.data, h->active_type, &leave_ev);
1110                   _e_drag_win_hide(h);
1111                }
1112           }
1113         if (drag->cb.finished)
1114           drag->cb.finished(drag, 0);
1115      }
1116
1117    _drag_current = NULL;
1118
1119    _drag_list = eina_list_remove(_drag_list, drag);
1120
1121    E_FREE(drag->shape_rects);
1122    drag->shape_rects_num = 0;
1123    e_object_unref(E_OBJECT(drag->container));
1124    e_container_shape_hide(drag->shape);
1125    e_object_del(E_OBJECT(drag->shape));
1126    evas_object_del(drag->object);
1127    e_canvas_del(drag->ecore_evas);
1128    ecore_evas_free(drag->ecore_evas);
1129    for (i = 0; i < drag->num_types; i++)
1130      eina_stringshare_del(drag->types[i]);
1131    free(drag);
1132    ecore_x_window_shadow_tree_flush();
1133 }
1134
1135 static Eina_Bool
1136 _e_dnd_cb_window_shape(void *data __UNUSED__, int ev_type __UNUSED__, void *ev)
1137 {
1138    Ecore_X_Event_Window_Shape *e = ev;
1139    const Eina_List *l;
1140    E_Drag *drag;
1141
1142    EINA_LIST_FOREACH(_drag_list, l, drag)
1143      {
1144         if (drag->evas_win == e->win)
1145           drag->need_shape_export = 1;
1146      }
1147    return ECORE_CALLBACK_PASS_ON;
1148 }
1149
1150 static Eina_Bool
1151 _e_dnd_cb_key_down(void *data __UNUSED__, int type __UNUSED__, void *event)
1152 {
1153    Ecore_Event_Key *ev;
1154
1155    ev = event;
1156    if (ev->window != _drag_win) return ECORE_CALLBACK_PASS_ON;
1157
1158    if (!_drag_current) return ECORE_CALLBACK_PASS_ON;
1159
1160    if (_drag_current->cb.key_down)
1161      _drag_current->cb.key_down(_drag_current, ev);
1162
1163    return ECORE_CALLBACK_PASS_ON;
1164 }
1165
1166 static Eina_Bool
1167 _e_dnd_cb_key_up(void *data __UNUSED__, int type __UNUSED__, void *event)
1168 {
1169    Ecore_Event_Key *ev;
1170
1171    ev = event;
1172    if (ev->window != _drag_win) return ECORE_CALLBACK_PASS_ON;
1173
1174    if (!_drag_current) return ECORE_CALLBACK_PASS_ON;
1175
1176    if (_drag_current->cb.key_up)
1177      _drag_current->cb.key_up(_drag_current, ev);
1178
1179    return ECORE_CALLBACK_PASS_ON;
1180 }
1181
1182 static Eina_Bool
1183 _e_dnd_cb_mouse_up(void *data __UNUSED__, int type __UNUSED__, void *event)
1184 {
1185    Ecore_Event_Mouse_Button *ev;
1186
1187    ev = event;
1188    if (ev->window != _drag_win) return ECORE_CALLBACK_PASS_ON;
1189
1190    _e_drag_end(_drag_win_root, ev->x, ev->y);
1191
1192    return ECORE_CALLBACK_PASS_ON;
1193 }
1194
1195 static Eina_Bool
1196 _e_dnd_cb_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event)
1197 {
1198    Ecore_Event_Mouse_Move *ev;
1199
1200    ev = event;
1201    if (ev->window != _drag_win) return ECORE_CALLBACK_PASS_ON;
1202
1203    if (!_xdnd)
1204      _e_drag_update(_drag_win_root, ev->x, ev->y,
1205                     ECORE_X_ATOM_XDND_ACTION_PRIVATE);
1206
1207    return ECORE_CALLBACK_PASS_ON;
1208 }
1209
1210 static Eina_Bool
1211 _e_dnd_cb_event_dnd_enter(void *data __UNUSED__, int type __UNUSED__, void *event)
1212 {
1213    Ecore_X_Event_Xdnd_Enter *ev;
1214    E_Drop_Handler *h;
1215    const char *id;
1216    const Eina_List *l;
1217    unsigned int j;
1218    int i;
1219
1220    ev = event;
1221    id = e_util_winid_str_get(ev->win);
1222    if (!eina_hash_find(_drop_win_hash, id)) return ECORE_CALLBACK_PASS_ON;
1223
1224    EINA_LIST_FOREACH(_drop_handlers, l, h)
1225      {
1226         h->active = 0;
1227         eina_stringshare_del(h->active_type);
1228         h->active_type = NULL;
1229         h->entered = 0;
1230      }
1231    for (i = 0; i < ev->num_types; i++)
1232      {
1233         const char *t = NULL;
1234         /* FIXME: Maybe we want to get something else then files dropped? */
1235         if (!strcmp(_type_text_uri_list, ev->types[i]))
1236           t = eina_stringshare_ref(_type_text_uri_list);
1237         else if (!strcmp(_type_xds, ev->types[i]))
1238           t = eina_stringshare_ref(_type_xds);
1239         if (t)
1240           {
1241              _xdnd = E_NEW(XDnd, 1);
1242              _xdnd->type = t;
1243              EINA_LIST_FOREACH(_drop_handlers, l, h)
1244                {
1245                   h->active = 0;
1246                   eina_stringshare_del(h->active_type);
1247                   h->active_type = NULL;
1248                   for (j = 0; j < h->num_types; j++)
1249                     {
1250                        if (h->types[j] == _xdnd->type)
1251                          {
1252                             h->active = 1;
1253                             h->active_type = eina_stringshare_ref(_xdnd->type);
1254                             break;
1255                          }
1256                     }
1257
1258                   h->entered = 0;
1259                }
1260              break;
1261           }
1262 #if 0
1263         else if ((_type_text_x_moz_url == ev->types[i]) ||
1264                  (!strcmp(_type_text_x_moz_url, ev->types[i])))  /* not sure it is stringshared */
1265           {
1266              _xdnd = E_NEW(XDnd, 1);
1267              _xdnd->type = eina_stringshare_ref(_type_text_x_moz_url);
1268              EINA_LIST_FOREACH(_drop_handlers, l, h)
1269                {
1270                   h->active = (h->type == _type_enlightenment_x_file);
1271                   h->entered = 0;
1272                }
1273              break;
1274           }
1275 #endif
1276      }
1277    return ECORE_CALLBACK_PASS_ON;
1278 }
1279
1280 static Eina_Bool
1281 _e_dnd_cb_event_dnd_leave(void *data __UNUSED__, int type __UNUSED__, void *event)
1282 {
1283    Ecore_X_Event_Xdnd_Leave *ev;
1284    E_Event_Dnd_Leave leave_ev;
1285    const char *id;
1286    const Eina_List *l;
1287
1288    ev = event;
1289
1290    id = e_util_winid_str_get(ev->win);
1291    if (!eina_hash_find(_drop_win_hash, id)) return ECORE_CALLBACK_PASS_ON;
1292
1293    leave_ev.x = 0;
1294    leave_ev.y = 0;
1295
1296    if (_xdnd)
1297      {
1298         E_Drop_Handler *h;
1299
1300         EINA_LIST_FOREACH(_drop_handlers, l, h)
1301           {
1302              if (!h->active) continue;
1303
1304              if (h->entered)
1305                {
1306                   if (h->cb.leave)
1307                     h->cb.leave(h->cb.data, h->active_type, &leave_ev);
1308                   h->entered = 0;
1309                }
1310           }
1311
1312         eina_stringshare_del(_xdnd->type);
1313         E_FREE(_xdnd);
1314      }
1315    return ECORE_CALLBACK_PASS_ON;
1316 }
1317
1318 static Eina_Bool
1319 _e_dnd_cb_event_dnd_position(void *data __UNUSED__, int type __UNUSED__, void *event)
1320 {
1321    Ecore_X_Event_Xdnd_Position *ev;
1322    Ecore_X_Rectangle rect;
1323    const char *id;
1324    const Eina_List *l;
1325    E_Drop_Handler *h;
1326
1327    int active;
1328    int responsive;
1329
1330    ev = event;
1331 //   double t1 = ecore_time_get(); ////
1332    id = e_util_winid_str_get(ev->win);
1333    if (!eina_hash_find(_drop_win_hash, id))
1334      {
1335 //      double t2 = ecore_time_get() - t1; ////
1336 //      printf("DND POS EV 1 %3.7f\n", t2); ////
1337         return ECORE_CALLBACK_PASS_ON;
1338      }
1339
1340    rect.x = 0;
1341    rect.y = 0;
1342    rect.width = 0;
1343    rect.height = 0;
1344
1345    active = 0;
1346    EINA_LIST_FOREACH(_drop_handlers, l, h)
1347      {
1348         if (h->active)
1349           {
1350              active = 1;
1351              break;
1352           }
1353      }
1354    if (!active)
1355      ecore_x_dnd_send_status(0, 0, rect, ECORE_X_DND_ACTION_PRIVATE);
1356    else
1357      {
1358         responsive = _e_drag_update(ev->win, ev->position.x, ev->position.y, ev->action);
1359         if (responsive)
1360           ecore_x_dnd_send_status(1, 0, rect, _action);
1361         else
1362           ecore_x_dnd_send_status(1, 0, rect, ECORE_X_ATOM_XDND_ACTION_PRIVATE);
1363      }
1364 //   double t2 = ecore_time_get() - t1; ////
1365 //   printf("DND POS EV 2 %3.7f\n", t2); ////
1366    return ECORE_CALLBACK_PASS_ON;
1367 }
1368
1369 static Eina_Bool
1370 _e_dnd_cb_event_dnd_status(void *data __UNUSED__, int type __UNUSED__, void *event)
1371 {
1372    Ecore_X_Event_Xdnd_Status *ev;
1373
1374    ev = event;
1375    if (ev->win != _drag_win) return ECORE_CALLBACK_PASS_ON;
1376    return ECORE_CALLBACK_PASS_ON;
1377 }
1378
1379 static Eina_Bool
1380 _e_dnd_cb_event_dnd_finished(void *data __UNUSED__, int type __UNUSED__, void *event)
1381 {
1382    Ecore_X_Event_Xdnd_Finished *ev;
1383
1384    ev = event;
1385
1386    if (!ev->completed) return ECORE_CALLBACK_PASS_ON;
1387
1388    if (_drag_current)
1389      {
1390         E_Drag *tmp;
1391
1392         tmp = _drag_current;
1393         _drag_current = NULL;
1394         e_object_del(E_OBJECT(tmp));
1395      }
1396
1397    ecore_x_window_free(_drag_win);
1398    _drag_win = 0;
1399
1400    return ECORE_CALLBACK_PASS_ON;
1401 }
1402
1403 static Eina_Bool
1404 _e_dnd_cb_event_dnd_drop(void *data __UNUSED__, int type __UNUSED__, void *event)
1405 {
1406    Ecore_X_Event_Xdnd_Drop *ev;
1407    const char *id;
1408
1409    ev = event;
1410    id = e_util_winid_str_get(ev->win);
1411    if (!eina_hash_find(_drop_win_hash, id)) return ECORE_CALLBACK_PASS_ON;
1412
1413    if (_xdnd)
1414      {
1415         E_Drop_Handler *h;
1416         Eina_Bool req = EINA_TRUE;
1417         Eina_List *l;
1418
1419         EINA_LIST_FOREACH(_drop_handlers, l, h)
1420           {
1421              if (!h->active) continue;
1422              if (_e_drag_win_matches(h, ev->win, 1) && h->entered && h->cb.xds)
1423                {
1424                   req = h->cb.xds(h->cb.data);
1425                }
1426           }
1427         if (req) ecore_x_selection_xdnd_request(ev->win, _xdnd->type);
1428
1429         _xdnd->x = ev->position.x;
1430         _xdnd->y = ev->position.y;
1431         if (!req)
1432           {
1433              _e_drag_xdnd_end(ev->win, _xdnd->x, _xdnd->y);
1434              ecore_x_dnd_send_finished();
1435              eina_stringshare_del(_xdnd->type);
1436              E_FREE(_xdnd);
1437           }
1438      }
1439
1440    return ECORE_CALLBACK_PASS_ON;
1441 }
1442
1443 static Eina_Bool
1444 _e_dnd_cb_event_dnd_selection(void *data __UNUSED__, int type __UNUSED__, void *event)
1445 {
1446    Ecore_X_Event_Selection_Notify *ev;
1447    const char *id;
1448    int i;
1449
1450    ev = event;
1451    id = e_util_winid_str_get(ev->win);
1452    if (!eina_hash_find(_drop_win_hash, id)) return ECORE_CALLBACK_PASS_ON;
1453    if (ev->selection != ECORE_X_SELECTION_XDND) return ECORE_CALLBACK_PASS_ON;
1454
1455    if (_type_text_uri_list == _xdnd->type)
1456      {
1457         Ecore_X_Selection_Data_Files *files;
1458         Eina_List *l = NULL;
1459
1460         files = ev->data;
1461         for (i = 0; i < files->num_files; i++)
1462           {
1463              /* TODO: Check if hostname is in file:// uri */
1464              if (!strncmp(files->files[i], "file://", 7))
1465                l = eina_list_append(l, files->files[i]);
1466              /* TODO: download files
1467                 else if (!strncmp(files->files[i], "http://", 7))
1468                 else if (!strncmp(files->files[i], "ftp://", 6))
1469               */
1470              else
1471                l = eina_list_append(l, files->files[i]);
1472           }
1473         _xdnd->data = l;
1474         _e_drag_xdnd_end(ev->win, _xdnd->x, _xdnd->y);
1475         eina_list_free(l);
1476      }
1477    else if (_type_text_x_moz_url == _xdnd->type)
1478      {
1479         /* FIXME: Create a ecore x parser for this type */
1480         Ecore_X_Selection_Data *sdata;
1481         Eina_List *l = NULL;
1482         char file[PATH_MAX];
1483         char *text;
1484         int size;
1485
1486         sdata = ev->data;
1487         text = (char *)sdata->data;
1488         size = MIN(sdata->length, PATH_MAX - 1);
1489         /* A moz url _shall_ contain a space */
1490         /* FIXME: The data is two-byte unicode. Somewhere it
1491          * is written that the url and the text is separated by
1492          * a space, but it seems like they are separated by
1493          * newline
1494          */
1495         for (i = 0; i < size; i++)
1496           {
1497              file[i] = text[i];
1498 //           printf("'%d-%c' ", text[i], text[i]);
1499              /*
1500                 if (text[i] == ' ')
1501                 {
1502                   file[i] = '\0';
1503                   break;
1504                 }
1505               */
1506           }
1507 //      printf("\n");
1508         file[i] = '\0';
1509 //      printf("file: %d \"%s\"\n", i, file);
1510         l = eina_list_append(l, file);
1511
1512         _xdnd->data = l;
1513         _e_drag_xdnd_end(ev->win, _xdnd->x, _xdnd->y);
1514         eina_list_free(l);
1515      }
1516    else
1517      _e_drag_xdnd_end(ev->win, _xdnd->x, _xdnd->y);
1518    /* FIXME: When to execute this? It could be executed in ecore_x after getting
1519     * the drop property... */
1520    ecore_x_dnd_send_finished();
1521    eina_stringshare_del(_xdnd->type);
1522    E_FREE(_xdnd);
1523    return ECORE_CALLBACK_PASS_ON;
1524 }
1525