diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h index b9b911bf7e..876d0d2b93 100644 --- a/include/wx/msw/window.h +++ b/include/wx/msw/window.h @@ -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; diff --git a/include/wx/window.h b/include/wx/window.h index 5dbecc519a..c08ffa7712 100644 --- a/include/wx/window.h +++ b/include/wx/window.h @@ -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, diff --git a/interface/wx/window.h b/interface/wx/window.h index ee69245147..8628ce5d26 100644 --- a/interface/wx/window.h +++ b/interface/wx/window.h @@ -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. diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp index 4939c3be30..63cc64514a 100644 --- a/src/common/wincmn.cpp +++ b/src/common/wincmn.cpp @@ -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" @@ -2855,6 +2856,11 @@ void wxWindowBase::OnInternalIdle() // DPI-independent pixels and dialog units translations // ---------------------------------------------------------------------------- +wxSize wxWindowBase::GetDPI() const +{ + return wxDisplay(static_cast(this)).GetPPI(); +} + #ifndef wxHAVE_DPI_INDEPENDENT_PIXELS /* static */ diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 7d9b33a068..77a883460b 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -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(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(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(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 // ---------------------------------------------------------------------------