DnD/Wl: support multi-layer Drag and Drop
authorDaniel Zaoui <daniel.zaoui@samsung.com>
Wed, 25 Feb 2015 08:36:18 +0000 (10:36 +0200)
committerDaniel Zaoui <daniel.zaoui@yahoo.com>
Wed, 25 Feb 2015 08:36:18 +0000 (10:36 +0200)
Now, we use the same way as in X11 to determine which dropable target
should receive the drop data.

@feature

src/lib/elm_cnp.c

index f04e11c..08fe144 100644 (file)
@@ -1292,20 +1292,28 @@ static void
 _dropable_coords_adjust(Dropable *dropable, Evas_Coord *x, Evas_Coord *y)
 {
    Ecore_Evas *ee;
+   Evas *evas = evas_object_evas_get(dropable->obj);
    int ex = 0, ey = 0, ew = 0, eh = 0;
    Evas_Object *win;
-   Evas_Coord x2, y2;
 
-   ee = ecore_evas_ecore_evas_get(evas_object_evas_get(dropable->obj));
+   ee = ecore_evas_ecore_evas_get(evas);
    ecore_evas_geometry_get(ee, &ex, &ey, &ew, &eh);
    *x = *x - ex;
    *y = *y - ey;
 
+   /* For Wayland, frame coords have to be subtracted. */
+   Evas_Coord fx, fy;
+   evas_output_framespace_get(evas, &fx, &fy, NULL, NULL);
+   if (fx || fy) cnp_debug("evas frame fx %d fy %d\n", fx, fy);
+   *x = *x - fx;
+   *y = *y - fy;
+
    if (elm_widget_is(dropable->obj))
      {
         win = elm_widget_top_get(dropable->obj);
         if (win && !strcmp(evas_object_type_get(win), "elm_win"))
           {
+             Evas_Coord x2, y2;
              int rot = elm_win_rotation_get(win);
              switch (rot)
                {
@@ -2452,6 +2460,7 @@ static void _wl_dropable_handle(Dropable *drop, Evas_Coord x, Evas_Coord y, Eina
 static void _wl_dropable_all_set(unsigned int win, Evas_Coord x, Evas_Coord y, Eina_Bool set);
 static Eina_Bool _wl_drops_accept(const char *type);
 static unsigned int _wl_elm_widget_window_get(Evas_Object *obj);
+static Evas * _wl_evas_get_from_win(unsigned int win);
 
 static void
 _wl_sel_obj_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
@@ -3090,6 +3099,8 @@ _wl_dnd_position(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
 
    ev = event;
 
+   cnp_debug("mouse pos %i %i\n", ev->position.x, ev->position.y);
+
    dragwin_x_end = ev->position.x - _dragx;
    dragwin_y_end = ev->position.y - _dragy;
 
@@ -3097,51 +3108,97 @@ _wl_dnd_position(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
 
    if (drop)
      {
-        Ecore_Evas *ee;
-        Evas_Coord ex = 0, ey = 0;
         Evas_Coord x = 0, y = 0;
 
         x = ev->position.x;
         y = ev->position.y;
-        ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drop->obj));
-        ecore_evas_geometry_get(ee, &ex, &ey, NULL, NULL);
-        x -= ex;
-        y -= ey;
+        _dropable_coords_adjust(drop, &x, &y);
+        Evas *evas = _wl_evas_get_from_win(ev->win);
 
-        if ((drop = _wl_dropable_find_geom(ev->win, x, y)))
-          {
-             Evas_Coord ox = 0, oy = 0;
-             int i = 0;
-
-             evas_object_geometry_get(drop->obj, &ox, &oy, NULL, NULL);
+        Eina_List *dropable_list = evas ? _dropable_list_geom_find(evas, x, y) : NULL;
 
-             _wl_dropable_handle(drop, x - ox, y - oy, EINA_TRUE);
+        /* check if there is dropable (obj) can accept this drop */
+        if (dropable_list)
+          {
+             Eina_List *l;
+             Eina_Bool found = EINA_FALSE;
+             Dropable *dropable = NULL;
 
-             for (i = 0; i < savedtypes.ntypes; i++)
+             EINA_LIST_FOREACH(dropable_list, l, dropable)
                {
+#if 0
+FIXME: add types support
+                  int i, j;
+                  Eina_Inlist *itr;
                   Dropable_Cbs *cbs;
-                  EINA_INLIST_FOREACH(drop->cbs_list, cbs)
+                  EINA_INLIST_FOREACH_SAFE(dropable->cbs_list, itr, cbs)
+                    {
+                       const char *types[CNP_N_ATOMS];
+                       int types_no = _x11_dnd_types_get(cbs->types, types);
+                       for (j = 0; j < types_no; j++)
+                         {
+                            for (i = 0; i < savedtypes.ntypes; i++)
+                              {
+                                 if (!strcmp(types[j], savedtypes.types[i]))
+                                   {
+                                      found = EINA_TRUE;
+                                      dropable->last.type = savedtypes.types[i];
+                                      dropable->last.format = cbs->types;
+                                      break;
+                                   }
+                              }
+                            if (found) break;
+                         }
+                       if (found) break;
+                    }
+#else
+                  found = EINA_TRUE;
+#endif
+                  if (found) break;
+               }
+             if (found)
+               {
+                  Evas_Coord ox = 0, oy = 0;
+                  int i = 0;
+
+                  evas_object_geometry_get(dropable->obj, &ox, &oy, NULL, NULL);
+
+                  cnp_debug("Candidate on %i %i: %p\n", x - ox, y - oy, dropable);
+                  _wl_dropable_handle(dropable, x - ox, y - oy, EINA_TRUE);
+                  // CCCCCCC: call dnd exit on last obj if obj != last
+                  // CCCCCCC: call drop position on obj
+
+                  for (i = 0; i < savedtypes.ntypes; i++)
                     {
-                       switch (cbs->types)
+                       Dropable_Cbs *cbs;
+                       EINA_INLIST_FOREACH(drop->cbs_list, cbs)
                          {
-                          case ELM_SEL_FORMAT_TARGETS:
-                          case ELM_SEL_FORMAT_IMAGE:
-                             if ((!strncmp(savedtypes.types[i], "text/uri", 8)) ||
-                                   (!strncmp(savedtypes.types[i], "image/", 6)))
-                               {
-                                  wl_cnp_selection.requestwidget = drop->obj;
-                                  will_accept = EINA_TRUE;
-                               }
-                             break;
-                          default:
-                             break;
+                            switch (cbs->types)
+                              {
+                               case ELM_SEL_FORMAT_TARGETS:
+                               case ELM_SEL_FORMAT_IMAGE:
+                                  if ((!strncmp(savedtypes.types[i], "text/uri", 8)) ||
+                                        (!strncmp(savedtypes.types[i], "image/", 6)))
+                                    {
+                                       wl_cnp_selection.requestwidget = drop->obj;
+                                       will_accept = EINA_TRUE;
+                                    }
+                                  break;
+                               default:
+                                  break;
+                              }
                          }
+                       if (will_accept) break;
                     }
-                  if (will_accept) break;
+               }
+             else
+               {
+                  //if not: send false status
+                  cnp_debug("dnd position (%d, %d) not in obj\n", x, y);
+                  _wl_dropable_handle(dropable_old, 0, 0, EINA_FALSE);
+                  // CCCCCCC: call dnd exit on last obj
                }
           }
-        else
-          _wl_dropable_handle(dropable_old, 0, 0, EINA_FALSE);
 
         _wl_dropable_all_set(ev->win, x, y, EINA_TRUE);
      }
@@ -3159,8 +3216,6 @@ _wl_dnd_drop(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
 {
    Ecore_Wl_Event_Dnd_Drop *ev;
    Dropable *drop;
-   Ecore_Evas *ee;
-   Evas_Coord ex = 0, ey = 0;
    int i = 0;
 
    ev = event;
@@ -3170,13 +3225,27 @@ _wl_dnd_drop(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
 
    savedtypes.x = ev->position.x;
    savedtypes.y = ev->position.y;
-   ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drop->obj));
-   ecore_evas_geometry_get(ee, &ex, &ey, NULL, NULL);
-   savedtypes.x -= ex;
-   savedtypes.y -= ey;
+   _dropable_coords_adjust(drop, &savedtypes.x, &savedtypes.y);
+   Evas *evas = _wl_evas_get_from_win(ev->win);
 
-   if (!(drop = _wl_dropable_find_geom(ev->win, savedtypes.x, savedtypes.y)))
-     return ECORE_CALLBACK_PASS_ON;
+   Eina_List *dropable_list = evas ? _dropable_list_geom_find(evas, savedtypes.x, savedtypes.y) : NULL;
+
+   /* check if there is dropable (obj) can accept this drop */
+   if (dropable_list)
+     {
+        Eina_List *l;
+        Eina_Bool found = EINA_FALSE;
+
+        EINA_LIST_FOREACH(dropable_list, l, drop)
+          {
+             if (drop->last.in)
+               {
+                  found = EINA_TRUE;
+                  break;
+               }
+          }
+        if (!found) return ECORE_CALLBACK_PASS_ON;
+     }
 
    for (i = 0; i < savedtypes.ntypes; i++)
      {
@@ -3295,13 +3364,13 @@ static void
 _wl_dropable_data_handle(Wl_Cnp_Selection *sel, char *data)
 {
    Dropable *drop;
-   unsigned int win = 0;
    Elm_Selection_Data sdata;
    int len = 0;
    char *s = NULL;
 
-   win = _wl_elm_widget_window_get(sel->requestwidget);
-   drop = _wl_dropable_find_geom(win, savedtypes.x, savedtypes.y);
+   Evas *evas = evas_object_evas_get(sel->requestwidget);
+   Eina_List *dropable_list = evas ? _dropable_list_geom_find(evas, savedtypes.x, savedtypes.y) : NULL, *l;
+   Eina_Bool drop_found = EINA_FALSE;
 
    len = strlen(data);
    if (!(s = malloc(len + 1))) return;
@@ -3320,25 +3389,31 @@ _wl_dropable_data_handle(Wl_Cnp_Selection *sel, char *data)
 
    if (!savedtypes.imgfile) return;
 
-   Dropable_Cbs *cbs;
-   Eina_Inlist *itr;
-   EINA_INLIST_FOREACH_SAFE(drop->cbs_list, itr, cbs)
+   EINA_LIST_FOREACH(dropable_list, l, drop)
      {
-        /* If it's markup that also supports images */
-        if ((cbs->types & ELM_SEL_FORMAT_MARKUP) &&
-              (cbs->types & ELM_SEL_FORMAT_IMAGE))
-          {
-             sdata.format = ELM_SEL_FORMAT_MARKUP;
-             sdata.data = (char *)savedtypes.imgfile;
-             if (cbs->dropcb) cbs->dropcb(cbs->dropdata, drop->obj, &sdata);
-             ecore_wl_dnd_drag_end(ecore_wl_input_get());
-          }
-        else if (cbs->types & ELM_SEL_FORMAT_IMAGE)
+        Eina_Inlist *itr;
+        Dropable_Cbs *cbs;
+        if (drop_found) continue;
+        EINA_INLIST_FOREACH_SAFE(drop->cbs_list, itr, cbs)
           {
-             sdata.format = ELM_SEL_FORMAT_IMAGE;
-             sdata.data = (char *)savedtypes.imgfile;
-             if (cbs->dropcb) cbs->dropcb(cbs->dropdata, drop->obj, &sdata);
-             ecore_wl_dnd_drag_end(ecore_wl_input_get());
+             /* If it's markup that also supports images */
+             if ((cbs->types & ELM_SEL_FORMAT_MARKUP) &&
+                   (cbs->types & ELM_SEL_FORMAT_IMAGE))
+               {
+                  sdata.format = ELM_SEL_FORMAT_MARKUP;
+                  sdata.data = (char *)savedtypes.imgfile;
+                  if (cbs->dropcb) cbs->dropcb(cbs->dropdata, drop->obj, &sdata);
+                  ecore_wl_dnd_drag_end(ecore_wl_input_get());
+                  drop_found = EINA_TRUE;
+               }
+             else if (cbs->types & ELM_SEL_FORMAT_IMAGE)
+               {
+                  sdata.format = ELM_SEL_FORMAT_IMAGE;
+                  sdata.data = (char *)savedtypes.imgfile;
+                  if (cbs->dropcb) cbs->dropcb(cbs->dropdata, drop->obj, &sdata);
+                  ecore_wl_dnd_drag_end(ecore_wl_input_get());
+                  drop_found = EINA_TRUE;
+               }
           }
      }
    ELM_SAFE_FREE(savedtypes.imgfile, free);
@@ -3357,6 +3432,13 @@ _wl_dropable_find(unsigned int win)
    return NULL;
 }
 
+static Evas *
+_wl_evas_get_from_win(unsigned int win)
+{
+   Dropable *dropable = _wl_dropable_find(win);
+   return dropable ? evas_object_evas_get(dropable->obj) : NULL;
+}
+
 static Dropable *
 _wl_dropable_find_geom(unsigned int win, Evas_Coord x, Evas_Coord y)
 {