From cc6ceca789f584cf3fc3fc17f6da4b7493ca69bd Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Sun, 13 Jan 2008 01:12:13 +0000
Subject: [PATCH] improvements to wxWeakRef and related classes

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@51187 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/classes.tex        |   1 +
 docs/latex/wx/trackable.tex      |  16 +-
 docs/latex/wx/weakref.tex        |  29 ++-
 docs/latex/wx/weakrefdynamic.tex |  20 ++
 include/wx/defs.h                |  15 ++
 include/wx/event.h               |  87 +++++----
 include/wx/tracker.h             | 140 ++++---------
 include/wx/weakref.h             | 324 +++++++++++++++++++++++++------
 src/common/event.cpp             | 116 ++++-------
 tests/test.bkl                   |   2 +
 tests/weakref/evtconnection.cpp  | 247 +++++++++++++++++++++++
 tests/weakref/weakref.cpp        | 281 +++++++++++++++++++++++++++
 12 files changed, 976 insertions(+), 302 deletions(-)
 create mode 100644 docs/latex/wx/weakrefdynamic.tex
 create mode 100644 tests/weakref/evtconnection.cpp
 create mode 100644 tests/weakref/weakref.cpp

diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex
index e270a4397b..11c7f6d8cd 100644
--- a/docs/latex/wx/classes.tex
+++ b/docs/latex/wx/classes.tex
@@ -467,6 +467,7 @@
 \input windowdc.tex
 \input destroyevt.tex
 \input weakref.tex
+\input weakrefdynamic.tex
 \input wnddisbl.tex
 \input wizard.tex
 \input wizevt.tex
diff --git a/docs/latex/wx/trackable.tex b/docs/latex/wx/trackable.tex
index 274a1e8002..a78f1a65cc 100644
--- a/docs/latex/wx/trackable.tex
+++ b/docs/latex/wx/trackable.tex
@@ -1,5 +1,4 @@
-
-\section{\class{wxTrackableBase}}\label{wxtrackablebase}
+\section{\class{wxTrackable}}\label{wxtrackable}
 
 Add-on base class for a trackable object. This class maintains
 an internal linked list of classes of type wxTrackerNode and
@@ -10,7 +9,7 @@ API. Its only use is by deriving another class from it to
 make it trackable.
 
 \begin{verbatim}
-class MyClass: public Foo, public TrackableBase
+class MyClass: public Foo, public wxTrackable
 {
    // whatever
 }
@@ -31,18 +30,7 @@ No base class
 
 \section{\class{wxTrackable}}\label{wxtrackable}
 
-The only difference to \helpref{wxTrackableBase}{wxtrackablebase} is
-that this class adds a virtual table to enable dynamic\_cast query for
-wxTrackable.
-
-\wxheading{Derived from}
-
-\helpref{wxTrackableBase}{wxtrackablebase}
-
 \wxheading{Include files}
 
 <tracker.h>
 
-\wxheading{Data structures}
-
-
diff --git a/docs/latex/wx/weakref.tex b/docs/latex/wx/weakref.tex
index de989942c5..5464e81f6d 100644
--- a/docs/latex/wx/weakref.tex
+++ b/docs/latex/wx/weakref.tex
@@ -6,11 +6,11 @@ such as \helpref{wxEvtHandler}{wxevthandler}, \helpref{wxWindow}{wxwindow} and
 pointer, but when the object pointed is destroyed, the weak reference is
 automatically reset to a NULL pointer. 
 
-wxWeakref<T> can be used whenever one must keep a pointer to an object 
-that does not directly own, and that may be destroyed before the object 
+wxWeakRef<T> can be used whenever one must keep a pointer to an object 
+that one does not directly own, and that may be destroyed before the object
 holding the reference. 
 
-wxWeakref<T> is a small object and the mechanism behind it is fast 
+wxWeakRef<T> is a small object and the mechanism behind it is fast 
 (\textbf{O(1)}). So the overall cost of using it is small. 
 
 
@@ -31,9 +31,8 @@ wxWeakref<T> is a small object and the mechanism behind it is fast
     wxASSERT( wr==NULL );
 \end{verbatim}
 
-wxWeakref<T> works for any objects that are derived from 
-\helpref{wxTrackableBase}{wxtrackablebase} or \helpref{wxTrackable}{wxtrackable}.
-By default, wxEvtHandler and wxWindow derive from wxTrackableBase. However, 
+wxWeakRef<T> works for any objects that are derived from \helpref{wxTrackable}{wxtrackable}.
+By default, wxEvtHandler and wxWindow derive from wxTrackable. However, 
 wxObject does not, so types like \helpref{wxFont}{wxfont} and 
 \helpref{wxColour}{wxcolour} are not trackable. The example below shows how to
 create a wxObject derived class that is trackable: 
@@ -44,18 +43,11 @@ create a wxObject derived class that is trackable:
     }; 
 \end{verbatim}
 
-\textbf{Note:} Custom trackable objects should derive from wxTrackable 
-if one wants to reference them from a \texttt{wxWeakRef<wxObject>}. The 
-difference between the two base classes is that wxTrackableBase 
-has no virtual member functions (no VTable), and thus cannot be detected
-through \texttt{dynamic\_cast<>}.
-
 \wxheading{Predefined types}
 
 The following types of weak references are predefined: 
 
 \begin{verbatim}
-typedef wxWeakRef<wxObject>      wxObjectRef;
 typedef wxWeakRef<wxEvtHandler>  wxEvtHandlerRef;
 typedef wxWeakRef<wxWindow>      wxWindowRef;
 \end{verbatim}
@@ -134,7 +126,7 @@ method will cause an assert in debug mode.
 
 \membersection{wxWeakRef<T>::operator=}\label{wxweakrefoperatorassign}
 
-\func{T* operator}{operator=}{\param{T* }{pobj}}
+\func{T*}{operator=}{\param{T* }{pobj}}
 
 Releases the currently tracked object and starts tracking {\it pobj}.
 A weak reference may be reset by passing {\it NULL} as {\it pobj}.
@@ -142,12 +134,19 @@ A weak reference may be reset by passing {\it NULL} as {\it pobj}.
 
 \membersection{wxWeakRef<T>::operator =}\label{wxweakrefoperatorassign2}
 
-\func{T* operator}{operator =}{\param{wxWeakRef<T>\& }{wr}}
+\func{T*}{operator =}{\param{wxWeakRef<T>\& }{wr}}
 
 Release currently tracked object and start tracking the same object as
 the wxWeakRef {\it wr}.
 
 
+\membersection{wxWeakRef<T>::Release}\label{wxweakrefrelease}
+
+\func{void}{Release}{\void}
+
+Release currently tracked object and rests object reference.
+
+
 \membersection{wxWeakRef<T>::OnObjectDestroy}\label{wxweakrefonobjectdestroy}
 
 \func{virtual void}{OnObjectDestroy}{\void}
diff --git a/docs/latex/wx/weakrefdynamic.tex b/docs/latex/wx/weakrefdynamic.tex
new file mode 100644
index 0000000000..cc7522fda7
--- /dev/null
+++ b/docs/latex/wx/weakrefdynamic.tex
@@ -0,0 +1,20 @@
+\section{\class{wxWeakRefDynamic<T>}}\label{wxweakrefdynamic}
+
+wxWeakRefDynamic<T> is a template class for weak references that is used in 
+the same way as wxWeakRef<T>. The only difference is that wxWeakRefDynamic 
+defaults to using \texttt{dynamic\_cast<>} for establishing the object 
+reference (while wxWeakRef defaults to \texttt{static\_cast<>}). 
+
+So, wxWeakRef will detect a type mismatch during compile time and will
+have a little better run-time performance. The role of wxWeakRefDynamic
+is to handle objects which derived type one does not know. 
+
+\textbf{Note:} wxWeakRef<T> selects an implementation based on the static type 
+of T. If T does not have wxTrackable statically, it defaults to to a mixed-
+mode operation, where it uses \texttt{dynamic\_cast<>} as the last measure (if 
+available from the compiler and enabled when building wxWidgets). 
+
+For general cases, wxWeakRef<T> is the better choice. 
+
+For API documentation, see: \helpref{wxWeakRef}{wxweakref}
+
diff --git a/include/wx/defs.h b/include/wx/defs.h
index 44704739c5..6acc275f86 100644
--- a/include/wx/defs.h
+++ b/include/wx/defs.h
@@ -444,6 +444,21 @@ typedef short int WXTYPE;
     #endif
 #endif /* HAVE_WOSTREAM */
 
+// ----------------------------------------------------------------------------
+// other C++ features
+// ----------------------------------------------------------------------------
+
+#ifndef HAVE_PARTIAL_SPECIALIZATION
+    // be optimistic by default
+    #define HAVE_PARTIAL_SPECIALIZATION
+#endif
+
+#ifdef __VISUALC__
+    #if __VISUALC__ < 1310
+        #undef HAVE_PARTIAL_SPECIALIZATION
+    #endif
+#endif // __VISUALC__
+
 /*  ---------------------------------------------------------------------------- */
 /*  portable calling conventions macros */
 /*  ---------------------------------------------------------------------------- */
diff --git a/include/wx/event.h b/include/wx/event.h
index 3e5bc79873..55e8cf5f31 100644
--- a/include/wx/event.h
+++ b/include/wx/event.h
@@ -39,6 +39,7 @@ class WXDLLIMPEXP_FWD_BASE wxList;
 #endif // wxUSE_GUI
 
 class WXDLLIMPEXP_FWD_BASE wxEvtHandler;
+class wxEventConnectionRef;
 
 // ----------------------------------------------------------------------------
 // Event types
@@ -2258,44 +2259,11 @@ 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)) { wxFAIL; return *this; } 
-};
-
-
-
 // ----------------------------------------------------------------------------
 // wxEvtHandler: the base class for all objects handling wxWidgets events
 // ----------------------------------------------------------------------------
 
-class WXDLLIMPEXP_BASE wxEvtHandler : public wxObject, public wxTrackableBase
+class WXDLLIMPEXP_BASE wxEvtHandler : public wxObject, public wxTrackable
 {
 public:
     wxEvtHandler();
@@ -2463,12 +2431,61 @@ protected:
     virtual void *DoGetClientData() const;
 
     // Search tracker objects for event connection with this sink
-    wxEventConnectionRef *FindRefInTrackerList( wxEvtHandler *eventSink );
+    wxEventConnectionRef *FindRefInTrackerList(wxEvtHandler *eventSink);
 
 private:
     DECLARE_DYNAMIC_CLASS_NO_COPY(wxEvtHandler)
 };
 
+// ----------------------------------------------------------------------------
+// wxEventConnectionRef 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 it reaches zero the node goes out of scope.
+// ----------------------------------------------------------------------------
+
+class wxEventConnectionRef : public wxTrackerNode
+{
+public:
+    wxEventConnectionRef() : m_src(NULL), m_sink(NULL), m_refCount(0) { }
+    wxEventConnectionRef(wxEvtHandler *src, wxEvtHandler *sink)
+        : m_src(src), m_sink(sink), m_refCount(1)
+    {
+        m_sink->AddNode(this);
+    }
+
+    // The sink is being destroyed
+    virtual void OnObjectDestroy( )
+    {
+        if ( m_src )
+            m_src->OnSinkDestroyed( m_sink );
+        delete this;
+    }
+
+    virtual wxEventConnectionRef *ToEventConnection() { return this; }
+
+    void IncRef() { m_refCount++; }
+    void DecRef()
+    {
+        if ( !--m_refCount )
+        {
+            // The sink holds the only external pointer to this object
+            if ( m_sink )
+                m_sink->RemoveNode(this);
+            delete this;
+        }
+    }
+
+private:
+    wxEvtHandler *m_src,
+                 *m_sink;
+    int m_refCount;
+
+    friend class wxEvtHandler;
+
+    DECLARE_NO_ASSIGN_CLASS(wxEventConnectionRef)
+};
+
 // Post a message to the given eventhandler which will be processed during the
 // next event loop iteration
 inline void wxPostEvent(wxEvtHandler *dest, const wxEvent& event)
diff --git a/include/wx/tracker.h b/include/wx/tracker.h
index ef1ab84388..0ffbc1df99 100644
--- a/include/wx/tracker.h
+++ b/include/wx/tracker.h
@@ -2,7 +2,7 @@
 // Name:        wx/tracker.h
 // Purpose:     Support class for object lifetime tracking (wxWeakRef<T>)
 // Author:      Arne Steinarson
-// Created:     2007-12-28
+// Created:     28 Dec 07
 // RCS-ID:      $Id$
 // Copyright:   (c) 2007 Arne Steinarson
 // Licence:     wxWindows licence
@@ -11,133 +11,73 @@
 #ifndef _WX_TRACKER_H_
 #define _WX_TRACKER_H_
 
+#include "wx/defs.h"
 
-// This structure represents an object tracker and is stored in a linked list
+class wxEventConnectionRef;
+
+// This class represents an object tracker and is stored in a linked list
 // in the tracked object. It is only used in one of its derived forms.
-struct wxTrackerNode {
-    wxTrackerNode( ) : m_nxt(0) { }
+class WXDLLIMPEXP_BASE wxTrackerNode
+{
+public:
+    wxTrackerNode() : m_nxt(NULL) { }
     virtual ~wxTrackerNode() { }
-    
-    virtual void OnObjectDestroy( ) = 0;
-    
-    // This is to tell the difference between different tracker node types. 
-    // It's a replacement of dynamic_cast<> for this class since dynamic_cast 
-    // may be disabled (and we don't have wxDynamicCast since wxTrackerNode 
-    // is not derived wxObject).
-    enum wxTrackerNodeType { WeakRef, EventConnectionRef }; 
-
-    virtual wxTrackerNodeType GetType() = 0;
-    
-protected:
+
+    virtual void OnObjectDestroy() = 0;
+
+    virtual wxEventConnectionRef *ToEventConnection() { return NULL; }
+
+private:
     wxTrackerNode *m_nxt;
-    friend class wxTrackableBase;    // For list access
+
+    friend class wxTrackable;        // For list access
     friend class wxEvtHandler;       // For list access
 };
 
-
 // Add-on base class for a trackable object.
-struct wxTrackableBase {
-    wxTrackableBase() : m_first(0) { }
-    ~wxTrackableBase()
-    { 
+class wxTrackable
+{
+public:
+    wxTrackable() : m_first(NULL) { }
+
+    ~wxTrackable()
+    {
         // Notify all registered refs
-        
-        wxTrackerNode *first;
-        while( m_first )
+        while ( m_first )
         {
-        	first = m_first;
-            first->OnObjectDestroy( );
-            RemoveNode(first);
+            wxTrackerNode * const first = m_first;
+            m_first = first->m_nxt;
+            first->OnObjectDestroy();
         }
     }
-    
-    void AddNode( wxTrackerNode *prn )
+
+    void AddNode(wxTrackerNode *prn)
     {
         prn->m_nxt = m_first;
         m_first = prn;
     }
-    void RemoveNode( wxTrackerNode *prn )
+
+    void RemoveNode(wxTrackerNode *prn)
     {
-        for( wxTrackerNode **pprn=&m_first; *pprn; pprn=&(*pprn)->m_nxt )
+        for ( wxTrackerNode **pprn = &m_first; *pprn; pprn = &(*pprn)->m_nxt )
         {
-            if( *pprn==prn )
+            if ( *pprn == prn )
             {
                 *pprn = prn->m_nxt;
                 return;
             }
         }
-        // Not found, an error.
-        wxASSERT( false );
-    }
-    
-    wxTrackerNode* GetFirst( ){ return m_first; }
 
-    // If trying to copy this object, then do not copy its ref list.
-    wxTrackableBase& operator = (const wxTrackableBase& WXUNUSED(other)) { return *this; }
-    
-protected:    
-    wxTrackerNode *m_first;
-};
+        wxFAIL_MSG( "removing invalid tracker node" );
+    }
 
+    wxTrackerNode *GetFirst() const { return m_first; }
 
-// The difference to wxTrackableBase is that this class adds 
-// a VTable to enable dynamic_cast query for wxTrackable.
-struct wxTrackable : public wxTrackableBase 
-{
-    virtual ~wxTrackable(){ }
-};
-
+protected:
+    wxTrackerNode *m_first;
 
-// Helper to decide if an object has a base class or not
-// (strictly speaking, this test succeeds if a type is convertible
-//  to another type in some way.)
-template<class T, class B>
-struct wxHasBase{
-	static char Match( B* pb );	   
-	static int Match( ... );       
-	enum { value = (sizeof(Match((T*)NULL))==sizeof(char)) };
+    DECLARE_NO_COPY_CLASS(wxTrackable)
 };
 
-// VC++ before 7.1 does not have partial template specialization 
-#ifdef __VISUALC__
-    #if __VISUALC__ < 1310
-        #define HAVE_NO_PARTIAL_SPECIALIZATION
-    #endif
-#endif 
-
-#if defined(HAVE_DYNAMIC_CAST) && !defined(HAVE_NO_PARTIAL_SPECIALIZATION) 
-    // A structure to cast to wxTrackableBase, using either static_cast<> or dynamic_cast<>. 
-    template<class T,bool is_static>
-    struct wxTrackableCaster;
-
-    template <class T>
-    struct wxTrackableCaster<T,true> {
-        static wxTrackableBase* Cast(T* pt){ return static_cast<wxTrackableBase*>(pt); }
-    };
-
-    template <class T>
-    struct wxTrackableCaster<T,false> {
-        static wxTrackableBase* Cast(T* pt){ return dynamic_cast<wxTrackableBase*>(pt); }
-    };
-#else 
-    #if defined(HAVE_DYNAMIC_CAST) 
-        // If we have dynamic_cast, default to that. For gcc, dynamic_cast<> does the job 
-        // of both the dynamic and the static case. It could be that all compilers do it 
-        // that way, rendering the specialization code above rednundant.
-        template <class T,bool is_static>
-        struct wxTrackableCaster {
-            static wxTrackableBase* Cast(T* pt){ return dynamic_cast<wxTrackableBase*>(pt); }
-        };
-    #else
-        // No dynamic_cast<> is available.
-        // We use static_cast<>, that gives support for wxEvtHandler and wxWindow references. 
-        // We don't get weak refs to other wxObject derived types.
-        template <class T,bool is_static>
-        struct wxTrackableCaster {
-            static wxTrackableBase* Cast(T* pt){ return static_cast<wxTrackableBase*>(pt); }
-        };
-    #endif
-#endif 
-
 #endif // _WX_TRACKER_H_
 
diff --git a/include/wx/weakref.h b/include/wx/weakref.h
index 3d4c445774..99621fca49 100644
--- a/include/wx/weakref.h
+++ b/include/wx/weakref.h
@@ -2,7 +2,7 @@
 // Name:        wx/weakref.h
 // Purpose:     wxWeakRef - Generic weak references for wxWidgets
 // Author:      Arne Steinarson
-// Created:     2007-12-27
+// Created:     27 Dec 07
 // RCS-ID:      $Id$
 // Copyright:   (c) 2007 Arne Steinarson
 // Licence:     wxWindows licence
@@ -11,114 +11,314 @@
 #ifndef _WX_WEAKREF_H_
 #define _WX_WEAKREF_H_
 
-#include <wx/tracker.h>
+#include "wx/tracker.h"
 
-// A weak reference to an object of type T, where T has type wxTrackable
-// as one of its base classes (in a static or dynamic sense).
+#include "wx/meta/convertible.h"
+#include "wx/meta/int2type.h"
+
+template <class T>
+struct wxIsStaticTrackable
+{
+    enum { value = wxConvertibleTo<T, wxTrackable>::value };
+};
+
+// Weak ref implementation when T has wxTrackable as a known base class
+template <class T>
+class wxWeakRefStatic : public wxTrackerNode
+{
+public:
+    wxWeakRefStatic() : m_pobj(NULL) { }
+
+    void Release()
+    {
+        // Release old object if any
+        if ( m_pobj )
+        {
+            // Remove ourselves from object tracker list
+            wxTrackable *pt = static_cast<wxTrackable*>(m_pobj);
+            pt->RemoveNode(this);
+            m_pobj = NULL;
+        }
+    }
+
+protected:
+    void Assign(T* pobj)
+    {
+        if ( m_pobj == pobj )
+            return;
+
+        Release();
+
+        // Now set new trackable object
+        if ( pobj )
+        {
+            // Add ourselves to object tracker list
+            wxTrackable *pt = static_cast<wxTrackable*>(pobj);
+            pt->AddNode(this);
+            m_pobj = pobj;
+        }
+    }
+
+    void AssignCopy( const wxWeakRefStatic& wr )
+    {
+        Assign( wr.m_pobj );
+    }
+
+    virtual void OnObjectDestroy()
+    {
+        // Tracked object itself removes us from list of trackers
+        wxASSERT( m_pobj!=NULL );
+        m_pobj = NULL;
+    }
+
+    T *m_pobj;
+};
+
+#ifdef HAVE_PARTIAL_SPECIALIZATION
+
+template<class T,bool use_static>
+struct wxWeakRefImpl;
+
+// Intermediate class, to select the static case above.
+template <class T>
+struct wxWeakRefImpl<T, true> : public wxWeakRefStatic<T>
+{
+    enum { value = 1 };
+};
+
+// Weak ref implementation when T does not have wxTrackable as known base class
 template<class T>
-class wxWeakRef : public wxTrackerNode
+struct wxWeakRefImpl<T, false> : public wxTrackerNode
+{
+    void Release()
+    {
+        // Release old object if any
+        if ( m_pobj )
+        {
+            // Remove ourselves from object tracker list
+            m_ptbase->RemoveNode(this);
+            m_pobj = NULL;
+            m_ptbase = NULL;
+        }
+    }
+
+protected:
+    wxWeakRefImpl() : m_pobj(NULL), m_ptbase(NULL) { }
+
+    // Assign receives most derived class here and can use that
+    template <class TDerived>
+    void Assign( TDerived* pobj )
+    {
+        AssignHelper( pobj, wxInt2Type<wxIsStaticTrackable<TDerived>::value>() );
+    }
+
+    template <class TDerived>
+    void AssignHelper(TDerived* pobj, wxInt2Type<true>)
+    {
+        wxTrackable *ptbase = static_cast<wxTrackable*>(pobj);
+        DoAssign( pobj, ptbase );
+    }
+
+#ifdef HAVE_DYNAMIC_CAST
+    void AssignHelper(T* pobj, wxInt2Type<false>)
+    {
+        // A last way to get a trackable pointer
+        wxTrackable *ptbase = dynamic_cast<wxTrackable*>(pobj);
+        if ( ptbase )
+        {
+            DoAssign( pobj, ptbase );
+        }
+        else
+        {
+            wxFAIL_MSG( "Tracked class should inherit from wxTrackable" );
+
+            Release();
+        }
+    }
+#endif // HAVE_DYNAMIC_CAST
+
+    void AssignCopy(const wxWeakRefImpl& wr)
+    {
+        DoAssign( wr.m_pobj, wr.m_ptbase );
+    }
+
+    void DoAssign( T* pobj, wxTrackable *ptbase ) {
+        if( m_pobj==pobj ) return;
+        Release();
+
+        // Now set new trackable object
+        if( pobj )
+        {
+            // Add ourselves to object tracker list
+            wxASSERT( ptbase );
+            ptbase->AddNode( this );
+            m_pobj = pobj;
+            m_ptbase = ptbase;
+        }
+    }
+
+    virtual void OnObjectDestroy()
+    {
+        // Tracked object itself removes us from list of trackers
+        wxASSERT( m_pobj!=NULL );
+        m_pobj = NULL;
+        m_ptbase = NULL;
+    }
+
+    T *m_pobj;
+    wxTrackable *m_ptbase;
+};
+
+#endif // HAVE_PARTIAL_SPECIALIZATION
+
+
+// A weak reference to an object of type T, where T has type wxTrackable
+// (usually statically but if not dynamic_cast<> is tried).
+template <class T>
+class wxWeakRef : public
+#ifdef HAVE_PARTIAL_SPECIALIZATION
+                  wxWeakRefImpl<T, wxIsStaticTrackable<T>::value>
+#else
+                  wxWeakRefStatic<T>
+#endif
 {
 public:
-    typedef T element_type;
-    
-    wxWeakRef(T *pobj = NULL) : m_pobj(NULL) { Assign(pobj); }
+    // Default ctor
+    wxWeakRef() { }
+
+    // When we have the full type here, static_cast<> will always work
+    // (or give a straight compiler error).
+    template <class TDerived>
+    wxWeakRef(TDerived* pobj)
+    {
+        Assign(pobj);
+    }
+
+    template <class TDerived>
+    wxWeakRef<T>& operator=(TDerived* pobj)
+    {
+        Assign(pobj);
+        return *this;
+    }
+
+    wxWeakRef<T>& operator=(const wxWeakRef<T>& wr)
+    {
+        AssignCopy(wr);
+        return *this;
+    }
 
-    virtual ~wxWeakRef() { Assign(NULL); }
+    virtual ~wxWeakRef() { Release(); }
+
+    // Smart pointer functions
+    T& operator*() const { return *m_pobj; }
+    T* operator->() const { return m_pobj; }
+
+    T* get() const { return m_pobj; }
 
     // test for pointer validity: defining conversion to unspecified_bool_type
     // and not more obvious bool to avoid implicit conversions to integer types
     typedef T *(wxWeakRef<T>::*unspecified_bool_type)() const;
     operator unspecified_bool_type() const
     {
-        return m_pobj ? &wxWeakRef<T>::get : NULL;
+        return this->m_pobj ? &wxWeakRef<T>::get : NULL;
     }
+};
+
+
+// Weak ref implementation assign objects are queried for wxTrackable
+// using dynamic_cast<>
+template<class T>
+class wxWeakRefDynamic : public wxTrackerNode
+{
+public:
+    wxWeakRefDynamic() : m_pobj(NULL) { }
 
-    T * get() const                 
-    {                               
-        return m_pobj;
-    }                               
-    
-    T* operator->()
-    { 
-        wxASSERT(m_pobj != NULL);    
-        return m_pobj; 
-    }
-    
-    T& operator*() const           
-    {                               
-        wxASSERT(m_pobj != NULL);    
-        return *m_pobj;              
-    }                               
-                                    
-    T* operator=(T *pobj)
+    wxWeakRefDynamic(T* pobj) : m_pobj(pobj)
     {
         Assign(pobj);
-        return m_pobj;
     }
 
-    // Assign from another weak ref, point to same object
-    T* operator = (const wxWeakRef<T> &wr)
-    { 
-        Assign(wr); 
-        return m_pobj; 
-    }
-    
-    virtual void OnObjectDestroy()
+    virtual ~wxWeakRefDynamic() { Release(); }
+
+    // Smart pointer functions
+    T& operator * (){ wxASSERT(this->m_pobj); return *m_pobj; }
+    T* operator -> (){ wxASSERT(this->m_pobj); return m_pobj; }
+    T* operator = (T* pobj) { Assign(pobj); return m_pobj; }
+
+    T* get(){ return this->m_pobj; }
+
+    // operator T* (){ return this->m_pobj; }
+
+    // test for pointer validity: defining conversion to unspecified_bool_type
+    // and not more obvious bool to avoid implicit conversions to integer types
+    typedef T *(wxWeakRef<T>::*unspecified_bool_type)() const;
+    operator unspecified_bool_type() const
     {
-        // Tracked object itself removes us from list of trackers
-        wxASSERT( m_pobj );
-        m_pobj = NULL;
+        return m_pobj ? &wxWeakRef<T>::get : NULL;
     }
 
-protected:
-    friend class wxTrackableBase; 
-    friend class wxEvtHandler;
+    // Assign from another weak ref, point to same object
+    T* operator = (const wxWeakRef<T> &wr) { Assign( wr.get() ); return this->m_pobj; }
 
-    virtual wxTrackerNodeType GetType() { return WeakRef; }
-    
-    void Assign(T* pobj)
+    void Release()
     {
-        if ( m_pobj == pobj )
-            return;
-
-        // First release old object if any
-        if ( m_pobj )
+        // Release old object if any
+        if( m_pobj )
         {
             // Remove ourselves from object tracker list
-            // This does static_cast if available, otherwise it tries dynamic cast
-            wxTrackableBase *pt = wxTrackableCaster<T,wxHasBase<T,wxTrackableBase>::value >::Cast(m_pobj);
+            wxTrackable *pt = dynamic_cast<wxTrackable*>(m_pobj);
             wxASSERT(pt);
             pt->RemoveNode(this);
             m_pobj = NULL;
         }
+    }
+
+protected:
+    void Assign(T *pobj)
+    {
+        if ( m_pobj == pobj )
+            return;
+
+        Release();
 
         // Now set new trackable object
         if ( pobj )
         {
-            wxTrackableBase *pt = wxTrackableCaster<T,wxHasBase<T,wxTrackableBase>::value >::Cast(pobj);
-            if( pt )
+            // Add ourselves to object tracker list
+            wxTrackable *pt = dynamic_cast<wxTrackable*>(pobj);
+            if ( pt )
             {
-                pt->AddNode( this );
+                pt->AddNode(this);
                 m_pobj = pobj;
             }
             else
             {
-                // If the tracked we want to track does not support wxTackableBase, then 
-                // log a message and keep the NULL object pointer. 
-                wxLogWarning( _T("wxWeakRef::Assign - Type does not provide wxTrackableBase - resetting tracked object") );
+                // If the object we want to track does not support wxTackable, then
+                // log a message and keep the NULL object pointer.
+                wxFAIL_MSG( "Tracked class should inherit from wxTrackable" );
             }
         }
     }
 
+    void AssignCopy(const wxWeakRefDynamic& wr)
+    {
+        Assign(wr.m_pobj);
+    }
+
+    virtual void OnObjectDestroy()
+    {
+        wxASSERT_MSG( m_pobj, "tracked object should have removed us itself" );
+
+        m_pobj = NULL;
+    }
+
     T *m_pobj;
 };
 
 // Provide some basic types of weak references
-class WXDLLIMPEXP_FWD_BASE wxObject;
 class WXDLLIMPEXP_FWD_BASE wxEvtHandler;
-class WXDLLIMPEXP_FWD_CORE wxWindow;
+class WXDLLIMPEXP_FWD_BASE wxWindow;
 
-typedef wxWeakRef<wxObject>      wxObjectRef;
 typedef wxWeakRef<wxEvtHandler>  wxEvtHandlerRef;
 typedef wxWeakRef<wxWindow>      wxWindowRef;
 
diff --git a/src/common/event.cpp b/src/common/event.cpp
index 4ca845660e..a03b9fe1b9 100644
--- a/src/common/event.cpp
+++ b/src/common/event.cpp
@@ -406,13 +406,15 @@ wxCommandEvent::wxCommandEvent(wxEventType commandType, int theId)
 
 wxString wxCommandEvent::GetString() const
 {
-    if(m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject)
+    if (m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject)
+    {
         return m_cmdString;
+    }
     else
     {
 #if wxUSE_TEXTCTRL
         wxTextCtrl *txt = wxDynamicCast(m_eventObject, wxTextCtrl);
-        if(txt)
+        if ( txt )
             return txt->GetValue();
         else
 #endif // wxUSE_TEXTCTRL
@@ -1012,44 +1014,6 @@ void wxEventHashTable::GrowEventTypeTable()
     delete[] oldEventTypeTable;
 }
 
-
-// ----------------------------------------------------------------------------
-// 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
 // ----------------------------------------------------------------------------
@@ -1089,19 +1053,20 @@ wxEvtHandler::~wxEvtHandler()
         {
             wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it;
 
-            // Remove ourselves from sink destructor notifications 
+            // Remove ourselves from sink destructor notifications
             // (this has usually been been done, in wxTrackable destructor)
             wxEvtHandler *eventSink = entry->m_eventSink;
-            if( eventSink )
+            if ( eventSink )
             {
-	            wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink );
-	            if( pecr )
-	            {
-	                eventSink->RemoveNode( pecr );
-	                delete pecr;
-	            }
+                wxEventConnectionRef * const
+                    evtConnRef = FindRefInTrackerList(eventSink);
+                if ( evtConnRef )
+                {
+                    eventSink->RemoveNode(evtConnRef);
+                    delete evtConnRef;
+                }
             }
-            
+
             if (entry->m_callbackUserData)
                 delete entry->m_callbackUserData;
             delete entry;
@@ -1117,7 +1082,7 @@ wxEvtHandler::~wxEvtHandler()
     if ( wxPendingEvents )
     {
 #if wxUSE_THREADS
-        if(wxPendingEventsLocker)
+        if (wxPendingEventsLocker)
             wxENTER_CRIT_SECT(*wxPendingEventsLocker);
 #endif
 
@@ -1130,7 +1095,7 @@ wxEvtHandler::~wxEvtHandler()
         //else: we weren't in this list at all, it's ok
 
 #if wxUSE_THREADS
-        if(wxPendingEventsLocker)
+        if (wxPendingEventsLocker)
             wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
 #endif
     }
@@ -1401,15 +1366,15 @@ 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 )
+
+    // Make sure we get to know when a sink is destroyed
+    if ( eventSink )
     {
-        wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink );
-        if( pecr )
-            pecr->IncRef( );
+        wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
+        if ( evtConnRef )
+            evtConnRef->IncRef( );
         else
-            pecr = new wxEventConnectionRef(this,eventSink);
+            evtConnRef = new wxEventConnectionRef(this, eventSink);
     }
 }
 
@@ -1422,11 +1387,11 @@ bool wxEvtHandler::Disconnect( int id, int lastId, wxEventType eventType,
         return false;
 
     // Remove connection from tracker node (wxEventConnectionRef)
-    if( eventSink )
+    if ( eventSink )
     {
-        wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink );
-        if( pecr )
-            pecr->DecRef( );
+        wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
+        if ( evtConnRef )
+            evtConnRef->DecRef();
     }
 
     wxList::compatibility_iterator node = m_dynamicEvents->GetFirst();
@@ -1519,37 +1484,36 @@ void *wxEvtHandler::DoGetClientData() const
     return m_clientData;
 }
 
-// A helper func to find an wxEventConnectionRef object 
-wxEventConnectionRef* wxEvtHandler::FindRefInTrackerList( wxEvtHandler *eventSink )
+// A helper to find an wxEventConnectionRef object
+wxEventConnectionRef *
+wxEvtHandler::FindRefInTrackerList(wxEvtHandler *eventSink)
 {
-    wxASSERT(eventSink);
-    for( wxTrackerNode *ptn=eventSink->GetFirst(); ptn; ptn=ptn->m_nxt )
+    for ( wxTrackerNode *node = eventSink->GetFirst(); node; node = node->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 )
+        // we only want wxEventConnectionRef nodes here
+        wxEventConnectionRef *evtConnRef = node->ToEventConnection();
+        if ( evtConnRef && evtConnRef->m_src == this )
         {
-            wxASSERT( pecr->m_sink==eventSink );
-            return pecr;
+            wxASSERT( evtConnRef->m_sink==eventSink );
+            return evtConnRef;
         }
     }
+
     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_eventSink==sink )
         {
             if (entry->m_callbackUserData)
                 delete entry->m_callbackUserData;
diff --git a/tests/test.bkl b/tests/test.bkl
index 7718e6c2e0..68132e086d 100644
--- a/tests/test.bkl
+++ b/tests/test.bkl
@@ -70,6 +70,8 @@
             thread/queue.cpp
             uris/uris.cpp
             vectors/vectors.cpp
+            weakref/evtconnection.cpp
+            weakref/weakref.cpp
         </sources>
         <wx-lib>net</wx-lib>
         <wx-lib>base</wx-lib>
diff --git a/tests/weakref/evtconnection.cpp b/tests/weakref/evtconnection.cpp
new file mode 100644
index 0000000000..3d9db0421b
--- /dev/null
+++ b/tests/weakref/evtconnection.cpp
@@ -0,0 +1,247 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        tests/weakref/evtconnection.cpp
+// Purpose:     wxWeakRef<T> unit test
+// Author:      Arne Steinarson
+// Created:     2008-01-10
+// RCS-ID:      $Id$
+// Copyright:   (c) 2007 Arne Steinarson
+///////////////////////////////////////////////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "testprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+    #include "wx/wx.h"
+#endif // WX_PRECOMP
+
+#include "wx/event.h"
+#include "wx/weakref.h"
+
+static int gs_value = 0; // Increased by 1 by first object and 0x10000 by 2nd object
+
+static wxObject *gs_psrc1;
+static wxObject *gs_psrc2;
+
+// We need some event types
+const wxEventType wxEVT_TEST = wxNewEventType(),
+                  wxEVT_TEST1 = wxNewEventType(),
+                  wxEVT_TEST2 = wxNewEventType();
+
+class wxTestEvent : public wxEvent
+{
+public:
+    wxTestEvent(wxEventType type = wxEVT_TEST) : wxEvent(0, type) { }
+    virtual wxEvent *Clone() const { return new wxTestEvent(GetEventType()); }
+};
+
+class wxTestSink : public wxEvtHandler
+{
+public:
+    void OnTestEvent(wxEvent& evt)
+    {
+        if ( evt.GetEventObject() == gs_psrc1 )
+            gs_value += 1;
+        else if ( evt.GetEventObject() == gs_psrc2 )
+            gs_value += 0x10000;
+    }
+
+    void OnTestEvent1(wxEvent& )
+    {
+        gs_value += 0x00100;
+    }
+
+    void OnTestEvent2(wxEvent&)
+    {
+        gs_value += 0x01000000;
+    }
+};
+
+
+
+// --------------------------------------------------------------------------
+// test class
+// --------------------------------------------------------------------------
+
+class EvtConnectionTestCase : public CppUnit::TestCase
+{
+public:
+    EvtConnectionTestCase() {}
+
+private:
+    CPPUNIT_TEST_SUITE( EvtConnectionTestCase );
+        CPPUNIT_TEST( SinkTest );
+        CPPUNIT_TEST( SourceDestroyTest );
+        CPPUNIT_TEST( MultiConnectionTest );
+    CPPUNIT_TEST_SUITE_END();
+
+    void SinkTest();
+    void SourceDestroyTest();
+    void MultiConnectionTest();
+
+    DECLARE_NO_COPY_CLASS(EvtConnectionTestCase)
+};
+
+// register in the unnamed registry so that these tests are run by default
+CPPUNIT_TEST_SUITE_REGISTRATION( EvtConnectionTestCase );
+
+// also include in it's own registry so that these tests can be run alone
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtConnectionTestCase, "EvtConnectionTestCase" );
+
+
+// Helpers
+void DoConnect( wxEvtHandler& eh1, wxEvtHandler& eh2, wxTestSink& ts ){
+    eh1.Connect(wxEVT_TEST, (wxObjectEventFunction)&wxTestSink::OnTestEvent,
+                NULL, &ts);
+    eh2.Connect(wxEVT_TEST, (wxObjectEventFunction) &wxTestSink::OnTestEvent,
+                NULL, &ts);
+}
+
+void DoDisconnect( wxEvtHandler& eh1, wxEvtHandler& eh2, wxTestSink& ts ){
+    eh1.Disconnect(wxEVT_TEST, (wxObjectEventFunction) &wxTestSink::OnTestEvent,
+                NULL, &ts);
+    eh2.Disconnect(wxEVT_TEST, (wxObjectEventFunction) &wxTestSink::OnTestEvent,
+                NULL, &ts);
+}
+
+
+void EvtConnectionTestCase::SinkTest()
+{
+    // Let the sink be destroyed before the sources
+
+    // An event used below
+    wxTestEvent evt;
+
+    // Connect two event handlers to one sink
+    wxEvtHandler eh1, eh2;
+    gs_psrc1 = &eh1;
+    gs_psrc2 = &eh2;
+
+    {
+        wxTestSink ts;
+        CPPUNIT_ASSERT( !ts.GetFirst() );
+        DoConnect(eh1, eh2, ts);
+
+        DoDisconnect(eh1, eh2, ts);
+
+        DoConnect(eh1, eh2, ts);
+
+        // Fire events
+        evt.SetEventObject(&eh1);
+        eh1.ProcessEvent(evt);
+        evt.SetEventObject(&eh2);
+        eh2.ProcessEvent(evt);
+
+        // Make sure they were processed correctly
+        CPPUNIT_ASSERT_EQUAL( 0x00010001, gs_value );
+    }
+
+    // Fire events again, should be no sink connected now
+    gs_value = 0;
+    evt.SetEventObject(&eh1);
+    eh1.ProcessEvent( evt );
+    evt.SetEventObject(&eh2);
+    eh2.ProcessEvent( evt );
+
+    // Make sure no processing happened
+    CPPUNIT_ASSERT_EQUAL( 0, gs_value );
+}
+
+void EvtConnectionTestCase::SourceDestroyTest()
+{
+    // Let the sources be destroyed before the sink
+    wxTestSink ts;
+    wxTestEvent evt;
+    {
+        wxEvtHandler eh1;
+        {
+            CPPUNIT_ASSERT( !ts.GetFirst() );
+
+            // Connect two event handlers to one sink
+            wxEvtHandler eh2;
+            gs_psrc1 = &eh1;
+            gs_psrc2 = &eh2;
+            DoConnect( eh1, eh2, ts );
+
+            // Fire events
+            gs_value = 0;
+            evt.SetEventObject(&eh1);
+            eh1.ProcessEvent( evt );
+            evt.SetEventObject(&eh2);
+            eh2.ProcessEvent( evt );
+
+            // Make sure they were processed correctly
+            CPPUNIT_ASSERT_EQUAL( 0x00010001, gs_value );
+        }
+
+        gs_value = 0;
+        evt.SetEventObject(&eh1);
+        eh1.ProcessEvent( evt );
+
+        // Make sure still connected
+        CPPUNIT_ASSERT_EQUAL( 0x00000001, gs_value );
+    }
+    CPPUNIT_ASSERT( !ts.GetFirst() );
+}
+
+void EvtConnectionTestCase::MultiConnectionTest()
+{
+    // events used below
+    wxTestEvent evt;
+    wxTestEvent evt1(wxEVT_TEST1);
+    wxTestEvent evt2(wxEVT_TEST2);
+
+    // One source
+    wxEvtHandler eh1;
+    evt.SetEventObject(&eh1);
+    gs_psrc1 = NULL;
+    gs_psrc2 = &eh1;
+
+    {
+        // ...and one sink
+        wxTestSink ts;
+
+        eh1.Connect(wxEVT_TEST, (wxObjectEventFunction)&wxTestSink::OnTestEvent,
+                    NULL, &ts);
+        eh1.Connect(wxEVT_TEST1, (wxObjectEventFunction)&wxTestSink::OnTestEvent1,
+                    NULL, &ts);
+        eh1.Connect(wxEVT_TEST2, (wxObjectEventFunction)&wxTestSink::OnTestEvent2,
+                    NULL, &ts);
+
+        // Generate events
+        gs_value = 0;
+        eh1.ProcessEvent(evt);
+        eh1.ProcessEvent(evt1);
+        eh1.ProcessEvent(evt2);
+        CPPUNIT_ASSERT( gs_value==0x01010100 );
+
+        {
+            // Declare weak references to the objects (using same list)
+            wxEvtHandlerRef re(&eh1), rs(&ts);
+        }
+        // And now destroyed
+
+        eh1.Disconnect(wxEVT_TEST, (wxObjectEventFunction)&wxTestSink::OnTestEvent,
+                       NULL, &ts);
+        eh1.ProcessEvent(evt);
+        eh1.ProcessEvent(evt1);
+        eh1.ProcessEvent(evt2);
+        CPPUNIT_ASSERT_EQUAL( 0x02010200, gs_value );
+    }
+
+    // No connection should be left now
+    gs_value = 0;
+    eh1.ProcessEvent(evt);
+    eh1.ProcessEvent(evt1);
+    eh1.ProcessEvent(evt2);
+
+    // Nothing should have been done
+    CPPUNIT_ASSERT_EQUAL( 0, gs_value );
+}
+
diff --git a/tests/weakref/weakref.cpp b/tests/weakref/weakref.cpp
new file mode 100644
index 0000000000..f2a9c79d04
--- /dev/null
+++ b/tests/weakref/weakref.cpp
@@ -0,0 +1,281 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        tests/weakref/weakref.cpp
+// Purpose:     wxWeakRef<T> unit test
+// Author:      Arne Steinarson
+// Created:     2008-01-10
+// RCS-ID:      $Id$
+// Copyright:   (c) 2007 Arne Steinarson
+///////////////////////////////////////////////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "testprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+    #include "wx/wx.h"
+#endif // WX_PRECOMP
+
+#include "wx/event.h"
+#include "wx/weakref.h"
+
+// A statically trackable derived wxObject
+class wxObjectTrackable : public wxObject, public wxTrackable
+{
+public:
+    // Test member access
+    void TestFunc(){ }
+
+    // Make sure this does not clash with wxTrackableBase method
+    int GetFirst() { return 0; }
+};
+
+// --------------------------------------------------------------------------
+// test class
+// --------------------------------------------------------------------------
+
+class WeakRefTestCase : public CppUnit::TestCase
+{
+public:
+    WeakRefTestCase() {}
+
+private:
+    CPPUNIT_TEST_SUITE( WeakRefTestCase );
+        CPPUNIT_TEST( DeclareTest );
+        CPPUNIT_TEST( AssignTest );
+        CPPUNIT_TEST( AssignWeakRefTest );
+        CPPUNIT_TEST( MultiAssignTest );
+        CPPUNIT_TEST( CleanupTest );
+        CPPUNIT_TEST( DeleteTest );
+#ifdef HAVE_DYNAMIC_CAST
+        CPPUNIT_TEST( DynamicRefTest );
+#endif
+    CPPUNIT_TEST_SUITE_END();
+
+    void DeclareTest();
+    void AssignTest();
+    void AssignWeakRefTest();
+    void MultiAssignTest();
+    void CleanupTest();
+    void DeleteTest();
+#ifdef HAVE_DYNAMIC_CAST
+    void DynamicRefTest();
+#endif
+
+    DECLARE_NO_COPY_CLASS(WeakRefTestCase)
+};
+
+// register in the unnamed registry so that these tests are run by default
+CPPUNIT_TEST_SUITE_REGISTRATION( WeakRefTestCase );
+
+// also include in it's own registry so that these tests can be run alone
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( WeakRefTestCase, "WeakRefTestCase" );
+
+void WeakRefTestCase::DeclareTest()
+{
+    {
+        wxObject o; // Should not work
+        wxEvtHandler eh;
+        wxObjectTrackable ot;
+
+        // Test declare when T is wxObject
+        // wxWeakRef<wxObject> wro1(&o);    // Gives compile time failure
+        wxWeakRef<wxEvtHandler> wro2(&eh);
+        wxWeakRef<wxObjectTrackable> wro3(&ot);
+
+        CPPUNIT_ASSERT( wro2.get() == &eh );
+        CPPUNIT_ASSERT( wro3.get() == &ot );
+
+        // Test accessing wxObject members
+        CPPUNIT_ASSERT( !wro2->GetRefData() );
+        CPPUNIT_ASSERT( !wro3->GetRefData() );
+
+
+        wxWeakRef<wxEvtHandler> wreh(&eh);
+        wxWeakRef<wxObjectTrackable> wrot(&ot);
+
+        CPPUNIT_ASSERT( wreh.get() == &eh );
+        CPPUNIT_ASSERT( wrot.get() == &ot );
+    }
+}
+
+void WeakRefTestCase::AssignTest()
+{
+    wxWeakRef<wxEvtHandler> wro1;
+    wxWeakRef<wxObjectTrackable> wro2;
+
+    {   // Scope for object destruction
+        wxEvtHandler eh;
+        wxObjectTrackable ot;
+
+        wro1 = &eh;
+        wro2 = &ot;
+
+        CPPUNIT_ASSERT( wro1.get() == &eh );
+        CPPUNIT_ASSERT( wro2.get() == &ot );
+    }
+
+    // Should be reset now
+    CPPUNIT_ASSERT( !wro1 );
+    CPPUNIT_ASSERT( !wro2 );
+}
+
+void WeakRefTestCase::AssignWeakRefTest()
+{
+    // Test declare when T is wxObject
+    wxWeakRef<wxEvtHandler> wro1;
+    wxWeakRef<wxObjectTrackable> wro2;
+
+    {   // Scope for object destruction
+        wxEvtHandler eh;
+        wxObjectTrackable ot;
+        wxWeakRef<wxEvtHandler> wro3;
+        wxWeakRef<wxObjectTrackable> wro4;
+
+        wro1 = &eh;
+        wro2 = &ot;
+        wro3 = wro1;
+        wro4 = wro2;
+
+        CPPUNIT_ASSERT( wro1.get() == &eh );
+        CPPUNIT_ASSERT( wro2.get() == &ot );
+        CPPUNIT_ASSERT( wro3.get() == &eh );
+        CPPUNIT_ASSERT( wro4.get() == &ot );
+
+        wro4.Release();
+        CPPUNIT_ASSERT( !wro4.get() );
+    }
+
+    // Should be reset now
+    CPPUNIT_ASSERT( !wro1 );
+    CPPUNIT_ASSERT( !wro2 );
+}
+
+void WeakRefTestCase::MultiAssignTest()
+{
+    // Object is tracked by several refs
+    wxEvtHandler *peh = new wxEvtHandler;
+
+    // Test declare when T is wxObject
+    wxWeakRef<wxEvtHandler> wro1(peh);
+    wxWeakRef<wxEvtHandler> wro2(peh);
+
+    wxObjectTrackable *pot = new wxObjectTrackable;
+    wxWeakRef<wxObjectTrackable> wro3 = pot;
+    wxWeakRef<wxObjectTrackable> wro4 = pot;
+
+    CPPUNIT_ASSERT( wro1.get() == peh );
+    CPPUNIT_ASSERT( wro2.get() == peh );
+    CPPUNIT_ASSERT( wro3.get() == pot );
+    CPPUNIT_ASSERT( wro4.get() == pot );
+
+    delete peh;
+    delete pot;
+
+    // Should be reset now
+    CPPUNIT_ASSERT( !wro1 );
+    CPPUNIT_ASSERT( !wro2 );
+    CPPUNIT_ASSERT( !wro3 );
+    CPPUNIT_ASSERT( !wro4 );
+}
+
+void WeakRefTestCase::CleanupTest()
+{
+    // Make sure that trackable objects have no left over tracker nodes after use.
+    // This time the references goes out of scope before the objects.
+    wxEvtHandler eh;
+    wxObjectTrackable ots;
+    wxObjectTrackable otd;
+
+    {   // Scope for object destruction
+        wxWeakRef<wxEvtHandler> wro1;
+        wxWeakRef<wxEvtHandler> wro2;
+        wxWeakRef<wxObjectTrackable> wro3;
+        wxWeakRef<wxObjectTrackable> wro4;
+
+        wro1 = &eh;
+        wro2 = &eh; // Has two tracker nodes now
+        wro3 = &ots;
+        wro4 = &otd;
+
+        // Access members of reffed object
+        wro3->TestFunc();
+
+        CPPUNIT_ASSERT( eh.GetFirst()==&wro2 );
+        CPPUNIT_ASSERT( ots.wxTrackable::GetFirst()==&wro3 );
+        CPPUNIT_ASSERT( otd.wxTrackable::GetFirst()==&wro4 );
+    }
+
+    // Should be reset now
+    CPPUNIT_ASSERT( !eh.GetFirst() );
+    CPPUNIT_ASSERT( !ots.wxTrackable::GetFirst() );
+    CPPUNIT_ASSERT( !otd.wxTrackable::GetFirst() );
+}
+
+void WeakRefTestCase::DeleteTest()
+{
+    // Object is tracked by several refs
+    wxEvtHandler *peh = new wxEvtHandler;
+
+    // Declared derived type of object and test deleting it
+    wxEvtHandlerRef wre(peh);
+    wxWeakRef<wxEvtHandler> wro(peh);
+
+    // test size of references (see that it has selected right base class)
+#ifdef HAVE_PARTIAL_SPECIALIZATION
+    CPPUNIT_ASSERT_EQUAL( sizeof(void*)*3, sizeof(wre) );
+    CPPUNIT_ASSERT_EQUAL( sizeof(void*)*4, sizeof(wro) );
+#else
+    CPPUNIT_ASSERT_EQUAL( sizeof(void*)*3, sizeof(wre) );
+    CPPUNIT_ASSERT_EQUAL( sizeof(void*)*3, sizeof(wro) );
+#endif
+
+    CPPUNIT_ASSERT( wre.get() == peh );
+    CPPUNIT_ASSERT( wro.get() == peh );
+
+    delete wre.get();
+
+    CPPUNIT_ASSERT( !wre );
+    CPPUNIT_ASSERT( !wro );
+}
+
+#ifdef HAVE_DYNAMIC_CAST
+
+void WeakRefTestCase::DynamicRefTest()
+{
+    wxWeakRefDynamic<wxEvtHandler> wro1;
+    wxWeakRefDynamic<wxObjectTrackable> wro2;
+    wxWeakRefDynamic<wxObjectTrackable> wro3;
+
+    {   // Scope for object destruction
+        {
+            wxEvtHandler eh;
+            wro1 = &eh;
+        }
+
+        CPPUNIT_ASSERT( !wro1 );
+
+        wxObjectTrackable otd1;
+        wxObjectTrackable otd2;
+        wro2 = &otd1;
+        wro3 = &otd2;
+
+        CPPUNIT_ASSERT( wro2.get() == &otd1 );
+        CPPUNIT_ASSERT( wro3.get() == &otd2 );
+
+        wro3 = wro2;
+        CPPUNIT_ASSERT( wro2.get() == &otd1 );
+        CPPUNIT_ASSERT( wro3.get() == &otd1 );
+    }
+
+    // Should be reset now
+    CPPUNIT_ASSERT( !wro2 );
+    CPPUNIT_ASSERT( !wro3 );
+}
+
+#endif // HAVE_DYNAMIC_CAST
-- 
2.45.2

