]> Dogcows Code - chaz/openbox/blob - src/Font.cc
e2649f10ae3e056ac7609e233cff365ef6e37b07
[chaz/openbox] / src / Font.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Font.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #ifdef HAVE_CONFIG_H
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 extern "C" {
29 #ifdef HAVE_STDLIB_H
30 # include <stdlib.h>
31 #endif // HAVE_STDLIB_H
32 }
33
34 #include <iostream>
35 #include <algorithm>
36
37 using std::string;
38 using std::cerr;
39 using std::endl;
40
41 #include "i18n.hh"
42 #include "Font.hh"
43 #include "Util.hh"
44 #include "GCCache.hh"
45 #include "Color.hh"
46
47 string BFont::_fallback_font = "fixed";
48
49 #ifdef XFT
50 BFont::BFont(Display *d, BScreen *screen, const string &family, int size,
51 bool bold, bool italic, bool shadow, unsigned char offset,
52 unsigned char tint, bool antialias) :
53 _display(d),
54 _screen(screen),
55 _family(family),
56 _simplename(False),
57 _size(size),
58 _bold(bold),
59 _italic(italic),
60 _antialias(antialias),
61 _shadow(shadow),
62 _offset(offset),
63 _tint(tint),
64 _xftfont(0),
65 _font(0),
66 _fontset(0),
67 _fontset_extents(0) {
68 _valid = False;
69
70 _xftfont = XftFontOpen(_display, _screen->getScreenNumber(),
71 XFT_FAMILY, XftTypeString, _family.c_str(),
72 XFT_SIZE, XftTypeInteger, _size,
73 XFT_WEIGHT, XftTypeInteger, (_bold ?
74 XFT_WEIGHT_BOLD :
75 XFT_WEIGHT_MEDIUM),
76 XFT_SLANT, XftTypeInteger, (_italic ?
77 XFT_SLANT_ITALIC :
78 XFT_SLANT_ROMAN),
79 XFT_ANTIALIAS, XftTypeBool, _antialias,
80 0);
81 if (! _xftfont)
82 return; // failure
83
84 _font = XLoadQueryFont(_display, buildXlfd().c_str());
85 if (! _font)
86 return; // failure
87
88 _valid = True;
89 }
90 #endif
91
92
93 BFont::BFont(Display *d, BScreen *screen, const string &xlfd) :
94 _display(d),
95 _screen(screen),
96 #ifdef XFT
97 _antialias(False),
98 _shadow(False),
99 _xftfont(0),
100 #endif // XFT
101 _font(0),
102 _fontset(0),
103 _fontset_extents(0) {
104 string int_xlfd;
105 if (xlfd.empty())
106 int_xlfd = _fallback_font;
107 else
108 int_xlfd = xlfd;
109
110 if ((_valid = createXFont(int_xlfd)))
111 return; // success
112
113 if (int_xlfd != _fallback_font) {
114 // try the fallback
115 cerr << "BFont::BFont(): couldn't load font '" << _family << "'" << endl <<
116 "Falling back to default '" << _fallback_font << "'" << endl;
117
118 if ((_valid = createXFont(_fallback_font)))
119 return; // success
120 }
121
122 cerr << "BFont::BFont(): couldn't load font '" << _family << "'" << endl <<
123 "Giving up!" << endl;
124 return; // failure
125 }
126
127
128 bool BFont::createXFont(const std::string &xlfd) {
129 /*
130 Even though this is only used for font sets (multibyte), it is still parsed
131 out so that the bold/italic/etc information is still available from the
132 class when using non-multibyte.
133
134 This is where _simplename, _bold, _italic, and _size are initialized, since
135 they are not initialized in the constructor. This needs to occur before
136 calling any Xlfd-building functions.
137 */
138 if (! parseXlfd(xlfd))
139 return False;
140
141 if (i18n.multibyte()) {
142 char **missing, *def = "-";
143 int nmissing;
144
145 _fontset = XCreateFontSet(_display, buildMultibyteXlfd().c_str(),
146 &missing, &nmissing, &def);
147 if (nmissing) XFreeStringList(missing);
148 if (_fontset)
149 _fontset_extents = XExtentsOfFontSet(_fontset);
150 else
151 return False;
152
153 assert(_fontset_extents);
154 }
155
156 _font = XLoadQueryFont(_display, xlfd.c_str());
157 if (! _font)
158 return False;
159 return True;
160 }
161
162
163 BFont::~BFont(void) {
164 #ifdef XFT
165 if (_xftfont)
166 XftFontClose(_display, _xftfont);
167 #endif // XFT
168
169 if (i18n.multibyte() && _fontset)
170 XFreeFontSet(_display, _fontset);
171 if (_font)
172 XFreeFont(_display, _font);
173 }
174
175
176 /*
177 * Takes _family, _size, _bold, _italic, etc and builds them into a full XLFD.
178 */
179 string BFont::buildXlfd(void) const {
180 if (_simplename)
181 return _family;
182
183 string weight = _bold ? "bold" : "medium";
184 string slant = _italic ? "i" : "r";
185 string sizestr= _size ? itostring(_size * 10) : "*";
186
187 return "-*-" + _family + "-" + weight + "-" + slant + "-*-*-*-" + sizestr +
188 "-*-*-*-*-*-*";
189 }
190
191
192 /*
193 * Takes _family, _size, _bold, _italic, etc and builds them into a full XLFD.
194 */
195 string BFont::buildMultibyteXlfd(void) const {
196 string weight = _bold ? "bold" : "medium";
197 string slant = _italic ? "i" : "r";
198 string sizestr= _size ? itostring(_size) : "*";
199
200 return _family + ','
201 + "-*-*-" + weight + "-" + slant + "-*-*-*-" + sizestr +
202 "-*-*-*-*-*-*" + ','
203 + "-*-*-*-*-*-*-*-" + sizestr + "-*-*-*-*-*-*" + ',' +
204 + "*";
205 }
206
207
208 /*
209 * Takes a full X font name and parses it out so we know if we're bold, our
210 * size, etc.
211 */
212 bool BFont::parseXlfd(const string &xlfd) {
213 if (xlfd.empty() || xlfd[0] != '-') {
214 _family = xlfd;
215 _simplename = True;
216 _bold = False;
217 _italic = False;
218 _size = 0;
219 } else {
220 _simplename = False;
221 string weight,
222 slant,
223 sizestr;
224 int i = 0;
225
226 string::const_iterator it = xlfd.begin(), end = xlfd.end();
227 while(1) {
228 string::const_iterator tmp = it; // current string.begin()
229 it = std::find(tmp, end, '-'); // look for comma between tmp and end
230 if (i == 2) _family = string(tmp, it); // s[tmp:it]
231 if (i == 3) weight = string(tmp, it);
232 if (i == 4) slant = string(tmp, it);
233 if (i == 7 && string(tmp, it) != "*") sizestr = string(tmp, it);
234 if (sizestr.empty() &&
235 i == 8 && string(tmp, it) != "*") sizestr = string(tmp, it);
236 if (it == end || i >= 8)
237 break;
238 ++it;
239 ++i;
240 }
241 if (i < 3) // no name even! can't parse that
242 return False;
243 _bold = weight == "bold" || weight == "demibold";
244 _italic = slant == "i" || slant == "o";
245 _size = atoi(sizestr.c_str()) / 10;
246 }
247
248 // min/max size restrictions for sanity, but 0 is the font's "default size"
249 if (_size && _size < 3)
250 _size = 3;
251 else if (_size > 97)
252 _size = 97;
253
254 return True;
255 }
256
257
258 void BFont::drawString(Drawable d, int x, int y, const BColor &color,
259 const string &string) const {
260 assert(_valid);
261
262 #ifdef XFT
263 if (_xftfont) {
264 XftDraw *draw = XftDrawCreate(_display, d, _screen->getVisual(),
265 _screen->getColormap());
266 assert(draw);
267
268 if (_shadow) {
269 XftColor c;
270 c.color.red = 0;
271 c.color.green = 0;
272 c.color.blue = 0;
273 c.color.alpha = _tint | _tint << 8; // transparent shadow
274 c.pixel = BlackPixel(_display, _screen->getScreenNumber());
275
276 #ifdef XFT_UTF8
277 XftDrawStringUtf8(
278 #else
279 XftDrawString8(
280 #endif
281 draw, &c, _xftfont, x + _offset,
282 _xftfont->ascent + y + _offset, (XftChar8 *) string.c_str(),
283 string.size());
284 }
285
286 XftColor c;
287 c.color.red = color.red() | color.red() << 8;
288 c.color.green = color.green() | color.green() << 8;
289 c.color.blue = color.blue() | color.blue() << 8;
290 c.pixel = color.pixel();
291 c.color.alpha = 0xff | 0xff << 8; // no transparency in BColor yet
292
293 #ifdef XFT_UTF8
294 XftDrawStringUtf8(
295 #else
296 XftDrawString8(
297 #endif
298 draw, &c, _xftfont, x, _xftfont->ascent + y,
299 (XftChar8 *) string.c_str(), string.size());
300
301 XftDrawDestroy(draw);
302 return;
303 }
304 #endif // XFT
305
306 BPen pen(color, _font);
307
308 if (i18n.multibyte())
309 XmbDrawString(_display, d, _fontset, pen.gc(),
310 x, y - _fontset_extents->max_ink_extent.y,
311 string.c_str(), string.size());
312 else
313 XDrawString(_display, d, pen.gc(),
314 x, _font->ascent + y,
315 string.c_str(), string.size());
316 }
317
318
319 unsigned int BFont::measureString(const string &string) const {
320 assert(_valid);
321
322 #ifdef XFT
323 if (_xftfont) {
324 XGlyphInfo info;
325
326 #ifdef XFT_UTF8
327 XftTextExtentsUtf8(
328 #else
329 XftTextExtents8(
330 #endif
331 _display, _xftfont, (XftChar8 *) string.c_str(),
332 string.size(), &info);
333
334 return info.xOff + (_shadow ? 1 : 0);
335 }
336 #endif // XFT
337
338 if (i18n.multibyte()) {
339 XRectangle ink, logical;
340 XmbTextExtents(_fontset, string.c_str(), string.size(), &ink, &logical);
341 return logical.width;
342 } else {
343 return XTextWidth(_font, string.c_str(), string.size());
344 }
345 }
346
347
348 unsigned int BFont::height(void) const {
349 assert(_valid);
350
351 #ifdef XFT
352 if (_xftfont)
353 return _xftfont->height + (_shadow ? 1 : 0);
354 #endif // XFT
355
356 if (i18n.multibyte())
357 return _fontset_extents->max_ink_extent.height;
358 else
359 return _font->ascent + _font->descent;
360 }
361
362
363 unsigned int BFont::maxCharWidth(void) const {
364 assert(_valid);
365
366 #ifdef XFT
367 if (_xftfont)
368 return _xftfont->max_advance_width;
369 #endif // XFT
370
371 if (i18n.multibyte())
372 return _fontset_extents->max_logical_extent.width;
373 else
374 return _font->max_bounds.rbearing - _font->min_bounds.lbearing;
375 }
This page took 0.04732 seconds and 3 git commands to generate.