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"
33 #elif defined (GDK_WINDOWING_NANOX)
34 #include "nanox/gdkprivate-nanox.h"
37 #include "gdk/gdkkeysyms.h"
40 #include "gtkinvisible.h"
42 #include "gtksignal.h"
43 #include "gtkwindow.h"
45 static GSList *drag_widgets = NULL;
46 static GSList *source_widgets = NULL;
48 typedef struct _GtkDragSourceSite GtkDragSourceSite;
49 typedef struct _GtkDragSourceInfo GtkDragSourceInfo;
50 typedef struct _GtkDragDestSite GtkDragDestSite;
51 typedef struct _GtkDragDestInfo GtkDragDestInfo;
52 typedef struct _GtkDragAnim GtkDragAnim;
53 typedef struct _GtkDragFindData GtkDragFindData;
63 struct _GtkDragSourceSite
65 GdkModifierType start_button_mask;
66 GtkTargetList *target_list; /* Targets for drag data */
67 GdkDragAction actions; /* Possible actions */
68 GdkColormap *colormap; /* Colormap for drag icon */
69 GdkPixmap *pixmap; /* Icon for drag data */
72 /* Stored button press information to detect drag beginning */
77 struct _GtkDragSourceInfo
80 GtkTargetList *target_list; /* Targets for drag data */
81 GdkDragAction possible_actions; /* Actions allowed by source */
82 GdkDragContext *context; /* drag context */
83 GtkWidget *icon_window; /* Window for drag */
84 GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */
85 GdkCursor *cursor; /* Cursor for drag */
86 gint hot_x, hot_y; /* Hot spot for drag */
87 gint button; /* mouse button starting drag */
89 GtkDragStatus status; /* drag status */
90 GdkEvent *last_event; /* motion event waiting for response */
92 gint start_x, start_y; /* Initial position */
93 gint cur_x, cur_y; /* Current Position */
95 GList *selections; /* selections we've claimed */
97 GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */
99 guint drop_timeout; /* Timeout for aborting drop */
100 guint destroy_icon : 1; /* If true, destroy icon_window
104 struct _GtkDragDestSite
106 GtkDestDefaults flags;
107 GtkTargetList *target_list;
108 GdkDragAction actions;
109 GdkWindow *proxy_window;
110 GdkDragProtocol proxy_protocol;
111 gboolean do_proxy : 1;
112 gboolean proxy_coords : 1;
113 gboolean have_drag : 1;
116 struct _GtkDragDestInfo
118 GtkWidget *widget; /* Widget in which drag is in */
119 GdkDragContext *context; /* Drag context */
120 GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */
121 GtkSelectionData *proxy_data; /* Set while retrieving proxied data */
122 gboolean dropped : 1; /* Set after we receive a drop */
123 guint32 proxy_drop_time; /* Timestamp for proxied drop */
124 gboolean proxy_drop_wait : 1; /* Set if we are waiting for a
125 * status reply before sending
128 gint drop_x, drop_y; /* Position of drop */
131 #define DROP_ABORT_TIME 300000
133 #define ANIM_STEP_TIME 50
134 #define ANIM_STEP_LENGTH 50
135 #define ANIM_MIN_STEPS 5
136 #define ANIM_MAX_STEPS 10
140 GtkDragSourceInfo *info;
145 struct _GtkDragFindData
149 GdkDragContext *context;
150 GtkDragDestInfo *info;
153 gboolean (*callback) (GtkWidget *widget, GdkDragContext *context,
154 gint x, gint y, guint32 time);
158 /* Enumeration for some targets we handle internally */
161 TARGET_MOTIF_SUCCESS = 0x40000000,
162 TARGET_MOTIF_FAILURE,
168 static GdkPixmap *default_icon_pixmap = NULL;
169 static GdkPixmap *default_icon_mask = NULL;
170 static GdkColormap *default_icon_colormap = NULL;
171 static gint default_icon_hot_x;
172 static gint default_icon_hot_y;
174 /* Forward declarations */
175 static void gtk_drag_get_event_actions (GdkEvent *event,
177 GdkDragAction actions,
178 GdkDragAction *suggested_action,
179 GdkDragAction *possible_actions);
180 static GdkCursor * gtk_drag_get_cursor (GdkDragAction action);
181 static GtkWidget *gtk_drag_get_ipc_widget (void);
182 static void gtk_drag_release_ipc_widget (GtkWidget *widget);
184 static void gtk_drag_highlight_paint (GtkWidget *widget);
185 static gboolean gtk_drag_highlight_expose (GtkWidget *widget,
186 GdkEventExpose *event,
190 static GdkAtom gtk_drag_dest_find_target (GtkWidget *widget,
191 GtkDragDestSite *site,
192 GdkDragContext *context);
193 static void gtk_drag_selection_received (GtkWidget *widget,
194 GtkSelectionData *selection_data,
197 static void gtk_drag_find_widget (GtkWidget *widget,
198 GtkDragFindData *data);
199 static void gtk_drag_proxy_begin (GtkWidget *widget,
200 GtkDragDestInfo *dest_info);
201 static void gtk_drag_dest_info_destroy (gpointer data);
202 static void gtk_drag_dest_realized (GtkWidget *widget);
203 static void gtk_drag_dest_site_destroy (gpointer data);
204 static void gtk_drag_dest_leave (GtkWidget *widget,
205 GdkDragContext *context,
207 static gboolean gtk_drag_dest_motion (GtkWidget *widget,
208 GdkDragContext *context,
212 static gboolean gtk_drag_dest_drop (GtkWidget *widget,
213 GdkDragContext *context,
218 static void gtk_drag_source_check_selection (GtkDragSourceInfo *info,
221 static void gtk_drag_source_release_selections (GtkDragSourceInfo *info,
223 static void gtk_drag_drop (GtkDragSourceInfo *info,
225 static void gtk_drag_drop_finished (GtkDragSourceInfo *info,
229 static gint gtk_drag_source_event_cb (GtkWidget *widget,
232 static void gtk_drag_source_site_destroy (gpointer data);
233 static void gtk_drag_selection_get (GtkWidget *widget,
234 GtkSelectionData *selection_data,
238 static gint gtk_drag_anim_timeout (gpointer data);
239 static void gtk_drag_remove_icon (GtkDragSourceInfo *info);
240 static void gtk_drag_source_info_destroy (gpointer data);
241 static void gtk_drag_update (GtkDragSourceInfo *info,
245 static gint gtk_drag_motion_cb (GtkWidget *widget,
246 GdkEventMotion *event,
248 static gint gtk_drag_key_cb (GtkWidget *widget,
251 static gint gtk_drag_button_release_cb (GtkWidget *widget,
252 GdkEventButton *event,
254 static gint gtk_drag_abort_timeout (gpointer data);
256 /************************
257 * Cursor and Icon data *
258 ************************/
260 #define action_ask_width 16
261 #define action_ask_height 16
262 static const guchar action_ask_bits[] = {
263 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xf8, 0xb6, 0xf7,
264 0xd6, 0xec, 0x66, 0xdb, 0x66, 0xdb, 0x96, 0xec, 0x76, 0xf7, 0x76, 0xfb,
265 0xf6, 0xfc, 0x72, 0xfb, 0x7a, 0xfb, 0xf8, 0xfc, };
267 #define action_ask_mask_width 16
268 #define action_ask_mask_height 16
269 static const guchar action_ask_mask_bits[] = {
270 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0xcf, 0x0f,
271 0xef, 0x1f, 0xff, 0x3c, 0xff, 0x3c, 0x6f, 0x1f, 0x8f, 0x0f, 0x8f, 0x07,
272 0x0f, 0x03, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x03, };
274 #define action_copy_width 16
275 #define action_copy_height 16
276 static const guchar action_copy_bits[] = {
277 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xfb, 0x76, 0xfb,
278 0x76, 0xfb, 0x06, 0x83, 0xf6, 0xbf, 0xf6, 0xbf, 0x06, 0x83, 0x76, 0xfb,
279 0x76, 0xfb, 0x72, 0xfb, 0x7a, 0xf8, 0xf8, 0xff, };
281 #define action_copy_mask_width 16
282 #define action_copy_mask_height 16
283 static const guchar action_copy_mask_bits[] = {
284 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0x8f, 0x07,
285 0x8f, 0x07, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x8f, 0x07,
286 0x8f, 0x07, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x00, };
288 #define action_move_width 16
289 #define action_move_height 16
290 static const guchar action_move_bits[] = {
291 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x96, 0xff, 0x26, 0xff,
292 0xc6, 0xf8, 0xd6, 0xe3, 0x96, 0x8f, 0xb6, 0xbf, 0x36, 0xc3, 0x76, 0xfb,
293 0x76, 0xfa, 0xf2, 0xfa, 0xfa, 0xf8, 0xf8, 0xff, };
295 #define action_move_mask_width 16
296 #define action_move_mask_height 16
297 static const guchar action_move_mask_bits[] = {
298 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x6f, 0x00, 0xff, 0x00,
299 0xff, 0x07, 0xef, 0x1f, 0xef, 0x7f, 0xcf, 0x7f, 0xcf, 0x3f, 0x8f, 0x07,
300 0x8f, 0x07, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x00, };
302 #define action_link_width 16
303 #define action_link_height 16
304 static const guchar action_link_bits[] = {
305 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x36, 0xf8, 0xd6, 0xf7,
306 0x66, 0xec, 0xa6, 0xe8, 0x26, 0xdf, 0xe6, 0xbd, 0xd6, 0xa7, 0xb6, 0xa8,
307 0xb6, 0xb1, 0x72, 0xdf, 0xfa, 0xe0, 0xf8, 0xff, };
309 #define action_link_mask_width 16
310 #define action_link_mask_height 16
311 static const guchar action_link_mask_bits[] = {
312 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xcf, 0x07, 0xef, 0x0f,
313 0xff, 0x1f, 0x7f, 0x1f, 0xff, 0x3f, 0xff, 0x7f, 0xef, 0x7f, 0xcf, 0x77,
314 0xcf, 0x7f, 0x8f, 0x3f, 0x07, 0x1f, 0x07, 0x00, };
316 #define action_none_width 16
317 #define action_none_height 16
318 static const guchar action_none_bits[] = {
319 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0xf6, 0xff, 0xf6, 0xff,
320 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff,
321 0xf6, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf8, 0xff, };
323 #define action_none_mask_width 16
324 #define action_none_mask_height 16
325 static const guchar action_none_mask_bits[] = {
326 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x0f, 0x00,
327 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00,
328 0x0f, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x07, 0x00, };
330 #define CURSOR_WIDTH 16
331 #define CURSOR_HEIGHT 16
334 GdkDragAction action;
339 { GDK_ACTION_DEFAULT, 0 },
340 { GDK_ACTION_ASK, action_ask_bits, action_ask_mask_bits, NULL },
341 { GDK_ACTION_COPY, action_copy_bits, action_copy_mask_bits, NULL },
342 { GDK_ACTION_MOVE, action_move_bits, action_move_mask_bits, NULL },
343 { GDK_ACTION_LINK, action_link_bits, action_link_mask_bits, NULL },
344 { 0 , action_none_bits, action_none_mask_bits, NULL },
347 static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[0]);
350 static const char *drag_default_xpm[] = {
363 " ...+++++++++++.. ",
364 " ..+.++++++++++++.. ",
365 " .++.++++++++++++.. ",
366 " .+++.++++++++++++.. ",
367 " .++++.++++++++++++. ",
368 " .+++.+++++++++++++.. ",
369 " .++.+++++++++++++++.. ",
370 " .+.+++++++++++++++++.. ",
371 " ..+++++++++++++++++++.. ",
372 " ..++++++++++++++++++++. ",
373 " .++++++++++++++++++++.. ",
374 " ..+++++++++++++++++.. ",
375 " .++++++++++++++++.. ",
376 " ..+++++++++++++... ",
388 /*********************
389 * Utility functions *
390 *********************/
392 /*************************************************************
393 * gtk_drag_get_ipc_widget:
394 * Return a invisible, off-screen, override-redirect
399 *************************************************************/
402 gtk_drag_get_ipc_widget (void)
408 GSList *tmp = drag_widgets;
409 result = drag_widgets->data;
410 drag_widgets = drag_widgets->next;
411 g_slist_free_1 (tmp);
415 result = gtk_invisible_new ();
416 gtk_widget_show (result);
422 /***************************************************************
423 * gtk_drag_release_ipc_widget:
424 * Releases widget retrieved with gtk_drag_get_ipc_widget ()
426 * widget: the widget to release.
428 ***************************************************************/
431 gtk_drag_release_ipc_widget (GtkWidget *widget)
433 drag_widgets = g_slist_prepend (drag_widgets, widget);
437 gtk_drag_get_event_time (GdkEvent *event)
439 guint32 tm = GDK_CURRENT_TIME;
444 case GDK_MOTION_NOTIFY:
445 tm = event->motion.time; break;
446 case GDK_BUTTON_PRESS:
447 case GDK_2BUTTON_PRESS:
448 case GDK_3BUTTON_PRESS:
449 case GDK_BUTTON_RELEASE:
450 tm = event->button.time; break;
452 case GDK_KEY_RELEASE:
453 tm = event->key.time; break;
454 case GDK_ENTER_NOTIFY:
455 case GDK_LEAVE_NOTIFY:
456 tm = event->crossing.time; break;
457 case GDK_PROPERTY_NOTIFY:
458 tm = event->property.time; break;
459 case GDK_SELECTION_CLEAR:
460 case GDK_SELECTION_REQUEST:
461 case GDK_SELECTION_NOTIFY:
462 tm = event->selection.time; break;
463 case GDK_PROXIMITY_IN:
464 case GDK_PROXIMITY_OUT:
465 tm = event->proximity.time; break;
466 default: /* use current time */
474 gtk_drag_get_event_actions (GdkEvent *event,
476 GdkDragAction actions,
477 GdkDragAction *suggested_action,
478 GdkDragAction *possible_actions)
480 *suggested_action = 0;
481 *possible_actions = 0;
485 GdkModifierType state = 0;
489 case GDK_MOTION_NOTIFY:
490 state = event->motion.state;
492 case GDK_BUTTON_PRESS:
493 case GDK_2BUTTON_PRESS:
494 case GDK_3BUTTON_PRESS:
495 case GDK_BUTTON_RELEASE:
496 state = event->button.state;
499 case GDK_KEY_RELEASE:
500 state = event->key.state;
502 case GDK_ENTER_NOTIFY:
503 case GDK_LEAVE_NOTIFY:
504 state = event->crossing.state;
510 if ((button == 2 || button == 3) && (actions & GDK_ACTION_ASK))
512 *suggested_action = GDK_ACTION_ASK;
513 *possible_actions = actions;
515 else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
517 if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
519 if (actions & GDK_ACTION_LINK)
521 *suggested_action = GDK_ACTION_LINK;
522 *possible_actions = GDK_ACTION_LINK;
525 else if (state & GDK_CONTROL_MASK)
527 if (actions & GDK_ACTION_COPY)
529 *suggested_action = GDK_ACTION_COPY;
530 *possible_actions = GDK_ACTION_COPY;
536 if (actions & GDK_ACTION_MOVE)
538 *suggested_action = GDK_ACTION_MOVE;
539 *possible_actions = GDK_ACTION_MOVE;
546 *possible_actions = actions;
548 if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK))
549 *suggested_action = GDK_ACTION_ASK;
550 else if (actions & GDK_ACTION_COPY)
551 *suggested_action = GDK_ACTION_COPY;
552 else if (actions & GDK_ACTION_MOVE)
553 *suggested_action = GDK_ACTION_MOVE;
554 else if (actions & GDK_ACTION_LINK)
555 *suggested_action = GDK_ACTION_LINK;
560 *possible_actions = actions;
562 if (actions & GDK_ACTION_COPY)
563 *suggested_action = GDK_ACTION_COPY;
564 else if (actions & GDK_ACTION_MOVE)
565 *suggested_action = GDK_ACTION_MOVE;
566 else if (actions & GDK_ACTION_LINK)
567 *suggested_action = GDK_ACTION_LINK;
574 gtk_drag_get_cursor (GdkDragAction action)
578 for (i = 0 ; i < n_drag_cursors - 1; i++)
579 if (drag_cursors[i].action == action)
582 if (drag_cursors[i].cursor == NULL)
587 gdk_bitmap_create_from_data (NULL,
588 drag_cursors[i].bits,
589 CURSOR_WIDTH, CURSOR_HEIGHT);
591 gdk_bitmap_create_from_data (NULL,
592 drag_cursors[i].mask,
593 CURSOR_WIDTH, CURSOR_HEIGHT);
595 gdk_color_white (gdk_colormap_get_system (), &bg);
596 gdk_color_black (gdk_colormap_get_system (), &fg);
598 drag_cursors[i].cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, 0, 0);
600 gdk_pixmap_unref (pixmap);
601 gdk_pixmap_unref (mask);
604 return drag_cursors[i].cursor;
607 /********************
609 ********************/
611 /*************************************************************
613 * Get the data for a drag or drop
615 * context - drag context
616 * target - format to retrieve the data in.
617 * time - timestamp of triggering event.
620 *************************************************************/
623 gtk_drag_get_data (GtkWidget *widget,
624 GdkDragContext *context,
628 GtkWidget *selection_widget;
630 g_return_if_fail (widget != NULL);
631 g_return_if_fail (context != NULL);
633 selection_widget = gtk_drag_get_ipc_widget ();
635 gdk_drag_context_ref (context);
636 gtk_widget_ref (widget);
638 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
639 GTK_SIGNAL_FUNC (gtk_drag_selection_received), widget);
641 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
643 gtk_selection_convert (selection_widget,
644 gdk_drag_get_selection (context),
650 /*************************************************************
651 * gtk_drag_get_source_widget:
652 * Get the widget the was the source of this drag, if
653 * the drag originated from this application.
655 * context: The drag context for this drag
657 * The source widget, or NULL if the drag originated from
658 * a different application.
659 *************************************************************/
662 gtk_drag_get_source_widget (GdkDragContext *context)
666 tmp_list = source_widgets;
669 GtkWidget *ipc_widget = tmp_list->data;
671 if (ipc_widget->window == context->source_window)
673 GtkDragSourceInfo *info;
674 info = gtk_object_get_data (GTK_OBJECT (ipc_widget), "gtk-info");
676 return info ? info->widget : NULL;
679 tmp_list = tmp_list->next;
685 /*************************************************************
687 * Notify the drag source that the transfer of data
690 * context: The drag context for this drag
691 * success: Was the data successfully transferred?
692 * time: The timestamp to use when notifying the destination.
694 *************************************************************/
697 gtk_drag_finish (GdkDragContext *context,
702 GdkAtom target = GDK_NONE;
704 g_return_if_fail (context != NULL);
708 target = gdk_atom_intern ("DELETE", FALSE);
710 else if (context->protocol == GDK_DRAG_PROTO_MOTIF)
712 target = gdk_atom_intern (success ?
713 "XmTRANSFER_SUCCESS" :
714 "XmTRANSFER_FAILURE",
718 if (target != GDK_NONE)
720 GtkWidget *selection_widget = gtk_drag_get_ipc_widget ();
722 gdk_drag_context_ref (context);
724 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
725 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
726 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
729 gtk_selection_convert (selection_widget,
730 gdk_drag_get_selection (context),
736 gdk_drop_finish (context, success, time);
739 /*************************************************************
740 * gtk_drag_highlight_paint:
741 * Paint a highlight indicating drag status onto the widget.
745 *************************************************************/
748 gtk_drag_highlight_paint (GtkWidget *widget)
750 gint x, y, width, height;
752 g_return_if_fail (widget != NULL);
754 if (GTK_WIDGET_DRAWABLE (widget))
756 if (GTK_WIDGET_NO_WINDOW (widget))
758 x = widget->allocation.x;
759 y = widget->allocation.y;
760 width = widget->allocation.width;
761 height = widget->allocation.height;
767 gdk_window_get_size (widget->window, &width, &height);
770 gtk_draw_shadow (widget->style, widget->window,
771 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
772 x, y, width, height);
774 gdk_draw_rectangle (widget->window,
775 widget->style->black_gc,
777 x, y, width - 1, height - 1);
781 /*************************************************************
782 * gtk_drag_highlight_expose:
783 * Callback for expose_event for highlighted widgets.
789 *************************************************************/
792 gtk_drag_highlight_expose (GtkWidget *widget,
793 GdkEventExpose *event,
796 gtk_drag_highlight_paint (widget);
800 /*************************************************************
801 * gtk_drag_highlight:
802 * Highlight the given widget in the default manner.
806 *************************************************************/
809 gtk_drag_highlight (GtkWidget *widget)
811 gtk_signal_connect_after (GTK_OBJECT (widget), "draw",
812 GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
814 gtk_signal_connect (GTK_OBJECT (widget), "expose_event",
815 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
818 gtk_widget_queue_draw (widget);
821 /*************************************************************
822 * gtk_drag_unhighlight:
823 * Refresh the given widget to remove the highlight.
827 *************************************************************/
830 gtk_drag_unhighlight (GtkWidget *widget)
832 g_return_if_fail (widget != NULL);
834 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
835 GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
837 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
838 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
841 gtk_widget_queue_clear (widget);
845 gtk_drag_dest_set_internal (GtkWidget *widget,
846 GtkDragDestSite *site)
848 GtkDragDestSite *old_site;
850 g_return_if_fail (widget != NULL);
852 /* HACK, do this in the destroy */
853 old_site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
855 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), old_site);
857 if (GTK_WIDGET_REALIZED (widget))
858 gtk_drag_dest_realized (widget);
860 gtk_signal_connect (GTK_OBJECT (widget), "realize",
861 GTK_SIGNAL_FUNC (gtk_drag_dest_realized), site);
863 gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
864 site, gtk_drag_dest_site_destroy);
868 /*************************************************************
870 * Register a drop site, and possibly add default behaviors.
873 * flags: Which types of default drag behavior to use
874 * targets: Table of targets that can be accepted
875 * n_targets: Number of of entries in targets
878 *************************************************************/
881 gtk_drag_dest_set (GtkWidget *widget,
882 GtkDestDefaults flags,
883 const GtkTargetEntry *targets,
885 GdkDragAction actions)
887 GtkDragDestSite *site;
889 g_return_if_fail (widget != NULL);
891 site = g_new (GtkDragDestSite, 1);
894 site->have_drag = FALSE;
896 site->target_list = gtk_target_list_new (targets, n_targets);
898 site->target_list = NULL;
900 site->actions = actions;
901 site->do_proxy = FALSE;
903 gtk_drag_dest_set_internal (widget, site);
906 /*************************************************************
907 * gtk_drag_dest_set_proxy:
908 * Set up this widget to proxy drags elsewhere.
911 * proxy_window: window to which forward drag events
912 * protocol: Drag protocol which the dest widget accepts
913 * use_coordinates: If true, send the same coordinates to the
914 * destination, because it is a embedded
917 *************************************************************/
920 gtk_drag_dest_set_proxy (GtkWidget *widget,
921 GdkWindow *proxy_window,
922 GdkDragProtocol protocol,
923 gboolean use_coordinates)
925 GtkDragDestSite *site;
927 g_return_if_fail (widget != NULL);
929 site = g_new (GtkDragDestSite, 1);
932 site->have_drag = FALSE;
933 site->target_list = NULL;
935 site->proxy_window = proxy_window;
937 gdk_window_ref (proxy_window);
938 site->do_proxy = TRUE;
939 site->proxy_protocol = protocol;
940 site->proxy_coords = use_coordinates;
942 gtk_drag_dest_set_internal (widget, site);
945 /*************************************************************
946 * gtk_drag_dest_unset
947 * Unregister this widget as a drag target.
951 *************************************************************/
954 gtk_drag_dest_unset (GtkWidget *widget)
956 g_return_if_fail (widget != NULL);
958 gtk_object_set_data (GTK_OBJECT (widget), "gtk-drag-dest", NULL);
961 /*************************************************************
962 * gtk_drag_dest_handle_event:
963 * Called from widget event handling code on Drag events
967 * toplevel: Toplevel widget that received the event
970 *************************************************************/
973 gtk_drag_dest_handle_event (GtkWidget *toplevel,
976 GtkDragDestInfo *info;
977 GdkDragContext *context;
979 g_return_if_fail (toplevel != NULL);
980 g_return_if_fail (event != NULL);
982 context = event->dnd.context;
984 info = g_dataset_get_data (context, "gtk-info");
987 info = g_new (GtkDragDestInfo, 1);
989 info->context = event->dnd.context;
990 info->proxy_source = NULL;
991 info->proxy_data = NULL;
992 info->dropped = FALSE;
993 info->proxy_drop_wait = FALSE;
994 g_dataset_set_data_full (context,
997 gtk_drag_dest_info_destroy);
1000 /* Find the widget for the event */
1001 switch (event->type)
1003 case GDK_DRAG_ENTER:
1006 case GDK_DRAG_LEAVE:
1009 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1010 info->widget = NULL;
1014 case GDK_DRAG_MOTION:
1015 case GDK_DROP_START:
1017 GtkDragFindData data;
1020 if (event->type == GDK_DROP_START)
1022 info->dropped = TRUE;
1023 /* We send a leave here so that the widget unhighlights
1028 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1029 info->widget = NULL;
1033 gdk_window_get_origin (toplevel->window, &tx, &ty);
1035 data.x = event->dnd.x_root - tx;
1036 data.y = event->dnd.y_root - ty;
1037 data.context = context;
1040 data.toplevel = TRUE;
1041 data.callback = (event->type == GDK_DRAG_MOTION) ?
1042 gtk_drag_dest_motion : gtk_drag_dest_drop;
1043 data.time = event->dnd.time;
1045 gtk_drag_find_widget (toplevel, &data);
1047 if (info->widget && !data.found)
1049 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1050 info->widget = NULL;
1055 if (event->type == GDK_DRAG_MOTION)
1058 gdk_drag_status (context, 0, event->dnd.time);
1060 else if (event->type == GDK_DROP_START && !info->proxy_source)
1062 gdk_drop_reply (context, data.found, event->dnd.time);
1063 if ((context->protocol == GDK_DRAG_PROTO_MOTIF) && !data.found)
1064 gtk_drag_finish (context, FALSE, FALSE, event->dnd.time);
1070 g_assert_not_reached ();
1074 /*************************************************************
1075 * gtk_drag_dest_find_target:
1076 * Decide on a target for the drag.
1081 *************************************************************/
1084 gtk_drag_dest_find_target (GtkWidget *widget,
1085 GtkDragDestSite *site,
1086 GdkDragContext *context)
1089 GList *tmp_source = NULL;
1090 GtkWidget *source_widget = gtk_drag_get_source_widget (context);
1092 tmp_target = site->target_list->list;
1095 GtkTargetPair *pair = tmp_target->data;
1096 tmp_source = context->targets;
1099 if (tmp_source->data == GUINT_TO_POINTER (pair->target))
1101 if ((!(pair->flags & GTK_TARGET_SAME_APP) || source_widget) &&
1102 (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget)))
1103 return pair->target;
1107 tmp_source = tmp_source->next;
1109 tmp_target = tmp_target->next;
1116 gtk_drag_selection_received (GtkWidget *widget,
1117 GtkSelectionData *selection_data,
1121 GdkDragContext *context;
1122 GtkDragDestInfo *info;
1123 GtkWidget *drop_widget;
1127 context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
1128 info = g_dataset_get_data (context, "gtk-info");
1130 if (info->proxy_data &&
1131 info->proxy_data->target == selection_data->target)
1133 gtk_selection_data_set (info->proxy_data,
1134 selection_data->type,
1135 selection_data->format,
1136 selection_data->data,
1137 selection_data->length);
1142 if (selection_data->target == gdk_atom_intern ("DELETE", FALSE))
1144 gtk_drag_finish (context, TRUE, FALSE, time);
1146 else if ((selection_data->target == gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE)) ||
1147 (selection_data->target == gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE)))
1153 GtkDragDestSite *site;
1155 site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest");
1157 if (site && site->target_list)
1161 if (gtk_target_list_find (site->target_list,
1162 selection_data->target,
1165 if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
1166 selection_data->length >= 0)
1167 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1168 "drag_data_received",
1169 context, info->drop_x, info->drop_y,
1176 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1177 "drag_data_received",
1178 context, info->drop_x, info->drop_y,
1179 selection_data, 0, time);
1182 if (site && site->flags & GTK_DEST_DEFAULT_DROP)
1185 gtk_drag_finish (context,
1186 (selection_data->length >= 0),
1187 (context->action == GDK_ACTION_MOVE),
1191 gtk_widget_unref (drop_widget);
1194 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
1195 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
1198 gtk_object_set_data (GTK_OBJECT (widget), "drag-context", NULL);
1199 gdk_drag_context_unref (context);
1201 gtk_drag_release_ipc_widget (widget);
1204 /*************************************************************
1205 * gtk_drag_find_widget:
1206 * Recursive callback used to locate widgets for
1207 * DRAG_MOTION and DROP_START events.
1211 *************************************************************/
1214 gtk_drag_find_widget (GtkWidget *widget,
1215 GtkDragFindData *data)
1217 GtkAllocation new_allocation;
1221 new_allocation = widget->allocation;
1223 if (data->found || !GTK_WIDGET_MAPPED (widget))
1226 /* Note that in the following code, we only count the
1227 * position as being inside a WINDOW widget if it is inside
1228 * widget->window; points that are outside of widget->window
1229 * but within the allocation are not counted. This is consistent
1230 * with the way we highlight drag targets.
1232 if (!GTK_WIDGET_NO_WINDOW (widget))
1234 new_allocation.x = 0;
1235 new_allocation.y = 0;
1240 GdkWindow *window = widget->window;
1241 while (window != widget->parent->window)
1243 gint tx, ty, twidth, theight;
1244 gdk_window_get_size (window, &twidth, &theight);
1246 if (new_allocation.x < 0)
1248 new_allocation.width += new_allocation.x;
1249 new_allocation.x = 0;
1251 if (new_allocation.y < 0)
1253 new_allocation.height += new_allocation.y;
1254 new_allocation.y = 0;
1256 if (new_allocation.x + new_allocation.width > twidth)
1257 new_allocation.width = twidth - new_allocation.x;
1258 if (new_allocation.y + new_allocation.height > theight)
1259 new_allocation.height = theight - new_allocation.y;
1261 gdk_window_get_position (window, &tx, &ty);
1262 new_allocation.x += tx;
1264 new_allocation.y += ty;
1267 window = gdk_window_get_parent (window);
1271 if (data->toplevel ||
1272 ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
1273 (data->x < new_allocation.x + new_allocation.width) &&
1274 (data->y < new_allocation.y + new_allocation.height)))
1276 /* First, check if the drag is in a valid drop site in
1277 * one of our children
1279 if (GTK_IS_CONTAINER (widget))
1281 GtkDragFindData new_data = *data;
1283 new_data.x -= x_offset;
1284 new_data.y -= y_offset;
1285 new_data.found = FALSE;
1286 new_data.toplevel = FALSE;
1288 gtk_container_forall (GTK_CONTAINER (widget),
1289 (GtkCallback)gtk_drag_find_widget,
1292 data->found = new_data.found;
1295 /* If not, and this widget is registered as a drop site, check to
1296 * emit "drag_motion" to check if we are actually in
1300 gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"))
1302 data->found = data->callback (widget,
1304 data->x - new_allocation.x,
1305 data->y - new_allocation.y,
1307 /* If so, send a "drag_leave" to the last widget */
1310 if (data->info->widget && data->info->widget != widget)
1312 gtk_drag_dest_leave (data->info->widget, data->context, data->time);
1314 data->info->widget = widget;
1321 gtk_drag_proxy_begin (GtkWidget *widget,
1322 GtkDragDestInfo *dest_info)
1324 GtkDragSourceInfo *source_info;
1327 source_info = g_new0 (GtkDragSourceInfo, 1);
1328 source_info->ipc_widget = gtk_drag_get_ipc_widget ();
1330 source_info->widget = widget;
1331 gtk_widget_ref (source_info->widget);
1332 source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
1333 dest_info->context->targets);
1335 source_info->target_list = gtk_target_list_new (NULL, 0);
1336 tmp_list = dest_info->context->targets;
1339 gtk_target_list_add (source_info->target_list,
1340 GPOINTER_TO_UINT (tmp_list->data), 0, 0);
1341 tmp_list = tmp_list->next;
1344 source_info->proxy_dest = dest_info;
1346 g_dataset_set_data (source_info->context, "gtk-info", source_info);
1348 gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget),
1350 GTK_SIGNAL_FUNC (gtk_drag_selection_get),
1353 dest_info->proxy_source = source_info;
1357 gtk_drag_dest_info_destroy (gpointer data)
1359 GtkDragDestInfo *info = data;
1365 gtk_drag_dest_realized (GtkWidget *widget)
1367 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1368 gdk_window_register_dnd (toplevel->window);
1372 gtk_drag_dest_site_destroy (gpointer data)
1374 GtkDragDestSite *site = data;
1376 if (site->target_list)
1377 gtk_target_list_unref (site->target_list);
1383 * Default drag handlers
1386 gtk_drag_dest_leave (GtkWidget *widget,
1387 GdkDragContext *context,
1390 GtkDragDestSite *site;
1392 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1393 g_return_if_fail (site != NULL);
1397 GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1399 if (info->proxy_source && !info->dropped)
1400 gdk_drag_abort (info->proxy_source->context, time);
1406 if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag)
1407 gtk_drag_unhighlight (widget);
1409 if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag)
1410 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_leave",
1413 site->have_drag = FALSE;
1418 gtk_drag_dest_motion (GtkWidget *widget,
1419 GdkDragContext *context,
1424 GtkDragDestSite *site;
1425 GdkDragAction action = 0;
1428 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1429 g_return_val_if_fail (site != NULL, FALSE);
1434 GdkEvent *current_event;
1435 GdkWindow *dest_window;
1436 GdkDragProtocol proto;
1438 GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1440 if (!info->proxy_source)
1441 gtk_drag_proxy_begin (widget, info);
1443 current_event = gtk_get_current_event ();
1445 if (site->proxy_window)
1447 dest_window = site->proxy_window;
1448 proto = site->proxy_protocol;
1452 gdk_drag_find_window (info->proxy_source->context,
1454 current_event->dnd.x_root,
1455 current_event->dnd.y_root,
1456 &dest_window, &proto);
1459 gdk_drag_motion (info->proxy_source->context,
1461 current_event->dnd.x_root,
1462 current_event->dnd.y_root,
1463 context->suggested_action,
1464 context->actions, time);
1466 if (!site->proxy_window && dest_window)
1467 gdk_window_unref (dest_window);
1469 selection = gdk_drag_get_selection (info->proxy_source->context);
1471 selection != gdk_drag_get_selection (info->context))
1472 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1474 gdk_event_free (current_event);
1479 if (site->flags & GTK_DEST_DEFAULT_MOTION)
1481 if (context->suggested_action & site->actions)
1482 action = context->suggested_action;
1489 if ((site->actions & (1 << i)) &&
1490 (context->actions & (1 << i)))
1498 if (action && gtk_drag_dest_find_target (widget, site, context))
1500 if (!site->have_drag)
1502 site->have_drag = TRUE;
1503 if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1504 gtk_drag_highlight (widget);
1507 gdk_drag_status (context, action, time);
1511 gdk_drag_status (context, 0, time);
1516 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_motion",
1517 context, x, y, time, &retval);
1519 return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1523 gtk_drag_dest_drop (GtkWidget *widget,
1524 GdkDragContext *context,
1529 GtkDragDestSite *site;
1530 GtkDragDestInfo *info;
1532 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1533 g_return_val_if_fail (site != NULL, FALSE);
1535 info = g_dataset_get_data (context, "gtk-info");
1536 g_return_val_if_fail (info != NULL, FALSE);
1543 if (info->proxy_source ||
1544 (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN))
1546 gtk_drag_drop (info->proxy_source, time);
1550 /* We need to synthesize a motion event, wait for a status,
1551 * and, if we get a good one, do a drop.
1554 GdkEvent *current_event;
1556 GdkWindow *dest_window;
1557 GdkDragProtocol proto;
1559 gtk_drag_proxy_begin (widget, info);
1560 info->proxy_drop_wait = TRUE;
1561 info->proxy_drop_time = time;
1563 current_event = gtk_get_current_event ();
1565 if (site->proxy_window)
1567 dest_window = site->proxy_window;
1568 proto = site->proxy_protocol;
1572 gdk_drag_find_window (info->proxy_source->context,
1574 current_event->dnd.x_root,
1575 current_event->dnd.y_root,
1576 &dest_window, &proto);
1579 gdk_drag_motion (info->proxy_source->context,
1581 current_event->dnd.x_root,
1582 current_event->dnd.y_root,
1583 context->suggested_action,
1584 context->actions, time);
1586 if (!site->proxy_window && dest_window)
1587 gdk_window_unref (dest_window);
1589 selection = gdk_drag_get_selection (info->proxy_source->context);
1591 selection != gdk_drag_get_selection (info->context))
1592 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1594 gdk_event_free (current_event);
1604 if (site->flags & GTK_DEST_DEFAULT_DROP)
1606 GdkAtom target = gtk_drag_dest_find_target (widget, site, context);
1608 if (target == GDK_NONE)
1611 gtk_drag_get_data (widget, context, target, time);
1614 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_drop",
1615 context, x, y, time, &retval);
1617 return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
1625 /*************************************************************
1626 * gtk_drag_begin: Start a drag operation
1629 * widget: Widget from which drag starts
1630 * handlers: List of handlers to supply the data for the drag
1631 * button: Button user used to start drag
1632 * time: Time of event starting drag
1635 *************************************************************/
1638 gtk_drag_begin (GtkWidget *widget,
1639 GtkTargetList *target_list,
1640 GdkDragAction actions,
1644 GtkDragSourceInfo *info;
1645 GList *targets = NULL;
1647 guint32 time = GDK_CURRENT_TIME;
1648 GdkDragAction possible_actions, suggested_action;
1650 g_return_val_if_fail (widget != NULL, NULL);
1651 g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
1652 g_return_val_if_fail (target_list != NULL, NULL);
1655 time = gdk_event_get_time (event);
1657 info = g_new0 (GtkDragSourceInfo, 1);
1658 info->ipc_widget = gtk_drag_get_ipc_widget ();
1659 source_widgets = g_slist_prepend (source_widgets, info->ipc_widget);
1661 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
1663 tmp_list = g_list_last (target_list->list);
1666 GtkTargetPair *pair = tmp_list->data;
1667 targets = g_list_prepend (targets,
1668 GINT_TO_POINTER (pair->target));
1669 tmp_list = tmp_list->prev;
1672 info->widget = widget;
1673 gtk_widget_ref (info->widget);
1675 info->context = gdk_drag_begin (info->ipc_widget->window, targets);
1676 g_list_free (targets);
1678 g_dataset_set_data (info->context, "gtk-info", info);
1680 info->button = button;
1681 info->target_list = target_list;
1682 gtk_target_list_ref (target_list);
1684 info->possible_actions = actions;
1686 info->cursor = NULL;
1687 info->status = GTK_DRAG_STATUS_DRAG;
1688 info->last_event = NULL;
1689 info->selections = NULL;
1690 info->icon_window = NULL;
1691 info->destroy_icon = FALSE;
1693 gtk_drag_get_event_actions (event, info->button, actions,
1694 &suggested_action, &possible_actions);
1696 info->cursor = gtk_drag_get_cursor (suggested_action);
1698 /* Set cur_x, cur_y here so if the "drag_begin" signal shows
1699 * the drag icon, it will be in the right place
1701 if (event && event->type == GDK_MOTION_NOTIFY)
1703 info->cur_x = event->motion.x_root;
1704 info->cur_y = event->motion.y_root;
1709 gdk_window_get_pointer (GDK_ROOT_PARENT (), &x, &y, NULL);
1715 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
1718 if (event && event->type == GDK_MOTION_NOTIFY)
1719 gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
1721 info->start_x = info->cur_x;
1722 info->start_y = info->cur_y;
1724 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "button_release_event",
1725 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info);
1726 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "motion_notify_event",
1727 GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info);
1728 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_press_event",
1729 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1730 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_release_event",
1731 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1732 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "selection_get",
1733 GTK_SIGNAL_FUNC (gtk_drag_selection_get), info);
1735 /* We use a GTK grab here to override any grabs that the widget
1736 * we are dragging from might have held
1738 gtk_grab_add (info->ipc_widget);
1739 if (gdk_pointer_grab (info->ipc_widget->window, FALSE,
1740 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1741 GDK_BUTTON_RELEASE_MASK, NULL,
1742 info->cursor, time) == 0)
1744 if (gdk_keyboard_grab (info->ipc_widget->window, FALSE, time) != 0)
1746 /* FIXME: This should be cleaned up... */
1750 ev.type = GDK_BUTTON_RELEASE;
1751 ev.button = info->button;
1753 gtk_drag_button_release_cb (widget, &ev, info);
1759 return info->context;
1762 /*************************************************************
1763 * gtk_drag_source_set:
1764 * Register a drop site, and possibly add default behaviors.
1767 * start_button_mask: Mask of allowed buttons to start drag
1768 * targets: Table of targets for this source
1770 * actions: Actions allowed for this source
1772 *************************************************************/
1775 gtk_drag_source_set (GtkWidget *widget,
1776 GdkModifierType start_button_mask,
1777 const GtkTargetEntry *targets,
1779 GdkDragAction actions)
1781 GtkDragSourceSite *site;
1783 g_return_if_fail (widget != NULL);
1785 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1787 gtk_widget_add_events (widget,
1788 gtk_widget_get_events (widget) |
1789 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1790 GDK_BUTTON_MOTION_MASK);
1794 if (site->target_list)
1795 gtk_target_list_unref (site->target_list);
1799 site = g_new0 (GtkDragSourceSite, 1);
1801 gtk_signal_connect (GTK_OBJECT (widget), "button_press_event",
1802 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1804 gtk_signal_connect (GTK_OBJECT (widget), "motion_notify_event",
1805 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1808 gtk_object_set_data_full (GTK_OBJECT (widget),
1810 site, gtk_drag_source_site_destroy);
1813 site->start_button_mask = start_button_mask;
1816 site->target_list = gtk_target_list_new (targets, n_targets);
1818 site->target_list = NULL;
1820 site->actions = actions;
1824 /*************************************************************
1825 * gtk_drag_source_unset
1826 * Unregister this widget as a drag source.
1830 *************************************************************/
1833 gtk_drag_source_unset (GtkWidget *widget)
1835 GtkDragSourceSite *site;
1837 g_return_if_fail (widget != NULL);
1839 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1843 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
1844 gtk_object_set_data (GTK_OBJECT (widget), "gtk-site-data", NULL);
1848 /*************************************************************
1849 * gtk_drag_source_set_icon:
1850 * Set an icon for drags from this source.
1852 * colormap: Colormap for this icon
1856 *************************************************************/
1859 gtk_drag_source_set_icon (GtkWidget *widget,
1860 GdkColormap *colormap,
1864 GtkDragSourceSite *site;
1866 g_return_if_fail (widget != NULL);
1868 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1869 g_return_if_fail (site != NULL);
1872 gdk_colormap_unref (site->colormap);
1874 gdk_pixmap_unref (site->pixmap);
1876 gdk_pixmap_unref (site->mask);
1878 site->colormap = colormap;
1880 gdk_colormap_ref (colormap);
1882 site->pixmap = pixmap;
1884 gdk_pixmap_ref (pixmap);
1888 gdk_pixmap_ref (mask);
1891 /*************************************************************
1892 * gtk_drag_set_icon_window:
1893 * Set a widget as the icon for a drag.
1900 *************************************************************/
1903 gtk_drag_set_icon_window (GdkDragContext *context,
1907 gboolean destroy_on_release)
1909 GtkDragSourceInfo *info;
1911 g_return_if_fail (context != NULL);
1912 g_return_if_fail (widget != NULL);
1914 info = g_dataset_get_data (context, "gtk-info");
1915 gtk_drag_remove_icon (info);
1917 info->icon_window = widget;
1918 info->hot_x = hot_x;
1919 info->hot_y = hot_y;
1923 gtk_widget_set_uposition (widget,
1924 info->cur_x - info->hot_x,
1925 info->cur_y - info->hot_y);
1926 gtk_widget_ref (widget);
1927 gdk_window_raise (widget->window);
1928 gtk_widget_show (widget);
1931 info->destroy_icon = destroy_on_release;
1934 /*************************************************************
1935 * gtk_drag_set_icon_widget:
1936 * Set a widget as the icon for a drag.
1943 *************************************************************/
1946 gtk_drag_set_icon_widget (GdkDragContext *context,
1951 g_return_if_fail (context != NULL);
1952 g_return_if_fail (widget != NULL);
1954 gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE);
1957 /*************************************************************
1958 * gtk_drag_set_icon_pixmap:
1959 * Set a widget as the icon for a drag.
1962 * colormap: Colormap for the icon window.
1968 *************************************************************/
1971 gtk_drag_set_icon_pixmap (GdkDragContext *context,
1972 GdkColormap *colormap,
1981 g_return_if_fail (context != NULL);
1982 g_return_if_fail (colormap != NULL);
1983 g_return_if_fail (pixmap != NULL);
1985 gdk_window_get_size (pixmap, &width, &height);
1987 gtk_widget_push_visual (gdk_colormap_get_visual (colormap));
1988 gtk_widget_push_colormap (colormap);
1990 window = gtk_window_new (GTK_WINDOW_POPUP);
1991 gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
1992 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
1994 gtk_widget_pop_visual ();
1995 gtk_widget_pop_colormap ();
1997 gtk_widget_set_usize (window, width, height);
1998 gtk_widget_realize (window);
2000 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
2003 gtk_widget_shape_combine_mask (window, mask, 0, 0);
2005 gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
2008 /*************************************************************
2009 * gtk_drag_set_icon_default:
2010 * Set the icon for a drag to the default icon.
2014 *************************************************************/
2017 gtk_drag_set_icon_default (GdkDragContext *context)
2019 g_return_if_fail (context != NULL);
2021 if (!default_icon_pixmap)
2023 default_icon_colormap = gdk_colormap_get_system ();
2024 default_icon_pixmap =
2025 gdk_pixmap_colormap_create_from_xpm_d (NULL,
2026 default_icon_colormap,
2028 NULL, (gchar **)drag_default_xpm);
2029 default_icon_hot_x = -2;
2030 default_icon_hot_y = -2;
2033 gtk_drag_set_icon_pixmap (context,
2034 default_icon_colormap,
2035 default_icon_pixmap,
2038 default_icon_hot_y);
2041 /*************************************************************
2042 * gtk_drag_set_default_icon:
2043 * Set a default icon for all drags as a pixmap.
2045 * colormap: Colormap for the icon window.
2051 *************************************************************/
2054 gtk_drag_set_default_icon (GdkColormap *colormap,
2060 g_return_if_fail (colormap != NULL);
2061 g_return_if_fail (pixmap != NULL);
2063 if (default_icon_colormap)
2064 gdk_colormap_unref (default_icon_colormap);
2065 if (default_icon_pixmap)
2066 gdk_pixmap_unref (default_icon_pixmap);
2067 if (default_icon_mask)
2068 gdk_pixmap_unref (default_icon_mask);
2070 default_icon_colormap = colormap;
2071 gdk_colormap_ref (colormap);
2073 default_icon_pixmap = pixmap;
2074 gdk_pixmap_ref (pixmap);
2076 default_icon_mask = mask;
2078 gdk_pixmap_ref (mask);
2080 default_icon_hot_x = hot_x;
2081 default_icon_hot_y = hot_y;
2085 /*************************************************************
2086 * gtk_drag_source_handle_event:
2087 * Called from widget event handling code on Drag events
2091 * toplevel: Toplevel widget that received the event
2094 *************************************************************/
2097 gtk_drag_source_handle_event (GtkWidget *widget,
2100 GtkDragSourceInfo *info;
2101 GdkDragContext *context;
2103 g_return_if_fail (widget != NULL);
2104 g_return_if_fail (event != NULL);
2106 context = event->dnd.context;
2107 info = g_dataset_get_data (context, "gtk-info");
2111 switch (event->type)
2113 case GDK_DRAG_STATUS:
2117 if (info->proxy_dest)
2119 if (!event->dnd.send_event)
2121 if (info->proxy_dest->proxy_drop_wait)
2123 gboolean result = context->action != 0;
2125 /* Aha - we can finally pass the MOTIF DROP on... */
2126 gdk_drop_reply (info->proxy_dest->context, result, info->proxy_dest->proxy_drop_time);
2128 gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
2130 gtk_drag_finish (info->proxy_dest->context, FALSE, FALSE, info->proxy_dest->proxy_drop_time);
2134 gdk_drag_status (info->proxy_dest->context,
2135 event->dnd.context->action,
2142 cursor = gtk_drag_get_cursor (event->dnd.context->action);
2143 if (info->cursor != cursor)
2145 #ifdef GDK_WINDOWING_X11
2146 XChangeActivePointerGrab (GDK_WINDOW_XDISPLAY (widget->window),
2147 PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask,
2148 ((GdkCursorPrivate *)cursor)->xcursor,
2150 #elif defined (GDK_WINDOWING_WIN32)
2151 gdk_pointer_grab (widget->window, FALSE,
2152 GDK_POINTER_MOTION_MASK |
2153 GDK_POINTER_MOTION_HINT_MASK |
2154 GDK_BUTTON_RELEASE_MASK,
2156 info->cursor, event->dnd.time);
2158 info->cursor = cursor;
2161 if (info->last_event)
2163 gtk_drag_update (info,
2164 info->cur_x, info->cur_y,
2166 info->last_event = NULL;
2172 case GDK_DROP_FINISHED:
2173 gtk_drag_drop_finished (info, TRUE, event->dnd.time);
2176 g_assert_not_reached ();
2180 /*************************************************************
2181 * gtk_drag_source_check_selection:
2182 * Check if we've set up handlers/claimed the selection
2183 * for a given drag. If not, add them.
2187 *************************************************************/
2190 gtk_drag_source_check_selection (GtkDragSourceInfo *info,
2196 tmp_list = info->selections;
2199 if (GPOINTER_TO_UINT (tmp_list->data) == selection)
2201 tmp_list = tmp_list->next;
2204 gtk_selection_owner_set (info->ipc_widget, selection, time);
2205 info->selections = g_list_prepend (info->selections,
2206 GUINT_TO_POINTER (selection));
2208 tmp_list = info->target_list->list;
2211 GtkTargetPair *pair = tmp_list->data;
2213 gtk_selection_add_target (info->ipc_widget,
2217 tmp_list = tmp_list->next;
2220 if (info->context->protocol == GDK_DRAG_PROTO_MOTIF)
2222 gtk_selection_add_target (info->ipc_widget,
2224 gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE),
2225 TARGET_MOTIF_SUCCESS);
2226 gtk_selection_add_target (info->ipc_widget,
2228 gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE),
2229 TARGET_MOTIF_FAILURE);
2232 gtk_selection_add_target (info->ipc_widget,
2234 gdk_atom_intern ("DELETE", FALSE),
2238 /*************************************************************
2239 * gtk_drag_drop_finished:
2240 * Clean up from the drag, and display snapback, if necessary.
2246 *************************************************************/
2249 gtk_drag_drop_finished (GtkDragSourceInfo *info,
2253 gtk_drag_source_release_selections (info, time);
2255 if (info->proxy_dest)
2257 /* The time from the event isn't reliable for Xdnd drags */
2258 gtk_drag_finish (info->proxy_dest->context, success, FALSE,
2259 info->proxy_dest->proxy_drop_time);
2260 gtk_drag_source_info_destroy (info);
2266 gtk_drag_source_info_destroy (info);
2270 GtkDragAnim *anim = g_new (GtkDragAnim, 1);
2274 anim->n_steps = MAX (info->cur_x - info->start_x,
2275 info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
2276 anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
2277 if (info->icon_window)
2279 gtk_widget_show (info->icon_window);
2280 gdk_window_raise (info->icon_window->window);
2283 /* Mark the context as dead, so if the destination decides
2284 * to respond really late, we still are OK.
2286 g_dataset_set_data (info->context, "gtk-info", NULL);
2287 gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
2293 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
2296 GList *tmp_list = info->selections;
2299 GdkAtom selection = GPOINTER_TO_UINT (tmp_list->data);
2300 if (gdk_selection_owner_get (selection) == info->ipc_widget->window)
2301 gtk_selection_owner_set (NULL, selection, time);
2302 tmp_list = tmp_list->next;
2305 g_list_free (info->selections);
2306 info->selections = NULL;
2309 /*************************************************************
2311 * Send a drop event.
2315 *************************************************************/
2318 gtk_drag_drop (GtkDragSourceInfo *info,
2321 if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN)
2323 GtkSelectionData selection_data;
2325 GdkAtom target = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
2327 tmp_list = info->target_list->list;
2330 GtkTargetPair *pair = tmp_list->data;
2332 if (pair->target == target)
2334 selection_data.selection = GDK_NONE;
2335 selection_data.target = target;
2336 selection_data.data = NULL;
2337 selection_data.length = -1;
2339 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2340 info->context, &selection_data,
2344 /* FIXME: Should we check for length >= 0 here? */
2345 gtk_drag_drop_finished (info, TRUE, time);
2348 tmp_list = tmp_list->next;
2350 gtk_drag_drop_finished (info, FALSE, time);
2354 if (info->icon_window)
2355 gtk_widget_hide (info->icon_window);
2357 gdk_drag_drop (info->context, time);
2358 info->drop_timeout = gtk_timeout_add (DROP_ABORT_TIME,
2359 gtk_drag_abort_timeout,
2365 * Source side callbacks.
2369 gtk_drag_source_event_cb (GtkWidget *widget,
2373 GtkDragSourceSite *site;
2374 site = (GtkDragSourceSite *)data;
2376 switch (event->type)
2378 case GDK_BUTTON_PRESS:
2379 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2381 site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1));
2382 site->x = event->button.x;
2383 site->y = event->button.y;
2387 case GDK_BUTTON_RELEASE:
2388 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2390 site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
2394 case GDK_MOTION_NOTIFY:
2395 if (site->state & event->motion.state & site->start_button_mask)
2397 /* FIXME: This is really broken and can leave us
2403 if (site->state & event->motion.state &
2404 GDK_BUTTON1_MASK << (i - 1))
2408 if (MAX (ABS (site->x - event->motion.x),
2409 ABS (site->y - event->motion.y)) > 3)
2411 GtkDragSourceInfo *info;
2412 GdkDragContext *context;
2415 context = gtk_drag_begin (widget, site->target_list,
2420 info = g_dataset_get_data (context, "gtk-info");
2422 if (!info->icon_window)
2425 gtk_drag_set_icon_pixmap (context,
2428 site->mask, -2, -2);
2430 gtk_drag_set_icon_default (context);
2438 default: /* hit for 2/3BUTTON_PRESS */
2445 gtk_drag_source_site_destroy (gpointer data)
2447 GtkDragSourceSite *site = data;
2449 if (site->target_list)
2450 gtk_target_list_unref (site->target_list);
2453 gdk_pixmap_unref (site->pixmap);
2456 gdk_pixmap_unref (site->mask);
2462 gtk_drag_selection_get (GtkWidget *widget,
2463 GtkSelectionData *selection_data,
2468 GtkDragSourceInfo *info = data;
2469 static GdkAtom null_atom = GDK_NONE;
2473 null_atom = gdk_atom_intern ("NULL", FALSE);
2478 gtk_signal_emit_by_name (GTK_OBJECT (info->widget),
2481 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2483 case TARGET_MOTIF_SUCCESS:
2484 gtk_drag_drop_finished (info, TRUE, time);
2485 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2487 case TARGET_MOTIF_FAILURE:
2488 gtk_drag_drop_finished (info, FALSE, time);
2489 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2492 if (info->proxy_dest)
2494 /* This is sort of dangerous and needs to be thought
2497 info->proxy_dest->proxy_data = selection_data;
2498 gtk_drag_get_data (info->widget,
2499 info->proxy_dest->context,
2500 selection_data->target,
2503 info->proxy_dest->proxy_data = NULL;
2507 if (gtk_target_list_find (info->target_list,
2508 selection_data->target,
2511 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2523 gtk_drag_anim_timeout (gpointer data)
2525 GtkDragAnim *anim = data;
2529 GDK_THREADS_ENTER ();
2531 if (anim->step == anim->n_steps)
2533 gtk_drag_source_info_destroy (anim->info);
2540 x = (anim->info->start_x * (anim->step + 1) +
2541 anim->info->cur_x * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2542 y = (anim->info->start_y * (anim->step + 1) +
2543 anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2544 if (anim->info->icon_window)
2545 gtk_widget_set_uposition (anim->info->icon_window,
2546 x - anim->info->hot_x,
2547 y - anim->info->hot_y);
2554 GDK_THREADS_LEAVE ();
2560 gtk_drag_remove_icon (GtkDragSourceInfo *info)
2562 if (info->icon_window)
2564 gtk_widget_hide (info->icon_window);
2565 if (info->destroy_icon)
2566 gtk_widget_destroy (info->icon_window);
2568 gtk_widget_unref (info->icon_window);
2569 info->icon_window = NULL;
2574 gtk_drag_source_info_destroy (gpointer data)
2576 GtkDragSourceInfo *info = data;
2578 gtk_drag_remove_icon (data);
2580 if (!info->proxy_dest)
2581 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end",
2585 gtk_widget_unref (info->widget);
2587 gtk_signal_disconnect_by_data (GTK_OBJECT (info->ipc_widget), info);
2588 gtk_selection_remove_all (info->ipc_widget);
2589 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", NULL);
2590 source_widgets = g_slist_remove (source_widgets, info->ipc_widget);
2591 gtk_drag_release_ipc_widget (info->ipc_widget);
2593 gtk_target_list_unref (info->target_list);
2595 g_dataset_set_data (info->context, "gtk-info", NULL);
2596 gdk_drag_context_unref (info->context);
2598 if (info->drop_timeout)
2599 gtk_timeout_remove (info->drop_timeout);
2604 /*************************************************************
2606 * Function to update the status of the drag when the
2607 * cursor moves or the modifier changes
2609 * info: DragSourceInfo for the drag
2610 * x_root, y_root: position of darg
2611 * event: The event that triggered this call
2613 *************************************************************/
2616 gtk_drag_update (GtkDragSourceInfo *info,
2621 GdkDragAction action;
2622 GdkDragAction possible_actions;
2623 GdkWindow *window = NULL;
2624 GdkWindow *dest_window;
2625 GdkDragProtocol protocol;
2627 guint32 time = gtk_drag_get_event_time (event);
2629 gtk_drag_get_event_actions (event,
2631 info->possible_actions,
2632 &action, &possible_actions);
2633 info->cur_x = x_root;
2634 info->cur_y = y_root;
2636 if (info->icon_window)
2638 gdk_window_raise (info->icon_window->window);
2639 gtk_widget_set_uposition (info->icon_window,
2640 info->cur_x - info->hot_x,
2641 info->cur_y - info->hot_y);
2642 window = info->icon_window->window;
2645 gdk_drag_find_window (info->context,
2646 window, x_root, y_root,
2647 &dest_window, &protocol);
2649 if (gdk_drag_motion (info->context, dest_window, protocol,
2650 x_root, y_root, action,
2654 if (info->last_event)
2655 gdk_event_free ((GdkEvent *)info->last_event);
2657 info->last_event = gdk_event_copy ((GdkEvent *)event);
2661 gdk_window_unref (dest_window);
2663 selection = gdk_drag_get_selection (info->context);
2665 gtk_drag_source_check_selection (info, selection, time);
2668 /*************************************************************
2670 * Called when the user finishes to drag, either by
2671 * releasing the mouse, or by pressing Esc.
2673 * widget: GtkInvisible widget for this drag
2676 *************************************************************/
2679 gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
2681 GdkEvent send_event;
2682 GtkWidget *source_widget = info->widget;
2684 gdk_pointer_ungrab (time);
2685 gdk_keyboard_ungrab (time);
2687 gtk_grab_remove (info->ipc_widget);
2689 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2690 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
2692 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2693 GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
2696 /* Send on a release pair to the the original
2697 * widget to convince it to release its grab. We need to
2698 * call gtk_propagate_event() here, instead of
2699 * gtk_widget_event() because widget like GtkList may
2700 * expect propagation.
2703 send_event.button.type = GDK_BUTTON_RELEASE;
2704 send_event.button.window = GDK_ROOT_PARENT ();
2705 send_event.button.send_event = TRUE;
2706 send_event.button.time = time;
2707 send_event.button.x = 0;
2708 send_event.button.y = 0;
2709 send_event.button.pressure = 0.;
2710 send_event.button.xtilt = 0.;
2711 send_event.button.ytilt = 0.;
2712 send_event.button.state = 0;
2713 send_event.button.button = info->button;
2714 send_event.button.source = GDK_SOURCE_PEN;
2715 send_event.button.deviceid = GDK_CORE_POINTER;
2716 send_event.button.x_root = 0;
2717 send_event.button.y_root = 0;
2719 gtk_propagate_event (source_widget, &send_event);
2722 /*************************************************************
2723 * gtk_drag_motion_cb:
2724 * "motion_notify_event" callback during drag.
2728 *************************************************************/
2731 gtk_drag_motion_cb (GtkWidget *widget,
2732 GdkEventMotion *event,
2735 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2736 gint x_root, y_root;
2740 gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL);
2741 event->x_root = x_root;
2742 event->y_root = y_root;
2745 gtk_drag_update (info, event->x_root, event->y_root, (GdkEvent *)event);
2750 /*************************************************************
2752 * "key_press/release_event" callback during drag.
2756 *************************************************************/
2759 gtk_drag_key_cb (GtkWidget *widget,
2763 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2764 GdkModifierType state;
2766 if (event->type == GDK_KEY_PRESS)
2768 if (event->keyval == GDK_Escape)
2770 gtk_drag_end (info, event->time);
2771 gdk_drag_abort (info->context, event->time);
2772 gtk_drag_drop_finished (info, FALSE, event->time);
2778 /* Now send a "motion" so that the modifier state is updated */
2780 /* The state is not yet updated in the event, so we need
2781 * to query it here. We could use XGetModifierMapping, but
2782 * that would be overkill.
2784 gdk_window_get_pointer (GDK_ROOT_PARENT(), NULL, NULL, &state);
2786 event->state = state;
2787 gtk_drag_update (info, info->cur_x, info->cur_y, (GdkEvent *)event);
2792 /*************************************************************
2793 * gtk_drag_button_release_cb:
2794 * "button_release_event" callback during drag.
2798 *************************************************************/
2801 gtk_drag_button_release_cb (GtkWidget *widget,
2802 GdkEventButton *event,
2805 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2807 if (event->button != info->button)
2810 gtk_drag_end (info, event->time);
2812 if ((info->context->action != 0) && (info->context->dest_window != NULL))
2814 gtk_drag_drop (info, event->time);
2818 gdk_drag_abort (info->context, event->time);
2819 gtk_drag_drop_finished (info, FALSE, event->time);
2826 gtk_drag_abort_timeout (gpointer data)
2828 GtkDragSourceInfo *info = data;
2829 guint32 time = GDK_CURRENT_TIME;
2831 GDK_THREADS_ENTER ();
2833 if (info->proxy_dest)
2834 time = info->proxy_dest->proxy_drop_time;
2836 info->drop_timeout = 0;
2837 gtk_drag_drop_finished (info, FALSE, time);
2839 GDK_THREADS_LEAVE ();