Data driven timeout handling
This commit is contained in:
parent
391e6e7079
commit
1e84773276
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
||||||
all: sxiv
|
all: sxiv
|
||||||
|
|
||||||
VERSION = git-20110819
|
VERSION = git-20110902
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
DESTDIR =
|
DESTDIR =
|
||||||
|
|
25
commands.c
25
commands.c
|
@ -30,6 +30,11 @@
|
||||||
void cleanup();
|
void cleanup();
|
||||||
void remove_file(int, unsigned char);
|
void remove_file(int, unsigned char);
|
||||||
void load_image(int);
|
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 appmode_t mode;
|
||||||
extern img_t img;
|
extern img_t img;
|
||||||
|
@ -39,10 +44,6 @@ extern win_t win;
|
||||||
extern fileinfo_t *files;
|
extern fileinfo_t *files;
|
||||||
extern int filecnt, fileidx;
|
extern int filecnt, fileidx;
|
||||||
|
|
||||||
extern int timo_cursor;
|
|
||||||
extern int timo_redraw;
|
|
||||||
extern int timo_adelay;
|
|
||||||
|
|
||||||
int it_quit(arg_t a) {
|
int it_quit(arg_t a) {
|
||||||
cleanup();
|
cleanup();
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@ -54,12 +55,11 @@ int it_switch_mode(arg_t a) {
|
||||||
tns_init(&tns, filecnt);
|
tns_init(&tns, filecnt);
|
||||||
img_close(&img, 0);
|
img_close(&img, 0);
|
||||||
win_set_cursor(&win, CURSOR_ARROW);
|
win_set_cursor(&win, CURSOR_ARROW);
|
||||||
timo_cursor = 0;
|
reset_timeout(hide_cursor);
|
||||||
tns.sel = fileidx;
|
tns.sel = fileidx;
|
||||||
tns.dirty = 1;
|
tns.dirty = 1;
|
||||||
mode = MODE_THUMB;
|
mode = MODE_THUMB;
|
||||||
} else {
|
} else {
|
||||||
timo_cursor = TO_CURSOR_HIDE;
|
|
||||||
load_image(tns.sel);
|
load_image(tns.sel);
|
||||||
mode = MODE_IMAGE;
|
mode = MODE_IMAGE;
|
||||||
}
|
}
|
||||||
|
@ -68,11 +68,11 @@ int it_switch_mode(arg_t a) {
|
||||||
|
|
||||||
int it_toggle_fullscreen(arg_t a) {
|
int it_toggle_fullscreen(arg_t a) {
|
||||||
win_toggle_fullscreen(&win);
|
win_toggle_fullscreen(&win);
|
||||||
|
set_timeout(redraw, TO_REDRAW_RESIZE, 0);
|
||||||
if (mode == MODE_IMAGE)
|
if (mode == MODE_IMAGE)
|
||||||
img.checkpan = 1;
|
img.checkpan = 1;
|
||||||
else
|
else
|
||||||
tns.dirty = 1;
|
tns.dirty = 1;
|
||||||
timo_redraw = TO_WIN_RESIZE;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,15 +156,18 @@ int i_navigate_frame(arg_t a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int i_toggle_animation(arg_t a) {
|
int i_toggle_animation(arg_t a) {
|
||||||
|
int delay;
|
||||||
|
|
||||||
if (mode != MODE_IMAGE)
|
if (mode != MODE_IMAGE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (img.multi.animate) {
|
if (img.multi.animate) {
|
||||||
timo_adelay = 0;
|
reset_timeout(animate);
|
||||||
img.multi.animate = 0;
|
img.multi.animate = 0;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
timo_adelay = img_frame_animate(&img, 1);
|
delay = img_frame_animate(&img, 1);
|
||||||
|
set_timeout(animate, delay, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,8 +248,8 @@ int i_drag(arg_t a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
win_set_cursor(&win, CURSOR_ARROW);
|
win_set_cursor(&win, CURSOR_ARROW);
|
||||||
timo_cursor = TO_CURSOR_HIDE;
|
set_timeout(hide_cursor, TO_CURSOR_HIDE, 1);
|
||||||
timo_redraw = 0;
|
reset_timeout(redraw);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
180
main.c
180
main.c
|
@ -41,6 +41,17 @@ enum {
|
||||||
FNAME_CNT = 1024
|
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;
|
appmode_t mode;
|
||||||
img_t img;
|
img_t img;
|
||||||
tns_t tns;
|
tns_t tns;
|
||||||
|
@ -52,9 +63,11 @@ size_t filesize;
|
||||||
|
|
||||||
char win_title[TITLE_LEN];
|
char win_title[TITLE_LEN];
|
||||||
|
|
||||||
int timo_cursor;
|
timeout_t timeouts[] = {
|
||||||
int timo_redraw;
|
{ { 0, 0 }, False, redraw },
|
||||||
int timo_adelay; /* multi-frame animation delay time */
|
{ { 0, 0 }, False, hide_cursor },
|
||||||
|
{ { 0, 0 }, False, animate }
|
||||||
|
};
|
||||||
|
|
||||||
void cleanup() {
|
void cleanup() {
|
||||||
static int in = 0;
|
static int in = 0;
|
||||||
|
@ -120,6 +133,54 @@ void remove_file(int n, unsigned char silent) {
|
||||||
tns.cnt--;
|
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) {
|
void load_image(int new) {
|
||||||
struct stat fstats;
|
struct stat fstats;
|
||||||
|
|
||||||
|
@ -144,9 +205,9 @@ void load_image(int new) {
|
||||||
|
|
||||||
if (img.multi.cnt) {
|
if (img.multi.cnt) {
|
||||||
if (img.multi.animate)
|
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
|
else
|
||||||
timo_adelay = 0;
|
reset_timeout(animate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,15 +247,31 @@ void update_title() {
|
||||||
void redraw() {
|
void redraw() {
|
||||||
if (mode == MODE_IMAGE) {
|
if (mode == MODE_IMAGE) {
|
||||||
img_render(&img, &win);
|
img_render(&img, &win);
|
||||||
if (timo_cursor)
|
if (img.multi.animate) {
|
||||||
win_set_cursor(&win, CURSOR_ARROW);
|
|
||||||
else
|
|
||||||
win_set_cursor(&win, CURSOR_NONE);
|
win_set_cursor(&win, CURSOR_NONE);
|
||||||
|
} else {
|
||||||
|
win_set_cursor(&win, CURSOR_ARROW);
|
||||||
|
set_timeout(hide_cursor, TO_CURSOR_HIDE, 1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tns_render(&tns, &win);
|
tns_render(&tns, &win);
|
||||||
}
|
}
|
||||||
update_title();
|
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) {
|
Bool keymask(const keymap_t *k, unsigned int state) {
|
||||||
|
@ -233,7 +310,7 @@ void on_buttonpress(XButtonEvent *bev) {
|
||||||
|
|
||||||
if (mode == MODE_IMAGE) {
|
if (mode == MODE_IMAGE) {
|
||||||
win_set_cursor(&win, CURSOR_ARROW);
|
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++) {
|
for (i = 0; i < LEN(buttons); i++) {
|
||||||
if (buttons[i].button == bev->button &&
|
if (buttons[i].button == bev->button &&
|
||||||
|
@ -252,7 +329,7 @@ void on_buttonpress(XButtonEvent *bev) {
|
||||||
if (sel == tns.sel) {
|
if (sel == tns.sel) {
|
||||||
load_image(tns.sel);
|
load_image(tns.sel);
|
||||||
mode = MODE_IMAGE;
|
mode = MODE_IMAGE;
|
||||||
timo_cursor = TO_CURSOR_HIDE;
|
set_timeout(hide_cursor, TO_CURSOR_HIDE, 1);
|
||||||
} else {
|
} else {
|
||||||
tns_highlight(&tns, &win, tns.sel, False);
|
tns_highlight(&tns, &win, tns.sel, False);
|
||||||
tns_highlight(&tns, &win, sel, True);
|
tns_highlight(&tns, &win, sel, True);
|
||||||
|
@ -272,75 +349,39 @@ void on_buttonpress(XButtonEvent *bev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
int xfd, timeout;
|
int xfd;
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
struct timeval tt, t0, t1;
|
struct timeval timeout;
|
||||||
XEvent ev;
|
XEvent ev;
|
||||||
|
|
||||||
timo_cursor = mode == MODE_IMAGE ? TO_CURSOR_HIDE : 0;
|
|
||||||
|
|
||||||
redraw();
|
redraw();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (mode == MODE_THUMB && tns.cnt < filecnt) {
|
if (!XPending(win.env.dpy)) {
|
||||||
/* load thumbnails */
|
/* load thumbnails */
|
||||||
win_set_cursor(&win, CURSOR_WATCH);
|
while (mode == MODE_THUMB && tns.cnt < filecnt) {
|
||||||
gettimeofday(&t0, 0);
|
win_set_cursor(&win, CURSOR_WATCH);
|
||||||
|
|
||||||
while (tns.cnt < filecnt && !XPending(win.env.dpy)) {
|
|
||||||
if (tns_load(&tns, tns.cnt, &files[tns.cnt], False, False))
|
if (tns_load(&tns, tns.cnt, &files[tns.cnt], False, False))
|
||||||
tns.cnt++;
|
tns.cnt++;
|
||||||
else
|
else
|
||||||
remove_file(tns.cnt, 0);
|
remove_file(tns.cnt, 0);
|
||||||
gettimeofday(&t1, 0);
|
if (tns.cnt == filecnt) {
|
||||||
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)
|
|
||||||
redraw();
|
redraw();
|
||||||
}
|
win_set_cursor(&win, CURSOR_ARROW);
|
||||||
if (timo_adelay) {
|
} else {
|
||||||
timo_adelay = MAX(0, timo_adelay - timeout);
|
set_timeout(redraw, TO_REDRAW_THUMBS, 0);
|
||||||
if (!timo_adelay) {
|
check_timeouts(NULL);
|
||||||
if ((timo_adelay = img_frame_animate(&img, 0)))
|
|
||||||
redraw();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((timo_cursor || timo_redraw || timo_adelay) &&
|
|
||||||
!XPending(win.env.dpy))
|
/* handle timeouts */
|
||||||
continue;
|
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)) {
|
if (!XNextEvent(win.env.dpy, &ev)) {
|
||||||
|
@ -355,7 +396,7 @@ void run() {
|
||||||
break;
|
break;
|
||||||
case ConfigureNotify:
|
case ConfigureNotify:
|
||||||
if (win_configure(&win, &ev.xconfigure)) {
|
if (win_configure(&win, &ev.xconfigure)) {
|
||||||
timo_redraw = TO_WIN_RESIZE;
|
set_timeout(redraw, TO_REDRAW_RESIZE, 0);
|
||||||
if (mode == MODE_IMAGE)
|
if (mode == MODE_IMAGE)
|
||||||
img.checkpan = 1;
|
img.checkpan = 1;
|
||||||
else
|
else
|
||||||
|
@ -366,9 +407,10 @@ void run() {
|
||||||
on_keypress(&ev.xkey);
|
on_keypress(&ev.xkey);
|
||||||
break;
|
break;
|
||||||
case MotionNotify:
|
case MotionNotify:
|
||||||
if (!timo_cursor)
|
if (mode == MODE_IMAGE) {
|
||||||
win_set_cursor(&win, CURSOR_ARROW);
|
win_set_cursor(&win, CURSOR_ARROW);
|
||||||
timo_cursor = TO_CURSOR_HIDE;
|
set_timeout(hide_cursor, TO_CURSOR_HIDE, 1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
8
types.h
8
types.h
|
@ -33,9 +33,11 @@ typedef struct {
|
||||||
|
|
||||||
/* timeouts in milliseconds: */
|
/* timeouts in milliseconds: */
|
||||||
enum {
|
enum {
|
||||||
TO_WIN_RESIZE = 75,
|
TO_REDRAW_RESIZE = 75,
|
||||||
TO_CURSOR_HIDE = 1500,
|
TO_REDRAW_THUMBS = 200,
|
||||||
TO_THUMBS_LOAD = 200
|
TO_CURSOR_HIDE = 1500
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef void (*timeout_f)(void);
|
||||||
|
|
||||||
#endif /* TYPES_H */
|
#endif /* TYPES_H */
|
||||||
|
|
13
util.c
13
util.c
|
@ -87,19 +87,6 @@ void die(const char* fmt, ...) {
|
||||||
exit(1);
|
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) {
|
void size_readable(float *size, const char **unit) {
|
||||||
const char *units[] = { "", "K", "M", "G" };
|
const char *units[] = { "", "K", "M", "G" };
|
||||||
int i;
|
int i;
|
||||||
|
|
9
util.h
9
util.h
|
@ -33,7 +33,12 @@
|
||||||
|
|
||||||
#define MSEC_TO_TIMEVAL(t,tv) { \
|
#define MSEC_TO_TIMEVAL(t,tv) { \
|
||||||
(tv)->tv_sec = (t) / 1000; \
|
(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
|
#ifndef TIMESPEC_TO_TIMEVAL
|
||||||
|
@ -60,8 +65,6 @@ char* s_strdup(char*);
|
||||||
void warn(const char*, ...);
|
void warn(const char*, ...);
|
||||||
void die(const char*, ...);
|
void die(const char*, ...);
|
||||||
|
|
||||||
int min_int_nz(int, ...);
|
|
||||||
|
|
||||||
void size_readable(float*, const char**);
|
void size_readable(float*, const char**);
|
||||||
|
|
||||||
char* absolute_path(const char*);
|
char* absolute_path(const char*);
|
||||||
|
|
Loading…
Reference in New Issue