X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f048f8290f5388de598e0108aa5b4a01c68269d5..b515af7a75c346262c6a4fb17f613aab83227d65:/wxPython/src/helpers.cpp diff --git a/wxPython/src/helpers.cpp b/wxPython/src/helpers.cpp index 46012aa7ee..f2d08f0fcb 100644 --- a/wxPython/src/helpers.cpp +++ b/wxPython/src/helpers.cpp @@ -49,9 +49,10 @@ bool wxPyDoingCleanup = False; struct wxPyThreadState { unsigned long tid; PyThreadState* tstate; + int blocked; wxPyThreadState(unsigned long _tid=0, PyThreadState* _tstate=NULL) - : tid(_tid), tstate(_tstate) {} + : tid(_tid), tstate(_tstate), blocked(1) {} }; #include @@ -359,7 +360,7 @@ void wxPyApp::_BootstrapApp() // The stock objects were all NULL when they were loaded into // SWIG generated proxies, so re-init those now... - wxPy_ReinitStockObjects(False); + wxPy_ReinitStockObjects(3); // It's now ok to generate exceptions for assertion errors. wxPythonApp->SetStartupComplete(True); @@ -472,7 +473,7 @@ void __wxPyPreStart(PyObject* moduleDict) 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(True); + wxPy_ReinitStockObjects(1); } @@ -564,33 +565,86 @@ bool wxPySwigInstance_Check(PyObject* obj) { //--------------------------------------------------------------------------- -// The stock objects are no longer created when the wxc module is imported, but -// only after the app object has been created. This function will be called before -// OnInit is called so we can hack the new pointer values into the obj.this attributes. +// The stock objects are no longer created when the wxc 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 it 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 OnInit patch things up so the stock objects can +// be used. + + +PyObject* __wxPyFixStockObjects(PyObject* /* self */, PyObject* args) +{ + wxPy_ReinitStockObjects(2); + RETURN_NONE(); +} -void wxPy_ReinitStockObjects(bool init) + +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) +{ #define REINITOBJ(name, classname) \ - if ( init ) { name = (classname*)0xC0C0C0C0; } else { \ - obj = PyDict_GetItemString(wxPython_dict, dropwx(#name)); \ - wxCHECK_RET(obj != NULL, wxT("Unable to find stock object for " #name)) \ - wxCHECK_RET(wxPySwigInstance_Check(obj), wxT("Not a swig instance: " #name)); \ - ptrobj = wxPyMakeSwigPtr((void*)name, wxT(#classname)); \ - PyObject_SetAttrString(obj, "this", ptrobj); \ - Py_DECREF(ptrobj); } + 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 ( init ) { } else { \ - obj = PyDict_GetItemString(wxPython_dict, dropwx(#name)); \ - wxCHECK_RET(obj != NULL, wxT("Unable to find stock object for " #name)) \ - wxCHECK_RET(wxPySwigInstance_Check(obj), wxT("Not a swig instance: " #name)); \ - ptrobj = wxPyMakeSwigPtr((void*)&name, wxT(#classname)); \ - PyObject_SetAttrString(obj, "this", ptrobj); \ - Py_DECREF(ptrobj); } + if (pass == 1) { } \ + else if (pass == 2) { rsoPass2(#name); } \ + else if (pass == 3) { rsoPass3(#name, #classname, (void*)&name); } REINITOBJ(wxNORMAL_FONT, wxFont); @@ -842,21 +896,21 @@ unsigned long wxPyGetCurrentThreadId() { return wxThread::GetCurrentId(); } -static PyThreadState* gs_shutdownTState; +static wxPyThreadState gs_shutdownTState; static -PyThreadState* wxPyGetThreadState() { +wxPyThreadState* wxPyGetThreadState() { if (wxPyTMutex == NULL) // Python is shutting down... - return gs_shutdownTState; + return &gs_shutdownTState; unsigned long ctid = wxPyGetCurrentThreadId(); - PyThreadState* tstate = NULL; + wxPyThreadState* 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; + tstate = &info; break; } } @@ -865,10 +919,11 @@ PyThreadState* wxPyGetThreadState() { return tstate; } + static void wxPySaveThreadState(PyThreadState* tstate) { if (wxPyTMutex == NULL) { // Python is shutting down, assume a single thread... - gs_shutdownTState = tstate; + gs_shutdownTState.tstate = tstate; return; } unsigned long ctid = wxPyGetCurrentThreadId(); @@ -897,6 +952,7 @@ void wxPySaveThreadState(PyThreadState* tstate) { #endif + // Calls from Python to wxWindows code are wrapped in calls to these // functions: @@ -904,6 +960,7 @@ PyThreadState* wxPyBeginAllowThreads() { #ifdef WXP_WITH_THREAD PyThreadState* saved = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS; wxPySaveThreadState(saved); + wxPyGetThreadState()->blocked -= 1; return saved; #else return NULL; @@ -912,6 +969,7 @@ PyThreadState* wxPyBeginAllowThreads() { void wxPyEndAllowThreads(PyThreadState* saved) { #ifdef WXP_WITH_THREAD + wxPyGetThreadState()->blocked += 1; PyEval_RestoreThread(saved); // Py_END_ALLOW_THREADS; #endif } @@ -923,17 +981,21 @@ void wxPyEndAllowThreads(PyThreadState* saved) { void wxPyBeginBlockThreads() { #ifdef WXP_WITH_THREAD - PyThreadState* tstate = wxPyGetThreadState(); - PyEval_RestoreThread(tstate); + wxPyThreadState* tstate = wxPyGetThreadState(); + if (tstate->blocked++ == 0) { // if nested calls then do nothing + PyEval_RestoreThread(tstate->tstate); + } #endif } void wxPyEndBlockThreads() { #ifdef WXP_WITH_THREAD - // Is there any need to save it again? - // PyThreadState* tstate = - PyEval_SaveThread(); + wxPyThreadState* tstate = wxPyGetThreadState(); + tstate->blocked -= 1; + if ( tstate->blocked == 0) { // if nested calls then do nothing + PyEval_SaveThread(); + } #endif } @@ -1283,31 +1345,34 @@ void wxPyCallback::EventThunker(wxEvent& event) { arg = wxPyConstructObject((void*)&event, className); } - // Call the event handler, passing the event object - tuple = PyTuple_New(1); - PyTuple_SET_ITEM(tuple, 0, arg); // steals ref to arg - result = PyEval_CallObject(func, tuple); - if ( result ) { - Py_DECREF(result); // result is ignored, but we still need to decref it - PyErr_Clear(); // Just in case... - } else { + if (!arg) { PyErr_Print(); - } - - if ( checkSkip ) { - // if the event object was one of our special types and - // it had been cloned, then we need to extract the Skipped - // value from the original and set it in the clone. - result = PyObject_CallMethod(arg, "GetSkipped", ""); + } else { + // Call the event handler, passing the event object + tuple = PyTuple_New(1); + PyTuple_SET_ITEM(tuple, 0, arg); // steals ref to arg + result = PyEval_CallObject(func, tuple); if ( result ) { - event.Skip(PyInt_AsLong(result)); - Py_DECREF(result); + Py_DECREF(result); // result is ignored, but we still need to decref it + PyErr_Clear(); // Just in case... } else { PyErr_Print(); } - } - Py_DECREF(tuple); + if ( checkSkip ) { + // if the event object was one of our special types and + // it had been cloned, then we need to extract the Skipped + // value from the original and set it in the clone. + result = PyObject_CallMethod(arg, "GetSkipped", ""); + if ( result ) { + event.Skip(PyInt_AsLong(result)); + Py_DECREF(result); + } else { + PyErr_Print(); + } + } + Py_DECREF(tuple); + } wxPyEndBlockThreads(); }