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.
-- 

Reply via email to