]> git.saurik.com Git - wxWidgets.git/blame - src/unix/fontutil.cpp
Added "set new icon" menu item to taskbar sample; updated some makefiles
[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 {
81c67e27
RR
281 if ( !wxTheFontMapper->GetAltForEncoding(encoding, &info) )
282 {
283 // unspported encoding - replace it with the default
284 //
285 // NB: we can't just return 0 from here because wxGTK code doesn't
286 // check for it (i.e. it supposes that we'll always succeed),
287 // so it would provoke a crash
288 wxGetNativeFontEncoding(wxFONTENCODING_SYSTEM, &info);
289 }
97d3f0ee 290 }
7beba2fc 291 }
6c49baf2 292
81c67e27 293 // OK, we have the correct xregistry/xencoding in info structure
30764ab5
VZ
294 wxNativeFont font = 0;
295
296 // if we already have the X font name, try to use it
297 if( xFontName && !xFontName->IsEmpty() )
6c49baf2
VZ
298 {
299 //
300 // Make sure point size is correct for scale factor.
301 //
302 wxStringTokenizer tokenizer(*xFontName, _T("-"), wxTOKEN_RET_DELIMS);
303 wxString newFontName;
304
305 for(int i = 0; i < 8; i++)
306 newFontName += tokenizer.NextToken();
307
308 (void) tokenizer.NextToken();
309
310 newFontName += wxString::Format("%d-", pointSize);
311
312 while(tokenizer.HasMoreTokens())
313 newFontName += tokenizer.GetNextToken();
314
315 font = wxLoadFont(newFontName);
316
317 if(font)
318 *xFontName = newFontName;
319 }
30764ab5
VZ
320
321 if( !font )
322 font = wxLoadQueryFont( pointSize, family, style, weight,
7beba2fc 323 underlined, facename,
30764ab5
VZ
324 info.xregistry, info.xencoding,
325 xFontName );
7beba2fc
VZ
326
327 if ( !font )
328 {
329 // search up and down by stepsize 10
330 int max_size = pointSize + 20 * (1 + (pointSize/180));
331 int min_size = pointSize - 20 * (1 + (pointSize/180));
332
333 int i;
334
335 // Search for smaller size (approx.)
336 for ( i = pointSize - 10; !font && i >= 10 && i >= min_size; i -= 10 )
337 {
338 font = wxLoadQueryFont(i, family, style, weight, underlined,
30764ab5
VZ
339 facename, info.xregistry, info.xencoding,
340 xFontName);
7beba2fc
VZ
341 }
342
343 // Search for larger size (approx.)
344 for ( i = pointSize + 10; !font && i <= max_size; i += 10 )
345 {
346 font = wxLoadQueryFont(i, family, style, weight, underlined,
30764ab5
VZ
347 facename, info.xregistry, info.xencoding,
348 xFontName);
7beba2fc
VZ
349 }
350
351 // Try default family
352 if ( !font && family != wxDEFAULT )
353 {
354 font = wxLoadQueryFont(pointSize, wxDEFAULT, style, weight,
355 underlined, facename,
30764ab5
VZ
356 info.xregistry, info.xencoding,
357 xFontName );
7beba2fc
VZ
358 }
359
360 // Bogus font I
361 if ( !font )
362 {
363 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
364 underlined, facename,
30764ab5
VZ
365 info.xregistry, info.xencoding,
366 xFontName);
7beba2fc
VZ
367 }
368
369 // Bogus font II
370 if ( !font )
371 {
372 font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL,
373 underlined, wxEmptyString,
30764ab5
VZ
374 info.xregistry, info.xencoding,
375 xFontName);
7beba2fc
VZ
376 }
377 }
378
379 return font;
380}
381
382// ----------------------------------------------------------------------------
383// private functions
384// ----------------------------------------------------------------------------
385
386// returns TRUE if there are any fonts matching this font spec
387static bool wxTestFontSpec(const wxString& fontspec)
388{
97d3f0ee
VZ
389 // some X servers will fail to load this font because there are too many
390 // matches so we must test explicitly for this
391 if ( fontspec == _T("-*-*-*-*-*-*-*-*-*-*-*-*-*-*") )
392 {
393 return TRUE;
394 }
395
2e0e025e
RR
396 wxNativeFont test = (wxNativeFont) g_fontHash->Get( fontspec );
397 if (test)
398 {
2e0e025e
RR
399 return TRUE;
400 }
401
402 test = wxLoadFont(fontspec);
403 g_fontHash->Put( fontspec, (wxObject*) test );
6c49baf2 404
7beba2fc
VZ
405 if ( test )
406 {
407 wxFreeFont(test);
408
409 return TRUE;
410 }
411 else
412 {
413 return FALSE;
414 }
415}
416
417static wxNativeFont wxLoadQueryFont(int pointSize,
418 int family,
419 int style,
420 int weight,
421 bool WXUNUSED(underlined),
422 const wxString& facename,
423 const wxString& xregistry,
30764ab5
VZ
424 const wxString& xencoding,
425 wxString* xFontName)
7beba2fc
VZ
426{
427 wxString xfamily;
428 switch (family)
429 {
430 case wxDECORATIVE: xfamily = wxT("lucida"); break;
431 case wxROMAN: xfamily = wxT("times"); break;
432 case wxMODERN: xfamily = wxT("courier"); break;
433 case wxSWISS: xfamily = wxT("helvetica"); break;
434 case wxTELETYPE: xfamily = wxT("lucidatypewriter"); break;
435 case wxSCRIPT: xfamily = wxT("utopia"); break;
436 default: xfamily = wxT("*");
437 }
438
439 wxString fontSpec;
440 if (!facename.IsEmpty())
441 {
442 fontSpec.Printf(wxT("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"),
443 facename.c_str());
444
445 if ( wxTestFontSpec(fontSpec) )
446 {
447 xfamily = facename;
448 }
449 //else: no such family, use default one instead
450 }
451
452 wxString xstyle;
453 switch (style)
454 {
f9dbf34f
VZ
455 case wxSLANT:
456 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
457 xfamily.c_str());
458 if ( wxTestFontSpec(fontSpec) )
459 {
460 xstyle = wxT("o");
461 break;
462 }
463 // fall through - try wxITALIC now
464
465 case wxITALIC:
466 fontSpec.Printf(wxT("-*-%s-*-i-*-*-*-*-*-*-*-*-*-*"),
467 xfamily.c_str());
468 if ( wxTestFontSpec(fontSpec) )
469 {
470 xstyle = wxT("i");
471 }
472 else if ( style == wxITALIC ) // and not wxSLANT
473 {
474 // try wxSLANT
475 fontSpec.Printf(wxT("-*-%s-*-o-*-*-*-*-*-*-*-*-*-*"),
476 xfamily.c_str());
477 if ( wxTestFontSpec(fontSpec) )
478 {
479 xstyle = wxT("o");
480 }
481 else
482 {
483 // no italic, no slant - leave default
484 xstyle = wxT("*");
485 }
486 }
487 break;
488
489 default:
490 wxFAIL_MSG(_T("unknown font style"));
491 // fall back to normal
492
493 case wxNORMAL:
494 xstyle = wxT("r");
495 break;
7beba2fc
VZ
496 }
497
498 wxString xweight;
499 switch (weight)
500 {
501 case wxBOLD:
502 {
503 fontSpec.Printf(wxT("-*-%s-bold-*-*-*-*-*-*-*-*-*-*-*"),
504 xfamily.c_str());
505 if ( wxTestFontSpec(fontSpec) )
506 {
507 xweight = wxT("bold");
508 break;
509 }
510 fontSpec.Printf(wxT("-*-%s-heavy-*-*-*-*-*-*-*-*-*-*-*"),
511 xfamily.c_str());
512 if ( wxTestFontSpec(fontSpec) )
513 {
514 xweight = wxT("heavy");
515 break;
516 }
517 fontSpec.Printf(wxT("-*-%s-extrabold-*-*-*-*-*-*-*-*-*-*-*"),
518 xfamily.c_str());
519 if ( wxTestFontSpec(fontSpec) )
520 {
521 xweight = wxT("extrabold");
522 break;
523 }
524 fontSpec.Printf(wxT("-*-%s-demibold-*-*-*-*-*-*-*-*-*-*-*"),
525 xfamily.c_str());
526 if ( wxTestFontSpec(fontSpec) )
527 {
528 xweight = wxT("demibold");
529 break;
530 }
531 fontSpec.Printf(wxT("-*-%s-black-*-*-*-*-*-*-*-*-*-*-*"),
532 xfamily.c_str());
533 if ( wxTestFontSpec(fontSpec) )
534 {
535 xweight = wxT("black");
536 break;
537 }
538 fontSpec.Printf(wxT("-*-%s-ultrablack-*-*-*-*-*-*-*-*-*-*-*"),
539 xfamily.c_str());
540 if ( wxTestFontSpec(fontSpec) )
541 {
542 xweight = wxT("ultrablack");
543 break;
544 }
545 }
546 break;
547 case wxLIGHT:
548 {
549 fontSpec.Printf(wxT("-*-%s-light-*-*-*-*-*-*-*-*-*-*-*"),
550 xfamily.c_str());
551 if ( wxTestFontSpec(fontSpec) )
552 {
553 xweight = wxT("light");
554 break;
555 }
556 fontSpec.Printf(wxT("-*-%s-thin-*-*-*-*-*-*-*-*-*-*-*"),
557 xfamily.c_str());
558 if ( wxTestFontSpec(fontSpec) )
559 {
560 xweight = wxT("thin");
561 break;
562 }
563 }
564 break;
565 case wxNORMAL:
566 {
567 fontSpec.Printf(wxT("-*-%s-medium-*-*-*-*-*-*-*-*-*-*-*"),
568 xfamily.c_str());
569 if ( wxTestFontSpec(fontSpec) )
570 {
571 xweight = wxT("medium");
572 break;
573 }
574 fontSpec.Printf(wxT("-*-%s-normal-*-*-*-*-*-*-*-*-*-*-*"),
575 xfamily.c_str());
576 if ( wxTestFontSpec(fontSpec) )
577 {
578 xweight = wxT("normal");
579 break;
580 }
581 fontSpec.Printf(wxT("-*-%s-regular-*-*-*-*-*-*-*-*-*-*-*"),
582 xfamily.c_str());
583 if ( wxTestFontSpec(fontSpec) )
584 {
585 xweight = wxT("regular");
586 break;
587 }
588 xweight = wxT("*");
589 }
590 break;
591 default: xweight = wxT("*"); break;
592 }
593
594 // construct the X font spec from our data
595 fontSpec.Printf(wxT("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-%s-%s"),
596 xfamily.c_str(), xweight.c_str(), xstyle.c_str(),
597 pointSize, xregistry.c_str(), xencoding.c_str());
598
30764ab5
VZ
599 if( xFontName )
600 *xFontName = fontSpec;
601
7beba2fc
VZ
602 return wxLoadFont(fontSpec);
603}
604
2e0e025e
RR
605// ----------------------------------------------------------------------------
606// wxFontModule
607// ----------------------------------------------------------------------------
608
609class wxFontModule : public wxModule
610{
611public:
612 bool OnInit();
613 void OnExit();
614
615private:
616 DECLARE_DYNAMIC_CLASS(wxFontModule)
617};
618
619IMPLEMENT_DYNAMIC_CLASS(wxFontModule, wxModule)
620
621bool wxFontModule::OnInit()
622{
623 g_fontHash = new wxHashTable( wxKEY_STRING );
624
625 return TRUE;
626}
627
628void wxFontModule::OnExit()
629{
630 delete g_fontHash;
631
632 g_fontHash = (wxHashTable *)NULL;
633}