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/.
27 #include "gdkconfig.h"
29 #if defined (GDK_WINDOWING_X11)
31 #elif defined (GDK_WINDOWING_WIN32)
32 #include "win32/gdkwin32.h"
35 #include "gdk/gdkkeysyms.h"
38 #include "gtkinvisible.h"
40 #include "gtksignal.h"
41 #include "gtkwindow.h"
43 static GSList *drag_widgets = NULL;
44 static GSList *source_widgets = NULL;
46 typedef struct _GtkDragSourceSite GtkDragSourceSite;
47 typedef struct _GtkDragSourceInfo GtkDragSourceInfo;
48 typedef struct _GtkDragDestSite GtkDragDestSite;
49 typedef struct _GtkDragDestInfo GtkDragDestInfo;
50 typedef struct _GtkDragAnim GtkDragAnim;
51 typedef struct _GtkDragFindData GtkDragFindData;
61 struct _GtkDragSourceSite
63 GdkModifierType start_button_mask;
64 GtkTargetList *target_list; /* Targets for drag data */
65 GdkDragAction actions; /* Possible actions */
66 GdkColormap *colormap; /* Colormap for drag icon */
67 GdkPixmap *pixmap; /* Icon for drag data */
70 /* Stored button press information to detect drag beginning */
75 struct _GtkDragSourceInfo
78 GtkTargetList *target_list; /* Targets for drag data */
79 GdkDragAction possible_actions; /* Actions allowed by source */
80 GdkDragContext *context; /* drag context */
81 GtkWidget *icon_window; /* Window for drag */
82 GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */
83 GdkCursor *cursor; /* Cursor for drag */
84 gint hot_x, hot_y; /* Hot spot for drag */
85 gint button; /* mouse button starting drag */
87 GtkDragStatus status; /* drag status */
88 GdkEvent *last_event; /* motion event waiting for response */
90 gint start_x, start_y; /* Initial position */
91 gint cur_x, cur_y; /* Current Position */
93 GList *selections; /* selections we've claimed */
95 GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */
97 guint drop_timeout; /* Timeout for aborting drop */
98 guint destroy_icon : 1; /* If true, destroy icon_window
102 struct _GtkDragDestSite
104 GtkDestDefaults flags;
105 GtkTargetList *target_list;
106 GdkDragAction actions;
107 GdkWindow *proxy_window;
108 GdkDragProtocol proxy_protocol;
109 gboolean do_proxy : 1;
110 gboolean proxy_coords : 1;
111 gboolean have_drag : 1;
114 struct _GtkDragDestInfo
116 GtkWidget *widget; /* Widget in which drag is in */
117 GdkDragContext *context; /* Drag context */
118 GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */
119 GtkSelectionData *proxy_data; /* Set while retrieving proxied data */
120 gboolean dropped : 1; /* Set after we receive a drop */
121 guint32 proxy_drop_time; /* Timestamp for proxied drop */
122 gboolean proxy_drop_wait : 1; /* Set if we are waiting for a
123 * status reply before sending
126 gint drop_x, drop_y; /* Position of drop */
129 #define DROP_ABORT_TIME 300000
131 #define ANIM_STEP_TIME 50
132 #define ANIM_STEP_LENGTH 50
133 #define ANIM_MIN_STEPS 5
134 #define ANIM_MAX_STEPS 10
138 GtkDragSourceInfo *info;
143 struct _GtkDragFindData
147 GdkDragContext *context;
148 GtkDragDestInfo *info;
151 gboolean (*callback) (GtkWidget *widget, GdkDragContext *context,
152 gint x, gint y, guint32 time);
156 /* Enumeration for some targets we handle internally */
159 TARGET_MOTIF_SUCCESS = 0x40000000,
160 TARGET_MOTIF_FAILURE,
166 static GdkPixmap *default_icon_pixmap = NULL;
167 static GdkPixmap *default_icon_mask = NULL;
168 static GdkColormap *default_icon_colormap = NULL;
169 static gint default_icon_hot_x;
170 static gint default_icon_hot_y;
172 /* Forward declarations */
173 static void gtk_drag_get_event_actions (GdkEvent *event,
175 GdkDragAction actions,
176 GdkDragAction *suggested_action,
177 GdkDragAction *possible_actions);
178 static GdkCursor * gtk_drag_get_cursor (GdkDragAction action);
179 static GtkWidget *gtk_drag_get_ipc_widget (void);
180 static void gtk_drag_release_ipc_widget (GtkWidget *widget);
182 static void gtk_drag_highlight_paint (GtkWidget *widget);
183 static gboolean gtk_drag_highlight_expose (GtkWidget *widget,
184 GdkEventExpose *event,
188 static GdkAtom gtk_drag_dest_find_target (GtkWidget *widget,
189 GtkDragDestSite *site,
190 GdkDragContext *context);
191 static void gtk_drag_selection_received (GtkWidget *widget,
192 GtkSelectionData *selection_data,
195 static void gtk_drag_find_widget (GtkWidget *widget,
196 GtkDragFindData *data);
197 static void gtk_drag_proxy_begin (GtkWidget *widget,
198 GtkDragDestInfo *dest_info);
199 static void gtk_drag_dest_info_destroy (gpointer data);
200 static void gtk_drag_dest_realized (GtkWidget *widget);
201 static void gtk_drag_dest_site_destroy (gpointer data);
202 static void gtk_drag_dest_leave (GtkWidget *widget,
203 GdkDragContext *context,
205 static gboolean gtk_drag_dest_motion (GtkWidget *widget,
206 GdkDragContext *context,
210 static gboolean gtk_drag_dest_drop (GtkWidget *widget,
211 GdkDragContext *context,
216 static void gtk_drag_source_check_selection (GtkDragSourceInfo *info,
219 static void gtk_drag_source_release_selections (GtkDragSourceInfo *info,
221 static void gtk_drag_drop (GtkDragSourceInfo *info,
223 static void gtk_drag_drop_finished (GtkDragSourceInfo *info,
227 static gint gtk_drag_source_event_cb (GtkWidget *widget,
230 static void gtk_drag_source_site_destroy (gpointer data);
231 static void gtk_drag_selection_get (GtkWidget *widget,
232 GtkSelectionData *selection_data,
236 static gint gtk_drag_anim_timeout (gpointer data);
237 static void gtk_drag_remove_icon (GtkDragSourceInfo *info);
238 static void gtk_drag_source_info_destroy (gpointer data);
239 static void gtk_drag_update (GtkDragSourceInfo *info,
243 static gint gtk_drag_motion_cb (GtkWidget *widget,
244 GdkEventMotion *event,
246 static gint gtk_drag_key_cb (GtkWidget *widget,
249 static gint gtk_drag_button_release_cb (GtkWidget *widget,
250 GdkEventButton *event,
252 static gint gtk_drag_abort_timeout (gpointer data);
254 /************************
255 * Cursor and Icon data *
256 ************************/
258 #define action_ask_width 16
259 #define action_ask_height 16
260 static const guchar action_ask_bits[] = {
261 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xf8, 0xb6, 0xf7,
262 0xd6, 0xec, 0x66, 0xdb, 0x66, 0xdb, 0x96, 0xec, 0x76, 0xf7, 0x76, 0xfb,
263 0xf6, 0xfc, 0x72, 0xfb, 0x7a, 0xfb, 0xf8, 0xfc, };
265 #define action_ask_mask_width 16
266 #define action_ask_mask_height 16
267 static const guchar action_ask_mask_bits[] = {
268 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0xcf, 0x0f,
269 0xef, 0x1f, 0xff, 0x3c, 0xff, 0x3c, 0x6f, 0x1f, 0x8f, 0x0f, 0x8f, 0x07,
270 0x0f, 0x03, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x03, };
272 #define action_copy_width 16
273 #define action_copy_height 16
274 static const guchar action_copy_bits[] = {
275 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xfb, 0x76, 0xfb,
276 0x76, 0xfb, 0x06, 0x83, 0xf6, 0xbf, 0xf6, 0xbf, 0x06, 0x83, 0x76, 0xfb,
277 0x76, 0xfb, 0x72, 0xfb, 0x7a, 0xf8, 0xf8, 0xff, };
279 #define action_copy_mask_width 16
280 #define action_copy_mask_height 16
281 static const guchar action_copy_mask_bits[] = {
282 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0x8f, 0x07,
283 0x8f, 0x07, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x8f, 0x07,
284 0x8f, 0x07, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x00, };
286 #define action_move_width 16
287 #define action_move_height 16
288 static const guchar action_move_bits[] = {
289 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x96, 0xff, 0x26, 0xff,
290 0xc6, 0xf8, 0xd6, 0xe3, 0x96, 0x8f, 0xb6, 0xbf, 0x36, 0xc3, 0x76, 0xfb,
291 0x76, 0xfa, 0xf2, 0xfa, 0xfa, 0xf8, 0xf8, 0xff, };
293 #define action_move_mask_width 16
294 #define action_move_mask_height 16
295 static const guchar action_move_mask_bits[] = {
296 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x6f, 0x00, 0xff, 0x00,
297 0xff, 0x07, 0xef, 0x1f, 0xef, 0x7f, 0xcf, 0x7f, 0xcf, 0x3f, 0x8f, 0x07,
298 0x8f, 0x07, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x00, };
300 #define action_link_width 16
301 #define action_link_height 16
302 static const guchar action_link_bits[] = {
303 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x36, 0xf8, 0xd6, 0xf7,
304 0x66, 0xec, 0xa6, 0xe8, 0x26, 0xdf, 0xe6, 0xbd, 0xd6, 0xa7, 0xb6, 0xa8,
305 0xb6, 0xb1, 0x72, 0xdf, 0xfa, 0xe0, 0xf8, 0xff, };
307 #define action_link_mask_width 16
308 #define action_link_mask_height 16
309 static const guchar action_link_mask_bits[] = {
310 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xcf, 0x07, 0xef, 0x0f,
311 0xff, 0x1f, 0x7f, 0x1f, 0xff, 0x3f, 0xff, 0x7f, 0xef, 0x7f, 0xcf, 0x77,
312 0xcf, 0x7f, 0x8f, 0x3f, 0x07, 0x1f, 0x07, 0x00, };
314 #define action_none_width 16
315 #define action_none_height 16
316 static const guchar action_none_bits[] = {
317 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0xf6, 0xff, 0xf6, 0xff,
318 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff,
319 0xf6, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf8, 0xff, };
321 #define action_none_mask_width 16
322 #define action_none_mask_height 16
323 static const guchar action_none_mask_bits[] = {
324 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x0f, 0x00,
325 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00,
326 0x0f, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x07, 0x00, };
328 #define CURSOR_WIDTH 16
329 #define CURSOR_HEIGHT 16
332 GdkDragAction action;
337 { GDK_ACTION_DEFAULT, 0 },
338 { GDK_ACTION_ASK, action_ask_bits, action_ask_mask_bits, NULL },
339 { GDK_ACTION_COPY, action_copy_bits, action_copy_mask_bits, NULL },
340 { GDK_ACTION_MOVE, action_move_bits, action_move_mask_bits, NULL },
341 { GDK_ACTION_LINK, action_link_bits, action_link_mask_bits, NULL },
342 { 0 , action_none_bits, action_none_mask_bits, NULL },
345 static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[0]);
348 static const char *drag_default_xpm[] = {
361 " ...+++++++++++.. ",
362 " ..+.++++++++++++.. ",
363 " .++.++++++++++++.. ",
364 " .+++.++++++++++++.. ",
365 " .++++.++++++++++++. ",
366 " .+++.+++++++++++++.. ",
367 " .++.+++++++++++++++.. ",
368 " .+.+++++++++++++++++.. ",
369 " ..+++++++++++++++++++.. ",
370 " ..++++++++++++++++++++. ",
371 " .++++++++++++++++++++.. ",
372 " ..+++++++++++++++++.. ",
373 " .++++++++++++++++.. ",
374 " ..+++++++++++++... ",
386 /*********************
387 * Utility functions *
388 *********************/
390 /*************************************************************
391 * gtk_drag_get_ipc_widget:
392 * Return a invisible, off-screen, override-redirect
397 *************************************************************/
400 gtk_drag_get_ipc_widget (void)
406 GSList *tmp = drag_widgets;
407 result = drag_widgets->data;
408 drag_widgets = drag_widgets->next;
409 g_slist_free_1 (tmp);
413 result = gtk_invisible_new ();
414 gtk_widget_show (result);
420 /***************************************************************
421 * gtk_drag_release_ipc_widget:
422 * Releases widget retrieved with gtk_drag_get_ipc_widget ()
424 * widget: the widget to release.
426 ***************************************************************/
429 gtk_drag_release_ipc_widget (GtkWidget *widget)
431 drag_widgets = g_slist_prepend (drag_widgets, widget);
435 gtk_drag_get_event_time (GdkEvent *event)
437 guint32 tm = GDK_CURRENT_TIME;
442 case GDK_MOTION_NOTIFY:
443 tm = event->motion.time; break;
444 case GDK_BUTTON_PRESS:
445 case GDK_2BUTTON_PRESS:
446 case GDK_3BUTTON_PRESS:
447 case GDK_BUTTON_RELEASE:
448 tm = event->button.time; break;
450 case GDK_KEY_RELEASE:
451 tm = event->key.time; break;
452 case GDK_ENTER_NOTIFY:
453 case GDK_LEAVE_NOTIFY:
454 tm = event->crossing.time; break;
455 case GDK_PROPERTY_NOTIFY:
456 tm = event->property.time; break;
457 case GDK_SELECTION_CLEAR:
458 case GDK_SELECTION_REQUEST:
459 case GDK_SELECTION_NOTIFY:
460 tm = event->selection.time; break;
461 case GDK_PROXIMITY_IN:
462 case GDK_PROXIMITY_OUT:
463 tm = event->proximity.time; break;
464 default: /* use current time */
472 gtk_drag_get_event_actions (GdkEvent *event,
474 GdkDragAction actions,
475 GdkDragAction *suggested_action,
476 GdkDragAction *possible_actions)
478 *suggested_action = 0;
479 *possible_actions = 0;
483 GdkModifierType state = 0;
487 case GDK_MOTION_NOTIFY:
488 state = event->motion.state;
490 case GDK_BUTTON_PRESS:
491 case GDK_2BUTTON_PRESS:
492 case GDK_3BUTTON_PRESS:
493 case GDK_BUTTON_RELEASE:
494 state = event->button.state;
497 case GDK_KEY_RELEASE:
498 state = event->key.state;
500 case GDK_ENTER_NOTIFY:
501 case GDK_LEAVE_NOTIFY:
502 state = event->crossing.state;
508 if ((button == 2 || button == 3) && (actions & GDK_ACTION_ASK))
510 *suggested_action = GDK_ACTION_ASK;
511 *possible_actions = actions;
513 else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
515 if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
517 if (actions & GDK_ACTION_LINK)
519 *suggested_action = GDK_ACTION_LINK;
520 *possible_actions = GDK_ACTION_LINK;
523 else if (state & GDK_CONTROL_MASK)
525 if (actions & GDK_ACTION_COPY)
527 *suggested_action = GDK_ACTION_COPY;
528 *possible_actions = GDK_ACTION_COPY;
534 if (actions & GDK_ACTION_MOVE)
536 *suggested_action = GDK_ACTION_MOVE;
537 *possible_actions = GDK_ACTION_MOVE;
544 *possible_actions = actions;
546 if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK))
547 *suggested_action = GDK_ACTION_ASK;
548 else if (actions & GDK_ACTION_COPY)
549 *suggested_action = GDK_ACTION_COPY;
550 else if (actions & GDK_ACTION_MOVE)
551 *suggested_action = GDK_ACTION_MOVE;
552 else if (actions & GDK_ACTION_LINK)
553 *suggested_action = GDK_ACTION_LINK;
561 gtk_drag_get_cursor (GdkDragAction action)
565 for (i = 0 ; i < n_drag_cursors - 1; i++)
566 if (drag_cursors[i].action == action)
569 if (drag_cursors[i].cursor == NULL)
574 gdk_bitmap_create_from_data (NULL,
575 drag_cursors[i].bits,
576 CURSOR_WIDTH, CURSOR_HEIGHT);
578 gdk_bitmap_create_from_data (NULL,
579 drag_cursors[i].mask,
580 CURSOR_WIDTH, CURSOR_HEIGHT);
582 gdk_color_white (gdk_colormap_get_system (), &bg);
583 gdk_color_black (gdk_colormap_get_system (), &fg);
585 drag_cursors[i].cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, 0, 0);
587 gdk_pixmap_unref (pixmap);
588 gdk_pixmap_unref (mask);
591 return drag_cursors[i].cursor;
594 /********************
596 ********************/
598 /*************************************************************
600 * Get the data for a drag or drop
602 * context - drag context
603 * target - format to retrieve the data in.
604 * time - timestamp of triggering event.
607 *************************************************************/
610 gtk_drag_get_data (GtkWidget *widget,
611 GdkDragContext *context,
615 GtkWidget *selection_widget;
617 g_return_if_fail (widget != NULL);
618 g_return_if_fail (context != NULL);
620 selection_widget = gtk_drag_get_ipc_widget ();
622 gdk_drag_context_ref (context);
623 gtk_widget_ref (widget);
625 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
626 GTK_SIGNAL_FUNC (gtk_drag_selection_received), widget);
628 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
630 gtk_selection_convert (selection_widget,
631 gdk_drag_get_selection (context),
637 /*************************************************************
638 * gtk_drag_get_source_widget:
639 * Get the widget the was the source of this drag, if
640 * the drag originated from this application.
642 * context: The drag context for this drag
644 * The source widget, or NULL if the drag originated from
645 * a different application.
646 *************************************************************/
649 gtk_drag_get_source_widget (GdkDragContext *context)
653 tmp_list = source_widgets;
656 GtkWidget *ipc_widget = tmp_list->data;
658 if (ipc_widget->window == context->source_window)
660 GtkDragSourceInfo *info;
661 info = gtk_object_get_data (GTK_OBJECT (ipc_widget), "gtk-info");
663 return info ? info->widget : NULL;
666 tmp_list = tmp_list->next;
672 /*************************************************************
674 * Notify the drag source that the transfer of data
677 * context: The drag context for this drag
678 * success: Was the data successfully transferred?
679 * time: The timestamp to use when notifying the destination.
681 *************************************************************/
684 gtk_drag_finish (GdkDragContext *context,
689 GdkAtom target = GDK_NONE;
691 g_return_if_fail (context != NULL);
695 target = gdk_atom_intern ("DELETE", FALSE);
697 else if (context->protocol == GDK_DRAG_PROTO_MOTIF)
699 target = gdk_atom_intern (success ?
700 "XmTRANSFER_SUCCESS" :
701 "XmTRANSFER_FAILURE",
705 if (target != GDK_NONE)
707 GtkWidget *selection_widget = gtk_drag_get_ipc_widget ();
709 gdk_drag_context_ref (context);
711 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
712 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
713 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
716 gtk_selection_convert (selection_widget,
717 gdk_drag_get_selection (context),
723 gdk_drop_finish (context, success, time);
726 /*************************************************************
727 * gtk_drag_highlight_paint:
728 * Paint a highlight indicating drag status onto the widget.
732 *************************************************************/
735 gtk_drag_highlight_paint (GtkWidget *widget)
737 gint x, y, width, height;
739 g_return_if_fail (widget != NULL);
741 if (GTK_WIDGET_DRAWABLE (widget))
743 if (GTK_WIDGET_NO_WINDOW (widget))
745 x = widget->allocation.x;
746 y = widget->allocation.y;
747 width = widget->allocation.width;
748 height = widget->allocation.height;
754 gdk_window_get_size (widget->window, &width, &height);
757 gtk_draw_shadow (widget->style, widget->window,
758 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
759 x, y, width, height);
761 gdk_draw_rectangle (widget->window,
762 widget->style->black_gc,
764 x, y, width - 1, height - 1);
768 /*************************************************************
769 * gtk_drag_highlight_expose:
770 * Callback for expose_event for highlighted widgets.
776 *************************************************************/
779 gtk_drag_highlight_expose (GtkWidget *widget,
780 GdkEventExpose *event,
783 gtk_drag_highlight_paint (widget);
787 /*************************************************************
788 * gtk_drag_highlight:
789 * Highlight the given widget in the default manner.
793 *************************************************************/
796 gtk_drag_highlight (GtkWidget *widget)
798 gtk_signal_connect_after (GTK_OBJECT (widget), "draw",
799 GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
801 gtk_signal_connect (GTK_OBJECT (widget), "expose_event",
802 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
805 gtk_widget_queue_draw (widget);
808 /*************************************************************
809 * gtk_drag_unhighlight:
810 * Refresh the given widget to remove the highlight.
814 *************************************************************/
817 gtk_drag_unhighlight (GtkWidget *widget)
819 g_return_if_fail (widget != NULL);
821 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
822 GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
824 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
825 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
828 gtk_widget_queue_clear (widget);
831 /*************************************************************
833 * Register a drop site, and possibly add default behaviors.
836 * flags: Which types of default drag behavior to use
837 * targets: Table of targets that can be accepted
838 * n_targets: Number of of entries in targets
841 *************************************************************/
844 gtk_drag_dest_set (GtkWidget *widget,
845 GtkDestDefaults flags,
846 const GtkTargetEntry *targets,
848 GdkDragAction actions)
850 GtkDragDestSite *site;
852 g_return_if_fail (widget != NULL);
854 /* HACK, do this in the destroy */
855 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
857 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
859 if (GTK_WIDGET_REALIZED (widget))
860 gtk_drag_dest_realized (widget);
862 gtk_signal_connect (GTK_OBJECT (widget), "realize",
863 GTK_SIGNAL_FUNC (gtk_drag_dest_realized), NULL);
865 site = g_new (GtkDragDestSite, 1);
868 site->have_drag = FALSE;
870 site->target_list = gtk_target_list_new (targets, n_targets);
872 site->target_list = NULL;
874 site->actions = actions;
875 site->do_proxy = FALSE;
877 gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
878 site, gtk_drag_dest_site_destroy);
881 /*************************************************************
882 * gtk_drag_dest_set_proxy:
883 * Set up this widget to proxy drags elsewhere.
886 * proxy_window: window to which forward drag events
887 * protocol: Drag protocol which the dest widget accepts
888 * use_coordinates: If true, send the same coordinates to the
889 * destination, because it is a embedded
892 *************************************************************/
895 gtk_drag_dest_set_proxy (GtkWidget *widget,
896 GdkWindow *proxy_window,
897 GdkDragProtocol protocol,
898 gboolean use_coordinates)
900 GtkDragDestSite *site;
902 g_return_if_fail (widget != NULL);
904 /* HACK, do this in the destroy */
905 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
907 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
909 if (GTK_WIDGET_REALIZED (widget))
910 gtk_drag_dest_realized (widget);
912 gtk_signal_connect (GTK_OBJECT (widget), "realize",
913 GTK_SIGNAL_FUNC (gtk_drag_dest_realized), NULL);
915 site = g_new (GtkDragDestSite, 1);
918 site->have_drag = FALSE;
919 site->target_list = NULL;
921 site->proxy_window = proxy_window;
923 gdk_window_ref (proxy_window);
924 site->do_proxy = TRUE;
925 site->proxy_protocol = protocol;
926 site->proxy_coords = use_coordinates;
928 gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
929 site, gtk_drag_dest_site_destroy);
932 /*************************************************************
933 * gtk_drag_dest_unset
934 * Unregister this widget as a drag target.
938 *************************************************************/
941 gtk_drag_dest_unset (GtkWidget *widget)
943 g_return_if_fail (widget != NULL);
945 gtk_object_set_data (GTK_OBJECT (widget), "gtk-drag-dest", NULL);
948 /*************************************************************
949 * gtk_drag_dest_handle_event:
950 * Called from widget event handling code on Drag events
954 * toplevel: Toplevel widget that received the event
957 *************************************************************/
960 gtk_drag_dest_handle_event (GtkWidget *toplevel,
963 GtkDragDestInfo *info;
964 GdkDragContext *context;
966 g_return_if_fail (toplevel != NULL);
967 g_return_if_fail (event != NULL);
969 context = event->dnd.context;
971 info = g_dataset_get_data (context, "gtk-info");
974 info = g_new (GtkDragDestInfo, 1);
976 info->context = event->dnd.context;
977 info->proxy_source = NULL;
978 info->proxy_data = NULL;
979 info->dropped = FALSE;
980 info->proxy_drop_wait = FALSE;
981 g_dataset_set_data_full (context,
984 gtk_drag_dest_info_destroy);
987 /* Find the widget for the event */
996 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1001 case GDK_DRAG_MOTION:
1002 case GDK_DROP_START:
1004 GtkDragFindData data;
1007 if (event->type == GDK_DROP_START)
1009 info->dropped = TRUE;
1010 /* We send a leave here so that the widget unhighlights
1015 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1016 info->widget = NULL;
1020 gdk_window_get_origin (toplevel->window, &tx, &ty);
1022 data.x = event->dnd.x_root - tx;
1023 data.y = event->dnd.y_root - ty;
1024 data.context = context;
1027 data.toplevel = TRUE;
1028 data.callback = (event->type == GDK_DRAG_MOTION) ?
1029 gtk_drag_dest_motion : gtk_drag_dest_drop;
1030 data.time = event->dnd.time;
1032 gtk_drag_find_widget (toplevel, &data);
1034 if (info->widget && !data.found)
1036 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1037 info->widget = NULL;
1042 if (event->type == GDK_DRAG_MOTION)
1045 gdk_drag_status (context, 0, event->dnd.time);
1047 else if (event->type == GDK_DROP_START && !info->proxy_source)
1049 gdk_drop_reply (context, data.found, event->dnd.time);
1050 if ((context->protocol == GDK_DRAG_PROTO_MOTIF) && !data.found)
1051 gtk_drag_finish (context, FALSE, FALSE, event->dnd.time);
1057 g_assert_not_reached ();
1061 /*************************************************************
1062 * gtk_drag_dest_find_target:
1063 * Decide on a target for the drag.
1068 *************************************************************/
1071 gtk_drag_dest_find_target (GtkWidget *widget,
1072 GtkDragDestSite *site,
1073 GdkDragContext *context)
1076 GList *tmp_source = NULL;
1077 GtkWidget *source_widget = gtk_drag_get_source_widget (context);
1079 tmp_target = site->target_list->list;
1082 GtkTargetPair *pair = tmp_target->data;
1083 tmp_source = context->targets;
1086 if (tmp_source->data == GUINT_TO_POINTER (pair->target))
1088 if ((!(pair->flags & GTK_TARGET_SAME_APP) || source_widget) &&
1089 (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget)))
1090 return pair->target;
1094 tmp_source = tmp_source->next;
1096 tmp_target = tmp_target->next;
1103 gtk_drag_selection_received (GtkWidget *widget,
1104 GtkSelectionData *selection_data,
1108 GdkDragContext *context;
1109 GtkDragDestInfo *info;
1110 GtkWidget *drop_widget;
1114 context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
1115 info = g_dataset_get_data (context, "gtk-info");
1117 if (info->proxy_data &&
1118 info->proxy_data->target == selection_data->target)
1120 gtk_selection_data_set (info->proxy_data,
1121 selection_data->type,
1122 selection_data->format,
1123 selection_data->data,
1124 selection_data->length);
1129 if (selection_data->target == gdk_atom_intern ("DELETE", FALSE))
1131 gtk_drag_finish (context, TRUE, FALSE, time);
1133 else if ((selection_data->target == gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE)) ||
1134 (selection_data->target == gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE)))
1140 GtkDragDestSite *site;
1142 site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest");
1144 if (site->target_list)
1148 if (gtk_target_list_find (site->target_list,
1149 selection_data->target,
1152 if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
1153 selection_data->length >= 0)
1154 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1155 "drag_data_received",
1156 context, info->drop_x, info->drop_y,
1163 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1164 "drag_data_received",
1165 context, info->drop_x, info->drop_y,
1166 selection_data, 0, time);
1169 if (site->flags & GTK_DEST_DEFAULT_DROP)
1172 gtk_drag_finish (context,
1173 (selection_data->length >= 0),
1174 (context->action == GDK_ACTION_MOVE),
1178 gtk_widget_unref (drop_widget);
1181 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
1182 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
1185 gtk_object_set_data (GTK_OBJECT (widget), "drag-context", NULL);
1186 gdk_drag_context_unref (context);
1188 gtk_drag_release_ipc_widget (widget);
1191 /*************************************************************
1192 * gtk_drag_find_widget:
1193 * Recursive callback used to locate widgets for
1194 * DRAG_MOTION and DROP_START events.
1198 *************************************************************/
1201 gtk_drag_find_widget (GtkWidget *widget,
1202 GtkDragFindData *data)
1204 GtkAllocation new_allocation;
1208 new_allocation = widget->allocation;
1210 if (data->found || !GTK_WIDGET_MAPPED (widget))
1213 /* Note that in the following code, we only count the
1214 * position as being inside a WINDOW widget if it is inside
1215 * widget->window; points that are outside of widget->window
1216 * but within the allocation are not counted. This is consistent
1217 * with the way we highlight drag targets.
1219 if (!GTK_WIDGET_NO_WINDOW (widget))
1221 new_allocation.x = 0;
1222 new_allocation.y = 0;
1227 GdkWindow *window = widget->window;
1228 while (window != widget->parent->window)
1230 gint tx, ty, twidth, theight;
1231 gdk_window_get_size (window, &twidth, &theight);
1233 if (new_allocation.x < 0)
1235 new_allocation.width += new_allocation.x;
1236 new_allocation.x = 0;
1238 if (new_allocation.y < 0)
1240 new_allocation.height += new_allocation.y;
1241 new_allocation.y = 0;
1243 if (new_allocation.x + new_allocation.width > twidth)
1244 new_allocation.width = twidth - new_allocation.x;
1245 if (new_allocation.y + new_allocation.height > theight)
1246 new_allocation.height = theight - new_allocation.y;
1248 gdk_window_get_position (window, &tx, &ty);
1249 new_allocation.x += tx;
1251 new_allocation.y += ty;
1254 window = gdk_window_get_parent (window);
1258 if (data->toplevel ||
1259 ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
1260 (data->x < new_allocation.x + new_allocation.width) &&
1261 (data->y < new_allocation.y + new_allocation.height)))
1263 /* First, check if the drag is in a valid drop site in
1264 * one of our children
1266 if (GTK_IS_CONTAINER (widget))
1268 GtkDragFindData new_data = *data;
1270 new_data.x -= x_offset;
1271 new_data.y -= y_offset;
1272 new_data.found = FALSE;
1273 new_data.toplevel = FALSE;
1275 gtk_container_forall (GTK_CONTAINER (widget),
1276 (GtkCallback)gtk_drag_find_widget,
1279 data->found = new_data.found;
1282 /* If not, and this widget is registered as a drop site, check to
1283 * emit "drag_motion" to check if we are actually in
1287 gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"))
1289 data->found = data->callback (widget,
1291 data->x - new_allocation.x,
1292 data->y - new_allocation.y,
1294 /* If so, send a "drag_leave" to the last widget */
1297 if (data->info->widget && data->info->widget != widget)
1299 gtk_drag_dest_leave (data->info->widget, data->context, data->time);
1301 data->info->widget = widget;
1308 gtk_drag_proxy_begin (GtkWidget *widget,
1309 GtkDragDestInfo *dest_info)
1311 GtkDragSourceInfo *source_info;
1314 source_info = g_new0 (GtkDragSourceInfo, 1);
1315 source_info->ipc_widget = gtk_drag_get_ipc_widget ();
1317 source_info->widget = widget;
1318 gtk_widget_ref (source_info->widget);
1319 source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
1320 dest_info->context->targets);
1322 source_info->target_list = gtk_target_list_new (NULL, 0);
1323 tmp_list = dest_info->context->targets;
1326 gtk_target_list_add (source_info->target_list,
1327 GPOINTER_TO_UINT (tmp_list->data), 0, 0);
1328 tmp_list = tmp_list->next;
1331 source_info->proxy_dest = dest_info;
1333 g_dataset_set_data (source_info->context, "gtk-info", source_info);
1335 gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget),
1337 GTK_SIGNAL_FUNC (gtk_drag_selection_get),
1340 dest_info->proxy_source = source_info;
1344 gtk_drag_dest_info_destroy (gpointer data)
1346 GtkDragDestInfo *info = data;
1352 gtk_drag_dest_realized (GtkWidget *widget)
1354 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1355 gdk_window_register_dnd (toplevel->window);
1359 gtk_drag_dest_site_destroy (gpointer data)
1361 GtkDragDestSite *site = data;
1363 if (site->target_list)
1364 gtk_target_list_unref (site->target_list);
1370 * Default drag handlers
1373 gtk_drag_dest_leave (GtkWidget *widget,
1374 GdkDragContext *context,
1377 GtkDragDestSite *site;
1379 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1380 g_return_if_fail (site != NULL);
1384 GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1386 if (info->proxy_source && !info->dropped)
1387 gdk_drag_abort (info->proxy_source->context, time);
1393 if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag)
1394 gtk_drag_unhighlight (widget);
1396 if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag)
1397 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_leave",
1400 site->have_drag = FALSE;
1405 gtk_drag_dest_motion (GtkWidget *widget,
1406 GdkDragContext *context,
1411 GtkDragDestSite *site;
1412 GdkDragAction action = 0;
1415 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1416 g_return_val_if_fail (site != NULL, FALSE);
1421 GdkEvent *current_event;
1422 GdkWindow *dest_window;
1423 GdkDragProtocol proto;
1425 GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1427 if (!info->proxy_source)
1428 gtk_drag_proxy_begin (widget, info);
1430 current_event = gtk_get_current_event ();
1432 if (site->proxy_window)
1434 dest_window = site->proxy_window;
1435 proto = site->proxy_protocol;
1439 gdk_drag_find_window (info->proxy_source->context,
1441 current_event->dnd.x_root,
1442 current_event->dnd.y_root,
1443 &dest_window, &proto);
1446 gdk_drag_motion (info->proxy_source->context,
1448 current_event->dnd.x_root,
1449 current_event->dnd.y_root,
1450 context->suggested_action,
1451 context->actions, time);
1453 if (!site->proxy_window && dest_window)
1454 gdk_window_unref (dest_window);
1456 selection = gdk_drag_get_selection (info->proxy_source->context);
1458 selection != gdk_drag_get_selection (info->context))
1459 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1461 gdk_event_free (current_event);
1466 if (site->flags & GTK_DEST_DEFAULT_MOTION)
1468 if (context->suggested_action & site->actions)
1469 action = context->suggested_action;
1476 if ((site->actions & (1 << i)) &&
1477 (context->actions & (1 << i)))
1485 if (action && gtk_drag_dest_find_target (widget, site, context))
1487 if (!site->have_drag)
1489 site->have_drag = TRUE;
1490 if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1491 gtk_drag_highlight (widget);
1494 gdk_drag_status (context, action, time);
1498 gdk_drag_status (context, 0, time);
1503 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_motion",
1504 context, x, y, time, &retval);
1506 return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1510 gtk_drag_dest_drop (GtkWidget *widget,
1511 GdkDragContext *context,
1516 GtkDragDestSite *site;
1517 GtkDragDestInfo *info;
1519 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1520 g_return_val_if_fail (site != NULL, FALSE);
1522 info = g_dataset_get_data (context, "gtk-info");
1523 g_return_val_if_fail (info != NULL, FALSE);
1530 if (info->proxy_source ||
1531 (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN))
1533 gtk_drag_drop (info->proxy_source, time);
1537 /* We need to synthesize a motion event, wait for a status,
1538 * and, if we get a good one, do a drop.
1541 GdkEvent *current_event;
1543 GdkWindow *dest_window;
1544 GdkDragProtocol proto;
1546 gtk_drag_proxy_begin (widget, info);
1547 info->proxy_drop_wait = TRUE;
1548 info->proxy_drop_time = time;
1550 current_event = gtk_get_current_event ();
1552 if (site->proxy_window)
1554 dest_window = site->proxy_window;
1555 proto = site->proxy_protocol;
1559 gdk_drag_find_window (info->proxy_source->context,
1561 current_event->dnd.x_root,
1562 current_event->dnd.y_root,
1563 &dest_window, &proto);
1566 gdk_drag_motion (info->proxy_source->context,
1568 current_event->dnd.x_root,
1569 current_event->dnd.y_root,
1570 context->suggested_action,
1571 context->actions, time);
1573 if (!site->proxy_window && dest_window)
1574 gdk_window_unref (dest_window);
1576 selection = gdk_drag_get_selection (info->proxy_source->context);
1578 selection != gdk_drag_get_selection (info->context))
1579 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1581 gdk_event_free (current_event);
1591 if (site->flags & GTK_DEST_DEFAULT_DROP)
1593 GdkAtom target = gtk_drag_dest_find_target (widget, site, context);
1595 if (target == GDK_NONE)
1598 gtk_drag_get_data (widget, context, target, time);
1601 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_drop",
1602 context, x, y, time, &retval);
1604 return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
1612 /*************************************************************
1613 * gtk_drag_begin: Start a drag operation
1616 * widget: Widget from which drag starts
1617 * handlers: List of handlers to supply the data for the drag
1618 * button: Button user used to start drag
1619 * time: Time of event starting drag
1622 *************************************************************/
1625 gtk_drag_begin (GtkWidget *widget,
1626 GtkTargetList *target_list,
1627 GdkDragAction actions,
1631 GtkDragSourceInfo *info;
1632 GList *targets = NULL;
1634 guint32 time = GDK_CURRENT_TIME;
1635 GdkDragAction possible_actions, suggested_action;
1637 g_return_val_if_fail (widget != NULL, NULL);
1638 g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
1639 g_return_val_if_fail (target_list != NULL, NULL);
1642 time = gdk_event_get_time (event);
1644 info = g_new0 (GtkDragSourceInfo, 1);
1645 info->ipc_widget = gtk_drag_get_ipc_widget ();
1646 source_widgets = g_slist_prepend (source_widgets, info->ipc_widget);
1648 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
1650 tmp_list = g_list_last (target_list->list);
1653 GtkTargetPair *pair = tmp_list->data;
1654 targets = g_list_prepend (targets,
1655 GINT_TO_POINTER (pair->target));
1656 tmp_list = tmp_list->prev;
1659 info->widget = widget;
1660 gtk_widget_ref (info->widget);
1662 info->context = gdk_drag_begin (info->ipc_widget->window, targets);
1663 g_list_free (targets);
1665 g_dataset_set_data (info->context, "gtk-info", info);
1667 info->button = button;
1668 info->target_list = target_list;
1669 gtk_target_list_ref (target_list);
1671 info->possible_actions = actions;
1673 info->cursor = NULL;
1674 info->status = GTK_DRAG_STATUS_DRAG;
1675 info->last_event = NULL;
1676 info->selections = NULL;
1677 info->icon_window = NULL;
1678 info->destroy_icon = FALSE;
1680 gtk_drag_get_event_actions (event, info->button, actions,
1681 &suggested_action, &possible_actions);
1684 info->cursor = gtk_drag_get_cursor (suggested_action);
1686 /* Set cur_x, cur_y here so if the "drag_begin" signal shows
1687 * the drag icon, it will be in the right place
1689 if (event->type == GDK_MOTION_NOTIFY)
1691 info->cur_x = event->motion.x_root;
1692 info->cur_y = event->motion.y_root;
1697 gdk_window_get_pointer (GDK_ROOT_PARENT (), &x, &y, NULL);
1703 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
1706 if (event->type == GDK_MOTION_NOTIFY)
1707 gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
1709 info->start_x = info->cur_x;
1710 info->start_y = info->cur_y;
1712 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "button_release_event",
1713 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info);
1714 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "motion_notify_event",
1715 GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info);
1716 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_press_event",
1717 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1718 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_release_event",
1719 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1720 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "selection_get",
1721 GTK_SIGNAL_FUNC (gtk_drag_selection_get), info);
1723 /* We use a GTK grab here to override any grabs that the widget
1724 * we are dragging from might have held
1726 gtk_grab_add (info->ipc_widget);
1727 if (gdk_pointer_grab (info->ipc_widget->window, FALSE,
1728 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1729 GDK_BUTTON_RELEASE_MASK, NULL,
1730 info->cursor, time) == 0)
1732 if (gdk_keyboard_grab (info->ipc_widget->window, FALSE, time) != 0)
1734 /* FIXME: This should be cleaned up... */
1738 ev.type = GDK_BUTTON_RELEASE;
1739 ev.button = info->button;
1741 gtk_drag_button_release_cb (widget, &ev, info);
1747 return info->context;
1750 /*************************************************************
1751 * gtk_drag_source_set:
1752 * Register a drop site, and possibly add default behaviors.
1755 * start_button_mask: Mask of allowed buttons to start drag
1756 * targets: Table of targets for this source
1758 * actions: Actions allowed for this source
1760 *************************************************************/
1763 gtk_drag_source_set (GtkWidget *widget,
1764 GdkModifierType start_button_mask,
1765 const GtkTargetEntry *targets,
1767 GdkDragAction actions)
1769 GtkDragSourceSite *site;
1771 g_return_if_fail (widget != NULL);
1773 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1775 gtk_widget_add_events (widget,
1776 gtk_widget_get_events (widget) |
1777 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1778 GDK_BUTTON_MOTION_MASK);
1782 if (site->target_list)
1783 gtk_target_list_unref (site->target_list);
1787 site = g_new0 (GtkDragSourceSite, 1);
1789 gtk_signal_connect (GTK_OBJECT (widget), "button_press_event",
1790 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1792 gtk_signal_connect (GTK_OBJECT (widget), "motion_notify_event",
1793 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1796 gtk_object_set_data_full (GTK_OBJECT (widget),
1798 site, gtk_drag_source_site_destroy);
1801 site->start_button_mask = start_button_mask;
1804 site->target_list = gtk_target_list_new (targets, n_targets);
1806 site->target_list = NULL;
1808 site->actions = actions;
1812 /*************************************************************
1813 * gtk_drag_source_unset
1814 * Unregister this widget as a drag source.
1818 *************************************************************/
1821 gtk_drag_source_unset (GtkWidget *widget)
1823 GtkDragSourceSite *site;
1825 g_return_if_fail (widget != NULL);
1827 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1831 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
1832 gtk_object_set_data (GTK_OBJECT (widget), "gtk-site-data", NULL);
1836 /*************************************************************
1837 * gtk_drag_source_set_icon:
1838 * Set an icon for drags from this source.
1840 * colormap: Colormap for this icon
1844 *************************************************************/
1847 gtk_drag_source_set_icon (GtkWidget *widget,
1848 GdkColormap *colormap,
1852 GtkDragSourceSite *site;
1854 g_return_if_fail (widget != NULL);
1856 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1857 g_return_if_fail (site != NULL);
1860 gdk_colormap_unref (site->colormap);
1862 gdk_pixmap_unref (site->pixmap);
1864 gdk_pixmap_unref (site->mask);
1866 site->colormap = colormap;
1868 gdk_colormap_ref (colormap);
1870 site->pixmap = pixmap;
1872 gdk_pixmap_ref (pixmap);
1876 gdk_pixmap_ref (mask);
1879 /*************************************************************
1880 * gtk_drag_set_icon_window:
1881 * Set a widget as the icon for a drag.
1888 *************************************************************/
1891 gtk_drag_set_icon_window (GdkDragContext *context,
1895 gboolean destroy_on_release)
1897 GtkDragSourceInfo *info;
1899 g_return_if_fail (context != NULL);
1900 g_return_if_fail (widget != NULL);
1902 info = g_dataset_get_data (context, "gtk-info");
1903 gtk_drag_remove_icon (info);
1905 info->icon_window = widget;
1906 info->hot_x = hot_x;
1907 info->hot_y = hot_y;
1911 gtk_widget_set_uposition (widget,
1912 info->cur_x - info->hot_x,
1913 info->cur_y - info->hot_y);
1914 gtk_widget_ref (widget);
1915 gdk_window_raise (widget->window);
1916 gtk_widget_show (widget);
1919 info->destroy_icon = destroy_on_release;
1922 /*************************************************************
1923 * gtk_drag_set_icon_widget:
1924 * Set a widget as the icon for a drag.
1931 *************************************************************/
1934 gtk_drag_set_icon_widget (GdkDragContext *context,
1939 g_return_if_fail (context != NULL);
1940 g_return_if_fail (widget != NULL);
1942 gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE);
1945 /*************************************************************
1946 * gtk_drag_set_icon_pixmap:
1947 * Set a widget as the icon for a drag.
1950 * colormap: Colormap for the icon window.
1956 *************************************************************/
1959 gtk_drag_set_icon_pixmap (GdkDragContext *context,
1960 GdkColormap *colormap,
1969 g_return_if_fail (context != NULL);
1970 g_return_if_fail (colormap != NULL);
1971 g_return_if_fail (pixmap != NULL);
1973 gdk_window_get_size (pixmap, &width, &height);
1975 gtk_widget_push_visual (gdk_colormap_get_visual (colormap));
1976 gtk_widget_push_colormap (colormap);
1978 window = gtk_window_new (GTK_WINDOW_POPUP);
1979 gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
1980 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
1982 gtk_widget_pop_visual ();
1983 gtk_widget_pop_colormap ();
1985 gtk_widget_set_usize (window, width, height);
1986 gtk_widget_realize (window);
1988 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
1991 gtk_widget_shape_combine_mask (window, mask, 0, 0);
1993 gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
1996 /*************************************************************
1997 * gtk_drag_set_icon_default:
1998 * Set the icon for a drag to the default icon.
2002 *************************************************************/
2005 gtk_drag_set_icon_default (GdkDragContext *context)
2007 g_return_if_fail (context != NULL);
2009 if (!default_icon_pixmap)
2011 default_icon_colormap = gdk_colormap_get_system ();
2012 default_icon_pixmap =
2013 gdk_pixmap_colormap_create_from_xpm_d (NULL,
2014 default_icon_colormap,
2016 NULL, (gchar **)drag_default_xpm);
2017 default_icon_hot_x = -2;
2018 default_icon_hot_y = -2;
2021 gtk_drag_set_icon_pixmap (context,
2022 default_icon_colormap,
2023 default_icon_pixmap,
2026 default_icon_hot_y);
2029 /*************************************************************
2030 * gtk_drag_set_default_icon:
2031 * Set a default icon for all drags as a pixmap.
2033 * colormap: Colormap for the icon window.
2039 *************************************************************/
2042 gtk_drag_set_default_icon (GdkColormap *colormap,
2048 g_return_if_fail (colormap != NULL);
2049 g_return_if_fail (pixmap != NULL);
2051 if (default_icon_colormap)
2052 gdk_colormap_unref (default_icon_colormap);
2053 if (default_icon_pixmap)
2054 gdk_pixmap_unref (default_icon_pixmap);
2055 if (default_icon_mask)
2056 gdk_pixmap_unref (default_icon_pixmap);
2058 default_icon_colormap = colormap;
2059 gdk_colormap_ref (colormap);
2061 default_icon_pixmap = pixmap;
2062 gdk_pixmap_ref (pixmap);
2064 default_icon_mask = mask;
2066 gdk_pixmap_ref (mask);
2068 default_icon_hot_x = hot_x;
2069 default_icon_hot_y = hot_y;
2073 /*************************************************************
2074 * gtk_drag_source_handle_event:
2075 * Called from widget event handling code on Drag events
2079 * toplevel: Toplevel widget that received the event
2082 *************************************************************/
2085 gtk_drag_source_handle_event (GtkWidget *widget,
2088 GtkDragSourceInfo *info;
2089 GdkDragContext *context;
2091 g_return_if_fail (widget != NULL);
2092 g_return_if_fail (event != NULL);
2094 context = event->dnd.context;
2095 info = g_dataset_get_data (context, "gtk-info");
2099 switch (event->type)
2101 case GDK_DRAG_STATUS:
2105 if (info->proxy_dest)
2107 if (!event->dnd.send_event)
2109 if (info->proxy_dest->proxy_drop_wait)
2111 gboolean result = context->action != 0;
2113 /* Aha - we can finally pass the MOTIF DROP on... */
2114 gdk_drop_reply (info->proxy_dest->context, result, info->proxy_dest->proxy_drop_time);
2116 gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
2118 gtk_drag_finish (info->proxy_dest->context, FALSE, FALSE, info->proxy_dest->proxy_drop_time);
2122 gdk_drag_status (info->proxy_dest->context,
2123 event->dnd.context->action,
2130 cursor = gtk_drag_get_cursor (event->dnd.context->action);
2131 if (info->cursor != cursor)
2133 #ifdef GDK_WINDOWING_X11
2134 XChangeActivePointerGrab (GDK_WINDOW_XDISPLAY (widget->window),
2135 PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask,
2136 ((GdkCursorPrivate *)cursor)->xcursor,
2138 #elif defined (GDK_WINDOWING_WIN32)
2139 gdk_pointer_grab (widget->window, FALSE,
2140 GDK_POINTER_MOTION_MASK |
2141 GDK_POINTER_MOTION_HINT_MASK |
2142 GDK_BUTTON_RELEASE_MASK,
2144 info->cursor, event->dnd.time);
2146 info->cursor = cursor;
2149 if (info->last_event)
2151 gtk_drag_update (info,
2152 info->cur_x, info->cur_y,
2154 info->last_event = NULL;
2160 case GDK_DROP_FINISHED:
2161 gtk_drag_drop_finished (info, TRUE, event->dnd.time);
2164 g_assert_not_reached ();
2168 /*************************************************************
2169 * gtk_drag_source_check_selection:
2170 * Check if we've set up handlers/claimed the selection
2171 * for a given drag. If not, add them.
2175 *************************************************************/
2178 gtk_drag_source_check_selection (GtkDragSourceInfo *info,
2184 tmp_list = info->selections;
2187 if (GPOINTER_TO_UINT (tmp_list->data) == selection)
2189 tmp_list = tmp_list->next;
2192 gtk_selection_owner_set (info->ipc_widget, selection, time);
2193 info->selections = g_list_prepend (info->selections,
2194 GUINT_TO_POINTER (selection));
2196 tmp_list = info->target_list->list;
2199 GtkTargetPair *pair = tmp_list->data;
2201 gtk_selection_add_target (info->ipc_widget,
2205 tmp_list = tmp_list->next;
2208 if (info->context->protocol == GDK_DRAG_PROTO_MOTIF)
2210 gtk_selection_add_target (info->ipc_widget,
2212 gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE),
2213 TARGET_MOTIF_SUCCESS);
2214 gtk_selection_add_target (info->ipc_widget,
2216 gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE),
2217 TARGET_MOTIF_FAILURE);
2220 gtk_selection_add_target (info->ipc_widget,
2222 gdk_atom_intern ("DELETE", FALSE),
2226 /*************************************************************
2227 * gtk_drag_drop_finished:
2228 * Clean up from the drag, and display snapback, if necessary.
2234 *************************************************************/
2237 gtk_drag_drop_finished (GtkDragSourceInfo *info,
2241 gtk_drag_source_release_selections (info, time);
2243 if (info->proxy_dest)
2245 /* The time from the event isn't reliable for Xdnd drags */
2246 gtk_drag_finish (info->proxy_dest->context, success, FALSE,
2247 info->proxy_dest->proxy_drop_time);
2248 gtk_drag_source_info_destroy (info);
2254 gtk_drag_source_info_destroy (info);
2258 GtkDragAnim *anim = g_new (GtkDragAnim, 1);
2262 anim->n_steps = MAX (info->cur_x - info->start_x,
2263 info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
2264 anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
2265 if (info->icon_window)
2267 gtk_widget_show (info->icon_window);
2268 gdk_window_raise (info->icon_window->window);
2271 /* Mark the context as dead, so if the destination decides
2272 * to respond really late, we still are OK.
2274 g_dataset_set_data (info->context, "gtk-info", NULL);
2275 gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
2281 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
2284 GList *tmp_list = info->selections;
2287 GdkAtom selection = GPOINTER_TO_UINT (tmp_list->data);
2288 if (gdk_selection_owner_get (selection) == info->ipc_widget->window)
2289 gtk_selection_owner_set (NULL, selection, time);
2290 tmp_list = tmp_list->next;
2293 g_list_free (info->selections);
2294 info->selections = NULL;
2297 /*************************************************************
2299 * Send a drop event.
2303 *************************************************************/
2306 gtk_drag_drop (GtkDragSourceInfo *info,
2309 if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN)
2311 GtkSelectionData selection_data;
2313 GdkAtom target = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
2315 tmp_list = info->target_list->list;
2318 GtkTargetPair *pair = tmp_list->data;
2320 if (pair->target == target)
2322 selection_data.selection = GDK_NONE;
2323 selection_data.target = target;
2324 selection_data.data = NULL;
2325 selection_data.length = -1;
2327 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2328 info->context, &selection_data,
2332 /* FIXME: Should we check for length >= 0 here? */
2333 gtk_drag_drop_finished (info, TRUE, time);
2336 tmp_list = tmp_list->next;
2338 gtk_drag_drop_finished (info, FALSE, time);
2342 if (info->icon_window)
2343 gtk_widget_hide (info->icon_window);
2345 gdk_drag_drop (info->context, time);
2346 info->drop_timeout = gtk_timeout_add (DROP_ABORT_TIME,
2347 gtk_drag_abort_timeout,
2353 * Source side callbacks.
2357 gtk_drag_source_event_cb (GtkWidget *widget,
2361 GtkDragSourceSite *site;
2362 site = (GtkDragSourceSite *)data;
2364 switch (event->type)
2366 case GDK_BUTTON_PRESS:
2367 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2369 site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1));
2370 site->x = event->button.x;
2371 site->y = event->button.y;
2375 case GDK_BUTTON_RELEASE:
2376 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2378 site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
2382 case GDK_MOTION_NOTIFY:
2383 if (site->state & event->motion.state & site->start_button_mask)
2385 /* FIXME: This is really broken and can leave us
2391 if (site->state & event->motion.state &
2392 GDK_BUTTON1_MASK << (i - 1))
2396 if (MAX (ABS (site->x - event->motion.x),
2397 ABS (site->y - event->motion.y)) > 3)
2399 GtkDragSourceInfo *info;
2400 GdkDragContext *context;
2403 context = gtk_drag_begin (widget, site->target_list,
2408 info = g_dataset_get_data (context, "gtk-info");
2410 if (!info->icon_window)
2413 gtk_drag_set_icon_pixmap (context,
2416 site->mask, -2, -2);
2418 gtk_drag_set_icon_default (context);
2426 default: /* hit for 2/3BUTTON_PRESS */
2433 gtk_drag_source_site_destroy (gpointer data)
2435 GtkDragSourceSite *site = data;
2437 if (site->target_list)
2438 gtk_target_list_unref (site->target_list);
2441 gdk_pixmap_unref (site->pixmap);
2444 gdk_pixmap_unref (site->mask);
2450 gtk_drag_selection_get (GtkWidget *widget,
2451 GtkSelectionData *selection_data,
2456 GtkDragSourceInfo *info = data;
2457 static GdkAtom null_atom = GDK_NONE;
2461 null_atom = gdk_atom_intern ("NULL", FALSE);
2466 gtk_signal_emit_by_name (GTK_OBJECT (info->widget),
2469 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2471 case TARGET_MOTIF_SUCCESS:
2472 gtk_drag_drop_finished (info, TRUE, time);
2473 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2475 case TARGET_MOTIF_FAILURE:
2476 gtk_drag_drop_finished (info, FALSE, time);
2477 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2480 if (info->proxy_dest)
2482 /* This is sort of dangerous and needs to be thought
2485 info->proxy_dest->proxy_data = selection_data;
2486 gtk_drag_get_data (info->widget,
2487 info->proxy_dest->context,
2488 selection_data->target,
2491 info->proxy_dest->proxy_data = NULL;
2495 if (gtk_target_list_find (info->target_list,
2496 selection_data->target,
2499 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2511 gtk_drag_anim_timeout (gpointer data)
2513 GtkDragAnim *anim = data;
2517 GDK_THREADS_ENTER ();
2519 if (anim->step == anim->n_steps)
2521 gtk_drag_source_info_destroy (anim->info);
2528 x = (anim->info->start_x * (anim->step + 1) +
2529 anim->info->cur_x * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2530 y = (anim->info->start_y * (anim->step + 1) +
2531 anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2532 if (anim->info->icon_window)
2533 gtk_widget_set_uposition (anim->info->icon_window,
2534 x - anim->info->hot_x,
2535 y - anim->info->hot_y);
2542 GDK_THREADS_LEAVE ();
2548 gtk_drag_remove_icon (GtkDragSourceInfo *info)
2550 if (info->icon_window)
2552 gtk_widget_hide (info->icon_window);
2553 if (info->destroy_icon)
2554 gtk_widget_destroy (info->icon_window);
2556 gtk_widget_unref (info->icon_window);
2557 info->icon_window = NULL;
2562 gtk_drag_source_info_destroy (gpointer data)
2564 GtkDragSourceInfo *info = data;
2566 gtk_drag_remove_icon (data);
2568 if (!info->proxy_dest)
2569 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end",
2573 gtk_widget_unref (info->widget);
2575 gtk_signal_disconnect_by_data (GTK_OBJECT (info->ipc_widget), info);
2576 gtk_selection_remove_all (info->ipc_widget);
2577 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", NULL);
2578 source_widgets = g_slist_remove (source_widgets, info->ipc_widget);
2579 gtk_drag_release_ipc_widget (info->ipc_widget);
2581 gtk_target_list_unref (info->target_list);
2583 g_dataset_set_data (info->context, "gtk-info", NULL);
2584 gdk_drag_context_unref (info->context);
2586 if (info->drop_timeout)
2587 gtk_timeout_remove (info->drop_timeout);
2592 /*************************************************************
2594 * Function to update the status of the drag when the
2595 * cursor moves or the modifier changes
2597 * info: DragSourceInfo for the drag
2598 * x_root, y_root: position of darg
2599 * event: The event that triggered this call
2601 *************************************************************/
2604 gtk_drag_update (GtkDragSourceInfo *info,
2609 GdkDragAction action;
2610 GdkDragAction possible_actions;
2611 GdkWindow *window = NULL;
2612 GdkWindow *dest_window;
2613 GdkDragProtocol protocol;
2615 guint32 time = gtk_drag_get_event_time (event);
2617 gtk_drag_get_event_actions (event,
2619 info->possible_actions,
2620 &action, &possible_actions);
2621 info->cur_x = x_root;
2622 info->cur_y = y_root;
2624 if (info->icon_window)
2626 gdk_window_raise (info->icon_window->window);
2627 gtk_widget_set_uposition (info->icon_window,
2628 info->cur_x - info->hot_x,
2629 info->cur_y - info->hot_y);
2630 window = info->icon_window->window;
2633 gdk_drag_find_window (info->context,
2634 window, x_root, y_root,
2635 &dest_window, &protocol);
2637 if (gdk_drag_motion (info->context, dest_window, protocol,
2638 x_root, y_root, action,
2642 if (info->last_event)
2643 gdk_event_free ((GdkEvent *)info->last_event);
2645 info->last_event = gdk_event_copy ((GdkEvent *)event);
2649 gdk_window_unref (dest_window);
2651 selection = gdk_drag_get_selection (info->context);
2653 gtk_drag_source_check_selection (info, selection, time);
2656 /*************************************************************
2658 * Called when the user finishes to drag, either by
2659 * releasing the mouse, or by pressing Esc.
2661 * widget: GtkInvisible widget for this drag
2664 *************************************************************/
2667 gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
2669 GdkEvent send_event;
2670 GtkWidget *source_widget = info->widget;
2672 gdk_pointer_ungrab (time);
2673 gdk_keyboard_ungrab (time);
2675 gtk_grab_remove (info->ipc_widget);
2677 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2678 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
2680 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2681 GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
2684 /* Send on a release pair to the the original
2685 * widget to convince it to release its grab. We need to
2686 * call gtk_propagate_event() here, instead of
2687 * gtk_widget_event() because widget like GtkList may
2688 * expect propagation.
2691 send_event.button.type = GDK_BUTTON_RELEASE;
2692 send_event.button.window = GDK_ROOT_PARENT ();
2693 send_event.button.send_event = TRUE;
2694 send_event.button.time = time;
2695 send_event.button.x = 0;
2696 send_event.button.y = 0;
2697 send_event.button.pressure = 0.;
2698 send_event.button.xtilt = 0.;
2699 send_event.button.ytilt = 0.;
2700 send_event.button.state = 0;
2701 send_event.button.button = info->button;
2702 send_event.button.source = GDK_SOURCE_PEN;
2703 send_event.button.deviceid = GDK_CORE_POINTER;
2704 send_event.button.x_root = 0;
2705 send_event.button.y_root = 0;
2707 gtk_propagate_event (source_widget, &send_event);
2710 /*************************************************************
2711 * gtk_drag_motion_cb:
2712 * "motion_notify_event" callback during drag.
2716 *************************************************************/
2719 gtk_drag_motion_cb (GtkWidget *widget,
2720 GdkEventMotion *event,
2723 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2724 gint x_root, y_root;
2728 gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL);
2729 event->x_root = x_root;
2730 event->y_root = y_root;
2733 gtk_drag_update (info, event->x_root, event->y_root, (GdkEvent *)event);
2738 /*************************************************************
2740 * "key_press/release_event" callback during drag.
2744 *************************************************************/
2747 gtk_drag_key_cb (GtkWidget *widget,
2751 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2752 GdkModifierType state;
2754 if (event->type == GDK_KEY_PRESS)
2756 if (event->keyval == GDK_Escape)
2758 gtk_drag_end (info, event->time);
2759 gdk_drag_abort (info->context, event->time);
2760 gtk_drag_drop_finished (info, FALSE, event->time);
2766 /* Now send a "motion" so that the modifier state is updated */
2768 /* The state is not yet updated in the event, so we need
2769 * to query it here. We could use XGetModifierMapping, but
2770 * that would be overkill.
2772 gdk_window_get_pointer (GDK_ROOT_PARENT(), NULL, NULL, &state);
2774 event->state = state;
2775 gtk_drag_update (info, info->cur_x, info->cur_y, (GdkEvent *)event);
2780 /*************************************************************
2781 * gtk_drag_button_release_cb:
2782 * "button_release_event" callback during drag.
2786 *************************************************************/
2789 gtk_drag_button_release_cb (GtkWidget *widget,
2790 GdkEventButton *event,
2793 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2795 if (event->button != info->button)
2798 gtk_drag_end (info, event->time);
2800 if ((info->context->action != 0) && (info->context->dest_window != NULL))
2802 gtk_drag_drop (info, event->time);
2806 gdk_drag_abort (info->context, event->time);
2807 gtk_drag_drop_finished (info, FALSE, event->time);
2814 gtk_drag_abort_timeout (gpointer data)
2816 GtkDragSourceInfo *info = data;
2817 guint32 time = GDK_CURRENT_TIME;
2819 GDK_THREADS_ENTER ();
2821 if (info->proxy_dest)
2822 time = info->proxy_dest->proxy_drop_time;
2824 info->drop_timeout = 0;
2825 gtk_drag_drop_finished (info, FALSE, time);
2827 GDK_THREADS_LEAVE ();