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");