diff --git a/docs/changes.txt b/docs/changes.txt index 9d90e57ef6..4c69315fbd 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -44,6 +44,7 @@ All: - Allow specifying custom comparator for wxSortedArrayString (Catalin Raceanu). - Add wxDateTime::GetWeekBasedYear(). - Specialize std::hash<> for wxString when using C++11. +- Allow recursive calls to wxYield(). Unix: diff --git a/include/wx/evtloop.h b/include/wx/evtloop.h index 9b2b731e10..00e6d097d5 100644 --- a/include/wx/evtloop.h +++ b/include/wx/evtloop.h @@ -145,8 +145,8 @@ public: // process all currently pending events right now // - // it is an error to call Yield() recursively unless the value of - // onlyIfNeeded is true + // if onlyIfNeeded is true, returns false without doing anything else if + // we're already inside Yield() // // WARNING: this function is dangerous as it can lead to unexpected // 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 virtual bool IsYielding() const - { return m_isInsideYield; } + { return m_yieldLevel != 0; } // returns true if events of the given event category should be immediately // processed inside a wxApp::Yield() call or rather should be queued for @@ -214,8 +214,10 @@ protected: // should we exit the loop? bool m_shouldExit; - // YieldFor() helpers: - bool m_isInsideYield; + // incremented each time on entering Yield() and decremented on leaving it + int m_yieldLevel; + + // the argument of the last call to YieldFor() long m_eventsToProcessInsideYield; private: diff --git a/interface/wx/evtloop.h b/interface/wx/evtloop.h index 817f8111ce..544d577e5c 100644 --- a/interface/wx/evtloop.h +++ b/interface/wx/evtloop.h @@ -224,7 +224,6 @@ public: user to perform actions which are not compatible with the current task. Disabling menu items or whole menus during processing can avoid unwanted 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 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 iteration), call wxLog::FlushActive. - Calling Yield() recursively is normally an error and an assert failure is - raised in debug build if such situation is detected. However if the - @a onlyIfNeeded parameter is @true, the method will just silently - return @false instead. + If @a onlyIfNeeded parameter is @true and the flow control is already + inside Yield(), i.e. IsYielding() returns @true, the method just + silently returns @false and doesn't do anything. */ bool Yield(bool onlyIfNeeded = false); diff --git a/src/common/evtloopcmn.cpp b/src/common/evtloopcmn.cpp index caecab0e33..626cb51b4d 100644 --- a/src/common/evtloopcmn.cpp +++ b/src/common/evtloopcmn.cpp @@ -34,7 +34,7 @@ wxEventLoopBase::wxEventLoopBase() { m_isInsideRun = false; m_shouldExit = false; - m_isInsideYield = false; + m_yieldLevel = 0; m_eventsToProcessInsideYield = wxEVT_CATEGORY_ALL; } @@ -100,15 +100,8 @@ bool wxEventLoopBase::ProcessIdle() bool wxEventLoopBase::Yield(bool onlyIfNeeded) { - if ( m_isInsideYield ) - { - if ( !onlyIfNeeded ) - { - wxFAIL_MSG( wxT("wxYield called recursively" ) ); - } - + if ( onlyIfNeeded && IsYielding() ) return false; - } return YieldFor(wxEVT_CATEGORY_ALL); } @@ -124,10 +117,14 @@ bool wxEventLoopBase::YieldFor(long eventsToProcess) #endif // wxUSE_THREADS // set the flag and don't forget to reset it before returning - m_isInsideYield = true; - m_eventsToProcessInsideYield = eventsToProcess; + const int yieldLevelOld = m_yieldLevel; + 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 // disable log flushing from here because a call to wxYield() shouldn't