aboutsummaryrefslogtreecommitdiff
path: root/drw.c
diff options
context:
space:
mode:
authorMarkus Teich <markus.teich@stusta.mhn.de>2016-05-21 21:51:14 +0200
committerHiltjo Posthuma <hiltjo@codemadness.org>2016-06-03 19:13:15 +0200
commit44c7de3dcf49ee568863f55610f40c7a05b4dfe7 (patch)
tree1a3e45f6e616ff256a0d195272d68ca69f5c153f /drw.c
parentb3d9451c2ddfad7c1b10e9a868afed4d92b37e41 (diff)
downloaddmenu-44c7de3dcf49ee568863f55610f40c7a05b4dfe7.tar.gz
dmenu-44c7de3dcf49ee568863f55610f40c7a05b4dfe7.tar.bz2
dmenu-44c7de3dcf49ee568863f55610f40c7a05b4dfe7.zip
import new drw from libsl and minor fixes.
- extract drawitem function (code deduplication) - fix bug where inputw was not correctly calculated from the widest item, but just from the one with the longest strlen() which is not the same. It's better now, but does not account for fallback fonts, since it would be too slow to calculate all the correct item widths on startup. - minor code style fixes (indentation, useless line breaks)
Diffstat (limited to 'drw.c')
-rw-r--r--drw.c241
1 files changed, 132 insertions, 109 deletions
diff --git a/drw.c b/drw.c
index 80e3c39..95839c9 100644
--- a/drw.c
+++ b/drw.c
@@ -63,9 +63,8 @@ utf8decode(const char *c, long *u, size_t clen)
Drw *
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
{
- Drw *drw;
+ Drw *drw = ecalloc(1, sizeof(Drw));
- drw = ecalloc(1, sizeof(Drw));
drw->dpy = dpy;
drw->screen = screen;
drw->root = root;
@@ -73,7 +72,6 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
drw->h = h;
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
drw->gc = XCreateGC(dpy, root, 0, NULL);
- drw->fontcount = 0;
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
return drw;
@@ -82,6 +80,9 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
void
drw_resize(Drw *drw, unsigned int w, unsigned int h)
{
+ if (!drw)
+ return;
+
drw->w = w;
drw->h = h;
if (drw->drawable)
@@ -92,44 +93,39 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
void
drw_free(Drw *drw)
{
- size_t i;
-
- for (i = 0; i < drw->fontcount; i++)
- drw_font_free(drw->fonts[i]);
XFreePixmap(drw->dpy, drw->drawable);
XFreeGC(drw->dpy, drw->gc);
free(drw);
}
/* This function is an implementation detail. Library users should use
- * drw_font_create instead.
+ * drw_fontset_create instead.
*/
static Fnt *
-drw_font_xcreate(Drw *drw, const char *fontname, FcPattern *fontpattern)
+xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
{
Fnt *font;
XftFont *xfont = NULL;
FcPattern *pattern = NULL;
if (fontname) {
- /* Using the pattern found at font->xfont->pattern does not yield same
- * the same substitution results as using the pattern returned by
+ /* Using the pattern found at font->xfont->pattern does not yield the
+ * same substitution results as using the pattern returned by
* FcNameParse; using the latter results in the desired fallback
- * behaviour whereas the former just results in
- * missing-character-rectangles being drawn, at least with some fonts.
- */
+ * behaviour whereas the former just results in missing-character
+ * rectangles being drawn, at least with some fonts. */
if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
- fprintf(stderr, "error, cannot load font: '%s'\n", fontname);
+ fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
return NULL;
}
if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
- fprintf(stderr, "error, cannot load font: '%s'\n", fontname);
+ fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
XftFontClose(drw->dpy, xfont);
return NULL;
}
} else if (fontpattern) {
if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
- fprintf(stderr, "error, cannot load font pattern.\n");
+ fprintf(stderr, "error, cannot load font from pattern.\n");
return NULL;
}
} else {
@@ -139,95 +135,115 @@ drw_font_xcreate(Drw *drw, const char *fontname, FcPattern *fontpattern)
font = ecalloc(1, sizeof(Fnt));
font->xfont = xfont;
font->pattern = pattern;
- font->ascent = xfont->ascent;
- font->descent = xfont->descent;
- font->h = font->ascent + font->descent;
+ font->h = xfont->ascent + xfont->descent;
font->dpy = drw->dpy;
return font;
}
-Fnt*
-drw_font_create(Drw *drw, const char *fontname)
+static void
+xfont_free(Fnt *font)
{
- return drw_font_xcreate(drw, fontname, NULL);
+ if (!font)
+ return;
+ if (font->pattern)
+ FcPatternDestroy(font->pattern);
+ XftFontClose(font->dpy, font->xfont);
+ free(font);
}
-void
-drw_load_fonts(Drw* drw, const char *fonts[], size_t fontcount)
+Fnt*
+drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
{
+ Fnt *cur, *ret = NULL;
size_t i;
- Fnt *font;
- for (i = 0; i < fontcount; i++) {
- if (drw->fontcount >= DRW_FONT_CACHE_SIZE) {
- die("Font cache exhausted.\n");
- } else if ((font = drw_font_xcreate(drw, fonts[i], NULL))) {
- drw->fonts[drw->fontcount++] = font;
+ if (!drw || !fonts)
+ return NULL;
+
+ for (i = 1; i <= fontcount; i++) {
+ if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
+ cur->next = ret;
+ ret = cur;
}
}
+ return (drw->fonts = ret);
}
void
-drw_font_free(Fnt *font)
+drw_fontset_free(Fnt *font)
{
- if (!font)
- return;
- if (font->pattern)
- FcPatternDestroy(font->pattern);
- XftFontClose(font->dpy, font->xfont);
- free(font);
+ if (font) {
+ drw_fontset_free(font->next);
+ xfont_free(font);
+ }
}
-Clr *
-drw_clr_create(Drw *drw, const char *clrname)
+void
+drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
{
- Clr *clr;
+ if (!drw || !dest || !clrname)
+ return;
- clr = ecalloc(1, sizeof(Clr));
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen),
- clrname, &clr->rgb))
+ clrname, dest))
die("error, cannot allocate color '%s'\n", clrname);
- clr->pix = clr->rgb.pixel;
+}
+
+/* Wrapper to create color schemes. The caller has to call free(3) on the
+ * returned color scheme when done using it. */
+Clr *
+drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
+{
+ size_t i;
+ Clr *ret;
- return clr;
+ /* need at least two colors for a scheme */
+ if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
+ return NULL;
+
+ for (i = 0; i < clrcount; i++)
+ drw_clr_create(drw, &ret[i], clrnames[i]);
+ return ret;
}
void
-drw_clr_free(Clr *clr)
+drw_setfontset(Drw *drw, Fnt *set)
{
- free(clr);
+ if (drw)
+ drw->fonts = set;
}
void
-drw_setscheme(Drw *drw, ClrScheme *scheme)
+drw_setscheme(Drw *drw, Clr *scm)
{
- drw->scheme = scheme;
+ if (drw)
+ drw->scheme = scm;
}
void
-drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert)
+drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
{
- if (!drw->scheme)
+ if (!drw || !drw->scheme)
return;
- XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->pix : drw->scheme->fg->pix);
+ XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
if (filled)
- XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w + 1, h + 1);
- else if (empty)
- XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+ else
+ XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
}
int
-drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert)
+drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
{
char buf[1024];
- int tx, ty, th;
- Extnts tex;
+ int ty;
+ unsigned int ew;
XftDraw *d = NULL;
- Fnt *curfont, *nextfont;
+ Fnt *usedfont, *curfont, *nextfont;
size_t i, len;
- int utf8strlen, utf8charlen, render;
+ int utf8strlen, utf8charlen, render = x || y || w || h;
long utf8codepoint = 0;
const char *utf8str;
FcCharSet *fccharset;
@@ -236,66 +252,67 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex
XftResult result;
int charexists = 0;
- if (!drw->scheme || !drw->fontcount)
+ if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
return 0;
- if (!(render = x || y || w || h)) {
+ if (!render) {
w = ~w;
} else {
- XSetForeground(drw->dpy, drw->gc, invert ?
- drw->scheme->fg->pix : drw->scheme->bg->pix);
+ XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
d = XftDrawCreate(drw->dpy, drw->drawable,
DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen));
+ x += lpad;
+ w -= lpad;
}
- curfont = drw->fonts[0];
+ usedfont = drw->fonts;
while (1) {
utf8strlen = 0;
utf8str = text;
nextfont = NULL;
while (*text) {
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
- for (i = 0; i < drw->fontcount; i++) {
- charexists = charexists || XftCharExists(drw->dpy, drw->fonts[i]->xfont, utf8codepoint);
+ for (curfont = drw->fonts; curfont; curfont = curfont->next) {
+ charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
if (charexists) {
- if (drw->fonts[i] == curfont) {
+ if (curfont == usedfont) {
utf8strlen += utf8charlen;
text += utf8charlen;
} else {
- nextfont = drw->fonts[i];
+ nextfont = curfont;
}
break;
}
}
- if (!charexists || (nextfont && nextfont != curfont))
+ if (!charexists || nextfont)
break;
else
charexists = 0;
}
if (utf8strlen) {
- drw_font_getexts(curfont, utf8str, utf8strlen, &tex);
+ drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
/* shorten text if necessary */
- for (len = MIN(utf8strlen, (sizeof buf) - 1); len && (tex.w > w - drw->fonts[0]->h || w < drw->fonts[0]->h); len--)
- drw_font_getexts(curfont, utf8str, len, &tex);
+ for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--)
+ drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
if (len) {
memcpy(buf, utf8str, len);
buf[len] = '\0';
if (len < utf8strlen)
- for (i = len; i && i > len - 3; buf[--i] = '.');
+ for (i = len; i && i > len - 3; buf[--i] = '.')
+ ; /* NOP */
if (render) {
- th = curfont->ascent + curfont->descent;
- ty = y + (h / 2) - (th / 2) + curfont->ascent;
- tx = x + (h / 2);
- XftDrawStringUtf8(d, invert ? &drw->scheme->bg->rgb : &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len);
+ ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
+ XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
+ usedfont->xfont, x, ty, (XftChar8 *)buf, len);
}
- x += tex.w;
- w -= tex.w;
+ x += ew;
+ w -= ew;
}
}
@@ -303,26 +320,21 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex
break;
} else if (nextfont) {
charexists = 0;
- curfont = nextfont;
+ usedfont = nextfont;
} else {
/* Regardless of whether or not a fallback font is found, the
- * character must be drawn.
- */
+ * character must be drawn. */
charexists = 1;
- if (drw->fontcount >= DRW_FONT_CACHE_SIZE)
- continue;
-
fccharset = FcCharSetCreate();
FcCharSetAddChar(fccharset, utf8codepoint);
- if (!drw->fonts[0]->pattern) {
- /* Refer to the comment in drw_font_xcreate for more
- * information. */
+ if (!drw->fonts->pattern) {
+ /* Refer to the comment in xfont_create for more information. */
die("the first font in the cache must be loaded from a font string.\n");
}
- fcpattern = FcPatternDuplicate(drw->fonts[0]->pattern);
+ fcpattern = FcPatternDuplicate(drw->fonts->pattern);
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
@@ -334,12 +346,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex
FcPatternDestroy(fcpattern);
if (match) {
- curfont = drw_font_xcreate(drw, NULL, match);
- if (curfont && XftCharExists(drw->dpy, curfont->xfont, utf8codepoint)) {
- drw->fonts[drw->fontcount++] = curfont;
+ usedfont = xfont_create(drw, NULL, match);
+ if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
+ for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
+ ; /* NOP */
+ curfont->next = usedfont;
} else {
- drw_font_free(curfont);
- curfont = drw->fonts[0];
+ xfont_free(usedfont);
+ usedfont = drw->fonts;
}
}
}
@@ -347,34 +361,40 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *tex
if (d)
XftDrawDestroy(d);
- return x;
+ return x + (render ? w : 0);
}
void
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
{
+ if (!drw)
+ return;
+
XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
XSync(drw->dpy, False);
}
-void
-drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *tex)
+unsigned int
+drw_fontset_getwidth(Drw *drw, const char *text)
{
- XGlyphInfo ext;
-
- XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
- tex->h = font->h;
- tex->w = ext.xOff;
+ if (!drw || !drw->fonts || !text)
+ return 0;
+ return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
}
-unsigned int
-drw_font_getexts_width(Fnt *font, const char *text, unsigned int len)
+void
+drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
{
- Extnts tex;
+ XGlyphInfo ext;
- drw_font_getexts(font, text, len, &tex);
+ if (!font || !text)
+ return;
- return tex.w;
+ XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
+ if (w)
+ *w = ext.xOff;
+ if (h)
+ *h = font->h;
}
Cur *
@@ -382,7 +402,9 @@ drw_cur_create(Drw *drw, int shape)
{
Cur *cur;
- cur = ecalloc(1, sizeof(Cur));
+ if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
+ return NULL;
+
cur->cursor = XCreateFontCursor(drw->dpy, shape);
return cur;
@@ -393,6 +415,7 @@ drw_cur_free(Drw *drw, Cur *cursor)
{
if (!cursor)
return;
+
XFreeCursor(drw->dpy, cursor->cursor);
free(cursor);
}