From ffe15b2fa6b0a6f56499e5f0a075424caa29630d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 26 Dec 2023 03:38:08 +0100 Subject: [PATCH 01/10] Enable wxAUI_MGR_LIVE_RESIZE by default This makes behaviour more consistent across all platforms, as this flag is always used in wxGTK and wxOSX, and might avoid some problems in wxMSW, see #23982. --- include/wx/aui/framemanager.h | 3 ++- interface/wx/aui/framemanager.h | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/wx/aui/framemanager.h b/include/wx/aui/framemanager.h index da9dff9609..167c486c35 100644 --- a/include/wx/aui/framemanager.h +++ b/include/wx/aui/framemanager.h @@ -51,7 +51,8 @@ enum wxAuiManagerOption wxAUI_MGR_DEFAULT = wxAUI_MGR_ALLOW_FLOATING | wxAUI_MGR_TRANSPARENT_HINT | wxAUI_MGR_HINT_FADE | - wxAUI_MGR_NO_VENETIAN_BLINDS_FADE + wxAUI_MGR_NO_VENETIAN_BLINDS_FADE | + wxAUI_MGR_LIVE_RESIZE }; diff --git a/interface/wx/aui/framemanager.h b/interface/wx/aui/framemanager.h index 359aecfc04..549492f354 100644 --- a/interface/wx/aui/framemanager.h +++ b/interface/wx/aui/framemanager.h @@ -45,12 +45,14 @@ enum wxAuiManagerOption wxAUI_MGR_NO_VENETIAN_BLINDS_FADE = 1 << 7, /// When a docked pane is resized, its content is refreshed in live (instead of moving /// the border alone and refreshing the content at the end). + /// Since wxWidgets 3.3.0 this flag is included in the default flags. wxAUI_MGR_LIVE_RESIZE = 1 << 8, /// Default behaviour. wxAUI_MGR_DEFAULT = wxAUI_MGR_ALLOW_FLOATING | wxAUI_MGR_TRANSPARENT_HINT | wxAUI_MGR_HINT_FADE | - wxAUI_MGR_NO_VENETIAN_BLINDS_FADE + wxAUI_MGR_NO_VENETIAN_BLINDS_FADE | + wxAUI_MGR_LIVE_RESIZE }; /** @@ -142,7 +144,11 @@ enum wxAuiManagerOption docking hint immediately. @style{wxAUI_MGR_LIVE_RESIZE} When a docked pane is resized, its content is refreshed in live (instead of moving - the border alone and refreshing the content at the end). + the border alone and refreshing the content at the end). Note that + this flag is included in wxAUI_MGR_DEFAULT and so needs to be + explicitly turned off if you don't need. Also note that it is + always enabled in wxGTK3 and wxOSX ports as non-live resizing is not + implemented in them. @style{wxAUI_MGR_DEFAULT} Default behaviour, combines: wxAUI_MGR_ALLOW_FLOATING | wxAUI_MGR_TRANSPARENT_HINT | wxAUI_MGR_HINT_FADE | wxAUI_MGR_NO_VENETIAN_BLINDS_FADE. From 62d652c353f0bb01a43117b102f493b310abe357 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 26 Dec 2023 16:31:24 +0100 Subject: [PATCH 02/10] Use wxUSE_AUI_LIVE_RESIZE_ALWAYS instead of explicit port checks This allows to avoid repeating the checks for the ports in which wxClientDC can't be used in multiple places. No real changes. --- src/aui/framemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index aa2e448e9f..26cbb7da3a 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -3911,7 +3911,7 @@ void wxAuiManager::Render(wxDC* dc) void wxAuiManager::Repaint(wxDC* dc) { -#if defined(__WXMAC__) || defined(__WXGTK3__) +#if wxUSE_AUI_LIVE_RESIZE_ALWAYS // We can't use wxClientDC in these ports. if ( dc == nullptr ) { From f82047feafebd2124ed8540f44b9bd6c3f28076d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 26 Dec 2023 16:39:16 +0100 Subject: [PATCH 03/10] Make wxAuiManager::Repaint() logic a bit more clear No real changes, just write a single check for "dc == nullptr" instead of doing it twice in combination with preprocessor checks. This commit is best viewed with Git --color-moved option. --- src/aui/framemanager.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index 26cbb7da3a..ac00f3053d 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -3911,28 +3911,27 @@ void wxAuiManager::Render(wxDC* dc) void wxAuiManager::Repaint(wxDC* dc) { -#if wxUSE_AUI_LIVE_RESIZE_ALWAYS - // We can't use wxClientDC in these ports. - if ( dc == nullptr ) - { - m_frame->Refresh() ; - m_frame->Update() ; - return ; - } -#endif - int w, h; - m_frame->GetClientSize(&w, &h); + wxClientDC* client_dc = nullptr; // figure out which dc to use; if one // has been specified, use it, otherwise // make a client dc - wxClientDC* client_dc = nullptr; if (!dc) { +#if wxUSE_AUI_LIVE_RESIZE_ALWAYS + // We can't use wxClientDC in these ports. + m_frame->Refresh() ; + m_frame->Update() ; + return ; +#else client_dc = new wxClientDC(m_frame); dc = client_dc; +#endif } + int w, h; + m_frame->GetClientSize(&w, &h); + // if the frame has a toolbar, the client area // origin will not be (0,0). wxPoint pt = m_frame->GetClientAreaOrigin(); From aa14096ca98365e77b5906373497ea5718d3a802 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 26 Dec 2023 16:42:14 +0100 Subject: [PATCH 04/10] Use unique_ptr instead of manual memory management No real changes, just use unique_ptr instead of deleting the DC object manually. --- src/aui/framemanager.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index ac00f3053d..43f24e2933 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -64,6 +64,8 @@ wxDEFINE_EVENT( wxEVT_AUI_FIND_MANAGER, wxAuiManagerEvent ); #include "wx/msw/dc.h" #endif +#include + wxIMPLEMENT_DYNAMIC_CLASS(wxAuiManagerEvent, wxEvent); wxIMPLEMENT_CLASS(wxAuiManager, wxEvtHandler); @@ -3911,7 +3913,7 @@ void wxAuiManager::Render(wxDC* dc) void wxAuiManager::Repaint(wxDC* dc) { - wxClientDC* client_dc = nullptr; + std::unique_ptr client_dc; // figure out which dc to use; if one // has been specified, use it, otherwise @@ -3924,8 +3926,8 @@ void wxAuiManager::Repaint(wxDC* dc) m_frame->Update() ; return ; #else - client_dc = new wxClientDC(m_frame); - dc = client_dc; + client_dc.reset(new wxClientDC(m_frame)); + dc = client_dc.get(); #endif } @@ -3940,10 +3942,6 @@ void wxAuiManager::Repaint(wxDC* dc) // render all the items Render(dc); - - // if we created a client_dc, delete it - if (client_dc) - delete client_dc; } void wxAuiManager::OnDestroy(wxWindowDestroyEvent& event) From 24fd54ed31a8b09dade9d6124d88042cd322a08b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 26 Dec 2023 18:31:36 +0100 Subject: [PATCH 05/10] Add wxClientDC::CanBeUsedForDrawing() This function can be used to check if drawing on wxClientDC actually works. This has to be a run-time, rather than compile-time, check because in wxGTK3 this depends on the backend being used: wxClientDC only doesn't work with Wayland, but does work with X11 (and, less importantly, Win32) backend(s). Currently the wxWindow parameter of this function is not used but it could be useful in the future and it will be simpler to allow not specifying it (by defaulting it to nullptr) than to add it later, so it seems better to have it. --- include/wx/dc.h | 4 ++++ include/wx/dcclient.h | 2 ++ include/wx/dfb/dcclient.h | 3 +++ include/wx/gtk/dc.h | 2 ++ include/wx/gtk/dcclient.h | 3 +++ include/wx/msw/dcclient.h | 3 +++ include/wx/osx/dcclient.h | 3 +++ include/wx/qt/dcclient.h | 3 +++ include/wx/x11/dcclient.h | 3 +++ interface/wx/dcclient.h | 30 ++++++++++++++++++++++++------ src/common/dcbase.cpp | 11 +++++++++++ src/gtk/dc.cpp | 19 +++++++++++++++++++ 12 files changed, 80 insertions(+), 6 deletions(-) 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) From 298fef23adf018211258f2bc61ba10de2dee22f7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 26 Dec 2023 18:38:08 +0100 Subject: [PATCH 06/10] Use wxClientDC::CanBeUsedForDrawing() in wxSplitterWindow No real changes, just simplify the code by using the just added wxClientDC function instead of reproducing its logic here. --- src/generic/splitter.cpp | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/generic/splitter.cpp b/src/generic/splitter.cpp index e457f5c6d4..ed0dc2710d 100644 --- a/src/generic/splitter.cpp +++ b/src/generic/splitter.cpp @@ -74,25 +74,12 @@ static bool IsLive(wxSplitterWindow* wnd) // with wxSP_LIVE_UPDATE style the splitter windows are always resized // following the mouse movement while it drags the sash, without it we only // draw the sash at the new position but only resize the windows when the - // dragging is finished -#if defined( __WXMAC__ ) && defined(TARGET_API_MAC_OSX) && TARGET_API_MAC_OSX == 1 - return true; // Mac can't paint outside paint event - always need live mode -#else - // wxClientDC doesn't work with Wayland either, so check if we're using it. - #if defined(__WXGTK3__) && defined(__UNIX__) - switch ( wxGetDisplayInfo().type ) - { - case wxDisplayNone: - case wxDisplayX11: - break; - - case wxDisplayWayland: - return true; - } - #endif // wxGTK3 + // dragging is finished -- but drawing the sash is done using wxClientDC, + // so check if we can use it and always use live resizing if we can't + if ( !wxClientDC::CanBeUsedForDrawing(wnd) ) + return true; return wnd->HasFlag(wxSP_LIVE_UPDATE); -#endif } bool wxSplitterWindow::Create(wxWindow *parent, wxWindowID id, From 1d328aa4e1928e1d199f0314b52cd6a2bb24509a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 26 Dec 2023 18:51:42 +0100 Subject: [PATCH 07/10] Add wxSplitterWindow::AlwaysUsesLiveUpdate() This is similar to wxAuiManager::AlwaysUsesLiveResize() and does the same thing, i.e. returns true if live update is always used, whether wxSP_LIVE_UPDATE is enabled or not. Use the new function in the sample to disable the menu item in the environments where it doesn't do anything, as it was confusing to have it under e.g. Wayland. --- include/wx/generic/splitter.h | 3 +++ interface/wx/splitter.h | 14 ++++++++++++++ samples/splitter/splitter.cpp | 8 +++++++- src/generic/splitter.cpp | 10 ++++++---- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/include/wx/generic/splitter.h b/include/wx/generic/splitter.h index 2294f431e4..f2fbe2a906 100644 --- a/include/wx/generic/splitter.h +++ b/include/wx/generic/splitter.h @@ -131,6 +131,9 @@ public: // Is the window split? bool IsSplit() const { return (m_windowTwo != nullptr); } + // Return true if wxSP_LIVE_UPDATE is always used. + bool AlwaysUsesLiveUpdate() const; + // Sets the border size void SetBorderSize(int WXUNUSED(width)) { } diff --git a/interface/wx/splitter.h b/interface/wx/splitter.h index 4ff835b2ee..22d564a7ea 100644 --- a/interface/wx/splitter.h +++ b/interface/wx/splitter.h @@ -142,6 +142,20 @@ public: */ virtual ~wxSplitterWindow(); + /** + Returns true if splitter always behaves as if wxSP_LIVE_UPDATE were + specified. + + This function returns true if non-live update mode is not supported and + live update is always used, even if wxSP_LIVE_UPDATE was not explicitly + specified. + + @see wxClientDC::CanBeUsedForDrawing() + + @since 3.3.0 + */ + bool AlwaysUsesLiveUpdate() const; + /** Creation function, for two-step construction. See wxSplitterWindow() for details. diff --git a/samples/splitter/splitter.cpp b/samples/splitter/splitter.cpp index 3d100be780..cee9eafc03 100644 --- a/samples/splitter/splitter.cpp +++ b/samples/splitter/splitter.cpp @@ -254,7 +254,7 @@ MyFrame::MyFrame() "Toggle sash invisibility"); splitMenu->AppendSeparator(); - splitMenu->AppendCheckItem(SPLIT_LIVE, + auto itemLive = splitMenu->AppendCheckItem(SPLIT_LIVE, "&Live update\tCtrl-L", "Toggle live update mode"); splitMenu->AppendCheckItem(SPLIT_BORDER, @@ -306,6 +306,12 @@ MyFrame::MyFrame() menuBar->Check(SPLIT_LIVE, true); m_splitter = new MySplitterWindow(this); + if ( m_splitter->AlwaysUsesLiveUpdate() ) + { + // Only live update mode is supported, so this menu item can't be used. + itemLive->Enable(false); + } + // If you use non-zero gravity you must initialize the splitter with its // correct initial size, otherwise it will change the sash position by a // huge amount when it's resized from its initial default size to its real diff --git a/src/generic/splitter.cpp b/src/generic/splitter.cpp index ed0dc2710d..5636704951 100644 --- a/src/generic/splitter.cpp +++ b/src/generic/splitter.cpp @@ -69,6 +69,11 @@ wxBEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow) #endif // wxMSW wxEND_EVENT_TABLE() +bool wxSplitterWindow::AlwaysUsesLiveUpdate() const +{ + return !wxClientDC::CanBeUsedForDrawing(this); +} + static bool IsLive(wxSplitterWindow* wnd) { // with wxSP_LIVE_UPDATE style the splitter windows are always resized @@ -76,10 +81,7 @@ static bool IsLive(wxSplitterWindow* wnd) // draw the sash at the new position but only resize the windows when the // dragging is finished -- but drawing the sash is done using wxClientDC, // so check if we can use it and always use live resizing if we can't - if ( !wxClientDC::CanBeUsedForDrawing(wnd) ) - return true; - - return wnd->HasFlag(wxSP_LIVE_UPDATE); + return wnd->AlwaysUsesLiveUpdate() || wnd->HasFlag(wxSP_LIVE_UPDATE); } bool wxSplitterWindow::Create(wxWindow *parent, wxWindowID id, From fffe7f717001d02be9c185938a3e06e39bc9d3a4 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 26 Dec 2023 19:23:40 +0100 Subject: [PATCH 08/10] Make using non-live resize work in wxAUI work in more cases Use wxClientDC instead of wxScreenDC, which only works in wxMSW, and use wxINVERT instead of wxXOR, to make DrawResizeHint() actually draw something in wxGTK3 too. And not using wxScreenDC might even help with some problems under MSW too, see #23982. Note that "rectangle hint" code still uses wxScreenDC, but this hint kind should probably be just removed as it doesn't seem useful for anything. --- src/aui/framemanager.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index 43f24e2933..3d8af0aeb3 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -279,16 +279,21 @@ static wxBitmap wxPaneCreateStippleBitmap() static void DrawResizeHint(wxDC& dc, const wxRect& rect) { +#ifdef __WXMSW__ wxBitmap stipple = wxPaneCreateStippleBitmap(); wxBrush brush(stipple); dc.SetBrush(brush); -#ifdef __WXMSW__ wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); PatBlt(GetHdcOf(*impl), rect.GetX(), rect.GetY(), rect.GetWidth(), rect.GetHeight(), PATINVERT); #else - dc.SetPen(*wxTRANSPARENT_PEN); + // Note that we have to use white colour for wxINVERT to work with + // wxGraphicsContext-based wxDC implementations, such as used by wxGTK3 + // (and wxOSX, but this code is never used for the latter because it always + // uses live resize). + dc.SetPen(*wxWHITE_PEN); + dc.SetBrush(*wxWHITE_BRUSH); - dc.SetLogicalFunction(wxXOR); + dc.SetLogicalFunction(wxINVERT); dc.DrawRectangle(rect); #endif } @@ -4469,7 +4474,7 @@ void wxAuiManager::OnLeftUp(wxMouseEvent& event) if (!HasLiveResize()) { // get rid of the hint rectangle - wxScreenDC dc; + wxClientDC dc{m_frame}; DrawResizeHint(dc, m_actionHintRect); } if (m_currentDragItem != -1 && HasLiveResize()) @@ -4584,9 +4589,8 @@ void wxAuiManager::OnMotion(wxMouseEvent& event) } else { - wxRect rect(m_frame->ClientToScreen(pos), - m_actionPart->rect.GetSize()); - wxScreenDC dc; + wxRect rect(pos, m_actionPart->rect.GetSize()); + wxClientDC dc{m_frame}; if (!m_actionHintRect.IsEmpty()) { @@ -4595,13 +4599,9 @@ void wxAuiManager::OnMotion(wxMouseEvent& event) m_actionHintRect = wxRect(); } - // draw new resize hint, if it's inside the managed frame - wxRect frameScreenRect = m_frame->GetScreenRect(); - if (frameScreenRect.Contains(rect)) - { - DrawResizeHint(dc, rect); - m_actionHintRect = rect; - } + // draw new resize hint + DrawResizeHint(dc, rect); + m_actionHintRect = rect; } } } From 3e32e0fa678e4d314a050c24f5f067df14c1493d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 26 Dec 2023 19:26:42 +0100 Subject: [PATCH 09/10] Allow using non-live resize in wxAUI with wxGTK3/X11 In this case we can still use wxClientDC, so let people do it if they really want to for consistency with wxSplitterWindow and because it doesn't really cost us anything. --- include/wx/aui/framemanager.h | 2 +- interface/wx/aui/framemanager.h | 10 ++++++--- src/aui/framemanager.cpp | 36 +++++++++++++-------------------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/include/wx/aui/framemanager.h b/include/wx/aui/framemanager.h index 167c486c35..0533a5b6f2 100644 --- a/include/wx/aui/framemanager.h +++ b/include/wx/aui/framemanager.h @@ -417,7 +417,7 @@ public: void SetFlags(unsigned int flags); unsigned int GetFlags() const; - static bool AlwaysUsesLiveResize(); + static bool AlwaysUsesLiveResize(const wxWindow* window = nullptr); bool HasLiveResize() const; void SetManagedWindow(wxWindow* managedWnd); diff --git a/interface/wx/aui/framemanager.h b/interface/wx/aui/framemanager.h index 549492f354..832b0282c8 100644 --- a/interface/wx/aui/framemanager.h +++ b/interface/wx/aui/framemanager.h @@ -219,12 +219,16 @@ public: If this function returns true, ::wxAUI_MGR_LIVE_RESIZE flag is ignored and live resize is always used, whether it's specified or not. - Currently this is the case for wxOSX and wxGTK3 ports, as live resizing - is the only implemented method there. + Currently this is the case for wxOSX and wxGTK3 when using Wayland, as + live resizing is the only implemented method there. See + wxClientDC::CanBeUsedForDrawing() for more details. + + @param window The associated window, may be null (this parameter was + added in wxWidgets 3.3.0) @since 3.1.4 */ - static bool AlwaysUsesLiveResize(); + static bool AlwaysUsesLiveResize(const wxWindow* window); /** This function is used by controls to calculate the drop hint rectangle. diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index 3d8af0aeb3..793e9498be 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -767,26 +767,17 @@ unsigned int wxAuiManager::GetFlags() const return m_flags; } -// With Core Graphics on Mac or GTK 3, it's not possible to show sash feedback, -// so we'll always use live update instead. -#if defined(__WXMAC__) || defined(__WXGTK3__) - #define wxUSE_AUI_LIVE_RESIZE_ALWAYS 1 -#else - #define wxUSE_AUI_LIVE_RESIZE_ALWAYS 0 -#endif - -/* static */ bool wxAuiManager::AlwaysUsesLiveResize() +/* static */ bool wxAuiManager::AlwaysUsesLiveResize(const wxWindow* window) { - return wxUSE_AUI_LIVE_RESIZE_ALWAYS; + // Not using live resize relies on wxClientDC being usable for drawing, so + // we have to use live resize if it can't be used on the current platform. + return !wxClientDC::CanBeUsedForDrawing(window); } bool wxAuiManager::HasLiveResize() const { -#if wxUSE_AUI_LIVE_RESIZE_ALWAYS - return true; -#else - return (GetFlags() & wxAUI_MGR_LIVE_RESIZE) == wxAUI_MGR_LIVE_RESIZE; -#endif + return AlwaysUsesLiveResize(m_frame) || + (GetFlags() & wxAUI_MGR_LIVE_RESIZE) == wxAUI_MGR_LIVE_RESIZE; } // don't use these anymore as they are deprecated @@ -3925,15 +3916,16 @@ void wxAuiManager::Repaint(wxDC* dc) // make a client dc if (!dc) { -#if wxUSE_AUI_LIVE_RESIZE_ALWAYS - // We can't use wxClientDC in these ports. - m_frame->Refresh() ; - m_frame->Update() ; - return ; -#else + if ( AlwaysUsesLiveResize(m_frame) ) + { + // We can't use wxClientDC in these ports. + m_frame->Refresh() ; + m_frame->Update() ; + return ; + } + client_dc.reset(new wxClientDC(m_frame)); dc = client_dc.get(); -#endif } int w, h; From 15af32035311dcf5c1b22b8ba05aa861c3682a00 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 26 Dec 2023 19:48:36 +0100 Subject: [PATCH 10/10] Fix updating wxAUI frame buttons on mouse hover This didn't work under wxOSX or wxGTK/Wayland as it used wxClientDC which doesn't work in these ports. Fix this in the usual way, i.e. by just redrawing everything in them. --- src/aui/framemanager.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index 793e9498be..3fe78a8a3c 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -4084,7 +4084,14 @@ void wxAuiManager::UpdateButtonOnScreen(wxAuiDockUIPart* button_ui_part, state = wxAUI_BUTTON_STATE_HOVER; } - // now repaint the button with hover state + // now repaint the button with hover state -- or everything if we can't + // repaint just it + if ( !wxClientDC::CanBeUsedForDrawing(m_frame) ) + { + m_frame->Refresh(); + m_frame->Update(); + } + wxClientDC cdc(m_frame); // if the frame has a toolbar, the client area