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