summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiep Ha <thiepha@gmail.com>2018-01-08 19:13:10 +0900
committerThiep Ha <thiepha@gmail.com>2018-01-11 17:56:24 +0900
commit763daa870e4013361727be61798f11ffc9ad2594 (patch)
tree1dd99f1555bfc4d765dc967472beccd5632d8c63
parent1b4f330c9c4dea9b08fb227cfca1f69fe59fccd3 (diff)
cnp_dnd: add selection manager
Selection manager implements functions for selection (cnp) and drag and drop. All objects can uses it APIs. It also supports multi-seat.
-rw-r--r--src/Makefile_Elementary.am6
-rw-r--r--src/lib/elementary/Elementary.h2
-rw-r--r--src/lib/elementary/efl_selection_manager.c5320
-rw-r--r--src/lib/elementary/efl_selection_manager.eo139
-rw-r--r--src/lib/elementary/efl_selection_manager_private.h319
-rw-r--r--src/lib/elementary/efl_selection_types.eot59
-rw-r--r--src/lib/elementary/efl_ui_dnd_types.eot58
-rw-r--r--src/lib/elementary/elm_priv.h1
8 files changed, 5903 insertions, 1 deletions
diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am
index dffd96f..b1ac265 100644
--- a/src/Makefile_Elementary.am
+++ b/src/Makefile_Elementary.am
@@ -127,6 +127,7 @@ elm_private_eolian_files = \
127 lib/elementary/efl_ui_focus_parent_provider_gen.eo \ 127 lib/elementary/efl_ui_focus_parent_provider_gen.eo \
128 tests/elementary/focus_test.eo \ 128 tests/elementary/focus_test.eo \
129 tests/elementary/focus_test_sub_main.eo \ 129 tests/elementary/focus_test_sub_main.eo \
130 lib/elementary/efl_selection_manager.eo \
130 $(NULL) 131 $(NULL)
131 132
132# Legacy classes - not part of public EO API 133# Legacy classes - not part of public EO API
@@ -226,7 +227,9 @@ elm_legacy_eolian_files = \
226elm_eolian_type_files = \ 227elm_eolian_type_files = \
227 lib/elementary/elm_general.eot \ 228 lib/elementary/elm_general.eot \
228 lib/elementary/efl_ui.eot \ 229 lib/elementary/efl_ui.eot \
229 lib/elementary/efl_ui_list_types.eot 230 lib/elementary/efl_ui_list_types.eot \
231 lib/elementary/efl_selection_types.eot \
232 lib/elementary/efl_ui_dnd_types.eot
230 233
231elm_public_eolian_c = $(elm_public_eolian_files:%.eo=%.eo.c) 234elm_public_eolian_c = $(elm_public_eolian_files:%.eo=%.eo.c)
232elm_public_eolian_h = $(elm_public_eolian_files:%.eo=%.eo.h) \ 235elm_public_eolian_h = $(elm_public_eolian_files:%.eo=%.eo.h) \
@@ -757,6 +760,7 @@ lib_elementary_libelementary_la_SOURCES = \
757 lib/elementary/efl_ui_scroller.c \ 760 lib/elementary/efl_ui_scroller.c \
758 lib/elementary/efl_ui_scroll_manager.c \ 761 lib/elementary/efl_ui_scroll_manager.c \
759 lib/elementary/efl_ui_pan.c \ 762 lib/elementary/efl_ui_pan.c \
763 lib/elementary/efl_selection_manager.c \
760 $(NULL) 764 $(NULL)
761 765
762 766
diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h
index da2cc35..b5c58c7 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -321,6 +321,8 @@ EAPI extern Elm_Version *elm_version;
321# include <efl_ui_list_pan.eo.h> 321# include <efl_ui_list_pan.eo.h>
322# include <efl_ui_scroll_manager.eo.h> 322# include <efl_ui_scroll_manager.eo.h>
323# include <efl_ui_scroller.eo.h> 323# include <efl_ui_scroller.eo.h>
324# include "efl_selection_types.eot.h"
325# include "efl_ui_dnd_types.eot.h"
324# include <efl_ui_pan.eo.h> 326# include <efl_ui_pan.eo.h>
325#endif 327#endif
326 328
diff --git a/src/lib/elementary/efl_selection_manager.c b/src/lib/elementary/efl_selection_manager.c
new file mode 100644
index 0000000..23bde3b
--- /dev/null
+++ b/src/lib/elementary/efl_selection_manager.c
@@ -0,0 +1,5320 @@
1#ifdef HAVE_CONFIG_H
2# include "elementary_config.h"
3#endif
4
5#include <Elementary.h>
6#include "elm_priv.h"
7#ifdef HAVE_MMAN_H
8# include <sys/mman.h>
9#endif
10
11#include "efl_selection_manager_private.h"
12
13#define MY_CLASS EFL_SELECTION_MANAGER_CLASS
14
15#define DEBUGON 1
16#ifdef DEBUGON
17# define sel_debug(fmt, args...) fprintf(stderr, __FILE__":%s:%d : " fmt "\n", __FUNCTION__, __LINE__, ##args)
18#else
19# define sel_debug(x...) do { } while (0)
20#endif
21
22static void _set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel);
23static void _anim_data_free(Sel_Manager_Drag_Container *dc);
24static void _cont_obj_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
25static void _cont_obj_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
26static void _item_container_del_internal(Sel_Manager_Drag_Container *dc, Eina_Bool full);
27
28void efl_selection_manager_drop_target_del(Eo *obj, Efl_Object *target_obj, Efl_Selection_Format format, unsigned int seat);
29void efl_selection_manager_selection_clear(Eo *obj, Efl_Object *owner, Efl_Selection_Type type, unsigned int seat);
30void efl_selection_manager_drag_start(Eo *obj, Efl_Object *drag_obj, Efl_Selection_Format format, Eina_Slice data, Efl_Selection_Action action, void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, unsigned int seat);
31
32#ifdef HAVE_ELEMENTARY_X
33static Ecore_X_Atom _x11_dnd_action_rev_map(Efl_Selection_Action action);
34static Ecore_X_Window _x11_xwin_get(const Evas_Object *obj);
35#endif
36
37#ifdef HAVE_ELEMENTARY_WL2
38static Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj);
39static Ecore_Wl2_Input *_wl_seat_get(Ecore_Wl2_Window *win, const Evas_Object *obj, unsigned int seat_id);
40#endif
41
42static inline void
43_owner_change_check(Efl_Object *owner, Sel_Manager_Seat_Selection *seat_sel,
44 Sel_Manager_Selection *sel,
45 Efl_Selection_Type type, Eina_Bool same_win)
46{
47 if ((sel->owner != NULL) &&
48 (sel->owner != owner) && same_win)
49 {
50 Eina_List *l, *l_next;
51 Sel_Manager_Selection_Lost *sel_lost;
52 EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost)
53 {
54 if ((sel_lost->request == sel->owner) &&
55 (sel_lost->type == type))
56 {
57 eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type));
58 seat_sel->sel_lost_list = eina_list_remove(seat_sel->sel_lost_list, sel_lost);
59 free(sel_lost);
60 }
61 }
62 }
63}
64
65static Sel_Manager_Seat_Selection *
66_sel_manager_seat_selection_get(Efl_Selection_Manager_Data *pd, unsigned int seat)
67{
68 Eina_List *l = NULL;
69 Sel_Manager_Seat_Selection *seat_sel = NULL;
70
71 EINA_LIST_FOREACH(pd->seat_list, l, seat_sel)
72 {
73 if (seat_sel->seat == seat)
74 break;
75 }
76 if (!seat_sel)
77 ERR("Could not find request seat");
78
79 return seat_sel;
80}
81
82static Sel_Manager_Seat_Selection *
83_sel_manager_seat_selection_init(Efl_Selection_Manager_Data *pd, unsigned int seat)
84{
85 Sel_Manager_Seat_Selection *seat_sel = NULL;
86 Eina_List *l = NULL;
87
88 EINA_LIST_FOREACH(pd->seat_list, l, seat_sel)
89 {
90 if(seat_sel->seat == seat)
91 break;
92 }
93 if (!seat_sel)
94 {
95 seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection));
96 if (!seat_sel)
97 {
98 ERR("Failed to allocate seat");
99 return NULL;
100 }
101 seat_sel->saved_types = calloc(1, sizeof(Saved_Type));
102 seat_sel->seat = seat;
103 seat_sel->pd = pd;
104 pd->seat_list = eina_list_append(pd->seat_list, seat_sel);
105 }
106#ifdef HAVE_ELEMENTARY_X
107 if (!seat_sel->sel_list)
108 {
109 seat_sel->sel_list = calloc(1, (EFL_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection));
110 if (!seat_sel->sel_list)
111 {
112 ERR("failed to allocate selection list");
113 return NULL;
114 }
115 _set_selection_list(seat_sel->sel_list, seat_sel);
116 }
117#endif
118#ifdef HAVE_ELEMENTARY_WL2
119 if (!seat_sel->sel)
120 {
121 Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection));
122 if (!sel)
123 {
124 ERR("failed to allocate selection");
125 return NULL;
126 }
127 sel->seat_sel = seat_sel;
128 seat_sel->sel = sel;
129 }
130#endif
131#ifdef HAVE_ELEMENTARY_COCOA
132 if (!seat_sel->sel)
133 {
134 Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection));
135 if (!sel)
136 {
137 ERR("failed to allocate selection");
138 return NULL;
139 }
140 sel->seat_sel = seat_sel;
141 seat_sel->sel = sel;
142 }
143#endif
144#ifdef HAVE_ELEMENTARY_WIN32
145 if (!seat_sel->sel_list)
146 {
147 seat_sel->sel_list = calloc(1, (EFL_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection));
148 if (!seat_sel->sel_list)
149 {
150 ERR("failed to allocate selection list");
151 return NULL;
152 }
153 _set_selection_list(seat_sel->sel_list, seat_sel);
154 }
155#endif
156
157 return seat_sel;
158}
159
160/* TODO: this should not be an actual tempfile, but rather encode the object
161 * as http://dataurl.net/ if it's an image or similar. Evas should support
162 * decoding it as memfile. */
163static Tmp_Info *
164_tempfile_new(int size)
165{
166#ifdef HAVE_MMAN_H
167 Tmp_Info *info;
168 const char *tmppath = NULL;
169 mode_t cur_umask;
170 int len;
171
172 info = calloc(1, sizeof(Tmp_Info));
173 if (!info) return NULL;
174#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
175 if (getuid() == geteuid())
176#endif
177 tmppath = getenv("TMP");
178 if (!tmppath) tmppath = P_tmpdir;
179 len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-");
180 if (len < 0) goto on_error;
181 len++;
182 info->filename = malloc(len);
183 if (!info->filename) goto on_error;
184 snprintf(info->filename,len,"%s/%sXXXXXX", tmppath, "elmcnpitem-");
185 cur_umask = umask(S_IRWXO | S_IRWXG);
186 info->fd = mkstemp(info->filename);
187 umask(cur_umask);
188 if (info->fd < 0) goto on_error;
189# ifdef __linux__
190 {
191 char *tmp;
192 /* And before someone says anything see POSIX 1003.1-2008 page 400 */
193 long pid;
194
195 pid = (long)getpid();
196 /* Use pid instead of /proc/self: That way if can be passed around */
197 len = snprintf(NULL,0,"/proc/%li/fd/%i", pid, info->fd);
198 len++;
199 tmp = malloc(len);
200 if (tmp)
201 {
202 snprintf(tmp,len, "/proc/%li/fd/%i", pid, info->fd);
203 unlink(info->filename);
204 free(info->filename);
205 info->filename = tmp;
206 }
207 }
208# endif
209 sel_debug("filename is %s\n", info->filename);
210 if (size < 1) goto on_error;
211 /* Map it in */
212 if (ftruncate(info->fd, size))
213 {
214 perror("ftruncate");
215 goto on_error;
216 }
217 eina_mmap_safety_enabled_set(EINA_TRUE);
218 info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0);
219 if (info->map == MAP_FAILED)
220 {
221 perror("mmap");
222 goto on_error;
223 }
224 return info;
225
226 on_error:
227 if (info->fd >= 0) close(info->fd);
228 info->fd = -1;
229 /* Set map to NULL and return */
230 info->map = NULL;
231 info->len = 0;
232 free(info->filename);
233 free(info);
234 return NULL;
235#else
236 (void) size;
237 return NULL;
238#endif
239}
240
241static int
242_tmpinfo_free(Tmp_Info *info)
243{
244 if (!info) return 0;
245 free(info->filename);
246 free(info);
247 return 0;
248}
249
250static void
251_all_drop_targets_cbs_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED)
252{
253 Efl_Selection_Manager_Data *pd = data;
254 Sel_Manager_Dropable *dropable = NULL;
255
256 if (!pd) return;
257 dropable = efl_key_data_get(obj, "__elm_dropable");
258 if (dropable)
259 {
260 Drop_Format *df;
261 while (dropable->format_list)
262 {
263 df = EINA_INLIST_CONTAINER_GET(dropable->format_list, Drop_Format);
264 efl_selection_manager_drop_target_del(pd->sel_man, obj, df->format, dropable->seat);
265 // If drop_target_del() happened to delete dropabale, then
266 // re-fetch it each loop to make sure it didn't
267 dropable = efl_key_data_get(obj, "__elm_dropable");
268 if (!dropable) break;
269 }
270 }
271}
272
273static void
274_dropable_coords_adjust(Sel_Manager_Dropable *dropable, Eina_Position2D *pos)
275{
276 Ecore_Evas *ee;
277 Evas *evas = evas_object_evas_get(dropable->obj);
278 int ex = 0, ey = 0, ew = 0, eh = 0;
279 Evas_Object *win;
280
281 ee = ecore_evas_ecore_evas_get(evas);
282 ecore_evas_geometry_get(ee, &ex, &ey, &ew, &eh);
283 pos->x = pos->x - ex;
284 pos->y = pos->y - ey;
285
286 /* For Wayland, frame coords have to be subtracted. */
287 Evas_Coord fx, fy;
288 evas_output_framespace_get(evas, &fx, &fy, NULL, NULL);
289 if (fx || fy) sel_debug("evas frame fx %d fy %d\n", fx, fy);
290 pos->x = pos->x - fx;
291 pos->y = pos->y - fy;
292
293 if (elm_widget_is(dropable->obj))
294 {
295 win = elm_widget_top_get(dropable->obj);
296 if (win && efl_isa(win, EFL_UI_WIN_CLASS))
297 {
298 Evas_Coord x2, y2;
299 int rot = elm_win_rotation_get(win);
300 switch (rot)
301 {
302 case 90:
303 x2 = ew - pos->y;
304 y2 = pos->x;
305 break;
306 case 180:
307 x2 = ew - pos->x;
308 y2 = eh - pos->y;
309 break;
310 case 270:
311 x2 = pos->y;
312 y2 = eh - pos->x;
313 break;
314 default:
315 x2 = pos->x;
316 y2 = pos->y;
317 break;
318 }
319 sel_debug("rotation %d, w %d, h %d - x:%d->%d, y:%d->%d\n",
320 rot, ew, eh, pos->x, x2, pos->y, y2);
321 pos->x = x2;
322 pos->y = y2;
323 }
324 }
325}
326
327static Eina_Bool
328_drag_cancel_animate(void *data, double pos)
329{ /* Animation to "move back" drag-window */
330 Sel_Manager_Seat_Selection *seat_sel = data;
331 sel_debug("in, pos: %f", pos);
332 if (pos >= 0.99)
333 {
334#ifdef HAVE_ELEMENTARY_X
335 Ecore_X_Window xdragwin = _x11_xwin_get(seat_sel->drag_win);
336 ecore_x_window_ignore_set(xdragwin, 0);
337#endif
338 ERR("Delete drag_win");
339 evas_object_del(seat_sel->drag_win);
340 seat_sel->drag_win = NULL;
341 return ECORE_CALLBACK_CANCEL;
342 }
343 else
344 {
345 int x, y;
346 x = seat_sel->drag_win_end.x - (pos * (seat_sel->drag_win_end.x - seat_sel->drag_win_start.x));
347 y = seat_sel->drag_win_end.y - (pos * (seat_sel->drag_win_end.y - seat_sel->drag_win_start.y));
348 evas_object_move(seat_sel->drag_win, x, y);
349 }
350
351 return ECORE_CALLBACK_RENEW;
352}
353
354static Efl_Selection_Format
355_dnd_types_to_format(Efl_Selection_Manager_Data *pd, const char **types, int ntypes)
356{
357 Efl_Selection_Format ret_type = 0;
358 int i;
359 for (i = 0; i < ntypes; i++)
360 {
361 Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, types[i]);
362 if (atom) ret_type |= atom->format;
363 }
364 return ret_type;
365}
366
367static Eina_List *
368_dropable_list_geom_find(Efl_Selection_Manager_Data *pd, Evas *evas, Evas_Coord px, Evas_Coord py)
369{
370 Eina_List *itr, *top_objects_list = NULL, *dropable_list = NULL;
371 Evas_Object *top_obj;
372 Sel_Manager_Dropable *dropable = NULL;
373
374 if (!pd->drop_list) return NULL;
375
376 /* We retrieve the (non-smart) objects pointed by (px, py) */
377 top_objects_list = evas_tree_objects_at_xy_get(evas, NULL, px, py);
378 /* We walk on this list from the last because if the list contains more than one
379 * element, all but the last will repeat events. The last one can repeat events
380 * or not. Anyway, this last one is the first that has to be taken into account
381 * for the determination of the drop target.
382 */
383 EINA_LIST_REVERSE_FOREACH(top_objects_list, itr, top_obj)
384 {
385 Evas_Object *object = top_obj;
386 /* We search for the dropable data into the object. If not found, we search into its parent.
387 * For example, if a button is a drop target, the first object will be an (internal) image.
388 * The drop target is attached to the button, i.e to image's parent. That's why we need to
389 * walk on the parents until NULL.
390 * If we find this dropable data, we found our drop target.
391 */
392 while (object)
393 {
394 dropable = efl_key_data_get(object, "__elm_dropable");
395 if (dropable)
396 {
397 Eina_Bool exist = EINA_FALSE;
398 Eina_List *l;
399 Sel_Manager_Dropable *d = NULL;
400 EINA_LIST_FOREACH(dropable_list, l, d)
401 {
402 if (d == dropable)
403 {
404 exist = EINA_TRUE;
405 break;
406 }
407 }
408 if (!exist)
409 dropable_list = eina_list_append(dropable_list, dropable);
410 object = evas_object_smart_parent_get(object);
411 if (dropable)
412 sel_debug("Drop target %p of type %s found\n",
413 dropable->obj, efl_class_name_get(efl_class_get(dropable->obj)));
414 }
415 else
416 object = evas_object_smart_parent_get(object);
417 }
418 }
419 eina_list_free(top_objects_list);
420 return dropable_list;
421}
422
423#ifdef HAVE_ELEMENTARY_X
424static Ecore_X_Window
425_x11_xwin_get(const Efl_Object *obj)
426{
427 if (!obj) return 0;
428
429 Ecore_X_Window xwin = 0;
430 //get top
431 const Evas_Object *top = obj;
432 const Evas_Object *parent = obj;
433 while(parent)
434 {
435 top = parent;
436 parent = efl_parent_get(parent);
437 }
438 if (efl_isa(top, EFL_UI_WIN_CLASS))
439 {
440 xwin = elm_win_xwindow_get(top);
441 }
442 if (!xwin)
443 {
444 Ecore_Evas *ee;
445 Evas *evas = evas_object_evas_get(obj);
446 if (!evas) return 0;
447 ee = ecore_evas_ecore_evas_get(evas);
448 if (!ee) return 0;
449
450 while(!xwin)
451 {
452 const char *engine_name = ecore_evas_engine_name_get(ee);
453 if (!strcmp(engine_name, ELM_BUFFER))
454 {
455 ee = ecore_evas_buffer_ecore_evas_parent_get(ee);
456 if (!ee) return 0;
457 xwin = _elm_ee_xwin_get(ee);
458 }
459 else
460 {
461 xwin = _elm_ee_xwin_get(ee);
462 if (!xwin) return 0;
463 }
464 }
465 }
466
467 return xwin;
468}
469
470static Eina_Bool
471_x11_is_uri_type_data(Sel_Manager_Selection *sel EINA_UNUSED, Ecore_X_Event_Selection_Notify *notify)
472{
473 Ecore_X_Selection_Data *data;
474 char *p;
475
476 data = notify->data;
477 sel_debug("data->format is %d %p %p", data->format, notify, data);
478 if (data->content == ECORE_X_SELECTION_CONTENT_FILES) return EINA_TRUE;
479 p = (char *)data->data;
480 if (!p) return EINA_TRUE;
481 sel_debug("Got %s", p);
482 if (strncmp(p, "file:/", 6))
483 {
484 if (*p != '/') return EINA_FALSE;
485 }
486 return EINA_TRUE;
487}
488
489static Sel_Manager_Seat_Selection *
490_x11_sel_manager_seat_selection_init(Efl_Selection_Manager_Data *pd, unsigned int seat)
491{
492 Sel_Manager_Seat_Selection *seat_sel = NULL;
493 Eina_List *l = NULL;
494
495 EINA_LIST_FOREACH(pd->seat_list, l, seat_sel)
496 {
497 if(seat_sel->seat == seat)
498 break;
499 }
500 if (!seat_sel)
501 {
502 seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection));
503 if (!seat_sel)
504 {
505 ERR("Failed to allocate seat");
506 return NULL;
507 }
508 seat_sel->saved_types = calloc(1, sizeof(Saved_Type));
509 seat_sel->seat = seat;
510 seat_sel->pd = pd;
511 pd->seat_list = eina_list_append(pd->seat_list, seat_sel);
512 }
513 if (!seat_sel->sel_list)
514 {
515 //TODO: reduce memory (may be just need one common sel_list)
516 seat_sel->sel_list = calloc(1, (EFL_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection));
517 if (!seat_sel->sel_list)
518 {
519 ERR("failed to allocate selection list");
520 return NULL;
521 }
522 _set_selection_list(seat_sel->sel_list, seat_sel);
523 }
524
525 return seat_sel;
526}
527
528static Eina_Bool
529_x11_data_preparer_text(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED,
530 Ecore_X_Event_Selection_Notify *notify,
531 Efl_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED)
532{
533 sel_debug("text data preparer");
534 Ecore_X_Selection_Data *data = notify->data;
535 ddata->format = EFL_SELECTION_FORMAT_TEXT;
536 ddata->data.mem = eina_memdup(data->data, data->length, EINA_TRUE);
537 ddata->data.len = data->length;
538 return EINA_TRUE;
539}
540
541static Eina_Bool
542_x11_data_preparer_markup(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED,
543 Ecore_X_Event_Selection_Notify *notify,
544 Efl_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED)
545{
546 sel_debug("markup data preparer");
547 Ecore_X_Selection_Data *data = notify->data;
548 ddata->format = EFL_SELECTION_FORMAT_MARKUP;
549 ddata->data.mem = eina_memdup(data->data, data->length, EINA_TRUE);
550 ddata->data.len = data->length;
551 return EINA_TRUE;
552}
553
554/**
555 * So someone is pasting an image into my entry or widget...
556 */
557static Eina_Bool
558_x11_data_preparer_uri(Sel_Manager_Seat_Selection *seat_sel, Ecore_X_Event_Selection_Notify *notify,
559 Efl_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED)
560{
561 sel_debug("uri data preparer");
562 Ecore_X_Selection_Data *data;
563 Ecore_X_Selection_Data_Files *files;
564 char *p, *stripstr = NULL;
565
566 data = notify->data;
567 sel_debug("data->format is %d %p %p\n", data->format, notify, data);
568 if (data->content == ECORE_X_SELECTION_CONTENT_FILES)
569 {
570 Efreet_Uri *uri;
571 Eina_Strbuf *strbuf;
572 int i;
573
574 sel_debug("got a files list\n");
575 files = notify->data;
576 /*
577 if (files->num_files > 1)
578 {
579 // Don't handle many items <- this makes mr bigglesworth sad :(
580 sel_debug("more then one file: Bailing\n");
581 return EINA_FALSE;
582 }
583 stripstr = p = strdup(files->files[0]);
584 */
585
586 strbuf = eina_strbuf_new();
587 if (!strbuf)
588 return EINA_FALSE;
589
590 for (i = 0; i < files->num_files ; i++)
591 {
592 uri = efreet_uri_decode(files->files[i]);
593 if (uri)
594 {
595 eina_strbuf_append(strbuf, uri->path);
596 efreet_uri_free(uri);
597 }
598 else
599 {
600 eina_strbuf_append(strbuf, files->files[i]);
601 }
602 if (i < (files->num_files - 1))
603 eina_strbuf_append(strbuf, "\n");
604 }
605 stripstr = eina_strbuf_string_steal(strbuf);
606 eina_strbuf_free(strbuf);
607 }
608 else
609 {
610 Efreet_Uri *uri;
611
612 p = (char *)eina_memdup((unsigned char *)data->data, data->length, EINA_TRUE);
613 if (!p) return EINA_FALSE;
614 uri = efreet_uri_decode(p);
615 if (!uri)
616 {
617 /* Is there any reason why we care of URI without scheme? */
618 if (p[0] == '/') stripstr = p;
619 else free(p);
620 }
621 else
622 {
623 free(p);
624 stripstr = strdup(uri->path);
625 efreet_uri_free(uri);
626 }
627 }
628
629 if (!stripstr)
630 {
631 sel_debug("Couldn't find a file\n");
632 return EINA_FALSE;
633 }
634 free(seat_sel->saved_types->imgfile);
635 if (seat_sel->saved_types->textreq)
636 {
637 seat_sel->saved_types->textreq = 0;
638 seat_sel->saved_types->imgfile = stripstr;
639 }
640 else
641 {
642 ddata->format = EFL_SELECTION_FORMAT_IMAGE;
643 ddata->data.mem = stripstr;
644 ddata->data.len = strlen(stripstr);
645 seat_sel->saved_types->imgfile = NULL;
646 }
647 return EINA_TRUE;
648}
649
650/**
651 * Just received an vcard, either through cut and paste, or dnd.
652 */
653static Eina_Bool
654_x11_data_preparer_vcard(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED,
655 Ecore_X_Event_Selection_Notify *notify,
656 Efl_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED)
657{
658 sel_debug("vcard receive\n");
659 Ecore_X_Selection_Data *data = notify->data;
660 ddata->format = EFL_SELECTION_FORMAT_VCARD;
661 ddata->data.mem = eina_memdup(data->data, data->length, EINA_TRUE);
662 ddata->data.len = data->length;
663 return EINA_TRUE;
664}
665
666static Eina_Bool
667_x11_data_preparer_image(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED,
668 Ecore_X_Event_Selection_Notify *notify,
669 Efl_Selection_Data *ddata, Tmp_Info **tmp_info)
670{
671 Ecore_X_Selection_Data *data = notify->data;
672 sel_debug("got a image file!\n");
673 sel_debug("Size if %d\n", data->length);
674
675 ddata->format = EFL_SELECTION_FORMAT_IMAGE;
676 data = notify->data;
677
678 Tmp_Info *tmp = _tempfile_new(data->length);
679 if (!tmp) return EINA_FALSE;
680 memcpy(tmp->map, data->data, data->length);
681 munmap(tmp->map, data->length);
682 ddata->data.mem = strdup(tmp->filename);
683 ddata->data.len = strlen(tmp->filename);
684 *tmp_info = tmp;
685 return EINA_TRUE;
686}
687
688/*
689 * Callback to handle a targets response on a selection request:
690 * So pick the format we'd like; and then request it.
691 */
692static Eina_Bool
693_x11_notify_handler_targets(Efl_Selection_Manager_Data *pd, Sel_Manager_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
694{
695 sel_debug("notify handler targets");
696 Ecore_X_Selection_Data_Targets *targets;
697 Ecore_X_Atom *atom_list;
698 int i, j;
699
700 targets = notify->data;
701 atom_list = (Ecore_X_Atom *)(targets->data.data);
702 for (j = (SELECTION_ATOM_LISTING_ATOMS + 1); j < SELECTION_N_ATOMS; j++)
703 {
704 sel_debug("\t%s %d", pd->atom_list[j].name, pd->atom_list[j].x_atom);
705 if (!(pd->atom_list[j].format & sel->request_format)) continue;
706 for (i = 0; i < targets->data.length; i++)
707 {
708 if ((pd->atom_list[j].x_atom == atom_list[i]) && (pd->atom_list[j].x_data_preparer))
709 {
710 if (j == SELECTION_ATOM_TEXT_URILIST)
711 {
712 if (!_x11_is_uri_type_data(sel, notify)) continue;
713 }
714 sel_debug("Atom %s matches", pd->atom_list[j].name);
715 goto done;
716 }
717 }
718 }
719 sel_debug("Couldn't find anything that matches");
720 return ECORE_CALLBACK_PASS_ON;
721done:
722 sel_debug("Sending request for %s, xwin=%#llx",
723 pd->atom_list[j].name, (unsigned long long)sel->xwin);
724 sel->request(sel->xwin, pd->atom_list[j].name);
725 return ECORE_CALLBACK_PASS_ON;
726}
727
728static Eina_Bool
729_x11_fixes_selection_notify(void *data, int t EINA_UNUSED, void *event)
730{
731 Efl_Selection_Manager_Data *pd = data;
732 Efl_Selection_Changed e;
733 Ecore_X_Event_Fixes_Selection_Notify *ev = event;
734 Sel_Manager_Seat_Selection *seat_sel;
735 Efl_Selection_Type type;
736 Sel_Manager_Selection *sel;
737
738 switch (ev->selection)
739 {
740 case ECORE_X_SELECTION_CLIPBOARD:
741 type = EFL_SELECTION_TYPE_CLIPBOARD;
742 break;
743 case ECORE_X_SELECTION_PRIMARY:
744 type = EFL_SELECTION_TYPE_PRIMARY;
745 break;
746 default: return ECORE_CALLBACK_RENEW;
747 }
748 seat_sel = _x11_sel_manager_seat_selection_init(pd, 1);
749 if (!seat_sel) return ECORE_CALLBACK_RENEW;
750 sel = seat_sel->sel_list + type;
751 if (sel->active && (sel->xwin != ev->owner))
752 efl_selection_manager_selection_clear(pd->sel_man, sel->owner, type, seat_sel->seat);
753 e.type = type;
754 e.seat = 1; /* under x11 this is always the default seat */
755 e.exist = !!ev->owner;
756 //efl_event_callback_call(sel->owner, EFL_SELECTION_EVENT_SELECTION_CHANGED, &e);
757 //ecore_event_add(ELM_CNP_EVENT_SELECTION_CHANGED, e, NULL, NULL);
758
759 return ECORE_CALLBACK_RENEW;
760}
761
762/*
763 * Response to a selection notify:
764 * - So we have asked for the selection list.
765 * - If it's the targets list, parse it, and fire of what we want,
766 * else it's the data we want.
767 */
768//NB: x11 does not have seat, use 1 as default
769static Eina_Bool
770_efl_sel_manager_x11_selection_notify(void *udata, int type EINA_UNUSED, void *event)
771{
772 Efl_Selection_Manager_Data *pd = udata;
773 Ecore_X_Event_Selection_Notify *ev = event;
774 Sel_Manager_Selection *sel;
775 Sel_Manager_Seat_Selection *seat_sel = NULL;
776 int i;
777
778 seat_sel = _sel_manager_seat_selection_get(pd, 1);
779 if (!seat_sel)
780 return EINA_FALSE;
781
782 sel_debug("selection notify callback: %d", ev->selection);
783 switch (ev->selection)
784 {
785 case ECORE_X_SELECTION_PRIMARY:
786 sel = seat_sel->sel_list + EFL_SELECTION_TYPE_PRIMARY;
787 break;
788 case ECORE_X_SELECTION_SECONDARY:
789 sel = seat_sel->sel_list + EFL_SELECTION_TYPE_SECONDARY;
790 break;
791 case ECORE_X_SELECTION_XDND:
792 sel = seat_sel->sel_list + EFL_SELECTION_TYPE_DND;
793 break;
794 case ECORE_X_SELECTION_CLIPBOARD:
795 sel = seat_sel->sel_list + EFL_SELECTION_TYPE_CLIPBOARD;
796 break;
797 default:
798 return ECORE_CALLBACK_PASS_ON;
799 }
800 sel_debug("Target is %s", ev->target);
801
802 if (ev->selection != ECORE_X_SELECTION_XDND &&
803 (!strcmp(ev->target, "TARGETS") || !strcmp(ev->target, "ATOMS")))
804 {
805 _x11_notify_handler_targets(pd, sel, ev);
806 return ECORE_CALLBACK_PASS_ON;
807 }
808 for (i = 0; i < SELECTION_N_ATOMS; i++)
809 {
810 if (!strcmp(ev->target, pd->atom_list[i].name))
811 {
812 if (pd->atom_list[i].x_data_preparer)
813 {
814 Efl_Selection_Data ddata;
815 Tmp_Info *tmp_info = NULL;
816 Eina_Bool success;
817 sel_debug("Found something: %s", pd->atom_list[i].name);
818
819 success = pd->atom_list[i].x_data_preparer(seat_sel, ev, &ddata, &tmp_info);
820 sel_debug("ddata: %s (%zd)", (const char *)ddata.data.mem, ddata.data.len);
821 if ((pd->atom_list[i].format == EFL_SELECTION_FORMAT_IMAGE) &&
822 (seat_sel->saved_types->imgfile))
823 break;
824 if (ev->selection == ECORE_X_SELECTION_XDND)
825 {
826 if (success)
827 {
828 Sel_Manager_Dropable *dropable;
829 Eina_List *l;
830 sel_debug("drag & drop\n");
831 EINA_LIST_FOREACH(pd->drop_list, l, dropable)
832 {
833 if (dropable->obj == sel->request_obj) break;
834 dropable = NULL;
835 }
836 if (dropable)
837 {
838 Drop_Format *df;
839 Eina_Inlist *itr;
840
841 ddata.action = sel->action;
842 if (!dropable->is_container)
843 {
844 sel_debug("normal dnd, not container");
845 ddata.pos = seat_sel->saved_types->pos;
846 }
847 else
848 {
849 sel_debug("Drop on container");
850 Eina_Position2D pos, posret;
851 evas_object_geometry_get(dropable->obj, &pos.x, &pos.y, NULL, NULL);
852 //get item
853 pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + pos.x,
854 seat_sel->saved_types->pos.y + pos.y);
855 Efl_Object *it = NULL;
856 if (dropable->item_func)
857 it = dropable->item_func(dropable->item_func_data,
858 dropable->obj, pos, &posret);
859 ddata.pos = posret;
860 ddata.item = it;
861 }
862 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
863 {
864 if (df->format & dropable->last.format)
865 {
866 sel_debug("calling Drop event on: %p", dropable->obj);
867 //efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata);
868 }
869 }
870 }
871 else
872 {
873 sel_debug("dnd: has NO dropable");
874 }
875 }
876 /* We have to finish DnD, no matter what */
877 ecore_x_dnd_send_finished();
878 }
879 else if (sel->data_func && success)
880 {
881 ddata.pos.x = ddata.pos.y = 0;
882 sel->data_func(sel->data_func_data, sel->request_obj, &ddata);
883 }
884 free((void *)ddata.data.mem);
885 if (tmp_info) _tmpinfo_free(tmp_info);
886 }
887 else sel_debug("Ignored: No handler!");
888 break;
889 }
890 }
891 return ECORE_CALLBACK_PASS_ON;
892}
893
894static Eina_Bool
895_x11_selection_clear(void *data, int type EINA_UNUSED, void *event)
896{
897 Efl_Selection_Manager_Data *pd = data;
898 Ecore_X_Event_Selection_Clear *ev = event;
899 Sel_Manager_Selection *sel;
900 Sel_Manager_Seat_Selection *seat_sel = NULL;
901 Eina_List *l, *l_next;
902 Sel_Manager_Selection_Lost *sel_lost;
903 unsigned int i;
904 ERR("In");
905
906 seat_sel = _sel_manager_seat_selection_get(pd, 1);
907 if (!seat_sel)
908 return EINA_FALSE;
909
910 for (i = EFL_SELECTION_TYPE_PRIMARY; i <= EFL_SELECTION_TYPE_CLIPBOARD; i++)
911 {
912 if (seat_sel->sel_list[i].ecore_sel == ev->selection) break;
913 }
914 sel_debug("selection %d clear", i);
915 /* Not me... Don't care */
916 if (i > EFL_SELECTION_TYPE_CLIPBOARD) return ECORE_CALLBACK_PASS_ON;
917
918 sel = seat_sel->sel_list + i;
919
920 EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost)
921 {
922 if ((sel_lost->request == sel->owner) &&
923 (sel_lost->type == i))
924 {
925 sel_debug("resolve the promise: %p", sel_lost->promise);
926 eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type));
927 seat_sel->sel_lost_list = eina_list_remove(seat_sel->sel_lost_list, sel_lost);
928 free(sel_lost);
929 }
930 }
931 sel->active = EINA_FALSE;
932 sel->owner = NULL;
933
934 return ECORE_CALLBACK_PASS_ON;
935}
936
937static Eina_Bool
938_x11_general_converter(char *target EINA_UNUSED, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED)
939{
940 sel_debug("general converter");
941 Sel_Manager_Selection *sel = *(Sel_Manager_Selection **)data;
942 if (sel->format == EFL_SELECTION_FORMAT_NONE)
943 {
944 if (data_ret)
945 {
946 *data_ret = malloc(sel->data.len * sizeof(char) + 1);
947 if (!*data_ret) return EINA_FALSE;
948 memcpy(*data_ret, sel->data.mem, sel->data.len);
949 ((char**)(data_ret))[0][sel->data.len] = 0;
950 }
951 if (size_ret) *size_ret = sel->data.len;
952 }
953 else
954 {
955 if (sel->data.mem)
956 {
957 if (data_ret)
958 {
959 *data_ret = strdup(sel->data.mem);
960 ((char **)(data_ret))[0][sel->data.len] = 0;
961 }
962 if (size_ret) *size_ret = strlen(sel->data.mem);
963 }
964 else
965 {
966 if (data_ret) *data_ret = NULL;
967 if (size_ret) *size_ret = 0;
968 }
969 }
970 return EINA_TRUE;
971}
972
973static Eina_Bool
974_x11_targets_converter(char *target EINA_UNUSED, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
975{
976 int i, count;
977 Ecore_X_Atom *aret;
978 Sel_Manager_Selection *sel;
979 Efl_Selection_Format seltype;
980
981 sel_debug("target converter");
982 if (!data_ret) return EINA_FALSE;
983
984 sel = *(Sel_Manager_Selection **)data;
985 seltype = sel->format;
986 Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel;
987 Efl_Selection_Manager_Data *pd = seat_sel->pd;
988
989 for (i = SELECTION_ATOM_LISTING_ATOMS + 1, count = 0; i < SELECTION_N_ATOMS ; i++)
990 {
991 if (seltype & pd->atom_list[i].format) count++;
992 }
993 aret = malloc(sizeof(Ecore_X_Atom) * count);
994 if (!aret) return EINA_FALSE;
995 for (i = SELECTION_ATOM_LISTING_ATOMS + 1, count = 0; i < SELECTION_N_ATOMS ; i++)
996 {
997 if (seltype & pd->atom_list[i].format)
998 aret[count ++] = pd->atom_list[i].x_atom;
999 }
1000
1001 *data_ret = aret;
1002 if (typesize) *typesize = 32 /* urk */;
1003 if (ttype) *ttype = ECORE_X_ATOM_ATOM;
1004 if (size_ret) *size_ret = count;
1005 return EINA_TRUE;
1006}
1007
1008static Eina_Bool
1009_x11_image_converter(char *target EINA_UNUSED, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret EINA_UNUSED, int *size_ret EINA_UNUSED, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED)
1010{
1011 sel_debug("Image converter called");
1012 return EINA_TRUE;
1013}
1014
1015static Eina_Bool
1016_x11_vcard_send(char *target EINA_UNUSED, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype EINA_UNUSED, int *typesize EINA_UNUSED)
1017{
1018 Sel_Manager_Selection *sel;
1019
1020 sel_debug("Vcard send called");
1021 sel = *(Sel_Manager_Selection **)data;
1022 if (data_ret) *data_ret = strdup(sel->data.mem);
1023 if (size_ret) *size_ret = strlen(sel->data.mem);
1024 return EINA_TRUE;
1025}
1026
1027static Eina_Bool
1028_x11_text_converter(char *target, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
1029{
1030 Sel_Manager_Selection *sel;
1031
1032 sel = *(Sel_Manager_Selection **)data;
1033 if (!sel) return EINA_FALSE;
1034
1035 sel_debug("text converter");
1036 if (sel->format == EFL_SELECTION_FORMAT_NONE)
1037 {
1038 sel_debug("none");
1039 if (data_ret)
1040 {
1041 *data_ret = malloc(sel->data.len * sizeof(char) + 1);
1042 if (!*data_ret) return EINA_FALSE;
1043 memcpy(*data_ret, data, sel->data.len);
1044 ((char**)(data_ret))[0][sel->data.len] = 0;
1045 }
1046 if (size_ret) *size_ret = sel->data.len;
1047 return EINA_TRUE;
1048 }
1049
1050 if (!sel->active) return EINA_TRUE;
1051
1052 if ((sel->format & EFL_SELECTION_FORMAT_MARKUP) ||
1053 (sel->format & EFL_SELECTION_FORMAT_HTML))
1054 {
1055 *data_ret = _elm_util_mkup_to_text(sel->data.mem);
1056 if (size_ret && *data_ret) *size_ret = strlen(*data_ret);
1057 sel_debug("markup or html: %s", (const char *)*data_ret);
1058 }
1059 else if (sel->format & EFL_SELECTION_FORMAT_TEXT)
1060 {
1061 ecore_x_selection_converter_text(target, sel->data.mem,
1062 sel->data.len,
1063 data_ret, size_ret,
1064 ttype, typesize);
1065 sel_debug("text");
1066 }
1067 else if (sel->format & EFL_SELECTION_FORMAT_IMAGE)
1068 {
1069 efl_file_get(sel->request_obj, (const char **)data_ret, NULL);
1070 if (!*data_ret) *data_ret = strdup("No file");
1071 else *data_ret = strdup(*data_ret);
1072
1073 if (!*data_ret)
1074 {
1075 ERR("Failed to allocate memory!");
1076 *size_ret = 0;
1077 return EINA_FALSE;
1078 }
1079
1080 *size_ret = strlen(*data_ret);
1081 }
1082 return EINA_TRUE;
1083}
1084
1085static void
1086_sel_manager_promise_cancel(void *data, const Eina_Promise *dead_future EINA_UNUSED)
1087{
1088 Sel_Manager_Selection_Lost *sel_lost = data;
1089 //FIXME: remove from sel_lost_list in seat_sel
1090 free(sel_lost);
1091}
1092
1093static inline Eina_Future *
1094_update_sel_lost_list(Efl_Object *obj, Efl_Selection_Type type,
1095 Sel_Manager_Seat_Selection *seat_sel)
1096{
1097 Eina_Promise *p;
1098 Sel_Manager_Selection_Lost *sel_lost;
1099
1100 sel_lost = calloc(1, sizeof(Sel_Manager_Selection_Lost));
1101 if (!sel_lost)
1102 return NULL;
1103 sel_lost->request = obj;
1104 sel_lost->type = type;
1105 seat_sel->sel_lost_list = eina_list_append(seat_sel->sel_lost_list, sel_lost);
1106
1107 p = eina_promise_new(efl_loop_future_scheduler_get(obj),
1108 _sel_manager_promise_cancel, NULL);
1109 eina_promise_data_set(p, sel_lost);
1110 if (!p) return NULL;
1111 sel_lost->promise = p;
1112
1113 return eina_future_new(p);
1114}
1115
1116static Eina_Future *
1117_x11_efl_sel_manager_selection_set(Efl_Selection_Manager_Data *pd, Efl_Object *owner,
1118 Efl_Selection_Type type, Efl_Selection_Format format, Eina_Slice data,
1119 Ecore_X_Window xwin, unsigned int seat)
1120{
1121 Sel_Manager_Seat_Selection *seat_sel;
1122 Sel_Manager_Selection *sel;
1123 Eina_Bool same_win = EINA_FALSE;
1124
1125 seat_sel = _x11_sel_manager_seat_selection_init(pd, seat);
1126 seat_sel->active_type = type;
1127 sel = seat_sel->sel_list + type;
1128 //support 1 app with multiple window, 1 selection manager
1129 if (sel->xwin == xwin)
1130 same_win = EINA_TRUE;
1131 _owner_change_check(owner, seat_sel, sel, type, same_win);
1132
1133 sel->owner = owner;
1134 free(sel->data.mem);
1135 sel->xwin = xwin;
1136 sel->data = eina_slice_dup(data);
1137 sel->active = EINA_TRUE;
1138 sel->format = format;
1139
1140 sel->set(xwin, &sel, sizeof(&sel));
1141 sel_debug("data: %p (%ld)", &sel, sizeof(&sel));
1142
1143 return _update_sel_lost_list(owner, type, seat_sel);
1144}
1145
1146static void
1147_x11_efl_sel_manager_selection_get(const Efl_Object *request, Efl_Selection_Manager_Data *pd,
1148 Efl_Selection_Type type, Efl_Selection_Format format,
1149 void *data_func_data, Efl_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb,
1150 Ecore_X_Window xwin, unsigned int seat)
1151{
1152 Sel_Manager_Seat_Selection *seat_sel;
1153 Sel_Manager_Selection *sel;;
1154
1155 sel_debug("request: %p, seat: %u, type: %d, format: %d", request, seat, type, format);
1156 seat_sel = _sel_manager_seat_selection_init(pd, seat);
1157 sel = seat_sel->sel_list + type;
1158 sel->request_obj = (Efl_Object *)request;
1159 sel->data_func_data = data_func_data;
1160 sel->data_func = data_func;
1161 sel->data_func_free_cb = data_func_free_cb;
1162 sel->request_format = format;
1163 sel->xwin = xwin;
1164
1165 if (sel->active)
1166 {
1167 if (sel->data.mem &&
1168 ((format == sel->format) || (xwin == 0)))
1169 {
1170 sel_debug("use local data");
1171 Efl_Selection_Data seldata;
1172
1173 seldata.data.mem = sel->data.mem;
1174 seldata.data.len = sel->data.len;
1175 seldata.pos.x = seldata.pos.y = 0;
1176 seldata.format = sel->format;
1177 sel->data_func(sel->data_func_data, sel->request_obj, &seldata);
1178 return;
1179 }
1180 }
1181
1182 sel->request(xwin, ECORE_X_SELECTION_TARGET_TARGETS);
1183}
1184
1185static void
1186_x11_win_rotation_changed_cb(void *data, const Efl_Event *event)
1187{
1188 Evas_Object *win = data;
1189 int rot = elm_win_rotation_get(event->object);
1190 elm_win_rotation_set(win, rot);
1191}
1192
1193static Eina_Bool
1194_x11_drag_mouse_up(void *data, int etype EINA_UNUSED, void *event)
1195{
1196 Sel_Manager_Seat_Selection *seat_sel = data;
1197 Efl_Selection_Manager_Data *pd = seat_sel->pd;
1198 Ecore_X_Window xwin = seat_sel->xwin;
1199 Ecore_Event_Mouse_Button *ev = event;
1200
1201 if ((ev->buttons == 1) &&
1202 (ev->event_window == xwin))
1203 {
1204 Eina_Bool have_drop_list = EINA_FALSE;
1205 Eina_List *l;
1206 Sel_Manager_Dropable *dropable;
1207
1208 ecore_x_pointer_ungrab();
1209 ELM_SAFE_FREE(seat_sel->mouse_up_handler, ecore_event_handler_del);
1210 ELM_SAFE_FREE(seat_sel->dnd_status_handler, ecore_event_handler_del);
1211 ecore_x_dnd_self_drop();
1212
1213 sel_debug("mouse up, xwin=%#llx\n", (unsigned long long)xwin);
1214
1215 EINA_LIST_FOREACH(pd->drop_list, l, dropable)
1216 {
1217 if (xwin == _x11_xwin_get(dropable->obj))
1218 {
1219 have_drop_list = EINA_TRUE;
1220 break;
1221 }
1222 }
1223 if (!have_drop_list) ecore_x_dnd_aware_set(xwin, EINA_FALSE);
1224 //efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_DONE, NULL);
1225 if (seat_sel->drag_win)
1226 {
1227 if (seat_sel->drag_obj)
1228 {
1229 if (elm_widget_is(seat_sel->drag_obj))
1230 {
1231 Evas_Object *win = elm_widget_top_get(seat_sel->drag_obj);
1232 if (win && efl_isa(win, EFL_UI_WIN_CLASS))
1233 efl_event_callback_del(win, EFL_UI_WIN_EVENT_ROTATION_CHANGED,
1234 _x11_win_rotation_changed_cb, seat_sel->drag_win);
1235 }
1236 }
1237
1238 if (!seat_sel->accept)
1239 { /* Commit animation when drag cancelled */
1240 /* Record final position of dragwin, then do animation */
1241 ecore_animator_timeline_add(0.3,
1242 _drag_cancel_animate, seat_sel);
1243 }
1244 else
1245 { /* No animation drop was committed */
1246 Ecore_X_Window xdragwin = _x11_xwin_get(seat_sel->drag_win);
1247 ecore_x_window_ignore_set(xdragwin, 0);
1248 evas_object_del(seat_sel->drag_win);
1249 seat_sel->drag_win = NULL;
1250 sel_debug("deleted drag_win");
1251 }
1252 }
1253
1254 seat_sel->drag_obj = NULL;
1255 seat_sel->accept = EINA_FALSE;
1256 }
1257 return EINA_TRUE;
1258}
1259
1260static void
1261_x11_drag_move(void *data, Ecore_X_Xdnd_Position *pos)
1262{
1263 Sel_Manager_Seat_Selection *seat_sel = data;
1264 Efl_Dnd_Drag_Pos dp;
1265
1266 evas_object_move(seat_sel->drag_win,
1267 pos->position.x - seat_sel->drag_pos.x,
1268 pos->position.y - seat_sel->drag_pos.y);
1269 seat_sel->drag_win_end.x = pos->position.x - seat_sel->drag_pos.x;
1270 seat_sel->drag_win_end.y = pos->position.y - seat_sel->drag_pos.y;
1271 sel_debug("dragevas: %p -> %p\n",
1272 seat_sel->drag_obj,
1273 evas_object_evas_get(seat_sel->drag_obj));
1274 dp.pos.x = pos->position.x;
1275 dp.pos.y = pos->position.y;
1276 dp.action = seat_sel->drag_action;
1277 //for drag side
1278 //efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_POS, &dp);
1279}
1280
1281static void
1282_x11_drag_target_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED)
1283{
1284 Sel_Manager_Seat_Selection *seat_sel = data;
1285 Sel_Manager_Selection *sel = &seat_sel->sel_list[seat_sel->active_type];
1286
1287 if (seat_sel->drag_obj == obj)
1288 {
1289 sel->request_obj = NULL;
1290 seat_sel->drag_obj = NULL;
1291 }
1292}
1293
1294static Eina_Bool
1295_x11_dnd_status(void *data, int etype EINA_UNUSED, void *ev)
1296{
1297 Sel_Manager_Seat_Selection *seat_sel = data;
1298 Ecore_X_Event_Xdnd_Status *status = ev;
1299
1300 seat_sel->accept = EINA_FALSE;
1301
1302 /* Only thing we care about: will accept */
1303 if ((status) && (status->will_accept))
1304 {
1305 sel_debug("Will accept\n");
1306 seat_sel->accept = EINA_TRUE;
1307 }
1308 /* Won't accept */
1309 else
1310 {
1311 sel_debug("Won't accept accept\n");
1312 }
1313 //efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, &seat_sel->accept);
1314
1315 return EINA_TRUE;
1316}
1317
1318static void
1319_x11_efl_sel_manager_drag_start(Eo *obj EINA_UNUSED, Efl_Selection_Manager_Data *pd,
1320 Efl_Object *drag_obj, Efl_Selection_Format format,
1321 Eina_Slice data, Efl_Selection_Action action,
1322 void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func,
1323 Eina_Free_Cb icon_func_free_cb EINA_UNUSED,
1324 Ecore_X_Window xwin, unsigned int seat)
1325{
1326 Ecore_X_Window xdragwin;
1327 Sel_Manager_Seat_Selection *seat_sel;
1328 Sel_Manager_Selection *sel;
1329 Ecore_Evas *ee;
1330 int x, y, x2 = 0, y2 = 0, x3, y3;
1331 Evas_Object *icon = NULL;
1332 int w = 0, h = 0;
1333 int ex, ey, ew, eh;
1334 Ecore_X_Atom actx;
1335 int i;
1336 int xr, yr, rot;
1337
1338 seat_sel = _x11_sel_manager_seat_selection_init(pd, seat);
1339 if (!seat_sel) return;
1340 seat_sel->active_type = EFL_SELECTION_TYPE_DND;
1341
1342 sel = &seat_sel->sel_list[seat_sel->active_type];
1343 ecore_x_dnd_types_set(xwin, NULL, 0);
1344 for (i = SELECTION_ATOM_LISTING_ATOMS + 1; i < SELECTION_N_ATOMS; i++)
1345 {
1346 if (format == EFL_SELECTION_FORMAT_TARGETS || (pd->atom_list[i].format & format))
1347 {
1348 ecore_x_dnd_type_set(xwin, pd->atom_list[i].name, EINA_TRUE);
1349 sel_debug("set dnd type: %s\n", pd->atom_list[i].name);
1350 }
1351 }
1352
1353 sel->active = EINA_TRUE;
1354 sel->request_obj = drag_obj;
1355 sel->format = format;
1356 if (sel->data.mem) free(sel->data.mem);
1357 sel->data = eina_slice_dup(data);
1358 sel->action = action;
1359 seat_sel->drag_obj = drag_obj;
1360 seat_sel->drag_action = action;
1361 seat_sel->xwin = xwin;
1362
1363 evas_object_event_callback_add(drag_obj, EVAS_CALLBACK_DEL,
1364 _x11_drag_target_del, seat_sel);
1365 /* TODO BUG: should increase dnd-awareness, in case it's drop target as well. See _x11_drag_mouse_up() */
1366 ecore_x_dnd_aware_set(xwin, EINA_TRUE);
1367 ecore_x_dnd_callback_pos_update_set(_x11_drag_move, seat_sel);
1368 ecore_x_dnd_self_begin(xwin, (unsigned char *)&sel, sizeof(Sel_Manager_Selection));
1369 actx = _x11_dnd_action_rev_map(seat_sel->drag_action);
1370 ecore_x_dnd_source_action_set(actx);
1371 ecore_x_pointer_grab(xwin);
1372 seat_sel->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
1373 _x11_drag_mouse_up, seat_sel);
1374 seat_sel->dnd_status_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
1375 _x11_dnd_status, seat_sel);
1376 seat_sel->drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND);
1377 elm_win_alpha_set(seat_sel->drag_win, EINA_TRUE);
1378 elm_win_override_set(seat_sel->drag_win, EINA_TRUE);
1379 xdragwin = _x11_xwin_get(seat_sel->drag_win);
1380 ecore_x_window_ignore_set(xdragwin, 1);
1381
1382 /* dragwin has to be rotated as the main window is */
1383 if (elm_widget_is(drag_obj))
1384 {
1385 Evas_Object *win = elm_widget_top_get(drag_obj);
1386 if (win && efl_isa(win, EFL_UI_WIN_CLASS))
1387 {
1388 elm_win_rotation_set(seat_sel->drag_win, elm_win_rotation_get(win));
1389 efl_event_callback_add(win, EFL_UI_WIN_EVENT_ROTATION_CHANGED,
1390 _x11_win_rotation_changed_cb, seat_sel->drag_win);
1391 }
1392 }
1393
1394 if (icon_func)
1395 {
1396 Eina_Position2D off;
1397
1398 icon = icon_func(icon_func_data, seat_sel->drag_win, drag_obj, &off);
1399 if (icon)
1400 {
1401 x2 = off.x;
1402 y2 = off.y;
1403 evas_object_geometry_get(icon, NULL, NULL, &w, &h);
1404 }
1405 }
1406 else
1407 {
1408 icon = elm_icon_add(seat_sel->drag_win);
1409 evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1410 // need to resize
1411 }
1412 elm_win_resize_object_add(seat_sel->drag_win, icon);
1413
1414 /* Position subwindow appropriately */
1415 ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_obj));
1416 ecore_evas_geometry_get(ee, &ex, &ey, &ew, &eh);
1417 evas_object_resize(seat_sel->drag_win, w, h);
1418
1419 evas_object_show(icon);
1420 evas_object_show(seat_sel->drag_win);
1421 evas_pointer_canvas_xy_get(evas_object_evas_get(drag_obj), &x3, &y3);
1422
1423 rot = ecore_evas_rotation_get(ee);
1424 switch (rot)
1425 {
1426 case 90:
1427 xr = y3;
1428 yr = ew - x3;
1429 seat_sel->drag_pos.x = y3 - y2;
1430 seat_sel->drag_pos.y = x3 - x2;
1431 break;
1432 case 180:
1433 xr = ew - x3;
1434 yr = eh - y3;
1435 seat_sel->drag_pos.x = x3 - x2;
1436 seat_sel->drag_pos.y = y3 - y2;
1437 break;
1438 case 270:
1439 xr = eh - y3;
1440 yr = x3;
1441 seat_sel->drag_pos.x = y3 - y2;
1442 seat_sel->drag_pos.y = x3 - x2;
1443 break;
1444 default:
1445 xr = x3;
1446 yr = y3;
1447 seat_sel->drag_pos.x = x3 - x2;
1448 seat_sel->drag_pos.y = y3 - y2;
1449 break;
1450 }
1451 x = ex + xr - seat_sel->drag_pos.x;
1452 y = ey + yr - seat_sel->drag_pos.y;
1453 evas_object_move(seat_sel->drag_win, x, y);
1454 seat_sel->drag_win_start = EINA_POSITION2D(x, y);
1455 seat_sel->drag_win_end = EINA_POSITION2D(x, y);
1456}
1457
1458static void
1459_x11_dnd_dropable_handle(Efl_Selection_Manager_Data *pd, Sel_Manager_Dropable *dropable, Eina_Position2D pos, Efl_Selection_Action action)
1460{
1461 Sel_Manager_Dropable *d, *last_dropable = NULL;
1462 Eina_List *l;
1463 Eina_Inlist *itr;
1464
1465 EINA_LIST_FOREACH(pd->drop_list, l, d)
1466 {
1467 if (d->last.in)
1468 {
1469 last_dropable = d;
1470 break;
1471 }
1472 }
1473 if (last_dropable)
1474 {
1475 if (last_dropable == dropable) // same
1476 {
1477 Evas_Coord ox, oy;
1478 Drop_Format *df;
1479
1480 sel_debug("same obj dropable %p\n", dropable->obj);
1481 evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL);
1482 Efl_Dnd_Drag_Pos pos_data;
1483 if (!dropable->is_container)
1484 {
1485 pos_data.pos = EINA_POSITION2D(pos.x - ox, pos.y - oy);
1486 pos_data.item = NULL;
1487 }
1488 else
1489 {
1490 Eina_Position2D posret;
1491 Efl_Object *it = NULL;
1492
1493 if (dropable->item_func)
1494 it = dropable->item_func(dropable->item_func_data, dropable->obj,
1495 pos, &posret);
1496 pos_data.pos = posret;
1497 pos_data.item = it;
1498 }
1499 pos_data.format = dropable->last.format;
1500 pos_data.action = action;
1501 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
1502 {
1503 if (df->format & dropable->last.format)
1504 {
1505 //efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data);
1506 }
1507 }
1508 }
1509 else
1510 {
1511 if (dropable) // leave last obj and enter new one
1512 {
1513 sel_debug("leave %p\n", last_dropable->obj);
1514 sel_debug("enter %p\n", dropable->obj);
1515 last_dropable->last.in = EINA_FALSE;
1516 last_dropable->last.type = NULL;
1517 dropable->last.in = EINA_TRUE;
1518
1519 Drop_Format *df;
1520 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
1521 {
1522 //if (df->format &dropable->last.format)
1523 // efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL);
1524 }
1525 EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df)
1526 {
1527 //if (df->format & last_dropable->last.format)
1528 // efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL);
1529 }
1530 }
1531 else // leave last obj
1532 {
1533 sel_debug("leave %p\n", last_dropable->obj);
1534 last_dropable->last.in = EINA_FALSE;
1535 last_dropable->last.type = NULL;
1536
1537 Drop_Format *df;
1538 EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df)
1539 {
1540 //if (df->format & last_dropable->last.format)
1541 // efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL);
1542 }
1543 }
1544 }
1545 }
1546 else
1547 {
1548 if (dropable) // enter new obj
1549 {
1550 Evas_Coord ox, oy;
1551
1552 sel_debug("enter %p\n", dropable->obj);
1553 evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL);
1554 dropable->last.in = EINA_TRUE;
1555
1556 Drop_Format *df;
1557 Efl_Dnd_Drag_Pos pos_data;
1558 if (!dropable->is_container)
1559 {
1560 pos_data.pos = EINA_POSITION2D(pos.x - ox, pos.y - oy);
1561 pos_data.item = NULL;
1562 }
1563 else
1564 {
1565 Eina_Position2D posret;
1566 Efl_Object *it = NULL;
1567 if (dropable->item_func)
1568 it = dropable->item_func(dropable->item_func_data, dropable->obj,
1569 pos, &posret);
1570 pos_data.pos = posret;
1571 pos_data.item = it;
1572 }
1573 pos_data.format = dropable->last.format;
1574 pos_data.action = action;
1575 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
1576 {
1577 if (df->format & dropable->last.format)
1578 {
1579 //efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL);
1580 //efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data);
1581 }
1582 }
1583 }
1584 else
1585 {
1586 sel_debug("both dropable & last_dropable are null\n");
1587 }
1588 }
1589}
1590
1591static Sel_Manager_Dropable *
1592_x11_dropable_find(Efl_Selection_Manager_Data *pd, Ecore_X_Window win)
1593{
1594 Eina_List *l;
1595 Sel_Manager_Dropable *dropable;
1596
1597 if (!pd->drop_list) return NULL;
1598 EINA_LIST_FOREACH(pd->drop_list, l, dropable)
1599 {
1600 if (_x11_xwin_get(dropable->obj) == win) return dropable;
1601 }
1602 return NULL;
1603}
1604
1605static Evas *
1606_x11_evas_get_from_xwin(Efl_Selection_Manager_Data *pd, Ecore_X_Window win)
1607{
1608 /* Find the Evas connected to the window */
1609 Sel_Manager_Dropable *dropable = _x11_dropable_find(pd, win);
1610 return dropable ? evas_object_evas_get(dropable->obj) : NULL;
1611}
1612
1613static Efl_Selection_Action
1614_x11_dnd_action_map(Ecore_X_Atom action)
1615{
1616 Efl_Selection_Action act = EFL_SELECTION_ACTION_UNKNOWN;
1617
1618 if (action == ECORE_X_ATOM_XDND_ACTION_COPY)
1619 act = EFL_SELECTION_ACTION_COPY;
1620 else if (action == ECORE_X_ATOM_XDND_ACTION_MOVE)
1621 act = EFL_SELECTION_ACTION_MOVE;
1622 else if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE)
1623 act = EFL_SELECTION_ACTION_PRIVATE;
1624 else if (action == ECORE_X_ATOM_XDND_ACTION_ASK)
1625 act = EFL_SELECTION_ACTION_ASK;
1626 else if (action == ECORE_X_ATOM_XDND_ACTION_LIST)
1627 act = EFL_SELECTION_ACTION_LIST;
1628 else if (action == ECORE_X_ATOM_XDND_ACTION_LINK)
1629 act = EFL_SELECTION_ACTION_LINK;
1630 else if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION)
1631 act = EFL_SELECTION_ACTION_DESCRIPTION;
1632 return act;
1633}
1634
1635static Ecore_X_Atom
1636_x11_dnd_action_rev_map(Efl_Selection_Action action)
1637{
1638 Ecore_X_Atom act = ECORE_X_ATOM_XDND_ACTION_MOVE;
1639
1640 if (action == EFL_SELECTION_ACTION_COPY)
1641 act = ECORE_X_ATOM_XDND_ACTION_COPY;
1642 else if (action == EFL_SELECTION_ACTION_MOVE)
1643 act = ECORE_X_ATOM_XDND_ACTION_MOVE;
1644 else if (action == EFL_SELECTION_ACTION_PRIVATE)
1645 act = ECORE_X_ATOM_XDND_ACTION_PRIVATE;
1646 else if (action == EFL_SELECTION_ACTION_ASK)
1647 act = ECORE_X_ATOM_XDND_ACTION_ASK;
1648 else if (action == EFL_SELECTION_ACTION_LIST)
1649 act = ECORE_X_ATOM_XDND_ACTION_LIST;
1650 else if (action == EFL_SELECTION_ACTION_LINK)
1651 act = ECORE_X_ATOM_XDND_ACTION_LINK;
1652 else if (action == EFL_SELECTION_ACTION_DESCRIPTION)
1653 act = ECORE_X_ATOM_XDND_ACTION_DESCRIPTION;
1654 return act;
1655}
1656
1657static Eina_Bool
1658_x11_dnd_enter(void *data, int etype EINA_UNUSED, void *ev)
1659{
1660 Sel_Manager_Seat_Selection *seat_sel = data;
1661 Efl_Selection_Manager_Data *pd = seat_sel->pd;
1662 Ecore_X_Event_Xdnd_Enter *enter = ev;
1663 Sel_Manager_Dropable *dropable;
1664 int i;
1665
1666 sel_debug("In");
1667 if (!enter) return EINA_TRUE;
1668 dropable = _x11_dropable_find(pd, enter->win);
1669 if (dropable)
1670 {
1671 sel_debug("Enter %x\n", enter->win);
1672 }
1673 /* Skip it */
1674 sel_debug("enter types=%p (%d)\n", enter->types, enter->num_types);
1675 if ((!enter->num_types) || (!enter->types)) return EINA_TRUE;
1676
1677 sel_debug("Types\n");
1678 seat_sel->saved_types->ntypes = enter->num_types;
1679 free(seat_sel->saved_types->types);
1680 seat_sel->saved_types->types = malloc(sizeof(char *) * enter->num_types);
1681 if (!seat_sel->saved_types->types) return EINA_FALSE;
1682
1683 for (i = 0; i < enter->num_types; i++)
1684 {
1685 seat_sel->saved_types->types[i] = eina_stringshare_add(enter->types[i]);
1686 sel_debug("Type is %s %p %p\n", enter->types[i],
1687 seat_sel->saved_types->types[i], pd->text_uri);
1688 if (seat_sel->saved_types->types[i] == pd->text_uri)
1689 {
1690 /* Request it, so we know what it is */
1691 sel_debug("Sending uri request\n");
1692 seat_sel->saved_types->textreq = 1;
1693 ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free);
1694 ecore_x_selection_xdnd_request(enter->win, pd->text_uri);
1695 }
1696 }
1697
1698 /* FIXME: Find an object and make it current */
1699 return EINA_TRUE;
1700}
1701
1702static Eina_Bool
1703_x11_dnd_position(void *data, int etype EINA_UNUSED, void *ev)
1704{
1705 Sel_Manager_Seat_Selection *seat_sel = data;
1706 Efl_Selection_Manager_Data *pd = seat_sel->pd;
1707 Ecore_X_Event_Xdnd_Position *xpos = ev;
1708 Ecore_X_Rectangle rect = { 0, 0, 0, 0 };
1709 Sel_Manager_Dropable *dropable;
1710 Efl_Selection_Action act;
1711
1712 sel_debug("In");
1713 /* Need to send a status back */
1714 /* FIXME: Should check I can drop here */
1715 /* FIXME: Should highlight widget */
1716 dropable = _x11_dropable_find(pd, xpos->win);
1717 if (dropable)
1718 {
1719 Evas_Coord ox = 0, oy = 0;
1720 Eina_Position2D pos;
1721
1722 act = _x11_dnd_action_map(xpos->action);
1723 pos.x = xpos->position.x;
1724 pos.y = xpos->position.y;
1725 _dropable_coords_adjust(dropable, &pos);
1726 Evas *evas = _x11_evas_get_from_xwin(pd, xpos->win);
1727 Eina_List *dropable_list = evas ? _dropable_list_geom_find(pd, evas, pos.x, pos.y) : NULL;
1728 /* check if there is dropable (obj) can accept this drop */
1729 if (dropable_list)
1730 {
1731 Efl_Selection_Format saved_format = _dnd_types_to_format(pd, seat_sel->saved_types->types, seat_sel->saved_types->ntypes);
1732 Eina_List *l;
1733 Eina_Bool found = EINA_FALSE;
1734
1735 EINA_LIST_FOREACH(dropable_list, l, dropable)
1736 {
1737 Drop_Format *df;
1738 Eina_Inlist *itr;
1739 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
1740 {
1741 Efl_Selection_Format common_fmt = saved_format & df->format;
1742 if (common_fmt)
1743 {
1744 //We found a target that can accept this type of data
1745 int i, min_index = SELECTION_N_ATOMS;
1746 //We have to find the first atom that corresponds to one
1747 //of the supported data types.
1748 for (i = 0; i < seat_sel->saved_types->ntypes; i++)
1749 {
1750 Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, seat_sel->saved_types->types[i]);
1751 if (atom && (atom->format & common_fmt))
1752 {
1753 int atom_idx = (atom - pd->atom_list);
1754 if (min_index > atom_idx) min_index = atom_idx;
1755 }
1756 }
1757 if (min_index != SELECTION_N_ATOMS)
1758 {
1759 sel_debug("Found atom %s\n", pd->atom_list[min_index].name);
1760 found = EINA_TRUE;
1761 dropable->last.type = pd->atom_list[min_index].name;
1762 dropable->last.format = common_fmt;
1763 break;
1764 }
1765 }
1766 }
1767 if (found) break;
1768 }
1769 if (found)
1770 {
1771 Sel_Manager_Dropable *d = NULL;
1772 Eina_Rectangle inter_rect = {0, 0, 0, 0};
1773 int idx = 0;
1774 EINA_LIST_FOREACH(dropable_list, l, d)
1775 {
1776 if (idx == 0)
1777 {
1778 evas_object_geometry_get(d->obj, &inter_rect.x, &inter_rect.y,
1779 &inter_rect.w, &inter_rect.h);
1780 }
1781 else
1782 {
1783 Eina_Rectangle cur_rect;
1784 evas_object_geometry_get(d->obj, &cur_rect.x, &cur_rect.y,
1785 &cur_rect.w, &cur_rect.h);
1786 if (!eina_rectangle_intersection(&inter_rect, &cur_rect)) continue;
1787 }
1788 idx++;
1789 }
1790 rect.x = inter_rect.x;
1791 rect.y = inter_rect.y;
1792 rect.width = inter_rect.w;
1793 rect.height = inter_rect.h;
1794 ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, xpos->action);
1795 sel_debug("dnd position %i %i %p\n", pos.x - ox, pos.y - oy, dropable);
1796 pos.x = pos.x - ox;
1797 pos.y = pos.y - oy;
1798 _x11_dnd_dropable_handle(pd, dropable, pos, act);
1799 // CCCCCCC: call dnd exit on last obj if obj != last
1800 // CCCCCCC: call drop position on obj
1801 }
1802 else
1803 {
1804 //if not: send false status
1805 ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action);
1806 sel_debug("dnd position (%d, %d) not in obj\n", pos.x, pos.y);
1807 _x11_dnd_dropable_handle(pd, NULL, EINA_POSITION2D(0, 0), act);
1808 // CCCCCCC: call dnd exit on last obj
1809 }
1810 eina_list_free(dropable_list);
1811 }
1812 else
1813 {
1814 ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action);
1815 sel_debug("dnd position (%d, %d) has no drop\n", pos.x, pos.y);
1816 _x11_dnd_dropable_handle(pd, NULL, EINA_POSITION2D(0, 0), act);
1817 }
1818 }
1819 else
1820 {
1821 ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action);
1822 }
1823 return EINA_TRUE;
1824}
1825
1826static Eina_Bool
1827_x11_dnd_leave(void *data, int etype EINA_UNUSED, void *ev)
1828{
1829 Sel_Manager_Seat_Selection *seat_sel = data;
1830 Eina_Position2D pos = {0, 0};
1831#ifdef DEBUGON
1832 sel_debug("Leave %x\n", ((Ecore_X_Event_Xdnd_Leave *)ev)->win);
1833#else
1834 (void)ev;
1835#endif
1836 _x11_dnd_dropable_handle(seat_sel->pd, NULL, pos, EFL_SELECTION_ACTION_UNKNOWN);
1837 // CCCCCCC: call dnd exit on last obj if there was one
1838 // leave->win leave->source
1839 return EINA_TRUE;
1840}
1841
1842static Eina_Bool
1843_x11_dnd_drop(void *data, int etype EINA_UNUSED, void *ev)
1844{
1845 sel_debug("In");
1846 Sel_Manager_Seat_Selection *seat_sel = data;
1847 Efl_Selection_Manager_Data *pd = seat_sel->pd;
1848 Ecore_X_Event_Xdnd_Drop *drop;
1849 Sel_Manager_Dropable *dropable = NULL;
1850 Efl_Selection_Data ddata;
1851 Evas_Coord x = 0, y = 0;
1852 Efl_Selection_Action act = EFL_SELECTION_ACTION_UNKNOWN;
1853 Eina_List *l;
1854 Eina_Inlist *itr;
1855 Sel_Manager_Selection *sel;
1856
1857 drop = ev;
1858 sel_debug("drop_list %p (%d)\n", pd->drop_list, eina_list_count(pd->drop_list));
1859 if (!(dropable = _x11_dropable_find(pd, drop->win))) return EINA_TRUE;
1860
1861 /* Calculate real (widget relative) position */
1862 // - window position
1863 // - widget position
1864 seat_sel->saved_types->pos = EINA_POSITION2D(drop->position.x, drop->position.y);
1865 _dropable_coords_adjust(dropable, &seat_sel->saved_types->pos);
1866
1867 sel_debug("Drop position is %d,%d\n", seat_sel->saved_types->pos.x, seat_sel->saved_types->pos.y);
1868
1869 EINA_LIST_FOREACH(pd->drop_list, l, dropable)
1870 {
1871 if (dropable->last.in)
1872 {
1873 evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL);
1874 seat_sel->saved_types->pos.x -= x;
1875 seat_sel->saved_types->pos.y -= y;
1876 goto found;
1877 }
1878 }
1879
1880 sel_debug("Didn't find a target\n");
1881 return EINA_TRUE;
1882
1883found:
1884 sel_debug("0x%x\n", drop->win);
1885
1886 act = _x11_dnd_action_map(drop->action);
1887
1888 dropable->last.in = EINA_FALSE;
1889 sel_debug("Last type: %s - Last format: %X\n", dropable->last.type, dropable->last.format);
1890 if ((!strcmp(dropable->last.type, pd->text_uri)))
1891 {
1892 sel_debug("We found a URI... (%scached) %s\n",
1893 seat_sel->saved_types->imgfile ? "" : "not ",
1894 seat_sel->saved_types->imgfile);
1895 if (seat_sel->saved_types->imgfile)
1896 {
1897 Drop_Format *df;
1898
1899 if (!dropable->is_container)
1900 {
1901 ddata.pos = seat_sel->saved_types->pos;
1902 ddata.item = NULL;
1903 }
1904 else
1905 {
1906 //for container
1907 Efl_Object *it = NULL;
1908 Evas_Coord x0 = 0, y0 = 0;
1909 Eina_Position2D pos, posret;
1910
1911 evas_object_geometry_get(dropable->obj, &x0, &y0, NULL, NULL);
1912 pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + x0,
1913 seat_sel->saved_types->pos.y + y0);
1914 if (dropable->item_func)
1915 it = dropable->item_func(dropable->item_func_data, dropable->obj,
1916 pos, &posret);
1917 ddata.pos = posret;
1918 ddata.item = it;
1919 }
1920 ddata.action = act;
1921
1922 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
1923 {
1924 if (df->format & EFL_SELECTION_FORMAT_IMAGE)
1925 {
1926 sel_debug("Doing image insert (%s)\n", seat_sel->saved_types->imgfile);
1927 ddata.format = EFL_SELECTION_FORMAT_IMAGE;
1928 ddata.data.mem = (char *)seat_sel->saved_types->imgfile;
1929 ddata.data.len = strlen(ddata.data.mem);
1930 //if (df->format & dropable->last.format)
1931 // efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata);
1932 }
1933 else
1934 {
1935 sel_debug("Item doesn't support images... passing\n");
1936 }
1937 }
1938 ecore_x_dnd_send_finished();
1939 ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free);
1940 return EINA_TRUE;
1941 }
1942 else if (seat_sel->saved_types->textreq)
1943 {
1944 /* Already asked: Pretend we asked now, and paste immediately when
1945 * it comes in */
1946 seat_sel->saved_types->textreq = 0;
1947 ecore_x_dnd_send_finished();
1948 return EINA_TRUE;
1949 }
1950 }
1951
1952 sel = seat_sel->sel_list + EFL_SELECTION_TYPE_DND;
1953 sel_debug("doing a request then: %s\n", dropable->last.type);
1954 sel->xwin = drop->win;
1955 sel->request_obj = dropable->obj;
1956 sel->request_format = dropable->last.format;
1957 sel->active = EINA_TRUE;
1958 sel->action = act;
1959 ecore_x_selection_xdnd_request(drop->win, dropable->last.type);
1960
1961 return EINA_TRUE;
1962}
1963
1964static Eina_Bool
1965_x11_sel_manager_drop_target_add(Efl_Selection_Manager_Data *pd, Efl_Object *target_obj,
1966 Efl_Selection_Format format, Ecore_X_Window xwin,
1967 unsigned int seat)
1968{
1969 ERR("In");
1970 Sel_Manager_Dropable *dropable = NULL;
1971 Eina_List *l;
1972 Eina_Bool have_drop_list = EINA_FALSE;
1973 Sel_Manager_Seat_Selection *seat_sel = NULL;
1974
1975 /* Is this the first? */
1976 EINA_LIST_FOREACH(pd->drop_list, l, dropable)
1977 {
1978 if (xwin == _x11_xwin_get(dropable->obj))
1979 {
1980 have_drop_list = EINA_TRUE;
1981 break;
1982 }
1983 }
1984 dropable = NULL; // In case of error, we don't want to free it
1985
1986
1987 Drop_Format *df = calloc(1, sizeof(Drop_Format));
1988 if (!df) return EINA_FALSE;
1989 df->format = format;
1990
1991 dropable = efl_key_data_get(target_obj, "__elm_dropable");
1992 if (!dropable)
1993 {
1994 /* Create new drop */
1995 dropable = calloc(1, sizeof(Sel_Manager_Dropable));
1996 if (!dropable) goto error;
1997 dropable->last.in = EINA_FALSE;
1998 pd->drop_list = eina_list_append(pd->drop_list, dropable);
1999 if (!pd->drop_list) goto error;
2000 dropable->obj = target_obj;
2001 efl_key_data_set(target_obj, "__elm_dropable", dropable);
2002 }
2003 dropable->format_list = eina_inlist_append(dropable->format_list, EINA_INLIST_GET(df));
2004 dropable->seat = seat;
2005
2006 evas_object_event_callback_add(target_obj, EVAS_CALLBACK_DEL,
2007 _all_drop_targets_cbs_del, pd);
2008 if (!have_drop_list) ecore_x_dnd_aware_set(xwin, EINA_TRUE);
2009
2010 seat_sel = _x11_sel_manager_seat_selection_init(pd, seat);
2011
2012 if (seat_sel->enter_handler) return EINA_TRUE;
2013 sel_debug("Adding drop target calls xwin=%#llx", (unsigned long long)xwin);
2014 seat_sel->enter_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
2015 _x11_dnd_enter, seat_sel);
2016 seat_sel->leave_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE,
2017 _x11_dnd_leave, seat_sel);
2018 seat_sel->pos_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
2019 _x11_dnd_position, seat_sel);
2020 seat_sel->drop_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
2021 _x11_dnd_drop, seat_sel);
2022 return EINA_TRUE;
2023error:
2024 free(df);
2025 free(dropable);
2026 return EINA_FALSE;
2027}
2028
2029#endif
2030
2031//Wayland
2032#ifdef HAVE_ELEMENTARY_WL2
2033static Sel_Manager_Seat_Selection *
2034_wl_sel_manager_seat_selection_init(Efl_Selection_Manager_Data *pd, unsigned int seat)
2035{
2036 Sel_Manager_Seat_Selection *seat_sel = NULL;
2037 Eina_List *l = NULL;
2038
2039 EINA_LIST_FOREACH(pd->seat_list, l, seat_sel)
2040 {
2041 if(seat_sel->seat == seat)
2042 break;
2043 }
2044 if (!seat_sel)
2045 {
2046 seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection));
2047 if (!seat_sel)
2048 {
2049 ERR("Failed to allocate seat");
2050 return NULL;
2051 }
2052 seat_sel->saved_types = calloc(1, sizeof(Saved_Type));
2053 seat_sel->seat = seat;
2054 seat_sel->pd = pd;
2055 pd->seat_list = eina_list_append(pd->seat_list, seat_sel);
2056 }
2057 if (!seat_sel->sel)
2058 {
2059 Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection));
2060 if (!sel)
2061 {
2062 ERR("failed to allocate selection");
2063 return NULL;
2064 }
2065 sel->seat_sel = seat_sel;
2066 seat_sel->sel = sel;
2067 }
2068
2069 return seat_sel;
2070}
2071
2072static void
2073_wl_drag_source_del(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED)
2074{
2075 Sel_Manager_Seat_Selection *seat_sel = data;
2076 if (seat_sel->drag_obj == obj)
2077 seat_sel->drag_obj = NULL;
2078}
2079
2080static void
2081_wl_efl_sel_manager_drag_start(Eo *obj, Efl_Selection_Manager_Data *pd, Efl_Object *drag_obj,
2082 Efl_Selection_Format format, Eina_Slice data,
2083 Efl_Selection_Action action, void *icon_func_data,
2084 Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb,
2085 Ecore_Wl2_Window *win, unsigned int seat)
2086{
2087 Ecore_Evas *ee;
2088 Evas_Object *icon = NULL;
2089 int x, y, x2 = 0, y2 = 0, x3, y3, w = 0, h = 0;
2090 const char *types[SELECTION_N_ATOMS + 1];
2091 int i, nb_types = 0;
2092 Ecore_Wl2_Window *parent = NULL;
2093 Sel_Manager_Seat_Selection *seat_sel;
2094 Sel_Manager_Selection *sel;
2095
2096 sel_debug("In");
2097 seat_sel = _wl_sel_manager_seat_selection_init(pd, seat);
2098 if (!seat_sel) return;
2099 seat_sel->active_type = EFL_SELECTION_TYPE_DND;
2100 sel = seat_sel->sel;
2101
2102 sel_debug("checking drag_win: %p", seat_sel->drag_win);
2103 /* if we already have a drag, get out */
2104 if (seat_sel->drag_win) return;
2105
2106 for (i = SELECTION_ATOM_LISTING_ATOMS + 1; i < SELECTION_N_ATOMS; i++)
2107 {
2108 if (format == EFL_SELECTION_FORMAT_TARGETS || (pd->atom_list[i].format & format))
2109 {
2110 types[nb_types++] = pd->atom_list[i].name;
2111 sel_debug("set dnd type: %s\n", pd->atom_list[i].name);
2112 }
2113 }
2114 types[nb_types] = NULL;
2115
2116 ecore_wl2_dnd_drag_types_set(_wl_seat_get(win, drag_obj, seat), types);
2117
2118 /* set the drag data used when a drop occurs */
2119 free(sel->data.mem);
2120 sel->data.len = 0;
2121 sel->data = eina_slice_dup(data);
2122
2123 /* setup callback to notify if this object gets deleted */
2124 evas_object_event_callback_add(drag_obj, EVAS_CALLBACK_DEL,
2125 _wl_drag_source_del, sel);
2126
2127 seat_sel->drag_obj = drag_obj;
2128 seat_sel->drag_action = action;
2129
2130 seat_sel->drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND);
2131 elm_win_alpha_set(seat_sel->drag_win, EINA_TRUE);
2132 elm_win_borderless_set(seat_sel->drag_win, EINA_TRUE);
2133 elm_win_override_set(seat_sel->drag_win, EINA_TRUE);
2134
2135 win = elm_win_wl_window_get(seat_sel->drag_win);
2136
2137 if (icon_func)
2138 {
2139 Eina_Position2D off;
2140
2141 icon = icon_func(icon_func_data, seat_sel->drag_win, drag_obj, &off);
2142 if (icon)
2143 {
2144 x2 = off.x;
2145 y2 = off.y;
2146 evas_object_geometry_get(icon, NULL, NULL, &w, &h);
2147 }
2148 }
2149 else
2150 {
2151 icon = elm_icon_add(seat_sel->drag_win);
2152 evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND,
2153 EVAS_HINT_EXPAND);
2154 }
2155
2156 elm_win_resize_object_add(seat_sel->drag_win, icon);
2157 evas_object_show(icon);
2158
2159 /* Position subwindow appropriately */
2160 ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_obj));
2161 ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
2162 x += x2;
2163 y += y2;
2164 seat_sel->drag_win_start.x = seat_sel->drag_win_end.x = x;
2165 seat_sel->drag_win_start.y = seat_sel->drag_win_end.y = y;
2166
2167 evas_object_move(seat_sel->drag_win, x, y);
2168 evas_object_resize(seat_sel->drag_win, w, h);
2169 evas_object_show(seat_sel->drag_win);
2170
2171 evas_pointer_canvas_xy_get(evas_object_evas_get(drag_obj), &x3, &y3);
2172 seat_sel->drag_pos.x = x3 - x2;
2173 seat_sel->drag_pos.y = y3 - y2;
2174
2175 if (elm_widget_is(drag_obj))
2176 {
2177 Evas_Object *top;
2178
2179 top = elm_widget_top_get(drag_obj);
2180 if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(drag_obj));
2181 if (top && (efl_isa(top, EFL_UI_WIN_CLASS)))
2182 parent = elm_win_wl_window_get(top);
2183 }
2184 if (!parent)
2185 {
2186 Evas *evas;
2187
2188 if (!(evas = evas_object_evas_get(drag_obj)))
2189 return;
2190 if (!(ee = ecore_evas_ecore_evas_get(evas)))
2191 return;
2192
2193 parent = ecore_evas_wayland2_window_get(ee);
2194 }
2195
2196 sel->drag_serial = ecore_wl2_dnd_drag_start(_wl_seat_get(win, drag_obj, seat), parent, win);
2197}
2198
2199static Eina_Bool
2200_wl_is_uri_type_data(const char *data, int len)
2201{
2202 char *p;
2203 if (len < 6) return EINA_FALSE;
2204
2205 p = (char *)data;
2206 if (!p) return EINA_FALSE;
2207 if (strncmp(p, "file:/", 6))
2208 {
2209 if (*p != '/') return EINA_FALSE;
2210 }
2211 return EINA_TRUE;
2212}
2213
2214static Efl_Selection_Action
2215_wl_to_elm(Ecore_Wl2_Drag_Action action)
2216{
2217 #define CONV(wl, elm) if (action == wl) return elm;
2218 CONV(ECORE_WL2_DRAG_ACTION_COPY, EFL_SELECTION_ACTION_COPY);
2219 CONV(ECORE_WL2_DRAG_ACTION_MOVE, EFL_SELECTION_ACTION_MOVE);
2220 CONV(ECORE_WL2_DRAG_ACTION_ASK, EFL_SELECTION_ACTION_ASK);
2221 #undef CONV
2222 return EFL_SELECTION_ACTION_UNKNOWN;
2223}
2224
2225static Eina_Bool
2226_wl_targets_converter(char *target, Sel_Manager_Selection *sel, void *data EINA_UNUSED, int size EINA_UNUSED, void **data_ret, int *size_ret)
2227{
2228 sel_debug("in\n");
2229 if (!data_ret) return EINA_FALSE;
2230
2231 const char *sep = "\n";
2232 char *aret;
2233 int len = 0;
2234 int i = 0;
2235 Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel;
2236 Efl_Selection_Manager_Data *pd = seat_sel->pd;
2237 Efl_Selection_Format format = EFL_SELECTION_FORMAT_NONE;
2238 Eina_Bool is_uri = EINA_FALSE;
2239
2240 if (sel->format)
2241 {
2242 format = sel->format;
2243 is_uri = _wl_is_uri_type_data(sel->data.mem, sel->data.len);
2244 }
2245 else
2246 {
2247 Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, target);
2248 if (atom)
2249 format = atom->format;
2250 }
2251 for (i = 0; i < SELECTION_N_ATOMS; i++)
2252 {
2253 if (format & pd->atom_list[i].format)
2254 {
2255 if ((is_uri) ||
2256 ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list")))
2257 len += strlen(pd->atom_list[i].name) + strlen(sep);
2258 }
2259 }
2260 len++; //terminating null byte
2261 aret = calloc(1, len * sizeof(char));
2262 if (!aret) return EINA_FALSE;
2263 for (i = 0; i < SELECTION_N_ATOMS; i++)
2264 {
2265 if (format & pd->atom_list[i].format)
2266 {
2267 if ((is_uri) ||
2268 ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list")))
2269 {
2270 aret = strcat(aret, pd->atom_list[i].name);
2271 aret = strcat(aret, sep);
2272 }
2273 }
2274 }
2275 *data_ret = aret;
2276 if (size_ret) *size_ret = len;
2277
2278 return EINA_TRUE;
2279}
2280
2281static Eina_Bool
2282_wl_general_converter(char *target, Sel_Manager_Selection *sel, void *data, int size, void **data_ret, int *size_ret)
2283{
2284 Efl_Selection_Format format = EFL_SELECTION_FORMAT_NONE;
2285 Sel_Manager_Atom *atom = NULL;
2286 Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel;
2287 Efl_Selection_Manager_Data *pd = seat_sel->pd;
2288
2289 sel_debug("in\n");
2290
2291 atom = eina_hash_find(pd->type_hash, target);
2292 if (atom)
2293 format = atom->format;
2294 if (format == EFL_SELECTION_FORMAT_NONE)
2295 {
2296 if (data_ret)
2297 {
2298 *data_ret = malloc(size * sizeof(char) + 1);
2299 if (!*data_ret) return EINA_FALSE;
2300 memcpy(*data_ret, data, size);
2301 ((char**)(data_ret))[0][size] = 0;
2302 }
2303 if (size_ret) *size_ret = size;
2304 }
2305 else
2306 {
2307 if (data)
2308 {
2309 if (data_ret) *data_ret = strdup(data);
2310 if (size_ret) *size_ret = strlen(data);
2311 }
2312 else
2313 {
2314 if (data_ret) *data_ret = NULL;
2315 if (size_ret) *size_ret = 0;
2316 }
2317 }
2318
2319 return EINA_TRUE;
2320}
2321
2322static Eina_Bool
2323_wl_text_converter(char *target, Sel_Manager_Selection *sel, void *data, int size, void **data_ret, int *size_ret)
2324{
2325 Efl_Selection_Format format = EFL_SELECTION_FORMAT_NONE;
2326 Sel_Manager_Atom *atom = NULL;
2327 Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel;
2328 Efl_Selection_Manager_Data *pd = seat_sel->pd;
2329
2330 sel_debug("in\n");
2331
2332 atom = eina_hash_find(pd->type_hash, target);
2333 if (atom)
2334 format = atom->format;
2335 if (format == EFL_SELECTION_FORMAT_NONE)
2336 {
2337 if (data_ret)
2338 {
2339 *data_ret = malloc(size * sizeof(char) + 1);
2340 if (!*data_ret) return EINA_FALSE;
2341 memcpy(*data_ret, data, size);
2342 ((char**)(data_ret))[0][size] = 0;
2343 if (size_ret) *size_ret = size;
2344 return EINA_TRUE;
2345 }
2346 }
2347 else if ((format & EFL_SELECTION_FORMAT_MARKUP) ||
2348 (format & EFL_SELECTION_FORMAT_HTML))
2349 {
2350 *data_ret = _elm_util_mkup_to_text(data);
2351 if (size_ret && *data_ret) *size_ret = strlen(*data_ret);
2352 }
2353 else if (format & EFL_SELECTION_FORMAT_TEXT)
2354 {
2355 *data_ret = strdup(data);
2356 if (size_ret && *data_ret) *size_ret = strlen(*data_ret);
2357 }
2358 else if (format & EFL_SELECTION_FORMAT_IMAGE)
2359 {
2360 sel_debug("Image %s\n", evas_object_type_get(sel->request_obj));
2361 efl_file_get(sel->request_obj, (const char **)data_ret, NULL);
2362 if (!*data_ret) *data_ret = strdup("No file");
2363 else *data_ret = strdup(*data_ret);
2364
2365 if (!*data_ret)
2366 {
2367 ERR("Failed to allocate memory!");
2368 *size_ret = 0;
2369 return EINA_FALSE;
2370 }
2371
2372 if (size_ret) *size_ret = strlen(*data_ret);
2373 }
2374 return EINA_TRUE;
2375}
2376
2377static void
2378_wl_sel_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
2379{
2380 Sel_Manager_Selection *sel = data;
2381 if (sel->owner == obj)
2382 {
2383 sel->owner = NULL;
2384 }
2385 //if (dragwidget == obj) dragwidget = NULL;
2386}
2387
2388static Eina_Future *
2389_wl_efl_sel_manager_selection_set(Efl_Selection_Manager_Data *pd,
2390 Efl_Object *owner, Efl_Selection_Type type,
2391 Efl_Selection_Format format,
2392 Eina_Slice data,
2393 Ecore_Wl2_Window *win,
2394 unsigned int seat)
2395{
2396 Sel_Manager_Seat_Selection *seat_sel;
2397 Sel_Manager_Selection *sel;
2398 int i = 0, count = 0;
2399 Eina_Bool is_uri = EINA_FALSE;
2400 const char **types;
2401
2402 if ((!data.mem) && (format != EFL_SELECTION_FORMAT_IMAGE))
2403 {
2404 efl_selection_manager_selection_clear(pd->sel_man, owner, type, seat);
2405 return NULL;
2406 }
2407
2408 if (data.len <= 0)
2409 return NULL;
2410
2411 seat_sel = _wl_sel_manager_seat_selection_init(pd, seat);
2412 seat_sel->active_type = type;
2413 sel = seat_sel->sel;
2414
2415 if (sel->owner != owner)
2416 {
2417 Eina_List *l, *l_next;
2418 Sel_Manager_Selection_Lost *sel_lost;
2419
2420 EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost)
2421 {
2422 if ((sel_lost->request == sel->owner) &&
2423 (sel_lost->type == type))
2424 {
2425 eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type));
2426 seat_sel->sel_lost_list = eina_list_remove(seat_sel->sel_lost_list, sel_lost);
2427 free(sel_lost);
2428 }
2429 }
2430 }
2431
2432 if (sel->owner)
2433 evas_object_event_callback_del_full(sel->owner, EVAS_CALLBACK_DEL,
2434 _wl_sel_obj_del, sel);
2435 sel->active = EINA_TRUE;
2436 sel->owner = owner;
2437 sel->win = win;
2438 /* sel->set(win, &selection, sizeof(Elm_Sel_Type)); */
2439 sel->format = format;
2440
2441 evas_object_event_callback_add
2442 (sel->owner, EVAS_CALLBACK_DEL, _wl_sel_obj_del, &sel);
2443
2444 sel->data = eina_slice_dup(data);
2445 if (!sel->data.mem)
2446 {
2447 efl_selection_manager_selection_clear(pd->sel_man, owner, type, seat_sel->seat);
2448 return NULL;
2449 }
2450
2451 is_uri = _wl_is_uri_type_data(sel->data.mem, sel->data.len);
2452 types = malloc(sizeof(char *));
2453 if (!types) return NULL;
2454 for (i = 0, count = 1; i < SELECTION_N_ATOMS; i++)
2455 {
2456 if (format & pd->atom_list[i].format)
2457 {
2458 if ((is_uri) ||
2459 ((!is_uri) && strcmp(pd->atom_list[i].name, "text/uri-list")))
2460 {
2461 const char **t = NULL;
2462
2463 types[count - 1] = pd->atom_list[i].name;
2464 count++;
2465 t = realloc(types, sizeof(char *) * count);
2466 if (!t)
2467 {
2468 free(types);
2469 return NULL;
2470 }
2471 types = t;
2472 }
2473 }
2474 }
2475 types[count - 1] = 0;
2476
2477 sel->selection_serial = ecore_wl2_dnd_selection_set(_wl_seat_get(win, owner, seat_sel->seat), types);
2478 ERR("serial: %d", sel->selection_serial);
2479
2480 free(types);
2481 //return _local_elm_cnp_selection_set(obj, selection, format, buf, buflen);
2482
2483 return _update_sel_lost_list(owner, type, seat_sel);
2484}
2485
2486static void
2487_wl_selection_changed_free(void *data, void *ev EINA_UNUSED)
2488{
2489 ecore_wl2_display_disconnect(data);
2490}
2491
2492static Eina_Bool
2493_wl_selection_changed(void *data, int type EINA_UNUSED, void *event)
2494{
2495 Efl_Selection_Manager_Data *pd = data;
2496 Sel_Manager_Seat_Selection *seat_sel;
2497 Sel_Manager_Selection *sel;
2498 Efl_Selection_Changed e;
2499 Ecore_Wl2_Event_Seat_Selection *ev = event;
2500 Ecore_Wl2_Input *seat;
2501
2502 seat_sel = _wl_sel_manager_seat_selection_init(pd, ev->seat);
2503 sel_debug("seat: %d", ev->seat);
2504 if (!seat_sel) return ECORE_CALLBACK_RENEW;
2505 sel = seat_sel->sel;
2506
2507 seat = ecore_wl2_display_input_find(ev->display, ev->seat);
2508 EINA_SAFETY_ON_NULL_RETURN_VAL(seat, ECORE_CALLBACK_RENEW);
2509 e.type = EFL_SELECTION_TYPE_CLIPBOARD;
2510 e.seat = ev->seat;
2511 /* connect again to add ref */
2512 e.display = ecore_wl2_display_connect(ecore_wl2_display_name_get(ev->display));
2513 e.exist = !!ecore_wl2_dnd_selection_get(seat);
2514 //ecore_event_add(ELM_CNP_EVENT_SELECTION_CHANGED, e, _wl_selection_changed_free, ev->display);
2515 //efl_event_callback_call(sel->request_obj, EFL_SELECTION_EVENT_SELECTION_CHANGED, &e);
2516
2517 return ECORE_CALLBACK_RENEW;
2518}
2519
2520static Eina_Bool
2521_wl_selection_send(void *data, int type, void *event)
2522{
2523 Efl_Selection_Manager_Data *pd = data;
2524 char *buf;
2525 int ret, len_remained;
2526 int len_written = 0;
2527 Ecore_Wl2_Event_Data_Source_Send *ev;
2528 int seat;
2529 Sel_Manager_Seat_Selection *seat_sel;
2530 Sel_Manager_Selection *sel;
2531 void *data_ret = NULL;
2532 int len_ret = 0;
2533 int i = 0;
2534
2535 ev = event;
2536 seat = ev->seat;
2537 sel_debug("seat: %d, type: %d", seat, type);
2538 seat_sel = _wl_sel_manager_seat_selection_init(pd, seat);
2539 if (!seat_sel) return ECORE_CALLBACK_RENEW;
2540 sel = seat_sel->sel;
2541
2542 if ((ev->serial != sel->selection_serial) &&
2543 (ev->serial != sel->drag_serial))
2544 return ECORE_CALLBACK_RENEW;
2545
2546 for (i = 0; i < SELECTION_N_ATOMS; i++)
2547 {
2548 if (!strcmp(pd->atom_list[i].name, ev->type))
2549 {
2550 sel_debug("Found a type: %s\n", pd->atom_list[i].name);
2551 Sel_Manager_Dropable *drop;
2552 drop = efl_key_data_get(sel->request_obj, "__elm_dropable");
2553 if (drop)
2554 drop->last.type = pd->atom_list[i].name;
2555 if (pd->atom_list[i].wl_converter)
2556 {
2557 pd->atom_list[i].wl_converter(ev->type, sel, sel->data.mem,
2558 sel->data.len, &data_ret, &len_ret);
2559 }
2560 else
2561 {
2562 data_ret = strdup(sel->data.mem);
2563 len_ret = sel->data.len;
2564 }
2565 break;
2566 }
2567 }
2568
2569 len_remained = len_ret;
2570 buf = data_ret;
2571
2572 while (len_written < len_ret)
2573 {
2574 ret = write(ev->fd, buf, len_remained);
2575 if (ret == -1) break;
2576 buf += ret;
2577 len_written += ret;
2578 len_remained -= ret;
2579 }
2580 free(data_ret);
2581
2582 close(ev->fd);
2583 return ECORE_CALLBACK_PASS_ON;
2584}
2585
2586static Eina_Bool
2587_wl_dnd_end(void *data, int type EINA_UNUSED, void *event)
2588{
2589 sel_debug("In");
2590 Efl_Selection_Manager_Data *pd = data;
2591 Ecore_Wl2_Event_Data_Source_End *ev;
2592 Sel_Manager_Seat_Selection *seat_sel;
2593 Sel_Manager_Selection *sel;
2594 Ecore_Wl2_Window *win;
2595
2596 ev = event;
2597 seat_sel = _wl_sel_manager_seat_selection_init(pd, ev->seat);
2598 sel = seat_sel->sel;
2599 if (ev->serial != sel->drag_serial)
2600 return ECORE_CALLBACK_RENEW;
2601
2602 //efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_DONE, NULL);
2603 if (seat_sel->drag_win)
2604 {
2605 if (!seat_sel->accept)
2606 {
2607 /* Commit animation when drag cancelled */
2608 /* Record final position of dragwin, then do animation */
2609 ecore_animator_timeline_add(0.3, _drag_cancel_animate, seat_sel);
2610 }
2611 else
2612 {
2613 /* No animation drop was committed */
2614 evas_object_del(seat_sel->drag_win);
2615 seat_sel->drag_win = NULL;
2616 }
2617 }
2618
2619 seat_sel->accept = EINA_FALSE;
2620 win = ecore_wl2_display_window_find(_elm_wl_display, ev->win);
2621 ecore_wl2_input_ungrab(_wl_seat_get(win, NULL, seat_sel->seat));
2622
2623 return ECORE_CALLBACK_PASS_ON;
2624}
2625
2626static Ecore_Wl2_Input *
2627_wl_seat_get(Ecore_Wl2_Window *win, const Evas_Object *obj, unsigned int seat_id)
2628{
2629 Eo *seat, *parent2, *ewin;
2630 Ecore_Wl2_Input *input = NULL;
2631
2632 input = ecore_wl2_display_input_find(ecore_wl2_window_display_get(win), seat_id);
2633 if (input) return input;
2634
2635 if (obj)
2636 {
2637 // FIXME (there might be a better solution):
2638 // In case of inwin, we want to use the main wl2 window for cnp, but obj
2639 // obj belongs to the buffer canvas, so the default seat for obj does not
2640 // match the window win.
2641 Eo *top = elm_widget_top_get(obj);
2642 if (efl_isa(top, EFL_UI_WIN_INLINED_CLASS))
2643 {
2644 parent2 = efl_ui_win_inlined_parent_get(top);
2645 if (parent2) obj = elm_widget_top_get(parent2) ?: parent2;
2646 }
2647 /* fake win means canvas seat id will not match protocol seat id */
2648 ewin = elm_win_get(obj);
2649 if (elm_win_type_get(ewin) == ELM_WIN_FAKE) obj = NULL;
2650 }
2651
2652 if (!obj)
2653 {
2654 Eina_Iterator *it;
2655 it = ecore_wl2_display_inputs_get(ecore_wl2_window_display_get(win));
2656 EINA_ITERATOR_FOREACH(it, input) break;
2657 eina_iterator_free(it);
2658 return input;
2659 }
2660
2661 seat = evas_canvas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT);
2662 EINA_SAFETY_ON_NULL_RETURN_VAL(seat, NULL);
2663 return ecore_wl2_display_input_find(ecore_wl2_window_display_get(win),
2664 evas_device_seat_id_get(seat));
2665}
2666
2667static Ecore_Wl2_Window *
2668_wl_window_get(const Evas_Object *obj)
2669{
2670 Evas_Object *top;
2671 Ecore_Wl2_Window *win = NULL;
2672
2673 if (elm_widget_is(obj))
2674 {
2675 top = elm_widget_top_get(obj);
2676 if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(obj));
2677 if (top && (efl_isa(top, EFL_UI_WIN_CLASS)))
2678 win = elm_win_wl_window_get(top);
2679 }
2680 if (!win)
2681 {
2682 Ecore_Evas *ee;
2683 Evas *evas;
2684 const char *engine_name;
2685
2686 if (!(evas = evas_object_evas_get(obj)))
2687 return NULL;
2688 if (!(ee = ecore_evas_ecore_evas_get(evas)))
2689 return NULL;
2690
2691 engine_name = ecore_evas_engine_name_get(ee);
2692 if (!strcmp(engine_name, ELM_BUFFER))
2693 {
2694 ee = ecore_evas_buffer_ecore_evas_parent_get(ee);
2695 if (!ee) return NULL;
2696 engine_name = ecore_evas_engine_name_get(ee);
2697 }
2698 if (!strncmp(engine_name, "wayland", sizeof("wayland") - 1))
2699 {
2700 /* In case the engine is not a buffer, we want to check once. */
2701 win = ecore_evas_wayland2_window_get(ee);
2702 if (!win) return NULL;
2703 }
2704 }
2705
2706 return win;
2707}
2708
2709static void
2710_wl_selection_receive_timeout(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
2711{
2712 Sel_Manager_Selection *sel = data;
2713
2714 if (sel->request_obj != obj) return;
2715
2716 ecore_event_handler_del(sel->offer_handler);
2717}
2718
2719static Eina_Bool
2720_wl_selection_receive(void *data, int type EINA_UNUSED, void *event)
2721{
2722 Ecore_Wl2_Event_Offer_Data_Ready *ev = event;
2723 Sel_Manager_Selection *sel = data;
2724 ERR("in");
2725
2726 if (sel->sel_offer != ev->offer) return ECORE_CALLBACK_PASS_ON;
2727
2728 if (sel->data_func)
2729 {
2730 Efl_Selection_Data sel_data;
2731
2732 sel_data.pos.x = sel_data.pos.y = 0;
2733 sel_data.format = sel->format;
2734 sel_data.data.mem = ev->data;
2735 sel_data.data.len = ev->len;
2736 sel_data.action = _wl_to_elm(ecore_wl2_offer_action_get(sel->sel_offer));
2737 sel->data_func(sel->data_func_data,
2738 sel->request_obj,
2739 &sel_data);
2740 }
2741 else
2742 {
2743 char *stripstr, *mkupstr;
2744
2745 stripstr = malloc(ev->len + 1);
2746 if (!stripstr) return ECORE_CALLBACK_CANCEL;
2747 strncpy(stripstr, (char *)ev->data, ev->len);
2748 stripstr[ev->len] = '\0';
2749 mkupstr = _elm_util_text_to_mkup((const char *)stripstr);
2750 /* TODO BUG: should never NEVER assume it's an elm_entry! */
2751 _elm_entry_entry_paste(sel->request_obj, mkupstr);
2752 free(stripstr);
2753 free(mkupstr);
2754 }
2755
2756 evas_object_event_callback_del_full(sel->request_obj,
2757 EVAS_CALLBACK_DEL,
2758 _wl_selection_receive_timeout, sel);
2759
2760 ecore_event_handler_del(sel->offer_handler);
2761 return ECORE_CALLBACK_CANCEL;
2762}
2763
2764static Eina_Bool
2765_wl_efl_sel_manager_selection_get(const Efl_Object *request, Efl_Selection_Manager_Data *pd,
2766 Efl_Selection_Type type, Efl_Selection_Format format,
2767 void *data_func_data, Efl_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb,
2768 Ecore_Wl2_Window *win, unsigned int seat)
2769{
2770 sel_debug("In, format: %d", format);
2771 Sel_Manager_Seat_Selection *seat_sel;
2772 Sel_Manager_Selection *sel;
2773 Ecore_Wl2_Input *input;
2774 Ecore_Wl2_Offer *offer;
2775 int i = 0;
2776
2777 if (type == EFL_SELECTION_TYPE_DND) return EINA_FALSE;
2778
2779 //if (sel->active)
2780 //return _local_elm_cnp_selection_get(obj, selection, format, datacb, udata);
2781 seat_sel = _sel_manager_seat_selection_init(pd, seat);
2782 sel = seat_sel->sel;
2783 sel->request_obj = (Efl_Object *)request;
2784 sel->data_func_data = data_func_data;
2785 sel->data_func = data_func;
2786 sel->data_func_free_cb = data_func_free_cb;
2787
2788 input = _wl_seat_get(win, request, seat_sel->seat);
2789 offer = ecore_wl2_dnd_selection_get(input);
2790
2791 //there can be no selection available
2792 if (!offer) return EINA_FALSE;
2793
2794 for (i = 0; sm_wl_convertion[i].translates; i++)
2795 {
2796 int j = 0;
2797 if (!(format & sm_wl_convertion[i].format)) continue;
2798
2799 for (j = 0; sm_wl_convertion[i].translates[j]; j++)
2800 {
2801 if (!ecore_wl2_offer_supports_mime(offer, sm_wl_convertion[i].translates[j])) continue;
2802
2803 //we have found matching mimetypes
2804 sel->sel_offer = offer;
2805 sel->format = sm_wl_convertion[i].format;
2806
2807 sel_debug("request type: %s", (char *)sm_wl_convertion[i].translates[j]);
2808 evas_object_event_callback_add(sel->request_obj, EVAS_CALLBACK_DEL,
2809 _wl_selection_receive_timeout, sel);
2810 sel->offer_handler = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY,
2811 _wl_selection_receive, sel);
2812
2813 ecore_wl2_offer_receive(offer, (char*)sm_wl_convertion[i].translates[j]);
2814 return EINA_TRUE;
2815 }
2816 }
2817
2818 sel_debug("no type match");
2819 return EINA_FALSE;
2820}
2821
2822static void
2823_wl_sel_obj_del2(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
2824{
2825 Sel_Manager_Selection *sel = data;
2826 if (sel->request_obj == obj) sel->request_obj = NULL;
2827}
2828
2829static Sel_Manager_Dropable *
2830_wl_dropable_find(Efl_Selection_Manager_Data *pd, unsigned int win)
2831{
2832 Eina_List *l;
2833 Sel_Manager_Dropable *dropable;
2834 Ecore_Wl2_Window *window;
2835
2836 if (!pd->drop_list) return NULL;
2837
2838 window = ecore_wl2_display_window_find(_elm_wl_display, win);
2839 if (!window) return NULL;
2840
2841 EINA_LIST_FOREACH(pd->drop_list, l, dropable)
2842 if (_wl_window_get(dropable->obj) == window)
2843 return dropable;
2844
2845 return NULL;
2846}
2847
2848static Evas *
2849_wl_evas_get_from_win(Efl_Selection_Manager_Data *pd, unsigned int win)
2850{
2851 Sel_Manager_Dropable *dropable = _wl_dropable_find(pd, win);
2852 return dropable ? evas_object_evas_get(dropable->obj) : NULL;
2853}
2854
2855static Eina_Bool
2856_wl_drops_accept(Sel_Manager_Seat_Selection *seat_sel, const char *type)
2857{
2858 Efl_Selection_Manager_Data *pd;
2859 Sel_Manager_Selection *sel;
2860 Eina_List *l;
2861 Sel_Manager_Dropable *drop;
2862 Eina_Bool will_accept = EINA_FALSE;
2863
2864 if (!type) return EINA_FALSE;
2865
2866 pd = seat_sel->pd;
2867 sel = seat_sel->sel;
2868 EINA_LIST_FOREACH(pd->drop_list, l, drop)
2869 {
2870 Drop_Format *df;
2871 EINA_INLIST_FOREACH(drop->format_list, df)
2872 {
2873 for (int i = 0; sm_wl_convertion[i].translates ; ++i)
2874 {
2875 if (!(sm_wl_convertion[i].format & df->format)) continue;
2876
2877 for (int j = 0; sm_wl_convertion[i].translates[j]; ++j)
2878 {
2879 if (!strncmp(type, sm_wl_convertion[i].translates[j], strlen(sm_wl_convertion[i].translates[j])))
2880 {
2881 sel->request_obj = drop->obj;
2882 return EINA_TRUE;
2883 }
2884 }
2885 }
2886 }
2887 }
2888
2889 return will_accept;
2890}
2891
2892static void
2893_wl_selection_parser(void *_data, int size, char ***ret_data, int *ret_count)
2894{
2895 char **files = NULL;
2896 int num_files = 0;
2897 char *data = NULL;
2898
2899 data = malloc(size);
2900 if (data && (size > 0))
2901 {
2902 int i, is;
2903 char *tmp;
2904 char **t2;
2905
2906 memcpy(data, _data, size);
2907 if (data[size - 1])
2908 {
2909 char *t;
2910
2911 /* Isn't nul terminated */
2912 size++;
2913 t = realloc(data, size);
2914 if (!t) goto done;
2915 data = t;
2916 data[size - 1] = 0;
2917 }
2918
2919 tmp = malloc(size);
2920 if (!tmp) goto done;
2921 i = 0;
2922 is = 0;
2923 while ((is < size) && (data[is]))
2924 {
2925 if ((i == 0) && (data[is] == '#'))
2926 for (; ((data[is]) && (data[is] != '\n')); is++) ;
2927 else
2928 {
2929 if ((data[is] != '\r') && (data[is] != '\n'))
2930 tmp[i++] = data[is++];
2931 else
2932 {
2933 while ((data[is] == '\r') || (data[is] == '\n'))
2934 is++;
2935 tmp[i] = 0;
2936 num_files++;
2937 t2 = realloc(files, num_files * sizeof(char *));
2938 if (t2)
2939 {
2940 files = t2;
2941 files[num_files - 1] = strdup(tmp);
2942 }
2943 else
2944 {
2945 num_files--;
2946 goto freetmp;
2947 }
2948 tmp[0] = 0;
2949 i = 0;
2950 }
2951 }
2952 }
2953 if (i > 0)
2954 {
2955 tmp[i] = 0;
2956 num_files++;
2957 t2 = realloc(files, num_files * sizeof(char *));
2958 if (t2)
2959 {
2960 files = t2;
2961 files[num_files - 1] = strdup(tmp);
2962 }
2963 else
2964 {
2965 num_files--;
2966 goto freetmp;
2967 }
2968 }
2969freetmp:
2970 free(tmp);
2971 }
2972done:
2973 free(data);
2974 if (ret_data) *ret_data = files;
2975 else
2976 {
2977 int i;
2978
2979 for (i = 0; i < num_files; i++) free(files[i]);
2980 free(files);
2981 }
2982 if (ret_count) *ret_count = num_files;
2983}
2984
2985static Eina_Bool
2986_wl_data_preparer_markup(Sel_Manager_Selection *sel, Efl_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED)
2987{
2988 sel_debug("In\n");
2989
2990 ddata->format = EFL_SELECTION_FORMAT_MARKUP;
2991 ddata->data.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE);
2992 ddata->data.len = ev->len;
2993 ddata->action = sel->action;
2994
2995 return EINA_TRUE;
2996}
2997
2998static Eina_Bool
2999_wl_data_preparer_uri(Sel_Manager_Selection *sel, Efl_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED)
3000{
3001 Sel_Manager_Seat_Selection *seat_sel;
3002 char *p, *stripstr = NULL;
3003 char *data = ev->data;
3004 Sel_Manager_Dropable *drop;
3005 const char *type = NULL;
3006
3007 sel_debug("In\n");
3008
3009 seat_sel = sel->seat_sel;
3010 drop = efl_key_data_get(sel->request_obj, "__elm_dropable");
3011 if (drop) type = drop->last.type;
3012
3013 if ((type) && (!strcmp(type, "text/uri-list")))
3014 {
3015 int num_files = 0;
3016 char **files = NULL;
3017 Efreet_Uri *uri;
3018 Eina_Strbuf *strbuf;
3019 int i;
3020
3021 strbuf = eina_strbuf_new();
3022 if (!strbuf) return EINA_FALSE;
3023
3024 _wl_selection_parser(ev->data, ev->len, &files, &num_files);
3025 sel_debug("got a files list\n");
3026
3027 for (i = 0; i < num_files; i++)
3028 {
3029 uri = efreet_uri_decode(files[i]);
3030 if (uri)
3031 {
3032 eina_strbuf_append(strbuf, uri->path);
3033 efreet_uri_free(uri);
3034 }
3035 else
3036 {
3037 eina_strbuf_append(strbuf, files[i]);
3038 }
3039 if (i < (num_files - 1))
3040 eina_strbuf_append(strbuf, "\n");
3041 free(files[i]);
3042 }
3043 free(files);
3044 stripstr = eina_strbuf_string_steal(strbuf);
3045 eina_strbuf_free(strbuf);
3046 }
3047 else
3048 {
3049 Efreet_Uri *uri;
3050
3051 p = (char *)eina_memdup((unsigned char *)data, ev->len, EINA_TRUE);
3052 if (!p) return EINA_FALSE;
3053 uri = efreet_uri_decode(p);
3054 if (!uri)
3055 {
3056 /* Is there any reason why we care of URI without scheme? */
3057 if (p[0] == '/') stripstr = p;
3058 else free(p);
3059 }
3060 else
3061 {
3062 free(p);
3063 stripstr = strdup(uri->path);
3064 efreet_uri_free(uri);
3065 }
3066 }
3067
3068 if (!stripstr)
3069 {
3070 sel_debug("Couldn't find a file\n");
3071 return EINA_FALSE;
3072 }
3073 free(seat_sel->saved_types->imgfile);
3074
3075 ddata->data.mem = stripstr;
3076 ddata->data.len = strlen(stripstr);
3077 ddata->action = sel->action;
3078 ddata->format = sel->request_format;
3079
3080 return EINA_TRUE;
3081}
3082
3083static Eina_Bool
3084_wl_data_preparer_vcard(Sel_Manager_Selection *sel, Efl_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED)
3085{
3086 sel_debug("In\n");
3087
3088 ddata->format = EFL_SELECTION_FORMAT_VCARD;
3089 ddata->data.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE);
3090 ddata->data.len = ev->len;
3091 ddata->action = sel->action;
3092
3093 return EINA_TRUE;
3094}
3095
3096static Eina_Bool
3097_wl_data_preparer_image(Sel_Manager_Selection *sel, Efl_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info)
3098{
3099 sel_debug("In\n");
3100 Tmp_Info *tmp;
3101 int len = 0;
3102
3103 tmp = _tempfile_new(ev->len);
3104 if (!tmp)
3105 return EINA_FALSE;
3106 memcpy(tmp->map, ev->data, ev->len);
3107 munmap(tmp->map, ev->len);
3108
3109 len = strlen(tmp->filename);
3110 ddata->format = EFL_SELECTION_FORMAT_IMAGE;
3111 ddata->data.mem = eina_memdup((unsigned char*)tmp->filename, len, EINA_TRUE);
3112 ddata->data.len = len;
3113 ddata->action = sel->action;
3114 *tmp_info = tmp;
3115
3116 return EINA_TRUE;
3117}
3118
3119static Eina_Bool
3120_wl_data_preparer_text(Sel_Manager_Selection *sel, Efl_Selection_Data *ddata, Ecore_Wl2_Event_Offer_Data_Ready *ev, Tmp_Info **tmp_info EINA_UNUSED)
3121{
3122 sel_debug("In\n");
3123
3124 ddata->format = EFL_SELECTION_FORMAT_TEXT;
3125 ddata->data.mem = eina_memdup((unsigned char *)ev->data, ev->len, EINA_TRUE);
3126 ddata->data.len = ev->len;
3127 ddata->action = sel->action;
3128
3129 return EINA_TRUE;
3130}
3131
3132
3133static void
3134_wl_dropable_handle(Sel_Manager_Seat_Selection *seat_sel, Sel_Manager_Dropable *dropable, Evas_Coord x, Evas_Coord y)
3135{
3136 Sel_Manager_Dropable *d, *last_dropable = NULL;
3137 Efl_Selection_Manager_Data *pd = seat_sel->pd;
3138 Sel_Manager_Selection *sel;
3139 Eina_Inlist *itr;
3140 Eina_List *l;
3141 Eina_Position2D pos;
3142
3143 EINA_LIST_FOREACH(pd->drop_list, l, d)
3144 {
3145 if (d->last.in)
3146 {
3147 last_dropable = d;
3148 break;
3149 }
3150 }
3151
3152 sel = seat_sel->sel;
3153 pos = EINA_POSITION2D(x, y);
3154 /* If we are on the same object, just update the position */
3155 if ((dropable) && (last_dropable == dropable))
3156 {
3157 Evas_Coord ox, oy;
3158 Efl_Dnd_Drag_Pos pos_data;
3159 Drop_Format *df;
3160
3161 evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL);
3162 if (!dropable->is_container)
3163 {
3164 pos_data.pos = EINA_POSITION2D(x - ox, y - oy);
3165 pos_data.item = NULL;
3166 }
3167 else
3168 {
3169 Efl_Object *it = NULL;
3170
3171 if (dropable->item_func)
3172 it = dropable->item_func(dropable->item_func_data, dropable->obj,
3173 pos, &pos_data.pos);
3174 pos_data.item = it;
3175 }
3176 pos_data.format = dropable->last.format;
3177 pos_data.action = sel->action;
3178 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
3179 {
3180 if (df->format & dropable->last.format)
3181 {
3182 //efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data);
3183 }
3184 }
3185
3186 return;
3187 }
3188 /* We leave the last dropable */
3189 if (last_dropable)
3190 {
3191 Drop_Format *df;
3192 sel_debug("leave %p\n", last_dropable->obj);
3193 last_dropable->last.in = EINA_FALSE;
3194
3195 EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df)
3196 {
3197 //if (df->format & last_dropable->last.format)
3198 // efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL);
3199 }
3200 }
3201 /* We enter the new dropable */
3202 if (dropable)
3203 {
3204 sel_debug("enter %p\n", dropable->obj);
3205 Evas_Coord ox, oy;
3206 Efl_Dnd_Drag_Pos pos_data;
3207 Drop_Format *df;
3208
3209 dropable->last.in = EINA_TRUE;
3210 evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL);
3211 if (!dropable->is_container)
3212 {
3213 pos_data.pos = EINA_POSITION2D(x - ox, y - oy);
3214 pos_data.item = NULL;
3215 }
3216 else
3217 {
3218 Efl_Object *it = NULL;
3219
3220 if (dropable->item_func)
3221 it = dropable->item_func(dropable->item_func_data, dropable->obj,
3222 pos, &pos_data.pos);
3223 pos_data.item = it;
3224 }
3225 pos_data.format = dropable->last.format;
3226 pos_data.action = sel->action;
3227
3228 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
3229 {
3230 if (df->format & dropable->last.format)
3231 {
3232 //efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL);
3233 //efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data);
3234 }
3235 }
3236 }
3237}
3238
3239static void
3240_wl_dropable_all_clean(Sel_Manager_Seat_Selection *seat_sel, unsigned int win)
3241{
3242 Eina_List *l;
3243 Sel_Manager_Dropable *dropable;
3244 Ecore_Wl2_Window *window;
3245
3246 window = ecore_wl2_display_window_find(_elm_wl_display, win);
3247 if (!window) return;
3248
3249 EINA_LIST_FOREACH(seat_sel->pd->drop_list, l, dropable)
3250 {
3251 if (_wl_window_get(dropable->obj) == window)
3252 {
3253 dropable->last.pos.x = 0;
3254 dropable->last.pos.y = 0;
3255 dropable->last.in = EINA_FALSE;
3256 }
3257 }
3258}
3259
3260static void
3261_wl_dropable_data_handle(Sel_Manager_Selection *sel, Ecore_Wl2_Event_Offer_Data_Ready *ev)
3262{
3263 Sel_Manager_Seat_Selection *seat_sel;
3264 Efl_Selection_Manager_Data *pd;
3265 Sel_Manager_Dropable *drop;
3266 Ecore_Wl2_Window *win;
3267
3268 sel_debug("In\n");
3269 seat_sel = sel->seat_sel;
3270 pd = seat_sel->pd;
3271 drop = efl_key_data_get(sel->request_obj, "__elm_dropable");
3272 if (drop)
3273 {
3274 Sel_Manager_Atom *atom = NULL;
3275
3276 atom = eina_hash_find(pd->type_hash, drop->last.type);
3277 if (atom && atom->wl_data_preparer)
3278 {
3279 Efl_Selection_Data ddata;
3280 Tmp_Info *tmp_info = NULL;
3281 Eina_Bool success;
3282
3283 sel_debug("Call notify for: %s\n", atom->name);
3284 success = atom->wl_data_preparer(sel, &ddata, ev, &tmp_info);
3285 if (success)
3286 {
3287 Sel_Manager_Dropable *dropable;
3288 Eina_List *l;
3289
3290 EINA_LIST_FOREACH(pd->drop_list, l, dropable)
3291 {
3292 if (dropable->obj == sel->request_obj) break;
3293 dropable = NULL;
3294 }
3295 if (dropable)
3296 {
3297 Drop_Format *df;
3298 Eina_Inlist *itr;
3299
3300 if (!dropable->is_container)
3301 {
3302 ddata.pos.x = seat_sel->saved_types->pos.x;
3303 ddata.pos.y = seat_sel->saved_types->pos.y;
3304 }
3305 else
3306 {
3307 //for container
3308 Efl_Object *it = NULL;
3309 Evas_Coord x0 = 0, y0 = 0;
3310 Eina_Position2D pos, posret;
3311
3312 evas_object_geometry_get(dropable->obj, &x0, &y0, NULL, NULL);
3313 pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + x0,
3314 seat_sel->saved_types->pos.y + y0);
3315 if (dropable->item_func)
3316 it = dropable->item_func(dropable->item_func_data, dropable->obj,
3317 pos, &posret);
3318 ddata.pos = posret;
3319 ddata.item = it;
3320 }
3321 ddata.action = seat_sel->drag_action;
3322
3323 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
3324 {
3325 //if (df->format & dropable->last.format)
3326 // efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata);
3327 }
3328 }
3329 }
3330 win = _wl_window_get(sel->request_obj);
3331 ecore_wl2_dnd_drag_end(_wl_seat_get(win, NULL, seat_sel->seat));
3332 if (tmp_info) _tmpinfo_free(tmp_info);
3333 return;
3334 }
3335 }
3336
3337 win = _wl_window_get(sel->request_obj);
3338 ecore_wl2_dnd_drag_end(_wl_seat_get(win, NULL, seat_sel->seat));
3339 seat_sel->saved_types->textreq = 0;
3340}
3341
3342static Eina_Bool
3343_wl_dnd_enter(void *data, int type EINA_UNUSED, void *event)
3344{
3345 Ecore_Wl2_Event_Dnd_Enter *ev;
3346 Eina_Array *known, *available;
3347 Sel_Manager_Seat_Selection *seat_sel = data;
3348 unsigned int i = 0;
3349
3350 ev = event;
3351
3352 available = ecore_wl2_offer_mimes_get(ev->offer);
3353
3354 free(seat_sel->saved_types->types);
3355
3356 seat_sel->saved_types->ntypes = eina_array_count(available);
3357 seat_sel->saved_types->types = malloc(sizeof(char *) * seat_sel->saved_types->ntypes);
3358 if (!seat_sel->saved_types->types) return EINA_FALSE;
3359
3360 known = eina_array_new(5);
3361
3362 for (i = 0; i < eina_array_count(available); i++)
3363 {
3364 seat_sel->saved_types->types[i] =
3365 eina_stringshare_add(eina_array_data_get(available, i));
3366 if (seat_sel->saved_types->types[i] == seat_sel->pd->text_uri)
3367 {
3368 seat_sel->saved_types->textreq = 1;
3369 ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free);
3370 }
3371 }
3372
3373 seat_sel->accept = EINA_FALSE;
3374 for (i = 0; i < eina_array_count(available); i++)
3375 {
3376 if (_wl_drops_accept(seat_sel, eina_array_data_get(available, i)))
3377 {
3378 eina_array_push(known, strdup(eina_array_data_get(available, i)));
3379 }
3380 }
3381
3382 ecore_wl2_offer_mimes_set(ev->offer, known);
3383
3384 return ECORE_CALLBACK_PASS_ON;
3385}
3386
3387static Eina_Bool
3388_wl_dnd_leave(void *data, int type EINA_UNUSED, void *event)
3389{
3390 Ecore_Wl2_Event_Dnd_Leave *ev;
3391 Sel_Manager_Seat_Selection *seat_sel = data;
3392 Sel_Manager_Dropable *drop;
3393 sel_debug("In\n");
3394
3395 ev = event;
3396 if ((drop = _wl_dropable_find(seat_sel->pd, ev->win)))
3397 {
3398 _wl_dropable_handle(seat_sel, NULL, 0, 0);
3399 _wl_dropable_all_clean(seat_sel, ev->win);
3400 }
3401
3402 return ECORE_CALLBACK_PASS_ON;
3403}
3404
3405static Eina_Bool
3406_wl_dnd_position(void *data, int type EINA_UNUSED, void *event)
3407{
3408 Ecore_Wl2_Event_Dnd_Motion *ev;
3409 Sel_Manager_Seat_Selection *seat_sel = data;
3410 Efl_Selection_Manager_Data *pd = seat_sel->pd;
3411 Sel_Manager_Dropable *drop;
3412 Eina_Bool will_accept = EINA_FALSE;
3413
3414 ev = event;
3415
3416 sel_debug("mouse pos %i %i\n", ev->x, ev->y);
3417 seat_sel->drag_win_end.x = ev->x - seat_sel->drag_pos.x;
3418 seat_sel->drag_win_end.y = ev->y - seat_sel->drag_pos.y;
3419
3420 drop = _wl_dropable_find(pd, ev->win);
3421
3422 if (drop)
3423 {
3424 Eina_Position2D pos = EINA_POSITION2D(ev->x, ev->y);
3425 Evas *evas = NULL;
3426 Eina_List *dropable_list = NULL;
3427
3428 _dropable_coords_adjust(drop, &pos);
3429 evas = _wl_evas_get_from_win(pd, ev->win);
3430 if (evas)
3431 dropable_list = _dropable_list_geom_find(pd, evas, pos.x, pos.y);
3432
3433 /* check if there is dropable (obj) can accept this drop */
3434 if (dropable_list)
3435 {
3436 Efl_Selection_Format saved_format;
3437 Eina_List *l;
3438 Eina_Bool found = EINA_FALSE;
3439 Sel_Manager_Dropable *dropable = NULL;
3440
3441 saved_format =
3442 _dnd_types_to_format(pd, seat_sel->saved_types->types, seat_sel->saved_types->ntypes);
3443
3444 EINA_LIST_FOREACH(dropable_list, l, dropable)
3445 {
3446 Drop_Format *df;
3447 Eina_Inlist *itr;
3448
3449 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
3450 {
3451 Efl_Selection_Format common_fmt = saved_format & df->format;
3452
3453 if (common_fmt)
3454 {
3455 /* We found a target that can accept this type of data */
3456 int i, min_index = SELECTION_N_ATOMS;
3457
3458 /* We have to find the first atom that corresponds to one
3459 * of the supported data types. */
3460 for (i = 0; i < seat_sel->saved_types->ntypes; i++)
3461 {
3462 Sel_Manager_Atom *atom;
3463
3464 atom = eina_hash_find(pd->type_hash,
3465 seat_sel->saved_types->types[i]);
3466
3467 if (atom && (atom->format & common_fmt))
3468 {
3469 int atom_idx = (atom - pd->atom_list);
3470
3471 if (min_index > atom_idx)
3472 min_index = atom_idx;
3473 }
3474 }
3475 if (min_index != SELECTION_N_ATOMS)
3476 {
3477 sel_debug("Found atom %s\n", pd->atom_list[min_index].name);
3478 found = EINA_TRUE;
3479 dropable->last.type = pd->atom_list[min_index].name;
3480 dropable->last.format = common_fmt;
3481 break;
3482 }
3483 }
3484 }
3485 if (found) break;
3486 }
3487 if (found)
3488 {
3489 Sel_Manager_Selection *sel = seat_sel->sel;
3490 Evas_Coord ox = 0, oy = 0;
3491
3492 evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL);
3493
3494 sel_debug("Candidate %p (%s)\n",
3495 dropable->obj, efl_class_name_get(efl_class_get(dropable->obj)));
3496 _wl_dropable_handle(seat_sel, dropable, pos.x - ox, pos.y - oy);
3497 sel->request_obj = dropable->obj;
3498 will_accept = EINA_TRUE;
3499 }
3500 else
3501 {
3502 //if not: send false status
3503 sel_debug("dnd position (%d, %d) not in obj\n", pos.x, pos.y);
3504 _wl_dropable_handle(seat_sel, NULL, 0, 0);
3505 // CCCCCCC: call dnd exit on last obj
3506 }
3507 eina_list_free(dropable_list);
3508 }
3509 }
3510
3511 seat_sel->accept = will_accept;
3512 //efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, &seat_sel->accept);
3513
3514 return ECORE_CALLBACK_PASS_ON;
3515}
3516
3517static Eina_Bool
3518_wl_dnd_receive(void *data, int type EINA_UNUSED, void *event)
3519{
3520 Ecore_Wl2_Event_Offer_Data_Ready *ev;
3521 Sel_Manager_Seat_Selection *seat_sel = data;
3522 Sel_Manager_Selection *sel;
3523 Ecore_Wl2_Offer *offer;
3524 sel_debug("In\n");
3525
3526 ev = event;
3527 sel = seat_sel->sel;
3528 offer = sel->dnd_offer;
3529
3530 if (offer != ev->offer) return ECORE_CALLBACK_PASS_ON;
3531
3532 if (sel->request_obj)
3533 {
3534 Ecore_Wl2_Drag_Action action;
3535
3536 action = ecore_wl2_offer_action_get(ev->offer);
3537 if (action == ECORE_WL2_DRAG_ACTION_ASK)
3538 ecore_wl2_offer_actions_set(ev->offer, ECORE_WL2_DRAG_ACTION_COPY, ECORE_WL2_DRAG_ACTION_COPY);
3539 action = ecore_wl2_offer_action_get(ev->offer);
3540 sel->action = _wl_to_elm(action);
3541
3542 _wl_dropable_data_handle(sel, ev);
3543 evas_object_event_callback_del_full(sel->request_obj,
3544 EVAS_CALLBACK_DEL,
3545 _wl_sel_obj_del2, sel);
3546 sel->request_obj = NULL;
3547 }
3548
3549 ecore_wl2_offer_finish(ev->offer);
3550
3551 return ECORE_CALLBACK_CANCEL;
3552}
3553
3554static Eina_Bool
3555_wl_dnd_drop(void *data, int type EINA_UNUSED, void *event)
3556{
3557 Ecore_Wl2_Event_Dnd_Drop *ev;
3558 Sel_Manager_Seat_Selection *seat_sel = data;