2 # include "elementary_config.h"
4 #include <Elementary.h>
9 #ifdef HAVE_ELEMENTARY_X
11 #define ARRAYINIT(foo) [foo] =
16 # define cnp_debug(x...) fprintf(stderr, __FILE__": " x)
18 # define cnp_debug(x...)
21 #define PROVIDER_SET "__elm_cnp_provider_set"
23 typedef struct _Paste_Image Paste_Image;
24 typedef struct _Cnp_Selection Cnp_Selection;
25 typedef struct _Escape Escape;
26 typedef struct _Tmp_Info Tmp_Info;
27 typedef struct _Cnp_Atom Cnp_Atom;
28 typedef struct _Saved_Type Saved_Type;
29 typedef struct _Dropable Dropable;
31 typedef Eina_Bool (*Converter_Fn_Cb) (char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
32 typedef int (*Response_Handler_Cb) (Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
33 typedef int (*Notify_Handler_Cb) (Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
39 CNP_ATOM_text_urilist,
40 CNP_ATOM_text_x_vcard,
51 CNP_ATOM_text_html_utf8,
56 CNP_ATOM_text_plain_utf8,
75 Evas_Object *requestwidget;
77 Elm_Sel_Format requestformat;
79 Eina_Bool (*set) (Ecore_X_Window, const void *data, int size);
80 Eina_Bool (*clear) (void);
81 void (*request) (Ecore_X_Window, const char *target);
83 Elm_Sel_Format format;
84 Ecore_X_Selection ecore_sel;
106 Elm_Sel_Format formats;
107 /* Called by ecore to do conversion */
108 Converter_Fn_Cb converter;
109 Response_Handler_Cb response;
110 Notify_Handler_Cb notify;
121 Eina_Bool textreq: 1;
127 /* FIXME: Cache window */
128 Elm_Sel_Format types;
133 static Tmp_Info *elm_cnp_tempfile_create(int size);
134 static int tmpinfo_free(Tmp_Info *tmp);
136 static Eina_Bool _elm_cnp_init(void);
137 static Eina_Bool selection_clear(void *udata __UNUSED__, int type, void *event);
138 static Eina_Bool selection_notify(void *udata __UNUSED__, int type, void *event);
139 static char *remove_tags(const char *p, int *len);
140 static char *mark_up(const char *start, int inlen, int *lenp);
142 static Evas_Object *image_provider(void *images, Evas_Object *entry, const char *item);
143 static void entry_deleted(void *images, Evas *e, Evas_Object *entry, void *unused);
146 static Eina_Bool targets_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
147 static Eina_Bool text_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
148 static Eina_Bool html_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
149 static Eina_Bool edje_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
150 static Eina_Bool uri_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
151 static Eina_Bool image_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
152 static Eina_Bool vcard_send(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
154 static int response_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *);
156 static int notify_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
157 static int notify_handler_text(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
158 static int notify_handler_image(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
159 static int notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
160 static int notify_handler_html(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify);
161 static int vcard_receive(Cnp_Selection *sed, Ecore_X_Event_Selection_Notify *notify);
163 static Paste_Image *pasteimage_alloc(const char *file, int pathlen);
164 static Eina_Bool pasteimage_append(Paste_Image *pi, Evas_Object *entry);
165 static void pasteimage_free(Paste_Image *pi);
167 /* Optimisation: Turn this into a 256 byte table:
168 * then can lookup in one index, not N checks */
169 static const Escape escapes[] = {
178 #define N_ESCAPES ((int)(sizeof(escapes) / sizeof(escapes[0])))
180 static const char *image_extensions[] =
183 ".jpg", ".jpeg", ".jpe", ".jfif", ".jfi",
186 ".ppm", "pgm", ".pbm", ".pnm",
195 static Cnp_Atom atoms[CNP_N_ATOMS] = {
196 [CNP_ATOM_TARGETS] = {
198 (Elm_Sel_Format) -1, // everything
200 response_handler_targets,
201 notify_handler_targets,
205 "application/x-elementary-markup",
206 ELM_SEL_FORMAT_MARKUP,
212 [CNP_ATOM_text_uri] = {
214 ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE, /* Either images or entries */
220 [CNP_ATOM_text_urilist] = {
222 ELM_SEL_FORMAT_IMAGE | ELM_SEL_FORMAT_MARKUP,
228 [CNP_ATOM_text_x_vcard] = {
230 ELM_SEL_FORMAT_VCARD,
234 [CNP_ATOM_image_png] = {
236 ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
239 notify_handler_image,
242 [CNP_ATOM_image_jpeg] = {
244 ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
247 notify_handler_image,/* Raw image data is the same */
250 [CNP_ATOM_image_bmp] = {
252 ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
255 notify_handler_image,/* Raw image data is the same */
258 [CNP_ATOM_image_gif] = {
260 ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
263 notify_handler_image,/* Raw image data is the same */
266 [CNP_ATOM_image_tiff] = {
268 ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
271 notify_handler_image,/* Raw image data is the same */
274 [CNP_ATOM_image_svg] = {
276 ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
279 notify_handler_image,/* Raw image data is the same */
282 [CNP_ATOM_image_xpm] = {
284 ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
287 notify_handler_image,/* Raw image data is the same */
290 [CNP_ATOM_image_tga] = {
292 ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
295 notify_handler_image,/* Raw image data is the same */
298 [CNP_ATOM_image_ppm] = {
299 "image/x-portable-pixmap",
300 ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE,
303 notify_handler_image,/* Raw image data is the same */
306 [CNP_ATOM_text_html_utf8] = {
307 "text/html;charset=utf-8",
308 ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
314 [CNP_ATOM_text_html] = {
319 notify_handler_html, /* No encoding: Webkit only */
322 [CNP_ATOM_UTF8STRING] = {
324 ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
330 [CNP_ATOM_STRING] = {
332 ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
340 ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
346 [CNP_ATOM_text_plain_utf8] = {
347 "text/plain;charset=utf-8",
348 ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
354 [CNP_ATOM_text_plain] = {
356 ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
364 static Cnp_Selection selections[ELM_SEL_MAX] = {
365 ARRAYINIT(ELM_SEL_PRIMARY) {
367 .ecore_sel = ECORE_X_SELECTION_PRIMARY,
368 .set = ecore_x_selection_primary_set,
369 .clear = ecore_x_selection_primary_clear,
370 .request = ecore_x_selection_primary_request,
372 ARRAYINIT(ELM_SEL_SECONDARY) {
373 .debug = "Secondary",
374 .ecore_sel = ECORE_X_SELECTION_SECONDARY,
375 .set = ecore_x_selection_secondary_set,
376 .clear = ecore_x_selection_secondary_clear,
377 .request = ecore_x_selection_secondary_request,
379 ARRAYINIT(ELM_SEL_CLIPBOARD) {
380 .debug = "Clipboard",
381 .ecore_sel = ECORE_X_SELECTION_CLIPBOARD,
382 .set = ecore_x_selection_clipboard_set,
383 .clear = ecore_x_selection_clipboard_clear,
384 .request = ecore_x_selection_clipboard_request,
386 ARRAYINIT(ELM_SEL_XDND) {
388 .ecore_sel = ECORE_X_SELECTION_XDND,
389 .request = ecore_x_selection_xdnd_request,
393 /* Data for DND in progress */
394 static Saved_Type savedtypes = { NULL, NULL, 0, 0, 0, EINA_FALSE };
396 static void (*dragdonecb) (void *data, Evas_Object *obj) = NULL;
397 static void *dragdonedata = NULL;
399 static int _elm_cnp_init_count = 0;
400 /* FIXME: who left this out of XAtoms.h */
401 static Ecore_X_Atom clipboard_atom;
403 static Eina_List *pastedimages = NULL;
406 * Drag & Drop functions
409 /* FIXME: Way too many globals */
410 static Eina_List *drops = NULL;
411 static Evas_Object *dragwin = NULL;
412 static int _dragx = 0, _dragy = 0;
413 static Ecore_Event_Handler *handler_pos = NULL;
414 static Ecore_Event_Handler *handler_drop = NULL;
415 static Ecore_Event_Handler *handler_enter = NULL;
416 static Ecore_Event_Handler *handler_status = NULL;
420 /* Stringshared, so I can just compare pointers later */
421 static const char *text_uri;
424 elm_selection_set(Elm_Sel_Type selection, Evas_Object *widget, Elm_Sel_Format format, const char *selbuf)
426 #ifdef HAVE_ELEMENTARY_X
429 if ((unsigned int)selection >= (unsigned int)ELM_SEL_MAX) return EINA_FALSE;
430 if (!_elm_cnp_init_count) _elm_cnp_init();
431 if ((!selbuf) && (format != ELM_SEL_FORMAT_IMAGE))
432 return elm_selection_clear(selection, widget);
434 sel = selections + selection;
437 sel->widget = widget;
439 sel->set(elm_win_xwindow_get(widget),&selection,sizeof(Elm_Sel_Type));
440 sel->format = format;
441 sel->selbuf = selbuf ? strdup(selbuf) : NULL;
450 elm_selection_clear(Elm_Sel_Type selection, Evas_Object *widget)
452 #ifdef HAVE_ELEMENTARY_X
455 if ((unsigned int)selection >= (unsigned int)ELM_SEL_MAX) return EINA_FALSE;
456 if (!_elm_cnp_init_count) _elm_cnp_init();
458 sel = selections + selection;
460 /* No longer this selection: Consider it gone! */
461 if ((!sel->active) || (sel->widget != widget)) return EINA_TRUE;
474 elm_selection_get(Elm_Sel_Type selection, Elm_Sel_Format format,
475 Evas_Object *widget, Elm_Drop_Cb datacb, void *udata)
477 #ifdef HAVE_ELEMENTARY_X
481 if ((unsigned int)selection >= (unsigned int)ELM_SEL_MAX) return EINA_FALSE;
482 if (!_elm_cnp_init_count) _elm_cnp_init();
484 sel = selections + selection;
485 top = elm_widget_top_get(widget);
486 if (!top) return EINA_FALSE;
488 sel->requestformat = format;
489 sel->requestwidget = widget;
490 sel->request(elm_win_xwindow_get(top), ECORE_X_SELECTION_TARGET_TARGETS);
491 sel->datacb = datacb;
500 #ifdef HAVE_ELEMENTARY_X
507 if (_elm_cnp_init_count++) return EINA_TRUE;
508 for (i = 0; i < CNP_N_ATOMS; i++)
510 atoms[i].atom = ecore_x_atom_get(atoms[i].name);
511 ecore_x_selection_converter_atom_add(atoms[i].atom,
514 clipboard_atom = ecore_x_atom_get("CLIPBOARD");
516 ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, selection_clear, NULL);
517 ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, selection_notify, NULL);
519 text_uri = eina_stringshare_add("text/uri-list");
524 selection_clear(void *udata __UNUSED__, int type __UNUSED__, void *event)
526 Ecore_X_Event_Selection_Clear *ev = event;
530 for (i = 0; i < ELM_SEL_MAX; i++)
532 if (selections[i].ecore_sel == ev->selection) break;
534 cnp_debug("selection %d clear\n", i);
535 /* Not me... Don't care */
536 if (i == ELM_SEL_MAX) return ECORE_CALLBACK_PASS_ON;
538 sel = selections + i;
543 return ECORE_CALLBACK_PASS_ON;
548 * Response to a selection notify:
549 * - So we have asked for the selection list.
550 * - If it's the targets list, parse it, and fire of what we want,
551 * else it's the data we want.
554 selection_notify(void *udata __UNUSED__, int type __UNUSED__, void *event)
556 Ecore_X_Event_Selection_Notify *ev = event;
560 cnp_debug("selection notify callback: %d\n",ev->selection);
561 switch (ev->selection)
563 case ECORE_X_SELECTION_CLIPBOARD:
564 sel = selections + ELM_SEL_CLIPBOARD;
566 case ECORE_X_SELECTION_PRIMARY:
567 sel = selections + ELM_SEL_PRIMARY;
569 case ECORE_X_SELECTION_SECONDARY:
570 sel = selections + ELM_SEL_SECONDARY;
572 case ECORE_X_SELECTION_XDND:
573 sel = selections + ELM_SEL_XDND;
576 return ECORE_CALLBACK_PASS_ON;
578 cnp_debug("Target is %s\n", ev->target);
580 for (i = 0; i < CNP_N_ATOMS; i++)
582 if (!strcmp(ev->target, atoms[i].name))
586 cnp_debug("Found something: %s\n", atoms[i].name);
587 atoms[i].notify(sel, ev);
591 cnp_debug("Ignored: No handler!\n");
596 return ECORE_CALLBACK_PASS_ON;
602 targets_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
608 if (!data_ret) return EINA_FALSE;
610 sel = selections + *((int *)data);
612 for (i = 0, count = 0; i < CNP_N_ATOMS ; i++)
614 if (sel->format & atoms[i].formats) count++;
617 aret = malloc(sizeof(Ecore_X_Atom) * count);
618 for (i = 0, count = 0; i < CNP_N_ATOMS; i++)
620 if (sel->format & atoms[i].formats) aret[count ++] = atoms[i].atom;
624 if (typesize) *typesize = 32 /* urk */;
625 if (ttype) *ttype = ECORE_X_ATOM_ATOM;
626 if (size_ret) *size_ret = count;
632 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__)
634 cnp_debug("Image converter called\n");
639 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__)
643 cnp_debug("Vcard send called\n");
645 sel = selections + *((int *)data);
647 if (data_ret) *data_ret = strdup(sel->selbuf);
648 if (size_ret) *size_ret = strlen(sel->selbuf);
653 * Callback to handle a targets response on a selection request:
654 * So pick the format we'd like; and then request it.
657 notify_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
659 Ecore_X_Selection_Data_Targets *targets;
660 Ecore_X_Atom *atomlist;
663 targets = notify->data;
664 atomlist = (Ecore_X_Atom *)(targets->data.data);
666 for (j = 1; j < CNP_N_ATOMS; j++)
668 cnp_debug("\t%s %d\n", atoms[j].name, atoms[j].atom);
669 if (!(atoms[j].formats & sel->requestformat)) continue;
670 for (i = 0; i < targets->data.length; i++)
672 if ((atoms[j].atom == atomlist[i]) && (atoms[j].notify))
674 cnp_debug("Atom %s matches\n",atoms[j].name);
680 cnp_debug("Couldn't find anything that matches\n");
681 return ECORE_CALLBACK_PASS_ON;
684 cnp_debug("Sending request for %s\n",atoms[j].name);
685 sel->request(elm_win_xwindow_get(sel->requestwidget), atoms[j].name);
687 return ECORE_CALLBACK_PASS_ON;
691 response_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
693 Ecore_X_Selection_Data_Targets *targets;
694 Ecore_X_Atom *atomlist;
698 targets = notify->data;
699 atomlist = (Ecore_X_Atom *)(targets->data.data);
701 /* Start from 1: Skip targets */
702 for (j = 1 ; j < CNP_N_ATOMS ; j ++)
704 if (!(atoms[j].formats & sel->requestformat)) continue;
705 for (i = 0 ; i < targets->data.length ; i ++)
707 if ((atoms[j].atom == atomlist[i]) && (atoms[j].response))
709 /* Found a match: Use it */
715 if (j == CNP_N_ATOMS)
717 cnp_debug("No matching type found\n");
721 top = elm_widget_top_get(sel->requestwidget);
724 sel->request(elm_win_xwindow_get(top), atoms[j].name);
730 notify_handler_text(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
732 Ecore_X_Selection_Data *data;
739 Elm_Selection_Data ddata;
741 str = mark_up((char *)data->data, data->length, NULL);
742 ddata.x = ddata.y = 0;
743 ddata.format = ELM_SEL_FORMAT_TEXT;
745 ddata.len = data->length;
746 sel->datacb(sel->udata, sel->widget, &ddata);
751 cnp_debug("Notify handler text %d %d %p\n", data->format,data->length, data->data);
752 str = mark_up((char *)data->data, data->length, NULL);
753 cnp_debug("String is %s (from %s)\n", str, data->data);
754 elm_entry_entry_insert(sel->requestwidget, str);
761 * So someone is pasting an image into my entry or widget...
764 notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
766 Ecore_X_Selection_Data *data;
767 Ecore_X_Selection_Data_Files *files;
772 cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
773 if (data->content == ECORE_X_SELECTION_CONTENT_FILES)
775 cnp_debug("got a files list\n");
776 files = notify->data;
777 if (files->num_files > 1)
779 /* Don't handle many items */
780 cnp_debug("more then one file: Bailing\n");
785 else p = (char *)data->data;
788 cnp_debug("Couldn't find a file\n");
791 cnp_debug("Got %s\n",p);
794 Elm_Selection_Data ddata;
796 ddata.x = ddata.y = 0;
797 ddata.format = ELM_SEL_FORMAT_MARKUP;
799 ddata.len = data->length;
800 sel->datacb(sel->udata, sel->widget, &ddata);
803 if (strncmp(p, "file://", 7))
805 /* Try and continue if it looks sane */
806 if (*p != '/') return 0;
808 else p += strlen("file://");
810 if (savedtypes.pi) pasteimage_free(savedtypes.pi);
811 pi = pasteimage_alloc(p, data->length);
812 if (savedtypes.textreq)
814 savedtypes.textreq = 0;
819 pasteimage_append(pi, sel->requestwidget);
820 savedtypes.pi = NULL;
826 * Just receieved an vcard, either through cut and paste, or dnd.
829 vcard_receive(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
833 Ecore_X_Selection_Data *data;
836 cnp_debug("vcard receive\n");
838 if (sel == (selections + ELM_SEL_XDND))
840 Elm_Selection_Data ddata;
842 cnp_debug("drag & drop\n");
843 /* FIXME: this needs to be generic: Used for all receives */
844 EINA_LIST_FOREACH(drops, l, dropable)
846 if (dropable->obj == sel->requestwidget) break;
850 cnp_debug("Unable to find drop object");
851 ecore_x_dnd_send_finished();
854 dropable = eina_list_data_get(l);
855 ddata.x = savedtypes.x;
856 ddata.y = savedtypes.y;
857 ddata.format = ELM_SEL_FORMAT_VCARD;
858 ddata.data = data->data;
859 ddata.len = data->length;
860 dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
861 ecore_x_dnd_send_finished();
863 else if (sel->datacb)
865 Elm_Selection_Data ddata;
866 ddata.x = ddata.y = 0;
867 ddata.format = ELM_SEL_FORMAT_IMAGE;
868 ddata.data = data->data;
869 ddata.len = data->length;
870 sel->datacb(sel->udata, sel->widget, &ddata);
874 cnp_debug("Paste request\n");
883 notify_handler_image(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
885 Ecore_X_Selection_Data *data;
889 cnp_debug("got a png (or a jpeg)!\n");
892 cnp_debug("Size if %d\n", data->length);
896 Elm_Selection_Data ddata;
898 ddata.x = ddata.y = 0;
899 ddata.format = ELM_SEL_FORMAT_IMAGE;
900 ddata.data = data->data;
901 ddata.len = data->length;
902 sel->datacb(sel->udata, sel->widget, &ddata);
906 /* generate tmp name */
907 tmp = elm_cnp_tempfile_create(data->length);
908 memcpy(tmp->map, data->data, data->length);
909 munmap(tmp->map,data->length);
911 /* FIXME: Add to paste image data to clean up */
912 pi = pasteimage_alloc(tmp->filename, data->length);
913 pasteimage_append(pi, sel->requestwidget);
921 * Warning: Generic text/html can';t handle it sanely.
922 * Firefox sends ucs2 (i think).
923 * chrome sends utf8... blerg
926 notify_handler_html(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
928 Ecore_X_Selection_Data *data;
930 cnp_debug("Got some HTML: Checking encoding is useful\n");
935 Elm_Selection_Data ddata;
936 ddata.x = ddata.y = 0;
937 ddata.format = ELM_SEL_FORMAT_HTML;
938 ddata.data = data->data;
939 ddata.len = data->length;
940 sel->datacb(sel->udata, sel->widget, &ddata);
944 char *stripstr = NULL;
945 stripstr = malloc(sizeof(char) * (data->length + 1));
946 strncpy(stripstr, (char *)data->data, data->length);
947 stripstr[data->length] = '\0';
948 cnp_debug("String is %s (%d bytes)\n", stripstr, data->length);
949 elm_entry_entry_insert(sel->requestwidget, stripstr);
956 text_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
960 cnp_debug("text converter\n");
961 sel = selections + *((int *)data);
962 if (!sel->active) return EINA_TRUE;
964 if ((sel->format == ELM_SEL_FORMAT_MARKUP) ||
965 (sel->format == ELM_SEL_FORMAT_HTML))
967 *data_ret = remove_tags(sel->selbuf, size_ret);
969 else if (sel->format == ELM_SEL_FORMAT_TEXT)
971 *data_ret = strdup(sel->selbuf);
972 *size_ret = strlen(sel->selbuf);
974 else if (sel->format == ELM_SEL_FORMAT_IMAGE)
976 cnp_debug("Image %s\n", evas_object_type_get(sel->widget));
977 cnp_debug("Elm type: %s\n", elm_object_widget_type_get(sel->widget));
978 evas_object_image_file_get(elm_photocam_internal_image_get(sel->widget), (const char **)data_ret, NULL);
979 if (!*data_ret) *data_ret = strdup("No file");
980 else *data_ret = strdup(*data_ret);
981 *size_ret = strlen(*data_ret);
987 edje_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
991 sel = selections + *((int *)data);
992 if (data_ret) *data_ret = strdup(sel->selbuf);
993 if (size_ret) *size_ret = strlen(sel->selbuf);
1000 html_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
1004 sel = selections + *(int *)data;
1005 if (data_ret) *data_ret = strdup(sel->selbuf);
1006 if (size_ret) *size_ret = strlen(sel->selbuf);
1012 uri_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **data_ret, int *size_ret, Ecore_X_Atom *ttype __UNUSED__, int *typesize __UNUSED__)
1015 sel = selections + *((int *)data);
1016 cnp_debug("Uri converter\n");
1017 if (data_ret) *data_ret = strdup(sel->selbuf);
1018 if (size_ret) *size_ret = strlen(sel->selbuf);
1023 * Image paste provide
1026 /* FIXME: Should add provider for each pasted item: Use data to store it
1028 static Evas_Object *
1029 image_provider(void *images __UNUSED__, Evas_Object *entry, const char *item)
1034 cnp_debug("image provider for %s called\n", item);
1035 EINA_LIST_FOREACH(pastedimages, l, pi)
1037 cnp_debug("is it %s?\n",pi->tag);
1038 if (!strcmp(pi->tag, item))
1042 o = evas_object_image_filled_add(evas_object_evas_get(entry));
1043 /* FIXME: Handle eets */
1044 cnp_debug("file is %s (object is %p)\n", pi->file, o);
1045 evas_object_image_file_set(o, pi->file, NULL);
1046 evas_object_show(o);
1054 static Paste_Image *
1055 pasteimage_alloc(const char *file, int pathlen)
1059 char *buf, *filebuf;
1060 int prefixlen = strlen("file://");
1062 pi = calloc(1, sizeof(Paste_Image));
1063 if (!pi) return NULL;
1065 len = snprintf(NULL, 0, "pasteimage-%p", pi);
1073 snprintf(buf, len, "pasteimage-%p", pi);
1078 if (strstr(file,"file://")) file += prefixlen;
1079 filebuf = alloca(sizeof(char) * (pathlen - prefixlen + 1));
1080 strncpy(filebuf, file, pathlen - prefixlen);
1081 filebuf[pathlen-prefixlen] = '\0';
1082 pi->file = strdup(filebuf);
1089 pasteimage_free(Paste_Image *pi)
1092 if (pi->file) free((void*)pi->file);
1093 if (pi->tag) free((void*)pi->tag);
1098 pasteimage_provider_set(Evas_Object *entry)
1103 if (!entry) return EINA_FALSE;
1104 type = elm_widget_type_get(entry);
1105 cnp_debug("type is %s\n", type);
1106 if ((!type) || (strcmp(type, "entry"))) return EINA_FALSE;
1108 v = evas_object_data_get(entry, PROVIDER_SET);
1111 evas_object_data_set(entry, PROVIDER_SET, pasteimage_provider_set);
1112 elm_entry_item_provider_append(entry, image_provider, NULL);
1113 evas_object_event_callback_add(entry, EVAS_CALLBACK_FREE,
1114 entry_deleted, NULL);
1121 pasteimage_append(Paste_Image *pi, Evas_Object *entry)
1124 char *tagstring = "<item absize=240x180 href=file://%s></item>";
1126 if (!pi) return EINA_FALSE;
1127 if (!entry) return EINA_FALSE;
1129 pasteimage_provider_set(entry);
1131 pastedimages = eina_list_append(pastedimages, pi);
1132 entrytag = alloca(sizeof(char)*(strlen(tagstring)+strlen(pi->file)+1));
1133 snprintf(entrytag, (strlen(tagstring)+strlen(pi->file)), tagstring, pi->file);
1134 elm_entry_entry_insert(entry, entrytag);
1140 entry_deleted(void *images __UNUSED__, Evas *e __UNUSED__, Evas_Object *entry, void *unused __UNUSED__)
1145 EINA_LIST_FOREACH_SAFE(pastedimages, l, next, pi)
1147 if (pi->entry == entry)
1148 pastedimages = eina_list_remove_list(pastedimages, l);
1154 remove_tags(const char *p, int *len)
1158 if (!p) return NULL;
1160 q = malloc(strlen(p) + 1);
1161 if (!q) return NULL;
1166 if ((*p != '<') && (*p != '&')) *q++ = *p++;
1169 if ((p[1] == 'b') && (p[2] == 'r') &&
1170 ((p[3] == ' ') || (p[3] == '/') || (p[3] == '>')))
1172 while ((*p) && (*p != '>')) p++;
1178 for (i = 0 ; i < N_ESCAPES ; i++)
1180 if (!strncmp(p,escapes[i].escape, strlen(escapes[i].escape)))
1182 p += strlen(escapes[i].escape);
1183 *q = escapes[i].value;
1188 if (i == N_ESCAPES) *q ++= '&';
1192 if (len) *len = q - ret;
1198 mark_up(const char *start, int inlen, int *lenp)
1203 const char *endp = NULL;
1205 if (!start) return NULL;
1206 if (inlen >= 0) endp = start + inlen;
1207 /* First pass: Count characters */
1208 for (l = 0, p = start; ((!endp) || (p < endp)) && (*p); p++)
1210 for (i = 0 ; i < N_ESCAPES ; i ++)
1212 if (*p == escapes[i].value)
1214 l += strlen(escapes[i].escape);
1218 if (i == N_ESCAPES) l++;
1221 q = ret = malloc(l + 1);
1223 /* Second pass: Change characters */
1224 for (p = start; *p; )
1226 for (i = 0; i < N_ESCAPES; i++)
1228 if (*p == escapes[i].value)
1230 strcpy(q, escapes[i].escape);
1231 q += strlen(escapes[i].escape);
1236 if (i == N_ESCAPES) *q++ = *p++;
1240 if (lenp) *lenp = l;
1246 _dnd_enter(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1248 Ecore_X_Event_Xdnd_Enter *enter = ev;
1252 if ((!enter) || (!enter->num_types) || (!enter->types)) return EINA_TRUE;
1254 cnp_debug("Types\n");
1255 savedtypes.ntypes = enter->num_types;
1256 if (savedtypes.types) free(savedtypes.types);
1257 savedtypes.types = malloc(sizeof(char *) * enter->num_types);
1258 if (!savedtypes.types) return EINA_FALSE;
1260 for (i = 0; i < enter->num_types; i++)
1262 savedtypes.types[i] = eina_stringshare_add(enter->types[i]);
1263 cnp_debug("Type is %s %p %p\n", enter->types[i],
1264 savedtypes.types[i],text_uri);
1265 if (savedtypes.types[i] == text_uri)
1267 /* Request it, so we know what it is */
1268 cnp_debug("Sending uri request\n");
1269 savedtypes.textreq = 1;
1270 savedtypes.pi = NULL; /* FIXME: Free? */
1271 ecore_x_selection_xdnd_request(enter->win, text_uri);
1275 /* FIXME: Find an object and make it current */
1280 _dnd_drop(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1282 struct _Ecore_X_Event_Xdnd_Drop *drop;
1286 Ecore_X_Window xwin;
1287 Elm_Selection_Data ddata;
1293 // check we still have something to drop
1294 if (!drops) return EINA_TRUE;
1296 /* Find any widget in our window; then work out geometry rel to our window */
1297 for (l = drops; l; l = l->next)
1300 xwin = (Ecore_X_Window)ecore_evas_window_get
1301 (ecore_evas_ecore_evas_get(evas_object_evas_get
1303 if (xwin == drop->win) break;
1305 /* didn't find a window */
1306 if (!l) return EINA_TRUE;
1308 /* Calculate real (widget relative) position */
1309 // - window position
1310 // - widget position
1311 ee = ecore_evas_ecore_evas_get(evas_object_evas_get(dropable->obj));
1312 ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
1313 savedtypes.x = drop->position.x - x;
1314 savedtypes.y = drop->position.y - y;
1316 cnp_debug("Drop position is %d,%d\n", savedtypes.x, savedtypes.y);
1318 for (; l; l = l->next)
1321 evas_object_geometry_get(dropable->obj, &x, &y, &w, &h);
1322 if ((savedtypes.x >= x) && (savedtypes.y >= y) &&
1323 (savedtypes.x < x + w) && (savedtypes.y < y + h))
1327 if (!l) return EINA_TRUE; /* didn't find one */
1329 evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL);
1333 /* Find our type from the previous list */
1334 for (i = 0; i < CNP_N_ATOMS; i++)
1336 for (j = 0; j < savedtypes.ntypes; j++)
1338 if (!strcmp(savedtypes.types[j], atoms[i].name)) goto found;
1342 cnp_debug("Didn't find a target\n");
1346 cnp_debug("Found a target we'd like: %s\n", atoms[i].name);
1347 cnp_debug("0x%x\n",xwin);
1349 if (i == CNP_ATOM_text_urilist)
1351 cnp_debug("We found a URI... (%scached)\n", savedtypes.pi ? "" : "not ");
1355 char *tagstring = "<item absize=240x180 href=file://%s></item>";
1357 ddata.x = savedtypes.x;
1358 ddata.y = savedtypes.y;
1360 if (dropable->types & ELM_SEL_FORMAT_IMAGE)
1362 cnp_debug("Doing image insert (%s)\n", savedtypes.pi->file);
1363 ddata.format = ELM_SEL_FORMAT_IMAGE;
1364 ddata.data = (char *)savedtypes.pi->file;
1365 dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1366 ecore_x_dnd_send_finished();
1368 pasteimage_free(savedtypes.pi);
1369 savedtypes.pi = NULL;
1373 else if (dropable->types & ELM_SEL_FORMAT_MARKUP)
1375 ddata.format = ELM_SEL_FORMAT_MARKUP;
1376 pasteimage_provider_set(dropable->obj);
1378 pastedimages = eina_list_append(pastedimages, savedtypes.pi);
1379 entrytag = alloca(sizeof(char)*(strlen(tagstring)+strlen(savedtypes.pi->file)+1));
1380 snprintf(entrytag, (strlen(tagstring)+strlen(savedtypes.pi->file)),
1381 tagstring, savedtypes.pi->file);
1382 ddata.data = entrytag;
1383 cnp_debug("Insert %s\n", (char *)ddata.data);
1384 dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
1385 ecore_x_dnd_send_finished();
1389 else if (savedtypes.textreq)
1391 /* Already asked: Pretend we asked now, and paste immediately when
1393 savedtypes.textreq = 0;
1394 ecore_x_dnd_send_finished();
1399 cnp_debug("doing a request then\n");
1400 selections[ELM_SEL_XDND].requestwidget = dropable->obj;
1401 selections[ELM_SEL_XDND].requestformat = ELM_SEL_FORMAT_MARKUP;
1402 selections[ELM_SEL_XDND].active = EINA_TRUE;
1404 ecore_x_selection_xdnd_request(xwin, atoms[i].name);
1409 _dnd_position(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1411 struct _Ecore_X_Event_Xdnd_Position *pos;
1412 Ecore_X_Rectangle rect;
1416 /* Need to send a status back */
1417 /* FIXME: Should check I can drop here */
1418 /* FIXME: Should highlight widget */
1419 rect.x = pos->position.x - 5;
1420 rect.y = pos->position.y - 5;
1423 ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, pos->action);
1429 * When dragging this is callback response from the destination.
1430 * The important thing we care about: Can we drop; thus update cursor
1434 _dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
1436 struct _Ecore_X_Event_Xdnd_Status *status = ev;
1438 if (!status) return EINA_TRUE;
1440 /* Only thing we care about: will accept */
1441 if (status->will_accept)
1443 cnp_debug("Will accept\n");
1446 { /* Won't accept */
1447 cnp_debug("Won't accept accept\n");
1453 * Add a widget as drop target.
1456 elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, void *cbdata)
1459 Ecore_X_Window xwin;
1462 if (!obj) return EINA_FALSE;
1463 if (!_elm_cnp_init_count) _elm_cnp_init();
1465 /* Is this the first? */
1466 first = (!drops) ? 1 : 0;
1468 drop = calloc(1, sizeof(Dropable));
1469 if (!drop) return EINA_FALSE;
1470 drop->dropcb = dropcb;
1471 drop->cbdata = cbdata;
1473 /* FIXME: Check it's not already there */
1475 /* FIXME: Check for eina's deranged error method */
1476 drops = eina_list_append(drops, drop);
1478 if (!drops/* || or other error */)
1485 /* Something for now */
1486 drop->types = format;
1488 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1489 /* I love C and varargs */
1490 (Evas_Object_Event_Cb)elm_drop_target_del,
1492 /* FIXME: Handle resizes */
1494 /* If not the first: We're done */
1495 if (!first) return EINA_TRUE;
1497 xwin = (Ecore_X_Window)ecore_evas_window_get
1498 (ecore_evas_ecore_evas_get(evas_object_evas_get(obj)));
1500 ecore_x_dnd_aware_set(xwin, EINA_TRUE);
1502 cnp_debug("Adding drop target calls\n");
1503 handler_enter = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
1505 handler_pos = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
1506 _dnd_position, NULL);
1507 handler_drop = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
1514 elm_drop_target_del(Evas_Object *obj)
1516 Dropable *drop,*del;
1518 Ecore_X_Window xwin;
1521 EINA_LIST_FOREACH(drops, item, drop)
1523 if (drop->obj == obj)
1525 drops = eina_list_remove_list(drops, item);
1530 if (!del) return EINA_FALSE;
1532 evas_object_event_callback_del(obj, EVAS_CALLBACK_FREE,
1533 (Evas_Object_Event_Cb)elm_drop_target_del);
1535 /* If still drops there: All fine.. continue */
1536 if (drops) return EINA_TRUE;
1538 cnp_debug("Disabling DND\n");
1539 xwin = (Ecore_X_Window)ecore_evas_window_get
1540 (ecore_evas_ecore_evas_get(evas_object_evas_get(obj)));
1541 ecore_x_dnd_aware_set(xwin, EINA_FALSE);
1543 ecore_event_handler_del(handler_pos);
1544 ecore_event_handler_del(handler_drop);
1545 ecore_event_handler_del(handler_enter);
1549 pasteimage_free(savedtypes.pi);
1550 savedtypes.pi = NULL;
1558 _drag_mouse_up(void *un __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *data __UNUSED__)
1560 evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP, _drag_mouse_up);
1564 dragdonecb(dragdonecb,selections[ELM_SEL_XDND].widget);
1569 evas_object_del(dragwin);
1575 _drag_move(void *data __UNUSED__, Ecore_X_Xdnd_Position *pos)
1577 evas_object_move(dragwin,
1578 pos->position.x - _dragx,
1579 pos->position.y - _dragy);
1584 elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, void (*dragdone) (void *data, Evas_Object *), void *donecbdata)
1586 Ecore_X_Window xwin;
1588 Elm_Sel_Type xdnd = ELM_SEL_XDND;
1590 int x, y, x2, y2, x3, y3;
1594 if (!_elm_cnp_init_count) _elm_cnp_init();
1596 xwin = elm_win_xwindow_get(obj);
1598 cnp_debug("starting drag...\n");
1600 ecore_x_dnd_type_set(xwin, "text/uri-list", 1);
1601 sel = selections + ELM_SEL_XDND;
1604 sel->format = format;
1605 sel->selbuf = data ? strdup(data) : NULL;
1606 dragdonecb = dragdone;
1607 dragdonedata = donecbdata;
1609 ecore_x_dnd_callback_pos_update_set(_drag_move, NULL);
1610 ecore_x_dnd_begin(xwin, (unsigned char *)&xdnd, sizeof(Elm_Sel_Type));
1611 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
1612 _drag_mouse_up, NULL);
1614 handler_status = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
1617 dragwin = elm_win_add(NULL, "Elm Drag Object", ELM_WIN_UTILITY);
1618 elm_win_override_set(dragwin, 1);
1620 /* FIXME: Images only */
1621 icon = elm_icon_add(dragwin);
1622 elm_icon_file_set(icon, data + 7, NULL); /* 7!? "file://" */
1623 elm_win_resize_object_add(dragwin,icon);
1624 evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1625 evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL);
1627 /* Position subwindow appropriately */
1628 ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
1629 ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
1630 evas_object_geometry_get(obj, &x2, &y2, &w, &h);
1633 evas_object_move(dragwin, x, y);
1634 evas_object_resize(icon, w, h);
1635 evas_object_resize(dragwin, w, h);
1637 evas_object_show(icon);
1638 evas_object_show(dragwin);
1640 evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x3, &y3);
1648 elm_cnp_tempfile_create(int size)
1651 const char *tmppath;
1654 info = malloc(sizeof(Tmp_Info));
1655 if (!info) return NULL;
1657 tmppath = getenv("TMP");
1658 if (!tmppath) tmppath = P_tmpdir;
1659 if (!tmppath) tmppath = "/tmp";
1660 len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-");
1667 info->filename = malloc(len);
1668 if (!info->filename)
1673 snprintf(info->filename,len,"%s/%sXXXXXX", tmppath, "elmcnpitem-");
1675 info->fd = mkstemp(info->filename);
1680 /* And before someone says anything see POSIX 1003.1-2008 page 400 */
1683 pid = (long)getpid();
1684 /* Use pid instead of /proc/self: That way if can be passed around */
1685 len = snprintf(NULL,0,"/proc/%li/fd/%i", pid, info->fd);
1690 snprintf(tmp,len, "/proc/%li/fd/%i", pid, info->fd);
1691 unlink(info->filename);
1692 free(info->filename);
1693 info->filename = tmp;
1698 cnp_debug("filename is %s\n", info->filename);
1701 /* Set map to NULL and return */
1708 if (ftruncate(info->fd, size))
1710 perror("ftruncate");
1716 info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0);
1717 if (info->map == MAP_FAILED)
1729 tmpinfo_free(Tmp_Info *info)
1731 if (!info) return 0;
1732 free(info->filename);
1738 /* Stubs for windows */
1740 elm_drag_start(Evas_Object *o, Elm_Sel_Format f, const char *d, void (*donecb)(void *, Evas_Object *),void *cbdata)
1746 elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, void *cbdata)
1752 elm_drop_target_del(Evas_Object *o)
1758 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/