Add stubs for wxNativeFontInfo::{Get,Set}Strikethrough() to wxGTK.
[wxWidgets.git] / src / unix / fontutil.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/fontutil.cpp
3 // Purpose: Font helper functions for wxX11, wxGTK, wxMotif
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 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/fontutil.h"
28
29 #ifndef WX_PRECOMP
30 #include "wx/app.h"
31 #include "wx/font.h" // wxFont enums
32 #include "wx/encinfo.h"
33 #include "wx/hash.h"
34 #include "wx/utils.h" // for wxGetDisplay()
35 #include "wx/module.h"
36 #endif // PCH
37
38 #include "wx/fontmap.h"
39 #include "wx/tokenzr.h"
40 #include "wx/fontenum.h"
41
42 #if wxUSE_PANGO
43
44 #include "pango/pango.h"
45
46 #ifdef __WXGTK20__
47 #include "wx/gtk/private.h"
48 extern GtkWidget *wxGetRootWindow();
49
50 #define wxPANGO_CONV wxGTK_CONV_SYS
51 #define wxPANGO_CONV_BACK wxGTK_CONV_BACK_SYS
52 #else
53 #include "wx/x11/private.h"
54 #include "wx/gtk/private/string.h"
55
56 #define wxPANGO_CONV(s) s.utf8_str()
57 #define wxPANGO_CONV_BACK(s) wxString::FromUTF8Unchecked(s)
58 #endif
59
60 // ----------------------------------------------------------------------------
61 // wxNativeFontInfo
62 // ----------------------------------------------------------------------------
63
64 void wxNativeFontInfo::Init()
65 {
66 description = NULL;
67 }
68
69 void wxNativeFontInfo::Init(const wxNativeFontInfo& info)
70 {
71 if (info.description)
72 description = pango_font_description_copy(info.description);
73 else
74 description = NULL;
75 }
76
77 void wxNativeFontInfo::Free()
78 {
79 if (description)
80 pango_font_description_free(description);
81 }
82
83 int wxNativeFontInfo::GetPointSize() const
84 {
85 return pango_font_description_get_size( description ) / PANGO_SCALE;
86 }
87
88 wxFontStyle wxNativeFontInfo::GetStyle() const
89 {
90 wxFontStyle m_style = wxFONTSTYLE_NORMAL;
91
92 switch (pango_font_description_get_style( description ))
93 {
94 case PANGO_STYLE_NORMAL:
95 m_style = wxFONTSTYLE_NORMAL;
96 break;
97 case PANGO_STYLE_ITALIC:
98 m_style = wxFONTSTYLE_ITALIC;
99 break;
100 case PANGO_STYLE_OBLIQUE:
101 m_style = wxFONTSTYLE_SLANT;
102 break;
103 }
104
105 return m_style;
106 }
107
108 wxFontWeight wxNativeFontInfo::GetWeight() const
109 {
110 // We seem to currently initialize only by string.
111 // In that case PANGO_FONT_MASK_WEIGHT is always set.
112 // if (!(pango_font_description_get_set_fields(description) & PANGO_FONT_MASK_WEIGHT))
113 // return wxFONTWEIGHT_NORMAL;
114
115 PangoWeight pango_weight = pango_font_description_get_weight( description );
116
117 // Until the API can be changed the following ranges of weight values are used:
118 // wxFONTWEIGHT_LIGHT: 100 .. 349 - range of 250
119 // wxFONTWEIGHT_NORMAL: 350 .. 599 - range of 250
120 // wxFONTWEIGHT_BOLD: 600 .. 900 - range of 301 (600 is "semibold" already)
121
122 if (pango_weight >= 600)
123 return wxFONTWEIGHT_BOLD;
124
125 if (pango_weight < 350)
126 return wxFONTWEIGHT_LIGHT;
127
128 return wxFONTWEIGHT_NORMAL;
129 }
130
131 bool wxNativeFontInfo::GetUnderlined() const
132 {
133 return false;
134 }
135
136 bool wxNativeFontInfo::GetStrikethrough() const
137 {
138 return false;
139 }
140
141 wxString wxNativeFontInfo::GetFaceName() const
142 {
143 // the Pango "family" is the wx "face name"
144 return wxPANGO_CONV_BACK(pango_font_description_get_family(description));
145 }
146
147 wxFontFamily wxNativeFontInfo::GetFamily() const
148 {
149 wxFontFamily ret = wxFONTFAMILY_UNKNOWN;
150
151 const char *family_name = pango_font_description_get_family( description );
152
153 // note: not passing -1 as the 2nd parameter to g_ascii_strdown to work
154 // around a bug in the 64-bit glib shipped with solaris 10, -1 causes it
155 // to try to allocate 2^32 bytes.
156 if ( !family_name )
157 return ret;
158 wxGtkString family_text(g_ascii_strdown(family_name, strlen(family_name)));
159
160 // Check for some common fonts, to salvage what we can from the current
161 // win32 centric wxFont API:
162 if (strncasecmp( family_text, "monospace", 9 ) == 0)
163 ret = wxFONTFAMILY_TELETYPE; // begins with "Monospace"
164 else if (strncasecmp( family_text, "courier", 7 ) == 0)
165 ret = wxFONTFAMILY_TELETYPE; // begins with "Courier"
166 #if defined(__WXGTK20__) || defined(HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE)
167 else
168 #ifdef __WXGTK20__
169 if (!gtk_check_version(2,4,0))
170 #endif
171 {
172 PangoFontFamily **families;
173 PangoFontFamily *family = NULL;
174 int n_families;
175 pango_context_list_families(
176 #ifdef __WXGTK20__
177 gtk_widget_get_pango_context( wxGetRootWindow() ),
178 #else
179 wxTheApp->GetPangoContext(),
180 #endif
181 &families, &n_families);
182
183 for (int i = 0; i < n_families; ++i)
184 {
185 if (g_ascii_strcasecmp(pango_font_family_get_name( families[i] ),
186 pango_font_description_get_family( description )) == 0 )
187 {
188 family = families[i];
189 break;
190 }
191 }
192
193 g_free(families);
194
195 // Some gtk+ systems might query for a non-existing font from
196 // wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) on initialization,
197 // don't assert until wxSystemSettings::GetFont is checked for this - MR
198 // wxASSERT_MSG( family, "No appropriate PangoFontFamily found for ::description" );
199
200 if (family != NULL && pango_font_family_is_monospace( family ))
201 ret = wxFONTFAMILY_TELETYPE; // is deemed a monospace font by pango
202 }
203 #endif // GTK+ 2 || HAVE_PANGO_FONT_FAMILY_IS_MONOSPACE
204
205 if (ret == wxFONTFAMILY_UNKNOWN)
206 {
207 if (strstr( family_text, "sans" ) != NULL || strstr( family_text, "Sans" ) != NULL)
208 // checked before serif, so that "* Sans Serif" fonts are detected correctly
209 ret = wxFONTFAMILY_SWISS; // contains "Sans"
210 else if (strstr( family_text, "serif" ) != NULL || strstr( family_text, "Serif" ) != NULL)
211 ret = wxFONTFAMILY_ROMAN; // contains "Serif"
212 else if (strncasecmp( family_text, "times", 5 ) == 0)
213 ret = wxFONTFAMILY_ROMAN; // begins with "Times"
214 else if (strncasecmp( family_text, "old", 3 ) == 0)
215 ret = wxFONTFAMILY_DECORATIVE; // begins with "Old" - "Old English", "Old Town"
216 }
217
218 return ret;
219 }
220
221 wxFontEncoding wxNativeFontInfo::GetEncoding() const
222 {
223 return wxFONTENCODING_SYSTEM;
224 }
225
226 void wxNativeFontInfo::SetPointSize(int pointsize)
227 {
228 pango_font_description_set_size( description, pointsize * PANGO_SCALE );
229 }
230
231 void wxNativeFontInfo::SetStyle(wxFontStyle style)
232 {
233 switch (style)
234 {
235 case wxFONTSTYLE_ITALIC:
236 pango_font_description_set_style( description, PANGO_STYLE_ITALIC );
237 break;
238 case wxFONTSTYLE_SLANT:
239 pango_font_description_set_style( description, PANGO_STYLE_OBLIQUE );
240 break;
241 default:
242 wxFAIL_MSG( "unknown font style" );
243 // fall through
244 case wxFONTSTYLE_NORMAL:
245 pango_font_description_set_style( description, PANGO_STYLE_NORMAL );
246 break;
247 }
248 }
249
250 void wxNativeFontInfo::SetWeight(wxFontWeight weight)
251 {
252 switch (weight)
253 {
254 case wxFONTWEIGHT_BOLD:
255 pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD);
256 break;
257 case wxFONTWEIGHT_LIGHT:
258 pango_font_description_set_weight(description, PANGO_WEIGHT_LIGHT);
259 break;
260 default:
261 wxFAIL_MSG( "unknown font weight" );
262 // fall through
263 case wxFONTWEIGHT_NORMAL:
264 pango_font_description_set_weight(description, PANGO_WEIGHT_NORMAL);
265 }
266 }
267
268 void wxNativeFontInfo::SetUnderlined(bool WXUNUSED(underlined))
269 {
270 // wxWindowDCImpl::DoDrawText will take care of rendering font with
271 // the underline attribute!
272 wxFAIL_MSG( "not implemented" );
273 }
274
275 bool wxNativeFontInfo::SetFaceName(const wxString& facename)
276 {
277 pango_font_description_set_family(description, wxPANGO_CONV(facename));
278
279 // we return true because Pango doesn't tell us if the call failed or not;
280 // instead on wxGTK wxFont::SetFaceName() will call wxFontBase::SetFaceName()
281 // which does the check
282 return true;
283 }
284
285 void wxNativeFontInfo::SetFamily(wxFontFamily family)
286 {
287 wxArrayString facename;
288
289 // the list of fonts associated with a family was partially
290 // taken from http://www.codestyle.org/css/font-family
291
292 switch ( family )
293 {
294 case wxFONTFAMILY_SCRIPT:
295 // corresponds to the cursive font family in the page linked above
296 facename.Add(wxS("URW Chancery L"));
297 facename.Add(wxS("Comic Sans MS"));
298 break;
299
300 case wxFONTFAMILY_DECORATIVE:
301 // corresponds to the fantasy font family in the page linked above
302 facename.Add(wxS("Impact"));
303 break;
304
305 case wxFONTFAMILY_ROMAN:
306 // corresponds to the serif font family in the page linked above
307 facename.Add(wxS("Century Schoolbook L"));
308 facename.Add(wxS("URW Bookman L"));
309 facename.Add(wxS("URW Palladio L"));
310 facename.Add(wxS("DejaVu Serif"));
311 facename.Add(wxS("FreeSerif"));
312 facename.Add(wxS("Times New Roman"));
313 facename.Add(wxS("Times"));
314 break;
315
316 case wxFONTFAMILY_TELETYPE:
317 case wxFONTFAMILY_MODERN:
318 // corresponds to the monospace font family in the page linked above
319 facename.Add(wxS("DejaVu Sans Mono"));
320 facename.Add(wxS("Nimbus Mono L"));
321 facename.Add(wxS("Bitstream Vera Sans Mono"));
322 facename.Add(wxS("Andale Mono"));
323 facename.Add(wxS("Lucida Sans Typewriter"));
324 facename.Add(wxS("FreeMono"));
325 facename.Add(wxS("Courier New"));
326 facename.Add(wxS("Courier"));
327 break;
328
329 case wxFONTFAMILY_SWISS:
330 case wxFONTFAMILY_DEFAULT:
331 default:
332 // corresponds to the sans-serif font family in the page linked above
333 facename.Add(wxS("DejaVu Sans"));
334 facename.Add(wxS("URW Gothic L"));
335 facename.Add(wxS("Nimbus Sans L"));
336 facename.Add(wxS("Bitstream Vera Sans"));
337 facename.Add(wxS("Lucida Sans"));
338 facename.Add(wxS("Arial"));
339 facename.Add(wxS("FreeSans"));
340 break;
341 }
342
343 SetFaceName(facename);
344 }
345
346 void wxNativeFontInfo::SetEncoding(wxFontEncoding WXUNUSED(encoding))
347 {
348 wxFAIL_MSG( "not implemented: Pango encoding is always UTF8" );
349 }
350
351 bool wxNativeFontInfo::FromString(const wxString& s)
352 {
353 if (description)
354 pango_font_description_free( description );
355
356 // there is a bug in at least pango <= 1.13 which makes it (or its backends)
357 // segfault for very big point sizes and for negative point sizes.
358 // To workaround that bug for pango <= 1.13
359 // (see http://bugzilla.gnome.org/show_bug.cgi?id=340229)
360 // we do the check on the size here using same (arbitrary) limits used by
361 // pango > 1.13. Note that the segfault could happen also for pointsize
362 // smaller than this limit !!
363 wxString str(s);
364 const size_t pos = str.find_last_of(wxS(" "));
365 double size;
366 if ( pos != wxString::npos && wxString(str, pos + 1).ToDouble(&size) )
367 {
368 wxString sizeStr;
369 if ( size < 1 )
370 sizeStr = wxS("1");
371 else if ( size >= 1E6 )
372 sizeStr = wxS("1E6");
373
374 if ( !sizeStr.empty() )
375 {
376 // replace the old size with the adjusted one
377 str = wxString(s, 0, pos) + sizeStr;
378 }
379 }
380
381 description = pango_font_description_from_string(wxPANGO_CONV(str));
382
383 #if wxUSE_FONTENUM
384 // ensure a valid facename is selected
385 if (!wxFontEnumerator::IsValidFacename(GetFaceName()))
386 SetFaceName(wxNORMAL_FONT->GetFaceName());
387 #endif // wxUSE_FONTENUM
388
389 return true;
390 }
391
392 wxString wxNativeFontInfo::ToString() const
393 {
394 wxGtkString str(pango_font_description_to_string( description ));
395
396 return wxPANGO_CONV_BACK(str);
397 }
398
399 bool wxNativeFontInfo::FromUserString(const wxString& s)
400 {
401 return FromString( s );
402 }
403
404 wxString wxNativeFontInfo::ToUserString() const
405 {
406 return ToString();
407 }
408
409 #else // GTK+ 1.x
410
411 #ifdef __X__
412 #ifdef __VMS__
413 #pragma message disable nosimpint
414 #endif
415
416 #include <X11/Xlib.h>
417
418 #ifdef __VMS__
419 #pragma message enable nosimpint
420 #endif
421
422 #elif defined(__WXGTK__)
423 // we have to declare struct tm to avoid problems with first forward
424 // declaring it in C code (glib.h included from gdk.h does it) and then
425 // defining it when time.h is included from the headers below - this is
426 // known not to work at least with Sun CC 6.01
427 #include <time.h>
428
429 #include <gdk/gdk.h>
430 #endif
431
432
433 // ----------------------------------------------------------------------------
434 // private data
435 // ----------------------------------------------------------------------------
436
437 static wxHashTable *g_fontHash = NULL;
438
439 // ----------------------------------------------------------------------------
440 // private functions
441 // ----------------------------------------------------------------------------
442
443 // define the functions to create and destroy native fonts for this toolkit
444 #ifdef __X__
445 wxNativeFont wxLoadFont(const wxString& fontSpec)
446 {
447 return XLoadQueryFont((Display *)wxGetDisplay(), fontSpec);
448 }
449
450 inline void wxFreeFont(wxNativeFont font)
451 {
452 XFreeFont((Display *)wxGetDisplay(), (XFontStruct *)font);
453 }
454 #elif defined(__WXGTK__)
455 wxNativeFont wxLoadFont(const wxString& fontSpec)
456 {
457 // VZ: we should use gdk_fontset_load() instead of gdk_font_load()
458 // here to be able to display Japanese fonts correctly (at least
459 // this is what people report) but unfortunately doing it results
460 // in tons of warnings when using GTK with "normal" European
461 // languages and so we can't always do it and I don't know enough
462 // to determine when should this be done... (FIXME)
463 return gdk_font_load( wxConvertWX2MB(fontSpec) );
464 }
465
466 inline void wxFreeFont(wxNativeFont font)
467 {
468 gdk_font_unref(font);
469 }
470 #else
471 #error "Unknown GUI toolkit"
472 #endif
473
474 static bool wxTestFontSpec(const wxString& fontspec);
475
476 static wxNativeFont wxLoadQueryFont(int pointSize,
477 int family,
478 int style,
479 int weight,
480 bool underlined,
481 const wxString& facename,
482 const wxString& xregistry,
483 const wxString& xencoding,
484 wxString* xFontName);
485
486 // ============================================================================
487 // implementation
488 // ============================================================================
489
490 // ----------------------------------------------------------------------------
491 // wxNativeEncodingInfo
492 // ----------------------------------------------------------------------------
493
494 // convert to/from the string representation: format is
495 // encodingid;registry;encoding[;facename]
496 bool wxNativeEncodingInfo::FromString(const wxString& s)
497 {
498 // use ";", not "-" because it may be part of encoding name
499 wxStringTokenizer tokenizer(s, wxT(";"));
500
501 wxString encid = tokenizer.GetNextToken();
502 long enc;
503 if ( !encid.ToLong(&enc) )
504 return false;
505 encoding = (wxFontEncoding)enc;
506
507 xregistry = tokenizer.GetNextToken();
508 if ( !xregistry )
509 return false;
510
511 xencoding = tokenizer.GetNextToken();
512 if ( !xencoding )
513 return false;
514
515 // ok even if empty
516 facename = tokenizer.GetNextToken();
517
518 return true;
519 }
520
521 wxString wxNativeEncodingInfo::ToString() const
522 {
523 wxString s;
524 s << (long)encoding << wxT(';') << xregistry << wxT(';') << xencoding;
525 if ( !facename.empty() )
526 {
527 s << wxT(';') << facename;
528 }
529
530 return s;
531 }
532
533 // ----------------------------------------------------------------------------
534 // wxNativeFontInfo
535 // ----------------------------------------------------------------------------
536
537 void wxNativeFontInfo::Init()
538 {
539 m_isDefault = true;
540 }
541
542 bool wxNativeFontInfo::FromString(const wxString& s)
543 {
544 wxStringTokenizer tokenizer(s, wxT(";"));
545
546 // check the version
547 wxString token = tokenizer.GetNextToken();
548 if ( token != wxT('0') )
549 return false;
550
551 xFontName = tokenizer.GetNextToken();
552
553 // this should be the end
554 if ( tokenizer.HasMoreTokens() )
555 return false;
556
557 return FromXFontName(xFontName);
558 }
559
560 wxString wxNativeFontInfo::ToString() const
561 {
562 // 0 is the version
563 return wxString::Format(wxT("%d;%s"), 0, GetXFontName().c_str());
564 }
565
566 bool wxNativeFontInfo::FromUserString(const wxString& s)
567 {
568 return FromXFontName(s);
569 }
570
571 wxString wxNativeFontInfo::ToUserString() const
572 {
573 return GetXFontName();
574 }
575
576 bool wxNativeFontInfo::HasElements() const
577 {
578 // we suppose that the foundry is never empty, so if it is it means that we
579 // had never parsed the XLFD
580 return !fontElements[0].empty();
581 }
582
583 wxString wxNativeFontInfo::GetXFontComponent(wxXLFDField field) const
584 {
585 wxCHECK_MSG( field < wxXLFD_MAX, wxEmptyString, wxT("invalid XLFD field") );
586
587 if ( !HasElements() )
588 {
589 if ( !const_cast<wxNativeFontInfo *>(this)->FromXFontName(xFontName) )
590 return wxEmptyString;
591 }
592
593 return fontElements[field];
594 }
595
596 bool wxNativeFontInfo::FromXFontName(const wxString& fontname)
597 {
598 // TODO: we should be able to handle the font aliases here, but how?
599 wxStringTokenizer tokenizer(fontname, wxT("-"));
600
601 // skip the leading, usually empty field (font name registry)
602 if ( !tokenizer.HasMoreTokens() )
603 return false;
604
605 (void)tokenizer.GetNextToken();
606
607 for ( size_t n = 0; n < WXSIZEOF(fontElements); n++ )
608 {
609 if ( !tokenizer.HasMoreTokens() )
610 {
611 // not enough elements in the XLFD - or maybe an alias
612 return false;
613 }
614
615 wxString field = tokenizer.GetNextToken();
616 if ( !field.empty() && field != wxT('*') )
617 {
618 // we're really initialized now
619 m_isDefault = false;
620 }
621
622 fontElements[n] = field;
623 }
624
625 // this should be all
626 if ( tokenizer.HasMoreTokens() )
627 return false;
628
629 return true;
630 }
631
632 wxString wxNativeFontInfo::GetXFontName() const
633 {
634 if ( xFontName.empty() )
635 {
636 for ( size_t n = 0; n < WXSIZEOF(fontElements); n++ )
637 {
638 // replace the non specified elements with '*' except for the
639 // additional style which is usually just omitted
640 wxString elt = fontElements[n];
641 if ( elt.empty() && n != wxXLFD_ADDSTYLE )
642 {
643 elt = wxT('*');
644 }
645
646 const_cast<wxNativeFontInfo *>(this)->xFontName << wxT('-') << elt;
647 }
648 }
649
650 return xFontName;
651 }
652
653 void
654 wxNativeFontInfo::SetXFontComponent(wxXLFDField field, const wxString& value)
655 {
656 wxCHECK_RET( field < wxXLFD_MAX, wxT("invalid XLFD field") );
657
658 // this class should be initialized with a valid font spec first and only
659 // then the fields may be modified!
660 wxASSERT_MSG( !IsDefault(), wxT("can't modify an uninitialized XLFD") );
661
662 if ( !HasElements() )
663 {
664 if ( !const_cast<wxNativeFontInfo *>(this)->FromXFontName(xFontName) )
665 {
666 wxFAIL_MSG( wxT("can't set font element for invalid XLFD") );
667
668 return;
669 }
670 }
671
672 fontElements[field] = value;
673
674 // invalidate the XFLD, it doesn't correspond to the font elements any more
675 xFontName.clear();
676 }
677
678 void wxNativeFontInfo::SetXFontName(const wxString& xFontName_)
679 {
680 // invalidate the font elements, GetXFontComponent() will reparse the XLFD
681 fontElements[0].clear();
682
683 xFontName = xFontName_;
684
685 m_isDefault = false;
686 }
687
688 int wxNativeFontInfo::GetPointSize() const
689 {
690 const wxString s = GetXFontComponent(wxXLFD_POINTSIZE);
691
692 // return -1 to indicate that the size is unknown
693 long l;
694 return s.ToLong(&l) ? l : -1;
695 }
696
697 wxFontStyle wxNativeFontInfo::GetStyle() const
698 {
699 const wxString s = GetXFontComponent(wxXLFD_SLANT);
700
701 if ( s.length() != 1 )
702 {
703 // it is really unknown but we don't have any way to return it from
704 // here
705 return wxFONTSTYLE_NORMAL;
706 }
707
708 switch ( s[0].GetValue() )
709 {
710 default:
711 // again, unknown but consider normal by default
712
713 case wxT('r'):
714 return wxFONTSTYLE_NORMAL;
715
716 case wxT('i'):
717 return wxFONTSTYLE_ITALIC;
718
719 case wxT('o'):
720 return wxFONTSTYLE_SLANT;
721 }
722 }
723
724 wxFontWeight wxNativeFontInfo::GetWeight() const
725 {
726 const wxString s = GetXFontComponent(wxXLFD_WEIGHT).MakeLower();
727 if ( s.find(wxT("bold")) != wxString::npos || s == wxT("black") )
728 return wxFONTWEIGHT_BOLD;
729 else if ( s == wxT("light") )
730 return wxFONTWEIGHT_LIGHT;
731
732 return wxFONTWEIGHT_NORMAL;
733 }
734
735 bool wxNativeFontInfo::GetUnderlined() const
736 {
737 // X fonts are never underlined
738 return false;
739 }
740
741 wxString wxNativeFontInfo::GetFaceName() const
742 {
743 // wxWidgets facename probably more accurately corresponds to X family
744 return GetXFontComponent(wxXLFD_FAMILY);
745 }
746
747 wxFontFamily wxNativeFontInfo::GetFamily() const
748 {
749 // and wxWidgets family -- to X foundry, but we have to translate it to
750 // wxFontFamily somehow...
751 wxFAIL_MSG(wxT("not implemented")); // GetXFontComponent(wxXLFD_FOUNDRY);
752
753 return wxFONTFAMILY_DEFAULT;
754 }
755
756 wxFontEncoding wxNativeFontInfo::GetEncoding() const
757 {
758 // we already have the code for this but need to refactor it first
759 wxFAIL_MSG( wxT("not implemented") );
760
761 return wxFONTENCODING_MAX;
762 }
763
764 void wxNativeFontInfo::SetPointSize(int pointsize)
765 {
766 SetXFontComponent(wxXLFD_POINTSIZE, wxString::Format(wxT("%d"), pointsize));
767 }
768
769 void wxNativeFontInfo::SetStyle(wxFontStyle style)
770 {
771 wxString s;
772 switch ( style )
773 {
774 case wxFONTSTYLE_ITALIC:
775 s = wxT('i');
776 break;
777
778 case wxFONTSTYLE_SLANT:
779 s = wxT('o');
780 break;
781
782 case wxFONTSTYLE_NORMAL:
783 s = wxT('r');
784
785 default:
786 wxFAIL_MSG( wxT("unknown wxFontStyle in wxNativeFontInfo::SetStyle") );
787 return;
788 }
789
790 SetXFontComponent(wxXLFD_SLANT, s);
791 }
792
793 void wxNativeFontInfo::SetWeight(wxFontWeight weight)
794 {
795 wxString s;
796 switch ( weight )
797 {
798 case wxFONTWEIGHT_BOLD:
799 s = wxT("bold");
800 break;
801
802 case wxFONTWEIGHT_LIGHT:
803 s = wxT("light");
804 break;
805
806 case wxFONTWEIGHT_NORMAL:
807 s = wxT("medium");
808 break;
809
810 default:
811 wxFAIL_MSG( wxT("unknown wxFontWeight in wxNativeFontInfo::SetWeight") );
812 return;
813 }
814
815 SetXFontComponent(wxXLFD_WEIGHT, s);
816 }
817
818 void wxNativeFontInfo::SetUnderlined(bool WXUNUSED(underlined))
819 {
820 // can't do this under X
821 }
822
823 void wxNativeFontInfo::SetStrikethrough(bool WXUNUSED(strikethrough))
824 {
825 // this is not supported by Pango fonts neither
826 }
827
828 bool wxNativeFontInfo::SetFaceName(const wxString& facename)
829 {
830 SetXFontComponent(wxXLFD_FAMILY, facename);
831 return true;
832 }
833
834 void wxNativeFontInfo::SetFamily(wxFontFamily WXUNUSED(family))
835 {
836 // wxFontFamily -> X foundry, anyone?
837 wxFAIL_MSG( wxT("not implemented") );
838
839 // SetXFontComponent(wxXLFD_FOUNDRY, ...);
840 }
841
842 void wxNativeFontInfo::SetEncoding(wxFontEncoding encoding)
843 {
844 wxNativeEncodingInfo info;
845 if ( wxGetNativeFontEncoding(encoding, &info) )
846 {
847 SetXFontComponent(wxXLFD_ENCODING, info.xencoding);
848 SetXFontComponent(wxXLFD_REGISTRY, info.xregistry);
849 }
850 }
851
852 // ----------------------------------------------------------------------------
853 // common functions
854 // ----------------------------------------------------------------------------
855
856 bool wxGetNativeFontEncoding(wxFontEncoding encoding,
857 wxNativeEncodingInfo *info)
858 {
859 wxCHECK_MSG( info, false, wxT("bad pointer in wxGetNativeFontEncoding") );
860
861 if ( encoding == wxFONTENCODING_DEFAULT )
862 {
863 encoding = wxFont::GetDefaultEncoding();
864 }
865
866 switch ( encoding )
867 {
868 case wxFONTENCODING_ISO8859_1:
869 case wxFONTENCODING_ISO8859_2:
870 case wxFONTENCODING_ISO8859_3:
871 case wxFONTENCODING_ISO8859_4:
872 case wxFONTENCODING_ISO8859_5:
873 case wxFONTENCODING_ISO8859_6:
874 case wxFONTENCODING_ISO8859_7:
875 case wxFONTENCODING_ISO8859_8:
876 case wxFONTENCODING_ISO8859_9:
877 case wxFONTENCODING_ISO8859_10:
878 case wxFONTENCODING_ISO8859_11:
879 case wxFONTENCODING_ISO8859_12:
880 case wxFONTENCODING_ISO8859_13:
881 case wxFONTENCODING_ISO8859_14:
882 case wxFONTENCODING_ISO8859_15:
883 {
884 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
885 info->xregistry = wxT("iso8859");
886 info->xencoding.Printf(wxT("%d"), cp);
887 }
888 break;
889
890 case wxFONTENCODING_UTF8:
891 info->xregistry = wxT("iso10646");
892 info->xencoding = wxT("*");
893 break;
894
895 case wxFONTENCODING_GB2312:
896 info->xregistry = wxT("GB2312"); // or the otherway round?
897 info->xencoding = wxT("*");
898 break;
899
900 case wxFONTENCODING_KOI8:
901 case wxFONTENCODING_KOI8_U:
902 info->xregistry = wxT("koi8");
903
904 // we don't make distinction between koi8-r, koi8-u and koi8-ru (so far)
905 info->xencoding = wxT("*");
906 break;
907
908 case wxFONTENCODING_CP1250:
909 case wxFONTENCODING_CP1251:
910 case wxFONTENCODING_CP1252:
911 case wxFONTENCODING_CP1253:
912 case wxFONTENCODING_CP1254:
913 case wxFONTENCODING_CP1255:
914 case wxFONTENCODING_CP1256:
915 case wxFONTENCODING_CP1257:
916 {
917 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
918 info->xregistry = wxT("microsoft");
919 info->xencoding.Printf(wxT("cp%d"), cp);
920 }
921 break;
922
923 case wxFONTENCODING_EUC_JP:
924 case wxFONTENCODING_SHIFT_JIS:
925 info->xregistry = "jis*";
926 info->xencoding = "*";
927 break;
928
929 case wxFONTENCODING_SYSTEM:
930 info->xregistry =
931 info->xencoding = wxT("*");
932 break;
933
934 default:
935 // don't know how to translate this encoding into X fontspec
936 return false;
937 }
938
939 info->encoding = encoding;
940
941 return true;
942 }
943
944 bool wxTestFontEncoding(const wxNativeEncodingInfo& info)
945 {
946 wxString fontspec;
947 fontspec.Printf(wxT("-*-%s-*-*-*-*-*-*-*-*-*-*-%s-%s"),
948 !info.facename ? wxT("*") : info.facename.c_str(),
949 info.xregistry.c_str(),
950 info.xencoding.c_str());
951
952 return wxTestFontSpec(fontspec);
953 }
954
955 // ----------------------------------------------------------------------------
956 // X-specific functions
957 // ----------------------------------------------------------------------------
958
959 wxNativeFont wxLoadQueryNearestFont(int pointSize,
960 int family,
961 int style,
962 int weight,
963 bool underlined,
964 const wxString &facename,
965 wxFontEncoding encoding,
966 wxString* xFontName)
967 {
968 if ( encoding == wxFONTENCODING_DEFAULT )
969 {
970 encoding = wxFont::GetDefaultEncoding();
971 }
972
973 // first determine the encoding - if the font doesn't exist at all in this
974 // encoding, it's useless to do all other approximations (i.e. size,
975 // family &c don't matter much)
976 wxNativeEncodingInfo info;
977 if ( encoding == wxFONTENCODING_SYSTEM )
978 {
979 // This will always work so we don't test to save time
980 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
981 }
982 else
983 {
984 if ( !wxGetNativeFontEncoding(encoding, &info) ||
985 !wxTestFontEncoding(info) )
986 {
987 #if wxUSE_FONTMAP
988 if ( !wxFontMapper::Get()->GetAltForEncoding(encoding, &info) )
989 #endif // wxUSE_FONTMAP
990 {
991 // unspported encoding - replace it with the default
992 //
993 // NB: we can't just return 0 from here because wxGTK code doesn't
994 // check for it (i.e. it supposes that we'll always succeed),
995 // so it would provoke a crash
996 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
997 }
998 }
999 }
1000
1001 // OK, we have the correct xregistry/xencoding in info structure
1002 wxNativeFont font = 0;
1003
1004 // if we already have the X font name, try to use it
1005 if( xFontName && !xFontName->empty() )
1006 {
1007 //
1008 // Make sure point size is correct for scale factor.
1009 //
1010 wxStringTokenizer tokenizer(*xFontName, wxT("-"), wxTOKEN_RET_DELIMS);
1011 wxString newFontName;
1012
1013 for(int i = 0; i < 8; i++)
1014 newFontName += tokenizer.NextToken();
1015
1016 (void) tokenizer.NextToken();
1017
1018 newFontName += wxString::Format(wxT("%d-"), pointSize);
1019
1020 while(tokenizer.HasMoreTokens())
1021 newFontName += tokenizer.GetNextToken();
1022
1023 font = wxLoadFont(newFontName);
1024
1025 if(font)
1026 *xFontName = newFontName;
1027 }
1028
1029 if ( !font )
1030 {
1031 // search up and down by stepsize 10
1032 int max_size = pointSize + 20 * (1 + (pointSize/180));
1033 int min_size = pointSize - 20 * (1 + (pointSize/180));
1034
1035 int i, round; // counters
1036
1037 // first round: search for equal, then for smaller and for larger size
1038 // with the given weight and style
1039 int testweight = weight;
1040 int teststyle = style;
1041
1042 for ( round = 0; round < 3; round++ )
1043 {
1044 // second round: use normal weight
1045 if ( round == 1 )
1046 {
1047 if ( testweight != wxNORMAL )
1048 {
1049 testweight = wxNORMAL;
1050 }
1051 else
1052 {
1053 ++round; // fall through to third round
1054 }
1055 }
1056
1057 // third round: ... and use normal style
1058 if ( round == 2 )
1059 {
1060 if ( teststyle != wxNORMAL )
1061 {
1062 teststyle = wxNORMAL;
1063 }
1064 else
1065 {
1066 break;
1067 }
1068 }
1069 // Search for equal or smaller size (approx.)
1070 for ( i = pointSize; !font && i >= 10 && i >= min_size; i -= 10 )
1071 {
1072 font = wxLoadQueryFont(i, family, teststyle, testweight, underlined,
1073 facename, info.xregistry, info.xencoding,
1074 xFontName);
1075 }
1076
1077 // Search for larger size (approx.)
1078 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
1079 {
1080 font = wxLoadQueryFont(i, family, teststyle, testweight, underlined,
1081 facename, info.xregistry, info.xencoding,
1082 xFontName);
1083 }
1084 }
1085
1086 // Try default family
1087 if ( !font && family != wxDEFAULT )
1088 {
1089 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
1090 underlined, facename,
1091 info.xregistry, info.xencoding,
1092 xFontName );
1093 }
1094
1095 // ignore size, family, style and weight but try to find font with the
1096 // given facename and encoding
1097 if ( !font )
1098 {
1099 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
1100 underlined, facename,
1101 info.xregistry, info.xencoding,
1102 xFontName);
1103
1104 // ignore family as well
1105 if ( !font )
1106 {
1107 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
1108 underlined, wxEmptyString,
1109 info.xregistry, info.xencoding,
1110 xFontName);
1111
1112 // if it still failed, try to get the font of any size but
1113 // with the requested encoding: this can happen if the
1114 // encoding is only available in one size which happens to be
1115 // different from 120
1116 if ( !font )
1117 {
1118 font = wxLoadQueryFont(-1, wxDEFAULT, wxNORMAL, wxNORMAL,
1119 false, wxEmptyString,
1120 info.xregistry, info.xencoding,
1121 xFontName);
1122
1123 // this should never happen as we had tested for it in the
1124 // very beginning, but if it does, do return something non
1125 // NULL or we'd crash in wxFont code
1126 if ( !font )
1127 {
1128 wxFAIL_MSG( wxT("this encoding should be available!") );
1129
1130 font = wxLoadQueryFont(-1,
1131 wxDEFAULT, wxNORMAL, wxNORMAL,
1132 false, wxEmptyString,
1133 wxT("*"), wxT("*"),
1134 xFontName);
1135 }
1136 }
1137 }
1138 }
1139 }
1140
1141 return font;
1142 }
1143
1144 // ----------------------------------------------------------------------------
1145 // private functions
1146 // ----------------------------------------------------------------------------
1147
1148 // returns true if there are any fonts matching this font spec
1149 static bool wxTestFontSpec(const wxString& fontspec)
1150 {
1151 // some X servers will fail to load this font because there are too many
1152 // matches so we must test explicitly for this
1153 if ( fontspec == wxT("-*-*-*-*-*-*-*-*-*-*-*-*-*-*") )
1154 {
1155 return true;
1156 }
1157
1158 wxNativeFont test = (wxNativeFont) g_fontHash->Get( fontspec );
1159 if (test)
1160 {
1161 return true;
1162 }
1163
1164 test = wxLoadFont(fontspec);
1165 g_fontHash->Put( fontspec, (wxObject*) test );
1166
1167 if ( test )
1168 {
1169 wxFreeFont(test);
1170
1171 return true;
1172 }
1173 else
1174 {
1175 return false;
1176 }
1177 }
1178
1179 static wxNativeFont wxLoadQueryFont(int pointSize,
1180 int family,
1181 int style,
1182 int weight,
1183 bool WXUNUSED(underlined),
1184 const wxString& facename,
1185 const wxString& xregistry,
1186 const wxString& xencoding,
1187 wxString* xFontName)
1188 {
1189 wxString xfamily;
1190 switch (family)
1191 {
1192 case wxDECORATIVE: xfamily = wxT("lucida"); break;
1193 case wxROMAN: xfamily = wxT("times"); break;
1194 case wxMODERN: xfamily = wxT("courier"); break;
1195 case wxSWISS: xfamily = wxT("helvetica"); break;
1196 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
1197 case wxSCRIPT: xfamily = wxT("utopia"); break;
1198 default: xfamily = wxT("*");
1199 }
1200 #if wxUSE_NANOX
1201 int xweight;
1202 switch (weight)
1203 {
1204 case wxBOLD:
1205 {
1206 xweight = MWLF_WEIGHT_BOLD;
1207 break;
1208 }
1209 case wxLIGHT:
1210 {
1211 xweight = MWLF_WEIGHT_LIGHT;
1212 break;
1213 }
1214 case wxNORMAL:
1215 {
1216 xweight = MWLF_WEIGHT_NORMAL;
1217 break;
1218 }
1219
1220 default:
1221 {
1222 xweight = MWLF_WEIGHT_DEFAULT;
1223 break;
1224 }
1225 }
1226 GR_SCREEN_INFO screenInfo;
1227 GrGetScreenInfo(& screenInfo);
1228
1229 int yPixelsPerCM = screenInfo.ydpcm;
1230
1231 // A point is 1/72 of an inch.
1232 // An inch is 2.541 cm.
1233 // So pixelHeight = (pointSize / 72) (inches) * 2.541 (for cm) * yPixelsPerCM (for pixels)
1234 // In fact pointSize is 10 * the normal point size so
1235 // divide by 10.
1236
1237 int pixelHeight = (int) ( (((float)pointSize) / 720.0) * 2.541 * (float) yPixelsPerCM) ;
1238
1239 // An alternative: assume that the screen is 72 dpi.
1240 //int pixelHeight = (int) (((float)pointSize / 720.0) * 72.0) ;
1241 //int pixelHeight = (int) ((float)pointSize / 10.0) ;
1242
1243 GR_LOGFONT logFont;
1244 logFont.lfHeight = pixelHeight;
1245 logFont.lfWidth = 0;
1246 logFont.lfEscapement = 0;
1247 logFont.lfOrientation = 0;
1248 logFont.lfWeight = xweight;
1249 logFont.lfItalic = (style == wxNORMAL ? 0 : 1) ;
1250 logFont.lfUnderline = 0;
1251 logFont.lfStrikeOut = 0;
1252 logFont.lfCharSet = MWLF_CHARSET_DEFAULT; // TODO: select appropriate one
1253 logFont.lfOutPrecision = MWLF_TYPE_DEFAULT;
1254 logFont.lfClipPrecision = 0; // Not used
1255 logFont.lfRoman = (family == wxROMAN ? 1 : 0) ;
1256 logFont.lfSerif = (family == wxSWISS ? 0 : 1) ;
1257 logFont.lfSansSerif = !logFont.lfSerif ;
1258 logFont.lfModern = (family == wxMODERN ? 1 : 0) ;
1259 logFont.lfProportional = (family == wxTELETYPE ? 0 : 1) ;
1260 logFont.lfOblique = 0;
1261 logFont.lfSmallCaps = 0;
1262 logFont.lfPitch = 0; // 0 = default
1263 strcpy(logFont.lfFaceName, facename.c_str());
1264
1265 XFontStruct* fontInfo = (XFontStruct*) malloc(sizeof(XFontStruct));
1266 fontInfo->fid = GrCreateFont((GR_CHAR*) facename.c_str(), pixelHeight, & logFont);
1267 GrGetFontInfo(fontInfo->fid, & fontInfo->info);
1268 return (wxNativeFont) fontInfo;
1269
1270 #else
1271 wxString fontSpec;
1272 if (!facename.empty())
1273 {
1274 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
1275 facename.c_str());
1276
1277 if ( wxTestFontSpec(fontSpec) )
1278 {
1279 xfamily = facename;
1280 }
1281 //else: no such family, use default one instead
1282 }
1283
1284 wxString xstyle;
1285 switch (style)
1286 {
1287 case wxSLANT:
1288 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
1289 xfamily.c_str());
1290 if ( wxTestFontSpec(fontSpec) )
1291 {
1292 xstyle = wxT("o");
1293 break;
1294 }
1295 // fall through - try wxITALIC now
1296
1297 case wxITALIC:
1298 fontSpec.Printf(wxT("-*-%s-*-i-*-*-*-*-*-*-*-*-*-*"),
1299 xfamily.c_str());
1300 if ( wxTestFontSpec(fontSpec) )
1301 {
1302 xstyle = wxT("i");
1303 }
1304 else if ( style == wxITALIC ) // and not wxSLANT
1305 {
1306 // try wxSLANT
1307 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
1308 xfamily.c_str());
1309 if ( wxTestFontSpec(fontSpec) )
1310 {
1311 xstyle = wxT("o");
1312 }
1313 else
1314 {
1315 // no italic, no slant - leave default
1316 xstyle = wxT("*");
1317 }
1318 }
1319 break;
1320
1321 default:
1322 wxFAIL_MSG(wxT("unknown font style"));
1323 // fall back to normal
1324
1325 case wxNORMAL:
1326 xstyle = wxT("r");
1327 break;
1328 }
1329
1330 wxString xweight;
1331 switch (weight)
1332 {
1333 case wxBOLD:
1334 {
1335 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
1336 xfamily.c_str());
1337 if ( wxTestFontSpec(fontSpec) )
1338 {
1339 xweight = wxT("bold");
1340 break;
1341 }
1342 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
1343 xfamily.c_str());
1344 if ( wxTestFontSpec(fontSpec) )
1345 {
1346 xweight = wxT("heavy");
1347 break;
1348 }
1349 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
1350 xfamily.c_str());
1351 if ( wxTestFontSpec(fontSpec) )
1352 {
1353 xweight = wxT("extrabold");
1354 break;
1355 }
1356 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
1357 xfamily.c_str());
1358 if ( wxTestFontSpec(fontSpec) )
1359 {
1360 xweight = wxT("demibold");
1361 break;
1362 }
1363 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
1364 xfamily.c_str());
1365 if ( wxTestFontSpec(fontSpec) )
1366 {
1367 xweight = wxT("black");
1368 break;
1369 }
1370 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
1371 xfamily.c_str());
1372 if ( wxTestFontSpec(fontSpec) )
1373 {
1374 xweight = wxT("ultrablack");
1375 break;
1376 }
1377 }
1378 break;
1379 case wxLIGHT:
1380 {
1381 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
1382 xfamily.c_str());
1383 if ( wxTestFontSpec(fontSpec) )
1384 {
1385 xweight = wxT("light");
1386 break;
1387 }
1388 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
1389 xfamily.c_str());
1390 if ( wxTestFontSpec(fontSpec) )
1391 {
1392 xweight = wxT("thin");
1393 break;
1394 }
1395 }
1396 break;
1397 case wxNORMAL:
1398 {
1399 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
1400 xfamily.c_str());
1401 if ( wxTestFontSpec(fontSpec) )
1402 {
1403 xweight = wxT("medium");
1404 break;
1405 }
1406 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
1407 xfamily.c_str());
1408 if ( wxTestFontSpec(fontSpec) )
1409 {
1410 xweight = wxT("normal");
1411 break;
1412 }
1413 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
1414 xfamily.c_str());
1415 if ( wxTestFontSpec(fontSpec) )
1416 {
1417 xweight = wxT("regular");
1418 break;
1419 }
1420 xweight = wxT("*");
1421 }
1422 break;
1423 default: xweight = wxT("*"); break;
1424 }
1425
1426 // if pointSize is -1, don't specify any
1427 wxString sizeSpec;
1428 if ( pointSize == -1 )
1429 {
1430 sizeSpec = wxT('*');
1431 }
1432 else
1433 {
1434 sizeSpec.Printf(wxT("%d"), pointSize);
1435 }
1436
1437 // construct the X font spec from our data
1438 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%s-*-*-*-*-%s-%s"),
1439 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
1440 sizeSpec.c_str(), xregistry.c_str(), xencoding.c_str());
1441
1442 if( xFontName )
1443 *xFontName = fontSpec;
1444
1445 return wxLoadFont(fontSpec);
1446 #endif
1447 // wxUSE_NANOX
1448 }
1449
1450 // ----------------------------------------------------------------------------
1451 // wxFontModule
1452 // ----------------------------------------------------------------------------
1453
1454 class wxFontModule : public wxModule
1455 {
1456 public:
1457 bool OnInit();
1458 void OnExit();
1459
1460 private:
1461 DECLARE_DYNAMIC_CLASS(wxFontModule)
1462 };
1463
1464 IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
1465
1466 bool wxFontModule::OnInit()
1467 {
1468 g_fontHash = new wxHashTable( wxKEY_STRING );
1469
1470 return true;
1471 }
1472
1473 void wxFontModule::OnExit()
1474 {
1475 wxDELETE(g_fontHash);
1476 }
1477
1478 #endif // GTK 2.0/1.x