Index: app/widgets/gimpdockbook.c =================================================================== --- app/widgets/gimpdockbook.c (revision 23554) +++ app/widgets/gimpdockbook.c (working copy) @@ -60,6 +60,7 @@ enum }; +static void gimp_dockbook_dispose (GObject *object); static void gimp_dockbook_finalize (GObject *object); static void gimp_dockbook_style_set (GtkWidget *widget, @@ -83,11 +84,23 @@ static void gimp_dockbook_tab_drag_ static void gimp_dockbook_tab_drag_end (GtkWidget *widget, GdkDragContext *context, GimpDockable *dockable); + +static void gimp_dockbook_tab_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time, + GimpDockable *dockable); +static gboolean gimp_dockbook_tab_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time, + GimpDockable *dockable); static gboolean gimp_dockbook_tab_drag_drop (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time); + static gboolean gimp_dockbook_tab_drag_expose (GtkWidget *widget, GdkEventExpose *event); @@ -140,6 +153,7 @@ gimp_dockbook_class_init (GimpDockbookCl G_TYPE_NONE, 1, GIMP_TYPE_DOCKABLE); + object_class->dispose = gimp_dockbook_dispose; object_class->finalize = gimp_dockbook_finalize; widget_class->style_set = gimp_dockbook_style_set; @@ -180,6 +194,21 @@ gimp_dockbook_init (GimpDockbook *dockbo } static void +gimp_dockbook_dispose (GObject *object) +{ + GimpDockbook *dockbook = GIMP_DOCKBOOK (object); + + if (dockbook->tab_hover_timeout) + { + g_source_remove (dockbook->tab_hover_timeout); + dockbook->tab_hover_timeout = 0; + dockbook->tab_hover_dockable = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void gimp_dockbook_finalize (GObject *object) { GimpDockbook *dockbook = GIMP_DOCKBOOK (object); @@ -359,6 +388,13 @@ gimp_dockbook_remove (GimpDockbook *dock g_object_ref (dockable); + if (dockbook->tab_hover_dockable == dockable) + { + g_source_remove (dockbook->tab_hover_timeout); + dockbook->tab_hover_timeout = 0; + dockbook->tab_hover_dockable = NULL; + } + dockable->dockbook = NULL; gimp_dockable_set_context (dockable, NULL); @@ -479,9 +515,15 @@ gimp_dockbook_get_tab_widget (GimpDockbo dockable); gtk_drag_dest_set (GTK_WIDGET (tab_widget), - GTK_DEST_DEFAULT_ALL, + GTK_DEST_DEFAULT_DROP, dialog_target_table, G_N_ELEMENTS (dialog_target_table), GDK_ACTION_MOVE); + g_signal_connect (tab_widget, "drag-leave", + G_CALLBACK (gimp_dockbook_tab_drag_leave), + dockable); + g_signal_connect (tab_widget, "drag-motion", + G_CALLBACK (gimp_dockbook_tab_drag_motion), + dockable); g_signal_connect (tab_widget, "drag-drop", G_CALLBACK (gimp_dockbook_tab_drag_drop), dockbook); @@ -532,6 +574,9 @@ gimp_dockbook_drop_dockable (GimpDockboo return FALSE; } + +/* tab DND source side */ + static void gimp_dockbook_tab_drag_begin (GtkWidget *widget, GdkDragContext *context, @@ -604,6 +649,100 @@ gimp_dockbook_tab_drag_end (GtkWidget gtk_widget_set_sensitive (GTK_WIDGET (dockable), TRUE); } + +/* tab DND target side */ + +static void +gimp_dockbook_tab_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time, + GimpDockable *dockable) +{ + GimpDockbook *dockbook = dockable->dockbook; + + if (dockbook->tab_hover_timeout) + { + g_source_remove (dockbook->tab_hover_timeout); + dockbook->tab_hover_timeout = 0; + dockbook->tab_hover_dockable = NULL; + } + + gtk_drag_unhighlight (widget); +} + +static gboolean +gimp_dockbook_tab_hover_timeout (GimpDockbook *dockbook) +{ + gint page_num; + + page_num = gtk_notebook_page_num (GTK_NOTEBOOK (dockbook), + GTK_WIDGET (dockbook->tab_hover_dockable)); + gtk_notebook_set_current_page (GTK_NOTEBOOK (dockbook), page_num); + + dockbook->tab_hover_timeout = 0; + dockbook->tab_hover_dockable = NULL; + + return FALSE; +} + +static gboolean +gimp_dockbook_tab_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time, + GimpDockable *dockable) +{ + GimpDockbook *dockbook = dockable->dockbook; + GtkTargetList *target_list; + GdkAtom target_atom; + guint unused; + + if (! dockbook->tab_hover_timeout || + dockbook->tab_hover_dockable != dockable) + { + gint page_num; + + if (dockbook->tab_hover_timeout) + { + g_source_remove (dockbook->tab_hover_timeout); + dockbook->tab_hover_timeout = 0; + dockbook->tab_hover_dockable = NULL; + } + + page_num = gtk_notebook_page_num (GTK_NOTEBOOK (dockbook), + GTK_WIDGET (dockable)); + + if (page_num != gtk_notebook_get_current_page (GTK_NOTEBOOK (dockbook))) + { + dockbook->tab_hover_timeout = + g_timeout_add (500, (GSourceFunc) gimp_dockbook_tab_hover_timeout, + dockbook); + dockbook->tab_hover_dockable = dockable; + } + } + + target_list = gtk_drag_dest_get_target_list (widget); + target_atom = gtk_drag_dest_find_target (widget, context, target_list); + +#ifdef __GNUC__ +#warning Remove "unused" as soon as we depend on GTK+ >= 2.12.1 +#endif + if (gtk_target_list_find (target_list, target_atom, &unused)) + { + gdk_drag_status (context, GDK_ACTION_MOVE, time); + gtk_drag_highlight (widget); + } + else + { + gdk_drag_status (context, 0, time); + gtk_drag_unhighlight (widget); + } + + /* always return TRUE so drag_leave() is called */ + return TRUE; +} + static gboolean gimp_dockbook_tab_drag_drop (GtkWidget *widget, GdkDragContext *context, Index: app/widgets/gimpdockbook.h =================================================================== --- app/widgets/gimpdockbook.h (revision 23554) +++ app/widgets/gimpdockbook.h (working copy) @@ -42,6 +42,9 @@ struct _GimpDockbook GimpDock *dock; GimpUIManager *ui_manager; + + guint tab_hover_timeout; + GimpDockable *tab_hover_dockable; }; struct _GimpDockbookClass