]> Dogcows Code - chaz/openbox/blob - render/font.c
add missing comment
[chaz/openbox] / render / font.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
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
7
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.
12
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.
17
18 See the COPYING file for a copy of the GNU General Public License.
19 */
20
21 #include "font.h"
22 #include "color.h"
23 #include "mask.h"
24 #include "theme.h"
25 #include "geom.h"
26 #include "instance.h"
27 #include "gettext.h"
28
29 #include <glib.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <locale.h>
33
34 #define OB_SHADOW "shadow"
35 #define OB_SHADOW_OFFSET "shadowoffset"
36 #define OB_SHADOW_ALPHA "shadowtint"
37
38 FcObjectType objs[] = {
39 { OB_SHADOW, FcTypeBool },
40 { OB_SHADOW_OFFSET, FcTypeInteger },
41 { OB_SHADOW_ALPHA, FcTypeInteger }
42 };
43
44 static gboolean started = FALSE;
45
46 static void font_startup(void)
47 {
48 if (!XftInit(0)) {
49 g_warning(_("Couldn't initialize Xft."));
50 exit(EXIT_FAILURE);
51 }
52
53 /* Here we are teaching xft about the shadow, shadowoffset & shadowtint */
54 FcNameRegisterObjectTypes(objs, (sizeof(objs) / sizeof(objs[0])));
55 }
56
57 static void measure_font(const RrInstance *inst, RrFont *f)
58 {
59 PangoFontMetrics *metrics;
60 gchar *locale, *p;
61
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 @ */
67
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);
74
75 g_free(locale);
76 }
77
78 static RrFont *openfont(const RrInstance *inst, gchar *fontstring)
79 {
80 /* This function is called for each font in the theme file. */
81 /* It returns a pointer to a RrFont struct after filling it. */
82 RrFont *out;
83 FcPattern *pat;
84 gint tint;
85 gchar *sval;
86 gint ival;
87
88 if (!(pat = XftNameParse(fontstring)))
89 return NULL;
90
91 out = g_new(RrFont, 1);
92 out->inst = inst;
93 out->font_desc = pango_font_description_new();
94 out->layout = pango_layout_new(inst->pango);
95
96 /* get the data from the parsed xft string */
97
98 /* get the family */
99 if (FcPatternGetString(pat, "family", 0,
100 (FcChar8**)&sval) == FcResultMatch)
101 pango_font_description_set_family(out->font_desc, sval);
102
103 /* get the weight */
104 if (FcPatternGetInteger(pat, "weight", 0, &ival) == FcResultMatch) {
105 if (ival == FC_WEIGHT_LIGHT)
106 pango_font_description_set_weight(out->font_desc,
107 PANGO_WEIGHT_LIGHT);
108 else if (ival == FC_WEIGHT_DEMIBOLD)
109 pango_font_description_set_weight(out->font_desc,
110 PANGO_WEIGHT_SEMIBOLD);
111 else if (ival == FC_WEIGHT_BOLD)
112 pango_font_description_set_weight(out->font_desc,
113 PANGO_WEIGHT_BOLD);
114 else if (ival == FC_WEIGHT_BLACK)
115 pango_font_description_set_weight(out->font_desc,
116 PANGO_WEIGHT_ULTRABOLD);
117 }
118
119 /* get the style/slant */
120 if (FcPatternGetInteger(pat, "slant", 0, &ival) == FcResultMatch) {
121 if (ival == FC_SLANT_ITALIC)
122 pango_font_description_set_style(out->font_desc,
123 PANGO_STYLE_ITALIC);
124 else if (ival == FC_SLANT_OBLIQUE)
125 pango_font_description_set_style(out->font_desc,
126 PANGO_STYLE_OBLIQUE);
127 }
128
129 /* get the size */
130 if (FcPatternGetInteger(pat, "size", 0, &ival) == FcResultMatch)
131 pango_font_description_set_size(out->font_desc, ival * PANGO_SCALE);
132 else if (FcPatternGetInteger(pat, "pixelsize", 0, &ival) == FcResultMatch)
133 pango_font_description_set_absolute_size(out->font_desc,
134 ival * PANGO_SCALE);
135
136 if (FcPatternGetBool(pat, OB_SHADOW, 0, &out->shadow) != FcResultMatch)
137 out->shadow = FALSE;
138
139 if (FcPatternGetInteger(pat, OB_SHADOW_OFFSET, 0, &out->offset) !=
140 FcResultMatch)
141 out->offset = 1;
142
143 if (FcPatternGetInteger(pat, OB_SHADOW_ALPHA, 0, &tint) != FcResultMatch)
144 tint = 25;
145 if (tint > 100) tint = 100;
146 else if (tint < -100) tint = -100;
147 out->tint = tint;
148
149 /* setup the layout */
150 pango_layout_set_font_description(out->layout, out->font_desc);
151 pango_layout_set_single_paragraph_mode(out->layout, TRUE);
152 pango_layout_set_ellipsize(out->layout, PANGO_ELLIPSIZE_MIDDLE);
153
154 /* get the ascent and descent */
155 measure_font(inst, out);
156
157 return out;
158 }
159
160 RrFont *RrFontOpen(const RrInstance *inst, gchar *fontstring)
161 {
162 RrFont *out;
163
164 if (!started) {
165 font_startup();
166 started = TRUE;
167 }
168
169 if ((out = openfont(inst, fontstring)))
170 return out;
171 g_warning(_("Unable to load font: %s\n"), fontstring);
172 g_warning(_("Trying fallback font: %s\n"), "sans");
173
174 if ((out = openfont(inst, "sans")))
175 return out;
176 g_warning(_("Unable to load font: %s\n"), "sans");
177
178 return NULL;
179 }
180
181 void RrFontClose(RrFont *f)
182 {
183 if (f) {
184 g_object_unref(f->layout);
185 pango_font_description_free(f->font_desc);
186 g_free(f);
187 }
188 }
189
190 static void font_measure_full(const RrFont *f, const gchar *str,
191 gint *x, gint *y)
192 {
193 PangoRectangle rect;
194
195 pango_layout_set_text(f->layout, str, -1);
196 pango_layout_set_width(f->layout, -1);
197 pango_layout_get_pixel_extents(f->layout, NULL, &rect);
198 *x = rect.width + (f->shadow ? ABS(f->offset) : 0);
199 *y = rect.height + (f->shadow ? ABS(f->offset) : 0);
200 }
201
202 RrSize *RrFontMeasureString(const RrFont *f, const gchar *str)
203 {
204 RrSize *size;
205 size = g_new(RrSize, 1);
206 font_measure_full(f, str, &size->width, &size->height);
207 return size;
208 }
209
210 gint RrFontHeight(const RrFont *f)
211 {
212 return (f->ascent + f->descent) / PANGO_SCALE +
213 (f->shadow ? f->offset : 0);
214 }
215
216 static inline int font_calculate_baseline(RrFont *f, gint height)
217 {
218 /* For my own reference:
219 * _________
220 * ^space/2 ^height ^baseline
221 * v_________|_ |
222 * | ^ascent | _ _
223 * | | | | |_ _____ _| |_ _ _
224 * | | | | _/ -_) \ / _| || |
225 * | v_________v \__\___/_\_\\__|\_, |
226 * | ^descent |__/
227 * __________|_v
228 * ^space/2 |
229 * V_________v
230 */
231 return (((height * PANGO_SCALE) /* height of the space in pango units */
232 - (f->ascent + f->descent)) /* minus space taken up by text */
233 / 2 /* divided by two -> half of the empty space (this is the top
234 of the text) */
235 + f->ascent) /* now move down to the baseline */
236 / PANGO_SCALE; /* back to pixels */
237 }
238
239 void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
240 {
241 gint x,y,w,h;
242 XftColor c;
243 gint mw;
244 PangoRectangle rect;
245
246 /* center the text vertically
247 We do this centering based on the 'baseline' since different fonts have
248 different top edges. It looks bad when the whole string is moved when 1
249 character from a non-default language is included in the string */
250 y = area->y +
251 font_calculate_baseline(t->font, area->height);
252
253 /* the +2 and -4 leave a small blank edge on the sides */
254 x = area->x + 2;
255 w = area->width - 4;
256 h = area->height;
257
258 pango_layout_set_text(t->font->layout, t->string, -1);
259 pango_layout_set_width(t->font->layout, w * PANGO_SCALE);
260
261 pango_layout_get_pixel_extents(t->font->layout, NULL, &rect);
262 mw = rect.width;
263
264 /* pango_layout_set_alignment doesn't work with
265 pango_xft_render_layout_line */
266 switch (t->justify) {
267 case RR_JUSTIFY_LEFT:
268 break;
269 case RR_JUSTIFY_RIGHT:
270 x += (w - mw);
271 break;
272 case RR_JUSTIFY_CENTER:
273 x += (w - mw) / 2;
274 break;
275 }
276
277 if (t->font->shadow) {
278 if (t->font->tint >= 0) {
279 c.color.red = 0;
280 c.color.green = 0;
281 c.color.blue = 0;
282 c.color.alpha = 0xffff * t->font->tint / 100;
283 c.pixel = BlackPixel(RrDisplay(t->font->inst),
284 RrScreen(t->font->inst));
285 } else {
286 c.color.red = 0xffff;
287 c.color.green = 0xffff;
288 c.color.blue = 0xffff;
289 c.color.alpha = 0xffff * -t->font->tint / 100;
290 c.pixel = WhitePixel(RrDisplay(t->font->inst),
291 RrScreen(t->font->inst));
292 }
293 /* see below... */
294 pango_xft_render_layout_line
295 (d, &c, pango_layout_get_line(t->font->layout, 0),
296 (x + t->font->offset) * PANGO_SCALE,
297 (y + t->font->offset) * PANGO_SCALE);
298 }
299
300 c.color.red = t->color->r | t->color->r << 8;
301 c.color.green = t->color->g | t->color->g << 8;
302 c.color.blue = t->color->b | t->color->b << 8;
303 c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */
304 c.pixel = t->color->pixel;
305
306 /* layout_line() uses y to specify the baseline
307 The line doesn't need to be freed, it's a part of the layout */
308 pango_xft_render_layout_line
309 (d, &c, pango_layout_get_line(t->font->layout, 0),
310 x * PANGO_SCALE, y * PANGO_SCALE);
311 }
This page took 0.048091 seconds and 5 git commands to generate.