X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/15c892875cf6f35490abc837031f2d904a1d3d93..12e7f72a35d947b2d5ae799bfd754b15eb9f6af2:/wxPython/src/helpers.cpp diff --git a/wxPython/src/helpers.cpp b/wxPython/src/helpers.cpp index a1a20b66fa..963d0c58df 100644 --- a/wxPython/src/helpers.cpp +++ b/wxPython/src/helpers.cpp @@ -15,6 +15,7 @@ #include #include "wx/wxPython/wxPython_int.h" #include "wx/wxPython/pyistream.h" +#include "wx/wxPython/swigver.h" #ifdef __WXMSW__ #include @@ -29,8 +30,8 @@ #include #include #define GetXWindow(wxwin) (wxwin)->m_wxwindow ? \ - GDK_WINDOW_XWINDOW(GTK_PIZZA((wxwin)->m_wxwindow)->bin_window) : \ - GDK_WINDOW_XWINDOW((wxwin)->m_widget->window) + GDK_WINDOW_XWINDOW(GTK_PIZZA((wxwin)->m_wxwindow)->bin_window) : \ + GDK_WINDOW_XWINDOW((wxwin)->m_widget->window) #include #endif @@ -176,6 +177,18 @@ int wxPyApp::OnExit() { } + +void wxPyApp::ExitMainLoop() { + bool found; + wxPyBlock_t blocked = wxPyBeginBlockThreads(); + if ((found = wxPyCBH_findCallback(m_myInst, "ExitMainLoop"))) + wxPyCBH_callCallback(m_myInst, Py_BuildValue("()")); + wxPyEndBlockThreads(blocked); + if (! found) + wxApp::ExitMainLoop(); +} + + #ifdef __WXDEBUG__ void wxPyApp::OnAssert(const wxChar *file, int line, @@ -467,6 +480,7 @@ void wxPyApp::_BootstrapApp() PyObject* method = m_myInst.GetLastFound(); PyObject* argTuple = PyTuple_New(0); retval = PyEval_CallObject(method, argTuple); + m_myInst.clearRecursionGuard(method); Py_DECREF(argTuple); Py_DECREF(method); if (retval == NULL) @@ -690,7 +704,8 @@ PyObject* __wxPySetDictionary(PyObject* /* self */, PyObject* args) #else _AddInfoString("wx-assertions-off"); #endif - + _AddInfoString(wxPy_SWIG_VERSION); + #undef _AddInfoString PyObject* PlatInfoTuple = PyList_AsTuple(PlatInfo); @@ -701,21 +716,6 @@ PyObject* __wxPySetDictionary(PyObject* /* self */, PyObject* args) } -//--------------------------------------------------------------------------- - -// Python's PyInstance_Check does not return True for instances of new-style -// classes. This should get close enough for both new and old classes but I -// should re-evaluate the need for doing instance checks... -bool wxPyInstance_Check(PyObject* obj) { - return PyObject_HasAttrString(obj, "__class__") != 0; -} - - -// This one checks if the object is an instance of a SWIG proxy class (it has -// a .this attribute) -bool wxPySwigInstance_Check(PyObject* obj) { - return PyObject_HasAttrString(obj, "this") != 0; -} //--------------------------------------------------------------------------- @@ -1730,45 +1730,80 @@ PyObject* PyFindClassWithAttr(PyObject *klass, PyObject *name) static -PyObject* PyMethod_GetDefiningClass(PyObject* method, const char* name) +PyObject* PyMethod_GetDefiningClass(PyObject* method, PyObject* nameo) { 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; + return PyFindClassWithAttr(mgc, nameo); #endif } +// To avoid recursion when an overridden virtual method wants to call the base +// class version, temporarily set an attribute in the instance with the same +// name as the method. Then the PyObject_GetAttr in the next findCallback +// will return this attribute and the PyMethod_Check will fail. + +void wxPyCallbackHelper::setRecursionGuard(PyObject* method) const +{ + PyFunctionObject* func = (PyFunctionObject*)PyMethod_Function(method); + PyObject_SetAttr(m_self, func->func_name, Py_None); +} + +void wxPyCallbackHelper::clearRecursionGuard(PyObject* method) const +{ + PyFunctionObject* func = (PyFunctionObject*)PyMethod_Function(method); + if (PyObject_HasAttr(m_self, func->func_name)) { + PyObject_DelAttr(m_self, func->func_name); + } +} + +// bool wxPyCallbackHelper::hasRecursionGuard(PyObject* method) const +// { +// PyFunctionObject* func = (PyFunctionObject*)PyMethod_Function(method); +// if (PyObject_HasAttr(m_self, func->func_name)) { +// PyObject* attr = PyObject_GetAttr(m_self, func->func_name); +// bool retval = (attr == Py_None); +// Py_DECREF(attr); +// return retval; +// } +// return false; +// } + + bool wxPyCallbackHelper::findCallback(const char* name) const { wxPyCallbackHelper* self = (wxPyCallbackHelper*)this; // cast away const + PyObject *method, *klass; + PyObject* nameo = PyString_FromString(name); self->m_lastFound = NULL; // 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); + if (m_self && PyObject_HasAttr(m_self, nameo)) { + method = PyObject_GetAttr(m_self, nameo); // ...and if that attribute is a method, and if that method's class is - // not from a base class... + // not from the registered class or a base class... if (PyMethod_Check(method) && - (klass = PyMethod_GetDefiningClass(method, (char*)name)) != NULL && - ((klass == m_class) || PyObject_IsSubclass(klass, m_class))) { - - // ...then we'll save a pointer to the method so callCallback can call it. + (klass = PyMethod_GetDefiningClass(method, nameo)) != NULL && + (klass != m_class) && + PyObject_IsSubclass(klass, m_class)) { + + // ...then we'll save a pointer to the method so callCallback can + // call it. But first, set a recursion guard in case the + // overridden method wants to call the base class version. + setRecursionGuard(method); self->m_lastFound = method; } else { Py_DECREF(method); } } + + Py_DECREF(nameo); return m_lastFound != NULL; } @@ -1797,6 +1832,8 @@ PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) const { PyObject* method = m_lastFound; result = PyEval_CallObject(method, argTuple); + clearRecursionGuard(method); + Py_DECREF(argTuple); Py_DECREF(method); if (!result) { @@ -2725,6 +2762,145 @@ PyObject* wxArrayInt2PyList_helper(const wxArrayInt& arr) { } +//---------------------------------------------------------------------- +// wxPyImageHandler methods +// +// TODO: Switch these to use wxPython's standard macros and helper classes +// for calling callbacks. + +PyObject* wxPyImageHandler::m_DoCanRead_Name = NULL; +PyObject* wxPyImageHandler::m_GetImageCount_Name = NULL; +PyObject* wxPyImageHandler::m_LoadFile_Name = NULL; +PyObject* wxPyImageHandler::m_SaveFile_Name = NULL; + +PyObject* wxPyImageHandler::py_InputStream(wxInputStream* stream) { + return wxPyConstructObject(new wxPyInputStream(stream), + wxT("wxPyInputStream"), 0); +} + +PyObject* wxPyImageHandler::py_Image(wxImage* image) { + return wxPyConstructObject(image, wxT("wxImage"), 0); +} + +PyObject* wxPyImageHandler::py_OutputStream(wxOutputStream* stream) { + return wxPyConstructObject(stream, wxT("wxOutputStream"), 0); +} + +wxPyImageHandler::wxPyImageHandler(): + m_self(NULL) +{ + if (!m_DoCanRead_Name) { + m_DoCanRead_Name = PyString_FromString("DoCanRead"); + m_GetImageCount_Name = PyString_FromString("GetImageCount"); + m_LoadFile_Name = PyString_FromString("LoadFile"); + m_SaveFile_Name = PyString_FromString("SaveFile"); + } +} + +wxPyImageHandler::~wxPyImageHandler() { + if (m_self) { + Py_DECREF(m_self); + m_self = NULL; + } +} + +void wxPyImageHandler::_SetSelf(PyObject *self) { + // should check here for isinstance(PyImageHandler) ?? + m_self = self; + Py_INCREF(m_self); +} + +bool wxPyImageHandler::DoCanRead(wxInputStream& stream) { + // check if our object has this method + wxPyBlock_t blocked = wxPyBeginBlockThreads(); + if (!m_self || !PyObject_HasAttr(m_self, m_DoCanRead_Name)) { + wxPyEndBlockThreads(blocked); + return false; + } + + PyObject* res = PyObject_CallMethodObjArgs(m_self, m_DoCanRead_Name, + py_InputStream(&stream), NULL); + bool retval = false; + if (res) { + retval = PyInt_AsLong(res); + Py_DECREF(res); + PyErr_Clear(); + } + else + PyErr_Print(); + wxPyEndBlockThreads(blocked); + return retval; +} + +bool wxPyImageHandler::LoadFile( wxImage* image, wxInputStream& stream, + bool verbose, int index ) { + // check if our object has this method + wxPyBlock_t blocked = wxPyBeginBlockThreads(); + if (!m_self || !PyObject_HasAttr(m_self, m_LoadFile_Name)) { + wxPyEndBlockThreads(blocked); + return false; + } + PyObject* res = PyObject_CallMethodObjArgs(m_self, m_LoadFile_Name, + py_Image(image), + py_InputStream(&stream), + PyInt_FromLong(verbose), + PyInt_FromLong(index), + NULL); + bool retval = false; + if (res) { + retval = PyInt_AsLong(res); + Py_DECREF(res); + PyErr_Clear(); + } else + PyErr_Print(); + wxPyEndBlockThreads(blocked); + return retval; +} + +bool wxPyImageHandler::SaveFile( wxImage* image, wxOutputStream& stream, + bool verbose ) { + wxPyBlock_t blocked = wxPyBeginBlockThreads(); + if (!m_self || !PyObject_HasAttr(m_self, m_SaveFile_Name)) { + wxPyEndBlockThreads(blocked); + return false; + } + PyObject* res = PyObject_CallMethodObjArgs(m_self, m_SaveFile_Name, + py_Image(image), + py_OutputStream(&stream), + PyInt_FromLong(verbose), + NULL); + bool retval = false; + if(res) { + retval=PyInt_AsLong(res); + Py_DECREF(res); + PyErr_Clear(); + } else + PyErr_Print(); + wxPyEndBlockThreads(blocked); + return retval; +} + +int wxPyImageHandler::GetImageCount( wxInputStream& stream ) { + wxPyBlock_t blocked = wxPyBeginBlockThreads(); + if (!m_self || !PyObject_HasAttr(m_self, m_GetImageCount_Name)) { + wxPyEndBlockThreads(blocked); + return 1; + } + PyObject *res=PyObject_CallMethodObjArgs(m_self, m_GetImageCount_Name, + py_InputStream(&stream), + NULL); + int retval = 1; + if(res) { + retval=PyInt_AsLong(res); + Py_DECREF(res); + PyErr_Clear(); + } else + PyErr_Print(); + wxPyEndBlockThreads(blocked); + return retval; +} + + //---------------------------------------------------------------------- //----------------------------------------------------------------------