fixed endless recursion for loading of default font
[wxWidgets.git] / src / unix / fontutil.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: unix/fontutil.cpp
3 // Purpose: Font helper functions for X11 (GDK/X)
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 05.11.99
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "fontutil.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #endif // PCH
33
34 #ifdef __X__
35 #include <X11/Xlib.h>
36
37 #include "wx/utils.h" // for wxGetDisplay()
38 #elif defined(__WXGTK__)
39 #include "gdk/gdk.h"
40 #endif
41
42 #include "wx/fontutil.h"
43 #include "wx/fontmap.h"
44 #include "wx/tokenzr.h"
45
46 // ----------------------------------------------------------------------------
47 // private functions
48 // ----------------------------------------------------------------------------
49
50 // define the functions to create and destroy native fonts for this toolkit
51 #ifdef __X__
52 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
53 {
54 return XLoadQueryFont((Display *)wxGetDisplay(), fontSpec);
55 }
56
57 static inline void wxFreeFont(wxNativeFont font)
58 {
59 XFreeFont((Display *)wxGetDisplay(), (XFontStruct *)font);
60 }
61 #elif defined(__WXGTK__)
62 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
63 {
64 wxNativeFont font = gdk_font_load( wxConvertWX2MB(fontSpec) );
65 if(fontSpec == "-*-*-*-*-*-*-*-*-*-*-*-*-*-*")
66 {
67 if(font == NULL)
68 font = gdk_font_load (wxConvertWX2MB("-*-*-*-*-*-*-*-*-75-*-*-*-*-*"));
69 if(font == NULL)
70 font = gdk_font_load (wxConvertWX2MB("-*-*-*-*-*-*-*-*-100-*-*-*-*-*"));
71 if(font == NULL)
72 font = gdk_font_load (wxConvertWX2MB("-*-fixed-*-*-*-*-*-*-*-*-*-*-*-*"));
73 }
74 return font;
75 }
76
77 static inline void wxFreeFont(wxNativeFont font)
78 {
79 gdk_font_unref(font);
80 }
81 #else
82 #error "Unknown GUI toolkit"
83 #endif
84
85 static bool wxTestFontSpec(const wxString& fontspec);
86
87 static wxNativeFont wxLoadQueryFont(int pointSize,
88 int family,
89 int style,
90 int weight,
91 bool underlined,
92 const wxString& facename,
93 const wxString& xregistry,
94 const wxString& xencoding);
95
96 // ============================================================================
97 // implementation
98 // ============================================================================
99
100 // ----------------------------------------------------------------------------
101 // wxNativeEncodingInfo
102 // ----------------------------------------------------------------------------
103
104 // convert to/from the string representation: format is
105 // registry-encoding[-facename]
106 bool wxNativeEncodingInfo::FromString(const wxString& s)
107 {
108 wxStringTokenizer tokenizer(s, _T("-"));
109
110 xregistry = tokenizer.GetNextToken();
111 if ( !xregistry )
112 return FALSE;
113
114 xencoding = tokenizer.GetNextToken();
115 if ( !xencoding )
116 return FALSE;
117
118 // ok even if empty
119 facename = tokenizer.GetNextToken();
120
121 return TRUE;
122 }
123
124 wxString wxNativeEncodingInfo::ToString() const
125 {
126 wxString s;
127 s << xregistry << _T('-') << xencoding;
128 if ( !!facename )
129 {
130 s << _T('-') << facename;
131 }
132
133 return s;
134 }
135
136 // ----------------------------------------------------------------------------
137 // common functions
138 // ----------------------------------------------------------------------------
139
140 bool wxGetNativeFontEncoding(wxFontEncoding encoding,
141 wxNativeEncodingInfo *info)
142 {
143 wxCHECK_MSG( info, FALSE, _T("bad pointer in wxGetNativeFontEncoding") );
144
145 if ( encoding == wxFONTENCODING_DEFAULT )
146 {
147 encoding = wxFont::GetDefaultEncoding();
148 }
149
150 switch ( encoding )
151 {
152 case wxFONTENCODING_ISO8859_1:
153 case wxFONTENCODING_ISO8859_2:
154 case wxFONTENCODING_ISO8859_3:
155 case wxFONTENCODING_ISO8859_4:
156 case wxFONTENCODING_ISO8859_5:
157 case wxFONTENCODING_ISO8859_6:
158 case wxFONTENCODING_ISO8859_7:
159 case wxFONTENCODING_ISO8859_8:
160 case wxFONTENCODING_ISO8859_9:
161 case wxFONTENCODING_ISO8859_10:
162 case wxFONTENCODING_ISO8859_11:
163 case wxFONTENCODING_ISO8859_13:
164 case wxFONTENCODING_ISO8859_14:
165 case wxFONTENCODING_ISO8859_15:
166 {
167 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
168 info->xregistry = wxT("iso8859");
169 info->xencoding.Printf(wxT("%d"), cp);
170 }
171 break;
172
173 case wxFONTENCODING_KOI8:
174 info->xregistry = wxT("koi8");
175
176 // we don't make distinction between koi8-r and koi8-u (so far)
177 info->xencoding = wxT("*");
178 break;
179
180 case wxFONTENCODING_CP1250:
181 case wxFONTENCODING_CP1251:
182 case wxFONTENCODING_CP1252:
183 case wxFONTENCODING_CP1253:
184 case wxFONTENCODING_CP1254:
185 case wxFONTENCODING_CP1255:
186 case wxFONTENCODING_CP1256:
187 case wxFONTENCODING_CP1257:
188 {
189 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
190 info->xregistry = wxT("microsoft");
191 info->xencoding.Printf(wxT("cp%d"), cp);
192 }
193 break;
194
195 case wxFONTENCODING_SYSTEM:
196 info->xregistry =
197 info->xencoding = wxT("*");
198 break;
199
200 default:
201 // don't know how to translate this encoding into X fontspec
202 return FALSE;
203 }
204
205 return TRUE;
206 }
207
208 bool wxTestFontEncoding(const wxNativeEncodingInfo& info)
209 {
210 wxString fontspec;
211 fontspec.Printf(_T("-*-%s-*-*-*-*-*-*-*-*-*-*-%s-%s"),
212 !info.facename ? _T("*") : info.facename.c_str(),
213 info.xregistry.c_str(),
214 info.xencoding.c_str());
215
216 return wxTestFontSpec(fontspec);
217 }
218
219 // ----------------------------------------------------------------------------
220 // X-specific functions
221 // ----------------------------------------------------------------------------
222
223 wxNativeFont wxLoadQueryNearestFont(int pointSize,
224 int family,
225 int style,
226 int weight,
227 bool underlined,
228 const wxString &facename,
229 wxFontEncoding encoding)
230 {
231 // first determine the encoding - if the font doesn't exist at all in this
232 // encoding, it's useless to do all other approximations (i.e. size,
233 // family &c don't matter much)
234 wxNativeEncodingInfo info;
235 if (encoding == wxFONTENCODING_SYSTEM)
236 {
237 // This will always work so we don't test to save time
238 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
239 }
240 else
241 {
242 if ( !wxGetNativeFontEncoding(encoding, &info) ||
243 !wxTestFontEncoding(info) )
244 {
245 if ( !wxTheFontMapper->GetAltForEncoding(encoding, &info) )
246 {
247 // unspported encoding - replace it with the default
248 //
249 // NB: we can't just return 0 from here because wxGTK code doesn't
250 // check for it (i.e. it supposes that we'll always succeed),
251 // so it would provoke a crash
252 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
253 }
254 }
255 }
256
257 // OK, we have the correct xregistry/xencoding in info structure
258
259 wxNativeFont font = wxLoadQueryFont( pointSize, family, style, weight,
260 underlined, facename,
261 info.xregistry, info.xencoding );
262
263 if ( !font )
264 {
265 // search up and down by stepsize 10
266 int max_size = pointSize + 20 * (1 + (pointSize/180));
267 int min_size = pointSize - 20 * (1 + (pointSize/180));
268
269 int i;
270
271 // Search for smaller size (approx.)
272 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
273 {
274 font = wxLoadQueryFont(i, family, style, weight, underlined,
275 facename, info.xregistry, info.xencoding);
276 }
277
278 // Search for larger size (approx.)
279 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
280 {
281 font = wxLoadQueryFont(i, family, style, weight, underlined,
282 facename, info.xregistry, info.xencoding);
283 }
284
285 // Try default family
286 if ( !font && family != wxDEFAULT )
287 {
288 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
289 underlined, facename,
290 info.xregistry, info.xencoding );
291 }
292
293 // Bogus font I
294 if ( !font )
295 {
296 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
297 underlined, facename,
298 info.xregistry, info.xencoding);
299 }
300
301 // Bogus font II
302 if ( !font )
303 {
304 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
305 underlined, wxEmptyString,
306 info.xregistry, info.xencoding);
307 }
308 }
309
310 return font;
311 }
312
313 // ----------------------------------------------------------------------------
314 // private functions
315 // ----------------------------------------------------------------------------
316
317 // returns TRUE if there are any fonts matching this font spec
318 static bool wxTestFontSpec(const wxString& fontspec)
319 {
320 wxNativeFont test = wxLoadFont(fontspec);
321 if ( test )
322 {
323 wxFreeFont(test);
324
325 return TRUE;
326 }
327 else
328 {
329 return FALSE;
330 }
331 }
332
333 static wxNativeFont wxLoadQueryFont(int pointSize,
334 int family,
335 int style,
336 int weight,
337 bool WXUNUSED(underlined),
338 const wxString& facename,
339 const wxString& xregistry,
340 const wxString& xencoding)
341 {
342 wxString xfamily;
343 switch (family)
344 {
345 case wxDECORATIVE: xfamily = wxT("lucida"); break;
346 case wxROMAN: xfamily = wxT("times"); break;
347 case wxMODERN: xfamily = wxT("courier"); break;
348 case wxSWISS: xfamily = wxT("helvetica"); break;
349 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
350 case wxSCRIPT: xfamily = wxT("utopia"); break;
351 default: xfamily = wxT("*");
352 }
353
354 wxString fontSpec;
355 if (!facename.IsEmpty())
356 {
357 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
358 facename.c_str());
359
360 if ( wxTestFontSpec(fontSpec) )
361 {
362 xfamily = facename;
363 }
364 //else: no such family, use default one instead
365 }
366
367 wxString xstyle;
368 switch (style)
369 {
370 case wxITALIC: xstyle = wxT("i"); break;
371 case wxSLANT: xstyle = wxT("o"); break;
372 case wxNORMAL: xstyle = wxT("r"); break;
373 default: xstyle = wxT("*"); break;
374 }
375
376 wxString xweight;
377 switch (weight)
378 {
379 case wxBOLD:
380 {
381 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
382 xfamily.c_str());
383 if ( wxTestFontSpec(fontSpec) )
384 {
385 xweight = wxT("bold");
386 break;
387 }
388 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
389 xfamily.c_str());
390 if ( wxTestFontSpec(fontSpec) )
391 {
392 xweight = wxT("heavy");
393 break;
394 }
395 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
396 xfamily.c_str());
397 if ( wxTestFontSpec(fontSpec) )
398 {
399 xweight = wxT("extrabold");
400 break;
401 }
402 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
403 xfamily.c_str());
404 if ( wxTestFontSpec(fontSpec) )
405 {
406 xweight = wxT("demibold");
407 break;
408 }
409 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
410 xfamily.c_str());
411 if ( wxTestFontSpec(fontSpec) )
412 {
413 xweight = wxT("black");
414 break;
415 }
416 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
417 xfamily.c_str());
418 if ( wxTestFontSpec(fontSpec) )
419 {
420 xweight = wxT("ultrablack");
421 break;
422 }
423 }
424 break;
425 case wxLIGHT:
426 {
427 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
428 xfamily.c_str());
429 if ( wxTestFontSpec(fontSpec) )
430 {
431 xweight = wxT("light");
432 break;
433 }
434 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
435 xfamily.c_str());
436 if ( wxTestFontSpec(fontSpec) )
437 {
438 xweight = wxT("thin");
439 break;
440 }
441 }
442 break;
443 case wxNORMAL:
444 {
445 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
446 xfamily.c_str());
447 if ( wxTestFontSpec(fontSpec) )
448 {
449 xweight = wxT("medium");
450 break;
451 }
452 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
453 xfamily.c_str());
454 if ( wxTestFontSpec(fontSpec) )
455 {
456 xweight = wxT("normal");
457 break;
458 }
459 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
460 xfamily.c_str());
461 if ( wxTestFontSpec(fontSpec) )
462 {
463 xweight = wxT("regular");
464 break;
465 }
466 xweight = wxT("*");
467 }
468 break;
469 default: xweight = wxT("*"); break;
470 }
471
472 // construct the X font spec from our data
473 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"),
474 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
475 pointSize, xregistry.c_str(), xencoding.c_str());
476
477 return wxLoadFont(fontSpec);
478 }
479