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