Added xft support (smooth fonts)
This commit is contained in:
parent
858338d978
commit
dbeb994054
2
config.h
2
config.h
|
@ -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";
|
||||||
|
|
|
@ -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
84
xmenu.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user