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