From 204f5a187782c5325ed6bed96c9a940f3aa67d04 Mon Sep 17 00:00:00 2001 From: Simon Feltman Date: Sun, 12 Jan 2014 12:26:30 -0800 Subject: 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 4c614f7b..82d52a13 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 a30f03e3..52573d65 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 6ac12cf0..f2cc27b2 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 3e8d46a1..544da3c9 100644 --- a/gi/pygi-value.h +++ b/gi/pygi-value.h @@ -20,12 +20,24 @@ #include #include +#include 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 f48d073b..be565d62 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 129f29ab..215376bf 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 9dc1153e..e1fb4e66 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 2f9e7add..204c1464 100644 --- a/gi/pygtype.h +++ b/gi/pygtype.h @@ -23,6 +23,23 @@ #ifndef __PYGOBJECT_TYPE_H__ #define __PYGOBJECT_TYPE_H__ +#include +#include + +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__ */ -- cgit v1.2.1