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:
parent
56a52e9094
commit
94fd5e4dc1
@ -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.
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -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!?!?!"));
|
||||
|
Loading…
Reference in New Issue
Block a user