summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hollerbach <mail@marcel-hollerbach.de>2020-01-19 13:58:26 +0100
committerMarcel Hollerbach <mail@marcel-hollerbach.de>2020-03-04 17:26:30 +0100
commit87901ea2ffda3ef0becde28c306b4208531cc1a1 (patch)
treec3750a4d02ded1876062ae4eeaaefad9356a8ab0
parent447fecd32e92d090d3b71f68d09d0ec6e99ef217 (diff)
rewrite efl cnp and dnd handling
the previous commits introduced a abstraction for drag in drop which can be now used for this here. With this commit all the direct protocol handling in efl.ui is removed, and only the ecore evas API is used. Additionally, this lead to a giant refactor of how APIs do work. All Efl.Ui. interfaces have been removed except Efl.Ui.Selection and Efl.Ui.Dnd, these two have been restructored. A small list of what is new: - In general no function pointers are used anymore. They feel very uncompftable in bindings and in C. For us its a lot easier to just listen to a event when a drop enters or leaves, there is no need to register custom functions for that. - Asynchronous data transphere is handled via futures, which proved to be more error safe. - Formats and actions are handled as mime types / strings. - 0 is the default seat if you do not know what else to take. - Content is in general passes as a content container from eina, this also allows applications to pass custom types The legacy dnd and cnp API is implemented based on that. All cnp related things are in elm_cnp.c the dnd parts are in elm_dnd.c Differential Revision: https://phab.enlightenment.org/D11190
-rw-r--r--src/lib/elementary/Efl_Ui.h3
-rw-r--r--src/lib/elementary/efl_ui_dnd.c870
-rw-r--r--src/lib/elementary/efl_ui_dnd.eo88
-rw-r--r--src/lib/elementary/efl_ui_dnd_container.eo46
-rw-r--r--src/lib/elementary/efl_ui_dnd_types.eot60
-rw-r--r--src/lib/elementary/efl_ui_selection.c297
-rw-r--r--src/lib/elementary/efl_ui_selection.eo90
-rw-r--r--src/lib/elementary/efl_ui_selection_manager.c5678
-rw-r--r--src/lib/elementary/efl_ui_selection_manager.eo139
-rw-r--r--src/lib/elementary/efl_ui_selection_types.eot60
-rw-r--r--src/lib/elementary/efl_ui_tags.c2
-rw-r--r--src/lib/elementary/efl_ui_textbox.c358
-rw-r--r--src/lib/elementary/efl_ui_textbox.eo12
-rw-r--r--src/lib/elementary/efl_ui_win.c252
-rw-r--r--src/lib/elementary/elm_cnp.c244
-rw-r--r--src/lib/elementary/elm_cnp.h2
-rw-r--r--src/lib/elementary/elm_dnd.c812
-rw-r--r--src/lib/elementary/elm_entry.c6
-rw-r--r--src/lib/elementary/elm_main.c1
-rw-r--r--src/lib/elementary/elm_priv.h10
-rw-r--r--src/lib/elementary/meson.build7
-rw-r--r--src/lib/eo/eina_types.eot2
-rw-r--r--src/lib/evas/canvas/evas_main.c18
-rw-r--r--src/tests/elementary/efl_ui_test_text.c14
24 files changed, 1754 insertions, 7317 deletions
diff --git a/src/lib/elementary/Efl_Ui.h b/src/lib/elementary/Efl_Ui.h
index 5bed200264..81f4522c71 100644
--- a/src/lib/elementary/Efl_Ui.h
+++ b/src/lib/elementary/Efl_Ui.h
@@ -119,8 +119,6 @@ extern EAPI Eina_Error EFL_UI_THEME_APPLY_ERROR_NONE;
119 119
120// EO types. Defined for legacy-only builds as legacy uses typedef of EO types. 120// EO types. Defined for legacy-only builds as legacy uses typedef of EO types.
121#include "efl_ui.eot.h" 121#include "efl_ui.eot.h"
122#include "efl_ui_selection_types.eot.h"
123#include "efl_ui_dnd_types.eot.h"
124 122
125//define focus manager earlier since focus object and manager is circular 123//define focus manager earlier since focus object and manager is circular
126typedef Eo Efl_Ui_Focus_Manager; 124typedef Eo Efl_Ui_Focus_Manager;
@@ -322,7 +320,6 @@ typedef Eo Efl_Ui_Spotlight_Indicator;
322# include <efl_ui_widget_focus_manager.eo.h> 320# include <efl_ui_widget_focus_manager.eo.h>
323# include <efl_ui_selection.eo.h> 321# include <efl_ui_selection.eo.h>
324# include <efl_ui_dnd.eo.h> 322# include <efl_ui_dnd.eo.h>
325# include <efl_ui_dnd_container.eo.h>
326 323
327# include <efl_ui_timepicker.eo.h> 324# include <efl_ui_timepicker.eo.h>
328# include <efl_ui_datepicker.eo.h> 325# include <efl_ui_datepicker.eo.h>
diff --git a/src/lib/elementary/efl_ui_dnd.c b/src/lib/elementary/efl_ui_dnd.c
index df79eb9762..e8bf19320b 100644
--- a/src/lib/elementary/efl_ui_dnd.c
+++ b/src/lib/elementary/efl_ui_dnd.c
@@ -12,838 +12,140 @@
12#include <Elementary_Cursor.h> 12#include <Elementary_Cursor.h>
13#include "elm_priv.h" 13#include "elm_priv.h"
14 14
15typedef struct _Efl_Ui_Dnd_Container_Data Efl_Ui_Dnd_Container_Data; 15typedef struct {
16struct _Efl_Ui_Dnd_Container_Data 16 Ecore_Evas *ee;
17{ 17 Eina_Bool registered;
18 unsigned int drag_delay_time; 18} Efl_Ui_Dnd_Data;
19};
20 19
21extern int _wl_default_seat_id_get(Evas_Object *obj); 20typedef struct {
22#ifdef HAVE_ELEMENTARY_WL2 21 Eo *win;
23Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj); 22 Efl_Ui_Dnd *obj;
24#endif 23} Efl_Ui_Drag_Start;
25 24
26Eo* 25static void
27_efl_ui_selection_manager_get(Eo *obj) 26_ecore_evas_drag_terminated(Ecore_Evas *ee EINA_UNUSED, unsigned int seat, void *data, Eina_Bool accepted)
28{ 27{
29 if (!efl_isa(obj, EFL_UI_WIDGET_CLASS)) return NULL; 28 Efl_Ui_Drag_Start *start = data;
30 Eo *app = efl_app_main_get(); 29 Efl_Ui_Drag_Finished_Event ev = {seat, accepted};
31 Eo *sel_man = efl_key_data_get(app, "__selection_manager"); 30 efl_event_callback_call(start->obj, EFL_UI_DND_EVENT_DRAG_FINISHED, &ev);
32 if (!sel_man) 31 efl_del(start->win);
33 { 32 free(start);
34 sel_man = efl_add(EFL_UI_SELECTION_MANAGER_CLASS, app);
35 efl_key_data_set(app, "__selection_manager", sel_man);
36 }
37 return sel_man;
38} 33}
39 34
40void 35EOLIAN static Efl_Content*
41_efl_ui_dnd_shutdown(void) 36_efl_ui_dnd_drag_start(Eo *obj, Efl_Ui_Dnd_Data *pd, Eina_Content *content, const char* action, unsigned int seat)
42{ 37{
43 Eo *app = efl_app_main_get(); 38 Eo *drag_win;
44 Eo *sel_man = efl_key_data_get(app, "__selection_manager"); 39 Efl_Ui_Drag_Start *start;
40 Efl_Ui_Drag_Started_Event ev = {seat};
41 Ecore_Evas *drag_ee;
42 EINA_SAFETY_ON_NULL_RETURN_VAL(pd->ee, NULL);
45 43
46 efl_del(sel_man); 44 start = calloc(1, sizeof(Efl_Ui_Drag_Start));
47} 45 start->obj = obj;
46 start->win = drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND);
47 elm_win_alpha_set(drag_win, EINA_TRUE);
48 elm_win_override_set(drag_win, EINA_TRUE);
49 elm_win_borderless_set(drag_win, EINA_TRUE);
50 drag_ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_win));
48 51
49EOLIAN static void 52 ecore_evas_drag_start(pd->ee, seat, content, drag_ee, action, _ecore_evas_drag_terminated, start);
50_efl_ui_dnd_drag_start(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, Eina_Slice data,
51 Efl_Ui_Selection_Action action, void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb,
52 unsigned int seat)
53{
54 Eo *sel_man = _efl_ui_selection_manager_get(obj);
55 efl_ui_selection_manager_drag_start(sel_man, obj, format, data, action,
56 icon_func_data, icon_func, icon_func_free_cb,
57 seat);
58}
59 53
60EOLIAN static void 54 evas_object_show(drag_win);
61_efl_ui_dnd_drag_cancel(Eo *obj, void *pd EINA_UNUSED, unsigned int seat)
62{
63 Eo *sel_man = _efl_ui_selection_manager_get(obj);
64 efl_ui_selection_manager_drag_cancel(sel_man, obj, seat);
65}
66
67EOLIAN static void
68_efl_ui_dnd_drag_action_set(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Action action, unsigned int seat)
69{
70 Eo *sel_man = _efl_ui_selection_manager_get(obj);
71 efl_ui_selection_manager_drag_action_set(sel_man, obj, action, seat);
72}
73 55
56 efl_event_callback_call(obj, EFL_UI_DND_EVENT_DRAG_STARTED, &ev);
74 57
75EOLIAN static void 58 return drag_win;
76_efl_ui_dnd_drop_target_add(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, unsigned int seat)
77{
78 Eo *sel_man = _efl_ui_selection_manager_get(obj);
79 efl_ui_selection_manager_drop_target_add(sel_man, obj, format, seat);
80} 59}
81 60
82EOLIAN static void 61EOLIAN static void
83_efl_ui_dnd_drop_target_del(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, unsigned int seat) 62_efl_ui_dnd_drag_cancel(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Data *pd, unsigned int seat)
84{ 63{
85 Eo *sel_man = _efl_ui_selection_manager_get(obj); 64 ecore_evas_drag_cancel(pd->ee, seat);
86 efl_ui_selection_manager_drop_target_del(sel_man, obj, format, seat);
87} 65}
88 66
89EOLIAN static double 67EOLIAN static Eina_Future*
90_efl_ui_dnd_container_drag_delay_time_get(const Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Container_Data *pd) 68_efl_ui_dnd_drop_data_get(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Data *pd, unsigned int seat, Eina_Iterator *acceptable_types)
91{ 69{
92 return pd->drag_delay_time; 70 return ecore_evas_selection_get(pd->ee, seat, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, acceptable_types);
93} 71}
94 72
95EOLIAN static void 73EOLIAN static Efl_Object *
96_efl_ui_dnd_container_drag_delay_time_set(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Container_Data *pd, double drag_delay_time) 74_efl_ui_dnd_efl_object_constructor(Eo *obj, Efl_Ui_Dnd_Data *pd)
97{ 75{
98 pd->drag_delay_time = drag_delay_time; 76 if (!efl_constructor(efl_super(obj, EFL_UI_DND_MIXIN)))
99} 77 return NULL;
100 78
101EOLIAN static void 79 pd->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
102_efl_ui_dnd_container_drag_item_add(Eo *obj, Efl_Ui_Dnd_Container_Data *pd,
103 void *data_func_data, Efl_Dnd_Drag_Data_Get data_func, Eina_Free_Cb data_func_free_cb,
104 void *item_func_data, Efl_Dnd_Item_Get item_func, Eina_Free_Cb item_func_free_cb,
105 void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb,
106 void *icon_list_func_data, Efl_Dnd_Drag_Icon_List_Create icon_list_func, Eina_Free_Cb icon_list_func_free_cb,
107 unsigned int seat)
108{
109 double drag_delay_time = pd->drag_delay_time;
110 double anim_time = elm_config_drag_anim_duration_get();
111 Eo *sel_man = _efl_ui_selection_manager_get(obj);
112 efl_ui_selection_manager_container_drag_item_add(sel_man, obj, drag_delay_time, anim_time,
113 data_func_data, data_func, data_func_free_cb,
114 item_func_data, item_func, item_func_free_cb,
115 icon_func_data, icon_func, icon_func_free_cb,
116 icon_list_func_data, icon_list_func, icon_list_func_free_cb,
117 seat);
118}
119 80
120static void 81 return obj;
121_efl_ui_dnd_container_drag_item_del(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, unsigned int seat)
122{
123 Eo *sel_man = _efl_ui_selection_manager_get(obj);
124 efl_ui_selection_manager_container_drag_item_del(sel_man, obj, seat);
125}
126EOLIAN static void
127_efl_ui_dnd_container_drop_item_add(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED,
128 Efl_Ui_Selection_Format format,
129 void *item_func_data, Efl_Dnd_Item_Get item_func, Eina_Free_Cb item_func_free_cb,
130 unsigned int seat)
131{
132 Eo *sel_man = _efl_ui_selection_manager_get(obj);
133 efl_ui_selection_manager_container_drop_item_add(sel_man, obj, format, item_func_data, item_func, item_func_free_cb, seat);
134} 82}
135 83
136EOLIAN static void 84EOLIAN static void
137_efl_ui_dnd_container_drop_item_del(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, unsigned int seat) 85_efl_ui_dnd_efl_object_invalidate(Eo *obj, Efl_Ui_Dnd_Data *pd)
138{
139 Eo *sel_man = _efl_ui_selection_manager_get(obj);
140 efl_ui_selection_manager_container_drop_item_del(sel_man, obj, seat);
141}
142
143
144///////////
145typedef struct _Dnd_Icon_Create Dnd_Icon_Create;
146typedef struct _Dnd_Drag_Pos Dnd_Drag_Pos;
147typedef struct _Dnd_Drag_Accept Dnd_Drag_Accept;
148typedef struct _Dnd_Drag_Done Dnd_Drag_Done;
149typedef struct _Dnd_Drag_State Dnd_Drag_State;
150typedef struct _Dnd_Drop Dnd_Drop;
151typedef struct _Dnd_Cont_Drag_Pos Dnd_Cont_Drag_Pos;
152typedef struct _Dnd_Cont_Drop Dnd_Cont_Drop;
153typedef struct _Item_Container_Drag_Info Item_Container_Drag_Info;
154
155struct _Dnd_Icon_Create
156{
157 void *icon_data;
158 Elm_Drag_Icon_Create_Cb icon_cb;
159};
160
161struct _Dnd_Drag_Pos
162{
163 void *pos_data;
164 Elm_Drag_Pos pos_cb;
165};
166
167struct _Dnd_Drag_Accept
168{
169 void *accept_data;
170 Elm_Drag_Accept accept_cb;
171};
172
173struct _Dnd_Drag_Done
174{
175 void *done_data;
176 Elm_Drag_State done_cb;
177
178 //for deleting
179 Dnd_Drag_Pos *pos;
180 Dnd_Drag_Accept *accept;
181};
182
183struct _Dnd_Drag_State
184{
185 void *state_data;
186 Elm_Drag_State state_cb;
187};
188
189struct _Dnd_Drop
190{
191 Efl_Object *obj;
192 Elm_Sel_Format format;
193 void *drop_data;
194 Elm_Drop_Cb drop_cb;
195
196 //for deleting
197 Dnd_Drag_State *enter;
198 Dnd_Drag_State *leave;
199 Dnd_Drag_Pos *pos;
200};
201
202struct _Dnd_Cont_Drag_Pos
203{
204 void *pos_data;
205 Elm_Drag_Item_Container_Pos pos_cb;
206 Elm_Xy_Item_Get_Cb item_get_cb;
207};
208
209struct _Dnd_Cont_Drop
210{
211 Efl_Object *obj;
212 Elm_Sel_Format format;
213 void *drop_data;
214 Elm_Drop_Item_Container_Cb drop_cb;
215 Elm_Xy_Item_Get_Cb item_get_cb;
216
217 //for deleting
218 Dnd_Drag_State *enter;
219 Dnd_Drag_State *leave;
220 Dnd_Cont_Drag_Pos *pos;
221};
222
223struct _Item_Container_Drag_Info
224{
225 Elm_Drag_User_Info user_info;
226 Elm_Object_Item *it;
227 Elm_Item_Container_Data_Get_Cb data_get_cb;
228 Elm_Xy_Item_Get_Cb item_get_cb;
229};
230
231static Efl_Object *
232_dnd_icon_create_cb(void *data, Efl_Object *win, Efl_Object *drag_obj EINA_UNUSED, Eina_Position2D *pos_ret)
233{
234 Dnd_Icon_Create *ic = data;
235 Efl_Object *ret = ic->icon_cb(ic->icon_data, win, &pos_ret->x, &pos_ret->y);
236
237 free(ic);
238 return ret;
239}
240
241static void
242_dnd_drag_pos_cb(void *data, const Efl_Event *event)
243{
244 Dnd_Drag_Pos *pos = data;
245 Efl_Dnd_Drag_Pos *ddata = event->info;
246
247 if (pos->pos_cb)
248 pos->pos_cb(pos->pos_data, event->object, ddata->pos.x, ddata->pos.y,
249 (Elm_Xdnd_Action)ddata->action);
250}
251
252static void
253_dnd_drag_accept_cb(void *data, const Efl_Event *event)
254{
255 Dnd_Drag_Accept *accept = data;
256
257 if (accept->accept_cb)
258 accept->accept_cb(accept->accept_data, event->object, *(Eina_Bool *)event->info);
259}
260
261static void
262_dnd_drag_done_cb(void *data, const Efl_Event *event)
263{
264 Dnd_Drag_Done *done = data;
265
266 if (done->done_cb)
267 done->done_cb(done->done_data, event->object);
268
269 efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_POS,
270 _dnd_drag_pos_cb, done->pos);
271 efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_ACCEPT,
272 _dnd_drag_accept_cb, done->accept);
273 efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_DONE,
274 _dnd_drag_done_cb, done);
275 free(done->pos);
276 free(done->accept);
277 free(done);
278}
279
280static void
281_dnd_drag_enter_leave_cb(void *data, const Efl_Event *event)
282{
283 Dnd_Drag_State *state = data;
284
285 if (state->state_cb)
286 state->state_cb(state->state_data, event->object);
287}
288
289static void
290_dnd_drop_cb(void *data, const Efl_Event *event)
291{
292 Dnd_Drop *drop = data;
293 Efl_Ui_Selection_Data *org_ddata = event->info;
294 Elm_Selection_Data ddata;
295
296 ddata.x = org_ddata->pos.x;
297 ddata.y = org_ddata->pos.y;
298 ddata.format = (Elm_Sel_Format)org_ddata->format;
299 ddata.action = (Elm_Xdnd_Action)org_ddata->action;
300 ddata.data = calloc(1, org_ddata->content.len);
301 if (!ddata.data) return;
302 ddata.data = memcpy(ddata.data, org_ddata->content.mem, org_ddata->content.len);
303 ddata.len = org_ddata->content.len;
304 if (drop->drop_cb)
305 drop->drop_cb(drop->drop_data, event->object, &ddata);
306 free(ddata.data);
307}
308
309EAPI Eina_Bool
310elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data,
311 Elm_Xdnd_Action action,
312 Elm_Drag_Icon_Create_Cb icon_create_cb, void *icon_create_data,
313 Elm_Drag_Pos drag_pos_cb, void *drag_pos_data,
314 Elm_Drag_Accept drag_accept_cb, void *drag_accept_data,
315 Elm_Drag_State drag_done_cb, void *drag_done_data)
316{
317 if (!data) return EINA_FALSE;
318 Eo *sel_man = _efl_ui_selection_manager_get(obj);
319 int seatid = 1;
320 Eina_Slice sl;
321 Dnd_Drag_Pos *pos = calloc(1, sizeof(Dnd_Drag_Pos));
322 Dnd_Drag_Accept *accept = calloc(1, sizeof(Dnd_Drag_Accept));
323 Dnd_Drag_Done *done = calloc(1, sizeof(Dnd_Drag_Done));
324 Dnd_Icon_Create *ic = calloc(1, sizeof(Dnd_Icon_Create));
325 if (!pos || !accept || !done || !ic) goto on_error;
326
327 pos->pos_data = drag_pos_data;
328 pos->pos_cb = drag_pos_cb;
329
330 accept->accept_data = drag_accept_data;
331 accept->accept_cb = drag_accept_cb;
332
333 done->done_data = drag_done_data;
334 done->done_cb = drag_done_cb;
335 done->pos = pos;
336 done->accept = accept;
337
338 efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS, _dnd_drag_pos_cb, pos);
339 efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, _dnd_drag_accept_cb, accept);
340 efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DONE, _dnd_drag_done_cb, done);
341 sl.mem = data;
342 sl.len = strlen(data);
343#ifdef HAVE_ELEMENTARY_WL2
344 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
345#endif
346
347 ic->icon_data = icon_create_data;
348 ic->icon_cb = icon_create_cb;
349 efl_ui_selection_manager_drag_start(sel_man, obj, (Efl_Ui_Selection_Format)format, sl,
350 (Efl_Ui_Selection_Action)action,
351 ic, _dnd_icon_create_cb, NULL, seatid);
352
353 return EINA_TRUE;
354
355on_error:
356 if (pos) free(pos);
357 if (accept) free(accept);
358 if (done) free(done);
359 if (ic) free(ic);
360
361 return EINA_FALSE;
362}
363
364EAPI Eina_Bool
365elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action)
366{
367 Eo *sel_man = _efl_ui_selection_manager_get(obj);
368 int seatid = 1;
369
370#ifdef HAVE_ELEMENTARY_WL2
371 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
372#endif
373 efl_ui_selection_manager_drag_action_set(sel_man, obj, (Efl_Ui_Selection_Action)action, seatid);
374
375 return EINA_TRUE;
376}
377
378EAPI Eina_Bool
379elm_drag_cancel(Evas_Object *obj)
380{
381 Eo *sel_man = _efl_ui_selection_manager_get(obj);
382 int seatid = 1;
383
384#ifdef HAVE_ELEMENTARY_WL2
385 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
386#endif
387
388 efl_ui_selection_manager_drag_cancel(sel_man, obj, seatid);
389
390 return EINA_TRUE;
391}
392
393static void
394_drop_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
395{ 86{
396 Eina_List *drop_list; 87 if (pd->registered)
397 Dnd_Drop *drop;
398
399 drop_list = efl_key_data_get(obj, "__drop_list");
400 EINA_LIST_FREE(drop_list, drop)
401 { 88 {
402 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER, 89 _drop_event_unregister(obj);
403 _dnd_drag_enter_leave_cb, drop->enter);
404 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE,
405 _dnd_drag_enter_leave_cb, drop->leave);
406 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS,
407 _dnd_drag_pos_cb, drop->pos);
408 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP,
409 _dnd_drop_cb, drop);
410 free(drop->enter);
411 free(drop->leave);
412 free(drop->pos);
413 free(drop);
414 } 90 }
415 efl_key_data_set(obj, "__drop_list", NULL); 91 efl_invalidate(efl_super(obj, EFL_UI_DND_MIXIN));
416}
417
418EAPI Eina_Bool
419elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
420 Elm_Drag_State enter_cb, void *enter_data,
421 Elm_Drag_State leave_cb, void *leave_data,
422 Elm_Drag_Pos pos_cb, void *pos_data,
423 Elm_Drop_Cb drop_cb, void *drop_data)
424{
425 Eo *sel_man = _efl_ui_selection_manager_get(obj);
426 int seatid = 1;
427 Dnd_Drag_State *enter, *leave;
428 Dnd_Drag_Pos *pos;
429 Dnd_Drop *drop;
430 Eina_List *drop_list;
431
432 enter = calloc(1, sizeof(Dnd_Drag_State));
433 leave = calloc(1, sizeof(Dnd_Drag_State));
434 pos = calloc(1, sizeof(Dnd_Drag_Pos));
435 drop = calloc(1, sizeof(Dnd_Drop));
436 if (!enter || !leave || !pos || !drop) goto on_error;
437#ifdef HAVE_ELEMENTARY_WL2
438 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
439#endif
440 enter->state_cb = enter_cb;
441 enter->state_data = enter_data;
442 leave->state_cb = leave_cb;
443 leave->state_data = leave_data;
444 pos->pos_cb = pos_cb;
445 pos->pos_data = pos_data;
446 drop->obj = obj;
447 drop->format = format;
448 drop->drop_cb = drop_cb;
449 drop->drop_data = drop_data;
450 drop->enter = enter;
451 drop->leave = leave;
452 drop->pos = pos;
453
454 drop_list = efl_key_data_get(obj, "__drop_list");
455 drop_list = eina_list_append(drop_list, drop);
456 efl_key_data_set(obj, "__drop_list", drop_list);
457 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
458 _drop_obj_del_cb, NULL);
459 efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ENTER,
460 _dnd_drag_enter_leave_cb, enter);
461 efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_LEAVE,
462 _dnd_drag_enter_leave_cb, leave);
463 efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS,
464 _dnd_drag_pos_cb, pos);
465 efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DROP,
466 _dnd_drop_cb, drop);
467 efl_ui_selection_manager_drop_target_add(sel_man, obj, (Efl_Ui_Selection_Format)format, seatid);
468
469 return EINA_TRUE;
470 92
471on_error:
472 if (enter) free(enter);
473 if (leave) free(leave);
474 if (pos) free(pos);
475 if (drop) free(drop);
476
477 return EINA_FALSE;
478} 93}
479 94
480EAPI Eina_Bool 95#define IS_DROP_EVENT(D) ( \
481elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format, 96(D == EFL_UI_DND_EVENT_DROP_POSITION_CHANGED) || \
482 Elm_Drag_State enter_cb, void *enter_data, 97(D == EFL_UI_DND_EVENT_DROP_DROPPED) || \
483 Elm_Drag_State leave_cb, void *leave_data, 98(D == EFL_UI_DND_EVENT_DROP_LEFT) || \
484 Elm_Drag_Pos pos_cb, void *pos_data, 99(D == EFL_UI_DND_EVENT_DROP_ENTERED) \
485 Elm_Drop_Cb drop_cb, void *drop_data) 100)
486{
487 Eo *sel_man = _efl_ui_selection_manager_get(obj);
488 int seatid = 1;
489 //Eina_List *l, *l2;
490 Eina_List *drop_list;
491 Dnd_Drop *drop;
492
493#ifdef HAVE_ELEMENTARY_WL2
494 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
495#endif
496
497 drop_list = efl_key_data_get(obj, "__drop_list");
498 drop = eina_list_data_get(drop_list);
499 if (drop &&
500 (drop->format == format) &&
501 (drop->enter->state_cb == enter_cb) &&
502 (drop->enter->state_data == enter_data) &&
503 (drop->leave->state_cb == leave_cb) &&
504 (drop->leave->state_data == leave_data) &&
505 (drop->pos->pos_cb == pos_cb) &&
506 (drop->pos->pos_data == pos_data) &&
507 (drop->drop_cb == drop_cb) &&
508 (drop->drop_data == drop_data))
509 {
510 drop_list = eina_list_remove(drop_list, drop);
511 efl_key_data_set(obj, "__drop_list", drop_list);
512 evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _drop_obj_del_cb);
513 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER,
514 _dnd_drag_enter_leave_cb, drop->enter);
515 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE,
516 _dnd_drag_enter_leave_cb, drop->leave);
517 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS,
518 _dnd_drag_pos_cb, drop->pos);
519 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP,
520 _dnd_drop_cb, drop);
521 free(drop->enter);
522 free(drop->leave);
523 free(drop->pos);
524 free(drop);
525 }
526 efl_ui_selection_manager_drop_target_del(sel_man, obj, (Efl_Ui_Selection_Format)format, seatid);
527 101
528 return EINA_TRUE; 102EOLIAN static Efl_Object*
529} 103_efl_ui_dnd_efl_object_finalize(Eo *obj, Efl_Ui_Dnd_Data *pd)
530
531static Efl_Object *
532_dnd_item_func(void *data, Efl_Canvas_Object *item, Eina_Position2D pos, Eina_Position2D *pos_ret)
533{ 104{
534 Elm_Xy_Item_Get_Cb item_get_cb = data; 105 if (pd->registered)
535 Evas_Coord x, y; 106 _drop_event_register(obj);
536 Efl_Object *obj = NULL;
537
538 x = y = 0;
539 if (item_get_cb)
540 obj = item_get_cb(item, pos.x, pos.y, &x, &y);
541 if (pos_ret)
542 {
543 pos_ret->x = x;
544 pos_ret->y = y;
545 }
546 107
547 return obj; 108 return efl_finalize(efl_super(obj, EFL_UI_DND_MIXIN));
548} 109}
549 110
550static void
551_dnd_cont_drag_pos_cb(void *data, const Efl_Event *event)
552{
553 Dnd_Cont_Drag_Pos *pos = data;
554 Efl_Dnd_Drag_Pos *ddata = event->info;
555 Evas_Coord xret = 0, yret = 0;
556 111
557 if (pos->item_get_cb) 112EOLIAN static Eina_Bool
558 { 113_efl_ui_dnd_efl_object_event_callback_priority_add(Eo *obj, Efl_Ui_Dnd_Data *pd,
559 Evas_Coord x, y; 114 const Efl_Event_Description *desc,
560 evas_object_geometry_get(event->object, &x, &y, NULL, NULL); 115 Efl_Callback_Priority priority,
561 pos->item_get_cb(event->object, ddata->pos.x + x, ddata->pos.y + y, 116 Efl_Event_Cb func,
562 &xret, &yret); 117 const void *user_data)
563 }
564 if (pos->pos_cb)
565 pos->pos_cb(pos->pos_data, event->object, ddata->item, ddata->pos.x, ddata->pos.y,
566 xret, yret, (Elm_Xdnd_Action)ddata->action);
567}
568
569static void
570_dnd_cont_drop_cb(void *data, const Efl_Event *event)
571{ 118{
572 Dnd_Cont_Drop *drop = data; 119 if (IS_DROP_EVENT(desc) && !pd->registered)
573 Efl_Ui_Selection_Data *org_ddata = event->info; 120 {
574 Elm_Selection_Data ddata; 121 pd->registered = EINA_TRUE;
575 Evas_Coord xret = 0, yret = 0; 122 if (efl_finalized_get(obj))
123 _drop_event_register(obj);
124 }
576 125
577 ddata.x = org_ddata->pos.x; 126 return efl_event_callback_priority_add(efl_super(obj, EFL_UI_DND_MIXIN), desc, priority, func, user_data);
578 ddata.y = org_ddata->pos.y;
579 ddata.format = (Elm_Sel_Format)org_ddata->format;
580 ddata.action = (Elm_Xdnd_Action)org_ddata->action;
581 ddata.data = calloc(1, org_ddata->content.len);
582 if (!ddata.data) return;
583 ddata.data = memcpy(ddata.data, org_ddata->content.mem, org_ddata->content.len);
584 ddata.len = org_ddata->content.len;
585
586 if (drop->item_get_cb)
587 {
588 Evas_Coord x, y;
589 evas_object_geometry_get(event->object, &x, &y, NULL, NULL);
590 drop->item_get_cb(event->object, ddata.x + x, ddata.y + y,
591 &xret, &yret);
592 }
593
594 if (drop->drop_cb)
595 drop->drop_cb(drop->drop_data, event->object, org_ddata->item,
596 &ddata, xret, yret);
597 free(ddata.data);
598} 127}
599 128
600static void 129EOLIAN static Eina_Bool
601_cont_drop_free_data(Evas_Object *obj) 130_efl_ui_dnd_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Ui_Dnd_Data *pd,
131 const Efl_Callback_Array_Item *array,
132 Efl_Callback_Priority priority,
133 const void *user_data)
602{ 134{
603 Eina_List *cont_drop_list; 135 for (int i = 0; array[i].desc; ++i)
604 Dnd_Cont_Drop *drop;
605
606 cont_drop_list = efl_key_data_get(obj, "__cont_drop_item");
607 drop = eina_list_data_get(cont_drop_list);
608 if (drop)
609 { 136 {
610 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER, 137 if (IS_DROP_EVENT(array[i].desc) && !pd->registered)
611 _dnd_drag_enter_leave_cb, drop->enter);
612 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE,
613 _dnd_drag_enter_leave_cb, drop->leave);
614 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS,
615 _dnd_cont_drag_pos_cb, drop->pos);
616 efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP,
617 _dnd_cont_drop_cb, drop);
618 free(drop->enter);
619 free(drop->leave);
620 free(drop->pos);
621 cont_drop_list = eina_list_remove(cont_drop_list, drop);
622 efl_key_data_set(obj, "__cont_drop_item", cont_drop_list);
623 free(drop);
624 }
625}
626
627static void
628_cont_drop_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED)
629{
630 _cont_drop_free_data(obj);
631}
632
633EAPI Eina_Bool
634elm_drop_item_container_add(Evas_Object *obj,
635 Elm_Sel_Format format,
636 Elm_Xy_Item_Get_Cb item_get_cb,
637 Elm_Drag_State enter_cb, void *enter_data,
638 Elm_Drag_State leave_cb, void *leave_data,
639 Elm_Drag_Item_Container_Pos pos_cb, void *pos_data,
640 Elm_Drop_Item_Container_Cb drop_cb, void *drop_data)
641{
642 Eo *sel_man = _efl_ui_selection_manager_get(obj);
643 int seatid = 1;
644 Dnd_Drag_State *enter = NULL, *leave = NULL;
645 Dnd_Cont_Drag_Pos *pos = NULL;
646 Dnd_Cont_Drop *drop = NULL;
647 Eina_List *cont_drop_list;
648
649 enter = calloc(1, sizeof(Dnd_Drag_State));
650 leave = calloc(1, sizeof(Dnd_Drag_State));
651 pos = calloc(1, sizeof(Dnd_Cont_Drag_Pos));
652 drop = calloc(1, sizeof(Dnd_Cont_Drop));
653 if (!enter || !leave || !pos || !drop) goto on_error;
654#ifdef HAVE_ELEMENTARY_WL2
655 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
656#endif
657
658 enter->state_cb = enter_cb;
659 enter->state_data = enter_data;
660 leave->state_cb = leave_cb;
661 leave->state_data = leave_data;
662 pos->pos_cb = pos_cb;
663 pos->pos_data = pos_data;
664 pos->item_get_cb = item_get_cb;
665 drop->obj = obj;
666 drop->format = format;
667 drop->drop_cb = drop_cb;
668 drop->drop_data = drop_data;
669 drop->enter = enter;
670 drop->leave = leave;
671 drop->pos = pos;
672
673 cont_drop_list = efl_key_data_get(obj, "__cont_drop_item");
674 cont_drop_list = eina_list_append(cont_drop_list, drop);
675 efl_key_data_set(obj, "__cont_drop_item", cont_drop_list);
676 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
677 _cont_drop_obj_del_cb, NULL);
678 efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ENTER,
679 _dnd_drag_enter_leave_cb, enter);
680 efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_LEAVE,
681 _dnd_drag_enter_leave_cb, leave);
682 efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS,
683 _dnd_cont_drag_pos_cb, pos);
684 efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DROP,
685 _dnd_cont_drop_cb, drop);
686 efl_ui_selection_manager_container_drop_item_add(sel_man, obj, (Efl_Ui_Selection_Format)format,
687 item_get_cb, _dnd_item_func, NULL,
688 seatid);
689
690 return EINA_TRUE;
691
692on_error:
693 if (enter) free(enter);
694 if (leave) free(leave);
695 if (pos) free(pos);
696 if (drop) free(drop);
697
698 return EINA_FALSE;
699}
700
701EAPI Eina_Bool
702elm_drop_item_container_del(Evas_Object *obj)
703{
704 Eo *sel_man = _efl_ui_selection_manager_get(obj);
705 int seatid = 1;
706
707#ifdef HAVE_ELEMENTARY_WL2
708 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
709#endif
710
711 _cont_drop_free_data(obj);
712 evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _cont_drop_obj_del_cb);
713 efl_ui_selection_manager_container_drop_item_del(sel_man, obj, seatid);
714
715 return EINA_TRUE;
716}
717
718static void
719_cont_drag_data_func(void *data, Efl_Object *obj, Efl_Ui_Selection_Format *format,
720 Eina_Rw_Slice *drag_data, Efl_Ui_Selection_Action *action)
721{
722 Item_Container_Drag_Info *di;
723
724 di = data;
725 if (!di) return;
726 di->data_get_cb(obj, di->it, &di->user_info);
727 if (format) *format = (Efl_Ui_Selection_Format)di->user_info.format;
728 if (drag_data)
729 {
730 if (di->user_info.data)
731 { 138 {
732 drag_data->mem = (void *)di->user_info.data; 139 pd->registered = EINA_TRUE;
733 drag_data->len = strlen(di->user_info.data); 140 if (efl_finalized_get(obj))
141 _drop_event_register(obj);
734 } 142 }
735 } 143 }
736 if (action) *action = (Efl_Ui_Selection_Action)di->user_info.action; 144 return efl_event_callback_array_priority_add(efl_super(obj, EFL_UI_DND_MIXIN), array, priority, user_data);
737}
738
739static Eina_List *
740_cont_drag_icon_list_create(void *data, Efl_Object *obj EINA_UNUSED)
741{
742 Item_Container_Drag_Info *di;
743
744 di = data;
745 return di->user_info.icons;
746}
747
748static Efl_Object *
749_cont_drag_icon_create(void *data, Efl_Object *win, Efl_Object *drag_obj EINA_UNUSED, Eina_Position2D *pos_ret)
750{
751 Item_Container_Drag_Info *di;
752 Elm_Object_Item *it = NULL;
753
754 di = data;
755 if (!di) return NULL;
756 if (!di->user_info.createicon) return NULL;
757 it = di->user_info.createicon(di->user_info.createdata, win, &pos_ret->x, &pos_ret->y);
758 di->it = it;
759 return it;
760}
761
762static Efl_Object *
763_cont_drag_item_func(void *data, Efl_Canvas_Object *item, Eina_Position2D pos, Eina_Position2D *pos_ret)
764{
765 Item_Container_Drag_Info *di = data;
766 Evas_Coord x, y;
767 Efl_Object *obj = NULL;
768
769 x = y = 0;
770 if (di->item_get_cb)
771 obj = di->item_get_cb(item, pos.x, pos.y, &x, &y);
772 if (pos_ret)
773 {
774 pos_ret->x = x;
775 pos_ret->y = y;
776 }
777 di->it = obj;
778
779 return obj;
780}
781
782static void
783_cont_drag_free_data(Evas_Object *obj)
784{
785 Eina_List *di_list;
786 Item_Container_Drag_Info *di;
787
788 di_list = efl_key_data_get(obj, "__cont_drag_item");
789 di = eina_list_data_get(di_list);
790 di_list = eina_list_remove(di_list, di);
791 efl_key_data_set(obj, "__cont_drag_item", di_list);
792 free(di);
793}
794
795static void
796_cont_drag_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED)
797{
798 _cont_drag_free_data(obj);
799}
800
801EAPI Eina_Bool
802elm_drag_item_container_add(Evas_Object *obj, double anim_tm, double tm_to_drag,
803 Elm_Xy_Item_Get_Cb item_get_cb, Elm_Item_Container_Data_Get_Cb data_get_cb)
804{
805 Eo *sel_man = _efl_ui_selection_manager_get(obj);
806 int seatid = 1;
807 Eina_List *di_list;
808 Item_Container_Drag_Info *di;
809
810#ifdef HAVE_ELEMENTARY_WL2
811 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
812#endif
813
814 di = calloc(1, sizeof(Item_Container_Drag_Info));
815 if (!di) return EINA_FALSE;
816 di->data_get_cb = data_get_cb;
817 di->item_get_cb = item_get_cb;
818 di_list = efl_key_data_get(obj, "__cont_drag_item");
819 di_list = eina_list_append(di_list, di);
820 efl_key_data_set(obj, "__cont_drag_item", di_list);
821 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _cont_drag_obj_del_cb, NULL);
822 efl_ui_selection_manager_container_drag_item_add(sel_man, obj, tm_to_drag, anim_tm,
823 di, _cont_drag_data_func, NULL,
824 di, _cont_drag_item_func, NULL,
825 di, _cont_drag_icon_create, NULL,
826 di, _cont_drag_icon_list_create, NULL,
827 seatid);
828 return EINA_TRUE;
829} 145}
830 146
831EAPI Eina_Bool 147#define EFL_UI_DND_EXTRA_OPS \
832elm_drag_item_container_del(Evas_Object *obj) 148 EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_ui_dnd_efl_object_event_callback_priority_add), \
833{ 149 EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_ui_dnd_efl_object_event_callback_array_priority_add), \
834 Eo *sel_man = _efl_ui_selection_manager_get(obj);
835 int seatid = 1;
836
837#ifdef HAVE_ELEMENTARY_WL2
838 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
839#endif
840
841 _cont_drag_free_data(obj);
842 evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _cont_drag_obj_del_cb);
843 efl_ui_selection_manager_container_drag_item_del(sel_man, obj, seatid);
844
845 return EINA_TRUE;
846}
847 150
848#include "efl_ui_dnd.eo.c" 151#include "efl_ui_dnd.eo.c"
849#include "efl_ui_dnd_container.eo.c"
diff --git a/src/lib/elementary/efl_ui_dnd.eo b/src/lib/elementary/efl_ui_dnd.eo
index 08f668856b..8ef19110d5 100644
--- a/src/lib/elementary/efl_ui_dnd.eo
+++ b/src/lib/elementary/efl_ui_dnd.eo
@@ -1,29 +1,40 @@
1import efl_ui_dnd_types; 1import eina_types;
2 2
3mixin @beta Efl.Ui.Dnd { 3struct @beta Efl.Ui.Drop_Event {
4 data: null; 4 [[Event struct that contains information about what is avaiable at which position, in which seat]]
5 position : Eina.Position2D; [[The position of the Drop event]]
6 seat : uint; [[In which seat it is happening]]
7 available_types : accessor<string>; [[which types are avaiable, you should use one of these for a call to @Efl.Ui.Dnd.drop_data_get ]]
8}
9
10struct @beta Efl.Ui.Drop_Dropped_Event {
11 dnd : Efl.Ui.Drop_Event; [[The overall information]]
12 action : string; [[The action the client should take]]
13}
14
15struct @beta Efl.Ui.Drag_Started_Event {
16 seat : uint;
17}
18
19struct @beta Efl.Ui.Drag_Finished_Event {
20 seat : uint;
21 accepted : bool;
22}
23
24mixin @beta Efl.Ui.Dnd requires Efl.Object {
5 methods { 25 methods {
6 drag_start { 26 drag_start {
7 [[Start a drag and drop process at the drag side. 27 [[Start a drag from this client.
8 During dragging, there are three events emitted as belows: 28
9 - EFL_UI_DND_EVENT_DRAG_POS 29 @[Efl.Ui.Dnd.drag,started] will be emitted each time a successfull drag will be started.
10 - EFL_UI_DND_EVENT_DRAG_ACCEPT 30 @[Efl.Ui.Dnd.drag,finished] will be emitted every time a drag is finished.
11 - EFL_UI_DND_EVENT_DRAG_DONE
12 ]] 31 ]]
13 params { 32 params {
14 @in format: Efl.Ui.Selection_Format; [[The data format]] 33 content : Eina.Content @by_ref; [[The content you want to provide via dnd]]
15 @in data: Eina.Slice; [[The drag data]] 34 @in action: string; [[Action when data is transferred]]
16 @in action: Efl.Ui.Selection_Action; [[Action when data is transferred]]
17 @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Function pointer to create icon]]
18 @in seat: uint; [[Specified seat for multiple seats case.]]
19 }
20 }
21 drag_action_set {
22 [[Set the action for the drag]]
23 params {
24 @in action: Efl.Ui.Selection_Action; [[Drag action]]
25 @in seat: uint; [[Specified seat for multiple seats case.]] 35 @in seat: uint; [[Specified seat for multiple seats case.]]
26 } 36 }
37 return : Efl.Content; [[A UI element where you can just set your visual representation into]]
27 } 38 }
28 drag_cancel { 39 drag_cancel {
29 [[Cancel the on-going drag]] 40 [[Cancel the on-going drag]]
@@ -31,33 +42,26 @@ mixin @beta Efl.Ui.Dnd {
31 @in seat: uint; [[Specified seat for multiple seats case.]] 42 @in seat: uint; [[Specified seat for multiple seats case.]]
32 } 43 }
33 } 44 }
34 drop_target_add { 45 drop_data_get {
35 [[Make the current object as drop target. 46 [[Get the data from the object that has selection]]
36 There are four events emitted:
37 - EFL_UI_DND_EVENT_DRAG_ENTER
38 - EFL_UI_DND_EVENT_DRAG_LEAVE
39 - EFL_UI_DND_EVENT_DRAG_POS
40 - EFL_UI_DND_EVENT_DRAG_DROP.]]
41 params { 47 params {
42 @in format: Efl.Ui.Selection_Format; [[Accepted data format]] 48 seat : uint; [[Specified seat for multiple seats case.]]
43 @in seat: uint; [[Specified seat for multiple seats case.]] 49 acceptable_types : iterator<string>; [[The types that are acceptable for you]]
44 }
45 }
46 drop_target_del {
47 [[Delete the dropable status from object]]
48 params {
49 @in format: Efl.Ui.Selection_Format; [[Accepted data format]]
50 @in seat: uint; [[Specified seat for multiple seats case.]]
51 } 50 }
51 return : future<Eina.Content> @move; [[fullfilled when the content is transmitted, and ready to use]]
52 } 52 }
53 } 53 }
54 events { 54 events {
55 /* FIXME: This is not very future-proof. Better return a struct. */ 55 drop,entered : Efl.Ui.Drop_Event;
56 drag,accept: ptr(bool); [[accept drag data]] 56 drop,left : Efl.Ui.Drop_Event;
57 drag,done: void; [[drag is done (mouse up)]] 57 drop,position,changed : Efl.Ui.Drop_Event;
58 drag,enter: void; [[called when the drag object enters this object]] 58 drop,dropped : Efl.Ui.Drop_Dropped_Event;
59 drag,leave: void; [[called when the drag object leaves this object]] 59 drag,started : Efl.Ui.Drag_Started_Event;
60 drag,pos: Efl.Dnd.Drag_Pos; [[called when the drag object changes drag position]] 60 drag,finished : Efl.Ui.Drag_Finished_Event;
61 drag,drop: Efl.Ui.Selection_Data; [[called when the drag object dropped on this object]] 61 }
62 implements {
63 Efl.Object.constructor;
64 Efl.Object.invalidate;
65 Efl.Object.finalize;
62 } 66 }
63} 67}
diff --git a/src/lib/elementary/efl_ui_dnd_container.eo b/src/lib/elementary/efl_ui_dnd_container.eo
deleted file mode 100644
index 0cc1f3f945..0000000000
--- a/src/lib/elementary/efl_ui_dnd_container.eo
+++ /dev/null
@@ -1,46 +0,0 @@
1import efl_ui_dnd_types;
2
3mixin @beta Efl.Ui.Dnd_Container {
4 methods {
5 @property drag_delay_time {
6 [[The time since mouse down happens to drag starts.]]
7 set {
8 }
9 get {
10 }
11 values {
12 time: double; [[The drag delay time]]
13 }
14 }
15 drag_item_add {
16 [[This registers a drag for items in a container. Many items can be
17 dragged at a time. During dragging, there are three events emitted:
18 EFL_DND_EVENT_DRAG_POS, EFL_DND_EVENT_DRAG_ACCEPT, EFL_DND_EVENT_DRAG_DONE.]]
19 params {
20 @in data_func: Efl.Dnd.Drag_Data_Get; [[Data and its format]]
21 @in item_func: Efl.Dnd.Item_Get; [[Item to determine drag start]]
22 @in icon_func: Efl.Dnd.Drag_Icon_Create; [[Icon used during drag]]
23 @in icon_list_func: Efl.Dnd.Drag_Icon_List_Create; [[Icons used for animations CHECKING ]]
24 @in seat: uint; [[Specified seat for multiple seats case.]]
25 }
26 }
27 drag_item_del {
28 [[Remove drag function of items in the container object.]]
29 params {
30 @in seat: uint; [[Specified seat for multiple seats case.]]
31 }
32 }
33 drop_item_add {
34 params {
35 @in format: Efl.Ui.Selection_Format; [[Accepted data formats]]
36 @in item_func: Efl.Dnd.Item_Get; [[Get item at specific position]]
37 @in seat: uint; [[Specified seat for multiple seats case.]]
38 }
39 }
40 drop_item_del {
41 params {
42 @in seat: uint; [[Specified seat for multiple seats case.]]
43 }
44 }
45 }
46}
diff --git a/src/lib/elementary/efl_ui_dnd_types.eot b/src/lib/elementary/efl_ui_dnd_types.eot
deleted file mode 100644
index ace1c8de7b..0000000000
--- a/src/lib/elementary/efl_ui_dnd_types.eot
+++ /dev/null
@@ -1,60 +0,0 @@
1import efl_ui_selection_types;
2
3function @beta Efl.Dnd.Drag_Icon_Create {
4 [[Function pointer for creating icon at the drag side.]]
5 params {
6 @in win: Efl.Canvas.Object; [[The window to create the objects relative to]]
7 @in drag_obj: Efl.Canvas.Object; [[The drag object]]
8 @out off: Eina.Position2D; [[Offset from the icon position to the cursor]]
9 }
10 return: Efl.Canvas.Object; [[The drag icon object]]
11};
12
13function @beta Efl.Dnd.Drag_Data_Get {
14 [[Function pointer for getting data and format at the drag side.]]
15 params {
16 @in obj: Efl.Canvas.Object; [[The container object]]
17 @out format: Efl.Ui.Selection_Format; [[Data format]]
18 @out drag_data: Eina.Rw_Slice; [[Data]]
19 @out action: Efl.Ui.Selection_Action; [[The drag action]]
20 }
21};
22
23function @beta Efl.Dnd.Item_Get {
24 [[Function pointer to find out which item is under position (x, y)]]
25 params {
26 @in obj: Efl.Canvas.Object; [[The container object]]
27 @in pos: Eina.Position2D; [[The coordinates to get item]]
28 @out posret: Eina.Position2D; [[position relative to item (left (-1), middle (0), right (1)]]
29 }
30 return: Efl.Object; [[Object under x,y coordinates or NULL if not found]]
31};
32
33function @beta Efl.Dnd.Drag_Icon_List_Create {
34 [[Function pointer to create list of icons at the drag side.
35 These icons are used for animation on combining selection icons
36 to one icon.]]
37 params {
38 @in obj: Efl.Canvas.Object; [[The container object]]
39 }
40 return: list<Efl.Canvas.Object>;
41};
42
43struct @beta Efl.Dnd.Drag_Accept {
44 accepted: bool;
45}
46
47struct @beta Efl.Dnd.Drag_Pos {
48 [[Dragging position information.]]
49 pos: Eina.Position2D; [[Evas Coordinate]]
50 action: Efl.Ui.Selection_Action; [[The drag action]]
51 format: Efl.Ui.Selection_Format; [[The drag format]]
52 item: Efl.Canvas.Object; [[The item object. It is only available for container object.]]
53}
54
55struct @beta Efl.Dnd.Drag_Item_Container_Drop {
56 [[Drop information for a drag&drop operation.]]
57 item: Efl.Canvas.Object; [[The item object]]
58 data: Efl.Ui.Selection_Data; [[The selection data]]
59 pos: Eina.Position2D; [[Position relative to item (left (-1), middle (0), right (1)]]
60}
diff --git a/src/lib/elementary/efl_ui_selection.c b/src/lib/elementary/efl_ui_selection.c
index 675eb0cf99..d67d1f3fef 100644
--- a/src/lib/elementary/efl_ui_selection.c
+++ b/src/lib/elementary/efl_ui_selection.c
@@ -9,278 +9,115 @@
9#define MY_CLASS EFL_UI_SELECTION_MIXIN 9#define MY_CLASS EFL_UI_SELECTION_MIXIN
10#define MY_CLASS_NAME "Efl.Ui.Selection" 10#define MY_CLASS_NAME "Efl.Ui.Selection"
11 11
12#ifdef HAVE_ELEMENTARY_WL2 12typedef struct {
13Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj); 13 Ecore_Evas *ee;
14#endif 14 Eina_Bool registered : 1;
15} Efl_Ui_Selection_Data;
15 16
16EOLIAN static void 17static inline Ecore_Evas_Selection_Buffer
17_efl_ui_selection_selection_get(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, 18_ee_buffer_get(Efl_Ui_Cnp_Buffer buffer)
18 void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, unsigned int seat)
19{ 19{
20 Eo *sel_man = _efl_ui_selection_manager_get(obj); 20 if (buffer == EFL_UI_CNP_BUFFER_SELECTION)
21 efl_ui_selection_manager_selection_get(sel_man, obj, type, format, 21 return ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER;
22 data_func_data, data_func, 22 else
23 data_func_free_cb, seat); 23 return ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER;
24} 24}
25 25
26EOLIAN static Eina_Future * 26EOLIAN static Eina_Future*
27_efl_ui_selection_selection_set(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, Eina_Slice data, unsigned int seat) 27_efl_ui_selection_selection_get(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat, Eina_Iterator *acceptable_types)
28{ 28{
29 Eo *sel_man = _efl_ui_selection_manager_get(obj); 29 return ecore_evas_selection_get(pd->ee, seat, _ee_buffer_get(buffer), acceptable_types);
30 return efl_ui_selection_manager_selection_set(sel_man, obj, type, format, data, seat);
31} 30}
32 31
33EOLIAN static void 32EOLIAN static void
34_efl_ui_selection_selection_clear(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, unsigned int seat) 33_efl_ui_selection_selection_set(Eo *obj, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, Eina_Content *content, unsigned int seat)
35{ 34{
36 Eo *sel_man = _efl_ui_selection_manager_get(obj); 35 _register_selection_changed(obj);
37 efl_ui_selection_manager_selection_clear(sel_man, obj, type, seat); 36 ecore_evas_selection_set(pd->ee, seat, _ee_buffer_get(buffer), content);
38} 37}
39 38
40EOLIAN static Eina_Bool 39EOLIAN static void
41_efl_ui_selection_has_owner(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, unsigned int seat) 40_efl_ui_selection_selection_clear(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat)
42{ 41{
43 Eo *sel_man = _efl_ui_selection_manager_get(obj); 42 ecore_evas_selection_set(pd->ee, seat, _ee_buffer_get(buffer), NULL);
44 return efl_ui_selection_manager_selection_has_owner(sel_man, obj, type, seat);
45} 43}
46 44
45EOLIAN static Eina_Bool
46_efl_ui_selection_has_selection(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat)
47{
48 return ecore_evas_selection_exists(pd->ee, seat, _ee_buffer_get(buffer));
49}
47 50
48////////// Support legacy APIs 51EOLIAN static Efl_Object*
49 52_efl_ui_selection_efl_object_constructor(Eo *obj, Efl_Ui_Selection_Data *pd)
50//TODO: Clear this list (when sel_man is deleted)
51Eina_List *lost_cb_list = NULL;
52
53#ifdef HAVE_ELEMENTARY_WL2
54static Ecore_Evas *
55_wl_is_wl(const Evas_Object *obj)
56{ 53{
57 Ecore_Evas *ee; 54 if (!efl_constructor(efl_super(obj, EFL_UI_SELECTION_MIXIN)))
58 Evas *evas; 55 return NULL;
59 const char *engine_name;
60 56
61 if (!(evas = evas_object_evas_get(obj))) 57 pd->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
62 return NULL;
63 if (!(ee = ecore_evas_ecore_evas_get(evas)))
64 return NULL;
65 58
66 engine_name = ecore_evas_engine_name_get(ee); 59 return obj;
67 if (!strcmp(engine_name, ELM_BUFFER))
68 {
69 ee = ecore_evas_buffer_ecore_evas_parent_get(ee);
70 if (!ee) return NULL;
71 engine_name = ecore_evas_engine_name_get(ee);
72 }
73 if (!strncmp(engine_name, "wayland", sizeof("wayland") - 1))
74 return ee;
75 return NULL;
76} 60}
77 61
78int 62EOLIAN static void
79_wl_default_seat_id_get(Evas_Object *obj) 63_efl_ui_selection_efl_object_invalidate(Eo *obj, Efl_Ui_Selection_Data *pd)
80{ 64{
81 Ecore_Wl2_Window *win = _wl_window_get(obj); 65 if (pd->registered)
82 Eo *seat, *parent2, *ewin;
83 Eina_Bool is_wl = EINA_FALSE;
84
85 if (obj)
86 { 66 {
87 if (_wl_is_wl(obj)) is_wl = EINA_TRUE; 67 _selection_changed_event_unregister(obj);
88 if (efl_isa(obj, EFL_UI_WIDGET_CLASS))
89 {
90 Eo *top = elm_widget_top_get(obj);
91 if (efl_isa(top, EFL_UI_WIN_INLINED_CLASS))
92 {
93 parent2 = efl_ui_win_inlined_parent_get(top);
94 if (parent2) obj = elm_widget_top_get(parent2) ?: parent2;
95 }
96 /* fake win means canvas seat id will not match protocol seat id */
97 ewin = elm_win_get(obj);
98 if (elm_win_type_get(ewin) == ELM_WIN_FAKE) obj = NULL;
99 }
100 }
101
102 if (!obj)
103 {
104 if (is_wl)
105 {
106 Ecore_Wl2_Input *input;
107 Eina_Iterator *it;
108
109 it = ecore_wl2_display_inputs_get(ecore_wl2_window_display_get(win));
110 EINA_ITERATOR_FOREACH(it, input) break;
111 eina_iterator_free(it);
112 if (input)
113 return ecore_wl2_input_seat_id_get(input);
114 }
115 } 68 }
116 69 efl_invalidate(efl_super(obj, EFL_UI_SELECTION_MIXIN));
117 seat = evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT);
118 EINA_SAFETY_ON_NULL_RETURN_VAL(seat, 1);
119 return evas_device_seat_id_get(seat);
120} 70}
121#endif
122 71
123typedef struct _Cnp_Data_Cb_Wrapper Cnp_Data_Cb_Wrapper; 72EOLIAN static Eina_Bool
124struct _Cnp_Data_Cb_Wrapper 73_efl_ui_selection_efl_object_event_callback_priority_add(Eo *obj, Efl_Ui_Selection_Data *pd,
74 const Efl_Event_Description *desc,
75 Efl_Callback_Priority priority,
76 Efl_Event_Cb func,
77 const void *user_data)
125{ 78{
126 void *udata; 79 if (desc == EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED && !pd->registered)
127 Elm_Drop_Cb datacb; 80 {
128};
129 81
130static void 82 pd->registered = EINA_TRUE;
131_selection_data_ready_cb(void *data, Efl_Object *obj, Efl_Ui_Selection_Data *seldata) 83 if (efl_finalized_get(obj))
132{ 84 _selection_changed_event_register(obj);
133 Cnp_Data_Cb_Wrapper *wdata = data; 85 }
134 if (!wdata) return;
135 Elm_Selection_Data ddata;
136 86
137 ddata.data = calloc(1, seldata->content.len + 1); 87 return efl_event_callback_priority_add(efl_super(obj, EFL_UI_SELECTION_MIXIN), desc, priority, func, user_data);
138 if (!ddata.data) return;
139 ddata.data = memcpy(ddata.data, seldata->content.mem, seldata->content.len);
140 ddata.len = seldata->content.len;
141 ddata.x = seldata->pos.x;
142 ddata.y = seldata->pos.y;
143 ddata.format = (Elm_Sel_Format)seldata->format;
144 ddata.action = (Elm_Xdnd_Action)seldata->action;
145 wdata->datacb(wdata->udata, obj, &ddata);
146 free(ddata.data);
147} 88}
148 89
149typedef struct _Sel_Lost_Data Sel_Lost_Data; 90EOLIAN static Eina_Bool
150struct _Sel_Lost_Data 91_efl_ui_selection_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Ui_Selection_Data *pd,
151{ 92 const Efl_Callback_Array_Item *array,
152 const Evas_Object *obj; 93 Efl_Callback_Priority priority,
153 Elm_Sel_Type type; 94 const void *user_data)
154 void *udata;
155 Elm_Selection_Loss_Cb loss_cb;
156};
157
158static Eina_Value
159_selection_lost_cb(void *data, const Eina_Value value)
160{ 95{
161 Eina_List *l, *l2; 96 for (int i = 0; array[i].desc; ++i)
162 Sel_Lost_Data *ldata, *ldata2;
163
164 ldata = data;
165 EINA_LIST_FOREACH_SAFE(lost_cb_list, l, l2, ldata2)
166 { 97 {
167 if ((ldata->obj == ldata2->obj) && 98 if (array[i].desc == EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED && !pd->registered)
168 (ldata->type == ldata2->type))
169 { 99 {
170 ldata2->loss_cb(ldata2->udata, ldata2->type); 100 pd->registered = EINA_TRUE;
171 lost_cb_list = eina_list_remove(lost_cb_list, ldata2); 101 if (efl_finalized_get(obj))
102 _selection_changed_event_register(obj);
172 } 103 }
173 } 104 }
174 free(ldata); 105 return efl_event_callback_array_priority_add(efl_super(obj, EFL_UI_SELECTION_MIXIN), array, priority, user_data);
175
176 return value;
177} 106}
178 107
179EAPI Eina_Bool
180elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type type,
181 Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata)
182{
183 int seatid = 1;
184 Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj);
185 Cnp_Data_Cb_Wrapper *wdata = calloc(1, sizeof(Cnp_Data_Cb_Wrapper));
186
187 if (!wdata) return EINA_FALSE;
188 108
189#ifdef HAVE_ELEMENTARY_WL2 109EOLIAN static Efl_Object*
190 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get((Evas_Object *)obj); 110_efl_ui_selection_efl_object_finalize(Eo *obj, Efl_Ui_Selection_Data *pd)
191#endif
192 wdata->udata = udata;
193 wdata->datacb = datacb;
194 efl_ui_selection_manager_selection_get(sel_man, (Evas_Object *)obj, (Efl_Ui_Selection_Type)type,
195 (Efl_Ui_Selection_Format)format,
196 wdata, _selection_data_ready_cb, NULL, seatid);
197 return EINA_TRUE;
198}
199
200EAPI Eina_Bool
201elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type type,
202 Elm_Sel_Format format, const void *selbuf, size_t buflen)
203{ 111{
204 int seatid = 1; 112 if (pd->registered)
205 Eina_Future *f; 113 _selection_changed_event_register(obj);
206 Sel_Lost_Data *ldata;
207 Eo *sel_man = _efl_ui_selection_manager_get(obj);
208 Eina_Slice data;
209 114
210 ldata = calloc(1, sizeof(Sel_Lost_Data)); 115 return efl_finalize(efl_super(obj, MY_CLASS));
211 if (!ldata) return EINA_FALSE;
212 data.mem = selbuf;
213 data.len = buflen;
214#ifdef HAVE_ELEMENTARY_WL2
215 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
216#endif
217 f = efl_ui_selection_manager_selection_set(sel_man, obj, (Efl_Ui_Selection_Type)type,
218 (Efl_Ui_Selection_Format)format, data, seatid);
219
220 ldata->obj = obj;
221 ldata->type = type;
222 eina_future_then_easy(f, _selection_lost_cb, NULL, NULL, EINA_VALUE_TYPE_UINT, ldata);
223
224 return EINA_TRUE;
225} 116}
226 117
227EAPI Eina_Bool
228elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type type)
229{
230 int seatid = 1;
231 Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj);
232
233#ifdef HAVE_ELEMENTARY_WL2
234 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
235#endif
236 efl_ui_selection_manager_selection_clear(sel_man, obj, (Efl_Ui_Selection_Type)type, seatid);
237
238 return EINA_TRUE;
239}
240 118
241EAPI void 119#define EFL_UI_SELECTION_EXTRA_OPS \
242elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type type, 120 EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_ui_selection_efl_object_event_callback_priority_add), \
243 Elm_Selection_Loss_Cb func, const void *data) 121 EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_ui_selection_efl_object_event_callback_array_priority_add), \
244{
245 Sel_Lost_Data *ldata = calloc(1, sizeof(Sel_Lost_Data));
246#if HAVE_ELEMENTARY_COCOA
247 // Currently, we have no way to track changes in Cocoa pasteboard.
248 // Therefore, don't track this...
249 return;
250#endif
251 if (!ldata) return;
252 ldata->obj = obj;
253 ldata->type = type;
254 ldata->udata = (void *)data;
255 ldata->loss_cb = func;
256 lost_cb_list = eina_list_append(lost_cb_list, ldata);
257}
258
259EAPI Eina_Bool
260elm_selection_selection_has_owner(Evas_Object *obj)
261{
262 int seatid = 1;
263 Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj);
264
265#ifdef HAVE_ELEMENTARY_WL2
266 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
267#endif
268
269 return efl_ui_selection_manager_selection_has_owner(sel_man, obj,
270 EFL_UI_SELECTION_TYPE_CLIPBOARD, seatid);
271}
272
273EAPI Eina_Bool
274elm_cnp_clipboard_selection_has_owner(Evas_Object *obj)
275{
276 int seatid = 1;
277 Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj);
278
279#ifdef HAVE_ELEMENTARY_WL2
280 if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
281#endif
282 return efl_ui_selection_manager_selection_has_owner(sel_man, obj,
283 EFL_UI_SELECTION_TYPE_CLIPBOARD, seatid);
284}
285 122
286#include "efl_ui_selection.eo.c" 123#include "efl_ui_selection.eo.c"
diff --git a/src/lib/elementary/efl_ui_selection.eo b/src/lib/elementary/efl_ui_selection.eo
index 20e42261d0..492e60e117 100644
--- a/src/lib/elementary/efl_ui_selection.eo
+++ b/src/lib/elementary/efl_ui_selection.eo
@@ -1,45 +1,57 @@
1import efl_ui_selection_types; 1import eina_types;
2 2
3mixin @beta Efl.Ui.Selection { 3enum @beta Efl.Ui.Cnp_Buffer{
4 [[Efl Ui Selection class]] 4 selection = 0,
5 data: null; 5 copy_and_paste = 1,
6 methods { 6}
7 selection_set { 7
8 [[Set the selection data to the object]] 8struct @beta Efl.Ui.Wm_Selection_Changed {
9 params { 9 buffer : Efl.Ui.Cnp_Buffer;
10 @in type: Efl.Ui.Selection_Type; [[Selection Type]] 10 caused_by : Efl.Ui.Selection;
11 @in format: Efl.Ui.Selection_Format; [[Selection Format]] 11 seat : uint;
12 @in data: Eina.Slice; [[Selection data]] 12}
13 @in seat: uint;[[Specified seat for multiple seats case.]] 13
14 } 14mixin @beta Efl.Ui.Selection requires Efl.Object {
15 return: future<void>; [[Future for tracking when the selection is lost]] 15 methods {
16 selection_set {
17 [[Set the selection data to the object]]
18 params {
19 buffer : Efl.Ui.Cnp_Buffer;
20 content : Eina.Content @by_ref;
21 seat : uint;
16 } 22 }
17 selection_get { 23 }
18 [[Get the data from the object that has selection]] 24 selection_clear {
19 params { 25 [[Clear the selection data from the object]]
20 @in type: Efl.Ui.Selection_Type; [[Selection Type]] 26 params {
21 @in format: Efl.Ui.Selection_Format; [[Selection Format]] 27 buffer : Efl.Ui.Cnp_Buffer;
22 @in data_func: Efl.Ui.Selection_Data_Ready; [[Data ready function pointer]] 28 seat : uint;
23 @in seat: uint;[[Specified seat for multiple seats case.]]
24 }
25 } 29 }
26 selection_clear { 30 }
27 [[Clear the selection data from the object]] 31 selection_get {
28 params { 32 [[Get the data from the object that has selection]]
29 @in type: Efl.Ui.Selection_Type; [[Selection Type]] 33 params {
30 @in seat: uint; [[Specified seat for multiple seats case.]] 34 buffer : Efl.Ui.Cnp_Buffer;
31 } 35 seat : uint;
36 acceptable_types : iterator<string>;
32 } 37 }
33 has_owner { 38 return : future<Eina.Content> @move;
34 [[Determine whether the selection data has owner]] 39 }
35 params { 40 has_selection {
36 @in type: Efl.Ui.Selection_Type; [[Selection type]] 41 [[Determine whether the selection data has owner]]
37 @in seat: uint; [[Specified seat for multiple seats case.]] 42 params {
38 } 43 buffer : Efl.Ui.Cnp_Buffer;
39 return: bool; [[EINA_TRUE if there is object owns selection, otherwise EINA_FALSE]] 44 seat : uint;
40 } 45 }
41 } 46 return : bool; [[$true if there is a available selection, $false if not]]
42 events { 47 }
43 wm_selection,changed: Efl.Ui.Selection_Changed; [[Called when display server's selection has changed]] 48 }
44 } 49 implements {
50 Efl.Object.constructor;
51 Efl.Object.invalidate;
52 Efl.Object.finalize;
53 }
54 events {
55 wm_selection,changed : Efl.Ui.Wm_Selection_Changed;
56 }
45} 57}
diff --git a/src/lib/elementary/efl_ui_selection_manager.c b/src/lib/elementary/efl_ui_selection_manager.c
deleted file mode 100644
index 76f2c03002..0000000000
--- a/src/lib/elementary/efl_ui_selection_manager.c
+++ /dev/null
@@ -1,5678 +0,0 @@
1#ifdef HAVE_CONFIG_H
2# include "elementary_config.h"
3#endif
4
5#include <Elementary.h>
6#include "elm_priv.h"
7
8#ifdef _WIN32
9# include <evil_private.h> /* mmap */
10#else
11# include <sys/mman.h>
12#endif
13
14#include "efl_ui_selection_manager_private.h"
15
16#define MY_CLASS EFL_UI_SELECTION_MANAGER_CLASS
17
18//#define DEBUGON 1
19#ifdef DEBUGON
20# define sel_debug(fmt, args...) fprintf(stderr, __FILE__":%s:%d : " fmt "\n", __FUNCTION__, __LINE__, ##args)
21#else
22# define sel_debug(x...) do { } while (0)
23#endif
24
25static void _anim_data_free(Sel_Manager_Drag_Container *dc);
26static void _cont_obj_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
27static void _cont_obj_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
28static void _item_container_del_internal(Sel_Manager_Drag_Container *dc, Eina_Bool full);
29
30void efl_ui_selection_manager_drop_target_del(Eo *obj, Efl_Object *target_obj, Efl_Ui_Selection_Format format, unsigned int seat);
31void efl_ui_selection_manager_selection_clear(Eo *obj, Efl_Object *owner, Efl_Ui_Selection_Type type, unsigned int seat);
32void efl_ui_selection_manager_drag_start(Eo *obj, Efl_Object *drag_obj, Efl_Ui_Selection_Format format, Eina_Slice data, Efl_Ui_Selection_Action action, void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb, unsigned int seat);
33
34static Eina_List *managers;
35
36#ifdef HAVE_ELEMENTARY_X
37static void _set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel);
38static Ecore_X_Atom _x11_dnd_action_rev_map(Efl_Ui_Selection_Action action);
39static Ecore_X_Window _x11_xwin_get(const Evas_Object *obj);
40#endif
41
42#ifdef HAVE_ELEMENTARY_WL2
43Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj);
44static Ecore_Wl2_Input *_wl_seat_get(Ecore_Wl2_Window *win, Evas_Object *obj, unsigned int seat_id);
45#endif
46
47#ifdef HAVE_ELEMENTARY_WIN32
48static void _set_selection_list(Sel_Manager_Selection *sel_list, Sel_Manager_Seat_Selection *seat_sel);
49#endif
50
51EAPI int ELM_CNP_EVENT_SELECTION_CHANGED = -1;
52
53#ifdef HAVE_ELEMENTARY_X
54static Sel_Manager_Seat_Selection *
55_sel_manager_seat_selection_get(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat)
56{
57 Eina_List *l = NULL;
58 Sel_Manager_Seat_Selection *seat_sel = NULL;
59
60 EINA_LIST_FOREACH(pd->seat_list, l, seat_sel)
61 {
62 if (seat_sel->seat == seat)
63 break;
64 }
65 if (!seat_sel)
66 ERR("Could not find request seat");
67
68 return seat_sel;
69}
70#endif
71
72static inline void
73_owner_change_check(Efl_Ui_Selection_Manager *manager, Efl_Object *owner,
74 Sel_Manager_Seat_Selection *seat_sel,
75 Sel_Manager_Selection *sel,
76 Efl_Ui_Selection_Type type, Eina_Bool same_win)
77{
78 if (!same_win)
79 {
80 Eina_List *l, *l_next;
81 Eo *man;
82
83 EINA_LIST_FOREACH_SAFE(managers, l, l_next, man)
84 {
85 if (man != manager)
86 {
87 Eina_List *l2, *l2_next, *l3, *l3_next;
88 Sel_Manager_Selection_Lost *sel_lost;
89 Sel_Manager_Seat_Selection *seat_sel2;
90 Efl_Ui_Selection_Manager_Data *pd = efl_data_scope_get(man, MY_CLASS);
91
92 if (!pd) continue;
93 EINA_LIST_FOREACH_SAFE(pd->seat_list, l3, l3_next, seat_sel2)
94 {
95 EINA_LIST_FOREACH_SAFE(seat_sel2->sel_lost_list, l2, l2_next, sel_lost)
96 {
97 if ((sel_lost->request) &&
98 (sel_lost->type == type))
99 {
100 eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type));
101 }
102 }
103 seat_sel2->xwin = 0;
104#if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_WIN32)
105 if (seat_sel2->sel_list)
106 {
107 int i;
108
109 for (i = 0;
110 i < (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1)
111 ; i++)
112 {
113#ifdef HAVE_ELEMENTARY_X
114 seat_sel2->sel_list[i].xwin = 0;
115#elif defined (HAVE_ELEMENTARY_WIN32)
116 seat_sel2->sel_list[i].win = NULL;
117#endif
118 seat_sel2->sel_list[i].active = EINA_FALSE;
119 }
120 }
121#endif
122#if defined(HAVE_ELEMENTARY_WL2) || defined(HAVE_ELEMENTARY_COCOA)
123 if (seat_sel2->sel)
124 {
125 seat_sel2->sel->win = 0;
126 seat_sel2->sel->active = EINA_FALSE;
127 }
128#endif
129 }
130 }
131 }
132 }
133 if ((sel->owner != NULL) &&
134 (sel->owner != owner) && same_win)
135 {
136 Eina_List *l, *l_next;
137 Sel_Manager_Selection_Lost *sel_lost;
138 EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost)
139 {
140 if ((sel_lost->request == sel->owner) &&
141 (sel_lost->type == type))
142 {
143 eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type));
144 }
145 }
146 }
147}
148
149static Sel_Manager_Seat_Selection *
150_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat)
151{
152 Sel_Manager_Seat_Selection *seat_sel = NULL;
153 Eina_List *l = NULL;
154
155 EINA_LIST_FOREACH(pd->seat_list, l, seat_sel)
156 {
157 if(seat_sel->seat == seat)
158 break;
159 }
160 if (!seat_sel)
161 {
162 seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection));
163 if (!seat_sel)
164 {
165 ERR("Failed to allocate seat");
166 return NULL;
167 }
168 seat_sel->saved_types = calloc(1, sizeof(Saved_Type));
169 seat_sel->seat = seat;
170 seat_sel->pd = pd;
171 pd->seat_list = eina_list_append(pd->seat_list, seat_sel);
172 }
173#ifdef HAVE_ELEMENTARY_X
174 if (!seat_sel->sel_list)
175 {
176 seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection));
177 if (!seat_sel->sel_list)
178 {
179 ERR("failed to allocate selection list");
180 return NULL;
181 }
182 _set_selection_list(seat_sel->sel_list, seat_sel);
183 }
184#endif
185#ifdef HAVE_ELEMENTARY_WL2
186 if (!seat_sel->sel)
187 {
188 Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection));
189 if (!sel)
190 {
191 ERR("failed to allocate selection");
192 return NULL;
193 }
194 sel->seat_sel = seat_sel;
195 seat_sel->sel = sel;
196 }
197#endif
198#ifdef HAVE_ELEMENTARY_COCOA
199 if (!seat_sel->sel)
200 {
201 Sel_Manager_Selection *sel = calloc(1, sizeof(Sel_Manager_Selection));
202 if (!sel)
203 {
204 ERR("failed to allocate selection");
205 return NULL;
206 }
207 sel->seat_sel = seat_sel;
208 seat_sel->sel = sel;
209 }
210#endif
211#ifdef HAVE_ELEMENTARY_WIN32
212 if (!seat_sel->sel_list)
213 {
214 seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection));
215 if (!seat_sel->sel_list)
216 {
217 ERR("failed to allocate selection list");
218 return NULL;
219 }
220 _set_selection_list(seat_sel->sel_list, seat_sel);
221 }
222#endif
223
224 return seat_sel;
225}
226
227static void
228_sel_manager_promise_cancel(Eo *obj EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
229{
230 Sel_Manager_Selection_Lost *sel_lost = data;
231 sel_lost->seat_sel->sel_lost_list = eina_list_remove(sel_lost->seat_sel->sel_lost_list, sel_lost);
232 free(sel_lost);
233}
234
235static inline Eina_Future *
236_update_sel_lost_list(Efl_Object *obj, Efl_Ui_Selection_Type type,
237 Sel_Manager_Seat_Selection *seat_sel)
238{
239 Eina_Promise *p;
240 Sel_Manager_Selection_Lost *sel_lost;
241
242 sel_lost = calloc(1, sizeof(Sel_Manager_Selection_Lost));
243 if (!sel_lost)
244 return NULL;
245 sel_lost->request = obj;
246 sel_lost->type = type;
247 sel_lost->seat_sel = seat_sel;
248 seat_sel->sel_lost_list = eina_list_append(seat_sel->sel_lost_list, sel_lost);
249
250 p = efl_loop_promise_new(obj);
251 if (!p) return NULL;
252 sel_lost->promise = p;
253
254 return efl_future_then(obj, eina_future_new(p),
255 .data = sel_lost,
256 .free = _sel_manager_promise_cancel);
257}
258
259/* TODO: this should not be an actual tempfile, but rather encode the object
260 * as http://dataurl.net/ if it's an image or similar. Evas should support
261 * decoding it as memfile. */
262static Tmp_Info *
263_tempfile_new(int size)
264{
265#ifdef HAVE_MMAP
266 Tmp_Info *info;
267 const char *tmppath = NULL;
268 mode_t cur_umask;
269 int len;
270
271 info = calloc(1, sizeof(Tmp_Info));
272 if (!info) return NULL;
273#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
274 if (getuid() == geteuid())
275#endif
276 tmppath = getenv("TMP");
277 if (!tmppath) tmppath = P_tmpdir;
278 len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-");
279 if (len < 0) goto on_error;
280 len++;
281 info->filename = malloc(len);
282 if (!info->filename) goto on_error;
283 snprintf(info->filename,len,"%s/%sXXXXXX", tmppath, "elmcnpitem-");
284 cur_umask = umask(S_IRWXO | S_IRWXG);
285 info->fd = mkstemp(info->filename);
286 umask(cur_umask);
287 if (info->fd < 0) goto on_error;
288# ifdef __linux__
289 {
290 char *tmp;
291 /* And before someone says anything see POSIX 1003.1-2008 page 400 */
292 long pid;
293
294 pid = (long)getpid();
295 /* Use pid instead of /proc/self: That way if can be passed around */
296 len = snprintf(NULL,0,"/proc/%li/fd/%i", pid, info->fd);
297 len++;
298 tmp = malloc(len);
299 if (tmp)
300 {
301 snprintf(tmp,len, "/proc/%li/fd/%i", pid, info->fd);
302 unlink(info->filename);
303 free(info->filename);
304 info->filename = tmp;
305 }
306 }
307# endif
308 sel_debug("filename is %s\n", info->filename);
309 if (size < 1) goto on_error;
310 /* Map it in */
311 if (ftruncate(info->fd, size))
312 {
313 perror("ftruncate");
314 goto on_error;
315 }
316 eina_mmap_safety_enabled_set(EINA_TRUE);
317 info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0);
318 if (info->map == MAP_FAILED)
319 {
320 perror("mmap");
321 goto on_error;
322 }
323 return info;
324
325 on_error:
326 if (info->fd >= 0) close(info->fd);
327 info->fd = -1;
328 /* Set map to NULL and return */
329 info->map = NULL;
330 info->len = 0;
331 free(info->filename);
332 free(info);
333 return NULL;
334#else
335 (void) size;
336 return NULL;
337#endif
338}
339
340static int
341_tmpinfo_free(Tmp_Info *info)
342{
343 if (!info) return 0;
344 free(info->filename);
345 free(info);
346 return 0;
347}
348
349static inline void
350_drop_target_cbs_del(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Dropable *dropable, Efl_Object *obj)
351{
352 if (dropable)
353 {
354 Drop_Format *df;
355 while (dropable->format_list)
356 {
357 df = EINA_INLIST_CONTAINER_GET(dropable->format_list, Drop_Format);
358 efl_ui_selection_manager_drop_target_del(pd->sel_man, obj,
359 df->format, dropable->seat);
360 // If drop_target_del() happened to delete dropabale, then
361 // re-fetch it each loop to make sure it didn't
362 dropable = efl_key_data_get(obj, "__elm_dropable");
363 if (!dropable) break;
364 }
365 }
366}
367
368static void
369_all_drop_targets_cbs_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED)
370{
371 Efl_Ui_Selection_Manager_Data *pd = data;
372 Sel_Manager_Dropable *dropable = NULL;
373
374 if (!pd) return;
375 dropable = efl_key_data_get(obj, "__elm_dropable");
376 _drop_target_cbs_del(pd, dropable, obj);
377}
378
379static void
380_dropable_coords_adjust(Sel_Manager_Dropable *dropable, Eina_Position2D *pos)
381{
382 Ecore_Evas *ee;
383 Evas *evas = evas_object_evas_get(dropable->obj);
384 int ex = 0, ey = 0, ew = 0, eh = 0;
385 Evas_Object *win;
386
387 ee = ecore_evas_ecore_evas_get(evas);
388 ecore_evas_geometry_get(ee, &ex, &ey, &ew, &eh);
389 pos->x = pos->x - ex;
390 pos->y = pos->y - ey;
391
392 /* For Wayland, frame coords have to be subtracted. */
393 Evas_Coord fx, fy;
394 evas_output_framespace_get(evas, &fx, &fy, NULL, NULL);
395 if (fx || fy) sel_debug("evas frame fx %d fy %d\n", fx, fy);
396 pos->x = pos->x - fx;
397 pos->y = pos->y - fy;
398
399 if (elm_widget_is(dropable->obj))
400 {
401 win = elm_widget_top_get(dropable->obj);
402 if (win && efl_isa(win, EFL_UI_WIN_CLASS))
403 {
404 Evas_Coord x2, y2;
405 int rot = elm_win_rotation_get(win);
406 switch (rot)
407 {
408 case 90:
409 x2 = ew - pos->y;
410 y2 = pos->x;
411 break;
412 case 180:
413 x2 = ew - pos->x;
414 y2 = eh - pos->y;
415 break;
416 case 270:
417 x2 = pos->y;
418 y2 = eh - pos->x;
419 break;
420 default:
421 x2 = pos->x;
422 y2 = pos->y;
423 break;
424 }
425 sel_debug("rotation %d, w %d, h %d - x:%d->%d, y:%d->%d\n",
426 rot, ew, eh, pos->x, x2, pos->y, y2);
427 pos->x = x2;
428 pos->y = y2;
429 }
430 }
431}
432
433static Eina_Bool
434_drag_cancel_animate(void *data, double pos)
435{ /* Animation to "move back" drag-window */
436 Sel_Manager_Seat_Selection *seat_sel = data;
437 sel_debug("in, pos: %f", pos);
438 if (pos >= 0.99)
439 {
440#ifdef HAVE_ELEMENTARY_X
441 Ecore_X_Window xdragwin = _x11_xwin_get(seat_sel->drag_win);
442 ecore_x_window_ignore_set(xdragwin, 0);
443#endif
444 sel_debug("Delete drag_win");
445 evas_object_del(seat_sel->drag_win);
446 seat_sel->drag_win = NULL;
447 return ECORE_CALLBACK_CANCEL;
448 }
449 else
450 {
451 int x, y;
452 x = seat_sel->drag_win_end.x - (pos * (seat_sel->drag_win_end.x - seat_sel->drag_win_start.x));
453 y = seat_sel->drag_win_end.y - (pos * (seat_sel->drag_win_end.y - seat_sel->drag_win_start.y));
454 evas_object_move(seat_sel->drag_win, x, y);
455 }
456
457 return ECORE_CALLBACK_RENEW;
458}
459
460static Efl_Ui_Selection_Format
461_dnd_types_to_format(Efl_Ui_Selection_Manager_Data *pd, const char **types, int ntypes)
462{
463 Efl_Ui_Selection_Format ret_type = 0;
464 int i;
465 for (i = 0; i < ntypes; i++)
466 {
467 Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, types[i]);
468 if (atom) ret_type |= atom->format;
469 }
470 return ret_type;
471}
472
473static Eina_List *
474_dropable_list_geom_find(Efl_Ui_Selection_Manager_Data *pd, Evas *evas, Evas_Coord px, Evas_Coord py)
475{
476 Eina_List *itr, *top_objects_list = NULL, *dropable_list = NULL;
477 Evas_Object *top_obj;
478 Sel_Manager_Dropable *dropable = NULL;
479
480 if (!pd->drop_list) return NULL;
481
482 /* We retrieve the (non-smart) objects pointed by (px, py) */
483 top_objects_list = evas_tree_objects_at_xy_get(evas, NULL, px, py);
484 /* We walk on this list from the last because if the list contains more than one
485 * element, all but the last will repeat events. The last one can repeat events
486 * or not. Anyway, this last one is the first that has to be taken into account
487 * for the determination of the drop target.
488 */
489 EINA_LIST_REVERSE_FOREACH(top_objects_list, itr, top_obj)
490 {
491 Evas_Object *object = top_obj;
492 /* We search for the dropable data into the object. If not found, we search into its parent.
493 * For example, if a button is a drop target, the first object will be an (internal) image.
494 * The drop target is attached to the button, i.e to image's parent. That's why we need to
495 * walk on the parents until NULL.
496 * If we find this dropable data, we found our drop target.
497 */
498 while (object)
499 {
500 dropable = efl_key_data_get(object, "__elm_dropable");
501 if (dropable)
502 {
503 Eina_Bool exist = EINA_FALSE;
504 Eina_List *l;
505 Sel_Manager_Dropable *d = NULL;
506 EINA_LIST_FOREACH(dropable_list, l, d)
507 {
508 if (d == dropable)
509 {
510 exist = EINA_TRUE;
511 break;
512 }
513 }
514 if (!exist)
515 dropable_list = eina_list_append(dropable_list, dropable);
516 object = evas_object_smart_parent_get(object);
517 if (dropable)
518 sel_debug("Drop target %p of type %s found\n",
519 dropable->obj, efl_class_name_get(efl_class_get(dropable->obj)));
520 }
521 else
522 object = evas_object_smart_parent_get(object);
523 }
524 }
525 eina_list_free(top_objects_list);
526 return dropable_list;
527}
528
529#ifdef HAVE_ELEMENTARY_X
530static Ecore_X_Window
531_x11_xwin_get(const Efl_Object *obj)
532{
533 if (!obj) return 0;
534
535 Ecore_X_Window xwin = 0;
536 //get top
537 const Evas_Object *top = obj;
538 const Evas_Object *parent = obj;
539 while(parent)
540 {
541 top = parent;
542 parent = efl_parent_get(parent);
543 }
544 if (efl_isa(top, EFL_UI_WIN_CLASS))
545 {
546 xwin = elm_win_xwindow_get(top);
547 }
548 if (!xwin)
549 {
550 Ecore_Evas *ee;
551 Evas *evas = evas_object_evas_get(obj);
552 if (!evas) return 0;
553 ee = ecore_evas_ecore_evas_get(evas);
554 if (!ee) return 0;
555
556 while(!xwin)
557 {
558 const char *engine_name = ecore_evas_engine_name_get(ee);
559 if (!strcmp(engine_name, ELM_BUFFER))
560 {
561 ee = ecore_evas_buffer_ecore_evas_parent_get(ee);
562 if (!ee) return 0;
563 xwin = _elm_ee_xwin_get(ee);
564 }
565 else
566 {
567 xwin = _elm_ee_xwin_get(ee);
568 if (!xwin) return 0;
569 }
570 }
571 }
572
573 return xwin;
574}
575
576static Eina_Bool
577_x11_is_uri_type_data(Sel_Manager_Selection *sel EINA_UNUSED, Ecore_X_Event_Selection_Notify *notify)
578{
579 Ecore_X_Selection_Data *data;
580 char *p;
581
582 data = notify->data;
583 sel_debug("data->format is %d %p %p", data->format, notify, data);
584 if (data->content == ECORE_X_SELECTION_CONTENT_FILES) return EINA_TRUE;
585 p = (char *)data->data;
586 if (!p) return EINA_TRUE;
587 sel_debug("Got %s", p);
588 if (strncmp(p, "file:/", 6))
589 {
590 if (*p != '/') return EINA_FALSE;
591 }
592 return EINA_TRUE;
593}
594
595static Sel_Manager_Seat_Selection *
596_x11_sel_manager_seat_selection_init(Efl_Ui_Selection_Manager_Data *pd, unsigned int seat)
597{
598 Sel_Manager_Seat_Selection *seat_sel = NULL;
599 Eina_List *l = NULL;
600
601 EINA_LIST_FOREACH(pd->seat_list, l, seat_sel)
602 {
603 if(seat_sel->seat == seat)
604 break;
605 }
606 if (!seat_sel)
607 {
608 seat_sel = calloc(1, sizeof(Sel_Manager_Seat_Selection));
609 if (!seat_sel)
610 {
611 ERR("Failed to allocate seat");
612 return NULL;
613 }
614 seat_sel->saved_types = calloc(1, sizeof(Saved_Type));
615 seat_sel->seat = seat;
616 seat_sel->pd = pd;
617 pd->seat_list = eina_list_append(pd->seat_list, seat_sel);
618 }
619 if (!seat_sel->sel_list)
620 {
621 //TODO: reduce memory (may be just need one common sel_list)
622 seat_sel->sel_list = calloc(1, (EFL_UI_SELECTION_TYPE_CLIPBOARD + 1) * sizeof(Sel_Manager_Selection));
623 if (!seat_sel->sel_list)
624 {
625 ERR("failed to allocate selection list");
626 return NULL;
627 }
628 _set_selection_list(seat_sel->sel_list, seat_sel);
629 }
630
631 return seat_sel;
632}
633
634static Eina_Bool
635_x11_data_preparer_text(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED,
636 Ecore_X_Event_Selection_Notify *notify,
637 Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED)
638{
639 sel_debug("text data preparer");
640 Ecore_X_Selection_Data *data = notify->data;
641 ddata->format = EFL_UI_SELECTION_FORMAT_TEXT;
642 ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE);
643 ddata->content.len = data->length;
644 return EINA_TRUE;
645}
646
647static Eina_Bool
648_x11_data_preparer_markup(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED,
649 Ecore_X_Event_Selection_Notify *notify,
650 Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED)
651{
652 sel_debug("markup data preparer");
653 Ecore_X_Selection_Data *data = notify->data;
654 ddata->format = EFL_UI_SELECTION_FORMAT_MARKUP;
655 ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE);
656 ddata->content.len = data->length;
657 return EINA_TRUE;
658}
659
660/**
661 * So someone is pasting an image into my entry or widget...
662 */
663static Eina_Bool
664_x11_data_preparer_uri(Sel_Manager_Seat_Selection *seat_sel, Ecore_X_Event_Selection_Notify *notify,
665 Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED)
666{
667 sel_debug("uri data preparer");
668 Ecore_X_Selection_Data *data;
669 Ecore_X_Selection_Data_Files *files;
670 char *p, *stripstr = NULL;
671
672 data = notify->data;
673 sel_debug("data->format is %d %p %p\n", data->format, notify, data);
674 if (data->content == ECORE_X_SELECTION_CONTENT_FILES)
675 {
676 Efreet_Uri *uri;
677 Eina_Strbuf *strbuf;
678 int i;
679
680 sel_debug("got a files list\n");
681 files = notify->data;
682 /*
683 if (files->num_files > 1)
684 {
685 // Don't handle many items <- this makes mr bigglesworth sad :(
686 sel_debug("more then one file: Bailing\n");
687 return EINA_FALSE;
688 }
689 stripstr = p = strdup(files->files[0]);
690 */
691
692 strbuf = eina_strbuf_new();
693 if (!strbuf)
694 return EINA_FALSE;
695
696 for (i = 0; i < files->num_files ; i++)
697 {
698 uri = efreet_uri_decode(files->files[i]);
699 if (uri)
700 {
701 eina_strbuf_append(strbuf, uri->path);
702 efreet_uri_free(uri);
703 }
704 else
705 {
706 eina_strbuf_append(strbuf, files->files[i]);
707 }
708 if (i < (files->num_files - 1))
709 eina_strbuf_append(strbuf, "\n");
710 }
711 stripstr = eina_strbuf_string_steal(strbuf);
712 eina_strbuf_free(strbuf);
713 }
714 else
715 {
716 Efreet_Uri *uri;
717
718 p = (char *)eina_memdup((unsigned char *)data->data, data->length, EINA_TRUE);
719 if (!p) return EINA_FALSE;
720 uri = efreet_uri_decode(p);
721 if (!uri)
722 {
723 /* Is there any reason why we care of URI without scheme? */
724 if (p[0] == '/') stripstr = p;
725 else free(p);
726 }
727 else
728 {
729 free(p);
730 stripstr = strdup(uri->path);
731 efreet_uri_free(uri);
732 }
733 }
734
735 if (!stripstr)
736 {
737 sel_debug("Couldn't find a file\n");
738 return EINA_FALSE;
739 }
740 free(seat_sel->saved_types->imgfile);
741#if 0 // this seems to be broken - we should be handling uri lists as text
742 if (seat_sel->saved_types->textreq)
743 {
744 seat_sel->saved_types->textreq = 0;
745 seat_sel->saved_types->imgfile = stripstr;
746 }
747 else
748#endif
749 {
750 ddata->format = EFL_UI_SELECTION_FORMAT_TEXT;
751 ddata->content.mem = stripstr;
752 ddata->content.len = strlen(stripstr);
753 seat_sel->saved_types->imgfile = NULL;
754 }
755 return EINA_TRUE;
756}
757
758/**
759 * Just received an vcard, either through cut and paste, or dnd.
760 */
761static Eina_Bool
762_x11_data_preparer_vcard(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED,
763 Ecore_X_Event_Selection_Notify *notify,
764 Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info EINA_UNUSED)
765{
766 sel_debug("vcard receive\n");
767 Ecore_X_Selection_Data *data = notify->data;
768 ddata->format = EFL_UI_SELECTION_FORMAT_VCARD;
769 ddata->content.mem = eina_memdup(data->data, data->length, EINA_TRUE);
770 ddata->content.len = data->length;
771 return EINA_TRUE;
772}
773
774static Eina_Bool
775_x11_data_preparer_image(Sel_Manager_Seat_Selection *seat_sel EINA_UNUSED,
776 Ecore_X_Event_Selection_Notify *notify,
777 Efl_Ui_Selection_Data *ddata, Tmp_Info **tmp_info)
778{
779 Ecore_X_Selection_Data *data = notify->data;
780 sel_debug("got a image file!\n");
781 sel_debug("Size if %d\n", data->length);
782
783 ddata->format = EFL_UI_SELECTION_FORMAT_IMAGE;
784 data = notify->data;
785
786 Tmp_Info *tmp = _tempfile_new(data->length);
787 if (!tmp) return EINA_FALSE;
788 memcpy(tmp->map, data->data, data->length);
789 munmap(tmp->map, data->length);
790 ddata->content.mem = strdup(tmp->filename);
791 ddata->content.len = strlen(tmp->filename);
792 *tmp_info = tmp;
793 return EINA_TRUE;
794}
795
796static Eina_Bool
797_x11_win_filter(Eo *manager EINA_UNUSED, Ecore_X_Window xwin)
798{
799 Eo *win;
800 const Eina_List *l;
801
802 EINA_LIST_FOREACH(_elm_win_list, l, win)
803 {
804 if (elm_win_window_id_get(win) == xwin) return EINA_FALSE;
805 }
806 return EINA_TRUE;
807}
808
809/*
810 * Callback to handle a targets response on a selection request:
811 * So pick the format we'd like; and then request it.
812 */
813static Eina_Bool
814_x11_notify_handler_targets(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
815{
816 sel_debug("notify handler targets");
817 Ecore_X_Selection_Data_Targets *targets;
818 Ecore_X_Atom *atom_list;
819 int i, j;
820
821 targets = notify->data;
822 atom_list = (Ecore_X_Atom *)(targets->data.data);
823 for (j = (SELECTION_ATOM_LISTING_ATOMS + 1); j < SELECTION_N_ATOMS; j++)
824 {
825 sel_debug("\t%s %d", pd->atom_list[j].name, pd->atom_list[j].x_atom);
826 if (!(pd->atom_list[j].format & sel->request_format)) continue;
827 for (i = 0; i < targets->data.length; i++)
828 {
829 if ((pd->atom_list[j].x_atom == atom_list[i]) && (pd->atom_list[j].x_data_preparer))
830 {
831 if (j == SELECTION_ATOM_TEXT_URILIST)
832 {
833 if (!_x11_is_uri_type_data(sel, notify)) continue;
834 }
835 sel_debug("Atom %s matches", pd->atom_list[j].name);
836 goto done;
837 }
838 }
839 }
840 sel_debug("Couldn't find anything that matches");
841 return ECORE_CALLBACK_PASS_ON;
842done:
843 sel_debug("Sending request for %s, xwin=%#llx",
844 pd->atom_list[j].name, (unsigned long long)sel->xwin);
845 sel->request(sel->xwin, pd->atom_list[j].name);
846 return ECORE_CALLBACK_PASS_ON;
847}
848
849static Eina_Bool
850_x11_fixes_selection_notify(void *data, int t EINA_UNUSED, void *event)
851{
852 Efl_Ui_Selection_Manager_Data *pd = data;
853 Efl_Ui_Selection_Changed e;
854 Elm_Cnp_Event_Selection_Changed *_e;
855 Ecore_X_Event_Fixes_Selection_Notify *ev = event;
856 Sel_Manager_Seat_Selection *seat_sel;
857 Efl_Ui_Selection_Type type;
858 Sel_Manager_Selection *sel;
859
860 if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON;
861
862 switch (ev->selection)
863 {
864 case ECORE_X_SELECTION_CLIPBOARD:
865 type = EFL_UI_SELECTION_TYPE_CLIPBOARD;
866 break;
867 case ECORE_X_SELECTION_PRIMARY:
868 type = EFL_UI_SELECTION_TYPE_PRIMARY;
869 break;
870 default: return ECORE_CALLBACK_RENEW;
871 }
872 seat_sel = _x11_sel_manager_seat_selection_init(pd, 1);
873 if (!seat_sel) return ECORE_CALLBACK_RENEW;
874 sel = seat_sel->sel_list + type;
875 if (sel->active && (sel->xwin != ev->owner))
876 efl_ui_selection_manager_selection_clear(pd->sel_man, sel->owner, type, seat_sel->seat);
877 e.type = type;
878 e.seat = 1; /* under x11 this is always the default seat */
879 e.exist = !!ev->owner;
880
881 _e = calloc(1, sizeof(Elm_Cnp_Event_Selection_Changed));
882 EINA_SAFETY_ON_NULL_RETURN_VAL(_e, ECORE_CALLBACK_RENEW);
883 _e->type = type;
884 _e->seat_id = 1;
885 _e->exists = e.exist;
886
887 ecore_event_add(ELM_CNP_EVENT_SELECTION_CHANGED, _e, NULL, NULL);
888 efl_event_callback_call(sel->owner, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, &e);
889
890 return ECORE_CALLBACK_RENEW;
891}
892
893/*
894 * Response to a selection notify:
895 * - So we have asked for the selection list.
896 * - If it's the targets list, parse it, and fire of what we want,
897 * else it's the data we want.
898 */
899//NB: x11 does not have seat, use 1 as default
900static Eina_Bool
901_efl_sel_manager_x11_selection_notify(void *udata, int type EINA_UNUSED, void *event)
902{
903 Efl_Ui_Selection_Manager_Data *pd = udata;
904 Ecore_X_Event_Selection_Notify *ev = event;
905 Sel_Manager_Selection *sel;
906 Sel_Manager_Seat_Selection *seat_sel = NULL;
907 int i;
908
909 if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON;
910
911 seat_sel = _sel_manager_seat_selection_get(pd, 1);
912 if (!seat_sel)
913 return EINA_FALSE;
914
915 sel_debug("selection notify callback: %d", ev->selection);
916 switch (ev->selection)
917 {
918 case ECORE_X_SELECTION_PRIMARY:
919 sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_PRIMARY;
920 break;
921 case ECORE_X_SELECTION_SECONDARY:
922 sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_SECONDARY;
923 break;
924 case ECORE_X_SELECTION_XDND:
925 sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_DND;
926 break;
927 case ECORE_X_SELECTION_CLIPBOARD:
928 sel = seat_sel->sel_list + EFL_UI_SELECTION_TYPE_CLIPBOARD;
929 break;
930 default:
931 return ECORE_CALLBACK_PASS_ON;
932 }
933 sel_debug("Target is %s", ev->target);
934 if (!sel->asked) return ECORE_CALLBACK_PASS_ON;
935 sel->asked--;
936
937 if (ev->selection != ECORE_X_SELECTION_XDND &&
938 (!strcmp(ev->target, "TARGETS") || !strcmp(ev->target, "ATOMS")))
939 {
940 _x11_notify_handler_targets(pd, sel, ev);
941 return ECORE_CALLBACK_PASS_ON;
942 }
943 for (i = 0; i < SELECTION_N_ATOMS; i++)
944 {
945 if (!strcmp(ev->target, pd->atom_list[i].name))
946 {
947 if (pd->atom_list[i].x_data_preparer)
948 {
949 Efl_Ui_Selection_Data ddata = { 0 };
950 Tmp_Info *tmp_info = NULL;
951 Eina_Bool success;
952 sel_debug("Found something: %s", pd->atom_list[i].name);
953
954 success = pd->atom_list[i].x_data_preparer(seat_sel, ev, &ddata, &tmp_info);
955 sel_debug("ddata: %s (%zd)", (const char *)ddata.content.mem, ddata.content.len);
956 if ((pd->atom_list[i].format == EFL_UI_SELECTION_FORMAT_IMAGE) &&
957 (seat_sel->saved_types->imgfile))
958 break;
959 if (ev->selection == ECORE_X_SELECTION_XDND)
960 {
961 if (success)
962 {
963 Sel_Manager_Dropable *dropable;
964 Eina_List *l;
965 sel_debug("drag & drop\n");
966 EINA_LIST_FOREACH(pd->drop_list, l, dropable)
967 {
968 if (dropable->obj == sel->request_obj) break;
969 dropable = NULL;
970 }
971 if (dropable)
972 {
973 Drop_Format *df;
974 Eina_Inlist *itr;
975
976 ddata.action = sel->action;
977 if (!dropable->is_container)
978 {
979 sel_debug("normal dnd, not container");
980 ddata.pos = seat_sel->saved_types->pos;
981 }
982 else
983 {
984 sel_debug("Drop on container");
985 Eina_Position2D pos, posret = {0, 0};
986 evas_object_geometry_get(dropable->obj, &pos.x, &pos.y, NULL, NULL);
987 //get item
988 pos = EINA_POSITION2D(seat_sel->saved_types->pos.x + pos.x,
989 seat_sel->saved_types->pos.y + pos.y);
990 Efl_Object *it = NULL;
991 if (dropable->item_func)
992 it = dropable->item_func(dropable->item_func_data,
993 dropable->obj, pos, &posret);
994 ddata.pos = posret;
995 ddata.item = it;
996 }
997 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
998 {
999 if (df->format & dropable->last.format)
1000 {
1001 sel_debug("calling Drop event on: %p", dropable->obj);
1002 efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_DROP, &ddata);
1003 }
1004 }
1005 }
1006 else
1007 {
1008 sel_debug("dnd: has NO dropable");
1009 }
1010 }
1011 /* We have to finish DnD, no matter what */
1012 ecore_x_dnd_send_finished();
1013 }
1014 else if (sel->data_func && success)
1015 {
1016 ddata.pos.x = ddata.pos.y = 0;
1017 sel->data_func(sel->data_func_data, sel->request_obj, &ddata);
1018 }
1019 free((void *)ddata.content.mem);
1020 if (tmp_info) _tmpinfo_free(tmp_info);
1021 }
1022 else sel_debug("Ignored: No handler!");
1023 break;
1024 }
1025 }
1026 return ECORE_CALLBACK_PASS_ON;
1027}
1028
1029static Eina_Bool
1030_x11_selection_clear(void *data, int type EINA_UNUSED, void *event)
1031{
1032 Efl_Ui_Selection_Manager_Data *pd = data;
1033 Ecore_X_Event_Selection_Clear *ev = event;
1034 Sel_Manager_Selection *sel;
1035 Sel_Manager_Seat_Selection *seat_sel = NULL;
1036 Eina_List *l, *l_next;
1037 Sel_Manager_Selection_Lost *sel_lost;
1038 unsigned int i;
1039
1040 if (_x11_win_filter(pd->sel_man, ev->win)) return ECORE_CALLBACK_PASS_ON;
1041
1042 seat_sel = _sel_manager_seat_selection_get(pd, 1);
1043 if (!seat_sel)
1044 return EINA_FALSE;
1045
1046 for (i = EFL_UI_SELECTION_TYPE_PRIMARY; i <= EFL_UI_SELECTION_TYPE_CLIPBOARD; i++)
1047 {
1048 if (seat_sel->sel_list[i].ecore_sel == ev->selection) break;
1049 }
1050 sel_debug("selection %d clear", i);
1051 /* Not me... Don't care */
1052 if (i > EFL_UI_SELECTION_TYPE_CLIPBOARD) return ECORE_CALLBACK_PASS_ON;
1053
1054 sel = seat_sel->sel_list + i;
1055
1056 EINA_LIST_FOREACH_SAFE(seat_sel->sel_lost_list, l, l_next, sel_lost)
1057 {
1058 if ((sel_lost->request == sel->owner) &&
1059 (sel_lost->type == i))
1060 {
1061 sel_debug("resolve the promise: %p", sel_lost->promise);
1062 eina_promise_resolve(sel_lost->promise, eina_value_uint_init(sel_lost->type));
1063 }
1064 }
1065 sel->active = EINA_FALSE;
1066 sel->owner = NULL;
1067
1068 return ECORE_CALLBACK_PASS_ON;
1069}
1070
1071static Eina_Bool
1072_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)
1073{
1074 sel_debug("general converter");
1075 Sel_Manager_Selection *sel = *(Sel_Manager_Selection **)data;
1076 if (sel->format == EFL_UI_SELECTION_FORMAT_NONE)
1077 {
1078 if (data_ret)
1079 {
1080 *data_ret = malloc(sel->data.len * sizeof(char) + 1);
1081 if (!*data_ret) return EINA_FALSE;
1082 memcpy(*data_ret, sel->data.mem, sel->data.len);
1083 ((char**)(data_ret))[0][sel->data.len] = 0;
1084 }
1085 if (size_ret) *size_ret = sel->data.len;
1086 }
1087 else
1088 {
1089 if (sel->data.mem)
1090 {
1091 if (data_ret)
1092 *data_ret = eina_memdup(sel->data.mem, sel->data.len, 1);
1093 if (size_ret) *size_ret = sel->data.len;
1094 }
1095 else
1096 {
1097 if (data_ret) *data_ret = NULL;
1098 if (size_ret) *size_ret = 0;
1099 }
1100 }
1101 return EINA_TRUE;
1102}
1103
1104static Eina_Bool
1105_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)
1106{
1107 int i, count;
1108 Ecore_X_Atom *aret;
1109 Sel_Manager_Selection *sel;
1110 Efl_Ui_Selection_Format seltype;
1111
1112 sel_debug("target converter");
1113 if (!data_ret) return EINA_FALSE;
1114
1115 sel = *(Sel_Manager_Selection **)data;
1116 seltype = sel->format;
1117 Sel_Manager_Seat_Selection *seat_sel = sel->seat_sel;
1118 Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd;
1119
1120 for (i = SELECTION_ATOM_LISTING_ATOMS + 1, count = 0; i < SELECTION_N_ATOMS ; i++)
1121 {
1122 if (seltype & pd->atom_list[i].format) count++;
1123 }
1124 aret = malloc(sizeof(Ecore_X_Atom) * count);
1125 if (!aret) return EINA_FALSE;
1126 for (i = SELECTION_ATOM_LISTING_ATOMS + 1, count = 0; i < SELECTION_N_ATOMS ; i++)
1127 {
1128 if (seltype & pd->atom_list[i].format)
1129 aret[count ++] = pd->atom_list[i].x_atom;
1130 }
1131
1132 *data_ret = aret;
1133 if (typesize) *typesize = 32 /* urk */;
1134 if (ttype) *ttype = ECORE_X_ATOM_ATOM;
1135 if (size_ret) *size_ret = count;
1136 return EINA_TRUE;
1137}
1138
1139static Eina_Bool
1140_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)
1141{
1142 sel_debug("Image converter called");
1143 return EINA_TRUE;
1144}
1145
1146static Eina_Bool
1147_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)
1148{
1149 Sel_Manager_Selection *sel;
1150
1151 sel_debug("Vcard send called");
1152 sel = *(Sel_Manager_Selection **)data;
1153 if (data_ret)
1154 {
1155 char *s;
1156
1157 s = malloc(sel->data.len + 1);
1158 if (!s) return EINA_FALSE;
1159 memcpy(s, sel->data.mem, sel->data.len);
1160 s[sel->data.len] = 0;
1161 *data_ret = s;
1162 }
1163
1164 if (size_ret) *size_ret = sel->data.len;
1165 return EINA_TRUE;
1166}
1167
1168static Eina_Bool
1169_x11_text_converter(char *target, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
1170{
1171 Sel_Manager_Selection *sel;
1172
1173 sel = *(Sel_Manager_Selection **)data;
1174 if (!sel) return EINA_FALSE;
1175
1176 sel_debug("text converter");
1177 if (sel->format == EFL_UI_SELECTION_FORMAT_NONE)
1178 {
1179 sel_debug("none");
1180 if (data_ret)
1181 {
1182 *data_ret = malloc(sel->data.len * sizeof(char) + 1);
1183 if (!*data_ret) return EINA_FALSE;
1184 memcpy(*data_ret, data, sel->data.len);
1185 ((char**)(data_ret))[0][sel->data.len] = 0;
1186 }
1187 if (size_ret) *size_ret = sel->data.len;
1188 return EINA_TRUE;
1189 }
1190
1191 if (!sel->active) return EINA_TRUE;
1192
1193 if ((sel->format & EFL_UI_SELECTION_FORMAT_MARKUP) ||
1194 (sel->format & EFL_UI_SELECTION_FORMAT_HTML))
1195 {
1196 char *tmp = malloc(sel->data.len + 1);
1197 if (tmp)
1198 {
1199 strncpy(tmp, sel->data.mem, sel->data.len);
1200 tmp[sel->data.len] = 0;
1201 *data_ret = _elm_util_mkup_to_text(tmp);
1202 if (size_ret && *data_ret) *size_ret = strlen(*data_ret);
1203 free(tmp);
1204 sel_debug("markup or html: %s", (const char *)*data_ret);
1205 }
1206 else return EINA_FALSE;
1207 }
1208 else if (sel->format & EFL_UI_SELECTION_FORMAT_TEXT)
1209 {
1210 ecore_x_selection_converter_text(target, sel->data.mem,
1211 sel->data.len,
1212 data_ret, size_ret,
1213 ttype, typesize);
1214 sel_debug("text");
1215 }
1216 else if (sel->format & EFL_UI_SELECTION_FORMAT_IMAGE)
1217 {
1218 efl_file_simple_get(sel->request_obj, (const char **)data_ret, NULL);
1219 if (!*data_ret) *data_ret = strdup("No file");
1220 else *data_ret = strdup(*data_ret);
1221
1222 if (!*data_ret)
1223 {
1224 ERR("Failed to allocate memory!");
1225 *size_ret = 0;
1226 return EINA_FALSE;
1227 }
1228
1229 *size_ret = strlen(*data_ret);
1230 }
1231 return EINA_TRUE;
1232}
1233
1234static Eina_Future *
1235_x11_efl_sel_manager_selection_set(Efl_Ui_Selection_Manager_Data *pd, Efl_Object *owner,
1236 Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, Eina_Slice data,
1237 Ecore_X_Window xwin, unsigned int seat)
1238{
1239 Sel_Manager_Seat_Selection *seat_sel;
1240 Sel_Manager_Selection *sel;
1241 Eina_Bool same_win = EINA_FALSE;
1242
1243 seat_sel = _x11_sel_manager_seat_selection_init(pd, seat);
1244 seat_sel->active_type = type;
1245 sel = seat_sel->sel_list + type;
1246 //support 1 app with multiple window, 1 selection manager
1247 if (seat_sel->xwin == xwin)
1248 same_win = EINA_TRUE;
1249 _owner_change_check(pd->sel_man, owner, seat_sel, sel, type, same_win);
1250 seat_sel->xwin = xwin;
1251
1252 sel->owner = owner;
1253 free(sel->data.mem);
1254 sel->xwin = xwin;
1255 sel->data = eina_slice_dup(data);
1256 sel->active = EINA_TRUE;
1257 sel->format = format;
1258
1259 sel->set(xwin, &sel, sizeof(Sel_Manager_Selection *));
1260 sel_debug("data: %p (%zu)", &sel, sizeof(Sel_Manager_Selection *));
1261
1262 return _update_sel_lost_list(owner, type, seat_sel);
1263}
1264
1265static void
1266_x11_efl_sel_manager_selection_get(const Efl_Object *request, Efl_Ui_Selection_Manager_Data *pd,
1267 Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format,
1268 void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb,
1269 Ecore_X_Window xwin, unsigned int seat)
1270{
1271 Sel_Manager_Seat_Selection *seat_sel;
1272 Sel_Manager_Selection *sel;;
1273
1274 sel_debug("request: %p, seat: %u, type: %d, format: %d", request, seat, type, format);
1275 seat_sel = _sel_manager_seat_selection_init(pd, seat);
1276 sel = seat_sel->sel_list + type;
1277 sel->request_obj = (Efl_Object *)request;
1278 sel->data_func_data = data_func_data;
1279 sel->data_func = data_func;
1280 sel->data_func_free_cb = data_func_free_cb;
1281 sel->request_format = format;
1282 sel->xwin = xwin;
1283
1284 if (sel->active)
1285 {
1286 if (sel->data.mem &&
1287 ((format == sel->format) || (xwin == 0)))
1288 {
1289 sel_debug("use local data");
1290 Efl_Ui_Selection_Data seldata;
1291
1292 seldata.content.mem = sel->data.mem;
1293 seldata.content.len = sel->data.len;
1294 seldata.pos.x = seldata.pos.y = 0;
1295 seldata.format = sel->format;
1296 sel->data_func(sel->data_func_data, sel->request_obj, &seldata);
1297 return;
1298 }
1299 }
1300
1301 sel->asked = 2;
1302 sel->request(xwin, ECORE_X_SELECTION_TARGET_TARGETS);
1303}
1304
1305static void
1306_x11_win_rotation_changed_cb(void *data, const Efl_Event *event)
1307{
1308 Evas_Object *win = data;
1309 int rot = elm_win_rotation_get(event->object);
1310 elm_win_rotation_set(win, rot);
1311}
1312
1313static Eina_Bool
1314_x11_drag_mouse_up(void *data, int etype EINA_UNUSED, void *event)
1315{
1316 Sel_Manager_Seat_Selection *seat_sel = data;
1317 Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd;
1318 Ecore_X_Window xwin = seat_sel->xwin;
1319 Ecore_Event_Mouse_Button *ev = event;
1320
1321 if ((ev->buttons == 1) &&
1322 (ev->event_window == xwin))
1323 {
1324 Eina_Bool have_drop_list = EINA_FALSE;
1325 Eina_List *l;
1326 Sel_Manager_Dropable *dropable;
1327
1328 ecore_x_pointer_ungrab();
1329 ELM_SAFE_FREE(seat_sel->mouse_up_handler, ecore_event_handler_del);
1330 ELM_SAFE_FREE(seat_sel->dnd_status_handler, ecore_event_handler_del);
1331 ecore_x_dnd_self_drop();
1332
1333 sel_debug("mouse up, xwin=%#llx\n", (unsigned long long)xwin);
1334
1335 EINA_LIST_FOREACH(pd->drop_list, l, dropable)
1336 {
1337 if (xwin == _x11_xwin_get(dropable->obj))
1338 {
1339 have_drop_list = EINA_TRUE;
1340 break;
1341 }
1342 }
1343 if (!have_drop_list) ecore_x_dnd_aware_set(xwin, EINA_FALSE);
1344 efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_DONE, NULL);
1345 if (seat_sel->drag_win)
1346 {
1347 if (seat_sel->drag_obj)
1348 {
1349 if (elm_widget_is(seat_sel->drag_obj))
1350 {
1351 Evas_Object *win = elm_widget_top_get(seat_sel->drag_obj);
1352 if (win && efl_isa(win, EFL_UI_WIN_CLASS))
1353 efl_event_callback_del(win, EFL_UI_WIN_EVENT_WIN_ROTATION_CHANGED,
1354 _x11_win_rotation_changed_cb, seat_sel->drag_win);
1355 }
1356 }
1357
1358 if (!seat_sel->accept)
1359 { /* Commit animation when drag cancelled */
1360 /* Record final position of dragwin, then do animation */
1361 ecore_evas_animator_timeline_add(seat_sel->drag_win, 0.3,
1362 _drag_cancel_animate, seat_sel);
1363 }
1364 else
1365 { /* No animation drop was committed */
1366 Ecore_X_Window xdragwin = _x11_xwin_get(seat_sel->drag_win);
1367 ecore_x_window_ignore_set(xdragwin, 0);
1368 evas_object_del(seat_sel->drag_win);
1369 seat_sel->drag_win = NULL;
1370 sel_debug("deleted drag_win");
1371 }
1372 }
1373
1374 seat_sel->drag_obj = NULL;
1375 seat_sel->accept = EINA_FALSE;
1376 }
1377 return EINA_TRUE;
1378}
1379
1380static void
1381_x11_drag_move(void *data, Ecore_X_Xdnd_Position *pos)
1382{
1383 Sel_Manager_Seat_Selection *seat_sel = data;
1384 Efl_Dnd_Drag_Pos dp;
1385
1386 evas_object_move(seat_sel->drag_win,
1387 pos->position.x - seat_sel->drag_pos.x,
1388 pos->position.y - seat_sel->drag_pos.y);
1389 seat_sel->drag_win_end.x = pos->position.x - seat_sel->drag_pos.x;
1390 seat_sel->drag_win_end.y = pos->position.y - seat_sel->drag_pos.y;
1391 sel_debug("dragevas: %p -> %p\n",
1392 seat_sel->drag_obj,
1393 evas_object_evas_get(seat_sel->drag_obj));
1394 dp.pos.x = pos->position.x;
1395 dp.pos.y = pos->position.y;
1396 dp.action = seat_sel->drag_action;
1397 //for drag side
1398 efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_POS, &dp);
1399}
1400
1401static void
1402_x11_drag_target_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED)
1403{
1404 Sel_Manager_Seat_Selection *seat_sel = data;
1405 Sel_Manager_Selection *sel = &seat_sel->sel_list[seat_sel->active_type];
1406
1407 if (seat_sel->drag_obj == obj)
1408 {
1409 sel->request_obj = NULL;
1410 seat_sel->drag_obj = NULL;
1411 }
1412}
1413
1414static Eina_Bool
1415_x11_dnd_status(void *data, int etype EINA_UNUSED, void *ev)
1416{
1417 Sel_Manager_Seat_Selection *seat_sel = data;
1418 Ecore_X_Event_Xdnd_Status *status = ev;
1419
1420 seat_sel->accept = EINA_FALSE;
1421
1422 /* Only thing we care about: will accept */
1423 if ((status) && (status->will_accept))
1424 {
1425 sel_debug("Will accept\n");
1426 seat_sel->accept = EINA_TRUE;
1427 }
1428 /* Won't accept */
1429 else
1430 {
1431 sel_debug("Won't accept accept\n");
1432 }
1433 efl_event_callback_call(seat_sel->drag_obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, &seat_sel->accept);
1434
1435 return EINA_TRUE;
1436}
1437
1438static void
1439_x11_efl_sel_manager_drag_start(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Manager_Data *pd,
1440 Efl_Object *drag_obj, Efl_Ui_Selection_Format format,
1441 Eina_Slice data, Efl_Ui_Selection_Action action,
1442 void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func,
1443 Eina_Free_Cb icon_func_free_cb EINA_UNUSED,
1444 Ecore_X_Window xwin, unsigned int seat)
1445{
1446 Ecore_X_Window xdragwin;
1447 Sel_Manager_Seat_Selection *seat_sel;
1448 Sel_Manager_Selection *sel;
1449 Ecore_Evas *ee;
1450 int x, y, x2 = 0, y2 = 0, x3, y3;
1451 Evas_Object *icon = NULL;
1452 int w = 0, h = 0;
1453 int ex, ey, ew, eh;
1454 Ecore_X_Atom actx;
1455 int i;
1456 int xr, yr, rot;
1457
1458 seat_sel = _x11_sel_manager_seat_selection_init(pd, seat);
1459 if (!seat_sel) return;
1460 seat_sel->active_type = EFL_UI_SELECTION_TYPE_DND;
1461
1462 sel = &seat_sel->sel_list[seat_sel->active_type];
1463 ecore_x_dnd_types_set(xwin, NULL, 0);
1464 for (i = SELECTION_ATOM_LISTING_ATOMS + 1; i < SELECTION_N_ATOMS; i++)
1465 {
1466 if (format == EFL_UI_SELECTION_FORMAT_TARGETS || (pd->atom_list[i].format & format))
1467 {
1468 ecore_x_dnd_type_set(xwin, pd->atom_list[i].name, EINA_TRUE);
1469 sel_debug("set dnd type: %s\n", pd->atom_list[i].name);
1470 }
1471 }
1472
1473 sel->active = EINA_TRUE;
1474 sel->request_obj = drag_obj;
1475 sel->format = format;
1476 if (sel->data.mem) free(sel->data.mem);
1477 sel->data = eina_slice_dup(data);
1478 sel->action = action;
1479 seat_sel->drag_obj = drag_obj;
1480 seat_sel->drag_action = action;
1481 seat_sel->xwin = xwin;
1482
1483 evas_object_event_callback_add(drag_obj, EVAS_CALLBACK_DEL,
1484 _x11_drag_target_del, seat_sel);
1485 /* TODO BUG: should increase dnd-awareness, in case it's drop target as well. See _x11_drag_mouse_up() */
1486 ecore_x_dnd_aware_set(xwin, EINA_TRUE);
1487 ecore_x_dnd_callback_pos_update_set(_x11_drag_move, seat_sel);
1488 ecore_x_dnd_self_begin(xwin, (unsigned char *)sel, sizeof(Sel_Manager_Selection));
1489 actx = _x11_dnd_action_rev_map(seat_sel->drag_action);
1490 ecore_x_dnd_source_action_set(actx);
1491 ecore_x_pointer_grab(xwin);
1492 seat_sel->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
1493 _x11_drag_mouse_up, seat_sel);
1494 seat_sel->dnd_status_handler = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
1495 _x11_dnd_status, seat_sel);
1496 seat_sel->drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND);
1497 elm_win_alpha_set(seat_sel->drag_win, EINA_TRUE);
1498 elm_win_override_set(seat_sel->drag_win, EINA_TRUE);
1499 xdragwin = _x11_xwin_get(seat_sel->drag_win);
1500 ecore_x_window_ignore_set(xdragwin, 1);
1501
1502 /* dragwin has to be rotated as the main window is */
1503 if (elm_widget_is(drag_obj))
1504 {
1505 Evas_Object *win = elm_widget_top_get(drag_obj);
1506 if (win && efl_isa(win, EFL_UI_WIN_CLASS))
1507 {
1508 elm_win_rotation_set(seat_sel->drag_win, elm_win_rotation_get(win));
1509 efl_event_callback_add(win, EFL_UI_WIN_EVENT_WIN_ROTATION_CHANGED,
1510 _x11_win_rotation_changed_cb, seat_sel->drag_win);
1511 }
1512 }
1513
1514 if (icon_func)
1515 {
1516 Eina_Position2D off;
1517
1518 icon = icon_func(icon_func_data, seat_sel->drag_win, drag_obj, &off);
1519 if (icon)
1520 {
1521 x2 = off.x;
1522 y2 = off.y;
1523 evas_object_geometry_get(icon, NULL, NULL, &w, &h);
1524 }
1525 }
1526 else
1527 {
1528 icon = elm_icon_add(seat_sel->drag_win);
1529 evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1530 // need to resize
1531 }
1532 elm_win_resize_object_add(seat_sel->drag_win, icon);
1533
1534 /* Position subwindow appropriately */
1535 ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_obj));
1536 ecore_evas_geometry_get(ee, &ex, &ey, &ew, &eh);
1537 evas_object_resize(seat_sel->drag_win, w, h);
1538
1539 evas_object_show(icon);
1540 evas_object_show(seat_sel->drag_win);
1541 evas_pointer_canvas_xy_get(evas_object_evas_get(drag_obj), &x3, &y3);
1542
1543 rot = ecore_evas_rotation_get(ee);
1544 switch (rot)
1545 {
1546 case 90:
1547 xr = y3;
1548 yr = ew - x3;
1549 seat_sel->drag_pos.x = y3 - y2;
1550 seat_sel->drag_pos.y = x3 - x2;
1551 break;
1552 case 180:
1553 xr = ew - x3;
1554 yr = eh - y3;
1555 seat_sel->drag_pos.x = x3 - x2;
1556 seat_sel->drag_pos.y = y3 - y2;
1557 break;
1558 case 270:
1559 xr = eh - y3;
1560 yr = x3;
1561 seat_sel->drag_pos.x = y3 - y2;
1562 seat_sel->drag_pos.y = x3 - x2;
1563 break;
1564 default:
1565 xr = x3;
1566 yr = y3;
1567 seat_sel->drag_pos.x = x3 - x2;
1568 seat_sel->drag_pos.y = y3 - y2;
1569 break;
1570 }
1571 x = ex + xr - seat_sel->drag_pos.x;
1572 y = ey + yr - seat_sel->drag_pos.y;
1573 evas_object_move(seat_sel->drag_win, x, y);
1574 seat_sel->drag_win_start = EINA_POSITION2D(x, y);
1575 seat_sel->drag_win_end = EINA_POSITION2D(x, y);
1576}
1577
1578static void
1579_x11_dnd_dropable_handle(Efl_Ui_Selection_Manager_Data *pd, Sel_Manager_Dropable *dropable, Eina_Position2D pos, Efl_Ui_Selection_Action action)
1580{
1581 Sel_Manager_Dropable *d, *last_dropable = NULL;
1582 Eina_List *l;
1583 Eina_Inlist *itr;
1584
1585 EINA_LIST_FOREACH(pd->drop_list, l, d)
1586 {
1587 if (d->last.in)
1588 {
1589 last_dropable = d;
1590 break;
1591 }
1592 }
1593 if (last_dropable)
1594 {
1595 if (last_dropable == dropable) // same
1596 {
1597 Evas_Coord ox, oy;
1598 Drop_Format *df;
1599
1600 sel_debug("same obj dropable %p\n", dropable->obj);
1601 evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL);
1602 Efl_Dnd_Drag_Pos pos_data;
1603 if (!dropable->is_container)
1604 {
1605 pos_data.pos = EINA_POSITION2D(pos.x - ox, pos.y - oy);
1606 pos_data.item = NULL;
1607 }
1608 else
1609 {
1610 Eina_Position2D posret = {0, 0};
1611 Efl_Object *it = NULL;
1612
1613 if (dropable->item_func)
1614 it = dropable->item_func(dropable->item_func_data, dropable->obj,
1615 pos, &posret);
1616 pos_data.pos = posret;
1617 pos_data.item = it;
1618 }
1619 pos_data.format = dropable->last.format;
1620 pos_data.action = action;
1621 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
1622 {
1623 if (df->format & dropable->last.format)
1624 efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data);
1625 }
1626 }
1627 else
1628 {
1629 if (dropable) // leave last obj and enter new one
1630 {
1631 sel_debug("leave %p\n", last_dropable->obj);
1632 sel_debug("enter %p\n", dropable->obj);
1633 last_dropable->last.in = EINA_FALSE;
1634 last_dropable->last.type = NULL;
1635 dropable->last.in = EINA_TRUE;
1636
1637 Drop_Format *df;
1638 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
1639 {
1640 if (df->format &dropable->last.format)
1641 efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL);
1642 }
1643 EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df)
1644 {
1645 if (df->format & last_dropable->last.format)
1646 efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL);
1647 }
1648 }
1649 else // leave last obj
1650 {
1651 sel_debug("leave %p\n", last_dropable->obj);
1652 last_dropable->last.in = EINA_FALSE;
1653 last_dropable->last.type = NULL;
1654
1655 Drop_Format *df;
1656 EINA_INLIST_FOREACH_SAFE(last_dropable->format_list, itr, df)
1657 {
1658 if (df->format & last_dropable->last.format)
1659 efl_event_callback_call(last_dropable->obj, EFL_UI_DND_EVENT_DRAG_LEAVE, NULL);
1660 }
1661 }
1662 }
1663 }
1664 else
1665 {
1666 if (dropable) // enter new obj
1667 {
1668 Evas_Coord ox, oy;
1669
1670 sel_debug("enter %p\n", dropable->obj);
1671 evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL);
1672 dropable->last.in = EINA_TRUE;
1673
1674 Drop_Format *df;
1675 Efl_Dnd_Drag_Pos pos_data;
1676 if (!dropable->is_container)
1677 {
1678 pos_data.pos = EINA_POSITION2D(pos.x - ox, pos.y - oy);
1679 pos_data.item = NULL;
1680 }
1681 else
1682 {
1683 Eina_Position2D posret = {0, 0};
1684 Efl_Object *it = NULL;
1685 if (dropable->item_func)
1686 it = dropable->item_func(dropable->item_func_data, dropable->obj,
1687 pos, &posret);
1688 pos_data.pos = posret;
1689 pos_data.item = it;
1690 }
1691 pos_data.format = dropable->last.format;
1692 pos_data.action = action;
1693 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
1694 {
1695 if (df->format & dropable->last.format)
1696 {
1697 efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_ENTER, NULL);
1698 efl_event_callback_call(dropable->obj, EFL_UI_DND_EVENT_DRAG_POS, &pos_data);
1699 }
1700 }
1701 }
1702 else
1703 {
1704 sel_debug("both dropable & last_dropable are null\n");
1705 }
1706 }
1707}
1708
1709static Sel_Manager_Dropable *
1710_x11_dropable_find(Efl_Ui_Selection_Manager_Data *pd, Ecore_X_Window win)
1711{
1712 Eina_List *l;
1713 Sel_Manager_Dropable *dropable;
1714
1715 if (!pd->drop_list) return NULL;
1716 EINA_LIST_FOREACH(pd->drop_list, l, dropable)
1717 {
1718 if (_x11_xwin_get(dropable->obj) == win) return dropable;
1719 }
1720 return NULL;
1721}
1722
1723static Evas *
1724_x11_evas_get_from_xwin(Efl_Ui_Selection_Manager_Data *pd, Ecore_X_Window win)
1725{
1726 /* Find the Evas connected to the window */
1727 Sel_Manager_Dropable *dropable = _x11_dropable_find(pd, win);
1728 return dropable ? evas_object_evas_get(dropable->obj) : NULL;
1729}
1730
1731static Efl_Ui_Selection_Action
1732_x11_dnd_action_map(Ecore_X_Atom action)
1733{
1734 Efl_Ui_Selection_Action act = EFL_UI_SELECTION_ACTION_UNKNOWN;
1735
1736 if (action == ECORE_X_ATOM_XDND_ACTION_COPY)
1737 act = EFL_UI_SELECTION_ACTION_COPY;
1738 else if (action == ECORE_X_ATOM_XDND_ACTION_MOVE)
1739 act = EFL_UI_SELECTION_ACTION_MOVE;
1740 else if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE)
1741 act = EFL_UI_SELECTION_ACTION_PRIVATE;
1742 else if (action == ECORE_X_ATOM_XDND_ACTION_ASK)
1743 act = EFL_UI_SELECTION_ACTION_ASK;
1744 else if (action == ECORE_X_ATOM_XDND_ACTION_LIST)
1745 act = EFL_UI_SELECTION_ACTION_LIST;
1746 else if (action == ECORE_X_ATOM_XDND_ACTION_LINK)
1747 act = EFL_UI_SELECTION_ACTION_LINK;
1748 else if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION)
1749 act = EFL_UI_SELECTION_ACTION_DESCRIPTION;
1750 return act;
1751}
1752
1753static Ecore_X_Atom
1754_x11_dnd_action_rev_map(Efl_Ui_Selection_Action action)
1755{
1756 Ecore_X_Atom act = ECORE_X_ATOM_XDND_ACTION_MOVE;
1757
1758 if (action == EFL_UI_SELECTION_ACTION_COPY)
1759 act = ECORE_X_ATOM_XDND_ACTION_COPY;
1760 else if (action == EFL_UI_SELECTION_ACTION_MOVE)
1761 act = ECORE_X_ATOM_XDND_ACTION_MOVE;
1762 else if (action == EFL_UI_SELECTION_ACTION_PRIVATE)
1763 act = ECORE_X_ATOM_XDND_ACTION_PRIVATE;
1764 else if (action == EFL_UI_SELECTION_ACTION_ASK)
1765 act = ECORE_X_ATOM_XDND_ACTION_ASK;
1766 else if (action == EFL_UI_SELECTION_ACTION_LIST)
1767 act = ECORE_X_ATOM_XDND_ACTION_LIST;
1768 else if (action == EFL_UI_SELECTION_ACTION_LINK)
1769 act = ECORE_X_ATOM_XDND_ACTION_LINK;
1770 else if (action == EFL_UI_SELECTION_ACTION_DESCRIPTION)
1771 act = ECORE_X_ATOM_XDND_ACTION_DESCRIPTION;
1772 return act;
1773}
1774
1775static Eina_Bool
1776_x11_dnd_enter(void *data, int etype EINA_UNUSED, void *ev)
1777{
1778 Sel_Manager_Seat_Selection *seat_sel = data;
1779 Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd;
1780 Ecore_X_Event_Xdnd_Enter *enter = ev;
1781 Sel_Manager_Dropable *dropable;
1782 int i;
1783
1784 sel_debug("In");
1785 if (!enter) return EINA_TRUE;
1786 dropable = _x11_dropable_find(pd, enter->win);
1787 if (dropable)
1788 {
1789 sel_debug("Enter %x\n", enter->win);
1790 }
1791 /* Skip it */
1792 sel_debug("enter types=%p (%d)\n", enter->types, enter->num_types);
1793 if ((!enter->num_types) || (!enter->types)) return EINA_TRUE;
1794
1795 sel_debug("Types\n");
1796 seat_sel->saved_types->ntypes = enter->num_types;
1797 free(seat_sel->saved_types->types);
1798 seat_sel->saved_types->types = malloc(sizeof(char *) * enter->num_types);
1799 if (!seat_sel->saved_types->types) return EINA_FALSE;
1800
1801 for (i = 0; i < enter->num_types; i++)
1802 {
1803 seat_sel->saved_types->types[i] = eina_stringshare_add(enter->types[i]);
1804 sel_debug("Type is %s %p %p\n", enter->types[i],
1805 seat_sel->saved_types->types[i], pd->text_uri);
1806 if (seat_sel->saved_types->types[i] == pd->text_uri)
1807 {
1808 /* Request it, so we know what it is */
1809 sel_debug("Sending uri request\n");
1810 seat_sel->saved_types->textreq = 1;
1811 ELM_SAFE_FREE(seat_sel->saved_types->imgfile, free);
1812 ecore_x_selection_xdnd_request(enter->win, pd->text_uri);
1813 }
1814 }
1815
1816 /* FIXME: Find an object and make it current */
1817 return EINA_TRUE;
1818}
1819
1820static Eina_Bool
1821_x11_dnd_position(void *data, int etype EINA_UNUSED, void *ev)
1822{
1823 Sel_Manager_Seat_Selection *seat_sel = data;
1824 Efl_Ui_Selection_Manager_Data *pd = seat_sel->pd;
1825 Ecore_X_Event_Xdnd_Position *xpos = ev;
1826 Ecore_X_Rectangle rect = { 0, 0, 0, 0 };
1827 Sel_Manager_Dropable *dropable;
1828 Efl_Ui_Selection_Action act;
1829
1830 sel_debug("In");
1831 /* Need to send a status back */
1832 /* FIXME: Should check I can drop here */
1833 /* FIXME: Should highlight widget */
1834 dropable = _x11_dropable_find(pd, xpos->win);
1835 if (dropable)
1836 {
1837 Evas_Coord ox = 0, oy = 0;
1838 Eina_Position2D pos;
1839
1840 act = _x11_dnd_action_map(xpos->action);
1841 pos.x = xpos->position.x;
1842 pos.y = xpos->position.y;
1843 _dropable_coords_adjust(dropable, &pos);
1844 Evas *evas = _x11_evas_get_from_xwin(pd, xpos->win);
1845 Eina_List *dropable_list = evas ? _dropable_list_geom_find(pd, evas, pos.x, pos.y) : NULL;
1846 /* check if there is dropable (obj) can accept this drop */
1847 if (dropable_list)
1848 {
1849 Efl_Ui_Selection_Format saved_format = _dnd_types_to_format(pd, seat_sel->saved_types->types, seat_sel->saved_types->ntypes);
1850 Eina_List *l;
1851 Eina_Bool found = EINA_FALSE;
1852
1853 EINA_LIST_FOREACH(dropable_list, l, dropable)
1854 {
1855 Drop_Format *df;
1856 Eina_Inlist *itr;
1857 EINA_INLIST_FOREACH_SAFE(dropable->format_list, itr, df)
1858 {
1859 Efl_Ui_Selection_Format common_fmt = saved_format & df->format;
1860 if (common_fmt)
1861 {
1862 //We found a target that can accept this type of data
1863 int i, min_index = SELECTION_N_ATOMS;
1864 //We have to find the first atom that corresponds to one
1865 //of the supported data types.
1866 for (i = 0; i < seat_sel->saved_types->ntypes; i++)
1867 {
1868 Sel_Manager_Atom *atom = eina_hash_find(pd->type_hash, seat_sel->saved_types->types[i]);
1869 if (atom && (atom->format & common_fmt))
1870 {
1871 int atom_idx = (atom - pd->atom_list);
1872 if (min_index > atom_idx) min_index = atom_idx;
1873 }
1874 }
1875 if (min_index != SELECTION_N_ATOMS)
1876 {
1877 sel_debug("Found atom %s\n", pd->atom_list[min_index].name);
1878 found = EINA_TRUE;
1879 dropable->last.type = pd->atom_list[min_index].name;
1880 dropable->last.format = common_fmt;
1881 break;
1882 }
1883 }
1884 }
1885 if (found) break;
1886 }
1887 if (found)
1888 {
1889 Sel_Manager_Dropable *d = NULL;
1890 Eina_Rectangle inter_rect = {0, 0, 0, 0};
1891 int idx = 0;
1892 EINA_LIST_FOREACH(dropable_list, l, d)
1893 {
1894 if (idx == 0)
1895 {
1896 evas_object_geometry_get(d->obj, &inter_rect.x, &inter_rect.y,
1897 &inter_rect.w, &inter_rect.h);
1898 }
1899 else
1900 {
1901 Eina_Rectangle cur_rect;
1902 evas_object_geometry_get(d->obj, &cur_rect.x, &cur_rect.y,
1903 &cur_rect.w, &cur_rect.h);
1904 if (!eina_rectangle_intersection(&inter_rect, &cur_rect)) continue;
1905 }
1906 idx++;
1907 }
1908 rect.x = inter_rect.x;
1909 rect.y = inter_rect.y;
1910 rect.width = inter_rect.w;
1911 rect.height = inter_rect.h;
1912 ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, xpos->action);
1913 sel_debug("dnd position %i %i %p\n", pos.x - ox, pos.y - oy, dropable);
1914 pos.x = pos.x - ox;
1915 pos.y = pos.y - oy;
1916 _x11_dnd_dropable_handle(pd, dropable, pos, act);
1917 // CCCCCCC: call dnd exit on last obj if obj != last
1918 // CCCCCCC: call drop position on obj
1919 }
1920 else
1921 {
1922 //if not: send false status
1923 ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, xpos->action);