This patch adds support for xft font rendering to dmenu (4.1.1).

Shouts go out to lattenwald (utf8 support) and R. Kyle Murphy (fg color fix)

The patch can also be found at:
http://aur.archlinux.org/packages.php?ID=28745

--
Henri
diff -up ../dmenu-4.1.1/config.def.h ../dmenu-4.1.1-xft/config.def.h
--- ../dmenu-4.1.1/config.def.h 2010-05-29 14:56:51.000000000 +0300
+++ ../dmenu-4.1.1-xft/config.def.h     2010-09-01 12:05:27.510000064 +0300
@@ -7,3 +7,4 @@ static const char *normfgcolor = "#00000
 static const char *selbgcolor  = "#0066ff";
 static const char *selfgcolor  = "#ffffff";
 static unsigned int spaceitem  = 30; /* px between menu items */
+static const char *fontxft     = "Monospace-10:normal"; /*if set xft is used 
*/  
diff -up ../dmenu-4.1.1/config.mk ../dmenu-4.1.1-xft/config.mk
--- ../dmenu-4.1.1/config.mk    2010-05-29 14:56:51.000000000 +0300
+++ ../dmenu-4.1.1-xft/config.mk        2010-09-01 12:05:27.513000063 +0300
@@ -15,8 +15,8 @@ XINERAMALIBS = -L${X11LIB} -lXinerama
 XINERAMAFLAGS = -DXINERAMA
 
 # includes and libs
-INCS = -I. -I/usr/include -I${X11INC}
-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS}
+INCS = -I. -I/usr/include -I${X11INC} -I/usr/include -I/usr/include/freetype2
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} -lXft -lX11 -lXrender 
-lfreetype -lz -lfontconfig -lXrender -lX11
 
 # flags
 CPPFLAGS = -D_BSD_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
diff -up ../dmenu-4.1.1/dmenu.1 ../dmenu-4.1.1-xft/dmenu.1
--- ../dmenu-4.1.1/dmenu.1      2010-05-29 14:56:51.000000000 +0300
+++ ../dmenu-4.1.1-xft/dmenu.1  2010-09-01 12:05:27.515000063 +0300
@@ -7,6 +7,7 @@ dmenu \- dynamic menu
 .RB [ \-b ]
 .RB [ \-l " <lines>"]
 .RB [ \-fn " <font>"]
+.RB [ \-fa " <xftfont>"]
 .RB [ \-nb " <color>"]
 .RB [ \-nf " <color>"]
 .RB [ \-p " <prompt>"]
@@ -34,6 +35,9 @@ The given number of lines will be displa
 .B \-fn <font>
 defines the font.
 .TP
+.B \-fa <font>
+defines the xft font.
+.TP
 .B \-nb <color>
 defines the normal background color (#RGB, #RRGGBB, and color names are 
supported).
 .TP
diff -up ../dmenu-4.1.1/dmenu.c ../dmenu-4.1.1-xft/dmenu.c
--- ../dmenu-4.1.1/dmenu.c      2010-05-29 14:56:51.000000000 +0300
+++ ../dmenu-4.1.1-xft/dmenu.c  2010-09-01 12:05:27.520000063 +0300
@@ -13,6 +13,7 @@
 #ifdef XINERAMA
 #include <X11/extensions/Xinerama.h>
 #endif
+#include <X11/Xft/Xft.h>
 
 /* macros */
 #define CLEANMASK(mask)         (mask & ~(numlockmask | LockMask))
@@ -29,6 +30,7 @@ typedef struct {
        int x, y, w, h;
        unsigned long norm[ColLast];
        unsigned long sel[ColLast];
+       Bool selected;
        Drawable drawable;
        GC gc;
        struct {
@@ -38,6 +40,16 @@ typedef struct {
                int descent;
                int height;
        } font;
+       XftDraw *xftdraw;
+       XftColor xftselcolor;
+       XftColor xftcolor;
+       XGlyphInfo gi;
+       struct {
+               XftFont *xft_font;
+               int ascent;
+               int descent;
+               int height;
+       } xftfont;
 } DC; /* draw context */
 
 typedef struct Item Item;
@@ -135,18 +147,23 @@ calcoffsetsh(void) {
 void
 calcoffsetsv(void) {
        static unsigned int h;
+       int h2;
 
        if(!curr)
                return;
-       h = (dc.font.height + 2) * (lines + 1);
+       if(fontxft)
+         h2 = dc.xftfont.height;
+       else
+         h2 = dc.font.height;
+       h = (h2 + 2) * (lines + 1);
        for(next = curr; next; next=next->right) {
-               h -= dc.font.height + 2;
+               h -= h2 + 2;
                if(h <= 0)
                        break;
        }
-       h = (dc.font.height + 2) * (lines + 1);
+       h = (h2 + 2) * (lines + 1);
        for(prev = curr; prev && prev->left; prev=prev->left) {
-               h -= dc.font.height + 2;
+               h -= h2 + 2;
                if(h <= 0)
                        break;
        }
@@ -185,9 +202,14 @@ cleanup(void) {
                free(allitems);
                allitems = itm;
        }
+       if(fontxft) {
+               XftColorFree (dpy, DefaultVisual(dpy, screen), 
DefaultColormap(dpy, screen), &dc.xftcolor);
+               XftFontClose (dpy, dc.xftfont.xft_font);
+               XftDrawDestroy(dc.xftdraw);
+       }
        if(dc.font.set)
                XFreeFontSet(dpy, dc.font.set);
-       else
+       else if(!fontxft)
                XFreeFont(dpy, dc.font.xfont);
        XFreePixmap(dpy, dc.drawable);
        XFreeGC(dpy, dc.gc);
@@ -198,8 +220,15 @@ cleanup(void) {
 void
 drawcursor(void) {
        XRectangle r = { dc.x, dc.y + 2, 1, dc.font.height - 2 };
+       int h2;
 
-       r.x += textnw(text, cursor) + dc.font.height / 2;
+       if(fontxft)
+         h2 = dc.xftfont.height;
+       else
+         h2 = dc.font.height;
+
+       r.height = h2 - 2;
+       r.x += textnw(text, cursor) + h2 / 2;
 
        XSetForeground(dpy, dc.gc, dc.norm[ColFG]);
        XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
@@ -213,9 +242,11 @@ drawmenu(void) {
        dc.h = mh;
        drawtext(NULL, dc.norm);
        /* print prompt? */
-       if(prompt) {
+       if(promptw) {
                dc.w = promptw;
+               dc.selected = True;
                drawtext(prompt, dc.sel);
+               dc.selected = False;
                dc.x += dc.w;
        }
        dc.w = mw - dc.x;
@@ -244,7 +275,13 @@ drawmenuh(void) {
        dc.x += dc.w;
        for(i = curr; i != next; i=i->right) {
                dc.w = MIN(textw(i->text), mw / 3);
-               drawtext(i->text, (sel == i) ? dc.sel : dc.norm);
+               if(sel == i) {
+                 dc.selected = True;
+                 drawtext(i->text, dc.sel);
+                 dc.selected = False;
+               } else {
+                 drawtext(i->text, dc.norm);
+               }
                dc.x += dc.w;
        }
        dc.w = spaceitem;
@@ -255,12 +292,18 @@ drawmenuh(void) {
 void
 drawmenuv(void) {
        Item *i;
+       int h2;
+
+       if(fontxft)
+         h2 = dc.xftfont.height;
+       else
+         h2 = dc.font.height;
 
        dc.w = mw - dc.x;
-       dc.y += dc.font.height + 2;
+       dc.y += h2 + 2;
        for(i = curr; i != next; i=i->right) {
                drawtext(i->text, (sel == i) ? dc.sel : dc.norm);
-               dc.y += dc.font.height + 2;
+               dc.y += h2 + 2;
        }
        drawtext(NULL, dc.norm);
 }
@@ -268,7 +311,7 @@ drawmenuv(void) {
 void
 drawtext(const char *text, unsigned long col[ColLast]) {
        char buf[256];
-       int i, x, y, h, len, olen;
+       int i, x, y, h, a, len, olen;
        XRectangle r = { dc.x, dc.y, dc.w, dc.h };
 
        XSetForeground(dpy, dc.gc, col[ColBG]);
@@ -276,8 +319,20 @@ drawtext(const char *text, unsigned long
        if(!text)
                return;
        olen = strlen(text);
-       h = dc.font.height;
-       y = dc.y + ((h+2) / 2) - (h / 2) + dc.font.ascent;
+       if(!fontxft) {
+         h = dc.font.height;
+         a = dc.font.ascent;
+       } else {
+         h = dc.xftfont.height;
+         a = dc.xftfont.ascent;
+       }
+       y = dc.y + ((h+2) / 2) - (h / 2) + a;
+#if 0
+       if(dc.xftfont.xft_font) {       
+               h = dc.xftfont.ascent + dc.xftfont.descent;
+               y = dc.y + (dc.h / 2) - (h / 2) + dc.xftfont.ascent;
+       }
+#endif
        x = dc.x + (h / 2);
        /* shorten text if necessary */
        for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; 
len--);
@@ -287,7 +342,15 @@ drawtext(const char *text, unsigned long
        if(len < olen)
                for(i = len; i && i > len - 3; buf[--i] = '.');
        XSetForeground(dpy, dc.gc, col[ColFG]);
-       if(dc.font.set)
+       if(fontxft) {
+               if (!dc.xftdraw)
+                       eprint("error, creating xft drawable failed");
+               if(dc.selected) {
+                       XftDrawStringUtf8(dc.xftdraw, &dc.xftselcolor, 
dc.xftfont.xft_font, x, y, (unsigned char*)buf, len);
+               } else {
+                       XftDrawStringUtf8(dc.xftdraw, &dc.xftcolor, 
dc.xftfont.xft_font, x, y, (unsigned char*)buf, len);
+               }
+       } else if(dc.font.set)
                XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, 
len);
        else
                XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
@@ -359,6 +422,15 @@ initfont(const char *fontstr) {
 }
 
 void
+initxft() {
+       if(!(dc.xftfont.xft_font = XftFontOpenName (dpy, screen, fontxft)))
+               eprint("error, cannot load xft font\n" );
+       dc.xftfont.ascent = dc.xftfont.xft_font->ascent;
+       dc.xftfont.descent = dc.xftfont.xft_font->descent;
+       dc.xftfont.height = dc.xftfont.ascent + dc.xftfont.descent;
+}
+
+void
 kpress(XKeyEvent * e) {
        char buf[sizeof text];
        int i, num, off;
@@ -697,7 +769,15 @@ setup(Bool topbar) {
        dc.norm[ColFG] = getcolor(normfgcolor);
        dc.sel[ColBG] = getcolor(selbgcolor);
        dc.sel[ColFG] = getcolor(selfgcolor);
-       initfont(font);
+       dc.selected = False;
+       if(fontxft){
+               if(!XftColorAllocName(dpy, DefaultVisual(dpy, screen), 
DefaultColormap(dpy, screen), (const char*)normfgcolor, &dc.xftcolor))
+                       eprint("error, cannot allocate xft font color '%s'\n", 
normfgcolor);
+               if(!XftColorAllocName(dpy, DefaultVisual(dpy, screen), 
DefaultColormap(dpy, screen), (const char*)selfgcolor, &dc.xftselcolor))
+                       eprint("error, cannot allocate xft font color '%s'\n", 
normfgcolor);
+        else
+                       initxft();
+       } else initfont(font);
 
        /* menu window */
        wa.override_redirect = True;
@@ -705,7 +785,10 @@ setup(Bool topbar) {
        wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask | 
VisibilityChangeMask;
 
        /* menu window geometry */
-       mh = (dc.font.height + 2) * (lines + 1);
+       if(fontxft) 
+         mh = (dc.xftfont.height + 2) * (lines + 1);
+       else
+         mh = (dc.font.height + 2) * (lines + 1);
 #if XINERAMA
        if(parent == RootWindow(dpy, screen) && XineramaIsActive(dpy) && (info 
= XineramaQueryScreens(dpy, &n))) {
                i = 0;
@@ -741,7 +824,7 @@ setup(Bool topbar) {
        dc.drawable = XCreatePixmap(dpy, parent, mw, mh, DefaultDepth(dpy, 
screen));
        dc.gc = XCreateGC(dpy, parent, 0, NULL);
        XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
-       if(!dc.font.set)
+       if(!dc.font.set && !fontxft)
                XSetFont(dpy, dc.gc, dc.font.xfont->fid);
        if(maxname)
                cmdw = MIN(textw(maxname), mw / 3);
@@ -750,13 +833,20 @@ setup(Bool topbar) {
        text[0] = '\0';
        match(text);
        XMapRaised(dpy, win);
+       if(fontxft) {
+               dc.xftdraw = XftDrawCreate(dpy, dc.drawable, 
DefaultVisual(dpy,screen), DefaultColormap(dpy,screen));
+               if(!dc.xftdraw)
+                       eprint("error, cannot create xft drawable\n");
+       }
 }
 
 int
 textnw(const char *text, unsigned int len) {
-       XRectangle r;
-
-       if(dc.font.set) {
+       if(fontxft) {
+               XftTextExtentsUtf8(dpy, dc.xftfont.xft_font, (const 
FcChar8*)text, len, &dc.gi);
+               return dc.gi.width;
+    } else if(dc.font.set) {
+           XRectangle r;
                XmbTextExtents(dc.font.set, text, len, NULL, &r);
                return r.width;
        }
@@ -765,6 +855,8 @@ textnw(const char *text, unsigned int le
 
 int
 textw(const char *text) {
+       if(fontxft)
+               return textnw(text, strlen(text)) + dc.xftfont.height;
        return textnw(text, strlen(text)) + dc.font.height;
 }
 
@@ -791,6 +883,9 @@ main(int argc, char *argv[]) {
                else if(!strcmp(argv[i], "-fn")) {
                        if(++i < argc) font = argv[i];
                }
+               else if(!strcmp(argv[i], "-fa")) {
+                       if(++i < argc) fontxft = argv[i];
+               }
                else if(!strcmp(argv[i], "-nb")) {
                        if(++i < argc) normbgcolor = argv[i];
                }
@@ -809,7 +904,7 @@ main(int argc, char *argv[]) {
                else if(!strcmp(argv[i], "-v"))
                        eprint("dmenu-"VERSION", © 2006-2010 dmenu engineers, 
see LICENSE for details\n");
                else
-                       eprint("usage: dmenu [-i] [-b] [-e <xid>] [-l <lines>] 
[-fn <font>] [-nb <color>]\n"
+                       eprint("usage: dmenu [-i] [-b] [-e <xid>] [-l <lines>] 
[-fn <font>] [-fa <xftfont>] [-nb <color>]\n"
                               "             [-nf <color>] [-p <prompt>] [-sb 
<color>] [-sf <color>] [-v]\n");
        if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
                fprintf(stderr, "warning: no locale support\n");

Reply via email to