Krolyxon
Commit 216ad81

Branches

Refs →

nsxiv216ad81

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

Author
Bert Münnich
Date
2014-11-27 22:37 +0100
Parent
51854c6
Commit
216ad81b59a7b3a9a4d1f83a26fa2a23ff17a0e0

+71 −55

3 files changed

  1. M exec/key-handler +20 −16
  2. M main.c +48 −37
  3. M sxiv.1 +3 −2
M exec/key-handler View
@@ -2,8 +2,9 @@
22
33 # Example for $XDG_CONFIG_HOME/sxiv/exec/key-handler
44 # Called by sxiv(1) after the external prefix key (C-x by default) is pressed.
5−# The next key combo is passed as its first argument, followed by the paths of
6−# all marked images or the path of the current image, if no image is marked.
5+# The next key combo is passed as its first argument. The paths of all marked
6+# images--or of the current image, if no image is marked--are passed via stdin,
7+# one file path per line.
78 # sxiv(1) blocks until this script terminates. It then checks which images
89 # have been modified and reloads them.
910
@@ -11,12 +12,13 @@
1112 # where C/M/S indicate Ctrl/Meta(Alt)/Shift modifier states and KEY is the X
1213 # keysym as listed in /usr/include/X11/keysymdef.h without the "XK_" prefix.
1314
14−readonly KEY="$1"; shift
15+readonly KEY="$1";
1516 readonly TAGFILE="$HOME/.config/sxiv/tags"
17+readonly TMPFILE="/tmp/sxiv.$$"
1618
1719 rotate() {
18− degree="$1"; shift
19− for file in "$@"; do
20+ degree="$1"
21+ while read file; do
2022 case "$(file -b -i "$file")" in
2123 image/jpeg*) jpegtran -rotate "$degree" -copy all -outfile "$file" "$file" ;;
2224 *) mogrify -rotate "$degree" "$file" ;;
@@ -28,25 +30,27 @@ tag_add() {
2830 >>"$TAGFILE"
2931 tags=$(dmenu <"$TAGFILE" | tr '\n' ',')
3032 [ -z "$tags" ] && return
31− iptckwed -a "$tags" "$@"
33+ iptckwed -i -a "$tags"
3234 echo -n "$tags" | tr ',' '\n' | sort - "$TAGFILE" | uniq >"$TAGFILE.new"
3335 mv -f "$TAGFILE"{.new,}
3436 }
3537
3638 tag_del() {
37− tags=$(iptckwed -ql "$@" | cut -f 2 | tr ',' '\n' | sort | uniq | dmenu | tr '\n' ',')
39+ cat >"$TMPFILE"
40+ tags=$(iptckwed -iql <"$TMPFILE" | cut -f 2 | tr ',' '\n' | sort | uniq | dmenu | tr '\n' ',')
3841 [ -z "$tags" ] && return
39− iptckwed -r "$tags" "$@"
42+ iptckwed -i -r "$tags" <"$TMPFILE"
43+ rm -f "$TMPFILE"
4044 }
4145
4246 case "$KEY" in
43−"C-c") echo -n "$@" | xsel -i ;;
44−"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 ;;
45−"C-g") gimp "$@" & ;;
46−"C-comma") rotate 270 "$@" ;;
47−"C-period") rotate 90 "$@" ;;
48−"C-slash") rotate 180 "$@" ;;
49−"C-t") tag_add "$@" ;;
50−"M-T") tag_del "$@" ;;
47+"C-c") tr '\n' ' ' | xsel -i ;;
48+"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 ;;
49+"C-g") tr '\n' '\0' | xargs -0 gimp & ;;
50+"C-comma") rotate 270 ;;
51+"C-period") rotate 90 ;;
52+"C-slash") rotate 180 ;;
53+"C-t") tag_add ;;
54+"M-T") tag_del ;;
5155 esac
5256
M main.c View
@@ -481,12 +481,13 @@ void clear_resize(void)
481481 void run_key_handler(const char *key, unsigned int mask)
482482 {
483483 pid_t pid;
484− int i, j, retval, status;
485− int fcnt = mode == MODE_THUMB && markcnt > 0 ? markcnt : 1;
484+ FILE *pfs;
485+ bool marked = mode == MODE_THUMB && markcnt > 0;
486486 bool changed = false;
487− char **args, kstr[32], oldbar[BAR_L_LEN];
488− struct stat *oldst, newst;
489− struct { int fn; struct stat st; } *finfo;
487+ int f, i, pfd[2], retval, status;
488+ int fcnt = marked ? markcnt : 1;
489+ char kstr[32], oldbar[BAR_L_LEN];
490+ struct stat *oldst, st;
490491
491492 if (keyhandler.cmd == NULL) {
492493 if (!keyhandler.warned) {
@@ -498,55 +499,66 @@ void run_key_handler(const char *key, unsigned int mask)
498499 if (key == NULL)
499500 return;
500501
501− finfo = s_malloc(fcnt * sizeof(*finfo));
502− args = s_malloc((fcnt + 3) * sizeof(*args));
503− args[0] = keyhandler.cmd;
504− args[1] = kstr;
505− args[fcnt+2] = NULL;
506− if (mode == MODE_IMAGE || markcnt == 0) {
507− finfo[0].fn = fileidx;
508− stat(files[fileidx].path, &finfo[0].st);
509− args[2] = (char*) files[fileidx].path;
510− } else for (i = j = 0; i < filecnt; i++) {
511− if (files[i].marked) {
512− finfo[j].fn = i;
513− stat(files[i].path, &finfo[j++].st);
514− args[j+1] = (char*) files[i].path;
515− }
502+ if (pipe(pfd) < 0) {
503+ warn("could not create pipe for key handler");
504+ return;
516505 }
517− snprintf(kstr, sizeof(kstr), "%s%s%s%s",
518− mask & ControlMask ? "C-" : "",
519− mask & Mod1Mask ? "M-" : "",
520− mask & ShiftMask ? "S-" : "", key);
506+ if ((pfs = fdopen(pfd[1], "w")) == NULL) {
507+ close(pfd[0]), close(pfd[1]);
508+ warn("could not open pipe for key handler");
509+ return;
510+ }
511+ oldst = s_malloc(fcnt * sizeof(*oldst));
521512
522513 memcpy(oldbar, win.bar.l.buf, sizeof(oldbar));
523514 strncpy(win.bar.l.buf, "Running key handler...", win.bar.l.size);
524515 win_draw(&win);
525516 win_set_cursor(&win, CURSOR_WATCH);
526517
518+ snprintf(kstr, sizeof(kstr), "%s%s%s%s",
519+ mask & ControlMask ? "C-" : "",
520+ mask & Mod1Mask ? "M-" : "",
521+ mask & ShiftMask ? "S-" : "", key);
522+
527523 if ((pid = fork()) == 0) {
528− execv(keyhandler.cmd, args);
524+ close(pfd[1]);
525+ dup2(pfd[0], 0);
526+ execl(keyhandler.cmd, keyhandler.cmd, kstr, NULL);
529527 warn("could not exec key handler");
530528 exit(EXIT_FAILURE);
531− } else if (pid < 0) {
529+ }
530+ close(pfd[0]);
531+ if (pid < 0) {
532+ fclose(pfs);
532533 warn("could not fork key handler");
533534 goto end;
534535 }
536+
537+ for (f = i = 0; f < fcnt; i++) {
538+ if ((marked && files[i].marked) || (!marked && i == fileidx)) {
539+ stat(files[i].path, &oldst[f]);
540+ fprintf(pfs, "%s\n", files[i].name);
541+ f++;
542+ }
543+ }
544+ fclose(pfs);
535545 waitpid(pid, &status, 0);
536546 retval = WEXITSTATUS(status);
537547 if (WIFEXITED(status) == 0 || retval != 0)
538548 warn("key handler exited with non-zero return value: %d", retval);
539549
540− for (i = 0; i < fcnt; i++) {
541− oldst = &finfo[i].st;
542− if (stat(files[finfo[i].fn].path, &newst) != 0 ||
543− memcmp(&oldst->st_mtime, &newst.st_mtime, sizeof(newst.st_mtime)) != 0)
544− {
545− if (tns.thumbs != NULL) {
546− tns_unload(&tns, finfo[i].fn);
547− tns.loadnext = MIN(tns.loadnext, finfo[i].fn);
550+ for (f = i = 0; f < fcnt; i++) {
551+ if ((marked && files[i].marked) || (!marked && i == fileidx)) {
552+ if (stat(files[i].path, &st) != 0 ||
553+ memcmp(&oldst[f].st_mtime, &st.st_mtime, sizeof(st.st_mtime)) != 0)
554+ {
555+ if (tns.thumbs != NULL) {
556+ tns_unload(&tns, i);
557+ tns.loadnext = MIN(tns.loadnext, i);
558+ }
559+ changed = true;
548560 }
549− changed = true;
561+ f++;
550562 }
551563 }
552564 end:
@@ -558,10 +570,9 @@ end:
558570 memcpy(win.bar.l.buf, oldbar, win.bar.l.size);
559571 }
560572 }
573+ free(oldst);
561574 reset_cursor();
562575 redraw();
563− free(finfo);
564− free(args);
565576 }
566577
567578 #define MODMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask))
M sxiv.1 View
@@ -358,8 +358,9 @@ located in
358358 .IR $XDG_CONFIG_HOME/sxiv/exec/key-handler .
359359 The handler is invoked by pressing
360360 .BR Ctrl-x .
361−The next key combo is then passed as its first argument, followed by the paths
362−of all marked images or the path of the current image, if no image is marked.
361+The next key combo is passed as its first argument. The paths of all marked
362+images--or of the current image, if no image is marked--are passed via stdin,
363+one file path per line.
363364 sxiv(1) will block until the handler terminates. It then checks which images
364365 have been modified and reloads them.
365366