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);
1083 * gtk_drag_dest_add_uri_targets:
1084 * @widget: a #GtkWidget that's a drag destination
1086 * Add the URI targets supported by #GtkSelection to
1087 * the target list of the drag destination. The targets
1088 * are added with @info = 0. If you need another value,
1089 * use gtk_target_list_add_uri_targets() and
1090 * gtk_drag_dest_set_target_list().
1095 gtk_drag_dest_add_uri_targets (GtkWidget *widget)
1097 GtkTargetList *target_list;
1099 target_list = gtk_drag_dest_get_target_list (widget);
1101 gtk_target_list_ref (target_list);
1103 target_list = gtk_target_list_new (NULL, 0);
1104 gtk_target_list_add_uri_targets (target_list, 0);
1105 gtk_drag_dest_set_target_list (widget, target_list);
1106 gtk_target_list_unref (target_list);
1109 /*************************************************************
1110 * _gtk_drag_dest_handle_event:
1111 * Called from widget event handling code on Drag events
1115 * toplevel: Toplevel widget that received the event
1118 *************************************************************/
1121 _gtk_drag_dest_handle_event (GtkWidget *toplevel,
1124 GtkDragDestInfo *info;
1125 GdkDragContext *context;
1127 g_return_if_fail (toplevel != NULL);
1128 g_return_if_fail (event != NULL);
1130 context = event->dnd.context;
1132 info = gtk_drag_get_dest_info (context, TRUE);
1134 /* Find the widget for the event */
1135 switch (event->type)
1137 case GDK_DRAG_ENTER:
1140 case GDK_DRAG_LEAVE:
1143 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1144 info->widget = NULL;
1148 case GDK_DRAG_MOTION:
1149 case GDK_DROP_START:
1151 GtkDragFindData data;
1154 if (event->type == GDK_DROP_START)
1156 info->dropped = TRUE;
1157 /* We send a leave here so that the widget unhighlights
1162 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1163 info->widget = NULL;
1167 #ifdef GDK_WINDOWING_X11
1168 /* Hackaround for: http://bugzilla.gnome.org/show_bug.cgi?id=136112
1170 * Currently gdk_window_get_position doesn't provide reliable
1171 * information for embedded windows, so we call the much more
1172 * expensive gdk_window_get_origin().
1174 if (GTK_IS_PLUG (toplevel))
1175 gdk_window_get_origin (toplevel->window, &tx, &ty);
1177 #endif /* GDK_WINDOWING_X11 */
1178 gdk_window_get_position (toplevel->window, &tx, &ty);
1180 data.x = event->dnd.x_root - tx;
1181 data.y = event->dnd.y_root - ty;
1182 data.context = context;
1185 data.toplevel = TRUE;
1186 data.callback = (event->type == GDK_DRAG_MOTION) ?
1187 gtk_drag_dest_motion : gtk_drag_dest_drop;
1188 data.time = event->dnd.time;
1190 gtk_drag_find_widget (toplevel, &data);
1192 if (info->widget && !data.found)
1194 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
1195 info->widget = NULL;
1200 if (event->type == GDK_DRAG_MOTION)
1203 gdk_drag_status (context, 0, event->dnd.time);
1205 else if (event->type == GDK_DROP_START && !info->proxy_source)
1207 gdk_drop_reply (context, data.found, event->dnd.time);
1208 if ((context->protocol == GDK_DRAG_PROTO_MOTIF) && !data.found)
1209 gtk_drag_finish (context, FALSE, FALSE, event->dnd.time);
1215 g_assert_not_reached ();
1220 * gtk_drag_dest_find_target:
1221 * @widget: drag destination widget
1222 * @context: drag context
1223 * @target_list: list of droppable targets, or %NULL to use
1224 * gtk_drag_dest_get_target_list (@widget).
1226 * Looks for a match between @context->targets and the
1227 * @dest_target_list, returning the first matching target, otherwise
1228 * returning %GDK_NONE. @dest_target_list should usually be the return
1229 * value from gtk_drag_dest_get_target_list(), but some widgets may
1230 * have different valid targets for different parts of the widget; in
1231 * that case, they will have to implement a drag_motion handler that
1232 * passes the correct target list to this function.
1234 * Return value: first target that the source offers and the dest can accept, or %GDK_NONE
1237 gtk_drag_dest_find_target (GtkWidget *widget,
1238 GdkDragContext *context,
1239 GtkTargetList *target_list)
1242 GList *tmp_source = NULL;
1243 GtkWidget *source_widget;
1245 g_return_val_if_fail (GTK_IS_WIDGET (widget), GDK_NONE);
1246 g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), GDK_NONE);
1247 g_return_val_if_fail (!context->is_source, GDK_NONE);
1250 source_widget = gtk_drag_get_source_widget (context);
1252 if (target_list == NULL)
1253 target_list = gtk_drag_dest_get_target_list (widget);
1255 if (target_list == NULL)
1258 tmp_target = target_list->list;
1261 GtkTargetPair *pair = tmp_target->data;
1262 tmp_source = context->targets;
1265 if (tmp_source->data == GUINT_TO_POINTER (pair->target))
1267 if ((!(pair->flags & GTK_TARGET_SAME_APP) || source_widget) &&
1268 (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget)))
1269 return pair->target;
1273 tmp_source = tmp_source->next;
1275 tmp_target = tmp_target->next;
1282 gtk_drag_selection_received (GtkWidget *widget,
1283 GtkSelectionData *selection_data,
1287 GdkDragContext *context;
1288 GtkDragDestInfo *info;
1289 GtkWidget *drop_widget;
1293 context = g_object_get_data (G_OBJECT (widget), "drag-context");
1294 info = gtk_drag_get_dest_info (context, FALSE);
1296 if (info->proxy_data &&
1297 info->proxy_data->target == selection_data->target)
1299 gtk_selection_data_set (info->proxy_data,
1300 selection_data->type,
1301 selection_data->format,
1302 selection_data->data,
1303 selection_data->length);
1308 if (selection_data->target == gdk_atom_intern ("DELETE", FALSE))
1310 gtk_drag_finish (context, TRUE, FALSE, time);
1312 else if ((selection_data->target == gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE)) ||
1313 (selection_data->target == gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE)))
1319 GtkDragDestSite *site;
1321 site = g_object_get_data (G_OBJECT (drop_widget), "gtk-drag-dest");
1323 if (site && site->target_list)
1327 if (gtk_target_list_find (site->target_list,
1328 selection_data->target,
1331 if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
1332 selection_data->length >= 0)
1333 g_signal_emit_by_name (drop_widget,
1334 "drag_data_received",
1335 context, info->drop_x, info->drop_y,
1342 g_signal_emit_by_name (drop_widget,
1343 "drag_data_received",
1344 context, info->drop_x, info->drop_y,
1349 if (site && site->flags & GTK_DEST_DEFAULT_DROP)
1352 gtk_drag_finish (context,
1353 (selection_data->length >= 0),
1354 (context->action == GDK_ACTION_MOVE),
1358 g_object_unref (drop_widget);
1361 g_signal_handlers_disconnect_by_func (widget,
1362 gtk_drag_selection_received,
1365 g_object_set_data (G_OBJECT (widget), "drag-context", NULL);
1366 g_object_unref (context);
1368 gtk_drag_release_ipc_widget (widget);
1372 prepend_and_ref_widget (GtkWidget *widget,
1375 GSList **slist_p = data;
1377 *slist_p = g_slist_prepend (*slist_p, g_object_ref (widget));
1380 /*************************************************************
1381 * gtk_drag_find_widget:
1382 * Recursive callback used to locate widgets for
1383 * DRAG_MOTION and DROP_START events.
1387 *************************************************************/
1390 gtk_drag_find_widget (GtkWidget *widget,
1391 GtkDragFindData *data)
1393 GtkAllocation new_allocation;
1394 gint allocation_to_window_x = 0;
1395 gint allocation_to_window_y = 0;
1399 if (data->found || !GTK_WIDGET_MAPPED (widget) || !GTK_WIDGET_SENSITIVE (widget))
1402 /* Note that in the following code, we only count the
1403 * position as being inside a WINDOW widget if it is inside
1404 * widget->window; points that are outside of widget->window
1405 * but within the allocation are not counted. This is consistent
1406 * with the way we highlight drag targets.
1408 * data->x,y are relative to widget->parent->window (if
1409 * widget is not a toplevel, widget->window otherwise).
1410 * We compute the allocation of widget in the same coordinates,
1411 * clipping to widget->window, and all intermediate
1412 * windows. If data->x,y is inside that, then we translate
1413 * our coordinates to be relative to widget->window and
1416 new_allocation = widget->allocation;
1421 GdkWindow *window = widget->window;
1423 /* Compute the offset from allocation-relative to
1424 * window-relative coordinates.
1426 allocation_to_window_x = widget->allocation.x;
1427 allocation_to_window_y = widget->allocation.y;
1429 if (!GTK_WIDGET_NO_WINDOW (widget))
1431 /* The allocation is relative to the parent window for
1432 * window widgets, not to widget->window.
1434 gdk_window_get_position (window, &tx, &ty);
1436 allocation_to_window_x -= tx;
1437 allocation_to_window_y -= ty;
1440 new_allocation.x = 0 + allocation_to_window_x;
1441 new_allocation.y = 0 + allocation_to_window_y;
1443 while (window && window != widget->parent->window)
1445 GdkRectangle window_rect = { 0, 0, 0, 0 };
1447 gdk_drawable_get_size (window, &window_rect.width, &window_rect.height);
1449 gdk_rectangle_intersect (&new_allocation, &window_rect, &new_allocation);
1451 gdk_window_get_position (window, &tx, &ty);
1452 new_allocation.x += tx;
1454 new_allocation.y += ty;
1457 window = gdk_window_get_parent (window);
1460 if (!window) /* Window and widget heirarchies didn't match. */
1464 if (data->toplevel ||
1465 ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
1466 (data->x < new_allocation.x + new_allocation.width) &&
1467 (data->y < new_allocation.y + new_allocation.height)))
1469 /* First, check if the drag is in a valid drop site in
1470 * one of our children
1472 if (GTK_IS_CONTAINER (widget))
1474 GtkDragFindData new_data = *data;
1475 GSList *children = NULL;
1478 new_data.x -= x_offset;
1479 new_data.y -= y_offset;
1480 new_data.found = FALSE;
1481 new_data.toplevel = FALSE;
1483 /* need to reference children temporarily in case the
1484 * ::drag_motion/::drag_drop callbacks change the widget heirarchy.
1486 gtk_container_forall (GTK_CONTAINER (widget), prepend_and_ref_widget, &children);
1487 for (tmp_list = children; tmp_list; tmp_list = tmp_list->next)
1489 if (!new_data.found && GTK_WIDGET_DRAWABLE (tmp_list->data))
1490 gtk_drag_find_widget (tmp_list->data, &new_data);
1491 g_object_unref (tmp_list->data);
1493 g_slist_free (children);
1495 data->found = new_data.found;
1498 /* If not, and this widget is registered as a drop site, check to
1499 * emit "drag_motion" to check if we are actually in
1503 g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"))
1505 data->found = data->callback (widget,
1507 data->x - x_offset - allocation_to_window_x,
1508 data->y - y_offset - allocation_to_window_y,
1510 /* If so, send a "drag_leave" to the last widget */
1513 if (data->info->widget && data->info->widget != widget)
1515 gtk_drag_dest_leave (data->info->widget, data->context, data->time);
1517 data->info->widget = widget;
1524 gtk_drag_proxy_begin (GtkWidget *widget,
1525 GtkDragDestInfo *dest_info,
1528 GtkDragSourceInfo *source_info;
1530 GdkDragContext *context;
1531 GtkWidget *ipc_widget;
1533 if (dest_info->proxy_source)
1535 gdk_drag_abort (dest_info->proxy_source->context, time);
1536 gtk_drag_source_info_destroy (dest_info->proxy_source);
1537 dest_info->proxy_source = NULL;
1540 ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
1541 context = gdk_drag_begin (ipc_widget->window,
1542 dest_info->context->targets);
1544 source_info = gtk_drag_get_source_info (context, TRUE);
1546 source_info->ipc_widget = ipc_widget;
1547 source_info->widget = gtk_widget_ref (widget);
1549 source_info->target_list = gtk_target_list_new (NULL, 0);
1550 tmp_list = dest_info->context->targets;
1553 gtk_target_list_add (source_info->target_list,
1554 GDK_POINTER_TO_ATOM (tmp_list->data), 0, 0);
1555 tmp_list = tmp_list->next;
1558 source_info->proxy_dest = dest_info;
1560 g_signal_connect (ipc_widget,
1562 G_CALLBACK (gtk_drag_selection_get),
1565 dest_info->proxy_source = source_info;
1569 gtk_drag_dest_info_destroy (gpointer data)
1571 GtkDragDestInfo *info = data;
1576 static GtkDragDestInfo *
1577 gtk_drag_get_dest_info (GdkDragContext *context,
1580 GtkDragDestInfo *info;
1581 static GQuark info_quark = 0;
1583 info_quark = g_quark_from_static_string ("gtk-dest-info");
1585 info = g_object_get_qdata (G_OBJECT (context), info_quark);
1586 if (!info && create)
1588 info = g_new (GtkDragDestInfo, 1);
1589 info->widget = NULL;
1590 info->context = context;
1591 info->proxy_source = NULL;
1592 info->proxy_data = NULL;
1593 info->dropped = FALSE;
1594 info->proxy_drop_wait = FALSE;
1595 g_object_set_qdata_full (G_OBJECT (context), info_quark,
1596 info, gtk_drag_dest_info_destroy);
1602 static GQuark dest_info_quark = 0;
1604 static GtkDragSourceInfo *
1605 gtk_drag_get_source_info (GdkDragContext *context,
1608 GtkDragSourceInfo *info;
1609 if (!dest_info_quark)
1610 dest_info_quark = g_quark_from_static_string ("gtk-source-info");
1612 info = g_object_get_qdata (G_OBJECT (context), dest_info_quark);
1613 if (!info && create)
1615 info = g_new0 (GtkDragSourceInfo, 1);
1616 info->context = context;
1617 g_object_set_qdata (G_OBJECT (context), dest_info_quark, info);
1624 gtk_drag_clear_source_info (GdkDragContext *context)
1626 g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL);
1630 gtk_drag_dest_realized (GtkWidget *widget)
1632 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1634 if (GTK_WIDGET_TOPLEVEL (toplevel))
1635 gdk_window_register_dnd (toplevel->window);
1639 gtk_drag_dest_hierarchy_changed (GtkWidget *widget,
1640 GtkWidget *previous_toplevel)
1642 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1644 if (GTK_WIDGET_TOPLEVEL (toplevel) && GTK_WIDGET_REALIZED (toplevel))
1645 gdk_window_register_dnd (toplevel->window);
1649 gtk_drag_dest_site_destroy (gpointer data)
1651 GtkDragDestSite *site = data;
1653 if (site->proxy_window)
1654 g_object_unref (site->proxy_window);
1656 if (site->target_list)
1657 gtk_target_list_unref (site->target_list);
1663 * Default drag handlers
1666 gtk_drag_dest_leave (GtkWidget *widget,
1667 GdkDragContext *context,
1670 GtkDragDestSite *site;
1672 site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
1673 g_return_if_fail (site != NULL);
1677 GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
1679 if (info->proxy_source && info->proxy_source->widget == widget && !info->dropped)
1681 gdk_drag_abort (info->proxy_source->context, time);
1682 gtk_drag_source_info_destroy (info->proxy_source);
1683 info->proxy_source = NULL;
1690 if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag)
1691 gtk_drag_unhighlight (widget);
1693 if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag)
1694 g_signal_emit_by_name (widget, "drag_leave",
1697 site->have_drag = FALSE;
1702 gtk_drag_dest_motion (GtkWidget *widget,
1703 GdkDragContext *context,
1708 GtkDragDestSite *site;
1709 GdkDragAction action = 0;
1712 site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
1713 g_return_val_if_fail (site != NULL, FALSE);
1718 GdkEvent *current_event;
1719 GdkWindow *dest_window;
1720 GdkDragProtocol proto;
1722 GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
1724 if (!info->proxy_source || info->proxy_source->widget != widget)
1725 gtk_drag_proxy_begin (widget, info, time);
1727 current_event = gtk_get_current_event ();
1729 if (site->proxy_window)
1731 dest_window = site->proxy_window;
1732 proto = site->proxy_protocol;
1736 gdk_drag_find_window_for_screen (info->proxy_source->context,
1738 gdk_drawable_get_screen (current_event->dnd.window),
1739 current_event->dnd.x_root,
1740 current_event->dnd.y_root,
1741 &dest_window, &proto);
1744 gdk_drag_motion (info->proxy_source->context,
1746 current_event->dnd.x_root,
1747 current_event->dnd.y_root,
1748 context->suggested_action,
1749 context->actions, time);
1751 if (!site->proxy_window && dest_window)
1752 g_object_unref (dest_window);
1754 selection = gdk_drag_get_selection (info->proxy_source->context);
1756 selection != gdk_drag_get_selection (info->context))
1757 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1759 gdk_event_free (current_event);
1764 if (site->flags & GTK_DEST_DEFAULT_MOTION)
1766 if (context->suggested_action & site->actions)
1767 action = context->suggested_action;
1774 if ((site->actions & (1 << i)) &&
1775 (context->actions & (1 << i)))
1783 if (action && gtk_drag_dest_find_target (widget, context, NULL))
1785 if (!site->have_drag)
1787 site->have_drag = TRUE;
1788 if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1789 gtk_drag_highlight (widget);
1792 gdk_drag_status (context, action, time);
1796 gdk_drag_status (context, 0, time);
1801 g_signal_emit_by_name (widget, "drag_motion",
1802 context, x, y, time, &retval);
1804 return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1808 gtk_drag_dest_drop (GtkWidget *widget,
1809 GdkDragContext *context,
1814 GtkDragDestSite *site;
1815 GtkDragDestInfo *info;
1817 site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
1818 g_return_val_if_fail (site != NULL, FALSE);
1820 info = gtk_drag_get_dest_info (context, FALSE);
1821 g_return_val_if_fail (info != NULL, FALSE);
1828 if (info->proxy_source ||
1829 (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN))
1831 gtk_drag_drop (info->proxy_source, time);
1835 /* We need to synthesize a motion event, wait for a status,
1836 * and, if we get a good one, do a drop.
1839 GdkEvent *current_event;
1841 GdkWindow *dest_window;
1842 GdkDragProtocol proto;
1844 gtk_drag_proxy_begin (widget, info, time);
1845 info->proxy_drop_wait = TRUE;
1846 info->proxy_drop_time = time;
1848 current_event = gtk_get_current_event ();
1850 if (site->proxy_window)
1852 dest_window = site->proxy_window;
1853 proto = site->proxy_protocol;
1857 gdk_drag_find_window_for_screen (info->proxy_source->context,
1859 gdk_drawable_get_screen (current_event->dnd.window),
1860 current_event->dnd.x_root,
1861 current_event->dnd.y_root,
1862 &dest_window, &proto);
1865 gdk_drag_motion (info->proxy_source->context,
1867 current_event->dnd.x_root,
1868 current_event->dnd.y_root,
1869 context->suggested_action,
1870 context->actions, time);
1872 if (!site->proxy_window && dest_window)
1873 g_object_unref (dest_window);
1875 selection = gdk_drag_get_selection (info->proxy_source->context);
1877 selection != gdk_drag_get_selection (info->context))
1878 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1880 gdk_event_free (current_event);
1889 if (site->flags & GTK_DEST_DEFAULT_DROP)
1891 GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
1893 if (target == GDK_NONE)
1895 gtk_drag_finish (context, FALSE, FALSE, time);
1899 gtk_drag_get_data (widget, context, target, time);
1902 g_signal_emit_by_name (widget, "drag_drop",
1903 context, x, y, time, &retval);
1905 return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
1913 /* Like GtkDragBegin, but also takes a GtkDragSourceSite,
1914 * so that we can set the icon from the source site information
1916 static GdkDragContext *
1917 gtk_drag_begin_internal (GtkWidget *widget,
1918 GtkDragSourceSite *site,
1919 GtkTargetList *target_list,
1920 GdkDragAction actions,
1924 GtkDragSourceInfo *info;
1925 GList *targets = NULL;
1927 guint32 time = GDK_CURRENT_TIME;
1928 GdkDragAction possible_actions, suggested_action;
1929 GdkDragContext *context;
1930 GtkWidget *ipc_widget;
1933 ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
1935 gtk_drag_get_event_actions (event, button, actions,
1936 &suggested_action, &possible_actions);
1938 cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget), suggested_action);
1941 time = gdk_event_get_time (event);
1943 if (gdk_pointer_grab (ipc_widget->window, FALSE,
1944 GDK_POINTER_MOTION_MASK |
1945 GDK_BUTTON_RELEASE_MASK, NULL,
1948 gtk_drag_release_ipc_widget (ipc_widget);
1952 if (gdk_keyboard_grab (ipc_widget->window, FALSE, time) != 0)
1954 gtk_drag_release_ipc_widget (ipc_widget);
1958 /* We use a GTK grab here to override any grabs that the widget
1959 * we are dragging from might have held
1961 gtk_grab_add (ipc_widget);
1963 tmp_list = g_list_last (target_list->list);
1966 GtkTargetPair *pair = tmp_list->data;
1967 targets = g_list_prepend (targets,
1968 GINT_TO_POINTER (pair->target));
1969 tmp_list = tmp_list->prev;
1972 source_widgets = g_slist_prepend (source_widgets, ipc_widget);
1974 context = gdk_drag_begin (ipc_widget->window, targets);
1975 g_list_free (targets);
1977 info = gtk_drag_get_source_info (context, TRUE);
1979 info->ipc_widget = ipc_widget;
1980 g_object_set_data (G_OBJECT (info->ipc_widget), "gtk-info", info);
1982 info->widget = gtk_widget_ref (widget);
1984 info->button = button;
1985 info->cursor = cursor;
1986 info->target_list = target_list;
1987 gtk_target_list_ref (target_list);
1989 info->possible_actions = actions;
1991 info->status = GTK_DRAG_STATUS_DRAG;
1992 info->last_event = NULL;
1993 info->selections = NULL;
1994 info->icon_window = NULL;
1995 info->destroy_icon = FALSE;
1997 /* Set cur_x, cur_y here so if the "drag_begin" signal shows
1998 * the drag icon, it will be in the right place
2000 if (event && event->type == GDK_MOTION_NOTIFY)
2002 info->cur_screen = gtk_widget_get_screen (widget);
2003 info->cur_x = event->motion.x_root;
2004 info->cur_y = event->motion.y_root;
2008 gdk_display_get_pointer (gtk_widget_get_display (widget),
2009 &info->cur_screen, &info->cur_x, &info->cur_y, NULL);
2012 g_signal_emit_by_name (widget, "drag_begin",
2015 /* Ensure that we have an icon before we start the drag; the
2016 * application may have set one in ::drag_begin, or it may
2019 if (!info->icon_window)
2021 if (!site || site->icon_type == GTK_IMAGE_EMPTY)
2022 gtk_drag_set_icon_default (context);
2024 switch (site->icon_type)
2026 case GTK_IMAGE_PIXMAP:
2027 gtk_drag_set_icon_pixmap (context,
2029 site->icon_data.pixmap.pixmap,
2033 case GTK_IMAGE_PIXBUF:
2034 gtk_drag_set_icon_pixbuf (context,
2035 site->icon_data.pixbuf.pixbuf,
2038 case GTK_IMAGE_STOCK:
2039 gtk_drag_set_icon_stock (context,
2040 site->icon_data.stock.stock_id,
2043 case GTK_IMAGE_EMPTY:
2045 g_assert_not_reached();
2050 if (event && event->type == GDK_MOTION_NOTIFY)
2051 gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
2053 info->start_x = info->cur_x;
2054 info->start_y = info->cur_y;
2056 g_signal_connect (info->ipc_widget, "button_release_event",
2057 G_CALLBACK (gtk_drag_button_release_cb), info);
2058 g_signal_connect (info->ipc_widget, "motion_notify_event",
2059 G_CALLBACK (gtk_drag_motion_cb), info);
2060 g_signal_connect (info->ipc_widget, "key_press_event",
2061 G_CALLBACK (gtk_drag_key_cb), info);
2062 g_signal_connect (info->ipc_widget, "key_release_event",
2063 G_CALLBACK (gtk_drag_key_cb), info);
2064 g_signal_connect (info->ipc_widget, "selection_get",
2065 G_CALLBACK (gtk_drag_selection_get), info);
2067 info->have_grab = TRUE;
2068 info->grab_time = time;
2070 return info->context;
2075 * @widget: the source widget.
2076 * @targets: The targets (data formats) in which the
2077 * source can provide the data.
2078 * @actions: A bitmask of the allowed drag actions for this drag.
2079 * @button: The button the user clicked to start the drag.
2080 * @event: The event that triggered the start of the drag.
2082 * Initiates a drag on the source side. The function
2083 * only needs to be used when the application is
2084 * starting drags itself, and is not needed when
2085 * gtk_drag_source_set() is used.
2087 * Return value: the context for this drag.
2090 gtk_drag_begin (GtkWidget *widget,
2091 GtkTargetList *targets,
2092 GdkDragAction actions,
2096 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
2097 g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
2098 g_return_val_if_fail (targets != NULL, NULL);
2100 return gtk_drag_begin_internal (widget, NULL, targets,
2101 actions, button, event);
2104 /*************************************************************
2105 * gtk_drag_source_set:
2106 * Register a drop site, and possibly add default behaviors.
2109 * start_button_mask: Mask of allowed buttons to start drag
2110 * targets: Table of targets for this source
2112 * actions: Actions allowed for this source
2114 *************************************************************/
2117 gtk_drag_source_set (GtkWidget *widget,
2118 GdkModifierType start_button_mask,
2119 const GtkTargetEntry *targets,
2121 GdkDragAction actions)
2123 GtkDragSourceSite *site;
2125 g_return_if_fail (GTK_IS_WIDGET (widget));
2127 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2129 gtk_widget_add_events (widget,
2130 gtk_widget_get_events (widget) |
2131 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
2132 GDK_BUTTON_MOTION_MASK);
2136 if (site->target_list)
2137 gtk_target_list_unref (site->target_list);
2141 site = g_new0 (GtkDragSourceSite, 1);
2143 site->icon_type = GTK_IMAGE_EMPTY;
2145 g_signal_connect (widget, "button_press_event",
2146 G_CALLBACK (gtk_drag_source_event_cb),
2148 g_signal_connect (widget, "motion_notify_event",
2149 G_CALLBACK (gtk_drag_source_event_cb),
2152 g_object_set_data_full (G_OBJECT (widget),
2154 site, gtk_drag_source_site_destroy);
2157 site->start_button_mask = start_button_mask;
2159 site->target_list = gtk_target_list_new (targets, n_targets);
2161 site->actions = actions;
2164 /*************************************************************
2165 * gtk_drag_source_unset
2166 * Unregister this widget as a drag source.
2170 *************************************************************/
2173 gtk_drag_source_unset (GtkWidget *widget)
2175 GtkDragSourceSite *site;
2177 g_return_if_fail (GTK_IS_WIDGET (widget));
2179 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2183 g_signal_handlers_disconnect_by_func (widget,
2184 gtk_drag_source_event_cb,
2186 g_signal_handlers_disconnect_by_func (widget,
2187 gtk_drag_source_event_cb,
2189 g_object_set_data (G_OBJECT (widget), "gtk-site-data", NULL);
2194 * gtk_drag_source_get_target_list:
2195 * @widget: a #GtkWidget
2197 * Gets the list of targets this widget can provide for
2200 * Return value: the #GtkTargetList, or %NULL if none
2205 gtk_drag_source_get_target_list (GtkWidget *widget)
2207 GtkDragSourceSite *site;
2209 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
2211 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2213 return site ? site->target_list : NULL;
2217 * gtk_drag_source_set_target_list:
2218 * @widget: a #GtkWidget that's a drag source
2219 * @target_list: list of draggable targets, or %NULL for none
2221 * Changes the target types that this widget offers for drag-and-drop.
2222 * The widget must first be made into a drag source with
2223 * gtk_drag_source_set().
2228 gtk_drag_source_set_target_list (GtkWidget *widget,
2229 GtkTargetList *target_list)
2231 GtkDragSourceSite *site;
2233 g_return_if_fail (GTK_IS_WIDGET (widget));
2235 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2238 g_warning ("gtk_drag_source_set_target_list() requires the widget "
2239 "to already be a drag source.");
2244 gtk_target_list_ref (target_list);
2246 if (site->target_list)
2247 gtk_target_list_unref (site->target_list);
2249 site->target_list = target_list;
2253 * gtk_drag_source_add_text_targets:
2254 * @widget: a #GtkWidget that's is a drag source
2256 * Add the text 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_source_set_target_list().
2265 gtk_drag_source_add_text_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_text_targets (target_list, 0);
2275 gtk_drag_source_set_target_list (widget, target_list);
2276 gtk_target_list_unref (target_list);
2280 * gtk_drag_source_add_image_targets:
2281 * @widget: a #GtkWidget that's is a drag source
2283 * Add the writable image targets supported by #GtkSelection to
2284 * the target list of the drag source. The targets
2285 * are added with @info = 0. If you need another value,
2286 * use gtk_target_list_add_image_targets() and
2287 * gtk_drag_source_set_target_list().
2292 gtk_drag_source_add_image_targets (GtkWidget *widget)
2294 GtkTargetList *target_list;
2296 target_list = gtk_drag_source_get_target_list (widget);
2298 gtk_target_list_ref (target_list);
2300 target_list = gtk_target_list_new (NULL, 0);
2301 gtk_target_list_add_image_targets (target_list, 0, TRUE);
2302 gtk_drag_source_set_target_list (widget, target_list);
2303 gtk_target_list_unref (target_list);
2307 * gtk_drag_source_add_uri_targets:
2308 * @widget: a #GtkWidget that's is a drag source
2310 * Add the URI targets supported by #GtkSelection to
2311 * the target list of the drag source. The targets
2312 * are added with @info = 0. If you need another value,
2313 * use gtk_target_list_add_uri_targets() and
2314 * gtk_drag_source_set_target_list().
2319 gtk_drag_source_add_uri_targets (GtkWidget *widget)
2321 GtkTargetList *target_list;
2323 target_list = gtk_drag_source_get_target_list (widget);
2325 gtk_target_list_ref (target_list);
2327 target_list = gtk_target_list_new (NULL, 0);
2328 gtk_target_list_add_uri_targets (target_list, 0);
2329 gtk_drag_source_set_target_list (widget, target_list);
2330 gtk_target_list_unref (target_list);
2334 gtk_drag_source_unset_icon (GtkDragSourceSite *site)
2336 switch (site->icon_type)
2338 case GTK_IMAGE_EMPTY:
2340 case GTK_IMAGE_PIXMAP:
2341 if (site->icon_data.pixmap.pixmap)
2342 g_object_unref (site->icon_data.pixmap.pixmap);
2343 if (site->icon_mask)
2344 g_object_unref (site->icon_mask);
2346 case GTK_IMAGE_PIXBUF:
2347 g_object_unref (site->icon_data.pixbuf.pixbuf);
2349 case GTK_IMAGE_STOCK:
2350 g_free (site->icon_data.stock.stock_id);
2353 g_assert_not_reached();
2356 site->icon_type = GTK_IMAGE_EMPTY;
2359 g_object_unref (site->colormap);
2360 site->colormap = NULL;
2364 * gtk_drag_source_set_icon:
2365 * @widget: a #GtkWidget
2366 * @colormap: the colormap of the icon
2367 * @pixmap: the image data for the icon
2368 * @mask: the transparency mask for an image.
2370 * Sets the icon that will be used for drags from a particular widget
2371 * from a pixmap/mask. GTK+ retains references for the arguments, and
2372 * will release them when they are no longer needed.
2373 * Use gtk_drag_source_set_icon_pixbuf() instead.
2376 gtk_drag_source_set_icon (GtkWidget *widget,
2377 GdkColormap *colormap,
2381 GtkDragSourceSite *site;
2383 g_return_if_fail (GTK_IS_WIDGET (widget));
2384 g_return_if_fail (GDK_IS_COLORMAP (colormap));
2385 g_return_if_fail (GDK_IS_PIXMAP (pixmap));
2386 g_return_if_fail (!mask || GDK_IS_PIXMAP (mask));
2388 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2389 g_return_if_fail (site != NULL);
2391 g_object_ref (colormap);
2392 g_object_ref (pixmap);
2394 g_object_ref (mask);
2396 gtk_drag_source_unset_icon (site);
2398 site->icon_type = GTK_IMAGE_PIXMAP;
2400 site->icon_data.pixmap.pixmap = pixmap;
2401 site->icon_mask = mask;
2402 site->colormap = colormap;
2406 * gtk_drag_source_set_icon_pixbuf:
2407 * @widget: a #GtkWidget
2408 * @pixbuf: the #GdkPixbuf for the drag icon
2410 * Sets the icon that will be used for drags from a particular widget
2411 * from a #GdkPixbuf. GTK+ retains a reference for @pixbuf and will
2412 * release it when it is no longer needed.
2415 gtk_drag_source_set_icon_pixbuf (GtkWidget *widget,
2418 GtkDragSourceSite *site;
2420 g_return_if_fail (GTK_IS_WIDGET (widget));
2421 g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
2423 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2424 g_return_if_fail (site != NULL);
2425 g_object_ref (pixbuf);
2427 gtk_drag_source_unset_icon (site);
2429 site->icon_type = GTK_IMAGE_PIXBUF;
2430 site->icon_data.pixbuf.pixbuf = pixbuf;
2434 * gtk_drag_source_set_icon_stock:
2435 * @widget: a #GtkWidget
2436 * @stock_id: the ID of the stock icon to use
2438 * Sets the icon that will be used for drags from a particular source
2442 gtk_drag_source_set_icon_stock (GtkWidget *widget,
2443 const gchar *stock_id)
2445 GtkDragSourceSite *site;
2447 g_return_if_fail (GTK_IS_WIDGET (widget));
2448 g_return_if_fail (stock_id != NULL);
2450 site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2451 g_return_if_fail (site != NULL);
2453 gtk_drag_source_unset_icon (site);
2455 site->icon_type = GTK_IMAGE_STOCK;
2456 site->icon_data.stock.stock_id = g_strdup (stock_id);
2460 gtk_drag_get_icon (GtkDragSourceInfo *info,
2461 GtkWidget **icon_window,
2465 if (get_can_change_screen (info->icon_window))
2466 gtk_window_set_screen (GTK_WINDOW (info->icon_window),
2469 if (gtk_widget_get_screen (info->icon_window) != info->cur_screen)
2471 if (!info->fallback_icon)
2473 gint save_hot_x, save_hot_y;
2474 gboolean save_destroy_icon;
2475 GtkWidget *save_icon_window;
2477 /* HACK to get the appropriate icon
2479 save_icon_window = info->icon_window;
2480 save_hot_x = info->hot_x;
2481 save_hot_y = info->hot_x;
2482 save_destroy_icon = info->destroy_icon;
2484 info->icon_window = NULL;
2485 gtk_drag_set_icon_default (info->context);
2486 info->fallback_icon = info->icon_window;
2488 info->icon_window = save_icon_window;
2489 info->hot_x = save_hot_x;
2490 info->hot_y = save_hot_y;
2491 info->destroy_icon = save_destroy_icon;
2494 gtk_widget_hide (info->icon_window);
2496 *icon_window = info->fallback_icon;
2497 gtk_window_set_screen (GTK_WINDOW (*icon_window), info->cur_screen);
2499 if (!default_icon_pixmap)
2506 *hot_x = default_icon_hot_x;
2507 *hot_y = default_icon_hot_y;
2512 if (info->fallback_icon)
2513 gtk_widget_hide (info->fallback_icon);
2515 *icon_window = info->icon_window;
2516 *hot_x = info->hot_x;
2517 *hot_y = info->hot_y;
2522 gtk_drag_update_icon (GtkDragSourceInfo *info)
2524 if (info->icon_window)
2526 GtkWidget *icon_window;
2529 gtk_drag_get_icon (info, &icon_window, &hot_x, &hot_y);
2531 gtk_window_move (GTK_WINDOW (icon_window),
2532 info->cur_x - hot_x,
2533 info->cur_y - hot_y);
2535 if (GTK_WIDGET_VISIBLE (icon_window))
2536 gdk_window_raise (icon_window->window);
2538 gtk_widget_show (icon_window);
2543 gtk_drag_set_icon_window (GdkDragContext *context,
2547 gboolean destroy_on_release)
2549 GtkDragSourceInfo *info;
2551 info = gtk_drag_get_source_info (context, FALSE);
2552 gtk_drag_remove_icon (info);
2555 gtk_widget_ref (widget);
2557 info->icon_window = widget;
2558 info->hot_x = hot_x;
2559 info->hot_y = hot_y;
2560 info->destroy_icon = destroy_on_release;
2562 gtk_drag_update_icon (info);
2566 * gtk_drag_set_icon_widget:
2567 * @context: the context for a drag. (This must be called
2568 with a context for the source side of a drag)
2569 * @widget: a toplevel window to use as an icon.
2570 * @hot_x: the X offset within @widget of the hotspot.
2571 * @hot_y: the Y offset within @widget of the hotspot.
2573 * Changes the icon for a widget to a given widget. GTK+
2574 * will not destroy the icon, so if you don't want
2575 * it to persist, you should connect to the "drag_end"
2576 * signal and destroy it yourself.
2579 gtk_drag_set_icon_widget (GdkDragContext *context,
2584 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
2585 g_return_if_fail (context->is_source);
2586 g_return_if_fail (GTK_IS_WIDGET (widget));
2588 gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE);
2592 icon_window_realize (GtkWidget *window,
2598 gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf,
2599 gtk_widget_get_colormap (window),
2600 &pixmap, &mask, 128);
2602 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
2605 gtk_widget_shape_combine_mask (window, mask, 0, 0);
2607 g_object_unref (pixmap);
2610 g_object_unref (mask);
2614 set_icon_stock_pixbuf (GdkDragContext *context,
2615 const gchar *stock_id,
2624 g_return_if_fail (context != NULL);
2625 g_return_if_fail (pixbuf != NULL || stock_id != NULL);
2626 g_return_if_fail (pixbuf == NULL || stock_id == NULL);
2628 screen = gdk_drawable_get_screen (context->source_window);
2630 /* Push a NULL colormap to guard against gtk_widget_push_colormap() */
2631 gtk_widget_push_colormap (NULL);
2632 window = gtk_window_new (GTK_WINDOW_POPUP);
2633 gtk_window_set_screen (GTK_WINDOW (window), screen);
2634 set_can_change_screen (window, TRUE);
2635 gtk_widget_pop_colormap ();
2637 gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
2638 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
2642 pixbuf = gtk_widget_render_icon (window, stock_id,
2643 GTK_ICON_SIZE_DND, NULL);
2647 g_warning ("Cannot load drag icon from stock_id %s", stock_id);
2648 gtk_widget_destroy (window);
2654 g_object_ref (pixbuf);
2656 width = gdk_pixbuf_get_width (pixbuf);
2657 height = gdk_pixbuf_get_width (pixbuf);
2659 gtk_widget_set_size_request (window,
2660 gdk_pixbuf_get_width (pixbuf),
2661 gdk_pixbuf_get_height (pixbuf));
2663 g_signal_connect_closure (window, "realize",
2664 g_cclosure_new (G_CALLBACK (icon_window_realize),
2666 (GClosureNotify)g_object_unref),
2669 gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
2673 * gtk_drag_set_icon_pixbuf:
2674 * @context: the context for a drag. (This must be called
2675 * with a context for the source side of a drag)
2676 * @pixbuf: the #GdkPixbuf to use as the drag icon.
2677 * @hot_x: the X offset within @widget of the hotspot.
2678 * @hot_y: the Y offset within @widget of the hotspot.
2680 * Sets @pixbuf as the icon for a given drag.
2683 gtk_drag_set_icon_pixbuf (GdkDragContext *context,
2688 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
2689 g_return_if_fail (context->is_source);
2690 g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
2692 set_icon_stock_pixbuf (context, NULL, pixbuf, hot_x, hot_y);
2696 * gtk_drag_set_icon_stock:
2697 * @context: the context for a drag. (This must be called
2698 * with a context for the source side of a drag)
2699 * @stock_id: the ID of the stock icon to use for the drag.
2700 * @hot_x: the X offset within the icon of the hotspot.
2701 * @hot_y: the Y offset within the icon of the hotspot.
2703 * Sets the the icon for a given drag from a stock ID.
2706 gtk_drag_set_icon_stock (GdkDragContext *context,
2707 const gchar *stock_id,
2711 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
2712 g_return_if_fail (context->is_source);
2713 g_return_if_fail (stock_id != NULL);
2715 set_icon_stock_pixbuf (context, stock_id, NULL, hot_x, hot_y);
2719 * gtk_drag_set_icon_pixmap:
2720 * @context: the context for a drag. (This must be called
2721 * with a context for the source side of a drag)
2722 * @colormap: the colormap of the icon
2723 * @pixmap: the image data for the icon
2724 * @mask: the transparency mask for the icon
2725 * @hot_x: the X offset within @pixmap of the hotspot.
2726 * @hot_y: the Y offset within @pixmap of the hotspot.
2728 * Sets @pixmap as the icon for a given drag. GTK+ retains
2729 * references for the arguments, and will release them when
2730 * they are no longer needed. In general, gtk_drag_set_icon_pixbuf()
2731 * will be more convenient to use.
2734 gtk_drag_set_icon_pixmap (GdkDragContext *context,
2735 GdkColormap *colormap,
2745 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
2746 g_return_if_fail (context->is_source);
2747 g_return_if_fail (GDK_IS_COLORMAP (colormap));
2748 g_return_if_fail (GDK_IS_PIXMAP (pixmap));
2749 g_return_if_fail (!mask || GDK_IS_PIXMAP (mask));
2751 screen = gdk_colormap_get_screen (colormap);
2753 g_return_if_fail (gdk_drawable_get_screen (pixmap) == screen);
2754 g_return_if_fail (!mask || gdk_drawable_get_screen (mask) == screen);
2756 gdk_drawable_get_size (pixmap, &width, &height);
2758 gtk_widget_push_colormap (colormap);
2760 window = gtk_window_new (GTK_WINDOW_POPUP);
2761 gtk_window_set_screen (GTK_WINDOW (window), screen);
2762 set_can_change_screen (window, FALSE);
2763 gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
2764 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
2766 gtk_widget_pop_colormap ();
2768 gtk_widget_set_size_request (window, width, height);
2769 gtk_widget_realize (window);
2771 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
2774 gtk_widget_shape_combine_mask (window, mask, 0, 0);
2776 gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
2780 * gtk_drag_set_icon_default:
2781 * @context: the context for a drag. (This must be called
2782 with a context for the source side of a drag)
2784 * Sets the icon for a particular drag to the default
2788 gtk_drag_set_icon_default (GdkDragContext *context)
2790 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
2791 g_return_if_fail (context->is_source);
2793 if (!default_icon_pixmap)
2794 gtk_drag_set_icon_stock (context, GTK_STOCK_DND, -2, -2);
2796 gtk_drag_set_icon_pixmap (context,
2797 default_icon_colormap,
2798 default_icon_pixmap,
2801 default_icon_hot_y);
2805 * gtk_drag_set_default_icon:
2806 * @colormap: the colormap of the icon
2807 * @pixmap: the image data for the icon
2808 * @mask: the transparency mask for an image.
2809 * @hot_x: The X offset within @widget of the hotspot.
2810 * @hot_y: The Y offset within @widget of the hotspot.
2812 * Changes the default drag icon. GTK+ retains references for the
2813 * arguments, and will release them when they are no longer needed.
2814 * This function is obsolete. The default icon should now be changed
2815 * via the stock system by changing the stock pixbuf for #GTK_STOCK_DND.
2818 gtk_drag_set_default_icon (GdkColormap *colormap,
2824 g_return_if_fail (GDK_IS_COLORMAP (colormap));
2825 g_return_if_fail (GDK_IS_PIXMAP (pixmap));
2826 g_return_if_fail (!mask || GDK_IS_PIXMAP (mask));
2828 if (default_icon_colormap)
2829 g_object_unref (default_icon_colormap);
2830 if (default_icon_pixmap)
2831 g_object_unref (default_icon_pixmap);
2832 if (default_icon_mask)
2833 g_object_unref (default_icon_mask);
2835 default_icon_colormap = colormap;
2836 g_object_ref (colormap);
2838 default_icon_pixmap = pixmap;
2839 g_object_ref (pixmap);
2841 default_icon_mask = mask;
2843 g_object_ref (mask);
2845 default_icon_hot_x = hot_x;
2846 default_icon_hot_y = hot_y;
2850 /*************************************************************
2851 * _gtk_drag_source_handle_event:
2852 * Called from widget event handling code on Drag events
2856 * toplevel: Toplevel widget that received the event
2859 *************************************************************/
2862 _gtk_drag_source_handle_event (GtkWidget *widget,
2865 GtkDragSourceInfo *info;
2866 GdkDragContext *context;
2868 g_return_if_fail (widget != NULL);
2869 g_return_if_fail (event != NULL);
2871 context = event->dnd.context;
2872 info = gtk_drag_get_source_info (context, FALSE);
2876 switch (event->type)
2878 case GDK_DRAG_STATUS:
2882 if (info->proxy_dest)
2884 if (!event->dnd.send_event)
2886 if (info->proxy_dest->proxy_drop_wait)
2888 gboolean result = context->action != 0;
2890 /* Aha - we can finally pass the MOTIF DROP on... */
2891 gdk_drop_reply (info->proxy_dest->context, result, info->proxy_dest->proxy_drop_time);
2893 gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
2895 gtk_drag_finish (info->proxy_dest->context, FALSE, FALSE, info->proxy_dest->proxy_drop_time);
2899 gdk_drag_status (info->proxy_dest->context,
2900 event->dnd.context->action,
2905 else if (info->have_grab)
2907 cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget),
2908 event->dnd.context->action);
2909 if (info->cursor != cursor)
2911 gdk_pointer_grab (widget->window, FALSE,
2912 GDK_POINTER_MOTION_MASK |
2913 GDK_BUTTON_RELEASE_MASK,
2915 cursor, info->grab_time);
2916 info->cursor = cursor;
2919 if (info->last_event)
2920 gtk_drag_add_update_idle (info);
2925 case GDK_DROP_FINISHED:
2926 gtk_drag_drop_finished (info, TRUE, event->dnd.time);
2929 g_assert_not_reached ();
2933 /*************************************************************
2934 * gtk_drag_source_check_selection:
2935 * Check if we've set up handlers/claimed the selection
2936 * for a given drag. If not, add them.
2940 *************************************************************/
2943 gtk_drag_source_check_selection (GtkDragSourceInfo *info,
2949 tmp_list = info->selections;
2952 if (GDK_POINTER_TO_ATOM (tmp_list->data) == selection)
2954 tmp_list = tmp_list->next;
2957 gtk_selection_owner_set_for_display (gtk_widget_get_display (info->widget),
2961 info->selections = g_list_prepend (info->selections,
2962 GUINT_TO_POINTER (selection));
2964 tmp_list = info->target_list->list;
2967 GtkTargetPair *pair = tmp_list->data;
2969 gtk_selection_add_target (info->ipc_widget,
2973 tmp_list = tmp_list->next;
2976 if (info->context->protocol == GDK_DRAG_PROTO_MOTIF)
2978 gtk_selection_add_target (info->ipc_widget,
2980 gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE),
2981 TARGET_MOTIF_SUCCESS);
2982 gtk_selection_add_target (info->ipc_widget,
2984 gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE),
2985 TARGET_MOTIF_FAILURE);
2988 gtk_selection_add_target (info->ipc_widget,
2990 gdk_atom_intern ("DELETE", FALSE),
2994 /*************************************************************
2995 * gtk_drag_drop_finished:
2996 * Clean up from the drag, and display snapback, if necessary.
3002 *************************************************************/
3005 gtk_drag_drop_finished (GtkDragSourceInfo *info,
3009 gtk_drag_source_release_selections (info, time);
3011 if (info->proxy_dest)
3013 /* The time from the event isn't reliable for Xdnd drags */
3014 gtk_drag_finish (info->proxy_dest->context, success, FALSE,
3015 info->proxy_dest->proxy_drop_time);
3016 gtk_drag_source_info_destroy (info);
3022 gtk_drag_source_info_destroy (info);
3026 GtkDragAnim *anim = g_new (GtkDragAnim, 1);
3030 anim->n_steps = MAX (info->cur_x - info->start_x,
3031 info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
3032 anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
3034 info->cur_screen = gtk_widget_get_screen (info->widget);
3035 gtk_drag_update_icon (info);
3037 /* Mark the context as dead, so if the destination decides
3038 * to respond really late, we still are OK.
3040 gtk_drag_clear_source_info (info->context);
3041 g_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
3047 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
3050 GdkDisplay *display = gtk_widget_get_display (info->widget);
3051 GList *tmp_list = info->selections;
3055 GdkAtom selection = GDK_POINTER_TO_ATOM (tmp_list->data);
3056 if (gdk_selection_owner_get_for_display (display, selection) == info->ipc_widget->window)
3057 gtk_selection_owner_set_for_display (display, NULL, selection, time);
3059 tmp_list = tmp_list->next;
3062 g_list_free (info->selections);
3063 info->selections = NULL;
3066 /*************************************************************
3068 * Send a drop event.
3072 *************************************************************/
3075 gtk_drag_drop (GtkDragSourceInfo *info,
3078 if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN)
3080 GtkSelectionData selection_data;
3082 /* GTK+ traditionally has used application/x-rootwin-drop, but the
3083 * XDND spec specifies x-rootwindow-drop.
3085 GdkAtom target1 = gdk_atom_intern ("application/x-rootwindow-drop", FALSE);
3086 GdkAtom target2 = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
3088 tmp_list = info->target_list->list;
3091 GtkTargetPair *pair = tmp_list->data;
3093 if (pair->target == target1 || pair->target == target2)
3095 selection_data.selection = GDK_NONE;
3096 selection_data.target = pair->target;
3097 selection_data.data = NULL;
3098 selection_data.length = -1;
3100 g_signal_emit_by_name (info->widget, "drag_data_get",
3101 info->context, &selection_data,
3105 /* FIXME: Should we check for length >= 0 here? */
3106 gtk_drag_drop_finished (info, TRUE, time);
3109 tmp_list = tmp_list->next;
3111 gtk_drag_drop_finished (info, FALSE, time);
3115 if (info->icon_window)
3116 gtk_widget_hide (info->icon_window);
3118 gdk_drag_drop (info->context, time);
3119 info->drop_timeout = g_timeout_add (DROP_ABORT_TIME,
3120 gtk_drag_abort_timeout,
3126 * Source side callbacks.
3130 gtk_drag_source_event_cb (GtkWidget *widget,
3134 GtkDragSourceSite *site;
3135 gboolean retval = FALSE;
3136 site = (GtkDragSourceSite *)data;
3138 switch (event->type)
3140 case GDK_BUTTON_PRESS:
3141 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
3143 site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1));
3144 site->x = event->button.x;
3145 site->y = event->button.y;
3149 case GDK_BUTTON_RELEASE:
3150 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
3151 site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1));
3154 case GDK_MOTION_NOTIFY:
3155 if (site->state & event->motion.state & site->start_button_mask)
3157 /* FIXME: This is really broken and can leave us
3163 if (site->state & event->motion.state &
3164 GDK_BUTTON1_MASK << (i - 1))
3168 if (gtk_drag_check_threshold (widget, site->x, site->y,
3169 event->motion.x, event->motion.y))
3171 GdkDragContext *context;
3174 context = gtk_drag_begin_internal (widget, site, site->target_list,
3183 default: /* hit for 2/3BUTTON_PRESS */
3191 gtk_drag_source_site_destroy (gpointer data)
3193 GtkDragSourceSite *site = data;
3195 if (site->target_list)
3196 gtk_target_list_unref (site->target_list);
3198 gtk_drag_source_unset_icon (site);
3203 gtk_drag_selection_get (GtkWidget *widget,
3204 GtkSelectionData *selection_data,
3209 GtkDragSourceInfo *info = data;
3210 static GdkAtom null_atom = GDK_NONE;
3214 null_atom = gdk_atom_intern ("NULL", FALSE);
3219 g_signal_emit_by_name (info->widget,
3222 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
3224 case TARGET_MOTIF_SUCCESS:
3225 gtk_drag_drop_finished (info, TRUE, time);
3226 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
3228 case TARGET_MOTIF_FAILURE:
3229 gtk_drag_drop_finished (info, FALSE, time);
3230 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
3233 if (info->proxy_dest)
3235 /* This is sort of dangerous and needs to be thought
3238 info->proxy_dest->proxy_data = selection_data;
3239 gtk_drag_get_data (info->widget,
3240 info->proxy_dest->context,
3241 selection_data->target,
3244 info->proxy_dest->proxy_data = NULL;
3248 if (gtk_target_list_find (info->target_list,
3249 selection_data->target,
3252 g_signal_emit_by_name (info->widget, "drag_data_get",
3264 gtk_drag_anim_timeout (gpointer data)
3266 GtkDragAnim *anim = data;
3270 GDK_THREADS_ENTER ();
3272 if (anim->step == anim->n_steps)
3274 gtk_drag_source_info_destroy (anim->info);
3281 x = (anim->info->start_x * (anim->step + 1) +
3282 anim->info->cur_x * (anim->n_steps - anim->step - 1)) / anim->n_steps;
3283 y = (anim->info->start_y * (anim->step + 1) +
3284 anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
3285 if (anim->info->icon_window)
3287 GtkWidget *icon_window;
3290 gtk_drag_get_icon (anim->info, &icon_window, &hot_x, &hot_y);
3292 gtk_window_move (GTK_WINDOW (icon_window),
3302 GDK_THREADS_LEAVE ();
3308 gtk_drag_remove_icon (GtkDragSourceInfo *info)
3310 if (info->icon_window)
3312 gtk_widget_hide (info->icon_window);
3313 if (info->destroy_icon)
3314 gtk_widget_destroy (info->icon_window);
3316 if (info->fallback_icon)
3318 gtk_widget_destroy (info->fallback_icon);
3319 info->fallback_icon = NULL;
3322 g_object_unref (info->icon_window);
3323 info->icon_window = NULL;
3328 gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
3330 gtk_drag_remove_icon (info);
3332 if (!info->proxy_dest)
3333 g_signal_emit_by_name (info->widget, "drag_end",
3337 g_object_unref (info->widget);
3340 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3341 gtk_drag_button_release_cb,
3343 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3346 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3349 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3350 gtk_drag_selection_get,
3353 gtk_selection_remove_all (info->ipc_widget);
3354 g_object_set_data (G_OBJECT (info->ipc_widget), "gtk-info", NULL);
3355 source_widgets = g_slist_remove (source_widgets, info->ipc_widget);
3356 gtk_drag_release_ipc_widget (info->ipc_widget);
3358 gtk_target_list_unref (info->target_list);
3360 gtk_drag_clear_source_info (info->context);
3361 g_object_unref (info->context);
3363 if (info->drop_timeout)
3364 g_source_remove (info->drop_timeout);
3370 gtk_drag_update_idle (gpointer data)
3372 GtkDragSourceInfo *info = data;
3373 GdkWindow *dest_window;
3374 GdkDragProtocol protocol;
3377 GdkDragAction action;
3378 GdkDragAction possible_actions;
3381 GDK_THREADS_ENTER ();
3383 info->update_idle = 0;
3385 time = gtk_drag_get_event_time (info->last_event);
3386 gtk_drag_get_event_actions (info->last_event,
3388 info->possible_actions,
3389 &action, &possible_actions);
3390 gtk_drag_update_icon (info);
3391 gdk_drag_find_window_for_screen (info->context,
3392 info->icon_window ? info->icon_window->window : NULL,
3393 info->cur_screen, info->cur_x, info->cur_y,
3394 &dest_window, &protocol);
3396 if (!gdk_drag_motion (info->context, dest_window, protocol,
3397 info->cur_x, info->cur_y, action,
3401 gdk_event_free ((GdkEvent *)info->last_event);
3402 info->last_event = NULL;
3406 g_object_unref (dest_window);
3408 selection = gdk_drag_get_selection (info->context);
3410 gtk_drag_source_check_selection (info, selection, time);
3412 GDK_THREADS_LEAVE ();
3418 gtk_drag_add_update_idle (GtkDragSourceInfo *info)
3420 /* We use an idle lowerthan GDK_PRIORITY_REDRAW so that exposes
3421 * from the last move can catch up before we move again.
3423 if (!info->update_idle)
3424 info->update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW + 5,
3425 gtk_drag_update_idle,
3432 * @info: DragSourceInfo for the drag
3433 * @screen: new screen
3434 * @x_root: new X position
3435 * @y_root: new y position
3436 * @event: event received requiring update
3438 * Updates the status of the drag; called when the
3439 * cursor moves or the modifier changes
3442 gtk_drag_update (GtkDragSourceInfo *info,
3448 info->cur_screen = screen;
3449 info->cur_x = x_root;
3450 info->cur_y = y_root;
3451 if (info->last_event)
3452 gdk_event_free ((GdkEvent *)info->last_event);
3453 info->last_event = gdk_event_copy ((GdkEvent *)event);
3455 gtk_drag_add_update_idle (info);
3458 /*************************************************************
3460 * Called when the user finishes to drag, either by
3461 * releasing the mouse, or by pressing Esc.
3463 * info: Source info for the drag
3464 * time: Timestamp for ending the drag
3466 *************************************************************/
3469 gtk_drag_end (GtkDragSourceInfo *info, guint32 time)
3471 GdkEvent *send_event;
3472 GtkWidget *source_widget = info->widget;
3473 GdkDisplay *display = gtk_widget_get_display (source_widget);
3475 if (info->update_idle)
3477 g_source_remove (info->update_idle);
3478 info->update_idle = 0;
3481 if (info->last_event)
3483 gdk_event_free (info->last_event);
3484 info->last_event = NULL;
3487 info->have_grab = FALSE;
3489 gdk_display_pointer_ungrab (display, time);
3490 gdk_display_keyboard_ungrab (display, time);
3491 gtk_grab_remove (info->ipc_widget);
3493 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3494 gtk_drag_button_release_cb,
3496 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3499 g_signal_handlers_disconnect_by_func (info->ipc_widget,
3503 /* Send on a release pair to the the original
3504 * widget to convince it to release its grab. We need to
3505 * call gtk_propagate_event() here, instead of
3506 * gtk_widget_event() because widget like GtkList may
3507 * expect propagation.
3510 send_event = gdk_event_new (GDK_BUTTON_RELEASE);
3511 send_event->button.window = g_object_ref (gtk_widget_get_root_window (source_widget));
3512 send_event->button.send_event = TRUE;
3513 send_event->button.time = time;
3514 send_event->button.x = 0;
3515 send_event->button.y = 0;
3516 send_event->button.axes = NULL;
3517 send_event->button.state = 0;
3518 send_event->button.button = info->button;
3519 send_event->button.device = gdk_display_get_core_pointer (display);
3520 send_event->button.x_root = 0;
3521 send_event->button.y_root = 0;
3523 gtk_propagate_event (source_widget, send_event);
3524 gdk_event_free (send_event);
3527 /*************************************************************
3529 * Called on cancellation of a drag, either by the user
3530 * or programmatically.
3532 * info: Source info for the drag
3533 * time: Timestamp for ending the drag
3535 *************************************************************/
3538 gtk_drag_cancel (GtkDragSourceInfo *info, guint32 time)
3540 gtk_drag_end (info, time);
3541 gdk_drag_abort (info->context, time);
3542 gtk_drag_drop_finished (info, FALSE, time);
3545 /*************************************************************
3546 * gtk_drag_motion_cb:
3547 * "motion_notify_event" callback during drag.
3551 *************************************************************/
3554 gtk_drag_motion_cb (GtkWidget *widget,
3555 GdkEventMotion *event,
3558 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
3560 gint x_root, y_root;
3564 GdkDisplay *display = gtk_widget_get_display (widget);
3566 gdk_display_get_pointer (display, &screen, &x_root, &y_root, NULL);
3567 event->x_root = x_root;
3568 event->y_root = y_root;
3571 screen = gdk_event_get_screen ((GdkEvent *)event);
3573 gtk_drag_update (info, screen, event->x_root, event->y_root, (GdkEvent *)event);
3578 /*************************************************************
3580 * "key_press/release_event" callback during drag.
3584 *************************************************************/
3587 gtk_drag_key_cb (GtkWidget *widget,
3591 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
3592 GdkModifierType state;
3593 GdkWindow *root_window;
3595 if (event->type == GDK_KEY_PRESS)
3597 if (event->keyval == GDK_Escape)
3599 gtk_drag_cancel (info, event->time);
3605 /* Now send a "motion" so that the modifier state is updated */
3607 /* The state is not yet updated in the event, so we need
3608 * to query it here. We could use XGetModifierMapping, but
3609 * that would be overkill.
3611 root_window = gtk_widget_get_root_window (widget);
3612 gdk_window_get_pointer (root_window, NULL, NULL, &state);
3614 event->state = state;
3615 gtk_drag_update (info, info->cur_screen, info->cur_x, info->cur_y, (GdkEvent *)event);
3620 /*************************************************************
3621 * gtk_drag_button_release_cb:
3622 * "button_release_event" callback during drag.
3626 *************************************************************/
3629 gtk_drag_button_release_cb (GtkWidget *widget,
3630 GdkEventButton *event,
3633 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
3635 if (event->button != info->button)
3638 if ((info->context->action != 0) && (info->context->dest_window != NULL))
3640 gtk_drag_end (info, event->time);
3641 gtk_drag_drop (info, event->time);
3645 gtk_drag_cancel (info, event->time);
3652 gtk_drag_abort_timeout (gpointer data)
3654 GtkDragSourceInfo *info = data;
3655 guint32 time = GDK_CURRENT_TIME;
3657 GDK_THREADS_ENTER ();
3659 if (info->proxy_dest)
3660 time = info->proxy_dest->proxy_drop_time;
3662 info->drop_timeout = 0;
3663 gtk_drag_drop_finished (info, FALSE, time);
3665 GDK_THREADS_LEAVE ();
3671 * gtk_drag_check_threshold:
3672 * @widget: a #GtkWidget
3673 * @start_x: X coordinate of start of drag
3674 * @start_y: Y coordinate of start of drag
3675 * @current_x: current X coordinate
3676 * @current_y: current Y coordinate
3678 * Checks to see if a mouse drag starting at (@start_x, @start_y) and ending
3679 * at (@current_x, @current_y) has passed the GTK+ drag threshold, and thus
3680 * should trigger the beginning of a drag-and-drop operation.
3682 * Return Value: %TRUE if the drag threshold has been passed.
3685 gtk_drag_check_threshold (GtkWidget *widget,
3691 gint drag_threshold;
3693 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
3695 g_object_get (gtk_widget_get_settings (widget),
3696 "gtk-dnd-drag-threshold", &drag_threshold,
3699 return (ABS (current_x - start_x) > drag_threshold ||
3700 ABS (current_y - start_y) > drag_threshold);