[gtk+/gtk-2-24-quartz: 26/27] Bug 658722: Drag and Drop sometimes stops working



commit df0aef74c8a33508bf69092864bd3443c75084e6
Author: John Ralls <jralls ceridwen us>
Date:   Sat Sep 24 12:32:24 2011 -0700

    Bug 658722: Drag and Drop sometimes stops working
    
    First, rather than assuming that there's already an event
    queued up if _gdk_quartz_drag_source_context isn't NULL,
    assume that it just didn't get cleaned up the last time
    it ran and abort it.
    
    This naturally requires implementing gdk_quartz_drag_abort(),
    so remove the code from
    [GdkQuartzWindow draggedImage:endedAt:operation:] and
    move it to gdkdnd_quartz.c as static void gdk_quartz_drag_end().
    Implement both gdk_quartz_drag_drop() and gdk_quartz_drag_abort() by calling gdk_quartz_drag_end().
    
    Next, try to get rid of the memory cycle between
    gtk_drag_source_info.context and _gdk_quartz_drag_source_context.
    Replace gtk_drag_source_clear_info() by using a
    g_object_set_qdata_full() for context in gtk_drag_get_source_context,
    calling gtk_drag_source_info_destroy() as the destructor. This
    eliminates the need to queue a cleanup idle event. I use
    g_object_run_dispose() on _gtk_quartz_drag_source_context to
    force the deletion of the info stored as qdata, which in turn unrefs the info->context pointer. Ordinarily this gets fired
    off from draggedImage:endedAt:operation:, meaning that the
    special dragging CFRunLoop is complete and NSEvents are again flowing, so queuing a cleanup event isn't necessary. The
    advantage is that it can also be run from gdk_drag_abort, so
    if Gdk thinks there's a drag but CF doesn't all of the memory still gets cleaned up.

 gdk/quartz/GdkQuartzWindow.c |   16 +---------------
 gdk/quartz/gdkdnd-quartz.c   |   38 +++++++++++++++++++++++++++++++++-----
 gtk/gtkdnd-quartz.c          |   30 ++++++++++++++++++++++--------
 3 files changed, 56 insertions(+), 28 deletions(-)
---
diff --git a/gdk/quartz/GdkQuartzWindow.c b/gdk/quartz/GdkQuartzWindow.c
index dcd7250..20ed80e 100644
--- a/gdk/quartz/GdkQuartzWindow.c
+++ b/gdk/quartz/GdkQuartzWindow.c
@@ -560,21 +560,7 @@ update_context_from_dragging_info (id <NSDraggingInfo> sender)
 
 - (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
 {
-  GdkEvent event;
-
-  g_assert (_gdk_quartz_drag_source_context != NULL);
-
-  event.dnd.type = GDK_DROP_FINISHED;
-  event.dnd.window = g_object_ref ([[self contentView] gdkWindow]);
-  event.dnd.send_event = FALSE;
-  event.dnd.context = _gdk_quartz_drag_source_context;
-
-  (*_gdk_event_func) (&event, _gdk_event_data);
-
-  g_object_unref (event.dnd.window);
-
-  g_object_unref (_gdk_quartz_drag_source_context);
-  _gdk_quartz_drag_source_context = NULL;
+  gdk_drag_drop (_gdk_quartz_drag_source_context, (guint32)g_get_real_time());
 }
 
 @end
diff --git a/gdk/quartz/gdkdnd-quartz.c b/gdk/quartz/gdkdnd-quartz.c
index f1ad1bc..fba4a1a 100644
--- a/gdk/quartz/gdkdnd-quartz.c
+++ b/gdk/quartz/gdkdnd-quartz.c
@@ -111,11 +111,20 @@ GdkDragContext *
 gdk_drag_begin (GdkWindow     *window,
 		GList         *targets)
 {
-  g_return_val_if_fail (_gdk_quartz_drag_source_context == NULL, NULL);
+  if (_gdk_quartz_drag_source_context != NULL)
+    {
+      /* Something is amiss with the existing drag, so log a message
+	 and abort it */
+      g_warning ("Drag begun with existing context; aborting the preexisting drag");
+      gdk_drag_abort (_gdk_quartz_drag_source_context,
+		      (guint32)g_get_real_time ());
+    }
+
   
   /* Create fake context */
   _gdk_quartz_drag_source_context = gdk_drag_context_new ();
   _gdk_quartz_drag_source_context->is_source = TRUE;
+  _gdk_quartz_drag_source_context->source_window = window;
   
   return _gdk_quartz_drag_source_context;
 }
@@ -155,20 +164,39 @@ gdk_drag_find_window_for_screen (GdkDragContext  *context,
   /* FIXME: Implement */
 }
 
+static void
+gdk_quartz_drag_end (GdkDragContext *context)
+{
+  GdkEvent event;
+
+  g_assert (context != NULL);
+  g_warning ("Gdk-quartz-drag-end\n");
+  event.dnd.type = GDK_DROP_FINISHED;
+  event.dnd.window = g_object_ref (context->source_window);
+  event.dnd.send_event = FALSE;
+  event.dnd.context = context;
+
+  (*_gdk_event_func) (&event, _gdk_event_data);
+
+  g_object_unref (event.dnd.window);
+
+  g_object_unref (_gdk_quartz_drag_source_context);
+  _gdk_quartz_drag_source_context = NULL;
+}
+
 void
 gdk_drag_drop (GdkDragContext *context,
 	       guint32         time)
 {
-  /* FIXME: Implement */
+  g_warning ("Gdk-quartz-drag-drop, ending\n");
+  gdk_quartz_drag_end (context);
 }
 
 void
 gdk_drag_abort (GdkDragContext *context,
 		guint32         time)
 {
-  g_return_if_fail (context != NULL);
-  
-  /* FIXME: Implement */
+  gdk_quartz_drag_end (context);
 }
 
 void             
diff --git a/gtk/gtkdnd-quartz.c b/gtk/gtkdnd-quartz.c
index 22b696c..b4d8c9c 100644
--- a/gtk/gtkdnd-quartz.c
+++ b/gtk/gtkdnd-quartz.c
@@ -138,7 +138,7 @@ struct _GtkDragFindData
 
 
 @interface GtkDragSourceOwner : NSObject {
-  GtkDragSourceInfo *info;
+  GdkDragContext *context;
 }
 
 @end
@@ -148,13 +148,16 @@ struct _GtkDragFindData
 {
   guint target_info;
   GtkSelectionData selection_data;
+  GtkDragSourceInfo *info;
+  g_return_if_fail (context != NULL);
+  info = gtk_drag_get_source_info (context, FALSE);
+  g_return_if_fail (info != NULL);
   g_return_if_fail(info->source_widget != NULL);
   g_return_if_fail(info->target_list != NULL);
   selection_data.selection = GDK_NONE;
   selection_data.data = NULL;
   selection_data.length = -1;
   selection_data.target = _gtk_quartz_pasteboard_type_to_atom (type);
-  selection_data.display = gdk_display_get_default ();
 
   if (gtk_target_list_find (info->target_list, 
 			    selection_data.target, 
@@ -175,18 +178,27 @@ struct _GtkDragFindData
 
 - (void)pasteboardChangedOwner: (NSPasteboard*)sender
 {
+  GtkDragSourceInfo *info;
+  if (context != gdk_quartz_drag_source_context())
+    {
+      context = NULL;
+      return;
+    }
+  info = gtk_drag_get_source_info (context, FALSE);
+  if (!info) return;
+
     info->target_list = NULL;
     info->widget = NULL;
     info->source_widget = NULL;
 }
 
-- (id)initWithInfo:(GtkDragSourceInfo *)anInfo
+- (id)initWithContext:(GdkDragContext *)aContext
 {
   self = [super init];
 
   if (self) 
     {
-      info = anInfo;
+      context = aContext;
     }
 
   return self;
@@ -500,6 +512,7 @@ gtk_drag_dest_site_destroy (gpointer data)
     gtk_target_list_unref (site->target_list);
 
   g_free (site);
+  site = NULL;
 }
 
 void 
@@ -1089,7 +1102,7 @@ gtk_drag_begin_idle (gpointer arg)
   g_assert (info != NULL);
 
   pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
-  owner = [[GtkDragSourceOwner alloc] initWithInfo:info];
+  owner = [[GtkDragSourceOwner alloc] initWithContext:context];
 
   types = _gtk_quartz_target_list_to_pasteboard_types (info->target_list);
 
@@ -1146,11 +1159,11 @@ gtk_drag_begin_internal (GtkWidget         *widget,
 		      eventNumber: 0
 		      clickCount: 1
 		      pressure: 0.0 ];
+  GdkWindow *window = [[nswindow contentView] gdkWindow];
   g_return_val_if_fail(nsevent != NULL, NULL);
 
-  context = gdk_drag_begin (NULL, NULL);
+  context = gdk_drag_begin (window, NULL);
   g_return_val_if_fail( context != NULL, NULL);
-
   context->is_source = TRUE;
 
   info = gtk_drag_get_source_info (context, TRUE);
@@ -1218,7 +1231,7 @@ gtk_drag_begin_internal (GtkWidget         *widget,
 	    break;
 	  case GTK_IMAGE_EMPTY:
 	  default:
-	    g_assert_not_reached();
+ 	    g_assert_not_reached();
 	    break;
 	  }
     }
@@ -1874,6 +1887,7 @@ gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
   g_object_unref (info->context);
 
   g_free (info);
+  info = NULL;
 }
 
 static gboolean



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