use gdk_fontset_load() instead of gdk_font_load() for better Japanese support (patch...
[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 licence
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 #include "wx/fontutil.h"
35 #include "wx/fontmap.h"
36 #include "wx/tokenzr.h"
37 #include "wx/hash.h"
38 #include "wx/module.h"
39
40 #if wxUSE_PANGO
41
42 #include "pango/pango.h"
43
44 #ifdef __WXGTK20__
45 #include "wx/gtk/private.h"
46 #else
47 #include "wx/x11/private.h"
48 #endif
49
50 // ----------------------------------------------------------------------------
51 // wxNativeFontInfo
52 // ----------------------------------------------------------------------------
53
54 void wxNativeFontInfo::Init()
55 {
56 description = NULL;
57 }
58
59 int wxNativeFontInfo::GetPointSize() const
60 {
61 return pango_font_description_get_size( description ) / PANGO_SCALE;
62 }
63
64 wxFontStyle wxNativeFontInfo::GetStyle() const
65 {
66 wxFontStyle m_style = wxFONTSTYLE_NORMAL;
67
68 switch (pango_font_description_get_style( description ))
69 {
70 case PANGO_STYLE_NORMAL:
71 m_style = wxFONTSTYLE_NORMAL;
72 break;
73 case PANGO_STYLE_ITALIC:
74 m_style = wxFONTSTYLE_ITALIC;
75 break;
76 case PANGO_STYLE_OBLIQUE:
77 m_style = wxFONTSTYLE_SLANT;
78 break;
79 }
80
81 return m_style;
82 }
83
84 wxFontWeight wxNativeFontInfo::GetWeight() const
85 {
86 wxFontWeight m_weight = wxFONTWEIGHT_NORMAL;
87
88 switch (pango_font_description_get_weight( description ))
89 {
90 case PANGO_WEIGHT_ULTRALIGHT:
91 m_weight = wxFONTWEIGHT_LIGHT;
92 break;
93 case PANGO_WEIGHT_LIGHT:
94 m_weight = wxFONTWEIGHT_LIGHT;
95 break;
96 case PANGO_WEIGHT_NORMAL:
97 m_weight = wxFONTWEIGHT_NORMAL;
98 break;
99 case PANGO_WEIGHT_BOLD:
100 m_weight = wxFONTWEIGHT_BOLD;
101 break;
102 case PANGO_WEIGHT_ULTRABOLD:
103 m_weight = wxFONTWEIGHT_BOLD;
104 break;
105 case PANGO_WEIGHT_HEAVY:
106 m_weight = wxFONTWEIGHT_BOLD;
107 break;
108 }
109
110 return m_weight;
111 }
112
113 bool wxNativeFontInfo::GetUnderlined() const
114 {
115 return FALSE;
116 }
117
118 wxString wxNativeFontInfo::GetFaceName() const
119 {
120 wxString tmp = wxGTK_CONV_BACK( pango_font_description_get_family( description ) );
121
122 return tmp;
123 }
124
125 wxFontFamily wxNativeFontInfo::GetFamily() const
126 {
127 return wxFONTFAMILY_SWISS;
128 }
129
130 wxFontEncoding wxNativeFontInfo::GetEncoding() const
131 {
132 return wxFONTENCODING_SYSTEM;
133 }
134
135 bool wxNativeFontInfo::FromString(const wxString& s)
136 {
137 if (description)
138 pango_font_description_free( description );
139
140 description = pango_font_description_from_string( wxGTK_CONV( s ) );
141
142 return TRUE;
143 }
144
145 wxString wxNativeFontInfo::ToString() const
146 {
147 char *str = pango_font_description_to_string( description );
148 wxString tmp = wxGTK_CONV_BACK( str );
149 g_free( str );
150
151 return tmp;
152 }
153
154 bool wxNativeFontInfo::FromUserString(const wxString& s)
155 {
156 return FromString( s );
157 }
158
159 wxString wxNativeFontInfo::ToUserString() const
160 {
161 return ToString();
162 }
163
164 // ----------------------------------------------------------------------------
165 // wxNativeEncodingInfo
166 // ----------------------------------------------------------------------------
167
168 bool wxNativeEncodingInfo::FromString(const wxString& s)
169 {
170 return FALSE;
171 }
172
173 wxString wxNativeEncodingInfo::ToString() const
174 {
175 return wxEmptyString;
176 }
177
178 bool wxTestFontEncoding(const wxNativeEncodingInfo& info)
179 {
180 return TRUE;
181 }
182
183 bool wxGetNativeFontEncoding(wxFontEncoding encoding,
184 wxNativeEncodingInfo *info)
185 {
186 return FALSE;
187 }
188
189 #else // GTK+ 1.x
190
191 #ifdef __X__
192 #ifdef __VMS__
193 #pragma message disable nosimpint
194 #endif
195
196 #include <X11/Xlib.h>
197
198 #ifdef __VMS__
199 #pragma message enable nosimpint
200 #endif
201
202 #include "wx/utils.h" // for wxGetDisplay()
203 #elif defined(__WXGTK__)
204 // we have to declare struct tm to avoid problems with first forward
205 // declaring it in C code (glib.h included from gdk.h does it) and then
206 // defining it when time.h is included from the headers below - this is
207 // known not to work at least with Sun CC 6.01
208 #include <time.h>
209
210 #include <gdk/gdk.h>
211 #endif
212
213
214 // ----------------------------------------------------------------------------
215 // private data
216 // ----------------------------------------------------------------------------
217
218 static wxHashTable *g_fontHash = (wxHashTable*) NULL;
219
220 // ----------------------------------------------------------------------------
221 // private functions
222 // ----------------------------------------------------------------------------
223
224 // define the functions to create and destroy native fonts for this toolkit
225 #ifdef __X__
226 wxNativeFont wxLoadFont(const wxString& fontSpec)
227 {
228 return XLoadQueryFont((Display *)wxGetDisplay(), fontSpec);
229 }
230
231 inline void wxFreeFont(wxNativeFont font)
232 {
233 XFreeFont((Display *)wxGetDisplay(), (XFontStruct *)font);
234 }
235 #elif defined(__WXGTK__)
236 wxNativeFont wxLoadFont(const wxString& fontSpec)
237 {
238 // use gdk_fontset_load() instead of gdk_font_load() because otherwise
239 // we have problems with Japanese (not terribly precise, I know, but
240 // this is all the patch said)
241 return gdk_fontset_load( wxConvertWX2MB(fontSpec) );
242 }
243
244 inline void wxFreeFont(wxNativeFont font)
245 {
246 gdk_font_unref(font);
247 }
248 #else
249 #error "Unknown GUI toolkit"
250 #endif
251
252 static bool wxTestFontSpec(const wxString& fontspec);
253
254 static wxNativeFont wxLoadQueryFont(int pointSize,
255 int family,
256 int style,
257 int weight,
258 bool underlined,
259 const wxString& facename,
260 const wxString& xregistry,
261 const wxString& xencoding,
262 wxString* xFontName);
263
264 // ============================================================================
265 // implementation
266 // ============================================================================
267
268 // ----------------------------------------------------------------------------
269 // wxNativeEncodingInfo
270 // ----------------------------------------------------------------------------
271
272 // convert to/from the string representation: format is
273 // encodingid;registry;encoding[;facename]
274 bool wxNativeEncodingInfo::FromString(const wxString& s)
275 {
276 // use ";", not "-" because it may be part of encoding name
277 wxStringTokenizer tokenizer(s, _T(";"));
278
279 wxString encid = tokenizer.GetNextToken();
280 long enc;
281 if ( !encid.ToLong(&enc) )
282 return FALSE;
283 encoding = (wxFontEncoding)enc;
284
285 xregistry = tokenizer.GetNextToken();
286 if ( !xregistry )
287 return FALSE;
288
289 xencoding = tokenizer.GetNextToken();
290 if ( !xencoding )
291 return FALSE;
292
293 // ok even if empty
294 facename = tokenizer.GetNextToken();
295
296 return TRUE;
297 }
298
299 wxString wxNativeEncodingInfo::ToString() const
300 {
301 wxString s;
302 s << (long)encoding << _T(';') << xregistry << _T(';') << xencoding;
303 if ( !!facename )
304 {
305 s << _T(';') << facename;
306 }
307
308 return s;
309 }
310
311 // ----------------------------------------------------------------------------
312 // wxNativeFontInfo
313 // ----------------------------------------------------------------------------
314
315 void wxNativeFontInfo::Init()
316 {
317 m_isDefault = TRUE;
318 }
319
320 bool wxNativeFontInfo::FromString(const wxString& s)
321 {
322 wxStringTokenizer tokenizer(s, _T(";"));
323
324 // check the version
325 wxString token = tokenizer.GetNextToken();
326 if ( token != _T('0') )
327 return FALSE;
328
329 xFontName = tokenizer.GetNextToken();
330
331 // this should be the end
332 if ( tokenizer.HasMoreTokens() )
333 return FALSE;
334
335 return FromXFontName(xFontName);
336 }
337
338 wxString wxNativeFontInfo::ToString() const
339 {
340 // 0 is the version
341 return wxString::Format(_T("%d;%s"), 0, GetXFontName().c_str());
342 }
343
344 bool wxNativeFontInfo::FromUserString(const wxString& s)
345 {
346 return FromXFontName(s);
347 }
348
349 wxString wxNativeFontInfo::ToUserString() const
350 {
351 return GetXFontName();
352 }
353
354 bool wxNativeFontInfo::HasElements() const
355 {
356 // we suppose that the foundry is never empty, so if it is it means that we
357 // had never parsed the XLFD
358 return !fontElements[0].empty();
359 }
360
361 wxString wxNativeFontInfo::GetXFontComponent(wxXLFDField field) const
362 {
363 wxCHECK_MSG( field < wxXLFD_MAX, _T(""), _T("invalid XLFD field") );
364
365 if ( !HasElements() )
366 {
367 // const_cast
368 if ( !((wxNativeFontInfo *)this)->FromXFontName(xFontName) )
369 return _T("");
370 }
371
372 return fontElements[field];
373 }
374
375 bool wxNativeFontInfo::FromXFontName(const wxString& fontname)
376 {
377 // TODO: we should be able to handle the font aliases here, but how?
378 wxStringTokenizer tokenizer(fontname, _T("-"));
379
380 // skip the leading, usually empty field (font name registry)
381 if ( !tokenizer.HasMoreTokens() )
382 return FALSE;
383
384 (void)tokenizer.GetNextToken();
385
386 for ( size_t n = 0; n < WXSIZEOF(fontElements); n++ )
387 {
388 if ( !tokenizer.HasMoreTokens() )
389 {
390 // not enough elements in the XLFD - or maybe an alias
391 return FALSE;
392 }
393
394 fontElements[n] = tokenizer.GetNextToken();
395 }
396
397 // this should be all
398 if ( tokenizer.HasMoreTokens() )
399 return FALSE;
400
401 // we're initialized now
402 m_isDefault = FALSE;
403
404 return TRUE;
405 }
406
407 wxString wxNativeFontInfo::GetXFontName() const
408 {
409 if ( xFontName.empty() )
410 {
411 for ( size_t n = 0; n < WXSIZEOF(fontElements); n++ )
412 {
413 // replace the non specified elements with '*' except for the
414 // additional style which is usually just omitted
415 wxString elt = fontElements[n];
416 if ( elt.empty() && n != wxXLFD_ADDSTYLE )
417 {
418 elt = _T('*');
419 }
420
421 // const_cast
422 ((wxNativeFontInfo *)this)->xFontName << _T('-') << elt;
423 }
424 }
425
426 return xFontName;
427 }
428
429 void
430 wxNativeFontInfo::SetXFontComponent(wxXLFDField field, const wxString& value)
431 {
432 wxCHECK_RET( field < wxXLFD_MAX, _T("invalid XLFD field") );
433
434 // this class should be initialized with a valid font spec first and only
435 // then the fields may be modified!
436 wxASSERT_MSG( !IsDefault(), _T("can't modify an uninitialized XLFD") );
437
438 if ( !HasElements() )
439 {
440 // const_cast
441 if ( !((wxNativeFontInfo *)this)->FromXFontName(xFontName) )
442 {
443 wxFAIL_MSG( _T("can't set font element for invalid XLFD") );
444
445 return;
446 }
447 }
448
449 fontElements[field] = value;
450
451 // invalidate the XFLD, it doesn't correspond to the font elements any more
452 xFontName.clear();
453 }
454
455 void wxNativeFontInfo::SetXFontName(const wxString& xFontName_)
456 {
457 // invalidate the font elements, GetXFontComponent() will reparse the XLFD
458 fontElements[0].clear();
459
460 xFontName = xFontName_;
461
462 m_isDefault = FALSE;
463 }
464
465 int wxNativeFontInfo::GetPointSize() const
466 {
467 const wxString s = GetXFontComponent(wxXLFD_POINTSIZE);
468
469 // return -1 to indicate that the size is unknown
470 long l;
471 return s.ToLong(&l) ? l : -1;
472 }
473
474 wxFontStyle wxNativeFontInfo::GetStyle() const
475 {
476 const wxString s = GetXFontComponent(wxXLFD_SLANT);
477
478 if ( s.length() != 1 )
479 {
480 // it is really unknown but we don't have any way to return it from
481 // here
482 return wxFONTSTYLE_NORMAL;
483 }
484
485 switch ( s[0] )
486 {
487 default:
488 // again, unknown but consider normal by default
489
490 case _T('r'):
491 return wxFONTSTYLE_NORMAL;
492
493 case _T('i'):
494 return wxFONTSTYLE_ITALIC;
495
496 case _T('o'):
497 return wxFONTSTYLE_SLANT;
498 }
499 }
500
501 wxFontWeight wxNativeFontInfo::GetWeight() const
502 {
503 const wxString s = GetXFontComponent(wxXLFD_WEIGHT).MakeLower();
504 if ( s.find(_T("bold")) != wxString::npos || s == _T("black") )
505 return wxFONTWEIGHT_BOLD;
506 else if ( s == _T("light") )
507 return wxFONTWEIGHT_LIGHT;
508
509 return wxFONTWEIGHT_NORMAL;
510 }
511
512 bool wxNativeFontInfo::GetUnderlined() const
513 {
514 // X fonts are never underlined
515 return FALSE;
516 }
517
518 wxString wxNativeFontInfo::GetFaceName() const
519 {
520 // wxWindows facename probably more accurately corresponds to X family
521 return GetXFontComponent(wxXLFD_FAMILY);
522 }
523
524 wxFontFamily wxNativeFontInfo::GetFamily() const
525 {
526 // and wxWindows family -- to X foundry, but we have to translate it to
527 // wxFontFamily somehow...
528 wxFAIL_MSG(_T("not implemented")); // GetXFontComponent(wxXLFD_FOUNDRY);
529
530 return wxFONTFAMILY_DEFAULT;
531 }
532
533 wxFontEncoding wxNativeFontInfo::GetEncoding() const
534 {
535 // we already have the code for this but need to refactor it first
536 wxFAIL_MSG( _T("not implemented") );
537
538 return wxFONTENCODING_MAX;
539 }
540
541 void wxNativeFontInfo::SetPointSize(int pointsize)
542 {
543 SetXFontComponent(wxXLFD_POINTSIZE, wxString::Format(_T("%d"), pointsize));
544 }
545
546 void wxNativeFontInfo::SetStyle(wxFontStyle style)
547 {
548 wxString s;
549 switch ( style )
550 {
551 case wxFONTSTYLE_ITALIC:
552 s = _T('i');
553 break;
554
555 case wxFONTSTYLE_SLANT:
556 s = _T('o');
557 break;
558
559 case wxFONTSTYLE_NORMAL:
560 s = _T('r');
561
562 default:
563 wxFAIL_MSG( _T("unknown wxFontStyle in wxNativeFontInfo::SetStyle") );
564 return;
565 }
566
567 SetXFontComponent(wxXLFD_SLANT, s);
568 }
569
570 void wxNativeFontInfo::SetWeight(wxFontWeight weight)
571 {
572 wxString s;
573 switch ( weight )
574 {
575 case wxFONTWEIGHT_BOLD:
576 s = _T("bold");
577 break;
578
579 case wxFONTWEIGHT_LIGHT:
580 s = _T("light");
581 break;
582
583 case wxFONTWEIGHT_NORMAL:
584 s = _T("medium");
585 break;
586
587 default:
588 wxFAIL_MSG( _T("unknown wxFontWeight in wxNativeFontInfo::SetWeight") );
589 return;
590 }
591
592 SetXFontComponent(wxXLFD_WEIGHT, s);
593 }
594
595 void wxNativeFontInfo::SetUnderlined(bool WXUNUSED(underlined))
596 {
597 // can't do this under X
598 }
599
600 void wxNativeFontInfo::SetFaceName(wxString facename)
601 {
602 SetXFontComponent(wxXLFD_FAMILY, facename);
603 }
604
605 void wxNativeFontInfo::SetFamily(wxFontFamily family)
606 {
607 // wxFontFamily -> X foundry, anyone?
608 wxFAIL_MSG( _T("not implemented") );
609
610 // SetXFontComponent(wxXLFD_FOUNDRY, ...);
611 }
612
613 void wxNativeFontInfo::SetEncoding(wxFontEncoding encoding)
614 {
615 wxNativeEncodingInfo info;
616 if ( wxGetNativeFontEncoding(encoding, &info) )
617 {
618 SetXFontComponent(wxXLFD_ENCODING, info.xencoding);
619 SetXFontComponent(wxXLFD_REGISTRY, info.xregistry);
620 }
621 }
622
623 // ----------------------------------------------------------------------------
624 // common functions
625 // ----------------------------------------------------------------------------
626
627 bool wxGetNativeFontEncoding(wxFontEncoding encoding,
628 wxNativeEncodingInfo *info)
629 {
630 wxCHECK_MSG( info, FALSE, _T("bad pointer in wxGetNativeFontEncoding") );
631
632 if ( encoding == wxFONTENCODING_DEFAULT )
633 {
634 encoding = wxFont::GetDefaultEncoding();
635 }
636
637 switch ( encoding )
638 {
639 case wxFONTENCODING_ISO8859_1:
640 case wxFONTENCODING_ISO8859_2:
641 case wxFONTENCODING_ISO8859_3:
642 case wxFONTENCODING_ISO8859_4:
643 case wxFONTENCODING_ISO8859_5:
644 case wxFONTENCODING_ISO8859_6:
645 case wxFONTENCODING_ISO8859_7:
646 case wxFONTENCODING_ISO8859_8:
647 case wxFONTENCODING_ISO8859_9:
648 case wxFONTENCODING_ISO8859_10:
649 case wxFONTENCODING_ISO8859_11:
650 case wxFONTENCODING_ISO8859_12:
651 case wxFONTENCODING_ISO8859_13:
652 case wxFONTENCODING_ISO8859_14:
653 case wxFONTENCODING_ISO8859_15:
654 {
655 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
656 info->xregistry = wxT("iso8859");
657 info->xencoding.Printf(wxT("%d"), cp);
658 }
659 break;
660
661 case wxFONTENCODING_UTF8:
662 info->xregistry = wxT("iso10646");
663 info->xencoding = wxT("*");
664 break;
665
666 case wxFONTENCODING_GB2312:
667 info->xregistry = wxT("GB2312"); // or the otherway round?
668 info->xencoding = wxT("*");
669 break;
670
671 case wxFONTENCODING_KOI8:
672 info->xregistry = wxT("koi8");
673
674 // we don't make distinction between koi8-r, koi8-u and koi8-ru (so far)
675 info->xencoding = wxT("*");
676 break;
677
678 case wxFONTENCODING_CP1250:
679 case wxFONTENCODING_CP1251:
680 case wxFONTENCODING_CP1252:
681 case wxFONTENCODING_CP1253:
682 case wxFONTENCODING_CP1254:
683 case wxFONTENCODING_CP1255:
684 case wxFONTENCODING_CP1256:
685 case wxFONTENCODING_CP1257:
686 {
687 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
688 info->xregistry = wxT("microsoft");
689 info->xencoding.Printf(wxT("cp%d"), cp);
690 }
691 break;
692
693 case wxFONTENCODING_SYSTEM:
694 info->xregistry =
695 info->xencoding = wxT("*");
696 break;
697
698 default:
699 // don't know how to translate this encoding into X fontspec
700 return FALSE;
701 }
702
703 info->encoding = encoding;
704
705 return TRUE;
706 }
707
708 bool wxTestFontEncoding(const wxNativeEncodingInfo& info)
709 {
710 wxString fontspec;
711 fontspec.Printf(_T("-*-%s-*-*-*-*-*-*-*-*-*-*-%s-%s"),
712 !info.facename ? _T("*") : info.facename.c_str(),
713 info.xregistry.c_str(),
714 info.xencoding.c_str());
715
716 return wxTestFontSpec(fontspec);
717 }
718
719 // ----------------------------------------------------------------------------
720 // X-specific functions
721 // ----------------------------------------------------------------------------
722
723 wxNativeFont wxLoadQueryNearestFont(int pointSize,
724 int family,
725 int style,
726 int weight,
727 bool underlined,
728 const wxString &facename,
729 wxFontEncoding encoding,
730 wxString* xFontName)
731 {
732 if ( encoding == wxFONTENCODING_DEFAULT )
733 {
734 encoding = wxFont::GetDefaultEncoding();
735 }
736
737 // first determine the encoding - if the font doesn't exist at all in this
738 // encoding, it's useless to do all other approximations (i.e. size,
739 // family &c don't matter much)
740 wxNativeEncodingInfo info;
741 if ( encoding == wxFONTENCODING_SYSTEM )
742 {
743 // This will always work so we don't test to save time
744 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
745 }
746 else
747 {
748 if ( !wxGetNativeFontEncoding(encoding, &info) ||
749 !wxTestFontEncoding(info) )
750 {
751 #if wxUSE_FONTMAP
752 if ( !wxFontMapper::Get()->GetAltForEncoding(encoding, &info) )
753 #endif // wxUSE_FONTMAP
754 {
755 // unspported encoding - replace it with the default
756 //
757 // NB: we can't just return 0 from here because wxGTK code doesn't
758 // check for it (i.e. it supposes that we'll always succeed),
759 // so it would provoke a crash
760 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
761 }
762 }
763 }
764
765 // OK, we have the correct xregistry/xencoding in info structure
766 wxNativeFont font = 0;
767
768 // if we already have the X font name, try to use it
769 if( xFontName && !xFontName->IsEmpty() )
770 {
771 //
772 // Make sure point size is correct for scale factor.
773 //
774 wxStringTokenizer tokenizer(*xFontName, _T("-"), wxTOKEN_RET_DELIMS);
775 wxString newFontName;
776
777 for(int i = 0; i < 8; i++)
778 newFontName += tokenizer.NextToken();
779
780 (void) tokenizer.NextToken();
781
782 newFontName += wxString::Format(wxT("%d-"), pointSize);
783
784 while(tokenizer.HasMoreTokens())
785 newFontName += tokenizer.GetNextToken();
786
787 font = wxLoadFont(newFontName);
788
789 if(font)
790 *xFontName = newFontName;
791 }
792
793 // try to load exactly the font requested first
794 if( !font )
795 {
796 font = wxLoadQueryFont( pointSize, family, style, weight,
797 underlined, facename,
798 info.xregistry, info.xencoding,
799 xFontName );
800 }
801
802 if ( !font )
803 {
804 // search up and down by stepsize 10
805 int max_size = pointSize + 20 * (1 + (pointSize/180));
806 int min_size = pointSize - 20 * (1 + (pointSize/180));
807
808 int i;
809
810 // Search for smaller size (approx.)
811 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
812 {
813 font = wxLoadQueryFont(i, family, style, weight, underlined,
814 facename, info.xregistry, info.xencoding,
815 xFontName);
816 }
817
818 // Search for larger size (approx.)
819 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
820 {
821 font = wxLoadQueryFont(i, family, style, weight, underlined,
822 facename, info.xregistry, info.xencoding,
823 xFontName);
824 }
825
826 // Try default family
827 if ( !font && family != wxDEFAULT )
828 {
829 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
830 underlined, facename,
831 info.xregistry, info.xencoding,
832 xFontName );
833 }
834
835 // ignore size, family, style and weight but try to find font with the
836 // given facename and encoding
837 if ( !font )
838 {
839 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
840 underlined, facename,
841 info.xregistry, info.xencoding,
842 xFontName);
843
844 // ignore family as well
845 if ( !font )
846 {
847 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
848 underlined, wxEmptyString,
849 info.xregistry, info.xencoding,
850 xFontName);
851
852 // if it still failed, try to get the font of any size but
853 // with the requested encoding: this can happen if the
854 // encoding is only available in one size which happens to be
855 // different from 120
856 if ( !font )
857 {
858 font = wxLoadQueryFont(-1, wxDEFAULT, wxNORMAL, wxNORMAL,
859 FALSE, wxEmptyString,
860 info.xregistry, info.xencoding,
861 xFontName);
862
863 // this should never happen as we had tested for it in the
864 // very beginning, but if it does, do return something non
865 // NULL or we'd crash in wxFont code
866 if ( !font )
867 {
868 wxFAIL_MSG( _T("this encoding should be available!") );
869
870 font = wxLoadQueryFont(-1,
871 wxDEFAULT, wxNORMAL, wxNORMAL,
872 FALSE, wxEmptyString,
873 _T("*"), _T("*"),
874 xFontName);
875 }
876 }
877 }
878 }
879 }
880
881 return font;
882 }
883
884 // ----------------------------------------------------------------------------
885 // private functions
886 // ----------------------------------------------------------------------------
887
888 // returns TRUE if there are any fonts matching this font spec
889 static bool wxTestFontSpec(const wxString& fontspec)
890 {
891 // some X servers will fail to load this font because there are too many
892 // matches so we must test explicitly for this
893 if ( fontspec == _T("-*-*-*-*-*-*-*-*-*-*-*-*-*-*") )
894 {
895 return TRUE;
896 }
897
898 wxNativeFont test = (wxNativeFont) g_fontHash->Get( fontspec );
899 if (test)
900 {
901 return TRUE;
902 }
903
904 test = wxLoadFont(fontspec);
905 g_fontHash->Put( fontspec, (wxObject*) test );
906
907 if ( test )
908 {
909 wxFreeFont(test);
910
911 return TRUE;
912 }
913 else
914 {
915 return FALSE;
916 }
917 }
918
919 static wxNativeFont wxLoadQueryFont(int pointSize,
920 int family,
921 int style,
922 int weight,
923 bool WXUNUSED(underlined),
924 const wxString& facename,
925 const wxString& xregistry,
926 const wxString& xencoding,
927 wxString* xFontName)
928 {
929 wxString xfamily;
930 switch (family)
931 {
932 case wxDECORATIVE: xfamily = wxT("lucida"); break;
933 case wxROMAN: xfamily = wxT("times"); break;
934 case wxMODERN: xfamily = wxT("courier"); break;
935 case wxSWISS: xfamily = wxT("helvetica"); break;
936 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
937 case wxSCRIPT: xfamily = wxT("utopia"); break;
938 default: xfamily = wxT("*");
939 }
940 #if wxUSE_NANOX
941 int xweight;
942 switch (weight)
943 {
944 case wxBOLD:
945 {
946 xweight = MWLF_WEIGHT_BOLD;
947 break;
948 }
949 case wxLIGHT:
950 {
951 xweight = MWLF_WEIGHT_LIGHT;
952 break;
953 }
954 case wxNORMAL:
955 {
956 xweight = MWLF_WEIGHT_NORMAL;
957 break;
958 }
959
960 default:
961 {
962 xweight = MWLF_WEIGHT_DEFAULT;
963 break;
964 }
965 }
966 GR_SCREEN_INFO screenInfo;
967 GrGetScreenInfo(& screenInfo);
968
969 int yPixelsPerCM = screenInfo.ydpcm;
970
971 // A point is 1/72 of an inch.
972 // An inch is 2.541 cm.
973 // So pixelHeight = (pointSize / 72) (inches) * 2.541 (for cm) * yPixelsPerCM (for pixels)
974 // In fact pointSize is 10 * the normal point size so
975 // divide by 10.
976
977 int pixelHeight = (int) ( (((float)pointSize) / 720.0) * 2.541 * (float) yPixelsPerCM) ;
978
979 // An alternative: assume that the screen is 72 dpi.
980 //int pixelHeight = (int) (((float)pointSize / 720.0) * 72.0) ;
981 //int pixelHeight = (int) ((float)pointSize / 10.0) ;
982
983 GR_LOGFONT logFont;
984 logFont.lfHeight = pixelHeight;
985 logFont.lfWidth = 0;
986 logFont.lfEscapement = 0;
987 logFont.lfOrientation = 0;
988 logFont.lfWeight = xweight;
989 logFont.lfItalic = (style == wxNORMAL ? 0 : 1) ;
990 logFont.lfUnderline = 0;
991 logFont.lfStrikeOut = 0;
992 logFont.lfCharSet = MWLF_CHARSET_DEFAULT; // TODO: select appropriate one
993 logFont.lfOutPrecision = MWLF_TYPE_DEFAULT;
994 logFont.lfClipPrecision = 0; // Not used
995 logFont.lfRoman = (family == wxROMAN ? 1 : 0) ;
996 logFont.lfSerif = (family == wxSWISS ? 0 : 1) ;
997 logFont.lfSansSerif = !logFont.lfSerif ;
998 logFont.lfModern = (family == wxMODERN ? 1 : 0) ;
999 logFont.lfProportional = (family == wxTELETYPE ? 0 : 1) ;
1000 logFont.lfOblique = 0;
1001 logFont.lfSmallCaps = 0;
1002 logFont.lfPitch = 0; // 0 = default
1003 strcpy(logFont.lfFaceName, facename.c_str());
1004
1005 XFontStruct* fontInfo = (XFontStruct*) malloc(sizeof(XFontStruct));
1006 fontInfo->fid = GrCreateFont((GR_CHAR*) facename.c_str(), pixelHeight, & logFont);
1007 GrGetFontInfo(fontInfo->fid, & fontInfo->info);
1008 return (wxNativeFont) fontInfo;
1009
1010 #else
1011 wxString fontSpec;
1012 if (!facename.IsEmpty())
1013 {
1014 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
1015 facename.c_str());
1016
1017 if ( wxTestFontSpec(fontSpec) )
1018 {
1019 xfamily = facename;
1020 }
1021 //else: no such family, use default one instead
1022 }
1023
1024 wxString xstyle;
1025 switch (style)
1026 {
1027 case wxSLANT:
1028 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
1029 xfamily.c_str());
1030 if ( wxTestFontSpec(fontSpec) )
1031 {
1032 xstyle = wxT("o");
1033 break;
1034 }
1035 // fall through - try wxITALIC now
1036
1037 case wxITALIC:
1038 fontSpec.Printf(wxT("-*-%s-*-i-*-*-*-*-*-*-*-*-*-*"),
1039 xfamily.c_str());
1040 if ( wxTestFontSpec(fontSpec) )
1041 {
1042 xstyle = wxT("i");
1043 }
1044 else if ( style == wxITALIC ) // and not wxSLANT
1045 {
1046 // try wxSLANT
1047 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
1048 xfamily.c_str());
1049 if ( wxTestFontSpec(fontSpec) )
1050 {
1051 xstyle = wxT("o");
1052 }
1053 else
1054 {
1055 // no italic, no slant - leave default
1056 xstyle = wxT("*");
1057 }
1058 }
1059 break;
1060
1061 default:
1062 wxFAIL_MSG(_T("unknown font style"));
1063 // fall back to normal
1064
1065 case wxNORMAL:
1066 xstyle = wxT("r");
1067 break;
1068 }
1069
1070 wxString xweight;
1071 switch (weight)
1072 {
1073 case wxBOLD:
1074 {
1075 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
1076 xfamily.c_str());
1077 if ( wxTestFontSpec(fontSpec) )
1078 {
1079 xweight = wxT("bold");
1080 break;
1081 }
1082 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
1083 xfamily.c_str());
1084 if ( wxTestFontSpec(fontSpec) )
1085 {
1086 xweight = wxT("heavy");
1087 break;
1088 }
1089 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
1090 xfamily.c_str());
1091 if ( wxTestFontSpec(fontSpec) )
1092 {
1093 xweight = wxT("extrabold");
1094 break;
1095 }
1096 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
1097 xfamily.c_str());
1098 if ( wxTestFontSpec(fontSpec) )
1099 {
1100 xweight = wxT("demibold");
1101 break;
1102 }
1103 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
1104 xfamily.c_str());
1105 if ( wxTestFontSpec(fontSpec) )
1106 {
1107 xweight = wxT("black");
1108 break;
1109 }
1110 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
1111 xfamily.c_str());
1112 if ( wxTestFontSpec(fontSpec) )
1113 {
1114 xweight = wxT("ultrablack");
1115 break;
1116 }
1117 }
1118 break;
1119 case wxLIGHT:
1120 {
1121 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
1122 xfamily.c_str());
1123 if ( wxTestFontSpec(fontSpec) )
1124 {
1125 xweight = wxT("light");
1126 break;
1127 }
1128 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
1129 xfamily.c_str());
1130 if ( wxTestFontSpec(fontSpec) )
1131 {
1132 xweight = wxT("thin");
1133 break;
1134 }
1135 }
1136 break;
1137 case wxNORMAL:
1138 {
1139 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
1140 xfamily.c_str());
1141 if ( wxTestFontSpec(fontSpec) )
1142 {
1143 xweight = wxT("medium");
1144 break;
1145 }
1146 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
1147 xfamily.c_str());
1148 if ( wxTestFontSpec(fontSpec) )
1149 {
1150 xweight = wxT("normal");
1151 break;
1152 }
1153 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
1154 xfamily.c_str());
1155 if ( wxTestFontSpec(fontSpec) )
1156 {
1157 xweight = wxT("regular");
1158 break;
1159 }
1160 xweight = wxT("*");
1161 }
1162 break;
1163 default: xweight = wxT("*"); break;
1164 }
1165
1166 // if pointSize is -1, don't specify any
1167 wxString sizeSpec;
1168 if ( pointSize == -1 )
1169 {
1170 sizeSpec = _T('*');
1171 }
1172 else
1173 {
1174 sizeSpec.Printf(_T("%d"), pointSize);
1175 }
1176
1177 // construct the X font spec from our data
1178 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%s-*-*-*-*-%s-%s"),
1179 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
1180 sizeSpec.c_str(), xregistry.c_str(), xencoding.c_str());
1181
1182 if( xFontName )
1183 *xFontName = fontSpec;
1184
1185 return wxLoadFont(fontSpec);
1186 #endif
1187 // wxUSE_NANOX
1188 }
1189
1190 // ----------------------------------------------------------------------------
1191 // wxFontModule
1192 // ----------------------------------------------------------------------------
1193
1194 class wxFontModule : public wxModule
1195 {
1196 public:
1197 bool OnInit();
1198 void OnExit();
1199
1200 private:
1201 DECLARE_DYNAMIC_CLASS(wxFontModule)
1202 };
1203
1204 IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
1205
1206 bool wxFontModule::OnInit()
1207 {
1208 g_fontHash = new wxHashTable( wxKEY_STRING );
1209
1210 return TRUE;
1211 }
1212
1213 void wxFontModule::OnExit()
1214 {
1215 delete g_fontHash;
1216
1217 g_fontHash = (wxHashTable *)NULL;
1218 }
1219
1220 #endif // GTK 2.0/1.x
1221