A little black magic... When the C++ object (for a window or
whatever) is deleted there is no way to force the Python shadow object to also be destroyed and clean up all references to it. This leads to crashes if the shadow object tries to call a method with the old C++ pointer... The black magic I've done is to replace the __class__ in the Python instanc object with a class that raises an exception whenever a method call is attempted. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15059 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -172,7 +172,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) {
|
||||
// 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);
|
||||
@@ -181,7 +181,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) {
|
||||
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;
|
||||
}
|
||||
|
@@ -221,7 +221,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) {
|
||||
// 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);
|
||||
@@ -230,7 +230,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) {
|
||||
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;
|
||||
}
|
||||
|
@@ -1249,7 +1249,7 @@ static PyObject *_wrap_wxPyShapeEvtHandler_Destroy(PyObject *self, PyObject *arg
|
||||
}
|
||||
|
||||
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;
|
||||
|
@@ -99,7 +99,7 @@ public:
|
||||
%addmethods { void Destroy() { delete self; } }
|
||||
%addmethods {
|
||||
void _setOORInfo(PyObject* _self) {
|
||||
self->SetClientObject(new wxPyClientData(_self));
|
||||
self->SetClientObject(new wxPyOORClientData(_self));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -647,6 +647,26 @@ def wxPyTypeCast(obj, typeStr):
|
||||
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
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
@@ -763,10 +783,10 @@ class wxPyWidgetTester(wxApp):
|
||||
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):
|
||||
|
@@ -74,6 +74,9 @@ static void wxPyCoreAPI_IMPORT() {
|
||||
#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.
|
||||
|
@@ -295,6 +295,7 @@ void __wxCleanup() {
|
||||
static PyObject* wxPython_dict = NULL;
|
||||
static PyObject* wxPyPtrTypeMap = NULL;
|
||||
|
||||
|
||||
PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
|
||||
{
|
||||
|
||||
@@ -334,6 +335,52 @@ 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
|
||||
@@ -344,6 +391,7 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
|
||||
// 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();
|
||||
@@ -379,7 +427,7 @@ PyObject* wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) {
|
||||
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);
|
||||
@@ -400,9 +448,9 @@ PyObject* wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) {
|
||||
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;
|
||||
@@ -423,7 +471,7 @@ PyObject* wxPyMake_wxSizer(wxSizer* source) {
|
||||
// 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);
|
||||
@@ -432,7 +480,7 @@ PyObject* wxPyMake_wxSizer(wxSizer* source) {
|
||||
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;
|
||||
}
|
||||
|
@@ -101,6 +101,9 @@ bool wxRealPoint_helper(PyObject* source, wxRealPoint** obj);
|
||||
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))
|
||||
@@ -113,9 +116,9 @@ bool _4int_seq_helper(PyObject* source, int* i1, int* i2, int* i3, int* i4);
|
||||
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)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
@@ -201,6 +204,18 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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
|
||||
@@ -256,12 +271,70 @@ struct wxPyCoreAPI {
|
||||
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 may not use it.
|
||||
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
|
||||
wxPyCoreAPIPtr->p_wxPyOORClientData_dtor(this);
|
||||
#else
|
||||
wxPyOORClientData_dtor(this);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// This class holds an instance of a Python Shadow Class object and assists
|
||||
// with looking up and invoking Python callback methods from C++ virtual
|
||||
@@ -312,53 +385,6 @@ void wxPyCBH_delete(wxPyCallbackHelper* cbh);
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
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
|
||||
|
@@ -866,14 +866,14 @@ class wxBufferedDC(wxBufferedDCPtr):
|
||||
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
|
||||
|
||||
|
||||
|
@@ -860,7 +860,7 @@ static void *SwigwxSizerTowxObject(void *ptr) {
|
||||
}
|
||||
|
||||
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;
|
||||
|
@@ -55,14 +55,13 @@ extern PyObject *SWIG_newvarlink(void);
|
||||
|
||||
#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(""));
|
||||
|
||||
|
||||
|
@@ -548,7 +548,7 @@ static PyObject *_wrap_wxEvtHandler_Disconnect(PyObject *self, PyObject *args, P
|
||||
}
|
||||
|
||||
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;
|
||||
|
@@ -677,7 +677,11 @@ static wxPyCoreAPI API = {
|
||||
wxPyMake_wxSizer,
|
||||
wxPyPtrTypeMap_Add,
|
||||
wxArrayString2PyList_helper,
|
||||
wxArrayInt2PyList_helper
|
||||
wxArrayInt2PyList_helper,
|
||||
|
||||
wxPyClientData_dtor,
|
||||
wxPyUserData_dtor,
|
||||
wxPyOORClientData_dtor
|
||||
};
|
||||
|
||||
|
||||
|
@@ -1554,6 +1554,26 @@ def wxPyTypeCast(obj, typeStr):
|
||||
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
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
@@ -1670,10 +1690,10 @@ class wxPyWidgetTester(wxApp):
|
||||
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):
|
||||
|
@@ -97,7 +97,7 @@ public:
|
||||
|
||||
%addmethods {
|
||||
void _setOORInfo(PyObject* _self) {
|
||||
self->SetClientObject(new wxPyClientData(_self));
|
||||
self->SetClientObject(new wxPyOORClientData(_self));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,7 +14,7 @@
|
||||
%module utils
|
||||
|
||||
%{
|
||||
#include "export.h"
|
||||
#include "helpers.h"
|
||||
#include <wx/config.h>
|
||||
#include <wx/fileconf.h>
|
||||
#include <wx/datetime.h>
|
||||
@@ -23,8 +23,7 @@
|
||||
//---------------------------------------------------------------------------
|
||||
%{
|
||||
// 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(""));
|
||||
|
||||
%}
|
||||
|
@@ -87,7 +87,7 @@ public:
|
||||
|
||||
%addmethods {
|
||||
void _setOORInfo(PyObject* _self) {
|
||||
self->SetClientObject(new wxPyClientData(_self));
|
||||
self->SetClientObject(new wxPyOORClientData(_self));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -202,7 +202,11 @@ static wxPyCoreAPI API = {
|
||||
wxPyMake_wxSizer,
|
||||
wxPyPtrTypeMap_Add,
|
||||
wxArrayString2PyList_helper,
|
||||
wxArrayInt2PyList_helper
|
||||
wxArrayInt2PyList_helper,
|
||||
|
||||
wxPyClientData_dtor,
|
||||
wxPyUserData_dtor,
|
||||
wxPyOORClientData_dtor
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user