auto-sync patch
This commit is contained in:
		
							
								
								
									
										13
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								config.h
									
									
									
									
									
								
							@@ -42,9 +42,14 @@ static unsigned int tripleclicktimeout = 600;
 | 
			
		||||
/* alt screens */
 | 
			
		||||
int allowaltscreen = 1;
 | 
			
		||||
 | 
			
		||||
/* frames per second st should at maximum draw to the screen */
 | 
			
		||||
static unsigned int xfps = 120;
 | 
			
		||||
static unsigned int actionfps = 30;
 | 
			
		||||
/*
 | 
			
		||||
 * draw latency range in ms - from new content/keypress/etc until drawing.
 | 
			
		||||
 * within this range, st draws when content stops arriving (idle). mostly it's
 | 
			
		||||
 * near minlatency, but it waits longer for slow updates to avoid partial draw.
 | 
			
		||||
 * low minlatency will tear/flicker more, as it can "detect" idle too early.
 | 
			
		||||
 */
 | 
			
		||||
static double minlatency = 8;
 | 
			
		||||
static double maxlatency = 33;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * blinking timeout (set to 0 to disable blinking) for the terminal blinking
 | 
			
		||||
@@ -197,8 +202,6 @@ ResourcePref resources[] = {
 | 
			
		||||
		{ "cursorColor",  STRING,  &colorname[256] },
 | 
			
		||||
		{ "termname",     STRING,  &termname },
 | 
			
		||||
		{ "shell",        STRING,  &shell },
 | 
			
		||||
		{ "xfps",         INTEGER, &xfps },
 | 
			
		||||
		{ "actionfps",    INTEGER, &actionfps },
 | 
			
		||||
		{ "blinktimeout", INTEGER, &blinktimeout },
 | 
			
		||||
		{ "bellvolume",   INTEGER, &bellvolume },
 | 
			
		||||
		{ "tabspaces",    INTEGER, &tabspaces },
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										120
									
								
								x.c
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								x.c
									
									
									
									
									
								
							@@ -1956,10 +1956,9 @@ run(void)
 | 
			
		||||
	XEvent ev;
 | 
			
		||||
	int w = win.w, h = win.h;
 | 
			
		||||
	fd_set rfd;
 | 
			
		||||
	int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
 | 
			
		||||
	int ttyfd;
 | 
			
		||||
	struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
 | 
			
		||||
	long deltatime;
 | 
			
		||||
	int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing;
 | 
			
		||||
	struct timespec seltv, *tv, now, lastblink, trigger;
 | 
			
		||||
	double timeout;
 | 
			
		||||
 | 
			
		||||
	/* Waiting for window mapping */
 | 
			
		||||
	do {
 | 
			
		||||
@@ -1980,82 +1979,77 @@ run(void)
 | 
			
		||||
	ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd);
 | 
			
		||||
	cresize(w, h);
 | 
			
		||||
 | 
			
		||||
	clock_gettime(CLOCK_MONOTONIC, &last);
 | 
			
		||||
	lastblink = last;
 | 
			
		||||
 | 
			
		||||
	for (xev = actionfps;;) {
 | 
			
		||||
	for (timeout = -1, drawing = 0, lastblink = (struct timespec){0};;) {
 | 
			
		||||
		FD_ZERO(&rfd);
 | 
			
		||||
		FD_SET(ttyfd, &rfd);
 | 
			
		||||
		FD_SET(xfd, &rfd);
 | 
			
		||||
 | 
			
		||||
		if (XPending(xw.dpy))
 | 
			
		||||
			timeout = 0;  /* existing events might not set xfd */
 | 
			
		||||
 | 
			
		||||
		seltv.tv_sec = timeout / 1E3;
 | 
			
		||||
		seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec);
 | 
			
		||||
		tv = timeout >= 0 ? &seltv : NULL;
 | 
			
		||||
 | 
			
		||||
		if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
 | 
			
		||||
			if (errno == EINTR)
 | 
			
		||||
				continue;
 | 
			
		||||
			die("select failed: %s\n", strerror(errno));
 | 
			
		||||
		}
 | 
			
		||||
		if (FD_ISSET(ttyfd, &rfd)) {
 | 
			
		||||
			ttyread();
 | 
			
		||||
			if (blinktimeout) {
 | 
			
		||||
				blinkset = tattrset(ATTR_BLINK);
 | 
			
		||||
				if (!blinkset)
 | 
			
		||||
					MODBIT(win.mode, 0, MODE_BLINK);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (FD_ISSET(xfd, &rfd))
 | 
			
		||||
			xev = actionfps;
 | 
			
		||||
 | 
			
		||||
		clock_gettime(CLOCK_MONOTONIC, &now);
 | 
			
		||||
		drawtimeout.tv_sec = 0;
 | 
			
		||||
		drawtimeout.tv_nsec =  (1000 * 1E6)/ xfps;
 | 
			
		||||
		tv = &drawtimeout;
 | 
			
		||||
 | 
			
		||||
		dodraw = 0;
 | 
			
		||||
		if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
 | 
			
		||||
			tsetdirtattr(ATTR_BLINK);
 | 
			
		||||
			win.mode ^= MODE_BLINK;
 | 
			
		||||
			lastblink = now;
 | 
			
		||||
			dodraw = 1;
 | 
			
		||||
		}
 | 
			
		||||
		deltatime = TIMEDIFF(now, last);
 | 
			
		||||
		if (deltatime > 1000 / (xev ? xfps : actionfps)) {
 | 
			
		||||
			dodraw = 1;
 | 
			
		||||
			last = now;
 | 
			
		||||
		if (FD_ISSET(ttyfd, &rfd))
 | 
			
		||||
			ttyread();
 | 
			
		||||
 | 
			
		||||
		xev = 0;
 | 
			
		||||
		while (XPending(xw.dpy)) {
 | 
			
		||||
			xev = 1;
 | 
			
		||||
			XNextEvent(xw.dpy, &ev);
 | 
			
		||||
			if (XFilterEvent(&ev, None))
 | 
			
		||||
				continue;
 | 
			
		||||
			if (handler[ev.type])
 | 
			
		||||
				(handler[ev.type])(&ev);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (dodraw) {
 | 
			
		||||
			while (XPending(xw.dpy)) {
 | 
			
		||||
				XNextEvent(xw.dpy, &ev);
 | 
			
		||||
				if (XFilterEvent(&ev, None))
 | 
			
		||||
					continue;
 | 
			
		||||
				if (handler[ev.type])
 | 
			
		||||
					(handler[ev.type])(&ev);
 | 
			
		||||
		/*
 | 
			
		||||
		 * To reduce flicker and tearing, when new content or event
 | 
			
		||||
		 * triggers drawing, we first wait a bit to ensure we got
 | 
			
		||||
		 * everything, and if nothing new arrives - we draw.
 | 
			
		||||
		 * We start with trying to wait minlatency ms. If more content
 | 
			
		||||
		 * arrives sooner, we retry with shorter and shorter preiods,
 | 
			
		||||
		 * and eventually draw even without idle after maxlatency ms.
 | 
			
		||||
		 * Typically this results in low latency while interacting,
 | 
			
		||||
		 * maximum latency intervals during `cat huge.txt`, and perfect
 | 
			
		||||
		 * sync with periodic updates from animations/key-repeats/etc.
 | 
			
		||||
		 */
 | 
			
		||||
		if (FD_ISSET(ttyfd, &rfd) || xev) {
 | 
			
		||||
			if (!drawing) {
 | 
			
		||||
				trigger = now;
 | 
			
		||||
				drawing = 1;
 | 
			
		||||
			}
 | 
			
		||||
			timeout = (maxlatency - TIMEDIFF(now, trigger)) \
 | 
			
		||||
			          / maxlatency * minlatency;
 | 
			
		||||
			if (timeout > 0)
 | 
			
		||||
				continue;  /* we have time, try to find idle */
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
			draw();
 | 
			
		||||
			XFlush(xw.dpy);
 | 
			
		||||
 | 
			
		||||
			if (xev && !FD_ISSET(xfd, &rfd))
 | 
			
		||||
				xev--;
 | 
			
		||||
			if (!FD_ISSET(ttyfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
 | 
			
		||||
				if (blinkset) {
 | 
			
		||||
					if (TIMEDIFF(now, lastblink) \
 | 
			
		||||
							> blinktimeout) {
 | 
			
		||||
						drawtimeout.tv_nsec = 1000;
 | 
			
		||||
					} else {
 | 
			
		||||
						drawtimeout.tv_nsec = (1E6 * \
 | 
			
		||||
							(blinktimeout - \
 | 
			
		||||
							TIMEDIFF(now,
 | 
			
		||||
								lastblink)));
 | 
			
		||||
					}
 | 
			
		||||
					drawtimeout.tv_sec = \
 | 
			
		||||
					    drawtimeout.tv_nsec / 1E9;
 | 
			
		||||
					drawtimeout.tv_nsec %= (long)1E9;
 | 
			
		||||
				} else {
 | 
			
		||||
					tv = NULL;
 | 
			
		||||
				}
 | 
			
		||||
		/* idle detected or maxlatency exhausted -> draw */
 | 
			
		||||
		timeout = -1;
 | 
			
		||||
		if (blinktimeout && tattrset(ATTR_BLINK)) {
 | 
			
		||||
			timeout = blinktimeout - TIMEDIFF(now, lastblink);
 | 
			
		||||
			if (timeout <= 0) {
 | 
			
		||||
				if (-timeout > blinktimeout) /* start visible */
 | 
			
		||||
					win.mode |= MODE_BLINK;
 | 
			
		||||
				win.mode ^= MODE_BLINK;
 | 
			
		||||
				tsetdirtattr(ATTR_BLINK);
 | 
			
		||||
				lastblink = now;
 | 
			
		||||
				timeout = blinktimeout;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		draw();
 | 
			
		||||
		XFlush(xw.dpy);
 | 
			
		||||
		drawing = 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user