]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/src/helpers.cpp
fix bug in WX_GL_DOUBLEBUFFER handling introduced during the last great refactoring
[wxWidgets.git] / wxPython / src / helpers.cpp
index d562546189a972676fcc4bb18b82b1e8de7ba3c8..41b3c33a5d2f3e196b5beedac13b3955e50efac1 100644 (file)
 #include <gdk/gdkx.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkprivate.h>
+#ifdef __WXGTK20__
 #include <wx/gtk/win_gtk.h>
+#else
+#include <wx/gtk1/win_gtk.h>
+#endif
 #define GetXWindow(wxwin) (wxwin)->m_wxwindow ? \
                           GDK_WINDOW_XWINDOW(GTK_PIZZA((wxwin)->m_wxwindow)->bin_window) : \
                           GDK_WINDOW_XWINDOW((wxwin)->m_widget->window)
@@ -293,6 +297,17 @@ void wxPyApp::MacOpenFile(const wxString &fileName)
     wxPyEndBlockThreads(blocked);
 }
 
+void wxPyApp::MacOpenURL(const wxString &url)
+{
+    wxPyBlock_t blocked = wxPyBeginBlockThreads();
+    if (wxPyCBH_findCallback(m_myInst, "MacOpenURL")) {
+        PyObject* s = wx2PyString(url);
+        wxPyCBH_callCallback(m_myInst, Py_BuildValue("(O)", s));
+        Py_DECREF(s);
+    }
+    wxPyEndBlockThreads(blocked);
+}
+
 void wxPyApp::MacPrintFile(const wxString &fileName)
 {
     wxPyBlock_t blocked = wxPyBeginBlockThreads();
@@ -323,11 +338,7 @@ void wxPyApp::MacReopenApp()
 
 /*static*/
 bool wxPyApp::GetMacSupportPCMenuShortcuts() {
-#ifdef __WXMAC__
-    return s_macSupportPCMenuShortcuts;
-#else
     return 0;
-#endif
 }
 
 /*static*/
@@ -367,10 +378,7 @@ wxString wxPyApp::GetMacHelpMenuTitleName() {
 }
 
 /*static*/
-void wxPyApp::SetMacSupportPCMenuShortcuts(bool val) {
-#ifdef __WXMAC__
-    s_macSupportPCMenuShortcuts = val;
-#endif
+void wxPyApp::SetMacSupportPCMenuShortcuts(bool) {
 }
 
 /*static*/
@@ -495,6 +503,8 @@ void wxPyApp::_BootstrapApp()
         Py_DECREF(argTuple);
         Py_DECREF(method);
         if (retval == NULL)
+            // Don't PyErr_Print here, let the exception in this case go back
+            // up to the wx.PyApp.__init__ scope.
             goto error;
 
         pyint = PyNumber_Int(retval);
@@ -713,7 +723,19 @@ PyObject* __wxPySetDictionary(PyObject* /* self */, PyObject* args)
     _AddInfoString("wx-assertions-off");
 #endif
     _AddInfoString(wxPy_SWIG_VERSION);    
-    
+#ifdef __WXMAC__
+    #if wxMAC_USE_CORE_GRAPHICS
+        _AddInfoString("mac-cg");
+    #else
+        _AddInfoString("mac-qd");
+    #endif
+    #if wxMAC_USE_NATIVE_TOOLBAR
+        _AddInfoString("mac-native-tb");
+    #else
+        _AddInfoString("mac-no-native-tb");
+    #endif
+#endif
+        
 #undef _AddInfoString
 
     PyObject* PlatInfoTuple = PyList_AsTuple(PlatInfo);
@@ -820,6 +842,7 @@ void wxPyOORClientData_dtor(wxPyOORClientData* self) {
             //Py_INCREF(deadObjectClass);
             Py_DECREF(klass);
             Py_DECREF(name);
+            Py_DECREF(dict);
         }
     }
 
@@ -1067,6 +1090,21 @@ void wxPyEndBlockThreads(wxPyBlock_t blocked) {
 // wxPyInputStream and wxPyCBInputStream methods
 
 
+static PyObject* wxPyGetMethod(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;
+}
+
+
+
+
 void wxPyInputStream::close() {
     /* do nothing for now */
 }
@@ -1223,7 +1261,7 @@ void wxPyInputStream::seek(int offset, int whence) {
         m_wxis->SeekI(offset, wxSeekMode(whence));
 }
 
-int wxPyInputStream::tell(){
+int wxPyInputStream::tell() {
     if (m_wxis)
         return m_wxis->TellI();
     else return 0;
@@ -1249,7 +1287,7 @@ wxPyCBInputStream::wxPyCBInputStream(const wxPyCBInputStream& other)
 
 
 wxPyCBInputStream::~wxPyCBInputStream() {
-    wxPyBlock_t blocked;
+    wxPyBlock_t blocked = wxPyBlock_t_default;
     if (m_block) blocked = wxPyBeginBlockThreads();
     Py_XDECREF(m_read);
     Py_XDECREF(m_seek);
@@ -1259,12 +1297,12 @@ wxPyCBInputStream::~wxPyCBInputStream() {
 
 
 wxPyCBInputStream* wxPyCBInputStream::create(PyObject *py, bool block) {
-    wxPyBlock_t blocked;
+    wxPyBlock_t blocked = wxPyBlock_t_default;
     if (block) blocked = wxPyBeginBlockThreads();
 
-    PyObject* read = getMethod(py, "read");
-    PyObject* seek = getMethod(py, "seek");
-    PyObject* tell = getMethod(py, "tell");
+    PyObject* read = wxPyGetMethod(py, "read");
+    PyObject* seek = wxPyGetMethod(py, "seek");
+    PyObject* tell = wxPyGetMethod(py, "tell");
 
     if (!read) {
         PyErr_SetString(PyExc_TypeError, "Not a file-like object");
@@ -1288,17 +1326,6 @@ wxPyCBInputStream* wxPyCBInputStream_copy(wxPyCBInputStream* other) {
     return new wxPyCBInputStream(*other);
 }
 
-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;
-}
-
 
 wxFileOffset wxPyCBInputStream::GetLength() const {
     wxPyCBInputStream* self = (wxPyCBInputStream*)this; // cast off const
@@ -1383,6 +1410,196 @@ wxFileOffset wxPyCBInputStream::OnSysTell() const {
     return o;
 }
 
+//----------------------------------------------------------------------
+// Output stream
+
+wxPyOutputStream::~wxPyOutputStream()
+{
+    if (m_wxos)
+        delete m_wxos;
+}
+
+void wxPyOutputStream::close()
+{
+}
+
+void wxPyOutputStream::flush()
+{
+}
+
+bool wxPyOutputStream::eof()
+{
+    return false;
+}
+
+void wxPyOutputStream::seek(int offset, int whence)
+{
+    if (m_wxos)
+        m_wxos->SeekO(offset, wxSeekMode(whence));
+}
+
+int wxPyOutputStream::tell()
+{
+    if (m_wxos)
+        return m_wxos->TellO();
+    else return 0;
+}
+
+void wxPyOutputStream::write(PyObject* data)
+{
+    if (!m_wxos)
+        return;
+    
+    // We use only strings for the streams, not unicode
+    PyObject* str = PyObject_Str(data);
+    if (! str) {
+        PyErr_SetString(PyExc_TypeError, "Unable to convert to string");
+        return;
+    }
+    m_wxos->Write(PyString_AS_STRING(str), PyString_GET_SIZE(str));
+    Py_DECREF(str);
+}
+  
+
+
+
+
+
+wxPyCBOutputStream::wxPyCBOutputStream(PyObject *w, PyObject *s, PyObject *t, bool block)
+    : wxOutputStream(), m_write(w), m_seek(s), m_tell(t), m_block(block)
+{}
+
+wxPyCBOutputStream::wxPyCBOutputStream(const wxPyCBOutputStream& other)
+{
+    m_write = other.m_write;
+    m_seek  = other.m_seek;
+    m_tell  = other.m_tell;
+    m_block = other.m_block;
+    Py_INCREF(m_write);
+    Py_INCREF(m_seek);
+    Py_INCREF(m_tell);
+}
+
+
+wxPyCBOutputStream::~wxPyCBOutputStream() {
+    wxPyBlock_t blocked = wxPyBlock_t_default;
+    if (m_block) blocked = wxPyBeginBlockThreads();
+    Py_XDECREF(m_write);
+    Py_XDECREF(m_seek);
+    Py_XDECREF(m_tell);
+    if (m_block) wxPyEndBlockThreads(blocked);
+}
+
+
+wxPyCBOutputStream* wxPyCBOutputStream::create(PyObject *py, bool block) {
+    wxPyBlock_t blocked = wxPyBlock_t_default;
+    if (block) blocked = wxPyBeginBlockThreads();
+
+    PyObject* write = wxPyGetMethod(py, "write");
+    PyObject* seek = wxPyGetMethod(py, "seek");
+    PyObject* tell = wxPyGetMethod(py, "tell");
+
+    if (!write) {
+        PyErr_SetString(PyExc_TypeError, "Not a file-like object");
+        Py_XDECREF(write);
+        Py_XDECREF(seek);
+        Py_XDECREF(tell);
+        if (block) wxPyEndBlockThreads(blocked);
+        return NULL;
+    }
+
+    if (block) wxPyEndBlockThreads(blocked);
+    return new wxPyCBOutputStream(write, seek, tell, block);
+}
+
+
+wxPyCBOutputStream* wxPyCBOutputStream_create(PyObject *py, bool block) {
+    return wxPyCBOutputStream::create(py, block);
+}
+
+wxPyCBOutputStream* wxPyCBOutputStream_copy(wxPyCBOutputStream* other) {
+    return new wxPyCBOutputStream(*other);
+}
+
+
+wxFileOffset wxPyCBOutputStream::GetLength() const {
+    wxPyCBOutputStream* self = (wxPyCBOutputStream*)this; // cast off const
+    if (m_seek && m_tell) {
+        wxFileOffset temp = self->OnSysTell();
+        wxFileOffset ret = self->OnSysSeek(0, wxFromEnd);
+        self->OnSysSeek(temp, wxFromStart);
+        return ret;
+    }
+    else
+        return wxInvalidOffset;
+}
+
+
+size_t wxPyCBOutputStream::OnSysRead(void *buffer, size_t bufsize) {
+    m_lasterror = wxSTREAM_READ_ERROR;
+    return 0;
+}
+
+size_t wxPyCBOutputStream::OnSysWrite(const void *buffer, size_t bufsize) {
+    if (bufsize == 0)
+        return 0;
+    
+    wxPyBlock_t blocked = wxPyBeginBlockThreads();
+    PyObject* arglist = PyTuple_New(1);
+    PyTuple_SET_ITEM(arglist, 0, PyString_FromStringAndSize((char*)buffer, bufsize));
+    
+    PyObject* result = PyEval_CallObject(m_write, arglist);
+    Py_DECREF(arglist);
+
+    if (result != NULL)
+        Py_DECREF(result);
+    else
+        m_lasterror = wxSTREAM_WRITE_ERROR;
+    wxPyEndBlockThreads(blocked);
+    return bufsize;
+}
+
+
+wxFileOffset wxPyCBOutputStream::OnSysSeek(wxFileOffset off, wxSeekMode mode) {
+    wxPyBlock_t blocked = wxPyBeginBlockThreads();
+    PyObject* arglist = PyTuple_New(2);
+
+    if (sizeof(wxFileOffset) > sizeof(long))
+        // wxFileOffset is a 64-bit value...
+        PyTuple_SET_ITEM(arglist, 0, PyLong_FromLongLong(off));
+    else
+        PyTuple_SET_ITEM(arglist, 0, PyInt_FromLong(off));
+
+    PyTuple_SET_ITEM(arglist, 1, PyInt_FromLong(mode));
+
+
+    PyObject* result = PyEval_CallObject(m_seek, arglist);
+    Py_DECREF(arglist);
+    Py_XDECREF(result);
+    wxPyEndBlockThreads(blocked);
+    return OnSysTell();
+}
+
+
+wxFileOffset wxPyCBOutputStream::OnSysTell() const {
+    wxPyBlock_t blocked = wxPyBeginBlockThreads();
+    PyObject* arglist = Py_BuildValue("()");
+    PyObject* result = PyEval_CallObject(m_tell, arglist);
+    Py_DECREF(arglist);
+    wxFileOffset o = 0;
+    if (result != NULL) {
+        if (PyLong_Check(result))
+            o = PyLong_AsLongLong(result);
+        else
+            o = PyInt_AsLong(result);
+        Py_DECREF(result);
+    };
+    wxPyEndBlockThreads(blocked);
+    return o;
+}
+
+
+
 //----------------------------------------------------------------------
 
 IMPLEMENT_ABSTRACT_CLASS(wxPyCallback, wxObject);
@@ -1713,7 +1930,7 @@ PyObject* wxPyCBH_callCallbackObj(const wxPyCallbackHelper& cbh, PyObject* argTu
 
 
 void wxPyCBH_delete(wxPyCallbackHelper* cbh) {
-    if (cbh->m_incRef) {
+    if (cbh->m_incRef && Py_IsInitialized()) {
         wxPyBlock_t blocked = wxPyBeginBlockThreads();
         Py_XDECREF(cbh->m_self);
         Py_XDECREF(cbh->m_class);
@@ -1815,6 +2032,7 @@ PyObject* wxPy_ConvertList(wxListBase* listbase) {
         wxObj = node->GetData();
         pyObj = wxPyMake_wxObject(wxObj,false);
         PyList_Append(pyList, pyObj);
+        Py_DECREF(pyObj);  // the Append also does an INCREF, that's one more than we need.
         node = node->GetNext();
     }
     wxPyEndBlockThreads(blocked);
@@ -1861,8 +2079,7 @@ wxString* wxString_in_helper(PyObject* source) {
     target = new wxString();
     size_t len = PyUnicode_GET_SIZE(uni);
     if (len) {
-        PyUnicode_AsWideChar((PyUnicodeObject*)uni, target->GetWriteBuf(len), len);
-        target->UngetWriteBuf(len);
+        PyUnicode_AsWideChar((PyUnicodeObject*)uni, wxStringBuffer(*target, len), len);
     }
 
     if (PyString_Check(source))
@@ -1904,8 +2121,7 @@ wxString Py2wxString(PyObject* source)
     }
     size_t len = PyUnicode_GET_SIZE(uni);
     if (len) {
-        PyUnicode_AsWideChar((PyUnicodeObject*)uni, target.GetWriteBuf(len), len);
-        target.UngetWriteBuf();
+        PyUnicode_AsWideChar((PyUnicodeObject*)uni, wxStringBuffer(target, len), len);
     }
 
     if (!PyUnicode_Check(source))
@@ -2051,37 +2267,73 @@ 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)) {
+//---------------------------------------------------------------------------
+// NOTE: The following functions could really use some refactoring using
+// templates to make things somewhat simpler...
+
+inline bool wxPointFromObjects(PyObject* o1, PyObject* o2, wxPoint* point)
+{
+    // get the x value
+    if (PyInt_Check(o1))
+        point->x = (int)PyInt_AS_LONG(o1);
+    else if (PyFloat_Check(o1))
         point->x = (int)PyFloat_AS_DOUBLE(o1);
+    else if (PyNumber_Check(o1))
+        point->x = (int)PyInt_AsLong(o1);
+    else
+        return false;
+
+    // get the y value
+    if (PyInt_Check(o2))
+        point->y = (int)PyInt_AS_LONG(o2);
+    else if (PyFloat_Check(o2))
         point->y = (int)PyFloat_AS_DOUBLE(o2);
-        return true;
-    }
-    if (wxPySwigInstance_Check(o1) || wxPySwigInstance_Check(o2)) {  // TODO: Why???
-        // Disallow instances because they can cause havok
+    else if (PyNumber_Check(o2))
+        point->y = (int)PyInt_AsLong(o2);
+    else
         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;
+
+    return true;
+
+// NOTE: This function used to have this code in it, but I don't know why it
+// is a problem nor what havok it will cause, so removing for now...
+//     if (wxPySwigInstance_Check(o1) || wxPySwigInstance_Check(o2)) {  
+//         // Disallow instances because they can cause havok
+//         return false;
+//     }
 }
 
 
-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;
+inline bool wxPoint2DFromObjects(PyObject* o1, PyObject* o2, wxPoint2D* point)
+{
+    // get the x value
+    if (PyInt_Check(o1))
+        point->m_x = (double)PyInt_AS_LONG(o1);
+    else if (PyFloat_Check(o1))
+        point->m_x = (double)PyFloat_AS_DOUBLE(o1);
+    else if (PyNumber_Check(o1))
+        point->m_x = (double)PyFloat_AsDouble(o1);
+    else
+        return false;
+
+    // get the y value
+    if (PyInt_Check(o2))
+        point->m_y = (double)PyInt_AS_LONG(o2);
+    else if (PyFloat_Check(o2))
+        point->m_y = (double)PyFloat_AS_DOUBLE(o2);
+    else if (PyNumber_Check(o2))
+        point->m_y = (double)PyFloat_AsDouble(o2);
+    else
+        return false;
+
+    return true;
+}
+
+
+
+wxPoint* wxPoint_LIST_helper(PyObject* source, int *count)
+{
+    int idx;
     wxPoint* temp;
     PyObject *o, *o1, *o2;
     bool isFast = PyList_Check(source) || PyTuple_Check(source);
@@ -2101,13 +2353,13 @@ wxPoint* wxPoint_LIST_helper(PyObject* source, int *count) {
         PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
         return NULL;
     }
-    for (x=0; x<*count; x++) {
+    for (idx=0; idx<*count; idx++) {
         // Get an item: try fast way first.
         if (isFast) {
-            o = PySequence_Fast_GET_ITEM(source, x);
+            o = PySequence_Fast_GET_ITEM(source, idx);
         }
         else {
-            o = PySequence_GetItem(source, x);
+            o = PySequence_GetItem(source, idx);
             if (o == NULL) {
                 goto error1;
             }
@@ -2118,7 +2370,7 @@ wxPoint* wxPoint_LIST_helper(PyObject* source, int *count) {
             (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])) {
+            if (!wxPointFromObjects(o1, o2, &temp[idx])) {
                 goto error2;
             }
         }
@@ -2127,12 +2379,12 @@ wxPoint* wxPoint_LIST_helper(PyObject* source, int *count) {
             if (! wxPyConvertSwigPtr(o, (void **)&pt, wxT("wxPoint"))) {
                 goto error2;
             }
-            temp[x] = *pt;
+            temp[idx] = *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])) {
+            if (!wxPointFromObjects(o1, o2, &temp[idx])) {
                 goto error3;
             }
             Py_DECREF(o1);
@@ -2159,8 +2411,91 @@ error0:
     PyErr_SetString(PyExc_TypeError, "Expected a sequence of length-2 sequences or wxPoints.");
     return NULL;
 }
-// end of patch
-//------------------------------
+
+
+
+wxPoint2D* wxPoint2D_LIST_helper(PyObject* source, size_t *count)
+{
+    size_t idx;
+    wxPoint2D* temp;
+    PyObject *o, *o1, *o2;
+    bool isFast = PyList_Check(source) || PyTuple_Check(source);
+
+    if (!PySequence_Check(source)) {
+        goto error0;
+    }
+
+    // The length of the sequence is returned in count.
+    *count = PySequence_Length(source);
+    if (*count < 0) {
+        goto error0;
+    }
+
+    temp = new wxPoint2D[*count];
+    if (!temp) {
+        PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
+        return NULL;
+    }
+    for (idx=0; idx<*count; idx++) {
+        // Get an item: try fast way first.
+        if (isFast) {
+            o = PySequence_Fast_GET_ITEM(source, idx);
+        }
+        else {
+            o = PySequence_GetItem(source, idx);
+            if (o == NULL) {
+                goto error1;
+            }
+        }
+
+        // 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 (!wxPoint2DFromObjects(o1, o2, &temp[idx])) {
+                goto error2;
+            }
+        }
+        else if (wxPySwigInstance_Check(o)) {
+            wxPoint2D* pt;
+            if (! wxPyConvertSwigPtr(o, (void **)&pt, wxT("wxPoint2D"))) {
+                goto error2;
+            }
+            temp[idx] = *pt;
+        }
+        else if (PySequence_Check(o) && PySequence_Length(o) == 2) {
+            o1 = PySequence_GetItem(o, 0);
+            o2 = PySequence_GetItem(o, 1);
+            if (!wxPoint2DFromObjects(o1, o2, &temp[idx])) {
+                goto error3;
+            }
+            Py_DECREF(o1);
+            Py_DECREF(o2);
+        }
+        else {
+            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 wxPoint2Ds.");
+    return NULL;
+}
+   
+//---------------------------------------------------------------------------
 
 
 wxBitmap** wxBitmap_LIST_helper(PyObject* source) {
@@ -2395,6 +2730,17 @@ bool wxPoint_helper(PyObject* source, wxPoint** obj)
 
 
 
+bool wxPosition_helper(PyObject* source, wxPosition** obj)
+{
+    if (source == Py_None) {
+        **obj = wxPosition(-1,-1);
+        return true;
+    }
+    return wxPyTwoIntItem_helper(source, obj, wxT("wxPosition"));
+}
+
+
+
 bool wxRealPoint_helper(PyObject* source, wxRealPoint** obj) {
 
     if (source == Py_None) {
@@ -2510,7 +2856,7 @@ bool wxColour_helper(PyObject* source, wxColour** obj) {
             return true;
         }
     }
-    // last chance: 3-tuple of integers is expected
+    // last chance: 3-tuple or 4-tuple of integers is expected
     else if (PySequence_Check(source) && PyObject_Length(source) == 3) {
         PyObject* o1 = PySequence_GetItem(source, 0);
         PyObject* o2 = PySequence_GetItem(source, 1);
@@ -2527,10 +2873,29 @@ bool wxColour_helper(PyObject* source, wxColour** obj) {
         Py_DECREF(o3);
         return true;
     }
+    else if (PySequence_Check(source) && PyObject_Length(source) == 4) {
+        PyObject* o1 = PySequence_GetItem(source, 0);
+        PyObject* o2 = PySequence_GetItem(source, 1);
+        PyObject* o3 = PySequence_GetItem(source, 2);
+        PyObject* o4 = PySequence_GetItem(source, 3);
+        if (!PyNumber_Check(o1) || !PyNumber_Check(o2) || !PyNumber_Check(o3) || !PyNumber_Check(o4)) {
+            Py_DECREF(o1);
+            Py_DECREF(o2);
+            Py_DECREF(o3);
+            Py_DECREF(o4);
+            goto error;
+        }
+        **obj = wxColour(PyInt_AsLong(o1), PyInt_AsLong(o2), PyInt_AsLong(o3), PyInt_AsLong(o4));
+        Py_DECREF(o1);
+        Py_DECREF(o2);
+        Py_DECREF(o3);
+        Py_DECREF(o4);
+        return true;
+    }
 
  error:
     PyErr_SetString(PyExc_TypeError,
-                    "Expected a wxColour object or a string containing a colour name or '#RRGGBB'.");
+                    "Expected a wxColour object, a string containing a colour name or '#RRGGBB', or a 3- or 4-tuple of integers.");
     return false;
 }
 
@@ -2579,15 +2944,60 @@ bool wxPoint2D_helper(PyObject* source, wxPoint2D** obj) {
         return true;
     }
  error:
-    PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of floats or a wxPoint2D object.");
+    PyErr_SetString(PyExc_TypeError, "Expected a 2-tuple of floats or a wx.Point2D object.");
     return false;
 }
 
 
-//----------------------------------------------------------------------
 
-PyObject* wxArrayString2PyList_helper(const wxArrayString& arr) {
+bool wxRect2D_helper(PyObject* source, wxRect2D** obj) {
 
+    if (source == Py_None) {
+        **obj = wxRect2D(-1,-1,-1,-1);
+        return true;
+    }
+
+    // If source is an object instance then it may already be the right type
+    if (wxPySwigInstance_Check(source)) {
+        wxRect2D* ptr;
+        if (! wxPyConvertSwigPtr(source, (void **)&ptr, wxT("wxRect2D")))
+            goto error;
+        *obj = ptr;
+        return true;
+    }
+    // otherwise a length-4 sequence of floats is expected
+    if (PySequence_Check(source) && PySequence_Length(source) == 4) {
+        PyObject* o1 = PySequence_GetItem(source, 0);
+        PyObject* o2 = PySequence_GetItem(source, 1);
+        PyObject* o3 = PySequence_GetItem(source, 2);
+        PyObject* o4 = PySequence_GetItem(source, 3);
+        // This should really check for floats, not numbers -- but that would break code.
+        if (!PyNumber_Check(o1) || !PyNumber_Check(o2) ||
+            !PyNumber_Check(o3) || !PyNumber_Check(o4)) {
+            Py_DECREF(o1);
+            Py_DECREF(o2);
+            Py_DECREF(o3);
+            Py_DECREF(o4);
+            goto error;
+        }
+        **obj = wxRect2D(PyFloat_AsDouble(o1), PyFloat_AsDouble(o2),
+                         PyFloat_AsDouble(o3), PyFloat_AsDouble(o4));
+        Py_DECREF(o1);
+        Py_DECREF(o2);
+        Py_DECREF(o3);
+        Py_DECREF(o4);
+        return true;
+    }
+ error:
+    PyErr_SetString(PyExc_TypeError, "Expected a 4-tuple of floats or a wx.Rect2D object.");
+    return false;
+}
+
+
+//----------------------------------------------------------------------
+
+PyObject* wxArrayString2PyList_helper(const wxArrayString& arr)
+{
     PyObject* list = PyList_New(0);
     for (size_t i=0; i < arr.GetCount(); i++) {
 #if wxUSE_UNICODE
@@ -2602,8 +3012,8 @@ PyObject* wxArrayString2PyList_helper(const wxArrayString& arr) {
 }
 
 
-PyObject* wxArrayInt2PyList_helper(const wxArrayInt& 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]);
@@ -2614,6 +3024,18 @@ PyObject* wxArrayInt2PyList_helper(const wxArrayInt& arr) {
 }
 
 
+PyObject* wxArrayDouble2PyList_helper(const wxArrayDouble& arr)
+{
+    PyObject* list = PyList_New(0);
+    for (size_t i=0; i < arr.GetCount(); i++) {
+        PyObject* number = PyFloat_FromDouble(arr[i]);
+        PyList_Append(list, number);
+        Py_DECREF(number);
+    }
+    return list;
+}
+
+
 //----------------------------------------------------------------------
 // wxPyImageHandler methods
 //