Revert to the original state
[framework/uifw/elementary.git] / src / lib / elm_cnp_helper.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 #include <Elementary.h>
5 #include "elm_priv.h"
6
7 #include <sys/mman.h>
8
9 #ifdef HAVE_ELEMENTARY_X
10
11 #define ARRAYINIT(foo)  [foo] =
12
13 //#define DEBUGON 1
14
15 #ifdef DEBUGON
16 # define cnp_debug(x...) fprintf(stderr, __FILE__": " x)
17 #else
18 # define cnp_debug(x...)
19 #endif
20
21 #define PROVIDER_SET "__elm_cnp_provider_set"
22
23 typedef struct _Paste_Image   Paste_Image;
24 typedef struct _Cnp_Selection Cnp_Selection;
25 typedef struct _Escape        Escape;
26 typedef struct _Tmp_Info      Tmp_Info;
27 typedef struct _Cnp_Atom      Cnp_Atom;
28 typedef struct _Saved_Type    Saved_Type;
29 typedef struct _Dropable      Dropable;
30
31 typedef Eina_Bool (*Converter_Fn_Cb)     (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
32 typedef int       (*Response_Handler_Cb) (Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
33 typedef int       (*Notify_Handler_Cb)   (Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
34
35 enum
36 {
37    CNP_ATOM_TARGETS = 0,
38    CNP_ATOM_text_uri,
39    CNP_ATOM_text_urilist,
40    CNP_ATOM_text_x_vcard,
41    CNP_ATOM_image_png,
42    CNP_ATOM_image_jpeg,
43    CNP_ATOM_image_bmp,
44    CNP_ATOM_image_gif,
45    CNP_ATOM_image_tiff,
46    CNP_ATOM_image_svg,
47    CNP_ATOM_image_xpm,
48    CNP_ATOM_image_tga,
49    CNP_ATOM_image_ppm,
50    CNP_ATOM_XELM,
51    CNP_ATOM_text_html_utf8,
52    CNP_ATOM_text_html,
53    CNP_ATOM_UTF8STRING,
54    CNP_ATOM_STRING,
55    CNP_ATOM_TEXT,
56    CNP_ATOM_text_plain_utf8,
57    CNP_ATOM_text_plain,
58    
59    CNP_N_ATOMS,
60 };
61
62 struct _Paste_Image
63 {
64    Evas_Object *entry;
65    const char  *tag;
66    const char  *file;
67    Evas_Object *img;
68 };
69
70 struct _Cnp_Selection
71 {
72    const char      *debug;
73    Evas_Object     *widget;
74    char            *selbuf;
75    Evas_Object     *requestwidget;
76    void            *udata;
77    Elm_Sel_Format   requestformat;
78    Elm_Drop_Cb      datacb;
79    Eina_Bool      (*set)     (Ecore_X_Window, const void *data, int size);
80    Eina_Bool      (*clear)   (void);
81    void           (*request) (Ecore_X_Window, const char *target);
82
83    Elm_Sel_Format    format;
84    Ecore_X_Selection ecore_sel;
85    
86    Eina_Bool         active : 1;
87 };
88
89 struct _Escape
90 {
91    const char *escape;
92    const char  value;
93 };
94
95 struct _Tmp_Info
96 {
97    char *filename;
98    void *map;
99    int   fd;
100    int   len;
101 };
102
103 struct _Cnp_Atom
104 {
105    const char          *name;
106    Elm_Sel_Format       formats;
107    /* Called by ecore to do conversion */
108    Converter_Fn_Cb      converter;
109    Response_Handler_Cb  response;
110    Notify_Handler_Cb    notify;
111    /* Atom */
112    Ecore_X_Atom         atom;
113 };
114
115 struct _Saved_Type
116 {
117    const char  **types;
118    Paste_Image  *pi;
119    int           ntypes;
120    int           x, y;
121    Eina_Bool     textreq: 1;
122 };
123
124 struct _Dropable
125 {
126    Evas_Object     *obj;
127    /* FIXME: Cache window */
128    Elm_Sel_Format   types;
129    Elm_Drop_Cb      dropcb;
130    void            *cbdata;
131 };
132
133 static Tmp_Info *elm_cnp_tempfile_create(int size);
134 static int tmpinfo_free(Tmp_Info *tmp);
135
136 static Eina_Bool _elm_cnp_init(void);
137 static Eina_Bool selection_clear(void *udata __UNUSED__, int type, void *event);
138 static Eina_Bool selection_notify(void *udata __UNUSED__, int type, void *event);
139 static char *remove_tags(const char *p, int *len);
140 static char *mark_up(const char *start, int inlen, int *lenp);
141
142 static Evas_Object *image_provider(void *images, Evas_Object *entry, const char *item);
143 static void entry_deleted(void *images, Evas *e, Evas_Object *entry, void *unused);
144
145
146 static Eina_Bool targets_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
147 static Eina_Bool text_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
148 static Eina_Bool html_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
149 static Eina_Bool edje_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
150 static Eina_Bool uri_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
151 static Eina_Bool image_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
152 static Eina_Bool vcard_send(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
153
154 static int response_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
155
156 static int notify_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
157 static int notify_handler_text(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
158 static int notify_handler_image(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
159 static int notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
160 static int notify_handler_html(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
161 static int vcard_receive(Cnp_Selection *sed, Ecore_X_Event_Selection_Notify *notify);
162
163 static Paste_Image *pasteimage_alloc(const char *file, int pathlen);
164 static Eina_Bool pasteimage_append(Paste_Image *pi, Evas_Object *entry);
165 static void pasteimage_free(Paste_Image *pi);
166
167 /* Optimisation: Turn this into a 256 byte table:
168  *      then can lookup in one index, not N checks */
169 static const Escape escapes[] = {
170    { "<br>",   '\n' },
171    { "<\t>",   '\t' },
172    { "gt;",    '>'  },
173    { "lt;",    '<'  },
174    { "amp;",   '&'  },
175    { "quot;",  '\'' },
176    { "dquot;", '"'  }
177 };
178 #define N_ESCAPES ((int)(sizeof(escapes) / sizeof(escapes[0])))
179
180 static const char *image_extensions[] =
181 {
182    ".png",
183    ".jpg", ".jpeg", ".jpe", ".jfif", ".jfi",
184    ".bmp",
185    ".xpm",
186    ".ppm", "pgm", ".pbm", ".pnm",
187    ".gif",
188    ".tif", ".tiff",
189    ".svg", ".svg.gz",
190    ".tga", ".targa",
191    
192    NULL
193 };
194
195 static Cnp_Atom atoms[CNP_N_ATOMS] = {
196    [CNP_ATOM_TARGETS] = {
197       "TARGETS",
198       (Elm_Sel_Format) -1, // everything
199       targets_converter,
200       response_handler_targets,
201       notify_handler_targets,
202       0
203    },
204    [CNP_ATOM_XELM] =  {
205       "application/x-elementary-markup",
206       ELM_SEL_FORMAT_MARKUP,
207       edje_converter,
208       NULL,
209       NULL,
210       0
211    },
212    [CNP_ATOM_text_uri] = {
213       "text/uri",
214       ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE, /* Either images or entries */
215       uri_converter,
216       NULL,
217       notify_handler_uri,
218       0
219    },
220    [CNP_ATOM_text_urilist] = {
221       "text/uri-list",
222       ELM_SEL_FORMAT_IMAGE | ELM_SEL_FORMAT_MARKUP,
223       uri_converter,
224       NULL,
225       notify_handler_uri,
226       0
227    },
228    [CNP_ATOM_text_x_vcard] = {
229       "text/x-vcard",
230       ELM_SEL_FORMAT_VCARD,
231       vcard_send, NULL,
232       vcard_receive, 0
233    },
234    [CNP_ATOM_image_png] = {
235       "image/png",
236       ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
237       image_converter,
238       NULL,
239       notify_handler_image,
240       0
241    },
242    [CNP_ATOM_image_jpeg] = {
243       "image/jpeg",
244       ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
245       image_converter,
246       NULL,
247       notify_handler_image,/* Raw image data is the same */
248       0
249    },
250    [CNP_ATOM_image_bmp] = {
251       "image/x-ms-bmp",
252       ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
253       image_converter,
254       NULL,
255       notify_handler_image,/* Raw image data is the same */
256       0
257    },
258    [CNP_ATOM_image_gif] = {
259       "image/gif",
260       ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
261       image_converter,
262       NULL,
263       notify_handler_image,/* Raw image data is the same */
264       0
265    },
266    [CNP_ATOM_image_tiff] = {
267       "image/tiff",
268       ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
269       image_converter,
270       NULL,
271       notify_handler_image,/* Raw image data is the same */
272       0
273    },
274    [CNP_ATOM_image_svg] = {
275       "image/svg+xml",
276       ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
277       image_converter,
278       NULL,
279       notify_handler_image,/* Raw image data is the same */
280       0
281    },
282    [CNP_ATOM_image_xpm] = {
283       "image/x-xpixmap",
284       ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
285       image_converter,
286       NULL,
287       notify_handler_image,/* Raw image data is the same */
288       0
289    },
290    [CNP_ATOM_image_tga] = {
291       "image/x-tga",
292       ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
293       image_converter,
294       NULL,
295       notify_handler_image,/* Raw image data is the same */
296       0
297    },
298    [CNP_ATOM_image_ppm] = {
299       "image/x-portable-pixmap",
300       ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
301       image_converter,
302       NULL,
303       notify_handler_image,/* Raw image data is the same */
304       0
305    },
306    [CNP_ATOM_text_html_utf8] = {
307       "text/html;charset=utf-8",
308       ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
309       html_converter,
310       NULL,
311       notify_handler_html,
312       0
313    },
314    [CNP_ATOM_text_html] = {
315       "text/html",
316       ELM_SEL_FORMAT_HTML,
317       html_converter,
318       NULL,
319       notify_handler_html, /* No encoding: Webkit only */
320       0
321    },
322    [CNP_ATOM_UTF8STRING] = {
323       "UTF8_STRING",
324       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
325       text_converter,
326       NULL,
327       notify_handler_text,
328       0
329    },
330    [CNP_ATOM_STRING] = {
331       "STRING",
332       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
333       text_converter,
334       NULL,
335       notify_handler_text,
336       0
337    },
338    [CNP_ATOM_TEXT] = {
339       "TEXT",
340       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
341       text_converter,
342       NULL,
343       NULL,
344       0
345    },
346    [CNP_ATOM_text_plain_utf8] = {
347       "text/plain;charset=utf-8",
348       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
349       text_converter,
350       NULL,
351       NULL,
352       0
353    },
354    [CNP_ATOM_text_plain] = {
355       "text/plain",
356       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
357       text_converter,
358       NULL,
359       NULL,
360       0
361    },
362 };
363
364 static Cnp_Selection selections[ELM_SEL_MAX] = {
365    ARRAYINIT(ELM_SEL_PRIMARY) {
366       .debug = "Primary",
367       .ecore_sel = ECORE_X_SELECTION_PRIMARY,
368       .set = ecore_x_selection_primary_set,
369       .clear = ecore_x_selection_primary_clear,
370       .request = ecore_x_selection_primary_request,
371    },
372    ARRAYINIT(ELM_SEL_SECONDARY) {
373       .debug = "Secondary",
374       .ecore_sel = ECORE_X_SELECTION_SECONDARY,
375       .set = ecore_x_selection_secondary_set,
376       .clear = ecore_x_selection_secondary_clear,
377       .request = ecore_x_selection_secondary_request,
378    },
379    ARRAYINIT(ELM_SEL_CLIPBOARD) {
380       .debug = "Clipboard",
381       .ecore_sel = ECORE_X_SELECTION_CLIPBOARD,
382       .set = ecore_x_selection_clipboard_set,
383       .clear = ecore_x_selection_clipboard_clear,
384       .request = ecore_x_selection_clipboard_request,
385    },
386    ARRAYINIT(ELM_SEL_XDND) {
387       .debug = "XDnD",
388       .ecore_sel = ECORE_X_SELECTION_XDND,
389       .request = ecore_x_selection_xdnd_request,
390    },
391 };
392
393 /* Data for DND in progress */
394 static Saved_Type savedtypes =  { NULL, NULL, 0, 0, 0, EINA_FALSE };
395
396 static void (*dragdonecb) (void *data, Evas_Object *obj) = NULL;
397 static void *dragdonedata = NULL;
398
399 static int _elm_cnp_init_count = 0;
400 /* FIXME: who left this out of XAtoms.h */
401 static Ecore_X_Atom clipboard_atom;
402
403 static Eina_List *pastedimages = NULL;
404
405 /**
406  * Drag & Drop functions
407  */
408
409 /* FIXME: Way too many globals */
410 static Eina_List *drops = NULL;
411 static Evas_Object *dragwin = NULL;
412 static int _dragx = 0, _dragy = 0;
413 static Ecore_Event_Handler *handler_pos = NULL;
414 static Ecore_Event_Handler *handler_drop = NULL;
415 static Ecore_Event_Handler *handler_enter = NULL;
416 static Ecore_Event_Handler *handler_status = NULL;
417
418 #endif
419
420 /* Stringshared, so I can just compare pointers later */
421 static const char *text_uri;
422
423 Eina_Bool
424 elm_selection_set(Elm_Sel_Type selection, Evas_Object *widget, Elm_Sel_Format format, const char *selbuf)
425 {
426 #ifdef HAVE_ELEMENTARY_X
427    Cnp_Selection *sel;
428
429    if ((unsigned int)selection >= (unsigned int)ELM_SEL_MAX) return EINA_FALSE;
430    if (!_elm_cnp_init_count) _elm_cnp_init();
431    if ((!selbuf) && (format != ELM_SEL_FORMAT_IMAGE))
432       return elm_selection_clear(selection, widget);
433
434    sel = selections + selection;
435
436    sel->active = 1;
437    sel->widget = widget;
438
439    sel->set(elm_win_xwindow_get(widget),&selection,sizeof(Elm_Sel_Type));
440    sel->format = format;
441    sel->selbuf = selbuf ? strdup(selbuf) : NULL;
442
443    return EINA_TRUE;
444 #else
445    return EINA_FALSE;
446 #endif
447 }
448
449 Eina_Bool
450 elm_selection_clear(Elm_Sel_Type selection, Evas_Object *widget)
451 {
452 #ifdef HAVE_ELEMENTARY_X
453    Cnp_Selection *sel;
454
455    if ((unsigned int)selection >= (unsigned int)ELM_SEL_MAX) return EINA_FALSE;
456    if (!_elm_cnp_init_count) _elm_cnp_init();
457
458    sel = selections + selection;
459
460    /* No longer this selection: Consider it gone! */
461    if ((!sel->active) || (sel->widget != widget)) return EINA_TRUE;
462
463    sel->active = 0;
464    sel->widget = NULL;
465    sel->clear();
466
467    return EINA_TRUE;
468 #else
469    return EINA_FALSE;
470 #endif
471 }
472
473 Eina_Bool
474 elm_selection_get(Elm_Sel_Type selection, Elm_Sel_Format format,
475                         Evas_Object *widget, Elm_Drop_Cb datacb, void *udata)
476 {
477 #ifdef HAVE_ELEMENTARY_X
478    Evas_Object *top;
479    Cnp_Selection *sel;
480
481    if ((unsigned int)selection >= (unsigned int)ELM_SEL_MAX) return EINA_FALSE;
482    if (!_elm_cnp_init_count) _elm_cnp_init();
483
484    sel = selections + selection;
485    top = elm_widget_top_get(widget);
486    if (!top) return EINA_FALSE;
487
488    sel->requestformat = format;
489    sel->requestwidget = widget;
490    sel->request(elm_win_xwindow_get(top), ECORE_X_SELECTION_TARGET_TARGETS);
491    sel->datacb = datacb;
492    sel->udata = udata;
493
494    return EINA_TRUE;
495 #else
496    return EINA_FALSE;
497 #endif
498 }
499
500 #ifdef HAVE_ELEMENTARY_X
501
502 static Eina_Bool
503 _elm_cnp_init(void)
504 {
505    int i;
506    
507    if (_elm_cnp_init_count++) return EINA_TRUE;
508    for (i = 0; i < CNP_N_ATOMS; i++)
509      {
510         atoms[i].atom = ecore_x_atom_get(atoms[i].name);
511         ecore_x_selection_converter_atom_add(atoms[i].atom,
512                                              atoms[i].converter);
513      }
514    clipboard_atom = ecore_x_atom_get("CLIPBOARD");
515
516    ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, selection_clear, NULL);
517    ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, selection_notify, NULL);
518    
519    text_uri = eina_stringshare_add("text/uri-list");
520    return EINA_TRUE;
521 }
522
523 static Eina_Bool
524 selection_clear(void *udata __UNUSED__, int type __UNUSED__, void *event)
525 {
526    Ecore_X_Event_Selection_Clear *ev = event;
527    Cnp_Selection *sel;
528    int i;
529    
530    for (i = 0; i < ELM_SEL_MAX; i++)
531      {
532         if (selections[i].ecore_sel == ev->selection) break;
533      }
534    cnp_debug("selection %d clear\n", i);
535    /* Not me... Don't care */
536    if (i == ELM_SEL_MAX) return ECORE_CALLBACK_PASS_ON;
537
538    sel = selections + i;
539    sel->active = 0;
540    sel->widget = NULL;
541    sel->selbuf = NULL;
542
543    return ECORE_CALLBACK_PASS_ON;
544 }
545
546
547 /*
548  * Response to a selection notify:
549  *      - So we have asked for the selection list.
550  *      - If it's the targets list, parse it, and fire of what we want,
551  *      else it's the data we want.
552  */
553 static Eina_Bool
554 selection_notify(void *udata __UNUSED__, int type __UNUSED__, void *event)
555 {
556    Ecore_X_Event_Selection_Notify *ev = event;
557    Cnp_Selection *sel;
558    int i;
559    
560    cnp_debug("selection notify callback: %d\n",ev->selection);
561    switch (ev->selection)
562      {
563       case ECORE_X_SELECTION_CLIPBOARD:
564         sel = selections + ELM_SEL_CLIPBOARD;
565         break;
566       case ECORE_X_SELECTION_PRIMARY:
567         sel = selections + ELM_SEL_PRIMARY;
568         break;
569       case ECORE_X_SELECTION_SECONDARY:
570         sel = selections + ELM_SEL_SECONDARY;
571         break;
572       case ECORE_X_SELECTION_XDND:
573         sel = selections + ELM_SEL_XDND;
574         break;
575       default:
576         return ECORE_CALLBACK_PASS_ON;
577      }
578    cnp_debug("Target is %s\n", ev->target);
579    
580    for (i = 0; i < CNP_N_ATOMS; i++)
581      {
582         if (!strcmp(ev->target, atoms[i].name))
583           {
584              if (atoms[i].notify)
585                {
586                   cnp_debug("Found something: %s\n", atoms[i].name);
587                   atoms[i].notify(sel, ev);
588                } 
589              else 
590                {
591                   cnp_debug("Ignored: No handler!\n");
592                }
593           }
594      }
595
596    return ECORE_CALLBACK_PASS_ON;
597 }
598
599
600
601 static Eina_Bool
602 targets_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
603 {
604    int i,count;
605    Ecore_X_Atom *aret;
606    Cnp_Selection *sel;
607    
608    if (!data_ret) return EINA_FALSE;
609
610    sel = selections + *((int *)data);
611
612    for (i = 0, count = 0; i < CNP_N_ATOMS ; i++)
613      {
614         if (sel->format & atoms[i].formats) count++;
615      }
616
617    aret = malloc(sizeof(Ecore_X_Atom) * count);
618    for (i = 0, count = 0; i < CNP_N_ATOMS; i++)
619      {
620         if (sel->format & atoms[i].formats) aret[count ++] = atoms[i].atom;
621      }
622
623    *data_ret = aret;
624    if (typesize) *typesize = 32 /* urk */;
625    if (ttype) *ttype = ECORE_X_ATOM_ATOM;
626    if (size_ret) *size_ret = count;
627
628    return EINA_TRUE;
629 }
630
631 static Eina_Bool
632 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__)
633 {
634    cnp_debug("Image converter called\n");
635    return EINA_TRUE;
636 }
637
638 static Eina_Bool
639 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__)
640 {
641    Cnp_Selection *sel;
642
643    cnp_debug("Vcard send called\n");
644    
645    sel = selections + *((int *)data);
646
647    if (data_ret) *data_ret = strdup(sel->selbuf);
648    if (size_ret) *size_ret = strlen(sel->selbuf);
649
650    return EINA_TRUE;
651 }
652 /*
653  * Callback to handle a targets response on a selection request:
654  * So pick the format we'd like; and then request it.
655  */
656 static int
657 notify_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
658 {
659    Ecore_X_Selection_Data_Targets *targets;
660    Ecore_X_Atom *atomlist;
661    int i, j;
662    
663    targets = notify->data;
664    atomlist = (Ecore_X_Atom *)(targets->data.data);
665
666    for (j = 1; j < CNP_N_ATOMS; j++)
667      {
668         cnp_debug("\t%s %d\n", atoms[j].name, atoms[j].atom);
669         if (!(atoms[j].formats & sel->requestformat)) continue;
670         for (i = 0; i < targets->data.length; i++)
671           {
672              if ((atoms[j].atom == atomlist[i]) && (atoms[j].notify))
673                {
674                   cnp_debug("Atom %s matches\n",atoms[j].name);
675                   goto done;
676                }
677           }
678      }
679
680    cnp_debug("Couldn't find anything that matches\n");
681    return ECORE_CALLBACK_PASS_ON;
682
683    done:
684    cnp_debug("Sending request for %s\n",atoms[j].name);
685    sel->request(elm_win_xwindow_get(sel->requestwidget), atoms[j].name);
686
687    return ECORE_CALLBACK_PASS_ON;
688 }
689
690 static int
691 response_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
692 {
693    Ecore_X_Selection_Data_Targets *targets;
694    Ecore_X_Atom *atomlist;
695    Evas_Object *top;
696    int i,j;
697
698    targets = notify->data;
699    atomlist = (Ecore_X_Atom *)(targets->data.data);
700
701    /* Start from 1: Skip targets */
702    for (j = 1 ; j < CNP_N_ATOMS ; j ++)
703      {
704         if (!(atoms[j].formats & sel->requestformat)) continue;
705         for (i = 0 ; i < targets->data.length ; i ++)
706           {
707              if ((atoms[j].atom == atomlist[i]) && (atoms[j].response))
708                {
709                   /* Found a match: Use it */
710                   goto found;
711                }
712           }
713      }
714 found:
715    if (j == CNP_N_ATOMS)
716      {
717         cnp_debug("No matching type found\n");
718         return 0;
719      }
720    
721    top = elm_widget_top_get(sel->requestwidget);
722    if (!top) return 0;
723    
724    sel->request(elm_win_xwindow_get(top), atoms[j].name);
725    return 0;
726 }
727
728
729 static int
730 notify_handler_text(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
731 {
732    Ecore_X_Selection_Data *data;
733    char *str;
734    
735    data = notify->data;
736    cnp_debug("Notify handler text %d %d %p\n", data->format,data->length, data->data);
737    str = mark_up((char *)data->data, data->length, NULL);
738    cnp_debug("String is %s (from %s)\n", str, data->data);
739    elm_entry_entry_insert(sel->requestwidget, str);
740    free(str);
741    return 0;
742 }
743
744
745 /**
746  * So someone is pasting an image into my entry or widget...
747  */
748 static int
749 notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
750 {
751    Ecore_X_Selection_Data *data;
752    Ecore_X_Selection_Data_Files *files;
753    Paste_Image *pi;
754    char *p, *pp, *ext;
755
756    data = notify->data;
757    cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
758    if (data->content == ECORE_X_SELECTION_CONTENT_FILES)
759      {
760         cnp_debug("got a files list\n");
761         files = notify->data;
762         if (files->num_files > 1)
763           {
764              /* Don't handle many items */
765              cnp_debug("more then one file: Bailing\n");
766              return 0;
767           }
768         p = files->files[0];
769      }
770    else p = (char *)data->data;
771    if (!p)
772      {
773         cnp_debug("Couldn't find a file\n");
774         return 0;
775      }
776    cnp_debug("Got %s\n",p);
777    if (strncmp(p, "file://", 7))
778      {
779         /* Try and continue if it looks sane */
780         if (*p != '/') return 0;
781      }
782    else p += strlen("file://");
783    
784    ext = p + strlen(p);
785    if (ext)
786      {
787         Eina_Bool extok = EINA_FALSE;
788         int i;
789         
790         for (i = 0; image_extensions[i]; i++)
791           {
792              pp = ext - strlen(image_extensions[i]);
793              if ((pp >= p) && (!strcasecmp(pp, image_extensions[i])))
794                {
795                   extok = EINA_TRUE;
796                   break;
797                }
798           }
799         if (!extok)
800           {
801              cnp_debug("No known image format extension, ignoring\n");
802              if (savedtypes.textreq) savedtypes.textreq = 0;
803              return 0;
804           }
805      }
806
807    if (savedtypes.pi) pasteimage_free(savedtypes.pi);
808    pi = pasteimage_alloc(p, data->length);
809    if (savedtypes.textreq)
810      {
811         savedtypes.textreq = 0;
812         savedtypes.pi = pi;
813      }
814    else
815      {
816         pasteimage_append(pi, sel->requestwidget);
817         savedtypes.pi = NULL;
818      }
819    return 0;
820 }
821
822 /**
823  * Just receieved an vcard, either through cut and paste, or dnd.
824  */
825 static int
826 vcard_receive(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
827 {
828    Dropable *dropable;
829    Eina_List *l;
830    Ecore_X_Selection_Data *data;
831
832    data = notify->data;
833    cnp_debug("vcard receive\n");
834
835    if (sel == (selections + ELM_SEL_XDND))
836      {
837         Elm_Selection_Data ddata;
838         
839         cnp_debug("drag & drop\n");
840         /* FIXME: this needs to be generic: Used for all receives */
841         EINA_LIST_FOREACH(drops, l, dropable)
842           {
843              if (dropable->obj == sel->requestwidget) break;
844           }
845         if (!dropable)
846           {
847              cnp_debug("Unable to find drop object");
848              ecore_x_dnd_send_finished();
849              return 0;
850           }
851         dropable = eina_list_data_get(l);
852         ddata.x = savedtypes.x;
853         ddata.y = savedtypes.y;
854         ddata.format = ELM_SEL_FORMAT_VCARD;
855         ddata.data = data->data;
856         ddata.len = data->length;
857         dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
858         ecore_x_dnd_send_finished();
859      }
860    else if (sel->datacb)
861      {
862         Elm_Selection_Data ddata;
863         ddata.x = ddata.y = 0;
864         ddata.format = ELM_SEL_FORMAT_IMAGE;
865         ddata.data = data->data;
866         ddata.len = data->length;
867         sel->datacb(sel->udata, sel->widget, &ddata);
868      }
869    else
870      {
871         cnp_debug("Paste request\n");
872      }
873    
874    return 0;
875
876 }
877
878
879 static int
880 notify_handler_image(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
881 {
882    Ecore_X_Selection_Data *data;
883    Tmp_Info *tmp;
884    Paste_Image *pi;
885    
886    cnp_debug("got a png (or a jpeg)!\n");
887    data = notify->data;
888    
889    cnp_debug("Size if %d\n", data->length);
890
891    if (sel->datacb)
892      {
893         Elm_Selection_Data ddata;
894         
895         ddata.x = ddata.y = 0;
896         ddata.format = ELM_SEL_FORMAT_IMAGE;
897         ddata.data = data->data;
898         ddata.len = data->length;
899         sel->datacb(sel->udata, sel->widget, &ddata);
900         return 0;
901      }
902    
903    /* generate tmp name */
904    tmp = elm_cnp_tempfile_create(data->length);
905    memcpy(tmp->map, data->data, data->length);
906    munmap(tmp->map,data->length);
907    
908    /* FIXME: Add to paste image data to clean up */
909    pi = pasteimage_alloc(tmp->filename, data->length);
910    pasteimage_append(pi, sel->requestwidget);
911
912    tmpinfo_free(tmp);
913    return 0;
914 }
915
916
917 /**
918  *    Warning: Generic text/html can';t handle it sanely.
919  *    Firefox sends ucs2 (i think).
920  *       chrome sends utf8... blerg
921  */
922 static int
923 notify_handler_html(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
924 {
925    Ecore_X_Selection_Data *data;
926    
927    cnp_debug("Got some HTML: Checking encoding is useful\n");
928    data = notify->data;
929    
930    if (sel->datacb)
931      {
932         Elm_Selection_Data ddata;
933         ddata.x = ddata.y = 0;
934         ddata.format = ELM_SEL_FORMAT_HTML;
935         ddata.data = data->data;
936         ddata.len = data->length;
937         sel->datacb(sel->udata, sel->widget, &ddata);
938         return 0;
939      }
940
941    char *stripstr = NULL;
942    stripstr = malloc(sizeof(char) * (data->length + 1));
943    strncpy(stripstr, (char *)data->data, data->length);
944    stripstr[data->length] = '\0';
945    cnp_debug("String is %s (%d bytes)\n", stripstr, data->length);
946    elm_entry_entry_insert(sel->requestwidget, stripstr);
947    free(stripstr);
948    return 0;
949 }
950
951
952 static Eina_Bool
953 text_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
954 {
955    Cnp_Selection *sel;
956
957    cnp_debug("text converter\n");
958    sel = selections + *((int *)data);
959    if (!sel->active) return EINA_TRUE;
960    
961    if ((sel->format == ELM_SEL_FORMAT_MARKUP) ||
962        (sel->format == ELM_SEL_FORMAT_HTML))
963      {
964         *data_ret = remove_tags(sel->selbuf, size_ret);
965      }
966    else if (sel->format == ELM_SEL_FORMAT_TEXT)
967      {
968         *data_ret = strdup(sel->selbuf);
969         *size_ret = strlen(sel->selbuf);
970      }
971    else if (sel->format == ELM_SEL_FORMAT_IMAGE)
972      {
973         cnp_debug("Image %s\n", evas_object_type_get(sel->widget));
974         cnp_debug("Elm type: %s\n", elm_object_widget_type_get(sel->widget));
975         evas_object_image_file_get(elm_photocam_internal_image_get(sel->widget), (const char **)data_ret, NULL);
976         if (!*data_ret) *data_ret = strdup("No file");
977         else *data_ret = strdup(*data_ret);
978         *size_ret = strlen(*data_ret);
979      }
980    return EINA_TRUE;
981 }
982
983 static Eina_Bool
984 edje_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
985 {
986    Cnp_Selection *sel;
987
988    sel = selections + *((int *)data);
989    if (data_ret) *data_ret = strdup(sel->selbuf);
990    if (size_ret) *size_ret = strlen(sel->selbuf);
991
992    return EINA_TRUE;
993 }
994
995
996 static Eina_Bool
997 html_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
998 {
999    Cnp_Selection *sel;
1000
1001    sel = selections + *(int *)data;
1002    if (data_ret) *data_ret = strdup(sel->selbuf);
1003    if (size_ret) *size_ret = strlen(sel->selbuf);
1004
1005    return EINA_TRUE;
1006 }
1007
1008 static Eina_Bool
1009 uri_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
1010 {
1011     Cnp_Selection *sel;
1012     sel = selections + *((int *)data);
1013     cnp_debug("Uri converter\n");
1014     if (data_ret) *data_ret = strdup(sel->selbuf);
1015     if (size_ret) *size_ret = strlen(sel->selbuf);
1016     return EINA_TRUE;
1017 }
1018
1019 /*
1020  * Image paste provide
1021  */
1022
1023 /* FIXME: Should add provider for each pasted item: Use data to store it
1024  * much easier */
1025 static Evas_Object *
1026 image_provider(void *images __UNUSED__, Evas_Object *entry, const char *item)
1027 {
1028    Paste_Image *pi;
1029    Eina_List *l;
1030
1031    cnp_debug("image provider for %s called\n", item);
1032    EINA_LIST_FOREACH(pastedimages, l, pi)
1033      {
1034         cnp_debug("is it %s?\n",pi->tag);
1035         if (!strcmp(pi->tag, item))
1036           {
1037              /* Found it */
1038              Evas_Object *o;
1039              o = evas_object_image_filled_add(evas_object_evas_get(entry));
1040              /* FIXME: Handle eets */
1041              cnp_debug("file is %s (object is %p)\n", pi->file, o);
1042              evas_object_image_file_set(o, pi->file, NULL);
1043              evas_object_show(o);
1044              return o;
1045           }
1046      }
1047    return NULL;
1048 }
1049
1050
1051 static Paste_Image *
1052 pasteimage_alloc(const char *file, int pathlen)
1053 {
1054    Paste_Image *pi;
1055    int len;
1056    char *buf, *filebuf;
1057    int prefixlen = strlen("file://");
1058
1059    pi = calloc(1, sizeof(Paste_Image));
1060    if (!pi) return NULL;
1061    
1062    len = snprintf(NULL, 0, "pasteimage-%p", pi);
1063    len++;
1064    buf = malloc(len);
1065    if (!buf)
1066      {
1067         free(pi);
1068         return NULL;
1069      }
1070    snprintf(buf, len, "pasteimage-%p", pi);
1071    pi->tag = buf;
1072    
1073    if (file)
1074      {
1075         if (strstr(file,"file://")) file += prefixlen;
1076         filebuf = alloca(sizeof(char) * (pathlen - prefixlen + 1));
1077         strncpy(filebuf, file, pathlen - prefixlen);
1078         filebuf[pathlen-prefixlen] = '\0';
1079         pi->file = strdup(filebuf);
1080      }
1081
1082    return pi;
1083 }
1084
1085 static void
1086 pasteimage_free(Paste_Image *pi)
1087 {
1088    if (!pi) return;
1089    if (pi->file) free((void*)pi->file);
1090    if (pi->tag) free((void*)pi->tag);
1091    free(pi);
1092 }
1093
1094 static Eina_Bool
1095 pasteimage_provider_set(Evas_Object *entry)
1096 {
1097    void *v;
1098    const char *type;
1099    
1100    if (!entry) return EINA_FALSE;
1101    type = elm_widget_type_get(entry);
1102    cnp_debug("type is %s\n", type);
1103    if ((!type) || (strcmp(type, "entry"))) return EINA_FALSE;
1104    
1105    v = evas_object_data_get(entry, PROVIDER_SET);
1106    if (!v)
1107      {
1108         evas_object_data_set(entry, PROVIDER_SET, pasteimage_provider_set);
1109         elm_entry_item_provider_append(entry, image_provider, NULL);
1110         evas_object_event_callback_add(entry, EVAS_CALLBACK_FREE,
1111                                        entry_deleted, NULL);
1112      }
1113    return EINA_TRUE;
1114 }
1115
1116
1117 static Eina_Bool
1118 pasteimage_append(Paste_Image *pi, Evas_Object *entry)
1119 {
1120    char *entrytag;
1121    char *tagstring = "<item absize=240x180 href=file://%s></item>";
1122    
1123    if (!pi) return EINA_FALSE;
1124    if (!entry) return EINA_FALSE;
1125
1126    pasteimage_provider_set(entry);
1127
1128    pastedimages = eina_list_append(pastedimages, pi);
1129    entrytag = alloca(sizeof(char)*(strlen(tagstring)+strlen(pi->file)+1));
1130    snprintf(entrytag, (strlen(tagstring)+strlen(pi->file)), tagstring, pi->file);
1131    elm_entry_entry_insert(entry, entrytag);
1132
1133    return EINA_TRUE;
1134 }
1135
1136 static void
1137 entry_deleted(void *images __UNUSED__, Evas *e __UNUSED__, Evas_Object *entry, void *unused __UNUSED__)
1138 {
1139    Paste_Image *pi;
1140    Eina_List *l,*next;
1141
1142    EINA_LIST_FOREACH_SAFE(pastedimages, l, next, pi)
1143      {
1144         if (pi->entry == entry)
1145            pastedimages = eina_list_remove_list(pastedimages, l);
1146      }
1147 }
1148
1149
1150 static char *
1151 remove_tags(const char *p, int *len)
1152 {
1153    char *q,*ret;
1154    int i;
1155    if (!p) return NULL;
1156    
1157    q = malloc(strlen(p) + 1);
1158    if (!q) return NULL;
1159    ret = q;
1160
1161    while (*p)
1162      {
1163         if ((*p != '<') && (*p != '&')) *q++ = *p++;
1164         else if (*p == '<')
1165           {
1166              if ((p[1] == 'b') && (p[2] == 'r') &&
1167                  ((p[3] == ' ') || (p[3] == '/') || (p[3] == '>')))
1168                 *q++ = '\n';
1169              while ((*p) && (*p != '>')) p++;
1170              p++;
1171           } 
1172         else if (*p == '&')
1173           {
1174              p++;
1175              for (i = 0 ; i < N_ESCAPES ; i++)
1176                {
1177                   if (!strncmp(p,escapes[i].escape, strlen(escapes[i].escape)))
1178                     {
1179                        p += strlen(escapes[i].escape);
1180                        *q = escapes[i].value;
1181                        q++;
1182                        break;
1183                     }
1184                }
1185              if (i == N_ESCAPES) *q ++= '&';
1186           }
1187      }
1188    *q = 0;
1189    if (len) *len = q - ret;
1190    return ret;
1191 }
1192
1193 /* Mark up */
1194 static char *
1195 mark_up(const char *start, int inlen, int *lenp)
1196 {
1197    int l, i;
1198    const char *p;
1199    char *q, *ret;
1200    const char *endp = NULL;
1201    
1202    if (!start) return NULL;
1203    if (inlen >= 0) endp = start + inlen;
1204    /* First pass: Count characters */
1205    for (l = 0, p = start; ((!endp) || (p < endp)) && (*p); p++)
1206      {
1207         for (i = 0 ; i < N_ESCAPES ; i ++)
1208           {
1209              if (*p == escapes[i].value)
1210                {
1211                   l += strlen(escapes[i].escape);
1212                   break;
1213                }
1214           }
1215         if (i == N_ESCAPES) l++;
1216      }
1217    
1218    q = ret = malloc(l + 1);
1219    
1220    /* Second pass: Change characters */
1221   for (p = start; *p; )
1222     {
1223        for (i = 0; i < N_ESCAPES; i++)
1224          {
1225             if (*p == escapes[i].value)
1226               {
1227                  strcpy(q, escapes[i].escape);
1228                  q += strlen(escapes[i].escape);
1229                  p ++;
1230                  break;
1231               }
1232          }
1233        if (i == N_ESCAPES) *q++ = *p++;
1234     }
1235    *q = 0;
1236    
1237    if (lenp) *lenp = l;
1238    return ret;
1239 }
1240
1241
1242 static Eina_Bool
1243 _dnd_enter(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1244 {
1245    Ecore_X_Event_Xdnd_Enter *enter = ev;
1246    int i;
1247
1248    /* Skip it */
1249    if ((!enter) || (!enter->num_types) || (!enter->types)) return EINA_TRUE;
1250
1251    cnp_debug("Types\n");
1252    savedtypes.ntypes = enter->num_types;
1253    if (savedtypes.types) free(savedtypes.types);
1254    savedtypes.types = malloc(sizeof(char *) * enter->num_types);
1255    if (!savedtypes.types) return EINA_FALSE;
1256    
1257    for (i = 0; i < enter->num_types; i++)
1258      {
1259         savedtypes.types[i] = eina_stringshare_add(enter->types[i]);
1260         cnp_debug("Type is %s %p %p\n", enter->types[i],
1261                   savedtypes.types[i],text_uri);
1262         if (savedtypes.types[i] == text_uri)
1263           {
1264              /* Request it, so we know what it is */
1265              cnp_debug("Sending uri request\n");
1266              savedtypes.textreq = 1;
1267              savedtypes.pi = NULL; /* FIXME: Free? */
1268              ecore_x_selection_xdnd_request(enter->win, text_uri);
1269           }
1270      }
1271
1272    /* FIXME: Find an object and make it current */
1273    return EINA_TRUE;
1274 }
1275
1276 static Eina_Bool
1277 _dnd_drop(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1278 {
1279    struct _Ecore_X_Event_Xdnd_Drop *drop;
1280    Dropable *dropable;
1281    Eina_List *l;
1282    Ecore_Evas *ee;
1283    Ecore_X_Window xwin;
1284    Elm_Selection_Data ddata;
1285    int x, y, w, h;
1286    int i, j;
1287
1288    drop = ev;
1289
1290    // check we still have something to drop
1291    if (!drops) return EINA_TRUE;
1292
1293    /* Find any widget in our window; then work out geometry rel to our window */
1294    for (l = drops; l; l = l->next)
1295      {
1296         dropable = l->data;
1297         xwin = (Ecore_X_Window)ecore_evas_window_get
1298            (ecore_evas_ecore_evas_get(evas_object_evas_get
1299                                       (dropable->obj)));
1300         if (xwin == drop->win) break;
1301      }
1302    /* didn't find a window */
1303    if (!l) return EINA_TRUE;
1304
1305    /* Calculate real (widget relative) position */
1306    // - window position
1307    // - widget position
1308    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(dropable->obj));
1309    ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
1310    savedtypes.x = drop->position.x - x;
1311    savedtypes.y = drop->position.y - y;
1312    
1313    cnp_debug("Drop position is %d,%d\n", savedtypes.x, savedtypes.y);
1314
1315    for (; l; l = l->next)
1316      {
1317         dropable = l->data;
1318         evas_object_geometry_get(dropable->obj, &x, &y, &w, &h);
1319         if ((savedtypes.x >= x) && (savedtypes.y >= y) &&
1320             (savedtypes.x < x + w) && (savedtypes.y < y + h))
1321            break; /* found! */
1322      }
1323    
1324    if (!l) return EINA_TRUE; /* didn't find one */
1325    
1326    evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL);
1327    savedtypes.x -= x;
1328    savedtypes.y -= y;
1329    
1330    /* Find our type from the previous list */
1331    for (i = 0; i < CNP_N_ATOMS; i++)
1332      {
1333         for (j = 0; j < savedtypes.ntypes; j++)
1334           {
1335              if (!strcmp(savedtypes.types[j], atoms[i].name)) goto found;
1336           }
1337      }
1338    
1339    cnp_debug("Didn't find a target\n");
1340    return EINA_TRUE;
1341    
1342 found:
1343    cnp_debug("Found a target we'd like: %s\n", atoms[i].name);
1344    cnp_debug("0x%x\n",xwin);
1345    
1346    if (i == CNP_ATOM_text_urilist)
1347      {
1348         cnp_debug("We found a URI... (%scached)\n", savedtypes.pi ? "" : "not ");
1349         if (savedtypes.pi)
1350           {
1351              char *entrytag;
1352              char *tagstring = "<item absize=240x180 href=file://%s></item>";
1353              
1354              ddata.x = savedtypes.x;
1355              ddata.y = savedtypes.y;
1356
1357              if (dropable->types & ELM_SEL_FORMAT_IMAGE)
1358                {
1359                   cnp_debug("Doing image insert (%s)\n", savedtypes.pi->file);
1360                   ddata.format = ELM_SEL_FORMAT_IMAGE;
1361                   ddata.data = (char *)savedtypes.pi->file;
1362                   dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1363                   ecore_x_dnd_send_finished();
1364                   
1365                   pasteimage_free(savedtypes.pi);
1366                   savedtypes.pi = NULL;
1367                   
1368                   return EINA_TRUE;
1369                }
1370              else if (dropable->types & ELM_SEL_FORMAT_MARKUP)
1371                {
1372                   ddata.format = ELM_SEL_FORMAT_MARKUP;
1373                   pasteimage_provider_set(dropable->obj);
1374                   
1375                   pastedimages = eina_list_append(pastedimages, savedtypes.pi);
1376                   entrytag = alloca(sizeof(char)*(strlen(tagstring)+strlen(savedtypes.pi->file)+1));
1377                   snprintf(entrytag, (strlen(tagstring)+strlen(savedtypes.pi->file)),
1378                            tagstring, savedtypes.pi->file);
1379                   ddata.data = entrytag;
1380                   cnp_debug("Insert %s\n", (char *)ddata.data);
1381                   dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1382                   ecore_x_dnd_send_finished();
1383                   return EINA_TRUE;
1384                }
1385           }
1386         else if (savedtypes.textreq)
1387           {
1388              /* Already asked: Pretend we asked now, and paste immediately when
1389               * it comes in */
1390              savedtypes.textreq = 0;
1391              ecore_x_dnd_send_finished();
1392              return EINA_TRUE;
1393           }
1394      }
1395
1396    cnp_debug("doing a request then\n");
1397    selections[ELM_SEL_XDND].requestwidget = dropable->obj;
1398    selections[ELM_SEL_XDND].requestformat = ELM_SEL_FORMAT_MARKUP;
1399    selections[ELM_SEL_XDND].active = EINA_TRUE;
1400
1401    ecore_x_selection_xdnd_request(xwin, atoms[i].name);
1402
1403    return EINA_TRUE;
1404 }
1405 static Eina_Bool
1406 _dnd_position(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1407 {
1408    struct _Ecore_X_Event_Xdnd_Position *pos;
1409    Ecore_X_Rectangle rect;
1410    
1411    pos = ev;
1412    
1413    /* Need to send a status back */
1414    /* FIXME: Should check I can drop here */
1415    /* FIXME: Should highlight widget */
1416    rect.x = pos->position.x - 5;
1417    rect.y = pos->position.y - 5;
1418    rect.width = 10;
1419    rect.height = 10;
1420    ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, pos->action);
1421
1422    return EINA_TRUE;
1423 }
1424
1425 /**
1426  * When dragging this is callback response from the destination.
1427  * The important thing we care about: Can we drop; thus update cursor
1428  * appropriately.
1429  */
1430 static Eina_Bool
1431 _dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1432 {
1433    struct _Ecore_X_Event_Xdnd_Status *status = ev;
1434
1435    if (!status) return EINA_TRUE;
1436    
1437    /* Only thing we care about: will accept */
1438    if (status->will_accept)
1439      {
1440         cnp_debug("Will accept\n");
1441      }
1442    else
1443      { /* Won't accept */
1444         cnp_debug("Won't accept accept\n");
1445      }
1446    return EINA_TRUE;
1447 }
1448
1449 /**
1450  * Add a widget as drop target.
1451  */
1452 Eina_Bool
1453 elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, void *cbdata)
1454 {
1455    Dropable *drop;
1456    Ecore_X_Window xwin;
1457    int first;
1458    
1459    if (!obj) return EINA_FALSE;
1460    if (!_elm_cnp_init_count) _elm_cnp_init();
1461    
1462    /* Is this the first? */
1463    first = (!drops) ? 1 : 0;
1464    
1465    drop = calloc(1, sizeof(Dropable));
1466    if (!drop) return EINA_FALSE;
1467    drop->dropcb = dropcb;
1468    drop->cbdata = cbdata;
1469    
1470    /* FIXME: Check it's not already there */
1471    
1472    /* FIXME: Check for eina's deranged error method */
1473    drops = eina_list_append(drops, drop);
1474    
1475    if (!drops/* || or other error */)
1476      {
1477         free(drop);
1478         return EINA_FALSE;
1479      }
1480    
1481    drop->obj = obj;
1482    /* Something for now */
1483    drop->types = format;
1484    
1485    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1486                                   /* I love C and varargs */
1487                                   (Evas_Object_Event_Cb)elm_drop_target_del,
1488                                   obj);
1489    /* FIXME: Handle resizes */
1490    
1491    /* If not the first: We're done */
1492    if (!first) return EINA_TRUE;
1493    
1494    xwin = (Ecore_X_Window)ecore_evas_window_get
1495       (ecore_evas_ecore_evas_get(evas_object_evas_get(obj)));
1496    
1497    ecore_x_dnd_aware_set(xwin, EINA_TRUE);
1498    
1499    cnp_debug("Adding drop target calls\n");
1500    handler_enter = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
1501                                            _dnd_enter, NULL);
1502    handler_pos = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
1503                                          _dnd_position, NULL);
1504    handler_drop = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
1505                                           _dnd_drop, NULL);
1506    
1507    return EINA_TRUE;
1508 }
1509
1510 Eina_Bool
1511 elm_drop_target_del(Evas_Object *obj)
1512 {
1513    Dropable *drop,*del;
1514    Eina_List *item;
1515    Ecore_X_Window xwin;
1516    
1517    del = NULL;
1518    EINA_LIST_FOREACH(drops, item, drop)
1519      {
1520         if (drop->obj == obj)
1521           {
1522              drops = eina_list_remove_list(drops, item);
1523              del = drop;
1524              break;
1525           }
1526      }
1527    if (!del) return EINA_FALSE;
1528    
1529    evas_object_event_callback_del(obj, EVAS_CALLBACK_FREE,
1530                                   (Evas_Object_Event_Cb)elm_drop_target_del);
1531    free(drop);
1532    /* If still drops there: All fine.. continue */
1533    if (drops) return EINA_TRUE;
1534    
1535    cnp_debug("Disabling DND\n");
1536    xwin = (Ecore_X_Window)ecore_evas_window_get
1537       (ecore_evas_ecore_evas_get(evas_object_evas_get(obj)));
1538    ecore_x_dnd_aware_set(xwin, EINA_FALSE);
1539    
1540    ecore_event_handler_del(handler_pos);
1541    ecore_event_handler_del(handler_drop);
1542    ecore_event_handler_del(handler_enter);
1543    
1544    if (savedtypes.pi)
1545      {
1546         pasteimage_free(savedtypes.pi);
1547         savedtypes.pi = NULL;
1548      }
1549    
1550    return EINA_TRUE;
1551 }
1552
1553
1554 static void
1555 _drag_mouse_up(void *un __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *data __UNUSED__)
1556 {
1557    evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP, _drag_mouse_up);
1558    ecore_x_dnd_drop();
1559    if (dragdonecb)
1560      {
1561         dragdonecb(dragdonecb,selections[ELM_SEL_XDND].widget);
1562         dragdonecb = NULL;
1563      }
1564    if (dragwin)
1565      {
1566         evas_object_del(dragwin);
1567         dragwin = NULL;
1568      }
1569 }
1570
1571 static void
1572 _drag_move(void *data __UNUSED__, Ecore_X_Xdnd_Position *pos)
1573 {
1574    evas_object_move(dragwin, 
1575                     pos->position.x - _dragx, 
1576                     pos->position.y - _dragy);
1577 }
1578
1579
1580 Eina_Bool
1581 elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, void (*dragdone) (void *data, Evas_Object *), void *donecbdata)
1582 {
1583    Ecore_X_Window xwin;
1584    Cnp_Selection *sel;
1585    Elm_Sel_Type xdnd = ELM_SEL_XDND;
1586    Ecore_Evas *ee;
1587    int x, y, x2, y2, x3, y3;
1588    Evas_Object *icon;
1589    int w, h;
1590    
1591    if (!_elm_cnp_init_count) _elm_cnp_init();
1592    
1593    xwin = elm_win_xwindow_get(obj);
1594
1595    cnp_debug("starting drag...\n");
1596
1597    ecore_x_dnd_type_set(xwin, "text/uri-list", 1);
1598    sel = selections + ELM_SEL_XDND;
1599    sel->active = 1;
1600    sel->widget = obj;
1601    sel->format = format;
1602    sel->selbuf = data ? strdup(data) : NULL;
1603    dragdonecb = dragdone;
1604    dragdonedata = donecbdata;
1605    
1606    ecore_x_dnd_callback_pos_update_set(_drag_move, NULL);
1607    ecore_x_dnd_begin(xwin, (unsigned char *)&xdnd, sizeof(Elm_Sel_Type));
1608    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
1609                                   _drag_mouse_up, NULL);
1610    
1611    handler_status = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
1612                                             _dnd_status, NULL);
1613    
1614    dragwin = elm_win_add(NULL, "Elm Drag Object", ELM_WIN_UTILITY);
1615    elm_win_override_set(dragwin, 1);
1616    
1617    /* FIXME: Images only */
1618    icon = elm_icon_add(dragwin);
1619    elm_icon_file_set(icon, data + 7, NULL); /* 7!? "file://" */
1620    elm_win_resize_object_add(dragwin,icon);
1621    evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1622    evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL);
1623
1624    /* Position subwindow appropriately */
1625    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
1626    ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
1627    evas_object_geometry_get(obj, &x2, &y2, &w, &h);
1628    x += x2;
1629    y += y2;
1630    evas_object_move(dragwin, x, y);
1631    evas_object_resize(icon, w, h);
1632    evas_object_resize(dragwin, w, h);
1633    
1634    evas_object_show(icon);
1635    evas_object_show(dragwin);
1636
1637    evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x3, &y3);
1638    _dragx = x3 - x2;
1639    _dragy = y3 - y2;
1640
1641    return EINA_TRUE;
1642 }
1643
1644 static Tmp_Info *
1645 elm_cnp_tempfile_create(int size)
1646 {
1647    Tmp_Info *info;
1648    const char *tmppath;
1649    int len;
1650    
1651    info = malloc(sizeof(Tmp_Info));
1652    if (!info) return NULL;
1653    
1654    tmppath = getenv("TMP");
1655    if (!tmppath) tmppath = P_tmpdir;
1656    if (!tmppath) tmppath = "/tmp";
1657    len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-");
1658    if (len < 0)
1659      {
1660         free(info);
1661         return NULL;
1662      }
1663    len++;
1664    info->filename = malloc(len);
1665    if (!info->filename)
1666      {
1667         free(info);
1668         return NULL;
1669      }
1670    snprintf(info->filename,len,"%s/%sXXXXXX", tmppath, "elmcnpitem-");
1671    
1672    info->fd = mkstemp(info->filename);
1673    
1674 # ifdef __linux__
1675      {
1676         char *tmp;
1677         /* And before someone says anything see POSIX 1003.1-2008 page 400 */
1678         long pid;
1679         
1680         pid = (long)getpid();
1681         /* Use pid instead of /proc/self: That way if can be passed around */
1682         len = snprintf(NULL,0,"/proc/%li/fd/%i", pid, info->fd);
1683         len++;
1684         tmp = malloc(len);
1685         if (tmp)
1686           {
1687              snprintf(tmp,len, "/proc/%li/fd/%i", pid, info->fd);
1688              unlink(info->filename);
1689              free(info->filename);
1690              info->filename = tmp;
1691           }
1692      }
1693 # endif
1694    
1695    cnp_debug("filename is %s\n", info->filename);
1696    if (size < 1)
1697      {
1698         /* Set map to NULL and return */
1699         info->map = NULL;
1700         info->len = 0;
1701         return info;
1702      }
1703    
1704    /* Map it in */
1705    if (ftruncate(info->fd, size))
1706      {
1707         perror("ftruncate");
1708         info->map = NULL;
1709         info->len = 0;
1710         return info;
1711      }
1712    
1713    info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0);
1714    if (info->map == MAP_FAILED)
1715      {
1716         perror("mmap");
1717         info->map = NULL;
1718         info->len = 0;
1719      }
1720    
1721    return info;
1722 }
1723
1724
1725 static int
1726 tmpinfo_free(Tmp_Info *info)
1727 {
1728    if (!info) return 0;
1729    free(info->filename);
1730    free(info);
1731    return 0;
1732 }
1733
1734 #else
1735 /* Stubs for windows */
1736 Eina_Bool
1737 elm_drag_start(Evas_Object *o, Elm_Sel_Format f, const char *d, void (*donecb)(void *, Evas_Object *),void *cbdata)
1738 {
1739    return EINA_FALSE;
1740 }
1741
1742 Eina_Bool
1743 elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, void *cbdata)
1744 {
1745    return EINA_FALSE;
1746 }
1747
1748 Eina_Bool
1749 elm_drop_target_del(Evas_Object *o)
1750 {
1751    return EINA_TRUE;
1752 }
1753 #endif
1754
1755 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/