icontheme: Keep a single string set

Instead of keeping a GtkStringSet per IconTheme,
just make one for the whole GtkIconTheme.

This avoids loops of the themes in some places, and
due to the overlap in icon names between the themes,
it reduces the amount of memory we use for the icon
names with Adwaita+hicolor from 5+4 chunks to 6 chunks.
This commit is contained in:
Matthias Clasen 2023-01-13 20:52:30 -05:00
parent 19bb043a85
commit 7c1a0e0c15

View File

@ -130,10 +130,35 @@ struct _GtkStringSet {
int used_in_chunk;
};
#ifdef G_ENABLE_DEBUG
static void
dump_string_set (GtkStringSet *set)
{
GtkStringSetChunk *chunk = set->chunks;
unsigned int n_chunks = 0;
GHashTableIter iter;
gpointer key;
while (chunk)
{
n_chunks++;
chunk = chunk->next;
}
g_print ("%u strings, %u chunks\n", g_hash_table_size (set->hash), n_chunks);
g_hash_table_iter_init (&iter, set->hash);
while (g_hash_table_iter_next (&iter, &key, NULL))
{
char *string = key;
g_print ("%s\n", string);
}
}
#endif
static void
gtk_string_set_init (GtkStringSet *set)
{
set->hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
set->hash = g_hash_table_new (g_str_hash, g_str_equal);
set->chunks = NULL;
set->used_in_chunk = STRING_SET_CHUNK_SIZE; /* To trigger a grow directly */
}
@ -306,6 +331,8 @@ struct _GtkIconTheme
GtkIconPaintable *lru_cache[LRU_CACHE_SIZE]; /* Protected by icon_cache lock */
int lru_cache_current; /* Protected by icon_cache lock */
GtkStringSet icons;
char *current_theme;
char **search_path;
char **resource_path;
@ -409,7 +436,6 @@ typedef struct
GArray *dir_sizes; /* IconThemeDirSize */
GArray *dirs; /* IconThemeDir */
GtkStringSet icons;
} IconTheme;
typedef struct
@ -465,8 +491,6 @@ static GtkIconPaintable *theme_lookup_icon (IconTheme *the
int size,
int scale,
gboolean allow_svg);
static gboolean theme_has_icon (IconTheme *theme,
const char *icon_name);
static void theme_subdir_load (GtkIconTheme *self,
IconTheme *theme,
GKeyFile *theme_file,
@ -1358,6 +1382,7 @@ blow_themes (GtkIconTheme *self)
g_list_free_full (self->themes, (GDestroyNotify) theme_destroy);
g_array_set_size (self->dir_mtimes, 0);
g_hash_table_destroy (self->unthemed_icons);
gtk_string_set_destroy (&self->icons);
}
self->themes = NULL;
self->unthemed_icons = NULL;
@ -1939,6 +1964,8 @@ load_themes (GtkIconTheme *self)
GStatBuf stat_buf;
int j;
gtk_string_set_init (&self->icons);
if (self->current_theme)
insert_theme (self, self->current_theme);
@ -2014,6 +2041,8 @@ load_themes (GtkIconTheme *self)
}
gdk_debug_message ("%s", s->str);
g_string_free (s, TRUE);
dump_string_set (&self->icons);
}
#endif
}
@ -2159,10 +2188,13 @@ real_choose_icon (GtkIconTheme *self,
theme = l->data;
for (i = 0; icon_names[i] && icon_name_is_symbolic (icon_names[i], -1); i++)
{
icon_name = icon_names[i];
icon = theme_lookup_icon (theme, icon_name, size, scale, self->pixbuf_supports_svg);
if (icon)
goto out;
icon_name = gtk_string_set_lookup (&self->icons, icon_names[i]);
if (icon_name)
{
icon = theme_lookup_icon (theme, icon_name, size, scale, self->pixbuf_supports_svg);
if (icon)
goto out;
}
}
}
@ -2172,10 +2204,13 @@ real_choose_icon (GtkIconTheme *self,
for (i = 0; icon_names[i]; i++)
{
icon_name = icon_names[i];
icon = theme_lookup_icon (theme, icon_name, size, scale, self->pixbuf_supports_svg);
if (icon)
goto out;
icon_name = gtk_string_set_lookup (&self->icons, icon_names[i]);
if (icon_name)
{
icon = theme_lookup_icon (theme, icon_name, size, scale, self->pixbuf_supports_svg);
if (icon)
goto out;
}
}
}
@ -2556,7 +2591,6 @@ gboolean
gtk_icon_theme_has_icon (GtkIconTheme *self,
const char *icon_name)
{
GList *l;
gboolean res = FALSE;
g_return_val_if_fail (GTK_IS_ICON_THEME (self), FALSE);
@ -2566,13 +2600,10 @@ gtk_icon_theme_has_icon (GtkIconTheme *self,
ensure_valid_themes (self, FALSE);
for (l = self->themes; l; l = l->next)
if (gtk_string_set_lookup (&self->icons, icon_name) != NULL)
{
if (theme_has_icon (l->data, icon_name))
{
res = TRUE;
goto out;
}
res = TRUE;
goto out;
}
out:
@ -2611,13 +2642,10 @@ gtk_icon_theme_has_gicon (GtkIconTheme *self,
for (int i = 0; names[i]; i++)
{
for (GList *l = self->themes; l; l = l->next)
if (gtk_string_set_lookup (&self->icons, names[i]) != NULL)
{
if (theme_has_icon (l->data, names[i]))
{
res = TRUE;
goto out;
}
res = TRUE;
goto out;
}
}
@ -2663,6 +2691,7 @@ gtk_icon_theme_get_icon_sizes (GtkIconTheme *self,
int i;
GHashTable *sizes;
int *result, *r;
const char *interned_icon_name;
g_return_val_if_fail (GTK_IS_ICON_THEME (self), NULL);
@ -2672,10 +2701,11 @@ gtk_icon_theme_get_icon_sizes (GtkIconTheme *self,
sizes = g_hash_table_new (g_direct_hash, g_direct_equal);
interned_icon_name = gtk_string_set_lookup (&self->icons, icon_name);
for (l = self->themes; l; l = l->next)
{
IconTheme *theme = l->data;
const char *interned_icon_name = gtk_string_set_lookup (&theme->icons, icon_name);
for (i = 0; i < theme->dir_sizes->len; i++)
{
@ -2732,25 +2762,15 @@ gtk_icon_theme_get_icon_names (GtkIconTheme *self)
char **names;
char *key;
int i;
GList *l;
gtk_icon_theme_lock (self);
ensure_valid_themes (self, FALSE);
icons = g_hash_table_new (g_str_hash, g_str_equal);
gtk_string_set_list (&self->icons, icons);
l = self->themes;
while (l != NULL)
{
IconTheme *theme = l->data;
gtk_string_set_list (&theme->icons, icons);
l = l->next;
}
g_hash_table_foreach (self->unthemed_icons,
add_key_to_hash,
icons);
g_hash_table_foreach (self->unthemed_icons, add_key_to_hash, icons);
names = g_new (char *, g_hash_table_size (icons) + 1);
@ -2809,7 +2829,6 @@ theme_new (const char *theme_name,
theme->name = g_strdup (theme_name);
theme->dir_sizes = g_array_new (FALSE, FALSE, sizeof (IconThemeDirSize));
theme->dirs = g_array_new (FALSE, FALSE, sizeof (IconThemeDir));
gtk_string_set_init (&theme->icons);
theme->display_name =
g_key_file_get_locale_string (theme_file, "Icon Theme", "Name", NULL, NULL);
@ -2840,8 +2859,6 @@ theme_destroy (IconTheme *theme)
theme_dir_destroy (&g_array_index (theme->dirs, IconThemeDir, i));
g_array_free (theme->dirs, TRUE);
gtk_string_set_destroy (&theme->icons);
g_free (theme);
}
@ -3040,13 +3057,6 @@ theme_lookup_icon (IconTheme *theme,
IconCacheFlag min_suffix;
int i;
/* Its not uncommon with misses, so we do an early check which allows us do
* do a lot less work.
* We also intern the name so later hash lookups are faster. */
icon_name = gtk_string_set_lookup (&theme->icons, icon_name);
if (icon_name == NULL)
return FALSE;
min_difference = G_MAXINT;
min_dir_size = NULL;
@ -3106,13 +3116,6 @@ theme_lookup_icon (IconTheme *theme,
return NULL;
}
static gboolean
theme_has_icon (IconTheme *theme,
const char *icon_name)
{
return gtk_string_set_lookup (&theme->icons, icon_name) != NULL;
}
static GHashTable *
scan_directory (GtkIconTheme *self,
char *full_dir,