From cae9e7b169b5507dc6dced7fc0e0c3b3d9575f3a Mon Sep 17 00:00:00 2001 From: Francesco Montorsi Date: Sun, 8 Mar 2009 12:58:24 +0000 Subject: [PATCH] add wxAppConsoleBase::DeletePendingEvents and wxEvtHandler::DeletePendingEvents. Fix wxAppConsoleBase::Suspend/ResumeProcessingOfPendingEvents: locking the mutex does not prevent wxAppConsoleBase::ProcessPendingEvents from running if the mutex was locked from the main thread! git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59433 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/app.h | 14 +++++++++++++- include/wx/event.h | 5 +++-- interface/wx/app.h | 24 ++++++++++++++++++++++-- interface/wx/event.h | 28 ++++++++++++++++++++++++++++ src/common/appbase.cpp | 24 +++++++++++++++++++++--- src/common/event.cpp | 15 ++++++++++----- 6 files changed, 97 insertions(+), 13 deletions(-) diff --git a/include/wx/app.h b/include/wx/app.h index 1a9a083f5e..5e0e97060e 100644 --- a/include/wx/app.h +++ b/include/wx/app.h @@ -313,6 +313,9 @@ public: //to the list of the handlers with _delayed_ pending events void DelayPendingEventHandler(wxEvtHandler* toDelay); + // deletes the current pending events + void DeletePendingEvents(); + // wxEventLoop redirections // ------------------------ @@ -420,11 +423,17 @@ protected: // been started yet or has already terminated) wxEventLoopBase *m_mainLoop; + + // pending events management vars: + // the array of the handlers with pending events which needs to be processed // inside ProcessPendingEvents() wxEvtHandlerArray m_handlersWithPendingEvents; - // helper array used by ProcessPendingEvents() + // helper array used by ProcessPendingEvents() to store the event handlers + // which have pending events but of these events none can be processed right now + // (because of a call to wxEventLoop::YieldFor() which asked to selectively process + // pending events) wxEvtHandlerArray m_handlersWithPendingDelayedEvents; #if wxUSE_THREADS @@ -432,6 +441,9 @@ protected: wxCriticalSection m_handlersWithPendingEventsLocker; #endif + // flag modified by Suspend/ResumeProcessingOfPendingEvents() + bool m_bDoPendingEventProcessing; + friend class WXDLLIMPEXP_FWD_BASE wxEvtHandler; // the application object is a singleton anyhow, there is no sense in diff --git a/include/wx/event.h b/include/wx/event.h index ad6469b958..259694172e 100644 --- a/include/wx/event.h +++ b/include/wx/event.h @@ -2864,7 +2864,6 @@ public: // Event queuing and processing // ---------------------------- - // Process an event right now: this can only be called from the main // thread, use QueueEvent() for scheduling the events for // processing from other threads. @@ -2900,9 +2899,11 @@ public: void ProcessPendingEvents(); // NOTE: uses ProcessEvent() + void DeletePendingEvents(); + #if wxUSE_THREADS bool ProcessThreadEvent(const wxEvent& event); - // NOTE: uses AddPendingEvent() + // NOTE: uses AddPendingEvent(); call only from secondary threads #endif diff --git a/interface/wx/app.h b/interface/wx/app.h index 9d358c7473..7bc9844834 100644 --- a/interface/wx/app.h +++ b/interface/wx/app.h @@ -125,15 +125,35 @@ public: /** Process all pending events; it is necessary to call this function to - process posted events. + process events posted with wxEvtHandler::QueueEvent or wxEvtHandler::AddPendingEvent. - This happens during each event loop iteration in GUI mode but + This happens during each event loop iteration (see wxEventLoopBase) in GUI mode but it may be also called directly. + + Note that this function does not only process the pending events for the wxApp object + itself (which derives from wxEvtHandler) but also the pending events for @e any + event handler of this application. + + This function will immediately return and do nothing if SuspendProcessingOfPendingEvents() + was called. */ virtual void ProcessPendingEvents(); + + /** + Deletes the pending events of all wxEvtHandlers of this application. + + See wxEvtHandler::DeletePendingEvents() for warnings about deleting the pending + events. + */ + void DeletePendingEvents(); /** Returns @true if there are pending events on the internal pending event list. + + Whenever wxEvtHandler::QueueEvent or wxEvtHandler::AddPendingEvent() are + called (not only for wxApp itself, but for any event handler of the application!), + the internal wxApp's list of handlers with pending events is updated and this + function will return true. */ bool HasPendingEvents() const; diff --git a/interface/wx/event.h b/interface/wx/event.h index 2e80f9c739..548ceffb06 100644 --- a/interface/wx/event.h +++ b/interface/wx/event.h @@ -533,7 +533,32 @@ public: @see wxWindow::HandleWindowEvent */ bool SafelyProcessEvent(wxEvent& event); + + /** + Processes the pending events previously queued using QueueEvent() or + AddPendingEvent(); you must call this function only if you are sure + there are pending events for this handler, otherwise a @c wxCHECK + will fail. + + The real processing still happens in ProcessEvent() which is called by this + function. + + Note that this function needs a valid application object (see + wxAppConsole::GetInstance()) because wxApp holds the list of the event + handlers with pending events and this function manipulates that list. + */ + void ProcessPendingEvents(); + /** + Deletes all events queued on this event handler using QueueEvent() or + AddPendingEvent(). + + Use with care because the events which are deleted are (obviously) not + processed and this may have unwanted consequences (e.g. user actions events + will be lost). + */ + void DeletePendingEvents(); + /** Searches the event table, executing an event handler function if an appropriate one is found. @@ -555,6 +580,9 @@ public: If a suitable function is called but calls wxEvent::Skip, this function will fail, and searching will continue. + + @todo this function in the header is listed as an "implementation only" function; + are we sure we want to document it? @see ProcessEvent() */ diff --git a/src/common/appbase.cpp b/src/common/appbase.cpp index a78e93d1d4..111ff3c7af 100644 --- a/src/common/appbase.cpp +++ b/src/common/appbase.cpp @@ -132,6 +132,7 @@ wxAppConsoleBase::wxAppConsoleBase() { m_traits = NULL; m_mainLoop = NULL; + m_bDoPendingEventProcessing = true; ms_appInstance = static_cast(this); @@ -415,17 +416,19 @@ bool wxAppConsoleBase::HasPendingEvents() const void wxAppConsoleBase::SuspendProcessingOfPendingEvents() { - wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker); - // entering the critical section locks blocks calls to ProcessPendingEvents() + m_bDoPendingEventProcessing = false; } void wxAppConsoleBase::ResumeProcessingOfPendingEvents() { - wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker); + m_bDoPendingEventProcessing = true; } void wxAppConsoleBase::ProcessPendingEvents() { + if (!m_bDoPendingEventProcessing) + return; + wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker); wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(), @@ -462,6 +465,21 @@ void wxAppConsoleBase::ProcessPendingEvents() wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker); } +void wxAppConsoleBase::DeletePendingEvents() +{ + wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker); + + wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(), + "this helper list should be empty" ); + + for (unsigned int i=0; iDeletePendingEvents(); + + m_handlersWithPendingEvents.Clear(); + + wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker); +} + // ---------------------------------------------------------------------------- // exception handling // ---------------------------------------------------------------------------- diff --git a/src/common/event.cpp b/src/common/event.cpp index 7118b7dbd9..461b6fe5e7 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -1079,14 +1079,12 @@ wxEvtHandler::~wxEvtHandler() delete m_dynamicEvents; } - if (m_pendingEvents) - m_pendingEvents->DeleteContents(true); - delete m_pendingEvents; - // Remove us from the list of the pending events if necessary. if (wxTheApp) wxTheApp->RemovePendingEventHandler(this); + DeletePendingEvents(); + // we only delete object data, not untyped if ( m_clientDataType == wxClientData_Object ) delete m_clientObject; @@ -1147,7 +1145,7 @@ void wxEvtHandler::QueueEvent(wxEvent *event) wxENTER_CRIT_SECT( m_pendingEventsLock ); if ( !m_pendingEvents ) - m_pendingEvents = new wxList; + m_pendingEvents = new wxList; m_pendingEvents->Append(event); @@ -1169,6 +1167,13 @@ void wxEvtHandler::QueueEvent(wxEvent *event) wxWakeUpIdle(); } +void wxEvtHandler::DeletePendingEvents() +{ + if (m_pendingEvents) + m_pendingEvents->DeleteContents(true); + wxDELETE(m_pendingEvents); +} + void wxEvtHandler::ProcessPendingEvents() { if (!wxTheApp) -- 2.45.2