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