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:
@@ -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
|
also been changed in order to better comply with Microsoft's examples
|
||||||
of how to use the control.
|
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
|
class wxPyTimer : public wxTimer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxPyTimer(wxEvtHandler *owner=NULL, int id = -1)
|
wxPyTimer(wxEvtHandler *owner=NULL, int id = -1);
|
||||||
: wxTimer(owner, id)
|
|
||||||
{
|
|
||||||
if (owner == NULL) SetOwner(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEC_PYCALLBACK__(Notify);
|
DEC_PYCALLBACK__(Notify);
|
||||||
PYPRIVATE;
|
PYPRIVATE;
|
||||||
|
@@ -467,12 +467,14 @@ public:
|
|||||||
// A wxClientData that holds a refernece to a Python object
|
// A wxClientData that holds a refernece to a Python object
|
||||||
class wxPyClientData : public wxClientData {
|
class wxPyClientData : public wxClientData {
|
||||||
public:
|
public:
|
||||||
wxPyClientData(PyObject* obj) {
|
wxPyClientData(PyObject* obj, bool incref=true) {
|
||||||
m_obj = obj;
|
m_obj = obj;
|
||||||
Py_INCREF(m_obj);
|
m_incRef = incref;
|
||||||
|
if (incref)
|
||||||
|
Py_INCREF(m_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
~wxPyClientData() {
|
~wxPyClientData() {
|
||||||
|
|
||||||
#ifdef wxPyUSE_EXPORTED_API
|
#ifdef wxPyUSE_EXPORTED_API
|
||||||
wxPyGetCoreAPIPtr()->p_wxPyClientData_dtor(this);
|
wxPyGetCoreAPIPtr()->p_wxPyClientData_dtor(this);
|
||||||
#else
|
#else
|
||||||
@@ -480,6 +482,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
PyObject* m_obj;
|
PyObject* m_obj;
|
||||||
|
bool m_incRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -487,10 +490,10 @@ public:
|
|||||||
// OOR magic on the Python Object.
|
// OOR magic on the Python Object.
|
||||||
class wxPyOORClientData : public wxPyClientData {
|
class wxPyOORClientData : public wxPyClientData {
|
||||||
public:
|
public:
|
||||||
wxPyOORClientData(PyObject* obj)
|
wxPyOORClientData(PyObject* obj, bool incref=true)
|
||||||
: wxPyClientData(obj) {}
|
: wxPyClientData(obj, incref) {}
|
||||||
|
|
||||||
~wxPyOORClientData() {
|
~wxPyOORClientData() {
|
||||||
|
|
||||||
#ifdef wxPyUSE_EXPORTED_API
|
#ifdef wxPyUSE_EXPORTED_API
|
||||||
wxPyGetCoreAPIPtr()->p_wxPyOORClientData_dtor(this);
|
wxPyGetCoreAPIPtr()->p_wxPyOORClientData_dtor(this);
|
||||||
#else
|
#else
|
||||||
|
@@ -73,9 +73,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
%extend {
|
%extend {
|
||||||
void _setOORInfo(PyObject* _self) {
|
void _setOORInfo(PyObject* _self, bool incref=true) {
|
||||||
if (_self && _self != Py_None) {
|
if (_self && _self != Py_None) {
|
||||||
self->SetClientObject(new wxPyOORClientData(_self));
|
self->SetClientObject(new wxPyOORClientData(_self, incref));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
wxPyOORClientData* data = (wxPyOORClientData*)self->GetClientObject();
|
wxPyOORClientData* data = (wxPyOORClientData*)self->GetClientObject();
|
||||||
|
@@ -36,6 +36,13 @@ enum {
|
|||||||
|
|
||||||
IMPLEMENT_ABSTRACT_CLASS(wxPyTimer, wxTimer);
|
IMPLEMENT_ABSTRACT_CLASS(wxPyTimer, wxTimer);
|
||||||
|
|
||||||
|
wxPyTimer::wxPyTimer(wxEvtHandler *owner, int id)
|
||||||
|
: wxTimer(owner, id)
|
||||||
|
{
|
||||||
|
if (owner == NULL) SetOwner(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void wxPyTimer::Notify() {
|
void wxPyTimer::Notify() {
|
||||||
bool found;
|
bool found;
|
||||||
bool blocked = wxPyBeginBlockThreads();
|
bool blocked = wxPyBeginBlockThreads();
|
||||||
@@ -58,7 +65,11 @@ MustHaveApp(wxPyTimer);
|
|||||||
%name(Timer) class wxPyTimer : public wxEvtHandler
|
%name(Timer) class wxPyTimer : public wxEvtHandler
|
||||||
{
|
{
|
||||||
public:
|
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
|
// 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
|
// notification. If the owner is set then it will get the timer
|
||||||
// notifications which can be handled with EVT_TIMER.
|
// notifications which can be handled with EVT_TIMER.
|
||||||
wxPyTimer(wxEvtHandler *owner=NULL, int id = -1);
|
wxPyTimer(wxEvtHandler *owner=NULL, int id = -1);
|
||||||
|
|
||||||
|
// Destructor.
|
||||||
virtual ~wxPyTimer();
|
virtual ~wxPyTimer();
|
||||||
|
|
||||||
void _setCallbackInfo(PyObject* self, PyObject* _class, int incref=1);
|
void _setCallbackInfo(PyObject* self, PyObject* _class, int incref=1);
|
||||||
@@ -101,6 +114,11 @@ public:
|
|||||||
// return the timer ID
|
// return the timer ID
|
||||||
int GetId() const;
|
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) {
|
void wxPyUserData_dtor(wxPyUserData* self) {
|
||||||
if (! wxPyDoingCleanup) {
|
if (! wxPyDoingCleanup) {
|
||||||
bool blocked = wxPyBeginBlockThreads();
|
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
|
// 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
|
// 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
|
// (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
|
// Only if there is more than one reference to the object and we are
|
||||||
if ( !wxPyDoingCleanup && self->m_obj->ob_refcnt > 1 ) {
|
// holding the OOR reference:
|
||||||
|
if ( !wxPyDoingCleanup && self->m_obj->ob_refcnt > 1 && self->m_incRef) {
|
||||||
// bool isInstance = wxPyInstance_Check(self->m_obj);
|
// bool isInstance = wxPyInstance_Check(self->m_obj);
|
||||||
// TODO same here
|
// TODO same here
|
||||||
//wxASSERT_MSG(isInstance, wxT("m_obj not an instance!?!?!"));
|
//wxASSERT_MSG(isInstance, wxT("m_obj not an instance!?!?!"));
|
||||||
|
Reference in New Issue
Block a user