de45c23dbbc5888f76578eb5728383b0d0b70b41
[framework/uifw/ecore.git] / src / lib / ecore_x / xlib / ecore_x_selection.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4 #include "ecore_private.h"
5 #include "Ecore.h"
6 #include "ecore_x_private.h"
7 #include "Ecore_X.h"
8 #include "Ecore_X_Atoms.h"
9
10 static Ecore_X_Selection_Intern selections[4];
11 static Ecore_X_Selection_Converter *converters = NULL;
12 static Ecore_X_Selection_Parser *parsers = NULL;
13
14 static int _ecore_x_selection_converter_text(char *target, void *data, int size, void **data_ret, int *size_ret);
15 static int _ecore_x_selection_data_default_free(void *data);
16 static void *_ecore_x_selection_parser_files(const char *target, void *data, int size, int format);
17 static int _ecore_x_selection_data_files_free(void *data);
18 static void *_ecore_x_selection_parser_text(const char *target, void *data, int size, int format);
19 static int _ecore_x_selection_data_text_free(void *data);
20 static void *_ecore_x_selection_parser_targets(const char *target, void *data, int size, int format);
21 static int _ecore_x_selection_data_targets_free(void *data);
22
23 #define ECORE_X_SELECTION_DATA(x) ((Ecore_X_Selection_Data *)(x))
24
25 void
26 _ecore_x_selection_data_init(void)
27 {
28    /* Initialize global data */
29    memset(selections, 0, sizeof(selections));
30
31    /* Initialize converters */
32    ecore_x_selection_converter_atom_add(ECORE_X_ATOM_TEXT, 
33                                         _ecore_x_selection_converter_text);
34 #ifdef X_HAVE_UTF8_STRING
35    ecore_x_selection_converter_atom_add(ECORE_X_ATOM_UTF8_STRING, 
36                                         _ecore_x_selection_converter_text);
37 #endif
38    ecore_x_selection_converter_atom_add(ECORE_X_ATOM_COMPOUND_TEXT,
39                                         _ecore_x_selection_converter_text);
40    ecore_x_selection_converter_atom_add(ECORE_X_ATOM_STRING,
41                                         _ecore_x_selection_converter_text);
42
43    /* Initialize parsers */
44    ecore_x_selection_parser_add("text/plain",
45                                 _ecore_x_selection_parser_text);
46    ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_UTF8_STRING,
47                                 _ecore_x_selection_parser_text);
48    ecore_x_selection_parser_add("text/uri-list",
49                                 _ecore_x_selection_parser_files);
50    ecore_x_selection_parser_add("_NETSCAPE_URL",
51                                 _ecore_x_selection_parser_files);
52    ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_TARGETS,
53                                 _ecore_x_selection_parser_targets);
54 }
55
56 void
57 _ecore_x_selection_shutdown(void)
58 {
59    Ecore_X_Selection_Converter *cnv;
60    Ecore_X_Selection_Parser *prs;
61
62    /* free the selection converters */
63    cnv = converters;
64    while (cnv)
65      {
66         Ecore_X_Selection_Converter *tmp;
67
68         tmp = cnv->next;
69         free(cnv);
70         cnv = tmp;
71      }
72    converters = NULL;
73
74    /* free the selection parsers */
75    prs = parsers;
76    while (prs)
77      {
78         Ecore_X_Selection_Parser *tmp;
79
80         tmp = prs;
81         prs = prs->next;
82         free(tmp->target);
83         free(tmp);
84      }
85    parsers = NULL;
86 }
87
88 Ecore_X_Selection_Intern *
89 _ecore_x_selection_get(Ecore_X_Atom selection)
90 {
91    if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
92      return &selections[0];
93    else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
94      return &selections[1];
95    else if (selection == ECORE_X_ATOM_SELECTION_XDND)
96      return &selections[2];
97    else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
98      return &selections[3];
99    else
100      return NULL;
101 }
102
103 int 
104 _ecore_x_selection_set(Window w, const void *data, int size, Ecore_X_Atom selection)
105 {
106    int in;
107    unsigned char *buf = NULL;
108    
109    XSetSelectionOwner(_ecore_x_disp, selection, w, _ecore_x_event_last_time);
110    if (XGetSelectionOwner(_ecore_x_disp, selection) != w)
111      return 0;
112    
113    if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
114      in = 0;
115    else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
116      in = 1;
117    else if (selection == ECORE_X_ATOM_SELECTION_XDND)
118      in = 2;
119    else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
120      in = 3;
121    else
122      return 0;
123
124    if (data)
125      {
126         selections[in].win = w;
127         selections[in].selection = selection;
128         selections[in].length = size;
129         selections[in].time = _ecore_x_event_last_time;
130
131         buf = malloc(size);
132         memcpy(buf, data, size);
133         selections[in].data = buf;
134      }
135    else
136      {
137         if (selections[in].data)
138           {
139              free(selections[in].data);
140              memset(&selections[in], 0, sizeof(Ecore_X_Selection_Data));
141           }
142      }
143
144    return 1;
145 }
146
147 /**
148  * Claim ownership of the PRIMARY selection and set its data.
149  * @param w    The window to which this selection belongs
150  * @param data The data associated with the selection
151  * @param size The size of the data buffer in bytes
152  * @return     Returns 1 if the ownership of the selection was successfully 
153  *             claimed, or 0 if unsuccessful.
154  */
155 EAPI int 
156 ecore_x_selection_primary_set(Ecore_X_Window w, const void *data, int size)
157 {
158    return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_PRIMARY);
159 }
160
161 /**
162  * Release ownership of the primary selection
163  * @return     Returns 1 if the selection was successfully cleared,
164  *             or 0 if unsuccessful.
165  *
166  */
167 EAPI int 
168 ecore_x_selection_primary_clear(void)
169 {
170    return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_PRIMARY);
171 }
172
173 /**
174  * Claim ownership of the SECONDARY selection and set its data.
175  * @param w    The window to which this selection belongs
176  * @param data The data associated with the selection
177  * @param size The size of the data buffer in bytes
178  * @return     Returns 1 if the ownership of the selection was successfully 
179  *             claimed, or 0 if unsuccessful.
180  */
181 EAPI int 
182 ecore_x_selection_secondary_set(Ecore_X_Window w, const void *data, int size)
183 {
184    return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_SECONDARY);
185 }
186
187 /**
188  * Release ownership of the secondary selection
189  * @return     Returns 1 if the selection was successfully cleared,
190  *             or 0 if unsuccessful.
191  *
192  */
193 EAPI int 
194 ecore_x_selection_secondary_clear(void)
195 {
196    return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_SECONDARY);
197 }
198
199 /**
200  * Claim ownership of the XDND selection and set its data.
201  * @param w    The window to which this selection belongs
202  * @param data The data associated with the selection
203  * @param size The size of the data buffer in bytes
204  * @return     Returns 1 if the ownership of the selection was successfully 
205  *             claimed, or 0 if unsuccessful.
206  */
207 EAPI int 
208 ecore_x_selection_xdnd_set(Ecore_X_Window w, const void *data, int size)
209 {
210    return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_XDND);
211 }
212
213 /**
214  * Release ownership of the XDND selection
215  * @return     Returns 1 if the selection was successfully cleared,
216  *             or 0 if unsuccessful.
217  *
218  */
219 EAPI int 
220 ecore_x_selection_xdnd_clear(void)
221 {
222    return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_XDND);
223 }
224
225 /**
226  * Claim ownership of the CLIPBOARD selection and set its data.
227  * @param w    The window to which this selection belongs
228  * @param data The data associated with the selection
229  * @param size The size of the data buffer in bytes
230  * @return     Returns 1 if the ownership of the selection was successfully 
231  *             claimed, or 0 if unsuccessful.
232  *
233  * Get the converted data from a previous CLIPBOARD selection
234  * request. The buffer must be freed when done with.
235  */
236 EAPI int 
237 ecore_x_selection_clipboard_set(Ecore_X_Window w, const void *data, int size)
238 {
239    return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_CLIPBOARD);
240 }
241
242 /**
243  * Release ownership of the clipboard selection
244  * @return     Returns 1 if the selection was successfully cleared,
245  *             or 0 if unsuccessful.
246  *
247  */
248 EAPI int 
249 ecore_x_selection_clipboard_clear(void)
250 {
251    return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_CLIPBOARD);
252 }
253
254 Ecore_X_Atom
255 _ecore_x_selection_target_atom_get(const char *target)
256 {
257    Ecore_X_Atom x_target;
258
259    if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT))
260      x_target = ECORE_X_ATOM_TEXT;
261    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT))
262      x_target = ECORE_X_ATOM_COMPOUND_TEXT;
263    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING))
264      x_target = ECORE_X_ATOM_STRING;
265    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING))
266      x_target = ECORE_X_ATOM_UTF8_STRING;
267    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_FILENAME))
268      x_target = ECORE_X_ATOM_FILE_NAME;
269    else
270      {
271         x_target = ecore_x_atom_get(target);
272      }
273
274    return x_target;
275 }
276
277 char *
278 _ecore_x_selection_target_get(Ecore_X_Atom target)
279 {
280    /* FIXME: Should not return mem allocated with strdup or X mixed,
281     * one should use free to free, the other XFree */
282    if (target == ECORE_X_ATOM_FILE_NAME)
283      return strdup(ECORE_X_SELECTION_TARGET_FILENAME);
284    else if (target == ECORE_X_ATOM_STRING)
285      return strdup(ECORE_X_SELECTION_TARGET_STRING);
286    else if (target == ECORE_X_ATOM_UTF8_STRING)
287      return strdup(ECORE_X_SELECTION_TARGET_UTF8_STRING);
288    else if (target == ECORE_X_ATOM_TEXT)
289      return strdup(ECORE_X_SELECTION_TARGET_TEXT);
290    else
291      return XGetAtomName(_ecore_x_disp, target);
292 }
293
294 static void 
295 _ecore_x_selection_request(Ecore_X_Window w, Ecore_X_Atom selection, const char *target_str) 
296 {
297    Ecore_X_Atom target, prop;
298
299    target = _ecore_x_selection_target_atom_get(target_str);
300
301    if (selection == ECORE_X_ATOM_SELECTION_PRIMARY)
302      prop = ECORE_X_ATOM_SELECTION_PROP_PRIMARY;
303    else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY)
304      prop = ECORE_X_ATOM_SELECTION_PROP_SECONDARY;
305    else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
306      prop = ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD;
307    else
308      return;
309
310    XConvertSelection(_ecore_x_disp, selection, target, prop,
311                      w, CurrentTime);
312 }
313
314 EAPI void 
315 ecore_x_selection_primary_request(Ecore_X_Window w, const char *target)
316 {
317    _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_PRIMARY, target);
318 }
319
320 EAPI void 
321 ecore_x_selection_secondary_request(Ecore_X_Window w, const char *target)
322 {
323    _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_SECONDARY, target);
324 }
325
326 EAPI void 
327 ecore_x_selection_xdnd_request(Ecore_X_Window w, const char *target)
328 {
329    Ecore_X_Atom atom;
330    Ecore_X_DND_Target *_target;
331
332    _target = _ecore_x_dnd_target_get();
333    atom = _ecore_x_selection_target_atom_get(target);
334    XConvertSelection(_ecore_x_disp, ECORE_X_ATOM_SELECTION_XDND, atom,
335                      ECORE_X_ATOM_SELECTION_PROP_XDND, w,
336                      _target->time);
337 }
338
339 EAPI void 
340 ecore_x_selection_clipboard_request(Ecore_X_Window w, const char *target)
341 {
342    _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_CLIPBOARD, target);
343 }
344
345 EAPI void
346 ecore_x_selection_converter_atom_add(Ecore_X_Atom target,
347       int (*func)(char *target, void *data, int size, void **data_ret, int *size_ret))
348 {
349    Ecore_X_Selection_Converter *cnv;
350
351    cnv = converters;
352    if (converters) 
353      {
354         while (1)
355           {
356              if (cnv->target == target)
357                {
358                   cnv->convert = func;
359                   return;
360                }
361              if (cnv->next)
362                cnv = cnv->next;
363              else
364                break;
365           }
366
367         cnv->next = calloc(1, sizeof(Ecore_X_Selection_Converter));
368         cnv = cnv->next;
369      }
370    else
371      {
372         converters = calloc(1, sizeof(Ecore_X_Selection_Converter));
373         cnv = converters;
374      }
375    cnv->target = target;
376    cnv->convert = func;
377 }
378
379 EAPI void
380 ecore_x_selection_converter_add(char *target, 
381       int (*func)(char *target, void *data, int size, void **data_ret, int *size_ret))
382 {
383    Ecore_X_Atom x_target;
384
385    if (!func || !target)
386      return;
387
388    x_target = _ecore_x_selection_target_atom_get(target);
389
390    ecore_x_selection_converter_atom_add(x_target, func);
391 }
392
393 EAPI void
394 ecore_x_selection_converter_atom_del(Ecore_X_Atom target)
395 {
396    Ecore_X_Selection_Converter *cnv, *prev_cnv;
397
398    prev_cnv = NULL;
399    cnv = converters;
400
401    while (cnv)
402      {
403         if (cnv->target == target)
404           {
405              if (prev_cnv)
406                prev_cnv->next = cnv->next;
407              else
408                converters = cnv->next; /* This was the first converter */
409              free(cnv);
410
411              return;
412           }
413         prev_cnv = cnv;
414         cnv = cnv->next;
415      }
416 }
417
418 EAPI void
419 ecore_x_selection_converter_del(char *target)
420 {
421    Ecore_X_Atom x_target;
422
423    if (!target)
424      return;
425
426    x_target = _ecore_x_selection_target_atom_get(target);
427    ecore_x_selection_converter_atom_del(x_target);
428 }
429
430 EAPI int
431 ecore_x_selection_notify_send(Ecore_X_Window requestor, Ecore_X_Atom selection, Ecore_X_Atom target, Ecore_X_Atom property, Ecore_X_Time time)
432 {
433    XEvent          xev;
434    XSelectionEvent xnotify;
435
436    xnotify.type = SelectionNotify;
437    xnotify.display = _ecore_x_disp;
438    xnotify.requestor = requestor;
439    xnotify.selection = selection;
440    xnotify.target = target;
441    xnotify.property = property;
442    xnotify.time = time;
443    xnotify.send_event = True;
444    xnotify.serial = 0;
445
446    xev.xselection = xnotify;
447    return ((XSendEvent(_ecore_x_disp, requestor, False, 0, &xev) > 0) ? 1 : 0);
448 }
449
450 /* Locate and run conversion callback for specified selection target */
451 EAPI int
452 ecore_x_selection_convert(Ecore_X_Atom selection, Ecore_X_Atom target, void **data_ret)
453 {
454    Ecore_X_Selection_Intern *sel;
455    Ecore_X_Selection_Converter *cnv;
456    void *data;
457    int size;
458    char *tgt_str;
459    
460    sel = _ecore_x_selection_get(selection);
461    tgt_str = _ecore_x_selection_target_get(target);
462
463    for (cnv = converters; cnv; cnv = cnv->next)
464      {
465         if (cnv->target == target)
466           {
467              int r;
468              r = cnv->convert(tgt_str, sel->data, sel->length, &data, &size);
469              free(tgt_str);
470              if (r)
471                {
472                   *data_ret = data;
473                   return r;
474                }
475              else
476                return 0;
477           }
478      }
479
480    /* 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." */
481    return 0; 
482
483    /* Default, just return the data 
484    *data_ret = malloc(sel->length);
485    memcpy(*data_ret, sel->data, sel->length);
486    free(tgt_str);
487    return 1;
488    */
489 }
490
491 /* TODO: We need to work out a mechanism for automatic conversion to any requested
492  * locale using Ecore_Txt functions */
493 /* Converter for standard non-utf8 text targets */
494 static int
495 _ecore_x_selection_converter_text(char *target, void *data, int size, void **data_ret, int *size_ret)
496 {
497    XTextProperty text_prop;
498    char *mystr;
499    XICCEncodingStyle style;
500
501    if (!data || !size)
502      return 0;
503
504    if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT))
505      style = XTextStyle;
506    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT))
507      style = XCompoundTextStyle;
508    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING))
509      style = XStringStyle;
510 #ifdef X_HAVE_UTF8_STRING
511    else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING))
512      style = XUTF8StringStyle;
513 #endif
514    else
515      return 0;
516
517    if (!(mystr = strdup(data)))
518      return 0;
519
520 #ifdef X_HAVE_UTF8_STRING
521    if (Xutf8TextListToTextProperty(_ecore_x_disp, &mystr, 1, style, &text_prop) == Success)
522      {
523         int bufsize = strlen((char *)text_prop.value) + 1;
524         *data_ret = malloc(bufsize);
525         memcpy(*data_ret, text_prop.value, bufsize);
526         *size_ret = bufsize;
527         XFree(text_prop.value);
528         free(mystr);
529         return 1;
530      }
531 #else
532    if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style, &text_prop) == Success)
533      {
534         int bufsize = strlen(text_prop.value) + 1;
535         *data_ret = malloc(bufsize);
536         memcpy(*data_ret, text_prop.value, bufsize);
537         *size_ret = bufsize;
538         XFree(text_prop.value);
539         free(mystr);
540         return 1;
541      }
542 #endif
543    else
544      {
545         free(mystr);
546         return 0;
547      }
548 }
549
550 EAPI void
551 ecore_x_selection_parser_add(const char *target,
552       void *(*func)(const char *target, void *data, int size, int format))
553 {
554    Ecore_X_Selection_Parser *prs;
555
556    if (!target)
557      return;
558
559    prs = parsers;
560    if (parsers) 
561      {
562         while (prs->next)
563           {
564              if (!strcmp(prs->target, target))
565                {
566                   prs->parse = func;
567                   return;
568                }
569              prs = prs->next;
570           }
571
572         prs->next = calloc(1, sizeof(Ecore_X_Selection_Parser));
573         prs = prs->next;
574      }
575    else
576      {
577         parsers = calloc(1, sizeof(Ecore_X_Selection_Parser));
578         prs = parsers;
579      }
580    prs->target = strdup(target);
581    prs->parse = func;
582 }
583
584 EAPI void
585 ecore_x_selection_parser_del(const char *target)
586 {
587    Ecore_X_Selection_Parser *prs, *prev_prs;
588
589    if (!target)
590      return;
591
592    prev_prs = NULL;
593    prs = parsers;
594
595    while (prs)
596      {
597         if (!strcmp(prs->target, target))
598           {
599              if (prev_prs)
600                prev_prs->next = prs->next;
601              else
602                parsers = prs->next; /* This was the first parser */
603              free(prs->target);
604              free(prs);
605
606              return;
607           }
608         prev_prs = prs;
609         prs = prs->next;
610      }
611 }
612
613 /* Locate and run conversion callback for specified selection target */
614 void *
615 _ecore_x_selection_parse(const char *target, void *data, int size, int format)
616 {
617    Ecore_X_Selection_Parser *prs;
618    Ecore_X_Selection_Data *sel;
619    
620    for (prs = parsers; prs; prs = prs->next)
621      {
622         if (!strcmp(prs->target, target))
623           {
624              sel = prs->parse(target, data, size, format);
625              return sel;
626           }
627      }
628
629    /* Default, just return the data */
630    sel = calloc(1, sizeof(Ecore_X_Selection_Data));
631    sel->free = _ecore_x_selection_data_default_free;
632    sel->length = size;
633    sel->format = format;
634    sel->data = data;
635    return sel;
636 }
637
638 static int
639 _ecore_x_selection_data_default_free(void *data)
640 {
641    Ecore_X_Selection_Data *sel;
642
643    sel = data;
644    free(sel->data);
645    free(sel);
646    return 1;
647 }
648
649 static void *
650 _ecore_x_selection_parser_files(const char *target, void *_data, int size, int format __UNUSED__)
651 {
652    Ecore_X_Selection_Data_Files *sel;
653    char *data = _data;
654    int i, is;
655    char *tmp;
656
657    if (strcmp(target, "text/uri-list") &&
658        strcmp(target, "_NETSCAPE_URL"))
659      return NULL;
660
661    sel = calloc(1, sizeof(Ecore_X_Selection_Data_Files));
662    ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_files_free;
663
664    if (data[size - 1])
665      {
666         /* Isn't nul terminated */
667         size++;
668         data = realloc(data, size);
669         data[size - 1] = 0;
670      }
671
672    tmp = malloc(size);
673    i = 0;
674    is = 0;
675    while ((is < size) && (data[is]))
676      {
677         if ((i == 0) && (data[is] == '#'))
678           {
679              for (; ((data[is]) && (data[is] != '\n')); is++);
680           }
681         else
682           {
683              if ((data[is] != '\r') &&
684                  (data[is] != '\n'))
685                {
686                   tmp[i++] = data[is++];
687                }
688              else
689                {
690                   while ((data[is] == '\r') || (data[is] == '\n')) is++;
691                   tmp[i] = 0;
692                   sel->num_files++;
693                   sel->files = realloc(sel->files, sel->num_files * sizeof(char *));
694                   sel->files[sel->num_files - 1] = strdup(tmp);
695                   tmp[0] = 0;
696                   i = 0;
697                }
698           }
699      }
700    if (i > 0)
701      {
702         tmp[i] = 0;
703         sel->num_files++;
704         sel->files = realloc(sel->files, sel->num_files * sizeof(char *));
705         sel->files[sel->num_files - 1] = strdup(tmp);
706      }
707    free(tmp);
708    free(data);
709
710    ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_FILES;
711    ECORE_X_SELECTION_DATA(sel)->length = sel->num_files;
712
713    return ECORE_X_SELECTION_DATA(sel);
714 }
715
716 static int
717 _ecore_x_selection_data_files_free(void *data)
718 {
719    Ecore_X_Selection_Data_Files *sel;
720    int i;
721
722    sel = data;
723    if (sel->files)
724      {
725         for (i = 0; i < sel->num_files; i++)
726           free(sel->files[i]);
727         free(sel->files);
728      }
729    free(sel);
730    return 0;
731 }
732
733 static void *
734 _ecore_x_selection_parser_text(const char *target __UNUSED__, void *_data, int size, int format __UNUSED__)
735 {
736    Ecore_X_Selection_Data_Text *sel;
737    char *data = _data;
738
739    sel = calloc(1, sizeof(Ecore_X_Selection_Data_Text));
740
741    if (data[size - 1])
742      {
743         /* Isn't nul terminated */
744         size++;
745         data = realloc(data, size);
746         data[size - 1] = 0;
747      }
748
749    sel->text = (char *)data;
750    ECORE_X_SELECTION_DATA(sel)->length = size;
751    ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TEXT;
752    ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_text_free;
753    return sel;
754 }
755
756 static int
757 _ecore_x_selection_data_text_free(void *data)
758 {
759    Ecore_X_Selection_Data_Text *sel;
760
761    sel = data;
762    free(sel->text);
763    free(sel);
764    return 1;
765 }
766
767 static void *
768 _ecore_x_selection_parser_targets(const char *target __UNUSED__, void *data, int size, int format __UNUSED__)
769 {
770    Ecore_X_Selection_Data_Targets *sel;
771    unsigned long *targets;
772    int i;
773
774    sel = calloc(1, sizeof(Ecore_X_Selection_Data_Targets));
775    targets = (unsigned long *)data;
776
777    sel->num_targets = size - 2;
778    sel->targets = malloc((size - 2) * sizeof(char *));
779    for (i = 2; i < size; i++)
780      sel->targets[i - 2] = XGetAtomName(_ecore_x_disp, targets[i]);
781    free(data);
782
783    ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_targets_free;
784    ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TARGETS;
785    ECORE_X_SELECTION_DATA(sel)->length = size;
786    return sel;
787 }
788
789 static int
790 _ecore_x_selection_data_targets_free(void *data)
791 {
792    Ecore_X_Selection_Data_Targets *sel;
793    int i;
794
795    sel = data;
796
797    if (sel->targets)
798      {
799         for (i = 0; i < sel->num_targets; i++)
800           XFree(sel->targets[i]);
801         free(sel->targets);
802      }
803    free(sel);
804    return 1;
805 }