The xft dmenu patch just needed a context line added and a context line removed
to apply cleanly to git HEAD.
diff --git a/config.mk b/config.mk
index c0d466b..04e2dce 100644
--- a/config.mk
+++ b/config.mk
@@ -12,9 +12,13 @@ X11LIB = /usr/X11R6/lib
 XINERAMALIBS  = -lXinerama
 XINERAMAFLAGS = -DXINERAMA
 
+# Xft, comment if you don't want it
+XFTINC = -I/usr/include/freetype2
+XFTLIBS  = -lXft -lXrender -lfreetype -lz -lfontconfig
+
 # includes and libs
-INCS = -I${X11INC}
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS}
+INCS = -I${X11INC} ${XFTINC}
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${XFTLIBS}
 
 # flags
 CPPFLAGS = -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" 
${XINERAMAFLAGS}
diff --git a/dmenu.1 b/dmenu.1
index 2897ab1..d06b484 100644
--- a/dmenu.1
+++ b/dmenu.1
@@ -58,7 +58,7 @@ dmenu is displayed on the monitor supplied.
 defines the prompt to be displayed to the left of the input field.
 .TP
 .BI \-fn " font"
-defines the font or font set used.
+defines the font or font set used. eg. "fixed" or "Monospace-12:normal" (a xft 
font)
 .TP
 .BI \-nb " color"
 defines the normal background color.
diff --git a/dmenu.c b/dmenu.c
index 94c70de..cc6dedf 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -17,6 +17,7 @@
                              * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - 
MAX((y),(r).y_org)))
 #define MIN(a,b)              ((a) < (b) ? (a) : (b))
 #define MAX(a,b)              ((a) > (b) ? (a) : (b))
+#define DEFFONT "fixed" /* xft example: "Monospace-11" */
 
 typedef struct Item Item;
 struct Item {
@@ -27,6 +28,7 @@ struct Item {
 
 static void appenditem(Item *item, Item **list, Item **last);
 static void calcoffsets(void);
+static void cleanup(void);
 static char *cistrstr(const char *s, const char *sub);
 static void drawmenu(void);
 static void grabkeyboard(void);
@@ -44,9 +46,9 @@ static char text[BUFSIZ] = "";
 static int bh, mw, mh;
 static int inputw, promptw;
 static size_t cursor = 0;
-static unsigned long normcol[ColLast];
-static unsigned long selcol[ColLast];
-static unsigned long outcol[ColLast];
+static ColorSet *normcol;
+static ColorSet *selcol;
+static ColorSet *outcol;
 static Atom clip, utf8;
 static DC *dc;
 static Item *items = NULL;
@@ -55,6 +57,8 @@ static Item *prev, *curr, *next, *sel;
 static Window win;
 static XIC xic;
 static int mon = -1;
+static Bool running = True;
+static int ret = EXIT_SUCCESS;
 
 #include "config.h"
 
@@ -103,7 +107,10 @@ main(int argc, char *argv[]) {
                        usage();
 
        dc = initdc();
-       initfont(dc, font);
+       initfont(dc, font ? font : DEFFONT);
+       normcol = initcolor(dc, normfgcolor, normbgcolor);
+       selcol = initcolor(dc, selfgcolor, selbgcolor);
+       outcol = initcolor(dc, outfgcolor, outbgcolor);
 
        if(fast) {
                grabkeyboard();
@@ -116,7 +123,8 @@ main(int argc, char *argv[]) {
        setup();
        run();
 
-       return 1; /* unreachable */
+       cleanup();
+       return ret;
 }
 
 void
@@ -159,6 +167,15 @@ cistrstr(const char *s, const char *sub) {
 }
 
 void
+cleanup(void) {
+       freecol(dc, normcol);
+       freecol(dc, selcol);
+       XDestroyWindow(dc->dpy, win);
+       XUngrabKeyboard(dc->dpy, CurrentTime);
+       freedc(dc);
+}
+
+void
 drawmenu(void) {
        int curpos;
        Item *item;
@@ -166,7 +183,7 @@ drawmenu(void) {
        dc->x = 0;
        dc->y = 0;
        dc->h = bh;
-       drawrect(dc, 0, 0, mw, mh, True, BG(dc, normcol));
+       drawrect(dc, 0, 0, mw, mh, True, normcol->BG);
 
        if(prompt && *prompt) {
                dc->w = promptw;
@@ -177,7 +194,7 @@ drawmenu(void) {
        dc->w = (lines > 0 || !matches) ? mw - dc->x : inputw;
        drawtext(dc, text, normcol);
        if((curpos = textnw(dc, text, cursor) + dc->h/2 - 2) < dc->w)
-               drawrect(dc, curpos, 2, 1, dc->h - 4, True, FG(dc, normcol));
+               drawrect(dc, curpos, 2, 1, dc->h - 4, True, normcol->FG);
 
        if(lines > 0) {
                /* draw vertical list */
@@ -281,9 +298,12 @@ keypress(XKeyEvent *ev) {
                        return;
                case XK_Return:
                case XK_KP_Enter:
+                       ret = EXIT_SUCCESS;
+                       running = False;
                        break;
                case XK_bracketleft:
-                       exit(EXIT_FAILURE);
+                       ret = EXIT_FAILURE;
+                       running = False;
                default:
                        return;
                }
@@ -330,7 +350,8 @@ keypress(XKeyEvent *ev) {
                sel = matchend;
                break;
        case XK_Escape:
-               exit(EXIT_FAILURE);
+               ret = EXIT_FAILURE;
+               running = False;
        case XK_Home:
                if(sel == matches) {
                        cursor = 0;
@@ -368,8 +389,10 @@ keypress(XKeyEvent *ev) {
        case XK_Return:
        case XK_KP_Enter:
                puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
-               if(!(ev->state & ControlMask))
-                       exit(EXIT_SUCCESS);
+               if(!(ev->state & ControlMask)) {
+                       ret = EXIT_SUCCESS;
+                       running = False;
+               }
                if(sel)
                        sel->out = True;
                break;
@@ -505,7 +528,7 @@ void
 run(void) {
        XEvent ev;
 
-       while(!XNextEvent(dc->dpy, &ev)) {
+       while(running && !XNextEvent(dc->dpy, &ev)) {
                if(XFilterEvent(&ev, win))
                        continue;
                switch(ev.type) {
@@ -539,13 +562,6 @@ setup(void) {
        XineramaScreenInfo *info;
 #endif
 
-       normcol[ColBG] = getcolor(dc, normbgcolor);
-       normcol[ColFG] = getcolor(dc, normfgcolor);
-       selcol[ColBG]  = getcolor(dc, selbgcolor);
-       selcol[ColFG]  = getcolor(dc, selfgcolor);
-       outcol[ColBG]  = getcolor(dc, outbgcolor);
-       outcol[ColFG]  = getcolor(dc, outfgcolor);
-
        clip = XInternAtom(dc->dpy, "CLIPBOARD",   False);
        utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False);
 
@@ -601,7 +617,7 @@ setup(void) {
 
        /* create menu window */
        swa.override_redirect = True;
-       swa.background_pixel = normcol[ColBG];
+       swa.background_pixel = normcol->BG;
        swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
        win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0,
                            DefaultDepth(dc->dpy, screen), CopyFromParent,
diff --git a/draw.c b/draw.c
index 76f0c54..09e66ea 100644
--- a/draw.c
+++ b/draw.c
@@ -9,9 +9,6 @@
 
 #define MAX(a, b)  ((a) > (b) ? (a) : (b))
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
-#define DEFAULTFN  "fixed"
-
-static Bool loadfont(DC *dc, const char *fontstr);
 
 void
 drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, 
unsigned long color) {
@@ -23,7 +20,7 @@ drawrect(DC *dc, int x, int y, unsigned int w, unsigned int 
h, Bool fill, unsign
 }
 
 void
-drawtext(DC *dc, const char *text, unsigned long col[ColLast]) {
+drawtext(DC *dc, const char *text, ColorSet *col) {
        char buf[BUFSIZ];
        size_t mn, n = strlen(text);
 
@@ -35,19 +32,24 @@ drawtext(DC *dc, const char *text, unsigned long 
col[ColLast]) {
        if(mn < n)
                for(n = MAX(mn-3, 0); n < mn; buf[n++] = '.');
 
-       drawrect(dc, 0, 0, dc->w, dc->h, True, BG(dc, col));
+       drawrect(dc, 0, 0, dc->w, dc->h, True, col->BG);
        drawtextn(dc, buf, mn, col);
 }
 
 void
-drawtextn(DC *dc, const char *text, size_t n, unsigned long col[ColLast]) {
+drawtextn(DC *dc, const char *text, size_t n, ColorSet *col) {
        int x = dc->x + dc->font.height/2;
        int y = dc->y + dc->font.ascent+1;
 
-       XSetForeground(dc->dpy, dc->gc, FG(dc, col));
-       if(dc->font.set)
+       XSetForeground(dc->dpy, dc->gc, col->FG);
+       if(dc->font.xft_font) {
+               if(!dc->xftdraw)
+                       eprintf("error, xft drawable does not exist");
+               XftDrawStringUtf8(dc->xftdraw, &col->FG_xft,
+                                 dc->font.xft_font, x, y, (unsigned 
char*)text, n);
+       } else if(dc->font.set) {
                XmbDrawString(dc->dpy, dc->canvas, dc->font.set, dc->gc, x, y, 
text, n);
-       else {
+       } else {
                XSetFont(dc->dpy, dc->gc, dc->font.xfont->fid);
                XDrawString(dc->dpy, dc->canvas, dc->gc, x, y, text, n);
        }
@@ -69,16 +71,33 @@ eprintf(const char *fmt, ...) {
 }
 
 void
+freecol(DC *dc, ColorSet *col) {
+       if(col) {
+               if(&col->FG_xft)
+                       XftColorFree(dc->dpy, DefaultVisual(dc->dpy, 
DefaultScreen(dc->dpy)),
+                                    DefaultColormap(dc->dpy, 
DefaultScreen(dc->dpy)), &col->FG_xft);
+               free(col);
+       }
+}
+
+void
 freedc(DC *dc) {
+       if(dc->font.xft_font) {
+               XftFontClose(dc->dpy, dc->font.xft_font);
+               XftDrawDestroy(dc->xftdraw);
+       }
        if(dc->font.set)
                XFreeFontSet(dc->dpy, dc->font.set);
        if(dc->font.xfont)
                XFreeFont(dc->dpy, dc->font.xfont);
        if(dc->canvas)
                XFreePixmap(dc->dpy, dc->canvas);
-       XFreeGC(dc->dpy, dc->gc);
-       XCloseDisplay(dc->dpy);
-       free(dc);
+       if(dc->gc)
+               XFreeGC(dc->dpy, dc->gc);
+       if(dc->dpy)
+               XCloseDisplay(dc->dpy);
+       if(dc)
+               free(dc);
 }
 
 unsigned long
@@ -91,6 +110,20 @@ getcolor(DC *dc, const char *colstr) {
        return color.pixel;
 }
 
+ColorSet *
+initcolor(DC *dc, const char * foreground, const char * background) {
+       ColorSet * col = (ColorSet *)malloc(sizeof(ColorSet));
+       if(!col)
+               eprintf("error, cannot allocate memory for color set");
+       col->BG = getcolor(dc, background);
+       col->FG = getcolor(dc, foreground);
+       if(dc->font.xft_font)
+               if(!XftColorAllocName(dc->dpy, DefaultVisual(dc->dpy, 
DefaultScreen(dc->dpy)),
+                       DefaultColormap(dc->dpy, DefaultScreen(dc->dpy)), 
foreground, &col->FG_xft))
+                       eprintf("error, cannot allocate xft font color '%s'\n", 
foreground);
+       return col;
+}
+
 DC *
 initdc(void) {
        DC *dc;
@@ -109,39 +142,33 @@ initdc(void) {
 
 void
 initfont(DC *dc, const char *fontstr) {
-       if(!loadfont(dc, fontstr ? fontstr : DEFAULTFN)) {
-               if(fontstr != NULL)
-                       fprintf(stderr, "cannot load font '%s'\n", fontstr);
-               if(fontstr == NULL || !loadfont(dc, DEFAULTFN))
-                       eprintf("cannot load font '%s'\n", DEFAULTFN);
-       }
-       dc->font.height = dc->font.ascent + dc->font.descent;
-}
-
-Bool
-loadfont(DC *dc, const char *fontstr) {
        char *def, **missing, **names;
        int i, n;
        XFontStruct **xfonts;
 
-       if(!*fontstr)
-               return False;
-       if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, 
&def))) {
+       missing = NULL;
+       if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) {
+               dc->font.ascent = dc->font.xfont->ascent;
+               dc->font.descent = dc->font.xfont->descent;
+               dc->font.width = dc->font.xfont->max_bounds.width;
+       } else if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, 
&n, &def))) {
                n = XFontsOfFontSet(dc->font.set, &xfonts, &names);
                for(i = 0; i < n; i++) {
-                       dc->font.ascent  = MAX(dc->font.ascent,  
xfonts[i]->ascent);
+                       dc->font.ascent= MAX(dc->font.ascent,xfonts[i]->ascent);
                        dc->font.descent = MAX(dc->font.descent, 
xfonts[i]->descent);
-                       dc->font.width   = MAX(dc->font.width,   
xfonts[i]->max_bounds.width);
+                       dc->font.width = MAX(dc->font.width, 
xfonts[i]->max_bounds.width);
                }
-       }
-       else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) {
-               dc->font.ascent  = dc->font.xfont->ascent;
-               dc->font.descent = dc->font.xfont->descent;
-               dc->font.width   = dc->font.xfont->max_bounds.width;
+       } else if((dc->font.xft_font = XftFontOpenName(dc->dpy, 
DefaultScreen(dc->dpy), fontstr))) {
+               dc->font.ascent = dc->font.xft_font->ascent;
+               dc->font.descent = dc->font.xft_font->descent;
+               dc->font.width = dc->font.xft_font->max_advance_width;
+       } else {
+               eprintf("cannot load font '%s'\n", fontstr);
        }
        if(missing)
                XFreeStringList(missing);
-       return dc->font.set || dc->font.xfont;
+       dc->font.height = dc->font.ascent + dc->font.descent;
+       return;
 }
 
 void
@@ -151,20 +178,29 @@ mapdc(DC *dc, Window win, unsigned int w, unsigned int h) 
{
 
 void
 resizedc(DC *dc, unsigned int w, unsigned int h) {
+       int screen = DefaultScreen(dc->dpy);
        if(dc->canvas)
                XFreePixmap(dc->dpy, dc->canvas);
 
        dc->w = w;
        dc->h = h;
        dc->canvas = XCreatePixmap(dc->dpy, DefaultRootWindow(dc->dpy), w, h,
-                                  DefaultDepth(dc->dpy, 
DefaultScreen(dc->dpy)));
+                                  DefaultDepth(dc->dpy, screen));
+       if(dc->font.xft_font && !(dc->xftdraw)) {
+               dc->xftdraw = XftDrawCreate(dc->dpy, dc->canvas, 
DefaultVisual(dc->dpy,screen), DefaultColormap(dc->dpy,screen));
+               if(!(dc->xftdraw))
+                       eprintf("error, cannot create xft drawable\n");
+       }
 }
 
 int
 textnw(DC *dc, const char *text, size_t len) {
-       if(dc->font.set) {
+       if(dc->font.xft_font) {
+               XGlyphInfo gi;
+               XftTextExtentsUtf8(dc->dpy, dc->font.xft_font, (const 
FcChar8*)text, len, &gi);
+               return gi.width;
+       } else if(dc->font.set) {
                XRectangle r;
-
                XmbTextExtents(dc->font.set, text, len, NULL, &r);
                return r.width;
        }
diff --git a/draw.h b/draw.h
index 43a57bf..1b4f21a 100644
--- a/draw.h
+++ b/draw.h
@@ -1,9 +1,6 @@
 /* See LICENSE file for copyright and license details. */
 
-#define FG(dc, col)  ((col)[(dc)->invert ? ColBG : ColFG])
-#define BG(dc, col)  ((col)[(dc)->invert ? ColFG : ColBG])
-
-enum { ColBG, ColFG, ColBorder, ColLast };
+#include <X11/Xft/Xft.h>
 
 typedef struct {
        int x, y, w, h;
@@ -11,6 +8,7 @@ typedef struct {
        Display *dpy;
        GC gc;
        Pixmap canvas;
+       XftDraw *xftdraw;
        struct {
                int ascent;
                int descent;
@@ -18,15 +16,24 @@ typedef struct {
                int width;
                XFontSet set;
                XFontStruct *xfont;
+               XftFont *xft_font;
        } font;
 } DC;  /* draw context */
 
+typedef struct {
+       unsigned long FG;
+       XftColor FG_xft;
+       unsigned long BG;
+} ColorSet;
+
 void drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, 
unsigned long color);
-void drawtext(DC *dc, const char *text, unsigned long col[ColLast]);
-void drawtextn(DC *dc, const char *text, size_t n, unsigned long col[ColLast]);
+void drawtext(DC *dc, const char *text, ColorSet *col);
+void drawtextn(DC *dc, const char *text, size_t n, ColorSet *col);
+void freecol(DC *dc, ColorSet *col);
 void eprintf(const char *fmt, ...);
 void freedc(DC *dc);
 unsigned long getcolor(DC *dc, const char *colstr);
+ColorSet *initcolor(DC *dc, const char *foreground, const char *background);
 DC *initdc(void);
 void initfont(DC *dc, const char *fontstr);
 void mapdc(DC *dc, Window win, unsigned int w, unsigned int h);

Reply via email to