]> git.saurik.com Git - wxWidgets.git/blob - src/unix/fontutil.cpp
fix for assert when setting tooltip for a readonly combo
[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 #ifdef __VMS__
36 #pragma message disable nosimpint
37 #endif
38 #include <X11/Xlib.h>
39 #ifdef __VMS__
40 #pragma message enable nosimpint
41 #endif
42
43 #include "wx/utils.h" // for wxGetDisplay()
44 #elif defined(__WXGTK__)
45 #include "gdk/gdk.h"
46 #endif
47
48 #include "wx/fontutil.h"
49 #include "wx/fontmap.h"
50 #include "wx/tokenzr.h"
51 #include "wx/hash.h"
52 #include "wx/module.h"
53
54 // ----------------------------------------------------------------------------
55 // private data
56 // ----------------------------------------------------------------------------
57
58 static wxHashTable *g_fontHash = (wxHashTable*) NULL;
59
60 // ----------------------------------------------------------------------------
61 // private functions
62 // ----------------------------------------------------------------------------
63
64 // define the functions to create and destroy native fonts for this toolkit
65 #ifdef __X__
66 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
67 {
68 return XLoadQueryFont((Display *)wxGetDisplay(), fontSpec);
69 }
70
71 static inline void wxFreeFont(wxNativeFont font)
72 {
73 XFreeFont((Display *)wxGetDisplay(), (XFontStruct *)font);
74 }
75 #elif defined(__WXGTK__)
76 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
77 {
78 return gdk_font_load( wxConvertWX2MB(fontSpec) );
79 }
80
81 static inline void wxFreeFont(wxNativeFont font)
82 {
83 gdk_font_unref(font);
84 }
85 #else
86 #error "Unknown GUI toolkit"
87 #endif
88
89 static bool wxTestFontSpec(const wxString& fontspec);
90
91 static wxNativeFont wxLoadQueryFont(int pointSize,
92 int family,
93 int style,
94 int weight,
95 bool underlined,
96 const wxString& facename,
97 const wxString& xregistry,
98 const wxString& xencoding);
99
100 // ============================================================================
101 // implementation
102 // ============================================================================
103
104 // ----------------------------------------------------------------------------
105 // wxNativeEncodingInfo
106 // ----------------------------------------------------------------------------
107
108 // convert to/from the string representation: format is
109 // encodingid;registry;encoding[;facename]
110 bool wxNativeEncodingInfo::FromString(const wxString& s)
111 {
112 wxStringTokenizer tokenizer(s, _T(";"));
113 // cannot use "-" because it may be part of encoding name
114
115 wxString encid = tokenizer.GetNextToken();
116 long enc;
117 if ( !encid.ToLong(&enc) )
118 return FALSE;
119 encoding = (wxFontEncoding)enc;
120
121 xregistry = tokenizer.GetNextToken();
122 if ( !xregistry )
123 return FALSE;
124
125 xencoding = tokenizer.GetNextToken();
126 if ( !xencoding )
127 return FALSE;
128
129 // ok even if empty
130 facename = tokenizer.GetNextToken();
131
132 return TRUE;
133 }
134
135 wxString wxNativeEncodingInfo::ToString() const
136 {
137 wxString s;
138 s << (long)encoding << _T(';') << xregistry << _T(';') << xencoding;
139 if ( !!facename )
140 {
141 s << _T(';') << facename;
142 }
143
144 return s;
145 }
146
147 // ----------------------------------------------------------------------------
148 // common functions
149 // ----------------------------------------------------------------------------
150
151 bool wxGetNativeFontEncoding(wxFontEncoding encoding,
152 wxNativeEncodingInfo *info)
153 {
154 wxCHECK_MSG( info, FALSE, _T("bad pointer in wxGetNativeFontEncoding") );
155
156 if ( encoding == wxFONTENCODING_DEFAULT )
157 {
158 encoding = wxFont::GetDefaultEncoding();
159 }
160
161 switch ( encoding )
162 {
163 case wxFONTENCODING_ISO8859_1:
164 case wxFONTENCODING_ISO8859_2:
165 case wxFONTENCODING_ISO8859_3:
166 case wxFONTENCODING_ISO8859_4:
167 case wxFONTENCODING_ISO8859_5:
168 case wxFONTENCODING_ISO8859_6:
169 case wxFONTENCODING_ISO8859_7:
170 case wxFONTENCODING_ISO8859_8:
171 case wxFONTENCODING_ISO8859_9:
172 case wxFONTENCODING_ISO8859_10:
173 case wxFONTENCODING_ISO8859_11:
174 case wxFONTENCODING_ISO8859_12:
175 case wxFONTENCODING_ISO8859_13:
176 case wxFONTENCODING_ISO8859_14:
177 case wxFONTENCODING_ISO8859_15:
178 {
179 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
180 info->xregistry = wxT("iso8859");
181 info->xencoding.Printf(wxT("%d"), cp);
182 }
183 break;
184
185 case wxFONTENCODING_KOI8:
186 info->xregistry = wxT("koi8");
187
188 // we don't make distinction between koi8-r and koi8-u (so far)
189 info->xencoding = wxT("*");
190 break;
191
192 case wxFONTENCODING_CP1250:
193 case wxFONTENCODING_CP1251:
194 case wxFONTENCODING_CP1252:
195 case wxFONTENCODING_CP1253:
196 case wxFONTENCODING_CP1254:
197 case wxFONTENCODING_CP1255:
198 case wxFONTENCODING_CP1256:
199 case wxFONTENCODING_CP1257:
200 {
201 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
202 info->xregistry = wxT("microsoft");
203 info->xencoding.Printf(wxT("cp%d"), cp);
204 }
205 break;
206
207 case wxFONTENCODING_SYSTEM:
208 info->xregistry =
209 info->xencoding = wxT("*");
210 break;
211
212 default:
213 // don't know how to translate this encoding into X fontspec
214 return FALSE;
215 }
216
217 info->encoding = encoding;
218
219 return TRUE;
220 }
221
222 bool wxTestFontEncoding(const wxNativeEncodingInfo& info)
223 {
224 wxString fontspec;
225 fontspec.Printf(_T("-*-%s-*-*-*-*-*-*-*-*-*-*-%s-%s"),
226 !info.facename ? _T("*") : info.facename.c_str(),
227 info.xregistry.c_str(),
228 info.xencoding.c_str());
229
230 return wxTestFontSpec(fontspec);
231 }
232
233 // ----------------------------------------------------------------------------
234 // X-specific functions
235 // ----------------------------------------------------------------------------
236
237 wxNativeFont wxLoadQueryNearestFont(int pointSize,
238 int family,
239 int style,
240 int weight,
241 bool underlined,
242 const wxString &facename,
243 wxFontEncoding encoding)
244 {
245 if ( encoding == wxFONTENCODING_DEFAULT )
246 {
247 encoding = wxFont::GetDefaultEncoding();
248 }
249
250 // first determine the encoding - if the font doesn't exist at all in this
251 // encoding, it's useless to do all other approximations (i.e. size,
252 // family &c don't matter much)
253 wxNativeEncodingInfo info;
254 if ( encoding == wxFONTENCODING_SYSTEM )
255 {
256 // This will always work so we don't test to save time
257 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
258 }
259 else
260 {
261 if ( !wxGetNativeFontEncoding(encoding, &info) ||
262 !wxTestFontEncoding(info) )
263 {
264 if ( !wxTheFontMapper->GetAltForEncoding(encoding, &info) )
265 {
266 // unspported encoding - replace it with the default
267 //
268 // NB: we can't just return 0 from here because wxGTK code doesn't
269 // check for it (i.e. it supposes that we'll always succeed),
270 // so it would provoke a crash
271 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
272 }
273 }
274 }
275
276 // OK, we have the correct xregistry/xencoding in info structure
277 wxNativeFont font = wxLoadQueryFont( pointSize, family, style, weight,
278 underlined, facename,
279 info.xregistry, info.xencoding );
280
281 if ( !font )
282 {
283 // search up and down by stepsize 10
284 int max_size = pointSize + 20 * (1 + (pointSize/180));
285 int min_size = pointSize - 20 * (1 + (pointSize/180));
286
287 int i;
288
289 // Search for smaller size (approx.)
290 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
291 {
292 font = wxLoadQueryFont(i, family, style, weight, underlined,
293 facename, info.xregistry, info.xencoding);
294 }
295
296 // Search for larger size (approx.)
297 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
298 {
299 font = wxLoadQueryFont(i, family, style, weight, underlined,
300 facename, info.xregistry, info.xencoding);
301 }
302
303 // Try default family
304 if ( !font && family != wxDEFAULT )
305 {
306 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
307 underlined, facename,
308 info.xregistry, info.xencoding );
309 }
310
311 // Bogus font I
312 if ( !font )
313 {
314 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
315 underlined, facename,
316 info.xregistry, info.xencoding);
317 }
318
319 // Bogus font II
320 if ( !font )
321 {
322 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
323 underlined, wxEmptyString,
324 info.xregistry, info.xencoding);
325 }
326 }
327
328 return font;
329 }
330
331 // ----------------------------------------------------------------------------
332 // private functions
333 // ----------------------------------------------------------------------------
334
335 // returns TRUE if there are any fonts matching this font spec
336 static bool wxTestFontSpec(const wxString& fontspec)
337 {
338 // some X servers will fail to load this font because there are too many
339 // matches so we must test explicitly for this
340 if ( fontspec == _T("-*-*-*-*-*-*-*-*-*-*-*-*-*-*") )
341 {
342 return TRUE;
343 }
344
345 wxNativeFont test = (wxNativeFont) g_fontHash->Get( fontspec );
346 if (test)
347 {
348 // printf( "speed up\n" );
349 return TRUE;
350 }
351
352 test = wxLoadFont(fontspec);
353 g_fontHash->Put( fontspec, (wxObject*) test );
354
355 if ( test )
356 {
357 wxFreeFont(test);
358
359 return TRUE;
360 }
361 else
362 {
363 return FALSE;
364 }
365 }
366
367 static wxNativeFont wxLoadQueryFont(int pointSize,
368 int family,
369 int style,
370 int weight,
371 bool WXUNUSED(underlined),
372 const wxString& facename,
373 const wxString& xregistry,
374 const wxString& xencoding)
375 {
376 wxString xfamily;
377 switch (family)
378 {
379 case wxDECORATIVE: xfamily = wxT("lucida"); break;
380 case wxROMAN: xfamily = wxT("times"); break;
381 case wxMODERN: xfamily = wxT("courier"); break;
382 case wxSWISS: xfamily = wxT("helvetica"); break;
383 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
384 case wxSCRIPT: xfamily = wxT("utopia"); break;
385 default: xfamily = wxT("*");
386 }
387
388 wxString fontSpec;
389 if (!facename.IsEmpty())
390 {
391 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
392 facename.c_str());
393
394 if ( wxTestFontSpec(fontSpec) )
395 {
396 xfamily = facename;
397 }
398 //else: no such family, use default one instead
399 }
400
401 wxString xstyle;
402 switch (style)
403 {
404 case wxSLANT:
405 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
406 xfamily.c_str());
407 if ( wxTestFontSpec(fontSpec) )
408 {
409 xstyle = wxT("o");
410 break;
411 }
412 // fall through - try wxITALIC now
413
414 case wxITALIC:
415 fontSpec.Printf(wxT("-*-%s-*-i-*-*-*-*-*-*-*-*-*-*"),
416 xfamily.c_str());
417 if ( wxTestFontSpec(fontSpec) )
418 {
419 xstyle = wxT("i");
420 }
421 else if ( style == wxITALIC ) // and not wxSLANT
422 {
423 // try wxSLANT
424 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
425 xfamily.c_str());
426 if ( wxTestFontSpec(fontSpec) )
427 {
428 xstyle = wxT("o");
429 }
430 else
431 {
432 // no italic, no slant - leave default
433 xstyle = wxT("*");
434 }
435 }
436 break;
437
438 default:
439 wxFAIL_MSG(_T("unknown font style"));
440 // fall back to normal
441
442 case wxNORMAL:
443 xstyle = wxT("r");
444 break;
445 }
446
447 wxString xweight;
448 switch (weight)
449 {
450 case wxBOLD:
451 {
452 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
453 xfamily.c_str());
454 if ( wxTestFontSpec(fontSpec) )
455 {
456 xweight = wxT("bold");
457 break;
458 }
459 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
460 xfamily.c_str());
461 if ( wxTestFontSpec(fontSpec) )
462 {
463 xweight = wxT("heavy");
464 break;
465 }
466 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
467 xfamily.c_str());
468 if ( wxTestFontSpec(fontSpec) )
469 {
470 xweight = wxT("extrabold");
471 break;
472 }
473 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
474 xfamily.c_str());
475 if ( wxTestFontSpec(fontSpec) )
476 {
477 xweight = wxT("demibold");
478 break;
479 }
480 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
481 xfamily.c_str());
482 if ( wxTestFontSpec(fontSpec) )
483 {
484 xweight = wxT("black");
485 break;
486 }
487 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
488 xfamily.c_str());
489 if ( wxTestFontSpec(fontSpec) )
490 {
491 xweight = wxT("ultrablack");
492 break;
493 }
494 }
495 break;
496 case wxLIGHT:
497 {
498 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
499 xfamily.c_str());
500 if ( wxTestFontSpec(fontSpec) )
501 {
502 xweight = wxT("light");
503 break;
504 }
505 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
506 xfamily.c_str());
507 if ( wxTestFontSpec(fontSpec) )
508 {
509 xweight = wxT("thin");
510 break;
511 }
512 }
513 break;
514 case wxNORMAL:
515 {
516 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
517 xfamily.c_str());
518 if ( wxTestFontSpec(fontSpec) )
519 {
520 xweight = wxT("medium");
521 break;
522 }
523 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
524 xfamily.c_str());
525 if ( wxTestFontSpec(fontSpec) )
526 {
527 xweight = wxT("normal");
528 break;
529 }
530 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
531 xfamily.c_str());
532 if ( wxTestFontSpec(fontSpec) )
533 {
534 xweight = wxT("regular");
535 break;
536 }
537 xweight = wxT("*");
538 }
539 break;
540 default: xweight = wxT("*"); break;
541 }
542
543 // construct the X font spec from our data
544 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"),
545 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
546 pointSize, xregistry.c_str(), xencoding.c_str());
547
548 return wxLoadFont(fontSpec);
549 }
550
551 // ----------------------------------------------------------------------------
552 // wxFontModule
553 // ----------------------------------------------------------------------------
554
555 class wxFontModule : public wxModule
556 {
557 public:
558 bool OnInit();
559 void OnExit();
560
561 private:
562 DECLARE_DYNAMIC_CLASS(wxFontModule)
563 };
564
565 IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
566
567 bool wxFontModule::OnInit()
568 {
569 g_fontHash = new wxHashTable( wxKEY_STRING );
570
571 return TRUE;
572 }
573
574 void wxFontModule::OnExit()
575 {
576 delete g_fontHash;
577
578 g_fontHash = (wxHashTable *)NULL;
579 }