diff --git a/config.def.h b/config.def.h index b41747f..638c3c5 100644 --- a/config.def.h +++ b/config.def.h @@ -1,11 +1,16 @@ /* See LICENSE file for copyright and license details. */ -/* - * appearance - * - * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html +/** + * Array of the primary font and fallback fonts. The first string in the array + * is the primary font while the rest of the fonts will be used as fallbacks + * when preceding fonts are missing a specific glyph. See + * http://freedesktop.org/software/fontconfig/fontconfig-user.html for more + * info on font definitions. */ -static char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +static char *fonts[] = { + "Liberation Mono:pixelsize=12:antialias=true:autohint=true", +}; + static int borderpx = 2; /* diff --git a/st.c b/st.c index 2594c65..f7973bd 100644 --- a/st.c +++ b/st.c @@ -353,10 +353,17 @@ typedef struct { FcPattern *pattern; } Font; +typedef struct { + Font font; + Font bfont; + Font ifont; + Font ibfont; +} FontFamily; + /* Drawing Context */ typedef struct { Color col[MAX(LEN(colorname), 256)]; - Font font, bfont, ifont, ibfont; + FontFamily fontfamily; GC gc; } DC; @@ -434,7 +441,7 @@ static void xloadcols(void); static int xsetcolorname(int, const char *); static int xgeommasktogravity(int); static int xloadfont(Font *, FcPattern *); -static void xloadfonts(char *, double); +static void xloadfonts(const char *, double); static void xsettitle(char *); static void xresettitle(void); static void xsetpointermotion(int); @@ -533,7 +540,7 @@ static char *opt_name = NULL; static char *opt_title = NULL; static int oldbutton = 3; /* button event on startup: 3 = release */ -static char *usedfont = NULL; +static const char *usedfont = NULL; static double usedfontsize = 0; static double defaultfontsize = 0; @@ -542,6 +549,9 @@ static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; +static FontFamily fontfamilies[16]; +static int fontfamiliescount = 0; + /* Font Ring Cache */ enum { FRC_NORMAL, @@ -3307,11 +3317,16 @@ xloadfont(Font *f, FcPattern *pattern) } void -xloadfonts(char *fontstr, double fontsize) +xloadfonts(const char *fontstr, double fontsize) { FcPattern *pattern; double fontval; float ceilf(float); + FontFamily fontfamily; + + if (fontfamiliescount >= LEN(fontfamilies)) { + die("Font family array is full.\n"); + } if (fontstr[0] == '-') { pattern = XftXlfdParse(fontstr, False, False); @@ -3345,37 +3360,43 @@ xloadfonts(char *fontstr, double fontsize) defaultfontsize = usedfontsize; } - if (xloadfont(&dc.font, pattern)) + if (xloadfont(&fontfamily.font, pattern)) die("st: can't open font %s\n", fontstr); if (usedfontsize < 0) { - FcPatternGetDouble(dc.font.match->pattern, + FcPatternGetDouble(fontfamily.font.match->pattern, FC_PIXEL_SIZE, 0, &fontval); usedfontsize = fontval; if (fontsize == 0) defaultfontsize = fontval; } - /* Setting character width and height. */ - xw.cw = ceilf(dc.font.width * cwscale); - xw.ch = ceilf(dc.font.height * chscale); - FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); - if (xloadfont(&dc.ifont, pattern)) + if (xloadfont(&fontfamily.ifont, pattern)) die("st: can't open font %s\n", fontstr); FcPatternDel(pattern, FC_WEIGHT); FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); - if (xloadfont(&dc.ibfont, pattern)) + if (xloadfont(&fontfamily.ibfont, pattern)) die("st: can't open font %s\n", fontstr); FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); - if (xloadfont(&dc.bfont, pattern)) + if (xloadfont(&fontfamily.bfont, pattern)) die("st: can't open font %s\n", fontstr); FcPatternDestroy(pattern); + + /* Setting character width and height. */ + if (!fontfamiliescount) { + xw.cw = ceilf(fontfamily.font.width * cwscale); + xw.ch = ceilf(fontfamily.font.height * chscale); + dc.fontfamily = fontfamily; + usedfont = fontstr; + } + + fontfamilies[fontfamiliescount++] = fontfamily; } void @@ -3394,10 +3415,13 @@ xunloadfonts(void) while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); - xunloadfont(&dc.font); - xunloadfont(&dc.bfont); - xunloadfont(&dc.ifont); - xunloadfont(&dc.ibfont); + while (fontfamiliescount > 0) { + fontfamiliescount--; + xunloadfont(&fontfamilies[fontfamiliescount].font); + xunloadfont(&fontfamilies[fontfamiliescount].bfont); + xunloadfont(&fontfamilies[fontfamiliescount].ifont); + xunloadfont(&fontfamilies[fontfamiliescount].ibfont); + } } void @@ -3434,6 +3458,8 @@ xzoomreset(const Arg *arg) void xinit(void) { + int i; + XGCValues gcvalues; Cursor cursor; Window parent; @@ -3449,8 +3475,13 @@ xinit(void) if (!FcInit()) die("Could not init fontconfig.\n"); - usedfont = (opt_font == NULL)? font : opt_font; - xloadfonts(usedfont, 0); + if (opt_font) { + xloadfonts(opt_font, 0); + } + + for (i = 0; i < LEN(fonts); i++) { + xloadfonts(fonts[i], 0); + } /* colors */ xw.cmap = XDefaultColormap(xw.dpy, xw.scr); @@ -3546,9 +3577,9 @@ xinit(void) int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { - float winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, xp, yp; - ushort mode, prevmode = USHRT_MAX; - Font *font = &dc.font; + float winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, xp; + ushort mode; + Font *font, *reference = NULL; int frcflags = FRC_NORMAL; float runewidth = xw.cw; Rune rune; @@ -3559,7 +3590,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcCharSet *fccharset; int i, f, numspecs = 0; - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { + for (i = 0, xp = winx; i < len; ++i) { /* Fetch rune and mode for current glyph. */ rune = glyphs[i].u; mode = glyphs[i].mode; @@ -3568,32 +3599,33 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x if (mode == ATTR_WDUMMY) continue; - /* Determine font for glyph if different from previous glyph. */ - if (prevmode != mode) { - prevmode = mode; - font = &dc.font; + /* Lookup character index within user-defined fonts. */ + for (glyphidx = 0, f = 0; f < fontfamiliescount && !glyphidx; f++) { + font = &fontfamilies[f].font; frcflags = FRC_NORMAL; runewidth = xw.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f); if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { - font = &dc.ibfont; + font = &fontfamilies[f].ibfont; frcflags = FRC_ITALICBOLD; } else if (mode & ATTR_ITALIC) { - font = &dc.ifont; + font = &fontfamilies[f].ifont; frcflags = FRC_ITALIC; } else if (mode & ATTR_BOLD) { - font = &dc.bfont; + font = &fontfamilies[f].bfont; frcflags = FRC_BOLD; } - yp = winy + font->ascent; + + if (!f) { + reference = font; + } + glyphidx = XftCharIndex(xw.dpy, font->match, rune); } - /* Lookup character index with default font. */ - glyphidx = XftCharIndex(xw.dpy, font->match, rune); if (glyphidx) { specs[numspecs].font = font->match; specs[numspecs].glyph = glyphidx; specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; + specs[numspecs].y = (short) (winy + font->ascent); xp += runewidth; numspecs++; continue; @@ -3612,12 +3644,14 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x } } - /* Nothing was found. Use fontconfig to find matching font. */ + /* Nothing was found. Use fontconfig to find matching font using the + * default font as the reference font. + */ if (f >= frclen) { - if (!font->set) - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; + if (!reference->set) + reference->set = FcFontSort(0, reference->pattern, + 1, 0, &fcres); + fcsets[0] = reference->set; /* * Nothing was found in the cache. Now use @@ -3626,7 +3660,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x * * Xft and fontconfig are design failures. */ - fcpattern = FcPatternDuplicate(font->pattern); + fcpattern = FcPatternDuplicate(reference->pattern); fccharset = FcCharSetCreate(); FcCharSetAddChar(fccharset, rune); @@ -3667,7 +3701,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x specs[numspecs].font = frc[f].font; specs[numspecs].glyph = glyphidx; specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; + specs[numspecs].y = (short) (winy + frc[f].font->ascent); xp += runewidth; numspecs++; } @@ -3796,12 +3830,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i /* Render underline and strikethrough. */ if (base.mode & ATTR_UNDERLINE) { - XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, + XftDrawRect(xw.draw, fg, winx, winy + dc.fontfamily.font.ascent + 1, width, 1); } if (base.mode & ATTR_STRUCK) { - XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, + XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.fontfamily.font.ascent / 3, width, 1); }