diff options
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | gtk/gtkdnd.c | 38 | ||||
-rw-r--r-- | gtk/gtkenums.h | 9 | ||||
-rw-r--r-- | gtk/gtkmarshalers.list | 1 | ||||
-rw-r--r-- | gtk/gtknotebook.c | 88 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 27 |
6 files changed, 135 insertions, 50 deletions
@@ -1,3 +1,25 @@ +2006-12-28 Carlos Garnacho <carlosg@gnome.org> + + Make GtkNotebook able to drop detached tabs anywhere. Bug #360225. + + * gtk/gtkwidget.c (gtk_widget_class_init): add "drag-failed" signal. + * gtk/gtkmarshalers.list: add new marshaler definition. + * gtk/gtkenums.h: add GtkDragResult enum. + + * gtk/gtkdnd.c (gtk_drag_drop_finished): emit "drag-failed" if DND + operation wasn't successful. + (_gtk_drag_source_handle_event) (gtk_drag_drop) + (gtk_drag_selection_get) (gtk_drag_cancel) (gtk_drag_key_cb) + (gtk_drag_grab_broken_event_cb) (gtk_drag_grab_notify_cb) + (gtk_drag_button_release_cb) (gtk_drag_abort_timeout): tell + gtk_drag_drop_finished() the operation result. + + * gtk/gtknotebook.c (gtk_notebook_drag_failed): new function. + (gtk_notebook_drag_data_get): do not call window creation hook here. + (gtk_notebook_init): do not set "application/x-rootwindow-drop" + target, instead connect to "drag-failed". + (gtk_notebook_draw_focus): fix potential crasher if cur_page is NULL. + 2006-12-28 Mikael Hallendal <micke@imendio.com> * gdk/quartz/gdkevents-quartz.c: Factored out the event loop diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c index 939f5f2cde..a30da5e5e1 100644 --- a/gtk/gtkdnd.c +++ b/gtk/gtkdnd.c @@ -252,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, @@ -2974,7 +2975,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) { @@ -3333,7 +3334,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 (); @@ -3413,9 +3414,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) @@ -3427,6 +3431,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); @@ -3518,12 +3526,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 { @@ -3635,11 +3643,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: @@ -3975,11 +3983,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); } /************************************************************* @@ -4044,7 +4052,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: @@ -4118,7 +4126,7 @@ 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; } @@ -4134,7 +4142,7 @@ gtk_drag_grab_notify_cb (GtkWidget *widget, /* 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_get_current_event_time ()); + 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); } } @@ -4165,7 +4173,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; @@ -4181,7 +4189,7 @@ gtk_drag_abort_timeout (gpointer data) time = info->proxy_dest->proxy_drop_time; info->drop_timeout = 0; - gtk_drag_drop_finished (info, FALSE, time); + gtk_drag_drop_finished (info, GTK_DRAG_RESULT_TIMEOUT_EXPIRED, time); return FALSE; } diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h index 85bfd38f82..a3a5e068ce 100644 --- a/gtk/gtkenums.h +++ b/gtk/gtkenums.h @@ -514,6 +514,15 @@ typedef enum { GTK_TREE_VIEW_GRID_LINES_BOTH } GtkTreeViewGridLines; +typedef enum { + GTK_DRAG_RESULT_SUCCESS, + GTK_DRAG_RESULT_NO_TARGET, + GTK_DRAG_RESULT_USER_CANCELLED, + GTK_DRAG_RESULT_TIMEOUT_EXPIRED, + GTK_DRAG_RESULT_GRAB_BROKEN, + GTK_DRAG_RESULT_ERROR +} GtkDragResult; + G_END_DECLS #endif /* __GTK_ENUMS_H__ */ diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list index c11f42b741..c1510ec2fe 100644 --- a/gtk/gtkmarshalers.list +++ b/gtk/gtkmarshalers.list @@ -34,6 +34,7 @@ BOOLEAN:OBJECT,BOXED BOOLEAN:OBJECT,BOXED,BOXED BOOLEAN:OBJECT,OBJECT,OBJECT BOOLEAN:OBJECT,STRING,STRING +BOOLEAN:OBJECT,ENUM BOOLEAN:INT BOOLEAN:INT,INT BOOLEAN:INT,INT,INT diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index 85d9953fd1..23abb59217 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -184,13 +184,8 @@ struct _GtkNotebookPrivate guint has_scrolled : 1; }; -static const GtkTargetEntry notebook_source_targets [] = { +static const GtkTargetEntry notebook_targets [] = { { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }, - { "application/x-rootwindow-drop", 0, 1 } -}; - -static const GtkTargetEntry notebook_dest_targets[] = { - { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 } }; #ifdef G_DISABLE_CHECKS @@ -267,6 +262,10 @@ static void gtk_notebook_drag_begin (GtkWidget *widget, GdkDragContext *context); static void gtk_notebook_drag_end (GtkWidget *widget, GdkDragContext *context); +static gboolean gtk_notebook_drag_failed (GtkWidget *widget, + GdkDragContext *context, + GtkDragResult result, + gpointer data); static gboolean gtk_notebook_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, @@ -406,6 +405,11 @@ static gboolean focus_child_in (GtkNotebook *notebook, GtkDirectionType direction); static void stop_scrolling (GtkNotebook *notebook); +static void do_detach_tab (GtkNotebook *from, + GtkNotebook *to, + GtkWidget *child, + gint x, + gint y); static GtkNotebookWindowCreationFunc window_creation_hook = NULL; @@ -1000,8 +1004,8 @@ gtk_notebook_init (GtkNotebook *notebook) priv->pressed_button = -1; priv->dnd_timer = 0; priv->switch_tab_timer = 0; - priv->source_targets = gtk_target_list_new (notebook_source_targets, - G_N_ELEMENTS (notebook_source_targets)); + priv->source_targets = gtk_target_list_new (notebook_targets, + G_N_ELEMENTS (notebook_targets)); priv->operation = DRAG_OPERATION_NONE; priv->detached_tab = NULL; priv->during_detach = FALSE; @@ -1009,9 +1013,12 @@ gtk_notebook_init (GtkNotebook *notebook) gtk_drag_dest_set (GTK_WIDGET (notebook), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, - notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets), + notebook_targets, G_N_ELEMENTS (notebook_targets), GDK_ACTION_MOVE); + g_signal_connect (G_OBJECT (notebook), "drag-failed", + G_CALLBACK (gtk_notebook_drag_failed), NULL); + gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE); } @@ -1470,6 +1477,7 @@ gtk_notebook_get_property (GObject *object, * gtk_notebook_style_set * gtk_notebook_drag_begin * gtk_notebook_drag_end + * gtk_notebook_drag_failed * gtk_notebook_drag_motion * gtk_notebook_drag_drop * gtk_notebook_drag_data_get @@ -2975,8 +2983,8 @@ gtk_notebook_draw_focus (GtkWidget *widget, GtkNotebook *notebook = GTK_NOTEBOOK (widget); if (GTK_WIDGET_HAS_FOCUS (widget) && GTK_WIDGET_DRAWABLE (widget) && - notebook->cur_page->tab_label->window == event->window && - notebook->show_tabs && notebook->cur_page) + notebook->show_tabs && notebook->cur_page && + notebook->cur_page->tab_label->window == event->window) { GtkNotebookPage *page; GdkRectangle area; @@ -3107,6 +3115,38 @@ gtk_notebook_drag_end (GtkWidget *widget, } static gboolean +gtk_notebook_drag_failed (GtkWidget *widget, + GdkDragContext *context, + GtkDragResult result, + gpointer data) +{ + if (result == GTK_DRAG_RESULT_NO_TARGET) + { + GtkNotebookPrivate *priv; + GtkNotebook *notebook, *dest_notebook; + GdkDisplay *display; + gint x, y; + + notebook = GTK_NOTEBOOK (widget); + priv = GTK_NOTEBOOK_GET_PRIVATE (notebook); + + display = gtk_widget_get_display (widget); + gdk_display_get_pointer (display, NULL, &x, &y, NULL); + + dest_notebook = (* window_creation_hook) (notebook, + priv->detached_tab->child, + x, y, + window_creation_hook_data); + if (dest_notebook) + do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0); + + return TRUE; + } + + return FALSE; +} + +static gboolean gtk_notebook_switch_tab_timeout (gpointer data) { GtkNotebook *notebook; @@ -3332,40 +3372,18 @@ gtk_notebook_drag_data_get (GtkWidget *widget, guint info, guint time) { - GtkNotebook *dest_notebook, *notebook; GtkNotebookPrivate *priv; - if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") && - (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") || - !window_creation_hook)) - return; - - notebook = GTK_NOTEBOOK (widget); - priv = GTK_NOTEBOOK_GET_PRIVATE (notebook); - if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB")) { + priv = GTK_NOTEBOOK_GET_PRIVATE (widget); + gtk_selection_data_set (data, data->target, 8, (void*) &priv->detached_tab->child, sizeof (gpointer)); } - else - { - GdkDisplay *display; - gint x, y; - - display = gtk_widget_get_display (widget); - gdk_display_get_pointer (display, NULL, &x, &y, NULL); - - dest_notebook = (* window_creation_hook) (notebook, - priv->detached_tab->child, - x, y, - window_creation_hook_data); - if (dest_notebook) - do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0); - } } static void diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index f021bf028d..7a727433d8 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -122,6 +122,7 @@ enum { GRAB_BROKEN, COMPOSITED_CHANGED, KEYNAV_FAILED, + DRAG_FAILED, LAST_SIGNAL }; @@ -1125,6 +1126,32 @@ gtk_widget_class_init (GtkWidgetClass *klass) GDK_TYPE_DRAG_CONTEXT); /** + * GtkWidget::drag-failed: + * @widget: the object which received the signal. + * @drag_context: the drag context. + * @result: the result of the drag operation. + * + * The ::drag-failed signal is emitted on the drag source when a drag has + * failed. The signal handler may hook custom code to handle a failed DND + * operation based on the type of error, it returns %TRUE is the failure has + * been already handled (not showing the default "drag operation failed" + * animation), otherwise it returns %FALSE. + * + * Return value: %TRUE if the failed drag operation has been already handled. + * + * Since: 2.12 + */ + widget_signals[DRAG_FAILED] = + g_signal_new (I_("drag_failed"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, _gtk_boolean_handled_accumulator, NULL, + _gtk_marshal_BOOLEAN__OBJECT_ENUM, + G_TYPE_BOOLEAN, 2, + GDK_TYPE_DRAG_CONTEXT, + GTK_TYPE_DRAG_RESULT); + + /** * GtkWidget::drag-motion: * @widget: the object which received the signal. * @drag_context: the drag context |