Elementary: DnD feature for genlist, gengrids and lists.
authorDaniel Zaoui <daniel.zaoui@samsung.com>
Wed, 8 May 2013 07:39:21 +0000 (10:39 +0300)
committerSungho Kwak <sungho1.kwak@samsung.com>
Wed, 12 Jun 2013 05:14:08 +0000 (14:14 +0900)
Three tests have been added in elementary_test to show the work done.
They are located in the new section "DnD".

Due to the new APIs in elm_cnp.c, some widgets had to be adapted.

14 files changed:
src/bin/Makefile.am
src/bin/test.c
src/bin/test_dnd.c [new file with mode: 0644]
src/lib/elm_cnp.c
src/lib/elm_cnp.h
src/lib/elm_entry.c
src/lib/elm_gengrid.c
src/lib/elm_gengrid.h
src/lib/elm_image.c
src/lib/elm_list.c
src/lib/elm_list.h
src/lib/elm_photo.c
src/lib/elm_thumb.c
src/lib/elm_widget.h

index 9b7cb16..20e01b1 100644 (file)
@@ -55,6 +55,7 @@ test_cursor.c \
 test_datetime.c \
 test_dayselector.c \
 test_diskselector.c \
+test_dnd.c \
 test_entry.c \
 test_entry_anchor.c \
 test_entry_anchor2.c \
index b83438d..078842b 100644 (file)
@@ -200,6 +200,9 @@ void test_eio(void *data, Evas_Object *obj, void *event_info);
 void test_web_normal(void *data, Evas_Object *obj, void *event_info);
 void test_web_mobile(void *data, Evas_Object *obj, void *event_info);
 #endif
+void test_dnd_genlist_default_anim(void *data, Evas_Object *obj, void *event_info);
+void test_dnd_genlist_user_anim(void *data, Evas_Object *obj, void *event_info);
+void test_dnd_genlist_gengrid(void *data, Evas_Object *obj, void *event_info);
 
 Evas_Object *win, *tbx; // TODO: refactoring
 void *tt;
@@ -705,10 +708,15 @@ add_tests:
 //   ADD_TEST(NULL, "Helpers", "Factory", test_factory);
 
    //------------------------------//
-   ADD_TEST(NULL, "Micellaneous", "Copy And Paste", test_cnp);
-   ADD_TEST(NULL, "Micellaneous", "Weather", test_weather);
-   ADD_TEST(NULL, "Micellaneous", "Icon Desktops", test_icon_desktops);
-   ADD_TEST(NULL, "Micellaneous", "Floating Objects", test_floating);
+   ADD_TEST(NULL, "Drag & Drop", "Genlist DnD Dflt Anim", test_dnd_genlist_default_anim);
+   ADD_TEST(NULL, "Drag & Drop", "Genlist DnD User Anim", test_dnd_genlist_user_anim);
+   ADD_TEST(NULL, "Drag & Drop", "Genlist-Gengrid DnD", test_dnd_genlist_gengrid);
+
+   //------------------------------//
+   ADD_TEST(NULL, "Miscellaneous", "Copy And Paste", test_cnp);
+   ADD_TEST(NULL, "Miscellaneous", "Weather", test_weather);
+   ADD_TEST(NULL, "Miscellaneous", "Icon Desktops", test_icon_desktops);
+   ADD_TEST(NULL, "Miscellaneous", "Floating Objects", test_floating);
 
 #undef ADD_TEST
 
diff --git a/src/bin/test_dnd.c b/src/bin/test_dnd.c
new file mode 100644 (file)
index 0000000..ca9468a
--- /dev/null
@@ -0,0 +1,893 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+#include <Elementary.h>
+
+static const char *img[9] =
+{
+   "panel_01.jpg",
+   "plant_01.jpg",
+   "rock_01.jpg",
+   "rock_02.jpg",
+   "sky_01.jpg",
+   "sky_02.jpg",
+   "sky_03.jpg",
+   "sky_04.jpg",
+   "wood_01.jpg",
+};
+
+struct _anim_icon_st
+{
+   int start_x;
+   int start_y;
+   Evas_Object *o;
+};
+typedef struct _anim_icon_st anim_icon_st;
+
+struct _drag_anim_st
+{
+   Evas_Object *icwin;
+   Evas *e;
+   Evas_Coord mdx;     /* Mouse-down x */
+   Evas_Coord mdy;     /* Mouse-down y */
+   Eina_List *icons;   /* List of icons to animate (anim_icon_st) */
+   Ecore_Timer *tm;
+   Ecore_Animator *ea;
+   Evas_Object *gl;
+};
+typedef struct _drag_anim_st drag_anim_st;
+
+#define DRAG_TIMEOUT 0.3
+#define ANIM_TIME 0.5
+
+static int
+_item_ptr_cmp(const void *d1, const void *d2)
+{
+   return (d1 - d2);
+}
+
+static Elm_Genlist_Item_Class *itc1;
+static Elm_Gengrid_Item_Class *gic;
+static char *
+gl_text_get(void *data, Evas_Object *obj __UNUSED__, const char *part __UNUSED__)
+{
+   return strdup(data);
+}
+
+static Evas_Object *
+gl_content_get(void *data, Evas_Object *obj, const char *part)
+{
+   if (!strcmp(part, "elm.swallow.icon"))
+     {
+        Evas_Object *icon = elm_icon_add(obj);
+        elm_image_file_set(icon, data, NULL);
+        evas_object_size_hint_aspect_set(icon, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
+        evas_object_show(icon);
+        return icon;
+     }
+   return NULL;
+}
+
+static void
+_win_del(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   printf("<%s> <%d> will del <%p>\n", __func__, __LINE__, data);
+   elm_drop_item_container_del(data);
+   elm_drag_item_container_del(data);
+
+   if (gic) elm_gengrid_item_class_free(gic);
+   gic = NULL;
+   if (itc1) elm_genlist_item_class_free(itc1);
+   itc1 = NULL;
+}
+
+static Elm_Object_Item *
+_gl_item_getcb(Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *xposret __UNUSED__, int *yposret)
+{  /* This function returns pointer to item under (x,y) coords */
+   printf("<%s> <%d> obj=<%p>\n", __func__, __LINE__, obj);
+   Elm_Object_Item *gli;
+   gli = elm_genlist_at_xy_item_get(obj, x, y, yposret);
+   if (gli)
+     printf("over <%s>, gli=<%p> yposret %i\n",
+           elm_object_item_part_text_get(gli, "elm.text"), gli, *yposret);
+   else
+     printf("over none, yposret %i\n", *yposret);
+   return gli;
+}
+
+static Elm_Object_Item *
+_grid_item_getcb(Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *xposret, int *yposret)
+{  /* This function returns pointer to item under (x,y) coords */
+   printf("<%s> <%d> obj=<%p>\n", __func__, __LINE__, obj);
+   Elm_Object_Item *item;
+   item = elm_gengrid_at_xy_item_get(obj, x, y, xposret, yposret);
+   if (item)
+     printf("over <%s>, item=<%p> xposret %i yposret %i\n",
+           elm_object_item_part_text_get(item, "elm.text"), item, *xposret, *yposret);
+   else
+     printf("over none, xposret %i yposret %i\n", *xposret, *yposret);
+   return item;
+}
+
+static Eina_Bool
+_gl_dropcb(void *data __UNUSED__, Evas_Object *obj, Elm_Object_Item *it, Elm_Selection_Data *ev, int xposret __UNUSED__, int yposret)
+{  /* This function is called when data is dropped on the genlist */
+   printf("<%s> <%d> str=<%s>\n", __func__, __LINE__, (char *) ev->data);
+   if (!ev->data)
+     return EINA_FALSE;
+
+   char *p = ev->data;
+   p = strchr(p, '#');
+   while(p)
+     {
+        p++;
+        char *p2 = strchr(p, '#');
+        if (p2)
+          {
+             *p2 = '\0';
+             printf("Item %s\n", p);
+             switch(yposret)
+               {
+                case -1:  /* Dropped on top-part of the it item */
+                     {
+                        elm_genlist_item_insert_before(obj,
+                              itc1, strdup(p), NULL, it,
+                              ELM_GENLIST_ITEM_NONE,
+                              NULL, NULL);
+                        break;
+                     }
+                case  0:  /* Dropped on center of the it item      */
+                case  1:  /* Dropped on botton-part of the it item */
+                     {
+                        if (!it) it = elm_genlist_last_item_get(obj);
+                        if (it) it = elm_genlist_item_insert_after(obj,
+                              itc1, strdup(p), NULL, it,
+                              ELM_GENLIST_ITEM_NONE,
+                              NULL, NULL);
+                        else
+                           it = elm_genlist_item_append(obj,
+                                 itc1, strdup(p), NULL,
+                                 ELM_GENLIST_ITEM_NONE,
+                                 NULL, NULL);
+                        break;
+                     }
+                default:
+                   return EINA_FALSE;
+               }
+             p = p2;
+          }
+        else p = NULL;
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_grid_dropcb(void *data __UNUSED__, Evas_Object *obj, Elm_Object_Item *it, Elm_Selection_Data *ev, int xposret __UNUSED__, int yposret EINA_UNUSED)
+{  /* This function is called when data is dropped on the genlist */
+   printf("<%s> <%d> str=<%s>\n", __func__, __LINE__, (char *) ev->data);
+   if (!ev->data)
+     return EINA_FALSE;
+
+   char *p = ev->data;
+   p = strchr(p, '#');
+   while(p)
+     {
+        p++;
+        char *p2 = strchr(p, '#');
+        if (p2)
+          {
+             *p2 = '\0';
+             printf("Item %s\n", p);
+             if (!it) it = elm_gengrid_last_item_get(obj);
+             if (it) it = elm_gengrid_item_insert_after(obj, gic, strdup(p), it, NULL, NULL);
+             else it = elm_gengrid_item_append(obj, gic, strdup(p), NULL, NULL);
+             p = p2;
+          }
+        else p = NULL;
+     }
+
+   return EINA_TRUE;
+}
+
+static void _gl_obj_mouse_move( void *data, Evas *e, Evas_Object *obj, void *event_info);
+static void _gl_obj_mouse_up( void *data, Evas *e, Evas_Object *obj, void *event_info);
+
+static void
+anim_st_free(drag_anim_st *anim_st)
+{  /* Stops and free mem of ongoing animation */
+   printf("<%s> <%d>\n", __func__, __LINE__);
+   if (anim_st)
+     {
+        evas_object_event_callback_del_full
+           (anim_st->gl, EVAS_CALLBACK_MOUSE_MOVE, _gl_obj_mouse_move, anim_st);
+        evas_object_event_callback_del_full
+           (anim_st->gl, EVAS_CALLBACK_MOUSE_UP, _gl_obj_mouse_up, anim_st);
+        if (anim_st->tm)
+          {
+             ecore_timer_del(anim_st->tm);
+             anim_st->tm = NULL;
+          }
+
+        if (anim_st->ea)
+          {
+             ecore_animator_del(anim_st->ea);
+             anim_st->ea = NULL;
+          }
+
+        anim_icon_st *st;
+
+        EINA_LIST_FREE(anim_st->icons, st)
+          {
+             evas_object_hide(st->o);
+             evas_object_del(st->o);
+             free(st);
+          }
+
+        free(anim_st);
+     }
+}
+
+static Eina_Bool
+_drag_anim_play(void *data, double pos)
+{  /* Impl of the animation of icons, called on frame time */
+   drag_anim_st *anim_st = data;
+   printf("<%s> <%d>\n", __func__, __LINE__);
+   Eina_List *l;
+   anim_icon_st *st;
+
+   if (anim_st)
+     {
+        if (pos > 0.99)
+          {
+             anim_st->ea = NULL;  /* Avoid deleting on mouse up */
+
+             EINA_LIST_FOREACH(anim_st->icons, l, st)
+                evas_object_hide(st->o);   /* Hide animated icons */
+             anim_st_free(anim_st);
+             return ECORE_CALLBACK_CANCEL;
+          }
+
+        EINA_LIST_FOREACH(anim_st->icons, l, st)
+          {
+             int x, y, w, h;
+             Evas_Coord xm, ym;
+             evas_object_geometry_get(st->o, NULL, NULL, &w, &h);
+             evas_pointer_canvas_xy_get(anim_st->e, &xm, &ym);
+             x = st->start_x + (pos * (xm - (st->start_x + (w/2))));
+             y = st->start_y + (pos * (ym - (st->start_y + (h/2))));
+             evas_object_move(st->o, x, y);
+          }
+
+        return ECORE_CALLBACK_RENEW;
+     }
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_gl_anim_start(void *data)
+{  /* Start icons animation before actually drag-starts */
+   drag_anim_st *anim_st = data;
+   printf("<%s> <%d>\n", __func__, __LINE__);
+   int yposret = 0;
+
+   Eina_List *l;
+   Eina_List *items = eina_list_clone(elm_genlist_selected_items_get(anim_st->gl));
+   Elm_Object_Item *gli = elm_genlist_at_xy_item_get(anim_st->gl,
+         anim_st->mdx, anim_st->mdy, &yposret);
+   if (gli)
+     {  /* Add the item mouse is over to the list if NOT seleced */
+        void *p = eina_list_search_unsorted(items, _item_ptr_cmp, gli);
+        if (!p)
+          items = eina_list_append(items, gli);
+     }
+
+   EINA_LIST_FOREACH(items, l, gli)
+     {  /* Now add icons to animation window */
+        Evas_Object *o = elm_object_item_part_content_get(gli,
+              "elm.swallow.icon");
+
+        if (o)
+          {
+             int w, h;
+             const char *f;
+             const char *g;
+             anim_icon_st *st = calloc(1, sizeof(*st));
+             elm_image_file_get(o, &f, &g);
+             Evas_Object *ic = elm_icon_add(anim_st->gl);
+             elm_image_file_set(ic, f, g);
+             evas_object_geometry_get(o, &st->start_x, &st->start_y, &w, &h);
+             evas_object_size_hint_align_set(ic,
+                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+             evas_object_size_hint_weight_set(ic,
+                   EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+
+             evas_object_move(ic, st->start_x, st->start_y);
+             evas_object_resize(ic, w, h);
+             evas_object_show(ic);
+
+             st->o = ic;
+             anim_st->icons = eina_list_append(anim_st->icons, st);
+          }
+     }
+
+   eina_list_free(items);
+
+   anim_st->tm = NULL;
+   anim_st->ea = ecore_animator_timeline_add(DRAG_TIMEOUT,
+         _drag_anim_play, anim_st);
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_gl_obj_mouse_up(
+   void *data,
+   Evas *e __UNUSED__,
+   Evas_Object *obj __UNUSED__,
+   void *event_info __UNUSED__)
+{  /* Cancel any drag waiting to start on timeout */
+   drag_anim_st *anim_st = data;
+   anim_st_free(anim_st);
+}
+
+static void
+_gl_obj_mouse_move(
+   void *data,
+   Evas *e __UNUSED__,
+   Evas_Object *obj __UNUSED__,
+   void *event_info)
+{  /* Cancel any drag waiting to start on timeout */
+
+   if (((Evas_Event_Mouse_Move *)event_info)->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
+     {
+        drag_anim_st *anim_st = data;
+        anim_st_free(anim_st);
+     }
+}
+
+static void
+_gl_obj_mouse_down(
+   void *data,
+   Evas *e __UNUSED__,
+   Evas_Object *obj __UNUSED__,
+   void *event_info)
+{  /* Launch a timer to start drag animation */
+   Evas_Event_Mouse_Down *ev = event_info;
+   drag_anim_st *anim_st = calloc(1, sizeof(*anim_st));
+   anim_st->e = e;
+   anim_st->mdx = ev->canvas.x;
+   anim_st->mdy = ev->canvas.y;
+   anim_st->gl = data;
+   anim_st->tm = ecore_timer_add(DRAG_TIMEOUT, _gl_anim_start, anim_st);
+   evas_object_event_callback_add(data, EVAS_CALLBACK_MOUSE_UP,
+         _gl_obj_mouse_up, anim_st);
+   evas_object_event_callback_add(data, EVAS_CALLBACK_MOUSE_MOVE,
+         _gl_obj_mouse_move, anim_st);
+}
+/* END   - Handling drag start animation */
+
+static void
+_gl_dragdone(void *data, Evas_Object *obj __UNUSED__, Eina_Bool doaccept)
+{
+   printf("<%s> <%d> data=<%p> doaccept=<%d>\n",
+         __func__, __LINE__, data, doaccept);
+
+   Elm_Object_Item *it;
+   Eina_List *l;
+
+   if (doaccept)
+     {  /* Remove items dragged out (accepted by target) */
+        EINA_LIST_FOREACH(data, l, it)
+           elm_object_item_del(it);
+     }
+
+   eina_list_free(data);
+   return;
+}
+
+static Evas_Object *
+_gl_createicon(void *data, Evas_Object *win, Evas_Coord *xoff, Evas_Coord *yoff)
+{
+   printf("<%s> <%d>\n", __func__, __LINE__);
+   Evas_Object *icon = NULL;
+   Evas_Object *o = elm_object_item_part_content_get(data, "elm.swallow.icon");
+
+   if (o)
+     {
+        int xm, ym, w = 30, h = 30;
+        const char *f;
+        const char *g;
+        elm_image_file_get(o, &f, &g);
+        evas_pointer_canvas_xy_get(evas_object_evas_get(o), &xm, &ym);
+        if (xoff) *xoff = xm - (w/2);
+        if (yoff) *yoff = ym - (h/2);
+        icon = elm_icon_add(win);
+        elm_image_file_set(icon, f, g);
+        evas_object_size_hint_align_set(icon,
+              EVAS_HINT_FILL, EVAS_HINT_FILL);
+        evas_object_size_hint_weight_set(icon,
+              EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        if (xoff && yoff) evas_object_move(icon, *xoff, *yoff);
+        evas_object_resize(icon, w, h);
+     }
+
+   return icon;
+}
+
+static Eina_List *
+_gl_icons_get(void *data)
+{  /* Start icons animation before actually drag-starts */
+   printf("<%s> <%d>\n", __func__, __LINE__);
+   int yposret = 0;
+
+   Eina_List *l;
+
+   Eina_List *icons = NULL;
+
+   Evas_Coord xm, ym;
+   evas_pointer_canvas_xy_get(evas_object_evas_get(data), &xm, &ym);
+   Eina_List *items = eina_list_clone(elm_genlist_selected_items_get(data));
+   Elm_Object_Item *gli = elm_genlist_at_xy_item_get(data,
+         xm, ym, &yposret);
+   if (gli)
+     {  /* Add the item mouse is over to the list if NOT seleced */
+        void *p = eina_list_search_unsorted(items, _item_ptr_cmp, gli);
+        if (!p)
+          items = eina_list_append(items, gli);
+     }
+
+   EINA_LIST_FOREACH(items, l, gli)
+     {  /* Now add icons to animation window */
+        Evas_Object *o = elm_object_item_part_content_get(gli,
+              "elm.swallow.icon");
+
+        if (o)
+          {
+             int x, y, w, h;
+             const char *f, *g;
+             elm_image_file_get(o, &f, &g);
+             Evas_Object *ic = elm_icon_add(data);
+             elm_image_file_set(ic, f, g);
+             evas_object_geometry_get(o, &x, &y, &w, &h);
+             evas_object_size_hint_align_set(ic,
+                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+             evas_object_size_hint_weight_set(ic,
+                   EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+
+             evas_object_move(ic, x, y);
+             evas_object_resize(ic, w, h);
+             evas_object_show(ic);
+
+             icons =  eina_list_append(icons, ic);
+          }
+     }
+
+   eina_list_free(items);
+   return icons;
+}
+
+static const char *
+_gl_get_drag_data(Evas_Object *obj, Elm_Object_Item *it, Eina_List **items)
+{  /* Construct a string of dragged info, user frees returned string */
+   const char *drag_data = NULL;
+   printf("<%s> <%d>\n", __func__, __LINE__);
+
+   *items = eina_list_clone(elm_genlist_selected_items_get(obj));
+   if (it)
+     {  /* Add the item mouse is over to the list if NOT seleced */
+        void *p = eina_list_search_unsorted(*items, _item_ptr_cmp, it);
+        if (!p)
+          *items = eina_list_append(*items, it);
+     }
+
+   if (*items)
+     {  /* Now we can actually compose string to send and start dragging */
+        Eina_List *l;
+        const char *t;
+        unsigned int len = 0;
+
+        EINA_LIST_FOREACH(*items, l, it)
+          {
+             t = elm_object_item_part_text_get(it, "elm.text");
+             if (t)
+               len += strlen(t);
+          }
+
+        drag_data = malloc(len + eina_list_count(*items) * 2 + 8);
+        strcpy((char *) drag_data, "file://");
+
+        EINA_LIST_FOREACH(*items, l, it)
+          {
+             t = elm_object_item_part_text_get(it, "elm.text");
+             if (t)
+               {
+                  strcat((char *) drag_data, "#");
+                  strcat((char *) drag_data, t);
+               }
+          }
+        strcat((char *) drag_data, "#");
+
+        printf("<%s> <%d> Sending <%s>\n", __func__, __LINE__, drag_data);
+     }
+
+   return drag_data;
+}
+
+static const char *
+_grid_get_drag_data(Evas_Object *obj, Elm_Object_Item *it, Eina_List **items)
+{  /* Construct a string of dragged info, user frees returned string */
+   const char *drag_data = NULL;
+   printf("<%s> <%d>\n", __func__, __LINE__);
+
+   *items = eina_list_clone(elm_gengrid_selected_items_get(obj));
+   if (it)
+     {  /* Add the item mouse is over to the list if NOT seleced */
+        void *p = eina_list_search_unsorted(*items, _item_ptr_cmp, it);
+        if (!p)
+          *items = eina_list_append(*items, it);
+     }
+
+   if (*items)
+     {  /* Now we can actually compose string to send and start dragging */
+        Eina_List *l;
+        const char *t;
+        unsigned int len = 0;
+
+        EINA_LIST_FOREACH(*items, l, it)
+          {
+             t = elm_object_item_part_text_get(it, "elm.text");
+             if (t)
+               len += strlen(t);
+          }
+
+        drag_data = malloc(len + eina_list_count(*items) * 2 + 8);
+        strcpy((char *) drag_data, "file://");
+
+        EINA_LIST_FOREACH(*items, l, it)
+          {
+             t = elm_object_item_part_text_get(it, "elm.text");
+             if (t)
+               {
+                  strcat((char *) drag_data, "#");
+                  strcat((char *) drag_data, t);
+               }
+          }
+        strcat((char *) drag_data, "#");
+
+        printf("<%s> <%d> Sending <%s>\n", __func__, __LINE__, drag_data);
+     }
+
+   return drag_data;
+}
+
+static Eina_Bool
+_gl_dnd_default_anim_data_getcb(Evas_Object *obj,  /* The genlist object */
+      Elm_Object_Item *it,
+      Elm_Drag_User_Info *info)
+{  /* This called before starting to drag, mouse-down was on it */
+   info->format = ELM_SEL_FORMAT_TARGETS;
+   info->createicon = _gl_createicon;
+   info->createdata = it;
+   info->icons = _gl_icons_get(obj);
+   info->dragdone = _gl_dragdone;
+
+   /* Now, collect data to send for drop from ALL selected items */
+   /* Save list pointer to remove items after drop and free list on done */
+   info->data = _gl_get_drag_data(obj, it, (Eina_List **) &info->donecbdata);
+   printf("%s - data = %s\n", __FUNCTION__, info->data);
+   info->acceptdata = info->donecbdata;
+
+   if (info->data)
+     return EINA_TRUE;
+   else
+     return EINA_FALSE;
+}
+
+static Eina_Bool
+_gl_data_getcb(Evas_Object *obj,  /* The genlist object */
+      Elm_Object_Item *it,
+      Elm_Drag_User_Info *info)
+{  /* This called before starting to drag, mouse-down was on it */
+   info->format = ELM_SEL_FORMAT_TARGETS;
+   info->createicon = _gl_createicon;
+   info->createdata = it;
+   info->dragdone = _gl_dragdone;
+
+   /* Now, collect data to send for drop from ALL selected items */
+   /* Save list pointer to remove items after drop and free list on done */
+   info->data = _gl_get_drag_data(obj, it, (Eina_List **) &info->donecbdata);
+   info->acceptdata = info->donecbdata;
+
+   if (info->data)
+     return EINA_TRUE;
+   else
+     return EINA_FALSE;
+}
+
+static Eina_List *
+_grid_icons_get(void *data)
+{  /* Start icons animation before actually drag-starts */
+   printf("<%s> <%d>\n", __func__, __LINE__);
+
+   Eina_List *l;
+
+   Eina_List *icons = NULL;
+
+   Evas_Coord xm, ym;
+   evas_pointer_canvas_xy_get(evas_object_evas_get(data), &xm, &ym);
+   Eina_List *items = eina_list_clone(elm_gengrid_selected_items_get(data));
+   Elm_Object_Item *gli = elm_gengrid_at_xy_item_get(data,
+         xm, ym, NULL, NULL);
+   if (gli)
+     {  /* Add the item mouse is over to the list if NOT seleced */
+        void *p = eina_list_search_unsorted(items, _item_ptr_cmp, gli);
+        if (!p)
+          items = eina_list_append(items, gli);
+     }
+
+   EINA_LIST_FOREACH(items, l, gli)
+     {  /* Now add icons to animation window */
+        Evas_Object *o = elm_object_item_part_content_get(gli,
+              "elm.swallow.icon");
+
+        if (o)
+          {
+             int x, y, w, h;
+             const char *f, *g;
+             elm_image_file_get(o, &f, &g);
+             Evas_Object *ic = elm_icon_add(data);
+             elm_image_file_set(ic, f, g);
+             evas_object_geometry_get(o, &x, &y, &w, &h);
+             evas_object_size_hint_align_set(ic,
+                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+             evas_object_size_hint_weight_set(ic,
+                   EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+
+             evas_object_move(ic, x, y);
+             evas_object_resize(ic, w, h);
+             evas_object_show(ic);
+
+             icons =  eina_list_append(icons, ic);
+          }
+     }
+
+   eina_list_free(items);
+   return icons;
+}
+
+static Eina_Bool
+_grid_data_getcb(Evas_Object *obj,  /* The genlist object */
+      Elm_Object_Item *it,
+      Elm_Drag_User_Info *info)
+{  /* This called before starting to drag, mouse-down was on it */
+   info->format = ELM_SEL_FORMAT_TARGETS;
+   info->createicon = _gl_createicon;
+   info->createdata = it;
+   info->icons = _grid_icons_get(obj);
+   info->dragdone = _gl_dragdone;
+
+   /* Now, collect data to send for drop from ALL selected items */
+   /* Save list pointer to remove items after drop and free list on done */
+   info->data = _grid_get_drag_data(obj, it, (Eina_List **) &info->donecbdata);
+   printf("%s - data = %s\n", __FUNCTION__, info->data);
+   info->acceptdata = info->donecbdata;
+
+   if (info->data)
+     return EINA_TRUE;
+   else
+     return EINA_FALSE;
+}
+
+void
+test_dnd_genlist_default_anim(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   char buf[PATH_MAX];
+   Evas_Object *win, *gl, *bxx;
+   int i, j;
+
+   win = elm_win_util_standard_add("dnd-genlist-default-anim", "DnD-Genlist-Default-Anim");
+   elm_win_autodel_set(win, EINA_TRUE);
+
+   bxx = elm_box_add(win);
+   elm_box_horizontal_set(bxx, EINA_TRUE);
+   evas_object_size_hint_weight_set(bxx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bxx);
+   evas_object_show(bxx);
+
+   itc1 = elm_genlist_item_class_new();
+   itc1->item_style     = "default";
+   itc1->func.text_get = gl_text_get;
+   itc1->func.content_get  = gl_content_get;
+   itc1->func.del       = NULL;
+
+   for (j = 0; j < 2; j++)
+     {
+        gl = elm_genlist_add(win);
+
+        /* START Drag and Drop handling */
+        evas_object_smart_callback_add(win, "delete,request", _win_del, gl);
+        elm_genlist_multi_select_set(gl, EINA_TRUE); /* We allow multi drag */
+        elm_drop_item_container_add(gl,
+              ELM_SEL_FORMAT_TARGETS,
+              _gl_item_getcb,
+              NULL, NULL,
+              NULL, NULL,
+              NULL, NULL,
+              _gl_dropcb, NULL);
+
+        elm_drag_item_container_add(gl, ANIM_TIME, DRAG_TIMEOUT,
+              _gl_item_getcb, _gl_dnd_default_anim_data_getcb);
+
+        // FIXME: This causes genlist to resize the horiz axis very slowly :(
+        // Reenable this and resize the window horizontally, then try to resize it back
+        //elm_genlist_mode_set(gl, ELM_LIST_LIMIT);
+        evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
+        elm_box_pack_end(bxx, gl);
+        evas_object_show(gl);
+
+        for (i = 0; i < 20; i++)
+          {
+             snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), img[(i % 9)]);
+             const char *path = eina_stringshare_add(buf);
+             elm_genlist_item_append(gl, itc1, path, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+          }
+     }
+
+   evas_object_resize(win, 680, 800);
+   evas_object_show(win);
+}
+
+void
+test_dnd_genlist_user_anim(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   char buf[PATH_MAX];
+   Evas_Object *win, *gl, *bxx;
+   int i, j;
+
+   win = elm_win_util_standard_add("dnd-genlist-user-anim", "DnD-Genlist-User-Anim");
+   elm_win_autodel_set(win, EINA_TRUE);
+
+   bxx = elm_box_add(win);
+   elm_box_horizontal_set(bxx, EINA_TRUE);
+   evas_object_size_hint_weight_set(bxx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bxx);
+   evas_object_show(bxx);
+
+   itc1 = elm_genlist_item_class_new();
+   itc1->item_style     = "default";
+   itc1->func.text_get = gl_text_get;
+   itc1->func.content_get  = gl_content_get;
+   itc1->func.del       = NULL;
+
+   for (j = 0; j < 2; j++)
+     {
+        gl = elm_genlist_add(win);
+
+        /* START Drag and Drop handling */
+        evas_object_smart_callback_add(win, "delete,request", _win_del, gl);
+        elm_genlist_multi_select_set(gl, EINA_TRUE); /* We allow multi drag */
+        elm_drop_item_container_add(gl,
+              ELM_SEL_FORMAT_TARGETS,
+              _gl_item_getcb,
+              NULL, NULL,
+              NULL, NULL,
+              NULL, NULL,
+              _gl_dropcb, NULL);
+
+        elm_drag_item_container_add(gl, ANIM_TIME, DRAG_TIMEOUT,
+              _gl_item_getcb, _gl_data_getcb);
+
+        /* We add mouse-down, up callbacks to start/stop drag animation */
+        evas_object_event_callback_add(gl, EVAS_CALLBACK_MOUSE_DOWN,
+              _gl_obj_mouse_down, gl);
+        /* END Drag and Drop handling */
+
+        // FIXME: This causes genlist to resize the horiz axis very slowly :(
+        // Reenable this and resize the window horizontally, then try to resize it back
+        //elm_genlist_mode_set(gl, ELM_LIST_LIMIT);
+        evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
+        elm_box_pack_end(bxx, gl);
+        evas_object_show(gl);
+
+        for (i = 0; i < 20; i++)
+          {
+             snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), img[(i % 9)]);
+             const char *path = eina_stringshare_add(buf);
+             elm_genlist_item_append(gl, itc1, path, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+          }
+     }
+
+   evas_object_resize(win, 680, 800);
+   evas_object_show(win);
+}
+
+void
+test_dnd_genlist_gengrid(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   char buf[PATH_MAX];
+   Evas_Object *win, *bxx;
+   int i;
+
+   win = elm_win_util_standard_add("dnd-genlist-gengrid", "DnD-Genlist-Gengrid");
+   elm_win_autodel_set(win, EINA_TRUE);
+
+   bxx = elm_box_add(win);
+   elm_box_horizontal_set(bxx, EINA_TRUE);
+   evas_object_size_hint_weight_set(bxx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bxx);
+   evas_object_show(bxx);
+
+     {
+        itc1 = elm_genlist_item_class_new();
+        itc1->item_style     = "default";
+        itc1->func.text_get = gl_text_get;
+        itc1->func.content_get  = gl_content_get;
+        itc1->func.del       = NULL;
+
+        Evas_Object *gl = elm_genlist_add(win);
+        evas_object_smart_callback_add(win, "delete,request", _win_del, gl);
+
+        /* START Drag and Drop handling */
+        elm_genlist_multi_select_set(gl, EINA_TRUE); /* We allow multi drag */
+        elm_drop_item_container_add(gl, ELM_SEL_FORMAT_TARGETS, _gl_item_getcb, NULL, NULL,
+              NULL, NULL, NULL, NULL, _gl_dropcb, NULL);
+
+        elm_drag_item_container_add(gl, ANIM_TIME, DRAG_TIMEOUT,
+              _gl_item_getcb, _gl_dnd_default_anim_data_getcb);
+        /* END Drag and Drop handling */
+
+        // FIXME: This causes genlist to resize the horiz axis very slowly :(
+        // Reenable this and resize the window horizontally, then try to resize it back
+        //elm_genlist_mode_set(gl, ELM_LIST_LIMIT);
+        evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
+        elm_box_pack_end(bxx, gl);
+        evas_object_show(gl);
+
+        for (i = 0; i < 20; i++)
+          {
+             snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), img[(i % 9)]);
+             const char *path = eina_stringshare_add(buf);
+             elm_genlist_item_append(gl, itc1, path, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+          }
+     }
+
+     {
+        Evas_Object *grid = elm_gengrid_add(win);
+        evas_object_smart_callback_add(win, "delete,request", _win_del, grid);
+        elm_gengrid_item_size_set(grid,
+              elm_config_scale_get() * 150,
+              elm_config_scale_get() * 150);
+        elm_gengrid_horizontal_set(grid, EINA_FALSE);
+        elm_gengrid_reorder_mode_set(grid, EINA_FALSE);
+        elm_gengrid_multi_select_set(grid, EINA_TRUE); /* We allow multi drag */
+        evas_object_size_hint_weight_set(grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        evas_object_size_hint_align_set(grid, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+        gic = elm_gengrid_item_class_new();
+        gic->item_style = "default";
+        gic->func.text_get = gl_text_get;
+        gic->func.content_get = gl_content_get;
+
+        elm_drop_item_container_add(grid, ELM_SEL_FORMAT_TARGETS, _grid_item_getcb, NULL, NULL,
+              NULL, NULL, NULL, NULL, _grid_dropcb, NULL);
+
+        elm_drag_item_container_add(grid, ANIM_TIME, DRAG_TIMEOUT,
+              _grid_item_getcb, _grid_data_getcb);
+        for (i = 0; i < 20; i++)
+          {
+             snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), img[(i % 9)]);
+             const char *path = eina_stringshare_add(buf);
+             elm_gengrid_item_append(grid, gic, path, NULL, NULL);
+          }
+        elm_box_pack_end(bxx, grid);
+        evas_object_show(grid);
+     }
+
+   evas_object_resize(win, 1280, 800);
+   evas_object_show(win);
+}
index 8223d3a..ad53bf6 100644 (file)
@@ -42,6 +42,7 @@ typedef struct _Tmp_Info      Tmp_Info;
 typedef struct _Saved_Type    Saved_Type;
 typedef struct _Cnp_Escape    Cnp_Escape;
 typedef struct _Dropable      Dropable;
+static Eina_Bool doaccept = EINA_FALSE;
 
 struct _Tmp_Info
 {
@@ -71,9 +72,61 @@ struct _Dropable
    Evas_Object    *obj;
    /* FIXME: Cache window */
    Elm_Sel_Format  types;
+   Elm_Drag_State  entercb;
+   Elm_Drag_State  leavecb;
+   Elm_Drag_Pos    poscb;
    Elm_Drop_Cb     dropcb;
+   void           *enterdata;
+   void           *leavedata;
+   void           *posdata;
    void           *cbdata;
+   struct {
+      Evas_Coord   x, y;
+      Eina_Bool    in : 1;
+   } last;
+};
+
+struct _Item_Container_Drop_Info
+{  /* Info kept for containers to support drop */
+   Evas_Object *obj;
+   Elm_Xy_Item_Get_Cb itemgetcb;
+   Elm_Drop_Item_Container_Cb dropcb;
+   Elm_Drag_Item_Container_Pos poscb;
+};
+typedef struct _Item_Container_Drop_Info Item_Container_Drop_Info;
+
+struct _Anim_Icon
+{
+   int start_x;
+   int start_y;
+   int start_w;
+   int start_h;
+   Evas_Object *o;
 };
+typedef struct _Anim_Icon Anim_Icon;
+
+struct _Item_Container_Drag_Info
+{  /* Info kept for containers to support drag */
+   Evas_Object *obj;
+   Ecore_Timer *tm;    /* When this expires, start drag */
+   double anim_tm;  /* Time period to set tm         */
+   double tm_to_drag;  /* Time period to set tm         */
+   Elm_Xy_Item_Get_Cb itemgetcb;
+   Elm_Item_Container_Data_Get_Cb data_get;
+
+   Evas_Coord x_down;  /* Mouse down x cord when drag starts */
+   Evas_Coord y_down;  /* Mouse down y cord when drag starts */
+
+   /* Some extra information needed to impl default anim */
+   Evas *e;
+   Eina_List *icons;   /* List of icons to animate (Anim_Icon) */
+   int final_icon_w; /* We need the w and h of the final icon for the animation */
+   int final_icon_h;
+   Ecore_Animator *ea;
+
+   Elm_Drag_User_Info user_info;
+};
+typedef struct _Item_Container_Drag_Info Item_Container_Drag_Info;
 
 static int _elm_cnp_init_count = 0;
 /* Stringshared, so I can just compare pointers later */
@@ -82,25 +135,41 @@ static const char *text_uri;
 static Saved_Type savedtypes =  { NULL, NULL, 0, 0, 0, EINA_FALSE };
 
 /* TODO BUG: should NEVER have these as globals! They should be per context (window). */
-static void (*dragdonecb) (void *data, Evas_Object *obj) = NULL;
+static Elm_Drag_Pos dragposcb = NULL;
+static Elm_Drag_Accept dragacceptcb = NULL;
+static Elm_Drag_State dragdonecb = NULL;
+static void *dragposdata = NULL;
+static void *dragacceptdata = NULL;
 static void *dragdonedata = NULL;
+static Evas_Object *dragwidget = NULL;
+static Elm_Xdnd_Action dragaction = ELM_XDND_ACTION_UNKNOWN;
+
+static Eina_List *cont_drop_tg = NULL; /* List of Item_Container_Drop_Info */
+static Eina_List *cont_drag_tg = NULL; /* List of Item_Container_Drag_Info */
+
+static void _cont_obj_mouse_up( void *data, Evas *e, Evas_Object *obj, void *event_info);
+static void _cont_obj_mouse_move( void *data, Evas *e, Evas_Object *obj, void *event_info);
 
 /* Drag & Drop functions */
 /* FIXME: Way too many globals */
 static Eina_List *drops = NULL;
 static Evas_Object *dragwin = NULL;
+static int dragwin_x_start, dragwin_y_start;
+static int dragwin_x_end, dragwin_y_end;
 static int _dragx = 0, _dragy = 0;
 static Ecore_Event_Handler *handler_pos = NULL;
 static Ecore_Event_Handler *handler_drop = NULL;
 static Ecore_Event_Handler *handler_enter = NULL;
 static Ecore_Event_Handler *handler_status = NULL;
+static Ecore_Event_Handler *handler_leave = NULL;
+static Ecore_Event_Handler *handler_up = NULL;
 
 static Tmp_Info  *_tempfile_new      (int size);
 static int        _tmpinfo_free      (Tmp_Info *tmp);
 static Eina_Bool  _pasteimage_append (char *file, Evas_Object *entry);
 static void       _entry_insert_filter(Evas_Object *entry, char *str); // TIZEN ONLY
 
-//#define DEBUGON 1
+#define DEBUGON 1
 #ifdef DEBUGON
 # define cnp_debug(x...) fprintf(stderr, __FILE__": " x)
 #else
@@ -137,6 +206,7 @@ struct _X11_Cnp_Selection
    Elm_Sel_Format     format;
    Ecore_X_Selection  ecore_sel;
    Ecore_X_Window     xwin;
+   Elm_Xdnd_Action    action;
 
    Eina_Bool          active : 1;
 };
@@ -175,7 +245,7 @@ static Eina_Bool      _x11_dnd_enter                (void *data __UNUSED__, int
 static Eina_Bool      _x11_dnd_drop                 (void *data __UNUSED__, int etype __UNUSED__, void *ev);
 static Eina_Bool      _x11_dnd_position             (void *data __UNUSED__, int etype __UNUSED__, void *ev);
 static Eina_Bool      _x11_dnd_status               (void *data __UNUSED__, int etype __UNUSED__, void *ev);
-static void           _x11_drag_mouse_up            (void *un __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *data);
+static Eina_Bool      _x11_drag_mouse_up            (void *data, int etype __UNUSED__, void *event);
 static void           _x11_drag_move                (void *data __UNUSED__, Ecore_X_Xdnd_Position *pos);
 
 static Ecore_X_Window _x11_elm_widget_xwin_get           (const Evas_Object *obj);
@@ -185,7 +255,11 @@ static Eina_Bool _x11_elm_cnp_selection_set              (Evas_Object *obj, Elm_
 static void      _x11_elm_cnp_selection_loss_callback_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const void *data);
 static Eina_Bool _x11_elm_object_cnp_selection_clear     (Evas_Object *obj, Elm_Sel_Type selection);
 static Eina_Bool _x11_elm_cnp_selection_get              (Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata);
-static Eina_Bool _x11_elm_drop_target_add                (Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, void *cbdata);
+static Eina_Bool _x11_elm_drop_target_add                (Evas_Object *obj, Elm_Sel_Format format, 
+                                                          Elm_Drag_State entercb, void *enterdata,
+                                                          Elm_Drag_State leavecb, void *leavedata,
+                                                          Elm_Drag_Pos poscb, void *posdata,
+                                                          Elm_Drop_Cb dropcb, void *cbdata);
 static Eina_Bool _x11_elm_drop_target_del                (Evas_Object *obj);
 static Eina_Bool _x11_elm_selection_selection_has_owner  (Evas_Object *obj __UNUSED__);
 
@@ -349,7 +423,7 @@ static X11_Cnp_Atom _x11_atoms[CNP_N_ATOMS] = {
       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
       _x11_text_converter,
       NULL,
-      NULL,
+      _x11_notify_handler_text,
       0
    },
    [CNP_ATOM_TEXT] = {
@@ -357,7 +431,7 @@ static X11_Cnp_Atom _x11_atoms[CNP_N_ATOMS] = {
       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
       _x11_text_converter,
       NULL,
-      NULL,
+      _x11_notify_handler_text,
       0
    },
    [CNP_ATOM_text_plain_utf8] = {
@@ -365,7 +439,7 @@ static X11_Cnp_Atom _x11_atoms[CNP_N_ATOMS] = {
       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
       _x11_text_converter,
       NULL,
-      NULL,
+      _x11_notify_handler_text,
       0
    },
    [CNP_ATOM_text_plain] = {
@@ -373,7 +447,7 @@ static X11_Cnp_Atom _x11_atoms[CNP_N_ATOMS] = {
       ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
       _x11_text_converter,
       NULL,
-      NULL,
+      _x11_notify_handler_text,
       0
    },
 };
@@ -412,6 +486,7 @@ _x11_sel_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_i
 {
    X11_Cnp_Selection *sel = data;
    if (sel->widget == obj) sel->widget = NULL;
+   if (dragwidget == obj) dragwidget = NULL;
 }
 
 static void
@@ -679,8 +754,33 @@ static int
 _x11_notify_handler_text(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
 {
    Ecore_X_Selection_Data *data;
+   Eina_List *l;
+   Dropable *dropable;
 
    data = notify->data;
+   if (sel == (_x11_selections + ELM_SEL_TYPE_XDND))
+     {
+        Elm_Selection_Data ddata;
+
+        cnp_debug("drag & drop\n");
+        /* FIXME: this needs to be generic: Used for all receives */
+        EINA_LIST_FOREACH(drops, l, dropable)
+          {
+             if (dropable->obj == sel->requestwidget) break;
+             dropable = NULL;
+          }
+        if (dropable)
+          {
+             ddata.x = savedtypes.x;
+             ddata.y = savedtypes.y;
+             ddata.format = ELM_SEL_FORMAT_TEXT;
+             ddata.data = data->data;
+             ddata.len = data->length;
+             ddata.action = sel->action;
+             dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
+             goto end;
+          }
+     }
    if (sel->datacb)
      {
         Elm_Selection_Data ddata;
@@ -689,6 +789,7 @@ _x11_notify_handler_text(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify
         ddata.format = ELM_SEL_FORMAT_TEXT;
         ddata.data = data->data;
         ddata.len = data->length;
+        ddata.action = sel->action;
         sel->datacb(sel->udata, sel->widget, &ddata);
      }
    else
@@ -696,7 +797,7 @@ _x11_notify_handler_text(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify
         char *stripstr, *mkupstr;
 
         stripstr = malloc(data->length + 1);
-        if (!stripstr) return 0;
+        if (!stripstr) goto end;
         strncpy(stripstr, (char *)data->data, data->length);
         stripstr[data->length] = '\0';
         cnp_debug("Notify handler text %d %d %p\n", data->format,
@@ -715,6 +816,9 @@ _x11_notify_handler_text(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify
         free(stripstr);
         free(mkupstr);
      }
+end:   
+   if (sel == (_x11_selections + ELM_SEL_TYPE_XDND))
+     ecore_x_dnd_send_finished();
    return 0;
 }
 
@@ -726,67 +830,90 @@ _x11_notify_handler_uri(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *
 {
    Ecore_X_Selection_Data *data;
    Ecore_X_Selection_Data_Files *files;
-   char *p, *stripstr;
+   char *p, *s, *stripstr = NULL;
 
    data = notify->data;
    cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
    if (data->content == ECORE_X_SELECTION_CONTENT_FILES)
      {
+        int i, len = 0;
+        
         cnp_debug("got a files list\n");
         files = notify->data;
+        /*
         if (files->num_files > 1)
           {
-             /* Don't handle many items */
+             // Don't handle many items <- this makes mr bigglesworth sad :(
              cnp_debug("more then one file: Bailing\n");
              return 0;
           }
         stripstr = p = strdup(files->files[0]);
+         */
+        for (i = 0; i < files->num_files ; i++)
+          {
+             p = files->files[i];
+             if ((strncmp(p, "file://", 7)) && (p[0] != '/')) continue;
+             len += strlen(files->files[i]) + 1;
+          }
+        p = NULL;
+        if (len > 0)
+          {
+             s = stripstr = malloc(len + 1);
+             for (i = 0; i < files->num_files ; i++)
+               {
+                  p = files->files[i];
+                  if (!strncmp(p, "file://", 7)) p += 7;
+                  else if (p[0] != '/') continue;
+                  len = strlen(p);
+                  strcpy(s, p);
+                  if (i < (files->num_files - 1))
+                    {
+                       s[len] = '\n';
+                       s[len + 1] = 0;
+                       s += len + 1;
+                    }
+                  else
+                    {
+                       s[len] = 0;
+                       s += len;
+                    }
+               }
+          }
      }
    else
      {
-        stripstr = p = malloc(data->length + 1);
-        if (!stripstr) return 0;
-        memcpy(stripstr, data->data, data->length);
-        stripstr[data->length] = 0;
+        p = (char *)data->data;
+        if ((!strncmp(p, "file://", 7)) || (p[0] == '/'))
+          {
+             int len = data->length;
+             if (!strncmp(p, "file://", 7))
+               {
+                  p += 7;
+                  len -= 7;
+               }
+             stripstr = malloc(len + 1);
+             if (!stripstr) return 0;
+             memcpy(stripstr, p, len);
+             stripstr[len] = 0;
+          }
      }
-   if (!p)
+   if (!stripstr)
      {
         cnp_debug("Couldn't find a file\n");
         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 != '/')
-          {
-             free(p);
-             return 0;
-          }
-     }
-   else p += strlen("file://");
    if (savedtypes.imgfile) free(savedtypes.imgfile);
    if (savedtypes.textreq)
      {
         savedtypes.textreq = 0;
-        savedtypes.imgfile = strdup(p);
+        savedtypes.imgfile = stripstr;
+     }
+   else
+     {
+        savedtypes.imgfile = NULL;
+        _pasteimage_append(p, sel->requestwidget);
+        free(stripstr);
      }
-   else _pasteimage_append(p, sel->requestwidget);
-   free(stripstr);
    return 0;
 }
 
@@ -824,6 +951,7 @@ _x11_vcard_receive(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notif
         ddata.format = ELM_SEL_FORMAT_VCARD;
         ddata.data = data->data;
         ddata.len = data->length;
+        ddata.action = sel->action;
         dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
         ecore_x_dnd_send_finished();
      }
@@ -834,6 +962,7 @@ _x11_vcard_receive(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notif
         ddata.format = ELM_SEL_FORMAT_VCARD;
         ddata.data = data->data;
         ddata.len = data->length;
+        ddata.action = sel->action;
         sel->datacb(sel->udata, sel->widget, &ddata);
      }
    else cnp_debug("Paste request\n");
@@ -858,6 +987,7 @@ _x11_notify_handler_image(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify
         ddata.format = ELM_SEL_FORMAT_IMAGE;
         ddata.data = data->data;
         ddata.len = data->length;
+        ddata.action = sel->action;
         sel->datacb(sel->udata, sel->widget, &ddata);
         return 0;
      }
@@ -931,6 +1061,7 @@ _x11_notify_handler_html(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify
         ddata.format = ELM_SEL_FORMAT_HTML;
         ddata.data = stripstr;
         ddata.len = data->length;
+        ddata.action = ELM_XDND_ACTION_UNKNOWN;
         sel->datacb(sel->udata, sel->widget, &ddata);
         free(stripstr);
         return 0;
@@ -1008,20 +1139,96 @@ _x11_general_converter(char *target __UNUSED__, void *data, int size, void **dat
    else
      {
         X11_Cnp_Selection *sel = _x11_selections + *((int *)data);
-        if (data_ret) *data_ret = strdup(sel->selbuf);
-        if (size_ret) *size_ret = strlen(sel->selbuf);
+        if (sel->selbuf)
+          {
+             if (data_ret) *data_ret = strdup(sel->selbuf);
+             if (size_ret) *size_ret = strlen(sel->selbuf);
+          }
+        else
+          {
+             if (data_ret) *data_ret = NULL;
+             if (size_ret) *size_ret = 0;
+          }
      }
    return EINA_TRUE;
 }
 
+static Dropable *
+_x11_dropable_find(Ecore_X_Window win)
+{
+   Eina_List *l;
+   Dropable *dropable;
+   
+   if (!drops) return NULL;
+   EINA_LIST_FOREACH(drops, l, dropable)
+     {
+        if (_x11_elm_widget_xwin_get(dropable->obj) == win) return dropable;
+     }
+   return NULL;
+}
+
+static Dropable *
+_x11_dropable_geom_find(Ecore_X_Window win, Evas_Coord px, Evas_Coord py)
+{
+   Eina_List *l;
+   Dropable *dropable;
+   Evas_Coord x, y, w, h;
+   
+   if (!drops) return NULL;
+   EINA_LIST_FOREACH(drops, l, dropable)
+     {
+        if (_x11_elm_widget_xwin_get(dropable->obj) == win)
+          {
+             evas_object_geometry_get(dropable->obj, &x, &y, &w, &h);
+             if ((px >= x) && (py >= y) && (px < (x + w)) && (py < (y + h)))
+               return dropable;
+          }
+     }
+   return NULL;
+}
+
+static void
+_x11_dropable_coords_adjust(Dropable *dropable, Evas_Coord *x, Evas_Coord *y)
+{
+   Ecore_Evas *ee;
+   int ex = 0, ey = 0;
+
+   ee = ecore_evas_ecore_evas_get(evas_object_evas_get(dropable->obj));
+   ecore_evas_geometry_get(ee, &ex, &ey, NULL, NULL);
+   *x = *x - ex;
+   *y = *y - ey;
+}
+
+static void
+_x11_dropable_all_set(Ecore_X_Window win, Evas_Coord x, Evas_Coord y, Eina_Bool set)
+{
+   Eina_List *l;
+   Dropable *dropable;
+   EINA_LIST_FOREACH(drops, l, dropable)
+     {
+        if (_x11_elm_widget_xwin_get(dropable->obj) == win)
+          {
+             dropable->last.x = x;
+             dropable->last.y = y;
+             dropable->last.in = set;
+          }
+     }
+}
+
 static Eina_Bool
 _x11_dnd_enter(void *data __UNUSED__, int etype __UNUSED__, void *ev)
 {
    Ecore_X_Event_Xdnd_Enter *enter = ev;
    int i;
+   Dropable *dropable;
 
+   dropable = _x11_dropable_find(enter->win);
+   if (dropable)
+     {
+        cnp_debug("Enter %x\n", enter->win);
+        _x11_dropable_all_set(enter->win, 0, 0, EINA_FALSE);
+     }
    /* Skip it */
-   cnp_debug("enter %p\n", enter);
    cnp_debug("enter types=%p (%d)\n", enter->types, enter->num_types);
    if ((!enter) || (!enter->num_types) || (!enter->types)) return EINA_TRUE;
 
@@ -1051,55 +1258,191 @@ _x11_dnd_enter(void *data __UNUSED__, int etype __UNUSED__, void *ev)
    return EINA_TRUE;
 }
 
+static void
+_x11_dnd_dropable_handle(Dropable *dropable, Evas_Coord x, Evas_Coord y, Eina_Bool have_obj, Elm_Xdnd_Action action)
+{
+   Dropable *dropable_last = NULL;
+   
+   if (dropable->last.in)
+     dropable_last = _x11_dropable_geom_find
+     (_x11_elm_widget_xwin_get(dropable->obj), 
+         dropable->last.x, dropable->last.y);
+   if ((have_obj) && (dropable_last == dropable)) // same
+     {
+        cnp_debug("same obj dropable %p\n", dropable);
+        if (dropable->poscb)
+          dropable->poscb(dropable->posdata, dropable->obj, x, y, action);
+     }
+   else if ((have_obj) && (!dropable_last)) // enter new obj
+     {
+        cnp_debug("enter %p\n", dropable->obj);
+        if (dropable->entercb)
+          dropable->entercb(dropable->enterdata, dropable->obj);
+        if (dropable->poscb)
+          dropable->poscb(dropable->posdata, dropable->obj, x, y, action);
+     }
+   else if ((!have_obj) && (dropable_last)) // leave last obj
+     {
+        cnp_debug("leave %p\n", dropable_last->obj);
+        if (dropable->leavecb)
+          dropable->leavecb(dropable->leavedata, dropable->obj);
+     }
+   else if (have_obj) // leave last obj and enter new one
+     {
+        cnp_debug("enter %p\n", dropable->obj);
+        if (dropable->entercb)
+          dropable->entercb(dropable->enterdata, dropable->obj);
+        if (dropable_last)
+          {
+             dropable = dropable_last;
+             if (dropable->leavecb)
+               dropable->leavecb(dropable->leavedata, dropable->obj);
+             cnp_debug("leave %p\n", dropable->obj);
+          }
+     }
+}
+
+static Elm_Xdnd_Action
+_x11_dnd_action_map(Ecore_X_Atom action)
+{
+   Elm_Xdnd_Action act = ELM_XDND_ACTION_UNKNOWN;
+
+   if (action == ECORE_X_ATOM_XDND_ACTION_COPY)
+     act = ELM_XDND_ACTION_COPY;
+   else if (action == ECORE_X_ATOM_XDND_ACTION_MOVE)
+     act = ELM_XDND_ACTION_MOVE;
+   else if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE)
+     act = ELM_XDND_ACTION_PRIVATE;
+   else if (action == ECORE_X_ATOM_XDND_ACTION_ASK)
+     act = ELM_XDND_ACTION_ASK;
+   else if (action == ECORE_X_ATOM_XDND_ACTION_LIST)
+     act = ELM_XDND_ACTION_LIST;
+   else if (action == ECORE_X_ATOM_XDND_ACTION_LINK)
+     act = ELM_XDND_ACTION_LINK;
+   else if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION)
+     act = ELM_XDND_ACTION_DESCRIPTION;
+   return act;
+}
+
+static Ecore_X_Atom
+_x11_dnd_action_rev_map(Elm_Xdnd_Action action)
+{
+   Ecore_X_Atom act = ECORE_X_ATOM_XDND_ACTION_MOVE;
+
+   if (action == ELM_XDND_ACTION_COPY)
+     act = ECORE_X_ATOM_XDND_ACTION_COPY;
+   else if (action == ELM_XDND_ACTION_MOVE)
+     act = ECORE_X_ATOM_XDND_ACTION_MOVE;
+   else if (action == ELM_XDND_ACTION_PRIVATE)
+     act = ECORE_X_ATOM_XDND_ACTION_PRIVATE;
+   else if (action == ELM_XDND_ACTION_ASK)
+     act = ECORE_X_ATOM_XDND_ACTION_ASK;
+   else if (action == ELM_XDND_ACTION_LIST)
+     act = ECORE_X_ATOM_XDND_ACTION_LIST;
+   else if (action == ELM_XDND_ACTION_LINK)
+     act = ECORE_X_ATOM_XDND_ACTION_LINK;
+   else if (action == ELM_XDND_ACTION_DESCRIPTION)
+     act = ECORE_X_ATOM_XDND_ACTION_DESCRIPTION;
+   return act;
+}
+
+static Eina_Bool
+_x11_dnd_position(void *data __UNUSED__, int etype __UNUSED__, void *ev)
+{
+   Ecore_X_Event_Xdnd_Position *pos = ev;
+   Ecore_X_Rectangle rect;
+   Dropable *dropable, *dropable_old;
+   Elm_Xdnd_Action act;
+   
+   /* Need to send a status back */
+   /* FIXME: Should check I can drop here */
+   /* FIXME: Should highlight widget */
+   dropable_old = dropable = _x11_dropable_find(pos->win);
+   if (dropable)
+     {
+        Evas_Coord x, y, ox = 0, oy = 0, ow = 0, oh = 0;
+        
+        x = pos->position.x;
+        y = pos->position.y;
+        _x11_dropable_coords_adjust(dropable, &x, &y);
+        dropable = _x11_dropable_geom_find(pos->win, x, y);
+        act = _x11_dnd_action_map(pos->action);
+        if (dropable)
+          {
+             evas_object_geometry_get(dropable->obj, &ox, &oy, &ow, &oh);
+             rect.x = pos->position.x - x + ox;
+             rect.y = pos->position.y - y + oy;
+             rect.width = ow;
+             rect.height = oh;
+             ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, pos->action);
+             cnp_debug("dnd position %i %i %p\n", x - ox, y - oy, dropable);
+             _x11_dnd_dropable_handle(dropable, x - ox, y - oy, EINA_TRUE, 
+                                      act);
+             // CCCCCCC: call dnd exit on last obj if obj != last
+             // CCCCCCC: call drop position on obj
+             _x11_dropable_all_set(pos->win, x, y, EINA_TRUE);
+          }
+        else
+          {
+             ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, pos->action);
+             cnp_debug("dnd position not in obj\n");
+             _x11_dnd_dropable_handle(dropable_old, 0, 0, EINA_FALSE, 
+                                      act);
+             // CCCCCCC: call dnd exit on last obj
+             _x11_dropable_all_set(pos->win, x, y, EINA_TRUE);
+          }
+     }
+   else
+     {
+        ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, pos->action);
+     }
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_x11_dnd_leave(void *data __UNUSED__, int etype __UNUSED__, void *ev)
+{
+   Ecore_X_Event_Xdnd_Leave *leave = ev;
+   Dropable *dropable;
+
+   dropable = _x11_dropable_find(leave->win);
+   if (dropable)
+     {
+        cnp_debug("Leave %x\n", leave->win);
+        _x11_dnd_dropable_handle(dropable, 0, 0, EINA_FALSE, ELM_XDND_ACTION_UNKNOWN);
+        _x11_dropable_all_set(leave->win, 0, 0, EINA_FALSE);
+        // CCCCCCC: call dnd exit on last obj if there was one
+     }
+   // leave->win leave->source
+   return EINA_TRUE;
+}
+
 static Eina_Bool
 _x11_dnd_drop(void *data __UNUSED__, int etype __UNUSED__, void *ev)
 {
-   struct _Ecore_X_Event_Xdnd_Drop *drop;
+   Ecore_X_Event_Xdnd_Drop *drop;
    Dropable *dropable;
-   Eina_List *l;
-   Ecore_Evas *ee;
-   Ecore_X_Window xwin;
    Elm_Selection_Data ddata;
-   int x, y, w, h;
+   Evas_Coord x = 0, y = 0;
+   Elm_Xdnd_Action act = ELM_XDND_ACTION_UNKNOWN;
    int i, j;
 
    drop = ev;
 
    cnp_debug("drops %p (%d)\n", drops, eina_list_count(drops));
-
-   // check we still have something to drop
-   if (!drops) return EINA_TRUE;
-
-   /* Find any widget in our window; then work out geometry rel to our window */
-   for (l = drops; l; l = l->next)
-     {
-        dropable = l->data;
-        xwin = _x11_elm_widget_xwin_get(dropable->obj);
-        if (xwin == drop->win) break;
-     }
-   /* didn't find a window */
-   if (!l) return EINA_TRUE;
+   if (!(dropable = _x11_dropable_find(drop->win))) return EINA_TRUE;
 
    /* Calculate real (widget relative) position */
    // - window position
    // - widget position
-   ee = ecore_evas_ecore_evas_get(evas_object_evas_get(dropable->obj));
-   ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
-   savedtypes.x = drop->position.x - x;
-   savedtypes.y = drop->position.y - y;
+   savedtypes.x = drop->position.x;
+   savedtypes.y = drop->position.y;
+   _x11_dropable_coords_adjust(dropable, &savedtypes.x, &savedtypes.y);
 
    cnp_debug("Drop position is %d,%d\n", savedtypes.x, savedtypes.y);
 
-   for (; l; l = l->next)
-     {
-        dropable = l->data;
-        evas_object_geometry_get(dropable->obj, &x, &y, &w, &h);
-        if ((savedtypes.x >= x) && (savedtypes.y >= y) &&
-            (savedtypes.x < x + w) && (savedtypes.y < y + h))
-          break; /* found! */
-     }
-
-   if (!l) return EINA_TRUE; /* didn't find one */
+   dropable = _x11_dropable_geom_find(drop->win, savedtypes.x, savedtypes.y);
+   if (!dropable) return EINA_TRUE; /* didn't find one */
 
    evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL);
    savedtypes.x -= x;
@@ -1119,8 +1462,10 @@ _x11_dnd_drop(void *data __UNUSED__, int etype __UNUSED__, void *ev)
 
 found:
    cnp_debug("Found a target we'd like: %s\n", _x11_atoms[i].name);
-   cnp_debug("0x%x\n",xwin);
+   cnp_debug("0x%x\n", drop->win);
 
+   act = _x11_dnd_action_map(drop->action);
+   
    if (i == CNP_ATOM_text_urilist)
      {
         cnp_debug("We found a URI... (%scached) %s\n",
@@ -1129,10 +1474,11 @@ found:
         if (savedtypes.imgfile)
           {
              char *entrytag;
-             static const char *tagstring = "<item absize=240x180 href="
-                "file://%s></item>";
+             static const char *tagstring = 
+               "<item absize=240x180 href=file://%s></item>";
              ddata.x = savedtypes.x;
              ddata.y = savedtypes.y;
+             ddata.action = act;
 
              /* If it's markup that also supports images */
              if ((dropable->types & ELM_SEL_FORMAT_MARKUP) &&
@@ -1182,78 +1528,141 @@ found:
      }
 
    cnp_debug("doing a request then\n");
-   _x11_selections[ELM_SEL_TYPE_XDND].xwin = xwin;
+   _x11_selections[ELM_SEL_TYPE_XDND].xwin = drop->win;
    _x11_selections[ELM_SEL_TYPE_XDND].requestwidget = dropable->obj;
    _x11_selections[ELM_SEL_TYPE_XDND].requestformat = ELM_SEL_FORMAT_MARKUP;
    _x11_selections[ELM_SEL_TYPE_XDND].active = EINA_TRUE;
+   _x11_selections[ELM_SEL_TYPE_XDND].action = act;
 
-   ecore_x_selection_xdnd_request(xwin, _x11_atoms[i].name);
+   ecore_x_selection_xdnd_request(drop->win, _x11_atoms[i].name);
    return EINA_TRUE;
 }
 
 static Eina_Bool
-_x11_dnd_position(void *data __UNUSED__, int etype __UNUSED__, void *ev)
+_x11_dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
 {
-   struct _Ecore_X_Event_Xdnd_Position *pos = ev;
-   Ecore_X_Rectangle rect;
+   Ecore_X_Event_Xdnd_Status *status = ev;
+   doaccept = EINA_FALSE;
 
-   /* Need to send a status back */
-   /* FIXME: Should check I can drop here */
-   /* FIXME: Should highlight widget */
-   rect.x = pos->position.x - 5;
-   rect.y = pos->position.y - 5;
-   rect.width = 10;
-   rect.height = 10;
-   ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, pos->action);
+   /* Only thing we care about: will accept */
+   if ((status) && (status->will_accept))
+     {
+        cnp_debug("Will accept\n");
+        doaccept = EINA_TRUE;
+     }
+   /* Won't accept */
+   else
+     {
+        cnp_debug("Won't accept accept\n");
+     }
+   if (dragacceptcb)
+     dragacceptcb(dragacceptdata, _x11_selections[ELM_SEL_TYPE_XDND].widget,
+                  doaccept);
    return EINA_TRUE;
 }
 
-/**
- * When dragging this is callback response from the destination.
- * The important thing we care about: Can we drop; thus update cursor
- * appropriately.
- */
 static Eina_Bool
-_x11_dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
-{
-   struct _Ecore_X_Event_Xdnd_Status *status = ev;
-
-   if (!status) return EINA_TRUE;
+_drag_cancel_animate(void *data __UNUSED__, double pos)
+{  /* Animation to "move back" drag-window */
+   if (pos >= 0.99)
+     {
+        evas_object_del(data);
+        return ECORE_CALLBACK_CANCEL;
+     }
+   else
+     {
+        int x, y;
+        x = dragwin_x_end - (pos * (dragwin_x_end - dragwin_x_start));
+        y = dragwin_y_end - (pos * (dragwin_y_end - dragwin_y_start));
+        evas_object_move(data, x, y);
+     }
 
-   /* Only thing we care about: will accept */
-   if (status->will_accept) cnp_debug("Will accept\n");
-   /* Won't accept */   
-   else cnp_debug("Won't accept accept\n");
-   return EINA_TRUE;
+   return ECORE_CALLBACK_RENEW;
 }
 
-static void
-_x11_drag_mouse_up(void *un __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *data)
+static Eina_Bool
+_x11_drag_mouse_up(void *data, int etype __UNUSED__, void *event)
 {
-   Ecore_X_Window xwin = *((Ecore_X_Window *)data);
-   evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP, _x11_drag_mouse_up);
-   ecore_x_dnd_drop();
-
-   cnp_debug("mouse up, xwin=%#llx\n", (unsigned long long)xwin);
+   Ecore_X_Window xwin = (Ecore_X_Window)(long)data;
+   Ecore_Event_Mouse_Button *ev = event;
 
-   /* TODO BUG: should not revert to FALSE if xwin is a drop target! */
-   ecore_x_dnd_aware_set(xwin, EINA_FALSE);
-   if (dragdonecb)
+   if ((ev->buttons == 1) &&
+       (ev->event_window == xwin))
      {
-        dragdonecb(dragdonedata, _x11_selections[ELM_SEL_TYPE_XDND].widget);
+        Eina_Bool have_drops = EINA_FALSE;
+        Eina_List *l;
+        Dropable *dropable;
+
+        ecore_x_pointer_ungrab();
+        if (handler_up)
+          {
+             ecore_event_handler_del(handler_up);
+             handler_up = NULL;
+          }
+        if (handler_status)
+          {
+             ecore_event_handler_del(handler_status);
+             handler_status = NULL;
+          }
+        ecore_x_dnd_self_drop();
+
+        cnp_debug("mouse up, xwin=%#llx\n", (unsigned long long)xwin);
+
+        EINA_LIST_FOREACH(drops, l, dropable)
+          {
+             if (xwin == _x11_elm_widget_xwin_get(dropable->obj))
+               {
+                  have_drops = EINA_TRUE;
+                  break;
+               }
+          }
+        if (!have_drops) ecore_x_dnd_aware_set(xwin, EINA_FALSE);
+        if (dragdonecb) dragdonecb(dragdonedata, dragwidget);
+        if (dragwin)
+          {
+             if (!doaccept)
+               {  /* Commit animation when drag cancelled */
+                  /* Record final position of dragwin, then do animation */
+                  ecore_animator_timeline_add(0.3,
+                        _drag_cancel_animate, dragwin);
+               }
+             else
+               {  /* No animation drop was committed */
+                  evas_object_del(dragwin);
+               }
+
+             dragwin = NULL;  /* if not freed here, free in end of anim */
+          }
+
         dragdonecb = NULL;
+        dragacceptcb = NULL;
+        dragposcb = NULL;
+        dragwidget = NULL;
+        doaccept = EINA_FALSE;
+        /*  moved to _drag_cancel_animate
+        if (dragwin)
+          {
+             evas_object_del(dragwin);
+             dragwin = NULL;
+          }
+          */
      }
-   if (dragwin)
-     {
-        evas_object_del(dragwin);
-        dragwin = NULL;
-     }
+   return EINA_TRUE;
 }
 
 static void
 _x11_drag_move(void *data __UNUSED__, Ecore_X_Xdnd_Position *pos)
 {
-   evas_object_move(dragwin, pos->position.x - _dragx, pos->position.y - _dragy);
+   evas_object_move(dragwin,
+                    pos->position.x - _dragx, pos->position.y - _dragy);
+   dragwin_x_end = pos->position.x - _dragx;
+   dragwin_y_end = pos->position.y - _dragy;
+   cnp_debug("dragevas: %p -> %p\n",
+          dragwidget,
+          evas_object_evas_get(dragwidget));
+   if (dragposcb)
+     dragposcb(dragposdata, dragwidget, pos->position.x, pos->position.y,
+               dragaction);
 }
 
 static Ecore_X_Window
@@ -1261,7 +1670,7 @@ _x11_elm_widget_xwin_get(const Evas_Object *obj)
 {
    Evas_Object *top;
    Ecore_X_Window xwin = 0;
-   
+
    top = elm_widget_top_get(obj);
    if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(obj));
    if (top) xwin = elm_win_xwindow_get(top);
@@ -1282,7 +1691,7 @@ _x11_elm_cnp_init(void)
 {
    int i;
    static int _init_count = 0;
-   
+
    if (_init_count > 0) return EINA_TRUE;
    _init_count++;
    for (i = 0; i < CNP_N_ATOMS; i++)
@@ -1291,6 +1700,7 @@ _x11_elm_cnp_init(void)
         ecore_x_selection_converter_atom_add
           (_x11_atoms[i].atom, _x11_atoms[i].converter);
      }
+   //XXX delete handlers?
    ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, _x11_selection_clear, NULL);
    ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, _x11_selection_notify, NULL);
    return EINA_TRUE;
@@ -1393,7 +1803,8 @@ _x11_elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection)
 
 static Eina_Bool
 _x11_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection,
-                      Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata)
+                           Elm_Sel_Format format, Elm_Drop_Cb datacb,
+                           void *udata)
 {
    Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
    X11_Cnp_Selection *sel;
@@ -1421,19 +1832,31 @@ _x11_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection,
 }
 
 static Eina_Bool
-_x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format,
+_x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
+                         Elm_Drag_State entercb, void *enterdata,
+                         Elm_Drag_State leavecb, void *leavedata,
+                         Elm_Drag_Pos poscb, void *posdata,
                          Elm_Drop_Cb dropcb, void *cbdata)
 {
-   Dropable *drop;
+   Dropable *drop, *dropable;
    Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
-   Eina_List *item;
+   Eina_List *item, *l;
    int first;
-
-   _x11_elm_cnp_init();
+   Eina_Bool have_drops = EINA_FALSE;
    
+   _x11_elm_cnp_init();
+
    /* TODO: check if obj is already a drop target. Do not add twice! */
 
    /* Is this the first? */
+   EINA_LIST_FOREACH(drops, l, dropable)
+     {
+        if (xwin == _x11_elm_widget_xwin_get(dropable->obj))
+          {
+             have_drops = EINA_TRUE;
+             break;
+          }
+     }
    first = (!drops) ? 1 : 0;
 
    EINA_LIST_FOREACH(drops, item, drop)
@@ -1459,6 +1882,12 @@ _x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format,
         free(drop);
         return EINA_FALSE;
      }
+   drop->entercb = entercb;
+   drop->enterdata = enterdata;
+   drop->leavecb = leavecb;
+   drop->leavedata = leavedata;
+   drop->poscb = poscb;
+   drop->posdata = posdata;
    drop->dropcb = dropcb;
    drop->cbdata = cbdata;
    drop->types = format;
@@ -1468,16 +1897,19 @@ _x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format,
                                   /* I love C and varargs */
                                   (Evas_Object_Event_Cb)elm_drop_target_del,
                                   obj);
+   if (!have_drops) ecore_x_dnd_aware_set(xwin, EINA_TRUE);
+   
    /* TODO BUG: should handle dnd-aware per window, not just the first
     * window that requested it! */
    /* If not the first: We're done */
    if (!first) return EINA_TRUE;
 
-   ecore_x_dnd_aware_set(xwin, EINA_TRUE);
 
    cnp_debug("Adding drop target calls xwin=%#llx\n", (unsigned long long)xwin);
    handler_enter = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
                                            _x11_dnd_enter, NULL);
+   handler_leave = ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE,
+                                           _x11_dnd_leave, NULL);
    handler_pos = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
                                          _x11_dnd_position, NULL);
    handler_drop = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
@@ -1488,9 +1920,10 @@ _x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format,
 static Eina_Bool
 _x11_elm_drop_target_del(Evas_Object *obj)
 {
-   Dropable *drop,*del;
-   Eina_List *item;
+   Dropable *drop, *del, *dropable;
+   Eina_List *item, *l;
    Ecore_X_Window xwin;
+   Eina_Bool have_drops = EINA_FALSE;
 
    _x11_elm_cnp_init();
    
@@ -1508,8 +1941,8 @@ _x11_elm_drop_target_del(Evas_Object *obj)
 
    evas_object_event_callback_del(obj, EVAS_CALLBACK_FREE,
                                   (Evas_Object_Event_Cb)elm_drop_target_del);
-   free(drop);
-
+   if (del) free(del);
+   
    /* TODO BUG: we should handle dnd-aware per window, not just the last that reelased it */
 
    /* If still drops there: All fine.. continue */
@@ -1517,11 +1950,39 @@ _x11_elm_drop_target_del(Evas_Object *obj)
 
    cnp_debug("Disabling DND\n");
    xwin = _x11_elm_widget_xwin_get(obj);
-   ecore_x_dnd_aware_set(xwin, EINA_FALSE);
+   EINA_LIST_FOREACH(drops, l, dropable)
+     {
+        if (xwin == _x11_elm_widget_xwin_get(dropable->obj))
+          {
+             have_drops = EINA_TRUE;
+             break;
+          }
+     }
+   if (!have_drops) ecore_x_dnd_aware_set(xwin, EINA_FALSE);
 
-   ecore_event_handler_del(handler_pos);
-   ecore_event_handler_del(handler_drop);
-   ecore_event_handler_del(handler_enter);
+   if (!drops)
+     {
+        if (handler_pos)
+          {
+             ecore_event_handler_del(handler_pos);
+             handler_pos = NULL;
+          }
+        if (handler_drop)
+          {
+             ecore_event_handler_del(handler_drop);
+             handler_drop = NULL;
+          }
+        if (handler_enter)
+          {
+             ecore_event_handler_del(handler_enter);
+             handler_enter = NULL;
+          }
+        if (handler_leave)
+          {
+             ecore_event_handler_del(handler_leave);
+             handler_leave = NULL;
+          }
+     }
 
    if (savedtypes.imgfile) free(savedtypes.imgfile);
    savedtypes.imgfile = NULL;
@@ -1529,20 +1990,38 @@ _x11_elm_drop_target_del(Evas_Object *obj)
    return EINA_TRUE;
 }
 
+static void
+_x11_drag_target_del(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *info __UNUSED__)
+{
+   X11_Cnp_Selection *sel = _x11_selections + ELM_SEL_TYPE_XDND;
+
+   if (dragwidget == obj)
+     {
+        sel->widget = NULL;
+        dragwidget = NULL;
+     }
+}
+
 static  Eina_Bool
-_x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, void (*dragdone) (void *data, Evas_Object *), void *donecbdata)
+_x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data,
+                    Elm_Xdnd_Action action,
+                    Elm_Drag_Icon_Create_Cb createicon, void *createdata,
+                    Elm_Drag_Pos dragpos, void *dragdata,
+                    Elm_Drag_Accept acceptcb, void *acceptdata,
+                    Elm_Drag_State dragdone, void *donecbdata)
 {
    Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
    X11_Cnp_Selection *sel;
    Elm_Sel_Type xdnd = ELM_SEL_TYPE_XDND;
    Ecore_Evas *ee;
-   int x, y, x2, y2, x3, y3;
-   Evas_Object *icon;
+   int x, y, x2 = 0, y2 = 0, x3, y3;
+   Evas_Object *icon = NULL;
    int w, h;
+   Ecore_X_Atom actx;
 
    _x11_elm_cnp_init();
-   
-   cnp_debug("starting drag...\n");
+
+   cnp_debug("starting drag... %p\n", obj);
 
    if (dragwin)
      {
@@ -1556,36 +2035,64 @@ _x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, v
    sel->widget = obj;
    sel->format = format;
    sel->selbuf = data ? strdup(data) : NULL;
+   sel->action = action;
+   dragwidget = obj;
+   dragaction = action;
 
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
+                                  _x11_drag_target_del, obj);
    /* TODO BUG: should NEVER have these as globals! They should be per context (window). */
+   dragposcb = dragpos;
+   dragposdata = dragdata;
+   dragacceptcb = acceptcb;
+   dragacceptdata = acceptdata;
    dragdonecb = dragdone;
    dragdonedata = donecbdata;
    /* TODO BUG: should increase dnd-awareness, in case it's drop target as well. See _x11_drag_mouse_up() */
    ecore_x_dnd_aware_set(xwin, EINA_TRUE);
    ecore_x_dnd_callback_pos_update_set(_x11_drag_move, NULL);
-   ecore_x_dnd_begin(xwin, (unsigned char *)&xdnd, sizeof(Elm_Sel_Type));
-   evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
-                                  _x11_drag_mouse_up, (void *)(long)xwin);
+   ecore_x_dnd_self_begin(xwin, (unsigned char *)&xdnd, sizeof(Elm_Sel_Type));
+   actx = _x11_dnd_action_rev_map(dragaction);
+   ecore_x_dnd_source_action_set(actx);
+   ecore_x_pointer_grab(xwin);
+   handler_up = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
+                                        _x11_drag_mouse_up,
+                                        (void *)(long)xwin);
    handler_status = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
                                             _x11_dnd_status, NULL);
-   dragwin = elm_win_add(NULL, "Elm Drag Object", ELM_WIN_UTILITY);
+   dragwin = elm_win_add(NULL, "Elm-Drag", ELM_WIN_UTILITY);
+   elm_win_alpha_set(dragwin, EINA_TRUE);
    elm_win_override_set(dragwin, EINA_TRUE);
 
-   /* FIXME: Images only */
-   icon = elm_icon_add(dragwin);
-   elm_image_file_set(icon, data + 7, NULL); /* 7!? "file://" */
+   if (createicon)
+     {
+        Evas_Coord xoff = 0, yoff = 0;
+
+        icon = createicon(createdata, dragwin, &xoff, &yoff);
+        if (icon)
+          {
+             x2 = xoff;
+             y2 = yoff;
+             evas_object_geometry_get(icon, NULL, NULL, &w, &h);
+          }
+     }
+   else
+     {
+        icon = elm_icon_add(dragwin);
+        evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL);
+        // need to resize
+     }
    elm_win_resize_object_add(dragwin, icon);
-   evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
-   evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL);
 
    /* Position subwindow appropriately */
    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
    ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
-   evas_object_geometry_get(obj, &x2, &y2, &w, &h);
    x += x2;
    y += y2;
+   dragwin_x_start = dragwin_x_end = x;
+   dragwin_y_start = dragwin_y_end = y;
    evas_object_move(dragwin, x, y);
-   evas_object_resize(icon, w, h);
    evas_object_resize(dragwin, w, h);
 
    evas_object_show(icon);
@@ -1599,6 +2106,22 @@ _x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, v
 }
 
 static Eina_Bool
+_x11_elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action)
+{
+   Ecore_X_Atom actx;
+   
+   _x11_elm_cnp_init();
+   if (!dragwin) return EINA_FALSE;
+   
+   if (dragwidget != obj) return EINA_FALSE;
+   if (dragaction == action) return EINA_TRUE;
+   dragaction = action;
+   actx = _x11_dnd_action_rev_map(dragaction);
+   ecore_x_dnd_source_action_set(actx);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
 _x11_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__)
 {
    _x11_elm_cnp_init();
@@ -1783,9 +2306,24 @@ static Eina_Bool  _local_elm_cnp_selection_set(Evas_Object *obj __UNUSED__, Elm_
 static void       _local_elm_cnp_selection_loss_callback_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection __UNUSED__, Elm_Selection_Loss_Cb func __UNUSED__, const void *data __UNUSED__);
 static Eina_Bool  _local_elm_object_cnp_selection_clear(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection);
 static Eina_Bool  _local_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, Elm_Drop_Cb datacb, void *udata);
-static  Eina_Bool _local_elm_drop_target_add(Evas_Object *obj __UNUSED__, Elm_Sel_Type format __UNUSED__, Elm_Drop_Cb dropcb __UNUSED__, void *cbdata __UNUSED__);
+static  Eina_Bool _local_elm_drop_target_add(Evas_Object *obj __UNUSED__, Elm_Sel_Format format __UNUSED__,
+                                             Elm_Drag_State entercb __UNUSED__, void *enterdata __UNUSED__,
+                                             Elm_Drag_State leavecb __UNUSED__, void *leavedata __UNUSED__,
+                                             Elm_Drag_Pos poscb __UNUSED__, void *posdata __UNUSED__,
+                                             Elm_Drop_Cb dropcb __UNUSED__, void *cbdata __UNUSED__);
 static  Eina_Bool _local_elm_drop_target_del(Evas_Object *obj __UNUSED__);
-static Eina_Bool  _local_elm_drag_start(Evas_Object *obj __UNUSED__, Elm_Sel_Format format __UNUSED__, const char *data __UNUSED__, void (*dragdone) (void *data, Evas_Object *) __UNUSED__, void *donecbdata __UNUSED__);
+static Eina_Bool  _local_elm_drag_start(Evas_Object *obj __UNUSED__,
+                                        Elm_Sel_Format format __UNUSED__,
+                                        const char *data __UNUSED__,
+                                        Elm_Xdnd_Action action __UNUSED__,
+                                        Elm_Drag_Icon_Create_Cb createicon __UNUSED__,
+                                        void *createdata __UNUSED__,
+                                        Elm_Drag_Pos dragpos __UNUSED__,
+                                        void *dragdata __UNUSED__,
+                                        Elm_Drag_Accept acceptcb __UNUSED__,
+                                        void *acceptdata __UNUSED__,
+                                        Elm_Drag_State dragdone __UNUSED__,
+                                        void *donecbdata __UNUSED__);
 static Eina_Bool  _local_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__);
 
 static void
@@ -1800,6 +2338,7 @@ _local_get_job(void *data)
    ev.format = info->format;
    ev.data = info->sel.buf;
    ev.len = info->sel.size;
+   ev.action = ELM_XDND_ACTION_UNKNOWN;
    if (info->get.func)
      info->get.func(info->get.data, info->get.obj, &ev);
 }
@@ -1877,7 +2416,13 @@ _local_elm_cnp_selection_get(Evas_Object *obj,
 
 static  Eina_Bool
 _local_elm_drop_target_add(Evas_Object *obj __UNUSED__,
-                           Elm_Sel_Type format __UNUSED__,
+                           Elm_Sel_Format format __UNUSED__,
+                           Elm_Drag_State entercb __UNUSED__,
+                           void *enterdata __UNUSED__,
+                           Elm_Drag_State leavecb __UNUSED__,
+                           void *leavedata __UNUSED__,
+                           Elm_Drag_Pos poscb __UNUSED__,
+                           void *posdata __UNUSED__,
                            Elm_Drop_Cb dropcb __UNUSED__,
                            void *cbdata __UNUSED__)
 {
@@ -1898,7 +2443,14 @@ static Eina_Bool
 _local_elm_drag_start(Evas_Object *obj __UNUSED__,
                       Elm_Sel_Format format __UNUSED__,
                       const char *data __UNUSED__,
-                      void (*dragdone) (void *data, Evas_Object *) __UNUSED__,
+                      Elm_Xdnd_Action action __UNUSED__,
+                      Elm_Drag_Icon_Create_Cb createicon __UNUSED__,
+                      void *createdata __UNUSED__,
+                      Elm_Drag_Pos dragpos __UNUSED__,
+                      void *dragdata __UNUSED__,
+                      Elm_Drag_Accept acceptcb __UNUSED__,
+                      void *acceptdata __UNUSED__,
+                      Elm_Drag_State dragdone __UNUSED__,
                       void *donecbdata __UNUSED__)
 {
    // XXX: implement me
@@ -1907,6 +2459,15 @@ _local_elm_drag_start(Evas_Object *obj __UNUSED__,
 }
 
 static Eina_Bool
+_local_elm_drag_action_set(Evas_Object *obj __UNUSED__,
+                           Elm_Xdnd_Action action __UNUSED__)
+{
+   // XXX: implement me
+   _local_elm_cnp_init();
+   return EINA_FALSE;
+}
+
+static Eina_Bool
 _local_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__)
 {
    _local_elm_cnp_init();
@@ -2138,15 +2699,22 @@ elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection,
  * Add a widget as drop target.
  */
 EAPI Eina_Bool
-elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format,
+elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
+                    Elm_Drag_State entercb, void *enterdata,
+                    Elm_Drag_State leavecb, void *leavedata,
+                    Elm_Drag_Pos poscb, void *posdata,
                     Elm_Drop_Cb dropcb, void *cbdata)
 {
    if (!_elm_cnp_init_count) _elm_cnp_init();
 #ifdef HAVE_ELEMENTARY_X
    if (_x11_elm_widget_xwin_get(obj))
-     return _x11_elm_drop_target_add(obj, format, dropcb, cbdata);
+     return _x11_elm_drop_target_add(obj, format, entercb, enterdata,
+                                     leavecb, leavedata, poscb, posdata,
+                                     dropcb, cbdata);
 #endif
-   return _local_elm_drop_target_add(obj, format, dropcb, cbdata);
+   return _local_elm_drop_target_add(obj, format, entercb, enterdata,
+                                     leavecb, leavedata, poscb, posdata,
+                                     dropcb, cbdata);
 }
 
 EAPI Eina_Bool
@@ -2161,15 +2729,38 @@ elm_drop_target_del(Evas_Object *obj)
 }
 
 EAPI Eina_Bool
-elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, 
-               void (*dragdone) (void *data, Evas_Object *), void *donecbdata)
+elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data,
+               Elm_Xdnd_Action action,
+               Elm_Drag_Icon_Create_Cb createicon, void *createdata,
+               Elm_Drag_Pos dragpos, void *dragdata,
+               Elm_Drag_Accept acceptcb, void *acceptdata,
+               Elm_Drag_State dragdone, void *donecbdata)
 {
    if (!_elm_cnp_init_count) _elm_cnp_init();
 #ifdef HAVE_ELEMENTARY_X
    if (_x11_elm_widget_xwin_get(obj))
-     return _x11_elm_drag_start(obj, format, data, dragdone, donecbdata);
+     return _x11_elm_drag_start(obj, format, data, action, 
+                                createicon, createdata, 
+                                dragpos, dragdata,
+                                acceptcb, acceptdata,
+                                dragdone, donecbdata);
 #endif
-   return _local_elm_drag_start(obj, format, data, dragdone, donecbdata);
+   return _local_elm_drag_start(obj, format, data, action,
+                                createicon, createdata,
+                                dragpos, dragdata,
+                                acceptcb, acceptdata,
+                                dragdone, donecbdata);
+}
+
+EAPI Eina_Bool
+elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action)
+{
+   if (!_elm_cnp_init_count) _elm_cnp_init();
+#ifdef HAVE_ELEMENTARY_X
+   if (_x11_elm_widget_xwin_get(obj))
+     return _x11_elm_drag_action_set(obj, action);
+#endif
+   return _local_elm_drag_action_set(obj, action);
 }
 
 EAPI Eina_Bool
@@ -2187,4 +2778,471 @@ elm_selection_selection_has_owner(Evas_Object *obj)
    return _local_elm_selection_selection_has_owner(obj);
 }
 
+/* START - Support elm containers for Drag and Drop */
+/* START - Support elm containers for Drop */
+static int
+_drop_item_container_cmp(const void *d1,
+               const void *d2)
+{
+   const Item_Container_Drop_Info *st = d1;
+   return (((uintptr_t) (st->obj)) - ((uintptr_t) d2));
+}
+
+static void
+_elm_item_container_pos_cb(void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action)
+{  /* obj is the container pointer */
+   Elm_Object_Item *it = NULL;
+   int xposret = 0;
+   int yposret = 0;
+   Item_Container_Drop_Info *st =
+      eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
+
+   if (st && st->poscb)
+     {  /* Call container drop func with specific item pointer */
+        int xo = 0;
+        int yo = 0;
+        evas_object_geometry_get(obj, &xo, &yo, NULL, NULL);
+        if (st->itemgetcb)
+          it = st->itemgetcb(obj, x+xo, y+yo, &xposret, &yposret);
+
+        st->poscb(data, obj, it, x, y, xposret, yposret, action);
+     }
+}
+
+static Eina_Bool
+_elm_item_container_drop_cb(void *data, Evas_Object *obj , Elm_Selection_Data *ev)
+{  /* obj is the container pointer */
+   Elm_Object_Item *it = NULL;
+   int xposret = 0;
+   int yposret = 0;
+   Item_Container_Drop_Info *st =
+      eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
+
+   if (st && st->dropcb)
+     {  /* Call container drop func with specific item pointer */
+        int xo = 0;
+        int yo = 0;
+        evas_object_geometry_get(obj, &xo, &yo, NULL, NULL);
+        if (st->itemgetcb)
+          it = st->itemgetcb(obj, ev->x+xo, ev->y+yo, &xposret, &yposret);
+
+        return st->dropcb(data, obj, it, ev, xposret, yposret);
+     }
+
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+elm_drop_item_container_del_internal(Evas_Object *obj, Eina_Bool full)
+{
+   Item_Container_Drop_Info *st =
+      eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
+
+   if (st)
+     {
+        elm_drop_target_del(obj);
+        st->itemgetcb= NULL;
+        st->poscb = NULL;
+        st->dropcb = NULL;
+
+        if (full)
+          {
+             free(st);
+             cont_drop_tg = eina_list_remove(cont_drop_tg, st);
+          }
+
+        return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+elm_drop_item_container_del(Evas_Object *obj)
+{
+   return elm_drop_item_container_del_internal(obj, EINA_TRUE);
+}
+
+EAPI Eina_Bool
+elm_drop_item_container_add(Evas_Object *obj,
+      Elm_Sel_Format format,
+      Elm_Xy_Item_Get_Cb itemgetcb,
+      Elm_Drag_State entercb, void *enterdata,
+      Elm_Drag_State leavecb, void *leavedata,
+      Elm_Drag_Item_Container_Pos poscb, void *posdata,
+      Elm_Drop_Item_Container_Cb dropcb, void *cbdata)
+{
+   Item_Container_Drop_Info *st;
+
+   if (elm_drop_item_container_del_internal(obj, EINA_FALSE))
+     {  /* Updating info of existing obj */
+        st = eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
+     }
+   else
+     {
+        st = calloc(1, sizeof(*st));
+        st->obj = obj;
+        cont_drop_tg = eina_list_append(cont_drop_tg, st);
+     }
+
+   st->itemgetcb = itemgetcb;
+   st->poscb = poscb;
+   st->dropcb = dropcb;
+   elm_drop_target_add(obj, format,
+                       entercb, enterdata,
+                       leavecb, leavedata,
+                       _elm_item_container_pos_cb, posdata,
+                       _elm_item_container_drop_cb, cbdata);
+
+   return EINA_TRUE;
+}
+/* END   - Support elm containers for Drop */
+
+
+/* START - Support elm containers for Drag */
+static int
+_drag_item_container_cmp(const void *d1,
+               const void *d2)
+{
+   const Item_Container_Drag_Info *st = d1;
+   return (((uintptr_t) (st->obj)) - ((uintptr_t) d2));
+}
+
+static void
+_cont_drag_done_cb(void *data, Evas_Object *obj __UNUSED__)
+{
+   Item_Container_Drag_Info *st = data;
+   elm_widget_scroll_freeze_pop(st->obj);
+   if (st->user_info.dragdone) st->user_info.dragdone(st->user_info.donecbdata, dragwidget, doaccept);
+}
+
+static Eina_Bool
+_cont_obj_drag_start(void *data)
+{  /* Start a drag-action when timer expires */
+   cnp_debug("%s In\n", __FUNCTION__);
+   Item_Container_Drag_Info *st = data;
+   st->tm = NULL;
+   Elm_Drag_User_Info *info = &st->user_info;
+   elm_widget_scroll_freeze_push(st->obj);
+   evas_object_event_callback_del_full
+      (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st);
+   elm_drag_start(  /* Commit the start only if data_get successful */
+         st->obj, info->format,
+         info->data, info->action,
+         info->createicon, info->createdata,
+         info->dragpos, info->dragdata,
+         info->acceptcb, info->acceptdata,
+         _cont_drag_done_cb, st);
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+void
+_anim_st_free(Item_Container_Drag_Info *st)
+{  /* Stops and free mem of ongoing animation */
+   if (st)
+     {
+        if (st->ea)
+          {
+             ecore_animator_del(st->ea);
+             st->ea = NULL;
+          }
+
+        Anim_Icon *sti;
+
+        EINA_LIST_FREE(st->icons, sti)
+          {
+             evas_object_del(sti->o);
+             free(sti);
+          }
+
+        st->icons = NULL;
+     }
+}
+
+static inline Eina_List *
+_anim_icons_make(Eina_List *icons)
+{  /* Make local copies of all icons, add them to list */
+   Eina_List *list = NULL, *itr;
+   Evas_Object *o;
+
+   EINA_LIST_FOREACH(icons, itr, o)
+     {  /* Now add icons to animation window */
+        Anim_Icon *st = calloc(1, sizeof(*st));
+        evas_object_geometry_get(o, &st->start_x, &st->start_y, &st->start_w, &st->start_h);
+        evas_object_show(o);
+        st->o = o;
+        list = eina_list_append(list, st);
+     }
+
+   return list;
+}
+
+static Eina_Bool
+_drag_anim_play(void *data, double pos)
+{  /* Impl of the animation of icons, called on frame time */
+   cnp_debug("%s In\n", __FUNCTION__);
+   Item_Container_Drag_Info *st = data;
+   Eina_List *l;
+   Anim_Icon *sti;
+
+   if (st->ea)
+     {
+        if (pos > 0.99)
+          {
+             st->ea = NULL;  /* Avoid deleting on mouse up */
+             EINA_LIST_FOREACH(st->icons, l, sti)
+                evas_object_hide(sti->o);
+
+             _cont_obj_drag_start(st);  /* Start dragging */
+             return ECORE_CALLBACK_CANCEL;
+          }
+
+        Evas_Coord xm, ym;
+        evas_pointer_canvas_xy_get(st->e, &xm, &ym);
+        EINA_LIST_FOREACH(st->icons, l, sti)
+          {
+             int x, y, h, w;
+             w = sti->start_w + ((st->final_icon_w - sti->start_w) * pos);
+             h = sti->start_h + ((st->final_icon_h - sti->start_h) * pos);
+             x = sti->start_x - (pos * ((sti->start_x + (w/2) - xm)));
+             y = sti->start_y - (pos * ((sti->start_y + (h/2) - ym)));
+             evas_object_move(sti->o, x, y);
+             evas_object_resize(sti->o, w, h);
+          }
+
+        return ECORE_CALLBACK_RENEW;
+     }
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static inline Eina_Bool
+_drag_anim_start(void *data)
+{  /* Start default animation */
+   cnp_debug("%s In\n", __FUNCTION__);
+   Item_Container_Drag_Info *st = data;
+
+   st->tm = NULL;
+   /* Now we need to build an (Anim_Icon *) list */
+   st->icons = _anim_icons_make(st->user_info.icons);
+   if (st->user_info.createicon)
+     {
+        Evas_Object *temp_win = elm_win_add(NULL, "Temp", ELM_WIN_UTILITY);
+        Evas_Object *final_icon = st->user_info.createicon(st->user_info.createdata, temp_win, NULL, NULL);
+        evas_object_geometry_get(final_icon, NULL, NULL, &st->final_icon_w, &st->final_icon_h);
+        evas_object_del(final_icon);
+        evas_object_del(temp_win);
+     }
+   st->ea = ecore_animator_timeline_add(st->anim_tm, _drag_anim_play, st);
+
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_cont_obj_anim_start(void *data)
+{  /* Start a drag-action when timer expires */
+   cnp_debug("%s In\n", __FUNCTION__);
+   Item_Container_Drag_Info *st = data;
+   int xposret, yposret;  /* Unused */
+   Elm_Object_Item *it = (st->itemgetcb) ?
+      (st->itemgetcb(st->obj, st->x_down, st->y_down, &xposret, &yposret))
+      : NULL;
+
+   st->tm = NULL;
+   st->user_info.format = ELM_SEL_FORMAT_TARGETS; /* Default */
+   st->icons = NULL;
+   st->user_info.data = NULL;
+   st->user_info.action = ELM_XDND_ACTION_COPY;  /* Default */
+
+   if (!it)   /* Failed to get mouse-down item, abort drag */
+     return ECORE_CALLBACK_CANCEL;
+
+   if (st->data_get)
+     {  /* collect info then start animation or start dragging */
+        if(st->data_get(    /* Collect drag info */
+                 st->obj,      /* The container object */
+                 it,           /* Drag started on this item */
+                 &st->user_info))
+          {
+             if (st->user_info.icons)
+               _drag_anim_start(st);
+             else
+               {
+                  if (st->anim_tm)
+                    {
+                       // even if we don't manage the icons animation, we have
+                       // to wait until it is finished before beginning drag.
+                       st->tm = ecore_timer_add(st->anim_tm, _cont_obj_drag_start, st);
+                    }
+                  else
+                    _cont_obj_drag_start(st);  /* Start dragging, no anim */
+               }
+          }
+     }
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_cont_obj_mouse_down(
+   void *data,
+   Evas *e,
+   Evas_Object *obj __UNUSED__,
+   void *event_info)
+{  /* Launch a timer to start dragging */
+   Evas_Event_Mouse_Down *ev = event_info;
+   cnp_debug("%s In - event %X\n", __FUNCTION__, ev->event_flags);
+   if (ev->button != 1)
+     return;  /* We only process left-click at the moment */
+
+   Item_Container_Drag_Info *st = data;
+   evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_MOVE,
+         _cont_obj_mouse_move, st);
+
+   evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_UP,
+         _cont_obj_mouse_up, st);
+
+   if (st->tm)
+     ecore_timer_del(st->tm);
+
+   st->e = e;
+   st->x_down = ev->canvas.x;
+   st->y_down = ev->canvas.y;
+   st->tm = ecore_timer_add(st->tm_to_drag, _cont_obj_anim_start, st);
+}
+
+static Eina_Bool elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full);
+
+static void
+_cont_obj_mouse_move(
+   void *data,
+   Evas *e __UNUSED__,
+   Evas_Object *obj __UNUSED__,
+   void *event_info)
+{  /* Cancel any drag waiting to start on timeout */
+
+   cnp_debug("%s In\n", __FUNCTION__);
+   if (((Evas_Event_Mouse_Move *)event_info)->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
+     {
+        cnp_debug("%s event on hold - have to cancel DnD\n", __FUNCTION__);
+        Item_Container_Drag_Info *st = data;
+        evas_object_event_callback_del_full
+           (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st);
+        evas_object_event_callback_del_full
+           (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st);
+        elm_drag_item_container_del_internal(obj, EINA_FALSE);
+
+        if (st->tm)
+          {
+             ecore_timer_del(st->tm);
+             st->tm = NULL;
+          }
+
+        _anim_st_free(st);
+     }
+   cnp_debug("%s Out\n", __FUNCTION__);
+}
+
+static void
+_cont_obj_mouse_up(
+   void *data,
+   Evas *e __UNUSED__,
+   Evas_Object *obj __UNUSED__,
+   void *event_info)
+{  /* Cancel any drag waiting to start on timeout */
+   Item_Container_Drag_Info *st = data;
+
+   cnp_debug("%s In\n", __FUNCTION__);
+   if (((Evas_Event_Mouse_Up *)event_info)->button != 1)
+     return;  /* We only process left-click at the moment */
+
+   evas_object_event_callback_del_full
+      (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st);
+   evas_object_event_callback_del_full
+      (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st);
+
+   if (st->tm)
+     {
+        ecore_timer_del(st->tm);
+        st->tm = NULL;
+     }
+
+   _anim_st_free(st);
+}
+
+static Eina_Bool
+elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full)
+{
+   Item_Container_Drag_Info *st =
+      eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj);
+
+   if (st)
+     {
+        if (st->tm)
+          ecore_timer_del(st->tm);  /* Cancel drag-start timer */
+
+        if (st->ea)  /* Cancel ongoing default animation */
+          _anim_st_free(st);
+
+        st->tm = NULL;
+
+        if (full)
+          {
+             st->itemgetcb = NULL;;
+             st->data_get = NULL;
+             evas_object_event_callback_del_full
+                (obj, EVAS_CALLBACK_MOUSE_DOWN, _cont_obj_mouse_down, st);
+
+             free(st);
+             cont_drag_tg = eina_list_remove(cont_drag_tg, st);
+          }
+
+        return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+elm_drag_item_container_del(Evas_Object *obj)
+{
+   return elm_drag_item_container_del_internal(obj, EINA_TRUE);
+}
+
+EAPI Eina_Bool
+elm_drag_item_container_add(
+   Evas_Object *obj,
+   double anim_tm,
+   double tm_to_drag,
+   Elm_Xy_Item_Get_Cb itemgetcb,
+   Elm_Item_Container_Data_Get_Cb data_get)
+{
+   Item_Container_Drag_Info *st;
+
+   if (elm_drag_item_container_del_internal(obj, EINA_FALSE))
+     {  /* Updating info of existing obj */
+        st = eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj);
+     }
+   else
+     {
+        st = calloc(1, sizeof(*st));
+        st->obj = obj;
+        cont_drag_tg = eina_list_append(cont_drag_tg, st);
+
+        /* Register for mouse callback for container to start/abort drag */
+        evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
+                                       _cont_obj_mouse_down, st);
+     }
+
+   st->tm = NULL;
+   st->anim_tm = anim_tm;
+   st->tm_to_drag = tm_to_drag;
+   st->itemgetcb = itemgetcb;
+   st->data_get = data_get;
+
+   return EINA_TRUE;
+}
+/* END   - Support elm containers for Drag */
+/* END   - Support elm containers for Drag and Drop */
 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 :*/
index 5997d3d..e49d116 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef _ELM_CNP_H
+#define _ELM_CNP_H
 /**
  * @defgroup CopyPaste CopyPaste
  * @ingroup Elementary
@@ -76,14 +78,31 @@ typedef enum
 } Elm_Sel_Format;
 
 /**
+ * Defines the kind of action associated with the drop data if for XDND
+ * @since 1.8
+ */
+typedef enum
+{
+   ELM_XDND_ACTION_UNKNOWN, /**< Action type is unknown */
+   ELM_XDND_ACTION_COPY, /**< Copy the data */
+   ELM_XDND_ACTION_MOVE, /**< Move the data */
+   ELM_XDND_ACTION_PRIVATE, /**< Pricate action type */
+   ELM_XDND_ACTION_ASK, /**< Ask the user what to do */
+   ELM_XDND_ACTION_LIST, /**< List the data */
+   ELM_XDND_ACTION_LINK, /**< Link the data */
+   ELM_XDND_ACTION_DESCRIPTION /**< Describe the data */
+} Elm_Xdnd_Action;
+
+/**
  * Structure holding the info about selected data.
  */
 struct _Elm_Selection_Data
 {
-   Evas_Coord     x, y;
-   Elm_Sel_Format format;
-   void          *data;
-   size_t         len;
+   Evas_Coord       x, y;
+   Elm_Sel_Format   format;
+   void            *data;
+   size_t           len;
+   Elm_Xdnd_Action  action; /**< The action to perform with the data @since 1.8 */
 };
 typedef struct _Elm_Selection_Data Elm_Selection_Data;
 
@@ -98,6 +117,18 @@ typedef struct _Elm_Selection_Data Elm_Selection_Data;
 typedef Eina_Bool (*Elm_Drop_Cb)(void *data, Evas_Object *obj, Elm_Selection_Data *ev);
 
 /**
+ * Callback invoked to find out what object is under (x,y) coords
+ *
+ * @param obj The container object
+ * @param x cord to check
+ * @param y cord to check
+ * @param xposret Position relative to item (left (-1), middle (0), right (1)
+ * @param yposret Position relative to item (upper (-1), middle (0), bottom (1)
+ * @return object under x,y cords or NULL if not found.
+ */
+typedef Elm_Object_Item *(*Elm_Xy_Item_Get_Cb)(Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *xposret, int *yposret);
+
+/**
  * Callback invoked in when the selection ownership for a given selection is lost.
  *
  * @param data Application specific data
@@ -106,6 +137,57 @@ typedef Eina_Bool (*Elm_Drop_Cb)(void *data, Evas_Object *obj, Elm_Selection_Dat
  */
 typedef void (*Elm_Selection_Loss_Cb)(void *data, Elm_Sel_Type selection);
 
+/**
+ * Callback called to create a drag icon object
+ *
+ * @param data Application specific data
+ * @param win The window to create the objects relative to
+ * @param xoff A return coordinate for the X offset at which to place the drag icon object relative to the source drag object
+ * @param yoff A return coordinate for the Y offset at which to place the drag icon object relative to the source drag object
+ * @return An object to fill the drag window with or NULL if not needed
+ * @since 1.8
+ */
+typedef Evas_Object *(*Elm_Drag_Icon_Create_Cb) (void *data, Evas_Object *win, Evas_Coord *xoff, Evas_Coord *yoff);
+
+/**
+ * Callback called when a drag is finished, enters, or leaves an object
+ * 
+ * @param data Application specific data
+ * @param obj The object where the drag started
+ * @since 1.8
+ */
+typedef void (*Elm_Drag_State) (void *data, Evas_Object *obj);
+
+/**
+ * Callback called when a drag is finished.
+ *
+ * @param data Application specific data
+ * @param obj The object where the drag started
+ * @param accepted TRUE if the droppped-data is accepted on drop
+ * @since 1.8
+ */
+typedef void (*Elm_Drag_Done) (void *data, Evas_Object *obj, Eina_Bool accepted);
+
+/**
+ * Callback called when a drag is responded to with an accept or deny
+ *
+ * @param data Application specific data
+ * @param obj The object where the drag started
+ * @param doaccept A boolean as to if the target accepts the drag or not
+ * @since 1.8
+ */
+typedef void (*Elm_Drag_Accept) (void *data, Evas_Object *obj, Eina_Bool doaccept);
+
+/**
+ * Callback called when a drag is over an object, and gives object-relative coordinates
+ * 
+ * @param data Application specific data
+ * @param obj The object where the drag started
+ * @param x The X coordinate relative to the top-left of the object
+ * @param y The Y coordinate relative to the top-left of the object
+ * @since 1.8
+ */
+typedef void (*Elm_Drag_Pos) (void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action);
 
 /**
  * @brief Set copy data for a widget.
@@ -200,5 +282,226 @@ EAPI Eina_Bool elm_object_cnp_selection_clear(Evas_Object *obj,
 EAPI void elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const void *data);
 
 /**
+ * @brief Set the given object as a target for drops for drag-and-drop
+ *
+ * @param obj The target object
+ * @param format The formats supported for dropping
+ * @param entercb The function to call when the object is entered with a drag
+ * @param enterdata The application data to pass to enterdata
+ * @param leavecb The function to call when the object is left with a drag
+ * @param leavedata The application data to pass to leavedata
+ * @param poscb The function to call when the object has a drag over it
+ * @param posdata The application data to pass to posdata
+ * @param dropcb The function to call when a drop has occurred
+ * @param cbdata The application data to pass to dropcb
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format, 
+                                   Elm_Drag_State entercb, void *enterdata,
+                                   Elm_Drag_State leavecb, void *leavedata,
+                                   Elm_Drag_Pos poscb, void *posdata,
+                                   Elm_Drop_Cb dropcb, void *cbdata);
+
+/**
+ * @brief Deletes the drop target status of an object
+ *
+ * @param obj The target object
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drop_target_del(Evas_Object *obj);
+
+/**
+ * @brief Begins a drag given a source object
+ *
+ * @param obj The source object
+ * @param format The drag formats supported by the data
+ * @param data The drag data itself (a string)
+ * @param action The drag action to be done
+ * @param createicon Function to call to create a drag object, or NULL if not wanted
+ * @param createdata Application data passed to @p createicon
+ * @param dragpos Function called with each position of the drag, x, y being screen coordinates if possible, and action being the current action.
+ * @param dragdata Application data passed to @p dragpos
+ * @param acceptcb Function called indicating if drop target accepts (or does not) the drop data while dragging
+ *
+ * @param acceptdata Application data passed to @p acceptcb
+ * @param dragdone Function to call when drag is done
+ * @param donecbdata Application data to pass to @p dragdone
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drag_start(Evas_Object *obj, Elm_Sel_Format format,
+                              const char *data, Elm_Xdnd_Action action,
+                              Elm_Drag_Icon_Create_Cb createicon,
+                              void *createdata,
+                              Elm_Drag_Pos dragpos, void *dragdata,
+                              Elm_Drag_Accept acceptcb, void *acceptdata,
+                              Elm_Drag_State dragdone, void *donecbdata);
+/**
+ * @brief Changes the current drag action
+ *
+ * @param obj The source of a drag if a drag is underway
+ * @param action The drag action to be done
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action);
+
+/**
+ * Callback called when a drag is over an object
+ *
+ * @param data Application specific data
+ * @param cont The container object where the drag started
+ * @param it The object item in container where mouse-over
+ * @param x The X coordinate relative to the top-left of the object
+ * @param y The Y coordinate relative to the top-left of the object
+ * @param xposret Position relative to item (left (-1), middle (0), right (1)
+ * @param yposret Position relative to item (upper (-1), middle (0), bottom (1)
+ * @param action The drag action to be done
+ * @since 1.8
+ */
+typedef void (*Elm_Drag_Item_Container_Pos) (void *data, Evas_Object *cont, Elm_Object_Item *it, Evas_Coord x, Evas_Coord y, int xposret, int yposret, Elm_Xdnd_Action action);
+
+/**
+ * Callback invoked in when the selected data is 'dropped' on container.
+ *
+ * @param data Application specific data
+ * @param obj The evas object where selected data is 'dropped'.
+ * @param it The item in container where drop-cords
+ * @param ev struct holding information about selected data
+ * @param xposret Position relative to item (left (-1), middle (0), right (1)
+ * @param yposret Position relative to item (upper (-1), middle (0), bottom (1)
+ */
+typedef Eina_Bool (*Elm_Drop_Item_Container_Cb)(void *data, Evas_Object *obj, Elm_Object_Item *it, Elm_Selection_Data *ev, int xposret, int yposret);
+
+/**
+ * Structure describing user information for the drag process.
+ *
+ * @param format The drag formats supported by the data (output)
+ * @param data The drag data itself (a string) (output)
+ * @param icons if value not NULL, play default anim (output)
+ * @param action The drag action to be done (output)
+ * @param createicon Function to call to create a drag object, or NULL if not wanted (output)
+ * @param createdata Application data passed to @p createicon (output)
+ * @param dragpos Function called with each position of the drag, x, y being screen coordinates if possible, and action being the current action. (output)
+ * @param dragdata Application data passed to @p dragpos (output)
+ * @param acceptcb Function called indicating if drop target accepts (or does not) the drop data while dragging (output)
+ * @param acceptdata Application data passed to @p acceptcb (output)
+ * @param dragdone Function to call when drag is done (output)
+ * @param donecbdata Application data to pass to @p dragdone (output)
+ */
+typedef struct _Elm_Drag_User_Info Elm_Drag_User_Info;
+
+struct _Elm_Drag_User_Info
+{
+   Elm_Sel_Format format;
+   const char *data;
+   Eina_List *icons;
+   Elm_Xdnd_Action action;
+   Elm_Drag_Icon_Create_Cb createicon;
+   void *createdata;
+   Elm_Drag_Pos dragpos;
+   void *dragdata;
+   Elm_Drag_Accept acceptcb;
+   void *acceptdata;
+   Elm_Drag_Done dragdone;
+   void *donecbdata;
+};
+
+/**
+ * Callback invoked when starting to drag for a container.
+ *
+ * @param obj The container object
+ * @param it The Elm_Object_Item pointer where drag-start
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ */
+typedef Eina_Bool (*Elm_Item_Container_Data_Get_Cb)(
+      Evas_Object *obj,
+      Elm_Object_Item *it,
+      Elm_Drag_User_Info *info);
+
+/**
+ * @brief Set a item container (list, genlist, grid) as source of drag
+ *
+ * @param obj The container object.
+ * @param tm_to_anim Time period to wait before start animation.
+ * @param tm_to_drag Time period to wait before start draggind.
+ * @param itemgetcb Callback to get Evas_Object pointer for item at (x,y)
+ * @param data_get  Callback to get drag info
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drag_item_container_add(Evas_Object *obj, double tm_to_anim, double tm_to_drag, Elm_Xy_Item_Get_Cb itemgetcb, Elm_Item_Container_Data_Get_Cb data_get);
+
+/**
+ * @brief Deletes a item container from drag-source list
+ *
+ * @param obj The target object
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drag_item_container_del(Evas_Object *obj);
+
+/**
+ * @brief Set a item container (list, genlist, grid) as target for drop.
+ *
+ * @param obj The container object.
+ * @param format The formats supported for dropping
+ * @param itemgetcb Callback to get Evas_Object pointer for item at (x,y)
+ * @param entercb The function to call when the object is entered with a drag
+ * @param enterdata The application data to pass to enterdata
+ * @param leavecb The function to call when the object is left with a drag
+ * @param leavedata The application data to pass to leavedata
+ * @param poscb The function to call when the object has a drag over it
+ * @param posdata The application data to pass to posdata
+ * @param dropcb The function to call when a drop has occurred
+ * @param cbdata The application data to pass to dropcb
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drop_item_container_add(Evas_Object *obj,
+      Elm_Sel_Format format,
+      Elm_Xy_Item_Get_Cb itemgetcb,
+      Elm_Drag_State entercb, void *enterdata,
+      Elm_Drag_State leavecb, void *leavedata,
+      Elm_Drag_Item_Container_Pos poscb, void *posdata,
+      Elm_Drop_Item_Container_Cb dropcb, void *cbdata);
+
+/**
+ * @brief Removes a container from list of drop tragets.
+ *
+ * @param obj The container object
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drop_item_container_del(Evas_Object *obj);
+
+/**
  * @}
  */
+#endif
index 26ec51e..51821fe 100644 (file)
@@ -3834,8 +3834,8 @@ _elm_entry_smart_add(Evas_Object *obj)
    priv->client_msg_handler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, _xclient_msg_cb, obj);  // TIZEN ONLY
 
    elm_drop_target_add
-     (obj, ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
-     _drag_drop_cb, NULL);
+     (obj, ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE, NULL, NULL, NULL, NULL,
+      NULL, NULL, _drag_drop_cb, NULL);
 #endif
 
    entries = eina_list_prepend(entries, obj);
@@ -4159,7 +4159,8 @@ elm_entry_password_set(Evas_Object *obj,
    else
      {
 #ifdef HAVE_ELEMENTARY_X
-        elm_drop_target_add(obj, ELM_SEL_FORMAT_MARKUP, _drag_drop_cb, NULL);
+        elm_drop_target_add(obj, ELM_SEL_FORMAT_MARKUP, NULL, NULL, NULL, NULL,
+              NULL, NULL, _drag_drop_cb, NULL);
 #endif
         _entry_selection_callbacks_register(obj);
      }
@@ -4347,7 +4348,8 @@ elm_entry_editable_set(Evas_Object *obj,
 
 #ifdef HAVE_ELEMENTARY_X
    if (editable)
-     elm_drop_target_add(obj, ELM_SEL_FORMAT_MARKUP, _drag_drop_cb, NULL);
+     elm_drop_target_add(obj, ELM_SEL_FORMAT_MARKUP, NULL, NULL,NULL, NULL,
+           NULL, NULL, _drag_drop_cb, NULL);
    else
      elm_drop_target_del(obj);
 #endif
@@ -5114,7 +5116,8 @@ elm_entry_cnp_mode_set(Evas_Object *obj,
    else if (cnp_mode == ELM_CNP_MODE_MARKUP)
      format |= ELM_SEL_FORMAT_IMAGE;
 #ifdef HAVE_ELEMENTARY_X
-   elm_drop_target_add(obj, format, _drag_drop_cb, NULL);
+   elm_drop_target_add(obj, format, NULL, NULL,NULL, NULL, NULL, NULL,
+         _drag_drop_cb, NULL);
 #endif
 }
 
index 403420e..e6fd42b 100644 (file)
@@ -3537,6 +3537,101 @@ elm_gengrid_first_item_get(const Evas_Object *obj)
 }
 
 EAPI Elm_Object_Item *
+elm_gengrid_at_xy_item_get(const Evas_Object *obj,
+                           Evas_Coord x,
+                           Evas_Coord y,
+                           int *xposret,
+                           int *yposret)
+{
+   ELM_GENGRID_CHECK(obj) NULL;
+   ELM_GENGRID_DATA_GET_OR_RETURN_VAL(obj, sd, NULL);
+
+   Elm_Gen_Item *it = ELM_GEN_ITEM_FROM_INLIST(sd->items);
+
+   Evas_Coord l = 0, r = 0, t = 0, b = 0; /* left, right, top, bottom */
+   Eina_Bool init = EINA_TRUE;
+
+   while ((it) && (it->generation < sd->generation))
+     it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
+
+   if (it)
+     do
+       {
+          Evas_Coord itx, ity;
+          Evas_Coord itw, ith;
+          evas_object_geometry_get(VIEW(it), &itx, &ity, &itw, &ith);
+
+          /* Record leftmost, rightmost, top, bottom cords to set posret */
+          if ((itw > 0) && (ith > 0) && (itx >= 0) && (ity >= 0))
+            {  /* A scroller, ignore items in negative cords,or not rendered */
+               if (init)
+                 {
+                    l = itx;
+                    r = itx + itw;
+                    t = ity;
+                    b = ity + ith;
+                    init = EINA_FALSE;
+                 }
+               else
+                 {
+                    if (itx < l)
+                      l = itx;
+                    if ((itx + itw) > r)
+                      r = itx + itw;
+                    if (ity < t)
+                      t = ity;
+                    if ((ity + ith) > b)
+                      b = ity + ith;
+                 }
+            }
+
+          if (ELM_RECTS_INTERSECT
+                (itx, ity, itw, ith, x, y, 1, 1))
+            {
+               if (yposret)
+                 {
+                    if (y <= (ity + (ith / 4))) *yposret = -1;
+                    else if (y >= (ity + ith - (ith / 4)))
+                      *yposret = 1;
+                    else *yposret = 0;
+                 }
+
+               if (xposret)
+                 {
+                    if (x <= (itx + (itw / 4))) *xposret = -1;
+                    else if (x >= (itx + itw - (itw / 4)))
+                      *xposret = 1;
+                    else *xposret = 0;
+                 }
+
+               return (Elm_Object_Item *) it;
+            }
+
+       } while ((it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next)));
+
+   /* No item found, tell the user if hit left/right/top/bottom of items */
+   if (xposret)
+     {
+        *xposret = 0;
+        if (x < l)
+          *xposret = (-1);
+        else if (x > r)
+          *xposret = (1);
+     }
+
+   if (yposret)
+     {
+        *yposret = 0;
+        if (y < t)
+          *yposret = (-1);
+        else if (y > b)
+          *yposret = (1);
+     }
+
+   return NULL;
+}
+
+EAPI Elm_Object_Item *
 elm_gengrid_last_item_get(const Evas_Object *obj)
 {
    ELM_GENGRID_CHECK(obj) NULL;
index ed0bd2b..f6e0ae0 100644 (file)
@@ -1671,5 +1671,32 @@ EAPI void                          elm_gengrid_item_select_mode_set(Elm_Object_I
 EAPI Elm_Object_Select_Mode        elm_gengrid_item_select_mode_get(const Elm_Object_Item *it);
 
 /**
+ * Get the item that is at the x, y canvas coords.
+ *
+ * @param obj The gengrid object.
+ * @param x The input x coordinate
+ * @param y The input y coordinate
+ * @param xposret The position relative to the item returned here
+ * @param yposret The position relative to the item returned here
+ * @return The item at the coordinates or NULL if none
+ *
+ * This returns the item at the given coordinates (which are canvas
+ * relative, not object-relative). If an item is at that coordinate,
+ * that item handle is returned, and if @p xposret is not NULL, the
+ * integer pointed to is set to a value of -1, 0 or 1, depending if
+ * the coordinate is on the left portion of that item (-1), on the
+ * middle section (0) or on the right part (1).
+ * if @p yposret is not NULL, the
+ * integer pointed to is set to a value of -1, 0 or 1, depending if
+ * the coordinate is on the upper portion of that item (-1), on the
+ * middle section (0) or on the lower part (1). If NULL is returned as
+ * an item (no item found there), then posret may indicate -1 or 1
+ * based if the coordinate is above or below all items respectively in
+ * the gengrid.
+ *
+ * @ingroup Gengrid
+ */
+EAPI Elm_Object_Item             *elm_gengrid_at_xy_item_get(const Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *xposret, int *yposret);
+/**
  * @}
  */
index 9081729..4b443c1 100644 (file)
@@ -1002,7 +1002,8 @@ _elm_image_smart_edit_set(Evas_Object *obj,
 
    if (sd->edit)
      elm_drop_target_add
-       (obj, ELM_SEL_FORMAT_IMAGE, _elm_image_drag_n_drop_cb, parent);
+       (obj, ELM_SEL_FORMAT_IMAGE, NULL, NULL, NULL, NULL, NULL, NULL,
+        _elm_image_drag_n_drop_cb, parent);
    else
      elm_drop_target_del(obj);
 }
index e1be283..7ad4a2d 100644 (file)
@@ -2383,3 +2383,51 @@ elm_list_last_item_get(const Evas_Object *obj)
 
    return eina_list_data_get(eina_list_last(sd->items));
 }
+
+EAPI Elm_Object_Item *
+elm_list_at_xy_item_get(const Evas_Object *obj,
+                           Evas_Coord x,
+                           Evas_Coord y,
+                           int *posret)
+{
+   ELM_LIST_CHECK(obj) NULL;
+   ELM_LIST_DATA_GET(obj, sd);
+   Eina_List *l;
+   Elm_List_Item *it;
+   Evas_Coord lasty;
+   evas_object_geometry_get(sd->hit_rect, &lasty, NULL, NULL, NULL);
+
+   EINA_LIST_FOREACH(sd->items, l, it)
+     {
+        Evas_Coord itx, ity;
+        Evas_Object *vit = VIEW(it);
+        Evas_Coord vx, vy, vw, vh;
+        evas_object_geometry_get(vit, &vx, &vy, &vw, &vh);
+
+        itx = vx;
+        ity = vy;
+        if (ELM_RECTS_INTERSECT
+              (itx, ity, vw, vh, x, y, 1, 1))
+          {
+             if (posret)
+               {
+                  if (y <= (ity + (vh / 4))) *posret = -1;
+                  else if (y >= (ity + vh - (vh / 4)))
+                    *posret = 1;
+                  else *posret = 0;
+               }
+
+             return (Elm_Object_Item *) it;
+          }
+
+        lasty = ity + vh;
+     }
+
+   if (posret)
+     {
+        if (y > lasty) *posret = 1;
+        else *posret = -1;
+     }
+
+   return NULL;
+}
index cf66010..4a45a51 100644 (file)
@@ -812,5 +812,29 @@ EAPI Elm_Object_Item             *elm_list_first_item_get(const Evas_Object *obj
 EAPI Elm_Object_Item             *elm_list_last_item_get(const Evas_Object *obj);
 
 /**
+ * Get the item that is at the x, y canvas coords.
+ *
+ * @param obj The list object.
+ * @param x The input x coordinate
+ * @param y The input y coordinate
+ * @param posret The position relative to the item returned here
+ * @return The item at the coordinates or NULL if none
+ *
+ * This returns the item at the given coordinates (which are canvas
+ * relative, not object-relative). If an item is at that coordinate,
+ * that item handle is returned, and if @p posret is not NULL, the
+ * integer pointed to is set to a value of -1, 0 or 1, depending if
+ * the coordinate is on the upper portion of that item (-1), on the
+ * middle section (0) or on the lower part (1). If NULL is returned as
+ * an item (no item found there), then posret may indicate -1 or 1
+ * based if the coordinate is above or below all items respectively in
+ * the list.
+ *
+ *
+ * @ingroup List
+ */
+EAPI Elm_Object_Item             *elm_list_at_xy_item_get(const Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *posret);
+
+/**
  * @}
  */
index 9b43517..03e6aea 100644 (file)
@@ -156,7 +156,9 @@ _long_press_cb(void *obj)
         /* FIXME: Deal with relative paths; use PATH_MAX */
         snprintf(buf, sizeof(buf), "file://%s", file);
         if (elm_drag_start
-              (obj, ELM_SEL_FORMAT_IMAGE, buf, _drag_done_cb, NULL))
+              (obj, ELM_SEL_FORMAT_IMAGE, buf, ELM_XDND_ACTION_COPY,
+               NULL, NULL, NULL, NULL, NULL, NULL,
+               _drag_done_cb, NULL))
           {
              elm_object_scroll_freeze_push(obj);
              evas_object_smart_callback_call(obj, SIG_DRAG_START, NULL);
index e7695e1..f8c6da1 100644 (file)
@@ -769,7 +769,8 @@ elm_thumb_editable_set(Evas_Object *obj,
 
    sd->edit = edit;
    if (sd->edit)
-     elm_drop_target_add(obj, ELM_SEL_FORMAT_IMAGE, _elm_thumb_dnd_cb, obj);
+     elm_drop_target_add(obj, ELM_SEL_FORMAT_IMAGE, NULL, NULL, NULL, NULL,
+           NULL, NULL, _elm_thumb_dnd_cb, obj);
    else
      elm_drop_target_del(obj);
 
index 546c057..83daa03 100644 (file)
@@ -1160,19 +1160,6 @@ EAPI void             elm_widget_tree_dot_dump(const Evas_Object *top, FILE *out
  * parsing script skips it */
 #define ELM_INTERNAL_SMART_SUBCLASS_NEW EVAS_SMART_SUBCLASS_NEW
 
-/**
- * The drag and drop API.
- * Currently experimental, and will change when it does dynamic type
- * addition RSN.
- *
- * Here so applications can start to use it, if they ask elm nicely.
- *
- * And yes, elm_widget, should probably be elm_experimental...
- * Complaints about this code should go to /dev/null, or failing that nash.
- */
-EAPI Eina_Bool elm_drop_target_add(Evas_Object *widget, Elm_Sel_Type, Elm_Drop_Cb, void *);
-EAPI Eina_Bool elm_drop_target_del(Evas_Object *widget);
-EAPI Eina_Bool elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, void (*dragdone) (void *data, Evas_Object *), void *donecbdata);
 EAPI Eina_Bool elm_selection_selection_has_owner(Evas_Object *obj);
 
 #endif