[wiki] [sites] [st][patch] add another visual-bell implementation || Avi Halachmi (:avih)

From: <git_AT_suckless.org>
Date: Tue, 16 Oct 2018 22:31:46 +0200

commit 3a82e2aa63c17fb10dfdb98803668ef50cfcd15f
Author: Avi Halachmi (:avih) <avihpit_AT_yahoo.com>
Date: Tue Oct 16 23:27:31 2018 +0300

    [st][patch] add another visual-bell implementation

diff --git a/st.suckless.org/patches/visualbell/index.md b/st.suckless.org/patches/visualbell/index.md
index 7eab792a..e6cb7f2f 100644
--- a/st.suckless.org/patches/visualbell/index.md
+++ b/st.suckless.org/patches/visualbell/index.md
_AT_@ -1,6 +1,12 @@
 visualbell
 ==========
 
+This page contains two unrelated implementations of visual bell which are not
+compatible with eachother. If you have one of them applied, remove it before
+trying the other.
+
+# === Visual bell 1 ===
+
 Description
 -----------
 
_AT_@ -26,3 +32,52 @@ Authors
 * Matthias Schoth - <mschoth_AT_gmail.com>
 * Laslo Hunhold - <dev_AT_frign.de> (git port)
 * Alexis Ben Miloud--Josselin; panpo; alexisbmj+code at protonmail dot com.
+
+# === Visual bell 2 ===
+
+Description
+-----------
+
+Briefly renders a configurable visual indication on terminal bell event.
+
+Notes
+-----
+
+- There are two variants available for download: basic and enhanced.
+- The enhanced version file already includes the basic version in it, and
+ supports the basic options too.
+- Both variants can be applied with either `git am <patch-file>` or
+ ` patch -p1 < <patch-file>`.
+- Visual bell is disabled by default, and can be enabled/configured via
+ `config.h`. If you already have this file, you'll need to add the visual-bell
+ values by copying them from `config.def.h` - which also includes their docs.
+
+### The basic variant supports:
+
+- Invert the whole screen (default).
+- Invert only the outer (border) cells for a less jarring effect.
+- Configuring the flash duration (default: 100ms).
+
+### The enhanced variant:
+
+This version experiments with a more graphical indication, by adding support
+for rendering a filled circle (needs to be chosen at `config.h`), which can be
+configured for:
+
+- Position: any corner/edge, center of the screen, or anything in between.
+- Size: relative to the window width or to the cell width.
+- Colors: base and outline.
+
+The enhanced variant allows, for instance, to render what looks like a LED
+indicator at a tmux status bar, with correct cell height, and can be
+positioned at the side/middle of a top/bottom bar, etc.
+
+Download
+--------
+
+- [st-visualbell2-basic-2018-10-16-30ec9a3.patch](st-visualbell2-basic-2018-10-16-30ec9a3.patch)
+- [st-visualbell2-enhanced-2018-10-16-30ec9a3.patch](st-visualbell2-enhanced-2018-10-16-30ec9a3.patch)
+
+Author
+------
+- Avi Halachmi (:avih) - [https://github.com/avih](https://github.com/avih)
diff --git a/st.suckless.org/patches/visualbell/st-visualbell2-basic-2018-10-16-30ec9a3.patch b/st.suckless.org/patches/visualbell/st-visualbell2-basic-2018-10-16-30ec9a3.patch
new file mode 100644
index 00000000..db922d43
--- /dev/null
+++ b/st.suckless.org/patches/visualbell/st-visualbell2-basic-2018-10-16-30ec9a3.patch
_AT_@ -0,0 +1,204 @@
+From bcc850d57fb4cb6941008fb2808d4d0d373aa5f8 Mon Sep 17 00:00:00 2001
+From: "Avi Halachmi (:avih)" <avihpit_AT_yahoo.com>
+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
+_AT_@ -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
+_AT_@ -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
+_AT_@ -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
+_AT_@ -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 {
+_AT_@ -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);
+
+_AT_@ -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;
+_AT_@ -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)
+ {
+_AT_@ -1617,6 +1646,8 @@ xbell(void)
+ xseturgency(1);
+ if (bellvolume)
+ XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL);
++ if (vbelltimeout)
++ vbellbegin();
+ }
+
+ void
+_AT_@ -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 {
+_AT_@ -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)) {
+_AT_@ -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
+
diff --git a/st.suckless.org/patches/visualbell/st-visualbell2-enhanced-2018-10-16-30ec9a3.patch b/st.suckless.org/patches/visualbell/st-visualbell2-enhanced-2018-10-16-30ec9a3.patch
new file mode 100644
index 00000000..36ef59a9
--- /dev/null
+++ b/st.suckless.org/patches/visualbell/st-visualbell2-enhanced-2018-10-16-30ec9a3.patch
_AT_@ -0,0 +1,308 @@
+From bcc850d57fb4cb6941008fb2808d4d0d373aa5f8 Mon Sep 17 00:00:00 2001
+From: "Avi Halachmi (:avih)" <avihpit_AT_yahoo.com>
+Date: Mon, 15 Oct 2018 01:06:01 +0300
+Subject: [PATCH 1/2] [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
+_AT_@ -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
+_AT_@ -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
+_AT_@ -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
+_AT_@ -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 {
+_AT_@ -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);
+
+_AT_@ -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;
+_AT_@ -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)
+ {
+_AT_@ -1617,6 +1646,8 @@ xbell(void)
+ xseturgency(1);
+ if (bellvolume)
+ XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL);
++ if (vbelltimeout)
++ vbellbegin();
+ }
+
+ void
+_AT_@ -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 {
+_AT_@ -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)) {
+_AT_@ -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
+
+
+From 587d0fdcdcccb601f61de4f6186ae310c8adb0e3 Mon Sep 17 00:00:00 2001
+From: "Avi Halachmi (:avih)" <avihpit_AT_yahoo.com>
+Date: Tue, 16 Oct 2018 16:04:45 +0300
+Subject: [PATCH 2/2] [vbell2] visual bell: experimental circle rendering mode
+
+This commit experiments with alternative rendering of visual bell,
+and as such it's extensively/excessively configurable.
+
+It renders an overlay of a circle with configurable colors (base,
+outline), position and size. Defaults to the center of the window.
+
+Size can be relative to window or chars width, and allows for instance
+to place it at the middle/side of a top/bottom tmux status-bar with
+exact char height to make it look like a flashing LED at the bar, etc.
+---
+ config.def.h | 12 ++++++++++++
+ x.c | 24 +++++++++++++++++++++++-
+ 2 files changed, 35 insertions(+), 1 deletion(-)
+
+diff --git a/config.def.h b/config.def.h
+index 0915ce5..a1c7f24 100644
+--- a/config.def.h
++++ b/config.def.h
+_AT_@ -70,8 +70,20 @@ static int vbelltimeout = 0;
+ * visual bell mode when enabled:
+ * 1: Inverse whole screen
+ * 2: Inverse outer (border) cells
++ * 3: Draw a filled circle.
+ */
+ static int vbellmode = 1;
++/*
++ * for vbellmode == 3 (circle) the following parameters apply:
++ * - base and outline colors (colorname index - see below).
++ * - radius: relative to window width, or if negative: relative to cell-width.
++ * - position: relative to window width/height (0 and 1 are at the edges).
++ */
++static int vbellcolor = 3;
++static int vbellcolor_outline = 1;
++static float vbellradius = 0.03;
++static float vbellx = 0.5;
++static float vbelly = 0.5;
+
+ /* default TERM value */
+ char *termname = "st-256color";
+diff --git a/x.c b/x.c
+index 7e66c6d..eb895d4 100644
+--- a/x.c
++++ b/x.c
+_AT_@ -177,6 +177,8 @@ static int match(uint, uint);
+
+ static void vbellbegin();
+ static int isvbellcell(int x, int y);
++static void xdrawvbell();
++static void xfillcircle(int x, int y, int r, uint color_ix);
+
+ static void run(void);
+ static void usage(void);
+_AT_@ -1554,6 +1556,9 @@ xdrawline(Line line, int x1, int y1, int x2)
+ void
+ xfinishdraw(void)
+ {
++ if (vbellmode == 3 && win.vbellset)
++ xdrawvbell();
++
+ XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
+ win.h, 0, 0);
+ XSetForeground(xw.dpy, dc.gc,
+_AT_@ -1617,6 +1622,22 @@ xseturgency(int add)
+ XFree(h);
+ }
+
++void
++xfillcircle(int x, int y, int r, uint color_ix)
++{
++ XSetForeground(xw.dpy, dc.gc, dc.col[color_ix].pixel);
++ XFillArc(xw.dpy, xw.buf, dc.gc, x - r, y - r, r * 2, r * 2, 0, 360*64);
++}
++
++void
++xdrawvbell() {
++ int r = round(vbellradius * (vbellradius > 0 ? win.w : -win.cw));
++ int x = borderpx + r + vbellx * (win.tw - 2 * r);
++ int y = borderpx + r + vbelly * (win.th - 2 * r);
++ xfillcircle(x, y, r, vbellcolor_outline);
++ xfillcircle(x, y, r / 1.2, vbellcolor); /* 1.2 - an artistic choice */
++}
++
+ int
+ isvbellcell(int x, int y)
+ {
+_AT_@ -1634,7 +1655,8 @@ vbellbegin() {
+ if (win.vbellset) /* already visible, just extend win.lastvbell */
+ return;
+ win.vbellset = 1;
+- tfulldirt();
++ if (vbellmode != 3) /* 3 is an overlay, no need to re-render cells */
++ tfulldirt();
+ draw();
+ XFlush(xw.dpy);
+ }
+--
+2.19.1
+
Received on Tue Oct 16 2018 - 22:31:46 CEST

This archive was generated by hypermail 2.3.0 : Tue Oct 16 2018 - 22:36:25 CEST