[cnp_helper] add datacb handling and remove file ext checking
[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
737    if (sel->datacb)
738      {
739         Elm_Selection_Data ddata;
740         
741         str = mark_up((char *)data->data, data->length, NULL);
742         ddata.x = ddata.y = 0;
743         ddata.format = ELM_SEL_FORMAT_TEXT;
744         ddata.data = str;
745         ddata.len = data->length;
746         sel->datacb(sel->udata, sel->widget, &ddata);
747         free(str);
748         return 0;
749      }
750    
751    cnp_debug("Notify handler text %d %d %p\n", data->format,data->length, data->data);
752    str = mark_up((char *)data->data, data->length, NULL);
753    cnp_debug("String is %s (from %s)\n", str, data->data);
754    elm_entry_entry_insert(sel->requestwidget, str);
755    free(str);
756    return 0;
757 }
758
759
760 /**
761  * So someone is pasting an image into my entry or widget...
762  */
763 static int
764 notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
765 {
766    Ecore_X_Selection_Data *data;
767    Ecore_X_Selection_Data_Files *files;
768    Paste_Image *pi;
769    char *p, *pp;
770
771    data = notify->data;
772    cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
773    if (data->content == ECORE_X_SELECTION_CONTENT_FILES)
774      {
775         cnp_debug("got a files list\n");
776         files = notify->data;
777         if (files->num_files > 1)
778           {
779              /* Don't handle many items */
780              cnp_debug("more then one file: Bailing\n");
781              return 0;
782           }
783         p = files->files[0];
784      }
785    else p = (char *)data->data;
786    if (!p)
787      {
788         cnp_debug("Couldn't find a file\n");
789         return 0;
790      }
791    cnp_debug("Got %s\n",p);
792    if (sel->datacb)
793      {
794         Elm_Selection_Data ddata;
795         
796         ddata.x = ddata.y = 0;
797         ddata.format = ELM_SEL_FORMAT_MARKUP;
798         ddata.data = p;
799         ddata.len = data->length;
800         sel->datacb(sel->udata, sel->widget, &ddata);
801         return 0;
802      }
803    if (strncmp(p, "file://", 7))
804      {
805         /* Try and continue if it looks sane */
806         if (*p != '/') return 0;
807      }
808    else p += strlen("file://");
809    
810    if (savedtypes.pi) pasteimage_free(savedtypes.pi);
811    pi = pasteimage_alloc(p, data->length);
812    if (savedtypes.textreq)
813      {
814         savedtypes.textreq = 0;
815         savedtypes.pi = pi;
816      }
817    else
818      {
819         pasteimage_append(pi, sel->requestwidget);
820         savedtypes.pi = NULL;
821      }
822    return 0;
823 }
824
825 /**
826  * Just receieved an vcard, either through cut and paste, or dnd.
827  */
828 static int
829 vcard_receive(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
830 {
831    Dropable *dropable;
832    Eina_List *l;
833    Ecore_X_Selection_Data *data;
834
835    data = notify->data;
836    cnp_debug("vcard receive\n");
837
838    if (sel == (selections + ELM_SEL_XDND))
839      {
840         Elm_Selection_Data ddata;
841         
842         cnp_debug("drag & drop\n");
843         /* FIXME: this needs to be generic: Used for all receives */
844         EINA_LIST_FOREACH(drops, l, dropable)
845           {
846              if (dropable->obj == sel->requestwidget) break;
847           }
848         if (!dropable)
849           {
850              cnp_debug("Unable to find drop object");
851              ecore_x_dnd_send_finished();
852              return 0;
853           }
854         dropable = eina_list_data_get(l);
855         ddata.x = savedtypes.x;
856         ddata.y = savedtypes.y;
857         ddata.format = ELM_SEL_FORMAT_VCARD;
858         ddata.data = data->data;
859         ddata.len = data->length;
860         dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
861         ecore_x_dnd_send_finished();
862      }
863    else if (sel->datacb)
864      {
865         Elm_Selection_Data ddata;
866         ddata.x = ddata.y = 0;
867         ddata.format = ELM_SEL_FORMAT_IMAGE;
868         ddata.data = data->data;
869         ddata.len = data->length;
870         sel->datacb(sel->udata, sel->widget, &ddata);
871      }
872    else
873      {
874         cnp_debug("Paste request\n");
875      }
876    
877    return 0;
878
879 }
880
881
882 static int
883 notify_handler_image(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
884 {
885    Ecore_X_Selection_Data *data;
886    Tmp_Info *tmp;
887    Paste_Image *pi;
888    
889    cnp_debug("got a png (or a jpeg)!\n");
890    data = notify->data;
891    
892    cnp_debug("Size if %d\n", data->length);
893
894    if (sel->datacb)
895      {
896         Elm_Selection_Data ddata;
897         
898         ddata.x = ddata.y = 0;
899         ddata.format = ELM_SEL_FORMAT_IMAGE;
900         ddata.data = data->data;
901         ddata.len = data->length;
902         sel->datacb(sel->udata, sel->widget, &ddata);
903         return 0;
904      }
905    
906    /* generate tmp name */
907    tmp = elm_cnp_tempfile_create(data->length);
908    memcpy(tmp->map, data->data, data->length);
909    munmap(tmp->map,data->length);
910    
911    /* FIXME: Add to paste image data to clean up */
912    pi = pasteimage_alloc(tmp->filename, data->length);
913    pasteimage_append(pi, sel->requestwidget);
914
915    tmpinfo_free(tmp);
916    return 0;
917 }
918
919
920 /**
921  *    Warning: Generic text/html can';t handle it sanely.
922  *    Firefox sends ucs2 (i think).
923  *       chrome sends utf8... blerg
924  */
925 static int
926 notify_handler_html(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
927 {
928    Ecore_X_Selection_Data *data;
929    
930    cnp_debug("Got some HTML: Checking encoding is useful\n");
931    data = notify->data;
932    
933    if (sel->datacb)
934      {
935         Elm_Selection_Data ddata;
936         ddata.x = ddata.y = 0;
937         ddata.format = ELM_SEL_FORMAT_HTML;
938         ddata.data = data->data;
939         ddata.len = data->length;
940         sel->datacb(sel->udata, sel->widget, &ddata);
941         return 0;
942      }
943
944    char *stripstr = NULL;
945    stripstr = malloc(sizeof(char) * (data->length + 1));
946    strncpy(stripstr, (char *)data->data, data->length);
947    stripstr[data->length] = '\0';
948    cnp_debug("String is %s (%d bytes)\n", stripstr, data->length);
949    elm_entry_entry_insert(sel->requestwidget, stripstr);
950    free(stripstr);
951    return 0;
952 }
953
954
955 static Eina_Bool
956 text_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
957 {
958    Cnp_Selection *sel;
959
960    cnp_debug("text converter\n");
961    sel = selections + *((int *)data);
962    if (!sel->active) return EINA_TRUE;
963    
964    if ((sel->format == ELM_SEL_FORMAT_MARKUP) ||
965        (sel->format == ELM_SEL_FORMAT_HTML))
966      {
967         *data_ret = remove_tags(sel->selbuf, size_ret);
968      }
969    else if (sel->format == ELM_SEL_FORMAT_TEXT)
970      {
971         *data_ret = strdup(sel->selbuf);
972         *size_ret = strlen(sel->selbuf);
973      }
974    else if (sel->format == ELM_SEL_FORMAT_IMAGE)
975      {
976         cnp_debug("Image %s\n", evas_object_type_get(sel->widget));
977         cnp_debug("Elm type: %s\n", elm_object_widget_type_get(sel->widget));
978         evas_object_image_file_get(elm_photocam_internal_image_get(sel->widget), (const char **)data_ret, NULL);
979         if (!*data_ret) *data_ret = strdup("No file");
980         else *data_ret = strdup(*data_ret);
981         *size_ret = strlen(*data_ret);
982      }
983    return EINA_TRUE;
984 }
985
986 static Eina_Bool
987 edje_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
988 {
989    Cnp_Selection *sel;
990
991    sel = selections + *((int *)data);
992    if (data_ret) *data_ret = strdup(sel->selbuf);
993    if (size_ret) *size_ret = strlen(sel->selbuf);
994
995    return EINA_TRUE;
996 }
997
998
999 static Eina_Bool
1000 html_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
1001 {
1002    Cnp_Selection *sel;
1003
1004    sel = selections + *(int *)data;
1005    if (data_ret) *data_ret = strdup(sel->selbuf);
1006    if (size_ret) *size_ret = strlen(sel->selbuf);
1007
1008    return EINA_TRUE;
1009 }
1010
1011 static Eina_Bool
1012 uri_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
1013 {
1014     Cnp_Selection *sel;
1015     sel = selections + *((int *)data);
1016     cnp_debug("Uri converter\n");
1017     if (data_ret) *data_ret = strdup(sel->selbuf);
1018     if (size_ret) *size_ret = strlen(sel->selbuf);
1019     return EINA_TRUE;
1020 }
1021
1022 /*
1023  * Image paste provide
1024  */
1025
1026 /* FIXME: Should add provider for each pasted item: Use data to store it
1027  * much easier */
1028 static Evas_Object *
1029 image_provider(void *images __UNUSED__, Evas_Object *entry, const char *item)
1030 {
1031    Paste_Image *pi;
1032    Eina_List *l;
1033
1034    cnp_debug("image provider for %s called\n", item);
1035    EINA_LIST_FOREACH(pastedimages, l, pi)
1036      {
1037         cnp_debug("is it %s?\n",pi->tag);
1038         if (!strcmp(pi->tag, item))
1039           {
1040              /* Found it */
1041              Evas_Object *o;
1042              o = evas_object_image_filled_add(evas_object_evas_get(entry));
1043              /* FIXME: Handle eets */
1044              cnp_debug("file is %s (object is %p)\n", pi->file, o);
1045              evas_object_image_file_set(o, pi->file, NULL);
1046              evas_object_show(o);
1047              return o;
1048           }
1049      }
1050    return NULL;
1051 }
1052
1053
1054 static Paste_Image *
1055 pasteimage_alloc(const char *file, int pathlen)
1056 {
1057    Paste_Image *pi;
1058    int len;
1059    char *buf, *filebuf;
1060    int prefixlen = strlen("file://");
1061
1062    pi = calloc(1, sizeof(Paste_Image));
1063    if (!pi) return NULL;
1064    
1065    len = snprintf(NULL, 0, "pasteimage-%p", pi);
1066    len++;
1067    buf = malloc(len);
1068    if (!buf)
1069      {
1070         free(pi);
1071         return NULL;
1072      }
1073    snprintf(buf, len, "pasteimage-%p", pi);
1074    pi->tag = buf;
1075    
1076    if (file)
1077      {
1078         if (strstr(file,"file://")) file += prefixlen;
1079         filebuf = alloca(sizeof(char) * (pathlen - prefixlen + 1));
1080         strncpy(filebuf, file, pathlen - prefixlen);
1081         filebuf[pathlen-prefixlen] = '\0';
1082         pi->file = strdup(filebuf);
1083      }
1084
1085    return pi;
1086 }
1087
1088 static void
1089 pasteimage_free(Paste_Image *pi)
1090 {
1091    if (!pi) return;
1092    if (pi->file) free((void*)pi->file);
1093    if (pi->tag) free((void*)pi->tag);
1094    free(pi);
1095 }
1096
1097 static Eina_Bool
1098 pasteimage_provider_set(Evas_Object *entry)
1099 {
1100    void *v;
1101    const char *type;
1102    
1103    if (!entry) return EINA_FALSE;
1104    type = elm_widget_type_get(entry);
1105    cnp_debug("type is %s\n", type);
1106    if ((!type) || (strcmp(type, "entry"))) return EINA_FALSE;
1107    
1108    v = evas_object_data_get(entry, PROVIDER_SET);
1109    if (!v)
1110      {
1111         evas_object_data_set(entry, PROVIDER_SET, pasteimage_provider_set);
1112         elm_entry_item_provider_append(entry, image_provider, NULL);
1113         evas_object_event_callback_add(entry, EVAS_CALLBACK_FREE,
1114                                        entry_deleted, NULL);
1115      }
1116    return EINA_TRUE;
1117 }
1118
1119
1120 static Eina_Bool
1121 pasteimage_append(Paste_Image *pi, Evas_Object *entry)
1122 {
1123    char *entrytag;
1124    char *tagstring = "<item absize=240x180 href=file://%s></item>";
1125    
1126    if (!pi) return EINA_FALSE;
1127    if (!entry) return EINA_FALSE;
1128
1129    pasteimage_provider_set(entry);
1130
1131    pastedimages = eina_list_append(pastedimages, pi);
1132    entrytag = alloca(sizeof(char)*(strlen(tagstring)+strlen(pi->file)+1));
1133    snprintf(entrytag, (strlen(tagstring)+strlen(pi->file)), tagstring, pi->file);
1134    elm_entry_entry_insert(entry, entrytag);
1135
1136    return EINA_TRUE;
1137 }
1138
1139 static void
1140 entry_deleted(void *images __UNUSED__, Evas *e __UNUSED__, Evas_Object *entry, void *unused __UNUSED__)
1141 {
1142    Paste_Image *pi;
1143    Eina_List *l,*next;
1144
1145    EINA_LIST_FOREACH_SAFE(pastedimages, l, next, pi)
1146      {
1147         if (pi->entry == entry)
1148            pastedimages = eina_list_remove_list(pastedimages, l);
1149      }
1150 }
1151
1152
1153 static char *
1154 remove_tags(const char *p, int *len)
1155 {
1156    char *q,*ret;
1157    int i;
1158    if (!p) return NULL;
1159    
1160    q = malloc(strlen(p) + 1);
1161    if (!q) return NULL;
1162    ret = q;
1163
1164    while (*p)
1165      {
1166         if ((*p != '<') && (*p != '&')) *q++ = *p++;
1167         else if (*p == '<')
1168           {
1169              if ((p[1] == 'b') && (p[2] == 'r') &&
1170                  ((p[3] == ' ') || (p[3] == '/') || (p[3] == '>')))
1171                 *q++ = '\n';
1172              while ((*p) && (*p != '>')) p++;
1173              p++;
1174           } 
1175         else if (*p == '&')
1176           {
1177              p++;
1178              for (i = 0 ; i < N_ESCAPES ; i++)
1179                {
1180                   if (!strncmp(p,escapes[i].escape, strlen(escapes[i].escape)))
1181                     {
1182                        p += strlen(escapes[i].escape);
1183                        *q = escapes[i].value;
1184                        q++;
1185                        break;
1186                     }
1187                }
1188              if (i == N_ESCAPES) *q ++= '&';
1189           }
1190      }
1191    *q = 0;
1192    if (len) *len = q - ret;
1193    return ret;
1194 }
1195
1196 /* Mark up */
1197 static char *
1198 mark_up(const char *start, int inlen, int *lenp)
1199 {
1200    int l, i;
1201    const char *p;
1202    char *q, *ret;
1203    const char *endp = NULL;
1204    
1205    if (!start) return NULL;
1206    if (inlen >= 0) endp = start + inlen;
1207    /* First pass: Count characters */
1208    for (l = 0, p = start; ((!endp) || (p < endp)) && (*p); p++)
1209      {
1210         for (i = 0 ; i < N_ESCAPES ; i ++)
1211           {
1212              if (*p == escapes[i].value)
1213                {
1214                   l += strlen(escapes[i].escape);
1215                   break;
1216                }
1217           }
1218         if (i == N_ESCAPES) l++;
1219      }
1220    
1221    q = ret = malloc(l + 1);
1222    
1223    /* Second pass: Change characters */
1224   for (p = start; *p; )
1225     {
1226        for (i = 0; i < N_ESCAPES; i++)
1227          {
1228             if (*p == escapes[i].value)
1229               {
1230                  strcpy(q, escapes[i].escape);
1231                  q += strlen(escapes[i].escape);
1232                  p ++;
1233                  break;
1234               }
1235          }
1236        if (i == N_ESCAPES) *q++ = *p++;
1237     }
1238    *q = 0;
1239    
1240    if (lenp) *lenp = l;
1241    return ret;
1242 }
1243
1244
1245 static Eina_Bool
1246 _dnd_enter(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1247 {
1248    Ecore_X_Event_Xdnd_Enter *enter = ev;
1249    int i;
1250
1251    /* Skip it */
1252    if ((!enter) || (!enter->num_types) || (!enter->types)) return EINA_TRUE;
1253
1254    cnp_debug("Types\n");
1255    savedtypes.ntypes = enter->num_types;
1256    if (savedtypes.types) free(savedtypes.types);
1257    savedtypes.types = malloc(sizeof(char *) * enter->num_types);
1258    if (!savedtypes.types) return EINA_FALSE;
1259    
1260    for (i = 0; i < enter->num_types; i++)
1261      {
1262         savedtypes.types[i] = eina_stringshare_add(enter->types[i]);
1263         cnp_debug("Type is %s %p %p\n", enter->types[i],
1264                   savedtypes.types[i],text_uri);
1265         if (savedtypes.types[i] == text_uri)
1266           {
1267              /* Request it, so we know what it is */
1268              cnp_debug("Sending uri request\n");
1269              savedtypes.textreq = 1;
1270              savedtypes.pi = NULL; /* FIXME: Free? */
1271              ecore_x_selection_xdnd_request(enter->win, text_uri);
1272           }
1273      }
1274
1275    /* FIXME: Find an object and make it current */
1276    return EINA_TRUE;
1277 }
1278
1279 static Eina_Bool
1280 _dnd_drop(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1281 {
1282    struct _Ecore_X_Event_Xdnd_Drop *drop;
1283    Dropable *dropable;
1284    Eina_List *l;
1285    Ecore_Evas *ee;
1286    Ecore_X_Window xwin;
1287    Elm_Selection_Data ddata;
1288    int x, y, w, h;
1289    int i, j;
1290
1291    drop = ev;
1292
1293    // check we still have something to drop
1294    if (!drops) return EINA_TRUE;
1295
1296    /* Find any widget in our window; then work out geometry rel to our window */
1297    for (l = drops; l; l = l->next)
1298      {
1299         dropable = l->data;
1300         xwin = (Ecore_X_Window)ecore_evas_window_get
1301            (ecore_evas_ecore_evas_get(evas_object_evas_get
1302                                       (dropable->obj)));
1303         if (xwin == drop->win) break;
1304      }
1305    /* didn't find a window */
1306    if (!l) return EINA_TRUE;
1307
1308    /* Calculate real (widget relative) position */
1309    // - window position
1310    // - widget position
1311    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(dropable->obj));
1312    ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
1313    savedtypes.x = drop->position.x - x;
1314    savedtypes.y = drop->position.y - y;
1315    
1316    cnp_debug("Drop position is %d,%d\n", savedtypes.x, savedtypes.y);
1317
1318    for (; l; l = l->next)
1319      {
1320         dropable = l->data;
1321         evas_object_geometry_get(dropable->obj, &x, &y, &w, &h);
1322         if ((savedtypes.x >= x) && (savedtypes.y >= y) &&
1323             (savedtypes.x < x + w) && (savedtypes.y < y + h))
1324            break; /* found! */
1325      }
1326    
1327    if (!l) return EINA_TRUE; /* didn't find one */
1328    
1329    evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL);
1330    savedtypes.x -= x;
1331    savedtypes.y -= y;
1332    
1333    /* Find our type from the previous list */
1334    for (i = 0; i < CNP_N_ATOMS; i++)
1335      {
1336         for (j = 0; j < savedtypes.ntypes; j++)
1337           {
1338              if (!strcmp(savedtypes.types[j], atoms[i].name)) goto found;
1339           }
1340      }
1341    
1342    cnp_debug("Didn't find a target\n");
1343    return EINA_TRUE;
1344    
1345 found:
1346    cnp_debug("Found a target we'd like: %s\n", atoms[i].name);
1347    cnp_debug("0x%x\n",xwin);
1348    
1349    if (i == CNP_ATOM_text_urilist)
1350      {
1351         cnp_debug("We found a URI... (%scached)\n", savedtypes.pi ? "" : "not ");
1352         if (savedtypes.pi)
1353           {
1354              char *entrytag;
1355              char *tagstring = "<item absize=240x180 href=file://%s></item>";
1356              
1357              ddata.x = savedtypes.x;
1358              ddata.y = savedtypes.y;
1359
1360              if (dropable->types & ELM_SEL_FORMAT_IMAGE)
1361                {
1362                   cnp_debug("Doing image insert (%s)\n", savedtypes.pi->file);
1363                   ddata.format = ELM_SEL_FORMAT_IMAGE;
1364                   ddata.data = (char *)savedtypes.pi->file;
1365                   dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1366                   ecore_x_dnd_send_finished();
1367                   
1368                   pasteimage_free(savedtypes.pi);
1369                   savedtypes.pi = NULL;
1370                   
1371                   return EINA_TRUE;
1372                }
1373              else if (dropable->types & ELM_SEL_FORMAT_MARKUP)
1374                {
1375                   ddata.format = ELM_SEL_FORMAT_MARKUP;
1376                   pasteimage_provider_set(dropable->obj);
1377                   
1378                   pastedimages = eina_list_append(pastedimages, savedtypes.pi);
1379                   entrytag = alloca(sizeof(char)*(strlen(tagstring)+strlen(savedtypes.pi->file)+1));
1380                   snprintf(entrytag, (strlen(tagstring)+strlen(savedtypes.pi->file)),
1381                            tagstring, savedtypes.pi->file);
1382                   ddata.data = entrytag;
1383                   cnp_debug("Insert %s\n", (char *)ddata.data);
1384                   dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1385                   ecore_x_dnd_send_finished();
1386                   return EINA_TRUE;
1387                }
1388           }
1389         else if (savedtypes.textreq)
1390           {
1391              /* Already asked: Pretend we asked now, and paste immediately when
1392               * it comes in */
1393              savedtypes.textreq = 0;
1394              ecore_x_dnd_send_finished();
1395              return EINA_TRUE;
1396           }
1397      }
1398
1399    cnp_debug("doing a request then\n");
1400    selections[ELM_SEL_XDND].requestwidget = dropable->obj;
1401    selections[ELM_SEL_XDND].requestformat = ELM_SEL_FORMAT_MARKUP;
1402    selections[ELM_SEL_XDND].active = EINA_TRUE;
1403
1404    ecore_x_selection_xdnd_request(xwin, atoms[i].name);
1405
1406    return EINA_TRUE;
1407 }
1408 static Eina_Bool
1409 _dnd_position(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1410 {
1411    struct _Ecore_X_Event_Xdnd_Position *pos;
1412    Ecore_X_Rectangle rect;
1413    
1414    pos = ev;
1415    
1416    /* Need to send a status back */
1417    /* FIXME: Should check I can drop here */
1418    /* FIXME: Should highlight widget */
1419    rect.x = pos->position.x - 5;
1420    rect.y = pos->position.y - 5;
1421    rect.width = 10;
1422    rect.height = 10;
1423    ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, pos->action);
1424
1425    return EINA_TRUE;
1426 }
1427
1428 /**
1429  * When dragging this is callback response from the destination.
1430  * The important thing we care about: Can we drop; thus update cursor
1431  * appropriately.
1432  */
1433 static Eina_Bool
1434 _dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1435 {
1436    struct _Ecore_X_Event_Xdnd_Status *status = ev;
1437
1438    if (!status) return EINA_TRUE;
1439    
1440    /* Only thing we care about: will accept */
1441    if (status->will_accept)
1442      {
1443         cnp_debug("Will accept\n");
1444      }
1445    else
1446      { /* Won't accept */
1447         cnp_debug("Won't accept accept\n");
1448      }
1449    return EINA_TRUE;
1450 }
1451
1452 /**
1453  * Add a widget as drop target.
1454  */
1455 Eina_Bool
1456 elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, void *cbdata)
1457 {
1458    Dropable *drop;
1459    Ecore_X_Window xwin;
1460    int first;
1461    
1462    if (!obj) return EINA_FALSE;
1463    if (!_elm_cnp_init_count) _elm_cnp_init();
1464    
1465    /* Is this the first? */
1466    first = (!drops) ? 1 : 0;
1467    
1468    drop = calloc(1, sizeof(Dropable));
1469    if (!drop) return EINA_FALSE;
1470    drop->dropcb = dropcb;
1471    drop->cbdata = cbdata;
1472    
1473    /* FIXME: Check it's not already there */
1474    
1475    /* FIXME: Check for eina's deranged error method */
1476    drops = eina_list_append(drops, drop);
1477    
1478    if (!drops/* || or other error */)
1479      {
1480         free(drop);
1481         return EINA_FALSE;
1482      }
1483    
1484    drop->obj = obj;
1485    /* Something for now */
1486    drop->types = format;
1487    
1488    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1489                                   /* I love C and varargs */
1490                                   (Evas_Object_Event_Cb)elm_drop_target_del,
1491                                   obj);
1492    /* FIXME: Handle resizes */
1493    
1494    /* If not the first: We're done */
1495    if (!first) return EINA_TRUE;
1496    
1497    xwin = (Ecore_X_Window)ecore_evas_window_get
1498       (ecore_evas_ecore_evas_get(evas_object_evas_get(obj)));
1499    
1500    ecore_x_dnd_aware_set(xwin, EINA_TRUE);
1501    
1502    cnp_debug("Adding drop target calls\n");
1503    handler_enter = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
1504                                            _dnd_enter, NULL);
1505    handler_pos = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
1506                                          _dnd_position, NULL);
1507    handler_drop = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
1508                                           _dnd_drop, NULL);
1509    
1510    return EINA_TRUE;
1511 }
1512
1513 Eina_Bool
1514 elm_drop_target_del(Evas_Object *obj)
1515 {
1516    Dropable *drop,*del;
1517    Eina_List *item;
1518    Ecore_X_Window xwin;
1519    
1520    del = NULL;
1521    EINA_LIST_FOREACH(drops, item, drop)
1522      {
1523         if (drop->obj == obj)
1524           {
1525              drops = eina_list_remove_list(drops, item);
1526              del = drop;
1527              break;
1528           }
1529      }
1530    if (!del) return EINA_FALSE;
1531    
1532    evas_object_event_callback_del(obj, EVAS_CALLBACK_FREE,
1533                                   (Evas_Object_Event_Cb)elm_drop_target_del);
1534    free(drop);
1535    /* If still drops there: All fine.. continue */
1536    if (drops) return EINA_TRUE;
1537    
1538    cnp_debug("Disabling DND\n");
1539    xwin = (Ecore_X_Window)ecore_evas_window_get
1540       (ecore_evas_ecore_evas_get(evas_object_evas_get(obj)));
1541    ecore_x_dnd_aware_set(xwin, EINA_FALSE);
1542    
1543    ecore_event_handler_del(handler_pos);
1544    ecore_event_handler_del(handler_drop);
1545    ecore_event_handler_del(handler_enter);
1546    
1547    if (savedtypes.pi)
1548      {
1549         pasteimage_free(savedtypes.pi);
1550         savedtypes.pi = NULL;
1551      }
1552    
1553    return EINA_TRUE;
1554 }
1555
1556
1557 static void
1558 _drag_mouse_up(void *un __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *data __UNUSED__)
1559 {
1560    evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP, _drag_mouse_up);
1561    ecore_x_dnd_drop();
1562    if (dragdonecb)
1563      {
1564         dragdonecb(dragdonecb,selections[ELM_SEL_XDND].widget);
1565         dragdonecb = NULL;
1566      }
1567    if (dragwin)
1568      {
1569         evas_object_del(dragwin);
1570         dragwin = NULL;
1571      }
1572 }
1573
1574 static void
1575 _drag_move(void *data __UNUSED__, Ecore_X_Xdnd_Position *pos)
1576 {
1577    evas_object_move(dragwin, 
1578                     pos->position.x - _dragx, 
1579                     pos->position.y - _dragy);
1580 }
1581
1582
1583 Eina_Bool
1584 elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, void (*dragdone) (void *data, Evas_Object *), void *donecbdata)
1585 {
1586    Ecore_X_Window xwin;
1587    Cnp_Selection *sel;
1588    Elm_Sel_Type xdnd = ELM_SEL_XDND;
1589    Ecore_Evas *ee;
1590    int x, y, x2, y2, x3, y3;
1591    Evas_Object *icon;
1592    int w, h;
1593    
1594    if (!_elm_cnp_init_count) _elm_cnp_init();
1595    
1596    xwin = elm_win_xwindow_get(obj);
1597
1598    cnp_debug("starting drag...\n");
1599
1600    ecore_x_dnd_type_set(xwin, "text/uri-list", 1);
1601    sel = selections + ELM_SEL_XDND;
1602    sel->active = 1;
1603    sel->widget = obj;
1604    sel->format = format;
1605    sel->selbuf = data ? strdup(data) : NULL;
1606    dragdonecb = dragdone;
1607    dragdonedata = donecbdata;
1608    
1609    ecore_x_dnd_callback_pos_update_set(_drag_move, NULL);
1610    ecore_x_dnd_begin(xwin, (unsigned char *)&xdnd, sizeof(Elm_Sel_Type));
1611    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
1612                                   _drag_mouse_up, NULL);
1613    
1614    handler_status = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
1615                                             _dnd_status, NULL);
1616    
1617    dragwin = elm_win_add(NULL, "Elm Drag Object", ELM_WIN_UTILITY);
1618    elm_win_override_set(dragwin, 1);
1619    
1620    /* FIXME: Images only */
1621    icon = elm_icon_add(dragwin);
1622    elm_icon_file_set(icon, data + 7, NULL); /* 7!? "file://" */
1623    elm_win_resize_object_add(dragwin,icon);
1624    evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1625    evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL);
1626
1627    /* Position subwindow appropriately */
1628    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
1629    ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
1630    evas_object_geometry_get(obj, &x2, &y2, &w, &h);
1631    x += x2;
1632    y += y2;
1633    evas_object_move(dragwin, x, y);
1634    evas_object_resize(icon, w, h);
1635    evas_object_resize(dragwin, w, h);
1636    
1637    evas_object_show(icon);
1638    evas_object_show(dragwin);
1639
1640    evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x3, &y3);
1641    _dragx = x3 - x2;
1642    _dragy = y3 - y2;
1643
1644    return EINA_TRUE;
1645 }
1646
1647 static Tmp_Info *
1648 elm_cnp_tempfile_create(int size)
1649 {
1650    Tmp_Info *info;
1651    const char *tmppath;
1652    int len;
1653    
1654    info = malloc(sizeof(Tmp_Info));
1655    if (!info) return NULL;
1656    
1657    tmppath = getenv("TMP");
1658    if (!tmppath) tmppath = P_tmpdir;
1659    if (!tmppath) tmppath = "/tmp";
1660    len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-");
1661    if (len < 0)
1662      {
1663         free(info);
1664         return NULL;
1665      }
1666    len++;
1667    info->filename = malloc(len);
1668    if (!info->filename)
1669      {
1670         free(info);
1671         return NULL;
1672      }
1673    snprintf(info->filename,len,"%s/%sXXXXXX", tmppath, "elmcnpitem-");
1674    
1675    info->fd = mkstemp(info->filename);
1676    
1677 # ifdef __linux__
1678      {
1679         char *tmp;
1680         /* And before someone says anything see POSIX 1003.1-2008 page 400 */
1681         long pid;
1682         
1683         pid = (long)getpid();
1684         /* Use pid instead of /proc/self: That way if can be passed around */
1685         len = snprintf(NULL,0,"/proc/%li/fd/%i", pid, info->fd);
1686         len++;
1687         tmp = malloc(len);
1688         if (tmp)
1689           {
1690              snprintf(tmp,len, "/proc/%li/fd/%i", pid, info->fd);
1691              unlink(info->filename);
1692              free(info->filename);
1693              info->filename = tmp;
1694           }
1695      }
1696 # endif
1697    
1698    cnp_debug("filename is %s\n", info->filename);
1699    if (size < 1)
1700      {
1701         /* Set map to NULL and return */
1702         info->map = NULL;
1703         info->len = 0;
1704         return info;
1705      }
1706    
1707    /* Map it in */
1708    if (ftruncate(info->fd, size))
1709      {
1710         perror("ftruncate");
1711         info->map = NULL;
1712         info->len = 0;
1713         return info;
1714      }
1715    
1716    info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0);
1717    if (info->map == MAP_FAILED)
1718      {
1719         perror("mmap");
1720         info->map = NULL;
1721         info->len = 0;
1722      }
1723    
1724    return info;
1725 }
1726
1727
1728 static int
1729 tmpinfo_free(Tmp_Info *info)
1730 {
1731    if (!info) return 0;
1732    free(info->filename);
1733    free(info);
1734    return 0;
1735 }
1736
1737 #else
1738 /* Stubs for windows */
1739 Eina_Bool
1740 elm_drag_start(Evas_Object *o, Elm_Sel_Format f, const char *d, void (*donecb)(void *, Evas_Object *),void *cbdata)
1741 {
1742    return EINA_FALSE;
1743 }
1744
1745 Eina_Bool
1746 elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, void *cbdata)
1747 {
1748    return EINA_FALSE;
1749 }
1750
1751 Eina_Bool
1752 elm_drop_target_del(Evas_Object *o)
1753 {
1754    return EINA_TRUE;
1755 }
1756 #endif
1757
1758 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/