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