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