Added xft support (smooth fonts)

This commit is contained in:
phillbush 2020-05-18 22:27:56 -03:00
parent 858338d978
commit dbeb994054
3 changed files with 57 additions and 40 deletions

View File

@ -1,4 +1,4 @@
static const char *font = "-*-*-medium-*-*-*-14-*-*-*-*-*-*-*"; static const char *font = "monospace:size=9";
static const char *background = "#FFFFFF"; static const char *background = "#FFFFFF";
static const char *foreground = "#2E3436"; static const char *foreground = "#2E3436";
static const char *selbackground = "#3584E4"; static const char *selbackground = "#3584E4";

View File

@ -8,9 +8,14 @@ MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib X11LIB = /usr/X11R6/lib
FREETYPEINC = /usr/include/freetype2
FREETYPELIB = -lfontconfig -lXft
# OpenBSD (uncomment)
#FREETYPEINC = $(X11INC)/freetype2
# includes and libs # includes and libs
INCS = -I${X11INC} INCS = -I${X11INC} -I${FREETYPEINC}
LIBS = -L${X11LIB} -lX11 LIBS = -L${X11LIB} -L${FREETYPELIB} -lX11
# flags # flags
CPPFLAGS = CPPFLAGS =

84
xmenu.c
View File

@ -7,6 +7,7 @@
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/Xresource.h> #include <X11/Xresource.h>
#include <X11/XKBlib.h> #include <X11/XKBlib.h>
#include <X11/Xft/Xft.h>
#define ITEMPREV 0 #define ITEMPREV 0
#define ITEMNEXT 1 #define ITEMNEXT 1
@ -21,14 +22,13 @@ enum {ColorFG, ColorBG, ColorLast};
/* draw context structure */ /* draw context structure */
struct DC { struct DC {
unsigned long normal[ColorLast]; XftColor normal[ColorLast];
unsigned long selected[ColorLast]; XftColor selected[ColorLast];
unsigned long decoration[ColorLast]; XftColor decoration[ColorLast];
Drawable d; Drawable d;
GC gc; GC gc;
XFontStruct *font; XftFont *font;
int fonth;
}; };
/* menu geometry structure */ /* menu geometry structure */
@ -67,11 +67,12 @@ struct Menu {
int x, y, w, h; /* menu geometry */ int x, y, w, h; /* menu geometry */
unsigned level; /* menu level relative to root */ unsigned level; /* menu level relative to root */
Drawable pixmap; /* pixmap to draw the menu on */ Drawable pixmap; /* pixmap to draw the menu on */
XftDraw *draw;
Window win; /* menu window to map on the screen */ Window win; /* menu window to map on the screen */
}; };
/* function declarations */ /* function declarations */
static unsigned long getcolor(const char *s); static void getcolor(const char *s, XftColor *color);
static void getresources(void); static void getresources(void);
static void setupdc(void); static void setupdc(void);
static void setupgeom(void); static void setupgeom(void);
@ -92,6 +93,7 @@ static void usage(void);
/* X variables */ /* X variables */
static Colormap colormap; static Colormap colormap;
static Display *dpy; static Display *dpy;
static Visual *visual;
static Window rootwin; static Window rootwin;
static int screen; static int screen;
static struct DC dc; static struct DC dc;
@ -131,6 +133,7 @@ main(int argc, char *argv[])
if ((dpy = XOpenDisplay(NULL)) == NULL) if ((dpy = XOpenDisplay(NULL)) == NULL)
errx(1, "cannot open display"); errx(1, "cannot open display");
screen = DefaultScreen(dpy); screen = DefaultScreen(dpy);
visual = DefaultVisual(dpy, screen);
rootwin = RootWindow(dpy, screen); rootwin = RootWindow(dpy, screen);
colormap = DefaultColormap(dpy, screen); colormap = DefaultColormap(dpy, screen);
@ -138,6 +141,7 @@ main(int argc, char *argv[])
getresources(); getresources();
setupdc(); setupdc();
setupgeom(); setupgeom();
if (override_redirect)
setupgrab(); setupgrab();
/* generate menus and recalculate them */ /* generate menus and recalculate them */
@ -206,14 +210,11 @@ getresources(void)
} }
/* get color from color string */ /* get color from color string */
static unsigned long static void
getcolor(const char *s) getcolor(const char *s, XftColor *color)
{ {
XColor color; if(!XftColorAllocName(dpy, visual, colormap, s, color))
if(!XAllocNamedColor(dpy, colormap, s, &color, &color))
errx(1, "cannot allocate color: %s", s); errx(1, "cannot allocate color: %s", s);
return color.pixel;
} }
/* init draw context */ /* init draw context */
@ -221,21 +222,19 @@ static void
setupdc(void) setupdc(void)
{ {
/* get color pixels */ /* get color pixels */
dc.normal[ColorBG] = getcolor(background); getcolor(background, &dc.normal[ColorBG]);
dc.normal[ColorFG] = getcolor(foreground); getcolor(foreground, &dc.normal[ColorFG]);
dc.selected[ColorBG] = getcolor(selbackground); getcolor(selbackground, &dc.selected[ColorBG]);
dc.selected[ColorFG] = getcolor(selforeground); getcolor(selforeground, &dc.selected[ColorFG]);
dc.decoration[ColorBG] = getcolor(separator); getcolor(separator, &dc.decoration[ColorBG]);
dc.decoration[ColorFG] = getcolor(border); getcolor(border, &dc.decoration[ColorFG]);
/* try to get font */ /* try to get font */
if ((dc.font = XLoadQueryFont(dpy, font)) == NULL) if ((dc.font = XftFontOpenName(dpy, screen, font)) == NULL)
errx(1, "cannot load font"); errx(1, "cannot load font");
dc.fonth = dc.font->ascent + dc.font->descent;
/* create GC and set its font */ /* create GC */
dc.gc = XCreateGC(dpy, rootwin, 0, NULL); dc.gc = XCreateGC(dpy, rootwin, 0, NULL);
XSetFont(dpy, dc.gc, dc.font->fid);
} }
/* init menu geometry values */ /* init menu geometry values */
@ -243,7 +242,7 @@ static void
setupgeom(void) setupgeom(void)
{ {
geom.itemb = itemborder; geom.itemb = itemborder;
geom.itemh = dc.fonth + itemborder * 2; geom.itemh = dc.font->height + itemborder * 2;
geom.itemw = width; geom.itemw = width;
geom.border = menuborder; geom.border = menuborder;
geom.separator = separatorsize; geom.separator = separatorsize;
@ -311,8 +310,8 @@ allocmenu(struct Menu *parent, struct Item *list, unsigned level)
menu->level = level; menu->level = level;
swa.override_redirect = override_redirect; swa.override_redirect = override_redirect;
swa.background_pixel = dc.decoration[ColorBG]; swa.background_pixel = dc.decoration[ColorBG].pixel;
swa.border_pixel = dc.decoration[ColorFG]; swa.border_pixel = dc.decoration[ColorFG].pixel;
swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask
| PointerMotionMask | LeaveWindowMask; | PointerMotionMask | LeaveWindowMask;
menu->win = XCreateWindow(dpy, rootwin, 0, 0, geom.itemw, geom.itemh, geom.border, menu->win = XCreateWindow(dpy, rootwin, 0, 0, geom.itemw, geom.itemh, geom.border,
@ -435,6 +434,7 @@ calcmenu(struct Menu *menu)
{ {
XWindowChanges changes; XWindowChanges changes;
XSizeHints sizeh; XSizeHints sizeh;
XGlyphInfo ext;
struct Item *item; struct Item *item;
int labelwidth; int labelwidth;
@ -447,7 +447,9 @@ calcmenu(struct Menu *menu)
else else
menu->h += geom.itemh; menu->h += geom.itemh;
labelwidth = XTextWidth(dc.font, item->label, item->labellen) + dc.fonth * 2; XftTextExtentsUtf8(dpy, dc.font, (XftChar8 *)item->label,
item->labellen, &ext);
labelwidth = ext.xOff + dc.font->height * 2;
menu->w = MAX(menu->w, labelwidth); menu->w = MAX(menu->w, labelwidth);
} }
@ -494,9 +496,10 @@ calcmenu(struct Menu *menu)
sizeh.min_height = sizeh.max_height = menu->h; sizeh.min_height = sizeh.max_height = menu->h;
XSetWMNormalHints(dpy, menu->win, &sizeh); XSetWMNormalHints(dpy, menu->win, &sizeh);
/* create pixmap */ /* create pixmap and XftDraw */
menu->pixmap = XCreatePixmap(dpy, menu->win, menu->w, menu->h, menu->pixmap = XCreatePixmap(dpy, menu->win, menu->w, menu->h,
DefaultDepth(dpy, screen)); DefaultDepth(dpy, screen));
menu->draw = XftDrawCreate(dpy, menu->pixmap, visual, colormap);
/* calculate positions of submenus */ /* calculate positions of submenus */
for (item = menu->list; item != NULL; item = item->next) { for (item = menu->list; item != NULL; item = item->next) {
@ -590,7 +593,7 @@ drawmenu(void)
for (menu = currmenu; menu != NULL; menu = menu->parent) { for (menu = currmenu; menu != NULL; menu = menu->parent) {
for (item = menu->list; item != NULL; item = item->next) { for (item = menu->list; item != NULL; item = item->next) {
unsigned long *color; XftColor *color;
int labelx, labely; int labelx, labely;
/* determine item color */ /* determine item color */
@ -604,22 +607,23 @@ drawmenu(void)
continue; continue;
/* draw item box */ /* draw item box */
XSetForeground(dpy, dc.gc, color[ColorBG]); XSetForeground(dpy, dc.gc, color[ColorBG].pixel);
XDrawRectangle(dpy, menu->pixmap, dc.gc, 0, item->y, XDrawRectangle(dpy, menu->pixmap, dc.gc, 0, item->y,
menu->w, item->h); menu->w, item->h);
XFillRectangle(dpy, menu->pixmap, dc.gc, 0, item->y, XFillRectangle(dpy, menu->pixmap, dc.gc, 0, item->y,
menu->w, item->h); menu->w, item->h);
/* draw item label */ /* draw item label */
labelx = 0 + dc.fonth; labelx = 0 + dc.font->height;
labely = item->y + dc.fonth + geom.itemb; labely = item->y + dc.font->height + geom.itemb / 2;
XSetForeground(dpy, dc.gc, color[ColorFG]); XSetForeground(dpy, dc.gc, color[ColorFG].pixel);
XDrawString(dpy, menu->pixmap, dc.gc, labelx, labely, XftDrawStringUtf8(menu->draw, &color[ColorFG], dc.font,
item->label, item->labellen); labelx, labely, item->label,
item->labellen);
/* draw triangle, if item contains a submenu */ /* draw triangle, if item contains a submenu */
if (item->submenu != NULL) { if (item->submenu != NULL) {
int trianglex = menu->w - dc.fonth + geom.itemb - 1; int trianglex = menu->w - dc.font->height + geom.itemb - 1;
int triangley = item->y + (3 * item->h)/8 -1; int triangley = item->y + (3 * item->h)/8 -1;
XPoint triangle[] = { XPoint triangle[] = {
@ -783,6 +787,7 @@ freewindow(struct Menu *menu)
freewindow(item->submenu); freewindow(item->submenu);
XFreePixmap(dpy, menu->pixmap); XFreePixmap(dpy, menu->pixmap);
XftDrawDestroy(menu->draw);
XDestroyWindow(dpy, menu->win); XDestroyWindow(dpy, menu->win);
} }
@ -791,7 +796,14 @@ static void
cleanup(void) cleanup(void)
{ {
freewindow(rootmenu); freewindow(rootmenu);
XFreeFont(dpy, dc.font);
XftColorFree(dpy, visual, colormap, &dc.normal[ColorBG]);
XftColorFree(dpy, visual, colormap, &dc.normal[ColorFG]);
XftColorFree(dpy, visual, colormap, &dc.selected[ColorBG]);
XftColorFree(dpy, visual, colormap, &dc.selected[ColorFG]);
XftColorFree(dpy, visual, colormap, &dc.decoration[ColorBG]);
XftColorFree(dpy, visual, colormap, &dc.decoration[ColorFG]);
XFreeGC(dpy, dc.gc); XFreeGC(dpy, dc.gc);
XCloseDisplay(dpy); XCloseDisplay(dpy);
} }