1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #include <Elementary.h>
6 #include <Ecore_Evas.h>
7 
8 #include "elm_priv.h"
9 #include "elm_entry_eo.h"
10 
11 static inline Ecore_Evas_Selection_Buffer
_elm_sel_type_to_ee_type(Elm_Sel_Type type)12 _elm_sel_type_to_ee_type(Elm_Sel_Type type)
13 {
14    if (type == ELM_SEL_TYPE_PRIMARY)
15      return ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER;
16    if (type == ELM_SEL_TYPE_XDND)
17      return ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER;
18    if (type == ELM_SEL_TYPE_CLIPBOARD)
19      return ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER;
20    return ECORE_EVAS_SELECTION_BUFFER_LAST;
21 }
22 
23 static inline Eina_Array*
_elm_sel_format_to_mime_type(Elm_Sel_Format format)24 _elm_sel_format_to_mime_type(Elm_Sel_Format format)
25 {
26    Eina_Array *ret = eina_array_new(10);
27    if (format & ELM_SEL_FORMAT_TEXT)
28      eina_array_push(ret, "text/plain;charset=utf-8");
29    if (format & ELM_SEL_FORMAT_MARKUP)
30       eina_array_push(ret, "application/x-elementary-markup");
31    if (format & ELM_SEL_FORMAT_IMAGE)
32      {
33         eina_array_push(ret, "image/png");
34         eina_array_push(ret, "image/jpeg");
35         eina_array_push(ret, "image/x-ms-bmp");
36         eina_array_push(ret, "image/gif");
37         eina_array_push(ret, "image/tiff");
38         eina_array_push(ret, "image/svg+xml");
39         eina_array_push(ret, "image/x-xpixmap");
40         eina_array_push(ret, "image/x-tga");
41         eina_array_push(ret, "image/x-portable-pixmap");
42      }
43    if (format & ELM_SEL_FORMAT_VCARD)
44      eina_array_push(ret, "text/vcard");
45    if (format & ELM_SEL_FORMAT_HTML)
46      eina_array_push(ret, "application/xhtml+xml");
47 
48    if (eina_array_count(ret) == 0)
49      ERR("Specified mime type is not available");
50 
51    return ret;
52 }
53 
54 typedef struct {
55   const unsigned char image_sequence[16];
56   const size_t image_sequence_len;
57   const char *mimetype;
58 } Mimetype_Content_Matcher;
59 
60 static const Mimetype_Content_Matcher matchers[] = {
61   {{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}, 8, "image/png"},
62   {{0xFF, 0xD8}, 2, "image/jpeg"},
63   {{0x42, 0x4D}, 2, "image/x-ms-bmp"},
64   {{0x47, 0x49, 0x46, 0x38, 0x37, 0x61}, 6, "image/gif"},
65   {{0x47, 0x49, 0x46, 0x38, 0x39, 0x61}, 6, "image/gif"},
66   {{0x49, 0x49, 0x2A, 00}, 4, "image/tiff"},
67   {{0x49, 0x4D, 0x00, 0x2A}, 4, "image/tiff"},
68   {{0},0, NULL}
69 };
70 
71 static inline Eina_Array*
_elm_sel_from_content_to_mime_type(const void * buf,size_t buflen)72 _elm_sel_from_content_to_mime_type(const void *buf, size_t buflen)
73 {
74    Eina_Array *ret = eina_array_new(10);
75 
76    for (int i = 0; matchers[i].mimetype && eina_array_count(ret) == 0; ++i)
77      {
78         if (matchers[i].image_sequence_len >= buflen) continue;
79         for (size_t j = 0; j < matchers[i].image_sequence_len; ++j)
80           {
81              if (((const unsigned  char*)buf)[j] == matchers[i].image_sequence[j])
82                {
83                   eina_array_push(ret, matchers[i].mimetype);
84                   break;
85                }
86           }
87      }
88 
89    if (eina_array_count(ret) != 1)
90      ERR("Specified mime type is not available");
91 
92    return ret;
93 }
94 
95 static inline Elm_Sel_Format
_mime_type_to_elm_sel_format(const char * mime_type)96 _mime_type_to_elm_sel_format(const char *mime_type)
97 {
98    if (eina_streq(mime_type, "text/vcard"))
99      return ELM_SEL_FORMAT_VCARD;
100    else if (eina_streq(mime_type, "application/x-elementary-markup"))
101      return ELM_SEL_FORMAT_MARKUP;
102    else if (eina_streq(mime_type, "application/xhtml+xml"))
103      return ELM_SEL_FORMAT_HTML;
104    else if (!strncmp(mime_type, "text/", strlen("text/")))
105      return ELM_SEL_FORMAT_TEXT;
106    else if (!strncmp(mime_type, "image/", strlen("image/")))
107      return ELM_SEL_FORMAT_IMAGE;
108 
109    return ELM_SEL_FORMAT_NONE;
110 }
111 
112 static int
_default_seat(const Eo * obj)113 _default_seat(const Eo *obj)
114 {
115    return evas_device_seat_id_get(evas_default_device_get(evas_object_evas_get(obj), EVAS_DEVICE_CLASS_SEAT));
116 }
117 
118 EAPI Eina_Bool
elm_cnp_selection_set(Evas_Object * obj,Elm_Sel_Type selection,Elm_Sel_Format format,const void * buf,size_t buflen)119 elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection,
120                                      Elm_Sel_Format format,
121                                      const void *buf, size_t buflen)
122 {
123    Eina_Content *content;
124    Ecore_Evas *ee;
125    const char *mime_type;
126    Eina_Slice data;
127    Eina_Array *tmp;
128    unsigned char *mem_buf = NULL;
129 
130    if (format == ELM_SEL_FORMAT_TEXT && ((char*)buf)[buflen - 1] != '\0')
131      {
132         mem_buf = eina_memdup((unsigned char *)buf, buflen, EINA_TRUE);
133         data.mem = mem_buf;
134         data.len = buflen + 1;
135      }
136    else
137      {
138         data.mem = buf;
139         data.len = buflen;
140      }
141 
142    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
143 
144    if (format == ELM_SEL_FORMAT_IMAGE)
145      {
146         tmp = _elm_sel_from_content_to_mime_type(buf, buflen);
147      }
148    else
149      {
150         tmp = _elm_sel_format_to_mime_type(format);
151      }
152 
153 
154    if (eina_array_count(tmp) != 1)
155      {
156         ERR("You cannot specify more than one format when setting selection");
157      }
158    mime_type = eina_array_data_get(tmp, 0);
159    eina_array_free(tmp);
160    content = eina_content_new(data, mime_type);
161    _register_selection_changed(obj);
162 
163    if (mem_buf != NULL)
164      free(mem_buf);
165 
166    return ecore_evas_selection_set(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), content);
167 }
168 
169 EAPI Eina_Bool
elm_object_cnp_selection_clear(Evas_Object * obj,Elm_Sel_Type selection)170 elm_object_cnp_selection_clear(Evas_Object *obj,
171                                               Elm_Sel_Type selection)
172 {
173    Ecore_Evas *ee;
174 
175    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
176    return ecore_evas_selection_set(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), NULL);
177 }
178 
179 EAPI Eina_Bool
elm_cnp_clipboard_selection_has_owner(Evas_Object * obj)180 elm_cnp_clipboard_selection_has_owner(Evas_Object *obj)
181 {
182    Ecore_Evas *ee;
183 
184    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
185    return ecore_evas_selection_exists(ee, _default_seat(obj), ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER);
186 
187 }
188 
189 typedef struct _Sel_Lost_Data Sel_Lost_Data;
190 struct _Sel_Lost_Data
191 {
192    const Evas_Object *obj;
193    Elm_Sel_Type type;
194    void *udata;
195    Elm_Selection_Loss_Cb loss_cb;
196 };
197 
198 static void
_selection_changed_cb(void * data,const Efl_Event * ev)199 _selection_changed_cb(void *data, const Efl_Event *ev)
200 {
201    Sel_Lost_Data *ldata = data;
202    Efl_Ui_Wm_Selection_Changed *changed = ev->info;
203 
204    if (changed->buffer == EFL_UI_CNP_BUFFER_SELECTION && ldata->type != ELM_SEL_TYPE_PRIMARY)
205      return;
206 
207    if (changed->buffer == EFL_UI_CNP_BUFFER_COPY_AND_PASTE && ldata->type != ELM_SEL_TYPE_CLIPBOARD)
208      return;
209 
210    if (ldata->obj == changed->caused_by)
211      return;
212 
213    ldata->loss_cb(ldata->udata, ldata->type);
214    efl_event_callback_del(ev->object, ev->desc, _selection_changed_cb, data);
215    free(data);
216 }
217 
218 EAPI void
elm_cnp_selection_loss_callback_set(Evas_Object * obj,Elm_Sel_Type type,Elm_Selection_Loss_Cb func,const void * data)219 elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type type, Elm_Selection_Loss_Cb func, const void *data)
220 {
221    Sel_Lost_Data *ldata = calloc(1, sizeof(Sel_Lost_Data));
222 
223    if (!ldata) return;
224    ldata->obj = obj;
225    ldata->type = type;
226    ldata->udata = (void *)data;
227    ldata->loss_cb = func;
228    efl_event_callback_add(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, _selection_changed_cb, ldata);
229 }
230 
231 typedef struct {
232    Elm_Drop_Cb data_cb;
233    void *data;
234    Elm_Sel_Format format;
235 } Callback_Storage;
236 
237 static Eina_Value
_callback_storage_deliver(Eo * obj,void * data,const Eina_Value value)238 _callback_storage_deliver(Eo *obj, void *data, const Eina_Value value)
239 {
240    Callback_Storage *cb_storage = data;
241    Eina_Content *content = eina_value_to_content(&value);
242    Elm_Sel_Format format = _mime_type_to_elm_sel_format(eina_content_type_get(content));
243    Eina_Slice cdata;
244 
245    cdata = eina_content_data_get(content);
246    Elm_Selection_Data d = { 0 };
247    d.data = eina_memdup((unsigned char*)cdata.bytes, cdata.len, EINA_FALSE);
248    d.len = cdata.len;
249    d.format = _mime_type_to_elm_sel_format(eina_content_type_get(content));
250 
251    if (cb_storage->data_cb)
252      {
253         cb_storage->data_cb(cb_storage->data, obj, &d);
254      }
255    else
256      {
257         EINA_SAFETY_ON_FALSE_GOTO(format == ELM_SEL_FORMAT_TEXT || format == ELM_SEL_FORMAT_MARKUP || format == ELM_SEL_FORMAT_HTML, end);
258 
259         _elm_entry_entry_paste(obj, (const char *) d.data);
260      }
261 
262 end:
263    free(d.data);
264 
265    return EINA_VALUE_EMPTY;
266 }
267 
268 static Eina_Value
_callback_storage_error(Eo * obj EINA_UNUSED,void * data EINA_UNUSED,Eina_Error error)269 _callback_storage_error(Eo *obj EINA_UNUSED, void *data EINA_UNUSED, Eina_Error error)
270 {
271    ERR("Content cound not be received because of %s.", eina_error_msg_get(error));
272    return EINA_VALUE_EMPTY;
273 }
274 
275 static void
_callback_storage_free(Eo * obj EINA_UNUSED,void * data,const Eina_Future * dead_future EINA_UNUSED)276 _callback_storage_free(Eo *obj EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
277 {
278    free(data);
279 }
280 
281 EAPI Eina_Bool
elm_cnp_selection_get(const Evas_Object * obj,Elm_Sel_Type selection,Elm_Sel_Format format,Elm_Drop_Cb data_cb,void * udata)282 elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type selection,
283                                      Elm_Sel_Format format,
284                                      Elm_Drop_Cb data_cb, void *udata)
285 {
286    Ecore_Evas *ee;
287    Eina_Array *mime_types;
288    Eina_Future *future;
289    Callback_Storage *storage;
290 
291    ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
292    mime_types = _elm_sel_format_to_mime_type(format);
293    future = ecore_evas_selection_get(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), eina_array_iterator_new(mime_types));
294    storage = calloc(1,sizeof(Callback_Storage));
295    storage->data_cb = data_cb;
296    storage->data = udata;
297    storage->format = format;
298 
299    efl_future_then(obj, future, _callback_storage_deliver, _callback_storage_error, _callback_storage_free, EINA_VALUE_TYPE_CONTENT, storage);
300 
301    return EINA_TRUE;
302 }
303