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