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
//to the list of the handlers with _delayed_ pending events
void DelayPendingEventHandler(wxEvtHandler* toDelay);
//to the list of the handlers with _delayed_ pending events
void DelayPendingEventHandler(wxEvtHandler* toDelay);
+ // deletes the current pending events
+ void DeletePendingEvents();
+
// wxEventLoop redirections
// ------------------------
// wxEventLoop redirections
// ------------------------
// been started yet or has already terminated)
wxEventLoopBase *m_mainLoop;
// 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;
// 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
wxEvtHandlerArray m_handlersWithPendingDelayedEvents;
#if wxUSE_THREADS
wxCriticalSection m_handlersWithPendingEventsLocker;
#endif
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
friend class WXDLLIMPEXP_FWD_BASE wxEvtHandler;
// the application object is a singleton anyhow, there is no sense in
// Event queuing and processing
// ----------------------------
// 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.
// 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.
void ProcessPendingEvents();
// NOTE: uses ProcessEvent()
void ProcessPendingEvents();
// NOTE: uses ProcessEvent()
+ void DeletePendingEvents();
+
#if wxUSE_THREADS
bool ProcessThreadEvent(const wxEvent& event);
#if wxUSE_THREADS
bool ProcessThreadEvent(const wxEvent& event);
- // NOTE: uses AddPendingEvent()
+ // NOTE: uses AddPendingEvent(); call only from secondary threads
/**
Process all pending events; it is necessary to call this function to
/**
Process all pending events; it is necessary to call this function to
+ 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.
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();
*/
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.
/**
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;
*/
bool HasPendingEvents() const;
@see wxWindow::HandleWindowEvent
*/
bool SafelyProcessEvent(wxEvent& event);
@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.
/**
Searches the event table, executing an event handler function if an appropriate
one is found.
If a suitable function is called but calls wxEvent::Skip, this
function will fail, and searching will continue.
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?
{
m_traits = NULL;
m_mainLoop = NULL;
{
m_traits = NULL;
m_mainLoop = NULL;
+ m_bDoPendingEventProcessing = true;
ms_appInstance = static_cast<wxAppConsole *>(this);
ms_appInstance = static_cast<wxAppConsole *>(this);
void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
{
void wxAppConsoleBase::SuspendProcessingOfPendingEvents()
{
- wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
- // entering the critical section locks blocks calls to ProcessPendingEvents()
+ m_bDoPendingEventProcessing = false;
}
void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
{
}
void wxAppConsoleBase::ResumeProcessingOfPendingEvents()
{
- wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
+ m_bDoPendingEventProcessing = true;
}
void wxAppConsoleBase::ProcessPendingEvents()
{
}
void wxAppConsoleBase::ProcessPendingEvents()
{
+ if (!m_bDoPendingEventProcessing)
+ return;
+
wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(),
wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(),
wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
}
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
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// exception handling
// ----------------------------------------------------------------------------
delete m_dynamicEvents;
}
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);
// 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;
// we only delete object data, not untyped
if ( m_clientDataType == wxClientData_Object )
delete m_clientObject;
wxENTER_CRIT_SECT( m_pendingEventsLock );
if ( !m_pendingEvents )
wxENTER_CRIT_SECT( m_pendingEventsLock );
if ( !m_pendingEvents )
- m_pendingEvents = new wxList;
+ m_pendingEvents = new wxList;
m_pendingEvents->Append(event);
m_pendingEvents->Append(event);
+void wxEvtHandler::DeletePendingEvents()
+{
+ if (m_pendingEvents)
+ m_pendingEvents->DeleteContents(true);
+ wxDELETE(m_pendingEvents);
+}
+
void wxEvtHandler::ProcessPendingEvents()
{
if (!wxTheApp)
void wxEvtHandler::ProcessPendingEvents()
{
if (!wxTheApp)