X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkdnd.c;h=31d1d9233edce8cbf9b38571270abdbfb9d26b91;hb=13e87f72c9d1deb7f208bd3932187a57ef7eb84a;hp=7b008cd999599d1f549193d22dd969f4fdc327f1;hpb=f8794ccccadc91bd37a4fe19577fc789cf0d0107;p=~andy%2Fgtk diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c index 7b008cd99..31d1d9233 100644 --- a/gtk/gtkdnd.c +++ b/gtk/gtkdnd.c @@ -43,6 +43,7 @@ #include "gtkstock.h" #include "gtkwindow.h" #include "gtkintl.h" +#include "gtkdndcursors.h" #include "gtkalias.h" static GSList *source_widgets = NULL; @@ -202,7 +203,8 @@ static GdkCursor * gtk_drag_get_cursor (GdkDisplay *display, GdkDragAction action, GtkDragSourceInfo *info); static void gtk_drag_update_cursor (GtkDragSourceInfo *info); -static GtkWidget *gtk_drag_get_ipc_widget (GdkScreen *screen); +static GtkWidget *gtk_drag_get_ipc_widget (GtkWidget *widget); +static GtkWidget *gtk_drag_get_ipc_widget_for_screen (GdkScreen *screen); static void gtk_drag_release_ipc_widget (GtkWidget *widget); static gboolean gtk_drag_highlight_expose (GtkWidget *widget, @@ -250,9 +252,10 @@ static void gtk_drag_source_release_selections (GtkDragSourceInfo *info, static void gtk_drag_drop (GtkDragSourceInfo *info, guint32 time); static void gtk_drag_drop_finished (GtkDragSourceInfo *info, - gboolean success, + GtkDragResult result, guint time); static void gtk_drag_cancel (GtkDragSourceInfo *info, + GtkDragResult result, guint32 time); static gboolean gtk_drag_source_event_cb (GtkWidget *widget, @@ -283,6 +286,9 @@ static gboolean gtk_drag_key_cb (GtkWidget *widget, static gboolean gtk_drag_grab_broken_event_cb (GtkWidget *widget, GdkEventGrabBroken *event, gpointer data); +static void gtk_drag_grab_notify_cb (GtkWidget *widget, + gboolean was_grabbed, + gpointer data); static gboolean gtk_drag_button_release_cb (GtkWidget *widget, GdkEventButton *event, gpointer data); @@ -299,8 +305,6 @@ static void set_icon_stock_pixbuf (GdkDragContext *context, * Cursor and Icon data * ************************/ -#include "gtkdndcursors.h" - static struct { GdkDragAction action; const gchar *name; @@ -339,17 +343,8 @@ get_can_change_screen (GtkWidget *widget) } -/************************************************************* - * gtk_drag_get_ipc_widget: - * Return a invisible, off-screen, override-redirect - * widget for IPC. - * arguments: - * - * results: - *************************************************************/ - static GtkWidget * -gtk_drag_get_ipc_widget (GdkScreen *screen) +gtk_drag_get_ipc_widget_for_screen (GdkScreen *screen) { GtkWidget *result; GSList *drag_widgets = g_object_get_data (G_OBJECT (screen), @@ -367,13 +362,37 @@ gtk_drag_get_ipc_widget (GdkScreen *screen) } else { - result = gtk_invisible_new_for_screen (screen); + result = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_screen (GTK_WINDOW (result), screen); + gtk_window_resize (GTK_WINDOW (result), 1, 1); + gtk_window_move (GTK_WINDOW (result), -100, -100); gtk_widget_show (result); + } + + return result; +} + +static GtkWidget * +gtk_drag_get_ipc_widget (GtkWidget *widget) +{ + GtkWidget *result; + GtkWidget *toplevel; + + result = gtk_drag_get_ipc_widget_for_screen (gtk_widget_get_screen (widget)); + + toplevel = gtk_widget_get_toplevel (widget); + + if (GTK_IS_WINDOW (toplevel)) + { + if (GTK_WINDOW (toplevel)->group) + gtk_window_group_add_window (GTK_WINDOW (toplevel)->group, + GTK_WINDOW (result)); } return result; } + /*************************************************************** * gtk_drag_release_ipc_widget: * Releases widget retrieved with gtk_drag_get_ipc_widget () @@ -385,9 +404,12 @@ gtk_drag_get_ipc_widget (GdkScreen *screen) static void gtk_drag_release_ipc_widget (GtkWidget *widget) { + GtkWindow *window = GTK_WINDOW (widget); GdkScreen *screen = gtk_widget_get_screen (widget); GSList *drag_widgets = g_object_get_data (G_OBJECT (screen), "gtk-dnd-ipc-widgets"); + if (window->group) + gtk_window_group_remove_window (window->group, window); drag_widgets = g_slist_prepend (drag_widgets, widget); g_object_set_data (G_OBJECT (screen), I_("gtk-dnd-ipc-widgets"), @@ -814,7 +836,7 @@ gtk_drag_get_data (GtkWidget *widget, g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); g_return_if_fail (!context->is_source); - selection_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget)); + selection_widget = gtk_drag_get_ipc_widget (widget); g_object_ref (context); g_object_ref (widget); @@ -904,7 +926,7 @@ gtk_drag_finish (GdkDragContext *context, if (target != GDK_NONE) { - GtkWidget *selection_widget = gtk_drag_get_ipc_widget (gdk_drawable_get_screen (context->source_window)); + GtkWidget *selection_widget = gtk_drag_get_ipc_widget_for_screen (gdk_drawable_get_screen (context->source_window)); g_object_ref (context); @@ -960,7 +982,7 @@ gtk_drag_highlight_expose (GtkWidget *widget, gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, - NULL, widget, "dnd", + &event->area, widget, "dnd", x, y, width, height); cr = gdk_cairo_create (widget->window); @@ -1498,7 +1520,9 @@ gtk_drag_dest_find_target (GtkWidget *widget, if (tmp_source->data == GUINT_TO_POINTER (pair->target)) { if ((!(pair->flags & GTK_TARGET_SAME_APP) || source_widget) && - (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget))) + (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget)) && + (!(pair->flags & GTK_TARGET_OTHER_APP) || !source_widget) && + (!(pair->flags & GTK_TARGET_OTHER_WIDGET) || (source_widget != widget))) return pair->target; else break; @@ -1770,7 +1794,7 @@ gtk_drag_proxy_begin (GtkWidget *widget, dest_info->proxy_source = NULL; } - ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget)); + ipc_widget = gtk_drag_get_ipc_widget (widget); context = gdk_drag_begin (ipc_widget->window, dest_info->context->targets); @@ -2164,7 +2188,7 @@ gtk_drag_begin_internal (GtkWidget *widget, GtkWidget *ipc_widget; GdkCursor *cursor; - ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget)); + ipc_widget = gtk_drag_get_ipc_widget (widget); gtk_drag_get_event_actions (event, button, actions, &suggested_action, &possible_actions); @@ -2313,6 +2337,8 @@ gtk_drag_begin_internal (GtkWidget *widget, g_signal_connect (info->ipc_widget, "grab_broken_event", G_CALLBACK (gtk_drag_grab_broken_event_cb), info); + g_signal_connect (info->ipc_widget, "grab_notify", + G_CALLBACK (gtk_drag_grab_notify_cb), 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", @@ -2951,7 +2977,7 @@ set_icon_stock_pixbuf (GdkDragContext *context, 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); + gtk_widget_set_app_paintable (window, TRUE); if (stock_id) { @@ -3091,7 +3117,7 @@ gtk_drag_set_icon_pixmap (GdkDragContext *context, gtk_widget_push_colormap (colormap); window = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_DND); + gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DND); 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); @@ -3310,7 +3336,7 @@ _gtk_drag_source_handle_event (GtkWidget *widget, break; case GDK_DROP_FINISHED: - gtk_drag_drop_finished (info, TRUE, event->dnd.time); + gtk_drag_drop_finished (info, GTK_DRAG_RESULT_SUCCESS, event->dnd.time); break; default: g_assert_not_reached (); @@ -3390,9 +3416,12 @@ gtk_drag_source_check_selection (GtkDragSourceInfo *info, static void gtk_drag_drop_finished (GtkDragSourceInfo *info, - gboolean success, + GtkDragResult result, guint time) { + gboolean success; + + success = (result == GTK_DRAG_RESULT_SUCCESS); gtk_drag_source_release_selections (info, time); if (info->proxy_dest) @@ -3404,6 +3433,10 @@ gtk_drag_drop_finished (GtkDragSourceInfo *info, } else { + if (!success) + g_signal_emit_by_name (info->widget, "drag_failed", + info->context, result, &success); + if (success) { gtk_drag_source_info_destroy (info); @@ -3430,7 +3463,7 @@ gtk_drag_drop_finished (GtkDragSourceInfo *info, * to respond really late, we still are OK. */ gtk_drag_clear_source_info (info->context); - g_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim); + gdk_threads_add_timeout (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim); } } } @@ -3495,12 +3528,12 @@ gtk_drag_drop (GtkDragSourceInfo *info, time); /* FIXME: Should we check for length >= 0 here? */ - gtk_drag_drop_finished (info, TRUE, time); + gtk_drag_drop_finished (info, GTK_DRAG_RESULT_SUCCESS, time); return; } tmp_list = tmp_list->next; } - gtk_drag_drop_finished (info, FALSE, time); + gtk_drag_drop_finished (info, GTK_DRAG_RESULT_NO_TARGET, time); } else { @@ -3508,7 +3541,7 @@ gtk_drag_drop (GtkDragSourceInfo *info, gtk_widget_hide (info->icon_window); gdk_drag_drop (info->context, time); - info->drop_timeout = g_timeout_add (DROP_ABORT_TIME, + info->drop_timeout = gdk_threads_add_timeout (DROP_ABORT_TIME, gtk_drag_abort_timeout, info); } @@ -3612,11 +3645,11 @@ gtk_drag_selection_get (GtkWidget *widget, gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0); break; case TARGET_MOTIF_SUCCESS: - gtk_drag_drop_finished (info, TRUE, time); + gtk_drag_drop_finished (info, GTK_DRAG_RESULT_SUCCESS, time); gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0); break; case TARGET_MOTIF_FAILURE: - gtk_drag_drop_finished (info, FALSE, time); + gtk_drag_drop_finished (info, GTK_DRAG_RESULT_NO_TARGET, time); gtk_selection_data_set (selection_data, null_atom, 8, NULL, 0); break; default: @@ -3657,8 +3690,6 @@ gtk_drag_anim_timeout (gpointer data) gint x, y; gboolean retval; - GDK_THREADS_ENTER (); - if (anim->step == anim->n_steps) { gtk_drag_source_info_destroy (anim->info); @@ -3688,8 +3719,6 @@ gtk_drag_anim_timeout (gpointer data) retval = TRUE; } - GDK_THREADS_LEAVE (); - return retval; } @@ -3730,19 +3759,17 @@ gtk_drag_source_info_destroy (GtkDragSourceInfo *info) gtk_drag_remove_icon (info); if (info->icon_pixbuf) - g_object_unref (info->icon_pixbuf); - - if (!info->proxy_dest) - g_signal_emit_by_name (info->widget, "drag_end", - info->context); - - if (info->widget) - g_object_unref (info->widget); - + { + g_object_unref (info->icon_pixbuf); + info->icon_pixbuf = NULL; + } g_signal_handlers_disconnect_by_func (info->ipc_widget, gtk_drag_grab_broken_event_cb, info); + g_signal_handlers_disconnect_by_func (info->ipc_widget, + gtk_drag_grab_notify_cb, + info); g_signal_handlers_disconnect_by_func (info->ipc_widget, gtk_drag_button_release_cb, info); @@ -3756,6 +3783,13 @@ gtk_drag_source_info_destroy (GtkDragSourceInfo *info) gtk_drag_selection_get, info); + if (!info->proxy_dest) + g_signal_emit_by_name (info->widget, "drag_end", + info->context); + + if (info->widget) + g_object_unref (info->widget); + gtk_selection_remove_all (info->ipc_widget); g_object_set_data (G_OBJECT (info->ipc_widget), I_("gtk-info"), NULL); source_widgets = g_slist_remove (source_widgets, info->ipc_widget); @@ -3784,8 +3818,6 @@ gtk_drag_update_idle (gpointer data) GdkDragAction possible_actions; guint32 time; - GDK_THREADS_ENTER (); - info->update_idle = 0; if (info->last_event) @@ -3819,8 +3851,6 @@ gtk_drag_update_idle (gpointer data) } - GDK_THREADS_LEAVE (); - return FALSE; } @@ -3831,7 +3861,7 @@ gtk_drag_add_update_idle (GtkDragSourceInfo *info) * from the last move can catch up before we move again. */ if (!info->update_idle) - info->update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW + 5, + info->update_idle = gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW + 5, gtk_drag_update_idle, info, NULL); @@ -3900,13 +3930,12 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time) info->have_grab = FALSE; - gdk_display_pointer_ungrab (display, time); - gdk_display_keyboard_ungrab (display, time); - gtk_grab_remove (info->ipc_widget); - g_signal_handlers_disconnect_by_func (info->ipc_widget, gtk_drag_grab_broken_event_cb, info); + g_signal_handlers_disconnect_by_func (info->ipc_widget, + gtk_drag_grab_notify_cb, + info); g_signal_handlers_disconnect_by_func (info->ipc_widget, gtk_drag_button_release_cb, info); @@ -3917,6 +3946,10 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time) gtk_drag_key_cb, info); + gdk_display_pointer_ungrab (display, time); + gdk_display_keyboard_ungrab (display, time); + gtk_grab_remove (info->ipc_widget); + /* Send on a release pair to the original * widget to convince it to release its grab. We need to * call gtk_propagate_event() here, instead of @@ -3952,11 +3985,11 @@ gtk_drag_end (GtkDragSourceInfo *info, guint32 time) *************************************************************/ static void -gtk_drag_cancel (GtkDragSourceInfo *info, guint32 time) +gtk_drag_cancel (GtkDragSourceInfo *info, GtkDragResult result, guint32 time) { gtk_drag_end (info, time); gdk_drag_abort (info->context, time); - gtk_drag_drop_finished (info, FALSE, time); + gtk_drag_drop_finished (info, result, time); } /************************************************************* @@ -4021,7 +4054,7 @@ gtk_drag_key_cb (GtkWidget *widget, switch (event->keyval) { case GDK_Escape: - gtk_drag_cancel (info, event->time); + gtk_drag_cancel (info, GTK_DRAG_RESULT_USER_CANCELLED, event->time); return TRUE; case GDK_space: @@ -4095,10 +4128,28 @@ gtk_drag_grab_broken_event_cb (GtkWidget *widget, || event->grab_window == info->ipc_widget->window) return FALSE; - gtk_drag_cancel (info, gtk_get_current_event_time ()); + gtk_drag_cancel (info, GTK_DRAG_RESULT_GRAB_BROKEN, gtk_get_current_event_time ()); return TRUE; } +static void +gtk_drag_grab_notify_cb (GtkWidget *widget, + gboolean was_grabbed, + gpointer data) +{ + GtkDragSourceInfo *info = (GtkDragSourceInfo *)data; + + if (!was_grabbed) + { + /* We have to block callbacks to avoid recursion here, because + gtk_drag_cancel calls gtk_grab_remove (via gtk_drag_end) */ + g_signal_handlers_block_by_func (widget, gtk_drag_grab_notify_cb, data); + gtk_drag_cancel (info, GTK_DRAG_RESULT_GRAB_BROKEN, gtk_get_current_event_time ()); + g_signal_handlers_unblock_by_func (widget, gtk_drag_grab_notify_cb, data); + } +} + + /************************************************************* * gtk_drag_button_release_cb: * "button_release_event" callback during drag. @@ -4124,7 +4175,7 @@ gtk_drag_button_release_cb (GtkWidget *widget, } else { - gtk_drag_cancel (info, event->time); + gtk_drag_cancel (info, GTK_DRAG_RESULT_NO_TARGET, event->time); } return TRUE; @@ -4136,15 +4187,11 @@ 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 (); + gtk_drag_drop_finished (info, GTK_DRAG_RESULT_TIMEOUT_EXPIRED, time); return FALSE; }