1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
23 #include "gtkinvisible.h"
25 #include "gtksignal.h"
26 #include "gtkwindow.h"
28 static GSList *drag_widgets = NULL;
30 typedef struct _GtkDragSourceSite GtkDragSourceSite;
31 typedef struct _GtkDragSourceInfo GtkDragSourceInfo;
32 typedef struct _GtkDragDestSite GtkDragDestSite;
33 typedef struct _GtkDragDestInfo GtkDragDestInfo;
34 typedef struct _GtkDragAnim GtkDragAnim;
35 typedef struct _GtkDragFindData GtkDragFindData;
44 struct _GtkDragSourceSite {
45 GdkModifierType start_button_mask;
46 GtkTargetList *target_list; /* Targets for drag data */
47 GdkDragAction actions; /* Possible actions */
48 GdkColormap *colormap; /* Colormap for drag icon */
49 GdkPixmap *pixmap; /* Icon for drag data */
52 /* Stored button press information to detect drag beginning */
57 struct _GtkDragSourceInfo {
59 GtkTargetList *target_list; /* Targets for drag data */
60 GdkDragContext *context; /* drag context */
61 GtkWidget *icon_window; /* Window for drag */
62 GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */
63 GdkCursor *cursor; /* Cursor for drag */
64 gint hot_x, hot_y; /* Hot spot for drag */
65 gint button; /* mouse button starting drag */
67 GtkDragStatus status; /* drag status */
68 GdkEvent *last_event; /* motion event waiting for response */
70 gint start_x, start_y; /* Initial position */
71 gint cur_x, cur_y; /* Current Position */
73 GList *selections; /* selections we've claimed */
75 GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */
77 guint drop_timeout; /* Timeout for aborting drop */
80 struct _GtkDragDestSite {
81 GtkDestDefaults flags;
82 GtkTargetList *target_list;
83 GdkDragAction actions;
84 GdkWindow *proxy_window;
85 GdkDragProtocol proxy_protocol;
86 gboolean proxy_coords : 1;
87 gboolean have_drag : 1;
90 struct _GtkDragDestInfo {
91 GtkWidget *widget; /* Widget in which drag is in */
92 GdkDragContext *context; /* Drag context */
93 GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */
94 GtkSelectionData *proxy_data; /* Set while retrieving proxied data */
95 gboolean dropped : 1; /* Set after we receive a drop */
96 guint32 proxy_drop_time; /* Timestamp for proxied drop */
97 gboolean proxy_drop_wait : 1; /* Set if we are waiting for a
98 * status reply before sending
101 gint drop_x, drop_y; /* Position of drop */
104 #define DROP_ABORT_TIME 10000
106 #define ANIM_STEP_TIME 50
107 #define ANIM_STEP_LENGTH 50
108 #define ANIM_MIN_STEPS 5
109 #define ANIM_MAX_STEPS 10
111 struct _GtkDragAnim {
112 GtkDragSourceInfo *info;
117 struct _GtkDragFindData {
120 GdkDragContext *context;
121 GtkDragDestInfo *info;
123 gboolean (*callback) (GtkWidget *widget, GdkDragContext *context,
124 gint x, gint y, guint32 time);
128 /* Enumeration for some targets we handle internally */
131 TARGET_MOTIF_SUCCESS = 0x80000000,
132 TARGET_MOTIF_FAILURE,
138 static GdkPixmap *default_icon_pixmap = NULL;
139 static GdkPixmap *default_icon_mask = NULL;
140 static GdkColormap *default_icon_colormap = NULL;
141 static gint default_icon_hot_x;
142 static gint default_icon_hot_y;
144 /* Forward declarations */
145 static GdkDragAction gtk_drag_get_event_action (GdkEvent *event,
147 GdkDragAction actions);
148 static GdkCursor * gtk_drag_get_cursor (GdkDragAction action);
149 static GtkWidget *gtk_drag_get_ipc_widget (void);
150 static void gtk_drag_release_ipc_widget (GtkWidget *widget);
152 static GdkAtom gtk_drag_dest_find_target (GtkDragDestSite *site,
153 GdkDragContext *context);
154 static void gtk_drag_selection_received (GtkWidget *widget,
155 GtkSelectionData *selection_data,
158 static void gtk_drag_find_widget (GtkWidget *widget,
159 GtkDragFindData *data);
160 static void gtk_drag_proxy_begin (GtkWidget *widget,
161 GtkDragDestInfo *dest_info);
162 static void gtk_drag_dest_info_destroy (gpointer data);
163 static void gtk_drag_dest_realized (GtkWidget *widget);
164 static void gtk_drag_dest_site_destroy (gpointer data);
165 static void gtk_drag_dest_leave (GtkWidget *widget,
166 GdkDragContext *context,
168 static gboolean gtk_drag_dest_motion (GtkWidget *widget,
169 GdkDragContext *context,
173 static gboolean gtk_drag_dest_drop (GtkWidget *widget,
174 GdkDragContext *context,
179 static void gtk_drag_source_check_selection (GtkDragSourceInfo *info,
182 static void gtk_drag_source_release_selections (GtkDragSourceInfo *info,
184 static void gtk_drag_drop (GtkDragSourceInfo *info,
186 static void gtk_drag_drop_finished (GtkDragSourceInfo *info,
190 static gint gtk_drag_source_event_cb (GtkWidget *widget,
193 static void gtk_drag_source_site_destroy (gpointer data);
194 static void gtk_drag_selection_get (GtkWidget *widget,
195 GtkSelectionData *selection_data,
199 static gint gtk_drag_anim_timeout (gpointer data);
200 static void gtk_drag_remove_icon (GtkDragSourceInfo *info);
201 static void gtk_drag_source_info_destroy (gpointer data);
202 static gint gtk_drag_motion_cb (GtkWidget *widget,
203 GdkEventMotion *event,
205 static gint gtk_drag_button_release_cb (GtkWidget *widget,
206 GdkEventButton *event,
208 static gint gtk_drag_abort_timeout (gpointer data);
210 /************************
211 * Cursor and Icon data *
212 ************************/
214 #define action_ask_width 16
215 #define action_ask_height 16
216 static char action_ask_bits[] = {
217 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xf8, 0xb6, 0xf7,
218 0xd6, 0xec, 0x66, 0xdb, 0x66, 0xdb, 0x96, 0xec, 0x76, 0xf7, 0x76, 0xfb,
219 0xf6, 0xfc, 0x72, 0xfb, 0x7a, 0xfb, 0xf8, 0xfc, };
221 #define action_ask_mask_width 16
222 #define action_ask_mask_height 16
223 static char action_ask_mask_bits[] = {
224 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0xcf, 0x0f,
225 0xef, 0x1f, 0xff, 0x3c, 0xff, 0x3c, 0x6f, 0x1f, 0x8f, 0x0f, 0x8f, 0x07,
226 0x0f, 0x03, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x03, };
228 #define action_copy_width 16
229 #define action_copy_height 16
230 static char action_copy_bits[] = {
231 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xfb, 0x76, 0xfb,
232 0x76, 0xfb, 0x06, 0x83, 0xf6, 0xbf, 0xf6, 0xbf, 0x06, 0x83, 0x76, 0xfb,
233 0x76, 0xfb, 0x72, 0xfb, 0x7a, 0xf8, 0xf8, 0xff, };
235 #define action_copy_mask_width 16
236 #define action_copy_mask_height 16
237 static char action_copy_mask_bits[] = {
238 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0x8f, 0x07,
239 0x8f, 0x07, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x8f, 0x07,
240 0x8f, 0x07, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x00, };
242 #define action_move_width 16
243 #define action_move_height 16
244 static char action_move_bits[] = {
245 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x96, 0xff, 0x26, 0xff,
246 0xc6, 0xf8, 0xd6, 0xe3, 0x96, 0x8f, 0xb6, 0xbf, 0x36, 0xc3, 0x76, 0xfb,
247 0x76, 0xfa, 0xf2, 0xfa, 0xfa, 0xf8, 0xf8, 0xff, };
249 #define action_move_mask_width 16
250 #define action_move_mask_height 16
251 static char action_move_mask_bits[] = {
252 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x6f, 0x00, 0xff, 0x00,
253 0xff, 0x07, 0xef, 0x1f, 0xef, 0x7f, 0xcf, 0x7f, 0xcf, 0x3f, 0x8f, 0x07,
254 0x8f, 0x07, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x00, };
256 #define action_link_width 16
257 #define action_link_height 16
258 static char action_link_bits[] = {
259 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x36, 0xf8, 0xd6, 0xf7,
260 0x66, 0xec, 0xa6, 0xe8, 0x26, 0xdf, 0xe6, 0xbd, 0xd6, 0xa7, 0xb6, 0xa8,
261 0xb6, 0xb1, 0x72, 0xdf, 0xfa, 0xe0, 0xf8, 0xff, };
263 #define action_link_mask_width 16
264 #define action_link_mask_height 16
265 static char action_link_mask_bits[] = {
266 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xcf, 0x07, 0xef, 0x0f,
267 0xff, 0x1f, 0x7f, 0x1f, 0xff, 0x3f, 0xff, 0x7f, 0xef, 0x7f, 0xcf, 0x77,
268 0xcf, 0x7f, 0x8f, 0x3f, 0x07, 0x1f, 0x07, 0x00, };
270 #define action_none_width 16
271 #define action_none_height 16
272 static char action_none_bits[] = {
273 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0xf6, 0xff, 0xf6, 0xff,
274 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff,
275 0xf6, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf8, 0xff, };
277 #define action_none_mask_width 16
278 #define action_none_mask_height 16
279 static char action_none_mask_bits[] = {
280 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x0f, 0x00,
281 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00,
282 0x0f, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x07, 0x00, };
284 static char empty_bits[] = {
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
289 #define CURSOR_WIDTH 16
290 #define CURSOR_HEIGHT 16
293 GdkDragAction action;
298 { GDK_ACTION_DEFAULT, 0 },
299 { GDK_ACTION_ASK, action_ask_bits, action_ask_mask_bits, NULL },
300 { GDK_ACTION_COPY, action_copy_bits, action_copy_mask_bits, NULL },
301 { GDK_ACTION_MOVE, action_move_bits, action_move_mask_bits, NULL },
302 { GDK_ACTION_LINK, action_link_bits, action_link_mask_bits, NULL },
303 { 0 , action_none_bits, action_none_mask_bits, NULL },
306 static gint n_drag_cursors = sizeof(drag_cursors) / sizeof(drag_cursors[0]);
309 static char * drag_default_xpm[] = {
322 " ...+++++++++++.. ",
323 " ..+.++++++++++++.. ",
324 " .++.++++++++++++.. ",
325 " .+++.++++++++++++.. ",
326 " .++++.++++++++++++. ",
327 " .+++.+++++++++++++.. ",
328 " .++.+++++++++++++++.. ",
329 " .+.+++++++++++++++++.. ",
330 " ..+++++++++++++++++++.. ",
331 " ..++++++++++++++++++++. ",
332 " .++++++++++++++++++++.. ",
333 " ..+++++++++++++++++.. ",
334 " .++++++++++++++++.. ",
335 " ..+++++++++++++... ",
347 /*********************
348 * Utility functions *
349 *********************/
351 /*************************************************************
352 * gtk_drag_get_ipc_widget:
353 * Return a invisible, off-screen, override-redirect
358 *************************************************************/
361 gtk_drag_get_ipc_widget(void)
367 GSList *tmp = drag_widgets;
368 result = drag_widgets->data;
369 drag_widgets = drag_widgets->next;
370 g_slist_free_1 (tmp);
374 result = gtk_invisible_new();
375 gtk_widget_show (result);
381 /*************************************************************
382 * gtk_drag_release_ipc_widget:
383 * Releases widget retrieved with gtk_drag_get_ipc_widget()
385 * widget: the widget to release.
387 *************************************************************/
390 gtk_drag_release_ipc_widget (GtkWidget *widget)
392 drag_widgets = g_slist_prepend (drag_widgets, widget);
396 gtk_drag_get_event_action (GdkEvent *event, gint button, GdkDragAction actions)
400 GdkModifierType state = 0;
404 case GDK_MOTION_NOTIFY:
405 state = event->motion.state;
407 case GDK_BUTTON_PRESS:
408 case GDK_2BUTTON_PRESS:
409 case GDK_3BUTTON_PRESS:
410 case GDK_BUTTON_RELEASE:
411 state = event->button.state;
414 case GDK_KEY_RELEASE:
415 state = event->key.state;
417 case GDK_ENTER_NOTIFY:
418 case GDK_LEAVE_NOTIFY:
419 state = event->crossing.state;
426 return GDK_ACTION_ASK;
428 if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
430 if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
431 return (actions & GDK_ACTION_LINK) ? GDK_ACTION_LINK : 0;
432 else if (state & GDK_CONTROL_MASK)
433 return (actions & GDK_ACTION_COPY) ? GDK_ACTION_COPY : 0;
435 return (actions & GDK_ACTION_MOVE) ? GDK_ACTION_MOVE : 0;
439 if (actions & GDK_ACTION_COPY)
440 return GDK_ACTION_COPY;
441 else if (actions & GDK_ACTION_MOVE)
442 return GDK_ACTION_MOVE;
443 else if (actions & GDK_ACTION_LINK)
444 return GDK_ACTION_LINK;
452 gtk_drag_get_cursor (GdkDragAction action)
456 for (i = 0 ; i < n_drag_cursors - 1; i++)
457 if (drag_cursors[i].action == action)
460 if (drag_cursors[i].cursor == NULL)
465 gdk_bitmap_create_from_data (NULL,
466 drag_cursors[i].bits,
467 CURSOR_WIDTH, CURSOR_HEIGHT);
469 gdk_bitmap_create_from_data (NULL,
470 drag_cursors[i].mask,
471 CURSOR_WIDTH, CURSOR_HEIGHT);
473 gdk_color_white (gdk_colormap_get_system(), &bg);
474 gdk_color_black (gdk_colormap_get_system(), &fg);
476 drag_cursors[i].cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, 0, 0);
478 gdk_pixmap_unref (pixmap);
479 gdk_pixmap_unref (mask);
482 return drag_cursors[i].cursor;
485 /********************
487 ********************/
489 /*************************************************************
491 * Get the data for a drag or drop
493 * context - drag context
494 * target - format to retrieve the data in.
495 * time - timestamp of triggering event.
498 *************************************************************/
501 gtk_drag_get_data (GtkWidget *widget,
502 GdkDragContext *context,
506 GtkWidget *selection_widget;
508 g_return_if_fail (widget != NULL);
509 g_return_if_fail (context != NULL);
511 selection_widget = gtk_drag_get_ipc_widget();
513 gdk_drag_context_ref (context);
514 gtk_widget_ref (widget);
516 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
517 GTK_SIGNAL_FUNC (gtk_drag_selection_received), widget);
519 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
521 gtk_selection_convert (selection_widget,
522 gdk_drag_get_selection(context),
527 /*************************************************************
529 * Notify the drag source that the transfer of data
532 * context: The drag context for this drag
533 * success: Was the data successfully transferred?
534 * time: The timestamp to use when notifying the destination.
536 *************************************************************/
539 gtk_drag_finish (GdkDragContext *context,
544 GdkAtom target = GDK_NONE;
546 g_return_if_fail (context != NULL);
550 target = gdk_atom_intern ("DELETE", FALSE);
552 else if (context->protocol == GDK_DRAG_PROTO_MOTIF)
554 target = gdk_atom_intern (success ?
555 "XmTRANSFER_SUCCESS" :
556 "XmTRANSFER_FAILURE",
560 if (target != GDK_NONE)
562 GtkWidget *selection_widget = gtk_drag_get_ipc_widget();
564 gdk_drag_context_ref (context);
566 gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context);
567 gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received",
568 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
571 gtk_selection_convert (selection_widget,
572 gdk_drag_get_selection(context),
578 gdk_drop_finish (context, success, time);
581 /*************************************************************
582 * gtk_drag_highlight:
583 * Highlight the given widget in the default manner.
587 *************************************************************/
590 gtk_drag_highlight (GtkWidget *widget)
594 g_return_if_fail (widget != NULL);
596 if (GTK_WIDGET_NO_WINDOW (widget))
598 x = widget->allocation.x;
599 y = widget->allocation.y;
607 gtk_draw_shadow (widget->style, widget->window,
608 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
610 widget->allocation.width,
611 widget->allocation.height);
613 gdk_draw_rectangle (widget->window,
614 widget->style->black_gc,
617 widget->allocation.width - 1,
618 widget->allocation.height - 1);
621 /*************************************************************
622 * gtk_drag_unhighlight:
623 * Refresh the given widget to remove the highlight.
627 *************************************************************/
630 gtk_drag_unhighlight (GtkWidget *widget)
634 g_return_if_fail (widget != NULL);
636 if (GTK_WIDGET_NO_WINDOW (widget))
638 x = widget->allocation.x;
639 y = widget->allocation.y;
647 gdk_window_clear_area_e (widget->window,
649 widget->allocation.width,
650 widget->allocation.height);
653 /*************************************************************
655 * Register a drop site, and possibly add default behaviors.
658 * flags: Which types of default drag behavior to use
659 * targets: Table of targets that can be accepted
660 * n_targets: Number of of entries in targets
663 *************************************************************/
666 gtk_drag_dest_set (GtkWidget *widget,
667 GtkDestDefaults flags,
668 GtkTargetEntry *targets,
670 GdkDragAction actions)
672 GtkDragDestSite *site;
674 g_return_if_fail (widget != NULL);
676 /* HACK, do this in the destroy */
677 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
679 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
681 if (GTK_WIDGET_REALIZED (widget))
682 gtk_drag_dest_realized (widget);
684 gtk_signal_connect (GTK_OBJECT (widget), "realize",
685 GTK_SIGNAL_FUNC (gtk_drag_dest_realized), NULL);
687 site = g_new (GtkDragDestSite, 1);
690 site->have_drag = FALSE;
692 site->target_list = gtk_target_list_new (targets, n_targets);
694 site->target_list = NULL;
696 site->actions = actions;
697 site->proxy_window = NULL;
699 gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
700 site, gtk_drag_dest_site_destroy);
703 /*************************************************************
704 * gtk_drag_dest_set_proxy:
705 * Set up this widget to proxy drags elsewhere.
708 * proxy_window: window to which forward drag events
709 * protocol: Drag protocol which the dest widget accepts
710 * use_coordinates: If true, send the same coordinates to the
711 * destination, because it is a embedded
714 *************************************************************/
717 gtk_drag_dest_set_proxy (GtkWidget *widget,
718 GdkWindow *proxy_window,
719 GdkDragProtocol protocol,
720 gboolean use_coordinates)
722 GtkDragDestSite *site;
724 g_return_if_fail (widget != NULL);
726 /* HACK, do this in the destroy */
727 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
729 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site);
731 if (GTK_WIDGET_REALIZED (widget))
732 gtk_drag_dest_realized (widget);
734 gtk_signal_connect (GTK_OBJECT (widget), "realize",
735 GTK_SIGNAL_FUNC (gtk_drag_dest_realized), NULL);
737 site = g_new (GtkDragDestSite, 1);
740 site->have_drag = FALSE;
741 site->target_list = NULL;
743 site->proxy_window = proxy_window;
744 gdk_window_ref (proxy_window);
745 site->proxy_protocol = protocol;
746 site->proxy_coords = use_coordinates;
748 gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest",
749 site, gtk_drag_dest_site_destroy);
752 /*************************************************************
753 * gtk_drag_dest_unset
754 * Unregister this widget as a drag target.
758 *************************************************************/
761 gtk_drag_dest_unset (GtkWidget *widget)
763 g_return_if_fail (widget != NULL);
765 gtk_object_set_data (GTK_OBJECT (widget), "gtk-drag-dest", NULL);
768 /*************************************************************
769 * gtk_drag_dest_handle_event:
770 * Called from widget event handling code on Drag events
774 * toplevel: Toplevel widget that received the event
777 *************************************************************/
780 gtk_drag_dest_handle_event (GtkWidget *toplevel,
783 GtkDragDestInfo *info;
784 GdkDragContext *context;
786 g_return_if_fail (toplevel != NULL);
787 g_return_if_fail (event != NULL);
789 context = event->dnd.context;
791 info = g_dataset_get_data (context, "gtk-info");
794 info = g_new (GtkDragDestInfo, 1);
796 info->context = event->dnd.context;
797 info->proxy_source = NULL;
798 info->proxy_data = NULL;
799 info->dropped = FALSE;
800 info->proxy_drop_wait = FALSE;
801 g_dataset_set_data_full (context,
804 gtk_drag_dest_info_destroy);
807 /* Find the widget for the event */
816 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
821 case GDK_DRAG_MOTION:
824 GtkDragFindData data;
827 if (event->type == GDK_DROP_START)
828 info->dropped = TRUE;
830 gdk_window_get_position (toplevel->window, &tx, &ty);
832 data.x = event->dnd.x_root - tx;
833 data.y = event->dnd.y_root - ty;
834 data.context = context;
837 data.callback = (event->type == GDK_DRAG_MOTION) ?
838 gtk_drag_dest_motion : gtk_drag_dest_drop;
839 data.time = event->dnd.time;
841 gtk_drag_find_widget (toplevel, &data);
843 /* We send a leave here so that the widget unhighlights
847 ((event->type == GDK_DROP_START) || (!data.found)))
849 gtk_drag_dest_leave (info->widget, context, event->dnd.time);
855 if (event->type == GDK_DRAG_MOTION)
858 gdk_drag_status (context, 0, event->dnd.time);
860 else if (event->type == GDK_DROP_START)
861 gdk_drop_reply (context, data.found, event->dnd.time);
866 g_assert_not_reached();
870 /*************************************************************
871 * gtk_drag_dest_find_target:
872 * Decide on a target for the drag.
877 *************************************************************/
880 gtk_drag_dest_find_target (GtkDragDestSite *site,
881 GdkDragContext *context)
884 GList *tmp_source = NULL;
886 tmp_target = site->target_list->list;
889 GtkTargetPair *pair = tmp_target->data;
890 tmp_source = context->targets;
893 if (tmp_source->data == GUINT_TO_POINTER (pair->target))
895 tmp_source = tmp_source->next;
897 tmp_target = tmp_target->next;
904 gtk_drag_selection_received (GtkWidget *widget,
905 GtkSelectionData *selection_data,
909 GdkDragContext *context;
910 GtkDragDestInfo *info;
911 GtkWidget *drop_widget;
915 context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
916 info = g_dataset_get_data (context, "gtk-info");
918 if (info->proxy_data &&
919 info->proxy_data->target == selection_data->target)
921 gtk_selection_data_set (info->proxy_data,
922 selection_data->type,
923 selection_data->format,
924 selection_data->data,
925 selection_data->length);
930 if (selection_data->target == gdk_atom_intern ("DELETE", FALSE))
932 gtk_drag_finish (context, TRUE, FALSE, time);
934 else if ((selection_data->target == gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE)) ||
935 (selection_data->target == gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE)))
941 GtkDragDestSite *site;
943 site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest");
945 if (site->target_list)
949 if (gtk_target_list_find (site->target_list,
950 selection_data->target,
953 if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
954 selection_data->length >= 0)
955 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
956 "drag_data_received",
957 context, info->drop_x, info->drop_y,
964 gtk_signal_emit_by_name (GTK_OBJECT (drop_widget),
965 "drag_data_received",
966 context, info->drop_x, info->drop_y,
967 selection_data, 0, time);
970 if (site->flags & GTK_DEST_DEFAULT_DROP)
973 gtk_drag_finish (context,
974 (selection_data->length >= 0),
975 (context->action == GDK_ACTION_MOVE),
979 gtk_widget_unref (drop_widget);
982 gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
983 GTK_SIGNAL_FUNC (gtk_drag_selection_received),
986 gtk_object_set_data (GTK_OBJECT (widget), "drag-context", NULL);
987 gdk_drag_context_unref (context);
989 gtk_drag_release_ipc_widget (widget);
992 /*************************************************************
993 * gtk_drag_find_widget:
994 * Recursive callback used to locate widgets for
995 * DRAG_MOTION and DROP_START events.
999 *************************************************************/
1002 gtk_drag_find_widget (GtkWidget *widget,
1003 GtkDragFindData *data)
1005 GtkAllocation new_allocation;
1009 new_allocation = widget->allocation;
1011 if (!GTK_WIDGET_VISIBLE (widget))
1014 if (!GTK_WIDGET_NO_WINDOW (widget))
1016 new_allocation.x = 0;
1017 new_allocation.y = 0;
1022 GdkWindow *window = widget->window;
1023 while (window != widget->parent->window)
1025 gint tx, ty, twidth, theight;
1026 gdk_window_get_size (window, &twidth, &theight);
1028 if (new_allocation.x < 0)
1030 new_allocation.width += new_allocation.x;
1031 new_allocation.x = 0;
1033 if (new_allocation.y < 0)
1035 new_allocation.height += new_allocation.y;
1036 new_allocation.y = 0;
1038 if (new_allocation.x + new_allocation.width > twidth)
1039 new_allocation.width = twidth - new_allocation.x;
1040 if (new_allocation.y + new_allocation.height > theight)
1041 new_allocation.height = theight - new_allocation.y;
1043 gdk_window_get_position (window, &tx, &ty);
1044 new_allocation.x += tx;
1046 new_allocation.y += ty;
1049 window = gdk_window_get_parent (window);
1053 if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
1054 (data->x < new_allocation.x + new_allocation.width) &&
1055 (data->y < new_allocation.y + new_allocation.height))
1057 /* First, check if the drag is in a valid drop site in
1058 * one of our children
1060 if (GTK_IS_CONTAINER (widget))
1062 GtkDragFindData new_data = *data;
1064 new_data.x -= x_offset;
1065 new_data.y -= y_offset;
1066 new_data.found = FALSE;
1068 gtk_container_foreach (GTK_CONTAINER (widget),
1069 (GtkCallback)gtk_drag_find_widget,
1072 data->found = new_data.found;
1075 /* If not, and this widget is registered as a drop site, check to
1076 * emit "drag_motion" to check if we are actually in
1080 gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"))
1082 data->found = data->callback (widget,
1084 data->x - new_allocation.x,
1085 data->y - new_allocation.y,
1087 /* If so, send a "drag_leave" to the last widget */
1090 if (data->info->widget && data->info->widget != widget)
1092 gtk_drag_dest_leave (data->info->widget, data->context, data->time);
1094 data->info->widget = widget;
1101 gtk_drag_proxy_begin (GtkWidget *widget, GtkDragDestInfo *dest_info)
1103 GtkDragSourceInfo *source_info;
1106 source_info = g_new0 (GtkDragSourceInfo, 1);
1107 source_info->ipc_widget = gtk_drag_get_ipc_widget ();
1109 source_info->widget = widget;
1110 gtk_widget_ref (source_info->widget);
1111 source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
1112 dest_info->context->targets,
1113 dest_info->context->actions);
1115 source_info->target_list = gtk_target_list_new (NULL, 0);
1116 tmp_list = dest_info->context->targets;
1119 gtk_target_list_add (source_info->target_list,
1120 GPOINTER_TO_UINT (tmp_list->data), 0, 0);
1121 tmp_list = tmp_list->next;
1124 source_info->proxy_dest = dest_info;
1126 g_dataset_set_data (source_info->context, "gtk-info", source_info);
1128 gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget),
1130 GTK_SIGNAL_FUNC (gtk_drag_selection_get),
1133 dest_info->proxy_source = source_info;
1137 gtk_drag_dest_info_destroy (gpointer data)
1139 GtkDragDestInfo *info = data;
1145 gtk_drag_dest_realized (GtkWidget *widget)
1147 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1148 gdk_window_register_dnd (toplevel->window);
1152 gtk_drag_dest_site_destroy (gpointer data)
1154 GtkDragDestSite *site = data;
1156 if (site->target_list)
1157 gtk_target_list_unref (site->target_list);
1163 * Default drag handlers
1166 gtk_drag_dest_leave (GtkWidget *widget,
1167 GdkDragContext *context,
1170 GtkDragDestSite *site;
1172 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1173 g_return_if_fail (site != NULL);
1175 if (site->proxy_window)
1177 GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1179 if (info->proxy_source && !info->dropped)
1180 gdk_drag_abort (info->proxy_source->context, time);
1184 else if (site->have_drag)
1186 site->have_drag = FALSE;
1188 if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1189 gtk_drag_unhighlight (widget);
1191 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_leave",
1197 gtk_drag_dest_motion (GtkWidget *widget,
1198 GdkDragContext *context,
1203 GtkDragDestSite *site;
1204 GdkDragAction action = 0;
1207 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1208 g_return_val_if_fail (site != NULL, FALSE);
1210 if (site->proxy_window)
1213 GdkEvent *current_event;
1214 GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info");
1216 if (!info->proxy_source)
1217 gtk_drag_proxy_begin (widget, info);
1219 current_event = gtk_get_current_event ();
1221 gdk_drag_motion (info->proxy_source->context,
1223 site->proxy_protocol,
1224 current_event->dnd.x_root,
1225 current_event->dnd.y_root,
1226 context->suggested_action, time);
1228 selection = gdk_drag_get_selection (info->proxy_source->context);
1230 selection != gdk_drag_get_selection (info->context))
1231 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1233 gdk_event_free (current_event);
1238 if (site->flags & GTK_DEST_DEFAULT_MOTION)
1240 if (context->suggested_action & site->actions)
1241 action = context->suggested_action;
1248 if ((site->actions & (1 << i)) &&
1249 (context->actions & (1 << i)))
1257 if (action && gtk_drag_dest_find_target (site, context))
1259 if (!site->have_drag)
1261 site->have_drag = TRUE;
1262 if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
1263 gtk_drag_highlight (widget);
1266 gdk_drag_status (context, action, time);
1270 gdk_drag_status (context, 0, time);
1275 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_motion",
1276 context, x, y, time, &retval);
1278 return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1282 gtk_drag_dest_drop (GtkWidget *widget,
1283 GdkDragContext *context,
1288 GtkDragDestSite *site;
1289 GtkDragDestInfo *info;
1291 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
1292 g_return_val_if_fail (site != NULL, FALSE);
1294 info = g_dataset_get_data (context, "gtk-info");
1295 g_return_val_if_fail (info != NULL, FALSE);
1300 if (site->proxy_window)
1302 if (info->proxy_source ||
1303 (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN))
1305 gtk_drag_drop (info->proxy_source, time);
1309 /* We need to synthesize a motion event, wait for a status,
1310 * and, if we get one a good one, do a drop.
1313 GdkEvent *current_event;
1316 gtk_drag_proxy_begin (widget, info);
1317 info->proxy_drop_wait = TRUE;
1318 info->proxy_drop_time = time;
1320 current_event = gtk_get_current_event ();
1322 gdk_drag_motion (info->proxy_source->context,
1324 site->proxy_protocol,
1325 current_event->dnd.x_root,
1326 current_event->dnd.y_root,
1327 context->suggested_action, time);
1329 selection = gdk_drag_get_selection (info->proxy_source->context);
1331 selection != gdk_drag_get_selection (info->context))
1332 gtk_drag_source_check_selection (info->proxy_source, selection, time);
1334 gdk_event_free (current_event);
1344 if (site->flags & GTK_DEST_DEFAULT_MOTION)
1346 GdkAtom target = gtk_drag_dest_find_target (site, context);
1348 if (target == GDK_NONE)
1351 gtk_drag_get_data (widget, context, target, time);
1354 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_drop",
1355 context, x, y, time, &retval);
1357 return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
1365 /*************************************************************
1366 * gtk_drag_begin: Start a drag operation
1369 * widget: Widget from which drag starts
1370 * handlers: List of handlers to supply the data for the drag
1371 * button: Button user used to start drag
1372 * time: Time of event starting drag
1375 *************************************************************/
1378 gtk_drag_begin (GtkWidget *widget,
1379 GtkTargetList *target_list,
1380 GdkDragAction actions,
1384 GtkDragSourceInfo *info;
1385 GList *targets = NULL;
1387 guint32 time = GDK_CURRENT_TIME;
1389 g_return_val_if_fail (widget != NULL, NULL);
1390 g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
1391 g_return_val_if_fail (target_list != NULL, NULL);
1394 time = gdk_event_get_time (event);
1396 info = g_new0 (GtkDragSourceInfo, 1);
1397 info->ipc_widget = gtk_drag_get_ipc_widget ();
1399 tmp_list = g_list_last (target_list->list);
1402 GtkTargetPair *pair = tmp_list->data;
1403 targets = g_list_prepend (targets,
1404 GINT_TO_POINTER (pair->target));
1405 tmp_list = tmp_list->prev;
1408 info->widget = widget;
1409 gtk_widget_ref (info->widget);
1411 info->context = gdk_drag_begin (info->ipc_widget->window,
1413 g_list_free (targets);
1415 g_dataset_set_data (info->context, "gtk-info", info);
1417 info->button = button;
1418 info->target_list = target_list;
1419 gtk_target_list_ref (target_list);
1421 info->cursor = NULL;
1422 info->status = GTK_DRAG_STATUS_DRAG;
1423 info->last_event = NULL;
1424 info->selections = NULL;
1425 info->icon_window = NULL;
1428 info->cursor = gtk_drag_get_cursor (
1429 gtk_drag_get_event_action (event, info->button, actions));
1431 gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
1432 info->context, NULL);
1434 /* We use a GTK grab here to override any grabs that the widget
1435 * we are dragging from might have held
1438 gtk_grab_add (info->ipc_widget);
1439 gdk_pointer_grab (info->ipc_widget->window, FALSE,
1440 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1441 GDK_BUTTON_RELEASE_MASK, NULL,
1442 info->cursor, time);
1444 if (event->type == GDK_MOTION_NOTIFY)
1445 gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
1449 gdk_window_get_pointer (GDK_ROOT_PARENT(), &x, &y, NULL);
1454 if (info->icon_window)
1456 gdk_window_raise (info->icon_window->window);
1457 gtk_widget_set_uposition (info->icon_window, x - info->hot_x, y - info->hot_y);
1461 info->start_x = info->cur_x;
1462 info->start_y = info->cur_y;
1464 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "button_release_event",
1465 GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info);
1466 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "motion_notify_event",
1467 GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info);
1468 gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "selection_get",
1469 GTK_SIGNAL_FUNC (gtk_drag_selection_get), info);
1471 return info->context;
1474 /*************************************************************
1475 * gtk_drag_source_set:
1476 * Register a drop site, and possibly add default behaviors.
1479 * start_button_mask: Mask of allowed buttons to start drag
1480 * targets: Table of targets for this source
1482 * actions: Actions allowed for this source
1484 *************************************************************/
1487 gtk_drag_source_set (GtkWidget *widget,
1488 GdkModifierType start_button_mask,
1489 GtkTargetEntry *targets,
1491 GdkDragAction actions)
1493 GtkDragSourceSite *site;
1495 g_return_if_fail (widget != NULL);
1497 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1499 gtk_widget_add_events (widget,
1500 gtk_widget_get_events (widget) |
1501 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_MOTION_MASK);
1505 if (site->target_list)
1506 gtk_target_list_unref (site->target_list);
1510 site = g_new0 (GtkDragSourceSite, 1);
1512 gtk_signal_connect (GTK_OBJECT (widget), "button_press_event",
1513 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1515 gtk_signal_connect (GTK_OBJECT (widget), "motion_notify_event",
1516 GTK_SIGNAL_FUNC (gtk_drag_source_event_cb),
1519 gtk_object_set_data_full (GTK_OBJECT (widget),
1521 site, gtk_drag_source_site_destroy);
1524 site->start_button_mask = start_button_mask;
1527 site->target_list = gtk_target_list_new (targets, n_targets);
1529 site->target_list = NULL;
1531 site->actions = actions;
1535 /*************************************************************
1536 * gtk_drag_source_set_icon:
1537 * Set an icon for drags from this source.
1539 * colormap: Colormap for this icon
1543 *************************************************************/
1546 gtk_drag_source_set_icon (GtkWidget *widget,
1547 GdkColormap *colormap,
1551 GtkDragSourceSite *site;
1553 g_return_if_fail (widget != NULL);
1555 site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1556 g_return_if_fail (site != NULL);
1559 gdk_colormap_unref (site->colormap);
1561 gdk_pixmap_unref (site->pixmap);
1563 gdk_pixmap_unref (site->mask);
1565 site->colormap = colormap;
1567 gdk_colormap_ref (colormap);
1569 site->pixmap = pixmap;
1571 gdk_pixmap_ref (pixmap);
1575 gdk_pixmap_ref (mask);
1578 /*************************************************************
1579 * gtk_drag_set_icon_widget:
1580 * Set a widget as the icon for a drag.
1587 *************************************************************/
1590 gtk_drag_set_icon_widget (GdkDragContext *context,
1595 GtkDragSourceInfo *info;
1597 g_return_if_fail (context != NULL);
1598 g_return_if_fail (widget != NULL);
1600 info = g_dataset_get_data (context, "gtk-info");
1601 gtk_drag_remove_icon (info);
1603 info->icon_window = widget;
1606 gtk_widget_set_uposition (widget, info->cur_x, info->cur_y);
1607 gtk_widget_ref (widget);
1608 gdk_window_raise (widget->window);
1609 gtk_widget_show (widget);
1612 info->hot_x = hot_x;
1613 info->hot_y = hot_y;
1616 /*************************************************************
1617 * gtk_drag_set_icon_pixmap:
1618 * Set a widget as the icon for a drag.
1621 * colormap: Colormap for the icon window.
1627 *************************************************************/
1630 gtk_drag_set_icon_pixmap (GdkDragContext *context,
1631 GdkColormap *colormap,
1640 g_return_if_fail (context != NULL);
1641 g_return_if_fail (colormap != NULL);
1642 g_return_if_fail (pixmap != NULL);
1644 gdk_window_get_size (pixmap, &width, &height);
1646 gtk_widget_push_visual (gdk_colormap_get_visual(colormap));
1647 gtk_widget_push_colormap (colormap);
1649 window = gtk_window_new (GTK_WINDOW_POPUP);
1651 gtk_widget_pop_visual ();
1652 gtk_widget_pop_colormap ();
1654 gtk_widget_set_usize (window, width, height);
1655 gtk_widget_realize (window);
1657 gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
1660 gtk_widget_shape_combine_mask (window, mask, 0, 0);
1662 gtk_drag_set_icon_widget (context, window, hot_x, hot_y);
1665 /*************************************************************
1666 * gtk_drag_set_icon_default:
1667 * Set the icon for a drag to the default icon.
1671 *************************************************************/
1674 gtk_drag_set_icon_default (GdkDragContext *context)
1676 g_return_if_fail (context != NULL);
1678 if (!default_icon_pixmap)
1680 default_icon_colormap = gdk_colormap_get_system ();
1681 default_icon_pixmap =
1682 gdk_pixmap_colormap_create_from_xpm_d (NULL,
1683 default_icon_colormap,
1685 NULL, drag_default_xpm);
1686 default_icon_hot_x = -2;
1687 default_icon_hot_y = -2;
1690 gtk_drag_set_icon_pixmap (context,
1691 default_icon_colormap,
1692 default_icon_pixmap,
1695 default_icon_hot_y);
1698 /*************************************************************
1699 * gtk_drag_set_default_icon:
1700 * Set a default icon for all drags as a pixmap.
1702 * colormap: Colormap for the icon window.
1708 *************************************************************/
1711 gtk_drag_set_default_icon (GdkColormap *colormap,
1717 g_return_if_fail (colormap != NULL);
1718 g_return_if_fail (pixmap != NULL);
1720 if (default_icon_colormap)
1721 gdk_colormap_unref (default_icon_colormap);
1722 if (default_icon_pixmap)
1723 gdk_pixmap_unref (default_icon_pixmap);
1724 if (default_icon_mask)
1725 gdk_pixmap_unref (default_icon_pixmap);
1727 default_icon_colormap = colormap;
1728 gdk_colormap_ref (colormap);
1730 default_icon_pixmap = pixmap;
1731 gdk_pixmap_ref (pixmap);
1733 default_icon_mask = mask;
1735 gdk_pixmap_ref (mask);
1737 default_icon_hot_x = hot_x;
1738 default_icon_hot_y = hot_y;
1742 /*************************************************************
1743 * gtk_drag_source_handle_event:
1744 * Called from widget event handling code on Drag events
1748 * toplevel: Toplevel widget that received the event
1751 *************************************************************/
1754 gtk_drag_source_handle_event (GtkWidget *widget,
1757 GtkDragSourceInfo *info;
1758 GdkDragContext *context;
1760 g_return_if_fail (widget != NULL);
1761 g_return_if_fail (event != NULL);
1763 context = event->dnd.context;
1764 info = g_dataset_get_data (context, "gtk-info");
1768 switch (event->type)
1770 case GDK_DRAG_STATUS:
1774 if (info->proxy_dest)
1776 if (!event->dnd.send_event)
1778 if (info->proxy_dest->proxy_drop_wait)
1780 /* Aha - we can finally pass the MOTIF DROP on... */
1781 gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
1785 gdk_drag_status (info->proxy_dest->context,
1786 event->dnd.context->action,
1793 cursor = gtk_drag_get_cursor (event->dnd.context->action);
1794 if (info->cursor != cursor)
1796 XChangeActivePointerGrab (GDK_WINDOW_XDISPLAY (widget->window),
1797 PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask,
1798 ((GdkCursorPrivate *)cursor)->xcursor,
1800 info->cursor = cursor;
1803 if (info->last_event)
1805 gtk_drag_motion_cb (info->widget,
1806 (GdkEventMotion *)info->last_event,
1808 info->last_event = NULL;
1814 case GDK_DROP_FINISHED:
1815 gtk_drag_drop_finished (info, TRUE, event->dnd.time);
1818 g_assert_not_reached();
1822 /*************************************************************
1823 * gtk_drag_source_check_selection:
1824 * Check if we've set up handlers/claimed the selection
1825 * for a given drag. If not, add them.
1829 *************************************************************/
1832 gtk_drag_source_check_selection (GtkDragSourceInfo *info,
1838 tmp_list = info->selections;
1841 if (GPOINTER_TO_UINT (tmp_list->data) == selection)
1843 tmp_list = tmp_list->next;
1846 gtk_selection_owner_set (info->ipc_widget, selection, time);
1847 info->selections = g_list_prepend (info->selections,
1848 GUINT_TO_POINTER (selection));
1850 tmp_list = info->target_list->list;
1853 GtkTargetPair *pair = tmp_list->data;
1855 gtk_selection_add_target (info->ipc_widget,
1859 tmp_list = tmp_list->next;
1862 if (info->context->protocol == GDK_DRAG_PROTO_MOTIF)
1864 gtk_selection_add_target (info->ipc_widget,
1866 gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE),
1867 TARGET_MOTIF_SUCCESS);
1868 gtk_selection_add_target (info->ipc_widget,
1870 gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE),
1871 TARGET_MOTIF_FAILURE);
1874 gtk_selection_add_target (info->ipc_widget,
1876 gdk_atom_intern ("DELETE", FALSE),
1880 /*************************************************************
1881 * gtk_drag_drop_finished:
1882 * Clean up from the drag, and display snapback, if necessary.
1888 *************************************************************/
1891 gtk_drag_drop_finished (GtkDragSourceInfo *info,
1895 if (info->proxy_dest)
1897 /* The time from the event isn't reliable for Xdnd drags */
1898 gtk_drag_finish (info->proxy_dest->context, success, FALSE,
1899 info->proxy_dest->proxy_drop_time);
1905 gtk_drag_source_info_destroy (info);
1909 GtkDragAnim *anim = g_new (GtkDragAnim, 1);
1913 anim->n_steps = MAX (info->cur_x - info->start_x,
1914 info->cur_y - info->start_y) / ANIM_STEP_LENGTH;
1915 anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS);
1917 gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
1921 gtk_drag_source_release_selections (info, GDK_CURRENT_TIME); /* fixme */
1925 gtk_drag_source_release_selections (GtkDragSourceInfo *info,
1928 GList *tmp_list = info->selections;
1931 GdkAtom selection = GPOINTER_TO_UINT (tmp_list->data);
1932 if (gdk_selection_owner_get (selection) == info->ipc_widget->window)
1933 gtk_selection_owner_set (NULL, selection, time);
1934 tmp_list = tmp_list->next;
1937 g_list_free (info->selections);
1938 info->selections = NULL;
1941 /*************************************************************
1943 * Send a drop event.
1947 *************************************************************/
1950 gtk_drag_drop (GtkDragSourceInfo *info, guint32 time)
1952 if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN)
1954 GtkSelectionData selection_data;
1956 GdkAtom target = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
1958 tmp_list = info->target_list->list;
1961 GtkTargetPair *pair = tmp_list->data;
1963 if (pair->target == target)
1965 selection_data.selection = GDK_NONE;
1966 selection_data.target = target;
1967 selection_data.data = NULL;
1968 selection_data.length = -1;
1970 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
1971 info->context, &selection_data,
1975 /* FIXME: Should we check for length >= 0 here? */
1976 gtk_drag_drop_finished (info, TRUE, time);
1979 tmp_list = tmp_list->next;
1981 gtk_drag_drop_finished (info, FALSE, time);
1985 gdk_drag_drop (info->context, time);
1986 info->drop_timeout = gtk_timeout_add (DROP_ABORT_TIME,
1987 gtk_drag_abort_timeout,
1993 * Source side callbacks.
1997 gtk_drag_source_event_cb (GtkWidget *widget,
2001 GtkDragSourceSite *site;
2002 site = (GtkDragSourceSite *)data;
2004 switch (event->type)
2006 case GDK_BUTTON_PRESS:
2007 if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask)
2009 site->x = event->button.x;
2010 site->y = event->button.y;
2013 case GDK_MOTION_NOTIFY:
2014 if (event->motion.state & site->start_button_mask)
2016 /* FIXME: This is really broken and can leave us
2022 if (event->motion.state & GDK_BUTTON1_MASK << (i - 1))
2026 if (MAX (abs(site->x - event->motion.x),
2027 abs(site->y - event->motion.y)) > 3)
2029 GtkDragSourceInfo *info;
2030 GdkDragContext *context;
2032 context = gtk_drag_begin (widget, site->target_list,
2037 info = g_dataset_get_data (context, "gtk-info");
2039 if (!info->icon_window)
2042 gtk_drag_set_icon_pixmap (context,
2045 site->mask, -2, -2);
2047 gtk_drag_set_icon_default (context);
2055 default: /* hit for 2/3BUTTON_PRESS */
2061 gtk_drag_source_site_destroy (gpointer data)
2063 GtkDragSourceSite *site = data;
2065 if (site->target_list)
2066 gtk_target_list_unref (site->target_list);
2069 gdk_pixmap_unref (site->pixmap);
2072 gdk_pixmap_unref (site->mask);
2078 gtk_drag_selection_get (GtkWidget *widget,
2079 GtkSelectionData *selection_data,
2084 GtkDragSourceInfo *info = data;
2085 static GdkAtom null_atom = GDK_NONE;
2089 null_atom = gdk_atom_intern ("NULL", FALSE);
2094 gtk_signal_emit_by_name (GTK_OBJECT (info->widget),
2097 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2099 case TARGET_MOTIF_SUCCESS:
2100 gtk_drag_drop_finished (info, TRUE, time);
2101 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2103 case TARGET_MOTIF_FAILURE:
2104 gtk_drag_drop_finished (info, FALSE, time);
2105 gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0);
2108 if (info->proxy_dest)
2110 /* This is sort of dangerous and needs to be thought
2113 info->proxy_dest->proxy_data = selection_data;
2114 gtk_drag_get_data (info->widget,
2115 info->proxy_dest->context,
2116 selection_data->target,
2119 info->proxy_dest->proxy_data = NULL;
2123 if (gtk_target_list_find (info->target_list,
2124 selection_data->target,
2127 gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get",
2139 gtk_drag_anim_timeout (gpointer data)
2141 GtkDragAnim *anim = data;
2144 if (anim->step == anim->n_steps)
2146 gtk_drag_source_info_destroy (anim->info);
2153 x = (anim->info->start_x * (anim->step + 1) +
2154 anim->info->cur_x * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2155 y = (anim->info->start_y * (anim->step + 1) +
2156 anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps;
2157 if (anim->info->icon_window)
2158 gtk_widget_set_uposition (anim->info->icon_window, x, y);
2167 gtk_drag_remove_icon (GtkDragSourceInfo *info)
2169 if (info->icon_window)
2171 gtk_widget_hide (info->icon_window);
2172 gtk_widget_unref (info->icon_window);
2174 info->icon_window = NULL;
2179 gtk_drag_source_info_destroy (gpointer data)
2181 GtkDragSourceInfo *info = data;
2183 gtk_drag_remove_icon (data);
2186 gtk_widget_unref (info->widget);
2188 gtk_signal_disconnect_by_data (GTK_OBJECT (info->ipc_widget), info);
2189 gtk_selection_remove_all (info->ipc_widget);
2190 gtk_drag_release_ipc_widget (info->ipc_widget);
2192 gtk_target_list_unref (info->target_list);
2194 g_dataset_set_data (info->context, "gtk-info", NULL);
2195 gdk_drag_context_unref (info->context);
2197 if (info->drop_timeout)
2198 gtk_timeout_remove (info->drop_timeout);
2203 /*************************************************************
2204 * gtk_drag_motion_cb:
2205 * "motion_notify_event" callback during drag.
2209 *************************************************************/
2212 gtk_drag_motion_cb (GtkWidget *widget,
2213 GdkEventMotion *event,
2216 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2218 GdkDragAction action;
2219 GdkWindow *window = NULL;
2220 GdkWindow *dest_window;
2221 GdkDragProtocol protocol;
2222 gint x_root, y_root;
2226 gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL);
2227 event->x_root = x_root;
2228 event->y_root = y_root;
2231 action = gtk_drag_get_event_action ((GdkEvent *)event,
2233 info->context->actions);
2235 info->cur_x = event->x_root - info->hot_x;
2236 info->cur_y = event->y_root - info->hot_y;
2238 if (info->icon_window)
2240 gdk_window_raise (info->icon_window->window);
2241 gtk_widget_set_uposition (info->icon_window, info->cur_x, info->cur_y);
2242 window = info->icon_window->window;
2245 gdk_drag_find_window (info->context,
2246 window, event->x_root, event->y_root,
2247 &dest_window, &protocol);
2249 if (gdk_drag_motion (info->context, dest_window, protocol,
2250 event->x_root, event->y_root, action,
2253 if (info->last_event)
2254 gdk_event_free ((GdkEvent *)info->last_event);
2256 info->last_event = gdk_event_copy ((GdkEvent *)event);
2260 gdk_window_unref (dest_window);
2262 selection = gdk_drag_get_selection (info->context);
2264 gtk_drag_source_check_selection (info, selection, event->time);
2267 /* We ignore the response, so we can respond precisely to the drop
2270 gdk_window_get_pointer (widget->window, NULL, NULL, NULL);
2276 /*************************************************************
2277 * gtk_drag_motion_cb:
2278 * "button_release_event" callback during drag.
2282 *************************************************************/
2285 gtk_drag_button_release_cb (GtkWidget *widget,
2286 GdkEventButton *event,
2289 GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
2290 GtkWidget *source_widget = info->widget;
2291 GdkEvent send_event;
2293 gtk_widget_ref (source_widget);
2295 if (event->button != info->button)
2298 gdk_pointer_ungrab (event->time);
2300 if ((info->context->action != 0) && (info->context->dest_window != NULL))
2302 gtk_drag_drop (info, event->time);
2306 gdk_drag_abort (info->context, event->time);
2307 gtk_drag_drop_finished (info, FALSE, event->time);
2310 gtk_grab_remove (widget);
2312 send_event.button.type = GDK_BUTTON_RELEASE;
2313 send_event.button.window = source_widget->window;
2314 send_event.button.x = 0;
2315 send_event.button.y = 0;
2316 send_event.button.state = event->state;
2317 send_event.button.button = event->button;
2319 send_event.button.time = event->time;
2321 /* Send on the button release to the original widget to
2322 * convince it to release its grab
2324 gtk_widget_event (source_widget, &send_event);
2325 gtk_widget_unref (source_widget);
2331 gtk_drag_abort_timeout (gpointer data)
2333 GtkDragSourceInfo *info = data;
2334 guint32 time = GDK_CURRENT_TIME;
2336 if (info->proxy_dest)
2337 time = info->proxy_dest->proxy_drop_time;
2339 info->drop_timeout = 0;
2340 gtk_drag_drop_finished (info, FALSE, time);