[vtk-developers] [Paraview-developers] Moving vtkMemberFunctionCommand to VTK

David Gobbi david.gobbi at gmail.com
Wed Oct 6 03:08:27 EDT 2010


Here's a new patch that has a working test, to show that
the weak pointers still work for vtkObjectBase objects
but that non-vtkObjectBase handlers work, too.

  David
-------------- next part --------------
diff --git a/Common/Testing/Cxx/TestObservers.cxx b/Common/Testing/Cxx/TestObservers.cxx
index 5828177..54833a8 100644
--- a/Common/Testing/Cxx/TestObservers.cxx
+++ b/Common/Testing/Cxx/TestObservers.cxx
@@ -39,6 +39,22 @@ vtkStandardNewMacro(vtkHandler);
 int vtkHandler::VoidEventCounts = 0;
 vtkstd::map<int, int> vtkHandler::EventCounts;
 
+class OtherHandler
+{
+public:
+  static vtkstd::map<int, int> EventCounts;
+  static int VoidEventCounts;
+public:
+  void VoidCallback() { this->VoidEventCounts++; }
+  void CallbackWithArguments(vtkObject*, unsigned long event, void*)
+    {
+    this->EventCounts[event]++;
+    }
+};
+
+int OtherHandler::VoidEventCounts = 0;
+vtkstd::map<int, int> OtherHandler::EventCounts;
+
 int TestObservers(int, char*[])
 {
   vtkHandler* handler = vtkHandler::New();
@@ -74,7 +90,8 @@ int TestObservers(int, char*[])
   volcano->InvokeEvent(1001);
   volcano->InvokeEvent(1002);
 
-  volcano->Delete();
+  // remove the final observer
+  volcano->RemoveObserver(event0);
 
   if (vtkHandler::VoidEventCounts == 2 &&
     vtkHandler::EventCounts[1000] == 0 &&
@@ -82,8 +99,55 @@ int TestObservers(int, char*[])
     vtkHandler::EventCounts[1002] == 1)
     {
     cout << "All callback counts as expected." << endl;
+    }
+  else
+    {
+    cerr << "Mismatched callback counts" << endl;
+    volcano->Delete();
+    return 1;
+    }
+
+  // Test again, with a non-VTK object
+
+  OtherHandler *handler2 = new OtherHandler();
+
+  unsigned long event3 = volcano->AddObserver(
+    1003, handler2, &OtherHandler::VoidCallback);
+  unsigned long event4 = volcano->AddObserver(
+    1004, handler2, &OtherHandler::CallbackWithArguments);
+  unsigned long event5 = volcano->AddObserver(
+    1005, handler2, &OtherHandler::CallbackWithArguments);
+
+  volcano->InvokeEvent(1003);
+  volcano->InvokeEvent(1004);
+  volcano->InvokeEvent(1005);
+
+  // let's see if removing an observer works
+  volcano->RemoveObserver(event5);
+  volcano->InvokeEvent(1003);
+  volcano->InvokeEvent(1004);
+  volcano->InvokeEvent(1005);
+
+  // if we delete this non-vtkObject observer, we will
+  // have dangling pointers and will see a crash...
+  // so let's not do that until the events are removed
+
+  volcano->RemoveObserver(event3);
+  volcano->RemoveObserver(event4);
+  delete handler2;
+
+  // delete the observed object
+  volcano->Delete();
+
+  if (OtherHandler::VoidEventCounts == 2 &&
+    OtherHandler::EventCounts[1003] == 0 &&
+    OtherHandler::EventCounts[1004] == 2 &&
+    OtherHandler::EventCounts[1005] == 1)
+    {
+    cout << "All callback counts as expected." << endl;
     return 0;
     }
-  cerr << "Mismatched callback counts" << endl;
+
+  cerr << "Mismatched callback counts " <<  OtherHandler::EventCounts[1003] << " " << OtherHandler::EventCounts[1004] << " " <<  OtherHandler::EventCounts[1005] << endl;
   return 1;
 }
diff --git a/Common/vtkObject.h b/Common/vtkObject.h
index f945c53..034a430 100644
--- a/Common/vtkObject.h
+++ b/Common/vtkObject.h
@@ -227,10 +227,11 @@ private:
   void operator=(const vtkObject&);  // Not implemented.
 
   // Description:
-  // Following classes (vtkClassMemberCallbackBase and vtkClassMemberCallback) along with
+  // Following classes (vtkClassMemberCallbackBase and
+  // vtkClassMemberCallback) along with
   // vtkObjectCommandInternal are for supporting
-  // templated AddObserver() overloads that allow developers to add event
-  // callbacks that are class member functions.
+  // templated AddObserver() overloads that allow developers
+  // to add event callbacks that are class member functions.
   class vtkClassMemberCallbackBase
     {
   public:
@@ -239,7 +240,37 @@ private:
     virtual void operator()(vtkObject*, unsigned long, void*) = 0;
     virtual ~vtkClassMemberCallbackBase(){}
   protected:
-    vtkWeakPointerBase Handler;
+
+    // Description:
+    // A weak pointer for vtkObjects, and a void pointer
+    // for everything else.
+    class DualPointer
+      {
+    public:
+      void operator=(vtkObjectBase *o)
+        {
+        this->VoidPointer = 0;
+        this->WeakPointer = o;
+        }
+      void operator=(void *o)
+        {
+        this->VoidPointer = o;
+        this->WeakPointer = 0;
+        }
+      vtkObjectBase *GetPointer()
+        {
+        return this->WeakPointer.GetPointer();
+        }
+      void *GetVoidPointer()
+        {
+        return this->VoidPointer;
+        }
+    private:
+      vtkWeakPointerBase WeakPointer;
+      void *VoidPointer;
+      };
+
+    DualPointer Handler;
     };
 
   template <class T>
@@ -266,11 +297,23 @@ private:
       virtual ~vtkClassMemberCallback() { }
 
       // Called when the event is invoked
-      virtual void operator()(vtkObject* caller, unsigned long event, void* calldata)
+      virtual void operator()(
+        vtkObject* caller, unsigned long event, void* calldata)
         {
+        // VoidPointer is for a non-vtkObjectBase handler
+        T* handler = static_cast<T*>(this->Handler.GetVoidPointer());
+        // Pointer is weak pointer for a vtkObjectBase handler
         if (this->Handler.GetPointer())
           {
-          T* handler = dynamic_cast<T*>(this->Handler.GetPointer());
+          handler = dynamic_cast<T*>(this->Handler.GetPointer());
+          // For when dynamic_cast fails due to shared object boundaries
+          if (handler == 0)
+            {
+            handler = (T *)this->Handler.GetPointer();
+            }
+          }
+        if (handler)
+          {
           if (this->Method1)
             {
             (handler->*this->Method1)();
diff --git a/Wrapping/Python/vtkPythonArgs.cxx b/Wrapping/Python/vtkPythonArgs.cxx
index 8e6fd1e..b18634b 100644
--- a/Wrapping/Python/vtkPythonArgs.cxx
+++ b/Wrapping/Python/vtkPythonArgs.cxx
@@ -36,7 +36,7 @@ resulting in wrapper code that is faster and more compact.
 #define VTK_PYTHON_FLOAT_CHECK()\
   if (PyFloat_Check(o) && \
       PyErr_Warn(PyExc_DeprecationWarning, \
-                 "integer argument expected, got float")) \
+                 (char *)"integer argument expected, got float")) \
     { \
     return false; \
     }


More information about the vtk-developers mailing list