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