From 767f545be5fe191f5abba35d1fb1374a7e2c158a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 8 Nov 2019 00:07:54 +0100 Subject: [PATCH 1/4] Number displays in the sample starting from 1, not 0 This is more usual and coincides with the built-in display names under MSW, where they're called "DISPLAY1", "DISPLAY2" etc. No real changes. --- samples/display/display.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/samples/display/display.cpp b/samples/display/display.cpp index 2d5b264dcb..2c7b523e92 100644 --- a/samples/display/display.cpp +++ b/samples/display/display.cpp @@ -327,9 +327,7 @@ void MyFrame::PopuplateWithDisplayInfo() page->SetSizer(sizerTop); page->Layout(); - m_book->AddPage(page, - wxString::Format("Display %lu", - (unsigned long)nDpy)); + m_book->AddPage(page, wxString::Format("Display %zu", nDpy + 1)); } SetClientSize(m_book->GetBestSize()); From 46cb23b0309b823cd99c9b8e509e750eaaa8693a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 8 Nov 2019 00:09:29 +0100 Subject: [PATCH 2/4] Don't assume that the first monitor is always the primary one This is not necessarily the case at least under MSW, so while it makes sense to do this by default in wxDisplayImpl::IsPrimary() implementation, MSW-specific version should override it instead of being totally unused as it was until now. --- src/common/dpycmn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/dpycmn.cpp b/src/common/dpycmn.cpp index b9123f39dd..24e77f237f 100644 --- a/src/common/dpycmn.cpp +++ b/src/common/dpycmn.cpp @@ -159,7 +159,7 @@ wxString wxDisplay::GetName() const bool wxDisplay::IsPrimary() const { - return m_impl && m_impl->GetIndex() == 0; + return m_impl && m_impl->IsPrimary(); } #if wxUSE_DISPLAY From d8cd02b480f3d14e70b7fb829b2436b0eece1b52 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 8 Nov 2019 00:26:20 +0100 Subject: [PATCH 3/4] Create primary monitor when using wxDisplay default ctor Previously, the first monitor was created instead and while it was often also the primary one, this wasn't always the case. In particular, this makes wxGetDisplayPPI() always return something reasonable instead of returning (0, 0) when the first monitor is not the primary one, as expected by plenty of code, including our own printing sample, which divides by the values returned from wxGetDisplayPPI() without checking if they're zero. --- include/wx/display.h | 8 +++++--- include/wx/private/display.h | 3 +++ interface/wx/display.h | 8 +++++++- src/common/dpycmn.cpp | 26 +++++++++++++++++++++++++- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/include/wx/display.h b/include/wx/display.h index f05c0c8451..b9fec42aba 100644 --- a/include/wx/display.h +++ b/include/wx/display.h @@ -42,12 +42,14 @@ class WXDLLIMPEXP_FWD_CORE wxDisplayImpl; class WXDLLIMPEXP_CORE wxDisplay { public: + // default ctor creates the object corresponding to the primary display + wxDisplay(); + // initialize the object containing all information about the given // display // - // the displays are numbered from 0 to GetCount() - 1, 0 is always the - // primary display and the only one which is always supported - wxDisplay(unsigned n = 0); + // the displays are numbered from 0 to GetCount() - 1 + explicit wxDisplay(unsigned n); // create display object corresponding to the display of the given window // or the default one if the window display couldn't be found diff --git a/include/wx/private/display.h b/include/wx/private/display.h index e7358f6e18..36f5985fbb 100644 --- a/include/wx/private/display.h +++ b/include/wx/private/display.h @@ -37,6 +37,9 @@ public: return m_impls[n]; } + // Return the primary display object, creating it if necessary. + wxDisplayImpl* GetPrimaryDisplay(); + // get the total number of displays virtual unsigned GetCount() = 0; diff --git a/interface/wx/display.h b/interface/wx/display.h index 3c4e28f4bb..2085ff15db 100644 --- a/interface/wx/display.h +++ b/interface/wx/display.h @@ -16,6 +16,12 @@ class wxDisplay { public: + /** + Default constructor creating wxDisplay object representing the primary + display. + */ + wxDisplay(); + /** Constructor, setting up a wxDisplay instance with the specified display. @@ -24,7 +30,7 @@ public: The index of the display to use. This must be non-negative and lower than the value returned by GetCount(). */ - wxDisplay(unsigned int index = 0); + explicit wxDisplay(unsigned int index); /** Constructor creating the display object associated with the given diff --git a/src/common/dpycmn.cpp b/src/common/dpycmn.cpp index 24e77f237f..4f0d537ef1 100644 --- a/src/common/dpycmn.cpp +++ b/src/common/dpycmn.cpp @@ -77,6 +77,11 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule); // ctor/dtor // ---------------------------------------------------------------------------- +wxDisplay::wxDisplay() +{ + m_impl = Factory().GetPrimaryDisplay(); +} + wxDisplay::wxDisplay(unsigned n) { wxASSERT_MSG( n == 0 || n < GetCount(), @@ -89,7 +94,8 @@ wxDisplay::wxDisplay(const wxWindow* window) { const int n = GetFromWindow(window); - m_impl = Factory().GetDisplay(n != wxNOT_FOUND ? n : 0); + m_impl = n != wxNOT_FOUND ? Factory().GetDisplay(n) + : Factory().GetPrimaryDisplay(); } // ---------------------------------------------------------------------------- @@ -245,6 +251,24 @@ void wxDisplayFactory::ClearImpls() m_impls.clear(); } +wxDisplayImpl* wxDisplayFactory::GetPrimaryDisplay() +{ + // Just use dumb linear search -- there seems to be the most reliable way + // to do this in general. In particular, primary monitor is not guaranteed + // to be the first one and it's not obvious if it always contains (0, 0). + const unsigned count = GetCount(); + for ( unsigned n = 0; n < count; ++n ) + { + wxDisplayImpl* const d = GetDisplay(n); + if ( d && d->IsPrimary() ) + return d; + } + + // This is not supposed to happen, but what else can we do if it + // somehow does? + return NULL; +} + int wxDisplayFactory::GetFromWindow(const wxWindow *window) { wxCHECK_MSG( window, wxNOT_FOUND, "window can't be NULL" ); From cdc68999247056fff21f2f7c8ccfa49c15c948ec Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 8 Nov 2019 00:34:40 +0100 Subject: [PATCH 4/4] Store MONITORINFOEX inside wxDisplayMSW There is no reason to call ::GetMonitorInfo() all the time, e.g. just to determine if the monitor is primary, as we can just store it entirely. We already invalidate the information stored for all the displays whenever anything changes, so the cached information doesn't risk getting out of sync. --- src/msw/display.cpp | 55 +++++++++------------------------------------ 1 file changed, 11 insertions(+), 44 deletions(-) diff --git a/src/msw/display.cpp b/src/msw/display.cpp index f159ec8db7..121ff78779 100644 --- a/src/msw/display.cpp +++ b/src/msw/display.cpp @@ -111,9 +111,14 @@ namespace // Simple struct storing the information needed by wxDisplayMSW. struct wxDisplayInfo { - wxDisplayInfo(HMONITOR hmon_, int depth_) : hmon(hmon_), depth(depth_) {} + wxDisplayInfo(HMONITOR hmon_, + const MONITORINFOEX& monInfo_, + int depth_) + : hmon(hmon_), monInfo(monInfo_), depth(depth_) + {} HMONITOR hmon; + MONITORINFOEX monInfo; int depth; }; @@ -157,10 +162,6 @@ protected: dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0); } - // Call GetMonitorInfo() and fill in the provided struct and return true if - // it succeeded, otherwise return false. - bool GetMonInfo(MONITORINFOEX& monInfo) const; - wxDisplayInfo m_info; private: @@ -298,37 +299,14 @@ wxDisplayFactoryMSW::GetDpiForMonitorData // wxDisplayMSW implementation // ---------------------------------------------------------------------------- -bool wxDisplayMSW::GetMonInfo(MONITORINFOEX& monInfo) const -{ - if ( !::GetMonitorInfo(m_info.hmon, &monInfo) ) - { - wxLogLastError(wxT("GetMonitorInfo")); - return false; - } - - return true; -} - wxRect wxDisplayMSW::GetGeometry() const { - WinStruct monInfo; - - wxRect rect; - if ( GetMonInfo(monInfo) ) - wxCopyRECTToRect(monInfo.rcMonitor, rect); - - return rect; + return wxRectFromRECT(m_info.monInfo.rcMonitor); } wxRect wxDisplayMSW::GetClientArea() const { - WinStruct monInfo; - - wxRect rectClient; - if ( GetMonInfo(monInfo) ) - wxCopyRECTToRect(monInfo.rcWork, rectClient); - - return rectClient; + return wxRectFromRECT(m_info.monInfo.rcWork); } int wxDisplayMSW::GetDepth() const @@ -356,23 +334,12 @@ wxSize wxDisplayMSW::GetPPI() const wxString wxDisplayMSW::GetName() const { - WinStruct monInfo; - - wxString name; - if ( GetMonInfo(monInfo) ) - name = monInfo.szDevice; - - return name; + return m_info.monInfo.szDevice; } bool wxDisplayMSW::IsPrimary() const { - WinStruct monInfo; - - if ( !GetMonInfo(monInfo) ) - return false; - - return (monInfo.dwFlags & MONITORINFOF_PRIMARY) != 0; + return (m_info.monInfo.dwFlags & MONITORINFOF_PRIMARY) != 0; } wxVideoMode wxDisplayMSW::GetCurrentMode() const @@ -623,7 +590,7 @@ wxDisplayFactoryMSW::MultimonEnumProc( const int hdcDepth = wxGetHDCDepth(hdcMonitor); ::DeleteDC(hdcMonitor); - self->m_displays.push_back(wxDisplayInfo(hMonitor, hdcDepth)); + self->m_displays.push_back(wxDisplayInfo(hMonitor, monInfo, hdcDepth)); // continue the enumeration return TRUE;