]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkdnd-x11.c
Cleanups
[~andy/gtk] / gdk / x11 / gdkdnd-x11.c
index c8a164afaa278b4791d4fbc5d477594b0eed8e2e..f9104313301fb46ca04589f8387c93cfef2aa60b 100644 (file)
@@ -2,28 +2,45 @@
  * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/*
+ * 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/. 
+ */
+
+#include <config.h>
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
 #include <string.h>
+
+#include "gdk.h"          /* For gdk_flush() */
 #include "gdkx.h"
-#include "gdk/gdkprivate.h"
-#include "gdk.h"
+#include "gdkasync.h"
+#include "gdkdnd.h"
+#include "gdkproperty.h"
+#include "gdkprivate-x11.h"
+#include "gdkinternals.h"
+#include "gdkscreen-x11.h"
+#include "gdkdisplay-x11.h"
+#include "gdkalias.h"
 
-typedef struct _GdkDragContextPrivate GdkDragContextPrivate;
+typedef struct _GdkDragContextPrivateX11 GdkDragContextPrivateX11;
 
 typedef enum {
   GDK_DRAG_STATUS_DRAG,
@@ -42,139 +59,218 @@ typedef struct {
   GList *children;
   GHashTable *child_hash;
   guint old_event_mask;
+  GdkScreen *screen;
 } GdkWindowCache;
 
 /* Structure that holds information about a drag in progress.
  * this is used on both source and destination sides.
  */
-struct _GdkDragContextPrivate {
+struct _GdkDragContextPrivateX11 {
   GdkDragContext context;
 
-  GdkAtom motif_selection;
-  GdkAtom xdnd_selection;
+  Atom motif_selection;
   guint   ref_count;
 
   guint16 last_x;              /* Coordinates from last event */
   guint16 last_y;
-  GdkDragAction old_action;    /* The last action we sent to the source */
+  GdkDragAction old_action;      /* The last action we sent to the source */
+  GdkDragAction old_actions;     /* The last actions we sent to the source */
+  GdkDragAction xdnd_actions;     /* What is currently set in XdndActionList */
 
-  Window  dest_xid;
+  Window dest_xid;              /* The last window we looked up */
+  Window drop_xid;            /* The (non-proxied) window that is receiving drops */
   guint xdnd_targets_set : 1;   /* Whether we've already set XdndTypeList */
-  guint xdnd_actions_set : 1;   /* Whether we've already set XdndActionsList */
-  guint xdnd_have_actions : 1; /* Whether an XdndActionList was provided */
+  guint xdnd_actions_set : 1;   /* Whether we've already set XdndActionList */
+  guint xdnd_have_actions : 1;  /* Whether an XdndActionList was provided */
   guint motif_targets_set : 1;  /* Whether we've already set motif initiator info */
   guint drag_status : 4;       /* current status of drag */
+  
+  guint drop_failed : 1;        /* Whether the drop was unsuccessful */
+  guint version;                /* Xdnd protocol version */
 
-  GdkWindowCache *window_cache;
+  GSList *window_caches;
 };
 
-GdkDragContext *current_dest_drag = NULL;
+#define PRIVATE_DATA(context) ((GdkDragContextPrivateX11 *) GDK_DRAG_CONTEXT (context)->windowing_data)
 
 /* Forward declarations */
 
 static void gdk_window_cache_destroy (GdkWindowCache *cache);
 
-static void     motif_read_target_table (void);
+static void motif_read_target_table (GdkDisplay *display);
+
 static GdkFilterReturn motif_dnd_filter (GdkXEvent *xev,
                                         GdkEvent  *event,
                                         gpointer   data);
 
-static GdkFilterReturn xdnd_enter_filter (GdkXEvent *xev,
-                                         GdkEvent  *event,
-                                         gpointer   data);
-
-static GdkFilterReturn xdnd_leave_filter (GdkXEvent *xev,
-                                         GdkEvent  *event,
-                                         gpointer   data);
-
+static GdkFilterReturn xdnd_enter_filter    (GdkXEvent *xev,
+                                            GdkEvent  *event,
+                                            gpointer   data);
+static GdkFilterReturn xdnd_leave_filter    (GdkXEvent *xev,
+                                            GdkEvent  *event,
+                                            gpointer   data);
 static GdkFilterReturn xdnd_position_filter (GdkXEvent *xev,
                                             GdkEvent  *event,
                                             gpointer   data);
-
-static GdkFilterReturn xdnd_status_filter (GdkXEvent *xev,
-                                          GdkEvent  *event,
-                                          gpointer   data);
-
+static GdkFilterReturn xdnd_status_filter   (GdkXEvent *xev,
+                                            GdkEvent  *event,
+                                            gpointer   data);
 static GdkFilterReturn xdnd_finished_filter (GdkXEvent *xev,
-                                           GdkEvent  *event,
-                                           gpointer   data);
+                                            GdkEvent  *event,
+                                            gpointer   data);
+static GdkFilterReturn xdnd_drop_filter     (GdkXEvent *xev,
+                                            GdkEvent  *event,
+                                            gpointer   data);
 
-static GdkFilterReturn xdnd_drop_filter (GdkXEvent *xev,
-                                        GdkEvent  *event,
-                                        gpointer   data);
+static void   xdnd_manage_source_filter (GdkDragContext *context,
+                                        GdkWindow      *window,
+                                        gboolean        add_filter);
 
-/* Drag Contexts */
+static void gdk_drag_context_finalize   (GObject              *object);
 
 static GList *contexts;
 
-GdkDragContext *
-gdk_drag_context_new        (void)
-{
-  GdkDragContextPrivate *result;
-
-  result = g_new0 (GdkDragContextPrivate, 1);
+static const struct {
+  const char *atom_name;
+  GdkFilterFunc func;
+} xdnd_filters[] = {
+  { "XdndEnter",    xdnd_enter_filter },
+  { "XdndLeave",    xdnd_leave_filter },
+  { "XdndPosition", xdnd_position_filter },
+  { "XdndStatus",   xdnd_status_filter },
+  { "XdndFinished", xdnd_finished_filter },
+  { "XdndDrop",     xdnd_drop_filter },
+};
+             
+G_DEFINE_TYPE (GdkDragContext, gdk_drag_context, G_TYPE_OBJECT)
 
-  result->ref_count = 1;
+static void
+gdk_drag_context_init (GdkDragContext *dragcontext)
+{
+  GdkDragContextPrivateX11 *private;
 
-  contexts = g_list_prepend (contexts, result);
+  private = G_TYPE_INSTANCE_GET_PRIVATE (dragcontext, 
+                                        GDK_TYPE_DRAG_CONTEXT, 
+                                        GdkDragContextPrivateX11);
+  
+  dragcontext->windowing_data = private;
 
-  return (GdkDragContext *)result;
+  contexts = g_list_prepend (contexts, dragcontext);
 }
 
-void            
-gdk_drag_context_ref (GdkDragContext *context)
+static void
+gdk_drag_context_class_init (GdkDragContextClass *klass)
 {
-  g_return_if_fail (context != NULL);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gdk_drag_context_finalize;
 
-  ((GdkDragContextPrivate *)context)->ref_count++;
+  g_type_class_add_private (object_class, sizeof (GdkDragContextPrivateX11));
 }
 
-void            
-gdk_drag_context_unref (GdkDragContext *context)
+static void
+gdk_drag_context_finalize (GObject *object)
 {
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
-
-  g_return_if_fail (context != NULL);
-
-  private->ref_count--;
+  GdkDragContext *context = GDK_DRAG_CONTEXT (object);
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GSList *tmp_list;
   
-  if (private->ref_count == 0)
+  g_list_free (context->targets);
+
+  if (context->source_window)
     {
-      g_dataset_destroy (private);
+      if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
+          !context->is_source)
+        xdnd_manage_source_filter (context, context->source_window, FALSE);
       
-      g_list_free (context->targets);
+      g_object_unref (context->source_window);
+    }
+  
+  if (context->dest_window)
+    g_object_unref (context->dest_window);
 
-      if (context->source_window)
-       gdk_window_unref (context->source_window);
+  for (tmp_list = private->window_caches; tmp_list; tmp_list = tmp_list->next)
+    gdk_window_cache_destroy (tmp_list->data);
+  g_slist_free (private->window_caches);
+  
+  contexts = g_list_remove (contexts, context);
 
-      if (context->dest_window)
-       gdk_window_unref (context->dest_window);
+  G_OBJECT_CLASS (gdk_drag_context_parent_class)->finalize (object);
+}
 
-      if (private->window_cache)
-       gdk_window_cache_destroy (private->window_cache);
+/* Drag Contexts */
 
-      contexts = g_list_remove (contexts, private);
-      g_free (private);
-    }
+/**
+ * gdk_drag_context_new:
+ * 
+ * Creates a new #GdkDragContext.
+ * 
+ * Return value: the newly created #GdkDragContext.
+ **/
+GdkDragContext *
+gdk_drag_context_new (void)
+{
+  return g_object_new (GDK_TYPE_DRAG_CONTEXT, NULL);
+}
+
+/**
+ * gdk_drag_context_ref:
+ * @context: a #GdkDragContext.
+ * 
+ * Deprecated function; use g_object_ref() instead.
+ **/
+void            
+gdk_drag_context_ref (GdkDragContext *context)
+{
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+
+  g_object_ref (context);
+}
+
+/**
+ * gdk_drag_context_unref:
+ * @context: a #GdkDragContext.
+ * 
+ * Deprecated function; use g_object_unref() instead.
+ **/
+void            
+gdk_drag_context_unref (GdkDragContext *context)
+{
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+
+  g_object_unref (context);
 }
 
 static GdkDragContext *
-gdk_drag_context_find (gboolean is_source,
-                      Window   source_xid,
-                      Window   dest_xid)
+gdk_drag_context_find (GdkDisplay *display,
+                      gboolean    is_source,
+                      Window      source_xid,
+                      Window      dest_xid)
 {
   GList *tmp_list = contexts;
   GdkDragContext *context;
+  GdkDragContextPrivateX11 *private;
+  Window context_dest_xid;
 
   while (tmp_list)
     {
       context = (GdkDragContext *)tmp_list->data;
+      private = PRIVATE_DATA (context);
+
+      if ((context->source_window && gdk_drawable_get_display (context->source_window) != display) ||
+         (context->dest_window && gdk_drawable_get_display (context->dest_window) != display))
+       continue;
+
+      context_dest_xid = context->dest_window ? 
+                            (private->drop_xid ?
+                              private->drop_xid :
+                              GDK_DRAWABLE_XID (context->dest_window)) :
+                            None;
 
       if ((!context->is_source == !is_source) &&
          ((source_xid == None) || (context->source_window &&
-           (GDK_WINDOW_XWINDOW (context->source_window) == source_xid))) &&
-         ((dest_xid == None) || (context->dest_window &&
-           (GDK_WINDOW_XWINDOW (context->dest_window) == dest_xid))))
+           (GDK_DRAWABLE_XID (context->source_window) == source_xid))) &&
+         ((dest_xid == None) || (context_dest_xid == dest_xid)))
        return context;
       
       tmp_list = tmp_list->next;
@@ -183,6 +279,29 @@ gdk_drag_context_find (gboolean is_source,
   return NULL;
 }
 
+static void
+precache_target_list (GdkDragContext *context)
+{
+  if (context->targets)
+    {
+      GPtrArray *targets = g_ptr_array_new ();
+      GList *tmp_list;
+      int i;
+
+      for (tmp_list = context->targets; tmp_list; tmp_list = tmp_list->next)
+       g_ptr_array_add (targets, gdk_atom_name (GDK_POINTER_TO_ATOM (tmp_list->data)));
+
+      _gdk_x11_precache_atoms (GDK_WINDOW_DISPLAY (context->source_window),
+                              (const gchar **)targets->pdata,
+                              targets->len);
+
+      for (i =0; i < targets->len; i++)
+       g_free (targets->pdata[i]);
+
+      g_ptr_array_free (targets, TRUE);
+    }
+}
+
 /* Utility functions */
 
 static void
@@ -243,14 +362,18 @@ gdk_window_cache_filter (GdkXEvent *xev,
              {
                GList *above_node = g_hash_table_lookup (cache->child_hash, 
                                                         GUINT_TO_POINTER (xce->above));
-               if (above_node && node->prev != above_node)
+               if (above_node && node->next != above_node)
                  {
+                   /* Put the window above (before in the list) above_node
+                    */
                    cache->children = g_list_remove_link (cache->children, node);
-                   node->next = above_node->next;
-                   if (node->next)
-                     node->next->prev = node;
-                   node->prev = above_node;
-                   above_node->next = node;
+                   node->prev = above_node->prev;
+                   if (node->prev)
+                     node->prev->next = node;
+                   else
+                     cache->children = node;
+                   node->next = above_node;
+                   above_node->prev = node;
                  }
              }
          }
@@ -321,55 +444,59 @@ gdk_window_cache_filter (GdkXEvent *xev,
 }
 
 static GdkWindowCache *
-gdk_window_cache_new (void)
+gdk_window_cache_new (GdkScreen *screen)
 {
   XWindowAttributes xwa;
-  Window root, parent, *children;
-  unsigned int nchildren;
-  int i;
-  
-  gint old_warnings = gdk_error_warnings;
+  Display *xdisplay = GDK_SCREEN_XDISPLAY (screen);
+  GdkWindow *root_window = gdk_screen_get_root_window (screen);
+  GdkChildInfoX11 *children;
+  guint nchildren, i;
   
   GdkWindowCache *result = g_new (GdkWindowCache, 1);
 
   result->children = NULL;
   result->child_hash = g_hash_table_new (g_direct_hash, NULL);
+  result->screen = screen;
 
-  XGetWindowAttributes (gdk_display, gdk_root_window, &xwa);
+  XGetWindowAttributes (xdisplay, GDK_WINDOW_XWINDOW (root_window), &xwa);
   result->old_event_mask = xwa.your_event_mask;
-  XSelectInput (gdk_display, gdk_root_window,
+
+  if (G_UNLIKELY (!GDK_DISPLAY_X11 (GDK_SCREEN_X11 (screen)->display)->trusted_client)) 
+    {
+      GList *toplevel_windows, *list;
+      GdkWindow *window;
+      gint x, y, width, height;
+      
+      toplevel_windows = gdk_screen_get_toplevel_windows (screen);
+      for (list = toplevel_windows; list; list = list->next) {
+       window = GDK_WINDOW (list->data);
+       gdk_window_get_geometry (window, &x, &y, &width, &height, NULL);
+       gdk_window_cache_add (result, GDK_WINDOW_XID (window), 
+                             x, y, width, height, 
+                             gdk_window_is_visible (window));
+      }
+      g_list_free (toplevel_windows);
+      return result;
+    }
+
+  XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
                result->old_event_mask | SubstructureNotifyMask);
-  gdk_window_add_filter ((GdkWindow *)&gdk_root_parent, 
-                        gdk_window_cache_filter, result);
-  
-  gdk_error_code = 0;
-  gdk_error_warnings = 0;
+  gdk_window_add_filter (root_window, gdk_window_cache_filter, result);
 
-  if (XQueryTree(gdk_display, gdk_root_window, 
-                &root, &parent, &children, &nchildren) == 0)
+  if (!_gdk_x11_get_window_child_info (gdk_screen_get_display (screen),
+                                      GDK_WINDOW_XWINDOW (root_window),
+                                      FALSE, NULL,
+                                      &children, &nchildren))
     return result;
-  
+
   for (i = 0; i < nchildren ; i++)
     {
-      XGetWindowAttributes (gdk_display, children[i], &xwa);
-
-      gdk_window_cache_add (result, children[i],
-                           xwa.x, xwa.y, xwa.width, xwa.height,
-                           xwa.map_state != IsUnmapped);
-
-      if (gdk_error_code != 0)
-       gdk_error_code = 0;
-      else
-       {
-         gdk_window_cache_add (result, children[i],
-                               xwa.x, xwa.y, xwa.width, xwa.height,
-                               (xwa.map_state != IsUnmapped));
-       }
+      gdk_window_cache_add (result, children[i].window,
+                           children[i].x, children[i].y, children[i].width, children[i].height,
+                           children[i].is_mapped);
     }
 
-  XFree (children);
-
-  gdk_error_warnings = old_warnings;
+  g_free (children);
 
   return result;
 }
@@ -377,9 +504,12 @@ gdk_window_cache_new (void)
 static void
 gdk_window_cache_destroy (GdkWindowCache *cache)
 {
-  XSelectInput (gdk_display, gdk_root_window, cache->old_event_mask);
-  gdk_window_remove_filter ((GdkWindow *)&gdk_root_parent, 
-                           gdk_window_cache_filter, cache);
+  GdkWindow *root_window = gdk_screen_get_root_window (cache->screen);
+  
+  XSelectInput (GDK_WINDOW_XDISPLAY (root_window), 
+               GDK_WINDOW_XWINDOW (root_window),
+               cache->old_event_mask);
+  gdk_window_remove_filter (root_window, gdk_window_cache_filter, cache);
 
   g_list_foreach (cache->children, (GFunc)g_free, NULL);
   g_list_free (cache->children);
@@ -389,84 +519,55 @@ gdk_window_cache_destroy (GdkWindowCache *cache)
 }
 
 static Window
-get_client_window_at_coords_recurse (Window  win,
-                                    gint    x,
-                                    gint    y)
+get_client_window_at_coords_recurse (GdkDisplay *display,
+                                    Window      win,
+                                    gboolean    is_toplevel,
+                                    gint        x,
+                                    gint        y)
 {
-  Window root, tmp_parent, *children;
+  GdkChildInfoX11 *children;
   unsigned int nchildren;
   int i;
-  Window child = None;
-  Atom type = None;
-  int format;
-  unsigned long nitems, after;
-  unsigned char *data;
-  
-  static Atom wm_state_atom = None;
+  gboolean found_child = FALSE;
+  GdkChildInfoX11 child = { 0, };
+  gboolean has_wm_state = FALSE;
 
-  if (!wm_state_atom)
-    wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
-    
-  XGetWindowProperty (gdk_display, win, 
-                     wm_state_atom, 0, 0, False, AnyPropertyType,
-                     &type, &format, &nitems, &after, &data);
-  
-  if (gdk_error_code != 0)
-    {
-      gdk_error_code = 0;
-      return None;
-    }
+  if (!_gdk_x11_get_window_child_info (display, win, TRUE,
+                                      is_toplevel? &has_wm_state : NULL,
+                                      &children, &nchildren))
+    return None;
 
-  if (type != None)
+  if (has_wm_state)
     {
-      XFree (data);
+      g_free (children);
+
       return win;
     }
 
-#if 0
-  /* This is beautiful! Damn Enlightenment and click-to-focus */
-  XTranslateCoordinates (gdk_display, gdk_root_window, win,
-                        x_root, y_root, &dest_x, &dest_y, &child);
-
-  if (gdk_error_code != 0)
+  for (i = nchildren - 1; (i >= 0) && !found_child; i--)
     {
-      gdk_error_code = 0;
-      return None;
+      GdkChildInfoX11 *cur_child = &children[i];
+       
+      if ((cur_child->is_mapped) && (cur_child->window_class == InputOutput) &&
+         (x >= cur_child->x) && (x < cur_child->x + cur_child->width) &&
+         (y >= cur_child->y) && (y < cur_child->y + cur_child->height))
+       {
+         x -= cur_child->x;
+         y -= cur_child->y;
+         child = *cur_child;
+         found_child = TRUE;
+       }
     }
-  
-#else
-  if (XQueryTree(gdk_display, win,
-                &root, &tmp_parent, &children, &nchildren) == 0)
-    return 0;
-
-  if (gdk_error_code == 0)
+   
+  g_free (children);
+  if (found_child)
     {
-      for (i = nchildren - 1; (i >= 0) && (child == None); i--)
-       {
-         XWindowAttributes xwa;
-         
-         XGetWindowAttributes (gdk_display, children[i], &xwa);
-         
-         if (gdk_error_code != 0)
-           gdk_error_code = 0;
-         else if ((xwa.map_state == IsViewable) && (xwa.class == InputOutput) &&
-                  (x >= xwa.x) && (x < xwa.x + (gint)xwa.width) &&
-                  (y >= xwa.y) && (y < xwa.y + (gint)xwa.height))
-           {
-             x -= xwa.x;
-             y -= xwa.y;
-             child = children[i];
-           }
-       }
-      
-      XFree (children);
+      if (child.has_wm_state)
+       return child.window;
+      else
+       return get_client_window_at_coords_recurse (display, child.window, FALSE, x, y);
     }
-  else
-    gdk_error_code = 0;
-#endif  
-
-  if (child)
-    return get_client_window_at_coords_recurse (child, x, y);
   else
     return None;
 }
@@ -480,11 +581,8 @@ get_client_window_at_coords (GdkWindowCache *cache,
   GList *tmp_list;
   Window retval = None;
 
-  gint old_warnings = gdk_error_warnings;
+  gdk_error_trap_push ();
   
-  gdk_error_code = 0;
-  gdk_error_warnings = 0;
-
   tmp_list = cache->children;
 
   while (tmp_list && !retval)
@@ -496,8 +594,9 @@ get_client_window_at_coords (GdkWindowCache *cache,
          if ((x_root >= child->x) && (x_root < child->x + child->width) &&
              (y_root >= child->y) && (y_root < child->y + child->height))
            {
-             retval = get_client_window_at_coords_recurse (child->xid,
-                                                           x_root - child->x, 
+             retval = get_client_window_at_coords_recurse (gdk_screen_get_display (cache->screen),
+                                                           child->xid, TRUE,
+                                                           x_root - child->x,
                                                            y_root - child->y);
              if (!retval)
                retval = child->xid;
@@ -507,112 +606,13 @@ get_client_window_at_coords (GdkWindowCache *cache,
       tmp_list = tmp_list->next;
     }
 
-  gdk_error_warnings = old_warnings;
-  if (retval)
-    return retval;
-  else
-    return gdk_root_window;
-}
-
-#if 0
-static Window
-get_client_window_at_coords_recurse (Window  win,
-                                    gint    x_root,
-                                    gint    y_root)
-{
-  Window child;
-  Atom type = None;
-  int format;
-  unsigned long nitems, after;
-  unsigned char *data;
-  int dest_x, dest_y;
-  
-  static Atom wm_state_atom = None;
-
-  if (!wm_state_atom)
-    wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
-    
-  XGetWindowProperty (gdk_display, win, 
-                     wm_state_atom, 0, 0, False, AnyPropertyType,
-                     &type, &format, &nitems, &after, &data);
-  
-  if (gdk_error_code != 0)
-    {
-      gdk_error_code = 0;
-      return None;
-    }
-
-  if (type != None)
-    {
-      XFree (data);
-      return win;
-    }
-
-  XTranslateCoordinates (gdk_display, gdk_root_window, win,
-                        x_root, y_root, &dest_x, &dest_y, &child);
-
-  if (gdk_error_code != 0)
-    {
-      gdk_error_code = 0;
-      return None;
-    }
-
-  if (child)
-    return get_client_window_at_coords_recurse (child, x_root, y_root);
-  else
-    return None;
-}
-
-static Window 
-get_client_window_at_coords (Window  ignore,
-                            gint    x_root,
-                            gint    y_root)
-{
-  Window root, parent, *children;
-  unsigned int nchildren;
-  int i;
-  Window retval = None;
-  
-  gint old_warnings = gdk_error_warnings;
+  gdk_error_trap_pop ();
   
-  gdk_error_code = 0;
-  gdk_error_warnings = 0;
-
-  if (XQueryTree(gdk_display, gdk_root_window, 
-                &root, &parent, &children, &nchildren) == 0)
-    return 0;
-
-  for (i = nchildren - 1; (i >= 0) && (retval == None); i--)
-    {
-      if (children[i] != ignore)
-       {
-         XWindowAttributes xwa;
-
-         XGetWindowAttributes (gdk_display, children[i], &xwa);
-
-         if (gdk_error_code != 0)
-           gdk_error_code = 0;
-         else if ((xwa.map_state == IsViewable) &&
-                  (x_root >= xwa.x) && (x_root < xwa.x + (gint)xwa.width) &&
-                  (y_root >= xwa.y) && (y_root < xwa.y + (gint)xwa.height))
-           {
-             retval = get_client_window_at_coords_recurse (children[i],
-                                                           x_root, y_root);
-             if (!retval)
-               retval = children[i];
-           }
-       }
-    }
-
-  XFree (children);
-
-  gdk_error_warnings = old_warnings;
   if (retval)
     return retval;
   else
-    return gdk_root_window;
+    return GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (cache->screen));
 }
-#endif
 
 /*************************************************************
  ***************************** MOTIF *************************
@@ -665,10 +665,6 @@ enum {
   XmDROP_INTERRUPT
 };
 
-/* Static data for MOTIF DND */
-static GList **motif_target_lists = NULL;
-static gint motif_n_target_lists = -1;
-
 /* Byte swapping routines. The motif specification leaves it
  * up to us to save a few bytes in the client messages
  */
@@ -680,7 +676,7 @@ print_target_list (GList *targets)
 {
   while (targets)
     {
-      gchar *name = gdk_atom_name (GPOINTER_TO_INT (targets->data));
+      gchar *name = gdk_atom_name (GDK_POINTER_TO_ATOM (targets->data));
       g_message ("\t%s", name);
       g_free (name);
       targets = targets->next;
@@ -760,49 +756,44 @@ typedef struct _MotifDragReceiverInfo {
   guint32 total_size;
 } MotifDragReceiverInfo;
 
-static Window motif_drag_window = None;
-static GdkWindow *motif_drag_gdk_window = NULL;
-
-static GdkAtom motif_drag_targets_atom = GDK_NONE;
-static GdkAtom motif_drag_receiver_info_atom = GDK_NONE;
-
 /* Target table handling */
 
-GdkFilterReturn
+static GdkFilterReturn
 motif_drag_window_filter (GdkXEvent *xevent,
                          GdkEvent  *event,
                          gpointer data)
 {
   XEvent *xev = (XEvent *)xevent;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (event->any.window); 
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
 
   switch (xev->xany.type)
     {
     case DestroyNotify:
-      motif_drag_window = None;
-      motif_drag_gdk_window = NULL;
+      display_x11->motif_drag_window = None;
+      display_x11->motif_drag_gdk_window = NULL;
       break;
     case PropertyNotify:
-      if (motif_target_lists &&
-         motif_drag_targets_atom &&
-         (xev->xproperty.atom == motif_drag_targets_atom))
-       motif_read_target_table();
+      if (display_x11->motif_target_lists &&
+         (xev->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS")))
+       motif_read_target_table (display);
       break;
     }
   return GDK_FILTER_REMOVE;
 }
 
-static Atom motif_drag_window_atom = GDK_NONE;
-
 static Window
-motif_lookup_drag_window (Display *display)
+motif_lookup_drag_window (GdkDisplay *display,
+                         Display    *lookup_xdisplay)
 {
   Window retval = None;
   gulong bytes_after, nitems;
-  GdkAtom type;
+  Atom type;
   gint format;
   guchar *data;
 
-  XGetWindowProperty (gdk_display, gdk_root_window, motif_drag_window_atom,
+  XGetWindowProperty (lookup_xdisplay, RootWindow (lookup_xdisplay, 0),
+                     gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW"),
                      0, 1, FALSE,
                      XA_WINDOW, &type, &format, &nitems, &bytes_after,
                      &data);
@@ -810,8 +801,8 @@ motif_lookup_drag_window (Display *display)
   if ((format == 32) && (nitems == 1) && (bytes_after == 0))
     {
       retval = *(Window *)data;
-      GDK_NOTE(DND, 
-              g_message ("Found drag window %#lx\n", motif_drag_window));
+      GDK_NOTE (DND, 
+               g_message ("Found drag window %#lx\n", GDK_DISPLAY_X11 (display)->motif_drag_window));
     }
 
   if (type != None)
@@ -823,122 +814,134 @@ motif_lookup_drag_window (Display *display)
 /* Finds the window where global Motif drag information is stored.
  * If it doesn't exist and 'create' is TRUE, create one.
  */
-Window 
-motif_find_drag_window (gboolean create)
+static Window 
+motif_find_drag_window (GdkDisplay *display,
+                       gboolean    create)
 {
-  if (!motif_drag_window)
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  
+  if (!display_x11->motif_drag_window)
     {
-      if (!motif_drag_window_atom)
-       motif_drag_window_atom = gdk_atom_intern ("_MOTIF_DRAG_WINDOW", TRUE);
-
-      motif_drag_window = motif_lookup_drag_window (gdk_display);
+      Atom motif_drag_window_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW");
+      display_x11->motif_drag_window = motif_lookup_drag_window (display, display_x11->xdisplay);
       
-      if (!motif_drag_window && create)
+      if (!display_x11->motif_drag_window && create)
        {
          /* Create a persistant window. (Copied from LessTif) */
          
-         Display *display;
+         Display *persistant_xdisplay;
          XSetWindowAttributes attr;
-         display = XOpenDisplay (NULL);
-         XSetCloseDownMode (display, RetainPermanent);
+         persistant_xdisplay = XOpenDisplay (gdk_display_get_name (display));
+         XSetCloseDownMode (persistant_xdisplay, RetainPermanent);
 
-         XGrabServer (display);
+         XGrabServer (persistant_xdisplay);
          
-         motif_drag_window = motif_lookup_drag_window (display);
+         display_x11->motif_drag_window = motif_lookup_drag_window (display, persistant_xdisplay);
 
-         if (!motif_drag_window)
+         if (!display_x11->motif_drag_window)
            {
              attr.override_redirect = True;
              attr.event_mask = PropertyChangeMask;
              
-             motif_drag_window = 
-               XCreateWindow(display, DefaultRootWindow(display),
+              display_x11->motif_drag_window = 
+               XCreateWindow (persistant_xdisplay, 
+                              RootWindow (persistant_xdisplay, 0),
                              -100, -100, 10, 10, 0, 0,
-                             InputOnly, CopyFromParent,
+                             InputOnly, (Visual *)CopyFromParent,
                              (CWOverrideRedirect | CWEventMask), &attr);
              
              GDK_NOTE (DND,
-                       g_message ("Created drag window %#lx\n", motif_drag_window));
+                       g_message ("Created drag window %#lx\n", display_x11->motif_drag_window));
              
-             XChangeProperty (display, gdk_root_window,
+             XChangeProperty (persistant_xdisplay, 
+                              RootWindow (persistant_xdisplay, 0),
                               motif_drag_window_atom, XA_WINDOW,
                               32, PropModeReplace,
                               (guchar *)&motif_drag_window_atom, 1);
 
            }
-         XUngrabServer (display);
-         XCloseDisplay (display);
+         XUngrabServer (persistant_xdisplay);
+         XCloseDisplay (persistant_xdisplay);
        }
 
       /* There is a miniscule race condition here if the drag window
        * gets destroyed exactly now.
        */
-      if (motif_drag_window)
+      if (display_x11->motif_drag_window)
        {
-         motif_drag_gdk_window = gdk_window_foreign_new (motif_drag_window);
-         gdk_window_add_filter (motif_drag_gdk_window,
+         display_x11->motif_drag_gdk_window = 
+           gdk_window_foreign_new_for_display (display, display_x11->motif_drag_window);
+         gdk_window_add_filter (display_x11->motif_drag_gdk_window,
                                 motif_drag_window_filter,
                                 NULL);
        }
     }
 
-  return motif_drag_window;
+  return display_x11->motif_drag_window;
 }
 
 static void 
-motif_read_target_table (void)
+motif_read_target_table (GdkDisplay *display)
 {
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
   gulong bytes_after, nitems;
-  GdkAtom type;
+  Atom type;
   gint format;
   gint i, j;
+  
+  Atom motif_drag_targets_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS");
 
-  if (!motif_drag_targets_atom)
-    motif_drag_targets_atom = gdk_atom_intern ("_MOTIF_DRAG_TARGETS", FALSE);
-
-  if (motif_target_lists)
+  if (display_x11->motif_target_lists)
     {
-      for (i=0; i<motif_n_target_lists; i++)
-       g_list_free (motif_target_lists[i]);
+      for (i=0; i<display_x11->motif_n_target_lists; i++)
+       g_list_free (display_x11->motif_target_lists[i]);
       
-      g_free (motif_target_lists);
-      motif_target_lists = NULL;
-      motif_n_target_lists = 0;
+      g_free (display_x11->motif_target_lists);
+      display_x11->motif_target_lists = NULL;
+      display_x11->motif_n_target_lists = 0;
     }
 
-  if (motif_find_drag_window (FALSE))
+  if (motif_find_drag_window (display, FALSE))
     {
+      guchar *data;
       MotifTargetTableHeader *header = NULL;
       guchar *target_bytes = NULL;
       guchar *p;
       gboolean success = FALSE;
 
-      XGetWindowProperty (gdk_display, motif_drag_window, 
+      gdk_error_trap_push ();
+      XGetWindowProperty (display_x11->xdisplay, 
+                         display_x11->motif_drag_window, 
                          motif_drag_targets_atom,
                          0, (sizeof(MotifTargetTableHeader)+3)/4, FALSE,
                          motif_drag_targets_atom, 
                          &type, &format, &nitems, &bytes_after,
-                         (guchar **)&header);
+                         &data);
 
-      if ((format != 8) || (nitems < sizeof (MotifTargetTableHeader)))
+      if (gdk_error_trap_pop () || (format != 8) || (nitems < sizeof (MotifTargetTableHeader)))
        goto error;
 
+      header = (MotifTargetTableHeader *)data;
+
       header->n_lists = card16_to_host (header->n_lists, header->byte_order);
       header->total_size = card32_to_host (header->total_size, header->byte_order);
 
-      XGetWindowProperty (gdk_display, motif_drag_window, motif_drag_targets_atom,
+      gdk_error_trap_push ();
+      XGetWindowProperty (display_x11->xdisplay, 
+                         display_x11->motif_drag_window, 
+                         motif_drag_targets_atom,
                          (sizeof(MotifTargetTableHeader)+3)/4, 
                          (header->total_size + 3)/4 - (sizeof(MotifTargetTableHeader) + 3)/4,
                          FALSE,
                          motif_drag_targets_atom, &type, &format, &nitems, 
                          &bytes_after, &target_bytes);
       
-      if ((format != 8) || (bytes_after != 0) || 
+      if (gdk_error_trap_pop () || (format != 8) || (bytes_after != 0) || 
          (nitems != header->total_size - sizeof(MotifTargetTableHeader)))
          goto error;
 
-      motif_n_target_lists = header->n_lists;
-      motif_target_lists = g_new0 (GList *, motif_n_target_lists);
+      display_x11->motif_n_target_lists = header->n_lists;
+      display_x11->motif_target_lists = g_new0 (GList *, display_x11->motif_n_target_lists);
 
       p = target_bytes;
       for (i=0; i<header->n_lists; i++)
@@ -962,12 +965,12 @@ motif_read_target_table (void)
            goto error;
 
          for (j=0; j<n_targets; j++)
-           motif_target_lists[i] = 
-             g_list_prepend (motif_target_lists[i],
-                             GUINT_TO_POINTER (card32_to_host (targets[j], 
+           display_x11->motif_target_lists[i] = 
+             g_list_prepend (display_x11->motif_target_lists[i],
+                             GUINT_TO_POINTER (card32_to_host (targets[j],
                                                                header->byte_order)));
          g_free (targets);
-         motif_target_lists[i] = g_list_reverse (motif_target_lists[i]);
+         display_x11->motif_target_lists[i] = g_list_reverse (display_x11->motif_target_lists[i]);
        }
 
       success = TRUE;
@@ -981,11 +984,11 @@ motif_read_target_table (void)
 
       if (!success)
        {
-         if (motif_target_lists)
+         if (display_x11->motif_target_lists)
            {
-             g_free (motif_target_lists);
-             motif_target_lists = NULL;
-             motif_n_target_lists = 0;
+             g_free (display_x11->motif_target_lists);
+             display_x11->motif_target_lists = NULL;
+             display_x11->motif_n_target_lists = 0;
            }
          g_warning ("Error reading Motif target table\n");
        }
@@ -1000,15 +1003,17 @@ targets_sort_func (gconstpointer a, gconstpointer b)
 }
 
 /* Check if given (sorted) list is in the targets table */
-static gboolean
-motif_target_table_check (GList *sorted)
+static gint
+motif_target_table_check (GdkDisplay *display,
+                         GList      *sorted)
 {
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
   GList *tmp_list1, *tmp_list2;
   gint i;
 
-  for (i=0; i<motif_n_target_lists; i++)
+  for (i=0; i<display_x11->motif_n_target_lists; i++)
     {
-      tmp_list1 = motif_target_lists[i];
+      tmp_list1 = display_x11->motif_target_lists[i];
       tmp_list2 = sorted;
       
       while (tmp_list1 && tmp_list2)
@@ -1027,8 +1032,10 @@ motif_target_table_check (GList *sorted)
 }
 
 static gint
-motif_add_to_target_table (GList *targets)
+motif_add_to_target_table (GdkDisplay *display,
+                          GList      *targets) /* targets is list of GdkAtom */
 {
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
   GList *sorted = NULL;
   gint index = -1;
   gint i;
@@ -1038,14 +1045,15 @@ motif_add_to_target_table (GList *targets)
   
   while (targets)
     {
-      sorted = g_list_insert_sorted (sorted, targets->data, targets_sort_func);
+      Atom xatom = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (targets->data));
+      sorted = g_list_insert_sorted (sorted, GUINT_TO_POINTER (xatom), targets_sort_func);
       targets = targets->next;
     }
 
-  /* First check if it is their already */
+  /* First check if it is there already */
 
-  if (motif_target_lists)
-    index = motif_target_table_check (sorted);
+  if (display_x11->motif_target_lists)
+    index = motif_target_table_check (display, sorted);
 
   /* We need to grab the server while doing this, to ensure
    * atomiticity. Ugh
@@ -1057,15 +1065,15 @@ motif_add_to_target_table (GList *targets)
        * server, since we can't open a new connection after we
        * grab the server. 
        */
-      motif_find_drag_window (TRUE);
+      motif_find_drag_window (display, TRUE);
 
-      XGrabServer(gdk_display);
-      motif_read_target_table();
+      gdk_x11_display_grab (display);
+      motif_read_target_table (display);
     
       /* Check again, in case it was added in the meantime */
       
-      if (motif_target_lists)
-       index =  motif_target_table_check (sorted);
+      if (display_x11->motif_target_lists)
+       index = motif_target_table_check (display, sorted);
 
       if (index < 0)
        {
@@ -1075,24 +1083,24 @@ motif_add_to_target_table (GList *targets)
          guint16 *p16;
          MotifTargetTableHeader *header;
          
-         if (!motif_target_lists)
+         if (!display_x11->motif_target_lists)
            {
-             motif_target_lists = g_new (GList *, 1);
-             motif_n_target_lists = 1;
+             display_x11->motif_target_lists = g_new (GList *, 1);
+             display_x11->motif_n_target_lists = 1;
            }
          else
            {
-             motif_n_target_lists++;
-             motif_target_lists = g_realloc (motif_target_lists,
-                                             sizeof(GList *) * motif_n_target_lists);
+             display_x11->motif_n_target_lists++;
+             display_x11->motif_target_lists = g_realloc (display_x11->motif_target_lists,
+                                                          sizeof(GList *) * display_x11->motif_n_target_lists);
            }
-         motif_target_lists[motif_n_target_lists - 1] = sorted;
+         display_x11->motif_target_lists[display_x11->motif_n_target_lists - 1] = sorted;
          sorted = NULL;
-         index = motif_n_target_lists - 1;
+         index = display_x11->motif_n_target_lists - 1;
 
          total_size = sizeof (MotifTargetTableHeader);
-         for (i = 0; i < motif_n_target_lists ; i++)
-           total_size += sizeof(guint16) + sizeof(guint32) * g_list_length (motif_target_lists[i]);
+         for (i = 0; i < display_x11->motif_n_target_lists ; i++)
+           total_size += sizeof(guint16) + sizeof(guint32) * g_list_length (display_x11->motif_target_lists[i]);
 
          data = g_malloc (total_size);
 
@@ -1101,16 +1109,16 @@ motif_add_to_target_table (GList *targets)
 
          header->byte_order = local_byte_order;
          header->protocol_version = 0;
-         header->n_lists = motif_n_target_lists;
+         header->n_lists = display_x11->motif_n_target_lists;
          header->total_size = total_size;
 
-         for (i = 0; i < motif_n_target_lists ; i++)
+         for (i = 0; i < display_x11->motif_n_target_lists ; i++)
            {
-             guint16 n_targets = g_list_length (motif_target_lists[i]);
+             guint16 n_targets = g_list_length (display_x11->motif_target_lists[i]);
              guint32 *targets = g_new (guint32, n_targets);
              guint32 *p32 = targets;
              
-             tmp_list = motif_target_lists[i];
+             tmp_list = display_x11->motif_target_lists[i];
              while (tmp_list)
                {
                  *p32 = GPOINTER_TO_UINT (tmp_list->data);
@@ -1129,13 +1137,14 @@ motif_add_to_target_table (GList *targets)
              g_free (targets);
            }
 
-         XChangeProperty (gdk_display, motif_drag_window,
-                          motif_drag_targets_atom,
-                          motif_drag_targets_atom,
+         XChangeProperty (display_x11->xdisplay,
+                          display_x11->motif_drag_window,
+                          gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
+                          gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
                           8, PropModeReplace,
                           data, total_size);
        }
-      XUngrabServer(gdk_display);
+      gdk_x11_display_ungrab (display);
     }
 
   g_list_free (sorted);
@@ -1211,134 +1220,146 @@ motif_dnd_get_flags (GdkDragContext *context)
 static void
 motif_set_targets (GdkDragContext *context)
 {
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
   MotifDragInitiatorInfo info;
   gint i;
-  static GdkAtom motif_drag_initiator_info = GDK_NONE;
-
-  if (!motif_drag_initiator_info)
-    motif_drag_initiator_info = gdk_atom_intern ("_MOTIF_DRAG_INITIATOR_INFO", FALSE);
-
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
+  
   info.byte_order = local_byte_order;
   info.protocol_version = 0;
   
-  info.targets_index = motif_add_to_target_table (context->targets);
+  info.targets_index = motif_add_to_target_table (display, context->targets);
 
   for (i=0; ; i++)
     {
       gchar buf[20];
       g_snprintf(buf, 20, "_GDK_SELECTION_%d", i);
       
-      private->motif_selection = gdk_atom_intern (buf, FALSE);
-      if (!XGetSelectionOwner (gdk_display, private->motif_selection))
+      private->motif_selection = gdk_x11_get_xatom_by_name_for_display (display, buf);
+      if (!XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), private->motif_selection))
        break;
     }
 
   info.selection_atom = private->motif_selection;
 
-  XChangeProperty (GDK_WINDOW_XDISPLAY (context->source_window),
-                  GDK_WINDOW_XWINDOW (context->source_window),
+  XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
+                  GDK_DRAWABLE_XID (context->source_window),
                   private->motif_selection,
-                  motif_drag_initiator_info, 8, PropModeReplace,
+                  gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
+                  8, PropModeReplace,
                   (guchar *)&info, sizeof (info));
 
   private->motif_targets_set = 1;
 }
 
-guint32
-motif_check_dest (Window win)
+static guint32
+motif_check_dest (GdkDisplay *display,
+                 Window      win)
 {
   gboolean retval = FALSE;
+  guchar *data;
   MotifDragReceiverInfo *info;
   Atom type = None;
   int format;
   unsigned long nitems, after;
+  Atom motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO");
 
-  if (!motif_drag_receiver_info_atom)
-    motif_drag_receiver_info_atom = gdk_atom_intern ("_MOTIF_DRAG_RECEIVER_INFO", FALSE);
-
-  XGetWindowProperty (gdk_display, win, 
+  gdk_error_trap_push ();
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win, 
                      motif_drag_receiver_info_atom, 
                      0, (sizeof(*info)+3)/4, False, AnyPropertyType,
                      &type, &format, &nitems, &after, 
-                     (guchar **)&info);
-  
-  if (type != None)
+                     &data);
+
+  if (gdk_error_trap_pop() == 0)
     {
-      if ((format == 8) && (nitems == sizeof(*info)))
-       {
-         if ((info->protocol_version == 0) &&
-             ((info->protocol_style == XmDRAG_PREFER_PREREGISTER) ||
-              (info->protocol_style == XmDRAG_PREFER_DYNAMIC) ||
-              (info->protocol_style == XmDRAG_DYNAMIC)))
-           retval = TRUE;
-       }
-      else
+      if (type != None)
        {
-         GDK_NOTE (DND, 
-                   g_warning ("Invalid Motif drag receiver property on window %ld\n", win));
+         info = (MotifDragReceiverInfo *)data;
+         
+         if ((format == 8) && (nitems == sizeof(*info)))
+           {
+             if ((info->protocol_version == 0) &&
+                 ((info->protocol_style == XmDRAG_PREFER_PREREGISTER) ||
+                  (info->protocol_style == XmDRAG_PREFER_DYNAMIC) ||
+                  (info->protocol_style == XmDRAG_DYNAMIC)))
+               retval = TRUE;
+           }
+         else
+           {
+             GDK_NOTE (DND, 
+                       g_warning ("Invalid Motif drag receiver property on window %ld\n", win));
+           }
+         
+         XFree (info);
        }
-
-      XFree (info);
     }
 
-  return retval ? win : GDK_NONE;
-  
+  return retval ? win : None;
 }
 
 static void
 motif_send_enter (GdkDragContext  *context,
                  guint32          time)
 {
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
   XEvent xev;
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+
+  if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+    return; /* Motif Dnd requires getting properties on the root window */
 
   xev.xclient.type = ClientMessage;
-  xev.xclient.message_type = gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE);
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
   xev.xclient.format = 8;
-  xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
+  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
 
   MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_ENTER;
   MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
   MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
   MOTIF_XCLIENT_LONG (&xev, 1) = time;
-  MOTIF_XCLIENT_LONG (&xev, 2) = GDK_WINDOW_XWINDOW (context->source_window);
+  MOTIF_XCLIENT_LONG (&xev, 2) = GDK_DRAWABLE_XID (context->source_window);
 
   if (!private->motif_targets_set)
     motif_set_targets (context);
 
   MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection;
+  MOTIF_XCLIENT_LONG (&xev, 4) = 0;
 
-  if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
-                       FALSE, 0, &xev))
+  if (!_gdk_send_xevent (display,
+                        GDK_DRAWABLE_XID (context->dest_window),
+                        FALSE, 0, &xev))
     GDK_NOTE (DND, 
              g_message ("Send event to %lx failed",
-                        GDK_WINDOW_XWINDOW (context->dest_window)));
+                        GDK_DRAWABLE_XID (context->dest_window)));
 }
 
 static void
 motif_send_leave (GdkDragContext  *context,
                  guint32          time)
 {
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
   XEvent xev;
 
   xev.xclient.type = ClientMessage;
-  xev.xclient.message_type = gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE);
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
   xev.xclient.format = 8;
-  xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
+  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
 
   MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_LEAVE;
   MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
   MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
   MOTIF_XCLIENT_LONG (&xev, 1) = time;
-  MOTIF_XCLIENT_LONG (&xev, 2) = GDK_WINDOW_XWINDOW (context->source_window);
+  MOTIF_XCLIENT_LONG (&xev, 2) = 0;
   MOTIF_XCLIENT_LONG (&xev, 3) = 0;
+  MOTIF_XCLIENT_LONG (&xev, 4) = 0;
 
-  if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
-                       FALSE, 0, &xev))
+  if (!_gdk_send_xevent (display,
+                        GDK_DRAWABLE_XID (context->dest_window),
+                        FALSE, 0, &xev))
     GDK_NOTE (DND, 
              g_message ("Send event to %lx failed",
-                        GDK_WINDOW_XWINDOW (context->dest_window)));
+                        GDK_DRAWABLE_XID (context->dest_window)));
 }
 
 static gboolean
@@ -1348,24 +1369,28 @@ motif_send_motion (GdkDragContext  *context,
                    GdkDragAction   action,
                    guint32         time)
 {
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
   gboolean retval;
   XEvent xev;
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
 
   xev.xclient.type = ClientMessage;
-  xev.xclient.message_type = gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE);
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
   xev.xclient.format = 8;
-  xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
+  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
 
   MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
   MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
   MOTIF_XCLIENT_LONG (&xev, 1) = time;
+  MOTIF_XCLIENT_LONG (&xev, 3) = 0;
+  MOTIF_XCLIENT_LONG (&xev, 4) = 0;
 
-  if (context->suggested_action != private->old_action)
+  if ((context->suggested_action != private->old_action) ||
+      (context->actions != private->old_actions))
     {
       MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
 
-      private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
+      /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
       retval = TRUE;
     }
   else
@@ -1379,11 +1404,12 @@ motif_send_motion (GdkDragContext  *context,
       retval = FALSE;
     }
 
-  if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
-                       FALSE, 0, &xev))
+  if (!_gdk_send_xevent (display,
+                        GDK_DRAWABLE_XID (context->dest_window),
+                        FALSE, 0, &xev))
     GDK_NOTE (DND, 
              g_message ("Send event to %lx failed",
-                        GDK_WINDOW_XWINDOW (context->dest_window)));
+                        GDK_DRAWABLE_XID (context->dest_window)));
 
   return retval;
 }
@@ -1391,13 +1417,14 @@ motif_send_motion (GdkDragContext  *context,
 static void
 motif_send_drop (GdkDragContext *context, guint32 time)
 {
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
   XEvent xev;
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
 
   xev.xclient.type = ClientMessage;
-  xev.xclient.message_type = gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE);
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
   xev.xclient.format = 8;
-  xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
+  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
 
   MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START;
   MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
@@ -1408,73 +1435,76 @@ motif_send_drop (GdkDragContext *context, guint32 time)
   MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
 
   MOTIF_XCLIENT_LONG (&xev, 3)  = private->motif_selection;
-  MOTIF_XCLIENT_LONG (&xev, 4)  = GDK_WINDOW_XWINDOW (context->source_window);
+  MOTIF_XCLIENT_LONG (&xev, 4)  = GDK_DRAWABLE_XID (context->source_window);
 
-  if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
-                       FALSE, 0, &xev))
+  if (!_gdk_send_xevent (display,
+                        GDK_DRAWABLE_XID (context->dest_window),
+                        FALSE, 0, &xev))
     GDK_NOTE (DND, 
              g_message ("Send event to %lx failed",
-                        GDK_WINDOW_XWINDOW (context->dest_window)));
+                        GDK_DRAWABLE_XID (context->dest_window)));
 }
 
 /* Target Side */
 
 static gboolean
-motif_read_initiator_info (Window source_window, 
-                          Atom atom,
-                          GList  **targets,
-                          GdkAtom *selection)
+motif_read_initiator_info (GdkDisplay *display,
+                          Window      source_window, 
+                          Atom        atom,
+                          GList     **targets,
+                          Atom       *selection)
 {
   GList *tmp_list;
-  static GdkAtom motif_drag_initiator_info = GDK_NONE;
-  GdkAtom type;
+  Atom type;
   gint format;
   gulong nitems;
   gulong bytes_after;
-
+  guchar *data;
   MotifDragInitiatorInfo *initiator_info;
-
-  if (!motif_drag_initiator_info)
-    motif_drag_initiator_info = gdk_atom_intern ("_MOTIF_DRAG_INITIATOR_INFO", FALSE);
-
-  XGetWindowProperty (gdk_display, source_window, atom,
+  
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  
+  gdk_error_trap_push ();
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), source_window, atom,
                      0, sizeof(*initiator_info), FALSE,
-                     motif_drag_initiator_info, 
+                     gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
                      &type, &format, &nitems, &bytes_after,
-                     (guchar **)&initiator_info);
+                     &data);
 
-  if ((format != 8) || (nitems != sizeof (MotifDragInitiatorInfo)) || (bytes_after != 0))
+  if (gdk_error_trap_pop () || (format != 8) || (nitems != sizeof (MotifDragInitiatorInfo)) || (bytes_after != 0))
     {
       g_warning ("Error reading initiator info\n");
       return FALSE;
     }
 
-  motif_read_target_table ();
+  initiator_info = (MotifDragInitiatorInfo *)data;
 
-  if (initiator_info->targets_index >= motif_n_target_lists)
-    {
-      g_warning ("Invalid target index in TOP_LEVEL_ENTER MESSAGE");
-      XFree (initiator_info);
-      return GDK_FILTER_REMOVE;
-    }
+  motif_read_target_table (display);
 
   initiator_info->targets_index = 
     card16_to_host (initiator_info->targets_index, initiator_info->byte_order);
   initiator_info->selection_atom = 
     card32_to_host (initiator_info->selection_atom, initiator_info->byte_order);
   
-  tmp_list = g_list_last (motif_target_lists[initiator_info->targets_index]);
+  if (initiator_info->targets_index >= display_x11->motif_n_target_lists)
+    {
+      g_warning ("Invalid target index in TOP_LEVEL_ENTER MESSAGE");
+      XFree (initiator_info);
+      return FALSE;
+    }
+
+  tmp_list = g_list_last (display_x11->motif_target_lists[initiator_info->targets_index]);
 
   *targets = NULL;
   while (tmp_list)
     {
-      *targets = g_list_prepend (*targets,
-                                tmp_list->data);
+      GdkAtom atom = gdk_x11_xatom_to_atom_for_display (display, GPOINTER_TO_UINT (tmp_list->data));
+      *targets = g_list_prepend (*targets, GDK_ATOM_TO_POINTER (atom));
       tmp_list = tmp_list->prev;
     }
 
 #ifdef G_ENABLE_DEBUG
-  if (gdk_debug_flags & GDK_DEBUG_DND)
+  if (_gdk_debug_flags & GDK_DEBUG_DND)
     print_target_list (*targets);
 #endif /* G_ENABLE_DEBUG */
 
@@ -1492,51 +1522,54 @@ motif_drag_context_new (GdkWindow *dest_window,
                        guint32    atom)
 {
   GdkDragContext *new_context;
-  GdkDragContextPrivate *private;
+  GdkDragContextPrivateX11 *private;
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (dest_window);
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
 
   /* FIXME, current_dest_drag really shouldn't be NULL'd
    * if we error below.
    */
-  if (current_dest_drag != NULL)
+  if (display_x11->current_dest_drag != NULL)
     {
-      if (timestamp >= current_dest_drag->start_time)
+      if (timestamp >= display_x11->current_dest_drag->start_time)
        {
-         gdk_drag_context_unref (current_dest_drag);
-         current_dest_drag = NULL;
+         g_object_unref (display_x11->current_dest_drag);
+         display_x11->current_dest_drag = NULL;
        }
       else
        return NULL;
     }
 
   new_context = gdk_drag_context_new ();
-  private = (GdkDragContextPrivate *)new_context;
+  private = PRIVATE_DATA (new_context);
 
   new_context->protocol = GDK_DRAG_PROTO_MOTIF;
   new_context->is_source = FALSE;
 
-  new_context->source_window = gdk_window_lookup (source_window);
+  new_context->source_window = gdk_window_lookup_for_display (display, source_window);
   if (new_context->source_window)
-    gdk_window_ref (new_context->source_window);
+    g_object_ref (new_context->source_window);
   else
     {
-      new_context->source_window = gdk_window_foreign_new (source_window);
+      new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
       if (!new_context->source_window)
        {
-         gdk_drag_context_unref (new_context);
+         g_object_unref (new_context);
          return NULL;
        }
     }
 
   new_context->dest_window = dest_window;
-  gdk_window_ref (dest_window);
+  g_object_ref (dest_window);
   new_context->start_time = timestamp;
 
-  if (!motif_read_initiator_info(source_window,
-                                atom,
-                                &new_context->targets,
-                                &private->motif_selection))
+  if (!motif_read_initiator_info (GDK_WINDOW_DISPLAY (dest_window),
+                                 source_window,
+                                 atom,
+                                 &new_context->targets,
+                                 &private->motif_selection))
     {
-      gdk_drag_context_unref (new_context);
+      g_object_unref (new_context);
       return NULL;
     }
 
@@ -1557,6 +1590,7 @@ motif_top_level_enter (GdkEvent *event,
                       guint32   source_window, 
                       guint32   atom)
 {
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
   GdkDragContext *new_context;
 
   GDK_NOTE(DND, g_message ("Motif DND top level enter: flags: %#4x time: %d source_widow: %#4x atom: %d",
@@ -1568,30 +1602,32 @@ motif_top_level_enter (GdkEvent *event,
 
   event->dnd.type = GDK_DRAG_ENTER;
   event->dnd.context = new_context;
-  gdk_drag_context_ref (new_context);
+  g_object_ref (new_context);
 
-  current_dest_drag = new_context;
+  display_x11->current_dest_drag = new_context;
 
   return GDK_FILTER_TRANSLATE;
 }
 
-GdkFilterReturn
+static GdkFilterReturn
 motif_top_level_leave (GdkEvent *event,
                       guint16   flags, 
                       guint32   timestamp)
 {
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
+
   GDK_NOTE(DND, g_message ("Motif DND top level leave: flags: %#4x time: %d",
                           flags, timestamp));
 
-  if ((current_dest_drag != NULL) &&
-      (current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
-      (timestamp >= current_dest_drag->start_time))
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
+      (timestamp >= display_x11->current_dest_drag->start_time))
     {
       event->dnd.type = GDK_DRAG_LEAVE;
       /* Pass ownership of context to the event */
-      event->dnd.context = current_dest_drag;
+      event->dnd.context = display_x11->current_dest_drag;
 
-      current_dest_drag = NULL;
+      display_x11->current_dest_drag = NULL;
 
       return GDK_FILTER_TRANSLATE;
     }
@@ -1599,31 +1635,32 @@ motif_top_level_leave (GdkEvent *event,
     return GDK_FILTER_REMOVE;
 }
 
-GdkFilterReturn
+static GdkFilterReturn
 motif_motion (GdkEvent *event,
              guint16   flags, 
              guint32   timestamp,
              gint16    x_root,
              gint16    y_root)
 {
-  GdkDragContextPrivate *private;
-
+  GdkDragContextPrivateX11 *private;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
+  
   GDK_NOTE(DND, g_message ("Motif DND motion: flags: %#4x time: %d (%d, %d)",
                           flags, timestamp, x_root, y_root));
 
-  if ((current_dest_drag != NULL) &&
-      (current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
-      (timestamp >= current_dest_drag->start_time))
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
+      (timestamp >= display_x11->current_dest_drag->start_time))
     {
-      private = (GdkDragContextPrivate *)current_dest_drag;
+      private = PRIVATE_DATA (display_x11->current_dest_drag);
 
       event->dnd.type = GDK_DRAG_MOTION;
-      event->dnd.context = current_dest_drag;
-      gdk_drag_context_ref (current_dest_drag);
+      event->dnd.context = display_x11->current_dest_drag;
+      g_object_ref (display_x11->current_dest_drag);
 
       event->dnd.time = timestamp;
 
-      motif_dnd_translate_flags (current_dest_drag, flags);
+      motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
 
       event->dnd.x_root = x_root;
       event->dnd.y_root = y_root;
@@ -1639,29 +1676,29 @@ motif_motion (GdkEvent *event,
   return GDK_FILTER_REMOVE;
 }
 
-GdkFilterReturn
+static GdkFilterReturn
 motif_operation_changed (GdkEvent *event,
                         guint16   flags, 
                         guint32   timestamp)
 {
-  GdkDragContextPrivate *private;
-
+  GdkDragContextPrivateX11 *private;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
   GDK_NOTE(DND, g_message ("Motif DND operation changed: flags: %#4x time: %d",
                           flags, timestamp));
 
-  if ((current_dest_drag != NULL) &&
-      (current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
-      (timestamp >= current_dest_drag->start_time))
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
+      (timestamp >= display_x11->current_dest_drag->start_time))
     {
       event->dnd.type = GDK_DRAG_MOTION;
       event->dnd.send_event = FALSE;
-      event->dnd.context = current_dest_drag;
-      gdk_drag_context_ref (current_dest_drag);
+      event->dnd.context = display_x11->current_dest_drag;
+      g_object_ref (display_x11->current_dest_drag);
 
       event->dnd.time = timestamp;
-      private = (GdkDragContextPrivate *)current_dest_drag;
+      private = PRIVATE_DATA (display_x11->current_dest_drag);
 
-      motif_dnd_translate_flags (current_dest_drag, flags);
+      motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
 
       event->dnd.x_root = private->last_x;
       event->dnd.y_root = private->last_y;
@@ -1674,7 +1711,7 @@ motif_operation_changed (GdkEvent *event,
   return GDK_FILTER_REMOVE;
 }
 
-GdkFilterReturn
+static GdkFilterReturn
 motif_drop_start (GdkEvent *event,
                  guint16   flags,
                  guint32   timestamp,
@@ -1684,7 +1721,7 @@ motif_drop_start (GdkEvent *event,
                  gint16    y_root)
 {
   GdkDragContext *new_context;
-
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
 
   GDK_NOTE(DND, g_message ("Motif DND drop start: flags: %#4x time: %d (%d, %d) source_widow: %#4x atom: %d",
                           flags, timestamp, x_root, y_root, source_window, atom));
@@ -1701,36 +1738,42 @@ motif_drop_start (GdkEvent *event,
   event->dnd.x_root = x_root;
   event->dnd.y_root = y_root;
 
-  gdk_drag_context_ref (new_context);
-  current_dest_drag = new_context;
+  gdk_x11_window_set_user_time (event->any.window, timestamp);
+
+  g_object_ref (new_context);
+  display_x11->current_dest_drag = new_context;
 
   return GDK_FILTER_TRANSLATE;
 }  
 
-GdkFilterReturn
+static GdkFilterReturn
 motif_drag_status (GdkEvent *event,
                   guint16   flags,
                   guint32   timestamp)
 {
   GdkDragContext *context;
+  GdkDisplay *display;
   
   GDK_NOTE (DND, 
            g_message ("Motif status message: flags %x", flags));
 
-  context = gdk_drag_context_find (TRUE, 
-                                  GDK_WINDOW_XWINDOW (event->any.window), 
-                                  None);
+  display = gdk_drawable_get_display (event->any.window);
+  if (!display)
+    return GDK_FILTER_REMOVE;
+  
+  context = gdk_drag_context_find (display, TRUE, GDK_DRAWABLE_XID (event->any.window), None);
 
   if (context)
     {
-      GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
-      if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
+      GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+      if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
+         (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
        private->drag_status = GDK_DRAG_STATUS_DRAG;
       
       event->dnd.type = GDK_DRAG_STATUS;
       event->dnd.send_event = FALSE;
       event->dnd.context = context;
-      gdk_drag_context_ref (context);
+      g_object_ref (context);
 
       event->dnd.time = timestamp;
 
@@ -1760,7 +1803,7 @@ motif_drag_status (GdkEvent *event,
   return GDK_FILTER_REMOVE;
 }
 
-GdkFilterReturn
+static GdkFilterReturn
 motif_dnd_filter (GdkXEvent *xev,
                  GdkEvent  *event,
                  gpointer data)
@@ -1771,9 +1814,13 @@ motif_dnd_filter (GdkXEvent *xev,
   guint16 flags;
   guint32 timestamp;
   guint32 source_window;
-  GdkAtom atom;
+  Atom atom;
   gint16 x_root, y_root;
   gboolean is_reply;
+
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;                        /* Not for us */
   
   /* First read some fields common to all Motif DND messages */
 
@@ -1844,15 +1891,15 @@ motif_dnd_filter (GdkXEvent *xev,
 /* Utility functions */
 
 static struct {
-  gchar *name;
+  const gchar *name;
   GdkAtom atom;
   GdkDragAction action;
 } xdnd_actions_table[] = {
-    { "XdndActionCopy",    GDK_NONE, GDK_ACTION_COPY },
-    { "XdndActionMove",    GDK_NONE, GDK_ACTION_MOVE },
-    { "XdndActionLink",    GDK_NONE, GDK_ACTION_LINK },
-    { "XdndActionAsk",     GDK_NONE, GDK_ACTION_ASK  },
-    { "XdndActionPrivate", GDK_NONE, GDK_ACTION_COPY },
+    { "XdndActionCopy",    None, GDK_ACTION_COPY },
+    { "XdndActionMove",    None, GDK_ACTION_MOVE },
+    { "XdndActionLink",    None, GDK_ACTION_LINK },
+    { "XdndActionAsk",     None, GDK_ACTION_ASK  },
+    { "XdndActionPrivate", None, GDK_ACTION_COPY },
   };
 
 static const gint xdnd_n_actions = sizeof(xdnd_actions_table) / sizeof(xdnd_actions_table[0]);
@@ -1865,12 +1912,14 @@ xdnd_initialize_actions (void)
   
   xdnd_actions_initialized = TRUE;
   for (i=0; i < xdnd_n_actions; i++)
-    xdnd_actions_table[i].atom = gdk_atom_intern (xdnd_actions_table[i].name, FALSE);
+    xdnd_actions_table[i].atom = gdk_atom_intern_static_string (xdnd_actions_table[i].name);
 }
 
 static GdkDragAction
-xdnd_action_from_atom (GdkAtom atom)
+xdnd_action_from_atom (GdkDisplay *display,
+                      Atom        xatom)
 {
+  GdkAtom atom = gdk_x11_xatom_to_atom_for_display (display, xatom);
   gint i;
 
   if (!xdnd_actions_initialized)
@@ -1883,8 +1932,9 @@ xdnd_action_from_atom (GdkAtom atom)
   return 0;
 }
 
-static GdkAtom
-xdnd_action_to_atom (GdkDragAction action)
+static Atom
+xdnd_action_to_atom (GdkDisplay    *display,
+                    GdkDragAction  action)
 {
   gint i;
 
@@ -1893,13 +1943,11 @@ xdnd_action_to_atom (GdkDragAction action)
 
   for (i=0; i<xdnd_n_actions; i++)
     if (action == xdnd_actions_table[i].action)
-      return xdnd_actions_table[i].atom;
+      return gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
 
-  return GDK_NONE;
+  return None;
 }
 
-static GdkAtom xdnd_aware_atom = GDK_NONE;
-
 /* Source side */
 
 static GdkFilterReturn 
@@ -1907,28 +1955,34 @@ xdnd_status_filter (GdkXEvent *xev,
                    GdkEvent  *event,
                    gpointer   data)
 {
+  GdkDisplay *display;
   XEvent *xevent = (XEvent *)xev;
   guint32 dest_window = xevent->xclient.data.l[0];
   guint32 flags = xevent->xclient.data.l[1];
-  GdkAtom action = xevent->xclient.data.l[4];
+  Atom action = xevent->xclient.data.l[4];
   GdkDragContext *context;
+
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;                        /* Not for us */
   
   GDK_NOTE (DND, 
            g_message ("XdndStatus: dest_window: %#x  action: %ld",
                       dest_window, action));
 
+  display = gdk_drawable_get_display (event->any.window);
+  context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
   
-  context = gdk_drag_context_find (TRUE, xevent->xclient.window, dest_window);
   if (context)
     {
-      GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+      GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
       if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
        private->drag_status = GDK_DRAG_STATUS_DRAG;
       
       event->dnd.send_event = FALSE;
       event->dnd.type = GDK_DRAG_STATUS;
       event->dnd.context = context;
-      gdk_drag_context_ref (context);
+      g_object_ref (context);
 
       event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
       if (!(action != 0) != !(flags & 1))
@@ -1938,7 +1992,7 @@ xdnd_status_filter (GdkXEvent *xev,
          action = 0;
        }
 
-      context->action = xdnd_action_from_atom (action);
+      context->action = xdnd_action_from_atom (display, action);
 
       return GDK_FILTER_TRANSLATE;
     }
@@ -1951,19 +2005,33 @@ xdnd_finished_filter (GdkXEvent *xev,
                      GdkEvent  *event,
                      gpointer   data)
 {
+  GdkDisplay *display;
   XEvent *xevent = (XEvent *)xev;
   guint32 dest_window = xevent->xclient.data.l[0];
   GdkDragContext *context;
+  GdkDragContextPrivateX11 *private;
+
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;                        /* Not for us */
   
   GDK_NOTE (DND, 
            g_message ("XdndFinished: dest_window: %#x", dest_window));
 
-  context = gdk_drag_context_find (TRUE, xevent->xclient.window, dest_window);
+  display = gdk_drawable_get_display (event->any.window);
+  context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
+  
   if (context)
     {
+      private = PRIVATE_DATA (context);
+      if (private->version == 5)
+       private->drop_failed = xevent->xclient.data.l[1] == 0;
+      
       event->dnd.type = GDK_DROP_FINISHED;
       event->dnd.context = context;
-      gdk_drag_context_ref (context);
+      g_object_ref (context);
+
+      event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
 
       return GDK_FILTER_TRANSLATE;
     }
@@ -1974,42 +2042,46 @@ xdnd_finished_filter (GdkXEvent *xev,
 static void
 xdnd_set_targets (GdkDragContext *context)
 {
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
-  GdkAtom *atomlist;
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  Atom *atomlist;
   GList *tmp_list = context->targets;
   gint i;
   gint n_atoms = g_list_length (context->targets);
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
 
-  atomlist = g_new (GdkAtom, n_atoms);
+  atomlist = g_new (Atom, n_atoms);
   i = 0;
   while (tmp_list)
     {
-      atomlist[i] = GPOINTER_TO_INT (tmp_list->data);
+      atomlist[i] = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (tmp_list->data));
       tmp_list = tmp_list->next;
       i++;
     }
 
-  XChangeProperty (GDK_WINDOW_XDISPLAY (context->source_window),
-                  GDK_WINDOW_XWINDOW (context->source_window),
-                  gdk_atom_intern ("XdndTypeList", FALSE),
+  XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
+                  GDK_DRAWABLE_XID (context->source_window),
+                  gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
                   XA_ATOM, 32, PropModeReplace,
                   (guchar *)atomlist, n_atoms);
 
+  g_free (atomlist);
+
   private->xdnd_targets_set = 1;
 }
 
 static void
 xdnd_set_actions (GdkDragContext *context)
 {
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
-  GdkAtom *atomlist;
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  Atom *atomlist;
   gint i;
   gint n_atoms;
   guint actions;
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
 
   if (!xdnd_actions_initialized)
     xdnd_initialize_actions();
-
+  
   actions = context->actions;
   n_atoms = 0;
   for (i=0; i<xdnd_n_actions; i++)
@@ -2021,7 +2093,7 @@ xdnd_set_actions (GdkDragContext *context)
        }
     }
 
-  atomlist = g_new (GdkAtom, n_atoms);
+  atomlist = g_new (Atom, n_atoms);
 
   actions = context->actions;
   n_atoms = 0;
@@ -2030,39 +2102,161 @@ xdnd_set_actions (GdkDragContext *context)
       if (actions & xdnd_actions_table[i].action)
        {
          actions &= ~xdnd_actions_table[i].action;
-         atomlist[n_atoms] = xdnd_actions_table[i].atom;
+         atomlist[n_atoms] = gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
          n_atoms++;
        }
     }
 
-  XChangeProperty (GDK_WINDOW_XDISPLAY (context->source_window),
-                  GDK_WINDOW_XWINDOW (context->source_window),
-                  gdk_atom_intern ("XdndActionList", FALSE),
+  XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
+                  GDK_DRAWABLE_XID (context->source_window),
+                  gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
                   XA_ATOM, 32, PropModeReplace,
                   (guchar *)atomlist, n_atoms);
 
-  private->xdnd_actions_set = 1;
+  g_free (atomlist);
+
+  private->xdnd_actions_set = TRUE;
+  private->xdnd_actions = context->actions;
+}
+
+static void
+send_client_message_async_cb (Window   window,
+                             gboolean success,
+                             gpointer data)
+{
+  GdkDragContext *context = data;
+  GDK_NOTE (DND,
+           g_message ("Got async callback for #%lx, success = %d",
+                      window, success));
+
+  /* On failure, we immediately continue with the protocol
+   * so we don't end up blocking for a timeout
+   */
+  if (!success &&
+      context->dest_window &&
+      window == GDK_WINDOW_XID (context->dest_window))
+    {
+      GdkEvent temp_event;
+      GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+
+      g_object_unref (context->dest_window);
+      context->dest_window = NULL;
+      context->action = 0;
+
+      private->drag_status = GDK_DRAG_STATUS_DRAG;
+
+      temp_event.dnd.type = GDK_DRAG_STATUS;
+      temp_event.dnd.window = context->source_window;
+      temp_event.dnd.send_event = TRUE;
+      temp_event.dnd.context = context;
+      temp_event.dnd.time = GDK_CURRENT_TIME;
+
+      gdk_event_put (&temp_event);
+    }
+
+  g_object_unref (context);
+}
+
+
+static GdkDisplay *
+gdk_drag_context_get_display (GdkDragContext *context)
+{
+  if (context->source_window)
+    return GDK_DRAWABLE_DISPLAY (context->source_window);
+  else if (context->dest_window)
+    return GDK_DRAWABLE_DISPLAY (context->dest_window);
+
+  g_assert_not_reached ();
+  return NULL;
+}
+
+static void
+send_client_message_async (GdkDragContext      *context,
+                          Window               window, 
+                          gboolean             propagate,
+                          glong                event_mask,
+                          XClientMessageEvent *event_send)
+{
+  GdkDisplay *display = gdk_drag_context_get_display (context);
+  
+  g_object_ref (context);
+
+  _gdk_x11_send_client_message_async (display, window,
+                                     propagate, event_mask, event_send,
+                                     send_client_message_async_cb, context);
 }
 
+static gboolean
+xdnd_send_xevent (GdkDragContext *context,
+                 GdkWindow      *window, 
+                 gboolean        propagate,
+                 XEvent         *event_send)
+{
+  GdkDisplay *display = gdk_drag_context_get_display (context);
+  Window xwindow;
+  glong event_mask;
+
+  g_assert (event_send->xany.type == ClientMessage);
+
+  /* We short-circuit messages to ourselves */
+  if (gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
+    {
+      gint i;
+      
+      for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
+       {
+         if (gdk_x11_get_xatom_by_name_for_display (display, xdnd_filters[i].atom_name) ==
+             event_send->xclient.message_type)
+           {
+             GdkEvent temp_event;
+             temp_event.any.window = window;
+
+             if  ((*xdnd_filters[i].func) (event_send, &temp_event, NULL) == GDK_FILTER_TRANSLATE)
+               {
+                 gdk_event_put (&temp_event);
+                 g_object_unref (temp_event.dnd.context);
+               }
+             
+             return TRUE;
+           }
+       }
+    }
+
+  xwindow = GDK_WINDOW_XWINDOW (window);
+  
+  if (_gdk_x11_display_is_root_window (display, xwindow))
+    event_mask = ButtonPressMask;
+  else
+    event_mask = 0;
+  
+  send_client_message_async (context, xwindow, propagate, event_mask,
+                            &event_send->xclient);
+
+  return TRUE;
+}
 static void
 xdnd_send_enter (GdkDragContext *context)
 {
   XEvent xev;
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->dest_window);
 
   xev.xclient.type = ClientMessage;
-  xev.xclient.message_type = gdk_atom_intern ("XdndEnter", FALSE);
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndEnter");
   xev.xclient.format = 32;
-  xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
-  xev.xclient.data.l[0] = GDK_WINDOW_XWINDOW (context->source_window);
-  xev.xclient.data.l[1] = (3 << 24); /* version */
+  xev.xclient.window = private->drop_xid ? 
+                           private->drop_xid : 
+                           GDK_DRAWABLE_XID (context->dest_window);
+  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
+  xev.xclient.data.l[1] = (private->version << 24); /* version */
   xev.xclient.data.l[2] = 0;
   xev.xclient.data.l[3] = 0;
   xev.xclient.data.l[4] = 0;
 
-  if (!private->xdnd_selection)
-    private->xdnd_selection = gdk_atom_intern ("XdndSelection", FALSE);
-
+  GDK_NOTE(DND,
+          g_message ("Sending enter source window %#lx XDND protocol version %d\n",
+                     GDK_DRAWABLE_XID (context->source_window), private->version));
   if (g_list_length (context->targets) > 3)
     {
       if (!private->xdnd_targets_set)
@@ -2076,22 +2270,20 @@ xdnd_send_enter (GdkDragContext *context)
 
       while (tmp_list)
        {
-         xev.xclient.data.l[i] = GPOINTER_TO_INT (tmp_list->data);
+         xev.xclient.data.l[i] = gdk_x11_atom_to_xatom_for_display (display,
+                                                                    GDK_POINTER_TO_ATOM (tmp_list->data));
          tmp_list = tmp_list->next;
          i++;
        }
     }
 
-  if (!private->xdnd_actions_set)
-    xdnd_set_actions (context);
-
-  if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
-                       FALSE, 0, &xev))
+  if (!xdnd_send_xevent (context, context->dest_window,
+                        FALSE, &xev))
     {
       GDK_NOTE (DND, 
                g_message ("Send event to %lx failed",
-                          GDK_WINDOW_XWINDOW (context->dest_window)));
-      gdk_window_unref (context->dest_window);
+                          GDK_DRAWABLE_XID (context->dest_window)));
+      g_object_unref (context->dest_window);
       context->dest_window = NULL;
     }
 }
@@ -2099,25 +2291,30 @@ xdnd_send_enter (GdkDragContext *context)
 static void
 xdnd_send_leave (GdkDragContext *context)
 {
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
   XEvent xev;
 
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+
   xev.xclient.type = ClientMessage;
-  xev.xclient.message_type = gdk_atom_intern ("XdndLeave", FALSE);
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndLeave");
   xev.xclient.format = 32;
-  xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
-  xev.xclient.data.l[0] = GDK_WINDOW_XWINDOW (context->source_window);
+  xev.xclient.window = private->drop_xid ? 
+                           private->drop_xid : 
+                           GDK_DRAWABLE_XID (context->dest_window);
+  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
   xev.xclient.data.l[1] = 0;
   xev.xclient.data.l[2] = 0;
   xev.xclient.data.l[3] = 0;
   xev.xclient.data.l[4] = 0;
 
-  if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
-                       FALSE, 0, &xev))
+  if (!xdnd_send_xevent (context, context->dest_window,
+                        FALSE, &xev))
     {
       GDK_NOTE (DND, 
                g_message ("Send event to %lx failed",
-                          GDK_WINDOW_XWINDOW (context->dest_window)));
-      gdk_window_unref (context->dest_window);
+                          GDK_DRAWABLE_XID (context->dest_window)));
+      g_object_unref (context->dest_window);
       context->dest_window = NULL;
     }
 }
@@ -2125,25 +2322,29 @@ xdnd_send_leave (GdkDragContext *context)
 static void
 xdnd_send_drop (GdkDragContext *context, guint32 time)
 {
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
   XEvent xev;
 
   xev.xclient.type = ClientMessage;
-  xev.xclient.message_type = gdk_atom_intern ("XdndDrop", FALSE);
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndDrop");
   xev.xclient.format = 32;
-  xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
-  xev.xclient.data.l[0] = GDK_WINDOW_XWINDOW (context->source_window);
+  xev.xclient.window = private->drop_xid ? 
+                           private->drop_xid : 
+                           GDK_DRAWABLE_XID (context->dest_window);
+  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
   xev.xclient.data.l[1] = 0;
   xev.xclient.data.l[2] = time;
   xev.xclient.data.l[3] = 0;
   xev.xclient.data.l[4] = 0;
 
-  if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
-                       FALSE, 0, &xev))
+  if (!xdnd_send_xevent (context, context->dest_window,
+                        FALSE, &xev))
     {
       GDK_NOTE (DND, 
                g_message ("Send event to %lx failed",
-                          GDK_WINDOW_XWINDOW (context->dest_window)));
-      gdk_window_unref (context->dest_window);
+                          GDK_DRAWABLE_XID (context->dest_window)));
+      g_object_unref (context->dest_window);
       context->dest_window = NULL;
     }
 }
@@ -2155,112 +2356,307 @@ xdnd_send_motion (GdkDragContext *context,
                  GdkDragAction   action,
                  guint32         time)
 {
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
   XEvent xev;
 
   xev.xclient.type = ClientMessage;
-  xev.xclient.message_type = gdk_atom_intern ("XdndPosition", FALSE);
+  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndPosition");
   xev.xclient.format = 32;
-  xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window);
-  xev.xclient.data.l[0] = GDK_WINDOW_XWINDOW (context->source_window);
+  xev.xclient.window = private->drop_xid ? 
+                           private->drop_xid : 
+                           GDK_DRAWABLE_XID (context->dest_window);
+  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
   xev.xclient.data.l[1] = 0;
   xev.xclient.data.l[2] = (x_root << 16) | y_root;
   xev.xclient.data.l[3] = time;
-  xev.xclient.data.l[4] = xdnd_action_to_atom (action);
+  xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
 
-  if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
-                       FALSE, 0, &xev))
+  if (!xdnd_send_xevent (context, context->dest_window,
+                        FALSE, &xev))
     {
       GDK_NOTE (DND, 
                g_message ("Send event to %lx failed",
-                          GDK_WINDOW_XWINDOW (context->dest_window)));
-      gdk_window_unref (context->dest_window);
+                          GDK_DRAWABLE_XID (context->dest_window)));
+      g_object_unref (context->dest_window);
       context->dest_window = NULL;
     }
   private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
 }
 
 static guint32
-xdnd_check_dest (Window win)
+xdnd_check_dest (GdkDisplay *display,
+                Window      win,
+                guint      *xdnd_version)
 {
   gboolean retval = FALSE;
   Atom type = None;
   int format;
   unsigned long nitems, after;
-  GdkAtom *version;
+  guchar *data;
+  Atom *version;
   Window *proxy_data;
   Window proxy;
-  static GdkAtom xdnd_proxy_atom = GDK_NONE;
-
-  gint old_warnings = gdk_error_warnings;
-
-  if (!xdnd_proxy_atom)
-    xdnd_proxy_atom = gdk_atom_intern ("XdndProxy", FALSE);
+  Atom xdnd_proxy_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndProxy");
+  Atom xdnd_aware_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndAware");
 
-  if (!xdnd_aware_atom)
-    xdnd_aware_atom = gdk_atom_intern ("XdndAware", FALSE);
+  proxy = None;
 
-  proxy = GDK_NONE;
+  gdk_error_trap_push ();
   
-  gdk_error_code = 0;
-  gdk_error_warnings = 0;
-
-  XGetWindowProperty (gdk_display, win, 
-                     xdnd_proxy_atom, 0, 
-                     1, False, AnyPropertyType,
-                     &type, &format, &nitems, &after, 
-                     (guchar **)&proxy_data);
-
-  if (!gdk_error_code)
+  if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win, 
+                         xdnd_proxy_atom, 0, 
+                         1, False, AnyPropertyType,
+                         &type, &format, &nitems, &after, 
+                         &data) == Success)
     {
       if (type != None)
        {
+         proxy_data = (Window *)data;
+         
          if ((format == 32) && (nitems == 1))
            {
              proxy = *proxy_data;
            }
          else
            GDK_NOTE (DND, 
-                     g_warning ("Invalid XdndOwner property on window %ld\n", win));
+                     g_warning ("Invalid XdndProxy "
+                                "property on window %ld\n", win));
          
          XFree (proxy_data);
        }
       
-      XGetWindowProperty (gdk_display, proxy ? proxy : win,
-                         xdnd_aware_atom, 0, 
-                         1, False, AnyPropertyType,
-                         &type, &format, &nitems, &after, 
-                         (guchar **)&version);
-      
-      if (!gdk_error_code && type != None)
+      if ((XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), proxy ? proxy : win,
+                              xdnd_aware_atom, 0, 
+                              1, False, AnyPropertyType,
+                              &type, &format, &nitems, &after, 
+                              &data) == Success) &&
+         type != None)
        {
+         version = (Atom *)data;
+         
          if ((format == 32) && (nitems == 1))
            {
-             if (*version == 3)
+             if (*version >= 3)
                retval = TRUE;
+             if (xdnd_version)
+               *xdnd_version = *version;
            }
          else
            GDK_NOTE (DND, 
-                     g_warning ("Invalid XdndAware property on window %ld\n", win));
+                     g_warning ("Invalid XdndAware "
+                                "property on window %ld\n", win));
          
          XFree (version);
        }
-      
     }
 
-  gdk_error_warnings = old_warnings;
-  gdk_error_code = 0;
+  gdk_error_trap_pop ();
   
-  return retval ? (proxy ? proxy : win) : GDK_NONE;
+  return retval ? (proxy ? proxy : win) : None;
 }
 
 /* Target side */
 
+static void
+xdnd_read_actions (GdkDragContext *context)
+{
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
+  Atom type;
+  int format;
+  gulong nitems, after;
+  guchar *data;
+  Atom *atoms;
+
+  gint i;
+  
+  PRIVATE_DATA (context)->xdnd_have_actions = FALSE;
+
+  if (gdk_window_get_window_type (context->source_window) == GDK_WINDOW_FOREIGN)
+    {
+      /* Get the XdndActionList, if set */
+      
+      gdk_error_trap_push ();
+      
+      if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
+                             GDK_DRAWABLE_XID (context->source_window),
+                             gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
+                             0, 65536,
+                             False, XA_ATOM, &type, &format, &nitems,
+                             &after, &data) == Success &&
+         type == XA_ATOM)
+       {
+         atoms = (Atom *)data;
+         
+         context->actions = 0;
+         
+         for (i=0; i<nitems; i++)
+           context->actions |= xdnd_action_from_atom (display, atoms[i]);
+         
+         PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
+         
+#ifdef G_ENABLE_DEBUG
+         if (_gdk_debug_flags & GDK_DEBUG_DND)
+           {
+             GString *action_str = g_string_new (NULL);
+             if (context->actions & GDK_ACTION_MOVE)
+               g_string_append(action_str, "MOVE ");
+             if (context->actions & GDK_ACTION_COPY)
+               g_string_append(action_str, "COPY ");
+             if (context->actions & GDK_ACTION_LINK)
+               g_string_append(action_str, "LINK ");
+             if (context->actions & GDK_ACTION_ASK)
+               g_string_append(action_str, "ASK ");
+             
+             g_message("Xdnd actions = %s", action_str->str);
+             g_string_free (action_str, TRUE);
+           }
+#endif /* G_ENABLE_DEBUG */
+         
+       }
+
+      if (data)
+       XFree (data);
+      
+      gdk_error_trap_pop ();
+    }
+  else
+    {
+      /* Local drag
+       */
+      GdkDragContext *source_context;
+
+      source_context = gdk_drag_context_find (display, TRUE,
+                                             GDK_DRAWABLE_XID (context->source_window),
+                                             GDK_DRAWABLE_XID (context->dest_window));
+
+      if (source_context)
+       {
+         context->actions = source_context->actions;
+         PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
+       }
+    }
+}
+
+/* We have to make sure that the XdndActionList we keep internally
+ * is up to date with the XdndActionList on the source window
+ * because we get no notification, because Xdnd wasn't meant
+ * to continually send actions. So we select on PropertyChangeMask
+ * and add this filter.
+ */
+static GdkFilterReturn 
+xdnd_source_window_filter (GdkXEvent *xev,
+                          GdkEvent  *event,
+                          gpointer   cb_data)
+{
+  XEvent *xevent = (XEvent *)xev;
+  GdkDragContext *context = cb_data;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY(event->any.window);
+
+  if ((xevent->xany.type == PropertyNotify) &&
+      (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList")))
+    {
+      xdnd_read_actions (context);
+
+      return GDK_FILTER_REMOVE;
+    }
+
+  return GDK_FILTER_CONTINUE;
+}
+
+static void
+xdnd_manage_source_filter (GdkDragContext *context,
+                          GdkWindow      *window,
+                          gboolean        add_filter)
+{
+  if (!GDK_WINDOW_DESTROYED (window) &&
+      gdk_window_get_window_type (window) == GDK_WINDOW_FOREIGN)
+    {
+      gdk_error_trap_push ();
+
+      if (add_filter)
+       {
+         gdk_window_set_events (window,
+                                gdk_window_get_events (window) |
+                                GDK_PROPERTY_CHANGE_MASK);
+         gdk_window_add_filter (window, xdnd_source_window_filter, context);
+       }
+      else
+       {
+         gdk_window_remove_filter (window,
+                                   xdnd_source_window_filter,
+                                   context);
+         /* Should we remove the GDK_PROPERTY_NOTIFY mask?
+          * but we might want it for other reasons. (Like
+          * INCR selection transactions).
+          */
+       }
+      
+      gdk_display_sync (gdk_drawable_get_display (window));
+      gdk_error_trap_pop ();  
+    }
+}
+
+static void
+base_precache_atoms (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (!display_x11->base_dnd_atoms_precached)
+    {
+      static const char *const precache_atoms[] = {
+       "ENLIGHTENMENT_DESKTOP",
+       "WM_STATE",
+       "XdndAware",
+       "XdndProxy",
+       "_MOTIF_DRAG_RECEIVER_INFO"
+      };
+
+      _gdk_x11_precache_atoms (display,
+                              precache_atoms, G_N_ELEMENTS (precache_atoms));
+
+      display_x11->base_dnd_atoms_precached = TRUE;
+    }
+}
+
+static void
+xdnd_precache_atoms (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (!display_x11->xdnd_atoms_precached)
+    {
+      static const char *const precache_atoms[] = {
+       "XdndActionAsk",
+       "XdndActionCopy",
+       "XdndActionLink",
+       "XdndActionList",
+       "XdndActionMove",
+       "XdndActionPrivate",
+       "XdndDrop",
+       "XdndEnter",
+       "XdndFinished",
+       "XdndLeave",
+       "XdndPosition",
+       "XdndSelection",
+       "XdndStatus",
+       "XdndTypeList"
+      };
+
+      _gdk_x11_precache_atoms (display,
+                              precache_atoms, G_N_ELEMENTS (precache_atoms));
+
+      display_x11->xdnd_atoms_precached = TRUE;
+    }
+}
+
 static GdkFilterReturn 
 xdnd_enter_filter (GdkXEvent *xev,
                   GdkEvent  *event,
                   gpointer   cb_data)
 {
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
   XEvent *xevent = (XEvent *)xev;
   GdkDragContext *new_context;
   gint i;
@@ -2268,127 +2664,116 @@ xdnd_enter_filter (GdkXEvent *xev,
   Atom type;
   int format;
   gulong nitems, after;
-  Atom *data;
+  guchar *data;
+  Atom *atoms;
 
-  guint32 source_window = xevent->xclient.data.l[0];
-  gboolean get_types = ((xevent->xclient.data.l[1] & 1) != 0);
-  gint version = (xevent->xclient.data.l[1] & 0xff000000) >> 24;
+  guint32 source_window;
+  gboolean get_types;
+  gint version;
+
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;                        /* Not for us */
+
+  source_window = xevent->xclient.data.l[0];
+  get_types = ((xevent->xclient.data.l[1] & 1) != 0);
+  version = (xevent->xclient.data.l[1] & 0xff000000) >> 24;
   
+  display = GDK_DRAWABLE_DISPLAY (event->any.window);
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  xdnd_precache_atoms (display);
+
   GDK_NOTE (DND, 
            g_message ("XdndEnter: source_window: %#x, version: %#x",
                       source_window, version));
 
-  if (version != 3)
+  if (version < 3)
     {
       /* Old source ignore */
       GDK_NOTE (DND, g_message ("Ignored old XdndEnter message"));
       return GDK_FILTER_REMOVE;
     }
   
-  if (current_dest_drag != NULL)
+  if (display_x11->current_dest_drag != NULL)
     {
-      gdk_drag_context_unref (current_dest_drag);
-      current_dest_drag = NULL;
+      g_object_unref (display_x11->current_dest_drag);
+      display_x11->current_dest_drag = NULL;
     }
 
   new_context = gdk_drag_context_new ();
   new_context->protocol = GDK_DRAG_PROTO_XDND;
-  new_context->is_source = FALSE;
+  PRIVATE_DATA(new_context)->version = version;
 
-  new_context->source_window = gdk_window_lookup (source_window);
+  new_context->source_window = gdk_window_lookup_for_display (display, source_window);
   if (new_context->source_window)
-    gdk_window_ref (new_context->source_window);
+    g_object_ref (new_context->source_window);
   else
     {
-      new_context->source_window = gdk_window_foreign_new (source_window);
+      new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
       if (!new_context->source_window)
        {
-         gdk_drag_context_unref (new_context);
+         g_object_unref (new_context);
          return GDK_FILTER_REMOVE;
        }
     }
   new_context->dest_window = event->any.window;
-  gdk_window_ref (new_context->dest_window);
+  g_object_ref (new_context->dest_window);
 
   new_context->targets = NULL;
   if (get_types)
     {
-      XGetWindowProperty (GDK_WINDOW_XDISPLAY (event->any.window), 
+      gdk_error_trap_push ();
+      XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (event->any.window), 
                          source_window, 
-                         gdk_atom_intern ("XdndTypeList", FALSE), 0, 65536,
+                         gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
+                         0, 65536,
                          False, XA_ATOM, &type, &format, &nitems,
-                         &after, (guchar **)&data);
+                         &after, &data);
 
-      if ((format != 32) || (type != XA_ATOM))
+      if (gdk_error_trap_pop () || (format != 32) || (type != XA_ATOM))
        {
-         gdk_drag_context_unref (new_context);
+         g_object_unref (new_context);
+
+         if (data)
+           XFree (data);
+
          return GDK_FILTER_REMOVE;
        }
 
+      atoms = (Atom *)data;
+
       for (i=0; i<nitems; i++)
-       new_context->targets = g_list_append (new_context->targets,
-                                             GUINT_TO_POINTER (data[i]));
+       new_context->targets = 
+         g_list_append (new_context->targets,
+                        GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display,
+                                                                                atoms[i])));
 
-      XFree(data);
+      XFree(atoms);
     }
   else
     {
       for (i=0; i<3; i++)
        if (xevent->xclient.data.l[2+i])
-         new_context->targets = g_list_append (new_context->targets,
-                                               GUINT_TO_POINTER (xevent->xclient.data.l[2+i]));
+         new_context->targets =
+           g_list_append (new_context->targets,
+                          GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display, 
+                                                                                  xevent->xclient.data.l[2+i])));
     }
 
-  /* Get the XdndActionList, if set */
-
-  XGetWindowProperty (GDK_WINDOW_XDISPLAY (event->any.window), 
-                     source_window, 
-                     gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
-                     False, XA_ATOM, &type, &format, &nitems,
-                     &after, (guchar **)&data);
-  
-  if ((format == 32) && (type == XA_ATOM))
-    {
-      new_context->actions = 0;
-
-      for (i=0; i<nitems; i++)
-       new_context->actions |= xdnd_action_from_atom (data[i]);
-
-      ((GdkDragContextPrivate *)new_context)->xdnd_have_actions = TRUE;
-
 #ifdef G_ENABLE_DEBUG
-      if (gdk_debug_flags & GDK_DEBUG_DND)
-       {
-         GString *action_str = g_string_new (NULL);
-         if (new_context->actions & GDK_ACTION_MOVE)
-           g_string_append(action_str, "MOVE ");
-         if (new_context->actions & GDK_ACTION_COPY)
-           g_string_append(action_str, "COPY ");
-         if (new_context->actions & GDK_ACTION_LINK)
-           g_string_append(action_str, "LINK ");
-         if (new_context->actions & GDK_ACTION_ASK)
-           g_string_append(action_str, "ASK ");
-         
-         g_message("\tactions = %s", action_str->str);
-         g_string_free (action_str, TRUE);
-       }
-#endif /* G_ENABLE_DEBUG */
-
-      XFree(data);
-    }
-  
-#ifdef G_ENABLE_DEBUG
-  if (gdk_debug_flags & GDK_DEBUG_DND)
+  if (_gdk_debug_flags & GDK_DEBUG_DND)
     print_target_list (new_context->targets);
 #endif /* G_ENABLE_DEBUG */
 
+  xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
+  xdnd_read_actions (new_context);
+
   event->dnd.type = GDK_DRAG_ENTER;
   event->dnd.context = new_context;
-  gdk_drag_context_ref (new_context);
+  g_object_ref (new_context);
 
-  current_dest_drag = new_context;
-  ((GdkDragContextPrivate *)new_context)->xdnd_selection = 
-    gdk_atom_intern ("XdndSelection", FALSE);
+  display_x11->current_dest_drag = new_context;
 
   return GDK_FILTER_TRANSLATE;
 }
@@ -2400,20 +2785,31 @@ xdnd_leave_filter (GdkXEvent *xev,
 {
   XEvent *xevent = (XEvent *)xev;
   guint32 source_window = xevent->xclient.data.l[0];
-  
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
+
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;                        /* Not for us */
   GDK_NOTE (DND, 
            g_message ("XdndLeave: source_window: %#x",
                       source_window));
 
-  if ((current_dest_drag != NULL) &&
-      (current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
-      (GDK_WINDOW_XWINDOW (current_dest_drag->source_window) == source_window))
+  display = GDK_DRAWABLE_DISPLAY (event->any.window);
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  xdnd_precache_atoms (display);
+
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
+      (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
     {
       event->dnd.type = GDK_DRAG_LEAVE;
       /* Pass ownership of context to the event */
-      event->dnd.context = current_dest_drag;
+      event->dnd.context = display_x11->current_dest_drag;
 
-      current_dest_drag = NULL;
+      display_x11->current_dest_drag = NULL;
 
       return GDK_FILTER_TRANSLATE;
     }
@@ -2431,32 +2827,44 @@ xdnd_position_filter (GdkXEvent *xev,
   gint16 x_root = xevent->xclient.data.l[2] >> 16;
   gint16 y_root = xevent->xclient.data.l[2] & 0xffff;
   guint32 time = xevent->xclient.data.l[3];
-  GdkAtom action = xevent->xclient.data.l[4];
-  
+  Atom action = xevent->xclient.data.l[4];
+
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
+
+   if (!event->any.window ||
+       gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+     return GDK_FILTER_CONTINUE;                       /* Not for us */
+   
   GDK_NOTE (DND, 
-           g_message ("XdndPosition: source_window: %#x  position: (%d, %d)  time: %d  action: %ld",
+           g_message ("XdndPosition: source_window: %#x position: (%d, %d)  time: %d  action: %ld",
                       source_window, x_root, y_root, time, action));
 
+  display = GDK_DRAWABLE_DISPLAY (event->any.window);
+  display_x11 = GDK_DISPLAY_X11 (display);
   
-  if ((current_dest_drag != NULL) &&
-      (current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
-      (GDK_WINDOW_XWINDOW (current_dest_drag->source_window) == source_window))
+  xdnd_precache_atoms (display);
+
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
+      (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
     {
       event->dnd.type = GDK_DRAG_MOTION;
-      event->dnd.context = current_dest_drag;
-      gdk_drag_context_ref (current_dest_drag);
+      event->dnd.context = display_x11->current_dest_drag;
+      g_object_ref (display_x11->current_dest_drag);
 
       event->dnd.time = time;
 
-      current_dest_drag->suggested_action = xdnd_action_from_atom (action);
-      if (!((GdkDragContextPrivate *)current_dest_drag)->xdnd_have_actions)
-       current_dest_drag->actions = current_dest_drag->suggested_action;
+      display_x11->current_dest_drag->suggested_action = xdnd_action_from_atom (display, action);
+      
+      if (!(PRIVATE_DATA (display_x11->current_dest_drag))->xdnd_have_actions)
+       display_x11->current_dest_drag->actions = display_x11->current_dest_drag->suggested_action;
 
       event->dnd.x_root = x_root;
       event->dnd.y_root = y_root;
 
-      ((GdkDragContextPrivate *)current_dest_drag)->last_x = x_root;
-      ((GdkDragContextPrivate *)current_dest_drag)->last_y = y_root;
+      (PRIVATE_DATA (display_x11->current_dest_drag))->last_x = x_root;
+      (PRIVATE_DATA (display_x11->current_dest_drag))->last_y = y_root;
       
       return GDK_FILTER_TRANSLATE;
     }
@@ -2472,26 +2880,39 @@ xdnd_drop_filter (GdkXEvent *xev,
   XEvent *xevent = (XEvent *)xev;
   guint32 source_window = xevent->xclient.data.l[0];
   guint32 time = xevent->xclient.data.l[2];
+  GdkDisplay *display;
+  GdkDisplayX11 *display_x11;
+  
+  if (!event->any.window ||
+      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
+    return GDK_FILTER_CONTINUE;                        /* Not for us */
   
   GDK_NOTE (DND, 
            g_message ("XdndDrop: source_window: %#x  time: %d",
                       source_window, time));
 
-  if ((current_dest_drag != NULL) &&
-      (current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
-      (GDK_WINDOW_XWINDOW (current_dest_drag->source_window) == source_window))
+  display = GDK_DRAWABLE_DISPLAY (event->any.window);
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  xdnd_precache_atoms (display);
+
+  if ((display_x11->current_dest_drag != NULL) &&
+      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
+      (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
     {
-      GdkDragContextPrivate *private;
-      private = (GdkDragContextPrivate *)current_dest_drag;
+      GdkDragContextPrivateX11 *private;
+      private = PRIVATE_DATA (display_x11->current_dest_drag);
 
       event->dnd.type = GDK_DROP_START;
 
-      event->dnd.context = current_dest_drag;
-      gdk_drag_context_ref (current_dest_drag);
+      event->dnd.context = display_x11->current_dest_drag;
+      g_object_ref (display_x11->current_dest_drag);
 
       event->dnd.time = time;
       event->dnd.x_root = private->last_x;
       event->dnd.y_root = private->last_y;
+
+      gdk_x11_window_set_user_time (event->any.window, time);
       
       return GDK_FILTER_TRANSLATE;
     }
@@ -2502,33 +2923,24 @@ xdnd_drop_filter (GdkXEvent *xev,
 /*************************************************************
  ************************** Public API ***********************
  *************************************************************/
-
 void
-gdk_dnd_init (void)
+_gdk_dnd_init (GdkDisplay *display)
 {
-  init_byte_order();
+  int i;
+  init_byte_order ();
 
-  gdk_add_client_message_filter (
-       gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE),
+  gdk_display_add_client_message_filter (
+       display,
+       gdk_atom_intern_static_string ("_MOTIF_DRAG_AND_DROP_MESSAGE"),
        motif_dnd_filter, NULL);
-  gdk_add_client_message_filter (
-       gdk_atom_intern ("XdndEnter", FALSE),
-       xdnd_enter_filter, NULL);
-  gdk_add_client_message_filter (
-       gdk_atom_intern ("XdndLeave", FALSE),
-       xdnd_leave_filter, NULL);
-  gdk_add_client_message_filter (
-       gdk_atom_intern ("XdndPosition", FALSE),
-       xdnd_position_filter, NULL);
-  gdk_add_client_message_filter (
-       gdk_atom_intern ("XdndStatus", FALSE),
-       xdnd_status_filter, NULL);
-  gdk_add_client_message_filter (
-       gdk_atom_intern ("XdndFinished", FALSE),
-       xdnd_finished_filter, NULL);
-  gdk_add_client_message_filter (
-       gdk_atom_intern ("XdndDrop", FALSE),
-       xdnd_drop_filter, NULL);
+  
+  for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
+    {
+      gdk_display_add_client_message_filter (
+       display,
+       gdk_atom_intern_static_string (xdnd_filters[i].atom_name),
+       xdnd_filters[i].func, NULL);
+    }
 }                    
 
 /* Source side */
@@ -2548,20 +2960,30 @@ gdk_drag_do_leave (GdkDragContext *context, guint32 time)
          break;
        case GDK_DRAG_PROTO_ROOTWIN:
        case GDK_DRAG_PROTO_NONE:
+       default:
          break;
        }
 
-      gdk_window_unref (context->dest_window);
+      g_object_unref (context->dest_window);
       context->dest_window = NULL;
     }
 }
 
+/**
+ * gdk_drag_begin:
+ * @window: the source window for this drag.
+ * @targets: the list of offered targets.
+ * 
+ * Starts a drag and creates a new drag context for it.
+ *
+ * This function is called by the drag source.
+ * 
+ * Return value: a newly created #GdkDragContext.
+ **/
 GdkDragContext * 
 gdk_drag_begin (GdkWindow     *window,
-               GList         *targets,
-               GdkDragAction  actions)
+               GList         *targets)
 {
-  GList *tmp_list;
   GdkDragContext *new_context;
   
   g_return_val_if_fail (window != NULL, NULL);
@@ -2569,35 +2991,58 @@ gdk_drag_begin (GdkWindow     *window,
   new_context = gdk_drag_context_new ();
   new_context->is_source = TRUE;
   new_context->source_window = window;
-  gdk_window_ref (window);
+  g_object_ref (window);
 
-  tmp_list = g_list_last (targets);
-  new_context->targets = NULL;
-  while (tmp_list)
-    {
-      new_context->targets = g_list_prepend (new_context->targets,
-                                            tmp_list->data);
-      tmp_list = tmp_list->prev;
-    }
-
-  new_context->actions = actions;
+  new_context->targets = g_list_copy (targets);
+  precache_target_list (new_context);
+  
+  new_context->actions = 0;
 
   return new_context;
 }
 
-guint32
-gdk_drag_get_protocol (guint32          xid,
-                      GdkDragProtocol *protocol)
+static guint32
+_gdk_drag_get_protocol_for_display (GdkDisplay      *display,
+                                   guint32          xid,
+                                   GdkDragProtocol *protocol,
+                                   guint           *version)
+
 {
+  GdkWindow *window;
   guint32 retval;
-  
-  if ((retval = xdnd_check_dest (xid)))
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
+
+  base_precache_atoms (display);
+
+  /* Check for a local drag
+   */
+  window = gdk_window_lookup_for_display (display, xid);
+  if (window &&
+      gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
+    {
+      if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
+       {
+         *protocol = GDK_DRAG_PROTO_XDND;
+         *version = 5;
+         xdnd_precache_atoms (display);
+         GDK_NOTE (DND, g_message ("Entering local Xdnd window %#x\n", xid));
+         return xid;
+       }
+      else if (_gdk_x11_display_is_root_window (display, (Window) xid))
+       {
+         *protocol = GDK_DRAG_PROTO_ROOTWIN;
+         GDK_NOTE (DND, g_message ("Entering root window\n"));
+         return xid;
+       }
+    }
+  else if ((retval = xdnd_check_dest (display, xid, version)))
     {
       *protocol = GDK_DRAG_PROTO_XDND;
-      GDK_NOTE (DND, g_message ("Entering dnd window %#x\n", xid));
+      xdnd_precache_atoms (display);
+      GDK_NOTE (DND, g_message ("Entering Xdnd window %#x\n", xid));
       return retval;
     }
-  else if ((retval = motif_check_dest (xid)))
+  else if ((retval = motif_check_dest (display, xid)))
     {
       *protocol = GDK_DRAG_PROTO_MOTIF;
       GDK_NOTE (DND, g_message ("Entering motif window %#x\n", xid));
@@ -2608,24 +3053,23 @@ gdk_drag_get_protocol (guint32          xid,
       /* Check if this is a root window */
 
       gboolean rootwin = FALSE;
-      gint old_warnings = gdk_error_warnings;
       Atom type = None;
       int format;
       unsigned long nitems, after;
       unsigned char *data;
 
-      if (xid == gdk_root_window)
+      if (_gdk_x11_display_is_root_window (display, (Window) xid))
        rootwin = TRUE;
 
+      gdk_error_trap_push ();
+      
       if (!rootwin)
        {
-         gdk_error_code = 0;
-         
-         XGetWindowProperty (gdk_display, xid,
-                             gdk_atom_intern ("ENLIGHTENMENT_DESKTOP", FALSE),
-                             0, 0, False, AnyPropertyType,
-                             &type, &format, &nitems, &after, &data);
-         if ((gdk_error_code == 0) && type != None)
+         if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid,
+                                 gdk_x11_get_xatom_by_name_for_display (display, "ENLIGHTENMENT_DESKTOP"),
+                                 0, 0, False, AnyPropertyType,
+                                 &type, &format, &nitems, &after, &data) == Success &&
+             type != None)
            {
              XFree (data);
              rootwin = TRUE;
@@ -2639,49 +3083,116 @@ gdk_drag_get_protocol (guint32          xid,
 #if 0
       if (!rootwin)
        {
-         gdk_error_code = 0;
-         
-         XGetWindowProperty (gdk_display, win,
-                             gdk_atom_intern ("__SWM_VROOT", FALSE),
-                             0, 0, False, AnyPropertyType,
-                             &type, &format, &nitems, &data);
-         if ((gdk_error_code == 0) && type != None)
-           rootwin = TRUE;
+         if (XGetWindowProperty (gdk_display, win,
+                                 gdk_x11_get_xatom_by_name ("__SWM_VROOT"),
+                                 0, 0, False, AnyPropertyType,
+                                 &type, &format, &nitems, &data) &&
+             type != None)
+           {
+             XFree (data);
+             rootwin = TRUE;
+           }
        }
 #endif      
 
-      gdk_error_warnings = old_warnings;
+      gdk_error_trap_pop ();
 
       if (rootwin)
        {
+         GDK_NOTE (DND, g_message ("Entering root window\n"));
          *protocol = GDK_DRAG_PROTO_ROOTWIN;
          return xid;
        }
     }
 
   *protocol = GDK_DRAG_PROTO_NONE;
-  return GDK_NONE;
+  return None;
+}
+
+/**
+ * gdk_drag_get_protocol_for_display:
+ * @display: the #GdkDisplay where the destination window resides
+ * @xid: the X id of the destination window.
+ * @protocol: location where the supported DND protocol is returned.
+ * @returns: the X id of the window where the drop should happen. This 
+ *     may be @xid or the X id of a proxy window, or None if @xid doesn't
+ *     support Drag and Drop.
+ *
+ * Finds out the DND protocol supported by a window.
+ *
+ * Since: 2.2
+ */ 
+guint32
+gdk_drag_get_protocol_for_display (GdkDisplay      *display,
+                                  guint32          xid,
+                                  GdkDragProtocol *protocol)
+{
+  return _gdk_drag_get_protocol_for_display (display, xid, protocol, NULL);
 }
 
+static GdkWindowCache *
+drag_context_find_window_cache (GdkDragContext  *context,
+                               GdkScreen       *screen)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GSList *tmp_list;
+  GdkWindowCache *cache;
+
+  for (tmp_list = private->window_caches; tmp_list; tmp_list = tmp_list->next)
+    {
+      cache = tmp_list->data;
+      if (cache->screen == screen)
+       return cache;
+    }
+
+  cache = gdk_window_cache_new (screen);
+  private->window_caches = g_slist_prepend (private->window_caches, cache);
+  
+  return cache;
+}
+
+/**
+ * gdk_drag_find_window_for_screen:
+ * @context: a #GdkDragContext
+ * @drag_window: a window which may be at the pointer position, but
+ * should be ignored, since it is put up by the drag source as an icon.
+ * @screen: the screen where the destination window is sought. 
+ * @x_root: the x position of the pointer in root coordinates.
+ * @y_root: the y position of the pointer in root coordinates.
+ * @dest_window: location to store the destination window in.
+ * @protocol: location to store the DND protocol in.
+ * 
+ * Finds the destination window and DND protocol to use at the
+ * given pointer position. 
+ *
+ * This function is called by the drag source to obtain the 
+ * @dest_window and @protocol parameters for gdk_drag_motion().
+ *
+ * Since: 2.2
+ **/
 void
-gdk_drag_find_window (GdkDragContext  *context,
-                     GdkWindow       *drag_window,
-                     gint             x_root,
-                     gint             y_root,
-                     GdkWindow      **dest_window,
-                     GdkDragProtocol *protocol)
-{
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+gdk_drag_find_window_for_screen (GdkDragContext  *context,
+                                GdkWindow       *drag_window,
+                                GdkScreen       *screen,
+                                gint             x_root,
+                                gint             y_root,
+                                GdkWindow      **dest_window,
+                                GdkDragProtocol *protocol)
+{
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
+  GdkWindowCache *window_cache;
+  GdkDisplay *display;
   Window dest;
 
   g_return_if_fail (context != NULL);
 
-  if (!private->window_cache)
-    private->window_cache = gdk_window_cache_new();
+  display = GDK_WINDOW_DISPLAY (context->source_window);
 
-  dest = get_client_window_at_coords (private->window_cache,
+  window_cache = drag_context_find_window_cache (context, screen);
+
+  dest = get_client_window_at_coords (window_cache,
                                      drag_window ? 
-                                     GDK_WINDOW_XWINDOW (drag_window) : GDK_NONE,
+                                     GDK_DRAWABLE_XID (drag_window) : None,
                                      x_root, y_root);
 
   if (private->dest_xid != dest)
@@ -2691,13 +3202,20 @@ gdk_drag_find_window (GdkDragContext  *context,
 
       /* Check if new destination accepts drags, and which protocol */
 
-      if ((recipient = gdk_drag_get_protocol (dest, protocol)))
+      /* There is some ugliness here. We actually need to pass
+       * _three_ pieces of information to drag_motion - dest_window,
+       * protocol, and the XID of the unproxied window. The first
+       * two are passed explicitely, the third implicitly through
+       * protocol->dest_xid.
+       */
+      if ((recipient = _gdk_drag_get_protocol_for_display (display, dest, 
+                                                          protocol, &private->version)))
        {
-         *dest_window = gdk_window_lookup (recipient);
+         *dest_window = gdk_window_lookup_for_display (display, recipient);
          if (*dest_window)
-           gdk_window_ref (*dest_window);
+           g_object_ref (*dest_window);
          else
-           *dest_window = gdk_window_foreign_new (recipient);
+           *dest_window = gdk_window_foreign_new_for_display (display, recipient);
        }
       else
        *dest_window = NULL;
@@ -2706,24 +3224,97 @@ gdk_drag_find_window (GdkDragContext  *context,
     {
       *dest_window = context->dest_window;
       if (*dest_window)
-       gdk_window_ref (*dest_window);
+       g_object_ref (*dest_window);
       *protocol = context->protocol;
     }
 }
 
+/**
+ * gdk_drag_motion:
+ * @context: a #GdkDragContext.
+ * @dest_window: the new destination window, obtained by 
+ *     gdk_drag_find_window().
+ * @protocol: the DND protocol in use, obtained by gdk_drag_find_window().
+ * @x_root: the x position of the pointer in root coordinates.
+ * @y_root: the y position of the pointer in root coordinates.
+ * @suggested_action: the suggested action.
+ * @possible_actions: the possible actions.
+ * @time_: the timestamp for this operation.
+ * 
+ * Updates the drag context when the pointer moves or the 
+ * set of actions changes.
+ *
+ * This function is called by the drag source.
+ * 
+ * Return value: FIXME
+ **/
 gboolean        
 gdk_drag_motion (GdkDragContext *context,
                 GdkWindow      *dest_window,
                 GdkDragProtocol protocol,
                 gint            x_root, 
                 gint            y_root,
-                GdkDragAction   action,
+                GdkDragAction   suggested_action,
+                GdkDragAction   possible_actions,
                 guint32         time)
 {
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
 
   g_return_val_if_fail (context != NULL, FALSE);
 
+  private->old_actions = context->actions;
+  context->actions = possible_actions;
+  
+  if (private->old_actions != possible_actions)
+    private->xdnd_actions_set = FALSE;
+  
+  if (protocol == GDK_DRAG_PROTO_XDND && private->version == 0)
+    {
+      /* This ugly hack is necessary since GTK+ doesn't know about
+       * the XDND protocol version, and in particular doesn't know 
+       * that gdk_drag_find_window_for_screen() has the side-effect 
+       * of setting private->version, and therefore sometimes call
+       * gdk_drag_motion() without a prior call to 
+       * gdk_drag_find_window_for_screen(). This happens, e.g.
+       * when GTK+ is proxying DND events to embedded windows.
+       */ 
+      if (dest_window)
+       {
+         GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
+         
+         xdnd_check_dest (display, 
+                          GDK_DRAWABLE_XID (dest_window), 
+                          &private->version);
+       }
+    }
+
+  /* When we have a Xdnd target, make sure our XdndActionList
+   * matches the current actions;
+   */
+  if (protocol == GDK_DRAG_PROTO_XDND && !private->xdnd_actions_set)
+    {
+      if (dest_window)
+       {
+         if (gdk_window_get_window_type (dest_window) == GDK_WINDOW_FOREIGN)
+           xdnd_set_actions (context);
+         else if (context->dest_window == dest_window)
+           {
+             GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
+             GdkDragContext *dest_context;
+                   
+             dest_context = gdk_drag_context_find (display, FALSE,
+                                                   GDK_DRAWABLE_XID (context->source_window),
+                                                   GDK_DRAWABLE_XID (dest_window));
+
+             if (dest_context)
+               {
+                 dest_context->actions = context->actions;
+                 PRIVATE_DATA (dest_context)->xdnd_have_actions = TRUE;
+               }
+           }
+       }
+    }
+
   if (context->dest_window != dest_window)
     {
       GdkEvent temp_event;
@@ -2737,7 +3328,8 @@ gdk_drag_motion (GdkDragContext *context,
       if (dest_window)
        {
          context->dest_window = dest_window;
-         gdk_window_ref (context->dest_window);
+         private->drop_xid = private->dest_xid;
+         g_object_ref (context->dest_window);
          context->protocol = protocol;
 
          switch (protocol)
@@ -2752,14 +3344,17 @@ gdk_drag_motion (GdkDragContext *context,
 
            case GDK_DRAG_PROTO_ROOTWIN:
            case GDK_DRAG_PROTO_NONE:
+           default:
              break;
            }
-         private->old_action = action;
-         context->suggested_action = action;
+         private->old_action = suggested_action;
+         context->suggested_action = suggested_action;
+         private->old_actions = possible_actions;
        }
       else
        {
          context->dest_window = NULL;
+         private->drop_xid = None;
          context->action = 0;
        }
 
@@ -2782,7 +3377,7 @@ gdk_drag_motion (GdkDragContext *context,
   else
     {
       private->old_action = context->suggested_action;
-      context->suggested_action = action;
+      context->suggested_action = suggested_action;
     }
 
   /* Send a drag-motion event */
@@ -2797,19 +3392,26 @@ gdk_drag_motion (GdkDragContext *context,
          switch (context->protocol)
            {
            case GDK_DRAG_PROTO_MOTIF:
-             motif_send_motion (context, x_root, y_root, action, time);
+             motif_send_motion (context, x_root, y_root, suggested_action, time);
              break;
              
            case GDK_DRAG_PROTO_XDND:
-             xdnd_send_motion (context, x_root, y_root, action, time);
+             xdnd_send_motion (context, x_root, y_root, suggested_action, time);
              break;
 
            case GDK_DRAG_PROTO_ROOTWIN:
              {
                GdkEvent temp_event;
+               /* GTK+ traditionally has used application/x-rootwin-drop,
+                * but the XDND spec specifies x-rootwindow-drop.
+                */
+               GdkAtom target1 = gdk_atom_intern_static_string ("application/x-rootwindow-drop");
+               GdkAtom target2 = gdk_atom_intern_static_string ("application/x-rootwin-drop");
 
                if (g_list_find (context->targets,
-                                GUINT_TO_POINTER (gdk_atom_intern ("application/x-rootwin-drop", FALSE))))
+                                GDK_ATOM_TO_POINTER (target1)) ||
+                   g_list_find (context->targets,
+                                GDK_ATOM_TO_POINTER (target2)))
                  context->action = context->suggested_action;
                else
                  context->action = 0;
@@ -2826,6 +3428,8 @@ gdk_drag_motion (GdkDragContext *context,
            case GDK_DRAG_PROTO_NONE:
              g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
              break;
+           default:
+             break;
            }
        }
       else
@@ -2835,6 +3439,15 @@ gdk_drag_motion (GdkDragContext *context,
   return FALSE;
 }
 
+/**
+ * gdk_drag_drop:
+ * @context: a #GdkDragContext.
+ * @time_: the timestamp for this operation.
+ * 
+ * Drops on the current destination.
+ * 
+ * This function is called by the drag source.
+ **/
 void
 gdk_drag_drop (GdkDragContext *context,
               guint32         time)
@@ -2860,10 +3473,21 @@ gdk_drag_drop (GdkDragContext *context,
        case GDK_DRAG_PROTO_NONE:
          g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
          break;
+       default:
+         break;
        }
     }
 }
 
+/**
+ * gdk_drag_abort:
+ * @context: a #GdkDragContext.
+ * @time_: the timestamp for this operation.
+ * 
+ * Aborts a drag without dropping. 
+ *
+ * This function is called by the drag source.
+ **/
 void
 gdk_drag_abort (GdkDragContext *context,
                guint32         time)
@@ -2875,26 +3499,43 @@ gdk_drag_abort (GdkDragContext *context,
 
 /* Destination side */
 
+/**
+ * gdk_drag_status:
+ * @context: a #GdkDragContext.
+ * @action: the selected action which will be taken when a drop happens, 
+ *    or 0 to indicate that a drop will not be accepted.
+ * @time_: the timestamp for this operation.
+ * 
+ * Selects one of the actions offered by the drag source.
+ *
+ * This function is called by the drag destination in response to
+ * gdk_drag_motion() called by the drag source.
+ **/
 void             
 gdk_drag_status (GdkDragContext   *context,
                 GdkDragAction     action,
                 guint32           time)
 {
-  GdkDragContextPrivate *private;
+  GdkDragContextPrivateX11 *private;
   XEvent xev;
+  GdkDisplay *display;
 
   g_return_if_fail (context != NULL);
 
-  private = (GdkDragContextPrivate *)context;
-
-  context->action = action;
+  private = PRIVATE_DATA (context);
+  display = GDK_DRAWABLE_DISPLAY (context->source_window);
   
+  context->action = action;
+
   if (context->protocol == GDK_DRAG_PROTO_MOTIF)
     {
+      gboolean need_coords = FALSE;
+      
       xev.xclient.type = ClientMessage;
-      xev.xclient.message_type = gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE);
+      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
+                                                                       "_MOTIF_DRAG_AND_DROP_MESSAGE");
       xev.xclient.format = 8;
-      xev.xclient.window = GDK_WINDOW_XWINDOW (context->source_window);
+      xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
 
       if (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT)
        {
@@ -2905,12 +3546,18 @@ gdk_drag_status (GdkDragContext   *context,
          if ((action != 0) != (private->old_action != 0))
            {
              if (action != 0)
-               MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_ENTER | 0x80;
+               {
+                 MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_ENTER | 0x80;
+                 need_coords = TRUE;
+               }
              else
                MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_LEAVE | 0x80;
            }
          else
-           MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION | 0x80;
+           {
+             MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION | 0x80;
+             need_coords = TRUE;
+           }
        }
 
       MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
@@ -2937,55 +3584,78 @@ gdk_drag_status (GdkDragContext   *context,
        MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmNO_DROP_SITE << 4);
 
       MOTIF_XCLIENT_LONG (&xev, 1) = time;
-      MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
-      MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
+      
+      if (need_coords)
+       {
+         MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
+         MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
+       }
+      else
+       MOTIF_XCLIENT_LONG (&xev, 2) = 0;
+      
+      MOTIF_XCLIENT_LONG (&xev, 3) = 0;
+      MOTIF_XCLIENT_LONG (&xev, 4) = 0;
 
-      if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->source_window),
-                      FALSE, 0, &xev))
+      if (!_gdk_send_xevent (display,
+                            GDK_DRAWABLE_XID (context->source_window),
+                            FALSE, 0, &xev))
        GDK_NOTE (DND, 
                  g_message ("Send event to %lx failed",
-                            GDK_WINDOW_XWINDOW (context->source_window)));
+                            GDK_DRAWABLE_XID (context->source_window)));
     }
   else if (context->protocol == GDK_DRAG_PROTO_XDND)
     {
       xev.xclient.type = ClientMessage;
-      xev.xclient.message_type = gdk_atom_intern ("XdndStatus", FALSE);
+      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndStatus");
       xev.xclient.format = 32;
-      xev.xclient.window = GDK_WINDOW_XWINDOW (context->source_window);
+      xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
 
-      xev.xclient.data.l[0] = GDK_WINDOW_XWINDOW (context->dest_window);
+      xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
       xev.xclient.data.l[1] = (action != 0) ? (2 | 1) : 0;
       xev.xclient.data.l[2] = 0;
       xev.xclient.data.l[3] = 0;
-      xev.xclient.data.l[4] = xdnd_action_to_atom (action);
-
-      if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->source_window),
-                      FALSE, 0, &xev))
+      xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
+      
+      if (!xdnd_send_xevent (context, context->source_window,
+                            FALSE, &xev))
        GDK_NOTE (DND, 
                  g_message ("Send event to %lx failed",
-                            GDK_WINDOW_XWINDOW (context->source_window)));
+                            GDK_DRAWABLE_XID (context->source_window)));
     }
 
   private->old_action = action;
 }
 
+/**
+ * gdk_drop_reply:
+ * @context: a #GdkDragContext.
+ * @ok: %TRUE if the drop is accepted.
+ * @time_: the timestamp for this operation.
+ * 
+ * Accepts or rejects a drop. 
+ *
+ * This function is called by the drag destination in response
+ * to a drop initiated by the drag source.
+ **/
 void 
 gdk_drop_reply (GdkDragContext   *context,
                gboolean          ok,
                guint32           time)
 {
-  GdkDragContextPrivate *private;
+  GdkDragContextPrivateX11 *private;
 
   g_return_if_fail (context != NULL);
 
-  private = (GdkDragContextPrivate *)context;
+  private = PRIVATE_DATA (context);
   
   if (context->protocol == GDK_DRAG_PROTO_MOTIF)
     {
+      GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
       XEvent xev;
 
       xev.xclient.type = ClientMessage;
-      xev.xclient.message_type = gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE);
+      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
+                                                                       "_MOTIF_DRAG_AND_DROP_MESSAGE");
       xev.xclient.format = 8;
 
       MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START | 0x80;
@@ -3002,12 +3672,26 @@ gdk_drop_reply (GdkDragContext   *context,
                                       (XmDROP_CANCEL << 12);
       MOTIF_XCLIENT_SHORT (&xev, 2) = private->last_x;
       MOTIF_XCLIENT_SHORT (&xev, 3) = private->last_y;
+      MOTIF_XCLIENT_LONG (&xev, 2) = 0;
+      MOTIF_XCLIENT_LONG (&xev, 3) = 0;
+      MOTIF_XCLIENT_LONG (&xev, 4) = 0;
       
-      gdk_send_xevent (GDK_WINDOW_XWINDOW (context->source_window),
-                      FALSE, 0, &xev);
+      _gdk_send_xevent (display,
+                       GDK_DRAWABLE_XID (context->source_window),
+                       FALSE, 0, &xev);
     }
 }
 
+/**
+ * gdk_drop_finish:
+ * @context: a #GtkDragContext.
+ * @success: %TRUE if the data was successfully received.
+ * @time_: the timestamp for this operation.
+ * 
+ * Ends the drag operation after a drop.
+ *
+ * This function is called by the drag destination.
+ **/
 void             
 gdk_drop_finish (GdkDragContext   *context,
                 gboolean          success,
@@ -3017,24 +3701,34 @@ gdk_drop_finish (GdkDragContext   *context,
 
   if (context->protocol == GDK_DRAG_PROTO_XDND)
     {
+      GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
       XEvent xev;
 
       xev.xclient.type = ClientMessage;
-      xev.xclient.message_type = gdk_atom_intern ("XdndFinished", FALSE);
+      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndFinished");
       xev.xclient.format = 32;
-      xev.xclient.window = GDK_WINDOW_XWINDOW (context->source_window);
-
-      xev.xclient.data.l[0] = GDK_WINDOW_XWINDOW (context->dest_window);
-      xev.xclient.data.l[1] = 0;
-      xev.xclient.data.l[2] = 0;
+      xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
+      
+      xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
+      if (success)
+       {
+         xev.xclient.data.l[1] = 1;
+         xev.xclient.data.l[2] = xdnd_action_to_atom (display, 
+                                                      context->action);
+       }
+      else
+       {
+         xev.xclient.data.l[1] = 0;
+         xev.xclient.data.l[2] = None;
+       }
       xev.xclient.data.l[3] = 0;
       xev.xclient.data.l[4] = 0;
 
-      if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->source_window),
-                      FALSE, 0, &xev))
+      if (!xdnd_send_xevent (context, context->source_window,
+                            FALSE, &xev))
        GDK_NOTE (DND, 
                  g_message ("Send event to %lx failed",
-                            GDK_WINDOW_XWINDOW (context->source_window)));
+                            GDK_DRAWABLE_XID (context->source_window)));
     }
 }
 
@@ -3042,24 +3736,34 @@ gdk_drop_finish (GdkDragContext   *context,
 void            
 gdk_window_register_dnd (GdkWindow      *window)
 {
-  static gulong xdnd_version = 3;
+  static const gulong xdnd_version = 5;
   MotifDragReceiverInfo info;
+  Atom motif_drag_receiver_info_atom;
+  GdkDisplay *display = gdk_drawable_get_display (window);
 
   g_return_if_fail (window != NULL);
 
-  /* Set Motif drag receiver information property */
+  base_precache_atoms (display);
 
-  if (!motif_drag_receiver_info_atom)
-    motif_drag_receiver_info_atom = gdk_atom_intern ("_MOTIF_DRAG_RECEIVER_INFO", FALSE);
+  if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
+    return;
+  else
+    g_object_set_data (G_OBJECT (window), "gdk-dnd-registered", GINT_TO_POINTER (TRUE));
+  
+  /* Set Motif drag receiver information property */
 
+  motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display,
+                                                                        "_MOTIF_DRAG_RECEIVER_INFO");
+  /* initialize to zero to avoid writing uninitialized data to socket */
+  memset(&info, 0, sizeof(info));
   info.byte_order = local_byte_order;
   info.protocol_version = 0;
   info.protocol_style = XmDRAG_DYNAMIC;
-  info.proxy_window = GDK_NONE;
+  info.proxy_window = None;
   info.num_drop_sites = 0;
   info.total_size = sizeof(info);
 
-  XChangeProperty (gdk_display, GDK_WINDOW_XWINDOW (window),
+  XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_DRAWABLE_XID (window),
                   motif_drag_receiver_info_atom,
                   motif_drag_receiver_info_atom,
                   8, PropModeReplace,
@@ -3068,35 +3772,60 @@ gdk_window_register_dnd (GdkWindow      *window)
 
   /* Set XdndAware */
 
-  if (!xdnd_aware_atom)
-    xdnd_aware_atom = gdk_atom_intern ("XdndAware", FALSE);
-
   /* The property needs to be of type XA_ATOM, not XA_INTEGER. Blech */
-  XChangeProperty (GDK_WINDOW_XDISPLAY (window), 
-                  GDK_WINDOW_XWINDOW (window),
-                  xdnd_aware_atom, XA_ATOM,
-                  32, PropModeReplace,
+  XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+                  GDK_DRAWABLE_XID (window),
+                  gdk_x11_get_xatom_by_name_for_display (display, "XdndAware"),
+                  XA_ATOM, 32, PropModeReplace,
                   (guchar *)&xdnd_version, 1);
 }
 
-/*************************************************************
+/**
  * gdk_drag_get_selection:
- *     Returns the selection atom for the current source window
- *   arguments:
- *     
- *   results:
- *************************************************************/
-
-GdkAtom       
+ * @context: a #GdkDragContext.
+ * 
+ * Returns the selection atom for the current source window.
+ * 
+ * Return value: the selection atom.
+ **/
+GdkAtom
 gdk_drag_get_selection (GdkDragContext *context)
 {
   g_return_val_if_fail (context != NULL, GDK_NONE);
 
   if (context->protocol == GDK_DRAG_PROTO_MOTIF)
-    return ((GdkDragContextPrivate *)context)->motif_selection;
+    return gdk_x11_xatom_to_atom_for_display (GDK_DRAWABLE_DISPLAY (context->source_window),
+                                             (PRIVATE_DATA (context))->motif_selection);
   else if (context->protocol == GDK_DRAG_PROTO_XDND)
-    return ((GdkDragContextPrivate *)context)->xdnd_selection;
-  else 
+    return gdk_atom_intern_static_string ("XdndSelection");
+  else
     return GDK_NONE;
 }
 
+/**
+ * gdk_drag_drop_succeeded:
+ * @context: a #GdkDragContext
+ * 
+ * Returns wether the dropped data has been successfully 
+ * transferred. This function is intended to be used while 
+ * handling a %GDK_DROP_FINISHED event, its return value is
+ * meaningless at other times.
+ * 
+ * Return value: %TRUE if the drop was successful.
+ *
+ * Since: 2.6
+ **/
+gboolean 
+gdk_drag_drop_succeeded (GdkDragContext *context)
+{
+  GdkDragContextPrivateX11 *private;
+
+  g_return_val_if_fail (context != NULL, FALSE);
+
+  private = PRIVATE_DATA (context);
+
+  return !private->drop_failed;
+}
+
+#define __GDK_DND_X11_C__
+#include "gdkaliasdef.c"