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