sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

st-undercurl-0.8.4-20210822.diff (16126B)


      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) {