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