Implement multi-type copy and paste 88/311488/10
authorBowon Ryu <bowon.ryu@samsung.com>
Wed, 22 May 2024 01:26:07 +0000 (10:26 +0900)
committerBowon Ryu <bowon.ryu@samsung.com>
Tue, 11 Jun 2024 01:21:47 +0000 (01:21 +0000)
Change-Id: I33081c5fa2b80eb9fc46b2c22b8a46086199e806
Signed-off-by: Bowon Ryu <bowon.ryu@samsung.com>
src/lib/ecore_evas/Ecore_Evas.h
src/lib/ecore_evas/ecore_evas.c
src/lib/ecore_evas/ecore_evas_fallback_selection.c
src/lib/ecore_evas/ecore_evas_private.h
src/lib/elementary/elm_cnp.c
src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_common.c
src/modules/ecore_evas/engines/wayland/ecore_evas_wayland_private.h

index 79d203f..1bf09e6 100755 (executable)
@@ -3998,6 +3998,20 @@ typedef enum {
 } Ecore_Evas_Selection_Buffer;
 
 /**
+ * @internal
+ *
+ * @brief Mime type of Copy&Paste operations
+ */
+typedef enum {
+   ECORE_EVAS_SELECTION_CNP_TYPE_TEXT = 0,  /**< text/plain;charset=utf-8 / application/x-elementary-markup */
+   ECORE_EVAS_SELECTION_CNP_TYPE_HTML = 1,  /**< application/xhtml+xml */
+   ECORE_EVAS_SELECTION_CNP_TYPE_URI = 2,   /**< text/uri-list */
+   ECORE_EVAS_SELECTION_CNP_TYPE_VCARD = 3, /**< text/vcard */
+   ECORE_EVAS_SELECTION_CNP_TYPE_IMAGE = 4, /**< image/ */
+   ECORE_EVAS_SELECTION_CNP_TYPE_LAST = 5,  /**< Sentinel value. Do not use. */
+} Ecore_Evas_Selection_Cnp_Type;
+
+/**
  * @brief Callback called when the content of one of the selection buffers changes.
  *
  * @param[in] ee The Ecore_Evas that handles this selection.
index 75ca5b7..0813bce 100644 (file)
@@ -6313,10 +6313,21 @@ _deliver_cb(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffe
 
    INF("Delivery request on seat %d in buffer %d", seat, buffer);
 
-   buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_FALSE);
-   EINA_SAFETY_ON_NULL_GOTO(buffers, free_everything);
-   content = buffers->selection_buffer[buffer];
+   if (buffer == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
+     {
+        buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_FALSE);
+        EINA_SAFETY_ON_NULL_GOTO(buffers, free_everything);
+        content = buffers->selection_buffer[buffer];
+     }
+   else
+     {
+        if (eina_streq(type, "application/x-elementary-markup"))
+          type = "text/plain;charset=utf-8";
+        content = eina_hash_find(ee->cnp_selection_buffers, type);
+     }
+
    EINA_SAFETY_ON_NULL_GOTO(content, free_everything);
+
    if (!eina_streq(type, eina_content_type_get(content)))
      converted = eina_content_convert(content, type);
    else
@@ -6340,29 +6351,42 @@ free_everything:
    if (converted && content && !eina_streq(type, eina_content_type_get(content)))
      eina_content_free(converted);
 
+   INF("Delivery request, type:%s, result:%d", type, result);
    return result;
 }
 
 static void
-_cancel_cb(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer)
+_cancel_cb(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type)
 {
-   Ecore_Evas_Selection_Seat_Buffers *buffers;
-
    INF("Cancel request on seat %d in buffer %d", seat, buffer);
 
-   buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_FALSE);
-   EINA_SAFETY_ON_FALSE_RETURN(buffers);
-   EINA_SAFETY_ON_FALSE_RETURN(buffers->selection_buffer[buffer]);
-   eina_content_free(buffers->selection_buffer[buffer]);
-   buffers->selection_buffer[buffer] = NULL;
-
    if (buffer == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
      {
+        Ecore_Evas_Selection_Seat_Buffers *buffers;
+        buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_FALSE);
+        EINA_SAFETY_ON_FALSE_RETURN(buffers);
+        EINA_SAFETY_ON_FALSE_RETURN(buffers->selection_buffer[buffer]);
+        eina_content_free(buffers->selection_buffer[buffer]);
+        buffers->selection_buffer[buffer] = NULL;
+
         ee->drag.rep = NULL;
         if (ee->drag.free)
           ee->drag.free(ee, seat, ee->drag.data, EINA_FALSE);
         ee->drag.free = NULL;
      }
+   else
+     {
+        if (ee->cnp_selection_buffers && type)
+          {
+             Eina_Content *content = eina_hash_find(ee->cnp_selection_buffers, type);
+             if (content)
+               {
+                  eina_content_free(content);
+                  eina_hash_del(ee->cnp_selection_buffers, type, NULL);
+                  INF("Cancel request, type:%s", type);
+               }
+          }
+     }
 }
 
 #define CALL(call)  (ee->engine.func->fn_ ##call ? : fallback_ ##call)
@@ -6404,14 +6428,36 @@ ecore_evas_selection_set(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection
 
    buffers = _fetch_selection_buffers_of_seat(ee, seat, EINA_TRUE);
 
+   const char *type = NULL;
    if (content)
-     available_type = eina_content_possible_conversions(content);
+     {
+        available_type = eina_content_possible_conversions(content);
+        type = eina_content_type_get(content);
+        if (eina_streq(type, "application/x-elementary-markup"))
+          type = "text/plain;charset=utf-8";
+     }
 
-   success = CALL(selection_claim)(ee, seat, buffer, _iterator_to_array(available_type, content ? eina_content_type_get(content) : NULL), content ? _deliver_cb : NULL, content ? _cancel_cb : NULL);
+   INF("Selection set type:%s", type);
+   success = CALL(selection_claim)(ee, seat, buffer, _iterator_to_array(available_type, content ? type : NULL), content ? _deliver_cb : NULL, content ? _cancel_cb : NULL);
    if (success)
      {
-        EINA_SAFETY_ON_FALSE_RETURN_VAL(buffers->selection_buffer[buffer] == NULL, EINA_FALSE);
-        //keep this after the claim, the claim might call cancel, which would overwrite this.
+        if (ee->cnp_selection_buffers)
+          {
+             Eina_Content *old_content = eina_hash_find(ee->cnp_selection_buffers, type);
+             if (old_content)
+               {
+                  eina_content_free(old_content);
+                  eina_hash_del(ee->cnp_selection_buffers, type, NULL);
+                  INF("Selection claim, old content free, type:%s\n", type);
+               }
+          }
+
+        if (!ee->cnp_selection_buffers)
+          ee->cnp_selection_buffers = eina_hash_string_superfast_new(NULL);
+
+        eina_hash_add(ee->cnp_selection_buffers, type, content);
+
+        // just keep last content.
         buffers->selection_buffer[buffer] = content;
      }
    else if (content)
index 1abdfa2..1fad849 100644 (file)
@@ -21,7 +21,7 @@ fallback_selection_shutdown(Ecore_Evas *ee)
    for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i)
      {
         if (data->callbacks[i].cancel)
-          data->callbacks[i].cancel(ee, data->seat, i);
+          data->callbacks[i].cancel(ee, data->seat, i, NULL);
      }
 }
 
@@ -32,7 +32,7 @@ fallback_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection
 
    if (callbacks->cancel)
      {
-        callbacks->cancel(ee, data->seat, selection);
+        callbacks->cancel(ee, data->seat, selection, NULL);
         eina_array_free(callbacks->available_types);
      }
 
index fb4f1b1..4ec4ca2 100644 (file)
@@ -83,7 +83,7 @@ typedef struct _Ecore_Evas_Aux_Hint Ecore_Evas_Aux_Hint;
 typedef struct _Ecore_Evas_Cursor Ecore_Evas_Cursor;
 
 typedef Eina_Bool (*Ecore_Evas_Selection_Internal_Delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice);
-typedef void (*Ecore_Evas_Selection_Internal_Cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer);
+typedef void (*Ecore_Evas_Selection_Internal_Cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type);
 typedef struct
 {
    Ecore_Evas_Selection_Internal_Delivery delivery;
@@ -256,6 +256,7 @@ struct _Ecore_Evas
    Eina_List  *vnc_server; /* @since 1.19 */
 
    Eina_Hash  *selection_buffers;
+   Eina_Hash  *cnp_selection_buffers;
 
    struct
      {
index 639925b..0fcfa12 100644 (file)
@@ -178,6 +178,7 @@ elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection,
    if (mem_buf != NULL)
      free(mem_buf);
 
+   ERR("type:%s, data:%s \n", mime_type, (char*)buf);
    return ecore_evas_selection_set(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), content);
 }
 
@@ -309,6 +310,12 @@ elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type selection,
 
    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
    mime_types = _elm_sel_format_to_mime_type(format);
+
+   unsigned int type_count = eina_array_count(mime_types);
+   ERR("selection:%d, format:%d, types:%u", selection, format, type_count);
+   for (unsigned int i = 0; i < type_count; ++i)
+     ERR("type:%s", (char *)eina_array_data_get(mime_types, i));
+
    future = ecore_evas_selection_get(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), eina_array_iterator_new(mime_types));
    storage = calloc(1,sizeof(Callback_Storage));
    storage->data_cb = data_cb;
index b0fe77e..1d198f4 100644 (file)
@@ -2083,6 +2083,10 @@ _ecore_evas_wl_common_free(Ecore_Evas *ee)
    EINA_LIST_FREE(wdata->devices_list, device)
       free(device);
 
+   const char *type;
+   EINA_LIST_FREE(wdata->set_types, type)
+      eina_stringshare_del(type);
+
    free(wdata);
 
    ecore_event_window_unregister(ee->prop.window);
@@ -3520,6 +3524,87 @@ _ecore_wl2_devices_setup(Ecore_Evas *ee, Ecore_Wl2_Display *display)
    return r;
 }
 
+static char*
+_cnp_type_to_mime_type(Ecore_Evas_Selection_Cnp_Type cnp_type)
+{
+   switch (cnp_type)
+   {
+      case ECORE_EVAS_SELECTION_CNP_TYPE_TEXT:
+      return "text/plain;charset=utf-8";
+
+      case ECORE_EVAS_SELECTION_CNP_TYPE_HTML:
+      return "application/xhtml+xml";
+
+      case ECORE_EVAS_SELECTION_CNP_TYPE_URI:
+      return "text/uri-list";
+
+      case ECORE_EVAS_SELECTION_CNP_TYPE_VCARD:
+      return "text/vcard";
+
+      case ECORE_EVAS_SELECTION_CNP_TYPE_IMAGE:
+      return ""; // use wdata->reserved_image_type
+
+      default:
+      return "text/plain;charset=utf-8";
+   }
+}
+
+static Ecore_Evas_Selection_Cnp_Type
+_mime_type_to_cnp_type(const char *mime_type)
+{
+   Ecore_Evas_Selection_Cnp_Type cnp_type = ECORE_EVAS_SELECTION_CNP_TYPE_TEXT;
+
+   if (eina_streq(mime_type, "text/plain;charset=utf-8") ||
+       eina_streq(mime_type, "application/x-elementary-markup"))
+     cnp_type = ECORE_EVAS_SELECTION_CNP_TYPE_TEXT;
+   else if (eina_streq(mime_type, "application/xhtml+xml"))
+     cnp_type = ECORE_EVAS_SELECTION_CNP_TYPE_HTML;
+   else if (eina_streq(mime_type, "text/uri-list"))
+     cnp_type = ECORE_EVAS_SELECTION_CNP_TYPE_URI;
+   else if (eina_streq(mime_type, "text/vcard"))
+     cnp_type = ECORE_EVAS_SELECTION_CNP_TYPE_VCARD;
+   else if (strcasestr(mime_type, "image/"))
+     cnp_type = ECORE_EVAS_SELECTION_CNP_TYPE_IMAGE;
+
+   return cnp_type;
+}
+
+static void
+_clear_reserved_offer_receive_types(Ecore_Evas *ee)
+{
+   Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data;
+
+   for (int i = 0 ; i < ECORE_EVAS_SELECTION_CNP_TYPE_LAST ; i ++)
+     wdata->reserved_types[i] = EINA_FALSE;
+}
+
+static void
+_reserve_offer_receive(Ecore_Evas *ee, Ecore_Evas_Selection_Cnp_Type cnp_type)
+{
+   Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data;
+
+   if (cnp_type < ECORE_EVAS_SELECTION_CNP_TYPE_LAST)
+     wdata->reserved_types[cnp_type] = EINA_TRUE;
+}
+
+static Ecore_Evas_Selection_Cnp_Type
+_get_reserved_offer_receive_type(Ecore_Evas *ee)
+{
+   Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data;
+   Ecore_Evas_Selection_Cnp_Type reserved_cnp_type = ECORE_EVAS_SELECTION_CNP_TYPE_LAST;
+
+   for (int i = 0 ; i < ECORE_EVAS_SELECTION_CNP_TYPE_LAST ; i ++)
+     {
+        if (wdata->reserved_types[i])
+          {
+             reserved_cnp_type = i;
+             wdata->reserved_types[i] = EINA_FALSE;
+             break;
+          }
+     }
+   return reserved_cnp_type;
+}
+
 static void
 _reeval_seat(unsigned int *seat, Ecore_Evas *ee)
 {
@@ -3532,14 +3617,30 @@ _reeval_seat(unsigned int *seat, Ecore_Evas *ee)
 }
 
 static inline void
-_clear_selection(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection)
+_clear_selection(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, const char *type)
 {
    Ecore_Evas_Engine_Wl_Data *edata = ee->engine.data;
-   Ecore_Evas_Selection_Callbacks *cbs = &edata->selection_data[selection].callbacks;
+   Ecore_Evas_Selection_Callbacks *cbs;
 
-   EINA_SAFETY_ON_FALSE_RETURN(cbs->cancel);
+   if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
+     {
+        cbs = &edata->selection_data[selection].callbacks;
+     }
+   else
+     {
+        if (type)
+          {
+             Ecore_Evas_Selection_Cnp_Type cnp_type = _mime_type_to_cnp_type(type);
+             cbs = &edata->selection_datas[cnp_type].callbacks;
+          }
+        else
+          {
+             cbs = &edata->selection_data[selection].callbacks;
+          }
+     }
 
-   cbs->cancel(ee, seat, selection);
+   EINA_SAFETY_ON_FALSE_RETURN(cbs->cancel);
+   cbs->cancel(ee, seat, selection, type);
    eina_array_free(cbs->available_types);
    memset(cbs, 0, sizeof(Ecore_Evas_Selection_Callbacks));
 }
@@ -3552,12 +3653,23 @@ _store_selection_cbs(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buf
    Ecore_Evas_Selection_Callbacks *cbs;
 
    edata = ee->engine.data;
-   sdata = &edata->selection_data[selection];
-   cbs = &sdata->callbacks;
+   char *type = NULL;
+
+   if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
+     {
+        sdata = &edata->selection_data[selection];
+     }
+   else
+     {
+        type = eina_array_data_get(available_types, 0u);
+        Ecore_Evas_Selection_Cnp_Type cnp_type = _mime_type_to_cnp_type(type);
+        sdata = &edata->selection_datas[cnp_type];
+     }
 
+   cbs = &sdata->callbacks;
    if (cbs->cancel)
      {
-        _clear_selection(ee, seat, selection);
+        _clear_selection(ee, seat, selection, type);
      }
 
    cbs->delivery = delivery;
@@ -3575,109 +3687,279 @@ _fetch_input(Ecore_Evas *ee, unsigned int seat)
 static Eina_Bool
 _ecore_evas_wl_selection_claim(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel)
 {
-   Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data;
-   Ecore_Evas_Wl_Selection_Data *data = &wdata->selection_data[selection];
-   char *tmp_array[eina_array_count(available_types) + 1];
-
    if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER)
      {
         _store_selection_cbs(ee, seat, selection, available_types, delivery, cancel);
         return EINA_TRUE;
      }
 
-   _reeval_seat(&seat, ee);
-   _store_selection_cbs(ee, seat, selection, available_types, delivery, cancel);
+   Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data;
+   unsigned int type_count = eina_array_count(available_types);
+   if (type_count == 0u)
+     {
+        ERR("available_types is empty");
+        return EINA_FALSE;
+     }
 
-   for (unsigned int i = 0; i < eina_array_count(available_types); ++i)
+   char *tmp_array[type_count + 1];
+
+   for (unsigned int i = 0; i < type_count; ++i)
      {
         tmp_array[i] = eina_array_data_get(available_types, i);
      }
-   tmp_array[eina_array_count(available_types)] = NULL;
+   tmp_array[type_count] = NULL;
 
-   data->sent_serial = ecore_wl2_dnd_selection_set(_fetch_input(ee, seat), (const char**)tmp_array);
-   return EINA_TRUE;
-}
+   char *mime_type = NULL;
+   for (unsigned int i = 0; i < type_count; ++i)
+     {
+        char *temp = eina_array_data_get(available_types, i);
+        if (eina_streq(temp, "application/x-elementary-markup"))
+          continue;
 
+        mime_type = temp;
+        break;
+     }
 
-static Eina_Future*
-_ecore_evas_wl_selection_request(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_types)
-{
-   Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data;
-   Ecore_Evas_Wl_Selection_Data *data = &wdata->selection_data[selection];
-   Ecore_Wl2_Input *input;
-   Ecore_Wl2_Offer *offer = NULL;
-   Eina_Future *future;
+   Ecore_Evas_Selection_Cnp_Type cnp_type = _mime_type_to_cnp_type(mime_type);
+   Ecore_Evas_Wl_Selection_Data *data = &wdata->selection_datas[cnp_type];
 
    _reeval_seat(&seat, ee);
-   input = _fetch_input(ee, seat);
+   _store_selection_cbs(ee, seat, selection, available_types, delivery, cancel);
 
-   if (data->delivery)
-     {
-        eina_promise_reject(data->delivery, ecore_evas_request_replaced);
-        data->delivery = NULL;
-     }
-   data->delivery = efl_loop_promise_new(efl_main_loop_get());
-   future = eina_future_new(data->delivery);
+   data->sent_serial = ecore_wl2_dnd_selection_set(_fetch_input(ee, seat), (const char**)tmp_array);
+   ERR("Selection set serial:%u, type:%s", data->sent_serial, mime_type);
 
-   if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
+   if (wdata->serial == data->sent_serial && !eina_streq(wdata->last_type, mime_type))
      {
-        offer = data->offer = wdata->external_offer;
+        bool type_exists = false;
+
+        Eina_List *l;
+        const char *type;
+        EINA_LIST_FOREACH(wdata->set_types, l, type)
+          {
+             if (eina_streq(type, mime_type))
+               {
+                  type_exists = true;
+                  break;
+               }
+          }
+
+        if (!type_exists)
+          {
+             wdata->set_types = eina_list_append(wdata->set_types, eina_stringshare_add(mime_type));
+             int type_count = eina_list_count(wdata->set_types);
+
+             const char* types[type_count + 1];
+             int index = 0;
+
+             Eina_List *list;
+             const char *type;
+             EINA_LIST_FOREACH(wdata->set_types, list, type)
+               {
+                  types[index] = type;
+                  ERR("Selection set multi types, serial:%u, type:%s", data->sent_serial, types[index]);
+                  index++;
+               }
+             types[type_count] = NULL;
+
+             data->sent_serial = ecore_wl2_dnd_selection_set(_fetch_input(ee, seat), types);
+          }
+        else
+          {
+             const char *type;
+             EINA_LIST_FREE(wdata->set_types, type)
+               eina_stringshare_del(type);
+             wdata->set_types = NULL;
+             wdata->set_types = eina_list_append(wdata->set_types, eina_stringshare_add(mime_type));
+          }
      }
-   else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
+   else
      {
-        offer = data->offer = ecore_wl2_dnd_selection_get(input);
+        const char *type;
+        EINA_LIST_FREE(wdata->set_types, type)
+          eina_stringshare_del(type);
+        wdata->set_types = NULL;
+        wdata->set_types = eina_list_append(wdata->set_types, eina_stringshare_add(mime_type));
      }
 
-   if (!offer)
-     {
-        eina_promise_reject(data->delivery, ecore_evas_no_selection);
-        data->delivery = NULL;
-     }
-   else
+   wdata->serial = data->sent_serial;
+   wdata->last_type = mime_type;
+
+   return EINA_TRUE;
+}
+
+
+static Eina_Future*
+_ecore_evas_wl_selection_request(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_types)
+{
+   if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
      {
-        Eina_Array *available_types = ecore_wl2_offer_mimes_get(offer);
-        char *selected_type = NULL;
+        Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data;
+        Ecore_Evas_Wl_Selection_Data *data = &wdata->selection_data[selection];
+        Ecore_Wl2_Input *input;
+        Ecore_Wl2_Offer *offer = NULL;
+        Eina_Future *future;
+
+        _reeval_seat(&seat, ee);
+        input = _fetch_input(ee, seat);
 
-        for (unsigned int i = 0; i < eina_array_count(available_types) && !selected_type; ++i)
+        if (data->delivery)
           {
-             char *available_type = eina_array_data_get(available_types, i);
-             for (unsigned int j = 0; j < eina_array_count(acceptable_types) && !selected_type; ++j)
-               {
-                  char *acceptable_type = eina_array_data_get(acceptable_types, j);
-                  if (eina_streq(acceptable_type, available_type))
-                    {
-                       selected_type = available_type;
-                       data->later_convert = NULL;
-                       break;
-                    }
+             eina_promise_reject(data->delivery, ecore_evas_request_replaced);
+             data->delivery = NULL;
+          }
+        data->delivery = efl_loop_promise_new(efl_main_loop_get());
+        future = eina_future_new(data->delivery);
+        offer = data->offer = wdata->external_offer;
+
+        if (!offer)
+          {
+             eina_promise_reject(data->delivery, ecore_evas_no_selection);
+             data->delivery = NULL;
+          }
+        else
+          {
+             Eina_Array *available_types = ecore_wl2_offer_mimes_get(offer);
+             char *selected_type = NULL;
 
-                  const char *convert_available_type;
-                  Eina_Iterator *convertions = eina_content_converter_possible_conversions(available_type);
-                  EINA_ITERATOR_FOREACH(convertions, convert_available_type)
+             for (unsigned int i = 0; i < eina_array_count(available_types) && !selected_type; ++i)
+               {
+                  char *available_type = eina_array_data_get(available_types, i);
+                  for (unsigned int j = 0; j < eina_array_count(acceptable_types) && !selected_type; ++j)
                     {
-                       if (eina_streq(convert_available_type, acceptable_type))
+                       char *acceptable_type = eina_array_data_get(acceptable_types, j);
+                       if (eina_streq(acceptable_type, available_type))
                          {
                             selected_type = available_type;
-                            data->later_convert = acceptable_type;
+                            data->later_convert = NULL;
+                            break;
+                         }
+
+                       const char *convert_available_type;
+                       Eina_Iterator *convertions = eina_content_converter_possible_conversions(available_type);
+                       EINA_ITERATOR_FOREACH(convertions, convert_available_type)
+                         {
+                            if (eina_streq(convert_available_type, acceptable_type))
+                              {
+                                 selected_type = available_type;
+                                 data->later_convert = acceptable_type;
+                              }
                          }
+                       eina_iterator_free(convertions);
                     }
-                  eina_iterator_free(convertions);
                }
-
+             if (selected_type)
+               {
+                  ecore_wl2_offer_receive(offer, selected_type);
+                  ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
+               }
+             else
+               {
+                  eina_promise_reject(data->delivery, ecore_evas_no_matching_type);
+                  data->delivery = NULL;
+               }
           }
-        if (selected_type)
+
+        return future;
+     }
+   else
+     {
+        Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data;
+        Ecore_Evas_Wl_Selection_Data *data;
+
+        Ecore_Wl2_Input *input;
+        Ecore_Wl2_Offer *offer = NULL;
+        Eina_Future *future;
+
+        _reeval_seat(&seat, ee);
+        input = _fetch_input(ee, seat);
+
+        offer = ecore_wl2_dnd_selection_get(input);
+        if (!offer)
           {
-             ecore_wl2_offer_receive(offer, selected_type);
-             ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
+             wdata->last_offer = NULL;
+             _clear_reserved_offer_receive_types(ee);
+             future = eina_future_new(NULL);
+             ERR("offer is null.");
           }
         else
           {
-             eina_promise_reject(data->delivery, ecore_evas_no_matching_type);
-             data->delivery = NULL;
+             Eina_Array *available_types = ecore_wl2_offer_mimes_get(offer);
+             char *selected_type = NULL;
+             char *later_convert = NULL;
+
+             for (unsigned int i = 0; i < eina_array_count(available_types) && !selected_type; ++i)
+               {
+                  char *available_type = eina_array_data_get(available_types, i);
+                  for (unsigned int j = 0; j < eina_array_count(acceptable_types) && !selected_type; ++j)
+                    {
+                       char *acceptable_type = eina_array_data_get(acceptable_types, j);
+                       if (eina_streq(acceptable_type, available_type))
+                         {
+                            selected_type = available_type;
+                            later_convert = NULL;
+                         }
+
+                       const char *convert_available_type;
+                       Eina_Iterator *convertions = eina_content_converter_possible_conversions(available_type);
+                       EINA_ITERATOR_FOREACH(convertions, convert_available_type)
+                         {
+                            if (eina_streq(convert_available_type, acceptable_type))
+                              {
+                                 selected_type = available_type;
+                                 later_convert = acceptable_type;
+                              }
+                         }
+                       eina_iterator_free(convertions);
+                    }
+               }
+
+             if (selected_type)
+               {
+                  Ecore_Evas_Selection_Cnp_Type cnp_type = _mime_type_to_cnp_type(selected_type);
+                  data = &wdata->selection_datas[cnp_type];
+                  if (data->delivery)
+                    {
+                       eina_promise_reject(data->delivery, ecore_evas_request_replaced);
+                       data->delivery = NULL;
+                    }
+
+                  ERR("Selection request, type:%s, index:%d", selected_type, cnp_type);
+
+                  data->delivery = efl_loop_promise_new(efl_main_loop_get());
+                  future = eina_future_new(data->delivery);
+
+                  data->offer = offer;
+                  data->later_convert = later_convert;
+
+                  if (wdata->last_offer == offer && wdata->last_delivery)
+                    {
+                       _reserve_offer_receive(ee, cnp_type);
+                       if (cnp_type == ECORE_EVAS_SELECTION_CNP_TYPE_IMAGE)
+                         wdata->reserved_image_type = selected_type;
+                    }
+                  else
+                    {
+                       ERR("Selection request offer receive, type:%s", selected_type);
+                       _clear_reserved_offer_receive_types(ee);
+                       ecore_wl2_offer_receive(offer, selected_type);
+                       ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
+                    }
+
+                  wdata->last_delivery = data->delivery;
+               }
+             else
+               {
+                  ERR("no matching type.");
+                  wdata->last_delivery = NULL;
+                  future = eina_future_new(NULL);
+               }
+
+             wdata->last_offer = offer;
           }
-      }
 
-   return future;
+       return future;
+   }
 }
 
 static Eina_Bool
@@ -3762,8 +4044,9 @@ _wl_interaction_send(void *data, int type EINA_UNUSED, void *event)
    Ecore_Evas_Wl_Selection_Data *selection = NULL;
    Delayed_Writing *forign_slice = calloc(1, sizeof(Delayed_Writing));
    Ecore_Evas_Selection_Buffer buffer = ECORE_EVAS_SELECTION_BUFFER_LAST;
+   Ecore_Evas_Selection_Cnp_Type cnp_type = _mime_type_to_cnp_type(ev->type);
 
-   if (ev->serial == wdata->selection_data[ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER].sent_serial)
+   if (ev->serial == wdata->selection_datas[cnp_type].sent_serial)
      buffer = ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER;
    else if (ev->serial == wdata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].sent_serial)
      {
@@ -3777,10 +4060,20 @@ _wl_interaction_send(void *data, int type EINA_UNUSED, void *event)
         goto end;
      }
 
-   selection = &wdata->selection_data[buffer];
+   if (buffer == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
+     {
+        selection = &wdata->selection_datas[cnp_type];
+     }
+   else if (buffer == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
+     {
+        selection = &wdata->selection_data[buffer];
+     }
+
    EINA_SAFETY_ON_NULL_GOTO(selection, end);
    EINA_SAFETY_ON_NULL_GOTO(selection->callbacks.delivery, end);
    EINA_SAFETY_ON_FALSE_GOTO(selection->callbacks.delivery(ee, ev->seat, buffer, ev->type, &forign_slice->slice), end);
+
+   ERR("Send data, type:%s", ev->type);
    ecore_main_fd_handler_add(ev->fd, ECORE_FD_WRITE, _write_to_fd, forign_slice, NULL, NULL);
 
    return ECORE_CALLBACK_PASS_ON;
@@ -3797,28 +4090,55 @@ _wl_selection_receive(void *data, int type EINA_UNUSED, void *event)
    Ecore_Evas_Engine_Wl_Data *wdata = ee->engine.data;
    Ecore_Wl2_Event_Offer_Data_Ready *ready = event;
    Ecore_Evas_Selection_Buffer selection = ECORE_EVAS_SELECTION_BUFFER_LAST;
+   Ecore_Evas_Selection_Cnp_Type cnp_type = ECORE_EVAS_SELECTION_CNP_TYPE_LAST;
 
    if ((!ready->data) || (ready->len < 1))
      {
         ERR("no selection data");
         return ECORE_CALLBACK_PASS_ON;
      }
+
+   bool need_break = false;
    for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i)
      {
-        if (wdata->selection_data[i].offer == ready->offer)
+        if (i == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
           {
-             selection = i;
-             break;
+             if (wdata->selection_data[i].offer == ready->offer)
+               {
+                  selection = i;
+                  break;
+               }
           }
+        else
+          {
+             for (int j = 0 ; j < ECORE_EVAS_SELECTION_CNP_TYPE_LAST; ++j)
+               {
+                  if (wdata->selection_datas[j].offer == ready->offer && j == (int)_mime_type_to_cnp_type(ready->mimetype))
+                    {
+                       selection = ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER;
+                       cnp_type = j;
+                       need_break = true;
+                       break;
+                    }
+               }
+          }
+
+        if (need_break)
+          break;
      }
 
    if (selection == ECORE_EVAS_SELECTION_BUFFER_LAST)
      return ECORE_CALLBACK_PASS_ON;
 
+   if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER && cnp_type == ECORE_EVAS_SELECTION_CNP_TYPE_LAST)
+     return ECORE_CALLBACK_PASS_ON;
+
+   ERR("Receive data, type:%s, data:%s", ready->mimetype, (char*)ready->data);
+
    //Now deliver the content
    Eina_Slice slice;
 
-   if (eina_str_has_prefix(ready->mimetype,"text"))
+   if (eina_str_has_prefix(ready->mimetype, "text"))
      {
         //ensure that we always have a \0 at the end, there is no assertion that \0 is included here.
         slice.len = ready->len + 1;
@@ -3832,18 +4152,55 @@ _wl_selection_receive(void *data, int type EINA_UNUSED, void *event)
 
    Eina_Content *content = eina_content_new(slice, ready->mimetype);
 
-   if (wdata->selection_data[selection].later_convert)
+   Ecore_Evas_Wl_Selection_Data *selection_data;
+   if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
      {
-        Eina_Content *tmp = eina_content_convert(content, wdata->selection_data[selection].later_convert);
-        wdata->selection_data[selection].later_convert = NULL;
+        selection_data = &wdata->selection_data[selection];
+     }
+   else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
+     {
+        selection_data = &wdata->selection_datas[cnp_type];
+     }
+
+   if (selection_data->later_convert)
+     {
+        Eina_Content *tmp = eina_content_convert(content, selection_data->later_convert);
+        selection_data->later_convert = NULL;
         eina_content_free(content);
         content = tmp;
      }
 
-   eina_promise_resolve(wdata->selection_data[selection].delivery, eina_value_content_init(content));
-   wdata->selection_data[selection].delivery = NULL;
+   INF("Receive data resolve, type:%s", eina_content_type_get(content));
+   eina_promise_resolve(selection_data->delivery, eina_value_content_init(content));
+   selection_data->delivery = NULL;
+
+   if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
+     wdata->last_delivery = NULL;
+
    eina_content_free(content);
 
+   if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
+     {
+        Ecore_Evas_Selection_Cnp_Type reserved_cnp_type = _get_reserved_offer_receive_type(ee);
+
+        if (reserved_cnp_type < ECORE_EVAS_SELECTION_CNP_TYPE_LAST)
+          {
+             char* reserved_type = _cnp_type_to_mime_type(reserved_cnp_type);
+             if (reserved_cnp_type == ECORE_EVAS_SELECTION_CNP_TYPE_IMAGE)
+               reserved_type = wdata->reserved_image_type;
+
+             if (reserved_type)
+               {
+                  Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
+                  Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display);
+
+                  ERR("Selection request offer receive, type:%s", reserved_type);
+                  ecore_wl2_offer_receive(ready->offer, reserved_type);
+                  ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
+               }
+          }
+     }
+
    return ECORE_CALLBACK_PASS_ON;
 }
 
@@ -3984,6 +4341,21 @@ _ecore_evas_wl_selection_init(Ecore_Evas *ee)
         wdata->selection_data[i].callbacks.delivery = NULL;
         wdata->selection_data[i].callbacks.cancel = NULL;
      }
+
+   for (int i = 0; i < ECORE_EVAS_SELECTION_CNP_TYPE_LAST; ++i)
+     {
+        wdata->selection_datas[i].callbacks.available_types = NULL;
+        wdata->selection_datas[i].callbacks.delivery = NULL;
+        wdata->selection_datas[i].callbacks.cancel = NULL;
+        wdata->reserved_types[i] = EINA_FALSE;
+     }
+
+   wdata->serial = UINT32_MAX;
+   wdata->last_type = NULL;
+   wdata->set_types = NULL;
+   wdata->last_offer = NULL;
+   wdata->last_delivery = NULL;
+   wdata->reserved_image_type = NULL;
 }
 
 static Eina_Bool
@@ -4010,7 +4382,7 @@ _ecore_evas_wl_dnd_start(Ecore_Evas *ee, unsigned int seat, Eina_Array *availabl
 static Eina_Bool
 _ecore_evas_wl_dnd_stop(Ecore_Evas *ee, unsigned int seat)
 {
-   _clear_selection(ee, seat, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER);
+   _clear_selection(ee, seat, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, NULL);
    _reeval_seat(&seat, ee);
    ecore_wl2_dnd_drag_end(_fetch_input(ee, seat));
    return EINA_TRUE;
index 37d3fa1..c3dc0c5 100644 (file)
@@ -61,6 +61,15 @@ struct _Ecore_Evas_Engine_Wl_Data
    Eina_List *tz_devices_list;
    //
 
+   // Support multi-type copy and paste
+   uint32_t serial;
+   char *last_type;
+   Eina_List *set_types;
+   Ecore_Wl2_Offer *last_offer;
+   Eina_Promise *last_delivery;
+   Eina_Bool reserved_types[ECORE_EVAS_SELECTION_CNP_TYPE_LAST];
+   char *reserved_image_type;
+
    //TIZEN_ONLY(20171115): support output transform
    Ecore_Event_Handler *output_transform_hdl;
    short output_rotation;
@@ -69,6 +78,8 @@ struct _Ecore_Evas_Engine_Wl_Data
    Ecore_Job *resize_job;
 
    Ecore_Evas_Wl_Selection_Data selection_data[ECORE_EVAS_SELECTION_BUFFER_LAST];
+   Ecore_Evas_Wl_Selection_Data selection_datas[ECORE_EVAS_SELECTION_CNP_TYPE_LAST];
+
    Ecore_Wl2_Offer *external_offer;
    struct
      {