From bcc850d57fb4cb6941008fb2808d4d0d373aa5f8 Mon Sep 17 00:00:00 2001 From: "Avi Halachmi (:avih)" Date: Mon, 15 Oct 2018 01:06:01 +0300 Subject: [PATCH] [vbell2] add visual bell with two rendering modes - Inverse the whole terminal - "standard" visual-bell, a bit jarring. - Inverse outer (border) cells - much less jarring, yet plenty visible. Note: blink used a timeout of 1us after drawing, probably to re-calculate the timeout without being affected by draw speed. This was changed to 1ms for code simplicity, and should be inconsequential. --- config.def.h | 11 ++++++++ st.c | 1 - st.h | 1 + x.c | 77 +++++++++++++++++++++++++++++++++++++++------------- 4 files changed, 70 insertions(+), 20 deletions(-) diff --git a/config.def.h b/config.def.h index 823e79f..0915ce5 100644 --- a/config.def.h +++ b/config.def.h @@ -62,6 +62,17 @@ static unsigned int cursorthickness = 2; */ static int bellvolume = 0; +/* + * visual-bell timeout (set to 0 to disable visual-bell). + */ +static int vbelltimeout = 0; +/* + * visual bell mode when enabled: + * 1: Inverse whole screen + * 2: Inverse outer (border) cells + */ +static int vbellmode = 1; + /* default TERM value */ char *termname = "st-256color"; diff --git a/st.c b/st.c index 46cf2da..1229479 100644 --- a/st.c +++ b/st.c @@ -193,7 +193,6 @@ static void tsetscroll(int, int); static void tswapscreen(void); static void tsetmode(int, int, int *, int); static int twrite(const char *, int, int); -static void tfulldirt(void); static void tcontrolcode(uchar ); static void tdectest(char ); static void tdefutf8(char); diff --git a/st.h b/st.h index 38c61c4..619d716 100644 --- a/st.h +++ b/st.h @@ -89,6 +89,7 @@ int tattrset(int); void tnew(int, int); void tresize(int, int); void tsetdirtattr(int); +void tfulldirt(); void ttyhangup(void); int ttynew(char *, char *, char *, char **); size_t ttyread(void); diff --git a/x.c b/x.c index 00cb6b1..7e66c6d 100644 --- a/x.c +++ b/x.c @@ -82,6 +82,8 @@ typedef struct { int cw; /* char width */ int mode; /* window state/mode flags */ int cursor; /* cursor style */ + int vbellset; /* 1 during visual bell, 0 otherwise */ + struct timespec lastvbell; } TermWindow; typedef struct { @@ -173,6 +175,9 @@ static void mousereport(XEvent *); static char *kmap(KeySym, uint); static int match(uint, uint); +static void vbellbegin(); +static int isvbellcell(int x, int y); + static void run(void); static void usage(void); @@ -1528,6 +1533,8 @@ xdrawline(Line line, int x1, int y1, int x2) continue; if (selected(x, y1)) new.mode ^= ATTR_REVERSE; + if (win.vbellset && isvbellcell(x, y1)) + new.mode ^= ATTR_REVERSE; if (i > 0 && ATTRCMP(base, new)) { xdrawglyphfontspecs(specs, base, i, ox, y1); specs += i; @@ -1610,6 +1617,28 @@ xseturgency(int add) XFree(h); } +int +isvbellcell(int x, int y) +{ + if (vbellmode == 1) + return 1; + if (vbellmode == 2) + return y == 0 || y == win.th / win.ch - 1 || + x == 0 || x == win.tw / win.cw - 1; + return 0; +} + +void +vbellbegin() { + clock_gettime(CLOCK_MONOTONIC, &win.lastvbell); + if (win.vbellset) /* already visible, just extend win.lastvbell */ + return; + win.vbellset = 1; + tfulldirt(); + draw(); + XFlush(xw.dpy); +} + void xbell(void) { @@ -1617,6 +1646,8 @@ xbell(void) xseturgency(1); if (bellvolume) XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); + if (vbelltimeout) + vbellbegin(); } void @@ -1770,7 +1801,7 @@ run(void) int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0; int ttyfd; struct timespec drawtimeout, *tv = NULL, now, last, lastblink; - long deltatime; + long deltatime, to_ms, remain; /* Waiting for window mapping */ do { @@ -1822,11 +1853,28 @@ run(void) tv = &drawtimeout; dodraw = 0; - if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) { - tsetdirtattr(ATTR_BLINK); - win.mode ^= MODE_BLINK; - lastblink = now; - dodraw = 1; + to_ms = -1; /* timeout in ms, indefinite if negative */ + if (blinkset) { + remain = blinktimeout - TIMEDIFF(now, lastblink); + if (remain <= 0) { + dodraw = 1; + remain = 1; /* draw, wait 1ms, and re-calc */ + tsetdirtattr(ATTR_BLINK); + win.mode ^= MODE_BLINK; + lastblink = now; + } + to_ms = remain; + } + if (win.vbellset) { + remain = vbelltimeout - TIMEDIFF(now, win.lastvbell); + if (remain <= 0) { + dodraw = 1; + remain = -1; /* draw (clear), and that's it */ + tfulldirt(); + win.vbellset = 0; + } + if (remain >= 0 && (to_ms < 0 || remain < to_ms)) + to_ms = remain; } deltatime = TIMEDIFF(now, last); if (deltatime > 1000 / (xev ? xfps : actionfps)) { @@ -1849,19 +1897,10 @@ run(void) 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; + if (to_ms >= 0) { + static const long k = 1E3, m = 1E6; + drawtimeout.tv_sec = to_ms / k; + drawtimeout.tv_nsec = (to_ms % k) * m; } else { tv = NULL; } -- 2.19.1