]> Dogcows Code - chaz/openbox/blob - render/font.c
you can create dialog windows called "prompts" which have a message and some buttons...
[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-2007 Dana 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 static void measure_font(const RrInstance *inst, RrFont *f)
35 {
36 PangoFontMetrics *metrics;
37 static PangoLanguage *lang = NULL;
38
39 if (lang == NULL) {
40 #if PANGO_VERSION_MAJOR > 1 || \
41 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
42 lang = pango_language_get_default();
43 #else
44 gchar *locale, *p;
45 /* get the default language from the locale
46 (based on gtk_get_default_language in gtkmain.c) */
47 locale = g_strdup(setlocale(LC_CTYPE, NULL));
48 if ((p = strchr(locale, '.'))) *p = '\0'; /* strip off the . */
49 if ((p = strchr(locale, '@'))) *p = '\0'; /* strip off the @ */
50 lang = pango_language_from_string(locale);
51 g_free(locale);
52 #endif
53 }
54
55 /* measure the ascent and descent */
56 metrics = pango_context_get_metrics(inst->pango, f->font_desc, lang);
57 f->ascent = pango_font_metrics_get_ascent(metrics);
58 f->descent = pango_font_metrics_get_descent(metrics);
59 pango_font_metrics_unref(metrics);
60
61 }
62
63 RrFont *RrFontOpen(const RrInstance *inst, const gchar *name, gint size,
64 RrFontWeight weight, RrFontSlant slant)
65 {
66 RrFont *out;
67 PangoWeight pweight;
68 PangoStyle pstyle;
69 PangoAttrList *attrlist;
70
71 out = g_new(RrFont, 1);
72 out->inst = inst;
73 out->ref = 1;
74 out->font_desc = pango_font_description_new();
75 out->layout = pango_layout_new(inst->pango);
76 out->shortcut_underline = pango_attr_underline_new(PANGO_UNDERLINE_LOW);
77 out->shortcut_underline->start_index = 0;
78 out->shortcut_underline->end_index = 0;
79
80 attrlist = pango_attr_list_new();
81 /* shortcut_underline is owned by the attrlist */
82 pango_attr_list_insert(attrlist, out->shortcut_underline);
83 /* the attributes are owned by the layout */
84 pango_layout_set_attributes(out->layout, attrlist);
85 pango_attr_list_unref(attrlist);
86
87 switch (weight) {
88 case RR_FONTWEIGHT_LIGHT: pweight = PANGO_WEIGHT_LIGHT; break;
89 case RR_FONTWEIGHT_NORMAL: pweight = PANGO_WEIGHT_NORMAL; break;
90 case RR_FONTWEIGHT_SEMIBOLD: pweight = PANGO_WEIGHT_SEMIBOLD; break;
91 case RR_FONTWEIGHT_BOLD: pweight = PANGO_WEIGHT_BOLD; break;
92 case RR_FONTWEIGHT_ULTRABOLD: pweight = PANGO_WEIGHT_ULTRABOLD; break;
93 default: g_assert_not_reached();
94 }
95
96 switch (slant) {
97 case RR_FONTSLANT_NORMAL: pstyle = PANGO_STYLE_NORMAL; break;
98 case RR_FONTSLANT_ITALIC: pstyle = PANGO_STYLE_ITALIC; break;
99 case RR_FONTSLANT_OBLIQUE: pstyle = PANGO_STYLE_OBLIQUE; break;
100 default: g_assert_not_reached();
101 }
102
103 /* setup the font */
104 pango_font_description_set_family(out->font_desc, name);
105 pango_font_description_set_weight(out->font_desc, pweight);
106 pango_font_description_set_style(out->font_desc, pstyle);
107 pango_font_description_set_size(out->font_desc, size * PANGO_SCALE);
108
109 /* setup the layout */
110 pango_layout_set_font_description(out->layout, out->font_desc);
111 pango_layout_set_single_paragraph_mode(out->layout, TRUE);
112 pango_layout_set_wrap(out->layout, PANGO_WRAP_WORD_CHAR);
113
114 /* get the ascent and descent */
115 measure_font(inst, out);
116
117 return out;
118 }
119
120 RrFont *RrFontOpenDefault(const RrInstance *inst)
121 {
122 return RrFontOpen(inst, RrDefaultFontFamily, RrDefaultFontSize,
123 RrDefaultFontWeight, RrDefaultFontSlant);
124 }
125
126 void RrFontRef(RrFont *f)
127 {
128 ++f->ref;
129 }
130
131 void RrFontClose(RrFont *f)
132 {
133 if (f) {
134 if (--f->ref < 1) {
135 g_object_unref(f->layout);
136 pango_font_description_free(f->font_desc);
137 g_free(f);
138 }
139 }
140 }
141
142 static void font_measure_full(const RrFont *f, const gchar *str,
143 gint *x, gint *y, gint shadow_x, gint shadow_y,
144 gint maxwidth)
145 {
146 PangoRectangle rect;
147
148 pango_layout_set_text(f->layout, str, -1);
149 pango_layout_set_width(f->layout,
150 (maxwidth <= 0 ? -1 : maxwidth * PANGO_SCALE));
151
152 /* pango_layout_get_pixel_extents lies! this is the right way to get the
153 size of the text's area */
154 pango_layout_get_extents(f->layout, NULL, &rect);
155 #if PANGO_VERSION_MAJOR > 1 || \
156 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
157 /* pass the logical rect as the ink rect, this is on purpose so we get the
158 full area for the text */
159 pango_extents_to_pixels(&rect, NULL);
160 #else
161 rect.width = (rect.width + PANGO_SCALE - 1) / PANGO_SCALE;
162 rect.height = (rect.height + PANGO_SCALE - 1) / PANGO_SCALE;
163 #endif
164 *x = rect.width + ABS(shadow_x) + 4 /* we put a 2 px edge on each side */;
165 *y = rect.height + ABS(shadow_y);
166 }
167
168 RrSize *RrFontMeasureString(const RrFont *f, const gchar *str,
169 gint shadow_x, gint shadow_y, gint maxwidth)
170 {
171 RrSize *size;
172 size = g_new(RrSize, 1);
173 font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y,
174 maxwidth);
175 return size;
176 }
177
178 gint RrFontHeight(const RrFont *f, gint shadow_y)
179 {
180 return (f->ascent + f->descent) / PANGO_SCALE + ABS(shadow_y);
181 }
182
183 static inline int font_calculate_baseline(RrFont *f, gint height)
184 {
185 /* For my own reference:
186 * _________
187 * ^space/2 ^height ^baseline
188 * v_________|_ |
189 * | ^ascent | _ _
190 * | | | | |_ _____ _| |_ _ _
191 * | | | | _/ -_) \ / _| || |
192 * | v_________v \__\___/_\_\\__|\_, |
193 * | ^descent |__/
194 * __________|_v
195 * ^space/2 |
196 * V_________v
197 */
198 return (((height * PANGO_SCALE) /* height of the space in pango units */
199 - (f->ascent + f->descent)) /* minus space taken up by text */
200 / 2 /* divided by two -> half of the empty space (this is the top
201 of the text) */
202 + f->ascent) /* now move down to the baseline */
203 / PANGO_SCALE; /* back to pixels */
204 }
205
206 void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
207 {
208 gint x,y,w,h;
209 XftColor c;
210 gint mw;
211 PangoRectangle rect;
212 PangoAttrList *attrlist;
213 PangoEllipsizeMode ell;
214
215 /* center the text vertically
216 We do this centering based on the 'baseline' since different fonts have
217 different top edges. It looks bad when the whole string is moved when 1
218 character from a non-default language is included in the string */
219 y = area->y +
220 font_calculate_baseline(t->font, area->height);
221
222 /* the +2 and -4 leave a small blank edge on the sides */
223 x = area->x + 2;
224 w = area->width - 4;
225 h = area->height;
226
227 switch (t->ellipsize) {
228 case RR_ELLIPSIZE_NONE:
229 ell = PANGO_ELLIPSIZE_NONE;
230 break;
231 case RR_ELLIPSIZE_START:
232 ell = PANGO_ELLIPSIZE_START;
233 break;
234 case RR_ELLIPSIZE_MIDDLE:
235 ell = PANGO_ELLIPSIZE_MIDDLE;
236 break;
237 case RR_ELLIPSIZE_END:
238 ell = PANGO_ELLIPSIZE_END;
239 break;
240 }
241
242 pango_layout_set_text(t->font->layout, t->string, -1);
243 pango_layout_set_width(t->font->layout, w * PANGO_SCALE);
244 pango_layout_set_ellipsize(t->font->layout, ell);
245
246 /* * * end of setting up the layout * * */
247
248 pango_layout_get_pixel_extents(t->font->layout, NULL, &rect);
249 mw = rect.width;
250
251 /* pango_layout_set_alignment doesn't work with
252 pango_xft_render_layout_line */
253 switch (t->justify) {
254 case RR_JUSTIFY_LEFT:
255 break;
256 case RR_JUSTIFY_RIGHT:
257 x += (w - mw);
258 break;
259 case RR_JUSTIFY_CENTER:
260 x += (w - mw) / 2;
261 break;
262 }
263
264 if (t->shadow_offset_x || t->shadow_offset_y) {
265 c.color.red = t->shadow_color->r | t->shadow_color->r << 8;
266 c.color.green = t->shadow_color->g | t->shadow_color->g << 8;
267 c.color.blue = t->shadow_color->b | t->shadow_color->b << 8;
268 c.color.alpha = 0xffff * t->shadow_alpha / 255;
269 c.pixel = t->shadow_color->pixel;
270
271 /* see below... */
272 pango_xft_render_layout_line
273 (d, &c, pango_layout_get_line(t->font->layout, 0),
274 (x + t->shadow_offset_x) * PANGO_SCALE,
275 (y + t->shadow_offset_y) * PANGO_SCALE);
276 }
277
278 c.color.red = t->color->r | t->color->r << 8;
279 c.color.green = t->color->g | t->color->g << 8;
280 c.color.blue = t->color->b | t->color->b << 8;
281 c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */
282 c.pixel = t->color->pixel;
283
284 if (t->shortcut) {
285 const gchar *s = t->string + t->shortcut_pos;
286
287 t->font->shortcut_underline->start_index = t->shortcut_pos;
288 t->font->shortcut_underline->end_index = t->shortcut_pos +
289 (g_utf8_next_char(s) - s);
290
291 /* the attributes are owned by the layout.
292 re-add the attributes to the layout after changing the
293 start and end index */
294 attrlist = pango_layout_get_attributes(t->font->layout);
295 pango_attr_list_ref(attrlist);
296 pango_layout_set_attributes(t->font->layout, attrlist);
297 pango_attr_list_unref(attrlist);
298 }
299
300 /* layout_line() uses y to specify the baseline
301 The line doesn't need to be freed, it's a part of the layout */
302 pango_xft_render_layout_line
303 (d, &c, pango_layout_get_line(t->font->layout, 0),
304 x * PANGO_SCALE, y * PANGO_SCALE);
305
306 if (t->shortcut) {
307 t->font->shortcut_underline->start_index = 0;
308 t->font->shortcut_underline->end_index = 0;
309 /* the attributes are owned by the layout.
310 re-add the attributes to the layout after changing the
311 start and end index */
312 attrlist = pango_layout_get_attributes(t->font->layout);
313 pango_attr_list_ref(attrlist);
314 pango_layout_set_attributes(t->font->layout, attrlist);
315 pango_attr_list_unref(attrlist);
316 }
317 }
This page took 0.047839 seconds and 5 git commands to generate.