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