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