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.
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;
// 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
#endif
}
PyObject* m_obj;
+ bool m_incRef;
};
// 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
}
%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();
//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();
%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
// 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);
// return the timer ID
int GetId() const;
+ %pythoncode {
+ def Destroy():
+ """NO-OP: Timers must be destroyed by normal refrence counting"""
+ pass
+ }
};
//---------------------------------------------------------------------------
-
-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;
}
}
-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
}
- // 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!?!?!"));