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
This commit is contained in:
Francesco Montorsi
2009-03-08 12:58:24 +00:00
parent db034c5228
commit cae9e7b169
6 changed files with 97 additions and 13 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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()
*/

View File

@@ -132,6 +132,7 @@ wxAppConsoleBase::wxAppConsoleBase()
{
m_traits = NULL;
m_mainLoop = NULL;
m_bDoPendingEventProcessing = true;
ms_appInstance = static_cast<wxAppConsole *>(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; i<m_handlersWithPendingEvents.GetCount(); i++)
m_handlersWithPendingEvents[i]->DeletePendingEvents();
m_handlersWithPendingEvents.Clear();
wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
}
// ----------------------------------------------------------------------------
// exception handling
// ----------------------------------------------------------------------------

View File

@@ -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)