+// 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
+}
+
+//---------------------------------------------------------------------------
+
+// Check for existence of a wxApp, setting an exception if there isn't one.
+// This doesn't need to aquire the GIL because it should only be called from
+// an %exception before the lock is released.
+
+bool wxPyCheckForApp() {
+ if (wxTheApp != NULL)
+ return true;
+ else {
+ PyErr_SetString(wxPyNoAppError, "The wx.App object must be created first!");
+ return false;
+ }
+}
+
+//---------------------------------------------------------------------------
+
+void wxPyUserData_dtor(wxPyUserData* self) {
+ if (! wxPyDoingCleanup) {
+ wxPyBlock_t blocked = wxPyBeginBlockThreads();
+ Py_DECREF(self->m_obj);
+ self->m_obj = NULL;
+ wxPyEndBlockThreads(blocked);
+ }
+}
+
+
+void wxPyClientData_dtor(wxPyClientData* self) {
+ if (! wxPyDoingCleanup) { // Don't do it during cleanup as Python
+ // may have already garbage collected the object...
+ if (self->m_incRef) {
+ wxPyBlock_t blocked = wxPyBeginBlockThreads();
+ Py_DECREF(self->m_obj);
+ wxPyEndBlockThreads(blocked);
+ }
+ self->m_obj = NULL;
+ }
+}
+
+
+
+// This is called when an OOR controled object is being destroyed. Although
+// the C++ object is going away there is no way to force the Python object
+// (and all references to it) to die too. This causes problems (crashes) in
+// wxPython when a python shadow object attempts to call a C++ method using
+// the now bogus pointer... So to try and prevent this we'll do a little black
+// magic and change the class of the python instance to a class that will
+// raise an exception for any attempt to call methods with it. See
+// _wxPyDeadObject in _core_ex.py for the implementation of this class.
+void wxPyOORClientData_dtor(wxPyOORClientData* self) {
+
+ static PyObject* deadObjectClass = NULL;
+
+ wxPyBlock_t blocked = wxPyBeginBlockThreads();
+ if (deadObjectClass == NULL) {
+ deadObjectClass = PyDict_GetItemString(wxPython_dict, "_wxPyDeadObject");
+ // TODO: Can not wxASSERT here because inside a wxPyBeginBlock Threads,
+ // will lead to a deadlock when it tries to aquire the GIL again.
+ //wxASSERT_MSG(deadObjectClass != NULL, wxT("Can't get _wxPyDeadObject class!"));
+ Py_INCREF(deadObjectClass);
+ }
+
+
+ // Only if there is more than one reference to the object and we are
+ // holding the OOR reference:
+ if ( !wxPyDoingCleanup && self->m_obj->ob_refcnt > 1 && self->m_incRef) {
+ // bool isInstance = wxPyInstance_Check(self->m_obj);
+ // TODO same here
+ //wxASSERT_MSG(isInstance, wxT("m_obj not an instance!?!?!"));
+
+ // Call __del__, if there is one.
+ PyObject* func = PyObject_GetAttrString(self->m_obj, "__del__");
+ if (func) {
+ PyObject* rv = PyObject_CallMethod(self->m_obj, "__del__", NULL);
+ Py_XDECREF(rv);
+ Py_DECREF(func);
+ }
+ if (PyErr_Occurred())
+ PyErr_Clear(); // just ignore it for now
+
+
+ PyObject* dict = PyObject_GetAttrString(self->m_obj, "__dict__");
+ if (dict) {
+ // Clear the instance's dictionary
+ PyDict_Clear(dict);
+
+ // put the name of the old class into the instance, and then reset the
+ // class to be the dead class.
+ PyObject* klass = PyObject_GetAttrString(self->m_obj, "__class__");
+ PyObject* name = PyObject_GetAttrString(klass, "__name__");
+ PyDict_SetItemString(dict, "_name", name);
+ PyObject_SetAttrString(self->m_obj, "__class__", deadObjectClass);
+ //Py_INCREF(deadObjectClass);
+ Py_DECREF(klass);
+ Py_DECREF(name);
+ }
+ }
+
+ // m_obj is DECREF'd in the base class dtor...
+ wxPyEndBlockThreads(blocked);