first
[dcc-suckless-config] / based-simple-term / patches / st-undercurl-0.8.4-20210822.diff_
1 diff --git a/config.def.h b/config.def.h
2 index 6f05dce..7ae1b92 100644
3 --- a/config.def.h
4 +++ b/config.def.h
5 @@ -470,3 +470,27 @@ static char ascii_printable[] =
6         " !\"#$%&'()*+,-./0123456789:;<=>?"
7         "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
8         "`abcdefghijklmnopqrstuvwxyz{|}~";
9 +
10 +/**
11 + * Undercurl style. Set UNDERCURL_STYLE to one of the available styles.
12 + *
13 + * Curly: Dunno how to draw it *shrug*
14 + *  _   _   _   _
15 + * ( ) ( ) ( ) ( )
16 + *      (_) (_) (_) (_)
17 + *
18 + * Spiky:
19 + * /\  /\   /\ /\
20 + *   \/  \/      \/
21 + *
22 + * Capped:
23 + *     _     _     _
24 + * / \   / \   / \
25 + *    \_/   \_/
26 + */
27 +// Available styles
28 +#define UNDERCURL_CURLY 0
29 +#define UNDERCURL_SPIKY 1
30 +#define UNDERCURL_CAPPED 2
31 +// Active style
32 +#define UNDERCURL_STYLE UNDERCURL_SPIKY
33 diff --git a/st.c b/st.c
34 index 76b7e0d..542ab3a 100644
35 --- a/st.c
36 +++ b/st.c
37 @@ -33,6 +33,7 @@
38  #define UTF_SIZ       4
39  #define ESC_BUF_SIZ   (128*UTF_SIZ)
40  #define ESC_ARG_SIZ   16
41 +#define CAR_PER_ARG   4
42  #define STR_BUF_SIZ   ESC_BUF_SIZ
43  #define STR_ARG_SIZ   ESC_ARG_SIZ
44  
45 @@ -139,6 +140,7 @@ typedef struct {
46         int arg[ESC_ARG_SIZ];
47         int narg;              /* nb of args */
48         char mode[2];
49 +       int carg[ESC_ARG_SIZ][CAR_PER_ARG]; /* colon args */
50  } CSIEscape;
51  
52  /* STR Escape sequence structs */
53 @@ -159,6 +161,7 @@ static void ttywriteraw(const char *, size_t);
54  
55  static void csidump(void);
56  static void csihandle(void);
57 +static void readcolonargs(char **, int, int[][CAR_PER_ARG]);
58  static void csiparse(void);
59  static void csireset(void);
60  static int eschandle(uchar);
61 @@ -1131,6 +1134,28 @@ tnewline(int first_col)
62         tmoveto(first_col ? 0 : term.c.x, y);
63  }
64  
65 +void
66 +readcolonargs(char **p, int cursor, int params[][CAR_PER_ARG])
67 +{
68 +       int i = 0;
69 +       for (; i < CAR_PER_ARG; i++)
70 +               params[cursor][i] = -1;
71 +
72 +       if (**p != ':')
73 +               return;
74 +
75 +       char *np = NULL;
76 +       i = 0;
77 +
78 +       while (**p == ':' && i < CAR_PER_ARG) {
79 +               while (**p == ':')
80 +                       (*p)++;
81 +               params[cursor][i] = strtol(*p, &np, 10);
82 +               *p = np;
83 +               i++;
84 +       }
85 +}
86 +
87  void
88  csiparse(void)
89  {
90 @@ -1153,6 +1178,7 @@ csiparse(void)
91                         v = -1;
92                 csiescseq.arg[csiescseq.narg++] = v;
93                 p = np;
94 +               readcolonargs(&p, csiescseq.narg-1, csiescseq.carg);
95                 if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
96                         break;
97                 p++;
98 @@ -1369,6 +1395,10 @@ tsetattr(int *attr, int l)
99                                 ATTR_STRUCK     );
100                         term.c.attr.fg = defaultfg;
101                         term.c.attr.bg = defaultbg;
102 +                       term.c.attr.ustyle = -1;
103 +                       term.c.attr.ucolor[0] = -1;
104 +                       term.c.attr.ucolor[1] = -1;
105 +                       term.c.attr.ucolor[2] = -1;
106                         break;
107                 case 1:
108                         term.c.attr.mode |= ATTR_BOLD;
109 @@ -1380,7 +1410,14 @@ tsetattr(int *attr, int l)
110                         term.c.attr.mode |= ATTR_ITALIC;
111                         break;
112                 case 4:
113 -                       term.c.attr.mode |= ATTR_UNDERLINE;
114 +                       term.c.attr.ustyle = csiescseq.carg[i][0];
115 +
116 +                       if (term.c.attr.ustyle != 0)
117 +                               term.c.attr.mode |= ATTR_UNDERLINE;
118 +                       else
119 +                               term.c.attr.mode &= ~ATTR_UNDERLINE;
120 +
121 +                       term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
122                         break;
123                 case 5: /* slow blink */
124                         /* FALLTHROUGH */
125 @@ -1431,6 +1468,18 @@ tsetattr(int *attr, int l)
126                 case 49:
127                         term.c.attr.bg = defaultbg;
128                         break;
129 +               case 58:
130 +                       term.c.attr.ucolor[0] = csiescseq.carg[i][1];
131 +                       term.c.attr.ucolor[1] = csiescseq.carg[i][2];
132 +                       term.c.attr.ucolor[2] = csiescseq.carg[i][3];
133 +                       term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
134 +                       break;
135 +               case 59:
136 +                       term.c.attr.ucolor[0] = -1;
137 +                       term.c.attr.ucolor[1] = -1;
138 +                       term.c.attr.ucolor[2] = -1;
139 +                       term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
140 +                       break;
141                 default:
142                         if (BETWEEN(attr[i], 30, 37)) {
143                                 term.c.attr.fg = attr[i] - 30;
144 diff --git a/st.h b/st.h
145 index 3d351b6..95bdcbd 100644
146 --- a/st.h
147 +++ b/st.h
148 @@ -34,6 +34,7 @@ enum glyph_attribute {
149         ATTR_WIDE       = 1 << 9,
150         ATTR_WDUMMY     = 1 << 10,
151         ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
152 +       ATTR_DIRTYUNDERLINE = 1 << 15,
153  };
154  
155  enum selection_mode {
156 @@ -65,6 +66,8 @@ typedef struct {
157         ushort mode;      /* attribute flags */
158         uint32_t fg;      /* foreground  */
159         uint32_t bg;      /* background  */
160 +       int ustyle;       /* underline style */
161 +       int ucolor[3];    /* underline color */
162  } Glyph;
163  
164  typedef Glyph *Line;
165 diff --git a/st.info b/st.info
166 index 8201ad6..659878c 100644
167 --- a/st.info
168 +++ b/st.info
169 @@ -1,4 +1,5 @@
170  st-mono| simpleterm monocolor,
171 +       Su,
172         acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
173         am,
174         bce,
175 diff --git a/x.c b/x.c
176 index 210f184..3a0e79e 100644
177 --- a/x.c
178 +++ b/x.c
179 @@ -45,6 +45,14 @@ typedef struct {
180         signed char appcursor; /* application cursor */
181  } Key;
182  
183 +/* Undercurl slope types */
184 +enum undercurl_slope_type {
185 +       UNDERCURL_SLOPE_ASCENDING = 0,
186 +       UNDERCURL_SLOPE_TOP_CAP = 1,
187 +       UNDERCURL_SLOPE_DESCENDING = 2,
188 +       UNDERCURL_SLOPE_BOTTOM_CAP = 3
189 +};
190 +
191  /* X modifiers */
192  #define XK_ANY_MOD    UINT_MAX
193  #define XK_NO_MOD     0
194 @@ -1339,6 +1347,51 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
195         return numspecs;
196  }
197  
198 +static int isSlopeRising (int x, int iPoint, int waveWidth)
199 +{
200 +       //    .     .     .     .
201 +       //   / \   / \   / \   / \
202 +       //  /   \ /   \ /   \ /   \
203 +       // .     .     .     .     .
204 +
205 +       // Find absolute `x` of point
206 +       x += iPoint * (waveWidth/2);
207 +
208 +       // Find index of absolute wave
209 +       int absSlope = x / ((float)waveWidth/2);
210 +
211 +       return (absSlope % 2);
212 +}
213 +
214 +static int getSlope (int x, int iPoint, int waveWidth)
215 +{
216 +       // Sizes: Caps are half width of slopes
217 +       //    1_2       1_2       1_2      1_2
218 +       //   /   \     /   \     /   \    /   \
219 +       //  /     \   /     \   /     \  /     \
220 +       // 0       3_0       3_0      3_0       3_
221 +       // <2->    <1>         <---6---->
222 +
223 +       // Find type of first point
224 +       int firstType;
225 +       x -= (x / waveWidth) * waveWidth;
226 +       if (x < (waveWidth * (2.f/6.f)))
227 +               firstType = UNDERCURL_SLOPE_ASCENDING;
228 +       else if (x < (waveWidth * (3.f/6.f)))
229 +               firstType = UNDERCURL_SLOPE_TOP_CAP;
230 +       else if (x < (waveWidth * (5.f/6.f)))
231 +               firstType = UNDERCURL_SLOPE_DESCENDING;
232 +       else
233 +               firstType = UNDERCURL_SLOPE_BOTTOM_CAP;
234 +
235 +       // Find type of given point
236 +       int pointType = (iPoint % 4);
237 +       pointType += firstType;
238 +       pointType %= 4;
239 +
240 +       return pointType;
241 +}
242 +
243  void
244  xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
245  {
246 @@ -1461,8 +1514,357 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
247  
248         /* Render underline and strikethrough. */
249         if (base.mode & ATTR_UNDERLINE) {
250 -               XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
251 -                               width, 1);
252 +               // Underline Color
253 +               const int widthThreshold  = 28; // +1 width every widthThreshold px of font
254 +               int wlw = (win.ch / widthThreshold) + 1; // Wave Line Width
255 +               int linecolor;
256 +               if ((base.ucolor[0] >= 0) &&
257 +                       !(base.mode & ATTR_BLINK && win.mode & MODE_BLINK) &&
258 +                       !(base.mode & ATTR_INVISIBLE)
259 +               ) {
260 +                       // Special color for underline
261 +                       // Index
262 +                       if (base.ucolor[1] < 0) {
263 +                               linecolor = dc.col[base.ucolor[0]].pixel;
264 +                       }
265 +                       // RGB
266 +                       else {
267 +                               XColor lcolor;
268 +                               lcolor.red = base.ucolor[0] * 257;
269 +                               lcolor.green = base.ucolor[1] * 257;
270 +                               lcolor.blue = base.ucolor[2] * 257;
271 +                               lcolor.flags = DoRed | DoGreen | DoBlue;
272 +                               XAllocColor(xw.dpy, xw.cmap, &lcolor);
273 +                               linecolor = lcolor.pixel;
274 +                       }
275 +               } else {
276 +                       // Foreground color for underline
277 +                       linecolor = fg->pixel;
278 +               }
279 +
280 +               XGCValues ugcv = {
281 +                       .foreground = linecolor,
282 +                       .line_width = wlw,
283 +                       .line_style = LineSolid,
284 +                       .cap_style = CapNotLast
285 +               };
286 +
287 +               GC ugc = XCreateGC(xw.dpy, XftDrawDrawable(xw.draw),
288 +                       GCForeground | GCLineWidth | GCLineStyle | GCCapStyle,
289 +                       &ugcv);
290 +
291 +               // Underline Style
292 +               if (base.ustyle != 3) {
293 +                       //XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, width, 1);
294 +                       XFillRectangle(xw.dpy, XftDrawDrawable(xw.draw), ugc, winx,
295 +                               winy + dc.font.ascent + 1, width, wlw);
296 +               } else if (base.ustyle == 3) {
297 +                       int ww = win.cw;//width;
298 +                       int wh = dc.font.descent - wlw/2 - 1;//r.height/7;
299 +                       int wx = winx;
300 +                       int wy = winy + win.ch - dc.font.descent;
301 +
302 +#if UNDERCURL_STYLE == UNDERCURL_CURLY
303 +                       // Draw waves
304 +                       int narcs = charlen * 2 + 1;
305 +                       XArc *arcs = xmalloc(sizeof(XArc) * narcs);
306 +
307 +                       int i = 0;
308 +                       for (i = 0; i < charlen-1; i++) {
309 +                               arcs[i*2] = (XArc) {
310 +                                       .x = wx + win.cw * i + ww / 4,
311 +                                       .y = wy,
312 +                                       .width = win.cw / 2,
313 +                                       .height = wh,
314 +                                       .angle1 = 0,
315 +                                       .angle2 = 180 * 64
316 +                               };
317 +                               arcs[i*2+1] = (XArc) {
318 +                                       .x = wx + win.cw * i + ww * 0.75,
319 +                                       .y = wy,
320 +                                       .width = win.cw/2,
321 +                                       .height = wh,
322 +                                       .angle1 = 180 * 64,
323 +                                       .angle2 = 180 * 64
324 +                               };
325 +                       }
326 +                       // Last wave
327 +                       arcs[i*2] = (XArc) {wx + ww * i + ww / 4, wy, ww / 2, wh,
328 +                       0, 180 * 64 };
329 +                       // Last wave tail
330 +                       arcs[i*2+1] = (XArc) {wx + ww * i + ww * 0.75, wy, ceil(ww / 2.),
331 +                       wh, 180 * 64, 90 * 64};
332 +                       // First wave tail
333 +                       i++;
334 +                       arcs[i*2] = (XArc) {wx - ww/4 - 1, wy, ceil(ww / 2.), wh, 270 * 64,
335 +                       90 * 64 };
336 +
337 +                       XDrawArcs(xw.dpy, XftDrawDrawable(xw.draw), ugc, arcs, narcs);
338 +
339 +                       free(arcs);
340 +#elif UNDERCURL_STYLE == UNDERCURL_SPIKY
341 +                       // Make the underline corridor larger
342 +                       /*
343 +                       wy -= wh;
344 +                       */
345 +                       wh *= 2;
346 +
347 +                       // Set the angle of the slope to 45°
348 +                       ww = wh;
349 +
350 +                       // Position of wave is independent of word, it's absolute
351 +                       wx = (wx / (ww/2)) * (ww/2);
352 +
353 +                       int marginStart = winx - wx;
354 +
355 +                       // Calculate number of points with floating precision
356 +                       float n = width;                                        // Width of word in pixels
357 +                       n = (n / ww) * 2;                                       // Number of slopes (/ or \)
358 +                       n += 2;                                                         // Add two last points
359 +                       int npoints = n;                                        // Convert to int
360 +
361 +                       // Total length of underline
362 +                       float waveLength = 0;
363 +
364 +                       if (npoints >= 3) {
365 +                               // We add an aditional slot in case we use a bonus point
366 +                               XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1));
367 +
368 +                               // First point (Starts with the word bounds)
369 +                               points[0] = (XPoint) {
370 +                                       .x = wx + marginStart,
371 +                                       .y = (isSlopeRising(wx, 0, ww))
372 +                                               ? (wy - marginStart + ww/2.f)
373 +                                               : (wy + marginStart)
374 +                               };
375 +
376 +                               // Second point (Goes back to the absolute point coordinates)
377 +                               points[1] = (XPoint) {
378 +                                       .x = (ww/2.f) - marginStart,
379 +                                       .y = (isSlopeRising(wx, 1, ww))
380 +                                               ? (ww/2.f - marginStart)
381 +                                               : (-ww/2.f + marginStart)
382 +                               };
383 +                               waveLength += (ww/2.f) - marginStart;
384 +
385 +                               // The rest of the points
386 +                               for (int i = 2; i < npoints-1; i++) {
387 +                                       points[i] = (XPoint) {
388 +                                               .x = ww/2,
389 +                                               .y = (isSlopeRising(wx, i, ww))
390 +                                                       ? wh/2
391 +                                                       : -wh/2
392 +                                       };
393 +                                       waveLength += ww/2;
394 +                               }
395 +
396 +                               // Last point
397 +                               points[npoints-1] = (XPoint) {
398 +                                       .x = ww/2,
399 +                                       .y = (isSlopeRising(wx, npoints-1, ww))
400 +                                               ? wh/2
401 +                                               : -wh/2
402 +                               };
403 +                               waveLength += ww/2;
404 +
405 +                               // End
406 +                               if (waveLength < width) { // Add a bonus point?
407 +                                       int marginEnd = width - waveLength;
408 +                                       points[npoints] = (XPoint) {
409 +                                               .x = marginEnd,
410 +                                               .y = (isSlopeRising(wx, npoints, ww))
411 +                                                       ? (marginEnd)
412 +                                                       : (-marginEnd)
413 +                                       };
414 +
415 +                                       npoints++;
416 +                               } else if (waveLength > width) { // Is last point too far?
417 +                                       int marginEnd = waveLength - width;
418 +                                       points[npoints-1].x -= marginEnd;
419 +                                       if (isSlopeRising(wx, npoints-1, ww))
420 +                                               points[npoints-1].y -= (marginEnd);
421 +                                       else
422 +                                               points[npoints-1].y += (marginEnd);
423 +                               }
424 +
425 +                               // Draw the lines
426 +                               XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints,
427 +                                               CoordModePrevious);
428 +
429 +                               // Draw a second underline with an offset of 1 pixel
430 +                               if ( ((win.ch / (widthThreshold/2)) % 2)) {
431 +                                       points[0].x++;
432 +
433 +                                       XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points,
434 +                                                       npoints, CoordModePrevious);
435 +                               }
436 +
437 +                               // Free resources
438 +                               free(points);
439 +                       }
440 +#else // UNDERCURL_CAPPED
441 +                       // Cap is half of wave width
442 +                       float capRatio = 0.5f;
443 +
444 +                       // Make the underline corridor larger
445 +                       wh *= 2;
446 +
447 +                       // Set the angle of the slope to 45°
448 +                       ww = wh;
449 +                       ww *= 1 + capRatio; // Add a bit of width for the cap
450 +
451 +                       // Position of wave is independent of word, it's absolute
452 +                       wx = (wx / ww) * ww;
453 +
454 +                       float marginStart;
455 +                       switch(getSlope(winx, 0, ww)) {
456 +                               case UNDERCURL_SLOPE_ASCENDING:
457 +                                       marginStart = winx - wx;
458 +                                       break;
459 +                               case UNDERCURL_SLOPE_TOP_CAP:
460 +                                       marginStart = winx - (wx + (ww * (2.f/6.f)));
461 +                                       break;
462 +                               case UNDERCURL_SLOPE_DESCENDING:
463 +                                       marginStart = winx - (wx + (ww * (3.f/6.f)));
464 +                                       break;
465 +                               case UNDERCURL_SLOPE_BOTTOM_CAP:
466 +                                       marginStart = winx - (wx + (ww * (5.f/6.f)));
467 +                                       break;
468 +                       }
469 +
470 +                       // Calculate number of points with floating precision
471 +                       float n = width;                                        // Width of word in pixels
472 +                                                                                               //                                         ._.
473 +                       n = (n / ww) * 4;                                       // Number of points (./   \.)
474 +                       n += 2;                                                         // Add two last points
475 +                       int npoints = n;                                        // Convert to int
476 +
477 +                       // Position of the pen to draw the lines
478 +                       float penX = 0;
479 +                       float penY = 0;
480 +
481 +                       if (npoints >= 3) {
482 +                               XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1));
483 +
484 +                               // First point (Starts with the word bounds)
485 +                               penX = winx;
486 +                               switch (getSlope(winx, 0, ww)) {
487 +                                       case UNDERCURL_SLOPE_ASCENDING:
488 +                                               penY = wy + wh/2.f - marginStart;
489 +                                               break;
490 +                                       case UNDERCURL_SLOPE_TOP_CAP:
491 +                                               penY = wy;
492 +                                               break;
493 +                                       case UNDERCURL_SLOPE_DESCENDING:
494 +                                               penY = wy + marginStart;
495 +                                               break;
496 +                                       case UNDERCURL_SLOPE_BOTTOM_CAP:
497 +                                               penY = wy + wh/2.f;
498 +                                               break;
499 +                               }
500 +                               points[0].x = penX;
501 +                               points[0].y = penY;
502 +
503 +                               // Second point (Goes back to the absolute point coordinates)
504 +                               switch (getSlope(winx, 1, ww)) {
505 +                                       case UNDERCURL_SLOPE_ASCENDING:
506 +                                               penX += ww * (1.f/6.f) - marginStart;
507 +                                               penY += 0;
508 +                                               break;
509 +                                       case UNDERCURL_SLOPE_TOP_CAP:
510 +                                               penX += ww * (2.f/6.f) - marginStart;
511 +                                               penY += -wh/2.f + marginStart;
512 +                                               break;
513 +                                       case UNDERCURL_SLOPE_DESCENDING:
514 +                                               penX += ww * (1.f/6.f) - marginStart;
515 +                                               penY += 0;
516 +                                               break;
517 +                                       case UNDERCURL_SLOPE_BOTTOM_CAP:
518 +                                               penX += ww * (2.f/6.f) - marginStart;
519 +                                               penY += -marginStart + wh/2.f;
520 +                                               break;
521 +                               }
522 +                               points[1].x = penX;
523 +                               points[1].y = penY;
524 +
525 +                               // The rest of the points
526 +                               for (int i = 2; i < npoints; i++) {
527 +                                       switch (getSlope(winx, i, ww)) {
528 +                                               case UNDERCURL_SLOPE_ASCENDING:
529 +                                               case UNDERCURL_SLOPE_DESCENDING:
530 +                                                       penX += ww * (1.f/6.f);
531 +                                                       penY += 0;
532 +                                                       break;
533 +                                               case UNDERCURL_SLOPE_TOP_CAP:
534 +                                                       penX += ww * (2.f/6.f);
535 +                                                       penY += -wh / 2.f;
536 +                                                       break;
537 +                                               case UNDERCURL_SLOPE_BOTTOM_CAP:
538 +                                                       penX += ww * (2.f/6.f);
539 +                                                       penY += wh / 2.f;
540 +                                                       break;
541 +                                       }
542 +                                       points[i].x = penX;
543 +                                       points[i].y = penY;
544 +                               }
545 +
546 +                               // End
547 +                               float waveLength = penX - winx;
548 +                               if (waveLength < width) { // Add a bonus point?
549 +                                       int marginEnd = width - waveLength;
550 +                                       penX += marginEnd;
551 +                                       switch(getSlope(winx, npoints, ww)) {
552 +                                               case UNDERCURL_SLOPE_ASCENDING:
553 +                                               case UNDERCURL_SLOPE_DESCENDING:
554 +                                                       //penY += 0;
555 +                                                       break;
556 +                                               case UNDERCURL_SLOPE_TOP_CAP:
557 +                                                       penY += -marginEnd;
558 +                                                       break;
559 +                                               case UNDERCURL_SLOPE_BOTTOM_CAP:
560 +                                                       penY += marginEnd;
561 +                                                       break;
562 +                                       }
563 +
564 +                                       points[npoints].x = penX;
565 +                                       points[npoints].y = penY;
566 +
567 +                                       npoints++;
568 +                               } else if (waveLength > width) { // Is last point too far?
569 +                                       int marginEnd = waveLength - width;
570 +                                       points[npoints-1].x -= marginEnd;
571 +                                       switch(getSlope(winx, npoints-1, ww)) {
572 +                                               case UNDERCURL_SLOPE_TOP_CAP:
573 +                                                       points[npoints-1].y += marginEnd;
574 +                                                       break;
575 +                                               case UNDERCURL_SLOPE_BOTTOM_CAP:
576 +                                                       points[npoints-1].y -= marginEnd;
577 +                                                       break;
578 +                                               default:
579 +                                                       break;
580 +                                       }
581 +                               }
582 +
583 +                               // Draw the lines
584 +                               XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints,
585 +                                               CoordModeOrigin);
586 +
587 +                               // Draw a second underline with an offset of 1 pixel
588 +                               if ( ((win.ch / (widthThreshold/2)) % 2)) {
589 +                                       for (int i = 0; i < npoints; i++)
590 +                                               points[i].x++;
591 +
592 +                                       XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points,
593 +                                                       npoints, CoordModeOrigin);
594 +                               }
595 +
596 +                               // Free resources
597 +                               free(points);
598 +                       }
599 +#endif
600 +               }
601 +
602 +               XFreeGC(xw.dpy, ugc);
603         }
604  
605         if (base.mode & ATTR_STRUCK) {