]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/src/helpers.cpp
Updated the changelog
[wxWidgets.git] / wxPython / src / helpers.cpp
index 6d0cb2173016eeb8e26f73fa23b05b43c20d9a90..9d12d8962ae08ced014f12a88bf438c93295feee 100644 (file)
 #endif
 
 
-//---------------------------------------------------------------------------
-
-//wxHashTable*  wxPyWindows = NULL;
-
-
-wxPoint     wxPyDefaultPosition;        //wxDefaultPosition);
-wxSize      wxPyDefaultSize;            //wxDefaultSize);
-wxString    wxPyEmptyStr("");
-
 
 
 #ifdef __WXMSW__             // If building for win32...
@@ -105,6 +96,11 @@ int  wxPyApp::MainLoop(void) {
 //---------------------------------------------------------------------
 //----------------------------------------------------------------------
 
+#ifdef __WXMSW__
+#include "wx/msw/msvcrt.h"
+#endif
+
+
 int  WXDLLEXPORT wxEntryStart( int argc, char** argv );
 int  WXDLLEXPORT wxEntryInitGui();
 void WXDLLEXPORT wxEntryCleanup();
@@ -113,7 +109,6 @@ void WXDLLEXPORT wxEntryCleanup();
 #ifdef WXP_WITH_THREAD
 PyThreadState*  wxPyEventThreadState = NULL;
 #endif
-static char* __nullArgv[1] = { 0 };
 
 
 // This is where we pick up the first part of the wxEntry functionality...
@@ -121,9 +116,19 @@ static char* __nullArgv[1] = { 0 };
 // wxcmodule is imported.  (Before there is a wxApp object.)
 void __wxPreStart()
 {
+
+#ifdef __WXMSW__
+//    wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
+#endif
+
 #ifdef WXP_WITH_THREAD
+#if 0   // OLD THREAD STUFF
     PyEval_InitThreads();
     wxPyEventThreadState = PyThreadState_Get();
+#else
+    PyEval_InitThreads();
+    wxPyEventThreadState = PyThreadState_New(PyThreadState_Get()->interp);
+#endif
 #endif
 
     // Bail out if there is already windows created.  This means that the
@@ -158,11 +163,12 @@ PyObject* __wxStart(PyObject* /* self */, PyObject* args)
     if (!PyArg_ParseTuple(args, "O", &onInitFunc))
         return NULL;
 
+#if 0  // Try it out without this check, see how it does...
     if (wxTopLevelWindows.Number() > 0) {
         PyErr_SetString(PyExc_TypeError, "Only 1 wxApp per process!");
         return NULL;
     }
-
+#endif
 
     // This is the next part of the wxEntry functionality...
     PyObject* sysargv = PySys_GetObject("argv");
@@ -248,6 +254,14 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
 PyObject* wxPyConstructObject(void* ptr,
                               const char* className,
                               int setThisOwn) {
+    PyObject* obj;
+    PyObject* arg;
+
+    if (!ptr) {
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+
     char    buff[64];               // should always be big enough...
     char    swigptr[64];
 
@@ -257,16 +271,24 @@ PyObject* wxPyConstructObject(void* ptr,
     sprintf(buff, "%sPtr", className);
     PyObject* classobj = PyDict_GetItemString(wxPython_dict, buff);
     if (! classobj) {
-        Py_INCREF(Py_None);
-        return Py_None;
+        //Py_INCREF(Py_None);
+        //return Py_None;
+        char temp[128];
+        sprintf(temp,
+                "*** Unknown class name %s, tell Robin about it please ***",
+                buff);
+        obj = PyString_FromString(temp);
+        return obj;
     }
 
-    PyObject* arg = Py_BuildValue("(s)", swigptr);
-    PyObject* obj = PyInstance_New(classobj, arg, NULL);
+    arg = Py_BuildValue("(s)", swigptr);
+    obj = PyInstance_New(classobj, arg, NULL);
     Py_DECREF(arg);
 
     if (setThisOwn) {
-        PyObject_SetAttrString(obj, "thisown", PyInt_FromLong(1));
+        PyObject* one = PyInt_FromLong(1);
+        PyObject_SetAttrString(obj, "thisown", one);
+        Py_DECREF(one);
     }
 
     return obj;
@@ -274,8 +296,6 @@ PyObject* wxPyConstructObject(void* ptr,
 
 //---------------------------------------------------------------------------
 
-static unsigned int _wxPyNestCount = 0;
-
 static PyThreadState* myPyThreadState_Get() {
     PyThreadState* current;
     current = PyThreadState_Swap(NULL);
@@ -284,7 +304,7 @@ static PyThreadState* myPyThreadState_Get() {
 }
 
 
-HELPEREXPORT bool wxPyRestoreThread() {
+bool wxPyRestoreThread() {
     // NOTE: The Python API docs state that if a thread already has the
     // interpreter lock and calls PyEval_RestoreThread again a deadlock
     // occurs, so I put in this code as a guard condition since there are
@@ -293,23 +313,35 @@ HELPEREXPORT bool wxPyRestoreThread() {
     // already have the lock.  (I hope!)
     //
 #ifdef WXP_WITH_THREAD
-    _wxPyNestCount += 1;
+#if 0   // OLD THREAD STUFF
     if (wxPyEventThreadState != myPyThreadState_Get()) {
         PyEval_RestoreThread(wxPyEventThreadState);
         return TRUE;
     }
     else
+#else
+    if (wxPyEventThreadState != myPyThreadState_Get()) {
+        PyEval_AcquireThread(wxPyEventThreadState);
+        return TRUE;
+    }
+    else
+#endif
 #endif
         return FALSE;
 }
 
 
-HELPEREXPORT void wxPySaveThread(bool doSave) {
+void wxPySaveThread(bool doSave) {
 #ifdef WXP_WITH_THREAD
+#if 0   // OLD THREAD STUFF
     if (doSave) {
         wxPyEventThreadState = PyEval_SaveThread();
     }
-    _wxPyNestCount -= 1;
+#else
+    if (doSave) {
+        PyEval_ReleaseThread(wxPyEventThreadState);
+    }
+#endif
 #endif
 }
 
@@ -371,23 +403,6 @@ void wxPyCallback::EventThunker(wxEvent& event) {
 
 //----------------------------------------------------------------------
 
-wxPyCallbackHelper::wxPyCallbackHelper() {
-    m_class = NULL;
-    m_self = NULL;
-    m_lastFound = NULL;
-    m_incRef = FALSE;
-}
-
-
-wxPyCallbackHelper::~wxPyCallbackHelper() {
-    bool doSave = wxPyRestoreThread();
-    if (m_incRef) {
-        Py_XDECREF(m_self);
-        Py_XDECREF(m_class);
-    }
-    wxPySaveThread(doSave);
-}
-
 wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper& other) {
       m_lastFound = NULL;
       m_self = other.m_self;
@@ -399,9 +414,9 @@ wxPyCallbackHelper::wxPyCallbackHelper(const wxPyCallbackHelper& other) {
 }
 
 
-void wxPyCallbackHelper::setSelf(PyObject* self, PyObject* _class, int incref) {
+void wxPyCallbackHelper::setSelf(PyObject* self, PyObject* klass, int incref) {
     m_self = self;
-    m_class = _class;
+    m_class = klass;
     m_incRef = incref;
     if (incref) {
         Py_INCREF(m_self);
@@ -413,12 +428,12 @@ void wxPyCallbackHelper::setSelf(PyObject* self, PyObject* _class, int incref) {
 // If the object (m_self) has an attibute of the given name, and if that
 // attribute is a method, and if that method's class is not from a base class,
 // then we'll save a pointer to the method so callCallback can call it.
-bool wxPyCallbackHelper::findCallback(const wxString& name) const {
+bool wxPyCallbackHelper::findCallback(const char* name) const {
     wxPyCallbackHelper* self = (wxPyCallbackHelper*)this; // cast away const
     self->m_lastFound = NULL;
-    if (m_self && PyObject_HasAttrString(m_self, (char*)name.c_str())) {
+    if (m_self && PyObject_HasAttrString(m_self, (char*)name)) {
         PyObject* method;
-        method = PyObject_GetAttrString(m_self, (char*)name.c_str());
+        method = PyObject_GetAttrString(m_self, (char*)name);
 
         if (PyMethod_Check(method) &&
             ((PyMethod_GET_CLASS(method) == m_class) ||
@@ -426,6 +441,9 @@ bool wxPyCallbackHelper::findCallback(const wxString& name) const {
 
             self->m_lastFound = method;
         }
+        else {
+            Py_DECREF(method);
+        }
     }
     return m_lastFound != NULL;
 }
@@ -447,10 +465,16 @@ int wxPyCallbackHelper::callCallback(PyObject* argTuple) const {
 // Invoke the Python callable object, returning the raw PyObject return
 // value.  Caller should DECREF the return value and also call PyEval_SaveThread.
 PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) const {
-    PyObject*   result;
+    PyObject* result;
+
+    // Save a copy of the pointer in case the callback generates another
+    // callback.  In that case m_lastFound will have a different value when
+    // it gets back here...
+    PyObject* method = m_lastFound;
 
-    result = PyEval_CallObject(m_lastFound, argTuple);
+    result = PyEval_CallObject(method, argTuple);
     Py_DECREF(argTuple);
+    Py_DECREF(method);
     if (!result) {
         PyErr_Print();
     }
@@ -458,6 +482,31 @@ PyObject* wxPyCallbackHelper::callCallbackObj(PyObject* argTuple) const {
 }
 
 
+void wxPyCBH_setSelf(wxPyCallbackHelper& cbh, PyObject* self, PyObject* klass, int incref) {
+    cbh.setSelf(self, klass, incref);
+}
+
+bool wxPyCBH_findCallback(const wxPyCallbackHelper& cbh, const char* name) {
+    return cbh.findCallback(name);
+}
+
+int  wxPyCBH_callCallback(const wxPyCallbackHelper& cbh, PyObject* argTuple) {
+    return cbh.callCallback(argTuple);
+}
+
+PyObject* wxPyCBH_callCallbackObj(const wxPyCallbackHelper& cbh, PyObject* argTuple) {
+    return cbh.callCallbackObj(argTuple);
+}
+
+
+void wxPyCBH_delete(wxPyCallbackHelper* cbh) {
+    bool doSave = wxPyRestoreThread();
+    if (cbh->m_incRef) {
+        Py_XDECREF(cbh->m_self);
+        Py_XDECREF(cbh->m_class);
+    }
+    wxPySaveThread(doSave);
+}
 
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
@@ -547,20 +596,26 @@ wxPyTimer::~wxPyTimer() {
 }
 
 void wxPyTimer::Notify() {
-    bool doSave = wxPyRestoreThread();
-
-    PyObject*   result;
-    PyObject*   args = Py_BuildValue("()");
+    if (!func || func == Py_None) {
+        wxTimer::Notify();
+    }
+    else {
+        bool doSave = wxPyRestoreThread();
+
+        PyObject*   result;
+        PyObject*   args = Py_BuildValue("()");
+
+        result = PyEval_CallObject(func, args);
+        Py_DECREF(args);
+        if (result) {
+            Py_DECREF(result);
+            PyErr_Clear();
+        } else {
+            PyErr_Print();
+        }
 
-    result = PyEval_CallObject(func, args);
-    Py_DECREF(args);
-    if (result) {
-        Py_DECREF(result);
-        PyErr_Clear();
-    } else {
-        PyErr_Print();
+        wxPySaveThread(doSave);
     }
-    wxPySaveThread(doSave);
 }
 
 
@@ -702,43 +757,120 @@ char** string_LIST_helper(PyObject* source) {
     return temp;
 }
 
+//--------------------------------
+// Part of patch from Tim Hochberg
+static inline bool wxPointFromObjects(PyObject* o1, PyObject* o2, wxPoint* point) {
+    if (PyInt_Check(o1) && PyInt_Check(o2)) {
+        point->x = PyInt_AS_LONG(o1);
+        point->y = PyInt_AS_LONG(o2);
+        return true;
+    }
+    if (PyFloat_Check(o1) && PyFloat_Check(o2)) {
+        point->x = (int)PyFloat_AS_DOUBLE(o1);
+        point->y = (int)PyFloat_AS_DOUBLE(o2);
+        return true;
+    }
+    if (PyInstance_Check(o1) || PyInstance_Check(o2)) {
+        // Disallow instances because they can cause havok
+        return false;
+    }
+    if (PyNumber_Check(o1) && PyNumber_Check(o2)) {
+        // I believe this excludes instances, so this should be safe without INCREFFing o1 and o2
+        point->x = PyInt_AsLong(o1);
+        point->y = PyInt_AsLong(o2);
+        return true;
+    }
+    return false;
+}
 
 
-wxPoint* wxPoint_LIST_helper(PyObject* source) {
-    if (!PyList_Check(source)) {
-        PyErr_SetString(PyExc_TypeError, "Expected a list object.");
-        return NULL;
+#if PYTHON_API_VERSION < 1009
+#define PySequence_Fast_GET_ITEM(o, i)\
+     (PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i))
+#endif
+
+wxPoint* wxPoint_LIST_helper(PyObject* source, int *count) {
+    // Putting all of the declarations here allows
+    // us to put the error handling all in one place.
+    int x;
+    wxPoint* temp;
+    PyObject *o, *o1, *o2;
+    int isFast = PyList_Check(source) || PyTuple_Check(source);
+
+    // The length of the sequence is returned in count.
+    if (!PySequence_Check(source)) {
+        goto error0;
     }
-    int count = PyList_Size(source);
-    wxPoint* temp = new wxPoint[count];
-    if (! temp) {
+    *count = PySequence_Length(source);
+    if (*count < 0) {
+        goto error0;
+    }
+
+    temp = new wxPoint[*count];
+    if (!temp) {
         PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
         return NULL;
     }
-    for (int x=0; x<count; x++) {
-        PyObject* o = PyList_GetItem(source, x);
-        if (PyTuple_Check(o)) {
-            PyObject* o1 = PyTuple_GetItem(o, 0);
-            PyObject* o2 = PyTuple_GetItem(o, 1);
+    for (x=0; x<*count; x++) {
+        // Get an item: try fast way first.
+        if (isFast) {
+            o = PySequence_Fast_GET_ITEM(source, x);
+        }
+        else {
+            o = PySequence_GetItem(source, x);
+            if (o == NULL) {
+                goto error1;
+            }
+        }
 
-            temp[x].x = PyInt_AsLong(o1);
-            temp[x].y = PyInt_AsLong(o2);
+        // Convert o to wxPoint.
+        if ((PyTuple_Check(o) && PyTuple_GET_SIZE(o) == 2) ||
+            (PyList_Check(o) && PyList_GET_SIZE(o) == 2)) {
+            o1 = PySequence_Fast_GET_ITEM(o, 0);
+            o2 = PySequence_Fast_GET_ITEM(o, 1);
+            if (!wxPointFromObjects(o1, o2, &temp[x])) {
+                goto error2;
+            }
         }
         else if (PyInstance_Check(o)) {
             wxPoint* pt;
-            if (SWIG_GetPtrObj(o,(void **) &pt,"_wxPoint_p")) {
-                PyErr_SetString(PyExc_TypeError,"Expected _wxPoint_p.");
-                return NULL;
+            if (SWIG_GetPtrObj(o, (void **)&pt, "_wxPoint_p")) {
+                goto error2;
             }
             temp[x] = *pt;
         }
+        else if (PySequence_Check(o) && PySequence_Length(o) == 2) {
+            o1 = PySequence_GetItem(o, 0);
+            o2 = PySequence_GetItem(o, 1);
+            if (!wxPointFromObjects(o1, o2, &temp[x])) {
+                goto error3;
+            }
+            Py_DECREF(o1);
+            Py_DECREF(o2);
+        }
         else {
-            PyErr_SetString(PyExc_TypeError, "Expected a list of 2-tuples or wxPoints.");
-            return NULL;
+            goto error2;
         }
+        // Clean up.
+        if (!isFast)
+            Py_DECREF(o);
     }
     return temp;
+
+error3:
+    Py_DECREF(o1);
+    Py_DECREF(o2);
+error2:
+    if (!isFast)
+        Py_DECREF(o);
+error1:
+    delete temp;
+error0:
+    PyErr_SetString(PyExc_TypeError, "Expected a sequence of length-2 sequences or wxPoints.");
+    return NULL;
 }
+// end of patch
+//------------------------------
 
 
 wxBitmap** wxBitmap_LIST_helper(PyObject* source) {
@@ -870,14 +1002,21 @@ bool wxPoint_helper(PyObject* source, wxPoint** obj) {
         *obj = ptr;
         return TRUE;
     }
-    // otherwise a 2-tuple of integers is expected
-    else if (PySequence_Check(source) && PyObject_Length(source) == 2) {
+    // otherwise a length-2 sequence of integers is expected
+    if (PySequence_Check(source) && PySequence_Length(source) == 2) {
         PyObject* o1 = PySequence_GetItem(source, 0);
         PyObject* o2 = PySequence_GetItem(source, 1);
-        **obj = wxPoint(PyInt_AsLong(o1), PyInt_AsLong(o2));
+               // This should really check for integers, not numbers -- but that would break code.
+               if (!PyNumber_Check(o1) || !PyNumber_Check(o2)) {
+                       Py_DECREF(o1);
+                   Py_DECREF(o2);
+                       goto error;
+               }
+               **obj = wxPoint(PyInt_AsLong(o1), PyInt_AsLong(o2));
+               Py_DECREF(o1);
+               Py_DECREF(o2);
         return TRUE;
     }
-
  error:
     PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of integers or a wxPoint object.");
     return FALSE;
@@ -952,7 +1091,7 @@ bool wxColour_helper(PyObject* source, wxColour** obj) {
     // otherwise a string is expected
     else if (PyString_Check(source)) {
         wxString spec = PyString_AS_STRING(source);
-        if (spec[0] == '#' && spec.Length() == 7) {  // It's  #RRGGBB
+        if (spec[0U] == '#' && spec.Length() == 7) {  // It's  #RRGGBB
             char* junk;
             int red   = strtol(spec.Mid(1,2), &junk, 16);
             int green = strtol(spec.Mid(3,2), &junk, 16);
@@ -967,7 +1106,7 @@ bool wxColour_helper(PyObject* source, wxColour** obj) {
     }
 
  error:
-    PyErr_SetString(PyExc_TypeError, "Expected a wxColour object or a string containing a colour name or #RRGGBB.");
+    PyErr_SetString(PyExc_TypeError, "Expected a wxColour object or a string containing a colour name or '#RRGGBB'.");
     return FALSE;
 }
 
@@ -978,3 +1117,4 @@ bool wxColour_helper(PyObject* source, wxColour** obj) {
 
 
 
+