From 6900cd36121062f81f29ec3651aa1ee8807edbe1 Mon Sep 17 00:00:00 2001 From: okan Date: Mon, 17 Dec 2012 02:28:45 +0000 Subject: non-trivial menu drawing rewrite, moving to Xft and solving various font/color drawing issues; from Alexander Polakov --- calmwm.c | 5 ---- calmwm.h | 20 ++++++++++------ conf.c | 17 ++++++++++---- cwmrc.5 | 5 +++- font.c | 34 +++++++++++++++++++++------ menu.c | 77 ++++++++++++++++++++++++++++++++++++++----------------------- mousefunc.c | 4 ++-- parse.y | 23 ++++++++++++------ xutil.c | 9 ++++++++ 9 files changed, 131 insertions(+), 63 deletions(-) diff --git a/calmwm.c b/calmwm.c index 97a25b1..c699751 100644 --- a/calmwm.c +++ b/calmwm.c @@ -147,11 +147,6 @@ x_setup(void) static void x_teardown(void) { - struct screen_ctx *sc; - - TAILQ_FOREACH(sc, &Screenq, entry) - XFreeGC(X_Dpy, sc->gc); - XCloseDisplay(X_Dpy); } diff --git a/calmwm.h b/calmwm.h index 38c3fee..bd0dbd7 100644 --- a/calmwm.h +++ b/calmwm.h @@ -84,14 +84,19 @@ union arg { int i; }; +enum menucolor { + CWM_COLOR_MENU_FG, + CWM_COLOR_MENU_BG, + CWM_COLOR_MENU_FONT, + CWM_COLOR_MENU_FONT_SEL, + CWM_COLOR_MENU_MAX +}; + enum cwmcolor { CWM_COLOR_BORDER_ACTIVE, CWM_COLOR_BORDER_INACTIVE, CWM_COLOR_BORDER_GROUP, CWM_COLOR_BORDER_UNGROUP, - CWM_COLOR_FG_MENU, - CWM_COLOR_BG_MENU, - CWM_COLOR_FONT, CWM_COLOR_MAX }; @@ -208,13 +213,12 @@ struct screen_ctx { Window rootwin; Window menuwin; struct color color[CWM_COLOR_MAX]; - GC gc; int cycling; struct geom view; /* viewable area */ struct geom work; /* workable area, gap-applied */ struct gap gap; struct cycle_entry_q mruq; - XftColor xftcolor; + XftColor xftcolor[CWM_COLOR_MENU_MAX]; XftDraw *xftdraw; XftFont *font; int xinerama_no; @@ -289,6 +293,7 @@ struct conf { int snapdist; struct gap gap; struct color color[CWM_COLOR_MAX]; + char *menucolor[CWM_COLOR_MENU_MAX]; char termpath[MAXPATHLEN]; char lockpath[MAXPATHLEN]; #define CONF_FONT "sans-serif:pixelsize=14:bold" @@ -445,10 +450,10 @@ void conf_ungrab(struct conf *, struct keybinding *); int font_ascent(struct screen_ctx *); int font_descent(struct screen_ctx *); void font_draw(struct screen_ctx *, const char *, int, - Drawable, int, int); + Drawable, int, int, int); u_int font_height(struct screen_ctx *); void font_init(struct screen_ctx *, const char *, - const char *); + const char **); int font_width(struct screen_ctx *, const char *, int); void xev_loop(void); @@ -486,6 +491,7 @@ void xu_ewmh_net_desktop_names(struct screen_ctx *, char *, int); void xu_ewmh_net_wm_desktop(struct client_ctx *); +void xu_xorcolor(XRenderColor, XRenderColor, XRenderColor *); void u_exec(char *); void u_spawn(char *); diff --git a/conf.c b/conf.c index 2fe7363..a42be91 100644 --- a/conf.c +++ b/conf.c @@ -62,17 +62,21 @@ conf_gap(struct conf *c, struct screen_ctx *sc) void conf_font(struct conf *c, struct screen_ctx *sc) { - font_init(sc, c->font, c->color[CWM_COLOR_FONT].name); + font_init(sc, c->font, (const char**)c->menucolor); } -static struct color color_binds[] = { +static char *menu_color_binds[CWM_COLOR_MENU_MAX] = { + "black", /* CWM_COLOR_MENU_FG */ + "white", /* CWM_COLOR_MENU_BG */ + "black", /* CWM_COLOR_MENU_FONT */ + "", /* CWM_COLOR_MENU_FONT_SEL */ +}; + +static struct color color_binds[CWM_COLOR_MAX] = { { "#CCCCCC", 0 }, /* CWM_COLOR_BORDER_ACTIVE */ { "#666666", 0 }, /* CWM_COLOR_BORDER_INACTIVE */ { "blue", 0 }, /* CWM_COLOR_BORDER_GROUP */ { "red", 0 }, /* CWM_COLOR_BORDER_UNGROUP */ - { "black", 0 }, /* CWM_COLOR_FG_MENU */ - { "white", 0 }, /* CWM_COLOR_BG_MENU */ - { "black", 0 }, /* CWM_COLOR_FONT */ }; void @@ -182,6 +186,9 @@ conf_init(struct conf *c) for (i = 0; i < nitems(color_binds); i++) c->color[i].name = xstrdup(color_binds[i].name); + for (i = 0; i < nitems(menu_color_binds); i++) + c->menucolor[i] = xstrdup(menu_color_binds[i]); + /* Default term/lock */ (void)strlcpy(c->termpath, "xterm", sizeof(c->termpath)); (void)strlcpy(c->lockpath, "xlock", sizeof(c->lockpath)); diff --git a/cwmrc.5 b/cwmrc.5 index 4e17dbd..c8ea841 100644 --- a/cwmrc.5 +++ b/cwmrc.5 @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: November 7 2012 $ +.Dd $Mdocdate: November 29 2012 $ .Dt CWMRC 5 .Os .Sh NAME @@ -112,6 +112,9 @@ Set the color of the active border. .It Ic color font Ar color Set menu font color. .Pp +.It Ic color selfont Ar color +Set font color for selected menu item. +.Pp .It Ic color groupborder Ar color Set the color of the border while grouping a window. .Pp diff --git a/font.c b/font.c index 0e1c144..cbd5b56 100644 --- a/font.c +++ b/font.c @@ -49,20 +49,37 @@ font_height(struct screen_ctx *sc) } void -font_init(struct screen_ctx *sc, const char *name, const char *color) +font_init(struct screen_ctx *sc, const char *name, const char **color) { + int i; + XRenderColor c; + sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin, DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which)); if (sc->xftdraw == NULL) errx(1, "XftDrawCreate"); - if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which), - DefaultColormap(X_Dpy, sc->which), color, &sc->xftcolor)) - errx(1, "XftColorAllocName"); - sc->font = XftFontOpenName(X_Dpy, sc->which, name); if (sc->font == NULL) errx(1, "XftFontOpenName"); + for(i = 0; i < CWM_COLOR_MENU_MAX; i++) { + if (*color[i] == '\0') + break; + if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which), + DefaultColormap(X_Dpy, sc->which), color[i], + &sc->xftcolor[i])) + errx(1, "XftColorAllocName"); + } + if (i == CWM_COLOR_MENU_MAX) + return; + + xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_BG].color, + sc->xftcolor[CWM_COLOR_MENU_FG].color, &c); + xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_FONT].color, c, &c); + if (!XftColorAllocValue(X_Dpy, DefaultVisual(X_Dpy, sc->which), + DefaultColormap(X_Dpy, sc->which), &c, + &sc->xftcolor[CWM_COLOR_MENU_FONT_SEL])) + errx(1, "XftColorAllocValue"); } int @@ -78,9 +95,12 @@ font_width(struct screen_ctx *sc, const char *text, int len) void font_draw(struct screen_ctx *sc, const char *text, int len, - Drawable d, int x, int y) + Drawable d, int active, int x, int y) { + int color; + + color = active ? CWM_COLOR_MENU_FONT_SEL : CWM_COLOR_MENU_FONT; XftDrawChange(sc->xftdraw, d); - XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor, sc->font, x, y, + XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor[color], sc->font, x, y, (const FcChar8*)text, len); } diff --git a/menu.c b/menu.c index e2b6e0e..8a0ce26 100644 --- a/menu.c +++ b/menu.c @@ -65,11 +65,13 @@ struct menu_ctx { static struct menu *menu_handle_key(XEvent *, struct menu_ctx *, struct menu_q *, struct menu_q *); static void menu_handle_move(XEvent *, struct menu_ctx *, - struct screen_ctx *); + struct screen_ctx *, struct menu_q *); static struct menu *menu_handle_release(XEvent *, struct menu_ctx *, struct screen_ctx *, struct menu_q *); static void menu_draw(struct screen_ctx *, struct menu_ctx *, struct menu_q *, struct menu_q *); +static void menu_draw_entry(struct screen_ctx *, struct menu_ctx *, + struct menu_q *, int, int); static int menu_calc_entry(struct screen_ctx *, struct menu_ctx *, int, int); static int menu_keycode(XKeyEvent *, enum ctltype *, @@ -78,20 +80,10 @@ static int menu_keycode(XKeyEvent *, enum ctltype *, void menu_init(struct screen_ctx *sc) { - XGCValues gv; - sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1, Conf.bwidth, - sc->color[CWM_COLOR_FG_MENU].pixel, - sc->color[CWM_COLOR_BG_MENU].pixel); - - gv.foreground = - sc->color[CWM_COLOR_FG_MENU].pixel^sc->color[CWM_COLOR_BG_MENU].pixel; - gv.background = sc->color[CWM_COLOR_BG_MENU].pixel; - gv.function = GXxor; - - sc->gc = XCreateGC(X_Dpy, sc->menuwin, - GCForeground|GCBackground|GCFunction, &gv); + sc->xftcolor[CWM_COLOR_MENU_FG].pixel, + sc->xftcolor[CWM_COLOR_MENU_BG].pixel); } struct menu * @@ -174,7 +166,7 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, menu_draw(sc, &mc, menuq, &resultq); break; case MotionNotify: - menu_handle_move(&e, &mc, sc); + menu_handle_move(&e, &mc, sc, &resultq); break; case ButtonRelease: if ((mi = menu_handle_release(&e, &mc, sc, &resultq)) @@ -442,8 +434,8 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, mc->width, mc->height); if (mc->hasprompt) { - font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin, - 0, font_ascent(sc) + 1); + font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin, 0, + 0, font_ascent(sc)); n = 1; } else n = 0; @@ -458,34 +450,61 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, break; font_draw(sc, text, MIN(strlen(text), MENU_MAXENTRY), - sc->menuwin, 0, y); + sc->menuwin, 0, 0, y); n++; } + if (mc->hasprompt && n > 1 && (mc->searchstr[0] != '\0')) { + mc->entry = 1; + menu_draw_entry(sc, mc, resultq, mc->entry, 1); + } +} + +static void +menu_draw_entry(struct screen_ctx *sc, struct menu_ctx *mc, + struct menu_q *resultq, int entry, int active) +{ + struct menu *mi; + char *text; + int color, i = 0; - if (mc->hasprompt && n > 1 && (mc->searchstr[0] != '\0')) - XFillRectangle(X_Dpy, sc->menuwin, sc->gc, - 0, font_height(sc), mc->width, font_height(sc)); + if (mc->hasprompt) + i = 1; + + TAILQ_FOREACH(mi, resultq, resultentry) + if (entry == i++) + break; - if (mc->noresult) - XFillRectangle(X_Dpy, sc->menuwin, sc->gc, - 0, 0, mc->width, font_height(sc)); + if (mi == NULL) + return; + color = active ? CWM_COLOR_MENU_FG : CWM_COLOR_MENU_BG; + text = mi->print[0] != '\0' ? + mi->print : mi->text; + XftDrawRect(sc->xftdraw, &sc->xftcolor[color], 0, + font_height(sc) * entry, mc->width, + font_height(sc) + font_descent(sc)); + font_draw(sc, text, strlen(text), sc->menuwin, active, + 0, font_height(sc) * entry + font_ascent(sc) + 1); } static void -menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc) +menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc, + struct menu_q *resultq) { mc->prev = mc->entry; mc->entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y); + if (mc->prev == mc->entry) + return; + if (mc->prev != -1) - XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0, - font_height(sc) * mc->prev, mc->width, font_height(sc)); + menu_draw_entry(sc, mc, resultq, mc->prev, 0); if (mc->entry != -1) { (void)xu_ptr_regrab(MENUGRABMASK, Cursor_normal); - XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0, - font_height(sc) * mc->entry, mc->width, font_height(sc)); + menu_draw_entry(sc, mc, resultq, mc->entry, 1); } else (void)xu_ptr_regrab(MENUGRABMASK, Cursor_default); + if (mc->hasprompt) + menu_draw_entry(sc, mc, resultq, 1, 1); } static struct menu * @@ -519,7 +538,7 @@ menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y) entry = y / font_height(sc); /* in bounds? */ - if (x <= 0 || x > mc->width || y <= 0 || + if (x < 0 || x > mc->width || y < 0 || y > font_height(sc) * mc->num || entry < 0 || entry >= mc->num) entry = -1; diff --git a/mousefunc.c b/mousefunc.c index d61adca..a342b8e 100644 --- a/mousefunc.c +++ b/mousefunc.c @@ -68,9 +68,9 @@ mousefunc_sweep_draw(struct client_ctx *cc) XMoveResizeWindow(X_Dpy, sc->menuwin, 0, 0, width, font_height(sc) * 2); XMapWindow(X_Dpy, sc->menuwin); XClearWindow(X_Dpy, sc->menuwin); - font_draw(sc, cc->name, strlen(cc->name), sc->menuwin, + font_draw(sc, cc->name, strlen(cc->name), sc->menuwin, 0, 2, font_ascent(sc) + 1); - font_draw(sc, asize, strlen(asize), sc->menuwin, + font_draw(sc, asize, strlen(asize), sc->menuwin, 0, width / 2 - width_size / 2, font_height(sc) + font_ascent(sc) + 1); } diff --git a/parse.y b/parse.y index c89c038..b36ee26 100644 --- a/parse.y +++ b/parse.y @@ -73,7 +73,8 @@ typedef struct { %token COLOR SNAPDIST %token ACTIVEBORDER INACTIVEBORDER %token GROUPBORDER UNGROUPBORDER -%token MENUBG MENUFG FONTCOLOR +%token MENUBG MENUFG +%token FONTCOLOR FONTSELCOLOR %token ERROR %token STRING %token NUMBER @@ -186,16 +187,20 @@ colors : ACTIVEBORDER STRING { conf->color[CWM_COLOR_BORDER_UNGROUP].name = $2; } | MENUBG STRING { - free(conf->color[CWM_COLOR_BG_MENU].name); - conf->color[CWM_COLOR_BG_MENU].name = $2; + free(conf->menucolor[CWM_COLOR_MENU_BG]); + conf->menucolor[CWM_COLOR_MENU_BG] = $2; } | MENUFG STRING { - free(conf->color[CWM_COLOR_FG_MENU].name); - conf->color[CWM_COLOR_FG_MENU].name = $2; + free(conf->menucolor[CWM_COLOR_MENU_FG]); + conf->menucolor[CWM_COLOR_MENU_FG] = $2; } | FONTCOLOR STRING { - free(conf->color[CWM_COLOR_FONT].name); - conf->color[CWM_COLOR_FONT].name = $2; + free(conf->menucolor[CWM_COLOR_MENU_FONT]); + conf->menucolor[CWM_COLOR_MENU_FONT] = $2; + } + | FONTSELCOLOR STRING { + free(conf->menucolor[CWM_COLOR_MENU_FONT_SEL]); + conf->menucolor[CWM_COLOR_MENU_FONT_SEL] = $2; } ; %% @@ -247,6 +252,7 @@ lookup(char *s) { "mousebind", MOUSEBIND}, { "moveamount", MOVEAMOUNT}, { "no", NO}, + { "selfont", FONTSELCOLOR}, { "snapdist", SNAPDIST}, { "sticky", STICKY}, { "ungroupborder", UNGROUPBORDER}, @@ -575,6 +581,9 @@ parse_config(const char *filename, struct conf *xconf) for (i = 0; i < CWM_COLOR_MAX; i++) xconf->color[i].name = conf->color[i].name; + for (i = 0; i < CWM_COLOR_MENU_MAX; i++) + xconf->menucolor[i]= conf->menucolor[i]; + xconf->font = conf->font; } diff --git a/xutil.c b/xutil.c index 9c80dfe..6e80379 100644 --- a/xutil.c +++ b/xutil.c @@ -430,3 +430,12 @@ xu_getcolor(struct screen_ctx *sc, char *name) return (color.pixel); } + +void +xu_xorcolor(XRenderColor a, XRenderColor b, XRenderColor *r) +{ + r->red = a.red ^ b.red; + r->green = a.green ^ b.green; + r->blue = a.blue ^ b.blue; + r->alpha = 0xffff; +} -- cgit 1.4.1