// already be a pointer to a Python object that we can use
// in the OOR data.
wxShapeEvtHandler* seh = (wxShapeEvtHandler*)source;
- wxPyClientData* data = (wxPyClientData*)seh->GetClientObject();
+ wxPyOORClientData* data = (wxPyOORClientData*)seh->GetClientObject();
if (data) {
target = data->m_obj;
Py_INCREF(target);
if (! target) {
target = wxPyMake_wxObject2(source, FALSE);
if (target != Py_None)
- ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyClientData(target));
+ ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target));
}
return target;
}
// already be a pointer to a Python object that we can use
// in the OOR data.
wxShapeEvtHandler* seh = (wxShapeEvtHandler*)source;
- wxPyClientData* data = (wxPyClientData*)seh->GetClientObject();
+ wxPyOORClientData* data = (wxPyOORClientData*)seh->GetClientObject();
if (data) {
target = data->m_obj;
Py_INCREF(target);
if (! target) {
target = wxPyMake_wxObject2(source, FALSE);
if (target != Py_None)
- ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyClientData(target));
+ ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target));
}
return target;
}
}
static void wxPyShapeEvtHandler__setOORInfo(wxPyShapeEvtHandler *self,PyObject * _self) {
- self->SetClientObject(new wxPyClientData(_self));
+ self->SetClientObject(new wxPyOORClientData(_self));
}
static PyObject *_wrap_wxPyShapeEvtHandler__setOORInfo(PyObject *self, PyObject *args, PyObject *kwargs) {
PyObject * _resultobj;
%addmethods { void Destroy() { delete self; } }
%addmethods {
void _setOORInfo(PyObject* _self) {
- self->SetClientObject(new wxPyClientData(_self));
+ self->SetClientObject(new wxPyOORClientData(_self));
}
}
return theObj
+#----------------------------------------------------------------------------
+
+
+class _wxPyDeadObject:
+ """
+ Instances of wx objects that are OOR capable will have their __class__
+ changed to this class when the C++ object is deleted. This should help
+ prevent crashes due to referencing a bogus C++ pointer.
+ """
+ def __repr__( self ):
+ if not hasattr(self, "_name"):
+ self._name = "[unknown]"
+ return 'wxPython wrapper for deleted %s object!!! Programming logic error' % self._name
+
+ def __getattr__( self, *args ):
+ if not hasattr(self, "_name"):
+ self._name = "[unknown]"
+ raise ValueError, 'Attempt to access attribute of a deleted %s object' % self._name
+
+
#----------------------------------------------------------------------
#----------------------------------------------------------------------
self.frame.Show(true)
#----------------------------------------------------------------------------
-# DO NOT hold any other references to this object. This is how we know when
-# to cleanup system resources that wxWin is holding. When this module is
-# unloaded, the refcount on __cleanMeUp goes to zero and it calls the
-# wxApp_CleanUp function.
+# DO NOT hold any other references to this object. This is how we
+# know when to cleanup system resources that wxWin is holding. When
+# the sys module is unloaded, the refcount on sys.__wxPythonCleanup
+# goes to zero and it calls the wxApp_CleanUp function.
class __wxPyCleanup:
def __init__(self):
#define wxArrayString2PyList_helper(a) (wxPyCoreAPIPtr->p_wxArrayString2PyList_helper(a))
#define wxArrayInt2PyList_helper(a) (wxPyCoreAPIPtr->p_wxArrayInt2PyList_helper(a))
+#define wxPyClientData_dtor(a) (wxPyCoreAPIPtr->p_wxPyClientData_dtor(a))
+#define wxPyUserData_dtor(a) (wxPyCoreAPIPtr->p_wxPyUserData_dtor(a))
+#define wxPyOORClientData_dtor(a) (wxPyCoreAPIPtr->p_wxPyOORClientData_dtor(a))
// This one is special. It's the first function called in SWIG generated
// modules, so we'll use it to also import the API.
static PyObject* wxPython_dict = NULL;
static PyObject* wxPyPtrTypeMap = NULL;
+
PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
{
return Py_None;
}
+//---------------------------------------------------------------------------
+
+void wxPyClientData_dtor(wxPyClientData* self) {
+ wxPyBeginBlockThreads();
+ Py_DECREF(self->m_obj);
+ wxPyEndBlockThreads();
+}
+
+void wxPyUserData_dtor(wxPyUserData* self) {
+ wxPyBeginBlockThreads();
+ Py_DECREF(self->m_obj);
+ wxPyEndBlockThreads();
+}
+
+
+// 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
+// wxPython when a python shadow object attempts to call a C++ method using
+// the now bogus pointer... So to try and prevent this we'll do a little black
+// magic and change the class of the python instance to a class that will
+// raise an exception for any attempt to call methods with it. See
+// _wxPyDeadObject in _extras.py for the implementation of this class.
+void wxPyOORClientData_dtor(wxPyOORClientData* self) {
+
+ static PyObject* deadObjectClass = NULL;
+
+ wxPyBeginBlockThreads();
+ if (deadObjectClass == NULL) {
+ deadObjectClass = PyDict_GetItemString(wxPython_dict, "_wxPyDeadObject");
+ wxASSERT_MSG(deadObjectClass != NULL, wxT("Can't get _wxPyDeadObject class!"));
+ Py_INCREF(deadObjectClass);
+ }
+
+ // Clear the instance's dictionary, put the name of the old class into the
+ // instance, and then reset the class to be the dead class.
+ if (self->m_obj->ob_refcnt > 1) { // but only if there is more than one reference
+ wxASSERT_MSG(PyInstance_Check(self->m_obj), wxT("m_obj not an instance!?!?!"));
+ PyInstanceObject* inst = (PyInstanceObject*)self->m_obj;
+ PyDict_Clear(inst->in_dict);
+ PyDict_SetItemString(inst->in_dict, "_name", inst->in_class->cl_name);
+ inst->in_class = (PyClassObject*)deadObjectClass;
+ Py_INCREF(deadObjectClass);
+ }
+ wxPyEndBlockThreads();
+}
//---------------------------------------------------------------------------
// Stuff used by OOR to find the right wxPython class type to return and to
// is not the same as the shadow class name, for example wxPyTreeCtrl
// vs. wxTreeCtrl. It needs to be referenced in Python as well as from C++,
// so we'll just make it a Python dictionary in the wx module's namespace.
+// (See __wxSetDictionary)
void wxPyPtrTypeMap_Add(const char* commonName, const char* ptrName) {
if (! wxPyPtrTypeMap)
wxPyPtrTypeMap = PyDict_New();
if (checkEvtHandler && wxIsKindOf(source, wxEvtHandler)) {
isEvtHandler = TRUE;
wxEvtHandler* eh = (wxEvtHandler*)source;
- wxPyClientData* data = (wxPyClientData*)eh->GetClientObject();
+ wxPyOORClientData* data = (wxPyOORClientData*)eh->GetClientObject();
if (data) {
target = data->m_obj;
Py_INCREF(target);
if (info) {
target = wxPyConstructObject(source, name, klass, FALSE);
if (target && isEvtHandler)
- ((wxEvtHandler*)source)->SetClientObject(new wxPyClientData(target));
+ ((wxEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target));
} else {
- wxString msg("wxPython class not found for ");
+ wxString msg(wxT("wxPython class not found for "));
msg += source->GetClassInfo()->GetClassName();
PyErr_SetString(PyExc_NameError, msg.mbc_str());
target = NULL;
// already be a pointer to a Python object that we can use
// in the OOR data.
wxSizer* sz = (wxSizer*)source;
- wxPyClientData* data = (wxPyClientData*)sz->GetClientObject();
+ wxPyOORClientData* data = (wxPyOORClientData*)sz->GetClientObject();
if (data) {
target = data->m_obj;
Py_INCREF(target);
if (! target) {
target = wxPyMake_wxObject(source, FALSE);
if (target != Py_None)
- ((wxSizer*)source)->SetClientObject(new wxPyClientData(target));
+ ((wxSizer*)source)->SetClientObject(new wxPyOORClientData(target));
}
return target;
}
bool wxRect_helper(PyObject* source, wxRect** obj);
bool wxColour_helper(PyObject* source, wxColour** obj);
+//----------------------------------------------------------------------
+// Other helpful stuff
+
#if PYTHON_API_VERSION < 1009
#define PySequence_Fast_GET_ITEM(o, i) \
(PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i))
PyObject* wxArrayString2PyList_helper(const wxArrayString& arr);
PyObject* wxArrayInt2PyList_helper(const wxArrayInt& arr);
-
-#define RETURN_NONE() { Py_INCREF(Py_None); return Py_None; }
-#define DECLARE_DEF_STRING(name) static wxString wxPy##name(wx##name)
+#define RETURN_NONE() { Py_INCREF(Py_None); return Py_None; }
+#define DECLARE_DEF_STRING(name) static const wxString wxPy##name(wx##name)
+#define DECLARE_DEF_STRING2(name,val) static const wxString wxPy##name(val)
//----------------------------------------------------------------------
};
+
+//----------------------------------------------------------------------
+// Forward decalre a few things used in the exported API
+class wxPyClientData;
+class wxPyUserData;
+class wxPyOORClientData;
+
+void wxPyClientData_dtor(wxPyClientData* self);
+void wxPyUserData_dtor(wxPyUserData* self);
+void wxPyOORClientData_dtor(wxPyOORClientData* self);
+
+
//---------------------------------------------------------------------------
// Export a C API in a struct. Other modules will be able to load this from
// the wxc module and will then have safe access to these functions, even if
void (*p_wxPyPtrTypeMap_Add)(const char* commonName, const char* ptrName);
PyObject* (*p_wxArrayString2PyList_helper)(const wxArrayString& arr);
PyObject* (*p_wxArrayInt2PyList_helper)(const wxArrayInt& arr);
+
+ void (*p_wxPyClientData_dtor)(wxPyClientData*);
+ void (*p_wxPyUserData_dtor)(wxPyUserData*);
+ void (*p_wxPyOORClientData_dtor)(wxPyOORClientData*);
+};
+
+#ifdef wxPyUSE_EXPORT
+static wxPyCoreAPI* wxPyCoreAPIPtr = NULL; // Each module needs one, but doesn't have to use it.
+#endif
+
+
+//---------------------------------------------------------------------------
+
+
+class wxPyUserData : public wxObject {
+public:
+ wxPyUserData(PyObject* obj) {
+ m_obj = obj;
+ Py_INCREF(m_obj);
+ }
+
+ ~wxPyUserData() {
+#ifdef wxPyUSE_EXPORT
+ wxPyCoreAPIPtr->p_wxPyUserData_dtor(this);
+#else
+ wxPyUserData_dtor(this);
+#endif
+ }
+ PyObject* m_obj;
+};
+
+
+class wxPyClientData : public wxClientData {
+public:
+ wxPyClientData(PyObject* obj) {
+ m_obj = obj;
+ Py_INCREF(m_obj);
+ }
+
+ ~wxPyClientData() {
+#ifdef wxPyUSE_EXPORT
+ wxPyCoreAPIPtr->p_wxPyClientData_dtor(this);
+#else
+ wxPyClientData_dtor(this);
+#endif
+ }
+ PyObject* m_obj;
};
+
+class wxPyOORClientData : public wxPyClientData {
+public:
+ wxPyOORClientData(PyObject* obj)
+ : wxPyClientData(obj) {}
+
+ ~wxPyOORClientData() {
#ifdef wxPyUSE_EXPORT
-static wxPyCoreAPI* wxPyCoreAPIPtr = NULL; // Each module needs one, but may not use it.
+ wxPyCoreAPIPtr->p_wxPyOORClientData_dtor(this);
+#else
+ wxPyOORClientData_dtor(this);
#endif
+ }
+};
//---------------------------------------------------------------------------
// This class holds an instance of a Python Shadow Class object and assists
-//----------------------------------------------------------------------
-
-class wxPyUserData : public wxObject {
-public:
- wxPyUserData(PyObject* obj) {
- m_obj = obj;
- Py_INCREF(m_obj);
- }
-
- ~wxPyUserData() {
-#ifdef wxPyUSE_EXPORT
- wxPyCoreAPIPtr->p_wxPyBeginBlockThreads();
- Py_DECREF(m_obj);
- wxPyCoreAPIPtr->p_wxPyEndBlockThreads();
-#else
- wxPyBeginBlockThreads();
- Py_DECREF(m_obj);
- wxPyEndBlockThreads();
-#endif
- }
- PyObject* m_obj;
-};
-
-
-
-class wxPyClientData : public wxClientData {
-public:
- wxPyClientData(PyObject* obj) {
- m_obj = obj;
- Py_INCREF(m_obj);
- }
-
- ~wxPyClientData() {
-#ifdef wxPyUSE_EXPORT
- wxPyCoreAPIPtr->p_wxPyBeginBlockThreads();
- Py_DECREF(m_obj);
- wxPyCoreAPIPtr->p_wxPyEndBlockThreads();
-#else
- wxPyBeginBlockThreads();
- Py_DECREF(m_obj);
- wxPyEndBlockThreads();
-#endif
- }
- PyObject* m_obj;
-};
-
-
//---------------------------------------------------------------------------
// These macros are used to implement the virtual methods that should
def __init__(self,*_args,**_kwargs):
self.this = apply(gdic.new_wxBufferedDC,_args,_kwargs)
self.thisown = 1
- self._dc = _args[0] # save a ref so it won't be deleted before self
+ self._dc = _args[0] # save a ref so the other dc won't be deleted before self
def wxBufferedDCInternalBuffer(*_args,**_kwargs):
val = wxBufferedDCPtr(apply(gdic.new_wxBufferedDCInternalBuffer,_args,_kwargs))
val.thisown = 1
- val._dc = _args[0] # save a ref so it won't be deleted before self
+ val._dc = _args[0] # save a ref so the other dc won't be deleted before self
return val
}
static void wxSizer__setOORInfo(wxSizer *self,PyObject * _self) {
- self->SetClientObject(new wxPyClientData(_self));
+ self->SetClientObject(new wxPyOORClientData(_self));
}
static PyObject *_wrap_wxSizer__setOORInfo(PyObject *self, PyObject *args, PyObject *kwargs) {
PyObject * _resultobj;
#define SWIG_name "utilsc"
-#include "export.h"
+#include "helpers.h"
#include <wx/config.h>
#include <wx/fileconf.h>
#include <wx/datetime.h>
// Put some wx default wxChar* values into wxStrings.
- static const wxChar* wxDateFormatStr = wxT("sashWindow");
- DECLARE_DEF_STRING(DateFormatStr);
+ DECLARE_DEF_STRING2(DateFormatStr, wxT("sashWindow"));
static const wxString wxPyEmptyString(wxT(""));
}
static void wxEvtHandler__setOORInfo(wxEvtHandler *self,PyObject * _self) {
- self->SetClientObject(new wxPyClientData(_self));
+ self->SetClientObject(new wxPyOORClientData(_self));
}
static PyObject *_wrap_wxEvtHandler__setOORInfo(PyObject *self, PyObject *args, PyObject *kwargs) {
PyObject * _resultobj;
wxPyMake_wxSizer,
wxPyPtrTypeMap_Add,
wxArrayString2PyList_helper,
- wxArrayInt2PyList_helper
+ wxArrayInt2PyList_helper,
+
+ wxPyClientData_dtor,
+ wxPyUserData_dtor,
+ wxPyOORClientData_dtor
};
return theObj
+#----------------------------------------------------------------------------
+
+
+class _wxPyDeadObject:
+ """
+ Instances of wx objects that are OOR capable will have their __class__
+ changed to this class when the C++ object is deleted. This should help
+ prevent crashes due to referencing a bogus C++ pointer.
+ """
+ def __repr__( self ):
+ if not hasattr(self, "_name"):
+ self._name = "[unknown]"
+ return 'wxPython wrapper for deleted %s object!!! Programming logic error' % self._name
+
+ def __getattr__( self, *args ):
+ if not hasattr(self, "_name"):
+ self._name = "[unknown]"
+ raise ValueError, 'Attempt to access attribute of a deleted %s object' % self._name
+
+
#----------------------------------------------------------------------
#----------------------------------------------------------------------
self.frame.Show(true)
#----------------------------------------------------------------------------
-# DO NOT hold any other references to this object. This is how we know when
-# to cleanup system resources that wxWin is holding. When this module is
-# unloaded, the refcount on __cleanMeUp goes to zero and it calls the
-# wxApp_CleanUp function.
+# DO NOT hold any other references to this object. This is how we
+# know when to cleanup system resources that wxWin is holding. When
+# the sys module is unloaded, the refcount on sys.__wxPythonCleanup
+# goes to zero and it calls the wxApp_CleanUp function.
class __wxPyCleanup:
def __init__(self):
%addmethods {
void _setOORInfo(PyObject* _self) {
- self->SetClientObject(new wxPyClientData(_self));
+ self->SetClientObject(new wxPyOORClientData(_self));
}
}
%module utils
%{
-#include "export.h"
+#include "helpers.h"
#include <wx/config.h>
#include <wx/fileconf.h>
#include <wx/datetime.h>
//---------------------------------------------------------------------------
%{
// Put some wx default wxChar* values into wxStrings.
- static const wxChar* wxDateFormatStr = wxT("sashWindow");
- DECLARE_DEF_STRING(DateFormatStr);
+ DECLARE_DEF_STRING2(DateFormatStr, wxT("sashWindow"));
static const wxString wxPyEmptyString(wxT(""));
%}
%addmethods {
void _setOORInfo(PyObject* _self) {
- self->SetClientObject(new wxPyClientData(_self));
+ self->SetClientObject(new wxPyOORClientData(_self));
}
}
};
wxPyMake_wxSizer,
wxPyPtrTypeMap_Add,
wxArrayString2PyList_helper,
- wxArrayInt2PyList_helper
+ wxArrayInt2PyList_helper,
+
+ wxPyClientData_dtor,
+ wxPyUserData_dtor,
+ wxPyOORClientData_dtor
};