Fix problem with nested wxEVT_PAINT handlers in wxMSW

If wxEVT_PAINT handler did something that resulted in another window
being repainted, the state of the global wxDidCreatePaintDC flag got
out of sync with reality, resulting in refresh problems.

This notably happened with wxStyledTextCtrl, which generates
wxEVT_STC_UPDATEUI from its own paint handler, and so wxSTC itself
wasn't redrawn correctly if wxEVT_STC_UPDATEUI handler did anything
resulting in another repaint itself, such as calling
wxStatusBar::SetStatusText().

Fix this by replacing a single global bool with a stack of booleans,
with each window being repainted storing and removing its own flag
indicating whether a wxPaintDC was created for it in this stack.

This is sufficient for nested repaints and we really shouldn't have
any interleaved ones in any case, os it's not a problem not to support
those.

Closes #18451.
This commit is contained in:
Andreas Falkenhahn
2019-11-10 17:15:39 +01:00
committed by Vadim Zeitlin
parent 4f7dde18ca
commit 5646ba7261
2 changed files with 12 additions and 7 deletions

View File

@@ -63,6 +63,7 @@
#include "wx/popupwin.h"
#include "wx/power.h"
#include "wx/scopeguard.h"
#include "wx/stack.h"
#include "wx/sysopt.h"
#if wxUSE_DRAG_AND_DROP
@@ -5261,8 +5262,8 @@ wxColour wxWindowMSW::MSWGetThemeColour(const wchar_t *themeName,
// endless stream of WM_PAINT messages for this window resulting in a lot of
// difficult to debug problems (e.g. impossibility to repaint other windows,
// lack of timer and idle events and so on)
extern bool wxDidCreatePaintDC;
bool wxDidCreatePaintDC = false;
extern wxStack<bool> wxDidCreatePaintDC;
wxStack<bool> wxDidCreatePaintDC;
bool wxWindowMSW::HandlePaint()
{
@@ -5278,14 +5279,14 @@ bool wxWindowMSW::HandlePaint()
m_updateRegion = wxRegion((WXHRGN) hRegion);
wxDidCreatePaintDC = false;
wxDidCreatePaintDC.push(false);
wxPaintEvent event(m_windowId);
event.SetEventObject(this);
bool processed = HandleWindowEvent(event);
if ( wxDidCreatePaintDC && !processed )
if ( wxDidCreatePaintDC.top() && !processed )
{
// Event handler did paint something as wxPaintDC object was created
// but then it must have skipped the event to indicate that default
@@ -5316,7 +5317,9 @@ bool wxWindowMSW::HandlePaint()
// was processed, we must still call MSWDefWindowProc() to ensure that the
// window is validated, i.e. to avoid the problem described in the comment
// before wxDidCreatePaintDC definition above.
return wxDidCreatePaintDC;
const bool ret = wxDidCreatePaintDC.top();
wxDidCreatePaintDC.pop();
return ret;
}
// Can be called from an application's OnPaint handler