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