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 Lesser 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 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser 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-2000. 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 (GTK_OBJECT (widget), "expose_event",
814 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
817 gtk_widget_queue_draw (widget);
820 /*************************************************************
821 * gtk_drag_unhighlight:
822 * Refresh the given widget to remove the highlight.
826 *************************************************************/
829 gtk_drag_unhighlight (GtkWidget *widget)
831 g_return_if_fail (widget != NULL);
833 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
834 GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
836 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
837 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
840 gtk_widget_queue_clear (widget);
844 gtk_drag_dest_set_internal (GtkWidget *widget,
845 GtkDragDestSite *site)
847 GtkDragDestSite *old_site;
849 g_return_if_fail (widget != NULL);
851 /* HACK, do this in the destroy */
852 old_site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
854 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), old_site);
856 if (GTK_WIDGET_REALIZED (widget))
857 gtk_drag_dest_realized (widget);
859 gtk_signal_connect (GTK_OBJECT (widget), "realize",
860 GTK_SIGNAL_FUNC (gtk_drag_dest_realized), site);
862 gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
863 site, gtk_drag_dest_site_destroy);
867 /*************************************************************
869 * Register a drop site, and possibly add default behaviors.
872 * flags: Which types of default drag behavior to use
873 * targets: Table of targets that can be accepted
874 * n_targets: Number of of entries in targets
877 *************************************************************/
880 gtk_drag_dest_set (GtkWidget *widget,
881 GtkDestDefaults flags,
882 const GtkTargetEntry *targets,
884 GdkDragAction actions)
886 GtkDragDestSite *site;
888 g_return_if_fail (widget != NULL);
890 site = g_new (GtkDragDestSite, 1);
893 site->have_drag = FALSE;
895 site->target_list = gtk_target_list_new (targets, n_targets);
897 site->target_list = NULL;
899 site->actions = actions;
900 site->do_proxy = FALSE;
902 gtk_drag_dest_set_internal (widget, site);
905 /*************************************************************
906 * gtk_drag_dest_set_proxy:
907 * Set up this widget to proxy drags elsewhere.
910 * proxy_window: window to which forward drag events
911 * protocol: Drag protocol which the dest widget accepts
912 * use_coordinates: If true, send the same coordinates to the
913 * destination, because it is a embedded
916 *************************************************************/
919 gtk_drag_dest_set_proxy (GtkWidget *widget,
920 GdkWindow *proxy_window,
921 GdkDragProtocol protocol,
922 gboolean use_coordinates)
924 GtkDragDestSite *site;
926 g_return_if_fail (widget != NULL);
928 site = g_new (GtkDragDestSite, 1);
931 site->have_drag = FALSE;
932 site->target_list = NULL;
934 site->proxy_window = proxy_window;
936 gdk_window_ref (proxy_window);
937 site->do_proxy = TRUE;
938 site->proxy_protocol = protocol;
939 site->proxy_coords = use_coordinates;
941 gtk_drag_dest_set_internal (widget, site);
944 /*************************************************************
945 * gtk_drag_dest_unset
946 * Unregister this widget as a drag target.
950 *************************************************************/
953 gtk_drag_dest_unset (GtkWidget *widget)
955 g_return_if_fail (widget != NULL);
957 gtk_object_set_data (GTK_OBJECT (widget), "gtk-drag-dest", NULL);
960 /*************************************************************
961 * gtk_drag_dest_handle_event:
962 * Called from widget event handling code on Drag events
966 * toplevel: Toplevel widget that received the event
969 *************************************************************/
972 gtk_drag_dest_handle_event (GtkWidget *toplevel,
975 GtkDragDestInfo *info;
976 GdkDragContext *context;
978 g_return_if_fail (toplevel != NULL);
979 g_return_if_fail (event != NULL);
981 context = event->dnd.context;
983 info = g_dataset_get_data (context, "gtk-info");
986 info = g_new (GtkDragDestInfo, 1);
988 info->context = event->dnd.context;
989 info->proxy_source = NULL;
990 info->proxy_data = NULL;
991 info->dropped = FALSE;
992 info->proxy_drop_wait = FALSE;
993 g_object_set_qdata_full (G_OBJECT (context),
994 g_quark_from_static_string ("gtk-info"),
996 gtk_drag_dest_info_destroy);
999 /* Find the widget for the event */
1000 switch (event->type)
1002 case GDK_DRAG_ENTER:
1005 case GDK_DRAG_LEAVE:
1008 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1009 info->widget = NULL;
1013 case GDK_DRAG_MOTION:
1014 case GDK_DROP_START:
1016 GtkDragFindData data;
1019 if (event->type == GDK_DROP_START)
1021 info->dropped = TRUE;
1022 /* We send a leave here so that the widget unhighlights
1027 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1028 info->widget = NULL;
1032 gdk_window_get_origin (toplevel->window, &tx, &ty);
1034 data.x = event->dnd.x_root - tx;
1035 data.y = event->dnd.y_root - ty;
1036 data.context = context;
1039 data.toplevel = TRUE;
1040 data.callback = (event->type == GDK_DRAG_MOTION) ?
1041 gtk_drag_dest_motion : gtk_drag_dest_drop;
1042 data.time = event->dnd.time;
1044 gtk_drag_find_widget (toplevel, &data);
1046 if (info->widget && !data.found)
1048 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1049 info->widget = NULL;
1054 if (event->type == GDK_DRAG_MOTION)
1057 gdk_drag_status (context, 0, event->dnd.time);
1059 else if (event->type == GDK_DROP_START && !info->proxy_source)
1061 gdk_drop_reply (context, data.found, event->dnd.time);
1062 if ((context->protocol == GDK_DRAG_PROTO_MOTIF) && !data.found)
1063 gtk_drag_finish (context, FALSE, FALSE, event->dnd.time);
1069 g_assert_not_reached ();
1073 /*************************************************************
1074 * gtk_drag_dest_find_target:
1075 * Decide on a target for the drag.
1080 *************************************************************/
1083 gtk_drag_dest_find_target (GtkWidget *widget,
1084 GtkDragDestSite *site,
1085 GdkDragContext *context)
1088 GList *tmp_source = NULL;
1089 GtkWidget *source_widget = gtk_drag_get_source_widget (context);
1091 tmp_target = site->target_list->list;
1094 GtkTargetPair *pair = tmp_target->data;
1095 tmp_source = context->targets;
1098 if (tmp_source->data == GUINT_TO_POINTER (pair->target))
1100 if ((!(pair->flags & GTK_TARGET_SAME_APP) || source_widget) &&
1101 (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget)))
1102 return pair->target;
1106 tmp_source = tmp_source->next;
1108 tmp_target = tmp_target->next;
1115 gtk_drag_selection_received (GtkWidget *widget,
1116 GtkSelectionData *selection_data,
1120 GdkDragContext *context;
1121 GtkDragDestInfo *info;
1122 GtkWidget *drop_widget;
1126 context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
1127 info = g_object_get_qdata (G_OBJECT (context), g_quark_from_static_string ("gtk-info"));
1129 if (info->proxy_data &&
1130 info->proxy_data->target == selection_data->target)
1132 gtk_selection_data_set (info->proxy_data,
1133 selection_data->type,
1134 selection_data->format,
1135 selection_data->data,
1136 selection_data->length);
1141 if (selection_data->target == gdk_atom_intern ("DELETE", FALSE))
1143 gtk_drag_finish (context, TRUE, FALSE, time);
1145 else if ((selection_data->target == gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE)) ||
1146 (selection_data->target == gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE)))
1152 GtkDragDestSite *site;
1154 site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest");
1156 if (site && site->target_list)
1160 if (gtk_target_list_find (site->target_list,
1161 selection_data->target,
1164 if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
1165 selection_data->length >= 0)
1166 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1167 "drag_data_received",
1168 context, info->drop_x, info->drop_y,
1175 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1176 "drag_data_received",
1177 context, info->drop_x, info->drop_y,
1178 selection_data, 0, time);
1181 if (site && site->flags & GTK_DEST_DEFAULT_DROP)
1184 gtk_drag_finish (context,
1185 (selection_data->length >= 0),
1186 (context->action == GDK_ACTION_MOVE),
1190 gtk_widget_unref (drop_widget);
1193 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
1194 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
1197 gtk_object_set_data (GTK_OBJECT (widget), "drag-context", NULL);
1198 gdk_drag_context_unref (context);
1200 gtk_drag_release_ipc_widget (widget);
1203 /*************************************************************
1204 * gtk_drag_find_widget:
1205 * Recursive callback used to locate widgets for
1206 * DRAG_MOTION and DROP_START events.
1210 *************************************************************/
1213 gtk_drag_find_widget (GtkWidget *widget,
1214 GtkDragFindData *data)
1216 GtkAllocation new_allocation;
1220 new_allocation = widget->allocation;
1222 if (data->found || !GTK_WIDGET_MAPPED (widget))
1225 /* Note that in the following code, we only count the
1226 * position as being inside a WINDOW widget if it is inside
1227 * widget->window; points that are outside of widget->window
1228 * but within the allocation are not counted. This is consistent
1229 * with the way we highlight drag targets.
1231 if (!GTK_WIDGET_NO_WINDOW (widget))
1233 new_allocation.x = 0;
1234 new_allocation.y = 0;
1239 GdkWindow *window = widget->window;
1240 while (window != widget->parent->window)
1242 gint tx, ty, twidth, theight;
1243 gdk_window_get_size (window, &twidth, &theight);
1245 if (new_allocation.x < 0)
1247 new_allocation.width += new_allocation.x;
1248 new_allocation.x = 0;
1250 if (new_allocation.y < 0)
1252 new_allocation.height += new_allocation.y;
1253 new_allocation.y = 0;
1255 if (new_allocation.x + new_allocation.width > twidth)
1256 new_allocation.width = twidth - new_allocation.x;
1257 if (new_allocation.y + new_allocation.height > theight)
1258 new_allocation.height = theight - new_allocation.y;
1260 gdk_window_get_position (window, &tx, &ty);
1261 new_allocation.x += tx;
1263 new_allocation.y += ty;
1266 window = gdk_window_get_parent (window);
1270 if (data->toplevel ||
1271 ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
1272 (data->x < new_allocation.x + new_allocation.width) &&
1273 (data->y < new_allocation.y + new_allocation.height)))
1275 /* First, check if the drag is in a valid drop site in
1276 * one of our children
1278 if (GTK_IS_CONTAINER (widget))
1280 GtkDragFindData new_data = *data;
1282 new_data.x -= x_offset;
1283 new_data.y -= y_offset;
1284 new_data.found = FALSE;
1285 new_data.toplevel = FALSE;
1287 gtk_container_forall (GTK_CONTAINER (widget),
1288 (GtkCallback)gtk_drag_find_widget,
1291 data->found = new_data.found;
1294 /* If not, and this widget is registered as a drop site, check to
1295 * emit "drag_motion" to check if we are actually in
1299 gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"))
1301 data->found = data->callback (widget,
1303 data->x - new_allocation.x,
1304 data->y - new_allocation.y,
1306 /* If so, send a "drag_leave" to the last widget */
1309 if (data->info->widget && data->info->widget != widget)
1311 gtk_drag_dest_leave (data->info->widget, data->context, data->time);
1313 data->info->widget = widget;
1320 gtk_drag_proxy_begin (GtkWidget *widget,
1321 GtkDragDestInfo *dest_info)
1323 GtkDragSourceInfo *source_info;
1326 source_info = g_new0 (GtkDragSourceInfo, 1);
1327 source_info->ipc_widget = gtk_drag_get_ipc_widget ();
1329 source_info->widget = widget;
1330 gtk_widget_ref (source_info->widget);
1331 source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
1332 dest_info->context->targets);
1334 source_info->target_list = gtk_target_list_new (NULL, 0);
1335 tmp_list = dest_info->context->targets;
1338 gtk_target_list_add (source_info->target_list,
1339 GPOINTER_TO_UINT (tmp_list->data), 0, 0);
1340 tmp_list = tmp_list->next;
1343 source_info->proxy_dest = dest_info;
1345 g_object_set_qdata (G_OBJECT (source_info->context),
1346 g_quark_from_static_string ("gtk-info"),
1349 gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget),
1351 GTK_SIGNAL_FUNC (gtk_drag_selection_get),
1354 dest_info->proxy_source = source_info;
1358 gtk_drag_dest_info_destroy (gpointer data)
1360 GtkDragDestInfo *info = data;
1366 gtk_drag_dest_realized (GtkWidget *widget)
1368 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1369 gdk_window_register_dnd (toplevel->window);
1373 gtk_drag_dest_site_destroy (gpointer data)
1375 GtkDragDestSite *site = data;
1377 if (site->target_list)
1378 gtk_target_list_unref (site->target_list);
1384 * Default drag handlers
1387 gtk_drag_dest_leave (GtkWidget *widget,
1388 GdkDragContext *context,
1391 GtkDragDestSite *site;
1393 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1394 g_return_if_fail (site != NULL);
1398 GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context),
1399 g_quark_from_static_string ("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_object_get_qdata (G_OBJECT (context),
1441 g_quark_from_static_string ("gtk-info"));
1443 if (!info->proxy_source)
1444 gtk_drag_proxy_begin (widget, info);
1446 current_event = gtk_get_current_event ();
1448 if (site->proxy_window)
1450 dest_window = site->proxy_window;
1451 proto = site->proxy_protocol;
1455 gdk_drag_find_window (info->proxy_source->context,
1457 current_event->dnd.x_root,
1458 current_event->dnd.y_root,
1459 &dest_window, &proto);
1462 gdk_drag_motion (info->proxy_source->context,
1464 current_event->dnd.x_root,
1465 current_event->dnd.y_root,
1466 context->suggested_action,
1467 context->actions, time);
1469 if (!site->proxy_window && dest_window)
1470 gdk_window_unref (dest_window);
1472 selection = gdk_drag_get_selection (info->proxy_source->context);
1474 selection != gdk_drag_get_selection (info->context))
1475 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1477 gdk_event_free (current_event);
1482 if (site->flags & GTK_DEST_DEFAULT_MOTION)
1484 if (context->suggested_action & site->actions)
1485 action = context->suggested_action;
1492 if ((site->actions & (1 << i)) &&
1493 (context->actions & (1 << i)))
1501 if (action && gtk_drag_dest_find_target (widget, site, context))
1503 if (!site->have_drag)
1505 site->have_drag = TRUE;
1506 if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1507 gtk_drag_highlight (widget);
1510 gdk_drag_status (context, action, time);
1514 gdk_drag_status (context, 0, time);
1519 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_motion",
1520 context, x, y, time, &retval);
1522 return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1526 gtk_drag_dest_drop (GtkWidget *widget,
1527 GdkDragContext *context,
1532 GtkDragDestSite *site;
1533 GtkDragDestInfo *info;
1535 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1536 g_return_val_if_fail (site != NULL, FALSE);
1538 info = g_object_get_qdata (G_OBJECT (context),
1539 g_quark_from_static_string ("gtk-info"));
1540 g_return_val_if_fail (info != NULL, FALSE);
1547 if (info->proxy_source ||
1548 (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN))
1550 gtk_drag_drop (info->proxy_source, time);
1554 /* We need to synthesize a motion event, wait for a status,
1555 * and, if we get a good one, do a drop.
1558 GdkEvent *current_event;
1560 GdkWindow *dest_window;
1561 GdkDragProtocol proto;
1563 gtk_drag_proxy_begin (widget, info);
1564 info->proxy_drop_wait = TRUE;
1565 info->proxy_drop_time = time;
1567 current_event = gtk_get_current_event ();
1569 if (site->proxy_window)
1571 dest_window = site->proxy_window;
1572 proto = site->proxy_protocol;
1576 gdk_drag_find_window (info->proxy_source->context,
1578 current_event->dnd.x_root,
1579 current_event->dnd.y_root,
1580 &dest_window, &proto);
1583 gdk_drag_motion (info->proxy_source->context,
1585 current_event->dnd.x_root,
1586 current_event->dnd.y_root,
1587 context->suggested_action,
1588 context->actions, time);
1590 if (!site->proxy_window && dest_window)
1591 gdk_window_unref (dest_window);
1593 selection = gdk_drag_get_selection (info->proxy_source->context);
1595 selection != gdk_drag_get_selection (info->context))
1596 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1598 gdk_event_free (current_event);
1608 if (site->flags & GTK_DEST_DEFAULT_DROP)
1610 GdkAtom target = gtk_drag_dest_find_target (widget, site, context);
1612 if (target == GDK_NONE)
1615 gtk_drag_get_data (widget, context, target, time);
1618 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_drop",
1619 context, x, y, time, &retval);
1621 return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
1629 /*************************************************************
1630 * gtk_drag_begin: Start a drag operation
1633 * widget: Widget from which drag starts
1634 * handlers: List of handlers to supply the data for the drag
1635 * button: Button user used to start drag
1636 * time: Time of event starting drag
1639 *************************************************************/
1642 gtk_drag_begin (GtkWidget *widget,
1643 GtkTargetList *target_list,
1644 GdkDragAction actions,
1648 GtkDragSourceInfo *info;
1649 GList *targets = NULL;
1651 guint32 time = GDK_CURRENT_TIME;
1652 GdkDragAction possible_actions, suggested_action;
1654 g_return_val_if_fail (widget != NULL, NULL);
1655 g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
1656 g_return_val_if_fail (target_list != NULL, NULL);
1659 time = gdk_event_get_time (event);
1661 info = g_new0 (GtkDragSourceInfo, 1);
1662 info->ipc_widget = gtk_drag_get_ipc_widget ();
1663 source_widgets = g_slist_prepend (source_widgets, info->ipc_widget);
1665 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
1667 tmp_list = g_list_last (target_list->list);
1670 GtkTargetPair *pair = tmp_list->data;
1671 targets = g_list_prepend (targets,
1672 GINT_TO_POINTER (pair->target));
1673 tmp_list = tmp_list->prev;
1676 info->widget = widget;
1677 gtk_widget_ref (info->widget);
1679 info->context = gdk_drag_begin (info->ipc_widget->window, targets);
1680 g_list_free (targets);
1682 g_object_set_qdata (G_OBJECT (info->context),
1683 g_quark_from_static_string ("gtk-info"), info);
1685 info->button = button;
1686 info->target_list = target_list;
1687 gtk_target_list_ref (target_list);
1689 info->possible_actions = actions;
1691 info->cursor = NULL;
1692 info->status = GTK_DRAG_STATUS_DRAG;
1693 info->last_event = NULL;
1694 info->selections = NULL;
1695 info->icon_window = NULL;
1696 info->destroy_icon = FALSE;
1698 gtk_drag_get_event_actions (event, info->button, actions,
1699 &suggested_action, &possible_actions);
1701 info->cursor = gtk_drag_get_cursor (suggested_action);
1703 /* Set cur_x, cur_y here so if the "drag_begin" signal shows
1704 * the drag icon, it will be in the right place
1706 if (event && event->type == GDK_MOTION_NOTIFY)
1708 info->cur_x = event->motion.x_root;
1709 info->cur_y = event->motion.y_root;
1714 gdk_window_get_pointer (GDK_ROOT_PARENT (), &x, &y, NULL);
1720 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
1723 if (event && event->type == GDK_MOTION_NOTIFY)
1724 gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
1726 info->start_x = info->cur_x;
1727 info->start_y = info->cur_y;
1729 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "button_release_event",
1730 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info);
1731 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "motion_notify_event",
1732 GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info);
1733 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_press_event",
1734 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1735 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_release_event",
1736 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1737 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "selection_get",
1738 GTK_SIGNAL_FUNC (gtk_drag_selection_get), info);
1740 /* We use a GTK grab here to override any grabs that the widget
1741 * we are dragging from might have held
1743 gtk_grab_add (info->ipc_widget);
1744 if (gdk_pointer_grab (info->ipc_widget->window, FALSE,
1745 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1746 GDK_BUTTON_RELEASE_MASK, NULL,
1747 info->cursor, time) == 0)
1749 if (gdk_keyboard_grab (info->ipc_widget->window, FALSE, time) != 0)
1751 /* FIXME: This should be cleaned up... */
1755 ev.type = GDK_BUTTON_RELEASE;
1756 ev.button = info->button;
1758 gtk_drag_button_release_cb (widget, &ev, info);
1764 return info->context;
1767 /*************************************************************
1768 * gtk_drag_source_set:
1769 * Register a drop site, and possibly add default behaviors.
1772 * start_button_mask: Mask of allowed buttons to start drag
1773 * targets: Table of targets for this source
1775 * actions: Actions allowed for this source
1777 *************************************************************/
1780 gtk_drag_source_set (GtkWidget *widget,
1781 GdkModifierType start_button_mask,
1782 const GtkTargetEntry *targets,
1784 GdkDragAction actions)
1786 GtkDragSourceSite *site;
1788 g_return_if_fail (widget != NULL);
1790 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1792 gtk_widget_add_events (widget,
1793 gtk_widget_get_events (widget) |
1794 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1795 GDK_BUTTON_MOTION_MASK);
1799 if (site->target_list)
1800 gtk_target_list_unref (site->target_list);
1804 site = g_new0 (GtkDragSourceSite, 1);
1806 gtk_signal_connect (GTK_OBJECT (widget), "button_press_event",
1807 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1809 gtk_signal_connect (GTK_OBJECT (widget), "motion_notify_event",
1810 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1813 gtk_object_set_data_full (GTK_OBJECT (widget),
1815 site, gtk_drag_source_site_destroy);
1818 site->start_button_mask = start_button_mask;
1821 site->target_list = gtk_target_list_new (targets, n_targets);
1823 site->target_list = NULL;
1825 site->actions = actions;
1829 /*************************************************************
1830 * gtk_drag_source_unset
1831 * Unregister this widget as a drag source.
1835 *************************************************************/
1838 gtk_drag_source_unset (GtkWidget *widget)
1840 GtkDragSourceSite *site;
1842 g_return_if_fail (widget != NULL);
1844 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1848 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
1849 gtk_object_set_data (GTK_OBJECT (widget), "gtk-site-data", NULL);
1853 /*************************************************************
1854 * gtk_drag_source_set_icon:
1855 * Set an icon for drags from this source.
1857 * colormap: Colormap for this icon
1861 *************************************************************/
1864 gtk_drag_source_set_icon (GtkWidget *widget,
1865 GdkColormap *colormap,
1869 GtkDragSourceSite *site;
1871 g_return_if_fail (widget != NULL);
1873 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1874 g_return_if_fail (site != NULL);
1877 gdk_colormap_unref (site->colormap);
1879 gdk_pixmap_unref (site->pixmap);
1881 gdk_pixmap_unref (site->mask);
1883 site->colormap = colormap;
1885 gdk_colormap_ref (colormap);
1887 site->pixmap = pixmap;
1889 gdk_pixmap_ref (pixmap);
1893 gdk_pixmap_ref (mask);
1896 /*************************************************************
1897 * gtk_drag_set_icon_window:
1898 * Set a widget as the icon for a drag.
1905 *************************************************************/
1908 gtk_drag_set_icon_window (GdkDragContext *context,
1912 gboolean destroy_on_release)
1914 GtkDragSourceInfo *info;
1916 g_return_if_fail (context != NULL);
1917 g_return_if_fail (widget != NULL);
1919 info = g_object_get_qdata (G_OBJECT (context),
1920 g_quark_from_static_string ("gtk-info"));
1921 gtk_drag_remove_icon (info);
1923 info->icon_window = widget;
1924 info->hot_x = hot_x;
1925 info->hot_y = hot_y;
1929 gtk_widget_set_uposition (widget,
1930 info->cur_x - info->hot_x,
1931 info->cur_y - info->hot_y);
1932 gtk_widget_ref (widget);
1933 gdk_window_raise (widget->window);
1934 gtk_widget_show (widget);
1937 info->destroy_icon = destroy_on_release;
1940 /*************************************************************
1941 * gtk_drag_set_icon_widget:
1942 * Set a widget as the icon for a drag.
1949 *************************************************************/
1952 gtk_drag_set_icon_widget (GdkDragContext *context,
1957 g_return_if_fail (context != NULL);
1958 g_return_if_fail (widget != NULL);
1960 gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE);
1963 /*************************************************************
1964 * gtk_drag_set_icon_pixmap:
1965 * Set a widget as the icon for a drag.
1968 * colormap: Colormap for the icon window.
1974 *************************************************************/
1977 gtk_drag_set_icon_pixmap (GdkDragContext *context,
1978 GdkColormap *colormap,
1987 g_return_if_fail (context != NULL);
1988 g_return_if_fail (colormap != NULL);
1989 g_return_if_fail (pixmap != NULL);
1991 gdk_window_get_size (pixmap, &width, &height);
1993 gtk_widget_push_colormap (colormap);
1995 window = gtk_window_new (GTK_WINDOW_POPUP);
1996 gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
1997 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
1999 gtk_widget_pop_colormap ();
2001 gtk_widget_set_usize (window, width, height);
2002 gtk_widget_realize (window);
2004 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
2007 gtk_widget_shape_combine_mask (window, mask, 0, 0);
2009 gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
2012 /*************************************************************
2013 * gtk_drag_set_icon_default:
2014 * Set the icon for a drag to the default icon.
2018 *************************************************************/
2021 gtk_drag_set_icon_default (GdkDragContext *context)
2023 g_return_if_fail (context != NULL);
2025 if (!default_icon_pixmap)
2027 default_icon_colormap = gdk_colormap_get_system ();
2028 default_icon_pixmap =
2029 gdk_pixmap_colormap_create_from_xpm_d (NULL,
2030 default_icon_colormap,
2032 NULL, (gchar **)drag_default_xpm);
2033 default_icon_hot_x = -2;
2034 default_icon_hot_y = -2;
2037 gtk_drag_set_icon_pixmap (context,
2038 default_icon_colormap,
2039 default_icon_pixmap,
2042 default_icon_hot_y);
2045 /*************************************************************
2046 * gtk_drag_set_default_icon:
2047 * Set a default icon for all drags as a pixmap.
2049 * colormap: Colormap for the icon window.
2055 *************************************************************/
2058 gtk_drag_set_default_icon (GdkColormap *colormap,
2064 g_return_if_fail (colormap != NULL);
2065 g_return_if_fail (pixmap != NULL);
2067 if (default_icon_colormap)
2068 gdk_colormap_unref (default_icon_colormap);
2069 if (default_icon_pixmap)
2070 gdk_pixmap_unref (default_icon_pixmap);
2071 if (default_icon_mask)
2072 gdk_pixmap_unref (default_icon_mask);
2074 default_icon_colormap = colormap;
2075 gdk_colormap_ref (colormap);
2077 default_icon_pixmap = pixmap;
2078 gdk_pixmap_ref (pixmap);
2080 default_icon_mask = mask;
2082 gdk_pixmap_ref (mask);
2084 default_icon_hot_x = hot_x;
2085 default_icon_hot_y = hot_y;
2089 /*************************************************************
2090 * gtk_drag_source_handle_event:
2091 * Called from widget event handling code on Drag events
2095 * toplevel: Toplevel widget that received the event
2098 *************************************************************/
2101 gtk_drag_source_handle_event (GtkWidget *widget,
2104 GtkDragSourceInfo *info;
2105 GdkDragContext *context;
2107 g_return_if_fail (widget != NULL);
2108 g_return_if_fail (event != NULL);
2110 context = event->dnd.context;
2111 info = g_object_get_qdata (G_OBJECT (context),
2112 g_quark_from_static_string ("gtk-info"));
2116 switch (event->type)
2118 case GDK_DRAG_STATUS:
2122 if (info->proxy_dest)
2124 if (!event->dnd.send_event)
2126 if (info->proxy_dest->proxy_drop_wait)
2128 gboolean result = context->action != 0;
2130 /* Aha - we can finally pass the MOTIF DROP on... */
2131 gdk_drop_reply (info->proxy_dest->context, result, info->proxy_dest->proxy_drop_time);
2133 gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
2135 gtk_drag_finish (info->proxy_dest->context, FALSE, FALSE, info->proxy_dest->proxy_drop_time);
2139 gdk_drag_status (info->proxy_dest->context,
2140 event->dnd.context->action,
2147 cursor = gtk_drag_get_cursor (event->dnd.context->action);
2148 if (info->cursor != cursor)
2150 #ifdef GDK_WINDOWING_X11
2151 XChangeActivePointerGrab (GDK_WINDOW_XDISPLAY (widget->window),
2152 PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask,
2153 ((GdkCursorPrivate *)cursor)->xcursor,
2155 #elif defined (GDK_WINDOWING_WIN32)
2156 gdk_pointer_grab (widget->window, FALSE,
2157 GDK_POINTER_MOTION_MASK |
2158 GDK_POINTER_MOTION_HINT_MASK |
2159 GDK_BUTTON_RELEASE_MASK,
2161 info->cursor, event->dnd.time);
2163 info->cursor = cursor;
2166 if (info->last_event)
2168 gtk_drag_update (info,
2169 info->cur_x, info->cur_y,
2171 info->last_event = NULL;
2177 case GDK_DROP_FINISHED:
2178 gtk_drag_drop_finished (info, TRUE, event->dnd.time);
2181 g_assert_not_reached ();
2185 /*************************************************************
2186 * gtk_drag_source_check_selection:
2187 * Check if we've set up handlers/claimed the selection
2188 * for a given drag. If not, add them.
2192 *************************************************************/
2195 gtk_drag_source_check_selection (GtkDragSourceInfo *info,
2201 tmp_list = info->selections;
2204 if (GPOINTER_TO_UINT (tmp_list->data) == selection)
2206 tmp_list = tmp_list->next;
2209 gtk_selection_owner_set (info->ipc_widget, selection, time);
2210 info->selections = g_list_prepend (info->selections,
2211 GUINT_TO_POINTER (selection));
2213 tmp_list = info->target_list->list;
2216 GtkTargetPair *pair = tmp_list->data;
2218 gtk_selection_add_target (info->ipc_widget,
2222 tmp_list = tmp_list->next;
2225 if (info->context->protocol == GDK_DRAG_PROTO_MOTIF)
2227 gtk_selection_add_target (info->ipc_widget,
2229 gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE),
2230 TARGET_MOTIF_SUCCESS);
2231 gtk_selection_add_target (info->ipc_widget,
2233 gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE),
2234 TARGET_MOTIF_FAILURE);
2237 gtk_selection_add_target (info->ipc_widget,
2239 gdk_atom_intern ("DELETE", FALSE),
2243 /*************************************************************
2244 * gtk_drag_drop_finished:
2245 * Clean up from the drag, and display snapback, if necessary.
2251 *************************************************************/
2254 gtk_drag_drop_finished (GtkDragSourceInfo *info,
2258 gtk_drag_source_release_selections (info, time);
2260 if (info->proxy_dest)
2262 /* The time from the event isn't reliable for Xdnd drags */
2263 gtk_drag_finish (info->proxy_dest->context, success, FALSE,
2264 info->proxy_dest->proxy_drop_time);
2265 gtk_drag_source_info_destroy (info);
2271 gtk_drag_source_info_destroy (info);
2275 GtkDragAnim *anim = g_new (GtkDragAnim, 1);
2279 anim->n_steps = MAX (info->cur_x - info->start_x,
2280 info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
2281 anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
2282 if (info->icon_window)
2284 gtk_widget_show (info->icon_window);
2285 gdk_window_raise (info->icon_window->window);
2288 /* Mark the context as dead, so if the destination decides
2289 * to respond really late, we still are OK.
2291 g_object_set_qdata (G_OBJECT (info->context),
2292 g_quark_from_static_string ("gtk-info"), NULL);
2293 gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
2299 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
2302 GList *tmp_list = info->selections;
2305 GdkAtom selection = GPOINTER_TO_UINT (tmp_list->data);
2306 if (gdk_selection_owner_get (selection) == info->ipc_widget->window)
2307 gtk_selection_owner_set (NULL, selection, time);
2308 tmp_list = tmp_list->next;
2311 g_list_free (info->selections);
2312 info->selections = NULL;
2315 /*************************************************************
2317 * Send a drop event.
2321 *************************************************************/
2324 gtk_drag_drop (GtkDragSourceInfo *info,
2327 if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN)
2329 GtkSelectionData selection_data;
2331 GdkAtom target = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
2333 tmp_list = info->target_list->list;
2336 GtkTargetPair *pair = tmp_list->data;
2338 if (pair->target == target)
2340 selection_data.selection = GDK_NONE;
2341 selection_data.target = target;
2342 selection_data.data = NULL;
2343 selection_data.length = -1;
2345 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2346 info->context, &selection_data,
2350 /* FIXME: Should we check for length >= 0 here? */
2351 gtk_drag_drop_finished (info, TRUE, time);
2354 tmp_list = tmp_list->next;
2356 gtk_drag_drop_finished (info, FALSE, time);
2360 if (info->icon_window)
2361 gtk_widget_hide (info->icon_window);
2363 gdk_drag_drop (info->context, time);
2364 info->drop_timeout = gtk_timeout_add (DROP_ABORT_TIME,
2365 gtk_drag_abort_timeout,
2371 * Source side callbacks.
2375 gtk_drag_source_event_cb (GtkWidget *widget,
2379 GtkDragSourceSite *site;
2380 site = (GtkDragSourceSite *)data;
2382 switch (event->type)
2384 case GDK_BUTTON_PRESS:
2385 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2387 site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1));
2388 site->x = event->button.x;
2389 site->y = event->button.y;
2393 case GDK_BUTTON_RELEASE:
2394 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2396 site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
2400 case GDK_MOTION_NOTIFY:
2401 if (site->state & event->motion.state & site->start_button_mask)
2403 /* FIXME: This is really broken and can leave us
2409 if (site->state & event->motion.state &
2410 GDK_BUTTON1_MASK << (i - 1))
2414 if (MAX (ABS (site->x - event->motion.x),
2415 ABS (site->y - event->motion.y)) > 3)
2417 GtkDragSourceInfo *info;
2418 GdkDragContext *context;
2421 context = gtk_drag_begin (widget, site->target_list,
2426 info = g_object_get_qdata (G_OBJECT (context),
2427 g_quark_from_static_string ("gtk-info"));
2429 if (!info->icon_window)
2432 gtk_drag_set_icon_pixmap (context,
2435 site->mask, -2, -2);
2437 gtk_drag_set_icon_default (context);
2445 default: /* hit for 2/3BUTTON_PRESS */
2452 gtk_drag_source_site_destroy (gpointer data)
2454 GtkDragSourceSite *site = data;
2456 if (site->target_list)
2457 gtk_target_list_unref (site->target_list);
2460 gdk_pixmap_unref (site->pixmap);
2463 gdk_pixmap_unref (site->mask);
2469 gtk_drag_selection_get (GtkWidget *widget,
2470 GtkSelectionData *selection_data,
2475 GtkDragSourceInfo *info = data;
2476 static GdkAtom null_atom = GDK_NONE;
2480 null_atom = gdk_atom_intern ("NULL", FALSE);
2485 gtk_signal_emit_by_name (GTK_OBJECT (info->widget),
2488 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2490 case TARGET_MOTIF_SUCCESS:
2491 gtk_drag_drop_finished (info, TRUE, time);
2492 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2494 case TARGET_MOTIF_FAILURE:
2495 gtk_drag_drop_finished (info, FALSE, time);
2496 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2499 if (info->proxy_dest)
2501 /* This is sort of dangerous and needs to be thought
2504 info->proxy_dest->proxy_data = selection_data;
2505 gtk_drag_get_data (info->widget,
2506 info->proxy_dest->context,
2507 selection_data->target,
2510 info->proxy_dest->proxy_data = NULL;
2514 if (gtk_target_list_find (info->target_list,
2515 selection_data->target,
2518 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2530 gtk_drag_anim_timeout (gpointer data)
2532 GtkDragAnim *anim = data;
2536 GDK_THREADS_ENTER ();
2538 if (anim->step == anim->n_steps)
2540 gtk_drag_source_info_destroy (anim->info);
2547 x = (anim->info->start_x * (anim->step + 1) +
2548 anim->info->cur_x * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2549 y = (anim->info->start_y * (anim->step + 1) +
2550 anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2551 if (anim->info->icon_window)
2552 gtk_widget_set_uposition (anim->info->icon_window,
2553 x - anim->info->hot_x,
2554 y - anim->info->hot_y);
2561 GDK_THREADS_LEAVE ();
2567 gtk_drag_remove_icon (GtkDragSourceInfo *info)
2569 if (info->icon_window)
2571 gtk_widget_hide (info->icon_window);
2572 if (info->destroy_icon)
2573 gtk_widget_destroy (info->icon_window);
2575 gtk_widget_unref (info->icon_window);
2576 info->icon_window = NULL;
2581 gtk_drag_source_info_destroy (gpointer data)
2583 GtkDragSourceInfo *info = data;
2585 gtk_drag_remove_icon (data);
2587 if (!info->proxy_dest)
2588 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end",
2592 gtk_widget_unref (info->widget);
2594 gtk_signal_disconnect_by_data (GTK_OBJECT (info->ipc_widget), info);
2595 gtk_selection_remove_all (info->ipc_widget);
2596 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", NULL);
2597 source_widgets = g_slist_remove (source_widgets, info->ipc_widget);
2598 gtk_drag_release_ipc_widget (info->ipc_widget);
2600 gtk_target_list_unref (info->target_list);
2602 g_object_set_qdata (G_OBJECT (info->context), g_quark_from_static_string ("gtk-info"), NULL);
2603 gdk_drag_context_unref (info->context);
2605 if (info->drop_timeout)
2606 gtk_timeout_remove (info->drop_timeout);
2611 /*************************************************************
2613 * Function to update the status of the drag when the
2614 * cursor moves or the modifier changes
2616 * info: DragSourceInfo for the drag
2617 * x_root, y_root: position of darg
2618 * event: The event that triggered this call
2620 *************************************************************/
2623 gtk_drag_update (GtkDragSourceInfo *info,
2628 GdkDragAction action;
2629 GdkDragAction possible_actions;
2630 GdkWindow *window = NULL;
2631 GdkWindow *dest_window;
2632 GdkDragProtocol protocol;
2634 guint32 time = gtk_drag_get_event_time (event);
2636 gtk_drag_get_event_actions (event,
2638 info->possible_actions,
2639 &action, &possible_actions);
2640 info->cur_x = x_root;
2641 info->cur_y = y_root;
2643 if (info->icon_window)
2645 gdk_window_raise (info->icon_window->window);
2646 gtk_widget_set_uposition (info->icon_window,
2647 info->cur_x - info->hot_x,
2648 info->cur_y - info->hot_y);
2649 window = info->icon_window->window;
2652 gdk_drag_find_window (info->context,
2653 window, x_root, y_root,
2654 &dest_window, &protocol);
2656 if (gdk_drag_motion (info->context, dest_window, protocol,
2657 x_root, y_root, action,
2661 if (info->last_event != event) /* Paranoia, should not happen */
2663 if (info->last_event)
2664 gdk_event_free ((GdkEvent *)info->last_event);
2665 info->last_event = gdk_event_copy ((GdkEvent *)event);
2670 if (info->last_event)
2672 gdk_event_free ((GdkEvent *)info->last_event);
2673 info->last_event = NULL;
2678 gdk_window_unref (dest_window);
2680 selection = gdk_drag_get_selection (info->context);
2682 gtk_drag_source_check_selection (info, selection, time);
2685 /*************************************************************
2687 * Called when the user finishes to drag, either by
2688 * releasing the mouse, or by pressing Esc.
2690 * widget: GtkInvisible widget for this drag
2693 *************************************************************/
2696 gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
2698 GdkEvent send_event;
2699 GtkWidget *source_widget = info->widget;
2701 gdk_pointer_ungrab (time);
2702 gdk_keyboard_ungrab (time);
2704 gtk_grab_remove (info->ipc_widget);
2706 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2707 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
2709 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2710 GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
2713 /* Send on a release pair to the the original
2714 * widget to convince it to release its grab. We need to
2715 * call gtk_propagate_event() here, instead of
2716 * gtk_widget_event() because widget like GtkList may
2717 * expect propagation.
2720 send_event.button.type = GDK_BUTTON_RELEASE;
2721 send_event.button.window = GDK_ROOT_PARENT ();
2722 send_event.button.send_event = TRUE;
2723 send_event.button.time = time;
2724 send_event.button.x = 0;
2725 send_event.button.y = 0;
2726 send_event.button.axes = NULL;
2727 send_event.button.state = 0;
2728 send_event.button.button = info->button;
2729 send_event.button.device = gdk_core_pointer;
2730 send_event.button.x_root = 0;
2731 send_event.button.y_root = 0;
2733 gtk_propagate_event (source_widget, &send_event);
2736 /*************************************************************
2737 * gtk_drag_motion_cb:
2738 * "motion_notify_event" callback during drag.
2742 *************************************************************/
2745 gtk_drag_motion_cb (GtkWidget *widget,
2746 GdkEventMotion *event,
2749 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2750 gint x_root, y_root;
2754 gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL);
2755 event->x_root = x_root;
2756 event->y_root = y_root;
2759 gtk_drag_update (info, event->x_root, event->y_root, (GdkEvent *)event);
2764 /*************************************************************
2766 * "key_press/release_event" callback during drag.
2770 *************************************************************/
2773 gtk_drag_key_cb (GtkWidget *widget,
2777 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2778 GdkModifierType state;
2780 if (event->type == GDK_KEY_PRESS)
2782 if (event->keyval == GDK_Escape)
2784 gtk_drag_end (info, event->time);
2785 gdk_drag_abort (info->context, event->time);
2786 gtk_drag_drop_finished (info, FALSE, event->time);
2792 /* Now send a "motion" so that the modifier state is updated */
2794 /* The state is not yet updated in the event, so we need
2795 * to query it here. We could use XGetModifierMapping, but
2796 * that would be overkill.
2798 gdk_window_get_pointer (GDK_ROOT_PARENT(), NULL, NULL, &state);
2800 event->state = state;
2801 gtk_drag_update (info, info->cur_x, info->cur_y, (GdkEvent *)event);
2806 /*************************************************************
2807 * gtk_drag_button_release_cb:
2808 * "button_release_event" callback during drag.
2812 *************************************************************/
2815 gtk_drag_button_release_cb (GtkWidget *widget,
2816 GdkEventButton *event,
2819 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2821 if (event->button != info->button)
2824 gtk_drag_end (info, event->time);
2826 if ((info->context->action != 0) && (info->context->dest_window != NULL))
2828 gtk_drag_drop (info, event->time);
2832 gdk_drag_abort (info->context, event->time);
2833 gtk_drag_drop_finished (info, FALSE, event->time);
2840 gtk_drag_abort_timeout (gpointer data)
2842 GtkDragSourceInfo *info = data;
2843 guint32 time = GDK_CURRENT_TIME;
2845 GDK_THREADS_ENTER ();
2847 if (info->proxy_dest)
2848 time = info->proxy_dest->proxy_drop_time;
2850 info->drop_timeout = 0;
2851 gtk_drag_drop_finished (info, FALSE, time);
2853 GDK_THREADS_LEAVE ();