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