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