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-02 17:31:01.176669712 +0300 @@ -7,3 +7,5 @@ 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"; +#define USE_XFT 1 /* 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-02 16:37:56.253340190 +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 -lXrender -lfreetype -lz -lfontconfig -lXrender # 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-02 16:37:56.283340181 +0300 @@ -7,6 +7,7 @@ dmenu \- dynamic menu .RB [ \-b ] .RB [ \-l " "] .RB [ \-fn " "] +.RB [ \-fa " "] .RB [ \-nb " "] .RB [ \-nf " "] .RB [ \-p " "] @@ -34,6 +35,9 @@ The given number of lines will be displa .B \-fn defines the font. .TP +.B \-fa +defines the xft font. +.TP .B \-nb 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-02 17:28:10.510006842 +0300 @@ -13,6 +13,7 @@ #ifdef XINERAMA #include #endif +#include /* 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(USE_XFT) + 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(USE_XFT) { + 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(!USE_XFT) 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; + + if(USE_XFT) + h2 = dc.xftfont.height; + else + h2 = dc.font.height; - r.x += textnw(text, cursor) + dc.font.height / 2; + 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); @@ -215,7 +244,9 @@ drawmenu(void) { /* print prompt? */ if(prompt) { dc.w = promptw; - drawtext(prompt, dc.sel); + 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,24 @@ drawmenuh(void) { void drawmenuv(void) { Item *i; + int h2; + + if(USE_XFT) + 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; + if(sel == i) { + dc.selected = True; + drawtext(i->text, dc.sel); + dc.selected = False; + } else { + drawtext(i->text, dc.norm); + } + dc.y += h2 + 2; } drawtext(NULL, dc.norm); } @@ -268,7 +317,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 +325,14 @@ 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(!USE_XFT) { + 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; 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(USE_XFT) { + 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(USE_XFT){ + 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(USE_XFT) + 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 && !USE_XFT) 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(USE_XFT) { + 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(USE_XFT) { + 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(USE_XFT) + 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 ] [-l ] [-fn ] [-nb ]\n" + eprint("usage: dmenu [-i] [-b] [-e ] [-l ] [-fn ] [-fa ] [-nb ]\n" " [-nf ] [-p ] [-sb ] [-sf ] [-v]\n"); if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fprintf(stderr, "warning: no locale support\n");