X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkdnd.c;h=0abbdda674573610126381bb8e2e9386073eed32;hb=ec319031cc2e4c82dcebedd65aa4dfa59f5a199e;hp=1c5efd714e278812f5e20d5ddea9b9101985b3cb;hpb=79fbe4824238ba68a1b801b9a3a72fffbb4041c5;p=~andy%2Fgtk diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c index 1c5efd714..0abbdda67 100644 --- a/gtk/gtkdnd.c +++ b/gtk/gtkdnd.c @@ -2,22 +2,41 @@ * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public + * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public + * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ -#include "gdk/gdkx.h" +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "gdkconfig.h" + +#if defined (GDK_WINDOWING_X11) +#include "x11/gdkx.h" +#elif defined (GDK_WINDOWING_WIN32) +#include "win32/gdkwin32.h" +#elif defined(GDK_WINDOWING_FB) +#include "linux-fb/gdkfb.h" +#elif defined (GDK_WINDOWING_NANOX) +#include "nanox/gdkprivate-nanox.h" +#endif + +#include "gdk/gdkkeysyms.h" #include "gtkdnd.h" #include "gtkinvisible.h" @@ -36,13 +55,15 @@ typedef struct _GtkDragAnim GtkDragAnim; typedef struct _GtkDragFindData GtkDragFindData; -typedef enum { +typedef enum +{ GTK_DRAG_STATUS_DRAG, GTK_DRAG_STATUS_WAIT, GTK_DRAG_STATUS_DROP } GtkDragStatus; -struct _GtkDragSourceSite { +struct _GtkDragSourceSite +{ GdkModifierType start_button_mask; GtkTargetList *target_list; /* Targets for drag data */ GdkDragAction actions; /* Possible actions */ @@ -55,9 +76,11 @@ struct _GtkDragSourceSite { gint x, y; }; -struct _GtkDragSourceInfo { +struct _GtkDragSourceInfo +{ GtkWidget *widget; GtkTargetList *target_list; /* Targets for drag data */ + GdkDragAction possible_actions; /* Actions allowed by source */ GdkDragContext *context; /* drag context */ GtkWidget *icon_window; /* Window for drag */ GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */ @@ -75,10 +98,13 @@ struct _GtkDragSourceInfo { GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */ - guint drop_timeout; /* Timeout for aborting drop */ + guint drop_timeout; /* Timeout for aborting drop */ + guint destroy_icon : 1; /* If true, destroy icon_window + */ }; -struct _GtkDragDestSite { +struct _GtkDragDestSite +{ GtkDestDefaults flags; GtkTargetList *target_list; GdkDragAction actions; @@ -89,7 +115,8 @@ struct _GtkDragDestSite { gboolean have_drag : 1; }; -struct _GtkDragDestInfo { +struct _GtkDragDestInfo +{ GtkWidget *widget; /* Widget in which drag is in */ GdkDragContext *context; /* Drag context */ GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */ @@ -110,13 +137,15 @@ struct _GtkDragDestInfo { #define ANIM_MIN_STEPS 5 #define ANIM_MAX_STEPS 10 -struct _GtkDragAnim { +struct _GtkDragAnim +{ GtkDragSourceInfo *info; gint step; gint n_steps; }; -struct _GtkDragFindData { +struct _GtkDragFindData +{ gint x; gint y; GdkDragContext *context; @@ -145,12 +174,20 @@ static gint default_icon_hot_x; static gint default_icon_hot_y; /* Forward declarations */ -static GdkDragAction gtk_drag_get_event_action (GdkEvent *event, - gint button, - GdkDragAction actions); +static void gtk_drag_get_event_actions (GdkEvent *event, + gint button, + GdkDragAction actions, + GdkDragAction *suggested_action, + GdkDragAction *possible_actions); static GdkCursor * gtk_drag_get_cursor (GdkDragAction action); static GtkWidget *gtk_drag_get_ipc_widget (void); -static void gtk_drag_release_ipc_widget (GtkWidget *widget); +static void gtk_drag_release_ipc_widget (GtkWidget *widget); + +static void gtk_drag_highlight_paint (GtkWidget *widget); +static gboolean gtk_drag_highlight_expose (GtkWidget *widget, + GdkEventExpose *event, + gpointer data); + static GdkAtom gtk_drag_dest_find_target (GtkWidget *widget, GtkDragDestSite *site, @@ -203,9 +240,16 @@ static void gtk_drag_selection_get (GtkWidget *widget, static gint gtk_drag_anim_timeout (gpointer data); static void gtk_drag_remove_icon (GtkDragSourceInfo *info); static void gtk_drag_source_info_destroy (gpointer data); +static void gtk_drag_update (GtkDragSourceInfo *info, + gint x_root, + gint y_root, + GdkEvent *event); static gint gtk_drag_motion_cb (GtkWidget *widget, GdkEventMotion *event, gpointer data); +static gint gtk_drag_key_cb (GtkWidget *widget, + GdkEventKey *event, + gpointer data); static gint gtk_drag_button_release_cb (GtkWidget *widget, GdkEventButton *event, gpointer data); @@ -217,70 +261,70 @@ static gint gtk_drag_abort_timeout (gpointer data); #define action_ask_width 16 #define action_ask_height 16 -static const char action_ask_bits[] = { +static const guchar action_ask_bits[] = { 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xf8, 0xb6, 0xf7, 0xd6, 0xec, 0x66, 0xdb, 0x66, 0xdb, 0x96, 0xec, 0x76, 0xf7, 0x76, 0xfb, 0xf6, 0xfc, 0x72, 0xfb, 0x7a, 0xfb, 0xf8, 0xfc, }; #define action_ask_mask_width 16 #define action_ask_mask_height 16 -static const char action_ask_mask_bits[] = { +static const guchar action_ask_mask_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0xcf, 0x0f, 0xef, 0x1f, 0xff, 0x3c, 0xff, 0x3c, 0x6f, 0x1f, 0x8f, 0x0f, 0x8f, 0x07, 0x0f, 0x03, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x03, }; #define action_copy_width 16 #define action_copy_height 16 -static const char action_copy_bits[] = { +static const guchar action_copy_bits[] = { 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x76, 0xfb, 0x76, 0xfb, 0x76, 0xfb, 0x06, 0x83, 0xf6, 0xbf, 0xf6, 0xbf, 0x06, 0x83, 0x76, 0xfb, 0x76, 0xfb, 0x72, 0xfb, 0x7a, 0xf8, 0xf8, 0xff, }; #define action_copy_mask_width 16 #define action_copy_mask_height 16 -static const char action_copy_mask_bits[] = { +static const guchar action_copy_mask_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0x07, 0x8f, 0x07, 0x8f, 0x07, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x8f, 0x07, 0x8f, 0x07, 0x8f, 0x07, 0x87, 0x07, 0x07, 0x00, }; #define action_move_width 16 #define action_move_height 16 -static const char action_move_bits[] = { +static const guchar action_move_bits[] = { 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x96, 0xff, 0x26, 0xff, 0xc6, 0xf8, 0xd6, 0xe3, 0x96, 0x8f, 0xb6, 0xbf, 0x36, 0xc3, 0x76, 0xfb, 0x76, 0xfa, 0xf2, 0xfa, 0xfa, 0xf8, 0xf8, 0xff, }; #define action_move_mask_width 16 #define action_move_mask_height 16 -static const char action_move_mask_bits[] = { +static const guchar action_move_mask_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x6f, 0x00, 0xff, 0x00, 0xff, 0x07, 0xef, 0x1f, 0xef, 0x7f, 0xcf, 0x7f, 0xcf, 0x3f, 0x8f, 0x07, 0x8f, 0x07, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x00, }; #define action_link_width 16 #define action_link_height 16 -static const char action_link_bits[] = { +static const guchar action_link_bits[] = { 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0x36, 0xf8, 0xd6, 0xf7, 0x66, 0xec, 0xa6, 0xe8, 0x26, 0xdf, 0xe6, 0xbd, 0xd6, 0xa7, 0xb6, 0xa8, 0xb6, 0xb1, 0x72, 0xdf, 0xfa, 0xe0, 0xf8, 0xff, }; #define action_link_mask_width 16 #define action_link_mask_height 16 -static const char action_link_mask_bits[] = { +static const guchar action_link_mask_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xcf, 0x07, 0xef, 0x0f, 0xff, 0x1f, 0x7f, 0x1f, 0xff, 0x3f, 0xff, 0x7f, 0xef, 0x7f, 0xcf, 0x77, 0xcf, 0x7f, 0x8f, 0x3f, 0x07, 0x1f, 0x07, 0x00, }; #define action_none_width 16 #define action_none_height 16 -static const char action_none_bits[] = { +static const guchar action_none_bits[] = { 0x00, 0x00, 0xfe, 0x7f, 0xfe, 0x1f, 0x06, 0xc0, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf8, 0xff, }; #define action_none_mask_width 16 #define action_none_mask_height 16 -static const char action_none_mask_bits[] = { +static const guchar action_none_mask_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x07, 0x00, }; @@ -302,10 +346,10 @@ static struct { { 0 , action_none_bits, action_none_mask_bits, NULL }, }; -static const gint n_drag_cursors = sizeof(drag_cursors) / sizeof(drag_cursors[0]); +static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[0]); /* XPM */ -static const char * drag_default_xpm[] = { +static const char *drag_default_xpm[] = { "32 32 3 1", " c None", ". c #000000", @@ -357,7 +401,7 @@ static const char * drag_default_xpm[] = { *************************************************************/ static GtkWidget * -gtk_drag_get_ipc_widget(void) +gtk_drag_get_ipc_widget (void) { GtkWidget *result; @@ -370,20 +414,20 @@ gtk_drag_get_ipc_widget(void) } else { - result = gtk_invisible_new(); + result = gtk_invisible_new (); gtk_widget_show (result); } return result; } -/************************************************************* +/*************************************************************** * gtk_drag_release_ipc_widget: - * Releases widget retrieved with gtk_drag_get_ipc_widget() + * Releases widget retrieved with gtk_drag_get_ipc_widget () * arguments: * widget: the widget to release. * results: - *************************************************************/ + ***************************************************************/ static void gtk_drag_release_ipc_widget (GtkWidget *widget) @@ -391,9 +435,53 @@ gtk_drag_release_ipc_widget (GtkWidget *widget) drag_widgets = g_slist_prepend (drag_widgets, widget); } -static GdkDragAction -gtk_drag_get_event_action (GdkEvent *event, gint button, GdkDragAction actions) +static guint32 +gtk_drag_get_event_time (GdkEvent *event) +{ + guint32 tm = GDK_CURRENT_TIME; + + if (event) + switch (event->type) + { + case GDK_MOTION_NOTIFY: + tm = event->motion.time; break; + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + tm = event->button.time; break; + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + tm = event->key.time; break; + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + tm = event->crossing.time; break; + case GDK_PROPERTY_NOTIFY: + tm = event->property.time; break; + case GDK_SELECTION_CLEAR: + case GDK_SELECTION_REQUEST: + case GDK_SELECTION_NOTIFY: + tm = event->selection.time; break; + case GDK_PROXIMITY_IN: + case GDK_PROXIMITY_OUT: + tm = event->proximity.time; break; + default: /* use current time */ + break; + } + + return tm; +} + +static void +gtk_drag_get_event_actions (GdkEvent *event, + gint button, + GdkDragAction actions, + GdkDragAction *suggested_action, + GdkDragAction *possible_actions) { + *suggested_action = 0; + *possible_actions = 0; + if (event) { GdkModifierType state = 0; @@ -413,41 +501,75 @@ gtk_drag_get_event_action (GdkEvent *event, gint button, GdkDragAction actions) case GDK_KEY_RELEASE: state = event->key.state; break; - case GDK_ENTER_NOTIFY: - case GDK_LEAVE_NOTIFY: + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: state = event->crossing.state; break; - default: - break; - } - - if (((button == 2) || (button == 3)) && (actions & GDK_ACTION_ASK)) - return GDK_ACTION_ASK; + default: + break; + } - if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) + if ((button == 2 || button == 3) && (actions & GDK_ACTION_ASK)) + { + *suggested_action = GDK_ACTION_ASK; + *possible_actions = actions; + } + else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) { if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK)) - return (actions & GDK_ACTION_LINK) ? GDK_ACTION_LINK : 0; + { + if (actions & GDK_ACTION_LINK) + { + *suggested_action = GDK_ACTION_LINK; + *possible_actions = GDK_ACTION_LINK; + } + } else if (state & GDK_CONTROL_MASK) - return (actions & GDK_ACTION_COPY) ? GDK_ACTION_COPY : 0; + { + if (actions & GDK_ACTION_COPY) + { + *suggested_action = GDK_ACTION_COPY; + *possible_actions = GDK_ACTION_COPY; + } + return; + } else - return (actions & GDK_ACTION_MOVE) ? GDK_ACTION_MOVE : 0; + { + if (actions & GDK_ACTION_MOVE) + { + *suggested_action = GDK_ACTION_MOVE; + *possible_actions = GDK_ACTION_MOVE; + } + return; + } } else { - if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK)) - return GDK_ACTION_ASK; + *possible_actions = actions; - if (actions & GDK_ACTION_COPY) - return GDK_ACTION_COPY; + if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK)) + *suggested_action = GDK_ACTION_ASK; + else if (actions & GDK_ACTION_COPY) + *suggested_action = GDK_ACTION_COPY; else if (actions & GDK_ACTION_MOVE) - return GDK_ACTION_MOVE; + *suggested_action = GDK_ACTION_MOVE; else if (actions & GDK_ACTION_LINK) - return GDK_ACTION_LINK; + *suggested_action = GDK_ACTION_LINK; } } + else + { + *possible_actions = actions; + + if (actions & GDK_ACTION_COPY) + *suggested_action = GDK_ACTION_COPY; + else if (actions & GDK_ACTION_MOVE) + *suggested_action = GDK_ACTION_MOVE; + else if (actions & GDK_ACTION_LINK) + *suggested_action = GDK_ACTION_LINK; + } - return 0; + return; } static GdkCursor * @@ -472,8 +594,8 @@ gtk_drag_get_cursor (GdkDragAction action) drag_cursors[i].mask, CURSOR_WIDTH, CURSOR_HEIGHT); - gdk_color_white (gdk_colormap_get_system(), &bg); - gdk_color_black (gdk_colormap_get_system(), &fg); + gdk_color_white (gdk_colormap_get_system (), &bg); + gdk_color_black (gdk_colormap_get_system (), &fg); drag_cursors[i].cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, 0, 0); @@ -510,7 +632,7 @@ gtk_drag_get_data (GtkWidget *widget, g_return_if_fail (widget != NULL); g_return_if_fail (context != NULL); - selection_widget = gtk_drag_get_ipc_widget(); + selection_widget = gtk_drag_get_ipc_widget (); gdk_drag_context_ref (context); gtk_widget_ref (widget); @@ -521,7 +643,7 @@ gtk_drag_get_data (GtkWidget *widget, gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context); gtk_selection_convert (selection_widget, - gdk_drag_get_selection(context), + gdk_drag_get_selection (context), target, time); } @@ -597,7 +719,7 @@ gtk_drag_finish (GdkDragContext *context, if (target != GDK_NONE) { - GtkWidget *selection_widget = gtk_drag_get_ipc_widget(); + GtkWidget *selection_widget = gtk_drag_get_ipc_widget (); gdk_drag_context_ref (context); @@ -607,7 +729,7 @@ gtk_drag_finish (GdkDragContext *context, NULL); gtk_selection_convert (selection_widget, - gdk_drag_get_selection(context), + gdk_drag_get_selection (context), target, time); } @@ -617,43 +739,85 @@ gtk_drag_finish (GdkDragContext *context, } /************************************************************* - * gtk_drag_highlight: - * Highlight the given widget in the default manner. + * gtk_drag_highlight_paint: + * Paint a highlight indicating drag status onto the widget. * arguments: * widget: * results: *************************************************************/ -void -gtk_drag_highlight (GtkWidget *widget) +static void +gtk_drag_highlight_paint (GtkWidget *widget) { - gint x, y; + gint x, y, width, height; g_return_if_fail (widget != NULL); - if (GTK_WIDGET_NO_WINDOW (widget)) + if (GTK_WIDGET_DRAWABLE (widget)) { - x = widget->allocation.x; - y = widget->allocation.y; - } - else - { - x = 0; - y = 0; + if (GTK_WIDGET_NO_WINDOW (widget)) + { + x = widget->allocation.x; + y = widget->allocation.y; + width = widget->allocation.width; + height = widget->allocation.height; + } + else + { + x = 0; + y = 0; + gdk_window_get_size (widget->window, &width, &height); + } + + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + x, y, width, height); + + gdk_draw_rectangle (widget->window, + widget->style->black_gc, + FALSE, + x, y, width - 1, height - 1); } - - gtk_draw_shadow (widget->style, widget->window, - GTK_STATE_NORMAL, GTK_SHADOW_OUT, - x, y, - widget->allocation.width, - widget->allocation.height); - - gdk_draw_rectangle (widget->window, - widget->style->black_gc, - FALSE, - x, y, - widget->allocation.width - 1, - widget->allocation.height - 1); +} + +/************************************************************* + * gtk_drag_highlight_expose: + * Callback for expose_event for highlighted widgets. + * arguments: + * widget: + * event: + * data: + * results: + *************************************************************/ + +static gboolean +gtk_drag_highlight_expose (GtkWidget *widget, + GdkEventExpose *event, + gpointer data) +{ + gtk_drag_highlight_paint (widget); + return TRUE; +} + +/************************************************************* + * gtk_drag_highlight: + * Highlight the given widget in the default manner. + * arguments: + * widget: + * results: + *************************************************************/ + +void +gtk_drag_highlight (GtkWidget *widget) +{ + gtk_signal_connect_after (GTK_OBJECT (widget), "draw", + GTK_SIGNAL_FUNC (gtk_drag_highlight_paint), + NULL); + gtk_signal_connect (GTK_OBJECT (widget), "expose_event", + GTK_SIGNAL_FUNC (gtk_drag_highlight_expose), + NULL); + + gtk_widget_queue_draw (widget); } /************************************************************* @@ -665,28 +829,43 @@ gtk_drag_highlight (GtkWidget *widget) *************************************************************/ void -gtk_drag_unhighlight (GtkWidget *widget) +gtk_drag_unhighlight (GtkWidget *widget) { - gint x, y; + g_return_if_fail (widget != NULL); + gtk_signal_disconnect_by_func (GTK_OBJECT (widget), + GTK_SIGNAL_FUNC (gtk_drag_highlight_paint), + NULL); + gtk_signal_disconnect_by_func (GTK_OBJECT (widget), + GTK_SIGNAL_FUNC (gtk_drag_highlight_expose), + NULL); + + gtk_widget_queue_clear (widget); +} + +static void +gtk_drag_dest_set_internal (GtkWidget *widget, + GtkDragDestSite *site) +{ + GtkDragDestSite *old_site; + g_return_if_fail (widget != NULL); - if (GTK_WIDGET_NO_WINDOW (widget)) - { - x = widget->allocation.x; - y = widget->allocation.y; - } - else - { - x = 0; - y = 0; - } - - gdk_window_clear_area_e (widget->window, - x, y, - widget->allocation.width, - widget->allocation.height); + /* HACK, do this in the destroy */ + old_site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); + if (old_site) + gtk_signal_disconnect_by_data (GTK_OBJECT (widget), old_site); + + if (GTK_WIDGET_REALIZED (widget)) + gtk_drag_dest_realized (widget); + + gtk_signal_connect (GTK_OBJECT (widget), "realize", + GTK_SIGNAL_FUNC (gtk_drag_dest_realized), site); + + gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest", + site, gtk_drag_dest_site_destroy); } + /************************************************************* * gtk_drag_dest_set: @@ -711,17 +890,6 @@ gtk_drag_dest_set (GtkWidget *widget, g_return_if_fail (widget != NULL); - /* HACK, do this in the destroy */ - site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); - if (site) - gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site); - - if (GTK_WIDGET_REALIZED (widget)) - gtk_drag_dest_realized (widget); - - gtk_signal_connect (GTK_OBJECT (widget), "realize", - GTK_SIGNAL_FUNC (gtk_drag_dest_realized), NULL); - site = g_new (GtkDragDestSite, 1); site->flags = flags; @@ -734,8 +902,7 @@ gtk_drag_dest_set (GtkWidget *widget, site->actions = actions; site->do_proxy = FALSE; - gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest", - site, gtk_drag_dest_site_destroy); + gtk_drag_dest_set_internal (widget, site); } /************************************************************* @@ -761,17 +928,6 @@ gtk_drag_dest_set_proxy (GtkWidget *widget, g_return_if_fail (widget != NULL); - /* HACK, do this in the destroy */ - site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); - if (site) - gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site); - - if (GTK_WIDGET_REALIZED (widget)) - gtk_drag_dest_realized (widget); - - gtk_signal_connect (GTK_OBJECT (widget), "realize", - GTK_SIGNAL_FUNC (gtk_drag_dest_realized), NULL); - site = g_new (GtkDragDestSite, 1); site->flags = 0; @@ -785,8 +941,7 @@ gtk_drag_dest_set_proxy (GtkWidget *widget, site->proxy_protocol = protocol; site->proxy_coords = use_coordinates; - gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest", - site, gtk_drag_dest_site_destroy); + gtk_drag_dest_set_internal (widget, site); } /************************************************************* @@ -798,7 +953,7 @@ gtk_drag_dest_set_proxy (GtkWidget *widget, *************************************************************/ void -gtk_drag_dest_unset (GtkWidget *widget) +gtk_drag_dest_unset (GtkWidget *widget) { g_return_if_fail (widget != NULL); @@ -838,8 +993,8 @@ gtk_drag_dest_handle_event (GtkWidget *toplevel, info->proxy_data = NULL; info->dropped = FALSE; info->proxy_drop_wait = FALSE; - g_dataset_set_data_full (context, - "gtk-info", + g_object_set_qdata_full (G_OBJECT (context), + g_quark_from_static_string ("gtk-info"), info, gtk_drag_dest_info_destroy); } @@ -865,7 +1020,17 @@ gtk_drag_dest_handle_event (GtkWidget *toplevel, gint tx, ty; if (event->type == GDK_DROP_START) - info->dropped = TRUE; + { + info->dropped = TRUE; + /* We send a leave here so that the widget unhighlights + * properly. + */ + if (info->widget) + { + gtk_drag_dest_leave (info->widget, context, event->dnd.time); + info->widget = NULL; + } + } gdk_window_get_origin (toplevel->window, &tx, &ty); @@ -881,11 +1046,7 @@ gtk_drag_dest_handle_event (GtkWidget *toplevel, gtk_drag_find_widget (toplevel, &data); - /* We send a leave here so that the widget unhighlights - * properly - */ - if (info->widget && - ((event->type == GDK_DROP_START) || (!data.found))) + if (info->widget && !data.found) { gtk_drag_dest_leave (info->widget, context, event->dnd.time); info->widget = NULL; @@ -898,7 +1059,7 @@ gtk_drag_dest_handle_event (GtkWidget *toplevel, if (!data.found) gdk_drag_status (context, 0, event->dnd.time); } - else if (event->type == GDK_DROP_START) + else if (event->type == GDK_DROP_START && !info->proxy_source) { gdk_drop_reply (context, data.found, event->dnd.time); if ((context->protocol == GDK_DRAG_PROTO_MOTIF) && !data.found) @@ -908,7 +1069,7 @@ gtk_drag_dest_handle_event (GtkWidget *toplevel, break; default: - g_assert_not_reached(); + g_assert_not_reached (); } } @@ -954,10 +1115,10 @@ gtk_drag_dest_find_target (GtkWidget *widget, } static void -gtk_drag_selection_received (GtkWidget *widget, - GtkSelectionData *selection_data, - guint32 time, - gpointer data) +gtk_drag_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data, + guint32 time, + gpointer data) { GdkDragContext *context; GtkDragDestInfo *info; @@ -966,7 +1127,7 @@ gtk_drag_selection_received (GtkWidget *widget, drop_widget = data; context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context"); - info = g_dataset_get_data (context, "gtk-info"); + info = g_object_get_qdata (G_OBJECT (context), g_quark_from_static_string ("gtk-info")); if (info->proxy_data && info->proxy_data->target == selection_data->target) @@ -976,7 +1137,7 @@ gtk_drag_selection_received (GtkWidget *widget, selection_data->format, selection_data->data, selection_data->length); - gtk_main_quit(); + gtk_main_quit (); return; } @@ -995,7 +1156,7 @@ gtk_drag_selection_received (GtkWidget *widget, site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest"); - if (site->target_list) + if (site && site->target_list) { guint target_info; @@ -1020,7 +1181,7 @@ gtk_drag_selection_received (GtkWidget *widget, selection_data, 0, time); } - if (site->flags & GTK_DEST_DEFAULT_DROP) + if (site && site->flags & GTK_DEST_DEFAULT_DROP) { gtk_drag_finish (context, @@ -1064,6 +1225,12 @@ gtk_drag_find_widget (GtkWidget *widget, if (data->found || !GTK_WIDGET_MAPPED (widget)) return; + /* Note that in the following code, we only count the + * position as being inside a WINDOW widget if it is inside + * widget->window; points that are outside of widget->window + * but within the allocation are not counted. This is consistent + * with the way we highlight drag targets. + */ if (!GTK_WIDGET_NO_WINDOW (widget)) { new_allocation.x = 0; @@ -1153,7 +1320,8 @@ gtk_drag_find_widget (GtkWidget *widget, } static void -gtk_drag_proxy_begin (GtkWidget *widget, GtkDragDestInfo *dest_info) +gtk_drag_proxy_begin (GtkWidget *widget, + GtkDragDestInfo *dest_info) { GtkDragSourceInfo *source_info; GList *tmp_list; @@ -1164,8 +1332,7 @@ gtk_drag_proxy_begin (GtkWidget *widget, GtkDragDestInfo *dest_info) source_info->widget = widget; gtk_widget_ref (source_info->widget); source_info->context = gdk_drag_begin (source_info->ipc_widget->window, - dest_info->context->targets, - dest_info->context->actions); + dest_info->context->targets); source_info->target_list = gtk_target_list_new (NULL, 0); tmp_list = dest_info->context->targets; @@ -1178,7 +1345,9 @@ gtk_drag_proxy_begin (GtkWidget *widget, GtkDragDestInfo *dest_info) source_info->proxy_dest = dest_info; - g_dataset_set_data (source_info->context, "gtk-info", source_info); + g_object_set_qdata (G_OBJECT (source_info->context), + g_quark_from_static_string ("gtk-info"), + source_info); gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget), "selection_get", @@ -1229,7 +1398,8 @@ gtk_drag_dest_leave (GtkWidget *widget, if (site->do_proxy) { - GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info"); + GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context), + g_quark_from_static_string ("gtk-info")); if (info->proxy_source && !info->dropped) gdk_drag_abort (info->proxy_source->context, time); @@ -1238,7 +1408,7 @@ gtk_drag_dest_leave (GtkWidget *widget, } else { - if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) + if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag) gtk_drag_unhighlight (widget); if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag) @@ -1270,7 +1440,8 @@ gtk_drag_dest_motion (GtkWidget *widget, GdkWindow *dest_window; GdkDragProtocol proto; - GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info"); + GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context), + g_quark_from_static_string ("gtk-info")); if (!info->proxy_source) gtk_drag_proxy_begin (widget, info); @@ -1295,7 +1466,11 @@ gtk_drag_dest_motion (GtkWidget *widget, dest_window, proto, current_event->dnd.x_root, current_event->dnd.y_root, - context->suggested_action, time); + context->suggested_action, + context->actions, time); + + if (!site->proxy_window && dest_window) + gdk_window_unref (dest_window); selection = gdk_drag_get_selection (info->proxy_source->context); if (selection && @@ -1363,7 +1538,8 @@ gtk_drag_dest_drop (GtkWidget *widget, site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); g_return_val_if_fail (site != NULL, FALSE); - info = g_dataset_get_data (context, "gtk-info"); + info = g_object_get_qdata (G_OBJECT (context), + g_quark_from_static_string ("gtk-info")); g_return_val_if_fail (info != NULL, FALSE); info->drop_x = x; @@ -1379,7 +1555,7 @@ gtk_drag_dest_drop (GtkWidget *widget, else { /* We need to synthesize a motion event, wait for a status, - * and, if we get one a good one, do a drop. + * and, if we get a good one, do a drop. */ GdkEvent *current_event; @@ -1406,12 +1582,16 @@ gtk_drag_dest_drop (GtkWidget *widget, current_event->dnd.y_root, &dest_window, &proto); } - + gdk_drag_motion (info->proxy_source->context, dest_window, proto, current_event->dnd.x_root, current_event->dnd.y_root, - context->suggested_action, time); + context->suggested_action, + context->actions, time); + + if (!site->proxy_window && dest_window) + gdk_window_unref (dest_window); selection = gdk_drag_get_selection (info->proxy_source->context); if (selection && @@ -1472,6 +1652,7 @@ gtk_drag_begin (GtkWidget *widget, GList *targets = NULL; GList *tmp_list; guint32 time = GDK_CURRENT_TIME; + GdkDragAction possible_actions, suggested_action; g_return_val_if_fail (widget != NULL, NULL); g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL); @@ -1498,56 +1679,53 @@ gtk_drag_begin (GtkWidget *widget, info->widget = widget; gtk_widget_ref (info->widget); - info->context = gdk_drag_begin (info->ipc_widget->window, - targets, actions); + info->context = gdk_drag_begin (info->ipc_widget->window, targets); g_list_free (targets); - g_dataset_set_data (info->context, "gtk-info", info); + g_object_set_qdata (G_OBJECT (info->context), + g_quark_from_static_string ("gtk-info"), info); info->button = button; info->target_list = target_list; gtk_target_list_ref (target_list); + info->possible_actions = actions; + info->cursor = NULL; info->status = GTK_DRAG_STATUS_DRAG; info->last_event = NULL; info->selections = NULL; info->icon_window = NULL; - - if (event) - info->cursor = gtk_drag_get_cursor ( - gtk_drag_get_event_action (event, info->button, 0)); + info->destroy_icon = FALSE; - gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin", - info->context); + gtk_drag_get_event_actions (event, info->button, actions, + &suggested_action, &possible_actions); - /* We use a GTK grab here to override any grabs that the widget - * we are dragging from might have held - */ - - gtk_grab_add (info->ipc_widget); - gdk_pointer_grab (info->ipc_widget->window, FALSE, - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | - GDK_BUTTON_RELEASE_MASK, NULL, - info->cursor, time); + info->cursor = gtk_drag_get_cursor (suggested_action); - if (event->type == GDK_MOTION_NOTIFY) - gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info); + /* Set cur_x, cur_y here so if the "drag_begin" signal shows + * the drag icon, it will be in the right place + */ + if (event && event->type == GDK_MOTION_NOTIFY) + { + info->cur_x = event->motion.x_root; + info->cur_y = event->motion.y_root; + } else { gint x, y; - gdk_window_get_pointer (GDK_ROOT_PARENT(), &x, &y, NULL); + gdk_window_get_pointer (GDK_ROOT_PARENT (), &x, &y, NULL); info->cur_x = x; info->cur_y = y; - - if (info->icon_window) - { - gdk_window_raise (info->icon_window->window); - gtk_widget_set_uposition (info->icon_window, x - info->hot_x, y - info->hot_y); - } } + gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin", + info->context); + + if (event && event->type == GDK_MOTION_NOTIFY) + gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info); + info->start_x = info->cur_x; info->start_y = info->cur_y; @@ -1555,9 +1733,37 @@ gtk_drag_begin (GtkWidget *widget, GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info); gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "motion_notify_event", GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info); + gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_press_event", + GTK_SIGNAL_FUNC (gtk_drag_key_cb), info); + gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "key_release_event", + GTK_SIGNAL_FUNC (gtk_drag_key_cb), info); gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "selection_get", GTK_SIGNAL_FUNC (gtk_drag_selection_get), info); + /* We use a GTK grab here to override any grabs that the widget + * we are dragging from might have held + */ + gtk_grab_add (info->ipc_widget); + if (gdk_pointer_grab (info->ipc_widget->window, FALSE, + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON_RELEASE_MASK, NULL, + info->cursor, time) == 0) + { + if (gdk_keyboard_grab (info->ipc_widget->window, FALSE, time) != 0) + { + /* FIXME: This should be cleaned up... */ + GdkEventButton ev; + + ev.time = time; + ev.type = GDK_BUTTON_RELEASE; + ev.button = info->button; + + gtk_drag_button_release_cb (widget, &ev, info); + + return NULL; + } + } + return info->context; } @@ -1574,11 +1780,11 @@ gtk_drag_begin (GtkWidget *widget, *************************************************************/ void -gtk_drag_source_set (GtkWidget *widget, - GdkModifierType start_button_mask, - const GtkTargetEntry *targets, - gint n_targets, - GdkDragAction actions) +gtk_drag_source_set (GtkWidget *widget, + GdkModifierType start_button_mask, + const GtkTargetEntry *targets, + gint n_targets, + GdkDragAction actions) { GtkDragSourceSite *site; @@ -1658,10 +1864,10 @@ gtk_drag_source_unset (GtkWidget *widget) *************************************************************/ void -gtk_drag_source_set_icon (GtkWidget *widget, - GdkColormap *colormap, - GdkPixmap *pixmap, - GdkBitmap *mask) +gtk_drag_source_set_icon (GtkWidget *widget, + GdkColormap *colormap, + GdkPixmap *pixmap, + GdkBitmap *mask) { GtkDragSourceSite *site; @@ -1691,7 +1897,7 @@ gtk_drag_source_set_icon (GtkWidget *widget, } /************************************************************* - * gtk_drag_set_icon_widget: + * gtk_drag_set_icon_window: * Set a widget as the icon for a drag. * arguments: * context: @@ -1701,31 +1907,60 @@ gtk_drag_source_set_icon (GtkWidget *widget, * results: *************************************************************/ -void -gtk_drag_set_icon_widget (GdkDragContext *context, - GtkWidget *widget, - gint hot_x, - gint hot_y) +static void +gtk_drag_set_icon_window (GdkDragContext *context, + GtkWidget *widget, + gint hot_x, + gint hot_y, + gboolean destroy_on_release) { GtkDragSourceInfo *info; g_return_if_fail (context != NULL); g_return_if_fail (widget != NULL); - info = g_dataset_get_data (context, "gtk-info"); + info = g_object_get_qdata (G_OBJECT (context), + g_quark_from_static_string ("gtk-info")); gtk_drag_remove_icon (info); - + info->icon_window = widget; + info->hot_x = hot_x; + info->hot_y = hot_y; + if (widget) { - gtk_widget_set_uposition (widget, info->cur_x, info->cur_y); + gtk_widget_set_uposition (widget, + info->cur_x - info->hot_x, + info->cur_y - info->hot_y); gtk_widget_ref (widget); gdk_window_raise (widget->window); gtk_widget_show (widget); } - info->hot_x = hot_x; - info->hot_y = hot_y; + info->destroy_icon = destroy_on_release; +} + +/************************************************************* + * gtk_drag_set_icon_widget: + * Set a widget as the icon for a drag. + * arguments: + * context: + * widget: + * hot_x: Hot spot + * hot_y: + * results: + *************************************************************/ + +void +gtk_drag_set_icon_widget (GdkDragContext *context, + GtkWidget *widget, + gint hot_x, + gint hot_y) +{ + g_return_if_fail (context != NULL); + g_return_if_fail (widget != NULL); + + gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE); } /************************************************************* @@ -1742,12 +1977,12 @@ gtk_drag_set_icon_widget (GdkDragContext *context, *************************************************************/ void -gtk_drag_set_icon_pixmap (GdkDragContext *context, - GdkColormap *colormap, - GdkPixmap *pixmap, - GdkBitmap *mask, - gint hot_x, - gint hot_y) +gtk_drag_set_icon_pixmap (GdkDragContext *context, + GdkColormap *colormap, + GdkPixmap *pixmap, + GdkBitmap *mask, + gint hot_x, + gint hot_y) { GtkWidget *window; gint width, height; @@ -1758,14 +1993,12 @@ gtk_drag_set_icon_pixmap (GdkDragContext *context, gdk_window_get_size (pixmap, &width, &height); - gtk_widget_push_visual (gdk_colormap_get_visual(colormap)); gtk_widget_push_colormap (colormap); window = gtk_window_new (GTK_WINDOW_POPUP); gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE); - gtk_widget_pop_visual (); gtk_widget_pop_colormap (); gtk_widget_set_usize (window, width, height); @@ -1776,7 +2009,7 @@ gtk_drag_set_icon_pixmap (GdkDragContext *context, if (mask) gtk_widget_shape_combine_mask (window, mask, 0, 0); - gtk_drag_set_icon_widget (context, window, hot_x, hot_y); + gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE); } /************************************************************* @@ -1799,7 +2032,7 @@ gtk_drag_set_icon_default (GdkDragContext *context) gdk_pixmap_colormap_create_from_xpm_d (NULL, default_icon_colormap, &default_icon_mask, - NULL, drag_default_xpm); + NULL, (gchar **)drag_default_xpm); default_icon_hot_x = -2; default_icon_hot_y = -2; } @@ -1839,7 +2072,7 @@ gtk_drag_set_default_icon (GdkColormap *colormap, if (default_icon_pixmap) gdk_pixmap_unref (default_icon_pixmap); if (default_icon_mask) - gdk_pixmap_unref (default_icon_pixmap); + gdk_pixmap_unref (default_icon_mask); default_icon_colormap = colormap; gdk_colormap_ref (colormap); @@ -1878,7 +2111,8 @@ gtk_drag_source_handle_event (GtkWidget *widget, g_return_if_fail (event != NULL); context = event->dnd.context; - info = g_dataset_get_data (context, "gtk-info"); + info = g_object_get_qdata (G_OBJECT (context), + g_quark_from_static_string ("gtk-info")); if (!info) return; @@ -1894,8 +2128,14 @@ gtk_drag_source_handle_event (GtkWidget *widget, { if (info->proxy_dest->proxy_drop_wait) { + gboolean result = context->action != 0; + /* Aha - we can finally pass the MOTIF DROP on... */ - gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time); + gdk_drop_reply (info->proxy_dest->context, result, info->proxy_dest->proxy_drop_time); + if (result) + gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time); + else + gtk_drag_finish (info->proxy_dest->context, FALSE, FALSE, info->proxy_dest->proxy_drop_time); } else { @@ -1910,18 +2150,27 @@ gtk_drag_source_handle_event (GtkWidget *widget, cursor = gtk_drag_get_cursor (event->dnd.context->action); if (info->cursor != cursor) { +#ifdef GDK_WINDOWING_X11 XChangeActivePointerGrab (GDK_WINDOW_XDISPLAY (widget->window), PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask, ((GdkCursorPrivate *)cursor)->xcursor, event->dnd.time); +#elif defined (GDK_WINDOWING_WIN32) + gdk_pointer_grab (widget->window, FALSE, + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON_RELEASE_MASK, + NULL, + info->cursor, event->dnd.time); +#endif info->cursor = cursor; } if (info->last_event) { - gtk_drag_motion_cb (info->widget, - (GdkEventMotion *)info->last_event, - info); + gtk_drag_update (info, + info->cur_x, info->cur_y, + info->last_event); info->last_event = NULL; } } @@ -1932,7 +2181,7 @@ gtk_drag_source_handle_event (GtkWidget *widget, gtk_drag_drop_finished (info, TRUE, event->dnd.time); break; default: - g_assert_not_reached(); + g_assert_not_reached (); } } @@ -2035,14 +2284,15 @@ gtk_drag_drop_finished (GtkDragSourceInfo *info, anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS); if (info->icon_window) { - gtk_widget_show(info->icon_window); + gtk_widget_show (info->icon_window); gdk_window_raise (info->icon_window->window); } /* Mark the context as dead, so if the destination decides * to respond really late, we still are OK. */ - g_dataset_set_data (info->context, "gtk-info", NULL); + g_object_set_qdata (G_OBJECT (info->context), + g_quark_from_static_string ("gtk-info"), NULL); gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim); } } @@ -2074,7 +2324,8 @@ gtk_drag_source_release_selections (GtkDragSourceInfo *info, *************************************************************/ static void -gtk_drag_drop (GtkDragSourceInfo *info, guint32 time) +gtk_drag_drop (GtkDragSourceInfo *info, + guint32 time) { if (info->context->protocol == GDK_DRAG_PROTO_ROOTWIN) { @@ -2163,8 +2414,8 @@ gtk_drag_source_event_cb (GtkWidget *widget, break; } - if (MAX (abs(site->x - event->motion.x), - abs(site->y - event->motion.y)) > 3) + if (MAX (ABS (site->x - event->motion.x), + ABS (site->y - event->motion.y)) > 3) { GtkDragSourceInfo *info; GdkDragContext *context; @@ -2175,7 +2426,8 @@ gtk_drag_source_event_cb (GtkWidget *widget, i, event); - info = g_dataset_get_data (context, "gtk-info"); + info = g_object_get_qdata (G_OBJECT (context), + g_quark_from_static_string ("gtk-info")); if (!info->icon_window) { @@ -2257,7 +2509,7 @@ gtk_drag_selection_get (GtkWidget *widget, info->proxy_dest->context, selection_data->target, time); - gtk_main(); + gtk_main (); info->proxy_dest->proxy_data = NULL; } else @@ -2300,7 +2552,9 @@ gtk_drag_anim_timeout (gpointer data) y = (anim->info->start_y * (anim->step + 1) + anim->info->cur_y * (anim->n_steps - anim->step - 1)) / anim->n_steps; if (anim->info->icon_window) - gtk_widget_set_uposition (anim->info->icon_window, x, y); + gtk_widget_set_uposition (anim->info->icon_window, + x - anim->info->hot_x, + y - anim->info->hot_y); anim->step++; @@ -2318,8 +2572,10 @@ gtk_drag_remove_icon (GtkDragSourceInfo *info) if (info->icon_window) { gtk_widget_hide (info->icon_window); - gtk_widget_unref (info->icon_window); + if (info->destroy_icon) + gtk_widget_destroy (info->icon_window); + gtk_widget_unref (info->icon_window); info->icon_window = NULL; } } @@ -2346,7 +2602,7 @@ gtk_drag_source_info_destroy (gpointer data) gtk_target_list_unref (info->target_list); - g_dataset_set_data (info->context, "gtk-info", NULL); + g_object_set_qdata (G_OBJECT (info->context), g_quark_from_static_string ("gtk-info"), NULL); gdk_drag_context_unref (info->context); if (info->drop_timeout) @@ -2356,54 +2612,54 @@ gtk_drag_source_info_destroy (gpointer data) } /************************************************************* - * gtk_drag_motion_cb: - * "motion_notify_event" callback during drag. + * gtk_drag_update: + * Function to update the status of the drag when the + * cursor moves or the modifier changes * arguments: - * + * info: DragSourceInfo for the drag + * x_root, y_root: position of darg + * event: The event that triggered this call * results: *************************************************************/ -static gint -gtk_drag_motion_cb (GtkWidget *widget, - GdkEventMotion *event, - gpointer data) +static void +gtk_drag_update (GtkDragSourceInfo *info, + gint x_root, + gint y_root, + GdkEvent *event) { - GtkDragSourceInfo *info = (GtkDragSourceInfo *)data; - GdkAtom selection; GdkDragAction action; + GdkDragAction possible_actions; GdkWindow *window = NULL; GdkWindow *dest_window; GdkDragProtocol protocol; - gint x_root, y_root; - - if (event->is_hint) - { - gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL); - event->x_root = x_root; - event->y_root = y_root; - } + GdkAtom selection; + guint32 time = gtk_drag_get_event_time (event); - action = gtk_drag_get_event_action ((GdkEvent *)event, - info->button, - info->context->actions); - - info->cur_x = event->x_root - info->hot_x; - info->cur_y = event->y_root - info->hot_y; + gtk_drag_get_event_actions (event, + info->button, + info->possible_actions, + &action, &possible_actions); + info->cur_x = x_root; + info->cur_y = y_root; if (info->icon_window) { gdk_window_raise (info->icon_window->window); - gtk_widget_set_uposition (info->icon_window, info->cur_x, info->cur_y); + gtk_widget_set_uposition (info->icon_window, + info->cur_x - info->hot_x, + info->cur_y - info->hot_y); window = info->icon_window->window; } gdk_drag_find_window (info->context, - window, event->x_root, event->y_root, + window, x_root, y_root, &dest_window, &protocol); if (gdk_drag_motion (info->context, dest_window, protocol, - event->x_root, event->y_root, action, - event->time)) + x_root, y_root, action, + possible_actions, + time)) { if (info->last_event) gdk_event_free ((GdkEvent *)info->last_event); @@ -2416,57 +2672,34 @@ gtk_drag_motion_cb (GtkWidget *widget, selection = gdk_drag_get_selection (info->context); if (selection) - gtk_drag_source_check_selection (info, selection, event->time); - -#if 0 - /* We ignore the response, so we can respond precisely to the drop - */ - if (event->is_hint) - gdk_window_get_pointer (widget->window, NULL, NULL, NULL); -#endif - - return TRUE; + gtk_drag_source_check_selection (info, selection, time); } /************************************************************* - * gtk_drag_motion_cb: - * "button_release_event" callback during drag. + * gtk_drag_end: + * Called when the user finishes to drag, either by + * releasing the mouse, or by pressing Esc. * arguments: - * + * widget: GtkInvisible widget for this drag + * info: * results: *************************************************************/ -static gint -gtk_drag_button_release_cb (GtkWidget *widget, - GdkEventButton *event, - gpointer data) +static void +gtk_drag_end (GtkDragSourceInfo *info, guint32 time) { - GtkDragSourceInfo *info = (GtkDragSourceInfo *)data; - GtkWidget *source_widget = info->widget; GdkEvent send_event; + GtkWidget *source_widget = info->widget; - gtk_widget_ref (source_widget); - - if (event->button != info->button) - return FALSE; - - gdk_pointer_ungrab (event->time); + gdk_pointer_ungrab (time); + gdk_keyboard_ungrab (time); - if ((info->context->action != 0) && (info->context->dest_window != NULL)) - { - gtk_drag_drop (info, event->time); - } - else - { - gdk_drag_abort (info->context, event->time); - gtk_drag_drop_finished (info, FALSE, event->time); - } + gtk_grab_remove (info->ipc_widget); - gtk_grab_remove (widget); - gtk_signal_disconnect_by_func (GTK_OBJECT (widget), + gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget), GTK_SIGNAL_FUNC (gtk_drag_button_release_cb), info); - gtk_signal_disconnect_by_func (GTK_OBJECT (widget), + gtk_signal_disconnect_by_func (GTK_OBJECT (info->ipc_widget), GTK_SIGNAL_FUNC (gtk_drag_motion_cb), info); @@ -2480,23 +2713,119 @@ gtk_drag_button_release_cb (GtkWidget *widget, send_event.button.type = GDK_BUTTON_RELEASE; send_event.button.window = GDK_ROOT_PARENT (); send_event.button.send_event = TRUE; - send_event.button.time = event->time; + send_event.button.time = time; send_event.button.x = 0; send_event.button.y = 0; - send_event.button.pressure = 0.; - send_event.button.xtilt = 0.; - send_event.button.ytilt = 0.; - send_event.button.state = event->state; - send_event.button.button = event->button; - send_event.button.source = GDK_SOURCE_PEN; - send_event.button.deviceid = GDK_CORE_POINTER; + send_event.button.axes = NULL; + send_event.button.state = 0; + send_event.button.button = info->button; + send_event.button.device = gdk_core_pointer; send_event.button.x_root = 0; send_event.button.y_root = 0; gtk_propagate_event (source_widget, &send_event); +} + +/************************************************************* + * gtk_drag_motion_cb: + * "motion_notify_event" callback during drag. + * arguments: + * + * results: + *************************************************************/ + +static gint +gtk_drag_motion_cb (GtkWidget *widget, + GdkEventMotion *event, + gpointer data) +{ + GtkDragSourceInfo *info = (GtkDragSourceInfo *)data; + gint x_root, y_root; + + if (event->is_hint) + { + gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL); + event->x_root = x_root; + event->y_root = y_root; + } + + gtk_drag_update (info, event->x_root, event->y_root, (GdkEvent *)event); - gtk_widget_unref (source_widget); + return TRUE; +} + +/************************************************************* + * gtk_drag_key_cb: + * "key_press/release_event" callback during drag. + * arguments: + * + * results: + *************************************************************/ + +static gint +gtk_drag_key_cb (GtkWidget *widget, + GdkEventKey *event, + gpointer data) +{ + GtkDragSourceInfo *info = (GtkDragSourceInfo *)data; + GdkModifierType state; + if (event->type == GDK_KEY_PRESS) + { + if (event->keyval == GDK_Escape) + { + gtk_drag_end (info, event->time); + gdk_drag_abort (info->context, event->time); + gtk_drag_drop_finished (info, FALSE, event->time); + + return TRUE; + } + } + + /* Now send a "motion" so that the modifier state is updated */ + + /* The state is not yet updated in the event, so we need + * to query it here. We could use XGetModifierMapping, but + * that would be overkill. + */ + gdk_window_get_pointer (GDK_ROOT_PARENT(), NULL, NULL, &state); + + event->state = state; + gtk_drag_update (info, info->cur_x, info->cur_y, (GdkEvent *)event); + + return TRUE; +} + +/************************************************************* + * gtk_drag_button_release_cb: + * "button_release_event" callback during drag. + * arguments: + * + * results: + *************************************************************/ + +static gint +gtk_drag_button_release_cb (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + GtkDragSourceInfo *info = (GtkDragSourceInfo *)data; + + if (event->button != info->button) + return FALSE; + + gtk_drag_end (info, event->time); + + if ((info->context->action != 0) && (info->context->dest_window != NULL)) + { + gtk_drag_drop (info, event->time); + } + else + { + gdk_drag_abort (info->context, event->time); + gtk_drag_drop_finished (info, FALSE, event->time); + } + return TRUE; } @@ -2506,11 +2835,15 @@ gtk_drag_abort_timeout (gpointer data) GtkDragSourceInfo *info = data; guint32 time = GDK_CURRENT_TIME; + GDK_THREADS_ENTER (); + if (info->proxy_dest) time = info->proxy_dest->proxy_drop_time; info->drop_timeout = 0; gtk_drag_drop_finished (info, FALSE, time); + GDK_THREADS_LEAVE (); + return FALSE; }