diff --git a/include/wx/fontutil.h b/include/wx/fontutil.h index 35bd9508a6..38f473654e 100644 --- a/include/wx/fontutil.h +++ b/include/wx/fontutil.h @@ -118,7 +118,20 @@ public: // set the XFLD void SetXFontName(const wxString& xFontName); #elif defined(__WXMSW__) - wxNativeFontInfo(const LOGFONT& lf_) : lf(lf_), pointSize(0.0f) { } + wxNativeFontInfo(const LOGFONT& lf_); + + // MSW-specific: get the height value in pixels using LOGFONT convention + // (i.e. negative) corresponding to the given size in points and DPI. + static int GetLogFontHeightAtPPI(float size, int ppi) + { + return -wxRound(size * ppi / 72.0); + } + + // And the same thing for the size of this font. + int GetLogFontHeightAtPPI(int ppi) const + { + return GetLogFontHeightAtPPI(pointSize, ppi); + } LOGFONT lf; diff --git a/include/wx/msw/private.h b/include/wx/msw/private.h index e04c44db50..1a426fd9ba 100644 --- a/include/wx/msw/private.h +++ b/include/wx/msw/private.h @@ -961,10 +961,14 @@ extern const wxCursor *wxGetGlobalCursor(); // from msw/cursor.cpp WXDLLIMPEXP_CORE void wxGetCursorPosMSW(POINT* pt); WXDLLIMPEXP_CORE void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font); -WXDLLIMPEXP_CORE void wxFillLogFont(LOGFONT *logFont, const wxFont *font); -WXDLLIMPEXP_CORE wxFont wxCreateFontFromLogFont(const LOGFONT *logFont); WXDLLIMPEXP_CORE wxFontEncoding wxGetFontEncFromCharSet(int charset); +inline void wxSetWindowFont(HWND hwnd, const wxFont& font) +{ + ::SendMessage(hwnd, WM_SETFONT, + (WPARAM)GetHfontOf(font), MAKELPARAM(TRUE, 0)); +} + WXDLLIMPEXP_CORE void wxSliderEvent(WXHWND control, WXWORD wParam, WXWORD pos); WXDLLIMPEXP_CORE void wxScrollBarEvent(WXHWND hbar, WXWORD wParam, WXWORD pos); diff --git a/include/wx/msw/subwin.h b/include/wx/msw/subwin.h index a0178147e7..038bf303f0 100644 --- a/include/wx/msw/subwin.h +++ b/include/wx/msw/subwin.h @@ -113,14 +113,11 @@ public: // set font for all windows void SetFont(const wxFont& font) { - HFONT hfont = GetHfontOf(font); - wxCHECK_RET( hfont, wxT("invalid font") ); - for ( size_t n = 0; n < m_count; n++ ) { if ( m_hwnds[n] ) { - ::SendMessage(m_hwnds[n], WM_SETFONT, (WPARAM)hfont, 0); + wxSetWindowFont(m_hwnds[n], font); // otherwise the window might not be redrawn correctly ::InvalidateRect(m_hwnds[n], NULL, FALSE /* don't erase bg */); diff --git a/src/msw/font.cpp b/src/msw/font.cpp index 2a74f6d1b2..255aafcdae 100644 --- a/src/msw/font.cpp +++ b/src/msw/font.cpp @@ -152,6 +152,16 @@ public: return m_hFont != 0; } + int GetLogFontHeight() const + { + return m_nativeFontInfo.lf.lfHeight; + } + + int GetLogFontHeightAtPPI(int ppi) const + { + return m_nativeFontInfo.GetLogFontHeightAtPPI(ppi); + } + // ... and setters: notice that all of them invalidate the currently // allocated HFONT, if any, so that the next call to GetHFONT() recreates a // new one @@ -223,6 +233,13 @@ public: m_nativeFontInfo.SetEncoding(encoding); } + void SetLogFontHeight(int height) + { + Free(); + + m_nativeFontInfo.lf.lfHeight = height; + } + const wxNativeFontInfo& GetNativeFontInfo() const { // we need to create the font now to get the corresponding LOGFONT if @@ -385,6 +402,15 @@ void wxFontRefData::Free() // wxNativeFontInfo // ---------------------------------------------------------------------------- +wxNativeFontInfo::wxNativeFontInfo(const LOGFONT& lf_) + : lf(lf_) +{ + // Determine the size in points using the primary screen DPI as we don't + // have anything else here. + const float ppi = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY); + pointSize = 72.0f * abs(lf.lfHeight) / ppi; +} + void wxNativeFontInfo::Init() { wxZeroMemory(lf); @@ -402,14 +428,7 @@ void wxNativeFontInfo::Init() float wxNativeFontInfo::GetFractionalPointSize() const { - if ( pointSize != 0.0f ) - return pointSize; - - // FIXME: using the screen here results in incorrect font size calculation - // for printing! - const int ppInch = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY); - - return (72.0*abs(lf.lfHeight)) / (double) ppInch; + return pointSize; } wxSize wxNativeFontInfo::GetPixelSize() const @@ -490,17 +509,14 @@ wxFontEncoding wxNativeFontInfo::GetEncoding() const return wxGetFontEncFromCharSet(lf.lfCharSet); } -void wxNativeFontInfo::SetFractionalPointSize(float pointsize) +void wxNativeFontInfo::SetFractionalPointSize(float pointSizeNew) { - // Store it to be able to return it from GetFractionalPointSize() later - // exactly. - pointSize = pointsize; + // We don't have the correct DPI to use here, so use that of the + // primary screen. + const int ppi = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY); + lf.lfHeight = GetLogFontHeightAtPPI(pointSizeNew, ppi); - // FIXME: using the screen here results in incorrect font size calculation - // for printing! - const int ppInch = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY); - - lf.lfHeight = -wxRound(pointsize*((double)ppInch)/72.0); + pointSize = pointSizeNew; } void wxNativeFontInfo::SetPixelSize(const wxSize& pixelSize) @@ -516,6 +532,11 @@ void wxNativeFontInfo::SetPixelSize(const wxSize& pixelSize) // versions by passing a negative value explicitly itself. lf.lfHeight = -abs(pixelSize.GetHeight()); lf.lfWidth = pixelSize.GetWidth(); + + // We don't have the right DPI to use here neither, but we need to update + // the point size too, so fall back to the default. + const float ppi = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY); + pointSize = 72.0f * pixelSize.GetHeight() / ppi; } void wxNativeFontInfo::SetStyle(wxFontStyle style) @@ -855,7 +876,6 @@ void wxFont::SetFractionalPointSize(float pointSize) { AllocExclusive(); - M_FONTDATA->Free(); M_FONTDATA->SetFractionalPointSize(pointSize); } diff --git a/src/msw/fontdlg.cpp b/src/msw/fontdlg.cpp index 2f7e6bb8d5..8edd4a9f91 100644 --- a/src/msw/fontdlg.cpp +++ b/src/msw/fontdlg.cpp @@ -36,6 +36,8 @@ #include "wx/math.h" #endif +#include "wx/fontutil.h" + #include #include @@ -118,7 +120,7 @@ int wxFontDialog::ShowModal() if ( m_fontData.m_initialFont.IsOk() ) { flags |= CF_INITTOLOGFONTSTRUCT; - wxFillLogFont(&logFont, &m_fontData.m_initialFont); + logFont = m_fontData.m_initialFont.GetNativeFontInfo()->lf; } if ( m_fontData.m_fontColour.IsOk() ) @@ -150,7 +152,7 @@ int wxFontDialog::ShowModal() if ( ChooseFont(&chooseFontStruct) != 0 ) { wxRGBToColour(m_fontData.m_fontColour, chooseFontStruct.rgbColors); - m_fontData.m_chosenFont = wxCreateFontFromLogFont(&logFont); + m_fontData.m_chosenFont = wxFont(wxNativeFontInfo(logFont)); m_fontData.EncodingInfo().facename = logFont.lfFaceName; m_fontData.EncodingInfo().charset = logFont.lfCharSet; diff --git a/src/msw/fontutil.cpp b/src/msw/fontutil.cpp index 3a6489b392..975ba52a02 100644 --- a/src/msw/fontutil.cpp +++ b/src/msw/fontutil.cpp @@ -264,35 +264,3 @@ wxFontEncoding wxGetFontEncFromCharSet(int cs) return fontEncoding; } - -// ---------------------------------------------------------------------------- -// wxFont <-> LOGFONT conversion -// ---------------------------------------------------------------------------- - -void wxFillLogFont(LOGFONT *logFont, const wxFont *font) -{ - wxNativeFontInfo fi; - - // maybe we already have LOGFONT for this font? - const wxNativeFontInfo *pFI = font->GetNativeFontInfo(); - if ( !pFI ) - { - // use wxNativeFontInfo methods to build a LOGFONT for this font - fi.InitFromFont(*font); - - pFI = &fi; - } - - // transfer all the data to LOGFONT - *logFont = pFI->lf; -} - -wxFont wxCreateFontFromLogFont(const LOGFONT *logFont) -{ - wxNativeFontInfo info; - - info.lf = *logFont; - - return wxFont(info); -} - diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index fc27322efc..af08c83b2d 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -620,8 +620,7 @@ bool wxListCtrl::SetHeaderAttr(const wxItemAttr& attr) // We need to tell the header about its new font to let it compute // its new height. - ::SendMessage(hwndHdr, WM_SETFONT, - (WPARAM)GetHfontOf(font), MAKELPARAM(TRUE, 0)); + wxSetWindowFont(hwndHdr, font); } // Refreshing the listview makes it notice the change in height of its diff --git a/src/msw/renderer.cpp b/src/msw/renderer.cpp index b7bd070f5e..b353eec254 100644 --- a/src/msw/renderer.cpp +++ b/src/msw/renderer.cpp @@ -552,7 +552,8 @@ int wxRendererMSW::GetHeaderButtonHeight(wxWindow * win) font = win->GetFont(); if ( !font.IsOk() ) wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - ::SendMessage(hwndHeader, WM_SETFONT, (WPARAM)GetHfontOf(font), 0); + + wxSetWindowFont(hwndHeader, font); // initialize the struct filled with the values by Header_Layout() RECT parentRect = { 0, 0, 100, 100 }; diff --git a/src/msw/settings.cpp b/src/msw/settings.cpp index 3377b5b080..0581dc1a08 100644 --- a/src/msw/settings.cpp +++ b/src/msw/settings.cpp @@ -345,7 +345,7 @@ extern wxFont wxGetCCDefaultFont() 0 ) ) { - return wxFont(wxCreateFontFromLogFont(&lf)); + return wxFont(lf); } else { diff --git a/src/msw/spinctrl.cpp b/src/msw/spinctrl.cpp index 222c787bc9..6c794fb47a 100644 --- a/src/msw/spinctrl.cpp +++ b/src/msw/spinctrl.cpp @@ -564,8 +564,7 @@ bool wxSpinCtrl::SetFont(const wxFont& font) return false; } - WXHANDLE hFont = GetFont().GetResourceHandle(); - (void)::SendMessage(GetBuddyHwnd(), WM_SETFONT, (WPARAM)hFont, TRUE); + wxSetWindowFont(GetBuddyHwnd(), GetFont()); return true; } diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index dadb293c2a..9b62c686a6 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -40,6 +40,7 @@ #include "wx/wxcrtvararg.h" #endif +#include "wx/fontutil.h" #include "wx/scopedptr.h" #include "wx/stack.h" #include "wx/sysopt.h" @@ -2829,14 +2830,13 @@ bool wxTextCtrl::MSWSetCharFormat(const wxTextAttr& style, long start, long end) CFM_ITALIC | CFM_BOLD | CFM_UNDERLINE | CFM_STRIKEOUT; // fill in data from LOGFONT but recalculate lfHeight because we need - // the real height in twips and not the negative number which - // wxFillLogFont() returns (this is correct in general and works with + // the real height in twips and not the negative number used inside + // LOGFONT returns (this is correct in general and works with // the Windows font mapper, but not here) wxFont font(style.GetFont()); - LOGFONT lf; - wxFillLogFont(&lf, &font); + LOGFONT lf = font.GetNativeFontInfo()->lf; cf.yHeight = 20*font.GetPointSize(); // 1 pt = 20 twips cf.bCharSet = lf.lfCharSet; cf.bPitchAndFamily = lf.lfPitchAndFamily; @@ -3126,8 +3126,9 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style) LOGFONT lf; // Convert the height from the units of 1/20th of the point in which // CHARFORMAT stores it to pixel-based units used by LOGFONT. - const wxCoord ppi = wxClientDC(this).GetPPI().y; - lf.lfHeight = -MulDiv(cf.yHeight/20, ppi, 72); + // Note that RichEdit seems to always use standard DPI of 96, even when the + // window is a monitor using a higher DPI. + lf.lfHeight = wxNativeFontInfo::GetLogFontHeightAtPPI(cf.yHeight/20.0f, 96); lf.lfWidth = 0; lf.lfCharSet = ANSI_CHARSET; // FIXME: how to get correct charset? lf.lfClipPrecision = 0; @@ -3160,7 +3161,7 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style) else lf.lfWeight = FW_NORMAL; - wxFont font = wxCreateFontFromLogFont(& lf); + wxFont font(lf); if (font.IsOk()) { style.SetFont(font); diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 0a380c0e8b..58d88811d2 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -827,11 +827,7 @@ bool wxWindowMSW::SetFont(const wxFont& font) // just been reset and in this case we need to change the font used by // the native window to the default for this class, i.e. exactly what // GetFont() returns - WXHANDLE hFont = GetFont().GetResourceHandle(); - - wxASSERT_MSG( hFont, wxT("should have valid font") ); - - ::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); + wxSetWindowFont(hWnd, GetFont()); } return true; @@ -7425,7 +7421,12 @@ static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win) #if !wxDIALOG_UNIT_COMPATIBILITY // and select the current font into it - HFONT hfont = GetHfontOf(win->GetFont()); + + // Note that it's important to extend the lifetime of the possibly + // temporary wxFont returned by GetFont() to ensure that its HFONT remains + // valid. + const wxFont& f(win->GetFont()); + HFONT hfont = GetHfontOf(f); if ( hfont ) { hfont = (HFONT)::SelectObject(hdc, hfont);