[gimp] Bug 676522 - Make DND work between images in *one* dockable...



commit 16938bb667d782979a9fe88be00ea2ecfd9c3c8a
Author: Michael Natterer <mitch gimp org>
Date:   Sat Feb 15 21:29:36 2014 +0100

    Bug 676522 - Make DND work between images in *one* dockable...
    
    ...after in-DND image switching
    
    This was actually two issues:
    
    First, DND data is normally transferred on drop. In this situation the
    contents of the source widget change in the middle of DND, so when the
    drop happens there is nothing to transfer. Fixed this by attaching the
    thing to transfer (image, item, color etc) to the GdkDragContext when
    the DND operation starts, and trying to retrieve it on drop. Only when
    nothing is attached we fall back to the traditional way of asking the
    source widget. This is expected and an obvious fix.
    
    Second, and not so obvious, the source part of the GTK+-internal state
    of the DND operation (GtkDragSourceInfo) contains a *reference* (not a
    copy) of the source widget's target list. When we change images in the
    middle of DND, the source layer view's target list gets modified, and
    because GtkDragSourceInfo only references it, the state of the ongoing
    DND operation gets destroyed with it. Fixed this by changing
    gimp_dnd_data_source_remove() to never change a source widget's target
    list but instead create a new list without the removed target and
    replace the source widget's list, keeping the ongoing drag's list
    unaffected.
    
    Also kept all the GIMP_LOG() stuff I added during debugging there, it
    turned out to be quite useful.

 app/widgets/gimpdnd.c |  207 +++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 168 insertions(+), 39 deletions(-)
---
diff --git a/app/widgets/gimpdnd.c b/app/widgets/gimpdnd.c
index 3064ee8..5f52a00 100644
--- a/app/widgets/gimpdnd.c
+++ b/app/widgets/gimpdnd.c
@@ -20,6 +20,7 @@
 #include <gegl.h>
 #include <gtk/gtk.h>
 
+#include "libgimpcolor/gimpcolor.h"
 #include "libgimpwidgets/gimpwidgets.h"
 
 #include "widgets-types.h"
@@ -61,6 +62,7 @@
 
 
 typedef GtkWidget * (* GimpDndGetIconFunc)  (GtkWidget        *widget,
+                                             GdkDragContext   *context,
                                              GCallback         get_data_func,
                                              gpointer          get_data_data);
 typedef void        (* GimpDndDragDataFunc) (GtkWidget        *widget,
@@ -95,12 +97,15 @@ struct _GimpDndDataDef
 
 
 static GtkWidget * gimp_dnd_get_viewable_icon  (GtkWidget        *widget,
+                                                GdkDragContext   *context,
                                                 GCallback         get_viewable_func,
                                                 gpointer          get_viewable_data);
 static GtkWidget * gimp_dnd_get_component_icon (GtkWidget        *widget,
+                                                GdkDragContext   *context,
                                                 GCallback         get_comp_func,
                                                 gpointer          get_comp_data);
 static GtkWidget * gimp_dnd_get_color_icon     (GtkWidget        *widget,
+                                                GdkDragContext   *context,
                                                 GCallback         get_color_func,
                                                 gpointer          get_color_data);
 
@@ -675,6 +680,7 @@ gimp_dnd_data_drag_begin (GtkWidget      *widget,
     return;
 
   icon_widget = dnd_data->get_icon_func (widget,
+                                         context,
                                          get_data_func,
                                          get_data_data);
 
@@ -934,16 +940,41 @@ gimp_dnd_data_source_remove (GimpDndType  data_type,
 
   if (dnd_data->target_entry.target)
     {
-      GtkTargetList *target_list;
-
-      target_list = gtk_drag_source_get_target_list (widget);
+      /* Don't just remove the target from the existing list, create a
+       * new list without the target and replace the old list. The
+       * source's target list is part of a drag operation's state, but
+       * only by reference, it's not copied. So when we change the
+       * list, we would change the state of that ongoing drag, making
+       * it impossible to drop anything. See bug #676522.
+       */
+      GtkTargetList *target_list = gtk_drag_source_get_target_list (widget);
 
       if (target_list)
         {
-          GdkAtom atom = gdk_atom_intern (dnd_data->target_entry.target, TRUE);
+          GtkTargetList  *new_list;
+          GtkTargetEntry *targets;
+          gint            n_targets;
+          gint            i;
 
-          if (atom != GDK_NONE)
-            gtk_target_list_remove (target_list, atom);
+          targets = gtk_target_table_new_from_list (target_list, &n_targets);
+
+          new_list = gtk_target_list_new (NULL, 0);
+
+          for (i = 0; i < n_targets; i++)
+            {
+              if (targets[i].info != data_type)
+                {
+                  gtk_target_list_add (new_list,
+                                       gdk_atom_intern (targets[i].target, FALSE),
+                                       targets[i].flags,
+                                       targets[i].info);
+                }
+            }
+
+          gtk_target_table_free (targets, n_targets);
+
+          gtk_drag_source_set_target_list (widget, new_list);
+          gtk_target_list_unref (new_list);
         }
     }
 }
@@ -1049,6 +1080,8 @@ gimp_dnd_get_uri_list_data (GtkWidget        *widget,
   uri_list = (* (GimpDndDragUriListFunc) get_uri_list_func) (widget,
                                                              get_uri_list_data);
 
+  GIMP_LOG (DND, "uri_list %p", uri_list);
+
   if (uri_list)
     {
       gimp_selection_data_set_uri_list (selection, uri_list);
@@ -1067,6 +1100,8 @@ gimp_dnd_set_uri_list_data (GtkWidget        *widget,
 {
   GList *uri_list = gimp_selection_data_get_uri_list (selection);
 
+  GIMP_LOG (DND, "uri_list %p", uri_list);
+
   if (! uri_list)
     return FALSE;
 
@@ -1150,9 +1185,14 @@ gimp_dnd_get_xds_data (GtkWidget        *widget,
   GimpImage   *image;
   GimpContext *gimp_context;
 
-  image = (GimpImage *)
-    (* (GimpDndDragViewableFunc) get_image_func) (widget, &gimp_context,
-                                                  get_image_data);
+  image = g_object_get_data (G_OBJECT (context), "gimp-dnd-viewable");
+
+  if (! image)
+    image = (GimpImage *)
+      (* (GimpDndDragViewableFunc) get_image_func) (widget, &gimp_context,
+                                                    get_image_data);
+
+  GIMP_LOG (DND, "image %p", image);
 
   if (image)
     gimp_dnd_xds_save_image (context, image, selection);
@@ -1180,6 +1220,8 @@ gimp_dnd_xds_drag_begin (GtkWidget      *widget,
         (* (GimpDndDragViewableFunc) get_data_func) (widget, &gimp_context,
                                                      get_data_data);
 
+      GIMP_LOG (DND, "image %p", image);
+
       gimp_dnd_xds_source_set (context, image);
     }
 }
@@ -1261,15 +1303,22 @@ gimp_dnd_xds_source_remove (GtkWidget *widget)
 /*************************/
 
 static GtkWidget *
-gimp_dnd_get_color_icon (GtkWidget *widget,
-                         GCallback  get_color_func,
-                         gpointer   get_color_data)
+gimp_dnd_get_color_icon (GtkWidget      *widget,
+                         GdkDragContext *context,
+                         GCallback       get_color_func,
+                         gpointer        get_color_data)
 {
   GtkWidget *color_area;
   GimpRGB    color;
 
   (* (GimpDndDragColorFunc) get_color_func) (widget, &color, get_color_data);
 
+  GIMP_LOG (DND, "called");
+
+  g_object_set_data_full (G_OBJECT (context),
+                          "gimp-dnd-color", g_memdup (&color, sizeof (GimpRGB)),
+                          (GDestroyNotify) g_free);
+
   color_area = gimp_color_area_new (&color, GIMP_COLOR_AREA_SMALL_CHECKS, 0);
   gtk_widget_set_size_request (color_area,
                                DRAG_PREVIEW_SIZE, DRAG_PREVIEW_SIZE);
@@ -1284,9 +1333,17 @@ gimp_dnd_get_color_data (GtkWidget        *widget,
                          gpointer          get_color_data,
                          GtkSelectionData *selection)
 {
-  GimpRGB color;
+  GimpRGB *c;
+  GimpRGB  color;
 
-  (* (GimpDndDragColorFunc) get_color_func) (widget, &color, get_color_data);
+  c = g_object_get_data (G_OBJECT (context), "gimp-dnd-color");
+
+  if (c)
+    color = *c;
+  else
+    (* (GimpDndDragColorFunc) get_color_func) (widget, &color, get_color_data);
+
+  GIMP_LOG (DND, "called");
 
   gimp_selection_data_set_color (selection, &color);
 }
@@ -1301,6 +1358,8 @@ gimp_dnd_set_color_data (GtkWidget        *widget,
 {
   GimpRGB color;
 
+  GIMP_LOG (DND, "called");
+
   if (! gimp_selection_data_get_color (selection, &color))
     return FALSE;
 
@@ -1368,6 +1427,8 @@ gimp_dnd_get_stream_data (GtkWidget        *widget,
   stream = (* (GimpDndDragStreamFunc) get_stream_func) (widget, &stream_length,
                                                         get_stream_data);
 
+  GIMP_LOG (DND, "stream %p, length %d", stream, stream_length);
+
   if (stream)
     {
       gimp_selection_data_set_stream (selection, stream, stream_length);
@@ -1388,6 +1449,8 @@ gimp_dnd_set_stream_data (GtkWidget        *widget,
 
   stream = gimp_selection_data_get_stream (selection, &stream_length);
 
+  GIMP_LOG (DND, "stream %p, length %d", stream, stream_length);
+
   if (! stream)
     return FALSE;
 
@@ -1463,6 +1526,8 @@ gimp_dnd_get_pixbuf_data (GtkWidget        *widget,
   pixbuf = (* (GimpDndDragPixbufFunc) get_pixbuf_func) (widget,
                                                         get_pixbuf_data);
 
+  GIMP_LOG (DND, "pixbuf %p", pixbuf);
+
   if (pixbuf)
     {
       gimp_set_busy (the_dnd_gimp);
@@ -1490,6 +1555,8 @@ gimp_dnd_set_pixbuf_data (GtkWidget        *widget,
 
   gimp_unset_busy (the_dnd_gimp);
 
+  GIMP_LOG (DND, "pixbuf %p", pixbuf);
+
   if (! pixbuf)
     return FALSE;
 
@@ -1590,23 +1657,32 @@ gimp_dnd_pixbuf_dest_remove (GtkWidget *widget)
 /*****************************/
 
 static GtkWidget *
-gimp_dnd_get_component_icon (GtkWidget *widget,
-                             GCallback  get_comp_func,
-                             gpointer   get_comp_data)
+gimp_dnd_get_component_icon (GtkWidget      *widget,
+                             GdkDragContext *context,
+                             GCallback       get_comp_func,
+                             gpointer        get_comp_data)
 {
   GtkWidget       *view;
   GimpImage       *image;
-  GimpContext     *context;
+  GimpContext     *gimp_context;
   GimpChannelType  channel;
 
-  image = (* (GimpDndDragComponentFunc) get_comp_func) (widget, &context,
+  image = (* (GimpDndDragComponentFunc) get_comp_func) (widget, &gimp_context,
                                                         &channel,
                                                         get_comp_data);
 
+  GIMP_LOG (DND, "image %p, component %d", image, channel);
+
   if (! image)
     return NULL;
 
-  view = gimp_view_new (context, GIMP_VIEWABLE (image),
+  g_object_set_data_full (G_OBJECT (context),
+                          "gimp-dnd-viewable", g_object_ref (image),
+                          (GDestroyNotify) g_object_unref);
+  g_object_set_data (G_OBJECT (context),
+                     "gimp-dnd-component", GINT_TO_POINTER (channel));
+
+  view = gimp_view_new (gimp_context, GIMP_VIEWABLE (image),
                         DRAG_PREVIEW_SIZE, 0, TRUE);
 
   GIMP_VIEW_RENDERER_IMAGE (GIMP_VIEW (view)->renderer)->channel = channel;
@@ -1625,9 +1701,16 @@ gimp_dnd_get_component_data (GtkWidget        *widget,
   GimpContext     *gimp_context;
   GimpChannelType  channel = 0;
 
-  image = (* (GimpDndDragComponentFunc) get_comp_func) (widget, &gimp_context,
-                                                        &channel,
-                                                        get_comp_data);
+  image = g_object_get_data (G_OBJECT (context), "gimp-dnd-viewable");
+  channel = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
+                                                "gimp-dnd-component"));
+
+  if (! image)
+    image = (* (GimpDndDragComponentFunc) get_comp_func) (widget, &gimp_context,
+                                                          &channel,
+                                                          get_comp_data);
+
+  GIMP_LOG (DND, "image %p, component %d", image, channel);
 
   if (image)
     gimp_selection_data_set_component (selection, image, channel);
@@ -1647,6 +1730,8 @@ gimp_dnd_set_component_data (GtkWidget        *widget,
   image = gimp_selection_data_get_component (selection, the_dnd_gimp,
                                              &channel);
 
+  GIMP_LOG (DND, "image %p, component %d", image, channel);
+
   if (! image)
     return FALSE;
 
@@ -1703,22 +1788,30 @@ gimp_dnd_component_dest_remove (GtkWidget *widget)
 /*******************************************/
 
 static GtkWidget *
-gimp_dnd_get_viewable_icon (GtkWidget *widget,
-                            GCallback  get_viewable_func,
-                            gpointer   get_viewable_data)
+gimp_dnd_get_viewable_icon (GtkWidget      *widget,
+                            GdkDragContext *context,
+                            GCallback       get_viewable_func,
+                            gpointer        get_viewable_data)
 {
   GimpViewable *viewable;
-  GimpContext  *context;
+  GimpContext  *gimp_context;
   GtkWidget    *view;
   gchar        *desc;
 
-  viewable = (* (GimpDndDragViewableFunc) get_viewable_func) (widget, &context,
+  viewable = (* (GimpDndDragViewableFunc) get_viewable_func) (widget,
+                                                              &gimp_context,
                                                               get_viewable_data);
 
+  GIMP_LOG (DND, "viewable %p", viewable);
+
   if (! viewable)
     return NULL;
 
-  view = gimp_view_new (context, viewable,
+  g_object_set_data_full (G_OBJECT (context),
+                          "gimp-dnd-viewable", g_object_ref (viewable),
+                          (GDestroyNotify) g_object_unref);
+
+  view = gimp_view_new (gimp_context, viewable,
                         DRAG_PREVIEW_SIZE, 0, TRUE);
 
   desc = gimp_viewable_get_description (viewable, NULL);
@@ -1974,7 +2067,6 @@ gimp_dnd_get_drag_data (GtkWidget *widget)
     return NULL;
 
   return (GimpViewable *) (* get_data_func) (widget, &context, get_data_data);
-
 }
 
 
@@ -1992,9 +2084,14 @@ gimp_dnd_get_image_data (GtkWidget        *widget,
   GimpImage   *image;
   GimpContext *gimp_context;
 
-  image = (GimpImage *)
-    (* (GimpDndDragViewableFunc) get_image_func) (widget, &gimp_context,
-                                                  get_image_data);
+  image = g_object_get_data (G_OBJECT (context), "gimp-dnd-viewable");
+
+  if (! image)
+    image = (GimpImage *)
+      (* (GimpDndDragViewableFunc) get_image_func) (widget, &gimp_context,
+                                                    get_image_data);
+
+  GIMP_LOG (DND, "image %p", image);
 
   if (image)
     gimp_selection_data_set_image (selection, image);
@@ -2010,6 +2107,8 @@ gimp_dnd_set_image_data (GtkWidget        *widget,
 {
   GimpImage *image = gimp_selection_data_get_image (selection, the_dnd_gimp);
 
+  GIMP_LOG (DND, "image %p", image);
+
   if (! image)
     return FALSE;
 
@@ -2035,9 +2134,14 @@ gimp_dnd_get_item_data (GtkWidget        *widget,
   GimpItem    *item;
   GimpContext *gimp_context;
 
-  item = (GimpItem *)
-    (* (GimpDndDragViewableFunc) get_item_func) (widget, &gimp_context,
-                                                 get_item_data);
+  item = g_object_get_data (G_OBJECT (context), "gimp-dnd-viewable");
+
+  if (! item)
+    item = (GimpItem *)
+      (* (GimpDndDragViewableFunc) get_item_func) (widget, &gimp_context,
+                                                   get_item_data);
+
+  GIMP_LOG (DND, "item %p", item);
 
   if (item)
     gimp_selection_data_set_item (selection, item);
@@ -2053,6 +2157,8 @@ gimp_dnd_set_item_data (GtkWidget        *widget,
 {
   GimpItem *item = gimp_selection_data_get_item (selection, the_dnd_gimp);
 
+  GIMP_LOG (DND, "item %p", item);
+
   if (! item)
     return FALSE;
 
@@ -2078,9 +2184,14 @@ gimp_dnd_get_object_data (GtkWidget        *widget,
   GimpObject  *object;
   GimpContext *gimp_context;
 
-  object = (GimpObject *)
-    (* (GimpDndDragViewableFunc) get_object_func) (widget, &gimp_context,
-                                                   get_object_data);
+  object = g_object_get_data (G_OBJECT (context), "gimp-dnd-viewable");
+
+  if (! object)
+    object = (GimpObject *)
+      (* (GimpDndDragViewableFunc) get_object_func) (widget, &gimp_context,
+                                                     get_object_data);
+
+  GIMP_LOG (DND, "object %p", object);
 
   if (GIMP_IS_OBJECT (object))
     gimp_selection_data_set_object (selection, object);
@@ -2101,6 +2212,8 @@ gimp_dnd_set_brush_data (GtkWidget        *widget,
 {
   GimpBrush *brush = gimp_selection_data_get_brush (selection, the_dnd_gimp);
 
+  GIMP_LOG (DND, "brush %p", brush);
+
   if (! brush)
     return FALSE;
 
@@ -2127,6 +2240,8 @@ gimp_dnd_set_pattern_data (GtkWidget        *widget,
   GimpPattern *pattern = gimp_selection_data_get_pattern (selection,
                                                           the_dnd_gimp);
 
+  GIMP_LOG (DND, "pattern %p", pattern);
+
   if (! pattern)
     return FALSE;
 
@@ -2153,6 +2268,8 @@ gimp_dnd_set_gradient_data (GtkWidget        *widget,
   GimpGradient *gradient = gimp_selection_data_get_gradient (selection,
                                                              the_dnd_gimp);
 
+  GIMP_LOG (DND, "gradient %p", gradient);
+
   if (! gradient)
     return FALSE;
 
@@ -2179,6 +2296,8 @@ gimp_dnd_set_palette_data (GtkWidget        *widget,
   GimpPalette *palette = gimp_selection_data_get_palette (selection,
                                                           the_dnd_gimp);
 
+  GIMP_LOG (DND, "palette %p", palette);
+
   if (! palette)
     return FALSE;
 
@@ -2204,6 +2323,8 @@ gimp_dnd_set_font_data (GtkWidget        *widget,
 {
   GimpFont *font = gimp_selection_data_get_font (selection, the_dnd_gimp);
 
+  GIMP_LOG (DND, "font %p", font);
+
   if (! font)
     return FALSE;
 
@@ -2229,6 +2350,8 @@ gimp_dnd_set_buffer_data (GtkWidget        *widget,
 {
   GimpBuffer *buffer = gimp_selection_data_get_buffer (selection, the_dnd_gimp);
 
+  GIMP_LOG (DND, "buffer %p", buffer);
+
   if (! buffer)
     return FALSE;
 
@@ -2255,6 +2378,8 @@ gimp_dnd_set_imagefile_data (GtkWidget        *widget,
   GimpImagefile *imagefile = gimp_selection_data_get_imagefile (selection,
                                                                 the_dnd_gimp);
 
+  GIMP_LOG (DND, "imagefile %p", imagefile);
+
   if (! imagefile)
     return FALSE;
 
@@ -2281,6 +2406,8 @@ gimp_dnd_set_template_data (GtkWidget        *widget,
   GimpTemplate *template = gimp_selection_data_get_template (selection,
                                                              the_dnd_gimp);
 
+  GIMP_LOG (DND, "template %p", template);
+
   if (! template)
     return FALSE;
 
@@ -2307,6 +2434,8 @@ gimp_dnd_set_tool_info_data (GtkWidget        *widget,
   GimpToolInfo *tool_info = gimp_selection_data_get_tool_info (selection,
                                                                the_dnd_gimp);
 
+  GIMP_LOG (DND, "tool_info %p", tool_info);
+
   if (! tool_info)
     return FALSE;
 


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