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