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