From b8ff1677b1cbb4d3e769861d1e14234c6a38a80a Mon Sep 17 00:00:00 2001 From: Bert Date: Tue, 26 Jul 2011 18:01:29 +0200 Subject: Major code refactoring - Configurable key and mouse mappings in config.h - Put event handling code from main.c into events.[ch] --- main.c | 650 +++++------------------------------------------------------------ 1 file changed, 47 insertions(+), 603 deletions(-) (limited to 'main.c') diff --git a/main.c b/main.c index 2a80aff..1b98efd 100644 --- a/main.c +++ b/main.c @@ -16,32 +16,22 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#define _XOPEN_SOURCE 700 - #include -#include #include -#include -#include -#include -#include #include +#include -#include -#include -#include - +#include "events.h" #include "image.h" #include "options.h" #include "thumbs.h" -#include "types.h" #include "util.h" #include "window.h" -#include "config.h" -enum { TITLE_LEN = 256, FNAME_CNT = 1024 }; - -void run(); +enum { + TITLE_LEN = 256, + FNAME_CNT = 1024 +}; appmode_t mode; img_t img; @@ -64,6 +54,23 @@ void cleanup() { } } +int check_add_file(char *filename) { + if (!filename) + return 0; + + if (access(filename, R_OK)) { + warn("could not open file: %s", filename); + return 0; + } else { + if (fileidx == filecnt) { + filecnt *= 2; + filenames = (char**) s_realloc(filenames, filecnt * sizeof(char*)); + } + filenames[fileidx++] = filename; + return 1; + } +} + void remove_file(int n, unsigned char silent) { if (n < 0 || n >= filecnt) return; @@ -84,32 +91,32 @@ void remove_file(int n, unsigned char silent) { memset(tns.thumbs + tns.cnt - 1, 0, sizeof(thumb_t)); } - --filecnt; + filecnt--; if (n < tns.cnt) - --tns.cnt; + tns.cnt--; } -int load_image(int new) { +void load_image(int new) { struct stat fstats; - if (new >= 0 && new < filecnt) { - win_set_cursor(&win, CURSOR_WATCH); - img_close(&img, 0); - - while (!img_load(&img, filenames[new])) { - remove_file(new, 0); - if (new >= filecnt) - new = filecnt - 1; - } - fileidx = new; - if (!stat(filenames[new], &fstats)) - filesize = fstats.st_size; - else - filesize = 0; + if (new < 0 || new >= filecnt) + return; - /* cursor is reset in redraw() */ + /* cursor is reset in redraw() */ + win_set_cursor(&win, CURSOR_WATCH); + img_close(&img, 0); + + while (!img_load(&img, filenames[new])) { + remove_file(new, 0); + if (new >= filecnt) + new = filecnt - 1; } - return 1; + + fileidx = new; + if (!stat(filenames[new], &fstats)) + filesize = fstats.st_size; + else + filesize = 0; } void update_title() { @@ -138,23 +145,6 @@ void update_title() { win_set_title(&win, win_title); } -int check_append(char *filename) { - if (!filename) - return 0; - - if (access(filename, R_OK)) { - warn("could not open file: %s", filename); - return 0; - } else { - if (fileidx == filecnt) { - filecnt *= 2; - filenames = (char**) s_realloc(filenames, filecnt * sizeof(char*)); - } - filenames[fileidx++] = filename; - return 1; - } -} - int fncmp(const void *a, const void *b) { return strcoll(*((char* const*) a), *((char* const*) b)); } @@ -187,20 +177,21 @@ int main(int argc, char **argv) { filenames = (char**) s_malloc(filecnt * sizeof(char*)); fileidx = 0; + /* build file list: */ if (options->from_stdin) { while ((len = getline(&filename, &n, stdin)) > 0) { if (filename[len-1] == '\n') filename[len-1] = '\0'; - if (!*filename || !check_append(filename)) + if (!*filename || !check_add_file(filename)) free(filename); filename = NULL; } } else { - for (i = 0; i < options->filecnt; ++i) { + for (i = 0; i < options->filecnt; i++) { filename = options->filenames[i]; if (stat(filename, &fstats) || !S_ISDIR(fstats.st_mode)) { - check_append(filename); + check_add_file(filename); } else { if (!options->recursive) { warn("ignoring directory: %s", filename); @@ -212,7 +203,7 @@ int main(int argc, char **argv) { } start = fileidx; while ((filename = r_readdir(&dir))) { - if (!check_append(filename)) + if (!check_add_file(filename)) free((void*) filename); } r_closedir(&dir); @@ -252,550 +243,3 @@ int main(int argc, char **argv) { return 0; } - -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; -} - - -/* event handling */ - -/* timeouts in milliseconds: */ -enum { - TO_WIN_RESIZE = 75, - TO_IMAGE_DRAG = 1, - TO_CURSOR_HIDE = 1500, - TO_THUMBS_LOAD = 200 -}; - -int timo_cursor; -int timo_redraw; -unsigned char drag; -int mox, moy; - -void redraw() { - if (mode == MODE_NORMAL) { - img_render(&img, &win); - if (timo_cursor) - win_set_cursor(&win, CURSOR_ARROW); - else if (!drag) - win_set_cursor(&win, CURSOR_NONE); - } else { - tns_render(&tns, &win); - } - update_title(); - timo_redraw = 0; -} - -void on_keypress(XKeyEvent *kev) { - int x, y; - unsigned int w, h; - char key; - KeySym ksym; - int changed, ctrl; - - if (!kev) - return; - - XLookupString(kev, &key, 1, &ksym, NULL); - changed = 0; - ctrl = CLEANMASK(kev->state) & ControlMask; - - /* external commands from commands.h */ - if (EXT_COMMANDS && ctrl) { - for (x = 0; x < LEN(commands); ++x) { - if (commands[x].key == key) { - win_set_cursor(&win, CURSOR_WATCH); - if (run_command(commands[x].cmdline, commands[x].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; - } - } - } - - if (mode == MODE_NORMAL) { - switch (ksym) { - /* navigate image list */ - case XK_n: - case XK_space: - if (fileidx + 1 < filecnt) - changed = load_image(fileidx + 1); - break; - case XK_p: - case XK_BackSpace: - if (fileidx > 0) - changed = load_image(fileidx - 1); - break; - case XK_bracketleft: - if (fileidx != 0) - changed = load_image(MAX(0, fileidx - 10)); - break; - case XK_bracketright: - if (fileidx != filecnt - 1) - changed = load_image(MIN(fileidx + 10, filecnt - 1)); - break; - case XK_g: - if (fileidx != 0) - changed = load_image(0); - break; - case XK_G: - if (fileidx != filecnt - 1) - changed = load_image(filecnt - 1); - break; - - /* zooming */ - case XK_plus: - case XK_equal: - case XK_KP_Add: - changed = img_zoom_in(&img, &win); - break; - case XK_minus: - case XK_KP_Subtract: - changed = img_zoom_out(&img, &win); - break; - case XK_0: - case XK_KP_0: - changed = img_zoom(&img, &win, 1.0); - break; - case XK_w: - if ((changed = img_fit_win(&img, &win))) - img_center(&img, &win); - break; - - /* panning */ - case XK_h: - case XK_Left: - changed = img_pan(&img, &win, DIR_LEFT, ctrl); - break; - case XK_j: - case XK_Down: - changed = img_pan(&img, &win, DIR_DOWN, ctrl); - break; - case XK_k: - case XK_Up: - changed = img_pan(&img, &win, DIR_UP, ctrl); - break; - case XK_l: - case XK_Right: - changed = img_pan(&img, &win, DIR_RIGHT, ctrl); - break; - case XK_Prior: - changed = img_pan(&img, &win, DIR_UP, 1); - break; - case XK_Next: - changed = img_pan(&img, &win, DIR_DOWN, 1); - break; - - case XK_H: - changed = img_pan_edge(&img, &win, DIR_LEFT); - break; - case XK_J: - changed = img_pan_edge(&img, &win, DIR_DOWN); - break; - case XK_K: - changed = img_pan_edge(&img, &win, DIR_UP); - break; - case XK_L: - changed = img_pan_edge(&img, &win, DIR_RIGHT); - break; - - /* rotation */ - case XK_less: - img_rotate_left(&img, &win); - changed = 1; - break; - case XK_greater: - img_rotate_right(&img, &win); - changed = 1; - break; - - /* control window */ - case XK_W: - x = MAX(0, win.x + img.x); - y = MAX(0, win.y + img.y); - w = img.w * img.zoom; - h = img.h * img.zoom; - if ((changed = win_moveresize(&win, x, y, w, h))) { - img.x = x - win.x; - img.y = y - win.y; - } - break; - - /* switch to thumbnail mode */ - case XK_Return: - if (!tns.thumbs) - tns_init(&tns, filecnt); - img_close(&img, 0); - mode = MODE_THUMBS; - win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = 0; - tns.sel = fileidx; - changed = tns.dirty = 1; - break; - - /* miscellaneous */ - case XK_a: - img_toggle_antialias(&img); - changed = 1; - break; - case XK_A: - img.alpha ^= 1; - changed = 1; - break; - case XK_D: - remove_file(fileidx, 1); - changed = load_image(fileidx >= filecnt ? filecnt - 1 : fileidx); - break; - case XK_r: - changed = load_image(fileidx); - break; - } - } else { - /* thumbnail mode */ - switch (ksym) { - /* open selected image */ - case XK_Return: - load_image(tns.sel); - mode = MODE_NORMAL; - changed = 1; - break; - - /* move selection */ - case XK_h: - case XK_Left: - changed = tns_move_selection(&tns, &win, DIR_LEFT); - break; - case XK_j: - case XK_Down: - changed = tns_move_selection(&tns, &win, DIR_DOWN); - break; - case XK_k: - case XK_Up: - changed = tns_move_selection(&tns, &win, DIR_UP); - break; - case XK_l: - case XK_Right: - changed = tns_move_selection(&tns, &win, DIR_RIGHT); - break; - case XK_g: - if (tns.sel != 0) { - tns.sel = 0; - changed = tns.dirty = 1; - } - break; - case XK_G: - if (tns.sel != tns.cnt - 1) { - tns.sel = tns.cnt - 1; - changed = tns.dirty = 1; - } - break; - - /* miscellaneous */ - case XK_D: - if (tns.sel < tns.cnt) { - remove_file(tns.sel, 1); - changed = tns.dirty = 1; - if (tns.sel >= tns.cnt) - tns.sel = tns.cnt - 1; - } - break; - } - } - - /* common key mappings */ - switch (ksym) { - case XK_q: - cleanup(); - exit(0); - case XK_f: - win_toggle_fullscreen(&win); - if (mode == MODE_NORMAL) - img.checkpan = 1; - else - tns.dirty = 1; - timo_redraw = TO_WIN_RESIZE; - break; - } - - if (changed) - redraw(); -} - -void on_buttonpress(XButtonEvent *bev) { - int changed, sel; - unsigned int mask; - - if (!bev) - return; - - mask = CLEANMASK(bev->state); - changed = 0; - - if (mode == MODE_NORMAL) { - if (!drag) { - win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = TO_CURSOR_HIDE; - } - - switch (bev->button) { - case Button1: - if (fileidx + 1 < filecnt) - changed = load_image(fileidx + 1); - break; - case Button2: - mox = bev->x; - moy = bev->y; - win_set_cursor(&win, CURSOR_HAND); - timo_cursor = 0; - drag = 1; - break; - case Button3: - if (fileidx > 0) - changed = load_image(fileidx - 1); - break; - case Button4: - if (mask == ControlMask) - changed = img_zoom_in(&img, &win); - else if (mask == ShiftMask) - changed = img_pan(&img, &win, DIR_LEFT, 0); - else - changed = img_pan(&img, &win, DIR_UP, 0); - break; - case Button5: - if (mask == ControlMask) - changed = img_zoom_out(&img, &win); - else if (mask == ShiftMask) - changed = img_pan(&img, &win, DIR_RIGHT, 0); - else - changed = img_pan(&img, &win, DIR_DOWN, 0); - break; - case 6: - changed = img_pan(&img, &win, DIR_LEFT, 0); - break; - case 7: - changed = img_pan(&img, &win, DIR_RIGHT, 0); - break; - } - } else { - /* thumbnail mode */ - switch (bev->button) { - case Button1: - if ((sel = tns_translate(&tns, bev->x, bev->y)) >= 0) { - if (sel == tns.sel) { - load_image(tns.sel); - mode = MODE_NORMAL; - timo_cursor = TO_CURSOR_HIDE; - } else { - tns_highlight(&tns, &win, tns.sel, False); - tns_highlight(&tns, &win, sel, True); - tns.sel = sel; - } - changed = 1; - break; - } - break; - case Button4: - changed = tns_scroll(&tns, DIR_UP); - break; - case Button5: - changed = tns_scroll(&tns, DIR_DOWN); - break; - } - } - - if (changed) - redraw(); -} - -void on_motionnotify(XMotionEvent *mev) { - if (!mev) - return; - - if (mev->x >= 0 && mev->x <= win.w && mev->y >= 0 && mev->y <= win.h) { - if (img_move(&img, &win, mev->x - mox, mev->y - moy)) - timo_redraw = TO_IMAGE_DRAG; - - mox = mev->x; - moy = mev->y; - } -} - -void run() { - int xfd, timeout; - fd_set fds; - struct timeval tt, t0, t1; - XEvent ev; - - drag = 0; - timo_cursor = mode == MODE_NORMAL ? TO_CURSOR_HIDE : 0; - - redraw(); - - while (1) { - if (mode == MODE_THUMBS && tns.cnt < filecnt) { - win_set_cursor(&win, CURSOR_WATCH); - gettimeofday(&t0, 0); - - while (tns.cnt < filecnt && !XPending(win.env.dpy)) { - if (tns_load(&tns, tns.cnt, filenames[tns.cnt], 0)) - ++tns.cnt; - else - remove_file(tns.cnt, 0); - gettimeofday(&t1, 0); - if (TIMEDIFF(&t1, &t0) >= TO_THUMBS_LOAD) - break; - } - if (tns.cnt == filecnt) - win_set_cursor(&win, CURSOR_ARROW); - if (!XPending(win.env.dpy)) { - redraw(); - continue; - } else { - timo_redraw = TO_THUMBS_LOAD; - } - } else if (timo_cursor || timo_redraw) { - gettimeofday(&t0, 0); - if (timo_cursor && timo_redraw) - timeout = MIN(timo_cursor, timo_redraw); - else if (timo_cursor) - timeout = timo_cursor; - else - timeout = timo_redraw; - MSEC_TO_TIMEVAL(timeout, &tt); - xfd = ConnectionNumber(win.env.dpy); - FD_ZERO(&fds); - FD_SET(xfd, &fds); - - if (!XPending(win.env.dpy)) - select(xfd + 1, &fds, 0, 0, &tt); - gettimeofday(&t1, 0); - timeout = MIN(TIMEDIFF(&t1, &t0), timeout); - - /* timeouts fired? */ - if (timo_cursor) { - timo_cursor = MAX(0, timo_cursor - timeout); - if (!timo_cursor) - win_set_cursor(&win, CURSOR_NONE); - } - if (timo_redraw) { - timo_redraw = MAX(0, timo_redraw - timeout); - if (!timo_redraw) - redraw(); - } - if (!XPending(win.env.dpy) && (timo_cursor || timo_redraw)) - continue; - } - - if (!XNextEvent(win.env.dpy, &ev)) { - switch (ev.type) { - case KeyPress: - on_keypress(&ev.xkey); - break; - case ButtonPress: - on_buttonpress(&ev.xbutton); - break; - case ButtonRelease: - if (ev.xbutton.button == Button2) { - drag = 0; - if (mode == MODE_NORMAL) { - win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = TO_CURSOR_HIDE; - } - } - break; - case MotionNotify: - if (drag) { - on_motionnotify(&ev.xmotion); - } else if (mode == MODE_NORMAL) { - if (!timo_cursor) - win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = TO_CURSOR_HIDE; - } - break; - case ConfigureNotify: - if (win_configure(&win, &ev.xconfigure)) { - timo_redraw = TO_WIN_RESIZE; - if (mode == MODE_NORMAL) - img.checkpan = 1; - else - tns.dirty = 1; - } - break; - case ClientMessage: - if ((Atom) ev.xclient.data.l[0] == wm_delete_win) - return; - break; - } - } - } -} -- cgit v1.2.3