X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=render%2Ffont.c;h=d2a4acaeed31e0b8177d4903489d136a3b913581;hb=35418ca0fcd3fd28ef579f4435b8bad3b7c87f04;hp=eb72feb17c63ab7e8ab05761742e720b59b45d6f;hpb=f8a47de5ec444c452093371e3db16857eb39a490;p=chaz%2Fopenbox diff --git a/render/font.c b/render/font.c index eb72feb1..d2a4acae 100644 --- a/render/font.c +++ b/render/font.c @@ -1,75 +1,229 @@ #include "font.h" +#include "color.h" +#include "mask.h" +#include "theme.h" +#include "gettext.h" -#include "../src/gettext.h" -#define _(str) gettext(str) +#include +#include +#include -font_open(const std::string &fontstring, - bool shadow, unsigned char offset, unsigned char tint) +#define ELIPSES "..." +#define ELIPSES_LENGTH(font) \ + (font->elipses_length + (font->shadow ? font->offset : 0)) + +#define OB_SHADOW "shadow" +#define OB_SHADOW_OFFSET "shadowoffset" +#define OB_SHADOW_ALPHA "shadowtint" + +FcObjectType objs[] = { + { OB_SHADOW, FcTypeBool }, + { OB_SHADOW_OFFSET, FcTypeInteger }, + { OB_SHADOW_ALPHA, FcTypeInteger } +}; + +static gboolean started = FALSE; + +static void font_startup(void) { - assert(screen_num >= 0); - assert(tint <= CHAR_MAX); - - if (!_xft_init) { if (!XftInit(0)) { - printf(_("Couldn't initialize Xft.\n\n")); - ::exit(3); + g_warning(_("Couldn't initialize Xft.\n")); + exit(EXIT_FAILURE); } -#ifdef DEBUG - int version = XftGetVersion(); - printf("Using Xft %d.%d.%d (Built against %d.%d.%d).\n", - version / 10000 % 100, version / 100 % 100, version % 100, - XFT_MAJOR, XFT_MINOR, XFT_REVISION); -#endif - _xft_init = true; - } - - if ((_xftfont = XftFontOpenName(ob_display, _screen_num, - fontstring))) - return; - - printf(_("Unable to load font: %s\n"), _fontstring.c_str()); - printf(_("Trying fallback font: %s\n"), "fixed"); - - if ((_xftfont = XftFontOpenName(ob_display, _screen_num, - "fixed"))) - return; + FcNameRegisterObjectTypes(objs, (sizeof(objs) / sizeof(objs[0]))); +} - printf(_("Unable to load font: %s\n"), "fixed"); - printf(_("Aborting!.\n")); +static void measure_font(RrFont *f) +{ + XGlyphInfo info; - exit(3); // can't continue without a font + /* measure an elipses */ + XftTextExtentsUtf8(RrDisplay(f->inst), f->xftfont, + (FcChar8*)ELIPSES, strlen(ELIPSES), &info); + f->elipses_length = (signed) info.xOff; } +static RrFont *openfont(const RrInstance *inst, char *fontstring) +{ + RrFont *out; + FcPattern *pat, *match; + XftFont *font; + FcResult res; + gint tint; + + if (!(pat = XftNameParse(fontstring))) + return NULL; + + match = XftFontMatch(RrDisplay(inst), RrScreen(inst), pat, &res); + if (!match) + return NULL; + + out = g_new(RrFont, 1); + out->inst = inst; + + if (FcPatternGetBool(match, OB_SHADOW, 0, &out->shadow) != FcResultMatch) + out->shadow = FALSE; + + if (FcPatternGetInteger(match, OB_SHADOW_OFFSET, 0, &out->offset) != + FcResultMatch) + out->offset = 1; + + if (FcPatternGetInteger(match, OB_SHADOW_ALPHA, 0, &tint) != FcResultMatch) + tint = 25; + if (tint > 100) tint = 100; + else if (tint < -100) tint = -100; + out->tint = tint; + + font = XftFontOpenPattern(RrDisplay(inst), match); + if (!font) { + FcPatternDestroy(match); + g_free(out); + return NULL; + } else + out->xftfont = font; + + measure_font(out); + + return out; +} -destroy_fonts(void) +RrFont *RrFontOpen(const RrInstance *inst, char *fontstring) { - if (_xftfont) - XftFontClose(ob_display, _xftfont); + RrFont *out; + + if (!started) { + font_startup(); + started = TRUE; + } + + if ((out = openfont(inst, fontstring))) + return out; + g_warning(_("Unable to load font: %s\n"), fontstring); + g_warning(_("Trying fallback font: %s\n"), "sans"); + + if ((out = openfont(inst, "sans"))) + return out; + g_warning(_("Unable to load font: %s\n"), "sans"); + + return NULL; } +void RrFontClose(RrFont *f) +{ + if (f) { + XftFontClose(RrDisplay(f->inst), f->xftfont); + g_free(f); + } +} -int font_measure_string(const char *) +static void font_measure_full(const RrFont *f, const gchar *str, + gint *x, gint *y) { - XGlyphInfo info; + XGlyphInfo info; - if (string.utf8()) - XftTextExtentsUtf8(**display, _xftfont, - (FcChar8*)string.c_str(), string.bytes(), &info); - else - XftTextExtents8(ob_display, _xftfont, - (FcChar8*)string.c_str(), string.bytes(), &info); + XftTextExtentsUtf8(RrDisplay(f->inst), f->xftfont, + (const FcChar8*)str, strlen(str), &info); - return (signed) info.xOff + (_shadow ? _offset : 0); + *x = (signed) info.xOff + (f->shadow ? ABS(f->offset) : 0); + *y = info.height + (f->shadow ? ABS(f->offset) : 0); } +int RrFontMeasureString(const RrFont *f, const gchar *str) +{ + gint x, y; + font_measure_full (f, str, &x, &y); + return x; +} -int font_height(void) +int RrFontHeight(const RrFont *f) { - return (signed) _xftfont->height + (_shadow ? _offset : 0); + return f->xftfont->ascent + f->xftfont->descent + + (f->shadow ? f->offset : 0); } +int RrFontMaxCharWidth(const RrFont *f) +{ + return (signed) f->xftfont->max_advance_width; +} -int font_max_char_width(void) +void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area) { - return (signed) _xftfont->max_advance_width; + gint x,y,w,h; + XftColor c; + GString *text; + gint mw, em, mh; + size_t l; + gboolean shortened = FALSE; + + /* center vertically */ + y = area->y + + (area->height - RrFontHeight(t->font)) / 2; + /* the +2 and -4 leave a small blank edge on the sides */ + x = area->x + 2; + w = area->width - 4; + h = area->height; + + text = g_string_new(t->string); + l = g_utf8_strlen(text->str, -1); + font_measure_full(t->font, text->str, &mw, &mh); + while (l && mw > area->width) { + shortened = TRUE; + /* remove a character from the middle */ + text = g_string_erase(text, l-- / 2, 1); + em = ELIPSES_LENGTH(t->font); + /* if the elipses are too large, don't show them at all */ + if (em > area->width) + shortened = FALSE; + font_measure_full(t->font, text->str, &mw, &mh); + mw += em; + } + if (shortened) { + text = g_string_insert(text, (l + 1) / 2, ELIPSES); + l += 3; + } + if (!l) return; + + switch (t->justify) { + case RR_JUSTIFY_LEFT: + break; + case RR_JUSTIFY_RIGHT: + x += (w - mw); + break; + case RR_JUSTIFY_CENTER: + x += (w - mw) / 2; + break; + } + + l = strlen(text->str); /* number of bytes */ + + if (t->font->shadow) { + if (t->font->tint >= 0) { + c.color.red = 0; + c.color.green = 0; + c.color.blue = 0; + c.color.alpha = 0xffff * t->font->tint / 100; + c.pixel = BlackPixel(RrDisplay(t->font->inst), + RrScreen(t->font->inst)); + } else { + c.color.red = 0xffff; + c.color.green = 0xffff; + c.color.blue = 0xffff; + c.color.alpha = 0xffff * -t->font->tint / 100; + c.pixel = WhitePixel(RrDisplay(t->font->inst), + RrScreen(t->font->inst)); + } + XftDrawStringUtf8(d, &c, t->font->xftfont, x + t->font->offset, + t->font->xftfont->ascent + y + t->font->offset, + (FcChar8*)text->str, l); + } + c.color.red = t->color->r | t->color->r << 8; + c.color.green = t->color->g | t->color->g << 8; + c.color.blue = t->color->b | t->color->b << 8; + c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */ + c.pixel = t->color->pixel; + + XftDrawStringUtf8(d, &c, t->font->xftfont, x, + t->font->xftfont->ascent + y, + (FcChar8*)text->str, l); + return; }