@@ -18,6 +18,7 @@ | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <sys/time.h> | |||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
@@ -292,6 +293,9 @@ int tns_translate(tns_t *tns, int x, int y) { | |||||
return -1; | return -1; | ||||
} | } | ||||
/* thumbnail caching */ | |||||
int tns_cache_enabled() { | int tns_cache_enabled() { | ||||
int len, ret = 0; | int len, ret = 0; | ||||
char *cpath, *homedir; | char *cpath, *homedir; | ||||
@@ -309,5 +313,70 @@ int tns_cache_enabled() { | |||||
return ret; | return ret; | ||||
} | } | ||||
char* tns_cache_filename(const char *filename) { | |||||
size_t len; | |||||
int i; | |||||
char *cfile, *abspath, *homedir; | |||||
if (!filename) | |||||
return NULL; | |||||
if (!(homedir = getenv("HOME"))) | |||||
return NULL; | |||||
if (*filename != '/') { | |||||
if (!(abspath = absolute_path(filename))) | |||||
return NULL; | |||||
} else { | |||||
abspath = (char*) s_malloc(strlen(filename) + 1); | |||||
strcpy(abspath, filename); | |||||
} | |||||
len = strlen(abspath); | |||||
for (i = 1; i < len; ++i) { | |||||
if (abspath[i] == '/') | |||||
abspath[i] = '%'; | |||||
} | |||||
len += strlen(homedir) + 15; | |||||
cfile = (char*) s_malloc(len); | |||||
snprintf(cfile, len, "%s/.sxiv/%s.png", homedir, abspath + 1); | |||||
free(abspath); | |||||
return cfile; | |||||
} | |||||
void tns_cache_write(thumb_t *t, Bool force) { | void tns_cache_write(thumb_t *t, Bool force) { | ||||
char *cfile; | |||||
struct stat cstats, fstats; | |||||
struct timeval times[2]; | |||||
Imlib_Load_Error err; | |||||
if (!t || !t->im || !t->filename) | |||||
return; | |||||
if ((cfile = tns_cache_filename(t->filename))) { | |||||
if (stat(t->filename, &fstats)) | |||||
goto end; | |||||
if (force || stat(cfile, &cstats) || | |||||
cstats.st_mtim.tv_sec != fstats.st_mtim.tv_sec || | |||||
cstats.st_mtim.tv_nsec != fstats.st_mtim.tv_nsec) | |||||
{ | |||||
imlib_context_set_image(t->im); | |||||
imlib_image_set_format("png"); | |||||
imlib_save_image_with_error_return(cfile, &err); | |||||
if (err) { | |||||
warn("could not cache thumbnail:", t->filename); | |||||
} else { | |||||
TIMESPEC_TO_TIMEVAL(×[0], &fstats.st_atim); | |||||
TIMESPEC_TO_TIMEVAL(×[1], &fstats.st_mtim); | |||||
utimes(cfile, times); | |||||
} | |||||
} | |||||
} | |||||
end: | |||||
free(cfile); | |||||
} | } |
@@ -18,11 +18,13 @@ | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | |||||
#include <errno.h> | |||||
#include "options.h" | #include "options.h" | ||||
#include "util.h" | #include "util.h" | ||||
#define FNAME_LEN 512 | #define FNAME_LEN 1024 | ||||
void cleanup(); | void cleanup(); | ||||
@@ -78,6 +80,82 @@ void size_readable(float *size, const char **unit) { | |||||
*unit = units[MIN(i, LEN(units) - 1)]; | *unit = units[MIN(i, LEN(units) - 1)]; | ||||
} | } | ||||
char* absolute_path(const char *filename) { | |||||
size_t len; | |||||
char *path = NULL; | |||||
const char *basename; | |||||
char *dirname = NULL; | |||||
char *cwd = NULL; | |||||
char *twd = NULL; | |||||
char *dir; | |||||
char *s; | |||||
if (!filename || *filename == '\0' || *filename == '/') | |||||
return NULL; | |||||
len = FNAME_LEN; | |||||
cwd = (char*) s_malloc(len); | |||||
while (!(s = getcwd(cwd, len)) && errno == ERANGE) { | |||||
len *= 2; | |||||
cwd = (char*) s_realloc(cwd, len); | |||||
} | |||||
if (!s) | |||||
goto error; | |||||
s = strrchr(filename, '/'); | |||||
if (s) { | |||||
len = s - filename; | |||||
dirname = (char*) s_malloc(len + 1); | |||||
strncpy(dirname, filename, len); | |||||
dirname[len] = '\0'; | |||||
basename = s + 1; | |||||
if (chdir(cwd)) | |||||
/* we're not able to come back afterwards */ | |||||
goto error; | |||||
if (chdir(dirname)) | |||||
goto error; | |||||
len = FNAME_LEN; | |||||
twd = (char*) s_malloc(len); | |||||
while (!(s = getcwd(twd, len)) && errno == ERANGE) { | |||||
len *= 2; | |||||
twd = (char*) s_realloc(twd, len); | |||||
} | |||||
if (chdir(cwd)) | |||||
die("could not revert to working directory"); | |||||
if (!s) | |||||
goto error; | |||||
dir = twd; | |||||
} else { | |||||
/* only a single filename given */ | |||||
basename = filename; | |||||
dir = cwd; | |||||
} | |||||
len = strlen(dir) + strlen(basename) + 2; | |||||
path = (char*) s_malloc(len); | |||||
snprintf(path, len, "%s/%s", dir, basename); | |||||
goto end; | |||||
error: | |||||
if (path) { | |||||
free(path); | |||||
path = NULL; | |||||
} | |||||
end: | |||||
if (dirname) | |||||
free(dirname); | |||||
if (cwd) | |||||
free(cwd); | |||||
if (twd) | |||||
free(twd); | |||||
return path; | |||||
} | |||||
char* readline(FILE *stream) { | char* readline(FILE *stream) { | ||||
size_t len; | size_t len; | ||||
char *buf, *s, *end; | char *buf, *s, *end; | ||||
@@ -30,6 +30,11 @@ | |||||
#define TV_TO_DOUBLE(x) ((double) ((x).tv_sec) + 0.000001 * \ | #define TV_TO_DOUBLE(x) ((double) ((x).tv_sec) + 0.000001 * \ | ||||
(double) ((x).tv_usec)) | (double) ((x).tv_usec)) | ||||
#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ | |||||
(tv)->tv_sec = (ts)->tv_sec; \ | |||||
(tv)->tv_usec = (ts)->tv_nsec / 1000; \ | |||||
} | |||||
void* s_malloc(size_t); | void* s_malloc(size_t); | ||||
void* s_realloc(void*, size_t); | void* s_realloc(void*, size_t); | ||||
@@ -38,6 +43,8 @@ void die(const char*, ...); | |||||
void size_readable(float*, const char**); | void size_readable(float*, const char**); | ||||
char* absolute_path(const char*); | |||||
char* readline(FILE*); | char* readline(FILE*); | ||||
#endif /* UTIL_H */ | #endif /* UTIL_H */ |