1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 font.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003 Ben Jansens
6 Copyright (c) 2003 Derek Foreman
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 See the COPYING file for a copy of the GNU General Public License.
34 #define OB_SHADOW "shadow"
35 #define OB_SHADOW_OFFSET "shadowoffset"
36 #define OB_SHADOW_ALPHA "shadowtint"
38 FcObjectType objs[] = {
39 { OB_SHADOW, FcTypeBool },
40 { OB_SHADOW_OFFSET, FcTypeInteger },
41 { OB_SHADOW_ALPHA, FcTypeInteger }
44 static gboolean started = FALSE;
46 static void font_startup(void)
49 g_warning(_("Couldn't initialize Xft."));
53 /* Here we are teaching xft about the shadow, shadowoffset & shadowtint */
54 FcNameRegisterObjectTypes(objs, (sizeof(objs) / sizeof(objs[0])));
57 static void measure_font(const RrInstance *inst, RrFont *f)
59 PangoFontMetrics *metrics;
62 /* get the default language from the locale
63 (based on gtk_get_default_language in gtkmain.c) */
64 locale = g_strdup(setlocale(LC_CTYPE, NULL));
65 if ((p = strchr(locale, '.'))) *p = '\0'; /* strip off the . */
66 if ((p = strchr(locale, '@'))) *p = '\0'; /* strip off the @ */
68 /* measure the ascent and descent */
69 metrics = pango_context_get_metrics(inst->pango, f->font_desc,
70 pango_language_from_string(locale));
71 f->ascent = pango_font_metrics_get_ascent(metrics);
72 f->descent = pango_font_metrics_get_descent(metrics);
73 pango_font_metrics_unref(metrics);
78 RrFont *RrFontOpen(const RrInstance *inst, gchar *name, gint size,
79 RrFontWeight weight, RrFontSlant slant, gboolean shadow,
80 gint shadowoffset, gchar shadowtint)
91 g_assert(shadowtint <= 100 && shadowtint >= -100);
93 out = g_new(RrFont, 1);
96 out->font_desc = pango_font_description_new();
97 out->layout = pango_layout_new(inst->pango);
100 case RR_FONTWEIGHT_LIGHT: pweight = PANGO_WEIGHT_LIGHT; break;
101 case RR_FONTWEIGHT_NORMAL: pweight = PANGO_WEIGHT_NORMAL; break;
102 case RR_FONTWEIGHT_SEMIBOLD: pweight = PANGO_WEIGHT_SEMIBOLD; break;
103 case RR_FONTWEIGHT_BOLD: pweight = PANGO_WEIGHT_BOLD; break;
104 case RR_FONTWEIGHT_ULTRABOLD: pweight = PANGO_WEIGHT_ULTRABOLD; break;
105 default: g_assert_not_reached();
109 case RR_FONTSLANT_NORMAL: pstyle = PANGO_STYLE_NORMAL; break;
110 case RR_FONTSLANT_ITALIC: pstyle = PANGO_STYLE_ITALIC; break;
111 case RR_FONTSLANT_OBLIQUE: pstyle = PANGO_STYLE_OBLIQUE; break;
112 default: g_assert_not_reached();
116 pango_font_description_set_family(out->font_desc, name);
117 pango_font_description_set_weight(out->font_desc, pweight);
118 pango_font_description_set_style(out->font_desc, pstyle);
119 pango_font_description_set_size(out->font_desc, size * PANGO_SCALE);
121 /* setup the shadow */
122 out->shadow = shadow;
123 out->offset = shadowoffset;
124 out->tint = shadowtint;
126 /* setup the layout */
127 pango_layout_set_font_description(out->layout, out->font_desc);
128 pango_layout_set_single_paragraph_mode(out->layout, TRUE);
129 pango_layout_set_ellipsize(out->layout, PANGO_ELLIPSIZE_MIDDLE);
131 /* get the ascent and descent */
132 measure_font(inst, out);
137 RrFont *RrFontOpenDefault(const RrInstance *inst)
139 return RrFontOpen(inst, RrDefaultFontFamily, RrDefaultFontSize,
140 RrDefaultFontWeight, RrDefaultFontSlant,
141 RrDefaultFontShadow, RrDefaultFontShadowOffset,
142 RrDefaultFontShadowTint);
145 void RrFontRef(RrFont *f)
150 void RrFontClose(RrFont *f)
154 g_object_unref(f->layout);
155 pango_font_description_free(f->font_desc);
161 static void font_measure_full(const RrFont *f, const gchar *str,
166 pango_layout_set_text(f->layout, str, -1);
167 pango_layout_set_width(f->layout, -1);
168 pango_layout_get_pixel_extents(f->layout, NULL, &rect);
169 *x = rect.width + (f->shadow ? ABS(f->offset) : 0);
170 *y = rect.height + (f->shadow ? ABS(f->offset) : 0);
173 RrSize *RrFontMeasureString(const RrFont *f, const gchar *str)
176 size = g_new(RrSize, 1);
177 font_measure_full(f, str, &size->width, &size->height);
181 gint RrFontHeight(const RrFont *f)
183 return (f->ascent + f->descent) / PANGO_SCALE +
184 (f->shadow ? f->offset : 0);
187 static inline int font_calculate_baseline(RrFont *f, gint height)
189 /* For my own reference:
191 * ^space/2 ^height ^baseline
194 * | | | | |_ _____ _| |_ _ _
195 * | | | | _/ -_) \ / _| || |
196 * | v_________v \__\___/_\_\\__|\_, |
202 return (((height * PANGO_SCALE) /* height of the space in pango units */
203 - (f->ascent + f->descent)) /* minus space taken up by text */
204 / 2 /* divided by two -> half of the empty space (this is the top
206 + f->ascent) /* now move down to the baseline */
207 / PANGO_SCALE; /* back to pixels */
210 void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
217 /* center the text vertically
218 We do this centering based on the 'baseline' since different fonts have
219 different top edges. It looks bad when the whole string is moved when 1
220 character from a non-default language is included in the string */
222 font_calculate_baseline(t->font, area->height);
224 /* the +2 and -4 leave a small blank edge on the sides */
229 pango_layout_set_text(t->font->layout, t->string, -1);
230 pango_layout_set_width(t->font->layout, w * PANGO_SCALE);
232 pango_layout_get_pixel_extents(t->font->layout, NULL, &rect);
235 /* pango_layout_set_alignment doesn't work with
236 pango_xft_render_layout_line */
237 switch (t->justify) {
238 case RR_JUSTIFY_LEFT:
240 case RR_JUSTIFY_RIGHT:
243 case RR_JUSTIFY_CENTER:
248 if (t->font->shadow) {
249 if (t->font->tint >= 0) {
253 c.color.alpha = 0xffff * t->font->tint / 100;
254 c.pixel = BlackPixel(RrDisplay(t->font->inst),
255 RrScreen(t->font->inst));
257 c.color.red = 0xffff;
258 c.color.green = 0xffff;
259 c.color.blue = 0xffff;
260 c.color.alpha = 0xffff * -t->font->tint / 100;
261 c.pixel = WhitePixel(RrDisplay(t->font->inst),
262 RrScreen(t->font->inst));
265 pango_xft_render_layout_line
266 (d, &c, pango_layout_get_line(t->font->layout, 0),
267 (x + t->font->offset) * PANGO_SCALE,
268 (y + t->font->offset) * PANGO_SCALE);
271 c.color.red = t->color->r | t->color->r << 8;
272 c.color.green = t->color->g | t->color->g << 8;
273 c.color.blue = t->color->b | t->color->b << 8;
274 c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */
275 c.pixel = t->color->pixel;
277 /* layout_line() uses y to specify the baseline
278 The line doesn't need to be freed, it's a part of the layout */
279 pango_xft_render_layout_line
280 (d, &c, pango_layout_get_line(t->font->layout, 0),
281 x * PANGO_SCALE, y * PANGO_SCALE);