]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/src/helpers.cpp
Removed unneeded assert
[wxWidgets.git] / wxPython / src / helpers.cpp
index 8216a27e4ea2ec35062cab17465feeebb03f80e7..bf1d3402f31995eb63c6605e65c36ac01facbd82 100644 (file)
 #undef DEBUG
 #include <Python.h>
 #include "helpers.h"
+#include "pyistream.h"
 
 #ifdef __WXMSW__
 #include <wx/msw/private.h>
 #include <wx/msw/winundef.h>
+#include <wx/msw/msvcrt.h>
 #endif
 
 #ifdef __WXGTK__
 #endif
 
 
+//----------------------------------------------------------------------
+
+#ifdef __WXGTK__
+int  WXDLLEXPORT wxEntryStart( int& argc, char** argv );
+#else
+int  WXDLLEXPORT wxEntryStart( int argc, char** argv );
+#endif
+int  WXDLLEXPORT wxEntryInitGui();
+void WXDLLEXPORT wxEntryCleanup();
+
+wxPyApp* wxPythonApp = NULL;  // Global instance of application object
+
+
+#ifdef WXP_WITH_THREAD
+struct wxPyThreadState {
+    unsigned long  tid;
+    PyThreadState* tstate;
+
+    wxPyThreadState(unsigned long _tid=0, PyThreadState* _tstate=NULL)
+        : tid(_tid), tstate(_tstate) {}
+};
+
+#include <wx/dynarray.h>
+WX_DECLARE_OBJARRAY(wxPyThreadState, wxPyThreadStateArray);
+#include <wx/arrimpl.cpp>
+WX_DEFINE_OBJARRAY(wxPyThreadStateArray);
+
+wxPyThreadStateArray* wxPyTStates = NULL;
+wxMutex*              wxPyTMutex = NULL;
+#endif
 
 
 #ifdef __WXMSW__             // If building for win32...
@@ -47,11 +79,9 @@ BOOL WINAPI DllMain(
 #endif
 
 //----------------------------------------------------------------------
-// Class for implementing the wxp main application shell.
+// Classes for implementing the wxp main application shell.
 //----------------------------------------------------------------------
 
-wxPyApp *wxPythonApp = NULL;            // Global instance of application object
-
 
 wxPyApp::wxPyApp() {
 //    printf("**** ctor\n");
@@ -63,43 +93,32 @@ wxPyApp::~wxPyApp() {
 
 
 // This one isn't acutally called...  See __wxStart()
-bool wxPyApp::OnInit(void) {
+bool wxPyApp::OnInit() {
     return FALSE;
 }
 
-int  wxPyApp::MainLoop(void) {
+
+int  wxPyApp::MainLoop() {
     int retval = 0;
 
     DeletePendingObjects();
+    bool initialized = wxTopLevelWindows.GetCount() != 0;
 #ifdef __WXGTK__
-    m_initialized = wxTopLevelWindows.GetCount() != 0;
+    m_initialized = initialized;
 #endif
 
-    if (Initialized()) {
+    if (initialized) {
         retval = wxApp::MainLoop();
-        wxPythonApp->OnExit();
+        OnExit();
     }
     return retval;
 }
 
 
+
 //---------------------------------------------------------------------
 //----------------------------------------------------------------------
 
-#ifdef __WXMSW__
-#include "wx/msw/msvcrt.h"
-#endif
-
-
-int  WXDLLEXPORT wxEntryStart( int argc, char** argv );
-int  WXDLLEXPORT wxEntryInitGui();
-void WXDLLEXPORT wxEntryCleanup();
-
-
-#ifdef WXP_WITH_THREAD
-PyInterpreterState* wxPyInterpreter = NULL;
-#endif
-
 
 // This is where we pick up the first part of the wxEntry functionality...
 // The rest is in __wxStart and  __wxCleanup.  This function is called when
@@ -113,7 +132,8 @@ void __wxPreStart()
 
 #ifdef WXP_WITH_THREAD
     PyEval_InitThreads();
-    wxPyInterpreter = PyThreadState_Get()->interp;
+    wxPyTStates = new wxPyThreadStateArray;
+    wxPyTMutex = new wxMutex;
 #endif
 
     // Bail out if there is already windows created.  This means that the
@@ -201,8 +221,16 @@ PyObject* __wxStart(PyObject* /* self */, PyObject* args)
     return Py_None;
 }
 
+
 void __wxCleanup() {
     wxEntryCleanup();
+#ifdef WXP_WITH_THREAD
+    delete wxPyTMutex;
+    wxPyTMutex = NULL;
+    wxPyTStates->Empty();
+    delete wxPyTStates;
+    wxPyTStates = NULL;
+#endif
 }
 
 
@@ -229,8 +257,8 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
 #ifdef __WXMOTIF__
 #define wxPlatform "__WXMOTIF__"
 #endif
-#ifdef __WXQT__
-#define wxPlatform "__WXQT__"
+#ifdef __WXX11__
+#define wxPlatform "__WXX11__"
 #endif
 #ifdef __WXGTK__
 #define wxPlatform "__WXGTK__"
@@ -261,7 +289,6 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
 void wxPyPtrTypeMap_Add(const char* commonName, const char* ptrName) {
     if (! wxPyPtrTypeMap)
         wxPyPtrTypeMap = PyDict_New();
-
     PyDict_SetItemString(wxPyPtrTypeMap,
                          (char*)commonName,
                          PyString_FromString((char*)ptrName));
@@ -400,7 +427,7 @@ PyObject* wxPyConstructObject(void* ptr,
     char    buff[64];               // should always be big enough...
     sprintf(buff, "%sPtr", className);
 
-        wxASSERT_MSG(wxPython_dict, "wxPython_dict is not set yet!!");
+    wxASSERT_MSG(wxPython_dict, "wxPython_dict is not set yet!!");
 
     PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff);
     if (! classobj) {
@@ -418,34 +445,384 @@ PyObject* wxPyConstructObject(void* ptr,
 //---------------------------------------------------------------------------
 
 
-wxPyTState* wxPyBeginBlockThreads() {
-    wxPyTState* state = NULL;
 #ifdef WXP_WITH_THREAD
-    if (1) {   // Can I check if I've already got the lock?
-        state = new wxPyTState;
-        PyEval_AcquireLock();
-        state->newState = PyThreadState_New(wxPyInterpreter);
-        state->prevState = PyThreadState_Swap(state->newState);
+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, "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) {
+            info.tstate = tstate;
+            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
-    return state;
 }
 
 
-void wxPyEndBlockThreads(wxPyTState* state) {
+
+// 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
-    if (state) {
-        PyThreadState_Swap(state->prevState);
-        PyThreadState_Clear(state->newState);
-        PyEval_ReleaseLock();
-        PyThreadState_Delete(state->newState);
-        delete state;
-    }
+    PyThreadState* tstate = wxPyGetThreadState();
+    PyEval_RestoreThread(tstate);
+#endif
+}
+
+
+void wxPyEndBlockThreads() {
+#ifdef WXP_WITH_THREAD
+    PyThreadState* tstate = PyEval_SaveThread();
+    // Is there any need to save it again?
 #endif
 }
 
 
 //---------------------------------------------------------------------------
+// wxPyInputStream and wxPyCBInputStream methods
+
+#include <wx/listimpl.cpp>
+WX_DEFINE_LIST(wxStringPtrList);
+
+
+void wxPyInputStream::close() {
+    /* do nothing */
+}
+
+void wxPyInputStream::flush() {
+    /* do nothing */
+}
+
+bool wxPyInputStream::eof() {
+    if (m_wxis)
+        return m_wxis->Eof();
+    else
+        return TRUE;
+}
+
+wxPyInputStream::~wxPyInputStream() {
+    /* do nothing */
+}
+
+wxString* wxPyInputStream::read(int size) {
+    wxString* s = NULL;
+    const int BUFSIZE = 1024;
+
+    // check if we have a real wxInputStream to work with
+    if (!m_wxis) {
+        PyErr_SetString(PyExc_IOError, "no valid C-wxInputStream");
+        return NULL;
+    }
+
+    if (size < 0) {
+        // init buffers
+        char * buf = new char[BUFSIZE];
+        if (!buf) {
+            PyErr_NoMemory();
+            return NULL;
+        }
+
+        s = new wxString();
+        if (!s) {
+            delete buf;
+            PyErr_NoMemory();
+            return NULL;
+        }
+
+        // read until EOF
+        while (! m_wxis->Eof()) {
+            m_wxis->Read(buf, BUFSIZE);
+            s->Append(buf, m_wxis->LastRead());
+        }
+        delete buf;
+
+        // error check
+        if (m_wxis->LastError() == wxSTREAM_READ_ERROR) {
+            delete s;
+            PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
+            return NULL;
+        }
+
+    } else {  // Read only size number of characters
+        s = new wxString;
+        if (!s) {
+            PyErr_NoMemory();
+            return NULL;
+        }
+
+        // read size bytes
+        m_wxis->Read(s->GetWriteBuf(size+1), size);
+        s->UngetWriteBuf(m_wxis->LastRead());
+
+        // error check
+        if (m_wxis->LastError() == wxSTREAM_READ_ERROR) {
+            delete s;
+            PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
+            return NULL;
+        }
+    }
+    return s;
+}
+
+
+wxString* wxPyInputStream::readline (int size) {
+    // check if we have a real wxInputStream to work with
+    if (!m_wxis) {
+        PyErr_SetString(PyExc_IOError,"no valid C-wxInputStream");
+        return NULL;
+    }
+
+    // init buffer
+    int i;
+    char ch;
+    wxString* s = new wxString;
+    if (!s) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+
+    // read until \n or byte limit reached
+    for (i=ch=0; (ch != '\n') && (!m_wxis->Eof()) && ((size < 0) || (i < size)); i++) {
+        *s += ch = m_wxis->GetC();
+    }
+
+    // errorcheck
+    if (m_wxis->LastError() == wxSTREAM_READ_ERROR) {
+        delete s;
+        PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
+        return NULL;
+    }
+    return s;
+}
+
+
+wxStringPtrList* wxPyInputStream::readlines (int sizehint) {
+    // check if we have a real wxInputStream to work with
+    if (!m_wxis) {
+        PyErr_SetString(PyExc_IOError,"no valid C-wxInputStream below");
+        return NULL;
+    }
+
+    // init list
+    wxStringPtrList* l = new wxStringPtrList();
+    if (!l) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+
+    // read sizehint bytes or until EOF
+    int i;
+    for (i=0; (!m_wxis->Eof()) && ((sizehint < 0) || (i < sizehint));) {
+        wxString* s = readline();
+        if (s == NULL) {
+            l->DeleteContents(TRUE);
+            l->Clear();
+            return NULL;
+        }
+        l->Append(s);
+        i = i + s->Length();
+    }
+
+    // error check
+    if (m_wxis->LastError() == wxSTREAM_READ_ERROR) {
+        l->DeleteContents(TRUE);
+        l->Clear();
+        PyErr_SetString(PyExc_IOError,"IOError in wxInputStream");
+        return NULL;
+    }
+    return l;
+}
+
+
+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();
+}
+
+
+wxPyCBInputStream* wxPyCBInputStream::create(PyObject *py, bool block) {
+    if (block) wxPyBeginBlockThreads();
+
+    PyObject* read = getMethod(py, "read");
+    PyObject* seek = getMethod(py, "seek");
+    PyObject* tell = getMethod(py, "tell");
+
+    if (!read) {
+        PyErr_SetString(PyExc_TypeError, "Not a file-like object");
+        Py_XDECREF(read);
+        Py_XDECREF(seek);
+        Py_XDECREF(tell);
+        if (block) wxPyEndBlockThreads();
+        return NULL;
+    }
+
+    if (block) wxPyEndBlockThreads();
+    return new wxPyCBInputStream(read, seek, tell, block);
+}
+
+PyObject* wxPyCBInputStream::getMethod(PyObject* py, char* name) {
+    if (!PyObject_HasAttrString(py, name))
+        return NULL;
+    PyObject* o = PyObject_GetAttrString(py, name);
+    if (!PyMethod_Check(o) && !PyCFunction_Check(o)) {
+        Py_DECREF(o);
+        return NULL;
+    }
+    return o;
+}
+
+
+size_t wxPyCBInputStream::GetSize() const {
+    wxPyCBInputStream* self = (wxPyCBInputStream*)this; // cast off const
+    if (m_seek && m_tell) {
+        off_t temp = self->OnSysTell();
+        off_t ret = self->OnSysSeek(0, wxFromEnd);
+        self->OnSysSeek(temp, wxFromStart);
+        return ret;
+    }
+    else
+        return 0;
+}
+
+
+size_t wxPyCBInputStream::OnSysRead(void *buffer, size_t bufsize) {
+    if (bufsize == 0)
+        return 0;
+
+    wxPyBeginBlockThreads();
+    PyObject* arglist = Py_BuildValue("(i)", bufsize);
+    PyObject* result = PyEval_CallObject(m_read, arglist);
+    Py_DECREF(arglist);
+
+    size_t o = 0;
+    if ((result != NULL) && PyString_Check(result)) {  // TODO: unicode?
+        o = PyString_Size(result);
+        if (o == 0)
+            m_lasterror = wxSTREAM_EOF;
+        if (o > bufsize)
+            o = bufsize;
+        memcpy((char*)buffer, PyString_AsString(result), o);
+        Py_DECREF(result);
+
+    }
+    else
+        m_lasterror = wxSTREAM_READ_ERROR;
+    wxPyEndBlockThreads();
+    m_lastcount = o;
+    return o;
+}
+
+size_t wxPyCBInputStream::OnSysWrite(const void *buffer, size_t bufsize) {
+    m_lasterror = wxSTREAM_WRITE_ERROR;
+    return 0;
+}
+
+off_t wxPyCBInputStream::OnSysSeek(off_t off, wxSeekMode mode) {
+    wxPyBeginBlockThreads();
+    PyObject* arglist = Py_BuildValue("(ii)", off, mode);
+    PyObject* result = PyEval_CallObject(m_seek, arglist);
+    Py_DECREF(arglist);
+    Py_XDECREF(result);
+    wxPyEndBlockThreads();
+    return OnSysTell();
+}
+
+off_t wxPyCBInputStream::OnSysTell() const {
+    wxPyBeginBlockThreads();
+    PyObject* arglist = Py_BuildValue("()");
+    PyObject* result = PyEval_CallObject(m_tell, arglist);
+    Py_DECREF(arglist);
+    off_t o = 0;
+    if (result != NULL) {
+        o = PyInt_AsLong(result);
+        Py_DECREF(result);
+    };
+    wxPyEndBlockThreads();
+    return o;
+}
+
+//----------------------------------------------------------------------
 
 IMPLEMENT_ABSTRACT_CLASS(wxPyCallback, wxObject);
 
@@ -460,9 +837,9 @@ wxPyCallback::wxPyCallback(const wxPyCallback& other) {
 }
 
 wxPyCallback::~wxPyCallback() {
-    wxPyTState* state = wxPyBeginBlockThreads();
+    wxPyBeginBlockThreads();
     Py_DECREF(m_func);
-    wxPyEndBlockThreads(state);
+    wxPyEndBlockThreads();
 }
 
 
@@ -476,7 +853,7 @@ void wxPyCallback::EventThunker(wxEvent& event) {
     PyObject*       tuple;
 
 
-    wxPyTState* state = wxPyBeginBlockThreads();
+    wxPyBeginBlockThreads();
     wxString className = event.GetClassInfo()->GetClassName();
 
     if (className == "wxPyEvent")
@@ -496,7 +873,7 @@ void wxPyCallback::EventThunker(wxEvent& event) {
     } else {
         PyErr_Print();
     }
-    wxPyEndBlockThreads(state);
+    wxPyEndBlockThreads();
 }
 
 
@@ -529,11 +906,11 @@ void wxPyCallbackHelper::setSelf(PyObject* self, PyObject* klass, int incref) {
 // Prior to Python 2.2 PyMethod_GetClass returned the class object
 // in which the method was defined.  Starting with 2.2 it returns
 // "class that asked for the method" which seems totally bogus to me
-// but apprently if fixes some obscure problem waiting to happen in
+// but apprently it fixes some obscure problem waiting to happen in
 // Python.  Since the API was not documented Guido and the gang felt
 // safe in changing it.  Needless to say that totally screwed up the
 // logic below in wxPyCallbackHelper::findCallback, hence this icky
-// code to find the class where the method is actuallt defined...
+// code to find the class where the method is actually defined...
 
 static
 PyObject* PyFindClassWithAttr(PyObject *klass, PyObject *name)
@@ -581,6 +958,7 @@ PyObject* PyFindClassWithAttr(PyObject *klass, PyObject *name)
         }
         return NULL;
     }
+    return NULL;
 }
 #endif
 
@@ -681,10 +1059,10 @@ PyObject* wxPyCBH_callCallbackObj(const wxPyCallbackHelper& cbh, PyObject* argTu
 
 void wxPyCBH_delete(wxPyCallbackHelper* cbh) {
     if (cbh->m_incRef) {
-        wxPyTState* state = wxPyBeginBlockThreads();
+        wxPyBeginBlockThreads();
         Py_XDECREF(cbh->m_self);
         Py_XDECREF(cbh->m_class);
-        wxPyEndBlockThreads(state);
+        wxPyEndBlockThreads();
     }
 }
 
@@ -702,14 +1080,14 @@ wxPyEvtSelfRef::wxPyEvtSelfRef() {
 }
 
 wxPyEvtSelfRef::~wxPyEvtSelfRef() {
-    wxPyTState* state = wxPyBeginBlockThreads();
+    wxPyBeginBlockThreads();
     if (m_cloned)
         Py_DECREF(m_self);
-    wxPyEndBlockThreads(state);
+    wxPyEndBlockThreads();
 }
 
 void wxPyEvtSelfRef::SetSelf(PyObject* self, bool clone) {
-    wxPyTState* state = wxPyBeginBlockThreads();
+    wxPyBeginBlockThreads();
     if (m_cloned)
         Py_DECREF(m_self);
     m_self = self;
@@ -717,7 +1095,7 @@ void wxPyEvtSelfRef::SetSelf(PyObject* self, bool clone) {
         Py_INCREF(m_self);
         m_cloned = TRUE;
     }
-    wxPyEndBlockThreads(state);
+    wxPyEndBlockThreads();
 }
 
 PyObject* wxPyEvtSelfRef::GetSelf() const {
@@ -774,9 +1152,9 @@ wxPyTimer::wxPyTimer(PyObject* callback) {
 }
 
 wxPyTimer::~wxPyTimer() {
-    wxPyTState* state = wxPyBeginBlockThreads();
+    wxPyBeginBlockThreads();
     Py_DECREF(func);
-    wxPyEndBlockThreads(state);
+    wxPyEndBlockThreads();
 }
 
 void wxPyTimer::Notify() {
@@ -784,7 +1162,7 @@ void wxPyTimer::Notify() {
         wxTimer::Notify();
     }
     else {
-        wxPyTState* state = wxPyBeginBlockThreads();
+        wxPyBeginBlockThreads();
 
         PyObject*   result;
         PyObject*   args = Py_BuildValue("()");
@@ -798,7 +1176,7 @@ void wxPyTimer::Notify() {
             PyErr_Print();
         }
 
-        wxPyEndBlockThreads(state);
+        wxPyEndBlockThreads();
     }
 }
 
@@ -814,7 +1192,7 @@ PyObject* wxPy_ConvertList(wxListBase* list, const char* className) {
     wxObject*   wxObj;
     wxNode*     node = list->First();
 
-    wxPyTState* state = wxPyBeginBlockThreads();
+    wxPyBeginBlockThreads();
     pyList = PyList_New(0);
     while (node) {
         wxObj = node->Data();
@@ -822,7 +1200,7 @@ PyObject* wxPy_ConvertList(wxListBase* list, const char* className) {
         PyList_Append(pyList, pyObj);
         node = node->Next();
     }
-    wxPyEndBlockThreads(state);
+    wxPyEndBlockThreads();
     return pyList;
 }
 
@@ -1408,6 +1786,18 @@ PyObject* wxArrayString2PyList_helper(const wxArrayString& arr) {
 }
 
 
+PyObject* wxArrayInt2PyList_helper(const wxArrayInt& arr) {
+
+    PyObject* list = PyList_New(0);
+    for (size_t i=0; i < arr.GetCount(); i++) {
+        PyObject* number = PyInt_FromLong(arr[i]);
+        PyList_Append(list, number);
+        Py_DECREF(number);
+    }
+    return list;
+}
+
+
 //----------------------------------------------------------------------
 //----------------------------------------------------------------------