[glade/dnd-cleanup] Drag&Drop clean up.



commit aa0d712d1a67a479be9724ead1a80ca37b61647b
Author: Juan Pablo Ugarte <juanpablougarte gmail com>
Date:   Wed Jul 17 17:54:16 2013 -0300

    Drag&Drop clean up.
    
    Added GladeDrag interface. (currently only used internaly un gladeui)
    
    Implemented GladeDrag in GladePlaceholder GladeWidget and GladeDesignLayout
    
    Added drag-dest property to GladeWidget to enable/disable drag support
    (used in GtkFixed GtkLayout and GtkOverlay containers)
    
    Made GladeInspector a drag source by implementing GtkTreeDragSource interface in GladeProject

 gladeui/Makefile.am                   |    8 +-
 gladeui/glade-design-layout.c         |  140 +---------
 gladeui/glade-design-private.h        |   16 +-
 gladeui/glade-design-view.c           |  494 +++++++++++++--------------------
 gladeui/glade-design-view.h           |    3 -
 gladeui/glade-dnd.c                   |  196 +++++++++++++
 gladeui/glade-dnd.h                   |   55 ++++
 gladeui/glade-drag.c                  |   86 ++++++
 gladeui/glade-drag.h                  |   76 +++++
 gladeui/glade-inspector.c             |    6 +
 gladeui/glade-palette.c               |   36 ++--
 gladeui/glade-placeholder.c           |  254 ++++++++++++-----
 gladeui/glade-project.c               |   48 +++-
 gladeui/glade-widget.c                |  165 +++++++++++-
 gladeui/glade-widget.h                |    5 +
 plugins/gtk+/glade-gtk-fixed-layout.c |    4 +
 plugins/gtk+/glade-gtk-overlay.c      |    6 +-
 src/glade-window.c                    |    2 -
 18 files changed, 1058 insertions(+), 542 deletions(-)
---
diff --git a/gladeui/Makefile.am b/gladeui/Makefile.am
index 88b143b..230efda 100644
--- a/gladeui/Makefile.am
+++ b/gladeui/Makefile.am
@@ -121,7 +121,9 @@ libgladeui_2_la_SOURCES = \
        glade-widget.c \
        glade-widget-action.c \
        glade-widget-adaptor.c \
-       glade-xml-utils.c
+       glade-xml-utils.c \
+       glade-drag.c \
+       glade-dnd.c
 
 libgladeui_2_la_CPPFLAGS =  \
        $(common_defines)   \
@@ -189,7 +191,9 @@ noinst_HEADERS = \
        glade-preview.h \
        glade-preview-tokens.h \
        glade-project-properties.h \
-       gladeui-resources.h
+       gladeui-resources.h \
+       glade-drag.h \
+       glade-dnd.h
 
 if PLATFORM_WIN32
 libgladeui_2_la_LDFLAGS += -no-undefined
diff --git a/gladeui/glade-design-layout.c b/gladeui/glade-design-layout.c
index 188ad77..10bfc02 100644
--- a/gladeui/glade-design-layout.c
+++ b/gladeui/glade-design-layout.c
@@ -110,7 +110,6 @@ struct _GladeDesignLayoutPrivate
 
   /* Drag & Drop */
   GtkWidget *drag_source;
-  GtkWidget *drag_icon;
   gint drag_x, drag_y;
 
   /* Properties */
@@ -382,9 +381,9 @@ glade_design_layout_motion_notify_event (GtkWidget *widget, GdkEventMotion *ev)
       static GtkTargetList *target = NULL;
 
       if (target == NULL)
-        target = gtk_target_list_new (_glade_design_layout_get_dnd_target (), 1);
+        target = gtk_target_list_new (_glade_dnd_get_target (), 1);
 
-      gtk_drag_begin (widget, target, GDK_ACTION_COPY, 1, (GdkEvent*)ev);
+      gtk_drag_begin (widget, target, 0, 1, (GdkEvent*)ev);
       return TRUE;
     }
 
@@ -1945,121 +1944,24 @@ glade_design_layout_finalize (GObject *object)
   G_OBJECT_CLASS (glade_design_layout_parent_class)->finalize (object);
 }
 
-static gboolean
-on_drag_icon_draw (GtkWidget *widget, cairo_t *cr)
-{
-  GtkStyleContext *context = gtk_widget_get_style_context (widget);
-  cairo_pattern_t *gradient;
-  GtkAllocation alloc;
-  gint x, y, w, h;
-  gdouble h2;
-  GdkRGBA bg;
-
-  /* Not needed acording to GtkWidget:draw documentation
-   * But seems like there is a bug when used as a drag_icon that makes the
-   * cairo translation used here persist when drawind children.
-   */
-  cairo_save (cr);
-
-  /* Clear BG */
-  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
-  cairo_paint (cr);
-  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
-  
-  gtk_widget_get_allocation (widget, &alloc);
-  x = alloc.x;
-  y = alloc.y;
-  w = alloc.width;
-  h = alloc.height;
-  h2 = h/2.0;
-
-  gtk_style_context_get_background_color (context, GTK_STATE_NORMAL, &bg);
-
-  gradient = cairo_pattern_create_linear (x, y, x, y+h);
-  cairo_pattern_add_color_stop_rgba (gradient, 0, bg.red, bg.green, bg.blue, 0);
-  cairo_pattern_add_color_stop_rgba (gradient, .5, bg.red, bg.green, bg.blue, .8);
-  cairo_pattern_add_color_stop_rgba (gradient, 1, bg.red, bg.green, bg.blue, 0);
-
-  cairo_set_source (cr, gradient);
-  cairo_rectangle (cr, x+h2, y, w-h, h);
-  cairo_fill (cr);
-  cairo_pattern_destroy (gradient);
-
-  gradient = cairo_pattern_create_radial (x+h2, y+h2, 0, x+h2, y+h2, h2);
-  cairo_pattern_add_color_stop_rgba (gradient, 0, bg.red, bg.green, bg.blue, .8);
-  cairo_pattern_add_color_stop_rgba (gradient, 1, bg.red, bg.green, bg.blue, 0);
-
-  cairo_set_source (cr, gradient);
-  cairo_rectangle (cr, x, y, h2, h);
-  cairo_fill (cr);
-
-  cairo_translate (cr, w-h, 0);
-  cairo_set_source (cr, gradient);
-  cairo_rectangle (cr, x+h2, y, h2, h);
-  cairo_fill (cr);
-  
-  cairo_pattern_destroy (gradient);
-  cairo_restore (cr);
-
-  return FALSE;
-}
-
-GtkWidget *
-_glade_design_layout_dnd_icon_widget_new (GdkDragContext *context,
-                                          const gchar *icon_name,
-                                          const gchar *description)
-{
-  GtkWidget *window, *box, *label, *icon;
-  GdkScreen *screen;
-  GdkVisual *visual;
-
-  screen = gdk_window_get_screen (gdk_drag_context_get_source_window (context));
-  visual = gdk_screen_get_rgba_visual (screen);
-  window = gtk_window_new (GTK_WINDOW_POPUP);
-  
-  gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DND);
-  gtk_window_set_screen (GTK_WINDOW (window), screen);
-  gtk_widget_set_visual (window, visual);
-
-  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
-  gtk_container_set_border_width (GTK_CONTAINER (box), 12);
-
-  icon = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
-  gtk_widget_set_opacity (icon, .8);
-  
-  label = gtk_label_new (description);
-
-  gtk_box_pack_start (GTK_BOX (box), icon, FALSE, TRUE, 0);
-  gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
-
-  gtk_widget_show_all (box);
-  gtk_container_add (GTK_CONTAINER (window), box);
-
-  gtk_widget_set_app_paintable (window, TRUE);
-  g_signal_connect (window, "draw", G_CALLBACK (on_drag_icon_draw), NULL);
-
-  return window;
-}
-
 static void
 glade_design_layout_drag_begin (GtkWidget *widget, GdkDragContext *context)
 {
   GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget);
   GladeWidgetAdaptor *adaptor;
   GladeWidget *gwidget;
-  const gchar *icon_name;
   gchar *description;
 
   gwidget = glade_widget_get_from_gobject (priv->drag_source);
   adaptor = glade_widget_get_adaptor (gwidget);
-  icon_name = glade_widget_adaptor_get_icon_name (adaptor);
   description = g_strdup_printf ("%s [%s]",
                                  glade_widget_adaptor_get_name (adaptor),
                                  glade_widget_get_name (gwidget));
 
-  priv->drag_icon = _glade_design_layout_dnd_icon_widget_new (context, icon_name, description);
-  g_object_ref_sink (priv->drag_icon);
-  gtk_drag_set_icon_widget (context, priv->drag_icon, 0, 0);
+  _glade_dnd_set_icon_widget (context,
+                              glade_widget_adaptor_get_icon_name (adaptor),
+                              description);
+  
   g_free (description);
 }
 
@@ -2071,25 +1973,13 @@ glade_design_layout_drag_data_get (GtkWidget        *widget,
                                    guint             time)
 {
   GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget);
-
-  if (priv->drag_source)
-    {
-      static GdkAtom type = 0;
-
-      if (!type)
-        type = gdk_atom_intern_static_string (GDL_DND_TARGET_WIDGET);
-
-      gtk_selection_data_set (data, type, sizeof (gpointer),
-                              (const guchar *)&priv->drag_source, sizeof (gpointer));
-    }
+  _glade_dnd_set_data (data, G_OBJECT (priv->drag_source));
 }
 
 static void
 glade_design_layout_drag_end (GtkWidget *widget, GdkDragContext *context)
 {
   GladeDesignLayoutPrivate *priv = GLADE_DESIGN_LAYOUT_PRIVATE (widget);
-
-  g_clear_object (&priv->drag_icon);
   priv->drag_source = NULL;
 }
 
@@ -2278,13 +2168,6 @@ _glade_design_layout_get_colors (GtkStyleContext *context,
   c1->blue += off;
 }
 
-GtkTargetEntry *
-_glade_design_layout_get_dnd_target (void)
-{
-  static GtkTargetEntry target = {GDL_DND_TARGET_WIDGET, GTK_TARGET_SAME_APP, GDL_DND_INFO_WIDGET};
-  return &target;
-}
-
 void
 _glade_design_layout_get_hot_point (GladeDesignLayout *layout,
                                     gint *x,
@@ -2353,7 +2236,8 @@ gdl_drag_source_check (GladeDesignLayout *layout,
       GObject *source;
 
       if (gwidget && (source = glade_widget_get_object (gwidget)) &&
-          !(event->button.state & GDK_SHIFT_MASK))
+          !(event->button.state & GDK_SHIFT_MASK) &&
+          glade_drag_can_drag (GLADE_DRAG (gwidget)))
         {
           priv->drag_source = GTK_WIDGET (source);
 
@@ -2372,6 +2256,12 @@ gdl_drag_source_check (GladeDesignLayout *layout,
     }
 }
 
+GladeWidget *
+_glade_design_layout_get_child (GladeDesignLayout *layout)
+{
+  return layout->priv->gchild;
+}
+
 /*
  * _glade_design_layout_do_event:
  * @layout: A #GladeDesignLayout
diff --git a/gladeui/glade-design-private.h b/gladeui/glade-design-private.h
index c883312..765a09c 100644
--- a/gladeui/glade-design-private.h
+++ b/gladeui/glade-design-private.h
@@ -25,11 +25,9 @@
 #ifndef __GLADE_DESIGN_PRIVATE_H__
 #define __GLADE_DESIGN_PRIVATE_H__
 
-#define GDL_DND_INFO_WIDGET 15956
-#define GDL_DND_TARGET_WIDGET "glade/x-widget"
-
 #include "glade-design-view.h"
 #include "glade-design-layout.h"
+#include "glade-dnd.h"
 
 G_BEGIN_DECLS
 
@@ -53,15 +51,11 @@ void _glade_design_layout_draw_pushpin (cairo_t *cr,
                                         GdkRGBA *bg,
                                         GdkRGBA *fg);
 
-void            _glade_design_layout_get_hot_point (GladeDesignLayout *layout,
-                                                    gint *x,
-                                                    gint *y);
-
-GtkTargetEntry *_glade_design_layout_get_dnd_target (void);
+void _glade_design_layout_get_hot_point (GladeDesignLayout *layout,
+                                         gint *x,
+                                         gint *y);
 
-GtkWidget *_glade_design_layout_dnd_icon_widget_new (GdkDragContext *context,
-                                                     const gchar *icon_name,
-                                                     const gchar *description);
+GladeWidget * _glade_design_layout_get_child (GladeDesignLayout *layout);
 
 G_END_DECLS
 
diff --git a/gladeui/glade-design-view.c b/gladeui/glade-design-view.c
index d696d31..72e0b66 100644
--- a/gladeui/glade-design-view.c
+++ b/gladeui/glade-design-view.c
@@ -35,6 +35,7 @@
 #include "config.h"
 
 #include "glade.h"
+#include "glade-dnd.h"
 #include "glade-utils.h"
 #include "glade-design-view.h"
 #include "glade-design-layout.h"
@@ -51,8 +52,7 @@
 enum
 {
   PROP_0,
-  PROP_PROJECT,
-  PROP_DRAG_SOURCE
+  PROP_PROJECT
 };
 
 struct _GladeDesignViewPrivate
@@ -61,15 +61,18 @@ struct _GladeDesignViewPrivate
   GtkWidget *scrolled_window;  /* Main scrolled window */
   GtkWidget *layout_box;       /* Box to pack a GladeDesignLayout for each toplevel in project */
 
-  GtkToolPalette *palette;
-  GladeWidgetAdaptor *drag_adaptor;
-  GtkWidget *drag_source;
-  GtkWidget *drag_target;
+  GladeDrag *drag_target;
+  GObject *drag_data;
+  gboolean drag_highlight;
 };
 
 static GtkVBoxClass *parent_class = NULL;
 
-G_DEFINE_TYPE (GladeDesignView, glade_design_view, GTK_TYPE_BOX)
+static void glade_design_view_drag_init (GladeDragInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GladeDesignView, glade_design_view, GTK_TYPE_BOX,
+                         G_IMPLEMENT_INTERFACE (GLADE_TYPE_DRAG,
+                                                glade_design_view_drag_init))
 
 static void
 glade_design_layout_scroll (GladeDesignView *view, gint x, gint y, gint w, gint h)
@@ -275,10 +278,6 @@ glade_design_view_set_property (GObject *object,
         glade_design_view_set_project (GLADE_DESIGN_VIEW (object),
                                        g_value_get_object (value));
         break;
-      case PROP_DRAG_SOURCE:
-        glade_design_view_set_drag_source (GLADE_DESIGN_VIEW (object),
-                                           GTK_TOOL_PALETTE (g_value_get_object (value)));
-        break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
@@ -296,9 +295,6 @@ glade_design_view_get_property (GObject *object,
       case PROP_PROJECT:
         g_value_set_object (value, GLADE_DESIGN_VIEW (object)->priv->project);
         break;
-      case PROP_DRAG_SOURCE:
-        g_value_set_object (value, GLADE_DESIGN_VIEW (object)->priv->palette);
-        break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
@@ -334,20 +330,37 @@ glade_design_view_draw (GtkWidget *widget, cairo_t *cr)
 {
   GladeDesignViewPrivate *priv = GLADE_DESIGN_VIEW_GET_PRIVATE (widget);
   GdkWindow *window = gtk_widget_get_window (widget);
+  gboolean should_draw = gtk_cairo_should_draw_window (cr, window);
+  gboolean sw_visible = gtk_widget_get_visible (priv->scrolled_window);
 
-  if (gtk_cairo_should_draw_window (cr, window))
+  if (should_draw)
     {
-      if (gtk_widget_get_visible (priv->scrolled_window) == FALSE)
-        logo_draw (widget, cr);
-      else
+      if (sw_visible)
         gtk_render_background (gtk_widget_get_style_context (widget),
-                               cr,
-                               0, 0,
-                               gdk_window_get_width (window),
-                               gdk_window_get_height (window));
+                               cr, 0, 0,
+                               gtk_widget_get_allocated_width (widget),
+                               gtk_widget_get_allocated_height (widget));
+      else
+        logo_draw (widget, cr);
     }
 
   GTK_WIDGET_CLASS (glade_design_view_parent_class)->draw (widget, cr);
+
+  if (should_draw && sw_visible && priv->drag_highlight)
+    {
+      GtkStyleContext *context = gtk_widget_get_style_context (widget);
+      GdkRGBA c;
+
+      gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED |
+                                              GTK_STATE_FLAG_FOCUSED, &c);
+
+      cairo_set_line_width (cr, 2);
+      gdk_cairo_set_source_rgba (cr, &c);
+      cairo_rectangle (cr, 0, 0,
+                       gtk_widget_get_allocated_width (widget),
+                       gtk_widget_get_allocated_height (widget));
+      cairo_stroke (cr);
+    }
   
   return FALSE;
 }
@@ -388,6 +401,8 @@ glade_design_view_init (GladeDesignView *view)
 
   gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (view)),
                                GTK_STYLE_CLASS_VIEW);
+
+  _glade_dnd_dest_set (GTK_WIDGET (view));
 }
 
 static void
@@ -400,120 +415,30 @@ glade_design_view_finalize (GObject *object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-static GtkWidget *
-widget_get_child_from_position (GtkWidget *toplevel, GtkWidget *widget, gint x, gint y)
-{
-  GtkWidget *retval = NULL;
-  GList *children, *l;
-
-  if (!GTK_IS_CONTAINER (widget))
-    return NULL;
-
-  children = glade_util_container_get_all_children (GTK_CONTAINER (widget));
-  
-  for (l = children;l; l = g_list_next (l))
-    {
-      GtkWidget *child = l->data;
-
-      if (gtk_widget_get_mapped (child))
-        {
-          GtkAllocation alloc;
-          gint xx, yy;
-
-          gtk_widget_translate_coordinates (toplevel, child, x, y, &xx, &yy);
-          gtk_widget_get_allocation (child, &alloc);
-          
-          if (xx >= 0 && yy >= 0 && xx <= alloc.width && yy <= alloc.height)
-            {
-              if (GTK_IS_CONTAINER (child))
-                retval = widget_get_child_from_position (toplevel, child, x, y);
-
-              if (!retval)
-                retval = child;
-
-              break;
-            }
-        }
-    }
-  
-  g_list_free (children);
-
-  return retval;
-}
-
-static GtkWidget *
-widget_get_gchild_from_position (GtkWidget *toplevel, GtkWidget *widget, gint x, gint y)
+typedef struct
 {
-  GtkWidget *retval = widget_get_child_from_position (toplevel, widget, x, y);
-
-  while (retval)
-    {
-      if (retval == toplevel || GLADE_IS_PLACEHOLDER (retval) ||
-          glade_widget_get_from_gobject (retval))
-        return retval;
-
-      retval = gtk_widget_get_parent (retval);
-    }
-
-  return NULL;
-}
+  GtkWidget *child;
+  gint x, y;
+} FindInContainerData;
 
-static gboolean
-drag_highlight_draw (GtkWidget *widget, cairo_t *cr, GladeDesignView *view)
+static void
+find_inside_container (GtkWidget *widget, FindInContainerData *data)
 {
-  GtkStyleContext *context;
-  gint width, height;
-  GdkRGBA c;
-
-  context = gtk_widget_get_style_context (GTK_WIDGET (view));
-  width = gtk_widget_get_allocated_width (widget);
-  height = gtk_widget_get_allocated_height (widget);
-
-  gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED |
-                                          GTK_STATE_FLAG_FOCUSED, &c);
-
-  if (GLADE_IS_PLACEHOLDER (widget))
-    {
-      cairo_pattern_t *gradient;
-      gdouble w, h;
-
-      w = gtk_widget_get_allocated_width (widget)/2.0;
-      h = gtk_widget_get_allocated_height (widget)/2.0;
-      gradient = cairo_pattern_create_radial (w, h, MIN (width, height)/6,
-                                              w, h, MAX (w, h));
-      cairo_pattern_add_color_stop_rgba (gradient, 0, c.red, c.green, c.blue, .08);
-      cairo_pattern_add_color_stop_rgba (gradient, 1, c.red, c.green, c.blue, .28);
+  GtkAllocation alloc;
+  gint x, y;
 
-      cairo_set_source (cr, gradient);
+  if (data->child || !gtk_widget_get_mapped (widget))
+    return;
 
-      cairo_rectangle (cr, 0, 0, width, height);
-      cairo_fill (cr);
+  x = data->x;
+  y = data->y;
+  gtk_widget_get_allocation (widget, &alloc);
 
-      cairo_pattern_destroy (gradient);
-    }
-  else
+  if (x >= alloc.x && x <= (alloc.x + alloc.width) &&
+      y >= alloc.y && y <= (alloc.y + alloc.height))
     {
-      cairo_set_line_width (cr, 2);
-      gdk_cairo_set_source_rgba (cr, &c);
-      cairo_rectangle (cr, 1, 1, width-2, height-2);
-      cairo_stroke (cr);
+      data->child = widget;
     }
-
-  return FALSE;
-}
-
-static void
-glade_design_view_drag_highlight (GladeDesignView *view, GtkWidget *widget)
-{
-  g_signal_connect_after (widget, "draw", G_CALLBACK (drag_highlight_draw), view);
-  gtk_widget_queue_draw (widget);
-}
-
-static void 
-glade_design_view_drag_unhighlight (GladeDesignView *view, GtkWidget *widget)
-{
-  g_signal_handlers_disconnect_by_func (widget, drag_highlight_draw, view);
-  gtk_widget_queue_draw (widget);
 }
 
 static gboolean
@@ -522,13 +447,12 @@ glade_design_view_drag_motion (GtkWidget *widget,
                                gint x, gint y,
                                guint time)
 {
-  GladeDesignViewPrivate *priv = GLADE_DESIGN_VIEW (widget)->priv;
-  GdkDragAction drag_action = GDK_ACTION_COPY;
-  GtkWidget *child;
-
-  child = widget_get_gchild_from_position (widget, widget, x, y);
+  GladeDesignView *view = GLADE_DESIGN_VIEW (widget);
+  GladeDesignViewPrivate *priv = view->priv;
+  FindInContainerData data;
+  GladeDrag *drag = NULL;
   
-  if (!(priv->drag_adaptor || priv->drag_source))
+  if (!priv->drag_data)
     {
       GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
 
@@ -536,78 +460,90 @@ glade_design_view_drag_motion (GtkWidget *widget,
         gtk_drag_get_data (widget, context, target, time);
     }
 
-  if (child)
-    {
-      GladeWidget *gwidget;
-
-      if (priv->drag_source &&
-          (priv->drag_source == child || gtk_widget_is_ancestor (child, priv->drag_source) ||
-           (!GLADE_IS_PLACEHOLDER (child) && 
-            !GTK_IS_FIXED (child) && !GTK_IS_LAYOUT (child) &&
-            (glade_widget_get_from_gobject (child) ||
-             ((gwidget = glade_widget_get_from_gobject (priv->drag_source)) &&
-             !glade_widget_get_parent (gwidget)
-            ))
-         )))
-        drag_action = 0;
-
-      if (priv->drag_adaptor &&
-          ((GLADE_IS_PLACEHOLDER (child) && GWA_IS_TOPLEVEL (priv->drag_adaptor)) ||
-           (!GLADE_IS_PLACEHOLDER (child) && !GTK_IS_FIXED (child) && !GTK_IS_LAYOUT (child) &&
-            glade_widget_get_from_gobject (child))))
-        drag_action = 0;
-    }
-  else
-    drag_action = 0;
-  
-  gdk_drag_status (context, drag_action, time);
+  data.child = NULL;
+  gtk_widget_translate_coordinates (widget, GTK_WIDGET (priv->layout_box),
+                                    x, y, &data.x, &data.y);
+  gtk_container_forall (GTK_CONTAINER (priv->layout_box),
+                        (GtkCallback) find_inside_container,
+                        &data);
 
-  if (priv->drag_target != child)
+  if (data.child)
     {
-      if (priv->drag_target)
-        {
-          glade_design_view_drag_unhighlight (GLADE_DESIGN_VIEW (widget),
-                                              priv->drag_target);
-          priv->drag_target = NULL;
-        }
+      GladeWidget *gchild = _glade_design_layout_get_child (GLADE_DESIGN_LAYOUT (data.child));
+      GtkWidget *child = GTK_WIDGET (glade_widget_get_object (gchild));
+      GtkWidget *drag_target;
+
+      gint xx, yy;
 
-      if (drag_action == GDK_ACTION_COPY)
+      gtk_widget_translate_coordinates (widget, child, x, y, &xx, &yy);
+      
+      drag_target = glade_widget_get_child_at_position (gchild, xx, yy);
+
+      if (drag_target)
         {
-          glade_design_view_drag_highlight (GLADE_DESIGN_VIEW (widget), child);
-          priv->drag_target = child;
+          GladeWidget *gwidget;
+
+          if (GLADE_IS_PLACEHOLDER (drag_target))
+            drag = GLADE_DRAG (drag_target);
+          else if ((gwidget = glade_widget_get_from_gobject (drag_target)))
+            {
+              while (gwidget && !glade_widget_get_drag_dest (gwidget))
+                gwidget = glade_widget_get_parent (gwidget);
+
+              if (gwidget)
+                drag = GLADE_DRAG (gwidget);
+            }
         }
     }
+  else
+    {
+      drag = GLADE_DRAG (widget);
+    }
+
+  if (priv->drag_target && priv->drag_target != drag)
+    {
+      glade_drag_highlight (priv->drag_target, FALSE);
+      g_clear_object (&priv->drag_target);
+    }
   
-  return drag_action != 0;
+  if (drag && glade_drag_can_drop (drag, priv->drag_data))
+    {
+      priv->drag_target = g_object_ref (drag);
+      glade_drag_highlight (drag, TRUE);
+      
+      gdk_drag_status (context, GDK_ACTION_COPY, time);
+      return TRUE;
+    }
+
+  gdk_drag_status (context, 0, time);
+  return FALSE;
 }
 
 static void
 glade_design_view_drag_leave (GtkWidget      *widget,
-                              GdkDragContext *drag_context,
+                              GdkDragContext *context,
                               guint           time)
 {
   GladeDesignViewPrivate *priv = GLADE_DESIGN_VIEW (widget)->priv;
 
   if (priv->drag_target)
-    {
-      glade_design_view_drag_unhighlight (GLADE_DESIGN_VIEW (widget),
-                                          priv->drag_target);
-      priv->drag_target = NULL;
-    }
+    glade_drag_highlight (priv->drag_target, FALSE);
 }
 
 static void
-on_drag_item_drag_end (GtkWidget *widget,
-                       GdkDragContext *context, 
-                       GladeDesignView *view)
+on_source_drag_end (GtkWidget       *widget,
+                    GdkDragContext  *context, 
+                    GladeDesignView *view)
 {
   GladeDesignViewPrivate *priv = view->priv;
-
-  priv->drag_adaptor = NULL;
-  priv->drag_source = NULL;
-  priv->drag_target = NULL;
   
-  g_signal_handlers_disconnect_by_func (widget, on_drag_item_drag_end, view);
+  if (priv->drag_target)
+    {
+      glade_drag_highlight (priv->drag_target, FALSE);
+      g_clear_object (&priv->drag_target);
+    }
+
+  g_clear_object (&priv->drag_data);
 }
 
 static void
@@ -619,34 +555,19 @@ glade_design_view_drag_data_received (GtkWidget        *widget,
                                       guint             info,
                                       guint             time)
 {
-  GladeDesignViewPrivate *priv = GLADE_DESIGN_VIEW (widget)->priv;
-  GdkAtom target = gtk_selection_data_get_target (selection);
-  const GtkTargetEntry *palette_target;
+  GtkWidget *source = gtk_drag_get_source_widget (context);
+  GladeDesignView *view = GLADE_DESIGN_VIEW (widget);
+  GladeDesignViewPrivate *priv = view->priv;
 
-  if (info == GDL_DND_INFO_WIDGET &&
-      g_strcmp0 (gdk_atom_name (target), GDL_DND_TARGET_WIDGET) == 0)
-    {
-      const guchar *data = gtk_selection_data_get_data (selection);
-      
-      if (data)
-        priv->drag_source = *((GtkWidget **)data);
-    }
-  else if (priv->palette &&
-           (palette_target = gtk_tool_palette_get_drag_target_item ()) &&
-           palette_target->info == info &&
-           g_strcmp0 (gdk_atom_name (target), palette_target->target) == 0)
-    {
-      GtkWidget *item = gtk_tool_palette_get_drag_item (priv->palette, selection);
+  g_signal_handlers_disconnect_by_func (source, on_source_drag_end, view);
 
-      if (item)
-        priv->drag_adaptor = g_object_get_data (G_OBJECT (item), "glade-widget-adaptor");
-    }
-  else
-    return;
+  g_clear_object (&priv->drag_data);
+  priv->drag_data = _glade_dnd_get_data (context, selection, info);
 
-  g_signal_connect (gtk_drag_get_source_widget (context), "drag-end",
-                    G_CALLBACK (on_drag_item_drag_end),
-                    GLADE_DESIGN_VIEW (widget));
+  if (priv->drag_data)
+    g_object_ref (priv->drag_data);
+
+  g_signal_connect_object (source, "drag-end", G_CALLBACK (on_source_drag_end), view, 0);
 }
 
 static gboolean
@@ -657,62 +578,79 @@ glade_design_view_drag_drop (GtkWidget       *widget,
                              guint            time)  
 {
   GladeDesignViewPrivate *priv = GLADE_DESIGN_VIEW (widget)->priv;
-  GtkWidget *child;
 
-  child = widget_get_gchild_from_position (widget, widget, x, y);
-  
-  if (priv->drag_source)
+  if (priv->drag_data && priv->drag_target)
     {
-      GladeWidget *gsource = glade_widget_get_from_gobject (priv->drag_source);
-      GList widgets = {gsource, NULL, NULL};
+      glade_drag_drop (GLADE_DRAG (priv->drag_target), priv->drag_data);
+      gtk_drag_finish (context, TRUE, FALSE, time);
+    }
+  else
+    gtk_drag_finish (context, FALSE, FALSE, time);
 
-      if (GLADE_IS_PLACEHOLDER (child))
-        {
-          GladePlaceholder *placeholder = GLADE_PLACEHOLDER (child);
-          GladeWidget *parent = glade_placeholder_get_parent (placeholder);
+  return TRUE;
+}
 
-          /* Check for recursive paste */
-          if (parent != gsource)
-            glade_command_dnd (&widgets, parent, placeholder);
-        }
-      else if (GTK_IS_FIXED (child) || GTK_IS_LAYOUT (child))
-        {
-          GladeWidget *parent = glade_widget_get_from_gobject (child);
+static gboolean
+glade_design_view_drag_iface_can_drop (GladeDrag *drag, GObject *data)
+{
+  GladeWidget *gwidget;
 
-         glade_command_dnd (&widgets, parent, NULL);
-        }
-      else if (!glade_widget_get_from_gobject (child))
-        glade_command_dnd (&widgets, NULL, NULL);
+  if (GLADE_IS_WIDGET_ADAPTOR (data) ||
+      ((gwidget = glade_widget_get_from_gobject (data)) &&
+       glade_widget_get_parent (gwidget)))
+    return TRUE;
+  else
+    return FALSE;
+}
+
+static gboolean
+glade_design_view_drag_iface_drop (GladeDrag *drag, GObject *data)
+{
+  GladeDesignViewPrivate *priv = GLADE_DESIGN_VIEW (drag)->priv;
+  GladeWidget *gsource;
+
+  if (GLADE_IS_WIDGET_ADAPTOR (data))
+    {
+      glade_command_create (GLADE_WIDGET_ADAPTOR (data),
+                            NULL, NULL, priv->project);
+      return TRUE;
     }
-  else if (child && priv->drag_adaptor)
+  else if ((gsource = glade_widget_get_from_gobject (data)))
     {
-      if (GLADE_IS_PLACEHOLDER (child))
-        {
-          GladePlaceholder *placeholder = GLADE_PLACEHOLDER (child);
+      GList widgets = {gsource, NULL, NULL};
+      glade_command_dnd (&widgets, NULL, NULL);
+      return TRUE;
+    }
 
-          glade_command_create (priv->drag_adaptor,
-                                glade_placeholder_get_parent (placeholder),
-                                placeholder, 
-                                priv->project);
-        }
-      else if (GTK_IS_FIXED (child) || GTK_IS_LAYOUT (child))
-        {
-          GladeWidget *parent = glade_widget_get_from_gobject (child);
+  return FALSE;
+}
 
-          if (parent)
-           glade_command_create (priv->drag_adaptor,
-                                 parent, NULL,
-                                 priv->project);
-        }
-      else
-        {
-          glade_command_create (priv->drag_adaptor, NULL, NULL, priv->project);
-        }
-    }
+static void
+glade_design_view_drag_iface_highlight (GladeDrag *drag, gboolean highlight)
+{
+  GladeDesignViewPrivate *priv = GLADE_DESIGN_VIEW (drag)->priv;
+  GtkWidget *target = priv->scrolled_window;
 
-  gtk_drag_finish (context, TRUE, FALSE, time);
+  if (highlight == priv->drag_highlight)
+    return;
+      
+  priv->drag_highlight = highlight;
+    
+  g_signal_handlers_disconnect_by_func (target, _glade_dnd_highlight_draw, NULL);
+  
+  if (highlight)
+    g_signal_connect_after (target, "draw", G_CALLBACK (_glade_dnd_highlight_draw), NULL);
 
-  return TRUE;
+  gtk_widget_queue_draw (target);
+}
+
+static void
+glade_design_view_drag_init (GladeDragInterface *iface)
+{
+  iface->can_drag = NULL;
+  iface->can_drop = glade_design_view_drag_iface_can_drop;
+  iface->drop = glade_design_view_drag_iface_drop;
+  iface->highlight = glade_design_view_drag_iface_highlight;
 }
 
 static void
@@ -743,19 +681,11 @@ glade_design_view_class_init (GladeDesignViewClass *klass)
                                                         GLADE_TYPE_PROJECT,
                                                         G_PARAM_READWRITE |
                                                         G_PARAM_CONSTRUCT_ONLY));
-  g_object_class_install_property (object_class,
-                                   PROP_DRAG_SOURCE,
-                                   g_param_spec_object ("drag-source",
-                                                        "Drag Source",
-                                                        "A palette to use as the source of drag events for 
this view",
-                                                        GTK_TYPE_TOOL_PALETTE,
-                                                        G_PARAM_READWRITE));
 
   g_type_class_add_private (object_class, sizeof (GladeDesignViewPrivate));
 }
 
 /* Private API */
-
 void
 _glade_design_view_freeze (GladeDesignView *view)
 {
@@ -809,44 +739,4 @@ glade_design_view_get_from_project (GladeProject *project)
   p = g_object_get_data (G_OBJECT (project), GLADE_DESIGN_VIEW_KEY);
 
   return (p != NULL) ? GLADE_DESIGN_VIEW (p) : NULL;
-
-}
-
-void
-glade_design_view_set_drag_source (GladeDesignView *view, GtkToolPalette *source)
-{
-  GladeDesignViewPrivate *priv;
-  GtkWidget *target;
-
-  g_return_if_fail (GLADE_IS_DESIGN_VIEW (view));
-  priv = view->priv;
-
-  if (priv->palette == source)
-    return;
-
-  if (priv->palette)
-    gtk_drag_dest_unset (GTK_WIDGET (priv->palette));
-
-  target = GTK_WIDGET (view);
-  priv->palette = source;
-
-  gtk_drag_dest_set (target, 0, NULL, 0, GDK_ACTION_COPY);
-
-  if (priv->palette)
-    {
-      GtkTargetEntry targets[2];
-      GtkTargetList *list;
-
-      gtk_tool_palette_add_drag_dest (priv->palette, target, 0,
-                                      GTK_TOOL_PALETTE_DRAG_ITEMS,
-                                      GDK_ACTION_COPY);
-
-      targets[0] = *gtk_tool_palette_get_drag_target_item ();
-      targets[1] = *_glade_design_layout_get_dnd_target ();
-
-      list = gtk_target_list_new (targets, 2);
-      gtk_drag_dest_set_target_list (target, list);
-
-      gtk_target_list_unref (list);
-    }
 }
diff --git a/gladeui/glade-design-view.h b/gladeui/glade-design-view.h
index 950ec45..733c748 100644
--- a/gladeui/glade-design-view.h
+++ b/gladeui/glade-design-view.h
@@ -69,9 +69,6 @@ GladeProject      *glade_design_view_get_project      (GladeDesignView *view);
 
 GladeDesignView   *glade_design_view_get_from_project (GladeProject *project);
 
-void               glade_design_view_set_drag_source  (GladeDesignView *view,
-                                                       GtkToolPalette  *source);
-
 G_END_DECLS
 
 #endif /* __GLADE_DESIGN_VIEW_H__ */
diff --git a/gladeui/glade-dnd.c b/gladeui/glade-dnd.c
new file mode 100644
index 0000000..c30f138
--- /dev/null
+++ b/gladeui/glade-dnd.c
@@ -0,0 +1,196 @@
+/*
+ * glade-dnd.c
+ *
+ * Copyright (C) 2013  Juan Pablo Ugarte
+   *
+ * Authors:
+ *   Juan Pablo Ugarte <juanpablougarte gmail com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+   *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glade.h"
+#include "glade-dnd.h"
+
+GtkTargetEntry *
+_glade_dnd_get_target (void)
+{
+  static GtkTargetEntry target = {GLADE_DND_TARGET_DATA, GTK_TARGET_SAME_APP, GLADE_DND_INFO_DATA};
+  return &target;
+}
+
+void
+_glade_dnd_dest_set (GtkWidget *target)
+{
+  GtkTargetEntry targets[1];
+
+  targets[0] = *_glade_dnd_get_target ();
+
+  gtk_drag_dest_set (target, 0, targets, 2, GDK_ACTION_COPY);
+}
+
+GObject *
+_glade_dnd_get_data (GdkDragContext   *context,
+                     GtkSelectionData *selection,
+                     guint             info)
+{
+  GdkAtom target = gtk_selection_data_get_target (selection);
+
+  if (info == GLADE_DND_INFO_DATA &&
+      g_strcmp0 (gdk_atom_name (target), GLADE_DND_TARGET_DATA) == 0)
+    {
+      const guchar *data = gtk_selection_data_get_data (selection);
+      if (data)
+        return *((GObject **)data);
+    }
+  return NULL;
+}
+
+
+void
+_glade_dnd_set_data (GtkSelectionData *selection, GObject *data)
+{
+  static GdkAtom type = 0;
+
+  if (!type)
+    type = gdk_atom_intern_static_string (GLADE_DND_TARGET_DATA);
+
+  gtk_selection_data_set (selection, type, sizeof (gpointer),
+                          (const guchar *)&data,
+                          sizeof (gpointer));
+}
+
+static gboolean
+on_drag_icon_draw (GtkWidget *widget, cairo_t *cr)
+{
+  GtkStyleContext *context = gtk_widget_get_style_context (widget);
+  cairo_pattern_t *gradient;
+  GtkAllocation alloc;
+  gint x, y, w, h;
+  gdouble h2;
+  GdkRGBA bg;
+
+  /* Not needed acording to GtkWidget:draw documentation
+   * But seems like there is a bug when used as a drag_icon that makes the
+   * cairo translation used here persist when drawing children.
+   */
+  cairo_save (cr);
+
+  /* Clear BG */
+  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+  cairo_paint (cr);
+  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+  gtk_widget_get_allocation (widget, &alloc);
+  x = alloc.x;
+  y = alloc.y;
+  w = alloc.width;
+  h = alloc.height;
+  h2 = h/2.0;
+
+  gtk_style_context_get_background_color (context, GTK_STATE_NORMAL, &bg);
+
+  gradient = cairo_pattern_create_linear (x, y, x, y+h);
+  cairo_pattern_add_color_stop_rgba (gradient, 0, bg.red, bg.green, bg.blue, 0);
+  cairo_pattern_add_color_stop_rgba (gradient, .5, bg.red, bg.green, bg.blue, .8);
+  cairo_pattern_add_color_stop_rgba (gradient, 1, bg.red, bg.green, bg.blue, 0);
+
+  cairo_set_source (cr, gradient);
+  cairo_rectangle (cr, x+h2, y, w-h, h);
+  cairo_fill (cr);
+  cairo_pattern_destroy (gradient);
+
+  gradient = cairo_pattern_create_radial (x+h2, y+h2, 0, x+h2, y+h2, h2);
+  cairo_pattern_add_color_stop_rgba (gradient, 0, bg.red, bg.green, bg.blue, .8);
+  cairo_pattern_add_color_stop_rgba (gradient, 1, bg.red, bg.green, bg.blue, 0);
+
+  cairo_set_source (cr, gradient);
+  cairo_rectangle (cr, x, y, h2, h);
+  cairo_fill (cr);
+
+  cairo_translate (cr, w-h, 0);
+  cairo_set_source (cr, gradient);
+  cairo_rectangle (cr, x+h2, y, h2, h);
+  cairo_fill (cr);
+
+  cairo_pattern_destroy (gradient);
+  cairo_restore (cr);
+
+  return FALSE;
+}
+
+void
+_glade_dnd_set_icon_widget (GdkDragContext *context,
+                            const gchar *icon_name,
+                            const gchar *description)
+{
+  GtkWidget *window, *box, *label, *icon;
+  GdkScreen *screen;
+  GdkVisual *visual;
+
+  screen = gdk_window_get_screen (gdk_drag_context_get_source_window (context));
+  window = gtk_window_new (GTK_WINDOW_POPUP);
+
+  gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DND);
+  gtk_window_set_screen (GTK_WINDOW (window), screen);
+
+  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
+  gtk_container_set_border_width (GTK_CONTAINER (box), 12);
+
+  icon = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
+  gtk_widget_set_opacity (icon, .8);
+
+  label = gtk_label_new (description);
+
+  gtk_box_pack_start (GTK_BOX (box), icon, FALSE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
+
+  gtk_widget_show_all (box);
+  gtk_container_add (GTK_CONTAINER (window), box);
+
+  if ((visual = gdk_screen_get_rgba_visual (screen)))
+    {
+      gtk_widget_set_visual (window, visual);
+      gtk_widget_set_app_paintable (window, TRUE);
+      g_signal_connect (window, "draw", G_CALLBACK (on_drag_icon_draw), NULL);
+    }
+
+  g_object_ref_sink (window);
+  gtk_drag_set_icon_widget (context, window, 0, 0);
+  g_object_unref (window);
+}
+
+gboolean
+_glade_dnd_highlight_draw (GtkWidget *widget, cairo_t *cr)
+{
+  GtkStyleContext *context;
+  gint width, height;
+  GdkRGBA c;
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (widget));
+  width = gtk_widget_get_allocated_width (widget);
+  height = gtk_widget_get_allocated_height (widget);
+
+  gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED |
+                                          GTK_STATE_FLAG_FOCUSED, &c);
+
+  cairo_set_line_width (cr, 2);
+  gdk_cairo_set_source_rgba (cr, &c);
+  cairo_rectangle (cr, 1, 1, width-2, height-2);
+  cairo_stroke (cr);
+
+  return FALSE;
+}
diff --git a/gladeui/glade-dnd.h b/gladeui/glade-dnd.h
new file mode 100644
index 0000000..05135ac
--- /dev/null
+++ b/gladeui/glade-dnd.h
@@ -0,0 +1,55 @@
+/*
+ * glade-dnd.h
+ *
+ * Copyright (C) 2013  Juan Pablo Ugarte
+ * 
+ * Authors:
+ *   Juan Pablo Ugarte <juanpablougarte gmail com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GLADE_DND_H__
+#define __GLADE_DND_H__
+
+#define GLADE_DND_INFO_DATA 96323
+#define GLADE_DND_TARGET_DATA "glade/x-drag-data"
+
+#include "glade-drag.h"
+
+G_BEGIN_DECLS
+
+GtkTargetEntry *_glade_dnd_get_target      (void);
+
+void            _glade_dnd_dest_set        (GtkWidget *target);
+
+void            _glade_dnd_set_data        (GtkSelectionData *selection,
+                                            GObject          *data);
+
+GObject        *_glade_dnd_get_data        (GdkDragContext   *context,
+                                            GtkSelectionData *selection,
+                                            guint             info);
+
+void            _glade_dnd_set_icon_widget (GdkDragContext *context,
+                                            const gchar    *icon_name,
+                                            const gchar    *description);
+
+gboolean        _glade_dnd_highlight_draw  (GtkWidget *widget,
+                                            cairo_t   *cr);
+
+G_END_DECLS
+
+#endif /* __GLADE_DND_H__ */
diff --git a/gladeui/glade-drag.c b/gladeui/glade-drag.c
new file mode 100644
index 0000000..f2db33c
--- /dev/null
+++ b/gladeui/glade-drag.c
@@ -0,0 +1,86 @@
+/*
+ * glade-drag.c
+ *
+ * Copyright (C) 2013  Juan Pablo Ugarte
+ *
+ * Authors:
+ *   Juan Pablo Ugarte <juanpablougarte gmail com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glade-drag.h"
+
+G_DEFINE_INTERFACE (GladeDrag, glade_drag, G_TYPE_OBJECT);
+
+static void
+glade_drag_default_init (GladeDragInterface *iface)
+{
+}
+
+gboolean
+glade_drag_can_drag (GladeDrag *source)
+{
+  GladeDragInterface *iface;
+
+  g_return_val_if_fail (GLADE_IS_DRAG (source), FALSE);
+  iface = GLADE_DRAG_GET_INTERFACE (source);
+  
+  if (iface->can_drag)
+    return iface->can_drag (source);
+  else
+    return FALSE;
+}
+
+gboolean
+glade_drag_can_drop (GladeDrag *dest, GObject *data)
+{
+  GladeDragInterface *iface;
+
+  g_return_val_if_fail (GLADE_IS_DRAG (dest), FALSE);
+  iface = GLADE_DRAG_GET_INTERFACE (dest);
+
+  if (iface->can_drop)
+    return iface->can_drop (dest, data);
+  else
+    return FALSE;
+}
+
+gboolean
+glade_drag_drop (GladeDrag *dest, GObject *data)
+{
+  GladeDragInterface *iface;
+
+  g_return_val_if_fail (GLADE_IS_DRAG (dest), FALSE);
+  iface = GLADE_DRAG_GET_INTERFACE (dest);
+
+  if (iface->drop)
+    return iface->drop (dest, data);
+  else
+    return FALSE;
+}
+
+void
+glade_drag_highlight (GladeDrag *dest, gboolean highlight)
+{
+  GladeDragInterface *iface;
+
+  g_return_if_fail (GLADE_IS_DRAG (dest));
+  iface = GLADE_DRAG_GET_INTERFACE (dest);
+
+  if (iface->highlight)
+    iface->highlight (dest, !!highlight);
+}
diff --git a/gladeui/glade-drag.h b/gladeui/glade-drag.h
new file mode 100644
index 0000000..4622293
--- /dev/null
+++ b/gladeui/glade-drag.h
@@ -0,0 +1,76 @@
+/*
+ * glade-drag.h
+ *
+ * Copyright (C) 2013  Juan Pablo Ugarte
+ *
+ * Authors:
+ *   Juan Pablo Ugarte <juanpablougarte gmail com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _GLADE_DRAG_H_
+#define _GLADE_DRAG_H_
+
+#include "glade-widget-adaptor.h"
+
+G_BEGIN_DECLS
+
+#define GLADE_TYPE_DRAG                (glade_drag_get_type ())
+#define GLADE_DRAG(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_DRAG, GladeDrag))
+#define GLADE_IS_DRAG(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_DRAG))
+#define GLADE_DRAG_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GLADE_TYPE_DRAG, 
GladeDragInterface))
+
+typedef struct _GladeDrag GladeDrag;
+typedef struct _GladeDragInterface GladeDragInterface;
+
+struct _GladeDragInterface
+{
+  GTypeInterface parent_instance;
+ 
+  gboolean (*can_drag)  (GladeDrag *source);
+  
+  gboolean (*can_drop)  (GladeDrag *dest,
+                         GObject   *data);
+
+  gboolean (*drop)      (GladeDrag *dest,
+                         GObject   *data);
+
+  void     (*highlight) (GladeDrag *dest,
+                         gboolean   highlight);
+  
+  void (* padding1) (void);
+  void (* padding2) (void);
+  void (* padding3) (void);
+  void (* padding4) (void); 
+};
+
+GType glade_drag_get_type (void) G_GNUC_CONST;
+
+gboolean glade_drag_can_drag  (GladeDrag *source);
+
+gboolean glade_drag_can_drop  (GladeDrag *dest,
+                               GObject   *data);
+
+gboolean glade_drag_drop      (GladeDrag *dest,
+                               GObject   *data);
+
+void     glade_drag_highlight (GladeDrag *dest,
+                               gboolean   highlight);
+
+G_END_DECLS
+
+#endif /* _GLADE_DRAG_DEST_H_ */
diff --git a/gladeui/glade-inspector.c b/gladeui/glade-inspector.c
index 75274be..9475f7f 100644
--- a/gladeui/glade-inspector.c
+++ b/gladeui/glade-inspector.c
@@ -43,6 +43,7 @@
 #include "glade-inspector.h"
 #include "glade-popup.h"
 #include "glade-app.h"
+#include "glade-dnd.h"
 
 #include <string.h>
 #include <glib/gi18n-lib.h>
@@ -604,6 +605,11 @@ glade_inspector_init (GladeInspector *inspector)
   gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (priv->view), GTK_SCROLL_MINIMUM);
   add_columns (GTK_TREE_VIEW (priv->view));
 
+  /* Set it as a drag source */
+  gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (priv->view),
+                                          GDK_BUTTON1_MASK,
+                                          _glade_dnd_get_target (), 1, 0);
+
   g_signal_connect (G_OBJECT (priv->view), "row-activated",
                     G_CALLBACK (item_activated_cb), inspector);
 
diff --git a/gladeui/glade-palette.c b/gladeui/glade-palette.c
index 811f935..cb3263f 100644
--- a/gladeui/glade-palette.c
+++ b/gladeui/glade-palette.c
@@ -47,6 +47,7 @@
 #include "glade-widget-adaptor.h"
 #include "glade-popup.h"
 #include "glade-design-private.h"
+#include "glade-dnd.h"
 
 #include <glib/gi18n-lib.h>
 #include <gdk/gdk.h>
@@ -271,28 +272,24 @@ palette_item_toggled_cb (GtkToggleToolButton *button, GladePalette *palette)
 }
 
 static void
-glade_palette_drag_end (GtkWidget *widget,
-                        GdkDragContext *context,
-                        GtkWidget *drag_icon)
-{
-  g_object_unref (drag_icon);
-  g_signal_handlers_disconnect_by_func (widget, glade_palette_drag_end, drag_icon);
-}
-
-static void
 glade_palette_drag_begin (GtkWidget *widget,
                           GdkDragContext *context,
                           GladeWidgetAdaptor *adaptor)
 {
-  GtkWidget *drag_icon;
+  _glade_dnd_set_icon_widget (context,
+                              glade_widget_adaptor_get_icon_name (adaptor),
+                              glade_widget_adaptor_get_name (adaptor));
+}
 
-  drag_icon = _glade_design_layout_dnd_icon_widget_new (context,
-                                                        glade_widget_adaptor_get_icon_name (adaptor),
-                                                        glade_widget_adaptor_get_name (adaptor));
-  g_object_ref_sink (drag_icon);
-  gtk_drag_set_icon_widget (context, drag_icon, 0, 0);
-  g_signal_connect_object (widget, "drag-end",
-                           G_CALLBACK (glade_palette_drag_end), drag_icon, 0);
+static void
+glade_palette_drag_data_get (GtkWidget          *widget,
+                             GdkDragContext     *context,
+                             GtkSelectionData   *data,
+                             guint               info,
+                             guint               time,
+                             GladeWidgetAdaptor *adaptor)
+{
+  _glade_dnd_set_data (data, G_OBJECT (adaptor));
 }
 
 static gint
@@ -350,6 +347,11 @@ glade_palette_new_item (GladePalette * palette, GladeWidgetAdaptor * adaptor)
                     G_CALLBACK (palette_item_button_press_cb), item);
   g_signal_connect_object (button, "drag-begin",
                            G_CALLBACK (glade_palette_drag_begin), adaptor, 0);
+  g_signal_connect_object (button, "drag-data-get",
+                           G_CALLBACK (glade_palette_drag_data_get), adaptor, 0);
+
+  gtk_drag_source_set (button, GDK_BUTTON1_MASK, _glade_dnd_get_target (), 1, 0);
+
   gtk_widget_show (item);
 
   g_hash_table_insert (palette->priv->button_table, 
diff --git a/gladeui/glade-placeholder.c b/gladeui/glade-placeholder.c
index f90e92a..ec5361b 100644
--- a/gladeui/glade-placeholder.c
+++ b/gladeui/glade-placeholder.c
@@ -47,37 +47,12 @@
 #include "glade-app.h"
 #include <math.h>
 
+#include "glade-dnd.h"
+#include "glade-drag.h"
+
 #define WIDTH_REQUISITION    20
 #define HEIGHT_REQUISITION   20
 
-static void glade_placeholder_finalize (GObject *object);
-static void glade_placeholder_set_property (GObject *object,
-                                            guint prop_id,
-                                            const GValue *value,
-                                            GParamSpec *pspec);
-static void glade_placeholder_get_property (GObject *object,
-                                            guint prop_id,
-                                            GValue *value,
-                                            GParamSpec *pspec);
-static void glade_placeholder_realize (GtkWidget *widget);
-static void glade_placeholder_unrealize (GtkWidget *widget);
-static void glade_placeholder_map (GtkWidget *widget);
-static void glade_placeholder_unmap (GtkWidget *widget);
-
-static void glade_placeholder_size_allocate (GtkWidget *widget,
-                                             GtkAllocation *allocation);
-
-static gboolean glade_placeholder_draw (GtkWidget *widget, cairo_t *cr);
-
-static gboolean glade_placeholder_motion_notify_event (GtkWidget *widget,
-                                                       GdkEventMotion *event);
-
-static gboolean glade_placeholder_button_press (GtkWidget *widget,
-                                                GdkEventButton *event);
-
-static gboolean glade_placeholder_popup_menu (GtkWidget *widget);
-
-
 static cairo_pattern_t *placeholder_pattern = NULL;
 
 struct _GladePlaceholderPrivate
@@ -85,6 +60,8 @@ struct _GladePlaceholderPrivate
   GList *packing_actions;
 
   GdkWindow *event_window;
+
+  gboolean drag_highlight;
 };
 
 enum
@@ -99,56 +76,14 @@ enum
 #define GLADE_PLACEHOLDER_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
                                                GLADE_TYPE_PLACEHOLDER,                \
                                                GladePlaceholderPrivate))
+#define GLADE_PLACEHOLDER_PRIVATE(object) (((GladePlaceholder*)object)->priv)
 
-G_DEFINE_TYPE_WITH_CODE (GladePlaceholder, glade_placeholder, GTK_TYPE_WIDGET,
-                         G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
-
-static void glade_placeholder_class_init (GladePlaceholderClass *klass)
-{
-  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  gchar *path;
-  cairo_surface_t *surface;
-
-  object_class->finalize = glade_placeholder_finalize;
-  object_class->set_property = glade_placeholder_set_property;
-  object_class->get_property = glade_placeholder_get_property;
-
-  widget_class->realize = glade_placeholder_realize;
-  widget_class->unrealize = glade_placeholder_unrealize;
-  widget_class->map = glade_placeholder_map;
-  widget_class->unmap = glade_placeholder_unmap;
-  widget_class->size_allocate = glade_placeholder_size_allocate;
-  widget_class->draw = glade_placeholder_draw;
-  widget_class->motion_notify_event = glade_placeholder_motion_notify_event;
-  widget_class->button_press_event = glade_placeholder_button_press;
-  widget_class->popup_menu = glade_placeholder_popup_menu;
-
-  /* GtkScrollable implementation */
-  g_object_class_override_property (object_class, PROP_HADJUSTMENT,
-                                    "hadjustment");
-  g_object_class_override_property (object_class, PROP_VADJUSTMENT,
-                                    "vadjustment");
-  g_object_class_override_property (object_class, PROP_HSCROLL_POLICY,
-                                    "hscroll-policy");
-  g_object_class_override_property (object_class, PROP_VSCROLL_POLICY,
-                                    "vscroll-policy");
-
-  /* Create our tiled background pattern */
-  path = g_build_filename (glade_app_get_pixmaps_dir (), "placeholder.png", NULL);
-  surface = cairo_image_surface_create_from_png (path);
-
-  if (!surface)
-    g_warning ("Failed to create surface for %s\n", path);
-  else
-    {
-      placeholder_pattern = cairo_pattern_create_for_surface (surface);
-      cairo_pattern_set_extend (placeholder_pattern, CAIRO_EXTEND_REPEAT);
-    }
-  g_free (path);
+static void glade_placeholder_drag_init (GladeDragInterface *iface);
 
-  g_type_class_add_private (klass, sizeof (GladePlaceholderPrivate));
-}
+G_DEFINE_TYPE_WITH_CODE (GladePlaceholder, glade_placeholder, GTK_TYPE_WIDGET,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)
+                         G_IMPLEMENT_INTERFACE (GLADE_TYPE_DRAG, 
+                                                glade_placeholder_drag_init))
 
 static void
 glade_placeholder_notify_parent (GObject *gobject,
@@ -188,6 +123,8 @@ glade_placeholder_init (GladePlaceholder *placeholder)
   gtk_widget_set_size_request (GTK_WIDGET (placeholder),
                                WIDTH_REQUISITION, HEIGHT_REQUISITION);
 
+  _glade_dnd_dest_set (GTK_WIDGET (placeholder));
+
   g_signal_connect (placeholder, "notify::parent",
                     G_CALLBACK (glade_placeholder_notify_parent), NULL);
 
@@ -360,6 +297,7 @@ glade_placeholder_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
 static gboolean
 glade_placeholder_draw (GtkWidget *widget, cairo_t *cr)
 {
+  GladePlaceholder *placeholder = GLADE_PLACEHOLDER (widget);
   gint h = gtk_widget_get_allocated_height (widget) - 1;
   gint w = gtk_widget_get_allocated_width (widget) - 1;
 
@@ -388,6 +326,32 @@ glade_placeholder_draw (GtkWidget *widget, cairo_t *cr)
   cairo_line_to (cr, 0, h);
   cairo_stroke (cr);
 
+  if (placeholder->priv->drag_highlight)
+    {
+      cairo_pattern_t *gradient;
+      GtkStyleContext *context;
+      gdouble ww, hh;
+      GdkRGBA c;
+
+      context = gtk_widget_get_style_context (widget);
+      gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED |
+                                              GTK_STATE_FLAG_FOCUSED, &c);
+
+      ww = w/2.0;
+      hh = h/2.0;
+      gradient = cairo_pattern_create_radial (ww, hh, MIN (w, h)/6,
+                                              ww, hh, MAX (ww, hh));
+      cairo_pattern_add_color_stop_rgba (gradient, 0, c.red, c.green, c.blue, .08);
+      cairo_pattern_add_color_stop_rgba (gradient, 1, c.red, c.green, c.blue, .28);
+
+      cairo_set_source (cr, gradient);
+
+      cairo_rectangle (cr, 0, 0, w, h);
+      cairo_fill (cr);
+
+      cairo_pattern_destroy (gradient);
+    }
+
   return FALSE;
 }
 
@@ -469,6 +433,144 @@ glade_placeholder_popup_menu (GtkWidget *widget)
   return TRUE;
 }
 
+static gboolean
+glade_placeholder_drag_can_drag (GladeDrag *source)
+{
+  GladeWidget *parent = glade_placeholder_get_parent (GLADE_PLACEHOLDER (source));
+  return (parent) ? glade_drag_can_drag (GLADE_DRAG (parent)) : FALSE;
+}
+
+static gboolean
+glade_placeholder_drag_can_drop (GladeDrag *dest, GObject *data)
+{
+  if (GLADE_IS_WIDGET_ADAPTOR (data))
+    {
+      GType otype = glade_widget_adaptor_get_object_type (GLADE_WIDGET_ADAPTOR (data));
+
+      if (g_type_is_a (otype, GTK_TYPE_WIDGET) && !GWA_IS_TOPLEVEL (data))
+        return TRUE;
+    }
+  else if (GTK_IS_WIDGET (data))
+    {
+      GladeWidget *parent, *new_child;
+
+      /* Avoid recursion */
+      if (gtk_widget_is_ancestor (GTK_WIDGET (dest), GTK_WIDGET (data)))
+        return FALSE;
+
+      parent = glade_placeholder_get_parent (GLADE_PLACEHOLDER (dest));
+
+      if ((new_child = glade_widget_get_from_gobject (data)) &&
+          !glade_widget_add_verify (parent, new_child, FALSE))
+        return FALSE;
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+glade_placeholder_drag_drop (GladeDrag *dest, GObject *data)
+{
+  GladePlaceholder *placeholder = GLADE_PLACEHOLDER (dest);
+  GladeWidget *gsource;
+
+  if (!data)
+    return FALSE;
+  
+  if (GLADE_IS_WIDGET_ADAPTOR (data))
+    {
+      GladeWidget *parent = glade_placeholder_get_parent (placeholder);
+      
+      glade_command_create (GLADE_WIDGET_ADAPTOR (data), parent, placeholder, 
+                            glade_widget_get_project (parent));
+      return TRUE;
+    }
+  else if ((gsource = glade_widget_get_from_gobject (data)))
+    {
+      GladeWidget *parent = glade_placeholder_get_parent (placeholder);
+      GList widgets = {gsource, NULL, NULL};
+
+      /* Check for recursive paste */
+      if (parent != gsource)
+        {
+          glade_command_dnd (&widgets, parent, placeholder);
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+glade_placeholder_drag_highlight (GladeDrag *dest, gboolean highlight)
+{
+  GladePlaceholderPrivate *priv = GLADE_PLACEHOLDER (dest)->priv;
+
+  if (priv->drag_highlight == highlight)
+    return;
+
+  priv->drag_highlight = highlight;
+  gtk_widget_queue_draw (GTK_WIDGET (dest));
+}
+
+static void
+glade_placeholder_drag_init (GladeDragInterface *iface)
+{
+  iface->can_drag = glade_placeholder_drag_can_drag;
+  iface->can_drop = glade_placeholder_drag_can_drop;
+  iface->drop = glade_placeholder_drag_drop;
+  iface->highlight = glade_placeholder_drag_highlight;
+}
+
+static void
+glade_placeholder_class_init (GladePlaceholderClass *klass)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  gchar *path;
+  cairo_surface_t *surface;
+
+  object_class->finalize = glade_placeholder_finalize;
+  object_class->set_property = glade_placeholder_set_property;
+  object_class->get_property = glade_placeholder_get_property;
+
+  widget_class->realize = glade_placeholder_realize;
+  widget_class->unrealize = glade_placeholder_unrealize;
+  widget_class->map = glade_placeholder_map;
+  widget_class->unmap = glade_placeholder_unmap;
+  widget_class->size_allocate = glade_placeholder_size_allocate;
+  widget_class->draw = glade_placeholder_draw;
+  widget_class->motion_notify_event = glade_placeholder_motion_notify_event;
+  widget_class->button_press_event = glade_placeholder_button_press;
+  widget_class->popup_menu = glade_placeholder_popup_menu;
+  
+  /* GtkScrollable implementation */
+  g_object_class_override_property (object_class, PROP_HADJUSTMENT,
+                                    "hadjustment");
+  g_object_class_override_property (object_class, PROP_VADJUSTMENT,
+                                    "vadjustment");
+  g_object_class_override_property (object_class, PROP_HSCROLL_POLICY,
+                                    "hscroll-policy");
+  g_object_class_override_property (object_class, PROP_VSCROLL_POLICY,
+                                    "vscroll-policy");
+
+  /* Create our tiled background pattern */
+  path = g_build_filename (glade_app_get_pixmaps_dir (), "placeholder.png", NULL);
+  surface = cairo_image_surface_create_from_png (path);
+
+  if (!surface)
+    g_warning ("Failed to create surface for %s\n", path);
+  else
+    {
+      placeholder_pattern = cairo_pattern_create_for_surface (surface);
+      cairo_pattern_set_extend (placeholder_pattern, CAIRO_EXTEND_REPEAT);
+    }
+  g_free (path);
+
+  g_type_class_add_private (klass, sizeof (GladePlaceholderPrivate));
+}
 
 /**
  * glade_placeholder_new:
diff --git a/gladeui/glade-project.c b/gladeui/glade-project.c
index 87a1699..cf485a5 100644
--- a/gladeui/glade-project.c
+++ b/gladeui/glade-project.c
@@ -53,6 +53,7 @@
 #include "glade-name-context.h"
 #include "glade-object-stub.h"
 #include "glade-project-properties.h"
+#include "glade-dnd.h"
 
 static void     glade_project_target_version_for_adaptor
                                                     (GladeProject       *project,
@@ -80,6 +81,7 @@ static void     glade_project_model_get_iter_for_object
                                                      GtkTreeIter        *iter);
 static gint     glade_project_count_children        (GladeProject       *project, 
                                                     GladeWidget        *parent);
+static void     glade_project_drag_source_init      (GtkTreeDragSourceIface *iface);
 
 struct _GladeProjectPrivate
 {
@@ -207,7 +209,9 @@ static GladeIDAllocator *unsaved_number_allocator = NULL;
 
 G_DEFINE_TYPE_WITH_CODE (GladeProject, glade_project, G_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
-                                                glade_project_model_iface_init))
+                                                glade_project_model_iface_init)
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
+                                                glade_project_drag_source_init))
 
 
 /*******************************************************************
@@ -1449,6 +1453,48 @@ glade_project_model_iface_init (GtkTreeModelIface *iface)
   iface->iter_parent = glade_project_model_iter_parent;
 }
 
+static gboolean 
+glade_project_row_draggable (GtkTreeDragSource *drag_source, GtkTreePath *path)
+{
+  return TRUE;
+}
+  
+static gboolean
+glade_project_drag_data_delete (GtkTreeDragSource *drag_source, GtkTreePath *path)
+{
+  return FALSE;
+}
+
+static gboolean
+glade_project_drag_data_get (GtkTreeDragSource *drag_source,
+                             GtkTreePath       *path,
+                             GtkSelectionData  *selection_data)
+{
+  GtkTreeIter iter;
+
+  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source), &iter, path))
+    {
+      GObject *object;
+
+      gtk_tree_model_get (GTK_TREE_MODEL (drag_source), &iter,
+                          GLADE_PROJECT_MODEL_COLUMN_OBJECT, &object,
+                          -1);
+
+      _glade_dnd_set_data (selection_data, object);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+glade_project_drag_source_init (GtkTreeDragSourceIface *iface)
+{
+  iface->row_draggable = glade_project_row_draggable;
+  iface->drag_data_delete = glade_project_drag_data_delete;
+  iface->drag_data_get = glade_project_drag_data_get;
+}
+
 /*******************************************************************
                     Loading project code here
  *******************************************************************/
diff --git a/gladeui/glade-widget.c b/gladeui/glade-widget.c
index dd35c9e..7a2e1e4 100644
--- a/gladeui/glade-widget.c
+++ b/gladeui/glade-widget.c
@@ -57,6 +57,7 @@
 #include "glade-widget-action.h"
 #include "glade-signal-model.h"
 #include "glade-object-stub.h"
+#include "glade-dnd.h"
 
 static void glade_widget_set_adaptor (GladeWidget * widget,
                                       GladeWidgetAdaptor * adaptor);
@@ -161,6 +162,10 @@ struct _GladeWidgetPrivate {
                                   */
   guint              rebuilding : 1;
   guint              composite : 1;
+
+  /* GladeDrag */
+  gboolean drag_dest : 1;
+  guint drag_highlight : 1;
 };
 
 enum
@@ -195,6 +200,7 @@ enum
   PROP_SUPPORT_WARNING,
   PROP_VISIBLE,
   PROP_COMPOSITE,
+  PROP_DRAG_DEST,
   N_PROPERTIES
 };
 
@@ -203,7 +209,12 @@ static guint glade_widget_signals[LAST_SIGNAL] = { 0 };
 
 static GQuark glade_widget_name_quark = 0;
 
-G_DEFINE_TYPE (GladeWidget, glade_widget, G_TYPE_INITIALLY_UNOWNED)
+static void glade_widget_drag_init (GladeDragInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GladeWidget, glade_widget, G_TYPE_INITIALLY_UNOWNED,
+                         G_IMPLEMENT_INTERFACE (GLADE_TYPE_DRAG, 
+                                                glade_widget_drag_init))
+
 /*******************************************************************************
                            GladeWidget class methods
  *******************************************************************************/
@@ -1119,6 +1130,9 @@ glade_widget_set_real_property (GObject * object,
     case PROP_COMPOSITE:
         glade_widget_set_is_composite (widget, g_value_get_boolean (value));
        break;
+    case PROP_DRAG_DEST:
+        glade_widget_set_drag_dest (widget, g_value_get_boolean (value));
+       break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
@@ -1178,6 +1192,9 @@ glade_widget_get_real_property (GObject * object,
       case PROP_COMPOSITE:
         g_value_set_boolean (value, glade_widget_get_is_composite (widget));
        break;
+      case PROP_DRAG_DEST:
+        g_value_set_boolean (value, glade_widget_get_drag_dest (widget));
+       break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
@@ -1213,6 +1230,109 @@ glade_widget_init (GladeWidget * widget)
   /* Initial invalid values */
   widget->priv->width = -1;
   widget->priv->height = -1;
+
+  widget->priv->drag_dest = FALSE;
+}
+
+static gboolean
+glade_widget_drag_can_drag (GladeDrag *source)
+{
+  GladeWidget *widget = GLADE_WIDGET (source);
+
+  return widget->priv->internal == NULL;
+}
+
+static gboolean
+glade_widget_drag_can_drop (GladeDrag *dest, GObject *data)
+{
+  if (GLADE_IS_WIDGET_ADAPTOR (data))
+    {
+      GType otype = glade_widget_adaptor_get_object_type (GLADE_WIDGET_ADAPTOR (data));
+
+      if (g_type_is_a (otype, GTK_TYPE_WIDGET) && !GWA_IS_TOPLEVEL (data))
+        return TRUE;
+    }
+  else
+    {
+      GladeWidget *new_child, *parent = GLADE_WIDGET (dest);
+      GObject *object = glade_widget_get_object (parent);
+
+      if (object == data)
+        return FALSE;
+        
+      if (GTK_IS_WIDGET (data) && GTK_IS_WIDGET (object) &&
+          gtk_widget_is_ancestor (GTK_WIDGET (data), GTK_WIDGET (object)))
+        return FALSE;
+
+      if ((new_child = glade_widget_get_from_gobject (data)) &&
+          (!glade_widget_add_verify (parent, new_child, FALSE) ||
+           glade_widget_placeholder_relation (parent, new_child)))
+        return FALSE;
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+glade_widget_drag_drop (GladeDrag *dest, GObject *data)
+{
+  GladeWidget *gsource;
+
+  if (!data)
+    return FALSE;
+
+  if (GLADE_IS_WIDGET_ADAPTOR (data))
+    {
+      GladeWidget *parent = GLADE_WIDGET (dest);
+
+      glade_command_create (GLADE_WIDGET_ADAPTOR (data), parent, NULL, 
+                            glade_widget_get_project (parent));
+      return TRUE;
+    }
+  else if ((gsource = glade_widget_get_from_gobject (data)))
+    {
+      GladeWidget *parent = GLADE_WIDGET (dest);
+      GList widgets = {gsource, NULL, NULL};
+
+      /* Check for recursive paste */
+      if (parent != gsource)
+        {
+          glade_command_dnd (&widgets, parent, NULL);
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+glade_widget_drag_highlight (GladeDrag *drag, gboolean highlight)
+{
+  GObject *target = glade_widget_get_object (GLADE_WIDGET (drag));
+  GladeWidgetPrivate *priv = GLADE_WIDGET (drag)->priv;
+
+  if (highlight == priv->drag_highlight || !GTK_IS_WIDGET (target))
+    return;
+
+  priv->drag_highlight = highlight;
+    
+  g_signal_handlers_disconnect_by_func (target, _glade_dnd_highlight_draw, NULL);
+  
+  if (highlight)
+    g_signal_connect_after (target, "draw", G_CALLBACK (_glade_dnd_highlight_draw), NULL);
+
+  gtk_widget_queue_draw (GTK_WIDGET (target));
+}
+
+static void
+glade_widget_drag_init (GladeDragInterface *iface)
+{
+  iface->can_drag = glade_widget_drag_can_drag;
+  iface->can_drop = glade_widget_drag_can_drop;
+  iface->drop = glade_widget_drag_drop;
+  iface->highlight = glade_widget_drag_highlight;
 }
 
 static void
@@ -1338,6 +1458,11 @@ glade_widget_class_init (GladeWidgetClass * klass)
        g_param_spec_boolean ("composite", _("Composite"),
                             _("Whether this widget is the template for a composite widget"),
                             FALSE, G_PARAM_READWRITE);
+  
+  properties[PROP_DRAG_DEST] =
+       g_param_spec_boolean ("drag-dest", _("Drag Destination"),
+                            _("Whether this widget is drag destination"),
+                            FALSE, G_PARAM_READWRITE);
 
   /* Install all properties */
   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
@@ -2643,6 +2768,44 @@ glade_widget_get_is_composite (GladeWidget *widget)
 }
 
 /**
+ * glade_widget_set_drag_dest:
+ * @widget: a #GladeWidget
+ * @drag_dest: whether @widget should be a drag destination
+ *
+ * Set's this widget to be drag destination.
+ */
+void
+glade_widget_set_drag_dest (GladeWidget *widget,
+                            gboolean     drag_dest)
+{
+  g_return_if_fail (GLADE_IS_WIDGET (widget));
+
+  drag_dest = !!drag_dest;
+
+  if (widget->priv->drag_dest != drag_dest)
+    {
+      widget->priv->drag_dest = drag_dest;
+      g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_DRAG_DEST]);
+    }
+}
+
+/**
+ * glade_widget_get_drag_dest:
+ * @widget: a #GladeWidget
+ *
+ * Checks if @widget is a drag destination.
+ *
+ * Returns: whether @widget is a drag destination.
+ */
+gboolean
+glade_widget_get_drag_dest (GladeWidget *widget)
+{
+  g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
+
+  return widget->priv->drag_dest;
+}
+
+/**
  * glade_widget_set_internal:
  * @widget: A #GladeWidget
  * @internal: The internal name
diff --git a/gladeui/glade-widget.h b/gladeui/glade-widget.h
index d594e1c..a23802f 100644
--- a/gladeui/glade-widget.h
+++ b/gladeui/glade-widget.h
@@ -401,6 +401,11 @@ GtkTreeModel           *glade_widget_get_signal_model       (GladeWidget      *w
 GladeWidget            *glade_widget_find_child             (GladeWidget *widget,
                                                              const gchar *name);
 
+void                    glade_widget_set_drag_dest          (GladeWidget *widget,
+                                                             gboolean     drag_dest);
+
+gboolean                glade_widget_get_drag_dest          (GladeWidget *widget);
+
 G_END_DECLS
 
 #endif /* __GLADE_WIDGET_H__ */
diff --git a/plugins/gtk+/glade-gtk-fixed-layout.c b/plugins/gtk+/glade-gtk-fixed-layout.c
index 22ce1ad..86b24ed 100644
--- a/plugins/gtk+/glade-gtk-fixed-layout.c
+++ b/plugins/gtk+/glade-gtk-fixed-layout.c
@@ -109,6 +109,10 @@ void
 glade_gtk_fixed_layout_post_create (GladeWidgetAdaptor * adaptor,
                                     GObject * object, GladeCreateReason reason)
 {
+  GladeWidget *widget = glade_widget_get_from_gobject (object);
+
+  glade_widget_set_drag_dest (widget, TRUE);
+  
   /* Set a minimun size so you can actually see it if you added to a box */
   gtk_widget_set_size_request (GTK_WIDGET (object), 32, 32);
 
diff --git a/plugins/gtk+/glade-gtk-overlay.c b/plugins/gtk+/glade-gtk-overlay.c
index a8f9af8..9ffcca3 100644
--- a/plugins/gtk+/glade-gtk-overlay.c
+++ b/plugins/gtk+/glade-gtk-overlay.c
@@ -151,11 +151,13 @@ glade_gtk_overlay_post_create (GladeWidgetAdaptor *adaptor,
                                GObject            *object,
                                GladeCreateReason   reason)
 {
+  GladeWidget *widget = glade_widget_get_from_gobject (object);
+
   if (reason == GLADE_CREATE_USER)
     gtk_container_add (GTK_CONTAINER (object), glade_placeholder_new ());
 
-  on_widget_project_notify (G_OBJECT (glade_widget_get_from_gobject (object)),
-                            NULL, NULL);
+  glade_widget_set_drag_dest (widget, TRUE);
+  on_widget_project_notify (G_OBJECT (widget), NULL, NULL);
 }
 
 gboolean
diff --git a/src/glade-window.c b/src/glade-window.c
index d2f0218..bc882a9 100644
--- a/src/glade-window.c
+++ b/src/glade-window.c
@@ -1813,8 +1813,6 @@ on_notebook_tab_added (GtkNotebook *notebook,
                                     gtk_radio_action_get_current_value (GTK_RADIO_ACTION 
(priv->icons_and_labels_radioaction)));
 
   gtk_notebook_append_page (window->priv->palettes_notebook, palette, NULL);
-
-  glade_design_view_set_drag_source (view, glade_palette_get_tool_palette (GLADE_PALETTE (palette)));
   
   if (GPOINTER_TO_INT
       (g_object_get_data (G_OBJECT (view), "view-added-while-loading")))


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