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