diff --git a/config.h b/config.h index a39cd24..e5df7aa 100644 --- a/config.h +++ b/config.h @@ -1,9 +1,3 @@ -#ifdef _GENERAL_CONFIG - -/* enable external commands (defined below)? 0 = off, 1 = on: */ -enum { EXT_COMMANDS = 0 }; - -#endif #ifdef _WINDOW_CONFIG /* default window dimensions (overwritten via -g option): */ @@ -42,79 +36,80 @@ enum { THUMB_SIZE = 60 }; /* keyboard mappings for image and thumbnail mode: */ static const keymap_t keys[] = { - /* key function argument */ - { XK_q, quit, None }, - { XK_r, reload, None }, - { XK_f, toggle_fullscreen, None }, - { XK_a, toggle_antialias, None }, - { XK_A, toggle_alpha, None }, - { XK_Return, switch_mode, None }, - - { XK_g, first, None }, - { XK_G, last, None }, - { XK_n, navigate, +1 }, - { XK_space, navigate, +1 }, - { XK_p, navigate, -1 }, - { XK_BackSpace, navigate, -1 }, - { XK_bracketright, navigate, +10 }, - { XK_bracketleft, navigate, -10 }, - - { XK_D, remove_image, None }, - - { XK_h, move, DIR_LEFT }, - { XK_Left, move, DIR_LEFT }, - { XK_j, move, DIR_DOWN }, - { XK_Down, move, DIR_DOWN }, - { XK_k, move, DIR_UP }, - { XK_Up, move, DIR_UP }, - { XK_l, move, DIR_RIGHT }, - { XK_Right, move, DIR_RIGHT }, - - { XK_braceleft, pan_screen, DIR_LEFT }, - { XK_Next, pan_screen, DIR_DOWN }, - { XK_Prior, pan_screen, DIR_UP }, - { XK_braceright, pan_screen, DIR_RIGHT }, - - { XK_H, pan_edge, DIR_LEFT }, - { XK_J, pan_edge, DIR_DOWN }, - { XK_K, pan_edge, DIR_UP }, - { XK_L, pan_edge, DIR_RIGHT }, - - { XK_plus, zoom, +1 }, - { XK_equal, zoom, +1 }, - { XK_KP_Add, zoom, +1 }, - { XK_minus, zoom, -1 }, - { XK_KP_Subtract, zoom, -1 }, - { XK_0, zoom, 0 }, - { XK_KP_0, zoom, 0 }, - { XK_w, fit_to_win, None }, - { XK_W, fit_to_img, None }, - - { XK_less, rotate, DIR_LEFT }, - { XK_greater, rotate, DIR_RIGHT }, -}; - -/* external commands and corresponding key mappings: */ -static const command_t commands[] = { - /* ctrl-... reload? command, '#' is replaced by filename */ - { XK_comma, True, "jpegtran -rotate 270 -copy all -outfile # #" }, - { XK_period, True, "jpegtran -rotate 90 -copy all -outfile # #" }, - { XK_less, True, "mogrify -rotate -90 #" }, - { XK_greater, True, "mogrify -rotate +90 #" } + /* ctrl key function argument */ + { False, XK_q, quit, (arg_t) None }, + { False, XK_r, reload, (arg_t) None }, + { False, XK_f, toggle_fullscreen, (arg_t) None }, + { False, XK_a, toggle_antialias, (arg_t) None }, + { False, XK_A, toggle_alpha, (arg_t) None }, + { False, XK_Return, switch_mode, (arg_t) None }, + + { False, XK_g, first, (arg_t) None }, + { False, XK_G, last, (arg_t) None }, + { False, XK_n, navigate, (arg_t) +1 }, + { False, XK_space, navigate, (arg_t) +1 }, + { False, XK_p, navigate, (arg_t) -1 }, + { False, XK_BackSpace, navigate, (arg_t) -1 }, + { False, XK_bracketright, navigate, (arg_t) +10 }, + { False, XK_bracketleft, navigate, (arg_t) -10 }, + + { False, XK_D, remove_image, (arg_t) None }, + + { False, XK_h, move, (arg_t) DIR_LEFT }, + { False, XK_Left, move, (arg_t) DIR_LEFT }, + { False, XK_j, move, (arg_t) DIR_DOWN }, + { False, XK_Down, move, (arg_t) DIR_DOWN }, + { False, XK_k, move, (arg_t) DIR_UP }, + { False, XK_Up, move, (arg_t) DIR_UP }, + { False, XK_l, move, (arg_t) DIR_RIGHT }, + { False, XK_Right, move, (arg_t) DIR_RIGHT }, + + { False, XK_braceleft, pan_screen, (arg_t) DIR_LEFT }, + { False, XK_Next, pan_screen, (arg_t) DIR_DOWN }, + { False, XK_Prior, pan_screen, (arg_t) DIR_UP }, + { False, XK_braceright, pan_screen, (arg_t) DIR_RIGHT }, + + { False, XK_H, pan_edge, (arg_t) DIR_LEFT }, + { False, XK_J, pan_edge, (arg_t) DIR_DOWN }, + { False, XK_K, pan_edge, (arg_t) DIR_UP }, + { False, XK_L, pan_edge, (arg_t) DIR_RIGHT }, + + { False, XK_plus, zoom, (arg_t) +1 }, + { False, XK_equal, zoom, (arg_t) +1 }, + { False, XK_KP_Add, zoom, (arg_t) +1 }, + { False, XK_minus, zoom, (arg_t) -1 }, + { False, XK_KP_Subtract, zoom, (arg_t) -1 }, + { False, XK_0, zoom, (arg_t) None }, + { False, XK_KP_0, zoom, (arg_t) None }, + { False, XK_w, fit_to_win, (arg_t) None }, + { False, XK_W, fit_to_img, (arg_t) None }, + + { False, XK_less, rotate, (arg_t) DIR_LEFT }, + { False, XK_greater, rotate, (arg_t) DIR_RIGHT }, + + /* open the current image with given program: */ + { True, XK_g, open_with, (arg_t) "gimp" }, + + /* run shell command line on the current file, + * '#' is replaced by filename: */ + { True, XK_less, run_command, (arg_t) "mogrify -rotate -90 #" }, + { True, XK_greater, run_command, (arg_t) "mogrify -rotate +90 #" }, + { True, XK_comma, run_command, (arg_t) "jpegtran -rotate 270 -copy all -outfile # #" }, + { True, XK_period, run_command, (arg_t) "jpegtran -rotate 90 -copy all -outfile # #" }, }; /* mouse button mappings for image mode: */ static const button_t buttons[] = { - /* modifier button function argument */ - { None, Button1, navigate, +1 }, - { None, Button3, navigate, -1 }, - { None, Button2, drag, None }, - { None, Button4, move, DIR_UP }, - { None, Button5, move, DIR_DOWN }, - { ShiftMask, Button4, move, DIR_LEFT }, - { ShiftMask, Button5, move, DIR_RIGHT }, - { ControlMask, Button4, zoom, +1 }, - { ControlMask, Button5, zoom, -1 }, + /* ctrl shift button function argument */ + { False, False, Button1, navigate, (arg_t) +1 }, + { False, False, Button3, navigate, (arg_t) -1 }, + { False, False, Button2, drag, (arg_t) None }, + { False, False, Button4, move, (arg_t) DIR_UP }, + { False, False, Button5, move, (arg_t) DIR_DOWN }, + { False, True, Button4, move, (arg_t) DIR_LEFT }, + { False, True, Button5, move, (arg_t) DIR_RIGHT }, + { True, False, Button4, zoom, (arg_t) +1 }, + { True, False, Button5, zoom, (arg_t) -1 }, }; #endif diff --git a/events.c b/events.c index 03ea292..618aa3a 100644 --- a/events.c +++ b/events.c @@ -58,62 +58,6 @@ extern int filecnt, fileidx; int timo_cursor; int timo_redraw; -int run_command(const char *cline, Bool reload) { - int fncnt, fnlen; - char *cn, *cmdline; - const char *co, *fname; - pid_t pid; - int ret, status; - - if (!cline || !*cline) - return 0; - - fncnt = 0; - co = cline - 1; - while ((co = strchr(co + 1, '#'))) - fncnt++; - - if (!fncnt) - return 0; - - ret = 0; - fname = filenames[mode == MODE_NORMAL ? fileidx : tns.sel]; - fnlen = strlen(fname); - cn = cmdline = (char*) s_malloc((strlen(cline) + fncnt * (fnlen + 2)) * - sizeof(char)); - - /* replace all '#' with filename */ - for (co = cline; *co; co++) { - if (*co == '#') { - *cn++ = '"'; - strcpy(cn, fname); - cn += fnlen; - *cn++ = '"'; - } else { - *cn++ = *co; - } - } - *cn = '\0'; - - if ((pid = fork()) == 0) { - execlp("/bin/sh", "/bin/sh", "-c", cmdline, NULL); - warn("could not exec: /bin/sh"); - exit(1); - } else if (pid < 0) { - warn("could not fork. command line was: %s", cmdline); - } else if (reload) { - waitpid(pid, &status, 0); - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) - ret = 1; - else - warn("child exited with non-zero return value: %d. command line was: %s", - WEXITSTATUS(status), cmdline); - } - - free(cmdline); - return ret; -} - void redraw() { if (mode == MODE_NORMAL) { img_render(&img, &win); @@ -128,6 +72,15 @@ void redraw() { timo_redraw = 0; } +Bool keymask(const keymap_t *k, unsigned int state) { + return (k->ctrl ? ControlMask : 0) == (state & ControlMask); +} + +Bool buttonmask(const button_t *b, unsigned int state) { + return ((b->ctrl ? ControlMask : 0) | (b->shift ? ShiftMask : 0)) == + (state & (ControlMask | ShiftMask)); +} + void on_keypress(XKeyEvent *kev) { int i; KeySym ksym; @@ -138,38 +91,9 @@ void on_keypress(XKeyEvent *kev) { XLookupString(kev, &key, 1, &ksym, NULL); - if (EXT_COMMANDS && (CLEANMASK(kev->state) & ControlMask)) { - for (i = 0; i < LEN(commands); i++) { - if (commands[i].ksym == ksym) { - win_set_cursor(&win, CURSOR_WATCH); - if (run_command(commands[i].cmdline, commands[i].reload)) { - if (mode == MODE_NORMAL) { - if (fileidx < tns.cnt) - tns_load(&tns, fileidx, filenames[fileidx], 1); - img_close(&img, 1); - load_image(fileidx); - } else { - if (!tns_load(&tns, tns.sel, filenames[tns.sel], 0)) { - remove_file(tns.sel, 0); - tns.dirty = 1; - if (tns.sel >= tns.cnt) - tns.sel = tns.cnt - 1; - } - } - redraw(); - } - if (mode == MODE_THUMBS) - win_set_cursor(&win, CURSOR_ARROW); - else if (!timo_cursor) - win_set_cursor(&win, CURSOR_NONE); - return; - } - } - } - for (i = 0; i < LEN(keys); i++) { - if (ksym == keys[i].ksym && keys[i].handler) { - if (keys[i].handler(keys[i].arg)) + if (keymask(&keys[i], kev->state) && ksym == keys[i].ksym) { + if (keys[i].handler && keys[i].handler(keys[i].arg)) redraw(); return; } @@ -187,10 +111,10 @@ void on_buttonpress(XButtonEvent *bev) { timo_cursor = TO_CURSOR_HIDE; for (i = 0; i < LEN(buttons); i++) { - if (CLEANMASK(bev->state) == CLEANMASK(buttons[i].mod) && - bev->button == buttons[i].button && buttons[i].handler) + if (buttonmask(&buttons[i], bev->state) && + bev->button == buttons[i].button) { - if (buttons[i].handler(buttons[i].arg)) + if (buttons[i].handler && buttons[i].handler(buttons[i].arg)) redraw(); return; } @@ -379,7 +303,9 @@ int switch_mode(arg_t a) { return 1; } -int navigate(arg_t n) { +int navigate(arg_t a) { + int n = (int) a; + if (mode == MODE_NORMAL) { n += fileidx; if (n < 0) @@ -437,21 +363,27 @@ int remove_image(arg_t a) { } } -int move(arg_t dir) { +int move(arg_t a) { + direction_t dir = (direction_t) a; + if (mode == MODE_NORMAL) return img_pan(&img, &win, dir, 0); else return tns_move_selection(&tns, &win, dir); } -int pan_screen(arg_t dir) { +int pan_screen(arg_t a) { + direction_t dir = (direction_t) a; + if (mode == MODE_NORMAL) return img_pan(&img, &win, dir, 1); else return 0; } -int pan_edge(arg_t dir) { +int pan_edge(arg_t a) { + direction_t dir = (direction_t) a; + if (mode == MODE_NORMAL) return img_pan_edge(&img, &win, dir); else @@ -459,7 +391,7 @@ int pan_edge(arg_t dir) { } /* Xlib helper function for drag() */ -Bool ismnotify(Display *d, XEvent *e, XPointer a) { +Bool is_motionnotify(Display *d, XEvent *e, XPointer a) { return e != NULL && e->type == MotionNotify; } @@ -498,7 +430,7 @@ int drag(arg_t a) { break; } if (dragging) - next = XCheckIfEvent(win.env.dpy, &e, ismnotify, None); + next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None); if ((!dragging || !next) && (dx != 0 || dy != 0)) { if (img_move(&img, &win, dx, dy)) img_render(&img, &win); @@ -513,7 +445,9 @@ int drag(arg_t a) { return 0; } -int rotate(arg_t dir) { +int rotate(arg_t a) { + direction_t dir = (direction_t) a; + if (mode == MODE_NORMAL) { if (dir == DIR_LEFT) { img_rotate_left(&img, &win); @@ -526,7 +460,9 @@ int rotate(arg_t dir) { return 0; } -int zoom(arg_t scale) { +int zoom(arg_t a) { + int scale = (int) a; + if (mode != MODE_NORMAL) return 0; if (scale > 0) @@ -537,7 +473,9 @@ int zoom(arg_t scale) { return img_zoom(&img, &win, 1.0); } -int fit_to_win(arg_t ret) { +int fit_to_win(arg_t a) { + int ret; + if (mode == MODE_NORMAL) { if ((ret = img_fit_win(&img, &win))) img_center(&img, &win); @@ -547,8 +485,8 @@ int fit_to_win(arg_t ret) { } } -int fit_to_img(arg_t ret) { - int x, y; +int fit_to_img(arg_t a) { + int ret, x, y; unsigned int w, h; if (mode == MODE_NORMAL) { @@ -565,3 +503,96 @@ int fit_to_img(arg_t ret) { return 0; } } + +int open_with(arg_t a) { + const char *prog = (const char*) a; + pid_t pid; + + if (!prog || !*prog) + return 0; + + if((pid = fork()) == 0) { + execlp(prog, prog, + filenames[mode == MODE_NORMAL ? fileidx : tns.sel], NULL); + warn("could not exec: %s", prog); + exit(1); + } else if (pid < 0) { + warn("could not for. program was: %s", prog); + } + + return 0; +} + +int run_command(arg_t a) { + const char *cline = (const char*) a; + char *cn, *cmdline; + const char *co, *fname; + int fncnt, fnlen, status; + pid_t pid; + + if (!cline || !*cline) + return 0; + + /* build command line: */ + fncnt = 0; + co = cline - 1; + while ((co = strchr(co + 1, '#'))) + fncnt++; + if (!fncnt) + return 0; + fname = filenames[mode == MODE_NORMAL ? fileidx : tns.sel]; + fnlen = strlen(fname); + cn = cmdline = (char*) s_malloc((strlen(cline) + fncnt * (fnlen + 2)) * + sizeof(char)); + /* replace all '#' with filename: */ + for (co = cline; *co; co++) { + if (*co == '#') { + *cn++ = '"'; + strcpy(cn, fname); + cn += fnlen; + *cn++ = '"'; + } else { + *cn++ = *co; + } + } + *cn = '\0'; + + win_set_cursor(&win, CURSOR_WATCH); + + if ((pid = fork()) == 0) { + execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL); + warn("could not exec: /bin/sh"); + exit(1); + } else if (pid < 0) { + warn("could not fork. command line was: %s", cmdline); + goto end; + } + + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + warn("child exited with non-zero return value: %d. command line was: %s", + WEXITSTATUS(status), cmdline); + + if (mode == MODE_NORMAL) { + if (fileidx < tns.cnt) + tns_load(&tns, fileidx, filenames[fileidx], 1); + img_close(&img, 1); + load_image(fileidx); + } else { + if (!tns_load(&tns, tns.sel, filenames[tns.sel], 0)) { + remove_file(tns.sel, 0); + tns.dirty = 1; + if (tns.sel >= tns.cnt) + tns.sel = tns.cnt - 1; + } + } + +end: + if (mode == MODE_THUMBS) + win_set_cursor(&win, CURSOR_ARROW); + /* else: cursor is reset in redraw() */ + + free(cmdline); + + return 1; +} diff --git a/events.h b/events.h index d2e7c6d..4e60d2a 100644 --- a/events.h +++ b/events.h @@ -21,22 +21,18 @@ #include -typedef struct { - KeySym ksym; - Bool reload; - const char *cmdline; -} command_t; - -typedef int arg_t; +typedef void* arg_t; typedef struct { + Bool ctrl; KeySym ksym; int (*handler)(arg_t); arg_t arg; } keymap_t; typedef struct { - unsigned int mod; + Bool ctrl; + Bool shift; unsigned int button; int (*handler)(arg_t); arg_t arg; @@ -63,5 +59,7 @@ int rotate(arg_t); int zoom(arg_t); int fit_to_win(arg_t); int fit_to_img(arg_t); +int open_with(arg_t); +int run_command(arg_t); #endif /* EVENTS_H */