diff --git a/include/wx/dc.h b/include/wx/dc.h index 26402a5859..b89c38130f 100644 --- a/include/wx/dc.h +++ b/include/wx/dc.h @@ -128,6 +128,8 @@ public: virtual wxDCImpl* CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data ) = 0; #endif + virtual bool CanDrawUsingClientDC(const wxWindow* window) const = 0; + static void Set(wxDCFactory *factory); static wxDCFactory *Get(); @@ -154,6 +156,8 @@ public: #if wxUSE_PRINTING_ARCHITECTURE virtual wxDCImpl* CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data ) override; #endif + + virtual bool CanDrawUsingClientDC(const wxWindow* window) const override; }; //----------------------------------------------------------------------------- diff --git a/include/wx/dcclient.h b/include/wx/dcclient.h index 28391d1266..ced769ce34 100644 --- a/include/wx/dcclient.h +++ b/include/wx/dcclient.h @@ -36,6 +36,8 @@ class WXDLLIMPEXP_CORE wxClientDC : public wxWindowDC public: wxClientDC(wxWindow *win); + static bool CanBeUsedForDrawing(const wxWindow* window); + protected: wxClientDC(wxDCImpl *impl) : wxWindowDC(impl) { } diff --git a/include/wx/dfb/dcclient.h b/include/wx/dfb/dcclient.h index 98655e4fd3..f195829f14 100644 --- a/include/wx/dfb/dcclient.h +++ b/include/wx/dfb/dcclient.h @@ -51,6 +51,9 @@ public: wxClientDCImpl(wxDC *owner) : wxWindowDCImpl(owner) { } wxClientDCImpl(wxDC *owner, wxWindow *win); + static bool + CanBeUsedForDrawing(const wxWindow* WXUNUSED(window)) { return true; } + wxDECLARE_DYNAMIC_CLASS(wxClientDCImpl); wxDECLARE_NO_COPY_CLASS(wxClientDCImpl); }; diff --git a/include/wx/gtk/dc.h b/include/wx/gtk/dc.h index 472c90fe11..dd9baf9725 100644 --- a/include/wx/gtk/dc.h +++ b/include/wx/gtk/dc.h @@ -64,6 +64,8 @@ class wxClientDCImpl: public wxGTKCairoDCImpl public: wxClientDCImpl(wxClientDC* owner, wxWindow* window); + static bool CanBeUsedForDrawing(const wxWindow* window); + wxDECLARE_NO_COPY_CLASS(wxClientDCImpl); }; //----------------------------------------------------------------------------- diff --git a/include/wx/gtk/dcclient.h b/include/wx/gtk/dcclient.h index 6b42e90467..f6d6f3ed5d 100644 --- a/include/wx/gtk/dcclient.h +++ b/include/wx/gtk/dcclient.h @@ -150,6 +150,9 @@ public: virtual void DoGetSize(int *width, int *height) const override; + static bool + CanBeUsedForDrawing(const wxWindow* WXUNUSED(window)) { return true; } + wxDECLARE_ABSTRACT_CLASS(wxClientDCImpl); }; diff --git a/include/wx/msw/dcclient.h b/include/wx/msw/dcclient.h index d6eaffda58..01f2cca210 100644 --- a/include/wx/msw/dcclient.h +++ b/include/wx/msw/dcclient.h @@ -56,6 +56,9 @@ public: virtual void DoGetSize(int *width, int *height) const override; + static bool + CanBeUsedForDrawing(const wxWindow* WXUNUSED(window)) { return true; } + protected: void InitDC(); diff --git a/include/wx/osx/dcclient.h b/include/wx/osx/dcclient.h index d5840ad98a..be16886f1b 100644 --- a/include/wx/osx/dcclient.h +++ b/include/wx/osx/dcclient.h @@ -54,6 +54,9 @@ public: wxClientDCImpl( wxDC *owner, wxWindow *window ); virtual ~wxClientDCImpl(); + static bool + CanBeUsedForDrawing(const wxWindow* WXUNUSED(window)) { return false; } + private: wxDECLARE_CLASS(wxClientDCImpl); wxDECLARE_NO_COPY_CLASS(wxClientDCImpl); diff --git a/include/wx/qt/dcclient.h b/include/wx/qt/dcclient.h index 788c4867ba..3eafbed172 100644 --- a/include/wx/qt/dcclient.h +++ b/include/wx/qt/dcclient.h @@ -40,6 +40,9 @@ public: wxClientDCImpl( wxDC *owner ); wxClientDCImpl( wxDC *owner, wxWindow *win ); + static bool + CanBeUsedForDrawing(const wxWindow* WXUNUSED(window)) { return false; } + private: wxDECLARE_CLASS(wxClientDCImpl); wxDECLARE_NO_COPY_CLASS(wxClientDCImpl); diff --git a/include/wx/x11/dcclient.h b/include/wx/x11/dcclient.h index beca1247de..7c477ed34f 100644 --- a/include/wx/x11/dcclient.h +++ b/include/wx/x11/dcclient.h @@ -153,6 +153,9 @@ public: wxClientDCImpl( wxDC *owner ) : wxWindowDCImpl( owner ) { } wxClientDCImpl( wxDC *owner, wxWindow *win ); + static bool + CanBeUsedForDrawing(const wxWindow* WXUNUSED(window)) { return true; } + protected: virtual void DoGetSize(int *width, int *height) const; diff --git a/interface/wx/dcclient.h b/interface/wx/dcclient.h index 05058d016a..41997f18ed 100644 --- a/interface/wx/dcclient.h +++ b/interface/wx/dcclient.h @@ -63,12 +63,13 @@ public: window from outside an EVT_PAINT() handler in some ports, this does @em not work on most of the platforms: neither wxOSX nor wxGTK with GTK 3 Wayland backend support this at all, so drawing using wxClientDC simply doesn't - have any effect there, while wxMSW doesn't support using it for composited - windows, so wxWindow::MSWDisableComposited() must be called to allow it to - work. The only supported way of drawing on a window is via wxPaintDC. To - redraw a small part of the window, use wxWindow::RefreshRect() to - invalidate just this part and check wxWindow::GetUpdateRegion() in the - paint event handler to redraw this part only. + have any effect there. CanBeUsedForDrawing() can be used to determine + whether wxClientDC can be used for drawing in the current environment, but + it is recommended to only draw on the window using wxPaintDC, as this is + guaranteed to work everywhere. To redraw a small part of the window, use + wxWindow::RefreshRect() to invalidate just this part and check + wxWindow::GetUpdateRegion() in the paint event handler to redraw this part + only. wxClientDC objects should normally be constructed as temporary stack objects, i.e. don't store a wxClientDC object. @@ -88,6 +89,23 @@ public: Constructor. Pass a pointer to the window on which you wish to paint. */ wxClientDC(wxWindow* window); + + /** + Return true if drawing on wxClientDC actually works. + + In many environments (currently this includes wxGTK when using Wayland + backend, wxMSW when using double buffering and wxOSX in all cases), + wxClientDC can be only used for obtaining information about the device + context, but not for actually drawing on it. Portable code should avoid + using wxClientDC completely, as explained in the class documentation, + but it is also possible to optionally use it only when it does work, + i.e. when this function returns @true. + + @param window The window that would be used with wxClientDC. + + @since 3.3.0 + */ + static bool CanBeUsedForDrawing(const wxWindow* window); }; diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp index e1060ae402..f36020179c 100644 --- a/src/common/dcbase.cpp +++ b/src/common/dcbase.cpp @@ -174,6 +174,11 @@ wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintD } #endif +bool wxNativeDCFactory::CanDrawUsingClientDC(const wxWindow* window) const +{ + return wxClientDCImpl::CanBeUsedForDrawing(window); +} + //----------------------------------------------------------------------------- // wxWindowDC //----------------------------------------------------------------------------- @@ -196,6 +201,12 @@ wxClientDC::wxClientDC(wxWindow *win) { } +/* static */ +bool wxClientDC::CanBeUsedForDrawing(const wxWindow* window) +{ + return wxDCFactory::Get()->CanDrawUsingClientDC(window); +} + //----------------------------------------------------------------------------- // wxMemoryDC //----------------------------------------------------------------------------- diff --git a/src/gtk/dc.cpp b/src/gtk/dc.cpp index 2c0e3d77c9..4cb49d135f 100644 --- a/src/gtk/dc.cpp +++ b/src/gtk/dc.cpp @@ -486,6 +486,25 @@ wxClientDCImpl::wxClientDCImpl(wxClientDC* owner, wxWindow* window) else SetGraphicsContext(wxGraphicsContext::Create()); } + +/* static */ +bool wxClientDCImpl::CanBeUsedForDrawing(const wxWindow* WXUNUSED(window)) +{ +#ifdef __UNIX__ + switch ( wxGetDisplayInfo().type ) + { + case wxDisplayNone: + case wxDisplayX11: + break; + + case wxDisplayWayland: + return false; + } +#endif // __UNIX__ + + return true; +} + //----------------------------------------------------------------------------- wxPaintDCImpl::wxPaintDCImpl(wxPaintDC* owner, wxWindow* window)