[pygobject] marshal refactoring: Move GValue marshaling from pytype into pygi-value



commit 204f5a187782c5325ed6bed96c9a940f3aa67d04
Author: Simon Feltman <sfeltman src gnome org>
Date:   Sun Jan 12 12:26:30 2014 -0800

    marshal refactoring: Move GValue marshaling from pytype into pygi-value
    
    Move marshaling of GValues to and from PyObjects into pygi-value.c. Make
    PyGTypeMarshal struct and related functions accessible via pygtype.h.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=709700

 gi/gobjectmodule.c       |    2 +
 gi/pygi-struct-marshal.c |    1 +
 gi/pygi-value.c          |  720 +++++++++++++++++++++++++++++++++++++++++++++-
 gi/pygi-value.h          |   12 +
 gi/pygobject-private.h   |   16 -
 gi/pygobject.c           |    2 +-
 gi/pygtype.c             |  728 +---------------------------------------------
 gi/pygtype.h             |   17 +
 8 files changed, 757 insertions(+), 741 deletions(-)
---
diff --git a/gi/gobjectmodule.c b/gi/gobjectmodule.c
index 4c614f7..82d52a1 100644
--- a/gi/gobjectmodule.c
+++ b/gi/gobjectmodule.c
@@ -38,6 +38,8 @@
 #include "pygtype.h"
 #include "pygoptiongroup.h"
 
+#include "pygi-value.h"
+
 static GHashTable *log_handlers = NULL;
 static gboolean log_handlers_disabled = FALSE;
 
diff --git a/gi/pygi-struct-marshal.c b/gi/pygi-struct-marshal.c
index a30f03e..52573d6 100644
--- a/gi/pygi-struct-marshal.c
+++ b/gi/pygi-struct-marshal.c
@@ -24,6 +24,7 @@
 
 #include "pygi-struct-marshal.h"
 #include "pygi-private.h"
+#include "pygi-value.h"
 
 /*
  * _is_union_member - check to see if the py_arg is actually a member of the
diff --git a/gi/pygi-value.c b/gi/pygi-value.c
index 6ac12cf..f2cc27b 100644
--- a/gi/pygi-value.c
+++ b/gi/pygi-value.c
@@ -17,7 +17,10 @@
  */
 
 #include "pygi-value.h"
-
+#include "pyglib-python-compat.h"
+#include "pygobject-private.h"
+#include "pygtype.h"
+#include "pygparamspec.h"
 
 GIArgument
 _pygi_argument_from_g_value(const GValue *value,
@@ -142,3 +145,718 @@ _pygi_argument_from_g_value(const GValue *value,
 
     return arg;
 }
+
+
+static int
+pyg_value_array_from_pyobject(GValue *value,
+                              PyObject *obj,
+                              const GParamSpecValueArray *pspec)
+{
+    int len;
+    GValueArray *value_array;
+    int i;
+
+    len = PySequence_Length(obj);
+    if (len == -1) {
+        PyErr_Clear();
+        return -1;
+    }
+
+    if (pspec && pspec->fixed_n_elements > 0 && len != pspec->fixed_n_elements)
+        return -1;
+
+    value_array = g_value_array_new(len);
+
+    for (i = 0; i < len; ++i) {
+        PyObject *item = PySequence_GetItem(obj, i);
+        GType type;
+        GValue item_value = { 0, };
+        int status;
+
+        if (! item) {
+            PyErr_Clear();
+            g_value_array_free(value_array);
+            return -1;
+        }
+
+        if (pspec && pspec->element_spec)
+            type = G_PARAM_SPEC_VALUE_TYPE(pspec->element_spec);
+        else if (item == Py_None)
+            type = G_TYPE_POINTER; /* store None as NULL */
+        else {
+            type = pyg_type_from_object((PyObject*)Py_TYPE(item));
+            if (! type) {
+                PyErr_Clear();
+                g_value_array_free(value_array);
+                Py_DECREF(item);
+                return -1;
+            }
+        }
+
+        g_value_init(&item_value, type);
+        status = (pspec && pspec->element_spec)
+                 ? pyg_param_gvalue_from_pyobject(&item_value, item, pspec->element_spec)
+                 : pyg_value_from_pyobject(&item_value, item);
+        Py_DECREF(item);
+
+        if (status == -1) {
+            g_value_array_free(value_array);
+            g_value_unset(&item_value);
+            return -1;
+        }
+
+        g_value_array_append(value_array, &item_value);
+        g_value_unset(&item_value);
+    }
+
+    g_value_take_boxed(value, value_array);
+    return 0;
+}
+
+static int
+pyg_array_from_pyobject(GValue *value,
+                        PyObject *obj)
+{
+    int len;
+    GArray *array;
+    int i;
+
+    len = PySequence_Length(obj);
+    if (len == -1) {
+        PyErr_Clear();
+        return -1;
+    }
+
+    array = g_array_new(FALSE, TRUE, sizeof(GValue));
+
+    for (i = 0; i < len; ++i) {
+        PyObject *item = PySequence_GetItem(obj, i);
+        GType type;
+        GValue item_value = { 0, };
+        int status;
+
+        if (! item) {
+            PyErr_Clear();
+            g_array_free(array, FALSE);
+            return -1;
+        }
+
+        if (item == Py_None)
+            type = G_TYPE_POINTER; /* store None as NULL */
+        else {
+            type = pyg_type_from_object((PyObject*)Py_TYPE(item));
+            if (! type) {
+                PyErr_Clear();
+                g_array_free(array, FALSE);
+                Py_DECREF(item);
+                return -1;
+            }
+        }
+
+        g_value_init(&item_value, type);
+        status = pyg_value_from_pyobject(&item_value, item);
+        Py_DECREF(item);
+
+        if (status == -1) {
+            g_array_free(array, FALSE);
+            g_value_unset(&item_value);
+            return -1;
+        }
+
+        g_array_append_val(array, item_value);
+    }
+
+    g_value_take_boxed(value, array);
+    return 0;
+}
+
+/**
+ * pyg_value_from_pyobject_with_error:
+ * @value: the GValue object to store the converted value in.
+ * @obj: the Python object to convert.
+ *
+ * This function converts a Python object and stores the result in a
+ * GValue.  The GValue must be initialised in advance with
+ * g_value_init().  If the Python object can't be converted to the
+ * type of the GValue, then an error is returned.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+int
+pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj)
+{
+    PyObject *tmp;
+    GType value_type = G_VALUE_TYPE(value);
+
+    switch (G_TYPE_FUNDAMENTAL(value_type)) {
+    case G_TYPE_INTERFACE:
+        /* we only handle interface types that have a GObject prereq */
+        if (g_type_is_a(value_type, G_TYPE_OBJECT)) {
+            if (obj == Py_None)
+                g_value_set_object(value, NULL);
+            else {
+                if (!PyObject_TypeCheck(obj, &PyGObject_Type)) {
+                    PyErr_SetString(PyExc_TypeError, "GObject is required");
+                    return -1;
+                }
+                if (!G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj),
+                        value_type)) {
+                    PyErr_SetString(PyExc_TypeError, "Invalid GObject type for assignment");
+                    return -1;
+                }
+                g_value_set_object(value, pygobject_get(obj));
+            }
+        } else {
+            PyErr_SetString(PyExc_TypeError, "Unsupported conversion");
+            return -1;
+        }
+        break;
+    case G_TYPE_CHAR:
+        if (PYGLIB_PyLong_Check(obj)) {
+            glong val;
+            val = PYGLIB_PyLong_AsLong(obj);
+            if (val >= -128 && val <= 127)
+                g_value_set_schar(value, (gchar) val);
+            else
+                return -1;
+        }
+#if PY_VERSION_HEX < 0x03000000
+        else if (PyString_Check(obj)) {
+            g_value_set_schar(value, PyString_AsString(obj)[0]);
+        }
+#endif
+        else if (PyUnicode_Check(obj)) {
+            tmp = PyUnicode_AsUTF8String(obj);
+            g_value_set_schar(value, PYGLIB_PyBytes_AsString(tmp)[0]);
+            Py_DECREF(tmp);
+        } else {
+            PyErr_SetString(PyExc_TypeError, "Cannot convert to TYPE_CHAR");
+            return -1;
+        }
+
+        break;
+    case G_TYPE_UCHAR:
+        if (PYGLIB_PyLong_Check(obj)) {
+            glong val;
+            val = PYGLIB_PyLong_AsLong(obj);
+            if (val >= 0 && val <= 255)
+                g_value_set_uchar(value, (guchar) val);
+            else
+                return -1;
+#if PY_VERSION_HEX < 0x03000000
+        } else if (PyString_Check(obj)) {
+            g_value_set_uchar(value, PyString_AsString(obj)[0]);
+#endif
+        } else if (PyUnicode_Check(obj)) {
+            tmp = PyUnicode_AsUTF8String(obj);
+            g_value_set_uchar(value, PYGLIB_PyBytes_AsString(tmp)[0]);
+            Py_DECREF(tmp);
+        } else {
+            PyErr_Clear();
+            return -1;
+        }
+        break;
+    case G_TYPE_BOOLEAN:
+        g_value_set_boolean(value, PyObject_IsTrue(obj));
+        break;
+    case G_TYPE_INT:
+        g_value_set_int(value, PYGLIB_PyLong_AsLong(obj));
+        break;
+    case G_TYPE_UINT:
+    {
+        if (PYGLIB_PyLong_Check(obj)) {
+            guint val;
+
+            /* check that number is not negative */
+            if (PyLong_AsLongLong(obj) < 0)
+                return -1;
+
+            val = PyLong_AsUnsignedLong(obj);
+            if (val <= G_MAXUINT)
+                g_value_set_uint(value, val);
+            else
+                return -1;
+        } else {
+            g_value_set_uint(value, PyLong_AsUnsignedLong(obj));
+        }
+    }
+    break;
+    case G_TYPE_LONG:
+        g_value_set_long(value, PYGLIB_PyLong_AsLong(obj));
+        break;
+    case G_TYPE_ULONG:
+#if PY_VERSION_HEX < 0x03000000
+        if (PyInt_Check(obj)) {
+            long val;
+
+            val = PYGLIB_PyLong_AsLong(obj);
+            if (val < 0) {
+                PyErr_SetString(PyExc_OverflowError, "negative value not allowed for uint64 property");
+                return -1;
+            }
+            g_value_set_ulong(value, (gulong)val);
+        } else
+#endif
+            if (PyLong_Check(obj))
+                g_value_set_ulong(value, PyLong_AsUnsignedLong(obj));
+            else
+                return -1;
+        break;
+    case G_TYPE_INT64:
+        g_value_set_int64(value, PyLong_AsLongLong(obj));
+        break;
+    case G_TYPE_UINT64:
+#if PY_VERSION_HEX < 0x03000000
+        if (PyInt_Check(obj)) {
+            long v = PyInt_AsLong(obj);
+            if (v < 0) {
+                PyErr_SetString(PyExc_OverflowError, "negative value not allowed for uint64 property");
+                return -1;
+            }
+            g_value_set_uint64(value, v);
+        } else
+#endif
+            if (PyLong_Check(obj))
+                g_value_set_uint64(value, PyLong_AsUnsignedLongLong(obj));
+            else
+                return -1;
+        break;
+    case G_TYPE_ENUM:
+    {
+        gint val = 0;
+        if (pyg_enum_get_value(G_VALUE_TYPE(value), obj, &val) < 0) {
+            return -1;
+        }
+        g_value_set_enum(value, val);
+    }
+    break;
+    case G_TYPE_FLAGS:
+    {
+        guint val = 0;
+        if (pyg_flags_get_value(G_VALUE_TYPE(value), obj, &val) < 0) {
+            return -1;
+        }
+        g_value_set_flags(value, val);
+    }
+    break;
+    case G_TYPE_FLOAT:
+        g_value_set_float(value, PyFloat_AsDouble(obj));
+        break;
+    case G_TYPE_DOUBLE:
+        g_value_set_double(value, PyFloat_AsDouble(obj));
+        break;
+    case G_TYPE_STRING:
+        if (obj == Py_None) {
+            g_value_set_string(value, NULL);
+        } else {
+            PyObject* tmp_str = PyObject_Str(obj);
+            if (tmp_str == NULL) {
+                PyErr_Clear();
+                if (PyUnicode_Check(obj)) {
+                    tmp = PyUnicode_AsUTF8String(obj);
+                    g_value_set_string(value, PYGLIB_PyBytes_AsString(tmp));
+                    Py_DECREF(tmp);
+                } else {
+                    PyErr_SetString(PyExc_TypeError, "Expected string");
+                    return -1;
+                }
+            } else {
+#if PY_VERSION_HEX < 0x03000000
+                g_value_set_string(value, PyString_AsString(tmp_str));
+#else
+                tmp = PyUnicode_AsUTF8String(tmp_str);
+                g_value_set_string(value, PyBytes_AsString(tmp));
+                Py_DECREF(tmp);
+#endif
+            }
+            Py_XDECREF(tmp_str);
+        }
+        break;
+    case G_TYPE_POINTER:
+        if (obj == Py_None)
+            g_value_set_pointer(value, NULL);
+        else if (PyObject_TypeCheck(obj, &PyGPointer_Type) &&
+                G_VALUE_HOLDS(value, ((PyGPointer *)obj)->gtype))
+            g_value_set_pointer(value, pyg_pointer_get(obj, gpointer));
+        else if (PYGLIB_CPointer_Check(obj))
+            g_value_set_pointer(value, PYGLIB_CPointer_GetPointer(obj, NULL));
+        else if (G_VALUE_HOLDS_GTYPE (value))
+            g_value_set_gtype (value, pyg_type_from_object (obj));
+        else {
+            PyErr_SetString(PyExc_TypeError, "Expected pointer");
+            return -1;
+        }
+        break;
+    case G_TYPE_BOXED: {
+        PyGTypeMarshal *bm;
+
+        if (obj == Py_None)
+            g_value_set_boxed(value, NULL);
+        else if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT))
+            g_value_set_boxed(value, obj);
+        else if (PyObject_TypeCheck(obj, &PyGBoxed_Type) &&
+                G_VALUE_HOLDS(value, ((PyGBoxed *)obj)->gtype))
+            g_value_set_boxed(value, pyg_boxed_get(obj, gpointer));
+        else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) {
+            GType type;
+            GValue *n_value;
+
+            type = pyg_type_from_object((PyObject*)Py_TYPE(obj));
+            if (G_UNLIKELY (! type)) {
+                return -1;
+            }
+            n_value = g_new0 (GValue, 1);
+            g_value_init (n_value, type);
+            g_value_take_boxed (value, n_value);
+            return pyg_value_from_pyobject_with_error (n_value, obj);
+        }
+        else if (PySequence_Check(obj) &&
+                G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY))
+            return pyg_value_array_from_pyobject(value, obj, NULL);
+        else if (PySequence_Check(obj) &&
+                G_VALUE_HOLDS(value, G_TYPE_ARRAY))
+            return pyg_array_from_pyobject(value, obj);
+        else if (PYGLIB_PyUnicode_Check(obj) &&
+                G_VALUE_HOLDS(value, G_TYPE_GSTRING)) {
+            GString *string;
+            char *buffer;
+            Py_ssize_t len;
+            if (PYGLIB_PyUnicode_AsStringAndSize(obj, &buffer, &len))
+                return -1;
+            string = g_string_new_len(buffer, len);
+            g_value_set_boxed(value, string);
+            g_string_free (string, TRUE);
+            break;
+        }
+        else if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL)
+            return bm->tovalue(value, obj);
+        else if (PYGLIB_CPointer_Check(obj))
+            g_value_set_boxed(value, PYGLIB_CPointer_GetPointer(obj, NULL));
+        else {
+            PyErr_SetString(PyExc_TypeError, "Expected Boxed");
+            return -1;
+        }
+        break;
+    }
+    case G_TYPE_PARAM:
+        /* we need to support both the wrapped _gobject.GParamSpec and the GI
+         * GObject.ParamSpec */
+        if (G_IS_PARAM_SPEC (pygobject_get (obj)))
+            g_value_set_param(value, G_PARAM_SPEC (pygobject_get (obj)));
+        else if (PyGParamSpec_Check(obj))
+            g_value_set_param(value, PYGLIB_CPointer_GetPointer(obj, NULL));
+        else {
+            PyErr_SetString(PyExc_TypeError, "Expected ParamSpec");
+            return -1;
+        }
+        break;
+    case G_TYPE_OBJECT:
+        if (obj == Py_None) {
+            g_value_set_object(value, NULL);
+        } else if (PyObject_TypeCheck(obj, &PyGObject_Type) &&
+                G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj),
+                        G_VALUE_TYPE(value))) {
+            g_value_set_object(value, pygobject_get(obj));
+        } else {
+            PyErr_SetString(PyExc_TypeError, "Expected GObject");
+            return -1;
+        }
+        break;
+    case G_TYPE_VARIANT:
+    {
+        if (obj == Py_None)
+            g_value_set_variant(value, NULL);
+        else if (pyg_type_from_object_strict(obj, FALSE) == G_TYPE_VARIANT)
+            g_value_set_variant(value, pyg_boxed_get(obj, GVariant));
+        else {
+            PyErr_SetString(PyExc_TypeError, "Expected Variant");
+            return -1;
+        }
+        break;
+    }
+    default:
+    {
+        PyGTypeMarshal *bm;
+        if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL) {
+            return bm->tovalue(value, obj);
+        } else {
+            PyErr_SetString(PyExc_TypeError, "Unknown value type");
+            return -1;
+        }
+        break;
+    }
+    }
+
+    /* If an error occurred, unset the GValue but don't clear the Python error. */
+    if (PyErr_Occurred()) {
+        g_value_unset(value);
+        return -1;
+    }
+
+    return 0;
+}
+
+/**
+ * pyg_value_from_pyobject:
+ * @value: the GValue object to store the converted value in.
+ * @obj: the Python object to convert.
+ *
+ * Same basic function as pyg_value_from_pyobject_with_error but clears
+ * any Python errors before returning.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+int
+pyg_value_from_pyobject(GValue *value, PyObject *obj)
+{
+    int res = pyg_value_from_pyobject_with_error (value, obj);
+
+    if (PyErr_Occurred()) {
+        PyErr_Clear();
+        return -1;
+    }
+    return res;
+}
+
+/**
+ * pyg_value_as_pyobject:
+ * @value: the GValue object.
+ * @copy_boxed: true if boxed values should be copied.
+ *
+ * This function creates/returns a Python wrapper object that
+ * represents the GValue passed as an argument.
+ *
+ * Returns: a PyObject representing the value.
+ */
+PyObject *
+pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed)
+{
+    gchar buf[128];
+
+    switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value))) {
+    case G_TYPE_INTERFACE:
+        if (g_type_is_a(G_VALUE_TYPE(value), G_TYPE_OBJECT))
+            return pygobject_new(g_value_get_object(value));
+        else
+            break;
+    case G_TYPE_CHAR: {
+        gint8 val = g_value_get_schar(value);
+        return PYGLIB_PyUnicode_FromStringAndSize((char *)&val, 1);
+    }
+    case G_TYPE_UCHAR: {
+        guint8 val = g_value_get_uchar(value);
+        return PYGLIB_PyBytes_FromStringAndSize((char *)&val, 1);
+    }
+    case G_TYPE_BOOLEAN: {
+        return PyBool_FromLong(g_value_get_boolean(value));
+    }
+    case G_TYPE_INT:
+        return PYGLIB_PyLong_FromLong(g_value_get_int(value));
+    case G_TYPE_UINT:
+    {
+        /* in Python, the Int object is backed by a long.  If a
+              long can hold the whole value of an unsigned int, use
+              an Int.  Otherwise, use a Long object to avoid overflow.
+              This matches the ULongArg behavior in codegen/argtypes.h */
+#if (G_MAXUINT <= G_MAXLONG)
+        return PYGLIB_PyLong_FromLong((glong) g_value_get_uint(value));
+#else
+        return PyLong_FromUnsignedLong((gulong) g_value_get_uint(value));
+#endif
+    }
+    case G_TYPE_LONG:
+        return PYGLIB_PyLong_FromLong(g_value_get_long(value));
+    case G_TYPE_ULONG:
+    {
+        gulong val = g_value_get_ulong(value);
+
+        if (val <= G_MAXLONG)
+            return PYGLIB_PyLong_FromLong((glong) val);
+        else
+            return PyLong_FromUnsignedLong(val);
+    }
+    case G_TYPE_INT64:
+    {
+        gint64 val = g_value_get_int64(value);
+
+        if (G_MINLONG <= val && val <= G_MAXLONG)
+            return PYGLIB_PyLong_FromLong((glong) val);
+        else
+            return PyLong_FromLongLong(val);
+    }
+    case G_TYPE_UINT64:
+    {
+        guint64 val = g_value_get_uint64(value);
+
+        if (val <= G_MAXLONG)
+            return PYGLIB_PyLong_FromLong((glong) val);
+        else
+            return PyLong_FromUnsignedLongLong(val);
+    }
+    case G_TYPE_ENUM:
+        return pyg_enum_from_gtype(G_VALUE_TYPE(value), g_value_get_enum(value));
+    case G_TYPE_FLAGS:
+        return pyg_flags_from_gtype(G_VALUE_TYPE(value), g_value_get_flags(value));
+    case G_TYPE_FLOAT:
+        return PyFloat_FromDouble(g_value_get_float(value));
+    case G_TYPE_DOUBLE:
+        return PyFloat_FromDouble(g_value_get_double(value));
+    case G_TYPE_STRING:
+    {
+        const gchar *str = g_value_get_string(value);
+
+        if (str)
+            return PYGLIB_PyUnicode_FromString(str);
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+    case G_TYPE_POINTER:
+        if (G_VALUE_HOLDS_GTYPE (value))
+            return pyg_type_wrapper_new (g_value_get_gtype (value));
+        else
+            return pyg_pointer_new(G_VALUE_TYPE(value),
+                    g_value_get_pointer(value));
+    case G_TYPE_BOXED: {
+        PyGTypeMarshal *bm;
+
+        if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT)) {
+            PyObject *ret = (PyObject *)g_value_dup_boxed(value);
+            if (ret == NULL) {
+                Py_INCREF(Py_None);
+                return Py_None;
+            }
+            return ret;
+        } else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) {
+            GValue *n_value = g_value_get_boxed (value);
+            return pyg_value_as_pyobject(n_value, copy_boxed);
+        } else if (G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY)) {
+            GValueArray *array = (GValueArray *) g_value_get_boxed(value);
+            PyObject *ret = PyList_New(array->n_values);
+            int i;
+            for (i = 0; i < array->n_values; ++i)
+                PyList_SET_ITEM(ret, i, pyg_value_as_pyobject
+                        (array->values + i, copy_boxed));
+            return ret;
+        } else if (G_VALUE_HOLDS(value, G_TYPE_GSTRING)) {
+            GString *string = (GString *) g_value_get_boxed(value);
+            PyObject *ret = PYGLIB_PyUnicode_FromStringAndSize(string->str, string->len);
+            return ret;
+        }
+        bm = pyg_type_lookup(G_VALUE_TYPE(value));
+        if (bm) {
+            return bm->fromvalue(value);
+        } else {
+            if (copy_boxed)
+                return pyg_boxed_new(G_VALUE_TYPE(value),
+                        g_value_get_boxed(value), TRUE, TRUE);
+            else
+                return pyg_boxed_new(G_VALUE_TYPE(value),
+                        g_value_get_boxed(value),FALSE,FALSE);
+        }
+    }
+    case G_TYPE_PARAM:
+        return pyg_param_spec_new(g_value_get_param(value));
+    case G_TYPE_OBJECT:
+        return pygobject_new(g_value_get_object(value));
+    case G_TYPE_VARIANT:
+    {
+        GVariant *v = g_value_get_variant(value);
+        if (v == NULL) {
+            Py_INCREF(Py_None);
+            return Py_None;
+        }
+        return pyg_boxed_new(G_TYPE_VARIANT, g_variant_ref(v), FALSE, FALSE);
+    }
+    default:
+    {
+        PyGTypeMarshal *bm;
+        if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))))
+            return bm->fromvalue(value);
+        break;
+    }
+    }
+    g_snprintf(buf, sizeof(buf), "unknown type %s",
+               g_type_name(G_VALUE_TYPE(value)));
+    PyErr_SetString(PyExc_TypeError, buf);
+    return NULL;
+}
+
+
+int
+pyg_param_gvalue_from_pyobject(GValue* value,
+                               PyObject* py_obj,
+                              const GParamSpec* pspec)
+{
+    if (G_IS_PARAM_SPEC_UNICHAR(pspec)) {
+       gunichar u;
+
+       if (!pyg_pyobj_to_unichar_conv(py_obj, &u)) {
+           PyErr_Clear();
+           return -1;
+       }
+        g_value_set_uint(value, u);
+       return 0;
+    }
+    else if (G_IS_PARAM_SPEC_VALUE_ARRAY(pspec))
+       return pyg_value_array_from_pyobject(value, py_obj,
+                                            G_PARAM_SPEC_VALUE_ARRAY(pspec));
+    else {
+       return pyg_value_from_pyobject(value, py_obj);
+    }
+}
+
+PyObject*
+pyg_param_gvalue_as_pyobject(const GValue* gvalue,
+                             gboolean copy_boxed,
+                            const GParamSpec* pspec)
+{
+    if (G_IS_PARAM_SPEC_UNICHAR(pspec)) {
+       gunichar u;
+       Py_UNICODE uni_buffer[2] = { 0, 0 };
+
+       u = g_value_get_uint(gvalue);
+       uni_buffer[0] = u;
+       return PyUnicode_FromUnicode(uni_buffer, 1);
+    }
+    else {
+       return pyg_value_as_pyobject(gvalue, copy_boxed);
+    }
+}
+
+PyObject *
+pyg_strv_from_gvalue(const GValue *value)
+{
+    gchar    **argv = (gchar **) g_value_get_boxed(value);
+    int        argc = 0, i;
+    PyObject  *py_argv;
+
+    if (argv) {
+        while (argv[argc])
+            argc++;
+    }
+    py_argv = PyList_New(argc);
+    for (i = 0; i < argc; ++i)
+       PyList_SET_ITEM(py_argv, i, PYGLIB_PyUnicode_FromString(argv[i]));
+    return py_argv;
+}
+
+int
+pyg_strv_to_gvalue(GValue *value, PyObject *obj)
+{
+    Py_ssize_t argc, i;
+    gchar **argv;
+
+    if (!(PyTuple_Check(obj) || PyList_Check(obj)))
+        return -1;
+
+    argc = PySequence_Length(obj);
+    for (i = 0; i < argc; ++i)
+       if (!PYGLIB_PyUnicode_Check(PySequence_Fast_GET_ITEM(obj, i)))
+           return -1;
+    argv = g_new(gchar *, argc + 1);
+    for (i = 0; i < argc; ++i)
+       argv[i] = g_strdup(PYGLIB_PyUnicode_AsString(PySequence_Fast_GET_ITEM(obj, i)));
+    argv[i] = NULL;
+    g_value_take_boxed(value, argv);
+    return 0;
+}
diff --git a/gi/pygi-value.h b/gi/pygi-value.h
index 3e8d46a..544da3c 100644
--- a/gi/pygi-value.h
+++ b/gi/pygi-value.h
@@ -20,12 +20,24 @@
 
 #include <glib-object.h>
 #include <girepository.h>
+#include <Python.h>
 
 G_BEGIN_DECLS
 
 GIArgument _pygi_argument_from_g_value(const GValue *value,
                                        GITypeInfo *type_info);
 
+int       pyg_value_from_pyobject(GValue *value, PyObject *obj);
+int       pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj);
+PyObject *pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed);
+int       pyg_param_gvalue_from_pyobject(GValue* value,
+                                         PyObject* py_obj,
+                                         const GParamSpec* pspec);
+PyObject *pyg_param_gvalue_as_pyobject(const GValue* gvalue,
+                                       gboolean copy_boxed,
+                                       const GParamSpec* pspec);
+PyObject *pyg_strv_from_gvalue(const GValue *value);
+int       pyg_strv_to_gvalue(GValue *value, PyObject *obj);
 
 G_END_DECLS
 
diff --git a/gi/pygobject-private.h b/gi/pygobject-private.h
index f48d073..be565d6 100644
--- a/gi/pygobject-private.h
+++ b/gi/pygobject-private.h
@@ -78,22 +78,6 @@ gint pyg_enum_get_value  (GType enum_type, PyObject *obj, gint *val);
 gint pyg_flags_get_value (GType flag_type, PyObject *obj, guint *val);
 int pyg_pyobj_to_unichar_conv (PyObject* py_obj, void* ptr);
 
-typedef PyObject *(* fromvaluefunc)(const GValue *value);
-typedef int (*tovaluefunc)(GValue *value, PyObject *obj);
-
-void      pyg_register_gtype_custom(GType gtype,
-                            fromvaluefunc from_func,
-                            tovaluefunc to_func);
-int       pyg_value_from_pyobject(GValue *value, PyObject *obj);
-int       pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj);
-PyObject *pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed);
-int       pyg_param_gvalue_from_pyobject(GValue* value,
-                                         PyObject* py_obj,
-                                         const GParamSpec* pspec);
-PyObject *pyg_param_gvalue_as_pyobject(const GValue* gvalue,
-                                       gboolean copy_boxed,
-                                       const GParamSpec* pspec);
-
 GClosure *pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data);
 void     pyg_closure_set_exception_handler(GClosure *closure,
                                            PyClosureExceptionHandler handler);
diff --git a/gi/pygobject.c b/gi/pygobject.c
index 129f29a..215376b 100644
--- a/gi/pygobject.c
+++ b/gi/pygobject.c
@@ -30,7 +30,7 @@
 #include "pygparamspec.h"
 
 #include "pygi.h"
-
+#include "pygi-value.h"
 
 static void pygobject_dealloc(PyGObject *self);
 static int  pygobject_traverse(PyGObject *self, visitproc visit, void *arg);
diff --git a/gi/pygtype.c b/gi/pygtype.c
index 9dc1153..e1fb4e6 100644
--- a/gi/pygtype.c
+++ b/gi/pygtype.c
@@ -30,6 +30,8 @@
 #include "pygparamspec.h"
 #include "pygtype.h"
 
+#include "pygi-value.h"
+
 /* -------------- __gtype__ objects ---------------------------- */
 
 typedef struct {
@@ -449,8 +451,6 @@ pyg_type_from_object(PyObject *obj)
     return pyg_type_from_object_strict(obj, TRUE);
 }
 
-/* -------------- GValue marshalling ------------------ */
-
 /**
  * pyg_enum_get_value:
  * @enum_type: the GType of the flag.
@@ -613,13 +613,9 @@ pyg_flags_get_value(GType flag_type, PyObject *obj, guint *val)
     return res;
 }
 
-typedef struct {
-    fromvaluefunc fromvalue;
-    tovaluefunc tovalue;
-} PyGTypeMarshal;
 static GQuark pyg_type_marshal_key = 0;
 
-static PyGTypeMarshal *
+PyGTypeMarshal *
 pyg_type_lookup(GType type)
 {
     GType      ptype = type;
@@ -661,640 +657,6 @@ pyg_register_gtype_custom(GType gtype,
     g_type_set_qdata(gtype, pyg_type_marshal_key, tm);
 }
 
-static int
-pyg_value_array_from_pyobject(GValue *value,
-                              PyObject *obj,
-                              const GParamSpecValueArray *pspec)
-{
-    int len;
-    GValueArray *value_array;
-    int i;
-
-    len = PySequence_Length(obj);
-    if (len == -1) {
-        PyErr_Clear();
-        return -1;
-    }
-
-    if (pspec && pspec->fixed_n_elements > 0 && len != pspec->fixed_n_elements)
-        return -1;
-
-    value_array = g_value_array_new(len);
-
-    for (i = 0; i < len; ++i) {
-        PyObject *item = PySequence_GetItem(obj, i);
-        GType type;
-        GValue item_value = { 0, };
-        int status;
-
-        if (! item) {
-            PyErr_Clear();
-            g_value_array_free(value_array);
-            return -1;
-        }
-
-        if (pspec && pspec->element_spec)
-            type = G_PARAM_SPEC_VALUE_TYPE(pspec->element_spec);
-        else if (item == Py_None)
-            type = G_TYPE_POINTER; /* store None as NULL */
-        else {
-            type = pyg_type_from_object((PyObject*)Py_TYPE(item));
-            if (! type) {
-                PyErr_Clear();
-                g_value_array_free(value_array);
-                Py_DECREF(item);
-                return -1;
-            }
-        }
-
-        g_value_init(&item_value, type);
-        status = (pspec && pspec->element_spec)
-                 ? pyg_param_gvalue_from_pyobject(&item_value, item, pspec->element_spec)
-                 : pyg_value_from_pyobject(&item_value, item);
-        Py_DECREF(item);
-
-        if (status == -1) {
-            g_value_array_free(value_array);
-            g_value_unset(&item_value);
-            return -1;
-        }
-
-        g_value_array_append(value_array, &item_value);
-        g_value_unset(&item_value);
-    }
-
-    g_value_take_boxed(value, value_array);
-    return 0;
-}
-
-static int
-pyg_array_from_pyobject(GValue *value,
-                        PyObject *obj)
-{
-    int len;
-    GArray *array;
-    int i;
-
-    len = PySequence_Length(obj);
-    if (len == -1) {
-        PyErr_Clear();
-        return -1;
-    }
-
-    array = g_array_new(FALSE, TRUE, sizeof(GValue));
-
-    for (i = 0; i < len; ++i) {
-        PyObject *item = PySequence_GetItem(obj, i);
-        GType type;
-        GValue item_value = { 0, };
-        int status;
-
-        if (! item) {
-            PyErr_Clear();
-            g_array_free(array, FALSE);
-            return -1;
-        }
-
-        if (item == Py_None)
-            type = G_TYPE_POINTER; /* store None as NULL */
-        else {
-            type = pyg_type_from_object((PyObject*)Py_TYPE(item));
-            if (! type) {
-                PyErr_Clear();
-                g_array_free(array, FALSE);
-                Py_DECREF(item);
-                return -1;
-            }
-        }
-
-        g_value_init(&item_value, type);
-        status = pyg_value_from_pyobject(&item_value, item);
-        Py_DECREF(item);
-
-        if (status == -1) {
-            g_array_free(array, FALSE);
-            g_value_unset(&item_value);
-            return -1;
-        }
-
-        g_array_append_val(array, item_value);
-    }
-
-    g_value_take_boxed(value, array);
-    return 0;
-}
-
-/**
- * pyg_value_from_pyobject_with_error:
- * @value: the GValue object to store the converted value in.
- * @obj: the Python object to convert.
- *
- * This function converts a Python object and stores the result in a
- * GValue.  The GValue must be initialised in advance with
- * g_value_init().  If the Python object can't be converted to the
- * type of the GValue, then an error is returned.
- *
- * Returns: 0 on success, -1 on error.
- */
-int
-pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj)
-{
-    PyObject *tmp;
-    GType value_type = G_VALUE_TYPE(value);
-
-    switch (G_TYPE_FUNDAMENTAL(value_type)) {
-    case G_TYPE_INTERFACE:
-        /* we only handle interface types that have a GObject prereq */
-        if (g_type_is_a(value_type, G_TYPE_OBJECT)) {
-            if (obj == Py_None)
-                g_value_set_object(value, NULL);
-            else {
-                if (!PyObject_TypeCheck(obj, &PyGObject_Type)) {
-                    PyErr_SetString(PyExc_TypeError, "GObject is required");
-                    return -1;
-                }
-                if (!G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj),
-                        value_type)) {
-                    PyErr_SetString(PyExc_TypeError, "Invalid GObject type for assignment");
-                    return -1;
-                }
-                g_value_set_object(value, pygobject_get(obj));
-            }
-        } else {
-            PyErr_SetString(PyExc_TypeError, "Unsupported conversion");
-            return -1;
-        }
-        break;
-    case G_TYPE_CHAR:
-        if (PYGLIB_PyLong_Check(obj)) {
-            glong val;
-            val = PYGLIB_PyLong_AsLong(obj);
-            if (val >= -128 && val <= 127)
-                g_value_set_schar(value, (gchar) val);
-            else
-                return -1;
-        }
-#if PY_VERSION_HEX < 0x03000000
-        else if (PyString_Check(obj)) {
-            g_value_set_schar(value, PyString_AsString(obj)[0]);
-        }
-#endif
-        else if (PyUnicode_Check(obj)) {
-            tmp = PyUnicode_AsUTF8String(obj);
-            g_value_set_schar(value, PYGLIB_PyBytes_AsString(tmp)[0]);
-            Py_DECREF(tmp);
-        } else {
-            PyErr_SetString(PyExc_TypeError, "Cannot convert to TYPE_CHAR");
-            return -1;
-        }
-
-        break;
-    case G_TYPE_UCHAR:
-        if (PYGLIB_PyLong_Check(obj)) {
-            glong val;
-            val = PYGLIB_PyLong_AsLong(obj);
-            if (val >= 0 && val <= 255)
-                g_value_set_uchar(value, (guchar) val);
-            else
-                return -1;
-#if PY_VERSION_HEX < 0x03000000
-        } else if (PyString_Check(obj)) {
-            g_value_set_uchar(value, PyString_AsString(obj)[0]);
-#endif
-        } else if (PyUnicode_Check(obj)) {
-            tmp = PyUnicode_AsUTF8String(obj);
-            g_value_set_uchar(value, PYGLIB_PyBytes_AsString(tmp)[0]);
-            Py_DECREF(tmp);
-        } else {
-            PyErr_Clear();
-            return -1;
-        }
-        break;
-    case G_TYPE_BOOLEAN:
-        g_value_set_boolean(value, PyObject_IsTrue(obj));
-        break;
-    case G_TYPE_INT:
-        g_value_set_int(value, PYGLIB_PyLong_AsLong(obj));
-        break;
-    case G_TYPE_UINT:
-    {
-        if (PYGLIB_PyLong_Check(obj)) {
-            guint val;
-
-            /* check that number is not negative */
-            if (PyLong_AsLongLong(obj) < 0)
-                return -1;
-
-            val = PyLong_AsUnsignedLong(obj);
-            if (val <= G_MAXUINT)
-                g_value_set_uint(value, val);
-            else
-                return -1;
-        } else {
-            g_value_set_uint(value, PyLong_AsUnsignedLong(obj));
-        }
-    }
-    break;
-    case G_TYPE_LONG:
-        g_value_set_long(value, PYGLIB_PyLong_AsLong(obj));
-        break;
-    case G_TYPE_ULONG:
-#if PY_VERSION_HEX < 0x03000000
-        if (PyInt_Check(obj)) {
-            long val;
-
-            val = PYGLIB_PyLong_AsLong(obj);
-            if (val < 0) {
-                PyErr_SetString(PyExc_OverflowError, "negative value not allowed for uint64 property");
-                return -1;
-            }
-            g_value_set_ulong(value, (gulong)val);
-        } else
-#endif
-            if (PyLong_Check(obj))
-                g_value_set_ulong(value, PyLong_AsUnsignedLong(obj));
-            else
-                return -1;
-        break;
-    case G_TYPE_INT64:
-        g_value_set_int64(value, PyLong_AsLongLong(obj));
-        break;
-    case G_TYPE_UINT64:
-#if PY_VERSION_HEX < 0x03000000
-        if (PyInt_Check(obj)) {
-            long v = PyInt_AsLong(obj);
-            if (v < 0) {
-                PyErr_SetString(PyExc_OverflowError, "negative value not allowed for uint64 property");
-                return -1;
-            }
-            g_value_set_uint64(value, v);
-        } else
-#endif
-            if (PyLong_Check(obj))
-                g_value_set_uint64(value, PyLong_AsUnsignedLongLong(obj));
-            else
-                return -1;
-        break;
-    case G_TYPE_ENUM:
-    {
-        gint val = 0;
-        if (pyg_enum_get_value(G_VALUE_TYPE(value), obj, &val) < 0) {
-            return -1;
-        }
-        g_value_set_enum(value, val);
-    }
-    break;
-    case G_TYPE_FLAGS:
-    {
-        guint val = 0;
-        if (pyg_flags_get_value(G_VALUE_TYPE(value), obj, &val) < 0) {
-            return -1;
-        }
-        g_value_set_flags(value, val);
-    }
-    break;
-    case G_TYPE_FLOAT:
-        g_value_set_float(value, PyFloat_AsDouble(obj));
-        break;
-    case G_TYPE_DOUBLE:
-        g_value_set_double(value, PyFloat_AsDouble(obj));
-        break;
-    case G_TYPE_STRING:
-        if (obj == Py_None) {
-            g_value_set_string(value, NULL);
-        } else {
-            PyObject* tmp_str = PyObject_Str(obj);
-            if (tmp_str == NULL) {
-                PyErr_Clear();
-                if (PyUnicode_Check(obj)) {
-                    tmp = PyUnicode_AsUTF8String(obj);
-                    g_value_set_string(value, PYGLIB_PyBytes_AsString(tmp));
-                    Py_DECREF(tmp);
-                } else {
-                    PyErr_SetString(PyExc_TypeError, "Expected string");
-                    return -1;
-                }
-            } else {
-#if PY_VERSION_HEX < 0x03000000
-                g_value_set_string(value, PyString_AsString(tmp_str));
-#else
-                tmp = PyUnicode_AsUTF8String(tmp_str);
-                g_value_set_string(value, PyBytes_AsString(tmp));
-                Py_DECREF(tmp);
-#endif
-            }
-            Py_XDECREF(tmp_str);
-        }
-        break;
-    case G_TYPE_POINTER:
-        if (obj == Py_None)
-            g_value_set_pointer(value, NULL);
-        else if (PyObject_TypeCheck(obj, &PyGPointer_Type) &&
-                G_VALUE_HOLDS(value, ((PyGPointer *)obj)->gtype))
-            g_value_set_pointer(value, pyg_pointer_get(obj, gpointer));
-        else if (PYGLIB_CPointer_Check(obj))
-            g_value_set_pointer(value, PYGLIB_CPointer_GetPointer(obj, NULL));
-        else if (G_VALUE_HOLDS_GTYPE (value))
-            g_value_set_gtype (value, pyg_type_from_object (obj));
-        else {
-            PyErr_SetString(PyExc_TypeError, "Expected pointer");
-            return -1;
-        }
-        break;
-    case G_TYPE_BOXED: {
-        PyGTypeMarshal *bm;
-
-        if (obj == Py_None)
-            g_value_set_boxed(value, NULL);
-        else if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT))
-            g_value_set_boxed(value, obj);
-        else if (PyObject_TypeCheck(obj, &PyGBoxed_Type) &&
-                G_VALUE_HOLDS(value, ((PyGBoxed *)obj)->gtype))
-            g_value_set_boxed(value, pyg_boxed_get(obj, gpointer));
-        else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) {
-            GType type;
-            GValue *n_value;
-
-            type = pyg_type_from_object((PyObject*)Py_TYPE(obj));
-            if (G_UNLIKELY (! type)) {
-                return -1;
-            }
-            n_value = g_new0 (GValue, 1);
-            g_value_init (n_value, type);
-            g_value_take_boxed (value, n_value);
-            return pyg_value_from_pyobject_with_error (n_value, obj);
-        }
-        else if (PySequence_Check(obj) &&
-                G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY))
-            return pyg_value_array_from_pyobject(value, obj, NULL);
-        else if (PySequence_Check(obj) &&
-                G_VALUE_HOLDS(value, G_TYPE_ARRAY))
-            return pyg_array_from_pyobject(value, obj);
-        else if (PYGLIB_PyUnicode_Check(obj) &&
-                G_VALUE_HOLDS(value, G_TYPE_GSTRING)) {
-            GString *string;
-            char *buffer;
-            Py_ssize_t len;
-            if (PYGLIB_PyUnicode_AsStringAndSize(obj, &buffer, &len))
-                return -1;
-            string = g_string_new_len(buffer, len);
-            g_value_set_boxed(value, string);
-            g_string_free (string, TRUE);
-            break;
-        }
-        else if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL)
-            return bm->tovalue(value, obj);
-        else if (PYGLIB_CPointer_Check(obj))
-            g_value_set_boxed(value, PYGLIB_CPointer_GetPointer(obj, NULL));
-        else {
-            PyErr_SetString(PyExc_TypeError, "Expected Boxed");
-            return -1;
-        }
-        break;
-    }
-    case G_TYPE_PARAM:
-        /* we need to support both the wrapped _gobject.GParamSpec and the GI
-         * GObject.ParamSpec */
-        if (G_IS_PARAM_SPEC (pygobject_get (obj)))
-            g_value_set_param(value, G_PARAM_SPEC (pygobject_get (obj)));
-        else if (PyGParamSpec_Check(obj))
-            g_value_set_param(value, PYGLIB_CPointer_GetPointer(obj, NULL));
-        else {
-            PyErr_SetString(PyExc_TypeError, "Expected ParamSpec");
-            return -1;
-        }
-        break;
-    case G_TYPE_OBJECT:
-        if (obj == Py_None) {
-            g_value_set_object(value, NULL);
-        } else if (PyObject_TypeCheck(obj, &PyGObject_Type) &&
-                G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj),
-                        G_VALUE_TYPE(value))) {
-            g_value_set_object(value, pygobject_get(obj));
-        } else {
-            PyErr_SetString(PyExc_TypeError, "Expected GObject");
-            return -1;
-        }
-        break;
-    case G_TYPE_VARIANT:
-    {
-        if (obj == Py_None)
-            g_value_set_variant(value, NULL);
-        else if (pyg_type_from_object_strict(obj, FALSE) == G_TYPE_VARIANT)
-            g_value_set_variant(value, pyg_boxed_get(obj, GVariant));
-        else {
-            PyErr_SetString(PyExc_TypeError, "Expected Variant");
-            return -1;
-        }
-        break;
-    }
-    default:
-    {
-        PyGTypeMarshal *bm;
-        if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL) {
-            return bm->tovalue(value, obj);
-        } else {
-            PyErr_SetString(PyExc_TypeError, "Unknown value type");
-            return -1;
-        }
-        break;
-    }
-    }
-
-    /* If an error occurred, unset the GValue but don't clear the Python error. */
-    if (PyErr_Occurred()) {
-        g_value_unset(value);
-        return -1;
-    }
-
-    return 0;
-}
-
-/**
- * pyg_value_from_pyobject:
- * @value: the GValue object to store the converted value in.
- * @obj: the Python object to convert.
- *
- * Same basic function as pyg_value_from_pyobject_with_error but clears
- * any Python errors before returning.
- *
- * Returns: 0 on success, -1 on error.
- */
-int
-pyg_value_from_pyobject(GValue *value, PyObject *obj)
-{
-    int res = pyg_value_from_pyobject_with_error (value, obj);
-
-    if (PyErr_Occurred()) {
-        PyErr_Clear();
-        return -1;
-    }
-    return res;
-}
-
-/**
- * pyg_value_as_pyobject:
- * @value: the GValue object.
- * @copy_boxed: true if boxed values should be copied.
- *
- * This function creates/returns a Python wrapper object that
- * represents the GValue passed as an argument.
- *
- * Returns: a PyObject representing the value.
- */
-PyObject *
-pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed)
-{
-    gchar buf[128];
-
-    switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value))) {
-    case G_TYPE_INTERFACE:
-        if (g_type_is_a(G_VALUE_TYPE(value), G_TYPE_OBJECT))
-            return pygobject_new(g_value_get_object(value));
-        else
-            break;
-    case G_TYPE_CHAR: {
-        gint8 val = g_value_get_schar(value);
-        return PYGLIB_PyUnicode_FromStringAndSize((char *)&val, 1);
-    }
-    case G_TYPE_UCHAR: {
-        guint8 val = g_value_get_uchar(value);
-        return PYGLIB_PyBytes_FromStringAndSize((char *)&val, 1);
-    }
-    case G_TYPE_BOOLEAN: {
-        return PyBool_FromLong(g_value_get_boolean(value));
-    }
-    case G_TYPE_INT:
-        return PYGLIB_PyLong_FromLong(g_value_get_int(value));
-    case G_TYPE_UINT:
-    {
-        /* in Python, the Int object is backed by a long.  If a
-              long can hold the whole value of an unsigned int, use
-              an Int.  Otherwise, use a Long object to avoid overflow.
-              This matches the ULongArg behavior in codegen/argtypes.h */
-#if (G_MAXUINT <= G_MAXLONG)
-        return PYGLIB_PyLong_FromLong((glong) g_value_get_uint(value));
-#else
-        return PyLong_FromUnsignedLong((gulong) g_value_get_uint(value));
-#endif
-    }
-    case G_TYPE_LONG:
-        return PYGLIB_PyLong_FromLong(g_value_get_long(value));
-    case G_TYPE_ULONG:
-    {
-        gulong val = g_value_get_ulong(value);
-
-        if (val <= G_MAXLONG)
-            return PYGLIB_PyLong_FromLong((glong) val);
-        else
-            return PyLong_FromUnsignedLong(val);
-    }
-    case G_TYPE_INT64:
-    {
-        gint64 val = g_value_get_int64(value);
-
-        if (G_MINLONG <= val && val <= G_MAXLONG)
-            return PYGLIB_PyLong_FromLong((glong) val);
-        else
-            return PyLong_FromLongLong(val);
-    }
-    case G_TYPE_UINT64:
-    {
-        guint64 val = g_value_get_uint64(value);
-
-        if (val <= G_MAXLONG)
-            return PYGLIB_PyLong_FromLong((glong) val);
-        else
-            return PyLong_FromUnsignedLongLong(val);
-    }
-    case G_TYPE_ENUM:
-        return pyg_enum_from_gtype(G_VALUE_TYPE(value), g_value_get_enum(value));
-    case G_TYPE_FLAGS:
-        return pyg_flags_from_gtype(G_VALUE_TYPE(value), g_value_get_flags(value));
-    case G_TYPE_FLOAT:
-        return PyFloat_FromDouble(g_value_get_float(value));
-    case G_TYPE_DOUBLE:
-        return PyFloat_FromDouble(g_value_get_double(value));
-    case G_TYPE_STRING:
-    {
-        const gchar *str = g_value_get_string(value);
-
-        if (str)
-            return PYGLIB_PyUnicode_FromString(str);
-        Py_INCREF(Py_None);
-        return Py_None;
-    }
-    case G_TYPE_POINTER:
-        if (G_VALUE_HOLDS_GTYPE (value))
-            return pyg_type_wrapper_new (g_value_get_gtype (value));
-        else
-            return pyg_pointer_new(G_VALUE_TYPE(value),
-                    g_value_get_pointer(value));
-    case G_TYPE_BOXED: {
-        PyGTypeMarshal *bm;
-
-        if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT)) {
-            PyObject *ret = (PyObject *)g_value_dup_boxed(value);
-            if (ret == NULL) {
-                Py_INCREF(Py_None);
-                return Py_None;
-            }
-            return ret;
-        } else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) {
-            GValue *n_value = g_value_get_boxed (value);
-            return pyg_value_as_pyobject(n_value, copy_boxed);
-        } else if (G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY)) {
-            GValueArray *array = (GValueArray *) g_value_get_boxed(value);
-            PyObject *ret = PyList_New(array->n_values);
-            int i;
-            for (i = 0; i < array->n_values; ++i)
-                PyList_SET_ITEM(ret, i, pyg_value_as_pyobject
-                        (array->values + i, copy_boxed));
-            return ret;
-        } else if (G_VALUE_HOLDS(value, G_TYPE_GSTRING)) {
-            GString *string = (GString *) g_value_get_boxed(value);
-            PyObject *ret = PYGLIB_PyUnicode_FromStringAndSize(string->str, string->len);
-            return ret;
-        }
-        bm = pyg_type_lookup(G_VALUE_TYPE(value));
-        if (bm) {
-            return bm->fromvalue(value);
-        } else {
-            if (copy_boxed)
-                return pyg_boxed_new(G_VALUE_TYPE(value),
-                        g_value_get_boxed(value), TRUE, TRUE);
-            else
-                return pyg_boxed_new(G_VALUE_TYPE(value),
-                        g_value_get_boxed(value),FALSE,FALSE);
-        }
-    }
-    case G_TYPE_PARAM:
-        return pyg_param_spec_new(g_value_get_param(value));
-    case G_TYPE_OBJECT:
-        return pygobject_new(g_value_get_object(value));
-    case G_TYPE_VARIANT:
-    {
-        GVariant *v = g_value_get_variant(value);
-        if (v == NULL) {
-            Py_INCREF(Py_None);
-            return Py_None;
-        }
-        return pyg_boxed_new(G_TYPE_VARIANT, g_variant_ref(v), FALSE, FALSE);
-    }
-    default:
-    {
-        PyGTypeMarshal *bm;
-        if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))))
-            return bm->fromvalue(value);
-        break;
-    }
-    }
-    g_snprintf(buf, sizeof(buf), "unknown type %s",
-               g_type_name(G_VALUE_TYPE(value)));
-    PyErr_SetString(PyExc_TypeError, buf);
-    return NULL;
-}
-
 /* -------------- PyGClosure ----------------- */
 
 static void
@@ -1817,92 +1179,12 @@ int pyg_pyobj_to_unichar_conv(PyObject* py_obj, void* ptr)
     return 0;
 }
 
-
-int
-pyg_param_gvalue_from_pyobject(GValue* value,
-                               PyObject* py_obj,
-                              const GParamSpec* pspec)
-{
-    if (G_IS_PARAM_SPEC_UNICHAR(pspec)) {
-       gunichar u;
-
-       if (!pyg_pyobj_to_unichar_conv(py_obj, &u)) {
-           PyErr_Clear();
-           return -1;
-       }
-        g_value_set_uint(value, u);
-       return 0;
-    }
-    else if (G_IS_PARAM_SPEC_VALUE_ARRAY(pspec))
-       return pyg_value_array_from_pyobject(value, py_obj,
-                                            G_PARAM_SPEC_VALUE_ARRAY(pspec));
-    else {
-       return pyg_value_from_pyobject(value, py_obj);
-    }
-}
-
-PyObject*
-pyg_param_gvalue_as_pyobject(const GValue* gvalue,
-                             gboolean copy_boxed,
-                            const GParamSpec* pspec)
-{
-    if (G_IS_PARAM_SPEC_UNICHAR(pspec)) {
-       gunichar u;
-       Py_UNICODE uni_buffer[2] = { 0, 0 };
-
-       u = g_value_get_uint(gvalue);
-       uni_buffer[0] = u;
-       return PyUnicode_FromUnicode(uni_buffer, 1);
-    }
-    else {
-       return pyg_value_as_pyobject(gvalue, copy_boxed);
-    }
-}
-
 gboolean
 pyg_gtype_is_custom(GType gtype)
 {
     return g_type_get_qdata (gtype, pygobject_custom_key) != NULL;
 }
 
-static PyObject *
-_pyg_strv_from_gvalue(const GValue *value)
-{
-    gchar    **argv = (gchar **) g_value_get_boxed(value);
-    int        argc = 0, i;
-    PyObject  *py_argv;
-
-    if (argv) {
-        while (argv[argc])
-            argc++;
-    }
-    py_argv = PyList_New(argc);
-    for (i = 0; i < argc; ++i)
-       PyList_SET_ITEM(py_argv, i, PYGLIB_PyUnicode_FromString(argv[i]));
-    return py_argv;
-}
-
-static int
-_pyg_strv_to_gvalue(GValue *value, PyObject *obj)
-{
-    Py_ssize_t argc, i;
-    gchar **argv;
-
-    if (!(PyTuple_Check(obj) || PyList_Check(obj)))
-        return -1;
-
-    argc = PySequence_Length(obj);
-    for (i = 0; i < argc; ++i)
-       if (!PYGLIB_PyUnicode_Check(PySequence_Fast_GET_ITEM(obj, i)))
-           return -1;
-    argv = g_new(gchar *, argc + 1);
-    for (i = 0; i < argc; ++i)
-       argv[i] = g_strdup(PYGLIB_PyUnicode_AsString(PySequence_Fast_GET_ITEM(obj, i)));
-    argv[i] = NULL;
-    g_value_take_boxed(value, argv);
-    return 0;
-}
-
 void
 pygobject_type_register_types(PyObject *d)
 {
@@ -1922,6 +1204,6 @@ pygobject_type_register_types(PyObject *d)
     PyGObjectDoc_Type.tp_descr_get = (descrgetfunc)object_doc_descr_get;
 
     pyg_register_gtype_custom(G_TYPE_STRV,
-                             _pyg_strv_from_gvalue,
-                             _pyg_strv_to_gvalue);
+                             pyg_strv_from_gvalue,
+                             pyg_strv_to_gvalue);
 }
diff --git a/gi/pygtype.h b/gi/pygtype.h
index 2f9e7ad..204c146 100644
--- a/gi/pygtype.h
+++ b/gi/pygtype.h
@@ -23,6 +23,23 @@
 #ifndef __PYGOBJECT_TYPE_H__ 
 #define __PYGOBJECT_TYPE_H__
 
+#include <glib-object.h>
+#include <Python.h>
+
+typedef PyObject *(* fromvaluefunc)(const GValue *value);
+typedef int (*tovaluefunc)(GValue *value, PyObject *obj);
+
+typedef struct {
+    fromvaluefunc fromvalue;
+    tovaluefunc tovalue;
+} PyGTypeMarshal;
+
+PyGTypeMarshal *pyg_type_lookup(GType type);
+
+void pyg_register_gtype_custom(GType gtype,
+                               fromvaluefunc from_func,
+                               tovaluefunc to_func);
+
 void pygobject_type_register_types(PyObject *d);
 
 #endif /* __PYGOBJECT_TYPE_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]