-- + - frc[frclen].font = XftFontOpenPattern(xw.dpy, - fontpattern); - if (!frc[frclen].font) _AT_@ -544,6 +548,11 @@ index 2a3bd38..66605ae 100644 - - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); ++ specs[numspecs].font = frc[f].font; ++ specs[numspecs].glyph = glyphidx; ++ specs[numspecs].x = (short)xp; ++ specs[numspecs].y = (short)yp; ++ numspecs++; } - - specs[numspecs].font = frc[f].font; _AT_@ -554,6 +563,8 @@ index 2a3bd38..66605ae 100644 - numspecs++; } ++ /* Cleanup and get ready for next segment. */ ++ hbcleanup(&shaped); return numspecs; } _AT_@ -565,7 +576,9 @@ index 2a3bd38..66605ae 100644 int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, width = charlen * win.cw; Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; -_AT_@ -1510,21 +1559,24 @@ void + XRenderColor colfg, colbg; +_AT_@ -1509,23 +1525,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + void xdrawglyph(Glyph g, int x, int y) { int numspecs; _AT_@ -595,7 +608,9 @@ index 2a3bd38..66605ae 100644 if (IS_SET(MODE_HIDE)) return; -_AT_@ -1652,18 +1704,16 @@ xdrawline(Line line, int x1, int y1, int x2) + +_AT_@ -1657,30 +1676,30 @@ xdrawline(Line line, int x1, int y1, int x2) + int i, x, ox, numspecs; Glyph base, new; XftGlyphFontSpec *specs = xw.specbuf; _AT_@ -618,7 +633,8 @@ index 2a3bd38..66605ae 100644 i = 0; } if (i == 0) { -_AT_@ -1672,8 +1722,10 @@ xdrawline(Line line, int x1, int y1, int x2) + ox = x; + base = new; } i++; } _AT_@ -631,3 +647,4 @@ index 2a3bd38..66605ae 100644 } void + xfinishdraw(void) diff --git a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20240427-0.9.2.diff b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20241226-0.9.2.diff similarity index 71% rename from st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20240427-0.9.2.diff rename to st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20241226-0.9.2.diff index a4ac3f7d..7a8aa2ff 100644 --- a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20240427-0.9.2.diff +++ b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20241226-0.9.2.diff _AT_@ -1,8 +1,9 @@ diff --git a/Makefile b/Makefile -index 470ac86..38240da 100644 +index 15db421..dfcea0f 100644 --- a/Makefile +++ b/Makefile -_AT_@ -4,7 +4,7 @@ +_AT_@ -3,9 +3,9 @@ + .POSIX: include config.mk _AT_@ -11,7 +12,9 @@ index 470ac86..38240da 100644 OBJ = $(SRC:.c=.o) all: st -_AT_@ -22,7 +22,8 @@ config.h: + +_AT_@ -15,9 +15,10 @@ config.h: + .c.o: $(CC) $(STCFLAGS) -c $< st.o: config.h st.h win.h _AT_@ -21,19 +24,20 @@ index 470ac86..38240da 100644 $(OBJ): config.h config.mk + st: $(OBJ) diff --git a/config.mk b/config.mk -index 47c615e..d7439a3 100644 +index 069a6c2..977b7c7 100644 --- a/config.mk +++ b/config.mk -_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config +_AT_@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config + # includes and libs INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ - `$(PKG_CONFIG) --cflags freetype2` --LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ + `$(PKG_CONFIG) --cflags freetype2` \ + `$(PKG_CONFIG) --cflags harfbuzz` -+LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \ + LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ `$(PKG_CONFIG) --libs fontconfig` \ - `$(PKG_CONFIG) --libs freetype2` + `$(PKG_CONFIG) --libs freetype2` \ _AT_@ -41,9 +45,22 @@ index 47c615e..d7439a3 100644 # flags STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 + STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) +_AT_@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS) + # OpenBSD: + #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE + #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ + # `$(PKG_CONFIG) --libs fontconfig` \ +-# `$(PKG_CONFIG) --libs freetype2` ++# `$(PKG_CONFIG) --libs freetype2` \ ++# `$(PKG_CONFIG) --libs harfbuzz` + #MANPREFIX = ${PREFIX}/man + + # compiler and linker + # CC = c99 diff --git a/hb.c b/hb.c new file mode 100644 -index 0000000..58d534b +index 0000000..99412c8 --- /dev/null +++ b/hb.c _AT_@ -0,0 +1,125 @@ _AT_@ -193,10 +210,11 @@ index 0000000..3b0ef44 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); +void hbcleanup(HbTransformData *); diff --git a/st.c b/st.c -index 62def59..041c6d8 100644 +index b9f66e7..da33a85 100644 --- a/st.c +++ b/st.c -_AT_@ -2640,7 +2640,8 @@ draw(void) +_AT_@ -2658,9 +2658,10 @@ draw(void) + cx--; drawregion(0, 0, term.col, term.row); xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], _AT_@ -206,11 +224,13 @@ index 62def59..041c6d8 100644 term.ocx = cx; term.ocy = term.c.y; xfinishdraw(); + if (ocx != term.ocx || ocy != term.ocy) diff --git a/st.h b/st.h index 9f91e2a..b1a6256 100644 --- a/st.h +++ b/st.h -_AT_@ -11,7 +11,8 @@ +_AT_@ -10,9 +10,10 @@ + #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) _AT_@ -220,11 +240,13 @@ index 9f91e2a..b1a6256 100644 (a).bg != (b).bg) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ (t1.tv_nsec-t2.tv_nsec)/1E6) + #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) diff --git a/win.h b/win.h index 6de960d..94679e4 100644 --- a/win.h +++ b/win.h -_AT_@ -25,7 +25,7 @@ enum win_mode { +_AT_@ -24,9 +24,9 @@ enum win_mode { + }; void xbell(void); void xclipcopy(void); _AT_@ -233,11 +255,13 @@ index 6de960d..94679e4 100644 void xdrawline(Line, int, int, int); void xfinishdraw(void); void xloadcols(void); + int xsetcolorname(int, const char *); diff --git a/x.c b/x.c -index 27e81d1..0632636 100644 +index 1e12ac8..b0819ac 100644 --- a/x.c +++ b/x.c -_AT_@ -19,6 +19,7 @@ char *argv0; +_AT_@ -18,8 +18,9 @@ + char *argv0; #include "arg.h" #include "st.h" #include "win.h" _AT_@ -245,7 +269,9 @@ index 27e81d1..0632636 100644 /* types used in config.h */ typedef struct { -_AT_@ -142,8 +143,9 @@ typedef struct { + uint mod; +_AT_@ -141,10 +142,11 @@ typedef struct { + GC gc; } DC; static inline ushort sixd_to_16bit(int); _AT_@ -256,7 +282,9 @@ index 27e81d1..0632636 100644 static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static int xgeommasktogravity(int); -_AT_@ -759,7 +761,7 @@ xresize(int col, int row) + static int ximopen(Display *); +_AT_@ -758,9 +760,9 @@ xresize(int col, int row) + XftDrawChange(xw.draw, xw.buf); xclear(0, 0, win.w, win.h); /* resize to new width */ _AT_@ -265,7 +293,9 @@ index 27e81d1..0632636 100644 } ushort -_AT_@ -1071,6 +1073,9 @@ xunloadfont(Font *f) + sixd_to_16bit(int x) +_AT_@ -1070,8 +1072,11 @@ xunloadfont(Font *f) + void xunloadfonts(void) { _AT_@ -275,7 +305,9 @@ index 27e81d1..0632636 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); -_AT_@ -1202,7 +1207,7 @@ xinit(int cols, int rows) + +_AT_@ -1201,9 +1206,9 @@ xinit(int cols, int rows) + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); /* font spec buffer */ _AT_@ -284,7 +316,9 @@ index 27e81d1..0632636 100644 /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); -_AT_@ -1256,6 +1261,22 @@ xinit(int cols, int rows) + +_AT_@ -1255,144 +1260,155 @@ xinit(int cols, int rows) + if (xsel.xtarget == None) xsel.xtarget = XA_STRING; } _AT_@ -307,28 +341,42 @@ index 27e81d1..0632636 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1270,128 +1291,157 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp; +- ushort mode, prevmode = USHRT_MAX; ++ ushort mode = glyphs[0].mode & ~ATTR_WRAP; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; +- float runewidth = win.cw; ++ float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f); + Rune rune; + FT_UInt glyphidx; + FcResult fcres; FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; -+ int i, f, length = 0, start = 0, numspecs = 0; ++ int f, code_idx, numspecs = 0; + float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; -+ -+ /* Initial values. */ -+ mode = prevmode = glyphs[0].mode & ~ATTR_WRAP; -+ xresetfontsettings(mode, &font, &frcflags); - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { +- for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { - /* Fetch rune and mode for current glyph. */ - rune = glyphs[i].u; - mode = glyphs[i].mode; -+ mode = glyphs[i].mode & ~ATTR_WRAP; ++ /* Initial values. */ ++ xresetfontsettings(mode, &font, &frcflags); - /* Skip dummy wide-character spacing. */ +- /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY && i < (len - 1)) ++ /* Shape the segment. */ ++ hbtransform(&shaped, font->match, glyphs, 0, len); ++ xp = winx; yp = winy + font->ascent; ++ cluster_xp = xp; cluster_yp = yp; ++ ++ for (code_idx = 0; code_idx < shaped.count; code_idx++) { ++ int idx = shaped.glyphs[code_idx].cluster; ++ ++ if (glyphs[idx].mode & ATTR_WDUMMY) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -346,31 +394,31 @@ index 27e81d1..0632636 100644 - } else if (mode & ATTR_BOLD) { - font = &dc.bfont; - frcflags = FRC_BOLD; -+ if ( -+ prevmode != mode -+ || ATTRCMP(glyphs[start], glyphs[i]) -+ || selected(x + i, y) != selected(x + start, y) -+ || i == (len - 1) -+ ) { -+ /* Handle 1-character wide segments and end of line */ -+ length = i - start; -+ if (i == start) { -+ length = 1; -+ } else if (i == (len - 1)) { -+ length = (i - start + 1); - } +- } - yp = winy + font->ascent; -- } ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; + } - /* Lookup character index with default font. */ - glyphidx = XftCharIndex(xw.dpy, font->match, rune); - if (glyphidx) { -- specs[numspecs].font = font->match; ++ if (shaped.glyphs[code_idx].codepoint != 0) { ++ /* If symbol is found, put it into the specs. */ + specs[numspecs].font = font->match; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; -- numspecs++; ++ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; + numspecs++; - continue; - } - _AT_@ -384,105 +432,18 @@ index 27e81d1..0632636 100644 - if (!glyphidx && frc[f].flags == frcflags - && frc[f].unicodep == rune) { - break; -+ /* Shape the segment. */ -+ hbtransform(&shaped, font->match, glyphs, start, length); -+ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ cluster_xp = xp; cluster_yp = yp; -+ for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ int idx = shaped.glyphs[code_idx].cluster; -+ -+ if (glyphs[start + idx].mode & ATTR_WDUMMY) -+ continue; -+ -+ /* Advance the drawing cursor if we've moved to a new cluster */ -+ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { -+ xp += runewidth; -+ cluster_xp = xp; -+ cluster_yp = yp; -+ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ } -+ -+ if (shaped.glyphs[code_idx].codepoint != 0) { -+ /* If symbol is found, put it into the specs. */ -+ specs[numspecs].font = font->match; -+ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); -+ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); -+ cluster_xp += shaped.positions[code_idx].x_advance / 64.; -+ cluster_yp += shaped.positions[code_idx].y_advance / 64.; -+ numspecs++; -+ } else { -+ /* If it's not found, try to fetch it through the font cache. */ -+ rune = glyphs[start + idx].u; -+ for (f = 0; f < frclen; f++) { -+ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); -+ /* Everything correct. */ -+ if (glyphidx && frc[f].flags == frcflags) -+ break; -+ /* We got a default font for a not found glyph. */ -+ if (!glyphidx && frc[f].flags == frcflags -+ && frc[f].unicodep == rune) { -+ break; -+ } -+ } -+ -+ /* Nothing was found. Use fontconfig to find matching font. */ -+ if (f >= frclen) { -+ if (!font->set) -+ font->set = FcFontSort(0, font->pattern, -+ 1, 0, &fcres); -+ fcsets[0] = font->set; -+ -+ /* -+ * Nothing was found in the cache. Now use -+ * some dozen of Fontconfig calls to get the -+ * font for one single character. -+ * -+ * Xft and fontconfig are design failures. -+ */ -+ fcpattern = FcPatternDuplicate(font->pattern); -+ fccharset = FcCharSetCreate(); -+ -+ FcCharSetAddChar(fccharset, rune); -+ FcPatternAddCharSet(fcpattern, FC_CHARSET, -+ fccharset); -+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); -+ -+ FcConfigSubstitute(0, fcpattern, -+ FcMatchPattern); -+ FcDefaultSubstitute(fcpattern); -+ -+ fontpattern = FcFontSetMatch(0, fcsets, 1, -+ fcpattern, &fcres); -+ -+ /* Allocate memory for the new cache entry. */ -+ if (frclen >= frccap) { -+ frccap += 16; -+ frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ } -+ -+ frc[frclen].font = XftFontOpenPattern(xw.dpy, -+ fontpattern); -+ if (!frc[frclen].font) -+ die("XftFontOpenPattern failed seeking fallback font: %s ", -+ strerror(errno)); -+ frc[frclen].flags = frcflags; -+ frc[frclen].unicodep = rune; -+ -+ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); -+ -+ f = frclen; -+ frclen++; -+ -+ FcPatternDestroy(fcpattern); -+ FcCharSetDestroy(fccharset); -+ } -+ -+ specs[numspecs].font = frc[f].font; -+ specs[numspecs].glyph = glyphidx; -+ specs[numspecs].x = (short)xp; -+ specs[numspecs].y = (short)yp; -+ numspecs++; ++ } else { ++ /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[idx].u; ++ for (f = 0; f < frclen; f++) { ++ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); ++ /* Everything correct. */ ++ if (glyphidx && frc[f].flags == frcflags) ++ break; ++ /* We got a default font for a not found glyph. */ ++ if (!glyphidx && frc[f].flags == frcflags ++ && frc[f].unicodep == rune) { ++ break; + } } - } _AT_@ -493,10 +454,7 @@ index 27e81d1..0632636 100644 - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; -+ /* Cleanup and get ready for next segment. */ -+ hbcleanup(&shaped); -+ start = i; - +- - /* - * Nothing was found in the cache. Now use - * some dozen of Fontconfig calls to get the _AT_@ -523,13 +481,58 @@ index 27e81d1..0632636 100644 - if (frclen >= frccap) { - frccap += 16; - frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ /* Determine font for glyph if different from previous glyph. */ -+ if (prevmode != mode) { -+ prevmode = mode; -+ xresetfontsettings(mode, &font, &frcflags); -+ yp = winy + font->ascent; ++ /* Nothing was found. Use fontconfig to find matching font. */ ++ if (f >= frclen) { ++ if (!font->set) ++ font->set = FcFontSort(0, font->pattern, ++ 1, 0, &fcres); ++ fcsets[0] = font->set; ++ ++ /* ++ * Nothing was found in the cache. Now use ++ * some dozen of Fontconfig calls to get the ++ * font for one single character. ++ * ++ * Xft and fontconfig are design failures. ++ */ ++ fcpattern = FcPatternDuplicate(font->pattern); ++ fccharset = FcCharSetCreate(); ++ ++ FcCharSetAddChar(fccharset, rune); ++ FcPatternAddCharSet(fcpattern, FC_CHARSET, ++ fccharset); ++ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); ++ ++ FcConfigSubstitute(0, fcpattern, ++ FcMatchPattern); ++ FcDefaultSubstitute(fcpattern); ++ ++ fontpattern = FcFontSetMatch(0, fcsets, 1, ++ fcpattern, &fcres); ++ ++ /* Allocate memory for the new cache entry. */ ++ if (frclen >= frccap) { ++ frccap += 16; ++ frc = xrealloc(frc, frccap * sizeof(Fontcache)); ++ } ++ ++ frc[frclen].font = XftFontOpenPattern(xw.dpy, ++ fontpattern); ++ if (!frc[frclen].font) ++ die("XftFontOpenPattern failed seeking fallback font: %s ", ++ strerror(errno)); ++ frc[frclen].flags = frcflags; ++ frc[frclen].unicodep = rune; ++ ++ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); ++ ++ f = frclen; ++ frclen++; ++ ++ FcPatternDestroy(fcpattern); ++ FcCharSetDestroy(fccharset); } -- + - frc[frclen].font = XftFontOpenPattern(xw.dpy, - fontpattern); - if (!frc[frclen].font) _AT_@ -545,6 +548,11 @@ index 27e81d1..0632636 100644 - - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); ++ specs[numspecs].font = frc[f].font; ++ specs[numspecs].glyph = glyphidx; ++ specs[numspecs].x = (short)xp; ++ specs[numspecs].y = (short)yp; ++ numspecs++; } - - specs[numspecs].font = frc[f].font; _AT_@ -555,6 +563,7 @@ index 27e81d1..0632636 100644 - numspecs++; } ++ /* Cleanup and get ready for next segment. */ + hbcleanup(&shaped); return numspecs; } _AT_@ -567,7 +576,9 @@ index 27e81d1..0632636 100644 int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, width = charlen * win.cw; Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; -_AT_@ -1527,21 +1577,24 @@ void + XRenderColor colfg, colbg; +_AT_@ -1526,23 +1542,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + void xdrawglyph(Glyph g, int x, int y) { int numspecs; _AT_@ -597,7 +608,9 @@ index 27e81d1..0632636 100644 if (IS_SET(MODE_HIDE)) return; -_AT_@ -1669,18 +1722,16 @@ xdrawline(Line line, int x1, int y1, int x2) + +_AT_@ -1674,30 +1693,30 @@ xdrawline(Line line, int x1, int y1, int x2) + int i, x, ox, numspecs; Glyph base, new; XftGlyphFontSpec *specs = xw.specbuf; _AT_@ -620,7 +633,8 @@ index 27e81d1..0632636 100644 i = 0; } if (i == 0) { -_AT_@ -1689,8 +1740,10 @@ xdrawline(Line line, int x1, int y1, int x2) + ox = x; + base = new; } i++; } _AT_@ -633,3 +647,4 @@ index 27e81d1..0632636 100644 } void + xfinishdraw(void) diff --git a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20240427-0.9.2.diff b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20241226-0.9.2.diff similarity index 71% rename from st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20240427-0.9.2.diff rename to st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20241226-0.9.2.diff index 3e9d6751..00abd127 100644 --- a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20240427-0.9.2.diff +++ b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20241226-0.9.2.diff _AT_@ -1,8 +1,9 @@ diff --git a/Makefile b/Makefile -index 470ac86..38240da 100644 +index 15db421..dfcea0f 100644 --- a/Makefile +++ b/Makefile -_AT_@ -4,7 +4,7 @@ +_AT_@ -3,9 +3,9 @@ + .POSIX: include config.mk _AT_@ -11,7 +12,9 @@ index 470ac86..38240da 100644 OBJ = $(SRC:.c=.o) all: st -_AT_@ -22,7 +22,8 @@ config.h: + +_AT_@ -15,9 +15,10 @@ config.h: + .c.o: $(CC) $(STCFLAGS) -c $< st.o: config.h st.h win.h _AT_@ -21,19 +24,20 @@ index 470ac86..38240da 100644 $(OBJ): config.h config.mk + st: $(OBJ) diff --git a/config.mk b/config.mk -index 47c615e..d7439a3 100644 +index 069a6c2..977b7c7 100644 --- a/config.mk +++ b/config.mk -_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config +_AT_@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config + # includes and libs INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ - `$(PKG_CONFIG) --cflags freetype2` --LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ + `$(PKG_CONFIG) --cflags freetype2` \ + `$(PKG_CONFIG) --cflags harfbuzz` -+LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \ + LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ `$(PKG_CONFIG) --libs fontconfig` \ - `$(PKG_CONFIG) --libs freetype2` + `$(PKG_CONFIG) --libs freetype2` \ _AT_@ -41,6 +45,19 @@ index 47c615e..d7439a3 100644 # flags STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 + STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) +_AT_@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS) + # OpenBSD: + #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE + #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ + # `$(PKG_CONFIG) --libs fontconfig` \ +-# `$(PKG_CONFIG) --libs freetype2` ++# `$(PKG_CONFIG) --libs freetype2` \ ++# `$(PKG_CONFIG) --libs harfbuzz` + #MANPREFIX = ${PREFIX}/man + + # compiler and linker + # CC = c99 diff --git a/hb.c b/hb.c new file mode 100644 index 0000000..99412c8 _AT_@ -193,25 +210,27 @@ index 0000000..3b0ef44 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); +void hbcleanup(HbTransformData *); diff --git a/st.c b/st.c -index 79ee9ba..454771d 100644 +index 2478942..bba90d3 100644 --- a/st.c +++ b/st.c -_AT_@ -2711,7 +2711,9 @@ draw(void) +_AT_@ -2729,9 +2729,10 @@ draw(void) + drawregion(0, 0, term.col, term.row); if (term.scr == 0) xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], - term.ocx, term.ocy, term.line[term.ocy][term.ocx]); + term.ocx, term.ocy, term.line[term.ocy][term.ocx], + term.line[term.ocy], term.col); -+ term.ocx = cx; term.ocy = term.c.y; xfinishdraw(); + if (ocx != term.ocx || ocy != term.ocy) diff --git a/st.h b/st.h index 78762a2..01eea49 100644 --- a/st.h +++ b/st.h -_AT_@ -11,7 +11,8 @@ +_AT_@ -10,9 +10,10 @@ + #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) _AT_@ -221,11 +240,13 @@ index 78762a2..01eea49 100644 (a).bg != (b).bg) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ (t1.tv_nsec-t2.tv_nsec)/1E6) + #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) diff --git a/win.h b/win.h index 6de960d..94679e4 100644 --- a/win.h +++ b/win.h -_AT_@ -25,7 +25,7 @@ enum win_mode { +_AT_@ -24,9 +24,9 @@ enum win_mode { + }; void xbell(void); void xclipcopy(void); _AT_@ -234,11 +255,13 @@ index 6de960d..94679e4 100644 void xdrawline(Line, int, int, int); void xfinishdraw(void); void xloadcols(void); + int xsetcolorname(int, const char *); diff --git a/x.c b/x.c -index 27e81d1..5e11c1f 100644 +index 1e12ac8..b0819ac 100644 --- a/x.c +++ b/x.c -_AT_@ -19,6 +19,7 @@ char *argv0; +_AT_@ -18,8 +18,9 @@ + char *argv0; #include "arg.h" #include "st.h" #include "win.h" _AT_@ -246,7 +269,9 @@ index 27e81d1..5e11c1f 100644 /* types used in config.h */ typedef struct { -_AT_@ -142,8 +143,9 @@ typedef struct { + uint mod; +_AT_@ -141,10 +142,11 @@ typedef struct { + GC gc; } DC; static inline ushort sixd_to_16bit(int); _AT_@ -257,7 +282,9 @@ index 27e81d1..5e11c1f 100644 static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static int xgeommasktogravity(int); -_AT_@ -759,7 +761,7 @@ xresize(int col, int row) + static int ximopen(Display *); +_AT_@ -758,9 +760,9 @@ xresize(int col, int row) + XftDrawChange(xw.draw, xw.buf); xclear(0, 0, win.w, win.h); /* resize to new width */ _AT_@ -266,7 +293,9 @@ index 27e81d1..5e11c1f 100644 } ushort -_AT_@ -1071,6 +1073,9 @@ xunloadfont(Font *f) + sixd_to_16bit(int x) +_AT_@ -1070,8 +1072,11 @@ xunloadfont(Font *f) + void xunloadfonts(void) { _AT_@ -276,7 +305,9 @@ index 27e81d1..5e11c1f 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); -_AT_@ -1202,7 +1207,7 @@ xinit(int cols, int rows) + +_AT_@ -1201,9 +1206,9 @@ xinit(int cols, int rows) + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); /* font spec buffer */ _AT_@ -285,7 +316,9 @@ index 27e81d1..5e11c1f 100644 /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); -_AT_@ -1256,6 +1261,22 @@ xinit(int cols, int rows) + +_AT_@ -1255,144 +1260,155 @@ xinit(int cols, int rows) + if (xsel.xtarget == None) xsel.xtarget = XA_STRING; } _AT_@ -308,28 +341,42 @@ index 27e81d1..5e11c1f 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1270,128 +1291,156 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp; +- ushort mode, prevmode = USHRT_MAX; ++ ushort mode = glyphs[0].mode & ~ATTR_WRAP; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; +- float runewidth = win.cw; ++ float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f); + Rune rune; + FT_UInt glyphidx; + FcResult fcres; FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; -+ int i, f, length = 0, start = 0, numspecs = 0; ++ int f, code_idx, numspecs = 0; + float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; -+ -+ /* Initial values. */ -+ mode = prevmode = glyphs[0].mode & ~ATTR_WRAP; -+ xresetfontsettings(mode, &font, &frcflags); - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { +- for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { - /* Fetch rune and mode for current glyph. */ - rune = glyphs[i].u; - mode = glyphs[i].mode; -+ mode = glyphs[i].mode & ~ATTR_WRAP; ++ /* Initial values. */ ++ xresetfontsettings(mode, &font, &frcflags); - /* Skip dummy wide-character spacing. */ +- /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY && i < (len - 1)) ++ /* Shape the segment. */ ++ hbtransform(&shaped, font->match, glyphs, 0, len); ++ xp = winx; yp = winy + font->ascent; ++ cluster_xp = xp; cluster_yp = yp; ++ ++ for (code_idx = 0; code_idx < shaped.count; code_idx++) { ++ int idx = shaped.glyphs[code_idx].cluster; ++ ++ if (glyphs[idx].mode & ATTR_WDUMMY) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -347,31 +394,31 @@ index 27e81d1..5e11c1f 100644 - } else if (mode & ATTR_BOLD) { - font = &dc.bfont; - frcflags = FRC_BOLD; -+ if ( -+ prevmode != mode -+ || ATTRCMP(glyphs[start], glyphs[i]) -+ || selected(x + i, y) != selected(x + start, y) -+ || i == (len - 1) -+ ) { -+ /* Handle 1-character wide segments and end of line */ -+ length = i - start; -+ if (i == start) { -+ length = 1; -+ } else if (i == (len - 1)) { -+ length = (i - start + 1); - } +- } - yp = winy + font->ascent; -- } ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; + } - /* Lookup character index with default font. */ - glyphidx = XftCharIndex(xw.dpy, font->match, rune); - if (glyphidx) { -- specs[numspecs].font = font->match; ++ if (shaped.glyphs[code_idx].codepoint != 0) { ++ /* If symbol is found, put it into the specs. */ + specs[numspecs].font = font->match; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; -- numspecs++; ++ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; + numspecs++; - continue; - } - _AT_@ -385,105 +432,18 @@ index 27e81d1..5e11c1f 100644 - if (!glyphidx && frc[f].flags == frcflags - && frc[f].unicodep == rune) { - break; -+ /* Shape the segment. */ -+ hbtransform(&shaped, font->match, glyphs, start, length); -+ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ cluster_xp = xp; cluster_yp = yp; -+ for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ int idx = shaped.glyphs[code_idx].cluster; -+ -+ if (glyphs[start + idx].mode & ATTR_WDUMMY) -+ continue; -+ -+ /* Advance the drawing cursor if we've moved to a new cluster */ -+ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { -+ xp += runewidth; -+ cluster_xp = xp; -+ cluster_yp = yp; -+ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ } -+ -+ if (shaped.glyphs[code_idx].codepoint != 0) { -+ /* If symbol is found, put it into the specs. */ -+ specs[numspecs].font = font->match; -+ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); -+ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); -+ cluster_xp += shaped.positions[code_idx].x_advance / 64.; -+ cluster_yp += shaped.positions[code_idx].y_advance / 64.; -+ numspecs++; -+ } else { -+ /* If it's not found, try to fetch it through the font cache. */ -+ rune = glyphs[start + idx].u; -+ for (f = 0; f < frclen; f++) { -+ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); -+ /* Everything correct. */ -+ if (glyphidx && frc[f].flags == frcflags) -+ break; -+ /* We got a default font for a not found glyph. */ -+ if (!glyphidx && frc[f].flags == frcflags -+ && frc[f].unicodep == rune) { -+ break; -+ } -+ } -+ -+ /* Nothing was found. Use fontconfig to find matching font. */ -+ if (f >= frclen) { -+ if (!font->set) -+ font->set = FcFontSort(0, font->pattern, -+ 1, 0, &fcres); -+ fcsets[0] = font->set; -+ -+ /* -+ * Nothing was found in the cache. Now use -+ * some dozen of Fontconfig calls to get the -+ * font for one single character. -+ * -+ * Xft and fontconfig are design failures. -+ */ -+ fcpattern = FcPatternDuplicate(font->pattern); -+ fccharset = FcCharSetCreate(); -+ -+ FcCharSetAddChar(fccharset, rune); -+ FcPatternAddCharSet(fcpattern, FC_CHARSET, -+ fccharset); -+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); -+ -+ FcConfigSubstitute(0, fcpattern, -+ FcMatchPattern); -+ FcDefaultSubstitute(fcpattern); -+ -+ fontpattern = FcFontSetMatch(0, fcsets, 1, -+ fcpattern, &fcres); -+ -+ /* Allocate memory for the new cache entry. */ -+ if (frclen >= frccap) { -+ frccap += 16; -+ frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ } -+ -+ frc[frclen].font = XftFontOpenPattern(xw.dpy, -+ fontpattern); -+ if (!frc[frclen].font) -+ die("XftFontOpenPattern failed seeking fallback font: %s ", -+ strerror(errno)); -+ frc[frclen].flags = frcflags; -+ frc[frclen].unicodep = rune; -+ -+ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); -+ -+ f = frclen; -+ frclen++; -+ -+ FcPatternDestroy(fcpattern); -+ FcCharSetDestroy(fccharset); -+ } -+ -+ specs[numspecs].font = frc[f].font; -+ specs[numspecs].glyph = glyphidx; -+ specs[numspecs].x = (short)xp; -+ specs[numspecs].y = (short)yp; -+ numspecs++; ++ } else { ++ /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[idx].u; ++ for (f = 0; f < frclen; f++) { ++ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); ++ /* Everything correct. */ ++ if (glyphidx && frc[f].flags == frcflags) ++ break; ++ /* We got a default font for a not found glyph. */ ++ if (!glyphidx && frc[f].flags == frcflags ++ && frc[f].unicodep == rune) { ++ break; + } } - } _AT_@ -494,10 +454,7 @@ index 27e81d1..5e11c1f 100644 - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; -+ /* Cleanup and get ready for next segment. */ -+ hbcleanup(&shaped); -+ start = i; - +- - /* - * Nothing was found in the cache. Now use - * some dozen of Fontconfig calls to get the _AT_@ -524,13 +481,58 @@ index 27e81d1..5e11c1f 100644 - if (frclen >= frccap) { - frccap += 16; - frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ /* Determine font for glyph if different from previous glyph. */ -+ if (prevmode != mode) { -+ prevmode = mode; -+ xresetfontsettings(mode, &font, &frcflags); -+ yp = winy + font->ascent; ++ /* Nothing was found. Use fontconfig to find matching font. */ ++ if (f >= frclen) { ++ if (!font->set) ++ font->set = FcFontSort(0, font->pattern, ++ 1, 0, &fcres); ++ fcsets[0] = font->set; ++ ++ /* ++ * Nothing was found in the cache. Now use ++ * some dozen of Fontconfig calls to get the ++ * font for one single character. ++ * ++ * Xft and fontconfig are design failures. ++ */ ++ fcpattern = FcPatternDuplicate(font->pattern); ++ fccharset = FcCharSetCreate(); ++ ++ FcCharSetAddChar(fccharset, rune); ++ FcPatternAddCharSet(fcpattern, FC_CHARSET, ++ fccharset); ++ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); ++ ++ FcConfigSubstitute(0, fcpattern, ++ FcMatchPattern); ++ FcDefaultSubstitute(fcpattern); ++ ++ fontpattern = FcFontSetMatch(0, fcsets, 1, ++ fcpattern, &fcres); ++ ++ /* Allocate memory for the new cache entry. */ ++ if (frclen >= frccap) { ++ frccap += 16; ++ frc = xrealloc(frc, frccap * sizeof(Fontcache)); ++ } ++ ++ frc[frclen].font = XftFontOpenPattern(xw.dpy, ++ fontpattern); ++ if (!frc[frclen].font) ++ die("XftFontOpenPattern failed seeking fallback font: %s ", ++ strerror(errno)); ++ frc[frclen].flags = frcflags; ++ frc[frclen].unicodep = rune; ++ ++ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); ++ ++ f = frclen; ++ frclen++; ++ ++ FcPatternDestroy(fcpattern); ++ FcCharSetDestroy(fccharset); } -- + - frc[frclen].font = XftFontOpenPattern(xw.dpy, - fontpattern); - if (!frc[frclen].font) _AT_@ -546,6 +548,11 @@ index 27e81d1..5e11c1f 100644 - - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); ++ specs[numspecs].font = frc[f].font; ++ specs[numspecs].glyph = glyphidx; ++ specs[numspecs].x = (short)xp; ++ specs[numspecs].y = (short)yp; ++ numspecs++; } - - specs[numspecs].font = frc[f].font; _AT_@ -556,6 +563,8 @@ index 27e81d1..5e11c1f 100644 - numspecs++; } ++ /* Cleanup and get ready for next segment. */ ++ hbcleanup(&shaped); return numspecs; } _AT_@ -567,7 +576,9 @@ index 27e81d1..5e11c1f 100644 int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, width = charlen * win.cw; Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; -_AT_@ -1527,21 +1576,24 @@ void + XRenderColor colfg, colbg; +_AT_@ -1526,23 +1542,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + void xdrawglyph(Glyph g, int x, int y) { int numspecs; _AT_@ -597,7 +608,9 @@ index 27e81d1..5e11c1f 100644 if (IS_SET(MODE_HIDE)) return; -_AT_@ -1669,18 +1721,16 @@ xdrawline(Line line, int x1, int y1, int x2) + +_AT_@ -1674,30 +1693,30 @@ xdrawline(Line line, int x1, int y1, int x2) + int i, x, ox, numspecs; Glyph base, new; XftGlyphFontSpec *specs = xw.specbuf; _AT_@ -620,7 +633,8 @@ index 27e81d1..5e11c1f 100644 i = 0; } if (i == 0) { -_AT_@ -1689,8 +1739,10 @@ xdrawline(Line line, int x1, int y1, int x2) + ox = x; + base = new; } i++; } _AT_@ -633,3 +647,4 @@ index 27e81d1..5e11c1f 100644 } void + xfinishdraw(void) diff --git a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20240427-0.9.2.diff b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20241226-0.9.2.diff similarity index 71% rename from st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20240427-0.9.2.diff rename to st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20241226-0.9.2.diff index 5d03b4df..49f33829 100644 --- a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20240427-0.9.2.diff +++ b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20241226-0.9.2.diff _AT_@ -1,8 +1,9 @@ diff --git a/Makefile b/Makefile -index 470ac86..38240da 100644 +index 15db421..dfcea0f 100644 --- a/Makefile +++ b/Makefile -_AT_@ -4,7 +4,7 @@ +_AT_@ -3,9 +3,9 @@ + .POSIX: include config.mk _AT_@ -11,7 +12,9 @@ index 470ac86..38240da 100644 OBJ = $(SRC:.c=.o) all: st -_AT_@ -22,7 +22,8 @@ config.h: + +_AT_@ -15,9 +15,10 @@ config.h: + .c.o: $(CC) $(STCFLAGS) -c $< st.o: config.h st.h win.h _AT_@ -21,19 +24,20 @@ index 470ac86..38240da 100644 $(OBJ): config.h config.mk + st: $(OBJ) diff --git a/config.mk b/config.mk -index 47c615e..d7439a3 100644 +index 069a6c2..977b7c7 100644 --- a/config.mk +++ b/config.mk -_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config +_AT_@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config + # includes and libs INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ - `$(PKG_CONFIG) --cflags freetype2` --LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ + `$(PKG_CONFIG) --cflags freetype2` \ + `$(PKG_CONFIG) --cflags harfbuzz` -+LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \ + LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ `$(PKG_CONFIG) --libs fontconfig` \ - `$(PKG_CONFIG) --libs freetype2` + `$(PKG_CONFIG) --libs freetype2` \ _AT_@ -41,6 +45,19 @@ index 47c615e..d7439a3 100644 # flags STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 + STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) +_AT_@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS) + # OpenBSD: + #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE + #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ + # `$(PKG_CONFIG) --libs fontconfig` \ +-# `$(PKG_CONFIG) --libs freetype2` ++# `$(PKG_CONFIG) --libs freetype2` \ ++# `$(PKG_CONFIG) --libs harfbuzz` + #MANPREFIX = ${PREFIX}/man + + # compiler and linker + # CC = c99 diff --git a/hb.c b/hb.c new file mode 100644 index 0000000..99412c8 _AT_@ -193,25 +210,27 @@ index 0000000..3b0ef44 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); +void hbcleanup(HbTransformData *); diff --git a/st.c b/st.c -index c44797b..18aa1bf 100644 +index d9b163e..fbca4ba 100644 --- a/st.c +++ b/st.c -_AT_@ -2759,7 +2759,9 @@ draw(void) +_AT_@ -2777,9 +2777,10 @@ draw(void) + drawregion(0, 0, term.col, term.row); if (TSCREEN.off == 0) xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx], - term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]); + term.ocx, term.ocy, TLINE(term.ocy)[term.ocx], + TLINE(term.ocy), term.col); -+ term.ocx = cx; term.ocy = term.c.y; xfinishdraw(); + if (ocx != term.ocx || ocy != term.ocy) diff --git a/st.h b/st.h index 073851a..d0b071d 100644 --- a/st.h +++ b/st.h -_AT_@ -11,7 +11,8 @@ +_AT_@ -10,9 +10,10 @@ + #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) _AT_@ -221,11 +240,13 @@ index 073851a..d0b071d 100644 (a).bg != (b).bg) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ (t1.tv_nsec-t2.tv_nsec)/1E6) + #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) diff --git a/win.h b/win.h index 6de960d..94679e4 100644 --- a/win.h +++ b/win.h -_AT_@ -25,7 +25,7 @@ enum win_mode { +_AT_@ -24,9 +24,9 @@ enum win_mode { + }; void xbell(void); void xclipcopy(void); _AT_@ -234,11 +255,13 @@ index 6de960d..94679e4 100644 void xdrawline(Line, int, int, int); void xfinishdraw(void); void xloadcols(void); + int xsetcolorname(int, const char *); diff --git a/x.c b/x.c -index b81f5be..c1611bb 100644 +index c497e53..a213e52 100644 --- a/x.c +++ b/x.c -_AT_@ -19,6 +19,7 @@ char *argv0; +_AT_@ -18,8 +18,9 @@ + char *argv0; #include "arg.h" #include "st.h" #include "win.h" _AT_@ -246,7 +269,9 @@ index b81f5be..c1611bb 100644 /* types used in config.h */ typedef struct { -_AT_@ -144,8 +145,9 @@ typedef struct { + uint mod; +_AT_@ -143,10 +144,11 @@ typedef struct { + GC gc; } DC; static inline ushort sixd_to_16bit(int); _AT_@ -257,7 +282,9 @@ index b81f5be..c1611bb 100644 static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static int xgeommasktogravity(int); -_AT_@ -761,7 +763,7 @@ xresize(int col, int row) + static int ximopen(Display *); +_AT_@ -760,9 +762,9 @@ xresize(int col, int row) + XftDrawChange(xw.draw, xw.buf); xclear(0, 0, win.w, win.h); /* resize to new width */ _AT_@ -266,7 +293,9 @@ index b81f5be..c1611bb 100644 } ushort -_AT_@ -1073,6 +1075,9 @@ xunloadfont(Font *f) + sixd_to_16bit(int x) +_AT_@ -1072,8 +1074,11 @@ xunloadfont(Font *f) + void xunloadfonts(void) { _AT_@ -276,7 +305,9 @@ index b81f5be..c1611bb 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); -_AT_@ -1204,7 +1209,7 @@ xinit(int cols, int rows) + +_AT_@ -1203,9 +1208,9 @@ xinit(int cols, int rows) + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); /* font spec buffer */ _AT_@ -285,7 +316,9 @@ index b81f5be..c1611bb 100644 /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); -_AT_@ -1258,6 +1263,22 @@ xinit(int cols, int rows) + +_AT_@ -1257,144 +1262,155 @@ xinit(int cols, int rows) + if (xsel.xtarget == None) xsel.xtarget = XA_STRING; } _AT_@ -308,28 +341,42 @@ index b81f5be..c1611bb 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1272,128 +1293,156 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp; +- ushort mode, prevmode = USHRT_MAX; ++ ushort mode = glyphs[0].mode & ~ATTR_WRAP; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; +- float runewidth = win.cw; ++ float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f); + Rune rune; + FT_UInt glyphidx; + FcResult fcres; FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; -+ int i, f, length = 0, start = 0, numspecs = 0; ++ int f, code_idx, numspecs = 0; + float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; -+ -+ /* Initial values. */ -+ mode = prevmode = glyphs[0].mode & ~ATTR_WRAP; -+ xresetfontsettings(mode, &font, &frcflags); - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { +- for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { - /* Fetch rune and mode for current glyph. */ - rune = glyphs[i].u; - mode = glyphs[i].mode; -+ mode = glyphs[i].mode & ~ATTR_WRAP; ++ /* Initial values. */ ++ xresetfontsettings(mode, &font, &frcflags); - /* Skip dummy wide-character spacing. */ +- /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY && i < (len - 1)) ++ /* Shape the segment. */ ++ hbtransform(&shaped, font->match, glyphs, 0, len); ++ xp = winx; yp = winy + font->ascent; ++ cluster_xp = xp; cluster_yp = yp; ++ ++ for (code_idx = 0; code_idx < shaped.count; code_idx++) { ++ int idx = shaped.glyphs[code_idx].cluster; ++ ++ if (glyphs[idx].mode & ATTR_WDUMMY) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -347,31 +394,31 @@ index b81f5be..c1611bb 100644 - } else if (mode & ATTR_BOLD) { - font = &dc.bfont; - frcflags = FRC_BOLD; -+ if ( -+ prevmode != mode -+ || ATTRCMP(glyphs[start], glyphs[i]) -+ || selected(x + i, y) != selected(x + start, y) -+ || i == (len - 1) -+ ) { -+ /* Handle 1-character wide segments and end of line */ -+ length = i - start; -+ if (i == start) { -+ length = 1; -+ } else if (i == (len - 1)) { -+ length = (i - start + 1); - } +- } - yp = winy + font->ascent; -- } ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; + } - /* Lookup character index with default font. */ - glyphidx = XftCharIndex(xw.dpy, font->match, rune); - if (glyphidx) { -- specs[numspecs].font = font->match; ++ if (shaped.glyphs[code_idx].codepoint != 0) { ++ /* If symbol is found, put it into the specs. */ + specs[numspecs].font = font->match; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; -- numspecs++; ++ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; + numspecs++; - continue; - } - _AT_@ -385,105 +432,18 @@ index b81f5be..c1611bb 100644 - if (!glyphidx && frc[f].flags == frcflags - && frc[f].unicodep == rune) { - break; -+ /* Shape the segment. */ -+ hbtransform(&shaped, font->match, glyphs, start, length); -+ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ cluster_xp = xp; cluster_yp = yp; -+ for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ int idx = shaped.glyphs[code_idx].cluster; -+ -+ if (glyphs[start + idx].mode & ATTR_WDUMMY) -+ continue; -+ -+ /* Advance the drawing cursor if we've moved to a new cluster */ -+ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { -+ xp += runewidth; -+ cluster_xp = xp; -+ cluster_yp = yp; -+ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ } -+ -+ if (shaped.glyphs[code_idx].codepoint != 0) { -+ /* If symbol is found, put it into the specs. */ -+ specs[numspecs].font = font->match; -+ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); -+ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); -+ cluster_xp += shaped.positions[code_idx].x_advance / 64.; -+ cluster_yp += shaped.positions[code_idx].y_advance / 64.; -+ numspecs++; -+ } else { -+ /* If it's not found, try to fetch it through the font cache. */ -+ rune = glyphs[start + idx].u; -+ for (f = 0; f < frclen; f++) { -+ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); -+ /* Everything correct. */ -+ if (glyphidx && frc[f].flags == frcflags) -+ break; -+ /* We got a default font for a not found glyph. */ -+ if (!glyphidx && frc[f].flags == frcflags -+ && frc[f].unicodep == rune) { -+ break; -+ } -+ } -+ -+ /* Nothing was found. Use fontconfig to find matching font. */ -+ if (f >= frclen) { -+ if (!font->set) -+ font->set = FcFontSort(0, font->pattern, -+ 1, 0, &fcres); -+ fcsets[0] = font->set; -+ -+ /* -+ * Nothing was found in the cache. Now use -+ * some dozen of Fontconfig calls to get the -+ * font for one single character. -+ * -+ * Xft and fontconfig are design failures. -+ */ -+ fcpattern = FcPatternDuplicate(font->pattern); -+ fccharset = FcCharSetCreate(); -+ -+ FcCharSetAddChar(fccharset, rune); -+ FcPatternAddCharSet(fcpattern, FC_CHARSET, -+ fccharset); -+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); -+ -+ FcConfigSubstitute(0, fcpattern, -+ FcMatchPattern); -+ FcDefaultSubstitute(fcpattern); -+ -+ fontpattern = FcFontSetMatch(0, fcsets, 1, -+ fcpattern, &fcres); -+ -+ /* Allocate memory for the new cache entry. */ -+ if (frclen >= frccap) { -+ frccap += 16; -+ frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ } -+ -+ frc[frclen].font = XftFontOpenPattern(xw.dpy, -+ fontpattern); -+ if (!frc[frclen].font) -+ die("XftFontOpenPattern failed seeking fallback font: %s ", -+ strerror(errno)); -+ frc[frclen].flags = frcflags; -+ frc[frclen].unicodep = rune; -+ -+ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); -+ -+ f = frclen; -+ frclen++; -+ -+ FcPatternDestroy(fcpattern); -+ FcCharSetDestroy(fccharset); -+ } -+ -+ specs[numspecs].font = frc[f].font; -+ specs[numspecs].glyph = glyphidx; -+ specs[numspecs].x = (short)xp; -+ specs[numspecs].y = (short)yp; -+ numspecs++; ++ } else { ++ /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[idx].u; ++ for (f = 0; f < frclen; f++) { ++ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); ++ /* Everything correct. */ ++ if (glyphidx && frc[f].flags == frcflags) ++ break; ++ /* We got a default font for a not found glyph. */ ++ if (!glyphidx && frc[f].flags == frcflags ++ && frc[f].unicodep == rune) { ++ break; + } } - } _AT_@ -494,10 +454,7 @@ index b81f5be..c1611bb 100644 - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; -+ /* Cleanup and get ready for next segment. */ -+ hbcleanup(&shaped); -+ start = i; - +- - /* - * Nothing was found in the cache. Now use - * some dozen of Fontconfig calls to get the _AT_@ -524,13 +481,58 @@ index b81f5be..c1611bb 100644 - if (frclen >= frccap) { - frccap += 16; - frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ /* Determine font for glyph if different from previous glyph. */ -+ if (prevmode != mode) { -+ prevmode = mode; -+ xresetfontsettings(mode, &font, &frcflags); -+ yp = winy + font->ascent; ++ /* Nothing was found. Use fontconfig to find matching font. */ ++ if (f >= frclen) { ++ if (!font->set) ++ font->set = FcFontSort(0, font->pattern, ++ 1, 0, &fcres); ++ fcsets[0] = font->set; ++ ++ /* ++ * Nothing was found in the cache. Now use ++ * some dozen of Fontconfig calls to get the ++ * font for one single character. ++ * ++ * Xft and fontconfig are design failures. ++ */ ++ fcpattern = FcPatternDuplicate(font->pattern); ++ fccharset = FcCharSetCreate(); ++ ++ FcCharSetAddChar(fccharset, rune); ++ FcPatternAddCharSet(fcpattern, FC_CHARSET, ++ fccharset); ++ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); ++ ++ FcConfigSubstitute(0, fcpattern, ++ FcMatchPattern); ++ FcDefaultSubstitute(fcpattern); ++ ++ fontpattern = FcFontSetMatch(0, fcsets, 1, ++ fcpattern, &fcres); ++ ++ /* Allocate memory for the new cache entry. */ ++ if (frclen >= frccap) { ++ frccap += 16; ++ frc = xrealloc(frc, frccap * sizeof(Fontcache)); ++ } ++ ++ frc[frclen].font = XftFontOpenPattern(xw.dpy, ++ fontpattern); ++ if (!frc[frclen].font) ++ die("XftFontOpenPattern failed seeking fallback font: %s ", ++ strerror(errno)); ++ frc[frclen].flags = frcflags; ++ frc[frclen].unicodep = rune; ++ ++ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); ++ ++ f = frclen; ++ frclen++; ++ ++ FcPatternDestroy(fcpattern); ++ FcCharSetDestroy(fccharset); } -- + - frc[frclen].font = XftFontOpenPattern(xw.dpy, - fontpattern); - if (!frc[frclen].font) _AT_@ -546,6 +548,11 @@ index b81f5be..c1611bb 100644 - - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); ++ specs[numspecs].font = frc[f].font; ++ specs[numspecs].glyph = glyphidx; ++ specs[numspecs].x = (short)xp; ++ specs[numspecs].y = (short)yp; ++ numspecs++; } - - specs[numspecs].font = frc[f].font; _AT_@ -556,6 +563,8 @@ index b81f5be..c1611bb 100644 - numspecs++; } ++ /* Cleanup and get ready for next segment. */ ++ hbcleanup(&shaped); return numspecs; } _AT_@ -567,7 +576,9 @@ index b81f5be..c1611bb 100644 int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, width = charlen * win.cw; Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; -_AT_@ -1529,21 +1578,24 @@ void + XRenderColor colfg, colbg; +_AT_@ -1528,23 +1544,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + void xdrawglyph(Glyph g, int x, int y) { int numspecs; _AT_@ -597,7 +608,9 @@ index b81f5be..c1611bb 100644 if (IS_SET(MODE_HIDE)) return; -_AT_@ -1671,18 +1723,16 @@ xdrawline(Line line, int x1, int y1, int x2) + +_AT_@ -1676,30 +1695,30 @@ xdrawline(Line line, int x1, int y1, int x2) + int i, x, ox, numspecs; Glyph base, new; XftGlyphFontSpec *specs = xw.specbuf; _AT_@ -620,7 +633,8 @@ index b81f5be..c1611bb 100644 i = 0; } if (i == 0) { -_AT_@ -1691,8 +1741,10 @@ xdrawline(Line line, int x1, int y1, int x2) + ox = x; + base = new; } i++; } _AT_@ -633,3 +647,4 @@ index b81f5be..c1611bb 100644 } void + xfinishdraw(void) diff --git a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20240427-0.9.2.diff b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20241226-0.9.2.diff similarity index 70% rename from st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20240427-0.9.2.diff rename to st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20241226-0.9.2.diff index 2a92a30b..1f8799c9 100644 --- a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20240427-0.9.2.diff +++ b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20241226-0.9.2.diff _AT_@ -1,8 +1,9 @@ diff --git a/Makefile b/Makefile -index 6dfa212..adfa07a 100644 +index a64b4c2..05124bf 100644 --- a/Makefile +++ b/Makefile -_AT_@ -4,7 +4,7 @@ +_AT_@ -3,9 +3,9 @@ + .POSIX: include config.mk _AT_@ -11,7 +12,9 @@ index 6dfa212..adfa07a 100644 OBJ = $(SRC:.c=.o) all: st -_AT_@ -22,8 +22,9 @@ config.h: + +_AT_@ -15,10 +15,11 @@ config.h: + .c.o: $(CC) $(STCFLAGS) -c $< st.o: config.h st.h win.h _AT_@ -22,11 +25,13 @@ index 6dfa212..adfa07a 100644 $(OBJ): config.h config.mk + st: $(OBJ) diff --git a/config.mk b/config.mk -index 1e306f8..3e13e53 100644 +index fdc29a7..6833b3b 100644 --- a/config.mk +++ b/config.mk -_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config +_AT_@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config + # includes and libs INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ _AT_@ -41,6 +46,19 @@ index 1e306f8..3e13e53 100644 # flags STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 + STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) +_AT_@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS) + # OpenBSD: + #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE + #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ + # `$(PKG_CONFIG) --libs fontconfig` \ +-# `$(PKG_CONFIG) --libs freetype2` ++# `$(PKG_CONFIG) --libs freetype2` \ ++# `$(PKG_CONFIG) --libs harfbuzz` + #MANPREFIX = ${PREFIX}/man + + # compiler and linker + # CC = c99 diff --git a/hb.c b/hb.c new file mode 100644 index 0000000..99412c8 _AT_@ -193,10 +211,11 @@ index 0000000..3b0ef44 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); +void hbcleanup(HbTransformData *); diff --git a/st.c b/st.c -index 41d5ace..1c2edd6 100644 +index ec6fbf3..1385f77 100644 --- a/st.c +++ b/st.c -_AT_@ -2643,7 +2643,8 @@ draw(void) +_AT_@ -2661,9 +2661,10 @@ draw(void) + cx--; drawregion(0, 0, term.col, term.row); xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], _AT_@ -206,11 +225,13 @@ index 41d5ace..1c2edd6 100644 term.ocx = cx; term.ocy = term.c.y; xfinishdraw(); + if (ocx != term.ocx || ocy != term.ocy) diff --git a/st.h b/st.h index 808f5f7..ae41368 100644 --- a/st.h +++ b/st.h -_AT_@ -11,7 +11,8 @@ +_AT_@ -10,9 +10,10 @@ + #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) _AT_@ -220,11 +241,13 @@ index 808f5f7..ae41368 100644 (a).bg != (b).bg) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ (t1.tv_nsec-t2.tv_nsec)/1E6) + #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) diff --git a/win.h b/win.h index 6de960d..94679e4 100644 --- a/win.h +++ b/win.h -_AT_@ -25,7 +25,7 @@ enum win_mode { +_AT_@ -24,9 +24,9 @@ enum win_mode { + }; void xbell(void); void xclipcopy(void); _AT_@ -233,11 +256,13 @@ index 6de960d..94679e4 100644 void xdrawline(Line, int, int, int); void xfinishdraw(void); void xloadcols(void); + int xsetcolorname(int, const char *); diff --git a/x.c b/x.c -index bf6bbf9..96b117f 100644 +index 978a8fc..c2d9993 100644 --- a/x.c +++ b/x.c -_AT_@ -19,6 +19,7 @@ char *argv0; +_AT_@ -18,8 +18,9 @@ + char *argv0; #include "arg.h" #include "st.h" #include "win.h" _AT_@ -245,7 +270,9 @@ index bf6bbf9..96b117f 100644 /* types used in config.h */ typedef struct { -_AT_@ -141,8 +142,9 @@ typedef struct { + uint mod; +_AT_@ -140,10 +141,11 @@ typedef struct { + GC gc; } DC; static inline ushort sixd_to_16bit(int); _AT_@ -256,7 +283,9 @@ index bf6bbf9..96b117f 100644 static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static int xgeommasktogravity(int); -_AT_@ -757,7 +759,7 @@ xresize(int col, int row) + static int ximopen(Display *); +_AT_@ -756,9 +758,9 @@ xresize(int col, int row) + XftDrawChange(xw.draw, xw.buf); xclear(0, 0, win.w, win.h); /* resize to new width */ _AT_@ -265,7 +294,9 @@ index bf6bbf9..96b117f 100644 } ushort -_AT_@ -1062,6 +1064,9 @@ xunloadfont(Font *f) + sixd_to_16bit(int x) +_AT_@ -1061,8 +1063,11 @@ xunloadfont(Font *f) + void xunloadfonts(void) { _AT_@ -275,7 +306,9 @@ index bf6bbf9..96b117f 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); -_AT_@ -1185,7 +1190,7 @@ xinit(int cols, int rows) + +_AT_@ -1184,9 +1189,9 @@ xinit(int cols, int rows) + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); /* font spec buffer */ _AT_@ -284,7 +317,9 @@ index bf6bbf9..96b117f 100644 /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); -_AT_@ -1241,6 +1246,22 @@ xinit(int cols, int rows) + +_AT_@ -1240,149 +1245,162 @@ xinit(int cols, int rows) + boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis); } _AT_@ -307,28 +342,42 @@ index bf6bbf9..96b117f 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1255,133 +1276,164 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp; +- ushort mode, prevmode = USHRT_MAX; ++ ushort mode = glyphs[0].mode & ~ATTR_WRAP; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; +- float runewidth = win.cw; ++ float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f); + Rune rune; + FT_UInt glyphidx; + FcResult fcres; FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; -+ int i, f, length = 0, start = 0, numspecs = 0; ++ int f, code_idx, numspecs = 0; + float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; -+ -+ /* Initial values. */ -+ mode = prevmode = glyphs[0].mode & ~ATTR_WRAP; -+ xresetfontsettings(mode, &font, &frcflags); - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { +- for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { - /* Fetch rune and mode for current glyph. */ - rune = glyphs[i].u; - mode = glyphs[i].mode; -+ mode = glyphs[i].mode & ~ATTR_WRAP; ++ /* Initial values. */ ++ xresetfontsettings(mode, &font, &frcflags); - /* Skip dummy wide-character spacing. */ +- /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY && i < (len - 1)) ++ /* Shape the segment. */ ++ hbtransform(&shaped, font->match, glyphs, 0, len); ++ xp = winx; yp = winy + font->ascent; ++ cluster_xp = xp; cluster_yp = yp; ++ ++ for (code_idx = 0; code_idx < shaped.count; code_idx++) { ++ int idx = shaped.glyphs[code_idx].cluster; ++ ++ if (glyphs[idx].mode & ATTR_WDUMMY) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -346,36 +395,33 @@ index bf6bbf9..96b117f 100644 - } else if (mode & ATTR_BOLD) { - font = &dc.bfont; - frcflags = FRC_BOLD; -+ if ( -+ prevmode != mode -+ || ATTRCMP(glyphs[start], glyphs[i]) -+ || selected(x + i, y) != selected(x + start, y) -+ || i == (len - 1) -+ ) { -+ /* Handle 1-character wide segments and end of line */ -+ length = i - start; -+ if (i == start) { -+ length = 1; -+ } else if (i == (len - 1)) { -+ length = (i - start + 1); - } +- } - yp = winy + font->ascent; -- } ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; + } - if (mode & ATTR_BOXDRAW) { -- /* minor shoehorning: boxdraw uses only this ushort */ ++ if (glyphs[idx].mode & ATTR_BOXDRAW) { + /* minor shoehorning: boxdraw uses only this ushort */ - glyphidx = boxdrawindex(&glyphs[i]); - } else { - /* Lookup character index with default font. */ - glyphidx = XftCharIndex(xw.dpy, font->match, rune); - } - if (glyphidx) { -- specs[numspecs].font = font->match; + specs[numspecs].font = font->match; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; -- numspecs++; ++ specs[numspecs].glyph = boxdrawindex(&glyphs[idx]); ++ specs[numspecs].x = xp; ++ specs[numspecs].y = yp; + numspecs++; - continue; - } - _AT_@ -389,126 +435,38 @@ index bf6bbf9..96b117f 100644 - if (!glyphidx && frc[f].flags == frcflags - && frc[f].unicodep == rune) { - break; -+ /* Shape the segment. */ -+ hbtransform(&shaped, font->match, glyphs, start, length); -+ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ cluster_xp = xp; cluster_yp = yp; -+ for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ int idx = shaped.glyphs[code_idx].cluster; -+ -+ if (glyphs[start + idx].mode & ATTR_WDUMMY) -+ continue; -+ -+ /* Advance the drawing cursor if we've moved to a new cluster */ -+ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { -+ xp += runewidth; -+ cluster_xp = xp; -+ cluster_yp = yp; -+ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ } -+ -+ if (glyphs[start + idx].mode & ATTR_BOXDRAW) { -+ /* minor shoehorning: boxdraw uses only this ushort */ -+ specs[numspecs].font = font->match; -+ specs[numspecs].glyph = boxdrawindex(&glyphs[start + idx]); -+ specs[numspecs].x = xp; -+ specs[numspecs].y = yp; -+ numspecs++; -+ } else if (shaped.glyphs[code_idx].codepoint != 0) { -+ /* If symbol is found, put it into the specs. */ -+ specs[numspecs].font = font->match; -+ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); -+ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); -+ cluster_xp += shaped.positions[code_idx].x_advance / 64.; -+ cluster_yp += shaped.positions[code_idx].y_advance / 64.; -+ numspecs++; -+ } else { -+ /* If it's not found, try to fetch it through the font cache. */ -+ rune = glyphs[start + idx].u; -+ for (f = 0; f < frclen; f++) { -+ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); -+ /* Everything correct. */ -+ if (glyphidx && frc[f].flags == frcflags) -+ break; -+ /* We got a default font for a not found glyph. */ -+ if (!glyphidx && frc[f].flags == frcflags -+ && frc[f].unicodep == rune) { -+ break; -+ } -+ } -+ -+ /* Nothing was found. Use fontconfig to find matching font. */ -+ if (f >= frclen) { -+ if (!font->set) -+ font->set = FcFontSort(0, font->pattern, -+ 1, 0, &fcres); -+ fcsets[0] = font->set; -+ -+ /* -+ * Nothing was found in the cache. Now use -+ * some dozen of Fontconfig calls to get the -+ * font for one single character. -+ * -+ * Xft and fontconfig are design failures. -+ */ -+ fcpattern = FcPatternDuplicate(font->pattern); -+ fccharset = FcCharSetCreate(); -+ -+ FcCharSetAddChar(fccharset, rune); -+ FcPatternAddCharSet(fcpattern, FC_CHARSET, -+ fccharset); -+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); -+ -+ FcConfigSubstitute(0, fcpattern, -+ FcMatchPattern); -+ FcDefaultSubstitute(fcpattern); -+ -+ fontpattern = FcFontSetMatch(0, fcsets, 1, -+ fcpattern, &fcres); -+ -+ /* Allocate memory for the new cache entry. */ -+ if (frclen >= frccap) { -+ frccap += 16; -+ frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ } -+ -+ frc[frclen].font = XftFontOpenPattern(xw.dpy, -+ fontpattern); -+ if (!frc[frclen].font) -+ die("XftFontOpenPattern failed seeking fallback font: %s ", -+ strerror(errno)); -+ frc[frclen].flags = frcflags; -+ frc[frclen].unicodep = rune; -+ -+ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); -+ -+ f = frclen; -+ frclen++; -+ -+ FcPatternDestroy(fcpattern); -+ FcCharSetDestroy(fccharset); -+ } -+ -+ specs[numspecs].font = frc[f].font; -+ specs[numspecs].glyph = glyphidx; -+ specs[numspecs].x = (short)xp; -+ specs[numspecs].y = (short)yp; -+ numspecs++; ++ } else if (shaped.glyphs[code_idx].codepoint != 0) { ++ /* If symbol is found, put it into the specs. */ ++ specs[numspecs].font = font->match; ++ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; ++ numspecs++; ++ } else { ++ /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[idx].u; ++ for (f = 0; f < frclen; f++) { ++ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); ++ /* Everything correct. */ ++ if (glyphidx && frc[f].flags == frcflags) ++ break; ++ /* We got a default font for a not found glyph. */ ++ if (!glyphidx && frc[f].flags == frcflags ++ && frc[f].unicodep == rune) { ++ break; + } } - } - +- - /* Nothing was found. Use fontconfig to find matching font. */ - if (f >= frclen) { - if (!font->set) - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; -+ /* Cleanup and get ready for next segment. */ -+ hbcleanup(&shaped); -+ start = i; - +- - /* - * Nothing was found in the cache. Now use - * some dozen of Fontconfig calls to get the _AT_@ -527,7 +485,7 @@ index bf6bbf9..96b117f 100644 - FcConfigSubstitute(0, fcpattern, - FcMatchPattern); - FcDefaultSubstitute(fcpattern); -- + - fontpattern = FcFontSetMatch(0, fcsets, 1, - fcpattern, &fcres); - _AT_@ -535,13 +493,58 @@ index bf6bbf9..96b117f 100644 - if (frclen >= frccap) { - frccap += 16; - frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ /* Determine font for glyph if different from previous glyph. */ -+ if (prevmode != mode) { -+ prevmode = mode; -+ xresetfontsettings(mode, &font, &frcflags); -+ yp = winy + font->ascent; ++ /* Nothing was found. Use fontconfig to find matching font. */ ++ if (f >= frclen) { ++ if (!font->set) ++ font->set = FcFontSort(0, font->pattern, ++ 1, 0, &fcres); ++ fcsets[0] = font->set; ++ ++ /* ++ * Nothing was found in the cache. Now use ++ * some dozen of Fontconfig calls to get the ++ * font for one single character. ++ * ++ * Xft and fontconfig are design failures. ++ */ ++ fcpattern = FcPatternDuplicate(font->pattern); ++ fccharset = FcCharSetCreate(); ++ ++ FcCharSetAddChar(fccharset, rune); ++ FcPatternAddCharSet(fcpattern, FC_CHARSET, ++ fccharset); ++ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); ++ ++ FcConfigSubstitute(0, fcpattern, ++ FcMatchPattern); ++ FcDefaultSubstitute(fcpattern); ++ ++ fontpattern = FcFontSetMatch(0, fcsets, 1, ++ fcpattern, &fcres); ++ ++ /* Allocate memory for the new cache entry. */ ++ if (frclen >= frccap) { ++ frccap += 16; ++ frc = xrealloc(frc, frccap * sizeof(Fontcache)); ++ } ++ ++ frc[frclen].font = XftFontOpenPattern(xw.dpy, ++ fontpattern); ++ if (!frc[frclen].font) ++ die("XftFontOpenPattern failed seeking fallback font: %s ", ++ strerror(errno)); ++ frc[frclen].flags = frcflags; ++ frc[frclen].unicodep = rune; ++ ++ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); ++ ++ f = frclen; ++ frclen++; ++ ++ FcPatternDestroy(fcpattern); ++ FcCharSetDestroy(fccharset); } -- + - frc[frclen].font = XftFontOpenPattern(xw.dpy, - fontpattern); - if (!frc[frclen].font) _AT_@ -557,6 +560,11 @@ index bf6bbf9..96b117f 100644 - - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); ++ specs[numspecs].font = frc[f].font; ++ specs[numspecs].glyph = glyphidx; ++ specs[numspecs].x = (short)xp; ++ specs[numspecs].y = (short)yp; ++ numspecs++; } - - specs[numspecs].font = frc[f].font; _AT_@ -567,6 +575,7 @@ index bf6bbf9..96b117f 100644 - numspecs++; } ++ /* Cleanup and get ready for next segment. */ + hbcleanup(&shaped); return numspecs; } _AT_@ -579,7 +588,9 @@ index bf6bbf9..96b117f 100644 int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, width = charlen * win.cw; Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; -_AT_@ -1521,21 +1573,24 @@ void + XRenderColor colfg, colbg; +_AT_@ -1520,23 +1538,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + void xdrawglyph(Glyph g, int x, int y) { int numspecs; _AT_@ -609,7 +620,9 @@ index bf6bbf9..96b117f 100644 if (IS_SET(MODE_HIDE)) return; -_AT_@ -1663,18 +1718,16 @@ xdrawline(Line line, int x1, int y1, int x2) + +_AT_@ -1668,30 +1689,30 @@ xdrawline(Line line, int x1, int y1, int x2) + int i, x, ox, numspecs; Glyph base, new; XftGlyphFontSpec *specs = xw.specbuf; _AT_@ -632,7 +645,8 @@ index bf6bbf9..96b117f 100644 i = 0; } if (i == 0) { -_AT_@ -1683,8 +1736,10 @@ xdrawline(Line line, int x1, int y1, int x2) + ox = x; + base = new; } i++; } _AT_@ -645,3 +659,4 @@ index bf6bbf9..96b117f 100644 } void + xfinishdraw(void) diff --git a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20240427-0.9.2.diff b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20241226-0.9.2.diff similarity index 71% rename from st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20240427-0.9.2.diff rename to st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20241226-0.9.2.diff index 92edf9a1..86d3939f 100644 --- a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20240427-0.9.2.diff +++ b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20241226-0.9.2.diff _AT_@ -1,8 +1,9 @@ diff --git a/Makefile b/Makefile -index 470ac86..38240da 100644 +index 15db421..dfcea0f 100644 --- a/Makefile +++ b/Makefile -_AT_@ -4,7 +4,7 @@ +_AT_@ -3,9 +3,9 @@ + .POSIX: include config.mk _AT_@ -11,7 +12,9 @@ index 470ac86..38240da 100644 OBJ = $(SRC:.c=.o) all: st -_AT_@ -22,7 +22,8 @@ config.h: + +_AT_@ -15,9 +15,10 @@ config.h: + .c.o: $(CC) $(STCFLAGS) -c $< st.o: config.h st.h win.h _AT_@ -21,11 +24,13 @@ index 470ac86..38240da 100644 $(OBJ): config.h config.mk + st: $(OBJ) diff --git a/config.mk b/config.mk -index 1e306f8..3e13e53 100644 +index fdc29a7..6833b3b 100644 --- a/config.mk +++ b/config.mk -_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config +_AT_@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config + # includes and libs INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ _AT_@ -40,6 +45,19 @@ index 1e306f8..3e13e53 100644 # flags STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 + STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) +_AT_@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS) + # OpenBSD: + #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE + #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ + # `$(PKG_CONFIG) --libs fontconfig` \ +-# `$(PKG_CONFIG) --libs freetype2` ++# `$(PKG_CONFIG) --libs freetype2` \ ++# `$(PKG_CONFIG) --libs harfbuzz` + #MANPREFIX = ${PREFIX}/man + + # compiler and linker + # CC = c99 diff --git a/hb.c b/hb.c new file mode 100644 index 0000000..99412c8 _AT_@ -192,10 +210,11 @@ index 0000000..3b0ef44 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); +void hbcleanup(HbTransformData *); diff --git a/st.c b/st.c -index 79ee9ba..7675db6 100644 +index 2478942..bba90d3 100644 --- a/st.c +++ b/st.c -_AT_@ -2711,7 +2711,8 @@ draw(void) +_AT_@ -2729,9 +2729,10 @@ draw(void) + drawregion(0, 0, term.col, term.row); if (term.scr == 0) xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], _AT_@ -205,11 +224,13 @@ index 79ee9ba..7675db6 100644 term.ocx = cx; term.ocy = term.c.y; xfinishdraw(); + if (ocx != term.ocx || ocy != term.ocy) diff --git a/st.h b/st.h index 818a6f8..4e584b6 100644 --- a/st.h +++ b/st.h -_AT_@ -11,7 +11,8 @@ +_AT_@ -10,9 +10,10 @@ + #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) _AT_@ -219,11 +240,13 @@ index 818a6f8..4e584b6 100644 (a).bg != (b).bg) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ (t1.tv_nsec-t2.tv_nsec)/1E6) + #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) diff --git a/win.h b/win.h index 6de960d..94679e4 100644 --- a/win.h +++ b/win.h -_AT_@ -25,7 +25,7 @@ enum win_mode { +_AT_@ -24,9 +24,9 @@ enum win_mode { + }; void xbell(void); void xclipcopy(void); _AT_@ -232,11 +255,13 @@ index 6de960d..94679e4 100644 void xdrawline(Line, int, int, int); void xfinishdraw(void); void xloadcols(void); + int xsetcolorname(int, const char *); diff --git a/x.c b/x.c -index 2a3bd38..0bb51ff 100644 +index bd23686..2bf3b72 100644 --- a/x.c +++ b/x.c -_AT_@ -19,6 +19,7 @@ char *argv0; +_AT_@ -18,8 +18,9 @@ + char *argv0; #include "arg.h" #include "st.h" #include "win.h" _AT_@ -244,7 +269,9 @@ index 2a3bd38..0bb51ff 100644 /* types used in config.h */ typedef struct { -_AT_@ -141,8 +142,9 @@ typedef struct { + uint mod; +_AT_@ -140,10 +141,11 @@ typedef struct { + GC gc; } DC; static inline ushort sixd_to_16bit(int); _AT_@ -255,7 +282,9 @@ index 2a3bd38..0bb51ff 100644 static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static int xgeommasktogravity(int); -_AT_@ -757,7 +759,7 @@ xresize(int col, int row) + static int ximopen(Display *); +_AT_@ -756,9 +758,9 @@ xresize(int col, int row) + XftDrawChange(xw.draw, xw.buf); xclear(0, 0, win.w, win.h); /* resize to new width */ _AT_@ -264,7 +293,9 @@ index 2a3bd38..0bb51ff 100644 } ushort -_AT_@ -1062,6 +1064,9 @@ xunloadfont(Font *f) + sixd_to_16bit(int x) +_AT_@ -1061,8 +1063,11 @@ xunloadfont(Font *f) + void xunloadfonts(void) { _AT_@ -274,7 +305,9 @@ index 2a3bd38..0bb51ff 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); -_AT_@ -1185,7 +1190,7 @@ xinit(int cols, int rows) + +_AT_@ -1184,9 +1189,9 @@ xinit(int cols, int rows) + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); /* font spec buffer */ _AT_@ -283,7 +316,9 @@ index 2a3bd38..0bb51ff 100644 /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); -_AT_@ -1239,6 +1244,22 @@ xinit(int cols, int rows) + +_AT_@ -1238,144 +1243,155 @@ xinit(int cols, int rows) + if (xsel.xtarget == None) xsel.xtarget = XA_STRING; } _AT_@ -306,28 +341,42 @@ index 2a3bd38..0bb51ff 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1253,128 +1274,157 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp; +- ushort mode, prevmode = USHRT_MAX; ++ ushort mode = glyphs[0].mode & ~ATTR_WRAP; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; +- float runewidth = win.cw; ++ float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f); + Rune rune; + FT_UInt glyphidx; + FcResult fcres; FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; -+ int i, f, length = 0, start = 0, numspecs = 0; ++ int f, code_idx, numspecs = 0; + float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; -+ -+ /* Initial values. */ -+ mode = prevmode = glyphs[0].mode & ~ATTR_WRAP; -+ xresetfontsettings(mode, &font, &frcflags); - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { +- for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { - /* Fetch rune and mode for current glyph. */ - rune = glyphs[i].u; - mode = glyphs[i].mode; -+ mode = glyphs[i].mode & ~ATTR_WRAP; ++ /* Initial values. */ ++ xresetfontsettings(mode, &font, &frcflags); - /* Skip dummy wide-character spacing. */ +- /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY && i < (len - 1)) ++ /* Shape the segment. */ ++ hbtransform(&shaped, font->match, glyphs, 0, len); ++ xp = winx; yp = winy + font->ascent; ++ cluster_xp = xp; cluster_yp = yp; ++ ++ for (code_idx = 0; code_idx < shaped.count; code_idx++) { ++ int idx = shaped.glyphs[code_idx].cluster; ++ ++ if (glyphs[idx].mode & ATTR_WDUMMY) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -345,31 +394,31 @@ index 2a3bd38..0bb51ff 100644 - } else if (mode & ATTR_BOLD) { - font = &dc.bfont; - frcflags = FRC_BOLD; -+ if ( -+ prevmode != mode -+ || ATTRCMP(glyphs[start], glyphs[i]) -+ || selected(x + i, y) != selected(x + start, y) -+ || i == (len - 1) -+ ) { -+ /* Handle 1-character wide segments and end of line */ -+ length = i - start; -+ if (i == start) { -+ length = 1; -+ } else if (i == (len - 1)) { -+ length = (i - start + 1); - } +- } - yp = winy + font->ascent; -- } ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; + } - /* Lookup character index with default font. */ - glyphidx = XftCharIndex(xw.dpy, font->match, rune); - if (glyphidx) { -- specs[numspecs].font = font->match; ++ if (shaped.glyphs[code_idx].codepoint != 0) { ++ /* If symbol is found, put it into the specs. */ + specs[numspecs].font = font->match; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; -- numspecs++; ++ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; + numspecs++; - continue; - } - _AT_@ -383,105 +432,18 @@ index 2a3bd38..0bb51ff 100644 - if (!glyphidx && frc[f].flags == frcflags - && frc[f].unicodep == rune) { - break; -+ /* Shape the segment. */ -+ hbtransform(&shaped, font->match, glyphs, start, length); -+ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ cluster_xp = xp; cluster_yp = yp; -+ for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ int idx = shaped.glyphs[code_idx].cluster; -+ -+ if (glyphs[start + idx].mode & ATTR_WDUMMY) -+ continue; -+ -+ /* Advance the drawing cursor if we've moved to a new cluster */ -+ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { -+ xp += runewidth; -+ cluster_xp = xp; -+ cluster_yp = yp; -+ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ } -+ -+ if (shaped.glyphs[code_idx].codepoint != 0) { -+ /* If symbol is found, put it into the specs. */ -+ specs[numspecs].font = font->match; -+ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); -+ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); -+ cluster_xp += shaped.positions[code_idx].x_advance / 64.; -+ cluster_yp += shaped.positions[code_idx].y_advance / 64.; -+ numspecs++; -+ } else { -+ /* If it's not found, try to fetch it through the font cache. */ -+ rune = glyphs[start + idx].u; -+ for (f = 0; f < frclen; f++) { -+ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); -+ /* Everything correct. */ -+ if (glyphidx && frc[f].flags == frcflags) -+ break; -+ /* We got a default font for a not found glyph. */ -+ if (!glyphidx && frc[f].flags == frcflags -+ && frc[f].unicodep == rune) { -+ break; -+ } -+ } -+ -+ /* Nothing was found. Use fontconfig to find matching font. */ -+ if (f >= frclen) { -+ if (!font->set) -+ font->set = FcFontSort(0, font->pattern, -+ 1, 0, &fcres); -+ fcsets[0] = font->set; -+ -+ /* -+ * Nothing was found in the cache. Now use -+ * some dozen of Fontconfig calls to get the -+ * font for one single character. -+ * -+ * Xft and fontconfig are design failures. -+ */ -+ fcpattern = FcPatternDuplicate(font->pattern); -+ fccharset = FcCharSetCreate(); -+ -+ FcCharSetAddChar(fccharset, rune); -+ FcPatternAddCharSet(fcpattern, FC_CHARSET, -+ fccharset); -+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); -+ -+ FcConfigSubstitute(0, fcpattern, -+ FcMatchPattern); -+ FcDefaultSubstitute(fcpattern); -+ -+ fontpattern = FcFontSetMatch(0, fcsets, 1, -+ fcpattern, &fcres); -+ -+ /* Allocate memory for the new cache entry. */ -+ if (frclen >= frccap) { -+ frccap += 16; -+ frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ } -+ -+ frc[frclen].font = XftFontOpenPattern(xw.dpy, -+ fontpattern); -+ if (!frc[frclen].font) -+ die("XftFontOpenPattern failed seeking fallback font: %s ", -+ strerror(errno)); -+ frc[frclen].flags = frcflags; -+ frc[frclen].unicodep = rune; -+ -+ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); -+ -+ f = frclen; -+ frclen++; -+ -+ FcPatternDestroy(fcpattern); -+ FcCharSetDestroy(fccharset); -+ } -+ -+ specs[numspecs].font = frc[f].font; -+ specs[numspecs].glyph = glyphidx; -+ specs[numspecs].x = (short)xp; -+ specs[numspecs].y = (short)yp; -+ numspecs++; ++ } else { ++ /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[idx].u; ++ for (f = 0; f < frclen; f++) { ++ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); ++ /* Everything correct. */ ++ if (glyphidx && frc[f].flags == frcflags) ++ break; ++ /* We got a default font for a not found glyph. */ ++ if (!glyphidx && frc[f].flags == frcflags ++ && frc[f].unicodep == rune) { ++ break; + } } - } _AT_@ -492,10 +454,7 @@ index 2a3bd38..0bb51ff 100644 - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; -+ /* Cleanup and get ready for next segment. */ -+ hbcleanup(&shaped); -+ start = i; - +- - /* - * Nothing was found in the cache. Now use - * some dozen of Fontconfig calls to get the _AT_@ -522,13 +481,58 @@ index 2a3bd38..0bb51ff 100644 - if (frclen >= frccap) { - frccap += 16; - frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ /* Determine font for glyph if different from previous glyph. */ -+ if (prevmode != mode) { -+ prevmode = mode; -+ xresetfontsettings(mode, &font, &frcflags); -+ yp = winy + font->ascent; ++ /* Nothing was found. Use fontconfig to find matching font. */ ++ if (f >= frclen) { ++ if (!font->set) ++ font->set = FcFontSort(0, font->pattern, ++ 1, 0, &fcres); ++ fcsets[0] = font->set; ++ ++ /* ++ * Nothing was found in the cache. Now use ++ * some dozen of Fontconfig calls to get the ++ * font for one single character. ++ * ++ * Xft and fontconfig are design failures. ++ */ ++ fcpattern = FcPatternDuplicate(font->pattern); ++ fccharset = FcCharSetCreate(); ++ ++ FcCharSetAddChar(fccharset, rune); ++ FcPatternAddCharSet(fcpattern, FC_CHARSET, ++ fccharset); ++ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); ++ ++ FcConfigSubstitute(0, fcpattern, ++ FcMatchPattern); ++ FcDefaultSubstitute(fcpattern); ++ ++ fontpattern = FcFontSetMatch(0, fcsets, 1, ++ fcpattern, &fcres); ++ ++ /* Allocate memory for the new cache entry. */ ++ if (frclen >= frccap) { ++ frccap += 16; ++ frc = xrealloc(frc, frccap * sizeof(Fontcache)); ++ } ++ ++ frc[frclen].font = XftFontOpenPattern(xw.dpy, ++ fontpattern); ++ if (!frc[frclen].font) ++ die("XftFontOpenPattern failed seeking fallback font: %s ", ++ strerror(errno)); ++ frc[frclen].flags = frcflags; ++ frc[frclen].unicodep = rune; ++ ++ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); ++ ++ f = frclen; ++ frclen++; ++ ++ FcPatternDestroy(fcpattern); ++ FcCharSetDestroy(fccharset); } -- + - frc[frclen].font = XftFontOpenPattern(xw.dpy, - fontpattern); - if (!frc[frclen].font) _AT_@ -544,6 +548,11 @@ index 2a3bd38..0bb51ff 100644 - - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); ++ specs[numspecs].font = frc[f].font; ++ specs[numspecs].glyph = glyphidx; ++ specs[numspecs].x = (short)xp; ++ specs[numspecs].y = (short)yp; ++ numspecs++; } - - specs[numspecs].font = frc[f].font; _AT_@ -554,6 +563,7 @@ index 2a3bd38..0bb51ff 100644 - numspecs++; } ++ /* Cleanup and get ready for next segment. */ + hbcleanup(&shaped); return numspecs; } _AT_@ -566,7 +576,9 @@ index 2a3bd38..0bb51ff 100644 int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, width = charlen * win.cw; Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; -_AT_@ -1510,21 +1560,24 @@ void + XRenderColor colfg, colbg; +_AT_@ -1509,23 +1525,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + void xdrawglyph(Glyph g, int x, int y) { int numspecs; _AT_@ -596,7 +608,9 @@ index 2a3bd38..0bb51ff 100644 if (IS_SET(MODE_HIDE)) return; -_AT_@ -1652,18 +1705,16 @@ xdrawline(Line line, int x1, int y1, int x2) + +_AT_@ -1657,30 +1676,30 @@ xdrawline(Line line, int x1, int y1, int x2) + int i, x, ox, numspecs; Glyph base, new; XftGlyphFontSpec *specs = xw.specbuf; _AT_@ -619,7 +633,8 @@ index 2a3bd38..0bb51ff 100644 i = 0; } if (i == 0) { -_AT_@ -1672,8 +1723,10 @@ xdrawline(Line line, int x1, int y1, int x2) + ox = x; + base = new; } i++; } _AT_@ -632,3 +647,4 @@ index 2a3bd38..0bb51ff 100644 } void + xfinishdraw(void) diff --git a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20240427-0.9.2.diff b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20241226-0.9.2.diff similarity index 71% rename from st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20240427-0.9.2.diff rename to st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20241226-0.9.2.diff index 26105db4..6f3fd265 100644 --- a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20240427-0.9.2.diff +++ b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20241226-0.9.2.diff _AT_@ -1,8 +1,9 @@ diff --git a/Makefile b/Makefile -index 470ac86..38240da 100644 +index 15db421..dfcea0f 100644 --- a/Makefile +++ b/Makefile -_AT_@ -4,7 +4,7 @@ +_AT_@ -3,9 +3,9 @@ + .POSIX: include config.mk _AT_@ -11,7 +12,9 @@ index 470ac86..38240da 100644 OBJ = $(SRC:.c=.o) all: st -_AT_@ -22,7 +22,8 @@ config.h: + +_AT_@ -15,9 +15,10 @@ config.h: + .c.o: $(CC) $(STCFLAGS) -c $< st.o: config.h st.h win.h _AT_@ -21,11 +24,13 @@ index 470ac86..38240da 100644 $(OBJ): config.h config.mk + st: $(OBJ) diff --git a/config.mk b/config.mk -index 1e306f8..3e13e53 100644 +index fdc29a7..6833b3b 100644 --- a/config.mk +++ b/config.mk -_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config +_AT_@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config + # includes and libs INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ _AT_@ -40,6 +45,19 @@ index 1e306f8..3e13e53 100644 # flags STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 + STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) +_AT_@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS) + # OpenBSD: + #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE + #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ + # `$(PKG_CONFIG) --libs fontconfig` \ +-# `$(PKG_CONFIG) --libs freetype2` ++# `$(PKG_CONFIG) --libs freetype2` \ ++# `$(PKG_CONFIG) --libs harfbuzz` + #MANPREFIX = ${PREFIX}/man + + # compiler and linker + # CC = c99 diff --git a/hb.c b/hb.c new file mode 100644 index 0000000..99412c8 _AT_@ -192,10 +210,11 @@ index 0000000..3b0ef44 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); +void hbcleanup(HbTransformData *); diff --git a/st.c b/st.c -index c44797b..91f54dc 100644 +index d9b163e..fbca4ba 100644 --- a/st.c +++ b/st.c -_AT_@ -2759,7 +2759,8 @@ draw(void) +_AT_@ -2777,9 +2777,10 @@ draw(void) + drawregion(0, 0, term.col, term.row); if (TSCREEN.off == 0) xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx], _AT_@ -205,11 +224,13 @@ index c44797b..91f54dc 100644 term.ocx = cx; term.ocy = term.c.y; xfinishdraw(); + if (ocx != term.ocx || ocy != term.ocy) diff --git a/st.h b/st.h index 3cea73b..709a369 100644 --- a/st.h +++ b/st.h -_AT_@ -11,7 +11,8 @@ +_AT_@ -10,9 +10,10 @@ + #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) _AT_@ -219,11 +240,13 @@ index 3cea73b..709a369 100644 (a).bg != (b).bg) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ (t1.tv_nsec-t2.tv_nsec)/1E6) + #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) diff --git a/win.h b/win.h index 6de960d..94679e4 100644 --- a/win.h +++ b/win.h -_AT_@ -25,7 +25,7 @@ enum win_mode { +_AT_@ -24,9 +24,9 @@ enum win_mode { + }; void xbell(void); void xclipcopy(void); _AT_@ -232,11 +255,13 @@ index 6de960d..94679e4 100644 void xdrawline(Line, int, int, int); void xfinishdraw(void); void xloadcols(void); + int xsetcolorname(int, const char *); diff --git a/x.c b/x.c -index 9891e91..7d42790 100644 +index 25785a6..16d7a3a 100644 --- a/x.c +++ b/x.c -_AT_@ -19,6 +19,7 @@ char *argv0; +_AT_@ -18,8 +18,9 @@ + char *argv0; #include "arg.h" #include "st.h" #include "win.h" _AT_@ -244,7 +269,9 @@ index 9891e91..7d42790 100644 /* types used in config.h */ typedef struct { -_AT_@ -143,8 +144,9 @@ typedef struct { + uint mod; +_AT_@ -142,10 +143,11 @@ typedef struct { + GC gc; } DC; static inline ushort sixd_to_16bit(int); _AT_@ -255,7 +282,9 @@ index 9891e91..7d42790 100644 static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static int xgeommasktogravity(int); -_AT_@ -759,7 +761,7 @@ xresize(int col, int row) + static int ximopen(Display *); +_AT_@ -758,9 +760,9 @@ xresize(int col, int row) + XftDrawChange(xw.draw, xw.buf); xclear(0, 0, win.w, win.h); /* resize to new width */ _AT_@ -264,7 +293,9 @@ index 9891e91..7d42790 100644 } ushort -_AT_@ -1064,6 +1066,9 @@ xunloadfont(Font *f) + sixd_to_16bit(int x) +_AT_@ -1063,8 +1065,11 @@ xunloadfont(Font *f) + void xunloadfonts(void) { _AT_@ -274,7 +305,9 @@ index 9891e91..7d42790 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); -_AT_@ -1187,7 +1192,7 @@ xinit(int cols, int rows) + +_AT_@ -1186,9 +1191,9 @@ xinit(int cols, int rows) + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); /* font spec buffer */ _AT_@ -283,7 +316,9 @@ index 9891e91..7d42790 100644 /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); -_AT_@ -1241,6 +1246,22 @@ xinit(int cols, int rows) + +_AT_@ -1240,144 +1245,155 @@ xinit(int cols, int rows) + if (xsel.xtarget == None) xsel.xtarget = XA_STRING; } _AT_@ -306,28 +341,42 @@ index 9891e91..7d42790 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1255,128 +1276,156 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp; +- ushort mode, prevmode = USHRT_MAX; ++ ushort mode = glyphs[0].mode & ~ATTR_WRAP; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; +- float runewidth = win.cw; ++ float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f); + Rune rune; + FT_UInt glyphidx; + FcResult fcres; FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; -+ int i, f, length = 0, start = 0, numspecs = 0; ++ int f, code_idx, numspecs = 0; + float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; -+ -+ /* Initial values. */ -+ mode = prevmode = glyphs[0].mode & ~ATTR_WRAP; -+ xresetfontsettings(mode, &font, &frcflags); - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { +- for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { - /* Fetch rune and mode for current glyph. */ - rune = glyphs[i].u; - mode = glyphs[i].mode; -+ mode = glyphs[i].mode & ~ATTR_WRAP; ++ /* Initial values. */ ++ xresetfontsettings(mode, &font, &frcflags); - /* Skip dummy wide-character spacing. */ +- /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY && i < (len - 1)) ++ /* Shape the segment. */ ++ hbtransform(&shaped, font->match, glyphs, 0, len); ++ xp = winx; yp = winy + font->ascent; ++ cluster_xp = xp; cluster_yp = yp; ++ ++ for (code_idx = 0; code_idx < shaped.count; code_idx++) { ++ int idx = shaped.glyphs[code_idx].cluster; ++ ++ if (glyphs[idx].mode & ATTR_WDUMMY) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -345,31 +394,31 @@ index 9891e91..7d42790 100644 - } else if (mode & ATTR_BOLD) { - font = &dc.bfont; - frcflags = FRC_BOLD; -+ if ( -+ prevmode != mode -+ || ATTRCMP(glyphs[start], glyphs[i]) -+ || selected(x + i, y) != selected(x + start, y) -+ || i == (len - 1) -+ ) { -+ /* Handle 1-character wide segments and end of line */ -+ length = i - start; -+ if (i == start) { -+ length = 1; -+ } else if (i == (len - 1)) { -+ length = (i - start + 1); - } +- } - yp = winy + font->ascent; -- } ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; + } - /* Lookup character index with default font. */ - glyphidx = XftCharIndex(xw.dpy, font->match, rune); - if (glyphidx) { -- specs[numspecs].font = font->match; ++ if (shaped.glyphs[code_idx].codepoint != 0) { ++ /* If symbol is found, put it into the specs. */ + specs[numspecs].font = font->match; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; -- numspecs++; ++ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; + numspecs++; - continue; - } - _AT_@ -383,105 +432,18 @@ index 9891e91..7d42790 100644 - if (!glyphidx && frc[f].flags == frcflags - && frc[f].unicodep == rune) { - break; -+ /* Shape the segment. */ -+ hbtransform(&shaped, font->match, glyphs, start, length); -+ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ cluster_xp = xp; cluster_yp = yp; -+ for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ int idx = shaped.glyphs[code_idx].cluster; -+ -+ if (glyphs[start + idx].mode & ATTR_WDUMMY) -+ continue; -+ -+ /* Advance the drawing cursor if we've moved to a new cluster */ -+ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { -+ xp += runewidth; -+ cluster_xp = xp; -+ cluster_yp = yp; -+ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); -+ } -+ -+ if (shaped.glyphs[code_idx].codepoint != 0) { -+ /* If symbol is found, put it into the specs. */ -+ specs[numspecs].font = font->match; -+ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); -+ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); -+ cluster_xp += shaped.positions[code_idx].x_advance / 64.; -+ cluster_yp += shaped.positions[code_idx].y_advance / 64.; -+ numspecs++; -+ } else { -+ /* If it's not found, try to fetch it through the font cache. */ -+ rune = glyphs[start + idx].u; -+ for (f = 0; f < frclen; f++) { -+ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); -+ /* Everything correct. */ -+ if (glyphidx && frc[f].flags == frcflags) -+ break; -+ /* We got a default font for a not found glyph. */ -+ if (!glyphidx && frc[f].flags == frcflags -+ && frc[f].unicodep == rune) { -+ break; -+ } -+ } -+ -+ /* Nothing was found. Use fontconfig to find matching font. */ -+ if (f >= frclen) { -+ if (!font->set) -+ font->set = FcFontSort(0, font->pattern, -+ 1, 0, &fcres); -+ fcsets[0] = font->set; -+ -+ /* -+ * Nothing was found in the cache. Now use -+ * some dozen of Fontconfig calls to get the -+ * font for one single character. -+ * -+ * Xft and fontconfig are design failures. -+ */ -+ fcpattern = FcPatternDuplicate(font->pattern); -+ fccharset = FcCharSetCreate(); -+ -+ FcCharSetAddChar(fccharset, rune); -+ FcPatternAddCharSet(fcpattern, FC_CHARSET, -+ fccharset); -+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); -+ -+ FcConfigSubstitute(0, fcpattern, -+ FcMatchPattern); -+ FcDefaultSubstitute(fcpattern); -+ -+ fontpattern = FcFontSetMatch(0, fcsets, 1, -+ fcpattern, &fcres); -+ -+ /* Allocate memory for the new cache entry. */ -+ if (frclen >= frccap) { -+ frccap += 16; -+ frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ } -+ -+ frc[frclen].font = XftFontOpenPattern(xw.dpy, -+ fontpattern); -+ if (!frc[frclen].font) -+ die("XftFontOpenPattern failed seeking fallback font: %s ", -+ strerror(errno)); -+ frc[frclen].flags = frcflags; -+ frc[frclen].unicodep = rune; -+ -+ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); -+ -+ f = frclen; -+ frclen++; -+ -+ FcPatternDestroy(fcpattern); -+ FcCharSetDestroy(fccharset); -+ } -+ -+ specs[numspecs].font = frc[f].font; -+ specs[numspecs].glyph = glyphidx; -+ specs[numspecs].x = (short)xp; -+ specs[numspecs].y = (short)yp; -+ numspecs++; ++ } else { ++ /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[idx].u; ++ for (f = 0; f < frclen; f++) { ++ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); ++ /* Everything correct. */ ++ if (glyphidx && frc[f].flags == frcflags) ++ break; ++ /* We got a default font for a not found glyph. */ ++ if (!glyphidx && frc[f].flags == frcflags ++ && frc[f].unicodep == rune) { ++ break; + } } - } _AT_@ -492,10 +454,7 @@ index 9891e91..7d42790 100644 - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; -+ /* Cleanup and get ready for next segment. */ -+ hbcleanup(&shaped); -+ start = i; - +- - /* - * Nothing was found in the cache. Now use - * some dozen of Fontconfig calls to get the _AT_@ -522,13 +481,58 @@ index 9891e91..7d42790 100644 - if (frclen >= frccap) { - frccap += 16; - frc = xrealloc(frc, frccap * sizeof(Fontcache)); -+ /* Determine font for glyph if different from previous glyph. */ -+ if (prevmode != mode) { -+ prevmode = mode; -+ xresetfontsettings(mode, &font, &frcflags); -+ yp = winy + font->ascent; ++ /* Nothing was found. Use fontconfig to find matching font. */ ++ if (f >= frclen) { ++ if (!font->set) ++ font->set = FcFontSort(0, font->pattern, ++ 1, 0, &fcres); ++ fcsets[0] = font->set; ++ ++ /* ++ * Nothing was found in the cache. Now use ++ * some dozen of Fontconfig calls to get the ++ * font for one single character. ++ * ++ * Xft and fontconfig are design failures. ++ */ ++ fcpattern = FcPatternDuplicate(font->pattern); ++ fccharset = FcCharSetCreate(); ++ ++ FcCharSetAddChar(fccharset, rune); ++ FcPatternAddCharSet(fcpattern, FC_CHARSET, ++ fccharset); ++ FcPatternAddBool(fcpattern, FC_SCALABLE, 1); ++ ++ FcConfigSubstitute(0, fcpattern, ++ FcMatchPattern); ++ FcDefaultSubstitute(fcpattern); ++ ++ fontpattern = FcFontSetMatch(0, fcsets, 1, ++ fcpattern, &fcres); ++ ++ /* Allocate memory for the new cache entry. */ ++ if (frclen >= frccap) { ++ frccap += 16; ++ frc = xrealloc(frc, frccap * sizeof(Fontcache)); ++ } ++ ++ frc[frclen].font = XftFontOpenPattern(xw.dpy, ++ fontpattern); ++ if (!frc[frclen].font) ++ die("XftFontOpenPattern failed seeking fallback font: %s ", ++ strerror(errno)); ++ frc[frclen].flags = frcflags; ++ frc[frclen].unicodep = rune; ++ ++ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); ++ ++ f = frclen; ++ frclen++; ++ ++ FcPatternDestroy(fcpattern); ++ FcCharSetDestroy(fccharset); } -- + - frc[frclen].font = XftFontOpenPattern(xw.dpy, - fontpattern); - if (!frc[frclen].font) _AT_@ -544,6 +548,11 @@ index 9891e91..7d42790 100644 - - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); ++ specs[numspecs].font = frc[f].font; ++ specs[numspecs].glyph = glyphidx; ++ specs[numspecs].x = (short)xp; ++ specs[numspecs].y = (short)yp; ++ numspecs++; } - - specs[numspecs].font = frc[f].font; _AT_@ -554,6 +563,8 @@ index 9891e91..7d42790 100644 - numspecs++; } ++ /* Cleanup and get ready for next segment. */ ++ hbcleanup(&shaped); return numspecs; } _AT_@ -565,7 +576,9 @@ index 9891e91..7d42790 100644 int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, width = charlen * win.cw; Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; -_AT_@ -1512,21 +1561,24 @@ void + XRenderColor colfg, colbg; +_AT_@ -1511,23 +1527,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + void xdrawglyph(Glyph g, int x, int y) { int numspecs; _AT_@ -595,7 +608,9 @@ index 9891e91..7d42790 100644 if (IS_SET(MODE_HIDE)) return; -_AT_@ -1654,18 +1706,16 @@ xdrawline(Line line, int x1, int y1, int x2) + +_AT_@ -1659,30 +1678,30 @@ xdrawline(Line line, int x1, int y1, int x2) + int i, x, ox, numspecs; Glyph base, new; XftGlyphFontSpec *specs = xw.specbuf; _AT_@ -618,7 +633,8 @@ index 9891e91..7d42790 100644 i = 0; } if (i == 0) { -_AT_@ -1674,8 +1724,10 @@ xdrawline(Line line, int x1, int y1, int x2) + ox = x; + base = new; } i++; } _AT_@ -631,3 +647,4 @@ index 9891e91..7d42790 100644 } void + xfinishdraw(void) diff --git a/st.suckless.org/patches/ligatures/index.md b/st.suckless.org/patches/ligatures/index.md index 3734a433..14f506cb 100644 --- a/st.suckless.org/patches/ligatures/index.md +++ b/st.suckless.org/patches/ligatures/index.md _AT_@ -28,13 +28,13 @@ Boxdraw Download -------- **0.9.2**: -* [st-ligatures-0.9.2](0.9.2/st-ligatures-20240427-0.9.2.diff) -* [st-ligatures-scrollback-0.9.2](0.9.2/st-ligatures-scrollback-20240427-0.9.2.diff) -* [st-ligatures-scrollback-ringbuffer-0.9.2](0.9.2/st-ligatures-scrollback-ringbuffer-20240427-0.9.2.diff) -* [st-ligatures-alpha-0.9.2](0.9.2/st-ligatures-alpha-20240427-0.9.2.diff) -* [st-ligatures-alpha-scrollback-0.9.2](0.9.2/st-ligatures-alpha-scrollback-20240427-0.9.2.diff) -* [st-ligatures-alpha-scrollback-ringbuffer-0.9.2](0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20240427-0.9.2.diff) -* [st-ligatures-boxdraw-0.9.2](0.9.2/st-ligatures-boxdraw-20240427-0.9.2.diff) +* [st-ligatures-0.9.2](0.9.2/st-ligatures-20241226-0.9.2.diff) +* [st-ligatures-scrollback-0.9.2](0.9.2/st-ligatures-scrollback-20241226-0.9.2.diff) +* [st-ligatures-scrollback-ringbuffer-0.9.2](0.9.2/st-ligatures-scrollback-ringbuffer-20241226-0.9.2.diff) +* [st-ligatures-alpha-0.9.2](0.9.2/st-ligatures-alpha-20241226-0.9.2.diff) +* [st-ligatures-alpha-scrollback-0.9.2](0.9.2/st-ligatures-alpha-scrollback-20241226-0.9.2.diff) +* [st-ligatures-alpha-scrollback-ringbuffer-0.9.2](0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20241226-0.9.2.diff) +* [st-ligatures-boxdraw-0.9.2](0.9.2/st-ligatures-boxdraw-20241226-0.9.2.diff) **0.9**: * [st-ligatures-0.9](0.9/st-ligatures-20240105-0.9.diff)Received on Thu Jan 09 2025 - 22:55:03 CET
This archive was generated by hypermail 2.3.0 : Thu Jan 09 2025 - 23:00:56 CET