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