Revision: 87416 http://trac.macports.org/changeset/87416 Author: ryandesign@macports.org Date: 2011-11-20 14:34:53 -0800 (Sun, 20 Nov 2011) Log Message: ----------- gtk2: fix drag and drop crash; see #32152 Modified Paths: -------------- trunk/dports/gnome/gtk2/Portfile Added Paths: ----------- trunk/dports/gnome/gtk2/files/658722.diff trunk/dports/gnome/gtk2/files/664238.diff Modified: trunk/dports/gnome/gtk2/Portfile =================================================================== --- trunk/dports/gnome/gtk2/Portfile 2011-11-20 21:15:16 UTC (rev 87415) +++ trunk/dports/gnome/gtk2/Portfile 2011-11-20 22:34:53 UTC (rev 87416) @@ -7,6 +7,7 @@ name gtk2 version 2.24.8 +revision 1 set branch [join [lrange [split ${version} .] 0 1] .] categories gnome x11 license LGPL-2+ @@ -34,7 +35,9 @@ sha256 ac2325a65312922a6722a7c02a389f3f4072d79e13131485cc7b7226e2537043 patchfiles patch-gtk-builder-convert.diff patch-aliases.diff \ - patch-tests_Makefile.in.diff + patch-tests_Makefile.in.diff \ + 658722.diff \ + 664238.diff depends_build port:pkgconfig \ port:perl5 Added: trunk/dports/gnome/gtk2/files/658722.diff =================================================================== --- trunk/dports/gnome/gtk2/files/658722.diff (rev 0) +++ trunk/dports/gnome/gtk2/files/658722.diff 2011-11-20 22:34:53 UTC (rev 87416) @@ -0,0 +1,270 @@ +From dcd9ab00c64a1df63fd5fa58c2ca25efd9b3e09e Mon Sep 17 00:00:00 2001 +From: John Ralls <jralls@ceridwen.us> +Date: Sat, 24 Sep 2011 18:14:09 -0700 +Subject: [PATCH 06/15] 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 [GdkQuartzNSWindow 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 (which carries the GtkQuartzDragSourceInfo +struct as qdata). 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 | 35 +++++++++++++-- + gtk/gtkdnd-quartz.c | 96 ++++++++++++++++------------------------- + 3 files changed, 69 insertions(+), 78 deletions(-) + +--- gdk/quartz/GdkQuartzWindow.c.orig ++++ 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 +--- gdk/quartz/gdkdnd-quartz.c.orig ++++ gdk/quartz/gdkdnd-quartz.c +@@ -111,11 +111,20 @@ GdkDragContext * + gdk_drag_begin (GdkWindow *window, + GList *targets) + { +- g_assert (_gdk_quartz_drag_source_context == 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,36 @@ gdk_drag_find_window_for_screen (GdkDragContext *context, + /* FIXME: Implement */ + } + ++static void ++gdk_quartz_drag_end (GdkDragContext *context) ++{ ++ GdkEvent event; ++ ++ g_assert (context != NULL); ++ 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_run_dispose (_gdk_quartz_drag_source_context); ++ _gdk_quartz_drag_source_context = NULL; ++} ++ + void + gdk_drag_drop (GdkDragContext *context, + guint32 time) + { +- /* FIXME: Implement */ ++ gdk_quartz_drag_end (context); + } + + void + gdk_drag_abort (GdkDragContext *context, + guint32 time) + { +- g_return_if_fail (context != NULL); +- +- /* FIXME: Implement */ ++ g_warning ("Gdk-quartz-drag-drop, aborting\n"); ++ gdk_quartz_drag_end (context); + } + + void +diff --git a/gtk/gtkdnd-quartz.c b/gtk/gtkdnd-quartz.c +index 5688568..be92a22 100644 +--- gtk/gtkdnd-quartz.c.orig ++++ gtk/gtkdnd-quartz.c +@@ -269,6 +269,39 @@ gtk_drag_dest_info_destroy (gpointer data) + g_free (info); + } + ++static void ++gtk_drag_source_info_destroy (GtkDragSourceInfo *info) ++{ ++ NSPasteboard *pasteboard; ++ NSAutoreleasePool *pool; ++ ++ if (info->icon_pixbuf) ++ g_object_unref (info->icon_pixbuf); ++ ++ g_signal_emit_by_name (info->widget, "drag-end", ++ info->context); ++ ++ if (info->source_widget) ++ g_object_unref (info->source_widget); ++ ++ if (info->widget) ++ g_object_unref (info->widget); ++ ++ gtk_target_list_unref (info->target_list); ++ ++ pool = [[NSAutoreleasePool alloc] init]; ++ ++ /* Empty the pasteboard, so that it will not accidentally access ++ * info->context after it has been destroyed. ++ */ ++ pasteboard = [NSPasteboard pasteboardWithName: NSDragPboard]; ++ [pasteboard declareTypes: nil owner: nil]; ++ ++ [pool release]; ++ ++ g_free (info); ++} ++ + static GtkDragDestInfo * + gtk_drag_get_dest_info (GdkDragContext *context, + gboolean create) +@@ -308,18 +341,14 @@ gtk_drag_get_source_info (GdkDragContext *context, + { + info = g_new0 (GtkDragSourceInfo, 1); + info->context = context; +- g_object_set_qdata (G_OBJECT (context), dest_info_quark, info); ++ g_object_ref (info->context); ++ g_object_set_qdata_full (G_OBJECT (context), dest_info_quark, ++ info, gtk_drag_source_info_destroy); + } + + return info; + } + +-static void +-gtk_drag_clear_source_info (GdkDragContext *context) +-{ +- g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL); +-} +- + GtkWidget * + gtk_drag_get_source_widget (GdkDragContext *context) + { +@@ -1089,7 +1118,8 @@ gtk_drag_begin_idle (gpointer arg) + [owner release]; + [types release]; + +- if ((nswindow = get_toplevel_nswindow (info->source_widget)) == NULL) ++ if (info->source_widget == NULL ++ || (nswindow = get_toplevel_nswindow (info->source_widget)) == NULL) + return FALSE; + + /* Ref the context. It's unreffed when the drag has been aborted */ +@@ -1108,7 +1138,6 @@ gtk_drag_begin_idle (gpointer arg) + source:nswindow + slideBack:YES]; + +- [info->nsevent release]; + [drag_image release]; + + [pool release]; +@@ -1833,61 +1862,12 @@ gtk_drag_set_default_icon (GdkColormap *colormap, + } + + static void +-gtk_drag_source_info_destroy (GtkDragSourceInfo *info) +-{ +- NSPasteboard *pasteboard; +- NSAutoreleasePool *pool; +- +- if (info->icon_pixbuf) +- g_object_unref (info->icon_pixbuf); +- +- g_signal_emit_by_name (info->widget, "drag-end", +- info->context); +- +- if (info->source_widget) +- g_object_unref (info->source_widget); +- +- if (info->widget) +- g_object_unref (info->widget); +- +- gtk_target_list_unref (info->target_list); +- +- pool = [[NSAutoreleasePool alloc] init]; +- +- /* Empty the pasteboard, so that it will not accidentally access +- * info->context after it has been destroyed. +- */ +- pasteboard = [NSPasteboard pasteboardWithName: NSDragPboard]; +- [pasteboard declareTypes: nil owner: nil]; +- +- [pool release]; +- +- gtk_drag_clear_source_info (info->context); +- g_object_unref (info->context); +- +- g_free (info); +- info = NULL; +-} +- +-static gboolean +-drag_drop_finished_idle_cb (gpointer data) +-{ +- gtk_drag_source_info_destroy (data); +- return FALSE; +-} +- +-static void + gtk_drag_drop_finished (GtkDragSourceInfo *info) + { + if (info->success && info->delete) + g_signal_emit_by_name (info->source_widget, "drag-data-delete", + info->context); + +- /* Workaround for the fact that the NS API blocks until the drag is +- * over. This way the context is still valid when returning from +- * drag_begin, even if it will still be quite useless. See bug #501588. +- */ +- g_idle_add (drag_drop_finished_idle_cb, info); + } + + /************************************************************* Added: trunk/dports/gnome/gtk2/files/664238.diff =================================================================== --- trunk/dports/gnome/gtk2/files/664238.diff (rev 0) +++ trunk/dports/gnome/gtk2/files/664238.diff 2011-11-20 22:34:53 UTC (rev 87416) @@ -0,0 +1,24 @@ +From ede7c10f00ca07bfcf129bb91af533a046c76e0f Mon Sep 17 00:00:00 2001 +From: John Ralls <jralls@ceridwen.us> +Date: Sat, 19 Nov 2011 11:33:28 -0800 +Subject: [PATCH] [Bug 664238] GTK apps crash when dragging something + +Corrects a bad condition in a test in fadc82ad. +--- + gtk/gtkquartz.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +--- gtk/gtkquartz.c.orig ++++ gtk/gtkquartz.c +@@ -39,7 +39,7 @@ _gtk_quartz_create_image_from_pixbuf (GdkPixbuf *pixbuf) + + pixbuf_width = gdk_pixbuf_get_width (pixbuf); + pixbuf_height = gdk_pixbuf_get_height (pixbuf); +- g_return_val_if_fail (pixbuf_width == 0 && pixbuf_height == 0, NULL); ++ g_return_val_if_fail (pixbuf_width != 0 && pixbuf_height != 0, NULL); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); + +-- +1.7.6.3.dirty +