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