#include <Python.h>
#include "wx/wxPython/wxPython_int.h"
#include "wx/wxPython/pyistream.h"
+#include "wx/wxPython/swigver.h"
+#include "wx/wxPython/twoitem.h"
#ifdef __WXMSW__
#include <wx/msw/private.h>
#include <gdk/gdkprivate.h>
#include <wx/gtk/win_gtk.h>
#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 <locale.h>
#endif
wxPyApp::~wxPyApp() {
+ wxPythonApp = NULL;
+ wxApp::SetInstance(NULL);
}
}
+
+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,
if (sysargv != NULL && executable != NULL) {
argc = PyList_Size(sysargv) + 1;
argv = new char*[argc+1];
- argv[0] = PyString_AsString(executable);
+ argv[0] = strdup(PyString_AsString(executable));
int x;
for(x=1; x<argc; x++) {
PyObject *pyArg = PyList_GetItem(sysargv, x-1);
- argv[x] = PyString_AsString(pyArg);
+ argv[x] = strdup(PyString_AsString(pyArg));
}
argv[argc] = NULL;
}
// Initialize wxWidgets
result = wxEntryStart(argc, argv);
- delete [] argv;
+ // wxApp takes ownership of the argv array, don't delete it here
blocked = wxPyBeginBlockThreads();
if (! result) {
setlocale(LC_NUMERIC, "C");
#endif
- wxSystemOptions::SetOption(wxT("mac.textcontrol-use-mlte"), 1);
+// wxSystemOptions::SetOption(wxT("mac.textcontrol-use-mlte"), 1);
- // The stock objects were all NULL when they were loaded into
- // SWIG generated proxies, so re-init those now...
- wxPy_ReinitStockObjects(3);
-
wxPyEndBlockThreads(blocked);
haveInitialized = true;
}
+ else {
+ this->argc = 0;
+ this->argv = NULL;
+ }
+
// It's now ok to generate exceptions for assertion errors.
wxPythonApp->SetStartupComplete(true);
- // Call the Python wxApp's OnInit function
+
+ // Call the Python wxApp's OnPreInit and OnInit functions
blocked = wxPyBeginBlockThreads();
+ if (wxPyCBH_findCallback(m_myInst, "OnPreInit")) {
+ 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)
+ goto error;
+ }
if (wxPyCBH_findCallback(m_myInst, "OnInit")) {
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)
// Ensure that the build options in the DLL (or whatever) match this build
wxApp::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "wxPython");
- // Init the stock objects to a non-NULL value so SWIG doesn't create them as None
- wxPy_ReinitStockObjects(1);
-
wxInitAllImageHandlers();
}
#else
_AddInfoString("wx-assertions-off");
#endif
-
+ _AddInfoString(wxPy_SWIG_VERSION);
+
#undef _AddInfoString
PyObject* PlatInfoTuple = PyList_AsTuple(PlatInfo);
}
-//---------------------------------------------------------------------------
-
-// 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;
-}
-
-//---------------------------------------------------------------------------
-
-// The stock objects are no longer created when the wx._core_ module is
-// imported, but only after the app object has been created. The
-// wxPy_ReinitStockObjects function will be called 3 times to pass the stock
-// objects though various stages of evolution:
-//
-// pass 1: Set all the pointers to a non-NULL value so the Python proxy
-// object will be created (otherwise SWIG will just use None.)
-//
-// pass 2: After the module has been imported and the python proxys have
-// been created, then set the __class__ to be _wxPyUnbornObject so
-// it will catch any access to the object and will raise an exception.
-//
-// pass 3: Finally, from BootstrapApp patch things up so the stock objects
-// can be used.
-
-
-PyObject* __wxPyFixStockObjects(PyObject* /* self */, PyObject* args)
-{
- wxPy_ReinitStockObjects(2);
- RETURN_NONE();
-}
-
-
-static void rsoPass2(const char* name)
-{
- static PyObject* unbornObjectClass = NULL;
- PyObject* obj;
-
- if (unbornObjectClass == NULL) {
- unbornObjectClass = PyDict_GetItemString(wxPython_dict, "_wxPyUnbornObject");
- Py_INCREF(unbornObjectClass);
- }
-
- // Find the object instance
- obj = PyDict_GetItemString(wxPython_dict, (char*)dropwx(name));
- wxCHECK_RET(obj != NULL, wxT("Unable to find stock object"));
- wxCHECK_RET(wxPySwigInstance_Check(obj), wxT("Not a swig instance"));
-
- // Change its class
- PyObject_SetAttrString(obj, "__class__", unbornObjectClass);
-
-}
-
-static void rsoPass3(const char* name, const char* classname, void* ptr)
-{
- PyObject* obj;
- PyObject* classobj;
- PyObject* ptrobj;
-
- // Find the object instance
- obj = PyDict_GetItemString(wxPython_dict, (char*)dropwx(name));
- wxCHECK_RET(obj != NULL, wxT("Unable to find stock object"));
- wxCHECK_RET(wxPySwigInstance_Check(obj), wxT("Not a swig instance"));
-
- // Find the class object and put it back in the instance
- classobj = PyDict_GetItemString(wxPython_dict, (char*)dropwx(classname));
- wxCHECK_RET(classobj != NULL, wxT("Unable to find stock class object"));
- PyObject_SetAttrString(obj, "__class__", classobj);
-
- // Rebuild the .this swigified pointer with the new value of the C++ pointer
- ptrobj = wxPyMakeSwigPtr(ptr, wxString(classname, *wxConvCurrent));
- PyObject_SetAttrString(obj, "this", ptrobj);
- Py_DECREF(ptrobj);
-}
-
-
-
-void wxPy_ReinitStockObjects(int pass)
-{
-
- // If there is already an App object then wxPython is probably embedded in
- // a wx C++ application, so there is no need to do all this.
- static bool embedded = false;
- if ((pass == 1 || pass == 2) && wxTheApp) {
- embedded = true;
- return;
- }
- if (pass == 3 && embedded)
- return;
-
-
-#define REINITOBJ(name, classname) \
- if (pass == 1) { name = (classname*)0xC0C0C0C0; } \
- else if (pass == 2) { rsoPass2(#name); } \
- else if (pass == 3) { rsoPass3(#name, #classname, (void*)name); }
-
-
-#define REINITOBJ2(name, classname) \
- if (pass == 1) { } \
- else if (pass == 2) { rsoPass2(#name); } \
- else if (pass == 3) { rsoPass3(#name, #classname, (void*)&name); }
-
-
- REINITOBJ(wxNORMAL_FONT, wxFont);
- REINITOBJ(wxSMALL_FONT, wxFont);
- REINITOBJ(wxITALIC_FONT, wxFont);
- REINITOBJ(wxSWISS_FONT, wxFont);
-
- REINITOBJ(wxRED_PEN, wxPen);
- REINITOBJ(wxCYAN_PEN, wxPen);
- REINITOBJ(wxGREEN_PEN, wxPen);
- REINITOBJ(wxBLACK_PEN, wxPen);
- REINITOBJ(wxWHITE_PEN, wxPen);
- REINITOBJ(wxTRANSPARENT_PEN, wxPen);
- REINITOBJ(wxBLACK_DASHED_PEN, wxPen);
- REINITOBJ(wxGREY_PEN, wxPen);
- REINITOBJ(wxMEDIUM_GREY_PEN, wxPen);
- REINITOBJ(wxLIGHT_GREY_PEN, wxPen);
-
- REINITOBJ(wxBLUE_BRUSH, wxBrush);
- REINITOBJ(wxGREEN_BRUSH, wxBrush);
- REINITOBJ(wxWHITE_BRUSH, wxBrush);
- REINITOBJ(wxBLACK_BRUSH, wxBrush);
- REINITOBJ(wxTRANSPARENT_BRUSH, wxBrush);
- REINITOBJ(wxCYAN_BRUSH, wxBrush);
- REINITOBJ(wxRED_BRUSH, wxBrush);
- REINITOBJ(wxGREY_BRUSH, wxBrush);
- REINITOBJ(wxMEDIUM_GREY_BRUSH, wxBrush);
- REINITOBJ(wxLIGHT_GREY_BRUSH, wxBrush);
-
- REINITOBJ(wxBLACK, wxColour);
- REINITOBJ(wxWHITE, wxColour);
- REINITOBJ(wxRED, wxColour);
- REINITOBJ(wxBLUE, wxColour);
- REINITOBJ(wxGREEN, wxColour);
- REINITOBJ(wxCYAN, wxColour);
- REINITOBJ(wxLIGHT_GREY, wxColour);
-
- REINITOBJ(wxSTANDARD_CURSOR, wxCursor);
- REINITOBJ(wxHOURGLASS_CURSOR, wxCursor);
- REINITOBJ(wxCROSS_CURSOR, wxCursor);
-
- REINITOBJ2(wxNullBitmap, wxBitmap);
- REINITOBJ2(wxNullIcon, wxIcon);
- REINITOBJ2(wxNullCursor, wxCursor);
- REINITOBJ2(wxNullPen, wxPen);
- REINITOBJ2(wxNullBrush, wxBrush);
- REINITOBJ2(wxNullPalette, wxPalette);
- REINITOBJ2(wxNullFont, wxFont);
- REINITOBJ2(wxNullColour, wxColour);
-
- REINITOBJ(wxTheFontList, wxFontList);
- REINITOBJ(wxThePenList, wxPenList);
- REINITOBJ(wxTheBrushList, wxBrushList);
- REINITOBJ(wxTheColourDatabase, wxColourDatabase);
-
-
- REINITOBJ2(wxDefaultValidator, wxValidator);
- REINITOBJ2(wxNullImage, wxImage);
- REINITOBJ2(wxNullAcceleratorTable, wxAcceleratorTable);
-
-#undef REINITOBJ
-#undef REINITOBJ2
-}
//---------------------------------------------------------------------------
PyObject* wxPyMake_wxObject(wxObject* source, bool setThisOwn, bool checkEvtHandler) {
PyObject* target = NULL;
bool isEvtHandler = false;
+ bool isSizer = false;
if (source) {
// If it's derived from wxEvtHandler then there may
}
}
+ // Also check for wxSizer
+ if (!target && wxIsKindOf(source, wxSizer)) {
+ isSizer = true;
+ wxSizer* sz = (wxSizer*)source;
+ wxPyOORClientData* data = (wxPyOORClientData*)sz->GetClientObject();
+ if (data) {
+ target = data->m_obj;
+ if (target)
+ Py_INCREF(target);
+ }
+ }
+
if (! target) {
// Otherwise make it the old fashioned way by making a new shadow
// object and putting this pointer in it. Look up the class
target = wxPyConstructObject((void*)source, name, setThisOwn);
if (target && isEvtHandler)
((wxEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target));
+ if (target && isSizer)
+ ((wxSizer*)source)->SetClientObject(new wxPyOORClientData(target));
} else {
wxString msg(wxT("wxPython class not found for "));
msg += source->GetClassInfo()->GetClassName();
PyObject* wxPyMake_wxSizer(wxSizer* source, bool setThisOwn) {
- 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;
- wxPyOORClientData* data = (wxPyOORClientData*)sz->GetClientObject();
- if (data) {
- target = data->m_obj;
- if (target)
- Py_INCREF(target);
- }
- }
- if (! target) {
- target = wxPyMake_wxObject(source, setThisOwn, false);
- if (target != Py_None)
- ((wxSizer*)source)->SetClientObject(new wxPyOORClientData(target));
- }
- return target;
+ return wxPyMake_wxObject(source, setThisOwn);
}
wxPyBlock_t wxPyBeginBlockThreads() {
#ifdef WXP_WITH_THREAD
+ if (! Py_IsInitialized()) {
+ return (wxPyBlock_t)0;
+ }
#if wxPyUSE_GIL_STATE
PyGILState_STATE state = PyGILState_Ensure();
return state;
return blocked;
#endif
#else
- return false;
+ return (wxPyBlock_t)0;
#endif
}
void wxPyEndBlockThreads(wxPyBlock_t blocked) {
#ifdef WXP_WITH_THREAD
+ if (! Py_IsInitialized()) {
+ return;
+ }
#if wxPyUSE_GIL_STATE
PyGILState_Release(blocked);
#else
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
}
-bool wxPyCallbackHelper::findCallback(const char* name) const {
+// 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, bool setGuard) 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.
+ if (setGuard)
+ setRecursionGuard(method);
self->m_lastFound = method;
}
else {
Py_DECREF(method);
}
}
+
+ Py_DECREF(nameo);
return m_lastFound != NULL;
}
PyObject* method = m_lastFound;
result = PyEval_CallObject(method, argTuple);
+ clearRecursionGuard(method);
+
Py_DECREF(argTuple);
Py_DECREF(method);
if (!result) {
cbh.setSelf(self, klass, incref);
}
-bool wxPyCBH_findCallback(const wxPyCallbackHelper& cbh, const char* name) {
- return cbh.findCallback(name);
+bool wxPyCBH_findCallback(const wxPyCallbackHelper& cbh, const char* name, bool setGuard) {
+ return cbh.findCallback(name, setGuard);
}
int wxPyCBH_callCallback(const wxPyCallbackHelper& cbh, PyObject* argTuple) {
}
+//----------------------------------------------------------------------
+// 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;
+}
+
+
//----------------------------------------------------------------------
//----------------------------------------------------------------------