Gets called on all unset key mappings. Arguments are: key combo and current file. Thanks to Francesco Orsenigo (xarvh) for the idea.master
@@ -35,8 +35,8 @@ install: all | |||||
sed "s!PREFIX!$(PREFIX)!g; s!VERSION!$(VERSION)!g" sxiv.1 > $(DESTDIR)$(MANPREFIX)/man1/sxiv.1 | sed "s!PREFIX!$(PREFIX)!g; s!VERSION!$(VERSION)!g" sxiv.1 > $(DESTDIR)$(MANPREFIX)/man1/sxiv.1 | ||||
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/sxiv.1 | chmod 644 $(DESTDIR)$(MANPREFIX)/man1/sxiv.1 | ||||
mkdir -p $(DESTDIR)$(PREFIX)/share/sxiv/exec | mkdir -p $(DESTDIR)$(PREFIX)/share/sxiv/exec | ||||
cp image-info $(DESTDIR)$(PREFIX)/share/sxiv/exec/image-info | cp exec/* $(DESTDIR)$(PREFIX)/share/sxiv/exec/ | ||||
chmod 755 $(DESTDIR)$(PREFIX)/share/sxiv/exec/image-info | chmod 755 $(DESTDIR)$(PREFIX)/share/sxiv/exec/* | ||||
uninstall: | uninstall: | ||||
rm -f $(DESTDIR)$(PREFIX)/bin/sxiv | rm -f $(DESTDIR)$(PREFIX)/bin/sxiv | ||||
@@ -504,69 +504,3 @@ bool it_toggle_alpha(arg_t a) | |||||
return true; | return true; | ||||
} | } | ||||
bool it_open_with(arg_t a) | |||||
{ | |||||
const char *prog = (const char*) a; | |||||
pid_t pid; | |||||
if (prog == NULL || *prog == '\0') | |||||
return false; | |||||
if ((pid = fork()) == 0) { | |||||
execlp(prog, prog, | |||||
files[mode == MODE_IMAGE ? fileidx : tns.sel].path, NULL); | |||||
warn("could not exec: %s", prog); | |||||
exit(EXIT_FAILURE); | |||||
} else if (pid < 0) { | |||||
warn("could not fork. program was: %s", prog); | |||||
} | |||||
return false; | |||||
} | |||||
bool it_shell_cmd(arg_t a) | |||||
{ | |||||
int n, status; | |||||
const char *cmdline = (const char*) a; | |||||
pid_t pid; | |||||
if (cmdline == NULL || *cmdline == '\0') | |||||
return false; | |||||
n = mode == MODE_IMAGE ? fileidx : tns.sel; | |||||
if (setenv("SXIV_IMG", files[n].path, 1) < 0) { | |||||
warn("could not set env.-variable: SXIV_IMG. command line was: %s", | |||||
cmdline); | |||||
return false; | |||||
} | |||||
if ((pid = fork()) == 0) { | |||||
execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL); | |||||
warn("could not exec: /bin/sh. command line was: %s", cmdline); | |||||
exit(EXIT_FAILURE); | |||||
} else if (pid < 0) { | |||||
warn("could not fork. command line was: %s", cmdline); | |||||
return false; | |||||
} | |||||
win_set_cursor(&win, CURSOR_WATCH); | |||||
waitpid(pid, &status, 0); | |||||
if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0) | |||||
warn("child exited with non-zero return value: %d. command line was: %s", | |||||
WEXITSTATUS(status), cmdline); | |||||
if (mode == MODE_IMAGE) { | |||||
img_close(&img, true); | |||||
load_image(fileidx); | |||||
} | |||||
if (!tns_load(&tns, n, &files[n], true, mode == MODE_IMAGE) && | |||||
mode == MODE_THUMB) | |||||
{ | |||||
remove_file(tns.sel, false); | |||||
tns.dirty = true; | |||||
if (tns.sel >= tns.cnt) | |||||
tns.sel = tns.cnt - 1; | |||||
} | |||||
return true; | |||||
} |
@@ -69,7 +69,5 @@ bool i_flip(arg_t); | |||||
bool i_toggle_antialias(arg_t); | bool i_toggle_antialias(arg_t); | ||||
bool i_change_gamma(arg_t); | bool i_change_gamma(arg_t); | ||||
bool it_toggle_alpha(arg_t); | bool it_toggle_alpha(arg_t); | ||||
bool it_open_with(arg_t); | |||||
bool it_shell_cmd(arg_t); | |||||
#endif /* COMMANDS_H */ | #endif /* COMMANDS_H */ |
@@ -151,23 +151,6 @@ static const keymap_t keys[] = { | |||||
{ 0, XK_braceleft, i_change_gamma, (arg_t) -1 }, | { 0, XK_braceleft, i_change_gamma, (arg_t) -1 }, | ||||
{ 0, XK_braceright, i_change_gamma, (arg_t) +1 }, | { 0, XK_braceright, i_change_gamma, (arg_t) +1 }, | ||||
{ ControlMask, XK_G, i_change_gamma, (arg_t) 0 }, | { ControlMask, XK_G, i_change_gamma, (arg_t) 0 }, | ||||
/* open current image with given program: */ | |||||
{ ControlMask, XK_g, it_open_with, (arg_t) "gimp" }, | |||||
/* run shell command line on current file ("$SXIV_IMG"): */ | |||||
{ ControlMask, XK_less, it_shell_cmd, (arg_t) \ | |||||
"mogrify -rotate -90 \"$SXIV_IMG\"" }, | |||||
{ ControlMask, XK_greater, it_shell_cmd, (arg_t) \ | |||||
"mogrify -rotate +90 \"$SXIV_IMG\"" }, | |||||
{ ControlMask, XK_question, it_shell_cmd, (arg_t) \ | |||||
"mogrify -rotate 180 \"$SXIV_IMG\"" }, | |||||
{ ControlMask, XK_comma, it_shell_cmd, (arg_t) \ | |||||
"jpegtran -rotate 270 -copy all -outfile \"$SXIV_IMG\" \"$SXIV_IMG\"" }, | |||||
{ ControlMask, XK_period, it_shell_cmd, (arg_t) \ | |||||
"jpegtran -rotate 90 -copy all -outfile \"$SXIV_IMG\" \"$SXIV_IMG\"" }, | |||||
{ ControlMask, XK_slash, it_shell_cmd, (arg_t) \ | |||||
"jpegtran -rotate 180 -copy all -outfile \"$SXIV_IMG\" \"$SXIV_IMG\"" }, | |||||
}; | }; | ||||
/* mouse button mappings for image mode: */ | /* mouse button mappings for image mode: */ | ||||
@@ -0,0 +1,19 @@ | |||||
#!/bin/sh | |||||
case "$1" in | |||||
"C-g") | |||||
gimp "$2" & ;; | |||||
"C-comma") | |||||
exec jpegtran -rotate 270 -copy all -outfile "$2" "$2" ;; | |||||
"C-period") | |||||
exec jpegtran -rotate 90 -copy all -outfile "$2" "$2" ;; | |||||
"C-slash") | |||||
exec jpegtran -rotate 180 -copy all -outfile "$2" "$2" ;; | |||||
"C-less") | |||||
exec mogrify -rotate -90 "$2" ;; | |||||
"C-greater") | |||||
exec mogrify -rotate +90 "$2" ;; | |||||
"C-question") | |||||
exec mogrify -rotate 180 "$2" ;; | |||||
esac | |||||
@@ -46,6 +46,18 @@ enum { | |||||
TITLE_LEN = 256 | TITLE_LEN = 256 | ||||
}; | }; | ||||
#define EXEC_REL_DIR ".sxiv/exec" | |||||
enum { | |||||
EXEC_INFO, | |||||
EXEC_KEY | |||||
}; | |||||
typedef struct { | |||||
const char *name; | |||||
char *cmd; | |||||
} exec_t; | |||||
typedef struct { | typedef struct { | ||||
struct timeval when; | struct timeval when; | ||||
bool active; | bool active; | ||||
@@ -71,9 +83,13 @@ int prefix; | |||||
bool resized = false; | bool resized = false; | ||||
const char * const INFO_SCRIPT = ".sxiv/exec/image-info"; | exec_t exec[] = { | ||||
{ "image-info", NULL }, | |||||
{ "key-handler", NULL } | |||||
}; | |||||
struct { | struct { | ||||
char *script; | char *cmd; | ||||
int fd; | int fd; | ||||
unsigned int i, lastsep; | unsigned int i, lastsep; | ||||
bool open; | bool open; | ||||
@@ -221,7 +237,7 @@ void open_info(void) | |||||
static pid_t pid; | static pid_t pid; | ||||
int pfd[2]; | int pfd[2]; | ||||
if (info.script == NULL || info.open || win.bar.h == 0) | if (info.cmd == NULL || info.open || win.bar.h == 0) | ||||
return; | return; | ||||
if (info.fd != -1) { | if (info.fd != -1) { | ||||
close(info.fd); | close(info.fd); | ||||
@@ -242,8 +258,8 @@ void open_info(void) | |||||
} else if (pid == 0) { | } else if (pid == 0) { | ||||
close(pfd[0]); | close(pfd[0]); | ||||
dup2(pfd[1], 1); | dup2(pfd[1], 1); | ||||
execl(info.script, info.script, files[fileidx].name, NULL); | execl(info.cmd, info.cmd, files[fileidx].name, NULL); | ||||
warn("could not exec: %s", info.script); | warn("could not exec: %s", info.cmd); | ||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
} | } | ||||
} | } | ||||
@@ -356,7 +372,7 @@ void update_info(void) | |||||
fn, img.multi.sel + 1, img.multi.cnt); | fn, img.multi.sel + 1, img.multi.cnt); | ||||
} | } | ||||
n += snprintf(rt + n, rlen - n, "%0*d/%d", fw, sel + 1, filecnt); | n += snprintf(rt + n, rlen - n, "%0*d/%d", fw, sel + 1, filecnt); | ||||
ow_info = info.script == NULL; | ow_info = info.cmd == NULL; | ||||
} | } | ||||
if (ow_info) { | if (ow_info) { | ||||
fn = strlen(files[sel].name); | fn = strlen(files[sel].name); | ||||
@@ -418,6 +434,49 @@ void clear_resize(void) | |||||
resized = false; | resized = false; | ||||
} | } | ||||
void key_handler(const char *key, unsigned int mask) | |||||
{ | |||||
pid_t pid; | |||||
int retval, status, n = mode == MODE_IMAGE ? fileidx : tns.sel; | |||||
char *cmd = exec[EXEC_KEY].cmd, kstr[32]; | |||||
if (cmd == NULL || key == NULL) | |||||
return; | |||||
snprintf(kstr, sizeof(kstr), "%s%s%s%s", | |||||
mask & ControlMask ? "C-" : "", | |||||
mask & Mod1Mask ? "M-" : "", | |||||
mask & ShiftMask ? "S-" : "", key); | |||||
if ((pid = fork()) == 0) { | |||||
execl(cmd, cmd, kstr, files[n].path, NULL); | |||||
warn("could not exec key handler"); | |||||
exit(EXIT_FAILURE); | |||||
} else if (pid < 0) { | |||||
warn("could not fork key handler"); | |||||
return; | |||||
} | |||||
win_set_cursor(&win, CURSOR_WATCH); | |||||
waitpid(pid, &status, 0); | |||||
retval = WEXITSTATUS(status); | |||||
if (WIFEXITED(status) == 0 || retval != 0) | |||||
warn("key handler exited with non-zero return value: %d", retval); | |||||
if (mode == MODE_IMAGE) { | |||||
img_close(&img, true); | |||||
load_image(fileidx); | |||||
} | |||||
if (!tns_load(&tns, n, &files[n], true, mode == MODE_IMAGE) && | |||||
mode == MODE_THUMB) | |||||
{ | |||||
remove_file(tns.sel, false); | |||||
tns.dirty = true; | |||||
if (tns.sel >= tns.cnt) | |||||
tns.sel = tns.cnt - 1; | |||||
} | |||||
redraw(); | |||||
} | |||||
#define MODMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask)) | #define MODMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask)) | ||||
void on_keypress(XKeyEvent *kev) | void on_keypress(XKeyEvent *kev) | ||||
@@ -438,6 +497,9 @@ void on_keypress(XKeyEvent *kev) | |||||
XLookupString(kev, &key, 1, &ksym, NULL); | XLookupString(kev, &key, 1, &ksym, NULL); | ||||
sh = (kev->state & ShiftMask) && ksym != shksym ? ShiftMask : 0; | sh = (kev->state & ShiftMask) && ksym != shksym ? ShiftMask : 0; | ||||
if (IsModifierKey(ksym)) | |||||
return; | |||||
if ((ksym == XK_Escape && MODMASK(kev->state) == 0) || | if ((ksym == XK_Escape && MODMASK(kev->state) == 0) || | ||||
(key >= '0' && key <= '9')) | (key >= '0' && key <= '9')) | ||||
{ | { | ||||
@@ -456,6 +518,7 @@ void on_keypress(XKeyEvent *kev) | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
key_handler(XKeysymToString(ksym), kev->state & ~sh); | |||||
} | } | ||||
void on_buttonpress(XButtonEvent *bev) | void on_buttonpress(XButtonEvent *bev) | ||||
@@ -706,16 +769,17 @@ int main(int argc, char **argv) | |||||
if ((homedir = getenv("HOME")) == NULL) { | if ((homedir = getenv("HOME")) == NULL) { | ||||
warn("could not locate home directory"); | warn("could not locate home directory"); | ||||
} else { | } else for (i = 0; i < ARRLEN(exec); i++) { | ||||
len = strlen(homedir) + strlen(INFO_SCRIPT) + 2; | len = strlen(homedir) + strlen(EXEC_REL_DIR) + strlen(exec[i].name) + 3; | ||||
info.script = (char*) s_malloc(len); | exec[i].cmd = (char*) s_malloc(len); | ||||
snprintf(info.script, len, "%s/%s", homedir, INFO_SCRIPT); | snprintf(exec[i].cmd, len, "%s/%s/%s", homedir, EXEC_REL_DIR, exec[i].name); | ||||
if (access(info.script, X_OK) != 0) { | if (access(exec[i].cmd, X_OK) != 0) { | ||||
free(info.script); | free(exec[i].cmd); | ||||
info.script = NULL; | exec[i].cmd = NULL; | ||||
} | } | ||||
} | } | ||||
info.fd = -1; | info.fd = -1; | ||||
info.cmd = exec[EXEC_INFO].cmd; | |||||
if (options->thumb_mode) { | if (options->thumb_mode) { | ||||
mode = MODE_THUMB; | mode = MODE_THUMB; | ||||