X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkdnd.c;h=35281f065e9f474b94cb933a10619478c9ef821c;hb=fcfb638ab0260c7f320c5ffe7c50a3d669f9881b;hp=982facda479337af787790d2119423dde218fe1f;hpb=207e3bb9771b9e28c93cf2da5edebab543ed6a36;p=~andy%2Fgtk diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c index 982facda4..35281f065 100644 --- a/gtk/gtkdnd.c +++ b/gtk/gtkdnd.c @@ -26,25 +26,15 @@ #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 "gtkimage.h" #include "gtkinvisible.h" #include "gtkmain.h" -#include "gtksignal.h" +#include "gtkstock.h" #include "gtkwindow.h" -static GSList *drag_widgets = NULL; static GSList *source_widgets = NULL; typedef struct _GtkDragSourceSite GtkDragSourceSite; @@ -67,9 +57,18 @@ struct _GtkDragSourceSite GdkModifierType start_button_mask; GtkTargetList *target_list; /* Targets for drag data */ GdkDragAction actions; /* Possible actions */ + + /* Drag icon */ + GtkImageType icon_type; + union + { + GtkImagePixmapData pixmap; + GtkImagePixbufData pixbuf; + GtkImageStockData stock; + } icon_data; + GdkBitmap *icon_mask; + GdkColormap *colormap; /* Colormap for drag icon */ - GdkPixmap *pixmap; /* Icon for drag data */ - GdkBitmap *mask; /* Stored button press information to detect drag beginning */ gint state; @@ -83,6 +82,7 @@ struct _GtkDragSourceInfo GdkDragAction possible_actions; /* Actions allowed by source */ GdkDragContext *context; /* drag context */ GtkWidget *icon_window; /* Window for drag */ + GtkWidget *fallback_icon; /* Window for drag used on other screens */ GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */ GdkCursor *cursor; /* Cursor for drag */ gint hot_x, hot_y; /* Hot spot for drag */ @@ -93,14 +93,18 @@ struct _GtkDragSourceInfo gint start_x, start_y; /* Initial position */ gint cur_x, cur_y; /* Current Position */ + GdkScreen *cur_screen; /* Current screen for pointer */ + guint32 grab_time; /* timestamp for initial grab */ GList *selections; /* selections we've claimed */ GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */ guint drop_timeout; /* Timeout for aborting drop */ guint destroy_icon : 1; /* If true, destroy icon_window - */ + */ + guint have_grab : 1; /* Do we still have the pointer grab + */ }; struct _GtkDragDestSite @@ -179,38 +183,41 @@ static void gtk_drag_get_event_actions (GdkEvent *event, 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 GdkCursor * gtk_drag_get_cursor (GdkDisplay *display, + GdkDragAction action); +static GtkWidget *gtk_drag_get_ipc_widget (GdkScreen *screen); static void gtk_drag_release_ipc_widget (GtkWidget *widget); static gboolean gtk_drag_highlight_expose (GtkWidget *widget, GdkEventExpose *event, gpointer data); -static void gtk_drag_selection_received (GtkWidget *widget, - GtkSelectionData *selection_data, - guint32 time, - gpointer data); -static void gtk_drag_find_widget (GtkWidget *widget, - GtkDragFindData *data); -static void gtk_drag_proxy_begin (GtkWidget *widget, - GtkDragDestInfo *dest_info, - guint32 time); -static void gtk_drag_dest_realized (GtkWidget *widget); -static void gtk_drag_dest_site_destroy (gpointer data); -static void gtk_drag_dest_leave (GtkWidget *widget, - GdkDragContext *context, - guint time); -static gboolean gtk_drag_dest_motion (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time); -static gboolean gtk_drag_dest_drop (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time); +static void gtk_drag_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data, + guint32 time, + gpointer data); +static void gtk_drag_find_widget (GtkWidget *widget, + GtkDragFindData *data); +static void gtk_drag_proxy_begin (GtkWidget *widget, + GtkDragDestInfo *dest_info, + guint32 time); +static void gtk_drag_dest_realized (GtkWidget *widget); +static void gtk_drag_dest_hierarchy_changed (GtkWidget *widget, + GtkWidget *previous_toplevel); +static void gtk_drag_dest_site_destroy (gpointer data); +static void gtk_drag_dest_leave (GtkWidget *widget, + GdkDragContext *context, + guint time); +static gboolean gtk_drag_dest_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); +static gboolean gtk_drag_dest_drop (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); static GtkDragDestInfo * gtk_drag_get_dest_info (GdkDragContext *context, gboolean create); @@ -228,6 +235,8 @@ static void gtk_drag_drop (GtkDragSourceInfo *info, static void gtk_drag_drop_finished (GtkDragSourceInfo *info, gboolean success, guint time); +static void gtk_drag_cancel (GtkDragSourceInfo *info, + guint32 time); static gint gtk_drag_source_event_cb (GtkWidget *widget, GdkEvent *event, @@ -242,6 +251,7 @@ static gint gtk_drag_anim_timeout (gpointer data); static void gtk_drag_remove_icon (GtkDragSourceInfo *info); static void gtk_drag_source_info_destroy (GtkDragSourceInfo *info); static void gtk_drag_update (GtkDragSourceInfo *info, + GdkScreen *screen, gint x_root, gint y_root, GdkEvent *event); @@ -335,8 +345,8 @@ static const guchar action_none_mask_bits[] = { static struct { GdkDragAction action; - const char *bits; - const char *mask; + const guchar *bits; + const guchar *mask; GdkCursor *cursor; } drag_cursors[] = { { GDK_ACTION_DEFAULT, 0 }, @@ -349,49 +359,27 @@ static struct { static const gint n_drag_cursors = sizeof (drag_cursors) / sizeof (drag_cursors[0]); -/* XPM */ -static const char *drag_default_xpm[] = { -"32 32 3 1", -" c None", -". c #000000", -"+ c #FFFFFF", -" ", -" ", -" .. ", -" ..+. ", -" ..++.. ", -" ...++++. ", -" ...++++++.. ", -" ...+++++++++. ", -" ...+++++++++++.. ", -" ..+.++++++++++++.. ", -" .++.++++++++++++.. ", -" .+++.++++++++++++.. ", -" .++++.++++++++++++. ", -" .+++.+++++++++++++.. ", -" .++.+++++++++++++++.. ", -" .+.+++++++++++++++++.. ", -" ..+++++++++++++++++++.. ", -" ..++++++++++++++++++++. ", -" .++++++++++++++++++++.. ", -" ..+++++++++++++++++.. ", -" .++++++++++++++++.. ", -" ..+++++++++++++... ", -" .++++++++++++.. ", -" ..+++++++++.. ", -" .++++++++.. ", -" ..++++++.. ", -" .+++++.. ", -" .++.. ", -" ... ", -" .. ", -" ", -" "}; - /********************* * Utility functions * *********************/ +static void +set_can_change_screen (GtkWidget *widget, + gboolean can_change_screen) +{ + can_change_screen = can_change_screen != FALSE; + + g_object_set_data (G_OBJECT (widget), "gtk-dnd-can-change-screen", + GUINT_TO_POINTER (can_change_screen)); +} + +static gboolean +get_can_change_screen (GtkWidget *widget) +{ + return g_object_get_data (G_OBJECT (widget), "gtk-dnd-can-change-screen") != NULL; + +} + /************************************************************* * gtk_drag_get_ipc_widget: * Return a invisible, off-screen, override-redirect @@ -402,20 +390,25 @@ static const char *drag_default_xpm[] = { *************************************************************/ static GtkWidget * -gtk_drag_get_ipc_widget (void) +gtk_drag_get_ipc_widget (GdkScreen *screen) { GtkWidget *result; + GSList *drag_widgets = g_object_get_data (G_OBJECT (screen), + "gtk-dnd-ipc-widgets"); if (drag_widgets) { GSList *tmp = drag_widgets; result = drag_widgets->data; drag_widgets = drag_widgets->next; + g_object_set_data (G_OBJECT (screen), + "gtk-dnd-ipc-widgets", + drag_widgets); g_slist_free_1 (tmp); } else { - result = gtk_invisible_new (); + result = gtk_invisible_new_for_screen (screen); gtk_widget_show (result); } @@ -433,7 +426,13 @@ gtk_drag_get_ipc_widget (void) static void gtk_drag_release_ipc_widget (GtkWidget *widget) { + GdkScreen *screen = gtk_widget_get_screen (widget); + GSList *drag_widgets = g_object_get_data (G_OBJECT (screen), + "gtk-dnd-ipc-widgets"); drag_widgets = g_slist_prepend (drag_widgets, widget); + g_object_set_data (G_OBJECT (screen), + "gtk-dnd-ipc-widgets", + drag_widgets); } static guint32 @@ -509,7 +508,7 @@ gtk_drag_get_event_actions (GdkEvent *event, default: break; } - + if ((button == 2 || button == 3) && (actions & GDK_ACTION_ASK)) { *suggested_action = GDK_ACTION_ASK; @@ -574,34 +573,40 @@ gtk_drag_get_event_actions (GdkEvent *event, } static GdkCursor * -gtk_drag_get_cursor (GdkDragAction action) +gtk_drag_get_cursor (GdkDisplay *display, + GdkDragAction action) { gint i; for (i = 0 ; i < n_drag_cursors - 1; i++) if (drag_cursors[i].action == action) break; + if (drag_cursors[i].cursor != NULL) + { + if (display != gdk_cursor_get_display (drag_cursors[i].cursor)) + { + gdk_cursor_unref (drag_cursors[i].cursor); + drag_cursors[i].cursor = NULL; + } + } if (drag_cursors[i].cursor == NULL) { - GdkColor fg, bg; + GdkColor bg = { 0, 0xffff, 0xffff, 0xffff }; + GdkColor fg = { 0, 0x0000, 0x0000, 0x0000 }; + GdkScreen *screen = gdk_display_get_default_screen (display); + GdkWindow *window = gdk_screen_get_root_window (screen); GdkPixmap *pixmap = - gdk_bitmap_create_from_data (NULL, - drag_cursors[i].bits, - CURSOR_WIDTH, CURSOR_HEIGHT); + gdk_bitmap_create_from_data (window, (gchar *)drag_cursors[i].bits, CURSOR_WIDTH, CURSOR_HEIGHT); + GdkPixmap *mask = - gdk_bitmap_create_from_data (NULL, - drag_cursors[i].mask, - CURSOR_WIDTH, CURSOR_HEIGHT); + gdk_bitmap_create_from_data (window, (gchar *)drag_cursors[i].mask, CURSOR_WIDTH, CURSOR_HEIGHT); - 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); - gdk_pixmap_unref (pixmap); - gdk_pixmap_unref (mask); + g_object_unref (pixmap); + g_object_unref (mask); } return drag_cursors[i].cursor; @@ -630,18 +635,19 @@ gtk_drag_get_data (GtkWidget *widget, { GtkWidget *selection_widget; - g_return_if_fail (widget != NULL); - g_return_if_fail (context != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); + g_return_if_fail (!context->is_source); - selection_widget = gtk_drag_get_ipc_widget (); + selection_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget)); - gdk_drag_context_ref (context); - gtk_widget_ref (widget); + g_object_ref (context); + g_object_ref (widget); - gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received", - GTK_SIGNAL_FUNC (gtk_drag_selection_received), widget); + g_signal_connect (selection_widget, "selection_received", + G_CALLBACK (gtk_drag_selection_received), widget); - gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context); + g_object_set_data (G_OBJECT (selection_widget), "drag-context", context); gtk_selection_convert (selection_widget, gdk_drag_get_selection (context), @@ -666,6 +672,9 @@ gtk_drag_get_source_widget (GdkDragContext *context) { GSList *tmp_list; + g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), NULL); + g_return_val_if_fail (!context->is_source, NULL); + tmp_list = source_widgets; while (tmp_list) { @@ -674,7 +683,7 @@ gtk_drag_get_source_widget (GdkDragContext *context) if (ipc_widget->window == context->source_window) { GtkDragSourceInfo *info; - info = gtk_object_get_data (GTK_OBJECT (ipc_widget), "gtk-info"); + info = g_object_get_data (G_OBJECT (ipc_widget), "gtk-info"); return info ? info->widget : NULL; } @@ -704,7 +713,8 @@ gtk_drag_finish (GdkDragContext *context, { GdkAtom target = GDK_NONE; - g_return_if_fail (context != NULL); + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); + g_return_if_fail (!context->is_source); if (success && del) { @@ -720,14 +730,14 @@ 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_drawable_get_screen (context->source_window)); - gdk_drag_context_ref (context); + g_object_ref (context); - gtk_object_set_data (GTK_OBJECT (selection_widget), "drag-context", context); - gtk_signal_connect (GTK_OBJECT (selection_widget), "selection_received", - GTK_SIGNAL_FUNC (gtk_drag_selection_received), - NULL); + g_object_set_data (G_OBJECT (selection_widget), "drag-context", context); + g_signal_connect (selection_widget, "selection_received", + G_CALLBACK (gtk_drag_selection_received), + NULL); gtk_selection_convert (selection_widget, gdk_drag_get_selection (context), @@ -735,7 +745,7 @@ gtk_drag_finish (GdkDragContext *context, time); } - if (!del) + if (!(success && del)) gdk_drop_finish (context, success, time); } @@ -769,12 +779,13 @@ gtk_drag_highlight_expose (GtkWidget *widget, { x = 0; y = 0; - gdk_window_get_size (widget->window, &width, &height); + gdk_drawable_get_size (widget->window, &width, &height); } - gtk_draw_shadow (widget->style, widget->window, - GTK_STATE_NORMAL, GTK_SHADOW_OUT, - x, y, width, height); + gtk_paint_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + NULL, widget, "dnd", + x, y, width, height); gdk_draw_rectangle (widget->window, widget->style->black_gc, @@ -782,7 +793,7 @@ gtk_drag_highlight_expose (GtkWidget *widget, x, y, width - 1, height - 1); } - return TRUE; + return FALSE; } /************************************************************* @@ -796,9 +807,11 @@ gtk_drag_highlight_expose (GtkWidget *widget, void gtk_drag_highlight (GtkWidget *widget) { - gtk_signal_connect (GTK_OBJECT (widget), "expose_event", - GTK_SIGNAL_FUNC (gtk_drag_highlight_expose), - NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + g_signal_connect_after (widget, "expose_event", + G_CALLBACK (gtk_drag_highlight_expose), + NULL); gtk_widget_queue_draw (widget); } @@ -814,13 +827,13 @@ gtk_drag_highlight (GtkWidget *widget) void gtk_drag_unhighlight (GtkWidget *widget) { - g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); - gtk_signal_disconnect_by_func (GTK_OBJECT (widget), - GTK_SIGNAL_FUNC (gtk_drag_highlight_expose), - NULL); + g_signal_handlers_disconnect_by_func (widget, + gtk_drag_highlight_expose, + NULL); - gtk_widget_queue_clear (widget); + gtk_widget_queue_draw (widget); } static void @@ -832,18 +845,27 @@ gtk_drag_dest_set_internal (GtkWidget *widget, g_return_if_fail (widget != NULL); /* HACK, do this in the destroy */ - old_site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); + old_site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"); if (old_site) - gtk_signal_disconnect_by_data (GTK_OBJECT (widget), old_site); + { + g_signal_handlers_disconnect_by_func (widget, + gtk_drag_dest_realized, + old_site); + g_signal_handlers_disconnect_by_func (widget, + gtk_drag_dest_hierarchy_changed, + 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); + g_signal_connect (widget, "realize", + G_CALLBACK (gtk_drag_dest_realized), site); + g_signal_connect (widget, "hierarchy_changed", + G_CALLBACK (gtk_drag_dest_hierarchy_changed), site); - gtk_object_set_data_full (GTK_OBJECT (widget), "gtk-drag-dest", - site, gtk_drag_dest_site_destroy); + g_object_set_data_full (G_OBJECT (widget), "gtk-drag-dest", + site, gtk_drag_dest_site_destroy); } @@ -868,7 +890,7 @@ gtk_drag_dest_set (GtkWidget *widget, { GtkDragDestSite *site; - g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); site = g_new (GtkDragDestSite, 1); @@ -878,9 +900,9 @@ gtk_drag_dest_set (GtkWidget *widget, site->target_list = gtk_target_list_new (targets, n_targets); else site->target_list = NULL; - site->actions = actions; site->do_proxy = FALSE; + site->proxy_window = NULL; gtk_drag_dest_set_internal (widget, site); } @@ -906,7 +928,8 @@ gtk_drag_dest_set_proxy (GtkWidget *widget, { GtkDragDestSite *site; - g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (!proxy_window || GDK_IS_WINDOW (proxy_window)); site = g_new (GtkDragDestSite, 1); @@ -916,7 +939,7 @@ gtk_drag_dest_set_proxy (GtkWidget *widget, site->actions = 0; site->proxy_window = proxy_window; if (proxy_window) - gdk_window_ref (proxy_window); + g_object_ref (proxy_window); site->do_proxy = TRUE; site->proxy_protocol = protocol; site->proxy_coords = use_coordinates; @@ -935,9 +958,9 @@ gtk_drag_dest_set_proxy (GtkWidget *widget, void gtk_drag_dest_unset (GtkWidget *widget) { - g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); - gtk_object_set_data (GTK_OBJECT (widget), "gtk-drag-dest", NULL); + g_object_set_data (G_OBJECT (widget), "gtk-drag-dest", NULL); } /** @@ -953,8 +976,10 @@ GtkTargetList* gtk_drag_dest_get_target_list (GtkWidget *widget) { GtkDragDestSite *site; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); + site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"); return site ? site->target_list : NULL; } @@ -973,8 +998,10 @@ gtk_drag_dest_set_target_list (GtkWidget *widget, GtkTargetList *target_list) { GtkDragDestSite *site; + + g_return_if_fail (GTK_IS_WIDGET (widget)); - site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); + site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"); if (site == NULL) { @@ -983,7 +1010,7 @@ gtk_drag_dest_set_target_list (GtkWidget *widget, } if (target_list) - gtk_target_list_ref (site->target_list); + gtk_target_list_ref (target_list); if (site->target_list) gtk_target_list_unref (site->target_list); @@ -993,7 +1020,7 @@ gtk_drag_dest_set_target_list (GtkWidget *widget, /************************************************************* - * gtk_drag_dest_handle_event: + * _gtk_drag_dest_handle_event: * Called from widget event handling code on Drag events * for destinations. * @@ -1004,7 +1031,7 @@ gtk_drag_dest_set_target_list (GtkWidget *widget, *************************************************************/ void -gtk_drag_dest_handle_event (GtkWidget *toplevel, +_gtk_drag_dest_handle_event (GtkWidget *toplevel, GdkEvent *event) { GtkDragDestInfo *info; @@ -1095,7 +1122,8 @@ gtk_drag_dest_handle_event (GtkWidget *toplevel, * gtk_drag_dest_find_target: * @widget: drag destination widget * @context: drag context - * @dest_target_list: list of droppable targets + * @target_list: list of droppable targets, or %NULL to use + * gtk_drag_dest_get_target_list (@widget). * * Looks for a match between @context->targets and the * @dest_target_list, returning the first matching target, otherwise @@ -1110,16 +1138,26 @@ gtk_drag_dest_handle_event (GtkWidget *toplevel, GdkAtom gtk_drag_dest_find_target (GtkWidget *widget, GdkDragContext *context, - GtkTargetList *dest_target_list) + GtkTargetList *target_list) { GList *tmp_target; GList *tmp_source = NULL; - GtkWidget *source_widget = gtk_drag_get_source_widget (context); + GtkWidget *source_widget; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), GDK_NONE); + g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), GDK_NONE); + g_return_val_if_fail (!context->is_source, GDK_NONE); - if (dest_target_list == NULL) + + source_widget = gtk_drag_get_source_widget (context); + + if (target_list == NULL) + target_list = gtk_drag_dest_get_target_list (widget); + + if (target_list == NULL) return GDK_NONE; - tmp_target = dest_target_list->list; + tmp_target = target_list->list; while (tmp_target) { GtkTargetPair *pair = tmp_target->data; @@ -1154,7 +1192,7 @@ gtk_drag_selection_received (GtkWidget *widget, drop_widget = data; - context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context"); + context = g_object_get_data (G_OBJECT (widget), "drag-context"); info = gtk_drag_get_dest_info (context, FALSE); if (info->proxy_data && @@ -1182,7 +1220,7 @@ gtk_drag_selection_received (GtkWidget *widget, { GtkDragDestSite *site; - site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest"); + site = g_object_get_data (G_OBJECT (drop_widget), "gtk-drag-dest"); if (site && site->target_list) { @@ -1194,19 +1232,20 @@ gtk_drag_selection_received (GtkWidget *widget, { if (!(site->flags & GTK_DEST_DEFAULT_DROP) || selection_data->length >= 0) - gtk_signal_emit_by_name (GTK_OBJECT (drop_widget), - "drag_data_received", - context, info->drop_x, info->drop_y, - selection_data, - target_info, time); + g_signal_emit_by_name (drop_widget, + "drag_data_received", + context, info->drop_x, info->drop_y, + selection_data, + target_info, time); } } else { - gtk_signal_emit_by_name (GTK_OBJECT (drop_widget), - "drag_data_received", - context, info->drop_x, info->drop_y, - selection_data, 0, time); + g_signal_emit_by_name (drop_widget, + "drag_data_received", + context, info->drop_x, info->drop_y, + selection_data, + 0, time); } if (site && site->flags & GTK_DEST_DEFAULT_DROP) @@ -1218,19 +1257,28 @@ gtk_drag_selection_received (GtkWidget *widget, time); } - gtk_widget_unref (drop_widget); + g_object_unref (drop_widget); } - gtk_signal_disconnect_by_func (GTK_OBJECT (widget), - GTK_SIGNAL_FUNC (gtk_drag_selection_received), - data); + g_signal_handlers_disconnect_by_func (widget, + gtk_drag_selection_received, + data); - gtk_object_set_data (GTK_OBJECT (widget), "drag-context", NULL); - gdk_drag_context_unref (context); + g_object_set_data (G_OBJECT (widget), "drag-context", NULL); + g_object_unref (context); gtk_drag_release_ipc_widget (widget); } +static void +prepend_and_ref_widget (GtkWidget *widget, + gpointer data) +{ + GSList **slist_p = data; + + *slist_p = g_slist_prepend (*slist_p, g_object_ref (widget)); +} + /************************************************************* * gtk_drag_find_widget: * Recursive callback used to locate widgets for @@ -1245,12 +1293,12 @@ gtk_drag_find_widget (GtkWidget *widget, GtkDragFindData *data) { GtkAllocation new_allocation; + gint allocation_to_window_x = 0; + gint allocation_to_window_y = 0; gint x_offset = 0; gint y_offset = 0; - new_allocation = widget->allocation; - - if (data->found || !GTK_WIDGET_MAPPED (widget)) + if (data->found || !GTK_WIDGET_MAPPED (widget) || !GTK_WIDGET_SENSITIVE (widget)) return; /* Note that in the following code, we only count the @@ -1258,35 +1306,49 @@ gtk_drag_find_widget (GtkWidget *widget, * 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; - new_allocation.y = 0; - } - + * + * data->x,y are relative to widget->parent->window (if + * widget is not a toplevel, widget->window otherwise). + * We compute the allocation of widget in the same coordinates, + * clipping to widget->window, and all intermediate + * windows. If data->x,y is inside that, then we translate + * our coordinates to be relative to widget->window and + * recurse. + */ + new_allocation = widget->allocation; + if (widget->parent) { + gint tx, ty; GdkWindow *window = widget->window; - while (window != widget->parent->window) + + /* Compute the offset from allocation-relative to + * window-relative coordinates. + */ + allocation_to_window_x = widget->allocation.x; + allocation_to_window_y = widget->allocation.y; + + if (!GTK_WIDGET_NO_WINDOW (widget)) { - gint tx, ty, twidth, theight; - gdk_window_get_size (window, &twidth, &theight); + /* The allocation is relative to the parent window for + * window widgets, not to widget->window. + */ + gdk_window_get_position (window, &tx, &ty); + + allocation_to_window_x -= tx; + allocation_to_window_y -= ty; + } - if (new_allocation.x < 0) - { - new_allocation.width += new_allocation.x; - new_allocation.x = 0; - } - if (new_allocation.y < 0) - { - new_allocation.height += new_allocation.y; - new_allocation.y = 0; - } - if (new_allocation.x + new_allocation.width > twidth) - new_allocation.width = twidth - new_allocation.x; - if (new_allocation.y + new_allocation.height > theight) - new_allocation.height = theight - new_allocation.y; + new_allocation.x = 0 + allocation_to_window_x; + new_allocation.y = 0 + allocation_to_window_y; + + while (window && window != widget->parent->window) + { + GdkRectangle window_rect = { 0, 0, 0, 0 }; + + gdk_drawable_get_size (window, &window_rect.width, &window_rect.height); + + gdk_rectangle_intersect (&new_allocation, &window_rect, &new_allocation); gdk_window_get_position (window, &tx, &ty); new_allocation.x += tx; @@ -1296,6 +1358,9 @@ gtk_drag_find_widget (GtkWidget *widget, window = gdk_window_get_parent (window); } + + if (!window) /* Window and widget heirarchies didn't match. */ + return; } if (data->toplevel || @@ -1309,15 +1374,25 @@ gtk_drag_find_widget (GtkWidget *widget, if (GTK_IS_CONTAINER (widget)) { GtkDragFindData new_data = *data; + GSList *children = NULL; + GSList *tmp_list; new_data.x -= x_offset; new_data.y -= y_offset; new_data.found = FALSE; new_data.toplevel = FALSE; - gtk_container_forall (GTK_CONTAINER (widget), - (GtkCallback)gtk_drag_find_widget, - &new_data); + /* need to reference children temporarily in case the + * ::drag_motion/::drag_drop callbacks change the widget heirarchy. + */ + gtk_container_forall (GTK_CONTAINER (widget), prepend_and_ref_widget, &children); + for (tmp_list = children; tmp_list; tmp_list = tmp_list->next) + { + if (!new_data.found && GTK_WIDGET_DRAWABLE (tmp_list->data)) + gtk_drag_find_widget (tmp_list->data, &new_data); + g_object_unref (tmp_list->data); + } + g_slist_free (children); data->found = new_data.found; } @@ -1327,12 +1402,12 @@ gtk_drag_find_widget (GtkWidget *widget, * a drop site. */ if (!data->found && - gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest")) + g_object_get_data (G_OBJECT (widget), "gtk-drag-dest")) { data->found = data->callback (widget, data->context, - data->x - new_allocation.x, - data->y - new_allocation.y, + data->x - x_offset - allocation_to_window_x, + data->y - y_offset - allocation_to_window_y, data->time); /* If so, send a "drag_leave" to the last widget */ if (data->found) @@ -1364,7 +1439,7 @@ gtk_drag_proxy_begin (GtkWidget *widget, dest_info->proxy_source = NULL; } - ipc_widget = gtk_drag_get_ipc_widget (); + ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget)); context = gdk_drag_begin (ipc_widget->window, dest_info->context->targets); @@ -1378,16 +1453,16 @@ gtk_drag_proxy_begin (GtkWidget *widget, while (tmp_list) { gtk_target_list_add (source_info->target_list, - GPOINTER_TO_UINT (tmp_list->data), 0, 0); + GDK_POINTER_TO_ATOM (tmp_list->data), 0, 0); tmp_list = tmp_list->next; } source_info->proxy_dest = dest_info; - gtk_signal_connect (GTK_OBJECT (ipc_widget), - "selection_get", - GTK_SIGNAL_FUNC (gtk_drag_selection_get), - source_info); + g_signal_connect (ipc_widget, + "selection_get", + G_CALLBACK (gtk_drag_selection_get), + source_info); dest_info->proxy_source = source_info; } @@ -1457,7 +1532,19 @@ static void gtk_drag_dest_realized (GtkWidget *widget) { GtkWidget *toplevel = gtk_widget_get_toplevel (widget); - gdk_window_register_dnd (toplevel->window); + + if (GTK_WIDGET_TOPLEVEL (toplevel)) + gdk_window_register_dnd (toplevel->window); +} + +static void +gtk_drag_dest_hierarchy_changed (GtkWidget *widget, + GtkWidget *previous_toplevel) +{ + GtkWidget *toplevel = gtk_widget_get_toplevel (widget); + + if (GTK_WIDGET_TOPLEVEL (toplevel) && GTK_WIDGET_REALIZED (toplevel)) + gdk_window_register_dnd (toplevel->window); } static void @@ -1465,6 +1552,9 @@ gtk_drag_dest_site_destroy (gpointer data) { GtkDragDestSite *site = data; + if (site->proxy_window) + g_object_unref (site->proxy_window); + if (site->target_list) gtk_target_list_unref (site->target_list); @@ -1481,7 +1571,7 @@ gtk_drag_dest_leave (GtkWidget *widget, { GtkDragDestSite *site; - site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); + site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"); g_return_if_fail (site != NULL); if (site->do_proxy) @@ -1503,8 +1593,8 @@ gtk_drag_dest_leave (GtkWidget *widget, gtk_drag_unhighlight (widget); if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag) - gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_leave", - context, time); + g_signal_emit_by_name (widget, "drag_leave", + context, time); site->have_drag = FALSE; } @@ -1521,7 +1611,7 @@ gtk_drag_dest_motion (GtkWidget *widget, GdkDragAction action = 0; gboolean retval; - site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); + site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"); g_return_val_if_fail (site != NULL, FALSE); if (site->do_proxy) @@ -1545,11 +1635,12 @@ gtk_drag_dest_motion (GtkWidget *widget, } else { - gdk_drag_find_window (info->proxy_source->context, - NULL, - current_event->dnd.x_root, - current_event->dnd.y_root, - &dest_window, &proto); + gdk_drag_find_window_for_screen (info->proxy_source->context, + NULL, + gdk_drawable_get_screen (current_event->dnd.window), + current_event->dnd.x_root, + current_event->dnd.y_root, + &dest_window, &proto); } gdk_drag_motion (info->proxy_source->context, @@ -1560,7 +1651,7 @@ gtk_drag_dest_motion (GtkWidget *widget, context->actions, time); if (!site->proxy_window && dest_window) - gdk_window_unref (dest_window); + g_object_unref (dest_window); selection = gdk_drag_get_selection (info->proxy_source->context); if (selection && @@ -1591,7 +1682,7 @@ gtk_drag_dest_motion (GtkWidget *widget, } } - if (action && gtk_drag_dest_find_target (widget, context, site->target_list)) + if (action && gtk_drag_dest_find_target (widget, context, NULL)) { if (!site->have_drag) { @@ -1609,8 +1700,8 @@ gtk_drag_dest_motion (GtkWidget *widget, } } - gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_motion", - context, x, y, time, &retval); + g_signal_emit_by_name (widget, "drag_motion", + context, x, y, time, &retval); return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval; } @@ -1625,7 +1716,7 @@ gtk_drag_dest_drop (GtkWidget *widget, GtkDragDestSite *site; GtkDragDestInfo *info; - site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); + site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest"); g_return_val_if_fail (site != NULL, FALSE); info = gtk_drag_get_dest_info (context, FALSE); @@ -1665,11 +1756,12 @@ gtk_drag_dest_drop (GtkWidget *widget, } else { - gdk_drag_find_window (info->proxy_source->context, - NULL, - current_event->dnd.x_root, - current_event->dnd.y_root, - &dest_window, &proto); + gdk_drag_find_window_for_screen (info->proxy_source->context, + NULL, + gdk_drawable_get_screen (current_event->dnd.window), + current_event->dnd.x_root, + current_event->dnd.y_root, + &dest_window, &proto); } gdk_drag_motion (info->proxy_source->context, @@ -1680,7 +1772,7 @@ gtk_drag_dest_drop (GtkWidget *widget, context->actions, time); if (!site->proxy_window && dest_window) - gdk_window_unref (dest_window); + g_object_unref (dest_window); selection = gdk_drag_get_selection (info->proxy_source->context); if (selection && @@ -1698,16 +1790,19 @@ gtk_drag_dest_drop (GtkWidget *widget, if (site->flags & GTK_DEST_DEFAULT_DROP) { - GdkAtom target = gtk_drag_dest_find_target (widget, context, site->target_list); + GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL); if (target == GDK_NONE) - return FALSE; - - gtk_drag_get_data (widget, context, target, time); + { + gtk_drag_finish (context, FALSE, FALSE, time); + return TRUE; + } + else + gtk_drag_get_data (widget, context, target, time); } - gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_drop", - context, x, y, time, &retval); + g_signal_emit_by_name (widget, "drag_drop", + context, x, y, time, &retval); return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval; } @@ -1744,7 +1839,7 @@ gtk_drag_begin (GtkWidget *widget, GdkDragContext *context; GtkWidget *ipc_widget; - g_return_val_if_fail (widget != NULL, NULL); + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL); g_return_val_if_fail (target_list != NULL, NULL); @@ -1760,7 +1855,7 @@ gtk_drag_begin (GtkWidget *widget, tmp_list = tmp_list->prev; } - ipc_widget = gtk_drag_get_ipc_widget (); + ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget)); source_widgets = g_slist_prepend (source_widgets, ipc_widget); context = gdk_drag_begin (ipc_widget->window, targets); @@ -1769,10 +1864,9 @@ gtk_drag_begin (GtkWidget *widget, info = gtk_drag_get_source_info (context, TRUE); info->ipc_widget = ipc_widget; - gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info); + g_object_set_data (G_OBJECT (info->ipc_widget), "gtk-info", info); info->widget = gtk_widget_ref (widget); - info->button = button; info->target_list = target_list; @@ -1789,28 +1883,26 @@ gtk_drag_begin (GtkWidget *widget, gtk_drag_get_event_actions (event, info->button, actions, &suggested_action, &possible_actions); - - info->cursor = gtk_drag_get_cursor (suggested_action); + + info->cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget), suggested_action); /* 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_screen = gtk_widget_get_screen (widget); 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); - - info->cur_x = x; - info->cur_y = y; + gdk_display_get_pointer (gtk_widget_get_display (widget), + &info->cur_screen, &info->cur_x, &info->cur_y, NULL); } - gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin", - info->context); + g_signal_emit_by_name (widget, "drag_begin", + info->context); if (event && event->type == GDK_MOTION_NOTIFY) gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info); @@ -1818,16 +1910,16 @@ gtk_drag_begin (GtkWidget *widget, info->start_x = info->cur_x; info->start_y = info->cur_y; - gtk_signal_connect (GTK_OBJECT (info->ipc_widget), "button_release_event", - 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); + g_signal_connect (info->ipc_widget, "button_release_event", + G_CALLBACK (gtk_drag_button_release_cb), info); + g_signal_connect (info->ipc_widget, "motion_notify_event", + G_CALLBACK (gtk_drag_motion_cb), info); + g_signal_connect (info->ipc_widget, "key_press_event", + G_CALLBACK (gtk_drag_key_cb), info); + g_signal_connect (info->ipc_widget, "key_release_event", + G_CALLBACK (gtk_drag_key_cb), info); + g_signal_connect (info->ipc_widget, "selection_get", + G_CALLBACK (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 @@ -1840,19 +1932,14 @@ gtk_drag_begin (GtkWidget *widget, { 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); - + gtk_drag_cancel (info, time); return NULL; } } + info->have_grab = TRUE; + info->grab_time = time; + return info->context; } @@ -1877,9 +1964,9 @@ gtk_drag_source_set (GtkWidget *widget, { GtkDragSourceSite *site; - g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); - site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data"); + site = g_object_get_data (G_OBJECT (widget), "gtk-site-data"); gtk_widget_add_events (widget, gtk_widget_get_events (widget) | @@ -1894,17 +1981,19 @@ gtk_drag_source_set (GtkWidget *widget, else { site = g_new0 (GtkDragSourceSite, 1); + + site->icon_type = GTK_IMAGE_EMPTY; - gtk_signal_connect (GTK_OBJECT (widget), "button_press_event", - GTK_SIGNAL_FUNC (gtk_drag_source_event_cb), - site); - gtk_signal_connect (GTK_OBJECT (widget), "motion_notify_event", - GTK_SIGNAL_FUNC (gtk_drag_source_event_cb), - site); + g_signal_connect (widget, "button_press_event", + G_CALLBACK (gtk_drag_source_event_cb), + site); + g_signal_connect (widget, "motion_notify_event", + G_CALLBACK (gtk_drag_source_event_cb), + site); - gtk_object_set_data_full (GTK_OBJECT (widget), - "gtk-site-data", - site, gtk_drag_source_site_destroy); + g_object_set_data_full (G_OBJECT (widget), + "gtk-site-data", + site, gtk_drag_source_site_destroy); } site->start_button_mask = start_button_mask; @@ -1931,27 +2020,64 @@ gtk_drag_source_unset (GtkWidget *widget) { GtkDragSourceSite *site; - g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); - site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data"); + site = g_object_get_data (G_OBJECT (widget), "gtk-site-data"); if (site) { - gtk_signal_disconnect_by_data (GTK_OBJECT (widget), site); - gtk_object_set_data (GTK_OBJECT (widget), "gtk-site-data", NULL); + g_signal_handlers_disconnect_by_func (widget, + gtk_drag_source_event_cb, + site); + g_signal_handlers_disconnect_by_func (widget, + gtk_drag_source_event_cb, + site); + g_object_set_data (G_OBJECT (widget), "gtk-site-data", NULL); } } -/************************************************************* - * gtk_drag_source_set_icon: - * Set an icon for drags from this source. - * arguments: - * colormap: Colormap for this icon - * pixmap: - * mask - * results: - *************************************************************/ +static void +gtk_drag_source_unset_icon (GtkDragSourceSite *site) +{ + switch (site->icon_type) + { + case GTK_IMAGE_EMPTY: + break; + case GTK_IMAGE_PIXMAP: + if (site->icon_data.pixmap.pixmap) + g_object_unref (site->icon_data.pixmap.pixmap); + if (site->icon_mask) + g_object_unref (site->icon_mask); + break; + case GTK_IMAGE_PIXBUF: + g_object_unref (site->icon_data.pixbuf.pixbuf); + break; + case GTK_IMAGE_STOCK: + g_free (G_OBJECT (site->icon_data.stock.stock_id)); + break; + default: + g_assert_not_reached(); + break; + } + site->icon_type = GTK_IMAGE_EMPTY; + + if (site->colormap) + g_object_unref (site->colormap); + site->colormap = NULL; +} +/** + * gtk_drag_source_set_icon: + * @widget: a #GtkWidget + * @colormap: the colormap of the icon + * @pixmap: the image data for the icon + * @mask: the transparency mask for an image. + * + * Sets the icon that will be used for drags from a particular widget + * from a pixmap/mask. GTK+ retains references for the arguments, and + * will release them when they are no longer needed. + * Use gtk_drag_source_set_icon_pixbuf() instead. + **/ void gtk_drag_source_set_icon (GtkWidget *widget, GdkColormap *colormap, @@ -1960,41 +2086,163 @@ gtk_drag_source_set_icon (GtkWidget *widget, { GtkDragSourceSite *site; - g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (GDK_IS_COLORMAP (colormap)); + g_return_if_fail (GDK_IS_PIXMAP (pixmap)); + g_return_if_fail (!mask || GDK_IS_PIXMAP (mask)); - site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data"); + site = g_object_get_data (G_OBJECT (widget), "gtk-site-data"); g_return_if_fail (site != NULL); - if (site->colormap) - gdk_colormap_unref (site->colormap); - if (site->pixmap) - gdk_pixmap_unref (site->pixmap); - if (site->mask) - gdk_pixmap_unref (site->mask); + g_object_ref (colormap); + g_object_ref (pixmap); + if (mask) + g_object_ref (mask); + gtk_drag_source_unset_icon (site); + + site->icon_type = GTK_IMAGE_PIXMAP; + + site->icon_data.pixmap.pixmap = pixmap; + site->icon_mask = mask; site->colormap = colormap; - if (colormap) - gdk_colormap_ref (colormap); +} - site->pixmap = pixmap; - if (pixmap) - gdk_pixmap_ref (pixmap); +/** + * gtk_drag_source_set_icon_pixbuf: + * @widget: a #GtkWidget + * @pixbuf: the #GdkPixbuf for the drag icon + * + * Sets the icon that will be used for drags from a particular widget + * from a #GdkPixbuf. GTK+ retains a reference for @pixbuf and will + * release it when it is no longer needed. + **/ +void +gtk_drag_source_set_icon_pixbuf (GtkWidget *widget, + GdkPixbuf *pixbuf) +{ + GtkDragSourceSite *site; - site->mask = mask; - if (mask) - gdk_pixmap_ref (mask); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); + + site = g_object_get_data (G_OBJECT (widget), "gtk-site-data"); + g_return_if_fail (site != NULL); + g_object_ref (pixbuf); + + gtk_drag_source_unset_icon (site); + + site->icon_type = GTK_IMAGE_PIXBUF; + site->icon_data.pixbuf.pixbuf = pixbuf; } -/************************************************************* - * gtk_drag_set_icon_window: - * Set a widget as the icon for a drag. - * arguments: - * context: - * widget: - * hot_x: Hot spot - * hot_y: - * results: - *************************************************************/ +/** + * gtk_drag_source_set_icon_stock: + * @widget: a #GtkWidget + * @stock_id: the ID of the stock icon to use + * + * Sets the icon that will be used for drags from a particular source + * to a stock icon. + **/ +void +gtk_drag_source_set_icon_stock (GtkWidget *widget, + const gchar *stock_id) +{ + GtkDragSourceSite *site; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (stock_id != NULL); + + site = g_object_get_data (G_OBJECT (widget), "gtk-site-data"); + g_return_if_fail (site != NULL); + + gtk_drag_source_unset_icon (site); + + site->icon_data.stock.stock_id = g_strdup (stock_id); +} + +static void +gtk_drag_get_icon (GtkDragSourceInfo *info, + GtkWidget **icon_window, + gint *hot_x, + gint *hot_y) +{ + if (get_can_change_screen (info->icon_window)) + gtk_window_set_screen (GTK_WINDOW (info->icon_window), + info->cur_screen); + + if (gtk_widget_get_screen (info->icon_window) != info->cur_screen) + { + if (!info->fallback_icon) + { + gint save_hot_x, save_hot_y; + gboolean save_destroy_icon; + GtkWidget *save_icon_window; + + /* HACK to get the appropriate icon + */ + save_icon_window = info->icon_window; + save_hot_x = info->hot_x; + save_hot_y = info->hot_x; + save_destroy_icon = info->destroy_icon; + + info->icon_window = NULL; + gtk_drag_set_icon_default (info->context); + info->fallback_icon = info->icon_window; + + info->icon_window = save_icon_window; + info->hot_x = save_hot_x; + info->hot_y = save_hot_y; + info->destroy_icon = save_destroy_icon; + } + + gtk_widget_hide (info->icon_window); + + *icon_window = info->fallback_icon; + gtk_window_set_screen (GTK_WINDOW (*icon_window), info->cur_screen); + + if (!default_icon_pixmap) + { + *hot_x = -2; + *hot_y = -2; + } + else + { + *hot_x = default_icon_hot_x; + *hot_y = default_icon_hot_y; + } + } + else + { + if (info->fallback_icon) + gtk_widget_hide (info->fallback_icon); + + *icon_window = info->icon_window; + *hot_x = info->hot_x; + *hot_y = info->hot_y; + } +} + +static void +gtk_drag_update_icon (GtkDragSourceInfo *info) +{ + if (info->icon_window) + { + GtkWidget *icon_window; + gint hot_x, hot_y; + + gtk_drag_get_icon (info, &icon_window, &hot_x, &hot_y); + + gtk_window_move (GTK_WINDOW (icon_window), + info->cur_x - hot_x, + info->cur_y - hot_y); + + if (GTK_WIDGET_VISIBLE (icon_window)) + gdk_window_raise (icon_window->window); + else + gtk_widget_show (icon_window); + } +} static void gtk_drag_set_icon_window (GdkDragContext *context, @@ -2005,65 +2253,188 @@ gtk_drag_set_icon_window (GdkDragContext *context, { GtkDragSourceInfo *info; - g_return_if_fail (context != NULL); - g_return_if_fail (widget != NULL); - info = gtk_drag_get_source_info (context, FALSE); gtk_drag_remove_icon (info); + if (widget) + gtk_widget_ref (widget); + 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->hot_x, - info->cur_y - info->hot_y); - gtk_widget_ref (widget); - gdk_window_raise (widget->window); - gtk_widget_show (widget); - } - info->destroy_icon = destroy_on_release; + + gtk_drag_update_icon (info); } -/************************************************************* +/** * gtk_drag_set_icon_widget: - * Set a widget as the icon for a drag. - * arguments: - * context: - * widget: - * hot_x: Hot spot - * hot_y: - * results: - *************************************************************/ - + * @context: the context for a drag. (This must be called + with a context for the source side of a drag) + * @widget: a toplevel window to use as an icon. + * @hot_x: the X offset within @widget of the hotspot. + * @hot_y: the Y offset within @widget of the hotspot. + * + * Changes the icon for a widget to a given widget. GTK+ + * will not destroy the icon, so if you don't want + * it to persist, you should connect to the "drag_end" + * signal and destroy it yourself. + **/ 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); + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); + g_return_if_fail (context->is_source); + g_return_if_fail (GTK_IS_WIDGET (widget)); gtk_drag_set_icon_window (context, widget, hot_x, hot_y, FALSE); } -/************************************************************* - * gtk_drag_set_icon_pixmap: - * Set a widget as the icon for a drag. - * arguments: - * context: - * colormap: Colormap for the icon window. - * pixmap: - * mask: - * hot_x: Hot spot - * hot_y: - * results: - *************************************************************/ +static void +icon_window_realize (GtkWidget *window, + GdkPixbuf *pixbuf) +{ + GdkPixmap *pixmap; + GdkPixmap *mask; + + gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf, + gtk_widget_get_colormap (window), + &pixmap, &mask, 128); + + gdk_window_set_back_pixmap (window->window, pixmap, FALSE); + + if (mask) + gtk_widget_shape_combine_mask (window, mask, 0, 0); + + g_object_unref (G_OBJECT (pixmap)); + + if (mask) + g_object_unref (G_OBJECT (mask)); +} + +static void +set_icon_stock_pixbuf (GdkDragContext *context, + const gchar *stock_id, + GdkPixbuf *pixbuf, + gint hot_x, + gint hot_y) +{ + GtkWidget *window; + gint width, height; + GdkScreen *screen; + + g_return_if_fail (context != NULL); + g_return_if_fail (pixbuf != NULL || stock_id != NULL); + g_return_if_fail (pixbuf == NULL || stock_id == NULL); + + screen = gdk_drawable_get_screen (context->source_window); + + /* Push a NULL colormap to guard against gtk_widget_push_colormap() */ + gtk_widget_push_colormap (NULL); + window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_screen (GTK_WINDOW (window), screen); + set_can_change_screen (window, TRUE); + gtk_widget_pop_colormap (); + + gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); + gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE); + + if (stock_id) + { + pixbuf = gtk_widget_render_icon (window, stock_id, + GTK_ICON_SIZE_DND, NULL); + + if (!pixbuf) + { + g_warning ("Cannot load drag icon from stock_id %s", stock_id); + gtk_widget_destroy (window); + return; + } + + } + else + g_object_ref (pixbuf); + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_width (pixbuf); + + gtk_widget_set_size_request (window, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf)); + + g_signal_connect_closure (window, "realize", + g_cclosure_new (G_CALLBACK (icon_window_realize), + pixbuf, + (GClosureNotify)g_object_unref), + FALSE); + + gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE); +} +/** + * gtk_drag_set_icon_pixbuf: + * @context: the context for a drag. (This must be called + * with a context for the source side of a drag) + * @pixbuf: the #GdkPixbuf to use as the drag icon. + * @hot_x: the X offset within @widget of the hotspot. + * @hot_y: the Y offset within @widget of the hotspot. + * + * Sets @pixbuf as the icon for a given drag. + **/ +void +gtk_drag_set_icon_pixbuf (GdkDragContext *context, + GdkPixbuf *pixbuf, + gint hot_x, + gint hot_y) +{ + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); + g_return_if_fail (context->is_source); + g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); + + set_icon_stock_pixbuf (context, NULL, pixbuf, hot_x, hot_y); +} + +/** + * gtk_drag_set_icon_stock: + * @context: the context for a drag. (This must be called + * with a context for the source side of a drag) + * @stock_id: the ID of the stock icon to use for the drag. + * @hot_x: the X offset within the icon of the hotspot. + * @hot_y: the Y offset within the icon of the hotspot. + * + * Sets the the icon for a given drag from a stock ID. + **/ +void +gtk_drag_set_icon_stock (GdkDragContext *context, + const gchar *stock_id, + gint hot_x, + gint hot_y) +{ + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); + g_return_if_fail (context->is_source); + g_return_if_fail (stock_id != NULL); + + set_icon_stock_pixbuf (context, stock_id, NULL, hot_x, hot_y); +} + +/** + * gtk_drag_set_icon_pixmap: + * @context: the context for a drag. (This must be called + * with a context for the source side of a drag) + * @colormap: the colormap of the icon + * @pixmap: the image data for the icon + * @mask: the transparency mask for the icon + * @hot_x: the X offset within @pixmap of the hotspot. + * @hot_y: the Y offset within @pixmap of the hotspot. + * + * Sets @pixmap as the icon for a given drag. GTK+ retains + * references for the arguments, and will release them when + * they are no longer needed. In general, gtk_drag_set_icon_pixbuf() + * will be more convenient to use. + **/ void gtk_drag_set_icon_pixmap (GdkDragContext *context, GdkColormap *colormap, @@ -2073,23 +2444,33 @@ gtk_drag_set_icon_pixmap (GdkDragContext *context, gint hot_y) { GtkWidget *window; + GdkScreen *screen; gint width, height; - g_return_if_fail (context != NULL); - g_return_if_fail (colormap != NULL); - g_return_if_fail (pixmap != NULL); + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); + g_return_if_fail (context->is_source); + g_return_if_fail (GDK_IS_COLORMAP (colormap)); + g_return_if_fail (GDK_IS_PIXMAP (pixmap)); + g_return_if_fail (!mask || GDK_IS_PIXMAP (mask)); - gdk_window_get_size (pixmap, &width, &height); + screen = gdk_colormap_get_screen (colormap); + + g_return_if_fail (gdk_drawable_get_screen (pixmap) == screen); + g_return_if_fail (!mask || gdk_drawable_get_screen (mask) == screen); + + gdk_drawable_get_size (pixmap, &width, &height); gtk_widget_push_colormap (colormap); window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_screen (GTK_WINDOW (window), screen); + set_can_change_screen (window, FALSE); 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_colormap (); - gtk_widget_set_usize (window, width, height); + gtk_widget_set_size_request (window, width, height); gtk_widget_realize (window); gdk_window_set_back_pixmap (window->window, pixmap, FALSE); @@ -2100,51 +2481,44 @@ gtk_drag_set_icon_pixmap (GdkDragContext *context, gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE); } -/************************************************************* +/** * gtk_drag_set_icon_default: - * Set the icon for a drag to the default icon. - * arguments: - * context: - * results: - *************************************************************/ - + * @context: the context for a drag. (This must be called + with a context for the source side of a drag) + * + * Sets the icon for a particular drag to the default + * icon. + **/ void gtk_drag_set_icon_default (GdkDragContext *context) { - g_return_if_fail (context != NULL); + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); + g_return_if_fail (context->is_source); if (!default_icon_pixmap) - { - default_icon_colormap = gdk_colormap_get_system (); - default_icon_pixmap = - gdk_pixmap_colormap_create_from_xpm_d (NULL, - default_icon_colormap, - &default_icon_mask, - NULL, (gchar **)drag_default_xpm); - default_icon_hot_x = -2; - default_icon_hot_y = -2; - } - - gtk_drag_set_icon_pixmap (context, - default_icon_colormap, - default_icon_pixmap, - default_icon_mask, - default_icon_hot_x, - default_icon_hot_y); + gtk_drag_set_icon_stock (context, GTK_STOCK_DND, -2, -2); + else + gtk_drag_set_icon_pixmap (context, + default_icon_colormap, + default_icon_pixmap, + default_icon_mask, + default_icon_hot_x, + default_icon_hot_y); } -/************************************************************* +/** * gtk_drag_set_default_icon: - * Set a default icon for all drags as a pixmap. - * arguments: - * colormap: Colormap for the icon window. - * pixmap: - * mask: - * hot_x: Hot spot - * hot_y: - * results: - *************************************************************/ - + * @colormap: the colormap of the icon + * @pixmap: the image data for the icon + * @mask: the transparency mask for an image. + * @hot_x: The X offset within @widget of the hotspot. + * @hot_y: The Y offset within @widget of the hotspot. + * + * Changes the default drag icon. GTK+ retains references for the + * arguments, and will release them when they are no longer needed. + * This function is obsolete. The default icon should now be changed + * via the stock system by changing the stock pixbuf for #GTK_STOCK_DND. + **/ void gtk_drag_set_default_icon (GdkColormap *colormap, GdkPixmap *pixmap, @@ -2152,25 +2526,26 @@ gtk_drag_set_default_icon (GdkColormap *colormap, gint hot_x, gint hot_y) { - g_return_if_fail (colormap != NULL); - g_return_if_fail (pixmap != NULL); + g_return_if_fail (GDK_IS_COLORMAP (colormap)); + g_return_if_fail (GDK_IS_PIXMAP (pixmap)); + g_return_if_fail (!mask || GDK_IS_PIXMAP (mask)); if (default_icon_colormap) - gdk_colormap_unref (default_icon_colormap); + g_object_unref (default_icon_colormap); if (default_icon_pixmap) - gdk_pixmap_unref (default_icon_pixmap); + g_object_unref (default_icon_pixmap); if (default_icon_mask) - gdk_pixmap_unref (default_icon_mask); + g_object_unref (default_icon_mask); default_icon_colormap = colormap; - gdk_colormap_ref (colormap); + g_object_ref (colormap); default_icon_pixmap = pixmap; - gdk_pixmap_ref (pixmap); + g_object_ref (pixmap); default_icon_mask = mask; if (mask) - gdk_pixmap_ref (mask); + g_object_ref (mask); default_icon_hot_x = hot_x; default_icon_hot_y = hot_y; @@ -2178,7 +2553,7 @@ gtk_drag_set_default_icon (GdkColormap *colormap, /************************************************************* - * gtk_drag_source_handle_event: + * _gtk_drag_source_handle_event: * Called from widget event handling code on Drag events * for drag sources. * @@ -2189,8 +2564,8 @@ gtk_drag_set_default_icon (GdkColormap *colormap, *************************************************************/ void -gtk_drag_source_handle_event (GtkWidget *widget, - GdkEvent *event) +_gtk_drag_source_handle_event (GtkWidget *widget, + GdkEvent *event) { GtkDragSourceInfo *info; GdkDragContext *context; @@ -2232,31 +2607,25 @@ gtk_drag_source_handle_event (GtkWidget *widget, } } } - else + else if (info->have_grab) { - cursor = gtk_drag_get_cursor (event->dnd.context->action); + cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget), + 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 + cursor, info->grab_time); info->cursor = cursor; } if (info->last_event) { gtk_drag_update (info, - info->cur_x, info->cur_y, + info->cur_screen, info->cur_x, info->cur_y, info->last_event); info->last_event = NULL; } @@ -2291,12 +2660,15 @@ gtk_drag_source_check_selection (GtkDragSourceInfo *info, tmp_list = info->selections; while (tmp_list) { - if (GPOINTER_TO_UINT (tmp_list->data) == selection) + if (GDK_POINTER_TO_ATOM (tmp_list->data) == selection) return; tmp_list = tmp_list->next; } - gtk_selection_owner_set (info->ipc_widget, selection, time); + gtk_selection_owner_set_for_display (gtk_widget_get_display (info->widget), + info->ipc_widget, + selection, + time); info->selections = g_list_prepend (info->selections, GUINT_TO_POINTER (selection)); @@ -2369,11 +2741,9 @@ gtk_drag_drop_finished (GtkDragSourceInfo *info, anim->n_steps = MAX (info->cur_x - info->start_x, info->cur_y - info->start_y) / ANIM_STEP_LENGTH; anim->n_steps = CLAMP (anim->n_steps, ANIM_MIN_STEPS, ANIM_MAX_STEPS); - if (info->icon_window) - { - gtk_widget_show (info->icon_window); - gdk_window_raise (info->icon_window->window); - } + + info->cur_screen = gtk_widget_get_screen (info->widget); + gtk_drag_update_icon (info); /* Mark the context as dead, so if the destination decides * to respond really late, we still are OK. @@ -2388,12 +2758,15 @@ static void gtk_drag_source_release_selections (GtkDragSourceInfo *info, guint32 time) { + GdkDisplay *display = gtk_widget_get_display (info->widget); GList *tmp_list = info->selections; + while (tmp_list) { - GdkAtom selection = GPOINTER_TO_UINT (tmp_list->data); - if (gdk_selection_owner_get (selection) == info->ipc_widget->window) - gtk_selection_owner_set (NULL, selection, time); + GdkAtom selection = GDK_POINTER_TO_ATOM (tmp_list->data); + if (gdk_selection_owner_get_for_display (display, selection) == info->ipc_widget->window) + gtk_selection_owner_set_for_display (display, NULL, selection, time); + tmp_list = tmp_list->next; } @@ -2431,10 +2804,10 @@ gtk_drag_drop (GtkDragSourceInfo *info, selection_data.data = NULL; selection_data.length = -1; - gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get", - info->context, &selection_data, - pair->info, - time); + g_signal_emit_by_name (info->widget, "drag_data_get", + info->context, &selection_data, + pair->info, + time); /* FIXME: Should we check for length >= 0 here? */ gtk_drag_drop_finished (info, TRUE, time); @@ -2477,16 +2850,12 @@ gtk_drag_source_event_cb (GtkWidget *widget, site->state |= (GDK_BUTTON1_MASK << (event->button.button - 1)); site->x = event->button.x; site->y = event->button.y; - retval = TRUE; } break; case GDK_BUTTON_RELEASE: if ((GDK_BUTTON1_MASK << (event->button.button - 1)) & site->start_button_mask) - { - site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1)); - retval = TRUE; - } + site->state &= ~(GDK_BUTTON1_MASK << (event->button.button - 1)); break; case GDK_MOTION_NOTIFY: @@ -2518,13 +2887,32 @@ gtk_drag_source_event_cb (GtkWidget *widget, if (!info->icon_window) { - if (site->pixmap) - gtk_drag_set_icon_pixmap (context, - site->colormap, - site->pixmap, - site->mask, -2, -2); - else - gtk_drag_set_icon_default (context); + switch (site->icon_type) + { + case GTK_IMAGE_EMPTY: + gtk_drag_set_icon_default (context); + break; + case GTK_IMAGE_PIXMAP: + gtk_drag_set_icon_pixmap (context, + site->colormap, + site->icon_data.pixmap.pixmap, + site->icon_mask, + -2, -2); + break; + case GTK_IMAGE_PIXBUF: + gtk_drag_set_icon_pixbuf (context, + site->icon_data.pixbuf.pixbuf, + -2, -2); + break; + case GTK_IMAGE_STOCK: + gtk_drag_set_icon_stock (context, + site->icon_data.stock.stock_id, + -2, -2); + break; + default: + g_assert_not_reached(); + break; + } } retval = TRUE; @@ -2547,12 +2935,7 @@ gtk_drag_source_site_destroy (gpointer data) if (site->target_list) gtk_target_list_unref (site->target_list); - if (site->pixmap) - gdk_pixmap_unref (site->pixmap); - - if (site->mask) - gdk_pixmap_unref (site->mask); - + gtk_drag_source_unset_icon (site); g_free (site); } @@ -2573,9 +2956,9 @@ gtk_drag_selection_get (GtkWidget *widget, switch (sel_info) { case TARGET_DELETE: - gtk_signal_emit_by_name (GTK_OBJECT (info->widget), - "drag_data_delete", - info->context); + g_signal_emit_by_name (info->widget, + "drag_data_delete", + info->context); gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0); break; case TARGET_MOTIF_SUCCESS: @@ -2606,11 +2989,11 @@ gtk_drag_selection_get (GtkWidget *widget, selection_data->target, &target_info)) { - gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_data_get", - info->context, - selection_data, - target_info, - time); + g_signal_emit_by_name (info->widget, "drag_data_get", + info->context, + selection_data, + target_info, + time); } } break; @@ -2640,9 +3023,16 @@ 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 - anim->info->hot_x, - y - anim->info->hot_y); + { + GtkWidget *icon_window; + gint hot_x, hot_y; + + gtk_drag_get_icon (anim->info, &icon_window, &hot_x, &hot_y); + + gtk_window_move (GTK_WINDOW (icon_window), + x - hot_x, + y - hot_y); + } anim->step++; @@ -2663,7 +3053,13 @@ gtk_drag_remove_icon (GtkDragSourceInfo *info) if (info->destroy_icon) gtk_widget_destroy (info->icon_window); - gtk_widget_unref (info->icon_window); + if (info->fallback_icon) + { + gtk_widget_destroy (info->fallback_icon); + info->fallback_icon = NULL; + } + + g_object_unref (info->icon_window); info->icon_window = NULL; } } @@ -2674,22 +3070,35 @@ gtk_drag_source_info_destroy (GtkDragSourceInfo *info) gtk_drag_remove_icon (info); if (!info->proxy_dest) - gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end", - info->context); + g_signal_emit_by_name (info->widget, "drag_end", + info->context); if (info->widget) - gtk_widget_unref (info->widget); + g_object_unref (info->widget); + + + g_signal_handlers_disconnect_by_func (info->ipc_widget, + gtk_drag_button_release_cb, + info); + g_signal_handlers_disconnect_by_func (info->ipc_widget, + gtk_drag_motion_cb, + info); + g_signal_handlers_disconnect_by_func (info->ipc_widget, + gtk_drag_key_cb, + info); + g_signal_handlers_disconnect_by_func (info->ipc_widget, + gtk_drag_selection_get, + info); - gtk_signal_disconnect_by_data (GTK_OBJECT (info->ipc_widget), info); gtk_selection_remove_all (info->ipc_widget); - gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", NULL); + g_object_set_data (G_OBJECT (info->ipc_widget), "gtk-info", NULL); source_widgets = g_slist_remove (source_widgets, info->ipc_widget); gtk_drag_release_ipc_widget (info->ipc_widget); gtk_target_list_unref (info->target_list); gtk_drag_clear_source_info (info->context); - gdk_drag_context_unref (info->context); + g_object_unref (info->context); if (info->drop_timeout) gtk_timeout_remove (info->drop_timeout); @@ -2710,13 +3119,13 @@ gtk_drag_source_info_destroy (GtkDragSourceInfo *info) static void gtk_drag_update (GtkDragSourceInfo *info, + GdkScreen *screen, gint x_root, gint y_root, GdkEvent *event) { GdkDragAction action; GdkDragAction possible_actions; - GdkWindow *window = NULL; GdkWindow *dest_window; GdkDragProtocol protocol; GdkAtom selection; @@ -2726,22 +3135,16 @@ gtk_drag_update (GtkDragSourceInfo *info, info->button, info->possible_actions, &action, &possible_actions); + info->cur_screen = screen; 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->hot_x, - info->cur_y - info->hot_y); - window = info->icon_window->window; - } + gtk_drag_update_icon (info); + gdk_drag_find_window_for_screen (info->context, + info->icon_window ? info->icon_window->window : NULL, + screen, x_root, y_root, + &dest_window, &protocol); - gdk_drag_find_window (info->context, - window, x_root, y_root, - &dest_window, &protocol); - if (gdk_drag_motion (info->context, dest_window, protocol, x_root, y_root, action, possible_actions, @@ -2764,7 +3167,7 @@ gtk_drag_update (GtkDragSourceInfo *info, } if (dest_window) - gdk_window_unref (dest_window); + g_object_unref (dest_window); selection = gdk_drag_get_selection (info->context); if (selection) @@ -2776,28 +3179,33 @@ gtk_drag_update (GtkDragSourceInfo *info, * Called when the user finishes to drag, either by * releasing the mouse, or by pressing Esc. * arguments: - * widget: GtkInvisible widget for this drag - * info: + * info: Source info for the drag + * time: Timestamp for ending the drag * results: *************************************************************/ static void gtk_drag_end (GtkDragSourceInfo *info, guint32 time) { - GdkEvent send_event; + GdkEvent *send_event; GtkWidget *source_widget = info->widget; + GdkDisplay *display = gtk_widget_get_display (source_widget); - gdk_pointer_ungrab (time); - gdk_keyboard_ungrab (time); - + info->have_grab = FALSE; + + gdk_display_pointer_ungrab (display, time); + gdk_display_keyboard_ungrab (display, time); gtk_grab_remove (info->ipc_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 (info->ipc_widget), - GTK_SIGNAL_FUNC (gtk_drag_motion_cb), - info); + g_signal_handlers_disconnect_by_func (info->ipc_widget, + gtk_drag_button_release_cb, + info); + g_signal_handlers_disconnect_by_func (info->ipc_widget, + gtk_drag_motion_cb, + info); + g_signal_handlers_disconnect_by_func (info->ipc_widget, + gtk_drag_key_cb, + info); /* Send on a release pair to the the original * widget to convince it to release its grab. We need to @@ -2806,20 +3214,39 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time) * expect propagation. */ - send_event.button.type = GDK_BUTTON_RELEASE; - send_event.button.window = GDK_ROOT_PARENT (); - send_event.button.send_event = TRUE; - send_event.button.time = time; - send_event.button.x = 0; - send_event.button.y = 0; - 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; + send_event = gdk_event_new (GDK_BUTTON_RELEASE); + send_event->button.window = g_object_ref (gtk_widget_get_root_window (source_widget)); + send_event->button.send_event = TRUE; + send_event->button.time = time; + send_event->button.x = 0; + send_event->button.y = 0; + send_event->button.axes = NULL; + send_event->button.state = 0; + send_event->button.button = info->button; + send_event->button.device = gdk_display_get_core_pointer (display); + send_event->button.x_root = 0; + send_event->button.y_root = 0; + + gtk_propagate_event (source_widget, send_event); + gdk_event_free (send_event); +} - gtk_propagate_event (source_widget, &send_event); +/************************************************************* + * gtk_drag_cancel: + * Called on cancellation of a drag, either by the user + * or programmatically. + * arguments: + * info: Source info for the drag + * time: Timestamp for ending the drag + * results: + *************************************************************/ + +static void +gtk_drag_cancel (GtkDragSourceInfo *info, guint32 time) +{ + gtk_drag_end (info, time); + gdk_drag_abort (info->context, time); + gtk_drag_drop_finished (info, FALSE, time); } /************************************************************* @@ -2836,16 +3263,21 @@ gtk_drag_motion_cb (GtkWidget *widget, gpointer data) { GtkDragSourceInfo *info = (GtkDragSourceInfo *)data; + GdkScreen *screen; gint x_root, y_root; if (event->is_hint) { - gdk_window_get_pointer (GDK_ROOT_PARENT(), &x_root, &y_root, NULL); + GdkDisplay *display = gtk_widget_get_display (widget); + + gdk_display_get_pointer (display, &screen, &x_root, &y_root, NULL); event->x_root = x_root; event->y_root = y_root; } + else + screen = gdk_event_get_screen ((GdkEvent *)event); - gtk_drag_update (info, event->x_root, event->y_root, (GdkEvent *)event); + gtk_drag_update (info, screen, event->x_root, event->y_root, (GdkEvent *)event); return TRUE; } @@ -2865,14 +3297,13 @@ gtk_drag_key_cb (GtkWidget *widget, { GtkDragSourceInfo *info = (GtkDragSourceInfo *)data; GdkModifierType state; + GdkWindow *root_window; 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); + gtk_drag_cancel (info, event->time); return TRUE; } @@ -2884,10 +3315,11 @@ gtk_drag_key_cb (GtkWidget *widget, * to query it here. We could use XGetModifierMapping, but * that would be overkill. */ - gdk_window_get_pointer (GDK_ROOT_PARENT(), NULL, NULL, &state); + root_window = gtk_widget_get_root_window (widget); + gdk_window_get_pointer (root_window, NULL, NULL, &state); event->state = state; - gtk_drag_update (info, info->cur_x, info->cur_y, (GdkEvent *)event); + gtk_drag_update (info, info->cur_screen, info->cur_x, info->cur_y, (GdkEvent *)event); return TRUE; } @@ -2910,16 +3342,14 @@ gtk_drag_button_release_cb (GtkWidget *widget, 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_end (info, event->time); gtk_drag_drop (info, event->time); } else { - gdk_drag_abort (info->context, event->time); - gtk_drag_drop_finished (info, FALSE, event->time); + gtk_drag_cancel (info, event->time); } return TRUE; @@ -2952,11 +3382,11 @@ gtk_drag_abort_timeout (gpointer data) * @current_x: current X coordinate * @current_y: current Y coordinate * - * Checks to see if a mouse drag starting at (start_x, start_y) and ending - * at (current_x, current_y) has passed the GTK drag threshhold, and thus + * Checks to see if a mouse drag starting at (@start_x, @start_y) and ending + * at (@current_x, @current_y) has passed the GTK+ drag threshhold, and thus * should trigger the beginning of a drag-and-drop operation. * - * Return Value: If the drag threshold has been passed. + * Return Value: %TRUE if the drag threshold has been passed. **/ gboolean gtk_drag_check_threshold (GtkWidget *widget, @@ -2965,8 +3395,14 @@ gtk_drag_check_threshold (GtkWidget *widget, gint current_x, gint current_y) { -#define DRAG_THRESHOLD 8 + gint drag_threshold; - return (ABS (current_x - start_x) > DRAG_THRESHOLD || - ABS (current_y - start_y) > DRAG_THRESHOLD); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + g_object_get (gtk_widget_get_settings (widget), + "gtk-dnd-drag-threshold", &drag_threshold, + NULL); + + return (ABS (current_x - start_x) > drag_threshold || + ABS (current_y - start_y) > drag_threshold); }