From 0a8d7603ea7448d80e5d1c39bdeb050d7ca926d8 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 3 Feb 2020 10:00:17 +0100 Subject: [PATCH 1/4] icon-cache: Add new function to list all the icons in a directory This lists the icons in a particular director, with their flags in a hashtable. We also convert from "icon.symbolic" + SUFFIX_PNG to "icon" + SUFFIX_SYMBOLIC_PNG. --- gtk/gtkiconcache.c | 84 +++++++++++++++++++++++++++++++++++++++ gtk/gtkiconcacheprivate.h | 2 + gtk/gtkicontheme.c | 1 + 3 files changed, 87 insertions(+) diff --git a/gtk/gtkiconcache.c b/gtk/gtkiconcache.c index bcbfe83071..bc238e0028 100644 --- a/gtk/gtkiconcache.c +++ b/gtk/gtkiconcache.c @@ -43,6 +43,18 @@ #define GET_UINT16(cache, offset) (GUINT16_FROM_BE (*(guint16 *)((cache) + (offset)))) #define GET_UINT32(cache, offset) (GUINT32_FROM_BE (*(guint32 *)((cache) + (offset)))) +/* Keep in sync with gtkicontheme.c */ +typedef enum +{ + /* These are used in the file format: */ + ICON_SUFFIX_NONE = 0, + ICON_SUFFIX_XPM = 1 << 0, + ICON_SUFFIX_SVG = 1 << 1, + ICON_SUFFIX_PNG = 1 << 2, + HAS_ICON_FILE = 1 << 3, + /* This is just used by Gtk, so we convert internally to this: */ + ICON_SUFFIX_SYMBOLIC_PNG = 1 << 4 +} IconSuffix; struct _GtkIconCache { gint ref_count; @@ -334,6 +346,78 @@ gtk_icon_cache_has_icons (GtkIconCache *cache, return FALSE; } +GHashTable * +gtk_icon_cache_list_icons_in_directory (GtkIconCache *cache, + const gchar *directory) +{ + gint directory_index; + guint32 hash_offset, n_buckets; + guint32 chain_offset; + guint32 image_list_offset, n_images; + int i, j; + GHashTable *icons = NULL; + + directory_index = get_directory_index (cache, directory); + + if (directory_index == -1) + return NULL; + + hash_offset = GET_UINT32 (cache->buffer, 4); + n_buckets = GET_UINT32 (cache->buffer, hash_offset); + + for (i = 0; i < n_buckets; i++) + { + chain_offset = GET_UINT32 (cache->buffer, hash_offset + 4 + 4 * i); + while (chain_offset != 0xffffffff) + { + guint32 flags = 0; + + image_list_offset = GET_UINT32 (cache->buffer, chain_offset + 8); + n_images = GET_UINT32 (cache->buffer, image_list_offset); + + for (j = 0; j < n_images; j++) + { + if (GET_UINT16 (cache->buffer, image_list_offset + 4 + 8 * j) == + directory_index) + { + flags = GET_UINT16 (cache->buffer, image_list_offset + 4 + 8 * j + 2); + break; + } + } + + if (flags != 0) + { + guint32 name_offset = GET_UINT32 (cache->buffer, chain_offset + 4); + const char *name = cache->buffer + name_offset; + char *converted_name; + guint32 hash_flags = 0; + + /* Icons named foo.symbolic.png are stored in the cache as "foo.symbolic" with ICON_SUFFIX_PNG, + * but we convert it internally to ICON_SUFFIX_SYMBOLIC_PNG. + * Otherwise we use the same enum values and names as on disk. */ + if (g_str_has_suffix (name, ".symbolic") && (flags & ICON_SUFFIX_PNG) != 0) + { + flags |= ICON_SUFFIX_SYMBOLIC_PNG; + flags &= ~ICON_SUFFIX_PNG; + converted_name = g_strndup (name, strlen(name) - 9); + } + else + converted_name = g_strdup (name); + + if (!icons) + icons = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + hash_flags = GPOINTER_TO_INT (g_hash_table_lookup (icons, converted_name)); + g_hash_table_replace (icons, converted_name, GUINT_TO_POINTER (hash_flags|flags)); + } + + chain_offset = GET_UINT32 (cache->buffer, chain_offset); + } + } + + return icons; +} + void gtk_icon_cache_add_icons (GtkIconCache *cache, const gchar *directory, diff --git a/gtk/gtkiconcacheprivate.h b/gtk/gtkiconcacheprivate.h index 08e581fe9a..2f73891e6b 100644 --- a/gtk/gtkiconcacheprivate.h +++ b/gtk/gtkiconcacheprivate.h @@ -32,6 +32,8 @@ gboolean gtk_icon_cache_has_icon (GtkIconCache *cache, gboolean gtk_icon_cache_has_icon_in_directory (GtkIconCache *cache, const gchar *icon_name, const gchar *directory); +GHashTable *gtk_icon_cache_list_icons_in_directory (GtkIconCache *cache, + const gchar *directory); gboolean gtk_icon_cache_has_icons (GtkIconCache *cache, const gchar *directory); void gtk_icon_cache_add_icons (GtkIconCache *cache, diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index d437094063..ae33375bce 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -167,6 +167,7 @@ typedef enum } IconThemeDirType; /* In reverse search order: */ +/* Keep in sync with gtkiconcache.c */ typedef enum { ICON_SUFFIX_NONE = 0, From e4170661b9228cb3e09dbc1cd789e15ef44f4ef5 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 3 Feb 2020 10:35:45 +0100 Subject: [PATCH 2/4] 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 | 683 ++++++++++++++++++++++++--------------------- 1 file changed, 372 insertions(+), 311 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; + + GArray *icon_files; + GHashTable *icon_hash; /* name (unowned) -> file index */ +} IconThemeDirSize; + +typedef struct +{ + GQuark context; gboolean is_resource; - - gchar *dir; - gchar *subdir; - gint subdir_index; - - GtkIconCache *cache; - - GHashTable *icons; + 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) - { - IconThemeDir *dir = d->data; - if (dir->type != ICON_THEME_DIR_SCALABLE && g_hash_table_lookup_extended (sizes, GINT_TO_POINTER (dir->size), NULL, NULL)) + for (i = 0; i < theme->dir_sizes->len; i++) + { + IconThemeDirSize *dir_size = &g_array_index (theme->dir_sizes, IconThemeDirSize, i); + + 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_size_destroy (IconThemeDirSize *dir) +{ + if (dir->icon_hash) + g_hash_table_destroy (dir->icon_hash); + if (dir->icon_files) + g_array_free (dir->icon_files, TRUE); +} + static void theme_dir_destroy (IconThemeDir *dir) { - if (dir->cache) - gtk_icon_cache_unref (dir->cache); - if (dir->icons) - g_hash_table_destroy (dir->icons); - - g_free (dir->dir); - g_free (dir->subdir); - g_free (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; + + /* 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; min_difference = G_MAXINT; - min_dir = NULL; + min_dir_size = NULL; - dirs = theme->dirs; - - l = dirs; - 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); + IconThemeFile *file; + guint best_suffix; + gint difference; + gpointer file_index; - 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) + if (!g_hash_table_lookup_extended (dir_size->icon_hash, icon_name, NULL, &file_index)) + continue; + + file = &g_array_index (dir_size->icon_files, IconThemeFile, GPOINTER_TO_INT(file_index)); + + + if (allow_svg) + best_suffix = file->best_suffix; + else + best_suffix = file->best_suffix_no_svg; + + if (best_suffix == ICON_SUFFIX_NONE) + continue; + + 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)) { - 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; - } + min_dir_size = dir_size; + min_file = file; + min_suffix = best_suffix; + min_difference = difference; } - - l = l->next; } - if (min_dir) + 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->type, min_dir->size, min_dir->scale); - icon->min_size = min_dir->min_size; - icon->max_size = min_dir->max_size; + 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; - suffix = min_suffix; - suffix = best_suffix (suffix, allow_svg); - g_assert (suffix != ICON_SUFFIX_NONE); - - if (min_dir->dir) - { - file = g_strconcat (icon_name, string_from_suffix (suffix), NULL); - icon->filename = g_build_filename (min_dir->dir, file, NULL); - - icon->is_svg = suffix == ICON_SUFFIX_SVG; - icon->is_resource = min_dir->is_resource; - g_free (file); - } - else - { - icon->filename = NULL; - } - - if (min_dir->cache) - { - icon->cache_pixbuf = gtk_icon_cache_get_icon (min_dir->cache, icon_name, - min_dir->subdir_index); - } + 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; - } + icons = scan_directory (self, full_dir); - if (!has_icons) + if (icons) { - g_assert (!icon_table); - g_free (full_dir); - continue; + theme_add_dir_with_icons (theme, + dir_size, + context, + FALSE, + g_steal_pointer (&full_dir), + icons); + g_hash_table_destroy (icons); } - - 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) - { - dir->cache = gtk_icon_cache_ref (dir_cache); - dir->subdir_index = gtk_icon_cache_get_directory_index (dir->cache, dir->subdir); - } - 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); } } } From 308d434b579f95204a215615f00a802c9c7d9dba Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 3 Feb 2020 11:01:48 +0100 Subject: [PATCH 3/4] GtkIconCache: Remove unused code We're not really using the icon theme cache much anymore, as the individual per-directory hashes are no longer used, so delete all the unused code. --- gtk/gtkiconcache.c | 357 ++------------------------------------ gtk/gtkiconcacheprivate.h | 20 --- 2 files changed, 10 insertions(+), 367 deletions(-) diff --git a/gtk/gtkiconcache.c b/gtk/gtkiconcache.c index bc238e0028..8e4b86d6eb 100644 --- a/gtk/gtkiconcache.c +++ b/gtk/gtkiconcache.c @@ -82,7 +82,7 @@ gtk_icon_cache_unref (GtkIconCache *cache) GTK_NOTE (ICONTHEME, g_message ("unmapping icon cache")); if (cache->map) - g_mapped_file_unref (cache->map); + g_mapped_file_unref (cache->map); g_free (cache); } } @@ -119,7 +119,7 @@ gtk_icon_cache_new_for_path (const gchar *path) /* (will need to check on the Windows DDK part later) */ #if ((defined (_MSC_VER) && (_MSC_VER >= 1400 || __MSVCRT_VERSION__ >= 0x0800)) || defined (__MINGW64_VERSION_MAJOR)) && !defined(_WIN64) #undef fstat /* Just in case */ -#define fstat _fstat32 +#define fstat _fstat32 #endif #endif @@ -130,7 +130,7 @@ gtk_icon_cache_new_for_path (const gchar *path) if (st.st_mtime < path_st.st_mtime) { GTK_NOTE (ICONTHEME, g_message ("icon cache outdated")); - goto done; + goto done; } map = g_mapped_file_new (cache_filename, FALSE, NULL); @@ -156,7 +156,7 @@ gtk_icon_cache_new_for_path (const gchar *path) goto done; } } -#endif +#endif GTK_NOTE (ICONTHEME, g_message ("found icon cache for %s", path)); @@ -166,7 +166,7 @@ gtk_icon_cache_new_for_path (const gchar *path) cache->buffer = g_mapped_file_get_contents (map); done: - g_free (cache_filename); + g_free (cache_filename); if (fd >= 0) close (fd); @@ -182,18 +182,18 @@ gtk_icon_cache_new (const gchar *data) cache->ref_count = 1; cache->map = NULL; cache->buffer = (gchar *)data; - + return cache; } static gint get_directory_index (GtkIconCache *cache, - const gchar *directory) + const gchar *directory) { guint32 dir_list_offset; gint n_dirs; gint i; - + dir_list_offset = GET_UINT32 (cache->buffer, 8); n_dirs = GET_UINT32 (cache->buffer, dir_list_offset); @@ -203,149 +203,12 @@ get_directory_index (GtkIconCache *cache, guint32 name_offset = GET_UINT32 (cache->buffer, dir_list_offset + 4 + 4 * i); gchar *name = cache->buffer + name_offset; if (strcmp (name, directory) == 0) - return i; + return i; } - + return -1; } -gint -gtk_icon_cache_get_directory_index (GtkIconCache *cache, - const gchar *directory) -{ - return get_directory_index (cache, directory); -} - -static guint -icon_name_hash (gconstpointer key) -{ - const signed char *p = key; - guint32 h = *p; - - if (h) - for (p += 1; *p != '\0'; p++) - h = (h << 5) - h + *p; - - return h; -} - -static gint -find_image_offset (GtkIconCache *cache, - const gchar *icon_name, - gint directory_index) -{ - guint32 hash_offset; - guint32 n_buckets; - guint32 chain_offset; - int hash; - guint32 image_list_offset, n_images; - int i; - - if (!icon_name) - return 0; - - chain_offset = cache->last_chain_offset; - if (chain_offset) - { - guint32 name_offset = GET_UINT32 (cache->buffer, chain_offset + 4); - gchar *name = cache->buffer + name_offset; - - if (strcmp (name, icon_name) == 0) - goto find_dir; - } - - hash_offset = GET_UINT32 (cache->buffer, 4); - n_buckets = GET_UINT32 (cache->buffer, hash_offset); - hash = icon_name_hash (icon_name) % n_buckets; - - chain_offset = GET_UINT32 (cache->buffer, hash_offset + 4 + 4 * hash); - while (chain_offset != 0xffffffff) - { - guint32 name_offset = GET_UINT32 (cache->buffer, chain_offset + 4); - gchar *name = cache->buffer + name_offset; - - if (strcmp (name, icon_name) == 0) - { - cache->last_chain_offset = chain_offset; - goto find_dir; - } - - chain_offset = GET_UINT32 (cache->buffer, chain_offset); - } - - cache->last_chain_offset = 0; - return 0; - -find_dir: - /* We've found an icon list, now check if we have the right icon in it */ - image_list_offset = GET_UINT32 (cache->buffer, chain_offset + 8); - n_images = GET_UINT32 (cache->buffer, image_list_offset); - - for (i = 0; i < n_images; i++) - { - if (GET_UINT16 (cache->buffer, image_list_offset + 4 + 8 * i) == - directory_index) - return image_list_offset + 4 + 8 * i; - } - - return 0; -} - -gint -gtk_icon_cache_get_icon_flags (GtkIconCache *cache, - const gchar *icon_name, - gint directory_index) -{ - guint32 image_offset; - - image_offset = find_image_offset (cache, icon_name, directory_index); - - if (!image_offset) - return 0; - - return GET_UINT16 (cache->buffer, image_offset + 2); -} - -gboolean -gtk_icon_cache_has_icons (GtkIconCache *cache, - const gchar *directory) -{ - int directory_index; - guint32 hash_offset, n_buckets; - guint32 chain_offset; - guint32 image_list_offset, n_images; - int i, j; - - directory_index = get_directory_index (cache, directory); - - if (directory_index == -1) - return FALSE; - - hash_offset = GET_UINT32 (cache->buffer, 4); - n_buckets = GET_UINT32 (cache->buffer, hash_offset); - - for (i = 0; i < n_buckets; i++) - { - chain_offset = GET_UINT32 (cache->buffer, hash_offset + 4 + 4 * i); - while (chain_offset != 0xffffffff) - { - image_list_offset = GET_UINT32 (cache->buffer, chain_offset + 8); - n_images = GET_UINT32 (cache->buffer, image_list_offset); - - for (j = 0; j < n_images; j++) - { - if (GET_UINT16 (cache->buffer, image_list_offset + 4 + 8 * j) == - directory_index) - return TRUE; - } - - chain_offset = GET_UINT32 (cache->buffer, chain_offset); - } - } - - return FALSE; -} - GHashTable * gtk_icon_cache_list_icons_in_directory (GtkIconCache *cache, const gchar *directory) @@ -417,203 +280,3 @@ gtk_icon_cache_list_icons_in_directory (GtkIconCache *cache, return icons; } - -void -gtk_icon_cache_add_icons (GtkIconCache *cache, - const gchar *directory, - GHashTable *hash_table) -{ - int directory_index; - guint32 hash_offset, n_buckets; - guint32 chain_offset; - guint32 image_list_offset, n_images; - int i, j; - - directory_index = get_directory_index (cache, directory); - - if (directory_index == -1) - return; - - hash_offset = GET_UINT32 (cache->buffer, 4); - n_buckets = GET_UINT32 (cache->buffer, hash_offset); - - for (i = 0; i < n_buckets; i++) - { - chain_offset = GET_UINT32 (cache->buffer, hash_offset + 4 + 4 * i); - while (chain_offset != 0xffffffff) - { - guint32 name_offset = GET_UINT32 (cache->buffer, chain_offset + 4); - gchar *name = cache->buffer + name_offset; - - image_list_offset = GET_UINT32 (cache->buffer, chain_offset + 8); - n_images = GET_UINT32 (cache->buffer, image_list_offset); - - for (j = 0; j < n_images; j++) - { - if (GET_UINT16 (cache->buffer, image_list_offset + 4 + 8 * j) == - directory_index) - g_hash_table_insert (hash_table, name, NULL); - } - - chain_offset = GET_UINT32 (cache->buffer, chain_offset); - } - } -} - -gboolean -gtk_icon_cache_has_icon (GtkIconCache *cache, - const gchar *icon_name) -{ - guint32 hash_offset; - guint32 n_buckets; - guint32 chain_offset; - gint hash; - - hash_offset = GET_UINT32 (cache->buffer, 4); - n_buckets = GET_UINT32 (cache->buffer, hash_offset); - - hash = icon_name_hash (icon_name) % n_buckets; - - chain_offset = GET_UINT32 (cache->buffer, hash_offset + 4 + 4 * hash); - while (chain_offset != 0xffffffff) - { - guint32 name_offset = GET_UINT32 (cache->buffer, chain_offset + 4); - gchar *name = cache->buffer + name_offset; - - if (strcmp (name, icon_name) == 0) - return TRUE; - - chain_offset = GET_UINT32 (cache->buffer, chain_offset); - } - - return FALSE; -} - -gboolean -gtk_icon_cache_has_icon_in_directory (GtkIconCache *cache, - const gchar *icon_name, - const gchar *directory) -{ - guint32 hash_offset; - guint32 n_buckets; - guint32 chain_offset; - gint hash; - gboolean found_icon = FALSE; - gint directory_index; - - directory_index = get_directory_index (cache, directory); - - if (directory_index == -1) - return FALSE; - - hash_offset = GET_UINT32 (cache->buffer, 4); - n_buckets = GET_UINT32 (cache->buffer, hash_offset); - - hash = icon_name_hash (icon_name) % n_buckets; - - chain_offset = GET_UINT32 (cache->buffer, hash_offset + 4 + 4 * hash); - while (chain_offset != 0xffffffff) - { - guint32 name_offset = GET_UINT32 (cache->buffer, chain_offset + 4); - gchar *name = cache->buffer + name_offset; - - if (strcmp (name, icon_name) == 0) - { - found_icon = TRUE; - break; - } - - chain_offset = GET_UINT32 (cache->buffer, chain_offset); - } - - if (found_icon) - { - guint32 image_list_offset = GET_UINT32 (cache->buffer, chain_offset + 8); - guint32 n_images = GET_UINT32 (cache->buffer, image_list_offset); - guint32 image_offset = image_list_offset + 4; - gint i; - for (i = 0; i < n_images; i++) - { - guint16 index = GET_UINT16 (cache->buffer, image_offset); - - if (index == directory_index) - return TRUE; - image_offset += 8; - } - } - - return FALSE; -} - -static void -pixbuf_destroy_cb (guchar *pixels, - gpointer data) -{ - GtkIconCache *cache = data; - - gtk_icon_cache_unref (cache); -} - -GdkPixbuf * -gtk_icon_cache_get_icon (GtkIconCache *cache, - const gchar *icon_name, - gint directory_index) -{ - guint32 offset, image_data_offset, pixel_data_offset; - guint32 length, type; - GdkPixbuf *pixbuf; - GdkPixdata pixdata; - GError *error = NULL; - - offset = find_image_offset (cache, icon_name, directory_index); - - if (!offset) - return NULL; - - image_data_offset = GET_UINT32 (cache->buffer, offset + 4); - - if (!image_data_offset) - return NULL; - - pixel_data_offset = GET_UINT32 (cache->buffer, image_data_offset); - - type = GET_UINT32 (cache->buffer, pixel_data_offset); - - if (type != 0) - { - GTK_NOTE (ICONTHEME, g_message ("invalid pixel data type %u", type)); - return NULL; - } - - length = GET_UINT32 (cache->buffer, pixel_data_offset + 4); - -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - if (!gdk_pixdata_deserialize (&pixdata, length, - (guchar *)(cache->buffer + pixel_data_offset + 8), - &error)) - { - GTK_NOTE (ICONTHEME, g_message ("could not deserialize data: %s", error->message)); - g_error_free (error); - - return NULL; - } -G_GNUC_END_IGNORE_DEPRECATIONS - - pixbuf = gdk_pixbuf_new_from_data (pixdata.pixel_data, GDK_COLORSPACE_RGB, - (pixdata.pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, - 8, pixdata.width, pixdata.height, pixdata.rowstride, - (GdkPixbufDestroyNotify)pixbuf_destroy_cb, - cache); - if (!pixbuf) - { - GTK_NOTE (ICONTHEME, g_message ("could not convert pixdata to pixbuf: %s", error->message)); - g_error_free (error); - - return NULL; - } - - gtk_icon_cache_ref (cache); - - return pixbuf; -} - diff --git a/gtk/gtkiconcacheprivate.h b/gtk/gtkiconcacheprivate.h index 2f73891e6b..4925e9c870 100644 --- a/gtk/gtkiconcacheprivate.h +++ b/gtk/gtkiconcacheprivate.h @@ -25,28 +25,8 @@ typedef struct _GtkIconCache GtkIconCache; GtkIconCache *gtk_icon_cache_new (const gchar *data); GtkIconCache *gtk_icon_cache_new_for_path (const gchar *path); -gint gtk_icon_cache_get_directory_index (GtkIconCache *cache, - const gchar *directory); -gboolean gtk_icon_cache_has_icon (GtkIconCache *cache, - const gchar *icon_name); -gboolean gtk_icon_cache_has_icon_in_directory (GtkIconCache *cache, - const gchar *icon_name, - const gchar *directory); GHashTable *gtk_icon_cache_list_icons_in_directory (GtkIconCache *cache, const gchar *directory); -gboolean gtk_icon_cache_has_icons (GtkIconCache *cache, - const gchar *directory); -void gtk_icon_cache_add_icons (GtkIconCache *cache, - const gchar *directory, - GHashTable *hash_table); - -gint gtk_icon_cache_get_icon_flags (GtkIconCache *cache, - const gchar *icon_name, - gint directory_index); -GdkPixbuf *gtk_icon_cache_get_icon (GtkIconCache *cache, - const gchar *icon_name, - gint directory_index); - GtkIconCache *gtk_icon_cache_ref (GtkIconCache *cache); void gtk_icon_cache_unref (GtkIconCache *cache); From 046de4ccbf5cb1e8e4d5b4d854106968d8203d52 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Tue, 4 Feb 2020 09:35:20 +0100 Subject: [PATCH 4/4] icon-theme: Only have one copy of the icon flags enum It turns out with the icon cache now using the virtual SYMBOLIC_PNG_SUFFIX flag the two enums are now identical, so lets just use one of them, the one GtkIconCache (so we move it to the header). --- gtk/gtkiconcache.c | 23 ++---- gtk/gtkiconcacheprivate.h | 14 ++++ gtk/gtkicontheme.c | 161 ++++++++++++++++++-------------------- 3 files changed, 94 insertions(+), 104 deletions(-) diff --git a/gtk/gtkiconcache.c b/gtk/gtkiconcache.c index 8e4b86d6eb..7c6e6dd247 100644 --- a/gtk/gtkiconcache.c +++ b/gtk/gtkiconcache.c @@ -43,19 +43,6 @@ #define GET_UINT16(cache, offset) (GUINT16_FROM_BE (*(guint16 *)((cache) + (offset)))) #define GET_UINT32(cache, offset) (GUINT32_FROM_BE (*(guint32 *)((cache) + (offset)))) -/* Keep in sync with gtkicontheme.c */ -typedef enum -{ - /* These are used in the file format: */ - ICON_SUFFIX_NONE = 0, - ICON_SUFFIX_XPM = 1 << 0, - ICON_SUFFIX_SVG = 1 << 1, - ICON_SUFFIX_PNG = 1 << 2, - HAS_ICON_FILE = 1 << 3, - /* This is just used by Gtk, so we convert internally to this: */ - ICON_SUFFIX_SYMBOLIC_PNG = 1 << 4 -} IconSuffix; - struct _GtkIconCache { gint ref_count; @@ -255,13 +242,13 @@ gtk_icon_cache_list_icons_in_directory (GtkIconCache *cache, char *converted_name; guint32 hash_flags = 0; - /* Icons named foo.symbolic.png are stored in the cache as "foo.symbolic" with ICON_SUFFIX_PNG, - * but we convert it internally to ICON_SUFFIX_SYMBOLIC_PNG. + /* Icons named foo.symbolic.png are stored in the cache as "foo.symbolic" with ICON_CACHE_FLAG_PNG, + * but we convert it internally to ICON_CACHE_FLAG_SYMBOLIC_PNG. * Otherwise we use the same enum values and names as on disk. */ - if (g_str_has_suffix (name, ".symbolic") && (flags & ICON_SUFFIX_PNG) != 0) + if (g_str_has_suffix (name, ".symbolic") && (flags & ICON_CACHE_FLAG_PNG_SUFFIX) != 0) { - flags |= ICON_SUFFIX_SYMBOLIC_PNG; - flags &= ~ICON_SUFFIX_PNG; + flags |= ICON_CACHE_FLAG_SYMBOLIC_PNG_SUFFIX; + flags &= ~ICON_CACHE_FLAG_PNG_SUFFIX; converted_name = g_strndup (name, strlen(name) - 9); } else diff --git a/gtk/gtkiconcacheprivate.h b/gtk/gtkiconcacheprivate.h index 4925e9c870..3f0b7c4747 100644 --- a/gtk/gtkiconcacheprivate.h +++ b/gtk/gtkiconcacheprivate.h @@ -21,6 +21,20 @@ G_BEGIN_DECLS +/* These are (mostly, see below) the on disk flags for each icon file, don't change */ +typedef enum +{ + ICON_CACHE_FLAG_NONE = 0, + ICON_CACHE_FLAG_XPM_SUFFIX = 1 << 0, + ICON_CACHE_FLAG_SVG_SUFFIX = 1 << 1, + ICON_CACHE_FLAG_PNG_SUFFIX = 1 << 2, + ICON_CACHE_FLAG_HAS_ICON_FILE = 1 << 3, + + /* This is a virtual flag we recreate in memory as the file format actually stores .symbolic.png as png */ + ICON_CACHE_FLAG_SYMBOLIC_PNG_SUFFIX = 1 << 4, +} IconCacheFlag; + + typedef struct _GtkIconCache GtkIconCache; GtkIconCache *gtk_icon_cache_new (const gchar *data); diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index 1ec6715a75..4ebca15dff 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -166,18 +166,6 @@ typedef enum ICON_THEME_DIR_UNTHEMED } IconThemeDirType; -/* In reverse search order: */ -/* Keep in sync with gtkiconcache.c */ -typedef enum -{ - ICON_SUFFIX_NONE = 0, - ICON_SUFFIX_XPM = 1 << 0, - ICON_SUFFIX_SVG = 1 << 1, - ICON_SUFFIX_PNG = 1 << 2, - HAS_ICON_FILE = 1 << 3, - ICON_SUFFIX_SYMBOLIC_PNG = 1 << 4 -} IconSuffix; - #if 0 #define DEBUG_CACHE(args) g_print args #else @@ -373,41 +361,42 @@ typedef struct gboolean exists; } IconThemeDirMtime; -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, - const gchar *icon_name, - gint size, - gint scale, - gboolean allow_svg); -static void theme_list_icons (IconTheme *theme, - GHashTable *icons, - GQuark context); -static gboolean theme_has_icon (IconTheme *theme, - const gchar *icon_name); -static void theme_subdir_load (GtkIconTheme *self, - IconTheme *theme, - GKeyFile *theme_file, - gchar *subdir); -static void do_theme_change (GtkIconTheme *self); -static void blow_themes (GtkIconTheme *self); -static gboolean rescan_themes (GtkIconTheme *self); -static GtkIcon * icon_new (IconThemeDirType type, - gint dir_size, - gint dir_scale); -static void icon_compute_rendered_size (GtkIcon *icon); -static IconSuffix suffix_from_name (const gchar *name); -static gboolean icon_ensure_scale_and_texture__locked (GtkIcon *icon, - gboolean in_thread); -static void unset_display (GtkIconTheme *self); -static void update_current_theme__mainthread (GtkIconTheme *self); -static gboolean ensure_valid_themes (GtkIconTheme *self, - gboolean non_blocking); +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, + const gchar *icon_name, + gint size, + gint scale, + gboolean allow_svg); +static void theme_list_icons (IconTheme *theme, + GHashTable *icons, + GQuark context); +static gboolean theme_has_icon (IconTheme *theme, + const gchar *icon_name); +static void theme_subdir_load (GtkIconTheme *self, + IconTheme *theme, + GKeyFile *theme_file, + gchar *subdir); +static void do_theme_change (GtkIconTheme *self); +static void blow_themes (GtkIconTheme *self); +static gboolean rescan_themes (GtkIconTheme *self); +static GtkIcon * icon_new (IconThemeDirType type, + gint dir_size, + gint dir_scale); +static void icon_compute_rendered_size (GtkIcon *icon); +static IconCacheFlag suffix_from_name (const gchar *name); +static gboolean icon_ensure_scale_and_texture__locked (GtkIcon *icon, + gboolean in_thread); +static void unset_display (GtkIconTheme *self); +static void update_current_theme__mainthread (GtkIconTheme *self); +static gboolean ensure_valid_themes (GtkIconTheme *self, + gboolean non_blocking); + static guint signal_changed = 0; @@ -1599,14 +1588,14 @@ add_unthemed_icon (GtkIconTheme *self, const gchar *file, gboolean is_resource) { - IconSuffix new_suffix, old_suffix; + IconCacheFlag new_suffix, old_suffix; gchar *abs_file; gchar *base_name; UnthemedIcon *unthemed_icon; new_suffix = suffix_from_name (file); - if (new_suffix == ICON_SUFFIX_NONE) + if (new_suffix == ICON_CACHE_FLAG_NONE) return; abs_file = g_build_filename (dir, file, NULL); @@ -1616,7 +1605,7 @@ add_unthemed_icon (GtkIconTheme *self, if (unthemed_icon) { - if (new_suffix == ICON_SUFFIX_SVG) + if (new_suffix == ICON_CACHE_FLAG_SVG_SUFFIX) { if (unthemed_icon->svg_filename) g_free (abs_file); @@ -1648,7 +1637,7 @@ add_unthemed_icon (GtkIconTheme *self, unthemed_icon->is_resource = is_resource; - if (new_suffix == ICON_SUFFIX_SVG) + if (new_suffix == ICON_CACHE_FLAG_SVG_SUFFIX) unthemed_icon->svg_filename = abs_file; else unthemed_icon->no_svg_filename = abs_file; @@ -1969,7 +1958,7 @@ real_choose_icon (GtkIconTheme *self, if (allow_svg && unthemed_icon->svg_filename && (!unthemed_icon->no_svg_filename || - suffix_from_name (unthemed_icon->no_svg_filename) < ICON_SUFFIX_PNG)) + suffix_from_name (unthemed_icon->no_svg_filename) < ICON_CACHE_FLAG_PNG_SUFFIX)) icon->filename = g_strdup (unthemed_icon->svg_filename); else if (unthemed_icon->no_svg_filename) icon->filename = g_strdup (unthemed_icon->no_svg_filename); @@ -1988,7 +1977,7 @@ real_choose_icon (GtkIconTheme *self, goto out; } - icon->is_svg = suffix_from_name (icon->filename) == ICON_SUFFIX_SVG; + icon->is_svg = suffix_from_name (icon->filename) == ICON_CACHE_FLAG_SVG_SUFFIX; icon->is_resource = unthemed_icon->is_resource; } @@ -2974,27 +2963,27 @@ theme_dir_size_difference (IconThemeDirSize *dir_size, } static const gchar * -string_from_suffix (IconSuffix suffix) +string_from_suffix (IconCacheFlag suffix) { switch (suffix) { - case ICON_SUFFIX_XPM: + case ICON_CACHE_FLAG_XPM_SUFFIX: return ".xpm"; - case ICON_SUFFIX_SVG: + case ICON_CACHE_FLAG_SVG_SUFFIX: return ".svg"; - case ICON_SUFFIX_PNG: + case ICON_CACHE_FLAG_PNG_SUFFIX: return ".png"; - case ICON_SUFFIX_SYMBOLIC_PNG: + case ICON_CACHE_FLAG_SYMBOLIC_PNG_SUFFIX: return ".symbolic.png"; - case ICON_SUFFIX_NONE: - case HAS_ICON_FILE: + case ICON_CACHE_FLAG_NONE: + case ICON_CACHE_FLAG_HAS_ICON_FILE: default: g_assert_not_reached(); return NULL; } } -static inline IconSuffix +static inline IconCacheFlag suffix_from_name (const gchar *name) { const gsize name_len = strlen (name); @@ -3004,36 +2993,36 @@ suffix_from_name (const gchar *name) if (name_len > strlen (".symbolic.png")) { if (strcmp (name + name_len - strlen (".symbolic.png"), ".symbolic.png") == 0) - return ICON_SUFFIX_SYMBOLIC_PNG; + return ICON_CACHE_FLAG_SYMBOLIC_PNG_SUFFIX; } if (strcmp (name + name_len - strlen (".png"), ".png") == 0) - return ICON_SUFFIX_PNG; + return ICON_CACHE_FLAG_PNG_SUFFIX; if (strcmp (name + name_len - strlen (".svg"), ".svg") == 0) - return ICON_SUFFIX_SVG; + return ICON_CACHE_FLAG_SVG_SUFFIX; if (strcmp (name + name_len - strlen (".xpm"), ".xpm") == 0) - return ICON_SUFFIX_XPM; + return ICON_CACHE_FLAG_XPM_SUFFIX; } - return ICON_SUFFIX_NONE; + return ICON_CACHE_FLAG_NONE; } -static IconSuffix -best_suffix (IconSuffix suffix, - gboolean allow_svg) +static IconCacheFlag +best_suffix (IconCacheFlag suffix, + gboolean allow_svg) { - if ((suffix & ICON_SUFFIX_SYMBOLIC_PNG) != 0) - return ICON_SUFFIX_SYMBOLIC_PNG; - else if ((suffix & ICON_SUFFIX_PNG) != 0) - return ICON_SUFFIX_PNG; - else if (allow_svg && ((suffix & ICON_SUFFIX_SVG) != 0)) - return ICON_SUFFIX_SVG; - else if ((suffix & ICON_SUFFIX_XPM) != 0) - return ICON_SUFFIX_XPM; + if ((suffix & ICON_CACHE_FLAG_SYMBOLIC_PNG_SUFFIX) != 0) + return ICON_CACHE_FLAG_SYMBOLIC_PNG_SUFFIX; + else if ((suffix & ICON_CACHE_FLAG_PNG_SUFFIX) != 0) + return ICON_CACHE_FLAG_PNG_SUFFIX; + else if (allow_svg && ((suffix & ICON_CACHE_FLAG_SVG_SUFFIX) != 0)) + return ICON_CACHE_FLAG_SVG_SUFFIX; + else if ((suffix & ICON_CACHE_FLAG_XPM_SUFFIX) != 0) + return ICON_CACHE_FLAG_XPM_SUFFIX; else - return ICON_SUFFIX_NONE; + return ICON_CACHE_FLAG_NONE; } /* returns TRUE if dir_a is a better match */ @@ -3111,7 +3100,7 @@ theme_lookup_icon (IconTheme *theme, IconThemeDirSize *min_dir_size; IconThemeFile *min_file; gint min_difference; - IconSuffix min_suffix; + IconCacheFlag min_suffix; int i; /* Its not uncommon with misses, so we do an early check which allows us do @@ -3141,7 +3130,7 @@ theme_lookup_icon (IconTheme *theme, else best_suffix = file->best_suffix_no_svg; - if (best_suffix == ICON_SUFFIX_NONE) + if (best_suffix == ICON_CACHE_FLAG_NONE) continue; difference = theme_dir_size_difference (dir_size, size, scale); @@ -3169,7 +3158,7 @@ theme_lookup_icon (IconTheme *theme, 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_svg = min_suffix == ICON_CACHE_FLAG_SVG_SUFFIX; icon->is_resource = dir->is_resource; g_free (filename); @@ -3238,10 +3227,10 @@ scan_directory (GtkIconTheme *self, while ((name = g_dir_read_name (gdir))) { gchar *base_name; - IconSuffix suffix, hash_suffix; + IconCacheFlag suffix, hash_suffix; suffix = suffix_from_name (name); - if (suffix == ICON_SUFFIX_NONE) + if (suffix == ICON_CACHE_FLAG_NONE) continue; if (!icons) @@ -3276,10 +3265,10 @@ scan_resource_directory (GtkIconTheme *self, { const char *name = children[i]; gchar *base_name; - IconSuffix suffix, hash_suffix; + IconCacheFlag suffix, hash_suffix; suffix = suffix_from_name (name); - if (suffix == ICON_SUFFIX_NONE) + if (suffix == ICON_CACHE_FLAG_NONE) continue; if (!icons) @@ -4271,7 +4260,7 @@ gtk_icon_new_for_file (GFile *file, icon->filename = g_file_get_path (file); } - icon->is_svg = suffix_from_name (icon->filename) == ICON_SUFFIX_SVG; + icon->is_svg = suffix_from_name (icon->filename) == ICON_CACHE_FLAG_SVG_SUFFIX; icon->desired_size = size; icon->desired_scale = scale;