]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkdnd.c
Skip insensitive widgets. (#84061)
[~andy/gtk] / gtk / gtkdnd.c
index f61ae769f2173d623768a45a167726d2a705c2ba..35281f065e9f474b94cb933a10619478c9ef821c 100644 (file)
 #include "gtkimage.h"
 #include "gtkinvisible.h"
 #include "gtkmain.h"
-#include "gtksignal.h"
 #include "gtkstock.h"
 #include "gtkwindow.h"
 
-static GSList *drag_widgets = NULL;
 static GSList *source_widgets = NULL;
 
 typedef struct _GtkDragSourceSite GtkDragSourceSite;
@@ -84,6 +82,7 @@ struct _GtkDragSourceInfo
   GdkDragAction      possible_actions; /* Actions allowed by source */
   GdkDragContext    *context;    /* drag context */
   GtkWidget         *icon_window; /* Window for drag */
+  GtkWidget         *fallback_icon; /* Window for drag used on other screens */
   GtkWidget         *ipc_widget;  /* GtkInvisible for grab, message passing */
   GdkCursor         *cursor;     /* Cursor for drag */
   gint hot_x, hot_y;             /* Hot spot for drag */
@@ -94,14 +93,18 @@ struct _GtkDragSourceInfo
 
   gint               start_x, start_y; /* Initial position */
   gint               cur_x, cur_y;     /* Current Position */
+  GdkScreen         *cur_screen;       /* Current screen for pointer */
 
+  guint32            grab_time;   /* timestamp for initial grab */
   GList             *selections;  /* selections we've claimed */
   
   GtkDragDestInfo   *proxy_dest;  /* Set if this is a proxy drag */
 
   guint              drop_timeout;     /* Timeout for aborting drop */
   guint              destroy_icon : 1; /* If true, destroy icon_window
-                                       */
+                                       */
+  guint              have_grab : 1;    /* Do we still have the pointer grab
+                                        */
 };
 
 struct _GtkDragDestSite 
@@ -180,8 +183,9 @@ static void          gtk_drag_get_event_actions (GdkEvent        *event,
                                                 GdkDragAction    actions,
                                                 GdkDragAction   *suggested_action,
                                                 GdkDragAction   *possible_actions);
-static GdkCursor *   gtk_drag_get_cursor         (GdkDragAction action);
-static GtkWidget    *gtk_drag_get_ipc_widget     (void);
+static GdkCursor *   gtk_drag_get_cursor         (GdkDisplay     *display,
+                                                 GdkDragAction   action);
+static GtkWidget    *gtk_drag_get_ipc_widget     (GdkScreen     *screen);
 static void          gtk_drag_release_ipc_widget (GtkWidget      *widget);
 
 static gboolean      gtk_drag_highlight_expose   (GtkWidget      *widget,
@@ -231,6 +235,8 @@ static void gtk_drag_drop                      (GtkDragSourceInfo *info,
 static void gtk_drag_drop_finished             (GtkDragSourceInfo *info,
                                                gboolean           success,
                                                guint              time);
+static void gtk_drag_cancel                    (GtkDragSourceInfo *info,
+                                               guint32            time);
 
 static gint gtk_drag_source_event_cb           (GtkWidget         *widget,
                                                GdkEvent          *event,
@@ -245,6 +251,7 @@ static gint gtk_drag_anim_timeout              (gpointer           data);
 static void gtk_drag_remove_icon               (GtkDragSourceInfo *info);
 static void gtk_drag_source_info_destroy       (GtkDragSourceInfo *info);
 static void gtk_drag_update                    (GtkDragSourceInfo *info,
+                                               GdkScreen         *screen,
                                                gint               x_root,
                                                gint               y_root,
                                                GdkEvent          *event);
@@ -338,8 +345,8 @@ static const guchar action_none_mask_bits[] = {
 
 static struct {
   GdkDragAction action;
-  const char *bits;
-  const char *mask;
+  const guchar *bits;
+  const guchar *mask;
   GdkCursor    *cursor;
 } drag_cursors[] = {
   { GDK_ACTION_DEFAULT, 0 },
@@ -356,6 +363,23 @@ static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[
  * Utility functions *
  *********************/
 
+static void
+set_can_change_screen (GtkWidget *widget,
+                      gboolean   can_change_screen)
+{
+  can_change_screen = can_change_screen != FALSE;
+  
+  g_object_set_data (G_OBJECT (widget), "gtk-dnd-can-change-screen",
+                    GUINT_TO_POINTER (can_change_screen));
+}
+
+static gboolean
+get_can_change_screen (GtkWidget *widget)
+{
+  return g_object_get_data (G_OBJECT (widget), "gtk-dnd-can-change-screen") != NULL;
+
+}
+
 /*************************************************************
  * gtk_drag_get_ipc_widget:
  *     Return a invisible, off-screen, override-redirect
@@ -366,20 +390,25 @@ static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[
  *************************************************************/
 
 static GtkWidget *
-gtk_drag_get_ipc_widget (void)
+gtk_drag_get_ipc_widget (GdkScreen *screen)
 {
   GtkWidget *result;
+  GSList *drag_widgets = g_object_get_data (G_OBJECT (screen), 
+                                           "gtk-dnd-ipc-widgets");
   
   if (drag_widgets)
     {
       GSList *tmp = drag_widgets;
       result = drag_widgets->data;
       drag_widgets = drag_widgets->next;
+      g_object_set_data (G_OBJECT (screen),
+                        "gtk-dnd-ipc-widgets",
+                        drag_widgets);
       g_slist_free_1 (tmp);
     }
   else
     {
-      result = gtk_invisible_new ();
+      result = gtk_invisible_new_for_screen (screen);
       gtk_widget_show (result);
     }
 
@@ -397,7 +426,13 @@ gtk_drag_get_ipc_widget (void)
 static void
 gtk_drag_release_ipc_widget (GtkWidget *widget)
 {
+  GdkScreen *screen = gtk_widget_get_screen (widget);
+  GSList *drag_widgets = g_object_get_data (G_OBJECT (screen),
+                                           "gtk-dnd-ipc-widgets");
   drag_widgets = g_slist_prepend (drag_widgets, widget);
+  g_object_set_data (G_OBJECT (screen),
+                    "gtk-dnd-ipc-widgets",
+                    drag_widgets);
 }
 
 static guint32
@@ -538,34 +573,40 @@ gtk_drag_get_event_actions (GdkEvent *event,
 }
 
 static GdkCursor *
-gtk_drag_get_cursor (GdkDragAction action)
+gtk_drag_get_cursor (GdkDisplay   *display,
+                    GdkDragAction action)
 {
   gint i;
   
   for (i = 0 ; i < n_drag_cursors - 1; i++)
     if (drag_cursors[i].action == action)
       break;
+  if (drag_cursors[i].cursor != NULL)
+    {
+      if (display != gdk_cursor_get_display (drag_cursors[i].cursor))
+       {
+         gdk_cursor_unref (drag_cursors[i].cursor);
+         drag_cursors[i].cursor = NULL;
+       }
+    }
 
   if (drag_cursors[i].cursor == NULL)
     {
-      GdkColor fg, bg;
+      GdkColor bg = { 0, 0xffff, 0xffff, 0xffff };
+      GdkColor fg = { 0, 0x0000, 0x0000, 0x0000 };
+      GdkScreen *screen = gdk_display_get_default_screen (display);
+      GdkWindow *window = gdk_screen_get_root_window (screen);
 
       GdkPixmap *pixmap = 
-       gdk_bitmap_create_from_data (NULL, 
-                                    drag_cursors[i].bits,
-                                    CURSOR_WIDTH, CURSOR_HEIGHT);
+       gdk_bitmap_create_from_data (window, (gchar *)drag_cursors[i].bits, CURSOR_WIDTH, CURSOR_HEIGHT);
+
       GdkPixmap *mask = 
-       gdk_bitmap_create_from_data (NULL, 
-                                    drag_cursors[i].mask,
-                                    CURSOR_WIDTH, CURSOR_HEIGHT);
+       gdk_bitmap_create_from_data (window, (gchar *)drag_cursors[i].mask, CURSOR_WIDTH, CURSOR_HEIGHT);
 
-      gdk_color_white (gdk_colormap_get_system (), &bg);
-      gdk_color_black (gdk_colormap_get_system (), &fg);
-      
       drag_cursors[i].cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, 0, 0);
 
-      gdk_pixmap_unref (pixmap);
-      gdk_pixmap_unref (mask);
+      g_object_unref (pixmap);
+      g_object_unref (mask);
     }
 
   return drag_cursors[i].cursor;
@@ -594,18 +635,19 @@ gtk_drag_get_data (GtkWidget      *widget,
 {
   GtkWidget *selection_widget;
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (context != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (!context->is_source);
 
-  selection_widget = gtk_drag_get_ipc_widget ();
+  selection_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
 
-  gdk_drag_context_ref (context);
-  gtk_widget_ref (widget);
+  g_object_ref (context);
+  g_object_ref (widget);
   
-  gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
-                     GTK_SIGNAL_FUNC (gtk_drag_selection_received), widget);
+  g_signal_connect (selection_widget, "selection_received",
+                   G_CALLBACK (gtk_drag_selection_received), widget);
 
-  gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
+  g_object_set_data (G_OBJECT (selection_widget), "drag-context", context);
 
   gtk_selection_convert (selection_widget,
                         gdk_drag_get_selection (context),
@@ -630,6 +672,9 @@ gtk_drag_get_source_widget (GdkDragContext *context)
 {
   GSList *tmp_list;
 
+  g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), NULL);
+  g_return_val_if_fail (!context->is_source, NULL);
+  
   tmp_list = source_widgets;
   while (tmp_list)
     {
@@ -638,7 +683,7 @@ gtk_drag_get_source_widget (GdkDragContext *context)
       if (ipc_widget->window == context->source_window)
        {
          GtkDragSourceInfo *info;
-         info = gtk_object_get_data (GTK_OBJECT (ipc_widget), "gtk-info");
+         info = g_object_get_data (G_OBJECT (ipc_widget), "gtk-info");
 
          return info ? info->widget : NULL;
        }
@@ -668,7 +713,8 @@ gtk_drag_finish (GdkDragContext *context,
 {
   GdkAtom target = GDK_NONE;
 
-  g_return_if_fail (context != NULL);
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (!context->is_source);
 
   if (success && del)
     {
@@ -684,14 +730,14 @@ gtk_drag_finish (GdkDragContext *context,
 
   if (target != GDK_NONE)
     {
-      GtkWidget *selection_widget = gtk_drag_get_ipc_widget ();
+      GtkWidget *selection_widget = gtk_drag_get_ipc_widget (gdk_drawable_get_screen (context->source_window));
 
-      gdk_drag_context_ref (context);
+      g_object_ref (context);
       
-      gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
-      gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
-                         GTK_SIGNAL_FUNC (gtk_drag_selection_received),
-                         NULL);
+      g_object_set_data (G_OBJECT (selection_widget), "drag-context", context);
+      g_signal_connect (selection_widget, "selection_received",
+                       G_CALLBACK (gtk_drag_selection_received),
+                       NULL);
       
       gtk_selection_convert (selection_widget,
                             gdk_drag_get_selection (context),
@@ -699,7 +745,7 @@ gtk_drag_finish (GdkDragContext *context,
                             time);
     }
   
-  if (!del)
+  if (!(success && del))
     gdk_drop_finish (context, success, time);
 }
 
@@ -733,12 +779,13 @@ gtk_drag_highlight_expose (GtkWidget      *widget,
        {
          x = 0;
          y = 0;
-         gdk_window_get_size (widget->window, &width, &height);
+         gdk_drawable_get_size (widget->window, &width, &height);
        }
       
-      gtk_draw_shadow (widget->style, widget->window,
-                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-                      x, y, width, height);
+      gtk_paint_shadow (widget->style, widget->window,
+                       GTK_STATE_NORMAL, GTK_SHADOW_OUT,
+                       NULL, widget, "dnd",
+                       x, y, width, height);
       
       gdk_draw_rectangle (widget->window,
                          widget->style->black_gc,
@@ -760,9 +807,11 @@ gtk_drag_highlight_expose (GtkWidget      *widget,
 void 
 gtk_drag_highlight (GtkWidget  *widget)
 {
-  gtk_signal_connect (GTK_OBJECT (widget), "expose_event",
-                     GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
-                     NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  g_signal_connect_after (widget, "expose_event",
+                         G_CALLBACK (gtk_drag_highlight_expose),
+                         NULL);
 
   gtk_widget_queue_draw (widget);
 }
@@ -778,13 +827,13 @@ gtk_drag_highlight (GtkWidget  *widget)
 void 
 gtk_drag_unhighlight (GtkWidget *widget)
 {
-  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
 
-  gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
-                                GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
-                                NULL);
+  g_signal_handlers_disconnect_by_func (widget,
+                                       gtk_drag_highlight_expose,
+                                       NULL);
   
-  gtk_widget_queue_clear (widget);
+  gtk_widget_queue_draw (widget);
 }
 
 static void
@@ -796,20 +845,27 @@ gtk_drag_dest_set_internal (GtkWidget       *widget,
   g_return_if_fail (widget != NULL);
 
   /* HACK, do this in the destroy */
-  old_site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
+  old_site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
   if (old_site)
-    gtk_signal_disconnect_by_data (GTK_OBJECT (widget), old_site);
+    {
+      g_signal_handlers_disconnect_by_func (widget,
+                                           gtk_drag_dest_realized,
+                                           old_site);
+      g_signal_handlers_disconnect_by_func (widget,
+                                           gtk_drag_dest_hierarchy_changed,
+                                           old_site);
+    }
 
   if (GTK_WIDGET_REALIZED (widget))
     gtk_drag_dest_realized (widget);
 
-  gtk_signal_connect (GTK_OBJECT (widget), "realize",
-                     GTK_SIGNAL_FUNC (gtk_drag_dest_realized), site);
-  gtk_signal_connect (GTK_OBJECT (widget), "hierarchy_changed",
-                     GTK_SIGNAL_FUNC (gtk_drag_dest_hierarchy_changed), site);
+  g_signal_connect (widget, "realize",
+                   G_CALLBACK (gtk_drag_dest_realized), site);
+  g_signal_connect (widget, "hierarchy_changed",
+                   G_CALLBACK (gtk_drag_dest_hierarchy_changed), site);
 
-  gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
-                           site, gtk_drag_dest_site_destroy);
+  g_object_set_data_full (G_OBJECT (widget), "gtk-drag-dest",
+                         site, gtk_drag_dest_site_destroy);
 }
                            
 
@@ -834,7 +890,7 @@ gtk_drag_dest_set   (GtkWidget            *widget,
 {
   GtkDragDestSite *site;
   
-  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
 
   site = g_new (GtkDragDestSite, 1);
 
@@ -844,9 +900,9 @@ gtk_drag_dest_set   (GtkWidget            *widget,
     site->target_list = gtk_target_list_new (targets, n_targets);
   else
     site->target_list = NULL;
-
   site->actions = actions;
   site->do_proxy = FALSE;
+  site->proxy_window = NULL;
 
   gtk_drag_dest_set_internal (widget, site);
 }
@@ -872,7 +928,8 @@ gtk_drag_dest_set_proxy (GtkWidget      *widget,
 {
   GtkDragDestSite *site;
   
-  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (!proxy_window || GDK_IS_WINDOW (proxy_window));
 
   site = g_new (GtkDragDestSite, 1);
 
@@ -882,7 +939,7 @@ gtk_drag_dest_set_proxy (GtkWidget      *widget,
   site->actions = 0;
   site->proxy_window = proxy_window;
   if (proxy_window)
-    gdk_window_ref (proxy_window);
+    g_object_ref (proxy_window);
   site->do_proxy = TRUE;
   site->proxy_protocol = protocol;
   site->proxy_coords = use_coordinates;
@@ -901,9 +958,9 @@ gtk_drag_dest_set_proxy (GtkWidget      *widget,
 void 
 gtk_drag_dest_unset (GtkWidget *widget)
 {
-  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
 
-  gtk_object_set_data (GTK_OBJECT (widget), "gtk-drag-dest", NULL);
+  g_object_set_data (G_OBJECT (widget), "gtk-drag-dest", NULL);
 }
 
 /**
@@ -919,8 +976,10 @@ GtkTargetList*
 gtk_drag_dest_get_target_list (GtkWidget *widget)
 {
   GtkDragDestSite *site;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
   
-  site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
+  site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
 
   return site ? site->target_list : NULL;  
 }
@@ -939,8 +998,10 @@ gtk_drag_dest_set_target_list (GtkWidget      *widget,
                                GtkTargetList  *target_list)
 {
   GtkDragDestSite *site;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
   
-  site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
+  site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
   
   if (site == NULL)
     {
@@ -1061,7 +1122,8 @@ _gtk_drag_dest_handle_event (GtkWidget *toplevel,
  * gtk_drag_dest_find_target:
  * @widget: drag destination widget
  * @context: drag context
- * @target_list: list of droppable targets
+ * @target_list: list of droppable targets, or %NULL to use
+ *    gtk_drag_dest_get_target_list (@widget).
  * 
  * Looks for a match between @context->targets and the
  * @dest_target_list, returning the first matching target, otherwise
@@ -1080,8 +1142,18 @@ gtk_drag_dest_find_target (GtkWidget      *widget,
 {
   GList *tmp_target;
   GList *tmp_source = NULL;
-  GtkWidget *source_widget = gtk_drag_get_source_widget (context);
+  GtkWidget *source_widget;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), GDK_NONE);
+  g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), GDK_NONE);
+  g_return_val_if_fail (!context->is_source, GDK_NONE);
+
+
+  source_widget = gtk_drag_get_source_widget (context);
 
+  if (target_list == NULL)
+    target_list = gtk_drag_dest_get_target_list (widget);
+  
   if (target_list == NULL)
     return GDK_NONE;
   
@@ -1120,7 +1192,7 @@ gtk_drag_selection_received (GtkWidget        *widget,
 
   drop_widget = data;
 
-  context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
+  context = g_object_get_data (G_OBJECT (widget), "drag-context");
   info = gtk_drag_get_dest_info (context, FALSE);
 
   if (info->proxy_data && 
@@ -1148,7 +1220,7 @@ gtk_drag_selection_received (GtkWidget        *widget,
     {
       GtkDragDestSite *site;
 
-      site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest");
+      site = g_object_get_data (G_OBJECT (drop_widget), "gtk-drag-dest");
 
       if (site && site->target_list)
        {
@@ -1160,19 +1232,20 @@ gtk_drag_selection_received (GtkWidget        *widget,
            {
              if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
                  selection_data->length >= 0)
-               gtk_signal_emit_by_name (GTK_OBJECT (drop_widget), 
-                                        "drag_data_received",
-                                        context, info->drop_x, info->drop_y,
-                                        selection_data, 
-                                        target_info, time);
+               g_signal_emit_by_name (drop_widget,
+                                      "drag_data_received",
+                                      context, info->drop_x, info->drop_y,
+                                      selection_data,
+                                      target_info, time);
            }
        }
       else
        {
-         gtk_signal_emit_by_name (GTK_OBJECT (drop_widget), 
-                                  "drag_data_received",
-                                  context, info->drop_x, info->drop_y,
-                                  selection_data, 0, time);
+         g_signal_emit_by_name (drop_widget,
+                                "drag_data_received",
+                                context, info->drop_x, info->drop_y,
+                                selection_data,
+                                0, time);
        }
       
       if (site && site->flags & GTK_DEST_DEFAULT_DROP)
@@ -1184,19 +1257,28 @@ gtk_drag_selection_received (GtkWidget        *widget,
                           time);
        }
       
-      gtk_widget_unref (drop_widget);
+      g_object_unref (drop_widget);
     }
 
-  gtk_signal_disconnect_by_func (GTK_OBJECT (widget), 
-                                GTK_SIGNAL_FUNC (gtk_drag_selection_received),
-                                data);
+  g_signal_handlers_disconnect_by_func (widget,
+                                       gtk_drag_selection_received,
+                                       data);
   
-  gtk_object_set_data (GTK_OBJECT (widget), "drag-context", NULL);
-  gdk_drag_context_unref (context);
+  g_object_set_data (G_OBJECT (widget), "drag-context", NULL);
+  g_object_unref (context);
 
   gtk_drag_release_ipc_widget (widget);
 }
 
+static void
+prepend_and_ref_widget (GtkWidget *widget,
+                       gpointer   data)
+{
+  GSList **slist_p = data;
+
+  *slist_p = g_slist_prepend (*slist_p, g_object_ref (widget));
+}
+
 /*************************************************************
  * gtk_drag_find_widget:
  *     Recursive callback used to locate widgets for 
@@ -1211,12 +1293,12 @@ gtk_drag_find_widget (GtkWidget       *widget,
                      GtkDragFindData *data)
 {
   GtkAllocation new_allocation;
+  gint allocation_to_window_x = 0;
+  gint allocation_to_window_y = 0;
   gint x_offset = 0;
   gint y_offset = 0;
 
-  new_allocation = widget->allocation;
-
-  if (data->found || !GTK_WIDGET_MAPPED (widget))
+  if (data->found || !GTK_WIDGET_MAPPED (widget) || !GTK_WIDGET_SENSITIVE (widget))
     return;
 
   /* Note that in the following code, we only count the
@@ -1224,35 +1306,49 @@ gtk_drag_find_widget (GtkWidget       *widget,
    * widget->window; points that are outside of widget->window
    * but within the allocation are not counted. This is consistent
    * with the way we highlight drag targets.
-   */
-  if (!GTK_WIDGET_NO_WINDOW (widget))
-    {
-      new_allocation.x = 0;
-      new_allocation.y = 0;
-    }
-  
+   *
+   * data->x,y are relative to widget->parent->window (if
+   * widget is not a toplevel, widget->window otherwise).
+   * We compute the allocation of widget in the same coordinates,
+   * clipping to widget->window, and all intermediate
+   * windows. If data->x,y is inside that, then we translate
+   * our coordinates to be relative to widget->window and
+   * recurse.
+   */  
+  new_allocation = widget->allocation;
+
   if (widget->parent)
     {
+      gint tx, ty;
       GdkWindow *window = widget->window;
-      while (window != widget->parent->window)
+
+      /* Compute the offset from allocation-relative to
+       * window-relative coordinates.
+       */
+      allocation_to_window_x = widget->allocation.x;
+      allocation_to_window_y = widget->allocation.y;
+
+      if (!GTK_WIDGET_NO_WINDOW (widget))
        {
-         gint tx, ty, twidth, theight;
-         gdk_window_get_size (window, &twidth, &theight);
+         /* The allocation is relative to the parent window for
+          * window widgets, not to widget->window.
+          */
+          gdk_window_get_position (window, &tx, &ty);
+         
+          allocation_to_window_x -= tx;
+          allocation_to_window_y -= ty;
+       }
 
-         if (new_allocation.x < 0)
-           {
-             new_allocation.width += new_allocation.x;
-             new_allocation.x = 0;
-           }
-         if (new_allocation.y < 0)
-           {
-             new_allocation.height += new_allocation.y;
-             new_allocation.y = 0;
-           }
-         if (new_allocation.x + new_allocation.width > twidth)
-           new_allocation.width = twidth - new_allocation.x;
-         if (new_allocation.y + new_allocation.height > theight)
-           new_allocation.height = theight - new_allocation.y;
+      new_allocation.x = 0 + allocation_to_window_x;
+      new_allocation.y = 0 + allocation_to_window_y;
+      
+      while (window && window != widget->parent->window)
+       {
+         GdkRectangle window_rect = { 0, 0, 0, 0 };
+         
+         gdk_drawable_get_size (window, &window_rect.width, &window_rect.height);
+
+         gdk_rectangle_intersect (&new_allocation, &window_rect, &new_allocation);
 
          gdk_window_get_position (window, &tx, &ty);
          new_allocation.x += tx;
@@ -1262,6 +1358,9 @@ gtk_drag_find_widget (GtkWidget       *widget,
          
          window = gdk_window_get_parent (window);
        }
+
+      if (!window)             /* Window and widget heirarchies didn't match. */
+       return;
     }
 
   if (data->toplevel ||
@@ -1275,15 +1374,25 @@ gtk_drag_find_widget (GtkWidget       *widget,
       if (GTK_IS_CONTAINER (widget))
        {
          GtkDragFindData new_data = *data;
+         GSList *children = NULL;
+         GSList *tmp_list;
          
          new_data.x -= x_offset;
          new_data.y -= y_offset;
          new_data.found = FALSE;
          new_data.toplevel = FALSE;
          
-         gtk_container_forall (GTK_CONTAINER (widget),
-                               (GtkCallback)gtk_drag_find_widget,
-                               &new_data);
+         /* need to reference children temporarily in case the
+          * ::drag_motion/::drag_drop callbacks change the widget heirarchy.
+          */
+         gtk_container_forall (GTK_CONTAINER (widget), prepend_and_ref_widget, &children);
+         for (tmp_list = children; tmp_list; tmp_list = tmp_list->next)
+           {
+             if (!new_data.found && GTK_WIDGET_DRAWABLE (tmp_list->data))
+               gtk_drag_find_widget (tmp_list->data, &new_data);
+             g_object_unref (tmp_list->data);
+           }
+         g_slist_free (children);
          
          data->found = new_data.found;
        }
@@ -1293,12 +1402,12 @@ gtk_drag_find_widget (GtkWidget       *widget,
        * a drop site.
        */
       if (!data->found &&
-         gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"))
+         g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"))
        {
          data->found = data->callback (widget,
                                        data->context,
-                                       data->x - new_allocation.x,
-                                       data->y - new_allocation.y,
+                                       data->x - x_offset - allocation_to_window_x,
+                                       data->y - y_offset - allocation_to_window_y,
                                        data->time);
          /* If so, send a "drag_leave" to the last widget */
          if (data->found)
@@ -1330,7 +1439,7 @@ gtk_drag_proxy_begin (GtkWidget       *widget,
       dest_info->proxy_source = NULL;
     }
   
-  ipc_widget = gtk_drag_get_ipc_widget ();
+  ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
   context = gdk_drag_begin (ipc_widget->window,
                            dest_info->context->targets);
 
@@ -1344,16 +1453,16 @@ gtk_drag_proxy_begin (GtkWidget       *widget,
   while (tmp_list)
     {
       gtk_target_list_add (source_info->target_list, 
-                          GPOINTER_TO_UINT (tmp_list->data), 0, 0);
+                          GDK_POINTER_TO_ATOM (tmp_list->data), 0, 0);
       tmp_list = tmp_list->next;
     }
 
   source_info->proxy_dest = dest_info;
   
-  gtk_signal_connect (GTK_OBJECT (ipc_widget), 
-                     "selection_get",
-                     GTK_SIGNAL_FUNC (gtk_drag_selection_get), 
-                     source_info);
+  g_signal_connect (ipc_widget,
+                   "selection_get",
+                   G_CALLBACK (gtk_drag_selection_get),
+                   source_info);
   
   dest_info->proxy_source = source_info;
 }
@@ -1443,6 +1552,9 @@ gtk_drag_dest_site_destroy (gpointer data)
 {
   GtkDragDestSite *site = data;
 
+  if (site->proxy_window)
+    g_object_unref (site->proxy_window);
+    
   if (site->target_list)
     gtk_target_list_unref (site->target_list);
 
@@ -1459,7 +1571,7 @@ gtk_drag_dest_leave (GtkWidget      *widget,
 {
   GtkDragDestSite *site;
 
-  site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
+  site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
   g_return_if_fail (site != NULL);
 
   if (site->do_proxy)
@@ -1481,8 +1593,8 @@ gtk_drag_dest_leave (GtkWidget      *widget,
        gtk_drag_unhighlight (widget);
 
       if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag)
-       gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_leave",
-                                context, time);
+       g_signal_emit_by_name (widget, "drag_leave",
+                              context, time);
       
       site->have_drag = FALSE;
     }
@@ -1499,7 +1611,7 @@ gtk_drag_dest_motion (GtkWidget        *widget,
   GdkDragAction action = 0;
   gboolean retval;
 
-  site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
+  site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
   g_return_val_if_fail (site != NULL, FALSE);
 
   if (site->do_proxy)
@@ -1523,11 +1635,12 @@ gtk_drag_dest_motion (GtkWidget      *widget,
        }
       else
        {
-         gdk_drag_find_window (info->proxy_source->context,
-                               NULL,
-                               current_event->dnd.x_root, 
-                               current_event->dnd.y_root,
-                               &dest_window, &proto);
+         gdk_drag_find_window_for_screen (info->proxy_source->context,
+                                          NULL,
+                                          gdk_drawable_get_screen (current_event->dnd.window),
+                                          current_event->dnd.x_root, 
+                                          current_event->dnd.y_root,
+                                          &dest_window, &proto);
        }
       
       gdk_drag_motion (info->proxy_source->context, 
@@ -1538,7 +1651,7 @@ gtk_drag_dest_motion (GtkWidget        *widget,
                       context->actions, time);
 
       if (!site->proxy_window && dest_window)
-       gdk_window_unref (dest_window);
+       g_object_unref (dest_window);
 
       selection = gdk_drag_get_selection (info->proxy_source->context);
       if (selection && 
@@ -1569,7 +1682,7 @@ gtk_drag_dest_motion (GtkWidget        *widget,
            }
        }
       
-      if (action && gtk_drag_dest_find_target (widget, context, site->target_list))
+      if (action && gtk_drag_dest_find_target (widget, context, NULL))
        {
          if (!site->have_drag)
            {
@@ -1587,8 +1700,8 @@ gtk_drag_dest_motion (GtkWidget        *widget,
        }
     }
 
-  gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_motion",
-                          context, x, y, time, &retval);
+  g_signal_emit_by_name (widget, "drag_motion",
+                        context, x, y, time, &retval);
 
   return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
 }
@@ -1603,7 +1716,7 @@ gtk_drag_dest_drop (GtkWidget          *widget,
   GtkDragDestSite *site;
   GtkDragDestInfo *info;
 
-  site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
+  site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
   g_return_val_if_fail (site != NULL, FALSE);
 
   info = gtk_drag_get_dest_info (context, FALSE);
@@ -1643,11 +1756,12 @@ gtk_drag_dest_drop (GtkWidget        *widget,
            }
          else
            {
-             gdk_drag_find_window (info->proxy_source->context,
-                                   NULL,
-                                   current_event->dnd.x_root, 
-                                   current_event->dnd.y_root,
-                                   &dest_window, &proto);
+             gdk_drag_find_window_for_screen (info->proxy_source->context,
+                                              NULL,
+                                              gdk_drawable_get_screen (current_event->dnd.window),
+                                              current_event->dnd.x_root, 
+                                              current_event->dnd.y_root,
+                                              &dest_window, &proto);
            }
 
          gdk_drag_motion (info->proxy_source->context, 
@@ -1658,7 +1772,7 @@ gtk_drag_dest_drop (GtkWidget          *widget,
                           context->actions, time);
 
          if (!site->proxy_window && dest_window)
-           gdk_window_unref (dest_window);
+           g_object_unref (dest_window);
 
          selection = gdk_drag_get_selection (info->proxy_source->context);
          if (selection && 
@@ -1676,16 +1790,19 @@ gtk_drag_dest_drop (GtkWidget        *widget,
 
       if (site->flags & GTK_DEST_DEFAULT_DROP)
        {
-         GdkAtom target = gtk_drag_dest_find_target (widget, context, site->target_list);
+         GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
       
          if (target == GDK_NONE)
-           return FALSE;
-         
-         gtk_drag_get_data (widget, context, target, time);
+           {
+             gtk_drag_finish (context, FALSE, FALSE, time);
+             return TRUE;
+           }
+         else
+           gtk_drag_get_data (widget, context, target, time);
        }
 
-      gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_drop",
-                              context, x, y, time, &retval);
+      g_signal_emit_by_name (widget, "drag_drop",
+                            context, x, y, time, &retval);
 
       return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
     }
@@ -1722,7 +1839,7 @@ gtk_drag_begin (GtkWidget         *widget,
   GdkDragContext *context;
   GtkWidget *ipc_widget;
 
-  g_return_val_if_fail (widget != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
   g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
   g_return_val_if_fail (target_list != NULL, NULL);
 
@@ -1738,7 +1855,7 @@ gtk_drag_begin (GtkWidget         *widget,
       tmp_list = tmp_list->prev;
     }
 
-  ipc_widget = gtk_drag_get_ipc_widget ();
+  ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
   source_widgets = g_slist_prepend (source_widgets, ipc_widget);
 
   context = gdk_drag_begin (ipc_widget->window, targets);
@@ -1747,10 +1864,9 @@ gtk_drag_begin (GtkWidget         *widget,
   info = gtk_drag_get_source_info (context, TRUE);
   
   info->ipc_widget = ipc_widget;
-  gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
+  g_object_set_data (G_OBJECT (info->ipc_widget), "gtk-info", info);
 
   info->widget = gtk_widget_ref (widget);
-
   
   info->button = button;
   info->target_list = target_list;
@@ -1768,27 +1884,25 @@ gtk_drag_begin (GtkWidget         *widget,
   gtk_drag_get_event_actions (event, info->button, actions,
                              &suggested_action, &possible_actions);
 
-  info->cursor = gtk_drag_get_cursor (suggested_action);
+  info->cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget), suggested_action);
 
   /* Set cur_x, cur_y here so if the "drag_begin" signal shows
    * the drag icon, it will be in the right place
    */
   if (event && event->type == GDK_MOTION_NOTIFY)
     {
+      info->cur_screen = gtk_widget_get_screen (widget);
       info->cur_x = event->motion.x_root;
       info->cur_y = event->motion.y_root;
     }
   else 
     {
-      gint x, y;
-      gdk_window_get_pointer (GDK_ROOT_PARENT (), &x, &y, NULL);
-
-      info->cur_x = x;
-      info->cur_y = y;
+      gdk_display_get_pointer (gtk_widget_get_display (widget),
+                              &info->cur_screen, &info->cur_x, &info->cur_y, NULL);
     }
 
-  gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
-                          info->context);
+  g_signal_emit_by_name (widget, "drag_begin",
+                        info->context);
   
   if (event && event->type == GDK_MOTION_NOTIFY)
     gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
@@ -1796,16 +1910,16 @@ gtk_drag_begin (GtkWidget         *widget,
   info->start_x = info->cur_x;
   info->start_y = info->cur_y;
 
-  gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "button_release_event",
-                     GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info);
-  gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "motion_notify_event",
-                     GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info);
-  gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_press_event",
-                     GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
-  gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_release_event",
-                     GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
-  gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "selection_get",
-                     GTK_SIGNAL_FUNC (gtk_drag_selection_get), info);
+  g_signal_connect (info->ipc_widget, "button_release_event",
+                   G_CALLBACK (gtk_drag_button_release_cb), info);
+  g_signal_connect (info->ipc_widget, "motion_notify_event",
+                   G_CALLBACK (gtk_drag_motion_cb), info);
+  g_signal_connect (info->ipc_widget, "key_press_event",
+                   G_CALLBACK (gtk_drag_key_cb), info);
+  g_signal_connect (info->ipc_widget, "key_release_event",
+                   G_CALLBACK (gtk_drag_key_cb), info);
+  g_signal_connect (info->ipc_widget, "selection_get",
+                   G_CALLBACK (gtk_drag_selection_get), info);
 
   /* We use a GTK grab here to override any grabs that the widget
    * we are dragging from might have held
@@ -1818,19 +1932,14 @@ gtk_drag_begin (GtkWidget         *widget,
     {
       if (gdk_keyboard_grab (info->ipc_widget->window, FALSE, time) != 0)
        {
-         /* FIXME: This should be cleaned up... */
-         GdkEventButton ev;
-
-         ev.time = time;
-         ev.type = GDK_BUTTON_RELEASE;
-         ev.button = info->button;
-
-         gtk_drag_button_release_cb (widget, &ev, info);
-
+         gtk_drag_cancel (info, time);
          return NULL;
        }
     }
 
+  info->have_grab = TRUE;
+  info->grab_time = time;
+
   return info->context;
 }
 
@@ -1855,9 +1964,9 @@ gtk_drag_source_set (GtkWidget            *widget,
 {
   GtkDragSourceSite *site;
 
-  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
 
-  site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
+  site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
 
   gtk_widget_add_events (widget,
                         gtk_widget_get_events (widget) |
@@ -1875,16 +1984,16 @@ gtk_drag_source_set (GtkWidget            *widget,
 
       site->icon_type = GTK_IMAGE_EMPTY;
       
-      gtk_signal_connect (GTK_OBJECT (widget), "button_press_event",
-                         GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
-                         site);
-      gtk_signal_connect (GTK_OBJECT (widget), "motion_notify_event",
-                         GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
-                         site);
+      g_signal_connect (widget, "button_press_event",
+                       G_CALLBACK (gtk_drag_source_event_cb),
+                       site);
+      g_signal_connect (widget, "motion_notify_event",
+                       G_CALLBACK (gtk_drag_source_event_cb),
+                       site);
       
-      gtk_object_set_data_full (GTK_OBJECT (widget),
-                               "gtk-site-data", 
-                               site, gtk_drag_source_site_destroy);
+      g_object_set_data_full (G_OBJECT (widget),
+                             "gtk-site-data", 
+                             site, gtk_drag_source_site_destroy);
     }
 
   site->start_button_mask = start_button_mask;
@@ -1911,14 +2020,19 @@ gtk_drag_source_unset (GtkWidget        *widget)
 {
   GtkDragSourceSite *site;
 
-  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
 
-  site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
+  site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
 
   if (site)
     {
-      gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
-      gtk_object_set_data (GTK_OBJECT (widget), "gtk-site-data", NULL);
+      g_signal_handlers_disconnect_by_func (widget,
+                                           gtk_drag_source_event_cb,
+                                           site);
+      g_signal_handlers_disconnect_by_func (widget,
+                                           gtk_drag_source_event_cb,
+                                           site);
+      g_object_set_data (G_OBJECT (widget), "gtk-site-data", NULL);
     }
 }
 
@@ -1931,12 +2045,12 @@ gtk_drag_source_unset_icon (GtkDragSourceSite *site)
       break;
     case GTK_IMAGE_PIXMAP:
       if (site->icon_data.pixmap.pixmap)
-       gdk_pixmap_unref (site->icon_data.pixmap.pixmap);
+       g_object_unref (site->icon_data.pixmap.pixmap);
       if (site->icon_mask)
-       gdk_pixmap_unref (site->icon_mask);
+       g_object_unref (site->icon_mask);
       break;
     case GTK_IMAGE_PIXBUF:
-      g_object_unref (G_OBJECT (site->icon_data.pixbuf.pixbuf));
+      g_object_unref (site->icon_data.pixbuf.pixbuf);
       break;
     case GTK_IMAGE_STOCK:
       g_free (G_OBJECT (site->icon_data.stock.stock_id));
@@ -1948,7 +2062,7 @@ gtk_drag_source_unset_icon (GtkDragSourceSite *site)
   site->icon_type = GTK_IMAGE_EMPTY;
   
   if (site->colormap)
-    gdk_colormap_unref (site->colormap);
+    g_object_unref (site->colormap);
   site->colormap = NULL;
 }
 
@@ -1960,8 +2074,8 @@ gtk_drag_source_unset_icon (GtkDragSourceSite *site)
  * @mask: the transparency mask for an image.
  * 
  * Sets the icon that will be used for drags from a particular widget
- * from a pixmap/mask. GTK+ retains a reference count for the
- * arguments, and will release them when they are no longer needed.
+ * from a pixmap/mask. GTK+ retains references for the arguments, and 
+ * will release them when they are no longer needed.
  * Use gtk_drag_source_set_icon_pixbuf() instead.
  **/
 void 
@@ -1972,18 +2086,18 @@ gtk_drag_source_set_icon (GtkWidget     *widget,
 {
   GtkDragSourceSite *site;
 
-  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (GDK_IS_COLORMAP (colormap));
   g_return_if_fail (GDK_IS_PIXMAP (pixmap));
   g_return_if_fail (!mask || GDK_IS_PIXMAP (mask));
 
-  site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
+  site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
   g_return_if_fail (site != NULL);
   
-  gdk_colormap_ref (colormap);
-  gdk_pixmap_ref (pixmap);
+  g_object_ref (colormap);
+  g_object_ref (pixmap);
   if (mask)
-    gdk_pixmap_ref (mask);
+    g_object_ref (mask);
 
   gtk_drag_source_unset_icon (site);
 
@@ -2000,8 +2114,8 @@ gtk_drag_source_set_icon (GtkWidget     *widget,
  * @pixbuf: the #GdkPixbuf for the drag icon
  * 
  * Sets the icon that will be used for drags from a particular widget
- * from a #GdkPixbuf. GTK+ retains a reference count @pixbuf.
- * and will release it when it is no longer needed.
+ * from a #GdkPixbuf. GTK+ retains a reference for @pixbuf and will 
+ * release it when it is no longer needed.
  **/
 void 
 gtk_drag_source_set_icon_pixbuf (GtkWidget   *widget,
@@ -2009,13 +2123,12 @@ gtk_drag_source_set_icon_pixbuf (GtkWidget   *widget,
 {
   GtkDragSourceSite *site;
 
-  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
 
-  site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
-  g_return_if_fail (site != NULL);
-  
-  gdk_pixbuf_ref (pixbuf);
+  site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
+  g_return_if_fail (site != NULL); 
+  g_object_ref (pixbuf);
 
   gtk_drag_source_unset_icon (site);
 
@@ -2026,11 +2139,10 @@ gtk_drag_source_set_icon_pixbuf (GtkWidget   *widget,
 /**
  * gtk_drag_source_set_icon_stock:
  * @widget: a #GtkWidget
- * @stock: the ID of the stock icon to use..
- * @size: size at which to render the stock icon
+ * @stock_id: the ID of the stock icon to use
  *
- * Sets the icon that will be used for drags from a particular to
- * a stock icon. 
+ * Sets the icon that will be used for drags from a particular source
+ * to a stock icon. 
  **/
 void 
 gtk_drag_source_set_icon_stock (GtkWidget   *widget,
@@ -2038,10 +2150,10 @@ gtk_drag_source_set_icon_stock (GtkWidget   *widget,
 {
   GtkDragSourceSite *site;
 
-  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (stock_id != NULL);
 
-  site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
+  site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
   g_return_if_fail (site != NULL);
   
   gtk_drag_source_unset_icon (site);
@@ -2049,6 +2161,89 @@ gtk_drag_source_set_icon_stock (GtkWidget   *widget,
   site->icon_data.stock.stock_id = g_strdup (stock_id);
 }
 
+static void
+gtk_drag_get_icon (GtkDragSourceInfo *info,
+                  GtkWidget        **icon_window,
+                  gint              *hot_x,
+                  gint              *hot_y)
+{
+  if (get_can_change_screen (info->icon_window))
+    gtk_window_set_screen (GTK_WINDOW (info->icon_window),
+                          info->cur_screen);
+      
+  if (gtk_widget_get_screen (info->icon_window) != info->cur_screen)
+    {
+      if (!info->fallback_icon)
+       {
+         gint save_hot_x, save_hot_y;
+         gboolean save_destroy_icon;
+         GtkWidget *save_icon_window;
+         
+         /* HACK to get the appropriate icon
+          */
+         save_icon_window = info->icon_window;
+         save_hot_x = info->hot_x;
+         save_hot_y = info->hot_x;
+         save_destroy_icon = info->destroy_icon;
+
+         info->icon_window = NULL;
+         gtk_drag_set_icon_default (info->context);
+         info->fallback_icon = info->icon_window;
+         
+         info->icon_window = save_icon_window;
+         info->hot_x = save_hot_x;
+         info->hot_y = save_hot_y;
+         info->destroy_icon = save_destroy_icon;
+       }
+      
+      gtk_widget_hide (info->icon_window);
+      
+      *icon_window = info->fallback_icon;
+      gtk_window_set_screen (GTK_WINDOW (*icon_window), info->cur_screen);
+      
+      if (!default_icon_pixmap)
+       {
+         *hot_x = -2;
+         *hot_y = -2;
+       }
+      else
+       {
+         *hot_x = default_icon_hot_x;
+         *hot_y = default_icon_hot_y;
+       }
+    }
+  else
+    {
+      if (info->fallback_icon)
+       gtk_widget_hide (info->fallback_icon);
+      
+      *icon_window = info->icon_window;
+      *hot_x = info->hot_x;
+      *hot_y = info->hot_y;
+    }
+}
+
+static void
+gtk_drag_update_icon (GtkDragSourceInfo *info)
+{
+  if (info->icon_window)
+    {
+      GtkWidget *icon_window;
+      gint hot_x, hot_y;
+  
+      gtk_drag_get_icon (info, &icon_window, &hot_x, &hot_y);
+      
+      gtk_window_move (GTK_WINDOW (icon_window), 
+                      info->cur_x - hot_x, 
+                      info->cur_y - hot_y);
+      
+      if (GTK_WIDGET_VISIBLE (icon_window))
+       gdk_window_raise (icon_window->window);
+      else
+       gtk_widget_show (icon_window);
+    }
+}
+
 static void 
 gtk_drag_set_icon_window (GdkDragContext *context,
                          GtkWidget      *widget,
@@ -2058,27 +2253,18 @@ gtk_drag_set_icon_window (GdkDragContext *context,
 {
   GtkDragSourceInfo *info;
 
-  g_return_if_fail (context != NULL);
-  g_return_if_fail (widget != NULL);
-
   info = gtk_drag_get_source_info (context, FALSE);
   gtk_drag_remove_icon (info);
 
+  if (widget)
+    gtk_widget_ref (widget);
+  
   info->icon_window = widget;
   info->hot_x = hot_x;
   info->hot_y = hot_y;
-
-  if (widget)
-    {
-      gtk_widget_set_uposition (widget, 
-                               info->cur_x - info->hot_x, 
-                               info->cur_y - info->hot_y);
-      gtk_widget_ref (widget);
-      gdk_window_raise (widget->window);
-      gtk_widget_show (widget);
-    }
-
   info->destroy_icon = destroy_on_release;
+  gtk_drag_update_icon (info);
 }
 
 /**
@@ -2100,12 +2286,35 @@ gtk_drag_set_icon_widget (GdkDragContext    *context,
                          gint               hot_x,
                          gint               hot_y)
 {
-  g_return_if_fail (context != NULL);
-  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (context->is_source);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
 
   gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE);
 }
 
+static void
+icon_window_realize (GtkWidget *window,
+                    GdkPixbuf *pixbuf)
+{
+  GdkPixmap *pixmap;
+  GdkPixmap *mask;
+  
+  gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf,
+                                                 gtk_widget_get_colormap (window),
+                                                 &pixmap, &mask, 128);
+  
+  gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
+  
+  if (mask)
+    gtk_widget_shape_combine_mask (window, mask, 0, 0);
+
+  g_object_unref (G_OBJECT (pixmap));
+
+  if (mask)
+    g_object_unref (G_OBJECT (mask));
+}
+
 static void
 set_icon_stock_pixbuf (GdkDragContext    *context,
                       const gchar       *stock_id,
@@ -2115,15 +2324,19 @@ set_icon_stock_pixbuf (GdkDragContext    *context,
 {
   GtkWidget *window;
   gint width, height;
-  GdkPixmap *pixmap;
-  GdkPixmap *mask;
-  
+  GdkScreen *screen;
+
   g_return_if_fail (context != NULL);
   g_return_if_fail (pixbuf != NULL || stock_id != NULL);
   g_return_if_fail (pixbuf == NULL || stock_id == NULL);
+  
+  screen = gdk_drawable_get_screen (context->source_window);
 
-  gtk_widget_push_colormap (gdk_rgb_get_colormap ());
+  /* Push a NULL colormap to guard against gtk_widget_push_colormap() */
+  gtk_widget_push_colormap (NULL);
   window = gtk_window_new (GTK_WINDOW_POPUP);
+  gtk_window_set_screen (GTK_WINDOW (window), screen);
+  set_can_change_screen (window, TRUE);
   gtk_widget_pop_colormap ();
 
   gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
@@ -2142,25 +2355,22 @@ set_icon_stock_pixbuf (GdkDragContext    *context,
        }
 
     }
+  else
+    g_object_ref (pixbuf);
   
   width = gdk_pixbuf_get_width (pixbuf);
   height = gdk_pixbuf_get_width (pixbuf);
 
-  gtk_widget_set_usize (window,
-                       gdk_pixbuf_get_width (pixbuf),
-                       gdk_pixbuf_get_height (pixbuf));
-  gtk_widget_realize (window);
-
-  gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &mask, 128);
-  
-  gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
-  
-  if (mask)
-    gtk_widget_shape_combine_mask (window, mask, 0, 0);
-
-  g_object_unref (G_OBJECT (pixmap));
-  g_object_unref (G_OBJECT (mask));
+  gtk_widget_set_size_request (window,
+                              gdk_pixbuf_get_width (pixbuf),
+                              gdk_pixbuf_get_height (pixbuf));
 
+  g_signal_connect_closure (window, "realize",
+                           g_cclosure_new (G_CALLBACK (icon_window_realize),
+                                           pixbuf,
+                                           (GClosureNotify)g_object_unref),
+                           FALSE);
+                   
   gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
 }
 
@@ -2181,16 +2391,17 @@ gtk_drag_set_icon_pixbuf  (GdkDragContext *context,
                           gint            hot_y)
 {
   g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (context->is_source);
   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
   
   set_icon_stock_pixbuf (context, NULL, pixbuf, hot_x, hot_y);
 }
 
 /**
- * gtk_drag_set_icon_pixbuf:
+ * gtk_drag_set_icon_stock:
  * @context: the context for a drag. (This must be called 
  *            with a  context for the source side of a drag)
- * @stock: the ID of the stock icon to use for the drag.
+ * @stock_id: the ID of the stock icon to use for the drag.
  * @hot_x: the X offset within the icon of the hotspot.
  * @hot_y: the Y offset within the icon of the hotspot.
  * 
@@ -2203,6 +2414,7 @@ gtk_drag_set_icon_stock  (GdkDragContext *context,
                          gint            hot_y)
 {
   g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (context->is_source);
   g_return_if_fail (stock_id != NULL);
   
   set_icon_stock_pixbuf (context, stock_id, NULL, hot_x, hot_y);
@@ -2218,8 +2430,8 @@ gtk_drag_set_icon_stock  (GdkDragContext *context,
  * @hot_x: the X offset within @pixmap of the hotspot.
  * @hot_y: the Y offset within @pixmap of the hotspot.
  * 
- * Sets @pixmap as the icon for a given drag. GTK+ retains a
- * reference count for the arguments, and will release them when
+ * Sets @pixmap as the icon for a given drag. GTK+ retains
+ * references for the arguments, and will release them when
  * they are no longer needed. In general, gtk_drag_set_icon_pixbuf()
  * will be more convenient to use.
  **/
@@ -2232,23 +2444,33 @@ gtk_drag_set_icon_pixmap (GdkDragContext    *context,
                          gint               hot_y)
 {
   GtkWidget *window;
+  GdkScreen *screen;
   gint width, height;
       
-  g_return_if_fail (context != NULL);
-  g_return_if_fail (colormap != NULL);
-  g_return_if_fail (pixmap != NULL);
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (context->is_source);
+  g_return_if_fail (GDK_IS_COLORMAP (colormap));
+  g_return_if_fail (GDK_IS_PIXMAP (pixmap));
+  g_return_if_fail (!mask || GDK_IS_PIXMAP (mask));
 
-  gdk_window_get_size (pixmap, &width, &height);
+  screen = gdk_colormap_get_screen (colormap);
+  
+  g_return_if_fail (gdk_drawable_get_screen (pixmap) == screen);
+  g_return_if_fail (!mask || gdk_drawable_get_screen (mask) == screen);
+  
+  gdk_drawable_get_size (pixmap, &width, &height);
 
   gtk_widget_push_colormap (colormap);
 
   window = gtk_window_new (GTK_WINDOW_POPUP);
+  gtk_window_set_screen (GTK_WINDOW (window), screen);
+  set_can_change_screen (window, FALSE);
   gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
   gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
 
   gtk_widget_pop_colormap ();
 
-  gtk_widget_set_usize (window, width, height);
+  gtk_widget_set_size_request (window, width, height);
   gtk_widget_realize (window);
 
   gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
@@ -2270,7 +2492,8 @@ gtk_drag_set_icon_pixmap (GdkDragContext    *context,
 void 
 gtk_drag_set_icon_default (GdkDragContext    *context)
 {
-  g_return_if_fail (context != NULL);
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (context->is_source);
 
   if (!default_icon_pixmap)
     gtk_drag_set_icon_stock (context, GTK_STOCK_DND, -2, -2);
@@ -2291,10 +2514,10 @@ gtk_drag_set_icon_default (GdkDragContext    *context)
  * @hot_x: The X offset within @widget of the hotspot.
  * @hot_y: The Y offset within @widget of the hotspot.
  * 
- * Changes the default drag icon. GTK+ retains a reference count for the
+ * Changes the default drag icon. GTK+ retains references for the
  * arguments, and will release them when they are no longer needed.
  * This function is obsolete. The default icon should now be changed
- * via the stock system by changing the stock pixbuf for GTK_STOCK_DND.
+ * via the stock system by changing the stock pixbuf for #GTK_STOCK_DND.
  **/
 void 
 gtk_drag_set_default_icon (GdkColormap   *colormap,
@@ -2303,25 +2526,26 @@ gtk_drag_set_default_icon (GdkColormap   *colormap,
                           gint           hot_x,
                           gint           hot_y)
 {
-  g_return_if_fail (colormap != NULL);
-  g_return_if_fail (pixmap != NULL);
+  g_return_if_fail (GDK_IS_COLORMAP (colormap));
+  g_return_if_fail (GDK_IS_PIXMAP (pixmap));
+  g_return_if_fail (!mask || GDK_IS_PIXMAP (mask));
   
   if (default_icon_colormap)
-    gdk_colormap_unref (default_icon_colormap);
+    g_object_unref (default_icon_colormap);
   if (default_icon_pixmap)
-    gdk_pixmap_unref (default_icon_pixmap);
+    g_object_unref (default_icon_pixmap);
   if (default_icon_mask)
-    gdk_pixmap_unref (default_icon_mask);
+    g_object_unref (default_icon_mask);
 
   default_icon_colormap = colormap;
-  gdk_colormap_ref (colormap);
+  g_object_ref (colormap);
   
   default_icon_pixmap = pixmap;
-  gdk_pixmap_ref (pixmap);
+  g_object_ref (pixmap);
 
   default_icon_mask = mask;
   if (mask)
-    gdk_pixmap_ref (mask);
+    g_object_ref (mask);
   
   default_icon_hot_x = hot_x;
   default_icon_hot_y = hot_y;
@@ -2383,9 +2607,10 @@ _gtk_drag_source_handle_event (GtkWidget *widget,
                  }
              }
          }
-       else
+       else if (info->have_grab)
          {
-           cursor = gtk_drag_get_cursor (event->dnd.context->action);
+           cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget),
+                                         event->dnd.context->action);
            if (info->cursor != cursor)
              {
                gdk_pointer_grab (widget->window, FALSE,
@@ -2393,14 +2618,14 @@ _gtk_drag_source_handle_event (GtkWidget *widget,
                                  GDK_POINTER_MOTION_HINT_MASK |
                                  GDK_BUTTON_RELEASE_MASK,
                                  NULL,
-                                 cursor, event->dnd.time);
+                                 cursor, info->grab_time);
                info->cursor = cursor;
              }
            
            if (info->last_event)
              {
                gtk_drag_update (info,
-                                info->cur_x, info->cur_y,
+                                info->cur_screen, info->cur_x, info->cur_y,
                                 info->last_event);
                info->last_event = NULL;
              }
@@ -2435,12 +2660,15 @@ gtk_drag_source_check_selection (GtkDragSourceInfo *info,
   tmp_list = info->selections;
   while (tmp_list)
     {
-      if (GPOINTER_TO_UINT (tmp_list->data) == selection)
+      if (GDK_POINTER_TO_ATOM (tmp_list->data) == selection)
        return;
       tmp_list = tmp_list->next;
     }
 
-  gtk_selection_owner_set (info->ipc_widget, selection, time);
+  gtk_selection_owner_set_for_display (gtk_widget_get_display (info->widget),
+                                      info->ipc_widget,
+                                      selection,
+                                      time);
   info->selections = g_list_prepend (info->selections,
                                     GUINT_TO_POINTER (selection));
 
@@ -2513,11 +2741,9 @@ gtk_drag_drop_finished (GtkDragSourceInfo *info,
          anim->n_steps = MAX (info->cur_x - info->start_x,
                               info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
          anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
-         if (info->icon_window)
-           {
-             gtk_widget_show (info->icon_window);
-             gdk_window_raise (info->icon_window->window);
-           }
+
+         info->cur_screen = gtk_widget_get_screen (info->widget);
+         gtk_drag_update_icon (info);
          
          /* Mark the context as dead, so if the destination decides
           * to respond really late, we still are OK.
@@ -2532,12 +2758,15 @@ static void
 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
                                    guint32            time)
 {
+  GdkDisplay *display = gtk_widget_get_display (info->widget);
   GList *tmp_list = info->selections;
+  
   while (tmp_list)
     {
-      GdkAtom selection = GPOINTER_TO_UINT (tmp_list->data);
-      if (gdk_selection_owner_get (selection) == info->ipc_widget->window)
-       gtk_selection_owner_set (NULL, selection, time);
+      GdkAtom selection = GDK_POINTER_TO_ATOM (tmp_list->data);
+      if (gdk_selection_owner_get_for_display (display, selection) == info->ipc_widget->window)
+       gtk_selection_owner_set_for_display (display, NULL, selection, time);
+
       tmp_list = tmp_list->next;
     }
 
@@ -2575,10 +2804,10 @@ gtk_drag_drop (GtkDragSourceInfo *info,
              selection_data.data = NULL;
              selection_data.length = -1;
              
-             gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
-                                      info->context, &selection_data,
-                                      pair->info, 
-                                      time);
+             g_signal_emit_by_name (info->widget, "drag_data_get",
+                                    info->context, &selection_data,
+                                    pair->info,
+                                    time);
              
              /* FIXME: Should we check for length >= 0 here? */
              gtk_drag_drop_finished (info, TRUE, time);
@@ -2727,9 +2956,9 @@ gtk_drag_selection_get (GtkWidget        *widget,
   switch (sel_info)
     {
     case TARGET_DELETE:
-      gtk_signal_emit_by_name (GTK_OBJECT (info->widget), 
-                              "drag_data_delete", 
-                              info->context);
+      g_signal_emit_by_name (info->widget,
+                            "drag_data_delete", 
+                            info->context);
       gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
       break;
     case TARGET_MOTIF_SUCCESS:
@@ -2760,11 +2989,11 @@ gtk_drag_selection_get (GtkWidget        *widget,
                                    selection_data->target, 
                                    &target_info))
            {
-             gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
-                                      info->context, 
-                                      selection_data, 
-                                      target_info, 
-                                      time);
+             g_signal_emit_by_name (info->widget, "drag_data_get",
+                                    info->context,
+                                    selection_data,
+                                    target_info,
+                                    time);
            }
        }
       break;
@@ -2794,9 +3023,16 @@ gtk_drag_anim_timeout (gpointer data)
       y = (anim->info->start_y * (anim->step + 1) +
           anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
       if (anim->info->icon_window)
-       gtk_widget_set_uposition (anim->info->icon_window, 
-                                 x - anim->info->hot_x, 
-                                 y - anim->info->hot_y);
+       {
+         GtkWidget *icon_window;
+         gint hot_x, hot_y;
+         
+         gtk_drag_get_icon (anim->info, &icon_window, &hot_x, &hot_y);
+         
+         gtk_window_move (GTK_WINDOW (icon_window), 
+                          x - hot_x, 
+                          y - hot_y);
+       }
   
       anim->step++;
 
@@ -2817,7 +3053,13 @@ gtk_drag_remove_icon (GtkDragSourceInfo *info)
       if (info->destroy_icon)
        gtk_widget_destroy (info->icon_window);
 
-      gtk_widget_unref (info->icon_window);
+      if (info->fallback_icon)
+       {
+         gtk_widget_destroy (info->fallback_icon);
+         info->fallback_icon = NULL;
+       }
+
+      g_object_unref (info->icon_window);
       info->icon_window = NULL;
     }
 }
@@ -2828,22 +3070,35 @@ gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
   gtk_drag_remove_icon (info);
 
   if (!info->proxy_dest)
-    gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end", 
-                            info->context);
+    g_signal_emit_by_name (info->widget, "drag_end", 
+                          info->context);
 
   if (info->widget)
-    gtk_widget_unref (info->widget);
+    g_object_unref (info->widget);
+
+
+  g_signal_handlers_disconnect_by_func (info->ipc_widget,
+                                       gtk_drag_button_release_cb,
+                                       info);
+  g_signal_handlers_disconnect_by_func (info->ipc_widget,
+                                       gtk_drag_motion_cb,
+                                       info);
+  g_signal_handlers_disconnect_by_func (info->ipc_widget,
+                                       gtk_drag_key_cb,
+                                       info);
+  g_signal_handlers_disconnect_by_func (info->ipc_widget,
+                                       gtk_drag_selection_get,
+                                       info);
 
-  gtk_signal_disconnect_by_data (GTK_OBJECT (info->ipc_widget), info);
   gtk_selection_remove_all (info->ipc_widget);
-  gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", NULL);
+  g_object_set_data (G_OBJECT (info->ipc_widget), "gtk-info", NULL);
   source_widgets = g_slist_remove (source_widgets, info->ipc_widget);
   gtk_drag_release_ipc_widget (info->ipc_widget);
 
   gtk_target_list_unref (info->target_list);
 
   gtk_drag_clear_source_info (info->context);
-  gdk_drag_context_unref (info->context);
+  g_object_unref (info->context);
 
   if (info->drop_timeout)
     gtk_timeout_remove (info->drop_timeout);
@@ -2864,13 +3119,13 @@ gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
 
 static void
 gtk_drag_update (GtkDragSourceInfo *info,
+                GdkScreen         *screen,
                 gint               x_root,
                 gint               y_root,
                 GdkEvent          *event)
 {
   GdkDragAction action;
   GdkDragAction possible_actions;
-  GdkWindow *window = NULL;
   GdkWindow *dest_window;
   GdkDragProtocol protocol;
   GdkAtom selection;
@@ -2880,21 +3135,15 @@ gtk_drag_update (GtkDragSourceInfo *info,
                              info->button, 
                              info->possible_actions,
                              &action, &possible_actions);
+  info->cur_screen = screen;
   info->cur_x = x_root;
   info->cur_y = y_root;
 
-  if (info->icon_window)
-    {
-      gdk_window_raise (info->icon_window->window);
-      gtk_widget_set_uposition (info->icon_window, 
-                               info->cur_x - info->hot_x, 
-                               info->cur_y - info->hot_y);
-      window = info->icon_window->window;
-    }
-  
-  gdk_drag_find_window (info->context,
-                       window, x_root, y_root,
-                       &dest_window, &protocol);
+  gtk_drag_update_icon (info);
+  gdk_drag_find_window_for_screen (info->context,
+                                  info->icon_window ? info->icon_window->window : NULL,
+                                  screen, x_root, y_root,
+                                  &dest_window, &protocol);
   
   if (gdk_drag_motion (info->context, dest_window, protocol,
                       x_root, y_root, action, 
@@ -2918,7 +3167,7 @@ gtk_drag_update (GtkDragSourceInfo *info,
     }
   
   if (dest_window)
-    gdk_window_unref (dest_window);
+    g_object_unref (dest_window);
 
   selection = gdk_drag_get_selection (info->context);
   if (selection)
@@ -2930,28 +3179,33 @@ gtk_drag_update (GtkDragSourceInfo *info,
  *     Called when the user finishes to drag, either by
  *     releasing the mouse, or by pressing Esc.
  *   arguments:
- *     widget: GtkInvisible widget for this drag
- *     info: 
+ *     info: Source info for the drag
+ *     time: Timestamp for ending the drag
  *   results:
  *************************************************************/
 
 static void
 gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
 {
-  GdkEvent send_event;
+  GdkEvent *send_event;
   GtkWidget *source_widget = info->widget;
+  GdkDisplay *display = gtk_widget_get_display (source_widget);
 
-  gdk_pointer_ungrab (time);
-  gdk_keyboard_ungrab (time);
-
+  info->have_grab = FALSE;
+  
+  gdk_display_pointer_ungrab (display, time);
+  gdk_display_keyboard_ungrab (display, time);
   gtk_grab_remove (info->ipc_widget);
 
-  gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget), 
-                                GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
-                                info);
-  gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget), 
-                                GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
-                                info);
+  g_signal_handlers_disconnect_by_func (info->ipc_widget,
+                                       gtk_drag_button_release_cb,
+                                       info);
+  g_signal_handlers_disconnect_by_func (info->ipc_widget,
+                                       gtk_drag_motion_cb,
+                                       info);
+  g_signal_handlers_disconnect_by_func (info->ipc_widget,
+                                       gtk_drag_key_cb,
+                                       info);
 
   /* Send on a release pair to the the original 
    * widget to convince it to release its grab. We need to
@@ -2960,20 +3214,39 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
    * expect propagation.
    */
 
-  send_event.button.type = GDK_BUTTON_RELEASE;
-  send_event.button.window = GDK_ROOT_PARENT ();
-  send_event.button.send_event = TRUE;
-  send_event.button.time = time;
-  send_event.button.x = 0;
-  send_event.button.y = 0;
-  send_event.button.axes = NULL;
-  send_event.button.state = 0;
-  send_event.button.button = info->button;
-  send_event.button.device = gdk_device_get_core_pointer ();
-  send_event.button.x_root = 0;
-  send_event.button.y_root = 0;
+  send_event = gdk_event_new (GDK_BUTTON_RELEASE);
+  send_event->button.window = g_object_ref (gtk_widget_get_root_window (source_widget));
+  send_event->button.send_event = TRUE;
+  send_event->button.time = time;
+  send_event->button.x = 0;
+  send_event->button.y = 0;
+  send_event->button.axes = NULL;
+  send_event->button.state = 0;
+  send_event->button.button = info->button;
+  send_event->button.device = gdk_display_get_core_pointer (display);
+  send_event->button.x_root = 0;
+  send_event->button.y_root = 0;
+
+  gtk_propagate_event (source_widget, send_event);
+  gdk_event_free (send_event);
+}
 
-  gtk_propagate_event (source_widget, &send_event);
+/*************************************************************
+ * gtk_drag_cancel:
+ *    Called on cancellation of a drag, either by the user
+ *    or programmatically.
+ *   arguments:
+ *     info: Source info for the drag
+ *     time: Timestamp for ending the drag
+ *   results:
+ *************************************************************/
+
+static void
+gtk_drag_cancel (GtkDragSourceInfo *info, guint32 time)
+{
+  gtk_drag_end (info, time);
+  gdk_drag_abort (info->context, time);
+  gtk_drag_drop_finished (info, FALSE, time);
 }
 
 /*************************************************************
@@ -2990,16 +3263,21 @@ gtk_drag_motion_cb (GtkWidget      *widget,
                    gpointer        data)
 {
   GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
+  GdkScreen *screen;
   gint x_root, y_root;
 
   if (event->is_hint)
     {
-      gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL);
+      GdkDisplay *display = gtk_widget_get_display (widget);
+      
+      gdk_display_get_pointer (display, &screen, &x_root, &y_root, NULL);
       event->x_root = x_root;
       event->y_root = y_root;
     }
+  else
+    screen = gdk_event_get_screen ((GdkEvent *)event);
 
-  gtk_drag_update (info, event->x_root, event->y_root, (GdkEvent *)event);
+  gtk_drag_update (info, screen, event->x_root, event->y_root, (GdkEvent *)event);
 
   return TRUE;
 }
@@ -3019,14 +3297,13 @@ gtk_drag_key_cb (GtkWidget         *widget,
 {
   GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
   GdkModifierType state;
+  GdkWindow *root_window;
   
   if (event->type == GDK_KEY_PRESS)
     {
       if (event->keyval == GDK_Escape)
        {
-         gtk_drag_end (info, event->time);
-         gdk_drag_abort (info->context, event->time);
-         gtk_drag_drop_finished (info, FALSE, event->time);
+         gtk_drag_cancel (info, event->time);
 
          return TRUE;
        }
@@ -3038,10 +3315,11 @@ gtk_drag_key_cb (GtkWidget         *widget,
    * to query it here. We could use XGetModifierMapping, but
    * that would be overkill.
    */
-  gdk_window_get_pointer (GDK_ROOT_PARENT(), NULL, NULL, &state);
+  root_window = gtk_widget_get_root_window (widget);
+  gdk_window_get_pointer (root_window, NULL, NULL, &state);
 
   event->state = state;
-  gtk_drag_update (info, info->cur_x, info->cur_y, (GdkEvent *)event);
+  gtk_drag_update (info, info->cur_screen, info->cur_x, info->cur_y, (GdkEvent *)event);
 
   return TRUE;
 }
@@ -3064,16 +3342,14 @@ gtk_drag_button_release_cb (GtkWidget      *widget,
   if (event->button != info->button)
     return FALSE;
 
-  gtk_drag_end (info, event->time);
-
   if ((info->context->action != 0) && (info->context->dest_window != NULL))
     {
+      gtk_drag_end (info, event->time);
       gtk_drag_drop (info, event->time);
     }
   else
     {
-      gdk_drag_abort (info->context, event->time);
-      gtk_drag_drop_finished (info, FALSE, event->time);
+      gtk_drag_cancel (info, event->time);
     }
 
   return TRUE;
@@ -3106,11 +3382,11 @@ gtk_drag_abort_timeout (gpointer data)
  * @current_x: current X coordinate
  * @current_y: current Y coordinate
  * 
- * Checks to see if a mouse drag starting at (start_x, start_y) and ending
- * at (current_x, current_y) has passed the GTK drag threshhold, and thus
+ * Checks to see if a mouse drag starting at (@start_x, @start_y) and ending
+ * at (@current_x, @current_y) has passed the GTK+ drag threshhold, and thus
  * should trigger the beginning of a drag-and-drop operation.
  *
- * Return Value: If the drag threshold has been passed.
+ * Return Value: %TRUE if the drag threshold has been passed.
  **/
 gboolean
 gtk_drag_check_threshold (GtkWidget *widget,
@@ -3119,8 +3395,14 @@ gtk_drag_check_threshold (GtkWidget *widget,
                          gint       current_x,
                          gint       current_y)
 {
-#define DRAG_THRESHOLD 8
+  gint drag_threshold;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
 
-  return (ABS (current_x - start_x) > DRAG_THRESHOLD ||
-         ABS (current_y - start_y) > DRAG_THRESHOLD);
+  g_object_get (gtk_widget_get_settings (widget),
+               "gtk-dnd-drag-threshold", &drag_threshold,
+               NULL);
+  
+  return (ABS (current_x - start_x) > drag_threshold ||
+         ABS (current_y - start_y) > drag_threshold);
 }