Initialize Tizen 2.3
[framework/uifw/elementary.git] / wearable / src / lib / elm_cnp.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 #include <Elementary.h>
5 #include "elm_priv.h"
6 #ifdef HAVE_MMAN_H
7 # include <sys/mman.h>
8 #endif
9
10 // common stuff
11 enum
12 {
13    CNP_ATOM_TARGETS = 0,
14    CNP_ATOM_ATOM,
15    CNP_ATOM_LISTING_ATOMS = CNP_ATOM_ATOM,
16    CNP_ATOM_text_uri,
17    CNP_ATOM_text_urilist,
18    CNP_ATOM_text_x_vcard,
19    CNP_ATOM_image_png,
20    CNP_ATOM_image_jpeg,
21    CNP_ATOM_image_bmp,
22    CNP_ATOM_image_gif,
23    CNP_ATOM_image_tiff,
24    CNP_ATOM_image_svg,
25    CNP_ATOM_image_xpm,
26    CNP_ATOM_image_tga,
27    CNP_ATOM_image_ppm,
28    CNP_ATOM_XELM,
29 //   CNP_ATOM_text_html_utf8,
30 //   CNP_ATOM_text_html,
31    CNP_ATOM_UTF8STRING,
32    CNP_ATOM_STRING,
33    CNP_ATOM_COMPOUND_TEXT,
34    CNP_ATOM_TEXT,
35    CNP_ATOM_text_plain_utf8,
36    CNP_ATOM_text_plain,
37
38    CNP_N_ATOMS,
39 };
40
41 typedef struct _Tmp_Info      Tmp_Info;
42 typedef struct _Saved_Type    Saved_Type;
43 typedef struct _Cnp_Escape    Cnp_Escape;
44 typedef struct _Dropable      Dropable;
45 static Eina_Bool doaccept = EINA_FALSE;
46
47 struct _Tmp_Info
48 {
49    char *filename;
50    void *map;
51    int   fd;
52    int   len;
53 };
54
55 struct _Saved_Type
56 {
57    const char  **types;
58    char         *imgfile;
59    int           ntypes;
60    int           x, y;
61    Eina_Bool     textreq: 1;
62 };
63
64 struct _Cnp_Escape
65 {
66    const char *escape;
67    const char *value;
68 };
69
70 struct _Dropable
71 {
72    Evas_Object    *obj;
73    /* FIXME: Cache window */
74    Elm_Sel_Format  types;
75    Elm_Drag_State  entercb;
76    Elm_Drag_State  leavecb;
77    Elm_Drag_Pos    poscb;
78    Elm_Drop_Cb     dropcb;
79    void           *enterdata;
80    void           *leavedata;
81    void           *posdata;
82    void           *cbdata;
83    struct {
84       Evas_Coord   x, y;
85       Eina_Bool    in : 1;
86    } last;
87 };
88
89 struct _Item_Container_Drop_Info
90 {  /* Info kept for containers to support drop */
91    Evas_Object *obj;
92    Elm_Xy_Item_Get_Cb itemgetcb;
93    Elm_Drop_Item_Container_Cb dropcb;
94    Elm_Drag_Item_Container_Pos poscb;
95 };
96 typedef struct _Item_Container_Drop_Info Item_Container_Drop_Info;
97
98 struct _Anim_Icon
99 {
100    int start_x;
101    int start_y;
102    int start_w;
103    int start_h;
104    Evas_Object *o;
105 };
106 typedef struct _Anim_Icon Anim_Icon;
107
108 struct _Item_Container_Drag_Info
109 {  /* Info kept for containers to support drag */
110    Evas_Object *obj;
111    Ecore_Timer *tm;    /* When this expires, start drag */
112    double anim_tm;  /* Time period to set tm         */
113    double tm_to_drag;  /* Time period to set tm         */
114    Elm_Xy_Item_Get_Cb itemgetcb;
115    Elm_Item_Container_Data_Get_Cb data_get;
116
117    Evas_Coord x_down;  /* Mouse down x cord when drag starts */
118    Evas_Coord y_down;  /* Mouse down y cord when drag starts */
119
120    /* Some extra information needed to impl default anim */
121    Evas *e;
122    Eina_List *icons;   /* List of icons to animate (Anim_Icon) */
123    int final_icon_w; /* We need the w and h of the final icon for the animation */
124    int final_icon_h;
125    Ecore_Animator *ea;
126
127    Elm_Drag_User_Info user_info;
128 };
129 typedef struct _Item_Container_Drag_Info Item_Container_Drag_Info;
130
131 static int _elm_cnp_init_count = 0;
132 /* Stringshared, so I can just compare pointers later */
133 static const char *text_uri;
134 /* Data for DND in progress */
135 static Saved_Type savedtypes =  { NULL, NULL, 0, 0, 0, EINA_FALSE };
136
137 /* TODO BUG: should NEVER have these as globals! They should be per context (window). */
138 static Elm_Drag_Pos dragposcb = NULL;
139 static Elm_Drag_Accept dragacceptcb = NULL;
140 static Elm_Drag_State dragdonecb = NULL;
141 static void *dragposdata = NULL;
142 static void *dragacceptdata = NULL;
143 static void *dragdonedata = NULL;
144 static Evas_Object *dragwidget = NULL;
145 static Elm_Xdnd_Action dragaction = ELM_XDND_ACTION_UNKNOWN;
146
147 static Eina_List *cont_drop_tg = NULL; /* List of Item_Container_Drop_Info */
148 static Eina_List *cont_drag_tg = NULL; /* List of Item_Container_Drag_Info */
149
150 static void _cont_obj_mouse_up( void *data, Evas *e, Evas_Object *obj, void *event_info);
151 static void _cont_obj_mouse_move( void *data, Evas *e, Evas_Object *obj, void *event_info);
152
153 /* Drag & Drop functions */
154 /* FIXME: Way too many globals */
155 static Eina_List *drops = NULL;
156 static Evas_Object *dragwin = NULL;
157 static int dragwin_x_start, dragwin_y_start;
158 static int dragwin_x_end, dragwin_y_end;
159 static int _dragx = 0, _dragy = 0;
160 static Ecore_Event_Handler *handler_pos = NULL;
161 static Ecore_Event_Handler *handler_drop = NULL;
162 static Ecore_Event_Handler *handler_enter = NULL;
163 static Ecore_Event_Handler *handler_status = NULL;
164 static Ecore_Event_Handler *handler_leave = NULL;
165 static Ecore_Event_Handler *handler_up = NULL;
166
167 static Tmp_Info  *_tempfile_new      (int size);
168 static int        _tmpinfo_free      (Tmp_Info *tmp);
169 static Eina_Bool  _pasteimage_append (char *file, Evas_Object *entry);
170 static void       _entry_insert_filter(Evas_Object *entry, char *str); // TIZEN ONLY
171
172 #define DEBUGON 1
173 #ifdef DEBUGON
174 # define cnp_debug(x...) fprintf(stderr, __FILE__": " x)
175 #else
176 # define cnp_debug(x...) do { } while (0)
177 #endif
178
179 // x11 specific stuff
180 ////////////////////////////////////////////////////////////////////////////
181 #ifdef HAVE_ELEMENTARY_X
182 #define ARRAYINIT(foo)  [foo] =
183
184 typedef struct _X11_Cnp_Selection X11_Cnp_Selection;
185 typedef struct _X11_Cnp_Atom      X11_Cnp_Atom;
186
187 typedef Eina_Bool (*X11_Converter_Fn_Cb)     (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
188 typedef int       (*X11_Response_Handler_Cb) (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
189 typedef int       (*X11_Notify_Handler_Cb)   (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
190
191 struct _X11_Cnp_Selection
192 {
193    const char        *debug;
194    Evas_Object       *widget;
195    char              *selbuf;
196    Evas_Object       *requestwidget;
197    void              *udata;
198    Elm_Sel_Format     requestformat;
199    Elm_Drop_Cb        datacb;
200    Eina_Bool        (*set)     (Ecore_X_Window, const void *data, int size);
201    Eina_Bool        (*clear)   (void);
202    void             (*request) (Ecore_X_Window, const char *target);
203    Elm_Selection_Loss_Cb  loss_cb;
204    void                  *loss_data;
205
206    Elm_Sel_Format     format;
207    Ecore_X_Selection  ecore_sel;
208    Ecore_X_Window     xwin;
209    Elm_Xdnd_Action    action;
210
211    Eina_Bool          active : 1;
212 };
213
214 struct _X11_Cnp_Atom
215 {
216    const char              *name;
217    Elm_Sel_Format           formats;
218    /* Called by ecore to do conversion */
219    X11_Converter_Fn_Cb      converter;
220    X11_Response_Handler_Cb  response;
221    X11_Notify_Handler_Cb    notify;
222    /* Atom */
223    Ecore_X_Atom             atom;
224 };
225
226 static void           _x11_sel_obj_del              (void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
227 static void           _x11_sel_obj_del2             (void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
228 static Eina_Bool      _x11_selection_clear          (void *udata __UNUSED__, int type, void *event);
229 static Eina_Bool      _x11_selection_notify         (void *udata __UNUSED__, int type, void *event);
230 static Eina_Bool      _x11_targets_converter        (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
231 static Eina_Bool      _x11_text_converter           (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
232 static Eina_Bool      _x11_general_converter        (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
233 static Eina_Bool      _x11_image_converter          (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
234 static Eina_Bool      _x11_vcard_send               (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
235 //TIZEN ONLY : static Eina_Bool      _x11_is_uri_type_data         (X11_Cnp_Selection *sel __UNUSED__, Ecore_X_Event_Selection_Notify *notify);
236 static int            _x11_response_handler_targets (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
237 static int            _x11_notify_handler_targets   (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
238 static int            _x11_notify_handler_text      (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
239 static int            _x11_notify_handler_image     (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
240 static int            _x11_notify_handler_uri       (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
241 //static int            _x11_notify_handler_html      (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
242 static int            _x11_notify_handler_edje      (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify); // TIZEN ONLY
243 static int            _x11_vcard_receive            (X11_Cnp_Selection *sed, Ecore_X_Event_Selection_Notify *notify);
244 static Eina_Bool      _x11_dnd_enter                (void *data __UNUSED__, int etype __UNUSED__, void *ev);
245 static Eina_Bool      _x11_dnd_drop                 (void *data __UNUSED__, int etype __UNUSED__, void *ev);
246 static Eina_Bool      _x11_dnd_position             (void *data __UNUSED__, int etype __UNUSED__, void *ev);
247 static Eina_Bool      _x11_dnd_status               (void *data __UNUSED__, int etype __UNUSED__, void *ev);
248 static Eina_Bool      _x11_drag_mouse_up            (void *data, int etype __UNUSED__, void *event);
249 static void           _x11_drag_move                (void *data __UNUSED__, Ecore_X_Xdnd_Position *pos);
250
251 static Ecore_X_Window _x11_elm_widget_xwin_get           (const Evas_Object *obj);
252
253 static Eina_Bool _x11_elm_cnp_init                       (void);
254 static Eina_Bool _x11_elm_cnp_selection_set              (Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, const void *selbuf, size_t buflen);
255 static void      _x11_elm_cnp_selection_loss_callback_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const void *data);
256 static Eina_Bool _x11_elm_object_cnp_selection_clear     (Evas_Object *obj, Elm_Sel_Type selection);
257 static Eina_Bool _x11_elm_cnp_selection_get              (Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata);
258 static Eina_Bool _x11_elm_drop_target_add                (Evas_Object *obj, Elm_Sel_Format format, 
259                                                           Elm_Drag_State entercb, void *enterdata,
260                                                           Elm_Drag_State leavecb, void *leavedata,
261                                                           Elm_Drag_Pos poscb, void *posdata,
262                                                           Elm_Drop_Cb dropcb, void *cbdata);
263 static Eina_Bool _x11_elm_drop_target_del                (Evas_Object *obj);
264 static Eina_Bool _x11_elm_selection_selection_has_owner  (Evas_Object *obj __UNUSED__);
265
266 static X11_Cnp_Atom _x11_atoms[CNP_N_ATOMS] = {
267    [CNP_ATOM_TARGETS] = {
268       "TARGETS",
269       ELM_SEL_FORMAT_TARGETS,
270       _x11_targets_converter,
271       _x11_response_handler_targets,
272       _x11_notify_handler_targets,
273       0
274    },
275    [CNP_ATOM_ATOM] = {
276       "ATOM", // for opera browser
277       ELM_SEL_FORMAT_TARGETS,
278       _x11_targets_converter,
279       _x11_response_handler_targets,
280       _x11_notify_handler_targets,
281       0
282    },
283    [CNP_ATOM_XELM] =  {
284       "application/x-elementary-markup",
285       ELM_SEL_FORMAT_MARKUP,
286       _x11_general_converter,
287       NULL,
288       //NULL,                    // TIZEN ONLY
289       _x11_notify_handler_edje,  // TIZEN ONLY
290       0
291    },
292    [CNP_ATOM_text_uri] = {
293       "text/uri",
294       //ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE, /* Either images or entries */   // TIZEN ONLY
295       ELM_SEL_FORMAT_IMAGE,      // TIZEN ONLY
296       _x11_general_converter,
297       NULL,
298       _x11_notify_handler_uri,
299       0
300    },
301    [CNP_ATOM_text_urilist] = {
302       "text/uri-list",
303       ELM_SEL_FORMAT_IMAGE,
304       _x11_general_converter,
305       NULL,
306       _x11_notify_handler_uri,
307       0
308    },
309    [CNP_ATOM_text_x_vcard] = {
310       "text/x-vcard",
311       ELM_SEL_FORMAT_VCARD,
312       _x11_vcard_send, NULL,
313       _x11_vcard_receive, 0
314    },
315    [CNP_ATOM_image_png] = {
316       "image/png",
317       ELM_SEL_FORMAT_IMAGE,
318       _x11_image_converter,
319       NULL,
320       _x11_notify_handler_image,
321       0
322    },
323    [CNP_ATOM_image_jpeg] = {
324       "image/jpeg",
325       ELM_SEL_FORMAT_IMAGE,
326       _x11_image_converter,
327       NULL,
328       _x11_notify_handler_image,/* Raw image data is the same */
329       0
330    },
331    [CNP_ATOM_image_bmp] = {
332       "image/x-ms-bmp",
333       ELM_SEL_FORMAT_IMAGE,
334       _x11_image_converter,
335       NULL,
336       _x11_notify_handler_image,/* Raw image data is the same */
337       0
338    },
339    [CNP_ATOM_image_gif] = {
340       "image/gif",
341       ELM_SEL_FORMAT_IMAGE,
342       _x11_image_converter,
343       NULL,
344       _x11_notify_handler_image,/* Raw image data is the same */
345       0
346    },
347    [CNP_ATOM_image_tiff] = {
348       "image/tiff",
349       ELM_SEL_FORMAT_IMAGE,
350       _x11_image_converter,
351       NULL,
352       _x11_notify_handler_image,/* Raw image data is the same */
353       0
354    },
355    [CNP_ATOM_image_svg] = {
356       "image/svg+xml",
357       ELM_SEL_FORMAT_IMAGE,
358       _x11_image_converter,
359       NULL,
360       _x11_notify_handler_image,/* Raw image data is the same */
361       0
362    },
363    [CNP_ATOM_image_xpm] = {
364       "image/x-xpixmap",
365       ELM_SEL_FORMAT_IMAGE,
366       _x11_image_converter,
367       NULL,
368       _x11_notify_handler_image,/* Raw image data is the same */
369       0
370    },
371    [CNP_ATOM_image_tga] = {
372       "image/x-tga",
373       ELM_SEL_FORMAT_IMAGE,
374       _x11_image_converter,
375       NULL,
376       _x11_notify_handler_image,/* Raw image data is the same */
377       0
378    },
379    [CNP_ATOM_image_ppm] = {
380       "image/x-portable-pixmap",
381       ELM_SEL_FORMAT_IMAGE,
382       _x11_image_converter,
383       NULL,
384       _x11_notify_handler_image,/* Raw image data is the same */
385       0
386    },
387 /*   
388    [CNP_ATOM_text_html_utf8] = {
389       "text/html;charset=utf-8",
390       ELM_SEL_FORMAT_HTML,
391       _x11_general_converter,
392       NULL,
393       _x11_notify_handler_html,
394       0
395    },
396    [CNP_ATOM_text_html] = {
397       "text/html",
398       ELM_SEL_FORMAT_HTML,
399       _x11_general_converter,
400       NULL,
401       _x11_notify_handler_html, // No encoding: Webkit only
402       0
403    },
404  */
405    [CNP_ATOM_UTF8STRING] = {
406       "UTF8_STRING",
407       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
408       _x11_text_converter,
409       NULL,
410       _x11_notify_handler_text,
411       0
412    },
413    [CNP_ATOM_STRING] = {
414       "STRING",
415       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
416       _x11_text_converter,
417       NULL,
418       _x11_notify_handler_text,
419       0
420    },
421    [CNP_ATOM_COMPOUND_TEXT] = {
422       "COMPOUND_TEXT",
423       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
424       _x11_text_converter,
425       NULL,
426       _x11_notify_handler_text,
427       0
428    },
429    [CNP_ATOM_TEXT] = {
430       "TEXT",
431       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
432       _x11_text_converter,
433       NULL,
434       _x11_notify_handler_text,
435       0
436    },
437    [CNP_ATOM_text_plain_utf8] = {
438       "text/plain;charset=utf-8",
439       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
440       _x11_text_converter,
441       NULL,
442       _x11_notify_handler_text,
443       0
444    },
445    [CNP_ATOM_text_plain] = {
446       "text/plain",
447       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
448       _x11_text_converter,
449       NULL,
450       _x11_notify_handler_text,
451       0
452    },
453 };
454
455 static X11_Cnp_Selection _x11_selections[ELM_SEL_TYPE_CLIPBOARD + 1] = {
456    ARRAYINIT(ELM_SEL_TYPE_PRIMARY) {
457       .debug = "Primary",
458         .ecore_sel = ECORE_X_SELECTION_PRIMARY,
459         .set = ecore_x_selection_primary_set,
460         .clear = ecore_x_selection_primary_clear,
461         .request = ecore_x_selection_primary_request,
462    },
463    ARRAYINIT(ELM_SEL_TYPE_SECONDARY) {
464       .debug = "Secondary",
465         .ecore_sel = ECORE_X_SELECTION_SECONDARY,
466         .set = ecore_x_selection_secondary_set,
467         .clear = ecore_x_selection_secondary_clear,
468         .request = ecore_x_selection_secondary_request,
469    },
470    ARRAYINIT(ELM_SEL_TYPE_XDND) {
471       .debug = "XDnD",
472         .ecore_sel = ECORE_X_SELECTION_XDND,
473         .request = ecore_x_selection_xdnd_request,
474    },
475    ARRAYINIT(ELM_SEL_TYPE_CLIPBOARD) {
476       .debug = "Clipboard",
477         .ecore_sel = ECORE_X_SELECTION_CLIPBOARD,
478         .set = ecore_x_selection_clipboard_set,
479         .clear = ecore_x_selection_clipboard_clear,
480         .request = ecore_x_selection_clipboard_request,
481    },
482 };
483
484 static void
485 _x11_sel_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
486 {
487    X11_Cnp_Selection *sel = data;
488    if (sel->widget == obj) sel->widget = NULL;
489    if (dragwidget == obj) dragwidget = NULL;
490 }
491
492 static void
493 _x11_sel_obj_del2(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
494 {
495    X11_Cnp_Selection *sel = data;
496    if (sel->requestwidget == obj) sel->requestwidget = NULL;
497 }
498
499 static Eina_Bool
500 _x11_selection_clear(void *udata __UNUSED__, int type __UNUSED__, void *event)
501 {
502    Ecore_X_Event_Selection_Clear *ev = event;
503    X11_Cnp_Selection *sel;
504    unsigned int i;
505
506    _x11_elm_cnp_init();
507    for (i = ELM_SEL_TYPE_PRIMARY; i <= ELM_SEL_TYPE_CLIPBOARD; i++)
508      {
509         if (_x11_selections[i].ecore_sel == ev->selection) break;
510      }
511    cnp_debug("selection %d clear\n", i);
512    /* Not me... Don't care */
513    if (i > ELM_SEL_TYPE_CLIPBOARD) return ECORE_CALLBACK_PASS_ON;
514
515    sel = _x11_selections + i;
516    if (sel->loss_cb) sel->loss_cb(sel->loss_data, i);
517    if (sel->widget)
518      evas_object_event_callback_del_full(sel->widget, EVAS_CALLBACK_DEL,
519                                          _x11_sel_obj_del, sel);
520    if (sel->requestwidget)
521      evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
522                                          _x11_sel_obj_del2, sel);
523    sel->widget = NULL;
524    sel->requestwidget = NULL;
525    sel->active = EINA_FALSE;
526    sel->widget = NULL;
527    if (sel->selbuf)
528      {
529         free(sel->selbuf);
530         sel->selbuf = NULL;
531      }
532    return ECORE_CALLBACK_PASS_ON;
533 }
534
535 /*
536  * Response to a selection notify:
537  *  - So we have asked for the selection list.
538  *  - If it's the targets list, parse it, and fire of what we want,
539  *    else it's the data we want.
540  */
541 static Eina_Bool
542 _x11_selection_notify(void *udata __UNUSED__, int type __UNUSED__, void *event)
543 {
544    Ecore_X_Event_Selection_Notify *ev = event;
545    X11_Cnp_Selection *sel;
546    int i;
547
548    cnp_debug("selection notify callback: %d\n",ev->selection);
549    switch (ev->selection)
550      {
551       case ECORE_X_SELECTION_PRIMARY:
552         sel = _x11_selections + ELM_SEL_TYPE_PRIMARY;
553         break;
554       case ECORE_X_SELECTION_SECONDARY:
555         sel = _x11_selections + ELM_SEL_TYPE_SECONDARY;
556         break;
557       case ECORE_X_SELECTION_XDND:
558         sel = _x11_selections + ELM_SEL_TYPE_XDND;
559         break;
560       case ECORE_X_SELECTION_CLIPBOARD:
561         sel = _x11_selections + ELM_SEL_TYPE_CLIPBOARD;
562         break;
563       default:
564         return ECORE_CALLBACK_PASS_ON;
565      }
566    cnp_debug("Target is %s\n", ev->target);
567
568    if (!elm_widget_focus_get(sel->requestwidget) &&
569        ((ev->selection == ECORE_X_SELECTION_SECONDARY) || (ev->selection == ECORE_X_SELECTION_CLIPBOARD)))
570      return ECORE_CALLBACK_PASS_ON;
571
572    for (i = 0; i < CNP_N_ATOMS; i++)
573      {
574         if (!strcmp(ev->target, _x11_atoms[i].name))
575           {
576              if (_x11_atoms[i].notify)
577                {
578                   cnp_debug("Found something: %s\n", _x11_atoms[i].name);
579                   _x11_atoms[i].notify(sel, ev);
580                }
581              else cnp_debug("Ignored: No handler!\n");
582           }
583      }
584    return ECORE_CALLBACK_PASS_ON;
585 }
586
587 static Elm_Sel_Format
588 _get_selection_type(void *data, int size)
589 {
590    if (size == sizeof(Elm_Sel_Type))
591      {
592         unsigned int seltype = *((unsigned int *)data);
593         if (seltype > ELM_SEL_TYPE_CLIPBOARD)
594           return ELM_SEL_FORMAT_NONE;
595         X11_Cnp_Selection *sel = _x11_selections + seltype;
596         if (sel->active &&
597             (sel->format >= ELM_SEL_FORMAT_TARGETS) &&
598             (sel->format <= ELM_SEL_FORMAT_HTML))
599           return sel->format;
600      }
601    return ELM_SEL_FORMAT_NONE;
602 }
603
604 static Eina_Bool
605 _x11_targets_converter(char *target __UNUSED__, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
606 {
607    int i, count;
608    Ecore_X_Atom *aret;
609    X11_Cnp_Selection *sel;
610    Elm_Sel_Format seltype;
611
612    if (!data_ret) return EINA_FALSE;
613    if (_get_selection_type(data, size) == ELM_SEL_FORMAT_NONE)
614      {
615         /* TODO : fallback into precise type */
616         seltype = ELM_SEL_FORMAT_TEXT;
617      }
618    else
619      {
620         sel = _x11_selections + *((int *)data);
621         seltype = sel->format;
622      }
623
624    for (i = 0, count = 0; i < CNP_N_ATOMS ; i++)
625      {
626         if (seltype & _x11_atoms[i].formats) count++;
627      }
628    aret = malloc(sizeof(Ecore_X_Atom) * count);
629    if (!aret) return EINA_FALSE;
630    for (i = 0, count = 0; i < CNP_N_ATOMS; i++)
631      {
632         if (seltype & _x11_atoms[i].formats)
633           aret[count ++] = _x11_atoms[i].atom;
634      }
635
636    *data_ret = aret;
637    if (typesize) *typesize = 32 /* urk */;
638    if (ttype) *ttype = ECORE_X_ATOM_ATOM;
639    if (size_ret) *size_ret = count;
640    return EINA_TRUE;
641 }
642
643 static Eina_Bool
644 _x11_image_converter(char *target __UNUSED__, void *data __UNUSED__, int size __UNUSED__, void **data_ret __UNUSED__, int *size_ret __UNUSED__, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
645 {
646    cnp_debug("Image converter called\n");
647    return EINA_TRUE;
648 }
649
650 static Eina_Bool
651 _x11_vcard_send(char *target __UNUSED__, void *data __UNUSED__, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
652 {
653    X11_Cnp_Selection *sel;
654
655    cnp_debug("Vcard send called\n");
656    sel = _x11_selections + *((int *)data);
657    if (data_ret) *data_ret = strdup(sel->selbuf);
658    if (size_ret) *size_ret = strlen(sel->selbuf);
659    return EINA_TRUE;
660 }
661
662 // TIZEN ONLY
663 #if 0
664 static Eina_Bool
665 _x11_is_uri_type_data(X11_Cnp_Selection *sel __UNUSED__, Ecore_X_Event_Selection_Notify *notify)
666 {
667    Ecore_X_Selection_Data *data;
668    char *p;
669
670    data = notify->data;
671    cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
672    if (data->content == ECORE_X_SELECTION_CONTENT_FILES) return EINA_TRUE;
673    p = (char *)data->data;
674    if (!p) return EINA_TRUE;
675    cnp_debug("Got %s\n", p);
676    if (strncmp(p, "file://", 7))
677      {
678         if (*p != '/') return EINA_FALSE;
679      }
680    return EINA_TRUE;
681 }
682 #endif
683 //
684
685 /*
686  * Callback to handle a targets response on a selection request:
687  * So pick the format we'd like; and then request it.
688  */
689 static int
690 _x11_notify_handler_targets(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
691 {
692    Ecore_X_Selection_Data_Targets *targets;
693    Ecore_X_Atom *atomlist;
694    int i, j;
695
696    targets = notify->data;
697    atomlist = (Ecore_X_Atom *)(targets->data.data);
698    for (j = (CNP_ATOM_LISTING_ATOMS + 1); j < CNP_N_ATOMS; j++)
699      {
700         cnp_debug("\t%s %d\n", _x11_atoms[j].name, _x11_atoms[j].atom);
701         if (!(_x11_atoms[j].formats & sel->requestformat)) continue;
702         for (i = 0; i < targets->data.length; i++)
703           {
704              if ((_x11_atoms[j].atom == atomlist[i]) && (_x11_atoms[j].notify))
705                {
706 // TIZEN ONLY
707 #if 0
708                   if ((j == CNP_ATOM_text_uri) ||
709                       (j == CNP_ATOM_text_urilist))
710                     {
711                        if (!_x11_is_uri_type_data(sel, notify)) continue;
712                     }
713 #endif
714 //
715                   cnp_debug("Atom %s matches\n", _x11_atoms[j].name);
716                   goto done;
717                }
718           }
719      }
720    cnp_debug("Couldn't find anything that matches\n");
721    return ECORE_CALLBACK_PASS_ON;
722 done:
723    cnp_debug("Sending request for %s, xwin=%#llx\n",
724              _x11_atoms[j].name, (unsigned long long)sel->xwin);
725    sel->request(sel->xwin, _x11_atoms[j].name);
726    return ECORE_CALLBACK_PASS_ON;
727 }
728
729 static int
730 _x11_response_handler_targets(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
731 {
732    Ecore_X_Selection_Data_Targets *targets;
733    Ecore_X_Atom *atomlist;
734    int i, j;
735
736    targets = notify->data;
737    atomlist = (Ecore_X_Atom *)(targets->data.data);
738
739    for (j = (CNP_ATOM_LISTING_ATOMS + 1); j < CNP_N_ATOMS; j++)
740      {
741         if (!(_x11_atoms[j].formats & sel->requestformat)) continue;
742         for (i = 0; i < targets->data.length; i++)
743           {
744              if ((_x11_atoms[j].atom == atomlist[i]) &&
745                  (_x11_atoms[j].response))
746                goto found;
747           }
748      }
749    cnp_debug("No matching type found\n");
750    return 0;
751 found:
752    sel->request(sel->xwin, _x11_atoms[j].name);
753    return 0;
754 }
755
756 static int
757 _x11_notify_handler_text(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
758 {
759    Ecore_X_Selection_Data *data;
760    Eina_List *l;
761    Dropable *dropable;
762
763    data = notify->data;
764    if (sel == (_x11_selections + ELM_SEL_TYPE_XDND))
765      {
766         Elm_Selection_Data ddata;
767
768         cnp_debug("drag & drop\n");
769         /* FIXME: this needs to be generic: Used for all receives */
770         EINA_LIST_FOREACH(drops, l, dropable)
771           {
772              if (dropable->obj == sel->requestwidget) break;
773              dropable = NULL;
774           }
775         if (dropable)
776           {
777              ddata.x = savedtypes.x;
778              ddata.y = savedtypes.y;
779              ddata.format = ELM_SEL_FORMAT_TEXT;
780              ddata.data = data->data;
781              ddata.len = data->length;
782              ddata.action = sel->action;
783              dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
784              goto end;
785           }
786      }
787    if (sel->datacb)
788      {
789         Elm_Selection_Data ddata;
790
791         ddata.x = ddata.y = 0;
792         ddata.format = ELM_SEL_FORMAT_TEXT;
793         ddata.data = data->data;
794         ddata.len = data->length;
795         ddata.action = sel->action;
796         sel->datacb(sel->udata, sel->widget, &ddata);
797      }
798    else
799      {
800         char *stripstr, *mkupstr;
801
802         stripstr = malloc(data->length + 1);
803         if (!stripstr) goto end;
804         strncpy(stripstr, (char *)data->data, data->length);
805         stripstr[data->length] = '\0';
806         cnp_debug("Notify handler text %d %d %p\n", data->format,
807                   data->length, data->data);
808         mkupstr = _elm_util_text_to_mkup((const char *)stripstr);
809         cnp_debug("String is %s (from %s)\n", stripstr, data->data);
810         /* TODO BUG: should never NEVER assume it's an elm_entry! */
811         //_elm_entry_entry_paste(sel->requestwidget, mkupstr); // TIZEN ONLY
812         // TIZEN ONLY
813         if (mkupstr)
814           _entry_insert_filter(sel->requestwidget, mkupstr);
815         else
816           _entry_insert_filter(sel->requestwidget, stripstr);
817         //
818
819         free(stripstr);
820         free(mkupstr);
821      }
822 end:   
823    if (sel == (_x11_selections + ELM_SEL_TYPE_XDND))
824      ecore_x_dnd_send_finished();
825    return 0;
826 }
827
828 /**
829  * So someone is pasting an image into my entry or widget...
830  */
831 static int
832 _x11_notify_handler_uri(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
833 {
834    Ecore_X_Selection_Data *data;
835    Ecore_X_Selection_Data_Files *files;
836    char *p, *s, *stripstr = NULL;
837
838    data = notify->data;
839    cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
840    if (data->content == ECORE_X_SELECTION_CONTENT_FILES)
841      {
842         int i, len = 0;
843
844         cnp_debug("got a files list\n");
845         files = notify->data;
846         /*
847         if (files->num_files > 1)
848           {
849              // Don't handle many items <- this makes mr bigglesworth sad :(
850              cnp_debug("more then one file: Bailing\n");
851              return 0;
852           }
853         stripstr = p = strdup(files->files[0]);
854          */
855         for (i = 0; i < files->num_files ; i++)
856           {
857              p = files->files[i];
858              if (strncmp(p, "file://", 7) && (p[0] != '/')) continue;
859              if (!strncmp(p, "file://", 7)) p += 7;
860              len += strlen(p) + 1;
861           }
862         p = NULL;
863         if (len > 0)
864           {
865              s = stripstr = malloc(len + 1);
866              for (i = 0; i < files->num_files ; i++)
867                {
868                   p = files->files[i];
869                   if ((strncmp(p, "file://", 7)) && (p[0] != '/')) continue;
870                   if (!strncmp(p, "file://", 7)) p += 7;
871                   len = strlen(p);
872                   strcpy(s, p);
873                   if (i < (files->num_files - 1))
874                     {
875                        s[len] = '\n';
876                        s[len + 1] = 0;
877                        s += len + 1;
878                     }
879                   else
880                     {
881                        s[len] = 0;
882                        s += len;
883                     }
884                }
885           }
886      }
887    else
888      {
889         p = (char *)data->data;
890         if ((!strncmp(p, "file://", 7)) || (p[0] == '/'))
891           {
892              int len = data->length;
893              if (!strncmp(p, "file://", 7))
894                {
895                   p += 7;
896                   len -= 7;
897                }
898              stripstr = malloc(len + 1);
899              if (!stripstr) return 0;
900              memcpy(stripstr, p, len);
901              stripstr[len] = 0;
902           }
903      }
904    if (!stripstr)
905      {
906         cnp_debug("Couldn't find a file\n");
907         return 0;
908      }
909    if (savedtypes.imgfile) free(savedtypes.imgfile);
910    if (savedtypes.textreq)
911      {
912         savedtypes.textreq = 0;
913         savedtypes.imgfile = stripstr;
914      }
915    else
916      {
917         savedtypes.imgfile = NULL;
918         _pasteimage_append(stripstr, sel->requestwidget);
919         free(stripstr);
920      }
921    return 0;
922 }
923
924 /**
925  * Just receieved an vcard, either through cut and paste, or dnd.
926  */
927 static int
928 _x11_vcard_receive(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
929 {
930    Dropable *dropable;
931    Eina_List *l;
932    Ecore_X_Selection_Data *data;
933
934    data = notify->data;
935    cnp_debug("vcard receive\n");
936    if (sel == (_x11_selections + ELM_SEL_TYPE_XDND))
937      {
938         Elm_Selection_Data ddata;
939
940         cnp_debug("drag & drop\n");
941         /* FIXME: this needs to be generic: Used for all receives */
942         EINA_LIST_FOREACH(drops, l, dropable)
943           {
944              if (dropable->obj == sel->requestwidget) break;
945           }
946         if (!dropable)
947           {
948              cnp_debug("Unable to find drop object");
949              ecore_x_dnd_send_finished();
950              return 0;
951           }
952         dropable = eina_list_data_get(l);
953         ddata.x = savedtypes.x;
954         ddata.y = savedtypes.y;
955         ddata.format = ELM_SEL_FORMAT_VCARD;
956         ddata.data = data->data;
957         ddata.len = data->length;
958         ddata.action = sel->action;
959         dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
960         ecore_x_dnd_send_finished();
961      }
962    else if (sel->datacb)
963      {
964         Elm_Selection_Data ddata;
965         ddata.x = ddata.y = 0;
966         ddata.format = ELM_SEL_FORMAT_VCARD;
967         ddata.data = data->data;
968         ddata.len = data->length;
969         ddata.action = sel->action;
970         sel->datacb(sel->udata, sel->widget, &ddata);
971      }
972    else cnp_debug("Paste request\n");
973    return 0;
974 }
975
976 static int
977 _x11_notify_handler_image(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
978 {
979    Ecore_X_Selection_Data *data;
980    Tmp_Info *tmp;
981
982    cnp_debug("got a image file!\n");
983    data = notify->data;
984
985    cnp_debug("Size if %d\n", data->length);
986    if (sel->datacb)
987      {
988         Elm_Selection_Data ddata;
989
990         ddata.x = ddata.y = 0;
991         ddata.format = ELM_SEL_FORMAT_IMAGE;
992         ddata.data = data->data;
993         ddata.len = data->length;
994         ddata.action = sel->action;
995         sel->datacb(sel->udata, sel->widget, &ddata);
996         return 0;
997      }
998    /* generate tmp name */
999    tmp = _tempfile_new(data->length);
1000    if (!tmp) return 0;
1001    memcpy(tmp->map, data->data, data->length);
1002    munmap(tmp->map, data->length);
1003    /* FIXME: Add to paste image data to clean up */
1004    _pasteimage_append(tmp->filename, sel->requestwidget);
1005    _tmpinfo_free(tmp);
1006    return 0;
1007 }
1008
1009 // TIZEN ONLY
1010 static int
1011 _x11_notify_handler_edje(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
1012 {
1013    Ecore_X_Selection_Data *data;
1014
1015    data = notify->data;
1016
1017    if (sel->datacb)
1018      {
1019         Elm_Selection_Data ddata;
1020         ddata.x = ddata.y = 0;
1021         ddata.format = ELM_SEL_FORMAT_MARKUP;
1022         ddata.data = data->data;
1023         ddata.len = data->length;
1024         sel->datacb(sel->udata, sel->widget, &ddata);
1025      }
1026    else
1027      {
1028         char *stripstr;
1029         stripstr = malloc(data->length + 1);
1030         if (!stripstr) return 0;
1031         strncpy(stripstr, (char *)data->data, data->length);
1032         stripstr[data->length] = '\0';
1033
1034         _entry_insert_filter(sel->requestwidget, stripstr);
1035         cnp_debug("String is %s (%d bytes)\n", stripstr, data->length);
1036         free(stripstr);
1037      }
1038
1039    return 0;
1040 }
1041 //
1042
1043 /**
1044  *    Warning: Generic text/html can';t handle it sanely.
1045  *    Firefox sends ucs2 (i think).
1046  *       chrome sends utf8... blerg
1047  */
1048 /*
1049 static int
1050 _x11_notify_handler_html(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
1051 {
1052    Ecore_X_Selection_Data *data;
1053
1054    cnp_debug("Got some HTML: Checking encoding is useful\n");
1055    data = notify->data;
1056    char *stripstr = malloc(data->length + 1);
1057    if (!stripstr) return 0;
1058    strncpy(stripstr, (char *)data->data, data->length);
1059    stripstr[data->length] = '\0';
1060
1061    if (sel->datacb)
1062      {
1063         Elm_Selection_Data ddata;
1064         ddata.x = ddata.y = 0;
1065         ddata.format = ELM_SEL_FORMAT_HTML;
1066         ddata.data = stripstr;
1067         ddata.len = data->length;
1068         ddata.action = ELM_XDND_ACTION_UNKNOWN;
1069         sel->datacb(sel->udata, sel->widget, &ddata);
1070         free(stripstr);
1071         return 0;
1072      }
1073
1074    cnp_debug("String is %s (%d bytes)\n", stripstr, data->length);
1075    // TODO BUG: should never NEVER assume it's an elm_entry!
1076    _elm_entry_entry_paste(sel->requestwidget, stripstr);
1077    free(stripstr);
1078    return 0;
1079 }
1080 */
1081
1082 static Eina_Bool
1083 _x11_text_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
1084 {
1085    X11_Cnp_Selection *sel;
1086
1087    cnp_debug("text converter\n");
1088    if (_get_selection_type(data, size) == ELM_SEL_FORMAT_NONE)
1089      {
1090         if (data_ret)
1091           {
1092              *data_ret = malloc(size * sizeof(char) + 1);
1093              if (!*data_ret) return EINA_FALSE;
1094              memcpy(*data_ret, data, size);
1095              ((char**)(data_ret))[0][size] = 0;
1096           }
1097         if (size_ret) *size_ret = size;
1098         return EINA_TRUE;
1099      }
1100    sel = _x11_selections + *((int *)data);
1101    if (!sel->active) return EINA_TRUE;
1102
1103    if ((sel->format & ELM_SEL_FORMAT_MARKUP) ||
1104        (sel->format & ELM_SEL_FORMAT_HTML))
1105      {
1106         *data_ret = _elm_util_mkup_to_text(sel->selbuf);
1107         if (size_ret && *data_ret) *size_ret = strlen(*data_ret);
1108      }
1109    else if (sel->format & ELM_SEL_FORMAT_TEXT)
1110      {
1111         ecore_x_selection_converter_text(target, sel->selbuf,
1112                                          strlen(sel->selbuf),
1113                                          data_ret, size_ret,
1114                                          ttype, typesize);
1115      }
1116    else if (sel->format & ELM_SEL_FORMAT_IMAGE)
1117      {
1118         cnp_debug("Image %s\n", evas_object_type_get(sel->widget));
1119         cnp_debug("Elm type: %s\n", elm_object_widget_type_get(sel->widget));
1120         evas_object_image_file_get(elm_photocam_internal_image_get(sel->widget),
1121                                    (const char **)data_ret, NULL);
1122         if (!*data_ret) *data_ret = strdup("No file");
1123         else *data_ret = strdup(*data_ret);
1124         *size_ret = strlen(*data_ret);
1125      }
1126    return EINA_TRUE;
1127 }
1128
1129 static Eina_Bool
1130 _x11_general_converter(char *target __UNUSED__, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
1131 {
1132    if (_get_selection_type(data, size) == ELM_SEL_FORMAT_NONE)
1133      {
1134         if (data_ret)
1135           {
1136              *data_ret = malloc(size * sizeof(char) + 1);
1137              if (!*data_ret) return EINA_FALSE;
1138              memcpy(*data_ret, data, size);
1139              ((char**)(data_ret))[0][size] = 0;
1140           }
1141         if (size_ret) *size_ret = size;
1142      }
1143    else
1144      {
1145         X11_Cnp_Selection *sel = _x11_selections + *((int *)data);
1146         if (sel->selbuf)
1147           {
1148              if (data_ret) *data_ret = strdup(sel->selbuf);
1149              if (size_ret) *size_ret = strlen(sel->selbuf);
1150           }
1151         else
1152           {
1153              if (data_ret) *data_ret = NULL;
1154              if (size_ret) *size_ret = 0;
1155           }
1156      }
1157    return EINA_TRUE;
1158 }
1159
1160 static Dropable *
1161 _x11_dropable_find(Ecore_X_Window win)
1162 {
1163    Eina_List *l;
1164    Dropable *dropable;
1165    
1166    if (!drops) return NULL;
1167    EINA_LIST_FOREACH(drops, l, dropable)
1168      {
1169         if (_x11_elm_widget_xwin_get(dropable->obj) == win) return dropable;
1170      }
1171    return NULL;
1172 }
1173
1174 static Dropable *
1175 _x11_dropable_geom_find(Ecore_X_Window win, Evas_Coord px, Evas_Coord py)
1176 {
1177    Eina_List *itr, *top_objects_list = NULL;
1178    Evas *evas = NULL;
1179    Evas_Object *top_obj;
1180    Dropable *dropable = NULL;
1181
1182     if (!drops) return NULL;
1183    /* Find the Evas connected to the window */
1184    EINA_LIST_FOREACH(drops, itr, dropable)
1185       {
1186          if (_x11_elm_widget_xwin_get(dropable->obj) == win)
1187            {
1188              evas = evas_object_evas_get(dropable->obj);
1189              break;
1190            }
1191       }
1192    if (!evas) return NULL;
1193
1194    /* We retrieve the (non-smart) objects pointed by (px, py) */
1195    top_objects_list = evas_tree_objects_at_xy_get(evas, NULL, px, py);
1196    /* We walk on this list from the last because if the list contains more than one
1197     * element, all but the last will repeat events. The last one can repeat events
1198     * or not. Anyway, this last one is the first that has to be taken into account
1199     * for the determination of the drop target.
1200     */
1201    EINA_LIST_REVERSE_FOREACH(top_objects_list, itr, top_obj)
1202      {
1203         Evas_Object *object = top_obj;
1204         /* We search for the dropable data into the object. If not found, we search into its parent.
1205          * For example, if a button is a drop target, the first object will be an (internal) image.
1206          * The drop target is attached to the button, i.e to image's parent. That's why we need to
1207          * walk on the parents until NULL.
1208          * If we find this dropable data, we found our drop target.
1209          */
1210         while (object)
1211           {
1212              dropable = evas_object_data_get(object, "dropable");
1213              if (dropable)
1214                 goto end;
1215              else
1216                 object = evas_object_smart_parent_get(object);
1217           }
1218      }
1219 end:
1220    eina_list_free(top_objects_list);
1221    return dropable;
1222 }
1223
1224 static void
1225 _x11_dropable_coords_adjust(Dropable *dropable, Evas_Coord *x, Evas_Coord *y)
1226 {
1227    Ecore_Evas *ee;
1228    int ex = 0, ey = 0;
1229
1230    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(dropable->obj));
1231    ecore_evas_geometry_get(ee, &ex, &ey, NULL, NULL);
1232    *x = *x - ex;
1233    *y = *y - ey;
1234 }
1235
1236 static void
1237 _x11_dropable_all_set(Ecore_X_Window win, Evas_Coord x, Evas_Coord y, Eina_Bool set)
1238 {
1239    Eina_List *l;
1240    Dropable *dropable;
1241    EINA_LIST_FOREACH(drops, l, dropable)
1242      {
1243         if (_x11_elm_widget_xwin_get(dropable->obj) == win)
1244           {
1245              dropable->last.x = x;
1246              dropable->last.y = y;
1247              dropable->last.in = set;
1248           }
1249      }
1250 }
1251
1252 static Eina_Bool
1253 _x11_dnd_enter(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1254 {
1255    Ecore_X_Event_Xdnd_Enter *enter = ev;
1256    int i;
1257    Dropable *dropable;
1258
1259    if (!enter) return EINA_TRUE;
1260    dropable = _x11_dropable_find(enter->win);
1261    if (dropable)
1262      {
1263         cnp_debug("Enter %x\n", enter->win);
1264         _x11_dropable_all_set(enter->win, 0, 0, EINA_FALSE);
1265      }
1266    /* Skip it */
1267    cnp_debug("enter types=%p (%d)\n", enter->types, enter->num_types);
1268    if ((!enter->num_types) || (!enter->types)) return EINA_TRUE;
1269
1270    cnp_debug("Types\n");
1271    savedtypes.ntypes = enter->num_types;
1272    if (savedtypes.types) free(savedtypes.types);
1273    savedtypes.types = malloc(sizeof(char *) * enter->num_types);
1274    if (!savedtypes.types) return EINA_FALSE;
1275
1276    for (i = 0; i < enter->num_types; i++)
1277      {
1278         savedtypes.types[i] = eina_stringshare_add(enter->types[i]);
1279         cnp_debug("Type is %s %p %p\n", enter->types[i],
1280                   savedtypes.types[i], text_uri);
1281         if (savedtypes.types[i] == text_uri)
1282           {
1283              /* Request it, so we know what it is */
1284              cnp_debug("Sending uri request\n");
1285              savedtypes.textreq = 1;
1286              if (savedtypes.imgfile) free(savedtypes.imgfile);
1287              savedtypes.imgfile = NULL;
1288              ecore_x_selection_xdnd_request(enter->win, text_uri);
1289           }
1290      }
1291
1292    /* FIXME: Find an object and make it current */
1293    return EINA_TRUE;
1294 }
1295
1296 static void
1297 _x11_dnd_dropable_handle(Dropable *dropable, Evas_Coord x, Evas_Coord y, Eina_Bool have_obj, Elm_Xdnd_Action action)
1298 {
1299    Dropable *dropable_last = NULL;
1300    
1301    if (dropable->last.in)
1302      dropable_last = _x11_dropable_geom_find
1303      (_x11_elm_widget_xwin_get(dropable->obj), 
1304          dropable->last.x, dropable->last.y);
1305    if ((have_obj) && (dropable_last == dropable)) // same
1306      {
1307         cnp_debug("same obj dropable %p\n", dropable);
1308         if (dropable->poscb)
1309           dropable->poscb(dropable->posdata, dropable->obj, x, y, action);
1310      }
1311    else if ((have_obj) && (!dropable_last)) // enter new obj
1312      {
1313         cnp_debug("enter %p\n", dropable->obj);
1314         if (dropable->entercb)
1315           dropable->entercb(dropable->enterdata, dropable->obj);
1316         if (dropable->poscb)
1317           dropable->poscb(dropable->posdata, dropable->obj, x, y, action);
1318      }
1319    else if ((!have_obj) && (dropable_last)) // leave last obj
1320      {
1321         cnp_debug("leave %p\n", dropable_last->obj);
1322         if (dropable->leavecb)
1323           dropable->leavecb(dropable->leavedata, dropable->obj);
1324      }
1325    else if (have_obj) // leave last obj and enter new one
1326      {
1327         cnp_debug("enter %p\n", dropable->obj);
1328         if (dropable->entercb)
1329           dropable->entercb(dropable->enterdata, dropable->obj);
1330         if (dropable_last)
1331           {
1332              dropable = dropable_last;
1333              if (dropable->leavecb)
1334                dropable->leavecb(dropable->leavedata, dropable->obj);
1335              cnp_debug("leave %p\n", dropable->obj);
1336           }
1337      }
1338 }
1339
1340 static Elm_Xdnd_Action
1341 _x11_dnd_action_map(Ecore_X_Atom action)
1342 {
1343    Elm_Xdnd_Action act = ELM_XDND_ACTION_UNKNOWN;
1344
1345    if (action == ECORE_X_ATOM_XDND_ACTION_COPY)
1346      act = ELM_XDND_ACTION_COPY;
1347    else if (action == ECORE_X_ATOM_XDND_ACTION_MOVE)
1348      act = ELM_XDND_ACTION_MOVE;
1349    else if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE)
1350      act = ELM_XDND_ACTION_PRIVATE;
1351    else if (action == ECORE_X_ATOM_XDND_ACTION_ASK)
1352      act = ELM_XDND_ACTION_ASK;
1353    else if (action == ECORE_X_ATOM_XDND_ACTION_LIST)
1354      act = ELM_XDND_ACTION_LIST;
1355    else if (action == ECORE_X_ATOM_XDND_ACTION_LINK)
1356      act = ELM_XDND_ACTION_LINK;
1357    else if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION)
1358      act = ELM_XDND_ACTION_DESCRIPTION;
1359    return act;
1360 }
1361
1362 static Ecore_X_Atom
1363 _x11_dnd_action_rev_map(Elm_Xdnd_Action action)
1364 {
1365    Ecore_X_Atom act = ECORE_X_ATOM_XDND_ACTION_MOVE;
1366
1367    if (action == ELM_XDND_ACTION_COPY)
1368      act = ECORE_X_ATOM_XDND_ACTION_COPY;
1369    else if (action == ELM_XDND_ACTION_MOVE)
1370      act = ECORE_X_ATOM_XDND_ACTION_MOVE;
1371    else if (action == ELM_XDND_ACTION_PRIVATE)
1372      act = ECORE_X_ATOM_XDND_ACTION_PRIVATE;
1373    else if (action == ELM_XDND_ACTION_ASK)
1374      act = ECORE_X_ATOM_XDND_ACTION_ASK;
1375    else if (action == ELM_XDND_ACTION_LIST)
1376      act = ECORE_X_ATOM_XDND_ACTION_LIST;
1377    else if (action == ELM_XDND_ACTION_LINK)
1378      act = ECORE_X_ATOM_XDND_ACTION_LINK;
1379    else if (action == ELM_XDND_ACTION_DESCRIPTION)
1380      act = ECORE_X_ATOM_XDND_ACTION_DESCRIPTION;
1381    return act;
1382 }
1383
1384 static Eina_Bool
1385 _x11_dnd_position(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1386 {
1387    Ecore_X_Event_Xdnd_Position *pos = ev;
1388    Ecore_X_Rectangle rect;
1389    Dropable *dropable, *dropable_old;
1390    Elm_Xdnd_Action act;
1391    
1392    /* Need to send a status back */
1393    /* FIXME: Should check I can drop here */
1394    /* FIXME: Should highlight widget */
1395    dropable_old = dropable = _x11_dropable_find(pos->win);
1396    if (dropable)
1397      {
1398         Evas_Coord x, y, ox = 0, oy = 0, ow = 0, oh = 0;
1399         
1400         x = pos->position.x;
1401         y = pos->position.y;
1402         _x11_dropable_coords_adjust(dropable, &x, &y);
1403         dropable = _x11_dropable_geom_find(pos->win, x, y);
1404         act = _x11_dnd_action_map(pos->action);
1405         if (dropable)
1406           {
1407              evas_object_geometry_get(dropable->obj, &ox, &oy, &ow, &oh);
1408              rect.x = pos->position.x - x + ox;
1409              rect.y = pos->position.y - y + oy;
1410              rect.width = ow;
1411              rect.height = oh;
1412              ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, pos->action);
1413              cnp_debug("dnd position %i %i %p\n", x - ox, y - oy, dropable);
1414              _x11_dnd_dropable_handle(dropable, x - ox, y - oy, EINA_TRUE, 
1415                                       act);
1416              // CCCCCCC: call dnd exit on last obj if obj != last
1417              // CCCCCCC: call drop position on obj
1418              _x11_dropable_all_set(pos->win, x, y, EINA_TRUE);
1419           }
1420         else
1421           {
1422              ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, pos->action);
1423              cnp_debug("dnd position (%d, %d) not in obj\n", x, y);
1424              _x11_dnd_dropable_handle(dropable_old, 0, 0, EINA_FALSE, 
1425                                       act);
1426              // CCCCCCC: call dnd exit on last obj
1427              _x11_dropable_all_set(pos->win, x, y, EINA_TRUE);
1428           }
1429      }
1430    else
1431      {
1432         ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, pos->action);
1433      }
1434    return EINA_TRUE;
1435 }
1436
1437 static Eina_Bool
1438 _x11_dnd_leave(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1439 {
1440    Ecore_X_Event_Xdnd_Leave *leave = ev;
1441    Dropable *dropable;
1442
1443    dropable = _x11_dropable_find(leave->win);
1444    if (dropable)
1445      {
1446         cnp_debug("Leave %x\n", leave->win);
1447         _x11_dnd_dropable_handle(dropable, 0, 0, EINA_FALSE, ELM_XDND_ACTION_UNKNOWN);
1448         _x11_dropable_all_set(leave->win, 0, 0, EINA_FALSE);
1449         // CCCCCCC: call dnd exit on last obj if there was one
1450      }
1451    // leave->win leave->source
1452    return EINA_TRUE;
1453 }
1454
1455 static Eina_Bool
1456 _x11_dnd_drop(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1457 {
1458    Ecore_X_Event_Xdnd_Drop *drop;
1459    Dropable *dropable;
1460    Elm_Selection_Data ddata;
1461    Evas_Coord x = 0, y = 0;
1462    Elm_Xdnd_Action act = ELM_XDND_ACTION_UNKNOWN;
1463    int i, j;
1464
1465    drop = ev;
1466
1467    cnp_debug("drops %p (%d)\n", drops, eina_list_count(drops));
1468    if (!(dropable = _x11_dropable_find(drop->win))) return EINA_TRUE;
1469
1470    /* Calculate real (widget relative) position */
1471    // - window position
1472    // - widget position
1473    savedtypes.x = drop->position.x;
1474    savedtypes.y = drop->position.y;
1475    _x11_dropable_coords_adjust(dropable, &savedtypes.x, &savedtypes.y);
1476
1477    cnp_debug("Drop position is %d,%d\n", savedtypes.x, savedtypes.y);
1478
1479    dropable = _x11_dropable_geom_find(drop->win, savedtypes.x, savedtypes.y);
1480    if (!dropable) return EINA_TRUE; /* didn't find one */
1481
1482    evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL);
1483    savedtypes.x -= x;
1484    savedtypes.y -= y;
1485
1486    /* Find our type from the previous list */
1487    for (i = 0; i < CNP_N_ATOMS; i++)
1488      {
1489         for (j = 0; j < savedtypes.ntypes; j++)
1490           {
1491              if (!strcmp(savedtypes.types[j], _x11_atoms[i].name)) goto found;
1492           }
1493      }
1494
1495    cnp_debug("Didn't find a target\n");
1496    return EINA_TRUE;
1497
1498 found:
1499    cnp_debug("Found a target we'd like: %s\n", _x11_atoms[i].name);
1500    cnp_debug("0x%x\n", drop->win);
1501
1502    act = _x11_dnd_action_map(drop->action);
1503    
1504    if (i == CNP_ATOM_text_urilist)
1505      {
1506         cnp_debug("We found a URI... (%scached) %s\n",
1507                   savedtypes.imgfile ? "" : "not ",
1508                   savedtypes.imgfile);
1509         if (savedtypes.imgfile)
1510           {
1511              ddata.x = savedtypes.x;
1512              ddata.y = savedtypes.y;
1513              ddata.action = act;
1514
1515              /* If it's markup that also supports images */
1516              if ((dropable->types & ELM_SEL_FORMAT_MARKUP) &&
1517                  (dropable->types & ELM_SEL_FORMAT_IMAGE))
1518                {
1519                   ddata.format = ELM_SEL_FORMAT_MARKUP;
1520                   ddata.data = savedtypes.imgfile;
1521                   cnp_debug("Insert %s\n", (char *)ddata.data);
1522                   if (dropable->dropcb) dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1523                   ecore_x_dnd_send_finished();
1524                   if (savedtypes.imgfile) free(savedtypes.imgfile);
1525                   savedtypes.imgfile = NULL;
1526
1527                   return EINA_TRUE;
1528                }
1529              else if (dropable->types & ELM_SEL_FORMAT_IMAGE)
1530                {
1531                   cnp_debug("Doing image insert (%s)\n", savedtypes.imgfile);
1532                   ddata.format = ELM_SEL_FORMAT_IMAGE;
1533                   ddata.data = (char *)savedtypes.imgfile;
1534                   dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1535                   ecore_x_dnd_send_finished();
1536                   if (savedtypes.imgfile) free(savedtypes.imgfile);
1537                   savedtypes.imgfile = NULL;
1538
1539                   return EINA_TRUE;
1540                }
1541              else
1542                {
1543                   cnp_debug("Item doesn't support images... passing\n");
1544                   return EINA_TRUE;
1545                }
1546           }
1547         else if (savedtypes.textreq)
1548           {
1549              /* Already asked: Pretend we asked now, and paste immediately when
1550               * it comes in */
1551              cnp_debug("textreq <%d>\n", __LINE__);
1552              ddata.x = savedtypes.x;
1553              ddata.y = savedtypes.y;
1554              ddata.data = _x11_selections[ELM_SEL_TYPE_PRIMARY].selbuf;
1555              dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1556              ecore_x_dnd_send_finished();
1557              return EINA_TRUE;
1558           }
1559      }
1560
1561    cnp_debug("doing a request then\n");
1562    _x11_selections[ELM_SEL_TYPE_XDND].xwin = drop->win;
1563    _x11_selections[ELM_SEL_TYPE_XDND].requestwidget = dropable->obj;
1564    _x11_selections[ELM_SEL_TYPE_XDND].requestformat = ELM_SEL_FORMAT_MARKUP;
1565    _x11_selections[ELM_SEL_TYPE_XDND].active = EINA_TRUE;
1566    _x11_selections[ELM_SEL_TYPE_XDND].action = act;
1567
1568    ecore_x_selection_xdnd_request(drop->win, _x11_atoms[i].name);
1569    return EINA_TRUE;
1570 }
1571
1572 static Eina_Bool
1573 _x11_dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1574 {
1575    Ecore_X_Event_Xdnd_Status *status = ev;
1576    doaccept = EINA_FALSE;
1577
1578    /* Only thing we care about: will accept */
1579    if ((status) && (status->will_accept))
1580      {
1581         cnp_debug("Will accept\n");
1582         doaccept = EINA_TRUE;
1583      }
1584    /* Won't accept */
1585    else
1586      {
1587         cnp_debug("Won't accept accept\n");
1588      }
1589    if (dragacceptcb)
1590      dragacceptcb(dragacceptdata, _x11_selections[ELM_SEL_TYPE_XDND].widget,
1591                   doaccept);
1592    return EINA_TRUE;
1593 }
1594
1595 static Eina_Bool
1596 _drag_cancel_animate(void *data __UNUSED__, double pos)
1597 {  /* Animation to "move back" drag-window */
1598    if (pos >= 0.99)
1599      {
1600         evas_object_del(data);
1601         return ECORE_CALLBACK_CANCEL;
1602      }
1603    else
1604      {
1605         int x, y;
1606         x = dragwin_x_end - (pos * (dragwin_x_end - dragwin_x_start));
1607         y = dragwin_y_end - (pos * (dragwin_y_end - dragwin_y_start));
1608         evas_object_move(data, x, y);
1609      }
1610
1611    return ECORE_CALLBACK_RENEW;
1612 }
1613
1614 static Eina_Bool
1615 _x11_drag_mouse_up(void *data, int etype __UNUSED__, void *event)
1616 {
1617    Ecore_X_Window xwin = (Ecore_X_Window)(long)data;
1618    Ecore_Event_Mouse_Button *ev = event;
1619
1620    if ((ev->buttons == 1) &&
1621        (ev->event_window == xwin))
1622      {
1623         Eina_Bool have_drops = EINA_FALSE;
1624         Eina_List *l;
1625         Dropable *dropable;
1626
1627         ecore_x_pointer_ungrab();
1628         if (handler_up)
1629           {
1630              ecore_event_handler_del(handler_up);
1631              handler_up = NULL;
1632           }
1633         if (handler_status)
1634           {
1635              ecore_event_handler_del(handler_status);
1636              handler_status = NULL;
1637           }
1638         ecore_x_dnd_self_drop();
1639
1640         cnp_debug("mouse up, xwin=%#llx\n", (unsigned long long)xwin);
1641
1642         EINA_LIST_FOREACH(drops, l, dropable)
1643           {
1644              if (xwin == _x11_elm_widget_xwin_get(dropable->obj))
1645                {
1646                   have_drops = EINA_TRUE;
1647                   break;
1648                }
1649           }
1650         if (!have_drops) ecore_x_dnd_aware_set(xwin, EINA_FALSE);
1651         if (dragdonecb) dragdonecb(dragdonedata, dragwidget);
1652         if (dragwin)
1653           {
1654              if (!doaccept)
1655                {  /* Commit animation when drag cancelled */
1656                   /* Record final position of dragwin, then do animation */
1657                   ecore_animator_timeline_add(0.3,
1658                         _drag_cancel_animate, dragwin);
1659                }
1660              else
1661                {  /* No animation drop was committed */
1662                   evas_object_del(dragwin);
1663                }
1664
1665              dragwin = NULL;  /* if not freed here, free in end of anim */
1666           }
1667
1668         dragdonecb = NULL;
1669         dragacceptcb = NULL;
1670         dragposcb = NULL;
1671         dragwidget = NULL;
1672         doaccept = EINA_FALSE;
1673         /*  moved to _drag_cancel_animate
1674         if (dragwin)
1675           {
1676              evas_object_del(dragwin);
1677              dragwin = NULL;
1678           }
1679           */
1680      }
1681    return EINA_TRUE;
1682 }
1683
1684 static void
1685 _x11_drag_move(void *data __UNUSED__, Ecore_X_Xdnd_Position *pos)
1686 {
1687    evas_object_move(dragwin,
1688                     pos->position.x - _dragx, pos->position.y - _dragy);
1689    dragwin_x_end = pos->position.x - _dragx;
1690    dragwin_y_end = pos->position.y - _dragy;
1691    cnp_debug("dragevas: %p -> %p\n",
1692           dragwidget,
1693           evas_object_evas_get(dragwidget));
1694    if (dragposcb)
1695      dragposcb(dragposdata, dragwidget, pos->position.x, pos->position.y,
1696                dragaction);
1697 }
1698
1699 static Ecore_X_Window
1700 _x11_elm_widget_xwin_get(const Evas_Object *obj)
1701 {
1702    Evas_Object *top;
1703    Ecore_X_Window xwin = 0;
1704
1705    top = elm_widget_top_get(obj);
1706    if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(obj));
1707    if (top) xwin = elm_win_xwindow_get(top);
1708    if (!xwin)
1709      {
1710         Ecore_Evas *ee;
1711         Evas *evas = evas_object_evas_get(obj);
1712         if (!evas) return 0;
1713         ee = ecore_evas_ecore_evas_get(evas);
1714         if (!ee) return 0;
1715         xwin = _elm_ee_xwin_get(ee);
1716      }
1717    return xwin;
1718 }
1719
1720 static Eina_Bool
1721 _x11_elm_cnp_init(void)
1722 {
1723    int i;
1724    static int _init_count = 0;
1725
1726    if (_init_count > 0) return EINA_TRUE;
1727    _init_count++;
1728    for (i = 0; i < CNP_N_ATOMS; i++)
1729      {
1730         _x11_atoms[i].atom = ecore_x_atom_get(_x11_atoms[i].name);
1731         ecore_x_selection_converter_atom_add
1732           (_x11_atoms[i].atom, _x11_atoms[i].converter);
1733      }
1734    //XXX delete handlers?
1735    ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, _x11_selection_clear, NULL);
1736    ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, _x11_selection_notify, NULL);
1737    return EINA_TRUE;
1738 }
1739
1740 static Eina_Bool
1741 _x11_elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, const void *selbuf, size_t buflen)
1742 {
1743    Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
1744    X11_Cnp_Selection *sel;
1745
1746    _x11_elm_cnp_init();
1747    if ((!selbuf) && (format != ELM_SEL_FORMAT_IMAGE))
1748      return elm_object_cnp_selection_clear(obj, selection);
1749
1750    sel = _x11_selections + selection;
1751    if (sel->loss_cb) sel->loss_cb(sel->loss_data, selection);
1752    if (sel->widget)
1753      evas_object_event_callback_del_full(sel->widget, EVAS_CALLBACK_DEL,
1754                                          _x11_sel_obj_del, sel);
1755    sel->widget = NULL;
1756    
1757    sel->active = EINA_TRUE;
1758    sel->widget = obj;
1759    sel->xwin = xwin;
1760    if (sel->set) sel->set(xwin, &selection, sizeof(Elm_Sel_Type));
1761    sel->format = format;
1762    sel->loss_cb = NULL;
1763    sel->loss_data = NULL;
1764
1765    evas_object_event_callback_add
1766      (sel->widget, EVAS_CALLBACK_DEL, _x11_sel_obj_del, sel);
1767    
1768    if (selbuf)
1769      {
1770         if (format == ELM_SEL_FORMAT_IMAGE)
1771           {
1772              // selbuf is actual image data, not text/string
1773              sel->selbuf = malloc(buflen + 1);
1774              if (!sel->selbuf)
1775                {
1776                   elm_object_cnp_selection_clear(obj, selection);
1777                   return EINA_FALSE;
1778                }
1779              memcpy(sel->selbuf, selbuf, buflen);
1780              sel->selbuf[buflen] = 0;
1781           }
1782         else
1783           sel->selbuf = strdup((char*)selbuf);
1784      }
1785    else
1786      sel->selbuf = NULL;
1787
1788    return EINA_TRUE;
1789 }
1790
1791 static void
1792 _x11_elm_cnp_selection_loss_callback_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const void *data)
1793 {
1794    X11_Cnp_Selection *sel;
1795    
1796    _x11_elm_cnp_init();
1797    sel = _x11_selections + selection;
1798    sel->loss_cb = func;
1799    sel->loss_data = (void *)data;
1800 }
1801
1802 static Eina_Bool
1803 _x11_elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection)
1804 {
1805    X11_Cnp_Selection *sel;
1806
1807    _x11_elm_cnp_init();
1808    
1809    sel = _x11_selections + selection;
1810
1811    /* No longer this selection: Consider it gone! */
1812    if ((!sel->active) || (sel->widget != obj)) return EINA_TRUE;
1813
1814    if (sel->widget)
1815      evas_object_event_callback_del_full(sel->widget, EVAS_CALLBACK_DEL,
1816                                          _x11_sel_obj_del, sel);
1817    if (sel->requestwidget)
1818      evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
1819                                          _x11_sel_obj_del2, sel);
1820    sel->widget = NULL;
1821    sel->requestwidget = NULL;
1822    sel->loss_cb = NULL;
1823    sel->loss_data = NULL;
1824    
1825    sel->active = EINA_FALSE;
1826    if (sel->selbuf)
1827      {
1828         free(sel->selbuf);
1829         sel->selbuf = NULL;
1830      }
1831    sel->clear();
1832
1833    return EINA_TRUE;
1834 }
1835
1836 static Eina_Bool
1837 _x11_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection,
1838                            Elm_Sel_Format format, Elm_Drop_Cb datacb,
1839                            void *udata)
1840 {
1841    Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
1842    X11_Cnp_Selection *sel;
1843
1844    _x11_elm_cnp_init();
1845    
1846    sel = _x11_selections + selection;
1847
1848    if (sel->requestwidget)
1849      evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
1850                                          _x11_sel_obj_del2, sel);
1851    sel->requestwidget = NULL;
1852    
1853    sel->requestformat = format;
1854    sel->requestwidget = obj;
1855    sel->xwin = xwin;
1856    sel->request(xwin, ECORE_X_SELECTION_TARGET_TARGETS);
1857    sel->datacb = datacb;
1858    sel->udata = udata;
1859
1860    evas_object_event_callback_add
1861      (sel->requestwidget, EVAS_CALLBACK_DEL, _x11_sel_obj_del2, sel);
1862    
1863    return EINA_TRUE;
1864 }
1865
1866 static Eina_Bool
1867 _x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
1868                          Elm_Drag_State entercb, void *enterdata,
1869                          Elm_Drag_State leavecb, void *leavedata,
1870                          Elm_Drag_Pos poscb, void *posdata,
1871                          Elm_Drop_Cb dropcb, void *cbdata)
1872 {
1873    Dropable *drop, *dropable;
1874    Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
1875    Eina_List *item, *l;
1876    int first;
1877    Eina_Bool have_drops = EINA_FALSE;
1878    
1879    _x11_elm_cnp_init();
1880
1881    /* TODO: check if obj is already a drop target. Do not add twice! */
1882
1883    /* Is this the first? */
1884    EINA_LIST_FOREACH(drops, l, dropable)
1885      {
1886         if (xwin == _x11_elm_widget_xwin_get(dropable->obj))
1887           {
1888              have_drops = EINA_TRUE;
1889              break;
1890           }
1891      }
1892    first = (!drops) ? 1 : 0;
1893
1894    EINA_LIST_FOREACH(drops, item, drop)
1895      {
1896         if (drop->obj == obj)
1897           {
1898              /* Update: Not a new one */
1899              drop->dropcb = dropcb;
1900              drop->cbdata = cbdata;
1901              drop->types = format;
1902              return EINA_TRUE;
1903           }
1904      }
1905
1906    /* Create new drop */
1907    drop = calloc(1, sizeof(Dropable));
1908    if (!drop) return EINA_FALSE;
1909    /* FIXME: Check for eina's deranged error method */
1910    drops = eina_list_append(drops, drop);
1911
1912    if (!drops/* || or other error */)
1913      {
1914         free(drop);
1915         return EINA_FALSE;
1916      }
1917    drop->entercb = entercb;
1918    drop->enterdata = enterdata;
1919    drop->leavecb = leavecb;
1920    drop->leavedata = leavedata;
1921    drop->poscb = poscb;
1922    drop->posdata = posdata;
1923    drop->dropcb = dropcb;
1924    drop->cbdata = cbdata;
1925    drop->types = format;
1926    drop->obj = obj;
1927
1928    evas_object_data_set(obj, "dropable", drop);
1929    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1930                                   /* I love C and varargs */
1931                                   (Evas_Object_Event_Cb)elm_drop_target_del,
1932                                   obj);
1933    if (!have_drops) ecore_x_dnd_aware_set(xwin, EINA_TRUE);
1934    
1935    /* TODO BUG: should handle dnd-aware per window, not just the first
1936     * window that requested it! */
1937    /* If not the first: We're done */
1938    if (!first) return EINA_TRUE;
1939
1940
1941    cnp_debug("Adding drop target calls xwin=%#llx\n", (unsigned long long)xwin);
1942    handler_enter = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
1943                                            _x11_dnd_enter, NULL);
1944    handler_leave = ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE,
1945                                            _x11_dnd_leave, NULL);
1946    handler_pos = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
1947                                          _x11_dnd_position, NULL);
1948    handler_drop = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
1949                                           _x11_dnd_drop, NULL);
1950    return EINA_TRUE;
1951 }
1952
1953 static Eina_Bool
1954 _x11_elm_drop_target_del(Evas_Object *obj)
1955 {
1956    Dropable *dropable;
1957    Eina_List *l;
1958    Ecore_X_Window xwin;
1959    Eina_Bool have_drops = EINA_FALSE;
1960
1961    _x11_elm_cnp_init();
1962    
1963    dropable = evas_object_data_get(obj, "dropable");
1964    if (dropable)
1965      {
1966         drops = eina_list_remove(drops, dropable);
1967         evas_object_data_del(obj, "dropable");
1968         free(dropable);
1969         dropable = NULL;
1970      }
1971    else return EINA_FALSE;
1972
1973    evas_object_event_callback_del(obj, EVAS_CALLBACK_FREE,
1974                                   (Evas_Object_Event_Cb)elm_drop_target_del);
1975    
1976    /* TODO BUG: we should handle dnd-aware per window, not just the last that reelased it */
1977
1978    /* If still drops there: All fine.. continue */
1979    if (drops) return EINA_TRUE;
1980
1981    cnp_debug("Disabling DND\n");
1982    xwin = _x11_elm_widget_xwin_get(obj);
1983    EINA_LIST_FOREACH(drops, l, dropable)
1984      {
1985         if (xwin == _x11_elm_widget_xwin_get(dropable->obj))
1986           {
1987              have_drops = EINA_TRUE;
1988              break;
1989           }
1990      }
1991    if (!have_drops) ecore_x_dnd_aware_set(xwin, EINA_FALSE);
1992
1993    if (!drops)
1994      {
1995         if (handler_pos)
1996           {
1997              ecore_event_handler_del(handler_pos);
1998              handler_pos = NULL;
1999           }
2000         if (handler_drop)
2001           {
2002              ecore_event_handler_del(handler_drop);
2003              handler_drop = NULL;
2004           }
2005         if (handler_enter)
2006           {
2007              ecore_event_handler_del(handler_enter);
2008              handler_enter = NULL;
2009           }
2010         if (handler_leave)
2011           {
2012              ecore_event_handler_del(handler_leave);
2013              handler_leave = NULL;
2014           }
2015      }
2016
2017    if (savedtypes.imgfile) free(savedtypes.imgfile);
2018    savedtypes.imgfile = NULL;
2019
2020    return EINA_TRUE;
2021 }
2022
2023 static void
2024 _x11_drag_target_del(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *info __UNUSED__)
2025 {
2026    X11_Cnp_Selection *sel = _x11_selections + ELM_SEL_TYPE_XDND;
2027
2028    if (dragwidget == obj)
2029      {
2030         sel->widget = NULL;
2031         dragwidget = NULL;
2032      }
2033 }
2034
2035 static  Eina_Bool
2036 _x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data,
2037                     Elm_Xdnd_Action action,
2038                     Elm_Drag_Icon_Create_Cb createicon, void *createdata,
2039                     Elm_Drag_Pos dragpos, void *dragdata,
2040                     Elm_Drag_Accept acceptcb, void *acceptdata,
2041                     Elm_Drag_State dragdone, void *donecbdata)
2042 {
2043    Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
2044    X11_Cnp_Selection *sel;
2045    Elm_Sel_Type xdnd = ELM_SEL_TYPE_XDND;
2046    Ecore_Evas *ee;
2047    int x, y, x2 = 0, y2 = 0, x3, y3;
2048    Evas_Object *icon = NULL;
2049    int w, h;
2050    Ecore_X_Atom actx;
2051
2052    _x11_elm_cnp_init();
2053
2054    cnp_debug("starting drag... %p\n", obj);
2055
2056    if (dragwin)
2057      {
2058         cnp_debug("another obj is dragging...\n");
2059         return EINA_FALSE;
2060      }
2061
2062    ecore_x_dnd_type_set(xwin, "text/uri-list", EINA_TRUE);
2063    sel = _x11_selections + ELM_SEL_TYPE_XDND;
2064    sel->active = EINA_TRUE;
2065    sel->widget = obj;
2066    sel->format = format;
2067    sel->selbuf = data ? strdup(data) : NULL;
2068    sel->action = action;
2069    dragwidget = obj;
2070    dragaction = action;
2071
2072    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
2073                                   _x11_drag_target_del, obj);
2074    /* TODO BUG: should NEVER have these as globals! They should be per context (window). */
2075    dragposcb = dragpos;
2076    dragposdata = dragdata;
2077    dragacceptcb = acceptcb;
2078    dragacceptdata = acceptdata;
2079    dragdonecb = dragdone;
2080    dragdonedata = donecbdata;
2081    /* TODO BUG: should increase dnd-awareness, in case it's drop target as well. See _x11_drag_mouse_up() */
2082    ecore_x_dnd_aware_set(xwin, EINA_TRUE);
2083    ecore_x_dnd_callback_pos_update_set(_x11_drag_move, NULL);
2084    ecore_x_dnd_self_begin(xwin, (unsigned char *)&xdnd, sizeof(Elm_Sel_Type));
2085    actx = _x11_dnd_action_rev_map(dragaction);
2086    ecore_x_dnd_source_action_set(actx);
2087    ecore_x_pointer_grab(xwin);
2088    handler_up = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
2089                                         _x11_drag_mouse_up,
2090                                         (void *)(long)xwin);
2091    handler_status = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
2092                                             _x11_dnd_status, NULL);
2093    dragwin = elm_win_add(NULL, "Elm-Drag", ELM_WIN_UTILITY);
2094    elm_win_alpha_set(dragwin, EINA_TRUE);
2095    elm_win_override_set(dragwin, EINA_TRUE);
2096
2097    Evas_Object *win = elm_widget_top_get(obj);
2098    if (win && !strcmp(evas_object_type_get(win), "elm_win"))
2099       elm_win_rotation_set(dragwin, elm_win_rotation_get(win));
2100
2101    if (createicon)
2102      {
2103         Evas_Coord xoff = 0, yoff = 0;
2104
2105         icon = createicon(createdata, dragwin, &xoff, &yoff);
2106         if (icon)
2107           {
2108              x2 = xoff;
2109              y2 = yoff;
2110              evas_object_geometry_get(icon, NULL, NULL, &w, &h);
2111           }
2112      }
2113    else
2114      {
2115         icon = elm_icon_add(dragwin);
2116         evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2117         evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL);
2118         // need to resize
2119      }
2120    elm_win_resize_object_add(dragwin, icon);
2121
2122    /* Position subwindow appropriately */
2123    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
2124    ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
2125    x += x2;
2126    y += y2;
2127    dragwin_x_start = dragwin_x_end = x;
2128    dragwin_y_start = dragwin_y_end = y;
2129    evas_object_move(dragwin, x, y);
2130    evas_object_resize(dragwin, w, h);
2131
2132    evas_object_show(icon);
2133    evas_object_show(dragwin);
2134
2135    evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x3, &y3);
2136    _dragx = x3 - x2;
2137    _dragy = y3 - y2;
2138
2139    return EINA_TRUE;
2140 }
2141
2142 static Eina_Bool
2143 _x11_elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action)
2144 {
2145    Ecore_X_Atom actx;
2146    
2147    _x11_elm_cnp_init();
2148    if (!dragwin) return EINA_FALSE;
2149    
2150    if (dragwidget != obj) return EINA_FALSE;
2151    if (dragaction == action) return EINA_TRUE;
2152    dragaction = action;
2153    actx = _x11_dnd_action_rev_map(dragaction);
2154    ecore_x_dnd_source_action_set(actx);
2155    return EINA_TRUE;
2156 }
2157
2158 static Eina_Bool
2159 _x11_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__)
2160 {
2161    _x11_elm_cnp_init();
2162    return !!ecore_x_selection_owner_get(ECORE_X_ATOM_SELECTION_CLIPBOARD);
2163 }
2164
2165 #endif
2166
2167 #ifdef HAVE_ELEMENTARY_WAYLAND
2168 typedef struct _Wl_Cnp_Selection Wl_Cnp_Selection;
2169
2170 struct _Wl_Cnp_Selection
2171 {
2172    char *selbuf;
2173    int buflen;
2174
2175    Evas_Object *widget;
2176    Evas_Object *requestwidget;
2177 };
2178
2179 static Eina_Bool _wl_elm_cnp_init(void);
2180
2181 static Wl_Cnp_Selection wl_cnp_selection = {0, 0, NULL, NULL};
2182 static void _wl_sel_obj_del2(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
2183 static Eina_Bool _wl_elm_cnp_selection_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, const void *selbuf, size_t buflen);
2184 static Eina_Bool _wl_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, Elm_Drop_Cb datacb __UNUSED__, void *udata __UNUSED__);
2185 static Eina_Bool _wl_selection_send(void *udata, int type __UNUSED__, void *event);
2186 static Eina_Bool _wl_selection_receive(void *udata, int type __UNUSED__, void *event);
2187
2188 static void
2189 _wl_sel_obj_del2(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
2190 {
2191    Wl_Cnp_Selection *sel = data;
2192    if (sel->requestwidget == obj) sel->requestwidget = NULL;
2193 }
2194
2195 static Eina_Bool 
2196 _wl_elm_cnp_selection_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, const void *selbuf, size_t buflen)
2197 {
2198    const char *types[10] = {0, };
2199
2200    _wl_elm_cnp_init();
2201
2202    /* TODO: other EML_SEL_TYPE and ELM_SEL_FORMAT */
2203    if (ELM_SEL_TYPE_CLIPBOARD == selection) 
2204      {
2205         types[0] = "text/plain;charset=utf-8";
2206         ecore_wl_dnd_set_selection(ecore_wl_dnd_get(), types);
2207
2208         if (wl_cnp_selection.selbuf) free(wl_cnp_selection.selbuf);
2209         wl_cnp_selection.selbuf = strdup((char*)selbuf);
2210         wl_cnp_selection.buflen = buflen;
2211         return EINA_TRUE;
2212      }
2213
2214    return EINA_FALSE;
2215 }
2216
2217 static Eina_Bool 
2218 _wl_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, Elm_Drop_Cb datacb __UNUSED__, void *udata __UNUSED__)
2219 {
2220    _wl_elm_cnp_init();
2221
2222    /* For now, just avoid overlapped request */
2223    if (wl_cnp_selection.requestwidget) return EINA_FALSE;
2224
2225    /* TODO: other EML_SEL_TYPE and ELM_SEL_FORMAT */
2226    if (ELM_SEL_TYPE_CLIPBOARD == selection)
2227      {
2228         wl_cnp_selection.requestwidget = obj;
2229         evas_object_event_callback_add(wl_cnp_selection.requestwidget, EVAS_CALLBACK_DEL,
2230                                        _wl_sel_obj_del2, &wl_cnp_selection);
2231         ecore_wl_dnd_get_selection(ecore_wl_dnd_get(), "text/plain;charset=utf-8");
2232      }
2233    return EINA_TRUE;
2234 }
2235
2236 static Eina_Bool
2237 _wl_selection_send(void *udata, int type __UNUSED__, void *event)
2238 {
2239    char *buf;
2240    int ret, len_remained;
2241    int len_written = 0;
2242    Wl_Cnp_Selection *sel = udata;
2243    Ecore_Wl_Event_Data_Source_Send *ev = event;
2244
2245    _wl_elm_cnp_init();
2246
2247    len_remained = sel->buflen;
2248    buf = sel->selbuf;
2249
2250    while (len_written < sel->buflen)
2251      {
2252         ret = write(ev->fd, buf, len_remained);
2253         if (ret == -1) break;
2254         buf += ret;
2255         len_written += ret;
2256         len_remained -= ret;
2257      }
2258
2259    close(ev->fd);
2260    return ECORE_CALLBACK_PASS_ON;
2261 }
2262
2263 static Eina_Bool
2264 _wl_selection_receive(void *udata, int type __UNUSED__, void *event)
2265 {
2266    Wl_Cnp_Selection *sel = udata;
2267    Ecore_Wl_Event_Selection_Data_Ready *ev = event;
2268
2269    _wl_elm_cnp_init();
2270
2271    if (sel->requestwidget)
2272      {
2273         if (!ev->done)
2274           {
2275              /* TODO BUG: should never NEVER assume it's an elm_entry! */
2276              _elm_entry_entry_paste(sel->requestwidget, ev->data);
2277           }
2278         else
2279           {
2280              evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
2281                                                  _wl_sel_obj_del2, sel);
2282              sel->requestwidget = NULL;
2283           }
2284      }
2285
2286    return ECORE_CALLBACK_PASS_ON;
2287 }
2288
2289 static Eina_Bool 
2290 _wl_elm_cnp_init(void)
2291 {
2292    static int _init_count = 0;
2293
2294    if (_init_count > 0) return EINA_TRUE;
2295    _init_count++;
2296
2297    ecore_event_handler_add(ECORE_WL_EVENT_DATA_SOURCE_SEND, 
2298                            _wl_selection_send, &wl_cnp_selection);
2299    ecore_event_handler_add(ECORE_WL_EVENT_SELECTION_DATA_READY, 
2300                            _wl_selection_receive, &wl_cnp_selection);
2301
2302    return EINA_TRUE;
2303 }
2304 #endif
2305
2306
2307
2308
2309
2310
2311 ////////////////////////////////////////////////////////////////////////////
2312 // for local (Within 1 app/process) cnp (used by fb as fallback
2313 ////////////////////////////////////////////////////////////////////////////
2314 #if 1
2315 typedef struct _Local_Selinfo Local_Selinfo;
2316
2317 struct _Local_Selinfo
2318 {
2319    Elm_Sel_Format format;
2320    struct {
2321       void *buf;
2322       size_t size;
2323    } sel;
2324    struct {
2325       Evas_Object *obj;
2326       Elm_Drop_Cb func;
2327       void *data;
2328       Ecore_Job *job;
2329    } get;
2330 };
2331
2332 // for ELM_SEL_TYPE_PRIMARY, ELM_SEL_TYPE_SECONDARY, ELM_SEL_TYPE_XDND,
2333 // ELM_SEL_TYPE_CLIPBOARD
2334 static Local_Selinfo _local_selinfo[4];
2335
2336 static void       _local_get_job(void *data);
2337
2338 static Eina_Bool  _local_elm_cnp_init(void);
2339 static Eina_Bool  _local_elm_cnp_selection_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Sel_Format format, const void *selbuf, size_t buflen);
2340 static void       _local_elm_cnp_selection_loss_callback_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection __UNUSED__, Elm_Selection_Loss_Cb func __UNUSED__, const void *data __UNUSED__);
2341 static Eina_Bool  _local_elm_object_cnp_selection_clear(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection);
2342 static Eina_Bool  _local_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, Elm_Drop_Cb datacb, void *udata);
2343 static  Eina_Bool _local_elm_drop_target_add(Evas_Object *obj __UNUSED__, Elm_Sel_Format format __UNUSED__,
2344                                              Elm_Drag_State entercb __UNUSED__, void *enterdata __UNUSED__,
2345                                              Elm_Drag_State leavecb __UNUSED__, void *leavedata __UNUSED__,
2346                                              Elm_Drag_Pos poscb __UNUSED__, void *posdata __UNUSED__,
2347                                              Elm_Drop_Cb dropcb __UNUSED__, void *cbdata __UNUSED__);
2348 static  Eina_Bool _local_elm_drop_target_del(Evas_Object *obj __UNUSED__);
2349 static Eina_Bool  _local_elm_drag_start(Evas_Object *obj __UNUSED__,
2350                                         Elm_Sel_Format format __UNUSED__,
2351                                         const char *data __UNUSED__,
2352                                         Elm_Xdnd_Action action __UNUSED__,
2353                                         Elm_Drag_Icon_Create_Cb createicon __UNUSED__,
2354                                         void *createdata __UNUSED__,
2355                                         Elm_Drag_Pos dragpos __UNUSED__,
2356                                         void *dragdata __UNUSED__,
2357                                         Elm_Drag_Accept acceptcb __UNUSED__,
2358                                         void *acceptdata __UNUSED__,
2359                                         Elm_Drag_State dragdone __UNUSED__,
2360                                         void *donecbdata __UNUSED__);
2361 static Eina_Bool  _local_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__);
2362
2363 static void
2364 _local_get_job(void *data)
2365 {
2366    Local_Selinfo *info = data;
2367    Elm_Selection_Data ev;
2368    
2369    info->get.job = NULL;
2370    ev.x = 0;
2371    ev.y = 0;
2372    ev.format = info->format;
2373    ev.data = info->sel.buf;
2374    ev.len = info->sel.size;
2375    ev.action = ELM_XDND_ACTION_UNKNOWN;
2376    if (info->get.func)
2377      info->get.func(info->get.data, info->get.obj, &ev);
2378 }
2379
2380 static Eina_Bool
2381 _local_elm_cnp_init(void)
2382 {
2383    static int _init_count = 0;
2384    
2385    if (_init_count > 0) return EINA_TRUE;
2386    _init_count++;
2387    memset(&(_local_selinfo), 0, sizeof(_local_selinfo));
2388    return EINA_TRUE;
2389 }
2390
2391 static Eina_Bool
2392 _local_elm_cnp_selection_set(Evas_Object *obj __UNUSED__,
2393                              Elm_Sel_Type selection, Elm_Sel_Format format,
2394                              const void *selbuf, size_t buflen)
2395 {
2396    _local_elm_cnp_init();
2397    if (_local_selinfo[selection].sel.buf)
2398      free(_local_selinfo[selection].sel.buf);
2399    _local_selinfo[selection].format = format;
2400    _local_selinfo[selection].sel.buf = malloc(buflen);
2401    if (_local_selinfo[selection].sel.buf)
2402      {
2403         memcpy(_local_selinfo[selection].sel.buf, selbuf, buflen);
2404         _local_selinfo[selection].sel.size = buflen;
2405      }
2406    else
2407      _local_selinfo[selection].sel.size = 0;
2408    return EINA_TRUE;
2409 }
2410
2411 static void
2412 _local_elm_cnp_selection_loss_callback_set(Evas_Object *obj __UNUSED__,
2413                                            Elm_Sel_Type selection __UNUSED__,
2414                                            Elm_Selection_Loss_Cb func __UNUSED__,
2415                                            const void *data __UNUSED__)
2416 {
2417    _local_elm_cnp_init();
2418    // this doesnt need to do anything as we never lose selection to anyone
2419    // as thisis local
2420 }
2421
2422 static Eina_Bool
2423 _local_elm_object_cnp_selection_clear(Evas_Object *obj __UNUSED__,
2424                                       Elm_Sel_Type selection)
2425 {
2426    _local_elm_cnp_init();
2427    if (_local_selinfo[selection].sel.buf)
2428      free(_local_selinfo[selection].sel.buf);
2429    _local_selinfo[selection].sel.buf = NULL;
2430    _local_selinfo[selection].sel.size = 0;
2431    return EINA_TRUE;
2432 }
2433
2434 static Eina_Bool
2435 _local_elm_cnp_selection_get(Evas_Object *obj,
2436                              Elm_Sel_Type selection,
2437                              Elm_Sel_Format format __UNUSED__,
2438                              Elm_Drop_Cb datacb, void *udata)
2439 {
2440    _local_elm_cnp_init();
2441    if (_local_selinfo[selection].get.job)
2442      ecore_job_del(_local_selinfo[selection].get.job);
2443    _local_selinfo[selection].get.obj = obj;
2444    _local_selinfo[selection].get.func = datacb;
2445    _local_selinfo[selection].get.data = udata;
2446    _local_selinfo[selection].get.job = 
2447      ecore_job_add(_local_get_job, &(_local_selinfo[selection]));
2448    return EINA_TRUE;
2449 }
2450
2451 static  Eina_Bool
2452 _local_elm_drop_target_add(Evas_Object *obj __UNUSED__,
2453                            Elm_Sel_Format format __UNUSED__,
2454                            Elm_Drag_State entercb __UNUSED__,
2455                            void *enterdata __UNUSED__,
2456                            Elm_Drag_State leavecb __UNUSED__,
2457                            void *leavedata __UNUSED__,
2458                            Elm_Drag_Pos poscb __UNUSED__,
2459                            void *posdata __UNUSED__,
2460                            Elm_Drop_Cb dropcb __UNUSED__,
2461                            void *cbdata __UNUSED__)
2462 {
2463    // XXX: implement me
2464    _local_elm_cnp_init();
2465    return EINA_FALSE;
2466 }
2467
2468 static  Eina_Bool
2469 _local_elm_drop_target_del(Evas_Object *obj __UNUSED__)
2470 {
2471    // XXX: implement me
2472    _local_elm_cnp_init();
2473    return EINA_FALSE;
2474 }
2475
2476 static Eina_Bool
2477 _local_elm_drag_start(Evas_Object *obj __UNUSED__,
2478                       Elm_Sel_Format format __UNUSED__,
2479                       const char *data __UNUSED__,
2480                       Elm_Xdnd_Action action __UNUSED__,
2481                       Elm_Drag_Icon_Create_Cb createicon __UNUSED__,
2482                       void *createdata __UNUSED__,
2483                       Elm_Drag_Pos dragpos __UNUSED__,
2484                       void *dragdata __UNUSED__,
2485                       Elm_Drag_Accept acceptcb __UNUSED__,
2486                       void *acceptdata __UNUSED__,
2487                       Elm_Drag_State dragdone __UNUSED__,
2488                       void *donecbdata __UNUSED__)
2489 {
2490    // XXX: implement me
2491    _local_elm_cnp_init();
2492    return EINA_FALSE;
2493 }
2494
2495 static Eina_Bool
2496 _local_elm_drag_action_set(Evas_Object *obj __UNUSED__,
2497                            Elm_Xdnd_Action action __UNUSED__)
2498 {
2499    // XXX: implement me
2500    _local_elm_cnp_init();
2501    return EINA_FALSE;
2502 }
2503
2504 static Eina_Bool
2505 _local_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__)
2506 {
2507    _local_elm_cnp_init();
2508    if (_local_selinfo[ELM_SEL_TYPE_CLIPBOARD].sel.buf) return EINA_TRUE;
2509    return EINA_FALSE;
2510 }
2511 #endif
2512
2513
2514
2515
2516
2517
2518 // common internal funcs
2519 ////////////////////////////////////////////////////////////////////////////
2520 static Eina_Bool
2521 _elm_cnp_init(void)
2522 {
2523    if (_elm_cnp_init_count > 0) return EINA_TRUE;
2524    _elm_cnp_init_count++;
2525    text_uri = eina_stringshare_add("text/uri-list");
2526    return EINA_TRUE;
2527 }
2528
2529 /* TODO: this should not be an actual tempfile, but rather encode the object
2530  * as http://dataurl.net/ if it's an image or similar. Evas should support
2531  * decoding it as memfile. */
2532 static Tmp_Info *
2533 _tempfile_new(int size)
2534 {
2535 #ifdef HAVE_MMAN_H
2536    Tmp_Info *info;
2537    const char *tmppath;
2538    mode_t cur_umask;
2539    int len;
2540
2541    info = calloc(1, sizeof(Tmp_Info));
2542    if (!info) return NULL;
2543    tmppath = getenv("TMP");
2544    if (!tmppath) tmppath = P_tmpdir;
2545    len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-");
2546    if (len < 0) goto on_error;
2547    len++;
2548    info->filename = malloc(len);
2549    if (!info->filename) goto on_error;
2550    snprintf(info->filename,len,"%s/%sXXXXXX", tmppath, "elmcnpitem-");
2551    cur_umask = umask(S_IRWXO | S_IRWXG);
2552    info->fd = mkstemp(info->filename);
2553    umask(cur_umask);
2554    if (info->fd < 0) goto on_error;
2555 # ifdef __linux__
2556      {
2557         char *tmp;
2558         /* And before someone says anything see POSIX 1003.1-2008 page 400 */
2559         long pid;
2560         
2561         pid = (long)getpid();
2562         /* Use pid instead of /proc/self: That way if can be passed around */
2563         len = snprintf(NULL,0,"/proc/%li/fd/%i", pid, info->fd);
2564         len++;
2565         tmp = malloc(len);
2566         if (tmp)
2567           {
2568              snprintf(tmp,len, "/proc/%li/fd/%i", pid, info->fd);
2569              unlink(info->filename);
2570              free(info->filename);
2571              info->filename = tmp;
2572           }
2573      }
2574 # endif
2575    cnp_debug("filename is %s\n", info->filename);
2576    if (size < 1) goto on_error;
2577    /* Map it in */
2578    if (ftruncate(info->fd, size))
2579      {
2580         perror("ftruncate");
2581         goto on_error;
2582      }
2583    eina_mmap_safety_enabled_set(EINA_TRUE);
2584    info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0);
2585    if (info->map == MAP_FAILED)
2586      {
2587         perror("mmap");
2588         goto on_error;
2589      }
2590    return info;
2591
2592  on_error:
2593    if (info->fd > 0) close(info->fd);
2594    info->fd = -1;
2595    /* Set map to NULL and return */
2596    info->map = NULL;
2597    info->len = 0;
2598    free(info->filename);
2599    free(info);
2600    return NULL;
2601 #else
2602    (void) size;
2603    return NULL;
2604 #endif
2605 }
2606
2607 static int
2608 _tmpinfo_free(Tmp_Info *info)
2609 {
2610    if (!info) return 0;
2611    free(info->filename);
2612    free(info);
2613    return 0;
2614 }
2615
2616 static Eina_Bool
2617 _pasteimage_append(char *file, Evas_Object *entry)
2618 {
2619    char *entrytag;
2620    int len;
2621    /* TODO BUG: shouldn't define absize=240x180. Prefer data:// instead of href:// -- may need support for evas. See  http://dataurl.net/ */
2622    static const char *tagstring = "<item absize=240x180 href=file://%s></item>";
2623
2624    if ((!file) || (!entry)) return EINA_FALSE;
2625    len = strlen(tagstring)+strlen(file);
2626    entrytag = alloca(len + 1);
2627    snprintf(entrytag, len + 1, tagstring, file);
2628    /* TODO BUG: should never NEVER assume it's an elm_entry! */
2629    _elm_entry_entry_paste(entry, entrytag);
2630    return EINA_TRUE;
2631 }
2632
2633 // TIZEN ONLY
2634 static void
2635 _entry_insert_filter(Evas_Object *entry, char *str)
2636 {
2637    if (!entry || !str)
2638      return;
2639
2640    char *insertStr = str;
2641
2642    if (elm_entry_single_line_get(entry))
2643      {
2644         Eina_Strbuf *buf = eina_strbuf_new();
2645         if (buf)
2646           {
2647              eina_strbuf_append(buf, insertStr);
2648              eina_strbuf_replace_all(buf, "<br>", "");
2649              eina_strbuf_replace_all(buf, "<br/>", "");
2650              eina_strbuf_replace_all(buf, "<ps/>", "");
2651              insertStr = eina_strbuf_string_steal(buf);
2652              eina_strbuf_free(buf);
2653           }
2654      }
2655    cnp_debug("remove break tag: %s\n", insertStr);
2656
2657    _elm_entry_entry_paste(entry, insertStr);
2658
2659    if (insertStr != str)
2660      free(insertStr);
2661 }
2662 //
2663
2664 ////////////////////////////////////////////////////////////////////////////
2665 ////////////////////////////////////////////////////////////////////////////
2666 ////////////////////////////////////////////////////////////////////////////
2667 // common exposed funcs
2668 ////////////////////////////////////////////////////////////////////////////
2669 ////////////////////////////////////////////////////////////////////////////
2670 ////////////////////////////////////////////////////////////////////////////
2671 EAPI Eina_Bool
2672 elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection,
2673                       Elm_Sel_Format format, const void *selbuf, size_t buflen)
2674 {
2675    if (selection > ELM_SEL_TYPE_CLIPBOARD) return EINA_FALSE;
2676    if (!_elm_cnp_init_count) _elm_cnp_init();
2677 #ifdef HAVE_ELEMENTARY_X
2678    if (_x11_elm_widget_xwin_get(obj))
2679      return _x11_elm_cnp_selection_set(obj, selection, format, selbuf, buflen);
2680 #endif
2681 #ifdef HAVE_ELEMENTARY_WAYLAND
2682    if (elm_win_wl_window_get(obj))
2683       return _wl_elm_cnp_selection_set(obj, selection, format, selbuf, buflen);
2684 #endif
2685    return _local_elm_cnp_selection_set(obj, selection, format, selbuf, buflen);
2686 }
2687
2688 EAPI void
2689 elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type selection,
2690                                     Elm_Selection_Loss_Cb func,
2691                                     const void *data)
2692 {
2693    if (selection > ELM_SEL_TYPE_CLIPBOARD) return;
2694    if (!_elm_cnp_init_count) _elm_cnp_init();
2695 #ifdef HAVE_ELEMENTARY_X
2696    if (_x11_elm_widget_xwin_get(obj))
2697      _x11_elm_cnp_selection_loss_callback_set(obj, selection, func, data);
2698 #endif   
2699    _local_elm_cnp_selection_loss_callback_set(obj, selection, func, data);
2700 }
2701
2702 EAPI Eina_Bool
2703 elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection)
2704 {
2705    if (selection > ELM_SEL_TYPE_CLIPBOARD) return EINA_FALSE;
2706    if (!_elm_cnp_init_count) _elm_cnp_init();
2707 #ifdef HAVE_ELEMENTARY_X
2708    if (_x11_elm_widget_xwin_get(obj))
2709      return _x11_elm_object_cnp_selection_clear(obj, selection);
2710 #endif
2711    return _local_elm_object_cnp_selection_clear(obj, selection);
2712 }
2713
2714 EAPI Eina_Bool
2715 elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection,
2716                       Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata)
2717 {
2718    if (selection > ELM_SEL_TYPE_CLIPBOARD) return EINA_FALSE;
2719    if (!_elm_cnp_init_count) _elm_cnp_init();
2720 #ifdef HAVE_ELEMENTARY_X
2721    if (_x11_elm_widget_xwin_get(obj))
2722      return _x11_elm_cnp_selection_get(obj, selection, format, datacb, udata);
2723 #endif
2724 #ifdef HAVE_ELEMENTARY_WAYLAND
2725    if (elm_win_wl_window_get(obj))
2726       return _wl_elm_cnp_selection_get(obj, selection, format, datacb, udata);
2727 #endif
2728    return _local_elm_cnp_selection_get(obj, selection, format, datacb, udata);
2729 }
2730
2731 ////////////////////////////////////////////////////////////////////////////
2732
2733 /**
2734  * Add a widget as drop target.
2735  */
2736 EAPI Eina_Bool
2737 elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
2738                     Elm_Drag_State entercb, void *enterdata,
2739                     Elm_Drag_State leavecb, void *leavedata,
2740                     Elm_Drag_Pos poscb, void *posdata,
2741                     Elm_Drop_Cb dropcb, void *cbdata)
2742 {
2743    if (!_elm_cnp_init_count) _elm_cnp_init();
2744 #ifdef HAVE_ELEMENTARY_X
2745    if (_x11_elm_widget_xwin_get(obj))
2746      return _x11_elm_drop_target_add(obj, format, entercb, enterdata,
2747                                      leavecb, leavedata, poscb, posdata,
2748                                      dropcb, cbdata);
2749 #endif
2750    return _local_elm_drop_target_add(obj, format, entercb, enterdata,
2751                                      leavecb, leavedata, poscb, posdata,
2752                                      dropcb, cbdata);
2753 }
2754
2755 EAPI Eina_Bool
2756 elm_drop_target_del(Evas_Object *obj)
2757 {
2758    if (!_elm_cnp_init_count) _elm_cnp_init();
2759 #ifdef HAVE_ELEMENTARY_X
2760    if (_x11_elm_widget_xwin_get(obj))
2761      return _x11_elm_drop_target_del(obj);
2762 #endif
2763    return _local_elm_drop_target_del(obj);
2764 }
2765
2766 EAPI Eina_Bool
2767 elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data,
2768                Elm_Xdnd_Action action,
2769                Elm_Drag_Icon_Create_Cb createicon, void *createdata,
2770                Elm_Drag_Pos dragpos, void *dragdata,
2771                Elm_Drag_Accept acceptcb, void *acceptdata,
2772                Elm_Drag_State dragdone, void *donecbdata)
2773 {
2774    if (!_elm_cnp_init_count) _elm_cnp_init();
2775 #ifdef HAVE_ELEMENTARY_X
2776    if (_x11_elm_widget_xwin_get(obj))
2777      return _x11_elm_drag_start(obj, format, data, action, 
2778                                 createicon, createdata, 
2779                                 dragpos, dragdata,
2780                                 acceptcb, acceptdata,
2781                                 dragdone, donecbdata);
2782 #endif
2783    return _local_elm_drag_start(obj, format, data, action,
2784                                 createicon, createdata,
2785                                 dragpos, dragdata,
2786                                 acceptcb, acceptdata,
2787                                 dragdone, donecbdata);
2788 }
2789
2790 EAPI Eina_Bool
2791 elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action)
2792 {
2793    if (!_elm_cnp_init_count) _elm_cnp_init();
2794 #ifdef HAVE_ELEMENTARY_X
2795    if (_x11_elm_widget_xwin_get(obj))
2796      return _x11_elm_drag_action_set(obj, action);
2797 #endif
2798    return _local_elm_drag_action_set(obj, action);
2799 }
2800
2801 EAPI Eina_Bool
2802 elm_selection_selection_has_owner(Evas_Object *obj)
2803 {
2804    if (!_elm_cnp_init_count) _elm_cnp_init();
2805 #ifdef HAVE_ELEMENTARY_X
2806    if (_x11_elm_widget_xwin_get(obj))
2807      return _x11_elm_selection_selection_has_owner(obj);
2808 #endif
2809 #ifdef HAVE_ELEMENTARY_WAYLAND
2810    if (elm_win_wl_window_get(obj))
2811      return ecore_wl_dnd_selection_has_owner(ecore_wl_dnd_get());
2812 #endif
2813    return _local_elm_selection_selection_has_owner(obj);
2814 }
2815
2816 /* START - Support elm containers for Drag and Drop */
2817 /* START - Support elm containers for Drop */
2818 static int
2819 _drop_item_container_cmp(const void *d1,
2820                const void *d2)
2821 {
2822    const Item_Container_Drop_Info *st = d1;
2823    return (((uintptr_t) (st->obj)) - ((uintptr_t) d2));
2824 }
2825
2826 static void
2827 _elm_item_container_pos_cb(void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action)
2828 {  /* obj is the container pointer */
2829    Elm_Object_Item *it = NULL;
2830    int xposret = 0;
2831    int yposret = 0;
2832    Item_Container_Drop_Info *st =
2833       eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
2834
2835    if (st && st->poscb)
2836      {  /* Call container drop func with specific item pointer */
2837         int xo = 0;
2838         int yo = 0;
2839         evas_object_geometry_get(obj, &xo, &yo, NULL, NULL);
2840         if (st->itemgetcb)
2841           it = st->itemgetcb(obj, x+xo, y+yo, &xposret, &yposret);
2842
2843         st->poscb(data, obj, it, x, y, xposret, yposret, action);
2844      }
2845 }
2846
2847 static Eina_Bool
2848 _elm_item_container_drop_cb(void *data, Evas_Object *obj , Elm_Selection_Data *ev)
2849 {  /* obj is the container pointer */
2850    Elm_Object_Item *it = NULL;
2851    int xposret = 0;
2852    int yposret = 0;
2853    Item_Container_Drop_Info *st =
2854       eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
2855
2856    if (st && st->dropcb)
2857      {  /* Call container drop func with specific item pointer */
2858         int xo = 0;
2859         int yo = 0;
2860         evas_object_geometry_get(obj, &xo, &yo, NULL, NULL);
2861         if (st->itemgetcb)
2862           it = st->itemgetcb(obj, ev->x+xo, ev->y+yo, &xposret, &yposret);
2863
2864         return st->dropcb(data, obj, it, ev, xposret, yposret);
2865      }
2866
2867    return EINA_FALSE;
2868 }
2869
2870 static Eina_Bool
2871 elm_drop_item_container_del_internal(Evas_Object *obj, Eina_Bool full)
2872 {
2873    Item_Container_Drop_Info *st =
2874       eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
2875
2876    if (st)
2877      {
2878         elm_drop_target_del(obj);
2879         st->itemgetcb= NULL;
2880         st->poscb = NULL;
2881         st->dropcb = NULL;
2882
2883         if (full)
2884           {
2885              cont_drop_tg = eina_list_remove(cont_drop_tg, st);
2886              free(st);
2887           }
2888
2889         return EINA_TRUE;
2890      }
2891
2892    return EINA_FALSE;
2893 }
2894
2895 EAPI Eina_Bool
2896 elm_drop_item_container_del(Evas_Object *obj)
2897 {
2898    return elm_drop_item_container_del_internal(obj, EINA_TRUE);
2899 }
2900
2901 EAPI Eina_Bool
2902 elm_drop_item_container_add(Evas_Object *obj,
2903       Elm_Sel_Format format,
2904       Elm_Xy_Item_Get_Cb itemgetcb,
2905       Elm_Drag_State entercb, void *enterdata,
2906       Elm_Drag_State leavecb, void *leavedata,
2907       Elm_Drag_Item_Container_Pos poscb, void *posdata,
2908       Elm_Drop_Item_Container_Cb dropcb, void *cbdata)
2909 {
2910    Item_Container_Drop_Info *st;
2911
2912    if (elm_drop_item_container_del_internal(obj, EINA_FALSE))
2913      {  /* Updating info of existing obj */
2914         st = eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
2915         if (!st) return EINA_FALSE;
2916      }
2917    else
2918      {
2919         st = calloc(1, sizeof(*st));
2920         if (!st) return EINA_FALSE;
2921
2922         st->obj = obj;
2923         cont_drop_tg = eina_list_append(cont_drop_tg, st);
2924      }
2925
2926    st->itemgetcb = itemgetcb;
2927    st->poscb = poscb;
2928    st->dropcb = dropcb;
2929    elm_drop_target_add(obj, format,
2930                        entercb, enterdata,
2931                        leavecb, leavedata,
2932                        _elm_item_container_pos_cb, posdata,
2933                        _elm_item_container_drop_cb, cbdata);
2934
2935    return EINA_TRUE;
2936 }
2937 /* END   - Support elm containers for Drop */
2938
2939
2940 /* START - Support elm containers for Drag */
2941 static int
2942 _drag_item_container_cmp(const void *d1,
2943                const void *d2)
2944 {
2945    const Item_Container_Drag_Info *st = d1;
2946    return (((uintptr_t) (st->obj)) - ((uintptr_t) d2));
2947 }
2948
2949 static void
2950 _cont_drag_done_cb(void *data, Evas_Object *obj __UNUSED__)
2951 {
2952    Item_Container_Drag_Info *st = data;
2953    elm_widget_scroll_freeze_pop(st->obj);
2954    if (st->user_info.dragdone) st->user_info.dragdone(st->user_info.donecbdata, dragwidget, doaccept);
2955 }
2956
2957 static Eina_Bool
2958 _cont_obj_drag_start(void *data)
2959 {  /* Start a drag-action when timer expires */
2960    cnp_debug("%s In\n", __FUNCTION__);
2961    Item_Container_Drag_Info *st = data;
2962    st->tm = NULL;
2963    Elm_Drag_User_Info *info = &st->user_info;
2964    elm_widget_scroll_freeze_push(st->obj);
2965    evas_object_event_callback_del_full
2966       (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st);
2967    elm_drag_start(  /* Commit the start only if data_get successful */
2968          st->obj, info->format,
2969          info->data, info->action,
2970          info->createicon, info->createdata,
2971          info->dragpos, info->dragdata,
2972          info->acceptcb, info->acceptdata,
2973          _cont_drag_done_cb, st);
2974
2975    return ECORE_CALLBACK_CANCEL;
2976 }
2977
2978 void
2979 _anim_st_free(Item_Container_Drag_Info *st)
2980 {  /* Stops and free mem of ongoing animation */
2981    if (st)
2982      {
2983         if (st->ea)
2984           {
2985              ecore_animator_del(st->ea);
2986              st->ea = NULL;
2987           }
2988
2989         Anim_Icon *sti;
2990
2991         EINA_LIST_FREE(st->icons, sti)
2992           {
2993              evas_object_del(sti->o);
2994              free(sti);
2995           }
2996
2997         st->icons = NULL;
2998      }
2999 }
3000
3001 static inline Eina_List *
3002 _anim_icons_make(Eina_List *icons)
3003 {  /* Make local copies of all icons, add them to list */
3004    Eina_List *list = NULL, *itr;
3005    Evas_Object *o;
3006
3007    EINA_LIST_FOREACH(icons, itr, o)
3008      {  /* Now add icons to animation window */
3009         Anim_Icon *st = calloc(1, sizeof(*st));
3010         evas_object_geometry_get(o, &st->start_x, &st->start_y, &st->start_w, &st->start_h);
3011         evas_object_show(o);
3012         st->o = o;
3013         list = eina_list_append(list, st);
3014      }
3015
3016    return list;
3017 }
3018
3019 static Eina_Bool
3020 _drag_anim_play(void *data, double pos)
3021 {  /* Impl of the animation of icons, called on frame time */
3022    cnp_debug("%s In\n", __FUNCTION__);
3023    Item_Container_Drag_Info *st = data;
3024    Eina_List *l;
3025    Anim_Icon *sti;
3026
3027    if (st->ea)
3028      {
3029         if (pos > 0.99)
3030           {
3031              st->ea = NULL;  /* Avoid deleting on mouse up */
3032              EINA_LIST_FOREACH(st->icons, l, sti)
3033                 evas_object_hide(sti->o);
3034
3035              _cont_obj_drag_start(st);  /* Start dragging */
3036              return ECORE_CALLBACK_CANCEL;
3037           }
3038
3039         Evas_Coord xm, ym;
3040         evas_pointer_canvas_xy_get(st->e, &xm, &ym);
3041         EINA_LIST_FOREACH(st->icons, l, sti)
3042           {
3043              int x, y, h, w;
3044              w = sti->start_w + ((st->final_icon_w - sti->start_w) * pos);
3045              h = sti->start_h + ((st->final_icon_h - sti->start_h) * pos);
3046              x = sti->start_x - (pos * ((sti->start_x + (w/2) - xm)));
3047              y = sti->start_y - (pos * ((sti->start_y + (h/2) - ym)));
3048              evas_object_move(sti->o, x, y);
3049              evas_object_resize(sti->o, w, h);
3050           }
3051
3052         return ECORE_CALLBACK_RENEW;
3053      }
3054
3055    return ECORE_CALLBACK_CANCEL;
3056 }
3057
3058 static inline Eina_Bool
3059 _drag_anim_start(void *data)
3060 {  /* Start default animation */
3061    cnp_debug("%s In\n", __FUNCTION__);
3062    Item_Container_Drag_Info *st = data;
3063
3064    st->tm = NULL;
3065    /* Now we need to build an (Anim_Icon *) list */
3066    st->icons = _anim_icons_make(st->user_info.icons);
3067    if (st->user_info.createicon)
3068      {
3069         Evas_Object *temp_win = elm_win_add(NULL, "Temp", ELM_WIN_UTILITY);
3070         Evas_Object *final_icon = st->user_info.createicon(st->user_info.createdata, temp_win, NULL, NULL);
3071         evas_object_geometry_get(final_icon, NULL, NULL, &st->final_icon_w, &st->final_icon_h);
3072         evas_object_del(final_icon);
3073         evas_object_del(temp_win);
3074      }
3075    st->ea = ecore_animator_timeline_add(st->anim_tm, _drag_anim_play, st);
3076
3077    return EINA_FALSE;
3078 }
3079
3080 static Eina_Bool
3081 _cont_obj_anim_start(void *data)
3082 {  /* Start a drag-action when timer expires */
3083    cnp_debug("%s In\n", __FUNCTION__);
3084    Item_Container_Drag_Info *st = data;
3085    int xposret, yposret;  /* Unused */
3086    Elm_Object_Item *it = (st->itemgetcb) ?
3087       (st->itemgetcb(st->obj, st->x_down, st->y_down, &xposret, &yposret))
3088       : NULL;
3089
3090    st->tm = NULL;
3091    st->user_info.format = ELM_SEL_FORMAT_TARGETS; /* Default */
3092    st->icons = NULL;
3093    st->user_info.data = NULL;
3094    st->user_info.action = ELM_XDND_ACTION_COPY;  /* Default */
3095
3096    if (!it)   /* Failed to get mouse-down item, abort drag */
3097      return ECORE_CALLBACK_CANCEL;
3098
3099    if (st->data_get)
3100      {  /* collect info then start animation or start dragging */
3101         if(st->data_get(    /* Collect drag info */
3102                  st->obj,      /* The container object */
3103                  it,           /* Drag started on this item */
3104                  &st->user_info))
3105           {
3106              if (st->user_info.icons)
3107                _drag_anim_start(st);
3108              else
3109                {
3110                   if (st->anim_tm)
3111                     {
3112                        // even if we don't manage the icons animation, we have
3113                        // to wait until it is finished before beginning drag.
3114                        st->tm = ecore_timer_add(st->anim_tm, _cont_obj_drag_start, st);
3115                     }
3116                   else
3117                     _cont_obj_drag_start(st);  /* Start dragging, no anim */
3118                }
3119           }
3120      }
3121
3122    return ECORE_CALLBACK_CANCEL;
3123 }
3124
3125 static void
3126 _cont_obj_mouse_down(
3127    void *data,
3128    Evas *e,
3129    Evas_Object *obj __UNUSED__,
3130    void *event_info)
3131 {  /* Launch a timer to start dragging */
3132    Evas_Event_Mouse_Down *ev = event_info;
3133    cnp_debug("%s In - event %X\n", __FUNCTION__, ev->event_flags);
3134    if (ev->button != 1)
3135      return;  /* We only process left-click at the moment */
3136
3137    Item_Container_Drag_Info *st = data;
3138    evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_MOVE,
3139          _cont_obj_mouse_move, st);
3140
3141    evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_UP,
3142          _cont_obj_mouse_up, st);
3143
3144    if (st->tm)
3145      ecore_timer_del(st->tm);
3146
3147    st->e = e;
3148    st->x_down = ev->canvas.x;
3149    st->y_down = ev->canvas.y;
3150    st->tm = ecore_timer_add(st->tm_to_drag, _cont_obj_anim_start, st);
3151 }
3152
3153 static Eina_Bool elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full);
3154
3155 static void
3156 _cont_obj_mouse_move(
3157    void *data,
3158    Evas *e __UNUSED__,
3159    Evas_Object *obj __UNUSED__,
3160    void *event_info)
3161 {  /* Cancel any drag waiting to start on timeout */
3162
3163    cnp_debug("%s In\n", __FUNCTION__);
3164    if (((Evas_Event_Mouse_Move *)event_info)->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
3165      {
3166         cnp_debug("%s event on hold - have to cancel DnD\n", __FUNCTION__);
3167         Item_Container_Drag_Info *st = data;
3168         evas_object_event_callback_del_full
3169            (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st);
3170         evas_object_event_callback_del_full
3171            (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st);
3172         elm_drag_item_container_del_internal(obj, EINA_FALSE);
3173
3174         if (st->tm)
3175           {
3176              ecore_timer_del(st->tm);
3177              st->tm = NULL;
3178           }
3179
3180         _anim_st_free(st);
3181      }
3182    cnp_debug("%s Out\n", __FUNCTION__);
3183 }
3184
3185 static void
3186 _cont_obj_mouse_up(
3187    void *data,
3188    Evas *e __UNUSED__,
3189    Evas_Object *obj __UNUSED__,
3190    void *event_info)
3191 {  /* Cancel any drag waiting to start on timeout */
3192    Item_Container_Drag_Info *st = data;
3193
3194    cnp_debug("%s In\n", __FUNCTION__);
3195    if (((Evas_Event_Mouse_Up *)event_info)->button != 1)
3196      return;  /* We only process left-click at the moment */
3197
3198    evas_object_event_callback_del_full
3199       (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st);
3200    evas_object_event_callback_del_full
3201       (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st);
3202
3203    if (st->tm)
3204      {
3205         ecore_timer_del(st->tm);
3206         st->tm = NULL;
3207      }
3208
3209    _anim_st_free(st);
3210 }
3211
3212 static Eina_Bool
3213 elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full)
3214 {
3215    Item_Container_Drag_Info *st =
3216       eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj);
3217
3218    if (st)
3219      {
3220         if (st->tm)
3221           ecore_timer_del(st->tm);  /* Cancel drag-start timer */
3222
3223         if (st->ea)  /* Cancel ongoing default animation */
3224           _anim_st_free(st);
3225
3226         st->tm = NULL;
3227
3228         if (full)
3229           {
3230              st->itemgetcb = NULL;;
3231              st->data_get = NULL;
3232              evas_object_event_callback_del_full
3233                 (obj, EVAS_CALLBACK_MOUSE_DOWN, _cont_obj_mouse_down, st);
3234              cont_drag_tg = eina_list_remove(cont_drag_tg, st);
3235              free(st);
3236           }
3237
3238         return EINA_TRUE;
3239      }
3240
3241    return EINA_FALSE;
3242 }
3243
3244 EAPI Eina_Bool
3245 elm_drag_item_container_del(Evas_Object *obj)
3246 {
3247    return elm_drag_item_container_del_internal(obj, EINA_TRUE);
3248 }
3249
3250 EAPI Eina_Bool
3251 elm_drag_item_container_add(
3252    Evas_Object *obj,
3253    double anim_tm,
3254    double tm_to_drag,
3255    Elm_Xy_Item_Get_Cb itemgetcb,
3256    Elm_Item_Container_Data_Get_Cb data_get)
3257 {
3258    Item_Container_Drag_Info *st;
3259
3260    if (elm_drag_item_container_del_internal(obj, EINA_FALSE))
3261      {  /* Updating info of existing obj */
3262         st = eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj);
3263         if (!st) return EINA_FALSE;
3264      }
3265    else
3266      {
3267         st = calloc(1, sizeof(*st));
3268         if (!st) return EINA_FALSE;
3269
3270         st->obj = obj;
3271         cont_drag_tg = eina_list_append(cont_drag_tg, st);
3272
3273         /* Register for mouse callback for container to start/abort drag */
3274         evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
3275                                        _cont_obj_mouse_down, st);
3276      }
3277
3278    st->tm = NULL;
3279    st->anim_tm = anim_tm;
3280    st->tm_to_drag = tm_to_drag;
3281    st->itemgetcb = itemgetcb;
3282    st->data_get = data_get;
3283
3284    return EINA_TRUE;
3285 }
3286 /* END   - Support elm containers for Drag */
3287 /* END   - Support elm containers for Drag and Drop */
3288 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 :*/