+//---------------------------------------------------------------------------
+
+void wxPyClientData_dtor(wxPyClientData* self) {
+    if (! wxPyDoingCleanup) {           // Don't do it during cleanup as Python
+                                        // may have already garbage collected the object...
+        wxPyBeginBlockThreads();
+        Py_DECREF(self->m_obj);
+        wxPyEndBlockThreads();
+    }
+}
+
+void wxPyUserData_dtor(wxPyUserData* self) {
+    if (! wxPyDoingCleanup) {
+        wxPyBeginBlockThreads();
+        Py_DECREF(self->m_obj);
+        wxPyEndBlockThreads();
+    }
+}
+
+
+// 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 _extras.py for the implementation of this class.
+void wxPyOORClientData_dtor(wxPyOORClientData* self) {
+
+    static PyObject* deadObjectClass = NULL;
+
+    wxPyBeginBlockThreads();
+    if (deadObjectClass == NULL) {
+        deadObjectClass = PyDict_GetItemString(wxPython_dict, "_wxPyDeadObject");
+        wxASSERT_MSG(deadObjectClass != NULL, wxT("Can't get _wxPyDeadObject class!"));
+        Py_INCREF(deadObjectClass);
+    }
+
+    // TODO:  If wxPyDOingCleanup, should we skip the code below?
+
+    // Clear the instance's dictionary, put the name of the old class into the
+    // instance, and then reset the class to be the dead class.
+    if (self->m_obj->ob_refcnt > 1) {  // but only if there is more than one reference
+        wxASSERT_MSG(PyInstance_Check(self->m_obj), wxT("m_obj not an instance!?!?!"));
+        PyInstanceObject* inst = (PyInstanceObject*)self->m_obj;
+        PyDict_Clear(inst->in_dict);
+        PyDict_SetItemString(inst->in_dict, "_name", inst->in_class->cl_name);
+        inst->in_class = (PyClassObject*)deadObjectClass;
+        Py_INCREF(deadObjectClass);
+    }
+    wxPyEndBlockThreads();
+}
+
+//---------------------------------------------------------------------------
+// Stuff used by OOR to find the right wxPython class type to return and to
+// build it.
+
+
+// The pointer type map is used when the "pointer" type name generated by SWIG
+// is not the same as the shadow class name, for example wxPyTreeCtrl
+// vs. wxTreeCtrl.  It needs to be referenced in Python as well as from C++,
+// so we'll just make it a Python dictionary in the wx module's namespace.
+// (See __wxSetDictionary)
+void wxPyPtrTypeMap_Add(const char* commonName, const char* ptrName) {
+    if (! wxPyPtrTypeMap)
+        wxPyPtrTypeMap = PyDict_New();
+    PyDict_SetItemString(wxPyPtrTypeMap,
+                         (char*)commonName,
+                         PyString_FromString((char*)ptrName));
+}
+
+
+
+PyObject* wxPyClassExists(const wxString& className) {
+
+    PyObject* item;
+    wxString  name(className);
+    char      buff[64];               // should always be big enough...
+
+    if (!className)
+        return NULL;
+
+    // Try the name as-is first
+    sprintf(buff, "%sPtr", (const char*)name.mbc_str());
+    PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff);
+
+    // if not found see if there is a mapped name for it
+    if ( ! classobj) {
+        if ((item = PyDict_GetItemString(wxPyPtrTypeMap, (char*)(const char*)name.mbc_str())) != NULL) {
+            name = wxString(PyString_AsString(item), *wxConvCurrent);
+            sprintf(buff, "%sPtr", (const char*)name.mbc_str());
+            classobj = PyDict_GetItemString(wxPython_dict, buff);
+        }
+    }
+
+    return classobj;  // returns NULL if not found
+}
+
+
+PyObject*  wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) {
+    PyObject* target = NULL;
+    bool      isEvtHandler = FALSE;
+
+    if (source) {
+        // If it's derived from wxEvtHandler then there may
+        // already be a pointer to a Python object that we can use
+        // in the OOR data.
+        if (checkEvtHandler && wxIsKindOf(source, wxEvtHandler)) {
+            isEvtHandler = TRUE;
+            wxEvtHandler* eh = (wxEvtHandler*)source;
+            wxPyOORClientData* data = (wxPyOORClientData*)eh->GetClientObject();
+            if (data) {
+                target = data->m_obj;
+                Py_INCREF(target);
+            }
+        }
+
+        if (! target) {
+            // Otherwise make it the old fashioned way by making a
+            // new shadow object and putting this pointer in it.
+            wxClassInfo* info  = source->GetClassInfo();
+            wxString     name  = info->GetClassName();
+            PyObject*    klass = wxPyClassExists(name);
+            while (info && !klass) {
+                name = (wxChar*)info->GetBaseClassName1();
+                info = wxClassInfo::FindClass(name);
+                klass = wxPyClassExists(name);
+            }
+            if (info) {
+                target = wxPyConstructObject(source, name, klass, FALSE);
+                if (target && isEvtHandler)
+                    ((wxEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target));
+            } else {
+                wxString msg(wxT("wxPython class not found for "));
+                msg += source->GetClassInfo()->GetClassName();
+                PyErr_SetString(PyExc_NameError, msg.mbc_str());
+                target = NULL;
+            }
+        }
+    } else {  // source was NULL so return None.
+        Py_INCREF(Py_None); target = Py_None;
+    }
+    return target;
+}
+
+
+PyObject*  wxPyMake_wxSizer(wxSizer* source) {
+    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;
+            Py_INCREF(target);
+        }
+    }
+    if (! target) {
+        target = wxPyMake_wxObject(source, FALSE);
+        if (target != Py_None)
+            ((wxSizer*)source)->SetClientObject(new wxPyOORClientData(target));
+    }
+    return target;
+}
+
+
+
+//---------------------------------------------------------------------------
+
+PyObject* wxPyConstructObject(void* ptr,
+                              const wxString& className,
+                              PyObject* klass,
+                              int setThisOwn) {
+
+    PyObject* obj;
+    PyObject* arg;
+    PyObject* item;
+    wxString  name(className);
+    char      swigptr[64];      // should always be big enough...
+    char      buff[64];
+
+    if ((item = PyDict_GetItemString(wxPyPtrTypeMap, (char*)(const char*)name.mbc_str())) != NULL) {
+        name = wxString(PyString_AsString(item), *wxConvCurrent);
+    }
+    sprintf(buff, "_%s_p", (const char*)name.mbc_str());
+    SWIG_MakePtr(swigptr, ptr, buff);
+
+    arg = Py_BuildValue("(s)", swigptr);
+    obj = PyInstance_New(klass, arg, NULL);
+    Py_DECREF(arg);
+
+    if (setThisOwn) {
+        PyObject* one = PyInt_FromLong(1);
+        PyObject_SetAttrString(obj, "thisown", one);
+        Py_DECREF(one);
+    }
+
+    return obj;
+}
+
+
+PyObject* wxPyConstructObject(void* ptr,
+                              const wxString& className,
+                              int setThisOwn) {
+    if (!ptr) {
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+
+    char    buff[64];               // should always be big enough...
+    sprintf(buff, "%sPtr", (const char*)className.mbc_str());
+
+    wxASSERT_MSG(wxPython_dict, wxT("wxPython_dict is not set yet!!"));
+
+    PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff);
+    if (! classobj) {
+        wxString msg(wxT("wxPython class not found for "));
+        msg += className;
+        PyErr_SetString(PyExc_NameError, msg.mbc_str());
+        return NULL;
+    }
+
+    return wxPyConstructObject(ptr, className, classobj, setThisOwn);
+}
+
+
+//---------------------------------------------------------------------------
+
+
+#ifdef WXP_WITH_THREAD
+inline
+unsigned long wxPyGetCurrentThreadId() {
+    return wxThread::GetCurrentId();
+}
+
+static PyThreadState* gs_shutdownTState;
+static
+PyThreadState* wxPyGetThreadState() {
+    if (wxPyTMutex == NULL) // Python is shutting down...
+        return gs_shutdownTState;
+
+    unsigned long ctid = wxPyGetCurrentThreadId();
+    PyThreadState* 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;
+            break;
+        }
+    }
+    wxPyTMutex->Unlock();
+    wxASSERT_MSG(tstate, wxT("PyThreadState should not be NULL!"));
+    return tstate;
+}
+
+static
+void wxPySaveThreadState(PyThreadState* tstate) {
+    if (wxPyTMutex == NULL) { // Python is shutting down, assume a single thread...
+        gs_shutdownTState = tstate;
+        return;
+    }
+    unsigned long ctid = wxPyGetCurrentThreadId();
+    wxPyTMutex->Lock();
+    for(size_t i=0; i < wxPyTStates->GetCount(); i++) {
+        wxPyThreadState& info = wxPyTStates->Item(i);
+        if (info.tid == ctid) {
+#if 0
+            if (info.tstate != tstate)
+                wxLogMessage("*** tstate mismatch!???");
+#endif
+            // info.tstate = tstate;    *** DO NOT update existing ones???
+            // Normally it will never change, but apparently COM callbacks
+            // (i.e. ActiveX controls) will (incorrectly IMHO) use a transient
+            // tstate which will then be garbage the next time we try to use
+            // it...
+            wxPyTMutex->Unlock();
+            return;
+        }
+    }
+    // not found, so add it...
+    wxPyTStates->Add(new wxPyThreadState(ctid, tstate));
+    wxPyTMutex->Unlock();
+}
+
+#endif
+
+
+// Calls from Python to wxWindows code are wrapped in calls to these
+// functions:
+
+PyThreadState* wxPyBeginAllowThreads() {
+#ifdef WXP_WITH_THREAD
+    PyThreadState* saved = PyEval_SaveThread();  // Py_BEGIN_ALLOW_THREADS;
+    wxPySaveThreadState(saved);
+    return saved;
+#else
+    return NULL;
+#endif
+}
+
+void wxPyEndAllowThreads(PyThreadState* saved) {
+#ifdef WXP_WITH_THREAD
+    PyEval_RestoreThread(saved);   // Py_END_ALLOW_THREADS;
+#endif
+}
+
+
+
+// Calls from wxWindows back to Python code, or even any PyObject
+// manipulations, PyDECREF's and etc. are wrapped in calls to these functions:
+
+void wxPyBeginBlockThreads() {
+#ifdef WXP_WITH_THREAD
+    PyThreadState* tstate = wxPyGetThreadState();
+    PyEval_RestoreThread(tstate);
+#endif
+}
+
+
+void wxPyEndBlockThreads() {
+#ifdef WXP_WITH_THREAD
+    // Is there any need to save it again?
+    // PyThreadState* tstate =
+    PyEval_SaveThread();
+#endif
+}
+
+
+//---------------------------------------------------------------------------
+// wxPyInputStream and wxPyCBInputStream methods
+
+
+void wxPyInputStream::close() {
+    /* do nothing for now */
+}
+
+void wxPyInputStream::flush() {
+    /* do nothing for now */
+}
+
+bool wxPyInputStream::eof() {
+    if (m_wxis)
+        return m_wxis->Eof();
+    else
+        return TRUE;
+}
+
+wxPyInputStream::~wxPyInputStream() {
+    /* do nothing */
+}
+
+
+
+
+PyObject* wxPyInputStream::read(int size) {
+    PyObject* obj = NULL;
+    wxMemoryBuffer buf;
+    const int BUFSIZE = 1024;
+
+    // check if we have a real wxInputStream to work with
+    if (!m_wxis) {
+        wxPyBeginBlockThreads();
+        PyErr_SetString(PyExc_IOError, "no valid C-wxInputStream");
+        wxPyEndBlockThreads();
+        return NULL;
+    }
+
+    if (size < 0) {
+        // read while bytes are available on the stream
+        while ( m_wxis->CanRead() ) {
+            m_wxis->Read(buf.GetAppendBuf(BUFSIZE), BUFSIZE);
+            buf.UngetAppendBuf(m_wxis->LastRead());
+        }
+
+    } else {  // Read only size number of characters
+        m_wxis->Read(buf.GetWriteBuf(size), size);
+        buf.UngetWriteBuf(m_wxis->LastRead());
+    }
+
+    // error check
+    wxPyBeginBlockThreads();
+    wxStreamError err = m_wxis->GetLastError();
+    if (err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF) {
+        PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
+    }
+    else {
+        // We use only strings for the streams, not unicode
+        obj = PyString_FromStringAndSize(buf, buf.GetDataLen());
+    }
+    wxPyEndBlockThreads();
+    return obj;
+}
+
+
+PyObject* wxPyInputStream::readline(int size) {
+    PyObject* obj = NULL;
+    wxMemoryBuffer buf;
+    int i;
+    char ch;
+
+    // check if we have a real wxInputStream to work with
+    if (!m_wxis) {
+        wxPyBeginBlockThreads();
+        PyErr_SetString(PyExc_IOError,"no valid C-wxInputStream");
+        wxPyEndBlockThreads();
+        return NULL;
+    }
+
+    // read until \n or byte limit reached
+    for (i=ch=0; (ch != '\n') && (m_wxis->CanRead()) && ((size < 0) || (i < size)); i++) {
+        ch = m_wxis->GetC();
+        buf.AppendByte(ch);
+    }
+
+    // errorcheck
+    wxPyBeginBlockThreads();
+    wxStreamError err = m_wxis->GetLastError();
+    if (err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF) {
+        PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
+    }
+    else {
+        // We use only strings for the streams, not unicode
+        obj = PyString_FromStringAndSize((char*)buf.GetData(), buf.GetDataLen());
+    }
+    wxPyEndBlockThreads();
+    return obj;
+}
+
+
+PyObject* wxPyInputStream::readlines(int sizehint) {
+    PyObject* pylist;
+
+    // check if we have a real wxInputStream to work with
+    if (!m_wxis) {
+        wxPyBeginBlockThreads();
+        PyErr_SetString(PyExc_IOError,"no valid C-wxInputStream");
+        wxPyEndBlockThreads();
+        return NULL;
+    }
+
+    // init list
+    wxPyBeginBlockThreads();
+    pylist = PyList_New(0);
+    if (!pylist) {
+        wxPyBeginBlockThreads();
+        PyErr_NoMemory();
+        wxPyEndBlockThreads();
+        return NULL;
+    }
+
+    // read sizehint bytes or until EOF
+    int i;
+    for (i=0; (m_wxis->CanRead()) && ((sizehint < 0) || (i < sizehint));) {
+        PyObject* s = this->readline();
+        if (s == NULL) {
+            wxPyBeginBlockThreads();
+            Py_DECREF(pylist);
+            wxPyEndBlockThreads();
+            return NULL;
+        }
+        wxPyBeginBlockThreads();
+        PyList_Append(pylist, s);
+        i += PyString_Size(s);
+        wxPyEndBlockThreads();
+    }
+
+    // error check
+    wxStreamError err = m_wxis->GetLastError();
+    if (err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF) {
+        wxPyBeginBlockThreads();
+        Py_DECREF(pylist);
+        PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
+        wxPyEndBlockThreads();
+        return NULL;
+    }
+
+    return pylist;
+}
+
+
+void wxPyInputStream::seek(int offset, int whence) {
+    if (m_wxis)
+        m_wxis->SeekI(offset, wxSeekMode(whence));
+}
+
+int wxPyInputStream::tell(){
+    if (m_wxis)
+        return m_wxis->TellI();
+    else return 0;
+}
+
+
+
+
+wxPyCBInputStream::wxPyCBInputStream(PyObject *r, PyObject *s, PyObject *t, bool block)
+    : wxInputStream(), m_read(r), m_seek(s), m_tell(t), m_block(block)
+{}
+
+
+wxPyCBInputStream::~wxPyCBInputStream() {
+    if (m_block) wxPyBeginBlockThreads();
+    Py_XDECREF(m_read);
+    Py_XDECREF(m_seek);
+    Py_XDECREF(m_tell);
+    if (m_block) wxPyEndBlockThreads();
+}
+