[cnp_helper] adjust pasting image size
[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=%s href=file://%s></item>";
1122    
1123    if (!pi) return EINA_FALSE;
1124    if (!entry) return EINA_FALSE;
1125
1126    char *imgres = alloca(sizeof(char)*10);
1127
1128    Evas_Object *o;
1129    o = evas_object_image_add(evas_object_evas_get(entry));
1130    evas_object_image_file_set(o, pi->file, NULL);
1131    if (evas_object_image_load_error_get(o) == EVAS_LOAD_ERROR_NONE)
1132    {
1133            int w = 0, h = 0;
1134            evas_object_image_size_get(o, &w, &h);
1135            
1136            if (w > 200 || h > 150)
1137            {
1138                    double divd, tw, th;
1139                    if (w > h)
1140                    {
1141                            divd = (double)200/w;
1142                            tw = (double)w*divd;
1143                            th = (double)h*divd;
1144                    }
1145                    else
1146                    {
1147                            divd = (double)150/h;
1148                            tw = (double)w*divd;
1149                            th = (double)h*divd;
1150                    }
1151                    sprintf(imgres, "%dx%d", (int)tw, (int)th);
1152            }
1153            else
1154            {
1155                    if (!w || !h)
1156                            strcpy(imgres, "240x180");
1157                    else
1158                            sprintf(imgres, "%dx%d", w, h);
1159            }
1160    }
1161    else
1162            strcpy(imgres, "240x180");
1163    evas_object_del(o);
1164
1165    pasteimage_provider_set(entry);
1166
1167    pastedimages = eina_list_append(pastedimages, pi);
1168    entrytag = alloca(sizeof(char)*(strlen(tagstring)+strlen(imgres)+strlen(pi->file)+1));
1169    snprintf(entrytag, (strlen(tagstring)+strlen(imgres)+strlen(pi->file)), tagstring, imgres, pi->file);
1170    elm_entry_entry_insert(entry, entrytag);
1171
1172    return EINA_TRUE;
1173 }
1174
1175 static void
1176 entry_deleted(void *images __UNUSED__, Evas *e __UNUSED__, Evas_Object *entry, void *unused __UNUSED__)
1177 {
1178    Paste_Image *pi;
1179    Eina_List *l,*next;
1180
1181    EINA_LIST_FOREACH_SAFE(pastedimages, l, next, pi)
1182      {
1183         if (pi->entry == entry)
1184            pastedimages = eina_list_remove_list(pastedimages, l);
1185      }
1186 }
1187
1188
1189 static char *
1190 remove_tags(const char *p, int *len)
1191 {
1192    char *q,*ret;
1193    int i;
1194    if (!p) return NULL;
1195    
1196    q = malloc(strlen(p) + 1);
1197    if (!q) return NULL;
1198    ret = q;
1199
1200    while (*p)
1201      {
1202         if ((*p != '<') && (*p != '&')) *q++ = *p++;
1203         else if (*p == '<')
1204           {
1205              if ((p[1] == 'b') && (p[2] == 'r') &&
1206                  ((p[3] == ' ') || (p[3] == '/') || (p[3] == '>')))
1207                 *q++ = '\n';
1208              while ((*p) && (*p != '>')) p++;
1209              p++;
1210           } 
1211         else if (*p == '&')
1212           {
1213              p++;
1214              for (i = 0 ; i < N_ESCAPES ; i++)
1215                {
1216                   if (!strncmp(p,escapes[i].escape, strlen(escapes[i].escape)))
1217                     {
1218                        p += strlen(escapes[i].escape);
1219                        *q = escapes[i].value;
1220                        q++;
1221                        break;
1222                     }
1223                }
1224              if (i == N_ESCAPES) *q ++= '&';
1225           }
1226      }
1227    *q = 0;
1228    if (len) *len = q - ret;
1229    return ret;
1230 }
1231
1232 /* Mark up */
1233 static char *
1234 mark_up(const char *start, int inlen, int *lenp)
1235 {
1236    int l, i;
1237    const char *p;
1238    char *q, *ret;
1239    const char *endp = NULL;
1240    
1241    if (!start) return NULL;
1242    if (inlen >= 0) endp = start + inlen;
1243    /* First pass: Count characters */
1244    for (l = 0, p = start; ((!endp) || (p < endp)) && (*p); p++)
1245      {
1246         for (i = 0 ; i < N_ESCAPES ; i ++)
1247           {
1248              if (*p == escapes[i].value)
1249                {
1250                   l += strlen(escapes[i].escape);
1251                   break;
1252                }
1253           }
1254         if (i == N_ESCAPES) l++;
1255      }
1256    
1257    q = ret = malloc(l + 1);
1258    
1259    /* Second pass: Change characters */
1260   for (p = start; *p; )
1261     {
1262        for (i = 0; i < N_ESCAPES; i++)
1263          {
1264             if (*p == escapes[i].value)
1265               {
1266                  strcpy(q, escapes[i].escape);
1267                  q += strlen(escapes[i].escape);
1268                  p ++;
1269                  break;
1270               }
1271          }
1272        if (i == N_ESCAPES) *q++ = *p++;
1273     }
1274    *q = 0;
1275    
1276    if (lenp) *lenp = l;
1277    return ret;
1278 }
1279
1280
1281 static Eina_Bool
1282 _dnd_enter(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1283 {
1284    Ecore_X_Event_Xdnd_Enter *enter = ev;
1285    int i;
1286
1287    /* Skip it */
1288    if ((!enter) || (!enter->num_types) || (!enter->types)) return EINA_TRUE;
1289
1290    cnp_debug("Types\n");
1291    savedtypes.ntypes = enter->num_types;
1292    if (savedtypes.types) free(savedtypes.types);
1293    savedtypes.types = malloc(sizeof(char *) * enter->num_types);
1294    if (!savedtypes.types) return EINA_FALSE;
1295    
1296    for (i = 0; i < enter->num_types; i++)
1297      {
1298         savedtypes.types[i] = eina_stringshare_add(enter->types[i]);
1299         cnp_debug("Type is %s %p %p\n", enter->types[i],
1300                   savedtypes.types[i],text_uri);
1301         if (savedtypes.types[i] == text_uri)
1302           {
1303              /* Request it, so we know what it is */
1304              cnp_debug("Sending uri request\n");
1305              savedtypes.textreq = 1;
1306              savedtypes.pi = NULL; /* FIXME: Free? */
1307              ecore_x_selection_xdnd_request(enter->win, text_uri);
1308           }
1309      }
1310
1311    /* FIXME: Find an object and make it current */
1312    return EINA_TRUE;
1313 }
1314
1315 static Eina_Bool
1316 _dnd_drop(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1317 {
1318    struct _Ecore_X_Event_Xdnd_Drop *drop;
1319    Dropable *dropable;
1320    Eina_List *l;
1321    Ecore_Evas *ee;
1322    Ecore_X_Window xwin;
1323    Elm_Selection_Data ddata;
1324    int x, y, w, h;
1325    int i, j;
1326
1327    drop = ev;
1328
1329    // check we still have something to drop
1330    if (!drops) return EINA_TRUE;
1331
1332    /* Find any widget in our window; then work out geometry rel to our window */
1333    for (l = drops; l; l = l->next)
1334      {
1335         dropable = l->data;
1336         xwin = (Ecore_X_Window)ecore_evas_window_get
1337            (ecore_evas_ecore_evas_get(evas_object_evas_get
1338                                       (dropable->obj)));
1339         if (xwin == drop->win) break;
1340      }
1341    /* didn't find a window */
1342    if (!l) return EINA_TRUE;
1343
1344    /* Calculate real (widget relative) position */
1345    // - window position
1346    // - widget position
1347    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(dropable->obj));
1348    ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
1349    savedtypes.x = drop->position.x - x;
1350    savedtypes.y = drop->position.y - y;
1351    
1352    cnp_debug("Drop position is %d,%d\n", savedtypes.x, savedtypes.y);
1353
1354    for (; l; l = l->next)
1355      {
1356         dropable = l->data;
1357         evas_object_geometry_get(dropable->obj, &x, &y, &w, &h);
1358         if ((savedtypes.x >= x) && (savedtypes.y >= y) &&
1359             (savedtypes.x < x + w) && (savedtypes.y < y + h))
1360            break; /* found! */
1361      }
1362    
1363    if (!l) return EINA_TRUE; /* didn't find one */
1364    
1365    evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL);
1366    savedtypes.x -= x;
1367    savedtypes.y -= y;
1368    
1369    /* Find our type from the previous list */
1370    for (i = 0; i < CNP_N_ATOMS; i++)
1371      {
1372         for (j = 0; j < savedtypes.ntypes; j++)
1373           {
1374              if (!strcmp(savedtypes.types[j], atoms[i].name)) goto found;
1375           }
1376      }
1377    
1378    cnp_debug("Didn't find a target\n");
1379    return EINA_TRUE;
1380    
1381 found:
1382    cnp_debug("Found a target we'd like: %s\n", atoms[i].name);
1383    cnp_debug("0x%x\n",xwin);
1384    
1385    if (i == CNP_ATOM_text_urilist)
1386      {
1387         cnp_debug("We found a URI... (%scached)\n", savedtypes.pi ? "" : "not ");
1388         if (savedtypes.pi)
1389           {
1390              char *entrytag;
1391              char *tagstring = "<item absize=240x180 href=file://%s></item>";
1392              
1393              ddata.x = savedtypes.x;
1394              ddata.y = savedtypes.y;
1395
1396              if (dropable->types & ELM_SEL_FORMAT_IMAGE)
1397                {
1398                   cnp_debug("Doing image insert (%s)\n", savedtypes.pi->file);
1399                   ddata.format = ELM_SEL_FORMAT_IMAGE;
1400                   ddata.data = (char *)savedtypes.pi->file;
1401                   dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1402                   ecore_x_dnd_send_finished();
1403                   
1404                   pasteimage_free(savedtypes.pi);
1405                   savedtypes.pi = NULL;
1406                   
1407                   return EINA_TRUE;
1408                }
1409              else if (dropable->types & ELM_SEL_FORMAT_MARKUP)
1410                {
1411                   ddata.format = ELM_SEL_FORMAT_MARKUP;
1412                   pasteimage_provider_set(dropable->obj);
1413                   
1414                   pastedimages = eina_list_append(pastedimages, savedtypes.pi);
1415                   entrytag = alloca(sizeof(char)*(strlen(tagstring)+strlen(savedtypes.pi->file)+1));
1416                   snprintf(entrytag, (strlen(tagstring)+strlen(savedtypes.pi->file)),
1417                            tagstring, savedtypes.pi->file);
1418                   ddata.data = entrytag;
1419                   cnp_debug("Insert %s\n", (char *)ddata.data);
1420                   dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1421                   ecore_x_dnd_send_finished();
1422                   return EINA_TRUE;
1423                }
1424           }
1425         else if (savedtypes.textreq)
1426           {
1427              /* Already asked: Pretend we asked now, and paste immediately when
1428               * it comes in */
1429              savedtypes.textreq = 0;
1430              ecore_x_dnd_send_finished();
1431              return EINA_TRUE;
1432           }
1433      }
1434
1435    cnp_debug("doing a request then\n");
1436    selections[ELM_SEL_XDND].requestwidget = dropable->obj;
1437    selections[ELM_SEL_XDND].requestformat = ELM_SEL_FORMAT_MARKUP;
1438    selections[ELM_SEL_XDND].active = EINA_TRUE;
1439
1440    ecore_x_selection_xdnd_request(xwin, atoms[i].name);
1441
1442    return EINA_TRUE;
1443 }
1444 static Eina_Bool
1445 _dnd_position(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1446 {
1447    struct _Ecore_X_Event_Xdnd_Position *pos;
1448    Ecore_X_Rectangle rect;
1449    
1450    pos = ev;
1451    
1452    /* Need to send a status back */
1453    /* FIXME: Should check I can drop here */
1454    /* FIXME: Should highlight widget */
1455    rect.x = pos->position.x - 5;
1456    rect.y = pos->position.y - 5;
1457    rect.width = 10;
1458    rect.height = 10;
1459    ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, pos->action);
1460
1461    return EINA_TRUE;
1462 }
1463
1464 /**
1465  * When dragging this is callback response from the destination.
1466  * The important thing we care about: Can we drop; thus update cursor
1467  * appropriately.
1468  */
1469 static Eina_Bool
1470 _dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1471 {
1472    struct _Ecore_X_Event_Xdnd_Status *status = ev;
1473
1474    if (!status) return EINA_TRUE;
1475    
1476    /* Only thing we care about: will accept */
1477    if (status->will_accept)
1478      {
1479         cnp_debug("Will accept\n");
1480      }
1481    else
1482      { /* Won't accept */
1483         cnp_debug("Won't accept accept\n");
1484      }
1485    return EINA_TRUE;
1486 }
1487
1488 /**
1489  * Add a widget as drop target.
1490  */
1491 Eina_Bool
1492 elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, void *cbdata)
1493 {
1494    Dropable *drop;
1495    Ecore_X_Window xwin;
1496    int first;
1497    
1498    if (!obj) return EINA_FALSE;
1499    if (!_elm_cnp_init_count) _elm_cnp_init();
1500    
1501    /* Is this the first? */
1502    first = (!drops) ? 1 : 0;
1503    
1504    drop = calloc(1, sizeof(Dropable));
1505    if (!drop) return EINA_FALSE;
1506    drop->dropcb = dropcb;
1507    drop->cbdata = cbdata;
1508    
1509    /* FIXME: Check it's not already there */
1510    
1511    /* FIXME: Check for eina's deranged error method */
1512    drops = eina_list_append(drops, drop);
1513    
1514    if (!drops/* || or other error */)
1515      {
1516         free(drop);
1517         return EINA_FALSE;
1518      }
1519    
1520    drop->obj = obj;
1521    /* Something for now */
1522    drop->types = format;
1523    
1524    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1525                                   /* I love C and varargs */
1526                                   (Evas_Object_Event_Cb)elm_drop_target_del,
1527                                   obj);
1528    /* FIXME: Handle resizes */
1529    
1530    /* If not the first: We're done */
1531    if (!first) return EINA_TRUE;
1532    
1533    xwin = (Ecore_X_Window)ecore_evas_window_get
1534       (ecore_evas_ecore_evas_get(evas_object_evas_get(obj)));
1535    
1536    ecore_x_dnd_aware_set(xwin, EINA_TRUE);
1537    
1538    cnp_debug("Adding drop target calls\n");
1539    handler_enter = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
1540                                            _dnd_enter, NULL);
1541    handler_pos = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
1542                                          _dnd_position, NULL);
1543    handler_drop = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
1544                                           _dnd_drop, NULL);
1545    
1546    return EINA_TRUE;
1547 }
1548
1549 Eina_Bool
1550 elm_drop_target_del(Evas_Object *obj)
1551 {
1552    Dropable *drop,*del;
1553    Eina_List *item;
1554    Ecore_X_Window xwin;
1555    
1556    del = NULL;
1557    EINA_LIST_FOREACH(drops, item, drop)
1558      {
1559         if (drop->obj == obj)
1560           {
1561              drops = eina_list_remove_list(drops, item);
1562              del = drop;
1563              break;
1564           }
1565      }
1566    if (!del) return EINA_FALSE;
1567    
1568    evas_object_event_callback_del(obj, EVAS_CALLBACK_FREE,
1569                                   (Evas_Object_Event_Cb)elm_drop_target_del);
1570    free(drop);
1571    /* If still drops there: All fine.. continue */
1572    if (drops) return EINA_TRUE;
1573    
1574    cnp_debug("Disabling DND\n");
1575    xwin = (Ecore_X_Window)ecore_evas_window_get
1576       (ecore_evas_ecore_evas_get(evas_object_evas_get(obj)));
1577    ecore_x_dnd_aware_set(xwin, EINA_FALSE);
1578    
1579    ecore_event_handler_del(handler_pos);
1580    ecore_event_handler_del(handler_drop);
1581    ecore_event_handler_del(handler_enter);
1582    
1583    if (savedtypes.pi)
1584      {
1585         pasteimage_free(savedtypes.pi);
1586         savedtypes.pi = NULL;
1587      }
1588    
1589    return EINA_TRUE;
1590 }
1591
1592
1593 static void
1594 _drag_mouse_up(void *un __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *data __UNUSED__)
1595 {
1596    evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP, _drag_mouse_up);
1597    ecore_x_dnd_drop();
1598    if (dragdonecb)
1599      {
1600         dragdonecb(dragdonecb,selections[ELM_SEL_XDND].widget);
1601         dragdonecb = NULL;
1602      }
1603    if (dragwin)
1604      {
1605         evas_object_del(dragwin);
1606         dragwin = NULL;
1607      }
1608 }
1609
1610 static void
1611 _drag_move(void *data __UNUSED__, Ecore_X_Xdnd_Position *pos)
1612 {
1613    evas_object_move(dragwin, 
1614                     pos->position.x - _dragx, 
1615                     pos->position.y - _dragy);
1616 }
1617
1618
1619 Eina_Bool
1620 elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, void (*dragdone) (void *data, Evas_Object *), void *donecbdata)
1621 {
1622    Ecore_X_Window xwin;
1623    Cnp_Selection *sel;
1624    Elm_Sel_Type xdnd = ELM_SEL_XDND;
1625    Ecore_Evas *ee;
1626    int x, y, x2, y2, x3, y3;
1627    Evas_Object *icon;
1628    int w, h;
1629    
1630    if (!_elm_cnp_init_count) _elm_cnp_init();
1631    
1632    xwin = elm_win_xwindow_get(obj);
1633
1634    cnp_debug("starting drag...\n");
1635
1636    ecore_x_dnd_type_set(xwin, "text/uri-list", 1);
1637    sel = selections + ELM_SEL_XDND;
1638    sel->active = 1;
1639    sel->widget = obj;
1640    sel->format = format;
1641    sel->selbuf = data ? strdup(data) : NULL;
1642    dragdonecb = dragdone;
1643    dragdonedata = donecbdata;
1644    
1645    ecore_x_dnd_callback_pos_update_set(_drag_move, NULL);
1646    ecore_x_dnd_begin(xwin, (unsigned char *)&xdnd, sizeof(Elm_Sel_Type));
1647    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
1648                                   _drag_mouse_up, NULL);
1649    
1650    handler_status = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
1651                                             _dnd_status, NULL);
1652    
1653    dragwin = elm_win_add(NULL, "Elm Drag Object", ELM_WIN_UTILITY);
1654    elm_win_override_set(dragwin, 1);
1655    
1656    /* FIXME: Images only */
1657    icon = elm_icon_add(dragwin);
1658    elm_icon_file_set(icon, data + 7, NULL); /* 7!? "file://" */
1659    elm_win_resize_object_add(dragwin,icon);
1660    evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1661    evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL);
1662
1663    /* Position subwindow appropriately */
1664    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
1665    ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
1666    evas_object_geometry_get(obj, &x2, &y2, &w, &h);
1667    x += x2;
1668    y += y2;
1669    evas_object_move(dragwin, x, y);
1670    evas_object_resize(icon, w, h);
1671    evas_object_resize(dragwin, w, h);
1672    
1673    evas_object_show(icon);
1674    evas_object_show(dragwin);
1675
1676    evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x3, &y3);
1677    _dragx = x3 - x2;
1678    _dragy = y3 - y2;
1679
1680    return EINA_TRUE;
1681 }
1682
1683 static Tmp_Info *
1684 elm_cnp_tempfile_create(int size)
1685 {
1686    Tmp_Info *info;
1687    const char *tmppath;
1688    int len;
1689    
1690    info = malloc(sizeof(Tmp_Info));
1691    if (!info) return NULL;
1692    
1693    tmppath = getenv("TMP");
1694    if (!tmppath) tmppath = P_tmpdir;
1695    if (!tmppath) tmppath = "/tmp";
1696    len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-");
1697    if (len < 0)
1698      {
1699         free(info);
1700         return NULL;
1701      }
1702    len++;
1703    info->filename = malloc(len);
1704    if (!info->filename)
1705      {
1706         free(info);
1707         return NULL;
1708      }
1709    snprintf(info->filename,len,"%s/%sXXXXXX", tmppath, "elmcnpitem-");
1710    
1711    info->fd = mkstemp(info->filename);
1712    
1713 # ifdef __linux__
1714      {
1715         char *tmp;
1716         /* And before someone says anything see POSIX 1003.1-2008 page 400 */
1717         long pid;
1718         
1719         pid = (long)getpid();
1720         /* Use pid instead of /proc/self: That way if can be passed around */
1721         len = snprintf(NULL,0,"/proc/%li/fd/%i", pid, info->fd);
1722         len++;
1723         tmp = malloc(len);
1724         if (tmp)
1725           {
1726              snprintf(tmp,len, "/proc/%li/fd/%i", pid, info->fd);
1727              unlink(info->filename);
1728              free(info->filename);
1729              info->filename = tmp;
1730           }
1731      }
1732 # endif
1733    
1734    cnp_debug("filename is %s\n", info->filename);
1735    if (size < 1)
1736      {
1737         /* Set map to NULL and return */
1738         info->map = NULL;
1739         info->len = 0;
1740         return info;
1741      }
1742    
1743    /* Map it in */
1744    if (ftruncate(info->fd, size))
1745      {
1746         perror("ftruncate");
1747         info->map = NULL;
1748         info->len = 0;
1749         return info;
1750      }
1751    
1752    info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0);
1753    if (info->map == MAP_FAILED)
1754      {
1755         perror("mmap");
1756         info->map = NULL;
1757         info->len = 0;
1758      }
1759    
1760    return info;
1761 }
1762
1763
1764 static int
1765 tmpinfo_free(Tmp_Info *info)
1766 {
1767    if (!info) return 0;
1768    free(info->filename);
1769    free(info);
1770    return 0;
1771 }
1772
1773 #else
1774 /* Stubs for windows */
1775 Eina_Bool
1776 elm_drag_start(Evas_Object *o, Elm_Sel_Format f, const char *d, void (*donecb)(void *, Evas_Object *),void *cbdata)
1777 {
1778    return EINA_FALSE;
1779 }
1780
1781 Eina_Bool
1782 elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, void *cbdata)
1783 {
1784    return EINA_FALSE;
1785 }
1786
1787 Eina_Bool
1788 elm_drop_target_del(Evas_Object *o)
1789 {
1790    return EINA_TRUE;
1791 }
1792 #endif
1793
1794 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/