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 gboolean gtk_drag_highlight_expose (GtkWidget *widget,
187 GdkEventExpose *event,
190 static void gtk_drag_selection_received (GtkWidget *widget,
191 GtkSelectionData *selection_data,
194 static void gtk_drag_find_widget (GtkWidget *widget,
195 GtkDragFindData *data);
196 static void gtk_drag_proxy_begin (GtkWidget *widget,
197 GtkDragDestInfo *dest_info,
199 static void gtk_drag_dest_realized (GtkWidget *widget);
200 static void gtk_drag_dest_site_destroy (gpointer data);
201 static void gtk_drag_dest_leave (GtkWidget *widget,
202 GdkDragContext *context,
204 static gboolean gtk_drag_dest_motion (GtkWidget *widget,
205 GdkDragContext *context,
209 static gboolean gtk_drag_dest_drop (GtkWidget *widget,
210 GdkDragContext *context,
215 static GtkDragDestInfo * gtk_drag_get_dest_info (GdkDragContext *context,
217 static GtkDragSourceInfo *gtk_drag_get_source_info (GdkDragContext *context,
219 static void gtk_drag_clear_source_info (GdkDragContext *context);
221 static void gtk_drag_source_check_selection (GtkDragSourceInfo *info,
224 static void gtk_drag_source_release_selections (GtkDragSourceInfo *info,
226 static void gtk_drag_drop (GtkDragSourceInfo *info,
228 static void gtk_drag_drop_finished (GtkDragSourceInfo *info,
232 static gint gtk_drag_source_event_cb (GtkWidget *widget,
235 static void gtk_drag_source_site_destroy (gpointer data);
236 static void gtk_drag_selection_get (GtkWidget *widget,
237 GtkSelectionData *selection_data,
241 static gint gtk_drag_anim_timeout (gpointer data);
242 static void gtk_drag_remove_icon (GtkDragSourceInfo *info);
243 static void gtk_drag_source_info_destroy (GtkDragSourceInfo *info);
244 static void gtk_drag_update (GtkDragSourceInfo *info,
248 static gint gtk_drag_motion_cb (GtkWidget *widget,
249 GdkEventMotion *event,
251 static gint gtk_drag_key_cb (GtkWidget *widget,
254 static gint gtk_drag_button_release_cb (GtkWidget *widget,
255 GdkEventButton *event,
257 static gint gtk_drag_abort_timeout (gpointer data);
259 /************************
260 * Cursor and Icon data *
261 ************************/
263 #define action_ask_width 16
264 #define action_ask_height 16
265 static const guchar action_ask_bits[] = {
266 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xf8, 0xb6, 0xf7,
267 0xd6, 0xec, 0x66, 0xdb, 0x66, 0xdb, 0x96, 0xec, 0x76, 0xf7, 0x76, 0xfb,
268 0xf6, 0xfc, 0x72, 0xfb, 0x7a, 0xfb, 0xf8, 0xfc, };
270 #define action_ask_mask_width 16
271 #define action_ask_mask_height 16
272 static const guchar action_ask_mask_bits[] = {
273 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0xcf, 0x0f,
274 0xef, 0x1f, 0xff, 0x3c, 0xff, 0x3c, 0x6f, 0x1f, 0x8f, 0x0f, 0x8f, 0x07,
275 0x0f, 0x03, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x03, };
277 #define action_copy_width 16
278 #define action_copy_height 16
279 static const guchar action_copy_bits[] = {
280 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xfb, 0x76, 0xfb,
281 0x76, 0xfb, 0x06, 0x83, 0xf6, 0xbf, 0xf6, 0xbf, 0x06, 0x83, 0x76, 0xfb,
282 0x76, 0xfb, 0x72, 0xfb, 0x7a, 0xf8, 0xf8, 0xff, };
284 #define action_copy_mask_width 16
285 #define action_copy_mask_height 16
286 static const guchar action_copy_mask_bits[] = {
287 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0x8f, 0x07,
288 0x8f, 0x07, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x8f, 0x07,
289 0x8f, 0x07, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x00, };
291 #define action_move_width 16
292 #define action_move_height 16
293 static const guchar action_move_bits[] = {
294 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x96, 0xff, 0x26, 0xff,
295 0xc6, 0xf8, 0xd6, 0xe3, 0x96, 0x8f, 0xb6, 0xbf, 0x36, 0xc3, 0x76, 0xfb,
296 0x76, 0xfa, 0xf2, 0xfa, 0xfa, 0xf8, 0xf8, 0xff, };
298 #define action_move_mask_width 16
299 #define action_move_mask_height 16
300 static const guchar action_move_mask_bits[] = {
301 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x6f, 0x00, 0xff, 0x00,
302 0xff, 0x07, 0xef, 0x1f, 0xef, 0x7f, 0xcf, 0x7f, 0xcf, 0x3f, 0x8f, 0x07,
303 0x8f, 0x07, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x00, };
305 #define action_link_width 16
306 #define action_link_height 16
307 static const guchar action_link_bits[] = {
308 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x36, 0xf8, 0xd6, 0xf7,
309 0x66, 0xec, 0xa6, 0xe8, 0x26, 0xdf, 0xe6, 0xbd, 0xd6, 0xa7, 0xb6, 0xa8,
310 0xb6, 0xb1, 0x72, 0xdf, 0xfa, 0xe0, 0xf8, 0xff, };
312 #define action_link_mask_width 16
313 #define action_link_mask_height 16
314 static const guchar action_link_mask_bits[] = {
315 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xcf, 0x07, 0xef, 0x0f,
316 0xff, 0x1f, 0x7f, 0x1f, 0xff, 0x3f, 0xff, 0x7f, 0xef, 0x7f, 0xcf, 0x77,
317 0xcf, 0x7f, 0x8f, 0x3f, 0x07, 0x1f, 0x07, 0x00, };
319 #define action_none_width 16
320 #define action_none_height 16
321 static const guchar action_none_bits[] = {
322 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0xf6, 0xff, 0xf6, 0xff,
323 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff,
324 0xf6, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf8, 0xff, };
326 #define action_none_mask_width 16
327 #define action_none_mask_height 16
328 static const guchar action_none_mask_bits[] = {
329 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x0f, 0x00,
330 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00,
331 0x0f, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x07, 0x00, };
333 #define CURSOR_WIDTH 16
334 #define CURSOR_HEIGHT 16
337 GdkDragAction action;
342 { GDK_ACTION_DEFAULT, 0 },
343 { GDK_ACTION_ASK, action_ask_bits, action_ask_mask_bits, NULL },
344 { GDK_ACTION_COPY, action_copy_bits, action_copy_mask_bits, NULL },
345 { GDK_ACTION_MOVE, action_move_bits, action_move_mask_bits, NULL },
346 { GDK_ACTION_LINK, action_link_bits, action_link_mask_bits, NULL },
347 { 0 , action_none_bits, action_none_mask_bits, NULL },
350 static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[0]);
353 static const char *drag_default_xpm[] = {
366 " ...+++++++++++.. ",
367 " ..+.++++++++++++.. ",
368 " .++.++++++++++++.. ",
369 " .+++.++++++++++++.. ",
370 " .++++.++++++++++++. ",
371 " .+++.+++++++++++++.. ",
372 " .++.+++++++++++++++.. ",
373 " .+.+++++++++++++++++.. ",
374 " ..+++++++++++++++++++.. ",
375 " ..++++++++++++++++++++. ",
376 " .++++++++++++++++++++.. ",
377 " ..+++++++++++++++++.. ",
378 " .++++++++++++++++.. ",
379 " ..+++++++++++++... ",
391 /*********************
392 * Utility functions *
393 *********************/
395 /*************************************************************
396 * gtk_drag_get_ipc_widget:
397 * Return a invisible, off-screen, override-redirect
402 *************************************************************/
405 gtk_drag_get_ipc_widget (void)
411 GSList *tmp = drag_widgets;
412 result = drag_widgets->data;
413 drag_widgets = drag_widgets->next;
414 g_slist_free_1 (tmp);
418 result = gtk_invisible_new ();
419 gtk_widget_show (result);
425 /***************************************************************
426 * gtk_drag_release_ipc_widget:
427 * Releases widget retrieved with gtk_drag_get_ipc_widget ()
429 * widget: the widget to release.
431 ***************************************************************/
434 gtk_drag_release_ipc_widget (GtkWidget *widget)
436 drag_widgets = g_slist_prepend (drag_widgets, widget);
440 gtk_drag_get_event_time (GdkEvent *event)
442 guint32 tm = GDK_CURRENT_TIME;
447 case GDK_MOTION_NOTIFY:
448 tm = event->motion.time; break;
449 case GDK_BUTTON_PRESS:
450 case GDK_2BUTTON_PRESS:
451 case GDK_3BUTTON_PRESS:
452 case GDK_BUTTON_RELEASE:
453 tm = event->button.time; break;
455 case GDK_KEY_RELEASE:
456 tm = event->key.time; break;
457 case GDK_ENTER_NOTIFY:
458 case GDK_LEAVE_NOTIFY:
459 tm = event->crossing.time; break;
460 case GDK_PROPERTY_NOTIFY:
461 tm = event->property.time; break;
462 case GDK_SELECTION_CLEAR:
463 case GDK_SELECTION_REQUEST:
464 case GDK_SELECTION_NOTIFY:
465 tm = event->selection.time; break;
466 case GDK_PROXIMITY_IN:
467 case GDK_PROXIMITY_OUT:
468 tm = event->proximity.time; break;
469 default: /* use current time */
477 gtk_drag_get_event_actions (GdkEvent *event,
479 GdkDragAction actions,
480 GdkDragAction *suggested_action,
481 GdkDragAction *possible_actions)
483 *suggested_action = 0;
484 *possible_actions = 0;
488 GdkModifierType state = 0;
492 case GDK_MOTION_NOTIFY:
493 state = event->motion.state;
495 case GDK_BUTTON_PRESS:
496 case GDK_2BUTTON_PRESS:
497 case GDK_3BUTTON_PRESS:
498 case GDK_BUTTON_RELEASE:
499 state = event->button.state;
502 case GDK_KEY_RELEASE:
503 state = event->key.state;
505 case GDK_ENTER_NOTIFY:
506 case GDK_LEAVE_NOTIFY:
507 state = event->crossing.state;
513 if ((button == 2 || button == 3) && (actions & GDK_ACTION_ASK))
515 *suggested_action = GDK_ACTION_ASK;
516 *possible_actions = actions;
518 else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
520 if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
522 if (actions & GDK_ACTION_LINK)
524 *suggested_action = GDK_ACTION_LINK;
525 *possible_actions = GDK_ACTION_LINK;
528 else if (state & GDK_CONTROL_MASK)
530 if (actions & GDK_ACTION_COPY)
532 *suggested_action = GDK_ACTION_COPY;
533 *possible_actions = GDK_ACTION_COPY;
539 if (actions & GDK_ACTION_MOVE)
541 *suggested_action = GDK_ACTION_MOVE;
542 *possible_actions = GDK_ACTION_MOVE;
549 *possible_actions = actions;
551 if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK))
552 *suggested_action = GDK_ACTION_ASK;
553 else if (actions & GDK_ACTION_COPY)
554 *suggested_action = GDK_ACTION_COPY;
555 else if (actions & GDK_ACTION_MOVE)
556 *suggested_action = GDK_ACTION_MOVE;
557 else if (actions & GDK_ACTION_LINK)
558 *suggested_action = GDK_ACTION_LINK;
563 *possible_actions = actions;
565 if (actions & GDK_ACTION_COPY)
566 *suggested_action = GDK_ACTION_COPY;
567 else if (actions & GDK_ACTION_MOVE)
568 *suggested_action = GDK_ACTION_MOVE;
569 else if (actions & GDK_ACTION_LINK)
570 *suggested_action = GDK_ACTION_LINK;
577 gtk_drag_get_cursor (GdkDragAction action)
581 for (i = 0 ; i < n_drag_cursors - 1; i++)
582 if (drag_cursors[i].action == action)
585 if (drag_cursors[i].cursor == NULL)
590 gdk_bitmap_create_from_data (NULL,
591 drag_cursors[i].bits,
592 CURSOR_WIDTH, CURSOR_HEIGHT);
594 gdk_bitmap_create_from_data (NULL,
595 drag_cursors[i].mask,
596 CURSOR_WIDTH, CURSOR_HEIGHT);
598 gdk_color_white (gdk_colormap_get_system (), &bg);
599 gdk_color_black (gdk_colormap_get_system (), &fg);
601 drag_cursors[i].cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, 0, 0);
603 gdk_pixmap_unref (pixmap);
604 gdk_pixmap_unref (mask);
607 return drag_cursors[i].cursor;
610 /********************
612 ********************/
614 /*************************************************************
616 * Get the data for a drag or drop
618 * context - drag context
619 * target - format to retrieve the data in.
620 * time - timestamp of triggering event.
623 *************************************************************/
626 gtk_drag_get_data (GtkWidget *widget,
627 GdkDragContext *context,
631 GtkWidget *selection_widget;
633 g_return_if_fail (widget != NULL);
634 g_return_if_fail (context != NULL);
636 selection_widget = gtk_drag_get_ipc_widget ();
638 gdk_drag_context_ref (context);
639 gtk_widget_ref (widget);
641 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
642 GTK_SIGNAL_FUNC (gtk_drag_selection_received), widget);
644 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
646 gtk_selection_convert (selection_widget,
647 gdk_drag_get_selection (context),
653 /*************************************************************
654 * gtk_drag_get_source_widget:
655 * Get the widget the was the source of this drag, if
656 * the drag originated from this application.
658 * context: The drag context for this drag
660 * The source widget, or NULL if the drag originated from
661 * a different application.
662 *************************************************************/
665 gtk_drag_get_source_widget (GdkDragContext *context)
669 tmp_list = source_widgets;
672 GtkWidget *ipc_widget = tmp_list->data;
674 if (ipc_widget->window == context->source_window)
676 GtkDragSourceInfo *info;
677 info = gtk_object_get_data (GTK_OBJECT (ipc_widget), "gtk-info");
679 return info ? info->widget : NULL;
682 tmp_list = tmp_list->next;
688 /*************************************************************
690 * Notify the drag source that the transfer of data
693 * context: The drag context for this drag
694 * success: Was the data successfully transferred?
695 * time: The timestamp to use when notifying the destination.
697 *************************************************************/
700 gtk_drag_finish (GdkDragContext *context,
705 GdkAtom target = GDK_NONE;
707 g_return_if_fail (context != NULL);
711 target = gdk_atom_intern ("DELETE", FALSE);
713 else if (context->protocol == GDK_DRAG_PROTO_MOTIF)
715 target = gdk_atom_intern (success ?
716 "XmTRANSFER_SUCCESS" :
717 "XmTRANSFER_FAILURE",
721 if (target != GDK_NONE)
723 GtkWidget *selection_widget = gtk_drag_get_ipc_widget ();
725 gdk_drag_context_ref (context);
727 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
728 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
729 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
732 gtk_selection_convert (selection_widget,
733 gdk_drag_get_selection (context),
739 gdk_drop_finish (context, success, time);
742 /*************************************************************
743 * gtk_drag_highlight_expose:
744 * Callback for expose_event for highlighted widgets.
750 *************************************************************/
753 gtk_drag_highlight_expose (GtkWidget *widget,
754 GdkEventExpose *event,
757 gint x, y, width, height;
759 if (GTK_WIDGET_DRAWABLE (widget))
761 if (GTK_WIDGET_NO_WINDOW (widget))
763 x = widget->allocation.x;
764 y = widget->allocation.y;
765 width = widget->allocation.width;
766 height = widget->allocation.height;
772 gdk_window_get_size (widget->window, &width, &height);
775 gtk_draw_shadow (widget->style, widget->window,
776 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
777 x, y, width, height);
779 gdk_draw_rectangle (widget->window,
780 widget->style->black_gc,
782 x, y, width - 1, height - 1);
788 /*************************************************************
789 * gtk_drag_highlight:
790 * Highlight the given widget in the default manner.
794 *************************************************************/
797 gtk_drag_highlight (GtkWidget *widget)
799 gtk_signal_connect (GTK_OBJECT (widget), "expose_event",
800 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
803 gtk_widget_queue_draw (widget);
806 /*************************************************************
807 * gtk_drag_unhighlight:
808 * Refresh the given widget to remove the highlight.
812 *************************************************************/
815 gtk_drag_unhighlight (GtkWidget *widget)
817 g_return_if_fail (widget != NULL);
819 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
820 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
823 gtk_widget_queue_clear (widget);
827 gtk_drag_dest_set_internal (GtkWidget *widget,
828 GtkDragDestSite *site)
830 GtkDragDestSite *old_site;
832 g_return_if_fail (widget != NULL);
834 /* HACK, do this in the destroy */
835 old_site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
837 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), old_site);
839 if (GTK_WIDGET_REALIZED (widget))
840 gtk_drag_dest_realized (widget);
842 gtk_signal_connect (GTK_OBJECT (widget), "realize",
843 GTK_SIGNAL_FUNC (gtk_drag_dest_realized), site);
845 gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
846 site, gtk_drag_dest_site_destroy);
850 /*************************************************************
852 * Register a drop site, and possibly add default behaviors.
855 * flags: Which types of default drag behavior to use
856 * targets: Table of targets that can be accepted
857 * n_targets: Number of of entries in targets
860 *************************************************************/
863 gtk_drag_dest_set (GtkWidget *widget,
864 GtkDestDefaults flags,
865 const GtkTargetEntry *targets,
867 GdkDragAction actions)
869 GtkDragDestSite *site;
871 g_return_if_fail (widget != NULL);
873 site = g_new (GtkDragDestSite, 1);
876 site->have_drag = FALSE;
878 site->target_list = gtk_target_list_new (targets, n_targets);
880 site->target_list = NULL;
882 site->actions = actions;
883 site->do_proxy = FALSE;
885 gtk_drag_dest_set_internal (widget, site);
888 /*************************************************************
889 * gtk_drag_dest_set_proxy:
890 * Set up this widget to proxy drags elsewhere.
893 * proxy_window: window to which forward drag events
894 * protocol: Drag protocol which the dest widget accepts
895 * use_coordinates: If true, send the same coordinates to the
896 * destination, because it is a embedded
899 *************************************************************/
902 gtk_drag_dest_set_proxy (GtkWidget *widget,
903 GdkWindow *proxy_window,
904 GdkDragProtocol protocol,
905 gboolean use_coordinates)
907 GtkDragDestSite *site;
909 g_return_if_fail (widget != NULL);
911 site = g_new (GtkDragDestSite, 1);
914 site->have_drag = FALSE;
915 site->target_list = NULL;
917 site->proxy_window = proxy_window;
919 gdk_window_ref (proxy_window);
920 site->do_proxy = TRUE;
921 site->proxy_protocol = protocol;
922 site->proxy_coords = use_coordinates;
924 gtk_drag_dest_set_internal (widget, site);
927 /*************************************************************
928 * gtk_drag_dest_unset
929 * Unregister this widget as a drag target.
933 *************************************************************/
936 gtk_drag_dest_unset (GtkWidget *widget)
938 g_return_if_fail (widget != NULL);
940 gtk_object_set_data (GTK_OBJECT (widget), "gtk-drag-dest", NULL);
944 * gtk_drag_dest_get_target_list:
945 * @widget: a #GtkWidget
947 * Returns the list of targets this widget can accept from
950 * Return value: the #GtkTargetList, or %NULL if none
953 gtk_drag_dest_get_target_list (GtkWidget *widget)
955 GtkDragDestSite *site;
957 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
959 return site ? site->target_list : NULL;
963 * gtk_drag_dest_set_target_list:
964 * @widget: a #GtkWidget that's a drag destination
965 * @target_list: list of droppable targets, or %NULL for none
967 * Sets the target types that this widget can accept from drag-and-drop.
968 * The widget must first be made into a drag destination with
969 * gtk_drag_dest_set().
972 gtk_drag_dest_set_target_list (GtkWidget *widget,
973 GtkTargetList *target_list)
975 GtkDragDestSite *site;
977 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
981 g_warning ("can't set a target list on a widget until you've called gtk_drag_dest_set() to make the widget into a drag destination");
986 gtk_target_list_ref (site->target_list);
988 if (site->target_list)
989 gtk_target_list_unref (site->target_list);
991 site->target_list = target_list;
995 /*************************************************************
996 * gtk_drag_dest_handle_event:
997 * Called from widget event handling code on Drag events
1001 * toplevel: Toplevel widget that received the event
1004 *************************************************************/
1007 gtk_drag_dest_handle_event (GtkWidget *toplevel,
1010 GtkDragDestInfo *info;
1011 GdkDragContext *context;
1013 g_return_if_fail (toplevel != NULL);
1014 g_return_if_fail (event != NULL);
1016 context = event->dnd.context;
1018 info = gtk_drag_get_dest_info (context, TRUE);
1020 /* Find the widget for the event */
1021 switch (event->type)
1023 case GDK_DRAG_ENTER:
1026 case GDK_DRAG_LEAVE:
1029 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1030 info->widget = NULL;
1034 case GDK_DRAG_MOTION:
1035 case GDK_DROP_START:
1037 GtkDragFindData data;
1040 if (event->type == GDK_DROP_START)
1042 info->dropped = TRUE;
1043 /* We send a leave here so that the widget unhighlights
1048 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1049 info->widget = NULL;
1053 gdk_window_get_origin (toplevel->window, &tx, &ty);
1055 data.x = event->dnd.x_root - tx;
1056 data.y = event->dnd.y_root - ty;
1057 data.context = context;
1060 data.toplevel = TRUE;
1061 data.callback = (event->type == GDK_DRAG_MOTION) ?
1062 gtk_drag_dest_motion : gtk_drag_dest_drop;
1063 data.time = event->dnd.time;
1065 gtk_drag_find_widget (toplevel, &data);
1067 if (info->widget && !data.found)
1069 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1070 info->widget = NULL;
1075 if (event->type == GDK_DRAG_MOTION)
1078 gdk_drag_status (context, 0, event->dnd.time);
1080 else if (event->type == GDK_DROP_START && !info->proxy_source)
1082 gdk_drop_reply (context, data.found, event->dnd.time);
1083 if ((context->protocol == GDK_DRAG_PROTO_MOTIF) && !data.found)
1084 gtk_drag_finish (context, FALSE, FALSE, event->dnd.time);
1090 g_assert_not_reached ();
1095 * gtk_drag_dest_find_target:
1096 * @widget: drag destination widget
1097 * @context: drag context
1098 * @dest_target_list: list of droppable targets
1100 * Looks for a match between @context->targets and the
1101 * @dest_target_list, returning the first matching target, otherwise
1102 * returning %GDK_NONE. @dest_target_list should usually be the return
1103 * value from gtk_drag_dest_get_target_list(), but some widgets may
1104 * have different valid targets for different parts of the widget; in
1105 * that case, they will have to implement a drag_motion handler that
1106 * passes the correct target list to this function.
1108 * Return value: first target that the source offers and the dest can accept, or %GDK_NONE
1111 gtk_drag_dest_find_target (GtkWidget *widget,
1112 GdkDragContext *context,
1113 GtkTargetList *dest_target_list)
1116 GList *tmp_source = NULL;
1117 GtkWidget *source_widget = gtk_drag_get_source_widget (context);
1119 if (dest_target_list == NULL)
1122 tmp_target = dest_target_list->list;
1125 GtkTargetPair *pair = tmp_target->data;
1126 tmp_source = context->targets;
1129 if (tmp_source->data == GUINT_TO_POINTER (pair->target))
1131 if ((!(pair->flags & GTK_TARGET_SAME_APP) || source_widget) &&
1132 (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget)))
1133 return pair->target;
1137 tmp_source = tmp_source->next;
1139 tmp_target = tmp_target->next;
1146 gtk_drag_selection_received (GtkWidget *widget,
1147 GtkSelectionData *selection_data,
1151 GdkDragContext *context;
1152 GtkDragDestInfo *info;
1153 GtkWidget *drop_widget;
1157 context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
1158 info = gtk_drag_get_dest_info (context, FALSE);
1160 if (info->proxy_data &&
1161 info->proxy_data->target == selection_data->target)
1163 gtk_selection_data_set (info->proxy_data,
1164 selection_data->type,
1165 selection_data->format,
1166 selection_data->data,
1167 selection_data->length);
1172 if (selection_data->target == gdk_atom_intern ("DELETE", FALSE))
1174 gtk_drag_finish (context, TRUE, FALSE, time);
1176 else if ((selection_data->target == gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE)) ||
1177 (selection_data->target == gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE)))
1183 GtkDragDestSite *site;
1185 site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest");
1187 if (site && site->target_list)
1191 if (gtk_target_list_find (site->target_list,
1192 selection_data->target,
1195 if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
1196 selection_data->length >= 0)
1197 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1198 "drag_data_received",
1199 context, info->drop_x, info->drop_y,
1206 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
1207 "drag_data_received",
1208 context, info->drop_x, info->drop_y,
1209 selection_data, 0, time);
1212 if (site && site->flags & GTK_DEST_DEFAULT_DROP)
1215 gtk_drag_finish (context,
1216 (selection_data->length >= 0),
1217 (context->action == GDK_ACTION_MOVE),
1221 gtk_widget_unref (drop_widget);
1224 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
1225 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
1228 gtk_object_set_data (GTK_OBJECT (widget), "drag-context", NULL);
1229 gdk_drag_context_unref (context);
1231 gtk_drag_release_ipc_widget (widget);
1234 /*************************************************************
1235 * gtk_drag_find_widget:
1236 * Recursive callback used to locate widgets for
1237 * DRAG_MOTION and DROP_START events.
1241 *************************************************************/
1244 gtk_drag_find_widget (GtkWidget *widget,
1245 GtkDragFindData *data)
1247 GtkAllocation new_allocation;
1251 new_allocation = widget->allocation;
1253 if (data->found || !GTK_WIDGET_MAPPED (widget))
1256 /* Note that in the following code, we only count the
1257 * position as being inside a WINDOW widget if it is inside
1258 * widget->window; points that are outside of widget->window
1259 * but within the allocation are not counted. This is consistent
1260 * with the way we highlight drag targets.
1262 if (!GTK_WIDGET_NO_WINDOW (widget))
1264 new_allocation.x = 0;
1265 new_allocation.y = 0;
1270 GdkWindow *window = widget->window;
1271 while (window != widget->parent->window)
1273 gint tx, ty, twidth, theight;
1274 gdk_window_get_size (window, &twidth, &theight);
1276 if (new_allocation.x < 0)
1278 new_allocation.width += new_allocation.x;
1279 new_allocation.x = 0;
1281 if (new_allocation.y < 0)
1283 new_allocation.height += new_allocation.y;
1284 new_allocation.y = 0;
1286 if (new_allocation.x + new_allocation.width > twidth)
1287 new_allocation.width = twidth - new_allocation.x;
1288 if (new_allocation.y + new_allocation.height > theight)
1289 new_allocation.height = theight - new_allocation.y;
1291 gdk_window_get_position (window, &tx, &ty);
1292 new_allocation.x += tx;
1294 new_allocation.y += ty;
1297 window = gdk_window_get_parent (window);
1301 if (data->toplevel ||
1302 ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
1303 (data->x < new_allocation.x + new_allocation.width) &&
1304 (data->y < new_allocation.y + new_allocation.height)))
1306 /* First, check if the drag is in a valid drop site in
1307 * one of our children
1309 if (GTK_IS_CONTAINER (widget))
1311 GtkDragFindData new_data = *data;
1313 new_data.x -= x_offset;
1314 new_data.y -= y_offset;
1315 new_data.found = FALSE;
1316 new_data.toplevel = FALSE;
1318 gtk_container_forall (GTK_CONTAINER (widget),
1319 (GtkCallback)gtk_drag_find_widget,
1322 data->found = new_data.found;
1325 /* If not, and this widget is registered as a drop site, check to
1326 * emit "drag_motion" to check if we are actually in
1330 gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"))
1332 data->found = data->callback (widget,
1334 data->x - new_allocation.x,
1335 data->y - new_allocation.y,
1337 /* If so, send a "drag_leave" to the last widget */
1340 if (data->info->widget && data->info->widget != widget)
1342 gtk_drag_dest_leave (data->info->widget, data->context, data->time);
1344 data->info->widget = widget;
1351 gtk_drag_proxy_begin (GtkWidget *widget,
1352 GtkDragDestInfo *dest_info,
1355 GtkDragSourceInfo *source_info;
1357 GdkDragContext *context;
1358 GtkWidget *ipc_widget;
1360 if (dest_info->proxy_source)
1362 gdk_drag_abort (dest_info->proxy_source->context, time);
1363 gtk_drag_source_info_destroy (dest_info->proxy_source);
1364 dest_info->proxy_source = NULL;
1367 ipc_widget = gtk_drag_get_ipc_widget ();
1368 context = gdk_drag_begin (ipc_widget->window,
1369 dest_info->context->targets);
1371 source_info = gtk_drag_get_source_info (context, TRUE);
1373 source_info->ipc_widget = ipc_widget;
1374 source_info->widget = gtk_widget_ref (widget);
1376 source_info->target_list = gtk_target_list_new (NULL, 0);
1377 tmp_list = dest_info->context->targets;
1380 gtk_target_list_add (source_info->target_list,
1381 GPOINTER_TO_UINT (tmp_list->data), 0, 0);
1382 tmp_list = tmp_list->next;
1385 source_info->proxy_dest = dest_info;
1387 gtk_signal_connect (GTK_OBJECT (ipc_widget),
1389 GTK_SIGNAL_FUNC (gtk_drag_selection_get),
1392 dest_info->proxy_source = source_info;
1396 gtk_drag_dest_info_destroy (gpointer data)
1398 GtkDragDestInfo *info = data;
1403 static GtkDragDestInfo *
1404 gtk_drag_get_dest_info (GdkDragContext *context,
1407 GtkDragDestInfo *info;
1408 static GQuark info_quark = 0;
1410 info_quark = g_quark_from_static_string ("gtk-dest-info");
1412 info = g_object_get_qdata (G_OBJECT (context), info_quark);
1413 if (!info && create)
1415 info = g_new (GtkDragDestInfo, 1);
1416 info->widget = NULL;
1417 info->context = context;
1418 info->proxy_source = NULL;
1419 info->proxy_data = NULL;
1420 info->dropped = FALSE;
1421 info->proxy_drop_wait = FALSE;
1422 g_object_set_qdata_full (G_OBJECT (context), info_quark,
1423 info, gtk_drag_dest_info_destroy);
1429 static GQuark dest_info_quark = 0;
1431 static GtkDragSourceInfo *
1432 gtk_drag_get_source_info (GdkDragContext *context,
1435 GtkDragSourceInfo *info;
1436 if (!dest_info_quark)
1437 dest_info_quark = g_quark_from_static_string ("gtk-source-info");
1439 info = g_object_get_qdata (G_OBJECT (context), dest_info_quark);
1440 if (!info && create)
1442 info = g_new0 (GtkDragSourceInfo, 1);
1443 info->context = context;
1444 g_object_set_qdata (G_OBJECT (context), dest_info_quark, info);
1451 gtk_drag_clear_source_info (GdkDragContext *context)
1453 g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL);
1457 gtk_drag_dest_realized (GtkWidget *widget)
1459 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1460 gdk_window_register_dnd (toplevel->window);
1464 gtk_drag_dest_site_destroy (gpointer data)
1466 GtkDragDestSite *site = data;
1468 if (site->target_list)
1469 gtk_target_list_unref (site->target_list);
1475 * Default drag handlers
1478 gtk_drag_dest_leave (GtkWidget *widget,
1479 GdkDragContext *context,
1482 GtkDragDestSite *site;
1484 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1485 g_return_if_fail (site != NULL);
1489 GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
1491 if (info->proxy_source && info->proxy_source->widget == widget && !info->dropped)
1493 gdk_drag_abort (info->proxy_source->context, time);
1494 gtk_drag_source_info_destroy (info->proxy_source);
1495 info->proxy_source = NULL;
1502 if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag)
1503 gtk_drag_unhighlight (widget);
1505 if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag)
1506 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_leave",
1509 site->have_drag = FALSE;
1514 gtk_drag_dest_motion (GtkWidget *widget,
1515 GdkDragContext *context,
1520 GtkDragDestSite *site;
1521 GdkDragAction action = 0;
1524 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1525 g_return_val_if_fail (site != NULL, FALSE);
1530 GdkEvent *current_event;
1531 GdkWindow *dest_window;
1532 GdkDragProtocol proto;
1534 GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
1536 if (!info->proxy_source || info->proxy_source->widget != widget)
1537 gtk_drag_proxy_begin (widget, info, time);
1539 current_event = gtk_get_current_event ();
1541 if (site->proxy_window)
1543 dest_window = site->proxy_window;
1544 proto = site->proxy_protocol;
1548 gdk_drag_find_window (info->proxy_source->context,
1550 current_event->dnd.x_root,
1551 current_event->dnd.y_root,
1552 &dest_window, &proto);
1555 gdk_drag_motion (info->proxy_source->context,
1557 current_event->dnd.x_root,
1558 current_event->dnd.y_root,
1559 context->suggested_action,
1560 context->actions, time);
1562 if (!site->proxy_window && dest_window)
1563 gdk_window_unref (dest_window);
1565 selection = gdk_drag_get_selection (info->proxy_source->context);
1567 selection != gdk_drag_get_selection (info->context))
1568 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1570 gdk_event_free (current_event);
1575 if (site->flags & GTK_DEST_DEFAULT_MOTION)
1577 if (context->suggested_action & site->actions)
1578 action = context->suggested_action;
1585 if ((site->actions & (1 << i)) &&
1586 (context->actions & (1 << i)))
1594 if (action && gtk_drag_dest_find_target (widget, context, site->target_list))
1596 if (!site->have_drag)
1598 site->have_drag = TRUE;
1599 if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1600 gtk_drag_highlight (widget);
1603 gdk_drag_status (context, action, time);
1607 gdk_drag_status (context, 0, time);
1612 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_motion",
1613 context, x, y, time, &retval);
1615 return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1619 gtk_drag_dest_drop (GtkWidget *widget,
1620 GdkDragContext *context,
1625 GtkDragDestSite *site;
1626 GtkDragDestInfo *info;
1628 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1629 g_return_val_if_fail (site != NULL, FALSE);
1631 info = gtk_drag_get_dest_info (context, FALSE);
1632 g_return_val_if_fail (info != NULL, FALSE);
1639 if (info->proxy_source ||
1640 (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN))
1642 gtk_drag_drop (info->proxy_source, time);
1646 /* We need to synthesize a motion event, wait for a status,
1647 * and, if we get a good one, do a drop.
1650 GdkEvent *current_event;
1652 GdkWindow *dest_window;
1653 GdkDragProtocol proto;
1655 gtk_drag_proxy_begin (widget, info, time);
1656 info->proxy_drop_wait = TRUE;
1657 info->proxy_drop_time = time;
1659 current_event = gtk_get_current_event ();
1661 if (site->proxy_window)
1663 dest_window = site->proxy_window;
1664 proto = site->proxy_protocol;
1668 gdk_drag_find_window (info->proxy_source->context,
1670 current_event->dnd.x_root,
1671 current_event->dnd.y_root,
1672 &dest_window, &proto);
1675 gdk_drag_motion (info->proxy_source->context,
1677 current_event->dnd.x_root,
1678 current_event->dnd.y_root,
1679 context->suggested_action,
1680 context->actions, time);
1682 if (!site->proxy_window && dest_window)
1683 gdk_window_unref (dest_window);
1685 selection = gdk_drag_get_selection (info->proxy_source->context);
1687 selection != gdk_drag_get_selection (info->context))
1688 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1690 gdk_event_free (current_event);
1699 if (site->flags & GTK_DEST_DEFAULT_DROP)
1701 GdkAtom target = gtk_drag_dest_find_target (widget, context, site->target_list);
1703 if (target == GDK_NONE)
1706 gtk_drag_get_data (widget, context, target, time);
1709 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_drop",
1710 context, x, y, time, &retval);
1712 return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
1720 /*************************************************************
1721 * gtk_drag_begin: Start a drag operation
1724 * widget: Widget from which drag starts
1725 * handlers: List of handlers to supply the data for the drag
1726 * button: Button user used to start drag
1727 * time: Time of event starting drag
1730 *************************************************************/
1733 gtk_drag_begin (GtkWidget *widget,
1734 GtkTargetList *target_list,
1735 GdkDragAction actions,
1739 GtkDragSourceInfo *info;
1740 GList *targets = NULL;
1742 guint32 time = GDK_CURRENT_TIME;
1743 GdkDragAction possible_actions, suggested_action;
1744 GdkDragContext *context;
1745 GtkWidget *ipc_widget;
1747 g_return_val_if_fail (widget != NULL, NULL);
1748 g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
1749 g_return_val_if_fail (target_list != NULL, NULL);
1752 time = gdk_event_get_time (event);
1754 tmp_list = g_list_last (target_list->list);
1757 GtkTargetPair *pair = tmp_list->data;
1758 targets = g_list_prepend (targets,
1759 GINT_TO_POINTER (pair->target));
1760 tmp_list = tmp_list->prev;
1763 ipc_widget = gtk_drag_get_ipc_widget ();
1764 source_widgets = g_slist_prepend (source_widgets, ipc_widget);
1766 context = gdk_drag_begin (ipc_widget->window, targets);
1767 g_list_free (targets);
1769 info = gtk_drag_get_source_info (context, TRUE);
1771 info->ipc_widget = ipc_widget;
1772 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
1774 info->widget = gtk_widget_ref (widget);
1777 info->button = button;
1778 info->target_list = target_list;
1779 gtk_target_list_ref (target_list);
1781 info->possible_actions = actions;
1783 info->cursor = NULL;
1784 info->status = GTK_DRAG_STATUS_DRAG;
1785 info->last_event = NULL;
1786 info->selections = NULL;
1787 info->icon_window = NULL;
1788 info->destroy_icon = FALSE;
1790 gtk_drag_get_event_actions (event, info->button, actions,
1791 &suggested_action, &possible_actions);
1793 info->cursor = gtk_drag_get_cursor (suggested_action);
1795 /* Set cur_x, cur_y here so if the "drag_begin" signal shows
1796 * the drag icon, it will be in the right place
1798 if (event && event->type == GDK_MOTION_NOTIFY)
1800 info->cur_x = event->motion.x_root;
1801 info->cur_y = event->motion.y_root;
1806 gdk_window_get_pointer (GDK_ROOT_PARENT (), &x, &y, NULL);
1812 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
1815 if (event && event->type == GDK_MOTION_NOTIFY)
1816 gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
1818 info->start_x = info->cur_x;
1819 info->start_y = info->cur_y;
1821 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "button_release_event",
1822 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info);
1823 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "motion_notify_event",
1824 GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info);
1825 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_press_event",
1826 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1827 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_release_event",
1828 GTK_SIGNAL_FUNC (gtk_drag_key_cb), info);
1829 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "selection_get",
1830 GTK_SIGNAL_FUNC (gtk_drag_selection_get), info);
1832 /* We use a GTK grab here to override any grabs that the widget
1833 * we are dragging from might have held
1835 gtk_grab_add (info->ipc_widget);
1836 if (gdk_pointer_grab (info->ipc_widget->window, FALSE,
1837 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1838 GDK_BUTTON_RELEASE_MASK, NULL,
1839 info->cursor, time) == 0)
1841 if (gdk_keyboard_grab (info->ipc_widget->window, FALSE, time) != 0)
1843 /* FIXME: This should be cleaned up... */
1847 ev.type = GDK_BUTTON_RELEASE;
1848 ev.button = info->button;
1850 gtk_drag_button_release_cb (widget, &ev, info);
1856 return info->context;
1859 /*************************************************************
1860 * gtk_drag_source_set:
1861 * Register a drop site, and possibly add default behaviors.
1864 * start_button_mask: Mask of allowed buttons to start drag
1865 * targets: Table of targets for this source
1867 * actions: Actions allowed for this source
1869 *************************************************************/
1872 gtk_drag_source_set (GtkWidget *widget,
1873 GdkModifierType start_button_mask,
1874 const GtkTargetEntry *targets,
1876 GdkDragAction actions)
1878 GtkDragSourceSite *site;
1880 g_return_if_fail (widget != NULL);
1882 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1884 gtk_widget_add_events (widget,
1885 gtk_widget_get_events (widget) |
1886 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1887 GDK_BUTTON_MOTION_MASK);
1891 if (site->target_list)
1892 gtk_target_list_unref (site->target_list);
1896 site = g_new0 (GtkDragSourceSite, 1);
1898 gtk_signal_connect (GTK_OBJECT (widget), "button_press_event",
1899 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1901 gtk_signal_connect (GTK_OBJECT (widget), "motion_notify_event",
1902 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1905 gtk_object_set_data_full (GTK_OBJECT (widget),
1907 site, gtk_drag_source_site_destroy);
1910 site->start_button_mask = start_button_mask;
1913 site->target_list = gtk_target_list_new (targets, n_targets);
1915 site->target_list = NULL;
1917 site->actions = actions;
1921 /*************************************************************
1922 * gtk_drag_source_unset
1923 * Unregister this widget as a drag source.
1927 *************************************************************/
1930 gtk_drag_source_unset (GtkWidget *widget)
1932 GtkDragSourceSite *site;
1934 g_return_if_fail (widget != NULL);
1936 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1940 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
1941 gtk_object_set_data (GTK_OBJECT (widget), "gtk-site-data", NULL);
1945 /*************************************************************
1946 * gtk_drag_source_set_icon:
1947 * Set an icon for drags from this source.
1949 * colormap: Colormap for this icon
1953 *************************************************************/
1956 gtk_drag_source_set_icon (GtkWidget *widget,
1957 GdkColormap *colormap,
1961 GtkDragSourceSite *site;
1963 g_return_if_fail (widget != NULL);
1965 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1966 g_return_if_fail (site != NULL);
1969 gdk_colormap_unref (site->colormap);
1971 gdk_pixmap_unref (site->pixmap);
1973 gdk_pixmap_unref (site->mask);
1975 site->colormap = colormap;
1977 gdk_colormap_ref (colormap);
1979 site->pixmap = pixmap;
1981 gdk_pixmap_ref (pixmap);
1985 gdk_pixmap_ref (mask);
1988 /*************************************************************
1989 * gtk_drag_set_icon_window:
1990 * Set a widget as the icon for a drag.
1997 *************************************************************/
2000 gtk_drag_set_icon_window (GdkDragContext *context,
2004 gboolean destroy_on_release)
2006 GtkDragSourceInfo *info;
2008 g_return_if_fail (context != NULL);
2009 g_return_if_fail (widget != NULL);
2011 info = gtk_drag_get_source_info (context, FALSE);
2012 gtk_drag_remove_icon (info);
2014 info->icon_window = widget;
2015 info->hot_x = hot_x;
2016 info->hot_y = hot_y;
2020 gtk_widget_set_uposition (widget,
2021 info->cur_x - info->hot_x,
2022 info->cur_y - info->hot_y);
2023 gtk_widget_ref (widget);
2024 gdk_window_raise (widget->window);
2025 gtk_widget_show (widget);
2028 info->destroy_icon = destroy_on_release;
2031 /*************************************************************
2032 * gtk_drag_set_icon_widget:
2033 * Set a widget as the icon for a drag.
2040 *************************************************************/
2043 gtk_drag_set_icon_widget (GdkDragContext *context,
2048 g_return_if_fail (context != NULL);
2049 g_return_if_fail (widget != NULL);
2051 gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE);
2054 /*************************************************************
2055 * gtk_drag_set_icon_pixmap:
2056 * Set a widget as the icon for a drag.
2059 * colormap: Colormap for the icon window.
2065 *************************************************************/
2068 gtk_drag_set_icon_pixmap (GdkDragContext *context,
2069 GdkColormap *colormap,
2078 g_return_if_fail (context != NULL);
2079 g_return_if_fail (colormap != NULL);
2080 g_return_if_fail (pixmap != NULL);
2082 gdk_window_get_size (pixmap, &width, &height);
2084 gtk_widget_push_colormap (colormap);
2086 window = gtk_window_new (GTK_WINDOW_POPUP);
2087 gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
2088 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
2090 gtk_widget_pop_colormap ();
2092 gtk_widget_set_usize (window, width, height);
2093 gtk_widget_realize (window);
2095 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
2098 gtk_widget_shape_combine_mask (window, mask, 0, 0);
2100 gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
2103 /*************************************************************
2104 * gtk_drag_set_icon_default:
2105 * Set the icon for a drag to the default icon.
2109 *************************************************************/
2112 gtk_drag_set_icon_default (GdkDragContext *context)
2114 g_return_if_fail (context != NULL);
2116 if (!default_icon_pixmap)
2118 default_icon_colormap = gdk_colormap_get_system ();
2119 default_icon_pixmap =
2120 gdk_pixmap_colormap_create_from_xpm_d (NULL,
2121 default_icon_colormap,
2123 NULL, (gchar **)drag_default_xpm);
2124 default_icon_hot_x = -2;
2125 default_icon_hot_y = -2;
2128 gtk_drag_set_icon_pixmap (context,
2129 default_icon_colormap,
2130 default_icon_pixmap,
2133 default_icon_hot_y);
2136 /*************************************************************
2137 * gtk_drag_set_default_icon:
2138 * Set a default icon for all drags as a pixmap.
2140 * colormap: Colormap for the icon window.
2146 *************************************************************/
2149 gtk_drag_set_default_icon (GdkColormap *colormap,
2155 g_return_if_fail (colormap != NULL);
2156 g_return_if_fail (pixmap != NULL);
2158 if (default_icon_colormap)
2159 gdk_colormap_unref (default_icon_colormap);
2160 if (default_icon_pixmap)
2161 gdk_pixmap_unref (default_icon_pixmap);
2162 if (default_icon_mask)
2163 gdk_pixmap_unref (default_icon_mask);
2165 default_icon_colormap = colormap;
2166 gdk_colormap_ref (colormap);
2168 default_icon_pixmap = pixmap;
2169 gdk_pixmap_ref (pixmap);
2171 default_icon_mask = mask;
2173 gdk_pixmap_ref (mask);
2175 default_icon_hot_x = hot_x;
2176 default_icon_hot_y = hot_y;
2180 /*************************************************************
2181 * gtk_drag_source_handle_event:
2182 * Called from widget event handling code on Drag events
2186 * toplevel: Toplevel widget that received the event
2189 *************************************************************/
2192 gtk_drag_source_handle_event (GtkWidget *widget,
2195 GtkDragSourceInfo *info;
2196 GdkDragContext *context;
2198 g_return_if_fail (widget != NULL);
2199 g_return_if_fail (event != NULL);
2201 context = event->dnd.context;
2202 info = gtk_drag_get_source_info (context, FALSE);
2206 switch (event->type)
2208 case GDK_DRAG_STATUS:
2212 if (info->proxy_dest)
2214 if (!event->dnd.send_event)
2216 if (info->proxy_dest->proxy_drop_wait)
2218 gboolean result = context->action != 0;
2220 /* Aha - we can finally pass the MOTIF DROP on... */
2221 gdk_drop_reply (info->proxy_dest->context, result, info->proxy_dest->proxy_drop_time);
2223 gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
2225 gtk_drag_finish (info->proxy_dest->context, FALSE, FALSE, info->proxy_dest->proxy_drop_time);
2229 gdk_drag_status (info->proxy_dest->context,
2230 event->dnd.context->action,
2237 cursor = gtk_drag_get_cursor (event->dnd.context->action);
2238 if (info->cursor != cursor)
2240 #ifdef GDK_WINDOWING_X11
2241 XChangeActivePointerGrab (GDK_WINDOW_XDISPLAY (widget->window),
2242 PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask,
2243 ((GdkCursorPrivate *)cursor)->xcursor,
2245 #elif defined (GDK_WINDOWING_WIN32)
2246 gdk_pointer_grab (widget->window, FALSE,
2247 GDK_POINTER_MOTION_MASK |
2248 GDK_POINTER_MOTION_HINT_MASK |
2249 GDK_BUTTON_RELEASE_MASK,
2251 info->cursor, event->dnd.time);
2253 info->cursor = cursor;
2256 if (info->last_event)
2258 gtk_drag_update (info,
2259 info->cur_x, info->cur_y,
2261 info->last_event = NULL;
2267 case GDK_DROP_FINISHED:
2268 gtk_drag_drop_finished (info, TRUE, event->dnd.time);
2271 g_assert_not_reached ();
2275 /*************************************************************
2276 * gtk_drag_source_check_selection:
2277 * Check if we've set up handlers/claimed the selection
2278 * for a given drag. If not, add them.
2282 *************************************************************/
2285 gtk_drag_source_check_selection (GtkDragSourceInfo *info,
2291 tmp_list = info->selections;
2294 if (GPOINTER_TO_UINT (tmp_list->data) == selection)
2296 tmp_list = tmp_list->next;
2299 gtk_selection_owner_set (info->ipc_widget, selection, time);
2300 info->selections = g_list_prepend (info->selections,
2301 GUINT_TO_POINTER (selection));
2303 tmp_list = info->target_list->list;
2306 GtkTargetPair *pair = tmp_list->data;
2308 gtk_selection_add_target (info->ipc_widget,
2312 tmp_list = tmp_list->next;
2315 if (info->context->protocol == GDK_DRAG_PROTO_MOTIF)
2317 gtk_selection_add_target (info->ipc_widget,
2319 gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE),
2320 TARGET_MOTIF_SUCCESS);
2321 gtk_selection_add_target (info->ipc_widget,
2323 gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE),
2324 TARGET_MOTIF_FAILURE);
2327 gtk_selection_add_target (info->ipc_widget,
2329 gdk_atom_intern ("DELETE", FALSE),
2333 /*************************************************************
2334 * gtk_drag_drop_finished:
2335 * Clean up from the drag, and display snapback, if necessary.
2341 *************************************************************/
2344 gtk_drag_drop_finished (GtkDragSourceInfo *info,
2348 gtk_drag_source_release_selections (info, time);
2350 if (info->proxy_dest)
2352 /* The time from the event isn't reliable for Xdnd drags */
2353 gtk_drag_finish (info->proxy_dest->context, success, FALSE,
2354 info->proxy_dest->proxy_drop_time);
2355 gtk_drag_source_info_destroy (info);
2361 gtk_drag_source_info_destroy (info);
2365 GtkDragAnim *anim = g_new (GtkDragAnim, 1);
2369 anim->n_steps = MAX (info->cur_x - info->start_x,
2370 info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
2371 anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
2372 if (info->icon_window)
2374 gtk_widget_show (info->icon_window);
2375 gdk_window_raise (info->icon_window->window);
2378 /* Mark the context as dead, so if the destination decides
2379 * to respond really late, we still are OK.
2381 gtk_drag_clear_source_info (info->context);
2382 gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
2388 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
2391 GList *tmp_list = info->selections;
2394 GdkAtom selection = GPOINTER_TO_UINT (tmp_list->data);
2395 if (gdk_selection_owner_get (selection) == info->ipc_widget->window)
2396 gtk_selection_owner_set (NULL, selection, time);
2397 tmp_list = tmp_list->next;
2400 g_list_free (info->selections);
2401 info->selections = NULL;
2404 /*************************************************************
2406 * Send a drop event.
2410 *************************************************************/
2413 gtk_drag_drop (GtkDragSourceInfo *info,
2416 if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN)
2418 GtkSelectionData selection_data;
2420 GdkAtom target = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
2422 tmp_list = info->target_list->list;
2425 GtkTargetPair *pair = tmp_list->data;
2427 if (pair->target == target)
2429 selection_data.selection = GDK_NONE;
2430 selection_data.target = target;
2431 selection_data.data = NULL;
2432 selection_data.length = -1;
2434 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2435 info->context, &selection_data,
2439 /* FIXME: Should we check for length >= 0 here? */
2440 gtk_drag_drop_finished (info, TRUE, time);
2443 tmp_list = tmp_list->next;
2445 gtk_drag_drop_finished (info, FALSE, time);
2449 if (info->icon_window)
2450 gtk_widget_hide (info->icon_window);
2452 gdk_drag_drop (info->context, time);
2453 info->drop_timeout = gtk_timeout_add (DROP_ABORT_TIME,
2454 gtk_drag_abort_timeout,
2460 * Source side callbacks.
2464 gtk_drag_source_event_cb (GtkWidget *widget,
2468 GtkDragSourceSite *site;
2469 gboolean retval = FALSE;
2470 site = (GtkDragSourceSite *)data;
2472 switch (event->type)
2474 case GDK_BUTTON_PRESS:
2475 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2477 site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1));
2478 site->x = event->button.x;
2479 site->y = event->button.y;
2484 case GDK_BUTTON_RELEASE:
2485 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2487 site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
2492 case GDK_MOTION_NOTIFY:
2493 if (site->state & event->motion.state & site->start_button_mask)
2495 /* FIXME: This is really broken and can leave us
2501 if (site->state & event->motion.state &
2502 GDK_BUTTON1_MASK << (i - 1))
2506 if (gtk_drag_check_threshold (widget, site->x, site->y,
2507 event->motion.x, event->motion.y))
2509 GtkDragSourceInfo *info;
2510 GdkDragContext *context;
2513 context = gtk_drag_begin (widget, site->target_list,
2517 info = gtk_drag_get_source_info (context, FALSE);
2519 if (!info->icon_window)
2522 gtk_drag_set_icon_pixmap (context,
2525 site->mask, -2, -2);
2527 gtk_drag_set_icon_default (context);
2535 default: /* hit for 2/3BUTTON_PRESS */
2543 gtk_drag_source_site_destroy (gpointer data)
2545 GtkDragSourceSite *site = data;
2547 if (site->target_list)
2548 gtk_target_list_unref (site->target_list);
2551 gdk_pixmap_unref (site->pixmap);
2554 gdk_pixmap_unref (site->mask);
2560 gtk_drag_selection_get (GtkWidget *widget,
2561 GtkSelectionData *selection_data,
2566 GtkDragSourceInfo *info = data;
2567 static GdkAtom null_atom = GDK_NONE;
2571 null_atom = gdk_atom_intern ("NULL", FALSE);
2576 gtk_signal_emit_by_name (GTK_OBJECT (info->widget),
2579 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2581 case TARGET_MOTIF_SUCCESS:
2582 gtk_drag_drop_finished (info, TRUE, time);
2583 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2585 case TARGET_MOTIF_FAILURE:
2586 gtk_drag_drop_finished (info, FALSE, time);
2587 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2590 if (info->proxy_dest)
2592 /* This is sort of dangerous and needs to be thought
2595 info->proxy_dest->proxy_data = selection_data;
2596 gtk_drag_get_data (info->widget,
2597 info->proxy_dest->context,
2598 selection_data->target,
2601 info->proxy_dest->proxy_data = NULL;
2605 if (gtk_target_list_find (info->target_list,
2606 selection_data->target,
2609 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2621 gtk_drag_anim_timeout (gpointer data)
2623 GtkDragAnim *anim = data;
2627 GDK_THREADS_ENTER ();
2629 if (anim->step == anim->n_steps)
2631 gtk_drag_source_info_destroy (anim->info);
2638 x = (anim->info->start_x * (anim->step + 1) +
2639 anim->info->cur_x * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2640 y = (anim->info->start_y * (anim->step + 1) +
2641 anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2642 if (anim->info->icon_window)
2643 gtk_widget_set_uposition (anim->info->icon_window,
2644 x - anim->info->hot_x,
2645 y - anim->info->hot_y);
2652 GDK_THREADS_LEAVE ();
2658 gtk_drag_remove_icon (GtkDragSourceInfo *info)
2660 if (info->icon_window)
2662 gtk_widget_hide (info->icon_window);
2663 if (info->destroy_icon)
2664 gtk_widget_destroy (info->icon_window);
2666 gtk_widget_unref (info->icon_window);
2667 info->icon_window = NULL;
2672 gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
2674 gtk_drag_remove_icon (info);
2676 if (!info->proxy_dest)
2677 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end",
2681 gtk_widget_unref (info->widget);
2683 gtk_signal_disconnect_by_data (GTK_OBJECT (info->ipc_widget), info);
2684 gtk_selection_remove_all (info->ipc_widget);
2685 gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", NULL);
2686 source_widgets = g_slist_remove (source_widgets, info->ipc_widget);
2687 gtk_drag_release_ipc_widget (info->ipc_widget);
2689 gtk_target_list_unref (info->target_list);
2691 gtk_drag_clear_source_info (info->context);
2692 gdk_drag_context_unref (info->context);
2694 if (info->drop_timeout)
2695 gtk_timeout_remove (info->drop_timeout);
2700 /*************************************************************
2702 * Function to update the status of the drag when the
2703 * cursor moves or the modifier changes
2705 * info: DragSourceInfo for the drag
2706 * x_root, y_root: position of darg
2707 * event: The event that triggered this call
2709 *************************************************************/
2712 gtk_drag_update (GtkDragSourceInfo *info,
2717 GdkDragAction action;
2718 GdkDragAction possible_actions;
2719 GdkWindow *window = NULL;
2720 GdkWindow *dest_window;
2721 GdkDragProtocol protocol;
2723 guint32 time = gtk_drag_get_event_time (event);
2725 gtk_drag_get_event_actions (event,
2727 info->possible_actions,
2728 &action, &possible_actions);
2729 info->cur_x = x_root;
2730 info->cur_y = y_root;
2732 if (info->icon_window)
2734 gdk_window_raise (info->icon_window->window);
2735 gtk_widget_set_uposition (info->icon_window,
2736 info->cur_x - info->hot_x,
2737 info->cur_y - info->hot_y);
2738 window = info->icon_window->window;
2741 gdk_drag_find_window (info->context,
2742 window, x_root, y_root,
2743 &dest_window, &protocol);
2745 if (gdk_drag_motion (info->context, dest_window, protocol,
2746 x_root, y_root, action,
2750 if (info->last_event != event) /* Paranoia, should not happen */
2752 if (info->last_event)
2753 gdk_event_free ((GdkEvent *)info->last_event);
2754 info->last_event = gdk_event_copy ((GdkEvent *)event);
2759 if (info->last_event)
2761 gdk_event_free ((GdkEvent *)info->last_event);
2762 info->last_event = NULL;
2767 gdk_window_unref (dest_window);
2769 selection = gdk_drag_get_selection (info->context);
2771 gtk_drag_source_check_selection (info, selection, time);
2774 /*************************************************************
2776 * Called when the user finishes to drag, either by
2777 * releasing the mouse, or by pressing Esc.
2779 * widget: GtkInvisible widget for this drag
2782 *************************************************************/
2785 gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
2787 GdkEvent send_event;
2788 GtkWidget *source_widget = info->widget;
2790 gdk_pointer_ungrab (time);
2791 gdk_keyboard_ungrab (time);
2793 gtk_grab_remove (info->ipc_widget);
2795 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2796 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
2798 gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget),
2799 GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
2802 /* Send on a release pair to the the original
2803 * widget to convince it to release its grab. We need to
2804 * call gtk_propagate_event() here, instead of
2805 * gtk_widget_event() because widget like GtkList may
2806 * expect propagation.
2809 send_event.button.type = GDK_BUTTON_RELEASE;
2810 send_event.button.window = GDK_ROOT_PARENT ();
2811 send_event.button.send_event = TRUE;
2812 send_event.button.time = time;
2813 send_event.button.x = 0;
2814 send_event.button.y = 0;
2815 send_event.button.axes = NULL;
2816 send_event.button.state = 0;
2817 send_event.button.button = info->button;
2818 send_event.button.device = gdk_core_pointer;
2819 send_event.button.x_root = 0;
2820 send_event.button.y_root = 0;
2822 gtk_propagate_event (source_widget, &send_event);
2825 /*************************************************************
2826 * gtk_drag_motion_cb:
2827 * "motion_notify_event" callback during drag.
2831 *************************************************************/
2834 gtk_drag_motion_cb (GtkWidget *widget,
2835 GdkEventMotion *event,
2838 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2839 gint x_root, y_root;
2843 gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL);
2844 event->x_root = x_root;
2845 event->y_root = y_root;
2848 gtk_drag_update (info, event->x_root, event->y_root, (GdkEvent *)event);
2853 /*************************************************************
2855 * "key_press/release_event" callback during drag.
2859 *************************************************************/
2862 gtk_drag_key_cb (GtkWidget *widget,
2866 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2867 GdkModifierType state;
2869 if (event->type == GDK_KEY_PRESS)
2871 if (event->keyval == GDK_Escape)
2873 gtk_drag_end (info, event->time);
2874 gdk_drag_abort (info->context, event->time);
2875 gtk_drag_drop_finished (info, FALSE, event->time);
2881 /* Now send a "motion" so that the modifier state is updated */
2883 /* The state is not yet updated in the event, so we need
2884 * to query it here. We could use XGetModifierMapping, but
2885 * that would be overkill.
2887 gdk_window_get_pointer (GDK_ROOT_PARENT(), NULL, NULL, &state);
2889 event->state = state;
2890 gtk_drag_update (info, info->cur_x, info->cur_y, (GdkEvent *)event);
2895 /*************************************************************
2896 * gtk_drag_button_release_cb:
2897 * "button_release_event" callback during drag.
2901 *************************************************************/
2904 gtk_drag_button_release_cb (GtkWidget *widget,
2905 GdkEventButton *event,
2908 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2910 if (event->button != info->button)
2913 gtk_drag_end (info, event->time);
2915 if ((info->context->action != 0) && (info->context->dest_window != NULL))
2917 gtk_drag_drop (info, event->time);
2921 gdk_drag_abort (info->context, event->time);
2922 gtk_drag_drop_finished (info, FALSE, event->time);
2929 gtk_drag_abort_timeout (gpointer data)
2931 GtkDragSourceInfo *info = data;
2932 guint32 time = GDK_CURRENT_TIME;
2934 GDK_THREADS_ENTER ();
2936 if (info->proxy_dest)
2937 time = info->proxy_dest->proxy_drop_time;
2939 info->drop_timeout = 0;
2940 gtk_drag_drop_finished (info, FALSE, time);
2942 GDK_THREADS_LEAVE ();
2948 * gtk_drag_check_threshold:
2949 * @widget: a #GtkWidget
2950 * @start_x: X coordinate of start of drag
2951 * @start_y: Y coordinate of start of drag
2952 * @current_x: current X coordinate
2953 * @current_y: current Y coordinate
2955 * Checks to see if a mouse drag starting at (start_x, start_y) and ending
2956 * at (current_x, current_y) has passed the GTK drag threshhold, and thus
2957 * should trigger the beginning of a drag-and-drop operation.
2959 * Return Value: If the drag threshold has been passed.
2962 gtk_drag_check_threshold (GtkWidget *widget,
2968 #define DRAG_THRESHOLD 8
2970 return (ABS (current_x - start_x) > DRAG_THRESHOLD ||
2971 ABS (current_y - start_y) > DRAG_THRESHOLD);