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