diff --git a/include/wx/display.h b/include/wx/display.h index 9d88425d77..f82c0fcf7e 100644 --- a/include/wx/display.h +++ b/include/wx/display.h @@ -94,6 +94,9 @@ public: // get the resolution of this monitor in pixels per inch wxSize GetPPI() const; + // get raw resolution in pixels per inch, i.e. without applying any scaling + wxSize GetRawPPI() const; + // get the default resolution for displays on this platform static int GetStdPPIValue() { diff --git a/include/wx/private/display.h b/include/wx/private/display.h index 23a7bf2e96..7dad779a1f 100644 --- a/include/wx/private/display.h +++ b/include/wx/private/display.h @@ -102,6 +102,10 @@ public: // but can be also overridden directly, as is done in wxMSW virtual wxSize GetPPI() const { return wxDisplay::GetStdPPI()*GetScaleFactor(); } + // return raw resolution of the display, by default returns standard PPI + // but should be overridden + virtual wxSize GetRawPPI() const { return wxDisplay::GetStdPPI(); } + // return the name (may be empty) virtual wxString GetName() const { return wxString(); } diff --git a/interface/wx/display.h b/interface/wx/display.h index 6fe7170ac2..d0a0fb2cc9 100644 --- a/interface/wx/display.h +++ b/interface/wx/display.h @@ -167,6 +167,19 @@ public: */ wxSize GetPPI() const; + /** + Returns raw display resolution in pixels per inch, i.e.\ without + applying any scaling. + + Horizontal and vertical resolution are returned in @c x and @c y + components of the wxSize object respectively. + + If the resolution information is not available, returns `wxSize(0, 0)`. + + @since 3.3.2 + */ + wxSize GetRawPPI() const; + /** Returns scaling factor used by this display. diff --git a/samples/display/display.cpp b/samples/display/display.cpp index 4f175bc877..e96d144944 100644 --- a/samples/display/display.cpp +++ b/samples/display/display.cpp @@ -299,8 +299,19 @@ void MyFrame::PopuplateWithDisplayInfo() sizer->Add(new wxStaticText(page, wxID_ANY, "Resolution: ")); const wxSize ppi = display.GetPPI(); - sizer->Add(new wxStaticText(page, wxID_ANY, - wxString::Format("%d*%d", ppi.x, ppi.y))); + const wxSize ppiRaw = display.GetRawPPI(); + wxString resolutionText; + if ( ppiRaw == ppi ) + { + resolutionText = wxString::Format("%d*%d", ppi.x, ppi.y); + } + else + { + resolutionText = wxString::Format("%d*%d (logical), %d*%d (raw)", + ppi.x, ppi.y, ppiRaw.x, ppiRaw.y); + } + + sizer->Add(new wxStaticText(page, wxID_ANY, resolutionText)); sizer->Add(new wxStaticText(page, wxID_ANY, "Depth: ")); sizer->Add(new wxStaticText(page, wxID_ANY, diff --git a/src/common/dpycmn.cpp b/src/common/dpycmn.cpp index 4c4883293a..4f83b41049 100644 --- a/src/common/dpycmn.cpp +++ b/src/common/dpycmn.cpp @@ -167,6 +167,16 @@ wxSize wxDisplay::GetPPI() const return m_impl->GetPPI(); } +wxSize wxDisplay::GetRawPPI() const +{ + wxCHECK_MSG( IsOk(), wxSize(), wxT("invalid wxDisplay object") ); + + if ( !m_impl->IsConnected() ) + return wxSize(); + + return m_impl->GetRawPPI(); +} + double wxDisplay::GetScaleFactor() const { wxCHECK_MSG( IsOk(), 0, wxT("invalid wxDisplay object") ); diff --git a/src/gtk/display.cpp b/src/gtk/display.cpp index 2a4112c840..55e8b7c8c0 100644 --- a/src/gtk/display.cpp +++ b/src/gtk/display.cpp @@ -246,6 +246,7 @@ public: #if GTK_CHECK_VERSION(3,10,0) virtual double GetScaleFactor() const override; #endif // GTK+ 3.10 + virtual wxSize GetRawPPI() const override; #if wxUSE_DISPLAY virtual bool IsPrimary() const override; @@ -340,6 +341,22 @@ double wxDisplayImplGTK::GetScaleFactor() const } #endif // GTK+ 3.10 +wxSize wxDisplayImplGTK::GetRawPPI() const +{ + auto const widthInMM = gdk_screen_get_monitor_width_mm(m_screen, m_index); + auto const heightInMM = gdk_screen_get_monitor_height_mm(m_screen, m_index); + + // Don't use manifestly invalid values. + if ( widthInMM <= 0 && heightInMM <= 0 ) + return wxDisplay::GetStdPPI(); + + const wxRect geometry = GetGeometry(); + const double ppiX = geometry.width * 25.4 / widthInMM; + const double ppiY = geometry.height * 25.4 / heightInMM; + + return wxSize(wxRound(ppiX), wxRound(ppiY)); +} + #if wxUSE_DISPLAY bool wxDisplayImplGTK::IsPrimary() const { diff --git a/src/msw/display.cpp b/src/msw/display.cpp index a2bb9149f2..16645e7a89 100644 --- a/src/msw/display.cpp +++ b/src/msw/display.cpp @@ -93,6 +93,7 @@ protected: #ifndef DPI_ENUMS_DECLARED #define MDT_EFFECTIVE_DPI 0 + #define MDT_RAW_DPI 2 #endif namespace @@ -131,6 +132,7 @@ public: virtual wxRect GetClientArea() const override; virtual int GetDepth() const override; virtual wxSize GetPPI() const override; + virtual wxSize GetRawPPI() const override; virtual double GetScaleFactor() const override; virtual wxString GetName() const override; @@ -160,6 +162,12 @@ protected: wxDisplayInfo m_info; private: + // Wrapper around GetDpiForMonitor() call: check if it's available and for + // its success. + // + // Return wxSize(0, 0) on failure. + wxSize CallGetDpiForMonitor(int type) const; + wxDECLARE_NO_COPY_CLASS(wxDisplayMSW); }; @@ -321,7 +329,7 @@ int wxDisplayMSW::GetDepth() const return m_info.depth; } -wxSize wxDisplayMSW::GetPPI() const +wxSize wxDisplayMSW::CallGetDpiForMonitor(int type) const { if ( const wxDisplayFactoryMSW::GetDpiForMonitor_t getFunc = wxDisplayFactoryMSW::GetDpiForMonitorPtr() ) @@ -329,14 +337,32 @@ wxSize wxDisplayMSW::GetPPI() const UINT dpiX = 0, dpiY = 0; const HRESULT - hr = (*getFunc)(m_info.hmon, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + hr = (*getFunc)(m_info.hmon, type, &dpiX, &dpiY); if ( SUCCEEDED(hr) ) return wxSize(dpiX, dpiY); wxLogApiError("GetDpiForMonitor", hr); } - return IsPrimary() ? wxDisplayImplSingleMSW().GetPPI() : wxSize(0, 0); + return wxSize(); +} + +wxSize wxDisplayMSW::GetPPI() const +{ + wxSize ppi = CallGetDpiForMonitor(MDT_EFFECTIVE_DPI); + if ( ppi.IsEmpty() && IsPrimary() ) + ppi = wxDisplayImplSingleMSW().GetPPI(); + + return ppi; +} + +wxSize wxDisplayMSW::GetRawPPI() const +{ + wxSize ppi = CallGetDpiForMonitor(MDT_RAW_DPI); + if ( ppi.IsEmpty() && IsPrimary() ) + ppi = wxDisplayImplSingleMSW().GetRawPPI(); + + return ppi; } double wxDisplayMSW::GetScaleFactor() const diff --git a/src/osx/core/display.cpp b/src/osx/core/display.cpp index ffe997a0d8..22d2cf509a 100644 --- a/src/osx/core/display.cpp +++ b/src/osx/core/display.cpp @@ -24,6 +24,7 @@ #ifndef WX_PRECOMP #include "wx/dynarray.h" #include "wx/log.h" + #include "wx/math.h" #include "wx/string.h" #include "wx/gdicmn.h" #include "wx/nonownedwnd.h" @@ -105,6 +106,7 @@ public: virtual wxRect GetClientArea() const override; virtual int GetDepth() const override; virtual double GetScaleFactor() const override; + virtual wxSize GetRawPPI() const override; virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const override; virtual wxVideoMode GetCurrentMode() const override; @@ -310,6 +312,21 @@ double wxDisplayImplMacOSX::GetScaleFactor() const return wxGetScaleFactor(m_id); } +wxSize wxDisplayImplMacOSX::GetRawPPI() const +{ + auto const sizeInMM = CGDisplayScreenSize(m_id); + + // Don't use manifestly invalid values. + if ( sizeInMM.width <= 0 && sizeInMM.height <= 0 ) + return wxDisplay::GetStdPPI(); + + const wxRect geometry = GetGeometry(); + const double ppiX = geometry.width * 25.4 / sizeInMM.width; + const double ppiY = geometry.height * 25.4 / sizeInMM.height; + + return wxSize(wxRound(ppiX), wxRound(ppiY)); +} + static int wxOSXCGDisplayModeGetBitsPerPixel( CGDisplayModeRef theValue ) { wxCFRef pixelEncoding( CGDisplayModeCopyPixelEncoding(theValue) );