From: Robin Dunn Date: Mon, 20 Dec 2004 22:50:29 +0000 (+0000) Subject: Allow the OOR reference to be saved without doing an INCREF. This X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/94fd5e4dc14c5de8a0a787eda125987616ace638 Allow the OOR reference to be saved without doing an INCREF. This solves the circular reference problem with wx.Timer. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@31095 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/wxPython/docs/CHANGES.txt b/wxPython/docs/CHANGES.txt index a2da7e6d48..62f5b95116 100644 --- a/wxPython/docs/CHANGES.txt +++ b/wxPython/docs/CHANGES.txt @@ -87,6 +87,22 @@ maintainable and hopefully less buggy. The position of the labels has also been changed in order to better comply with Microsoft's examples of how to use the control. +wxMSW: Fix wx.TreeCtrl to end label editing if the control loses +focus (a slightly modified patch 1084592.) + +Added wx.EXEC_NODISABLE flag for wx.Execute, which will prevent all +the app's windows being disabled while a synchronous child process is +running. + +wxMSW: Much work to correct painting (or leaving transparent) of +control backgrounds, properly using background themes on XP, etc. + +Fixed a circular reference problem with wx.Timer. It will now +completely cleanup after itself when the last reference to the timer +is removed. If you were previously using timer.Destroy() to cleanup +your timers it will no longer work. Instead you should hold a +reference to the timer and then del the reference when you are +finished with the timer. diff --git a/wxPython/include/wx/wxPython/pyclasses.h b/wxPython/include/wx/wxPython/pyclasses.h index 2859590f09..8ec04a4fde 100644 --- a/wxPython/include/wx/wxPython/pyclasses.h +++ b/wxPython/include/wx/wxPython/pyclasses.h @@ -79,11 +79,7 @@ public: class wxPyTimer : public wxTimer { public: - wxPyTimer(wxEvtHandler *owner=NULL, int id = -1) - : wxTimer(owner, id) - { - if (owner == NULL) SetOwner(this); - } + wxPyTimer(wxEvtHandler *owner=NULL, int id = -1); DEC_PYCALLBACK__(Notify); PYPRIVATE; diff --git a/wxPython/include/wx/wxPython/wxPython_int.h b/wxPython/include/wx/wxPython/wxPython_int.h index ff605d8b4b..336c20c33e 100644 --- a/wxPython/include/wx/wxPython/wxPython_int.h +++ b/wxPython/include/wx/wxPython/wxPython_int.h @@ -467,12 +467,14 @@ public: // A wxClientData that holds a refernece to a Python object class wxPyClientData : public wxClientData { public: - wxPyClientData(PyObject* obj) { + wxPyClientData(PyObject* obj, bool incref=true) { m_obj = obj; - Py_INCREF(m_obj); + m_incRef = incref; + if (incref) + Py_INCREF(m_obj); } - ~wxPyClientData() { + #ifdef wxPyUSE_EXPORTED_API wxPyGetCoreAPIPtr()->p_wxPyClientData_dtor(this); #else @@ -480,6 +482,7 @@ public: #endif } PyObject* m_obj; + bool m_incRef; }; @@ -487,10 +490,10 @@ public: // OOR magic on the Python Object. class wxPyOORClientData : public wxPyClientData { public: - wxPyOORClientData(PyObject* obj) - : wxPyClientData(obj) {} - + wxPyOORClientData(PyObject* obj, bool incref=true) + : wxPyClientData(obj, incref) {} ~wxPyOORClientData() { + #ifdef wxPyUSE_EXPORTED_API wxPyGetCoreAPIPtr()->p_wxPyOORClientData_dtor(this); #else diff --git a/wxPython/src/_evthandler.i b/wxPython/src/_evthandler.i index 5cbe3734c9..d54c5aa1eb 100644 --- a/wxPython/src/_evthandler.i +++ b/wxPython/src/_evthandler.i @@ -73,9 +73,9 @@ public: } %extend { - void _setOORInfo(PyObject* _self) { + void _setOORInfo(PyObject* _self, bool incref=true) { if (_self && _self != Py_None) { - self->SetClientObject(new wxPyOORClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self, incref)); } else { wxPyOORClientData* data = (wxPyOORClientData*)self->GetClientObject(); diff --git a/wxPython/src/_timer.i b/wxPython/src/_timer.i index b84e0db64b..910a3864ca 100644 --- a/wxPython/src/_timer.i +++ b/wxPython/src/_timer.i @@ -35,7 +35,14 @@ enum { //IMP_PYCALLBACK__(wxPyTimer, wxTimer, Notify); IMPLEMENT_ABSTRACT_CLASS(wxPyTimer, wxTimer); - + +wxPyTimer::wxPyTimer(wxEvtHandler *owner, int id) + : wxTimer(owner, id) +{ + if (owner == NULL) SetOwner(this); +} + + void wxPyTimer::Notify() { bool found; bool blocked = wxPyBeginBlockThreads(); @@ -58,7 +65,11 @@ MustHaveApp(wxPyTimer); %name(Timer) class wxPyTimer : public wxEvtHandler { public: - %pythonAppend wxPyTimer "self._setCallbackInfo(self, Timer, 0); self._setOORInfo(self)" + // Don't let the OOR or callback info hold references to the object so + // there won't be a reference cycle and it can clean itself up via normal + // Python refcounting + %pythonAppend wxPyTimer + "self._setCallbackInfo(self, Timer, 0); self._setOORInfo(self, 0)" // if you don't call SetOwner() or provide an owner in the contstructor @@ -66,6 +77,8 @@ public: // notification. If the owner is set then it will get the timer // notifications which can be handled with EVT_TIMER. wxPyTimer(wxEvtHandler *owner=NULL, int id = -1); + + // Destructor. virtual ~wxPyTimer(); void _setCallbackInfo(PyObject* self, PyObject* _class, int incref=1); @@ -101,6 +114,11 @@ public: // return the timer ID int GetId() const; + %pythoncode { + def Destroy(): + """NO-OP: Timers must be destroyed by normal refrence counting""" + pass + } }; diff --git a/wxPython/src/helpers.cpp b/wxPython/src/helpers.cpp index ef5fb35e32..d3f1aebbb8 100644 --- a/wxPython/src/helpers.cpp +++ b/wxPython/src/helpers.cpp @@ -866,10 +866,8 @@ bool wxPyCheckForApp() { //--------------------------------------------------------------------------- - -void wxPyClientData_dtor(wxPyClientData* self) { - if (! wxPyDoingCleanup) { // Don't do it during cleanup as Python - // may have already garbage collected the object... +void wxPyUserData_dtor(wxPyUserData* self) { + if (! wxPyDoingCleanup) { bool blocked = wxPyBeginBlockThreads(); Py_DECREF(self->m_obj); self->m_obj = NULL; @@ -877,16 +875,21 @@ void wxPyClientData_dtor(wxPyClientData* self) { } } -void wxPyUserData_dtor(wxPyUserData* self) { - if (! wxPyDoingCleanup) { - bool blocked = wxPyBeginBlockThreads(); - Py_DECREF(self->m_obj); + +void wxPyClientData_dtor(wxPyClientData* self) { + if (! wxPyDoingCleanup) { // Don't do it during cleanup as Python + // may have already garbage collected the object... + if (self->m_incRef) { + bool blocked = wxPyBeginBlockThreads(); + Py_DECREF(self->m_obj); + wxPyEndBlockThreads(blocked); + } self->m_obj = NULL; - wxPyEndBlockThreads(blocked); } } + // This is called when an OOR controled object is being destroyed. Although // the C++ object is going away there is no way to force the Python object // (and all references to it) to die too. This causes problems (crashes) in @@ -909,8 +912,9 @@ void wxPyOORClientData_dtor(wxPyOORClientData* self) { } - // Only if there is more than one reference to the object - if ( !wxPyDoingCleanup && self->m_obj->ob_refcnt > 1 ) { + // Only if there is more than one reference to the object and we are + // holding the OOR reference: + if ( !wxPyDoingCleanup && self->m_obj->ob_refcnt > 1 && self->m_incRef) { // bool isInstance = wxPyInstance_Check(self->m_obj); // TODO same here //wxASSERT_MSG(isInstance, wxT("m_obj not an instance!?!?!"));