]> Dogcows Code - chaz/openbox/blob - src/Font.cc
merged with 2_1-merged-to-HEAD-2002-09-30
[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, bool antialias) :
52 _display(d),
53 _screen(screen),
54 _family(family),
55 _simplename(False),
56 _size(size),
57 _bold(bold),
58 _italic(italic),
59 _antialias(antialias),
60 _shadow(shadow),
61 _xftfont(0),
62 _font(0),
63 _fontset(0),
64 _fontset_extents(0) {
65 _valid = False;
66
67 _xftfont = XftFontOpen(_display, _screen->getScreenNumber(),
68 XFT_FAMILY, XftTypeString, _family.c_str(),
69 XFT_SIZE, XftTypeInteger, _size,
70 XFT_WEIGHT, XftTypeInteger, (_bold ?
71 XFT_WEIGHT_BOLD :
72 XFT_WEIGHT_MEDIUM),
73 XFT_SLANT, XftTypeInteger, (_italic ?
74 XFT_SLANT_ITALIC :
75 XFT_SLANT_ROMAN),
76 XFT_ANTIALIAS, XftTypeBool, _antialias,
77 0);
78 if (! _xftfont)
79 return; // failure
80
81 _font = XLoadQueryFont(_display, buildXlfd().c_str());
82 if (! _font)
83 return; // failure
84
85 _valid = True;
86 }
87 #endif
88
89
90 BFont::BFont(Display *d, BScreen *screen, const string &xlfd) :
91 _display(d),
92 _screen(screen),
93 #ifdef XFT
94 _antialias(False),
95 _shadow(False),
96 _xftfont(0),
97 #endif // XFT
98 _font(0),
99 _fontset(0),
100 _fontset_extents(0) {
101 string int_xlfd;
102 if (xlfd.empty())
103 int_xlfd = _fallback_font;
104 else
105 int_xlfd = xlfd;
106
107 if ((_valid = createXFont(int_xlfd)))
108 return; // success
109
110 if (int_xlfd != _fallback_font) {
111 // try the fallback
112 cerr << "BFont::BFont(): couldn't load font '" << _family << "'" << endl <<
113 "Falling back to default '" << _fallback_font << "'" << endl;
114
115 if ((_valid = createXFont(_fallback_font)))
116 return; // success
117 }
118
119 cerr << "BFont::BFont(): couldn't load font '" << _family << "'" << endl <<
120 "Giving up!" << endl;
121 return; // failure
122 }
123
124
125 bool BFont::createXFont(const std::string &xlfd) {
126 /*
127 Even though this is only used for font sets (multibyte), it is still parsed
128 out so that the bold/italic/etc information is still available from the
129 class when using non-multibyte.
130
131 This is where _simplename, _bold, _italic, and _size are initialized, since
132 they are not initialized in the constructor. This needs to occur before
133 calling any Xlfd-building functions.
134 */
135 if (! parseXlfd(xlfd))
136 return False;
137
138 if (i18n.multibyte()) {
139 char **missing, *def = "-";
140 int nmissing;
141
142 _fontset = XCreateFontSet(_display, buildMultibyteXlfd().c_str(),
143 &missing, &nmissing, &def);
144 if (nmissing) XFreeStringList(missing);
145 if (_fontset)
146 _fontset_extents = XExtentsOfFontSet(_fontset);
147 else
148 return False;
149
150 assert(_fontset_extents);
151 }
152
153 _font = XLoadQueryFont(_display, xlfd.c_str());
154 if (! _font)
155 return False;
156 return True;
157 }
158
159
160 BFont::~BFont(void) {
161 #ifdef XFT
162 if (_xftfont)
163 XftFontClose(_display, _xftfont);
164 #endif // XFT
165
166 if (i18n.multibyte() && _fontset)
167 XFreeFontSet(_display, _fontset);
168 if (_font)
169 XFreeFont(_display, _font);
170 }
171
172
173 /*
174 * Takes _family, _size, _bold, _italic, etc and builds them into a full XLFD.
175 */
176 string BFont::buildXlfd(void) const {
177 if (_simplename)
178 return _family;
179
180 string weight = _bold ? "bold" : "medium";
181 string slant = _italic ? "i" : "r";
182 string sizestr= _size ? itostring(_size * 10) : "*";
183
184 return "-*-" + _family + "-" + weight + "-" + slant + "-*-*-*-" + sizestr +
185 "-*-*-*-*-*-*";
186 }
187
188
189 /*
190 * Takes _family, _size, _bold, _italic, etc and builds them into a full XLFD.
191 */
192 string BFont::buildMultibyteXlfd(void) const {
193 string weight = _bold ? "bold" : "medium";
194 string slant = _italic ? "i" : "r";
195 string sizestr= _size ? itostring(_size) : "*";
196
197 return _family + ','
198 + "-*-*-" + weight + "-" + slant + "-*-*-*-" + sizestr +
199 "-*-*-*-*-*-*" + ','
200 + "-*-*-*-*-*-*-*-" + sizestr + "-*-*-*-*-*-*" + ',' +
201 + "*";
202 }
203
204
205 /*
206 * Takes a full X font name and parses it out so we know if we're bold, our
207 * size, etc.
208 */
209 bool BFont::parseXlfd(const string &xlfd) {
210 if (xlfd.empty() || xlfd[0] != '-') {
211 _family = xlfd;
212 _simplename = True;
213 _bold = False;
214 _italic = False;
215 _size = 0;
216 } else {
217 _simplename = False;
218 string weight,
219 slant,
220 sizestr;
221 int i = 0;
222
223 string::const_iterator it = xlfd.begin(), end = xlfd.end();
224 while(1) {
225 string::const_iterator tmp = it; // current string.begin()
226 it = std::find(tmp, end, '-'); // look for comma between tmp and end
227 if (i == 2) _family = string(tmp, it); // s[tmp:it]
228 if (i == 3) weight = string(tmp, it);
229 if (i == 4) slant = string(tmp, it);
230 if (i == 7 && string(tmp, it) != "*") sizestr = string(tmp, it);
231 if (sizestr.empty() &&
232 i == 8 && string(tmp, it) != "*") sizestr = string(tmp, it);
233 if (it == end || i >= 8)
234 break;
235 ++it;
236 ++i;
237 }
238 if (i < 3) // no name even! can't parse that
239 return False;
240 _bold = weight == "bold" || weight == "demibold";
241 _italic = slant == "i" || slant == "o";
242 _size = atoi(sizestr.c_str()) / 10;
243 }
244
245 // min/max size restrictions for sanity, but 0 is the font's "default size"
246 if (_size && _size < 3)
247 _size = 3;
248 else if (_size > 97)
249 _size = 97;
250
251 return True;
252 }
253
254
255 void BFont::drawString(Drawable d, int x, int y, const BColor &color,
256 const string &string) const {
257 assert(_valid);
258
259 #ifdef XFT
260 if (_xftfont) {
261 XftDraw *draw = XftDrawCreate(_display, d, _screen->getVisual(),
262 _screen->getColormap());
263 assert(draw);
264
265 if (_shadow) {
266 XftColor c;
267 c.color.red = 0;
268 c.color.green = 0;
269 c.color.blue = 0;
270 c.color.alpha = 0x40 | 0x40 << 8; // transparent shadow
271 c.pixel = BlackPixel(_display, _screen->getScreenNumber());
272
273 #ifdef XFT_UTF8
274 XftDrawStringUtf8(
275 #else
276 XftDrawString8(
277 #endif
278 draw, &c, _xftfont, x + 1, _xftfont->ascent + y + 1,
279 (XftChar8 *) string.c_str(), string.size());
280 }
281
282 XftColor c;
283 c.color.red = color.red() | color.red() << 8;
284 c.color.green = color.green() | color.green() << 8;
285 c.color.blue = color.blue() | color.blue() << 8;
286 c.pixel = color.pixel();
287 c.color.alpha = 0xff | 0xff << 8; // no transparency in BColor yet
288
289 #ifdef XFT_UTF8
290 XftDrawStringUtf8(
291 #else
292 XftDrawString8(
293 #endif
294 draw, &c, _xftfont, x, _xftfont->ascent + y,
295 (XftChar8 *) string.c_str(), string.size());
296
297 XftDrawDestroy(draw);
298 return;
299 }
300 #endif // XFT
301
302 BPen pen(color, _font);
303
304 if (i18n.multibyte())
305 XmbDrawString(_display, d, _fontset, pen.gc(),
306 x, y - _fontset_extents->max_ink_extent.y,
307 string.c_str(), string.size());
308 else
309 XDrawString(_display, d, pen.gc(),
310 x, _font->ascent + y,
311 string.c_str(), string.size());
312 }
313
314
315 unsigned int BFont::measureString(const string &string) const {
316 assert(_valid);
317
318 #ifdef XFT
319 if (_xftfont) {
320 XGlyphInfo info;
321
322 #ifdef XFT_UTF8
323 XftTextExtentsUtf8(
324 #else
325 XftTextExtents8(
326 #endif
327 _display, _xftfont, (XftChar8 *) string.c_str(),
328 string.size(), &info);
329
330 return info.xOff + (_shadow ? 1 : 0);
331 }
332 #endif // XFT
333
334 if (i18n.multibyte()) {
335 XRectangle ink, logical;
336 XmbTextExtents(_fontset, string.c_str(), string.size(), &ink, &logical);
337 return logical.width;
338 } else {
339 return XTextWidth(_font, string.c_str(), string.size());
340 }
341 }
342
343
344 unsigned int BFont::height(void) const {
345 assert(_valid);
346
347 #ifdef XFT
348 if (_xftfont)
349 return _xftfont->height + (_shadow ? 1 : 0);
350 #endif // XFT
351
352 if (i18n.multibyte())
353 return _fontset_extents->max_ink_extent.height;
354 else
355 return _font->ascent + _font->descent;
356 }
357
358
359 unsigned int BFont::maxCharWidth(void) const {
360 assert(_valid);
361
362 #ifdef XFT
363 if (_xftfont)
364 return _xftfont->max_advance_width;
365 #endif // XFT
366
367 if (i18n.multibyte())
368 return _fontset_extents->max_logical_extent.width;
369 else
370 return _font->max_bounds.rbearing - _font->min_bounds.lbearing;
371 }
This page took 0.0467 seconds and 4 git commands to generate.