[gimp] app: Use a GdkWindow instead of GimpDockSeparators for dockable DND



commit 7b85cf4de8938bfe833de223026bd6e99d585bac
Author: Martin Nordholts <martinn src gnome org>
Date:   Sun Nov 29 18:22:12 2009 +0100

    app: Use a GdkWindow instead of GimpDockSeparators for dockable DND
    
    Make drag-and-drop rearrangement of dockables happen directly in the
    existing widget hierarchy so we don't have to use special, ugly
    widgets (read GimpDockSeparator:s) for that.
    
    More specifically, make edges of dockables and dockbooks have the same
    semantics as the GimpDockSeparators had. We put a highlight colored
    GdkWindow on top of the widget in question to highlight these special
    drop areas. This GdkWindow is not taken into consideration in the GTK+
    drag-and-drop code, so it does not interupt the DND interaction.
    
    To achive this, there is a problem we must solve: Drag events in GTK+
    are propagated inwards and out, but we sometimes want ancenstor
    widgets to take care of drop events. We solve this by introducing the
    concept of "drag handlers". A drag handler is asked if it will handle
    a given drag event, and if it will, a client will let the drag event
    be propagated upwards in the widget hierarchy. Right now, the
    GimpPanedBox is the only "drag handler". The code could be generalized
    more but it doesn't feel worth it at this point.
    
    The size of the special drop area is 5px, the same size as the default
    GtkPaned handles. This is because the plan is to later use these
    handles as drop areas too.
    
    Other changes of interest are:
     * We need to take care of "drag-motion", "drag-drop" and widget
       highlightning ourselves. We can not use the GtkDestDefaults
       conveniences with gtk_drag_dest_set() any longer since we need more
       control.
     * Make the drop callback pass the insert index directly instead of a
       GimpDockSeparator
     * Add some GIMP_LOG() debug output for DND
     * Disable the GimpDockSeparator code in GimpToolbox

 app/widgets/gimpdock.c          |   13 +-
 app/widgets/gimpdockable.c      |   86 +++++++-
 app/widgets/gimpdockable.h      |   68 +++---
 app/widgets/gimpdockbook.c      |  147 +++++++++++--
 app/widgets/gimpdockbook.h      |    2 +
 app/widgets/gimpdockcolumns.c   |   16 +-
 app/widgets/gimpdockseparator.c |   20 +-
 app/widgets/gimpdockseparator.h |   14 +-
 app/widgets/gimppanedbox.c      |  460 +++++++++++++++++++++++++++++++++------
 app/widgets/gimppanedbox.h      |   34 ++--
 app/widgets/gimptoolbox.c       |   22 --
 app/widgets/widgets-types.h     |    4 +-
 12 files changed, 695 insertions(+), 191 deletions(-)
---
diff --git a/app/widgets/gimpdock.c b/app/widgets/gimpdock.c
index 5ec1f21..9539db6 100644
--- a/app/widgets/gimpdock.c
+++ b/app/widgets/gimpdock.c
@@ -88,8 +88,8 @@ static void      gimp_dock_real_book_added   (GimpDock              *dock,
                                               GimpDockbook          *dockbook);
 static void      gimp_dock_real_book_removed (GimpDock              *dock,
                                               GimpDockbook          *dockbook);
-static gboolean  gimp_dock_dropped_cb        (GimpDockSeparator     *separator,
-                                              GtkWidget             *source,
+static gboolean  gimp_dock_dropped_cb        (GtkWidget             *source,
+                                              gint                   insert_index,
                                               gpointer               data);
 
 
@@ -292,14 +292,13 @@ gimp_dock_real_book_removed (GimpDock     *dock,
 }
 
 static gboolean
-gimp_dock_dropped_cb (GimpDockSeparator *separator,
-                      GtkWidget         *source,
-                      gpointer           data)
+gimp_dock_dropped_cb (GtkWidget *source,
+                      gint       insert_index,
+                      gpointer   data)
 {
   GimpDock     *dock     = GIMP_DOCK (data);
   GimpDockable *dockable = gimp_dockbook_drag_source_to_dockable (source);
   GtkWidget    *dockbook = NULL;
-  gint          index    = gimp_dock_separator_get_insert_pos (separator);
 
   if (!dockable )
     return FALSE;
@@ -329,7 +328,7 @@ gimp_dock_dropped_cb (GimpDockSeparator *separator,
 
   /* Create a new dockbook */
   dockbook = gimp_dockbook_new (gimp_dock_get_dialog_factory (dock)->menu_factory);
-  gimp_dock_add_book (dock, GIMP_DOCKBOOK (dockbook), index);
+  gimp_dock_add_book (dock, GIMP_DOCKBOOK (dockbook), insert_index);
 
   /* Add the dockable to new new dockbook */
   gimp_dockbook_add (GIMP_DOCKBOOK (dockbook), dockable, -1);
diff --git a/app/widgets/gimpdockable.c b/app/widgets/gimpdockable.c
index da365a9..c258d70 100644
--- a/app/widgets/gimpdockable.c
+++ b/app/widgets/gimpdockable.c
@@ -40,6 +40,7 @@
 #include "gimpdocked.h"
 #include "gimpdockwindow.h"
 #include "gimphelp-ids.h"
+#include "gimppanedbox.h"
 #include "gimpsessioninfo-aux.h"
 #include "gimpuimanager.h"
 #include "gimpwidgets-utils.h"
@@ -71,11 +72,20 @@ static void       gimp_dockable_unrealize         (GtkWidget      *widget);
 static void       gimp_dockable_map               (GtkWidget      *widget);
 static void       gimp_dockable_unmap             (GtkWidget      *widget);
 
+static void       gimp_dockable_drag_leave        (GtkWidget      *widget,
+                                                   GdkDragContext *context,
+                                                   guint           time);
+static gboolean   gimp_dockable_drag_motion       (GtkWidget      *widget,
+                                                   GdkDragContext *context,
+                                                   gint            x,
+                                                   gint            y,
+                                                   guint           time);
 static gboolean   gimp_dockable_drag_drop         (GtkWidget      *widget,
                                                    GdkDragContext *context,
                                                    gint            x,
                                                    gint            y,
                                                    guint           time);
+
 static void       gimp_dockable_style_set         (GtkWidget      *widget,
                                                    GtkStyle       *prev_style);
 static gboolean   gimp_dockable_expose_event      (GtkWidget      *widget,
@@ -138,6 +148,8 @@ gimp_dockable_class_init (GimpDockableClass *klass)
   widget_class->map           = gimp_dockable_map;
   widget_class->unmap         = gimp_dockable_unmap;
   widget_class->style_set     = gimp_dockable_style_set;
+  widget_class->drag_leave    = gimp_dockable_drag_leave;
+  widget_class->drag_motion   = gimp_dockable_drag_motion;
   widget_class->drag_drop     = gimp_dockable_drag_drop;
   widget_class->expose_event  = gimp_dockable_expose_event;
   widget_class->popup_menu    = gimp_dockable_popup_menu;
@@ -201,7 +213,7 @@ gimp_dockable_init (GimpDockable *dockable)
                     dockable);
 
   gtk_drag_dest_set (GTK_WIDGET (dockable),
-                     GTK_DEST_DEFAULT_ALL,
+                     0,
                      dialog_target_table, G_N_ELEMENTS (dialog_target_table),
                      GDK_ACTION_MOVE);
 
@@ -482,6 +494,35 @@ gimp_dockable_unmap (GtkWidget *widget)
   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
 }
 
+static void
+gimp_dockable_drag_leave (GtkWidget      *widget,
+                          GdkDragContext *context,
+                          guint           time)
+{
+  gimp_highlight_widget (widget, FALSE);
+}
+
+static gboolean
+gimp_dockable_drag_motion (GtkWidget      *widget,
+                           GdkDragContext *context,
+                           gint            x,
+                           gint            y,
+                           guint           time)
+{
+  GimpDockable *dockable          = GIMP_DOCKABLE (widget);
+  gboolean      other_will_handle = FALSE;
+
+  other_will_handle = gimp_paned_box_will_handle_drag (dockable->drag_handler,
+                                                       widget,
+                                                       context,
+                                                       x, y,
+                                                       time);
+
+  gdk_drag_status (context, other_will_handle ? 0 : GDK_ACTION_MOVE, time);
+  gimp_highlight_widget (widget, ! other_will_handle);
+  return other_will_handle ? FALSE : TRUE;
+}
+
 static gboolean
 gimp_dockable_drag_drop (GtkWidget      *widget,
                          GdkDragContext *context,
@@ -489,8 +530,30 @@ gimp_dockable_drag_drop (GtkWidget      *widget,
                          gint            y,
                          guint           time)
 {
-  return gimp_dockbook_drop_dockable (GIMP_DOCKABLE (widget)->dockbook,
-                                      gtk_drag_get_source_widget (context));
+  GimpDockable *dockable = GIMP_DOCKABLE (widget);
+  gboolean      handled  = FALSE;
+
+  if (gimp_paned_box_will_handle_drag (dockable->drag_handler,
+                                       widget,
+                                       context,
+                                       x, y,
+                                       time))
+    {
+      /* Make event fall through to the drag handler */
+      handled = FALSE;
+    }
+  else
+    {
+      handled =
+        gimp_dockbook_drop_dockable (GIMP_DOCKABLE (widget)->dockbook,
+                                     gtk_drag_get_source_widget (context));
+    }
+
+  /* We must call gtk_drag_finish() ourselves */
+  if (handled)
+    gtk_drag_finish (context, TRUE, TRUE, time);
+
+  return handled;
 }
 
 static void
@@ -992,6 +1055,23 @@ gimp_dockable_get_menu (GimpDockable  *dockable,
   return NULL;
 }
 
+/**
+ * gimp_dockable_set_drag_handler:
+ * @dockable:
+ * @handler:
+ *
+ * Set a drag handler that will be asked if it will handle drag events
+ * before the dockable handles the event itself.
+ **/
+void
+gimp_dockable_set_drag_handler (GimpDockable *dockable,
+                                GimpPanedBox *handler)
+{
+  g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
+
+  dockable->drag_handler = handler;
+}
+
 void
 gimp_dockable_detach (GimpDockable *dockable)
 {
diff --git a/app/widgets/gimpdockable.h b/app/widgets/gimpdockable.h
index 7e84c63..90adc55 100644
--- a/app/widgets/gimpdockable.h
+++ b/app/widgets/gimpdockable.h
@@ -64,6 +64,8 @@ struct _GimpDockable
   guint         blink_timeout_id;
   gint          blink_counter;
 
+  GimpPanedBox *drag_handler;
+
   /*  drag icon hotspot  */
   gint          drag_x;
   gint          drag_y;
@@ -75,38 +77,40 @@ struct _GimpDockableClass
 };
 
 
-GType           gimp_dockable_get_type        (void) G_GNUC_CONST;
-
-GtkWidget     * gimp_dockable_new             (const gchar    *name,
-                                               const gchar    *blurb,
-                                               const gchar    *stock_id,
-                                               const gchar    *help_id);
-
-void            gimp_dockable_set_aux_info    (GimpDockable   *dockable,
-                                               GList          *aux_info);
-GList         * gimp_dockable_get_aux_info    (GimpDockable   *dockable);
-
-void            gimp_dockable_set_locked      (GimpDockable   *dockable,
-                                               gboolean        lock);
-gboolean        gimp_dockable_is_locked       (GimpDockable   *dockable);
-
-void            gimp_dockable_set_tab_style   (GimpDockable   *dockable,
-                                               GimpTabStyle    tab_style);
-GtkWidget     * gimp_dockable_get_tab_widget  (GimpDockable   *dockable,
-                                               GimpContext    *context,
-                                               GimpTabStyle    tab_style,
-                                               GtkIconSize     size);
-GtkWidget     * gimp_dockable_get_drag_widget (GimpDockable   *dockable);
-void            gimp_dockable_set_context     (GimpDockable   *dockable,
-                                               GimpContext    *context);
-GimpUIManager * gimp_dockable_get_menu        (GimpDockable   *dockable,
-                                               const gchar   **ui_path,
-                                               gpointer       *popup_data);
-
-void            gimp_dockable_detach          (GimpDockable   *dockable);
-
-void            gimp_dockable_blink           (GimpDockable   *dockable);
-void            gimp_dockable_blink_cancel    (GimpDockable   *dockable);
+GType           gimp_dockable_get_type         (void) G_GNUC_CONST;
+
+GtkWidget     * gimp_dockable_new              (const gchar    *name,
+                                                const gchar    *blurb,
+                                                const gchar    *stock_id,
+                                                const gchar    *help_id);
+
+void            gimp_dockable_set_aux_info     (GimpDockable   *dockable,
+                                                GList          *aux_info);
+GList         * gimp_dockable_get_aux_info     (GimpDockable   *dockable);
+
+void            gimp_dockable_set_locked       (GimpDockable   *dockable,
+                                                gboolean        lock);
+gboolean        gimp_dockable_is_locked        (GimpDockable   *dockable);
+
+void            gimp_dockable_set_tab_style    (GimpDockable   *dockable,
+                                                GimpTabStyle    tab_style);
+GtkWidget     * gimp_dockable_get_tab_widget   (GimpDockable   *dockable,
+                                                GimpContext    *context,
+                                                GimpTabStyle    tab_style,
+                                                GtkIconSize     size);
+GtkWidget     * gimp_dockable_get_drag_widget  (GimpDockable   *dockable);
+void            gimp_dockable_set_context      (GimpDockable   *dockable,
+                                                GimpContext    *context);
+GimpUIManager * gimp_dockable_get_menu         (GimpDockable   *dockable,
+                                                const gchar   **ui_path,
+                                                gpointer       *popup_data);
+void            gimp_dockable_set_drag_handler (GimpDockable   *dockable,
+                                                GimpPanedBox   *drag_handler);
+
+void            gimp_dockable_detach           (GimpDockable   *dockable);
+
+void            gimp_dockable_blink            (GimpDockable   *dockable);
+void            gimp_dockable_blink_cancel     (GimpDockable   *dockable);
 
 
 #endif /* __GIMP_DOCKABLE_H__ */
diff --git a/app/widgets/gimpdockbook.c b/app/widgets/gimpdockbook.c
index c5e3e04..ccbc48b 100644
--- a/app/widgets/gimpdockbook.c
+++ b/app/widgets/gimpdockbook.c
@@ -47,6 +47,7 @@
 #include "gimpview.h"
 #include "gimpwidgets-utils.h"
 
+#include "gimp-log.h"
 
 #define DEFAULT_TAB_BORDER     0
 #define DEFAULT_TAB_ICON_SIZE  GTK_ICON_SIZE_BUTTON
@@ -71,6 +72,8 @@ struct _GimpDockbookPrivate
 
   guint          tab_hover_timeout;
   GimpDockable  *tab_hover_dockable;
+
+  GimpPanedBox  *drag_handler;
 };
 
 
@@ -79,6 +82,15 @@ static void      gimp_dockbook_finalize           (GObject        *object);
 
 static void      gimp_dockbook_style_set          (GtkWidget      *widget,
                                                    GtkStyle       *prev_style);
+
+static void      gimp_dockbook_drag_leave         (GtkWidget      *widget,
+                                                   GdkDragContext *context,
+                                                   guint           time);
+static gboolean  gimp_dockbook_drag_motion        (GtkWidget      *widget,
+                                                   GdkDragContext *context,
+                                                   gint            x,
+                                                   gint            y,
+                                                   guint           time);
 static gboolean  gimp_dockbook_drag_drop          (GtkWidget      *widget,
                                                    GdkDragContext *context,
                                                    gint            x,
@@ -178,6 +190,8 @@ gimp_dockbook_class_init (GimpDockbookClass *klass)
   object_class->finalize    = gimp_dockbook_finalize;
 
   widget_class->style_set   = gimp_dockbook_style_set;
+  widget_class->drag_leave  = gimp_dockbook_drag_leave;
+  widget_class->drag_motion = gimp_dockbook_drag_motion;
   widget_class->drag_drop   = gimp_dockbook_drag_drop;
 
   klass->dockable_added     = gimp_dockbook_dockable_added;
@@ -214,7 +228,7 @@ gimp_dockbook_init (GimpDockbook *dockbook)
   gtk_notebook_set_show_border (GTK_NOTEBOOK (dockbook), FALSE);
 
   gtk_drag_dest_set (GTK_WIDGET (dockbook),
-                     GTK_DEST_DEFAULT_ALL,
+                     0,
                      dialog_target_table, G_N_ELEMENTS (dialog_target_table),
                      GDK_ACTION_MOVE);
 }
@@ -278,6 +292,35 @@ gimp_dockbook_style_set (GtkWidget *widget,
   g_list_free (children);
 }
 
+static void
+gimp_dockbook_drag_leave (GtkWidget      *widget,
+                          GdkDragContext *context,
+                          guint           time)
+{
+  gimp_highlight_widget (widget, FALSE);
+}
+
+static gboolean
+gimp_dockbook_drag_motion (GtkWidget      *widget,
+                           GdkDragContext *context,
+                           gint            x,
+                           gint            y,
+                           guint           time)
+{
+  GimpDockbook *dockbook          = GIMP_DOCKBOOK (widget);
+  gboolean      other_will_handle = FALSE;
+
+  other_will_handle = gimp_paned_box_will_handle_drag (dockbook->p->drag_handler,
+                                                       widget,
+                                                       context,
+                                                       x, y,
+                                                       time);
+
+  gdk_drag_status (context, other_will_handle ? 0 : GDK_ACTION_MOVE, time);
+  gimp_highlight_widget (widget, ! other_will_handle);
+  return other_will_handle ? FALSE : TRUE;
+}
+
 static gboolean
 gimp_dockbook_drag_drop (GtkWidget      *widget,
                          GdkDragContext *context,
@@ -285,8 +328,30 @@ gimp_dockbook_drag_drop (GtkWidget      *widget,
                          gint            y,
                          guint           time)
 {
-  return gimp_dockbook_drop_dockable (GIMP_DOCKBOOK (widget),
-                                      gtk_drag_get_source_widget (context));
+  GimpDockbook *dockbook = GIMP_DOCKBOOK (widget);
+  gboolean      handled  = FALSE;
+
+  if (gimp_paned_box_will_handle_drag (dockbook->p->drag_handler,
+                                       widget,
+                                       context,
+                                       x, y,
+                                       time))
+    {
+      /* Make event fall through to the drag handler */
+      handled = FALSE;
+    }
+  else
+    {
+      handled =
+        gimp_dockbook_drop_dockable (dockbook,
+                                     gtk_drag_get_source_widget (context));
+    }
+
+  /* We must call gtk_drag_finish() ourselves */
+  if (handled)
+    gtk_drag_finish (context, TRUE, TRUE, time);
+
+  return handled;
 }
 
 static void
@@ -386,10 +451,14 @@ gimp_dockbook_add (GimpDockbook *dockbook,
   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
   g_return_if_fail (dockable->dockbook == NULL);
 
+  GIMP_LOG (DND, "Adding GimpDockable %p to GimpDockbook %p", dockable, dockbook);
+
   tab_widget = gimp_dockbook_create_tab_widget (dockbook, dockable);
 
   g_return_if_fail (GTK_IS_WIDGET (tab_widget));
 
+  gimp_dockable_set_drag_handler (dockable, dockbook->p->drag_handler);
+
   menu_widget = gimp_dockable_get_tab_widget (dockable,
                                               gimp_dock_get_context (dockbook->p->dock),
                                               GIMP_TAB_STYLE_ICON_BLURB,
@@ -436,6 +505,10 @@ gimp_dockbook_remove (GimpDockbook *dockbook,
   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
   g_return_if_fail (dockable->dockbook == dockbook);
 
+  GIMP_LOG (DND, "Removing GimpDockable %p from GimpDockbook %p", dockable, dockbook);
+
+  gimp_dockable_set_drag_handler (dockable, NULL);
+
   g_object_ref (dockable);
 
   g_signal_handlers_disconnect_by_func (dockable,
@@ -557,7 +630,7 @@ gimp_dockbook_create_tab_widget (GimpDockbook *dockbook,
                     dockable);
 
   gtk_drag_dest_set (tab_widget,
-                     GTK_DEST_DEFAULT_DROP,
+                     0,
                      dialog_target_table, G_N_ELEMENTS (dialog_target_table),
                      GDK_ACTION_MOVE);
   g_signal_connect (tab_widget, "drag-leave",
@@ -609,6 +682,23 @@ gimp_dockbook_drop_dockable (GimpDockbook *dockbook,
 }
 
 /**
+ * gimp_dockable_set_drag_handler:
+ * @dockable:
+ * @handler:
+ *
+ * Set a drag handler that will be asked if it will handle drag events
+ * before the dockbook handles the event itself.
+ **/
+void
+gimp_dockbook_set_drag_handler (GimpDockbook *dockbook,
+                                GimpPanedBox *drag_handler)
+{
+  g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
+
+  dockbook->p->drag_handler = drag_handler;
+}
+
+/**
  * gimp_dockbook_drag_source_to_dockable:
  * @drag_source: A drag-and-drop source widget
  *
@@ -705,8 +795,6 @@ gimp_dockbook_tab_drag_begin (GtkWidget      *widget,
    * it's the dockable that's being dragged around
    */
   gtk_widget_set_sensitive (GTK_WIDGET (dockable), FALSE);
-
-  gimp_paned_box_class_show_separators (paned_box_class, TRUE);
 }
 
 static void
@@ -735,8 +823,6 @@ gimp_dockbook_tab_drag_end (GtkWidget      *widget,
   dockable->drag_x = GIMP_DOCKABLE_DRAG_OFFSET;
   dockable->drag_y = GIMP_DOCKABLE_DRAG_OFFSET;
   gtk_widget_set_sensitive (GTK_WIDGET (dockable), TRUE);
-
-  gimp_paned_box_class_show_separators (paned_box_class, FALSE);
 }
 
 
@@ -766,7 +852,18 @@ gimp_dockbook_tab_drag_motion (GtkWidget      *widget,
   GimpDockbook  *dockbook = dockable->dockbook;
   GtkTargetList *target_list;
   GdkAtom        target_atom;
-  gboolean       target_exists;
+  gboolean       handle   = FALSE;
+
+  /* If the handler will handle the drag, return FALSE */
+  if (gimp_paned_box_will_handle_drag (dockbook->p->drag_handler,
+                                       widget,
+                                       context,
+                                       x, y,
+                                       time))
+    {
+      handle = FALSE;
+      goto finish;
+    }
 
   if (! dockbook->p->tab_hover_timeout ||
       dockbook->p->tab_hover_dockable != dockable)
@@ -785,12 +882,12 @@ gimp_dockbook_tab_drag_motion (GtkWidget      *widget,
   target_list = gtk_drag_dest_get_target_list (widget);
   target_atom = gtk_drag_dest_find_target (widget, context, target_list);
 
-  target_exists = gtk_target_list_find (target_list, target_atom, NULL);
-  gdk_drag_status (context, target_exists ? GDK_ACTION_MOVE : 0, time);
-  gimp_highlight_widget (widget, target_exists);
+  handle = gtk_target_list_find (target_list, target_atom, NULL);
 
-  /*  always return TRUE so drag_leave() is called  */
-  return TRUE;
+ finish:
+  gdk_drag_status (context, handle ? GDK_ACTION_MOVE : 0, time);
+  gimp_highlight_widget (widget, handle);
+  return handle;
 }
 
 static gboolean
@@ -802,11 +899,23 @@ gimp_dockbook_tab_drag_drop (GtkWidget      *widget,
 {
   GimpDockable *dest_dockable;
   GtkWidget    *source;
+  gboolean      handle = FALSE;
 
   dest_dockable = g_object_get_data (G_OBJECT (widget), "gimp-dockable");
 
   source = gtk_drag_get_source_widget (context);
 
+  /* If the handler will handle the drag, return FALSE */
+  if (gimp_paned_box_will_handle_drag (dest_dockable->drag_handler,
+                                       widget,
+                                       context,
+                                       x, y,
+                                       time))
+    {
+      handle = FALSE;
+      goto finish;
+    }
+
   if (dest_dockable && source)
     {
       GimpDockable *src_dockable =
@@ -830,7 +939,7 @@ gimp_dockbook_tab_drag_drop (GtkWidget      *widget,
 
               g_object_unref (src_dockable);
 
-              return TRUE;
+              handle = TRUE;
             }
           else if (src_dockable != dest_dockable)
             {
@@ -842,12 +951,16 @@ gimp_dockbook_tab_drag_drop (GtkWidget      *widget,
                              dockbook_signals[DOCKABLE_REORDERED], 0,
                              src_dockable);
 
-              return TRUE;
+              handle = TRUE;
             }
         }
     }
 
-  return FALSE;
+ finish:
+  if (handle)
+    gtk_drag_finish (context, TRUE, TRUE, time);
+
+  return handle;
 }
 
 static void
diff --git a/app/widgets/gimpdockbook.h b/app/widgets/gimpdockbook.h
index 77cccdf..fd3ba73 100644
--- a/app/widgets/gimpdockbook.h
+++ b/app/widgets/gimpdockbook.h
@@ -74,6 +74,8 @@ GtkWidget    *  gimp_dockbook_create_tab_widget         (GimpDockbook    *dockbo
                                                          GimpDockable    *dockable);
 gboolean        gimp_dockbook_drop_dockable             (GimpDockbook    *dockbook,
                                                          GtkWidget       *drag_source);
+void            gimp_dockbook_set_drag_handler          (GimpDockbook    *dockbook,
+                                                         GimpPanedBox    *drag_handler);
 GimpDockable *  gimp_dockbook_drag_source_to_dockable   (GtkWidget       *drag_source);
 
 
diff --git a/app/widgets/gimpdockcolumns.c b/app/widgets/gimpdockcolumns.c
index f06944c..72286b7 100644
--- a/app/widgets/gimpdockcolumns.c
+++ b/app/widgets/gimpdockcolumns.c
@@ -39,6 +39,7 @@
 #include "gimpmenudock.h"
 #include "gimppanedbox.h"
 
+#include "gimp-log.h"
 
 enum
 {
@@ -56,8 +57,8 @@ struct _GimpDockColumnsPrivate
 };
 
 
-static gboolean  gimp_dock_columns_dropped_cb        (GimpDockSeparator *separator,
-                                                      GtkWidget         *source,
+static gboolean  gimp_dock_columns_dropped_cb        (GtkWidget         *source,
+                                                      gint               insert_index,
                                                       gpointer           data);
 static void      gimp_dock_columns_real_dock_added   (GimpDockColumns   *dock_columns,
                                                       GimpDock          *dock);
@@ -121,15 +122,14 @@ gimp_dock_columns_init (GimpDockColumns *dock_columns)
 }
 
 static gboolean
-gimp_dock_columns_dropped_cb (GimpDockSeparator *separator,
-                              GtkWidget         *source,
+gimp_dock_columns_dropped_cb (GtkWidget         *source,
+                              gint               insert_index,
                               gpointer           data)
 {
   GimpDockColumns *dock_columns = GIMP_DOCK_COLUMNS (data);
   GimpDockable    *dockable     = gimp_dockbook_drag_source_to_dockable (source);
   GtkWidget       *dock         = NULL;
   GtkWidget       *dockbook     = NULL;
-  gint             index        = gimp_dock_separator_get_insert_pos (separator);
 
   if (!dockable )
     return FALSE;
@@ -138,7 +138,7 @@ gimp_dock_columns_dropped_cb (GimpDockSeparator *separator,
   dock = gimp_menu_dock_new (global_dock_factory,
                              global_dock_factory->context->gimp->images,
                              global_dock_factory->context->gimp->displays);
-  gimp_dock_columns_add_dock (dock_columns, GIMP_DOCK (dock), index);
+  gimp_dock_columns_add_dock (dock_columns, GIMP_DOCK (dock), insert_index);
 
   /* Put a now dockbook in the dock */
   dockbook = gimp_dockbook_new (gimp_dock_get_dialog_factory (GIMP_DOCK (dock))->menu_factory);
@@ -197,6 +197,8 @@ gimp_dock_columns_add_dock (GimpDockColumns *dock_columns,
   g_return_if_fail (GIMP_IS_DOCK_COLUMNS (dock_columns));
   g_return_if_fail (GIMP_IS_DOCK (dock));
 
+  GIMP_LOG (DND, "Adding GimpDock %p to GimpDockColumns %p", dock, dock_columns);
+
   dock_columns->p->docks = g_list_prepend (dock_columns->p->docks, dock);
 
   gimp_paned_box_add_widget (GIMP_PANED_BOX (dock_columns->p->paned_hbox),
@@ -219,6 +221,8 @@ gimp_dock_columns_remove_dock (GimpDockColumns *dock_columns,
   g_return_if_fail (GIMP_IS_DOCK_COLUMNS (dock_columns));
   g_return_if_fail (GIMP_IS_DOCK (dock));
 
+  GIMP_LOG (DND, "Removing GimpDock %p from GimpDockColumns %p", dock, dock_columns);
+
   dock_columns->p->docks = g_list_remove (dock_columns->p->docks, dock);
 
   g_signal_handlers_disconnect_by_func (dock,
diff --git a/app/widgets/gimpdockseparator.c b/app/widgets/gimpdockseparator.c
index e244205..51f3683 100644
--- a/app/widgets/gimpdockseparator.c
+++ b/app/widgets/gimpdockseparator.c
@@ -44,13 +44,13 @@
 
 struct _GimpDockSeparatorPrivate
 {
-  GimpDockSeparatorDroppedFunc  dropped_cb;
-  gpointer                     *dropped_cb_data;
+  GimpPanedBoxDroppedFunc  dropped_cb;
+  gpointer                *dropped_cb_data;
 
-  GtkWidget                    *frame;
-  GtkWidget                    *label;
+  GtkWidget               *frame;
+  GtkWidget               *label;
 
-  GtkAnchorType                 anchor;
+  GtkAnchorType            anchor;
 };
 
 
@@ -201,7 +201,9 @@ gimp_dock_separator_drag_drop (GtkWidget      *widget,
 
   if (source)
     {
-      return separator->p->dropped_cb (separator, source, separator->p->dropped_cb_data);
+      return separator->p->dropped_cb (source,
+                                       gimp_dock_separator_get_insert_pos (separator),
+                                       separator->p->dropped_cb_data);
     }
 
   return FALSE;
@@ -223,9 +225,9 @@ gimp_dock_separator_new (GtkAnchorType anchor)
 }
 
 void
-gimp_dock_separator_set_dropped_cb (GimpDockSeparator            *separator,
-                                    GimpDockSeparatorDroppedFunc  dropped_cb,
-                                    gpointer                      dropped_cb_data)
+gimp_dock_separator_set_dropped_cb (GimpDockSeparator       *separator,
+                                    GimpPanedBoxDroppedFunc  dropped_cb,
+                                    gpointer                 dropped_cb_data)
 {
   g_return_if_fail (GIMP_IS_DOCK_SEPARATOR (separator));
 
diff --git a/app/widgets/gimpdockseparator.h b/app/widgets/gimpdockseparator.h
index 2b367bc..a9b3606 100644
--- a/app/widgets/gimpdockseparator.h
+++ b/app/widgets/gimpdockseparator.h
@@ -53,13 +53,13 @@ struct _GimpDockSeparatorClass
 
 
 GType          gimp_dock_separator_get_type       (void) G_GNUC_CONST;
-GtkWidget    * gimp_dock_separator_new            (GtkAnchorType                 anchor);
-void           gimp_dock_separator_set_dropped_cb (GimpDockSeparator            *separator,
-                                                   GimpDockSeparatorDroppedFunc  dropped_cb,
-                                                   gpointer                      dropped_cb_data);
-gint           gimp_dock_separator_get_insert_pos (GimpDockSeparator            *separator);
-void           gimp_dock_separator_set_show_label (GimpDockSeparator            *separator,
-                                                   gboolean                      show);
+GtkWidget    * gimp_dock_separator_new            (GtkAnchorType            anchor);
+void           gimp_dock_separator_set_dropped_cb (GimpDockSeparator       *separator,
+                                                   GimpPanedBoxDroppedFunc  dropped_cb,
+                                                   gpointer                 dropped_cb_data);
+gint           gimp_dock_separator_get_insert_pos (GimpDockSeparator       *separator);
+void           gimp_dock_separator_set_show_label (GimpDockSeparator       *separator,
+                                                   gboolean                 show);
 
 
 #endif /* __GIMP_DOCK_SEPARATOR_H__ */
diff --git a/app/widgets/gimppanedbox.c b/app/widgets/gimppanedbox.c
index 2e74892..ef117b2 100644
--- a/app/widgets/gimppanedbox.c
+++ b/app/widgets/gimppanedbox.c
@@ -25,39 +25,88 @@
 
 #include "widgets-types.h"
 
-#include "gimpdockseparator.h"
+#include "core/gimp.h"
+#include "core/gimpcontext.h"
+#include "core/gimpmarshal.h"
+
+#include "dialogs/dialogs.h"
+
+#include "gimpdialogfactory.h"
+#include "gimpdnd.h"
+#include "gimpdockable.h"
+#include "gimpdockbook.h"
+#include "gimpmenudock.h"
 #include "gimppanedbox.h"
+#include "gimpwidgets-utils.h"
+
+#include "gimp-log.h"
+
+
+/**
+ * Defines the size of the area that dockables can be dropped on in
+ * order to be inserted and get space on their own (rather than
+ * inserted among others and sharing space)
+ */
+#define DROP_AREA_SIZE      5
+
+#define INSERT_INDEX_UNUSED G_MININT
 
 
 struct _GimpPanedBoxPrivate
 {
   /* Widgets that are separated by panes */
-  GList     *widgets;
+  GList                  *widgets;
 
-  /* Supports drag & drop rearrangement of widgets */
-  GtkWidget *first_separator;
-  GtkWidget *last_separator;
-};
+  /* Window used for drag-and-drop output */
+  GdkWindow              *dnd_window;
 
+  /* The insert index to use on drop */
+  gint                    insert_index;
 
-static void      gimp_paned_box_finalize          (GObject               *object);
+  /* Callback on drop */
+  GimpPanedBoxDroppedFunc dropped_cb;
+  gpointer                dropped_cb_data;
 
+  /* A drag handler offered to handle drag events */
+  GimpPanedBox           *drag_handler;
+  
+};
 
-G_DEFINE_TYPE (GimpPanedBox, gimp_paned_box, GTK_TYPE_BOX)
+static void      gimp_paned_box_drag_leave              (GtkWidget      *widget,
+                                                         GdkDragContext *context,
+                                                         guint           time);
+static gboolean  gimp_paned_box_drag_motion             (GtkWidget      *widget,
+                                                         GdkDragContext *context,
+                                                         gint            x,
+                                                         gint            y,
+                                                         guint           time);
+static gboolean  gimp_paned_box_drag_drop               (GtkWidget      *widget,
+                                                         GdkDragContext *context,
+                                                         gint            x,
+                                                         gint            y,
+                                                         guint           time);
+static void      gimp_paned_box_realize                 (GtkWidget      *widget);
+static void      gimp_paned_box_unrealize               (GtkWidget      *widget);
+static void      gimp_paned_box_set_widget_drag_handler (GtkWidget      *widget,
+                                                         GimpPanedBox   *handler);
 
-#define parent_class gimp_paned_box_parent_class
 
+G_DEFINE_TYPE (GimpPanedBox, gimp_paned_box, GTK_TYPE_BOX)
 
-/* Keep the list of instance for gimp_dock_class_show_separators() */
-static GList *paned_box_instances = NULL;
+#define parent_class gimp_paned_box_parent_class
 
+static const GtkTargetEntry dialog_target_table[] = { GIMP_TARGET_DIALOG };
 
 static void
 gimp_paned_box_class_init (GimpPanedBoxClass *klass)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
-  object_class->finalize = gimp_paned_box_finalize;
+  widget_class->drag_leave  = gimp_paned_box_drag_leave;
+  widget_class->drag_motion = gimp_paned_box_drag_motion;
+  widget_class->drag_drop   = gimp_paned_box_drag_drop;
+  widget_class->realize     = gimp_paned_box_realize;
+  widget_class->unrealize   = gimp_paned_box_unrealize;
 
   g_type_class_add_private (klass, sizeof (GimpPanedBoxPrivate));
 }
@@ -69,23 +118,253 @@ gimp_paned_box_init (GimpPanedBox *paned_box)
                                               GIMP_TYPE_PANED_BOX,
                                               GimpPanedBoxPrivate);
 
-  paned_box->p->first_separator = gimp_dock_separator_new (GTK_ANCHOR_NORTH);
-  paned_box->p->last_separator = gimp_dock_separator_new (GTK_ANCHOR_SOUTH);
+  gtk_drag_dest_set (GTK_WIDGET (paned_box),
+                     0,
+                     dialog_target_table, G_N_ELEMENTS (dialog_target_table),
+                     GDK_ACTION_MOVE);
+}
 
-  gtk_box_pack_start (GTK_BOX (paned_box), paned_box->p->first_separator,
-                      FALSE, FALSE, 0);
-  gtk_box_pack_end (GTK_BOX (paned_box), paned_box->p->last_separator,
-                    FALSE, FALSE, 0);
 
-  paned_box_instances = g_list_prepend (paned_box_instances, paned_box);
+static void
+gimp_paned_box_realize (GtkWidget *widget)
+{
+  GTK_WIDGET_CLASS (parent_class)->realize (widget);
+
+  /* We realize() dnd_window on demand in
+   * gimp_paned_box_show_separators()
+   */
 }
 
 static void
-gimp_paned_box_finalize (GObject *object)
+gimp_paned_box_unrealize (GtkWidget *widget)
 {
-  paned_box_instances = g_list_remove (paned_box_instances, object);
+  GimpPanedBox *paned_box = GIMP_PANED_BOX (widget);
 
-  G_OBJECT_CLASS (parent_class)->finalize (object);
+  if (paned_box->p->dnd_window)
+    {
+      gdk_window_set_user_data (paned_box->p->dnd_window, NULL);
+      gdk_window_destroy (paned_box->p->dnd_window);
+      paned_box->p->dnd_window = NULL;
+    }
+
+  GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
+}
+
+static void
+gimp_paned_box_set_widget_drag_handler (GtkWidget    *widget,
+                                        GimpPanedBox *drag_handler)
+{
+  /* Hook us in for drag events. We could abstract this properly and
+   * put gimp_paned_box_will_handle_drag() in an interface for
+   * example, but it doesn't feel worth it at this point
+   */
+  if (GIMP_IS_DOCKBOOK (widget))
+    {
+      gimp_dockbook_set_drag_handler (GIMP_DOCKBOOK (widget),
+                                      drag_handler);
+    }
+  if (GIMP_IS_DOCK (widget))
+    {
+      GimpPanedBox *dock_paned_box = NULL;
+      dock_paned_box = GIMP_PANED_BOX (gimp_dock_get_vbox (GIMP_DOCK (widget)));
+      gimp_paned_box_set_drag_handler (dock_paned_box, drag_handler);
+    }
+}
+
+static void
+gimp_paned_box_position_drop_indicator (GimpPanedBox *paned_box,
+                                        gint          x,
+                                        gint          y,
+                                        gint          width,
+                                        gint          height)
+{
+  GtkWidget *widget = GTK_WIDGET (paned_box);
+
+  if (! gtk_widget_is_drawable (widget))
+    return;
+
+  /* Create or move the GdkWindow in place */
+  if (! paned_box->p->dnd_window)
+    {
+      GdkColor      *color;
+      GtkWidget     *paned_box_w = NULL;
+      GtkAllocation  allocation  = { 0, };
+      GdkWindowAttr  attributes = { 0, };
+
+      paned_box_w = GTK_WIDGET (paned_box);
+      gtk_widget_get_allocation (paned_box_w, &allocation);
+
+      attributes.x                 = x;
+      attributes.y                 = y;
+      attributes.width             = width;
+      attributes.height            = height;
+      attributes.window_type       = GDK_WINDOW_CHILD;
+      attributes.wclass            = GDK_INPUT_OUTPUT;
+      attributes.event_mask        = gtk_widget_get_events (paned_box_w);
+
+      paned_box->p->dnd_window = gdk_window_new (gtk_widget_get_window (paned_box_w),
+                                                 &attributes,
+                                                 GDK_WA_X | GDK_WA_Y);
+      gdk_window_set_user_data (paned_box->p->dnd_window, paned_box_w);
+
+      color = gtk_widget_get_style (widget)->bg + GTK_STATE_SELECTED;
+      gdk_window_set_background (paned_box->p->dnd_window, color);
+    }
+  else
+    {
+      gdk_window_move_resize (paned_box->p->dnd_window,
+                              x, y,
+                              width, height);
+    }
+  gdk_window_show (paned_box->p->dnd_window);
+}
+
+static void
+gimp_paned_box_hide_drop_indicator (GimpPanedBox *paned_box)
+{
+  if (! paned_box->p->dnd_window)
+    return;
+
+  gdk_window_hide (paned_box->p->dnd_window);
+}
+
+static void
+gimp_paned_box_drag_leave (GtkWidget      *widget,
+                           GdkDragContext *context,
+                           guint           time)
+{
+  gimp_paned_box_hide_drop_indicator (GIMP_PANED_BOX (widget));
+  gimp_highlight_widget (widget, FALSE);
+}
+
+static gboolean
+gimp_paned_box_drag_motion (GtkWidget      *widget,
+                            GdkDragContext *context,
+                            gint            x,
+                            gint            y,
+                            guint           time)
+{
+  GimpPanedBox  *paned_box         = GIMP_PANED_BOX (widget);
+  gint           insert_index      = INSERT_INDEX_UNUSED;
+  gint           dnd_window_x      = 0;
+  gint           dnd_window_y      = 0;
+  gint           dnd_window_w      = 0;
+  gint           dnd_window_h      = 0;
+  GtkOrientation orientation       = 0;
+  GtkAllocation  allocation        = { 0, };
+  gboolean       handle            = FALSE;
+
+  if (gimp_paned_box_will_handle_drag (paned_box->p->drag_handler,
+                                       widget,
+                                       context,
+                                       x, y,
+                                       time))
+    {
+      /* A parent widget will handle the event, just go to the end */
+      handle = FALSE;
+      goto finish;
+    }
+
+  gtk_widget_get_allocation (widget, &allocation);
+
+  /* See if we're at the edge of the dock */
+  orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (paned_box));
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      dnd_window_y = 0;
+      dnd_window_w = DROP_AREA_SIZE;
+      dnd_window_h = allocation.height;
+
+      if (x < DROP_AREA_SIZE)
+        {
+          insert_index = 0;
+          dnd_window_x = 0;
+        }
+      if (x > allocation.width - DROP_AREA_SIZE)
+        {
+          insert_index = -1;
+          dnd_window_x = allocation.width - DROP_AREA_SIZE;
+        }
+    }
+  else /* if (orientation = GTK_ORIENTATION_VERTICAL) */
+    {
+      dnd_window_x = 0;
+      dnd_window_w = allocation.width;
+      dnd_window_h = DROP_AREA_SIZE;
+
+      if (y < DROP_AREA_SIZE)
+        {
+          insert_index = 0;
+          dnd_window_y = 0;
+        }
+      if (y > allocation.height - DROP_AREA_SIZE)
+        {
+          insert_index = -1;
+          dnd_window_y = allocation.height - DROP_AREA_SIZE;
+        }
+    }
+
+  /* If we are at the edge, show a GdkWindow to communicate that a
+   * drop will create a new dock column
+   */
+  handle = (insert_index != INSERT_INDEX_UNUSED);
+  if (handle)
+    {
+      gimp_paned_box_position_drop_indicator (paned_box,
+                                              allocation.x + dnd_window_x,
+                                              allocation.y + dnd_window_y,
+                                              dnd_window_w,
+                                              dnd_window_h);
+    }
+  else
+    {
+      gimp_paned_box_hide_drop_indicator (paned_box);
+    }
+
+  /* Save the insert index for drag-drop */
+  paned_box->p->insert_index = insert_index;
+
+ finish:
+  gdk_drag_status (context, handle ? GDK_ACTION_MOVE : 0, time);
+  gimp_highlight_widget (widget, handle);
+  return handle;
+}
+
+static gboolean
+gimp_paned_box_drag_drop (GtkWidget      *widget,
+                          GdkDragContext *context,
+                          gint            x,
+                          gint            y,
+                          guint           time)
+{
+  gboolean      found   = FALSE;
+  GimpPanedBox *paned_box = GIMP_PANED_BOX (widget);
+
+  if (gimp_paned_box_will_handle_drag (paned_box->p->drag_handler,
+                                       widget,
+                                       context,
+                                       x, y,
+                                       time))
+    {
+      /* A parent widget will handle the event, just go to the end */
+      found = FALSE;
+      goto finish;
+    }
+  
+  if (paned_box->p->dropped_cb)
+    {
+      GtkWidget *source = gtk_drag_get_source_widget (context);
+
+      if (source)
+        found = paned_box->p->dropped_cb (source,
+                                          paned_box->p->insert_index,
+                                          paned_box->p->dropped_cb_data);
+    }
+
+ finish:
+  if (found)
+    gtk_drag_finish (context, TRUE, TRUE, time);
+  return found;
 }
 
 
@@ -102,18 +381,14 @@ gimp_paned_box_new (gboolean       homogeneous,
 }
 
 void
-gimp_paned_box_set_dropped_cb (GimpPanedBox                 *paned_box,
-                               GimpDockSeparatorDroppedFunc  dropped_cb,
-                               gpointer                      dropped_cb_data)
+gimp_paned_box_set_dropped_cb (GimpPanedBox            *paned_box,
+                               GimpPanedBoxDroppedFunc  dropped_cb,
+                               gpointer                 dropped_cb_data)
 {
   g_return_if_fail (GIMP_IS_PANED_BOX (paned_box));
 
-  gimp_dock_separator_set_dropped_cb (GIMP_DOCK_SEPARATOR (paned_box->p->first_separator),
-                                      dropped_cb,
-                                      dropped_cb_data);
-  gimp_dock_separator_set_dropped_cb (GIMP_DOCK_SEPARATOR (paned_box->p->last_separator),
-                                      dropped_cb,
-                                      dropped_cb_data);
+  paned_box->p->dropped_cb      = dropped_cb;
+  paned_box->p->dropped_cb_data = dropped_cb_data;
 }
 
 /**
@@ -135,6 +410,8 @@ gimp_paned_box_add_widget (GimpPanedBox *paned_box,
   g_return_if_fail (GIMP_IS_PANED_BOX (paned_box));
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
+  GIMP_LOG (DND, "Adding GtkWidget %p to GimpPanedBox %p", widget, paned_box);
+
   /* Calculate length */
   old_length = g_list_length (paned_box->p->widgets);
 
@@ -147,16 +424,15 @@ gimp_paned_box_add_widget (GimpPanedBox *paned_box,
   /* Insert into the list */
   paned_box->p->widgets = g_list_insert (paned_box->p->widgets, widget, index);
 
+  /* Hook us in for drag events. We could abstract this but it doesn't
+   * seem worth it at this point
+   */
+  gimp_paned_box_set_widget_drag_handler (widget, paned_box);
+
   /* Insert into the GtkPaned hierarchy */
   if (old_length == 0)
     {
       gtk_box_pack_start (GTK_BOX (paned_box), widget, TRUE, TRUE, 0);
-
-      /* Keep the desired widget at the end */
-      if (paned_box->p->last_separator)
-        gtk_box_reorder_child (GTK_BOX (paned_box),
-                               paned_box->p->last_separator,
-                               -1);
     }
   else
     {
@@ -245,6 +521,8 @@ gimp_paned_box_remove_widget (GimpPanedBox *paned_box,
   g_return_if_fail (GIMP_IS_PANED_BOX (paned_box));
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
+  GIMP_LOG (DND, "Removing GtkWidget %p from GimpPanedBox %p", widget, paned_box);
+
   /* Calculate length and index */
   old_length = g_list_length (paned_box->p->widgets);
   index      = g_list_index (paned_box->p->widgets, widget);
@@ -252,6 +530,9 @@ gimp_paned_box_remove_widget (GimpPanedBox *paned_box,
   /* Remove from list */
   paned_box->p->widgets = g_list_remove (paned_box->p->widgets, widget);
 
+  /* Reset the drag events hook */
+  gimp_paned_box_set_widget_drag_handler (widget, paned_box);
+
   /* Remove from widget hierarchy */
   if (old_length == 1)
     {
@@ -289,48 +570,85 @@ gimp_paned_box_remove_widget (GimpPanedBox *paned_box,
     }
 }
 
-void
-gimp_paned_box_show_separators (GimpPanedBox *paned_box,
-                                gboolean      show)
+/**
+ * gimp_paned_box_will_handle_drag:
+ * @paned_box: A #GimpPanedBox
+ * @widget:    The widget that got the drag event
+ * @context:   Context from drag event
+ * @x:         x from drag event
+ * @y:         y from drag event
+ * @time:      time from drag event
+ *
+ * Returns: %TRUE if the drag event on @widget will be handled by
+ *          @paned_box.
+ **/
+gboolean
+gimp_paned_box_will_handle_drag (GimpPanedBox   *paned_box,
+                                 GtkWidget      *widget,
+                                 GdkDragContext *context,
+                                 gint            x,
+                                 gint            y,
+                                 gint            time)
 {
-  if (show)
+  gint           paned_box_x = 0;
+  gint           paned_box_y = 0;
+  GtkAllocation  allocation  = { 0, };
+  GtkOrientation orientation = 0;
+  gboolean       will_handle = FALSE;
+
+  g_return_val_if_fail (paned_box == NULL ||
+                        GIMP_IS_PANED_BOX (paned_box), FALSE);
+
+  /* Check for NULL to allow cleaner client code */
+  if (paned_box == NULL)
+    return FALSE;
+
+  /* Our handler might handle it */
+  if (gimp_paned_box_will_handle_drag (paned_box->p->drag_handler,
+                                       widget,
+                                       context,
+                                       x, y,
+                                       time))
+    {
+      /* Return TRUE so the client will pass on the drag event */
+      return TRUE;
+    }
+
+  /* If we don't have a common ancenstor we will not handle it */
+  if (! gtk_widget_translate_coordinates (widget,
+                                          GTK_WIDGET (paned_box),
+                                          x, y,
+                                          &paned_box_x, &paned_box_y))
     {
-      gtk_widget_show (paned_box->p->first_separator);
+      /* Return FALSE so the client can take care of the drag event */
+      return FALSE;
+    }
 
-      /* Only show the south separator if there are any widgets */
-      if (g_list_length (paned_box->p->widgets) > 0)
-        gtk_widget_show (paned_box->p->last_separator);
+  /* We now have paned_box coordinates, see if the paned_box will
+   * handle the event
+   */
+  gtk_widget_get_allocation (GTK_WIDGET (paned_box), &allocation);
+
+  orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (paned_box));
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      will_handle = (paned_box_x < DROP_AREA_SIZE ||
+                     paned_box_x > allocation.width - DROP_AREA_SIZE);
     }
-  else /* (! show) */
+  else /*if (orientation = GTK_ORIENTATION_VERTICAL)*/
     {
-      /* Hide separators unconditionally so we can handle the case
-       * where we remove the last dockbook while separators are shown
-       */
-      gtk_widget_hide (paned_box->p->first_separator);
-      gtk_widget_hide (paned_box->p->last_separator);
+      will_handle = (paned_box_y < DROP_AREA_SIZE ||
+                     paned_box_y > allocation.height - DROP_AREA_SIZE);
     }
-}
 
+  return will_handle;
+}
 
-/**
- * gimp_dock_class_show_separators:
- * @klass:
- * @show:
- *
- * Show/hide the separators in all docks.
- **/
 void
-gimp_paned_box_class_show_separators (GimpPanedBoxClass *klass,
-                                      gboolean           show)
+gimp_paned_box_set_drag_handler (GimpPanedBox *paned_box,
+                                 GimpPanedBox *drag_handler)
 {
-  GList *list;
-
-  /* Conceptually this is a class varaible */
-  g_return_if_fail (GIMP_IS_PANED_BOX_CLASS (klass));
+  g_return_if_fail (GIMP_IS_PANED_BOX (paned_box));
 
-  for (list = paned_box_instances; list != NULL; list = list->next)
-    {
-      GimpPanedBox *paned_box = GIMP_PANED_BOX (list->data);
-      gimp_paned_box_show_separators (paned_box, show);
-    }
+  paned_box->p->drag_handler = drag_handler;
 }
diff --git a/app/widgets/gimppanedbox.h b/app/widgets/gimppanedbox.h
index 6fd1782..0f07e5e 100644
--- a/app/widgets/gimppanedbox.h
+++ b/app/widgets/gimppanedbox.h
@@ -54,21 +54,25 @@ struct _GimpPanedBoxClass
 
 
 GType               gimp_paned_box_get_type              (void) G_GNUC_CONST;
-GtkWidget         * gimp_paned_box_new                   (gboolean                      homogeneous,
-                                                          gint                          spacing,
-                                                          GtkOrientation                orientation);
-void                gimp_paned_box_set_dropped_cb        (GimpPanedBox                 *paned_box,
-                                                          GimpDockSeparatorDroppedFunc  dropped_cb,
-                                                          gpointer                      dropped_cb_data);
-void                gimp_paned_box_add_widget            (GimpPanedBox                 *paned_box,
-                                                          GtkWidget                    *widget,
-                                                          gint                          index);
-void                gimp_paned_box_remove_widget         (GimpPanedBox                 *paned_box,
-                                                          GtkWidget                    *widget);
-void                gimp_paned_box_show_separators       (GimpPanedBox                 *dock,
-                                                          gboolean                      show);
-void                gimp_paned_box_class_show_separators (GimpPanedBoxClass            *klass,
-                                                          gboolean                      show);
+GtkWidget         * gimp_paned_box_new                   (gboolean                 homogeneous,
+                                                          gint                     spacing,
+                                                          GtkOrientation           orientation);
+void                gimp_paned_box_set_dropped_cb        (GimpPanedBox            *paned_box,
+                                                          GimpPanedBoxDroppedFunc  dropped_cb,
+                                                          gpointer                 dropped_cb_data);
+void                gimp_paned_box_add_widget            (GimpPanedBox            *paned_box,
+                                                          GtkWidget               *widget,
+                                                          gint                     index);
+void                gimp_paned_box_remove_widget         (GimpPanedBox            *paned_box,
+                                                          GtkWidget               *widget);
+gboolean            gimp_paned_box_will_handle_drag      (GimpPanedBox            *paned_box,
+                                                          GtkWidget               *widget,
+                                                          GdkDragContext          *context,
+                                                          gint                     x,
+                                                          gint                     y,
+                                                          gint                     time);
+void                gimp_paned_box_set_drag_handler      (GimpPanedBox            *paned_box,
+                                                          GimpPanedBox            *drag_handler);
 
 
 #endif /* __GIMP_PANED_BOX_H__ */
diff --git a/app/widgets/gimptoolbox.c b/app/widgets/gimptoolbox.c
index c097b13..571c0fe 100644
--- a/app/widgets/gimptoolbox.c
+++ b/app/widgets/gimptoolbox.c
@@ -668,33 +668,11 @@ gimp_toolbox_get_vbox (GimpToolbox *toolbox)
 static void
 toolbox_separator_expand (GimpToolbox *toolbox)
 {
-  GimpDock  *dock = GIMP_DOCK (toolbox);
-  GList     *children;
-  GtkWidget *separator;
-
-  children = gtk_container_get_children (GTK_CONTAINER (gimp_dock_get_vbox (dock)));
-  separator = children->data;
-  g_list_free (children);
-
-  gtk_box_set_child_packing (GTK_BOX (gimp_dock_get_vbox (dock)), separator,
-                             TRUE, TRUE, 0, GTK_PACK_START);
-  gimp_dock_separator_set_show_label (GIMP_DOCK_SEPARATOR (separator), TRUE);
 }
 
 static void
 toolbox_separator_collapse (GimpToolbox *toolbox)
 {
-  GimpDock  *dock = GIMP_DOCK (toolbox);
-  GList     *children;
-  GtkWidget *separator;
-
-  children = gtk_container_get_children (GTK_CONTAINER (gimp_dock_get_vbox (dock)));
-  separator = children->data;
-  g_list_free (children);
-
-  gtk_box_set_child_packing (GTK_BOX (gimp_dock_get_vbox (dock)), separator,
-                             FALSE, FALSE, 0, GTK_PACK_START);
-  gimp_dock_separator_set_show_label (GIMP_DOCK_SEPARATOR (separator), FALSE);
 }
 
 static void
diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h
index 188ebde..9c4c817 100644
--- a/app/widgets/widgets-types.h
+++ b/app/widgets/widgets-types.h
@@ -259,8 +259,8 @@ typedef void     (* GimpMenuPositionFunc)         (GtkMenu         *menu,
                                                    gint            *x,
                                                    gint            *y,
                                                    gpointer         data);
-typedef gboolean (* GimpDockSeparatorDroppedFunc) (GimpDockSeparator *separator,
-                                                   GtkWidget         *source,
+typedef gboolean (* GimpPanedBoxDroppedFunc)      (GtkWidget         *source,
+                                                   gint               insert_index,
                                                    gpointer           data);
 
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]