diff --git a/Makefile b/Makefile index ade1b3e..07c577a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ all: sxiv -VERSION = git-20110819 +VERSION = git-20110902 CC = gcc DESTDIR = diff --git a/commands.c b/commands.c index 51f7a55..123d4f5 100644 --- a/commands.c +++ b/commands.c @@ -30,6 +30,11 @@ void cleanup(); void remove_file(int, unsigned char); void load_image(int); +void redraw(); +void hide_cursor(); +void animate(); +void set_timeout(timeout_f, int, int); +void reset_timeout(timeout_f); extern appmode_t mode; extern img_t img; @@ -39,10 +44,6 @@ extern win_t win; extern fileinfo_t *files; extern int filecnt, fileidx; -extern int timo_cursor; -extern int timo_redraw; -extern int timo_adelay; - int it_quit(arg_t a) { cleanup(); exit(0); @@ -54,12 +55,11 @@ int it_switch_mode(arg_t a) { tns_init(&tns, filecnt); img_close(&img, 0); win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = 0; + reset_timeout(hide_cursor); tns.sel = fileidx; tns.dirty = 1; mode = MODE_THUMB; } else { - timo_cursor = TO_CURSOR_HIDE; load_image(tns.sel); mode = MODE_IMAGE; } @@ -68,11 +68,11 @@ int it_switch_mode(arg_t a) { int it_toggle_fullscreen(arg_t a) { win_toggle_fullscreen(&win); + set_timeout(redraw, TO_REDRAW_RESIZE, 0); if (mode == MODE_IMAGE) img.checkpan = 1; else tns.dirty = 1; - timo_redraw = TO_WIN_RESIZE; return 0; } @@ -156,15 +156,18 @@ int i_navigate_frame(arg_t a) { } int i_toggle_animation(arg_t a) { + int delay; + if (mode != MODE_IMAGE) return 0; if (img.multi.animate) { - timo_adelay = 0; + reset_timeout(animate); img.multi.animate = 0; return 0; } else { - timo_adelay = img_frame_animate(&img, 1); + delay = img_frame_animate(&img, 1); + set_timeout(animate, delay, 1); return 1; } } @@ -245,8 +248,8 @@ int i_drag(arg_t a) { } win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = TO_CURSOR_HIDE; - timo_redraw = 0; + set_timeout(hide_cursor, TO_CURSOR_HIDE, 1); + reset_timeout(redraw); return 0; } diff --git a/main.c b/main.c index 6545cfb..5866823 100644 --- a/main.c +++ b/main.c @@ -41,6 +41,17 @@ enum { FNAME_CNT = 1024 }; +typedef struct { + struct timeval when; + Bool active; + timeout_f handler; +} timeout_t; + +/* timeout handler functions: */ +void redraw(); +void hide_cursor(); +void animate(); + appmode_t mode; img_t img; tns_t tns; @@ -52,9 +63,11 @@ size_t filesize; char win_title[TITLE_LEN]; -int timo_cursor; -int timo_redraw; -int timo_adelay; /* multi-frame animation delay time */ +timeout_t timeouts[] = { + { { 0, 0 }, False, redraw }, + { { 0, 0 }, False, hide_cursor }, + { { 0, 0 }, False, animate } +}; void cleanup() { static int in = 0; @@ -120,6 +133,54 @@ void remove_file(int n, unsigned char silent) { tns.cnt--; } +void set_timeout(timeout_f handler, int time, int overwrite) { + int i; + + for (i = 0; i < LEN(timeouts); i++) { + if (timeouts[i].handler == handler) { + if (!timeouts[i].active || overwrite) { + gettimeofday(&timeouts[i].when, 0); + MSEC_ADD_TO_TIMEVAL(time, &timeouts[i].when); + timeouts[i].active = True; + } + return; + } + } +} + +void reset_timeout(timeout_f handler) { + int i; + + for (i = 0; i < LEN(timeouts); i++) { + if (timeouts[i].handler == handler) { + timeouts[i].active = False; + return; + } + } +} + +int check_timeouts(struct timeval *t) { + int i, tdiff, tmin = -1; + struct timeval now; + + gettimeofday(&now, 0); + for (i = 0; i < LEN(timeouts); i++) { + if (timeouts[i].active) { + tdiff = TIMEDIFF(&timeouts[i].when, &now); + if (tdiff <= 0) { + timeouts[i].active = False; + if (timeouts[i].handler) + timeouts[i].handler(); + } else if (tmin < 0 || tdiff < tmin) { + tmin = tdiff; + } + } + } + if (tmin > 0 && t) + MSEC_TO_TIMEVAL(tmin, t); + return tmin > 0; +} + void load_image(int new) { struct stat fstats; @@ -144,9 +205,9 @@ void load_image(int new) { if (img.multi.cnt) { if (img.multi.animate) - timo_adelay = img.multi.frames[img.multi.sel].delay; + set_timeout(animate, img.multi.frames[img.multi.sel].delay, 1); else - timo_adelay = 0; + reset_timeout(animate); } } @@ -186,15 +247,31 @@ void update_title() { void redraw() { if (mode == MODE_IMAGE) { img_render(&img, &win); - if (timo_cursor) - win_set_cursor(&win, CURSOR_ARROW); - else + if (img.multi.animate) { win_set_cursor(&win, CURSOR_NONE); + } else { + win_set_cursor(&win, CURSOR_ARROW); + set_timeout(hide_cursor, TO_CURSOR_HIDE, 1); + } } else { tns_render(&tns, &win); } update_title(); - timo_redraw = 0; + reset_timeout(redraw); +} + +void hide_cursor() { + win_set_cursor(&win, CURSOR_NONE); +} + +void animate() { + int delay; + + delay = img_frame_animate(&img, 0); + if (delay) { + set_timeout(animate, delay, 1); + redraw(); + } } Bool keymask(const keymap_t *k, unsigned int state) { @@ -233,7 +310,7 @@ void on_buttonpress(XButtonEvent *bev) { if (mode == MODE_IMAGE) { win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = TO_CURSOR_HIDE; + set_timeout(hide_cursor, TO_CURSOR_HIDE, 1); for (i = 0; i < LEN(buttons); i++) { if (buttons[i].button == bev->button && @@ -252,7 +329,7 @@ void on_buttonpress(XButtonEvent *bev) { if (sel == tns.sel) { load_image(tns.sel); mode = MODE_IMAGE; - timo_cursor = TO_CURSOR_HIDE; + set_timeout(hide_cursor, TO_CURSOR_HIDE, 1); } else { tns_highlight(&tns, &win, tns.sel, False); tns_highlight(&tns, &win, sel, True); @@ -272,75 +349,39 @@ void on_buttonpress(XButtonEvent *bev) { } void run() { - int xfd, timeout; + int xfd; fd_set fds; - struct timeval tt, t0, t1; + struct timeval timeout; XEvent ev; - timo_cursor = mode == MODE_IMAGE ? TO_CURSOR_HIDE : 0; - redraw(); while (1) { - if (mode == MODE_THUMB && tns.cnt < filecnt) { + if (!XPending(win.env.dpy)) { /* load thumbnails */ - win_set_cursor(&win, CURSOR_WATCH); - gettimeofday(&t0, 0); - - while (tns.cnt < filecnt && !XPending(win.env.dpy)) { + while (mode == MODE_THUMB && tns.cnt < filecnt) { + win_set_cursor(&win, CURSOR_WATCH); if (tns_load(&tns, tns.cnt, &files[tns.cnt], False, False)) 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; - } - } - - if (timo_cursor || timo_redraw || timo_adelay) { - /* check active timeouts */ - gettimeofday(&t0, 0); - timeout = min_int_nz(3, timo_cursor, timo_redraw, timo_adelay); - 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) + if (tns.cnt == filecnt) { redraw(); - } - if (timo_adelay) { - timo_adelay = MAX(0, timo_adelay - timeout); - if (!timo_adelay) { - if ((timo_adelay = img_frame_animate(&img, 0))) - redraw(); + win_set_cursor(&win, CURSOR_ARROW); + } else { + set_timeout(redraw, TO_REDRAW_THUMBS, 0); + check_timeouts(NULL); } } - if ((timo_cursor || timo_redraw || timo_adelay) && - !XPending(win.env.dpy)) - continue; + + /* handle timeouts */ + if (check_timeouts(&timeout)) { + xfd = ConnectionNumber(win.env.dpy); + FD_ZERO(&fds); + FD_SET(xfd, &fds); + if (!select(xfd + 1, &fds, 0, 0, &timeout)) + check_timeouts(NULL); + } } if (!XNextEvent(win.env.dpy, &ev)) { @@ -355,7 +396,7 @@ void run() { break; case ConfigureNotify: if (win_configure(&win, &ev.xconfigure)) { - timo_redraw = TO_WIN_RESIZE; + set_timeout(redraw, TO_REDRAW_RESIZE, 0); if (mode == MODE_IMAGE) img.checkpan = 1; else @@ -366,9 +407,10 @@ void run() { on_keypress(&ev.xkey); break; case MotionNotify: - if (!timo_cursor) + if (mode == MODE_IMAGE) { win_set_cursor(&win, CURSOR_ARROW); - timo_cursor = TO_CURSOR_HIDE; + set_timeout(hide_cursor, TO_CURSOR_HIDE, 1); + } break; } } diff --git a/types.h b/types.h index f19d693..bf8d4e2 100644 --- a/types.h +++ b/types.h @@ -33,9 +33,11 @@ typedef struct { /* timeouts in milliseconds: */ enum { - TO_WIN_RESIZE = 75, - TO_CURSOR_HIDE = 1500, - TO_THUMBS_LOAD = 200 + TO_REDRAW_RESIZE = 75, + TO_REDRAW_THUMBS = 200, + TO_CURSOR_HIDE = 1500 }; +typedef void (*timeout_f)(void); + #endif /* TYPES_H */ diff --git a/util.c b/util.c index 5bed511..0c4574e 100644 --- a/util.c +++ b/util.c @@ -87,19 +87,6 @@ void die(const char* fmt, ...) { exit(1); } -int min_int_nz(int n, ...) { - va_list args; - int i, a, m = 0; - - va_start(args, n); - for (i = 0; i < n; i++) { - if ((a = va_arg(args, int)) && (!m || a < m)) - m = a; - } - va_end(args); - return m; -} - void size_readable(float *size, const char **unit) { const char *units[] = { "", "K", "M", "G" }; int i; diff --git a/util.h b/util.h index a891054..19ebcd7 100644 --- a/util.h +++ b/util.h @@ -33,7 +33,12 @@ #define MSEC_TO_TIMEVAL(t,tv) { \ (tv)->tv_sec = (t) / 1000; \ - (tv)->tv_usec = (t) % 1000 * 1000; \ + (tv)->tv_usec = (t) % 1000 * 1000; \ +} + +#define MSEC_ADD_TO_TIMEVAL(t,tv) { \ + (tv)->tv_sec += (t) / 1000; \ + (tv)->tv_usec += (t) % 1000 * 1000; \ } #ifndef TIMESPEC_TO_TIMEVAL @@ -60,8 +65,6 @@ char* s_strdup(char*); void warn(const char*, ...); void die(const char*, ...); -int min_int_nz(int, ...); - void size_readable(float*, const char**); char* absolute_path(const char*);