]> git.saurik.com Git - wxWidgets.git/commitdiff
Last part from weak ref patch for event sink disconnection
authorRobert Roebling <robert@roebling.de>
Tue, 8 Jan 2008 17:57:27 +0000 (17:57 +0000)
committerRobert Roebling <robert@roebling.de>
Tue, 8 Jan 2008 17:57:27 +0000 (17:57 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@51111 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/event.h
include/wx/tracker.h
src/common/event.cpp

index 60d4978b746f62c03b9b464cebf2e944e57383df..7b41f1ff387f499c51be84cb73761c4817fb0972 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "wx/dynarray.h"
 #include "wx/thread.h"
+#include "wx/tracker.h"
 
 // ----------------------------------------------------------------------------
 // forward declarations
@@ -2255,11 +2256,44 @@ protected:
     DECLARE_NO_COPY_CLASS(wxEventHashTable)
 };
 
+// ----------------------------------------------------------------------------
+// wxEventConnectionRef: A class that represents all connections between two event 
+// handlers and enables automatic disconnect when an event handler sink goes 
+// out of scope. Each connection/disconnect increases/decreases ref count, and
+// when zero the node goes out of scope. 
+// ----------------------------------------------------------------------------
+
+struct wxEventConnectionRef : public wxTrackerNode {
+
+    wxEventConnectionRef() : m_src(0), m_sink(0), m_refCount(0) { }
+    wxEventConnectionRef( wxEvtHandler *src, wxEvtHandler *sink );
+    virtual ~wxEventConnectionRef();
+        
+    // The sink is being destroyed 
+    virtual void OnObjectDestroy( );
+    virtual wxTrackerNodeType GetType( ){ return EventConnectionRef; } 
+    
+    void IncRef( ) { m_refCount++; }
+    void DecRef( );
+
+protected:   
+    wxEvtHandler *m_src, *m_sink;
+    int m_refCount;
+    
+    friend class wxEvtHandler;
+    
+private:
+    // It makes no sense to copy objects of this class 
+    wxEventConnectionRef& operator = (const wxEventConnectionRef& WXUNUSED(other)) { wxASSERT(0); return *this; } 
+};
+
+
+
 // ----------------------------------------------------------------------------
 // wxEvtHandler: the base class for all objects handling wxWidgets events
 // ----------------------------------------------------------------------------
 
-class WXDLLIMPEXP_BASE wxEvtHandler : public wxObject
+class WXDLLIMPEXP_BASE wxEvtHandler : public wxObject, public wxTrackableBase
 {
 public:
     wxEvtHandler();
@@ -2359,6 +2393,7 @@ public:
 
     // Avoid problems at exit by cleaning up static hash table gracefully
     void ClearEventHashTable() { GetEventHashTable().Clear(); }
+    void OnSinkDestroyed( wxEvtHandler *sink );
 
 private:
     static const wxEventTableEntry sm_eventTableEntries[];
@@ -2425,6 +2460,9 @@ protected:
     virtual void DoSetClientData( void *data );
     virtual void *DoGetClientData() const;
 
+    // Search tracker objects for event connection with this sink
+    wxEventConnectionRef *FindRefInTrackerList( wxEvtHandler *eventSink );
+
 private:
     DECLARE_DYNAMIC_CLASS_NO_COPY(wxEvtHandler)
 };
index 4f4ec195a73beb9aeb575827922ec99d82fb531b..ef1ab843888f172e3396979a57701660a8898a74 100644 (file)
@@ -73,7 +73,7 @@ struct wxTrackableBase {
     wxTrackerNode* GetFirst( ){ return m_first; }
 
     // If trying to copy this object, then do not copy its ref list.
-    wxTrackableBase& operator = (const wxTrackableBase& other) { return *this; }
+    wxTrackableBase& operator = (const wxTrackableBase& WXUNUSED(other)) { return *this; }
     
 protected:    
     wxTrackerNode *m_first;
index dc121dee420abdf6048d516c75438140bda7b39b..46efb4f7e57ce5b9ad2813fdae6f37b7c8b2d22f 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
 // ----------------------------------------------------------------------------
@@ -1052,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;
@@ -1347,6 +1397,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,
@@ -1357,6 +1417,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)
     {
@@ -1447,6 +1515,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