[elm_cnp_helper] adding workaround for SEL_SECONDARY
[framework/uifw/elementary.git] / src / lib / elm_cnp_helper.c
1 #include <stdbool.h>
2
3 #include <stdio.h> // debug
4
5 #include <Elementary.h>
6
7 #include "elm_priv.h"
8
9 #ifdef HAVE_ELEMENTARY_X
10
11 # include <X11/X.h>
12 # include <X11/Xatom.h>
13
14
15 # define ARRAYINIT(foo)  [foo]=
16
17 #define DEBUGON 1
18
19 #if DEBUGON
20 #define cnp_debug(x...) printf(__FILE__": " x)
21 #else
22 #define cnp_debug(x...)
23 #endif
24
25
26 enum {
27      CNP_ATOM_TARGETS = 0,
28      CNP_ATOM_text_uri,
29      CNP_ATOM_image_png,
30      CNP_ATOM_XELM,
31      CNP_ATOM_text_html_utf8,
32      CNP_ATOM_text_html,
33      CNP_ATOM_UTF8STRING,
34      CNP_ATOM_STRING,
35      CNP_ATOM_TEXT,
36      CNP_ATOM_text_plain_utf8,
37      CNP_ATOM_text_plain,
38
39      CNP_N_ATOMS,
40 };
41 struct pasteimage {
42      Evas_Object *entry;
43      const char *tag;
44      const char *file;
45      Evas_Object *img;
46 };
47
48
49 struct _elm_cnp_selection {
50    const char *debug;
51    Evas_Object *widget;
52
53    enum _elm_sel_format format;
54    char *selbuf;
55
56    unsigned int active : 1;
57
58    Ecore_X_Selection ecore_sel;
59
60    Evas_Object *requestwidget;
61    enum _elm_sel_format requestformat;
62
63    int (*set)(Ecore_X_Window, const void *data, int size);
64    int (*clear)(void);
65    void (*request)(Ecore_X_Window, const char *target);
66 };
67
68 /* Optimisation: Turn this into a 256 byte table:
69  *      then can lookup in one index, not N checks */
70 static const struct escapes {
71    const char *escape;
72    const char value;
73 } escapes[] = {
74    { "<br>",    '\n' },
75    { "<\t>",    '\t' },
76    { "gt;",     '>' },
77    { "lt;",     '<' },
78    { "amp;",'&' },
79    { "quot;",'\'' },
80    { "dquot;", '"' },
81 };
82 #define N_ESCAPES ((int)(sizeof(escapes)/sizeof(escapes[0])))
83
84
85 static Eina_Bool _elm_cnp_init(void);
86 static Eina_Bool selection_clear(void *udata __UNUSED__, int type, void *event);
87 //static Eina_Bool selection_request(void *udata __UNUSED__, int type, void *event);
88 static Eina_Bool selection_notify(void *udata __UNUSED__, int type, void *event);
89 static char *remove_tags(const char *p, int *len);
90 static char *mark_up(const char *start, int *lenp);
91
92 static Evas_Object *image_provider(void *images, Evas_Object *entry, const char *item);
93
94
95 typedef int (*converter_fn)(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
96
97 static int targets_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
98 static int text_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
99 static int html_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
100 static int edje_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
101 static int uri_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
102 static int png_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
103
104 /* FIXME: Which way should this be: Notify or response */
105 typedef int (*response_handler)(struct _elm_cnp_selection *sel,
106       Ecore_X_Event_Selection_Notify *);
107 static int response_handler_targets(struct _elm_cnp_selection *sel,
108       Ecore_X_Event_Selection_Notify *);
109
110 typedef int (*notify_handler)(struct _elm_cnp_selection *sel,
111       Ecore_X_Event_Selection_Notify *);
112 static int notify_handler_targets(struct _elm_cnp_selection *sel,
113       Ecore_X_Event_Selection_Notify *notify);
114 static int notify_handler_text(struct _elm_cnp_selection *sel,
115       Ecore_X_Event_Selection_Notify *notify);
116 static int notify_handler_png(struct _elm_cnp_selection *sel,
117       Ecore_X_Event_Selection_Notify *notify);
118 static int notify_handler_uri(struct _elm_cnp_selection *sel,
119       Ecore_X_Event_Selection_Notify *notify);
120
121
122 static struct {
123    const char *name;
124    enum _elm_sel_format formats;
125    /* Called by ecore to do conversion */
126    converter_fn converter;
127    response_handler response;
128    notify_handler notify;
129    /* Atom */
130    Ecore_X_Atom atom;
131 } atoms[CNP_N_ATOMS] = {
132    [CNP_ATOM_TARGETS] = {
133         "TARGETS",
134         (enum _elm_sel_format)-1,
135         targets_converter,
136         response_handler_targets,
137         notify_handler_targets,
138         0
139    },
140    [CNP_ATOM_XELM] =  {
141         "application/x-elementary-markup",
142         ELM_SEL_MARKUP,
143         edje_converter,
144         NULL,
145         NULL,
146         0
147    },
148    [CNP_ATOM_text_uri] = {
149         "text/uri",
150         ELM_SEL_MARKUP | ELM_SEL_IMAGE, /* Either images or entries */
151         uri_converter,
152         NULL,
153         notify_handler_uri,
154         0
155    },
156    [CNP_ATOM_image_png] = {
157         "image/png",
158         ELM_SEL_IMAGE | ELM_SEL_IMAGE,
159         png_converter,
160         NULL,
161         notify_handler_png,
162         0
163    },
164    [CNP_ATOM_text_html_utf8] = {
165         "text/html;charset=utf-8",
166         ELM_SEL_MARKUP,
167         html_converter,
168         NULL,
169         NULL,
170         0
171    },
172    [CNP_ATOM_text_html] = {
173         "text/html",
174         ELM_SEL_MARKUP,
175         html_converter,
176         NULL,
177         NULL,
178         0
179    },
180    [CNP_ATOM_UTF8STRING] = {
181         "UTF8_STRING",
182 //      ELM_SEL_MARKUP,
183         ELM_SEL_MARKUP | ELM_SEL_IMAGE,
184         text_converter,
185         NULL,
186         notify_handler_text,
187         0
188    },
189    [CNP_ATOM_STRING] = {
190         "STRING",
191         ELM_SEL_MARKUP | ELM_SEL_IMAGE,
192         text_converter,
193         NULL,
194         notify_handler_text,
195         0
196    },
197    [CNP_ATOM_TEXT] = {
198         "TEXT",
199         ELM_SEL_MARKUP | ELM_SEL_IMAGE,
200         text_converter,
201         NULL,
202         NULL,
203         0
204    },
205    [CNP_ATOM_text_plain_utf8] = {
206         "text/plain;charset=ut-8",
207         ELM_SEL_MARKUP,
208         text_converter,
209         NULL,
210         NULL,
211         0
212    },
213    [CNP_ATOM_text_plain] = {
214         "text/plain",
215         ELM_SEL_MARKUP,
216         text_converter,
217         NULL,
218         NULL,
219         0
220    },
221 };
222
223 static struct _elm_cnp_selection selections[ELM_SEL_MAX] = {
224    ARRAYINIT(ELM_SEL_PRIMARY) {
225        .debug = "Primary",
226        .ecore_sel = ECORE_X_SELECTION_PRIMARY,
227        .set = ecore_x_selection_primary_set,
228        .clear = ecore_x_selection_primary_clear,
229        .request = ecore_x_selection_primary_request,
230    },
231    ARRAYINIT(ELM_SEL_SECONDARY) {
232        .debug = "Secondary",
233        .ecore_sel = ECORE_X_SELECTION_SECONDARY,
234        .set = ecore_x_selection_secondary_set,
235        .clear = ecore_x_selection_secondary_clear,
236        .request = ecore_x_selection_secondary_request,
237    },
238    ARRAYINIT(ELM_SEL_CLIPBOARD) {
239        .debug = "Clipboard",
240        .ecore_sel = ECORE_X_SELECTION_CLIPBOARD,
241        .set = ecore_x_selection_clipboard_set,
242        .clear = ecore_x_selection_clipboard_clear,
243        .request = ecore_x_selection_clipboard_request,
244    }
245 };
246
247 static int _elm_cnp_init_count = 0;
248   /* Gah... who left this out of XAtoms.h */
249 static Ecore_X_Atom clipboard_atom;
250
251 Eina_List *pastedimages;
252 #endif
253
254
255 Eina_Bool
256 elm_selection_set(enum _elm_sel_type selection, Evas_Object *widget,
257                         enum _elm_sel_format format, const char *selbuf)
258 {
259 #ifdef HAVE_ELEMENTARY_X
260    struct _elm_cnp_selection *sel;
261
262    if ((unsigned int)selection >= (unsigned int)ELM_SEL_MAX) return EINA_FALSE;
263    if (!_elm_cnp_init_count) _elm_cnp_init();
264    if (!selbuf && format != ELM_SEL_IMAGE)
265      return elm_selection_clear(selection, widget);
266
267    sel = selections + selection;
268
269    sel->active = 1;
270    sel->widget = widget;
271
272    sel->set(elm_win_xwindow_get(widget),&selection,sizeof(enum _elm_sel_type));
273    sel->format = format;
274    sel->selbuf = selbuf ? strdup(selbuf) : NULL;
275
276    return EINA_TRUE;
277 #else
278    return EINA_FALSE;
279 #endif
280 }
281
282 Eina_Bool
283 elm_selection_clear(enum _elm_sel_type selection, Evas_Object *widget)
284 {
285 #ifdef HAVE_ELEMENTARY_X
286    struct _elm_cnp_selection *sel;
287
288    if ((unsigned int)selection >= (unsigned int)ELM_SEL_MAX) return EINA_FALSE;
289    if (!_elm_cnp_init_count) _elm_cnp_init();
290
291    sel = selections + selection;
292
293    /* No longer this selection: Consider it gone! */
294    if (!sel->active || sel->widget != widget) return EINA_TRUE;
295
296    sel->active = 0;
297    sel->widget = NULL;
298    sel->clear();
299
300    return EINA_TRUE;
301 #else
302    return EINA_FALSE;
303 #endif
304 }
305
306 Eina_Bool
307 elm_selection_get(enum _elm_sel_type selection, enum _elm_sel_format format,
308                         Evas_Object *widget)
309 {
310 #ifdef HAVE_ELEMENTARY_X
311    Evas_Object *top;
312    struct _elm_cnp_selection *sel;
313
314    if ((unsigned int)selection >= (unsigned int)ELM_SEL_MAX) return EINA_FALSE;
315    if (!_elm_cnp_init_count) _elm_cnp_init();
316
317    sel = selections + selection;
318    top = elm_widget_top_get(widget);
319    if (!top) return EINA_FALSE;
320
321    sel->requestformat = format;
322    sel->requestwidget = widget;
323    sel->request(elm_win_xwindow_get(top), ECORE_X_SELECTION_TARGET_UTF8_STRING);
324
325    return EINA_TRUE;
326 #else
327    return EINA_FALSE;
328 #endif
329 }
330
331 #ifdef HAVE_ELEMENTARY_X
332
333 static Eina_Bool
334 _elm_cnp_init(void){
335    int i;
336    if (_elm_cnp_init_count ++) return EINA_TRUE;
337
338    /* FIXME: Handle XCB */
339    for (i = 0 ; i < CNP_N_ATOMS ; i ++)
340      {
341         atoms[i].atom = ecore_x_atom_get(atoms[i].name);
342         ecore_x_selection_converter_atom_add(atoms[i].atom,
343               atoms[i].converter);
344      }
345    clipboard_atom = ecore_x_atom_get("CLIPBOARD");
346
347    ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, selection_clear,NULL);
348    ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY,selection_notify,NULL);
349     return EINA_TRUE;
350 }
351
352 static Eina_Bool
353 selection_clear(void *udata __UNUSED__, int type __UNUSED__, void *event){
354    Ecore_X_Event_Selection_Clear *ev = event;
355    struct _elm_cnp_selection *sel;
356    int i;
357
358    for (i = 0 ; i < ELM_SEL_MAX ; i ++)
359      {
360         if (selections[i].ecore_sel == ev->selection) break;
361      }
362    /* Not me... Don't care */
363    if (i == ELM_SEL_MAX) return ECORE_CALLBACK_PASS_ON;
364
365    sel = selections + i;
366    sel->active = 0;
367    sel->widget = NULL;
368    sel->selbuf = NULL;
369
370    return ECORE_CALLBACK_PASS_ON;
371 }
372
373 #if 0
374 /**
375  * Response to a selection request
376  */
377 static Eina_Bool
378 selection_request(void *udata __UNUSED__, int type, void *event){
379    Ecore_X_Event_Selection_Request *ev = event;
380    struct _elm_cnp_selection *sel;
381    int i;
382 printf("selection request callback: %d\n",ev->selection);
383 printf("selection request callback: %d\n",ev->target);
384
385    if (ev->selection == clipboard_atom){
386          sel = selections + ELM_SEL_CLIPBOARD;
387    } else if (ev->selection == XA_PRIMARY){
388          sel = selections + ELM_SEL_PRIMARY;
389    } else if (ev->selection ==  XA_SECONDARY){
390          sel = selections + ELM_SEL_SECONDARY;
391    } else {
392          return ECORE_CALLBACK_PASS_ON;
393    }
394    return ECORE_CALLBACK_PASS_ON;
395
396    for (i = 0 ; i < CNP_N_ATOMS ; i ++)
397      {
398         if (ev->target == atoms[i].atom)
399           {
400              if (atoms[i].response){
401                   atoms[i].response(sel, ev);
402              } else {
403                   printf("Ignored: No handler!\n");
404              }
405           }
406      }
407
408    return ECORE_CALLBACK_PASS_ON;
409 }
410 #endif
411
412
413 /*
414  * Response to a selection notify:
415  *      - So we have asked for the selection list.
416  *      - If it's the targets list, parse it, and fire of what we want,
417  *      else it's the data we want.
418  */
419 static Eina_Bool
420 selection_notify(void *udata __UNUSED__, int type __UNUSED__, void *event){
421    Ecore_X_Event_Selection_Notify *ev = event;
422    struct _elm_cnp_selection *sel;
423    struct _elm_cnp_selection *bufsel;
424    int i;
425
426    cnp_debug("selection notify callback: %d\n",ev->selection);
427    switch (ev->selection){
428       case ECORE_X_SELECTION_CLIPBOARD:
429          sel = selections + ELM_SEL_CLIPBOARD;
430          break;
431
432       case ECORE_X_SELECTION_PRIMARY:
433          sel = selections + ELM_SEL_PRIMARY;
434          break;
435       case ECORE_X_SELECTION_SECONDARY:
436          sel = selections + ELM_SEL_SECONDARY;
437          break;
438       default:
439          return ECORE_CALLBACK_PASS_ON;
440    }
441    cnp_debug("Target is %s\n",ev->target);
442
443    for (i = 0 ; i < CNP_N_ATOMS ; i ++)
444      {
445         if (strcmp(ev->target, atoms[i].name) == 0)
446           {
447              if (atoms[i].notify){
448                   cnp_debug("Found something: %s\n", atoms[i].name);
449                   bufsel = selections;
450                   /* FIXME : it's maybe a bug. more overhaul it!!! */
451                   sel->selbuf = bufsel->selbuf;
452                   atoms[i].notify(sel, ev);
453              } else {
454                   printf("Ignored: No handler!\n");
455              }
456           }
457      }
458
459    return ECORE_CALLBACK_PASS_ON;
460 }
461
462
463
464 static int
465 targets_converter(char *target __UNUSED__, void *data, int size __UNUSED__,
466                   void **data_ret, int *size_ret,
467                   Ecore_X_Atom *ttype, int *typesize){
468    int i,count;
469    Ecore_X_Atom *aret;
470    struct _elm_cnp_selection *sel;
471
472    if (!data_ret) return -1;
473
474    sel = selections + *(int*)data;
475
476    for (i = 0, count = 0 ; i < CNP_N_ATOMS ; i ++)
477         if (sel->format & atoms[i].formats)
478            count ++;
479
480    aret = malloc(sizeof(Ecore_X_Atom) * count);
481    for (i = 0, count = 0 ; i < CNP_N_ATOMS ; i ++)
482         if (sel->format & atoms[i].formats)
483           aret[count ++] = atoms[i].atom;
484
485    *data_ret = aret;
486    if (typesize) *typesize = 32 /* urk */;
487    if (ttype) *ttype = XA_ATOM;
488    if (size_ret) *size_ret = count;
489
490    return 1;
491 }
492
493 static int
494 png_converter(char *target __UNUSED__, void *data __UNUSED__, int size __UNUSED__,
495               void **data_ret __UNUSED__, int *size_ret __UNUSED__,
496               Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
497 {
498      return 1;
499 }
500
501 /*
502  * Callback to handle a targets response on a selection request:
503  * So pick the format we'd like; and then request it.
504  */
505 static int
506 notify_handler_targets(struct _elm_cnp_selection *sel,
507                        Ecore_X_Event_Selection_Notify *notify)
508 {
509    Ecore_X_Selection_Data_Targets *targets;
510    Ecore_X_Atom *atomlist;
511    int i,j;
512
513    targets = notify->data;
514    atomlist = (Ecore_X_Atom *)(targets->data.data);
515
516    for (j = 1; j < CNP_N_ATOMS ; j ++)
517      {
518         cnp_debug("\t%s %d\n",atoms[j].name, atoms[j].atom);
519         if (!(atoms[j].formats & sel->requestformat)) continue;
520         for (i = 0 ; i < targets->data.length ; i ++)
521           {
522              if (atoms[j].atom == atomlist[i])
523                {
524                   cnp_debug("Atom %s matches\n",atoms[j].name);
525                   goto done;
526                }
527           }
528      }
529
530    cnp_debug("Couldn't find anything that matches\n");
531    return ECORE_CALLBACK_PASS_ON;
532
533    done:
534    cnp_debug("Sending request for %s\n",atoms[j].name);
535    sel->request(elm_win_xwindow_get(sel->requestwidget), atoms[j].name);
536
537    return ECORE_CALLBACK_PASS_ON;
538 }
539
540 static int
541 response_handler_targets(struct _elm_cnp_selection *sel,
542                          Ecore_X_Event_Selection_Notify *notify)
543 {
544    Ecore_X_Selection_Data_Targets *targets;
545    Ecore_X_Atom *atomlist;
546    Evas_Object *top;
547    int i,j;
548    int prio, selected;
549
550    targets = notify->data;
551    atomlist = (Ecore_X_Atom *)(targets->data.data);
552
553    prio = -1;
554    selected = -1;
555    /* Start from 1: Skip targets */
556    for (j = 1 ; j < CNP_N_ATOMS ; j ++)
557      {
558         if (!(atoms[j].formats & sel->requestformat)) continue;
559         for (i = 0 ; i < targets->data.length ; i ++)
560           {
561              if (atoms[j].atom == atomlist[i] && atoms[j].response){
562                   /* Found a match: Use it */
563                   goto found;
564              }
565         }
566      }
567         found:
568    if (j == CNP_N_ATOMS)
569      {
570         cnp_debug("No matching type found\n");
571         return 0;
572      }
573
574    top = elm_widget_top_get(sel->requestwidget);
575    if (!top) return 0;
576
577    sel->request(elm_win_xwindow_get(top), atoms[j].name);
578    return 0;
579 }
580
581
582 static int
583 notify_handler_text(struct _elm_cnp_selection *sel,
584                     Ecore_X_Event_Selection_Notify *notify)
585 {
586    Ecore_X_Selection_Data *data;
587    char *str;
588
589    fprintf(stderr, "## notify_handler_text selbuf - %s\n", sel->selbuf);
590
591 //   data = notify->data;
592 //   str = mark_up((char*)data->data, NULL);
593    str = mark_up(sel->selbuf, NULL);
594    fprintf(stderr, "## notify_handler_text str - %s\n", str);
595
596    elm_entry_entry_insert(sel->requestwidget, str);
597    free(str);
598
599    return 0;
600 }
601
602
603 /**
604  * So someone is pasting an image into my entry or widget...
605  */
606 static int
607 notify_handler_uri(struct _elm_cnp_selection *sel,
608          Ecore_X_Event_Selection_Notify *notify)
609 {
610    Ecore_X_Selection_Data *data;
611    struct pasteimage *pi;
612    char entrytag[100];
613    char *p;
614
615    data = notify->data;
616    p = (char *)data->data;
617    cnp_debug("Got %s\n",p);
618    if (strncmp(p,"file://",7) != 0){
619         cnp_debug("Doesn't start with ;file;  %s\n",p);
620         return 0;
621    }
622
623    p += strlen("file://");
624
625    pi = calloc(1,sizeof(struct pasteimage));
626    snprintf(entrytag, sizeof(entrytag), "pasteimage-%p",pi);
627    pi->tag = strdup(entrytag);
628    pi->file = strndup(p,data->length - strlen("file://"));
629
630    elm_entry_item_provider_append(sel->requestwidget, image_provider, pi);
631    pastedimages = eina_list_append(pastedimages, pi);
632
633    snprintf(entrytag, sizeof(entrytag), "<item absize=240x180 href=%s>",pi->tag);
634    elm_entry_entry_insert(sel->requestwidget, entrytag);
635
636    return 0;
637 }
638
639 static int
640 notify_handler_png(struct _elm_cnp_selection *sel __UNUSED__,
641                    Ecore_X_Event_Selection_Notify *notify __UNUSED__)
642 {
643    cnp_debug("got a png!\n");
644    return 0;
645 }
646
647
648 static int
649 text_converter(char *target __UNUSED__, void *data, int size __UNUSED__,
650                void **data_ret, int *size_ret,
651                Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
652 {
653    struct _elm_cnp_selection *sel;
654
655    sel = selections + *(int *)data;
656    if (!sel->active)
657      {
658         return 1;
659      }
660
661    if (sel->format == ELM_SEL_MARKUP){
662         *data_ret = remove_tags(sel->selbuf, size_ret);
663         fprintf(stderr, "## text_convert - %s\n", *data_ret);
664    } else if (sel->format == ELM_SEL_IMAGE){
665         cnp_debug("Image %s\n",evas_object_type_get(sel->widget));
666         cnp_debug("Elm type: %s\n",elm_object_widget_type_get(sel->widget));
667         evas_object_image_file_get(elm_photocam_internal_image_get(sel->widget), (const char **)data_ret, NULL);
668         if (!*data_ret) *data_ret = strdup("No file");
669         else *data_ret = strdup(*data_ret);
670         *size_ret = strlen(*data_ret);
671    }
672    return 1;
673 }
674
675 static int
676 edje_converter(char *target __UNUSED__, void *data, int size __UNUSED__, 
677                void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, 
678                int *typesize __UNUSED__)
679 {
680    struct _elm_cnp_selection *sel;
681
682    sel = selections + *(int *)data;
683    if (data_ret) *data_ret = strdup(sel->selbuf);
684    if (size_ret) *size_ret = strlen(sel->selbuf);
685
686    return 1;
687 }
688
689
690 static int
691 html_converter(char *target __UNUSED__, void *data, int size __UNUSED__, 
692                void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, 
693                int *typesize __UNUSED__)
694 {
695    struct _elm_cnp_selection *sel;
696
697    sel = selections + *(int *)data;
698    if (data_ret) *data_ret = strdup(sel->selbuf);
699    if (size_ret) *size_ret = strlen(sel->selbuf);
700
701    return 1;
702 }
703
704 static int
705 uri_converter(char *target __UNUSED__, void *data, int size __UNUSED__, 
706               void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, 
707               int *typesize __UNUSED__)
708 {
709     struct _elm_cnp_selection *sel;
710     sel = selections + *(int *)data;
711     cnp_debug("Uri converter\n");
712     if (data_ret) *data_ret = strdup(sel->selbuf);
713     if (size_ret) *size_ret = strlen(sel->selbuf);
714     return 1;
715 }
716
717
718 /*
719  * Image paste provide
720  */
721
722 /* FIXME: Should add provider for each pated item: Use data to store it
723  * much easier */
724 static Evas_Object *
725 image_provider(void *images __UNUSED__, Evas_Object *entry, const char *item)
726 {
727    struct pasteimage *pi;
728    Eina_List *l;
729
730    cnp_debug("image provider for %s called\n",item);
731    EINA_LIST_FOREACH(pastedimages, l, pi)
732      {
733         cnp_debug("is it %s?\n",pi->tag);
734         if (strcmp(pi->tag,item) == 0){
735              /* Found it */
736              Evas_Object *o;
737              o = evas_object_image_filled_add(evas_object_evas_get(entry));
738              /* FIXME: Handle eets */
739              cnp_debug("file is %s (object is %p)\n",pi->file,o);
740              evas_object_image_file_set(o, pi->file, NULL);
741              evas_object_show(o);
742              return o;
743         }
744      }
745    return NULL;
746 }
747
748 static void
749 entry_deleted(void *images __UNUSED__, Evas *e __UNUSED__, Evas_Object *entry, void *unused __UNUSED__)
750 {
751    struct pasteimage *pi;
752    Eina_List *l,*next;
753
754    EINA_LIST_FOREACH_SAFE(pastedimages, l, next, pi)
755      {
756         if (pi->entry == entry){
757              pastedimages = eina_list_remove_list(pastedimages, l);
758         }
759      }
760 }
761
762
763 static char *
764 remove_tags(const char *p, int *len){
765    char *q,*ret;
766    int i;
767    if (!p) return NULL;
768
769    q = malloc(strlen(p) + 1);
770    if (!q) return NULL;
771    ret = q;
772
773    while (*p)
774      {
775         if (*p != '<' && *p != '&'){
776              *q ++ = *p ++;
777         } else if (*p == '<') {
778              if (p[1] == 'b' && p[2] == 'r' &&
779                         (p[3] == ' ' || p[3] == '/' || p[3] == '>'))
780                 *q++ = '\n';
781              while (*p && *p != '>') p ++;
782              p ++;
783         } else if (*p == '&') {
784              p ++;
785              for (i = 0 ; i < N_ESCAPES ; i ++){
786                   if (!strncmp(p,escapes[i].escape, strlen(escapes[i].escape))){
787                        p += strlen(escapes[i].escape);
788                        *q = escapes[i].value;
789                        q ++;
790                        break;
791                   }
792              }
793              if (i == N_ESCAPES)
794                *q ++ = '&';
795         }
796      }
797    *q = 0;
798    if (len) *len = q - ret;
799    return ret;
800 }
801
802 /* Mark up */
803 static char *
804 mark_up(const char *start, int *lenp){
805   int l,i;
806   const char *p;
807   char *q,*ret;
808
809   if (!start) return NULL;
810   /* First pass: Count characters */
811   for (l = 0, p = start ; *p ; p ++)
812     {
813     for (i = 0 ; i < N_ESCAPES ; i ++)
814       {
815          if (*p == escapes[i].value)
816            {
817               l += strlen(escapes[i].escape);
818               break;
819            }
820       }
821     if (i == N_ESCAPES)
822          l ++;
823   }
824
825   q = ret = malloc(l + 1);
826
827   /* Second pass: Change characters */
828   for (p = start ; *p ; )
829     {
830     for (i = 0 ; i < N_ESCAPES ; i ++)
831       {
832          if (*p == escapes[i].value)
833            {
834               strcpy(q, escapes[i].escape);
835               q += strlen(escapes[i].escape);
836               p ++;
837               break;
838            }
839       }
840     if (i == N_ESCAPES)
841          *q ++ = *p ++;
842   }
843   *q = 0;
844
845   if (lenp) *lenp = l;
846   return ret;
847 }
848
849
850 #endif