diff --git a/src/clntdata.sip b/src/clntdata.sip index 09a6c8ad..c5cd239f 100644 --- a/src/clntdata.sip +++ b/src/clntdata.sip @@ -11,29 +11,15 @@ %ModuleHeaderCode - // A wxClientData that holds a reference to a Python object - class wxPyClientData : public wxClientData - { - public: - wxPyClientData(PyObject* obj, bool incref=true) - { - m_obj = obj; - m_incRef = incref; - if (incref) { - wxPyBLOCK_THREADS( Py_INCREF(m_obj) ); - } - } - ~wxPyClientData() - { - if (m_incRef) { - wxPyBLOCK_THREADS( Py_DECREF(m_obj) ); - } - m_obj = NULL; - } - PyObject* m_obj; - bool m_incRef; - }; - +// A wxClientData that holds a reference to a Python object +class wxPyClientData : public wxPyUserDataHelper +{ +public: + wxPyClientData(PyObject* obj = NULL) + : wxPyUserDataHelper(obj) + { } +}; + %End @@ -59,13 +45,7 @@ %ConvertFromTypeCode // Code to convert a wxClientData back to the PyObject. PyObject* obj; - if (sipCpp == NULL) { - obj = Py_None; - } else { - wxPyClientData* data = static_cast(sipCpp); // TODO: verify poitner type? - obj = data->m_obj; - } - Py_INCREF(obj); + obj = wxPyClientData::SafeGetData(static_cast(sipCpp)); return obj; %End diff --git a/src/treeitemdata.sip b/src/treeitemdata.sip index b31fed8c..6f4e213f 100644 --- a/src/treeitemdata.sip +++ b/src/treeitemdata.sip @@ -15,21 +15,14 @@ #include // A wxTreeItemData that knows what to do with PyObjects for maintianing the refcount -class wxPyTreeItemData : public wxTreeItemData { +class wxPyTreeItemData : public wxPyUserDataHelper +{ public: - wxPyTreeItemData(PyObject* obj = NULL) { - if (obj == NULL) - obj = Py_None; - wxPyBLOCK_THREADS( Py_INCREF(obj) ); - m_obj = obj; - } + wxPyTreeItemData(PyObject* obj = NULL) + : wxPyUserDataHelper(obj) + { } +}; - ~wxPyTreeItemData() { - wxPyBLOCK_THREADS( Py_DECREF(m_obj) ); - } - - PyObject* m_obj; -}; %End @@ -41,7 +34,7 @@ public: return TRUE; // any python object is valid } - // Code to create a new wxClientData from the PyObject + // Code to create a new wxTreeItemData from the PyObject wxPyTreeItemData* data = new wxPyTreeItemData(sipPy); *sipCppPtr = data; return sipGetState(sipTransferObj); @@ -51,13 +44,7 @@ public: %ConvertFromTypeCode // Code to convert a wxPyTreeItemData back to the PyObject. PyObject* obj; - if (sipCpp == NULL) { - obj = Py_None; - } else { - wxPyTreeItemData* data = static_cast(sipCpp); - obj = data->m_obj; - } - Py_INCREF(obj); + obj = wxPyTreeItemData::SafeGetData(static_cast(sipCpp)); return obj; %End diff --git a/src/userdata.sip b/src/userdata.sip index 7c95498b..918f9ce9 100644 --- a/src/userdata.sip +++ b/src/userdata.sip @@ -11,36 +11,15 @@ %ModuleHeaderCode - // A wxPyUserData object that holds a reference to a Python object - class wxPyUserData : public wxObject - { - public: - wxPyUserData() : wxObject() - { - m_obj = NULL; - m_incRef = false; - } - - wxPyUserData(PyObject* obj, bool incref=true) - : wxObject() - { - m_obj = obj; - m_incRef = incref; - if (incref) { - wxPyBLOCK_THREADS( Py_INCREF(m_obj) ); - } - } - virtual ~wxPyUserData() - { - if (m_incRef) { - wxPyBLOCK_THREADS( Py_DECREF(m_obj) ); - } - m_obj = NULL; - } - PyObject* m_obj; - bool m_incRef; - }; - +// A wxObject object that holds a reference to a Python object +class wxPyUserData : public wxPyUserDataHelper +{ +public: + wxPyUserData(PyObject* obj = NULL) + : wxPyUserDataHelper(obj) + { } +}; + %End @@ -66,17 +45,8 @@ %ConvertFromTypeCode // Code to convert a wxPyUserData back to the PyObject. PyObject* obj; - if (sipCpp == NULL) { - obj = Py_None; - } else { - wxPyUserData* data = static_cast(sipCpp); // TODO: verify pointer type? - obj = data->m_obj; - } - Py_INCREF(obj); + obj = wxPyUserData::SafeGetData(static_cast(sipCpp)); return obj; %End }; - -// NOTE TO SELF: It looks like the GIL is already held by the current thread -// in ConvertToTypeCode and ConvertFromTypeCode code blocks... diff --git a/src/wxpy_api.h b/src/wxpy_api.h index 6744a30c..bb4844d2 100644 --- a/src/wxpy_api.h +++ b/src/wxpy_api.h @@ -213,5 +213,71 @@ private: wxPyBlock_t m_oldstate; bool m_block; }; + + +//-------------------------------------------------------------------------- +// helper template to make common code for all of the various user data owners +template +class wxPyUserDataHelper : public Base { +public: + explicit wxPyUserDataHelper(PyObject* obj = NULL) + : m_obj(obj ? obj : Py_None) + { + wxPyThreadBlocker blocker; + Py_INCREF(m_obj); + } + ~wxPyUserDataHelper() + { // normally the derived class does the clean up, or deliberately leaks + // by setting m_obj to 0, but if not then do it here. + if (m_obj) { + wxPyThreadBlocker blocker; + Py_DECREF(m_obj); + m_obj = 0; + } + } + + // Return Value: New reference + PyObject* GetData() const { + wxPyThreadBlocker blocker; + Py_INCREF(m_obj); + return m_obj; + } + + // Return Value: Borrowed reference + PyObject* BorrowData() const { + return m_obj; + } + + void SetData(PyObject* obj) { + if (obj != m_obj) { + wxPyThreadBlocker blocker; + Py_DECREF(m_obj); + m_obj = obj ? obj : Py_None; + Py_INCREF(m_obj); + } + } + + // Return the object in udata or None if udata is null + // Return Value: New reference + static PyObject* SafeGetData(wxPyUserDataHelper* udata) { + wxPyThreadBlocker blocker; + PyObject* obj = udata ? udata->BorrowData() : Py_None; + Py_INCREF(obj); + return obj; + } + + // Set the m_obj to null, this should only be used during clean up, when + // the object should be leaked. + // Calling any other methods on this object is then undefined behaviour + void ReleaseDataDuringCleanup() + { + m_obj = 0; + } + +private: + PyObject* m_obj; +}; + +//-------------------------------------------------------------------------- #endif