]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkselection-x11.c
Add annotations so that methods are properly paired to objects.
[~andy/gtk] / gdk / x11 / gdkselection-x11.c
index 4cadfb63cfac9e1d9b11a2d4851d06ddf1ff9257..69761cad17152f2f218aba8476c79a5dd51d3f60 100644 (file)
  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GTK+ Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
  */
 
-#include <X11/Xlib.h>
-#include <X11/Xatom.h>
-#include <string.h>
+#include "config.h"
 
-#include "gdkproperty.h"
 #include "gdkselection.h"
+#include "gdkproperty.h"
 #include "gdkprivate.h"
 #include "gdkprivate-x11.h"
+#include "gdkdisplay-x11.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <string.h>
+
 
 typedef struct _OwnerInfo OwnerInfo;
 
@@ -50,19 +54,19 @@ static GSList *owner_list;
  * low code solution
  */
 void
-_gdk_selection_window_destroyed (GdkWindow *window)
+_gdk_x11_selection_window_destroyed (GdkWindow *window)
 {
   GSList *tmp_list = owner_list;
   while (tmp_list)
     {
       OwnerInfo *info = tmp_list->data;
       tmp_list = tmp_list->next;
-      
+
       if (info->owner == window)
-       {
-         owner_list = g_slist_remove (owner_list, info);
-         g_free (info);
-       }
+        {
+          owner_list = g_slist_remove (owner_list, info);
+          g_free (info);
+        }
     }
 }
 
@@ -70,25 +74,28 @@ _gdk_selection_window_destroyed (GdkWindow *window)
  * reflect changes to the selection owner that we didn't make ourself.
  */
 gboolean
-_gdk_selection_filter_clear_event (XSelectionClearEvent *event)
+_gdk_x11_selection_filter_clear_event (XSelectionClearEvent *event)
 {
   GSList *tmp_list = owner_list;
+  GdkDisplay *display = gdk_x11_lookup_xdisplay (event->display);
 
   while (tmp_list)
     {
       OwnerInfo *info = tmp_list->data;
-      if (info->selection == gdk_x11_xatom_to_atom (event->selection))
-       {
-         if ((GDK_DRAWABLE_XID (info->owner) == event->window &&
-              event->serial >= info->serial))
-           {
-             owner_list = g_slist_remove (owner_list, info);
-             g_free (info);
-             return TRUE;
-           }
-         else
-           return FALSE;
-       }
+
+      if (gdk_window_get_display (info->owner) == display &&
+          info->selection == gdk_x11_xatom_to_atom_for_display (display, event->selection))
+        {
+          if ((GDK_WINDOW_XID (info->owner) == event->window &&
+               event->serial >= info->serial))
+            {
+              owner_list = g_slist_remove (owner_list, info);
+              g_free (info);
+              return TRUE;
+            }
+          else
+            return FALSE;
+        }
       tmp_list = tmp_list->next;
     }
 
@@ -96,10 +103,11 @@ _gdk_selection_filter_clear_event (XSelectionClearEvent *event)
 }
 
 gboolean
-gdk_selection_owner_set (GdkWindow *owner,
-                        GdkAtom    selection,
-                        guint32    time,
-                        gboolean   send_event)
+_gdk_x11_display_set_selection_owner (GdkDisplay *display,
+                                      GdkWindow  *owner,
+                                      GdkAtom     selection,
+                                      guint32     time,
+                                      gboolean    send_event)
 {
   Display *xdisplay;
   Window xwindow;
@@ -107,32 +115,36 @@ gdk_selection_owner_set (GdkWindow *owner,
   GSList *tmp_list;
   OwnerInfo *info;
 
-  xselection = gdk_x11_atom_to_xatom (selection);
-  
+  if (gdk_display_is_closed (display))
+    return FALSE;
+
   if (owner)
     {
-      if (GDK_WINDOW_DESTROYED (owner))
-       return FALSE;
+      if (GDK_WINDOW_DESTROYED (owner) || !GDK_WINDOW_IS_X11 (owner))
+        return FALSE;
 
+      gdk_window_ensure_native (owner);
       xdisplay = GDK_WINDOW_XDISPLAY (owner);
       xwindow = GDK_WINDOW_XID (owner);
     }
   else
     {
-      xdisplay = gdk_display;
+      xdisplay = GDK_DISPLAY_XDISPLAY (display);
       xwindow = None;
     }
-  
+
+  xselection = gdk_x11_atom_to_xatom_for_display (display, selection);
+
   tmp_list = owner_list;
   while (tmp_list)
     {
       info = tmp_list->data;
       if (info->selection == selection)
-       {
-         owner_list = g_slist_remove (owner_list, info);
-         g_free (info);
-         break;
-       }
+        {
+          owner_list = g_slist_remove (owner_list, info);
+          g_free (info);
+          break;
+        }
       tmp_list = tmp_list->next;
     }
 
@@ -151,179 +163,248 @@ gdk_selection_owner_set (GdkWindow *owner,
   return (XGetSelectionOwner (xdisplay, xselection) == xwindow);
 }
 
-GdkWindow*
-gdk_selection_owner_get (GdkAtom selection)
+GdkWindow *
+_gdk_x11_display_get_selection_owner (GdkDisplay *display,
+                                      GdkAtom     selection)
 {
   Window xwindow;
 
-  xwindow = XGetSelectionOwner (gdk_display, gdk_x11_atom_to_xatom (selection));
+  if (gdk_display_is_closed (display))
+    return NULL;
+
+  xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
+                                gdk_x11_atom_to_xatom_for_display (display,
+                                                                   selection));
   if (xwindow == None)
     return NULL;
 
-  return gdk_window_lookup (xwindow);
+  return gdk_x11_window_lookup_for_display (display, xwindow);
 }
 
 void
-gdk_selection_convert (GdkWindow *requestor,
-                      GdkAtom    selection,
-                      GdkAtom    target,
-                      guint32    time)
+_gdk_x11_display_convert_selection (GdkDisplay *display,
+                                    GdkWindow  *requestor,
+                                    GdkAtom     selection,
+                                    GdkAtom     target,
+                                    guint32     time)
 {
-  if (GDK_WINDOW_DESTROYED (requestor))
+  g_return_if_fail (selection != GDK_NONE);
+
+  if (GDK_WINDOW_DESTROYED (requestor) || !GDK_WINDOW_IS_X11 (requestor))
     return;
 
+  gdk_window_ensure_native (requestor);
+
   XConvertSelection (GDK_WINDOW_XDISPLAY (requestor),
-                    gdk_x11_atom_to_xatom (selection),
-                    gdk_x11_atom_to_xatom (target),
-                    gdk_x11_atom_to_xatom (_gdk_selection_property),
-                    GDK_WINDOW_XID (requestor), time);
+                     gdk_x11_atom_to_xatom_for_display (display, selection),
+                     gdk_x11_atom_to_xatom_for_display (display, target),
+                     gdk_x11_get_xatom_by_name_for_display (display, "GDK_SELECTION"),
+                     GDK_WINDOW_XID (requestor), time);
 }
 
 gint
-gdk_selection_property_get (GdkWindow  *requestor,
-                           guchar    **data,
-                           GdkAtom    *ret_type,
-                           gint       *ret_format)
+_gdk_x11_display_get_selection_property (GdkDisplay  *display,
+                                         GdkWindow   *requestor,
+                                         guchar     **data,
+                                         GdkAtom     *ret_type,
+                                         gint        *ret_format)
 {
   gulong nitems;
   gulong nbytes;
-  gulong length;
+  gulong length = 0;
   Atom prop_type;
   gint prop_format;
   guchar *t = NULL;
 
-  g_return_val_if_fail (requestor != NULL, 0);
-  g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
-
-  /* If retrieved chunks are typically small, (and the ICCCM says the
-     should be) it would be a win to try first with a buffer of
-     moderate length, to avoid two round trips to the server */
-
-  if (GDK_WINDOW_DESTROYED (requestor))
-    return 0;
+  if (GDK_WINDOW_DESTROYED (requestor) || !GDK_WINDOW_IS_X11 (requestor))
+    goto err;
 
   t = NULL;
-  XGetWindowProperty (GDK_WINDOW_XDISPLAY (requestor),
-                     GDK_WINDOW_XID (requestor),
-                     gdk_x11_atom_to_xatom (_gdk_selection_property),
-                     0, 0, False,
-                     AnyPropertyType, &prop_type, &prop_format,
-                     &nitems, &nbytes, &t);
-
-  if (ret_type)
-    *ret_type = gdk_x11_xatom_to_atom (prop_type);
-  if (ret_format)
-    *ret_format = prop_format;
-
-  if (prop_type == None)
-    {
-      *data = NULL;
-      return 0;
-    }
-  
-  if (t)
-    {
-      XFree (t);
-      t = NULL;
-    }
-
-  /* Add on an extra byte to handle null termination.  X guarantees
-     that t will be 1 longer than nbytes and null terminated */
-  length = nbytes + 1;
 
   /* We can't delete the selection here, because it might be the INCR
      protocol, in which case the client has to make sure they'll be
      notified of PropertyChange events _before_ the property is deleted.
      Otherwise there's no guarantee we'll win the race ... */
-  XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (requestor),
-                     GDK_DRAWABLE_XID (requestor),
-                     gdk_x11_atom_to_xatom (_gdk_selection_property),
-                     0, (nbytes + 3) / 4, False,
-                     AnyPropertyType, &prop_type, &prop_format,
-                     &nitems, &nbytes, &t);
+  if (XGetWindowProperty (GDK_WINDOW_XDISPLAY (requestor),
+                          GDK_WINDOW_XID (requestor),
+                          gdk_x11_get_xatom_by_name_for_display (display, "GDK_SELECTION"),
+                          0, 0x1FFFFFFF /* MAXINT32 / 4 */, False,
+                          AnyPropertyType, &prop_type, &prop_format,
+                          &nitems, &nbytes, &t) != Success)
+    goto err;
 
   if (prop_type != None)
     {
-      *data = g_new (guchar, length);
-
-      if (prop_type == XA_ATOM)
-       {
-         Atom* atoms = (Atom*) t;
-         GdkAtom* atoms_dest = (GdkAtom*) *data;
-         gint num_atom, i;
-         
-         num_atom = (length - 1) / sizeof (GdkAtom);
-         for (i=0; i < num_atom; i++)
-           atoms_dest[i] = gdk_x11_xatom_to_atom (atoms[i]);
-       }
+      if (ret_type)
+        *ret_type = gdk_x11_xatom_to_atom_for_display (display, prop_type);
+      if (ret_format)
+        *ret_format = prop_format;
+
+      if (prop_type == XA_ATOM ||
+          prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
+        {
+          Atom* atoms = (Atom*) t;
+          GdkAtom* atoms_dest;
+          gint num_atom, i;
+
+          if (prop_format != 32)
+            goto err;
+
+          num_atom = nitems;
+          length = sizeof (GdkAtom) * num_atom + 1;
+
+          if (data)
+            {
+              *data = g_malloc (length);
+              (*data)[length - 1] = '\0';
+              atoms_dest = (GdkAtom *)(*data);
+
+              for (i=0; i < num_atom; i++)
+                atoms_dest[i] = gdk_x11_xatom_to_atom_for_display (display, atoms[i]);
+            }
+        }
       else
-       {
-         memcpy (*data, t, length);
-       }
-      
+        {
+          switch (prop_format)
+            {
+            case 8:
+              length = nitems;
+              break;
+            case 16:
+              length = sizeof(short) * nitems;
+              break;
+            case 32:
+              length = sizeof(long) * nitems;
+              break;
+            default:
+              g_assert_not_reached ();
+              break;
+            }
+
+          /* Add on an extra byte to handle null termination.  X guarantees
+             that t will be 1 longer than nitems and null terminated */
+          length += 1;
+
+          if (data)
+            *data = g_memdup (t, length);
+        }
+
       if (t)
-       XFree (t);
-      return length-1;
-    }
-  else
-    {
-      *data = NULL;
-      return 0;
+        XFree (t);
+
+      return length - 1;
     }
-}
 
+ err:
+  if (ret_type)
+    *ret_type = GDK_NONE;
+  if (ret_format)
+    *ret_format = 0;
+  if (data)
+    *data = NULL;
+
+  return 0;
+}
 
 void
-gdk_selection_send_notify (guint32  requestor,
-                          GdkAtom  selection,
-                          GdkAtom  target,
-                          GdkAtom  property,
-                          guint32  time)
+_gdk_x11_display_send_selection_notify (GdkDisplay       *display,
+                                        GdkWindow        *requestor,
+                                        GdkAtom          selection,
+                                        GdkAtom          target,
+                                        GdkAtom          property,
+                                        guint32          time)
 {
   XSelectionEvent xevent;
 
   xevent.type = SelectionNotify;
   xevent.serial = 0;
   xevent.send_event = True;
-  xevent.display = gdk_display;
-  xevent.requestor = requestor;
-  xevent.selection = gdk_x11_atom_to_xatom (selection);
-  xevent.target = gdk_x11_atom_to_xatom (target);
-  xevent.property = gdk_x11_atom_to_xatom (property);
+  xevent.requestor = GDK_WINDOW_XID (requestor);
+  xevent.selection = gdk_x11_atom_to_xatom_for_display (display, selection);
+  xevent.target = gdk_x11_atom_to_xatom_for_display (display, target);
+  if (property == GDK_NONE)
+    xevent.property = None;
+  else
+    xevent.property = gdk_x11_atom_to_xatom_for_display (display, property);
   xevent.time = time;
 
-  gdk_send_xevent (requestor, False, NoEventMask, (XEvent*) &xevent);
+  _gdk_x11_display_send_xevent (display, xevent.requestor, False, NoEventMask, (XEvent*) & xevent);
 }
 
+/**
+ * gdk_x11_display_text_property_to_text_list:
+ * @display: (type GdkX11Display): The #GdkDisplay where the encoding is defined
+ * @encoding: an atom representing the encoding. The most
+ *    common values for this are STRING, or COMPOUND_TEXT.
+ *    This is value used as the type for the property
+ * @format: the format of the property
+ * @text: The text data
+ * @length: The number of items to transform
+ * @list: location to store an  array of strings in
+ *    the encoding of the current locale. This array should be
+ *    freed using gdk_free_text_list().
+ *
+ * Convert a text string from the encoding as it is stored
+ * in a property into an array of strings in the encoding of
+ * the current locale. (The elements of the array represent the
+ * nul-separated elements of the original text string.)
+ *
+ * Returns: the number of strings stored in list, or 0,
+ *     if the conversion failed
+ *
+ * Since: 2.24
+ */
 gint
-gdk_text_property_to_text_list (GdkAtom       encoding,
-                               gint          format, 
-                               const guchar *text,
-                               gint          length,
-                               gchar      ***list)
+gdk_x11_display_text_property_to_text_list (GdkDisplay   *display,
+                                            GdkAtom       encoding,
+                                            gint          format,
+                                            const guchar *text,
+                                            gint          length,
+                                            gchar      ***list)
 {
   XTextProperty property;
   gint count = 0;
   gint res;
+  gchar **local_list;
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
 
-  if (!list) 
+  if (list)
+    *list = NULL;
+
+  if (gdk_display_is_closed (display))
     return 0;
 
   property.value = (guchar *)text;
-  property.encoding = gdk_x11_atom_to_xatom (encoding);
+  property.encoding = gdk_x11_atom_to_xatom_for_display (display, encoding);
   property.format = format;
   property.nitems = length;
-  res = XmbTextPropertyToTextList (GDK_DISPLAY(), &property, list, &count);
-
-  if (res == XNoMemory || res == XLocaleNotSupported || 
-      res == XConverterNotFound)
+  res = XmbTextPropertyToTextList (GDK_DISPLAY_XDISPLAY (display), &property,
+                                   &local_list, &count);
+  if (res == XNoMemory || res == XLocaleNotSupported || res == XConverterNotFound)
     return 0;
   else
-    return count;
+    {
+      if (list)
+        *list = local_list;
+      else
+        XFreeStringList (local_list);
+
+      return count;
+    }
 }
 
+/**
+ * gdk_x11_free_text_list:
+ * @list: the value stored in the @list parameter by
+ *   a call to gdk_x11_display_text_property_to_text_list().
+ *
+ * Frees the array of strings created by
+ * gdk_x11_display_text_property_to_text_list().
+ *
+ * Since: 2.24
+ */
 void
-gdk_free_text_list (gchar **list)
+gdk_x11_free_text_list (gchar **list)
 {
   g_return_if_fail (list != NULL);
 
@@ -332,9 +413,9 @@ gdk_free_text_list (gchar **list)
 
 static gint
 make_list (const gchar  *text,
-          gint          length,
-          gboolean      latin1,
-          gchar      ***list)
+           gint          length,
+           gboolean      latin1,
+           gchar      ***list)
 {
   GSList *strings = NULL;
   gint n_strings = 0;
@@ -347,49 +428,58 @@ make_list (const gchar  *text,
   while (p < text + length)
     {
       gchar *str;
-      
+
       q = p;
       while (*q && q < text + length)
-       q++;
+        q++;
 
       if (latin1)
-       {
-         str = g_convert (p, q - p,
-                          "UTF-8", "ISO-8859-1",
-                          NULL, NULL, &error);
-
-         if (!str)
-           {
-             g_warning ("Error converting selection from STRING: %s",
-                        error->message);
-             g_error_free (error);
-           }
-       }
+        {
+          str = g_convert (p, q - p,
+                           "UTF-8", "ISO-8859-1",
+                           NULL, NULL, &error);
+
+          if (!str)
+            {
+              g_warning ("Error converting selection from STRING: %s",
+                         error->message);
+              g_error_free (error);
+            }
+        }
       else
-       str = g_strndup (p, q - p);
+        {
+          str = g_strndup (p, q - p);
+          if (!g_utf8_validate (str, -1, NULL))
+            {
+              g_warning ("Error converting selection from UTF8_STRING");
+              g_free (str);
+              str = NULL;
+            }
+        }
 
       if (str)
-       {
-         strings = g_slist_prepend (strings, str);
-         n_strings++;
-       }
+        {
+          strings = g_slist_prepend (strings, str);
+          n_strings++;
+        }
 
       p = q + 1;
     }
 
   if (list)
-    *list = g_new (gchar *, n_strings + 1);
+    {
+      *list = g_new (gchar *, n_strings + 1);
+      (*list)[n_strings] = NULL;
+    }
 
-  (*list)[n_strings] = NULL;
-  
   i = n_strings;
   tmp_list = strings;
   while (tmp_list)
     {
       if (list)
-       (*list)[--i] = tmp_list->data;
+        (*list)[--i] = tmp_list->data;
       else
-       g_free (tmp_list->data);
+        g_free (tmp_list->data);
 
       tmp_list = tmp_list->next;
     }
@@ -399,36 +489,19 @@ make_list (const gchar  *text,
   return n_strings;
 }
 
-/**
- * gdk_text_property_to_utf8_list:
- * @encoding: an atom representing the encoding of the text
- * @format:   the format of the property
- * @text:     the text to convert
- * @length:   the length of @text, in bytes
- * @list:     location to store the list of strings or %NULL. The
- *            list should be freed with g_strfreev().
- * 
- * Converts a text property in the giving encoding to
- * a list of UTF-8 strings. 
- * 
- * Return value: the number of strings in the resulting
- *               list.
- **/
-gint 
-gdk_text_property_to_utf8_list (GdkAtom        encoding,
-                               gint           format,
-                               const guchar  *text,
-                               gint           length,
-                               gchar       ***list)
+gint
+_gdk_x11_display_text_property_to_utf8_list (GdkDisplay    *display,
+                                             GdkAtom        encoding,
+                                             gint           format,
+                                             const guchar  *text,
+                                             gint           length,
+                                             gchar       ***list)
 {
-  g_return_val_if_fail (text != NULL, 0);
-  g_return_val_if_fail (length >= 0, 0);
-  
   if (encoding == GDK_TARGET_STRING)
     {
       return make_list ((gchar *)text, length, TRUE, list);
     }
-  else if (encoding == gdk_atom_intern ("UTF8_STRING", FALSE))
+  else if (encoding == gdk_atom_intern_static_string ("UTF8_STRING"))
     {
       return make_list ((gchar *)text, length, FALSE, list);
     }
@@ -441,68 +514,101 @@ gdk_text_property_to_utf8_list (GdkAtom        encoding,
       gboolean need_conversion = !g_get_charset (&charset);
       gint count = 0;
       GError *error = NULL;
-      
+
       /* Probably COMPOUND text, we fall back to Xlib routines
        */
-      local_count = gdk_text_property_to_text_list (encoding,
-                                                   format, 
-                                                   text,
-                                                   length,
-                                                   &local_list);
+      local_count = gdk_x11_display_text_property_to_text_list (display,
+                                                                encoding,
+                                                                format,
+                                                                text,
+                                                                length,
+                                                                &local_list);
       if (list)
-       *list = g_new (gchar *, local_count + 1);
-      
+        *list = g_new (gchar *, local_count + 1);
+
       for (i=0; i<local_count; i++)
-       {
-         /* list contains stuff in our default encoding
-          */
-         if (need_conversion)
-           {
-             gchar *utf = g_convert (local_list[i], -1,
-                                     "UTF-8", charset,
-                                     NULL, NULL, &error);
-             if (utf)
-               {
-                 if (list)
-                   (*list)[count++] = utf;
-                 else
-                   g_free (utf);
-               }
-             else
-               {
-                 g_warning ("Error converting to UTF-8 from '%s': %s",
-                            charset, error->message);
-                 g_error_free (error);
-                 error = NULL;
-               }
-           }
-         else
-           {
-             if (list)
-               (*list)[count++] = g_strdup (local_list[i]);
-           }
-       }
-      
-      gdk_free_text_list (local_list);
-      (*list)[count] = NULL;
+        {
+          /* list contains stuff in our default encoding
+           */
+          if (need_conversion)
+            {
+              gchar *utf = g_convert (local_list[i], -1,
+                                      "UTF-8", charset,
+                                      NULL, NULL, &error);
+              if (utf)
+                {
+                  if (list)
+                    (*list)[count++] = utf;
+                  else
+                    g_free (utf);
+                }
+              else
+                {
+                  g_warning ("Error converting to UTF-8 from '%s': %s",
+                             charset, error->message);
+                  g_error_free (error);
+                  error = NULL;
+                }
+            }
+          else
+            {
+              if (list)
+                {
+                  if (g_utf8_validate (local_list[i], -1, NULL))
+                    (*list)[count++] = g_strdup (local_list[i]);
+                  else
+                    g_warning ("Error converting selection");
+                }
+            }
+        }
+
+      if (local_count)
+        gdk_x11_free_text_list (local_list);
+
+      if (list)
+        (*list)[count] = NULL;
 
       return count;
     }
 }
 
+/**
+ * gdk_x11_display_string_to_compound_text:
+ * @display: (type GdkX11Display): the #GdkDisplay where the encoding is defined
+ * @str: a nul-terminated string
+ * @encoding: (out) (transfer none): location to store the encoding atom
+ *     (to be used as the type for the property)
+ * @format: (out): location to store the format of the property
+ * @ctext: (out) (array length=length): location to store newly
+ *     allocated data for the property
+ * @length: the length of @ctext, in bytes
+ *
+ * Convert a string from the encoding of the current
+ * locale into a form suitable for storing in a window property.
+ *
+ * Returns: 0 upon success, non-zero upon failure
+ *
+ * Since: 2.24
+ */
 gint
-gdk_string_to_compound_text (const gchar *str,
-                            GdkAtom     *encoding,
-                            gint        *format,
-                            guchar     **ctext,
-                            gint        *length)
+gdk_x11_display_string_to_compound_text (GdkDisplay  *display,
+                                         const gchar *str,
+                                         GdkAtom     *encoding,
+                                         gint        *format,
+                                         guchar     **ctext,
+                                         gint        *length)
 {
   gint res;
   XTextProperty property;
 
-  res = XmbTextListToTextProperty (GDK_DISPLAY(), 
-                                  (char **)&str, 1, XCompoundTextStyle,
-                                          &property);
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
+
+  if (gdk_display_is_closed (display))
+    res = XLocaleNotSupported;
+  else
+    res = XmbTextListToTextProperty (GDK_DISPLAY_XDISPLAY (display),
+                                     (char **)&str, 1, XCompoundTextStyle,
+                                     &property);
   if (res != Success)
     {
       property.encoding = None;
@@ -512,7 +618,7 @@ gdk_string_to_compound_text (const gchar *str,
     }
 
   if (encoding)
-    *encoding = gdk_x11_xatom_to_atom (property.encoding);
+    *encoding = gdk_x11_xatom_to_atom_for_display (display, property.encoding);
   if (format)
     *format = property.format;
   if (ctext)
@@ -528,10 +634,11 @@ gdk_string_to_compound_text (const gchar *str,
  * routines for COMPOUND_TEXT only enforce this in one direction,
  * causing cut-and-paste of \r and \r\n separated text to fail.
  * This routine strips out all non-allowed C0 and C1 characters
- * from the input string and also canonicalizes \r, \r\n, and \n\r to \n
+ * from the input string and also canonicalizes \r, and \r\n to \n
  */
-static gchar * 
-sanitize_utf8 (const gchar *src)
+static gchar *
+sanitize_utf8 (const gchar *src,
+               gboolean return_latin1)
 {
   gint len = strlen (src);
   GString *result = g_string_sized_new (len);
@@ -539,86 +646,77 @@ sanitize_utf8 (const gchar *src)
 
   while (*p)
     {
-      if (*p == '\r' || *p == '\n')
-       {
-         p++;
-         if (*p == '\r' || *p == '\n')
-           p++;
-
-         g_string_append_c (result, '\n');
-       }
+      if (*p == '\r')
+        {
+          p++;
+          if (*p == '\n')
+            p++;
+
+          g_string_append_c (result, '\n');
+        }
       else
-       {
-         gunichar ch = g_utf8_get_char (p);
-         char buf[7];
-         gint buflen;
-         
-         if (!((ch < 0x20 && ch != '\t') || (ch >= 0x7f && ch < 0xa0)))
-           {
-             buflen = g_unichar_to_utf8 (ch, buf);
-             g_string_append_len (result, buf, buflen);
-           }
-
-         p = g_utf8_next_char (p);
-       }
+        {
+          gunichar ch = g_utf8_get_char (p);
+
+          if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
+            {
+              if (return_latin1)
+                {
+                  if (ch <= 0xff)
+                    g_string_append_c (result, ch);
+                  else
+                    g_string_append_printf (result,
+                                            ch < 0x10000 ? "\\u%04x" : "\\U%08x",
+                                            ch);
+                }
+              else
+                {
+                  char buf[7];
+                  gint buflen;
+
+                  buflen = g_unichar_to_utf8 (ch, buf);
+                  g_string_append_len (result, buf, buflen);
+                }
+            }
+
+          p = g_utf8_next_char (p);
+        }
     }
 
   return g_string_free (result, FALSE);
 }
 
-/**
- * gdk_utf8_to_string_target:
- * @str: a UTF-8 string
- * 
- * Converts an UTF-8 string into the best possible representation
- * as a STRING. The representation of characters not in STRING
- * is not specified; it may be as pseudo-escape sequences
- * \x{ABCD}, or it may be in some other form of approximation.
- * 
- * Return value: the newly-allocated string, or %NULL if the
- *               conversion failed. (It should not fail for
- *               any properly formed UTF-8 string.)
- **/
 gchar *
-gdk_utf8_to_string_target (const gchar *str)
+_gdk_x11_display_utf8_to_string_target (GdkDisplay  *display,
+                                        const gchar *str)
 {
-  GError *error = NULL;
-  
-  gchar *tmp_str = sanitize_utf8 (str);
-  gchar *result =  g_convert_with_fallback (tmp_str, -1,
-                                           "ISO-8859-1", "UTF-8",
-                                           NULL, NULL, NULL, &error);
-  if (!result)
-    {
-      g_warning ("Error converting from UTF-8 to STRING: %s",
-                error->message);
-      g_error_free (error);
-    }
-  
-  g_free (tmp_str);
-  return result;
+  return sanitize_utf8 (str, TRUE);
 }
 
 /**
- * gdk_utf8_to_compound_text:
- * @str:      a UTF-8 string
- * @encoding: location to store resulting encoding
- * @format:   location to store format of the result
- * @ctext:    location to store the data of the result
- * @length:   location to store the length of the data
- *            stored in @ctext
- * 
- * Converts from UTF-8 to compound text. 
- * 
- * Return value: %TRUE if the conversion succeeded, otherwise
- *               %FALSE.
- **/
+ * gdk_x11_display_utf8_to_compound_text:
+ * @display: (type GdkX11Display): a #GdkDisplay
+ * @str: a UTF-8 string
+ * @encoding: (out): location to store resulting encoding
+ * @format: (out): location to store format of the result
+ * @ctext: (out) (array length=length): location to store the data of the result
+ * @length: location to store the length of the data
+ *     stored in @ctext
+ *
+ * Converts from UTF-8 to compound text.
+ *
+ * Return value: %TRUE if the conversion succeeded,
+ *     otherwise %FALSE
+ *
+ * Since: 2.24
+ */
 gboolean
-gdk_utf8_to_compound_text (const gchar *str,
-                          GdkAtom     *encoding,
-                          gint        *format,
-                          guchar     **ctext,
-                          gint        *length)
+gdk_x11_display_utf8_to_compound_text (GdkDisplay  *display,
+                                       const gchar *str,
+                                       GdkAtom     *encoding,
+                                       gint        *format,
+                                       guchar     **ctext,
+                                       gint        *length)
 {
   gboolean need_conversion;
   const gchar *charset;
@@ -627,49 +725,65 @@ gdk_utf8_to_compound_text (const gchar *str,
   gboolean result;
 
   g_return_val_if_fail (str != NULL, FALSE);
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
 
   need_conversion = !g_get_charset (&charset);
 
-  tmp_str = sanitize_utf8 (str);
+  tmp_str = sanitize_utf8 (str, FALSE);
 
   if (need_conversion)
     {
-      locale_str = g_convert_with_fallback (tmp_str, -1,
-                                           charset, "UTF-8",
-                                           NULL, NULL, NULL, &error);
+      locale_str = g_convert (tmp_str, -1,
+                              charset, "UTF-8",
+                              NULL, NULL, &error);
       g_free (tmp_str);
 
       if (!locale_str)
-       {
-         g_warning ("Error converting from UTF-8 to '%s': %s",
-                    charset, error->message);
-         g_error_free (error);
-
-         if (encoding)
-           *encoding = None;
-         if (format)
-           *format = None;
-         if (ctext)
-           *ctext = NULL;
-         if (length)
-           *length = 0;
-
-         return FALSE;
-       }
+        {
+          if (!(error->domain = G_CONVERT_ERROR &&
+                error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
+            {
+              g_warning ("Error converting from UTF-8 to '%s': %s",
+                         charset, error->message);
+            }
+          g_error_free (error);
+
+          if (encoding)
+            *encoding = None;
+          if (format)
+            *format = None;
+          if (ctext)
+            *ctext = NULL;
+          if (length)
+            *length = 0;
+
+          return FALSE;
+        }
     }
   else
     locale_str = tmp_str;
-    
-  result = gdk_string_to_compound_text (locale_str,
-                                       encoding, format, ctext, length);
+
+  result = gdk_x11_display_string_to_compound_text (display, locale_str,
+                                                    encoding, format,
+                                                    ctext, length);
   result = (result == Success? TRUE : FALSE);
-  
+
   g_free (locale_str);
 
   return result;
 }
 
-void gdk_free_compound_text (guchar *ctext)
+/**
+ * gdk_x11_free_compound_text:
+ * @ctext: The pointer stored in @ctext from a call to
+ *   gdk_x11_display_string_to_compound_text().
+ *
+ * Frees the data returned from gdk_x11_display_string_to_compound_text().
+ *
+ * Since: 2.24
+ */
+void
+gdk_x11_free_compound_text (guchar *ctext)
 {
   if (ctext)
     XFree (ctext);