source: trunk/dports/gnome/gtk2/files/658722.diff @ 87416

Last change on this file since 87416 was 87416, checked in by ryandesign@…, 9 years ago

gtk2: fix drag and drop crash; see #32152

File size: 8.2 KB
  • gdk/quartz/GdkQuartzWindow.c

    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(-)
    
    old new update_context_from_dragging_info (id <NSDraggingInfo> sender) 
    560560
    561561- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
    562562{
    563   GdkEvent event;
    564 
    565   g_assert (_gdk_quartz_drag_source_context != NULL);
    566 
    567   event.dnd.type = GDK_DROP_FINISHED;
    568   event.dnd.window = g_object_ref ([[self contentView] gdkWindow]);
    569   event.dnd.send_event = FALSE;
    570   event.dnd.context = _gdk_quartz_drag_source_context;
    571 
    572   (*_gdk_event_func) (&event, _gdk_event_data);
    573 
    574   g_object_unref (event.dnd.window);
    575 
    576   g_object_unref (_gdk_quartz_drag_source_context);
    577   _gdk_quartz_drag_source_context = NULL;
     563  gdk_drag_drop (_gdk_quartz_drag_source_context, (guint32)g_get_real_time());
    578564}
    579565
    580566@end
  • gdk/quartz/gdkdnd-quartz.c

    old new GdkDragContext * 
    111111gdk_drag_begin (GdkWindow     *window,
    112112                GList         *targets)
    113113{
    114   g_assert (_gdk_quartz_drag_source_context == NULL);
     114  if (_gdk_quartz_drag_source_context != NULL)
     115    {
     116      /* Something is amiss with the existing drag, so log a message
     117         and abort it */
     118      g_warning ("Drag begun with existing context; aborting the preexisting drag");
     119      gdk_drag_abort (_gdk_quartz_drag_source_context,
     120                      (guint32)g_get_real_time ());
     121    }
     122
    115123 
    116124  /* Create fake context */
    117125  _gdk_quartz_drag_source_context = gdk_drag_context_new ();
    118126  _gdk_quartz_drag_source_context->is_source = TRUE;
     127  _gdk_quartz_drag_source_context->source_window = window;
    119128 
    120129  return _gdk_quartz_drag_source_context;
    121130}
    gdk_drag_find_window_for_screen (GdkDragContext *context, 
    155164  /* FIXME: Implement */
    156165}
    157166
     167static void
     168gdk_quartz_drag_end (GdkDragContext *context)
     169{
     170  GdkEvent event;
     171
     172  g_assert (context != NULL);
     173  event.dnd.type = GDK_DROP_FINISHED;
     174  event.dnd.window = g_object_ref (context->source_window);
     175  event.dnd.send_event = FALSE;
     176  event.dnd.context = context;
     177
     178  (*_gdk_event_func) (&event, _gdk_event_data);
     179
     180  g_object_run_dispose (_gdk_quartz_drag_source_context);
     181  _gdk_quartz_drag_source_context = NULL;
     182}
     183
    158184void
    159185gdk_drag_drop (GdkDragContext *context,
    160186               guint32         time)
    161187{
    162   /* FIXME: Implement */
     188  gdk_quartz_drag_end (context);
    163189}
    164190
    165191void
    166192gdk_drag_abort (GdkDragContext *context,
    167193                guint32         time)
    168194{
    169   g_return_if_fail (context != NULL);
    170  
    171   /* FIXME: Implement */
     195  g_warning ("Gdk-quartz-drag-drop, aborting\n");
     196  gdk_quartz_drag_end (context);
    172197}
    173198
    174199void             
  • gtk/gtkdnd-quartz.c

    diff --git a/gtk/gtkdnd-quartz.c b/gtk/gtkdnd-quartz.c
    index 5688568..be92a22 100644
    old new gtk_drag_dest_info_destroy (gpointer data) 
    269269  g_free (info);
    270270}
    271271
     272static void
     273gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
     274{
     275  NSPasteboard *pasteboard;
     276  NSAutoreleasePool *pool;
     277
     278  if (info->icon_pixbuf)
     279    g_object_unref (info->icon_pixbuf);
     280
     281  g_signal_emit_by_name (info->widget, "drag-end",
     282                         info->context);
     283
     284  if (info->source_widget)
     285    g_object_unref (info->source_widget);
     286
     287  if (info->widget)
     288    g_object_unref (info->widget);
     289
     290  gtk_target_list_unref (info->target_list);
     291
     292  pool = [[NSAutoreleasePool alloc] init];
     293
     294  /* Empty the pasteboard, so that it will not accidentally access
     295   * info->context after it has been destroyed.
     296   */
     297  pasteboard = [NSPasteboard pasteboardWithName: NSDragPboard];
     298  [pasteboard declareTypes: nil owner: nil];
     299
     300  [pool release];
     301
     302  g_free (info);
     303}
     304
    272305static GtkDragDestInfo *
    273306gtk_drag_get_dest_info (GdkDragContext *context,
    274307                        gboolean        create)
    gtk_drag_get_source_info (GdkDragContext *context, 
    308341    {
    309342      info = g_new0 (GtkDragSourceInfo, 1);
    310343      info->context = context;
    311       g_object_set_qdata (G_OBJECT (context), dest_info_quark, info);
     344      g_object_ref (info->context);
     345      g_object_set_qdata_full (G_OBJECT (context), dest_info_quark,
     346                               info, gtk_drag_source_info_destroy);
    312347    }
    313348
    314349  return info;
    315350}
    316351
    317 static void
    318 gtk_drag_clear_source_info (GdkDragContext *context)
    319 {
    320   g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL);
    321 }
    322 
    323352GtkWidget *
    324353gtk_drag_get_source_widget (GdkDragContext *context)
    325354{
    gtk_drag_begin_idle (gpointer arg) 
    10891118  [owner release];
    10901119  [types release];
    10911120
    1092   if ((nswindow = get_toplevel_nswindow (info->source_widget)) == NULL)
     1121  if (info->source_widget == NULL
     1122      || (nswindow = get_toplevel_nswindow (info->source_widget)) == NULL)
    10931123     return FALSE;
    10941124 
    10951125  /* Ref the context. It's unreffed when the drag has been aborted */
    gtk_drag_begin_idle (gpointer arg) 
    11081138               source:nswindow
    11091139            slideBack:YES];
    11101140
    1111   [info->nsevent release];
    11121141  [drag_image release];
    11131142
    11141143  [pool release];
    gtk_drag_set_default_icon (GdkColormap *colormap, 
    18331862}
    18341863
    18351864static void
    1836 gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
    1837 {
    1838   NSPasteboard *pasteboard;
    1839   NSAutoreleasePool *pool;
    1840 
    1841   if (info->icon_pixbuf)
    1842     g_object_unref (info->icon_pixbuf);
    1843 
    1844   g_signal_emit_by_name (info->widget, "drag-end",
    1845                          info->context);
    1846 
    1847   if (info->source_widget)
    1848     g_object_unref (info->source_widget);
    1849 
    1850   if (info->widget)
    1851     g_object_unref (info->widget);
    1852 
    1853   gtk_target_list_unref (info->target_list);
    1854 
    1855   pool = [[NSAutoreleasePool alloc] init];
    1856 
    1857   /* Empty the pasteboard, so that it will not accidentally access
    1858    * info->context after it has been destroyed.
    1859    */
    1860   pasteboard = [NSPasteboard pasteboardWithName: NSDragPboard];
    1861   [pasteboard declareTypes: nil owner: nil];
    1862 
    1863   [pool release];
    1864 
    1865   gtk_drag_clear_source_info (info->context);
    1866   g_object_unref (info->context);
    1867 
    1868   g_free (info);
    1869   info = NULL;
    1870 }
    1871 
    1872 static gboolean
    1873 drag_drop_finished_idle_cb (gpointer data)
    1874 {
    1875   gtk_drag_source_info_destroy (data);
    1876   return FALSE;
    1877 }
    1878 
    1879 static void
    18801865gtk_drag_drop_finished (GtkDragSourceInfo *info)
    18811866{
    18821867  if (info->success && info->delete)
    18831868    g_signal_emit_by_name (info->source_widget, "drag-data-delete",
    18841869                           info->context);
    18851870
    1886   /* Workaround for the fact that the NS API blocks until the drag is
    1887    * over. This way the context is still valid when returning from
    1888    * drag_begin, even if it will still be quite useless. See bug #501588.
    1889   */
    1890   g_idle_add (drag_drop_finished_idle_cb, info);
    18911871}
    18921872
    18931873/*************************************************************
Note: See TracBrowser for help on using the repository browser.