Merge branch 'fontdlg-dpi'

Fix font sizes in MSW font dialog in high DPI.

See #22322.
This commit is contained in:
Vadim Zeitlin 2022-04-19 00:35:20 +02:00
commit 3439087685
4 changed files with 88 additions and 15 deletions

View File

@ -35,22 +35,21 @@ class AutoSystemDpiAware
public:
AutoSystemDpiAware()
: m_prevContext(WXDPI_AWARENESS_CONTEXT_UNAWARE),
m_pfnSetThreadDpiAwarenessContext((SetThreadDpiAwarenessContext_t)-1)
: m_prevContext(WXDPI_AWARENESS_CONTEXT_UNAWARE)
{
if ( m_pfnSetThreadDpiAwarenessContext == (SetThreadDpiAwarenessContext_t)-1)
if ( ms_pfnSetThreadDpiAwarenessContext == (SetThreadDpiAwarenessContext_t)-1)
{
wxLoadedDLL dllUser32("user32.dll");
wxDL_INIT_FUNC(m_pfn, SetThreadDpiAwarenessContext, dllUser32);
wxDL_INIT_FUNC(ms_pfn, SetThreadDpiAwarenessContext, dllUser32);
}
if ( m_pfnSetThreadDpiAwarenessContext )
if ( ms_pfnSetThreadDpiAwarenessContext )
{
m_prevContext = m_pfnSetThreadDpiAwarenessContext(
m_prevContext = ms_pfnSetThreadDpiAwarenessContext(
WXDPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED);
if ( !m_prevContext )
{
m_prevContext = m_pfnSetThreadDpiAwarenessContext(
m_prevContext = ms_pfnSetThreadDpiAwarenessContext(
WXDPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
}
}
@ -59,16 +58,17 @@ public:
~AutoSystemDpiAware()
{
if ( m_pfnSetThreadDpiAwarenessContext )
if ( ms_pfnSetThreadDpiAwarenessContext )
{
m_pfnSetThreadDpiAwarenessContext(m_prevContext);
ms_pfnSetThreadDpiAwarenessContext(m_prevContext);
}
}
private:
WXDPI_AWARENESS_CONTEXT m_prevContext;
SetThreadDpiAwarenessContext_t m_pfnSetThreadDpiAwarenessContext;
// This static member is defined in src/msw/window.cpp.
static SetThreadDpiAwarenessContext_t ms_pfnSetThreadDpiAwarenessContext;
};
#else // !wxUSE_DYNLIB_CLASS

View File

@ -432,7 +432,7 @@ bool MyApp::OnInit()
#endif // wxUSE_COLOURDLG
#if wxUSE_FONTDLG
choices_menu->Append(DIALOGS_CHOOSE_FONT, "Choose &font");
choices_menu->Append(DIALOGS_CHOOSE_FONT, "Choose &font\tShift-Ctrl-N");
#endif // wxUSE_FONTDLG
#if wxUSE_CHOICEDLG

View File

@ -34,6 +34,7 @@
#endif
#include "wx/fontutil.h"
#include "wx/display.h"
#include "wx/msw/private/dpiaware.h"
#include <stdlib.h>
@ -88,6 +89,14 @@ wxString wxFontDialog::GetTitle() const
return m_title;
}
// Tiny wrapper calling ::ChooseFont() with system DPI awareness, as the
// standard dialog doesn't work correctly when using per-monitor awareness.
static BOOL wxMSWChooseFont(CHOOSEFONT* pCF)
{
wxMSWImpl::AutoSystemDpiAware dpiAwareness;
return ::ChooseFont(pCF);
}
int wxFontDialog::ShowModal()
{
WX_HOOK_MODAL_DIALOG();
@ -121,6 +130,17 @@ int wxFontDialog::ShowModal()
{
flags |= CF_INITTOLOGFONTSTRUCT;
logFont = m_fontData.m_initialFont.GetNativeFontInfo()->lf;
// The standard dialog seems to always use the default DPI for
// converting LOGFONT height to the value in points shown in the
// dialog (and this happens even when not using AutoSystemDpiAware),
// so we need to convert it to standard (not even system, because the
// dialog doesn't take it into account neither) DPI.
logFont.lfHeight = wxNativeFontInfo::GetLogFontHeightAtPPI
(
m_fontData.m_initialFont.GetFractionalPointSize(),
wxDisplay::GetStdPPIValue()
);
}
if ( m_fontData.m_fontColour.IsOk() )
@ -153,12 +173,51 @@ int wxFontDialog::ShowModal()
chooseFontStruct.Flags = flags;
wxMSWImpl::AutoSystemDpiAware dpiAwareness;
if ( ChooseFont(&chooseFontStruct) != 0 )
if ( wxMSWChooseFont(&chooseFontStruct) != 0 )
{
wxRGBToColour(m_fontData.m_fontColour, chooseFontStruct.rgbColors);
m_fontData.m_chosenFont = wxFont(wxNativeFontInfo(logFont, this));
// Don't trust the LOGFONT height returned by the native dialog because
// it doesn't use the correct DPI.
//
// Note that we must use our parent and not this window itself, as it
// doesn't have any valid HWND and so its DPI can't be determined.
if ( parent )
{
// We can't just adjust lfHeight directly to the correct DPI here
// as doing this would introduce rounding problems, e.g. 8pt font
// corresponds to lfHeight == 11px and scaling this up for 150% DPI
// would result in 17px height which would then map to 8.5pt at
// 150% DPI and end up being rounded to 9pt, which would be wrong.
//
// So find the point size itself first:
const int pointSize = wxRound(wxNativeFontInfo::GetPointSizeAtPPI
(
logFont.lfHeight,
wxDisplay::GetStdPPIValue()
));
// And then compute the pixel height that results in this point
// size at the actual DPI being used.
logFont.lfHeight = wxNativeFontInfo::GetLogFontHeightAtPPI
(
pointSize,
parent->GetDPI().y
);
}
wxFont f(wxNativeFontInfo(logFont, parent));
// The native dialog allows selecting only integer font sizes in
// points, but converting them to pixel height loses precision and so
// converting them back to points may result in a fractional value
// different from the value selected in the dialog. So ensure that we
// use exactly the same font size in points as what was selected in the
// dialog by rounding the possibly fractional value to the integer ones
// entered there.
f.SetPointSize(wxRound(f.GetFractionalPointSize()));
m_fontData.m_chosenFont = f;
m_fontData.EncodingInfo().facename = logFont.lfFaceName;
m_fontData.EncodingInfo().charset = logFont.lfCharSet;

View File

@ -76,6 +76,7 @@
#endif
#include "wx/msw/private.h"
#include "wx/msw/private/dpiaware.h"
#include "wx/msw/private/keyboard.h"
#include "wx/msw/private/paint.h"
#include "wx/msw/private/winstyle.h"
@ -4758,6 +4759,19 @@ wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
// DPI
// ---------------------------------------------------------------------------
#if wxUSE_DYNLIB_CLASS
namespace wxMSWImpl
{
AutoSystemDpiAware::SetThreadDpiAwarenessContext_t
AutoSystemDpiAware::ms_pfnSetThreadDpiAwarenessContext =
(AutoSystemDpiAware::SetThreadDpiAwarenessContext_t)-1;
} // namespace wxMSWImpl
#endif // wxUSE_DYNLIB_CLASS
namespace
{