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