Improvements to cut and paste.
authorBrett Nash <nash@nash.id.au>
Wed, 30 Jun 2010 13:20:58 +0000 (13:20 +0000)
committerBrett Nash <nash@nash.id.au>
Wed, 30 Jun 2010 13:20:58 +0000 (13:20 +0000)
SVN revision: 49947

src/lib/elm_cnp_helper.c
src/lib/elm_icon.c

index 0a5dabe423b834b491ebfae26db1f390c73909c7..d59836c5ff930f646287c417bcfe16afa127dd88 100644 (file)
 
 # define ARRAYINIT(foo)  [foo]=
 
+#define DEBUGON        1
+
+#if DEBUGON
+#define cnp_debug(x...) printf(__FILE__": " x)
+#else
+#define cnp_debug(x...)
+#endif
+
 
 enum {
-  CNP_ATOM_TARGETS = 0,
-  CNP_ATOM_XEDJE,
-  CNP_ATOM_text_html_utf8,
-  CNP_ATOM_text_html,
-  CNP_ATOM_UTF8STRING,
-  CNP_ATOM_STRING,
-  CNP_ATOM_TEXT,
-  CNP_ATOM_text_plain_utf8,
-  CNP_ATOM_text_plain,
-
-  CNP_N_ATOMS,
+     CNP_ATOM_TARGETS = 0,
+     CNP_ATOM_text_uri,
+     CNP_ATOM_image_png,
+     CNP_ATOM_XELM,
+     CNP_ATOM_text_html_utf8,
+     CNP_ATOM_text_html,
+     CNP_ATOM_UTF8STRING,
+     CNP_ATOM_STRING,
+     CNP_ATOM_TEXT,
+     CNP_ATOM_text_plain_utf8,
+     CNP_ATOM_text_plain,
+
+     CNP_N_ATOMS,
+};
+struct pasteimage {
+     Evas_Object *entry;
+     const char *tag;
+     const char *file;
+     Evas_Object *img;
 };
 
 
@@ -68,10 +84,13 @@ static const struct escapes {
 
 static Eina_Bool _elm_cnp_init(void);
 static Eina_Bool selection_clear(void *udata __UNUSED__, int type, void *event);
+//static Eina_Bool selection_request(void *udata __UNUSED__, int type, void *event);
 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 *lenp);
 
+static Evas_Object *image_provider(void *images, Evas_Object *entry, const char *item);
+
 
 typedef int (*converter_fn)(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
 
@@ -79,41 +98,125 @@ static int targets_converter(char *target, void *data, int size, void **data_ret
 static int text_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
 static int html_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
 static int edje_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
+static int uri_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
+static int png_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
 
+/* FIXME: Which way should this be: Notify or response */
 typedef int (*response_handler)(struct _elm_cnp_selection *sel,
       Ecore_X_Event_Selection_Notify *);
 static int response_handler_targets(struct _elm_cnp_selection *sel,
       Ecore_X_Event_Selection_Notify *);
-static int response_handler_text(struct _elm_cnp_selection *sel,
+
+typedef int (*notify_handler)(struct _elm_cnp_selection *sel,
       Ecore_X_Event_Selection_Notify *);
+static int notify_handler_targets(struct _elm_cnp_selection *sel,
+      Ecore_X_Event_Selection_Notify *notify);
+static int notify_handler_text(struct _elm_cnp_selection *sel,
+      Ecore_X_Event_Selection_Notify *notify);
+static int notify_handler_png(struct _elm_cnp_selection *sel,
+      Ecore_X_Event_Selection_Notify *notify);
+static int notify_handler_uri(struct _elm_cnp_selection *sel,
+      Ecore_X_Event_Selection_Notify *notify);
+
 
 static struct {
    const char *name;
    enum _elm_sel_format formats;
+   /* Called by ecore to do conversion */
    converter_fn converter;
    response_handler response;
+   notify_handler notify;
+   /* Atom */
    Ecore_X_Atom atom;
 } atoms[CNP_N_ATOMS] = {
-   ARRAYINIT(CNP_ATOM_TARGETS) { "TARGETS",
-               (enum _elm_sel_format)-1, targets_converter,
-               response_handler_targets, 0 },
-   ARRAYINIT(CNP_ATOM_XEDJE)  { "application/x-edje-string",
-                       ELM_SEL_MARKUP, edje_converter, NULL, 0},
-   ARRAYINIT(CNP_ATOM_text_html_utf8) { "text/html;charset=utf-8",
-                       ELM_SEL_MARKUP, html_converter, NULL, 0 },
-   ARRAYINIT(CNP_ATOM_text_html) { "text/html", ELM_SEL_MARKUP,
-                       html_converter, NULL, 0 },
-   ARRAYINIT(CNP_ATOM_UTF8STRING) { "UTF8_STRING", ELM_SEL_MARKUP,
-                       text_converter, response_handler_text, 0 },
-   ARRAYINIT(CNP_ATOM_STRING) { "STRING", ELM_SEL_MARKUP,
-                       text_converter, response_handler_text, 0 },
-   ARRAYINIT(CNP_ATOM_TEXT) { "TEXT", ELM_SEL_MARKUP,
-                       text_converter, response_handler_text, 0 },
-   ARRAYINIT(CNP_ATOM_text_plain_utf8) { "text/plain;charset=ut-8",
-                       ELM_SEL_MARKUP, text_converter,
-                       response_handler_text, 0 },
-   ARRAYINIT(CNP_ATOM_text_plain) { "text/plain", ELM_SEL_MARKUP,
-                       text_converter, response_handler_text, 0 },
+   [CNP_ATOM_TARGETS] = {
+       "TARGETS",
+       (enum _elm_sel_format)-1,
+       targets_converter,
+       response_handler_targets,
+       notify_handler_targets,
+       0
+   },
+   [CNP_ATOM_XELM] =  {
+       "application/x-elementary-markup",
+       ELM_SEL_MARKUP,
+       edje_converter,
+       NULL,
+       NULL,
+       0
+   },
+   [CNP_ATOM_text_uri] = {
+       "text/uri",
+       ELM_SEL_MARKUP | ELM_SEL_IMAGE, /* Either images or entries */
+       uri_converter,
+       NULL,
+       notify_handler_uri,
+       0
+   },
+   [CNP_ATOM_image_png] = {
+       "image/png",
+       ELM_SEL_IMAGE | ELM_SEL_IMAGE,
+       png_converter,
+       NULL,
+       notify_handler_png,
+       0
+   },
+   [CNP_ATOM_text_html_utf8] = {
+       "text/html;charset=utf-8",
+       ELM_SEL_MARKUP,
+       html_converter,
+       NULL,
+       NULL,
+       0
+   },
+   [CNP_ATOM_text_html] = {
+       "text/html",
+       ELM_SEL_MARKUP,
+       html_converter,
+       NULL,
+       NULL,
+       0
+   },
+   [CNP_ATOM_UTF8STRING] = {
+       "UTF8_STRING",
+       ELM_SEL_MARKUP,
+       text_converter,
+       NULL,
+       notify_handler_text,
+       0
+   },
+   [CNP_ATOM_STRING] = {
+       "STRING",
+       ELM_SEL_MARKUP | ELM_SEL_IMAGE,
+       text_converter,
+       NULL,
+       notify_handler_text,
+       0
+   },
+   [CNP_ATOM_TEXT] = {
+       "TEXT",
+       ELM_SEL_MARKUP | ELM_SEL_IMAGE,
+       text_converter,
+       NULL,
+       NULL,
+       0
+   },
+   [CNP_ATOM_text_plain_utf8] = {
+       "text/plain;charset=ut-8",
+       ELM_SEL_MARKUP,
+       text_converter,
+       NULL,
+       NULL,
+       0
+   },
+   [CNP_ATOM_text_plain] = {
+       "text/plain",
+       ELM_SEL_MARKUP,
+       text_converter,
+       NULL,
+       NULL,
+       0
+   },
 };
 
 static struct _elm_cnp_selection selections[ELM_SEL_MAX] = {
@@ -141,7 +244,10 @@ static struct _elm_cnp_selection selections[ELM_SEL_MAX] = {
 };
 
 static int _elm_cnp_init_count = 0;
+  /* Gah... who left this out of XAtoms.h */
+static Ecore_X_Atom clipboard_atom;
 
+Eina_List *pastedimages;
 #endif
 
 
@@ -154,16 +260,18 @@ elm_selection_set(enum _elm_sel_type selection, Evas_Object *widget,
 
    if ((unsigned int)selection >= (unsigned int)ELM_SEL_MAX) return EINA_FALSE;
    if (!_elm_cnp_init_count) _elm_cnp_init();
-   if (!selbuf) return elm_selection_clear(selection, widget);
+   if (!selbuf && format != ELM_SEL_IMAGE)
+     return elm_selection_clear(selection, widget);
 
    sel = selections + selection;
 
    sel->active = 1;
    sel->widget = widget;
-   sel->set(elm_win_xwindow_get(elm_widget_top_get(widget)),
-        &selection, sizeof(int));
+
+   sel->set(elm_win_xwindow_get(widget),&selection,sizeof(enum _elm_sel_type));
    sel->format = format;
-   sel->selbuf = strdup(selbuf);
+   sel->selbuf = selbuf ? strdup(selbuf) : NULL;
+
    return EINA_TRUE;
 #else
    return EINA_FALSE;
@@ -233,10 +341,10 @@ _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);
-
     return EINA_TRUE;
 }
 
@@ -261,8 +369,51 @@ selection_clear(void *udata __UNUSED__, int type, void *event){
    return ECORE_CALLBACK_PASS_ON;
 }
 
+#if 0
 /**
- * Response to a selection notify
+ * Response to a selection request
+ */
+static Eina_Bool
+selection_request(void *udata __UNUSED__, int type, void *event){
+   Ecore_X_Event_Selection_Request *ev = event;
+   struct _elm_cnp_selection *sel;
+   int i;
+printf("selection request callback: %d\n",ev->selection);
+printf("selection request callback: %d\n",ev->target);
+
+   if (ev->selection == clipboard_atom){
+        sel = selections + ELM_SEL_CLIPBOARD;
+   } else if (ev->selection == XA_PRIMARY){
+        sel = selections + ELM_SEL_PRIMARY;
+   } else if (ev->selection ==  XA_SECONDARY){
+        sel = selections + ELM_SEL_SECONDARY;
+   } else {
+        return ECORE_CALLBACK_PASS_ON;
+   }
+   return ECORE_CALLBACK_PASS_ON;
+
+   for (i = 0 ; i < CNP_N_ATOMS ; i ++)
+     {
+       if (ev->target == atoms[i].atom)
+         {
+            if (atoms[i].response){
+                 atoms[i].response(sel, ev);
+            } else {
+                 printf("Ignored: No handler!\n");
+            }
+         }
+     }
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+#endif
+
+
+/*
+ * Response to a selection notify:
+ *     - So we have asked for the selection list.
+ *     - If it's the targets list, parse it, and fire of what we want,
+ *     else it's the data we want.
  */
 static Eina_Bool
 selection_notify(void *udata __UNUSED__, int type, void *event){
@@ -270,6 +421,7 @@ selection_notify(void *udata __UNUSED__, int type, void *event){
    struct _elm_cnp_selection *sel;
    int i;
 
+   cnp_debug("selection notify callback: %d\n",ev->selection);
    switch (ev->selection){
       case ECORE_X_SELECTION_CLIPBOARD:
         sel = selections + ELM_SEL_CLIPBOARD;
@@ -284,13 +436,15 @@ selection_notify(void *udata __UNUSED__, int type, void *event){
       default:
         return ECORE_CALLBACK_PASS_ON;
    }
+   cnp_debug("Target is %s\n",ev->target);
 
    for (i = 0 ; i < CNP_N_ATOMS ; i ++)
      {
        if (strcmp(ev->target, atoms[i].name) == 0)
          {
-            if (atoms[i].response){
-                 atoms[i].response(sel, ev);
+            if (atoms[i].notify){
+                 cnp_debug("Found something: %s\n", atoms[i].name);
+                 atoms[i].notify(sel, ev);
             } else {
                  printf("Ignored: No handler!\n");
             }
@@ -301,6 +455,7 @@ selection_notify(void *udata __UNUSED__, int type, void *event){
 }
 
 
+
 static int
 targets_converter(char *target, void *data, int size,
                void **data_ret, int *size_ret,
@@ -319,7 +474,7 @@ targets_converter(char *target, void *data, int size,
 
    aret = malloc(sizeof(Ecore_X_Atom) * count);
    for (i = 0, count = 0 ; i < CNP_N_ATOMS ; i ++)
-       if (sel->format && atoms[i].formats)
+       if (sel->format & atoms[i].formats)
          aret[count ++] = atoms[i].atom;
 
    if (data_ret) *data_ret = aret;
@@ -330,6 +485,51 @@ targets_converter(char *target, void *data, int size,
    return 1;
 }
 
+static int
+png_converter(char *target, void *data, int size,
+      void **data_ret, int *size_ret,
+      Ecore_X_Atom *ttype, int *typesize){
+
+     return 1;
+}
+
+/*
+ * Callback to handle a targets response on a selection request:
+ * So pick the format we'd like; and then request it.
+ */
+static int
+notify_handler_targets(struct _elm_cnp_selection *sel,
+      Ecore_X_Event_Selection_Notify *notify){
+   Ecore_X_Selection_Data_Targets *targets;
+   Ecore_X_Atom *atomlist;
+   int i,j;
+
+   targets = notify->data;
+   atomlist = (Ecore_X_Atom *)(targets->data.data);
+
+   for (j = 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;
+       for (i = 0 ; i < targets->data.length ; i ++)
+         {
+            if (atoms[j].atom == atomlist[i])
+              {
+                 cnp_debug("Atom %s matches\n",atoms[j].name);
+                 goto done;
+              }
+         }
+     }
+
+   cnp_debug("Couldn't find anything that matches\n");
+   return ECORE_CALLBACK_PASS_ON;
+
+   done:
+   cnp_debug("Sending request for %s\n",atoms[j].name);
+   sel->request(elm_win_xwindow_get(sel->requestwidget), atoms[j].name);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
 
 static int
 response_handler_targets(struct _elm_cnp_selection *sel,
@@ -360,7 +560,7 @@ response_handler_targets(struct _elm_cnp_selection *sel,
        found:
    if (j == CNP_N_ATOMS)
      {
-       printf("No matching type found\n");
+       cnp_debug("No matching type found\n");
        return 0;
      }
 
@@ -371,14 +571,15 @@ response_handler_targets(struct _elm_cnp_selection *sel,
    return 0;
 }
 
+
 static int
-response_handler_text(struct _elm_cnp_selection *sel,
+notify_handler_text(struct _elm_cnp_selection *sel,
       Ecore_X_Event_Selection_Notify *notify){
-   Ecore_X_Selection_Data_Text *text;
+   Ecore_X_Selection_Data *data;
    char *str;
 
-   text = notify->data;
-   str = mark_up(text->text, NULL);
+   data = notify->data;
+   str = mark_up((char*)data->data, NULL);
    elm_entry_entry_insert(sel->requestwidget, str);
    free(str);
 
@@ -386,6 +587,51 @@ response_handler_text(struct _elm_cnp_selection *sel,
 }
 
 
+/**
+ * So someone is pasting an image into my entry or widget...
+ */
+static int
+notify_handler_uri(struct _elm_cnp_selection *sel,
+        Ecore_X_Event_Selection_Notify *notify)
+{
+   Ecore_X_Selection_Data *data;
+   struct pasteimage *pi;
+   char entrytag[100];
+   char *p;
+
+   data = notify->data;
+   p = (char *)data->data;
+   cnp_debug("Got %s\n",p);
+   if (strncmp(p,"file://",7) != 0){
+       cnp_debug("Doesn't start with ;file;  %s\n",p);
+       return 0;
+   }
+
+   p += strlen("file://");
+
+   pi = calloc(1,sizeof(struct pasteimage));
+   snprintf(entrytag, sizeof(entrytag), "pasteimage-%p",pi);
+   pi->tag = strdup(entrytag);
+   pi->file = strndup(p,data->length - strlen("file://"));
+
+   elm_entry_item_provider_append(sel->requestwidget, image_provider, pi);
+   pastedimages = eina_list_append(pastedimages, pi);
+
+   snprintf(entrytag, sizeof(entrytag), "<item absize=240x180 href=%s>",pi->tag);
+   elm_entry_entry_insert(sel->requestwidget, entrytag);
+
+   return 0;
+}
+
+static int
+notify_handler_png(struct _elm_cnp_selection *sel,
+        Ecore_X_Event_Selection_Notify *notify)
+{
+   cnp_debug("got a png!\n");
+       return 0;
+}
+
+
 static int
 text_converter(char *target, void *data, int size,
                void **data_ret, int *size_ret,
@@ -397,7 +643,17 @@ text_converter(char *target, void *data, int size,
      {
        return 1;
      }
-   *data_ret = remove_tags(sel->selbuf, size_ret);
+
+   if (sel->format == ELM_SEL_MARKUP){
+       *data_ret = remove_tags(sel->selbuf, size_ret);
+   } else if (sel->format == ELM_SEL_IMAGE){
+       cnp_debug("Image %s\n",evas_object_type_get(sel->widget));
+       cnp_debug("Elm type: %s\n",elm_object_widget_type_get(sel->widget));
+       evas_object_image_file_get(elm_photocam_internal_image_get(sel->widget), (const char **)data_ret, NULL);
+       if (!*data_ret) *data_ret = strdup("No file");
+       else *data_ret = strdup(*data_ret);
+       *size_ret = strlen(*data_ret);
+   }
    return 1;
 }
 
@@ -425,6 +681,61 @@ html_converter(char *target, void *data, int size, void **data_ret, int *size_re
      return 1;
 }
 
+static int
+uri_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize){
+
+    struct _elm_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);
+    return 1;
+}
+
+
+/*
+ * Image paste provide
+ */
+
+/* FIXME: Should add provider for each pated item: Use data to store it
+ * much easier */
+static Evas_Object *
+image_provider(void *images, Evas_Object *entry, const char *item)
+{
+   struct pasteimage *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) == 0){
+            /* 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 void
+entry_deleted(void *images, Evas *e, Evas_Object *entry, void *unused)
+{
+   struct pasteimage *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 *
@@ -433,7 +744,7 @@ remove_tags(const char *p, int *len){
    int i;
    if (!p) return NULL;
 
-   q = malloc(strlen(p));
+   q = malloc(strlen(p) + 1);
    if (!q) return NULL;
    ret = q;
 
@@ -450,10 +761,11 @@ remove_tags(const char *p, int *len){
        } else if (*p == '&') {
             p ++;
             for (i = 0 ; i < N_ESCAPES ; i ++){
-                 if (strncmp(p,escapes[i].escape, strlen(escapes[i].escape))){
+                 if (!strncmp(p,escapes[i].escape, strlen(escapes[i].escape))){
                       p += strlen(escapes[i].escape);
                       *q = escapes[i].value;
                       q ++;
+                      break;
                  }
             }
             if (i == N_ESCAPES)
@@ -489,7 +801,7 @@ mark_up(const char *start, int *lenp){
 
   q = ret = malloc(l + 1);
 
-  /* Second pass: Count characters */
+  /* Second pass: Change characters */
   for (p = start ; *p ; )
     {
     for (i = 0 ; i < N_ESCAPES ; i ++)
index c4ae4b61bce5b50a37bc4543a5062abb38a4fe43..a34a872f766c6885cf963f3f62c6dc78b1099d59 100644 (file)
@@ -288,3 +288,5 @@ elm_icon_prescale_set(Evas_Object *obj, int size)
    if (!wd) return;
    _els_smart_icon_scale_size_set(wd->img, size);
 }
+
+