1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
28 #include "gdk/gdkkeysyms.h"
31 #include "gtkinvisible.h"
33 #include "gtksignal.h"
34 #include "gtkwindow.h"
36 static GSList *drag_widgets = NULL;
37 static GSList *source_widgets = NULL;
39 typedef struct _GtkDragSourceSite GtkDragSourceSite;
40 typedef struct _GtkDragSourceInfo GtkDragSourceInfo;
41 typedef struct _GtkDragDestSite GtkDragDestSite;
42 typedef struct _GtkDragDestInfo GtkDragDestInfo;
43 typedef struct _GtkDragAnim GtkDragAnim;
44 typedef struct _GtkDragFindData GtkDragFindData;
54 struct _GtkDragSourceSite
56 GdkModifierType start_button_mask;
57 GtkTargetList *target_list; /* Targets for drag data */
58 GdkDragAction actions; /* Possible actions */
59 GdkColormap *colormap; /* Colormap for drag icon */
60 GdkPixmap *pixmap; /* Icon for drag data */
63 /* Stored button press information to detect drag beginning */
68 struct _GtkDragSourceInfo
71 GtkTargetList *target_list; /* Targets for drag data */
72 GdkDragAction possible_actions; /* Actions allowed by source */
73 GdkDragContext *context; /* drag context */
74 GtkWidget *icon_window; /* Window for drag */
75 GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */
76 GdkCursor *cursor; /* Cursor for drag */
77 gint hot_x, hot_y; /* Hot spot for drag */
78 gint button; /* mouse button starting drag */
80 GtkDragStatus status; /* drag status */
81 GdkEvent *last_event; /* motion event waiting for response */
83 gint start_x, start_y; /* Initial position */
84 gint cur_x, cur_y; /* Current Position */
86 GList *selections; /* selections we've claimed */
88 GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */
90 guint drop_timeout; /* Timeout for aborting drop */
91 guint destroy_icon : 1; /* If true, destroy icon_window
95 struct _GtkDragDestSite
97 GtkDestDefaults flags;
98 GtkTargetList *target_list;
99 GdkDragAction actions;
100 GdkWindow *proxy_window;
101 GdkDragProtocol proxy_protocol;
102 gboolean do_proxy : 1;
103 gboolean proxy_coords : 1;
104 gboolean have_drag : 1;
107 struct _GtkDragDestInfo
109 GtkWidget *widget; /* Widget in which drag is in */
110 GdkDragContext *context; /* Drag context */
111 GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */
112 GtkSelectionData *proxy_data; /* Set while retrieving proxied data */
113 gboolean dropped : 1; /* Set after we receive a drop */
114 guint32 proxy_drop_time; /* Timestamp for proxied drop */
115 gboolean proxy_drop_wait : 1; /* Set if we are waiting for a
116 * status reply before sending
119 gint drop_x, drop_y; /* Position of drop */
122 #define DROP_ABORT_TIME 300000
124 #define ANIM_STEP_TIME 50
125 #define ANIM_STEP_LENGTH 50
126 #define ANIM_MIN_STEPS 5
127 #define ANIM_MAX_STEPS 10
131 GtkDragSourceInfo *info;
136 struct _GtkDragFindData
140 GdkDragContext *context;
141 GtkDragDestInfo *info;
144 gboolean (*callback) (GtkWidget *widget, GdkDragContext *context,
145 gint x, gint y, guint32 time);
149 /* Enumeration for some targets we handle internally */
152 TARGET_MOTIF_SUCCESS = 0x40000000,
153 TARGET_MOTIF_FAILURE,
159 static GdkPixmap *default_icon_pixmap = NULL;
160 static GdkPixmap *default_icon_mask = NULL;
161 static GdkColormap *default_icon_colormap = NULL;
162 static gint default_icon_hot_x;
163 static gint default_icon_hot_y;
165 /* Forward declarations */
166 static void gtk_drag_get_event_actions (GdkEvent *event,
168 GdkDragAction actions,
169 GdkDragAction *suggested_action,
170 GdkDragAction *possible_actions);
171 static GdkCursor * gtk_drag_get_cursor (GdkDragAction action);
172 static GtkWidget *gtk_drag_get_ipc_widget (void);
173 static void gtk_drag_release_ipc_widget (GtkWidget *widget);
175 static void gtk_drag_highlight_paint (GtkWidget *widget);
176 static gboolean gtk_drag_highlight_expose (GtkWidget *widget,
177 GdkEventExpose *event,
181 static GdkAtom gtk_drag_dest_find_target (GtkWidget *widget,
182 GtkDragDestSite *site,
183 GdkDragContext *context);
184 static void gtk_drag_selection_received (GtkWidget *widget,
185 GtkSelectionData *selection_data,
188 static void gtk_drag_find_widget (GtkWidget *widget,
189 GtkDragFindData *data);
190 static void gtk_drag_proxy_begin (GtkWidget *widget,
191 GtkDragDestInfo *dest_info);
192 static void gtk_drag_dest_info_destroy (gpointer data);
193 static void gtk_drag_dest_realized (GtkWidget *widget);
194 static void gtk_drag_dest_site_destroy (gpointer data);
195 static void gtk_drag_dest_leave (GtkWidget *widget,
196 GdkDragContext *context,
198 static gboolean gtk_drag_dest_motion (GtkWidget *widget,
199 GdkDragContext *context,
203 static gboolean gtk_drag_dest_drop (GtkWidget *widget,
204 GdkDragContext *context,
209 static void gtk_drag_source_check_selection (GtkDragSourceInfo *info,
212 static void gtk_drag_source_release_selections (GtkDragSourceInfo *info,
214 static void gtk_drag_drop (GtkDragSourceInfo *info,
216 static void gtk_drag_drop_finished (GtkDragSourceInfo *info,
220 static gint gtk_drag_source_event_cb (GtkWidget *widget,
223 static void gtk_drag_source_site_destroy (gpointer data);
224 static void gtk_drag_selection_get (GtkWidget *widget,
225 GtkSelectionData *selection_data,
229 static gint gtk_drag_anim_timeout (gpointer data);
230 static void gtk_drag_remove_icon (GtkDragSourceInfo *info);
231 static void gtk_drag_source_info_destroy (gpointer data);
232 static void gtk_drag_update (GtkDragSourceInfo *info,
236 static gint gtk_drag_motion_cb (GtkWidget *widget,
237 GdkEventMotion *event,
239 static gint gtk_drag_key_cb (GtkWidget *widget,
242 static gint gtk_drag_button_release_cb (GtkWidget *widget,
243 GdkEventButton *event,
245 static gint gtk_drag_abort_timeout (gpointer data);
247 /************************
248 * Cursor and Icon data *
249 ************************/
251 #define action_ask_width 16
252 #define action_ask_height 16
253 static const guchar action_ask_bits[] = {
254 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xf8, 0xb6, 0xf7,
255 0xd6, 0xec, 0x66, 0xdb, 0x66, 0xdb, 0x96, 0xec, 0x76, 0xf7, 0x76, 0xfb,
256 0xf6, 0xfc, 0x72, 0xfb, 0x7a, 0xfb, 0xf8, 0xfc, };
258 #define action_ask_mask_width 16
259 #define action_ask_mask_height 16
260 static const guchar action_ask_mask_bits[] = {
261 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0xcf, 0x0f,
262 0xef, 0x1f, 0xff, 0x3c, 0xff, 0x3c, 0x6f, 0x1f, 0x8f, 0x0f, 0x8f, 0x07,
263 0x0f, 0x03, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x03, };
265 #define action_copy_width 16
266 #define action_copy_height 16
267 static const guchar action_copy_bits[] = {
268 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xfb, 0x76, 0xfb,
269 0x76, 0xfb, 0x06, 0x83, 0xf6, 0xbf, 0xf6, 0xbf, 0x06, 0x83, 0x76, 0xfb,
270 0x76, 0xfb, 0x72, 0xfb, 0x7a, 0xf8, 0xf8, 0xff, };
272 #define action_copy_mask_width 16
273 #define action_copy_mask_height 16
274 static const guchar action_copy_mask_bits[] = {
275 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0x8f, 0x07,
276 0x8f, 0x07, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x8f, 0x07,
277 0x8f, 0x07, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x00, };
279 #define action_move_width 16
280 #define action_move_height 16
281 static const guchar action_move_bits[] = {
282 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x96, 0xff, 0x26, 0xff,
283 0xc6, 0xf8, 0xd6, 0xe3, 0x96, 0x8f, 0xb6, 0xbf, 0x36, 0xc3, 0x76, 0xfb,
284 0x76, 0xfa, 0xf2, 0xfa, 0xfa, 0xf8, 0xf8, 0xff, };
286 #define action_move_mask_width 16
287 #define action_move_mask_height 16
288 static const guchar action_move_mask_bits[] = {
289 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x6f, 0x00, 0xff, 0x00,
290 0xff, 0x07, 0xef, 0x1f, 0xef, 0x7f, 0xcf, 0x7f, 0xcf, 0x3f, 0x8f, 0x07,
291 0x8f, 0x07, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x00, };
293 #define action_link_width 16
294 #define action_link_height 16
295 static const guchar action_link_bits[] = {
296 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x36, 0xf8, 0xd6, 0xf7,
297 0x66, 0xec, 0xa6, 0xe8, 0x26, 0xdf, 0xe6, 0xbd, 0xd6, 0xa7, 0xb6, 0xa8,
298 0xb6, 0xb1, 0x72, 0xdf, 0xfa, 0xe0, 0xf8, 0xff, };
300 #define action_link_mask_width 16
301 #define action_link_mask_height 16
302 static const guchar action_link_mask_bits[] = {
303 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xcf, 0x07, 0xef, 0x0f,
304 0xff, 0x1f, 0x7f, 0x1f, 0xff, 0x3f, 0xff, 0x7f, 0xef, 0x7f, 0xcf, 0x77,
305 0xcf, 0x7f, 0x8f, 0x3f, 0x07, 0x1f, 0x07, 0x00, };
307 #define action_none_width 16
308 #define action_none_height 16
309 static const guchar action_none_bits[] = {
310 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0xf6, 0xff, 0xf6, 0xff,
311 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff,
312 0xf6, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf8, 0xff, };
314 #define action_none_mask_width 16
315 #define action_none_mask_height 16
316 static const guchar action_none_mask_bits[] = {
317 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x0f, 0x00,
318 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00,
319 0x0f, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x07, 0x00, };
321 #define CURSOR_WIDTH 16
322 #define CURSOR_HEIGHT 16
325 GdkDragAction action;
330 { GDK_ACTION_DEFAULT, 0 },
331 { GDK_ACTION_ASK, action_ask_bits, action_ask_mask_bits, NULL },
332 { GDK_ACTION_COPY, action_copy_bits, action_copy_mask_bits, NULL },
333 { GDK_ACTION_MOVE, action_move_bits, action_move_mask_bits, NULL },
334 { GDK_ACTION_LINK, action_link_bits, action_link_mask_bits, NULL },
335 { 0 , action_none_bits, action_none_mask_bits, NULL },
338 static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[0]);
341 static const char *drag_default_xpm[] = {
354 " ...+++++++++++.. ",
355 " ..+.++++++++++++.. ",
356 " .++.++++++++++++.. ",
357 " .+++.++++++++++++.. ",
358 " .++++.++++++++++++. ",
359 " .+++.+++++++++++++.. ",
360 " .++.+++++++++++++++.. ",
361 " .+.+++++++++++++++++.. ",
362 " ..+++++++++++++++++++.. ",
363 " ..++++++++++++++++++++. ",
364 " .++++++++++++++++++++.. ",
365 " ..+++++++++++++++++.. ",
366 " .++++++++++++++++.. ",
367 " ..+++++++++++++... ",
379 /*********************
380 * Utility functions *
381 *********************/
383 /*************************************************************
384 * gtk_drag_get_ipc_widget:
385 * Return a invisible, off-screen, override-redirect
390 *************************************************************/
393 gtk_drag_get_ipc_widget (void)
399 GSList *tmp = drag_widgets;
400 result = drag_widgets->data;
401 drag_widgets = drag_widgets->next;
402 g_slist_free_1 (tmp);
406 result = gtk_invisible_new ();
407 gtk_widget_show (result);
413 /***************************************************************
414 * gtk_drag_release_ipc_widget:
415 * Releases widget retrieved with gtk_drag_get_ipc_widget ()
417 * widget: the widget to release.
419 ***************************************************************/
422 gtk_drag_release_ipc_widget (GtkWidget *widget)
424 drag_widgets = g_slist_prepend (drag_widgets, widget);
428 gtk_drag_get_event_time (GdkEvent *event)
430 guint32 tm = GDK_CURRENT_TIME;
435 case GDK_MOTION_NOTIFY:
436 tm = event->motion.time; break;
437 case GDK_BUTTON_PRESS:
438 case GDK_2BUTTON_PRESS:
439 case GDK_3BUTTON_PRESS:
440 case GDK_BUTTON_RELEASE:
441 tm = event->button.time; break;
443 case GDK_KEY_RELEASE:
444 tm = event->key.time; break;
445 case GDK_ENTER_NOTIFY:
446 case GDK_LEAVE_NOTIFY:
447 tm = event->crossing.time; break;
448 case GDK_PROPERTY_NOTIFY:
449 tm = event->property.time; break;
450 case GDK_SELECTION_CLEAR:
451 case GDK_SELECTION_REQUEST:
452 case GDK_SELECTION_NOTIFY:
453 tm = event->selection.time; break;
454 case GDK_PROXIMITY_IN:
455 case GDK_PROXIMITY_OUT:
456 tm = event->proximity.time; break;
457 default: /* use current time */
465 gtk_drag_get_event_actions (GdkEvent *event,
467 GdkDragAction actions,
468 GdkDragAction *suggested_action,
469 GdkDragAction *possible_actions)
471 *suggested_action = 0;
472 *possible_actions = 0;
476 GdkModifierType state = 0;
480 case GDK_MOTION_NOTIFY:
481 state = event->motion.state;
483 case GDK_BUTTON_PRESS:
484 case GDK_2BUTTON_PRESS:
485 case GDK_3BUTTON_PRESS:
486 case GDK_BUTTON_RELEASE:
487 state = event->button.state;
490 case GDK_KEY_RELEASE:
491 state = event->key.state;
493 case GDK_ENTER_NOTIFY:
494 case GDK_LEAVE_NOTIFY:
495 state = event->crossing.state;
501 if ((button == 2 || button == 3) && (actions & GDK_ACTION_ASK))
503 *suggested_action = GDK_ACTION_ASK;
504 *possible_actions = actions;
506 else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
508 if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
510 if (actions & GDK_ACTION_LINK)
512 *suggested_action = GDK_ACTION_LINK;
513 *possible_actions = GDK_ACTION_LINK;
516 else if (state & GDK_CONTROL_MASK)
518 if (actions & GDK_ACTION_COPY)
520 *suggested_action = GDK_ACTION_COPY;
521 *possible_actions = GDK_ACTION_COPY;
527 if (actions & GDK_ACTION_MOVE)
529 *suggested_action = GDK_ACTION_MOVE;
530 *possible_actions = GDK_ACTION_MOVE;
537 *possible_actions = actions;
539 if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK))
540 *suggested_action = GDK_ACTION_ASK;
541 else if (actions & GDK_ACTION_COPY)
542 *suggested_action = GDK_ACTION_COPY;
543 else if (actions & GDK_ACTION_MOVE)
544 *suggested_action = GDK_ACTION_MOVE;
545 else if (actions & GDK_ACTION_LINK)
546 *suggested_action = GDK_ACTION_LINK;
554 gtk_drag_get_cursor (GdkDragAction action)
558 for (i = 0 ; i < n_drag_cursors - 1; i++)
559 if (drag_cursors[i].action == action)
562 if (drag_cursors[i].cursor == NULL)
567 gdk_bitmap_create_from_data (NULL,
568 drag_cursors[i].bits,
569 CURSOR_WIDTH, CURSOR_HEIGHT);
571 gdk_bitmap_create_from_data (NULL,
572 drag_cursors[i].mask,
573 CURSOR_WIDTH, CURSOR_HEIGHT);
575 gdk_color_white (gdk_colormap_get_system (), &bg);
576 gdk_color_black (gdk_colormap_get_system (), &fg);
578 drag_cursors[i].cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, 0, 0);
580 gdk_pixmap_unref (pixmap);
581 gdk_pixmap_unref (mask);
584 return drag_cursors[i].cursor;
587 /********************
589 ********************/
591 /*************************************************************
593 * Get the data for a drag or drop
595 * context - drag context
596 * target - format to retrieve the data in.
597 * time - timestamp of triggering event.
600 *************************************************************/
603 gtk_drag_get_data (GtkWidget *widget,
604 GdkDragContext *context,
608 GtkWidget *selection_widget;
610 g_return_if_fail (widget != NULL);
611 g_return_if_fail (context != NULL);
613 selection_widget = gtk_drag_get_ipc_widget ();
615 gdk_drag_context_ref (context);
616 gtk_widget_ref (widget);
618 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
619 GTK_SIGNAL_FUNC (gtk_drag_selection_received), widget);
621 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
623 gtk_selection_convert (selection_widget,
624 gdk_drag_get_selection (context),
630 /*************************************************************
631 * gtk_drag_get_source_widget:
632 * Get the widget the was the source of this drag, if
633 * the drag originated from this application.
635 * context: The drag context for this drag
637 * The source widget, or NULL if the drag originated from
638 * a different application.
639 *************************************************************/
642 gtk_drag_get_source_widget (GdkDragContext *context)
646 tmp_list = source_widgets;
649 GtkWidget *ipc_widget = tmp_list->data;
651 if (ipc_widget->window == context->source_window)
653 GtkDragSourceInfo *info;
654 info = gtk_object_get_data (GTK_OBJECT (ipc_widget), "gtk-info");
656 return info ? info->widget : NULL;
659 tmp_list = tmp_list->next;
665 /*************************************************************
667 * Notify the drag source that the transfer of data
670 * context: The drag context for this drag
671 * success: Was the data successfully transferred?
672 * time: The timestamp to use when notifying the destination.
674 *************************************************************/
677 gtk_drag_finish (GdkDragContext *context,
682 GdkAtom target = GDK_NONE;
684 g_return_if_fail (context != NULL);
688 target = gdk_atom_intern ("DELETE", FALSE);
690 else if (context->protocol == GDK_DRAG_PROTO_MOTIF)
692 target = gdk_atom_intern (success ?
693 "XmTRANSFER_SUCCESS" :
694 "XmTRANSFER_FAILURE",
698 if (target != GDK_NONE)
700 GtkWidget *selection_widget = gtk_drag_get_ipc_widget ();
702 gdk_drag_context_ref (context);
704 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
705 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
706 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
709 gtk_selection_convert (selection_widget,
710 gdk_drag_get_selection (context),
716 gdk_drop_finish (context, success, time);
719 /*************************************************************
720 * gtk_drag_highlight_paint:
721 * Paint a highlight indicating drag status onto the widget.
725 *************************************************************/
728 gtk_drag_highlight_paint (GtkWidget *widget)
730 gint x, y, width, height;
732 g_return_if_fail (widget != NULL);
734 if (GTK_WIDGET_DRAWABLE (widget))
736 if (GTK_WIDGET_NO_WINDOW (widget))
738 x = widget->allocation.x;
739 y = widget->allocation.y;
740 width = widget->allocation.width;
741 height = widget->allocation.height;
747 gdk_window_get_size (widget->window, &width, &height);
750 gtk_draw_shadow (widget->style, widget->window,
751 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
752 x, y, width, height);
754 gdk_draw_rectangle (widget->window,
755 widget->style->black_gc,
757 x, y, width - 1, height - 1);
761 /*************************************************************
762 * gtk_drag_highlight_expose:
763 * Callback for expose_event for highlighted widgets.
769 *************************************************************/
772 gtk_drag_highlight_expose (GtkWidget *widget,
773 GdkEventExpose *event,
776 gtk_drag_highlight_paint (widget);
780 /*************************************************************
781 * gtk_drag_highlight:
782 * Highlight the given widget in the default manner.
786 *************************************************************/
789 gtk_drag_highlight (GtkWidget *widget)
791 gtk_signal_connect_after (GTK_OBJECT (widget), "draw",
792 GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
794 gtk_signal_connect (GTK_OBJECT (widget), "expose_event",
795 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
798 gtk_widget_queue_draw (widget);
801 /*************************************************************
802 * gtk_drag_unhighlight:
803 * Refresh the given widget to remove the highlight.
807 *************************************************************/
810 gtk_drag_unhighlight (GtkWidget *widget)
812 g_return_if_fail (widget != NULL);
814 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
815 GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
817 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
818 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
821 gtk_widget_queue_clear (widget);
824 /*************************************************************
826 * Register a drop site, and possibly add default behaviors.
829 * flags: Which types of default drag behavior to use
830 * targets: Table of targets that can be accepted
831 * n_targets: Number of of entries in targets
834 *************************************************************/
837 gtk_drag_dest_set (GtkWidget *widget,
838 GtkDestDefaults flags,
839 const GtkTargetEntry *targets,
841 GdkDragAction actions)
843 GtkDragDestSite *site;
845 g_return_if_fail (widget != NULL);
847 /* HACK, do this in the destroy */
848 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
850 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
852 if (GTK_WIDGET_REALIZED (widget))
853 gtk_drag_dest_realized (widget);
855 gtk_signal_connect (GTK_OBJECT (widget), "realize",
856 GTK_SIGNAL_FUNC (gtk_drag_dest_realized), NULL);
858 site = g_new (GtkDragDestSite, 1);
861 site->have_drag = FALSE;
863 site->target_list = gtk_target_list_new (targets, n_targets);
865 site->target_list = NULL;
867 site->actions = actions;
868 site->do_proxy = FALSE;
870 gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
871 site, gtk_drag_dest_site_destroy);
874 /*************************************************************
875 * gtk_drag_dest_set_proxy:
876 * Set up this widget to proxy drags elsewhere.
879 * proxy_window: window to which forward drag events
880 * protocol: Drag protocol which the dest widget accepts
881 * use_coordinates: If true, send the same coordinates to the
882 * destination, because it is a embedded
885 *************************************************************/
888 gtk_drag_dest_set_proxy (GtkWidget *widget,
889 GdkWindow *proxy_window,
890 GdkDragProtocol protocol,
891 gboolean use_coordinates)
893 GtkDragDestSite *site;
895 g_return_if_fail (widget != NULL);
897 /* HACK, do this in the destroy */
898 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
900 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
902 if (GTK_WIDGET_REALIZED (widget))
903 gtk_drag_dest_realized (widget);
905 gtk_signal_connect (GTK_OBJECT (widget), "realize",
906 GTK_SIGNAL_FUNC (gtk_drag_dest_realized), NULL);
908 site = g_new (GtkDragDestSite, 1);
911 site->have_drag = FALSE;
912 site->target_list = NULL;
914 site->proxy_window = proxy_window;
916 gdk_window_ref (proxy_window);
917 site->do_proxy = TRUE;
918 site->proxy_protocol = protocol;
919 site->proxy_coords = use_coordinates;
921 gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
922 site, gtk_drag_dest_site_destroy);
925 /*************************************************************
926 * gtk_drag_dest_unset
927 * Unregister this widget as a drag target.
931 *************************************************************/
934 gtk_drag_dest_unset (GtkWidget *widget)
936 g_return_if_fail (widget != NULL);
938 gtk_object_set_data (GTK_OBJECT (widget), "gtk-drag-dest", NULL);
941 /*************************************************************
942 * gtk_drag_dest_handle_event:
943 * Called from widget event handling code on Drag events
947 * toplevel: Toplevel widget that received the event
950 *************************************************************/
953 gtk_drag_dest_handle_event (GtkWidget *toplevel,
956 GtkDragDestInfo *info;
957 GdkDragContext *context;
959 g_return_if_fail (toplevel != NULL);
960 g_return_if_fail (event != NULL);
962 context = event->dnd.context;
964 info = g_dataset_get_data (context, "gtk-info");
967 info = g_new (GtkDragDestInfo, 1);
969 info->context = event->dnd.context;
970 info->proxy_source = NULL;
971 info->proxy_data = NULL;
972 info->dropped = FALSE;
973 info->proxy_drop_wait = FALSE;
974 g_dataset_set_data_full (context,
977 gtk_drag_dest_info_destroy);
980 /* Find the widget for the event */
989 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
994 case GDK_DRAG_MOTION:
997 GtkDragFindData data;
1000 if (event->type == GDK_DROP_START)
1002 info->dropped = TRUE;
1003 /* We send a leave here so that the widget unhighlights
1008 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1009 info->widget = NULL;
1013 gdk_window_get_origin (toplevel->window, &tx, &ty);
1015 data.x = event->dnd.x_root - tx;
1016 data.y = event->dnd.y_root - ty;
1017 data.context = context;
1020 data.toplevel = TRUE;
1021 data.callback = (event->type == GDK_DRAG_MOTION) ?
1022 gtk_drag_dest_motion : gtk_drag_dest_drop;
1023 data.time = event->dnd.time;
1025 gtk_drag_find_widget (toplevel, &data);
1027 if (info->widget && !data.found)
1029 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1030 info->widget = NULL;
1035 if (event->type == GDK_DRAG_MOTION)
1038 gdk_drag_status (context, 0, event->dnd.time);
1040 else if (event->type == GDK_DROP_START && !info->proxy_source)
1042 gdk_drop_reply (context, data.found, event->dnd.time);
1043 if ((context->protocol == GDK_DRAG_PROTO_MOTIF) && !data.found)
1044 gtk_drag_finish (context, FALSE, FALSE, event->dnd.time);
1050 g_assert_not_reached ();
1054 /*************************************************************
1055 * gtk_drag_dest_find_target:
1056 * Decide on a target for the drag.
1061 *************************************************************/
1064 gtk_drag_dest_find_target (GtkWidget *widget,
1065 GtkDragDestSite *site,
1066 GdkDragContext *context)
1069 GList *tmp_source = NULL;
1070 GtkWidget *source_widget = gtk_drag_get_source_widget (context);
1072 tmp_target = site->target_list->list;
1075 GtkTargetPair *pair = tmp_target->data;
1076 tmp_source = context->targets;
1079 if (tmp_source->data == GUINT_TO_POINTER (pair->target))
1081 if ((!(pair->flags & GTK_TARGET_SAME_APP) || source_widget) &&
1082 (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget)))
1083 return pair->target;
1087 tmp_source = tmp_source->next;
1089 tmp_target = tmp_target->next;
1096 gtk_drag_selection_received (GtkWidget *widget,
1097 GtkSelectionData *selection_data,
1101 GdkDragContext *context;
1102 GtkDragDestInfo *info;
1103 GtkWidget *drop_widget;
1107 context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
1108 info = g_dataset_get_data (context, "gtk-info");
1110 if (info->proxy_data &&
1111 info->proxy_data->target == selection_data->target)
1113 gtk_selection_data_set (info->proxy_data,
1114 selection_data->type,
1115 selection_data->format,
1116 selection_data->data,
1117 selection_data->length);
1122 if (selection_data->target == gdk_atom_intern ("DELETE", FALSE))
1124 gtk_drag_finish (context, TRUE, FALSE, time);
1126 else if ((selection_data->target == gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE)) ||
1127 (selection_data->target == gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE)))
1133 GtkDragDestSite *site;
1135 site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest");
1137 if (site->target_list)
1141 if (gtk_target_list_find (site->target_list,
1142 selection_data->target,
1145 if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
1146 selection_data->length >= 0)
1147 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1148 "drag_data_received",
1149 context, info->drop_x, info->drop_y,
1156 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1157 "drag_data_received",
1158 context, info->drop_x, info->drop_y,
1159 selection_data, 0, time);
1162 if (site->flags & GTK_DEST_DEFAULT_DROP)
1165 gtk_drag_finish (context,
1166 (selection_data->length >= 0),
1167 (context->action == GDK_ACTION_MOVE),
1171 gtk_widget_unref (drop_widget);
1174 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
1175 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
1178 gtk_object_set_data (GTK_OBJECT (widget), "drag-context", NULL);
1179 gdk_drag_context_unref (context);
1181 gtk_drag_release_ipc_widget (widget);
1184 /*************************************************************
1185 * gtk_drag_find_widget:
1186 * Recursive callback used to locate widgets for
1187 * DRAG_MOTION and DROP_START events.
1191 *************************************************************/
1194 gtk_drag_find_widget (GtkWidget *widget,
1195 GtkDragFindData *data)
1197 GtkAllocation new_allocation;
1201 new_allocation = widget->allocation;
1203 if (data->found || !GTK_WIDGET_MAPPED (widget))
1206 /* Note that in the following code, we only count the
1207 * position as being inside a WINDOW widget if it is inside
1208 * widget->window; points that are outside of widget->window
1209 * but within the allocation are not counted. This is consistent
1210 * with the way we highlight drag targets.
1212 if (!GTK_WIDGET_NO_WINDOW (widget))
1214 new_allocation.x = 0;
1215 new_allocation.y = 0;
1220 GdkWindow *window = widget->window;
1221 while (window != widget->parent->window)
1223 gint tx, ty, twidth, theight;
1224 gdk_window_get_size (window, &twidth, &theight);
1226 if (new_allocation.x < 0)
1228 new_allocation.width += new_allocation.x;
1229 new_allocation.x = 0;
1231 if (new_allocation.y < 0)
1233 new_allocation.height += new_allocation.y;
1234 new_allocation.y = 0;
1236 if (new_allocation.x + new_allocation.width > twidth)
1237 new_allocation.width = twidth - new_allocation.x;
1238 if (new_allocation.y + new_allocation.height > theight)
1239 new_allocation.height = theight - new_allocation.y;
1241 gdk_window_get_position (window, &tx, &ty);
1242 new_allocation.x += tx;
1244 new_allocation.y += ty;
1247 window = gdk_window_get_parent (window);
1251 if (data->toplevel ||
1252 ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
1253 (data->x < new_allocation.x + new_allocation.width) &&
1254 (data->y < new_allocation.y + new_allocation.height)))
1256 /* First, check if the drag is in a valid drop site in
1257 * one of our children
1259 if (GTK_IS_CONTAINER (widget))
1261 GtkDragFindData new_data = *data;
1263 new_data.x -= x_offset;
1264 new_data.y -= y_offset;
1265 new_data.found = FALSE;
1266 new_data.toplevel = FALSE;
1268 gtk_container_forall (GTK_CONTAINER (widget),
1269 (GtkCallback)gtk_drag_find_widget,
1272 data->found = new_data.found;
1275 /* If not, and this widget is registered as a drop site, check to
1276 * emit "drag_motion" to check if we are actually in
1280 gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"))
1282 data->found = data->callback (widget,
1284 data->x - new_allocation.x,
1285 data->y - new_allocation.y,
1287 /* If so, send a "drag_leave" to the last widget */
1290 if (data->info->widget && data->info->widget != widget)
1292 gtk_drag_dest_leave (data->info->widget, data->context, data->time);
1294 data->info->widget = widget;
1301 gtk_drag_proxy_begin (GtkWidget *widget,
1302 GtkDragDestInfo *dest_info)
1304 GtkDragSourceInfo *source_info;
1307 source_info = g_new0 (GtkDragSourceInfo, 1);
1308 source_info->ipc_widget = gtk_drag_get_ipc_widget ();
1310 source_info->widget = widget;
1311 gtk_widget_ref (source_info->widget);
1312 source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
1313 dest_info->context->targets);
1315 source_info->target_list = gtk_target_list_new (NULL, 0);
1316 tmp_list = dest_info->context->targets;
1319 gtk_target_list_add (source_info->target_list,
1320 GPOINTER_TO_UINT (tmp_list->data), 0, 0);
1321 tmp_list = tmp_list->next;
1324 source_info->proxy_dest = dest_info;
1326 g_dataset_set_data (source_info->context, "gtk-info", source_info);
1328 gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget),
1330 GTK_SIGNAL_FUNC (gtk_drag_selection_get),
1333 dest_info->proxy_source = source_info;
1337 gtk_drag_dest_info_destroy (gpointer data)
1339 GtkDragDestInfo *info = data;
1345 gtk_drag_dest_realized (GtkWidget *widget)
1347 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1348 gdk_window_register_dnd (toplevel->window);
1352 gtk_drag_dest_site_destroy (gpointer data)
1354 GtkDragDestSite *site = data;
1356 if (site->target_list)
1357 gtk_target_list_unref (site->target_list);
1363 * Default drag handlers
1366 gtk_drag_dest_leave (GtkWidget *widget,
1367 GdkDragContext *context,
1370 GtkDragDestSite *site;
1372 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1373 g_return_if_fail (site != NULL);
1377 GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1379 if (info->proxy_source && !info->dropped)
1380 gdk_drag_abort (info->proxy_source->context, time);
1386 if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag)
1387 gtk_drag_unhighlight (widget);
1389 if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag)
1390 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_leave",
1393 site->have_drag = FALSE;
1398 gtk_drag_dest_motion (GtkWidget *widget,
1399 GdkDragContext *context,
1404 GtkDragDestSite *site;
1405 GdkDragAction action = 0;
1408 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1409 g_return_val_if_fail (site != NULL, FALSE);
1414 GdkEvent *current_event;
1415 GdkWindow *dest_window;
1416 GdkDragProtocol proto;
1418 GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1420 if (!info->proxy_source)
1421 gtk_drag_proxy_begin (widget, info);
1423 current_event = gtk_get_current_event ();
1425 if (site->proxy_window)
1427 dest_window = site->proxy_window;
1428 proto = site->proxy_protocol;
1432 gdk_drag_find_window (info->proxy_source->context,
1434 current_event->dnd.x_root,
1435 current_event->dnd.y_root,
1436 &dest_window, &proto);
1439 gdk_drag_motion (info->proxy_source->context,
1441 current_event->dnd.x_root,
1442 current_event->dnd.y_root,
1443 context->suggested_action,
1444 context->actions, time);
1446 if (!site->proxy_window && dest_window)
1447 gdk_window_unref (dest_window);
1449 selection = gdk_drag_get_selection (info->proxy_source->context);
1451 selection != gdk_drag_get_selection (info->context))
1452 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1454 gdk_event_free (current_event);
1459 if (site->flags & GTK_DEST_DEFAULT_MOTION)
1461 if (context->suggested_action & site->actions)
1462 action = context->suggested_action;
1469 if ((site->actions & (1 << i)) &&
1470 (context->actions & (1 << i)))
1478 if (action && gtk_drag_dest_find_target (widget, site, context))
1480 if (!site->have_drag)
1482 site->have_drag = TRUE;
1483 if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1484 gtk_drag_highlight (widget);
1487 gdk_drag_status (context, action, time);
1491 gdk_drag_status (context, 0, time);
1496 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_motion",
1497 context, x, y, time, &retval);
1499 return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1503 gtk_drag_dest_drop (GtkWidget *widget,
1504 GdkDragContext *context,
1509 GtkDragDestSite *site;
1510 GtkDragDestInfo *info;
1512 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1513 g_return_val_if_fail (site != NULL, FALSE);
1515 info = g_dataset_get_data (context, "gtk-info");
1516 g_return_val_if_fail (info != NULL, FALSE);
1523 if (info->proxy_source ||
1524 (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN))
1526 gtk_drag_drop (info->proxy_source, time);
1530 /* We need to synthesize a motion event, wait for a status,
1531 * and, if we get a good one, do a drop.
1534 GdkEvent *current_event;
1536 GdkWindow *dest_window;
1537 GdkDragProtocol proto;
1539 gtk_drag_proxy_begin (widget, info);
1540 info->proxy_drop_wait = TRUE;
1541 info->proxy_drop_time = time;
1543 current_event = gtk_get_current_event ();
1545 if (site->proxy_window)
1547 dest_window = site->proxy_window;
1548 proto = site->proxy_protocol;
1552 gdk_drag_find_window (info->proxy_source->context,
1554 current_event->dnd.x_root,
1555 current_event->dnd.y_root,
1556 &dest_window, &proto);
1559 gdk_drag_motion (info->proxy_source->context,
1561 current_event->dnd.x_root,
1562 current_event->dnd.y_root,
1563 context->suggested_action,
1564 context->actions, time);
1566 if (!site->proxy_window && dest_window)
1567 gdk_window_unref (dest_window);
1569 selection = gdk_drag_get_selection (info->proxy_source->context);
1571 selection != gdk_drag_get_selection (info->context))
1572 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1574 gdk_event_free (current_event);
1584 if (site->flags & GTK_DEST_DEFAULT_DROP)
1586 GdkAtom target = gtk_drag_dest_find_target (widget, site, context);
1588 if (target == GDK_NONE)
1591 gtk_drag_get_data (widget, context, target, time);
1594 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_drop",
1595 context, x, y, time, &retval);
1597 return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
1605 /*************************************************************
1606 * gtk_drag_begin: Start a drag operation
1609 * widget: Widget from which drag starts
1610 * handlers: List of handlers to supply the data for the drag
1611 * button: Button user used to start drag
1612 * time: Time of event starting drag
1615 *************************************************************/
1618 gtk_drag_begin (GtkWidget *widget,
1619 GtkTargetList *target_list,
1620 GdkDragAction actions,
1624 GtkDragSourceInfo *info;
1625 GList *targets = NULL;
1627 guint32 time = GDK_CURRENT_TIME;
1628 GdkDragAction possible_actions, suggested_action;
1630 g_return_val_if_fail (widget != NULL, NULL);
1631 g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
1632 g_return_val_if_fail (target_list != NULL, NULL);
1635 time = gdk_event_get_time (event);
1637 info = g_new0 (GtkDragSourceInfo, 1);
1638 info->ipc_widget = gtk_drag_get_ipc_widget ();
1639 source_widgets = g_slist_prepend (source_widgets, info->ipc_widget);
1641 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
1643 tmp_list = g_list_last (target_list->list);
1646 GtkTargetPair *pair = tmp_list->data;
1647 targets = g_list_prepend (targets,
1648 GINT_TO_POINTER (pair->target));
1649 tmp_list = tmp_list->prev;
1652 info->widget = widget;
1653 gtk_widget_ref (info->widget);
1655 info->context = gdk_drag_begin (info->ipc_widget->window, targets);
1656 g_list_free (targets);
1658 g_dataset_set_data (info->context, "gtk-info", info);
1660 info->button = button;
1661 info->target_list = target_list;
1662 gtk_target_list_ref (target_list);
1664 info->possible_actions = actions;
1666 info->cursor = NULL;
1667 info->status = GTK_DRAG_STATUS_DRAG;
1668 info->last_event = NULL;
1669 info->selections = NULL;
1670 info->icon_window = NULL;
1671 info->destroy_icon = FALSE;
1673 gtk_drag_get_event_actions (event, info->button, actions,
1674 &suggested_action, &possible_actions);
1677 info->cursor = gtk_drag_get_cursor (suggested_action);
1679 /* Set cur_x, cur_y here so if the "drag_begin" signal shows
1680 * the drag icon, it will be in the right place
1682 if (event->type == GDK_MOTION_NOTIFY)
1684 info->cur_x = event->motion.x_root;
1685 info->cur_y = event->motion.y_root;
1690 gdk_window_get_pointer (GDK_ROOT_PARENT (), &x, &y, NULL);
1696 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
1699 if (event->type == GDK_MOTION_NOTIFY)
1700 gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
1702 info->start_x = info->cur_x;
1703 info->start_y = info->cur_y;
1705 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "button_release_event",
1706 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info);
1707 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "motion_notify_event",
1708 GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info);
1709 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_press_event",
1710 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1711 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_release_event",
1712 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1713 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "selection_get",
1714 GTK_SIGNAL_FUNC (gtk_drag_selection_get), info);
1716 /* We use a GTK grab here to override any grabs that the widget
1717 * we are dragging from might have held
1719 gtk_grab_add (info->ipc_widget);
1720 if (gdk_pointer_grab (info->ipc_widget->window, FALSE,
1721 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1722 GDK_BUTTON_RELEASE_MASK, NULL,
1723 info->cursor, time) == 0)
1725 if (gdk_keyboard_grab (info->ipc_widget->window, FALSE, time) != 0)
1727 /* FIXME: This should be cleaned up... */
1731 ev.type = GDK_BUTTON_RELEASE;
1732 ev.button = info->button;
1734 gtk_drag_button_release_cb (widget, &ev, info);
1740 return info->context;
1743 /*************************************************************
1744 * gtk_drag_source_set:
1745 * Register a drop site, and possibly add default behaviors.
1748 * start_button_mask: Mask of allowed buttons to start drag
1749 * targets: Table of targets for this source
1751 * actions: Actions allowed for this source
1753 *************************************************************/
1756 gtk_drag_source_set (GtkWidget *widget,
1757 GdkModifierType start_button_mask,
1758 const GtkTargetEntry *targets,
1760 GdkDragAction actions)
1762 GtkDragSourceSite *site;
1764 g_return_if_fail (widget != NULL);
1766 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1768 gtk_widget_add_events (widget,
1769 gtk_widget_get_events (widget) |
1770 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1771 GDK_BUTTON_MOTION_MASK);
1775 if (site->target_list)
1776 gtk_target_list_unref (site->target_list);
1780 site = g_new0 (GtkDragSourceSite, 1);
1782 gtk_signal_connect (GTK_OBJECT (widget), "button_press_event",
1783 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1785 gtk_signal_connect (GTK_OBJECT (widget), "motion_notify_event",
1786 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1789 gtk_object_set_data_full (GTK_OBJECT (widget),
1791 site, gtk_drag_source_site_destroy);
1794 site->start_button_mask = start_button_mask;
1797 site->target_list = gtk_target_list_new (targets, n_targets);
1799 site->target_list = NULL;
1801 site->actions = actions;
1805 /*************************************************************
1806 * gtk_drag_source_unset
1807 * Unregister this widget as a drag source.
1811 *************************************************************/
1814 gtk_drag_source_unset (GtkWidget *widget)
1816 GtkDragSourceSite *site;
1818 g_return_if_fail (widget != NULL);
1820 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1824 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
1825 gtk_object_set_data (GTK_OBJECT (widget), "gtk-site-data", NULL);
1829 /*************************************************************
1830 * gtk_drag_source_set_icon:
1831 * Set an icon for drags from this source.
1833 * colormap: Colormap for this icon
1837 *************************************************************/
1840 gtk_drag_source_set_icon (GtkWidget *widget,
1841 GdkColormap *colormap,
1845 GtkDragSourceSite *site;
1847 g_return_if_fail (widget != NULL);
1849 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1850 g_return_if_fail (site != NULL);
1853 gdk_colormap_unref (site->colormap);
1855 gdk_pixmap_unref (site->pixmap);
1857 gdk_pixmap_unref (site->mask);
1859 site->colormap = colormap;
1861 gdk_colormap_ref (colormap);
1863 site->pixmap = pixmap;
1865 gdk_pixmap_ref (pixmap);
1869 gdk_pixmap_ref (mask);
1872 /*************************************************************
1873 * gtk_drag_set_icon_window:
1874 * Set a widget as the icon for a drag.
1881 *************************************************************/
1884 gtk_drag_set_icon_window (GdkDragContext *context,
1888 gboolean destroy_on_release)
1890 GtkDragSourceInfo *info;
1892 g_return_if_fail (context != NULL);
1893 g_return_if_fail (widget != NULL);
1895 info = g_dataset_get_data (context, "gtk-info");
1896 gtk_drag_remove_icon (info);
1898 info->icon_window = widget;
1899 info->hot_x = hot_x;
1900 info->hot_y = hot_y;
1904 gtk_widget_set_uposition (widget,
1905 info->cur_x - info->hot_x,
1906 info->cur_y - info->hot_y);
1907 gtk_widget_ref (widget);
1908 gdk_window_raise (widget->window);
1909 gtk_widget_show (widget);
1912 info->destroy_icon = destroy_on_release;
1915 /*************************************************************
1916 * gtk_drag_set_icon_widget:
1917 * Set a widget as the icon for a drag.
1924 *************************************************************/
1927 gtk_drag_set_icon_widget (GdkDragContext *context,
1932 g_return_if_fail (context != NULL);
1933 g_return_if_fail (widget != NULL);
1935 gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE);
1938 /*************************************************************
1939 * gtk_drag_set_icon_pixmap:
1940 * Set a widget as the icon for a drag.
1943 * colormap: Colormap for the icon window.
1949 *************************************************************/
1952 gtk_drag_set_icon_pixmap (GdkDragContext *context,
1953 GdkColormap *colormap,
1962 g_return_if_fail (context != NULL);
1963 g_return_if_fail (colormap != NULL);
1964 g_return_if_fail (pixmap != NULL);
1966 gdk_window_get_size (pixmap, &width, &height);
1968 gtk_widget_push_visual (gdk_colormap_get_visual (colormap));
1969 gtk_widget_push_colormap (colormap);
1971 window = gtk_window_new (GTK_WINDOW_POPUP);
1972 gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
1973 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
1975 gtk_widget_pop_visual ();
1976 gtk_widget_pop_colormap ();
1978 gtk_widget_set_usize (window, width, height);
1979 gtk_widget_realize (window);
1981 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
1984 gtk_widget_shape_combine_mask (window, mask, 0, 0);
1986 gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
1989 /*************************************************************
1990 * gtk_drag_set_icon_default:
1991 * Set the icon for a drag to the default icon.
1995 *************************************************************/
1998 gtk_drag_set_icon_default (GdkDragContext *context)
2000 g_return_if_fail (context != NULL);
2002 if (!default_icon_pixmap)
2004 default_icon_colormap = gdk_colormap_get_system ();
2005 default_icon_pixmap =
2006 gdk_pixmap_colormap_create_from_xpm_d (NULL,
2007 default_icon_colormap,
2009 NULL, (gchar **)drag_default_xpm);
2010 default_icon_hot_x = -2;
2011 default_icon_hot_y = -2;
2014 gtk_drag_set_icon_pixmap (context,
2015 default_icon_colormap,
2016 default_icon_pixmap,
2019 default_icon_hot_y);
2022 /*************************************************************
2023 * gtk_drag_set_default_icon:
2024 * Set a default icon for all drags as a pixmap.
2026 * colormap: Colormap for the icon window.
2032 *************************************************************/
2035 gtk_drag_set_default_icon (GdkColormap *colormap,
2041 g_return_if_fail (colormap != NULL);
2042 g_return_if_fail (pixmap != NULL);
2044 if (default_icon_colormap)
2045 gdk_colormap_unref (default_icon_colormap);
2046 if (default_icon_pixmap)
2047 gdk_pixmap_unref (default_icon_pixmap);
2048 if (default_icon_mask)
2049 gdk_pixmap_unref (default_icon_pixmap);
2051 default_icon_colormap = colormap;
2052 gdk_colormap_ref (colormap);
2054 default_icon_pixmap = pixmap;
2055 gdk_pixmap_ref (pixmap);
2057 default_icon_mask = mask;
2059 gdk_pixmap_ref (mask);
2061 default_icon_hot_x = hot_x;
2062 default_icon_hot_y = hot_y;
2066 /*************************************************************
2067 * gtk_drag_source_handle_event:
2068 * Called from widget event handling code on Drag events
2072 * toplevel: Toplevel widget that received the event
2075 *************************************************************/
2078 gtk_drag_source_handle_event (GtkWidget *widget,
2081 GtkDragSourceInfo *info;
2082 GdkDragContext *context;
2084 g_return_if_fail (widget != NULL);
2085 g_return_if_fail (event != NULL);
2087 context = event->dnd.context;
2088 info = g_dataset_get_data (context, "gtk-info");
2092 switch (event->type)
2094 case GDK_DRAG_STATUS:
2098 if (info->proxy_dest)
2100 if (!event->dnd.send_event)
2102 if (info->proxy_dest->proxy_drop_wait)
2104 gboolean result = context->action != 0;
2106 /* Aha - we can finally pass the MOTIF DROP on... */
2107 gdk_drop_reply (info->proxy_dest->context, result, info->proxy_dest->proxy_drop_time);
2109 gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
2111 gtk_drag_finish (info->proxy_dest->context, FALSE, FALSE, info->proxy_dest->proxy_drop_time);
2115 gdk_drag_status (info->proxy_dest->context,
2116 event->dnd.context->action,
2123 cursor = gtk_drag_get_cursor (event->dnd.context->action);
2124 if (info->cursor != cursor)
2126 #ifdef GDK_WINDOWING_X11
2127 XChangeActivePointerGrab (GDK_WINDOW_XDISPLAY (widget->window),
2128 PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask,
2129 ((GdkCursorPrivate *)cursor)->xcursor,
2131 #elif defined (GDK_WINDOWING_WIN32)
2132 gdk_pointer_grab (widget->window, FALSE,
2133 GDK_POINTER_MOTION_MASK |
2134 GDK_POINTER_MOTION_HINT_MASK |
2135 GDK_BUTTON_RELEASE_MASK,
2137 info->cursor, event->dnd.time);
2139 info->cursor = cursor;
2142 if (info->last_event)
2144 gtk_drag_update (info,
2145 info->cur_x, info->cur_y,
2147 info->last_event = NULL;
2153 case GDK_DROP_FINISHED:
2154 gtk_drag_drop_finished (info, TRUE, event->dnd.time);
2157 g_assert_not_reached ();
2161 /*************************************************************
2162 * gtk_drag_source_check_selection:
2163 * Check if we've set up handlers/claimed the selection
2164 * for a given drag. If not, add them.
2168 *************************************************************/
2171 gtk_drag_source_check_selection (GtkDragSourceInfo *info,
2177 tmp_list = info->selections;
2180 if (GPOINTER_TO_UINT (tmp_list->data) == selection)
2182 tmp_list = tmp_list->next;
2185 gtk_selection_owner_set (info->ipc_widget, selection, time);
2186 info->selections = g_list_prepend (info->selections,
2187 GUINT_TO_POINTER (selection));
2189 tmp_list = info->target_list->list;
2192 GtkTargetPair *pair = tmp_list->data;
2194 gtk_selection_add_target (info->ipc_widget,
2198 tmp_list = tmp_list->next;
2201 if (info->context->protocol == GDK_DRAG_PROTO_MOTIF)
2203 gtk_selection_add_target (info->ipc_widget,
2205 gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE),
2206 TARGET_MOTIF_SUCCESS);
2207 gtk_selection_add_target (info->ipc_widget,
2209 gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE),
2210 TARGET_MOTIF_FAILURE);
2213 gtk_selection_add_target (info->ipc_widget,
2215 gdk_atom_intern ("DELETE", FALSE),
2219 /*************************************************************
2220 * gtk_drag_drop_finished:
2221 * Clean up from the drag, and display snapback, if necessary.
2227 *************************************************************/
2230 gtk_drag_drop_finished (GtkDragSourceInfo *info,
2234 gtk_drag_source_release_selections (info, time);
2236 if (info->proxy_dest)
2238 /* The time from the event isn't reliable for Xdnd drags */
2239 gtk_drag_finish (info->proxy_dest->context, success, FALSE,
2240 info->proxy_dest->proxy_drop_time);
2241 gtk_drag_source_info_destroy (info);
2247 gtk_drag_source_info_destroy (info);
2251 GtkDragAnim *anim = g_new (GtkDragAnim, 1);
2255 anim->n_steps = MAX (info->cur_x - info->start_x,
2256 info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
2257 anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
2258 if (info->icon_window)
2260 gtk_widget_show (info->icon_window);
2261 gdk_window_raise (info->icon_window->window);
2264 /* Mark the context as dead, so if the destination decides
2265 * to respond really late, we still are OK.
2267 g_dataset_set_data (info->context, "gtk-info", NULL);
2268 gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
2274 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
2277 GList *tmp_list = info->selections;
2280 GdkAtom selection = GPOINTER_TO_UINT (tmp_list->data);
2281 if (gdk_selection_owner_get (selection) == info->ipc_widget->window)
2282 gtk_selection_owner_set (NULL, selection, time);
2283 tmp_list = tmp_list->next;
2286 g_list_free (info->selections);
2287 info->selections = NULL;
2290 /*************************************************************
2292 * Send a drop event.
2296 *************************************************************/
2299 gtk_drag_drop (GtkDragSourceInfo *info,
2302 if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN)
2304 GtkSelectionData selection_data;
2306 GdkAtom target = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
2308 tmp_list = info->target_list->list;
2311 GtkTargetPair *pair = tmp_list->data;
2313 if (pair->target == target)
2315 selection_data.selection = GDK_NONE;
2316 selection_data.target = target;
2317 selection_data.data = NULL;
2318 selection_data.length = -1;
2320 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2321 info->context, &selection_data,
2325 /* FIXME: Should we check for length >= 0 here? */
2326 gtk_drag_drop_finished (info, TRUE, time);
2329 tmp_list = tmp_list->next;
2331 gtk_drag_drop_finished (info, FALSE, time);
2335 if (info->icon_window)
2336 gtk_widget_hide (info->icon_window);
2338 gdk_drag_drop (info->context, time);
2339 info->drop_timeout = gtk_timeout_add (DROP_ABORT_TIME,
2340 gtk_drag_abort_timeout,
2346 * Source side callbacks.
2350 gtk_drag_source_event_cb (GtkWidget *widget,
2354 GtkDragSourceSite *site;
2355 site = (GtkDragSourceSite *)data;
2357 switch (event->type)
2359 case GDK_BUTTON_PRESS:
2360 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2362 site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1));
2363 site->x = event->button.x;
2364 site->y = event->button.y;
2368 case GDK_BUTTON_RELEASE:
2369 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2371 site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
2375 case GDK_MOTION_NOTIFY:
2376 if (site->state & event->motion.state & site->start_button_mask)
2378 /* FIXME: This is really broken and can leave us
2384 if (site->state & event->motion.state &
2385 GDK_BUTTON1_MASK << (i - 1))
2389 if (MAX (ABS (site->x - event->motion.x),
2390 ABS (site->y - event->motion.y)) > 3)
2392 GtkDragSourceInfo *info;
2393 GdkDragContext *context;
2396 context = gtk_drag_begin (widget, site->target_list,
2401 info = g_dataset_get_data (context, "gtk-info");
2403 if (!info->icon_window)
2406 gtk_drag_set_icon_pixmap (context,
2409 site->mask, -2, -2);
2411 gtk_drag_set_icon_default (context);
2419 default: /* hit for 2/3BUTTON_PRESS */
2426 gtk_drag_source_site_destroy (gpointer data)
2428 GtkDragSourceSite *site = data;
2430 if (site->target_list)
2431 gtk_target_list_unref (site->target_list);
2434 gdk_pixmap_unref (site->pixmap);
2437 gdk_pixmap_unref (site->mask);
2443 gtk_drag_selection_get (GtkWidget *widget,
2444 GtkSelectionData *selection_data,
2449 GtkDragSourceInfo *info = data;
2450 static GdkAtom null_atom = GDK_NONE;
2454 null_atom = gdk_atom_intern ("NULL", FALSE);
2459 gtk_signal_emit_by_name (GTK_OBJECT (info->widget),
2462 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2464 case TARGET_MOTIF_SUCCESS:
2465 gtk_drag_drop_finished (info, TRUE, time);
2466 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2468 case TARGET_MOTIF_FAILURE:
2469 gtk_drag_drop_finished (info, FALSE, time);
2470 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2473 if (info->proxy_dest)
2475 /* This is sort of dangerous and needs to be thought
2478 info->proxy_dest->proxy_data = selection_data;
2479 gtk_drag_get_data (info->widget,
2480 info->proxy_dest->context,
2481 selection_data->target,
2484 info->proxy_dest->proxy_data = NULL;
2488 if (gtk_target_list_find (info->target_list,
2489 selection_data->target,
2492 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2504 gtk_drag_anim_timeout (gpointer data)
2506 GtkDragAnim *anim = data;
2510 GDK_THREADS_ENTER ();
2512 if (anim->step == anim->n_steps)
2514 gtk_drag_source_info_destroy (anim->info);
2521 x = (anim->info->start_x * (anim->step + 1) +
2522 anim->info->cur_x * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2523 y = (anim->info->start_y * (anim->step + 1) +
2524 anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2525 if (anim->info->icon_window)
2526 gtk_widget_set_uposition (anim->info->icon_window,
2527 x - anim->info->hot_x,
2528 y - anim->info->hot_y);
2535 GDK_THREADS_LEAVE ();
2541 gtk_drag_remove_icon (GtkDragSourceInfo *info)
2543 if (info->icon_window)
2545 gtk_widget_hide (info->icon_window);
2546 if (info->destroy_icon)
2547 gtk_widget_destroy (info->icon_window);
2549 gtk_widget_unref (info->icon_window);
2550 info->icon_window = NULL;
2555 gtk_drag_source_info_destroy (gpointer data)
2557 GtkDragSourceInfo *info = data;
2559 gtk_drag_remove_icon (data);
2561 if (!info->proxy_dest)
2562 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end",
2566 gtk_widget_unref (info->widget);
2568 gtk_signal_disconnect_by_data (GTK_OBJECT (info->ipc_widget), info);
2569 gtk_selection_remove_all (info->ipc_widget);
2570 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", NULL);
2571 source_widgets = g_slist_remove (source_widgets, info->ipc_widget);
2572 gtk_drag_release_ipc_widget (info->ipc_widget);
2574 gtk_target_list_unref (info->target_list);
2576 g_dataset_set_data (info->context, "gtk-info", NULL);
2577 gdk_drag_context_unref (info->context);
2579 if (info->drop_timeout)
2580 gtk_timeout_remove (info->drop_timeout);
2585 /*************************************************************
2587 * Function to update the status of the drag when the
2588 * cursor moves or the modifier changes
2590 * info: DragSourceInfo for the drag
2591 * x_root, y_root: position of darg
2592 * event: The event that triggered this call
2594 *************************************************************/
2597 gtk_drag_update (GtkDragSourceInfo *info,
2602 GdkDragAction action;
2603 GdkDragAction possible_actions;
2604 GdkWindow *window = NULL;
2605 GdkWindow *dest_window;
2606 GdkDragProtocol protocol;
2608 guint32 time = gtk_drag_get_event_time (event);
2610 gtk_drag_get_event_actions (event,
2612 info->possible_actions,
2613 &action, &possible_actions);
2614 info->cur_x = x_root;
2615 info->cur_y = y_root;
2617 if (info->icon_window)
2619 gdk_window_raise (info->icon_window->window);
2620 gtk_widget_set_uposition (info->icon_window,
2621 info->cur_x - info->hot_x,
2622 info->cur_y - info->hot_y);
2623 window = info->icon_window->window;
2626 gdk_drag_find_window (info->context,
2627 window, x_root, y_root,
2628 &dest_window, &protocol);
2630 if (gdk_drag_motion (info->context, dest_window, protocol,
2631 x_root, y_root, action,
2635 if (info->last_event)
2636 gdk_event_free ((GdkEvent *)info->last_event);
2638 info->last_event = gdk_event_copy ((GdkEvent *)event);
2642 gdk_window_unref (dest_window);
2644 selection = gdk_drag_get_selection (info->context);
2646 gtk_drag_source_check_selection (info, selection, time);
2649 /*************************************************************
2651 * Called when the user finishes to drag, either by
2652 * releasing the mouse, or by pressing Esc.
2654 * widget: GtkInvisible widget for this drag
2657 *************************************************************/
2660 gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
2662 GdkEvent send_event;
2663 GtkWidget *source_widget = info->widget;
2665 gdk_pointer_ungrab (time);
2666 gdk_keyboard_ungrab (time);
2668 gtk_grab_remove (info->ipc_widget);
2670 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2671 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
2673 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2674 GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
2677 /* Send on a release pair to the the original
2678 * widget to convince it to release its grab. We need to
2679 * call gtk_propagate_event() here, instead of
2680 * gtk_widget_event() because widget like GtkList may
2681 * expect propagation.
2684 send_event.button.type = GDK_BUTTON_RELEASE;
2685 send_event.button.window = GDK_ROOT_PARENT ();
2686 send_event.button.send_event = TRUE;
2687 send_event.button.time = time;
2688 send_event.button.x = 0;
2689 send_event.button.y = 0;
2690 send_event.button.pressure = 0.;
2691 send_event.button.xtilt = 0.;
2692 send_event.button.ytilt = 0.;
2693 send_event.button.state = 0;
2694 send_event.button.button = info->button;
2695 send_event.button.source = GDK_SOURCE_PEN;
2696 send_event.button.deviceid = GDK_CORE_POINTER;
2697 send_event.button.x_root = 0;
2698 send_event.button.y_root = 0;
2700 gtk_propagate_event (source_widget, &send_event);
2703 /*************************************************************
2704 * gtk_drag_motion_cb:
2705 * "motion_notify_event" callback during drag.
2709 *************************************************************/
2712 gtk_drag_motion_cb (GtkWidget *widget,
2713 GdkEventMotion *event,
2716 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2717 gint x_root, y_root;
2721 gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL);
2722 event->x_root = x_root;
2723 event->y_root = y_root;
2726 gtk_drag_update (info, event->x_root, event->y_root, (GdkEvent *)event);
2731 /*************************************************************
2733 * "key_press/release_event" callback during drag.
2737 *************************************************************/
2740 gtk_drag_key_cb (GtkWidget *widget,
2744 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2745 GdkModifierType state;
2747 if (event->type == GDK_KEY_PRESS)
2749 if (event->keyval == GDK_Escape)
2751 gtk_drag_end (info, event->time);
2752 gdk_drag_abort (info->context, event->time);
2753 gtk_drag_drop_finished (info, FALSE, event->time);
2759 /* Now send a "motion" so that the modifier state is updated */
2761 /* The state is not yet updated in the event, so we need
2762 * to query it here. We could use XGetModifierMapping, but
2763 * that would be overkill.
2765 gdk_window_get_pointer (GDK_ROOT_PARENT(), NULL, NULL, &state);
2767 event->state = state;
2768 gtk_drag_update (info, info->cur_x, info->cur_y, (GdkEvent *)event);
2773 /*************************************************************
2774 * gtk_drag_button_release_cb:
2775 * "button_release_event" callback during drag.
2779 *************************************************************/
2782 gtk_drag_button_release_cb (GtkWidget *widget,
2783 GdkEventButton *event,
2786 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2788 if (event->button != info->button)
2791 gtk_drag_end (info, event->time);
2793 if ((info->context->action != 0) && (info->context->dest_window != NULL))
2795 gtk_drag_drop (info, event->time);
2799 gdk_drag_abort (info->context, event->time);
2800 gtk_drag_drop_finished (info, FALSE, event->time);
2807 gtk_drag_abort_timeout (gpointer data)
2809 GtkDragSourceInfo *info = data;
2810 guint32 time = GDK_CURRENT_TIME;
2812 GDK_THREADS_ENTER ();
2814 if (info->proxy_dest)
2815 time = info->proxy_dest->proxy_drop_time;
2817 info->drop_timeout = 0;
2818 gtk_drag_drop_finished (info, FALSE, time);
2820 GDK_THREADS_LEAVE ();