From 43d2b1db0e5d0352fcf94eab79b9e0fc5339980b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 29 Oct 2018 17:40:14 +0100 Subject: [PATCH 01/12] Simplify and fix layout of the display sample Get rid of an unnecessary wxPanel and just create wxBookCtrl containing pages showing information about the displays directly as a child of wxFrame. --- samples/display/display.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/samples/display/display.cpp b/samples/display/display.cpp index 7996eac945..ed5420d147 100644 --- a/samples/display/display.cpp +++ b/samples/display/display.cpp @@ -232,9 +232,7 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, #endif // wxUSE_STATUSBAR // create child controls - wxPanel *panel = new wxPanel(this, wxID_ANY); - - m_book = new wxBookCtrl(panel, wxID_ANY); + m_book = new wxBookCtrl(this, wxID_ANY); const size_t countDpy = wxDisplay::GetCount(); for ( size_t nDpy = 0; nDpy < countDpy; nDpy++ ) { @@ -291,6 +289,7 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, sizer->Add(new wxStaticText(page, wxID_ANY, display.IsPrimary() ? "yes" : "no")); + // add it to another sizer to have borders around it and button below wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); sizerTop->Add(sizer, 1, wxALL | wxEXPAND, 10); @@ -313,22 +312,19 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, sizer->Add(new wxStaticText(page, Display_CurrentMode, VideoModeToText(display.GetCurrentMode()))); - // add it to another sizer to have borders around it and button below sizerTop->Add(new wxButton(page, Display_ResetMode, "&Reset mode"), 0, wxALL | wxCENTRE, 5); #endif // wxUSE_DISPLAY page->SetSizer(sizerTop); + page->Layout(); m_book->AddPage(page, wxString::Format("Display %lu", (unsigned long)nDpy)); } - wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(m_book, 1, wxEXPAND); - panel->SetSizer(sizer); - sizer->SetSizeHints(this); + SetClientSize(m_book->GetBestSize()); } #if wxUSE_DISPLAY From f09b9dbfa26641fa2b3cfe281e9b13f161b107f9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 29 Oct 2018 17:41:37 +0100 Subject: [PATCH 02/12] Add wxDisplayImpl::GetScaleFactor() and implement it for wxGTK We need to account for the scale factor under GTK+ (and, presumably, under macOS) to compute the correct PPI value as it must use the number of physical and not logical pixels. --- include/wx/private/display.h | 7 +++++-- src/common/dpycmn.cpp | 6 ++++-- src/gtk/display.cpp | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/include/wx/private/display.h b/include/wx/private/display.h index 1cd7bae8d0..053885d05a 100644 --- a/include/wx/private/display.h +++ b/include/wx/private/display.h @@ -81,8 +81,11 @@ public: // return the depth or 0 if unknown virtual int GetDepth() const = 0; - // return the resolution of the display, uses GetSizeMM() by default but - // can be also overridden directly + // return the scale factor used to convert logical pixels to physical ones + virtual double GetScaleFactor() const { return 1.0; } + + // return the resolution of the display, uses GetSize(), GetScaleFactor() + // and GetSizeMM() by default but can be also overridden directly virtual wxSize GetPPI() const; // return the physical size of the display or (0, 0) if unknown: this is diff --git a/src/common/dpycmn.cpp b/src/common/dpycmn.cpp index d0073ee32c..b72f72c8f6 100644 --- a/src/common/dpycmn.cpp +++ b/src/common/dpycmn.cpp @@ -195,9 +195,7 @@ bool wxDisplay::ChangeMode(const wxVideoMode& mode) wxSize wxDisplayImpl::GetPPI() const { - const wxSize pixels = GetGeometry().GetSize(); const wxSize mm = GetSizeMM(); - if ( !mm.x || !mm.y ) { // Physical size is unknown, return a special value indicating that we @@ -205,6 +203,10 @@ wxSize wxDisplayImpl::GetPPI() const return wxSize(0, 0); } + // We need physical pixels here, not logical ones returned by + // GetGeometry(), to compute the real DPI. + const wxSize pixels = GetGeometry().GetSize()*GetScaleFactor(); + return wxSize(wxRound((pixels.x * inches2mm) / mm.x), wxRound((pixels.y * inches2mm) / mm.y)); } diff --git a/src/gtk/display.cpp b/src/gtk/display.cpp index 07e1fc45f3..b5eedeab71 100644 --- a/src/gtk/display.cpp +++ b/src/gtk/display.cpp @@ -46,6 +46,7 @@ public: virtual wxRect GetGeometry() const wxOVERRIDE; virtual wxRect GetClientArea() const wxOVERRIDE; virtual int GetDepth() const wxOVERRIDE; + virtual double GetScaleFactor() const wxOVERRIDE; virtual wxSize GetSizeMM() const wxOVERRIDE; #if wxUSE_DISPLAY @@ -121,6 +122,11 @@ int wxDisplayImplGTK::GetDepth() const return 24; } +double wxDisplayImplGTK::GetScaleFactor() const +{ + return gdk_monitor_get_scale_factor(m_monitor); +} + wxSize wxDisplayImplGTK::GetSizeMM() const { return wxSize @@ -222,6 +228,9 @@ public: virtual wxRect GetGeometry() const wxOVERRIDE; virtual wxRect GetClientArea() const wxOVERRIDE; virtual int GetDepth() const wxOVERRIDE; +#if GTK_CHECK_VERSION(3,10,0) + virtual double GetScaleFactor() const wxOVERRIDE; +#endif // GTK+ 3.10 virtual wxSize GetSizeMM() const wxOVERRIDE; #if wxUSE_DISPLAY @@ -293,6 +302,16 @@ int wxDisplayImplGTK::GetDepth() const return gdk_visual_get_depth(gdk_window_get_visual(wxGetTopLevelGDK())); } +#if GTK_CHECK_VERSION(3,10,0) +double wxDisplayImplGTK::GetScaleFactor() const +{ + if ( gtk_check_version(3,10,0) == NULL ) + return gdk_screen_get_monitor_scale_factor(m_screen, m_index); + + return 1.0; +} +#endif // GTK+ 3.10 + wxSize wxDisplayImplGTK::GetSizeMM() const { // At least in some configurations, gdk_screen_xxx_mm() functions return From 1938adb5dc3d0593210c774cfaae09ca5a3b3fd3 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 29 Oct 2018 17:50:56 +0100 Subject: [PATCH 03/12] Don't use gdk_screen_xxx_mm() with multiple displays These functions combine the sizes of all displays and so only return the correct size when there is only a single display. This fixes wildly wrong PPI values returned when more than one display is used. --- src/gtk/display.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gtk/display.cpp b/src/gtk/display.cpp index b5eedeab71..281901cc70 100644 --- a/src/gtk/display.cpp +++ b/src/gtk/display.cpp @@ -317,7 +317,7 @@ wxSize wxDisplayImplGTK::GetSizeMM() const // At least in some configurations, gdk_screen_xxx_mm() functions return // valid values when gdk_screen_get_monitor_xxx_mm() only return -1, so // handle this case specially. - if ( IsPrimary() ) + if ( gdk_screen_get_n_monitors(m_screen) == 1 ) { return wxSize(gdk_screen_width_mm(), gdk_screen_height_mm()); } From 68a7cbd08de59623640c6f0cfd9e3881d2230c35 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 29 Oct 2018 18:01:23 +0100 Subject: [PATCH 04/12] Use gdk_screen_xxx_mm() as fallback only Return the "real" PPI value from wxDisplay::GetPPI() in wxGTK and not the value defined at X11 level which is what these functions seem to use. --- src/gtk/display.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/gtk/display.cpp b/src/gtk/display.cpp index 281901cc70..7c79456758 100644 --- a/src/gtk/display.cpp +++ b/src/gtk/display.cpp @@ -314,14 +314,6 @@ double wxDisplayImplGTK::GetScaleFactor() const wxSize wxDisplayImplGTK::GetSizeMM() const { - // At least in some configurations, gdk_screen_xxx_mm() functions return - // valid values when gdk_screen_get_monitor_xxx_mm() only return -1, so - // handle this case specially. - if ( gdk_screen_get_n_monitors(m_screen) == 1 ) - { - return wxSize(gdk_screen_width_mm(), gdk_screen_height_mm()); - } - wxSize sizeMM; #if GTK_CHECK_VERSION(2,14,0) if ( wx_is_at_least_gtk2(14) ) @@ -337,6 +329,19 @@ wxSize wxDisplayImplGTK::GetSizeMM() const sizeMM.y = rc; } #endif // GTK+ 2.14 + + // When we have only a single display, we can use global GTK+ functions. + // Note that at least in some configurations, these functions return valid + // values when gdk_screen_get_monitor_xxx_mm() only return -1, so it's + // always worth fallng back on them, but we can't do it when using + // multiple displays because they combine the sizes of all displays in this + // case, which would result in a completely wrong value for GetPPI(). + if ( !(sizeMM.x && sizeMM.y) && gdk_screen_get_n_monitors(m_screen) == 1 ) + { + sizeMM.x = gdk_screen_width_mm(); + sizeMM.y = gdk_screen_height_mm(); + } + return sizeMM; } From 9f8684c789a5dd956254b1abbac15a42ee178983 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 29 Oct 2018 18:31:42 +0100 Subject: [PATCH 05/12] Factor out wxDisplayImpl::ComputePPI() helper No real changes, this is a pure refactoring. --- include/wx/private/display.h | 5 +++++ src/common/dpycmn.cpp | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/wx/private/display.h b/include/wx/private/display.h index 053885d05a..9a97a75f9c 100644 --- a/include/wx/private/display.h +++ b/include/wx/private/display.h @@ -118,6 +118,11 @@ protected: // create the object providing access to the display with the given index wxDisplayImpl(unsigned n) : m_index(n) { } + // Compute PPI from the sizes in pixels and mm. + // + // Return (0, 0) if physical size (in mm) is not known, i.e. 0. + static wxSize ComputePPI(int pxX, int pxY, int mmX, int mmY); + // the index of this display (0 is always the primary one) const unsigned m_index; diff --git a/src/common/dpycmn.cpp b/src/common/dpycmn.cpp index b72f72c8f6..53311f86ef 100644 --- a/src/common/dpycmn.cpp +++ b/src/common/dpycmn.cpp @@ -193,22 +193,29 @@ bool wxDisplay::ChangeMode(const wxVideoMode& mode) // wxDisplayImpl implementation // ============================================================================ -wxSize wxDisplayImpl::GetPPI() const +/* static */ +wxSize wxDisplayImpl::ComputePPI(int pxX, int pxY, int mmX, int mmY) { - const wxSize mm = GetSizeMM(); - if ( !mm.x || !mm.y ) + if ( !mmX || !mmY ) { // Physical size is unknown, return a special value indicating that we // can't compute the resolution -- what else can we do? return wxSize(0, 0); } + return wxSize(wxRound((pxX * inches2mm) / mmX), + wxRound((pxY * inches2mm) / mmY)); +} + +wxSize wxDisplayImpl::GetPPI() const +{ + const wxSize mm = GetSizeMM(); + // We need physical pixels here, not logical ones returned by // GetGeometry(), to compute the real DPI. const wxSize pixels = GetGeometry().GetSize()*GetScaleFactor(); - return wxSize(wxRound((pixels.x * inches2mm) / mm.x), - wxRound((pixels.y * inches2mm) / mm.y)); + return ComputePPI(pixels.x, pixels.y, mm.x, mm.y); } // ============================================================================ From e13df3140f0f9029ffec15c7b0b1e671cf2072b8 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 29 Oct 2018 18:31:59 +0100 Subject: [PATCH 06/12] Fall back to display-independent PPI in wxGTK If we can't determine the display-specific PPI value, use the global one which seems to be always available (and always equal to 96*96 in my testing -- but this is what previous versions of wxWidgets returned, so it's still better than nothing). --- src/gtk/display.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/gtk/display.cpp b/src/gtk/display.cpp index 7c79456758..7ab2c8d36b 100644 --- a/src/gtk/display.cpp +++ b/src/gtk/display.cpp @@ -231,6 +231,7 @@ public: #if GTK_CHECK_VERSION(3,10,0) virtual double GetScaleFactor() const wxOVERRIDE; #endif // GTK+ 3.10 + virtual wxSize GetPPI() const wxOVERRIDE; virtual wxSize GetSizeMM() const wxOVERRIDE; #if wxUSE_DISPLAY @@ -312,6 +313,24 @@ double wxDisplayImplGTK::GetScaleFactor() const } #endif // GTK+ 3.10 +wxSize wxDisplayImplGTK::GetPPI() const +{ + // Try the base class version which uses our GetSizeMM() and returns + // per-display PPI value if it works. + wxSize ppi = wxDisplayImpl::GetPPI(); + + if ( !ppi.x || !ppi.y ) + { + // But if it didn't work, fall back to the global DPI value common to + // all displays -- this is still better than nothing and more + // compatible with the previous wxWidgets versions. + ppi = ComputePPI(gdk_screen_width(), gdk_screen_height(), + gdk_screen_width_mm(), gdk_screen_height_mm()); + } + + return ppi; +} + wxSize wxDisplayImplGTK::GetSizeMM() const { wxSize sizeMM; From f57cb6c1d99e53d140626785938e594bd2829a2f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 1 Nov 2018 00:02:47 +0100 Subject: [PATCH 07/12] Add wxDisplay(wxWindow*) ctor with fall back on primary display This is more convenient than calling GetFromWindow() and then checking its return value. --- include/wx/display.h | 4 ++++ interface/wx/display.h | 17 +++++++++++++++++ src/common/dpycmn.cpp | 9 +++++++++ 3 files changed, 30 insertions(+) diff --git a/include/wx/display.h b/include/wx/display.h index af299a74e0..1c3a67298a 100644 --- a/include/wx/display.h +++ b/include/wx/display.h @@ -49,6 +49,10 @@ public: // primary display and the only one which is always supported wxDisplay(unsigned n = 0); + // create display object corresponding to the display of the given window + // or the default one if the window display couldn't be found + explicit wxDisplay(const wxWindow* window); + // dtor is not virtual as this is a concrete class not meant to be derived // from diff --git a/interface/wx/display.h b/interface/wx/display.h index 1a3ca71450..3c4e28f4bb 100644 --- a/interface/wx/display.h +++ b/interface/wx/display.h @@ -26,6 +26,23 @@ public: */ wxDisplay(unsigned int index = 0); + /** + Constructor creating the display object associated with the given + window. + + This is the most convenient way of finding the display on which the + given window is shown while falling back to the default display if it + is not shown at all or positioned outside of any display. + + @param window + A valid, i.e. non-null, window. + + @see GetFromWindow() + + @since 3.1.2 + */ + explicit wxDisplay(const wxWindow* window); + /** Destructor. */ diff --git a/src/common/dpycmn.cpp b/src/common/dpycmn.cpp index 53311f86ef..6171335b1a 100644 --- a/src/common/dpycmn.cpp +++ b/src/common/dpycmn.cpp @@ -85,6 +85,13 @@ wxDisplay::wxDisplay(unsigned n) m_impl = Factory().GetDisplay(n); } +wxDisplay::wxDisplay(const wxWindow* window) +{ + const int n = GetFromWindow(window); + + m_impl = Factory().GetDisplay(n != wxNOT_FOUND ? n : 0); +} + // ---------------------------------------------------------------------------- // static functions forwarded to wxDisplayFactory // ---------------------------------------------------------------------------- @@ -233,6 +240,8 @@ wxDisplayFactory::~wxDisplayFactory() int wxDisplayFactory::GetFromWindow(const wxWindow *window) { + wxCHECK_MSG( window, wxNOT_FOUND, "window can't be NULL" ); + // consider that the window belongs to the display containing its centre const wxRect r(window->GetScreenRect()); return GetFromPoint(wxPoint(r.x + r.width/2, r.y + r.height/2)); From 4ad9cde3805f16958bdb6e072ae072e999ce798d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 1 Nov 2018 00:06:34 +0100 Subject: [PATCH 08/12] Use the new wxDisplay(wxWindow*) ctor to simplify the code Make the code simpler and, in a couple of places where the fall back to the primary display in case wxDisplay::GetFromWindow() returned -1 was missing, also more correct. --- src/common/dlgcmn.cpp | 2 +- src/common/sizer.cpp | 12 +++--------- src/common/toplvcmn.cpp | 3 +-- src/generic/richtooltipg.cpp | 6 +----- src/msw/msgdlg.cpp | 5 +---- src/msw/toplevel.cpp | 9 ++------- src/stc/PlatWX.cpp | 3 +-- 7 files changed, 10 insertions(+), 30 deletions(-) diff --git a/src/common/dlgcmn.cpp b/src/common/dlgcmn.cpp index 55e37cc2e6..a7a6803bb3 100644 --- a/src/common/dlgcmn.cpp +++ b/src/common/dlgcmn.cpp @@ -871,7 +871,7 @@ int wxStandardDialogLayoutAdapter::DoMustScroll(wxDialog* dialog, wxSize& window wxSize minWindowSize = dialog->GetSizer()->GetMinSize(); windowSize = dialog->GetSize(); windowSize = wxSize(wxMax(windowSize.x, minWindowSize.x), wxMax(windowSize.y, minWindowSize.y)); - displaySize = wxDisplay(wxDisplay::GetFromWindow(dialog)).GetClientArea().GetSize(); + displaySize = wxDisplay(dialog).GetClientArea().GetSize(); int flags = 0; diff --git a/src/common/sizer.cpp b/src/common/sizer.cpp index ba50b6c9c0..8f2dc9f887 100644 --- a/src/common/sizer.cpp +++ b/src/common/sizer.cpp @@ -930,15 +930,9 @@ wxSize wxSizer::ComputeFittingClientSize(wxWindow *window) return tlw->GetClientSize(); } - // limit the window to the size of the display it is on - int disp = wxDisplay::GetFromWindow(window); - if ( disp == wxNOT_FOUND ) - { - // or, if we don't know which one it is, of the main one - disp = 0; - } - - sizeMax = wxDisplay(disp).GetClientArea().GetSize(); + // limit the window to the size of the display it is on (or the main + // one if the window display can't be determined) + sizeMax = wxDisplay(window).GetClientArea().GetSize(); // If determining the display size failed, skip the max size checks as // we really don't want to create windows of (0, 0) size. diff --git a/src/common/toplvcmn.cpp b/src/common/toplvcmn.cpp index a5660a3b23..7619328a18 100644 --- a/src/common/toplvcmn.cpp +++ b/src/common/toplvcmn.cpp @@ -249,8 +249,7 @@ void wxTopLevelWindowBase::DoCentre(int dir) // we need the display rect anyhow so store it first: notice that we should // be centered on the same display as our parent window, the display of // this window itself is not really defined yet - int nDisplay = wxDisplay::GetFromWindow(GetParent() ? GetParent() : this); - wxDisplay dpy(nDisplay == wxNOT_FOUND ? 0 : nDisplay); + wxDisplay dpy(GetParent() ? GetParent() : this); const wxRect rectDisplay(dpy.GetClientArea()); // what should we centre this window on? diff --git a/src/generic/richtooltipg.cpp b/src/generic/richtooltipg.cpp index 574f36b672..b774341d33 100644 --- a/src/generic/richtooltipg.cpp +++ b/src/generic/richtooltipg.cpp @@ -318,11 +318,7 @@ private: // Use GetFromWindow() and not GetFromPoint() here to try to get the // correct display even if the tip point itself is not visible. - int dpy = wxDisplay::GetFromWindow(GetParent()); - if ( dpy == wxNOT_FOUND ) - dpy = 0; // What else can we do? - - const wxRect rectDpy = wxDisplay(dpy).GetClientArea(); + const wxRect rectDpy = wxDisplay(GetParent()).GetClientArea(); #ifdef __WXMAC__ return pos.y > rectDpy.height/2 ? wxTipKind_Bottom : wxTipKind_Top; diff --git a/src/msw/msgdlg.cpp b/src/msw/msgdlg.cpp index 017991a4b4..61a0a878a8 100644 --- a/src/msw/msgdlg.cpp +++ b/src/msw/msgdlg.cpp @@ -162,10 +162,7 @@ wxMessageDialog::HookFunction(int code, WXWPARAM wParam, WXLPARAM lParam) void wxMessageDialog::ReplaceStaticWithEdit() { // check if the message box fits the display - int nDisplay = wxDisplay::GetFromWindow(this); - if ( nDisplay == wxNOT_FOUND ) - nDisplay = 0; - const wxRect rectDisplay = wxDisplay(nDisplay).GetClientArea(); + const wxRect rectDisplay = wxDisplay(this).GetClientArea(); if ( rectDisplay.Contains(GetRect()) ) { diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index df9e001c93..b883d9d8f9 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -756,8 +756,7 @@ void wxTopLevelWindowMSW::DoGetPosition(int *x, int *y) const { // we must use the correct display for the translation as the // task bar might be shown on one display but not the other one - int n = wxDisplay::GetFromWindow(this); - wxDisplay dpy(n == wxNOT_FOUND ? 0 : n); + wxDisplay dpy(this); const wxPoint ptOfs = dpy.GetClientArea().GetPosition() - dpy.GetGeometry().GetPosition(); @@ -916,11 +915,7 @@ bool wxTopLevelWindowMSW::ShowFullScreen(bool show, long style) // resize to the size of the display containing us, falling back to the // primary one - int dpy = wxDisplay::GetFromWindow(this); - if ( dpy == wxNOT_FOUND ) - dpy = 0; - - const wxRect rect = wxDisplay(dpy).GetGeometry(); + const wxRect rect = wxDisplay(this).GetGeometry(); SetSize(rect); diff --git a/src/stc/PlatWX.cpp b/src/stc/PlatWX.cpp index 4fd42772bb..ffb3db94bc 100644 --- a/src/stc/PlatWX.cpp +++ b/src/stc/PlatWX.cpp @@ -1861,8 +1861,7 @@ void Window::SetPositionRelative(PRectangle rc, Window relativeTo) { position.x = wxRound(position.x + rc.left); position.y = wxRound(position.y + rc.top); - const int currentDisplay = wxDisplay::GetFromWindow(relativeWin); - const wxRect displayRect = wxDisplay(currentDisplay).GetClientArea(); + const wxRect displayRect = wxDisplay(relativeWin).GetClientArea(); if (position.x < displayRect.GetLeft()) position.x = displayRect.GetLeft(); From 81c67c368647f6efbcd55d2d77c095d738cc7c1c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 1 Nov 2018 00:07:24 +0100 Subject: [PATCH 09/12] Make wxDC::GetPPI() monitor-dependent in wxGTK3 Return the PPI for the display on which the associated window is shown and not the main display PPI. --- src/gtk/dc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gtk/dc.cpp b/src/gtk/dc.cpp index 3e7868173c..a41910ac32 100644 --- a/src/gtk/dc.cpp +++ b/src/gtk/dc.cpp @@ -15,6 +15,7 @@ #include "wx/dcclient.h" #include "wx/dcmemory.h" #include "wx/dcscreen.h" +#include "wx/display.h" #include "wx/gdicmn.h" #include "wx/icon.h" #include "wx/gtk/dc.h" @@ -238,7 +239,7 @@ wxSize wxGTKCairoDCImpl::GetPPI() const { if ( m_window ) { - return wxGetDisplayPPI(); + return wxDisplay(m_window).GetPPI(); } // For a non-window-based DC the concept of PPI doesn't make much sense From 5e53b22bd4fc7c6a196d14c75b404c56d5af577e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 6 Nov 2018 03:17:49 +0100 Subject: [PATCH 10/12] Add wxGraphicsContext::GetWindow() This method allows to retrieve the window this context is associated with, if any. Add "wxWindow*" argument to wxGraphicsContext ctor and provide the window pointer to it when available, i.e. when creating the context from a wxWindow directly or from wxWindowDC, which is also associated with a window, in platform-specific code. No real changes yet. --- docs/changes.txt | 1 + include/wx/graphics.h | 11 ++++++++- interface/wx/graphics.h | 13 ++++++++++ src/common/graphcmn.cpp | 8 ++++--- src/generic/graphicc.cpp | 4 ++-- src/msw/graphics.cpp | 12 ++++++---- src/msw/graphicsd2d.cpp | 47 +++++++++++++++++++++++++++---------- src/osx/carbon/graphics.cpp | 45 ++++++++++++++++++----------------- 8 files changed, 96 insertions(+), 45 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index f35cb268d6..d59874488b 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -128,6 +128,7 @@ All (GUI): - Add wxGrid::SetCornerLabelValue() (Pavel Kalugin). - Add strikethrough support for fonts defined in XRC. - Add wxDisplay::GetPPI(). +- Add wxGraphicsContext::GetWindow(). wxGTK: diff --git a/include/wx/graphics.h b/include/wx/graphics.h index 9141d39450..a35667491f 100644 --- a/include/wx/graphics.h +++ b/include/wx/graphics.h @@ -452,7 +452,7 @@ private: class WXDLLIMPEXP_CORE wxGraphicsContext : public wxGraphicsObject { public: - wxGraphicsContext(wxGraphicsRenderer* renderer); + wxGraphicsContext(wxGraphicsRenderer* renderer, wxWindow* window = NULL); virtual ~wxGraphicsContext(); @@ -490,6 +490,9 @@ public: // create a context that can be used for measuring texts only, no drawing allowed static wxGraphicsContext * Create(); + // Return the window this context is associated with, if any. + wxWindow* GetWindow() const { return m_window; } + // begin a new document (relevant only for printing / pdf etc) if there is a progress dialog, message will be shown virtual bool StartDoc( const wxString& message ); @@ -788,6 +791,12 @@ protected: wxDouble angle, const wxGraphicsBrush& backgroundBrush); +private: + // The associated window, if any, i.e. if one was passed directly to + // Create() or the associated window of the wxDC this context was created + // from. + wxWindow* const m_window; + wxDECLARE_NO_COPY_CLASS(wxGraphicsContext); wxDECLARE_ABSTRACT_CLASS(wxGraphicsContext); }; diff --git a/interface/wx/graphics.h b/interface/wx/graphics.h index 2e1bd40477..5154ec19ba 100644 --- a/interface/wx/graphics.h +++ b/interface/wx/graphics.h @@ -1095,6 +1095,19 @@ public: */ virtual void GetDPI( wxDouble* dpiX, wxDouble* dpiY); + /** + Returns the associated window if any. + + If this context was created using Create() overload taking wxWindow or + wxWindowDC, this method returns the corresponding window. Otherwise + returns @NULL. + + @return A possibly @NULL window pointer. + + @since 3.1.2 + */ + wxWindow* GetWindow() const; + /** @} */ diff --git a/src/common/graphcmn.cpp b/src/common/graphcmn.cpp index fc0e6ab894..006db0586e 100644 --- a/src/common/graphcmn.cpp +++ b/src/common/graphcmn.cpp @@ -565,12 +565,14 @@ void * wxGraphicsBitmap::GetNativeBitmap() const wxIMPLEMENT_ABSTRACT_CLASS(wxGraphicsContext, wxObject); -wxGraphicsContext::wxGraphicsContext(wxGraphicsRenderer* renderer) : - wxGraphicsObject(renderer), +wxGraphicsContext::wxGraphicsContext(wxGraphicsRenderer* renderer, + wxWindow* window) + : wxGraphicsObject(renderer), m_antialias(wxANTIALIAS_DEFAULT), m_composition(wxCOMPOSITION_OVER), m_interpolation(wxINTERPOLATION_DEFAULT), - m_enableOffset(false) + m_enableOffset(false), + m_window(window) { } diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index 7ed04b4bd4..ebebea96df 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -1830,7 +1830,7 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC& #endif wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc ) -: wxGraphicsContext(renderer) +: wxGraphicsContext(renderer, dc.GetWindow()) { int width, height; dc.GetSize( &width, &height ); @@ -2244,7 +2244,7 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context ) } wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window) - : wxGraphicsContext(renderer) + : wxGraphicsContext(renderer, window) #ifdef __WXMSW__ , m_mswWindowHDC(GetHwndOf(window)) #endif diff --git a/src/msw/graphics.cpp b/src/msw/graphics.cpp index 04cca9d732..ebecbeb72a 100644 --- a/src/msw/graphics.cpp +++ b/src/msw/graphics.cpp @@ -358,7 +358,7 @@ class wxGDIPlusContext : public wxGraphicsContext public: wxGDIPlusContext( wxGraphicsRenderer* renderer, const wxDC& dc ); wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc, wxDouble width, wxDouble height ); - wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd ); + wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd, wxWindow* window = NULL); wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr); wxGDIPlusContext(wxGraphicsRenderer* renderer); @@ -1647,7 +1647,7 @@ wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc, wxDou } wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, const wxDC& dc ) - : wxGraphicsContext(renderer) + : wxGraphicsContext(renderer, dc.GetWindow()) { wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl ); HDC hdc = (HDC) msw->GetHDC(); @@ -1656,8 +1656,10 @@ wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, const wxDC& dc Init(new Graphics(hdc), sz.x, sz.y); } -wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd ) - : wxGraphicsContext(renderer) +wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, + HWND hwnd, + wxWindow* window ) + : wxGraphicsContext(renderer, window) { RECT rect = wxGetWindowRect(hwnd); Init(new Graphics(hwnd), rect.right - rect.left, rect.bottom - rect.top); @@ -2492,7 +2494,7 @@ wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeHDC(WXHDC dc) wxGraphicsContext * wxGDIPlusRenderer::CreateContext( wxWindow* window ) { ENSURE_LOADED_OR_RETURN(NULL); - return new wxGDIPlusContext(this, (HWND) window->GetHWND() ); + return new wxGDIPlusContext(this, (HWND) window->GetHWND(), window ); } // Path diff --git a/src/msw/graphicsd2d.cpp b/src/msw/graphicsd2d.cpp index 00eb65dde3..eccdf77122 100644 --- a/src/msw/graphicsd2d.cpp +++ b/src/msw/graphicsd2d.cpp @@ -3400,9 +3400,19 @@ public: class wxD2DContext : public wxGraphicsContext, wxD2DResourceManager { public: - wxD2DContext(wxGraphicsRenderer* renderer, ID2D1Factory* direct2dFactory, HWND hwnd); + // Create the context for the given HWND, which may be associated (if it's + // non-null) with the given wxWindow. + wxD2DContext(wxGraphicsRenderer* renderer, + ID2D1Factory* direct2dFactory, + HWND hwnd, + wxWindow* window = NULL); - wxD2DContext(wxGraphicsRenderer* renderer, ID2D1Factory* direct2dFactory, HDC hdc, const wxSize& dcSize, + // Create the context for the given HDC which may be associated (if it's + // non-null) with the given wxDC. + wxD2DContext(wxGraphicsRenderer* renderer, + ID2D1Factory* direct2dFactory, + HDC hdc, + const wxDC* dc = NULL, D2D1_ALPHA_MODE alphaMode = D2D1_ALPHA_MODE_IGNORE); #if wxUSE_IMAGE @@ -3550,8 +3560,11 @@ private: // wxD2DContext implementation //----------------------------------------------------------------------------- -wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer, ID2D1Factory* direct2dFactory, HWND hwnd) : - wxGraphicsContext(renderer), m_direct2dFactory(direct2dFactory), +wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer, + ID2D1Factory* direct2dFactory, + HWND hwnd, + wxWindow* window) : + wxGraphicsContext(renderer, window), m_direct2dFactory(direct2dFactory), #if wxD2D_DEVICE_CONTEXT_SUPPORTED m_renderTargetHolder(new wxD2DDeviceContextResourceHolder(direct2dFactory, hwnd)) #else @@ -3564,13 +3577,21 @@ wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer, ID2D1Factory* direct2dF Init(); } -wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer, ID2D1Factory* direct2dFactory, HDC hdc, - const wxSize& dcSize, D2D1_ALPHA_MODE alphaMode) : - wxGraphicsContext(renderer), m_direct2dFactory(direct2dFactory), +wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer, + ID2D1Factory* direct2dFactory, + HDC hdc, + const wxDC* dc, + D2D1_ALPHA_MODE alphaMode) : + wxGraphicsContext(renderer, dc->GetWindow()), m_direct2dFactory(direct2dFactory), m_renderTargetHolder(new wxD2DDCRenderTargetResourceHolder(direct2dFactory, hdc, alphaMode)) { - m_width = dcSize.GetWidth(); - m_height = dcSize.GetHeight(); + if ( dc ) + { + const wxSize dcSize = dc->GetSize(); + m_width = dcSize.GetWidth(); + m_height = dcSize.GetHeight(); + } + Init(); } @@ -4531,7 +4552,7 @@ wxD2DRenderer::~wxD2DRenderer() wxGraphicsContext* wxD2DRenderer::CreateContext(const wxWindowDC& dc) { - return new wxD2DContext(this, m_direct2dFactory, dc.GetHDC(), dc.GetSize()); + return new wxD2DContext(this, m_direct2dFactory, dc.GetHDC(), &dc); } wxGraphicsContext* wxD2DRenderer::CreateContext(const wxMemoryDC& dc) @@ -4539,7 +4560,7 @@ wxGraphicsContext* wxD2DRenderer::CreateContext(const wxMemoryDC& dc) wxBitmap bmp = dc.GetSelectedBitmap(); wxASSERT_MSG( bmp.IsOk(), wxS("Should select a bitmap before creating wxGraphicsContext") ); - return new wxD2DContext(this, m_direct2dFactory, dc.GetHDC(), dc.GetSize(), + return new wxD2DContext(this, m_direct2dFactory, dc.GetHDC(), &dc, bmp.HasAlpha() ? D2D1_ALPHA_MODE_PREMULTIPLIED : D2D1_ALPHA_MODE_IGNORE); } @@ -4571,12 +4592,12 @@ wxGraphicsContext* wxD2DRenderer::CreateContextFromNativeWindow(void* window) wxGraphicsContext* wxD2DRenderer::CreateContextFromNativeHDC(WXHDC dc) { - return new wxD2DContext(this, m_direct2dFactory, (HDC)dc, wxSize(0, 0)); + return new wxD2DContext(this, m_direct2dFactory, (HDC)dc); } wxGraphicsContext* wxD2DRenderer::CreateContext(wxWindow* window) { - return new wxD2DContext(this, m_direct2dFactory, (HWND)window->GetHWND()); + return new wxD2DContext(this, m_direct2dFactory, (HWND)window->GetHWND(), window); } #if wxUSE_IMAGE diff --git a/src/osx/carbon/graphics.cpp b/src/osx/carbon/graphics.cpp index 16f58329da..c8f96aa43f 100644 --- a/src/osx/carbon/graphics.cpp +++ b/src/osx/carbon/graphics.cpp @@ -1303,7 +1303,11 @@ bool wxMacCoreGraphicsPathData::Contains( wxDouble x, wxDouble y, wxPolygonFillM class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext { public: - wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext, wxDouble width = 0, wxDouble height = 0 ); + wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, + CGContextRef cgcontext, + wxDouble width = 0, + wxDouble height = 0, + wxWindow* window = NULL ); wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, wxWindow* window ); @@ -1509,7 +1513,12 @@ void wxMacCoreGraphicsContext::Init() m_interpolation = wxINTERPOLATION_DEFAULT; } -wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext, wxDouble width, wxDouble height ) : wxGraphicsContext(renderer) +wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, + CGContextRef cgcontext, + wxDouble width, + wxDouble height, + wxWindow* window ) + : wxGraphicsContext(renderer, window) { Init(); SetNativeContext(cgcontext); @@ -1518,7 +1527,9 @@ wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer m_initTransform = m_cgContext ? CGContextGetCTM(m_cgContext) : CGAffineTransformIdentity; } -wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, wxWindow* window ): wxGraphicsContext(renderer) +wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, + wxWindow* window ) + : wxGraphicsContext(renderer, window) { Init(); @@ -2694,26 +2705,18 @@ wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer() wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC& dc ) { - const wxDCImpl* impl = dc.GetImpl(); - wxWindowDCImpl *win_impl = wxDynamicCast( impl, wxWindowDCImpl ); - if (win_impl) - { - int w, h; - win_impl->GetSize( &w, &h ); - CGContextRef cgctx = 0; + wxWindow* const win = dc.GetWindow(); + wxCHECK_MSG( win, NULL, "Invalid wxWindowDC" ); - wxASSERT_MSG(win_impl->GetWindow(), "Invalid wxWindow in wxMacCoreGraphicsRenderer::CreateContext"); - if (win_impl->GetWindow()) - cgctx = (CGContextRef)(win_impl->GetWindow()->MacGetCGContextRef()); + const wxSize sz = win->GetSize(); - // having a cgctx being NULL is fine (will be created on demand) - // this is the case for all wxWindowDCs except wxPaintDC - wxMacCoreGraphicsContext *context = - new wxMacCoreGraphicsContext( this, cgctx, (wxDouble) w, (wxDouble) h ); - context->EnableOffset(dc.GetContentScaleFactor() < 2); - return context; - } - return NULL; + // having a cgctx being NULL is fine (will be created on demand) + // this is the case for all wxWindowDCs except wxPaintDC + CGContextRef cgctx = (CGContextRef)(win->MacGetCGContextRef()); + wxMacCoreGraphicsContext *context = + new wxMacCoreGraphicsContext( this, cgctx, sz.x, sz.y, win ); + context->EnableOffset(dc.GetContentScaleFactor() < 2); + return context; } wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxMemoryDC& dc ) From d5c43831b523c889e565495682b658715017a77b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 6 Nov 2018 03:19:27 +0100 Subject: [PATCH 11/12] Really implement wxGraphicsContext::GetDPI() Return the DPI of the associated window, if any, instead of always returning hard-coded 72*72. --- docs/changes.txt | 2 +- src/common/graphcmn.cpp | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index d59874488b..68034a6744 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -128,7 +128,7 @@ All (GUI): - Add wxGrid::SetCornerLabelValue() (Pavel Kalugin). - Add strikethrough support for fonts defined in XRC. - Add wxDisplay::GetPPI(). -- Add wxGraphicsContext::GetWindow(). +- Add wxGraphicsContext::GetWindow() and implement wxGraphicsContext::GetDPI(). wxGTK: diff --git a/src/common/graphcmn.cpp b/src/common/graphcmn.cpp index 006db0586e..1f4f74cc7c 100644 --- a/src/common/graphcmn.cpp +++ b/src/common/graphcmn.cpp @@ -31,6 +31,8 @@ #include "wx/log.h" #endif +#include "wx/display.h" + #ifdef __WXMSW__ #include "wx/msw/enhmeta.h" #endif @@ -620,8 +622,19 @@ wxDouble wxGraphicsContext::GetAlpha() const void wxGraphicsContext::GetDPI( wxDouble* dpiX, wxDouble* dpiY) { - *dpiX = 72.0; - *dpiY = 72.0; + if ( m_window ) + { + const wxSize ppi = wxDisplay(m_window).GetPPI(); + *dpiX = ppi.x; + *dpiY = ppi.y; + } + else + { + // Use some standard DPI value, it doesn't make much sense for the + // contexts not using any pixels anyhow. + *dpiX = 72.0; + *dpiY = 72.0; + } } // sets the pen From bfe11f233f7990ce8447b071a3067638100196ea Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 6 Nov 2018 03:20:24 +0100 Subject: [PATCH 12/12] Really implement wxGCDC::GetPPI() Return the DPI of the associated window, if any, instead of the hard-coded 72*72. --- src/common/dcgraph.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/common/dcgraph.cpp b/src/common/dcgraph.cpp index d70113dfcc..292d058220 100644 --- a/src/common/dcgraph.cpp +++ b/src/common/dcgraph.cpp @@ -418,6 +418,15 @@ void wxGCDCImpl::SetTextBackground( const wxColour &col ) wxSize wxGCDCImpl::GetPPI() const { + if ( m_graphicContext ) + { + wxDouble x, y; + m_graphicContext->GetDPI(&x, &y); + return wxSize(wxRound(x), wxRound(y)); + } + + // This is the same value that wxGraphicsContext::GetDPI() returns by + // default. return wxSize(72, 72); }