Allow recursive calls to wxEventLoop::Yield().

There doesn't seem to be any reason to forbid them and this change allows
wxExecute() without wxEXEC_NOEVENTS to work without assertion failures when
called from inside wxYield().

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@77650 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2014-09-10 16:51:06 +00:00
parent 36f51e1479
commit dc65fa8d5a
4 changed files with 20 additions and 22 deletions

View File

@@ -44,6 +44,7 @@ All:
- Allow specifying custom comparator for wxSortedArrayString (Catalin Raceanu). - Allow specifying custom comparator for wxSortedArrayString (Catalin Raceanu).
- Add wxDateTime::GetWeekBasedYear(). - Add wxDateTime::GetWeekBasedYear().
- Specialize std::hash<> for wxString when using C++11. - Specialize std::hash<> for wxString when using C++11.
- Allow recursive calls to wxYield().
Unix: Unix:

View File

@@ -145,8 +145,8 @@ public:
// process all currently pending events right now // process all currently pending events right now
// //
// it is an error to call Yield() recursively unless the value of // if onlyIfNeeded is true, returns false without doing anything else if
// onlyIfNeeded is true // we're already inside Yield()
// //
// WARNING: this function is dangerous as it can lead to unexpected // WARNING: this function is dangerous as it can lead to unexpected
// reentrancies (i.e. when called from an event handler it // reentrancies (i.e. when called from an event handler it
@@ -162,7 +162,7 @@ public:
// returns true if the main thread is inside a Yield() call // returns true if the main thread is inside a Yield() call
virtual bool IsYielding() const virtual bool IsYielding() const
{ return m_isInsideYield; } { return m_yieldLevel != 0; }
// returns true if events of the given event category should be immediately // returns true if events of the given event category should be immediately
// processed inside a wxApp::Yield() call or rather should be queued for // processed inside a wxApp::Yield() call or rather should be queued for
@@ -214,8 +214,10 @@ protected:
// should we exit the loop? // should we exit the loop?
bool m_shouldExit; bool m_shouldExit;
// YieldFor() helpers: // incremented each time on entering Yield() and decremented on leaving it
bool m_isInsideYield; int m_yieldLevel;
// the argument of the last call to YieldFor()
long m_eventsToProcessInsideYield; long m_eventsToProcessInsideYield;
private: private:

View File

@@ -224,7 +224,6 @@ public:
user to perform actions which are not compatible with the current task. user to perform actions which are not compatible with the current task.
Disabling menu items or whole menus during processing can avoid unwanted Disabling menu items or whole menus during processing can avoid unwanted
reentrance of code: see ::wxSafeYield for a better function. reentrance of code: see ::wxSafeYield for a better function.
You can avoid unwanted reentrancies also using IsYielding().
Note that Yield() will not flush the message logs. This is intentional as Note that Yield() will not flush the message logs. This is intentional as
calling Yield() is usually done to quickly update the screen and popping up calling Yield() is usually done to quickly update the screen and popping up
@@ -232,10 +231,9 @@ public:
messages immediately (otherwise it will be done during the next idle loop messages immediately (otherwise it will be done during the next idle loop
iteration), call wxLog::FlushActive. iteration), call wxLog::FlushActive.
Calling Yield() recursively is normally an error and an assert failure is If @a onlyIfNeeded parameter is @true and the flow control is already
raised in debug build if such situation is detected. However if the inside Yield(), i.e. IsYielding() returns @true, the method just
@a onlyIfNeeded parameter is @true, the method will just silently silently returns @false and doesn't do anything.
return @false instead.
*/ */
bool Yield(bool onlyIfNeeded = false); bool Yield(bool onlyIfNeeded = false);

View File

@@ -34,7 +34,7 @@ wxEventLoopBase::wxEventLoopBase()
{ {
m_isInsideRun = false; m_isInsideRun = false;
m_shouldExit = false; m_shouldExit = false;
m_isInsideYield = false; m_yieldLevel = 0;
m_eventsToProcessInsideYield = wxEVT_CATEGORY_ALL; m_eventsToProcessInsideYield = wxEVT_CATEGORY_ALL;
} }
@@ -100,15 +100,8 @@ bool wxEventLoopBase::ProcessIdle()
bool wxEventLoopBase::Yield(bool onlyIfNeeded) bool wxEventLoopBase::Yield(bool onlyIfNeeded)
{ {
if ( m_isInsideYield ) if ( onlyIfNeeded && IsYielding() )
{
if ( !onlyIfNeeded )
{
wxFAIL_MSG( wxT("wxYield called recursively" ) );
}
return false; return false;
}
return YieldFor(wxEVT_CATEGORY_ALL); return YieldFor(wxEVT_CATEGORY_ALL);
} }
@@ -124,10 +117,14 @@ bool wxEventLoopBase::YieldFor(long eventsToProcess)
#endif // wxUSE_THREADS #endif // wxUSE_THREADS
// set the flag and don't forget to reset it before returning // set the flag and don't forget to reset it before returning
m_isInsideYield = true; const int yieldLevelOld = m_yieldLevel;
m_eventsToProcessInsideYield = eventsToProcess; const long eventsToProcessOld = m_eventsToProcessInsideYield;
wxON_BLOCK_EXIT_SET(m_isInsideYield, false); m_yieldLevel++;
wxON_BLOCK_EXIT_SET(m_yieldLevel, yieldLevelOld);
m_eventsToProcessInsideYield = eventsToProcess;
wxON_BLOCK_EXIT_SET(m_eventsToProcessInsideYield, eventsToProcessOld);
#if wxUSE_LOG #if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't // disable log flushing from here because a call to wxYield() shouldn't