sxiv

simple X image viewer
git clone git://git.suckless.org/sxiv
Log | Files | Refs | LICENSE

commit 216ad81b59a7b3a9a4d1f83a26fa2a23ff17a0e0
parent 51854c614873f59571e80da79f0dc0e8446cbf21
Author: Bert M√ľnnich <ber.t@posteo.de>
Date:   Thu, 27 Nov 2014 22:37:20 +0100

Pass file paths to key handler via stdin; fixes issue #187

Diffstat:
exec/key-handler | 36++++++++++++++++++++----------------
main.c | 85+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
sxiv.1 | 5+++--
3 files changed, 71 insertions(+), 55 deletions(-)

diff --git a/exec/key-handler b/exec/key-handler @@ -2,8 +2,9 @@ # 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, followed by the paths of -# all marked images or the path of the current image, if no image is marked. +# The next key combo is passed as its first argument. The paths of all marked +# images--or of the current image, if no image is marked--are passed via stdin, +# one file path per line. # sxiv(1) blocks until this script terminates. It then checks which images # have been modified and reloads them. @@ -11,12 +12,13 @@ # 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. -readonly KEY="$1"; shift +readonly KEY="$1"; readonly TAGFILE="$HOME/.config/sxiv/tags" +readonly TMPFILE="/tmp/sxiv.$$" rotate() { - degree="$1"; shift - for file in "$@"; do + degree="$1" + while read file; do case "$(file -b -i "$file")" in image/jpeg*) jpegtran -rotate "$degree" -copy all -outfile "$file" "$file" ;; *) mogrify -rotate "$degree" "$file" ;; @@ -28,25 +30,27 @@ tag_add() { >>"$TAGFILE" tags=$(dmenu <"$TAGFILE" | tr '\n' ',') [ -z "$tags" ] && return - iptckwed -a "$tags" "$@" + iptckwed -i -a "$tags" echo -n "$tags" | tr ',' '\n' | sort - "$TAGFILE" | uniq >"$TAGFILE.new" mv -f "$TAGFILE"{.new,} } tag_del() { - tags=$(iptckwed -ql "$@" | cut -f 2 | tr ',' '\n' | sort | uniq | dmenu | tr '\n' ',') + cat >"$TMPFILE" + tags=$(iptckwed -iql <"$TMPFILE" | cut -f 2 | tr ',' '\n' | sort | uniq | dmenu | tr '\n' ',') [ -z "$tags" ] && return - iptckwed -r "$tags" "$@" + iptckwed -i -r "$tags" <"$TMPFILE" + rm -f "$TMPFILE" } case "$KEY" in -"C-c") echo -n "$@" | xsel -i ;; -"C-e") 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 "$@" & ;; -"C-comma") rotate 270 "$@" ;; -"C-period") rotate 90 "$@" ;; -"C-slash") rotate 180 "$@" ;; -"C-t") tag_add "$@" ;; -"M-T") tag_del "$@" ;; +"C-c") tr '\n' ' ' | xsel -i ;; +"C-e") while read file; do urxvt -bg "#444" -fg "#eee" -sl 0 -title "$file" -e sh -c "exiv2 pr -q -pa '$file' | less" & done ;; +"C-g") tr '\n' '\0' | xargs -0 gimp & ;; +"C-comma") rotate 270 ;; +"C-period") rotate 90 ;; +"C-slash") rotate 180 ;; +"C-t") tag_add ;; +"M-T") tag_del ;; esac diff --git a/main.c b/main.c @@ -481,12 +481,13 @@ void clear_resize(void) void run_key_handler(const char *key, unsigned int mask) { pid_t pid; - int i, j, retval, status; - int fcnt = mode == MODE_THUMB && markcnt > 0 ? markcnt : 1; + FILE *pfs; + bool marked = mode == MODE_THUMB && markcnt > 0; bool changed = false; - char **args, kstr[32], oldbar[BAR_L_LEN]; - struct stat *oldst, newst; - struct { int fn; struct stat st; } *finfo; + int f, i, pfd[2], retval, status; + int fcnt = marked ? markcnt : 1; + char kstr[32], oldbar[BAR_L_LEN]; + struct stat *oldst, st; if (keyhandler.cmd == NULL) { if (!keyhandler.warned) { @@ -498,55 +499,66 @@ 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; - } + if (pipe(pfd) < 0) { + warn("could not create pipe for key handler"); + return; } - snprintf(kstr, sizeof(kstr), "%s%s%s%s", - mask & ControlMask ? "C-" : "", - mask & Mod1Mask ? "M-" : "", - mask & ShiftMask ? "S-" : "", key); + if ((pfs = fdopen(pfd[1], "w")) == NULL) { + close(pfd[0]), close(pfd[1]); + warn("could not open pipe for key handler"); + return; + } + oldst = s_malloc(fcnt * sizeof(*oldst)); memcpy(oldbar, win.bar.l.buf, sizeof(oldbar)); strncpy(win.bar.l.buf, "Running key handler...", win.bar.l.size); win_draw(&win); win_set_cursor(&win, CURSOR_WATCH); + snprintf(kstr, sizeof(kstr), "%s%s%s%s", + mask & ControlMask ? "C-" : "", + mask & Mod1Mask ? "M-" : "", + mask & ShiftMask ? "S-" : "", key); + if ((pid = fork()) == 0) { - execv(keyhandler.cmd, args); + close(pfd[1]); + dup2(pfd[0], 0); + execl(keyhandler.cmd, keyhandler.cmd, kstr, NULL); warn("could not exec key handler"); exit(EXIT_FAILURE); - } else if (pid < 0) { + } + close(pfd[0]); + if (pid < 0) { + fclose(pfs); warn("could not fork key handler"); goto end; } + + for (f = i = 0; f < fcnt; i++) { + if ((marked && files[i].marked) || (!marked && i == fileidx)) { + stat(files[i].path, &oldst[f]); + fprintf(pfs, "%s\n", files[i].name); + f++; + } + } + fclose(pfs); waitpid(pid, &status, 0); retval = WEXITSTATUS(status); if (WIFEXITED(status) == 0 || retval != 0) warn("key handler exited with non-zero return value: %d", retval); - 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_unload(&tns, finfo[i].fn); - tns.loadnext = MIN(tns.loadnext, finfo[i].fn); + for (f = i = 0; f < fcnt; i++) { + if ((marked && files[i].marked) || (!marked && i == fileidx)) { + if (stat(files[i].path, &st) != 0 || + memcmp(&oldst[f].st_mtime, &st.st_mtime, sizeof(st.st_mtime)) != 0) + { + if (tns.thumbs != NULL) { + tns_unload(&tns, i); + tns.loadnext = MIN(tns.loadnext, i); + } + changed = true; } - changed = true; + f++; } } end: @@ -558,10 +570,9 @@ end: memcpy(win.bar.l.buf, oldbar, win.bar.l.size); } } + free(oldst); reset_cursor(); redraw(); - free(finfo); - free(args); } #define MODMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask)) diff --git a/sxiv.1 b/sxiv.1 @@ -358,8 +358,9 @@ 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, followed by the paths -of all marked images or the path of the current image, if no image is marked. +The next key combo is passed as its first argument. The paths of all marked +images--or of the current image, if no image is marked--are passed via stdin, +one file path per line. sxiv(1) will block until the handler terminates. It then checks which images have been modified and reloads them.