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