[elm_cnp_helper, elm_entry] modify for CBHM refactoring
[framework/uifw/elementary.git] / src / lib / elm_cnp_helper.c
index ffa88fe..424b335 100644 (file)
@@ -18,6 +18,9 @@
 # define cnp_debug(x...)
 #endif
 
+#define PROVIDER_SET "__elm_cnp_provider_set"
+
+typedef struct _Paste_Image   Paste_Image;
 typedef struct _Cnp_Selection Cnp_Selection;
 typedef struct _Escape        Escape;
 typedef struct _Tmp_Info      Tmp_Info;
@@ -32,6 +35,8 @@ typedef int       (*Notify_Handler_Cb)   (Cnp_Selection *sel, Ecore_X_Event_Sele
 enum
 {
    CNP_ATOM_TARGETS = 0,
+   CNP_ATOM_ATOM,
+   CNP_ATOM_LISTING_ATOMS = CNP_ATOM_ATOM,
    CNP_ATOM_text_uri,
    CNP_ATOM_text_urilist,
    CNP_ATOM_text_x_vcard,
@@ -56,6 +61,14 @@ enum
    CNP_N_ATOMS,
 };
 
+struct _Paste_Image
+{
+   Evas_Object *entry;
+   const char  *tag;
+   const char  *file;
+   Evas_Object *img;
+};
+
 struct _Cnp_Selection
 {
    const char      *debug;
@@ -78,7 +91,7 @@ struct _Cnp_Selection
 struct _Escape
 {
    const char *escape;
-   const char  value;
+   const char  *value;
 };
 
 struct _Tmp_Info
@@ -104,7 +117,7 @@ struct _Cnp_Atom
 struct _Saved_Type
 {
    const char  **types;
-   char         *imgfile;
+   Paste_Image  *pi;
    int           ntypes;
    int           x, y;
    Eina_Bool     textreq: 1;
@@ -128,11 +141,12 @@ static Eina_Bool selection_notify(void *udata __UNUSED__, int type, void *event)
 static char *remove_tags(const char *p, int *len);
 static char *mark_up(const char *start, int inlen, int *lenp);
 
+static Evas_Object *image_provider(void *images, Evas_Object *entry, const char *item);
+static void entry_deleted(void *images, Evas *e, Evas_Object *entry, void *unused);
+
 static Eina_Bool targets_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
 static Eina_Bool text_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
-static Eina_Bool html_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
-static Eina_Bool edje_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
-static Eina_Bool uri_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
+static Eina_Bool general_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
 static Eina_Bool image_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
 static Eina_Bool vcard_send(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
 
@@ -142,21 +156,28 @@ static int notify_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_No
 static int notify_handler_text(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
 static int notify_handler_image(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
 static int notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
+static int notify_handler_edje(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
 static int notify_handler_html(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
 static int vcard_receive(Cnp_Selection *sed, Ecore_X_Event_Selection_Notify *notify);
 
-static Eina_Bool pasteimage_append(char *file, Evas_Object *entry);
+static Paste_Image *pasteimage_alloc(const char *file, int pathlen);
+static Eina_Bool pasteimage_append(Paste_Image *pi, Evas_Object *entry);
+static void pasteimage_free(Paste_Image *pi);
+static void entry_insert_filter(Evas_Object* entry, char* str);
+
+#define _PARAGRAPH_SEPARATOR "\xE2\x80\xA9"
 
 /* Optimisation: Turn this into a 256 byte table:
  *     then can lookup in one index, not N checks */
 static const Escape escapes[] = {
-       { "<br>",   '\n' },
-       { "<\t>",   '\t' },
-       { "gt;",    '>'  },
-       { "lt;",    '<'  },
-       { "amp;",   '&'  },
-       { "quot;",  '\'' },
-       { "dquot;", '"'  }
+  { "<ps>",  _PARAGRAPH_SEPARATOR },
+  { "<br>",  "\n" },
+  { "<\t>",  "\t" },
+  { "&gt;",   ">" },
+  { "&lt;",    "<" },
+  { "&amp;",   "&" },
+  { "&quot;",  "'" },
+  { "&dquot;", "\"" }
 };
 #define N_ESCAPES ((int)(sizeof(escapes) / sizeof(escapes[0])))
 
@@ -169,18 +190,26 @@ static Cnp_Atom atoms[CNP_N_ATOMS] = {
           notify_handler_targets,
           0
      },
+     [CNP_ATOM_ATOM] = {
+          "ATOM",
+          (Elm_Sel_Format) -1, // everything
+          targets_converter,
+          response_handler_targets,
+          notify_handler_targets,
+          0
+     },
      [CNP_ATOM_XELM] =  {
           "application/x-elementary-markup",
           ELM_SEL_FORMAT_MARKUP,
-          edje_converter,
-          NULL,
+          general_converter,
           NULL,
+          notify_handler_edje,
           0
      },
      [CNP_ATOM_text_uri] = {
           "text/uri",
-          ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE, /* Either images or entries */
-          uri_converter,
+          ELM_SEL_FORMAT_IMAGE, /* Either images or entries */
+          general_converter,
           NULL,
           notify_handler_uri,
           0
@@ -188,7 +217,7 @@ static Cnp_Atom atoms[CNP_N_ATOMS] = {
      [CNP_ATOM_text_urilist] = {
           "text/uri-list",
           ELM_SEL_FORMAT_IMAGE,
-          uri_converter,
+          general_converter,
           NULL,
           notify_handler_uri,
           0
@@ -274,7 +303,7 @@ static Cnp_Atom atoms[CNP_N_ATOMS] = {
      [CNP_ATOM_text_html_utf8] = {
           "text/html;charset=utf-8",
           ELM_SEL_FORMAT_HTML,
-          html_converter,
+          general_converter,
           NULL,
           notify_handler_html,
           0
@@ -282,7 +311,7 @@ static Cnp_Atom atoms[CNP_N_ATOMS] = {
      [CNP_ATOM_text_html] = {
           "text/html",
           ELM_SEL_FORMAT_HTML,
-          html_converter,
+          general_converter,
           NULL,
           notify_handler_html, /* No encoding: Webkit only */
           0
@@ -365,8 +394,8 @@ static void (*dragdonecb) (void *data, Evas_Object *obj) = NULL;
 static void *dragdonedata = NULL;
 
 static int _elm_cnp_init_count = 0;
-/* FIXME: who left this out of XAtoms.h */
-static Ecore_X_Atom clipboard_atom;
+
+static Eina_List *pastedimages = NULL;
 
 /**
  * Drag & Drop functions
@@ -387,6 +416,16 @@ static Ecore_Event_Handler *handler_status = NULL;
 static const char *text_uri;
 
 Eina_Bool
+elm_selection_selection_has_owner(void)
+{
+#ifdef HAVE_ELEMENTARY_X
+   return !!ecore_x_selection_owner_get(ECORE_X_ATOM_SELECTION_CLIPBOARD);
+#else
+   return EINA_FALSE;
+#endif
+}
+
+Eina_Bool
 elm_selection_set(Elm_Sel_Type selection, Evas_Object *widget, Elm_Sel_Format format, const char *selbuf)
 {
 #ifdef HAVE_ELEMENTARY_X
@@ -482,7 +521,6 @@ _elm_cnp_init(void)
         ecore_x_selection_converter_atom_add(atoms[i].atom,
                                              atoms[i].converter);
      }
-   clipboard_atom = ecore_x_atom_get("CLIPBOARD");
 
    ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, selection_clear, NULL);
    ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, selection_notify, NULL);
@@ -570,7 +608,7 @@ selection_notify(void *udata __UNUSED__, int type __UNUSED__, void *event)
 
 
 static Eina_Bool
-targets_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
+targets_converter(char *target __UNUSED__, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
 {
    int i,count;
    Ecore_X_Atom *aret;
@@ -578,6 +616,20 @@ targets_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void
 
    if (!data_ret) return EINA_FALSE;
 
+   if (size != sizeof(int))
+     {
+        if (data_ret)
+          {
+             *data_ret = malloc(size * sizeof(char) + 1);
+             memcpy(*data_ret, data, size);
+             ((char**)(data_ret))[0][size] = 0;
+          }
+        if (size_ret) *size_ret = size;
+        return EINA_TRUE;
+     }
+
+   if (!data || (*((unsigned int *)data) >= ELM_SEL_MAX))
+     return EINA_FALSE;
    sel = selections + *((int *)data);
 
    for (i = 0, count = 0; i < CNP_N_ATOMS ; i++)
@@ -613,6 +665,8 @@ vcard_send(char *target __UNUSED__, void *data __UNUSED__, int size __UNUSED__,
 
    cnp_debug("Vcard send called\n");
 
+   if (!data || (*((unsigned int *)data) >= ELM_SEL_MAX))
+     return EINA_FALSE;
    sel = selections + *((int *)data);
 
    if (data_ret) *data_ret = strdup(sel->selbuf);
@@ -621,6 +675,7 @@ vcard_send(char *target __UNUSED__, void *data __UNUSED__, int size __UNUSED__,
    return EINA_TRUE;
 }
 
+#if 0
 static Eina_Bool
 is_uri_type_data(Cnp_Selection *sel __UNUSED__, Ecore_X_Event_Selection_Notify *notify)
 {
@@ -641,7 +696,7 @@ is_uri_type_data(Cnp_Selection *sel __UNUSED__, Ecore_X_Event_Selection_Notify *
 
    return EINA_TRUE;
 }
-
+#endif
 /*
  * Callback to handle a targets response on a selection request:
  * So pick the format we'd like; and then request it.
@@ -657,7 +712,7 @@ notify_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notif
    targets = notify->data;
    atomlist = (Ecore_X_Atom *)(targets->data.data);
 
-   for (j = 1; j < CNP_N_ATOMS; j++)
+   for (j = (CNP_ATOM_LISTING_ATOMS+1); j < CNP_N_ATOMS; j++)
      {
         cnp_debug("\t%s %d\n", atoms[j].name, atoms[j].atom);
         if (!(atoms[j].formats & sel->requestformat)) continue;
@@ -665,11 +720,13 @@ notify_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notif
           {
              if ((atoms[j].atom == atomlist[i]) && (atoms[j].notify))
                {
+#if 0
                   if ((j == CNP_ATOM_text_uri) ||
                       (j == CNP_ATOM_text_urilist))
                     {
                       if(!is_uri_type_data(sel, notify)) continue;
                     }
+#endif
                   cnp_debug("Atom %s matches\n",atoms[j].name);
                   goto done;
                }
@@ -726,6 +783,71 @@ found:
    return 0;
 }
 
+static void
+entry_insert_filter(Evas_Object* entry, char* str)
+{
+   if (!entry || !str)
+     return;
+
+   char *insertStr = str;
+   // if entry has text only set then remove item tags
+   if (elm_entry_cnp_mode_get(entry) != ELM_CNP_MODE_MARKUP)
+     {
+        while (EINA_TRUE)
+          {
+             char *startTag = NULL;
+             char *endTag = NULL;
+
+             startTag = strstr(insertStr, "<item");
+             if (!startTag)
+               startTag = strstr(insertStr, "</item");
+             if (startTag)
+               endTag = strstr(startTag, ">");
+             else
+               break;
+             if (!endTag || startTag > endTag)
+               {
+                  cnp_debug("Broken tag: %s\n", str);
+                  break;
+               }
+
+             size_t sindex = startTag - insertStr;
+             size_t eindex = endTag - insertStr + 1;
+
+             Eina_Strbuf *buf = eina_strbuf_new();
+             if (buf)
+               {
+                  eina_strbuf_append(buf, insertStr);
+                  eina_strbuf_remove(buf, sindex, eindex);
+                  insertStr = eina_strbuf_string_steal(buf);
+                  eina_strbuf_free(buf);
+               }
+          }
+     }
+   cnp_debug("remove item tag: %s\n", insertStr);
+
+   // if entry has single line set then remove <br> & <ps> tags
+   if (elm_entry_single_line_get(entry))
+     {
+        Eina_Strbuf *buf = eina_strbuf_new();
+        if (buf)
+          {
+             eina_strbuf_append(buf, insertStr);
+             eina_strbuf_replace_all(buf, "<br>", "");
+             eina_strbuf_replace_all(buf, "<ps>", "");
+             insertStr = eina_strbuf_string_steal(buf);
+             eina_strbuf_free(buf);
+          }
+     }
+   cnp_debug("remove break tag: %s\n", insertStr);
+
+   elm_entry_entry_insert(entry, insertStr);
+   // TODO:
+   //_elm_entry_entry_paste//
+
+   if (insertStr != str)
+     free(insertStr);
+}
 
 static int
 notify_handler_text(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
@@ -738,19 +860,25 @@ notify_handler_text(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
    if (sel->datacb)
      {
         Elm_Selection_Data ddata;
+        char *str = NULL;
+        str = malloc(sizeof(char) * (data->length + 1));
+        strncpy(str, (char *)data->data, data->length);
+        str[data->length] = '\0';
 
         ddata.x = ddata.y = 0;
         ddata.format = ELM_SEL_FORMAT_TEXT;
-        ddata.data = data->data;
+        ddata.data = str;
         ddata.len = data->length;
         sel->datacb(sel->udata, sel->widget, &ddata);
+        free(str);
         return 0;
      }
 
    cnp_debug("Notify handler text %d %d %p\n", data->format,data->length, data->data);
    str = mark_up((char *)data->data, data->length, NULL);
    cnp_debug("String is %s (from %s)\n", str, data->data);
-   elm_entry_entry_insert(sel->requestwidget, str);
+   entry_insert_filter(sel->requestwidget, str);
+   //elm_entry_entry_insert(sel->requestwidget, str);
    free(str);
    return 0;
 }
@@ -764,7 +892,8 @@ notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
 {
    Ecore_X_Selection_Data *data;
    Ecore_X_Selection_Data_Files *files;
-   char *p;
+   Paste_Image *pi;
+   char *p, *stripstr;
 
    data = notify->data;
    cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
@@ -778,11 +907,13 @@ notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
              cnp_debug("more then one file: Bailing\n");
              return 0;
           }
-        p = files->files[0];
+        stripstr = p = strdup(files->files[0]);
      }
    else
      {
-        p = (char *)data->data;
+        stripstr = p = malloc(data->length * sizeof(char) + 1);
+        memcpy(stripstr, data->data, data->length);
+        stripstr[data->length] = 0;
      }
 
    if (!p)
@@ -791,26 +922,45 @@ notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
         return 0;
      }
    cnp_debug("Got %s\n",p);
+   if (sel->datacb)
+     {
+        Elm_Selection_Data ddata;
+
+        ddata.x = ddata.y = 0;
+        ddata.format = ELM_SEL_FORMAT_IMAGE;
+        ddata.data = p;
+        ddata.len = data->length;
+        sel->datacb(sel->udata, sel->widget, &ddata);
+        free(p);
+        return 0;
+     }
    if (strncmp(p, "file://", 7))
      {
         /* Try and continue if it looks sane */
-        if (*p != '/') return 0;
+        if (*p != '/')
+          {
+             free(p);
+             return 0;
+          }
      }
    else
      {
         p += strlen("file://");
      }
 
-   if (savedtypes.imgfile) free((void*)savedtypes.imgfile);
+   if (savedtypes.pi) pasteimage_free(savedtypes.pi);
+   pi = pasteimage_alloc(p, strlen(p));
    if (savedtypes.textreq)
      {
         savedtypes.textreq = 0;
-        savedtypes.imgfile = strdup(p);
+        savedtypes.pi = pi;
      }
    else
      {
-        pasteimage_append(p, sel->requestwidget);
+        pasteimage_append(pi, sel->requestwidget);
+        savedtypes.pi = NULL;
      }
+   free(stripstr);
    return 0;
 }
 
@@ -870,12 +1020,12 @@ vcard_receive(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
 
 }
 
-
 static int
 notify_handler_image(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
 {
    Ecore_X_Selection_Data *data;
    Tmp_Info *tmp;
+   Paste_Image *pi;
 
    cnp_debug("got a png (or a jpeg)!\n");
    data = notify->data;
@@ -900,12 +1050,42 @@ notify_handler_image(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
    munmap(tmp->map,data->length);
 
    /* FIXME: Add to paste image data to clean up */
-   pasteimage_append(tmp->filename, sel->requestwidget);
+   pi = pasteimage_alloc(tmp->filename, strlen(tmp->filename));
+   pasteimage_append(pi, sel->requestwidget);
 
    tmpinfo_free(tmp);
    return 0;
 }
 
+static int
+notify_handler_edje(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
+{
+   Ecore_X_Selection_Data *data;
+
+   data = notify->data;
+
+   char *stripstr = NULL;
+   stripstr = malloc(sizeof(char) * (data->length + 1));
+   strncpy(stripstr, (char *)data->data, data->length);
+   stripstr[data->length] = '\0';
+
+   if (sel->datacb)
+     {
+        Elm_Selection_Data ddata;
+        ddata.x = ddata.y = 0;
+        ddata.format = ELM_SEL_FORMAT_MARKUP;
+        ddata.data = stripstr;
+        ddata.len = data->length;
+        sel->datacb(sel->udata, sel->widget, &ddata);
+     }
+   else
+     entry_insert_filter(sel->requestwidget, stripstr);
+     //elm_entry_entry_insert(sel->requestwidget, stripstr);
+
+   cnp_debug("String is %s (%d bytes)\n", stripstr, data->length);
+   free(stripstr);
+   return 0;
+}
 
 /**
  *    Warning: Generic text/html can';t handle it sanely.
@@ -920,41 +1100,69 @@ notify_handler_html(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
    cnp_debug("Got some HTML: Checking encoding is useful\n");
    data = notify->data;
 
+   char *stripstr = NULL;
+   stripstr = malloc(sizeof(char) * (data->length + 1));
+   strncpy(stripstr, (char *)data->data, data->length);
+   stripstr[data->length] = '\0';
+
    if (sel->datacb)
      {
         Elm_Selection_Data ddata;
         ddata.x = ddata.y = 0;
         ddata.format = ELM_SEL_FORMAT_HTML;
-        ddata.data = data->data;
+        ddata.data = stripstr;
         ddata.len = data->length;
         sel->datacb(sel->udata, sel->widget, &ddata);
-        return 0;
      }
+   else
+     entry_insert_filter(sel->requestwidget, stripstr);
+     //elm_entry_entry_insert(sel->requestwidget, stripstr);
 
-   char *stripstr = NULL;
-   stripstr = malloc(sizeof(char) * (data->length + 1));
-   strncpy(stripstr, (char *)data->data, data->length);
-   stripstr[data->length] = '\0';
    cnp_debug("String is %s (%d bytes)\n", stripstr, data->length);
-   elm_entry_entry_insert(sel->requestwidget, stripstr);
    free(stripstr);
    return 0;
 }
 
 
 static Eina_Bool
-text_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
+text_converter(char *target __UNUSED__, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
 {
    Cnp_Selection *sel;
 
    cnp_debug("text converter\n");
+   if (size != sizeof(int))
+     {
+        if (data_ret)
+          {
+             *data_ret = malloc(size * sizeof(char) + 1);
+             memcpy(*data_ret, data, size);
+             ((char**)(data_ret))[0][size] = 0;
+          }
+        if (size_ret) *size_ret = size;
+        return EINA_TRUE;
+     }
+   if (!data || (*((unsigned int *)data) >= ELM_SEL_MAX))
+     return EINA_FALSE;
    sel = selections + *((int *)data);
    if (!sel->active) return EINA_TRUE;
 
-   if ((sel->format & ELM_SEL_FORMAT_MARKUP) ||
-       (sel->format & ELM_SEL_FORMAT_HTML))
+   if (sel->format & ELM_SEL_FORMAT_MARKUP)
+     *data_ret = remove_tags(sel->selbuf, size_ret);
+   else if (sel->format & ELM_SEL_FORMAT_HTML)
      {
-        *data_ret = remove_tags(sel->selbuf, size_ret);
+        char *text = NULL;
+        Eina_Strbuf *buf = eina_strbuf_new();
+        if (buf)
+          {
+             eina_strbuf_append(buf, sel->selbuf);
+             eina_strbuf_replace_all(buf, "&nbsp;", " ");
+             text = eina_strbuf_string_steal(buf);
+             eina_strbuf_free(buf);
+             *data_ret = remove_tags(text, size_ret);
+             free(text);
+          }
+        else
+          *data_ret = remove_tags(sel->selbuf, size_ret);
      }
    else if (sel->format & ELM_SEL_FORMAT_TEXT)
      {
@@ -974,60 +1182,166 @@ text_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **
 }
 
 static Eina_Bool
-edje_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
+general_converter(char *target __UNUSED__, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
 {
-   Cnp_Selection *sel;
-
-   sel = selections + *((int *)data);
-   if (data_ret) *data_ret = strdup(sel->selbuf);
-   if (size_ret) *size_ret = strlen(sel->selbuf);
+   if (size == sizeof(int))
+     {
+        Cnp_Selection *sel;
+        if (!data || (*((unsigned int *)data) >= ELM_SEL_MAX))
+          return EINA_FALSE;
 
+        sel = selections + *((int *)data);
+        if (data_ret) *data_ret = strdup(sel->selbuf);
+        if (size_ret) *size_ret = strlen(sel->selbuf);
+     }
+   else if (size)
+     {
+        if (data_ret)
+          {
+             *data_ret = malloc(size * sizeof(char) + 1);
+             memcpy(*data_ret, data, size);
+             ((char**)(data_ret))[0][size] = 0;
+          }
+        if (size_ret) *size_ret = size;
+     }
    return EINA_TRUE;
 }
 
+/*
+ * Image paste provide
+ */
+
+/* FIXME: Should add provider for each pasted item: Use data to store it
+ * much easier */
+static Evas_Object *
+image_provider(void *images __UNUSED__, Evas_Object *entry, const char *item)
+{
+   Paste_Image *pi;
+   Eina_List *l;
+
+   cnp_debug("image provider for %s called\n", item);
+   EINA_LIST_FOREACH(pastedimages, l, pi)
+     {
+        cnp_debug("is it %s?\n",pi->tag);
+        if (!strcmp(pi->tag, item))
+          {
+             /* Found it */
+             Evas_Object *o;
+             o = evas_object_image_filled_add(evas_object_evas_get(entry));
+             /* FIXME: Handle eets */
+             cnp_debug("file is %s (object is %p)\n", pi->file, o);
+             evas_object_image_file_set(o, pi->file, NULL);
+             evas_object_show(o);
+             return o;
+          }
+     }
+   return NULL;
+}
+
 
-static Eina_Bool
-html_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
+static Paste_Image *
+pasteimage_alloc(const char *file, int pathlen)
 {
-   Cnp_Selection *sel;
+   Paste_Image *pi;
+   int len;
+   char *buf, *filebuf;
+   int prefixlen = strlen("file://");
 
-   sel = selections + *(int *)data;
-   if (data_ret) *data_ret = strdup(sel->selbuf);
-   if (size_ret) *size_ret = strlen(sel->selbuf);
+   pi = calloc(1, sizeof(Paste_Image));
+   if (!pi) return NULL;
 
-   return EINA_TRUE;
+   len = snprintf(NULL, 0, "pasteimage-%p", pi);
+   len++;
+   buf = malloc(len);
+   if (!buf)
+     {
+        free(pi);
+        return NULL;
+     }
+   snprintf(buf, len, "pasteimage-%p", pi);
+   pi->tag = buf;
+
+   if (file)
+     {
+        if (strstr(file,"file://")) file += prefixlen;
+        filebuf = alloca(pathlen + 1);
+        strncpy(filebuf, file, pathlen);
+        filebuf[pathlen] = 0;
+        pi->file = strdup(filebuf);
+     }
+
+   return pi;
+}
+
+static void
+pasteimage_free(Paste_Image *pi)
+{
+   if (!pi) return;
+   if (pi->file) free((void*)pi->file);
+   if (pi->tag) free((void*)pi->tag);
+   free(pi);
 }
 
 static Eina_Bool
-uri_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
+pasteimage_provider_set(Evas_Object *entry)
 {
-   Cnp_Selection *sel;
-   sel = selections + *((int *)data);
-   cnp_debug("Uri converter\n");
-   if (data_ret) *data_ret = strdup(sel->selbuf);
-   if (size_ret) *size_ret = strlen(sel->selbuf);
+   void *v;
+   const char *type;
+
+   if (!entry) return EINA_FALSE;
+   type = elm_widget_type_get(entry);
+   cnp_debug("type is %s\n", type);
+   if ((!type) || (strcmp(type, "entry"))) return EINA_FALSE;
+
+   v = evas_object_data_get(entry, PROVIDER_SET);
+   if (!v)
+     {
+        evas_object_data_set(entry, PROVIDER_SET, pasteimage_provider_set);
+        elm_entry_item_provider_append(entry, image_provider, NULL);
+        evas_object_event_callback_add(entry, EVAS_CALLBACK_FREE,
+                                       entry_deleted, NULL);
+     }
    return EINA_TRUE;
 }
 
+
 static Eina_Bool
-pasteimage_append(char *file, Evas_Object *entry)
+pasteimage_append(Paste_Image *pi, Evas_Object *entry)
 {
    char *entrytag;
    int len;
    static const char *tagstring = "<item absize=240x180 href=file://%s></item>";
 
-   if (!file) return EINA_FALSE;
+   if (!pi) return EINA_FALSE;
    if (!entry) return EINA_FALSE;
+   if (elm_entry_cnp_mode_get(entry) != ELM_CNP_MODE_MARKUP) return EINA_FALSE;
 
-   len = strlen(tagstring)+strlen(file);
+   pasteimage_provider_set(entry);
 
+   len = strlen(tagstring)+strlen(pi->file);
+
+   pastedimages = eina_list_append(pastedimages, pi);
    entrytag = alloca(len + 1);
-   snprintf(entrytag, len + 1, tagstring, file);
+   snprintf(entrytag, len + 1, tagstring, pi->file);
    elm_entry_entry_insert(entry, entrytag);
 
    return EINA_TRUE;
 }
 
+static void
+entry_deleted(void *images __UNUSED__, Evas *e __UNUSED__, Evas_Object *entry, void *unused __UNUSED__)
+{
+   Paste_Image *pi;
+   Eina_List *l,*next;
+
+   EINA_LIST_FOREACH_SAFE(pastedimages, l, next, pi)
+     {
+        if (pi->entry == entry)
+          pastedimages = eina_list_remove_list(pastedimages, l);
+     }
+}
+
+
 static char *
 remove_tags(const char *p, int *len)
 {
@@ -1041,29 +1355,63 @@ remove_tags(const char *p, int *len)
 
    while (*p)
      {
-        if ((*p != '<') && (*p != '&')) *q++ = *p++;
-        else if (*p == '<')
-          {
-             if ((p[1] == 'b') && (p[2] == 'r') &&
-                 ((p[3] == ' ') || (p[3] == '/') || (p[3] == '>')))
-               *q++ = '\n';
-             while ((*p) && (*p != '>')) p++;
-             p++;
-          }
-        else if (*p == '&')
+        Eina_Bool esc = EINA_TRUE;
+        const char *x;
+        switch (p[0])
           {
-             p++;
-             for (i = 0 ; i < N_ESCAPES ; i++)
+           case '<':
+             x = strchr(p + 3, '>');
+             if (!x)
                {
-                  if (!strncmp(p,escapes[i].escape, strlen(escapes[i].escape)))
+                  strcpy(q, p);
+                  if (len) *len = strlen(ret);
+                  return ret;
+               }
+             if (memcmp(p + 1, "br", 2) && memcmp(p + 1, "ps", 2))
+               {
+                  strncpy(q, p, x - p + 1);
+                  p = x + 1;
+                  break;
+               }
+             i = x - p - 1;
+             if (p[i] == '/') i--;
+             for (; i > 2; i++)
+               {
+                  if (p[i] != ' ')
                     {
-                       p += strlen(escapes[i].escape);
-                       *q = escapes[i].value;
-                       q++;
+                       esc = EINA_FALSE;
                        break;
                     }
                }
+             if (!esc)
+               {
+                  strncpy(q, p, x - p + 1);
+                  p = x + 1;
+                  break;
+               }
+             if (p[1] == 'b')
+               *q++ = '\n';
+             else
+               {
+                  strcpy(q, _PARAGRAPH_SEPARATOR);
+                  q += sizeof(_PARAGRAPH_SEPARATOR) - 1;
+               }
+             p = x + 1;
+             break;
+           case '&':
+             for (i = 3 ; i < N_ESCAPES ; i++)
+               {
+                  if (strncmp(p, escapes[i].escape, strlen(escapes[i].escape)))
+                    continue;
+                  p += strlen(escapes[i].escape);
+                  strcpy(q, escapes[i].value);
+                  q += strlen(escapes[i].value);
+                  break;
+               }
              if (i == N_ESCAPES) *q ++= '&';
+             break;
+           default:
+             *q++ = *p++;
           }
      }
    *q = 0;
@@ -1087,9 +1435,10 @@ mark_up(const char *start, int inlen, int *lenp)
      {
         for (i = 0 ; i < N_ESCAPES ; i ++)
           {
-             if (*p == escapes[i].value)
+             if (*p == escapes[i].value[0])
                {
-                  l += strlen(escapes[i].escape);
+                  if (!strncmp(p, escapes[i].value, strlen(escapes[i].value)))
+                    l += strlen(escapes[i].escape);
                   break;
                }
           }
@@ -1103,11 +1452,14 @@ mark_up(const char *start, int inlen, int *lenp)
      {
         for (i = 0; i < N_ESCAPES; i++)
           {
-             if (*p == escapes[i].value)
+             if (*p == escapes[i].value[0])
                {
-                  strcpy(q, escapes[i].escape);
-                  q += strlen(escapes[i].escape);
-                  p ++;
+                  if (!strncmp(p, escapes[i].value, strlen(escapes[i].value)))
+                    {
+                       strcpy(q, escapes[i].escape);
+                       q += strlen(escapes[i].escape);
+                       p += strlen(escapes[i].value);
+                    }
                   break;
                }
           }
@@ -1145,8 +1497,8 @@ _dnd_enter(void *data __UNUSED__, int etype __UNUSED__, void *ev)
              /* Request it, so we know what it is */
              cnp_debug("Sending uri request\n");
              savedtypes.textreq = 1;
-             if (savedtypes.imgfile) free((void*)savedtypes.imgfile);
-             savedtypes.imgfile = NULL;
+             if (savedtypes.pi) pasteimage_free(savedtypes.pi);
+             savedtypes.pi = NULL; /* FIXME: Free? */
              ecore_x_selection_xdnd_request(enter->win, text_uri);
           }
      }
@@ -1228,9 +1580,9 @@ found:
    if (i == CNP_ATOM_text_urilist)
      {
         cnp_debug("We found a URI... (%scached) %s\n",
-                  savedtypes.imgfile ? "" : "not ",
-                  savedtypes.imgfile);
-        if (savedtypes.imgfile)
+                  savedtypes.pi ? "" : "not ",
+                  savedtypes.pi->file);
+        if (savedtypes.pi)
           {
              char *entrytag;
              static const char *tagstring = "<item absize=240x180 href="
@@ -1244,34 +1596,38 @@ found:
                {
                   int len;
                   ddata.format = ELM_SEL_FORMAT_MARKUP;
+                  pasteimage_provider_set(dropable->obj);
 
-                  len = strlen(tagstring) + strlen(savedtypes.imgfile);
+                  pastedimages = eina_list_append(pastedimages, savedtypes.pi);
+                  len = strlen(tagstring) + strlen(savedtypes.pi->file);
                   entrytag = alloca(len + 1);
-                  snprintf(entrytag, len + 1, tagstring, savedtypes.imgfile);
+                  snprintf(entrytag, len + 1, tagstring, savedtypes.pi->file);
                   ddata.data = entrytag;
                   cnp_debug("Insert %s\n", (char *)ddata.data);
                   dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
                   ecore_x_dnd_send_finished();
-                  if (savedtypes.imgfile) free((void*)savedtypes.imgfile);
-                  savedtypes.imgfile = NULL;
-                   
+
+                  if (savedtypes.pi) pasteimage_free(savedtypes.pi);
+                  savedtypes.pi = NULL;
                   return EINA_TRUE;
                }
              else if (dropable->types & ELM_SEL_FORMAT_IMAGE)
                {
-                  cnp_debug("Doing image insert (%s)\n", savedtypes.imgfile);
+                  cnp_debug("Doing image insert (%s)\n", savedtypes.pi->file);
                   ddata.format = ELM_SEL_FORMAT_IMAGE;
-                  ddata.data = (char *)savedtypes.imgfile;
+                  ddata.data = (char *)savedtypes.pi->file;
                   dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
                   ecore_x_dnd_send_finished();
-                  if (savedtypes.imgfile) free((void*)savedtypes.imgfile);
-                  savedtypes.imgfile = NULL;
+
+                  if (savedtypes.pi) pasteimage_free(savedtypes.pi);
+                  savedtypes.pi = NULL;
 
                   return EINA_TRUE;
                }
              else
                {
                   cnp_debug("Item doesn't support images... passing\n");
+                  pasteimage_free(savedtypes.pi);
                   return EINA_TRUE;
                }
           }
@@ -1348,8 +1704,11 @@ elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, v
    Ecore_X_Window xwin;
    Eina_List *item;
    int first;
+   Evas_Object *top;
 
    if (!obj) return EINA_FALSE;
+   top = elm_widget_top_get(obj);
+   if (!top || !elm_win_xwindow_get(top)) return EINA_FALSE;
    if (!_elm_cnp_init_count) _elm_cnp_init();
 
    /* Is this the first? */
@@ -1442,8 +1801,11 @@ elm_drop_target_del(Evas_Object *obj)
    ecore_event_handler_del(handler_drop);
    ecore_event_handler_del(handler_enter);
 
-   if (savedtypes.imgfile) free((void*)savedtypes.imgfile);
-   savedtypes.imgfile = NULL;
+   if (savedtypes.pi)
+     {
+        pasteimage_free(savedtypes.pi);
+        savedtypes.pi = NULL;
+     }
 
    return EINA_TRUE;
 }
@@ -1551,7 +1913,6 @@ elm_cnp_tempfile_create(int size)
 
    tmppath = getenv("TMP");
    if (!tmppath) tmppath = P_tmpdir;
-   if (!tmppath) tmppath = "/tmp";
    len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-");
    if (len < 0)
      {
@@ -1608,6 +1969,8 @@ elm_cnp_tempfile_create(int size)
         return info;
      }
 
+   eina_mmap_safety_enabled_set(EINA_TRUE);
+
    info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0);
    if (info->map == MAP_FAILED)
      {