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