Move icon cache to a separate file; protect cache with file locks
This commit is contained in:
parent
4dfe411bf4
commit
50e6278327
7 changed files with 214 additions and 81 deletions
|
@ -118,6 +118,7 @@ set( SOURCES src/config.c
|
|||
src/util/common.c
|
||||
src/util/strnatcmp.c
|
||||
src/util/timer.c
|
||||
src/util/cache.c
|
||||
src/util/window.c )
|
||||
|
||||
if( ENABLE_BATTERY )
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "apps-common.h"
|
||||
#include "common.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define ICON_DIR_TYPE_SCALABLE 0
|
||||
#define ICON_DIR_TYPE_FIXED 1
|
||||
|
@ -317,7 +318,7 @@ void free_themes(IconThemeWrapper *wrapper)
|
|||
}
|
||||
g_slist_free(wrapper->themes_fallback);
|
||||
g_slist_free_full(wrapper->_queued, free);
|
||||
g_hash_table_destroy(wrapper->_cache);
|
||||
free_cache(&wrapper->_cache);
|
||||
free(wrapper);
|
||||
}
|
||||
|
||||
|
@ -452,72 +453,9 @@ 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)
|
||||
if (wrapper->_cache.loaded)
|
||||
return;
|
||||
|
||||
fprintf(stderr, GREEN "Loading icon theme cache..." RESET "\n");
|
||||
|
@ -529,12 +467,12 @@ void load_icon_cache(IconThemeWrapper *wrapper)
|
|||
|
||||
void save_icon_cache(IconThemeWrapper *wrapper)
|
||||
{
|
||||
if (!wrapper || !wrapper->_cache || !wrapper->_cache_dirty)
|
||||
if (!wrapper || !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);
|
||||
save_cache(&wrapper->_cache, cache_path);
|
||||
g_free(cache_path);
|
||||
}
|
||||
|
||||
|
@ -761,8 +699,9 @@ char *get_icon_path_from_cache(IconThemeWrapper *wrapper, const char *icon_name,
|
|||
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);
|
||||
const gchar *value = get_from_cache(&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",
|
||||
|
@ -787,13 +726,8 @@ void add_icon_path_to_cache(IconThemeWrapper *wrapper, const char *icon_name, in
|
|||
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)) {
|
||||
add_to_cache(&wrapper->_cache, key, 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)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define ICON_THEME_COMMON_H
|
||||
|
||||
#include <glib.h>
|
||||
#include "cache.h"
|
||||
|
||||
typedef struct IconThemeWrapper {
|
||||
// The icon theme name for which this wrapper was created
|
||||
|
@ -19,8 +20,7 @@ typedef struct IconThemeWrapper {
|
|||
GSList *themes_fallback;
|
||||
// Fallback themes are loaded lazily when needed.
|
||||
gboolean _fallback_loaded;
|
||||
GHashTable *_cache;
|
||||
gboolean _cache_dirty;
|
||||
Cache _cache;
|
||||
// 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;
|
||||
|
|
|
@ -21,6 +21,7 @@ include_directories( ../util
|
|||
|
||||
set(SOURCES ../util/common.c
|
||||
../util/strnatcmp.c
|
||||
../util/cache.c
|
||||
../config.c
|
||||
../server.c
|
||||
../launcher/apps-common.c
|
||||
|
|
156
src/util/cache.c
Normal file
156
src/util/cache.c
Normal file
|
@ -0,0 +1,156 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Tint2 : cache
|
||||
*
|
||||
* Copyright (C) 2016 @o9000
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**************************************************************************/
|
||||
|
||||
#include "cache.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void init_cache(Cache *cache)
|
||||
{
|
||||
if (cache->_table)
|
||||
free_cache(cache);
|
||||
cache->_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
||||
cache->dirty = FALSE;
|
||||
cache->loaded = FALSE;
|
||||
}
|
||||
|
||||
void free_cache(Cache *cache)
|
||||
{
|
||||
if (cache->_table)
|
||||
g_hash_table_destroy(cache->_table);
|
||||
cache->_table = NULL;
|
||||
cache->dirty = FALSE;
|
||||
cache->loaded = FALSE;
|
||||
}
|
||||
|
||||
void load_cache(Cache *cache, const gchar *cache_path)
|
||||
{
|
||||
init_cache(cache);
|
||||
|
||||
int fd = open(cache_path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return;
|
||||
flock(fd, LOCK_SH);
|
||||
|
||||
FILE *f = fopen(cache_path, "rt");
|
||||
if (!f)
|
||||
goto unlock;
|
||||
|
||||
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_line(line, &key, &value)) {
|
||||
g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value));
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
fclose(f);
|
||||
|
||||
cache->loaded = TRUE;
|
||||
|
||||
unlock:
|
||||
flock(fd, LOCK_UN);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
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(Cache *cache, const gchar *cache_path)
|
||||
{
|
||||
int fd = open(cache_path, O_RDONLY | O_CREAT);
|
||||
if (fd == -1)
|
||||
return;
|
||||
flock(fd, LOCK_EX);
|
||||
|
||||
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");
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
g_hash_table_foreach(cache->_table, write_cache_line, f);
|
||||
fclose(f);
|
||||
cache->dirty = FALSE;
|
||||
|
||||
unlock:
|
||||
flock(fd, LOCK_UN);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
const gchar *get_from_cache(Cache *cache, const gchar *key)
|
||||
{
|
||||
if (!cache->_table)
|
||||
return NULL;
|
||||
return g_hash_table_lookup(cache->_table, key);
|
||||
}
|
||||
|
||||
void add_to_cache(Cache *cache, const gchar *key, const gchar *value)
|
||||
{
|
||||
if (!cache->_table)
|
||||
init_cache(cache);
|
||||
|
||||
if (!key || !value)
|
||||
return;
|
||||
|
||||
gchar *old_value = g_hash_table_lookup(cache->_table, key);
|
||||
if (old_value && g_str_equal(old_value, value))
|
||||
return;
|
||||
|
||||
g_hash_table_insert(cache->_table, g_strdup(key), g_strdup(value));
|
||||
cache->dirty = TRUE;
|
||||
}
|
39
src/util/cache.h
Normal file
39
src/util/cache.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef CACHE_H
|
||||
#define CACHE_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
// A cache with string keys and values, backed by a file.
|
||||
// The strings must not be NULL and are stripped of any whitespace at start and end.
|
||||
typedef struct Cache {
|
||||
gboolean dirty;
|
||||
gboolean loaded;
|
||||
GHashTable *_table;
|
||||
} Cache;
|
||||
|
||||
// Initializes the cache. You can also call load_cache directly if you set the memory contents to zero first.
|
||||
void init_cache(Cache *cache);
|
||||
|
||||
// Clears the cache contents and releases all memory, but not the object.
|
||||
// You can use init_cache or load_cache afterwards.
|
||||
void free_cache(Cache *cache);
|
||||
|
||||
// Clears the cache contents and loads new contents from a file.
|
||||
// Sets the loaded flag to TRUE.
|
||||
void load_cache(Cache *cache, const gchar *cache_path);
|
||||
|
||||
// Saves the cache contents to a file.
|
||||
// Clears the dirty flag.
|
||||
void save_cache(Cache *cache, const gchar *cache_path);
|
||||
|
||||
// Returns a pointer to the value in the cache, or NULL if not found.
|
||||
// Do not free the returned value!
|
||||
const gchar *get_from_cache(Cache *cache, const gchar *key);
|
||||
|
||||
// Adds a key-value pair to the cache. NULL keys or values are not allowed.
|
||||
// If the key already exists, the old value is and replaced with the new value.
|
||||
// Does not take ownership of the pointers (neither key, nor value); instead it makes copies.
|
||||
// Sets the dirty flag to TRUE.
|
||||
void add_to_cache(Cache *cache, const gchar *key, const gchar *value);
|
||||
|
||||
#endif
|
|
@ -177,3 +177,5 @@ tint2.files
|
|||
tint2.includes
|
||||
tint2.svg
|
||||
src/tint2conf/po/ru.po
|
||||
src/util/cache.c
|
||||
src/util/cache.h
|
||||
|
|
Loading…
Reference in a new issue