]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/event.cpp
compute scrollbar widths in a more standard way, get rid of redundant m_hasScrolling...
[wxWidgets.git] / src / common / event.cpp
index e5d4884bba21017d06abafe8fc9af983407502d5..4ca845660e2bd86724a8733661b406acc7075c3c 100644 (file)
@@ -1013,6 +1013,43 @@ void wxEventHashTable::GrowEventTypeTable()
 }
 
 
+// ----------------------------------------------------------------------------
+// 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
 // ----------------------------------------------------------------------------
@@ -1028,11 +1065,6 @@ wxEvtHandler::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;
@@ -1057,6 +1089,19 @@ wxEvtHandler::~wxEvtHandler()
         {
             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;
@@ -1068,15 +1113,13 @@ wxEvtHandler::~wxEvtHandler()
         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) )
         {
@@ -1086,8 +1129,10 @@ wxEvtHandler::~wxEvtHandler()
         }
         //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
@@ -1108,14 +1153,6 @@ bool wxEvtHandler::ProcessThreadEvent(const wxEvent& event)
     return true;
 }
 
-void wxEvtHandler::ClearEventLocker()
-{
-#if !defined(__VISAGECPP__)
-    delete m_eventsLocker;
-    m_eventsLocker = NULL;
-#endif
-}
-
 #endif // wxUSE_THREADS
 
 void wxEvtHandler::AddPendingEvent(const wxEvent& event)
@@ -1129,14 +1166,14 @@ 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.
@@ -1157,7 +1194,7 @@ void wxEvtHandler::AddPendingEvent(const wxEvent& event)
 
 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
@@ -1177,7 +1214,7 @@ void wxEvtHandler::ProcessPendingEvents()
     if ( m_pendingEvents->IsEmpty() )
         wxPendingEvents->DeleteObject(this);
 
-    wxLEAVE_CRIT_SECT( Lock() );
+    wxLEAVE_CRIT_SECT( m_pendingEventsLock );
 
     ProcessEvent(*event);
 
@@ -1364,6 +1401,16 @@ void wxEvtHandler::Connect( int id, int lastId,
 
     // 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,
@@ -1374,6 +1421,14 @@ 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)
     {
@@ -1464,6 +1519,47 @@ void *wxEvtHandler::DoGetClientData() const
     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