From 4700298c2667bee149b17e2ccbb21b816639cc7e Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Mon, 1 Jun 2020 13:58:12 +0200 Subject: [PATCH] Move DPI handling from wxTopLevelWindow to wxNonOwnedWindow This way, other windows (like wxPopupWindow) will also be able to handle DPI events. Override InheritAttributes() and use it to set the initial DPI values. --- include/wx/msw/nonownedwnd.h | 16 +++++ include/wx/msw/toplevel.h | 14 +---- src/msw/nonownedwnd.cpp | 119 ++++++++++++++++++++++++++++++----- src/msw/toplevel.cpp | 80 +---------------------- 4 files changed, 122 insertions(+), 107 deletions(-) diff --git a/include/wx/msw/nonownedwnd.h b/include/wx/msw/nonownedwnd.h index c5d40bfa97..a3f8aa4274 100644 --- a/include/wx/msw/nonownedwnd.h +++ b/include/wx/msw/nonownedwnd.h @@ -27,11 +27,27 @@ protected: virtual bool DoSetRegionShape(const wxRegion& region) wxOVERRIDE; #if wxUSE_GRAPHICS_CONTEXT virtual bool DoSetPathShape(const wxGraphicsPath& path) wxOVERRIDE; +#endif // wxUSE_GRAPHICS_CONTEXT + + virtual WXLRESULT MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) wxOVERRIDE; + virtual void InheritAttributes() wxOVERRIDE; private: + bool HandleDPIChange(const wxSize& newDPI, const wxRect& newRect); + +#if wxUSE_GRAPHICS_CONTEXT wxNonOwnedWindowShapeImpl* m_shapeImpl; #endif // wxUSE_GRAPHICS_CONTEXT + // Keep track of the DPI used in this window. So when per-monitor dpi + // awareness is enabled, both old and new DPI are known for + // wxDPIChangedEvent and wxWindow::MSWUpdateOnDPIChange. + wxSize m_activeDPI; + + // This window supports handling per-monitor DPI awareness when the + // application manifest contains PerMonitorV2. + bool m_perMonitorDPIaware; + wxDECLARE_NO_COPY_CLASS(wxNonOwnedWindow); }; diff --git a/include/wx/msw/toplevel.h b/include/wx/msw/toplevel.h index d32764bb1f..5412de421e 100644 --- a/include/wx/msw/toplevel.h +++ b/include/wx/msw/toplevel.h @@ -115,7 +115,7 @@ public: virtual WXHWND MSWGetParent() const wxOVERRIDE; // window proc for the frames - WXLRESULT MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) wxOVERRIDE; + virtual WXLRESULT MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) wxOVERRIDE; // returns true if the platform should explicitly apply a theme border virtual bool CanApplyThemeBorder() const wxOVERRIDE { return false; } @@ -166,9 +166,6 @@ protected: int& x, int& y, int& w, int& h) const wxOVERRIDE; - // WM_DPICHANGED handler. - bool HandleDPIChange(const wxSize& newDPI, const wxRect& newRect); - // This field contains the show command to use when showing the window the // next time and also indicates whether the window should be considered // being iconized or maximized (which may be different from whether it's @@ -195,15 +192,6 @@ protected: wxWindowRef m_winLastFocused; private: - // Keep track of the DPI used in this window. So when per-monitor dpi - // awareness is enabled, both old and new DPI are known for - // wxDPIChangedEvent and wxWindow::MSWUpdateOnDPIChange. - wxSize m_activeDPI; - - // This window supports handling per-monitor DPI awareness when the - // application manifest contains PerMonitorV2. - bool m_perMonitorDPIaware; - // The system menu: initially NULL but can be set (once) by // MSWGetSystemMenu(). Owned by this window. wxMenu *m_menuSystem; diff --git a/src/msw/nonownedwnd.cpp b/src/msw/nonownedwnd.cpp index 3876870071..16ca7ae585 100644 --- a/src/msw/nonownedwnd.cpp +++ b/src/msw/nonownedwnd.cpp @@ -36,6 +36,7 @@ #include "wx/graphics.h" #endif // wxUSE_GRAPHICS_CONTEXT +#include "wx/dynlib.h" #include "wx/scopedptr.h" // ============================================================================ @@ -128,16 +129,6 @@ private: wxDECLARE_NO_COPY_CLASS(wxNonOwnedWindowShapeImpl); }; -wxNonOwnedWindow::wxNonOwnedWindow() -{ - m_shapeImpl = NULL; -} - -wxNonOwnedWindow::~wxNonOwnedWindow() -{ - delete m_shapeImpl; -} - bool wxNonOwnedWindow::DoSetPathShape(const wxGraphicsPath& path) { delete m_shapeImpl; @@ -146,17 +137,115 @@ bool wxNonOwnedWindow::DoSetPathShape(const wxGraphicsPath& path) return true; } -#else // !wxUSE_GRAPHICS_CONTEXT +#endif // wxUSE_GRAPHICS_CONTEXT -// Trivial ctor and dtor as we don't have anything to do when wxGraphicsContext -// is not used but still define them here to avoid adding even more #if checks -// to the header, it it doesn't do any harm even though it's not needed. wxNonOwnedWindow::wxNonOwnedWindow() { +#if wxUSE_GRAPHICS_CONTEXT + m_shapeImpl = NULL; +#endif // wxUSE_GRAPHICS_CONTEXT + + m_activeDPI = wxDefaultSize; + m_perMonitorDPIaware = false; } wxNonOwnedWindow::~wxNonOwnedWindow() { +#if wxUSE_GRAPHICS_CONTEXT + delete m_shapeImpl; +#endif // wxUSE_GRAPHICS_CONTEXT } -#endif // wxUSE_GRAPHICS_CONTEXT/!wxUSE_GRAPHICS_CONTEXT +namespace +{ + +static bool IsPerMonitorDPIAware(HWND hwnd) +{ + bool dpiAware = false; + + // Determine if 'Per Monitor v2' DPI awareness is enabled in the + // applications manifest. +#if wxUSE_DYNLIB_CLASS + #define WXDPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((WXDPI_AWARENESS_CONTEXT)-4) + typedef WXDPI_AWARENESS_CONTEXT(WINAPI * GetWindowDpiAwarenessContext_t)(HWND hwnd); + typedef BOOL(WINAPI * AreDpiAwarenessContextsEqual_t)(WXDPI_AWARENESS_CONTEXT dpiContextA, WXDPI_AWARENESS_CONTEXT dpiContextB); + static GetWindowDpiAwarenessContext_t s_pfnGetWindowDpiAwarenessContext = NULL; + static AreDpiAwarenessContextsEqual_t s_pfnAreDpiAwarenessContextsEqual = NULL; + static bool s_initDone = false; + + if ( !s_initDone ) + { + wxLoadedDLL dllUser32("user32.dll"); + wxDL_INIT_FUNC(s_pfn, GetWindowDpiAwarenessContext, dllUser32); + wxDL_INIT_FUNC(s_pfn, AreDpiAwarenessContextsEqual, dllUser32); + s_initDone = true; + } + + if ( s_pfnGetWindowDpiAwarenessContext && s_pfnAreDpiAwarenessContextsEqual ) + { + WXDPI_AWARENESS_CONTEXT dpiAwarenessContext = s_pfnGetWindowDpiAwarenessContext(hwnd); + + if ( s_pfnAreDpiAwarenessContextsEqual(dpiAwarenessContext, WXDPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) == TRUE ) + { + dpiAware = true; + } + } +#endif // wxUSE_DYNLIB_CLASS + + return dpiAware; +} + +} + +void wxNonOwnedWindow::InheritAttributes() +{ + m_activeDPI = GetDPI(); + m_perMonitorDPIaware = IsPerMonitorDPIAware(GetHwnd()); + + wxNonOwnedWindowBase::InheritAttributes(); +} + +WXLRESULT wxNonOwnedWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) +{ + WXLRESULT rc = 0; + bool processed = false; + + switch ( message ) + { + case WM_DPICHANGED: + { + const RECT* const prcNewWindow = + reinterpret_cast(lParam); + + processed = HandleDPIChange(wxSize(LOWORD(wParam), + HIWORD(wParam)), + wxRectFromRECT(*prcNewWindow)); + } + break; + } + + if (!processed) + rc = wxNonOwnedWindowBase::MSWWindowProc(message, wParam, lParam); + + return rc; +} + +bool wxNonOwnedWindow::HandleDPIChange(const wxSize& newDPI, const wxRect& newRect) +{ + if ( !m_perMonitorDPIaware ) + { + return false; + } + + if ( newDPI != m_activeDPI ) + { + MSWUpdateOnDPIChange(m_activeDPI, newDPI); + m_activeDPI = newDPI; + } + + SetSize(newRect); + + Refresh(); + + return true; +} diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index 2ede920e8b..4c552f2604 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -37,7 +37,6 @@ #include "wx/module.h" #endif //WX_PRECOMP -#include "wx/dynlib.h" #include "wx/scopeguard.h" #include "wx/tooltip.h" @@ -104,9 +103,6 @@ void wxTopLevelWindowMSW::Init() m_fsIsShowing = false; m_menuSystem = NULL; - - m_activeDPI = wxDefaultSize; - m_perMonitorDPIaware = false; } WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const @@ -249,26 +245,6 @@ WXHWND wxTopLevelWindowMSW::MSWGetParent() const return (WXHWND)hwndParent; } -bool wxTopLevelWindowMSW::HandleDPIChange(const wxSize& newDPI, const wxRect& newRect) -{ - if ( !m_perMonitorDPIaware ) - { - return false; - } - - if ( newDPI != m_activeDPI ) - { - MSWUpdateOnDPIChange(m_activeDPI, newDPI); - m_activeDPI = newDPI; - } - - SetSize(newRect); - - Refresh(); - - return true; -} - WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) { WXLRESULT rc = 0; @@ -329,17 +305,6 @@ WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WX #endif // #ifndef __WXUNIVERSAL__ } break; - - case WM_DPICHANGED: - { - const RECT* const prcNewWindow = - reinterpret_cast(lParam); - - processed = HandleDPIChange(wxSize(LOWORD(wParam), - HIWORD(wParam)), - wxRectFromRECT(*prcNewWindow)); - } - break; } if ( !processed ) @@ -348,47 +313,6 @@ WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WX return rc; } -namespace -{ - -static bool IsPerMonitorDPIAware(HWND hwnd) -{ - bool dpiAware = false; - - // Determine if 'Per Monitor v2' DPI awareness is enabled in the - // applications manifest. -#if wxUSE_DYNLIB_CLASS - #define WXDPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((WXDPI_AWARENESS_CONTEXT)-4) - typedef WXDPI_AWARENESS_CONTEXT(WINAPI * GetWindowDpiAwarenessContext_t)(HWND hwnd); - typedef BOOL(WINAPI * AreDpiAwarenessContextsEqual_t)(WXDPI_AWARENESS_CONTEXT dpiContextA, WXDPI_AWARENESS_CONTEXT dpiContextB); - static GetWindowDpiAwarenessContext_t s_pfnGetWindowDpiAwarenessContext = NULL; - static AreDpiAwarenessContextsEqual_t s_pfnAreDpiAwarenessContextsEqual = NULL; - static bool s_initDone = false; - - if ( !s_initDone ) - { - wxLoadedDLL dllUser32("user32.dll"); - wxDL_INIT_FUNC(s_pfn, GetWindowDpiAwarenessContext, dllUser32); - wxDL_INIT_FUNC(s_pfn, AreDpiAwarenessContextsEqual, dllUser32); - s_initDone = true; - } - - if ( s_pfnGetWindowDpiAwarenessContext && s_pfnAreDpiAwarenessContextsEqual ) - { - WXDPI_AWARENESS_CONTEXT dpiAwarenessContext = s_pfnGetWindowDpiAwarenessContext(hwnd); - - if ( s_pfnAreDpiAwarenessContextsEqual(dpiAwarenessContext, WXDPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) == TRUE ) - { - dpiAware = true; - } - } -#endif // wxUSE_DYNLIB_CLASS - - return dpiAware; -} - -} - bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate, const wxString& title, const wxPoint& pos, @@ -559,9 +483,7 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent, EnableCloseButton(false); } - m_activeDPI = GetDPI(); - - m_perMonitorDPIaware = IsPerMonitorDPIAware(GetHwnd()); + InheritAttributes(); // for standard dialogs the dialog manager generates WM_CHANGEUISTATE // itself but for custom windows we have to do it ourselves in order to