Reset static sizes when DPI changes

This commit is contained in:
Maarten Bent
2019-09-04 20:47:52 +02:00
parent e312569b94
commit fa2242a0a6
8 changed files with 125 additions and 69 deletions

View File

@@ -11,6 +11,7 @@
#define _WX_PRIVATE_WINDOW_H_ #define _WX_PRIVATE_WINDOW_H_
#include "wx/gdicmn.h" #include "wx/gdicmn.h"
#include "wx/dynlib.h"
namespace wxPrivate namespace wxPrivate
{ {
@@ -33,6 +34,67 @@ inline wxSize GetAverageASCIILetterSize(const T& of_what)
return s; return s;
} }
namespace
{
inline bool SupportsPerMonitorDPI()
{
static bool s_checkDPI =
#if defined(__WXMSW__) && wxUSE_DYNLIB_CLASS
// Only check the DPI when GetDpiForWindow is available because the old
// method (GetDeviceCaps) is a lot slower (about 1500 times).
// And when GetDpiForWindow is not available (for example older Windows
// versions), per-monitor DPI (V2) is also not available.
wxLoadedDLL("user32.dll").HasSymbol("GetDpiForWindow");
#else
false;
#endif
return s_checkDPI;
}
}
template <typename T>
class DpiDependentValue
{
public:
// Explicit initialization is needed if T is a primitive type.
DpiDependentValue()
: m_value(), m_dpi()
{ }
bool HasChanged(const wxWindowBase* win)
{
if ( win && SupportsPerMonitorDPI() )
{
const wxSize dpi = win->GetDPI();
if ( dpi != m_dpi )
{
m_dpi = dpi;
return true;
}
}
// Ensure that we return true the first time we're called,
// asuming that the value will always be set to a non-default value.
return m_value == T();
}
void SetAtNewDPI(const T& value)
{
m_value = value;
}
T& Get()
{
return m_value;
}
private:
T m_value;
wxSize m_dpi;
};
} // namespace wxPrivate } // namespace wxPrivate
#endif // _WX_PRIVATE_WINDOW_H_ #endif // _WX_PRIVATE_WINDOW_H_

View File

@@ -120,13 +120,7 @@ public:
// current DPI, do it once (and cache the result) in another function. // current DPI, do it once (and cache the result) in another function.
#define wxNEEDS_BORDER_IN_PX #define wxNEEDS_BORDER_IN_PX
// We don't react to dynamic DPI changes, so we can cache the values of return DoGetDefaultBorderInPx();
// the border in on-screen pixels after computing it once. This
// could/should change in the future.
if ( !ms_defaultBorderInPx )
ms_defaultBorderInPx = DoGetDefaultBorderInPx();
return ms_defaultBorderInPx;
#endif #endif
#else #else
return 0; return 0;
@@ -230,8 +224,6 @@ public:
private: private:
#ifdef wxNEEDS_BORDER_IN_PX #ifdef wxNEEDS_BORDER_IN_PX
static int DoGetDefaultBorderInPx(); static int DoGetDefaultBorderInPx();
static int ms_defaultBorderInPx;
#endif // wxNEEDS_BORDER_IN_PX #endif // wxNEEDS_BORDER_IN_PX
int m_proportion; int m_proportion;

View File

@@ -28,11 +28,13 @@
#include "wx/button.h" #include "wx/button.h"
#include "wx/statbox.h" #include "wx/statbox.h"
#include "wx/toplevel.h" #include "wx/toplevel.h"
#include "wx/app.h"
#endif // WX_PRECOMP #endif // WX_PRECOMP
#include "wx/display.h" #include "wx/display.h"
#include "wx/vector.h" #include "wx/vector.h"
#include "wx/listimpl.cpp" #include "wx/listimpl.cpp"
#include "wx/private/window.h"
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -90,8 +92,6 @@ WX_DEFINE_EXPORTED_LIST( wxSizerItemList )
#ifdef wxNEEDS_BORDER_IN_PX #ifdef wxNEEDS_BORDER_IN_PX
int wxSizerFlags::ms_defaultBorderInPx = 0;
/* static */ /* static */
int wxSizerFlags::DoGetDefaultBorderInPx() int wxSizerFlags::DoGetDefaultBorderInPx()
{ {
@@ -103,11 +103,14 @@ int wxSizerFlags::DoGetDefaultBorderInPx()
// between related and unrelated controls, as explained at the above URL, // between related and unrelated controls, as explained at the above URL,
// but we don't have a way to specify this in our API currently. // but we don't have a way to specify this in our API currently.
// //
// We also have to use the DPI for the primary monitor here as we don't // We also have to use the DPI for the monitor showing the top window here
// have any associated window, so this is wrong on systems using multiple // as we don't have any associated window -- but, again, without changes
// monitors with different resolutions too -- but, again, without changes
// in the API, there is nothing we can do about this. // in the API, there is nothing we can do about this.
return wxWindow::FromDIP(5, NULL); const wxWindow* const win = wxTheApp ? wxTheApp->GetTopWindow() : NULL;
static wxPrivate::DpiDependentValue<int> s_defaultBorderInPx;
if ( s_defaultBorderInPx.HasChanged(win) )
s_defaultBorderInPx.SetAtNewDPI(wxWindow::FromDIP(5, win));
return s_defaultBorderInPx.Get();
} }
#endif // wxNEEDS_BORDER_IN_PX #endif // wxNEEDS_BORDER_IN_PX

View File

@@ -2921,7 +2921,7 @@ wxWindowBase::ToDIP(const wxSize& sz, const wxWindowBase* w)
// using them. // using them.
wxSize wxWindowBase::GetDlgUnitBase() const wxSize wxWindowBase::GetDlgUnitBase() const
{ {
const wxWindowBase * const parent = wxGetTopLevelParent((wxWindow*)this); const wxWindowBase* const parent = wxGetTopLevelParent((wxWindow*)this);
wxCHECK_MSG( parent, wxDefaultSize, wxS("Must have TLW parent") ); wxCHECK_MSG( parent, wxDefaultSize, wxS("Must have TLW parent") );
@@ -2929,10 +2929,10 @@ wxSize wxWindowBase::GetDlgUnitBase() const
{ {
// Default GUI font is used. This is the most common case, so // Default GUI font is used. This is the most common case, so
// cache the results. // cache the results.
static wxSize s_defFontSize; static wxPrivate::DpiDependentValue<wxSize> s_defFontSize;
if ( s_defFontSize.x == 0 ) if ( s_defFontSize.HasChanged(parent) )
s_defFontSize = wxPrivate::GetAverageASCIILetterSize(*parent); s_defFontSize.SetAtNewDPI(wxPrivate::GetAverageASCIILetterSize(*parent));
return s_defFontSize; return s_defFontSize.Get();
} }
else else
{ {

View File

@@ -162,12 +162,25 @@ WXDWORD wxButton::MSWGetStyle(long style, WXDWORD *exstyle) const
/* static */ /* static */
wxSize wxButtonBase::GetDefaultSize() wxSize wxButtonBase::GetDefaultSize()
{ {
static wxSize s_sizeBtn; wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL;
if ( s_sizeBtn.x == 0 ) static wxPrivate::DpiDependentValue<wxSize> s_sizeBtn;
if ( s_sizeBtn.HasChanged(win) )
{ {
wxScreenDC dc; wxSize base;
dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); if ( win )
{
wxClientDC dc(win);
dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
base = wxPrivate::GetAverageASCIILetterSize(dc);
}
else
{
wxScreenDC dc;
dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
base = wxPrivate::GetAverageASCIILetterSize(dc);
}
// The size of a standard button in the dialog units is 50x14, // The size of a standard button in the dialog units is 50x14,
// translate this to pixels. // translate this to pixels.
@@ -180,12 +193,11 @@ wxSize wxButtonBase::GetDefaultSize()
// //
// NB: wxMulDivInt32() is used, because it correctly rounds the result // NB: wxMulDivInt32() is used, because it correctly rounds the result
const wxSize base = wxPrivate::GetAverageASCIILetterSize(dc); s_sizeBtn.SetAtNewDPI(wxSize(wxMulDivInt32(50, base.x, 4),
s_sizeBtn.x = wxMulDivInt32(50, base.x, 4); wxMulDivInt32(14, base.y, 8)));
s_sizeBtn.y = wxMulDivInt32(14, base.y, 8);
} }
return s_sizeBtn; return s_sizeBtn.Get();
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -28,15 +28,14 @@
#include "wx/checkbox.h" #include "wx/checkbox.h"
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/brush.h"
#include "wx/dcclient.h" #include "wx/dcclient.h"
#include "wx/dcscreen.h"
#include "wx/settings.h" #include "wx/settings.h"
#endif #endif
#include "wx/renderer.h" #include "wx/renderer.h"
#include "wx/msw/uxtheme.h" #include "wx/msw/uxtheme.h"
#include "wx/msw/private/button.h" #include "wx/msw/private/button.h"
#include "wx/private/window.h"
#include "wx/msw/missing.h" #include "wx/msw/missing.h"
// ============================================================================ // ============================================================================
@@ -98,16 +97,17 @@ WXDWORD wxCheckBox::MSWGetStyle(long style, WXDWORD *exstyle) const
wxSize wxCheckBox::DoGetBestClientSize() const wxSize wxCheckBox::DoGetBestClientSize() const
{ {
static int s_checkSize = 0; static wxPrivate::DpiDependentValue<wxCoord> s_checkSize;
if ( !s_checkSize ) if ( s_checkSize.HasChanged(this) )
{ {
wxScreenDC dc; wxClientDC dc(const_cast<wxCheckBox*>(this));
dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
s_checkSize = dc.GetCharHeight(); s_checkSize.SetAtNewDPI(dc.GetCharHeight());
} }
wxCoord& checkSize = s_checkSize.Get();
wxString str = wxGetWindowText(GetHWND()); wxString str = wxGetWindowText(GetHWND());
int wCheckbox, hCheckbox; int wCheckbox, hCheckbox;
@@ -116,7 +116,7 @@ wxSize wxCheckBox::DoGetBestClientSize() const
wxClientDC dc(const_cast<wxCheckBox *>(this)); wxClientDC dc(const_cast<wxCheckBox *>(this));
dc.SetFont(GetFont()); dc.SetFont(GetFont());
dc.GetMultiLineTextExtent(GetLabelText(str), &wCheckbox, &hCheckbox); dc.GetMultiLineTextExtent(GetLabelText(str), &wCheckbox, &hCheckbox);
wCheckbox += s_checkSize + GetCharWidth(); wCheckbox += checkSize + GetCharWidth();
if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & BS_MULTILINE ) if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & BS_MULTILINE )
{ {
@@ -128,16 +128,16 @@ wxSize wxCheckBox::DoGetBestClientSize() const
// label appears on 3 lines, not 2, under Windows 2003 using // label appears on 3 lines, not 2, under Windows 2003 using
// classic look and feel (although it works fine under Windows 7, // classic look and feel (although it works fine under Windows 7,
// with or without themes). // with or without themes).
wCheckbox += s_checkSize; wCheckbox += checkSize;
} }
if ( hCheckbox < s_checkSize ) if ( hCheckbox < checkSize )
hCheckbox = s_checkSize; hCheckbox = checkSize;
} }
else else
{ {
wCheckbox = s_checkSize; wCheckbox = checkSize;
hCheckbox = s_checkSize; hCheckbox = checkSize;
} }
return wxSize(wCheckbox, hCheckbox); return wxSize(wCheckbox, hCheckbox);

View File

@@ -63,9 +63,6 @@ public:
private: private:
bool m_destroyCursor; bool m_destroyCursor;
// standard cursor size, computed on first use
static wxSize ms_sizeStd;
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -110,28 +107,17 @@ public:
// wxCursorRefData // wxCursorRefData
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
wxSize wxCursorRefData::ms_sizeStd;
wxCoord wxCursorRefData::GetStandardWidth() wxCoord wxCursorRefData::GetStandardWidth()
{ {
if ( !ms_sizeStd.x ) const wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL;
{ return wxSystemSettings::GetMetric(wxSYS_CURSOR_X, win);
wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL;
ms_sizeStd.x = wxSystemSettings::GetMetric(wxSYS_CURSOR_X, win);
}
return ms_sizeStd.x;
} }
wxCoord wxCursorRefData::GetStandardHeight() wxCoord wxCursorRefData::GetStandardHeight()
{ {
if ( !ms_sizeStd.y ) const wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL;
{ return wxSystemSettings::GetMetric(wxSYS_CURSOR_Y, win);
wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL;
ms_sizeStd.y = wxSystemSettings::GetMetric(wxSYS_CURSOR_Y, win);
}
return ms_sizeStd.y;
} }
wxCursorRefData::wxCursorRefData(HCURSOR hcursor, bool destroy) wxCursorRefData::wxCursorRefData(HCURSOR hcursor, bool destroy)

View File

@@ -29,11 +29,11 @@
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/settings.h" #include "wx/settings.h"
#include "wx/dcscreen.h" #include "wx/dcclient.h"
#include "wx/toplevel.h"
#endif #endif
#include "wx/msw/private.h" #include "wx/msw/private.h"
#include "wx/private/window.h"
#include "wx/renderer.h" #include "wx/renderer.h"
#include "wx/msw/uxtheme.h" #include "wx/msw/uxtheme.h"
@@ -238,31 +238,32 @@ bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
wxSize wxRadioButton::DoGetBestSize() const wxSize wxRadioButton::DoGetBestSize() const
{ {
static int s_radioSize = 0; static wxPrivate::DpiDependentValue<wxCoord> s_radioSize;
if ( !s_radioSize ) if ( s_radioSize.HasChanged(this) )
{ {
wxScreenDC dc; wxClientDC dc(const_cast<wxRadioButton*>(this));
dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
s_radioSize = dc.GetCharHeight(); s_radioSize.SetAtNewDPI(dc.GetCharHeight());
} }
wxCoord& radioSize = s_radioSize.Get();
wxString str = GetLabel(); wxString str = GetLabel();
int wRadio, hRadio; int wRadio, hRadio;
if ( !str.empty() ) if ( !str.empty() )
{ {
GetTextExtent(GetLabelText(str), &wRadio, &hRadio); GetTextExtent(GetLabelText(str), &wRadio, &hRadio);
wRadio += s_radioSize + GetCharWidth(); wRadio += radioSize + GetCharWidth();
if ( hRadio < s_radioSize ) if ( hRadio < radioSize )
hRadio = s_radioSize; hRadio = radioSize;
} }
else else
{ {
wRadio = s_radioSize; wRadio = radioSize;
hRadio = s_radioSize; hRadio = radioSize;
} }
return wxSize(wRadio, hRadio); return wxSize(wRadio, hRadio);