+ // not found, so add it...
+ wxPyTStates->Add(new wxPyThreadState(ctid, tstate));
+ wxPyTMutex->Unlock();
+}
+
+#endif
+#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;
+#if !wxPyUSE_GIL_STATE
+ wxPySaveThreadState(saved);
+#endif
+ 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:
+
+wxPyBlock_t wxPyBeginBlockThreads() {
+#ifdef WXP_WITH_THREAD
+ if (! Py_IsInitialized()) {
+ return (wxPyBlock_t)0;
+ }
+#if wxPyUSE_GIL_STATE
+ PyGILState_STATE state = PyGILState_Ensure();
+ return state;
+#else
+ PyThreadState *current = _PyThreadState_Current;
+
+ // Only block if there wasn't already a tstate, or if the current one is
+ // not the one we are wanting to change to. This should prevent deadlock
+ // if there are nested calls to wxPyBeginBlockThreads
+ wxPyBlock_t blocked = false;
+ wxPyThreadState* tstate = wxPyGetThreadState();
+ if (current != tstate->tstate) {
+ PyEval_RestoreThread(tstate->tstate);
+ blocked = true;
+ }
+ return blocked;
+#endif
+#else
+ return (wxPyBlock_t)0;
+#endif
+}
+
+
+void wxPyEndBlockThreads(wxPyBlock_t blocked) {
+#ifdef WXP_WITH_THREAD
+ if (! Py_IsInitialized()) {
+ return;
+ }
+#if wxPyUSE_GIL_STATE
+ PyGILState_Release(blocked);
+#else
+ // Only unblock if we blocked in the last call to wxPyBeginBlockThreads.
+ // The value of blocked passed in needs to be the same as that returned
+ // from wxPyBeginBlockThreads at the same nesting level.
+ if ( blocked ) {
+ PyEval_SaveThread();
+ }
+#endif
+#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() {
+ if (m_wxis)
+ delete m_wxis;
+}
+
+
+
+
+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) {
+ wxPyBlock_t blocked = wxPyBeginBlockThreads();
+ PyErr_SetString(PyExc_IOError, "no valid C-wxInputStream");
+ wxPyEndBlockThreads(blocked);
+ 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
+ wxPyBlock_t blocked = 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(blocked);
+ 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) {
+ wxPyBlock_t blocked = wxPyBeginBlockThreads();
+ PyErr_SetString(PyExc_IOError,"no valid C-wxInputStream");
+ wxPyEndBlockThreads(blocked);
+ 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
+ wxPyBlock_t blocked = 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(blocked);
+ return obj;
+}
+
+
+PyObject* wxPyInputStream::readlines(int sizehint) {
+ PyObject* pylist;
+
+ // check if we have a real wxInputStream to work with
+ if (!m_wxis) {
+ wxPyBlock_t blocked = wxPyBeginBlockThreads();
+ PyErr_SetString(PyExc_IOError,"no valid C-wxInputStream");
+ wxPyEndBlockThreads(blocked);
+ return NULL;
+ }
+
+ // init list
+ wxPyBlock_t blocked = wxPyBeginBlockThreads();
+ pylist = PyList_New(0);
+ wxPyEndBlockThreads(blocked);
+
+ if (!pylist) {
+ wxPyBlock_t blocked = wxPyBeginBlockThreads();
+ PyErr_NoMemory();
+ wxPyEndBlockThreads(blocked);
+ 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) {
+ wxPyBlock_t blocked = wxPyBeginBlockThreads();
+ Py_DECREF(pylist);
+ wxPyEndBlockThreads(blocked);
+ return NULL;
+ }
+ wxPyBlock_t blocked = wxPyBeginBlockThreads();
+ PyList_Append(pylist, s);
+ i += PyString_Size(s);
+ wxPyEndBlockThreads(blocked);
+ }
+
+ // error check
+ wxStreamError err = m_wxis->GetLastError();
+ if (err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF) {
+ wxPyBlock_t blocked = wxPyBeginBlockThreads();
+ Py_DECREF(pylist);
+ PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
+ wxPyEndBlockThreads(blocked);
+ 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(const wxPyCBInputStream& other)
+{
+ m_read = other.m_read;
+ m_seek = other.m_seek;
+ m_tell = other.m_tell;
+ m_block = other.m_block;
+ Py_INCREF(m_read);
+ Py_INCREF(m_seek);
+ Py_INCREF(m_tell);