made GetColourFromGTKWidget() more general, it is now used for all colours
[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
9// Licence: wxWindows license
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
79e4b627 34#ifdef __X__
4ea45e6b
VZ
35 #ifdef __VMS__
36 #pragma message disable nosimpint
37 #endif
38
39 #include <X11/Xlib.h>
40
41 #ifdef __VMS__
42 #pragma message enable nosimpint
43 #endif
79e4b627
VZ
44
45 #include "wx/utils.h" // for wxGetDisplay()
46#elif defined(__WXGTK__)
4ea45e6b
VZ
47 // we have to declare struct tm to avoid problems with first forward
48 // declaring it in C code (glib.h included from gdk.h does it) and then
49 // defining it when time.h is included from the headers below - this is
50 // known not to work at least with Sun CC 6.01
51 #include <time.h>
52
53 #include <gdk/gdk.h>
79e4b627
VZ
54#endif
55
7beba2fc
VZ
56#include "wx/fontutil.h"
57#include "wx/fontmap.h"
58#include "wx/tokenzr.h"
2e0e025e
RR
59#include "wx/hash.h"
60#include "wx/module.h"
61
62// ----------------------------------------------------------------------------
63// private data
64// ----------------------------------------------------------------------------
65
66static wxHashTable *g_fontHash = (wxHashTable*) NULL;
7beba2fc
VZ
67
68// ----------------------------------------------------------------------------
69// private functions
70// ----------------------------------------------------------------------------
71
72// define the functions to create and destroy native fonts for this toolkit
73#ifdef __X__
74 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
75 {
76 return XLoadQueryFont((Display *)wxGetDisplay(), fontSpec);
77 }
78
79 static inline void wxFreeFont(wxNativeFont font)
80 {
a5fc62a1 81 XFreeFont((Display *)wxGetDisplay(), (XFontStruct *)font);
7beba2fc
VZ
82 }
83#elif defined(__WXGTK__)
7beba2fc
VZ
84 static inline wxNativeFont wxLoadFont(const wxString& fontSpec)
85 {
97d3f0ee 86 return gdk_font_load( wxConvertWX2MB(fontSpec) );
7beba2fc
VZ
87 }
88
89 static inline void wxFreeFont(wxNativeFont font)
90 {
91 gdk_font_unref(font);
92 }
93#else
94 #error "Unknown GUI toolkit"
95#endif
96
97static bool wxTestFontSpec(const wxString& fontspec);
98
99static wxNativeFont wxLoadQueryFont(int pointSize,
100 int family,
101 int style,
102 int weight,
103 bool underlined,
104 const wxString& facename,
105 const wxString& xregistry,
30764ab5
VZ
106 const wxString& xencoding,
107 wxString* xFontName);
7beba2fc
VZ
108
109// ============================================================================
110// implementation
111// ============================================================================
112
113// ----------------------------------------------------------------------------
114// wxNativeEncodingInfo
115// ----------------------------------------------------------------------------
116
117// convert to/from the string representation: format is
1e1d0be1 118// encodingid;registry;encoding[;facename]
7beba2fc
VZ
119bool wxNativeEncodingInfo::FromString(const wxString& s)
120{
6c49baf2 121 // use ";", not "-" because it may be part of encoding name
1e1d0be1 122 wxStringTokenizer tokenizer(s, _T(";"));
1e1d0be1
VS
123
124 wxString encid = tokenizer.GetNextToken();
125 long enc;
126 if ( !encid.ToLong(&enc) )
127 return FALSE;
128 encoding = (wxFontEncoding)enc;
7beba2fc
VZ
129
130 xregistry = tokenizer.GetNextToken();
131 if ( !xregistry )
132 return FALSE;
133
134 xencoding = tokenizer.GetNextToken();
135 if ( !xencoding )
136 return FALSE;
137
138 // ok even if empty
139 facename = tokenizer.GetNextToken();
140
141 return TRUE;
142}
143
144wxString wxNativeEncodingInfo::ToString() const
145{
146 wxString s;
1e1d0be1 147 s << (long)encoding << _T(';') << xregistry << _T(';') << xencoding;
7beba2fc
VZ
148 if ( !!facename )
149 {
1e1d0be1 150 s << _T(';') << facename;
7beba2fc
VZ
151 }
152
153 return s;
154}
155
156// ----------------------------------------------------------------------------
157// common functions
158// ----------------------------------------------------------------------------
159
160bool wxGetNativeFontEncoding(wxFontEncoding encoding,
161 wxNativeEncodingInfo *info)
162{
163 wxCHECK_MSG( info, FALSE, _T("bad pointer in wxGetNativeFontEncoding") );
164
165 if ( encoding == wxFONTENCODING_DEFAULT )
166 {
167 encoding = wxFont::GetDefaultEncoding();
168 }
169
170 switch ( encoding )
171 {
172 case wxFONTENCODING_ISO8859_1:
173 case wxFONTENCODING_ISO8859_2:
174 case wxFONTENCODING_ISO8859_3:
175 case wxFONTENCODING_ISO8859_4:
176 case wxFONTENCODING_ISO8859_5:
177 case wxFONTENCODING_ISO8859_6:
178 case wxFONTENCODING_ISO8859_7:
179 case wxFONTENCODING_ISO8859_8:
180 case wxFONTENCODING_ISO8859_9:
181 case wxFONTENCODING_ISO8859_10:
182 case wxFONTENCODING_ISO8859_11:
80a24267 183 case wxFONTENCODING_ISO8859_12:
7beba2fc
VZ
184 case wxFONTENCODING_ISO8859_13:
185 case wxFONTENCODING_ISO8859_14:
186 case wxFONTENCODING_ISO8859_15:
187 {
188 int cp = encoding - wxFONTENCODING_ISO8859_1 + 1;
189 info->xregistry = wxT("iso8859");
190 info->xencoding.Printf(wxT("%d"), cp);
191 }
192 break;
193
bb84929e
VZ
194 case wxFONTENCODING_UTF8:
195 // FIXME: this is probably false, but this is how they are called on
196 // my system and I don't know what the standard XFLD is (VZ)
197 info->xregistry = wxT("iso646.1991");
198 info->xencoding = wxT("*");
199 break;
200
7beba2fc
VZ
201 case wxFONTENCODING_KOI8:
202 info->xregistry = wxT("koi8");
203
204 // we don't make distinction between koi8-r and koi8-u (so far)
205 info->xencoding = wxT("*");
206 break;
207
208 case wxFONTENCODING_CP1250:
209 case wxFONTENCODING_CP1251:
210 case wxFONTENCODING_CP1252:
211 case wxFONTENCODING_CP1253:
212 case wxFONTENCODING_CP1254:
213 case wxFONTENCODING_CP1255:
214 case wxFONTENCODING_CP1256:
215 case wxFONTENCODING_CP1257:
216 {
217 int cp = encoding - wxFONTENCODING_CP1250 + 1250;
218 info->xregistry = wxT("microsoft");
219 info->xencoding.Printf(wxT("cp%d"), cp);
220 }
221 break;
222
223 case wxFONTENCODING_SYSTEM:
224 info->xregistry =
81c67e27 225 info->xencoding = wxT("*");
7beba2fc
VZ
226 break;
227
228 default:
229 // don't know how to translate this encoding into X fontspec
230 return FALSE;
231 }
232
6b0eebc5
VS
233 info->encoding = encoding;
234
7beba2fc
VZ
235 return TRUE;
236}
237
238bool wxTestFontEncoding(const wxNativeEncodingInfo& info)
239{
240 wxString fontspec;
241 fontspec.Printf(_T("-*-%s-*-*-*-*-*-*-*-*-*-*-%s-%s"),
242 !info.facename ? _T("*") : info.facename.c_str(),
243 info.xregistry.c_str(),
244 info.xencoding.c_str());
245
246 return wxTestFontSpec(fontspec);
247}
248
249// ----------------------------------------------------------------------------
250// X-specific functions
251// ----------------------------------------------------------------------------
252
253wxNativeFont wxLoadQueryNearestFont(int pointSize,
254 int family,
255 int style,
256 int weight,
257 bool underlined,
258 const wxString &facename,
30764ab5
VZ
259 wxFontEncoding encoding,
260 wxString* xFontName)
7beba2fc 261{
97d3f0ee
VZ
262 if ( encoding == wxFONTENCODING_DEFAULT )
263 {
264 encoding = wxFont::GetDefaultEncoding();
265 }
266
7beba2fc
VZ
267 // first determine the encoding - if the font doesn't exist at all in this
268 // encoding, it's useless to do all other approximations (i.e. size,
269 // family &c don't matter much)
270 wxNativeEncodingInfo info;
97d3f0ee 271 if ( encoding == wxFONTENCODING_SYSTEM )
81c67e27
RR
272 {
273 // This will always work so we don't test to save time
274 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
275 }
276 else
7beba2fc 277 {
81c67e27
RR
278 if ( !wxGetNativeFontEncoding(encoding, &info) ||
279 !wxTestFontEncoding(info) )
7beba2fc 280 {
1e6feb95 281#if wxUSE_FONTMAP
81c67e27 282 if ( !wxTheFontMapper->GetAltForEncoding(encoding, &info) )
1e6feb95 283#endif // wxUSE_FONTMAP
81c67e27
RR
284 {
285 // unspported encoding - replace it with the default
286 //
287 // NB: we can't just return 0 from here because wxGTK code doesn't
288 // check for it (i.e. it supposes that we'll always succeed),
289 // so it would provoke a crash
290 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
291 }
97d3f0ee 292 }
7beba2fc 293 }
6c49baf2 294
81c67e27 295 // OK, we have the correct xregistry/xencoding in info structure
30764ab5
VZ
296 wxNativeFont font = 0;
297
298 // if we already have the X font name, try to use it
299 if( xFontName && !xFontName->IsEmpty() )
6c49baf2
VZ
300 {
301 //
302 // Make sure point size is correct for scale factor.
303 //
304 wxStringTokenizer tokenizer(*xFontName, _T("-"), wxTOKEN_RET_DELIMS);
305 wxString newFontName;
306
307 for(int i = 0; i < 8; i++)
308 newFontName += tokenizer.NextToken();
309
310 (void) tokenizer.NextToken();
311
312 newFontName += wxString::Format("%d-", pointSize);
313
314 while(tokenizer.HasMoreTokens())
315 newFontName += tokenizer.GetNextToken();
316
317 font = wxLoadFont(newFontName);
318
319 if(font)
320 *xFontName = newFontName;
321 }
30764ab5 322
f139dfe8 323 // try to load exactly the font requested first
30764ab5 324 if( !font )
f139dfe8 325 {
30764ab5 326 font = wxLoadQueryFont( pointSize, family, style, weight,
f139dfe8 327 underlined, facename,
30764ab5
VZ
328 info.xregistry, info.xencoding,
329 xFontName );
f139dfe8 330 }
7beba2fc
VZ
331
332 if ( !font )
333 {
334 // search up and down by stepsize 10
335 int max_size = pointSize + 20 * (1 + (pointSize/180));
336 int min_size = pointSize - 20 * (1 + (pointSize/180));
337
338 int i;
339
340 // Search for smaller size (approx.)
341 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
342 {
343 font = wxLoadQueryFont(i, family, style, weight, underlined,
30764ab5
VZ
344 facename, info.xregistry, info.xencoding,
345 xFontName);
7beba2fc
VZ
346 }
347
348 // Search for larger size (approx.)
349 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
350 {
351 font = wxLoadQueryFont(i, family, style, weight, underlined,
30764ab5
VZ
352 facename, info.xregistry, info.xencoding,
353 xFontName);
7beba2fc
VZ
354 }
355
356 // Try default family
357 if ( !font && family != wxDEFAULT )
358 {
359 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
360 underlined, facename,
30764ab5
VZ
361 info.xregistry, info.xencoding,
362 xFontName );
7beba2fc
VZ
363 }
364
f139dfe8
VZ
365 // ignore size, family, style and weight but try to find font with the
366 // given facename and encoding
7beba2fc
VZ
367 if ( !font )
368 {
369 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
370 underlined, facename,
30764ab5
VZ
371 info.xregistry, info.xencoding,
372 xFontName);
7beba2fc 373
f139dfe8
VZ
374 // ignore family as well
375 if ( !font )
376 {
377 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
378 underlined, wxEmptyString,
379 info.xregistry, info.xencoding,
380 xFontName);
381
382 // if it still failed, try to get the font of any size but
383 // with the requested encoding: this can happen if the
384 // encoding is only available in one size which happens to be
385 // different from 120
386 if ( !font )
387 {
388 font = wxLoadQueryFont(-1, wxDEFAULT, wxNORMAL, wxNORMAL,
389 FALSE, wxEmptyString,
390 info.xregistry, info.xencoding,
391 xFontName);
392
393 // this should never happen as we had tested for it in the
394 // very beginning, but if it does, do return something non
395 // NULL or we'd crash in wxFont code
396 if ( !font )
397 {
398 wxFAIL_MSG( _T("this encoding should be available!") );
399
400 font = wxLoadQueryFont(-1,
401 wxDEFAULT, wxNORMAL, wxNORMAL,
402 FALSE, wxEmptyString,
403 _T("*"), _T("*"),
404 xFontName);
405 }
406 }
407 }
7beba2fc
VZ
408 }
409 }
410
411 return font;
412}
413
414// ----------------------------------------------------------------------------
415// private functions
416// ----------------------------------------------------------------------------
417
418// returns TRUE if there are any fonts matching this font spec
419static bool wxTestFontSpec(const wxString& fontspec)
420{
97d3f0ee
VZ
421 // some X servers will fail to load this font because there are too many
422 // matches so we must test explicitly for this
423 if ( fontspec == _T("-*-*-*-*-*-*-*-*-*-*-*-*-*-*") )
424 {
425 return TRUE;
426 }
427
2e0e025e
RR
428 wxNativeFont test = (wxNativeFont) g_fontHash->Get( fontspec );
429 if (test)
430 {
2e0e025e
RR
431 return TRUE;
432 }
433
434 test = wxLoadFont(fontspec);
435 g_fontHash->Put( fontspec, (wxObject*) test );
6c49baf2 436
7beba2fc
VZ
437 if ( test )
438 {
439 wxFreeFont(test);
440
441 return TRUE;
442 }
443 else
444 {
445 return FALSE;
446 }
447}
448
449static wxNativeFont wxLoadQueryFont(int pointSize,
450 int family,
451 int style,
452 int weight,
453 bool WXUNUSED(underlined),
454 const wxString& facename,
455 const wxString& xregistry,
30764ab5
VZ
456 const wxString& xencoding,
457 wxString* xFontName)
7beba2fc
VZ
458{
459 wxString xfamily;
460 switch (family)
461 {
462 case wxDECORATIVE: xfamily = wxT("lucida"); break;
463 case wxROMAN: xfamily = wxT("times"); break;
464 case wxMODERN: xfamily = wxT("courier"); break;
465 case wxSWISS: xfamily = wxT("helvetica"); break;
466 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
467 case wxSCRIPT: xfamily = wxT("utopia"); break;
468 default: xfamily = wxT("*");
469 }
470
471 wxString fontSpec;
472 if (!facename.IsEmpty())
473 {
474 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
475 facename.c_str());
476
477 if ( wxTestFontSpec(fontSpec) )
478 {
479 xfamily = facename;
480 }
481 //else: no such family, use default one instead
482 }
483
484 wxString xstyle;
485 switch (style)
486 {
f9dbf34f
VZ
487 case wxSLANT:
488 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
489 xfamily.c_str());
490 if ( wxTestFontSpec(fontSpec) )
491 {
492 xstyle = wxT("o");
493 break;
494 }
495 // fall through - try wxITALIC now
496
497 case wxITALIC:
498 fontSpec.Printf(wxT("-*-%s-*-i-*-*-*-*-*-*-*-*-*-*"),
499 xfamily.c_str());
500 if ( wxTestFontSpec(fontSpec) )
501 {
502 xstyle = wxT("i");
503 }
504 else if ( style == wxITALIC ) // and not wxSLANT
505 {
506 // try wxSLANT
507 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
508 xfamily.c_str());
509 if ( wxTestFontSpec(fontSpec) )
510 {
511 xstyle = wxT("o");
512 }
513 else
514 {
515 // no italic, no slant - leave default
516 xstyle = wxT("*");
517 }
518 }
519 break;
520
521 default:
522 wxFAIL_MSG(_T("unknown font style"));
523 // fall back to normal
524
525 case wxNORMAL:
526 xstyle = wxT("r");
527 break;
7beba2fc
VZ
528 }
529
530 wxString xweight;
531 switch (weight)
532 {
533 case wxBOLD:
534 {
535 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
536 xfamily.c_str());
537 if ( wxTestFontSpec(fontSpec) )
538 {
539 xweight = wxT("bold");
540 break;
541 }
542 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
543 xfamily.c_str());
544 if ( wxTestFontSpec(fontSpec) )
545 {
546 xweight = wxT("heavy");
547 break;
548 }
549 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
550 xfamily.c_str());
551 if ( wxTestFontSpec(fontSpec) )
552 {
553 xweight = wxT("extrabold");
554 break;
555 }
556 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
557 xfamily.c_str());
558 if ( wxTestFontSpec(fontSpec) )
559 {
560 xweight = wxT("demibold");
561 break;
562 }
563 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
564 xfamily.c_str());
565 if ( wxTestFontSpec(fontSpec) )
566 {
567 xweight = wxT("black");
568 break;
569 }
570 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
571 xfamily.c_str());
572 if ( wxTestFontSpec(fontSpec) )
573 {
574 xweight = wxT("ultrablack");
575 break;
576 }
577 }
578 break;
579 case wxLIGHT:
580 {
581 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
582 xfamily.c_str());
583 if ( wxTestFontSpec(fontSpec) )
584 {
585 xweight = wxT("light");
586 break;
587 }
588 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
589 xfamily.c_str());
590 if ( wxTestFontSpec(fontSpec) )
591 {
592 xweight = wxT("thin");
593 break;
594 }
595 }
596 break;
597 case wxNORMAL:
598 {
599 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
600 xfamily.c_str());
601 if ( wxTestFontSpec(fontSpec) )
602 {
603 xweight = wxT("medium");
604 break;
605 }
606 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
607 xfamily.c_str());
608 if ( wxTestFontSpec(fontSpec) )
609 {
610 xweight = wxT("normal");
611 break;
612 }
613 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
614 xfamily.c_str());
615 if ( wxTestFontSpec(fontSpec) )
616 {
617 xweight = wxT("regular");
618 break;
619 }
620 xweight = wxT("*");
621 }
622 break;
623 default: xweight = wxT("*"); break;
624 }
625
f139dfe8
VZ
626 // if pointSize is -1, don't specify any
627 wxString sizeSpec;
628 if ( fontSpec == -1 )
629 {
630 sizeSpec = _T('*');
631 }
632 else
633 {
634 sizeSpec.Printf(_T("%d"), pointSize);
635 }
636
7beba2fc 637 // construct the X font spec from our data
f139dfe8 638 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%s-*-*-*-*-%s-%s"),
7beba2fc 639 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
f139dfe8 640 sizeSpec.c_str(), xregistry.c_str(), xencoding.c_str());
7beba2fc 641
30764ab5
VZ
642 if( xFontName )
643 *xFontName = fontSpec;
644
7beba2fc
VZ
645 return wxLoadFont(fontSpec);
646}
647
2e0e025e
RR
648// ----------------------------------------------------------------------------
649// wxFontModule
650// ----------------------------------------------------------------------------
651
652class wxFontModule : public wxModule
653{
654public:
655 bool OnInit();
656 void OnExit();
657
658private:
659 DECLARE_DYNAMIC_CLASS(wxFontModule)
660};
661
662IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
663
664bool wxFontModule::OnInit()
665{
666 g_fontHash = new wxHashTable( wxKEY_STRING );
667
668 return TRUE;
669}
670
671void wxFontModule::OnExit()
672{
673 delete g_fontHash;
674
675 g_fontHash = (wxHashTable *)NULL;
676}