]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/src/helpers.cpp
Minor tweaks to bring up to date with CVS changes
[wxWidgets.git] / wxPython / src / helpers.cpp
index d426e4d00753a26a3f6191eebd109835f8ac33ab..65457ddfbad137c07f63da7b98b106caff62275f 100644 (file)
@@ -177,6 +177,18 @@ int wxPyApp::OnExit() {
 }
 
 
+
+void wxPyApp::ExitMainLoop() {
+    bool found;
+    wxPyBlock_t blocked = wxPyBeginBlockThreads();
+    if ((found = wxPyCBH_findCallback(m_myInst, "ExitMainLoop")))
+        wxPyCBH_callCallback(m_myInst, Py_BuildValue("()"));
+    wxPyEndBlockThreads(blocked);
+    if (! found)
+        wxApp::ExitMainLoop();
+}  
+
+
 #ifdef __WXDEBUG__
 void wxPyApp::OnAssert(const wxChar *file,
                      int line,
@@ -468,6 +480,7 @@ void wxPyApp::_BootstrapApp()
         PyObject* method = m_myInst.GetLastFound();
         PyObject* argTuple = PyTuple_New(0);
         retval = PyEval_CallObject(method, argTuple);
+        m_myInst.clearRecursionGuard(method);
         Py_DECREF(argTuple);
         Py_DECREF(method);
         if (retval == NULL)
@@ -1717,45 +1730,81 @@ PyObject* PyFindClassWithAttr(PyObject *klass, PyObject *name)
 
 
 static
-PyObject* PyMethod_GetDefiningClass(PyObject* method, const char* name)
+PyObject* PyMethod_GetDefiningClass(PyObject* method, PyObject* nameo)
 {
     PyObject* mgc = PyMethod_GET_CLASS(method);
 
 #if PYTHON_API_VERSION <= 1010    // prior to Python 2.2, the easy way
     return mgc;
 #else                             // 2.2 and after, the hard way...
-
-    PyObject* nameo = PyString_FromString(name);
-    PyObject* klass = PyFindClassWithAttr(mgc, nameo);
-    Py_DECREF(nameo);
-    return klass;
+    return PyFindClassWithAttr(mgc, nameo);
 #endif
 }
 
 
 
-bool wxPyCallbackHelper::findCallback(const char* name) const {
+// To avoid recursion when an overridden virtual method wants to call the base
+// class version, temporarily set an attribute in the instance with the same
+// name as the method.  Then the PyObject_GetAttr in the next findCallback
+// will return this attribute and the PyMethod_Check will fail.
+
+void wxPyCallbackHelper::setRecursionGuard(PyObject* method) const
+{
+    PyFunctionObject* func = (PyFunctionObject*)PyMethod_Function(method);
+    PyObject_SetAttr(m_self, func->func_name, Py_None);
+}
+
+void wxPyCallbackHelper::clearRecursionGuard(PyObject* method) const
+{
+    PyFunctionObject* func = (PyFunctionObject*)PyMethod_Function(method);
+    if (PyObject_HasAttr(m_self, func->func_name)) {
+        PyObject_DelAttr(m_self, func->func_name);
+    }
+}
+
+// bool wxPyCallbackHelper::hasRecursionGuard(PyObject* method) const
+// {
+//     PyFunctionObject* func = (PyFunctionObject*)PyMethod_Function(method);
+//     if (PyObject_HasAttr(m_self, func->func_name)) {
+//         PyObject* attr = PyObject_GetAttr(m_self, func->func_name);
+//         bool retval = (attr == Py_None);
+//         Py_DECREF(attr);
+//         return retval;
+//     }
+//     return false;
+// }
+
+
+bool wxPyCallbackHelper::findCallback(const char* name, bool setGuard) const {
     wxPyCallbackHelper* self = (wxPyCallbackHelper*)this; // cast away const
+    PyObject *method, *klass;
+    PyObject* nameo = PyString_FromString(name);
     self->m_lastFound = NULL;
 
     // If the object (m_self) has an attibute of the given name...
-    if (m_self && PyObject_HasAttrString(m_self, (char*)name)) {
-        PyObject *method, *klass;
-        method = PyObject_GetAttrString(m_self, (char*)name);
+    if (m_self && PyObject_HasAttr(m_self, nameo)) {
+        method = PyObject_GetAttr(m_self, nameo);
 
         // ...and if that attribute is a method, and if that method's class is
-        // not from a base class...
+        // not from the registered class or a base class...
         if (PyMethod_Check(method) &&
-            (klass = PyMethod_GetDefiningClass(method, (char*)name)) != NULL &&
-            ((klass == m_class) || PyObject_IsSubclass(klass, m_class))) {
-
-            // ...then we'll save a pointer to the method so callCallback can call it.
+            (klass = PyMethod_GetDefiningClass(method, nameo)) != NULL &&
+            (klass != m_class) &&
+            PyObject_IsSubclass(klass, m_class)) {
+
+            // ...then we'll save a pointer to the method so callCallback can
+            // call it.  But first, set a recursion guard in case the
+            // overridden method wants to call the base class version.
+            if (setGuard)
+                setRecursionGuard(method);
             self->m_lastFound = method;
         }
         else {
             Py_DECREF(method);
         }
     }
+    
+    Py_DECREF(nameo);
     return m_lastFound != NULL;
 }
 
@@ -1784,6 +1833,8 @@ PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) const {
     PyObject* method = m_lastFound;
 
     result = PyEval_CallObject(method, argTuple);
+    clearRecursionGuard(method);
+    
     Py_DECREF(argTuple);
     Py_DECREF(method);
     if (!result) {
@@ -1797,8 +1848,8 @@ void wxPyCBH_setCallbackInfo(wxPyCallbackHelper& cbh, PyObject* self, PyObject*
     cbh.setSelf(self, klass, incref);
 }
 
-bool wxPyCBH_findCallback(const wxPyCallbackHelper& cbh, const char* name) {
-    return cbh.findCallback(name);
+bool wxPyCBH_findCallback(const wxPyCallbackHelper& cbh, const char* name, bool setGuard) {
+    return cbh.findCallback(name, setGuard);
 }
 
 int  wxPyCBH_callCallback(const wxPyCallbackHelper& cbh, PyObject* argTuple) {