Cache launcher icons
This commit is contained in:
parent
5a9dc31fbb
commit
4dfe411bf4
7 changed files with 209 additions and 36 deletions
14
ChangeLog
14
ChangeLog
|
@ -4,18 +4,22 @@
|
|||
- Create temporary files in /tmp
|
||||
- Compute task icon size correctly (issue #560)
|
||||
- Fix build on powerpc
|
||||
- The XDG paths are used in the icon and application lookup in addition to the hardcoded defaults
|
||||
- Minor code cleanup in the system tray
|
||||
- tint2conf:
|
||||
- Sort applications correctly
|
||||
- Avoid duplicate icon themes due to symlinks
|
||||
- Avoid loading desktop files marked as NoDisplay
|
||||
- Enhancements:
|
||||
- Use a better Name and GenericName in the .desktop files
|
||||
- Use the XDG paths in addition to the defaults when looking for icons and applications
|
||||
- Fallback icon themes are loaded lazily to speed up tint2 startup
|
||||
- Launcher icon paths are now cached, which greatly improves loading time for tint2 and tint2conf.
|
||||
The correct icon should be found even if you change the icon theme or install a new theme.
|
||||
If this is not the case, delete the file ~/.cache/tint2/icon.cache, restart tint2 and please file a bug report
|
||||
indicating the application name and the icon theme name.
|
||||
- Fallback icon themes are loaded lazily to speed up tint2 and tint2conf startup
|
||||
- A better Name and GenericName is used in the tint2 and tint2conf .desktop files
|
||||
- tint2conf:
|
||||
- Sort icon themes
|
||||
- Updated ru translation
|
||||
- Sort icon themes in list
|
||||
- Updated ru translation (thanks @Vladimir-csp)
|
||||
|
||||
2016-01-29 0.12.7
|
||||
- Fixes:
|
||||
|
|
|
@ -300,24 +300,25 @@ void free_icon_theme(IconTheme *theme)
|
|||
theme->list_directories = NULL;
|
||||
}
|
||||
|
||||
void free_themes(IconThemeWrapper *themes)
|
||||
void free_themes(IconThemeWrapper *wrapper)
|
||||
{
|
||||
if (!themes)
|
||||
if (!wrapper)
|
||||
return;
|
||||
for (GSList *l = themes->themes; l; l = l->next) {
|
||||
for (GSList *l = wrapper->themes; l; l = l->next) {
|
||||
IconTheme *theme = (IconTheme *)l->data;
|
||||
free_icon_theme(theme);
|
||||
free(theme);
|
||||
}
|
||||
g_slist_free(themes->themes);
|
||||
for (GSList *l = themes->themes_fallback; l; l = l->next) {
|
||||
g_slist_free(wrapper->themes);
|
||||
for (GSList *l = wrapper->themes_fallback; l; l = l->next) {
|
||||
IconTheme *theme = (IconTheme *)l->data;
|
||||
free_icon_theme(theme);
|
||||
free(theme);
|
||||
}
|
||||
g_slist_free(themes->themes_fallback);
|
||||
g_slist_free_full(themes->_queued, free);
|
||||
free(themes);
|
||||
g_slist_free(wrapper->themes_fallback);
|
||||
g_slist_free_full(wrapper->_queued, free);
|
||||
g_hash_table_destroy(wrapper->_cache);
|
||||
free(wrapper);
|
||||
}
|
||||
|
||||
void test_launcher_read_theme_file()
|
||||
|
@ -405,21 +406,17 @@ void load_themes_helper(const char *name, GSList **themes, GSList **queued)
|
|||
g_slist_free(queue);
|
||||
}
|
||||
|
||||
IconThemeWrapper *load_themes(const char *icon_theme_name)
|
||||
void load_default_theme(IconThemeWrapper *wrapper)
|
||||
{
|
||||
IconThemeWrapper *wrapper = calloc(1, sizeof(IconThemeWrapper));
|
||||
if (wrapper->_themes_loaded)
|
||||
return;
|
||||
|
||||
if (!icon_theme_name) {
|
||||
fprintf(stderr, "Missing icon_theme_name theme, default to 'hicolor'.\n");
|
||||
icon_theme_name = "hicolor";
|
||||
} else {
|
||||
fprintf(stderr, "Loading %s. Icon theme :", icon_theme_name);
|
||||
}
|
||||
fprintf(stderr, GREEN "Loading icon theme %s:" RESET "\n", wrapper->icon_theme_name);
|
||||
|
||||
load_themes_helper(icon_theme_name, &wrapper->themes, &wrapper->_queued);
|
||||
load_themes_helper(wrapper->icon_theme_name, &wrapper->themes, &wrapper->_queued);
|
||||
load_themes_helper("hicolor", &wrapper->themes, &wrapper->_queued);
|
||||
|
||||
return wrapper;
|
||||
wrapper->_themes_loaded = TRUE;
|
||||
}
|
||||
|
||||
void load_fallbacks(IconThemeWrapper *wrapper)
|
||||
|
@ -450,6 +447,111 @@ void load_fallbacks(IconThemeWrapper *wrapper)
|
|||
wrapper->_fallback_loaded = TRUE;
|
||||
}
|
||||
|
||||
gchar *get_icon_cache_path()
|
||||
{
|
||||
return g_build_filename(g_get_user_cache_dir(), "tint2", "icon.cache", NULL);
|
||||
}
|
||||
|
||||
void load_cache(GHashTable **cache, gchar *cache_path)
|
||||
{
|
||||
*cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
||||
|
||||
FILE *f = fopen(cache_path, "rt");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
char *line = NULL;
|
||||
size_t line_size;
|
||||
|
||||
while (getline(&line, &line_size, f) >= 0) {
|
||||
char *key, *value;
|
||||
|
||||
size_t line_len = strlen(line);
|
||||
gboolean has_newline = FALSE;
|
||||
if (line_len >= 1) {
|
||||
if (line[line_len - 1] == '\n') {
|
||||
line[line_len - 1] = '\0';
|
||||
line_len--;
|
||||
has_newline = TRUE;
|
||||
}
|
||||
}
|
||||
if (!has_newline)
|
||||
break;
|
||||
|
||||
if (line_len == 0)
|
||||
continue;
|
||||
|
||||
if (parse_theme_line(line, &key, &value)) {
|
||||
g_hash_table_insert(*cache, g_strdup(key), g_strdup(value));
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void write_cache_line(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
gchar *k = key;
|
||||
gchar *v = value;
|
||||
FILE *f = user_data;
|
||||
|
||||
fprintf(f, "%s=%s\n", k, v);
|
||||
}
|
||||
|
||||
void save_cache(GHashTable *cache, gchar *cache_path)
|
||||
{
|
||||
FILE *f = fopen(cache_path, "w");
|
||||
if (!f) {
|
||||
gchar *dir_path = g_path_get_dirname(cache_path);
|
||||
g_mkdir_with_parents(dir_path, 0700);
|
||||
g_free(dir_path);
|
||||
f = fopen(cache_path, "w");
|
||||
if (!f) {
|
||||
fprintf(stderr, RED "Could not save icon theme cache!" RESET "\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
g_hash_table_foreach(cache, write_cache_line, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void load_icon_cache(IconThemeWrapper *wrapper)
|
||||
{
|
||||
if (wrapper->_cache)
|
||||
return;
|
||||
|
||||
fprintf(stderr, GREEN "Loading icon theme cache..." RESET "\n");
|
||||
|
||||
gchar *cache_path = get_icon_cache_path();
|
||||
load_cache(&wrapper->_cache, cache_path);
|
||||
g_free(cache_path);
|
||||
}
|
||||
|
||||
void save_icon_cache(IconThemeWrapper *wrapper)
|
||||
{
|
||||
if (!wrapper || !wrapper->_cache || !wrapper->_cache_dirty)
|
||||
return;
|
||||
|
||||
fprintf(stderr, GREEN "Saving icon theme cache..." RESET "\n");
|
||||
gchar *cache_path = get_icon_cache_path();
|
||||
save_cache(wrapper->_cache, cache_path);
|
||||
g_free(cache_path);
|
||||
}
|
||||
|
||||
IconThemeWrapper *load_themes(const char *icon_theme_name)
|
||||
{
|
||||
IconThemeWrapper *wrapper = calloc(1, sizeof(IconThemeWrapper));
|
||||
|
||||
if (!icon_theme_name) {
|
||||
fprintf(stderr, "Missing icon_theme_name theme, default to 'hicolor'.\n");
|
||||
icon_theme_name = "hicolor";
|
||||
}
|
||||
|
||||
wrapper->icon_theme_name = strdup(icon_theme_name);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
int directory_matches_size(IconThemeDir *dir, int size)
|
||||
{
|
||||
if (dir->type == ICON_DIR_TYPE_FIXED) {
|
||||
|
@ -651,6 +753,49 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
char *get_icon_path_from_cache(IconThemeWrapper *wrapper, const char *icon_name, int size)
|
||||
{
|
||||
if (!wrapper || !icon_name || strlen(icon_name) == 0)
|
||||
return NULL;
|
||||
|
||||
load_icon_cache(wrapper);
|
||||
|
||||
gchar *key = g_strdup_printf("%s\t%s\t%d", wrapper->icon_theme_name, icon_name, size);
|
||||
gchar *value = g_hash_table_lookup(wrapper->_cache, key);
|
||||
g_free(key);
|
||||
if (!value) {
|
||||
fprintf(stderr,
|
||||
YELLOW "Icon path not found in cache: theme = %s, icon = %s, size = %d" RESET "\n",
|
||||
wrapper->icon_theme_name,
|
||||
icon_name,
|
||||
size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// fprintf(stderr, "Icon path found in cache: theme = %s, icon = %s, size = %d, path = %s\n", wrapper->icon_theme_name, icon_name, size, value);
|
||||
|
||||
return strdup(value);
|
||||
}
|
||||
|
||||
void add_icon_path_to_cache(IconThemeWrapper *wrapper, const char *icon_name, int size, const char *path)
|
||||
{
|
||||
if (!wrapper || !icon_name || strlen(icon_name) == 0 || !path || strlen(path) == 0)
|
||||
return;
|
||||
|
||||
fprintf(stderr, "Adding icon path to cache: theme = %s, icon = %s, size = %d, path = %s\n", wrapper->icon_theme_name, icon_name, size, path);
|
||||
|
||||
load_icon_cache(wrapper);
|
||||
|
||||
gchar *key = g_strdup_printf("%s\t%s\t%d", wrapper->icon_theme_name, icon_name, size);
|
||||
gchar *value = g_hash_table_lookup(wrapper->_cache, key);
|
||||
if (value && g_str_equal(value, path)) {
|
||||
g_free(key);
|
||||
return;
|
||||
}
|
||||
g_hash_table_insert(wrapper->_cache, key, g_strdup(path));
|
||||
wrapper->_cache_dirty = TRUE;
|
||||
}
|
||||
|
||||
char *get_icon_path(IconThemeWrapper *wrapper, const char *icon_name, int size)
|
||||
{
|
||||
if (!wrapper)
|
||||
|
@ -659,17 +804,27 @@ char *get_icon_path(IconThemeWrapper *wrapper, const char *icon_name, int size)
|
|||
if (!icon_name || strlen(icon_name) == 0)
|
||||
return NULL;
|
||||
|
||||
icon_name = icon_name ? icon_name : DEFAULT_ICON;
|
||||
char *path = get_icon_path_helper(wrapper->themes, icon_name, size);
|
||||
char *path = get_icon_path_from_cache(wrapper, icon_name, size);
|
||||
if (path)
|
||||
return path;
|
||||
|
||||
load_default_theme(wrapper);
|
||||
|
||||
icon_name = icon_name ? icon_name : DEFAULT_ICON;
|
||||
path = get_icon_path_helper(wrapper->themes, icon_name, size);
|
||||
if (path) {
|
||||
add_icon_path_to_cache(wrapper, icon_name, size, path);
|
||||
return path;
|
||||
}
|
||||
|
||||
fprintf(stderr, YELLOW "Icon not found in default theme: %s" RESET "\n", icon_name);
|
||||
load_fallbacks(wrapper);
|
||||
|
||||
path = get_icon_path_helper(wrapper->themes_fallback, icon_name, size);
|
||||
if (path)
|
||||
if (path) {
|
||||
add_icon_path_to_cache(wrapper, icon_name, size, path);
|
||||
return path;
|
||||
}
|
||||
|
||||
fprintf(stderr, RED "Could not find icon %s, using default." RESET "\n", icon_name);
|
||||
path = get_icon_path_helper(wrapper->themes, DEFAULT_ICON, size);
|
||||
|
|
|
@ -9,12 +9,21 @@
|
|||
#include <glib.h>
|
||||
|
||||
typedef struct IconThemeWrapper {
|
||||
// The icon theme name for which this wrapper was created
|
||||
char *icon_theme_name;
|
||||
// List of IconTheme*
|
||||
GSList *themes;
|
||||
// Themes are loaded lazily when needed.
|
||||
gboolean _themes_loaded;
|
||||
// List of IconTheme*
|
||||
GSList *themes_fallback;
|
||||
GSList *_queued;
|
||||
// Fallback themes are loaded lazily when needed.
|
||||
gboolean _fallback_loaded;
|
||||
GHashTable *_cache;
|
||||
gboolean _cache_dirty;
|
||||
// List of icon theme names that have been queued for loading.
|
||||
// Used to avoid loading the same theme twice, and to avoid cycles.
|
||||
GSList *_queued;
|
||||
} IconThemeWrapper;
|
||||
|
||||
typedef struct IconTheme {
|
||||
|
@ -33,14 +42,16 @@ int parse_theme_line(char *line, char **key, char **value);
|
|||
// inherited themes, the hicolor theme and possibly fallback themes.
|
||||
IconThemeWrapper *load_themes(const char *icon_theme_name);
|
||||
|
||||
void free_themes(IconThemeWrapper *themes);
|
||||
void save_icon_cache(IconThemeWrapper *wrapper);
|
||||
|
||||
void free_themes(IconThemeWrapper *wrapper);
|
||||
void free_icon_theme(IconTheme *theme);
|
||||
|
||||
#define DEFAULT_ICON "application-x-executable"
|
||||
|
||||
// Returns the full path to an icon file (or NULL) given the list of icon themes to search and the icon name
|
||||
// Note: needs to be released with free().
|
||||
char *get_icon_path(IconThemeWrapper *theme, const char *icon_name, int size);
|
||||
char *get_icon_path(IconThemeWrapper *wrapper, const char *icon_name, int size);
|
||||
|
||||
// Returns a list of the directories used to store icons.
|
||||
// Do not free the result, it is cached.
|
||||
|
|
|
@ -147,8 +147,8 @@ void cleanup_launcher_theme(Launcher *launcher)
|
|||
g_slist_free(launcher->list_icons);
|
||||
launcher->list_icons = NULL;
|
||||
|
||||
free_themes(launcher->list_themes);
|
||||
launcher->list_themes = NULL;
|
||||
free_themes(launcher->icon_theme_wrapper);
|
||||
launcher->icon_theme_wrapper = NULL;
|
||||
}
|
||||
|
||||
gboolean resize_launcher(void *obj)
|
||||
|
@ -176,7 +176,7 @@ gboolean resize_launcher(void *obj)
|
|||
|
||||
// Get the path for an icon file with the new size
|
||||
char *new_icon_path =
|
||||
get_icon_path(launcher->list_themes, launcherIcon->icon_name, launcherIcon->icon_size);
|
||||
get_icon_path(launcher->icon_theme_wrapper, launcherIcon->icon_name, launcherIcon->icon_size);
|
||||
if (!new_icon_path) {
|
||||
// Draw a blank icon
|
||||
free_icon(launcherIcon->image);
|
||||
|
@ -195,7 +195,7 @@ gboolean resize_launcher(void *obj)
|
|||
// On loading error, fallback to default
|
||||
if (!launcherIcon->image) {
|
||||
free(new_icon_path);
|
||||
new_icon_path = get_icon_path(launcher->list_themes, DEFAULT_ICON, launcherIcon->icon_size);
|
||||
new_icon_path = get_icon_path(launcher->icon_theme_wrapper, DEFAULT_ICON, launcherIcon->icon_size);
|
||||
if (new_icon_path)
|
||||
launcherIcon->image = imlib_load_image_immediately(new_icon_path);
|
||||
}
|
||||
|
@ -225,6 +225,7 @@ gboolean resize_launcher(void *obj)
|
|||
panel_config.mouse_pressed_brightness);
|
||||
}
|
||||
}
|
||||
save_icon_cache(launcher->icon_theme_wrapper);
|
||||
|
||||
int count = g_slist_length(launcher->list_icons);
|
||||
|
||||
|
@ -465,10 +466,10 @@ void launcher_load_icons(Launcher *launcher)
|
|||
}
|
||||
}
|
||||
|
||||
// Populates the list_themes list
|
||||
// Populates the icon_theme_wrapper list
|
||||
void launcher_load_themes(Launcher *launcher)
|
||||
{
|
||||
launcher->list_themes =
|
||||
launcher->icon_theme_wrapper =
|
||||
load_themes(launcher_icon_theme_override
|
||||
? (icon_theme_name_config ? icon_theme_name_config
|
||||
: icon_theme_name_xsettings ? icon_theme_name_xsettings : "hicolor")
|
||||
|
|
|
@ -17,7 +17,7 @@ typedef struct Launcher {
|
|||
Area area;
|
||||
GSList *list_apps; // List of char*, each is a path to a app.desktop file
|
||||
GSList *list_icons; // List of LauncherIcon*
|
||||
IconThemeWrapper *list_themes;
|
||||
IconThemeWrapper *icon_theme_wrapper;
|
||||
} Launcher;
|
||||
|
||||
typedef struct LauncherIcon {
|
||||
|
|
|
@ -485,6 +485,7 @@ static void edit_current_theme()
|
|||
GtkWidget *prop;
|
||||
prop = create_properties();
|
||||
config_read_file(file);
|
||||
save_icon_cache(icon_theme);
|
||||
gtk_window_present(GTK_WINDOW(prop));
|
||||
g_free(file);
|
||||
}
|
||||
|
|
|
@ -2222,6 +2222,7 @@ void icon_theme_changed()
|
|||
|
||||
load_icons(launcher_apps);
|
||||
load_icons(all_apps);
|
||||
save_icon_cache(icon_theme);
|
||||
}
|
||||
|
||||
void launcher_icon_theme_changed(GtkWidget *widget, gpointer data)
|
||||
|
|
Loading…
Reference in a new issue