]> Pileus Git - ~andy/gtk/blob - gtk/gtkdnd.c
Changed to 5 min from 10 seconds, so it doesn't abort while users have an
[~andy/gtk] / gtk / gtkdnd.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "gdk/gdkx.h"
21
22 #include "gtkdnd.h"
23 #include "gtkinvisible.h"
24 #include "gtkmain.h"
25 #include "gtksignal.h"
26 #include "gtkdrawwindow.h"
27
28 static GSList *drag_widgets = NULL;
29 static GSList *source_widgets = NULL;
30
31 typedef struct _GtkDragSourceSite GtkDragSourceSite;
32 typedef struct _GtkDragSourceInfo GtkDragSourceInfo;
33 typedef struct _GtkDragDestSite GtkDragDestSite;
34 typedef struct _GtkDragDestInfo GtkDragDestInfo;
35 typedef struct _GtkDragAnim GtkDragAnim;
36 typedef struct _GtkDragFindData GtkDragFindData;
37
38
39 typedef enum {
40   GTK_DRAG_STATUS_DRAG,
41   GTK_DRAG_STATUS_WAIT,
42   GTK_DRAG_STATUS_DROP
43 } GtkDragStatus;
44
45 struct _GtkDragSourceSite {
46   GdkModifierType    start_button_mask;
47   GtkTargetList     *target_list;        /* Targets for drag data */
48   GdkDragAction      actions;            /* Possible actions */
49   GdkColormap       *colormap;           /* Colormap for drag icon */
50   GdkPixmap         *pixmap;             /* Icon for drag data */
51   GdkBitmap         *mask;
52
53   /* Stored button press information to detect drag beginning */
54   gint               state;
55   gint               x, y;
56 };
57   
58 struct _GtkDragSourceInfo {
59   GtkWidget         *widget;
60   GtkTargetList     *target_list; /* Targets for drag data */
61   GdkDragContext    *context;     /* drag context */
62   GtkWidget         *icon_window; /* Window for drag */
63   GtkWidget         *ipc_widget;  /* GtkInvisible for grab, message passing */
64   GdkCursor         *cursor;      /* Cursor for drag */
65   gint hot_x, hot_y;              /* Hot spot for drag */
66   gint button;                    /* mouse button starting drag */
67
68   GtkDragStatus      status;      /* drag status */
69   GdkEvent          *last_event;  /* motion event waiting for response */
70
71   gint               start_x, start_y; /* Initial position */
72   gint               cur_x, cur_y;     /* Current Position */
73
74   GList             *selections;  /* selections we've claimed */
75   
76   GtkDragDestInfo   *proxy_dest;  /* Set if this is a proxy drag */
77
78   guint              drop_timeout; /* Timeout for aborting drop */
79 };
80
81 struct _GtkDragDestSite {
82   GtkDestDefaults    flags;
83   GtkTargetList     *target_list;
84   GdkDragAction      actions;
85   GdkWindow         *proxy_window;
86   GdkDragProtocol    proxy_protocol;
87   gboolean           do_proxy : 1;
88   gboolean           proxy_coords : 1;
89   gboolean           have_drag : 1;
90 };
91   
92 struct _GtkDragDestInfo {
93   GtkWidget         *widget;       /* Widget in which drag is in */
94   GdkDragContext    *context;      /* Drag context */
95   GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */
96   GtkSelectionData  *proxy_data;   /* Set while retrieving proxied data */
97   gboolean           dropped : 1;     /* Set after we receive a drop */
98   guint32            proxy_drop_time; /* Timestamp for proxied drop */
99   gboolean           proxy_drop_wait : 1; /* Set if we are waiting for a
100                                            * status reply before sending
101                                            * a proxied drop on.
102                                            */
103   gint               drop_x, drop_y; /* Position of drop */
104 };
105
106 #define DROP_ABORT_TIME 300000
107
108 #define ANIM_STEP_TIME 50
109 #define ANIM_STEP_LENGTH 50
110 #define ANIM_MIN_STEPS 5
111 #define ANIM_MAX_STEPS 10
112
113 struct _GtkDragAnim {
114   GtkDragSourceInfo *info;
115   gint step;
116   gint n_steps;
117 };
118
119 struct _GtkDragFindData {
120   gint x;
121   gint y;
122   GdkDragContext *context;
123   GtkDragDestInfo *info;
124   gboolean found;
125   gboolean toplevel;
126   gboolean (*callback) (GtkWidget *widget, GdkDragContext *context,
127                         gint x, gint y, guint32 time);
128   guint32 time;
129 };
130
131 /* Enumeration for some targets we handle internally */
132
133 enum {
134   TARGET_MOTIF_SUCCESS = 0x40000000,
135   TARGET_MOTIF_FAILURE,
136   TARGET_DELETE
137 };
138
139 /* Drag icons */
140
141 static GdkPixmap   *default_icon_pixmap = NULL;
142 static GdkPixmap   *default_icon_mask = NULL;
143 static GdkColormap *default_icon_colormap = NULL;
144 static gint         default_icon_hot_x;
145 static gint         default_icon_hot_y;
146
147 /* Forward declarations */
148 static GdkDragAction gtk_drag_get_event_action   (GdkEvent        *event, 
149                                                   gint             button,
150                                                   GdkDragAction    actions);
151 static GdkCursor *   gtk_drag_get_cursor         (GdkDragAction action);
152 static GtkWidget    *gtk_drag_get_ipc_widget     (void);
153 static void          gtk_drag_release_ipc_widget (GtkWidget *widget);
154
155 static GdkAtom   gtk_drag_dest_find_target    (GtkWidget          *widget,
156                                                GtkDragDestSite    *site,
157                                                GdkDragContext     *context);
158 static void      gtk_drag_selection_received  (GtkWidget          *widget,
159                                                GtkSelectionData   *selection_data,
160                                                guint32             time,
161                                                gpointer            data);
162 static void      gtk_drag_find_widget         (GtkWidget          *widget,
163                                                GtkDragFindData    *data);
164 static void      gtk_drag_proxy_begin         (GtkWidget          *widget,
165                                                GtkDragDestInfo    *dest_info);
166 static void      gtk_drag_dest_info_destroy   (gpointer            data);
167 static void      gtk_drag_dest_realized       (GtkWidget          *widget);
168 static void      gtk_drag_dest_site_destroy   (gpointer            data);
169 static void      gtk_drag_dest_leave          (GtkWidget          *widget,
170                                                GdkDragContext     *context,
171                                                guint               time);
172 static gboolean  gtk_drag_dest_motion         (GtkWidget          *widget,
173                                                GdkDragContext     *context,
174                                                gint                x,
175                                                gint                y,
176                                                guint               time);
177 static gboolean  gtk_drag_dest_drop           (GtkWidget          *widget,
178                                                GdkDragContext     *context,
179                                                gint                x,
180                                                gint                y,
181                                                guint               time);
182
183 static void gtk_drag_source_check_selection    (GtkDragSourceInfo *info, 
184                                                 GdkAtom            selection,
185                                                 guint32            time);
186 static void gtk_drag_source_release_selections (GtkDragSourceInfo *info,
187                                                 guint32            time);
188 static void gtk_drag_drop                      (GtkDragSourceInfo *info,
189                                                 guint32            time);
190 static void gtk_drag_drop_finished             (GtkDragSourceInfo *info,
191                                                 gboolean           success,
192                                                 guint              time);
193
194 static gint gtk_drag_source_event_cb           (GtkWidget         *widget,
195                                                 GdkEvent          *event,
196                                                 gpointer           data);
197 static void gtk_drag_source_site_destroy       (gpointer           data);
198 static void gtk_drag_selection_get             (GtkWidget         *widget, 
199                                                 GtkSelectionData  *selection_data,
200                                                 guint              sel_info,
201                                                 guint32            time,
202                                                 gpointer           data);
203 static gint gtk_drag_anim_timeout              (gpointer           data);
204 static void gtk_drag_remove_icon               (GtkDragSourceInfo *info);
205 static void gtk_drag_source_info_destroy       (gpointer           data);
206 static gint gtk_drag_motion_cb                 (GtkWidget         *widget, 
207                                                 GdkEventMotion    *event, 
208                                                 gpointer           data);
209 static gint gtk_drag_button_release_cb         (GtkWidget         *widget, 
210                                                 GdkEventButton    *event, 
211                                                 gpointer           data);
212 static gint gtk_drag_abort_timeout             (gpointer           data);
213
214 /************************
215  * Cursor and Icon data *
216  ************************/
217
218 #define action_ask_width 16
219 #define action_ask_height 16
220 static const char action_ask_bits[] = {
221   0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xf8, 0xb6, 0xf7, 
222   0xd6, 0xec, 0x66, 0xdb, 0x66, 0xdb, 0x96, 0xec, 0x76, 0xf7, 0x76, 0xfb, 
223   0xf6, 0xfc, 0x72, 0xfb, 0x7a, 0xfb, 0xf8, 0xfc, };
224
225 #define action_ask_mask_width 16
226 #define action_ask_mask_height 16
227 static const char action_ask_mask_bits[] = {
228   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0xcf, 0x0f, 
229   0xef, 0x1f, 0xff, 0x3c, 0xff, 0x3c, 0x6f, 0x1f, 0x8f, 0x0f, 0x8f, 0x07, 
230   0x0f, 0x03, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x03, };
231
232 #define action_copy_width 16
233 #define action_copy_height 16
234 static const char action_copy_bits[] = {
235   0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xfb, 0x76, 0xfb, 
236   0x76, 0xfb, 0x06, 0x83, 0xf6, 0xbf, 0xf6, 0xbf, 0x06, 0x83, 0x76, 0xfb, 
237   0x76, 0xfb, 0x72, 0xfb, 0x7a, 0xf8, 0xf8, 0xff, };
238
239 #define action_copy_mask_width 16
240 #define action_copy_mask_height 16
241 static const char action_copy_mask_bits[] = {
242   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0x8f, 0x07, 
243   0x8f, 0x07, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x8f, 0x07, 
244   0x8f, 0x07, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x00, };
245
246 #define action_move_width 16
247 #define action_move_height 16
248 static const char action_move_bits[] = {
249   0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x96, 0xff, 0x26, 0xff, 
250   0xc6, 0xf8, 0xd6, 0xe3, 0x96, 0x8f, 0xb6, 0xbf, 0x36, 0xc3, 0x76, 0xfb, 
251   0x76, 0xfa, 0xf2, 0xfa, 0xfa, 0xf8, 0xf8, 0xff, };
252
253 #define action_move_mask_width 16
254 #define action_move_mask_height 16
255 static const char action_move_mask_bits[] = {
256   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x6f, 0x00, 0xff, 0x00, 
257   0xff, 0x07, 0xef, 0x1f, 0xef, 0x7f, 0xcf, 0x7f, 0xcf, 0x3f, 0x8f, 0x07, 
258   0x8f, 0x07, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x00, };
259
260 #define action_link_width 16
261 #define action_link_height 16
262 static const char action_link_bits[] = {
263   0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x36, 0xf8, 0xd6, 0xf7, 
264   0x66, 0xec, 0xa6, 0xe8, 0x26, 0xdf, 0xe6, 0xbd, 0xd6, 0xa7, 0xb6, 0xa8, 
265   0xb6, 0xb1, 0x72, 0xdf, 0xfa, 0xe0, 0xf8, 0xff, };
266
267 #define action_link_mask_width 16
268 #define action_link_mask_height 16
269 static const char action_link_mask_bits[] = {
270   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xcf, 0x07, 0xef, 0x0f, 
271   0xff, 0x1f, 0x7f, 0x1f, 0xff, 0x3f, 0xff, 0x7f, 0xef, 0x7f, 0xcf, 0x77, 
272   0xcf, 0x7f, 0x8f, 0x3f, 0x07, 0x1f, 0x07, 0x00, };
273
274 #define action_none_width 16
275 #define action_none_height 16
276 static const char action_none_bits[] = {
277   0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0xf6, 0xff, 0xf6, 0xff, 
278   0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 
279   0xf6, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf8, 0xff, };
280
281 #define action_none_mask_width 16
282 #define action_none_mask_height 16
283 static const char action_none_mask_bits[] = {
284   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x0f, 0x00, 
285   0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 
286   0x0f, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x07, 0x00, };
287
288 #define CURSOR_WIDTH 16
289 #define CURSOR_HEIGHT 16
290
291 static struct {
292   GdkDragAction action;
293   const char *bits;
294   const char *mask;
295   GdkCursor    *cursor;
296 } drag_cursors[] = {
297   { GDK_ACTION_DEFAULT, 0 },
298   { GDK_ACTION_ASK,   action_ask_bits,  action_ask_mask_bits,  NULL },
299   { GDK_ACTION_COPY,  action_copy_bits, action_copy_mask_bits, NULL },
300   { GDK_ACTION_MOVE,  action_move_bits, action_move_mask_bits, NULL },
301   { GDK_ACTION_LINK,  action_link_bits, action_link_mask_bits, NULL },
302   { 0              ,  action_none_bits, action_none_mask_bits, NULL },
303 };
304
305 static const gint n_drag_cursors = sizeof(drag_cursors) / sizeof(drag_cursors[0]);
306
307 /* XPM */
308 static const char * drag_default_xpm[] = {
309 "32 32 3 1",
310 "       c None",
311 ".      c #000000",
312 "+      c #FFFFFF",
313 "                                ",
314 "                                ",
315 "                ..              ",
316 "              ..+.              ",
317 "             ..++..             ",
318 "           ...++++.             ",
319 "         ...++++++..            ",
320 "       ...+++++++++.            ",
321 "     ...+++++++++++..           ",
322 "    ..+.++++++++++++..          ",
323 "     .++.++++++++++++..         ",
324 "     .+++.++++++++++++..        ",
325 "     .++++.++++++++++++.        ",
326 "     .+++.+++++++++++++..       ",
327 "     .++.+++++++++++++++..      ",
328 "     .+.+++++++++++++++++..     ",
329 "     ..+++++++++++++++++++..    ",
330 "     ..++++++++++++++++++++.    ",
331 "     .++++++++++++++++++++..    ",
332 "     ..+++++++++++++++++..      ",
333 "      .++++++++++++++++..       ",
334 "      ..+++++++++++++...        ",
335 "       .++++++++++++..          ",
336 "       ..+++++++++..            ",
337 "        .++++++++..             ",
338 "        ..++++++..              ",
339 "         .+++++..               ",
340 "          .++..                 ",
341 "           ...                  ",
342 "           ..                   ",
343 "                                ",
344 "                                "};
345
346 /*********************
347  * Utility functions *
348  *********************/
349
350 /*************************************************************
351  * gtk_drag_get_ipc_widget:
352  *     Return a invisible, off-screen, override-redirect
353  *     widget for IPC.
354  *   arguments:
355  *     
356  *   results:
357  *************************************************************/
358
359 static GtkWidget *
360 gtk_drag_get_ipc_widget(void)
361 {
362   GtkWidget *result;
363   
364   if (drag_widgets)
365     {
366       GSList *tmp = drag_widgets;
367       result = drag_widgets->data;
368       drag_widgets = drag_widgets->next;
369       g_slist_free_1 (tmp);
370     }
371   else
372     {
373       result = gtk_invisible_new();
374       gtk_widget_show (result);
375     }
376
377   return result;
378 }
379
380 /*************************************************************
381  * gtk_drag_release_ipc_widget:
382  *     Releases widget retrieved with gtk_drag_get_ipc_widget()
383  *   arguments:
384  *     widget: the widget to release.
385  *   results:
386  *************************************************************/
387
388 static void
389 gtk_drag_release_ipc_widget (GtkWidget *widget)
390 {
391   drag_widgets = g_slist_prepend (drag_widgets, widget);
392 }
393
394 static GdkDragAction
395 gtk_drag_get_event_action (GdkEvent *event, gint button, GdkDragAction actions)
396 {
397   if (event)
398     {
399       GdkModifierType state = 0;
400       
401       switch (event->type)
402         {
403         case GDK_MOTION_NOTIFY:
404           state = event->motion.state;
405           break;
406         case GDK_BUTTON_PRESS:
407         case GDK_2BUTTON_PRESS:
408         case GDK_3BUTTON_PRESS:
409         case GDK_BUTTON_RELEASE:
410           state = event->button.state;
411           break;
412         case GDK_KEY_PRESS:
413         case GDK_KEY_RELEASE:
414           state = event->key.state;
415           break;
416       case GDK_ENTER_NOTIFY:
417       case GDK_LEAVE_NOTIFY:
418           state = event->crossing.state;
419           break;
420       default:
421         break;
422       }
423       
424       if (button == 3)
425         return GDK_ACTION_ASK;
426       
427       if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
428         {
429           if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
430             return (actions & GDK_ACTION_LINK) ? GDK_ACTION_LINK : 0;
431           else if (state & GDK_CONTROL_MASK)
432             return (actions & GDK_ACTION_COPY) ? GDK_ACTION_COPY : 0;
433           else
434             return (actions & GDK_ACTION_MOVE) ? GDK_ACTION_MOVE : 0;
435         }
436       else
437         {
438           if (actions & GDK_ACTION_COPY)
439             return GDK_ACTION_COPY;
440           else if (actions & GDK_ACTION_MOVE)
441             return GDK_ACTION_MOVE;
442           else if (actions & GDK_ACTION_LINK)
443             return GDK_ACTION_LINK;
444         }
445     }
446   
447   return 0;
448 }
449
450 static GdkCursor *
451 gtk_drag_get_cursor (GdkDragAction action)
452 {
453   gint i;
454   
455   for (i = 0 ; i < n_drag_cursors - 1; i++)
456     if (drag_cursors[i].action == action)
457       break;
458
459   if (drag_cursors[i].cursor == NULL)
460     {
461       GdkColor fg, bg;
462
463       GdkPixmap *pixmap = 
464         gdk_bitmap_create_from_data (NULL, 
465                                      drag_cursors[i].bits,
466                                      CURSOR_WIDTH, CURSOR_HEIGHT);
467       GdkPixmap *mask = 
468         gdk_bitmap_create_from_data (NULL, 
469                                      drag_cursors[i].mask,
470                                      CURSOR_WIDTH, CURSOR_HEIGHT);
471
472       gdk_color_white (gdk_colormap_get_system(), &bg);
473       gdk_color_black (gdk_colormap_get_system(), &fg);
474       
475       drag_cursors[i].cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, 0, 0);
476
477       gdk_pixmap_unref (pixmap);
478       gdk_pixmap_unref (mask);
479     }
480
481   return drag_cursors[i].cursor;
482 }
483
484 /********************
485  * Destination side *
486  ********************/
487
488 /*************************************************************
489  * gtk_drag_get_data:
490  *     Get the data for a drag or drop
491  *   arguments:
492  *     context - drag context
493  *     target  - format to retrieve the data in.
494  *     time    - timestamp of triggering event.
495  *     
496  *   results:
497  *************************************************************/
498
499 void 
500 gtk_drag_get_data (GtkWidget      *widget,
501                    GdkDragContext *context,
502                    GdkAtom         target,
503                    guint32         time)
504 {
505   GtkWidget *selection_widget;
506
507   g_return_if_fail (widget != NULL);
508   g_return_if_fail (context != NULL);
509
510   selection_widget = gtk_drag_get_ipc_widget();
511
512   gdk_drag_context_ref (context);
513   gtk_widget_ref (widget);
514   
515   gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
516                       GTK_SIGNAL_FUNC (gtk_drag_selection_received), widget);
517
518   gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
519
520   gtk_selection_convert (selection_widget,
521                          gdk_drag_get_selection(context),
522                          target,
523                          time);
524 }
525
526
527 /*************************************************************
528  * gtk_drag_get_source_widget:
529  *     Get the widget the was the source of this drag, if
530  *     the drag originated from this application.
531  *   arguments:
532  *     context: The drag context for this drag
533  *   results:
534  *     The source widget, or NULL if the drag originated from
535  *     a different application.
536  *************************************************************/
537
538 GtkWidget *
539 gtk_drag_get_source_widget (GdkDragContext *context)
540 {
541   GSList *tmp_list;
542
543   tmp_list = source_widgets;
544   while (tmp_list)
545     {
546       GtkWidget *ipc_widget = tmp_list->data;
547       
548       if (ipc_widget->window == context->source_window)
549         {
550           GtkDragSourceInfo *info;
551           info = gtk_object_get_data (GTK_OBJECT (ipc_widget), "gtk-info");
552
553           return info ? info->widget : NULL;
554         }
555
556       tmp_list = tmp_list->next;
557     }
558
559   return NULL;
560 }
561
562 /*************************************************************
563  * gtk_drag_finish:
564  *     Notify the drag source that the transfer of data
565  *     is complete.
566  *   arguments:
567  *     context: The drag context for this drag
568  *     success: Was the data successfully transferred?
569  *     time:    The timestamp to use when notifying the destination.
570  *   results:
571  *************************************************************/
572
573 void 
574 gtk_drag_finish (GdkDragContext *context,
575                  gboolean        success,
576                  gboolean        del,
577                  guint32         time)
578 {
579   GdkAtom target = GDK_NONE;
580
581   g_return_if_fail (context != NULL);
582
583   if (success && del)
584     {
585       target = gdk_atom_intern ("DELETE", FALSE);
586     }
587   else if (context->protocol == GDK_DRAG_PROTO_MOTIF)
588     {
589       target = gdk_atom_intern (success ? 
590                                   "XmTRANSFER_SUCCESS" : 
591                                   "XmTRANSFER_FAILURE",
592                                 FALSE);
593     }
594
595   if (target != GDK_NONE)
596     {
597       GtkWidget *selection_widget = gtk_drag_get_ipc_widget();
598
599       gdk_drag_context_ref (context);
600       
601       gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
602       gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
603                           GTK_SIGNAL_FUNC (gtk_drag_selection_received),
604                           NULL);
605       
606       gtk_selection_convert (selection_widget,
607                              gdk_drag_get_selection(context),
608                              target,
609                              time);
610     }
611   
612   if (!del)
613     gdk_drop_finish (context, success, time);
614 }
615
616 /*************************************************************
617  * gtk_drag_highlight:
618  *     Highlight the given widget in the default manner.
619  *   arguments:
620  *     widget:
621  *   results:
622  *************************************************************/
623
624 void 
625 gtk_drag_highlight (GtkWidget  *widget)
626 {
627   gint x, y;
628
629   g_return_if_fail (widget != NULL);
630
631   if (GTK_WIDGET_NO_WINDOW (widget))
632     {
633       x = widget->allocation.x;
634       y = widget->allocation.y;
635     }
636   else
637     {
638       x = 0;
639       y = 0;
640     }
641         
642   gtk_draw_shadow (widget->style, widget->window,
643                    GTK_STATE_NORMAL, GTK_SHADOW_OUT,
644                    x, y, 
645                    widget->allocation.width,
646                    widget->allocation.height);
647
648   gdk_draw_rectangle (widget->window,
649                       widget->style->black_gc,
650                       FALSE,
651                       x, y,
652                       widget->allocation.width - 1,
653                       widget->allocation.height - 1);
654 }
655
656 /*************************************************************
657  * gtk_drag_unhighlight:
658  *     Refresh the given widget to remove the highlight.
659  *   arguments:
660  *     widget:
661  *   results:
662  *************************************************************/
663
664 void 
665 gtk_drag_unhighlight (GtkWidget  *widget)
666 {
667   gint x, y;
668
669   g_return_if_fail (widget != NULL);
670
671   if (GTK_WIDGET_NO_WINDOW (widget))
672     {
673       x = widget->allocation.x;
674       y = widget->allocation.y;
675     }
676   else
677     {
678       x = 0;
679       y = 0;
680     }
681         
682   gdk_window_clear_area_e (widget->window,
683                            x, y,
684                            widget->allocation.width,
685                            widget->allocation.height);
686 }
687
688 /*************************************************************
689  * gtk_drag_dest_set:
690  *     Register a drop site, and possibly add default behaviors.
691  *   arguments:
692  *     widget:    
693  *     flags:     Which types of default drag behavior to use
694  *     targets:   Table of targets that can be accepted
695  *     n_targets: Number of of entries in targets
696  *     actions:   
697  *   results:
698  *************************************************************/
699
700 void 
701 gtk_drag_dest_set   (GtkWidget       *widget,
702                      GtkDestDefaults  flags,
703                      GtkTargetEntry  *targets,
704                      gint             n_targets,
705                      GdkDragAction    actions)
706 {
707   GtkDragDestSite *site;
708   
709   g_return_if_fail (widget != NULL);
710
711   /* HACK, do this in the destroy */
712   site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
713   if (site)
714     gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
715
716   if (GTK_WIDGET_REALIZED (widget))
717     gtk_drag_dest_realized (widget);
718
719   gtk_signal_connect (GTK_OBJECT (widget), "realize",
720                       GTK_SIGNAL_FUNC (gtk_drag_dest_realized), NULL);
721
722   site = g_new (GtkDragDestSite, 1);
723
724   site->flags = flags;
725   site->have_drag = FALSE;
726   if (targets)
727     site->target_list = gtk_target_list_new (targets, n_targets);
728   else
729     site->target_list = NULL;
730
731   site->actions = actions;
732   site->do_proxy = FALSE;
733
734   gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
735                             site, gtk_drag_dest_site_destroy);
736 }
737
738 /*************************************************************
739  * gtk_drag_dest_set_proxy:
740  *     Set up this widget to proxy drags elsewhere.
741  *   arguments:
742  *     widget:          
743  *     proxy_window:    window to which forward drag events
744  *     protocol:        Drag protocol which the dest widget accepts
745  *     use_coordinates: If true, send the same coordinates to the
746  *                      destination, because it is a embedded 
747  *                      subwindow.
748  *   results:
749  *************************************************************/
750
751 void 
752 gtk_drag_dest_set_proxy (GtkWidget      *widget,
753                          GdkWindow      *proxy_window,
754                          GdkDragProtocol protocol,
755                          gboolean        use_coordinates)
756 {
757   GtkDragDestSite *site;
758   
759   g_return_if_fail (widget != NULL);
760
761   /* HACK, do this in the destroy */
762   site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
763   if (site)
764     gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
765
766   if (GTK_WIDGET_REALIZED (widget))
767     gtk_drag_dest_realized (widget);
768
769   gtk_signal_connect (GTK_OBJECT (widget), "realize",
770                       GTK_SIGNAL_FUNC (gtk_drag_dest_realized), NULL);
771
772   site = g_new (GtkDragDestSite, 1);
773
774   site->flags = 0;
775   site->have_drag = FALSE;
776   site->target_list = NULL;
777   site->actions = 0;
778   site->proxy_window = proxy_window;
779   if (proxy_window)
780     gdk_window_ref (proxy_window);
781   site->do_proxy = TRUE;
782   site->proxy_protocol = protocol;
783   site->proxy_coords = use_coordinates;
784
785   gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
786                             site, gtk_drag_dest_site_destroy);
787 }
788
789 /*************************************************************
790  * gtk_drag_dest_unset
791  *     Unregister this widget as a drag target.
792  *   arguments:
793  *     widget:
794  *   results:
795  *************************************************************/
796
797 void 
798 gtk_drag_dest_unset (GtkWidget        *widget)
799 {
800   g_return_if_fail (widget != NULL);
801
802   gtk_object_set_data (GTK_OBJECT (widget), "gtk-drag-dest", NULL);
803 }
804
805 /*************************************************************
806  * gtk_drag_dest_handle_event:
807  *     Called from widget event handling code on Drag events
808  *     for destinations.
809  *
810  *   arguments:
811  *     toplevel: Toplevel widget that received the event
812  *     event:
813  *   results:
814  *************************************************************/
815
816 void
817 gtk_drag_dest_handle_event (GtkWidget *toplevel,
818                             GdkEvent  *event)
819 {
820   GtkDragDestInfo *info;
821   GdkDragContext *context;
822
823   g_return_if_fail (toplevel != NULL);
824   g_return_if_fail (event != NULL);
825
826   context = event->dnd.context;
827
828   info = g_dataset_get_data (context, "gtk-info");
829   if (!info)
830     {
831       info = g_new (GtkDragDestInfo, 1);
832       info->widget = NULL;
833       info->context = event->dnd.context;
834       info->proxy_source = NULL;
835       info->proxy_data = NULL;
836       info->dropped = FALSE;
837       info->proxy_drop_wait = FALSE;
838       g_dataset_set_data_full (context,
839                                "gtk-info",
840                                info,
841                                gtk_drag_dest_info_destroy);
842     }
843
844   /* Find the widget for the event */
845   switch (event->type)
846     {
847     case GDK_DRAG_ENTER:
848       break;
849       
850     case GDK_DRAG_LEAVE:
851       if (info->widget)
852         {
853           gtk_drag_dest_leave (info->widget, context, event->dnd.time);
854           info->widget = NULL;
855         }
856       break;
857       
858     case GDK_DRAG_MOTION:
859     case GDK_DROP_START:
860       {
861         GtkDragFindData data;
862         gint tx, ty;
863
864         if (event->type == GDK_DROP_START)
865           info->dropped = TRUE;
866
867         gdk_window_get_position (toplevel->window, &tx, &ty);
868
869         data.x = event->dnd.x_root - tx;
870         data.y = event->dnd.y_root - ty;
871         data.context = context;
872         data.info = info;
873         data.found = FALSE;
874         data.toplevel = TRUE;
875         data.callback = (event->type == GDK_DRAG_MOTION) ?
876           gtk_drag_dest_motion : gtk_drag_dest_drop;
877         data.time = event->dnd.time;
878         
879         gtk_drag_find_widget (toplevel, &data);
880
881         /* We send a leave here so that the widget unhighlights
882          * properly
883          */
884         if (info->widget &&
885             ((event->type == GDK_DROP_START) || (!data.found)))
886           {
887             gtk_drag_dest_leave (info->widget, context, event->dnd.time);
888             info->widget = NULL;
889           }
890         
891         /* Send a reply.
892          */
893         if (event->type == GDK_DRAG_MOTION)
894           {
895             if (!data.found)
896               gdk_drag_status (context, 0, event->dnd.time);
897           }
898         else if (event->type == GDK_DROP_START)
899           gdk_drop_reply (context, data.found, event->dnd.time);
900       }
901       break;
902
903     default:
904       g_assert_not_reached();
905     }
906 }
907
908 /*************************************************************
909  * gtk_drag_dest_find_target:
910  *     Decide on a target for the drag.
911  *   arguments:
912  *     site:
913  *     context:
914  *   results:
915  *************************************************************/
916
917 static GdkAtom
918 gtk_drag_dest_find_target (GtkWidget       *widget,
919                            GtkDragDestSite *site,
920                            GdkDragContext  *context)
921 {
922   GList *tmp_target;
923   GList *tmp_source = NULL;
924   GtkWidget *source_widget = gtk_drag_get_source_widget (context);
925
926   tmp_target = site->target_list->list;
927   while (tmp_target)
928     {
929       GtkTargetPair *pair = tmp_target->data;
930       tmp_source = context->targets;
931       while (tmp_source)
932         {
933           if (tmp_source->data == GUINT_TO_POINTER (pair->target))
934             {
935               if ((!(pair->flags & GTK_TARGET_SAME_APP) || source_widget) &&
936                   (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget)))
937                 return pair->target;
938               else
939                 break;
940             }
941           tmp_source = tmp_source->next;
942         }
943       tmp_target = tmp_target->next;
944     }
945
946   return GDK_NONE;
947 }
948
949 static void
950 gtk_drag_selection_received (GtkWidget          *widget,
951                              GtkSelectionData   *selection_data,
952                              guint32             time,
953                              gpointer            data)
954 {
955   GdkDragContext *context;
956   GtkDragDestInfo *info;
957   GtkWidget *drop_widget;
958
959   drop_widget = data;
960
961   context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
962   info = g_dataset_get_data (context, "gtk-info");
963
964   if (info->proxy_data && 
965       info->proxy_data->target == selection_data->target)
966     {
967       gtk_selection_data_set (info->proxy_data,
968                               selection_data->type,
969                               selection_data->format,
970                               selection_data->data,
971                               selection_data->length);
972       gtk_main_quit();
973       return;
974     }
975
976   if (selection_data->target == gdk_atom_intern ("DELETE", FALSE))
977     {
978       gtk_drag_finish (context, TRUE, FALSE, time);
979     }
980   else if ((selection_data->target == gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE)) ||
981            (selection_data->target == gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE)))
982     {
983       /* Do nothing */
984     }
985   else
986     {
987       GtkDragDestSite *site;
988
989       site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest");
990
991       if (site->target_list)
992         {
993           guint target_info;
994
995           if (gtk_target_list_find (site->target_list, 
996                                     selection_data->target,
997                                     &target_info))
998             {
999               if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
1000                   selection_data->length >= 0)
1001                 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget), 
1002                                          "drag_data_received",
1003                                          context, info->drop_x, info->drop_y,
1004                                          selection_data, 
1005                                          target_info, time);
1006             }
1007         }
1008       else
1009         {
1010           gtk_signal_emit_by_name (GTK_OBJECT (drop_widget), 
1011                                    "drag_data_received",
1012                                    context, info->drop_x, info->drop_y,
1013                                    selection_data, 0, time);
1014         }
1015       
1016       if (site->flags & GTK_DEST_DEFAULT_DROP)
1017         {
1018
1019           gtk_drag_finish (context, 
1020                            (selection_data->length >= 0),
1021                            (context->action == GDK_ACTION_MOVE),
1022                            time);
1023         }
1024       
1025       gtk_widget_unref (drop_widget);
1026     }
1027
1028   gtk_signal_disconnect_by_func (GTK_OBJECT (widget), 
1029                                  GTK_SIGNAL_FUNC (gtk_drag_selection_received),
1030                                  data);
1031   
1032   gtk_object_set_data (GTK_OBJECT (widget), "drag-context", NULL);
1033   gdk_drag_context_unref (context);
1034
1035   gtk_drag_release_ipc_widget (widget);
1036 }
1037
1038 /*************************************************************
1039  * gtk_drag_find_widget:
1040  *     Recursive callback used to locate widgets for 
1041  *     DRAG_MOTION and DROP_START events.
1042  *   arguments:
1043  *     
1044  *   results:
1045  *************************************************************/
1046
1047 static void
1048 gtk_drag_find_widget (GtkWidget       *widget,
1049                       GtkDragFindData *data)
1050 {
1051   GtkAllocation new_allocation;
1052   gint x_offset = 0;
1053   gint y_offset = 0;
1054
1055   new_allocation = widget->allocation;
1056
1057   if (!GTK_WIDGET_VISIBLE (widget))
1058     return;
1059
1060   if (!GTK_WIDGET_NO_WINDOW (widget))
1061     {
1062       new_allocation.x = 0;
1063       new_allocation.y = 0;
1064     }
1065   
1066   if (widget->parent)
1067     {
1068       GdkWindow *window = widget->window;
1069       while (window != widget->parent->window)
1070         {
1071           gint tx, ty, twidth, theight;
1072           gdk_window_get_size (window, &twidth, &theight);
1073
1074           if (new_allocation.x < 0)
1075             {
1076               new_allocation.width += new_allocation.x;
1077               new_allocation.x = 0;
1078             }
1079           if (new_allocation.y < 0)
1080             {
1081               new_allocation.height += new_allocation.y;
1082               new_allocation.y = 0;
1083             }
1084           if (new_allocation.x + new_allocation.width > twidth)
1085             new_allocation.width = twidth - new_allocation.x;
1086           if (new_allocation.y + new_allocation.height > theight)
1087             new_allocation.height = theight - new_allocation.y;
1088
1089           gdk_window_get_position (window, &tx, &ty);
1090           new_allocation.x += tx;
1091           x_offset += tx;
1092           new_allocation.y += ty;
1093           y_offset += ty;
1094           
1095           window = gdk_window_get_parent (window);
1096         }
1097     }
1098
1099   if (data->toplevel ||
1100       ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
1101        (data->x < new_allocation.x + new_allocation.width) && 
1102        (data->y < new_allocation.y + new_allocation.height)))
1103     {
1104       /* First, check if the drag is in a valid drop site in
1105        * one of our children 
1106        */
1107       if (GTK_IS_CONTAINER (widget))
1108         {
1109           GtkDragFindData new_data = *data;
1110           
1111           new_data.x -= x_offset;
1112           new_data.y -= y_offset;
1113           new_data.found = FALSE;
1114           new_data.toplevel = FALSE;
1115           
1116           gtk_container_foreach (GTK_CONTAINER (widget),
1117                                  (GtkCallback)gtk_drag_find_widget,
1118                                  &new_data);
1119           
1120           data->found = new_data.found;
1121         }
1122
1123       /* If not, and this widget is registered as a drop site, check to
1124        * emit "drag_motion" to check if we are actually in
1125        * a drop site.
1126        */
1127       if (!data->found &&
1128           gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"))
1129         {
1130           data->found = data->callback (widget,
1131                                         data->context,
1132                                         data->x - new_allocation.x,
1133                                         data->y - new_allocation.y,
1134                                         data->time);
1135           /* If so, send a "drag_leave" to the last widget */
1136           if (data->found)
1137             {
1138               if (data->info->widget && data->info->widget != widget)
1139                 {
1140                   gtk_drag_dest_leave (data->info->widget, data->context, data->time);
1141                 }
1142               data->info->widget = widget;
1143             }
1144         }
1145     }
1146 }
1147
1148 static void
1149 gtk_drag_proxy_begin (GtkWidget *widget, GtkDragDestInfo *dest_info)
1150 {
1151   GtkDragSourceInfo *source_info;
1152   GList *tmp_list;
1153   
1154   source_info = g_new0 (GtkDragSourceInfo, 1);
1155   source_info->ipc_widget = gtk_drag_get_ipc_widget ();
1156   
1157   source_info->widget = widget;
1158   gtk_widget_ref (source_info->widget);
1159   source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
1160                                          dest_info->context->targets, 
1161                                          dest_info->context->actions);
1162
1163   source_info->target_list = gtk_target_list_new (NULL, 0);
1164   tmp_list = dest_info->context->targets;
1165   while (tmp_list)
1166     {
1167       gtk_target_list_add (source_info->target_list, 
1168                            GPOINTER_TO_UINT (tmp_list->data), 0, 0);
1169       tmp_list = tmp_list->next;
1170     }
1171
1172   source_info->proxy_dest = dest_info;
1173   
1174   g_dataset_set_data (source_info->context, "gtk-info", source_info);
1175   
1176   gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget), 
1177                       "selection_get",
1178                       GTK_SIGNAL_FUNC (gtk_drag_selection_get), 
1179                       source_info);
1180   
1181   dest_info->proxy_source = source_info;
1182 }
1183
1184 static void
1185 gtk_drag_dest_info_destroy (gpointer data)
1186 {
1187   GtkDragDestInfo *info = data;
1188
1189   g_free (info);
1190 }
1191
1192 static void
1193 gtk_drag_dest_realized (GtkWidget *widget)
1194 {
1195   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1196   gdk_window_register_dnd (toplevel->window);
1197 }
1198
1199 static void
1200 gtk_drag_dest_site_destroy (gpointer data)
1201 {
1202   GtkDragDestSite *site = data;
1203
1204   if (site->target_list)
1205     gtk_target_list_unref (site->target_list);
1206
1207   g_free (site);
1208 }
1209
1210 /*
1211  * Default drag handlers
1212  */
1213 static void  
1214 gtk_drag_dest_leave (GtkWidget      *widget,
1215                      GdkDragContext *context,
1216                      guint           time)
1217 {
1218   GtkDragDestSite *site;
1219
1220   site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1221   g_return_if_fail (site != NULL);
1222
1223   if (site->do_proxy)
1224     {
1225       GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1226
1227       if (info->proxy_source && !info->dropped)
1228         gdk_drag_abort (info->proxy_source->context, time);
1229       
1230       return;
1231     }
1232   else
1233     {
1234       if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1235         gtk_drag_unhighlight (widget);
1236
1237       if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag)
1238         gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_leave",
1239                                  context, time);
1240       
1241       site->have_drag = FALSE;
1242     }
1243 }
1244
1245 static gboolean
1246 gtk_drag_dest_motion (GtkWidget      *widget,
1247                       GdkDragContext *context,
1248                       gint            x,
1249                       gint            y,
1250                       guint           time)
1251 {
1252   GtkDragDestSite *site;
1253   GdkDragAction action = 0;
1254   gboolean retval;
1255
1256   site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1257   g_return_val_if_fail (site != NULL, FALSE);
1258
1259   if (site->do_proxy)
1260     {
1261       GdkAtom selection;
1262       GdkEvent *current_event;
1263       GdkWindow *dest_window;
1264       GdkDragProtocol proto;
1265         
1266       GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1267
1268       if (!info->proxy_source)
1269         gtk_drag_proxy_begin (widget, info);
1270
1271       current_event = gtk_get_current_event ();
1272
1273       if (site->proxy_window)
1274         {
1275           dest_window = site->proxy_window;
1276           proto = site->proxy_protocol;
1277         }
1278       else
1279         {
1280           gdk_drag_find_window (info->proxy_source->context,
1281                                 NULL,
1282                                 current_event->dnd.x_root, 
1283                                 current_event->dnd.y_root,
1284                                 &dest_window, &proto);
1285         }
1286       
1287       gdk_drag_motion (info->proxy_source->context, 
1288                        dest_window, proto,
1289                        current_event->dnd.x_root, 
1290                        current_event->dnd.y_root, 
1291                        context->suggested_action, time);
1292
1293       selection = gdk_drag_get_selection (info->proxy_source->context);
1294       if (selection && 
1295           selection != gdk_drag_get_selection (info->context))
1296         gtk_drag_source_check_selection (info->proxy_source, selection, time);
1297
1298       gdk_event_free (current_event);
1299       
1300       return TRUE;
1301     }
1302
1303   if (site->flags & GTK_DEST_DEFAULT_MOTION)
1304     {
1305       if (context->suggested_action & site->actions)
1306         action = context->suggested_action;
1307       else
1308         {
1309           gint i;
1310           
1311           for (i=0; i<8; i++)
1312             {
1313               if ((site->actions & (1 << i)) &&
1314                   (context->actions & (1 << i)))
1315                 {
1316                   action = (1 << i);
1317                   break;
1318                 }
1319             }
1320         }
1321       
1322       if (action && gtk_drag_dest_find_target (widget, site, context))
1323         {
1324           if (!site->have_drag)
1325             {
1326               site->have_drag = TRUE;
1327               if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1328                 gtk_drag_highlight (widget);
1329             }
1330           
1331           gdk_drag_status (context, action, time);
1332         }
1333       else
1334         {
1335           gdk_drag_status (context, 0, time);
1336           return TRUE;
1337         }
1338     }
1339
1340   gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_motion",
1341                            context, x, y, time, &retval);
1342
1343   return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1344 }
1345
1346 static gboolean
1347 gtk_drag_dest_drop (GtkWidget        *widget,
1348                     GdkDragContext   *context,
1349                     gint              x,
1350                     gint              y,
1351                     guint             time)
1352 {
1353   GtkDragDestSite *site;
1354   GtkDragDestInfo *info;
1355
1356   site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1357   g_return_val_if_fail (site != NULL, FALSE);
1358
1359   info = g_dataset_get_data (context, "gtk-info");
1360   g_return_val_if_fail (info != NULL, FALSE);
1361
1362   info->drop_x = x;
1363   info->drop_y = y;
1364
1365   if (site->do_proxy)
1366     {
1367       if (info->proxy_source || 
1368           (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN))
1369         {
1370           gtk_drag_drop (info->proxy_source, time);
1371         }
1372       else
1373         {
1374           /* We need to synthesize a motion event, wait for a status,
1375            * and, if we get one a good one, do a drop.
1376            */
1377           
1378           GdkEvent *current_event;
1379           GdkAtom selection;
1380           GdkWindow *dest_window;
1381           GdkDragProtocol proto;
1382           
1383           gtk_drag_proxy_begin (widget, info);
1384           info->proxy_drop_wait = TRUE;
1385           info->proxy_drop_time = time;
1386           
1387           current_event = gtk_get_current_event ();
1388
1389           if (site->proxy_window)
1390             {
1391               dest_window = site->proxy_window;
1392               proto = site->proxy_protocol;
1393             }
1394           else
1395             {
1396               gdk_drag_find_window (info->proxy_source->context,
1397                                     NULL,
1398                                     current_event->dnd.x_root, 
1399                                     current_event->dnd.y_root,
1400                                     &dest_window, &proto);
1401             }
1402             
1403           gdk_drag_motion (info->proxy_source->context, 
1404                            dest_window, proto,
1405                            current_event->dnd.x_root, 
1406                            current_event->dnd.y_root, 
1407                            context->suggested_action, time);
1408
1409           selection = gdk_drag_get_selection (info->proxy_source->context);
1410           if (selection && 
1411               selection != gdk_drag_get_selection (info->context))
1412             gtk_drag_source_check_selection (info->proxy_source, selection, time);
1413
1414           gdk_event_free (current_event);
1415       
1416         }
1417
1418       return TRUE;
1419     }
1420   else
1421     {
1422       gboolean retval;
1423
1424       if (site->flags & GTK_DEST_DEFAULT_MOTION)
1425         {
1426           GdkAtom target = gtk_drag_dest_find_target (widget, site, context);
1427       
1428           if (target == GDK_NONE)
1429             return FALSE;
1430           
1431           gtk_drag_get_data (widget, context, target, time);
1432         }
1433
1434       gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_drop",
1435                                context, x, y, time, &retval);
1436
1437       return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1438     }
1439 }
1440
1441 /***************
1442  * Source side *
1443  ***************/
1444
1445 /*************************************************************
1446  * gtk_drag_begin: Start a drag operation
1447  *     
1448  *   arguments:
1449  *     widget:   Widget from which drag starts
1450  *     handlers: List of handlers to supply the data for the drag
1451  *     button:   Button user used to start drag
1452  *     time:     Time of event starting drag
1453  *
1454  *   results:
1455  *************************************************************/
1456
1457 GdkDragContext *
1458 gtk_drag_begin (GtkWidget         *widget,
1459                 GtkTargetList     *target_list,
1460                 GdkDragAction      actions,
1461                 gint               button,
1462                 GdkEvent          *event)
1463 {
1464   GtkDragSourceInfo *info;
1465   GList *targets = NULL;
1466   GList *tmp_list;
1467   guint32 time = GDK_CURRENT_TIME;
1468
1469   g_return_val_if_fail (widget != NULL, NULL);
1470   g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
1471   g_return_val_if_fail (target_list != NULL, NULL);
1472
1473   if (event)
1474     time = gdk_event_get_time (event);
1475
1476   info = g_new0 (GtkDragSourceInfo, 1);
1477   info->ipc_widget = gtk_drag_get_ipc_widget ();
1478   source_widgets = g_slist_prepend (source_widgets, info->ipc_widget);
1479
1480   gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
1481
1482   tmp_list = g_list_last (target_list->list);
1483   while (tmp_list)
1484     {
1485       GtkTargetPair *pair = tmp_list->data;
1486       targets = g_list_prepend (targets, 
1487                                 GINT_TO_POINTER (pair->target));
1488       tmp_list = tmp_list->prev;
1489     }
1490
1491   info->widget = widget;
1492   gtk_widget_ref (info->widget);
1493   
1494   info->context = gdk_drag_begin (info->ipc_widget->window,
1495                                   targets, actions);
1496   g_list_free (targets);
1497   
1498   g_dataset_set_data (info->context, "gtk-info", info);
1499
1500   info->button = button;
1501   info->target_list = target_list;
1502   gtk_target_list_ref (target_list);
1503
1504   info->cursor = NULL;
1505   info->status = GTK_DRAG_STATUS_DRAG;
1506   info->last_event = NULL;
1507   info->selections = NULL;
1508   info->icon_window = NULL;
1509   
1510   if (event)
1511     info->cursor = gtk_drag_get_cursor (
1512             gtk_drag_get_event_action (event, info->button, actions));
1513
1514   gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
1515                            info->context);
1516   
1517   /* We use a GTK grab here to override any grabs that the widget
1518    * we are dragging from might have held
1519    */
1520
1521   gtk_grab_add (info->ipc_widget);
1522   gdk_pointer_grab (info->ipc_widget->window, FALSE,
1523                     GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1524                     GDK_BUTTON_RELEASE_MASK, NULL,
1525                     info->cursor, time);
1526
1527   if (event->type == GDK_MOTION_NOTIFY)
1528     gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
1529   else 
1530     {
1531       gint x, y;
1532       gdk_window_get_pointer (GDK_ROOT_PARENT(), &x, &y, NULL);
1533
1534       info->cur_x = x;
1535       info->cur_y = y;
1536
1537       if (info->icon_window)
1538         {
1539           gdk_window_raise (info->icon_window->window);
1540           gtk_widget_set_uposition (info->icon_window, x - info->hot_x, y - info->hot_y);
1541         }
1542     }
1543
1544   info->start_x = info->cur_x;
1545   info->start_y = info->cur_y;
1546
1547   gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "button_release_event",
1548                       GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info);
1549   gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "motion_notify_event",
1550                       GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info);
1551   gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "selection_get",
1552                       GTK_SIGNAL_FUNC (gtk_drag_selection_get), info);
1553
1554   return info->context;
1555 }
1556
1557 /*************************************************************
1558  * gtk_drag_source_set:
1559  *     Register a drop site, and possibly add default behaviors.
1560  *   arguments:
1561  *     widget:
1562  *     start_button_mask: Mask of allowed buttons to start drag
1563  *     targets:           Table of targets for this source
1564  *     n_targets:
1565  *     actions:           Actions allowed for this source
1566  *   results:
1567  *************************************************************/
1568
1569 void 
1570 gtk_drag_source_set  (GtkWidget         *widget,
1571                       GdkModifierType    start_button_mask,
1572                       GtkTargetEntry    *targets,
1573                       gint               n_targets,
1574                       GdkDragAction      actions)
1575 {
1576   GtkDragSourceSite *site;
1577
1578   g_return_if_fail (widget != NULL);
1579
1580   site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1581
1582   gtk_widget_add_events (widget,
1583                          gtk_widget_get_events (widget) |
1584                          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1585                          GDK_BUTTON_MOTION_MASK);
1586
1587   if (site)
1588     {
1589       if (site->target_list)
1590         gtk_target_list_unref (site->target_list);
1591     }
1592   else
1593     {
1594       site = g_new0 (GtkDragSourceSite, 1);
1595       
1596       gtk_signal_connect (GTK_OBJECT (widget), "button_press_event",
1597                           GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1598                           site);
1599       gtk_signal_connect (GTK_OBJECT (widget), "motion_notify_event",
1600                           GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1601                           site);
1602       
1603       gtk_object_set_data_full (GTK_OBJECT (widget),
1604                                 "gtk-site-data", 
1605                                 site, gtk_drag_source_site_destroy);
1606     }
1607
1608   site->start_button_mask = start_button_mask;
1609
1610   if (targets)
1611     site->target_list = gtk_target_list_new (targets, n_targets);
1612   else
1613     site->target_list = NULL;
1614
1615   site->actions = actions;
1616
1617 }
1618
1619 /*************************************************************
1620  * gtk_drag_source_set_icon:
1621  *     Set an icon for drags from this source.
1622  *   arguments:
1623  *     colormap: Colormap for this icon
1624  *     pixmap:
1625  *     mask
1626  *   results:
1627  *************************************************************/
1628
1629 void 
1630 gtk_drag_source_set_icon  (GtkWidget     *widget,
1631                            GdkColormap   *colormap,
1632                            GdkPixmap     *pixmap,
1633                            GdkBitmap     *mask)
1634 {
1635   GtkDragSourceSite *site;
1636
1637   g_return_if_fail (widget != NULL);
1638
1639   site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1640   g_return_if_fail (site != NULL);
1641   
1642   if (site->colormap)
1643     gdk_colormap_unref (site->colormap);
1644   if (site->pixmap)
1645     gdk_pixmap_unref (site->pixmap);
1646   if (site->mask)
1647     gdk_pixmap_unref (site->mask);
1648
1649   site->colormap = colormap;
1650   if (colormap)
1651     gdk_colormap_ref (colormap);
1652
1653   site->pixmap = pixmap;
1654   if (pixmap)
1655     gdk_pixmap_ref (pixmap);
1656
1657   site->mask = mask;
1658   if (mask)
1659     gdk_pixmap_ref (mask);
1660 }
1661
1662 /*************************************************************
1663  * gtk_drag_set_icon_widget:
1664  *     Set a widget as the icon for a drag.
1665  *   arguments:
1666  *     context:
1667  *     widget:
1668  *     hot_x:    Hot spot
1669  *     hot_y:
1670  *   results:
1671  *************************************************************/
1672
1673 void 
1674 gtk_drag_set_icon_widget  (GdkDragContext    *context,
1675                            GtkWidget         *widget,
1676                            gint               hot_x,
1677                            gint               hot_y)
1678 {
1679   GtkDragSourceInfo *info;
1680
1681   g_return_if_fail (context != NULL);
1682   g_return_if_fail (widget != NULL);
1683
1684   info = g_dataset_get_data (context, "gtk-info");
1685   gtk_drag_remove_icon (info);
1686   
1687   info->icon_window = widget;
1688   if (widget)
1689     {
1690       gtk_widget_set_uposition (widget, info->cur_x, info->cur_y);      
1691       gtk_widget_ref (widget);
1692       gdk_window_raise (widget->window);
1693       gtk_widget_show (widget);
1694     }
1695
1696   info->hot_x = hot_x;
1697   info->hot_y = hot_y;
1698 }
1699
1700 /*************************************************************
1701  * gtk_drag_set_icon_pixmap:
1702  *     Set a widget as the icon for a drag.
1703  *   arguments:
1704  *     context:
1705  *     colormap: Colormap for the icon window.
1706  *     pixmap:   
1707  *     mask:
1708  *     hot_x:    Hot spot
1709  *     hot_y:
1710  *   results:
1711  *************************************************************/
1712
1713 void 
1714 gtk_drag_set_icon_pixmap  (GdkDragContext    *context,
1715                            GdkColormap       *colormap,
1716                            GdkPixmap         *pixmap,
1717                            GdkBitmap         *mask,
1718                            gint               hot_x,
1719                            gint               hot_y)
1720 {
1721   GtkWidget *window;
1722   gint width, height;
1723       
1724   g_return_if_fail (context != NULL);
1725   g_return_if_fail (colormap != NULL);
1726   g_return_if_fail (pixmap != NULL);
1727
1728   gdk_window_get_size (pixmap, &width, &height);
1729
1730   gtk_widget_push_visual (gdk_colormap_get_visual(colormap));
1731   gtk_widget_push_colormap (colormap);
1732
1733   window = gtk_draw_window_new (GTK_WINDOW_POPUP);
1734
1735   gtk_widget_pop_visual ();
1736   gtk_widget_pop_colormap ();
1737
1738   gtk_widget_set_usize (window, width, height);
1739   gtk_widget_realize (window);
1740
1741   gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
1742   
1743   if (mask)
1744     gtk_widget_shape_combine_mask (window, mask, 0, 0);
1745
1746   gtk_drag_set_icon_widget (context, window, hot_x, hot_y);
1747 }
1748
1749 /*************************************************************
1750  * gtk_drag_set_icon_default:
1751  *     Set the icon for a drag to the default icon.
1752  *   arguments:
1753  *     context:
1754  *   results:
1755  *************************************************************/
1756
1757 void 
1758 gtk_drag_set_icon_default (GdkDragContext    *context)
1759 {
1760   g_return_if_fail (context != NULL);
1761
1762   if (!default_icon_pixmap)
1763     {
1764       default_icon_colormap = gdk_colormap_get_system ();
1765       default_icon_pixmap = 
1766         gdk_pixmap_colormap_create_from_xpm_d (NULL,
1767                                                default_icon_colormap,
1768                                                &default_icon_mask,
1769                                                NULL, drag_default_xpm);
1770       default_icon_hot_x = -2;
1771       default_icon_hot_y = -2;
1772     }
1773
1774   gtk_drag_set_icon_pixmap (context, 
1775                             default_icon_colormap, 
1776                             default_icon_pixmap, 
1777                             default_icon_mask,
1778                             default_icon_hot_x,
1779                             default_icon_hot_y);
1780 }
1781
1782 /*************************************************************
1783  * gtk_drag_set_default_icon:
1784  *     Set a default icon for all drags as a pixmap.
1785  *   arguments:
1786  *     colormap: Colormap for the icon window.
1787  *     pixmap:   
1788  *     mask:
1789  *     hot_x:    Hot spot
1790  *     hot_y:
1791  *   results:
1792  *************************************************************/
1793
1794 void 
1795 gtk_drag_set_default_icon (GdkColormap   *colormap,
1796                            GdkPixmap     *pixmap,
1797                            GdkBitmap     *mask,
1798                            gint           hot_x,
1799                            gint           hot_y)
1800 {
1801   g_return_if_fail (colormap != NULL);
1802   g_return_if_fail (pixmap != NULL);
1803   
1804   if (default_icon_colormap)
1805     gdk_colormap_unref (default_icon_colormap);
1806   if (default_icon_pixmap)
1807     gdk_pixmap_unref (default_icon_pixmap);
1808   if (default_icon_mask)
1809     gdk_pixmap_unref (default_icon_pixmap);
1810
1811   default_icon_colormap = colormap;
1812   gdk_colormap_ref (colormap);
1813   
1814   default_icon_pixmap = pixmap;
1815   gdk_pixmap_ref (pixmap);
1816
1817   default_icon_mask = mask;
1818   if (mask)
1819     gdk_pixmap_ref (mask);
1820   
1821   default_icon_hot_x = hot_x;
1822   default_icon_hot_y = hot_y;
1823 }
1824
1825
1826 /*************************************************************
1827  * gtk_drag_source_handle_event:
1828  *     Called from widget event handling code on Drag events
1829  *     for drag sources.
1830  *
1831  *   arguments:
1832  *     toplevel: Toplevel widget that received the event
1833  *     event:
1834  *   results:
1835  *************************************************************/
1836
1837 void
1838 gtk_drag_source_handle_event (GtkWidget *widget,
1839                               GdkEvent  *event)
1840 {
1841   GtkDragSourceInfo *info;
1842   GdkDragContext *context;
1843
1844   g_return_if_fail (widget != NULL);
1845   g_return_if_fail (event != NULL);
1846
1847   context = event->dnd.context;
1848   info = g_dataset_get_data (context, "gtk-info");
1849   if (!info)
1850     return;
1851
1852   switch (event->type)
1853     {
1854     case GDK_DRAG_STATUS:
1855       {
1856         GdkCursor *cursor;
1857
1858         if (info->proxy_dest)
1859           {
1860             if (!event->dnd.send_event)
1861               {
1862                 if (info->proxy_dest->proxy_drop_wait)
1863                   {
1864                     /* Aha - we can finally pass the MOTIF DROP on... */
1865                     gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
1866                   }
1867                 else
1868                   {
1869                     gdk_drag_status (info->proxy_dest->context,
1870                                      event->dnd.context->action,
1871                                      event->dnd.time);
1872                   }
1873               }
1874           }
1875         else
1876           {
1877             cursor = gtk_drag_get_cursor (event->dnd.context->action);
1878             if (info->cursor != cursor)
1879               {
1880                 XChangeActivePointerGrab (GDK_WINDOW_XDISPLAY (widget->window), 
1881                                           PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask,
1882                                           ((GdkCursorPrivate *)cursor)->xcursor,
1883                                           event->dnd.time);
1884                 info->cursor = cursor;
1885               }
1886             
1887             if (info->last_event)
1888               {
1889                 gtk_drag_motion_cb (info->widget, 
1890                                     (GdkEventMotion *)info->last_event, 
1891                                     info);
1892                 info->last_event = NULL;
1893               }
1894           }
1895       }
1896       break;
1897       
1898     case GDK_DROP_FINISHED:
1899       gtk_drag_drop_finished (info, TRUE, event->dnd.time);
1900       break;
1901     default:
1902       g_assert_not_reached();
1903     }
1904 }
1905
1906 /*************************************************************
1907  * gtk_drag_source_check_selection:
1908  *     Check if we've set up handlers/claimed the selection
1909  *     for a given drag. If not, add them.
1910  *   arguments:
1911  *     
1912  *   results:
1913  *************************************************************/
1914
1915 static void
1916 gtk_drag_source_check_selection (GtkDragSourceInfo *info, 
1917                                  GdkAtom            selection,
1918                                  guint32            time)
1919 {
1920   GList *tmp_list;
1921
1922   tmp_list = info->selections;
1923   while (tmp_list)
1924     {
1925       if (GPOINTER_TO_UINT (tmp_list->data) == selection)
1926         return;
1927       tmp_list = tmp_list->next;
1928     }
1929
1930   gtk_selection_owner_set (info->ipc_widget, selection, time);
1931   info->selections = g_list_prepend (info->selections,
1932                                      GUINT_TO_POINTER (selection));
1933
1934   tmp_list = info->target_list->list;
1935   while (tmp_list)
1936     {
1937       GtkTargetPair *pair = tmp_list->data;
1938
1939       gtk_selection_add_target (info->ipc_widget,
1940                                 selection,
1941                                 pair->target,
1942                                 pair->info);
1943       tmp_list = tmp_list->next;
1944     }
1945   
1946   if (info->context->protocol == GDK_DRAG_PROTO_MOTIF)
1947     {
1948       gtk_selection_add_target (info->ipc_widget,
1949                                 selection,
1950                                 gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE),
1951                                 TARGET_MOTIF_SUCCESS);
1952       gtk_selection_add_target (info->ipc_widget,
1953                                 selection,
1954                                 gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE),
1955                                 TARGET_MOTIF_FAILURE);
1956     }
1957
1958   gtk_selection_add_target (info->ipc_widget,
1959                             selection,
1960                             gdk_atom_intern ("DELETE", FALSE),
1961                             TARGET_DELETE);
1962 }
1963
1964 /*************************************************************
1965  * gtk_drag_drop_finished:
1966  *     Clean up from the drag, and display snapback, if necessary.
1967  *   arguments:
1968  *     info:
1969  *     success:
1970  *     time:
1971  *   results:
1972  *************************************************************/
1973
1974 static void
1975 gtk_drag_drop_finished (GtkDragSourceInfo *info,
1976                         gboolean           success,
1977                         guint              time)
1978 {
1979   if (info->proxy_dest)
1980     {
1981       /* The time from the event isn't reliable for Xdnd drags */
1982       gtk_drag_finish (info->proxy_dest->context, success, FALSE, 
1983                        info->proxy_dest->proxy_drop_time);
1984     }
1985   else
1986     {
1987       if (success)
1988         {
1989           gtk_drag_source_info_destroy (info);
1990         }
1991       else
1992         {
1993           GtkDragAnim *anim = g_new (GtkDragAnim, 1);
1994           anim->info = info;
1995           anim->step = 0;
1996           
1997           anim->n_steps = MAX (info->cur_x - info->start_x,
1998                                info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
1999           anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
2000           if (info->icon_window)
2001             {
2002               gtk_widget_show(info->icon_window);
2003               gdk_window_raise (info->icon_window->window);
2004             }
2005           
2006           gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
2007         }
2008     }
2009
2010   gtk_drag_source_release_selections (info, GDK_CURRENT_TIME); /* fixme */
2011 }
2012
2013 static void
2014 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
2015                                     guint32            time)
2016 {
2017   GList *tmp_list = info->selections;
2018   while (tmp_list)
2019     {
2020       GdkAtom selection = GPOINTER_TO_UINT (tmp_list->data);
2021       if (gdk_selection_owner_get (selection) == info->ipc_widget->window)
2022         gtk_selection_owner_set (NULL, selection, time);
2023       tmp_list = tmp_list->next;
2024     }
2025
2026   g_list_free (info->selections);
2027   info->selections = NULL;
2028 }
2029
2030 /*************************************************************
2031  * gtk_drag_drop:
2032  *     Send a drop event.
2033  *   arguments:
2034  *     
2035  *   results:
2036  *************************************************************/
2037
2038 static void
2039 gtk_drag_drop (GtkDragSourceInfo *info, guint32 time)
2040 {
2041   if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN)
2042     {
2043       GtkSelectionData selection_data;
2044       GList *tmp_list;
2045       GdkAtom target = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
2046       
2047       tmp_list = info->target_list->list;
2048       while (tmp_list)
2049         {
2050           GtkTargetPair *pair = tmp_list->data;
2051           
2052           if (pair->target == target)
2053             {
2054               selection_data.selection = GDK_NONE;
2055               selection_data.target = target;
2056               selection_data.data = NULL;
2057               selection_data.length = -1;
2058               
2059               gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2060                                        info->context, &selection_data,
2061                                        pair->info, 
2062                                        time);
2063               
2064               /* FIXME: Should we check for length >= 0 here? */
2065               gtk_drag_drop_finished (info, TRUE, time);
2066               return;
2067             }
2068           tmp_list = tmp_list->next;
2069         }
2070       gtk_drag_drop_finished (info, FALSE, time);
2071     }
2072   else
2073     {
2074       if (info->icon_window)
2075         gtk_widget_hide (info->icon_window);
2076         
2077       gdk_drag_drop (info->context, time);
2078       info->drop_timeout = gtk_timeout_add (DROP_ABORT_TIME,
2079                                             gtk_drag_abort_timeout,
2080                                             info);
2081     }
2082 }
2083
2084 /*
2085  * Source side callbacks.
2086  */
2087
2088 static gint
2089 gtk_drag_source_event_cb (GtkWidget      *widget,
2090                           GdkEvent       *event,
2091                           gpointer        data)
2092 {
2093   GtkDragSourceSite *site;
2094   site = (GtkDragSourceSite *)data;
2095
2096   switch (event->type)
2097     {
2098     case GDK_BUTTON_PRESS:
2099       if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2100         {
2101           site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1));
2102           site->x = event->button.x;
2103           site->y = event->button.y;
2104         }
2105       break;
2106       
2107     case GDK_BUTTON_RELEASE:
2108       if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2109         {
2110           site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
2111         }
2112       break;
2113       
2114     case GDK_MOTION_NOTIFY:
2115       if (site->state & event->motion.state & site->start_button_mask)
2116         {
2117           /* FIXME: This is really broken and can leave us
2118            * with a stuck grab
2119            */
2120           int i;
2121           for (i=1; i<6; i++)
2122             {
2123               if (site->state & event->motion.state & 
2124                   GDK_BUTTON1_MASK << (i - 1))
2125                 break;
2126             }
2127           
2128           if (MAX (abs(site->x - event->motion.x),
2129                    abs(site->y - event->motion.y)) > 3)
2130             {
2131               GtkDragSourceInfo *info;
2132               GdkDragContext *context;
2133               
2134               site->state = 0;
2135               context = gtk_drag_begin (widget, site->target_list,
2136                                         site->actions, 
2137                                         i, event);
2138
2139               
2140               info = g_dataset_get_data (context, "gtk-info");
2141
2142               if (!info->icon_window)
2143                 {
2144                   if (site->pixmap)
2145                     gtk_drag_set_icon_pixmap (context,
2146                                               site->colormap,
2147                                               site->pixmap,
2148                                               site->mask, -2, -2);
2149                   else
2150                     gtk_drag_set_icon_default (context);
2151                 }
2152
2153               return TRUE;
2154             }
2155         }
2156       break;
2157       
2158     default:                    /* hit for 2/3BUTTON_PRESS */
2159       break;
2160     }
2161   return FALSE;
2162 }
2163
2164 static void 
2165 gtk_drag_source_site_destroy (gpointer data)
2166 {
2167   GtkDragSourceSite *site = data;
2168
2169   if (site->target_list)
2170     gtk_target_list_unref (site->target_list);
2171
2172   if (site->pixmap)
2173     gdk_pixmap_unref (site->pixmap);
2174   
2175   if (site->mask)
2176     gdk_pixmap_unref (site->mask);
2177   
2178   g_free (site);
2179 }
2180
2181 static void
2182 gtk_drag_selection_get (GtkWidget        *widget, 
2183                         GtkSelectionData *selection_data,
2184                         guint             sel_info,
2185                         guint32           time,
2186                         gpointer          data)
2187 {
2188   GtkDragSourceInfo *info = data;
2189   static GdkAtom null_atom = GDK_NONE;
2190   guint target_info;
2191
2192   if (!null_atom)
2193     null_atom = gdk_atom_intern ("NULL", FALSE);
2194
2195   switch (sel_info)
2196     {
2197     case TARGET_DELETE:
2198       gtk_signal_emit_by_name (GTK_OBJECT (info->widget), 
2199                                "drag_data_delete", 
2200                                info->context);
2201       gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2202       break;
2203     case TARGET_MOTIF_SUCCESS:
2204       gtk_drag_drop_finished (info, TRUE, time);
2205       gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2206       break;
2207     case TARGET_MOTIF_FAILURE:
2208       gtk_drag_drop_finished (info, FALSE, time);
2209       gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2210       break;
2211     default:
2212       if (info->proxy_dest)
2213         {
2214           /* This is sort of dangerous and needs to be thought
2215            * through better
2216            */
2217           info->proxy_dest->proxy_data = selection_data;
2218           gtk_drag_get_data (info->widget,
2219                              info->proxy_dest->context,
2220                              selection_data->target,
2221                              time);
2222           gtk_main();
2223           info->proxy_dest->proxy_data = NULL;
2224         }
2225       else
2226         {
2227           if (gtk_target_list_find (info->target_list, 
2228                                     selection_data->target, 
2229                                     &target_info))
2230             {
2231               gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2232                                        info->context, 
2233                                        selection_data, 
2234                                        target_info, 
2235                                        time);
2236             }
2237         }
2238       break;
2239     }
2240 }
2241
2242 static gint
2243 gtk_drag_anim_timeout (gpointer data)
2244 {
2245   GtkDragAnim *anim = data;
2246   gint x, y;
2247
2248   if (anim->step == anim->n_steps)
2249     {
2250       gtk_drag_source_info_destroy (anim->info);
2251       g_free (anim);
2252
2253       return FALSE;
2254     }
2255   else
2256     {
2257       x = (anim->info->start_x * (anim->step + 1) +
2258            anim->info->cur_x * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2259       y = (anim->info->start_y * (anim->step + 1) +
2260            anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2261       if (anim->info->icon_window)
2262         gtk_widget_set_uposition (anim->info->icon_window, x, y);
2263   
2264       anim->step++;
2265
2266       return TRUE;
2267     }
2268 }
2269
2270 static void
2271 gtk_drag_remove_icon (GtkDragSourceInfo *info)
2272 {
2273   if (info->icon_window)
2274     {
2275       gtk_widget_hide (info->icon_window);
2276       gtk_widget_unref (info->icon_window);
2277
2278       info->icon_window = NULL;
2279     }
2280 }
2281
2282 static void
2283 gtk_drag_source_info_destroy (gpointer data)
2284 {
2285   GtkDragSourceInfo *info = data;
2286
2287   gtk_drag_remove_icon (data);
2288
2289   if (!info->proxy_dest)
2290     gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end", 
2291                              info->context);
2292
2293   if (info->widget)
2294     gtk_widget_unref (info->widget);
2295   
2296   gtk_signal_disconnect_by_data (GTK_OBJECT (info->ipc_widget), info);
2297   gtk_selection_remove_all (info->ipc_widget);
2298   gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", NULL);
2299   source_widgets = g_slist_remove (source_widgets, info->ipc_widget);
2300   gtk_drag_release_ipc_widget (info->ipc_widget);
2301
2302   gtk_target_list_unref (info->target_list);
2303
2304   g_dataset_set_data (info->context, "gtk-info", NULL);
2305   gdk_drag_context_unref (info->context);
2306
2307   if (info->drop_timeout)
2308     gtk_timeout_remove (info->drop_timeout);
2309
2310   g_free (info);
2311 }
2312
2313 /*************************************************************
2314  * gtk_drag_motion_cb:
2315  *     "motion_notify_event" callback during drag.
2316  *   arguments:
2317  *     
2318  *   results:
2319  *************************************************************/
2320
2321 static gint
2322 gtk_drag_motion_cb (GtkWidget      *widget, 
2323                     GdkEventMotion *event, 
2324                     gpointer        data)
2325 {
2326   GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2327   GdkAtom selection;
2328   GdkDragAction action;
2329   GdkWindow *window = NULL;
2330   GdkWindow *dest_window;
2331   GdkDragProtocol protocol;
2332   gint x_root, y_root;
2333
2334   if (event->is_hint)
2335     {
2336       gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL);
2337       event->x_root = x_root;
2338       event->y_root = y_root;
2339     }
2340
2341   action = gtk_drag_get_event_action ((GdkEvent *)event, 
2342                                       info->button, 
2343                                       info->context->actions);
2344   
2345   info->cur_x = event->x_root - info->hot_x;
2346   info->cur_y = event->y_root - info->hot_y;
2347
2348   if (info->icon_window)
2349     {
2350       gdk_window_raise (info->icon_window->window);
2351       gtk_widget_set_uposition (info->icon_window, info->cur_x, info->cur_y);
2352       window = info->icon_window->window;
2353     }
2354   
2355   gdk_drag_find_window (info->context,
2356                         window, event->x_root, event->y_root,
2357                         &dest_window, &protocol);
2358
2359   if (gdk_drag_motion (info->context, dest_window, protocol,
2360                        event->x_root, event->y_root, action,
2361                        event->time))
2362     {
2363       if (info->last_event)
2364         gdk_event_free ((GdkEvent *)info->last_event);
2365       
2366       info->last_event = gdk_event_copy ((GdkEvent *)event);
2367     }
2368
2369   if (dest_window)
2370     gdk_window_unref (dest_window);
2371
2372   selection = gdk_drag_get_selection (info->context);
2373   if (selection)
2374     gtk_drag_source_check_selection (info, selection, event->time);
2375
2376 #if 0
2377   /* We ignore the response, so we can respond precisely to the drop
2378    */
2379   if (event->is_hint)
2380     gdk_window_get_pointer (widget->window, NULL, NULL, NULL);
2381 #endif  
2382
2383   return TRUE;
2384 }
2385
2386 /*************************************************************
2387  * gtk_drag_motion_cb:
2388  *     "button_release_event" callback during drag.
2389  *   arguments:
2390  *     
2391  *   results:
2392  *************************************************************/
2393
2394 static gint
2395 gtk_drag_button_release_cb (GtkWidget      *widget, 
2396                             GdkEventButton *event, 
2397                             gpointer        data)
2398 {
2399   GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2400   GtkWidget *source_widget = info->widget;
2401   GdkEvent send_event;
2402
2403   gtk_widget_ref (source_widget);
2404
2405   if (event->button != info->button)
2406     return FALSE;
2407
2408   gdk_pointer_ungrab (event->time);
2409
2410   if ((info->context->action != 0) && (info->context->dest_window != NULL))
2411     {
2412       gtk_drag_drop (info, event->time);
2413     }
2414   else
2415     {
2416       gdk_drag_abort (info->context, event->time);
2417       gtk_drag_drop_finished (info, FALSE, event->time);
2418     }
2419
2420   gtk_grab_remove (widget);
2421
2422   send_event.button.type = GDK_BUTTON_RELEASE;
2423   send_event.button.window = source_widget->window;
2424   send_event.button.x = 0;
2425   send_event.button.y = 0;
2426   send_event.button.state = event->state;
2427   send_event.button.button = event->button;
2428   
2429   send_event.button.time = event->time;
2430
2431   /* Send on the button release to the original widget to
2432    * convince it to release its grab
2433    */
2434   gtk_widget_event (source_widget, &send_event);
2435   gtk_widget_unref (source_widget);
2436   
2437   return TRUE;
2438 }
2439
2440 static gint
2441 gtk_drag_abort_timeout (gpointer data)
2442 {
2443   GtkDragSourceInfo *info = data;
2444   guint32 time = GDK_CURRENT_TIME;
2445
2446   if (info->proxy_dest)
2447     time = info->proxy_dest->proxy_drop_time;
2448
2449   info->drop_timeout = 0;
2450   gtk_drag_drop_finished (info, FALSE, time);
2451   
2452   return FALSE;
2453 }