]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkselection-x11.c
Fix handling of GDK_NONE
[~andy/gtk] / gdk / x11 / gdkselection-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28 #include <X11/Xlib.h>
29 #include <X11/Xatom.h>
30 #include <string.h>
31
32 #include "gdkx.h"
33 #include "gdkproperty.h"
34 #include "gdkselection.h"
35 #include "gdkprivate.h"
36 #include "gdkprivate-x11.h"
37 #include "gdkdisplay-x11.h"
38 #include "gdkalias.h"
39
40 typedef struct _OwnerInfo OwnerInfo;
41
42 struct _OwnerInfo
43 {
44   GdkAtom    selection;
45   GdkWindow *owner;
46   gulong     serial;
47 };
48
49 static GSList *owner_list;
50
51 /* When a window is destroyed we check if it is the owner
52  * of any selections. This is somewhat inefficient, but
53  * owner_list is typically short, and it is a low memory,
54  * low code solution
55  */
56 void
57 _gdk_selection_window_destroyed (GdkWindow *window)
58 {
59   GSList *tmp_list = owner_list;
60   while (tmp_list)
61     {
62       OwnerInfo *info = tmp_list->data;
63       tmp_list = tmp_list->next;
64       
65       if (info->owner == window)
66         {
67           owner_list = g_slist_remove (owner_list, info);
68           g_free (info);
69         }
70     }
71 }
72
73 /* We only pass through those SelectionClear events that actually
74  * reflect changes to the selection owner that we didn't make ourself.
75  */
76 gboolean
77 _gdk_selection_filter_clear_event (XSelectionClearEvent *event)
78 {
79   GSList *tmp_list = owner_list;
80   GdkDisplay *display = gdk_x11_lookup_xdisplay (event->display);
81   
82   while (tmp_list)
83     {
84       OwnerInfo *info = tmp_list->data;
85
86       if (gdk_drawable_get_display (info->owner) == display &&
87           info->selection == gdk_x11_xatom_to_atom_for_display (display, event->selection))
88         {
89           if ((GDK_DRAWABLE_XID (info->owner) == event->window &&
90                event->serial >= info->serial))
91             {
92               owner_list = g_slist_remove (owner_list, info);
93               g_free (info);
94               return TRUE;
95             }
96           else
97             return FALSE;
98         }
99       tmp_list = tmp_list->next;
100     }
101
102   return FALSE;
103 }
104 /**
105  * gdk_selection_owner_set_for_display:
106  * @display: the #GdkDisplay.
107  * @owner: a #GdkWindow or %NULL to indicate that the owner for
108  *         the given should be unset.
109  * @selection: an atom identifying a selection.
110  * @time_: timestamp to use when setting the selection. 
111  *         If this is older than the timestamp given last time the owner was 
112  *         set for the given selection, the request will be ignored.
113  * @send_event: if %TRUE, and the new owner is different from the current
114  *              owner, the current owner will be sent a SelectionClear event.
115  *
116  * Sets the #GdkWindow @owner as the current owner of the selection @selection.
117  * 
118  * Returns: %TRUE if the selection owner was successfully changed to owner,
119  *          otherwise %FALSE. 
120  *
121  * Since: 2.2
122  */
123 gboolean
124 gdk_selection_owner_set_for_display (GdkDisplay *display,
125                                      GdkWindow  *owner,
126                                      GdkAtom     selection,
127                                      guint32     time, 
128                                      gboolean    send_event)
129 {
130   Display *xdisplay;
131   Window xwindow;
132   Atom xselection;
133   GSList *tmp_list;
134   OwnerInfo *info;
135
136   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
137   g_return_val_if_fail (selection != GDK_NONE, FALSE);
138
139   if (display->closed)
140     return FALSE;
141
142   if (owner) 
143     {
144       if (GDK_WINDOW_DESTROYED (owner))
145         return FALSE;
146       
147       xdisplay = GDK_WINDOW_XDISPLAY (owner);
148       xwindow = GDK_WINDOW_XID (owner);
149     }
150   else 
151     {
152       xdisplay = GDK_DISPLAY_XDISPLAY (display);
153       xwindow = None;
154     }
155   
156   xselection = gdk_x11_atom_to_xatom_for_display (display, selection);
157
158   tmp_list = owner_list;
159   while (tmp_list)
160     {
161       info = tmp_list->data;
162       if (info->selection == selection) 
163         {
164           owner_list = g_slist_remove (owner_list, info);
165           g_free (info);
166           break;
167         }
168       tmp_list = tmp_list->next;
169     }
170
171   if (owner)
172     {
173       info = g_new (OwnerInfo, 1);
174       info->owner = owner;
175       info->serial = NextRequest (GDK_WINDOW_XDISPLAY (owner));
176       info->selection = selection;
177
178       owner_list = g_slist_prepend (owner_list, info);
179     }
180
181   XSetSelectionOwner (xdisplay, xselection, xwindow, time);
182
183   return (XGetSelectionOwner (xdisplay, xselection) == xwindow);
184 }
185
186 /**
187  * gdk_selection_owner_get_for_display:
188  * @display: a #GdkDisplay.
189  * @selection: an atom indentifying a selection.
190  *
191  * Determine the owner of the given selection.
192  *
193  * Note that the return value may be owned by a different 
194  * process if a foreign window was previously created for that
195  * window, but a new foreign window will never be created by this call. 
196  *
197  * Returns: if there is a selection owner for this window, and it is a 
198  *    window known to the current process, the #GdkWindow that owns the 
199  *    selection, otherwise %NULL.
200  *
201  * Since: 2.2
202  */ 
203 GdkWindow *
204 gdk_selection_owner_get_for_display (GdkDisplay *display,
205                                      GdkAtom     selection)
206 {
207   Window xwindow;
208   
209   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
210   g_return_val_if_fail (selection != GDK_NONE, NULL);
211   
212   if (display->closed)
213     return NULL;
214   
215   xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
216                                 gdk_x11_atom_to_xatom_for_display (display, 
217                                                                    selection));
218   if (xwindow == None)
219     return NULL;
220
221   return gdk_window_lookup_for_display (display, xwindow);
222 }
223
224 void
225 gdk_selection_convert (GdkWindow *requestor,
226                        GdkAtom    selection,
227                        GdkAtom    target,
228                        guint32    time)
229 {
230   GdkDisplay *display;
231
232   g_return_if_fail (selection != GDK_NONE);
233   
234   if (GDK_WINDOW_DESTROYED (requestor))
235     return;
236
237   display = GDK_WINDOW_DISPLAY (requestor);
238
239   XConvertSelection (GDK_WINDOW_XDISPLAY (requestor),
240                      gdk_x11_atom_to_xatom_for_display (display, selection),
241                      gdk_x11_atom_to_xatom_for_display (display, target),
242                      gdk_x11_atom_to_xatom_for_display (display, _gdk_selection_property), 
243                      GDK_WINDOW_XID (requestor), time);
244 }
245
246 /**
247  * gdk_selection_property_get:
248  * @requestor: the window on which the data is stored
249  * @data: location to store a pointer to the retrieved data.
250        If the retrieval failed, %NULL we be stored here, otherwise, it
251        will be non-%NULL and the returned data should be freed with g_free()
252        when you are finished using it. The length of the
253        allocated memory is one more than the length
254        of the returned data, and the final byte will always
255        be zero, to ensure nul-termination of strings.
256  * @prop_type: location to store the type of the property.
257  * @prop_format: location to store the format of the property.
258  * 
259  * Retrieves selection data that was stored by the selection
260  * data in response to a call to gdk_selection_convert(). This function
261  * will not be used by applications, who should use the #GtkClipboard
262  * API instead.
263  * 
264  * Return value: the length of the retrieved data.
265  **/
266 gint
267 gdk_selection_property_get (GdkWindow  *requestor,
268                             guchar    **data,
269                             GdkAtom    *ret_type,
270                             gint       *ret_format)
271 {
272   gulong nitems;
273   gulong nbytes;
274   gulong length = 0;            /* Quiet GCC */
275   Atom prop_type;
276   gint prop_format;
277   guchar *t = NULL;
278   GdkDisplay *display; 
279
280   g_return_val_if_fail (requestor != NULL, 0);
281   g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
282   
283   display = GDK_WINDOW_DISPLAY (requestor);
284
285   if (GDK_WINDOW_DESTROYED (requestor))
286     goto err;
287
288   t = NULL;
289
290   /* We can't delete the selection here, because it might be the INCR
291      protocol, in which case the client has to make sure they'll be
292      notified of PropertyChange events _before_ the property is deleted.
293      Otherwise there's no guarantee we'll win the race ... */
294   if (XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (requestor),
295                           GDK_DRAWABLE_XID (requestor),
296                           gdk_x11_atom_to_xatom_for_display (display, _gdk_selection_property),
297                           0, 0x1FFFFFFF /* MAXINT32 / 4 */, False, 
298                           AnyPropertyType, &prop_type, &prop_format,
299                           &nitems, &nbytes, &t) != Success)
300     goto err;
301     
302   if (prop_type != None)
303     {
304       if (ret_type)
305         *ret_type = gdk_x11_xatom_to_atom_for_display (display, prop_type);
306       if (ret_format)
307         *ret_format = prop_format;
308
309       if (prop_type == XA_ATOM ||
310           prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
311         {
312           Atom* atoms = (Atom*) t;
313           GdkAtom* atoms_dest;
314           gint num_atom, i;
315
316           if (prop_format != 32)
317             goto err;
318           
319           num_atom = nitems;
320           length = sizeof (GdkAtom) * num_atom + 1;
321
322           if (data)
323             {
324               *data = g_malloc (length);
325               (*data)[length - 1] = '\0';
326               atoms_dest = (GdkAtom *)(*data);
327           
328               for (i=0; i < num_atom; i++)
329                 atoms_dest[i] = gdk_x11_xatom_to_atom_for_display (display, atoms[i]);
330             }
331         }
332       else
333         {
334           switch (prop_format)
335             {
336             case 8:
337               length = nitems;
338               break;
339             case 16:
340               length = sizeof(short) * nitems;
341               break;
342             case 32:
343               length = sizeof(long) * nitems;
344               break;
345             default:
346               g_assert_not_reached ();
347               break;
348             }
349           
350           /* Add on an extra byte to handle null termination.  X guarantees
351              that t will be 1 longer than nitems and null terminated */
352           length += 1;
353
354           if (data)
355             *data = g_memdup (t, length);
356         }
357       
358       if (t)
359         XFree (t);
360       
361       return length - 1;
362     }
363
364  err:
365   if (ret_type)
366     *ret_type = GDK_NONE;
367   if (ret_format)
368     *ret_format = 0;
369   if (data)
370     *data = NULL;
371   
372   return 0;
373 }
374
375 /**
376  * gdk_selection_send_notify_for_display:
377  * @display: the #GdkDisplay where @requestor is realized
378  * @requestor: window to which to deliver response.
379  * @selection: selection that was requested.
380  * @target: target that was selected.
381  * @property: property in which the selection owner stored the data,
382  *            or %GDK_NONE to indicate that the request was rejected.
383  * @time_: timestamp. 
384  *
385  * Send a response to SelectionRequest event.
386  *
387  * Since: 2.2
388  **/
389 void
390 gdk_selection_send_notify_for_display (GdkDisplay       *display,
391                                        GdkNativeWindow  requestor,
392                                        GdkAtom          selection,
393                                        GdkAtom          target,
394                                        GdkAtom          property, 
395                                        guint32          time)
396 {
397   XSelectionEvent xevent;
398   
399   g_return_if_fail (GDK_IS_DISPLAY (display));
400   
401   xevent.type = SelectionNotify;
402   xevent.serial = 0;
403   xevent.send_event = True;
404   xevent.requestor = requestor;
405   xevent.selection = gdk_x11_atom_to_xatom_for_display (display, selection);
406   xevent.target = gdk_x11_atom_to_xatom_for_display (display, target);
407   if (property == GDK_NONE)
408     xevent.property = None;
409   else
410     xevent.property = gdk_x11_atom_to_xatom_for_display (display, property);
411   xevent.time = time;
412
413   _gdk_send_xevent (display, requestor, False, NoEventMask, (XEvent*) & xevent);
414 }
415
416 /**
417  * gdk_text_property_to_text_list_for_display:
418  * @display: The #GdkDisplay where the encoding is defined.
419  * @encoding: an atom representing the encoding. The most 
420  *    common values for this are STRING, or COMPOUND_TEXT. 
421  *    This is value used as the type for the property.
422  * @format: the format of the property.
423  * @text: The text data.
424  * @length: The number of items to transform.
425  * @list: location to store a terminated array of strings in 
426  *    the encoding of the current locale. This array should be 
427  *    freed using gdk_free_text_list().
428  *
429  * Convert a text string from the encoding as it is stored 
430  * in a property into an array of strings in the encoding of
431  * the current locale. (The elements of the array represent the
432  * nul-separated elements of the original text string.)
433  *
434  * Returns: the number of strings stored in list, or 0, 
435  * if the conversion failed. 
436  *
437  * Since: 2.2
438  */
439 gint
440 gdk_text_property_to_text_list_for_display (GdkDisplay   *display,
441                                             GdkAtom       encoding,
442                                             gint          format, 
443                                             const guchar *text,
444                                             gint          length,
445                                             gchar      ***list)
446 {
447   XTextProperty property;
448   gint count = 0;
449   gint res;
450   gchar **local_list;
451   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
452
453   if (list)
454     *list = NULL;
455
456   if (display->closed)
457     return 0;
458
459   property.value = (guchar *)text;
460   property.encoding = gdk_x11_atom_to_xatom_for_display (display, encoding);
461   property.format = format;
462   property.nitems = length;
463   res = XmbTextPropertyToTextList (GDK_DISPLAY_XDISPLAY (display), &property, 
464                                    &local_list, &count);
465   if (res == XNoMemory || res == XLocaleNotSupported || res == XConverterNotFound)
466     return 0;
467   else
468     {
469       if (list)
470         *list = local_list;
471       else
472         XFreeStringList (local_list);
473       
474       return count;
475     }
476 }
477
478 void
479 gdk_free_text_list (gchar **list)
480 {
481   g_return_if_fail (list != NULL);
482
483   XFreeStringList (list);
484 }
485
486 static gint
487 make_list (const gchar  *text,
488            gint          length,
489            gboolean      latin1,
490            gchar      ***list)
491 {
492   GSList *strings = NULL;
493   gint n_strings = 0;
494   gint i;
495   const gchar *p = text;
496   const gchar *q;
497   GSList *tmp_list;
498   GError *error = NULL;
499
500   while (p < text + length)
501     {
502       gchar *str;
503       
504       q = p;
505       while (*q && q < text + length)
506         q++;
507
508       if (latin1)
509         {
510           str = g_convert (p, q - p,
511                            "UTF-8", "ISO-8859-1",
512                            NULL, NULL, &error);
513
514           if (!str)
515             {
516               g_warning ("Error converting selection from STRING: %s",
517                          error->message);
518               g_error_free (error);
519             }
520         }
521       else
522         {
523           str = g_strndup (p, q - p);
524           if (!g_utf8_validate (str, -1, NULL))
525             {
526               g_warning ("Error converting selection from UTF8_STRING");
527               g_free (str);
528               str = NULL;
529             }
530         }
531
532       if (str)
533         {
534           strings = g_slist_prepend (strings, str);
535           n_strings++;
536         }
537
538       p = q + 1;
539     }
540
541   if (list)
542     {
543       *list = g_new (gchar *, n_strings + 1);
544       (*list)[n_strings] = NULL;
545     }
546      
547   i = n_strings;
548   tmp_list = strings;
549   while (tmp_list)
550     {
551       if (list)
552         (*list)[--i] = tmp_list->data;
553       else
554         g_free (tmp_list->data);
555       
556       tmp_list = tmp_list->next;
557     }
558   
559   g_slist_free (strings);
560
561   return n_strings;
562 }
563
564 /**
565  * gdk_text_property_to_utf8_list_for_display:
566  * @display:  a #GdkDisplay
567  * @encoding: an atom representing the encoding of the text
568  * @format:   the format of the property
569  * @text:     the text to convert
570  * @length:   the length of @text, in bytes
571  * @list:     location to store the list of strings or %NULL. The
572  *            list should be freed with g_strfreev().
573  * 
574  * Converts a text property in the given encoding to
575  * a list of UTF-8 strings. 
576  * 
577  * Return value: the number of strings in the resulting
578  *               list.
579  *
580  * Since: 2.2
581  **/
582 gint 
583 gdk_text_property_to_utf8_list_for_display (GdkDisplay    *display,
584                                             GdkAtom        encoding,
585                                             gint           format,
586                                             const guchar  *text,
587                                             gint           length,
588                                             gchar       ***list)
589 {
590   g_return_val_if_fail (text != NULL, 0);
591   g_return_val_if_fail (length >= 0, 0);
592   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
593   
594   if (encoding == GDK_TARGET_STRING)
595     {
596       return make_list ((gchar *)text, length, TRUE, list);
597     }
598   else if (encoding == gdk_atom_intern_static_string ("UTF8_STRING"))
599     {
600       return make_list ((gchar *)text, length, FALSE, list);
601     }
602   else
603     {
604       gchar **local_list;
605       gint local_count;
606       gint i;
607       const gchar *charset = NULL;
608       gboolean need_conversion = !g_get_charset (&charset);
609       gint count = 0;
610       GError *error = NULL;
611       
612       /* Probably COMPOUND text, we fall back to Xlib routines
613        */
614       local_count = gdk_text_property_to_text_list_for_display (display,
615                                                                 encoding,
616                                                                 format, 
617                                                                 text,
618                                                                 length,
619                                                                 &local_list);
620       if (list)
621         *list = g_new (gchar *, local_count + 1);
622       
623       for (i=0; i<local_count; i++)
624         {
625           /* list contains stuff in our default encoding
626            */
627           if (need_conversion)
628             {
629               gchar *utf = g_convert (local_list[i], -1,
630                                       "UTF-8", charset,
631                                       NULL, NULL, &error);
632               if (utf)
633                 {
634                   if (list)
635                     (*list)[count++] = utf;
636                   else
637                     g_free (utf);
638                 }
639               else
640                 {
641                   g_warning ("Error converting to UTF-8 from '%s': %s",
642                              charset, error->message);
643                   g_error_free (error);
644                   error = NULL;
645                 }
646             }
647           else
648             {
649               if (list)
650                 {
651                   if (g_utf8_validate (local_list[i], -1, NULL))
652                     (*list)[count++] = g_strdup (local_list[i]);
653                   else
654                     g_warning ("Error converting selection");
655                 }
656             }
657         }
658
659       if (local_count)
660         gdk_free_text_list (local_list);
661       
662       if (list)
663         (*list)[count] = NULL;
664
665       return count;
666     }
667 }
668
669 /**
670  * gdk_string_to_compound_text_for_display:
671  * @display:  the #GdkDisplay where the encoding is defined.
672  * @str:      a nul-terminated string.
673  * @encoding: location to store the encoding atom 
674  *            (to be used as the type for the property).
675  * @format:   location to store the format of the property
676  * @ctext:    location to store newly allocated data for the property.
677  * @length:   the length of @text, in bytes
678  * 
679  * Convert a string from the encoding of the current 
680  * locale into a form suitable for storing in a window property.
681  * 
682  * Returns: 0 upon success, non-zero upon failure. 
683  *
684  * Since: 2.2
685  **/
686 gint
687 gdk_string_to_compound_text_for_display (GdkDisplay  *display,
688                                          const gchar *str,
689                                          GdkAtom     *encoding,
690                                          gint        *format,
691                                          guchar     **ctext,
692                                          gint        *length)
693 {
694   gint res;
695   XTextProperty property;
696
697   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
698
699   if (display->closed)
700     res = XLocaleNotSupported;
701   else
702     res = XmbTextListToTextProperty (GDK_DISPLAY_XDISPLAY (display), 
703                                      (char **)&str, 1, XCompoundTextStyle,
704                                      &property);
705   if (res != Success)
706     {
707       property.encoding = None;
708       property.format = None;
709       property.value = NULL;
710       property.nitems = 0;
711     }
712
713   if (encoding)
714     *encoding = gdk_x11_xatom_to_atom_for_display (display, property.encoding);
715   if (format)
716     *format = property.format;
717   if (ctext)
718     *ctext = property.value;
719   if (length)
720     *length = property.nitems;
721
722   return res;
723 }
724
725 /* The specifications for COMPOUND_TEXT and STRING specify that C0 and
726  * C1 are not allowed except for \n and \t, however the X conversions
727  * routines for COMPOUND_TEXT only enforce this in one direction,
728  * causing cut-and-paste of \r and \r\n separated text to fail.
729  * This routine strips out all non-allowed C0 and C1 characters
730  * from the input string and also canonicalizes \r, and \r\n to \n
731  */
732 static gchar * 
733 sanitize_utf8 (const gchar *src,
734                gboolean return_latin1)
735 {
736   gint len = strlen (src);
737   GString *result = g_string_sized_new (len);
738   const gchar *p = src;
739
740   while (*p)
741     {
742       if (*p == '\r')
743         {
744           p++;
745           if (*p == '\n')
746             p++;
747
748           g_string_append_c (result, '\n');
749         }
750       else
751         {
752           gunichar ch = g_utf8_get_char (p);
753           
754           if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
755             {
756               if (return_latin1)
757                 {
758                   if (ch <= 0xff)
759                     g_string_append_c (result, ch);
760                   else
761                     g_string_append_printf (result,
762                                             ch < 0x10000 ? "\\u%04x" : "\\U%08x",
763                                             ch);
764                 }
765               else
766                 {
767                   char buf[7];
768                   gint buflen;
769                   
770                   buflen = g_unichar_to_utf8 (ch, buf);
771                   g_string_append_len (result, buf, buflen);
772                 }
773             }
774
775           p = g_utf8_next_char (p);
776         }
777     }
778
779   return g_string_free (result, FALSE);
780 }
781
782 /**
783  * gdk_utf8_to_string_target:
784  * @str: a UTF-8 string
785  * 
786  * Converts an UTF-8 string into the best possible representation
787  * as a STRING. The representation of characters not in STRING
788  * is not specified; it may be as pseudo-escape sequences
789  * \x{ABCD}, or it may be in some other form of approximation.
790  * 
791  * Return value: the newly-allocated string, or %NULL if the
792  *               conversion failed. (It should not fail for
793  *               any properly formed UTF-8 string unless system
794  *               limits like memory or file descriptors are exceeded.)
795  **/
796 gchar *
797 gdk_utf8_to_string_target (const gchar *str)
798 {
799   return sanitize_utf8 (str, TRUE);
800 }
801
802 /**
803  * gdk_utf8_to_compound_text_for_display:
804  * @display:  a #GdkDisplay
805  * @str:      a UTF-8 string
806  * @encoding: location to store resulting encoding
807  * @format:   location to store format of the result
808  * @ctext:    location to store the data of the result
809  * @length:   location to store the length of the data
810  *            stored in @ctext
811  * 
812  * Converts from UTF-8 to compound text. 
813  * 
814  * Return value: %TRUE if the conversion succeeded, otherwise
815  *               %FALSE.
816  *
817  * Since: 2.2
818  **/
819 gboolean
820 gdk_utf8_to_compound_text_for_display (GdkDisplay  *display,
821                                        const gchar *str,
822                                        GdkAtom     *encoding,
823                                        gint        *format,
824                                        guchar     **ctext,
825                                        gint        *length)
826 {
827   gboolean need_conversion;
828   const gchar *charset;
829   gchar *locale_str, *tmp_str;
830   GError *error = NULL;
831   gboolean result;
832
833   g_return_val_if_fail (str != NULL, FALSE);
834   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
835
836   need_conversion = !g_get_charset (&charset);
837
838   tmp_str = sanitize_utf8 (str, FALSE);
839
840   if (need_conversion)
841     {
842       locale_str = g_convert (tmp_str, -1,
843                               charset, "UTF-8",
844                               NULL, NULL, &error);
845       g_free (tmp_str);
846
847       if (!locale_str)
848         {
849           if (!(error->domain = G_CONVERT_ERROR &&
850                 error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
851             {
852               g_warning ("Error converting from UTF-8 to '%s': %s",
853                          charset, error->message);
854             }
855           g_error_free (error);
856
857           if (encoding)
858             *encoding = None;
859           if (format)
860             *format = None;
861           if (ctext)
862             *ctext = NULL;
863           if (length)
864             *length = 0;
865
866           return FALSE;
867         }
868     }
869   else
870     locale_str = tmp_str;
871     
872   result = gdk_string_to_compound_text_for_display (display, locale_str,
873                                                     encoding, format, 
874                                                     ctext, length);
875   result = (result == Success? TRUE : FALSE);
876   
877   g_free (locale_str);
878
879   return result;
880 }
881
882 void gdk_free_compound_text (guchar *ctext)
883 {
884   if (ctext)
885     XFree (ctext);
886 }
887
888 #define __GDK_SELECTION_X11_C__
889 #include "gdkaliasdef.c"