+//---------------------------------------------------------------------------
+
+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();
+}
+