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