// List containing event handlers with pending events (each handler can occur
// at most once here)
-wxList *wxPendingEvents = NULL;
+wxList *wxHandlersWithPendingEvents = NULL;
#if wxUSE_THREADS
- // protects wxPendingEvents list
- wxCriticalSection *wxPendingEventsLocker = NULL;
+ // protects wxHandlersWithPendingEvents list
+ wxCriticalSection *wxHandlersWithPendingEventsLocker = NULL;
#endif
// common event types are defined here, other event types are defined by the
void wxMouseEvent::Assign(const wxMouseEvent& event)
{
wxEvent::operator=(event);
- wxMouseState::operator=(event);
+
+ // Borland C++ 5.82 doesn't compile an explicit call to an implicitly
+ // defined operator=() so need to do it this way:
+ *static_cast<wxMouseState *>(this) = event;
m_x = event.m_x;
m_y = event.m_y;
wxEvtHandler::wxEvtHandler()
{
- m_beingDeleted = false;
-
m_nextHandler = (wxEvtHandler *) NULL;
m_previousHandler = (wxEvtHandler *) NULL;
m_enabled = true;
wxEvtHandler::~wxEvtHandler()
{
- m_beingDeleted = true;
-
// Takes itself out of the list of handlers
if (m_previousHandler)
m_previousHandler->m_nextHandler = m_nextHandler;
wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it;
// Remove ourselves from sink destructor notifications
+ // (this has usually been been done, in wxTrackable destructor)
wxEvtHandler *eventSink = entry->m_eventSink;
if ( eventSink )
{
};
if (m_pendingEvents)
- {
- // At this time, we could still be used from other threads.
- // Continue to use sync objects.
- wxENTER_CRIT_SECT( m_pendingEventsLock );
-
m_pendingEvents->DeleteContents(true);
- delete m_pendingEvents;
- m_pendingEvents = NULL;
-
- wxLEAVE_CRIT_SECT( m_pendingEventsLock );
- }
+ delete m_pendingEvents;
- // Remove us from wxPendingEvents if necessary.
- if ( wxPendingEvents )
+ // Remove us from wxHandlersWithPendingEvents if necessary.
+ if ( wxHandlersWithPendingEvents )
{
#if wxUSE_THREADS
- if (wxPendingEventsLocker)
- wxENTER_CRIT_SECT(*wxPendingEventsLocker);
+ if (wxHandlersWithPendingEventsLocker)
+ wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
#endif
- if ( wxPendingEvents->DeleteObject(this) )
+ if ( wxHandlersWithPendingEvents->DeleteObject(this) )
{
// check that we were present only once in the list
- wxASSERT_MSG( !wxPendingEvents->Find(this),
- "Handler occurs twice in wxPendingEvents list" );
+ wxASSERT_MSG( !wxHandlersWithPendingEvents->Find(this),
+ "Handler occurs twice in wxHandlersWithPendingEvents list" );
}
//else: we weren't in this list at all, it's ok
#if wxUSE_THREADS
- if (wxPendingEventsLocker)
- wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
+ if (wxHandlersWithPendingEventsLocker)
+ wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
#endif
}
{
wxCHECK_RET( event, "NULL event can't be posted" );
- // Catch the situation where destructor is already invoked (in another thread)
- if( m_beingDeleted ) return;
-
// 1) Add this event to our list of pending events
wxENTER_CRIT_SECT( m_pendingEventsLock );
m_pendingEvents->Append(event);
- wxLEAVE_CRIT_SECT( m_pendingEventsLock );
-
// 2) Add this event handler to list of event handlers that
// have pending events.
- wxENTER_CRIT_SECT(*wxPendingEventsLocker);
+ wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
+
+ if ( !wxHandlersWithPendingEvents )
+ wxHandlersWithPendingEvents = new wxList;
+ if ( !wxHandlersWithPendingEvents->Find(this) )
+ wxHandlersWithPendingEvents->Append(this);
- if ( !wxPendingEvents )
- wxPendingEvents = new wxList;
- if ( !wxPendingEvents->Find(this) )
- wxPendingEvents->Append(this);
+ wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
- wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
+ // only release m_pendingEventsLock now because otherwise there is a race
+ // condition as described in the ticket #9093: we could process the event
+ // just added to m_pendingEvents in our ProcessPendingEvents() below before
+ // we had time to append this pointer to wxHandlersWithPendingEvents list; thus
+ // breaking the invariant that a handler should be in the list iff it has
+ // any pending events to process
+ wxLEAVE_CRIT_SECT( m_pendingEventsLock );
// 3) Inform the system that new pending events are somewhere,
// and that these should be processed in idle time.
{
wxENTER_CRIT_SECT( m_pendingEventsLock );
- // This method is only called by wxApp if this handler does have
- // pending events, but it happens occasionally when using multi-
- // threading and we don't want a crash due to that.
- if( !m_pendingEvents )
- {
- wxLEAVE_CRIT_SECT( m_pendingEventsLock );
- return;
- }
-
- if( m_pendingEvents->IsEmpty() )
- {
- wxPendingEvents->DeleteObject(this);
- wxLEAVE_CRIT_SECT( m_pendingEventsLock );
- return;
- }
+ // this method is only called by wxApp if this handler does have
+ // pending events
+ wxCHECK_RET( m_pendingEvents && !m_pendingEvents->IsEmpty(),
+ "should have pending events if called" );
wxList::compatibility_iterator node = m_pendingEvents->GetFirst();
- wxEventPtr event(wx_static_cast(wxEvent *, node->GetData()));
+ wxEventPtr event(static_cast<wxEvent *>(node->GetData()));
// it's important we remove event from list before processing it, else a
// nested event loop, for example from a modal dialog, might process the
if ( m_pendingEvents->IsEmpty() )
{
#if wxUSE_THREADS
- if (wxPendingEventsLocker)
- wxENTER_CRIT_SECT(*wxPendingEventsLocker);
+ if (wxHandlersWithPendingEventsLocker)
+ wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
#endif
- wxPendingEvents->DeleteObject(this);
+ wxHandlersWithPendingEvents->DeleteObject(this);
#if wxUSE_THREADS
- if (wxPendingEventsLocker)
- wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
+ if (wxHandlersWithPendingEventsLocker)
+ wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
#endif
}
bool wxEvtHandler::TryParent(wxEvent& event)
{
+ if ( GetNextHandler() )
+ {
+ // the next handler will pass it to wxTheApp if it doesn't process it,
+ // so return from here to avoid doing it again
+ return GetNextHandler()->TryParent(event);
+ }
+
if ( wxTheApp && (this != wxTheApp) )
{
// Special case: don't pass wxEVT_IDLE to wxApp, since it'll always
return true;
// propagate the event upwards the window chain and/or to the application
- // object if it wasn't processed at this level
+ // object if it wasn't processed at this level
return TryParent(event);
}
}
void wxEvtHandler::Connect( int id, int lastId,
- int eventType,
+ wxEventType eventType,
wxObjectEventFunction func,
wxObject *userData,
wxEvtHandler* eventSink )
if ( evtConnRef )
evtConnRef->IncRef( );
else
- evtConnRef = new wxEventConnectionRef(this, eventSink);
+ new wxEventConnectionRef(this, eventSink);
}
}