IconCache: Keep a ref on the GtkIconData
The icon data in GttkIconInfo->data is currently owned by the IconThemeDir->icon_data hashtable. However, on e.g. a theme change blow_themes() destroys the dirs and thus the data, meaning any outstanding GtkIconInfo points to stale data. We solve this by adding a refcount to GtkIconData and reffing it from GtkIconInfo. https://bugzilla.gnome.org/show_bug.cgi?id=702598
This commit is contained in:
@ -520,6 +520,7 @@ _gtk_icon_cache_get_icon_data (GtkIconCache *cache,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
data = g_slice_new0 (GtkIconData);
|
data = g_slice_new0 (GtkIconData);
|
||||||
|
data->ref = 1;
|
||||||
|
|
||||||
offset = GET_UINT32 (cache->buffer, meta_data_offset);
|
offset = GET_UINT32 (cache->buffer, meta_data_offset);
|
||||||
if (offset)
|
if (offset)
|
||||||
|
|||||||
@ -25,6 +25,7 @@ typedef struct _GtkIconData GtkIconData;
|
|||||||
|
|
||||||
struct _GtkIconData
|
struct _GtkIconData
|
||||||
{
|
{
|
||||||
|
gint ref;
|
||||||
gboolean has_embedded_rect;
|
gboolean has_embedded_rect;
|
||||||
gint x0, y0, x1, y1;
|
gint x0, y0, x1, y1;
|
||||||
|
|
||||||
|
|||||||
@ -350,7 +350,8 @@ static void blow_themes (GtkIconTheme *icon_themes);
|
|||||||
static gboolean rescan_themes (GtkIconTheme *icon_themes);
|
static gboolean rescan_themes (GtkIconTheme *icon_themes);
|
||||||
|
|
||||||
static GtkIconData *icon_data_dup (GtkIconData *icon_data);
|
static GtkIconData *icon_data_dup (GtkIconData *icon_data);
|
||||||
static void icon_data_free (GtkIconData *icon_data);
|
static GtkIconData *icon_data_ref (GtkIconData *icon_data);
|
||||||
|
static void icon_data_unref (GtkIconData *icon_data);
|
||||||
static void load_icon_data (IconThemeDir *dir,
|
static void load_icon_data (IconThemeDir *dir,
|
||||||
const char *path,
|
const char *path,
|
||||||
const char *name);
|
const char *name);
|
||||||
@ -2606,9 +2607,9 @@ theme_lookup_icon (IconTheme *theme,
|
|||||||
icon_info->filename = NULL;
|
icon_info->filename = NULL;
|
||||||
icon_info->icon_file = NULL;
|
icon_info->icon_file = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (min_dir->icon_data != NULL)
|
if (min_dir->icon_data != NULL)
|
||||||
icon_info->data = g_hash_table_lookup (min_dir->icon_data, icon_name);
|
icon_info->data = icon_data_ref (g_hash_table_lookup (min_dir->icon_data, icon_name));
|
||||||
|
|
||||||
if (icon_info->data == NULL && min_dir->cache != NULL)
|
if (icon_info->data == NULL && min_dir->cache != NULL)
|
||||||
{
|
{
|
||||||
@ -2617,9 +2618,9 @@ theme_lookup_icon (IconTheme *theme,
|
|||||||
{
|
{
|
||||||
if (min_dir->icon_data == NULL)
|
if (min_dir->icon_data == NULL)
|
||||||
min_dir->icon_data = g_hash_table_new_full (g_str_hash, g_str_equal,
|
min_dir->icon_data = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
g_free, (GDestroyNotify)icon_data_free);
|
g_free, (GDestroyNotify)icon_data_unref);
|
||||||
|
|
||||||
g_hash_table_replace (min_dir->icon_data, g_strdup (icon_name), icon_info->data);
|
g_hash_table_replace (min_dir->icon_data, g_strdup (icon_name), icon_data_ref (icon_info->data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2634,10 +2635,10 @@ theme_lookup_icon (IconTheme *theme,
|
|||||||
{
|
{
|
||||||
if (min_dir->icon_data == NULL)
|
if (min_dir->icon_data == NULL)
|
||||||
min_dir->icon_data = g_hash_table_new_full (g_str_hash, g_str_equal,
|
min_dir->icon_data = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
g_free, (GDestroyNotify)icon_data_free);
|
g_free, (GDestroyNotify)icon_data_unref);
|
||||||
load_icon_data (min_dir, icon_file_path, icon_file_name);
|
load_icon_data (min_dir, icon_file_path, icon_file_name);
|
||||||
|
|
||||||
icon_info->data = g_hash_table_lookup (min_dir->icon_data, icon_name);
|
icon_info->data = icon_data_ref (g_hash_table_lookup (min_dir->icon_data, icon_name));
|
||||||
}
|
}
|
||||||
g_free (icon_file_name);
|
g_free (icon_file_name);
|
||||||
g_free (icon_file_path);
|
g_free (icon_file_path);
|
||||||
@ -2726,7 +2727,6 @@ load_icon_data (IconThemeDir *dir, const char *path, const char *name)
|
|||||||
int i;
|
int i;
|
||||||
gint *ivalues;
|
gint *ivalues;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
GtkIconData *data;
|
GtkIconData *data;
|
||||||
|
|
||||||
icon_file = g_key_file_new ();
|
icon_file = g_key_file_new ();
|
||||||
@ -2741,8 +2741,10 @@ load_icon_data (IconThemeDir *dir, const char *path, const char *name)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
base_name = strip_suffix (name);
|
base_name = strip_suffix (name);
|
||||||
|
|
||||||
data = g_slice_new0 (GtkIconData);
|
data = g_slice_new0 (GtkIconData);
|
||||||
|
data->ref = 1;
|
||||||
|
|
||||||
/* takes ownership of base_name */
|
/* takes ownership of base_name */
|
||||||
g_hash_table_replace (dir->icon_data, base_name, data);
|
g_hash_table_replace (dir->icon_data, base_name, data);
|
||||||
|
|
||||||
@ -2823,7 +2825,7 @@ scan_directory (GtkIconThemePrivate *icon_theme,
|
|||||||
{
|
{
|
||||||
if (dir->icon_data == NULL)
|
if (dir->icon_data == NULL)
|
||||||
dir->icon_data = g_hash_table_new_full (g_str_hash, g_str_equal,
|
dir->icon_data = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
g_free, (GDestroyNotify)icon_data_free);
|
g_free, (GDestroyNotify)icon_data_unref);
|
||||||
|
|
||||||
path = g_build_filename (full_dir, name, NULL);
|
path = g_build_filename (full_dir, name, NULL);
|
||||||
if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
|
if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
|
||||||
@ -2962,12 +2964,27 @@ theme_subdir_load (GtkIconTheme *icon_theme,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static GtkIconData *
|
||||||
icon_data_free (GtkIconData *icon_data)
|
icon_data_ref (GtkIconData *icon_data)
|
||||||
{
|
{
|
||||||
g_free (icon_data->attach_points);
|
if (icon_data)
|
||||||
g_free (icon_data->display_name);
|
icon_data->ref++;
|
||||||
g_slice_free (GtkIconData, icon_data);
|
return icon_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
icon_data_unref (GtkIconData *icon_data)
|
||||||
|
{
|
||||||
|
if (icon_data)
|
||||||
|
{
|
||||||
|
icon_data->ref--;
|
||||||
|
if (icon_data->ref == 0)
|
||||||
|
{
|
||||||
|
g_free (icon_data->attach_points);
|
||||||
|
g_free (icon_data->display_name);
|
||||||
|
g_slice_free (GtkIconData, icon_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GtkIconData *
|
static GtkIconData *
|
||||||
@ -2977,6 +2994,7 @@ icon_data_dup (GtkIconData *icon_data)
|
|||||||
if (icon_data)
|
if (icon_data)
|
||||||
{
|
{
|
||||||
dup = g_slice_new0 (GtkIconData);
|
dup = g_slice_new0 (GtkIconData);
|
||||||
|
dup->ref = 1;
|
||||||
*dup = *icon_data;
|
*dup = *icon_data;
|
||||||
if (dup->n_attach_points > 0)
|
if (dup->n_attach_points > 0)
|
||||||
{
|
{
|
||||||
@ -3125,6 +3143,7 @@ gtk_icon_info_finalize (GObject *object)
|
|||||||
g_object_unref (icon_info->cache_pixbuf);
|
g_object_unref (icon_info->cache_pixbuf);
|
||||||
if (icon_info->symbolic_pixbuf_size)
|
if (icon_info->symbolic_pixbuf_size)
|
||||||
gtk_requisition_free (icon_info->symbolic_pixbuf_size);
|
gtk_requisition_free (icon_info->symbolic_pixbuf_size);
|
||||||
|
icon_data_unref (icon_info->data);
|
||||||
|
|
||||||
symbolic_pixbuf_cache_free (icon_info->symbolic_pixbuf_cache);
|
symbolic_pixbuf_cache_free (icon_info->symbolic_pixbuf_cache);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user