]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/motif/font.cpp
Only give capture to wxPopupTransientWindow child if it's the only one.
[wxWidgets.git] / src / motif / font.cpp
... / ...
CommitLineData
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
50class wxXFont : public wxObject
51{
52public:
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
69class wxFontRefData: public wxGDIRefData
70{
71 friend class wxFont;
72
73public:
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
93protected:
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
126wxXFont::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
141wxXFont::~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
165void 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
199wxFontRefData::~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
217wxFont::wxFont(const wxNativeFontInfo& info)
218{
219 (void)Create(info.GetXFontName());
220}
221
222bool 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
237bool 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
340wxFont::~wxFont()
341{
342}
343
344wxGDIRefData *wxFont::CreateGDIRefData() const
345{
346 return new wxFontRefData;
347}
348
349wxGDIRefData *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
358void 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
373void 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
381void 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
389void 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
397void 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
405bool 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
415void wxFont::SetUnderlined(bool underlined)
416{
417 Unshare();
418
419 M_FONTDATA->m_underlined = underlined;
420}
421
422void 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
430void wxFont::DoSetNativeFontInfo(const wxNativeFontInfo& info)
431{
432 Unshare();
433
434 M_FONTDATA->m_nativeFontInfo = info;
435}
436
437// ----------------------------------------------------------------------------
438// query font attributes
439// ----------------------------------------------------------------------------
440
441int wxFont::GetPointSize() const
442{
443 wxCHECK_MSG( IsOk(), 0, wxT("invalid font") );
444
445 return M_FONTDATA->m_pointSize;
446}
447
448wxString wxFont::GetFaceName() const
449{
450 wxCHECK_MSG( IsOk(), wxEmptyString, wxT("invalid font") );
451
452 return M_FONTDATA->m_faceName ;
453}
454
455wxFontFamily wxFont::DoGetFamily() const
456{
457 return M_FONTDATA->m_family;
458}
459
460wxFontStyle wxFont::GetStyle() const
461{
462 wxCHECK_MSG( IsOk(), wxFONTSTYLE_MAX, wxT("invalid font") );
463
464 return M_FONTDATA->m_style;
465}
466
467wxFontWeight wxFont::GetWeight() const
468{
469 wxCHECK_MSG( IsOk(), wxFONTWEIGHT_MAX, wxT("invalid font") );
470
471 return M_FONTDATA->m_weight;
472}
473
474bool wxFont::GetUnderlined() const
475{
476 wxCHECK_MSG( IsOk(), false, wxT("invalid font") );
477
478 return M_FONTDATA->m_underlined;
479}
480
481wxFontEncoding wxFont::GetEncoding() const
482{
483 wxCHECK_MSG( IsOk(), wxFONTENCODING_DEFAULT, wxT("invalid font") );
484
485 return M_FONTDATA->m_encoding;
486}
487
488const 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.
505wxXFont* 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
587WXFontStructPtr 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
598WXFontList 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
607WXRenderTable 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
616WXFontType 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
625WXFontType 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
645WXFontSet 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
660void 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
677void 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