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