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_FB)
34 #include "linux-fb/gdkfb.h"
35 #elif defined (GDK_WINDOWING_NANOX)
36 #include "nanox/gdkprivate-nanox.h"
39 #include "gdk/gdkkeysyms.h"
42 #include "gtkinvisible.h"
44 #include "gtksignal.h"
45 #include "gtkwindow.h"
47 static GSList *drag_widgets = NULL;
48 static GSList *source_widgets = NULL;
50 typedef struct _GtkDragSourceSite GtkDragSourceSite;
51 typedef struct _GtkDragSourceInfo GtkDragSourceInfo;
52 typedef struct _GtkDragDestSite GtkDragDestSite;
53 typedef struct _GtkDragDestInfo GtkDragDestInfo;
54 typedef struct _GtkDragAnim GtkDragAnim;
55 typedef struct _GtkDragFindData GtkDragFindData;
65 struct _GtkDragSourceSite
67 GdkModifierType start_button_mask;
68 GtkTargetList *target_list; /* Targets for drag data */
69 GdkDragAction actions; /* Possible actions */
70 GdkColormap *colormap; /* Colormap for drag icon */
71 GdkPixmap *pixmap; /* Icon for drag data */
74 /* Stored button press information to detect drag beginning */
79 struct _GtkDragSourceInfo
82 GtkTargetList *target_list; /* Targets for drag data */
83 GdkDragAction possible_actions; /* Actions allowed by source */
84 GdkDragContext *context; /* drag context */
85 GtkWidget *icon_window; /* Window for drag */
86 GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */
87 GdkCursor *cursor; /* Cursor for drag */
88 gint hot_x, hot_y; /* Hot spot for drag */
89 gint button; /* mouse button starting drag */
91 GtkDragStatus status; /* drag status */
92 GdkEvent *last_event; /* motion event waiting for response */
94 gint start_x, start_y; /* Initial position */
95 gint cur_x, cur_y; /* Current Position */
97 GList *selections; /* selections we've claimed */
99 GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */
101 guint drop_timeout; /* Timeout for aborting drop */
102 guint destroy_icon : 1; /* If true, destroy icon_window
106 struct _GtkDragDestSite
108 GtkDestDefaults flags;
109 GtkTargetList *target_list;
110 GdkDragAction actions;
111 GdkWindow *proxy_window;
112 GdkDragProtocol proxy_protocol;
113 gboolean do_proxy : 1;
114 gboolean proxy_coords : 1;
115 gboolean have_drag : 1;
118 struct _GtkDragDestInfo
120 GtkWidget *widget; /* Widget in which drag is in */
121 GdkDragContext *context; /* Drag context */
122 GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */
123 GtkSelectionData *proxy_data; /* Set while retrieving proxied data */
124 gboolean dropped : 1; /* Set after we receive a drop */
125 guint32 proxy_drop_time; /* Timestamp for proxied drop */
126 gboolean proxy_drop_wait : 1; /* Set if we are waiting for a
127 * status reply before sending
130 gint drop_x, drop_y; /* Position of drop */
133 #define DROP_ABORT_TIME 300000
135 #define ANIM_STEP_TIME 50
136 #define ANIM_STEP_LENGTH 50
137 #define ANIM_MIN_STEPS 5
138 #define ANIM_MAX_STEPS 10
142 GtkDragSourceInfo *info;
147 struct _GtkDragFindData
151 GdkDragContext *context;
152 GtkDragDestInfo *info;
155 gboolean (*callback) (GtkWidget *widget, GdkDragContext *context,
156 gint x, gint y, guint32 time);
160 /* Enumeration for some targets we handle internally */
163 TARGET_MOTIF_SUCCESS = 0x40000000,
164 TARGET_MOTIF_FAILURE,
170 static GdkPixmap *default_icon_pixmap = NULL;
171 static GdkPixmap *default_icon_mask = NULL;
172 static GdkColormap *default_icon_colormap = NULL;
173 static gint default_icon_hot_x;
174 static gint default_icon_hot_y;
176 /* Forward declarations */
177 static void gtk_drag_get_event_actions (GdkEvent *event,
179 GdkDragAction actions,
180 GdkDragAction *suggested_action,
181 GdkDragAction *possible_actions);
182 static GdkCursor * gtk_drag_get_cursor (GdkDragAction action);
183 static GtkWidget *gtk_drag_get_ipc_widget (void);
184 static void gtk_drag_release_ipc_widget (GtkWidget *widget);
186 static void gtk_drag_highlight_paint (GtkWidget *widget);
187 static gboolean gtk_drag_highlight_expose (GtkWidget *widget,
188 GdkEventExpose *event,
192 static GdkAtom gtk_drag_dest_find_target (GtkWidget *widget,
193 GtkDragDestSite *site,
194 GdkDragContext *context);
195 static void gtk_drag_selection_received (GtkWidget *widget,
196 GtkSelectionData *selection_data,
199 static void gtk_drag_find_widget (GtkWidget *widget,
200 GtkDragFindData *data);
201 static void gtk_drag_proxy_begin (GtkWidget *widget,
202 GtkDragDestInfo *dest_info);
203 static void gtk_drag_dest_info_destroy (gpointer data);
204 static void gtk_drag_dest_realized (GtkWidget *widget);
205 static void gtk_drag_dest_site_destroy (gpointer data);
206 static void gtk_drag_dest_leave (GtkWidget *widget,
207 GdkDragContext *context,
209 static gboolean gtk_drag_dest_motion (GtkWidget *widget,
210 GdkDragContext *context,
214 static gboolean gtk_drag_dest_drop (GtkWidget *widget,
215 GdkDragContext *context,
220 static void gtk_drag_source_check_selection (GtkDragSourceInfo *info,
223 static void gtk_drag_source_release_selections (GtkDragSourceInfo *info,
225 static void gtk_drag_drop (GtkDragSourceInfo *info,
227 static void gtk_drag_drop_finished (GtkDragSourceInfo *info,
231 static gint gtk_drag_source_event_cb (GtkWidget *widget,
234 static void gtk_drag_source_site_destroy (gpointer data);
235 static void gtk_drag_selection_get (GtkWidget *widget,
236 GtkSelectionData *selection_data,
240 static gint gtk_drag_anim_timeout (gpointer data);
241 static void gtk_drag_remove_icon (GtkDragSourceInfo *info);
242 static void gtk_drag_source_info_destroy (gpointer data);
243 static void gtk_drag_update (GtkDragSourceInfo *info,
247 static gint gtk_drag_motion_cb (GtkWidget *widget,
248 GdkEventMotion *event,
250 static gint gtk_drag_key_cb (GtkWidget *widget,
253 static gint gtk_drag_button_release_cb (GtkWidget *widget,
254 GdkEventButton *event,
256 static gint gtk_drag_abort_timeout (gpointer data);
258 /************************
259 * Cursor and Icon data *
260 ************************/
262 #define action_ask_width 16
263 #define action_ask_height 16
264 static const guchar action_ask_bits[] = {
265 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xf8, 0xb6, 0xf7,
266 0xd6, 0xec, 0x66, 0xdb, 0x66, 0xdb, 0x96, 0xec, 0x76, 0xf7, 0x76, 0xfb,
267 0xf6, 0xfc, 0x72, 0xfb, 0x7a, 0xfb, 0xf8, 0xfc, };
269 #define action_ask_mask_width 16
270 #define action_ask_mask_height 16
271 static const guchar action_ask_mask_bits[] = {
272 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0xcf, 0x0f,
273 0xef, 0x1f, 0xff, 0x3c, 0xff, 0x3c, 0x6f, 0x1f, 0x8f, 0x0f, 0x8f, 0x07,
274 0x0f, 0x03, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x03, };
276 #define action_copy_width 16
277 #define action_copy_height 16
278 static const guchar action_copy_bits[] = {
279 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xfb, 0x76, 0xfb,
280 0x76, 0xfb, 0x06, 0x83, 0xf6, 0xbf, 0xf6, 0xbf, 0x06, 0x83, 0x76, 0xfb,
281 0x76, 0xfb, 0x72, 0xfb, 0x7a, 0xf8, 0xf8, 0xff, };
283 #define action_copy_mask_width 16
284 #define action_copy_mask_height 16
285 static const guchar action_copy_mask_bits[] = {
286 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0x8f, 0x07,
287 0x8f, 0x07, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x8f, 0x07,
288 0x8f, 0x07, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x00, };
290 #define action_move_width 16
291 #define action_move_height 16
292 static const guchar action_move_bits[] = {
293 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x96, 0xff, 0x26, 0xff,
294 0xc6, 0xf8, 0xd6, 0xe3, 0x96, 0x8f, 0xb6, 0xbf, 0x36, 0xc3, 0x76, 0xfb,
295 0x76, 0xfa, 0xf2, 0xfa, 0xfa, 0xf8, 0xf8, 0xff, };
297 #define action_move_mask_width 16
298 #define action_move_mask_height 16
299 static const guchar action_move_mask_bits[] = {
300 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x6f, 0x00, 0xff, 0x00,
301 0xff, 0x07, 0xef, 0x1f, 0xef, 0x7f, 0xcf, 0x7f, 0xcf, 0x3f, 0x8f, 0x07,
302 0x8f, 0x07, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x00, };
304 #define action_link_width 16
305 #define action_link_height 16
306 static const guchar action_link_bits[] = {
307 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x36, 0xf8, 0xd6, 0xf7,
308 0x66, 0xec, 0xa6, 0xe8, 0x26, 0xdf, 0xe6, 0xbd, 0xd6, 0xa7, 0xb6, 0xa8,
309 0xb6, 0xb1, 0x72, 0xdf, 0xfa, 0xe0, 0xf8, 0xff, };
311 #define action_link_mask_width 16
312 #define action_link_mask_height 16
313 static const guchar action_link_mask_bits[] = {
314 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xcf, 0x07, 0xef, 0x0f,
315 0xff, 0x1f, 0x7f, 0x1f, 0xff, 0x3f, 0xff, 0x7f, 0xef, 0x7f, 0xcf, 0x77,
316 0xcf, 0x7f, 0x8f, 0x3f, 0x07, 0x1f, 0x07, 0x00, };
318 #define action_none_width 16
319 #define action_none_height 16
320 static const guchar action_none_bits[] = {
321 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0xf6, 0xff, 0xf6, 0xff,
322 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff,
323 0xf6, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf8, 0xff, };
325 #define action_none_mask_width 16
326 #define action_none_mask_height 16
327 static const guchar action_none_mask_bits[] = {
328 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x0f, 0x00,
329 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00,
330 0x0f, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x07, 0x00, };
332 #define CURSOR_WIDTH 16
333 #define CURSOR_HEIGHT 16
336 GdkDragAction action;
341 { GDK_ACTION_DEFAULT, 0 },
342 { GDK_ACTION_ASK, action_ask_bits, action_ask_mask_bits, NULL },
343 { GDK_ACTION_COPY, action_copy_bits, action_copy_mask_bits, NULL },
344 { GDK_ACTION_MOVE, action_move_bits, action_move_mask_bits, NULL },
345 { GDK_ACTION_LINK, action_link_bits, action_link_mask_bits, NULL },
346 { 0 , action_none_bits, action_none_mask_bits, NULL },
349 static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[0]);
352 static const char *drag_default_xpm[] = {
365 " ...+++++++++++.. ",
366 " ..+.++++++++++++.. ",
367 " .++.++++++++++++.. ",
368 " .+++.++++++++++++.. ",
369 " .++++.++++++++++++. ",
370 " .+++.+++++++++++++.. ",
371 " .++.+++++++++++++++.. ",
372 " .+.+++++++++++++++++.. ",
373 " ..+++++++++++++++++++.. ",
374 " ..++++++++++++++++++++. ",
375 " .++++++++++++++++++++.. ",
376 " ..+++++++++++++++++.. ",
377 " .++++++++++++++++.. ",
378 " ..+++++++++++++... ",
390 /*********************
391 * Utility functions *
392 *********************/
394 /*************************************************************
395 * gtk_drag_get_ipc_widget:
396 * Return a invisible, off-screen, override-redirect
401 *************************************************************/
404 gtk_drag_get_ipc_widget (void)
410 GSList *tmp = drag_widgets;
411 result = drag_widgets->data;
412 drag_widgets = drag_widgets->next;
413 g_slist_free_1 (tmp);
417 result = gtk_invisible_new ();
418 gtk_widget_show (result);
424 /***************************************************************
425 * gtk_drag_release_ipc_widget:
426 * Releases widget retrieved with gtk_drag_get_ipc_widget ()
428 * widget: the widget to release.
430 ***************************************************************/
433 gtk_drag_release_ipc_widget (GtkWidget *widget)
435 drag_widgets = g_slist_prepend (drag_widgets, widget);
439 gtk_drag_get_event_time (GdkEvent *event)
441 guint32 tm = GDK_CURRENT_TIME;
446 case GDK_MOTION_NOTIFY:
447 tm = event->motion.time; break;
448 case GDK_BUTTON_PRESS:
449 case GDK_2BUTTON_PRESS:
450 case GDK_3BUTTON_PRESS:
451 case GDK_BUTTON_RELEASE:
452 tm = event->button.time; break;
454 case GDK_KEY_RELEASE:
455 tm = event->key.time; break;
456 case GDK_ENTER_NOTIFY:
457 case GDK_LEAVE_NOTIFY:
458 tm = event->crossing.time; break;
459 case GDK_PROPERTY_NOTIFY:
460 tm = event->property.time; break;
461 case GDK_SELECTION_CLEAR:
462 case GDK_SELECTION_REQUEST:
463 case GDK_SELECTION_NOTIFY:
464 tm = event->selection.time; break;
465 case GDK_PROXIMITY_IN:
466 case GDK_PROXIMITY_OUT:
467 tm = event->proximity.time; break;
468 default: /* use current time */
476 gtk_drag_get_event_actions (GdkEvent *event,
478 GdkDragAction actions,
479 GdkDragAction *suggested_action,
480 GdkDragAction *possible_actions)
482 *suggested_action = 0;
483 *possible_actions = 0;
487 GdkModifierType state = 0;
491 case GDK_MOTION_NOTIFY:
492 state = event->motion.state;
494 case GDK_BUTTON_PRESS:
495 case GDK_2BUTTON_PRESS:
496 case GDK_3BUTTON_PRESS:
497 case GDK_BUTTON_RELEASE:
498 state = event->button.state;
501 case GDK_KEY_RELEASE:
502 state = event->key.state;
504 case GDK_ENTER_NOTIFY:
505 case GDK_LEAVE_NOTIFY:
506 state = event->crossing.state;
512 if ((button == 2 || button == 3) && (actions & GDK_ACTION_ASK))
514 *suggested_action = GDK_ACTION_ASK;
515 *possible_actions = actions;
517 else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
519 if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
521 if (actions & GDK_ACTION_LINK)
523 *suggested_action = GDK_ACTION_LINK;
524 *possible_actions = GDK_ACTION_LINK;
527 else if (state & GDK_CONTROL_MASK)
529 if (actions & GDK_ACTION_COPY)
531 *suggested_action = GDK_ACTION_COPY;
532 *possible_actions = GDK_ACTION_COPY;
538 if (actions & GDK_ACTION_MOVE)
540 *suggested_action = GDK_ACTION_MOVE;
541 *possible_actions = GDK_ACTION_MOVE;
548 *possible_actions = actions;
550 if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK))
551 *suggested_action = GDK_ACTION_ASK;
552 else if (actions & GDK_ACTION_COPY)
553 *suggested_action = GDK_ACTION_COPY;
554 else if (actions & GDK_ACTION_MOVE)
555 *suggested_action = GDK_ACTION_MOVE;
556 else if (actions & GDK_ACTION_LINK)
557 *suggested_action = GDK_ACTION_LINK;
562 *possible_actions = actions;
564 if (actions & GDK_ACTION_COPY)
565 *suggested_action = GDK_ACTION_COPY;
566 else if (actions & GDK_ACTION_MOVE)
567 *suggested_action = GDK_ACTION_MOVE;
568 else if (actions & GDK_ACTION_LINK)
569 *suggested_action = GDK_ACTION_LINK;
576 gtk_drag_get_cursor (GdkDragAction action)
580 for (i = 0 ; i < n_drag_cursors - 1; i++)
581 if (drag_cursors[i].action == action)
584 if (drag_cursors[i].cursor == NULL)
589 gdk_bitmap_create_from_data (NULL,
590 drag_cursors[i].bits,
591 CURSOR_WIDTH, CURSOR_HEIGHT);
593 gdk_bitmap_create_from_data (NULL,
594 drag_cursors[i].mask,
595 CURSOR_WIDTH, CURSOR_HEIGHT);
597 gdk_color_white (gdk_colormap_get_system (), &bg);
598 gdk_color_black (gdk_colormap_get_system (), &fg);
600 drag_cursors[i].cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, 0, 0);
602 gdk_pixmap_unref (pixmap);
603 gdk_pixmap_unref (mask);
606 return drag_cursors[i].cursor;
609 /********************
611 ********************/
613 /*************************************************************
615 * Get the data for a drag or drop
617 * context - drag context
618 * target - format to retrieve the data in.
619 * time - timestamp of triggering event.
622 *************************************************************/
625 gtk_drag_get_data (GtkWidget *widget,
626 GdkDragContext *context,
630 GtkWidget *selection_widget;
632 g_return_if_fail (widget != NULL);
633 g_return_if_fail (context != NULL);
635 selection_widget = gtk_drag_get_ipc_widget ();
637 gdk_drag_context_ref (context);
638 gtk_widget_ref (widget);
640 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
641 GTK_SIGNAL_FUNC (gtk_drag_selection_received), widget);
643 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
645 gtk_selection_convert (selection_widget,
646 gdk_drag_get_selection (context),
652 /*************************************************************
653 * gtk_drag_get_source_widget:
654 * Get the widget the was the source of this drag, if
655 * the drag originated from this application.
657 * context: The drag context for this drag
659 * The source widget, or NULL if the drag originated from
660 * a different application.
661 *************************************************************/
664 gtk_drag_get_source_widget (GdkDragContext *context)
668 tmp_list = source_widgets;
671 GtkWidget *ipc_widget = tmp_list->data;
673 if (ipc_widget->window == context->source_window)
675 GtkDragSourceInfo *info;
676 info = gtk_object_get_data (GTK_OBJECT (ipc_widget), "gtk-info");
678 return info ? info->widget : NULL;
681 tmp_list = tmp_list->next;
687 /*************************************************************
689 * Notify the drag source that the transfer of data
692 * context: The drag context for this drag
693 * success: Was the data successfully transferred?
694 * time: The timestamp to use when notifying the destination.
696 *************************************************************/
699 gtk_drag_finish (GdkDragContext *context,
704 GdkAtom target = GDK_NONE;
706 g_return_if_fail (context != NULL);
710 target = gdk_atom_intern ("DELETE", FALSE);
712 else if (context->protocol == GDK_DRAG_PROTO_MOTIF)
714 target = gdk_atom_intern (success ?
715 "XmTRANSFER_SUCCESS" :
716 "XmTRANSFER_FAILURE",
720 if (target != GDK_NONE)
722 GtkWidget *selection_widget = gtk_drag_get_ipc_widget ();
724 gdk_drag_context_ref (context);
726 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
727 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
728 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
731 gtk_selection_convert (selection_widget,
732 gdk_drag_get_selection (context),
738 gdk_drop_finish (context, success, time);
741 /*************************************************************
742 * gtk_drag_highlight_paint:
743 * Paint a highlight indicating drag status onto the widget.
747 *************************************************************/
750 gtk_drag_highlight_paint (GtkWidget *widget)
752 gint x, y, width, height;
754 g_return_if_fail (widget != NULL);
756 if (GTK_WIDGET_DRAWABLE (widget))
758 if (GTK_WIDGET_NO_WINDOW (widget))
760 x = widget->allocation.x;
761 y = widget->allocation.y;
762 width = widget->allocation.width;
763 height = widget->allocation.height;
769 gdk_window_get_size (widget->window, &width, &height);
772 gtk_draw_shadow (widget->style, widget->window,
773 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
774 x, y, width, height);
776 gdk_draw_rectangle (widget->window,
777 widget->style->black_gc,
779 x, y, width - 1, height - 1);
783 /*************************************************************
784 * gtk_drag_highlight_expose:
785 * Callback for expose_event for highlighted widgets.
791 *************************************************************/
794 gtk_drag_highlight_expose (GtkWidget *widget,
795 GdkEventExpose *event,
798 gtk_drag_highlight_paint (widget);
802 /*************************************************************
803 * gtk_drag_highlight:
804 * Highlight the given widget in the default manner.
808 *************************************************************/
811 gtk_drag_highlight (GtkWidget *widget)
813 gtk_signal_connect_after (GTK_OBJECT (widget), "draw",
814 GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
816 gtk_signal_connect (GTK_OBJECT (widget), "expose_event",
817 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
820 gtk_widget_queue_draw (widget);
823 /*************************************************************
824 * gtk_drag_unhighlight:
825 * Refresh the given widget to remove the highlight.
829 *************************************************************/
832 gtk_drag_unhighlight (GtkWidget *widget)
834 g_return_if_fail (widget != NULL);
836 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
837 GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
839 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
840 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
843 gtk_widget_queue_clear (widget);
847 gtk_drag_dest_set_internal (GtkWidget *widget,
848 GtkDragDestSite *site)
850 GtkDragDestSite *old_site;
852 g_return_if_fail (widget != NULL);
854 /* HACK, do this in the destroy */
855 old_site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
857 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), old_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), site);
865 gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
866 site, gtk_drag_dest_site_destroy);
870 /*************************************************************
872 * Register a drop site, and possibly add default behaviors.
875 * flags: Which types of default drag behavior to use
876 * targets: Table of targets that can be accepted
877 * n_targets: Number of of entries in targets
880 *************************************************************/
883 gtk_drag_dest_set (GtkWidget *widget,
884 GtkDestDefaults flags,
885 const GtkTargetEntry *targets,
887 GdkDragAction actions)
889 GtkDragDestSite *site;
891 g_return_if_fail (widget != NULL);
893 site = g_new (GtkDragDestSite, 1);
896 site->have_drag = FALSE;
898 site->target_list = gtk_target_list_new (targets, n_targets);
900 site->target_list = NULL;
902 site->actions = actions;
903 site->do_proxy = FALSE;
905 gtk_drag_dest_set_internal (widget, site);
908 /*************************************************************
909 * gtk_drag_dest_set_proxy:
910 * Set up this widget to proxy drags elsewhere.
913 * proxy_window: window to which forward drag events
914 * protocol: Drag protocol which the dest widget accepts
915 * use_coordinates: If true, send the same coordinates to the
916 * destination, because it is a embedded
919 *************************************************************/
922 gtk_drag_dest_set_proxy (GtkWidget *widget,
923 GdkWindow *proxy_window,
924 GdkDragProtocol protocol,
925 gboolean use_coordinates)
927 GtkDragDestSite *site;
929 g_return_if_fail (widget != NULL);
931 site = g_new (GtkDragDestSite, 1);
934 site->have_drag = FALSE;
935 site->target_list = NULL;
937 site->proxy_window = proxy_window;
939 gdk_window_ref (proxy_window);
940 site->do_proxy = TRUE;
941 site->proxy_protocol = protocol;
942 site->proxy_coords = use_coordinates;
944 gtk_drag_dest_set_internal (widget, site);
947 /*************************************************************
948 * gtk_drag_dest_unset
949 * Unregister this widget as a drag target.
953 *************************************************************/
956 gtk_drag_dest_unset (GtkWidget *widget)
958 g_return_if_fail (widget != NULL);
960 gtk_object_set_data (GTK_OBJECT (widget), "gtk-drag-dest", NULL);
963 /*************************************************************
964 * gtk_drag_dest_handle_event:
965 * Called from widget event handling code on Drag events
969 * toplevel: Toplevel widget that received the event
972 *************************************************************/
975 gtk_drag_dest_handle_event (GtkWidget *toplevel,
978 GtkDragDestInfo *info;
979 GdkDragContext *context;
981 g_return_if_fail (toplevel != NULL);
982 g_return_if_fail (event != NULL);
984 context = event->dnd.context;
986 info = g_dataset_get_data (context, "gtk-info");
989 info = g_new (GtkDragDestInfo, 1);
991 info->context = event->dnd.context;
992 info->proxy_source = NULL;
993 info->proxy_data = NULL;
994 info->dropped = FALSE;
995 info->proxy_drop_wait = FALSE;
996 g_dataset_set_data_full (context,
999 gtk_drag_dest_info_destroy);
1002 /* Find the widget for the event */
1003 switch (event->type)
1005 case GDK_DRAG_ENTER:
1008 case GDK_DRAG_LEAVE:
1011 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1012 info->widget = NULL;
1016 case GDK_DRAG_MOTION:
1017 case GDK_DROP_START:
1019 GtkDragFindData data;
1022 if (event->type == GDK_DROP_START)
1024 info->dropped = TRUE;
1025 /* We send a leave here so that the widget unhighlights
1030 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1031 info->widget = NULL;
1035 gdk_window_get_origin (toplevel->window, &tx, &ty);
1037 data.x = event->dnd.x_root - tx;
1038 data.y = event->dnd.y_root - ty;
1039 data.context = context;
1042 data.toplevel = TRUE;
1043 data.callback = (event->type == GDK_DRAG_MOTION) ?
1044 gtk_drag_dest_motion : gtk_drag_dest_drop;
1045 data.time = event->dnd.time;
1047 gtk_drag_find_widget (toplevel, &data);
1049 if (info->widget && !data.found)
1051 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1052 info->widget = NULL;
1057 if (event->type == GDK_DRAG_MOTION)
1060 gdk_drag_status (context, 0, event->dnd.time);
1062 else if (event->type == GDK_DROP_START && !info->proxy_source)
1064 gdk_drop_reply (context, data.found, event->dnd.time);
1065 if ((context->protocol == GDK_DRAG_PROTO_MOTIF) && !data.found)
1066 gtk_drag_finish (context, FALSE, FALSE, event->dnd.time);
1072 g_assert_not_reached ();
1076 /*************************************************************
1077 * gtk_drag_dest_find_target:
1078 * Decide on a target for the drag.
1083 *************************************************************/
1086 gtk_drag_dest_find_target (GtkWidget *widget,
1087 GtkDragDestSite *site,
1088 GdkDragContext *context)
1091 GList *tmp_source = NULL;
1092 GtkWidget *source_widget = gtk_drag_get_source_widget (context);
1094 tmp_target = site->target_list->list;
1097 GtkTargetPair *pair = tmp_target->data;
1098 tmp_source = context->targets;
1101 if (tmp_source->data == GUINT_TO_POINTER (pair->target))
1103 if ((!(pair->flags & GTK_TARGET_SAME_APP) || source_widget) &&
1104 (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget)))
1105 return pair->target;
1109 tmp_source = tmp_source->next;
1111 tmp_target = tmp_target->next;
1118 gtk_drag_selection_received (GtkWidget *widget,
1119 GtkSelectionData *selection_data,
1123 GdkDragContext *context;
1124 GtkDragDestInfo *info;
1125 GtkWidget *drop_widget;
1129 context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
1130 info = g_dataset_get_data (context, "gtk-info");
1132 if (info->proxy_data &&
1133 info->proxy_data->target == selection_data->target)
1135 gtk_selection_data_set (info->proxy_data,
1136 selection_data->type,
1137 selection_data->format,
1138 selection_data->data,
1139 selection_data->length);
1144 if (selection_data->target == gdk_atom_intern ("DELETE", FALSE))
1146 gtk_drag_finish (context, TRUE, FALSE, time);
1148 else if ((selection_data->target == gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE)) ||
1149 (selection_data->target == gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE)))
1155 GtkDragDestSite *site;
1157 site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest");
1159 if (site && site->target_list)
1163 if (gtk_target_list_find (site->target_list,
1164 selection_data->target,
1167 if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
1168 selection_data->length >= 0)
1169 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1170 "drag_data_received",
1171 context, info->drop_x, info->drop_y,
1178 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1179 "drag_data_received",
1180 context, info->drop_x, info->drop_y,
1181 selection_data, 0, time);
1184 if (site && site->flags & GTK_DEST_DEFAULT_DROP)
1187 gtk_drag_finish (context,
1188 (selection_data->length >= 0),
1189 (context->action == GDK_ACTION_MOVE),
1193 gtk_widget_unref (drop_widget);
1196 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
1197 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
1200 gtk_object_set_data (GTK_OBJECT (widget), "drag-context", NULL);
1201 gdk_drag_context_unref (context);
1203 gtk_drag_release_ipc_widget (widget);
1206 /*************************************************************
1207 * gtk_drag_find_widget:
1208 * Recursive callback used to locate widgets for
1209 * DRAG_MOTION and DROP_START events.
1213 *************************************************************/
1216 gtk_drag_find_widget (GtkWidget *widget,
1217 GtkDragFindData *data)
1219 GtkAllocation new_allocation;
1223 new_allocation = widget->allocation;
1225 if (data->found || !GTK_WIDGET_MAPPED (widget))
1228 /* Note that in the following code, we only count the
1229 * position as being inside a WINDOW widget if it is inside
1230 * widget->window; points that are outside of widget->window
1231 * but within the allocation are not counted. This is consistent
1232 * with the way we highlight drag targets.
1234 if (!GTK_WIDGET_NO_WINDOW (widget))
1236 new_allocation.x = 0;
1237 new_allocation.y = 0;
1242 GdkWindow *window = widget->window;
1243 while (window != widget->parent->window)
1245 gint tx, ty, twidth, theight;
1246 gdk_window_get_size (window, &twidth, &theight);
1248 if (new_allocation.x < 0)
1250 new_allocation.width += new_allocation.x;
1251 new_allocation.x = 0;
1253 if (new_allocation.y < 0)
1255 new_allocation.height += new_allocation.y;
1256 new_allocation.y = 0;
1258 if (new_allocation.x + new_allocation.width > twidth)
1259 new_allocation.width = twidth - new_allocation.x;
1260 if (new_allocation.y + new_allocation.height > theight)
1261 new_allocation.height = theight - new_allocation.y;
1263 gdk_window_get_position (window, &tx, &ty);
1264 new_allocation.x += tx;
1266 new_allocation.y += ty;
1269 window = gdk_window_get_parent (window);
1273 if (data->toplevel ||
1274 ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
1275 (data->x < new_allocation.x + new_allocation.width) &&
1276 (data->y < new_allocation.y + new_allocation.height)))
1278 /* First, check if the drag is in a valid drop site in
1279 * one of our children
1281 if (GTK_IS_CONTAINER (widget))
1283 GtkDragFindData new_data = *data;
1285 new_data.x -= x_offset;
1286 new_data.y -= y_offset;
1287 new_data.found = FALSE;
1288 new_data.toplevel = FALSE;
1290 gtk_container_forall (GTK_CONTAINER (widget),
1291 (GtkCallback)gtk_drag_find_widget,
1294 data->found = new_data.found;
1297 /* If not, and this widget is registered as a drop site, check to
1298 * emit "drag_motion" to check if we are actually in
1302 gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"))
1304 data->found = data->callback (widget,
1306 data->x - new_allocation.x,
1307 data->y - new_allocation.y,
1309 /* If so, send a "drag_leave" to the last widget */
1312 if (data->info->widget && data->info->widget != widget)
1314 gtk_drag_dest_leave (data->info->widget, data->context, data->time);
1316 data->info->widget = widget;
1323 gtk_drag_proxy_begin (GtkWidget *widget,
1324 GtkDragDestInfo *dest_info)
1326 GtkDragSourceInfo *source_info;
1329 source_info = g_new0 (GtkDragSourceInfo, 1);
1330 source_info->ipc_widget = gtk_drag_get_ipc_widget ();
1332 source_info->widget = widget;
1333 gtk_widget_ref (source_info->widget);
1334 source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
1335 dest_info->context->targets);
1337 source_info->target_list = gtk_target_list_new (NULL, 0);
1338 tmp_list = dest_info->context->targets;
1341 gtk_target_list_add (source_info->target_list,
1342 GPOINTER_TO_UINT (tmp_list->data), 0, 0);
1343 tmp_list = tmp_list->next;
1346 source_info->proxy_dest = dest_info;
1348 g_dataset_set_data (source_info->context, "gtk-info", source_info);
1350 gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget),
1352 GTK_SIGNAL_FUNC (gtk_drag_selection_get),
1355 dest_info->proxy_source = source_info;
1359 gtk_drag_dest_info_destroy (gpointer data)
1361 GtkDragDestInfo *info = data;
1367 gtk_drag_dest_realized (GtkWidget *widget)
1369 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1370 gdk_window_register_dnd (toplevel->window);
1374 gtk_drag_dest_site_destroy (gpointer data)
1376 GtkDragDestSite *site = data;
1378 if (site->target_list)
1379 gtk_target_list_unref (site->target_list);
1385 * Default drag handlers
1388 gtk_drag_dest_leave (GtkWidget *widget,
1389 GdkDragContext *context,
1392 GtkDragDestSite *site;
1394 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1395 g_return_if_fail (site != NULL);
1399 GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1401 if (info->proxy_source && !info->dropped)
1402 gdk_drag_abort (info->proxy_source->context, time);
1408 if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag)
1409 gtk_drag_unhighlight (widget);
1411 if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag)
1412 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_leave",
1415 site->have_drag = FALSE;
1420 gtk_drag_dest_motion (GtkWidget *widget,
1421 GdkDragContext *context,
1426 GtkDragDestSite *site;
1427 GdkDragAction action = 0;
1430 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1431 g_return_val_if_fail (site != NULL, FALSE);
1436 GdkEvent *current_event;
1437 GdkWindow *dest_window;
1438 GdkDragProtocol proto;
1440 GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1442 if (!info->proxy_source)
1443 gtk_drag_proxy_begin (widget, info);
1445 current_event = gtk_get_current_event ();
1447 if (site->proxy_window)
1449 dest_window = site->proxy_window;
1450 proto = site->proxy_protocol;
1454 gdk_drag_find_window (info->proxy_source->context,
1456 current_event->dnd.x_root,
1457 current_event->dnd.y_root,
1458 &dest_window, &proto);
1461 gdk_drag_motion (info->proxy_source->context,
1463 current_event->dnd.x_root,
1464 current_event->dnd.y_root,
1465 context->suggested_action,
1466 context->actions, time);
1468 if (!site->proxy_window && dest_window)
1469 gdk_window_unref (dest_window);
1471 selection = gdk_drag_get_selection (info->proxy_source->context);
1473 selection != gdk_drag_get_selection (info->context))
1474 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1476 gdk_event_free (current_event);
1481 if (site->flags & GTK_DEST_DEFAULT_MOTION)
1483 if (context->suggested_action & site->actions)
1484 action = context->suggested_action;
1491 if ((site->actions & (1 << i)) &&
1492 (context->actions & (1 << i)))
1500 if (action && gtk_drag_dest_find_target (widget, site, context))
1502 if (!site->have_drag)
1504 site->have_drag = TRUE;
1505 if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1506 gtk_drag_highlight (widget);
1509 gdk_drag_status (context, action, time);
1513 gdk_drag_status (context, 0, time);
1518 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_motion",
1519 context, x, y, time, &retval);
1521 return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1525 gtk_drag_dest_drop (GtkWidget *widget,
1526 GdkDragContext *context,
1531 GtkDragDestSite *site;
1532 GtkDragDestInfo *info;
1534 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1535 g_return_val_if_fail (site != NULL, FALSE);
1537 info = g_dataset_get_data (context, "gtk-info");
1538 g_return_val_if_fail (info != NULL, FALSE);
1545 if (info->proxy_source ||
1546 (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN))
1548 gtk_drag_drop (info->proxy_source, time);
1552 /* We need to synthesize a motion event, wait for a status,
1553 * and, if we get a good one, do a drop.
1556 GdkEvent *current_event;
1558 GdkWindow *dest_window;
1559 GdkDragProtocol proto;
1561 gtk_drag_proxy_begin (widget, info);
1562 info->proxy_drop_wait = TRUE;
1563 info->proxy_drop_time = time;
1565 current_event = gtk_get_current_event ();
1567 if (site->proxy_window)
1569 dest_window = site->proxy_window;
1570 proto = site->proxy_protocol;
1574 gdk_drag_find_window (info->proxy_source->context,
1576 current_event->dnd.x_root,
1577 current_event->dnd.y_root,
1578 &dest_window, &proto);
1581 gdk_drag_motion (info->proxy_source->context,
1583 current_event->dnd.x_root,
1584 current_event->dnd.y_root,
1585 context->suggested_action,
1586 context->actions, time);
1588 if (!site->proxy_window && dest_window)
1589 gdk_window_unref (dest_window);
1591 selection = gdk_drag_get_selection (info->proxy_source->context);
1593 selection != gdk_drag_get_selection (info->context))
1594 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1596 gdk_event_free (current_event);
1606 if (site->flags & GTK_DEST_DEFAULT_DROP)
1608 GdkAtom target = gtk_drag_dest_find_target (widget, site, context);
1610 if (target == GDK_NONE)
1613 gtk_drag_get_data (widget, context, target, time);
1616 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_drop",
1617 context, x, y, time, &retval);
1619 return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
1627 /*************************************************************
1628 * gtk_drag_begin: Start a drag operation
1631 * widget: Widget from which drag starts
1632 * handlers: List of handlers to supply the data for the drag
1633 * button: Button user used to start drag
1634 * time: Time of event starting drag
1637 *************************************************************/
1640 gtk_drag_begin (GtkWidget *widget,
1641 GtkTargetList *target_list,
1642 GdkDragAction actions,
1646 GtkDragSourceInfo *info;
1647 GList *targets = NULL;
1649 guint32 time = GDK_CURRENT_TIME;
1650 GdkDragAction possible_actions, suggested_action;
1652 g_return_val_if_fail (widget != NULL, NULL);
1653 g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
1654 g_return_val_if_fail (target_list != NULL, NULL);
1657 time = gdk_event_get_time (event);
1659 info = g_new0 (GtkDragSourceInfo, 1);
1660 info->ipc_widget = gtk_drag_get_ipc_widget ();
1661 source_widgets = g_slist_prepend (source_widgets, info->ipc_widget);
1663 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
1665 tmp_list = g_list_last (target_list->list);
1668 GtkTargetPair *pair = tmp_list->data;
1669 targets = g_list_prepend (targets,
1670 GINT_TO_POINTER (pair->target));
1671 tmp_list = tmp_list->prev;
1674 info->widget = widget;
1675 gtk_widget_ref (info->widget);
1677 info->context = gdk_drag_begin (info->ipc_widget->window, targets);
1678 g_list_free (targets);
1680 g_dataset_set_data (info->context, "gtk-info", info);
1682 info->button = button;
1683 info->target_list = target_list;
1684 gtk_target_list_ref (target_list);
1686 info->possible_actions = actions;
1688 info->cursor = NULL;
1689 info->status = GTK_DRAG_STATUS_DRAG;
1690 info->last_event = NULL;
1691 info->selections = NULL;
1692 info->icon_window = NULL;
1693 info->destroy_icon = FALSE;
1695 gtk_drag_get_event_actions (event, info->button, actions,
1696 &suggested_action, &possible_actions);
1698 info->cursor = gtk_drag_get_cursor (suggested_action);
1700 /* Set cur_x, cur_y here so if the "drag_begin" signal shows
1701 * the drag icon, it will be in the right place
1703 if (event && event->type == GDK_MOTION_NOTIFY)
1705 info->cur_x = event->motion.x_root;
1706 info->cur_y = event->motion.y_root;
1711 gdk_window_get_pointer (GDK_ROOT_PARENT (), &x, &y, NULL);
1717 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
1720 if (event && event->type == GDK_MOTION_NOTIFY)
1721 gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
1723 info->start_x = info->cur_x;
1724 info->start_y = info->cur_y;
1726 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "button_release_event",
1727 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info);
1728 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "motion_notify_event",
1729 GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info);
1730 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_press_event",
1731 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1732 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_release_event",
1733 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1734 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "selection_get",
1735 GTK_SIGNAL_FUNC (gtk_drag_selection_get), info);
1737 /* We use a GTK grab here to override any grabs that the widget
1738 * we are dragging from might have held
1740 gtk_grab_add (info->ipc_widget);
1741 if (gdk_pointer_grab (info->ipc_widget->window, FALSE,
1742 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1743 GDK_BUTTON_RELEASE_MASK, NULL,
1744 info->cursor, time) == 0)
1746 if (gdk_keyboard_grab (info->ipc_widget->window, FALSE, time) != 0)
1748 /* FIXME: This should be cleaned up... */
1752 ev.type = GDK_BUTTON_RELEASE;
1753 ev.button = info->button;
1755 gtk_drag_button_release_cb (widget, &ev, info);
1761 return info->context;
1764 /*************************************************************
1765 * gtk_drag_source_set:
1766 * Register a drop site, and possibly add default behaviors.
1769 * start_button_mask: Mask of allowed buttons to start drag
1770 * targets: Table of targets for this source
1772 * actions: Actions allowed for this source
1774 *************************************************************/
1777 gtk_drag_source_set (GtkWidget *widget,
1778 GdkModifierType start_button_mask,
1779 const GtkTargetEntry *targets,
1781 GdkDragAction actions)
1783 GtkDragSourceSite *site;
1785 g_return_if_fail (widget != NULL);
1787 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1789 gtk_widget_add_events (widget,
1790 gtk_widget_get_events (widget) |
1791 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1792 GDK_BUTTON_MOTION_MASK);
1796 if (site->target_list)
1797 gtk_target_list_unref (site->target_list);
1801 site = g_new0 (GtkDragSourceSite, 1);
1803 gtk_signal_connect (GTK_OBJECT (widget), "button_press_event",
1804 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1806 gtk_signal_connect (GTK_OBJECT (widget), "motion_notify_event",
1807 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1810 gtk_object_set_data_full (GTK_OBJECT (widget),
1812 site, gtk_drag_source_site_destroy);
1815 site->start_button_mask = start_button_mask;
1818 site->target_list = gtk_target_list_new (targets, n_targets);
1820 site->target_list = NULL;
1822 site->actions = actions;
1826 /*************************************************************
1827 * gtk_drag_source_unset
1828 * Unregister this widget as a drag source.
1832 *************************************************************/
1835 gtk_drag_source_unset (GtkWidget *widget)
1837 GtkDragSourceSite *site;
1839 g_return_if_fail (widget != NULL);
1841 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1845 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
1846 gtk_object_set_data (GTK_OBJECT (widget), "gtk-site-data", NULL);
1850 /*************************************************************
1851 * gtk_drag_source_set_icon:
1852 * Set an icon for drags from this source.
1854 * colormap: Colormap for this icon
1858 *************************************************************/
1861 gtk_drag_source_set_icon (GtkWidget *widget,
1862 GdkColormap *colormap,
1866 GtkDragSourceSite *site;
1868 g_return_if_fail (widget != NULL);
1870 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1871 g_return_if_fail (site != NULL);
1874 gdk_colormap_unref (site->colormap);
1876 gdk_pixmap_unref (site->pixmap);
1878 gdk_pixmap_unref (site->mask);
1880 site->colormap = colormap;
1882 gdk_colormap_ref (colormap);
1884 site->pixmap = pixmap;
1886 gdk_pixmap_ref (pixmap);
1890 gdk_pixmap_ref (mask);
1893 /*************************************************************
1894 * gtk_drag_set_icon_window:
1895 * Set a widget as the icon for a drag.
1902 *************************************************************/
1905 gtk_drag_set_icon_window (GdkDragContext *context,
1909 gboolean destroy_on_release)
1911 GtkDragSourceInfo *info;
1913 g_return_if_fail (context != NULL);
1914 g_return_if_fail (widget != NULL);
1916 info = g_dataset_get_data (context, "gtk-info");
1917 gtk_drag_remove_icon (info);
1919 info->icon_window = widget;
1920 info->hot_x = hot_x;
1921 info->hot_y = hot_y;
1925 gtk_widget_set_uposition (widget,
1926 info->cur_x - info->hot_x,
1927 info->cur_y - info->hot_y);
1928 gtk_widget_ref (widget);
1929 gdk_window_raise (widget->window);
1930 gtk_widget_show (widget);
1933 info->destroy_icon = destroy_on_release;
1936 /*************************************************************
1937 * gtk_drag_set_icon_widget:
1938 * Set a widget as the icon for a drag.
1945 *************************************************************/
1948 gtk_drag_set_icon_widget (GdkDragContext *context,
1953 g_return_if_fail (context != NULL);
1954 g_return_if_fail (widget != NULL);
1956 gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE);
1959 /*************************************************************
1960 * gtk_drag_set_icon_pixmap:
1961 * Set a widget as the icon for a drag.
1964 * colormap: Colormap for the icon window.
1970 *************************************************************/
1973 gtk_drag_set_icon_pixmap (GdkDragContext *context,
1974 GdkColormap *colormap,
1983 g_return_if_fail (context != NULL);
1984 g_return_if_fail (colormap != NULL);
1985 g_return_if_fail (pixmap != NULL);
1987 gdk_window_get_size (pixmap, &width, &height);
1989 gtk_widget_push_visual (gdk_colormap_get_visual (colormap));
1990 gtk_widget_push_colormap (colormap);
1992 window = gtk_window_new (GTK_WINDOW_POPUP);
1993 gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
1994 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
1996 gtk_widget_pop_visual ();
1997 gtk_widget_pop_colormap ();
1999 gtk_widget_set_usize (window, width, height);
2000 gtk_widget_realize (window);
2002 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
2005 gtk_widget_shape_combine_mask (window, mask, 0, 0);
2007 gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
2010 /*************************************************************
2011 * gtk_drag_set_icon_default:
2012 * Set the icon for a drag to the default icon.
2016 *************************************************************/
2019 gtk_drag_set_icon_default (GdkDragContext *context)
2021 g_return_if_fail (context != NULL);
2023 if (!default_icon_pixmap)
2025 default_icon_colormap = gdk_colormap_get_system ();
2026 default_icon_pixmap =
2027 gdk_pixmap_colormap_create_from_xpm_d (NULL,
2028 default_icon_colormap,
2030 NULL, (gchar **)drag_default_xpm);
2031 default_icon_hot_x = -2;
2032 default_icon_hot_y = -2;
2035 gtk_drag_set_icon_pixmap (context,
2036 default_icon_colormap,
2037 default_icon_pixmap,
2040 default_icon_hot_y);
2043 /*************************************************************
2044 * gtk_drag_set_default_icon:
2045 * Set a default icon for all drags as a pixmap.
2047 * colormap: Colormap for the icon window.
2053 *************************************************************/
2056 gtk_drag_set_default_icon (GdkColormap *colormap,
2062 g_return_if_fail (colormap != NULL);
2063 g_return_if_fail (pixmap != NULL);
2065 if (default_icon_colormap)
2066 gdk_colormap_unref (default_icon_colormap);
2067 if (default_icon_pixmap)
2068 gdk_pixmap_unref (default_icon_pixmap);
2069 if (default_icon_mask)
2070 gdk_pixmap_unref (default_icon_mask);
2072 default_icon_colormap = colormap;
2073 gdk_colormap_ref (colormap);
2075 default_icon_pixmap = pixmap;
2076 gdk_pixmap_ref (pixmap);
2078 default_icon_mask = mask;
2080 gdk_pixmap_ref (mask);
2082 default_icon_hot_x = hot_x;
2083 default_icon_hot_y = hot_y;
2087 /*************************************************************
2088 * gtk_drag_source_handle_event:
2089 * Called from widget event handling code on Drag events
2093 * toplevel: Toplevel widget that received the event
2096 *************************************************************/
2099 gtk_drag_source_handle_event (GtkWidget *widget,
2102 GtkDragSourceInfo *info;
2103 GdkDragContext *context;
2105 g_return_if_fail (widget != NULL);
2106 g_return_if_fail (event != NULL);
2108 context = event->dnd.context;
2109 info = g_dataset_get_data (context, "gtk-info");
2113 switch (event->type)
2115 case GDK_DRAG_STATUS:
2119 if (info->proxy_dest)
2121 if (!event->dnd.send_event)
2123 if (info->proxy_dest->proxy_drop_wait)
2125 gboolean result = context->action != 0;
2127 /* Aha - we can finally pass the MOTIF DROP on... */
2128 gdk_drop_reply (info->proxy_dest->context, result, info->proxy_dest->proxy_drop_time);
2130 gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
2132 gtk_drag_finish (info->proxy_dest->context, FALSE, FALSE, info->proxy_dest->proxy_drop_time);
2136 gdk_drag_status (info->proxy_dest->context,
2137 event->dnd.context->action,
2144 cursor = gtk_drag_get_cursor (event->dnd.context->action);
2145 if (info->cursor != cursor)
2147 #ifdef GDK_WINDOWING_X11
2148 XChangeActivePointerGrab (GDK_WINDOW_XDISPLAY (widget->window),
2149 PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask,
2150 ((GdkCursorPrivate *)cursor)->xcursor,
2152 #elif defined (GDK_WINDOWING_WIN32)
2153 gdk_pointer_grab (widget->window, FALSE,
2154 GDK_POINTER_MOTION_MASK |
2155 GDK_POINTER_MOTION_HINT_MASK |
2156 GDK_BUTTON_RELEASE_MASK,
2158 info->cursor, event->dnd.time);
2160 info->cursor = cursor;
2163 if (info->last_event)
2165 gtk_drag_update (info,
2166 info->cur_x, info->cur_y,
2168 info->last_event = NULL;
2174 case GDK_DROP_FINISHED:
2175 gtk_drag_drop_finished (info, TRUE, event->dnd.time);
2178 g_assert_not_reached ();
2182 /*************************************************************
2183 * gtk_drag_source_check_selection:
2184 * Check if we've set up handlers/claimed the selection
2185 * for a given drag. If not, add them.
2189 *************************************************************/
2192 gtk_drag_source_check_selection (GtkDragSourceInfo *info,
2198 tmp_list = info->selections;
2201 if (GPOINTER_TO_UINT (tmp_list->data) == selection)
2203 tmp_list = tmp_list->next;
2206 gtk_selection_owner_set (info->ipc_widget, selection, time);
2207 info->selections = g_list_prepend (info->selections,
2208 GUINT_TO_POINTER (selection));
2210 tmp_list = info->target_list->list;
2213 GtkTargetPair *pair = tmp_list->data;
2215 gtk_selection_add_target (info->ipc_widget,
2219 tmp_list = tmp_list->next;
2222 if (info->context->protocol == GDK_DRAG_PROTO_MOTIF)
2224 gtk_selection_add_target (info->ipc_widget,
2226 gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE),
2227 TARGET_MOTIF_SUCCESS);
2228 gtk_selection_add_target (info->ipc_widget,
2230 gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE),
2231 TARGET_MOTIF_FAILURE);
2234 gtk_selection_add_target (info->ipc_widget,
2236 gdk_atom_intern ("DELETE", FALSE),
2240 /*************************************************************
2241 * gtk_drag_drop_finished:
2242 * Clean up from the drag, and display snapback, if necessary.
2248 *************************************************************/
2251 gtk_drag_drop_finished (GtkDragSourceInfo *info,
2255 gtk_drag_source_release_selections (info, time);
2257 if (info->proxy_dest)
2259 /* The time from the event isn't reliable for Xdnd drags */
2260 gtk_drag_finish (info->proxy_dest->context, success, FALSE,
2261 info->proxy_dest->proxy_drop_time);
2262 gtk_drag_source_info_destroy (info);
2268 gtk_drag_source_info_destroy (info);
2272 GtkDragAnim *anim = g_new (GtkDragAnim, 1);
2276 anim->n_steps = MAX (info->cur_x - info->start_x,
2277 info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
2278 anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
2279 if (info->icon_window)
2281 gtk_widget_show (info->icon_window);
2282 gdk_window_raise (info->icon_window->window);
2285 /* Mark the context as dead, so if the destination decides
2286 * to respond really late, we still are OK.
2288 g_dataset_set_data (info->context, "gtk-info", NULL);
2289 gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
2295 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
2298 GList *tmp_list = info->selections;
2301 GdkAtom selection = GPOINTER_TO_UINT (tmp_list->data);
2302 if (gdk_selection_owner_get (selection) == info->ipc_widget->window)
2303 gtk_selection_owner_set (NULL, selection, time);
2304 tmp_list = tmp_list->next;
2307 g_list_free (info->selections);
2308 info->selections = NULL;
2311 /*************************************************************
2313 * Send a drop event.
2317 *************************************************************/
2320 gtk_drag_drop (GtkDragSourceInfo *info,
2323 if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN)
2325 GtkSelectionData selection_data;
2327 GdkAtom target = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
2329 tmp_list = info->target_list->list;
2332 GtkTargetPair *pair = tmp_list->data;
2334 if (pair->target == target)
2336 selection_data.selection = GDK_NONE;
2337 selection_data.target = target;
2338 selection_data.data = NULL;
2339 selection_data.length = -1;
2341 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2342 info->context, &selection_data,
2346 /* FIXME: Should we check for length >= 0 here? */
2347 gtk_drag_drop_finished (info, TRUE, time);
2350 tmp_list = tmp_list->next;
2352 gtk_drag_drop_finished (info, FALSE, time);
2356 if (info->icon_window)
2357 gtk_widget_hide (info->icon_window);
2359 gdk_drag_drop (info->context, time);
2360 info->drop_timeout = gtk_timeout_add (DROP_ABORT_TIME,
2361 gtk_drag_abort_timeout,
2367 * Source side callbacks.
2371 gtk_drag_source_event_cb (GtkWidget *widget,
2375 GtkDragSourceSite *site;
2376 site = (GtkDragSourceSite *)data;
2378 switch (event->type)
2380 case GDK_BUTTON_PRESS:
2381 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2383 site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1));
2384 site->x = event->button.x;
2385 site->y = event->button.y;
2389 case GDK_BUTTON_RELEASE:
2390 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2392 site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
2396 case GDK_MOTION_NOTIFY:
2397 if (site->state & event->motion.state & site->start_button_mask)
2399 /* FIXME: This is really broken and can leave us
2405 if (site->state & event->motion.state &
2406 GDK_BUTTON1_MASK << (i - 1))
2410 if (MAX (ABS (site->x - event->motion.x),
2411 ABS (site->y - event->motion.y)) > 3)
2413 GtkDragSourceInfo *info;
2414 GdkDragContext *context;
2417 context = gtk_drag_begin (widget, site->target_list,
2422 info = g_dataset_get_data (context, "gtk-info");
2424 if (!info->icon_window)
2427 gtk_drag_set_icon_pixmap (context,
2430 site->mask, -2, -2);
2432 gtk_drag_set_icon_default (context);
2440 default: /* hit for 2/3BUTTON_PRESS */
2447 gtk_drag_source_site_destroy (gpointer data)
2449 GtkDragSourceSite *site = data;
2451 if (site->target_list)
2452 gtk_target_list_unref (site->target_list);
2455 gdk_pixmap_unref (site->pixmap);
2458 gdk_pixmap_unref (site->mask);
2464 gtk_drag_selection_get (GtkWidget *widget,
2465 GtkSelectionData *selection_data,
2470 GtkDragSourceInfo *info = data;
2471 static GdkAtom null_atom = GDK_NONE;
2475 null_atom = gdk_atom_intern ("NULL", FALSE);
2480 gtk_signal_emit_by_name (GTK_OBJECT (info->widget),
2483 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2485 case TARGET_MOTIF_SUCCESS:
2486 gtk_drag_drop_finished (info, TRUE, time);
2487 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2489 case TARGET_MOTIF_FAILURE:
2490 gtk_drag_drop_finished (info, FALSE, time);
2491 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2494 if (info->proxy_dest)
2496 /* This is sort of dangerous and needs to be thought
2499 info->proxy_dest->proxy_data = selection_data;
2500 gtk_drag_get_data (info->widget,
2501 info->proxy_dest->context,
2502 selection_data->target,
2505 info->proxy_dest->proxy_data = NULL;
2509 if (gtk_target_list_find (info->target_list,
2510 selection_data->target,
2513 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2525 gtk_drag_anim_timeout (gpointer data)
2527 GtkDragAnim *anim = data;
2531 GDK_THREADS_ENTER ();
2533 if (anim->step == anim->n_steps)
2535 gtk_drag_source_info_destroy (anim->info);
2542 x = (anim->info->start_x * (anim->step + 1) +
2543 anim->info->cur_x * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2544 y = (anim->info->start_y * (anim->step + 1) +
2545 anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2546 if (anim->info->icon_window)
2547 gtk_widget_set_uposition (anim->info->icon_window,
2548 x - anim->info->hot_x,
2549 y - anim->info->hot_y);
2556 GDK_THREADS_LEAVE ();
2562 gtk_drag_remove_icon (GtkDragSourceInfo *info)
2564 if (info->icon_window)
2566 gtk_widget_hide (info->icon_window);
2567 if (info->destroy_icon)
2568 gtk_widget_destroy (info->icon_window);
2570 gtk_widget_unref (info->icon_window);
2571 info->icon_window = NULL;
2576 gtk_drag_source_info_destroy (gpointer data)
2578 GtkDragSourceInfo *info = data;
2580 gtk_drag_remove_icon (data);
2582 if (!info->proxy_dest)
2583 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end",
2587 gtk_widget_unref (info->widget);
2589 gtk_signal_disconnect_by_data (GTK_OBJECT (info->ipc_widget), info);
2590 gtk_selection_remove_all (info->ipc_widget);
2591 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", NULL);
2592 source_widgets = g_slist_remove (source_widgets, info->ipc_widget);
2593 gtk_drag_release_ipc_widget (info->ipc_widget);
2595 gtk_target_list_unref (info->target_list);
2597 g_dataset_set_data (info->context, "gtk-info", NULL);
2598 gdk_drag_context_unref (info->context);
2600 if (info->drop_timeout)
2601 gtk_timeout_remove (info->drop_timeout);
2606 /*************************************************************
2608 * Function to update the status of the drag when the
2609 * cursor moves or the modifier changes
2611 * info: DragSourceInfo for the drag
2612 * x_root, y_root: position of darg
2613 * event: The event that triggered this call
2615 *************************************************************/
2618 gtk_drag_update (GtkDragSourceInfo *info,
2623 GdkDragAction action;
2624 GdkDragAction possible_actions;
2625 GdkWindow *window = NULL;
2626 GdkWindow *dest_window;
2627 GdkDragProtocol protocol;
2629 guint32 time = gtk_drag_get_event_time (event);
2631 gtk_drag_get_event_actions (event,
2633 info->possible_actions,
2634 &action, &possible_actions);
2635 info->cur_x = x_root;
2636 info->cur_y = y_root;
2638 if (info->icon_window)
2640 gdk_window_raise (info->icon_window->window);
2641 gtk_widget_set_uposition (info->icon_window,
2642 info->cur_x - info->hot_x,
2643 info->cur_y - info->hot_y);
2644 window = info->icon_window->window;
2647 gdk_drag_find_window (info->context,
2648 window, x_root, y_root,
2649 &dest_window, &protocol);
2651 if (gdk_drag_motion (info->context, dest_window, protocol,
2652 x_root, y_root, action,
2656 if (info->last_event)
2657 gdk_event_free ((GdkEvent *)info->last_event);
2659 info->last_event = gdk_event_copy ((GdkEvent *)event);
2663 gdk_window_unref (dest_window);
2665 selection = gdk_drag_get_selection (info->context);
2667 gtk_drag_source_check_selection (info, selection, time);
2670 /*************************************************************
2672 * Called when the user finishes to drag, either by
2673 * releasing the mouse, or by pressing Esc.
2675 * widget: GtkInvisible widget for this drag
2678 *************************************************************/
2681 gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
2683 GdkEvent send_event;
2684 GtkWidget *source_widget = info->widget;
2686 gdk_pointer_ungrab (time);
2687 gdk_keyboard_ungrab (time);
2689 gtk_grab_remove (info->ipc_widget);
2691 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2692 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
2694 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2695 GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
2698 /* Send on a release pair to the the original
2699 * widget to convince it to release its grab. We need to
2700 * call gtk_propagate_event() here, instead of
2701 * gtk_widget_event() because widget like GtkList may
2702 * expect propagation.
2705 send_event.button.type = GDK_BUTTON_RELEASE;
2706 send_event.button.window = GDK_ROOT_PARENT ();
2707 send_event.button.send_event = TRUE;
2708 send_event.button.time = time;
2709 send_event.button.x = 0;
2710 send_event.button.y = 0;
2711 send_event.button.pressure = 0.;
2712 send_event.button.xtilt = 0.;
2713 send_event.button.ytilt = 0.;
2714 send_event.button.state = 0;
2715 send_event.button.button = info->button;
2716 send_event.button.source = GDK_SOURCE_PEN;
2717 send_event.button.deviceid = GDK_CORE_POINTER;
2718 send_event.button.x_root = 0;
2719 send_event.button.y_root = 0;
2721 gtk_propagate_event (source_widget, &send_event);
2724 /*************************************************************
2725 * gtk_drag_motion_cb:
2726 * "motion_notify_event" callback during drag.
2730 *************************************************************/
2733 gtk_drag_motion_cb (GtkWidget *widget,
2734 GdkEventMotion *event,
2737 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2738 gint x_root, y_root;
2742 gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL);
2743 event->x_root = x_root;
2744 event->y_root = y_root;
2747 gtk_drag_update (info, event->x_root, event->y_root, (GdkEvent *)event);
2752 /*************************************************************
2754 * "key_press/release_event" callback during drag.
2758 *************************************************************/
2761 gtk_drag_key_cb (GtkWidget *widget,
2765 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2766 GdkModifierType state;
2768 if (event->type == GDK_KEY_PRESS)
2770 if (event->keyval == GDK_Escape)
2772 gtk_drag_end (info, event->time);
2773 gdk_drag_abort (info->context, event->time);
2774 gtk_drag_drop_finished (info, FALSE, event->time);
2780 /* Now send a "motion" so that the modifier state is updated */
2782 /* The state is not yet updated in the event, so we need
2783 * to query it here. We could use XGetModifierMapping, but
2784 * that would be overkill.
2786 gdk_window_get_pointer (GDK_ROOT_PARENT(), NULL, NULL, &state);
2788 event->state = state;
2789 gtk_drag_update (info, info->cur_x, info->cur_y, (GdkEvent *)event);
2794 /*************************************************************
2795 * gtk_drag_button_release_cb:
2796 * "button_release_event" callback during drag.
2800 *************************************************************/
2803 gtk_drag_button_release_cb (GtkWidget *widget,
2804 GdkEventButton *event,
2807 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2809 if (event->button != info->button)
2812 gtk_drag_end (info, event->time);
2814 if ((info->context->action != 0) && (info->context->dest_window != NULL))
2816 gtk_drag_drop (info, event->time);
2820 gdk_drag_abort (info->context, event->time);
2821 gtk_drag_drop_finished (info, FALSE, event->time);
2828 gtk_drag_abort_timeout (gpointer data)
2830 GtkDragSourceInfo *info = data;
2831 guint32 time = GDK_CURRENT_TIME;
2833 GDK_THREADS_ENTER ();
2835 if (info->proxy_dest)
2836 time = info->proxy_dest->proxy_drop_time;
2838 info->drop_timeout = 0;
2839 gtk_drag_drop_finished (info, FALSE, time);
2841 GDK_THREADS_LEAVE ();