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_object_set_qdata_full (G_OBJECT (context),
997 g_quark_from_static_string ("gtk-info"),
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_object_get_qdata (G_OBJECT (context), g_quark_from_static_string ("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_object_set_qdata (G_OBJECT (source_info->context),
1349 g_quark_from_static_string ("gtk-info"),
1352 gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget),
1354 GTK_SIGNAL_FUNC (gtk_drag_selection_get),
1357 dest_info->proxy_source = source_info;
1361 gtk_drag_dest_info_destroy (gpointer data)
1363 GtkDragDestInfo *info = data;
1369 gtk_drag_dest_realized (GtkWidget *widget)
1371 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1372 gdk_window_register_dnd (toplevel->window);
1376 gtk_drag_dest_site_destroy (gpointer data)
1378 GtkDragDestSite *site = data;
1380 if (site->target_list)
1381 gtk_target_list_unref (site->target_list);
1387 * Default drag handlers
1390 gtk_drag_dest_leave (GtkWidget *widget,
1391 GdkDragContext *context,
1394 GtkDragDestSite *site;
1396 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1397 g_return_if_fail (site != NULL);
1401 GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context),
1402 g_quark_from_static_string ("gtk-info"));
1404 if (info->proxy_source && !info->dropped)
1405 gdk_drag_abort (info->proxy_source->context, time);
1411 if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag)
1412 gtk_drag_unhighlight (widget);
1414 if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag)
1415 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_leave",
1418 site->have_drag = FALSE;
1423 gtk_drag_dest_motion (GtkWidget *widget,
1424 GdkDragContext *context,
1429 GtkDragDestSite *site;
1430 GdkDragAction action = 0;
1433 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1434 g_return_val_if_fail (site != NULL, FALSE);
1439 GdkEvent *current_event;
1440 GdkWindow *dest_window;
1441 GdkDragProtocol proto;
1443 GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context),
1444 g_quark_from_static_string ("gtk-info"));
1446 if (!info->proxy_source)
1447 gtk_drag_proxy_begin (widget, info);
1449 current_event = gtk_get_current_event ();
1451 if (site->proxy_window)
1453 dest_window = site->proxy_window;
1454 proto = site->proxy_protocol;
1458 gdk_drag_find_window (info->proxy_source->context,
1460 current_event->dnd.x_root,
1461 current_event->dnd.y_root,
1462 &dest_window, &proto);
1465 gdk_drag_motion (info->proxy_source->context,
1467 current_event->dnd.x_root,
1468 current_event->dnd.y_root,
1469 context->suggested_action,
1470 context->actions, time);
1472 if (!site->proxy_window && dest_window)
1473 gdk_window_unref (dest_window);
1475 selection = gdk_drag_get_selection (info->proxy_source->context);
1477 selection != gdk_drag_get_selection (info->context))
1478 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1480 gdk_event_free (current_event);
1485 if (site->flags & GTK_DEST_DEFAULT_MOTION)
1487 if (context->suggested_action & site->actions)
1488 action = context->suggested_action;
1495 if ((site->actions & (1 << i)) &&
1496 (context->actions & (1 << i)))
1504 if (action && gtk_drag_dest_find_target (widget, site, context))
1506 if (!site->have_drag)
1508 site->have_drag = TRUE;
1509 if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1510 gtk_drag_highlight (widget);
1513 gdk_drag_status (context, action, time);
1517 gdk_drag_status (context, 0, time);
1522 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_motion",
1523 context, x, y, time, &retval);
1525 return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1529 gtk_drag_dest_drop (GtkWidget *widget,
1530 GdkDragContext *context,
1535 GtkDragDestSite *site;
1536 GtkDragDestInfo *info;
1538 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1539 g_return_val_if_fail (site != NULL, FALSE);
1541 info = g_object_get_qdata (G_OBJECT (context),
1542 g_quark_from_static_string ("gtk-info"));
1543 g_return_val_if_fail (info != NULL, FALSE);
1550 if (info->proxy_source ||
1551 (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN))
1553 gtk_drag_drop (info->proxy_source, time);
1557 /* We need to synthesize a motion event, wait for a status,
1558 * and, if we get a good one, do a drop.
1561 GdkEvent *current_event;
1563 GdkWindow *dest_window;
1564 GdkDragProtocol proto;
1566 gtk_drag_proxy_begin (widget, info);
1567 info->proxy_drop_wait = TRUE;
1568 info->proxy_drop_time = time;
1570 current_event = gtk_get_current_event ();
1572 if (site->proxy_window)
1574 dest_window = site->proxy_window;
1575 proto = site->proxy_protocol;
1579 gdk_drag_find_window (info->proxy_source->context,
1581 current_event->dnd.x_root,
1582 current_event->dnd.y_root,
1583 &dest_window, &proto);
1586 gdk_drag_motion (info->proxy_source->context,
1588 current_event->dnd.x_root,
1589 current_event->dnd.y_root,
1590 context->suggested_action,
1591 context->actions, time);
1593 if (!site->proxy_window && dest_window)
1594 gdk_window_unref (dest_window);
1596 selection = gdk_drag_get_selection (info->proxy_source->context);
1598 selection != gdk_drag_get_selection (info->context))
1599 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1601 gdk_event_free (current_event);
1611 if (site->flags & GTK_DEST_DEFAULT_DROP)
1613 GdkAtom target = gtk_drag_dest_find_target (widget, site, context);
1615 if (target == GDK_NONE)
1618 gtk_drag_get_data (widget, context, target, time);
1621 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_drop",
1622 context, x, y, time, &retval);
1624 return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
1632 /*************************************************************
1633 * gtk_drag_begin: Start a drag operation
1636 * widget: Widget from which drag starts
1637 * handlers: List of handlers to supply the data for the drag
1638 * button: Button user used to start drag
1639 * time: Time of event starting drag
1642 *************************************************************/
1645 gtk_drag_begin (GtkWidget *widget,
1646 GtkTargetList *target_list,
1647 GdkDragAction actions,
1651 GtkDragSourceInfo *info;
1652 GList *targets = NULL;
1654 guint32 time = GDK_CURRENT_TIME;
1655 GdkDragAction possible_actions, suggested_action;
1657 g_return_val_if_fail (widget != NULL, NULL);
1658 g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
1659 g_return_val_if_fail (target_list != NULL, NULL);
1662 time = gdk_event_get_time (event);
1664 info = g_new0 (GtkDragSourceInfo, 1);
1665 info->ipc_widget = gtk_drag_get_ipc_widget ();
1666 source_widgets = g_slist_prepend (source_widgets, info->ipc_widget);
1668 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
1670 tmp_list = g_list_last (target_list->list);
1673 GtkTargetPair *pair = tmp_list->data;
1674 targets = g_list_prepend (targets,
1675 GINT_TO_POINTER (pair->target));
1676 tmp_list = tmp_list->prev;
1679 info->widget = widget;
1680 gtk_widget_ref (info->widget);
1682 info->context = gdk_drag_begin (info->ipc_widget->window, targets);
1683 g_list_free (targets);
1685 g_object_set_qdata (G_OBJECT (info->context),
1686 g_quark_from_static_string ("gtk-info"), info);
1688 info->button = button;
1689 info->target_list = target_list;
1690 gtk_target_list_ref (target_list);
1692 info->possible_actions = actions;
1694 info->cursor = NULL;
1695 info->status = GTK_DRAG_STATUS_DRAG;
1696 info->last_event = NULL;
1697 info->selections = NULL;
1698 info->icon_window = NULL;
1699 info->destroy_icon = FALSE;
1701 gtk_drag_get_event_actions (event, info->button, actions,
1702 &suggested_action, &possible_actions);
1704 info->cursor = gtk_drag_get_cursor (suggested_action);
1706 /* Set cur_x, cur_y here so if the "drag_begin" signal shows
1707 * the drag icon, it will be in the right place
1709 if (event && event->type == GDK_MOTION_NOTIFY)
1711 info->cur_x = event->motion.x_root;
1712 info->cur_y = event->motion.y_root;
1717 gdk_window_get_pointer (GDK_ROOT_PARENT (), &x, &y, NULL);
1723 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
1726 if (event && event->type == GDK_MOTION_NOTIFY)
1727 gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
1729 info->start_x = info->cur_x;
1730 info->start_y = info->cur_y;
1732 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "button_release_event",
1733 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info);
1734 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "motion_notify_event",
1735 GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info);
1736 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_press_event",
1737 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1738 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_release_event",
1739 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1740 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "selection_get",
1741 GTK_SIGNAL_FUNC (gtk_drag_selection_get), info);
1743 /* We use a GTK grab here to override any grabs that the widget
1744 * we are dragging from might have held
1746 gtk_grab_add (info->ipc_widget);
1747 if (gdk_pointer_grab (info->ipc_widget->window, FALSE,
1748 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1749 GDK_BUTTON_RELEASE_MASK, NULL,
1750 info->cursor, time) == 0)
1752 if (gdk_keyboard_grab (info->ipc_widget->window, FALSE, time) != 0)
1754 /* FIXME: This should be cleaned up... */
1758 ev.type = GDK_BUTTON_RELEASE;
1759 ev.button = info->button;
1761 gtk_drag_button_release_cb (widget, &ev, info);
1767 return info->context;
1770 /*************************************************************
1771 * gtk_drag_source_set:
1772 * Register a drop site, and possibly add default behaviors.
1775 * start_button_mask: Mask of allowed buttons to start drag
1776 * targets: Table of targets for this source
1778 * actions: Actions allowed for this source
1780 *************************************************************/
1783 gtk_drag_source_set (GtkWidget *widget,
1784 GdkModifierType start_button_mask,
1785 const GtkTargetEntry *targets,
1787 GdkDragAction actions)
1789 GtkDragSourceSite *site;
1791 g_return_if_fail (widget != NULL);
1793 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1795 gtk_widget_add_events (widget,
1796 gtk_widget_get_events (widget) |
1797 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1798 GDK_BUTTON_MOTION_MASK);
1802 if (site->target_list)
1803 gtk_target_list_unref (site->target_list);
1807 site = g_new0 (GtkDragSourceSite, 1);
1809 gtk_signal_connect (GTK_OBJECT (widget), "button_press_event",
1810 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1812 gtk_signal_connect (GTK_OBJECT (widget), "motion_notify_event",
1813 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1816 gtk_object_set_data_full (GTK_OBJECT (widget),
1818 site, gtk_drag_source_site_destroy);
1821 site->start_button_mask = start_button_mask;
1824 site->target_list = gtk_target_list_new (targets, n_targets);
1826 site->target_list = NULL;
1828 site->actions = actions;
1832 /*************************************************************
1833 * gtk_drag_source_unset
1834 * Unregister this widget as a drag source.
1838 *************************************************************/
1841 gtk_drag_source_unset (GtkWidget *widget)
1843 GtkDragSourceSite *site;
1845 g_return_if_fail (widget != NULL);
1847 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1851 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
1852 gtk_object_set_data (GTK_OBJECT (widget), "gtk-site-data", NULL);
1856 /*************************************************************
1857 * gtk_drag_source_set_icon:
1858 * Set an icon for drags from this source.
1860 * colormap: Colormap for this icon
1864 *************************************************************/
1867 gtk_drag_source_set_icon (GtkWidget *widget,
1868 GdkColormap *colormap,
1872 GtkDragSourceSite *site;
1874 g_return_if_fail (widget != NULL);
1876 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1877 g_return_if_fail (site != NULL);
1880 gdk_colormap_unref (site->colormap);
1882 gdk_pixmap_unref (site->pixmap);
1884 gdk_pixmap_unref (site->mask);
1886 site->colormap = colormap;
1888 gdk_colormap_ref (colormap);
1890 site->pixmap = pixmap;
1892 gdk_pixmap_ref (pixmap);
1896 gdk_pixmap_ref (mask);
1899 /*************************************************************
1900 * gtk_drag_set_icon_window:
1901 * Set a widget as the icon for a drag.
1908 *************************************************************/
1911 gtk_drag_set_icon_window (GdkDragContext *context,
1915 gboolean destroy_on_release)
1917 GtkDragSourceInfo *info;
1919 g_return_if_fail (context != NULL);
1920 g_return_if_fail (widget != NULL);
1922 info = g_object_get_qdata (G_OBJECT (context),
1923 g_quark_from_static_string ("gtk-info"));
1924 gtk_drag_remove_icon (info);
1926 info->icon_window = widget;
1927 info->hot_x = hot_x;
1928 info->hot_y = hot_y;
1932 gtk_widget_set_uposition (widget,
1933 info->cur_x - info->hot_x,
1934 info->cur_y - info->hot_y);
1935 gtk_widget_ref (widget);
1936 gdk_window_raise (widget->window);
1937 gtk_widget_show (widget);
1940 info->destroy_icon = destroy_on_release;
1943 /*************************************************************
1944 * gtk_drag_set_icon_widget:
1945 * Set a widget as the icon for a drag.
1952 *************************************************************/
1955 gtk_drag_set_icon_widget (GdkDragContext *context,
1960 g_return_if_fail (context != NULL);
1961 g_return_if_fail (widget != NULL);
1963 gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE);
1966 /*************************************************************
1967 * gtk_drag_set_icon_pixmap:
1968 * Set a widget as the icon for a drag.
1971 * colormap: Colormap for the icon window.
1977 *************************************************************/
1980 gtk_drag_set_icon_pixmap (GdkDragContext *context,
1981 GdkColormap *colormap,
1990 g_return_if_fail (context != NULL);
1991 g_return_if_fail (colormap != NULL);
1992 g_return_if_fail (pixmap != NULL);
1994 gdk_window_get_size (pixmap, &width, &height);
1996 gtk_widget_push_colormap (colormap);
1998 window = gtk_window_new (GTK_WINDOW_POPUP);
1999 gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
2000 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
2002 gtk_widget_pop_colormap ();
2004 gtk_widget_set_usize (window, width, height);
2005 gtk_widget_realize (window);
2007 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
2010 gtk_widget_shape_combine_mask (window, mask, 0, 0);
2012 gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
2015 /*************************************************************
2016 * gtk_drag_set_icon_default:
2017 * Set the icon for a drag to the default icon.
2021 *************************************************************/
2024 gtk_drag_set_icon_default (GdkDragContext *context)
2026 g_return_if_fail (context != NULL);
2028 if (!default_icon_pixmap)
2030 default_icon_colormap = gdk_colormap_get_system ();
2031 default_icon_pixmap =
2032 gdk_pixmap_colormap_create_from_xpm_d (NULL,
2033 default_icon_colormap,
2035 NULL, (gchar **)drag_default_xpm);
2036 default_icon_hot_x = -2;
2037 default_icon_hot_y = -2;
2040 gtk_drag_set_icon_pixmap (context,
2041 default_icon_colormap,
2042 default_icon_pixmap,
2045 default_icon_hot_y);
2048 /*************************************************************
2049 * gtk_drag_set_default_icon:
2050 * Set a default icon for all drags as a pixmap.
2052 * colormap: Colormap for the icon window.
2058 *************************************************************/
2061 gtk_drag_set_default_icon (GdkColormap *colormap,
2067 g_return_if_fail (colormap != NULL);
2068 g_return_if_fail (pixmap != NULL);
2070 if (default_icon_colormap)
2071 gdk_colormap_unref (default_icon_colormap);
2072 if (default_icon_pixmap)
2073 gdk_pixmap_unref (default_icon_pixmap);
2074 if (default_icon_mask)
2075 gdk_pixmap_unref (default_icon_mask);
2077 default_icon_colormap = colormap;
2078 gdk_colormap_ref (colormap);
2080 default_icon_pixmap = pixmap;
2081 gdk_pixmap_ref (pixmap);
2083 default_icon_mask = mask;
2085 gdk_pixmap_ref (mask);
2087 default_icon_hot_x = hot_x;
2088 default_icon_hot_y = hot_y;
2092 /*************************************************************
2093 * gtk_drag_source_handle_event:
2094 * Called from widget event handling code on Drag events
2098 * toplevel: Toplevel widget that received the event
2101 *************************************************************/
2104 gtk_drag_source_handle_event (GtkWidget *widget,
2107 GtkDragSourceInfo *info;
2108 GdkDragContext *context;
2110 g_return_if_fail (widget != NULL);
2111 g_return_if_fail (event != NULL);
2113 context = event->dnd.context;
2114 info = g_object_get_qdata (G_OBJECT (context),
2115 g_quark_from_static_string ("gtk-info"));
2119 switch (event->type)
2121 case GDK_DRAG_STATUS:
2125 if (info->proxy_dest)
2127 if (!event->dnd.send_event)
2129 if (info->proxy_dest->proxy_drop_wait)
2131 gboolean result = context->action != 0;
2133 /* Aha - we can finally pass the MOTIF DROP on... */
2134 gdk_drop_reply (info->proxy_dest->context, result, info->proxy_dest->proxy_drop_time);
2136 gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
2138 gtk_drag_finish (info->proxy_dest->context, FALSE, FALSE, info->proxy_dest->proxy_drop_time);
2142 gdk_drag_status (info->proxy_dest->context,
2143 event->dnd.context->action,
2150 cursor = gtk_drag_get_cursor (event->dnd.context->action);
2151 if (info->cursor != cursor)
2153 #ifdef GDK_WINDOWING_X11
2154 XChangeActivePointerGrab (GDK_WINDOW_XDISPLAY (widget->window),
2155 PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask,
2156 ((GdkCursorPrivate *)cursor)->xcursor,
2158 #elif defined (GDK_WINDOWING_WIN32)
2159 gdk_pointer_grab (widget->window, FALSE,
2160 GDK_POINTER_MOTION_MASK |
2161 GDK_POINTER_MOTION_HINT_MASK |
2162 GDK_BUTTON_RELEASE_MASK,
2164 info->cursor, event->dnd.time);
2166 info->cursor = cursor;
2169 if (info->last_event)
2171 gtk_drag_update (info,
2172 info->cur_x, info->cur_y,
2174 info->last_event = NULL;
2180 case GDK_DROP_FINISHED:
2181 gtk_drag_drop_finished (info, TRUE, event->dnd.time);
2184 g_assert_not_reached ();
2188 /*************************************************************
2189 * gtk_drag_source_check_selection:
2190 * Check if we've set up handlers/claimed the selection
2191 * for a given drag. If not, add them.
2195 *************************************************************/
2198 gtk_drag_source_check_selection (GtkDragSourceInfo *info,
2204 tmp_list = info->selections;
2207 if (GPOINTER_TO_UINT (tmp_list->data) == selection)
2209 tmp_list = tmp_list->next;
2212 gtk_selection_owner_set (info->ipc_widget, selection, time);
2213 info->selections = g_list_prepend (info->selections,
2214 GUINT_TO_POINTER (selection));
2216 tmp_list = info->target_list->list;
2219 GtkTargetPair *pair = tmp_list->data;
2221 gtk_selection_add_target (info->ipc_widget,
2225 tmp_list = tmp_list->next;
2228 if (info->context->protocol == GDK_DRAG_PROTO_MOTIF)
2230 gtk_selection_add_target (info->ipc_widget,
2232 gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE),
2233 TARGET_MOTIF_SUCCESS);
2234 gtk_selection_add_target (info->ipc_widget,
2236 gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE),
2237 TARGET_MOTIF_FAILURE);
2240 gtk_selection_add_target (info->ipc_widget,
2242 gdk_atom_intern ("DELETE", FALSE),
2246 /*************************************************************
2247 * gtk_drag_drop_finished:
2248 * Clean up from the drag, and display snapback, if necessary.
2254 *************************************************************/
2257 gtk_drag_drop_finished (GtkDragSourceInfo *info,
2261 gtk_drag_source_release_selections (info, time);
2263 if (info->proxy_dest)
2265 /* The time from the event isn't reliable for Xdnd drags */
2266 gtk_drag_finish (info->proxy_dest->context, success, FALSE,
2267 info->proxy_dest->proxy_drop_time);
2268 gtk_drag_source_info_destroy (info);
2274 gtk_drag_source_info_destroy (info);
2278 GtkDragAnim *anim = g_new (GtkDragAnim, 1);
2282 anim->n_steps = MAX (info->cur_x - info->start_x,
2283 info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
2284 anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
2285 if (info->icon_window)
2287 gtk_widget_show (info->icon_window);
2288 gdk_window_raise (info->icon_window->window);
2291 /* Mark the context as dead, so if the destination decides
2292 * to respond really late, we still are OK.
2294 g_object_set_qdata (G_OBJECT (info->context),
2295 g_quark_from_static_string ("gtk-info"), NULL);
2296 gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
2302 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
2305 GList *tmp_list = info->selections;
2308 GdkAtom selection = GPOINTER_TO_UINT (tmp_list->data);
2309 if (gdk_selection_owner_get (selection) == info->ipc_widget->window)
2310 gtk_selection_owner_set (NULL, selection, time);
2311 tmp_list = tmp_list->next;
2314 g_list_free (info->selections);
2315 info->selections = NULL;
2318 /*************************************************************
2320 * Send a drop event.
2324 *************************************************************/
2327 gtk_drag_drop (GtkDragSourceInfo *info,
2330 if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN)
2332 GtkSelectionData selection_data;
2334 GdkAtom target = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
2336 tmp_list = info->target_list->list;
2339 GtkTargetPair *pair = tmp_list->data;
2341 if (pair->target == target)
2343 selection_data.selection = GDK_NONE;
2344 selection_data.target = target;
2345 selection_data.data = NULL;
2346 selection_data.length = -1;
2348 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2349 info->context, &selection_data,
2353 /* FIXME: Should we check for length >= 0 here? */
2354 gtk_drag_drop_finished (info, TRUE, time);
2357 tmp_list = tmp_list->next;
2359 gtk_drag_drop_finished (info, FALSE, time);
2363 if (info->icon_window)
2364 gtk_widget_hide (info->icon_window);
2366 gdk_drag_drop (info->context, time);
2367 info->drop_timeout = gtk_timeout_add (DROP_ABORT_TIME,
2368 gtk_drag_abort_timeout,
2374 * Source side callbacks.
2378 gtk_drag_source_event_cb (GtkWidget *widget,
2382 GtkDragSourceSite *site;
2383 site = (GtkDragSourceSite *)data;
2385 switch (event->type)
2387 case GDK_BUTTON_PRESS:
2388 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2390 site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1));
2391 site->x = event->button.x;
2392 site->y = event->button.y;
2396 case GDK_BUTTON_RELEASE:
2397 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2399 site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
2403 case GDK_MOTION_NOTIFY:
2404 if (site->state & event->motion.state & site->start_button_mask)
2406 /* FIXME: This is really broken and can leave us
2412 if (site->state & event->motion.state &
2413 GDK_BUTTON1_MASK << (i - 1))
2417 if (MAX (ABS (site->x - event->motion.x),
2418 ABS (site->y - event->motion.y)) > 3)
2420 GtkDragSourceInfo *info;
2421 GdkDragContext *context;
2424 context = gtk_drag_begin (widget, site->target_list,
2429 info = g_object_get_qdata (G_OBJECT (context),
2430 g_quark_from_static_string ("gtk-info"));
2432 if (!info->icon_window)
2435 gtk_drag_set_icon_pixmap (context,
2438 site->mask, -2, -2);
2440 gtk_drag_set_icon_default (context);
2448 default: /* hit for 2/3BUTTON_PRESS */
2455 gtk_drag_source_site_destroy (gpointer data)
2457 GtkDragSourceSite *site = data;
2459 if (site->target_list)
2460 gtk_target_list_unref (site->target_list);
2463 gdk_pixmap_unref (site->pixmap);
2466 gdk_pixmap_unref (site->mask);
2472 gtk_drag_selection_get (GtkWidget *widget,
2473 GtkSelectionData *selection_data,
2478 GtkDragSourceInfo *info = data;
2479 static GdkAtom null_atom = GDK_NONE;
2483 null_atom = gdk_atom_intern ("NULL", FALSE);
2488 gtk_signal_emit_by_name (GTK_OBJECT (info->widget),
2491 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2493 case TARGET_MOTIF_SUCCESS:
2494 gtk_drag_drop_finished (info, TRUE, time);
2495 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2497 case TARGET_MOTIF_FAILURE:
2498 gtk_drag_drop_finished (info, FALSE, time);
2499 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2502 if (info->proxy_dest)
2504 /* This is sort of dangerous and needs to be thought
2507 info->proxy_dest->proxy_data = selection_data;
2508 gtk_drag_get_data (info->widget,
2509 info->proxy_dest->context,
2510 selection_data->target,
2513 info->proxy_dest->proxy_data = NULL;
2517 if (gtk_target_list_find (info->target_list,
2518 selection_data->target,
2521 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2533 gtk_drag_anim_timeout (gpointer data)
2535 GtkDragAnim *anim = data;
2539 GDK_THREADS_ENTER ();
2541 if (anim->step == anim->n_steps)
2543 gtk_drag_source_info_destroy (anim->info);
2550 x = (anim->info->start_x * (anim->step + 1) +
2551 anim->info->cur_x * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2552 y = (anim->info->start_y * (anim->step + 1) +
2553 anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2554 if (anim->info->icon_window)
2555 gtk_widget_set_uposition (anim->info->icon_window,
2556 x - anim->info->hot_x,
2557 y - anim->info->hot_y);
2564 GDK_THREADS_LEAVE ();
2570 gtk_drag_remove_icon (GtkDragSourceInfo *info)
2572 if (info->icon_window)
2574 gtk_widget_hide (info->icon_window);
2575 if (info->destroy_icon)
2576 gtk_widget_destroy (info->icon_window);
2578 gtk_widget_unref (info->icon_window);
2579 info->icon_window = NULL;
2584 gtk_drag_source_info_destroy (gpointer data)
2586 GtkDragSourceInfo *info = data;
2588 gtk_drag_remove_icon (data);
2590 if (!info->proxy_dest)
2591 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end",
2595 gtk_widget_unref (info->widget);
2597 gtk_signal_disconnect_by_data (GTK_OBJECT (info->ipc_widget), info);
2598 gtk_selection_remove_all (info->ipc_widget);
2599 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", NULL);
2600 source_widgets = g_slist_remove (source_widgets, info->ipc_widget);
2601 gtk_drag_release_ipc_widget (info->ipc_widget);
2603 gtk_target_list_unref (info->target_list);
2605 g_object_set_qdata (G_OBJECT (info->context), g_quark_from_static_string ("gtk-info"), NULL);
2606 gdk_drag_context_unref (info->context);
2608 if (info->drop_timeout)
2609 gtk_timeout_remove (info->drop_timeout);
2614 /*************************************************************
2616 * Function to update the status of the drag when the
2617 * cursor moves or the modifier changes
2619 * info: DragSourceInfo for the drag
2620 * x_root, y_root: position of darg
2621 * event: The event that triggered this call
2623 *************************************************************/
2626 gtk_drag_update (GtkDragSourceInfo *info,
2631 GdkDragAction action;
2632 GdkDragAction possible_actions;
2633 GdkWindow *window = NULL;
2634 GdkWindow *dest_window;
2635 GdkDragProtocol protocol;
2637 guint32 time = gtk_drag_get_event_time (event);
2639 gtk_drag_get_event_actions (event,
2641 info->possible_actions,
2642 &action, &possible_actions);
2643 info->cur_x = x_root;
2644 info->cur_y = y_root;
2646 if (info->icon_window)
2648 gdk_window_raise (info->icon_window->window);
2649 gtk_widget_set_uposition (info->icon_window,
2650 info->cur_x - info->hot_x,
2651 info->cur_y - info->hot_y);
2652 window = info->icon_window->window;
2655 gdk_drag_find_window (info->context,
2656 window, x_root, y_root,
2657 &dest_window, &protocol);
2659 if (gdk_drag_motion (info->context, dest_window, protocol,
2660 x_root, y_root, action,
2664 if (info->last_event)
2665 gdk_event_free ((GdkEvent *)info->last_event);
2667 info->last_event = gdk_event_copy ((GdkEvent *)event);
2671 gdk_window_unref (dest_window);
2673 selection = gdk_drag_get_selection (info->context);
2675 gtk_drag_source_check_selection (info, selection, time);
2678 /*************************************************************
2680 * Called when the user finishes to drag, either by
2681 * releasing the mouse, or by pressing Esc.
2683 * widget: GtkInvisible widget for this drag
2686 *************************************************************/
2689 gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
2691 GdkEvent send_event;
2692 GtkWidget *source_widget = info->widget;
2694 gdk_pointer_ungrab (time);
2695 gdk_keyboard_ungrab (time);
2697 gtk_grab_remove (info->ipc_widget);
2699 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2700 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
2702 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2703 GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
2706 /* Send on a release pair to the the original
2707 * widget to convince it to release its grab. We need to
2708 * call gtk_propagate_event() here, instead of
2709 * gtk_widget_event() because widget like GtkList may
2710 * expect propagation.
2713 send_event.button.type = GDK_BUTTON_RELEASE;
2714 send_event.button.window = GDK_ROOT_PARENT ();
2715 send_event.button.send_event = TRUE;
2716 send_event.button.time = time;
2717 send_event.button.x = 0;
2718 send_event.button.y = 0;
2719 send_event.button.pressure = 0.;
2720 send_event.button.xtilt = 0.;
2721 send_event.button.ytilt = 0.;
2722 send_event.button.state = 0;
2723 send_event.button.button = info->button;
2724 send_event.button.source = GDK_SOURCE_PEN;
2725 send_event.button.deviceid = GDK_CORE_POINTER;
2726 send_event.button.x_root = 0;
2727 send_event.button.y_root = 0;
2729 gtk_propagate_event (source_widget, &send_event);
2732 /*************************************************************
2733 * gtk_drag_motion_cb:
2734 * "motion_notify_event" callback during drag.
2738 *************************************************************/
2741 gtk_drag_motion_cb (GtkWidget *widget,
2742 GdkEventMotion *event,
2745 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2746 gint x_root, y_root;
2750 gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL);
2751 event->x_root = x_root;
2752 event->y_root = y_root;
2755 gtk_drag_update (info, event->x_root, event->y_root, (GdkEvent *)event);
2760 /*************************************************************
2762 * "key_press/release_event" callback during drag.
2766 *************************************************************/
2769 gtk_drag_key_cb (GtkWidget *widget,
2773 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2774 GdkModifierType state;
2776 if (event->type == GDK_KEY_PRESS)
2778 if (event->keyval == GDK_Escape)
2780 gtk_drag_end (info, event->time);
2781 gdk_drag_abort (info->context, event->time);
2782 gtk_drag_drop_finished (info, FALSE, event->time);
2788 /* Now send a "motion" so that the modifier state is updated */
2790 /* The state is not yet updated in the event, so we need
2791 * to query it here. We could use XGetModifierMapping, but
2792 * that would be overkill.
2794 gdk_window_get_pointer (GDK_ROOT_PARENT(), NULL, NULL, &state);
2796 event->state = state;
2797 gtk_drag_update (info, info->cur_x, info->cur_y, (GdkEvent *)event);
2802 /*************************************************************
2803 * gtk_drag_button_release_cb:
2804 * "button_release_event" callback during drag.
2808 *************************************************************/
2811 gtk_drag_button_release_cb (GtkWidget *widget,
2812 GdkEventButton *event,
2815 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2817 if (event->button != info->button)
2820 gtk_drag_end (info, event->time);
2822 if ((info->context->action != 0) && (info->context->dest_window != NULL))
2824 gtk_drag_drop (info, event->time);
2828 gdk_drag_abort (info->context, event->time);
2829 gtk_drag_drop_finished (info, FALSE, event->time);
2836 gtk_drag_abort_timeout (gpointer data)
2838 GtkDragSourceInfo *info = data;
2839 guint32 time = GDK_CURRENT_TIME;
2841 GDK_THREADS_ENTER ();
2843 if (info->proxy_dest)
2844 time = info->proxy_dest->proxy_drop_time;
2846 info->drop_timeout = 0;
2847 gtk_drag_drop_finished (info, FALSE, time);
2849 GDK_THREADS_LEAVE ();