3 /* FIXME: broken when drop areas intersect
4 * (sub window has drop area on top of lower window or desktop)
8 * - Let an internal drag work with several types.
9 * - Let a drag be both internal and external, or allow internal xdnd
10 * (internal xdnd is unnecessary load)
13 /* local subsystem functions */
15 static void _e_drag_show(E_Drag *drag);
16 static void _e_drag_hide(E_Drag *drag);
17 static void _e_drag_move(E_Drag *drag, int x, int y);
18 static void _e_drag_coords_update(const E_Drop_Handler *h, int *dx, int *dy);
19 static Ecore_X_Window _e_drag_win_get(const E_Drop_Handler *h, int xdnd);
20 static int _e_drag_win_matches(E_Drop_Handler *h, Ecore_X_Window win, int xdnd);
21 static void _e_drag_win_show(E_Drop_Handler *h);
22 static void _e_drag_win_hide(E_Drop_Handler *h);
23 static int _e_drag_update(Ecore_X_Window root, int x, int y, Ecore_X_Atom action);
24 static void _e_drag_end(Ecore_X_Window root, int x, int y);
25 static void _e_drag_xdnd_end(Ecore_X_Window root, int x, int y);
26 static void _e_drag_free(E_Drag *drag);
28 static Eina_Bool _e_dnd_cb_window_shape(void *data, int type, void *event);
30 static Eina_Bool _e_dnd_cb_key_down(void *data, int type, void *event);
31 static Eina_Bool _e_dnd_cb_key_up(void *data, int type, void *event);
32 static Eina_Bool _e_dnd_cb_mouse_up(void *data, int type, void *event);
33 static Eina_Bool _e_dnd_cb_mouse_move(void *data, int type, void *event);
34 static Eina_Bool _e_dnd_cb_event_dnd_enter(void *data, int type, void *event);
35 static Eina_Bool _e_dnd_cb_event_dnd_leave(void *data, int type, void *event);
36 static Eina_Bool _e_dnd_cb_event_dnd_position(void *data, int type, void *event);
37 static Eina_Bool _e_dnd_cb_event_dnd_status(void *data, int type, void *event);
38 static Eina_Bool _e_dnd_cb_event_dnd_finished(void *data, int type, void *event);
39 static Eina_Bool _e_dnd_cb_event_dnd_drop(void *data, int type, void *event);
40 static Eina_Bool _e_dnd_cb_event_dnd_selection(void *data, int type, void *event);
42 /* local subsystem globals */
44 typedef struct _XDnd XDnd;
53 static Eina_List *_event_handlers = NULL;
54 static Eina_List *_drop_handlers = NULL;
55 static Eina_Hash *_drop_win_hash = NULL;
57 static Ecore_X_Window _drag_win = 0;
58 static Ecore_X_Window _drag_win_root = 0;
60 static Eina_List *_drag_list = NULL;
61 static E_Drag *_drag_current = NULL;
63 static XDnd *_xdnd = NULL;
64 #define XDS_ATOM "XdndDirectSave0"
65 static Ecore_X_Atom _xds_atom = 0;
66 static Ecore_X_Atom _text_atom = 0;
67 static const char *_type_text_uri_list = NULL;
68 static const char *_type_xds = NULL;
69 static const char *_type_text_x_moz_url = NULL;
70 static const char *_type_enlightenment_x_file = NULL;
72 static Eina_Hash *_drop_handlers_responsives;
73 static Ecore_X_Atom _action;
75 /* externally accessible functions */
80 _type_text_uri_list = eina_stringshare_add("text/uri-list");
81 _type_xds = eina_stringshare_add(XDS_ATOM);
82 _type_text_x_moz_url = eina_stringshare_add("text/x-moz-url");
83 _type_enlightenment_x_file = eina_stringshare_add("enlightenment/x-file");
84 _xds_atom = ecore_x_atom_get(XDS_ATOM);
85 _text_atom = ecore_x_atom_get("text/plain");
87 _drop_win_hash = eina_hash_string_superfast_new(NULL);
88 _drop_handlers_responsives = eina_hash_string_superfast_new(NULL);
90 _event_handlers = eina_list_append(_event_handlers,
91 ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
92 _e_dnd_cb_mouse_up, NULL));
93 _event_handlers = eina_list_append(_event_handlers,
94 ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
95 _e_dnd_cb_mouse_move, NULL));
96 _event_handlers = eina_list_append(_event_handlers,
97 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHAPE,
98 _e_dnd_cb_window_shape, NULL));
100 _event_handlers = eina_list_append(_event_handlers,
101 ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
102 _e_dnd_cb_event_dnd_enter, NULL));
103 _event_handlers = eina_list_append(_event_handlers,
104 ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE,
105 _e_dnd_cb_event_dnd_leave, NULL));
106 _event_handlers = eina_list_append(_event_handlers,
107 ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
108 _e_dnd_cb_event_dnd_position, NULL));
109 _event_handlers = eina_list_append(_event_handlers,
110 ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
111 _e_dnd_cb_event_dnd_status, NULL));
112 _event_handlers = eina_list_append(_event_handlers,
113 ecore_event_handler_add(ECORE_X_EVENT_XDND_FINISHED,
114 _e_dnd_cb_event_dnd_finished, NULL));
115 _event_handlers = eina_list_append(_event_handlers,
116 ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
117 _e_dnd_cb_event_dnd_drop, NULL));
118 _event_handlers = eina_list_append(_event_handlers,
119 ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY,
120 _e_dnd_cb_event_dnd_selection, NULL));
121 _event_handlers = eina_list_append(_event_handlers,
122 ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
123 _e_dnd_cb_key_down, NULL));
124 _event_handlers = eina_list_append(_event_handlers,
125 ecore_event_handler_add(ECORE_EVENT_KEY_UP,
126 _e_dnd_cb_key_up, NULL));
128 _action = ECORE_X_ATOM_XDND_ACTION_PRIVATE;
135 E_FREE_LIST(_drag_list, e_object_del);
137 E_FREE_LIST(_drop_handlers, e_drop_handler_del);
139 E_FREE_LIST(_event_handlers, ecore_event_handler_del);
141 eina_hash_free(_drop_win_hash);
143 eina_hash_free(_drop_handlers_responsives);
145 eina_stringshare_del(_type_text_uri_list);
146 eina_stringshare_del(_type_xds);
147 eina_stringshare_del(_type_text_x_moz_url);
148 eina_stringshare_del(_type_enlightenment_x_file);
149 _type_text_uri_list = NULL;
151 _type_text_x_moz_url = NULL;
152 _type_enlightenment_x_file = NULL;
153 _text_atom = _xds_atom = 0;
159 e_drag_new(E_Container *container, int x, int y,
160 const char **types, unsigned int num_types,
161 void *data, int size,
162 void *(*convert_cb)(E_Drag * drag, const char *type),
163 void (*finished_cb)(E_Drag *drag, int dropped))
168 /* No need to create a drag object without type */
169 if ((!types) || (!num_types)) return NULL;
170 drag = e_object_alloc(sizeof(E_Drag) + num_types * sizeof(char *),
171 E_DRAG_TYPE, E_OBJECT_CLEANUP_FUNC(_e_drag_free));
172 if (!drag) return NULL;
179 drag->container = container;
180 e_object_ref(E_OBJECT(drag->container));
181 drag->ecore_evas = e_canvas_new(drag->container->win,
182 drag->x, drag->y, drag->w, drag->h, 1, 1,
184 if (e_config->use_composite)
185 ecore_evas_alpha_set(drag->ecore_evas, 1);
188 /* avoid excess exposes when shaped - set damage avoid to 1 */
189 ecore_evas_avoid_damage_set(drag->ecore_evas, 1);
190 ecore_evas_shaped_set(drag->ecore_evas, 1);
191 ecore_x_window_shape_events_select(drag->evas_win, 1);
194 e_canvas_add(drag->ecore_evas);
195 drag->shape = e_container_shape_add(drag->container);
196 e_container_shape_move(drag->shape, drag->x, drag->y);
197 e_container_shape_resize(drag->shape, drag->w, drag->h);
199 drag->evas = ecore_evas_get(drag->ecore_evas);
200 e_container_window_raise(drag->container, drag->evas_win, drag->layer);
202 ecore_evas_name_class_set(drag->ecore_evas, "E", "_e_drag_window");
203 ecore_evas_title_set(drag->ecore_evas, "E Drag");
204 ecore_evas_ignore_events_set(drag->ecore_evas, 1);
206 drag->object = evas_object_rectangle_add(drag->evas);
207 evas_object_color_set(drag->object, 255, 0, 0, 255);
208 evas_object_show(drag->object);
210 evas_object_move(drag->object, 0, 0);
211 evas_object_resize(drag->object, drag->w, drag->h);
212 ecore_evas_resize(drag->ecore_evas, drag->w, drag->h);
214 drag->type = E_DRAG_NONE;
216 for (i = 0; i < num_types; i++)
217 drag->types[i] = eina_stringshare_add(types[i]);
218 drag->num_types = num_types;
220 drag->data_size = size;
221 drag->cb.convert = convert_cb;
222 drag->cb.finished = finished_cb;
224 _drag_list = eina_list_append(_drag_list, drag);
226 ecore_x_window_shadow_tree_flush();
228 _drag_win_root = drag->container->manager->root;
230 drag->cb.key_down = NULL;
231 drag->cb.key_up = NULL;
237 e_drag_evas_get(const E_Drag *drag)
243 e_drag_object_set(E_Drag *drag, Evas_Object *object)
245 if (drag->object) evas_object_del(drag->object);
246 drag->object = object;
247 evas_object_resize(drag->object, drag->w, drag->h);
251 e_drag_move(E_Drag *drag, int x, int y)
253 if ((drag->x == x) && (drag->y == y)) return;
260 e_drag_resize(E_Drag *drag, int w, int h)
262 if ((drag->w == w) && (drag->h == h)) return;
265 evas_object_resize(drag->object, drag->w, drag->h);
266 ecore_evas_resize(drag->ecore_evas, drag->w, drag->h);
267 e_container_shape_resize(drag->shape, drag->w, drag->h);
273 return _drag_win != 0;
277 e_drag_start(E_Drag *drag, int x, int y)
282 if (_drag_win) return 0;
283 _drag_win = ecore_x_window_input_new(drag->container->win,
284 drag->container->x, drag->container->y,
285 drag->container->w, drag->container->h);
286 _drag_win_root = drag->container->manager->root;
287 ecore_x_window_show(_drag_win);
288 if (!e_grabinput_get(_drag_win, 1, _drag_win))
290 ecore_x_window_free(_drag_win);
294 drag->type = E_DRAG_INTERNAL;
296 drag->dx = x - drag->x;
297 drag->dy = y - drag->y;
299 EINA_LIST_FOREACH(_drop_handlers, l, h)
304 eina_stringshare_del(h->active_type);
305 h->active_type = NULL;
306 for (i = 0; i < h->num_types; i++)
308 for (j = 0; j < drag->num_types; j++)
310 if (h->types[i] == drag->types[j])
313 h->active_type = eina_stringshare_ref(h->types[i]);
317 if (h->active) break;
322 _drag_current = drag;
327 e_drag_xdnd_start(E_Drag *drag, int x, int y)
329 Ecore_X_Atom actions[] = {
330 ECORE_X_DND_ACTION_MOVE, ECORE_X_DND_ACTION_PRIVATE,
331 ECORE_X_DND_ACTION_COPY, ECORE_X_DND_ACTION_ASK,
332 ECORE_X_DND_ACTION_LINK
334 if (_drag_win) return 0;
335 _drag_win = ecore_x_window_input_new(drag->container->win,
336 drag->container->x, drag->container->y,
337 drag->container->w, drag->container->h);
339 ecore_x_window_show(_drag_win);
340 if (!e_grabinput_get(_drag_win, 1, _drag_win))
342 ecore_x_window_free(_drag_win);
346 drag->type = E_DRAG_XDND;
348 drag->dx = x - drag->x;
349 drag->dy = y - drag->y;
351 ecore_x_dnd_aware_set(_drag_win, 1);
352 ecore_x_dnd_types_set(_drag_win, drag->types, drag->num_types);
353 ecore_x_dnd_actions_set(_drag_win, actions, 5);
354 ecore_x_dnd_begin(_drag_win, drag->data, drag->data_size);
356 _drag_current = drag;
361 e_drop_handler_xds_set(E_Drop_Handler *handler, Ecore_Task_Cb cb)
363 handler->cb.xds = cb;
366 /* should only be used for windows */
368 e_drop_xds_update(Eina_Bool enable, const char *value)
371 char buf[PATH_MAX + 8];
378 xwin = ecore_x_selection_owner_get(ECORE_X_ATOM_SELECTION_XDND);
381 if (!ecore_x_window_prop_property_get(xwin, _xds_atom, _text_atom, 8, (unsigned char **)&file, &size))
384 if (size + len + 8 + 1 > sizeof(buf))
389 snprintf(buf, sizeof(buf), "file://%s/", value);
390 strncat(buf, file, size);
392 ecore_x_window_prop_property_set(xwin, _xds_atom, _text_atom, 8, (void*)buf, size + len + 8);
395 ecore_x_window_prop_property_del(xwin, _xds_atom);
398 EAPI E_Drop_Handler *
399 e_drop_handler_add(E_Object *obj,
401 void (*enter_cb)(void *data, const char *type, void *event),
402 void (*move_cb)(void *data, const char *type, void *event),
403 void (*leave_cb)(void *data, const char *type, void *event),
404 void (*drop_cb)(void *data, const char *type, void *event),
405 const char **types, unsigned int num_types, int x, int y, int w, int h)
407 E_Drop_Handler *handler;
410 handler = calloc(1, sizeof(E_Drop_Handler) + num_types * sizeof(char *));
411 if (!handler) return NULL;
413 handler->cb.data = data;
414 handler->cb.enter = enter_cb;
415 handler->cb.move = move_cb;
416 handler->cb.leave = leave_cb;
417 handler->cb.drop = drop_cb;
418 handler->num_types = num_types;
419 for (i = 0; i < num_types; i++)
420 handler->types[i] = eina_stringshare_add(types[i]);
427 handler->entered = 0;
429 _drop_handlers = eina_list_append(_drop_handlers, handler);
435 e_drop_handler_geometry_set(E_Drop_Handler *handler, int x, int y, int w, int h)
444 e_drop_inside(const E_Drop_Handler *handler, int x, int y)
448 _e_drag_coords_update(handler, &dx, &dy);
451 return E_INSIDE(x, y, handler->x, handler->y, handler->w, handler->h);
455 e_drop_handler_del(E_Drop_Handler *handler)
462 _drop_handlers = eina_list_remove(_drop_handlers, handler);
463 for (i = 0; i < handler->num_types; i++)
464 eina_stringshare_del(handler->types[i]);
465 eina_stringshare_del(handler->active_type);
470 e_drop_xdnd_register_set(Ecore_X_Window win, int reg)
474 id = e_util_winid_str_get(win);
477 if (!eina_hash_find(_drop_win_hash, id))
479 ecore_x_dnd_aware_set(win, 1);
480 eina_hash_add(_drop_win_hash, id, (void *)1);
485 ecore_x_dnd_aware_set(win, 0);
486 eina_hash_del(_drop_win_hash, id, (void *)1);
492 e_drag_idler_before(void)
497 EINA_LIST_FOREACH(_drag_list, l, drag)
499 if (drag->need_shape_export)
501 Ecore_X_Rectangle *rects, *orects;
504 rects = ecore_x_window_shape_rectangles_get(drag->evas_win, &num);
510 if ((num == drag->shape_rects_num) && (drag->shape_rects))
514 orects = drag->shape_rects;
515 for (i = 0; i < num; i++)
517 if ((orects[i].x != rects[i].x) ||
518 (orects[i].y != rects[i].y) ||
519 (orects[i].width != rects[i].width) ||
520 (orects[i].height != rects[i].height))
526 // TODO: This is meaningless
531 E_FREE(drag->shape_rects);
532 drag->shape_rects = rects;
533 drag->shape_rects_num = num;
534 e_container_shape_rects_set(drag->shape, rects, num);
541 E_FREE(drag->shape_rects);
542 drag->shape_rects = NULL;
543 drag->shape_rects_num = 0;
544 e_container_shape_rects_set(drag->shape, NULL, 0);
546 drag->need_shape_export = 0;
548 e_container_shape_show(drag->shape);
552 ecore_evas_move(drag->ecore_evas, drag->x, drag->y);
553 e_container_shape_move(drag->shape, drag->x, drag->y);
560 e_drop_handler_responsive_set(E_Drop_Handler *handler)
562 Ecore_X_Window hwin = _e_drag_win_get(handler, 1);
563 const char *wid = e_util_winid_str_get(hwin);
565 eina_hash_add(_drop_handlers_responsives, wid, (void *)handler);
569 e_drop_handler_responsive_get(const E_Drop_Handler *handler)
571 Ecore_X_Window hwin = _e_drag_win_get(handler, 1);
572 const char *wid = e_util_winid_str_get(hwin);
574 return eina_hash_find(_drop_handlers_responsives, wid) == (void *)handler;
578 e_drop_handler_action_set(Ecore_X_Atom action)
584 e_drop_handler_action_get(void)
590 e_drag_key_down_cb_set(E_Drag *drag, void (*func)(E_Drag *drag, Ecore_Event_Key *e))
592 drag->cb.key_down = func;
596 e_drag_key_up_cb_set(E_Drag *drag, void (*func)(E_Drag *drag, Ecore_Event_Key *e))
598 drag->cb.key_up = func;
601 /* local subsystem functions */
604 _e_drag_show(E_Drag *drag)
606 if (drag->visible) return;
608 evas_object_show(drag->object);
609 ecore_evas_show(drag->ecore_evas);
610 e_container_shape_show(drag->shape);
614 _e_drag_hide(E_Drag *drag)
616 if (!drag->visible) return;
618 evas_object_hide(drag->object);
619 ecore_evas_hide(drag->ecore_evas);
620 e_container_shape_hide(drag->shape);
624 _e_drag_move(E_Drag *drag, int x, int y)
628 if (((drag->x + drag->dx) == x) && ((drag->y + drag->dy) == y)) return;
630 zone = e_container_zone_at_point_get(drag->container, x, y);
631 if (zone) e_zone_flip_coords_handle(zone, x, y);
633 drag->x = x - drag->dx;
634 drag->y = y - drag->dy;
639 _e_drag_coords_update(const E_Drop_Handler *h, int *dx, int *dy)
647 switch (h->obj->type)
650 e_gadcon_canvas_zone_geometry_get((E_Gadcon *)(h->obj), &px, &py, NULL, NULL);
653 case E_GADCON_CLIENT_TYPE:
654 e_gadcon_canvas_zone_geometry_get(((E_Gadcon_Client *)(h->obj))->gadcon, &px, &py, NULL, NULL);
658 px = ((E_Win *)(h->obj))->x;
659 py = ((E_Win *)(h->obj))->y;
663 // zone based drag targets are in a container thus their coords should be
664 // screen-relative as containers just cover the screen
665 // px = ((E_Zone *)(h->obj))->x;
666 // py = ((E_Zone *)(h->obj))->y;
670 px = ((E_Border *)(h->obj))->x + ((E_Border *)(h->obj))->fx.x;
671 py = ((E_Border *)(h->obj))->y + ((E_Border *)(h->obj))->fx.y;
675 px = ((E_Popup *)(h->obj))->x;
676 py = ((E_Popup *)(h->obj))->y;
679 /* FIXME: add more types as needed */
688 static Ecore_X_Window
689 _e_drag_win_get(const E_Drop_Handler *h, int xdnd)
691 Ecore_X_Window hwin = 0;
695 switch (h->obj->type)
698 if (xdnd) hwin = e_gadcon_xdnd_window_get((E_Gadcon *)(h->obj));
699 else hwin = e_gadcon_dnd_window_get((E_Gadcon *)(h->obj));
702 case E_GADCON_CLIENT_TYPE:
703 if (xdnd) hwin = e_gadcon_xdnd_window_get(((E_Gadcon_Client *)(h->obj))->gadcon);
704 else hwin = e_gadcon_dnd_window_get(((E_Gadcon_Client *)(h->obj))->gadcon);
708 hwin = ((E_Win *)(h->obj))->evas_win;
712 /* Not quite sure about this, probably need to set up
713 * E_Container to pass DND events from event_win to bg_win. */
714 // hwin = ((E_Zone *)(h->obj))->container->event_win;
715 hwin = ((E_Zone *)(h->obj))->container->event_win;
719 hwin = ((E_Border *)(h->obj))->event_win;
723 hwin = ((E_Popup *)(h->obj))->evas_win;
726 /* FIXME: add more types as needed */
736 _e_drag_win_matches(E_Drop_Handler *h, Ecore_X_Window win, int xdnd)
738 Ecore_X_Window hwin = _e_drag_win_get(h, xdnd);
740 if (win == hwin) return 1;
745 _e_drag_win_show(E_Drop_Handler *h)
751 switch (h->obj->type)
754 shelf = e_gadcon_shelf_get((E_Gadcon *)(h->obj));
755 if (shelf) e_shelf_toggle(shelf, 1);
758 case E_GADCON_CLIENT_TYPE:
759 shelf = e_gadcon_shelf_get(((E_Gadcon_Client *)(h->obj))->gadcon);
760 if (shelf) e_shelf_toggle(shelf, 1);
763 /* FIXME: add more types as needed */
771 _e_drag_win_hide(E_Drop_Handler *h)
777 switch (h->obj->type)
780 shelf = e_gadcon_shelf_get((E_Gadcon *)(h->obj));
781 if (shelf) e_shelf_toggle(shelf, 0);
784 case E_GADCON_CLIENT_TYPE:
785 shelf = e_gadcon_shelf_get(((E_Gadcon_Client *)(h->obj))->gadcon);
786 if (shelf) e_shelf_toggle(shelf, 0);
789 /* FIXME: add more types as needed */
797 _e_drag_update(Ecore_X_Window root, int x, int y, Ecore_X_Atom action)
800 E_Event_Dnd_Enter enter_ev;
801 E_Event_Dnd_Move move_ev;
802 E_Event_Dnd_Leave leave_ev;
804 Ecore_X_Window win, ignore_win[2];
807 // double t1 = ecore_time_get(); ////
808 if (_drag_current && !_xdnd)
810 ignore_win[0] = _drag_current->evas_win;
811 ignore_win[1] = _drag_win;
812 /* FIXME: this is nasty. every x mouse event we go back to x and do
813 * a whole bunch of round-trips narrowing down the toplevel window
814 * which contains the mouse */
815 win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, ignore_win, 2);
816 // win = ecore_x_window_at_xy_with_skip_get(x, y, ignore_win, 2);
823 _e_drag_show(_drag_current);
824 _e_drag_move(_drag_current, x, y);
831 EINA_LIST_FOREACH(_drop_handlers, l, h)
833 if (!h->active) continue;
834 _e_drag_coords_update(h, &dx, &dy);
837 enter_ev.data = NULL;
838 enter_ev.action = action;
841 move_ev.action = action;
845 if (E_INSIDE(enter_ev.x, enter_ev.y, h->x, h->y, h->w, h->h) &&
846 _e_drag_win_matches(h, win, 0))
848 if (e_drop_handler_responsive_get(h)) responsive = 1;
855 if (_drag_current->cb.convert)
857 enter_ev.data = _drag_current->cb.convert(_drag_current,
861 enter_ev.data = _drag_current->data;
862 h->cb.enter(h->cb.data, h->active_type, &enter_ev);
867 h->cb.move(h->cb.data, h->active_type, &move_ev);
874 h->cb.leave(h->cb.data, h->active_type, &leave_ev);
885 EINA_LIST_FOREACH(_drop_handlers, l, h)
887 if (!h->active) continue;
888 _e_drag_coords_update(h, &dx, &dy);
891 enter_ev.action = action;
894 move_ev.action = action;
897 if (E_INSIDE(enter_ev.x, enter_ev.y, h->x, h->y, h->w, h->h) && _e_drag_win_matches(h, win, 1))
899 if (e_drop_handler_responsive_get(h)) responsive = 1;
904 h->cb.enter(h->cb.data, h->active_type, &enter_ev);
908 h->cb.move(h->cb.data, h->active_type, &move_ev);
915 h->cb.leave(h->cb.data, h->active_type, &leave_ev);
923 // double t2 = ecore_time_get() - t1; ////
924 // printf("DND UPDATE %3.7f\n", t2); ////
928 _e_drag_end(Ecore_X_Window root, int x, int y)
934 Ecore_X_Window win, ignore_win[2];
937 if (!_drag_current) return;
938 ignore_win[0] = _drag_current->evas_win;
939 ignore_win[1] = _drag_win;
940 /* this is nasty - but necessary to get the window stacking */
941 win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, ignore_win, 2);
942 // win = ecore_x_window_at_xy_with_skip_get(x, y, ignore_win, 2);
943 zone = e_container_zone_at_point_get(_drag_current->container, x, y);
944 /* Pass -1, -1, so that it is possible to drop at the edge. */
945 if (zone) e_zone_flip_coords_handle(zone, -1, -1);
947 _e_drag_hide(_drag_current);
949 e_grabinput_release(_drag_win, _drag_win);
950 if (_drag_current->type == E_DRAG_XDND)
954 if (!(dropped = ecore_x_dnd_drop()))
956 ecore_x_window_free(_drag_win);
959 if (_drag_current->cb.finished)
960 _drag_current->cb.finished(_drag_current, dropped);
962 if (_drag_current && !_xdnd)
965 _drag_current = NULL;
966 e_object_del(E_OBJECT(tmp));
968 //e_grabinput_release(_drag_win, _drag_win);
969 ecore_x_window_hide(_drag_win);
973 ecore_x_window_free(_drag_win);
976 if (_drag_current->data)
981 EINA_LIST_FOREACH(_drop_handlers, l, h)
983 if (!h->active) continue;
984 _e_drag_coords_update(h, &dx, &dy);
987 if ((_e_drag_win_matches(h, win, 0)) &&
988 ((h->cb.drop) && (E_INSIDE(ev.x, ev.y, h->x, h->y, h->w, h->h))))
990 if (_drag_current->cb.convert)
992 ev.data = _drag_current->cb.convert(_drag_current,
996 ev.data = _drag_current->data;
997 h->cb.drop(h->cb.data, h->active_type, &ev);
1003 if (_drag_current->cb.finished)
1004 _drag_current->cb.finished(_drag_current, dropped);
1006 tmp = _drag_current;
1007 _drag_current = NULL;
1008 e_object_del(E_OBJECT(tmp));
1013 E_Event_Dnd_Leave leave_ev;
1016 /* FIXME: We don't need x and y in leave */
1020 EINA_LIST_FOREACH(_drop_handlers, l, h)
1022 if (!h->active) continue;
1027 h->cb.leave(h->cb.data, h->active_type, &leave_ev);
1035 _e_drag_xdnd_end(Ecore_X_Window win, int x, int y)
1038 E_Event_Dnd_Drop ev;
1043 ev.data = _xdnd->data;
1049 EINA_LIST_FOREACH(_drop_handlers, l, h)
1051 if (!h->active) continue;
1052 _e_drag_coords_update(h, &dx, &dy);
1055 if (_e_drag_win_matches(h, win, 1) && h->cb.drop
1056 && E_INSIDE(ev.x, ev.y, h->x, h->y, h->w, h->h))
1058 h->cb.drop(h->cb.data, h->active_type, &ev);
1065 E_Event_Dnd_Leave leave_ev;
1068 /* FIXME: We don't need x and y in leave */
1072 EINA_LIST_FOREACH(_drop_handlers, l, h)
1074 if (!h->active) continue;
1079 h->cb.leave(h->cb.data, h->active_type, &leave_ev);
1087 _e_drag_free(E_Drag *drag)
1091 if (drag == _drag_current)
1094 E_Event_Dnd_Leave leave_ev;
1097 e_grabinput_release(_drag_win, _drag_win);
1098 ecore_x_window_free(_drag_win);
1104 EINA_LIST_FOREACH(_drop_handlers, l, h)
1106 if ((h->active) && (h->entered))
1109 h->cb.leave(h->cb.data, h->active_type, &leave_ev);
1110 _e_drag_win_hide(h);
1113 if (drag->cb.finished)
1114 drag->cb.finished(drag, 0);
1117 _drag_current = NULL;
1119 _drag_list = eina_list_remove(_drag_list, drag);
1121 E_FREE(drag->shape_rects);
1122 drag->shape_rects_num = 0;
1123 e_object_unref(E_OBJECT(drag->container));
1124 e_container_shape_hide(drag->shape);
1125 e_object_del(E_OBJECT(drag->shape));
1126 evas_object_del(drag->object);
1127 e_canvas_del(drag->ecore_evas);
1128 ecore_evas_free(drag->ecore_evas);
1129 for (i = 0; i < drag->num_types; i++)
1130 eina_stringshare_del(drag->types[i]);
1132 ecore_x_window_shadow_tree_flush();
1136 _e_dnd_cb_window_shape(void *data __UNUSED__, int ev_type __UNUSED__, void *ev)
1138 Ecore_X_Event_Window_Shape *e = ev;
1142 EINA_LIST_FOREACH(_drag_list, l, drag)
1144 if (drag->evas_win == e->win)
1145 drag->need_shape_export = 1;
1147 return ECORE_CALLBACK_PASS_ON;
1151 _e_dnd_cb_key_down(void *data __UNUSED__, int type __UNUSED__, void *event)
1153 Ecore_Event_Key *ev;
1156 if (ev->window != _drag_win) return ECORE_CALLBACK_PASS_ON;
1158 if (!_drag_current) return ECORE_CALLBACK_PASS_ON;
1160 if (_drag_current->cb.key_down)
1161 _drag_current->cb.key_down(_drag_current, ev);
1163 return ECORE_CALLBACK_PASS_ON;
1167 _e_dnd_cb_key_up(void *data __UNUSED__, int type __UNUSED__, void *event)
1169 Ecore_Event_Key *ev;
1172 if (ev->window != _drag_win) return ECORE_CALLBACK_PASS_ON;
1174 if (!_drag_current) return ECORE_CALLBACK_PASS_ON;
1176 if (_drag_current->cb.key_up)
1177 _drag_current->cb.key_up(_drag_current, ev);
1179 return ECORE_CALLBACK_PASS_ON;
1183 _e_dnd_cb_mouse_up(void *data __UNUSED__, int type __UNUSED__, void *event)
1185 Ecore_Event_Mouse_Button *ev;
1188 if (ev->window != _drag_win) return ECORE_CALLBACK_PASS_ON;
1190 _e_drag_end(_drag_win_root, ev->x, ev->y);
1192 return ECORE_CALLBACK_PASS_ON;
1196 _e_dnd_cb_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event)
1198 Ecore_Event_Mouse_Move *ev;
1201 if (ev->window != _drag_win) return ECORE_CALLBACK_PASS_ON;
1204 _e_drag_update(_drag_win_root, ev->x, ev->y,
1205 ECORE_X_ATOM_XDND_ACTION_PRIVATE);
1207 return ECORE_CALLBACK_PASS_ON;
1211 _e_dnd_cb_event_dnd_enter(void *data __UNUSED__, int type __UNUSED__, void *event)
1213 Ecore_X_Event_Xdnd_Enter *ev;
1221 id = e_util_winid_str_get(ev->win);
1222 if (!eina_hash_find(_drop_win_hash, id)) return ECORE_CALLBACK_PASS_ON;
1224 EINA_LIST_FOREACH(_drop_handlers, l, h)
1227 eina_stringshare_del(h->active_type);
1228 h->active_type = NULL;
1231 for (i = 0; i < ev->num_types; i++)
1233 const char *t = NULL;
1234 /* FIXME: Maybe we want to get something else then files dropped? */
1235 if (!strcmp(_type_text_uri_list, ev->types[i]))
1236 t = eina_stringshare_ref(_type_text_uri_list);
1237 else if (!strcmp(_type_xds, ev->types[i]))
1238 t = eina_stringshare_ref(_type_xds);
1241 _xdnd = E_NEW(XDnd, 1);
1243 EINA_LIST_FOREACH(_drop_handlers, l, h)
1246 eina_stringshare_del(h->active_type);
1247 h->active_type = NULL;
1248 for (j = 0; j < h->num_types; j++)
1250 if (h->types[j] == _xdnd->type)
1253 h->active_type = eina_stringshare_ref(_xdnd->type);
1263 else if ((_type_text_x_moz_url == ev->types[i]) ||
1264 (!strcmp(_type_text_x_moz_url, ev->types[i]))) /* not sure it is stringshared */
1266 _xdnd = E_NEW(XDnd, 1);
1267 _xdnd->type = eina_stringshare_ref(_type_text_x_moz_url);
1268 EINA_LIST_FOREACH(_drop_handlers, l, h)
1270 h->active = (h->type == _type_enlightenment_x_file);
1277 return ECORE_CALLBACK_PASS_ON;
1281 _e_dnd_cb_event_dnd_leave(void *data __UNUSED__, int type __UNUSED__, void *event)
1283 Ecore_X_Event_Xdnd_Leave *ev;
1284 E_Event_Dnd_Leave leave_ev;
1290 id = e_util_winid_str_get(ev->win);
1291 if (!eina_hash_find(_drop_win_hash, id)) return ECORE_CALLBACK_PASS_ON;
1300 EINA_LIST_FOREACH(_drop_handlers, l, h)
1302 if (!h->active) continue;
1307 h->cb.leave(h->cb.data, h->active_type, &leave_ev);
1312 eina_stringshare_del(_xdnd->type);
1315 return ECORE_CALLBACK_PASS_ON;
1319 _e_dnd_cb_event_dnd_position(void *data __UNUSED__, int type __UNUSED__, void *event)
1321 Ecore_X_Event_Xdnd_Position *ev;
1322 Ecore_X_Rectangle rect;
1331 // double t1 = ecore_time_get(); ////
1332 id = e_util_winid_str_get(ev->win);
1333 if (!eina_hash_find(_drop_win_hash, id))
1335 // double t2 = ecore_time_get() - t1; ////
1336 // printf("DND POS EV 1 %3.7f\n", t2); ////
1337 return ECORE_CALLBACK_PASS_ON;
1346 EINA_LIST_FOREACH(_drop_handlers, l, h)
1355 ecore_x_dnd_send_status(0, 0, rect, ECORE_X_DND_ACTION_PRIVATE);
1358 responsive = _e_drag_update(ev->win, ev->position.x, ev->position.y, ev->action);
1360 ecore_x_dnd_send_status(1, 0, rect, _action);
1362 ecore_x_dnd_send_status(1, 0, rect, ECORE_X_ATOM_XDND_ACTION_PRIVATE);
1364 // double t2 = ecore_time_get() - t1; ////
1365 // printf("DND POS EV 2 %3.7f\n", t2); ////
1366 return ECORE_CALLBACK_PASS_ON;
1370 _e_dnd_cb_event_dnd_status(void *data __UNUSED__, int type __UNUSED__, void *event)
1372 Ecore_X_Event_Xdnd_Status *ev;
1375 if (ev->win != _drag_win) return ECORE_CALLBACK_PASS_ON;
1376 return ECORE_CALLBACK_PASS_ON;
1380 _e_dnd_cb_event_dnd_finished(void *data __UNUSED__, int type __UNUSED__, void *event)
1382 Ecore_X_Event_Xdnd_Finished *ev;
1386 if (!ev->completed) return ECORE_CALLBACK_PASS_ON;
1392 tmp = _drag_current;
1393 _drag_current = NULL;
1394 e_object_del(E_OBJECT(tmp));
1397 ecore_x_window_free(_drag_win);
1400 return ECORE_CALLBACK_PASS_ON;
1404 _e_dnd_cb_event_dnd_drop(void *data __UNUSED__, int type __UNUSED__, void *event)
1406 Ecore_X_Event_Xdnd_Drop *ev;
1410 id = e_util_winid_str_get(ev->win);
1411 if (!eina_hash_find(_drop_win_hash, id)) return ECORE_CALLBACK_PASS_ON;
1416 Eina_Bool req = EINA_TRUE;
1419 EINA_LIST_FOREACH(_drop_handlers, l, h)
1421 if (!h->active) continue;
1422 if (_e_drag_win_matches(h, ev->win, 1) && h->entered && h->cb.xds)
1424 req = h->cb.xds(h->cb.data);
1427 if (req) ecore_x_selection_xdnd_request(ev->win, _xdnd->type);
1429 _xdnd->x = ev->position.x;
1430 _xdnd->y = ev->position.y;
1433 _e_drag_xdnd_end(ev->win, _xdnd->x, _xdnd->y);
1434 ecore_x_dnd_send_finished();
1435 eina_stringshare_del(_xdnd->type);
1440 return ECORE_CALLBACK_PASS_ON;
1444 _e_dnd_cb_event_dnd_selection(void *data __UNUSED__, int type __UNUSED__, void *event)
1446 Ecore_X_Event_Selection_Notify *ev;
1451 id = e_util_winid_str_get(ev->win);
1452 if (!eina_hash_find(_drop_win_hash, id)) return ECORE_CALLBACK_PASS_ON;
1453 if (ev->selection != ECORE_X_SELECTION_XDND) return ECORE_CALLBACK_PASS_ON;
1455 if (_type_text_uri_list == _xdnd->type)
1457 Ecore_X_Selection_Data_Files *files;
1458 Eina_List *l = NULL;
1461 for (i = 0; i < files->num_files; i++)
1463 /* TODO: Check if hostname is in file:// uri */
1464 if (!strncmp(files->files[i], "file://", 7))
1465 l = eina_list_append(l, files->files[i]);
1466 /* TODO: download files
1467 else if (!strncmp(files->files[i], "http://", 7))
1468 else if (!strncmp(files->files[i], "ftp://", 6))
1471 l = eina_list_append(l, files->files[i]);
1474 _e_drag_xdnd_end(ev->win, _xdnd->x, _xdnd->y);
1477 else if (_type_text_x_moz_url == _xdnd->type)
1479 /* FIXME: Create a ecore x parser for this type */
1480 Ecore_X_Selection_Data *sdata;
1481 Eina_List *l = NULL;
1482 char file[PATH_MAX];
1487 text = (char *)sdata->data;
1488 size = MIN(sdata->length, PATH_MAX - 1);
1489 /* A moz url _shall_ contain a space */
1490 /* FIXME: The data is two-byte unicode. Somewhere it
1491 * is written that the url and the text is separated by
1492 * a space, but it seems like they are separated by
1495 for (i = 0; i < size; i++)
1498 // printf("'%d-%c' ", text[i], text[i]);
1509 // printf("file: %d \"%s\"\n", i, file);
1510 l = eina_list_append(l, file);
1513 _e_drag_xdnd_end(ev->win, _xdnd->x, _xdnd->y);
1517 _e_drag_xdnd_end(ev->win, _xdnd->x, _xdnd->y);
1518 /* FIXME: When to execute this? It could be executed in ecore_x after getting
1519 * the drop property... */
1520 ecore_x_dnd_send_finished();
1521 eina_stringshare_del(_xdnd->type);
1523 return ECORE_CALLBACK_PASS_ON;