]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkdnd.c
Skip insensitive widgets. (#84061)
[~andy/gtk] / gtk / gtkdnd.c
index 03aff7f691594a5cd6a53d186db2b81c93571f17..35281f065e9f474b94cb933a10619478c9ef821c 100644 (file)
 
 #include "gdkconfig.h"
 
-#if defined (GDK_WINDOWING_X11)
-#include "x11/gdkx.h"
-#elif defined (GDK_WINDOWING_WIN32)
-#include "win32/gdkwin32.h"
-#elif defined(GDK_WINDOWING_FB)
-#include "linux-fb/gdkfb.h"
-#elif defined (GDK_WINDOWING_NANOX)
-#include "nanox/gdkprivate-nanox.h"
-#endif
-
 #include "gdk/gdkkeysyms.h"
 
 #include "gtkdnd.h"
+#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;
@@ -67,9 +57,18 @@ struct _GtkDragSourceSite
   GdkModifierType    start_button_mask;
   GtkTargetList     *target_list;        /* Targets for drag data */
   GdkDragAction      actions;            /* Possible actions */
+
+  /* Drag icon */
+  GtkImageType icon_type;
+  union
+  {
+    GtkImagePixmapData pixmap;
+    GtkImagePixbufData pixbuf;
+    GtkImageStockData stock;
+  } icon_data;
+  GdkBitmap *icon_mask;
+
   GdkColormap       *colormap;          /* Colormap for drag icon */
-  GdkPixmap         *pixmap;             /* Icon for drag data */
-  GdkBitmap         *mask;
 
   /* Stored button press information to detect drag beginning */
   gint               state;
@@ -83,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 */
@@ -93,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 
@@ -179,43 +183,47 @@ 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 void          gtk_drag_highlight_paint    (GtkWidget      *widget);
 static gboolean      gtk_drag_highlight_expose   (GtkWidget      *widget,
                                                  GdkEventExpose *event,
                                                  gpointer        data);
 
-
-static GdkAtom   gtk_drag_dest_find_target    (GtkWidget          *widget,
-                                              GtkDragDestSite    *site,
-                                              GdkDragContext     *context);
-static void      gtk_drag_selection_received  (GtkWidget          *widget,
-                                              GtkSelectionData   *selection_data,
-                                              guint32             time,
-                                              gpointer            data);
-static void      gtk_drag_find_widget         (GtkWidget          *widget,
-                                              GtkDragFindData    *data);
-static void      gtk_drag_proxy_begin         (GtkWidget          *widget,
-                                              GtkDragDestInfo    *dest_info);
-static void      gtk_drag_dest_info_destroy   (gpointer            data);
-static void      gtk_drag_dest_realized       (GtkWidget          *widget);
-static void      gtk_drag_dest_site_destroy   (gpointer            data);
-static void      gtk_drag_dest_leave          (GtkWidget          *widget,
-                                              GdkDragContext     *context,
-                                              guint               time);
-static gboolean  gtk_drag_dest_motion         (GtkWidget         *widget,
-                                              GdkDragContext     *context,
-                                              gint                x,
-                                              gint                y,
-                                              guint               time);
-static gboolean  gtk_drag_dest_drop           (GtkWidget         *widget,
-                                              GdkDragContext     *context,
-                                              gint                x,
-                                              gint                y,
-                                              guint               time);
+static void     gtk_drag_selection_received     (GtkWidget        *widget,
+                                                GtkSelectionData *selection_data,
+                                                guint32           time,
+                                                gpointer          data);
+static void     gtk_drag_find_widget            (GtkWidget        *widget,
+                                                GtkDragFindData  *data);
+static void     gtk_drag_proxy_begin            (GtkWidget        *widget,
+                                                GtkDragDestInfo  *dest_info,
+                                                guint32           time);
+static void     gtk_drag_dest_realized          (GtkWidget        *widget);
+static void     gtk_drag_dest_hierarchy_changed (GtkWidget        *widget,
+                                                GtkWidget        *previous_toplevel);
+static void     gtk_drag_dest_site_destroy      (gpointer          data);
+static void     gtk_drag_dest_leave             (GtkWidget        *widget,
+                                                GdkDragContext   *context,
+                                                guint             time);
+static gboolean gtk_drag_dest_motion            (GtkWidget        *widget,
+                                                GdkDragContext   *context,
+                                                gint              x,
+                                                gint              y,
+                                                guint             time);
+static gboolean gtk_drag_dest_drop              (GtkWidget        *widget,
+                                                GdkDragContext   *context,
+                                                gint              x,
+                                                gint              y,
+                                                guint             time);
+
+static GtkDragDestInfo *  gtk_drag_get_dest_info     (GdkDragContext *context,
+                                                     gboolean        create);
+static GtkDragSourceInfo *gtk_drag_get_source_info   (GdkDragContext *context,
+                                                     gboolean        create);
+static void               gtk_drag_clear_source_info (GdkDragContext *context);
 
 static void gtk_drag_source_check_selection    (GtkDragSourceInfo *info, 
                                                GdkAtom            selection,
@@ -227,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,
@@ -239,8 +249,9 @@ static void gtk_drag_selection_get             (GtkWidget         *widget,
                                                gpointer           data);
 static gint gtk_drag_anim_timeout              (gpointer           data);
 static void gtk_drag_remove_icon               (GtkDragSourceInfo *info);
-static void gtk_drag_source_info_destroy       (gpointer           data);
+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);
@@ -334,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 },
@@ -348,49 +359,27 @@ static struct {
 
 static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[0]);
 
-/* XPM */
-static const char *drag_default_xpm[] = {
-"32 32 3 1",
-"      c None",
-".     c #000000",
-"+     c #FFFFFF",
-"                                ",
-"                                ",
-"                ..              ",
-"              ..+.              ",
-"             ..++..             ",
-"           ...++++.             ",
-"         ...++++++..            ",
-"       ...+++++++++.            ",
-"     ...+++++++++++..           ",
-"    ..+.++++++++++++..          ",
-"     .++.++++++++++++..         ",
-"     .+++.++++++++++++..        ",
-"     .++++.++++++++++++.        ",
-"     .+++.+++++++++++++..       ",
-"     .++.+++++++++++++++..      ",
-"     .+.+++++++++++++++++..     ",
-"     ..+++++++++++++++++++..    ",
-"     ..++++++++++++++++++++.    ",
-"     .++++++++++++++++++++..    ",
-"     ..+++++++++++++++++..      ",
-"      .++++++++++++++++..       ",
-"      ..+++++++++++++...        ",
-"       .++++++++++++..          ",
-"       ..+++++++++..            ",
-"        .++++++++..             ",
-"        ..++++++..              ",
-"         .+++++..               ",
-"          .++..                 ",
-"           ...                  ",
-"           ..                   ",
-"                                ",
-"                                "};
-
 /*********************
  * 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
@@ -401,20 +390,25 @@ static const char *drag_default_xpm[] = {
  *************************************************************/
 
 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);
     }
 
@@ -432,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
@@ -508,7 +508,7 @@ gtk_drag_get_event_actions (GdkEvent *event,
        default:
          break;
        }
-      
+
       if ((button == 2 || button == 3) && (actions & GDK_ACTION_ASK))
        {
          *suggested_action = GDK_ACTION_ASK;
@@ -573,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;
@@ -629,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),
@@ -665,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)
     {
@@ -673,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;
        }
@@ -703,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)
     {
@@ -719,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),
@@ -734,25 +745,27 @@ gtk_drag_finish (GdkDragContext *context,
                             time);
     }
   
-  if (!del)
+  if (!(success && del))
     gdk_drop_finish (context, success, time);
 }
 
 /*************************************************************
- * gtk_drag_highlight_paint:
- *     Paint a highlight indicating drag status onto the widget.
+ * gtk_drag_highlight_expose:
+ *     Callback for expose_event for highlighted widgets.
  *   arguments:
  *     widget:
+ *     event:
+ *     data:
  *   results:
  *************************************************************/
 
-static void 
-gtk_drag_highlight_paint (GtkWidget  *widget)
+static gboolean
+gtk_drag_highlight_expose (GtkWidget      *widget,
+                          GdkEventExpose *event,
+                          gpointer        data)
 {
   gint x, y, width, height;
-
-  g_return_if_fail (widget != NULL);
-
+  
   if (GTK_WIDGET_DRAWABLE (widget))
     {
       if (GTK_WIDGET_NO_WINDOW (widget))
@@ -766,37 +779,21 @@ gtk_drag_highlight_paint (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,
                          FALSE,
                          x, y, width - 1, height - 1);
     }
-}
 
-/*************************************************************
- * gtk_drag_highlight_expose:
- *     Callback for expose_event for highlighted widgets.
- *   arguments:
- *     widget:
- *     event:
- *     data:
- *   results:
- *************************************************************/
-
-static gboolean
-gtk_drag_highlight_expose (GtkWidget      *widget,
-                          GdkEventExpose *event,
-                          gpointer        data)
-{
-  gtk_drag_highlight_paint (widget);
-  return TRUE;
+  return FALSE;
 }
 
 /*************************************************************
@@ -810,12 +807,11 @@ gtk_drag_highlight_expose (GtkWidget      *widget,
 void 
 gtk_drag_highlight (GtkWidget  *widget)
 {
-  gtk_signal_connect_after (GTK_OBJECT (widget), "draw",
-                           GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
-                           NULL);
-  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);
 }
@@ -831,16 +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_paint),
-                                NULL);
-  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
@@ -852,18 +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);
+  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);
 }
                            
 
@@ -888,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);
 
@@ -898,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);
 }
@@ -926,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);
 
@@ -936,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;
@@ -955,13 +958,69 @@ 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);
 }
 
+/**
+ * gtk_drag_dest_get_target_list:
+ * @widget: a #GtkWidget
+ * 
+ * Returns the list of targets this widget can accept from
+ * drag-and-drop.
+ * 
+ * Return value: the #GtkTargetList, or %NULL if none
+ **/
+GtkTargetList*
+gtk_drag_dest_get_target_list (GtkWidget *widget)
+{
+  GtkDragDestSite *site;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+  
+  site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
+
+  return site ? site->target_list : NULL;  
+}
+
+/**
+ * gtk_drag_dest_set_target_list:
+ * @widget: a #GtkWidget that's a drag destination
+ * @target_list: list of droppable targets, or %NULL for none
+ * 
+ * Sets the target types that this widget can accept from drag-and-drop.
+ * The widget must first be made into a drag destination with
+ * gtk_drag_dest_set().
+ **/
+void
+gtk_drag_dest_set_target_list (GtkWidget      *widget,
+                               GtkTargetList  *target_list)
+{
+  GtkDragDestSite *site;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  
+  site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
+  
+  if (site == NULL)
+    {
+      g_warning ("can't set a target list on a widget until you've called gtk_drag_dest_set() to make the widget into a drag destination");
+      return;
+    }
+
+  if (target_list)
+    gtk_target_list_ref (target_list);
+  
+  if (site->target_list)
+    gtk_target_list_unref (site->target_list);
+
+  site->target_list = target_list;
+}
+
+
 /*************************************************************
- * gtk_drag_dest_handle_event:
+ * _gtk_drag_dest_handle_event:
  *     Called from widget event handling code on Drag events
  *     for destinations.
  *
@@ -972,7 +1031,7 @@ gtk_drag_dest_unset (GtkWidget *widget)
  *************************************************************/
 
 void
-gtk_drag_dest_handle_event (GtkWidget *toplevel,
+_gtk_drag_dest_handle_event (GtkWidget *toplevel,
                            GdkEvent  *event)
 {
   GtkDragDestInfo *info;
@@ -983,21 +1042,7 @@ gtk_drag_dest_handle_event (GtkWidget *toplevel,
 
   context = event->dnd.context;
 
-  info = g_dataset_get_data (context, "gtk-info");
-  if (!info)
-    {
-      info = g_new (GtkDragDestInfo, 1);
-      info->widget = NULL;
-      info->context = event->dnd.context;
-      info->proxy_source = NULL;
-      info->proxy_data = NULL;
-      info->dropped = FALSE;
-      info->proxy_drop_wait = FALSE;
-      g_object_set_qdata_full (G_OBJECT (context),
-                              g_quark_from_static_string ("gtk-info"),
-                              info,
-                              gtk_drag_dest_info_destroy);
-    }
+  info = gtk_drag_get_dest_info (context, TRUE);
 
   /* Find the widget for the event */
   switch (event->type)
@@ -1073,25 +1118,46 @@ gtk_drag_dest_handle_event (GtkWidget *toplevel,
     }
 }
 
-/*************************************************************
+/**
  * gtk_drag_dest_find_target:
- *     Decide on a target for the drag.
- *   arguments:
- *     site:
- *     context:
- *   results:
- *************************************************************/
-
-static GdkAtom
-gtk_drag_dest_find_target (GtkWidget       *widget,
-                          GtkDragDestSite *site,
-                          GdkDragContext  *context)
+ * @widget: drag destination widget
+ * @context: drag context
+ * @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
+ * returning %GDK_NONE. @dest_target_list should usually be the return
+ * value from gtk_drag_dest_get_target_list(), but some widgets may
+ * have different valid targets for different parts of the widget; in
+ * that case, they will have to implement a drag_motion handler that
+ * passes the correct target list to this function.
+ * 
+ * Return value: first target that the source offers and the dest can accept, or %GDK_NONE
+ **/
+GdkAtom
+gtk_drag_dest_find_target (GtkWidget      *widget,
+                           GdkDragContext *context,
+                           GtkTargetList  *target_list)
 {
   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);
 
-  tmp_target = site->target_list->list;
+  if (target_list == NULL)
+    target_list = gtk_drag_dest_get_target_list (widget);
+  
+  if (target_list == NULL)
+    return GDK_NONE;
+  
+  tmp_target = target_list->list;
   while (tmp_target)
     {
       GtkTargetPair *pair = tmp_target->data;
@@ -1126,8 +1192,8 @@ gtk_drag_selection_received (GtkWidget        *widget,
 
   drop_widget = data;
 
-  context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
-  info = g_object_get_qdata (G_OBJECT (context), g_quark_from_static_string ("gtk-info"));
+  context = g_object_get_data (G_OBJECT (widget), "drag-context");
+  info = gtk_drag_get_dest_info (context, FALSE);
 
   if (info->proxy_data && 
       info->proxy_data->target == selection_data->target)
@@ -1154,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)
        {
@@ -1166,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)
@@ -1190,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 
@@ -1217,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
@@ -1230,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;
@@ -1268,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 ||
@@ -1281,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;
        }
@@ -1299,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)
@@ -1321,38 +1424,45 @@ gtk_drag_find_widget (GtkWidget       *widget,
 
 static void
 gtk_drag_proxy_begin (GtkWidget       *widget, 
-                     GtkDragDestInfo *dest_info)
+                     GtkDragDestInfo *dest_info,
+                     guint32          time)
 {
   GtkDragSourceInfo *source_info;
   GList *tmp_list;
+  GdkDragContext *context;
+  GtkWidget *ipc_widget;
+
+  if (dest_info->proxy_source)
+    {
+      gdk_drag_abort (dest_info->proxy_source->context, time);
+      gtk_drag_source_info_destroy (dest_info->proxy_source);
+      dest_info->proxy_source = NULL;
+    }
   
-  source_info = g_new0 (GtkDragSourceInfo, 1);
-  source_info->ipc_widget = gtk_drag_get_ipc_widget ();
-  
-  source_info->widget = widget;
-  gtk_widget_ref (source_info->widget);
-  source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
-                                        dest_info->context->targets);
+  ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
+  context = gdk_drag_begin (ipc_widget->window,
+                           dest_info->context->targets);
+
+  source_info = gtk_drag_get_source_info (context, TRUE);
+
+  source_info->ipc_widget = ipc_widget;
+  source_info->widget = gtk_widget_ref (widget);
 
   source_info->target_list = gtk_target_list_new (NULL, 0);
   tmp_list = dest_info->context->targets;
   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;
   
-  g_object_set_qdata (G_OBJECT (source_info->context),
-                      g_quark_from_static_string ("gtk-info"),
-                      source_info);
-  
-  gtk_signal_connect (GTK_OBJECT (source_info->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;
 }
@@ -1365,11 +1475,76 @@ gtk_drag_dest_info_destroy (gpointer data)
   g_free (info);
 }
 
+static GtkDragDestInfo *
+gtk_drag_get_dest_info (GdkDragContext *context,
+                       gboolean        create)
+{
+  GtkDragDestInfo *info;
+  static GQuark info_quark = 0;
+  if (!info_quark)
+    info_quark = g_quark_from_static_string ("gtk-dest-info");
+  
+  info = g_object_get_qdata (G_OBJECT (context), info_quark);
+  if (!info && create)
+    {
+      info = g_new (GtkDragDestInfo, 1);
+      info->widget = NULL;
+      info->context = context;
+      info->proxy_source = NULL;
+      info->proxy_data = NULL;
+      info->dropped = FALSE;
+      info->proxy_drop_wait = FALSE;
+      g_object_set_qdata_full (G_OBJECT (context), info_quark,
+                              info, gtk_drag_dest_info_destroy);
+    }
+
+  return info;
+}
+
+static GQuark dest_info_quark = 0;
+
+static GtkDragSourceInfo *
+gtk_drag_get_source_info (GdkDragContext *context,
+                         gboolean        create)
+{
+  GtkDragSourceInfo *info;
+  if (!dest_info_quark)
+    dest_info_quark = g_quark_from_static_string ("gtk-source-info");
+  
+  info = g_object_get_qdata (G_OBJECT (context), dest_info_quark);
+  if (!info && create)
+    {
+      info = g_new0 (GtkDragSourceInfo, 1);
+      info->context = context;
+      g_object_set_qdata (G_OBJECT (context), dest_info_quark, info);
+    }
+
+  return info;
+}
+
+static void
+gtk_drag_clear_source_info (GdkDragContext *context)
+{
+  g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL);
+}
+
 static void
 gtk_drag_dest_realized (GtkWidget *widget)
 {
   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
-  gdk_window_register_dnd (toplevel->window);
+
+  if (GTK_WIDGET_TOPLEVEL (toplevel))
+    gdk_window_register_dnd (toplevel->window);
+}
+
+static void
+gtk_drag_dest_hierarchy_changed (GtkWidget *widget,
+                                GtkWidget *previous_toplevel)
+{
+  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+
+  if (GTK_WIDGET_TOPLEVEL (toplevel) && GTK_WIDGET_REALIZED (toplevel))
+    gdk_window_register_dnd (toplevel->window);
 }
 
 static void
@@ -1377,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);
 
@@ -1393,16 +1571,19 @@ 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)
     {
-      GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context),
-                                                  g_quark_from_static_string ("gtk-info"));
+      GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
 
-      if (info->proxy_source && !info->dropped)
-       gdk_drag_abort (info->proxy_source->context, time);
+      if (info->proxy_source && info->proxy_source->widget == widget && !info->dropped)
+       {
+         gdk_drag_abort (info->proxy_source->context, time);
+         gtk_drag_source_info_destroy (info->proxy_source);
+         info->proxy_source = NULL;
+       }
       
       return;
     }
@@ -1412,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;
     }
@@ -1430,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)
@@ -1440,11 +1621,10 @@ gtk_drag_dest_motion (GtkWidget      *widget,
       GdkWindow *dest_window;
       GdkDragProtocol proto;
        
-      GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context),
-                                                 g_quark_from_static_string ("gtk-info"));
+      GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
 
-      if (!info->proxy_source)
-       gtk_drag_proxy_begin (widget, info);
+      if (!info->proxy_source || info->proxy_source->widget != widget)
+       gtk_drag_proxy_begin (widget, info, time);
 
       current_event = gtk_get_current_event ();
 
@@ -1455,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, 
@@ -1470,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 && 
@@ -1501,7 +1682,7 @@ gtk_drag_dest_motion (GtkWidget        *widget,
            }
        }
       
-      if (action && gtk_drag_dest_find_target (widget, site, context))
+      if (action && gtk_drag_dest_find_target (widget, context, NULL))
        {
          if (!site->have_drag)
            {
@@ -1519,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;
 }
@@ -1535,11 +1716,10 @@ 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 = g_object_get_qdata (G_OBJECT (context),
-                             g_quark_from_static_string ("gtk-info"));
+  info = gtk_drag_get_dest_info (context, FALSE);
   g_return_val_if_fail (info != NULL, FALSE);
 
   info->drop_x = x;
@@ -1563,7 +1743,7 @@ gtk_drag_dest_drop (GtkWidget          *widget,
          GdkWindow *dest_window;
          GdkDragProtocol proto;
          
-         gtk_drag_proxy_begin (widget, info);
+         gtk_drag_proxy_begin (widget, info, time);
          info->proxy_drop_wait = TRUE;
          info->proxy_drop_time = time;
          
@@ -1576,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, 
@@ -1591,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 && 
@@ -1599,7 +1780,6 @@ gtk_drag_dest_drop (GtkWidget          *widget,
            gtk_drag_source_check_selection (info->proxy_source, selection, time);
 
          gdk_event_free (current_event);
-      
        }
 
       return TRUE;
@@ -1610,16 +1790,19 @@ gtk_drag_dest_drop (GtkWidget        *widget,
 
       if (site->flags & GTK_DEST_DEFAULT_DROP)
        {
-         GdkAtom target = gtk_drag_dest_find_target (widget, site, context);
+         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;
     }
@@ -1653,20 +1836,16 @@ gtk_drag_begin (GtkWidget         *widget,
   GList *tmp_list;
   guint32 time = GDK_CURRENT_TIME;
   GdkDragAction possible_actions, suggested_action;
+  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);
 
   if (event)
     time = gdk_event_get_time (event);
 
-  info = g_new0 (GtkDragSourceInfo, 1);
-  info->ipc_widget = gtk_drag_get_ipc_widget ();
-  source_widgets = g_slist_prepend (source_widgets, info->ipc_widget);
-
-  gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
-
   tmp_list = g_list_last (target_list->list);
   while (tmp_list)
     {
@@ -1676,15 +1855,19 @@ gtk_drag_begin (GtkWidget         *widget,
       tmp_list = tmp_list->prev;
     }
 
-  info->widget = widget;
-  gtk_widget_ref (info->widget);
-  
-  info->context = gdk_drag_begin (info->ipc_widget->window, targets);
+  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);
   g_list_free (targets);
   
-  g_object_set_qdata (G_OBJECT (info->context),
-                     g_quark_from_static_string ("gtk-info"), info);
+  info = gtk_drag_get_source_info (context, TRUE);
+  
+  info->ipc_widget = ipc_widget;
+  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;
   gtk_target_list_ref (target_list);
@@ -1700,28 +1883,26 @@ 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);
@@ -1729,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
@@ -1751,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;
 }
 
@@ -1788,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) |
@@ -1805,17 +1981,19 @@ gtk_drag_source_set (GtkWidget            *widget,
   else
     {
       site = g_new0 (GtkDragSourceSite, 1);
+
+      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;
@@ -1842,27 +2020,64 @@ 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);
     }
 }
 
-/*************************************************************
- * gtk_drag_source_set_icon:
- *     Set an icon for drags from this source.
- *   arguments:
- *     colormap: Colormap for this icon
- *     pixmap:
- *     mask
- *   results:
- *************************************************************/
+static void
+gtk_drag_source_unset_icon (GtkDragSourceSite *site)
+{
+  switch (site->icon_type)
+    {
+    case GTK_IMAGE_EMPTY:
+      break;
+    case GTK_IMAGE_PIXMAP:
+      if (site->icon_data.pixmap.pixmap)
+       g_object_unref (site->icon_data.pixmap.pixmap);
+      if (site->icon_mask)
+       g_object_unref (site->icon_mask);
+      break;
+    case GTK_IMAGE_PIXBUF:
+      g_object_unref (site->icon_data.pixbuf.pixbuf);
+      break;
+    case GTK_IMAGE_STOCK:
+      g_free (G_OBJECT (site->icon_data.stock.stock_id));
+      break;
+    default:
+      g_assert_not_reached();
+      break;
+    }
+  site->icon_type = GTK_IMAGE_EMPTY;
+  
+  if (site->colormap)
+    g_object_unref (site->colormap);
+  site->colormap = NULL;
+}
 
+/**
+ * gtk_drag_source_set_icon:
+ * @widget: a #GtkWidget
+ * @colormap: the colormap of the icon
+ * @pixmap: the image data for the icon
+ * @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 references for the arguments, and 
+ * will release them when they are no longer needed.
+ * Use gtk_drag_source_set_icon_pixbuf() instead.
+ **/
 void 
 gtk_drag_source_set_icon (GtkWidget     *widget,
                          GdkColormap   *colormap,
@@ -1871,41 +2086,163 @@ 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);
   
-  if (site->colormap)
-    gdk_colormap_unref (site->colormap);
-  if (site->pixmap)
-    gdk_pixmap_unref (site->pixmap);
-  if (site->mask)
-    gdk_pixmap_unref (site->mask);
+  g_object_ref (colormap);
+  g_object_ref (pixmap);
+  if (mask)
+    g_object_ref (mask);
+
+  gtk_drag_source_unset_icon (site);
 
+  site->icon_type = GTK_IMAGE_PIXMAP;
+  
+  site->icon_data.pixmap.pixmap = pixmap;
+  site->icon_mask = mask;
   site->colormap = colormap;
-  if (colormap)
-    gdk_colormap_ref (colormap);
+}
 
-  site->pixmap = pixmap;
-  if (pixmap)
-    gdk_pixmap_ref (pixmap);
+/**
+ * gtk_drag_source_set_icon_pixbuf:
+ * @widget: a #GtkWidget
+ * @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 for @pixbuf and will 
+ * release it when it is no longer needed.
+ **/
+void 
+gtk_drag_source_set_icon_pixbuf (GtkWidget   *widget,
+                                GdkPixbuf   *pixbuf)
+{
+  GtkDragSourceSite *site;
 
-  site->mask = mask;
-  if (mask)
-    gdk_pixmap_ref (mask);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (GDK_IS_PIXBUF (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);
+
+  site->icon_type = GTK_IMAGE_PIXBUF;
+  site->icon_data.pixbuf.pixbuf = pixbuf;
 }
 
-/*************************************************************
- * gtk_drag_set_icon_window:
- *     Set a widget as the icon for a drag.
- *   arguments:
- *     context:
- *     widget:
- *     hot_x:    Hot spot
- *     hot_y:
- *   results:
- *************************************************************/
+/**
+ * gtk_drag_source_set_icon_stock:
+ * @widget: a #GtkWidget
+ * @stock_id: the ID of the stock icon to use
+ *
+ * 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,
+                               const gchar *stock_id)
+{
+  GtkDragSourceSite *site;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (stock_id != NULL);
+
+  site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
+  g_return_if_fail (site != NULL);
+  
+  gtk_drag_source_unset_icon (site);
+
+  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,
@@ -1916,66 +2253,188 @@ gtk_drag_set_icon_window (GdkDragContext *context,
 {
   GtkDragSourceInfo *info;
 
-  g_return_if_fail (context != NULL);
-  g_return_if_fail (widget != NULL);
-
-  info = g_object_get_qdata (G_OBJECT (context),
-                            g_quark_from_static_string ("gtk-info"));
+  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);
 }
 
-/*************************************************************
+/**
  * gtk_drag_set_icon_widget:
- *     Set a widget as the icon for a drag.
- *   arguments:
- *     context:
- *     widget:
- *     hot_x:    Hot spot
- *     hot_y:
- *   results:
- *************************************************************/
-
+ * @context: the context for a drag. (This must be called 
+          with a  context for the source side of a drag)
+ * @widget: a toplevel window to use as an icon.
+ * @hot_x: the X offset within @widget of the hotspot.
+ * @hot_y: the Y offset within @widget of the hotspot.
+ * 
+ * Changes the icon for a widget to a given widget. GTK+
+ * will not destroy the icon, so if you don't want
+ * it to persist, you should connect to the "drag_end" 
+ * signal and destroy it yourself.
+ **/
 void 
 gtk_drag_set_icon_widget (GdkDragContext    *context,
                          GtkWidget         *widget,
                          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);
 }
 
-/*************************************************************
- * gtk_drag_set_icon_pixmap:
- *     Set a widget as the icon for a drag.
- *   arguments:
- *     context:
- *     colormap: Colormap for the icon window.
- *     pixmap:   
- *     mask:
- *     hot_x:    Hot spot
- *     hot_y:
- *   results:
- *************************************************************/
+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,
+                      GdkPixbuf         *pixbuf,
+                      gint               hot_x,
+                      gint               hot_y)
+{
+  GtkWidget *window;
+  gint width, height;
+  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);
+
+  /* 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);
+  gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
+  
+  if (stock_id)
+    {
+      pixbuf = gtk_widget_render_icon (window, stock_id,
+                                      GTK_ICON_SIZE_DND, NULL);
+
+      if (!pixbuf)
+       {
+         g_warning ("Cannot load drag icon from stock_id %s", stock_id);
+         gtk_widget_destroy (window);
+         return;
+       }
+
+    }
+  else
+    g_object_ref (pixbuf);
+  
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_width (pixbuf);
+
+  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);
+}
+
+/**
+ * gtk_drag_set_icon_pixbuf:
+ * @context: the context for a drag. (This must be called 
+ *            with a  context for the source side of a drag)
+ * @pixbuf: the #GdkPixbuf to use as the drag icon.
+ * @hot_x: the X offset within @widget of the hotspot.
+ * @hot_y: the Y offset within @widget of the hotspot.
+ * 
+ * Sets @pixbuf as the icon for a given drag.
+ **/
+void 
+gtk_drag_set_icon_pixbuf  (GdkDragContext *context,
+                          GdkPixbuf      *pixbuf,
+                          gint            hot_x,
+                          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_stock:
+ * @context: the context for a drag. (This must be called 
+ *            with a  context for the source side of a 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.
+ * 
+ * Sets the the icon for a given drag from a stock ID.
+ **/
+void 
+gtk_drag_set_icon_stock  (GdkDragContext *context,
+                         const gchar    *stock_id,
+                         gint            hot_x,
+                         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);
+}
+
+/**
+ * gtk_drag_set_icon_pixmap:
+ * @context: the context for a drag. (This must be called 
+ *            with a  context for the source side of a drag)
+ * @colormap: the colormap of the icon 
+ * @pixmap: the image data for the icon 
+ * @mask: the transparency mask for the icon
+ * @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
+ * 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.
+ **/
 void 
 gtk_drag_set_icon_pixmap (GdkDragContext    *context,
                          GdkColormap       *colormap,
@@ -1985,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);
@@ -2012,51 +2481,44 @@ gtk_drag_set_icon_pixmap (GdkDragContext    *context,
   gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
 }
 
-/*************************************************************
+/**
  * gtk_drag_set_icon_default:
- *     Set the icon for a drag to the default icon.
- *   arguments:
- *     context:
- *   results:
- *************************************************************/
-
+ * @context: the context for a drag. (This must be called 
+             with a  context for the source side of a drag)
+ * 
+ * Sets the icon for a particular drag to the default
+ * icon.
+ **/
 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)
-    {
-      default_icon_colormap = gdk_colormap_get_system ();
-      default_icon_pixmap = 
-       gdk_pixmap_colormap_create_from_xpm_d (NULL,
-                                              default_icon_colormap,
-                                              &default_icon_mask,
-                                              NULL, (gchar **)drag_default_xpm);
-      default_icon_hot_x = -2;
-      default_icon_hot_y = -2;
-    }
-
-  gtk_drag_set_icon_pixmap (context, 
-                           default_icon_colormap, 
-                           default_icon_pixmap, 
-                           default_icon_mask,
-                           default_icon_hot_x,
-                           default_icon_hot_y);
+    gtk_drag_set_icon_stock (context, GTK_STOCK_DND, -2, -2);
+  else
+    gtk_drag_set_icon_pixmap (context, 
+                             default_icon_colormap, 
+                             default_icon_pixmap, 
+                             default_icon_mask,
+                             default_icon_hot_x,
+                             default_icon_hot_y);
 }
 
-/*************************************************************
+/**
  * gtk_drag_set_default_icon:
- *     Set a default icon for all drags as a pixmap.
- *   arguments:
- *     colormap: Colormap for the icon window.
- *     pixmap:   
- *     mask:
- *     hot_x:    Hot spot
- *     hot_y:
- *   results:
- *************************************************************/
-
+ * @colormap: the colormap of the icon
+ * @pixmap: the image data for the icon
+ * @mask: the transparency mask for an image.
+ * @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 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.
+ **/
 void 
 gtk_drag_set_default_icon (GdkColormap   *colormap,
                           GdkPixmap     *pixmap,
@@ -2064,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;
@@ -2090,7 +2553,7 @@ gtk_drag_set_default_icon (GdkColormap   *colormap,
 
 
 /*************************************************************
- * gtk_drag_source_handle_event:
+ * _gtk_drag_source_handle_event:
  *     Called from widget event handling code on Drag events
  *     for drag sources.
  *
@@ -2101,8 +2564,8 @@ gtk_drag_set_default_icon (GdkColormap   *colormap,
  *************************************************************/
 
 void
-gtk_drag_source_handle_event (GtkWidget *widget,
-                             GdkEvent  *event)
+_gtk_drag_source_handle_event (GtkWidget *widget,
+                              GdkEvent  *event)
 {
   GtkDragSourceInfo *info;
   GdkDragContext *context;
@@ -2111,8 +2574,7 @@ gtk_drag_source_handle_event (GtkWidget *widget,
   g_return_if_fail (event != NULL);
 
   context = event->dnd.context;
-  info = g_object_get_qdata (G_OBJECT (context),
-                            g_quark_from_static_string ("gtk-info"));
+  info = gtk_drag_get_source_info (context, FALSE);
   if (!info)
     return;
 
@@ -2145,31 +2607,25 @@ 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)
              {
-#ifdef GDK_WINDOWING_X11
-               XChangeActivePointerGrab (GDK_WINDOW_XDISPLAY (widget->window), 
-                                         PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask,
-                                         ((GdkCursorPrivate *)cursor)->xcursor,
-                                         event->dnd.time);
-#elif defined (GDK_WINDOWING_WIN32)
                gdk_pointer_grab (widget->window, FALSE,
                                  GDK_POINTER_MOTION_MASK |
                                  GDK_POINTER_MOTION_HINT_MASK |
                                  GDK_BUTTON_RELEASE_MASK,
                                  NULL,
-                                 info->cursor, event->dnd.time);
-#endif
+                                 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;
              }
@@ -2204,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));
 
@@ -2282,17 +2741,14 @@ 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.
           */
-         g_object_set_qdata (G_OBJECT (info->context),
-                             g_quark_from_static_string ("gtk-info"), NULL);
+         gtk_drag_clear_source_info (info->context);
          gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
        }
     }
@@ -2302,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;
     }
 
@@ -2345,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);
@@ -2380,6 +2839,7 @@ gtk_drag_source_event_cb (GtkWidget      *widget,
                          gpointer        data)
 {
   GtkDragSourceSite *site;
+  gboolean retval = FALSE;
   site = (GtkDragSourceSite *)data;
 
   switch (event->type)
@@ -2395,9 +2855,7 @@ gtk_drag_source_event_cb (GtkWidget      *widget,
       
     case GDK_BUTTON_RELEASE:
       if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
-       {
-         site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
-       }
+       site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
       break;
       
     case GDK_MOTION_NOTIFY:
@@ -2413,9 +2871,9 @@ gtk_drag_source_event_cb (GtkWidget      *widget,
                  GDK_BUTTON1_MASK << (i - 1))
                break;
            }
-         
-         if (MAX (ABS (site->x - event->motion.x),
-                  ABS (site->y - event->motion.y)) > 3)
+
+         if (gtk_drag_check_threshold (widget, site->x, site->y,
+                                       event->motion.x, event->motion.y))
            {
              GtkDragSourceInfo *info;
              GdkDragContext *context;
@@ -2425,22 +2883,39 @@ gtk_drag_source_event_cb (GtkWidget      *widget,
                                        site->actions, 
                                        i, event);
 
-             
-             info = g_object_get_qdata (G_OBJECT (context),
-                                         g_quark_from_static_string ("gtk-info"));
+             info = gtk_drag_get_source_info (context, FALSE);
 
              if (!info->icon_window)
                {
-                 if (site->pixmap)
-                   gtk_drag_set_icon_pixmap (context,
-                                             site->colormap,
-                                             site->pixmap,
-                                             site->mask, -2, -2);
-                 else
-                   gtk_drag_set_icon_default (context);
+                 switch (site->icon_type)
+                   {
+                   case GTK_IMAGE_EMPTY:
+                     gtk_drag_set_icon_default (context);
+                     break;
+                   case GTK_IMAGE_PIXMAP:
+                     gtk_drag_set_icon_pixmap (context,
+                                               site->colormap,
+                                               site->icon_data.pixmap.pixmap,
+                                               site->icon_mask,
+                                               -2, -2);
+                     break;
+                   case GTK_IMAGE_PIXBUF:
+                     gtk_drag_set_icon_pixbuf (context,
+                                               site->icon_data.pixbuf.pixbuf,
+                                               -2, -2);
+                     break;
+                   case GTK_IMAGE_STOCK:
+                     gtk_drag_set_icon_stock (context,
+                                              site->icon_data.stock.stock_id,
+                                              -2, -2);
+                     break;
+                   default:
+                     g_assert_not_reached();
+                     break;
+                   }
                }
 
-             return TRUE;
+             retval = TRUE;
            }
        }
       break;
@@ -2448,7 +2923,8 @@ gtk_drag_source_event_cb (GtkWidget      *widget,
     default:                   /* hit for 2/3BUTTON_PRESS */
       break;
     }
-  return FALSE;
+  
+  return retval;
 }
 
 static void 
@@ -2459,12 +2935,7 @@ gtk_drag_source_site_destroy (gpointer data)
   if (site->target_list)
     gtk_target_list_unref (site->target_list);
 
-  if (site->pixmap)
-    gdk_pixmap_unref (site->pixmap);
-  
-  if (site->mask)
-    gdk_pixmap_unref (site->mask);
-  
+  gtk_drag_source_unset_icon (site);
   g_free (site);
 }
 
@@ -2485,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:
@@ -2518,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;
@@ -2552,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++;
 
@@ -2575,37 +3053,52 @@ 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;
     }
 }
 
 static void
-gtk_drag_source_info_destroy (gpointer data)
+gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
 {
-  GtkDragSourceInfo *info = data;
-
-  g_warning ("Destroying drag source info!");
-  
-  gtk_drag_remove_icon (data);
+  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);
 
-  g_object_set_qdata (G_OBJECT (info->context), g_quark_from_static_string ("gtk-info"), NULL);
-  gdk_drag_context_unref (info->context);
+  gtk_drag_clear_source_info (info->context);
+  g_object_unref (info->context);
 
   if (info->drop_timeout)
     gtk_timeout_remove (info->drop_timeout);
@@ -2626,13 +3119,13 @@ gtk_drag_source_info_destroy (gpointer data)
 
 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;
@@ -2642,35 +3135,39 @@ 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;
-    }
+  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);
   
-  gdk_drag_find_window (info->context,
-                       window, x_root, y_root,
-                       &dest_window, &protocol);
-
   if (gdk_drag_motion (info->context, dest_window, protocol,
                       x_root, y_root, action, 
                       possible_actions,
                       time))
+    {
+      if (info->last_event != event) /* Paranoia, should not happen */
+       {
+         if (info->last_event)
+           gdk_event_free ((GdkEvent *)info->last_event);
+         info->last_event = gdk_event_copy ((GdkEvent *)event);
+       }
+    }
+  else
     {
       if (info->last_event)
-       gdk_event_free ((GdkEvent *)info->last_event);
-      
-      info->last_event = gdk_event_copy ((GdkEvent *)event);
+       {
+         gdk_event_free ((GdkEvent *)info->last_event);
+         info->last_event = NULL;
+       }
     }
-
+  
   if (dest_window)
-    gdk_window_unref (dest_window);
+    g_object_unref (dest_window);
 
   selection = gdk_drag_get_selection (info->context);
   if (selection)
@@ -2682,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
@@ -2712,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_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_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:
+ *************************************************************/
 
-  gtk_propagate_event (source_widget, &send_event);
+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);
 }
 
 /*************************************************************
@@ -2742,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;
 }
@@ -2771,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;
        }
@@ -2790,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;
 }
@@ -2816,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;
@@ -2849,3 +3373,36 @@ gtk_drag_abort_timeout (gpointer data)
   
   return FALSE;
 }
+
+/**
+ * gtk_drag_check_threshold:
+ * @widget: a #GtkWidget
+ * @start_x: X coordinate of start of drag
+ * @start_y: Y coordinate of start of drag
+ * @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
+ * should trigger the beginning of a drag-and-drop operation.
+ *
+ * Return Value: %TRUE if the drag threshold has been passed.
+ **/
+gboolean
+gtk_drag_check_threshold (GtkWidget *widget,
+                         gint       start_x,
+                         gint       start_y,
+                         gint       current_x,
+                         gint       current_y)
+{
+  gint drag_threshold;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  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);
+}