Merge in from trunk r67662 to r64801
[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 #include "wx/utils.h" // for wxGetDisplay()
37 #include "wx/settings.h"
38 #include "wx/gdicmn.h"
39 #endif
40
41 #include "wx/fontutil.h" // for wxNativeFontInfo
42 #include "wx/tokenzr.h"
43 #include "wx/motif/private.h"
44
45 // ----------------------------------------------------------------------------
46 // private classes
47 // ----------------------------------------------------------------------------
48
49 // For every wxFont, there must be a font for each display and scale requested.
50 // So these objects are stored in wxFontRefData::m_fonts
51 class wxXFont : public wxObject
52 {
53 public:
54 wxXFont();
55 virtual ~wxXFont();
56
57 #if !wxMOTIF_NEW_FONT_HANDLING
58 WXFontStructPtr m_fontStruct; // XFontStruct
59 #endif
60 #if !wxMOTIF_USE_RENDER_TABLE
61 WXFontList m_fontList; // Motif XmFontList
62 #else // if wxMOTIF_USE_RENDER_TABLE
63 WXRenderTable m_renderTable; // Motif XmRenderTable
64 WXRendition m_rendition; // Motif XmRendition
65 #endif
66 WXDisplay* m_display; // XDisplay
67 int m_scale; // Scale * 100
68 };
69
70 class wxFontRefData: public wxGDIRefData
71 {
72 friend class wxFont;
73
74 public:
75 wxFontRefData(int size = wxDEFAULT,
76 wxFontFamily family = wxFONTFAMILY_DEFAULT,
77 wxFontStyle style = wxFONTSTYLE_NORMAL,
78 wxFontWeight weight = wxFONTWEIGHT_NORMAL,
79 bool underlined = false,
80 const wxString& faceName = wxEmptyString,
81 wxFontEncoding encoding = wxFONTENCODING_DEFAULT)
82 {
83 Init(size, family, style, weight, underlined, faceName, encoding);
84 }
85
86 wxFontRefData(const wxFontRefData& data)
87 {
88 Init(data.m_pointSize, data.m_family, data.m_style, data.m_weight,
89 data.m_underlined, data.m_faceName, data.m_encoding);
90 }
91
92 virtual ~wxFontRefData();
93
94 protected:
95 // common part of all ctors
96 void Init(int size,
97 wxFontFamily family,
98 wxFontStyle style,
99 wxFontWeight weight,
100 bool underlined,
101 const wxString& faceName,
102 wxFontEncoding encoding);
103
104 // font attributes
105 int m_pointSize;
106 wxFontFamily m_family;
107 wxFontStyle m_style;
108 wxFontWeight m_weight;
109 bool m_underlined;
110 wxString m_faceName;
111 wxFontEncoding m_encoding;
112
113 wxNativeFontInfo m_nativeFontInfo;
114
115 // A list of wxXFonts
116 wxList m_fonts;
117 };
118
119 // ============================================================================
120 // implementation
121 // ============================================================================
122
123 // ----------------------------------------------------------------------------
124 // wxXFont
125 // ----------------------------------------------------------------------------
126
127 wxXFont::wxXFont()
128 {
129 #if !wxMOTIF_NEW_FONT_HANDLING
130 m_fontStruct = (WXFontStructPtr) 0;
131 #endif
132 #if !wxMOTIF_USE_RENDER_TABLE
133 m_fontList = (WXFontList) 0;
134 #else // if wxMOTIF_USE_RENDER_TABLE
135 m_renderTable = (WXRenderTable) 0;
136 m_rendition = (WXRendition) 0;
137 #endif
138 m_display = (WXDisplay*) 0;
139 m_scale = 100;
140 }
141
142 wxXFont::~wxXFont()
143 {
144 #if !wxMOTIF_USE_RENDER_TABLE
145 if (m_fontList)
146 XmFontListFree ((XmFontList) m_fontList);
147 m_fontList = NULL;
148 #else // if wxMOTIF_USE_RENDER_TABLE
149 if (m_renderTable)
150 XmRenderTableFree ((XmRenderTable) m_renderTable);
151 m_renderTable = NULL;
152 #endif
153
154 // TODO: why does freeing the font produce a segv???
155 // Note that XFreeFont wasn't called in wxWin 1.68 either.
156 // MBN: probably some interaction with fonts being still
157 // in use in some widgets...
158 // XFontStruct* fontStruct = (XFontStruct*) m_fontStruct;
159 // XFreeFont((Display*) m_display, fontStruct);
160 }
161
162 // ----------------------------------------------------------------------------
163 // wxFontRefData
164 // ----------------------------------------------------------------------------
165
166 void wxFontRefData::Init(int pointSize,
167 wxFontFamily family,
168 wxFontStyle style,
169 wxFontWeight weight,
170 bool underlined,
171 const wxString& faceName,
172 wxFontEncoding encoding)
173 {
174 if (family == wxDEFAULT)
175 m_family = wxFONTFAMILY_SWISS;
176 else
177 m_family = family;
178
179 m_faceName = faceName;
180
181 if (style == wxDEFAULT)
182 m_style = wxFONTSTYLE_NORMAL;
183 else
184 m_style = style;
185
186 if (weight == wxDEFAULT)
187 m_weight = wxFONTWEIGHT_NORMAL;
188 else
189 m_weight = weight;
190
191 if (pointSize == wxDEFAULT)
192 m_pointSize = 12;
193 else
194 m_pointSize = pointSize;
195
196 m_underlined = underlined;
197 m_encoding = encoding;
198 }
199
200 wxFontRefData::~wxFontRefData()
201 {
202 wxList::compatibility_iterator node = m_fonts.GetFirst();
203 while (node)
204 {
205 wxXFont* f = (wxXFont*) node->GetData();
206 delete f;
207 node = node->GetNext();
208 }
209 m_fonts.Clear();
210 }
211
212 #define M_FONTDATA ((wxFontRefData*)m_refData)
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 wxFontFamily family,
225 wxFontStyle style,
226 wxFontWeight 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 = wxFONTWEIGHT_BOLD;
262 if (tmp == wxT("BLACK")) M_FONTDATA->m_weight = wxFONTWEIGHT_BOLD;
263 if (tmp == wxT("EXTRABOLD")) M_FONTDATA->m_weight = wxFONTWEIGHT_BOLD;
264 if (tmp == wxT("DEMIBOLD")) M_FONTDATA->m_weight = wxFONTWEIGHT_BOLD;
265 if (tmp == wxT("ULTRABOLD")) M_FONTDATA->m_weight = wxFONTWEIGHT_BOLD;
266
267 if (tmp == wxT("LIGHT")) M_FONTDATA->m_weight = wxFONTWEIGHT_LIGHT;
268 if (tmp == wxT("THIN")) M_FONTDATA->m_weight = wxFONTWEIGHT_LIGHT;
269
270 tmp = tn.GetNextToken().MakeUpper(); // slant
271 if (tmp == wxT("I")) M_FONTDATA->m_style = wxFONTSTYLE_ITALIC;
272 if (tmp == wxT("O")) M_FONTDATA->m_style = wxFONTSTYLE_ITALIC;
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.mb_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 = wxFONTFAMILY_MODERN;
292 else if (M_FONTDATA->m_faceName == wxT("TIMES"))
293 M_FONTDATA->m_family = wxFONTFAMILY_ROMAN;
294 else if (M_FONTDATA->m_faceName == wxT("HELVETICA"))
295 M_FONTDATA->m_family = wxFONTFAMILY_SWISS;
296 else if (M_FONTDATA->m_faceName == wxT("LUCIDATYPEWRITER"))
297 M_FONTDATA->m_family = wxFONTFAMILY_TELETYPE;
298 else if (M_FONTDATA->m_faceName == wxT("LUCIDA"))
299 M_FONTDATA->m_family = wxFONTFAMILY_DECORATIVE;
300 else if (M_FONTDATA->m_faceName == wxT("UTOPIA"))
301 M_FONTDATA->m_family = wxFONTFAMILY_SCRIPT;
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 == wxT("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 == wxT("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 == wxT("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 wxGDIRefData *wxFont::CreateGDIRefData() const
346 {
347 return new wxFontRefData;
348 }
349
350 wxGDIRefData *wxFont::CloneGDIRefData(const wxGDIRefData *data) const
351 {
352 return new wxFontRefData(*static_cast<const wxFontRefData *>(data));
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
382 void wxFont::SetFamily(wxFontFamily family)
383 {
384 Unshare();
385
386 M_FONTDATA->m_family = family;
387 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
388 }
389
390 void wxFont::SetStyle(wxFontStyle style)
391 {
392 Unshare();
393
394 M_FONTDATA->m_style = style;
395 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
396 }
397
398 void wxFont::SetWeight(wxFontWeight weight)
399 {
400 Unshare();
401
402 M_FONTDATA->m_weight = weight;
403 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
404 }
405
406 bool wxFont::SetFaceName(const wxString& faceName)
407 {
408 Unshare();
409
410 M_FONTDATA->m_faceName = faceName;
411 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
412
413 return wxFontBase::SetFaceName(faceName);
414 }
415
416 void wxFont::SetUnderlined(bool underlined)
417 {
418 Unshare();
419
420 M_FONTDATA->m_underlined = underlined;
421 }
422
423 void wxFont::SetEncoding(wxFontEncoding encoding)
424 {
425 Unshare();
426
427 M_FONTDATA->m_encoding = encoding;
428 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now
429 }
430
431 void wxFont::DoSetNativeFontInfo(const wxNativeFontInfo& info)
432 {
433 Unshare();
434
435 M_FONTDATA->m_nativeFontInfo = info;
436 }
437
438 // ----------------------------------------------------------------------------
439 // query font attributes
440 // ----------------------------------------------------------------------------
441
442 int wxFont::GetPointSize() const
443 {
444 wxCHECK_MSG( IsOk(), 0, wxT("invalid font") );
445
446 return M_FONTDATA->m_pointSize;
447 }
448
449 wxString wxFont::GetFaceName() const
450 {
451 wxCHECK_MSG( IsOk(), wxEmptyString, wxT("invalid font") );
452
453 return M_FONTDATA->m_faceName ;
454 }
455
456 wxFontFamily wxFont::DoGetFamily() const
457 {
458 return M_FONTDATA->m_family;
459 }
460
461 wxFontStyle wxFont::GetStyle() const
462 {
463 wxCHECK_MSG( IsOk(), wxFONTSTYLE_MAX, wxT("invalid font") );
464
465 return M_FONTDATA->m_style;
466 }
467
468 wxFontWeight wxFont::GetWeight() const
469 {
470 wxCHECK_MSG( IsOk(), wxFONTWEIGHT_MAX, wxT("invalid font") );
471
472 return M_FONTDATA->m_weight;
473 }
474
475 bool wxFont::GetUnderlined() const
476 {
477 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
478
479 return M_FONTDATA->m_underlined;
480 }
481
482 wxFontEncoding wxFont::GetEncoding() const
483 {
484 wxCHECK_MSG( IsOk(), wxFONTENCODING_DEFAULT, wxT("invalid font") );
485
486 return M_FONTDATA->m_encoding;
487 }
488
489 const wxNativeFontInfo *wxFont::GetNativeFontInfo() const
490 {
491 wxCHECK_MSG( IsOk(), NULL, wxT("invalid font") );
492
493 if(M_FONTDATA->m_nativeFontInfo.GetXFontName().empty())
494 GetInternalFont();
495
496 return &(M_FONTDATA->m_nativeFontInfo);
497 }
498
499 // ----------------------------------------------------------------------------
500 // real implementation
501 // ----------------------------------------------------------------------------
502
503 // Find an existing, or create a new, XFontStruct
504 // based on this wxFont and the given scale. Append the
505 // font to list in the private data for future reference.
506 wxXFont* wxFont::GetInternalFont(double scale, WXDisplay* display) const
507 {
508 if ( !IsOk() )
509 return NULL;
510
511 long intScale = long(scale * 100.0 + 0.5); // key for wxXFont
512 int pointSize = (M_FONTDATA->m_pointSize * 10 * intScale) / 100;
513
514 // search existing fonts first
515 wxList::compatibility_iterator node = M_FONTDATA->m_fonts.GetFirst();
516 while (node)
517 {
518 wxXFont* f = (wxXFont*) node->GetData();
519 if ((!display || (f->m_display == display)) && (f->m_scale == intScale))
520 return f;
521 node = node->GetNext();
522 }
523
524 // not found, create a new one
525 wxString xFontSpec;
526 XFontStruct *font = (XFontStruct *)
527 wxLoadQueryNearestFont(pointSize,
528 M_FONTDATA->m_family,
529 M_FONTDATA->m_style,
530 M_FONTDATA->m_weight,
531 M_FONTDATA->m_underlined,
532 wxT(""),
533 M_FONTDATA->m_encoding,
534 &xFontSpec);
535
536 if ( !font )
537 {
538 wxFAIL_MSG( wxT("Could not allocate even a default font -- something is wrong.") );
539
540 return NULL;
541 }
542
543 wxXFont* f = new wxXFont;
544 #if wxMOTIF_NEW_FONT_HANDLING
545 XFreeFont( (Display*) display, font );
546 #else
547 f->m_fontStruct = (WXFontStructPtr)font;
548 #endif
549 f->m_display = ( display ? display : wxGetDisplay() );
550 f->m_scale = intScale;
551
552 #if wxMOTIF_USE_RENDER_TABLE
553 XmRendition rendition;
554 XmRenderTable renderTable;
555 Arg args[5];
556 int count = 0;
557
558 #if wxMOTIF_NEW_FONT_HANDLING
559 char* fontSpec = wxStrdup(xFontSpec.mb_str());
560 XtSetArg( args[count], XmNfontName, fontSpec ); ++count;
561 XtSetArg( args[count], XmNfontType, XmFONT_IS_FONTSET ); ++count;
562 #else
563 XtSetArg( args[count], XmNfont, font ); ++count;
564 #endif
565 XtSetArg( args[count], XmNunderlineType,
566 GetUnderlined() ? XmSINGLE_LINE : XmNO_LINE ); ++count;
567 rendition = XmRenditionCreate( XmGetXmDisplay( (Display*)f->m_display ),
568 (XmStringTag)"",
569 args, count );
570 renderTable = XmRenderTableAddRenditions( NULL, &rendition, 1,
571 XmMERGE_REPLACE );
572
573 f->m_renderTable = (WXRenderTable)renderTable;
574 f->m_rendition = (WXRendition)rendition;
575 wxASSERT( f->m_renderTable != NULL );
576 #else // if !wxMOTIF_USE_RENDER_TABLE
577 f->m_fontList = XmFontListCreate ((XFontStruct*) font, XmSTRING_DEFAULT_CHARSET);
578 wxASSERT( f->m_fontList != NULL );
579 #endif
580
581 M_FONTDATA->m_fonts.Append(f);
582
583 return f;
584 }
585
586 #if !wxMOTIF_NEW_FONT_HANDLING
587
588 WXFontStructPtr wxFont::GetFontStruct(double scale, WXDisplay* display) const
589 {
590 wxXFont* f = GetInternalFont(scale, display);
591
592 return (f ? f->m_fontStruct : (WXFontStructPtr) 0);
593 }
594
595 #endif
596
597 #if !wxMOTIF_USE_RENDER_TABLE
598
599 WXFontList wxFont::GetFontList(double scale, WXDisplay* display) const
600 {
601 wxXFont* f = GetInternalFont(scale, display);
602
603 return (f ? f->m_fontList : (WXFontList) 0);
604 }
605
606 #else // if wxMOTIF_USE_RENDER_TABLE
607
608 WXRenderTable wxFont::GetRenderTable(WXDisplay* display) const
609 {
610 wxXFont* f = GetInternalFont(1.0, display);
611
612 return (f ? f->m_renderTable : (WXRenderTable) 0);
613 }
614
615 #endif // wxMOTIF_USE_RENDER_TABLE
616
617 WXFontType wxFont::GetFontType(WXDisplay* display) const
618 {
619 #if wxMOTIF_USE_RENDER_TABLE
620 return IsOk() ? GetRenderTable(display) : NULL;
621 #else
622 return IsOk() ? GetFontList(1.0, display) : NULL;
623 #endif
624 }
625
626 WXFontType wxFont::GetFontTypeC(WXDisplay* display) const
627 {
628 #if wxMOTIF_USE_RENDER_TABLE
629 return IsOk() ? GetRenderTable(display) : NULL;
630 #else
631 return IsOk() ? XmFontListCopy( (XmFontList)GetFontList(1.0, display) ) : NULL;
632 #endif
633 }
634
635 /*static*/ WXString wxFont::GetFontTag()
636 {
637 #if wxMOTIF_USE_RENDER_TABLE
638 return (WXString)XmNrenderTable;
639 #else
640 return (WXString)XmNfontList;
641 #endif
642 }
643
644 #if wxMOTIF_USE_RENDER_TABLE
645
646 WXFontSet wxFont::GetFontSet(double scale, WXDisplay* display) const
647 {
648 wxXFont* f = GetInternalFont(scale, display);
649
650 if( !f ) return (WXFontSet) 0;
651
652 Arg args[2];
653 int count = 0;
654
655 XtSetArg( args[count], XmNfont, 0 ); ++count;
656 XmRenditionRetrieve( (XmRendition) f->m_rendition, args, count );
657
658 return (WXFontSet) args[0].value;
659 }
660
661 void wxGetTextExtent(WXDisplay* display, const wxFont& font, double scale,
662 const wxString& str,
663 int* width, int* height, int* ascent, int* descent)
664 {
665 XRectangle ink, logical;
666 WXFontSet fset = font.GetFontSet(scale, display);
667
668 XmbTextExtents( (XFontSet)fset, str.mb_str(), str.length(), &ink, &logical);
669
670 if( width ) *width = logical.width;
671 if( height ) *height = logical.height;
672 if( ascent ) *ascent = -logical.y;
673 if( descent ) *descent = logical.height + logical.y;
674 }
675
676 #else // if !wxMOTIF_USE_RENDER_TABLE
677
678 void wxGetTextExtent(WXDisplay* display, const wxFont& font,
679 double scale, const wxString& str,
680 int* width, int* height, int* ascent, int* descent)
681 {
682 WXFontStructPtr pFontStruct = font.GetFontStruct(scale, display);
683
684 int direction, ascent2, descent2;
685 XCharStruct overall;
686 int slen = str.length();
687
688 XTextExtents((XFontStruct*) pFontStruct,
689 const_cast<char*>((const char *)str.mb_str()), slen,
690 &direction, &ascent2, &descent2, &overall);
691
692 if ( width )
693 *width = (overall.width);
694 if ( height )
695 *height = (ascent2 + descent2);
696 if ( descent )
697 *descent = descent2;
698 if ( ascent )
699 *ascent = ascent2;
700 }
701
702 #endif // !wxMOTIF_USE_RENDER_TABLE