After spending about an hour today trying to figure out why my old dmenu
config wasn't working properly (it was ignoring the value of -sf) I finally
tracked the problem back to the dmenu XFT patch. A little googling turned up
that this was either a "known bug", or a "feature" depending on how one
chooses to interpret the comment in the mailing list. After some discussion
in the #suckless IRC channel in which it was implied that -sf was removed
because "that's the way xft works" and that it was impossible to have
foreground highlighting while using XFT I decided to take a stab at fixing
the patch to not break -sf. Attached you will find a minor alteration to the
existing xft patch that does in fact re-enable -sf support (although not
very nicely, someone feel free to write a better version). I'm sure there'a
better way to have implemented this, but it works and I haven't noticed any
real differences between my version and the previous patch besides the fact
that it now once again honors the setting of -sf.
-R. Kyle Murphy
--
Curiosity was framed, Ignorance killed the cat.
Only in dmenu-4.0: .dmenu.c.swp
diff -up dmenu-4.0/config.h dmenu-4.0-xft/config.h
--- dmenu-4.0/config.h 2009-04-18 07:50:04.000000000 -0400
+++ dmenu-4.0-xft/config.h 2009-11-08 05:07:40.028951847 -0500
@@ -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.0/config.mk dmenu-4.0-xft/config.mk
--- dmenu-4.0/config.mk 2009-04-18 07:50:04.000000000 -0400
+++ dmenu-4.0-xft/config.mk 2009-11-08 05:07:40.028951847 -0500
@@ -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.0/dmenu.1 dmenu-4.0-xft/dmenu.1
--- dmenu-4.0/dmenu.1 2009-04-18 07:50:04.000000000 -0400
+++ dmenu-4.0-xft/dmenu.1 2009-11-08 05:07:40.028951847 -0500
@@ -6,6 +6,7 @@ dmenu \- dynamic menu
.RB [ \-i ]
.RB [ \-b ]
.RB [ \-fn " <font>"]
+.RB [ \-fa " <xftfont>"]
.RB [ \-nb " <color>"]
.RB [ \-nf " <color>"]
.RB [ \-p " <prompt>"]
@@ -29,6 +30,9 @@ defines that dmenu appears at the bottom
.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.0/dmenu.c dmenu-4.0-xft/dmenu.c
--- dmenu-4.0/dmenu.c 2009-04-18 07:50:04.000000000 -0400
+++ dmenu-4.0-xft/dmenu.c 2009-11-08 05:50:32.962034661 -0500
@@ -13,6 +13,7 @@
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif
+#include <X11/Xft/Xft.h>
/* macros */
#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
@@ -27,6 +28,7 @@ typedef struct {
int x, y, w, h;
unsigned long norm[ColLast];
unsigned long sel[ColLast];
+ Bool selected;
Drawable drawable;
GC gc;
struct {
@@ -36,6 +38,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;
@@ -160,9 +172,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);
@@ -182,7 +199,9 @@ drawmenu(void) {
/* print prompt? */
if(promptw) {
dc.w = promptw;
+ dc.selected = True;
drawtext(prompt, dc.sel);
+ dc.selected = False;
}
dc.x += promptw;
dc.w = mw - promptw;
@@ -200,7 +219,13 @@ drawmenu(void) {
dc.w = textw(i->text);
if(dc.w > mw / 3)
dc.w = 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.x = mw - spaceitem;
@@ -224,7 +249,11 @@ drawtext(const char *text, unsigned long
olen = strlen(text);
h = dc.font.ascent + dc.font.descent;
y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
- x = dc.x + (h / 2);
+ if(dc.xftfont.xft_font) {
+ h = dc.xftfont.ascent + dc.xftfont.descent;
+ y = dc.y + (dc.h / 2) - (h / 2) + dc.xftfont.ascent;
+ }
+ x = dc.x + (h / 2);
/* shorten text if necessary */
for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--);
if(!len)
@@ -233,7 +262,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) {
+ XftDrawString8(dc.xftdraw, &dc.xftselcolor, dc.xftfont.xft_font, x, y, (unsigned char*)buf, len);
+ } else {
+ XftDrawString8(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);
@@ -253,7 +290,6 @@ unsigned long
getcolor(const char *colstr) {
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
-
if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
eprint("error, cannot allocate color '%s'\n", colstr);
return color.pixel;
@@ -309,6 +345,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[32];
int i, num;
@@ -589,7 +634,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;
@@ -597,6 +650,9 @@ setup(Bool topbar) {
wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask;
/* menu window geometry */
+ if(fontxft)
+ mh = dc.xftfont.height + 2;
+ else
mh = dc.font.height + 2;
#if XINERAMA
if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) {
@@ -632,7 +688,7 @@ setup(Bool topbar) {
dc.drawable = XCreatePixmap(dpy, root, mw, mh, DefaultDepth(dpy, screen));
dc.gc = XCreateGC(dpy, root, 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 = textw(maxname);
@@ -645,13 +701,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) {
+ XftTextExtents8(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;
}
@@ -660,6 +723,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;
}
@@ -679,6 +744,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];
}
@@ -697,7 +765,7 @@ main(int argc, char *argv[]) {
else if(!strcmp(argv[i], "-v"))
eprint("dmenu-"VERSION", © 2006-2008 dmenu engineers, see LICENSE for details\n");
else
- eprint("usage: dmenu [-i] [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n"
+ eprint("usage: dmenu [-i] [-b] [-fn <font>] [-fa <xftfont>] [-nb <color>] [-nf <color>]\n"
" [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n");
if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
fprintf(stderr, "warning: no locale support\n");