]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkselection-x11.c
Bug 567761 – Spellfixes in GTK+ documentation
[~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   xevent.property = gdk_x11_atom_to_xatom_for_display (display, property);
408   xevent.time = time;
409
410   _gdk_send_xevent (display, requestor, False, NoEventMask, (XEvent*) & xevent);
411 }
412
413 /**
414  * gdk_text_property_to_text_list_for_display:
415  * @display: The #GdkDisplay where the encoding is defined.
416  * @encoding: an atom representing the encoding. The most 
417  *    common values for this are STRING, or COMPOUND_TEXT. 
418  *    This is value used as the type for the property.
419  * @format: the format of the property.
420  * @text: The text data.
421  * @length: The number of items to transform.
422  * @list: location to store a terminated array of strings in 
423  *    the encoding of the current locale. This array should be 
424  *    freed using gdk_free_text_list().
425  *
426  * Convert a text string from the encoding as it is stored 
427  * in a property into an array of strings in the encoding of
428  * the current locale. (The elements of the array represent the
429  * nul-separated elements of the original text string.)
430  *
431  * Returns: the number of strings stored in list, or 0, 
432  * if the conversion failed. 
433  *
434  * Since: 2.2
435  */
436 gint
437 gdk_text_property_to_text_list_for_display (GdkDisplay   *display,
438                                             GdkAtom       encoding,
439                                             gint          format, 
440                                             const guchar *text,
441                                             gint          length,
442                                             gchar      ***list)
443 {
444   XTextProperty property;
445   gint count = 0;
446   gint res;
447   gchar **local_list;
448   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
449
450   if (list)
451     *list = NULL;
452
453   if (display->closed)
454     return 0;
455
456   property.value = (guchar *)text;
457   property.encoding = gdk_x11_atom_to_xatom_for_display (display, encoding);
458   property.format = format;
459   property.nitems = length;
460   res = XmbTextPropertyToTextList (GDK_DISPLAY_XDISPLAY (display), &property, 
461                                    &local_list, &count);
462   if (res == XNoMemory || res == XLocaleNotSupported || res == XConverterNotFound)
463     return 0;
464   else
465     {
466       if (list)
467         *list = local_list;
468       else
469         XFreeStringList (local_list);
470       
471       return count;
472     }
473 }
474
475 void
476 gdk_free_text_list (gchar **list)
477 {
478   g_return_if_fail (list != NULL);
479
480   XFreeStringList (list);
481 }
482
483 static gint
484 make_list (const gchar  *text,
485            gint          length,
486            gboolean      latin1,
487            gchar      ***list)
488 {
489   GSList *strings = NULL;
490   gint n_strings = 0;
491   gint i;
492   const gchar *p = text;
493   const gchar *q;
494   GSList *tmp_list;
495   GError *error = NULL;
496
497   while (p < text + length)
498     {
499       gchar *str;
500       
501       q = p;
502       while (*q && q < text + length)
503         q++;
504
505       if (latin1)
506         {
507           str = g_convert (p, q - p,
508                            "UTF-8", "ISO-8859-1",
509                            NULL, NULL, &error);
510
511           if (!str)
512             {
513               g_warning ("Error converting selection from STRING: %s",
514                          error->message);
515               g_error_free (error);
516             }
517         }
518       else
519         {
520           str = g_strndup (p, q - p);
521           if (!g_utf8_validate (str, -1, NULL))
522             {
523               g_warning ("Error converting selection from UTF8_STRING");
524               g_free (str);
525               str = NULL;
526             }
527         }
528
529       if (str)
530         {
531           strings = g_slist_prepend (strings, str);
532           n_strings++;
533         }
534
535       p = q + 1;
536     }
537
538   if (list)
539     {
540       *list = g_new (gchar *, n_strings + 1);
541       (*list)[n_strings] = NULL;
542     }
543      
544   i = n_strings;
545   tmp_list = strings;
546   while (tmp_list)
547     {
548       if (list)
549         (*list)[--i] = tmp_list->data;
550       else
551         g_free (tmp_list->data);
552       
553       tmp_list = tmp_list->next;
554     }
555   
556   g_slist_free (strings);
557
558   return n_strings;
559 }
560
561 /**
562  * gdk_text_property_to_utf8_list_for_display:
563  * @display:  a #GdkDisplay
564  * @encoding: an atom representing the encoding of the text
565  * @format:   the format of the property
566  * @text:     the text to convert
567  * @length:   the length of @text, in bytes
568  * @list:     location to store the list of strings or %NULL. The
569  *            list should be freed with g_strfreev().
570  * 
571  * Converts a text property in the given encoding to
572  * a list of UTF-8 strings. 
573  * 
574  * Return value: the number of strings in the resulting
575  *               list.
576  *
577  * Since: 2.2
578  **/
579 gint 
580 gdk_text_property_to_utf8_list_for_display (GdkDisplay    *display,
581                                             GdkAtom        encoding,
582                                             gint           format,
583                                             const guchar  *text,
584                                             gint           length,
585                                             gchar       ***list)
586 {
587   g_return_val_if_fail (text != NULL, 0);
588   g_return_val_if_fail (length >= 0, 0);
589   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
590   
591   if (encoding == GDK_TARGET_STRING)
592     {
593       return make_list ((gchar *)text, length, TRUE, list);
594     }
595   else if (encoding == gdk_atom_intern_static_string ("UTF8_STRING"))
596     {
597       return make_list ((gchar *)text, length, FALSE, list);
598     }
599   else
600     {
601       gchar **local_list;
602       gint local_count;
603       gint i;
604       const gchar *charset = NULL;
605       gboolean need_conversion = !g_get_charset (&charset);
606       gint count = 0;
607       GError *error = NULL;
608       
609       /* Probably COMPOUND text, we fall back to Xlib routines
610        */
611       local_count = gdk_text_property_to_text_list_for_display (display,
612                                                                 encoding,
613                                                                 format, 
614                                                                 text,
615                                                                 length,
616                                                                 &local_list);
617       if (list)
618         *list = g_new (gchar *, local_count + 1);
619       
620       for (i=0; i<local_count; i++)
621         {
622           /* list contains stuff in our default encoding
623            */
624           if (need_conversion)
625             {
626               gchar *utf = g_convert (local_list[i], -1,
627                                       "UTF-8", charset,
628                                       NULL, NULL, &error);
629               if (utf)
630                 {
631                   if (list)
632                     (*list)[count++] = utf;
633                   else
634                     g_free (utf);
635                 }
636               else
637                 {
638                   g_warning ("Error converting to UTF-8 from '%s': %s",
639                              charset, error->message);
640                   g_error_free (error);
641                   error = NULL;
642                 }
643             }
644           else
645             {
646               if (list)
647                 {
648                   if (g_utf8_validate (local_list[i], -1, NULL))
649                     (*list)[count++] = g_strdup (local_list[i]);
650                   else
651                     g_warning ("Error converting selection");
652                 }
653             }
654         }
655
656       if (local_count)
657         gdk_free_text_list (local_list);
658       
659       if (list)
660         (*list)[count] = NULL;
661
662       return count;
663     }
664 }
665
666 /**
667  * gdk_string_to_compound_text_for_display:
668  * @display:  the #GdkDisplay where the encoding is defined.
669  * @str:      a nul-terminated string.
670  * @encoding: location to store the encoding atom 
671  *            (to be used as the type for the property).
672  * @format:   location to store the format of the property
673  * @ctext:    location to store newly allocated data for the property.
674  * @length:   the length of @text, in bytes
675  * 
676  * Convert a string from the encoding of the current 
677  * locale into a form suitable for storing in a window property.
678  * 
679  * Returns: 0 upon success, non-zero upon failure. 
680  *
681  * Since: 2.2
682  **/
683 gint
684 gdk_string_to_compound_text_for_display (GdkDisplay  *display,
685                                          const gchar *str,
686                                          GdkAtom     *encoding,
687                                          gint        *format,
688                                          guchar     **ctext,
689                                          gint        *length)
690 {
691   gint res;
692   XTextProperty property;
693
694   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
695
696   if (display->closed)
697     res = XLocaleNotSupported;
698   else
699     res = XmbTextListToTextProperty (GDK_DISPLAY_XDISPLAY (display), 
700                                      (char **)&str, 1, XCompoundTextStyle,
701                                      &property);
702   if (res != Success)
703     {
704       property.encoding = None;
705       property.format = None;
706       property.value = NULL;
707       property.nitems = 0;
708     }
709
710   if (encoding)
711     *encoding = gdk_x11_xatom_to_atom_for_display (display, property.encoding);
712   if (format)
713     *format = property.format;
714   if (ctext)
715     *ctext = property.value;
716   if (length)
717     *length = property.nitems;
718
719   return res;
720 }
721
722 /* The specifications for COMPOUND_TEXT and STRING specify that C0 and
723  * C1 are not allowed except for \n and \t, however the X conversions
724  * routines for COMPOUND_TEXT only enforce this in one direction,
725  * causing cut-and-paste of \r and \r\n separated text to fail.
726  * This routine strips out all non-allowed C0 and C1 characters
727  * from the input string and also canonicalizes \r, and \r\n to \n
728  */
729 static gchar * 
730 sanitize_utf8 (const gchar *src,
731                gboolean return_latin1)
732 {
733   gint len = strlen (src);
734   GString *result = g_string_sized_new (len);
735   const gchar *p = src;
736
737   while (*p)
738     {
739       if (*p == '\r')
740         {
741           p++;
742           if (*p == '\n')
743             p++;
744
745           g_string_append_c (result, '\n');
746         }
747       else
748         {
749           gunichar ch = g_utf8_get_char (p);
750           
751           if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
752             {
753               if (return_latin1)
754                 {
755                   if (ch <= 0xff)
756                     g_string_append_c (result, ch);
757                   else
758                     g_string_append_printf (result,
759                                             ch < 0x10000 ? "\\u%04x" : "\\U%08x",
760                                             ch);
761                 }
762               else
763                 {
764                   char buf[7];
765                   gint buflen;
766                   
767                   buflen = g_unichar_to_utf8 (ch, buf);
768                   g_string_append_len (result, buf, buflen);
769                 }
770             }
771
772           p = g_utf8_next_char (p);
773         }
774     }
775
776   return g_string_free (result, FALSE);
777 }
778
779 /**
780  * gdk_utf8_to_string_target:
781  * @str: a UTF-8 string
782  * 
783  * Converts an UTF-8 string into the best possible representation
784  * as a STRING. The representation of characters not in STRING
785  * is not specified; it may be as pseudo-escape sequences
786  * \x{ABCD}, or it may be in some other form of approximation.
787  * 
788  * Return value: the newly-allocated string, or %NULL if the
789  *               conversion failed. (It should not fail for
790  *               any properly formed UTF-8 string unless system
791  *               limits like memory or file descriptors are exceeded.)
792  **/
793 gchar *
794 gdk_utf8_to_string_target (const gchar *str)
795 {
796   return sanitize_utf8 (str, TRUE);
797 }
798
799 /**
800  * gdk_utf8_to_compound_text_for_display:
801  * @display:  a #GdkDisplay
802  * @str:      a UTF-8 string
803  * @encoding: location to store resulting encoding
804  * @format:   location to store format of the result
805  * @ctext:    location to store the data of the result
806  * @length:   location to store the length of the data
807  *            stored in @ctext
808  * 
809  * Converts from UTF-8 to compound text. 
810  * 
811  * Return value: %TRUE if the conversion succeeded, otherwise
812  *               %FALSE.
813  *
814  * Since: 2.2
815  **/
816 gboolean
817 gdk_utf8_to_compound_text_for_display (GdkDisplay  *display,
818                                        const gchar *str,
819                                        GdkAtom     *encoding,
820                                        gint        *format,
821                                        guchar     **ctext,
822                                        gint        *length)
823 {
824   gboolean need_conversion;
825   const gchar *charset;
826   gchar *locale_str, *tmp_str;
827   GError *error = NULL;
828   gboolean result;
829
830   g_return_val_if_fail (str != NULL, FALSE);
831   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
832
833   need_conversion = !g_get_charset (&charset);
834
835   tmp_str = sanitize_utf8 (str, FALSE);
836
837   if (need_conversion)
838     {
839       locale_str = g_convert (tmp_str, -1,
840                               charset, "UTF-8",
841                               NULL, NULL, &error);
842       g_free (tmp_str);
843
844       if (!locale_str)
845         {
846           if (!(error->domain = G_CONVERT_ERROR &&
847                 error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
848             {
849               g_warning ("Error converting from UTF-8 to '%s': %s",
850                          charset, error->message);
851             }
852           g_error_free (error);
853
854           if (encoding)
855             *encoding = None;
856           if (format)
857             *format = None;
858           if (ctext)
859             *ctext = NULL;
860           if (length)
861             *length = 0;
862
863           return FALSE;
864         }
865     }
866   else
867     locale_str = tmp_str;
868     
869   result = gdk_string_to_compound_text_for_display (display, locale_str,
870                                                     encoding, format, 
871                                                     ctext, length);
872   result = (result == Success? TRUE : FALSE);
873   
874   g_free (locale_str);
875
876   return result;
877 }
878
879 void gdk_free_compound_text (guchar *ctext)
880 {
881   if (ctext)
882     XFree (ctext);
883 }
884
885 #define __GDK_SELECTION_X11_C__
886 #include "gdkaliasdef.c"