X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/47d67540a017101b3e46abe9ef0f55914d8de37e..1475671a6655702355270d44757711bf63af9ed7:/utils/wxPython/src/helpers.cpp diff --git a/utils/wxPython/src/helpers.cpp b/utils/wxPython/src/helpers.cpp index 4aba1c4abf..df05338a93 100644 --- a/utils/wxPython/src/helpers.cpp +++ b/utils/wxPython/src/helpers.cpp @@ -10,22 +10,24 @@ // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// -#ifdef __WXMSW__ -#include -#undef FindWindow -#undef GetCharWidth -#undef LoadAccelerators + +#ifdef __WXGTK__ +#include #endif #undef DEBUG #include #include "helpers.h" - -#ifdef __WXGTK__ -#ifdef wxUSE_GDK_IMLIB -#include "gdk_imlib/gdk_imlib.h" -#endif +#ifdef __WXMSW__ +#include +#undef FindWindow +#undef GetCharWidth +#undef LoadAccelerators +#undef GetClassInfo +#undef GetClassName #endif +#include + //--------------------------------------------------------------------------- @@ -39,18 +41,17 @@ wxString wxPyEmptyStr(""); #ifdef __WXMSW__ // If building for win32... -extern HINSTANCE wxhInstance; - //---------------------------------------------------------------------- // This gets run when the DLL is loaded. We just need to save a handle. //---------------------------------------------------------------------- + BOOL WINAPI DllMain( HINSTANCE hinstDLL, // handle to DLL module DWORD fdwReason, // reason for calling function LPVOID lpvReserved // reserved ) { - wxhInstance = hinstDLL; + wxSetInstance(hinstDLL); return 1; } #endif @@ -62,6 +63,15 @@ BOOL WINAPI DllMain( wxPyApp *wxPythonApp = NULL; // Global instance of application object +wxPyApp::wxPyApp() { +// printf("**** ctor\n"); +} + +wxPyApp::~wxPyApp() { +// printf("**** dtor\n"); +} + + // This one isn't acutally called... See __wxStart() bool wxPyApp::OnInit(void) { return false; @@ -69,41 +79,36 @@ bool wxPyApp::OnInit(void) { int wxPyApp::MainLoop(void) { int retval = wxApp::MainLoop(); - AfterMainLoop(); +//# AfterMainLoop(); + wxPythonApp->OnExit(); //# return retval; } -void wxPyApp::AfterMainLoop(void) { - // more stuff from wxEntry... -#ifdef __WXMSW__ - if (wxPythonApp->GetTopWindow()) { - // Forcibly delete the window. - if (wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxFrame)) || - wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxDialog))) { +//# void wxPyApp::AfterMainLoop(void) { +// // more stuff from wxEntry... - wxPythonApp->GetTopWindow()->Close(TRUE); - wxPythonApp->DeletePendingObjects(); - } - else { - delete wxPythonApp->GetTopWindow(); - wxPythonApp->SetTopWindow(NULL); - } - } -#endif -#ifdef __WXGTK__ - wxPythonApp->DeletePendingObjects(); -#endif +// if (wxPythonApp->GetTopWindow()) { +// // Forcibly delete the window. +// if (wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxFrame)) || +// wxPythonApp->GetTopWindow()->IsKindOf(CLASSINFO(wxDialog))) { - wxPythonApp->OnExit(); -#ifdef __WXMSW__ - wxApp::CleanUp(); -#endif -#ifdef __WXGTK__ - wxApp::CommonCleanUp(); -#endif - delete wxPythonApp; -} +// wxPythonApp->GetTopWindow()->Close(TRUE); +// wxPythonApp->DeletePendingObjects(); +// } +// else { +// delete wxPythonApp->GetTopWindow(); +// wxPythonApp->SetTopWindow(NULL); +// } +// } +// #ifdef __WXGTK__ +// wxPythonApp->DeletePendingObjects(); +// #endif + +// wxPythonApp->OnExit(); +// wxApp::CleanUp(); +// // delete wxPythonApp; +// } //--------------------------------------------------------------------- @@ -112,8 +117,8 @@ void wxPyApp::AfterMainLoop(void) { // This is where we pick up the first part of the wxEntry functionality... -// The rest is in __wxStart and AfterMainLoop. Thi function is called when -// wxpc is imported. (Before there is a wxApp object.) +// The rest is in __wxStart and AfterMainLoop. This function is called when +// wxcmodule is imported. (Before there is a wxApp object.) void __wxPreStart() { // Bail out if there is already windows created. This means that the @@ -123,11 +128,10 @@ void __wxPreStart() return; #ifdef __WXMSW__ - wxApp::Initialize((WXHINSTANCE)wxhInstance); + wxApp::Initialize(); #endif -#ifdef __WXGTK__ - wxClassInfo::InitializeClasses(); +#ifdef __WXGTK__ PyObject* sysargv = PySys_GetObject("argv"); int argc = PyList_Size(sysargv); char** argv = new char*[argc+1]; @@ -136,24 +140,29 @@ void __wxPreStart() argv[x] = PyString_AsString(PyList_GetItem(sysargv, x)); argv[argc] = NULL; + gtk_set_locale(); +#if wxUSE_WCHAR_T + if (!wxOKlibc()) wxConvCurrent = &wxConvLocal; +#else + if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL; +#endif gtk_init( &argc, &argv ); + wxSetDetectableAutoRepeat( TRUE ); delete [] argv; -#ifdef wxUSE_GDK_IMLIB - gdk_imlib_init(); - gtk_widget_push_visual(gdk_imlib_get_visual()); - gtk_widget_push_colormap(gdk_imlib_get_colormap()); -#endif - - wxApp::CommonInit(); + wxApp::Initialize(); // may return FALSE. Should we check? #endif } - +#ifdef WXP_WITH_THREAD +PyThreadState* wxPyEventThreadState = NULL; +#endif static char* __nullArgv[1] = { 0 }; + + // Start the user application, user App's OnInit method is a parameter here PyObject* __wxStart(PyObject* /* self */, PyObject* args) { @@ -162,6 +171,9 @@ PyObject* __wxStart(PyObject* /* self */, PyObject* args) PyObject* result; long bResult; +#ifdef WXP_WITH_THREAD + wxPyEventThreadState = PyThreadState_Get(); +#endif if (!PyArg_ParseTuple(args, "O", &onInitFunc)) return NULL; @@ -174,16 +186,15 @@ PyObject* __wxStart(PyObject* /* self */, PyObject* args) // This is the next part of the wxEntry functionality... wxPythonApp->argc = 0; - wxPythonApp->argv = __nullArgv; + wxPythonApp->argv = NULL; wxPythonApp->OnInitGui(); // Call the Python App's OnInit function arglist = PyTuple_New(0); result = PyEval_CallObject(onInitFunc, arglist); - if (!result) { - PyErr_Print(); - exit(1); + if (!result) { // an exception was raised. + return NULL; } if (! PyInt_Check(result)) { @@ -192,14 +203,6 @@ PyObject* __wxStart(PyObject* /* self */, PyObject* args) } bResult = PyInt_AS_LONG(result); if (! bResult) { - wxPythonApp->DeletePendingObjects(); - wxPythonApp->OnExit(); -#ifdef __WXMSW__ - wxApp::CleanUp(); -#endif -#ifdef __WXGTK__ - wxApp::CommonCleanUp(); -#endif PyErr_SetString(PyExc_SystemExit, "OnInit returned false, exiting..."); return NULL; } @@ -252,11 +255,8 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args) //--------------------------------------------------------------------------- - -static -PyObject* wxPyConstructObject(void* ptr, char* className) -{ - char buff[64]; // should be big enough... +PyObject* wxPyConstructObject(void* ptr, char* className) { + char buff[64]; // should always be big enough... char swigptr[64]; sprintf(buff, "_%s_p", className); @@ -276,6 +276,77 @@ PyObject* wxPyConstructObject(void* ptr, char* className) return obj; } +//--------------------------------------------------------------------------- + +//static bool _wxPyInEvent = false; +static unsigned int _wxPyNestCount = 0; + +HELPEREXPORT bool wxPyRestoreThread() { +// #ifdef WXP_WITH_THREAD +// //if (wxPyEventThreadState != PyThreadState_Get()) { +// if (! _wxPyInEvent) { +// PyEval_RestoreThread(wxPyEventThreadState); +// _wxPyInEvent = true; +// return TRUE; +// } else +// #endif +// return FALSE; + + // 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 the above code as a guard condition since there are + // many possibilites for nested events and callbacks in wxPython. + // + // Unfortunately, it seems like somebody was lying (or I'm not + // understanding...) because each of the nested calls to this function + // MUST call PyEval_RestoreThread or Python pukes with a thread error (at + // least on Win32.) + // + // until I know better, this is how I am doing it instead: +#ifdef WXP_WITH_THREAD + PyEval_RestoreThread(wxPyEventThreadState); + _wxPyNestCount += 1; + if (_wxPyNestCount == 1) + return TRUE; + else +#endif + return FALSE; +} + + +HELPEREXPORT void wxPySaveThread(bool doSave) { +#ifdef WXP_WITH_THREAD + if (doSave) { + PyEval_SaveThread(); + //_wxPyInEvent = false; + } + _wxPyNestCount -= 1; +#endif +} + +//--------------------------------------------------------------------------- + + +IMPLEMENT_ABSTRACT_CLASS(wxPyCallback, wxObject); + +wxPyCallback::wxPyCallback(PyObject* func) { + m_func = func; + Py_INCREF(m_func); +} + +wxPyCallback::wxPyCallback(const wxPyCallback& other) { + m_func = other.m_func; + Py_INCREF(m_func); +} + +wxPyCallback::~wxPyCallback() { + bool doSave = wxPyRestoreThread(); + Py_DECREF(m_func); + wxPySaveThread(doSave); +} + + + // This function is used for all events destined for Python event handlers. void wxPyCallback::EventThunker(wxEvent& event) { @@ -285,12 +356,13 @@ void wxPyCallback::EventThunker(wxEvent& event) { PyObject* arg; PyObject* tuple; + + bool doSave = wxPyRestoreThread(); arg = wxPyConstructObject((void*)&event, event.GetClassInfo()->GetClassName()); tuple = PyTuple_New(1); PyTuple_SET_ITEM(tuple, 0, arg); result = PyEval_CallObject(func, tuple); - Py_DECREF(arg); Py_DECREF(tuple); if (result) { Py_DECREF(result); @@ -298,57 +370,94 @@ void wxPyCallback::EventThunker(wxEvent& event) { } else { PyErr_Print(); } + wxPySaveThread(doSave); } -//--------------------------------------------------------------------------- +//---------------------------------------------------------------------- + +wxPyCallbackHelper::wxPyCallbackHelper() { + m_self = NULL; + m_lastFound = NULL; +} -wxPyMenu::wxPyMenu(const wxString& title, PyObject* _func) - : wxMenu(title, (wxFunction)(func ? MenuCallback : NULL)), func(0) { - if (_func) { - func = _func; - Py_INCREF(func); - } +wxPyCallbackHelper::~wxPyCallbackHelper() { + bool doSave = wxPyRestoreThread(); + Py_XDECREF(m_self); + wxPySaveThread(doSave); +} + +wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper& other) { + m_lastFound = NULL; + m_self = other.m_self; + if (m_self) + Py_INCREF(m_self); +} + + +void wxPyCallbackHelper::setSelf(PyObject* self, int incref) { + m_self = self; + if (incref) + Py_INCREF(m_self); +} + + +bool wxPyCallbackHelper::findCallback(const wxString& name) { + m_lastFound = NULL; + if (m_self && PyObject_HasAttrString(m_self, (char*)name.c_str())) + m_lastFound = PyObject_GetAttrString(m_self, (char*)name.c_str()); + + return m_lastFound != NULL; } -wxPyMenu::~wxPyMenu() { - if (func) - Py_DECREF(func); + +int wxPyCallbackHelper::callCallback(PyObject* argTuple) { + PyObject* result; + int retval = FALSE; + + result = callCallbackObj(argTuple); + if (result) { // Assumes an integer return type... + retval = PyInt_AsLong(result); + Py_DECREF(result); + PyErr_Clear(); // forget about it if it's not... + } + return retval; } +// 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) { + PyObject* result; -void wxPyMenu::MenuCallback(wxMenu& menu, wxCommandEvent& evt) { - PyObject* evtobj = wxPyConstructObject((void*)&evt, "wxCommandEvent"); - PyObject* menuobj = wxPyConstructObject((void*)&menu, "wxMenu"); - if (PyErr_Occurred()) { - // bail out if a problem + result = PyEval_CallObject(m_lastFound, argTuple); + Py_DECREF(argTuple); + if (!result) { PyErr_Print(); - return; } - // Now call the callback... - PyObject* func = ((wxPyMenu*)&menu)->func; - PyObject* args = Py_BuildValue("(OO)", menuobj, evtobj); - PyObject* res = PyEval_CallObject(func, args); - Py_DECREF(args); - Py_DECREF(res); - Py_DECREF(evtobj); - Py_DECREF(menuobj); + return result; } + +//--------------------------------------------------------------------------- //--------------------------------------------------------------------------- + wxPyTimer::wxPyTimer(PyObject* callback) { func = callback; Py_INCREF(func); } wxPyTimer::~wxPyTimer() { + bool doSave = wxPyRestoreThread(); Py_DECREF(func); + wxPySaveThread(doSave); } void wxPyTimer::Notify() { + bool doSave = wxPyRestoreThread(); + PyObject* result; PyObject* args = Py_BuildValue("()"); @@ -360,15 +469,59 @@ void wxPyTimer::Notify() { } else { PyErr_Print(); } + wxPySaveThread(doSave); } +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- +// Convert a wxList to a Python List + +PyObject* wxPy_ConvertList(wxListBase* list, char* className) { + PyObject* pyList; + PyObject* pyObj; + wxObject* wxObj; + wxNode* node = list->First(); + + bool doSave = wxPyRestoreThread(); + pyList = PyList_New(0); + while (node) { + wxObj = node->Data(); + pyObj = wxPyConstructObject(wxObj, className); + PyList_Append(pyList, pyObj); + node = node->Next(); + } + wxPySaveThread(doSave); + return pyList; +} -//---------------------------------------------------------------------- //---------------------------------------------------------------------- // Some helper functions for typemaps in my_typemaps.i, so they won't be -// imcluded in every file... +// included in every file... + + +byte* byte_LIST_helper(PyObject* source) { + if (!PyList_Check(source)) { + PyErr_SetString(PyExc_TypeError, "Expected a list object."); + return NULL; + } + int count = PyList_Size(source); + byte* temp = new byte[count]; + if (! temp) { + PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array"); + return NULL; + } + for (int x=0; xargc; -// char** argv = wxPythonApp->argv; +bool wxRealPoint_helper(PyObject* source, wxRealPoint** obj) { + + // If source is an object instance then it may already be the right type + if (PyInstance_Check(source)) { + wxRealPoint* ptr; + if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxRealPoint_p")) + goto error; + *obj = ptr; + return TRUE; + } + // otherwise a 2-tuple of floats is expected + else if (PySequence_Check(source) && PyObject_Length(source) == 2) { + PyObject* o1 = PySequence_GetItem(source, 0); + PyObject* o2 = PySequence_GetItem(source, 1); + **obj = wxRealPoint(PyFloat_AsDouble(o1), PyFloat_AsDouble(o2)); + return TRUE; + } + + error: + PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of floats or a wxRealPoint object."); + return FALSE; +} -// for (int i = 1; i < argc; i++) { -// if (strncmp(argv[i], "wxpstderr=", 10) == 0) -// stderrfilename = argv[i]+10; -// else { -// PyList_Append(argvList, PyString_FromString(argv[i])); -// if (!script) -// script = argv[i]; -// pyargc++; -// } -// } -// PySys_SetObject("argv", argvList); -//#if 1 -// char buf[256]; -//// //PyRun_SimpleString("import sys; sys.stdout=open('wxpstdout.log','w')"); -// sprintf(buf, "import sys; sys.stdout=sys.stderr=open('%s','w')", stderrfilename); -// PyRun_SimpleString(buf); -//#endif -// initwxPythonc(); +bool wxRect_helper(PyObject* source, wxRect** obj) { -// if (script) { -// FILE *fp = fopen(script, "r"); -// if (fp) { -// PyRun_SimpleFile(fp, script);// This returns after wxpApp constructor -// fclose(fp); -// } -// else { -// char msg[256]; -// sprintf(msg, "Cannot open %s", script); -// wxMessageBox(msg); -// } -// } -// else -// PyRun_SimpleString("import wxpide"); + // If source is an object instance then it may already be the right type + if (PyInstance_Check(source)) { + wxRect* ptr; + if (SWIG_GetPtrObj(source, (void **)&ptr, "_wxRect_p")) + goto error; + *obj = ptr; + return TRUE; + } + // otherwise a 4-tuple of integers is expected + else if (PySequence_Check(source) && PyObject_Length(source) == 4) { + PyObject* o1 = PySequence_GetItem(source, 0); + PyObject* o2 = PySequence_GetItem(source, 1); + PyObject* o3 = PySequence_GetItem(source, 2); + PyObject* o4 = PySequence_GetItem(source, 3); + **obj = wxRect(PyInt_AsLong(o1), PyInt_AsLong(o2), + PyInt_AsLong(o3), PyInt_AsLong(o4)); + return TRUE; + } -// return 0; -//} + error: + PyErr_SetString(PyExc_TypeError, "Expected a 4-tuple of integers or a wxRect object."); + return FALSE; +} -//#endif //---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- + + -///////////////////////////////////////////////////////////////////////////// -// -// $Log$ -// Revision 1.9 1998/09/25 13:28:52 VZ -// USE_xxx constants renamed to wxUSE_xxx. This is an incompatible change, you -// must recompile everything after upgrading! -// -// Revision 1.8 1998/08/27 21:59:08 RD -// Some chicken-and-egg problems solved for wxPython on wxGTK -// -// Revision 1.7 1998/08/27 00:00:26 RD -// - more tweaks -// - have discovered some problems but not yet discovered solutions... -// -// Revision 1.6 1998/08/18 21:54:12 RD -// -// ifdef out some wxGTK specific code -// -// Revision 1.5 1998/08/18 19:48:17 RD -// more wxGTK compatibility things. -// -// It builds now but there are serious runtime problems... -// -// Revision 1.4 1998/08/16 04:31:06 RD -// More wxGTK work. -// -// Revision 1.3 1998/08/15 07:36:36 RD -// - Moved the header in the .i files out of the code that gets put into -// the .cpp files. It caused CVS conflicts because of the RCS ID being -// different each time. -// -// - A few minor fixes. -// -// Revision 1.2 1998/08/14 23:36:36 RD -// Beginings of wxGTK compatibility -// -// Revision 1.1 1998/08/09 08:25:51 RD -// Initial version -// -//