X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f6bcfd974ef26faf6f91a62cac09827e09463fd1..9cf99fc093f9c45b6b5d8d8b357699d826c9916a:/wxPython/src/helpers.cpp diff --git a/wxPython/src/helpers.cpp b/wxPython/src/helpers.cpp index 32578bf5f6..131ed8b56d 100644 --- a/wxPython/src/helpers.cpp +++ b/wxPython/src/helpers.cpp @@ -29,24 +29,9 @@ #include #include #include -//#include -//#include -//#include - -//extern GtkWidget *wxRootWindow; - #endif -//--------------------------------------------------------------------------- - -//wxHashTable* wxPyWindows = NULL; - - -wxPoint wxPyDefaultPosition; //wxDefaultPosition); -wxSize wxPyDefaultSize; //wxDefaultSize); -wxString wxPyEmptyStr(""); - #ifdef __WXMSW__ // If building for win32... @@ -105,6 +90,11 @@ int wxPyApp::MainLoop(void) { //--------------------------------------------------------------------- //---------------------------------------------------------------------- +#ifdef __WXMSW__ +#include "wx/msw/msvcrt.h" +#endif + + int WXDLLEXPORT wxEntryStart( int argc, char** argv ); int WXDLLEXPORT wxEntryInitGui(); void WXDLLEXPORT wxEntryCleanup(); @@ -113,7 +103,6 @@ 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... @@ -121,9 +110,14 @@ static char* __nullArgv[1] = { 0 }; // 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(); + wxPyEventThreadState = PyThreadState_Get(); // PyThreadState_New(PyThreadState_Get()->interp); #endif // Bail out if there is already windows created. This means that the @@ -133,13 +127,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; @@ -209,7 +211,9 @@ void __wxCleanup() { -PyObject* wxPython_dict; +static PyObject* wxPython_dict = NULL; +static PyObject* wxPyPtrTypeMap = NULL; + PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args) { @@ -220,6 +224,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 @@ -244,32 +254,126 @@ 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; -PyObject* wxPyConstructObject(void* ptr, const char* className) { char buff[64]; // should always be big enough... - char swigptr[64]; + sprintf(buff, "%sPtr", className); + PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff); + + return classobj; // returns NULL if not found +} + + +PyObject* wxPyMake_wxObject(wxObject* source) { + PyObject* target; + + if (source) { + 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); + } 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* wxPyConstructObject(void* ptr, + 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); - sprintf(buff, "%sPtr", className); - PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff); - if (! classobj) { + 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); return Py_None; } - PyObject* arg = Py_BuildValue("(s)", swigptr); - PyObject* obj = PyInstance_New(classobj, arg, NULL); - Py_DECREF(arg); + char buff[64]; // should always be big enough... - return obj; + sprintf(buff, "%sPtr", className); + PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff); + if (! classobj) { + char temp[128]; + sprintf(temp, + "*** Unknown class name %s, tell Robin about it please ***", + buff); + obj = PyString_FromString(temp); + return obj; + } + + return wxPyConstructObject(ptr, className, classobj, setThisOwn); } //--------------------------------------------------------------------------- -static unsigned int _wxPyNestCount = 0; - static PyThreadState* myPyThreadState_Get() { PyThreadState* current; current = PyThreadState_Swap(NULL); @@ -278,7 +382,7 @@ static PyThreadState* myPyThreadState_Get() { } -HELPEREXPORT bool wxPyRestoreThread() { +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 @@ -287,9 +391,8 @@ HELPEREXPORT bool wxPyRestoreThread() { // already have the lock. (I hope!) // #ifdef WXP_WITH_THREAD - _wxPyNestCount += 1; if (wxPyEventThreadState != myPyThreadState_Get()) { - PyEval_RestoreThread(wxPyEventThreadState); + PyEval_AcquireThread(wxPyEventThreadState); return TRUE; } else @@ -298,18 +401,16 @@ HELPEREXPORT bool wxPyRestoreThread() { } -HELPEREXPORT void wxPySaveThread(bool doSave) { +void wxPySaveThread(bool doSave) { #ifdef WXP_WITH_THREAD if (doSave) { - wxPyEventThreadState = PyEval_SaveThread(); + PyEval_ReleaseThread(wxPyEventThreadState); } - _wxPyNestCount -= 1; #endif } //--------------------------------------------------------------------------- - IMPLEMENT_ABSTRACT_CLASS(wxPyCallback, wxObject); wxPyCallback::wxPyCallback(PyObject* func) { @@ -355,7 +456,7 @@ void wxPyCallback::EventThunker(wxEvent& event) { Py_DECREF(tuple); if (result) { Py_DECREF(result); - PyErr_Clear(); + PyErr_Clear(); // Just in case... } else { PyErr_Print(); } @@ -365,23 +466,6 @@ void wxPyCallback::EventThunker(wxEvent& event) { //---------------------------------------------------------------------- -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; @@ -393,9 +477,9 @@ wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper& other) { } -void wxPyCallbackHelper::setSelf(PyObject* self, PyObject* _class, int incref) { +void wxPyCallbackHelper::setSelf(PyObject* self, PyObject* klass, int incref) { m_self = self; - m_class = _class; + m_class = klass; m_incRef = incref; if (incref) { Py_INCREF(m_self); @@ -407,12 +491,12 @@ void wxPyCallbackHelper::setSelf(PyObject* self, PyObject* _class, 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 { +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())) { + if (m_self && PyObject_HasAttrString(m_self, (char*)name)) { PyObject* method; - method = PyObject_GetAttrString(m_self, (char*)name.c_str()); + method = PyObject_GetAttrString(m_self, (char*)name); if (PyMethod_Check(method) && ((PyMethod_GET_CLASS(method) == m_class) || @@ -420,6 +504,9 @@ bool wxPyCallbackHelper::findCallback(const wxString& name) const { self->m_lastFound = method; } + else { + Py_DECREF(method); + } } return m_lastFound != NULL; } @@ -441,10 +528,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(); } @@ -452,11 +545,36 @@ PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) const { } +void wxPyCBH_setSelf(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) { + bool doSave = wxPyRestoreThread(); + if (cbh->m_incRef) { + Py_XDECREF(cbh->m_self); + Py_XDECREF(cbh->m_class); + } + wxPySaveThread(doSave); +} //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // These classes can be derived from in Python and passed through the event -// system without loosing anything. They do this by keeping a reference to +// system without losing anything. They do this by keeping a reference to // themselves and some special case handling in wxPyCallback::EventThunker. @@ -541,20 +659,26 @@ wxPyTimer::~wxPyTimer() { } void wxPyTimer::Notify() { - bool doSave = wxPyRestoreThread(); - - PyObject* result; - PyObject* args = Py_BuildValue("()"); + if (!func || func == Py_None) { + wxTimer::Notify(); + } + else { + bool doSave = wxPyRestoreThread(); + + 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(); + wxPySaveThread(doSave); } - wxPySaveThread(doSave); } @@ -573,7 +697,7 @@ PyObject* wxPy_ConvertList(wxListBase* list, const char* className) { 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(); } @@ -696,43 +820,120 @@ 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; +#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)) +#endif + +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; + int isFast = PyList_Check(source) || PyTuple_Check(source); + + // The length of the sequence is returned in count. + if (!PySequence_Check(source)) { + goto error0; } - int count = PyList_Size(source); - wxPoint* temp = new wxPoint[count]; - if (! temp) { + *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