1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif /* ifdef HAVE_CONFIG_H */
4
5 #ifdef STDC_HEADERS
6 # include <stdlib.h>
7 # include <stddef.h>
8 #else
9 # ifdef HAVE_STDLIB_H
10 # include <stdlib.h>
11 # endif
12 #endif
13
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include "Ecore.h"
18 #include "ecore_private.h"
19 #include "ecore_x_private.h"
20 #include "Ecore_X.h"
21 #include "Ecore_X_Atoms.h"
22
23 static Ecore_X_Selection_Intern selections[4];
24 static Ecore_X_Selection_Converter *converters = NULL;
25 static Ecore_X_Selection_Parser *parsers = NULL;
26
27 static int _ecore_x_selection_data_default_free(void *data);
28 static void *_ecore_x_selection_parser_files(const char *target,
29 void *data,
30 int size,
31 int format);
32 static int _ecore_x_selection_data_files_free(void *data);
33 static void *_ecore_x_selection_parser_text(const char *target,
34 void *data,
35 int size,
36 int format);
37 static void *_ecore_x_selection_parser_xmozurl(const char *target,
38 void *data,
39 int size,
40 int format);
41 static int _ecore_x_selection_data_text_free(void *data);
42 static void *_ecore_x_selection_parser_targets(const char *target,
43 void *data,
44 int size,
45 int format);
46 static int _ecore_x_selection_data_targets_free(void *data);
47
48 #define ECORE_X_SELECTION_DATA(x) ((Ecore_X_Selection_Data *)(x))
49
50 void
_ecore_x_selection_data_init(void)51 _ecore_x_selection_data_init(void)
52 {
53 /* Initialize global data */
54 memset(selections, 0, sizeof(selections));
55
56 /* Initialize converters */
57 ecore_x_selection_converter_atom_add(ECORE_X_ATOM_TEXT,
58 ecore_x_selection_converter_text);
59 #ifdef X_HAVE_UTF8_STRING
60 ecore_x_selection_converter_atom_add(ECORE_X_ATOM_UTF8_STRING,
61 ecore_x_selection_converter_text);
62 #endif /* ifdef X_HAVE_UTF8_STRING */
63 ecore_x_selection_converter_atom_add(ECORE_X_ATOM_COMPOUND_TEXT,
64 ecore_x_selection_converter_text);
65 ecore_x_selection_converter_atom_add(ECORE_X_ATOM_STRING,
66 ecore_x_selection_converter_text);
67
68 /* Initialize parsers */
69 ecore_x_selection_parser_add("text/plain",
70 _ecore_x_selection_parser_text);
71 ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_UTF8_STRING,
72 _ecore_x_selection_parser_text);
73 ecore_x_selection_parser_add("text/uri-list",
74 _ecore_x_selection_parser_files);
75 ecore_x_selection_parser_add("text/x-moz-url",
76 _ecore_x_selection_parser_xmozurl);
77 ecore_x_selection_parser_add("_NETSCAPE_URL",
78 _ecore_x_selection_parser_files);
79 ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_TARGETS,
80 _ecore_x_selection_parser_targets);
81 }
82
83 void
_ecore_x_selection_shutdown(void)84 _ecore_x_selection_shutdown(void)
85 {
86 Ecore_X_Selection_Converter *cnv;
87 Ecore_X_Selection_Parser *prs;
88 Eina_Inlist *inlist;
89
90 /* free the selection converters */
91 EINA_INLIST_FOREACH_SAFE(converters, inlist, cnv)
92 free(cnv);
93 converters = NULL;
94
95 /* free the selection parsers */
96 EINA_INLIST_FOREACH_SAFE(parsers, inlist, prs)
97 {
98 free(prs->target);
99 free(prs);
100 }
101 parsers = NULL;
102 }
103
104 Ecore_X_Selection_Intern *
_ecore_x_selection_get(Ecore_X_Atom selection)105 _ecore_x_selection_get(Ecore_X_Atom selection)
106 {
107 if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
108 return &selections[0];
109 else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
110 return &selections[1];
111 else if (selection == ECORE_X_ATOM_SELECTION_XDND)
112 return &selections[2];
113 else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
114 return &selections[3];
115 else
116 return NULL;
117 }
118
119 Eina_Bool
_ecore_x_selection_set(Window w,const void * data,int size,Ecore_X_Atom selection)120 _ecore_x_selection_set(Window w,
121 const void *data,
122 int size,
123 Ecore_X_Atom selection)
124 {
125 int in;
126 unsigned char *buf = NULL;
127
128 XSetSelectionOwner(_ecore_x_disp, selection, w, _ecore_x_event_last_time);
129 if (XGetSelectionOwner(_ecore_x_disp, selection) != w)
130 return EINA_FALSE;
131
132 if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
133 in = 0;
134 else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
135 in = 1;
136 else if (selection == ECORE_X_ATOM_SELECTION_XDND)
137 in = 2;
138 else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
139 in = 3;
140 else
141 return EINA_FALSE;
142
143 if (selections[in].data)
144 {
145 free(selections[in].data);
146 memset(&selections[in], 0, sizeof(Ecore_X_Selection_Intern));
147 }
148
149 if (data)
150 {
151 selections[in].win = w;
152 selections[in].selection = selection;
153 selections[in].length = size;
154 selections[in].time = _ecore_x_event_last_time;
155
156 buf = malloc(size);
157 if (!buf) return EINA_FALSE;
158 memcpy(buf, data, size);
159 selections[in].data = buf;
160 }
161
162 return EINA_TRUE;
163 }
164
165 /**
166 * Claim ownership of the PRIMARY selection and set its data.
167 * @param w The window to which this selection belongs
168 * @param data The data associated with the selection
169 * @param size The size of the data buffer in bytes
170 * @return Returns 1 if the ownership of the selection was successfully
171 * claimed, or 0 if unsuccessful.
172 */
173 EAPI Eina_Bool
ecore_x_selection_primary_set(Ecore_X_Window w,const void * data,int size)174 ecore_x_selection_primary_set(Ecore_X_Window w,
175 const void *data,
176 int size)
177 {
178 LOGFN;
179 return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_PRIMARY);
180 }
181
182 /**
183 * Release ownership of the primary selection
184 * @return Returns 1 if the selection was successfully cleared,
185 * or 0 if unsuccessful.
186 *
187 */
188 EAPI Eina_Bool
ecore_x_selection_primary_clear(void)189 ecore_x_selection_primary_clear(void)
190 {
191 LOGFN;
192 return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_PRIMARY);
193 }
194
195 /**
196 * Claim ownership of the SECONDARY selection and set its data.
197 * @param w The window to which this selection belongs
198 * @param data The data associated with the selection
199 * @param size The size of the data buffer in bytes
200 * @return Returns 1 if the ownership of the selection was successfully
201 * claimed, or 0 if unsuccessful.
202 */
203 EAPI Eina_Bool
ecore_x_selection_secondary_set(Ecore_X_Window w,const void * data,int size)204 ecore_x_selection_secondary_set(Ecore_X_Window w,
205 const void *data,
206 int size)
207 {
208 LOGFN;
209 return _ecore_x_selection_set(w,
210 data,
211 size,
212 ECORE_X_ATOM_SELECTION_SECONDARY);
213 }
214
215 /**
216 * Release ownership of the secondary selection
217 * @return Returns 1 if the selection was successfully cleared,
218 * or 0 if unsuccessful.
219 *
220 */
221 EAPI Eina_Bool
ecore_x_selection_secondary_clear(void)222 ecore_x_selection_secondary_clear(void)
223 {
224 LOGFN;
225 return _ecore_x_selection_set(None,
226 NULL,
227 0,
228 ECORE_X_ATOM_SELECTION_SECONDARY);
229 }
230
231 /**
232 * Claim ownership of the XDND selection and set its data.
233 * @param w The window to which this selection belongs
234 * @param data The data associated with the selection
235 * @param size The size of the data buffer in bytes
236 * @return Returns 1 if the ownership of the selection was successfully
237 * claimed, or 0 if unsuccessful.
238 */
239 EAPI Eina_Bool
ecore_x_selection_xdnd_set(Ecore_X_Window w,const void * data,int size)240 ecore_x_selection_xdnd_set(Ecore_X_Window w,
241 const void *data,
242 int size)
243 {
244 LOGFN;
245 return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_XDND);
246 }
247
248 /**
249 * Release ownership of the XDND selection
250 * @return Returns 1 if the selection was successfully cleared,
251 * or 0 if unsuccessful.
252 *
253 */
254 EAPI Eina_Bool
ecore_x_selection_xdnd_clear(void)255 ecore_x_selection_xdnd_clear(void)
256 {
257 LOGFN;
258 return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_XDND);
259 }
260
261 /**
262 * Claim ownership of the CLIPBOARD selection and set its data.
263 * @param w The window to which this selection belongs
264 * @param data The data associated with the selection
265 * @param size The size of the data buffer in bytes
266 * @return Returns 1 if the ownership of the selection was successfully
267 * claimed, or 0 if unsuccessful.
268 *
269 * Get the converted data from a previous CLIPBOARD selection
270 * request. The buffer must be freed when done with.
271 */
272 EAPI Eina_Bool
ecore_x_selection_clipboard_set(Ecore_X_Window w,const void * data,int size)273 ecore_x_selection_clipboard_set(Ecore_X_Window w,
274 const void *data,
275 int size)
276 {
277 LOGFN;
278 return _ecore_x_selection_set(w,
279 data,
280 size,
281 ECORE_X_ATOM_SELECTION_CLIPBOARD);
282 }
283
284 /**
285 * Release ownership of the clipboard selection
286 * @return Returns 1 if the selection was successfully cleared,
287 * or 0 if unsuccessful.
288 *
289 */
290 EAPI Eina_Bool
ecore_x_selection_clipboard_clear(void)291 ecore_x_selection_clipboard_clear(void)
292 {
293 LOGFN;
294 return _ecore_x_selection_set(None,
295 NULL,
296 0,
297 ECORE_X_ATOM_SELECTION_CLIPBOARD);
298 }
299
300 Ecore_X_Atom
_ecore_x_selection_target_atom_get(const char * target)301 _ecore_x_selection_target_atom_get(const char *target)
302 {
303 Ecore_X_Atom x_target;
304
305 if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT))
306 x_target = ECORE_X_ATOM_TEXT;
307 else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT))
308 x_target = ECORE_X_ATOM_COMPOUND_TEXT;
309 else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING))
310 x_target = ECORE_X_ATOM_STRING;
311 else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING))
312 x_target = ECORE_X_ATOM_UTF8_STRING;
313 else if (!strcmp(target, ECORE_X_SELECTION_TARGET_FILENAME))
314 x_target = ECORE_X_ATOM_FILE_NAME;
315 else if (!strcmp(target, ECORE_X_SELECTION_TARGET_X_MOZ_URL))
316 x_target = ECORE_X_ATOM_X_MOZ_URL;
317 else
318 x_target = ecore_x_atom_get(target);
319
320 return x_target;
321 }
322
323 char *
_ecore_x_selection_target_get(Ecore_X_Atom target)324 _ecore_x_selection_target_get(Ecore_X_Atom target)
325 {
326 /* FIXME: Should not return mem allocated with strdup or X mixed,
327 * one should use free to free, the other XFree */
328 if (target == ECORE_X_ATOM_FILE_NAME)
329 return strdup(ECORE_X_SELECTION_TARGET_FILENAME);
330 else if (target == ECORE_X_ATOM_STRING)
331 return strdup(ECORE_X_SELECTION_TARGET_STRING);
332 else if (target == ECORE_X_ATOM_UTF8_STRING)
333 return strdup(ECORE_X_SELECTION_TARGET_UTF8_STRING);
334 else if (target == ECORE_X_ATOM_TEXT)
335 return strdup(ECORE_X_SELECTION_TARGET_TEXT);
336 else if (target == ECORE_X_ATOM_X_MOZ_URL)
337 return strdup(ECORE_X_SELECTION_TARGET_X_MOZ_URL);
338 else
339 return XGetAtomName(_ecore_x_disp, target);
340 }
341
342 static void
_ecore_x_selection_request(Ecore_X_Window w,Ecore_X_Atom selection,const char * target_str)343 _ecore_x_selection_request(Ecore_X_Window w,
344 Ecore_X_Atom selection,
345 const char *target_str)
346 {
347 Ecore_X_Atom target, prop;
348
349 target = _ecore_x_selection_target_atom_get(target_str);
350
351 if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
352 prop = ECORE_X_ATOM_SELECTION_PROP_PRIMARY;
353 else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
354 prop = ECORE_X_ATOM_SELECTION_PROP_SECONDARY;
355 else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
356 prop = ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD;
357 else
358 return;
359
360 XConvertSelection(_ecore_x_disp, selection, target, prop,
361 w, CurrentTime);
362 }
363
364 EAPI void
ecore_x_selection_primary_request(Ecore_X_Window w,const char * target)365 ecore_x_selection_primary_request(Ecore_X_Window w,
366 const char *target)
367 {
368 LOGFN;
369 _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_PRIMARY, target);
370 }
371
372 EAPI void
ecore_x_selection_secondary_request(Ecore_X_Window w,const char * target)373 ecore_x_selection_secondary_request(Ecore_X_Window w,
374 const char *target)
375 {
376 LOGFN;
377 _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_SECONDARY, target);
378 }
379
380 EAPI void
ecore_x_selection_xdnd_request(Ecore_X_Window w,const char * target)381 ecore_x_selection_xdnd_request(Ecore_X_Window w,
382 const char *target)
383 {
384 Ecore_X_Atom atom;
385 Ecore_X_DND_Target *_target;
386
387 LOGFN;
388 _target = _ecore_x_dnd_target_get();
389 atom = _ecore_x_selection_target_atom_get(target);
390 XConvertSelection(_ecore_x_disp, ECORE_X_ATOM_SELECTION_XDND, atom,
391 ECORE_X_ATOM_SELECTION_PROP_XDND, w,
392 _target->time);
393 if (_ecore_xlib_sync) ecore_x_sync();
394 }
395
396 EAPI void
ecore_x_selection_clipboard_request(Ecore_X_Window w,const char * target)397 ecore_x_selection_clipboard_request(Ecore_X_Window w,
398 const char *target)
399 {
400 LOGFN;
401 _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_CLIPBOARD, target);
402 }
403
404 EAPI void
ecore_x_selection_converter_atom_add(Ecore_X_Atom target,Eina_Bool (* func)(char * target,void * data,int size,void ** data_ret,int * size_ret,Ecore_X_Atom * ttype,int * tsize))405 ecore_x_selection_converter_atom_add(Ecore_X_Atom target,
406 Eina_Bool (*func)(char *target,
407 void *data,
408 int size,
409 void **data_ret,
410 int *size_ret,
411 Ecore_X_Atom *ttype,
412 int *tsize))
413 {
414 Ecore_X_Selection_Converter *cnv;
415
416 LOGFN;
417
418 EINA_INLIST_FOREACH(converters, cnv)
419 if (cnv->target == target)
420 {
421 cnv->convert = func;
422 return;
423 }
424
425 cnv = calloc(1, sizeof(Ecore_X_Selection_Converter));
426 if (!cnv) return;
427
428 cnv->target = target;
429 cnv->convert = func;
430 converters = (Ecore_X_Selection_Converter *)eina_inlist_append
431 (EINA_INLIST_GET(converters), EINA_INLIST_GET(cnv));
432 }
433
434 EAPI void
ecore_x_selection_converter_add(char * target,Eina_Bool (* func)(char * target,void * data,int size,void ** data_ret,int * size_ret,Ecore_X_Atom *,int *))435 ecore_x_selection_converter_add(char *target,
436 Eina_Bool (*func)(char *target,
437 void *data,
438 int size,
439 void **data_ret,
440 int *size_ret,
441 Ecore_X_Atom *,
442 int *))
443 {
444 Ecore_X_Atom x_target;
445
446 if (!func || !target)
447 return;
448
449 LOGFN;
450 x_target = _ecore_x_selection_target_atom_get(target);
451
452 ecore_x_selection_converter_atom_add(x_target, func);
453 }
454
455 EAPI void
ecore_x_selection_converter_atom_del(Ecore_X_Atom target)456 ecore_x_selection_converter_atom_del(Ecore_X_Atom target)
457 {
458 Ecore_X_Selection_Converter *cnv;
459
460 LOGFN;
461
462 EINA_INLIST_FOREACH(converters, cnv)
463 {
464 if (cnv->target == target)
465 {
466 converters = (Ecore_X_Selection_Converter *)eina_inlist_remove
467 (EINA_INLIST_GET(converters), EINA_INLIST_GET(cnv));
468 free(cnv);
469 return;
470 }
471 }
472 }
473
474 EAPI void
ecore_x_selection_converter_del(char * target)475 ecore_x_selection_converter_del(char *target)
476 {
477 Ecore_X_Atom x_target;
478
479 if (!target)
480 return;
481
482 LOGFN;
483 x_target = _ecore_x_selection_target_atom_get(target);
484 ecore_x_selection_converter_atom_del(x_target);
485 }
486
487 EAPI Eina_Bool
ecore_x_selection_notify_send(Ecore_X_Window requestor,Ecore_X_Atom selection,Ecore_X_Atom target,Ecore_X_Atom property,Ecore_X_Time tim)488 ecore_x_selection_notify_send(Ecore_X_Window requestor,
489 Ecore_X_Atom selection,
490 Ecore_X_Atom target,
491 Ecore_X_Atom property,
492 Ecore_X_Time tim)
493 {
494 XEvent xev = { 0 };
495 XSelectionEvent xnotify;
496
497 LOGFN;
498 xnotify.type = SelectionNotify;
499 xnotify.display = _ecore_x_disp;
500 xnotify.requestor = requestor;
501 xnotify.selection = selection;
502 xnotify.target = target;
503 xnotify.property = property;
504 xnotify.time = tim;
505 xnotify.send_event = True;
506 xnotify.serial = 0;
507
508 xev.xselection = xnotify;
509 return (XSendEvent(_ecore_x_disp, requestor, False, 0, &xev) > 0) ? EINA_TRUE : EINA_FALSE;
510 }
511
512 /* Locate and run conversion callback for specified selection target */
513 EAPI Eina_Bool
ecore_x_selection_convert(Ecore_X_Atom selection,Ecore_X_Atom target,void ** data_ret,int * size,Ecore_X_Atom * targtype,int * typesize)514 ecore_x_selection_convert(Ecore_X_Atom selection,
515 Ecore_X_Atom target,
516 void **data_ret,
517 int *size,
518 Ecore_X_Atom *targtype,
519 int *typesize)
520 {
521 Ecore_X_Selection_Intern *sel;
522 Ecore_X_Selection_Converter *cnv;
523 void *data = NULL;
524 char *tgt_str;
525
526 LOGFN;
527 sel = _ecore_x_selection_get(selection);
528 tgt_str = _ecore_x_selection_target_get(target);
529
530 EINA_INLIST_FOREACH(converters, cnv)
531 {
532 if (cnv->target == target)
533 {
534 int r;
535 r = cnv->convert(tgt_str, sel->data, sel->length, &data, size,
536 targtype, typesize);
537 free(tgt_str);
538 if (r)
539 {
540 if (data_ret) *data_ret = data;
541 return r;
542 }
543 else
544 return EINA_FALSE;
545 }
546 }
547 free(tgt_str);
548
549 /* ICCCM says "If the selection cannot be converted into a form based on the target (and parameters, if any), the owner should refuse the SelectionRequest as previously described." */
550 return EINA_FALSE;
551
552 /* Default, just return the data
553 * data_ret = malloc(sel->length);
554 memcpy(*data_ret, sel->data, sel->length);
555 free(tgt_str);
556 return 1;
557 */
558 }
559
560 /* TODO: We need to work out a mechanism for automatic conversion to any requested
561 * locale using Ecore_Txt functions */
562 /* Converter for standard non-utf8 text targets */
563 EAPI Eina_Bool
ecore_x_selection_converter_text(char * target,void * data,int size,void ** data_ret,int * size_ret,Ecore_X_Atom * targprop EINA_UNUSED,int * s EINA_UNUSED)564 ecore_x_selection_converter_text(char *target,
565 void *data,
566 int size,
567 void **data_ret,
568 int *size_ret,
569 Ecore_X_Atom *targprop EINA_UNUSED,
570 int *s EINA_UNUSED)
571 {
572 XTextProperty text_prop;
573 char *mystr;
574 XICCEncodingStyle style;
575
576 if (!data || !size)
577 return EINA_FALSE;
578
579 LOGFN;
580 if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT))
581 style = XTextStyle;
582 else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT))
583 style = XCompoundTextStyle;
584 else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING))
585 style = XStringStyle;
586
587 #ifdef X_HAVE_UTF8_STRING
588 else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING))
589 style = XUTF8StringStyle;
590 #endif /* ifdef X_HAVE_UTF8_STRING */
591 else
592 return EINA_FALSE;
593
594 mystr = alloca(size + 1);
595 memcpy(mystr, data, size);
596 mystr[size] = '\0';
597
598 #ifdef X_HAVE_UTF8_STRING
599 if (Xutf8TextListToTextProperty(_ecore_x_disp, &mystr, 1, style,
600 &text_prop) == Success)
601 {
602 int bufsize = strlen((char *)text_prop.value);
603 char *str = malloc(bufsize + 1);
604 if (!str) return EINA_FALSE;
605 *data_ret = str;
606 memcpy(str, text_prop.value, bufsize);
607 str[bufsize] = 0;
608 *size_ret = bufsize;
609 XFree(text_prop.value);
610 return EINA_TRUE;
611 }
612
613 #else /* ifdef X_HAVE_UTF8_STRING */
614 if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style,
615 &text_prop) == Success)
616 {
617 int bufsize = strlen(text_prop.value);
618 *data_ret = malloc(bufsize);
619 if (!*data_ret) return EINA_FALSE;
620 memcpy(*data_ret, text_prop.value, bufsize);
621 *size_ret = bufsize;
622 XFree(text_prop.value);
623 return EINA_TRUE;
624 }
625
626 #endif /* ifdef X_HAVE_UTF8_STRING */
627 else
628 {
629 return EINA_TRUE;
630 }
631 }
632
633 EAPI void
ecore_x_selection_parser_add(const char * target,void * (* func)(const char * target,void * data,int size,int format))634 ecore_x_selection_parser_add(const char *target,
635 void *(*func)(const char *target, void *data,
636 int size,
637 int format))
638 {
639 Ecore_X_Selection_Parser *prs;
640
641 if (!target)
642 return;
643
644 LOGFN;
645
646 EINA_INLIST_FOREACH(parsers, prs)
647 if (!strcmp(prs->target, target))
648 {
649 prs->parse = func;
650 return;
651 }
652
653 prs = calloc(1, sizeof(Ecore_X_Selection_Parser));
654 if (!prs) return;
655
656 prs->target = strdup(target);
657 prs->parse = func;
658
659 parsers = (Ecore_X_Selection_Parser *)eina_inlist_append
660 (EINA_INLIST_GET(parsers), EINA_INLIST_GET(prs));
661 }
662
663 EAPI void
ecore_x_selection_parser_del(const char * target)664 ecore_x_selection_parser_del(const char *target)
665 {
666 Ecore_X_Selection_Parser *prs;
667
668 if (!target)
669 return;
670
671 LOGFN;
672
673 EINA_INLIST_FOREACH(parsers, prs)
674 {
675 if (!strcmp(prs->target, target))
676 {
677 parsers = (Ecore_X_Selection_Parser *)eina_inlist_remove
678 (EINA_INLIST_GET(parsers), EINA_INLIST_GET(prs));
679 free(prs->target);
680 free(prs);
681 return;
682 }
683 }
684 }
685
686 /**
687 * Change the owner and last-change time for the specified selection.
688 * @param win The owner of the specified atom.
689 * @param atom The selection atom
690 * @param tim Specifies the time
691 * @since 1.1.0
692 */
693 EAPI void
ecore_x_selection_owner_set(Ecore_X_Window win,Ecore_X_Atom atom,Ecore_X_Time tim)694 ecore_x_selection_owner_set(Ecore_X_Window win,
695 Ecore_X_Atom atom,
696 Ecore_X_Time tim)
697 {
698 XSetSelectionOwner(_ecore_x_disp, atom, win, tim);
699 }
700
701 /**
702 * Return the window that currently owns the specified selection.
703 *
704 * @param atom The specified selection atom.
705 *
706 * @return The window that currently owns the specified selection.
707 * @since 1.1.0
708 */
709 EAPI Ecore_X_Window
ecore_x_selection_owner_get(Ecore_X_Atom atom)710 ecore_x_selection_owner_get(Ecore_X_Atom atom)
711 {
712 return XGetSelectionOwner(_ecore_x_disp, atom);
713 }
714
715 /* Locate and run conversion callback for specified selection target */
716 void *
_ecore_x_selection_parse(const char * target,void * data,int size,int format)717 _ecore_x_selection_parse(const char *target,
718 void *data,
719 int size,
720 int format)
721 {
722 Ecore_X_Selection_Parser *prs;
723 Ecore_X_Selection_Data *sel;
724
725 EINA_INLIST_FOREACH(parsers, prs)
726 {
727 if (!strcmp(prs->target, target))
728 {
729 sel = prs->parse(target, data, size, format);
730 if (sel) return sel;
731 }
732 }
733
734 /* Default, just return the data */
735 sel = calloc(1, sizeof(Ecore_X_Selection_Data));
736 if (!sel) return NULL;
737 sel->free = _ecore_x_selection_data_default_free;
738 sel->length = size;
739 sel->format = format;
740 sel->data = data;
741 return sel;
742 }
743
744 static int
_ecore_x_selection_data_default_free(void * data)745 _ecore_x_selection_data_default_free(void *data)
746 {
747 Ecore_X_Selection_Data *sel;
748
749 sel = data;
750 free(sel->data);
751 free(sel);
752 return 1;
753 }
754
755 static void *
_ecore_x_selection_parser_files(const char * target,void * _data,int size,int format EINA_UNUSED)756 _ecore_x_selection_parser_files(const char *target,
757 void *_data,
758 int size,
759 int format EINA_UNUSED)
760 {
761 Ecore_X_Selection_Data_Files *sel;
762 char *data = _data;
763
764 if (strcmp(target, "text/uri-list") &&
765 strcmp(target, "_NETSCAPE_URL"))
766 return NULL;
767
768 sel = calloc(1, sizeof(Ecore_X_Selection_Data_Files));
769 if (!sel) return NULL;
770 ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_files_free;
771
772 if (data && (size > 0))
773 {
774 int i, is;
775 char *tmp;
776 char **t2;
777
778 if (data[size - 1])
779 {
780 char *t;
781
782 /* Isn't nul terminated */
783 size++;
784 t = realloc(data, size);
785 if (!t) goto done;
786 data = t;
787 data[size - 1] = 0;
788 }
789
790 tmp = malloc(size);
791 if (!tmp) goto done;
792 i = 0;
793 is = 0;
794 while ((is < size) && (data[is]))
795 {
796 if ((i == 0) && (data[is] == '#'))
797 for (; ((data[is]) && (data[is] != '\n')); is++) ;
798 else
799 {
800 if ((data[is] != '\r') &&
801 (data[is] != '\n'))
802 tmp[i++] = data[is++];
803 else
804 {
805 while ((data[is] == '\r') || (data[is] == '\n'))
806 is++;
807 tmp[i] = 0;
808 sel->num_files++;
809 t2 = realloc(sel->files, sel->num_files * sizeof(char *));
810 if (t2)
811 {
812 sel->files = t2;
813 sel->files[sel->num_files - 1] = strdup(tmp);
814 }
815 tmp[0] = 0;
816 i = 0;
817 }
818 }
819 }
820 if (i > 0)
821 {
822 tmp[i] = 0;
823 sel->num_files++;
824 t2 = realloc(sel->files, sel->num_files * sizeof(char *));
825 if (t2)
826 {
827 sel->files = t2;
828 sel->files[sel->num_files - 1] = strdup(tmp);
829 }
830 }
831
832 free(tmp);
833 }
834 done:
835 free(data);
836
837 ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_FILES;
838 ECORE_X_SELECTION_DATA(sel)->length = sel->num_files;
839
840 return ECORE_X_SELECTION_DATA(sel);
841 }
842
843 static int
_ecore_x_selection_data_files_free(void * data)844 _ecore_x_selection_data_files_free(void *data)
845 {
846 Ecore_X_Selection_Data_Files *sel;
847 int i;
848
849 sel = data;
850 if (sel->files)
851 {
852 for (i = 0; i < sel->num_files; i++)
853 free(sel->files[i]);
854 free(sel->files);
855 }
856
857 free(sel);
858 return 0;
859 }
860
861 static void *
_ecore_x_selection_parser_text(const char * target EINA_UNUSED,void * _data,int size,int format EINA_UNUSED)862 _ecore_x_selection_parser_text(const char *target EINA_UNUSED,
863 void *_data,
864 int size,
865 int format EINA_UNUSED)
866 {
867 Ecore_X_Selection_Data_Text *sel;
868 unsigned char *data = _data;
869 void *t;
870
871 sel = calloc(1, sizeof(Ecore_X_Selection_Data_Text));
872 if (!sel) return NULL;
873 if (data && data[size - 1])
874 {
875 /* Isn't nul terminated */
876 size++;
877 t = realloc(data, size);
878 if (!t)
879 {
880 free(sel);
881 return NULL;
882 }
883 data = t;
884 data[size - 1] = 0;
885 }
886
887 sel->text = (char *)data;
888 ECORE_X_SELECTION_DATA(sel)->length = size;
889 ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TEXT;
890 ECORE_X_SELECTION_DATA(sel)->data = data;
891 ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_text_free;
892 return sel;
893 }
894
895 static int
_ecore_x_selection_data_xmozurl_free(void * data)896 _ecore_x_selection_data_xmozurl_free(void *data)
897 {
898 Ecore_X_Selection_Data_X_Moz_Url *sel = data;
899 char **buf;
900
901 buf = eina_inarray_nth(sel->links, 0);
902 free(*buf);
903 eina_inarray_free(sel->links);
904 eina_inarray_free(sel->link_names);
905 free(sel);
906 return 1;
907 }
908 #ifdef HAVE_ICONV
909 # include <errno.h>
910 # include <iconv.h>
911 #endif
912 static void *
_ecore_x_selection_parser_xmozurl(const char * target EINA_UNUSED,void * _data,int size,int format EINA_UNUSED)913 _ecore_x_selection_parser_xmozurl(const char *target EINA_UNUSED,
914 void *_data,
915 int size,
916 int format EINA_UNUSED)
917 {
918 Ecore_X_Selection_Data_X_Moz_Url *sel;
919 char *prev, *n, *buf, *data = _data;
920 size_t sz;
921 int num = 0;
922
923 buf = eina_str_convert_len("UTF-16LE", "UTF-8", data, size, &sz);
924 if (!buf) return NULL;
925 sel = calloc(1, sizeof(Ecore_X_Selection_Data_X_Moz_Url));
926 if (!sel)
927 goto error_sel;
928
929 sz = strlen(buf);
930 sel->links = eina_inarray_new(sizeof(char*), 0);
931 if (!sel->links)
932 goto error_links;
933
934 sel->link_names = eina_inarray_new(sizeof(char*), 0);
935 if (!sel->link_names)
936 goto error_link_names;
937
938 prev = buf;
939 for (n = memchr(buf, '\n', sz); n; n = memchr(prev, '\n', sz - (prev - buf)))
940 {
941 n[0] = 0;
942 if (num % 2 == 0)
943 eina_inarray_push(sel->links, &prev);
944 else
945 eina_inarray_push(sel->link_names, &prev);
946 num++;
947 prev = n + 1;
948 }
949 eina_inarray_push(sel->link_names, &prev);
950
951 ECORE_X_SELECTION_DATA(sel)->length = size;
952 ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_X_MOZ_URL;
953 ECORE_X_SELECTION_DATA(sel)->data = (void*)data;
954 ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_xmozurl_free;
955 return sel;
956
957 error_link_names:
958 eina_inarray_free(sel->links);
959
960 error_links:
961 free(sel);
962
963 error_sel:
964 free(buf);
965 return NULL;
966 }
967
968 static int
_ecore_x_selection_data_text_free(void * data)969 _ecore_x_selection_data_text_free(void *data)
970 {
971 Ecore_X_Selection_Data_Text *sel;
972
973 sel = data;
974 free(sel->text);
975 free(sel);
976 return 1;
977 }
978
979 static void *
_ecore_x_selection_parser_targets(const char * target EINA_UNUSED,void * data,int size,int format EINA_UNUSED)980 _ecore_x_selection_parser_targets(const char *target EINA_UNUSED,
981 void *data,
982 int size,
983 int format EINA_UNUSED)
984 {
985 Ecore_X_Selection_Data_Targets *sel;
986 int *targets;
987 int i;
988
989 sel = calloc(1, sizeof(Ecore_X_Selection_Data_Targets));
990 if (!sel) return NULL;
991 targets = data;
992
993 sel->num_targets = size;
994 sel->targets = malloc((sel->num_targets) * sizeof(char *));
995 if (!sel->targets)
996 {
997 free(sel);
998 return NULL;
999 }
1000 for (i = 0; i < size; i++)
1001 sel->targets[i] = XGetAtomName(_ecore_x_disp, targets[i]);
1002
1003 ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_targets_free;
1004 ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TARGETS;
1005 ECORE_X_SELECTION_DATA(sel)->length = size;
1006 ECORE_X_SELECTION_DATA(sel)->data = data;
1007 return sel;
1008 }
1009
1010 static int
_ecore_x_selection_data_targets_free(void * data)1011 _ecore_x_selection_data_targets_free(void *data)
1012 {
1013 Ecore_X_Selection_Data_Targets *sel;
1014 int i;
1015
1016 sel = data;
1017
1018 if (sel->targets)
1019 {
1020 for (i = 0; i < sel->num_targets; i++)
1021 XFree(sel->targets[i]);
1022 free(sel->targets);
1023 }
1024
1025 free(ECORE_X_SELECTION_DATA(sel)->data);
1026 free(sel);
1027 return 1;
1028 }
1029
1030