some patches and configuration for st terminal emulator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

st-boxdraw_v2-0.8.2.diff 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. From 318ae7fe1bd614cb937c8f43d855a1c2e8e93fd4 Mon Sep 17 00:00:00 2001
  2. From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
  3. Date: Wed, 26 Dec 2018 14:51:45 +0200
  4. Subject: [PATCH] boxdraw_v2: custom render lines/blocks/braille for perfect
  5. alignment
  6. It seems impossible to ensure that blocks and line drawing glyphs
  7. align without visible gaps for all combinations of arbitrary font,
  8. size and width/height scale factor.
  9. This commit adds options to render most of the lines/blocks and
  10. braille codepoints without using the font such that they align
  11. perfectly regardless of font, size or other configuration values.
  12. Supported codepoints are U+2500 - U+259F except dashes/diagonals,
  13. and U28XX.
  14. The lines/blocks data is stored as 16-bit values at boxdraw_data.h
  15. boxdraw/braille are independent, disabled by default at config[.def].h
  16. ---
  17. Makefile | 3 +-
  18. boxdraw.c | 194 ++++++++++++++++++++++++++++++++++++++++++++
  19. boxdraw_data.h | 214 +++++++++++++++++++++++++++++++++++++++++++++++++
  20. config.def.h | 12 +++
  21. st.c | 3 +
  22. st.h | 10 +++
  23. x.c | 21 +++--
  24. 7 files changed, 451 insertions(+), 6 deletions(-)
  25. create mode 100644 boxdraw.c
  26. create mode 100644 boxdraw_data.h
  27. diff --git a/Makefile b/Makefile
  28. index 470ac86..6dfa212 100644
  29. --- a/Makefile
  30. +++ b/Makefile
  31. @@ -4,7 +4,7 @@
  32. include config.mk
  33. -SRC = st.c x.c
  34. +SRC = st.c x.c boxdraw.c
  35. OBJ = $(SRC:.c=.o)
  36. all: options st
  37. @@ -23,6 +23,7 @@ config.h:
  38. st.o: config.h st.h win.h
  39. x.o: arg.h config.h st.h win.h
  40. +boxdraw.o: config.h st.h boxdraw_data.h
  41. $(OBJ): config.h config.mk
  42. diff --git a/boxdraw.c b/boxdraw.c
  43. new file mode 100644
  44. index 0000000..28a92d0
  45. --- /dev/null
  46. +++ b/boxdraw.c
  47. @@ -0,0 +1,194 @@
  48. +/*
  49. + * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
  50. + * MIT/X Consortium License
  51. + */
  52. +
  53. +#include <X11/Xft/Xft.h>
  54. +#include "st.h"
  55. +#include "boxdraw_data.h"
  56. +
  57. +/* Rounded non-negative integers division of n / d */
  58. +#define DIV(n, d) (((n) + (d) / 2) / (d))
  59. +
  60. +static Display *xdpy;
  61. +static Colormap xcmap;
  62. +static XftDraw *xd;
  63. +static Visual *xvis;
  64. +
  65. +static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort);
  66. +static void drawboxlines(int, int, int, int, XftColor *, ushort);
  67. +
  68. +/* public API */
  69. +
  70. +void
  71. +boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis)
  72. +{
  73. + xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis;
  74. +}
  75. +
  76. +int
  77. +isboxdraw(Rune u)
  78. +{
  79. + Rune block = u & ~0xff;
  80. + return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) ||
  81. + (boxdraw_braille && block == 0x2800);
  82. +}
  83. +
  84. +/* the "index" is actually the entire shape data encoded as ushort */
  85. +ushort
  86. +boxdrawindex(const Glyph *g)
  87. +{
  88. + if (boxdraw_braille && (g->u & ~0xff) == 0x2800)
  89. + return BRL | (uint8_t)g->u;
  90. + if (boxdraw_bold && (g->mode & ATTR_BOLD))
  91. + return BDB | boxdata[(uint8_t)g->u];
  92. + return boxdata[(uint8_t)g->u];
  93. +}
  94. +
  95. +void
  96. +drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg,
  97. + const XftGlyphFontSpec *specs, int len)
  98. +{
  99. + for ( ; len-- > 0; x += cw, specs++)
  100. + drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph);
  101. +}
  102. +
  103. +/* implementation */
  104. +
  105. +void
  106. +drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd)
  107. +{
  108. + ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */
  109. + if (bd & (BDL | BDA)) {
  110. + /* lines (light/double/heavy/arcs) */
  111. + drawboxlines(x, y, w, h, fg, bd);
  112. +
  113. + } else if (cat == BBD) {
  114. + /* lower (8-X)/8 block */
  115. + int d = DIV((uint8_t)bd * h, 8);
  116. + XftDrawRect(xd, fg, x, y + d, w, h - d);
  117. +
  118. + } else if (cat == BBU) {
  119. + /* upper X/8 block */
  120. + XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8));
  121. +
  122. + } else if (cat == BBL) {
  123. + /* left X/8 block */
  124. + XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h);
  125. +
  126. + } else if (cat == BBR) {
  127. + /* right (8-X)/8 block */
  128. + int d = DIV((uint8_t)bd * w, 8);
  129. + XftDrawRect(xd, fg, x + d, y, w - d, h);
  130. +
  131. + } else if (cat == BBQ) {
  132. + /* Quadrants */
  133. + int w2 = DIV(w, 2), h2 = DIV(h, 2);
  134. + if (bd & TL)
  135. + XftDrawRect(xd, fg, x, y, w2, h2);
  136. + if (bd & TR)
  137. + XftDrawRect(xd, fg, x + w2, y, w - w2, h2);
  138. + if (bd & BL)
  139. + XftDrawRect(xd, fg, x, y + h2, w2, h - h2);
  140. + if (bd & BR)
  141. + XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2);
  142. +
  143. + } else if (bd & BBS) {
  144. + /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */
  145. + int d = (uint8_t)bd;
  146. + XftColor xfc;
  147. + XRenderColor xrc = { .alpha = 0xffff };
  148. +
  149. + xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4);
  150. + xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4);
  151. + xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4);
  152. +
  153. + XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc);
  154. + XftDrawRect(xd, &xfc, x, y, w, h);
  155. + XftColorFree(xdpy, xvis, xcmap, &xfc);
  156. +
  157. + } else if (cat == BRL) {
  158. + /* braille, each data bit corresponds to one dot at 2x4 grid */
  159. + int w1 = DIV(w, 2);
  160. + int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4);
  161. +
  162. + if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1);
  163. + if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1);
  164. + if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2);
  165. + if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1);
  166. + if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1);
  167. + if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2);
  168. + if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3);
  169. + if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3);
  170. +
  171. + }
  172. +}
  173. +
  174. +void
  175. +drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd)
  176. +{
  177. + /* s: stem thickness. width/8 roughly matches underscore thickness. */
  178. + /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */
  179. + /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */
  180. + int mwh = MIN(w, h);
  181. + int base_s = MAX(1, DIV(mwh, 8));
  182. + int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */
  183. + int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s;
  184. + int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2);
  185. + /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */
  186. + /* The base length (per direction till edge) includes this square. */
  187. +
  188. + int light = bd & (LL | LU | LR | LD);
  189. + int double_ = bd & (DL | DU | DR | DD);
  190. +
  191. + if (light) {
  192. + /* d: additional (negative) length to not-draw the center */
  193. + /* texel - at arcs and avoid drawing inside (some) doubles */
  194. + int arc = bd & BDA;
  195. + int multi_light = light & (light - 1);
  196. + int multi_double = double_ & (double_ - 1);
  197. + /* light crosses double only at DH+LV, DV+LH (ref. shapes) */
  198. + int d = arc || (multi_double && !multi_light) ? -s : 0;
  199. +
  200. + if (bd & LL)
  201. + XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s);
  202. + if (bd & LU)
  203. + XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d);
  204. + if (bd & LR)
  205. + XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s);
  206. + if (bd & LD)
  207. + XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d);
  208. + }
  209. +
  210. + /* double lines - also align with light to form heavy when combined */
  211. + if (double_) {
  212. + /*
  213. + * going clockwise, for each double-ray: p is additional length
  214. + * to the single-ray nearer to the previous direction, and n to
  215. + * the next. p and n adjust from the base length to lengths
  216. + * which consider other doubles - shorter to avoid intersections
  217. + * (p, n), or longer to draw the far-corner texel (n).
  218. + */
  219. + int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD;
  220. + if (dl) {
  221. + int p = dd ? -s : 0, n = du ? -s : dd ? s : 0;
  222. + XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s);
  223. + XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s);
  224. + }
  225. + if (du) {
  226. + int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0;
  227. + XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p);
  228. + XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n);
  229. + }
  230. + if (dr) {
  231. + int p = du ? -s : 0, n = dd ? -s : du ? s : 0;
  232. + XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s);
  233. + XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s);
  234. + }
  235. + if (dd) {
  236. + int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0;
  237. + XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p);
  238. + XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n);
  239. + }
  240. + }
  241. +}
  242. diff --git a/boxdraw_data.h b/boxdraw_data.h
  243. new file mode 100644
  244. index 0000000..7890500
  245. --- /dev/null
  246. +++ b/boxdraw_data.h
  247. @@ -0,0 +1,214 @@
  248. +/*
  249. + * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
  250. + * MIT/X Consortium License
  251. + */
  252. +
  253. +/*
  254. + * U+25XX codepoints data
  255. + *
  256. + * References:
  257. + * http://www.unicode.org/charts/PDF/U2500.pdf
  258. + * http://www.unicode.org/charts/PDF/U2580.pdf
  259. + *
  260. + * Test page:
  261. + * https://github.com/GNOME/vte/blob/master/doc/boxes.txt
  262. + */
  263. +
  264. +/* Each shape is encoded as 16-bits. Higher bits are category, lower are data */
  265. +/* Categories (mutually exclusive except BDB): */
  266. +/* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */
  267. +#define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */
  268. +#define BDA (1<<9) /* Box Draw Arc (light) */
  269. +
  270. +#define BBD (1<<10) /* Box Block Down (lower) X/8 */
  271. +#define BBL (2<<10) /* Box Block Left X/8 */
  272. +#define BBU (3<<10) /* Box Block Upper X/8 */
  273. +#define BBR (4<<10) /* Box Block Right X/8 */
  274. +#define BBQ (5<<10) /* Box Block Quadrants */
  275. +#define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */
  276. +
  277. +#define BBS (1<<14) /* Box Block Shades */
  278. +#define BDB (1<<15) /* Box Draw is Bold */
  279. +
  280. +/* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */
  281. +/* Heavy is light+double (literally drawing light+double align to form heavy) */
  282. +#define LL (1<<0)
  283. +#define LU (1<<1)
  284. +#define LR (1<<2)
  285. +#define LD (1<<3)
  286. +#define LH (LL+LR)
  287. +#define LV (LU+LD)
  288. +
  289. +#define DL (1<<4)
  290. +#define DU (1<<5)
  291. +#define DR (1<<6)
  292. +#define DD (1<<7)
  293. +#define DH (DL+DR)
  294. +#define DV (DU+DD)
  295. +
  296. +#define HL (LL+DL)
  297. +#define HU (LU+DU)
  298. +#define HR (LR+DR)
  299. +#define HD (LD+DD)
  300. +#define HH (HL+HR)
  301. +#define HV (HU+HD)
  302. +
  303. +/* (BBQ) Quadrants Top/Bottom x Left/Right */
  304. +#define TL (1<<0)
  305. +#define TR (1<<1)
  306. +#define BL (1<<2)
  307. +#define BR (1<<3)
  308. +
  309. +/* Data for U+2500 - U+259F except dashes/diagonals */
  310. +static const unsigned short boxdata[256] = {
  311. + /* light lines */
  312. + [0x00] = BDL + LH, /* light horizontal */
  313. + [0x02] = BDL + LV, /* light vertical */
  314. + [0x0c] = BDL + LD + LR, /* light down and right */
  315. + [0x10] = BDL + LD + LL, /* light down and left */
  316. + [0x14] = BDL + LU + LR, /* light up and right */
  317. + [0x18] = BDL + LU + LL, /* light up and left */
  318. + [0x1c] = BDL + LV + LR, /* light vertical and right */
  319. + [0x24] = BDL + LV + LL, /* light vertical and left */
  320. + [0x2c] = BDL + LH + LD, /* light horizontal and down */
  321. + [0x34] = BDL + LH + LU, /* light horizontal and up */
  322. + [0x3c] = BDL + LV + LH, /* light vertical and horizontal */
  323. + [0x74] = BDL + LL, /* light left */
  324. + [0x75] = BDL + LU, /* light up */
  325. + [0x76] = BDL + LR, /* light right */
  326. + [0x77] = BDL + LD, /* light down */
  327. +
  328. + /* heavy [+light] lines */
  329. + [0x01] = BDL + HH,
  330. + [0x03] = BDL + HV,
  331. + [0x0d] = BDL + HR + LD,
  332. + [0x0e] = BDL + HD + LR,
  333. + [0x0f] = BDL + HD + HR,
  334. + [0x11] = BDL + HL + LD,
  335. + [0x12] = BDL + HD + LL,
  336. + [0x13] = BDL + HD + HL,
  337. + [0x15] = BDL + HR + LU,
  338. + [0x16] = BDL + HU + LR,
  339. + [0x17] = BDL + HU + HR,
  340. + [0x19] = BDL + HL + LU,
  341. + [0x1a] = BDL + HU + LL,
  342. + [0x1b] = BDL + HU + HL,
  343. + [0x1d] = BDL + HR + LV,
  344. + [0x1e] = BDL + HU + LD + LR,
  345. + [0x1f] = BDL + HD + LR + LU,
  346. + [0x20] = BDL + HV + LR,
  347. + [0x21] = BDL + HU + HR + LD,
  348. + [0x22] = BDL + HD + HR + LU,
  349. + [0x23] = BDL + HV + HR,
  350. + [0x25] = BDL + HL + LV,
  351. + [0x26] = BDL + HU + LD + LL,
  352. + [0x27] = BDL + HD + LU + LL,
  353. + [0x28] = BDL + HV + LL,
  354. + [0x29] = BDL + HU + HL + LD,
  355. + [0x2a] = BDL + HD + HL + LU,
  356. + [0x2b] = BDL + HV + HL,
  357. + [0x2d] = BDL + HL + LD + LR,
  358. + [0x2e] = BDL + HR + LL + LD,
  359. + [0x2f] = BDL + HH + LD,
  360. + [0x30] = BDL + HD + LH,
  361. + [0x31] = BDL + HD + HL + LR,
  362. + [0x32] = BDL + HR + HD + LL,
  363. + [0x33] = BDL + HH + HD,
  364. + [0x35] = BDL + HL + LU + LR,
  365. + [0x36] = BDL + HR + LU + LL,
  366. + [0x37] = BDL + HH + LU,
  367. + [0x38] = BDL + HU + LH,
  368. + [0x39] = BDL + HU + HL + LR,
  369. + [0x3a] = BDL + HU + HR + LL,
  370. + [0x3b] = BDL + HH + HU,
  371. + [0x3d] = BDL + HL + LV + LR,
  372. + [0x3e] = BDL + HR + LV + LL,
  373. + [0x3f] = BDL + HH + LV,
  374. + [0x40] = BDL + HU + LH + LD,
  375. + [0x41] = BDL + HD + LH + LU,
  376. + [0x42] = BDL + HV + LH,
  377. + [0x43] = BDL + HU + HL + LD + LR,
  378. + [0x44] = BDL + HU + HR + LD + LL,
  379. + [0x45] = BDL + HD + HL + LU + LR,
  380. + [0x46] = BDL + HD + HR + LU + LL,
  381. + [0x47] = BDL + HH + HU + LD,
  382. + [0x48] = BDL + HH + HD + LU,
  383. + [0x49] = BDL + HV + HL + LR,
  384. + [0x4a] = BDL + HV + HR + LL,
  385. + [0x4b] = BDL + HV + HH,
  386. + [0x78] = BDL + HL,
  387. + [0x79] = BDL + HU,
  388. + [0x7a] = BDL + HR,
  389. + [0x7b] = BDL + HD,
  390. + [0x7c] = BDL + HR + LL,
  391. + [0x7d] = BDL + HD + LU,
  392. + [0x7e] = BDL + HL + LR,
  393. + [0x7f] = BDL + HU + LD,
  394. +
  395. + /* double [+light] lines */
  396. + [0x50] = BDL + DH,
  397. + [0x51] = BDL + DV,
  398. + [0x52] = BDL + DR + LD,
  399. + [0x53] = BDL + DD + LR,
  400. + [0x54] = BDL + DR + DD,
  401. + [0x55] = BDL + DL + LD,
  402. + [0x56] = BDL + DD + LL,
  403. + [0x57] = BDL + DL + DD,
  404. + [0x58] = BDL + DR + LU,
  405. + [0x59] = BDL + DU + LR,
  406. + [0x5a] = BDL + DU + DR,
  407. + [0x5b] = BDL + DL + LU,
  408. + [0x5c] = BDL + DU + LL,
  409. + [0x5d] = BDL + DL + DU,
  410. + [0x5e] = BDL + DR + LV,
  411. + [0x5f] = BDL + DV + LR,
  412. + [0x60] = BDL + DV + DR,
  413. + [0x61] = BDL + DL + LV,
  414. + [0x62] = BDL + DV + LL,
  415. + [0x63] = BDL + DV + DL,
  416. + [0x64] = BDL + DH + LD,
  417. + [0x65] = BDL + DD + LH,
  418. + [0x66] = BDL + DD + DH,
  419. + [0x67] = BDL + DH + LU,
  420. + [0x68] = BDL + DU + LH,
  421. + [0x69] = BDL + DH + DU,
  422. + [0x6a] = BDL + DH + LV,
  423. + [0x6b] = BDL + DV + LH,
  424. + [0x6c] = BDL + DH + DV,
  425. +
  426. + /* (light) arcs */
  427. + [0x6d] = BDA + LD + LR,
  428. + [0x6e] = BDA + LD + LL,
  429. + [0x6f] = BDA + LU + LL,
  430. + [0x70] = BDA + LU + LR,
  431. +
  432. + /* Lower (Down) X/8 block (data is 8 - X) */
  433. + [0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4,
  434. + [0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0,
  435. +
  436. + /* Left X/8 block (data is X) */
  437. + [0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4,
  438. + [0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1,
  439. +
  440. + /* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */
  441. + [0x80] = BBU + 4, [0x94] = BBU + 1,
  442. + [0x90] = BBR + 4, [0x95] = BBR + 7,
  443. +
  444. + /* Quadrants */
  445. + [0x96] = BBQ + BL,
  446. + [0x97] = BBQ + BR,
  447. + [0x98] = BBQ + TL,
  448. + [0x99] = BBQ + TL + BL + BR,
  449. + [0x9a] = BBQ + TL + BR,
  450. + [0x9b] = BBQ + TL + TR + BL,
  451. + [0x9c] = BBQ + TL + TR + BR,
  452. + [0x9d] = BBQ + TR,
  453. + [0x9e] = BBQ + BL + TR,
  454. + [0x9f] = BBQ + BL + TR + BR,
  455. +
  456. + /* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */
  457. + [0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3,
  458. +
  459. + /* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */
  460. + /* U+2571 - U+2573: unsupported (diagonals) */
  461. +};
  462. diff --git a/config.def.h b/config.def.h
  463. index 0e01717..e3654a9 100644
  464. --- a/config.def.h
  465. +++ b/config.def.h
  466. @@ -56,6 +56,18 @@ static unsigned int blinktimeout = 800;
  467. */
  468. static unsigned int cursorthickness = 2;
  469. +/*
  470. + * 1: render most of the lines/blocks characters without using the font for
  471. + * perfect alignment between cells (U2500 - U259F except dashes/diagonals).
  472. + * Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored.
  473. + * 0: disable (render all U25XX glyphs normally from the font).
  474. + */
  475. +const int boxdraw = 0;
  476. +const int boxdraw_bold = 0;
  477. +
  478. +/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */
  479. +const int boxdraw_braille = 0;
  480. +
  481. /*
  482. * bell volume. It must be a value between -100 and 100. Use 0 for disabling
  483. * it
  484. diff --git a/st.c b/st.c
  485. index b8e6077..d65f722 100644
  486. --- a/st.c
  487. +++ b/st.c
  488. @@ -1230,6 +1230,9 @@ tsetchar(Rune u, Glyph *attr, int x, int y)
  489. term.dirty[y] = 1;
  490. term.line[y][x] = *attr;
  491. term.line[y][x].u = u;
  492. +
  493. + if (isboxdraw(u))
  494. + term.line[y][x].mode |= ATTR_BOXDRAW;
  495. }
  496. void
  497. diff --git a/st.h b/st.h
  498. index 38c61c4..9275632 100644
  499. --- a/st.h
  500. +++ b/st.h
  501. @@ -33,6 +33,7 @@ enum glyph_attribute {
  502. ATTR_WRAP = 1 << 8,
  503. ATTR_WIDE = 1 << 9,
  504. ATTR_WDUMMY = 1 << 10,
  505. + ATTR_BOXDRAW = 1 << 11,
  506. ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
  507. };
  508. @@ -110,6 +111,14 @@ void *xmalloc(size_t);
  509. void *xrealloc(void *, size_t);
  510. char *xstrdup(char *);
  511. +int isboxdraw(Rune);
  512. +ushort boxdrawindex(const Glyph *);
  513. +#ifdef XFT_VERSION
  514. +/* only exposed to x.c, otherwise we'll need Xft.h for the types */
  515. +void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *);
  516. +void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int);
  517. +#endif
  518. +
  519. /* config.h globals */
  520. extern char *utmp;
  521. extern char *stty_args;
  522. @@ -120,3 +129,4 @@ extern char *termname;
  523. extern unsigned int tabspaces;
  524. extern unsigned int defaultfg;
  525. extern unsigned int defaultbg;
  526. +extern const int boxdraw, boxdraw_bold, boxdraw_braille;
  527. diff --git a/x.c b/x.c
  528. index 0422421..c740bed 100644
  529. --- a/x.c
  530. +++ b/x.c
  531. @@ -1118,6 +1118,8 @@ xinit(int cols, int rows)
  532. xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
  533. if (xsel.xtarget == None)
  534. xsel.xtarget = XA_STRING;
  535. +
  536. + boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis);
  537. }
  538. int
  539. @@ -1164,8 +1166,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
  540. yp = winy + font->ascent;
  541. }
  542. - /* Lookup character index with default font. */
  543. - glyphidx = XftCharIndex(xw.dpy, font->match, rune);
  544. + if (mode & ATTR_BOXDRAW) {
  545. + /* minor shoehorning: boxdraw uses only this ushort */
  546. + glyphidx = boxdrawindex(&glyphs[i]);
  547. + } else {
  548. + /* Lookup character index with default font. */
  549. + glyphidx = XftCharIndex(xw.dpy, font->match, rune);
  550. + }
  551. if (glyphidx) {
  552. specs[numspecs].font = font->match;
  553. specs[numspecs].glyph = glyphidx;
  554. @@ -1372,8 +1379,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
  555. r.width = width;
  556. XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
  557. - /* Render the glyphs. */
  558. - XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
  559. + if (base.mode & ATTR_BOXDRAW) {
  560. + drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len);
  561. + } else {
  562. + /* Render the glyphs. */
  563. + XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
  564. + }
  565. /* Render underline and strikethrough. */
  566. if (base.mode & ATTR_UNDERLINE) {
  567. @@ -1416,7 +1427,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
  568. /*
  569. * Select the right color for the right mode.
  570. */
  571. - g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
  572. + g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW;
  573. if (IS_SET(MODE_REVERSE)) {
  574. g.mode |= ATTR_REVERSE;
  575. --
  576. 2.17.1