[gtk: 2/5] IconTheme: Make icon lookups faster
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk: 2/5] IconTheme: Make icon lookups faster
- Date: Tue, 4 Feb 2020 10:54:32 +0000 (UTC)
commit e4170661b9228cb3e09dbc1cd789e15ef44f4ef5
Author: Alexander Larsson <alexl redhat com>
Date: Mon Feb 3 10:35:45 2020 +0100
IconTheme: Make icon lookups faster
Traditionally the icon lookup for a theme has been:
lookup (icon_name, size):
best_directory = NULL
forearch theme
foreach directory in theme
if dir_size_matches (directory, size) && dir_has_icon (directory, icon-name)
best_directory = chose_best_size_dir (best_directory, directory)
if best_directory
return icon from best_directory
However, it turns out that there are a lot of subdirectories which have the same
size, as they differ only in the (essentially useless) "context" value. For example
the "16x16/apps" subdirectory is essentially the same as the "16x16/actions" one.
So, instead rathern than keeping all the directories as separate we store the
all the directories with the same size as a single entity (DirSize) and the
icon lookup in that DirSize looks up not only which suffix to use for that icon
but also which subdir it is in.
Additionally we keep a hashtable with all icon names that are
available in the entire theme (i.e. all DirSizes), which allows use
both to store each icon name only once, but also to do a quick
negative lookup and early exit in case we're looking up an icon that
doesn't exist. This is pretty common because we often look up sets of
icons like "image-png-symbolic", "image-png", "image", expecting some
to fail.
This brings down the time of the initial css validation from 20msec to 15msec for
me when running icon-factory.
gtk/gtkicontheme.c | 679 +++++++++++++++++++++++++++++------------------------
1 file changed, 370 insertions(+), 309 deletions(-)
---
diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
index ae33375bce..1ec6715a75 100644
--- a/gtk/gtkicontheme.c
+++ b/gtk/gtkicontheme.c
@@ -326,29 +326,36 @@ typedef struct
gchar *display_name;
gchar *comment;
- /* In search order */
- GList *dirs;
+ GArray *dir_sizes; /* IconThemeDirSize */
+ GArray *dirs; /* IconThemeDir */
+ GHashTable *icons; /* name (owned) -> name */
} IconTheme;
typedef struct
{
- IconThemeDirType type;
- GQuark context;
+ guint16 dir_index; /* index in dirs */
+ guint8 best_suffix;
+ guint8 best_suffix_no_svg;
+} IconThemeFile;
+typedef struct
+{
+ IconThemeDirType type;
gint size;
gint min_size;
gint max_size;
gint threshold;
gint scale;
- gboolean is_resource;
-
- gchar *dir;
- gchar *subdir;
- gint subdir_index;
- GtkIconCache *cache;
+ GArray *icon_files;
+ GHashTable *icon_hash; /* name (unowned) -> file index */
+} IconThemeDirSize;
- GHashTable *icons;
+typedef struct
+{
+ GQuark context;
+ gboolean is_resource;
+ char *path; /* e.g. "/usr/share/icons/hicolor/32x32/apps" */
} IconThemeDir;
typedef struct
@@ -368,6 +375,9 @@ typedef struct
static void gtk_icon_theme_finalize (GObject *object);
static void gtk_icon_theme_dispose (GObject *object);
+static IconTheme *theme_new (const char *theme_name,
+ GKeyFile *theme_file);
+static void theme_dir_size_destroy (IconThemeDirSize *dir_size);
static void theme_dir_destroy (IconThemeDir *dir);
static void theme_destroy (IconTheme *theme);
static GtkIcon * theme_lookup_icon (IconTheme *theme,
@@ -387,8 +397,6 @@ static void theme_subdir_load (GtkIconTheme *self,
static void do_theme_change (GtkIconTheme *self);
static void blow_themes (GtkIconTheme *self);
static gboolean rescan_themes (GtkIconTheme *self);
-static IconSuffix theme_dir_get_icon_suffix (IconThemeDir *dir,
- const gchar *icon_name);
static GtkIcon * icon_new (IconThemeDirType type,
gint dir_size,
gint dir_scale);
@@ -1508,47 +1516,31 @@ insert_theme (GtkIconTheme *self,
g_free (path);
}
- if (theme_file || strcmp (theme_name, FALLBACK_ICON_THEME) == 0)
+ if (theme_file == NULL)
{
- theme = g_new0 (IconTheme, 1);
- theme->name = g_strdup (theme_name);
- self->themes = g_list_prepend (self->themes, theme);
- if (!theme_file)
+ if (strcmp (theme_name, FALLBACK_ICON_THEME) == 0)
{
theme_file = g_key_file_new ();
g_key_file_set_list_separator (theme_file, ',');
g_key_file_load_from_data (theme_file, builtin_hicolor_index, -1, 0, NULL);
}
+ else
+ return;
}
- if (theme_file == NULL)
- return;
-
- theme->display_name =
- g_key_file_get_locale_string (theme_file, "Icon Theme", "Name", NULL, NULL);
- if (!theme->display_name)
- g_warning ("Theme file for %s has no name", theme_name);
-
dirs = g_key_file_get_string_list (theme_file, "Icon Theme", "Directories", NULL, NULL);
if (!dirs)
{
g_warning ("Theme file for %s has no directories", theme_name);
- self->themes = g_list_remove (self->themes, theme);
- g_free (theme->name);
- g_free (theme->display_name);
- g_free (theme);
g_key_file_free (theme_file);
return;
}
scaled_dirs = g_key_file_get_string_list (theme_file, "Icon Theme", "ScaledDirectories", NULL, NULL);
- theme->comment =
- g_key_file_get_locale_string (theme_file,
- "Icon Theme", "Comment",
- NULL, NULL);
+ theme = theme_new (theme_name, theme_file);
+ self->themes = g_list_prepend (self->themes, theme);
- theme->dirs = NULL;
for (i = 0; dirs[i] != NULL; i++)
theme_subdir_load (self, theme, theme_file, dirs[i]);
@@ -1557,11 +1549,10 @@ insert_theme (GtkIconTheme *self,
for (i = 0; scaled_dirs[i] != NULL; i++)
theme_subdir_load (self, theme, theme_file, scaled_dirs[i]);
}
+
g_strfreev (dirs);
g_strfreev (scaled_dirs);
- theme->dirs = g_list_reverse (theme->dirs);
-
themes = g_key_file_get_string_list (theme_file,
"Icon Theme",
"Inherits",
@@ -2639,18 +2630,6 @@ gtk_icon_theme_has_icon (GtkIconTheme *self,
ensure_valid_themes (self, FALSE);
- for (l = self->dir_mtimes; l; l = l->next)
- {
- IconThemeDirMtime *dir_mtime = l->data;
- GtkIconCache *cache = dir_mtime->cache;
-
- if (cache && gtk_icon_cache_has_icon (cache, icon_name))
- {
- res = TRUE;
- goto out;
- }
- }
-
for (l = self->themes; l; l = l->next)
{
if (theme_has_icon (l->data, icon_name))
@@ -2697,10 +2676,10 @@ gint *
gtk_icon_theme_get_icon_sizes (GtkIconTheme *self,
const gchar *icon_name)
{
- GList *l, *d;
+ GList *l;
+ int i;
GHashTable *sizes;
gint *result, *r;
- guint suffix;
g_return_val_if_fail (GTK_IS_ICON_THEME (self), NULL);
@@ -2713,21 +2692,21 @@ gtk_icon_theme_get_icon_sizes (GtkIconTheme *self,
for (l = self->themes; l; l = l->next)
{
IconTheme *theme = l->data;
- for (d = theme->dirs; d; d = d->next)
+
+ for (i = 0; i < theme->dir_sizes->len; i++)
{
- IconThemeDir *dir = d->data;
+ IconThemeDirSize *dir_size = &g_array_index (theme->dir_sizes, IconThemeDirSize, i);
- if (dir->type != ICON_THEME_DIR_SCALABLE && g_hash_table_lookup_extended (sizes, GINT_TO_POINTER
(dir->size), NULL, NULL))
+ if (dir_size->type != ICON_THEME_DIR_SCALABLE && g_hash_table_lookup_extended (sizes,
GINT_TO_POINTER (dir_size->size), NULL, NULL))
continue;
- suffix = theme_dir_get_icon_suffix (dir, icon_name);
- if (suffix != ICON_SUFFIX_NONE)
- {
- if (suffix == ICON_SUFFIX_SVG)
- g_hash_table_insert (sizes, GINT_TO_POINTER (-1), NULL);
- else
- g_hash_table_insert (sizes, GINT_TO_POINTER (dir->size), NULL);
- }
+ if (!g_hash_table_contains (dir_size->icon_hash, icon_name))
+ continue;
+
+ if (dir_size->type == ICON_THEME_DIR_SCALABLE)
+ g_hash_table_insert (sizes, GINT_TO_POINTER (-1), NULL);
+ else
+ g_hash_table_insert (sizes, GINT_TO_POINTER (dir_size->size), NULL);
}
}
@@ -2895,57 +2874,92 @@ gtk_icon_theme_rescan_if_needed (GtkIconTheme *self)
return retval;
}
+static IconTheme *
+theme_new (const char *theme_name,
+ GKeyFile *theme_file)
+{
+ IconTheme *theme;
+
+ theme = g_new0 (IconTheme, 1);
+ 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));
+ theme->icons = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ theme->display_name =
+ g_key_file_get_locale_string (theme_file, "Icon Theme", "Name", NULL, NULL);
+ if (!theme->display_name)
+ g_warning ("Theme file for %s has no name", theme_name);
+
+ theme->comment =
+ g_key_file_get_locale_string (theme_file,
+ "Icon Theme", "Comment",
+ NULL, NULL);
+ return theme;
+}
+
static void
theme_destroy (IconTheme *theme)
{
+ gsize i;
+
+ g_free (theme->name);
g_free (theme->display_name);
g_free (theme->comment);
- g_free (theme->name);
- g_list_free_full (theme->dirs, (GDestroyNotify) theme_dir_destroy);
+ for (i = 0; i < theme->dir_sizes->len; i++)
+ theme_dir_size_destroy (&g_array_index (theme->dir_sizes, IconThemeDirSize, i));
+ g_array_free (theme->dir_sizes, TRUE);
+
+ for (i = 0; i < theme->dirs->len; i++)
+ theme_dir_destroy (&g_array_index (theme->dirs, IconThemeDir, i));
+ g_array_free (theme->dirs, TRUE);
+ g_hash_table_destroy (theme->icons);
g_free (theme);
}
static void
-theme_dir_destroy (IconThemeDir *dir)
+theme_dir_size_destroy (IconThemeDirSize *dir)
{
- if (dir->cache)
- gtk_icon_cache_unref (dir->cache);
- if (dir->icons)
- g_hash_table_destroy (dir->icons);
+ if (dir->icon_hash)
+ g_hash_table_destroy (dir->icon_hash);
+ if (dir->icon_files)
+ g_array_free (dir->icon_files, TRUE);
+}
- g_free (dir->dir);
- g_free (dir->subdir);
- g_free (dir);
+static void
+theme_dir_destroy (IconThemeDir *dir)
+{
+ g_free (dir->path);
}
static int
-theme_dir_size_difference (IconThemeDir *dir,
- gint size,
- gint scale)
+theme_dir_size_difference (IconThemeDirSize *dir_size,
+ gint size,
+ gint scale)
{
gint scaled_size, scaled_dir_size;
gint min, max;
scaled_size = size * scale;
- scaled_dir_size = dir->size * dir->scale;
+ scaled_dir_size = dir_size->size * dir_size->scale;
- switch (dir->type)
+ switch (dir_size->type)
{
case ICON_THEME_DIR_FIXED:
return abs (scaled_size - scaled_dir_size);
case ICON_THEME_DIR_SCALABLE:
- if (scaled_size < (dir->min_size * dir->scale))
- return (dir->min_size * dir->scale) - scaled_size;
- if (size > (dir->max_size * dir->scale))
- return scaled_size - (dir->max_size * dir->scale);
+ if (scaled_size < (dir_size->min_size * dir_size->scale))
+ return (dir_size->min_size * dir_size->scale) - scaled_size;
+ if (size > (dir_size->max_size * dir_size->scale))
+ return scaled_size - (dir_size->max_size * dir_size->scale);
return 0;
case ICON_THEME_DIR_THRESHOLD:
- min = (dir->size - dir->threshold) * dir->scale;
- max = (dir->size + dir->threshold) * dir->scale;
+ min = (dir_size->size - dir_size->threshold) * dir_size->scale;
+ max = (dir_size->size + dir_size->threshold) * dir_size->scale;
if (scaled_size < min)
return min - scaled_size;
if (scaled_size > max)
@@ -3022,53 +3036,12 @@ best_suffix (IconSuffix suffix,
return ICON_SUFFIX_NONE;
}
-static IconSuffix
-theme_dir_get_icon_suffix (IconThemeDir *dir,
- const gchar *icon_name)
-{
- IconSuffix suffix, symbolic_suffix;
-
- if (dir->cache)
- {
- int icon_name_len = strlen (icon_name);
-
- if (icon_name_is_symbolic (icon_name, icon_name_len))
- {
- /* Look for foo-symbolic.symbolic.png, as the cache only stores the ".png" suffix */
- char *icon_name_with_prefix = g_strconcat (icon_name, ".symbolic", NULL);
- symbolic_suffix = (IconSuffix)gtk_icon_cache_get_icon_flags (dir->cache,
- icon_name_with_prefix,
- dir->subdir_index);
- g_free (icon_name_with_prefix);
-
- if (symbolic_suffix & ICON_SUFFIX_PNG)
- suffix = ICON_SUFFIX_SYMBOLIC_PNG;
- else
- suffix = (IconSuffix)gtk_icon_cache_get_icon_flags (dir->cache,
- icon_name,
- dir->subdir_index);
- }
- else
- suffix = (IconSuffix)gtk_icon_cache_get_icon_flags (dir->cache,
- icon_name,
- dir->subdir_index);
-
- suffix = suffix & ~HAS_ICON_FILE;
- }
- else
- suffix = GPOINTER_TO_UINT (g_hash_table_lookup (dir->icons, icon_name));
-
- GTK_NOTE (ICONTHEME, g_message ("get icon suffix%s: %u", dir->cache ? " (cached)" : "", suffix));
-
- return suffix;
-}
-
/* returns TRUE if dir_a is a better match */
static gboolean
-compare_dir_matches (IconThemeDir *dir_a, gint difference_a,
- IconThemeDir *dir_b, gint difference_b,
- gint requested_size,
- gint requested_scale)
+compare_dir_size_matches (IconThemeDirSize *dir_a, gint difference_a,
+ IconThemeDirSize *dir_b, gint difference_b,
+ gint requested_size,
+ gint requested_scale)
{
gint diff_a;
gint diff_b;
@@ -3135,73 +3108,70 @@ theme_lookup_icon (IconTheme *theme,
gint scale,
gboolean allow_svg)
{
- GList *dirs, *l;
- IconThemeDir *dir, *min_dir;
- gchar *file;
- gint min_difference, difference;
- IconSuffix suffix;
+ IconThemeDirSize *min_dir_size;
+ IconThemeFile *min_file;
+ gint min_difference;
IconSuffix min_suffix;
+ int i;
- min_difference = G_MAXINT;
- min_dir = NULL;
+ /* Its not uncommon with misses, so we do an early check which allows us do
+ do a lot less work. */
+ if (!g_hash_table_contains (theme->icons, icon_name))
+ return FALSE;
- dirs = theme->dirs;
+ min_difference = G_MAXINT;
+ min_dir_size = NULL;
- l = dirs;
- while (l != NULL)
+ for (i = 0; i < theme->dir_sizes->len; i++)
{
- dir = l->data;
-
- GTK_NOTE (ICONTHEME, g_message ("look up icon dir %s", dir->dir));
- suffix = theme_dir_get_icon_suffix (dir, icon_name);
- if (best_suffix (suffix, allow_svg) != ICON_SUFFIX_NONE)
- {
- difference = theme_dir_size_difference (dir, size, scale);
- if (min_dir == NULL ||
- compare_dir_matches (dir, difference,
- min_dir, min_difference,
- size, scale))
- {
- min_dir = dir;
- min_suffix = suffix;
- min_difference = difference;
- }
- }
+ IconThemeDirSize *dir_size = &g_array_index (theme->dir_sizes, IconThemeDirSize, i);
+ IconThemeFile *file;
+ guint best_suffix;
+ gint difference;
+ gpointer file_index;
- l = l->next;
- }
+ if (!g_hash_table_lookup_extended (dir_size->icon_hash, icon_name, NULL, &file_index))
+ continue;
- if (min_dir)
- {
- GtkIcon *icon;
+ file = &g_array_index (dir_size->icon_files, IconThemeFile, GPOINTER_TO_INT(file_index));
- icon = icon_new (min_dir->type, min_dir->size, min_dir->scale);
- icon->min_size = min_dir->min_size;
- icon->max_size = min_dir->max_size;
- suffix = min_suffix;
- suffix = best_suffix (suffix, allow_svg);
- g_assert (suffix != ICON_SUFFIX_NONE);
+ if (allow_svg)
+ best_suffix = file->best_suffix;
+ else
+ best_suffix = file->best_suffix_no_svg;
- if (min_dir->dir)
- {
- file = g_strconcat (icon_name, string_from_suffix (suffix), NULL);
- icon->filename = g_build_filename (min_dir->dir, file, NULL);
+ if (best_suffix == ICON_SUFFIX_NONE)
+ continue;
- icon->is_svg = suffix == ICON_SUFFIX_SVG;
- icon->is_resource = min_dir->is_resource;
- g_free (file);
- }
- else
+ difference = theme_dir_size_difference (dir_size, size, scale);
+ if (min_dir_size == NULL ||
+ compare_dir_size_matches (dir_size, difference,
+ min_dir_size, min_difference,
+ size, scale))
{
- icon->filename = NULL;
+ min_dir_size = dir_size;
+ min_file = file;
+ min_suffix = best_suffix;
+ min_difference = difference;
}
+ }
- if (min_dir->cache)
- {
- icon->cache_pixbuf = gtk_icon_cache_get_icon (min_dir->cache, icon_name,
- min_dir->subdir_index);
- }
+ if (min_dir_size)
+ {
+ GtkIcon *icon;
+ IconThemeDir *dir = &g_array_index (theme->dirs, IconThemeDir, min_file->dir_index);
+ gchar *filename;
+
+ icon = icon_new (min_dir_size->type, min_dir_size->size, min_dir_size->scale);
+ icon->min_size = min_dir_size->min_size;
+ icon->max_size = min_dir_size->max_size;
+
+ filename = g_strconcat (icon_name, string_from_suffix (min_suffix), NULL);
+ icon->filename = g_build_filename (dir->path, filename, NULL);
+ icon->is_svg = min_suffix == ICON_SUFFIX_SVG;
+ icon->is_resource = dir->is_resource;
+ g_free (filename);
return icon;
}
@@ -3214,22 +3184,31 @@ theme_list_icons (IconTheme *theme,
GHashTable *icons,
GQuark context)
{
- GList *l = theme->dirs;
- IconThemeDir *dir;
+ int i;
- while (l != NULL)
+ for (i = 0; i < theme->dir_sizes->len; i++)
{
- dir = l->data;
+ IconThemeDirSize *dir_size = &g_array_index (theme->dir_sizes, IconThemeDirSize, i);
+ GHashTableIter iter;
+ gpointer key, value;
- if (context == dir->context ||
- context == 0)
+ g_hash_table_iter_init (&iter, dir_size->icon_hash);
+ while (g_hash_table_iter_next (&iter, &key, &value))
{
- if (dir->cache)
- gtk_icon_cache_add_icons (dir->cache, dir->subdir, icons);
- else
- g_hash_table_foreach (dir->icons, add_key_to_hash, icons);
+ char *icon_name = key;
+ gint file_index = GPOINTER_TO_INT (value);
+
+ if (context != 0)
+ {
+ IconThemeFile *file = &g_array_index (dir_size->icon_files, IconThemeFile, file_index);
+ IconThemeDir *dir = &g_array_index (theme->dirs, IconThemeDir, file->dir_index);
+
+ if (dir->context != context)
+ continue;
+ }
+
+ g_hash_table_insert (icons, icon_name, NULL);
}
- l = l->next;
}
}
@@ -3237,25 +3216,7 @@ static gboolean
theme_has_icon (IconTheme *theme,
const gchar *icon_name)
{
- GList *l;
-
- for (l = theme->dirs; l; l = l->next)
- {
- IconThemeDir *dir = l->data;
-
- if (dir->cache)
- {
- if (gtk_icon_cache_has_icon (dir->cache, icon_name))
- return TRUE;
- }
- else
- {
- if (g_hash_table_lookup (dir->icons, icon_name) != NULL)
- return TRUE;
- }
- }
-
- return FALSE;
+ return g_hash_table_contains (theme->icons, icon_name);
}
static GHashTable *
@@ -3298,6 +3259,164 @@ scan_directory (GtkIconTheme *self,
return icons;
}
+static GHashTable *
+scan_resource_directory (GtkIconTheme *self,
+ char *full_dir)
+{
+ GHashTable *icons = NULL;
+ char **children;
+ int i;
+
+ GTK_DISPLAY_NOTE (self->display, ICONTHEME,
+ g_message ("scanning resource directory %s", full_dir));
+
+ children = g_resources_enumerate_children (full_dir, 0, NULL);
+
+ for (i = 0; children != NULL && children[i]; i++)
+ {
+ const char *name = children[i];
+ gchar *base_name;
+ IconSuffix suffix, hash_suffix;
+
+ suffix = suffix_from_name (name);
+ if (suffix == ICON_SUFFIX_NONE)
+ continue;
+
+ if (!icons)
+ icons = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ base_name = strip_suffix (name);
+
+ hash_suffix = GPOINTER_TO_INT (g_hash_table_lookup (icons, base_name));
+ /* takes ownership of base_name */
+ g_hash_table_replace (icons, base_name, GUINT_TO_POINTER (hash_suffix|suffix));
+ }
+
+ return icons;
+}
+
+static gboolean
+theme_dir_size_equal (IconThemeDirSize *a,
+ IconThemeDirSize *b)
+{
+ return
+ a->type == b->type &&
+ a->size == b->size &&
+ a->min_size == b->min_size &&
+ a->max_size == b->max_size &&
+ a->threshold == b->threshold &&
+ a->scale == b->scale;
+ }
+
+static guint32
+theme_ensure_dir_size (IconTheme *theme,
+ IconThemeDirType type,
+ gint size,
+ gint min_size,
+ gint max_size,
+ gint threshold,
+ gint scale)
+{
+ guint32 index;
+ IconThemeDirSize new = { 0 };
+
+ new.type = type;
+ new.size = size;
+ new.min_size = min_size;
+ new.max_size = max_size;
+ new.threshold = threshold;
+ new.scale = scale;
+
+ for (index = 0; index < theme->dir_sizes->len; index++)
+ {
+ IconThemeDirSize *dir_size = &g_array_index (theme->dir_sizes, IconThemeDirSize, index);
+
+ if (theme_dir_size_equal (dir_size, &new))
+ return index;
+ }
+
+ new.icon_files = g_array_new (FALSE, FALSE, sizeof (IconThemeFile));
+ new.icon_hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
+
+ index = theme->dir_sizes->len;
+ g_array_append_val (theme->dir_sizes, new);
+
+ return index;
+}
+
+static guint32
+theme_add_icon_dir (IconTheme *theme,
+ GQuark context,
+ gboolean is_resource,
+ char *path /* takes ownership */)
+{
+ IconThemeDir new_dir = { 0 };
+ guint32 dir_index;
+
+ new_dir.context = context;
+ new_dir.is_resource = is_resource;
+ new_dir.path = path;
+
+ dir_index = theme->dirs->len;
+ g_array_append_val (theme->dirs, new_dir);
+ return dir_index;
+}
+
+static void
+theme_add_icon_file (IconTheme *theme,
+ const char *icon_name,
+ guint suffixes,
+ IconThemeDirSize *dir_size,
+ guint dir_index)
+{
+ IconThemeFile new_file = { 0 };
+ guint index;
+ char *owned_icon_name = NULL;
+
+ if (g_hash_table_contains (dir_size->icon_hash, icon_name))
+ return;
+
+ owned_icon_name = g_hash_table_lookup (theme->icons, icon_name);
+ if (owned_icon_name == NULL)
+ {
+ owned_icon_name = g_strdup (icon_name);
+ g_hash_table_insert (theme->icons, owned_icon_name, owned_icon_name);
+ }
+
+ new_file.dir_index = dir_index;
+ new_file.best_suffix = best_suffix (suffixes, TRUE);
+ new_file.best_suffix_no_svg = best_suffix (suffixes, FALSE);
+
+ index = dir_size->icon_files->len;
+ g_array_append_val (dir_size->icon_files, new_file);
+
+ g_hash_table_insert (dir_size->icon_hash, owned_icon_name, GINT_TO_POINTER(index));
+
+}
+
+static void
+theme_add_dir_with_icons (IconTheme *theme,
+ IconThemeDirSize *dir_size,
+ GQuark context,
+ gboolean is_resource,
+ char *path /* takes ownership */,
+ GHashTable *icons)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+ guint32 dir_index;
+
+ dir_index = theme_add_icon_dir (theme, context, is_resource, path);
+
+ g_hash_table_iter_init (&iter, icons);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ const char *icon_name = key;
+ guint suffixes = GPOINTER_TO_INT(value);
+ theme_add_icon_file (theme, icon_name, suffixes, dir_size, dir_index);
+ }
+}
+
static void
theme_subdir_load (GtkIconTheme *self,
IconTheme *theme,
@@ -3306,7 +3425,6 @@ theme_subdir_load (GtkIconTheme *self,
{
GList *d;
gchar *type_string;
- IconThemeDir *dir;
IconThemeDirType type;
gchar *context_string;
GQuark context;
@@ -3314,16 +3432,17 @@ theme_subdir_load (GtkIconTheme *self,
gint min_size;
gint max_size;
gint threshold;
- gchar *full_dir;
GError *error = NULL;
IconThemeDirMtime *dir_mtime;
+ guint32 dir_size_index;
+ IconThemeDirSize *dir_size;
gint scale;
size = g_key_file_get_integer (theme_file, subdir, "Size", &error);
if (error)
{
g_error_free (error);
- g_warning ("Theme directory %s of theme %s has no size field\n",
+ g_warning ("Theme directory %s of theme %s has no size field\n",
subdir, theme->name);
return;
}
@@ -3342,14 +3461,6 @@ theme_subdir_load (GtkIconTheme *self,
g_free (type_string);
}
- context = 0;
- context_string = g_key_file_get_string (theme_file, subdir, "Context", NULL);
- if (context_string)
- {
- context = g_quark_from_string (context_string);
- g_free (context_string);
- }
-
if (g_key_file_has_key (theme_file, subdir, "MaxSize", NULL))
max_size = g_key_file_get_integer (theme_file, subdir, "MaxSize", NULL);
else
@@ -3370,8 +3481,20 @@ theme_subdir_load (GtkIconTheme *self,
else
scale = 1;
+ dir_size_index = theme_ensure_dir_size (theme, type, size, min_size, max_size, threshold, scale);
+ dir_size = &g_array_index (theme->dir_sizes, IconThemeDirSize, dir_size_index);
+
+ context = 0;
+ context_string = g_key_file_get_string (theme_file, subdir, "Context", NULL);
+ if (context_string)
+ {
+ context = g_quark_from_string (context_string);
+ g_free (context_string);
+ }
+
for (d = self->dir_mtimes; d; d = d->next)
{
+ gchar *full_dir;
dir_mtime = (IconThemeDirMtime *)d->data;
if (!dir_mtime->exists)
@@ -3382,9 +3505,7 @@ theme_subdir_load (GtkIconTheme *self,
/* First, see if we have a cache for the directory */
if (dir_mtime->cache != NULL || g_file_test (full_dir, G_FILE_TEST_IS_DIR))
{
- gboolean has_icons;
- GtkIconCache *dir_cache;
- GHashTable *icon_table = NULL;
+ GHashTable *icons = NULL;
if (dir_mtime->cache == NULL)
{
@@ -3393,109 +3514,49 @@ theme_subdir_load (GtkIconTheme *self,
}
if (dir_mtime->cache != NULL)
- {
- dir_cache = dir_mtime->cache;
- has_icons = gtk_icon_cache_has_icons (dir_cache, subdir);
- }
+ icons = gtk_icon_cache_list_icons_in_directory (dir_mtime->cache, subdir);
else
- {
- dir_cache = NULL;
- icon_table = scan_directory (self, full_dir);
- has_icons = icon_table != NULL;
- }
-
- if (!has_icons)
- {
- g_assert (!icon_table);
- g_free (full_dir);
- continue;
- }
+ icons = scan_directory (self, full_dir);
- dir = g_new0 (IconThemeDir, 1);
- dir->type = type;
- dir->is_resource = FALSE;
- dir->context = context;
- dir->size = size;
- dir->min_size = min_size;
- dir->max_size = max_size;
- dir->threshold = threshold;
- dir->dir = full_dir;
- dir->subdir = g_strdup (subdir);
- dir->scale = scale;
- dir->icons = icon_table;
-
- if (dir_cache)
+ if (icons)
{
- dir->cache = gtk_icon_cache_ref (dir_cache);
- dir->subdir_index = gtk_icon_cache_get_directory_index (dir->cache, dir->subdir);
+ theme_add_dir_with_icons (theme,
+ dir_size,
+ context,
+ FALSE,
+ g_steal_pointer (&full_dir),
+ icons);
+ g_hash_table_destroy (icons);
}
- else
- {
- dir_cache = NULL;
- dir->subdir_index = -1;
- }
-
- theme->dirs = g_list_prepend (theme->dirs, dir);
}
- else
- g_free (full_dir);
+
+ g_free (full_dir);
}
if (strcmp (theme->name, FALLBACK_ICON_THEME) == 0)
{
for (d = self->resource_paths; d; d = d->next)
{
- int i;
- char **children;
+ GHashTable *icons;
+ gchar *full_dir;
/* Force a trailing / here, to avoid extra copies in GResource */
full_dir = g_build_filename ((const gchar *)d->data, subdir, " ", NULL);
full_dir[strlen (full_dir) - 1] = '\0';
- children = g_resources_enumerate_children (full_dir, 0, NULL);
-
- if (!children)
+ icons = scan_resource_directory (self, full_dir);
+ if (icons)
{
- g_free (full_dir);
- continue;
+ theme_add_dir_with_icons (theme,
+ dir_size,
+ context,
+ TRUE,
+ g_steal_pointer (&full_dir),
+ icons);
+ g_hash_table_destroy (icons);
}
- dir = g_new0 (IconThemeDir, 1);
- dir->icons = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- dir->type = type;
- dir->is_resource = TRUE;
- dir->context = context;
- dir->size = size;
- dir->min_size = min_size;
- dir->max_size = max_size;
- dir->threshold = threshold;
- dir->dir = full_dir;
- dir->subdir = g_strdup (subdir);
- dir->scale = scale;
- dir->cache = NULL;
- dir->subdir_index = -1;
-
- for (i = 0; children[i]; i++)
- {
- gchar *base_name;
- IconSuffix suffix, hash_suffix;
-
- suffix = suffix_from_name (children[i]);
- if (suffix == ICON_SUFFIX_NONE)
- continue;
-
- base_name = strip_suffix (children[i]);
-
- hash_suffix = GPOINTER_TO_INT (g_hash_table_lookup (dir->icons, base_name));
- /* takes ownership of base_name */
- g_hash_table_replace (dir->icons, base_name, GUINT_TO_POINTER (hash_suffix|suffix));
- }
- g_strfreev (children);
-
- if (g_hash_table_size (dir->icons) > 0)
- theme->dirs = g_list_prepend (theme->dirs, dir);
- else
- theme_dir_destroy (dir);
+ g_free (full_dir);
}
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]