commit 9bb304a974185cbd9fa48c890450c6582d3e0546
Author: HexOctal <[email protected]>
Date:   Sun Aug 22 16:09:21 2021 +0100

    [st][patch][st-undercurl] Added new line styles
    
    Added two new underline styles, and changed default style.
    Updated image example with new style.
    Added a dynamic line width that updates with terminal font size.

diff --git a/st.suckless.org/patches/undercurl/index.md 
b/st.suckless.org/patches/undercurl/index.md
index 81207644..d35fff1f 100644
--- a/st.suckless.org/patches/undercurl/index.md
+++ b/st.suckless.org/patches/undercurl/index.md
@@ -12,6 +12,9 @@ following 
[SGR](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR) parameters:
 * 58:2:r:g:b - Where r, g and b are the red, green and blue color values of 
the underline respectively.
 * 59 - Resets the underline color to the foreground color.
 
+Three styles are available to choose from. You can do so in the `config.def.h`
+file by editing the `UNDERCURL_STYLE` define.
+
 Notes
 -----
 These escape codes aren't standard, but they are supported by most other
@@ -19,7 +22,7 @@ terminal emulators, as well as many terminal programs (Such 
as Vim).
 
 Download
 --------
-* [st-undercurl-0.8.4.diff](st-undercurl-0.8.4.diff)
+* [st-undercurl-0.8.4-20210822.diff](st-undercurl-0.8.4-20210822.diff)
 
 Authors
 -------
diff --git a/st.suckless.org/patches/undercurl/st-undercurl-0.8.4-20210822.diff 
b/st.suckless.org/patches/undercurl/st-undercurl-0.8.4-20210822.diff
new file mode 100644
index 00000000..fab2ddca
--- /dev/null
+++ b/st.suckless.org/patches/undercurl/st-undercurl-0.8.4-20210822.diff
@@ -0,0 +1,605 @@
+diff --git a/config.def.h b/config.def.h
+index 6f05dce..7ae1b92 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -470,3 +470,27 @@ static char ascii_printable[] =
+       " !\"#$%&'()*+,-./0123456789:;<=>?"
+       "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_"
+       "`abcdefghijklmnopqrstuvwxyz{|}~";
++
++/**
++ * Undercurl style. Set UNDERCURL_STYLE to one of the available styles.
++ *
++ * Curly: Dunno how to draw it *shrug*
++ *  _   _   _   _
++ * ( ) ( ) ( ) ( )
++ *     (_) (_) (_) (_)
++ *
++ * Spiky:
++ * /\  /\   /\        /\
++ *   \/  \/     \/
++ *
++ * Capped:
++ *    _     _     _
++ * / \   / \   / \
++ *    \_/   \_/
++ */
++// Available styles
++#define UNDERCURL_CURLY 0
++#define UNDERCURL_SPIKY 1
++#define UNDERCURL_CAPPED 2
++// Active style
++#define UNDERCURL_STYLE UNDERCURL_SPIKY
+diff --git a/st.c b/st.c
+index 76b7e0d..542ab3a 100644
+--- a/st.c
++++ b/st.c
+@@ -33,6 +33,7 @@
+ #define UTF_SIZ       4
+ #define ESC_BUF_SIZ   (128*UTF_SIZ)
+ #define ESC_ARG_SIZ   16
++#define CAR_PER_ARG   4
+ #define STR_BUF_SIZ   ESC_BUF_SIZ
+ #define STR_ARG_SIZ   ESC_ARG_SIZ
+ 
+@@ -139,6 +140,7 @@ typedef struct {
+       int arg[ESC_ARG_SIZ];
+       int narg;              /* nb of args */
+       char mode[2];
++      int carg[ESC_ARG_SIZ][CAR_PER_ARG]; /* colon args */
+ } CSIEscape;
+ 
+ /* STR Escape sequence structs */
+@@ -159,6 +161,7 @@ static void ttywriteraw(const char *, size_t);
+ 
+ static void csidump(void);
+ static void csihandle(void);
++static void readcolonargs(char **, int, int[][CAR_PER_ARG]);
+ static void csiparse(void);
+ static void csireset(void);
+ static int eschandle(uchar);
+@@ -1131,6 +1134,28 @@ tnewline(int first_col)
+       tmoveto(first_col ? 0 : term.c.x, y);
+ }
+ 
++void
++readcolonargs(char **p, int cursor, int params[][CAR_PER_ARG])
++{
++      int i = 0;
++      for (; i < CAR_PER_ARG; i++)
++              params[cursor][i] = -1;
++
++      if (**p != ':')
++              return;
++
++      char *np = NULL;
++      i = 0;
++
++      while (**p == ':' && i < CAR_PER_ARG) {
++              while (**p == ':')
++                      (*p)++;
++              params[cursor][i] = strtol(*p, &np, 10);
++              *p = np;
++              i++;
++      }
++}
++
+ void
+ csiparse(void)
+ {
+@@ -1153,6 +1178,7 @@ csiparse(void)
+                       v = -1;
+               csiescseq.arg[csiescseq.narg++] = v;
+               p = np;
++              readcolonargs(&p, csiescseq.narg-1, csiescseq.carg);
+               if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
+                       break;
+               p++;
+@@ -1369,6 +1395,10 @@ tsetattr(int *attr, int l)
+                               ATTR_STRUCK     );
+                       term.c.attr.fg = defaultfg;
+                       term.c.attr.bg = defaultbg;
++                      term.c.attr.ustyle = -1;
++                      term.c.attr.ucolor[0] = -1;
++                      term.c.attr.ucolor[1] = -1;
++                      term.c.attr.ucolor[2] = -1;
+                       break;
+               case 1:
+                       term.c.attr.mode |= ATTR_BOLD;
+@@ -1380,7 +1410,14 @@ tsetattr(int *attr, int l)
+                       term.c.attr.mode |= ATTR_ITALIC;
+                       break;
+               case 4:
+-                      term.c.attr.mode |= ATTR_UNDERLINE;
++                      term.c.attr.ustyle = csiescseq.carg[i][0];
++
++                      if (term.c.attr.ustyle != 0)
++                              term.c.attr.mode |= ATTR_UNDERLINE;
++                      else
++                              term.c.attr.mode &= ~ATTR_UNDERLINE;
++
++                      term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
+                       break;
+               case 5: /* slow blink */
+                       /* FALLTHROUGH */
+@@ -1431,6 +1468,18 @@ tsetattr(int *attr, int l)
+               case 49:
+                       term.c.attr.bg = defaultbg;
+                       break;
++              case 58:
++                      term.c.attr.ucolor[0] = csiescseq.carg[i][1];
++                      term.c.attr.ucolor[1] = csiescseq.carg[i][2];
++                      term.c.attr.ucolor[2] = csiescseq.carg[i][3];
++                      term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
++                      break;
++              case 59:
++                      term.c.attr.ucolor[0] = -1;
++                      term.c.attr.ucolor[1] = -1;
++                      term.c.attr.ucolor[2] = -1;
++                      term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
++                      break;
+               default:
+                       if (BETWEEN(attr[i], 30, 37)) {
+                               term.c.attr.fg = attr[i] - 30;
+diff --git a/st.h b/st.h
+index 3d351b6..95bdcbd 100644
+--- a/st.h
++++ b/st.h
+@@ -34,6 +34,7 @@ enum glyph_attribute {
+       ATTR_WIDE       = 1 << 9,
+       ATTR_WDUMMY     = 1 << 10,
+       ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
++      ATTR_DIRTYUNDERLINE = 1 << 15,
+ };
+ 
+ enum selection_mode {
+@@ -65,6 +66,8 @@ typedef struct {
+       ushort mode;      /* attribute flags */
+       uint32_t fg;      /* foreground  */
+       uint32_t bg;      /* background  */
++      int ustyle;       /* underline style */
++      int ucolor[3];    /* underline color */
+ } Glyph;
+ 
+ typedef Glyph *Line;
+diff --git a/st.info b/st.info
+index 8201ad6..659878c 100644
+--- a/st.info
++++ b/st.info
+@@ -1,4 +1,5 @@
+ st-mono| simpleterm monocolor,
++      Su,
+       acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+       am,
+       bce,
+diff --git a/x.c b/x.c
+index 210f184..3a0e79e 100644
+--- a/x.c
++++ b/x.c
+@@ -45,6 +45,14 @@ typedef struct {
+       signed char appcursor; /* application cursor */
+ } Key;
+ 
++/* Undercurl slope types */
++enum undercurl_slope_type {
++      UNDERCURL_SLOPE_ASCENDING = 0,
++      UNDERCURL_SLOPE_TOP_CAP = 1,
++      UNDERCURL_SLOPE_DESCENDING = 2,
++      UNDERCURL_SLOPE_BOTTOM_CAP = 3
++};
++
+ /* X modifiers */
+ #define XK_ANY_MOD    UINT_MAX
+ #define XK_NO_MOD     0
+@@ -1339,6 +1347,51 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const 
Glyph *glyphs, int len, int x
+       return numspecs;
+ }
+ 
++static int isSlopeRising (int x, int iPoint, int waveWidth)
++{
++      //    .     .     .     .
++      //   / \   / \   / \   / \
++      //  /   \ /   \ /   \ /   \
++      // .     .     .     .     .
++
++      // Find absolute `x` of point
++      x += iPoint * (waveWidth/2);
++
++      // Find index of absolute wave
++      int absSlope = x / ((float)waveWidth/2);
++
++      return (absSlope % 2);
++}
++
++static int getSlope (int x, int iPoint, int waveWidth)
++{
++      // Sizes: Caps are half width of slopes
++      //    1_2       1_2       1_2      1_2
++      //   /   \     /   \     /   \    /   \
++      //  /     \   /     \   /     \  /     \
++      // 0       3_0       3_0      3_0       3_
++      // <2->    <1>         <---6---->
++
++      // Find type of first point
++      int firstType;
++      x -= (x / waveWidth) * waveWidth;
++      if (x < (waveWidth * (2.f/6.f)))
++              firstType = UNDERCURL_SLOPE_ASCENDING;
++      else if (x < (waveWidth * (3.f/6.f)))
++              firstType = UNDERCURL_SLOPE_TOP_CAP;
++      else if (x < (waveWidth * (5.f/6.f)))
++              firstType = UNDERCURL_SLOPE_DESCENDING;
++      else
++              firstType = UNDERCURL_SLOPE_BOTTOM_CAP;
++
++      // Find type of given point
++      int pointType = (iPoint % 4);
++      pointType += firstType;
++      pointType %= 4;
++
++      return pointType;
++}
++
+ void
+ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int 
x, int y)
+ {
+@@ -1461,8 +1514,357 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, 
Glyph base, int len, int x, i
+ 
+       /* Render underline and strikethrough. */
+       if (base.mode & ATTR_UNDERLINE) {
+-              XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
+-                              width, 1);
++              // Underline Color
++              const int widthThreshold  = 28; // +1 width every 
widthThreshold px of font
++              int wlw = (win.ch / widthThreshold) + 1; // Wave Line Width
++              int linecolor;
++              if ((base.ucolor[0] >= 0) &&
++                      !(base.mode & ATTR_BLINK && win.mode & MODE_BLINK) &&
++                      !(base.mode & ATTR_INVISIBLE)
++              ) {
++                      // Special color for underline
++                      // Index
++                      if (base.ucolor[1] < 0) {
++                              linecolor = dc.col[base.ucolor[0]].pixel;
++                      }
++                      // RGB
++                      else {
++                              XColor lcolor;
++                              lcolor.red = base.ucolor[0] * 257;
++                              lcolor.green = base.ucolor[1] * 257;
++                              lcolor.blue = base.ucolor[2] * 257;
++                              lcolor.flags = DoRed | DoGreen | DoBlue;
++                              XAllocColor(xw.dpy, xw.cmap, &lcolor);
++                              linecolor = lcolor.pixel;
++                      }
++              } else {
++                      // Foreground color for underline
++                      linecolor = fg->pixel;
++              }
++
++              XGCValues ugcv = {
++                      .foreground = linecolor,
++                      .line_width = wlw,
++                      .line_style = LineSolid,
++                      .cap_style = CapNotLast
++              };
++
++              GC ugc = XCreateGC(xw.dpy, XftDrawDrawable(xw.draw),
++                      GCForeground | GCLineWidth | GCLineStyle | GCCapStyle,
++                      &ugcv);
++
++              // Underline Style
++              if (base.ustyle != 3) {
++                      //XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent 
+ 1, width, 1);
++                      XFillRectangle(xw.dpy, XftDrawDrawable(xw.draw), ugc, 
winx,
++                              winy + dc.font.ascent + 1, width, wlw);
++              } else if (base.ustyle == 3) {
++                      int ww = win.cw;//width;
++                      int wh = dc.font.descent - wlw/2 - 1;//r.height/7;
++                      int wx = winx;
++                      int wy = winy + win.ch - dc.font.descent;
++
++#if UNDERCURL_STYLE == UNDERCURL_CURLY
++                      // Draw waves
++                      int narcs = charlen * 2 + 1;
++                      XArc *arcs = xmalloc(sizeof(XArc) * narcs);
++
++                      int i = 0;
++                      for (i = 0; i < charlen-1; i++) {
++                              arcs[i*2] = (XArc) {
++                                      .x = wx + win.cw * i + ww / 4,
++                                      .y = wy,
++                                      .width = win.cw / 2,
++                                      .height = wh,
++                                      .angle1 = 0,
++                                      .angle2 = 180 * 64
++                              };
++                              arcs[i*2+1] = (XArc) {
++                                      .x = wx + win.cw * i + ww * 0.75,
++                                      .y = wy,
++                                      .width = win.cw/2,
++                                      .height = wh,
++                                      .angle1 = 180 * 64,
++                                      .angle2 = 180 * 64
++                              };
++                      }
++                      // Last wave
++                      arcs[i*2] = (XArc) {wx + ww * i + ww / 4, wy, ww / 2, 
wh,
++                      0, 180 * 64 };
++                      // Last wave tail
++                      arcs[i*2+1] = (XArc) {wx + ww * i + ww * 0.75, wy, 
ceil(ww / 2.),
++                      wh, 180 * 64, 90 * 64};
++                      // First wave tail
++                      i++;
++                      arcs[i*2] = (XArc) {wx - ww/4 - 1, wy, ceil(ww / 2.), 
wh, 270 * 64,
++                      90 * 64 };
++
++                      XDrawArcs(xw.dpy, XftDrawDrawable(xw.draw), ugc, arcs, 
narcs);
++
++                      free(arcs);
++#elif UNDERCURL_STYLE == UNDERCURL_SPIKY
++                      // Make the underline corridor larger
++                      /*
++                      wy -= wh;
++                      */
++                      wh *= 2;
++
++                      // Set the angle of the slope to 45°
++                      ww = wh;
++
++                      // Position of wave is independent of word, it's 
absolute
++                      wx = (wx / (ww/2)) * (ww/2);
++
++                      int marginStart = winx - wx;
++
++                      // Calculate number of points with floating precision
++                      float n = width;                                        
// Width of word in pixels
++                      n = (n / ww) * 2;                                       
// Number of slopes (/ or \)
++                      n += 2;                                                 
        // Add two last points
++                      int npoints = n;                                        
// Convert to int
++
++                      // Total length of underline
++                      float waveLength = 0;
++
++                      if (npoints >= 3) {
++                              // We add an aditional slot in case we use a 
bonus point
++                              XPoint *points = xmalloc(sizeof(XPoint) * 
(npoints + 1));
++
++                              // First point (Starts with the word bounds)
++                              points[0] = (XPoint) {
++                                      .x = wx + marginStart,
++                                      .y = (isSlopeRising(wx, 0, ww))
++                                              ? (wy - marginStart + ww/2.f)
++                                              : (wy + marginStart)
++                              };
++
++                              // Second point (Goes back to the absolute 
point coordinates)
++                              points[1] = (XPoint) {
++                                      .x = (ww/2.f) - marginStart,
++                                      .y = (isSlopeRising(wx, 1, ww))
++                                              ? (ww/2.f - marginStart)
++                                              : (-ww/2.f + marginStart)
++                              };
++                              waveLength += (ww/2.f) - marginStart;
++
++                              // The rest of the points
++                              for (int i = 2; i < npoints-1; i++) {
++                                      points[i] = (XPoint) {
++                                              .x = ww/2,
++                                              .y = (isSlopeRising(wx, i, ww))
++                                                      ? wh/2
++                                                      : -wh/2
++                                      };
++                                      waveLength += ww/2;
++                              }
++
++                              // Last point
++                              points[npoints-1] = (XPoint) {
++                                      .x = ww/2,
++                                      .y = (isSlopeRising(wx, npoints-1, ww))
++                                              ? wh/2
++                                              : -wh/2
++                              };
++                              waveLength += ww/2;
++
++                              // End
++                              if (waveLength < width) { // Add a bonus point?
++                                      int marginEnd = width - waveLength;
++                                      points[npoints] = (XPoint) {
++                                              .x = marginEnd,
++                                              .y = (isSlopeRising(wx, 
npoints, ww))
++                                                      ? (marginEnd)
++                                                      : (-marginEnd)
++                                      };
++
++                                      npoints++;
++                              } else if (waveLength > width) { // Is last 
point too far?
++                                      int marginEnd = waveLength - width;
++                                      points[npoints-1].x -= marginEnd;
++                                      if (isSlopeRising(wx, npoints-1, ww))
++                                              points[npoints-1].y -= 
(marginEnd);
++                                      else
++                                              points[npoints-1].y += 
(marginEnd);
++                              }
++
++                              // Draw the lines
++                              XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), 
ugc, points, npoints,
++                                              CoordModePrevious);
++
++                              // Draw a second underline with an offset of 1 
pixel
++                              if ( ((win.ch / (widthThreshold/2)) % 2)) {
++                                      points[0].x++;
++
++                                      XDrawLines(xw.dpy, 
XftDrawDrawable(xw.draw), ugc, points,
++                                                      npoints, 
CoordModePrevious);
++                              }
++
++                              // Free resources
++                              free(points);
++                      }
++#else // UNDERCURL_CAPPED
++                      // Cap is half of wave width
++                      float capRatio = 0.5f;
++
++                      // Make the underline corridor larger
++                      wh *= 2;
++
++                      // Set the angle of the slope to 45°
++                      ww = wh;
++                      ww *= 1 + capRatio; // Add a bit of width for the cap
++
++                      // Position of wave is independent of word, it's 
absolute
++                      wx = (wx / ww) * ww;
++
++                      float marginStart;
++                      switch(getSlope(winx, 0, ww)) {
++                              case UNDERCURL_SLOPE_ASCENDING:
++                                      marginStart = winx - wx;
++                                      break;
++                              case UNDERCURL_SLOPE_TOP_CAP:
++                                      marginStart = winx - (wx + (ww * 
(2.f/6.f)));
++                                      break;
++                              case UNDERCURL_SLOPE_DESCENDING:
++                                      marginStart = winx - (wx + (ww * 
(3.f/6.f)));
++                                      break;
++                              case UNDERCURL_SLOPE_BOTTOM_CAP:
++                                      marginStart = winx - (wx + (ww * 
(5.f/6.f)));
++                                      break;
++                      }
++
++                      // Calculate number of points with floating precision
++                      float n = width;                                        
// Width of word in pixels
++                                                                              
                //                                         ._.
++                      n = (n / ww) * 4;                                       
// Number of points (./   \.)
++                      n += 2;                                                 
        // Add two last points
++                      int npoints = n;                                        
// Convert to int
++
++                      // Position of the pen to draw the lines
++                      float penX = 0;
++                      float penY = 0;
++
++                      if (npoints >= 3) {
++                              XPoint *points = xmalloc(sizeof(XPoint) * 
(npoints + 1));
++
++                              // First point (Starts with the word bounds)
++                              penX = winx;
++                              switch (getSlope(winx, 0, ww)) {
++                                      case UNDERCURL_SLOPE_ASCENDING:
++                                              penY = wy + wh/2.f - 
marginStart;
++                                              break;
++                                      case UNDERCURL_SLOPE_TOP_CAP:
++                                              penY = wy;
++                                              break;
++                                      case UNDERCURL_SLOPE_DESCENDING:
++                                              penY = wy + marginStart;
++                                              break;
++                                      case UNDERCURL_SLOPE_BOTTOM_CAP:
++                                              penY = wy + wh/2.f;
++                                              break;
++                              }
++                              points[0].x = penX;
++                              points[0].y = penY;
++
++                              // Second point (Goes back to the absolute 
point coordinates)
++                              switch (getSlope(winx, 1, ww)) {
++                                      case UNDERCURL_SLOPE_ASCENDING:
++                                              penX += ww * (1.f/6.f) - 
marginStart;
++                                              penY += 0;
++                                              break;
++                                      case UNDERCURL_SLOPE_TOP_CAP:
++                                              penX += ww * (2.f/6.f) - 
marginStart;
++                                              penY += -wh/2.f + marginStart;
++                                              break;
++                                      case UNDERCURL_SLOPE_DESCENDING:
++                                              penX += ww * (1.f/6.f) - 
marginStart;
++                                              penY += 0;
++                                              break;
++                                      case UNDERCURL_SLOPE_BOTTOM_CAP:
++                                              penX += ww * (2.f/6.f) - 
marginStart;
++                                              penY += -marginStart + wh/2.f;
++                                              break;
++                              }
++                              points[1].x = penX;
++                              points[1].y = penY;
++
++                              // The rest of the points
++                              for (int i = 2; i < npoints; i++) {
++                                      switch (getSlope(winx, i, ww)) {
++                                              case UNDERCURL_SLOPE_ASCENDING:
++                                              case UNDERCURL_SLOPE_DESCENDING:
++                                                      penX += ww * (1.f/6.f);
++                                                      penY += 0;
++                                                      break;
++                                              case UNDERCURL_SLOPE_TOP_CAP:
++                                                      penX += ww * (2.f/6.f);
++                                                      penY += -wh / 2.f;
++                                                      break;
++                                              case UNDERCURL_SLOPE_BOTTOM_CAP:
++                                                      penX += ww * (2.f/6.f);
++                                                      penY += wh / 2.f;
++                                                      break;
++                                      }
++                                      points[i].x = penX;
++                                      points[i].y = penY;
++                              }
++
++                              // End
++                              float waveLength = penX - winx;
++                              if (waveLength < width) { // Add a bonus point?
++                                      int marginEnd = width - waveLength;
++                                      penX += marginEnd;
++                                      switch(getSlope(winx, npoints, ww)) {
++                                              case UNDERCURL_SLOPE_ASCENDING:
++                                              case UNDERCURL_SLOPE_DESCENDING:
++                                                      //penY += 0;
++                                                      break;
++                                              case UNDERCURL_SLOPE_TOP_CAP:
++                                                      penY += -marginEnd;
++                                                      break;
++                                              case UNDERCURL_SLOPE_BOTTOM_CAP:
++                                                      penY += marginEnd;
++                                                      break;
++                                      }
++
++                                      points[npoints].x = penX;
++                                      points[npoints].y = penY;
++
++                                      npoints++;
++                              } else if (waveLength > width) { // Is last 
point too far?
++                                      int marginEnd = waveLength - width;
++                                      points[npoints-1].x -= marginEnd;
++                                      switch(getSlope(winx, npoints-1, ww)) {
++                                              case UNDERCURL_SLOPE_TOP_CAP:
++                                                      points[npoints-1].y += 
marginEnd;
++                                                      break;
++                                              case UNDERCURL_SLOPE_BOTTOM_CAP:
++                                                      points[npoints-1].y -= 
marginEnd;
++                                                      break;
++                                              default:
++                                                      break;
++                                      }
++                              }
++
++                              // Draw the lines
++                              XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), 
ugc, points, npoints,
++                                              CoordModeOrigin);
++
++                              // Draw a second underline with an offset of 1 
pixel
++                              if ( ((win.ch / (widthThreshold/2)) % 2)) {
++                                      for (int i = 0; i < npoints; i++)
++                                              points[i].x++;
++
++                                      XDrawLines(xw.dpy, 
XftDrawDrawable(xw.draw), ugc, points,
++                                                      npoints, 
CoordModeOrigin);
++                              }
++
++                              // Free resources
++                              free(points);
++                      }
++#endif
++              }
++
++              XFreeGC(xw.dpy, ugc);
+       }
+ 
+       if (base.mode & ATTR_STRUCK) {
diff --git a/st.suckless.org/patches/undercurl/st-undercurl-0.8.4.diff 
b/st.suckless.org/patches/undercurl/st-undercurl-0.8.4.diff
deleted file mode 100644
index a91b6074..00000000
--- a/st.suckless.org/patches/undercurl/st-undercurl-0.8.4.diff
+++ /dev/null
@@ -1,244 +0,0 @@
-diff --git a/st.c b/st.c
-index 76b7e0d..542ab3a 100644
---- a/st.c
-+++ b/st.c
-@@ -33,6 +33,7 @@
- #define UTF_SIZ       4
- #define ESC_BUF_SIZ   (128*UTF_SIZ)
- #define ESC_ARG_SIZ   16
-+#define CAR_PER_ARG   4
- #define STR_BUF_SIZ   ESC_BUF_SIZ
- #define STR_ARG_SIZ   ESC_ARG_SIZ
- 
-@@ -139,6 +140,7 @@ typedef struct {
-       int arg[ESC_ARG_SIZ];
-       int narg;              /* nb of args */
-       char mode[2];
-+      int carg[ESC_ARG_SIZ][CAR_PER_ARG]; /* colon args */
- } CSIEscape;
- 
- /* STR Escape sequence structs */
-@@ -159,6 +161,7 @@ static void ttywriteraw(const char *, size_t);
- 
- static void csidump(void);
- static void csihandle(void);
-+static void readcolonargs(char **, int, int[][CAR_PER_ARG]);
- static void csiparse(void);
- static void csireset(void);
- static int eschandle(uchar);
-@@ -1131,6 +1134,28 @@ tnewline(int first_col)
-       tmoveto(first_col ? 0 : term.c.x, y);
- }
- 
-+void
-+readcolonargs(char **p, int cursor, int params[][CAR_PER_ARG])
-+{
-+      int i = 0;
-+      for (; i < CAR_PER_ARG; i++)
-+              params[cursor][i] = -1;
-+
-+      if (**p != ':')
-+              return;
-+
-+      char *np = NULL;
-+      i = 0;
-+
-+      while (**p == ':' && i < CAR_PER_ARG) {
-+              while (**p == ':')
-+                      (*p)++;
-+              params[cursor][i] = strtol(*p, &np, 10);
-+              *p = np;
-+              i++;
-+      }
-+}
-+
- void
- csiparse(void)
- {
-@@ -1153,6 +1178,7 @@ csiparse(void)
-                       v = -1;
-               csiescseq.arg[csiescseq.narg++] = v;
-               p = np;
-+              readcolonargs(&p, csiescseq.narg-1, csiescseq.carg);
-               if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
-                       break;
-               p++;
-@@ -1369,6 +1395,10 @@ tsetattr(int *attr, int l)
-                               ATTR_STRUCK     );
-                       term.c.attr.fg = defaultfg;
-                       term.c.attr.bg = defaultbg;
-+                      term.c.attr.ustyle = -1;
-+                      term.c.attr.ucolor[0] = -1;
-+                      term.c.attr.ucolor[1] = -1;
-+                      term.c.attr.ucolor[2] = -1;
-                       break;
-               case 1:
-                       term.c.attr.mode |= ATTR_BOLD;
-@@ -1380,7 +1410,14 @@ tsetattr(int *attr, int l)
-                       term.c.attr.mode |= ATTR_ITALIC;
-                       break;
-               case 4:
--                      term.c.attr.mode |= ATTR_UNDERLINE;
-+                      term.c.attr.ustyle = csiescseq.carg[i][0];
-+
-+                      if (term.c.attr.ustyle != 0)
-+                              term.c.attr.mode |= ATTR_UNDERLINE;
-+                      else
-+                              term.c.attr.mode &= ~ATTR_UNDERLINE;
-+
-+                      term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
-                       break;
-               case 5: /* slow blink */
-                       /* FALLTHROUGH */
-@@ -1431,6 +1468,18 @@ tsetattr(int *attr, int l)
-               case 49:
-                       term.c.attr.bg = defaultbg;
-                       break;
-+              case 58:
-+                      term.c.attr.ucolor[0] = csiescseq.carg[i][1];
-+                      term.c.attr.ucolor[1] = csiescseq.carg[i][2];
-+                      term.c.attr.ucolor[2] = csiescseq.carg[i][3];
-+                      term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
-+                      break;
-+              case 59:
-+                      term.c.attr.ucolor[0] = -1;
-+                      term.c.attr.ucolor[1] = -1;
-+                      term.c.attr.ucolor[2] = -1;
-+                      term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
-+                      break;
-               default:
-                       if (BETWEEN(attr[i], 30, 37)) {
-                               term.c.attr.fg = attr[i] - 30;
-diff --git a/st.h b/st.h
-index 3d351b6..2cfac88 100644
---- a/st.h
-+++ b/st.h
-@@ -34,6 +34,7 @@ enum glyph_attribute {
-       ATTR_WIDE       = 1 << 9,
-       ATTR_WDUMMY     = 1 << 10,
-       ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
-+      ATTR_DIRTYUNDERLINE = 1 << 15,
- };
- 
- enum selection_mode {
-@@ -65,6 +66,8 @@ typedef struct {
-       ushort mode;      /* attribute flags */
-       uint32_t fg;      /* foreground  */
-       uint32_t bg;      /* background  */
-+      int ustyle;       /* underline style */
-+      int ucolor[3];    /* underline color */
- } Glyph;
- 
- typedef Glyph *Line;
-diff --git a/st.info b/st.info
-index 8201ad6..659878c 100644
---- a/st.info
-+++ b/st.info
-@@ -1,4 +1,5 @@
- st-mono| simpleterm monocolor,
-+      Su,
-       acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
-       am,
-       bce,
-diff --git a/x.c b/x.c
-index 210f184..9a6a2bd 100644
---- a/x.c
-+++ b/x.c
-@@ -1461,8 +1461,95 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, 
Glyph base, int len, int x, i
- 
-       /* Render underline and strikethrough. */
-       if (base.mode & ATTR_UNDERLINE) {
--              XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
--                              width, 1);
-+              // Underline Color
-+              int wlw = 1; // Wave Line Width
-+              int linecolor;
-+              if ((base.ucolor[0] >= 0) &&
-+                      !(base.mode & ATTR_BLINK && win.mode & MODE_BLINK) &&
-+                      !(base.mode & ATTR_INVISIBLE)
-+              ) {
-+                      // Special color for underline
-+                      // Index
-+                      if (base.ucolor[1] < 0) {
-+                              linecolor = dc.col[base.ucolor[0]].pixel;
-+                      }
-+                      // RGB
-+                      else {
-+                              XColor lcolor;
-+                              lcolor.red = base.ucolor[0] * 257;
-+                              lcolor.green = base.ucolor[1] * 257;
-+                              lcolor.blue = base.ucolor[2] * 257;
-+                              lcolor.flags = DoRed | DoGreen | DoBlue;
-+                              XAllocColor(xw.dpy, xw.cmap, &lcolor);
-+                              linecolor = lcolor.pixel;
-+                      }
-+              } else {
-+                      // Foreground color for underline
-+                      linecolor = fg->pixel;
-+              }
-+
-+              XGCValues ugcv = {
-+                      .foreground = linecolor,
-+                      .line_width = wlw,
-+                      .line_style = LineSolid,
-+                      .cap_style = CapNotLast
-+              };
-+
-+              GC ugc = XCreateGC(xw.dpy, XftDrawDrawable(xw.draw),
-+                      GCForeground | GCLineWidth | GCLineStyle | GCCapStyle,
-+                      &ugcv);
-+
-+              // Underline Style
-+              if (base.ustyle != 3) {
-+                      //XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent 
+ 1, width, 1);
-+                      XFillRectangle(xw.dpy, XftDrawDrawable(xw.draw), ugc, 
winx,
-+                              winy + dc.font.ascent + 1, width, wlw);
-+              } else if (base.ustyle == 3) {
-+                      int ww = win.cw;//width;
-+                      int wh = dc.font.descent - wlw/2 - 1;//r.height/7;
-+                      int wx = winx;
-+                      int wy = winy + win.ch - dc.font.descent;
-+
-+                      // Draw waves
-+                      int narcs = charlen * 2 + 1;
-+                      XArc *arcs = xmalloc(sizeof(XArc) * narcs);
-+
-+                      int i = 0;
-+                      for (i = 0; i < charlen-1; i++) {
-+                              arcs[i*2] = (XArc) {
-+                                      .x = wx + win.cw * i + ww / 4,
-+                                      .y = wy,
-+                                      .width = win.cw / 2,
-+                                      .height = wh,
-+                                      .angle1 = 0,
-+                                      .angle2 = 180 * 64
-+                              };
-+                              arcs[i*2+1] = (XArc) {
-+                                      .x = wx + win.cw * i + ww * 0.75,
-+                                      .y = wy,
-+                                      .width = win.cw/2,
-+                                      .height = wh,
-+                                      .angle1 = 180 * 64,
-+                                      .angle2 = 180 * 64
-+                              };
-+                      }
-+                      // Last wave
-+                      arcs[i*2] = (XArc) {wx + ww * i + ww / 4, wy, ww / 2, 
wh,
-+                      0, 180 * 64 };
-+                      // Last wave tail
-+                      arcs[i*2+1] = (XArc) {wx + ww * i + ww * 0.75, wy, 
ceil(ww / 2.),
-+                      wh, 180 * 64, 90 * 64};
-+                      // First wave tail
-+                      i++;
-+                      arcs[i*2] = (XArc) {wx - ww/4 - 1, wy, ceil(ww / 2.), 
wh, 270 * 64,
-+                      90 * 64 };
-+
-+                      XDrawArcs(xw.dpy, XftDrawDrawable(xw.draw), ugc, arcs, 
narcs);
-+
-+                      free(arcs);
-+              }
-+
-+              XFreeGC(xw.dpy, ugc);
-       }
- 
-       if (base.mode & ATTR_STRUCK) {
diff --git a/st.suckless.org/patches/undercurl/undercurl.png 
b/st.suckless.org/patches/undercurl/undercurl.png
index dce372e9..6219b261 100644
Binary files a/st.suckless.org/patches/undercurl/undercurl.png and 
b/st.suckless.org/patches/undercurl/undercurl.png differ


Reply via email to