Instantly share code, notes, and snippets.
Last active
December 31, 2015 22:59
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save kaorimatz/8057265 to your computer and use it in GitHub Desktop.
Xft support for dmenu.
Works with the revision 5ed5e90.
Original: http://tools.suckless.org/dmenu/patches/dmenu-4.5-xft.diff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/config.mk b/config.mk | |
index c0d466b..22a5112 100644 | |
--- a/config.mk | |
+++ b/config.mk | |
@@ -12,9 +12,13 @@ X11LIB = /usr/X11R6/lib | |
XINERAMALIBS = -lXinerama | |
XINERAMAFLAGS = -DXINERAMA | |
+# Xft, comment if you don't want it | |
+XFTINC = -I/usr/local/include/freetype2 | |
+XFTLIBS = -lXft -lXrender -lfreetype -lz -lfontconfig | |
+ | |
# includes and libs | |
-INCS = -I${X11INC} | |
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} | |
+INCS = -I${X11INC} ${XFTINC} | |
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${XFTLIBS} | |
# flags | |
CPPFLAGS = -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} | |
diff --git a/dmenu.1 b/dmenu.1 | |
index bbee17d..d258e13 100644 | |
--- a/dmenu.1 | |
+++ b/dmenu.1 | |
@@ -58,7 +58,7 @@ dmenu is displayed on the monitor supplied. | |
defines the prompt to be displayed to the left of the input field. | |
.TP | |
.BI \-fn " font" | |
-defines the font or font set used. | |
+defines the font or font set used. eg. "fixed" or "Monospace-12:normal" (an xft font) | |
.TP | |
.BI \-nb " color" | |
defines the normal background color. | |
diff --git a/dmenu.c b/dmenu.c | |
index 8d9bbb6..76601a0 100644 | |
--- a/dmenu.c | |
+++ b/dmenu.c | |
@@ -17,6 +17,7 @@ | |
* MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) | |
#define MIN(a,b) ((a) < (b) ? (a) : (b)) | |
#define MAX(a,b) ((a) > (b) ? (a) : (b)) | |
+#define DEFFONT "fixed" /* xft example: "Monospace-11" */ | |
typedef struct Item Item; | |
struct Item { | |
@@ -27,6 +28,7 @@ struct Item { | |
static void appenditem(Item *item, Item **list, Item **last); | |
static void calcoffsets(void); | |
+static void cleanup(void); | |
static char *cistrstr(const char *s, const char *sub); | |
static void drawmenu(void); | |
static void grabkeyboard(void); | |
@@ -44,10 +46,12 @@ static char text[BUFSIZ] = ""; | |
static int bh, mw, mh; | |
static int inputw, promptw; | |
static size_t cursor = 0; | |
-static unsigned long normcol[ColLast]; | |
-static unsigned long selcol[ColLast]; | |
-static unsigned long outcol[ColLast]; | |
+static ColorSet *normcol; | |
+static ColorSet *selcol; | |
+static ColorSet *outcol; | |
static Atom clip, utf8; | |
+static Bool running = True; | |
+static int ret = 0; | |
static DC *dc; | |
static Item *items = NULL; | |
static Item *matches, *matchend; | |
@@ -103,7 +107,10 @@ main(int argc, char *argv[]) { | |
usage(); | |
dc = initdc(); | |
- initfont(dc, font); | |
+ initfont(dc, font ? font : DEFFONT); | |
+ normcol = initcolor(dc, normfgcolor, normbgcolor); | |
+ selcol = initcolor(dc, selfgcolor, selbgcolor); | |
+ outcol = initcolor(dc, outbgcolor, outfgcolor); | |
if(fast) { | |
grabkeyboard(); | |
@@ -116,7 +123,8 @@ main(int argc, char *argv[]) { | |
setup(); | |
run(); | |
- return 1; /* unreachable */ | |
+ cleanup(); | |
+ return ret; | |
} | |
void | |
@@ -159,6 +167,16 @@ cistrstr(const char *s, const char *sub) { | |
} | |
void | |
+cleanup(void) { | |
+ freecol(dc, normcol); | |
+ freecol(dc, selcol); | |
+ freecol(dc, outcol); | |
+ XDestroyWindow(dc->dpy, win); | |
+ XUngrabKeyboard(dc->dpy, CurrentTime); | |
+ freedc(dc); | |
+} | |
+ | |
+void | |
drawmenu(void) { | |
int curpos; | |
Item *item; | |
@@ -166,7 +184,7 @@ drawmenu(void) { | |
dc->x = 0; | |
dc->y = 0; | |
dc->h = bh; | |
- drawrect(dc, 0, 0, mw, mh, True, BG(dc, normcol)); | |
+ drawrect(dc, 0, 0, mw, mh, True, normcol->BG); | |
if(prompt && *prompt) { | |
dc->w = promptw; | |
@@ -177,7 +195,7 @@ drawmenu(void) { | |
dc->w = (lines > 0 || !matches) ? mw - dc->x : inputw; | |
drawtext(dc, text, normcol); | |
if((curpos = textnw(dc, text, cursor) + dc->h/2 - 2) < dc->w) | |
- drawrect(dc, curpos, 2, 1, dc->h - 4, True, FG(dc, normcol)); | |
+ drawrect(dc, curpos, 2, 1, dc->h - 4, True, normcol->FG); | |
if(lines > 0) { | |
/* draw vertical list */ | |
@@ -283,7 +301,9 @@ keypress(XKeyEvent *ev) { | |
case XK_KP_Enter: | |
break; | |
case XK_bracketleft: | |
- exit(EXIT_FAILURE); | |
+ ret = EXIT_SUCCESS; | |
+ running = False; | |
+ break; | |
default: | |
return; | |
} | |
@@ -330,7 +350,9 @@ keypress(XKeyEvent *ev) { | |
sel = matchend; | |
break; | |
case XK_Escape: | |
- exit(EXIT_FAILURE); | |
+ ret = EXIT_FAILURE; | |
+ running = False; | |
+ break; | |
case XK_Home: | |
if(sel == matches) { | |
cursor = 0; | |
@@ -368,8 +390,11 @@ keypress(XKeyEvent *ev) { | |
case XK_Return: | |
case XK_KP_Enter: | |
puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); | |
- if(!(ev->state & ControlMask)) | |
- exit(EXIT_SUCCESS); | |
+ if(!(ev->state & ControlMask)) { | |
+ ret = EXIT_SUCCESS; | |
+ running = False; | |
+ break; | |
+ } | |
sel->out = True; | |
break; | |
case XK_Right: | |
@@ -504,7 +529,7 @@ void | |
run(void) { | |
XEvent ev; | |
- while(!XNextEvent(dc->dpy, &ev)) { | |
+ while(running && !XNextEvent(dc->dpy, &ev)) { | |
if(XFilterEvent(&ev, win)) | |
continue; | |
switch(ev.type) { | |
@@ -538,13 +563,6 @@ setup(void) { | |
XineramaScreenInfo *info; | |
#endif | |
- normcol[ColBG] = getcolor(dc, normbgcolor); | |
- normcol[ColFG] = getcolor(dc, normfgcolor); | |
- selcol[ColBG] = getcolor(dc, selbgcolor); | |
- selcol[ColFG] = getcolor(dc, selfgcolor); | |
- outcol[ColBG] = getcolor(dc, outbgcolor); | |
- outcol[ColFG] = getcolor(dc, outfgcolor); | |
- | |
clip = XInternAtom(dc->dpy, "CLIPBOARD", False); | |
utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False); | |
@@ -600,7 +618,7 @@ setup(void) { | |
/* create menu window */ | |
swa.override_redirect = True; | |
- swa.background_pixel = normcol[ColBG]; | |
+ swa.background_pixel = normcol->BG; | |
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; | |
win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0, | |
DefaultDepth(dc->dpy, screen), CopyFromParent, | |
diff --git a/dmenu_path b/dmenu_path | |
old mode 100644 | |
new mode 100755 | |
diff --git a/draw.c b/draw.c | |
index 76f0c54..a36d19a 100644 | |
--- a/draw.c | |
+++ b/draw.c | |
@@ -9,9 +9,6 @@ | |
#define MAX(a, b) ((a) > (b) ? (a) : (b)) | |
#define MIN(a, b) ((a) < (b) ? (a) : (b)) | |
-#define DEFAULTFN "fixed" | |
- | |
-static Bool loadfont(DC *dc, const char *fontstr); | |
void | |
drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, unsigned long color) { | |
@@ -23,7 +20,7 @@ drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, unsign | |
} | |
void | |
-drawtext(DC *dc, const char *text, unsigned long col[ColLast]) { | |
+drawtext(DC *dc, const char *text, ColorSet *col) { | |
char buf[BUFSIZ]; | |
size_t mn, n = strlen(text); | |
@@ -35,19 +32,24 @@ drawtext(DC *dc, const char *text, unsigned long col[ColLast]) { | |
if(mn < n) | |
for(n = MAX(mn-3, 0); n < mn; buf[n++] = '.'); | |
- drawrect(dc, 0, 0, dc->w, dc->h, True, BG(dc, col)); | |
+ drawrect(dc, 0, 0, dc->w, dc->h, True, col->BG); | |
drawtextn(dc, buf, mn, col); | |
} | |
void | |
-drawtextn(DC *dc, const char *text, size_t n, unsigned long col[ColLast]) { | |
+drawtextn(DC *dc, const char *text, size_t n, ColorSet *col) { | |
int x = dc->x + dc->font.height/2; | |
int y = dc->y + dc->font.ascent+1; | |
- XSetForeground(dc->dpy, dc->gc, FG(dc, col)); | |
- if(dc->font.set) | |
+ XSetForeground(dc->dpy, dc->gc, col->FG); | |
+ if(dc->font.xft_font) { | |
+ if (!dc->xftdraw) | |
+ eprintf("error, xft drawable does not exist"); | |
+ XftDrawStringUtf8(dc->xftdraw, &col->FG_xft, | |
+ dc->font.xft_font, x, y, (unsigned char*)text, n); | |
+ } else if(dc->font.set) { | |
XmbDrawString(dc->dpy, dc->canvas, dc->font.set, dc->gc, x, y, text, n); | |
- else { | |
+ } else { | |
XSetFont(dc->dpy, dc->gc, dc->font.xfont->fid); | |
XDrawString(dc->dpy, dc->canvas, dc->gc, x, y, text, n); | |
} | |
@@ -69,16 +71,33 @@ eprintf(const char *fmt, ...) { | |
} | |
void | |
+freecol(DC *dc, ColorSet *col) { | |
+ if(col) { | |
+ if(&col->FG_xft) | |
+ XftColorFree(dc->dpy, DefaultVisual(dc->dpy, DefaultScreen(dc->dpy)), | |
+ DefaultColormap(dc->dpy, DefaultScreen(dc->dpy)), &col->FG_xft); | |
+ free(col); | |
+ } | |
+} | |
+ | |
+void | |
freedc(DC *dc) { | |
+ if(dc->font.xft_font) { | |
+ XftFontClose(dc->dpy, dc->font.xft_font); | |
+ XftDrawDestroy(dc->xftdraw); | |
+ } | |
if(dc->font.set) | |
XFreeFontSet(dc->dpy, dc->font.set); | |
- if(dc->font.xfont) | |
+ if(dc->font.xfont) | |
XFreeFont(dc->dpy, dc->font.xfont); | |
- if(dc->canvas) | |
+ if(dc->canvas) | |
XFreePixmap(dc->dpy, dc->canvas); | |
- XFreeGC(dc->dpy, dc->gc); | |
- XCloseDisplay(dc->dpy); | |
- free(dc); | |
+ if(dc->gc) | |
+ XFreeGC(dc->dpy, dc->gc); | |
+ if(dc->dpy) | |
+ XCloseDisplay(dc->dpy); | |
+ if(dc) | |
+ free(dc); | |
} | |
unsigned long | |
@@ -91,6 +110,20 @@ getcolor(DC *dc, const char *colstr) { | |
return color.pixel; | |
} | |
+ColorSet * | |
+initcolor(DC *dc, const char * foreground, const char * background) { | |
+ ColorSet * col = (ColorSet *)malloc(sizeof(ColorSet)); | |
+ if(!col) | |
+ eprintf("error, cannot allocate memory for color set"); | |
+ col->BG = getcolor(dc, background); | |
+ col->FG = getcolor(dc, foreground); | |
+ if(dc->font.xft_font) | |
+ if(!XftColorAllocName(dc->dpy, DefaultVisual(dc->dpy, DefaultScreen(dc->dpy)), | |
+ DefaultColormap(dc->dpy, DefaultScreen(dc->dpy)), foreground, &col->FG_xft)) | |
+ eprintf("error, cannot allocate xft font color '%s'\n", foreground); | |
+ return col; | |
+} | |
+ | |
DC * | |
initdc(void) { | |
DC *dc; | |
@@ -109,39 +142,33 @@ initdc(void) { | |
void | |
initfont(DC *dc, const char *fontstr) { | |
- if(!loadfont(dc, fontstr ? fontstr : DEFAULTFN)) { | |
- if(fontstr != NULL) | |
- fprintf(stderr, "cannot load font '%s'\n", fontstr); | |
- if(fontstr == NULL || !loadfont(dc, DEFAULTFN)) | |
- eprintf("cannot load font '%s'\n", DEFAULTFN); | |
- } | |
- dc->font.height = dc->font.ascent + dc->font.descent; | |
-} | |
- | |
-Bool | |
-loadfont(DC *dc, const char *fontstr) { | |
char *def, **missing, **names; | |
int i, n; | |
XFontStruct **xfonts; | |
- if(!*fontstr) | |
- return False; | |
- if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def))) { | |
+ missing = NULL; | |
+ if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) { | |
+ dc->font.ascent = dc->font.xfont->ascent; | |
+ dc->font.descent = dc->font.xfont->descent; | |
+ dc->font.width = dc->font.xfont->max_bounds.width; | |
+ } else if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def))) { | |
n = XFontsOfFontSet(dc->font.set, &xfonts, &names); | |
for(i = 0; i < n; i++) { | |
dc->font.ascent = MAX(dc->font.ascent, xfonts[i]->ascent); | |
dc->font.descent = MAX(dc->font.descent, xfonts[i]->descent); | |
dc->font.width = MAX(dc->font.width, xfonts[i]->max_bounds.width); | |
} | |
- } | |
- else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) { | |
- dc->font.ascent = dc->font.xfont->ascent; | |
- dc->font.descent = dc->font.xfont->descent; | |
- dc->font.width = dc->font.xfont->max_bounds.width; | |
+ } else if((dc->font.xft_font = XftFontOpenName(dc->dpy, DefaultScreen(dc->dpy), fontstr))) { | |
+ dc->font.ascent = dc->font.xft_font->ascent; | |
+ dc->font.descent = dc->font.xft_font->descent; | |
+ dc->font.width = dc->font.xft_font->max_advance_width; | |
+ } else { | |
+ eprintf("cannot load font '%s'\n", fontstr); | |
} | |
if(missing) | |
XFreeStringList(missing); | |
- return dc->font.set || dc->font.xfont; | |
+ dc->font.height = dc->font.ascent + dc->font.descent; | |
+ return; | |
} | |
void | |
@@ -151,20 +178,29 @@ mapdc(DC *dc, Window win, unsigned int w, unsigned int h) { | |
void | |
resizedc(DC *dc, unsigned int w, unsigned int h) { | |
+ int screen = DefaultScreen(dc->dpy); | |
if(dc->canvas) | |
XFreePixmap(dc->dpy, dc->canvas); | |
dc->w = w; | |
dc->h = h; | |
dc->canvas = XCreatePixmap(dc->dpy, DefaultRootWindow(dc->dpy), w, h, | |
- DefaultDepth(dc->dpy, DefaultScreen(dc->dpy))); | |
+ DefaultDepth(dc->dpy, screen)); | |
+ if(dc->font.xft_font && !(dc->xftdraw)) { | |
+ dc->xftdraw = XftDrawCreate(dc->dpy, dc->canvas, DefaultVisual(dc->dpy,screen), DefaultColormap(dc->dpy,screen)); | |
+ if(!(dc->xftdraw)) | |
+ eprintf("error, cannot create xft drawable\n"); | |
+ } | |
} | |
int | |
textnw(DC *dc, const char *text, size_t len) { | |
- if(dc->font.set) { | |
+ if(dc->font.xft_font) { | |
+ XGlyphInfo gi; | |
+ XftTextExtentsUtf8(dc->dpy, dc->font.xft_font, (const FcChar8*)text, len, &gi); | |
+ return gi.width; | |
+ } else if(dc->font.set) { | |
XRectangle r; | |
- | |
XmbTextExtents(dc->font.set, text, len, NULL, &r); | |
return r.width; | |
} | |
diff --git a/draw.h b/draw.h | |
index 43a57bf..1b4f21a 100644 | |
--- a/draw.h | |
+++ b/draw.h | |
@@ -1,9 +1,6 @@ | |
/* See LICENSE file for copyright and license details. */ | |
-#define FG(dc, col) ((col)[(dc)->invert ? ColBG : ColFG]) | |
-#define BG(dc, col) ((col)[(dc)->invert ? ColFG : ColBG]) | |
- | |
-enum { ColBG, ColFG, ColBorder, ColLast }; | |
+#include <X11/Xft/Xft.h> | |
typedef struct { | |
int x, y, w, h; | |
@@ -11,6 +8,7 @@ typedef struct { | |
Display *dpy; | |
GC gc; | |
Pixmap canvas; | |
+ XftDraw *xftdraw; | |
struct { | |
int ascent; | |
int descent; | |
@@ -18,15 +16,24 @@ typedef struct { | |
int width; | |
XFontSet set; | |
XFontStruct *xfont; | |
+ XftFont *xft_font; | |
} font; | |
} DC; /* draw context */ | |
+typedef struct { | |
+ unsigned long FG; | |
+ XftColor FG_xft; | |
+ unsigned long BG; | |
+} ColorSet; | |
+ | |
void drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, unsigned long color); | |
-void drawtext(DC *dc, const char *text, unsigned long col[ColLast]); | |
-void drawtextn(DC *dc, const char *text, size_t n, unsigned long col[ColLast]); | |
+void drawtext(DC *dc, const char *text, ColorSet *col); | |
+void drawtextn(DC *dc, const char *text, size_t n, ColorSet *col); | |
+void freecol(DC *dc, ColorSet *col); | |
void eprintf(const char *fmt, ...); | |
void freedc(DC *dc); | |
unsigned long getcolor(DC *dc, const char *colstr); | |
+ColorSet *initcolor(DC *dc, const char *foreground, const char *background); | |
DC *initdc(void); | |
void initfont(DC *dc, const char *fontstr); | |
void mapdc(DC *dc, Window win, unsigned int w, unsigned int h); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment