}
+// ----------------------------------------------------------------------------
+// wxEventConnectionRef
+// ----------------------------------------------------------------------------
+
+// Below functions are mostly short but kept in cpp file to simplify setting
+// breakpoints (GDB)
+wxEventConnectionRef::wxEventConnectionRef(wxEvtHandler *src, wxEvtHandler *sink)
+ : m_src(src), m_sink(sink), m_refCount(1)
+{
+ wxASSERT( m_sink );
+ m_sink->AddNode( this );
+}
+
+wxEventConnectionRef::~wxEventConnectionRef()
+{
+}
+
+void wxEventConnectionRef::OnObjectDestroy( )
+{
+ if( m_src )
+ m_src->OnSinkDestroyed( m_sink );
+ // It is safe to delete this tracker object here
+ delete this;
+}
+
+void wxEventConnectionRef::DecRef( )
+{
+ if( !--m_refCount )
+ {
+ // The sink holds the only external pointer to this object
+ if( m_sink )
+ m_sink->RemoveNode(this);
+ delete this;
+ }
+}
+
+
// ----------------------------------------------------------------------------
// wxEvtHandler
// ----------------------------------------------------------------------------
m_enabled = true;
m_dynamicEvents = (wxList *) NULL;
m_pendingEvents = (wxList *) NULL;
-#if wxUSE_THREADS
-# if !defined(__VISAGECPP__)
- m_eventsLocker = new wxCriticalSection;
-# endif
-#endif
// no client data (yet)
m_clientData = NULL;
{
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 )
+ {
+ wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink );
+ if( pecr )
+ {
+ eventSink->RemoveNode( pecr );
+ delete pecr;
+ }
+ }
+
if (entry->m_callbackUserData)
delete entry->m_callbackUserData;
delete entry;
m_pendingEvents->DeleteContents(true);
delete m_pendingEvents;
-# if !defined(__VISAGECPP__)
- delete m_eventsLocker;
-# endif
-
// Remove us from wxPendingEvents if necessary.
if ( wxPendingEvents )
{
+#if wxUSE_THREADS
if(wxPendingEventsLocker)
wxENTER_CRIT_SECT(*wxPendingEventsLocker);
+#endif
if ( wxPendingEvents->DeleteObject(this) )
{
}
//else: we weren't in this list at all, it's ok
+#if wxUSE_THREADS
if(wxPendingEventsLocker)
wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
+#endif
}
// we only delete object data, not untyped
return true;
}
-void wxEvtHandler::ClearEventLocker()
-{
-#if !defined(__VISAGECPP__)
- delete m_eventsLocker;
- m_eventsLocker = NULL;
-#endif
-}
-
#endif // wxUSE_THREADS
void wxEvtHandler::AddPendingEvent(const wxEvent& event)
wxCHECK_RET( eventCopy,
_T("events of this type aren't supposed to be posted") );
- wxENTER_CRIT_SECT( Lock() );
+ wxENTER_CRIT_SECT( m_pendingEventsLock );
if ( !m_pendingEvents )
m_pendingEvents = new wxList;
m_pendingEvents->Append(eventCopy);
- wxLEAVE_CRIT_SECT( Lock() );
+ wxLEAVE_CRIT_SECT( m_pendingEventsLock );
// 2) Add this event handler to list of event handlers that
// have pending events.
void wxEvtHandler::ProcessPendingEvents()
{
- wxENTER_CRIT_SECT( Lock() );
+ wxENTER_CRIT_SECT( m_pendingEventsLock );
// this method is only called by wxApp if this handler does have
// pending events
if ( m_pendingEvents->IsEmpty() )
wxPendingEvents->DeleteObject(this);
- wxLEAVE_CRIT_SECT( Lock() );
+ wxLEAVE_CRIT_SECT( m_pendingEventsLock );
ProcessEvent(*event);
// Insert at the front of the list so most recent additions are found first
m_dynamicEvents->Insert( (wxObject*) entry );
+
+ // Make sure we get to know when a sink is destroyed
+ if( eventSink )
+ {
+ wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink );
+ if( pecr )
+ pecr->IncRef( );
+ else
+ pecr = new wxEventConnectionRef(this,eventSink);
+ }
}
bool wxEvtHandler::Disconnect( int id, int lastId, wxEventType eventType,
if (!m_dynamicEvents)
return false;
+ // Remove connection from tracker node (wxEventConnectionRef)
+ if( eventSink )
+ {
+ wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink );
+ if( pecr )
+ pecr->DecRef( );
+ }
+
wxList::compatibility_iterator node = m_dynamicEvents->GetFirst();
while (node)
{
return m_clientData;
}
+// A helper func to find an wxEventConnectionRef object
+wxEventConnectionRef* wxEvtHandler::FindRefInTrackerList( wxEvtHandler *eventSink )
+{
+ wxASSERT(eventSink);
+ for( wxTrackerNode *ptn=eventSink->GetFirst(); ptn; ptn=ptn->m_nxt )
+ {
+ // Only want wxEventConnectionRef nodes here
+ if( ptn->GetType()!=wxTrackerNode::EventConnectionRef )
+ continue;
+ wxEventConnectionRef *pecr = static_cast<wxEventConnectionRef*>(ptn);
+ if( pecr && pecr->m_src==this )
+ {
+ wxASSERT( pecr->m_sink==eventSink );
+ return pecr;
+ }
+ }
+ return NULL;
+}
+
+void wxEvtHandler::OnSinkDestroyed( wxEvtHandler *sink )
+{
+ wxASSERT(m_dynamicEvents);
+
+ // remove all connections with this sink
+ wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(), node_nxt;
+ while (node)
+ {
+ wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData();
+ node_nxt = node->GetNext();
+
+ if( entry->m_eventSink==sink )
+ {
+ if (entry->m_callbackUserData)
+ delete entry->m_callbackUserData;
+ m_dynamicEvents->Erase( node );
+ delete entry;
+ }
+ node = node_nxt;
+ }
+}
+
#endif // wxUSE_BASE
#if wxUSE_GUI