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