Invalidate wxDisplay cache under MSW when the displays change

The cache added in 990c8bfd73 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
This commit is contained in:
Vadim Zeitlin
2018-12-18 23:39:10 +01:00
parent 7f63adde95
commit 22c18a107e
4 changed files with 24 additions and 3 deletions

View File

@@ -115,6 +115,11 @@ public:
void ResetMode() { (void)ChangeMode(); } void ResetMode() { (void)ChangeMode(); }
#endif // wxUSE_DISPLAY #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: private:
// returns the factory used to implement our static methods and create new // returns the factory used to implement our static methods and create new
// displays // displays

View File

@@ -22,7 +22,7 @@ class wxDisplayFactory
{ {
public: public:
wxDisplayFactory() { } wxDisplayFactory() { }
virtual ~wxDisplayFactory(); virtual ~wxDisplayFactory() { ClearImpls(); }
// Create the display if necessary using CreateDisplay(), otherwise just // Create the display if necessary using CreateDisplay(), otherwise just
// get it from cache. // get it from cache.
@@ -48,6 +48,9 @@ public:
// the window pointer must not be NULL (i.e. caller should check it) // the window pointer must not be NULL (i.e. caller should check it)
virtual int GetFromWindow(const wxWindow *window); virtual int GetFromWindow(const wxWindow *window);
// Trigger recreation of wxDisplayImpl when they're needed the next time.
void InvalidateCache() { ClearImpls(); }
protected: protected:
// create a new display object // create a new display object
// //
@@ -55,6 +58,9 @@ protected:
virtual wxDisplayImpl *CreateDisplay(unsigned n) = 0; virtual wxDisplayImpl *CreateDisplay(unsigned n) = 0;
private: private:
// Delete all the elements of m_impls vector and clear it.
void ClearImpls();
// On-demand populated vector of wxDisplayImpl objects. // On-demand populated vector of wxDisplayImpl objects.
wxVector<wxDisplayImpl*> m_impls; wxVector<wxDisplayImpl*> m_impls;

View File

@@ -113,6 +113,11 @@ wxDisplay::wxDisplay(const wxWindow* window)
return Factory().GetFromWindow(window); return Factory().GetFromWindow(window);
} }
/* static */ void wxDisplay::InvalidateCache()
{
Factory().InvalidateCache();
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// functions forwarded to wxDisplayImpl // functions forwarded to wxDisplayImpl
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -229,13 +234,15 @@ wxSize wxDisplayImpl::GetPPI() const
// wxDisplayFactory implementation // wxDisplayFactory implementation
// ============================================================================ // ============================================================================
wxDisplayFactory::~wxDisplayFactory() void wxDisplayFactory::ClearImpls()
{ {
for ( size_t n = 0; n < m_impls.size(); ++n ) for ( size_t n = 0; n < m_impls.size(); ++n )
{ {
// It can be null, that's ok. // It can be null, that's ok.
delete m_impls[n]; delete m_impls[n];
} }
m_impls.clear();
} }
int wxDisplayFactory::GetFromWindow(const wxWindow *window) int wxDisplayFactory::GetFromWindow(const wxWindow *window)

View File

@@ -58,8 +58,9 @@
#include "wx/ownerdrw.h" #include "wx/ownerdrw.h"
#endif #endif
#include "wx/hashmap.h" #include "wx/display.h"
#include "wx/evtloop.h" #include "wx/evtloop.h"
#include "wx/hashmap.h"
#include "wx/popupwin.h" #include "wx/popupwin.h"
#include "wx/power.h" #include "wx/power.h"
#include "wx/scopeguard.h" #include "wx/scopeguard.h"
@@ -4692,6 +4693,8 @@ bool wxWindowMSW::HandleSysColorChange()
bool wxWindowMSW::HandleDisplayChange() bool wxWindowMSW::HandleDisplayChange()
{ {
wxDisplay::InvalidateCache();
wxDisplayChangedEvent event; wxDisplayChangedEvent event;
event.SetEventObject(this); event.SetEventObject(this);