Add wxWindow::GetDPI() for per-monitor DPI support.

See https://github.com/wxWidgets/wxWidgets/pull/1494
This commit is contained in:
Vadim Zeitlin 2019-08-21 23:44:19 +02:00
commit fe56ef557f
5 changed files with 103 additions and 33 deletions

View File

@ -99,6 +99,8 @@ public:
virtual bool Reparent(wxWindowBase *newParent) wxOVERRIDE;
virtual wxSize GetDPI() const wxOVERRIDE;
virtual void WarpPointer(int x, int y) wxOVERRIDE;
virtual bool EnableTouchEvents(int eventsMask) wxOVERRIDE;

View File

@ -949,14 +949,16 @@ public:
// translation between different units
// -----------------------------------
// Get the DPI used by the given window or wxSize(0, 0) if unknown.
virtual wxSize GetDPI() const;
// DPI-independent pixels, or DIPs, are pixel values for the standard
// 96 DPI display, they are scaled to take the current resolution into
// account (i.e. multiplied by the same factor as returned by
// GetContentScaleFactor()) if necessary for the current platform.
//
// Currently the conversion factor is the same for all windows but this
// will change with the monitor-specific resolution support in the
// future, so prefer using the non-static member functions.
// To support monitor-specific resolutions, prefer using the non-static
// member functions or use a valid (non-null) window pointer.
//
// Similarly, currently in practice the factor is the same in both
// horizontal and vertical directions, but this could, in principle,

View File

@ -2036,6 +2036,20 @@ public:
*/
virtual wxVisualAttributes GetDefaultAttributes() const;
/**
Return the DPI of the display used by this window.
The returned value can be different for different windows on systems
with support for per-monitor DPI values, such as Microsoft Windows 10.
If the DPI is not available, returns @c wxSize(0,0) object.
@see wxDisplay::GetPPI()
@since 3.1.3
*/
virtual wxSize GetDPI() const;
/**
Returns the font for this window.

View File

@ -74,6 +74,7 @@
#include "wx/sysopt.h"
#endif
#include "wx/display.h"
#include "wx/platinfo.h"
#include "wx/recguard.h"
#include "wx/private/window.h"
@ -787,15 +788,33 @@ wxSize wxWindowBase::DoGetBestSize() const
return best;
}
namespace
{
static wxSize GetDPIHelper(const wxWindowBase* w)
{
wxSize dpi;
if ( w )
dpi = w->GetDPI();
if ( !dpi.x || !dpi.y )
dpi = wxScreenDC().GetPPI();
if ( !dpi.x || !dpi.y )
dpi = wxSize(BASELINE_DPI, BASELINE_DPI);
return dpi;
}
}
double wxWindowBase::GetContentScaleFactor() const
{
// Currently we don't support per-monitor DPI, so it's useless to construct
// a DC associated with this window, just use the global value.
//
// We also use just the vertical component of the DPI because it's the one
const wxSize dpi = GetDPIHelper(this);
// We use just the vertical component of the DPI because it's the one
// that counts most and, in practice, it's equal to the horizontal one
// anyhow.
return double(wxScreenDC().GetPPI().y) / BASELINE_DPI;
return dpi.y / (double)BASELINE_DPI;
}
// helper of GetWindowBorderSize(): as many ports don't implement support for
@ -2855,13 +2874,18 @@ void wxWindowBase::OnInternalIdle()
// DPI-independent pixels and dialog units translations
// ----------------------------------------------------------------------------
wxSize wxWindowBase::GetDPI() const
{
return wxDisplay(static_cast<const wxWindow*>(this)).GetPPI();
}
#ifndef wxHAVE_DPI_INDEPENDENT_PIXELS
/* static */
wxSize
wxWindowBase::FromDIP(const wxSize& sz, const wxWindowBase* WXUNUSED(w))
wxWindowBase::FromDIP(const wxSize& sz, const wxWindowBase* w)
{
const wxSize dpi = wxScreenDC().GetPPI();
const wxSize dpi = GetDPIHelper(w);
// Take care to not scale -1 because it has a special meaning of
// "unspecified" which should be preserved.
@ -2871,9 +2895,9 @@ wxWindowBase::FromDIP(const wxSize& sz, const wxWindowBase* WXUNUSED(w))
/* static */
wxSize
wxWindowBase::ToDIP(const wxSize& sz, const wxWindowBase* WXUNUSED(w))
wxWindowBase::ToDIP(const wxSize& sz, const wxWindowBase* w)
{
const wxSize dpi = wxScreenDC().GetPPI();
const wxSize dpi = GetDPIHelper(w);
// Take care to not scale -1 because it has a special meaning of
// "unspecified" which should be preserved.

View File

@ -4719,23 +4719,28 @@ wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
namespace
{
static inline const wxTopLevelWindow* wxGetWinTLW(const wxWindow* win)
static wxSize GetWindowDPI(HWND hwnd)
{
if ( win )
#if wxUSE_DYNLIB_CLASS
typedef UINT (WINAPI *GetDpiForWindow_t)(HWND hwnd);
static GetDpiForWindow_t s_pfnGetDpiForWindow = NULL;
static bool s_initDone = false;
if ( !s_initDone )
{
const wxWindow* tlwWin = wxGetTopLevelParent(const_cast<wxWindow*>(win));
return wxDynamicCast(tlwWin, wxTopLevelWindow);
}
else if ( wxTheApp )
{
wxWindow* window = wxTheApp->GetTopWindow();
if ( window )
{
return wxDynamicCast(wxGetTopLevelParent(window), wxTopLevelWindow);
}
wxLoadedDLL dllUser32("user32.dll");
wxDL_INIT_FUNC(s_pfn, GetDpiForWindow, dllUser32);
s_initDone = true;
}
return NULL;
if ( s_pfnGetDpiForWindow )
{
const int dpi = static_cast<int>(s_pfnGetDpiForWindow(hwnd));
return wxSize(dpi, dpi);
}
#endif // wxUSE_DYNLIB_CLASS
return wxSize();
}
}
@ -4744,9 +4749,9 @@ static inline const wxTopLevelWindow* wxGetWinTLW(const wxWindow* win)
int wxGetSystemMetrics(int nIndex, const wxWindow* win)
{
#if wxUSE_DYNLIB_CLASS
const wxTopLevelWindow* tlw = wxGetWinTLW(win);
const wxWindow* window = (!win && wxTheApp) ? wxTheApp->GetTopWindow() : win;
if ( tlw )
if ( window )
{
typedef int (WINAPI * GetSystemMetricsForDpi_t)(int nIndex, UINT dpi);
static GetSystemMetricsForDpi_t s_pfnGetSystemMetricsForDpi = NULL;
@ -4761,8 +4766,7 @@ int wxGetSystemMetrics(int nIndex, const wxWindow* win)
if ( s_pfnGetSystemMetricsForDpi )
{
WindowHDC hdc(tlw->GetHWND());
const int dpi = ::GetDeviceCaps(hdc, LOGPIXELSY);
const int dpi = window->GetDPI().y;
return s_pfnGetSystemMetricsForDpi(nIndex, (UINT)dpi);
}
}
@ -4777,9 +4781,9 @@ int wxGetSystemMetrics(int nIndex, const wxWindow* win)
bool wxSystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni, const wxWindow* win)
{
#if wxUSE_DYNLIB_CLASS
const wxTopLevelWindow* tlw = wxGetWinTLW(win);
const wxWindow* window = (!win && wxTheApp) ? wxTheApp->GetTopWindow() : win;
if ( tlw )
if ( window )
{
typedef int (WINAPI * SystemParametersInfoForDpi_t)(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni, UINT dpi);
static SystemParametersInfoForDpi_t s_pfnSystemParametersInfoForDpi = NULL;
@ -4794,8 +4798,7 @@ bool wxSystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWi
if ( s_pfnSystemParametersInfoForDpi )
{
WindowHDC hdc(tlw->GetHWND());
const int dpi = ::GetDeviceCaps(hdc, LOGPIXELSY);
const int dpi = window->GetDPI().y;
if ( s_pfnSystemParametersInfoForDpi(uiAction, uiParam, pvParam, fWinIni, (UINT)dpi) == TRUE )
{
return true;
@ -4809,6 +4812,31 @@ bool wxSystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWi
return ::SystemParametersInfo(uiAction, uiParam, pvParam, fWinIni) == TRUE;
}
wxSize wxWindowMSW::GetDPI() const
{
HWND hwnd = GetHwnd();
if ( hwnd == NULL )
{
const wxWindow* topWin = wxGetTopLevelParent(const_cast<wxWindow*>(this));
if ( topWin )
{
hwnd = GetHwndOf(topWin);
}
}
wxSize dpi = GetWindowDPI(hwnd);
if ( !dpi.x || !dpi.y )
{
WindowHDC hdc(GetHwnd());
dpi.x = ::GetDeviceCaps(hdc, LOGPIXELSX);
dpi.y = ::GetDeviceCaps(hdc, LOGPIXELSY);
}
return dpi;
}
// ---------------------------------------------------------------------------
// colours and palettes
// ---------------------------------------------------------------------------