sync drw.c, drw.h and arg.h from dmenu - libsl - shared code master of various suckless projects
 (HTM) git clone git://git.suckless.org/libsl
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
 (DIR) commit e1132a979e39d6cdb8c34ea5496c901a5b8c2d79
 (DIR) parent 4ef363a6c7f0265024845e151a5fe7dcaefb3ee1
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Sat,  5 Nov 2016 11:44:30 +0100
       
       sync drw.c, drw.h and arg.h from dmenu
       
       Diffstat:
         M arg.h                               |      46 ++++++++++++++++++-------------
         M drw.c                               |     396 ++++++++++++++++---------------
         M drw.h                               |      51 +++++++++++---------------------
         M util.c                              |      28 +++++++++++++++++++++++-----
       
       4 files changed, 270 insertions(+), 251 deletions(-)
       ---
 (DIR) diff --git a/arg.h b/arg.h
       @@ -3,39 +3,47 @@
         * by 20h
         */
        
       -#ifndef __ARG_H__
       -#define __ARG_H__
       +#ifndef ARG_H__
       +#define ARG_H__
        
        extern char *argv0;
        
       -#define USED(x) ((void)(x))
       -
       +/* use main(int argc, char *argv[]) */
        #define ARGBEGIN        for (argv0 = *argv, argv++, argc--;\
       -                                        argv[0] && argv[0][1]\
       -                                        && argv[0][0] == '-';\
       +                                        argv[0] && argv[0][0] == '-'\
       +                                        && argv[0][1];\
                                                argc--, argv++) {\
       -                                char _argc;\
       -                                char **_argv;\
       +                                char argc_;\
       +                                char **argv_;\
       +                                int brk_;\
                                        if (argv[0][1] == '-' && argv[0][2] == '\0') {\
                                                argv++;\
                                                argc--;\
                                                break;\
                                        }\
       -                                for (argv[0]++, _argv = argv; argv[0][0];\
       +                                for (brk_ = 0, argv[0]++, argv_ = argv;\
       +                                                argv[0][0] && !brk_;\
                                                        argv[0]++) {\
       -                                        if (_argv != argv)\
       +                                        if (argv_ != argv)\
                                                        break;\
       -                                        _argc = argv[0][0];\
       -                                        switch (_argc)
       +                                        argc_ = argv[0][0];\
       +                                        switch (argc_)
        
        #define ARGEND                        }\
       -                                USED(_argc);\
       -                        }\
       -                        USED(argv);\
       -                        USED(argc);
       +                        }
        
       -#define EARGF(x)        ((argv[1] == NULL)? ((x), abort(), (char *)0) :\
       -                        (argc--, argv++, argv[0]))
       +#define ARGC()                argc_
        
       -#endif
       +#define EARGF(x)        ((argv[0][1] == '\0' && argv[1] == NULL)?\
       +                                ((x), abort(), (char *)0) :\
       +                                (brk_ = 1, (argv[0][1] != '\0')?\
       +                                        (&argv[0][1]) :\
       +                                        (argc--, argv++, argv[0])))
        
       +#define ARGF()                ((argv[0][1] == '\0' && argv[1] == NULL)?\
       +                                (char *)0 :\
       +                                (brk_ = 1, (argv[0][1] != '\0')?\
       +                                        (&argv[0][1]) :\
       +                                        (argc--, argv++, argv[0])))
       +
       +#endif
 (DIR) diff --git a/drw.c b/drw.c
       @@ -9,7 +9,7 @@
        #include "util.h"
        
        #define UTF_INVALID 0xFFFD
       -#define UTF_SIZ 4
       +#define UTF_SIZ     4
        
        static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0};
        static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
       @@ -17,50 +17,54 @@ static const long utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000
        static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
        
        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])
       +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))
       +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)
       +        for (i = 1; *u > utfmax[i]; ++i)
                        ;
                return i;
        }
        
        static size_t
       -utf8decode(const char *c, long *u, size_t clen) {
       +utf8decode(const char *c, long *u, size_t clen)
       +{
                size_t i, j, len, type;
                long udecoded;
        
                *u = UTF_INVALID;
       -        if(!clen)
       +        if (!clen)
                        return 0;
                udecoded = utf8decodebyte(c[0], &len);
       -        if(!BETWEEN(len, 1, UTF_SIZ))
       +        if (!BETWEEN(len, 1, UTF_SIZ))
                        return 1;
       -        for(i = 1, j = 1; i < clen && j < len; ++i, ++j) {
       +        for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
                        udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
       -                if(type != 0)
       +                if (type)
                                return j;
                }
       -        if(j < len)
       +        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 h) {
       -        Drw *drw = (Drw *)calloc(1, sizeof(Drw));
       -        if(!drw)
       -                return NULL;
       +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
       +{
       +        Drw *drw = ecalloc(1, sizeof(Drw));
       +
                drw->dpy = dpy;
                drw->screen = screen;
                drw->root = root;
       @@ -68,165 +72,178 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
                drw->h = h;
                drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
                drw->gc = XCreateGC(dpy, root, 0, NULL);
       -        drw->fontcount = 0;
                XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
       +
                return drw;
        }
        
        void
       -drw_resize(Drw *drw, unsigned int w, unsigned int h) {
       -        if(!drw)
       +drw_resize(Drw *drw, unsigned int w, unsigned int h)
       +{
       +        if (!drw)
                        return;
       +
                drw->w = w;
                drw->h = h;
       -        if(drw->drawable != 0)
       +        if (drw->drawable)
                        XFreePixmap(drw->dpy, drw->drawable);
                drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
        }
        
        void
       -drw_free(Drw *drw) {
       -        size_t i;
       -        for (i = 0; i < drw->fontcount; i++) {
       -                drw_font_free(drw->fonts[i]);
       -        }
       +drw_free(Drw *drw)
       +{
                XFreePixmap(drw->dpy, drw->drawable);
                XFreeGC(drw->dpy, drw->gc);
                free(drw);
        }
        
        /* This function is an implementation detail. Library users should use
       - * drw_font_create instead.
       + * drw_fontset_create instead.
         */
        static Fnt *
       -drw_font_xcreate(Drw *drw, const char *fontname, FcPattern *fontpattern) {
       +xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
       +{
                Fnt *font;
       -
       -        if (!(fontname || fontpattern))
       -                die("No font specified.\n");
       -
       -        if (!(font = (Fnt *)calloc(1, sizeof(Fnt))))
       -                return NULL;
       +        XftFont *xfont = NULL;
       +        FcPattern *pattern = NULL;
        
                if (fontname) {
       -                /* Using the pattern found at font->xfont->pattern does not yield same
       -                 * the same substitution results as using the pattern returned by
       +                /* Using the pattern found at font->xfont->pattern does not yield the
       +                 * same substitution results as using the pattern returned by
                         * FcNameParse; using the latter results in the desired fallback
       -                 * behaviour whereas the former just results in
       -                 * missing-character-rectangles being drawn, at least with some fonts.
       -                 */
       -                if (!(font->xfont = XftFontOpenName(drw->dpy, drw->screen, fontname)) ||
       -                    !(font->pattern = FcNameParse((FcChar8 *) fontname))) {
       -                        if (font->xfont) {
       -                                XftFontClose(drw->dpy, font->xfont);
       -                                font->xfont = NULL;
       -                        }
       -                        fprintf(stderr, "error, cannot load font: '%s'\n", fontname);
       +                 * behaviour whereas the former just results in missing-character
       +                 * rectangles being drawn, at least with some fonts. */
       +                if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
       +                        fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
       +                        return NULL;
       +                }
       +                if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
       +                        fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
       +                        XftFontClose(drw->dpy, xfont);
       +                        return NULL;
                        }
                } else if (fontpattern) {
       -                if (!(font->xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
       -                        fprintf(stderr, "error, cannot load font pattern.\n");
       -                } else {
       -                        font->pattern = NULL;
       +                if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
       +                        fprintf(stderr, "error, cannot load font from pattern.\n");
       +                        return NULL;
                        }
       +        } else {
       +                die("no font specified.");
                }
        
       -        if (!font->xfont) {
       -                free(font);
       -                return NULL;
       -        }
       -
       -        font->ascent = font->xfont->ascent;
       -        font->descent = font->xfont->descent;
       -        font->h = font->ascent + font->descent;
       +        font = ecalloc(1, sizeof(Fnt));
       +        font->xfont = xfont;
       +        font->pattern = pattern;
       +        font->h = xfont->ascent + xfont->descent;
                font->dpy = drw->dpy;
       +
                return font;
        }
        
       -Fnt*
       -drw_font_create(Drw *drw, const char *fontname) {
       -        return drw_font_xcreate(drw, fontname, NULL);
       +static void
       +xfont_free(Fnt *font)
       +{
       +        if (!font)
       +                return;
       +        if (font->pattern)
       +                FcPatternDestroy(font->pattern);
       +        XftFontClose(font->dpy, font->xfont);
       +        free(font);
        }
        
       -void
       -drw_load_fonts(Drw* drw, const char *fonts[], size_t fontcount) {
       +Fnt*
       +drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
       +{
       +        Fnt *cur, *ret = NULL;
                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;
       +
       +        if (!drw || !fonts)
       +                return NULL;
       +
       +        for (i = 1; i <= fontcount; i++) {
       +                if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
       +                        cur->next = ret;
       +                        ret = cur;
                        }
                }
       +        return (drw->fonts = ret);
       +}
       +
       +void
       +drw_fontset_free(Fnt *font)
       +{
       +        if (font) {
       +                drw_fontset_free(font->next);
       +                xfont_free(font);
       +        }
        }
        
        void
       -drw_font_free(Fnt *font) {
       -        if(!font)
       +drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
       +{
       +        if (!drw || !dest || !clrname)
                        return;
       -        if(font->pattern)
       -                FcPatternDestroy(font->pattern);
       -        XftFontClose(font->dpy, font->xfont);
       -        free(font);
       +
       +        if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
       +                               DefaultColormap(drw->dpy, drw->screen),
       +                               clrname, dest))
       +                die("error, cannot allocate color '%s'", clrname);
        }
        
       +/* Wrapper to create color schemes. The caller has to call free(3) on the
       + * returned color scheme when done using it. */
        Clr *
       -drw_clr_create(Drw *drw, const char *clrname) {
       -        Clr *clr;
       -        Colormap cmap;
       -        Visual *vis;
       +drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
       +{
       +        size_t i;
       +        Clr *ret;
        
       -        if(!drw)
       +        /* need at least two colors for a scheme */
       +        if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
                        return NULL;
       -        clr = (Clr *)calloc(1, sizeof(Clr));
       -        if(!clr)
       -                return NULL;
       -        cmap = DefaultColormap(drw->dpy, drw->screen);
       -        vis = DefaultVisual(drw->dpy, drw->screen);
       -        if(!XftColorAllocName(drw->dpy, vis, cmap, clrname, &clr->rgb))
       -                die("error, cannot allocate color '%s'\n", clrname);
       -        clr->pix = clr->rgb.pixel;
       -        return clr;
       +
       +        for (i = 0; i < clrcount; i++)
       +                drw_clr_create(drw, &ret[i], clrnames[i]);
       +        return ret;
        }
        
        void
       -drw_clr_free(Clr *clr) {
       -        if(clr)
       -                free(clr);
       +drw_setfontset(Drw *drw, Fnt *set)
       +{
       +        if (drw)
       +                drw->fonts = set;
        }
        
        void
       -drw_setscheme(Drw *drw, ClrScheme *scheme) {
       -        if(drw && scheme)
       -                drw->scheme = scheme;
       +drw_setscheme(Drw *drw, Clr *scm)
       +{
       +        if (drw)
       +                drw->scheme = scm;
        }
        
        void
       -drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) {
       -        int dx;
       -
       -        if(!drw || !drw->fontcount || !drw->scheme)
       +drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
       +{
       +        if (!drw || !drw->scheme)
                        return;
       -        XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->pix : drw->scheme->fg->pix);
       -        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+1, dx+1);
       -        else if(empty)
       -                XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x+1, y+1, dx, dx);
       +        XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
       +        if (filled)
       +                XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
       +        else
       +                XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
        }
        
        int
       -drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert) {
       +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
       +{
                char buf[1024];
       -        int tx, ty, th;
       -        Extnts tex;
       -        Colormap cmap;
       -        Visual *vis;
       -        XftDraw *d;
       -        Fnt *curfont, *nextfont;
       +        int ty;
       +        unsigned int ew;
       +        XftDraw *d = NULL;
       +        Fnt *usedfont, *curfont, *nextfont;
                size_t i, len;
       -        int utf8strlen, utf8charlen, render;
       +        int utf8strlen, utf8charlen, render = x || y || w || h;
                long utf8codepoint = 0;
                const char *utf8str;
                FcCharSet *fccharset;
       @@ -235,73 +252,67 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex
                XftResult result;
                int charexists = 0;
        
       -        if (!(render = x || y || w || h)) {
       -                w = ~w;
       -        }
       -
       -        if (!drw || !drw->scheme) {
       +        if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
                        return 0;
       -        } else if (render) {
       -                XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->fg->pix : drw->scheme->bg->pix);
       -                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);
       +        if (!render) {
       +                w = ~w;
       +        } else {
       +                XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
       +                XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
       +                d = XftDrawCreate(drw->dpy, drw->drawable,
       +                                  DefaultVisual(drw->dpy, drw->screen),
       +                                  DefaultColormap(drw->dpy, drw->screen));
       +                x += lpad;
       +                w -= lpad;
                }
        
       -        curfont = drw->fonts[0];
       +        usedfont = drw->fonts;
                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->dpy, drw->fonts[i]->xfont, utf8codepoint);
       +                        for (curfont = drw->fonts; curfont; curfont = curfont->next) {
       +                                charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
                                        if (charexists) {
       -                                        if (drw->fonts[i] == curfont) {
       +                                        if (curfont == usedfont) {
                                                        utf8strlen += utf8charlen;
                                                        text += utf8charlen;
                                                } else {
       -                                                nextfont = drw->fonts[i];
       +                                                nextfont = curfont;
                                                }
                                                break;
                                        }
                                }
        
       -                        if (!charexists || (nextfont && nextfont != curfont)) {
       +                        if (!charexists || nextfont)
                                        break;
       -                        } else {
       +                        else
                                        charexists = 0;
       -                        }
                        }
        
                        if (utf8strlen) {
       -                        drw_font_getexts(curfont, utf8str, utf8strlen, &tex);
       +                        drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
                                /* shorten text if necessary */
       -                        for(len = MIN(utf8strlen, (sizeof buf) - 1); len && (tex.w > w - drw->fonts[0]->h || w < drw->fonts[0]->h); len--)
       -                                drw_font_getexts(curfont, utf8str, len, &tex);
       +                        for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--)
       +                                drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
        
                                if (len) {
                                        memcpy(buf, utf8str, len);
                                        buf[len] = '\0';
       -                                if(len < utf8strlen)
       -                                        for(i = len; i && i > len - 3; buf[--i] = '.');
       +                                if (len < utf8strlen)
       +                                        for (i = len; i && i > len - 3; buf[--i] = '.')
       +                                                ; /* NOP */
        
                                        if (render) {
       -                                        th = curfont->ascent + curfont->descent;
       -                                        ty = y + (h / 2) - (th / 2) + curfont->ascent;
       -                                        tx = x + (h / 2);
       -                                        XftDrawStringUtf8(d, invert ? &drw->scheme->bg->rgb : &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len);
       +                                        ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
       +                                        XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
       +                                                          usedfont->xfont, x, ty, (XftChar8 *)buf, len);
                                        }
       -
       -                                x += tex.w;
       -                                w -= tex.w;
       +                                x += ew;
       +                                w -= ew;
                                }
                        }
        
       @@ -309,28 +320,21 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex
                                break;
                        } else if (nextfont) {
                                charexists = 0;
       -                        curfont = nextfont;
       +                        usedfont = nextfont;
                        } else {
                                /* Regardless of whether or not a fallback font is found, the
       -                         * character must be drawn.
       -                         */
       +                         * 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 for more
       -                                 * information.
       -                                 */
       -                                die("The first font in the cache must be loaded from a font string.\n");
       +                        if (!drw->fonts->pattern) {
       +                                /* Refer to the comment in xfont_create for more information. */
       +                                die("the first font in the cache must be loaded from a font string.");
                                }
        
       -                        fcpattern = FcPatternDuplicate(drw->fonts[0]->pattern);
       +                        fcpattern = FcPatternDuplicate(drw->fonts->pattern);
                                FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
                                FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
        
       @@ -342,70 +346,76 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex
                                FcPatternDestroy(fcpattern);
        
                                if (match) {
       -                                curfont = drw_font_xcreate(drw, NULL, match);
       -                                if (curfont && XftCharExists(drw->dpy, curfont->xfont, utf8codepoint)) {
       -                                        drw->fonts[drw->fontcount++] = curfont;
       +                                usedfont = xfont_create(drw, NULL, match);
       +                                if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
       +                                        for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
       +                                                ; /* NOP */
       +                                        curfont->next = usedfont;
                                        } else {
       -                                        if (curfont) {
       -                                                drw_font_free(curfont);
       -                                        }
       -                                        curfont = drw->fonts[0];
       +                                        xfont_free(usedfont);
       +                                        usedfont = drw->fonts;
                                        }
                                }
                        }
                }
       -
       -        if (render) {
       +        if (d)
                        XftDrawDestroy(d);
       -        }
        
       -        return x;
       +        return x + (render ? w : 0);
        }
        
        void
       -drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) {
       -        if(!drw)
       +drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
       +{
       +        if (!drw)
                        return;
       +
                XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
                XSync(drw->dpy, False);
        }
        
       +unsigned int
       +drw_fontset_getwidth(Drw *drw, const char *text)
       +{
       +        if (!drw || !drw->fonts || !text)
       +                return 0;
       +        return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
       +}
        
        void
       -drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *tex) {
       +drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
       +{
                XGlyphInfo ext;
        
       -        if(!font || !text)
       +        if (!font || !text)
                        return;
       -        XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
       -        tex->h = font->h;
       -        tex->w = ext.xOff;
       -}
       -
       -unsigned int
       -drw_font_getexts_width(Fnt *font, const char *text, unsigned int len) {
       -        Extnts tex;
        
       -        if(!font)
       -                return -1;
       -        drw_font_getexts(font, text, len, &tex);
       -        return tex.w;
       +        XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
       +        if (w)
       +                *w = ext.xOff;
       +        if (h)
       +                *h = font->h;
        }
        
        Cur *
       -drw_cur_create(Drw *drw, int shape) {
       -        Cur *cur = (Cur *)calloc(1, sizeof(Cur));
       +drw_cur_create(Drw *drw, int shape)
       +{
       +        Cur *cur;
        
       -        if(!drw || !cur)
       +        if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
                        return NULL;
       +
                cur->cursor = XCreateFontCursor(drw->dpy, shape);
       +
                return cur;
        }
        
        void
       -drw_cur_free(Drw *drw, Cur *cursor) {
       -        if(!drw || !cursor)
       +drw_cur_free(Drw *drw, Cur *cursor)
       +{
       +        if (!cursor)
                        return;
       +
                XFreeCursor(drw->dpy, cursor->cursor);
                free(cursor);
        }
 (DIR) diff --git a/drw.h b/drw.h
       @@ -1,29 +1,19 @@
        /* See LICENSE file for copyright and license details. */
       -#define DRW_FONT_CACHE_SIZE 32
       -
       -typedef struct {
       -        unsigned long pix;
       -        XftColor rgb;
       -} Clr;
        
        typedef struct {
                Cursor cursor;
        } Cur;
        
       -typedef struct {
       +typedef struct Fnt {
                Display *dpy;
       -        int ascent;
       -        int descent;
                unsigned int h;
                XftFont *xfont;
                FcPattern *pattern;
       +        struct Fnt *next;
        } Fnt;
        
       -typedef struct {
       -        Clr *fg;
       -        Clr *bg;
       -        Clr *border;
       -} ClrScheme;
       +enum { ColFg, ColBg }; /* Clr scheme index */
       +typedef XftColor Clr;
        
        typedef struct {
                unsigned int w, h;
       @@ -32,43 +22,36 @@ typedef struct {
                Window root;
                Drawable drawable;
                GC gc;
       -        ClrScheme *scheme;
       -        size_t fontcount;
       -        Fnt *fonts[DRW_FONT_CACHE_SIZE];
       +        Clr *scheme;
       +        Fnt *fonts;
        } Drw;
        
       -typedef struct {
       -        unsigned int w;
       -        unsigned int h;
       -} Extnts;
       -
        /* Drawable abstraction */
        Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
        void drw_resize(Drw *drw, unsigned int w, unsigned int h);
        void drw_free(Drw *drw);
        
        /* Fnt abstraction */
       -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 *extnts);
       -unsigned int drw_font_getexts_width(Fnt *font, const char *text, unsigned int len);
       +Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
       +void drw_fontset_free(Fnt* set);
       +unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
       +void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
        
       -/* Colour abstraction */
       -Clr *drw_clr_create(Drw *drw, const char *clrname);
       -void drw_clr_free(Clr *clr);
       +/* Colorscheme abstraction */
       +void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
       +Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
        
        /* Cursor abstraction */
        Cur *drw_cur_create(Drw *drw, int shape);
        void drw_cur_free(Drw *drw, Cur *cursor);
        
        /* Drawing context manipulation */
       -void drw_setfont(Drw *drw, Fnt *font);
       -void drw_setscheme(Drw *drw, ClrScheme *scheme);
       +void drw_setfontset(Drw *drw, Fnt *set);
       +void drw_setscheme(Drw *drw, Clr *scm);
        
        /* Drawing functions */
       -void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert);
       -int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert);
       +void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
       +int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
        
        /* Map functions */
        void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
 (DIR) diff --git a/util.c b/util.c
       @@ -2,16 +2,34 @@
        #include <stdarg.h>
        #include <stdio.h>
        #include <stdlib.h>
       +#include <string.h>
        
        #include "util.h"
        
       +void *
       +ecalloc(size_t nmemb, size_t size)
       +{
       +        void *p;
       +
       +        if (!(p = calloc(nmemb, size)))
       +                die("calloc:");
       +        return p;
       +}
       +
        void
       -die(const char *errstr, ...) {
       +die(const char *fmt, ...) {
                va_list ap;
        
       -        va_start(ap, errstr);
       -        vfprintf(stderr, errstr, ap);
       +        va_start(ap, fmt);
       +        vfprintf(stderr, fmt, ap);
                va_end(ap);
       -        exit(EXIT_FAILURE);
       -}
        
       +        if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
       +                fputc(' ', stderr);
       +                perror(NULL);
       +        } else {
       +                fputc('\n', stderr);
       +        }
       +
       +        exit(1);
       +}