Merge branch 'msw-display-refresh'

Fixes for display information refreshing under MSW.

See https://github.com/wxWidgets/wxWidgets/pull/1282
This commit is contained in:
Vadim Zeitlin
2019-04-02 17:19:01 +02:00
2 changed files with 30 additions and 37 deletions

View File

@@ -81,6 +81,9 @@ public:
void OnLeftClick(wxMouseEvent& event); void OnLeftClick(wxMouseEvent& event);
private: private:
// Fill m_book with the information about all the displays.
void PopuplateWithDisplayInfo();
#if wxUSE_DISPLAY #if wxUSE_DISPLAY
// convert video mode to textual description // convert video mode to textual description
wxString VideoModeToText(const wxVideoMode& mode); wxString VideoModeToText(const wxVideoMode& mode);
@@ -233,6 +236,11 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
// create child controls // create child controls
m_book = new wxBookCtrl(this, wxID_ANY); m_book = new wxBookCtrl(this, wxID_ANY);
PopuplateWithDisplayInfo();
}
void MyFrame::PopuplateWithDisplayInfo()
{
const size_t countDpy = wxDisplay::GetCount(); const size_t countDpy = wxDisplay::GetCount();
for ( size_t nDpy = 0; nDpy < countDpy; nDpy++ ) for ( size_t nDpy = 0; nDpy < countDpy; nDpy++ )
{ {
@@ -426,16 +434,8 @@ void MyFrame::OnLeftClick(wxMouseEvent& event)
void MyFrame::OnDisplayChanged(wxDisplayChangedEvent& event) void MyFrame::OnDisplayChanged(wxDisplayChangedEvent& event)
{ {
// update the current mode text m_book->DeleteAllPages();
for ( size_t n = 0; n < m_book->GetPageCount(); n++ ) PopuplateWithDisplayInfo();
{
wxStaticText *label = wxDynamicCast(m_book->GetPage(n)->
FindWindow(Display_CurrentMode),
wxStaticText);
if ( label )
label->SetLabel(VideoModeToText(wxDisplay(n).GetCurrentMode()));
}
wxLogStatus(this, "Display resolution was changed."); wxLogStatus(this, "Display resolution was changed.");

View File

@@ -198,10 +198,6 @@ public:
DoRefreshMonitors(); DoRefreshMonitors();
} }
// Called when we receive WM_SETTINGCHANGE to refresh the list of monitor
// handles.
static void RefreshMonitors() { ms_factory->InvalidateCache(); }
// Declare the second argument as int to avoid problems with older SDKs not // Declare the second argument as int to avoid problems with older SDKs not
// declaring MONITOR_DPI_TYPE enum. // declaring MONITOR_DPI_TYPE enum.
typedef HRESULT (WINAPI *GetDpiForMonitor_t)(HMONITOR, int, UINT*, UINT*); typedef HRESULT (WINAPI *GetDpiForMonitor_t)(HMONITOR, int, UINT*, UINT*);
@@ -221,15 +217,9 @@ private:
// return wxNOT_FOUND if not found // return wxNOT_FOUND if not found
int FindDisplayFromHMONITOR(HMONITOR hmon) const; int FindDisplayFromHMONITOR(HMONITOR hmon) const;
// Update m_displays array, used by RefreshMonitors(). // Update m_displays array, used initially and by InvalidateCache().
void DoRefreshMonitors(); void DoRefreshMonitors();
// The unique factory being used (as we don't have direct access to the
// global factory pointer in the common code so we just duplicate this
// variable (also making it of correct type for us) here).
static wxDisplayFactoryMSW* ms_factory;
// The pointer to GetDpiForMonitorPtr(), retrieved on demand, and the // The pointer to GetDpiForMonitorPtr(), retrieved on demand, and the
// related data, including the DLL containing the function that we must // related data, including the DLL containing the function that we must
// keep loaded. // keep loaded.
@@ -285,7 +275,6 @@ private:
wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryMSW); wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryMSW);
}; };
wxDisplayFactoryMSW* wxDisplayFactoryMSW::ms_factory = NULL;
wxDisplayFactoryMSW::GetDpiForMonitorData wxDisplayFactoryMSW::GetDpiForMonitorData
wxDisplayFactoryMSW::ms_getDpiForMonitorData; wxDisplayFactoryMSW::ms_getDpiForMonitorData;
@@ -535,7 +524,8 @@ bool wxDisplayMSW::ChangeMode(const wxVideoMode& mode)
LRESULT APIENTRY LRESULT APIENTRY
wxDisplayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) wxDisplayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
if ( msg == WM_SETTINGCHANGE || msg == WM_DISPLAYCHANGE ) if ( (msg == WM_SETTINGCHANGE && wParam == SPI_SETWORKAREA) ||
msg == WM_DISPLAYCHANGE )
{ {
wxDisplay::InvalidateCache(); wxDisplay::InvalidateCache();
@@ -547,12 +537,6 @@ wxDisplayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
wxDisplayFactoryMSW::wxDisplayFactoryMSW() wxDisplayFactoryMSW::wxDisplayFactoryMSW()
{ {
// This is not supposed to happen with the current code, the factory is
// implicitly a singleton.
wxASSERT_MSG( !ms_factory, wxS("Using more than one factory?") );
ms_factory = this;
m_hiddenHwnd = NULL; m_hiddenHwnd = NULL;
m_hiddenClass = NULL; m_hiddenClass = NULL;
@@ -592,8 +576,6 @@ wxDisplayFactoryMSW::~wxDisplayFactoryMSW()
ms_getDpiForMonitorData.UnloadIfNecessary(); ms_getDpiForMonitorData.UnloadIfNecessary();
ms_getDpiForMonitorData.m_initialized = false; ms_getDpiForMonitorData.m_initialized = false;
} }
ms_factory = NULL;
} }
/* static */ /* static */
@@ -613,10 +595,10 @@ void wxDisplayFactoryMSW::DoRefreshMonitors()
{ {
m_displays.clear(); m_displays.clear();
// We need to pass a valid HDC here in order to get valid hdcMonitor in our // Note that we pass NULL as first parameter here because using screen HDC
// callback. // doesn't work reliably: notably, it doesn't enumerate any displays if
ScreenHDC dc; // this code is executed while a UAC prompt is shown or during log-off.
if ( !::EnumDisplayMonitors(dc, NULL, MultimonEnumProc, (LPARAM)this) ) if ( !::EnumDisplayMonitors(NULL, NULL, MultimonEnumProc, (LPARAM)this) )
{ {
wxLogLastError(wxT("EnumDisplayMonitors")); wxLogLastError(wxT("EnumDisplayMonitors"));
} }
@@ -626,13 +608,24 @@ void wxDisplayFactoryMSW::DoRefreshMonitors()
BOOL CALLBACK BOOL CALLBACK
wxDisplayFactoryMSW::MultimonEnumProc( wxDisplayFactoryMSW::MultimonEnumProc(
HMONITOR hMonitor, // handle to display monitor HMONITOR hMonitor, // handle to display monitor
HDC hdcMonitor, // handle to monitor-appropriate device context HDC /* hdcMonitor */, // handle to monitor-appropriate device context:
// not set due to our use of EnumDisplayMonitors(NULL, ...)
LPRECT WXUNUSED(lprcMonitor), // pointer to monitor intersection rectangle LPRECT WXUNUSED(lprcMonitor), // pointer to monitor intersection rectangle
LPARAM dwData) // data passed from EnumDisplayMonitors (this) LPARAM dwData) // data passed from EnumDisplayMonitors (this)
{ {
wxDisplayFactoryMSW *const self = (wxDisplayFactoryMSW *)dwData; wxDisplayFactoryMSW *const self = (wxDisplayFactoryMSW *)dwData;
self->m_displays.push_back(wxDisplayInfo(hMonitor, wxGetHDCDepth(hdcMonitor))); WinStruct<MONITORINFOEX> monInfo;
if ( !::GetMonitorInfo(hMonitor, &monInfo) )
{
wxLogLastError(wxT("GetMonitorInfo"));
}
HDC hdcMonitor = ::CreateDC(NULL, monInfo.szDevice, NULL, NULL);
const int hdcDepth = wxGetHDCDepth(hdcMonitor);
::DeleteDC(hdcMonitor);
self->m_displays.push_back(wxDisplayInfo(hMonitor, hdcDepth));
// continue the enumeration // continue the enumeration
return TRUE; return TRUE;