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/.
29 #include "gdkconfig.h"
31 #include "gdk/gdkkeysyms.h"
35 #include "gtkinvisible.h"
39 #include "gtkwindow.h"
41 static GSList *source_widgets = NULL;
43 typedef struct _GtkDragSourceSite GtkDragSourceSite;
44 typedef struct _GtkDragSourceInfo GtkDragSourceInfo;
45 typedef struct _GtkDragDestSite GtkDragDestSite;
46 typedef struct _GtkDragDestInfo GtkDragDestInfo;
47 typedef struct _GtkDragAnim GtkDragAnim;
48 typedef struct _GtkDragFindData GtkDragFindData;
58 struct _GtkDragSourceSite
60 GdkModifierType start_button_mask;
61 GtkTargetList *target_list; /* Targets for drag data */
62 GdkDragAction actions; /* Possible actions */
65 GtkImageType icon_type;
68 GtkImagePixmapData pixmap;
69 GtkImagePixbufData pixbuf;
70 GtkImageStockData stock;
74 GdkColormap *colormap; /* Colormap for drag icon */
76 /* Stored button press information to detect drag beginning */
81 struct _GtkDragSourceInfo
84 GtkTargetList *target_list; /* Targets for drag data */
85 GdkDragAction possible_actions; /* Actions allowed by source */
86 GdkDragContext *context; /* drag context */
87 GtkWidget *icon_window; /* Window for drag */
88 GtkWidget *fallback_icon; /* Window for drag used on other screens */
89 GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */
90 GdkCursor *cursor; /* Cursor for drag */
91 gint hot_x, hot_y; /* Hot spot for drag */
92 gint button; /* mouse button starting drag */
94 GtkDragStatus status; /* drag status */
95 GdkEvent *last_event; /* pending event */
97 gint start_x, start_y; /* Initial position */
98 gint cur_x, cur_y; /* Current Position */
99 GdkScreen *cur_screen; /* Current screen for pointer */
101 guint32 grab_time; /* timestamp for initial grab */
102 GList *selections; /* selections we've claimed */
104 GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */
106 guint update_idle; /* Idle function to update the drag */
107 guint drop_timeout; /* Timeout for aborting drop */
108 guint destroy_icon : 1; /* If true, destroy icon_window
110 guint have_grab : 1; /* Do we still have the pointer grab
114 struct _GtkDragDestSite
116 GtkDestDefaults flags;
117 GtkTargetList *target_list;
118 GdkDragAction actions;
119 GdkWindow *proxy_window;
120 GdkDragProtocol proxy_protocol;
122 guint proxy_coords : 1;
126 struct _GtkDragDestInfo
128 GtkWidget *widget; /* Widget in which drag is in */
129 GdkDragContext *context; /* Drag context */
130 GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */
131 GtkSelectionData *proxy_data; /* Set while retrieving proxied data */
132 guint dropped : 1; /* Set after we receive a drop */
133 guint32 proxy_drop_time; /* Timestamp for proxied drop */
134 guint proxy_drop_wait : 1; /* Set if we are waiting for a
135 * status reply before sending
138 gint drop_x, drop_y; /* Position of drop */
141 #define DROP_ABORT_TIME 300000
143 #define ANIM_STEP_TIME 50
144 #define ANIM_STEP_LENGTH 50
145 #define ANIM_MIN_STEPS 5
146 #define ANIM_MAX_STEPS 10
150 GtkDragSourceInfo *info;
155 struct _GtkDragFindData
159 GdkDragContext *context;
160 GtkDragDestInfo *info;
163 gboolean (*callback) (GtkWidget *widget, GdkDragContext *context,
164 gint x, gint y, guint32 time);
168 /* Enumeration for some targets we handle internally */
171 TARGET_MOTIF_SUCCESS = 0x40000000,
172 TARGET_MOTIF_FAILURE,
178 static GdkPixmap *default_icon_pixmap = NULL;
179 static GdkPixmap *default_icon_mask = NULL;
180 static GdkColormap *default_icon_colormap = NULL;
181 static gint default_icon_hot_x;
182 static gint default_icon_hot_y;
184 /* Forward declarations */
185 static void gtk_drag_get_event_actions (GdkEvent *event,
187 GdkDragAction actions,
188 GdkDragAction *suggested_action,
189 GdkDragAction *possible_actions);
190 static GdkCursor * gtk_drag_get_cursor (GdkDisplay *display,
191 GdkDragAction action);
192 static GtkWidget *gtk_drag_get_ipc_widget (GdkScreen *screen);
193 static void gtk_drag_release_ipc_widget (GtkWidget *widget);
195 static gboolean gtk_drag_highlight_expose (GtkWidget *widget,
196 GdkEventExpose *event,
199 static void gtk_drag_selection_received (GtkWidget *widget,
200 GtkSelectionData *selection_data,
203 static void gtk_drag_find_widget (GtkWidget *widget,
204 GtkDragFindData *data);
205 static void gtk_drag_proxy_begin (GtkWidget *widget,
206 GtkDragDestInfo *dest_info,
208 static void gtk_drag_dest_realized (GtkWidget *widget);
209 static void gtk_drag_dest_hierarchy_changed (GtkWidget *widget,
210 GtkWidget *previous_toplevel);
211 static void gtk_drag_dest_site_destroy (gpointer data);
212 static void gtk_drag_dest_leave (GtkWidget *widget,
213 GdkDragContext *context,
215 static gboolean gtk_drag_dest_motion (GtkWidget *widget,
216 GdkDragContext *context,
220 static gboolean gtk_drag_dest_drop (GtkWidget *widget,
221 GdkDragContext *context,
226 static GtkDragDestInfo * gtk_drag_get_dest_info (GdkDragContext *context,
228 static GtkDragSourceInfo *gtk_drag_get_source_info (GdkDragContext *context,
230 static void gtk_drag_clear_source_info (GdkDragContext *context);
232 static void gtk_drag_source_check_selection (GtkDragSourceInfo *info,
235 static void gtk_drag_source_release_selections (GtkDragSourceInfo *info,
237 static void gtk_drag_drop (GtkDragSourceInfo *info,
239 static void gtk_drag_drop_finished (GtkDragSourceInfo *info,
242 static void gtk_drag_cancel (GtkDragSourceInfo *info,
245 static gint gtk_drag_source_event_cb (GtkWidget *widget,
248 static void gtk_drag_source_site_destroy (gpointer data);
249 static void gtk_drag_selection_get (GtkWidget *widget,
250 GtkSelectionData *selection_data,
254 static gint gtk_drag_anim_timeout (gpointer data);
255 static void gtk_drag_remove_icon (GtkDragSourceInfo *info);
256 static void gtk_drag_source_info_destroy (GtkDragSourceInfo *info);
257 static void gtk_drag_add_update_idle (GtkDragSourceInfo *info);
259 static void gtk_drag_update (GtkDragSourceInfo *info,
264 static gint gtk_drag_motion_cb (GtkWidget *widget,
265 GdkEventMotion *event,
267 static gint gtk_drag_key_cb (GtkWidget *widget,
270 static gint gtk_drag_button_release_cb (GtkWidget *widget,
271 GdkEventButton *event,
273 static gint gtk_drag_abort_timeout (gpointer data);
275 /************************
276 * Cursor and Icon data *
277 ************************/
279 #define action_ask_width 16
280 #define action_ask_height 16
281 static const guchar action_ask_bits[] = {
282 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xf8, 0xb6, 0xf7,
283 0xd6, 0xec, 0x66, 0xdb, 0x66, 0xdb, 0x96, 0xec, 0x76, 0xf7, 0x76, 0xfb,
284 0xf6, 0xfc, 0x72, 0xfb, 0x7a, 0xfb, 0xf8, 0xfc, };
286 #define action_ask_mask_width 16
287 #define action_ask_mask_height 16
288 static const guchar action_ask_mask_bits[] = {
289 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0xcf, 0x0f,
290 0xef, 0x1f, 0xff, 0x3c, 0xff, 0x3c, 0x6f, 0x1f, 0x8f, 0x0f, 0x8f, 0x07,
291 0x0f, 0x03, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x03, };
293 #define action_copy_width 16
294 #define action_copy_height 16
295 static const guchar action_copy_bits[] = {
296 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xfb, 0x76, 0xfb,
297 0x76, 0xfb, 0x06, 0x83, 0xf6, 0xbf, 0xf6, 0xbf, 0x06, 0x83, 0x76, 0xfb,
298 0x76, 0xfb, 0x72, 0xfb, 0x7a, 0xf8, 0xf8, 0xff, };
300 #define action_copy_mask_width 16
301 #define action_copy_mask_height 16
302 static const guchar action_copy_mask_bits[] = {
303 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0x8f, 0x07,
304 0x8f, 0x07, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x8f, 0x07,
305 0x8f, 0x07, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x00, };
307 #define action_move_width 16
308 #define action_move_height 16
309 static const guchar action_move_bits[] = {
310 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x96, 0xff, 0x26, 0xff,
311 0xc6, 0xf8, 0xd6, 0xe3, 0x96, 0x8f, 0xb6, 0xbf, 0x36, 0xc3, 0x76, 0xfb,
312 0x76, 0xfa, 0xf2, 0xfa, 0xfa, 0xf8, 0xf8, 0xff, };
314 #define action_move_mask_width 16
315 #define action_move_mask_height 16
316 static const guchar action_move_mask_bits[] = {
317 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x6f, 0x00, 0xff, 0x00,
318 0xff, 0x07, 0xef, 0x1f, 0xef, 0x7f, 0xcf, 0x7f, 0xcf, 0x3f, 0x8f, 0x07,
319 0x8f, 0x07, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x00, };
321 #define action_link_width 16
322 #define action_link_height 16
323 static const guchar action_link_bits[] = {
324 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x36, 0xf8, 0xd6, 0xf7,
325 0x66, 0xec, 0xa6, 0xe8, 0x26, 0xdf, 0xe6, 0xbd, 0xd6, 0xa7, 0xb6, 0xa8,
326 0xb6, 0xb1, 0x72, 0xdf, 0xfa, 0xe0, 0xf8, 0xff, };
328 #define action_link_mask_width 16
329 #define action_link_mask_height 16
330 static const guchar action_link_mask_bits[] = {
331 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xcf, 0x07, 0xef, 0x0f,
332 0xff, 0x1f, 0x7f, 0x1f, 0xff, 0x3f, 0xff, 0x7f, 0xef, 0x7f, 0xcf, 0x77,
333 0xcf, 0x7f, 0x8f, 0x3f, 0x07, 0x1f, 0x07, 0x00, };
335 #define action_none_width 16
336 #define action_none_height 16
337 static const guchar action_none_bits[] = {
338 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0xf6, 0xff, 0xf6, 0xff,
339 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff,
340 0xf6, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf8, 0xff, };
342 #define action_none_mask_width 16
343 #define action_none_mask_height 16
344 static const guchar action_none_mask_bits[] = {
345 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x0f, 0x00,
346 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00,
347 0x0f, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x07, 0x00, };
349 #define CURSOR_WIDTH 16
350 #define CURSOR_HEIGHT 16
353 GdkDragAction action;
358 { GDK_ACTION_DEFAULT, 0 },
359 { GDK_ACTION_ASK, action_ask_bits, action_ask_mask_bits, NULL },
360 { GDK_ACTION_COPY, action_copy_bits, action_copy_mask_bits, NULL },
361 { GDK_ACTION_MOVE, action_move_bits, action_move_mask_bits, NULL },
362 { GDK_ACTION_LINK, action_link_bits, action_link_mask_bits, NULL },
363 { 0 , action_none_bits, action_none_mask_bits, NULL },
366 static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[0]);
368 /*********************
369 * Utility functions *
370 *********************/
373 set_can_change_screen (GtkWidget *widget,
374 gboolean can_change_screen)
376 can_change_screen = can_change_screen != FALSE;
378 g_object_set_data (G_OBJECT (widget), "gtk-dnd-can-change-screen",
379 GUINT_TO_POINTER (can_change_screen));
383 get_can_change_screen (GtkWidget *widget)
385 return g_object_get_data (G_OBJECT (widget), "gtk-dnd-can-change-screen") != NULL;
389 /*************************************************************
390 * gtk_drag_get_ipc_widget:
391 * Return a invisible, off-screen, override-redirect
396 *************************************************************/
399 gtk_drag_get_ipc_widget (GdkScreen *screen)
402 GSList *drag_widgets = g_object_get_data (G_OBJECT (screen),
403 "gtk-dnd-ipc-widgets");
407 GSList *tmp = drag_widgets;
408 result = drag_widgets->data;
409 drag_widgets = drag_widgets->next;
410 g_object_set_data (G_OBJECT (screen),
411 "gtk-dnd-ipc-widgets",
413 g_slist_free_1 (tmp);
417 result = gtk_invisible_new_for_screen (screen);
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 GdkScreen *screen = gtk_widget_get_screen (widget);
436 GSList *drag_widgets = g_object_get_data (G_OBJECT (screen),
437 "gtk-dnd-ipc-widgets");
438 drag_widgets = g_slist_prepend (drag_widgets, widget);
439 g_object_set_data (G_OBJECT (screen),
440 "gtk-dnd-ipc-widgets",
445 gtk_drag_get_event_time (GdkEvent *event)
447 guint32 tm = GDK_CURRENT_TIME;
452 case GDK_MOTION_NOTIFY:
453 tm = event->motion.time; break;
454 case GDK_BUTTON_PRESS:
455 case GDK_2BUTTON_PRESS:
456 case GDK_3BUTTON_PRESS:
457 case GDK_BUTTON_RELEASE:
458 tm = event->button.time; break;
460 case GDK_KEY_RELEASE:
461 tm = event->key.time; break;
462 case GDK_ENTER_NOTIFY:
463 case GDK_LEAVE_NOTIFY:
464 tm = event->crossing.time; break;
465 case GDK_PROPERTY_NOTIFY:
466 tm = event->property.time; break;
467 case GDK_SELECTION_CLEAR:
468 case GDK_SELECTION_REQUEST:
469 case GDK_SELECTION_NOTIFY:
470 tm = event->selection.time; break;
471 case GDK_PROXIMITY_IN:
472 case GDK_PROXIMITY_OUT:
473 tm = event->proximity.time; break;
474 default: /* use current time */
482 gtk_drag_get_event_actions (GdkEvent *event,
484 GdkDragAction actions,
485 GdkDragAction *suggested_action,
486 GdkDragAction *possible_actions)
488 *suggested_action = 0;
489 *possible_actions = 0;
493 GdkModifierType state = 0;
497 case GDK_MOTION_NOTIFY:
498 state = event->motion.state;
500 case GDK_BUTTON_PRESS:
501 case GDK_2BUTTON_PRESS:
502 case GDK_3BUTTON_PRESS:
503 case GDK_BUTTON_RELEASE:
504 state = event->button.state;
507 case GDK_KEY_RELEASE:
508 state = event->key.state;
510 case GDK_ENTER_NOTIFY:
511 case GDK_LEAVE_NOTIFY:
512 state = event->crossing.state;
518 if ((button == 2 || button == 3) && (actions & GDK_ACTION_ASK))
520 *suggested_action = GDK_ACTION_ASK;
521 *possible_actions = actions;
523 else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
525 if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
527 if (actions & GDK_ACTION_LINK)
529 *suggested_action = GDK_ACTION_LINK;
530 *possible_actions = GDK_ACTION_LINK;
533 else if (state & GDK_CONTROL_MASK)
535 if (actions & GDK_ACTION_COPY)
537 *suggested_action = GDK_ACTION_COPY;
538 *possible_actions = GDK_ACTION_COPY;
544 if (actions & GDK_ACTION_MOVE)
546 *suggested_action = GDK_ACTION_MOVE;
547 *possible_actions = GDK_ACTION_MOVE;
554 *possible_actions = actions;
556 if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK))
557 *suggested_action = GDK_ACTION_ASK;
558 else if (actions & GDK_ACTION_COPY)
559 *suggested_action = GDK_ACTION_COPY;
560 else if (actions & GDK_ACTION_MOVE)
561 *suggested_action = GDK_ACTION_MOVE;
562 else if (actions & GDK_ACTION_LINK)
563 *suggested_action = GDK_ACTION_LINK;
568 *possible_actions = actions;
570 if (actions & GDK_ACTION_COPY)
571 *suggested_action = GDK_ACTION_COPY;
572 else if (actions & GDK_ACTION_MOVE)
573 *suggested_action = GDK_ACTION_MOVE;
574 else if (actions & GDK_ACTION_LINK)
575 *suggested_action = GDK_ACTION_LINK;
582 gtk_drag_get_cursor (GdkDisplay *display,
583 GdkDragAction action)
587 for (i = 0 ; i < n_drag_cursors - 1; i++)
588 if (drag_cursors[i].action == action)
590 if (drag_cursors[i].cursor != NULL)
592 if (display != gdk_cursor_get_display (drag_cursors[i].cursor))
594 gdk_cursor_unref (drag_cursors[i].cursor);
595 drag_cursors[i].cursor = NULL;
599 if (drag_cursors[i].cursor == NULL)
601 GdkColor bg = { 0, 0xffff, 0xffff, 0xffff };
602 GdkColor fg = { 0, 0x0000, 0x0000, 0x0000 };
603 GdkScreen *screen = gdk_display_get_default_screen (display);
604 GdkWindow *window = gdk_screen_get_root_window (screen);
607 gdk_bitmap_create_from_data (window, (gchar *)drag_cursors[i].bits, CURSOR_WIDTH, CURSOR_HEIGHT);
610 gdk_bitmap_create_from_data (window, (gchar *)drag_cursors[i].mask, CURSOR_WIDTH, CURSOR_HEIGHT);
612 drag_cursors[i].cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, 0, 0);
614 g_object_unref (pixmap);
615 g_object_unref (mask);
618 return drag_cursors[i].cursor;
621 /********************
623 ********************/
625 /*************************************************************
627 * Get the data for a drag or drop
629 * context - drag context
630 * target - format to retrieve the data in.
631 * time - timestamp of triggering event.
634 *************************************************************/
637 gtk_drag_get_data (GtkWidget *widget,
638 GdkDragContext *context,
642 GtkWidget *selection_widget;
644 g_return_if_fail (GTK_IS_WIDGET (widget));
645 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
646 g_return_if_fail (!context->is_source);
648 selection_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
650 g_object_ref (context);
651 g_object_ref (widget);
653 g_signal_connect (selection_widget, "selection_received",
654 G_CALLBACK (gtk_drag_selection_received), widget);
656 g_object_set_data (G_OBJECT (selection_widget), "drag-context", context);
658 gtk_selection_convert (selection_widget,
659 gdk_drag_get_selection (context),
665 /*************************************************************
666 * gtk_drag_get_source_widget:
667 * Get the widget the was the source of this drag, if
668 * the drag originated from this application.
670 * context: The drag context for this drag
672 * The source widget, or NULL if the drag originated from
673 * a different application.
674 *************************************************************/
677 gtk_drag_get_source_widget (GdkDragContext *context)
681 g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), NULL);
682 g_return_val_if_fail (!context->is_source, NULL);
684 tmp_list = source_widgets;
687 GtkWidget *ipc_widget = tmp_list->data;
689 if (ipc_widget->window == context->source_window)
691 GtkDragSourceInfo *info;
692 info = g_object_get_data (G_OBJECT (ipc_widget), "gtk-info");
694 return info ? info->widget : NULL;
697 tmp_list = tmp_list->next;
703 /*************************************************************
705 * Notify the drag source that the transfer of data
708 * context: The drag context for this drag
709 * success: Was the data successfully transferred?
710 * time: The timestamp to use when notifying the destination.
712 *************************************************************/
715 gtk_drag_finish (GdkDragContext *context,
720 GdkAtom target = GDK_NONE;
722 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
723 g_return_if_fail (!context->is_source);
727 target = gdk_atom_intern ("DELETE", FALSE);
729 else if (context->protocol == GDK_DRAG_PROTO_MOTIF)
731 target = gdk_atom_intern (success ?
732 "XmTRANSFER_SUCCESS" :
733 "XmTRANSFER_FAILURE",
737 if (target != GDK_NONE)
739 GtkWidget *selection_widget = gtk_drag_get_ipc_widget (gdk_drawable_get_screen (context->source_window));
741 g_object_ref (context);
743 g_object_set_data (G_OBJECT (selection_widget), "drag-context", context);
744 g_signal_connect (selection_widget, "selection_received",
745 G_CALLBACK (gtk_drag_selection_received),
748 gtk_selection_convert (selection_widget,
749 gdk_drag_get_selection (context),
754 if (!(success && del))
755 gdk_drop_finish (context, success, time);
758 /*************************************************************
759 * gtk_drag_highlight_expose:
760 * Callback for expose_event for highlighted widgets.
766 *************************************************************/
769 gtk_drag_highlight_expose (GtkWidget *widget,
770 GdkEventExpose *event,
773 gint x, y, width, height;
775 if (GTK_WIDGET_DRAWABLE (widget))
777 if (GTK_WIDGET_NO_WINDOW (widget))
779 x = widget->allocation.x;
780 y = widget->allocation.y;
781 width = widget->allocation.width;
782 height = widget->allocation.height;
788 gdk_drawable_get_size (widget->window, &width, &height);
791 gtk_paint_shadow (widget->style, widget->window,
792 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
794 x, y, width, height);
796 gdk_draw_rectangle (widget->window,
797 widget->style->black_gc,
799 x, y, width - 1, height - 1);
805 /*************************************************************
806 * gtk_drag_highlight:
807 * Highlight the given widget in the default manner.
811 *************************************************************/
814 gtk_drag_highlight (GtkWidget *widget)
816 g_return_if_fail (GTK_IS_WIDGET (widget));
818 g_signal_connect_after (widget, "expose_event",
819 G_CALLBACK (gtk_drag_highlight_expose),
822 gtk_widget_queue_draw (widget);
825 /*************************************************************
826 * gtk_drag_unhighlight:
827 * Refresh the given widget to remove the highlight.
831 *************************************************************/
834 gtk_drag_unhighlight (GtkWidget *widget)
836 g_return_if_fail (GTK_IS_WIDGET (widget));
838 g_signal_handlers_disconnect_by_func (widget,
839 gtk_drag_highlight_expose,
842 gtk_widget_queue_draw (widget);
846 gtk_drag_dest_set_internal (GtkWidget *widget,
847 GtkDragDestSite *site)
849 GtkDragDestSite *old_site;
851 g_return_if_fail (widget != NULL);
853 /* HACK, do this in the destroy */
854 old_site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
857 g_signal_handlers_disconnect_by_func (widget,
858 gtk_drag_dest_realized,
860 g_signal_handlers_disconnect_by_func (widget,
861 gtk_drag_dest_hierarchy_changed,
865 if (GTK_WIDGET_REALIZED (widget))
866 gtk_drag_dest_realized (widget);
868 g_signal_connect (widget, "realize",
869 G_CALLBACK (gtk_drag_dest_realized), site);
870 g_signal_connect (widget, "hierarchy_changed",
871 G_CALLBACK (gtk_drag_dest_hierarchy_changed), site);
873 g_object_set_data_full (G_OBJECT (widget), "gtk-drag-dest",
874 site, gtk_drag_dest_site_destroy);
878 /*************************************************************
880 * Register a drop site, and possibly add default behaviors.
883 * flags: Which types of default drag behavior to use
884 * targets: Table of targets that can be accepted
885 * n_targets: Number of of entries in targets
888 *************************************************************/
891 gtk_drag_dest_set (GtkWidget *widget,
892 GtkDestDefaults flags,
893 const GtkTargetEntry *targets,
895 GdkDragAction actions)
897 GtkDragDestSite *site;
899 g_return_if_fail (GTK_IS_WIDGET (widget));
901 site = g_new (GtkDragDestSite, 1);
904 site->have_drag = FALSE;
906 site->target_list = gtk_target_list_new (targets, n_targets);
908 site->target_list = NULL;
909 site->actions = actions;
910 site->do_proxy = FALSE;
911 site->proxy_window = NULL;
913 gtk_drag_dest_set_internal (widget, site);
916 /*************************************************************
917 * gtk_drag_dest_set_proxy:
918 * Set up this widget to proxy drags elsewhere.
921 * proxy_window: window to which forward drag events
922 * protocol: Drag protocol which the dest widget accepts
923 * use_coordinates: If true, send the same coordinates to the
924 * destination, because it is a embedded
927 *************************************************************/
930 gtk_drag_dest_set_proxy (GtkWidget *widget,
931 GdkWindow *proxy_window,
932 GdkDragProtocol protocol,
933 gboolean use_coordinates)
935 GtkDragDestSite *site;
937 g_return_if_fail (GTK_IS_WIDGET (widget));
938 g_return_if_fail (!proxy_window || GDK_IS_WINDOW (proxy_window));
940 site = g_new (GtkDragDestSite, 1);
943 site->have_drag = FALSE;
944 site->target_list = NULL;
946 site->proxy_window = proxy_window;
948 g_object_ref (proxy_window);
949 site->do_proxy = TRUE;
950 site->proxy_protocol = protocol;
951 site->proxy_coords = use_coordinates;
953 gtk_drag_dest_set_internal (widget, site);
956 /*************************************************************
957 * gtk_drag_dest_unset
958 * Unregister this widget as a drag target.
962 *************************************************************/
965 gtk_drag_dest_unset (GtkWidget *widget)
967 g_return_if_fail (GTK_IS_WIDGET (widget));
969 g_object_set_data (G_OBJECT (widget), "gtk-drag-dest", NULL);
973 * gtk_drag_dest_get_target_list:
974 * @widget: a #GtkWidget
976 * Returns the list of targets this widget can accept from
979 * Return value: the #GtkTargetList, or %NULL if none
982 gtk_drag_dest_get_target_list (GtkWidget *widget)
984 GtkDragDestSite *site;
986 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
988 site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
990 return site ? site->target_list : NULL;
994 * gtk_drag_dest_set_target_list:
995 * @widget: a #GtkWidget that's a drag destination
996 * @target_list: list of droppable targets, or %NULL for none
998 * Sets the target types that this widget can accept from drag-and-drop.
999 * The widget must first be made into a drag destination with
1000 * gtk_drag_dest_set().
1003 gtk_drag_dest_set_target_list (GtkWidget *widget,
1004 GtkTargetList *target_list)
1006 GtkDragDestSite *site;
1008 g_return_if_fail (GTK_IS_WIDGET (widget));
1010 site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
1014 g_warning ("Can't set a target list on a widget until you've called gtk_drag_dest_set() "
1015 "to make the widget into a drag destination");
1020 gtk_target_list_ref (target_list);
1022 if (site->target_list)
1023 gtk_target_list_unref (site->target_list);
1025 site->target_list = target_list;
1029 * gtk_drag_dest_add_text_targets:
1030 * @widget: a #GtkWidget that's a drag destination
1032 * Add the text targets supported by #GtkSelection to
1033 * the target list of the drag destination. The targets
1034 * are added with @info = 0. If you need another value,
1035 * use gtk_target_list_add_text_targets() and
1036 * gtk_drag_dest_set_target_list().
1041 gtk_drag_dest_add_text_targets (GtkWidget *widget)
1043 GtkTargetList *target_list;
1045 target_list = gtk_drag_dest_get_target_list (widget);
1047 gtk_target_list_ref (target_list);
1049 target_list = gtk_target_list_new (NULL, 0);
1050 gtk_target_list_add_text_targets (target_list, 0);
1051 gtk_drag_dest_set_target_list (widget, target_list);
1052 gtk_target_list_unref (target_list);
1056 * gtk_drag_dest_add_image_targets:
1057 * @widget: a #GtkWidget that's a drag destination
1059 * Add the image targets supported by #GtkSelection to
1060 * the target list of the drag destination. The targets
1061 * are added with @info = 0. If you need another value,
1062 * use gtk_target_list_add_image_targets() and
1063 * gtk_drag_dest_set_target_list().
1068 gtk_drag_dest_add_image_targets (GtkWidget *widget)
1070 GtkTargetList *target_list;
1072 target_list = gtk_drag_dest_get_target_list (widget);
1074 gtk_target_list_ref (target_list);
1076 target_list = gtk_target_list_new (NULL, 0);
1077 gtk_target_list_add_image_targets (target_list, 0, FALSE);
1078 gtk_drag_dest_set_target_list (widget, target_list);
1079 gtk_target_list_unref (target_list);
1082 /*************************************************************
1083 * _gtk_drag_dest_handle_event:
1084 * Called from widget event handling code on Drag events
1088 * toplevel: Toplevel widget that received the event
1091 *************************************************************/
1094 _gtk_drag_dest_handle_event (GtkWidget *toplevel,
1097 GtkDragDestInfo *info;
1098 GdkDragContext *context;
1100 g_return_if_fail (toplevel != NULL);
1101 g_return_if_fail (event != NULL);
1103 context = event->dnd.context;
1105 info = gtk_drag_get_dest_info (context, TRUE);
1107 /* Find the widget for the event */
1108 switch (event->type)
1110 case GDK_DRAG_ENTER:
1113 case GDK_DRAG_LEAVE:
1116 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1117 info->widget = NULL;
1121 case GDK_DRAG_MOTION:
1122 case GDK_DROP_START:
1124 GtkDragFindData data;
1127 if (event->type == GDK_DROP_START)
1129 info->dropped = TRUE;
1130 /* We send a leave here so that the widget unhighlights
1135 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1136 info->widget = NULL;
1140 #ifdef GDK_WINDOWING_X11
1141 /* Hackaround for: http://bugzilla.gnome.org/show_bug.cgi?id=136112
1143 * Currently gdk_window_get_position doesn't provide reliable
1144 * information for embedded windows, so we call the much more
1145 * expensive gdk_window_get_origin().
1147 if (GTK_IS_PLUG (toplevel))
1148 gdk_window_get_origin (toplevel->window, &tx, &ty);
1150 #endif /* GDK_WINDOWING_X11 */
1151 gdk_window_get_position (toplevel->window, &tx, &ty);
1153 data.x = event->dnd.x_root - tx;
1154 data.y = event->dnd.y_root - ty;
1155 data.context = context;
1158 data.toplevel = TRUE;
1159 data.callback = (event->type == GDK_DRAG_MOTION) ?
1160 gtk_drag_dest_motion : gtk_drag_dest_drop;
1161 data.time = event->dnd.time;
1163 gtk_drag_find_widget (toplevel, &data);
1165 if (info->widget && !data.found)
1167 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1168 info->widget = NULL;
1173 if (event->type == GDK_DRAG_MOTION)
1176 gdk_drag_status (context, 0, event->dnd.time);
1178 else if (event->type == GDK_DROP_START && !info->proxy_source)
1180 gdk_drop_reply (context, data.found, event->dnd.time);
1181 if ((context->protocol == GDK_DRAG_PROTO_MOTIF) && !data.found)
1182 gtk_drag_finish (context, FALSE, FALSE, event->dnd.time);
1188 g_assert_not_reached ();
1193 * gtk_drag_dest_find_target:
1194 * @widget: drag destination widget
1195 * @context: drag context
1196 * @target_list: list of droppable targets, or %NULL to use
1197 * gtk_drag_dest_get_target_list (@widget).
1199 * Looks for a match between @context->targets and the
1200 * @dest_target_list, returning the first matching target, otherwise
1201 * returning %GDK_NONE. @dest_target_list should usually be the return
1202 * value from gtk_drag_dest_get_target_list(), but some widgets may
1203 * have different valid targets for different parts of the widget; in
1204 * that case, they will have to implement a drag_motion handler that
1205 * passes the correct target list to this function.
1207 * Return value: first target that the source offers and the dest can accept, or %GDK_NONE
1210 gtk_drag_dest_find_target (GtkWidget *widget,
1211 GdkDragContext *context,
1212 GtkTargetList *target_list)
1215 GList *tmp_source = NULL;
1216 GtkWidget *source_widget;
1218 g_return_val_if_fail (GTK_IS_WIDGET (widget), GDK_NONE);
1219 g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), GDK_NONE);
1220 g_return_val_if_fail (!context->is_source, GDK_NONE);
1223 source_widget = gtk_drag_get_source_widget (context);
1225 if (target_list == NULL)
1226 target_list = gtk_drag_dest_get_target_list (widget);
1228 if (target_list == NULL)
1231 tmp_target = target_list->list;
1234 GtkTargetPair *pair = tmp_target->data;
1235 tmp_source = context->targets;
1238 if (tmp_source->data == GUINT_TO_POINTER (pair->target))
1240 if ((!(pair->flags & GTK_TARGET_SAME_APP) || source_widget) &&
1241 (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget)))
1242 return pair->target;
1246 tmp_source = tmp_source->next;
1248 tmp_target = tmp_target->next;
1255 gtk_drag_selection_received (GtkWidget *widget,
1256 GtkSelectionData *selection_data,
1260 GdkDragContext *context;
1261 GtkDragDestInfo *info;
1262 GtkWidget *drop_widget;
1266 context = g_object_get_data (G_OBJECT (widget), "drag-context");
1267 info = gtk_drag_get_dest_info (context, FALSE);
1269 if (info->proxy_data &&
1270 info->proxy_data->target == selection_data->target)
1272 gtk_selection_data_set (info->proxy_data,
1273 selection_data->type,
1274 selection_data->format,
1275 selection_data->data,
1276 selection_data->length);
1281 if (selection_data->target == gdk_atom_intern ("DELETE", FALSE))
1283 gtk_drag_finish (context, TRUE, FALSE, time);
1285 else if ((selection_data->target == gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE)) ||
1286 (selection_data->target == gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE)))
1292 GtkDragDestSite *site;
1294 site = g_object_get_data (G_OBJECT (drop_widget), "gtk-drag-dest");
1296 if (site && site->target_list)
1300 if (gtk_target_list_find (site->target_list,
1301 selection_data->target,
1304 if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
1305 selection_data->length >= 0)
1306 g_signal_emit_by_name (drop_widget,
1307 "drag_data_received",
1308 context, info->drop_x, info->drop_y,
1315 g_signal_emit_by_name (drop_widget,
1316 "drag_data_received",
1317 context, info->drop_x, info->drop_y,
1322 if (site && site->flags & GTK_DEST_DEFAULT_DROP)
1325 gtk_drag_finish (context,
1326 (selection_data->length >= 0),
1327 (context->action == GDK_ACTION_MOVE),
1331 g_object_unref (drop_widget);
1334 g_signal_handlers_disconnect_by_func (widget,
1335 gtk_drag_selection_received,
1338 g_object_set_data (G_OBJECT (widget), "drag-context", NULL);
1339 g_object_unref (context);
1341 gtk_drag_release_ipc_widget (widget);
1345 prepend_and_ref_widget (GtkWidget *widget,
1348 GSList **slist_p = data;
1350 *slist_p = g_slist_prepend (*slist_p, g_object_ref (widget));
1353 /*************************************************************
1354 * gtk_drag_find_widget:
1355 * Recursive callback used to locate widgets for
1356 * DRAG_MOTION and DROP_START events.
1360 *************************************************************/
1363 gtk_drag_find_widget (GtkWidget *widget,
1364 GtkDragFindData *data)
1366 GtkAllocation new_allocation;
1367 gint allocation_to_window_x = 0;
1368 gint allocation_to_window_y = 0;
1372 if (data->found || !GTK_WIDGET_MAPPED (widget) || !GTK_WIDGET_SENSITIVE (widget))
1375 /* Note that in the following code, we only count the
1376 * position as being inside a WINDOW widget if it is inside
1377 * widget->window; points that are outside of widget->window
1378 * but within the allocation are not counted. This is consistent
1379 * with the way we highlight drag targets.
1381 * data->x,y are relative to widget->parent->window (if
1382 * widget is not a toplevel, widget->window otherwise).
1383 * We compute the allocation of widget in the same coordinates,
1384 * clipping to widget->window, and all intermediate
1385 * windows. If data->x,y is inside that, then we translate
1386 * our coordinates to be relative to widget->window and
1389 new_allocation = widget->allocation;
1394 GdkWindow *window = widget->window;
1396 /* Compute the offset from allocation-relative to
1397 * window-relative coordinates.
1399 allocation_to_window_x = widget->allocation.x;
1400 allocation_to_window_y = widget->allocation.y;
1402 if (!GTK_WIDGET_NO_WINDOW (widget))
1404 /* The allocation is relative to the parent window for
1405 * window widgets, not to widget->window.
1407 gdk_window_get_position (window, &tx, &ty);
1409 allocation_to_window_x -= tx;
1410 allocation_to_window_y -= ty;
1413 new_allocation.x = 0 + allocation_to_window_x;
1414 new_allocation.y = 0 + allocation_to_window_y;
1416 while (window && window != widget->parent->window)
1418 GdkRectangle window_rect = { 0, 0, 0, 0 };
1420 gdk_drawable_get_size (window, &window_rect.width, &window_rect.height);
1422 gdk_rectangle_intersect (&new_allocation, &window_rect, &new_allocation);
1424 gdk_window_get_position (window, &tx, &ty);
1425 new_allocation.x += tx;
1427 new_allocation.y += ty;
1430 window = gdk_window_get_parent (window);
1433 if (!window) /* Window and widget heirarchies didn't match. */
1437 if (data->toplevel ||
1438 ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
1439 (data->x < new_allocation.x + new_allocation.width) &&
1440 (data->y < new_allocation.y + new_allocation.height)))
1442 /* First, check if the drag is in a valid drop site in
1443 * one of our children
1445 if (GTK_IS_CONTAINER (widget))
1447 GtkDragFindData new_data = *data;
1448 GSList *children = NULL;
1451 new_data.x -= x_offset;
1452 new_data.y -= y_offset;
1453 new_data.found = FALSE;
1454 new_data.toplevel = FALSE;
1456 /* need to reference children temporarily in case the
1457 * ::drag_motion/::drag_drop callbacks change the widget heirarchy.
1459 gtk_container_forall (GTK_CONTAINER (widget), prepend_and_ref_widget, &children);
1460 for (tmp_list = children; tmp_list; tmp_list = tmp_list->next)
1462 if (!new_data.found && GTK_WIDGET_DRAWABLE (tmp_list->data))
1463 gtk_drag_find_widget (tmp_list->data, &new_data);
1464 g_object_unref (tmp_list->data);
1466 g_slist_free (children);
1468 data->found = new_data.found;
1471 /* If not, and this widget is registered as a drop site, check to
1472 * emit "drag_motion" to check if we are actually in
1476 g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"))
1478 data->found = data->callback (widget,
1480 data->x - x_offset - allocation_to_window_x,
1481 data->y - y_offset - allocation_to_window_y,
1483 /* If so, send a "drag_leave" to the last widget */
1486 if (data->info->widget && data->info->widget != widget)
1488 gtk_drag_dest_leave (data->info->widget, data->context, data->time);
1490 data->info->widget = widget;
1497 gtk_drag_proxy_begin (GtkWidget *widget,
1498 GtkDragDestInfo *dest_info,
1501 GtkDragSourceInfo *source_info;
1503 GdkDragContext *context;
1504 GtkWidget *ipc_widget;
1506 if (dest_info->proxy_source)
1508 gdk_drag_abort (dest_info->proxy_source->context, time);
1509 gtk_drag_source_info_destroy (dest_info->proxy_source);
1510 dest_info->proxy_source = NULL;
1513 ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
1514 context = gdk_drag_begin (ipc_widget->window,
1515 dest_info->context->targets);
1517 source_info = gtk_drag_get_source_info (context, TRUE);
1519 source_info->ipc_widget = ipc_widget;
1520 source_info->widget = gtk_widget_ref (widget);
1522 source_info->target_list = gtk_target_list_new (NULL, 0);
1523 tmp_list = dest_info->context->targets;
1526 gtk_target_list_add (source_info->target_list,
1527 GDK_POINTER_TO_ATOM (tmp_list->data), 0, 0);
1528 tmp_list = tmp_list->next;
1531 source_info->proxy_dest = dest_info;
1533 g_signal_connect (ipc_widget,
1535 G_CALLBACK (gtk_drag_selection_get),
1538 dest_info->proxy_source = source_info;
1542 gtk_drag_dest_info_destroy (gpointer data)
1544 GtkDragDestInfo *info = data;
1549 static GtkDragDestInfo *
1550 gtk_drag_get_dest_info (GdkDragContext *context,
1553 GtkDragDestInfo *info;
1554 static GQuark info_quark = 0;
1556 info_quark = g_quark_from_static_string ("gtk-dest-info");
1558 info = g_object_get_qdata (G_OBJECT (context), info_quark);
1559 if (!info && create)
1561 info = g_new (GtkDragDestInfo, 1);
1562 info->widget = NULL;
1563 info->context = context;
1564 info->proxy_source = NULL;
1565 info->proxy_data = NULL;
1566 info->dropped = FALSE;
1567 info->proxy_drop_wait = FALSE;
1568 g_object_set_qdata_full (G_OBJECT (context), info_quark,
1569 info, gtk_drag_dest_info_destroy);
1575 static GQuark dest_info_quark = 0;
1577 static GtkDragSourceInfo *
1578 gtk_drag_get_source_info (GdkDragContext *context,
1581 GtkDragSourceInfo *info;
1582 if (!dest_info_quark)
1583 dest_info_quark = g_quark_from_static_string ("gtk-source-info");
1585 info = g_object_get_qdata (G_OBJECT (context), dest_info_quark);
1586 if (!info && create)
1588 info = g_new0 (GtkDragSourceInfo, 1);
1589 info->context = context;
1590 g_object_set_qdata (G_OBJECT (context), dest_info_quark, info);
1597 gtk_drag_clear_source_info (GdkDragContext *context)
1599 g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL);
1603 gtk_drag_dest_realized (GtkWidget *widget)
1605 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1607 if (GTK_WIDGET_TOPLEVEL (toplevel))
1608 gdk_window_register_dnd (toplevel->window);
1612 gtk_drag_dest_hierarchy_changed (GtkWidget *widget,
1613 GtkWidget *previous_toplevel)
1615 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1617 if (GTK_WIDGET_TOPLEVEL (toplevel) && GTK_WIDGET_REALIZED (toplevel))
1618 gdk_window_register_dnd (toplevel->window);
1622 gtk_drag_dest_site_destroy (gpointer data)
1624 GtkDragDestSite *site = data;
1626 if (site->proxy_window)
1627 g_object_unref (site->proxy_window);
1629 if (site->target_list)
1630 gtk_target_list_unref (site->target_list);
1636 * Default drag handlers
1639 gtk_drag_dest_leave (GtkWidget *widget,
1640 GdkDragContext *context,
1643 GtkDragDestSite *site;
1645 site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
1646 g_return_if_fail (site != NULL);
1650 GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
1652 if (info->proxy_source && info->proxy_source->widget == widget && !info->dropped)
1654 gdk_drag_abort (info->proxy_source->context, time);
1655 gtk_drag_source_info_destroy (info->proxy_source);
1656 info->proxy_source = NULL;
1663 if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag)
1664 gtk_drag_unhighlight (widget);
1666 if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag)
1667 g_signal_emit_by_name (widget, "drag_leave",
1670 site->have_drag = FALSE;
1675 gtk_drag_dest_motion (GtkWidget *widget,
1676 GdkDragContext *context,
1681 GtkDragDestSite *site;
1682 GdkDragAction action = 0;
1685 site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
1686 g_return_val_if_fail (site != NULL, FALSE);
1691 GdkEvent *current_event;
1692 GdkWindow *dest_window;
1693 GdkDragProtocol proto;
1695 GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
1697 if (!info->proxy_source || info->proxy_source->widget != widget)
1698 gtk_drag_proxy_begin (widget, info, time);
1700 current_event = gtk_get_current_event ();
1702 if (site->proxy_window)
1704 dest_window = site->proxy_window;
1705 proto = site->proxy_protocol;
1709 gdk_drag_find_window_for_screen (info->proxy_source->context,
1711 gdk_drawable_get_screen (current_event->dnd.window),
1712 current_event->dnd.x_root,
1713 current_event->dnd.y_root,
1714 &dest_window, &proto);
1717 gdk_drag_motion (info->proxy_source->context,
1719 current_event->dnd.x_root,
1720 current_event->dnd.y_root,
1721 context->suggested_action,
1722 context->actions, time);
1724 if (!site->proxy_window && dest_window)
1725 g_object_unref (dest_window);
1727 selection = gdk_drag_get_selection (info->proxy_source->context);
1729 selection != gdk_drag_get_selection (info->context))
1730 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1732 gdk_event_free (current_event);
1737 if (site->flags & GTK_DEST_DEFAULT_MOTION)
1739 if (context->suggested_action & site->actions)
1740 action = context->suggested_action;
1747 if ((site->actions & (1 << i)) &&
1748 (context->actions & (1 << i)))
1756 if (action && gtk_drag_dest_find_target (widget, context, NULL))
1758 if (!site->have_drag)
1760 site->have_drag = TRUE;
1761 if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1762 gtk_drag_highlight (widget);
1765 gdk_drag_status (context, action, time);
1769 gdk_drag_status (context, 0, time);
1774 g_signal_emit_by_name (widget, "drag_motion",
1775 context, x, y, time, &retval);
1777 return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1781 gtk_drag_dest_drop (GtkWidget *widget,
1782 GdkDragContext *context,
1787 GtkDragDestSite *site;
1788 GtkDragDestInfo *info;
1790 site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
1791 g_return_val_if_fail (site != NULL, FALSE);
1793 info = gtk_drag_get_dest_info (context, FALSE);
1794 g_return_val_if_fail (info != NULL, FALSE);
1801 if (info->proxy_source ||
1802 (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN))
1804 gtk_drag_drop (info->proxy_source, time);
1808 /* We need to synthesize a motion event, wait for a status,
1809 * and, if we get a good one, do a drop.
1812 GdkEvent *current_event;
1814 GdkWindow *dest_window;
1815 GdkDragProtocol proto;
1817 gtk_drag_proxy_begin (widget, info, time);
1818 info->proxy_drop_wait = TRUE;
1819 info->proxy_drop_time = time;
1821 current_event = gtk_get_current_event ();
1823 if (site->proxy_window)
1825 dest_window = site->proxy_window;
1826 proto = site->proxy_protocol;
1830 gdk_drag_find_window_for_screen (info->proxy_source->context,
1832 gdk_drawable_get_screen (current_event->dnd.window),
1833 current_event->dnd.x_root,
1834 current_event->dnd.y_root,
1835 &dest_window, &proto);
1838 gdk_drag_motion (info->proxy_source->context,
1840 current_event->dnd.x_root,
1841 current_event->dnd.y_root,
1842 context->suggested_action,
1843 context->actions, time);
1845 if (!site->proxy_window && dest_window)
1846 g_object_unref (dest_window);
1848 selection = gdk_drag_get_selection (info->proxy_source->context);
1850 selection != gdk_drag_get_selection (info->context))
1851 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1853 gdk_event_free (current_event);
1862 if (site->flags & GTK_DEST_DEFAULT_DROP)
1864 GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
1866 if (target == GDK_NONE)
1868 gtk_drag_finish (context, FALSE, FALSE, time);
1872 gtk_drag_get_data (widget, context, target, time);
1875 g_signal_emit_by_name (widget, "drag_drop",
1876 context, x, y, time, &retval);
1878 return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
1886 /* Like GtkDragBegin, but also takes a GtkDragSourceSite,
1887 * so that we can set the icon from the source site information
1889 static GdkDragContext *
1890 gtk_drag_begin_internal (GtkWidget *widget,
1891 GtkDragSourceSite *site,
1892 GtkTargetList *target_list,
1893 GdkDragAction actions,
1897 GtkDragSourceInfo *info;
1898 GList *targets = NULL;
1900 guint32 time = GDK_CURRENT_TIME;
1901 GdkDragAction possible_actions, suggested_action;
1902 GdkDragContext *context;
1903 GtkWidget *ipc_widget;
1906 ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
1908 gtk_drag_get_event_actions (event, button, actions,
1909 &suggested_action, &possible_actions);
1911 cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget), suggested_action);
1914 time = gdk_event_get_time (event);
1916 if (gdk_pointer_grab (ipc_widget->window, FALSE,
1917 GDK_POINTER_MOTION_MASK |
1918 GDK_BUTTON_RELEASE_MASK, NULL,
1921 gtk_drag_release_ipc_widget (ipc_widget);
1925 if (gdk_keyboard_grab (ipc_widget->window, FALSE, time) != 0)
1927 gtk_drag_release_ipc_widget (ipc_widget);
1931 /* We use a GTK grab here to override any grabs that the widget
1932 * we are dragging from might have held
1934 gtk_grab_add (ipc_widget);
1936 tmp_list = g_list_last (target_list->list);
1939 GtkTargetPair *pair = tmp_list->data;
1940 targets = g_list_prepend (targets,
1941 GINT_TO_POINTER (pair->target));
1942 tmp_list = tmp_list->prev;
1945 source_widgets = g_slist_prepend (source_widgets, ipc_widget);
1947 context = gdk_drag_begin (ipc_widget->window, targets);
1948 g_list_free (targets);
1950 info = gtk_drag_get_source_info (context, TRUE);
1952 info->ipc_widget = ipc_widget;
1953 g_object_set_data (G_OBJECT (info->ipc_widget), "gtk-info", info);
1955 info->widget = gtk_widget_ref (widget);
1957 info->button = button;
1958 info->cursor = cursor;
1959 info->target_list = target_list;
1960 gtk_target_list_ref (target_list);
1962 info->possible_actions = actions;
1964 info->status = GTK_DRAG_STATUS_DRAG;
1965 info->last_event = NULL;
1966 info->selections = NULL;
1967 info->icon_window = NULL;
1968 info->destroy_icon = FALSE;
1970 /* Set cur_x, cur_y here so if the "drag_begin" signal shows
1971 * the drag icon, it will be in the right place
1973 if (event && event->type == GDK_MOTION_NOTIFY)
1975 info->cur_screen = gtk_widget_get_screen (widget);
1976 info->cur_x = event->motion.x_root;
1977 info->cur_y = event->motion.y_root;
1981 gdk_display_get_pointer (gtk_widget_get_display (widget),
1982 &info->cur_screen, &info->cur_x, &info->cur_y, NULL);
1985 g_signal_emit_by_name (widget, "drag_begin",
1988 /* Ensure that we have an icon before we start the drag; the
1989 * application may have set one in ::drag_begin, or it may
1992 if (!info->icon_window)
1994 if (!site || site->icon_type == GTK_IMAGE_EMPTY)
1995 gtk_drag_set_icon_default (context);
1997 switch (site->icon_type)
1999 case GTK_IMAGE_PIXMAP:
2000 gtk_drag_set_icon_pixmap (context,
2002 site->icon_data.pixmap.pixmap,
2006 case GTK_IMAGE_PIXBUF:
2007 gtk_drag_set_icon_pixbuf (context,
2008 site->icon_data.pixbuf.pixbuf,
2011 case GTK_IMAGE_STOCK:
2012 gtk_drag_set_icon_stock (context,
2013 site->icon_data.stock.stock_id,
2016 case GTK_IMAGE_EMPTY:
2018 g_assert_not_reached();
2023 if (event && event->type == GDK_MOTION_NOTIFY)
2024 gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
2026 info->start_x = info->cur_x;
2027 info->start_y = info->cur_y;
2029 g_signal_connect (info->ipc_widget, "button_release_event",
2030 G_CALLBACK (gtk_drag_button_release_cb), info);
2031 g_signal_connect (info->ipc_widget, "motion_notify_event",
2032 G_CALLBACK (gtk_drag_motion_cb), info);
2033 g_signal_connect (info->ipc_widget, "key_press_event",
2034 G_CALLBACK (gtk_drag_key_cb), info);
2035 g_signal_connect (info->ipc_widget, "key_release_event",
2036 G_CALLBACK (gtk_drag_key_cb), info);
2037 g_signal_connect (info->ipc_widget, "selection_get",
2038 G_CALLBACK (gtk_drag_selection_get), info);
2040 info->have_grab = TRUE;
2041 info->grab_time = time;
2043 return info->context;
2048 * @widget: the source widget.
2049 * @targets: The targets (data formats) in which the
2050 * source can provide the data.
2051 * @actions: A bitmask of the allowed drag actions for this drag.
2052 * @button: The button the user clicked to start the drag.
2053 * @event: The event that triggered the start of the drag.
2055 * Initiates a drag on the source side. The function
2056 * only needs to be used when the application is
2057 * starting drags itself, and is not needed when
2058 * gtk_drag_source_set() is used.
2060 * Return value: the context for this drag.
2063 gtk_drag_begin (GtkWidget *widget,
2064 GtkTargetList *targets,
2065 GdkDragAction actions,
2069 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
2070 g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
2071 g_return_val_if_fail (targets != NULL, NULL);
2073 return gtk_drag_begin_internal (widget, NULL, targets,
2074 actions, button, event);
2077 /*************************************************************
2078 * gtk_drag_source_set:
2079 * Register a drop site, and possibly add default behaviors.
2082 * start_button_mask: Mask of allowed buttons to start drag
2083 * targets: Table of targets for this source
2085 * actions: Actions allowed for this source
2087 *************************************************************/
2090 gtk_drag_source_set (GtkWidget *widget,
2091 GdkModifierType start_button_mask,
2092 const GtkTargetEntry *targets,
2094 GdkDragAction actions)
2096 GtkDragSourceSite *site;
2098 g_return_if_fail (GTK_IS_WIDGET (widget));
2100 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2102 gtk_widget_add_events (widget,
2103 gtk_widget_get_events (widget) |
2104 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
2105 GDK_BUTTON_MOTION_MASK);
2109 if (site->target_list)
2110 gtk_target_list_unref (site->target_list);
2114 site = g_new0 (GtkDragSourceSite, 1);
2116 site->icon_type = GTK_IMAGE_EMPTY;
2118 g_signal_connect (widget, "button_press_event",
2119 G_CALLBACK (gtk_drag_source_event_cb),
2121 g_signal_connect (widget, "motion_notify_event",
2122 G_CALLBACK (gtk_drag_source_event_cb),
2125 g_object_set_data_full (G_OBJECT (widget),
2127 site, gtk_drag_source_site_destroy);
2130 site->start_button_mask = start_button_mask;
2132 site->target_list = gtk_target_list_new (targets, n_targets);
2134 site->actions = actions;
2137 /*************************************************************
2138 * gtk_drag_source_unset
2139 * Unregister this widget as a drag source.
2143 *************************************************************/
2146 gtk_drag_source_unset (GtkWidget *widget)
2148 GtkDragSourceSite *site;
2150 g_return_if_fail (GTK_IS_WIDGET (widget));
2152 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2156 g_signal_handlers_disconnect_by_func (widget,
2157 gtk_drag_source_event_cb,
2159 g_signal_handlers_disconnect_by_func (widget,
2160 gtk_drag_source_event_cb,
2162 g_object_set_data (G_OBJECT (widget), "gtk-site-data", NULL);
2167 * gtk_drag_source_get_target_list:
2168 * @widget: a #GtkWidget
2170 * Gets the list of targets this widget can provide for
2173 * Return value: the #GtkTargetList, or %NULL if none
2178 gtk_drag_source_get_target_list (GtkWidget *widget)
2180 GtkDragSourceSite *site;
2182 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
2184 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2186 return site ? site->target_list : NULL;
2190 * gtk_drag_source_set_target_list:
2191 * @widget: a #GtkWidget that's a drag source
2192 * @target_list: list of draggable targets, or %NULL for none
2194 * Changes the target types that this widget offers for drag-and-drop.
2195 * The widget must first be made into a drag source with
2196 * gtk_drag_source_set().
2201 gtk_drag_source_set_target_list (GtkWidget *widget,
2202 GtkTargetList *target_list)
2204 GtkDragSourceSite *site;
2206 g_return_if_fail (GTK_IS_WIDGET (widget));
2208 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2211 g_warning ("gtk_drag_source_set_target_list() requires the widget "
2212 "to already be a drag source.");
2217 gtk_target_list_ref (target_list);
2219 if (site->target_list)
2220 gtk_target_list_unref (site->target_list);
2222 site->target_list = target_list;
2226 * gtk_drag_source_add_text_targets:
2227 * @widget: a #GtkWidget that's is a drag source
2229 * Add the text targets supported by #GtkSelection to
2230 * the target list of the drag source. The targets
2231 * are added with @info = 0. If you need another value,
2232 * use gtk_target_list_add_text_targets() and
2233 * gtk_drag_dest_set_target_list().
2238 gtk_drag_source_add_text_targets (GtkWidget *widget)
2240 GtkTargetList *target_list;
2242 target_list = gtk_drag_source_get_target_list (widget);
2244 gtk_target_list_ref (target_list);
2246 target_list = gtk_target_list_new (NULL, 0);
2247 gtk_target_list_add_text_targets (target_list, 0);
2248 gtk_drag_source_set_target_list (widget, target_list);
2249 gtk_target_list_unref (target_list);
2253 * gtk_drag_source_add_image_targets:
2254 * @widget: a #GtkWidget that's is a drag source
2256 * Add the writable image targets supported by #GtkSelection to
2257 * the target list of the drag source. The targets
2258 * are added with @info = 0. If you need another value,
2259 * use gtk_target_list_add_text_targets() and
2260 * gtk_drag_dest_set_target_list().
2265 gtk_drag_source_add_image_targets (GtkWidget *widget)
2267 GtkTargetList *target_list;
2269 target_list = gtk_drag_source_get_target_list (widget);
2271 gtk_target_list_ref (target_list);
2273 target_list = gtk_target_list_new (NULL, 0);
2274 gtk_target_list_add_image_targets (target_list, 0, TRUE);
2275 gtk_drag_source_set_target_list (widget, target_list);
2276 gtk_target_list_unref (target_list);
2280 gtk_drag_source_unset_icon (GtkDragSourceSite *site)
2282 switch (site->icon_type)
2284 case GTK_IMAGE_EMPTY:
2286 case GTK_IMAGE_PIXMAP:
2287 if (site->icon_data.pixmap.pixmap)
2288 g_object_unref (site->icon_data.pixmap.pixmap);
2289 if (site->icon_mask)
2290 g_object_unref (site->icon_mask);
2292 case GTK_IMAGE_PIXBUF:
2293 g_object_unref (site->icon_data.pixbuf.pixbuf);
2295 case GTK_IMAGE_STOCK:
2296 g_free (site->icon_data.stock.stock_id);
2299 g_assert_not_reached();
2302 site->icon_type = GTK_IMAGE_EMPTY;
2305 g_object_unref (site->colormap);
2306 site->colormap = NULL;
2310 * gtk_drag_source_set_icon:
2311 * @widget: a #GtkWidget
2312 * @colormap: the colormap of the icon
2313 * @pixmap: the image data for the icon
2314 * @mask: the transparency mask for an image.
2316 * Sets the icon that will be used for drags from a particular widget
2317 * from a pixmap/mask. GTK+ retains references for the arguments, and
2318 * will release them when they are no longer needed.
2319 * Use gtk_drag_source_set_icon_pixbuf() instead.
2322 gtk_drag_source_set_icon (GtkWidget *widget,
2323 GdkColormap *colormap,
2327 GtkDragSourceSite *site;
2329 g_return_if_fail (GTK_IS_WIDGET (widget));
2330 g_return_if_fail (GDK_IS_COLORMAP (colormap));
2331 g_return_if_fail (GDK_IS_PIXMAP (pixmap));
2332 g_return_if_fail (!mask || GDK_IS_PIXMAP (mask));
2334 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2335 g_return_if_fail (site != NULL);
2337 g_object_ref (colormap);
2338 g_object_ref (pixmap);
2340 g_object_ref (mask);
2342 gtk_drag_source_unset_icon (site);
2344 site->icon_type = GTK_IMAGE_PIXMAP;
2346 site->icon_data.pixmap.pixmap = pixmap;
2347 site->icon_mask = mask;
2348 site->colormap = colormap;
2352 * gtk_drag_source_set_icon_pixbuf:
2353 * @widget: a #GtkWidget
2354 * @pixbuf: the #GdkPixbuf for the drag icon
2356 * Sets the icon that will be used for drags from a particular widget
2357 * from a #GdkPixbuf. GTK+ retains a reference for @pixbuf and will
2358 * release it when it is no longer needed.
2361 gtk_drag_source_set_icon_pixbuf (GtkWidget *widget,
2364 GtkDragSourceSite *site;
2366 g_return_if_fail (GTK_IS_WIDGET (widget));
2367 g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
2369 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2370 g_return_if_fail (site != NULL);
2371 g_object_ref (pixbuf);
2373 gtk_drag_source_unset_icon (site);
2375 site->icon_type = GTK_IMAGE_PIXBUF;
2376 site->icon_data.pixbuf.pixbuf = pixbuf;
2380 * gtk_drag_source_set_icon_stock:
2381 * @widget: a #GtkWidget
2382 * @stock_id: the ID of the stock icon to use
2384 * Sets the icon that will be used for drags from a particular source
2388 gtk_drag_source_set_icon_stock (GtkWidget *widget,
2389 const gchar *stock_id)
2391 GtkDragSourceSite *site;
2393 g_return_if_fail (GTK_IS_WIDGET (widget));
2394 g_return_if_fail (stock_id != NULL);
2396 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2397 g_return_if_fail (site != NULL);
2399 gtk_drag_source_unset_icon (site);
2401 site->icon_type = GTK_IMAGE_STOCK;
2402 site->icon_data.stock.stock_id = g_strdup (stock_id);
2406 gtk_drag_get_icon (GtkDragSourceInfo *info,
2407 GtkWidget **icon_window,
2411 if (get_can_change_screen (info->icon_window))
2412 gtk_window_set_screen (GTK_WINDOW (info->icon_window),
2415 if (gtk_widget_get_screen (info->icon_window) != info->cur_screen)
2417 if (!info->fallback_icon)
2419 gint save_hot_x, save_hot_y;
2420 gboolean save_destroy_icon;
2421 GtkWidget *save_icon_window;
2423 /* HACK to get the appropriate icon
2425 save_icon_window = info->icon_window;
2426 save_hot_x = info->hot_x;
2427 save_hot_y = info->hot_x;
2428 save_destroy_icon = info->destroy_icon;
2430 info->icon_window = NULL;
2431 gtk_drag_set_icon_default (info->context);
2432 info->fallback_icon = info->icon_window;
2434 info->icon_window = save_icon_window;
2435 info->hot_x = save_hot_x;
2436 info->hot_y = save_hot_y;
2437 info->destroy_icon = save_destroy_icon;
2440 gtk_widget_hide (info->icon_window);
2442 *icon_window = info->fallback_icon;
2443 gtk_window_set_screen (GTK_WINDOW (*icon_window), info->cur_screen);
2445 if (!default_icon_pixmap)
2452 *hot_x = default_icon_hot_x;
2453 *hot_y = default_icon_hot_y;
2458 if (info->fallback_icon)
2459 gtk_widget_hide (info->fallback_icon);
2461 *icon_window = info->icon_window;
2462 *hot_x = info->hot_x;
2463 *hot_y = info->hot_y;
2468 gtk_drag_update_icon (GtkDragSourceInfo *info)
2470 if (info->icon_window)
2472 GtkWidget *icon_window;
2475 gtk_drag_get_icon (info, &icon_window, &hot_x, &hot_y);
2477 gtk_window_move (GTK_WINDOW (icon_window),
2478 info->cur_x - hot_x,
2479 info->cur_y - hot_y);
2481 if (GTK_WIDGET_VISIBLE (icon_window))
2482 gdk_window_raise (icon_window->window);
2484 gtk_widget_show (icon_window);
2489 gtk_drag_set_icon_window (GdkDragContext *context,
2493 gboolean destroy_on_release)
2495 GtkDragSourceInfo *info;
2497 info = gtk_drag_get_source_info (context, FALSE);
2498 gtk_drag_remove_icon (info);
2501 gtk_widget_ref (widget);
2503 info->icon_window = widget;
2504 info->hot_x = hot_x;
2505 info->hot_y = hot_y;
2506 info->destroy_icon = destroy_on_release;
2508 gtk_drag_update_icon (info);
2512 * gtk_drag_set_icon_widget:
2513 * @context: the context for a drag. (This must be called
2514 with a context for the source side of a drag)
2515 * @widget: a toplevel window to use as an icon.
2516 * @hot_x: the X offset within @widget of the hotspot.
2517 * @hot_y: the Y offset within @widget of the hotspot.
2519 * Changes the icon for a widget to a given widget. GTK+
2520 * will not destroy the icon, so if you don't want
2521 * it to persist, you should connect to the "drag_end"
2522 * signal and destroy it yourself.
2525 gtk_drag_set_icon_widget (GdkDragContext *context,
2530 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
2531 g_return_if_fail (context->is_source);
2532 g_return_if_fail (GTK_IS_WIDGET (widget));
2534 gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE);
2538 icon_window_realize (GtkWidget *window,
2544 gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf,
2545 gtk_widget_get_colormap (window),
2546 &pixmap, &mask, 128);
2548 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
2551 gtk_widget_shape_combine_mask (window, mask, 0, 0);
2553 g_object_unref (pixmap);
2556 g_object_unref (mask);
2560 set_icon_stock_pixbuf (GdkDragContext *context,
2561 const gchar *stock_id,
2570 g_return_if_fail (context != NULL);
2571 g_return_if_fail (pixbuf != NULL || stock_id != NULL);
2572 g_return_if_fail (pixbuf == NULL || stock_id == NULL);
2574 screen = gdk_drawable_get_screen (context->source_window);
2576 /* Push a NULL colormap to guard against gtk_widget_push_colormap() */
2577 gtk_widget_push_colormap (NULL);
2578 window = gtk_window_new (GTK_WINDOW_POPUP);
2579 gtk_window_set_screen (GTK_WINDOW (window), screen);
2580 set_can_change_screen (window, TRUE);
2581 gtk_widget_pop_colormap ();
2583 gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
2584 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
2588 pixbuf = gtk_widget_render_icon (window, stock_id,
2589 GTK_ICON_SIZE_DND, NULL);
2593 g_warning ("Cannot load drag icon from stock_id %s", stock_id);
2594 gtk_widget_destroy (window);
2600 g_object_ref (pixbuf);
2602 width = gdk_pixbuf_get_width (pixbuf);
2603 height = gdk_pixbuf_get_width (pixbuf);
2605 gtk_widget_set_size_request (window,
2606 gdk_pixbuf_get_width (pixbuf),
2607 gdk_pixbuf_get_height (pixbuf));
2609 g_signal_connect_closure (window, "realize",
2610 g_cclosure_new (G_CALLBACK (icon_window_realize),
2612 (GClosureNotify)g_object_unref),
2615 gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
2619 * gtk_drag_set_icon_pixbuf:
2620 * @context: the context for a drag. (This must be called
2621 * with a context for the source side of a drag)
2622 * @pixbuf: the #GdkPixbuf to use as the drag icon.
2623 * @hot_x: the X offset within @widget of the hotspot.
2624 * @hot_y: the Y offset within @widget of the hotspot.
2626 * Sets @pixbuf as the icon for a given drag.
2629 gtk_drag_set_icon_pixbuf (GdkDragContext *context,
2634 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
2635 g_return_if_fail (context->is_source);
2636 g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
2638 set_icon_stock_pixbuf (context, NULL, pixbuf, hot_x, hot_y);
2642 * gtk_drag_set_icon_stock:
2643 * @context: the context for a drag. (This must be called
2644 * with a context for the source side of a drag)
2645 * @stock_id: the ID of the stock icon to use for the drag.
2646 * @hot_x: the X offset within the icon of the hotspot.
2647 * @hot_y: the Y offset within the icon of the hotspot.
2649 * Sets the the icon for a given drag from a stock ID.
2652 gtk_drag_set_icon_stock (GdkDragContext *context,
2653 const gchar *stock_id,
2657 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
2658 g_return_if_fail (context->is_source);
2659 g_return_if_fail (stock_id != NULL);
2661 set_icon_stock_pixbuf (context, stock_id, NULL, hot_x, hot_y);
2665 * gtk_drag_set_icon_pixmap:
2666 * @context: the context for a drag. (This must be called
2667 * with a context for the source side of a drag)
2668 * @colormap: the colormap of the icon
2669 * @pixmap: the image data for the icon
2670 * @mask: the transparency mask for the icon
2671 * @hot_x: the X offset within @pixmap of the hotspot.
2672 * @hot_y: the Y offset within @pixmap of the hotspot.
2674 * Sets @pixmap as the icon for a given drag. GTK+ retains
2675 * references for the arguments, and will release them when
2676 * they are no longer needed. In general, gtk_drag_set_icon_pixbuf()
2677 * will be more convenient to use.
2680 gtk_drag_set_icon_pixmap (GdkDragContext *context,
2681 GdkColormap *colormap,
2691 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
2692 g_return_if_fail (context->is_source);
2693 g_return_if_fail (GDK_IS_COLORMAP (colormap));
2694 g_return_if_fail (GDK_IS_PIXMAP (pixmap));
2695 g_return_if_fail (!mask || GDK_IS_PIXMAP (mask));
2697 screen = gdk_colormap_get_screen (colormap);
2699 g_return_if_fail (gdk_drawable_get_screen (pixmap) == screen);
2700 g_return_if_fail (!mask || gdk_drawable_get_screen (mask) == screen);
2702 gdk_drawable_get_size (pixmap, &width, &height);
2704 gtk_widget_push_colormap (colormap);
2706 window = gtk_window_new (GTK_WINDOW_POPUP);
2707 gtk_window_set_screen (GTK_WINDOW (window), screen);
2708 set_can_change_screen (window, FALSE);
2709 gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
2710 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
2712 gtk_widget_pop_colormap ();
2714 gtk_widget_set_size_request (window, width, height);
2715 gtk_widget_realize (window);
2717 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
2720 gtk_widget_shape_combine_mask (window, mask, 0, 0);
2722 gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
2726 * gtk_drag_set_icon_default:
2727 * @context: the context for a drag. (This must be called
2728 with a context for the source side of a drag)
2730 * Sets the icon for a particular drag to the default
2734 gtk_drag_set_icon_default (GdkDragContext *context)
2736 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
2737 g_return_if_fail (context->is_source);
2739 if (!default_icon_pixmap)
2740 gtk_drag_set_icon_stock (context, GTK_STOCK_DND, -2, -2);
2742 gtk_drag_set_icon_pixmap (context,
2743 default_icon_colormap,
2744 default_icon_pixmap,
2747 default_icon_hot_y);
2751 * gtk_drag_set_default_icon:
2752 * @colormap: the colormap of the icon
2753 * @pixmap: the image data for the icon
2754 * @mask: the transparency mask for an image.
2755 * @hot_x: The X offset within @widget of the hotspot.
2756 * @hot_y: The Y offset within @widget of the hotspot.
2758 * Changes the default drag icon. GTK+ retains references for the
2759 * arguments, and will release them when they are no longer needed.
2760 * This function is obsolete. The default icon should now be changed
2761 * via the stock system by changing the stock pixbuf for #GTK_STOCK_DND.
2764 gtk_drag_set_default_icon (GdkColormap *colormap,
2770 g_return_if_fail (GDK_IS_COLORMAP (colormap));
2771 g_return_if_fail (GDK_IS_PIXMAP (pixmap));
2772 g_return_if_fail (!mask || GDK_IS_PIXMAP (mask));
2774 if (default_icon_colormap)
2775 g_object_unref (default_icon_colormap);
2776 if (default_icon_pixmap)
2777 g_object_unref (default_icon_pixmap);
2778 if (default_icon_mask)
2779 g_object_unref (default_icon_mask);
2781 default_icon_colormap = colormap;
2782 g_object_ref (colormap);
2784 default_icon_pixmap = pixmap;
2785 g_object_ref (pixmap);
2787 default_icon_mask = mask;
2789 g_object_ref (mask);
2791 default_icon_hot_x = hot_x;
2792 default_icon_hot_y = hot_y;
2796 /*************************************************************
2797 * _gtk_drag_source_handle_event:
2798 * Called from widget event handling code on Drag events
2802 * toplevel: Toplevel widget that received the event
2805 *************************************************************/
2808 _gtk_drag_source_handle_event (GtkWidget *widget,
2811 GtkDragSourceInfo *info;
2812 GdkDragContext *context;
2814 g_return_if_fail (widget != NULL);
2815 g_return_if_fail (event != NULL);
2817 context = event->dnd.context;
2818 info = gtk_drag_get_source_info (context, FALSE);
2822 switch (event->type)
2824 case GDK_DRAG_STATUS:
2828 if (info->proxy_dest)
2830 if (!event->dnd.send_event)
2832 if (info->proxy_dest->proxy_drop_wait)
2834 gboolean result = context->action != 0;
2836 /* Aha - we can finally pass the MOTIF DROP on... */
2837 gdk_drop_reply (info->proxy_dest->context, result, info->proxy_dest->proxy_drop_time);
2839 gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
2841 gtk_drag_finish (info->proxy_dest->context, FALSE, FALSE, info->proxy_dest->proxy_drop_time);
2845 gdk_drag_status (info->proxy_dest->context,
2846 event->dnd.context->action,
2851 else if (info->have_grab)
2853 cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget),
2854 event->dnd.context->action);
2855 if (info->cursor != cursor)
2857 gdk_pointer_grab (widget->window, FALSE,
2858 GDK_POINTER_MOTION_MASK |
2859 GDK_BUTTON_RELEASE_MASK,
2861 cursor, info->grab_time);
2862 info->cursor = cursor;
2865 if (info->last_event)
2866 gtk_drag_add_update_idle (info);
2871 case GDK_DROP_FINISHED:
2872 gtk_drag_drop_finished (info, TRUE, event->dnd.time);
2875 g_assert_not_reached ();
2879 /*************************************************************
2880 * gtk_drag_source_check_selection:
2881 * Check if we've set up handlers/claimed the selection
2882 * for a given drag. If not, add them.
2886 *************************************************************/
2889 gtk_drag_source_check_selection (GtkDragSourceInfo *info,
2895 tmp_list = info->selections;
2898 if (GDK_POINTER_TO_ATOM (tmp_list->data) == selection)
2900 tmp_list = tmp_list->next;
2903 gtk_selection_owner_set_for_display (gtk_widget_get_display (info->widget),
2907 info->selections = g_list_prepend (info->selections,
2908 GUINT_TO_POINTER (selection));
2910 tmp_list = info->target_list->list;
2913 GtkTargetPair *pair = tmp_list->data;
2915 gtk_selection_add_target (info->ipc_widget,
2919 tmp_list = tmp_list->next;
2922 if (info->context->protocol == GDK_DRAG_PROTO_MOTIF)
2924 gtk_selection_add_target (info->ipc_widget,
2926 gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE),
2927 TARGET_MOTIF_SUCCESS);
2928 gtk_selection_add_target (info->ipc_widget,
2930 gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE),
2931 TARGET_MOTIF_FAILURE);
2934 gtk_selection_add_target (info->ipc_widget,
2936 gdk_atom_intern ("DELETE", FALSE),
2940 /*************************************************************
2941 * gtk_drag_drop_finished:
2942 * Clean up from the drag, and display snapback, if necessary.
2948 *************************************************************/
2951 gtk_drag_drop_finished (GtkDragSourceInfo *info,
2955 gtk_drag_source_release_selections (info, time);
2957 if (info->proxy_dest)
2959 /* The time from the event isn't reliable for Xdnd drags */
2960 gtk_drag_finish (info->proxy_dest->context, success, FALSE,
2961 info->proxy_dest->proxy_drop_time);
2962 gtk_drag_source_info_destroy (info);
2968 gtk_drag_source_info_destroy (info);
2972 GtkDragAnim *anim = g_new (GtkDragAnim, 1);
2976 anim->n_steps = MAX (info->cur_x - info->start_x,
2977 info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
2978 anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
2980 info->cur_screen = gtk_widget_get_screen (info->widget);
2981 gtk_drag_update_icon (info);
2983 /* Mark the context as dead, so if the destination decides
2984 * to respond really late, we still are OK.
2986 gtk_drag_clear_source_info (info->context);
2987 g_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
2993 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
2996 GdkDisplay *display = gtk_widget_get_display (info->widget);
2997 GList *tmp_list = info->selections;
3001 GdkAtom selection = GDK_POINTER_TO_ATOM (tmp_list->data);
3002 if (gdk_selection_owner_get_for_display (display, selection) == info->ipc_widget->window)
3003 gtk_selection_owner_set_for_display (display, NULL, selection, time);
3005 tmp_list = tmp_list->next;
3008 g_list_free (info->selections);
3009 info->selections = NULL;
3012 /*************************************************************
3014 * Send a drop event.
3018 *************************************************************/
3021 gtk_drag_drop (GtkDragSourceInfo *info,
3024 if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN)
3026 GtkSelectionData selection_data;
3028 /* GTK+ traditionally has used application/x-rootwin-drop, but the
3029 * XDND spec specifies x-rootwindow-drop.
3031 GdkAtom target1 = gdk_atom_intern ("application/x-rootwindow-drop", FALSE);
3032 GdkAtom target2 = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
3034 tmp_list = info->target_list->list;
3037 GtkTargetPair *pair = tmp_list->data;
3039 if (pair->target == target1 || pair->target == target2)
3041 selection_data.selection = GDK_NONE;
3042 selection_data.target = pair->target;
3043 selection_data.data = NULL;
3044 selection_data.length = -1;
3046 g_signal_emit_by_name (info->widget, "drag_data_get",
3047 info->context, &selection_data,
3051 /* FIXME: Should we check for length >= 0 here? */
3052 gtk_drag_drop_finished (info, TRUE, time);
3055 tmp_list = tmp_list->next;
3057 gtk_drag_drop_finished (info, FALSE, time);
3061 if (info->icon_window)
3062 gtk_widget_hide (info->icon_window);
3064 gdk_drag_drop (info->context, time);
3065 info->drop_timeout = g_timeout_add (DROP_ABORT_TIME,
3066 gtk_drag_abort_timeout,
3072 * Source side callbacks.
3076 gtk_drag_source_event_cb (GtkWidget *widget,
3080 GtkDragSourceSite *site;
3081 gboolean retval = FALSE;
3082 site = (GtkDragSourceSite *)data;
3084 switch (event->type)
3086 case GDK_BUTTON_PRESS:
3087 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
3089 site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1));
3090 site->x = event->button.x;
3091 site->y = event->button.y;
3095 case GDK_BUTTON_RELEASE:
3096 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
3097 site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
3100 case GDK_MOTION_NOTIFY:
3101 if (site->state & event->motion.state & site->start_button_mask)
3103 /* FIXME: This is really broken and can leave us
3109 if (site->state & event->motion.state &
3110 GDK_BUTTON1_MASK << (i - 1))
3114 if (gtk_drag_check_threshold (widget, site->x, site->y,
3115 event->motion.x, event->motion.y))
3117 GdkDragContext *context;
3120 context = gtk_drag_begin_internal (widget, site, site->target_list,
3129 default: /* hit for 2/3BUTTON_PRESS */
3137 gtk_drag_source_site_destroy (gpointer data)
3139 GtkDragSourceSite *site = data;
3141 if (site->target_list)
3142 gtk_target_list_unref (site->target_list);
3144 gtk_drag_source_unset_icon (site);
3149 gtk_drag_selection_get (GtkWidget *widget,
3150 GtkSelectionData *selection_data,
3155 GtkDragSourceInfo *info = data;
3156 static GdkAtom null_atom = GDK_NONE;
3160 null_atom = gdk_atom_intern ("NULL", FALSE);
3165 g_signal_emit_by_name (info->widget,
3168 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
3170 case TARGET_MOTIF_SUCCESS:
3171 gtk_drag_drop_finished (info, TRUE, time);
3172 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
3174 case TARGET_MOTIF_FAILURE:
3175 gtk_drag_drop_finished (info, FALSE, time);
3176 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
3179 if (info->proxy_dest)
3181 /* This is sort of dangerous and needs to be thought
3184 info->proxy_dest->proxy_data = selection_data;
3185 gtk_drag_get_data (info->widget,
3186 info->proxy_dest->context,
3187 selection_data->target,
3190 info->proxy_dest->proxy_data = NULL;
3194 if (gtk_target_list_find (info->target_list,
3195 selection_data->target,
3198 g_signal_emit_by_name (info->widget, "drag_data_get",
3210 gtk_drag_anim_timeout (gpointer data)
3212 GtkDragAnim *anim = data;
3216 GDK_THREADS_ENTER ();
3218 if (anim->step == anim->n_steps)
3220 gtk_drag_source_info_destroy (anim->info);
3227 x = (anim->info->start_x * (anim->step + 1) +
3228 anim->info->cur_x * (anim->n_steps - anim->step - 1)) / anim->n_steps;
3229 y = (anim->info->start_y * (anim->step + 1) +
3230 anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
3231 if (anim->info->icon_window)
3233 GtkWidget *icon_window;
3236 gtk_drag_get_icon (anim->info, &icon_window, &hot_x, &hot_y);
3238 gtk_window_move (GTK_WINDOW (icon_window),
3248 GDK_THREADS_LEAVE ();
3254 gtk_drag_remove_icon (GtkDragSourceInfo *info)
3256 if (info->icon_window)
3258 gtk_widget_hide (info->icon_window);
3259 if (info->destroy_icon)
3260 gtk_widget_destroy (info->icon_window);
3262 if (info->fallback_icon)
3264 gtk_widget_destroy (info->fallback_icon);
3265 info->fallback_icon = NULL;
3268 g_object_unref (info->icon_window);
3269 info->icon_window = NULL;
3274 gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
3276 gtk_drag_remove_icon (info);
3278 if (!info->proxy_dest)
3279 g_signal_emit_by_name (info->widget, "drag_end",
3283 g_object_unref (info->widget);
3286 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3287 gtk_drag_button_release_cb,
3289 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3292 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3295 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3296 gtk_drag_selection_get,
3299 gtk_selection_remove_all (info->ipc_widget);
3300 g_object_set_data (G_OBJECT (info->ipc_widget), "gtk-info", NULL);
3301 source_widgets = g_slist_remove (source_widgets, info->ipc_widget);
3302 gtk_drag_release_ipc_widget (info->ipc_widget);
3304 gtk_target_list_unref (info->target_list);
3306 gtk_drag_clear_source_info (info->context);
3307 g_object_unref (info->context);
3309 if (info->drop_timeout)
3310 g_source_remove (info->drop_timeout);
3316 gtk_drag_update_idle (gpointer data)
3318 GtkDragSourceInfo *info = data;
3319 GdkWindow *dest_window;
3320 GdkDragProtocol protocol;
3323 GdkDragAction action;
3324 GdkDragAction possible_actions;
3327 GDK_THREADS_ENTER ();
3329 info->update_idle = 0;
3331 time = gtk_drag_get_event_time (info->last_event);
3332 gtk_drag_get_event_actions (info->last_event,
3334 info->possible_actions,
3335 &action, &possible_actions);
3336 gtk_drag_update_icon (info);
3337 gdk_drag_find_window_for_screen (info->context,
3338 info->icon_window ? info->icon_window->window : NULL,
3339 info->cur_screen, info->cur_x, info->cur_y,
3340 &dest_window, &protocol);
3342 if (!gdk_drag_motion (info->context, dest_window, protocol,
3343 info->cur_x, info->cur_y, action,
3347 gdk_event_free ((GdkEvent *)info->last_event);
3348 info->last_event = NULL;
3352 g_object_unref (dest_window);
3354 selection = gdk_drag_get_selection (info->context);
3356 gtk_drag_source_check_selection (info, selection, time);
3358 GDK_THREADS_LEAVE ();
3364 gtk_drag_add_update_idle (GtkDragSourceInfo *info)
3366 /* We use an idle lowerthan GDK_PRIORITY_REDRAW so that exposes
3367 * from the last move can catch up before we move again.
3369 if (!info->update_idle)
3370 info->update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW + 5,
3371 gtk_drag_update_idle,
3378 * @info: DragSourceInfo for the drag
3379 * @screen: new screen
3380 * @x_root: new X position
3381 * @y_root: new y position
3382 * @event: event received requiring update
3384 * Updates the status of the drag; called when the
3385 * cursor moves or the modifier changes
3388 gtk_drag_update (GtkDragSourceInfo *info,
3394 info->cur_screen = screen;
3395 info->cur_x = x_root;
3396 info->cur_y = y_root;
3397 if (info->last_event)
3398 gdk_event_free ((GdkEvent *)info->last_event);
3399 info->last_event = gdk_event_copy ((GdkEvent *)event);
3401 gtk_drag_add_update_idle (info);
3404 /*************************************************************
3406 * Called when the user finishes to drag, either by
3407 * releasing the mouse, or by pressing Esc.
3409 * info: Source info for the drag
3410 * time: Timestamp for ending the drag
3412 *************************************************************/
3415 gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
3417 GdkEvent *send_event;
3418 GtkWidget *source_widget = info->widget;
3419 GdkDisplay *display = gtk_widget_get_display (source_widget);
3421 if (info->update_idle)
3423 g_source_remove (info->update_idle);
3424 info->update_idle = 0;
3427 if (info->last_event)
3429 gdk_event_free (info->last_event);
3430 info->last_event = NULL;
3433 info->have_grab = FALSE;
3435 gdk_display_pointer_ungrab (display, time);
3436 gdk_display_keyboard_ungrab (display, time);
3437 gtk_grab_remove (info->ipc_widget);
3439 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3440 gtk_drag_button_release_cb,
3442 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3445 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3449 /* Send on a release pair to the the original
3450 * widget to convince it to release its grab. We need to
3451 * call gtk_propagate_event() here, instead of
3452 * gtk_widget_event() because widget like GtkList may
3453 * expect propagation.
3456 send_event = gdk_event_new (GDK_BUTTON_RELEASE);
3457 send_event->button.window = g_object_ref (gtk_widget_get_root_window (source_widget));
3458 send_event->button.send_event = TRUE;
3459 send_event->button.time = time;
3460 send_event->button.x = 0;
3461 send_event->button.y = 0;
3462 send_event->button.axes = NULL;
3463 send_event->button.state = 0;
3464 send_event->button.button = info->button;
3465 send_event->button.device = gdk_display_get_core_pointer (display);
3466 send_event->button.x_root = 0;
3467 send_event->button.y_root = 0;
3469 gtk_propagate_event (source_widget, send_event);
3470 gdk_event_free (send_event);
3473 /*************************************************************
3475 * Called on cancellation of a drag, either by the user
3476 * or programmatically.
3478 * info: Source info for the drag
3479 * time: Timestamp for ending the drag
3481 *************************************************************/
3484 gtk_drag_cancel (GtkDragSourceInfo *info, guint32 time)
3486 gtk_drag_end (info, time);
3487 gdk_drag_abort (info->context, time);
3488 gtk_drag_drop_finished (info, FALSE, time);
3491 /*************************************************************
3492 * gtk_drag_motion_cb:
3493 * "motion_notify_event" callback during drag.
3497 *************************************************************/
3500 gtk_drag_motion_cb (GtkWidget *widget,
3501 GdkEventMotion *event,
3504 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
3506 gint x_root, y_root;
3510 GdkDisplay *display = gtk_widget_get_display (widget);
3512 gdk_display_get_pointer (display, &screen, &x_root, &y_root, NULL);
3513 event->x_root = x_root;
3514 event->y_root = y_root;
3517 screen = gdk_event_get_screen ((GdkEvent *)event);
3519 gtk_drag_update (info, screen, event->x_root, event->y_root, (GdkEvent *)event);
3524 /*************************************************************
3526 * "key_press/release_event" callback during drag.
3530 *************************************************************/
3533 gtk_drag_key_cb (GtkWidget *widget,
3537 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
3538 GdkModifierType state;
3539 GdkWindow *root_window;
3541 if (event->type == GDK_KEY_PRESS)
3543 if (event->keyval == GDK_Escape)
3545 gtk_drag_cancel (info, event->time);
3551 /* Now send a "motion" so that the modifier state is updated */
3553 /* The state is not yet updated in the event, so we need
3554 * to query it here. We could use XGetModifierMapping, but
3555 * that would be overkill.
3557 root_window = gtk_widget_get_root_window (widget);
3558 gdk_window_get_pointer (root_window, NULL, NULL, &state);
3560 event->state = state;
3561 gtk_drag_update (info, info->cur_screen, info->cur_x, info->cur_y, (GdkEvent *)event);
3566 /*************************************************************
3567 * gtk_drag_button_release_cb:
3568 * "button_release_event" callback during drag.
3572 *************************************************************/
3575 gtk_drag_button_release_cb (GtkWidget *widget,
3576 GdkEventButton *event,
3579 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
3581 if (event->button != info->button)
3584 if ((info->context->action != 0) && (info->context->dest_window != NULL))
3586 gtk_drag_end (info, event->time);
3587 gtk_drag_drop (info, event->time);
3591 gtk_drag_cancel (info, event->time);
3598 gtk_drag_abort_timeout (gpointer data)
3600 GtkDragSourceInfo *info = data;
3601 guint32 time = GDK_CURRENT_TIME;
3603 GDK_THREADS_ENTER ();
3605 if (info->proxy_dest)
3606 time = info->proxy_dest->proxy_drop_time;
3608 info->drop_timeout = 0;
3609 gtk_drag_drop_finished (info, FALSE, time);
3611 GDK_THREADS_LEAVE ();
3617 * gtk_drag_check_threshold:
3618 * @widget: a #GtkWidget
3619 * @start_x: X coordinate of start of drag
3620 * @start_y: Y coordinate of start of drag
3621 * @current_x: current X coordinate
3622 * @current_y: current Y coordinate
3624 * Checks to see if a mouse drag starting at (@start_x, @start_y) and ending
3625 * at (@current_x, @current_y) has passed the GTK+ drag threshold, and thus
3626 * should trigger the beginning of a drag-and-drop operation.
3628 * Return Value: %TRUE if the drag threshold has been passed.
3631 gtk_drag_check_threshold (GtkWidget *widget,
3637 gint drag_threshold;
3639 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
3641 g_object_get (gtk_widget_get_settings (widget),
3642 "gtk-dnd-drag-threshold", &drag_threshold,
3645 return (ABS (current_x - start_x) > drag_threshold ||
3646 ABS (current_y - start_y) > drag_threshold);