Merge branch 'tcache'
Conflicts: main.c
This commit is contained in:
commit
bac610ddc4
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
||||||
all: sxiv
|
all: sxiv
|
||||||
|
|
||||||
VERSION=git-20110407
|
VERSION=git-20110408
|
||||||
|
|
||||||
CC?=gcc
|
CC?=gcc
|
||||||
PREFIX?=/usr/local
|
PREFIX?=/usr/local
|
||||||
|
|
|
@ -36,6 +36,7 @@ sxiv supports the following command-line options:
|
||||||
|
|
||||||
-a Display all given files, do not filter out unsupported files
|
-a Display all given files, do not filter out unsupported files
|
||||||
(shorter startup time for long file list or slow file types)
|
(shorter startup time for long file list or slow file types)
|
||||||
|
-C Remove all orphaned cache files from thumbnail cache and exit
|
||||||
-d Scale all images to 100%, but fit large images into window
|
-d Scale all images to 100%, but fit large images into window
|
||||||
-F Use size-hints to make the window fixed/floating
|
-F Use size-hints to make the window fixed/floating
|
||||||
-f Start in fullscreen mode
|
-f Start in fullscreen mode
|
||||||
|
|
110
main.c
110
main.c
|
@ -19,7 +19,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -48,7 +47,6 @@ typedef enum {
|
||||||
|
|
||||||
void update_title();
|
void update_title();
|
||||||
int check_append(const char*);
|
int check_append(const char*);
|
||||||
void read_dir_rec(const char*);
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
appmode_t mode;
|
appmode_t mode;
|
||||||
|
@ -56,7 +54,6 @@ img_t img;
|
||||||
tns_t tns;
|
tns_t tns;
|
||||||
win_t win;
|
win_t win;
|
||||||
|
|
||||||
#define DNAME_CNT 512
|
|
||||||
#define FNAME_CNT 1024
|
#define FNAME_CNT 1024
|
||||||
const char **filenames;
|
const char **filenames;
|
||||||
int filecnt, fileidx;
|
int filecnt, fileidx;
|
||||||
|
@ -95,13 +92,24 @@ int load_image(int new) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fncmp(const void *a, const void *b) {
|
||||||
|
return strcoll(*((char* const*) a), *((char* const*) b));
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
int i;
|
int i, start;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
struct stat fstats;
|
struct stat fstats;
|
||||||
|
r_dir_t dir;
|
||||||
|
|
||||||
parse_options(argc, argv);
|
parse_options(argc, argv);
|
||||||
|
|
||||||
|
if (options->clean_cache) {
|
||||||
|
tns_init(&tns, 0);
|
||||||
|
tns_clear_cache(&tns);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (!options->filecnt) {
|
if (!options->filecnt) {
|
||||||
print_usage();
|
print_usage();
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -123,13 +131,26 @@ int main(int argc, char **argv) {
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < options->filecnt; ++i) {
|
for (i = 0; i < options->filecnt; ++i) {
|
||||||
filename = options->filenames[i];
|
filename = options->filenames[i];
|
||||||
if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
|
|
||||||
if (options->recursive)
|
if (stat(filename, &fstats) || !S_ISDIR(fstats.st_mode)) {
|
||||||
read_dir_rec(filename);
|
|
||||||
else
|
|
||||||
warn("ignoring directory: %s", filename);
|
|
||||||
} else {
|
|
||||||
check_append(filename);
|
check_append(filename);
|
||||||
|
} else {
|
||||||
|
if (!options->recursive) {
|
||||||
|
warn("ignoring directory: %s", filename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (r_opendir(&dir, filename)) {
|
||||||
|
warn("could not open directory: %s", filename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
start = fileidx;
|
||||||
|
while ((filename = r_readdir(&dir))) {
|
||||||
|
if (!check_append(filename))
|
||||||
|
free((void*) filename);
|
||||||
|
}
|
||||||
|
r_closedir(&dir);
|
||||||
|
if (fileidx - start > 1)
|
||||||
|
qsort(filenames + start, fileidx - start, sizeof(char*), fncmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,75 +236,6 @@ int check_append(const char *filename) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int fncmp(const void *a, const void *b) {
|
|
||||||
return strcoll(*((char* const*) a), *((char* const*) b));
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_dir_rec(const char *dirname) {
|
|
||||||
char *filename;
|
|
||||||
const char **dirnames;
|
|
||||||
int dircnt, diridx;
|
|
||||||
int fcnt, fstart;
|
|
||||||
unsigned char first;
|
|
||||||
size_t len;
|
|
||||||
DIR *dir;
|
|
||||||
struct dirent *dentry;
|
|
||||||
struct stat fstats;
|
|
||||||
|
|
||||||
if (!dirname)
|
|
||||||
return;
|
|
||||||
|
|
||||||
dircnt = DNAME_CNT;
|
|
||||||
diridx = first = 1;
|
|
||||||
dirnames = (const char**) s_malloc(dircnt * sizeof(const char*));
|
|
||||||
dirnames[0] = dirname;
|
|
||||||
|
|
||||||
fcnt = 0;
|
|
||||||
fstart = fileidx;
|
|
||||||
|
|
||||||
while (diridx > 0) {
|
|
||||||
dirname = dirnames[--diridx];
|
|
||||||
if (!(dir = opendir(dirname))) {
|
|
||||||
warn("could not open directory: %s", dirname);
|
|
||||||
} else {
|
|
||||||
while ((dentry = readdir(dir))) {
|
|
||||||
if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
len = strlen(dirname) + strlen(dentry->d_name) + 2;
|
|
||||||
filename = (char*) s_malloc(len * sizeof(char));
|
|
||||||
snprintf(filename, len, "%s%s%s", dirname,
|
|
||||||
dirname[strlen(dirname)-1] == '/' ? "" : "/", dentry->d_name);
|
|
||||||
|
|
||||||
if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
|
|
||||||
if (diridx == dircnt) {
|
|
||||||
dircnt *= 2;
|
|
||||||
dirnames = (const char**) s_realloc(dirnames,
|
|
||||||
dircnt * sizeof(const char*));
|
|
||||||
}
|
|
||||||
dirnames[diridx++] = filename;
|
|
||||||
} else {
|
|
||||||
if (check_append(filename))
|
|
||||||
++fcnt;
|
|
||||||
else
|
|
||||||
free(filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!first)
|
|
||||||
free((void*) dirname);
|
|
||||||
else
|
|
||||||
first = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fcnt > 1)
|
|
||||||
qsort(filenames + fstart, fcnt, sizeof(char*), fncmp);
|
|
||||||
|
|
||||||
free(dirnames);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if EXT_COMMANDS
|
#if EXT_COMMANDS
|
||||||
int run_command(const char *cline, Bool reload) {
|
int run_command(const char *cline, Bool reload) {
|
||||||
int fncnt, fnlen;
|
int fncnt, fnlen;
|
||||||
|
|
|
@ -31,7 +31,7 @@ options_t _options;
|
||||||
const options_t *options = (const options_t*) &_options;
|
const options_t *options = (const options_t*) &_options;
|
||||||
|
|
||||||
void print_usage() {
|
void print_usage() {
|
||||||
printf("usage: sxiv [-adFfhpqrstvZ] [-g GEOMETRY] [-z ZOOM] FILES...\n");
|
printf("usage: sxiv [-aCdFfhpqrstvZ] [-g GEOMETRY] [-z ZOOM] FILES...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_version() {
|
void print_version() {
|
||||||
|
@ -53,9 +53,10 @@ void parse_options(int argc, char **argv) {
|
||||||
|
|
||||||
_options.all = 0;
|
_options.all = 0;
|
||||||
_options.quiet = 0;
|
_options.quiet = 0;
|
||||||
|
_options.clean_cache = 0;
|
||||||
_options.recursive = 0;
|
_options.recursive = 0;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "adFfg:hpqrstvZz:")) != -1) {
|
while ((opt = getopt(argc, argv, "aCdFfg:hpqrstvZz:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case '?':
|
case '?':
|
||||||
print_usage();
|
print_usage();
|
||||||
|
@ -63,6 +64,9 @@ void parse_options(int argc, char **argv) {
|
||||||
case 'a':
|
case 'a':
|
||||||
_options.all = 1;
|
_options.all = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'C':
|
||||||
|
_options.clean_cache = 1;
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
_options.scalemode = SCALE_DOWN;
|
_options.scalemode = SCALE_DOWN;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -37,6 +37,7 @@ typedef struct {
|
||||||
|
|
||||||
unsigned char all;
|
unsigned char all;
|
||||||
unsigned char quiet;
|
unsigned char quiet;
|
||||||
|
unsigned char clean_cache;
|
||||||
unsigned char recursive;
|
unsigned char recursive;
|
||||||
} options_t;
|
} options_t;
|
||||||
|
|
||||||
|
|
25
sxiv.1
25
sxiv.1
|
@ -3,7 +3,7 @@
|
||||||
sxiv \- Simple (or small or suckless) X Image Viewer
|
sxiv \- Simple (or small or suckless) X Image Viewer
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B sxiv
|
.B sxiv
|
||||||
.RB [ \-adFfhpqrstvZ ]
|
.RB [ \-aCdFfhpqrstvZ ]
|
||||||
.RB [ \-g
|
.RB [ \-g
|
||||||
.IR GEOMETRY ]
|
.IR GEOMETRY ]
|
||||||
.RB [ \-z
|
.RB [ \-z
|
||||||
|
@ -24,6 +24,9 @@ sxiv has two modes of operation: image and thumbnail mode. The default is image
|
||||||
mode, in which only the current image is shown. In thumbnail mode a grid of
|
mode, in which only the current image is shown. In thumbnail mode a grid of
|
||||||
small previews is displayed, making it easy to choose an image to open.
|
small previews is displayed, making it easy to choose an image to open.
|
||||||
.P
|
.P
|
||||||
|
sxiv can also cache its thumbnails. Please see the section THUMBNAIL CACHING
|
||||||
|
for information on how to enable this feature.
|
||||||
|
.P
|
||||||
Please note, that the fullscreen mode requires an EWMH/NetWM compliant window
|
Please note, that the fullscreen mode requires an EWMH/NetWM compliant window
|
||||||
manager.
|
manager.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
|
@ -33,6 +36,9 @@ Display all given files, do not filter out unsupported files. This might result
|
||||||
in a much shorter startup time, when the file list is very long or contains
|
in a much shorter startup time, when the file list is very long or contains
|
||||||
large files of slow loadable types, e.g. gif and progressive jpg.
|
large files of slow loadable types, e.g. gif and progressive jpg.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-C
|
||||||
|
Remove all orphaned cache files from the thumbnail cache directory and exit.
|
||||||
|
.TP
|
||||||
.B \-d
|
.B \-d
|
||||||
Scale all images to 100%, but fit large images into window.
|
Scale all images to 100%, but fit large images into window.
|
||||||
.TP
|
.TP
|
||||||
|
@ -191,6 +197,23 @@ Pan image left.
|
||||||
.TP
|
.TP
|
||||||
.B Shift+ScrollDown
|
.B Shift+ScrollDown
|
||||||
Pan image right.
|
Pan image right.
|
||||||
|
.SH THUMBNAIL CACHING
|
||||||
|
To enable thumbnail caching, please make sure to create the directory
|
||||||
|
.I ~/.sxiv/
|
||||||
|
with write permissions. sxiv will then store all thumbnails inside this
|
||||||
|
directory, but it will not create this directory by itself. It rather uses the
|
||||||
|
existance of this directory as an affirmation, that the user wants thumbnails
|
||||||
|
to be cached.
|
||||||
|
.P
|
||||||
|
Use the command line option
|
||||||
|
.I \-C
|
||||||
|
to keep the cache directory clean by removing all orphaned cache files.
|
||||||
|
Additionally, run the following command afterwards inside the cache directory
|
||||||
|
to remove empty subdirectories:
|
||||||
|
.P
|
||||||
|
.RS
|
||||||
|
find -type d -empty -delete
|
||||||
|
.RE
|
||||||
.SH AUTHORS
|
.SH AUTHORS
|
||||||
.EX
|
.EX
|
||||||
Bert Muennich <ber.t at gmx.com>
|
Bert Muennich <ber.t at gmx.com>
|
||||||
|
|
198
thumbs.c
198
thumbs.c
|
@ -18,49 +18,214 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "thumbs.h"
|
#include "thumbs.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
extern Imlib_Image *im_invalid;
|
extern Imlib_Image *im_invalid;
|
||||||
|
|
||||||
const int thumb_dim = THUMB_SIZE + 10;
|
const int thumb_dim = THUMB_SIZE + 10;
|
||||||
|
char *cache_dir = NULL;
|
||||||
|
|
||||||
|
int tns_cache_enabled() {
|
||||||
|
struct stat stats;
|
||||||
|
|
||||||
|
return cache_dir && !stat(cache_dir, &stats) && S_ISDIR(stats.st_mode) &&
|
||||||
|
!access(cache_dir, W_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* tns_cache_filename(const char *filename) {
|
||||||
|
size_t len;
|
||||||
|
char *cfile = NULL;
|
||||||
|
const char *abspath;
|
||||||
|
|
||||||
|
if (!cache_dir || !filename)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (*filename != '/') {
|
||||||
|
if (!(abspath = absolute_path(filename)))
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
abspath = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(abspath, cache_dir, strlen(cache_dir))) {
|
||||||
|
len = strlen(cache_dir) + strlen(abspath) + 6;
|
||||||
|
cfile = (char*) s_malloc(len);
|
||||||
|
snprintf(cfile, len, "%s/%s.png", cache_dir, abspath + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abspath != filename)
|
||||||
|
free((void*) abspath);
|
||||||
|
|
||||||
|
return cfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
Imlib_Image* tns_cache_load(const char *filename) {
|
||||||
|
char *cfile;
|
||||||
|
struct stat cstats, fstats;
|
||||||
|
Imlib_Image *im = NULL;
|
||||||
|
|
||||||
|
if (!filename)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (stat(filename, &fstats))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ((cfile = tns_cache_filename(filename))) {
|
||||||
|
if (!stat(cfile, &cstats) &&
|
||||||
|
cstats.st_mtim.tv_sec == fstats.st_mtim.tv_sec &&
|
||||||
|
cstats.st_mtim.tv_nsec == fstats.st_mtim.tv_nsec)
|
||||||
|
{
|
||||||
|
im = imlib_load_image(cfile);
|
||||||
|
}
|
||||||
|
free(cfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return im;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tns_cache_write(thumb_t *t, Bool force) {
|
||||||
|
char *cfile, *dirend;
|
||||||
|
struct stat cstats, fstats;
|
||||||
|
struct timeval times[2];
|
||||||
|
Imlib_Load_Error err = 0;
|
||||||
|
|
||||||
|
if (!t || !t->im || !t->filename)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (stat(t->filename, &fstats))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((cfile = tns_cache_filename(t->filename))) {
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if ((dirend = strrchr(cfile, '/'))) {
|
||||||
|
*dirend = '\0';
|
||||||
|
err = r_mkdir(cfile);
|
||||||
|
*dirend = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!err) {
|
||||||
|
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: %s", t->filename);
|
||||||
|
} else {
|
||||||
|
TIMESPEC_TO_TIMEVAL(×[0], &fstats.st_atim);
|
||||||
|
TIMESPEC_TO_TIMEVAL(×[1], &fstats.st_mtim);
|
||||||
|
utimes(cfile, times);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(cfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tns_clear_cache(tns_t *tns) {
|
||||||
|
int dirlen, delete;
|
||||||
|
char *cfile, *filename, *tpos;
|
||||||
|
r_dir_t dir;
|
||||||
|
|
||||||
|
if (!cache_dir)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (r_opendir(&dir, cache_dir)) {
|
||||||
|
warn("could not open thumbnail cache directory: %s", cache_dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dirlen = strlen(cache_dir);
|
||||||
|
|
||||||
|
while ((cfile = r_readdir(&dir))) {
|
||||||
|
filename = cfile + dirlen;
|
||||||
|
delete = 0;
|
||||||
|
|
||||||
|
if ((tpos = strrchr(filename, '.'))) {
|
||||||
|
*tpos = '\0';
|
||||||
|
delete = access(filename, F_OK);
|
||||||
|
*tpos = '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delete && unlink(cfile))
|
||||||
|
warn("could not delete cache file: %s", cfile);
|
||||||
|
|
||||||
|
free(cfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
r_closedir(&dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void tns_init(tns_t *tns, int cnt) {
|
void tns_init(tns_t *tns, int cnt) {
|
||||||
|
int len;
|
||||||
|
char *homedir;
|
||||||
|
|
||||||
if (!tns)
|
if (!tns)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tns->cnt = tns->first = tns->sel = 0;
|
if (cnt) {
|
||||||
tns->thumbs = (thumb_t*) s_malloc(cnt * sizeof(thumb_t));
|
tns->thumbs = (thumb_t*) s_malloc(cnt * sizeof(thumb_t));
|
||||||
memset(tns->thumbs, 0, cnt * sizeof(thumb_t));
|
memset(tns->thumbs, 0, cnt * sizeof(thumb_t));
|
||||||
|
} else {
|
||||||
|
tns->thumbs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tns->cnt = tns->first = tns->sel = 0;
|
||||||
tns->cap = cnt;
|
tns->cap = cnt;
|
||||||
tns->dirty = 0;
|
tns->dirty = 0;
|
||||||
|
|
||||||
|
if ((homedir = getenv("HOME"))) {
|
||||||
|
if (cache_dir)
|
||||||
|
free(cache_dir);
|
||||||
|
len = strlen(homedir) + 10;
|
||||||
|
cache_dir = (char*) s_malloc(len * sizeof(char));
|
||||||
|
snprintf(cache_dir, len, "%s/.sxiv", homedir);
|
||||||
|
} else {
|
||||||
|
warn("could not locate thumbnail cache directory");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tns_free(tns_t *tns, win_t *win) {
|
void tns_free(tns_t *tns, win_t *win) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!tns || !tns->thumbs)
|
if (!tns)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (tns->thumbs) {
|
||||||
for (i = 0; i < tns->cnt; ++i) {
|
for (i = 0; i < tns->cnt; ++i) {
|
||||||
if (tns->thumbs[i].im) {
|
if (tns->thumbs[i].im) {
|
||||||
imlib_context_set_image(tns->thumbs[i].im);
|
imlib_context_set_image(tns->thumbs[i].im);
|
||||||
imlib_free_image();
|
imlib_free_image();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(tns->thumbs);
|
free(tns->thumbs);
|
||||||
tns->thumbs = NULL;
|
tns->thumbs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cache_dir) {
|
||||||
|
free(cache_dir);
|
||||||
|
cache_dir = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void tns_load(tns_t *tns, win_t *win, int n, const char *filename) {
|
void tns_load(tns_t *tns, win_t *win, int n, const char *filename) {
|
||||||
int w, h;
|
int w, h;
|
||||||
|
int use_cache, cached = 0;
|
||||||
float z, zw, zh;
|
float z, zw, zh;
|
||||||
thumb_t *t;
|
thumb_t *t;
|
||||||
Imlib_Image *im;
|
Imlib_Image *im;
|
||||||
|
|
||||||
if (!tns || !win || !filename)
|
if (!tns || !tns->thumbs || !win || !filename)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (n >= tns->cap)
|
if (n >= tns->cap)
|
||||||
|
@ -75,7 +240,12 @@ void tns_load(tns_t *tns, win_t *win, int n, const char *filename) {
|
||||||
imlib_free_image();
|
imlib_free_image();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((im = imlib_load_image(filename)))
|
if ((use_cache = tns_cache_enabled())) {
|
||||||
|
if ((im = tns_cache_load(filename)))
|
||||||
|
cached = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cached || (im = imlib_load_image(filename)))
|
||||||
imlib_context_set_image(im);
|
imlib_context_set_image(im);
|
||||||
else
|
else
|
||||||
imlib_context_set_image(im_invalid);
|
imlib_context_set_image(im_invalid);
|
||||||
|
@ -84,10 +254,12 @@ void tns_load(tns_t *tns, win_t *win, int n, const char *filename) {
|
||||||
h = imlib_image_get_height();
|
h = imlib_image_get_height();
|
||||||
|
|
||||||
if (im) {
|
if (im) {
|
||||||
|
t->filename = filename;
|
||||||
zw = (float) THUMB_SIZE / (float) w;
|
zw = (float) THUMB_SIZE / (float) w;
|
||||||
zh = (float) THUMB_SIZE / (float) h;
|
zh = (float) THUMB_SIZE / (float) h;
|
||||||
z = MIN(zw, zh);
|
z = MIN(zw, zh);
|
||||||
} else {
|
} else {
|
||||||
|
t->filename = NULL;
|
||||||
z = 1.0;
|
z = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +271,8 @@ void tns_load(tns_t *tns, win_t *win, int n, const char *filename) {
|
||||||
die("could not allocate memory");
|
die("could not allocate memory");
|
||||||
if (im)
|
if (im)
|
||||||
imlib_free_image_and_decache();
|
imlib_free_image_and_decache();
|
||||||
|
if (use_cache && !cached)
|
||||||
|
tns_cache_write(t, False);
|
||||||
|
|
||||||
tns->dirty = 1;
|
tns->dirty = 1;
|
||||||
}
|
}
|
||||||
|
@ -134,7 +308,10 @@ void tns_render(tns_t *tns, win_t *win) {
|
||||||
int i, cnt, r, x, y;
|
int i, cnt, r, x, y;
|
||||||
thumb_t *t;
|
thumb_t *t;
|
||||||
|
|
||||||
if (!tns || !tns->dirty || !win)
|
if (!tns || !tns->thumbs || !win)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!tns->dirty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
win_clear(win);
|
win_clear(win);
|
||||||
|
@ -182,7 +359,7 @@ void tns_highlight(tns_t *tns, win_t *win, int n, Bool hl) {
|
||||||
thumb_t *t;
|
thumb_t *t;
|
||||||
unsigned long col;
|
unsigned long col;
|
||||||
|
|
||||||
if (!tns || !win)
|
if (!tns || !tns->thumbs || !win)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (n >= 0 && n < tns->cnt) {
|
if (n >= 0 && n < tns->cnt) {
|
||||||
|
@ -205,7 +382,7 @@ void tns_highlight(tns_t *tns, win_t *win, int n, Bool hl) {
|
||||||
int tns_move_selection(tns_t *tns, win_t *win, tnsdir_t dir) {
|
int tns_move_selection(tns_t *tns, win_t *win, tnsdir_t dir) {
|
||||||
int old;
|
int old;
|
||||||
|
|
||||||
if (!tns || !win)
|
if (!tns || !tns->thumbs || !win)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
old = tns->sel;
|
old = tns->sel;
|
||||||
|
@ -264,7 +441,10 @@ int tns_translate(tns_t *tns, int x, int y) {
|
||||||
int n;
|
int n;
|
||||||
thumb_t *t;
|
thumb_t *t;
|
||||||
|
|
||||||
if (!tns || x < tns->x || y < tns->y)
|
if (!tns || !tns->thumbs)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (x < tns->x || y < tns->y)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
n = tns->first + (y - tns->y) / thumb_dim * tns->cols +
|
n = tns->first + (y - tns->y) / thumb_dim * tns->cols +
|
||||||
|
|
3
thumbs.h
3
thumbs.h
|
@ -32,6 +32,7 @@ typedef enum {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Imlib_Image *im;
|
Imlib_Image *im;
|
||||||
|
const char *filename;
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
int w;
|
int w;
|
||||||
|
@ -51,6 +52,8 @@ typedef struct {
|
||||||
unsigned char dirty;
|
unsigned char dirty;
|
||||||
} tns_t;
|
} tns_t;
|
||||||
|
|
||||||
|
void tns_clear_cache(tns_t*);
|
||||||
|
|
||||||
void tns_init(tns_t*, int);
|
void tns_init(tns_t*, int);
|
||||||
void tns_free(tns_t*, win_t*);
|
void tns_free(tns_t*, win_t*);
|
||||||
|
|
||||||
|
|
222
util.c
222
util.c
|
@ -18,11 +18,16 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define FNAME_LEN 512
|
#define DNAME_CNT 512
|
||||||
|
#define FNAME_LEN 1024
|
||||||
|
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
|
@ -78,6 +83,221 @@ 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 prior 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r_opendir(r_dir_t *rdir, const char *dirname) {
|
||||||
|
if (!rdir || !dirname || !*dirname)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!(rdir->dir = opendir(dirname))) {
|
||||||
|
rdir->name = NULL;
|
||||||
|
rdir->stack = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdir->stcap = DNAME_CNT;
|
||||||
|
rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
|
||||||
|
rdir->stlen = 0;
|
||||||
|
|
||||||
|
rdir->name = (char*) dirname;
|
||||||
|
rdir->d = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r_closedir(r_dir_t *rdir) {
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!rdir)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (rdir->stack) {
|
||||||
|
while (rdir->stlen > 0)
|
||||||
|
free(rdir->stack[--rdir->stlen]);
|
||||||
|
free(rdir->stack);
|
||||||
|
rdir->stack = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rdir->dir) {
|
||||||
|
if (!(ret = closedir(rdir->dir)))
|
||||||
|
rdir->dir = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rdir->d && rdir->name) {
|
||||||
|
free(rdir->name);
|
||||||
|
rdir->name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* r_readdir(r_dir_t *rdir) {
|
||||||
|
size_t len;
|
||||||
|
char *filename;
|
||||||
|
struct dirent *dentry;
|
||||||
|
struct stat fstats;
|
||||||
|
|
||||||
|
if (!rdir || !rdir->dir || !rdir->name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (rdir->dir && (dentry = readdir(rdir->dir))) {
|
||||||
|
if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
|
||||||
|
filename = (char*) s_malloc(len);
|
||||||
|
snprintf(filename, len, "%s%s%s", rdir->name,
|
||||||
|
rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
|
||||||
|
dentry->d_name);
|
||||||
|
|
||||||
|
if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
|
||||||
|
/* put subdirectory on the stack */
|
||||||
|
if (rdir->stlen == rdir->stcap) {
|
||||||
|
rdir->stcap *= 2;
|
||||||
|
rdir->stack = (char**) s_realloc(rdir->stack,
|
||||||
|
rdir->stcap * sizeof(char*));
|
||||||
|
}
|
||||||
|
rdir->stack[rdir->stlen++] = filename;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rdir->stlen > 0) {
|
||||||
|
/* open next subdirectory */
|
||||||
|
closedir(rdir->dir);
|
||||||
|
if (rdir->d)
|
||||||
|
free(rdir->name);
|
||||||
|
rdir->name = rdir->stack[--rdir->stlen];
|
||||||
|
rdir->d = 1;
|
||||||
|
if (!(rdir->dir = opendir(rdir->name)))
|
||||||
|
warn("could not open directory: %s", rdir->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no more entries */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r_mkdir(const char *path) {
|
||||||
|
char *dir, *d;
|
||||||
|
struct stat stats;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!path || !*path)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!stat(path, &stats)) {
|
||||||
|
if (S_ISDIR(stats.st_mode)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
warn("not a directory: %s", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d = dir = (char*) s_malloc(strlen(path) + 1);
|
||||||
|
strcpy(dir, path);
|
||||||
|
|
||||||
|
while (d != NULL && !err) {
|
||||||
|
d = strchr(d + 1, '/');
|
||||||
|
if (d != NULL)
|
||||||
|
*d = '\0';
|
||||||
|
if (access(dir, F_OK) && errno == ENOENT) {
|
||||||
|
if (mkdir(dir, 0755)) {
|
||||||
|
warn("could not create directory: %s", dir);
|
||||||
|
err = -1;
|
||||||
|
}
|
||||||
|
} else if (stat(dir, &stats) || !S_ISDIR(stats.st_mode)) {
|
||||||
|
warn("not a directory: %s", dir);
|
||||||
|
err = -1;
|
||||||
|
}
|
||||||
|
if (d != NULL)
|
||||||
|
*d = '/';
|
||||||
|
}
|
||||||
|
free(dir);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
char* readline(FILE *stream) {
|
char* readline(FILE *stream) {
|
||||||
size_t len;
|
size_t len;
|
||||||
char *buf, *s, *end;
|
char *buf, *s, *end;
|
||||||
|
|
23
util.h
23
util.h
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
#define ABS(a) ((a) < 0 ? (-(a)) : (a))
|
#define ABS(a) ((a) < 0 ? (-(a)) : (a))
|
||||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||||
|
@ -30,6 +31,21 @@
|
||||||
#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; \
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
DIR *dir;
|
||||||
|
char *name;
|
||||||
|
int d;
|
||||||
|
|
||||||
|
char **stack;
|
||||||
|
int stcap;
|
||||||
|
int stlen;
|
||||||
|
} r_dir_t;
|
||||||
|
|
||||||
void* s_malloc(size_t);
|
void* s_malloc(size_t);
|
||||||
void* s_realloc(void*, size_t);
|
void* s_realloc(void*, size_t);
|
||||||
|
|
||||||
|
@ -38,6 +54,13 @@ void die(const char*, ...);
|
||||||
|
|
||||||
void size_readable(float*, const char**);
|
void size_readable(float*, const char**);
|
||||||
|
|
||||||
|
char* absolute_path(const char*);
|
||||||
|
|
||||||
|
int r_opendir(r_dir_t*, const char*);
|
||||||
|
int r_closedir(r_dir_t*);
|
||||||
|
char* r_readdir(r_dir_t*);
|
||||||
|
int r_mkdir(const char *);
|
||||||
|
|
||||||
char* readline(FILE*);
|
char* readline(FILE*);
|
||||||
|
|
||||||
#endif /* UTIL_H */
|
#endif /* UTIL_H */
|
||||||
|
|
Loading…
Reference in a new issue