From 22c18a107efdbff65b9dcc67f2f33fa5f2c67662 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 18 Dec 2018 23:39:10 +0100 Subject: [PATCH] Invalidate wxDisplay cache under MSW when the displays change The cache added in 990c8bfd733577885baad419025fc0580557ba8c was not invalidated properly, meaning that wrong information was returned when displays were [dis]connected after the application startup. Fix this at least for MSW by invalidating the cache on receiving WM_DISPLAYCHANGE (which means that sometimes we will do it unnecessarily, as the change in resolution of an existing display doesn't require cache invalidation, but this shouldn't be a big problem in practice as the speed with which the user can change the display resolution is not very high). Closes https://github.com/wxWidgets/wxWidgets/pull/1090 --- include/wx/display.h | 5 +++++ include/wx/private/display.h | 8 +++++++- src/common/dpycmn.cpp | 9 ++++++++- src/msw/window.cpp | 5 ++++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/include/wx/display.h b/include/wx/display.h index 1c3a67298a..f05c0c8451 100644 --- a/include/wx/display.h +++ b/include/wx/display.h @@ -115,6 +115,11 @@ public: void ResetMode() { (void)ChangeMode(); } #endif // wxUSE_DISPLAY + // If the implementation caches any information about the displays, calling + // this function clears it -- this should be done e.g. after a display + // [dis]connection. + static void InvalidateCache(); + private: // returns the factory used to implement our static methods and create new // displays diff --git a/include/wx/private/display.h b/include/wx/private/display.h index 9a97a75f9c..15668eaaf8 100644 --- a/include/wx/private/display.h +++ b/include/wx/private/display.h @@ -22,7 +22,7 @@ class wxDisplayFactory { public: wxDisplayFactory() { } - virtual ~wxDisplayFactory(); + virtual ~wxDisplayFactory() { ClearImpls(); } // Create the display if necessary using CreateDisplay(), otherwise just // get it from cache. @@ -48,6 +48,9 @@ public: // the window pointer must not be NULL (i.e. caller should check it) virtual int GetFromWindow(const wxWindow *window); + // Trigger recreation of wxDisplayImpl when they're needed the next time. + void InvalidateCache() { ClearImpls(); } + protected: // create a new display object // @@ -55,6 +58,9 @@ protected: virtual wxDisplayImpl *CreateDisplay(unsigned n) = 0; private: + // Delete all the elements of m_impls vector and clear it. + void ClearImpls(); + // On-demand populated vector of wxDisplayImpl objects. wxVector m_impls; diff --git a/src/common/dpycmn.cpp b/src/common/dpycmn.cpp index 6171335b1a..85262ae042 100644 --- a/src/common/dpycmn.cpp +++ b/src/common/dpycmn.cpp @@ -113,6 +113,11 @@ wxDisplay::wxDisplay(const wxWindow* window) return Factory().GetFromWindow(window); } +/* static */ void wxDisplay::InvalidateCache() +{ + Factory().InvalidateCache(); +} + // ---------------------------------------------------------------------------- // functions forwarded to wxDisplayImpl // ---------------------------------------------------------------------------- @@ -229,13 +234,15 @@ wxSize wxDisplayImpl::GetPPI() const // wxDisplayFactory implementation // ============================================================================ -wxDisplayFactory::~wxDisplayFactory() +void wxDisplayFactory::ClearImpls() { for ( size_t n = 0; n < m_impls.size(); ++n ) { // It can be null, that's ok. delete m_impls[n]; } + + m_impls.clear(); } int wxDisplayFactory::GetFromWindow(const wxWindow *window) diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 609f6e8c19..652910c9af 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -58,8 +58,9 @@ #include "wx/ownerdrw.h" #endif -#include "wx/hashmap.h" +#include "wx/display.h" #include "wx/evtloop.h" +#include "wx/hashmap.h" #include "wx/popupwin.h" #include "wx/power.h" #include "wx/scopeguard.h" @@ -4692,6 +4693,8 @@ bool wxWindowMSW::HandleSysColorChange() bool wxWindowMSW::HandleDisplayChange() { + wxDisplay::InvalidateCache(); + wxDisplayChangedEvent event; event.SetEventObject(this);