Pass marked files to external key handler in thumbnail mode; fixes issue #135

This commit is contained in:
Bert Münnich 2014-08-16 21:31:05 +02:00
parent 284be74927
commit e267dc7793
6 changed files with 77 additions and 57 deletions

View file

@ -130,7 +130,7 @@ bool cg_reload_image(arg_t a)
load_image(fileidx); load_image(fileidx);
} else { } else {
win_set_cursor(&win, CURSOR_WATCH); 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); remove_file(fileidx, false);
tns.dirty = true; tns.dirty = true;
} }

View file

@ -2,33 +2,36 @@
# Example for $XDG_CONFIG_HOME/sxiv/exec/key-handler # Example for $XDG_CONFIG_HOME/sxiv/exec/key-handler
# Called by sxiv(1) after the external prefix key (C-x by default) is pressed. # 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 # The next key combo is passed as its first argument, followed by the paths of
# current image as its second argument. # 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 if the image # sxiv(1) blocks until this script terminates. It then checks which images
# has been modified and reloads it. # have been modified and reloads them.
# The key combo argument has the following form: "[C-][M-][S-]KEY", # 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 # 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. # keysym as listed in /usr/include/X11/keysymdef.h without the "XK_" prefix.
case "$1" in key="$1"
shift
case "$key" in
"C-c") "C-c")
echo -n "$2" | xsel -i ;; echo -n "$@" | xsel -i ;;
"C-e") "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") "C-g")
gimp "$2" & ;; gimp "$@" & ;;
"C-comma") "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") "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") "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") "C-less")
exec mogrify -rotate -90 "$2" ;; exec mogrify -rotate -90 "$@" ;;
"C-greater") "C-greater")
exec mogrify -rotate +90 "$2" ;; exec mogrify -rotate +90 "$@" ;;
"C-question") "C-question")
exec mogrify -rotate 180 "$2" ;; exec mogrify -rotate 180 "$@" ;;
esac esac

73
main.c
View file

@ -467,10 +467,12 @@ void clear_resize(void)
void run_key_handler(const char *key, unsigned int mask) void run_key_handler(const char *key, unsigned int mask)
{ {
pid_t pid; pid_t pid;
int retval, status; int i, j, retval, status;
char kstr[32], oldbar[sizeof(win.bar.l)]; int fcnt = mode == MODE_THUMB && markcnt > 0 ? markcnt : 1;
bool restore_bar = mode == MODE_IMAGE && info.cmd != NULL; bool changed = false;
struct stat oldst, newst; 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.cmd == NULL) {
if (!keyhandler.warned) { if (!keyhandler.warned) {
@ -482,20 +484,34 @@ void run_key_handler(const char *key, unsigned int mask)
if (key == NULL) if (key == NULL)
return; 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", snprintf(kstr, sizeof(kstr), "%s%s%s%s",
mask & ControlMask ? "C-" : "", mask & ControlMask ? "C-" : "",
mask & Mod1Mask ? "M-" : "", mask & Mod1Mask ? "M-" : "",
mask & ShiftMask ? "S-" : "", key); 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)); strncpy(win.bar.l, "Running key handler...", sizeof(win.bar.l));
win_draw(&win); win_draw(&win);
win_set_cursor(&win, CURSOR_WATCH); win_set_cursor(&win, CURSOR_WATCH);
stat(files[fileidx].path, &oldst);
if ((pid = fork()) == 0) { if ((pid = fork()) == 0) {
execl(keyhandler.cmd, keyhandler.cmd, kstr, files[fileidx].path, NULL); execv(keyhandler.cmd, args);
warn("could not exec key handler"); warn("could not exec key handler");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} else if (pid < 0) { } else if (pid < 0) {
@ -507,31 +523,31 @@ void run_key_handler(const char *key, unsigned int mask)
if (WIFEXITED(status) == 0 || retval != 0) if (WIFEXITED(status) == 0 || retval != 0)
warn("key handler exited with non-zero return value: %d", retval); warn("key handler exited with non-zero return value: %d", retval);
if (stat(files[fileidx].path, &newst) == 0 && for (i = 0; i < fcnt; i++) {
memcmp(&oldst.st_mtime, &newst.st_mtime, sizeof(oldst.st_mtime)) == 0) 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)
{ {
/* file has not changed */ if (tns.thumbs != NULL) {
goto end; tns.thumbs[finfo[i].fn].loaded = false;
tns.loadnext = MIN(tns.loadnext, finfo[i].fn);
} }
restore_bar = false; changed = true;
strncpy(win.bar.l, "Reloading image...", sizeof(win.bar.l));
win_draw(&win);
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;
} }
end: end:
if (restore_bar) if (mode == MODE_IMAGE) {
if (changed) {
img_close(&img, true);
load_image(fileidx);
} else if (info.cmd != NULL) {
memcpy(win.bar.l, oldbar, sizeof(win.bar.l)); memcpy(win.bar.l, oldbar, sizeof(win.bar.l));
}
}
reset_cursor(); reset_cursor();
redraw(); redraw();
free(finfo);
free(args);
} }
#define MODMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask)) #define MODMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask))
@ -651,7 +667,7 @@ void run(void)
int xfd; int xfd;
fd_set fds; fd_set fds;
struct timeval timeout; struct timeval timeout;
bool discard, to_set; bool discard, reload, to_set;
XEvent ev, nextev; XEvent ev, nextev;
set_timeout(redraw, 25, false); set_timeout(redraw, 25, false);
@ -661,9 +677,10 @@ void run(void)
XPending(win.env.dpy) == 0) XPending(win.env.dpy) == 0)
{ {
/* load thumbnails */ /* load thumbnails */
reload = tns.loadnext != tns.cnt;
set_timeout(redraw, TO_REDRAW_THUMBS, false); set_timeout(redraw, TO_REDRAW_THUMBS, false);
if (tns_load(&tns, tns.loadnext, &files[tns.loadnext], false, false)) { if (tns_load(&tns, tns.loadnext, &files[tns.loadnext], reload)) {
if (tns.cnt == tns.loadnext) if (!reload)
tns.cnt++; tns.cnt++;
} else { } else {
remove_file(tns.loadnext, false); remove_file(tns.loadnext, false);
@ -860,7 +877,7 @@ int main(int argc, char **argv)
if (options->thumb_mode) { if (options->thumb_mode) {
mode = MODE_THUMB; mode = MODE_THUMB;
tns_init(&tns, filecnt, &win, &fileidx); 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); remove_file(0, false);
tns.cnt = 1; tns.cnt = 1;
} else { } else {

10
sxiv.1
View file

@ -112,7 +112,8 @@ Toggle fullscreen mode.
Toggle visibility of info bar on bottom of window. Toggle visibility of info bar on bottom of window.
.TP .TP
.B Ctrl-x .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 .TP
.B g .B g
Go to the first image. Go to the first image.
@ -354,9 +355,10 @@ located in
.IR $XDG_CONFIG_HOME/sxiv/exec/key-handler . .IR $XDG_CONFIG_HOME/sxiv/exec/key-handler .
The handler is invoked by pressing The handler is invoked by pressing
.BR Ctrl-x . .BR Ctrl-x .
The next key combo is then passed as its first argument and the path of the The next key combo is then passed as its first argument, followed by the paths
current image as its second argument. sxiv(1) will block until the handler of all marked images or the path of the current image, if no image is marked.
terminates. It then checks if the image has been modified and reloads it. 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", 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 where C/M/S indicate Ctrl/Meta(Alt)/Shift modifier states and KEY is the X

View file

@ -209,8 +209,7 @@ void tns_free(tns_t *tns)
} }
} }
bool tns_load(tns_t *tns, int n, const fileinfo_t *file, bool tns_load(tns_t *tns, int n, const fileinfo_t *file, bool force)
bool force, bool silent)
{ {
int w, h; int w, h;
bool cache_hit = false; bool cache_hit = false;
@ -295,7 +294,6 @@ bool tns_load(tns_t *tns, int n, const fileinfo_t *file,
if (im == NULL && (access(file->path, R_OK) < 0 || if (im == NULL && (access(file->path, R_OK) < 0 ||
(im = imlib_load_image(file->path)) == NULL)) (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; return false;
} }

View file

@ -57,7 +57,7 @@ void tns_clean_cache(tns_t*);
void tns_init(tns_t*, int, win_t*, int*); void tns_init(tns_t*, int, win_t*, int*);
void tns_free(tns_t*); 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_render(tns_t*);
void tns_mark(tns_t*, int, bool); void tns_mark(tns_t*, int, bool);