Introduction
Introduction Statistics Contact Development Disclaimer Help
Add Xft and follback-fonts support to graphics lib - libsl - shared code master…
git clone git://git.suckless.org/libsl
Log
Files
Refs
LICENSE
---
commit 4ef363a6c7f0265024845e151a5fe7dcaefb3ee1
parent 57b9b1642a4e17ba794029ee37568aa5564e5983
Author: Eric Pruitt <[email protected]>
Date: Thu, 5 Mar 2015 20:28:49 -0800
Add Xft and follback-fonts support to graphics lib
Diffstat:
M drw.c | 349 +++++++++++++++++++++++------…
M drw.h | 19 ++++++++++++-------
M util.h | 1 +
3 files changed, 280 insertions(+), 89 deletions(-)
---
diff --git a/drw.c b/drw.c
@@ -3,10 +3,59 @@
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
+#include <X11/Xft/Xft.h>
#include "drw.h"
#include "util.h"
+#define UTF_INVALID 0xFFFD
+#define UTF_SIZ 4
+
+static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF…
+static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF…
+static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x100…
+static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FF…
+
+static long
+utf8decodebyte(const char c, size_t *i) {
+ for(*i = 0; *i < (UTF_SIZ + 1); ++(*i))
+ if(((unsigned char)c & utfmask[*i]) == utfbyte[*i])
+ return (unsigned char)c & ~utfmask[*i];
+ return 0;
+}
+
+static size_t
+utf8validate(long *u, size_t i) {
+ if(!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
+ *u = UTF_INVALID;
+ for(i = 1; *u > utfmax[i]; ++i)
+ ;
+ return i;
+}
+
+static size_t
+utf8decode(const char *c, long *u, size_t clen) {
+ size_t i, j, len, type;
+ long udecoded;
+
+ *u = UTF_INVALID;
+ if(!clen)
+ return 0;
+ udecoded = utf8decodebyte(c[0], &len);
+ if(!BETWEEN(len, 1, UTF_SIZ))
+ return 1;
+ for(i = 1, j = 1; i < clen && j < len; ++i, ++j) {
+ udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
+ if(type != 0)
+ return j;
+ }
+ if(j < len)
+ return 0;
+ *u = udecoded;
+ utf8validate(u, len);
+ return len;
+}
+
Drw *
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int…
Drw *drw = (Drw *)calloc(1, sizeof(Drw));
@@ -19,6 +68,7 @@ drw_create(Display *dpy, int screen, Window root, unsigned in…
drw->h = h;
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, scree…
drw->gc = XCreateGC(dpy, root, 0, NULL);
+ drw->fontcount = 0;
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
return drw;
}
@@ -36,56 +86,88 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h) {
void
drw_free(Drw *drw) {
+ size_t i;
+ for (i = 0; i < drw->fontcount; i++) {
+ drw_font_free(drw->fonts[i]);
+ }
XFreePixmap(drw->dpy, drw->drawable);
XFreeGC(drw->dpy, drw->gc);
free(drw);
}
-Fnt *
-drw_font_create(Display *dpy, const char *fontname) {
+/* This function is an implementation detail. Library users should use
+ * drw_font_create instead.
+ */
+static Fnt *
+drw_font_xcreate(Drw *drw, const char *fontname, FcPattern *fontpattern) {
Fnt *font;
- char *def, **missing;
- int n;
- font = (Fnt *)calloc(1, sizeof(Fnt));
- if(!font)
+ if (!(fontname || fontpattern))
+ die("No font specified.\n");
+
+ if (!(font = (Fnt *)calloc(1, sizeof(Fnt))))
return NULL;
- font->set = XCreateFontSet(dpy, fontname, &missing, &n, &def);
- if(missing) {
- while(n--)
- fprintf(stderr, "drw: missing fontset: %s\n", missing[…
- XFreeStringList(missing);
- }
- if(font->set) {
- XFontStruct **xfonts;
- char **font_names;
- XExtentsOfFontSet(font->set);
- n = XFontsOfFontSet(font->set, &xfonts, &font_names);
- while(n--) {
- font->ascent = MAX(font->ascent, (*xfonts)->ascent);
- font->descent = MAX(font->descent,(*xfonts)->descent);
- xfonts++;
+
+ if (fontname) {
+ /* Using the pattern found at font->xfont->pattern does not yi…
+ * the same substitution results as using the pattern returned…
+ * FcNameParse; using the latter results in the desired fallba…
+ * behaviour whereas the former just results in
+ * missing-character-rectangles being drawn, at least with som…
+ */
+ if (!(font->xfont = XftFontOpenName(drw->dpy, drw->screen, fon…
+ !(font->pattern = FcNameParse((FcChar8 *) fontname))) {
+ if (font->xfont) {
+ XftFontClose(drw->dpy, font->xfont);
+ font->xfont = NULL;
+ }
+ fprintf(stderr, "error, cannot load font: '%s'\n", fon…
+ }
+ } else if (fontpattern) {
+ if (!(font->xfont = XftFontOpenPattern(drw->dpy, fontpattern))…
+ fprintf(stderr, "error, cannot load font pattern.\n");
+ } else {
+ font->pattern = NULL;
}
}
- else {
- if(!(font->xfont = XLoadQueryFont(dpy, fontname))
- && !(font->xfont = XLoadQueryFont(dpy, "fixed")))
- die("error, cannot load font: '%s'\n", fontname);
- font->ascent = font->xfont->ascent;
- font->descent = font->xfont->descent;
+
+ if (!font->xfont) {
+ free(font);
+ return NULL;
}
+
+ font->ascent = font->xfont->ascent;
+ font->descent = font->xfont->descent;
font->h = font->ascent + font->descent;
+ font->dpy = drw->dpy;
return font;
}
+Fnt*
+drw_font_create(Drw *drw, const char *fontname) {
+ return drw_font_xcreate(drw, fontname, NULL);
+}
+
+void
+drw_load_fonts(Drw* drw, const char *fonts[], size_t fontcount) {
+ size_t i;
+ Fnt *font;
+ for (i = 0; i < fontcount; i++) {
+ if (drw->fontcount >= DRW_FONT_CACHE_SIZE) {
+ die("Font cache exhausted.\n");
+ } else if ((font = drw_font_xcreate(drw, fonts[i], NULL))) {
+ drw->fonts[drw->fontcount++] = font;
+ }
+ }
+}
+
void
-drw_font_free(Display *dpy, Fnt *font) {
+drw_font_free(Fnt *font) {
if(!font)
return;
- if(font->set)
- XFreeFontSet(dpy, font->set);
- else
- XFreeFont(dpy, font->xfont);
+ if(font->pattern)
+ FcPatternDestroy(font->pattern);
+ XftFontClose(font->dpy, font->xfont);
free(font);
}
@@ -93,7 +175,7 @@ Clr *
drw_clr_create(Drw *drw, const char *clrname) {
Clr *clr;
Colormap cmap;
- XColor color;
+ Visual *vis;
if(!drw)
return NULL;
@@ -101,9 +183,10 @@ drw_clr_create(Drw *drw, const char *clrname) {
if(!clr)
return NULL;
cmap = DefaultColormap(drw->dpy, drw->screen);
- if(!XAllocNamedColor(drw->dpy, cmap, clrname, &color, &color))
+ vis = DefaultVisual(drw->dpy, drw->screen);
+ if(!XftColorAllocName(drw->dpy, vis, cmap, clrname, &clr->rgb))
die("error, cannot allocate color '%s'\n", clrname);
- clr->rgb = color.pixel;
+ clr->pix = clr->rgb.pixel;
return clr;
}
@@ -114,14 +197,8 @@ drw_clr_free(Clr *clr) {
}
void
-drw_setfont(Drw *drw, Fnt *font) {
- if(drw)
- drw->font = font;
-}
-
-void
drw_setscheme(Drw *drw, ClrScheme *scheme) {
- if(drw && scheme)
+ if(drw && scheme)
drw->scheme = scheme;
}
@@ -129,46 +206,160 @@ void
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, i…
int dx;
- if(!drw || !drw->font || !drw->scheme)
+ if(!drw || !drw->fontcount || !drw->scheme)
return;
- XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->rgb : drw-…
- dx = (drw->font->ascent + drw->font->descent + 2) / 4;
+ XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->pix : drw-…
+ dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4;
if(filled)
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x+1, y+1, dx+…
else if(empty)
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x+1, y+1, dx,…
}
-void
+int
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *t…
- char buf[256];
- int i, tx, ty, th, len, olen;
+ char buf[1024];
+ int tx, ty, th;
Extnts tex;
+ Colormap cmap;
+ Visual *vis;
+ XftDraw *d;
+ Fnt *curfont, *nextfont;
+ size_t i, len;
+ int utf8strlen, utf8charlen, render;
+ long utf8codepoint = 0;
+ const char *utf8str;
+ FcCharSet *fccharset;
+ FcPattern *fcpattern;
+ FcPattern *match;
+ XftResult result;
+ int charexists = 0;
- if(!drw || !drw->scheme)
- return;
- XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->fg->rgb : drw-…
- XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
- if(!text || !drw->font)
- return;
- olen = strlen(text);
- drw_font_getexts(drw->font, text, olen, &tex);
- th = drw->font->ascent + drw->font->descent;
- ty = y + (h / 2) - (th / 2) + drw->font->ascent;
- tx = x + (h / 2);
- /* shorten text if necessary */
- for(len = MIN(olen, sizeof buf); len && (tex.w > w - tex.h || w < tex.…
- drw_font_getexts(drw->font, text, len, &tex);
- if(!len)
- return;
- memcpy(buf, text, len);
- if(len < olen)
- for(i = len; i && i > len - 3; buf[--i] = '.');
- XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->rgb : drw-…
- if(drw->font->set)
- XmbDrawString(drw->dpy, drw->drawable, drw->font->set, drw->gc…
- else
- XDrawString(drw->dpy, drw->drawable, drw->gc, tx, ty, buf, len…
+ if (!(render = x || y || w || h)) {
+ w = ~w;
+ }
+
+ if (!drw || !drw->scheme) {
+ return 0;
+ } else if (render) {
+ XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->fg->pi…
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+ }
+
+ if (!text || !drw->fontcount) {
+ return 0;
+ } else if (render) {
+ cmap = DefaultColormap(drw->dpy, drw->screen);
+ vis = DefaultVisual(drw->dpy, drw->screen);
+ d = XftDrawCreate(drw->dpy, drw->drawable, vis, cmap);
+ }
+
+ curfont = drw->fonts[0];
+ while (1) {
+ utf8strlen = 0;
+ utf8str = text;
+ nextfont = NULL;
+ while (*text) {
+ utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ…
+ for (i = 0; i < drw->fontcount; i++) {
+ charexists = charexists || XftCharExists(drw->…
+ if (charexists) {
+ if (drw->fonts[i] == curfont) {
+ utf8strlen += utf8charlen;
+ text += utf8charlen;
+ } else {
+ nextfont = drw->fonts[i];
+ }
+ break;
+ }
+ }
+
+ if (!charexists || (nextfont && nextfont != curfont)) {
+ break;
+ } else {
+ charexists = 0;
+ }
+ }
+
+ if (utf8strlen) {
+ drw_font_getexts(curfont, utf8str, utf8strlen, &tex);
+ /* shorten text if necessary */
+ for(len = MIN(utf8strlen, (sizeof buf) - 1); len && (t…
+ drw_font_getexts(curfont, utf8str, len, &tex);
+
+ if (len) {
+ memcpy(buf, utf8str, len);
+ buf[len] = '\0';
+ if(len < utf8strlen)
+ for(i = len; i && i > len - 3; buf[--i…
+
+ if (render) {
+ th = curfont->ascent + curfont->descen…
+ ty = y + (h / 2) - (th / 2) + curfont-…
+ tx = x + (h / 2);
+ XftDrawStringUtf8(d, invert ? &drw->sc…
+ }
+
+ x += tex.w;
+ w -= tex.w;
+ }
+ }
+
+ if (!*text) {
+ break;
+ } else if (nextfont) {
+ charexists = 0;
+ curfont = nextfont;
+ } else {
+ /* Regardless of whether or not a fallback font is fou…
+ * character must be drawn.
+ */
+ charexists = 1;
+
+ if (drw->fontcount >= DRW_FONT_CACHE_SIZE) {
+ continue;
+ }
+
+ fccharset = FcCharSetCreate();
+ FcCharSetAddChar(fccharset, utf8codepoint);
+
+ if (!drw->fonts[0]->pattern) {
+ /* Refer to the comment in drw_font_xcreate fo…
+ * information.
+ */
+ die("The first font in the cache must be loade…
+ }
+
+ fcpattern = FcPatternDuplicate(drw->fonts[0]->pattern);
+ FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
+ FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
+
+ FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
+ FcDefaultSubstitute(fcpattern);
+ match = XftFontMatch(drw->dpy, drw->screen, fcpattern,…
+
+ FcCharSetDestroy(fccharset);
+ FcPatternDestroy(fcpattern);
+
+ if (match) {
+ curfont = drw_font_xcreate(drw, NULL, match);
+ if (curfont && XftCharExists(drw->dpy, curfont…
+ drw->fonts[drw->fontcount++] = curfont;
+ } else {
+ if (curfont) {
+ drw_font_free(curfont);
+ }
+ curfont = drw->fonts[0];
+ }
+ }
+ }
+ }
+
+ if (render) {
+ XftDrawDestroy(d);
+ }
+
+ return x;
}
void
@@ -182,19 +373,13 @@ drw_map(Drw *drw, Window win, int x, int y, unsigned int …
void
drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *tex) {
- XRectangle r;
+ XGlyphInfo ext;
if(!font || !text)
return;
- if(font->set) {
- XmbTextExtents(font->set, text, len, NULL, &r);
- tex->w = r.width;
- tex->h = r.height;
- }
- else {
- tex->h = font->ascent + font->descent;
- tex->w = XTextWidth(font->xfont, text, len);
- }
+ XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext…
+ tex->h = font->h;
+ tex->w = ext.xOff;
}
unsigned int
diff --git a/drw.h b/drw.h
@@ -1,7 +1,9 @@
/* See LICENSE file for copyright and license details. */
+#define DRW_FONT_CACHE_SIZE 32
typedef struct {
- unsigned long rgb;
+ unsigned long pix;
+ XftColor rgb;
} Clr;
typedef struct {
@@ -9,11 +11,12 @@ typedef struct {
} Cur;
typedef struct {
+ Display *dpy;
int ascent;
int descent;
unsigned int h;
- XFontSet set;
- XFontStruct *xfont;
+ XftFont *xfont;
+ FcPattern *pattern;
} Fnt;
typedef struct {
@@ -30,7 +33,8 @@ typedef struct {
Drawable drawable;
GC gc;
ClrScheme *scheme;
- Fnt *font;
+ size_t fontcount;
+ Fnt *fonts[DRW_FONT_CACHE_SIZE];
} Drw;
typedef struct {
@@ -44,8 +48,9 @@ void drw_resize(Drw *drw, unsigned int w, unsigned int h);
void drw_free(Drw *drw);
/* Fnt abstraction */
-Fnt *drw_font_create(Display *dpy, const char *fontname);
-void drw_font_free(Display *dpy, Fnt *font);
+Fnt *drw_font_create(Drw *drw, const char *fontname);
+void drw_load_fonts(Drw* drw, const char *fonts[], size_t fontcount);
+void drw_font_free(Fnt *font);
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *e…
unsigned int drw_font_getexts_width(Fnt *font, const char *text, unsigned int …
@@ -63,7 +68,7 @@ void drw_setscheme(Drw *drw, ClrScheme *scheme);
/* Drawing functions */
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int fill…
-void drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const ch…
+int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const cha…
/* Map functions */
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int …
diff --git a/util.h b/util.h
@@ -2,5 +2,6 @@
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
+#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
void die(const char *errstr, ...);
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.