Pass file paths to key handler via stdin; fixes issue #187
This commit is contained in:
parent
51854c6148
commit
216ad81b59
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
# 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, followed by the paths of
|
# The next key combo is passed as its first argument. The paths of all marked
|
||||||
# all marked images or the path of the current image, if no image is 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
|
# sxiv(1) blocks until this script terminates. It then checks which images
|
||||||
# have been modified and reloads them.
|
# 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
|
# 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.
|
||||||
|
|
||||||
readonly KEY="$1"; shift
|
readonly KEY="$1";
|
||||||
readonly TAGFILE="$HOME/.config/sxiv/tags"
|
readonly TAGFILE="$HOME/.config/sxiv/tags"
|
||||||
|
readonly TMPFILE="/tmp/sxiv.$$"
|
||||||
|
|
||||||
rotate() {
|
rotate() {
|
||||||
degree="$1"; shift
|
degree="$1"
|
||||||
for file in "$@"; do
|
while read file; do
|
||||||
case "$(file -b -i "$file")" in
|
case "$(file -b -i "$file")" in
|
||||||
image/jpeg*) jpegtran -rotate "$degree" -copy all -outfile "$file" "$file" ;;
|
image/jpeg*) jpegtran -rotate "$degree" -copy all -outfile "$file" "$file" ;;
|
||||||
*) mogrify -rotate "$degree" "$file" ;;
|
*) mogrify -rotate "$degree" "$file" ;;
|
||||||
|
@ -28,25 +30,27 @@ tag_add() {
|
||||||
>>"$TAGFILE"
|
>>"$TAGFILE"
|
||||||
tags=$(dmenu <"$TAGFILE" | tr '\n' ',')
|
tags=$(dmenu <"$TAGFILE" | tr '\n' ',')
|
||||||
[ -z "$tags" ] && return
|
[ -z "$tags" ] && return
|
||||||
iptckwed -a "$tags" "$@"
|
iptckwed -i -a "$tags"
|
||||||
echo -n "$tags" | tr ',' '\n' | sort - "$TAGFILE" | uniq >"$TAGFILE.new"
|
echo -n "$tags" | tr ',' '\n' | sort - "$TAGFILE" | uniq >"$TAGFILE.new"
|
||||||
mv -f "$TAGFILE"{.new,}
|
mv -f "$TAGFILE"{.new,}
|
||||||
}
|
}
|
||||||
|
|
||||||
tag_del() {
|
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
|
[ -z "$tags" ] && return
|
||||||
iptckwed -r "$tags" "$@"
|
iptckwed -i -r "$tags" <"$TMPFILE"
|
||||||
|
rm -f "$TMPFILE"
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$KEY" in
|
case "$KEY" in
|
||||||
"C-c") echo -n "$@" | xsel -i ;;
|
"C-c") tr '\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-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") gimp "$@" & ;;
|
"C-g") tr '\n' '\0' | xargs -0 gimp & ;;
|
||||||
"C-comma") rotate 270 "$@" ;;
|
"C-comma") rotate 270 ;;
|
||||||
"C-period") rotate 90 "$@" ;;
|
"C-period") rotate 90 ;;
|
||||||
"C-slash") rotate 180 "$@" ;;
|
"C-slash") rotate 180 ;;
|
||||||
"C-t") tag_add "$@" ;;
|
"C-t") tag_add ;;
|
||||||
"M-T") tag_del "$@" ;;
|
"M-T") tag_del ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
85
main.c
85
main.c
|
@ -481,12 +481,13 @@ 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 i, j, retval, status;
|
FILE *pfs;
|
||||||
int fcnt = mode == MODE_THUMB && markcnt > 0 ? markcnt : 1;
|
bool marked = mode == MODE_THUMB && markcnt > 0;
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
char **args, kstr[32], oldbar[BAR_L_LEN];
|
int f, i, pfd[2], retval, status;
|
||||||
struct stat *oldst, newst;
|
int fcnt = marked ? markcnt : 1;
|
||||||
struct { int fn; struct stat st; } *finfo;
|
char kstr[32], oldbar[BAR_L_LEN];
|
||||||
|
struct stat *oldst, st;
|
||||||
|
|
||||||
if (keyhandler.cmd == NULL) {
|
if (keyhandler.cmd == NULL) {
|
||||||
if (!keyhandler.warned) {
|
if (!keyhandler.warned) {
|
||||||
|
@ -498,55 +499,66 @@ void run_key_handler(const char *key, unsigned int mask)
|
||||||
if (key == NULL)
|
if (key == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
finfo = s_malloc(fcnt * sizeof(*finfo));
|
if (pipe(pfd) < 0) {
|
||||||
args = s_malloc((fcnt + 3) * sizeof(*args));
|
warn("could not create pipe for key handler");
|
||||||
args[0] = keyhandler.cmd;
|
return;
|
||||||
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",
|
if ((pfs = fdopen(pfd[1], "w")) == NULL) {
|
||||||
mask & ControlMask ? "C-" : "",
|
close(pfd[0]), close(pfd[1]);
|
||||||
mask & Mod1Mask ? "M-" : "",
|
warn("could not open pipe for key handler");
|
||||||
mask & ShiftMask ? "S-" : "", key);
|
return;
|
||||||
|
}
|
||||||
|
oldst = s_malloc(fcnt * sizeof(*oldst));
|
||||||
|
|
||||||
memcpy(oldbar, win.bar.l.buf, sizeof(oldbar));
|
memcpy(oldbar, win.bar.l.buf, sizeof(oldbar));
|
||||||
strncpy(win.bar.l.buf, "Running key handler...", win.bar.l.size);
|
strncpy(win.bar.l.buf, "Running key handler...", win.bar.l.size);
|
||||||
win_draw(&win);
|
win_draw(&win);
|
||||||
win_set_cursor(&win, CURSOR_WATCH);
|
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) {
|
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");
|
warn("could not exec key handler");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
} else if (pid < 0) {
|
}
|
||||||
|
close(pfd[0]);
|
||||||
|
if (pid < 0) {
|
||||||
|
fclose(pfs);
|
||||||
warn("could not fork key handler");
|
warn("could not fork key handler");
|
||||||
goto end;
|
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);
|
waitpid(pid, &status, 0);
|
||||||
retval = WEXITSTATUS(status);
|
retval = WEXITSTATUS(status);
|
||||||
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);
|
||||||
|
|
||||||
for (i = 0; i < fcnt; i++) {
|
for (f = i = 0; f < fcnt; i++) {
|
||||||
oldst = &finfo[i].st;
|
if ((marked && files[i].marked) || (!marked && i == fileidx)) {
|
||||||
if (stat(files[finfo[i].fn].path, &newst) != 0 ||
|
if (stat(files[i].path, &st) != 0 ||
|
||||||
memcmp(&oldst->st_mtime, &newst.st_mtime, sizeof(newst.st_mtime)) != 0)
|
memcmp(&oldst[f].st_mtime, &st.st_mtime, sizeof(st.st_mtime)) != 0)
|
||||||
{
|
{
|
||||||
if (tns.thumbs != NULL) {
|
if (tns.thumbs != NULL) {
|
||||||
tns_unload(&tns, finfo[i].fn);
|
tns_unload(&tns, i);
|
||||||
tns.loadnext = MIN(tns.loadnext, finfo[i].fn);
|
tns.loadnext = MIN(tns.loadnext, i);
|
||||||
|
}
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
changed = true;
|
f++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
|
@ -558,10 +570,9 @@ end:
|
||||||
memcpy(win.bar.l.buf, oldbar, win.bar.l.size);
|
memcpy(win.bar.l.buf, oldbar, win.bar.l.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(oldst);
|
||||||
reset_cursor();
|
reset_cursor();
|
||||||
redraw();
|
redraw();
|
||||||
free(finfo);
|
|
||||||
free(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MODMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask))
|
#define MODMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask))
|
||||||
|
|
5
sxiv.1
5
sxiv.1
|
@ -358,8 +358,9 @@ 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, followed by the paths
|
The next key combo is passed as its first argument. The paths of all marked
|
||||||
of all marked images or the path of the current image, if no image is 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
|
sxiv(1) will block until the handler terminates. It then checks which images
|
||||||
have been modified and reloads them.
|
have been modified and reloads them.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue