@@ -130,7 +130,7 @@ bool cg_reload_image(arg_t a) | |||
load_image(fileidx); | |||
} else { | |||
win_set_cursor(&win, CURSOR_WATCH); | |||
if (!tns_load(&tns, fileidx, &files[fileidx], true, false)) { | |||
if (!tns_load(&tns, fileidx, &files[fileidx], true)) { | |||
remove_file(fileidx, false); | |||
tns.dirty = true; | |||
} | |||
@@ -2,33 +2,36 @@ | |||
# Example for $XDG_CONFIG_HOME/sxiv/exec/key-handler | |||
# Called by sxiv(1) after the external prefix key (C-x by default) is pressed. | |||
# The next key combo is passed as its first argument and the path of the | |||
# current image as its second argument. | |||
# sxiv(1) blocks until this script terminates. It then checks if the image | |||
# has been modified and reloads it. | |||
# The next key combo is passed as its first argument, followed by the paths of | |||
# all marked images or the path of the current image, if no image is marked. | |||
# sxiv(1) blocks until this script terminates. It then checks which images | |||
# have been modified and reloads them. | |||
# The key combo argument has the following form: "[C-][M-][S-]KEY", | |||
# where C/M/S indicate Ctrl/Meta(Alt)/Shift modifier states and KEY is the X | |||
# keysym as listed in /usr/include/X11/keysymdef.h without the "XK_" prefix. | |||
case "$1" in | |||
key="$1" | |||
shift | |||
case "$key" in | |||
"C-c") | |||
echo -n "$2" | xsel -i ;; | |||
echo -n "$@" | xsel -i ;; | |||
"C-e") | |||
urxvt -bg "#444" -fg "#eee" -sl 0 -title "$2" -e sh -c "exiv2 pr -q -pa '$2' | less" & ;; | |||
for file in "$@"; do urxvt -bg "#444" -fg "#eee" -sl 0 -title "$file" -e sh -c "exiv2 pr -q -pa '$file' | less" & done ;; | |||
"C-g") | |||
gimp "$2" & ;; | |||
gimp "$@" & ;; | |||
"C-comma") | |||
exec jpegtran -rotate 270 -copy all -outfile "$2" "$2" ;; | |||
for file in "$@"; do jpegtran -rotate 270 -copy all -outfile "$file" "$file"; done ;; | |||
"C-period") | |||
exec jpegtran -rotate 90 -copy all -outfile "$2" "$2" ;; | |||
for file in "$@"; do jpegtran -rotate 90 -copy all -outfile "$file" "$file"; done ;; | |||
"C-slash") | |||
exec jpegtran -rotate 180 -copy all -outfile "$2" "$2" ;; | |||
for file in "$@"; do jpegtran -rotate 180 -copy all -outfile "$file" "$file"; done ;; | |||
"C-less") | |||
exec mogrify -rotate -90 "$2" ;; | |||
exec mogrify -rotate -90 "$@" ;; | |||
"C-greater") | |||
exec mogrify -rotate +90 "$2" ;; | |||
exec mogrify -rotate +90 "$@" ;; | |||
"C-question") | |||
exec mogrify -rotate 180 "$2" ;; | |||
exec mogrify -rotate 180 "$@" ;; | |||
esac | |||
@@ -467,10 +467,12 @@ void clear_resize(void) | |||
void run_key_handler(const char *key, unsigned int mask) | |||
{ | |||
pid_t pid; | |||
int retval, status; | |||
char kstr[32], oldbar[sizeof(win.bar.l)]; | |||
bool restore_bar = mode == MODE_IMAGE && info.cmd != NULL; | |||
struct stat oldst, newst; | |||
int i, j, retval, status; | |||
int fcnt = mode == MODE_THUMB && markcnt > 0 ? markcnt : 1; | |||
bool changed = false; | |||
char **args, kstr[32], oldbar[sizeof(win.bar.l)]; | |||
struct stat *oldst, newst; | |||
struct { int fn; struct stat st; } *finfo; | |||
if (keyhandler.cmd == NULL) { | |||
if (!keyhandler.warned) { | |||
@@ -482,20 +484,34 @@ void run_key_handler(const char *key, unsigned int mask) | |||
if (key == NULL) | |||
return; | |||
finfo = s_malloc(fcnt * sizeof(*finfo)); | |||
args = s_malloc((fcnt + 3) * sizeof(*args)); | |||
args[0] = keyhandler.cmd; | |||
args[1] = kstr; | |||
args[fcnt+2] = NULL; | |||
if (mode == MODE_IMAGE || markcnt == 0) { | |||
finfo[0].fn = fileidx; | |||
stat(files[fileidx].path, &finfo[0].st); | |||
args[2] = (char*) files[fileidx].path; | |||
} else for (i = j = 0; i < filecnt; i++) { | |||
if (files[i].marked) { | |||
finfo[j].fn = i; | |||
stat(files[i].path, &finfo[j++].st); | |||
args[j+1] = (char*) files[i].path; | |||
} | |||
} | |||
snprintf(kstr, sizeof(kstr), "%s%s%s%s", | |||
mask & ControlMask ? "C-" : "", | |||
mask & Mod1Mask ? "M-" : "", | |||
mask & ShiftMask ? "S-" : "", key); | |||
if (restore_bar) | |||
memcpy(oldbar, win.bar.l, sizeof(win.bar.l)); | |||
memcpy(oldbar, win.bar.l, sizeof(win.bar.l)); | |||
strncpy(win.bar.l, "Running key handler...", sizeof(win.bar.l)); | |||
win_draw(&win); | |||
win_set_cursor(&win, CURSOR_WATCH); | |||
stat(files[fileidx].path, &oldst); | |||
if ((pid = fork()) == 0) { | |||
execl(keyhandler.cmd, keyhandler.cmd, kstr, files[fileidx].path, NULL); | |||
execv(keyhandler.cmd, args); | |||
warn("could not exec key handler"); | |||
exit(EXIT_FAILURE); | |||
} else if (pid < 0) { | |||
@@ -507,31 +523,31 @@ void run_key_handler(const char *key, unsigned int mask) | |||
if (WIFEXITED(status) == 0 || retval != 0) | |||
warn("key handler exited with non-zero return value: %d", retval); | |||
if (stat(files[fileidx].path, &newst) == 0 && | |||
memcmp(&oldst.st_mtime, &newst.st_mtime, sizeof(oldst.st_mtime)) == 0) | |||
{ | |||
/* file has not changed */ | |||
goto end; | |||
for (i = 0; i < fcnt; i++) { | |||
oldst = &finfo[i].st; | |||
if (stat(files[finfo[i].fn].path, &newst) != 0 || | |||
memcmp(&oldst->st_mtime, &newst.st_mtime, sizeof(newst.st_mtime)) != 0) | |||
{ | |||
if (tns.thumbs != NULL) { | |||
tns.thumbs[finfo[i].fn].loaded = false; | |||
tns.loadnext = MIN(tns.loadnext, finfo[i].fn); | |||
} | |||
changed = true; | |||
} | |||
} | |||
restore_bar = false; | |||
strncpy(win.bar.l, "Reloading image...", sizeof(win.bar.l)); | |||
win_draw(&win); | |||
end: | |||
if (mode == MODE_IMAGE) { | |||
img_close(&img, true); | |||
load_image(fileidx); | |||
} | |||
if (!tns_load(&tns, fileidx, &files[fileidx], true, mode == MODE_IMAGE) && | |||
mode == MODE_THUMB) | |||
{ | |||
remove_file(fileidx, false); | |||
tns.dirty = true; | |||
if (changed) { | |||
img_close(&img, true); | |||
load_image(fileidx); | |||
} else if (info.cmd != NULL) { | |||
memcpy(win.bar.l, oldbar, sizeof(win.bar.l)); | |||
} | |||
} | |||
end: | |||
if (restore_bar) | |||
memcpy(win.bar.l, oldbar, sizeof(win.bar.l)); | |||
reset_cursor(); | |||
redraw(); | |||
free(finfo); | |||
free(args); | |||
} | |||
#define MODMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask)) | |||
@@ -651,7 +667,7 @@ void run(void) | |||
int xfd; | |||
fd_set fds; | |||
struct timeval timeout; | |||
bool discard, to_set; | |||
bool discard, reload, to_set; | |||
XEvent ev, nextev; | |||
set_timeout(redraw, 25, false); | |||
@@ -661,9 +677,10 @@ void run(void) | |||
XPending(win.env.dpy) == 0) | |||
{ | |||
/* load thumbnails */ | |||
reload = tns.loadnext != tns.cnt; | |||
set_timeout(redraw, TO_REDRAW_THUMBS, false); | |||
if (tns_load(&tns, tns.loadnext, &files[tns.loadnext], false, false)) { | |||
if (tns.cnt == tns.loadnext) | |||
if (tns_load(&tns, tns.loadnext, &files[tns.loadnext], reload)) { | |||
if (!reload) | |||
tns.cnt++; | |||
} else { | |||
remove_file(tns.loadnext, false); | |||
@@ -860,7 +877,7 @@ int main(int argc, char **argv) | |||
if (options->thumb_mode) { | |||
mode = MODE_THUMB; | |||
tns_init(&tns, filecnt, &win, &fileidx); | |||
while (!tns_load(&tns, 0, &files[0], false, false)) | |||
while (!tns_load(&tns, 0, &files[0], false)) | |||
remove_file(0, false); | |||
tns.cnt = 1; | |||
} else { | |||
@@ -112,7 +112,8 @@ Toggle fullscreen mode. | |||
Toggle visibility of info bar on bottom of window. | |||
.TP | |||
.B Ctrl-x | |||
Send the next key to the external key-handler. | |||
Send the next key to the external key-handler. See section EXTERNAL KEY HANDLER | |||
for more information. | |||
.TP | |||
.B g | |||
Go to the first image. | |||
@@ -354,9 +355,10 @@ located in | |||
.IR $XDG_CONFIG_HOME/sxiv/exec/key-handler . | |||
The handler is invoked by pressing | |||
.BR Ctrl-x . | |||
The next key combo is then passed as its first argument and the path of the | |||
current image as its second argument. sxiv(1) will block until the handler | |||
terminates. It then checks if the image has been modified and reloads it. | |||
The next key combo is then passed as its first argument, followed by the paths | |||
of all marked images or the path of the current image, if no image is marked. | |||
sxiv(1) will block until the handler terminates. It then checks which images | |||
have been modified and reloads them. | |||
The key combo argument has the following form: "[C-][M-][S-]KEY", | |||
where C/M/S indicate Ctrl/Meta(Alt)/Shift modifier states and KEY is the X | |||
@@ -209,8 +209,7 @@ void tns_free(tns_t *tns) | |||
} | |||
} | |||
bool tns_load(tns_t *tns, int n, const fileinfo_t *file, | |||
bool force, bool silent) | |||
bool tns_load(tns_t *tns, int n, const fileinfo_t *file, bool force) | |||
{ | |||
int w, h; | |||
bool cache_hit = false; | |||
@@ -295,8 +294,7 @@ bool tns_load(tns_t *tns, int n, const fileinfo_t *file, | |||
if (im == NULL && (access(file->path, R_OK) < 0 || | |||
(im = imlib_load_image(file->path)) == NULL)) | |||
{ | |||
if (!silent) | |||
warn("could not open image: %s", file->name); | |||
warn("could not open image: %s", file->name); | |||
return false; | |||
} | |||
} | |||
@@ -57,7 +57,7 @@ void tns_clean_cache(tns_t*); | |||
void tns_init(tns_t*, int, win_t*, int*); | |||
void tns_free(tns_t*); | |||
bool tns_load(tns_t*, int, const fileinfo_t*, bool, bool); | |||
bool tns_load(tns_t*, int, const fileinfo_t*, bool); | |||
void tns_render(tns_t*); | |||
void tns_mark(tns_t*, int, bool); | |||