Data driven timeout handling
This commit is contained in:
		
							parent
							
								
									391e6e7079
								
							
						
					
					
						commit
						1e84773276
					
				
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| all: sxiv | ||||
| 
 | ||||
| VERSION = git-20110819 | ||||
| VERSION = git-20110902 | ||||
| 
 | ||||
| CC = gcc | ||||
| DESTDIR = | ||||
|  | ||||
							
								
								
									
										25
									
								
								commands.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								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; | ||||
| } | ||||
|  | ||||
							
								
								
									
										180
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										180
									
								
								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; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
							
								
								
									
										8
									
								
								types.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								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 */ | ||||
|  | ||||
							
								
								
									
										13
									
								
								util.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								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; | ||||
|  | ||||
							
								
								
									
										9
									
								
								util.h
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								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*); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Bert
						Bert