Decouple GdkWindowCache life-cycle from GdkX11DragContext
By making window caches refcounted. This fixes problems with leaking drag contexts, as experienced in https://bugzilla.gnome.org/show_bug.cgi?id=637691 and https://bugzilla.gnome.org/show_bug.cgi?id=144324 Based on a patch by drago01@gmail.com
This commit is contained in:
		@ -68,6 +68,7 @@ typedef struct {
 | 
				
			|||||||
  GHashTable *child_hash;
 | 
					  GHashTable *child_hash;
 | 
				
			||||||
  guint old_event_mask;
 | 
					  guint old_event_mask;
 | 
				
			||||||
  GdkScreen *screen;
 | 
					  GdkScreen *screen;
 | 
				
			||||||
 | 
					  gint ref_count;
 | 
				
			||||||
} GdkWindowCache;
 | 
					} GdkWindowCache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -105,7 +106,9 @@ struct _GdkX11DragContextClass
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Forward declarations */
 | 
					/* Forward declarations */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gdk_window_cache_destroy (GdkWindowCache *cache);
 | 
					static GdkWindowCache *gdk_window_cache_get   (GdkScreen      *screen);
 | 
				
			||||||
 | 
					static GdkWindowCache *gdk_window_cache_ref   (GdkWindowCache *cache);
 | 
				
			||||||
 | 
					static void            gdk_window_cache_unref (GdkWindowCache *cache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void motif_read_target_table (GdkDisplay *display);
 | 
					static void motif_read_target_table (GdkDisplay *display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -137,6 +140,7 @@ static void   xdnd_manage_source_filter (GdkDragContext *context,
 | 
				
			|||||||
                                         gboolean        add_filter);
 | 
					                                         gboolean        add_filter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static GList *contexts;
 | 
					static GList *contexts;
 | 
				
			||||||
 | 
					static GSList *window_caches;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct {
 | 
					static const struct {
 | 
				
			||||||
  const char *atom_name;
 | 
					  const char *atom_name;
 | 
				
			||||||
@ -212,8 +216,8 @@ gdk_x11_drag_context_class_init (GdkX11DragContextClass *klass)
 | 
				
			|||||||
static void
 | 
					static void
 | 
				
			||||||
gdk_x11_drag_context_finalize (GObject *object)
 | 
					gdk_x11_drag_context_finalize (GObject *object)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  GdkX11DragContext *context_x11 = GDK_X11_DRAG_CONTEXT (object);
 | 
					 | 
				
			||||||
  GdkDragContext *context = GDK_DRAG_CONTEXT (object);
 | 
					  GdkDragContext *context = GDK_DRAG_CONTEXT (object);
 | 
				
			||||||
 | 
					  GdkX11DragContext *x11_context = GDK_X11_DRAG_CONTEXT (object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (context->source_window)
 | 
					  if (context->source_window)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -221,7 +225,8 @@ gdk_x11_drag_context_finalize (GObject *object)
 | 
				
			|||||||
        xdnd_manage_source_filter (context, context->source_window, FALSE);
 | 
					        xdnd_manage_source_filter (context, context->source_window, FALSE);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  g_slist_free_full (context_x11->window_caches, (GDestroyNotify)gdk_window_cache_destroy);
 | 
					  g_slist_free_full (x11_context->window_caches, (GDestroyNotify)gdk_window_cache_unref);
 | 
				
			||||||
 | 
					  x11_context->window_caches = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  contexts = g_list_remove (contexts, context);
 | 
					  contexts = g_list_remove (contexts, context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -509,6 +514,7 @@ gdk_window_cache_new (GdkScreen *screen)
 | 
				
			|||||||
  result->children = NULL;
 | 
					  result->children = NULL;
 | 
				
			||||||
  result->child_hash = g_hash_table_new (g_direct_hash, NULL);
 | 
					  result->child_hash = g_hash_table_new (g_direct_hash, NULL);
 | 
				
			||||||
  result->screen = screen;
 | 
					  result->screen = screen;
 | 
				
			||||||
 | 
					  result->ref_count = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  XGetWindowAttributes (xdisplay, GDK_WINDOW_XID (root_window), &xwa);
 | 
					  XGetWindowAttributes (xdisplay, GDK_WINDOW_XID (root_window), &xwa);
 | 
				
			||||||
  result->old_event_mask = xwa.your_event_mask;
 | 
					  result->old_event_mask = xwa.your_event_mask;
 | 
				
			||||||
@ -595,6 +601,48 @@ gdk_window_cache_destroy (GdkWindowCache *cache)
 | 
				
			|||||||
  g_free (cache);
 | 
					  g_free (cache);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GdkWindowCache *
 | 
				
			||||||
 | 
					gdk_window_cache_ref (GdkWindowCache *cache)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  cache->ref_count += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return cache;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					gdk_window_cache_unref (GdkWindowCache *cache)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  g_assert (cache->ref_count > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cache->ref_count -= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (cache->ref_count == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      window_caches = g_slist_remove (window_caches, cache);
 | 
				
			||||||
 | 
					      gdk_window_cache_destroy (cache);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GdkWindowCache *
 | 
				
			||||||
 | 
					gdk_window_cache_get (GdkScreen *screen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  GSList *list;
 | 
				
			||||||
 | 
					  GdkWindowCache *cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (list = window_caches; list; list = list->next)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      cache = list->data;
 | 
				
			||||||
 | 
					      if (cache->screen == screen)
 | 
				
			||||||
 | 
					        return gdk_window_cache_ref (cache);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cache = gdk_window_cache_new (screen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  window_caches = g_slist_prepend (window_caches, cache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return cache;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static gboolean
 | 
					static gboolean
 | 
				
			||||||
is_pointer_within_shape (GdkDisplay    *display,
 | 
					is_pointer_within_shape (GdkDisplay    *display,
 | 
				
			||||||
                         GdkCacheChild *child,
 | 
					                         GdkCacheChild *child,
 | 
				
			||||||
@ -3229,7 +3277,7 @@ drag_context_find_window_cache (GdkX11DragContext *context_x11,
 | 
				
			|||||||
        return cache;
 | 
					        return cache;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  cache = gdk_window_cache_new (screen);
 | 
					  cache = gdk_window_cache_get (screen);
 | 
				
			||||||
  context_x11->window_caches = g_slist_prepend (context_x11->window_caches, cache);
 | 
					  context_x11->window_caches = g_slist_prepend (context_x11->window_caches, cache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return cache;
 | 
					  return cache;
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user