From: Robin Dunn Date: Wed, 17 Dec 2003 23:59:57 +0000 (+0000) Subject: Reworked how stock objects are initialized. They now have an X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/9e58eb5674cfac859568c9a4b1030012e1f0eb64 Reworked how stock objects are initialized. They now have an alternate __class__ until the App is initialized so they will raise an exception if anybody tries to use them before the C++ object has been created. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@24899 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/wxPython/include/wx/wxPython/wxPython_int.h b/wxPython/include/wx/wxPython/wxPython_int.h index af51069726..2d42ea5e51 100644 --- a/wxPython/include/wx/wxPython/wxPython_int.h +++ b/wxPython/include/wx/wxPython/wxPython_int.h @@ -92,6 +92,7 @@ const bool False = false; void __wxPyPreStart(PyObject*); void __wxPyCleanup(); PyObject* __wxPySetDictionary(PyObject*, PyObject* args); +PyObject* __wxPyFixStockObjects(PyObject*, PyObject* args); void wxPyEventThunker(wxObject*, wxEvent& event); @@ -116,7 +117,7 @@ void wxPyPtrTypeMap_Add(const char* commonName, const char* ptrName); PyObject* wxPy_ConvertList(wxListBase* list); long wxPyGetWinHandle(wxWindow* win); -void wxPy_ReinitStockObjects(bool init); +void wxPy_ReinitStockObjects(int pass); bool wxPyInstance_Check(PyObject* obj); bool wxPySwigInstance_Check(PyObject* obj); diff --git a/wxPython/src/_core_ex.py b/wxPython/src/_core_ex.py index 8bf9c34ef6..52edf3c955 100644 --- a/wxPython/src/_core_ex.py +++ b/wxPython/src/_core_ex.py @@ -33,7 +33,6 @@ if RELEASE_VERSION != _core.RELEASE_VERSION: class PyDeadObjectError(AttributeError): pass - class _wxPyDeadObject(object): """ Instances of wx objects that are OOR capable will have their __class__ @@ -43,15 +42,46 @@ class _wxPyDeadObject(object): reprStr = "wxPython wrapper for DELETED %s object! (The C++ object no longer exists.)" attrStr = "The C++ part of the %s object has been deleted, attribute access no longer allowed." - def __repr__( self ): + def __repr__(self): if not hasattr(self, "_name"): self._name = "[unknown]" return self.reprStr % self._name - def __getattr__( self, *args ): + def __getattr__(self, *args): if not hasattr(self, "_name"): self._name = "[unknown]" - raise PyDeadObjectError( self.attrStr % self._name ) + raise PyDeadObjectError(self.attrStr % self._name) + + def __nonzero__(self): + return 0 + + + +class PyUnbornObjectError(AttributeError): + pass + +class _wxPyUnbornObject(object): + """ + Some stock objects are created when the wx.core module is + imported, but their C++ instance is not created until the wx.App + object is created and initialized. These object instances will + temporarily have their __class__ changed to this class so an + exception will be raised if they are used before the C++ instance + is ready. + """ + + reprStr = "wxPython wrapper for UNBORN object! (The C++ object is not initialized yet.)" + attrStr = "The C++ part of this object has not been initialized, attribute access not allowed." + + def __repr__(self): + #if not hasattr(self, "_name"): + # self._name = "[unknown]" + return self.reprStr #% self._name + + def __getattr__(self, *args): + #if not hasattr(self, "_name"): + # self._name = "[unknown]" + raise PyUnbornObjectError(self.attrStr) # % self._name ) def __nonzero__(self): return 0 @@ -186,5 +216,10 @@ from windows import * from controls import * from misc import * + +# Fixup the stock objects since they can't be used yet. (They will be +# restored in wx.PyApp.OnInit.) +_core._wxPyFixStockObjects() + #---------------------------------------------------------------------------- #---------------------------------------------------------------------------- diff --git a/wxPython/src/_core_reverse.txt b/wxPython/src/_core_reverse.txt index 0176d97744..1e0b04cf77 100644 --- a/wxPython/src/_core_reverse.txt +++ b/wxPython/src/_core_reverse.txt @@ -26,6 +26,7 @@ RELEASE_VERSION SUBREL_VERSION VERSION RELEASE_NUMBER +PyUnbornObjectError PyDeadObjectError CallAfter FutureCall diff --git a/wxPython/src/_stockobjs.i b/wxPython/src/_stockobjs.i index 15d6377989..3abd60a2e2 100644 --- a/wxPython/src/_stockobjs.i +++ b/wxPython/src/_stockobjs.i @@ -80,6 +80,11 @@ public: %newgroup +// %typemap(varout) wxFont* { +// // my typemap +// $result = SWIG_NewPointerObj((void *) $1, $1_descriptor, 0); +// } + // See also wxPy_ReinitStockObjects in helpers.cpp %immutable; diff --git a/wxPython/src/core.i b/wxPython/src/core.i index a8a81e8d94..a41427188f 100644 --- a/wxPython/src/core.i +++ b/wxPython/src/core.i @@ -28,9 +28,8 @@ %include _core_api.i %include _core_rename.i - - %native(_wxPySetDictionary) __wxPySetDictionary; +%native(_wxPyFixStockObjects) __wxPyFixStockObjects; %pythoncode { %#// Give a reference to the dictionary of this module to the C++ extension diff --git a/wxPython/src/helpers.cpp b/wxPython/src/helpers.cpp index 46012aa7ee..5030bead5f 100644 --- a/wxPython/src/helpers.cpp +++ b/wxPython/src/helpers.cpp @@ -359,7 +359,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 +472,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 +564,88 @@ 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, 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, 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, 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) +{ + PyObject* obj; + PyObject* ptrobj; #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);