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: font.cpp 43545 2006-11-20 16:21:08Z VS $ 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/font.h" 33 34#ifndef WX_PRECOMP 35 #include "wx/string.h" 36 #include "wx/utils.h" // for wxGetDisplay() 37 #include "wx/settings.h" 38 #include "wx/gdicmn.h" 39#endif 40 41#include "wx/fontutil.h" // for wxNativeFontInfo 42#include "wx/tokenzr.h" 43#include "wx/motif/private.h" 44 45IMPLEMENT_DYNAMIC_CLASS(wxFont, wxGDIObject) 46 47// ---------------------------------------------------------------------------- 48// private classes 49// ---------------------------------------------------------------------------- 50 51// For every wxFont, there must be a font for each display and scale requested. 52// So these objects are stored in wxFontRefData::m_fonts 53class wxXFont : public wxObject 54{ 55public: 56 wxXFont(); 57 virtual ~wxXFont(); 58 59#if !wxMOTIF_NEW_FONT_HANDLING 60 WXFontStructPtr m_fontStruct; // XFontStruct 61#endif 62#if !wxMOTIF_USE_RENDER_TABLE && !wxMOTIF_NEW_FONT_HANDLING 63 WXFontList m_fontList; // Motif XmFontList 64#else // if wxUSE_RENDER_TABLE 65 WXRenderTable m_renderTable; // Motif XmRenderTable 66 WXRendition m_rendition; // Motif XmRendition 67#endif 68 WXDisplay* m_display; // XDisplay 69 int m_scale; // Scale * 100 70}; 71 72class wxFontRefData: public wxGDIRefData 73{ 74 friend class wxFont; 75 76public: 77 wxFontRefData(int size = wxDEFAULT, 78 int family = wxDEFAULT, 79 int style = wxDEFAULT, 80 int weight = wxDEFAULT, 81 bool underlined = false, 82 const wxString& faceName = wxEmptyString, 83 wxFontEncoding encoding = wxFONTENCODING_DEFAULT) 84 { 85 Init(size, family, style, weight, underlined, faceName, encoding); 86 } 87 88 wxFontRefData(const wxFontRefData& data) 89 { 90 Init(data.m_pointSize, data.m_family, data.m_style, data.m_weight, 91 data.m_underlined, data.m_faceName, data.m_encoding); 92 } 93 94 virtual ~wxFontRefData(); 95 96protected: 97 // common part of all ctors 98 void Init(int size, 99 int family, 100 int style, 101 int weight, 102 bool underlined, 103 const wxString& faceName, 104 wxFontEncoding encoding); 105 106 // font attributes 107 int m_pointSize; 108 int m_family; 109 int m_style; 110 int m_weight; 111 bool m_underlined; 112 wxString m_faceName; 113 wxFontEncoding m_encoding; 114 115 wxNativeFontInfo m_nativeFontInfo; 116 117 // A list of wxXFonts 118 wxList m_fonts; 119}; 120 121// ============================================================================ 122// implementation 123// ============================================================================ 124 125// ---------------------------------------------------------------------------- 126// wxXFont 127// ---------------------------------------------------------------------------- 128 129wxXFont::wxXFont() 130{ 131#if !wxMOTIF_NEW_FONT_HANDLING 132 m_fontStruct = (WXFontStructPtr) 0; 133#endif 134#if !wxMOTIF_USE_RENDER_TABLE && !wxMOTIF_NEW_FONT_HANDLING 135 m_fontList = (WXFontList) 0; 136#else // if wxMOTIF_USE_RENDER_TABLE 137 m_renderTable = (WXRenderTable) 0; 138 m_rendition = (WXRendition) 0; 139#endif 140 m_display = (WXDisplay*) 0; 141 m_scale = 100; 142} 143 144wxXFont::~wxXFont() 145{ 146#if !wxMOTIF_USE_RENDER_TABLE 147 if (m_fontList) 148 XmFontListFree ((XmFontList) m_fontList); 149 m_fontList = NULL; 150#else // if wxUSE_RENDER_TABLE 151 if (m_renderTable) 152 XmRenderTableFree ((XmRenderTable) m_renderTable); 153 m_renderTable = NULL; 154#endif 155 156 // TODO: why does freeing the font produce a segv??? 157 // Note that XFreeFont wasn't called in wxWin 1.68 either. 158 // MBN: probably some interaction with fonts being still 159 // in use in some widgets... 160 // XFontStruct* fontStruct = (XFontStruct*) m_fontStruct; 161 // XFreeFont((Display*) m_display, fontStruct); 162} 163 164// ---------------------------------------------------------------------------- 165// wxFontRefData 166// ---------------------------------------------------------------------------- 167 168void wxFontRefData::Init(int pointSize, 169 int family, 170 int style, 171 int weight, 172 bool underlined, 173 const wxString& faceName, 174 wxFontEncoding encoding) 175{ 176 if (family == wxDEFAULT) 177 m_family = wxSWISS; 178 else 179 m_family = family; 180 181 m_faceName = faceName; 182 183 if (style == wxDEFAULT) 184 m_style = wxNORMAL; 185 else 186 m_style = style; 187 188 if (weight == wxDEFAULT) 189 m_weight = wxNORMAL; 190 else 191 m_weight = weight; 192 193 if (pointSize == wxDEFAULT) 194 m_pointSize = 12; 195 else 196 m_pointSize = pointSize; 197 198 m_underlined = underlined; 199 m_encoding = encoding; 200} 201 202wxFontRefData::~wxFontRefData() 203{ 204 wxList::compatibility_iterator node = m_fonts.GetFirst(); 205 while (node) 206 { 207 wxXFont* f = (wxXFont*) node->GetData(); 208 delete f; 209 node = node->GetNext(); 210 } 211 m_fonts.Clear(); 212} 213 214#define M_FONTDATA ((wxFontRefData*)m_refData) 215 216// ---------------------------------------------------------------------------- 217// wxFont 218// ---------------------------------------------------------------------------- 219 220wxFont::wxFont(const wxNativeFontInfo& info) 221{ 222 (void)Create(info.GetXFontName()); 223} 224 225bool wxFont::Create(int pointSize, 226 int family, 227 int style, 228 int weight, 229 bool underlined, 230 const wxString& faceName, 231 wxFontEncoding encoding) 232{ 233 UnRef(); 234 m_refData = new wxFontRefData(pointSize, family, style, weight, 235 underlined, faceName, encoding); 236 237 return true; 238} 239 240bool wxFont::Create(const wxString& fontname, wxFontEncoding enc) 241{ 242 if( !fontname ) 243 { 244 *this = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT); 245 return true; 246 } 247 248 m_refData = new wxFontRefData(); 249 250 M_FONTDATA->m_nativeFontInfo.SetXFontName(fontname); // X font name 251 252 wxString tmp; 253 254 wxStringTokenizer tn( fontname, wxT("-") ); 255 256 tn.GetNextToken(); // skip initial empty token 257 tn.GetNextToken(); // foundry 258 259 260 M_FONTDATA->m_faceName = tn.GetNextToken(); // family 261 262 tmp = tn.GetNextToken().MakeUpper(); // weight 263 if (tmp == wxT("BOLD")) M_FONTDATA->m_weight = wxBOLD; 264 if (tmp == wxT("BLACK")) M_FONTDATA->m_weight = wxBOLD; 265 if (tmp == wxT("EXTRABOLD")) M_FONTDATA->m_weight = wxBOLD; 266 if (tmp == wxT("DEMIBOLD")) M_FONTDATA->m_weight = wxBOLD; 267 if (tmp == wxT("ULTRABOLD")) M_FONTDATA->m_weight = wxBOLD; 268 269 if (tmp == wxT("LIGHT")) M_FONTDATA->m_weight = wxLIGHT; 270 if (tmp == wxT("THIN")) M_FONTDATA->m_weight = wxLIGHT; 271 272 tmp = tn.GetNextToken().MakeUpper(); // slant 273 if (tmp == wxT("I")) M_FONTDATA->m_style = wxITALIC; 274 if (tmp == wxT("O")) M_FONTDATA->m_style = wxITALIC; 275 276 tn.GetNextToken(); // set width 277 tn.GetNextToken(); // add. style 278 tn.GetNextToken(); // pixel size 279 280 tmp = tn.GetNextToken(); // pointsize 281 if (tmp != wxT("*")) 282 { 283 long num = wxStrtol (tmp.c_str(), (wxChar **) NULL, 10); 284 M_FONTDATA->m_pointSize = (int)(num / 10); 285 } 286 287 tn.GetNextToken(); // x-res 288 tn.GetNextToken(); // y-res 289 290 tmp = tn.GetNextToken().MakeUpper(); // spacing 291 292 if (tmp == wxT("M")) 293 M_FONTDATA->m_family = wxMODERN; 294 else if (M_FONTDATA->m_faceName == wxT("TIMES")) 295 M_FONTDATA->m_family = wxROMAN; 296 else if (M_FONTDATA->m_faceName == wxT("HELVETICA")) 297 M_FONTDATA->m_family = wxSWISS; 298 else if (M_FONTDATA->m_faceName == wxT("LUCIDATYPEWRITER")) 299 M_FONTDATA->m_family = wxTELETYPE; 300 else if (M_FONTDATA->m_faceName == wxT("LUCIDA")) 301 M_FONTDATA->m_family = wxDECORATIVE; 302 else if (M_FONTDATA->m_faceName == wxT("UTOPIA")) 303 M_FONTDATA->m_family = wxSCRIPT; 304 305 tn.GetNextToken(); // avg width 306 307 // deal with font encoding 308 M_FONTDATA->m_encoding = enc; 309 if ( M_FONTDATA->m_encoding == wxFONTENCODING_SYSTEM ) 310 { 311 wxString registry = tn.GetNextToken().MakeUpper(), 312 encoding = tn.GetNextToken().MakeUpper(); 313 314 if ( registry == _T("ISO8859") ) 315 { 316 int cp; 317 if ( wxSscanf(encoding, wxT("%d"), &cp) == 1 ) 318 { 319 M_FONTDATA->m_encoding = 320 (wxFontEncoding)(wxFONTENCODING_ISO8859_1 + cp - 1); 321 } 322 } 323 else if ( registry == _T("MICROSOFT") ) 324 { 325 int cp; 326 if ( wxSscanf(encoding, wxT("cp125%d"), &cp) == 1 ) 327 { 328 M_FONTDATA->m_encoding = 329 (wxFontEncoding)(wxFONTENCODING_CP1250 + cp); 330 } 331 } 332 else if ( registry == _T("KOI8") ) 333 { 334 M_FONTDATA->m_encoding = wxFONTENCODING_KOI8; 335 } 336 //else: unknown encoding - may be give a warning here? 337 else 338 return false; 339 } 340 return true; 341} 342 343wxFont::~wxFont() 344{ 345} 346 347// ---------------------------------------------------------------------------- 348// change the font attributes 349// ---------------------------------------------------------------------------- 350 351void wxFont::Unshare() 352{ 353 // Don't change shared data 354 if (!m_refData) 355 { 356 m_refData = new wxFontRefData(); 357 } 358 else 359 { 360 wxFontRefData* ref = new wxFontRefData(*(wxFontRefData*)m_refData); 361 UnRef(); 362 m_refData = ref; 363 } 364} 365 366void wxFont::SetPointSize(int pointSize) 367{ 368 Unshare(); 369 370 M_FONTDATA->m_pointSize = pointSize; 371 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now 372} 373 374void wxFont::SetFamily(int family) 375{ 376 Unshare(); 377 378 M_FONTDATA->m_family = family; 379 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now 380} 381 382void wxFont::SetStyle(int style) 383{ 384 Unshare(); 385 386 M_FONTDATA->m_style = style; 387 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now 388} 389 390void wxFont::SetWeight(int weight) 391{ 392 Unshare(); 393 394 M_FONTDATA->m_weight = weight; 395 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now 396} 397 398bool wxFont::SetFaceName(const wxString& faceName) 399{ 400 Unshare(); 401 402 M_FONTDATA->m_faceName = faceName; 403 M_FONTDATA->m_nativeFontInfo.GetXFontName().Clear(); // invalid now 404 405 return wxFontBase::SetFaceName(faceName); 406} 407 408void wxFont::SetUnderlined(bool underlined) 409{ 410 Unshare(); 411 412 M_FONTDATA->m_underlined = underlined; 413} 414 415void 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 423void wxFont::DoSetNativeFontInfo(const wxNativeFontInfo& info) 424{ 425 Unshare(); 426 427 M_FONTDATA->m_nativeFontInfo = info; 428} 429 430// ---------------------------------------------------------------------------- 431// query font attributes 432// ---------------------------------------------------------------------------- 433 434int wxFont::GetPointSize() const 435{ 436 wxCHECK_MSG( Ok(), 0, wxT("invalid font") ); 437 438 return M_FONTDATA->m_pointSize; 439} 440 441wxString wxFont::GetFaceName() const 442{ 443 wxCHECK_MSG( Ok(), wxEmptyString, wxT("invalid font") ); 444 445 return M_FONTDATA->m_faceName ; 446} 447 448int wxFont::GetFamily() const 449{ 450 wxCHECK_MSG( Ok(), 0, wxT("invalid font") ); 451 452 return M_FONTDATA->m_family; 453} 454 455int wxFont::GetStyle() const 456{ 457 wxCHECK_MSG( Ok(), 0, wxT("invalid font") ); 458 459 return M_FONTDATA->m_style; 460} 461 462int wxFont::GetWeight() const 463{ 464 wxCHECK_MSG( Ok(), 0, wxT("invalid font") ); 465 466 return M_FONTDATA->m_weight; 467} 468 469bool wxFont::GetUnderlined() const 470{ 471 wxCHECK_MSG( Ok(), false, wxT("invalid font") ); 472 473 return M_FONTDATA->m_underlined; 474} 475 476wxFontEncoding wxFont::GetEncoding() const 477{ 478 wxCHECK_MSG( Ok(), wxFONTENCODING_DEFAULT, wxT("invalid font") ); 479 480 return M_FONTDATA->m_encoding; 481} 482 483const wxNativeFontInfo *wxFont::GetNativeFontInfo() const 484{ 485 wxCHECK_MSG( Ok(), (wxNativeFontInfo *)NULL, wxT("invalid font") ); 486 487 if(M_FONTDATA->m_nativeFontInfo.GetXFontName().empty()) 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. 500wxXFont* 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 582WXFontStructPtr 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 593WXFontList 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 602WXRenderTable 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 611WXFontType 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 620WXFontType 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 640WXFontSet 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 655void 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 672void 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.length(); 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 696