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