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
This commit is contained in:
Robin Dunn 2004-12-20 22:50:29 +00:00
parent 56a52e9094
commit 94fd5e4dc1
6 changed files with 65 additions and 28 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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
}
};

View File

@ -866,17 +866,6 @@ bool wxPyCheckForApp() {
//---------------------------------------------------------------------------
void wxPyClientData_dtor(wxPyClientData* self) {
if (! wxPyDoingCleanup) { // Don't do it during cleanup as Python
// may have already garbage collected the object...
bool blocked = wxPyBeginBlockThreads();
Py_DECREF(self->m_obj);
self->m_obj = NULL;
wxPyEndBlockThreads(blocked);
}
}
void wxPyUserData_dtor(wxPyUserData* self) {
if (! wxPyDoingCleanup) {
bool blocked = wxPyBeginBlockThreads();
@ -887,6 +876,20 @@ void wxPyUserData_dtor(wxPyUserData* self) {
}
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;
}
}
// 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!?!?!"));