Applied patch by Johan van Zyl
[wxWidgets.git] / src / motif / font.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/font.cpp
3 // Purpose: wxFont class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "font.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #include "wx/defs.h"
28
29 #ifdef __VMS
30 #pragma message disable nosimpint
31 #include "wx/vms_x_fix.h"
32 #endif
33 #include <Xm/Xm.h>
34 #ifdef __VMS
35 #pragma message enable nosimpint
36 #endif
37
38 #include "wx/string.h"
39 #include "wx/font.h"
40 #include "wx/gdicmn.h"
41 #include "wx/utils.h" // for wxGetDisplay()
42 #include "wx/fontutil.h" // for wxNativeFontInfo
43 #include "wx/tokenzr.h"
44 #include "wx/settings.h"
45 #include "wx/motif/private.h"
46
47 IMPLEMENT_DYNAMIC_CLASS(wxFont, wxGDIObject)
48
49 #if wxCHECK_MOTIF_VERSION( 2, 0 ) && !wxCHECK_LESSTIF()
50 #define wxUSE_RENDER_TABLE 1
51 #else
52 #define wxUSE_RENDER_TABLE 0
53 #endif
54
55 // ----------------------------------------------------------------------------
56 // private classes
57 // ----------------------------------------------------------------------------
58
59 // For every wxFont, there must be a font for each display and scale requested.
60 // So these objects are stored in wxFontRefData::m_fonts
61 class wxXFont : public wxObject
62 {
63 public:
64 wxXFont();
65 ~wxXFont();
66
67 WXFontStructPtr m_fontStruct; // XFontStruct
68 #if !wxUSE_RENDER_TABLE
69 WXFontList m_fontList; // Motif XmFontList
70 #else // if wxUSE_RENDER_TABLE
71 WXRenderTable m_renderTable; // Motif XmRenderTable
72 #endif
73 WXDisplay* m_display; // XDisplay
74 int m_scale; // Scale * 100
75 };
76
77 class wxFontRefData: public wxGDIRefData
78 {
79 friend class wxFont;
80
81 public:
82 wxFontRefData(int size = wxDEFAULT,
83 int family = wxDEFAULT,
84 int style = wxDEFAULT,
85 int weight = wxDEFAULT,
86 bool underlined = false,
87 const wxString& faceName = wxEmptyString,
88 wxFontEncoding encoding = wxFONTENCODING_DEFAULT)
89 {
90 Init(size, family, style, weight, underlined, faceName, encoding);
91 }
92
93 wxFontRefData(const wxFontRefData& data)
94 {
95 Init(data.m_pointSize, data.m_family, data.m_style, data.m_weight,
96 data.m_underlined, data.m_faceName, data.m_encoding);
97 }
98
99 ~wxFontRefData();
100
101 protected:
102 // common part of all ctors
103 void Init(int size,
104 int family,
105 int style,
106 int weight,
107 bool underlined,
108 const wxString& faceName,
109 wxFontEncoding encoding);
110
111 // font attributes
112 int m_pointSize;
113 int m_family;
114 int m_style;
115 int m_weight;
116 bool m_underlined;
117 wxString m_faceName;
118 wxFontEncoding m_encoding;
119
120 wxNativeFontInfo m_nativeFontInfo;
121
122 // A list of wxXFonts
123 wxList m_fonts;
124 };
125
126 // ============================================================================
127 // implementation
128 // ============================================================================
129
130 // ----------------------------------------------------------------------------
131 // wxXFont
132 // ----------------------------------------------------------------------------
133
134 wxXFont::wxXFont()
135 {
136 m_fontStruct = (WXFontStructPtr) 0;
137 #if !wxUSE_RENDER_TABLE
138 m_fontList = (WXFontList) 0;
139 #else // if wxUSE_RENDER_TABLE
140 m_renderTable = (WXRenderTable) 0;
141 #endif
142 m_display = (WXDisplay*) 0;
143 m_scale = 100;
144 }
145
146 wxXFont::~wxXFont()
147 {
148 #if !wxUSE_RENDER_TABLE
149 if (m_fontList)
150 XmFontListFree ((XmFontList) m_fontList);
151 m_fontList = NULL;
152 #else // if wxUSE_RENDER_TABLE
153 if (m_renderTable)
154 XmRenderTableFree ((XmRenderTable) m_renderTable);
155 m_renderTable = NULL;
156 #endif
157
158 // TODO: why does freeing the font produce a segv???
159 // Note that XFreeFont wasn't called in wxWin 1.68 either.
160 // MBN: probably some interaction with fonts being still
161 // in use in some widgets...
162 // XFontStruct* fontStruct = (XFontStruct*) m_fontStruct;
163 // XFreeFont((Display*) m_display, fontStruct);
164 }
165
166 // ----------------------------------------------------------------------------
167 // wxFontRefData
168 // ----------------------------------------------------------------------------
169
170 void wxFontRefData::Init(int pointSize,
171 int family,
172 int style,
173 int weight,
174 bool underlined,
175 const wxString& faceName,
176 wxFontEncoding encoding)
177 {
178 if (family == wxDEFAULT)
179 m_family = wxSWISS;
180 else
181 m_family = family;
182
183 m_faceName = faceName;
184
185 if (style == wxDEFAULT)
186 m_style = wxNORMAL;
187 else
188 m_style = style;
189
190 if (weight == wxDEFAULT)
191 m_weight = wxNORMAL;
192 else
193 m_weight = weight;
194
195 if (pointSize == wxDEFAULT)
196 m_pointSize = 12;
197 else
198 m_pointSize = pointSize;
199
200 m_underlined = underlined;
201 m_encoding = encoding;
202 }
203
204 wxFontRefData::~wxFontRefData()
205 {
206 wxList::compatibility_iterator node = m_fonts.GetFirst();
207 while (node)
208 {
209 wxXFont* f = (wxXFont*) node->GetData();
210 delete f;
211 node = node->GetNext();
212 }
213 m_fonts.Clear();
214 }
215
216 // ----------------------------------------------------------------------------
217 // wxFont
218 // ----------------------------------------------------------------------------
219
220 wxFont::wxFont(const wxNativeFontInfo& info)
221 {
222 Init();
223
224 (void)Create(info.GetXFontName());
225 }
226
227 void wxFont::Init()
228 {
229 }
230
231 bool wxFont::Create(int pointSize,
232 int family,
233 int style,
234 int weight,
235 bool underlined,
236 const wxString& faceName,
237 wxFontEncoding encoding)
238 {
239 UnRef();
240 m_refData = new wxFontRefData(pointSize, family, style, weight,
241 underlined, faceName, encoding);
242
243 RealizeResource();
244
245 return true;
246 }
247
248 bool wxFont::Create(const wxString& fontname, wxFontEncoding enc)
249 {
250 if( !fontname )
251 {
252 *this = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT);
253 return true;
254 }
255
256 m_refData = new wxFontRefData();
257
258 M_FONTDATA->m_nativeFontInfo.SetXFontName(fontname); // X font name
259
260 wxString tmp;
261
262 wxStringTokenizer tn( fontname, wxT("-") );
263
264 tn.GetNextToken(); // skip initial empty token
265 tn.GetNextToken(); // foundry
266
267
268 M_FONTDATA->m_faceName = tn.GetNextToken(); // family
269
270 tmp = tn.GetNextToken().MakeUpper(); // weight
271 if (tmp == wxT("BOLD")) M_FONTDATA->m_weight = wxBOLD;
272 if (tmp == wxT("BLACK")) M_FONTDATA->m_weight = wxBOLD;
273 if (tmp == wxT("EXTRABOLD")) M_FONTDATA->m_weight = wxBOLD;
274 if (tmp == wxT("DEMIBOLD")) M_FONTDATA->m_weight = wxBOLD;
275 if (tmp == wxT("ULTRABOLD")) M_FONTDATA->m_weight = wxBOLD;
276
277 if (tmp == wxT("LIGHT")) M_FONTDATA->m_weight = wxLIGHT;
278 if (tmp == wxT("THIN")) M_FONTDATA->m_weight = wxLIGHT;
279
280 tmp = tn.GetNextToken().MakeUpper(); // slant
281 if (tmp == wxT("I")) M_FONTDATA->m_style = wxITALIC;
282 if (tmp == wxT("O")) M_FONTDATA->m_style = wxITALIC;
283
284 tn.GetNextToken(); // set width
285 tn.GetNextToken(); // add. style
286 tn.GetNextToken(); // pixel size
287
288 tmp = tn.GetNextToken(); // pointsize
289 if (tmp != wxT("*"))
290 {
291 long num = wxStrtol (tmp.c_str(), (wxChar **) NULL, 10);
292 M_FONTDATA->m_pointSize = (int)(num / 10);
293 }
294
295 tn.GetNextToken(); // x-res
296 tn.GetNextToken(); // y-res
297
298 tmp = tn.GetNextToken().MakeUpper(); // spacing
299
300 if (tmp == wxT("M"))
301 M_FONTDATA->m_family = wxMODERN;
302 else if (M_FONTDATA->m_faceName == wxT("TIMES"))
303 M_FONTDATA->m_family = wxROMAN;
304 else if (M_FONTDATA->m_faceName == wxT("HELVETICA"))
305 M_FONTDATA->m_family = wxSWISS;
306 else if (M_FONTDATA->m_faceName == wxT("LUCIDATYPEWRITER"))
307 M_FONTDATA->m_family = wxTELETYPE;
308 else if (M_FONTDATA->m_faceName == wxT("LUCIDA"))
309 M_FONTDATA->m_family = wxDECORATIVE;
310 else if (M_FONTDATA->m_faceName == wxT("UTOPIA"))
311 M_FONTDATA->m_family = wxSCRIPT;
312
313 tn.GetNextToken(); // avg width
314
315 // deal with font encoding
316 M_FONTDATA->m_encoding = enc;
317 if ( M_FONTDATA->m_encoding == wxFONTENCODING_SYSTEM )
318 {
319 wxString registry = tn.GetNextToken().MakeUpper(),
320 encoding = tn.GetNextToken().MakeUpper();
321
322 if ( registry == _T("ISO8859") )
323 {
324 int cp;
325 if ( wxSscanf(encoding, wxT("%d"), &cp) == 1 )
326 {
327 M_FONTDATA->m_encoding =
328 (wxFontEncoding)(wxFONTENCODING_ISO8859_1 + cp - 1);
329 }
330 }
331 else if ( registry == _T("MICROSOFT") )
332 {
333 int cp;
334 if ( wxSscanf(encoding, wxT("cp125%d"), &cp) == 1 )
335 {
336 M_FONTDATA->m_encoding =
337 (wxFontEncoding)(wxFONTENCODING_CP1250 + cp);
338 }
339 }
340 else if ( registry == _T("KOI8") )
341 {
342 M_FONTDATA->m_encoding = wxFONTENCODING_KOI8;
343 }
344 //else: unknown encoding - may be give a warning here?
345 else
346 return false;
347 }
348 return true;
349 }
350
351 wxFont::~wxFont()
352 {
353 }
354
355 // ----------------------------------------------------------------------------
356 // change the font attributes
357 // ----------------------------------------------------------------------------
358
359 void wxFont::Unshare()
360 {
361 // Don't change shared data
362 if (!m_refData)
363 {
364 m_refData = new wxFontRefData();
365 }
366 else
367 {
368 wxFontRefData* ref = new wxFontRefData(*(wxFontRefData*)m_refData);
369 UnRef();
370 m_refData = ref;
371 }
372 }
373
374 void wxFont::SetPointSize(int pointSize)
375 {
376 Unshare();
377
378 M_FONTDATA->m_pointSize = pointSize;
379 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
380
381 RealizeResource();
382 }
383
384 void wxFont::SetFamily(int family)
385 {
386 Unshare();
387
388 M_FONTDATA->m_family = family;
389 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
390
391 RealizeResource();
392 }
393
394 void wxFont::SetStyle(int style)
395 {
396 Unshare();
397
398 M_FONTDATA->m_style = style;
399 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
400
401 RealizeResource();
402 }
403
404 void wxFont::SetWeight(int weight)
405 {
406 Unshare();
407
408 M_FONTDATA->m_weight = weight;
409 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
410
411 RealizeResource();
412 }
413
414 void wxFont::SetFaceName(const wxString& faceName)
415 {
416 Unshare();
417
418 M_FONTDATA->m_faceName = faceName;
419 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
420
421 RealizeResource();
422 }
423
424 void wxFont::SetUnderlined(bool underlined)
425 {
426 Unshare();
427
428 M_FONTDATA->m_underlined = underlined;
429
430 RealizeResource();
431 }
432
433 void wxFont::SetEncoding(wxFontEncoding encoding)
434 {
435 Unshare();
436
437 M_FONTDATA->m_encoding = encoding;
438 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
439
440 RealizeResource();
441 }
442
443 void wxFont::DoSetNativeFontInfo(const wxNativeFontInfo& info)
444 {
445 Unshare();
446
447 M_FONTDATA->m_nativeFontInfo = info;
448 }
449
450 // ----------------------------------------------------------------------------
451 // query font attributes
452 // ----------------------------------------------------------------------------
453
454 int wxFont::GetPointSize() const
455 {
456 wxCHECK_MSG( Ok(), 0, wxT("invalid font") );
457
458 return M_FONTDATA->m_pointSize;
459 }
460
461 wxString wxFont::GetFaceName() const
462 {
463 wxCHECK_MSG( Ok(), wxT(""), wxT("invalid font") );
464
465 return M_FONTDATA->m_faceName ;
466 }
467
468 int wxFont::GetFamily() const
469 {
470 wxCHECK_MSG( Ok(), 0, wxT("invalid font") );
471
472 return M_FONTDATA->m_family;
473 }
474
475 int wxFont::GetStyle() const
476 {
477 wxCHECK_MSG( Ok(), 0, wxT("invalid font") );
478
479 return M_FONTDATA->m_style;
480 }
481
482 int wxFont::GetWeight() const
483 {
484 wxCHECK_MSG( Ok(), 0, wxT("invalid font") );
485
486 return M_FONTDATA->m_weight;
487 }
488
489 bool wxFont::GetUnderlined() const
490 {
491 wxCHECK_MSG( Ok(), false, wxT("invalid font") );
492
493 return M_FONTDATA->m_underlined;
494 }
495
496 wxFontEncoding wxFont::GetEncoding() const
497 {
498 wxCHECK_MSG( Ok(), wxFONTENCODING_DEFAULT, wxT("invalid font") );
499
500 return M_FONTDATA->m_encoding;
501 }
502
503 const wxNativeFontInfo *wxFont::GetNativeFontInfo() const
504 {
505 wxCHECK_MSG( Ok(), (wxNativeFontInfo *)NULL, wxT("invalid font") );
506
507 if(M_FONTDATA->m_nativeFontInfo.GetXFontName().IsEmpty())
508 GetInternalFont();
509
510 return &(M_FONTDATA->m_nativeFontInfo);
511 }
512
513 // ----------------------------------------------------------------------------
514 // real implementation
515 // ----------------------------------------------------------------------------
516
517 // Find an existing, or create a new, XFontStruct
518 // based on this wxFont and the given scale. Append the
519 // font to list in the private data for future reference.
520 wxXFont* wxFont::GetInternalFont(double scale, WXDisplay* display) const
521 {
522 if ( !Ok() )
523 return (wxXFont *)NULL;
524
525 long intScale = long(scale * 100.0 + 0.5); // key for wxXFont
526 int pointSize = (M_FONTDATA->m_pointSize * 10 * intScale) / 100;
527
528 // search existing fonts first
529 wxList::compatibility_iterator node = M_FONTDATA->m_fonts.GetFirst();
530 while (node)
531 {
532 wxXFont* f = (wxXFont*) node->GetData();
533 if ((!display || (f->m_display == display)) && (f->m_scale == intScale))
534 return f;
535 node = node->GetNext();
536 }
537
538 // not found, create a new one
539 XFontStruct *font = (XFontStruct *)
540 wxLoadQueryNearestFont(pointSize,
541 M_FONTDATA->m_family,
542 M_FONTDATA->m_style,
543 M_FONTDATA->m_weight,
544 M_FONTDATA->m_underlined,
545 wxT(""),
546 M_FONTDATA->m_encoding);
547
548 if ( !font )
549 {
550 wxFAIL_MSG( wxT("Could not allocate even a default font -- something is wrong.") );
551
552 return (wxXFont*) NULL;
553 }
554
555 wxXFont* f = new wxXFont;
556 f->m_fontStruct = (WXFontStructPtr)font;
557 f->m_display = ( display ? display : wxGetDisplay() );
558 f->m_scale = intScale;
559
560 M_FONTDATA->m_fonts.Append(f);
561
562 #if !wxUSE_RENDER_TABLE
563 f->m_fontList = XmFontListCreate ((XFontStruct*) font, XmSTRING_DEFAULT_CHARSET);
564 #else // if wxUSE_RENDER_TABLE
565 XmRendition rendition;
566 XmRenderTable renderTable;
567 Arg args[5];
568 int count = 0;
569
570 XtSetArg( args[count], XmNfont, font ); ++count;
571 XtSetArg( args[count], XmNunderlineType,
572 GetUnderlined() ? XmSINGLE_LINE : XmNO_LINE ); ++count;
573 rendition = XmRenditionCreate( XmGetXmDisplay( (Display*)f->m_display ),
574 (XmStringTag)"",
575 args, count );
576 renderTable = XmRenderTableAddRenditions( NULL, &rendition, 1,
577 XmMERGE_REPLACE );
578
579 f->m_renderTable = (WXRenderTable)renderTable;
580 #endif
581
582 return f;
583 }
584
585 WXFontStructPtr wxFont::GetFontStruct(double scale, WXDisplay* display) const
586 {
587 wxXFont* f = GetInternalFont(scale, display);
588
589 return (f ? f->m_fontStruct : (WXFontStructPtr) 0);
590 }
591
592 WXFontList wxFont::GetFontList(double scale, WXDisplay* display) const
593 {
594 #if !wxUSE_RENDER_TABLE
595 wxXFont* f = GetInternalFont(scale, display);
596
597 return (f ? f->m_fontList : (WXFontList) 0);
598 #else
599 return NULL;
600 #endif
601 }
602
603 // declared in the header, can't use wxUSE_RENDER_TABLE
604 #if wxCHECK_MOTIF_VERSION( 2, 0 )
605
606 WXRenderTable wxFont::GetRenderTable(WXDisplay* display) const
607 {
608 #if wxUSE_RENDER_TABLE
609 wxXFont* f = GetInternalFont(1.0, display);
610
611 return (f ? f->m_renderTable : (WXFontList) 0);
612 #else
613 return NULL;
614 #endif
615 }
616
617 #endif
618
619 WXFontType wxFont::GetFontType(WXDisplay* display) const
620 {
621 #if wxUSE_RENDER_TABLE
622 return Ok() ? GetRenderTable(display) : NULL;
623 #else
624 return Ok() ? GetFontList(1.0, display) : NULL;
625 #endif
626 }
627
628 WXFontType wxFont::GetFontTypeC(WXDisplay* display) const
629 {
630 #if wxUSE_RENDER_TABLE
631 return Ok() ? GetRenderTable(display) : NULL;
632 #else
633 return Ok() ? XmFontListCopy( (XmFontList)GetFontList(1.0, display) ) : NULL;
634 #endif
635 }
636
637 /*static*/ WXString wxFont::GetFontTag()
638 {
639 #if wxUSE_RENDER_TABLE
640 return (WXString)XmNrenderTable;
641 #else
642 return (WXString)XmNfontList;
643 #endif
644 }