X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/33510773054b4e60aeb3715941f7e4faefafe103..8dba8632c5bcd64724e2e9e2d40e295555a0cb86:/wxPython/src/helpers.cpp diff --git a/wxPython/src/helpers.cpp b/wxPython/src/helpers.cpp index 715c3e3576..b7c8510f85 100644 --- a/wxPython/src/helpers.cpp +++ b/wxPython/src/helpers.cpp @@ -18,35 +18,44 @@ #ifdef __WXMSW__ #include -#undef FindWindow -#undef GetCharWidth -#undef LoadAccelerators -#undef GetClassInfo -#undef GetClassName +#include +#include #endif #ifdef __WXGTK__ #include #include #include -//#include -//#include -//#include +#endif -//extern GtkWidget *wxRootWindow; -#endif +//---------------------------------------------------------------------- -//--------------------------------------------------------------------------- +int WXDLLEXPORT wxEntryStart( int argc, char** argv ); +int WXDLLEXPORT wxEntryInitGui(); +void WXDLLEXPORT wxEntryCleanup(); -//wxHashTable* wxPyWindows = NULL; +wxPyApp* wxPythonApp = NULL; // Global instance of application object -wxPoint wxPyDefaultPosition; //wxDefaultPosition); -wxSize wxPyDefaultSize; //wxDefaultSize); -wxString wxPyEmptyStr(""); +#ifdef WXP_WITH_THREAD +struct wxPyThreadState { + unsigned long tid; + PyThreadState* tstate; + wxPyThreadState(unsigned long _tid=0, PyThreadState* _tstate=NULL) + : tid(_tid), tstate(_tstate) {} +}; + +#include +WX_DECLARE_OBJARRAY(wxPyThreadState, wxPyThreadStateArray); +#include +WX_DEFINE_OBJARRAY(wxPyThreadStateArray); + +wxPyThreadStateArray* wxPyTStates = NULL; +wxMutex* wxPyTMutex = NULL; +#endif #ifdef __WXMSW__ // If building for win32... @@ -66,11 +75,9 @@ BOOL WINAPI DllMain( #endif //---------------------------------------------------------------------- -// Class for implementing the wxp main application shell. +// Classes for implementing the wxp main application shell. //---------------------------------------------------------------------- -wxPyApp *wxPythonApp = NULL; // Global instance of application object - wxPyApp::wxPyApp() { // printf("**** ctor\n"); @@ -82,48 +89,47 @@ wxPyApp::~wxPyApp() { // This one isn't acutally called... See __wxStart() -bool wxPyApp::OnInit(void) { +bool wxPyApp::OnInit() { return FALSE; } -int wxPyApp::MainLoop(void) { + +int wxPyApp::MainLoop() { int retval = 0; DeletePendingObjects(); + bool initialized = wxTopLevelWindows.GetCount() != 0; #ifdef __WXGTK__ - m_initialized = wxTopLevelWindows.GetCount() != 0; + m_initialized = initialized; #endif - if (Initialized()) { + if (initialized) { retval = wxApp::MainLoop(); - wxPythonApp->OnExit(); + OnExit(); } return retval; } + //--------------------------------------------------------------------- //---------------------------------------------------------------------- -int WXDLLEXPORT wxEntryStart( int argc, char** argv ); -int WXDLLEXPORT wxEntryInitGui(); -void WXDLLEXPORT wxEntryCleanup(); - - -#ifdef WXP_WITH_THREAD -PyThreadState* wxPyEventThreadState = NULL; -#endif -static char* __nullArgv[1] = { 0 }; - // This is where we pick up the first part of the wxEntry functionality... // The rest is in __wxStart and __wxCleanup. This function is called when // wxcmodule is imported. (Before there is a wxApp object.) void __wxPreStart() { + +#ifdef __WXMSW__ + wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF); +#endif + #ifdef WXP_WITH_THREAD PyEval_InitThreads(); - wxPyEventThreadState = PyThreadState_Get(); + wxPyTStates = new wxPyThreadStateArray; + wxPyTMutex = new wxMutex; #endif // Bail out if there is already windows created. This means that the @@ -133,13 +139,17 @@ void __wxPreStart() return; + int argc = 0; + char** argv = NULL; PyObject* sysargv = PySys_GetObject("argv"); - int argc = PyList_Size(sysargv); - char** argv = new char*[argc+1]; - int x; - for(x=0; x 0) { PyErr_SetString(PyExc_TypeError, "Only 1 wxApp per process!"); return NULL; } - +#endif // This is the next part of the wxEntry functionality... + int argc = 0; + char** argv = NULL; PyObject* sysargv = PySys_GetObject("argv"); - int argc = PyList_Size(sysargv); - char** argv = new char*[argc+1]; - int x; - for(x=0; xargc = argc; wxPythonApp->argv = argv; @@ -203,13 +217,21 @@ PyObject* __wxStart(PyObject* /* self */, PyObject* args) return Py_None; } + void __wxCleanup() { wxEntryCleanup(); + delete wxPyTMutex; + wxPyTMutex = NULL; + wxPyTStates->Empty(); + delete wxPyTStates; + wxPyTStates = NULL; } -PyObject* wxPython_dict; +static PyObject* wxPython_dict = NULL; +static PyObject* wxPyPtrTypeMap = NULL; + PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args) { @@ -220,6 +242,12 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args) PyErr_SetString(PyExc_TypeError, "_wxSetDictionary must have dictionary object!"); return NULL; } + + if (! wxPyPtrTypeMap) + wxPyPtrTypeMap = PyDict_New(); + PyDict_SetItemString(wxPython_dict, "__wxPyPtrTypeMap", wxPyPtrTypeMap); + + #ifdef __WXMOTIF__ #define wxPlatform "__WXMOTIF__" #endif @@ -243,13 +271,147 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args) } +//--------------------------------------------------------------------------- +// Stuff used by OOR to find the right wxPython class type to return and to +// build it. + + +// The pointer type map is used when the "pointer" type name generated by SWIG +// 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. +void wxPyPtrTypeMap_Add(const char* commonName, const char* ptrName) { + if (! wxPyPtrTypeMap) + wxPyPtrTypeMap = PyDict_New(); + PyDict_SetItemString(wxPyPtrTypeMap, + (char*)commonName, + PyString_FromString((char*)ptrName)); +} + + + +PyObject* wxPyClassExists(const char* className) { + + if (!className) + return NULL; + + char buff[64]; // should always be big enough... + + sprintf(buff, "%sPtr", className); + PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff); + + return classobj; // returns NULL if not found +} + + +PyObject* wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) { + PyObject* target = NULL; + bool isEvtHandler = FALSE; + + if (source) { + // If it's derived from wxEvtHandler then there may + // already be a pointer to a Python object that we can use + // in the OOR data. + if (checkEvtHandler && wxIsKindOf(source, wxEvtHandler)) { + isEvtHandler = TRUE; + wxEvtHandler* eh = (wxEvtHandler*)source; + wxPyClientData* data = (wxPyClientData*)eh->GetClientObject(); + if (data) { + target = data->m_obj; + Py_INCREF(target); + } + } + + if (! target) { + // Otherwise make it the old fashioned way by making a + // new shadow object and putting this pointer in it. + wxClassInfo* info = source->GetClassInfo(); + wxChar* name = (wxChar*)info->GetClassName(); + PyObject* klass = wxPyClassExists(name); + while (info && !klass) { + name = (wxChar*)info->GetBaseClassName1(); + info = wxClassInfo::FindClass(name); + klass = wxPyClassExists(name); + } + if (info) { + target = wxPyConstructObject(source, name, klass, FALSE); + if (target && isEvtHandler) + ((wxEvtHandler*)source)->SetClientObject(new wxPyClientData(target)); + } else { + wxString msg("wxPython class not found for "); + msg += source->GetClassInfo()->GetClassName(); + PyErr_SetString(PyExc_NameError, msg.c_str()); + target = NULL; + } + } + } else { // source was NULL so return None. + Py_INCREF(Py_None); target = Py_None; + } + return target; +} + + +PyObject* wxPyMake_wxSizer(wxSizer* source) { + PyObject* target = NULL; + + if (source && wxIsKindOf(source, wxSizer)) { + // If it's derived from wxSizer then there may + // 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(); + 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)); + } + return target; +} + + + //--------------------------------------------------------------------------- PyObject* wxPyConstructObject(void* ptr, - const char* className, - int setThisOwn) { + const char* className, + PyObject* klass, + int setThisOwn) { + PyObject* obj; PyObject* arg; + PyObject* item; + char swigptr[64]; // should always be big enough... + char buff[64]; + + if ((item = PyDict_GetItemString(wxPyPtrTypeMap, (char*)className)) != NULL) { + className = PyString_AsString(item); + } + sprintf(buff, "_%s_p", className); + SWIG_MakePtr(swigptr, ptr, buff); + + arg = Py_BuildValue("(s)", swigptr); + obj = PyInstance_New(klass, arg, NULL); + Py_DECREF(arg); + + if (setThisOwn) { + PyObject* one = PyInt_FromLong(1); + PyObject_SetAttrString(obj, "thisown", one); + Py_DECREF(one); + } + + return obj; +} + + +PyObject* wxPyConstructObject(void* ptr, + const char* className, + int setThisOwn) { + PyObject* obj; if (!ptr) { Py_INCREF(Py_None); @@ -257,16 +419,12 @@ PyObject* wxPyConstructObject(void* ptr, } char buff[64]; // should always be big enough... - char swigptr[64]; + sprintf(buff, "%sPtr", className); - sprintf(buff, "_%s_p", className); - SWIG_MakePtr(swigptr, ptr, buff); + wxASSERT_MSG(wxPython_dict, "wxPython_dict is not set yet!!"); - sprintf(buff, "%sPtr", className); PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff); if (! classobj) { - //Py_INCREF(Py_None); - //return Py_None; char temp[128]; sprintf(temp, "*** Unknown class name %s, tell Robin about it please ***", @@ -275,60 +433,112 @@ PyObject* wxPyConstructObject(void* ptr, return obj; } - arg = Py_BuildValue("(s)", swigptr); - obj = PyInstance_New(classobj, arg, NULL); - Py_DECREF(arg); + return wxPyConstructObject(ptr, className, classobj, setThisOwn); +} - if (setThisOwn) { - PyObject_SetAttrString(obj, "thisown", PyInt_FromLong(1)); +//--------------------------------------------------------------------------- + +// TODO: This should really be wxThread::GetCurrentId(), and I will do so +// after I make a quick 2.3.2.1 release. +#ifdef WXP_WITH_THREAD +#ifdef __WXGTK__ // does wxGTK always use pthreads? +#include +#include +#endif +inline +unsigned long wxPyGetCurrentThreadId() { +#ifdef __WXMSW__ + return (unsigned long)::GetCurrentThreadId(); +#endif +#ifdef __WXGTK__ // does wxGTK always use pthreads? + return (unsigned long)pthread_self(); +#endif +#ifdef __WXMAC__ +#error Fix this! +#endif +} + + + +static +PyThreadState* wxPyGetThreadState() { + unsigned long ctid = wxPyGetCurrentThreadId(); + PyThreadState* tstate = NULL; + + wxPyTMutex->Lock(); + for(size_t i=0; i < wxPyTStates->GetCount(); i++) { + wxPyThreadState& info = wxPyTStates->Item(i); + if (info.tid == ctid) { + tstate = info.tstate; + break; + } } + wxPyTMutex->Unlock(); + wxASSERT_MSG(tstate, "PyThreadState should not be NULL!"); + return tstate; +} - return obj; +static +void wxPySaveThreadState(PyThreadState* tstate) { + unsigned long ctid = wxPyGetCurrentThreadId(); + wxPyTMutex->Lock(); + for(size_t i=0; i < wxPyTStates->GetCount(); i++) { + wxPyThreadState& info = wxPyTStates->Item(i); + if (info.tid == ctid) { + info.tstate = tstate; + wxPyTMutex->Unlock(); + return; + } + } + // not found, so add it... + wxPyTStates->Add(new wxPyThreadState(ctid, tstate)); + wxPyTMutex->Unlock(); } -//--------------------------------------------------------------------------- +#endif -static unsigned int _wxPyNestCount = 0; -static PyThreadState* myPyThreadState_Get() { - PyThreadState* current; - current = PyThreadState_Swap(NULL); - PyThreadState_Swap(current); - return current; +// Calls from Python to wxWindows code are wrapped in calls to these +// functions: + +PyThreadState* wxPyBeginAllowThreads() { +#ifdef WXP_WITH_THREAD + PyThreadState* saved = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS; + wxPySaveThreadState(saved); + return saved; +#else + return NULL; +#endif } +void wxPyEndAllowThreads(PyThreadState* saved) { +#ifdef WXP_WITH_THREAD + PyEval_RestoreThread(saved); // Py_END_ALLOW_THREADS; +#endif +} + + + +// Calls from wxWindows back to Python code, or even any PyObject +// manipulations, PyDECREF's and etc. are wrapped in calls to these functions: -HELPEREXPORT bool wxPyRestoreThread() { - // NOTE: The Python API docs state that if a thread already has the - // interpreter lock and calls PyEval_RestoreThread again a deadlock - // occurs, so I put in this code as a guard condition since there are - // many possibilites for nested events and callbacks in wxPython. If - // The current thread is our thread, then we can assume that we - // already have the lock. (I hope!) - // +void wxPyBeginBlockThreads() { #ifdef WXP_WITH_THREAD - _wxPyNestCount += 1; - if (wxPyEventThreadState != myPyThreadState_Get()) { - PyEval_RestoreThread(wxPyEventThreadState); - return TRUE; - } - else + PyThreadState* tstate = wxPyGetThreadState(); + PyEval_RestoreThread(tstate); #endif - return FALSE; } -HELPEREXPORT void wxPySaveThread(bool doSave) { +void wxPyEndBlockThreads() { #ifdef WXP_WITH_THREAD - if (doSave) { - wxPyEventThreadState = PyEval_SaveThread(); - } - _wxPyNestCount -= 1; + PyThreadState* tstate = PyEval_SaveThread(); + // Is there any need to save it again? #endif } -//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- IMPLEMENT_ABSTRACT_CLASS(wxPyCallback, wxObject); @@ -343,9 +553,9 @@ wxPyCallback::wxPyCallback(const wxPyCallback& other) { } wxPyCallback::~wxPyCallback() { - bool doSave = wxPyRestoreThread(); + wxPyBeginBlockThreads(); Py_DECREF(m_func); - wxPySaveThread(doSave); + wxPyEndBlockThreads(); } @@ -359,7 +569,7 @@ void wxPyCallback::EventThunker(wxEvent& event) { PyObject* tuple; - bool doSave = wxPyRestoreThread(); + wxPyBeginBlockThreads(); wxString className = event.GetClassInfo()->GetClassName(); if (className == "wxPyEvent") @@ -375,33 +585,16 @@ void wxPyCallback::EventThunker(wxEvent& event) { Py_DECREF(tuple); if (result) { Py_DECREF(result); - PyErr_Clear(); + PyErr_Clear(); // Just in case... } else { PyErr_Print(); } - wxPySaveThread(doSave); + wxPyEndBlockThreads(); } //---------------------------------------------------------------------- -wxPyCallbackHelper::wxPyCallbackHelper() { - m_class = NULL; - m_self = NULL; - m_lastFound = NULL; - m_incRef = FALSE; -} - - -wxPyCallbackHelper::~wxPyCallbackHelper() { - bool doSave = wxPyRestoreThread(); - if (m_incRef) { - Py_XDECREF(m_self); - Py_XDECREF(m_class); - } - wxPySaveThread(doSave); -} - wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper& other) { m_lastFound = NULL; m_self = other.m_self; @@ -424,22 +617,106 @@ void wxPyCallbackHelper::setSelf(PyObject* self, PyObject* klass, int incref) { } -// If the object (m_self) has an attibute of the given name, and if that -// attribute is a method, and if that method's class is not from a base class, -// then we'll save a pointer to the method so callCallback can call it. -bool wxPyCallbackHelper::findCallback(const wxString& name) const { +#if PYTHON_API_VERSION >= 1011 + +// Prior to Python 2.2 PyMethod_GetClass returned the class object +// in which the method was defined. Starting with 2.2 it returns +// "class that asked for the method" which seems totally bogus to me +// but apprently if fixes some obscure problem waiting to happen in +// Python. Since the API was not documented Guido and the gang felt +// safe in changing it. Needless to say that totally screwed up the +// logic below in wxPyCallbackHelper::findCallback, hence this icky +// code to find the class where the method is actuallt defined... + +static +PyObject* PyFindClassWithAttr(PyObject *klass, PyObject *name) +{ + int i, n; + + if (PyType_Check(klass)) { // new style classes + // This code is borrowed/adapted from _PyType_Lookup in typeobject.c + // (TODO: This part is not tested yet, so I'm not sure it is correct...) + PyTypeObject* type = (PyTypeObject*)klass; + PyObject *mro, *res, *base, *dict; + /* Look in tp_dict of types in MRO */ + mro = type->tp_mro; + assert(PyTuple_Check(mro)); + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + base = PyTuple_GET_ITEM(mro, i); + if (PyClass_Check(base)) + dict = ((PyClassObject *)base)->cl_dict; + else { + assert(PyType_Check(base)); + dict = ((PyTypeObject *)base)->tp_dict; + } + assert(dict && PyDict_Check(dict)); + res = PyDict_GetItem(dict, name); + if (res != NULL) + return base; + } + return NULL; + } + + else if (PyClass_Check(klass)) { // old style classes + // This code is borrowed/adapted from class_lookup in classobject.c + PyClassObject* cp = (PyClassObject*)klass; + PyObject *value = PyDict_GetItem(cp->cl_dict, name); + if (value != NULL) { + return (PyObject*)cp; + } + n = PyTuple_Size(cp->cl_bases); + for (i = 0; i < n; i++) { + PyObject* base = PyTuple_GetItem(cp->cl_bases, i); + PyObject *v = PyFindClassWithAttr(base, name); + if (v != NULL) + return v; + } + return NULL; + } +} +#endif + + +static +PyObject* PyMethod_GetDefiningClass(PyObject* method, const char* name) +{ + PyObject* mgc = PyMethod_GET_CLASS(method); + +#if PYTHON_API_VERSION <= 1010 // prior to Python 2.2, the easy way + return mgc; +#else // 2.2 and after, the hard way... + + PyObject* nameo = PyString_FromString(name); + PyObject* klass = PyFindClassWithAttr(mgc, nameo); + Py_DECREF(nameo); + return klass; +#endif +} + + + +bool wxPyCallbackHelper::findCallback(const char* name) const { wxPyCallbackHelper* self = (wxPyCallbackHelper*)this; // cast away const self->m_lastFound = NULL; - if (m_self && PyObject_HasAttrString(m_self, (char*)name.c_str())) { - PyObject* method; - method = PyObject_GetAttrString(m_self, (char*)name.c_str()); + // If the object (m_self) has an attibute of the given name... + if (m_self && PyObject_HasAttrString(m_self, (char*)name)) { + PyObject *method, *klass; + method = PyObject_GetAttrString(m_self, (char*)name); + + // ...and if that attribute is a method, and if that method's class is + // not from a base class... if (PyMethod_Check(method) && - ((PyMethod_GET_CLASS(method) == m_class) || - PyClass_IsSubclass(PyMethod_GET_CLASS(method), m_class))) { + (klass = PyMethod_GetDefiningClass(method, (char*)name)) != NULL && + ((klass == m_class) || PyClass_IsSubclass(klass, m_class))) { + // ...then we'll save a pointer to the method so callCallback can call it. self->m_lastFound = method; } + else { + Py_DECREF(method); + } } return m_lastFound != NULL; } @@ -461,10 +738,16 @@ int wxPyCallbackHelper::callCallback(PyObject* argTuple) const { // Invoke the Python callable object, returning the raw PyObject return // value. Caller should DECREF the return value and also call PyEval_SaveThread. PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) const { - PyObject* result; + PyObject* result; + + // Save a copy of the pointer in case the callback generates another + // callback. In that case m_lastFound will have a different value when + // it gets back here... + PyObject* method = m_lastFound; - result = PyEval_CallObject(m_lastFound, argTuple); + result = PyEval_CallObject(method, argTuple); Py_DECREF(argTuple); + Py_DECREF(method); if (!result) { PyErr_Print(); } @@ -472,10 +755,35 @@ PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) const { } +void wxPyCBH_setCallbackInfo(wxPyCallbackHelper& cbh, PyObject* self, PyObject* klass, int incref) { + cbh.setSelf(self, klass, incref); +} + +bool wxPyCBH_findCallback(const wxPyCallbackHelper& cbh, const char* name) { + return cbh.findCallback(name); +} + +int wxPyCBH_callCallback(const wxPyCallbackHelper& cbh, PyObject* argTuple) { + return cbh.callCallback(argTuple); +} + +PyObject* wxPyCBH_callCallbackObj(const wxPyCallbackHelper& cbh, PyObject* argTuple) { + return cbh.callCallbackObj(argTuple); +} + + +void wxPyCBH_delete(wxPyCallbackHelper* cbh) { + if (cbh->m_incRef) { + wxPyBeginBlockThreads(); + Py_XDECREF(cbh->m_self); + Py_XDECREF(cbh->m_class); + wxPyEndBlockThreads(); + } +} //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- -// These classes can be derived from in Python and passed through the event +// These event classes can be derived from in Python and passed through the event // system without losing anything. They do this by keeping a reference to // themselves and some special case handling in wxPyCallback::EventThunker. @@ -487,14 +795,14 @@ wxPyEvtSelfRef::wxPyEvtSelfRef() { } wxPyEvtSelfRef::~wxPyEvtSelfRef() { - bool doSave = wxPyRestoreThread(); + wxPyBeginBlockThreads(); if (m_cloned) Py_DECREF(m_self); - wxPySaveThread(doSave); + wxPyEndBlockThreads(); } void wxPyEvtSelfRef::SetSelf(PyObject* self, bool clone) { - bool doSave = wxPyRestoreThread(); + wxPyBeginBlockThreads(); if (m_cloned) Py_DECREF(m_self); m_self = self; @@ -502,7 +810,7 @@ void wxPyEvtSelfRef::SetSelf(PyObject* self, bool clone) { Py_INCREF(m_self); m_cloned = TRUE; } - wxPySaveThread(doSave); + wxPyEndBlockThreads(); } PyObject* wxPyEvtSelfRef::GetSelf() const { @@ -511,37 +819,41 @@ PyObject* wxPyEvtSelfRef::GetSelf() const { } +IMPLEMENT_ABSTRACT_CLASS(wxPyEvent, wxEvent); +IMPLEMENT_ABSTRACT_CLASS(wxPyCommandEvent, wxCommandEvent); + + wxPyEvent::wxPyEvent(int id) : wxEvent(id) { } -wxPyEvent::~wxPyEvent() { -} -// This one is so the event object can be Cloned... -void wxPyEvent::CopyObject(wxObject& dest) const { - wxEvent::CopyObject(dest); - ((wxPyEvent*)&dest)->SetSelf(m_self, TRUE); +wxPyEvent::wxPyEvent(const wxPyEvent& evt) + : wxEvent(evt) +{ + SetSelf(evt.m_self, TRUE); } -IMPLEMENT_DYNAMIC_CLASS(wxPyEvent, wxEvent); +wxPyEvent::~wxPyEvent() { +} wxPyCommandEvent::wxPyCommandEvent(wxEventType commandType, int id) : wxCommandEvent(commandType, id) { } -wxPyCommandEvent::~wxPyCommandEvent() { -} -void wxPyCommandEvent::CopyObject(wxObject& dest) const { - wxCommandEvent::CopyObject(dest); - ((wxPyCommandEvent*)&dest)->SetSelf(m_self, TRUE); +wxPyCommandEvent::wxPyCommandEvent(const wxPyCommandEvent& evt) + : wxCommandEvent(evt) +{ + SetSelf(evt.m_self, TRUE); } -IMPLEMENT_DYNAMIC_CLASS(wxPyCommandEvent, wxCommandEvent); +wxPyCommandEvent::~wxPyCommandEvent() { +} + @@ -555,26 +867,32 @@ wxPyTimer::wxPyTimer(PyObject* callback) { } wxPyTimer::~wxPyTimer() { - bool doSave = wxPyRestoreThread(); + wxPyBeginBlockThreads(); Py_DECREF(func); - wxPySaveThread(doSave); + wxPyEndBlockThreads(); } void wxPyTimer::Notify() { - bool doSave = wxPyRestoreThread(); - - PyObject* result; - PyObject* args = Py_BuildValue("()"); + if (!func || func == Py_None) { + wxTimer::Notify(); + } + else { + wxPyBeginBlockThreads(); + + PyObject* result; + PyObject* args = Py_BuildValue("()"); + + result = PyEval_CallObject(func, args); + Py_DECREF(args); + if (result) { + Py_DECREF(result); + PyErr_Clear(); + } else { + PyErr_Print(); + } - result = PyEval_CallObject(func, args); - Py_DECREF(args); - if (result) { - Py_DECREF(result); - PyErr_Clear(); - } else { - PyErr_Print(); + wxPyEndBlockThreads(); } - wxPySaveThread(doSave); } @@ -589,15 +907,15 @@ PyObject* wxPy_ConvertList(wxListBase* list, const char* className) { wxObject* wxObj; wxNode* node = list->First(); - bool doSave = wxPyRestoreThread(); + wxPyBeginBlockThreads(); pyList = PyList_New(0); while (node) { wxObj = node->Data(); - pyObj = wxPyConstructObject(wxObj, className); + pyObj = wxPyMake_wxObject(wxObj); //wxPyConstructObject(wxObj, className); PyList_Append(pyList, pyObj); node = node->Next(); } - wxPySaveThread(doSave); + wxPyEndBlockThreads(); return pyList; } @@ -716,43 +1034,116 @@ char** string_LIST_helper(PyObject* source) { return temp; } +//-------------------------------- +// Part of patch from Tim Hochberg +static inline bool wxPointFromObjects(PyObject* o1, PyObject* o2, wxPoint* point) { + if (PyInt_Check(o1) && PyInt_Check(o2)) { + point->x = PyInt_AS_LONG(o1); + point->y = PyInt_AS_LONG(o2); + return true; + } + if (PyFloat_Check(o1) && PyFloat_Check(o2)) { + point->x = (int)PyFloat_AS_DOUBLE(o1); + point->y = (int)PyFloat_AS_DOUBLE(o2); + return true; + } + if (PyInstance_Check(o1) || PyInstance_Check(o2)) { + // Disallow instances because they can cause havok + return false; + } + if (PyNumber_Check(o1) && PyNumber_Check(o2)) { + // I believe this excludes instances, so this should be safe without INCREFFing o1 and o2 + point->x = PyInt_AsLong(o1); + point->y = PyInt_AsLong(o2); + return true; + } + return false; +} -wxPoint* wxPoint_LIST_helper(PyObject* source) { - if (!PyList_Check(source)) { - PyErr_SetString(PyExc_TypeError, "Expected a list object."); - return NULL; +wxPoint* wxPoint_LIST_helper(PyObject* source, int *count) { + // Putting all of the declarations here allows + // us to put the error handling all in one place. + int x; + wxPoint* temp; + PyObject *o, *o1, *o2; + bool isFast = PyList_Check(source) || PyTuple_Check(source); + + if (!PySequence_Check(source)) { + goto error0; } - int count = PyList_Size(source); - wxPoint* temp = new wxPoint[count]; - if (! temp) { + + // The length of the sequence is returned in count. + *count = PySequence_Length(source); + if (*count < 0) { + goto error0; + } + + temp = new wxPoint[*count]; + if (!temp) { PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array"); return NULL; } - for (int x=0; x= 1009 + if (! PyString_Check(o) && ! PyUnicode_Check(o)) { + PyErr_SetString(PyExc_TypeError, "Expected a list of string or unicode objects."); + return NULL; + } + + char* buff; + int length; + if (PyString_AsStringAndSize(o, &buff, &length) == -1) + return NULL; + temp[x] = wxString(buff, length); +#else if (! PyString_Check(o)) { PyErr_SetString(PyExc_TypeError, "Expected a list of strings."); return NULL; } temp[x] = PyString_AsString(o); +#endif } return temp; } @@ -834,10 +1238,7 @@ wxAcceleratorEntry* wxAcceleratorEntry_LIST_helper(PyObject* source) { PyObject* o1 = PyTuple_GetItem(o, 0); PyObject* o2 = PyTuple_GetItem(o, 1); PyObject* o3 = PyTuple_GetItem(o, 2); - - temp[x].m_flags = PyInt_AsLong(o1); - temp[x].m_keyCode = PyInt_AsLong(o2); - temp[x].m_command = PyInt_AsLong(o3); + temp[x].Set(PyInt_AsLong(o1), PyInt_AsLong(o2), PyInt_AsLong(o3)); } else { PyErr_SetString(PyExc_TypeError, "Expected a list of 3-tuples or wxAcceleratorEntry objects."); @@ -848,6 +1249,99 @@ wxAcceleratorEntry* wxAcceleratorEntry_LIST_helper(PyObject* source) { } +wxPen** wxPen_LIST_helper(PyObject* source) { + if (!PyList_Check(source)) { + PyErr_SetString(PyExc_TypeError, "Expected a list object."); + return NULL; + } + int count = PyList_Size(source); + wxPen** temp = new wxPen*[count]; + if (!temp) { + PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array"); + return NULL; + } + for (int x=0; x