Excerpts from Henri Mannerberg's message of 2010-09-01 12:10:06 +0200: > > 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 > > 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");
Thanks for this, Henri. The only issue I have is that the font colour does not change when highlighted when I call dmenu with the '-l' option. --