nsxivc21a3e3
Write thumbnail cache files on exit
+155 −1
3 files changed
| @@ -18,6 +18,7 @@ | |||
| 18 | 18 | ||
| 19 | 19 | #include <stdlib.h> | |
| 20 | 20 | #include <string.h> | |
| 21 | + | #include <sys/time.h> | |
| 21 | 22 | #include <sys/types.h> | |
| 22 | 23 | #include <sys/stat.h> | |
| 23 | 24 | #include <unistd.h> | |
| @@ -292,6 +293,9 @@ int tns_translate(tns_t *tns, int x, int y) { | |||
| 292 | 293 | return -1; | |
| 293 | 294 | } | |
| 294 | 295 | ||
| 296 | + | ||
| 297 | + | /* thumbnail caching */ | |
| 298 | + | ||
| 295 | 299 | int tns_cache_enabled() { | |
| 296 | 300 | int len, ret = 0; | |
| 297 | 301 | char *cpath, *homedir; | |
| @@ -309,5 +313,70 @@ int tns_cache_enabled() { | |||
| 309 | 313 | return ret; | |
| 310 | 314 | } | |
| 311 | 315 | ||
| 316 | + | char* tns_cache_filename(const char *filename) { | |
| 317 | + | size_t len; | |
| 318 | + | int i; | |
| 319 | + | char *cfile, *abspath, *homedir; | |
| 320 | + | ||
| 321 | + | if (!filename) | |
| 322 | + | return NULL; | |
| 323 | + | if (!(homedir = getenv("HOME"))) | |
| 324 | + | return NULL; | |
| 325 | + | ||
| 326 | + | if (*filename != '/') { | |
| 327 | + | if (!(abspath = absolute_path(filename))) | |
| 328 | + | return NULL; | |
| 329 | + | } else { | |
| 330 | + | abspath = (char*) s_malloc(strlen(filename) + 1); | |
| 331 | + | strcpy(abspath, filename); | |
| 332 | + | } | |
| 333 | + | ||
| 334 | + | len = strlen(abspath); | |
| 335 | + | for (i = 1; i < len; ++i) { | |
| 336 | + | if (abspath[i] == '/') | |
| 337 | + | abspath[i] = '%'; | |
| 338 | + | } | |
| 339 | + | ||
| 340 | + | len += strlen(homedir) + 15; | |
| 341 | + | cfile = (char*) s_malloc(len); | |
| 342 | + | snprintf(cfile, len, "%s/.sxiv/%s.png", homedir, abspath + 1); | |
| 343 | + | ||
| 344 | + | free(abspath); | |
| 345 | + | ||
| 346 | + | return cfile; | |
| 347 | + | } | |
| 348 | + | ||
| 312 | 349 | void tns_cache_write(thumb_t *t, Bool force) { | |
| 350 | + | char *cfile; | |
| 351 | + | struct stat cstats, fstats; | |
| 352 | + | struct timeval times[2]; | |
| 353 | + | Imlib_Load_Error err; | |
| 354 | + | ||
| 355 | + | if (!t || !t->im || !t->filename) | |
| 356 | + | return; | |
| 357 | + | ||
| 358 | + | if ((cfile = tns_cache_filename(t->filename))) { | |
| 359 | + | if (stat(t->filename, &fstats)) | |
| 360 | + | goto end; | |
| 361 | + | ||
| 362 | + | if (force || stat(cfile, &cstats) || | |
| 363 | + | cstats.st_mtim.tv_sec != fstats.st_mtim.tv_sec || | |
| 364 | + | cstats.st_mtim.tv_nsec != fstats.st_mtim.tv_nsec) | |
| 365 | + | { | |
| 366 | + | imlib_context_set_image(t->im); | |
| 367 | + | imlib_image_set_format("png"); | |
| 368 | + | imlib_save_image_with_error_return(cfile, &err); | |
| 369 | + | ||
| 370 | + | if (err) { | |
| 371 | + | warn("could not cache thumbnail:", t->filename); | |
| 372 | + | } else { | |
| 373 | + | TIMESPEC_TO_TIMEVAL(×[0], &fstats.st_atim); | |
| 374 | + | TIMESPEC_TO_TIMEVAL(×[1], &fstats.st_mtim); | |
| 375 | + | utimes(cfile, times); | |
| 376 | + | } | |
| 377 | + | } | |
| 378 | + | } | |
| 379 | + | ||
| 380 | + | end: | |
| 381 | + | free(cfile); | |
| 313 | 382 | } | |
| @@ -18,11 +18,13 @@ | |||
| 18 | 18 | ||
| 19 | 19 | #include <stdlib.h> | |
| 20 | 20 | #include <string.h> | |
| 21 | + | #include <unistd.h> | |
| 22 | + | #include <errno.h> | |
| 21 | 23 | ||
| 22 | 24 | #include "options.h" | |
| 23 | 25 | #include "util.h" | |
| 24 | 26 | ||
| 25 | − | #define FNAME_LEN 512 | |
| 27 | + | #define FNAME_LEN 1024 | |
| 26 | 28 | ||
| 27 | 29 | void cleanup(); | |
| 28 | 30 | ||
| @@ -78,6 +80,82 @@ void size_readable(float *size, const char **unit) { | |||
| 78 | 80 | *unit = units[MIN(i, LEN(units) - 1)]; | |
| 79 | 81 | } | |
| 80 | 82 | ||
| 83 | + | char* absolute_path(const char *filename) { | |
| 84 | + | size_t len; | |
| 85 | + | char *path = NULL; | |
| 86 | + | const char *basename; | |
| 87 | + | char *dirname = NULL; | |
| 88 | + | char *cwd = NULL; | |
| 89 | + | char *twd = NULL; | |
| 90 | + | char *dir; | |
| 91 | + | char *s; | |
| 92 | + | ||
| 93 | + | if (!filename || *filename == '\0' || *filename == '/') | |
| 94 | + | return NULL; | |
| 95 | + | ||
| 96 | + | len = FNAME_LEN; | |
| 97 | + | cwd = (char*) s_malloc(len); | |
| 98 | + | while (!(s = getcwd(cwd, len)) && errno == ERANGE) { | |
| 99 | + | len *= 2; | |
| 100 | + | cwd = (char*) s_realloc(cwd, len); | |
| 101 | + | } | |
| 102 | + | if (!s) | |
| 103 | + | goto error; | |
| 104 | + | ||
| 105 | + | s = strrchr(filename, '/'); | |
| 106 | + | if (s) { | |
| 107 | + | len = s - filename; | |
| 108 | + | dirname = (char*) s_malloc(len + 1); | |
| 109 | + | strncpy(dirname, filename, len); | |
| 110 | + | dirname[len] = '\0'; | |
| 111 | + | basename = s + 1; | |
| 112 | + | ||
| 113 | + | if (chdir(cwd)) | |
| 114 | + | /* we're not able to come back afterwards */ | |
| 115 | + | goto error; | |
| 116 | + | if (chdir(dirname)) | |
| 117 | + | goto error; | |
| 118 | + | ||
| 119 | + | len = FNAME_LEN; | |
| 120 | + | twd = (char*) s_malloc(len); | |
| 121 | + | while (!(s = getcwd(twd, len)) && errno == ERANGE) { | |
| 122 | + | len *= 2; | |
| 123 | + | twd = (char*) s_realloc(twd, len); | |
| 124 | + | } | |
| 125 | + | if (chdir(cwd)) | |
| 126 | + | die("could not revert to working directory"); | |
| 127 | + | if (!s) | |
| 128 | + | goto error; | |
| 129 | + | dir = twd; | |
| 130 | + | } else { | |
| 131 | + | /* only a single filename given */ | |
| 132 | + | basename = filename; | |
| 133 | + | dir = cwd; | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | len = strlen(dir) + strlen(basename) + 2; | |
| 137 | + | path = (char*) s_malloc(len); | |
| 138 | + | snprintf(path, len, "%s/%s", dir, basename); | |
| 139 | + | ||
| 140 | + | goto end; | |
| 141 | + | ||
| 142 | + | error: | |
| 143 | + | if (path) { | |
| 144 | + | free(path); | |
| 145 | + | path = NULL; | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | end: | |
| 149 | + | if (dirname) | |
| 150 | + | free(dirname); | |
| 151 | + | if (cwd) | |
| 152 | + | free(cwd); | |
| 153 | + | if (twd) | |
| 154 | + | free(twd); | |
| 155 | + | ||
| 156 | + | return path; | |
| 157 | + | } | |
| 158 | + | ||
| 81 | 159 | char* readline(FILE *stream) { | |
| 82 | 160 | size_t len; | |
| 83 | 161 | char *buf, *s, *end; | |
| @@ -30,6 +30,11 @@ | |||
| 30 | 30 | #define TV_TO_DOUBLE(x) ((double) ((x).tv_sec) + 0.000001 * \ | |
| 31 | 31 | (double) ((x).tv_usec)) | |
| 32 | 32 | ||
| 33 | + | #define TIMESPEC_TO_TIMEVAL(tv, ts) { \ | |
| 34 | + | (tv)->tv_sec = (ts)->tv_sec; \ | |
| 35 | + | (tv)->tv_usec = (ts)->tv_nsec / 1000; \ | |
| 36 | + | } | |
| 37 | + | ||
| 33 | 38 | void* s_malloc(size_t); | |
| 34 | 39 | void* s_realloc(void*, size_t); | |
| 35 | 40 | ||
| @@ -38,6 +43,8 @@ void die(const char*, ...); | |||
| 38 | 43 | ||
| 39 | 44 | void size_readable(float*, const char**); | |
| 40 | 45 | ||
| 46 | + | char* absolute_path(const char*); | |
| 47 | + | ||
| 41 | 48 | char* readline(FILE*); | |
| 42 | 49 | ||
| 43 | 50 | #endif /* UTIL_H */ | |