2 # include "elementary_config.h"
4 #include <Elementary.h>
15 CNP_ATOM_LISTING_ATOMS = CNP_ATOM_ATOM,
17 CNP_ATOM_text_urilist,
18 CNP_ATOM_text_x_vcard,
29 // CNP_ATOM_text_html_utf8,
30 // CNP_ATOM_text_html,
33 CNP_ATOM_COMPOUND_TEXT,
35 CNP_ATOM_text_plain_utf8,
41 typedef struct _Tmp_Info Tmp_Info;
42 typedef struct _Saved_Type Saved_Type;
43 typedef struct _Cnp_Escape Cnp_Escape;
44 typedef struct _Dropable Dropable;
72 /* FIXME: Cache window */
78 static int _elm_cnp_init_count = 0;
79 /* Stringshared, so I can just compare pointers later */
80 static const char *text_uri;
81 /* Data for DND in progress */
82 static Saved_Type savedtypes = { NULL, NULL, 0, 0, 0, EINA_FALSE };
84 /* TODO BUG: should NEVER have these as globals! They should be per context (window). */
85 static void (*dragdonecb) (void *data, Evas_Object *obj) = NULL;
86 static void *dragdonedata = NULL;
88 /* Drag & Drop functions */
89 /* FIXME: Way too many globals */
90 static Eina_List *drops = NULL;
91 static Evas_Object *dragwin = NULL;
92 static int _dragx = 0, _dragy = 0;
93 static Ecore_Event_Handler *handler_pos = NULL;
94 static Ecore_Event_Handler *handler_drop = NULL;
95 static Ecore_Event_Handler *handler_enter = NULL;
96 static Ecore_Event_Handler *handler_status = NULL;
98 static Tmp_Info *_tempfile_new (int size);
99 static int _tmpinfo_free (Tmp_Info *tmp);
100 static Eina_Bool _pasteimage_append (char *file, Evas_Object *entry);
101 static void _entry_insert_filter(Evas_Object *entry, char *str); // TIZEN ONLY
105 # define cnp_debug(x...) fprintf(stderr, __FILE__": " x)
107 # define cnp_debug(x...) do { } while (0)
110 // x11 specific stuff
111 ////////////////////////////////////////////////////////////////////////////
112 #ifdef HAVE_ELEMENTARY_X
113 #define ARRAYINIT(foo) [foo] =
115 typedef struct _X11_Cnp_Selection X11_Cnp_Selection;
116 typedef struct _X11_Cnp_Atom X11_Cnp_Atom;
118 typedef Eina_Bool (*X11_Converter_Fn_Cb) (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
119 typedef int (*X11_Response_Handler_Cb) (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
120 typedef int (*X11_Notify_Handler_Cb) (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
122 struct _X11_Cnp_Selection
127 Evas_Object *requestwidget;
129 Elm_Sel_Format requestformat;
131 Eina_Bool (*set) (Ecore_X_Window, const void *data, int size);
132 Eina_Bool (*clear) (void);
133 void (*request) (Ecore_X_Window, const char *target);
134 Elm_Selection_Loss_Cb loss_cb;
137 Elm_Sel_Format format;
138 Ecore_X_Selection ecore_sel;
141 Eina_Bool active : 1;
147 Elm_Sel_Format formats;
148 /* Called by ecore to do conversion */
149 X11_Converter_Fn_Cb converter;
150 X11_Response_Handler_Cb response;
151 X11_Notify_Handler_Cb notify;
156 static void _x11_sel_obj_del (void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
157 static void _x11_sel_obj_del2 (void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
158 static Eina_Bool _x11_selection_clear (void *udata __UNUSED__, int type, void *event);
159 static Eina_Bool _x11_selection_notify (void *udata __UNUSED__, int type, void *event);
160 static Eina_Bool _x11_targets_converter (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
161 static Eina_Bool _x11_text_converter (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
162 static Eina_Bool _x11_general_converter (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
163 static Eina_Bool _x11_image_converter (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
164 static Eina_Bool _x11_vcard_send (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
165 //TIZEN ONLY : static Eina_Bool _x11_is_uri_type_data (X11_Cnp_Selection *sel __UNUSED__, Ecore_X_Event_Selection_Notify *notify);
166 static int _x11_response_handler_targets (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
167 static int _x11_notify_handler_targets (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
168 static int _x11_notify_handler_text (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
169 static int _x11_notify_handler_image (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
170 static int _x11_notify_handler_uri (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
171 //static int _x11_notify_handler_html (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
172 static int _x11_notify_handler_edje (X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify); // TIZEN ONLY
173 static int _x11_vcard_receive (X11_Cnp_Selection *sed, Ecore_X_Event_Selection_Notify *notify);
174 static Eina_Bool _x11_dnd_enter (void *data __UNUSED__, int etype __UNUSED__, void *ev);
175 static Eina_Bool _x11_dnd_drop (void *data __UNUSED__, int etype __UNUSED__, void *ev);
176 static Eina_Bool _x11_dnd_position (void *data __UNUSED__, int etype __UNUSED__, void *ev);
177 static Eina_Bool _x11_dnd_status (void *data __UNUSED__, int etype __UNUSED__, void *ev);
178 static void _x11_drag_mouse_up (void *un __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *data);
179 static void _x11_drag_move (void *data __UNUSED__, Ecore_X_Xdnd_Position *pos);
181 static Ecore_X_Window _x11_elm_widget_xwin_get (const Evas_Object *obj);
183 static Eina_Bool _x11_elm_cnp_init (void);
184 static Eina_Bool _x11_elm_cnp_selection_set (Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, const void *selbuf, size_t buflen);
185 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);
186 static Eina_Bool _x11_elm_object_cnp_selection_clear (Evas_Object *obj, Elm_Sel_Type selection);
187 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);
188 static Eina_Bool _x11_elm_drop_target_add (Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, void *cbdata);
189 static Eina_Bool _x11_elm_drop_target_del (Evas_Object *obj);
190 static Eina_Bool _x11_elm_selection_selection_has_owner (Evas_Object *obj __UNUSED__);
192 static X11_Cnp_Atom _x11_atoms[CNP_N_ATOMS] = {
193 [CNP_ATOM_TARGETS] = {
195 ELM_SEL_FORMAT_TARGETS,
196 _x11_targets_converter,
197 _x11_response_handler_targets,
198 _x11_notify_handler_targets,
202 "ATOM", // for opera browser
203 ELM_SEL_FORMAT_TARGETS,
204 _x11_targets_converter,
205 _x11_response_handler_targets,
206 _x11_notify_handler_targets,
210 "application/x-elementary-markup",
211 ELM_SEL_FORMAT_MARKUP,
212 _x11_general_converter,
214 //NULL, // TIZEN ONLY
215 _x11_notify_handler_edje, // TIZEN ONLY
218 [CNP_ATOM_text_uri] = {
220 //ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE, /* Either images or entries */ // TIZEN ONLY
221 ELM_SEL_FORMAT_IMAGE, // TIZEN ONLY
222 _x11_general_converter,
224 _x11_notify_handler_uri,
227 [CNP_ATOM_text_urilist] = {
229 ELM_SEL_FORMAT_IMAGE,
230 _x11_general_converter,
232 _x11_notify_handler_uri,
235 [CNP_ATOM_text_x_vcard] = {
237 ELM_SEL_FORMAT_VCARD,
238 _x11_vcard_send, NULL,
239 _x11_vcard_receive, 0
241 [CNP_ATOM_image_png] = {
243 ELM_SEL_FORMAT_IMAGE,
244 _x11_image_converter,
246 _x11_notify_handler_image,
249 [CNP_ATOM_image_jpeg] = {
251 ELM_SEL_FORMAT_IMAGE,
252 _x11_image_converter,
254 _x11_notify_handler_image,/* Raw image data is the same */
257 [CNP_ATOM_image_bmp] = {
259 ELM_SEL_FORMAT_IMAGE,
260 _x11_image_converter,
262 _x11_notify_handler_image,/* Raw image data is the same */
265 [CNP_ATOM_image_gif] = {
267 ELM_SEL_FORMAT_IMAGE,
268 _x11_image_converter,
270 _x11_notify_handler_image,/* Raw image data is the same */
273 [CNP_ATOM_image_tiff] = {
275 ELM_SEL_FORMAT_IMAGE,
276 _x11_image_converter,
278 _x11_notify_handler_image,/* Raw image data is the same */
281 [CNP_ATOM_image_svg] = {
283 ELM_SEL_FORMAT_IMAGE,
284 _x11_image_converter,
286 _x11_notify_handler_image,/* Raw image data is the same */
289 [CNP_ATOM_image_xpm] = {
291 ELM_SEL_FORMAT_IMAGE,
292 _x11_image_converter,
294 _x11_notify_handler_image,/* Raw image data is the same */
297 [CNP_ATOM_image_tga] = {
299 ELM_SEL_FORMAT_IMAGE,
300 _x11_image_converter,
302 _x11_notify_handler_image,/* Raw image data is the same */
305 [CNP_ATOM_image_ppm] = {
306 "image/x-portable-pixmap",
307 ELM_SEL_FORMAT_IMAGE,
308 _x11_image_converter,
310 _x11_notify_handler_image,/* Raw image data is the same */
314 [CNP_ATOM_text_html_utf8] = {
315 "text/html;charset=utf-8",
317 _x11_general_converter,
319 _x11_notify_handler_html,
322 [CNP_ATOM_text_html] = {
325 _x11_general_converter,
327 _x11_notify_handler_html, // No encoding: Webkit only
331 [CNP_ATOM_UTF8STRING] = {
333 ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
336 _x11_notify_handler_text,
339 [CNP_ATOM_STRING] = {
341 ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
344 _x11_notify_handler_text,
347 [CNP_ATOM_COMPOUND_TEXT] = {
349 ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
357 ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
363 [CNP_ATOM_text_plain_utf8] = {
364 "text/plain;charset=utf-8",
365 ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
371 [CNP_ATOM_text_plain] = {
373 ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
381 static X11_Cnp_Selection _x11_selections[ELM_SEL_TYPE_CLIPBOARD + 1] = {
382 ARRAYINIT(ELM_SEL_TYPE_PRIMARY) {
384 .ecore_sel = ECORE_X_SELECTION_PRIMARY,
385 .set = ecore_x_selection_primary_set,
386 .clear = ecore_x_selection_primary_clear,
387 .request = ecore_x_selection_primary_request,
389 ARRAYINIT(ELM_SEL_TYPE_SECONDARY) {
390 .debug = "Secondary",
391 .ecore_sel = ECORE_X_SELECTION_SECONDARY,
392 .set = ecore_x_selection_secondary_set,
393 .clear = ecore_x_selection_secondary_clear,
394 .request = ecore_x_selection_secondary_request,
396 ARRAYINIT(ELM_SEL_TYPE_XDND) {
398 .ecore_sel = ECORE_X_SELECTION_XDND,
399 .request = ecore_x_selection_xdnd_request,
401 ARRAYINIT(ELM_SEL_TYPE_CLIPBOARD) {
402 .debug = "Clipboard",
403 .ecore_sel = ECORE_X_SELECTION_CLIPBOARD,
404 .set = ecore_x_selection_clipboard_set,
405 .clear = ecore_x_selection_clipboard_clear,
406 .request = ecore_x_selection_clipboard_request,
411 _x11_sel_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
413 X11_Cnp_Selection *sel = data;
414 if (sel->widget == obj) sel->widget = NULL;
418 _x11_sel_obj_del2(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
420 X11_Cnp_Selection *sel = data;
421 if (sel->requestwidget == obj) sel->requestwidget = NULL;
425 _x11_selection_clear(void *udata __UNUSED__, int type __UNUSED__, void *event)
427 Ecore_X_Event_Selection_Clear *ev = event;
428 X11_Cnp_Selection *sel;
432 for (i = ELM_SEL_TYPE_PRIMARY; i <= ELM_SEL_TYPE_CLIPBOARD; i++)
434 if (_x11_selections[i].ecore_sel == ev->selection) break;
436 cnp_debug("selection %d clear\n", i);
437 /* Not me... Don't care */
438 if (i > ELM_SEL_TYPE_CLIPBOARD) return ECORE_CALLBACK_PASS_ON;
440 sel = _x11_selections + i;
441 if (sel->loss_cb) sel->loss_cb(sel->loss_data, i);
443 evas_object_event_callback_del_full(sel->widget, EVAS_CALLBACK_DEL,
444 _x11_sel_obj_del, sel);
445 if (sel->requestwidget)
446 evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
447 _x11_sel_obj_del2, sel);
449 sel->requestwidget = NULL;
451 sel->active = EINA_FALSE;
458 return ECORE_CALLBACK_PASS_ON;
462 * Response to a selection notify:
463 * - So we have asked for the selection list.
464 * - If it's the targets list, parse it, and fire of what we want,
465 * else it's the data we want.
468 _x11_selection_notify(void *udata __UNUSED__, int type __UNUSED__, void *event)
470 Ecore_X_Event_Selection_Notify *ev = event;
471 X11_Cnp_Selection *sel;
474 cnp_debug("selection notify callback: %d\n",ev->selection);
475 switch (ev->selection)
477 case ECORE_X_SELECTION_PRIMARY:
478 sel = _x11_selections + ELM_SEL_TYPE_PRIMARY;
480 case ECORE_X_SELECTION_SECONDARY:
481 sel = _x11_selections + ELM_SEL_TYPE_SECONDARY;
483 case ECORE_X_SELECTION_XDND:
484 sel = _x11_selections + ELM_SEL_TYPE_XDND;
486 case ECORE_X_SELECTION_CLIPBOARD:
487 sel = _x11_selections + ELM_SEL_TYPE_CLIPBOARD;
490 return ECORE_CALLBACK_PASS_ON;
492 cnp_debug("Target is %s\n", ev->target);
494 for (i = 0; i < CNP_N_ATOMS; i++)
496 if (!strcmp(ev->target, _x11_atoms[i].name))
498 if (_x11_atoms[i].notify)
500 cnp_debug("Found something: %s\n", _x11_atoms[i].name);
501 _x11_atoms[i].notify(sel, ev);
503 else cnp_debug("Ignored: No handler!\n");
506 return ECORE_CALLBACK_PASS_ON;
509 static Elm_Sel_Format
510 _get_selection_type(void *data, int size)
512 if (size == sizeof(Elm_Sel_Type))
514 unsigned int seltype = *((unsigned int *)data);
515 if (seltype > ELM_SEL_TYPE_CLIPBOARD)
516 return ELM_SEL_FORMAT_NONE;
517 X11_Cnp_Selection *sel = _x11_selections + seltype;
519 (sel->format >= ELM_SEL_FORMAT_TARGETS) &&
520 (sel->format <= ELM_SEL_FORMAT_HTML))
523 return ELM_SEL_FORMAT_NONE;
527 _x11_targets_converter(char *target __UNUSED__, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
531 X11_Cnp_Selection *sel;
532 Elm_Sel_Format seltype;
534 if (!data_ret) return EINA_FALSE;
535 if (_get_selection_type(data, size) == ELM_SEL_FORMAT_NONE)
537 /* TODO : fallback into precise type */
538 seltype = ELM_SEL_FORMAT_TEXT;
542 sel = _x11_selections + *((int *)data);
543 seltype = sel->format;
546 for (i = 0, count = 0; i < CNP_N_ATOMS ; i++)
548 if (seltype & _x11_atoms[i].formats) count++;
550 aret = malloc(sizeof(Ecore_X_Atom) * count);
551 if (!aret) return EINA_FALSE;
552 for (i = 0, count = 0; i < CNP_N_ATOMS; i++)
554 if (seltype & _x11_atoms[i].formats)
555 aret[count ++] = _x11_atoms[i].atom;
559 if (typesize) *typesize = 32 /* urk */;
560 if (ttype) *ttype = ECORE_X_ATOM_ATOM;
561 if (size_ret) *size_ret = count;
566 _x11_image_converter(char *target __UNUSED__, void *data __UNUSED__, int size __UNUSED__, void **data_ret __UNUSED__, int *size_ret __UNUSED__, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
568 cnp_debug("Image converter called\n");
573 _x11_vcard_send(char *target __UNUSED__, void *data __UNUSED__, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
575 X11_Cnp_Selection *sel;
577 cnp_debug("Vcard send called\n");
578 sel = _x11_selections + *((int *)data);
579 if (data_ret) *data_ret = strdup(sel->selbuf);
580 if (size_ret) *size_ret = strlen(sel->selbuf);
587 _x11_is_uri_type_data(X11_Cnp_Selection *sel __UNUSED__, Ecore_X_Event_Selection_Notify *notify)
589 Ecore_X_Selection_Data *data;
593 cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
594 if (data->content == ECORE_X_SELECTION_CONTENT_FILES) return EINA_TRUE;
595 p = (char *)data->data;
596 if (!p) return EINA_TRUE;
597 cnp_debug("Got %s\n", p);
598 if (strncmp(p, "file://", 7))
600 if (*p != '/') return EINA_FALSE;
608 * Callback to handle a targets response on a selection request:
609 * So pick the format we'd like; and then request it.
612 _x11_notify_handler_targets(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
614 Ecore_X_Selection_Data_Targets *targets;
615 Ecore_X_Atom *atomlist;
618 targets = notify->data;
619 atomlist = (Ecore_X_Atom *)(targets->data.data);
620 for (j = (CNP_ATOM_LISTING_ATOMS + 1); j < CNP_N_ATOMS; j++)
622 cnp_debug("\t%s %d\n", _x11_atoms[j].name, _x11_atoms[j].atom);
623 if (!(_x11_atoms[j].formats & sel->requestformat)) continue;
624 for (i = 0; i < targets->data.length; i++)
626 if ((_x11_atoms[j].atom == atomlist[i]) && (_x11_atoms[j].notify))
630 if ((j == CNP_ATOM_text_uri) ||
631 (j == CNP_ATOM_text_urilist))
633 if (!_x11_is_uri_type_data(sel, notify)) continue;
637 cnp_debug("Atom %s matches\n", _x11_atoms[j].name);
642 cnp_debug("Couldn't find anything that matches\n");
643 return ECORE_CALLBACK_PASS_ON;
645 cnp_debug("Sending request for %s, xwin=%#llx\n",
646 _x11_atoms[j].name, (unsigned long long)sel->xwin);
647 sel->request(sel->xwin, _x11_atoms[j].name);
648 return ECORE_CALLBACK_PASS_ON;
652 _x11_response_handler_targets(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
654 Ecore_X_Selection_Data_Targets *targets;
655 Ecore_X_Atom *atomlist;
658 targets = notify->data;
659 atomlist = (Ecore_X_Atom *)(targets->data.data);
661 for (j = (CNP_ATOM_LISTING_ATOMS + 1); j < CNP_N_ATOMS; j++)
663 if (!(_x11_atoms[j].formats & sel->requestformat)) continue;
664 for (i = 0; i < targets->data.length; i++)
666 if ((_x11_atoms[j].atom == atomlist[i]) &&
667 (_x11_atoms[j].response))
671 cnp_debug("No matching type found\n");
674 sel->request(sel->xwin, _x11_atoms[j].name);
679 _x11_notify_handler_text(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
681 Ecore_X_Selection_Data *data;
686 Elm_Selection_Data ddata;
688 ddata.x = ddata.y = 0;
689 ddata.format = ELM_SEL_FORMAT_TEXT;
690 ddata.data = data->data;
691 ddata.len = data->length;
692 sel->datacb(sel->udata, sel->widget, &ddata);
696 char *stripstr, *mkupstr;
698 stripstr = malloc(data->length + 1);
699 if (!stripstr) return 0;
700 strncpy(stripstr, (char *)data->data, data->length);
701 stripstr[data->length] = '\0';
702 cnp_debug("Notify handler text %d %d %p\n", data->format,
703 data->length, data->data);
704 mkupstr = _elm_util_text_to_mkup((const char *)stripstr);
705 cnp_debug("String is %s (from %s)\n", stripstr, data->data);
706 /* TODO BUG: should never NEVER assume it's an elm_entry! */
707 //_elm_entry_entry_paste(sel->requestwidget, mkupstr); // TIZEN ONLY
710 _entry_insert_filter(sel->requestwidget, mkupstr);
712 _entry_insert_filter(sel->requestwidget, stripstr);
722 * So someone is pasting an image into my entry or widget...
725 _x11_notify_handler_uri(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
727 Ecore_X_Selection_Data *data;
728 Ecore_X_Selection_Data_Files *files;
732 cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
733 if (data->content == ECORE_X_SELECTION_CONTENT_FILES)
735 cnp_debug("got a files list\n");
736 files = notify->data;
737 if (files->num_files > 1)
739 /* Don't handle many items */
740 cnp_debug("more then one file: Bailing\n");
743 stripstr = p = strdup(files->files[0]);
747 stripstr = p = malloc(data->length + 1);
748 if (!stripstr) return 0;
749 memcpy(stripstr, data->data, data->length);
750 stripstr[data->length] = 0;
754 cnp_debug("Couldn't find a file\n");
757 cnp_debug("Got %s\n", p);
761 Elm_Selection_Data ddata;
763 ddata.x = ddata.y = 0;
764 ddata.format = ELM_SEL_FORMAT_IMAGE;
766 ddata.len = data->length;
767 sel->datacb(sel->udata, sel->widget, &ddata);
772 if (strncmp(p, "file://", 7))
774 /* Try and continue if it looks sane */
781 else p += strlen("file://");
782 if (savedtypes.imgfile) free(savedtypes.imgfile);
783 if (savedtypes.textreq)
785 savedtypes.textreq = 0;
786 savedtypes.imgfile = strdup(p);
788 else _pasteimage_append(p, sel->requestwidget);
794 * Just receieved an vcard, either through cut and paste, or dnd.
797 _x11_vcard_receive(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
801 Ecore_X_Selection_Data *data;
804 cnp_debug("vcard receive\n");
805 if (sel == (_x11_selections + ELM_SEL_TYPE_XDND))
807 Elm_Selection_Data ddata;
809 cnp_debug("drag & drop\n");
810 /* FIXME: this needs to be generic: Used for all receives */
811 EINA_LIST_FOREACH(drops, l, dropable)
813 if (dropable->obj == sel->requestwidget) break;
817 cnp_debug("Unable to find drop object");
818 ecore_x_dnd_send_finished();
821 dropable = eina_list_data_get(l);
822 ddata.x = savedtypes.x;
823 ddata.y = savedtypes.y;
824 ddata.format = ELM_SEL_FORMAT_VCARD;
825 ddata.data = data->data;
826 ddata.len = data->length;
827 dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
828 ecore_x_dnd_send_finished();
830 else if (sel->datacb)
832 Elm_Selection_Data ddata;
833 ddata.x = ddata.y = 0;
834 ddata.format = ELM_SEL_FORMAT_VCARD;
835 ddata.data = data->data;
836 ddata.len = data->length;
837 sel->datacb(sel->udata, sel->widget, &ddata);
839 else cnp_debug("Paste request\n");
844 _x11_notify_handler_image(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
846 Ecore_X_Selection_Data *data;
849 cnp_debug("got a image file!\n");
852 cnp_debug("Size if %d\n", data->length);
855 Elm_Selection_Data ddata;
857 ddata.x = ddata.y = 0;
858 ddata.format = ELM_SEL_FORMAT_IMAGE;
859 ddata.data = data->data;
860 ddata.len = data->length;
861 sel->datacb(sel->udata, sel->widget, &ddata);
864 /* generate tmp name */
865 tmp = _tempfile_new(data->length);
867 memcpy(tmp->map, data->data, data->length);
868 munmap(tmp->map, data->length);
869 /* FIXME: Add to paste image data to clean up */
870 _pasteimage_append(tmp->filename, sel->requestwidget);
877 _x11_notify_handler_edje(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
879 Ecore_X_Selection_Data *data;
885 Elm_Selection_Data ddata;
886 ddata.x = ddata.y = 0;
887 ddata.format = ELM_SEL_FORMAT_MARKUP;
888 ddata.data = data->data;
889 ddata.len = data->length;
890 sel->datacb(sel->udata, sel->widget, &ddata);
895 stripstr = malloc(data->length + 1);
896 if (!stripstr) return 0;
897 strncpy(stripstr, (char *)data->data, data->length);
898 stripstr[data->length] = '\0';
900 _entry_insert_filter(sel->requestwidget, stripstr);
901 cnp_debug("String is %s (%d bytes)\n", stripstr, data->length);
910 * Warning: Generic text/html can';t handle it sanely.
911 * Firefox sends ucs2 (i think).
912 * chrome sends utf8... blerg
916 _x11_notify_handler_html(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
918 Ecore_X_Selection_Data *data;
920 cnp_debug("Got some HTML: Checking encoding is useful\n");
922 char *stripstr = malloc(data->length + 1);
923 if (!stripstr) return 0;
924 strncpy(stripstr, (char *)data->data, data->length);
925 stripstr[data->length] = '\0';
929 Elm_Selection_Data ddata;
930 ddata.x = ddata.y = 0;
931 ddata.format = ELM_SEL_FORMAT_HTML;
932 ddata.data = stripstr;
933 ddata.len = data->length;
934 sel->datacb(sel->udata, sel->widget, &ddata);
939 cnp_debug("String is %s (%d bytes)\n", stripstr, data->length);
940 // TODO BUG: should never NEVER assume it's an elm_entry!
941 _elm_entry_entry_paste(sel->requestwidget, stripstr);
948 _x11_text_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
950 X11_Cnp_Selection *sel;
952 cnp_debug("text converter\n");
953 if (_get_selection_type(data, size) == ELM_SEL_FORMAT_NONE)
957 *data_ret = malloc(size * sizeof(char) + 1);
958 if (!*data_ret) return EINA_FALSE;
959 memcpy(*data_ret, data, size);
960 ((char**)(data_ret))[0][size] = 0;
962 if (size_ret) *size_ret = size;
965 sel = _x11_selections + *((int *)data);
966 if (!sel->active) return EINA_TRUE;
968 if ((sel->format & ELM_SEL_FORMAT_MARKUP) ||
969 (sel->format & ELM_SEL_FORMAT_HTML))
971 *data_ret = _elm_util_mkup_to_text(sel->selbuf);
972 if (size_ret) *size_ret = strlen(*data_ret);
974 else if (sel->format & ELM_SEL_FORMAT_TEXT)
976 ecore_x_selection_converter_text(target, sel->selbuf,
981 else if (sel->format & ELM_SEL_FORMAT_IMAGE)
983 cnp_debug("Image %s\n", evas_object_type_get(sel->widget));
984 cnp_debug("Elm type: %s\n", elm_object_widget_type_get(sel->widget));
985 evas_object_image_file_get(elm_photocam_internal_image_get(sel->widget),
986 (const char **)data_ret, NULL);
987 if (!*data_ret) *data_ret = strdup("No file");
988 else *data_ret = strdup(*data_ret);
989 *size_ret = strlen(*data_ret);
995 _x11_general_converter(char *target __UNUSED__, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
997 if (_get_selection_type(data, size) == ELM_SEL_FORMAT_NONE)
1001 *data_ret = malloc(size * sizeof(char) + 1);
1002 if (!*data_ret) return EINA_FALSE;
1003 memcpy(*data_ret, data, size);
1004 ((char**)(data_ret))[0][size] = 0;
1006 if (size_ret) *size_ret = size;
1010 X11_Cnp_Selection *sel = _x11_selections + *((int *)data);
1011 if (data_ret) *data_ret = strdup(sel->selbuf);
1012 if (size_ret) *size_ret = strlen(sel->selbuf);
1018 _x11_dnd_enter(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1020 Ecore_X_Event_Xdnd_Enter *enter = ev;
1024 cnp_debug("enter %p\n", enter);
1025 cnp_debug("enter types=%p (%d)\n", enter->types, enter->num_types);
1026 if ((!enter) || (!enter->num_types) || (!enter->types)) return EINA_TRUE;
1028 cnp_debug("Types\n");
1029 savedtypes.ntypes = enter->num_types;
1030 if (savedtypes.types) free(savedtypes.types);
1031 savedtypes.types = malloc(sizeof(char *) * enter->num_types);
1032 if (!savedtypes.types) return EINA_FALSE;
1034 for (i = 0; i < enter->num_types; i++)
1036 savedtypes.types[i] = eina_stringshare_add(enter->types[i]);
1037 cnp_debug("Type is %s %p %p\n", enter->types[i],
1038 savedtypes.types[i], text_uri);
1039 if (savedtypes.types[i] == text_uri)
1041 /* Request it, so we know what it is */
1042 cnp_debug("Sending uri request\n");
1043 savedtypes.textreq = 1;
1044 if (savedtypes.imgfile) free(savedtypes.imgfile);
1045 savedtypes.imgfile = NULL;
1046 ecore_x_selection_xdnd_request(enter->win, text_uri);
1050 /* FIXME: Find an object and make it current */
1055 _x11_dnd_drop(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1057 struct _Ecore_X_Event_Xdnd_Drop *drop;
1061 Ecore_X_Window xwin;
1062 Elm_Selection_Data ddata;
1068 cnp_debug("drops %p (%d)\n", drops, eina_list_count(drops));
1070 // check we still have something to drop
1071 if (!drops) return EINA_TRUE;
1073 /* Find any widget in our window; then work out geometry rel to our window */
1074 for (l = drops; l; l = l->next)
1077 xwin = _x11_elm_widget_xwin_get(dropable->obj);
1078 if (xwin == drop->win) break;
1080 /* didn't find a window */
1081 if (!l) return EINA_TRUE;
1083 /* Calculate real (widget relative) position */
1084 // - window position
1085 // - widget position
1086 ee = ecore_evas_ecore_evas_get(evas_object_evas_get(dropable->obj));
1087 ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
1088 savedtypes.x = drop->position.x - x;
1089 savedtypes.y = drop->position.y - y;
1091 cnp_debug("Drop position is %d,%d\n", savedtypes.x, savedtypes.y);
1093 for (; l; l = l->next)
1096 evas_object_geometry_get(dropable->obj, &x, &y, &w, &h);
1097 if ((savedtypes.x >= x) && (savedtypes.y >= y) &&
1098 (savedtypes.x < x + w) && (savedtypes.y < y + h))
1102 if (!l) return EINA_TRUE; /* didn't find one */
1104 evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL);
1108 /* Find our type from the previous list */
1109 for (i = 0; i < CNP_N_ATOMS; i++)
1111 for (j = 0; j < savedtypes.ntypes; j++)
1113 if (!strcmp(savedtypes.types[j], _x11_atoms[i].name)) goto found;
1117 cnp_debug("Didn't find a target\n");
1121 cnp_debug("Found a target we'd like: %s\n", _x11_atoms[i].name);
1122 cnp_debug("0x%x\n",xwin);
1124 if (i == CNP_ATOM_text_urilist)
1126 cnp_debug("We found a URI... (%scached) %s\n",
1127 savedtypes.imgfile ? "" : "not ",
1128 savedtypes.imgfile);
1129 if (savedtypes.imgfile)
1132 static const char *tagstring = "<item absize=240x180 href="
1133 "file://%s></item>";
1134 ddata.x = savedtypes.x;
1135 ddata.y = savedtypes.y;
1137 /* If it's markup that also supports images */
1138 if ((dropable->types & ELM_SEL_FORMAT_MARKUP) &&
1139 (dropable->types & ELM_SEL_FORMAT_IMAGE))
1142 ddata.format = ELM_SEL_FORMAT_MARKUP;
1144 len = strlen(tagstring) + strlen(savedtypes.imgfile);
1145 entrytag = alloca(len + 1);
1146 snprintf(entrytag, len + 1, tagstring, savedtypes.imgfile);
1147 ddata.data = entrytag;
1148 cnp_debug("Insert %s\n", (char *)ddata.data);
1149 dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1150 ecore_x_dnd_send_finished();
1151 if (savedtypes.imgfile) free(savedtypes.imgfile);
1152 savedtypes.imgfile = NULL;
1156 else if (dropable->types & ELM_SEL_FORMAT_IMAGE)
1158 cnp_debug("Doing image insert (%s)\n", savedtypes.imgfile);
1159 ddata.format = ELM_SEL_FORMAT_IMAGE;
1160 ddata.data = (char *)savedtypes.imgfile;
1161 dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1162 ecore_x_dnd_send_finished();
1163 if (savedtypes.imgfile) free(savedtypes.imgfile);
1164 savedtypes.imgfile = NULL;
1170 cnp_debug("Item doesn't support images... passing\n");
1174 else if (savedtypes.textreq)
1176 /* Already asked: Pretend we asked now, and paste immediately when
1178 savedtypes.textreq = 0;
1179 ecore_x_dnd_send_finished();
1184 cnp_debug("doing a request then\n");
1185 _x11_selections[ELM_SEL_TYPE_XDND].xwin = xwin;
1186 _x11_selections[ELM_SEL_TYPE_XDND].requestwidget = dropable->obj;
1187 _x11_selections[ELM_SEL_TYPE_XDND].requestformat = ELM_SEL_FORMAT_MARKUP;
1188 _x11_selections[ELM_SEL_TYPE_XDND].active = EINA_TRUE;
1190 ecore_x_selection_xdnd_request(xwin, _x11_atoms[i].name);
1195 _x11_dnd_position(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1197 struct _Ecore_X_Event_Xdnd_Position *pos = ev;
1198 Ecore_X_Rectangle rect;
1200 /* Need to send a status back */
1201 /* FIXME: Should check I can drop here */
1202 /* FIXME: Should highlight widget */
1203 rect.x = pos->position.x - 5;
1204 rect.y = pos->position.y - 5;
1207 ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, pos->action);
1212 * When dragging this is callback response from the destination.
1213 * The important thing we care about: Can we drop; thus update cursor
1217 _x11_dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1219 struct _Ecore_X_Event_Xdnd_Status *status = ev;
1221 if (!status) return EINA_TRUE;
1223 /* Only thing we care about: will accept */
1224 if (status->will_accept) cnp_debug("Will accept\n");
1226 else cnp_debug("Won't accept accept\n");
1231 _x11_drag_mouse_up(void *un __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *data)
1233 Ecore_X_Window xwin = *((Ecore_X_Window *)data);
1234 evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP, _x11_drag_mouse_up);
1237 cnp_debug("mouse up, xwin=%#llx\n", (unsigned long long)xwin);
1239 /* TODO BUG: should not revert to FALSE if xwin is a drop target! */
1240 ecore_x_dnd_aware_set(xwin, EINA_FALSE);
1243 dragdonecb(dragdonedata, _x11_selections[ELM_SEL_TYPE_XDND].widget);
1248 evas_object_del(dragwin);
1254 _x11_drag_move(void *data __UNUSED__, Ecore_X_Xdnd_Position *pos)
1256 evas_object_move(dragwin, pos->position.x - _dragx, pos->position.y - _dragy);
1259 static Ecore_X_Window
1260 _x11_elm_widget_xwin_get(const Evas_Object *obj)
1263 Ecore_X_Window xwin = 0;
1265 top = elm_widget_top_get(obj);
1266 if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(obj));
1267 if (top) xwin = elm_win_xwindow_get(top);
1271 Evas *evas = evas_object_evas_get(obj);
1272 if (!evas) return 0;
1273 ee = ecore_evas_ecore_evas_get(evas);
1275 xwin = _elm_ee_xwin_get(ee);
1281 _x11_elm_cnp_init(void)
1284 static int _init_count = 0;
1286 if (_init_count > 0) return EINA_TRUE;
1288 for (i = 0; i < CNP_N_ATOMS; i++)
1290 _x11_atoms[i].atom = ecore_x_atom_get(_x11_atoms[i].name);
1291 ecore_x_selection_converter_atom_add
1292 (_x11_atoms[i].atom, _x11_atoms[i].converter);
1294 ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, _x11_selection_clear, NULL);
1295 ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, _x11_selection_notify, NULL);
1300 _x11_elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, const void *selbuf, size_t buflen)
1302 Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
1303 X11_Cnp_Selection *sel;
1305 _x11_elm_cnp_init();
1306 if ((!selbuf) && (format != ELM_SEL_FORMAT_IMAGE))
1307 return elm_object_cnp_selection_clear(obj, selection);
1309 sel = _x11_selections + selection;
1310 if (sel->loss_cb) sel->loss_cb(sel->loss_data, selection);
1312 evas_object_event_callback_del_full(sel->widget, EVAS_CALLBACK_DEL,
1313 _x11_sel_obj_del, sel);
1316 sel->active = EINA_TRUE;
1319 sel->set(xwin, &selection, sizeof(Elm_Sel_Type));
1320 sel->format = format;
1321 sel->loss_cb = NULL;
1322 sel->loss_data = NULL;
1324 evas_object_event_callback_add
1325 (sel->widget, EVAS_CALLBACK_DEL, _x11_sel_obj_del, sel);
1329 if (format == ELM_SEL_FORMAT_IMAGE)
1331 // selbuf is actual image data, not text/string
1332 sel->selbuf = malloc(buflen);
1335 elm_object_cnp_selection_clear(obj, selection);
1338 memcpy(sel->selbuf, selbuf, buflen);
1341 sel->selbuf = strdup((char*)selbuf);
1350 _x11_elm_cnp_selection_loss_callback_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const void *data)
1352 X11_Cnp_Selection *sel;
1354 _x11_elm_cnp_init();
1355 sel = _x11_selections + selection;
1356 sel->loss_cb = func;
1357 sel->loss_data = (void *)data;
1361 _x11_elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection)
1363 X11_Cnp_Selection *sel;
1365 _x11_elm_cnp_init();
1367 sel = _x11_selections + selection;
1369 /* No longer this selection: Consider it gone! */
1370 if ((!sel->active) || (sel->widget != obj)) return EINA_TRUE;
1373 evas_object_event_callback_del_full(sel->widget, EVAS_CALLBACK_DEL,
1374 _x11_sel_obj_del, sel);
1375 if (sel->requestwidget)
1376 evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
1377 _x11_sel_obj_del2, sel);
1379 sel->requestwidget = NULL;
1380 sel->loss_cb = NULL;
1381 sel->loss_data = NULL;
1383 sel->active = EINA_FALSE;
1395 _x11_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection,
1396 Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata)
1398 Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
1399 X11_Cnp_Selection *sel;
1401 _x11_elm_cnp_init();
1403 sel = _x11_selections + selection;
1405 if (sel->requestwidget)
1406 evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
1407 _x11_sel_obj_del2, sel);
1408 sel->requestwidget = NULL;
1410 sel->requestformat = format;
1411 sel->requestwidget = obj;
1413 sel->request(xwin, ECORE_X_SELECTION_TARGET_TARGETS);
1414 sel->datacb = datacb;
1417 evas_object_event_callback_add
1418 (sel->requestwidget, EVAS_CALLBACK_DEL, _x11_sel_obj_del2, sel);
1424 _x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format,
1425 Elm_Drop_Cb dropcb, void *cbdata)
1428 Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
1432 _x11_elm_cnp_init();
1434 /* TODO: check if obj is already a drop target. Do not add twice! */
1436 /* Is this the first? */
1437 first = (!drops) ? 1 : 0;
1439 EINA_LIST_FOREACH(drops, item, drop)
1441 if (drop->obj == obj)
1443 /* Update: Not a new one */
1444 drop->dropcb = dropcb;
1445 drop->cbdata = cbdata;
1446 drop->types = format;
1451 /* Create new drop */
1452 drop = calloc(1, sizeof(Dropable));
1453 if (!drop) return EINA_FALSE;
1454 /* FIXME: Check for eina's deranged error method */
1455 drops = eina_list_append(drops, drop);
1457 if (!drops/* || or other error */)
1462 drop->dropcb = dropcb;
1463 drop->cbdata = cbdata;
1464 drop->types = format;
1467 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1468 /* I love C and varargs */
1469 (Evas_Object_Event_Cb)elm_drop_target_del,
1471 /* TODO BUG: should handle dnd-aware per window, not just the first
1472 * window that requested it! */
1473 /* If not the first: We're done */
1474 if (!first) return EINA_TRUE;
1476 ecore_x_dnd_aware_set(xwin, EINA_TRUE);
1478 cnp_debug("Adding drop target calls xwin=%#llx\n", (unsigned long long)xwin);
1479 handler_enter = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
1480 _x11_dnd_enter, NULL);
1481 handler_pos = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
1482 _x11_dnd_position, NULL);
1483 handler_drop = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
1484 _x11_dnd_drop, NULL);
1489 _x11_elm_drop_target_del(Evas_Object *obj)
1491 Dropable *drop,*del;
1493 Ecore_X_Window xwin;
1495 _x11_elm_cnp_init();
1498 EINA_LIST_FOREACH(drops, item, drop)
1500 if (drop->obj == obj)
1502 drops = eina_list_remove_list(drops, item);
1507 if (!del) return EINA_FALSE;
1509 evas_object_event_callback_del(obj, EVAS_CALLBACK_FREE,
1510 (Evas_Object_Event_Cb)elm_drop_target_del);
1513 /* TODO BUG: we should handle dnd-aware per window, not just the last that reelased it */
1515 /* If still drops there: All fine.. continue */
1516 if (drops) return EINA_TRUE;
1518 cnp_debug("Disabling DND\n");
1519 xwin = _x11_elm_widget_xwin_get(obj);
1520 ecore_x_dnd_aware_set(xwin, EINA_FALSE);
1522 ecore_event_handler_del(handler_pos);
1523 ecore_event_handler_del(handler_drop);
1524 ecore_event_handler_del(handler_enter);
1526 if (savedtypes.imgfile) free(savedtypes.imgfile);
1527 savedtypes.imgfile = NULL;
1533 _x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, void (*dragdone) (void *data, Evas_Object *), void *donecbdata)
1535 Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
1536 X11_Cnp_Selection *sel;
1537 Elm_Sel_Type xdnd = ELM_SEL_TYPE_XDND;
1539 int x, y, x2, y2, x3, y3;
1543 _x11_elm_cnp_init();
1545 cnp_debug("starting drag...\n");
1549 cnp_debug("another obj is dragging...\n");
1553 ecore_x_dnd_type_set(xwin, "text/uri-list", EINA_TRUE);
1554 sel = _x11_selections + ELM_SEL_TYPE_XDND;
1555 sel->active = EINA_TRUE;
1557 sel->format = format;
1558 sel->selbuf = data ? strdup(data) : NULL;
1560 /* TODO BUG: should NEVER have these as globals! They should be per context (window). */
1561 dragdonecb = dragdone;
1562 dragdonedata = donecbdata;
1563 /* TODO BUG: should increase dnd-awareness, in case it's drop target as well. See _x11_drag_mouse_up() */
1564 ecore_x_dnd_aware_set(xwin, EINA_TRUE);
1565 ecore_x_dnd_callback_pos_update_set(_x11_drag_move, NULL);
1566 ecore_x_dnd_begin(xwin, (unsigned char *)&xdnd, sizeof(Elm_Sel_Type));
1567 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
1568 _x11_drag_mouse_up, (void *)(long)xwin);
1569 handler_status = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
1570 _x11_dnd_status, NULL);
1571 dragwin = elm_win_add(NULL, "Elm Drag Object", ELM_WIN_UTILITY);
1572 elm_win_override_set(dragwin, EINA_TRUE);
1574 /* FIXME: Images only */
1575 icon = elm_icon_add(dragwin);
1576 elm_image_file_set(icon, data + 7, NULL); /* 7!? "file://" */
1577 elm_win_resize_object_add(dragwin, icon);
1578 evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1579 evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL);
1581 /* Position subwindow appropriately */
1582 ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
1583 ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
1584 evas_object_geometry_get(obj, &x2, &y2, &w, &h);
1587 evas_object_move(dragwin, x, y);
1588 evas_object_resize(icon, w, h);
1589 evas_object_resize(dragwin, w, h);
1591 evas_object_show(icon);
1592 evas_object_show(dragwin);
1594 evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x3, &y3);
1602 _x11_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__)
1604 _x11_elm_cnp_init();
1605 return !!ecore_x_selection_owner_get(ECORE_X_ATOM_SELECTION_CLIPBOARD);
1610 #ifdef HAVE_ELEMENTARY_WAYLAND
1611 typedef struct _Wl_Cnp_Selection Wl_Cnp_Selection;
1613 struct _Wl_Cnp_Selection
1618 Evas_Object *widget;
1619 Evas_Object *requestwidget;
1622 static Eina_Bool _wl_elm_cnp_init(void);
1624 static Wl_Cnp_Selection wl_cnp_selection = {0, 0, NULL, NULL};
1625 static void _wl_sel_obj_del2(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
1626 static Eina_Bool _wl_elm_cnp_selection_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, const void *selbuf, size_t buflen);
1627 static Eina_Bool _wl_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, Elm_Drop_Cb datacb __UNUSED__, void *udata __UNUSED__);
1628 static Eina_Bool _wl_selection_send(void *udata, int type __UNUSED__, void *event);
1629 static Eina_Bool _wl_selection_receive(void *udata, int type __UNUSED__, void *event);
1632 _wl_sel_obj_del2(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1634 Wl_Cnp_Selection *sel = data;
1635 if (sel->requestwidget == obj) sel->requestwidget = NULL;
1639 _wl_elm_cnp_selection_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, const void *selbuf, size_t buflen)
1641 const char *types[10] = {0, };
1645 /* TODO: other EML_SEL_TYPE and ELM_SEL_FORMAT */
1646 if (ELM_SEL_TYPE_CLIPBOARD == selection)
1648 types[0] = "text/plain;charset=utf-8";
1649 ecore_wl_dnd_set_selection(ecore_wl_dnd_get(), types);
1651 if (wl_cnp_selection.selbuf) free(wl_cnp_selection.selbuf);
1652 wl_cnp_selection.selbuf = strdup((char*)selbuf);
1653 wl_cnp_selection.buflen = buflen;
1661 _wl_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, Elm_Drop_Cb datacb __UNUSED__, void *udata __UNUSED__)
1665 /* For now, just avoid overlapped request */
1666 if (wl_cnp_selection.requestwidget) return EINA_FALSE;
1668 /* TODO: other EML_SEL_TYPE and ELM_SEL_FORMAT */
1669 if (ELM_SEL_TYPE_CLIPBOARD == selection)
1671 wl_cnp_selection.requestwidget = obj;
1672 evas_object_event_callback_add(wl_cnp_selection.requestwidget, EVAS_CALLBACK_DEL,
1673 _wl_sel_obj_del2, &wl_cnp_selection);
1674 ecore_wl_dnd_get_selection(ecore_wl_dnd_get(), "text/plain;charset=utf-8");
1680 _wl_selection_send(void *udata, int type __UNUSED__, void *event)
1683 int ret, len_remained;
1684 int len_written = 0;
1685 Wl_Cnp_Selection *sel = udata;
1686 Ecore_Wl_Event_Data_Source_Send *ev = event;
1690 len_remained = sel->buflen;
1693 while (len_written < sel->buflen)
1695 ret = write(ev->fd, buf, len_remained);
1696 if (ret == -1) break;
1699 len_remained -= ret;
1703 return ECORE_CALLBACK_PASS_ON;
1707 _wl_selection_receive(void *udata, int type __UNUSED__, void *event)
1709 Wl_Cnp_Selection *sel = udata;
1710 Ecore_Wl_Event_Selection_Data_Ready *ev = event;
1714 if (sel->requestwidget)
1718 /* TODO BUG: should never NEVER assume it's an elm_entry! */
1719 _elm_entry_entry_paste(sel->requestwidget, ev->data);
1723 evas_object_event_callback_del_full(sel->requestwidget, EVAS_CALLBACK_DEL,
1724 _wl_sel_obj_del2, sel);
1725 sel->requestwidget = NULL;
1729 return ECORE_CALLBACK_PASS_ON;
1733 _wl_elm_cnp_init(void)
1735 static int _init_count = 0;
1737 if (_init_count > 0) return EINA_TRUE;
1740 ecore_event_handler_add(ECORE_WL_EVENT_DATA_SOURCE_SEND,
1741 _wl_selection_send, &wl_cnp_selection);
1742 ecore_event_handler_add(ECORE_WL_EVENT_SELECTION_DATA_READY,
1743 _wl_selection_receive, &wl_cnp_selection);
1754 ////////////////////////////////////////////////////////////////////////////
1755 // for local (Within 1 app/process) cnp (used by fb as fallback
1756 ////////////////////////////////////////////////////////////////////////////
1758 typedef struct _Local_Selinfo Local_Selinfo;
1760 struct _Local_Selinfo
1762 Elm_Sel_Format format;
1775 // for ELM_SEL_TYPE_PRIMARY, ELM_SEL_TYPE_SECONDARY, ELM_SEL_TYPE_XDND,
1776 // ELM_SEL_TYPE_CLIPBOARD
1777 static Local_Selinfo _local_selinfo[4];
1779 static void _local_get_job(void *data);
1781 static Eina_Bool _local_elm_cnp_init(void);
1782 static Eina_Bool _local_elm_cnp_selection_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Sel_Format format, const void *selbuf, size_t buflen);
1783 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__);
1784 static Eina_Bool _local_elm_object_cnp_selection_clear(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection);
1785 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);
1786 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__);
1787 static Eina_Bool _local_elm_drop_target_del(Evas_Object *obj __UNUSED__);
1788 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__);
1789 static Eina_Bool _local_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__);
1792 _local_get_job(void *data)
1794 Local_Selinfo *info = data;
1795 Elm_Selection_Data ev;
1797 info->get.job = NULL;
1800 ev.format = info->format;
1801 ev.data = info->sel.buf;
1802 ev.len = info->sel.size;
1804 info->get.func(info->get.data, info->get.obj, &ev);
1808 _local_elm_cnp_init(void)
1810 static int _init_count = 0;
1812 if (_init_count > 0) return EINA_TRUE;
1814 memset(&(_local_selinfo), 0, sizeof(_local_selinfo));
1819 _local_elm_cnp_selection_set(Evas_Object *obj __UNUSED__,
1820 Elm_Sel_Type selection, Elm_Sel_Format format,
1821 const void *selbuf, size_t buflen)
1823 _local_elm_cnp_init();
1824 if (_local_selinfo[selection].sel.buf)
1825 free(_local_selinfo[selection].sel.buf);
1826 _local_selinfo[selection].format = format;
1827 _local_selinfo[selection].sel.buf = malloc(buflen);
1828 if (_local_selinfo[selection].sel.buf)
1830 memcpy(_local_selinfo[selection].sel.buf, selbuf, buflen);
1831 _local_selinfo[selection].sel.size = buflen;
1834 _local_selinfo[selection].sel.size = 0;
1839 _local_elm_cnp_selection_loss_callback_set(Evas_Object *obj __UNUSED__,
1840 Elm_Sel_Type selection __UNUSED__,
1841 Elm_Selection_Loss_Cb func __UNUSED__,
1842 const void *data __UNUSED__)
1844 _local_elm_cnp_init();
1845 // this doesnt need to do anything as we never lose selection to anyone
1850 _local_elm_object_cnp_selection_clear(Evas_Object *obj __UNUSED__,
1851 Elm_Sel_Type selection)
1853 _local_elm_cnp_init();
1854 if (_local_selinfo[selection].sel.buf)
1855 free(_local_selinfo[selection].sel.buf);
1856 _local_selinfo[selection].sel.buf = NULL;
1857 _local_selinfo[selection].sel.size = 0;
1862 _local_elm_cnp_selection_get(Evas_Object *obj,
1863 Elm_Sel_Type selection,
1864 Elm_Sel_Format format __UNUSED__,
1865 Elm_Drop_Cb datacb, void *udata)
1867 _local_elm_cnp_init();
1868 if (_local_selinfo[selection].get.job)
1869 ecore_job_del(_local_selinfo[selection].get.job);
1870 _local_selinfo[selection].get.obj = obj;
1871 _local_selinfo[selection].get.func = datacb;
1872 _local_selinfo[selection].get.data = udata;
1873 _local_selinfo[selection].get.job =
1874 ecore_job_add(_local_get_job, &(_local_selinfo[selection]));
1879 _local_elm_drop_target_add(Evas_Object *obj __UNUSED__,
1880 Elm_Sel_Type format __UNUSED__,
1881 Elm_Drop_Cb dropcb __UNUSED__,
1882 void *cbdata __UNUSED__)
1884 // XXX: implement me
1885 _local_elm_cnp_init();
1890 _local_elm_drop_target_del(Evas_Object *obj __UNUSED__)
1892 // XXX: implement me
1893 _local_elm_cnp_init();
1898 _local_elm_drag_start(Evas_Object *obj __UNUSED__,
1899 Elm_Sel_Format format __UNUSED__,
1900 const char *data __UNUSED__,
1901 void (*dragdone) (void *data, Evas_Object *) __UNUSED__,
1902 void *donecbdata __UNUSED__)
1904 // XXX: implement me
1905 _local_elm_cnp_init();
1910 _local_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__)
1912 _local_elm_cnp_init();
1913 if (_local_selinfo[ELM_SEL_TYPE_CLIPBOARD].sel.buf) return EINA_TRUE;
1923 // common internal funcs
1924 ////////////////////////////////////////////////////////////////////////////
1928 if (_elm_cnp_init_count > 0) return EINA_TRUE;
1929 _elm_cnp_init_count++;
1930 text_uri = eina_stringshare_add("text/uri-list");
1934 /* TODO: this should not be an actual tempfile, but rather encode the object
1935 * as http://dataurl.net/ if it's an image or similar. Evas should support
1936 * decoding it as memfile. */
1938 _tempfile_new(int size)
1942 const char *tmppath;
1946 info = calloc(1, sizeof(Tmp_Info));
1947 if (!info) return NULL;
1948 tmppath = getenv("TMP");
1949 if (!tmppath) tmppath = P_tmpdir;
1950 len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-");
1951 if (len < 0) goto on_error;
1953 info->filename = malloc(len);
1954 if (!info->filename) goto on_error;
1955 snprintf(info->filename,len,"%s/%sXXXXXX", tmppath, "elmcnpitem-");
1956 cur_umask = umask(S_IRWXO | S_IRWXG);
1957 info->fd = mkstemp(info->filename);
1959 if (info->fd < 0) goto on_error;
1963 /* And before someone says anything see POSIX 1003.1-2008 page 400 */
1966 pid = (long)getpid();
1967 /* Use pid instead of /proc/self: That way if can be passed around */
1968 len = snprintf(NULL,0,"/proc/%li/fd/%i", pid, info->fd);
1973 snprintf(tmp,len, "/proc/%li/fd/%i", pid, info->fd);
1974 unlink(info->filename);
1975 free(info->filename);
1976 info->filename = tmp;
1980 cnp_debug("filename is %s\n", info->filename);
1981 if (size < 1) goto on_error;
1983 if (ftruncate(info->fd, size))
1985 perror("ftruncate");
1988 eina_mmap_safety_enabled_set(EINA_TRUE);
1989 info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0);
1990 if (info->map == MAP_FAILED)
1998 if (info->fd > 0) close(info->fd);
2000 /* Set map to NULL and return */
2012 _tmpinfo_free(Tmp_Info *info)
2014 if (!info) return 0;
2015 free(info->filename);
2021 _pasteimage_append(char *file, Evas_Object *entry)
2025 /* TODO BUG: shouldn't define absize=240x180. Prefer data:// instead of href:// -- may need support for evas. See http://dataurl.net/ */
2026 static const char *tagstring = "<item absize=240x180 href=file://%s></item>";
2028 if ((!file) || (!entry)) return EINA_FALSE;
2029 len = strlen(tagstring)+strlen(file);
2030 entrytag = alloca(len + 1);
2031 snprintf(entrytag, len + 1, tagstring, file);
2032 /* TODO BUG: should never NEVER assume it's an elm_entry! */
2033 _elm_entry_entry_paste(entry, entrytag);
2039 _entry_insert_filter(Evas_Object *entry, char *str)
2044 char *insertStr = str;
2046 if (elm_entry_single_line_get(entry))
2048 Eina_Strbuf *buf = eina_strbuf_new();
2051 eina_strbuf_append(buf, insertStr);
2052 eina_strbuf_replace_all(buf, "<br>", "");
2053 eina_strbuf_replace_all(buf, "<br/>", "");
2054 eina_strbuf_replace_all(buf, "<ps/>", "");
2055 insertStr = eina_strbuf_string_steal(buf);
2056 eina_strbuf_free(buf);
2059 cnp_debug("remove break tag: %s\n", insertStr);
2061 _elm_entry_entry_paste(entry, insertStr);
2063 if (insertStr != str)
2068 ////////////////////////////////////////////////////////////////////////////
2069 ////////////////////////////////////////////////////////////////////////////
2070 ////////////////////////////////////////////////////////////////////////////
2071 // common exposed funcs
2072 ////////////////////////////////////////////////////////////////////////////
2073 ////////////////////////////////////////////////////////////////////////////
2074 ////////////////////////////////////////////////////////////////////////////
2076 elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection,
2077 Elm_Sel_Format format, const void *selbuf, size_t buflen)
2079 if (selection > ELM_SEL_TYPE_CLIPBOARD) return EINA_FALSE;
2080 if (!_elm_cnp_init_count) _elm_cnp_init();
2081 #ifdef HAVE_ELEMENTARY_X
2082 if (_x11_elm_widget_xwin_get(obj))
2083 return _x11_elm_cnp_selection_set(obj, selection, format, selbuf, buflen);
2085 #ifdef HAVE_ELEMENTARY_WAYLAND
2086 if (elm_win_wl_window_get(obj))
2087 return _wl_elm_cnp_selection_set(obj, selection, format, selbuf, buflen);
2089 return _local_elm_cnp_selection_set(obj, selection, format, selbuf, buflen);
2093 elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type selection,
2094 Elm_Selection_Loss_Cb func,
2097 if (selection > ELM_SEL_TYPE_CLIPBOARD) return;
2098 if (!_elm_cnp_init_count) _elm_cnp_init();
2099 #ifdef HAVE_ELEMENTARY_X
2100 if (_x11_elm_widget_xwin_get(obj))
2101 _x11_elm_cnp_selection_loss_callback_set(obj, selection, func, data);
2103 _local_elm_cnp_selection_loss_callback_set(obj, selection, func, data);
2107 elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection)
2109 if (selection > ELM_SEL_TYPE_CLIPBOARD) return EINA_FALSE;
2110 if (!_elm_cnp_init_count) _elm_cnp_init();
2111 #ifdef HAVE_ELEMENTARY_X
2112 if (_x11_elm_widget_xwin_get(obj))
2113 return _x11_elm_object_cnp_selection_clear(obj, selection);
2115 return _local_elm_object_cnp_selection_clear(obj, selection);
2119 elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection,
2120 Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata)
2122 if (selection > ELM_SEL_TYPE_CLIPBOARD) return EINA_FALSE;
2123 if (!_elm_cnp_init_count) _elm_cnp_init();
2124 #ifdef HAVE_ELEMENTARY_X
2125 if (_x11_elm_widget_xwin_get(obj))
2126 return _x11_elm_cnp_selection_get(obj, selection, format, datacb, udata);
2128 #ifdef HAVE_ELEMENTARY_WAYLAND
2129 if (elm_win_wl_window_get(obj))
2130 return _wl_elm_cnp_selection_get(obj, selection, format, datacb, udata);
2132 return _local_elm_cnp_selection_get(obj, selection, format, datacb, udata);
2135 ////////////////////////////////////////////////////////////////////////////
2138 * Add a widget as drop target.
2141 elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format,
2142 Elm_Drop_Cb dropcb, void *cbdata)
2144 if (!_elm_cnp_init_count) _elm_cnp_init();
2145 #ifdef HAVE_ELEMENTARY_X
2146 if (_x11_elm_widget_xwin_get(obj))
2147 return _x11_elm_drop_target_add(obj, format, dropcb, cbdata);
2149 return _local_elm_drop_target_add(obj, format, dropcb, cbdata);
2153 elm_drop_target_del(Evas_Object *obj)
2155 if (!_elm_cnp_init_count) _elm_cnp_init();
2156 #ifdef HAVE_ELEMENTARY_X
2157 if (_x11_elm_widget_xwin_get(obj))
2158 return _x11_elm_drop_target_del(obj);
2160 return _local_elm_drop_target_del(obj);
2164 elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data,
2165 void (*dragdone) (void *data, Evas_Object *), void *donecbdata)
2167 if (!_elm_cnp_init_count) _elm_cnp_init();
2168 #ifdef HAVE_ELEMENTARY_X
2169 if (_x11_elm_widget_xwin_get(obj))
2170 return _x11_elm_drag_start(obj, format, data, dragdone, donecbdata);
2172 return _local_elm_drag_start(obj, format, data, dragdone, donecbdata);
2176 elm_selection_selection_has_owner(Evas_Object *obj)
2178 if (!_elm_cnp_init_count) _elm_cnp_init();
2179 #ifdef HAVE_ELEMENTARY_X
2180 if (_x11_elm_widget_xwin_get(obj))
2181 return _x11_elm_selection_selection_has_owner(obj);
2183 #ifdef HAVE_ELEMENTARY_WAYLAND
2184 if (elm_win_wl_window_get(obj))
2185 return ecore_wl_dnd_selection_has_owner(ecore_wl_dnd_get());
2187 return _local_elm_selection_selection_has_owner(obj);
2190 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 :*/