auto-sync patch
This commit is contained in:
parent
b35e4f5727
commit
4f44d2d13f
2 changed files with 65 additions and 68 deletions
13
config.h
13
config.h
|
@ -42,9 +42,14 @@ static unsigned int tripleclicktimeout = 600;
|
||||||
/* alt screens */
|
/* alt screens */
|
||||||
int allowaltscreen = 1;
|
int allowaltscreen = 1;
|
||||||
|
|
||||||
/* frames per second st should at maximum draw to the screen */
|
/*
|
||||||
static unsigned int xfps = 120;
|
* draw latency range in ms - from new content/keypress/etc until drawing.
|
||||||
static unsigned int actionfps = 30;
|
* 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
|
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
|
||||||
|
@ -197,8 +202,6 @@ ResourcePref resources[] = {
|
||||||
{ "cursorColor", STRING, &colorname[256] },
|
{ "cursorColor", STRING, &colorname[256] },
|
||||||
{ "termname", STRING, &termname },
|
{ "termname", STRING, &termname },
|
||||||
{ "shell", STRING, &shell },
|
{ "shell", STRING, &shell },
|
||||||
{ "xfps", INTEGER, &xfps },
|
|
||||||
{ "actionfps", INTEGER, &actionfps },
|
|
||||||
{ "blinktimeout", INTEGER, &blinktimeout },
|
{ "blinktimeout", INTEGER, &blinktimeout },
|
||||||
{ "bellvolume", INTEGER, &bellvolume },
|
{ "bellvolume", INTEGER, &bellvolume },
|
||||||
{ "tabspaces", INTEGER, &tabspaces },
|
{ "tabspaces", INTEGER, &tabspaces },
|
||||||
|
|
110
x.c
110
x.c
|
@ -1956,10 +1956,9 @@ run(void)
|
||||||
XEvent ev;
|
XEvent ev;
|
||||||
int w = win.w, h = win.h;
|
int w = win.w, h = win.h;
|
||||||
fd_set rfd;
|
fd_set rfd;
|
||||||
int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
|
int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing;
|
||||||
int ttyfd;
|
struct timespec seltv, *tv, now, lastblink, trigger;
|
||||||
struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
|
double timeout;
|
||||||
long deltatime;
|
|
||||||
|
|
||||||
/* Waiting for window mapping */
|
/* Waiting for window mapping */
|
||||||
do {
|
do {
|
||||||
|
@ -1980,51 +1979,31 @@ run(void)
|
||||||
ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd);
|
ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd);
|
||||||
cresize(w, h);
|
cresize(w, h);
|
||||||
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &last);
|
for (timeout = -1, drawing = 0, lastblink = (struct timespec){0};;) {
|
||||||
lastblink = last;
|
|
||||||
|
|
||||||
for (xev = actionfps;;) {
|
|
||||||
FD_ZERO(&rfd);
|
FD_ZERO(&rfd);
|
||||||
FD_SET(ttyfd, &rfd);
|
FD_SET(ttyfd, &rfd);
|
||||||
FD_SET(xfd, &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 (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
die("select failed: %s\n", strerror(errno));
|
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);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
drawtimeout.tv_sec = 0;
|
|
||||||
drawtimeout.tv_nsec = (1000 * 1E6)/ xfps;
|
|
||||||
tv = &drawtimeout;
|
|
||||||
|
|
||||||
dodraw = 0;
|
if (FD_ISSET(ttyfd, &rfd))
|
||||||
if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
|
ttyread();
|
||||||
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 (dodraw) {
|
xev = 0;
|
||||||
while (XPending(xw.dpy)) {
|
while (XPending(xw.dpy)) {
|
||||||
|
xev = 1;
|
||||||
XNextEvent(xw.dpy, &ev);
|
XNextEvent(xw.dpy, &ev);
|
||||||
if (XFilterEvent(&ev, None))
|
if (XFilterEvent(&ev, None))
|
||||||
continue;
|
continue;
|
||||||
|
@ -2032,30 +2011,45 @@ run(void)
|
||||||
(handler[ev.type])(&ev);
|
(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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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();
|
draw();
|
||||||
XFlush(xw.dpy);
|
XFlush(xw.dpy);
|
||||||
|
drawing = 0;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue