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