summaryrefslogtreecommitdiff
path: root/gi/pygi-value.c
diff options
context:
space:
mode:
Diffstat (limited to 'gi/pygi-value.c')
-rw-r--r--gi/pygi-value.c933
1 files changed, 933 insertions, 0 deletions
diff --git a/gi/pygi-value.c b/gi/pygi-value.c
new file mode 100644
index 0000000..e7ee1e0
--- /dev/null
+++ b/gi/pygi-value.c
@@ -0,0 +1,933 @@
+
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <Python.h>
+#include "pygi-value.h"
+#include "pygi-struct.h"
+#include "pygi-basictype.h"
+#include "pygobject-object.h"
+#include "pygi-type.h"
+#include "pygenum.h"
+#include "pygpointer.h"
+#include "pygboxed.h"
+#include "pygflags.h"
+#include "pygparamspec.h"
+
+
+/* glib 2.62 has started to print warnings for these which can't be disabled selectively, so just copy them here */
+#define PYGI_TYPE_VALUE_ARRAY (g_value_array_get_type())
+#define PYGI_IS_PARAM_SPEC_VALUE_ARRAY(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), PYGI_TYPE_VALUE_ARRAY))
+#define PYGI_PARAM_SPEC_VALUE_ARRAY(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), g_param_spec_types[18], GParamSpecValueArray))
+
+GIArgument
+_pygi_argument_from_g_value(const GValue *value,
+ GITypeInfo *type_info)
+{
+ GIArgument arg = { 0, };
+
+ GITypeTag type_tag = g_type_info_get_tag (type_info);
+
+ /* For the long handling: long can be equivalent to
+ int32 or int64, depending on the architecture, but
+ gi doesn't tell us (and same for ulong)
+ */
+ switch (type_tag) {
+ case GI_TYPE_TAG_BOOLEAN:
+ arg.v_boolean = g_value_get_boolean (value);
+ break;
+ case GI_TYPE_TAG_INT8:
+ arg.v_int8 = g_value_get_schar (value);
+ break;
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_INT32:
+ if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_LONG))
+ arg.v_int32 = (gint32)g_value_get_long (value);
+ else
+ arg.v_int32 = (gint32)g_value_get_int (value);
+ break;
+ case GI_TYPE_TAG_INT64:
+ if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_LONG))
+ arg.v_int64 = g_value_get_long (value);
+ else
+ arg.v_int64 = g_value_get_int64 (value);
+ break;
+ case GI_TYPE_TAG_UINT8:
+ arg.v_uint8 = g_value_get_uchar (value);
+ break;
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_UINT32:
+ if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_ULONG))
+ arg.v_uint32 = (guint32)g_value_get_ulong (value);
+ else
+ arg.v_uint32 = (guint32)g_value_get_uint (value);
+ break;
+ case GI_TYPE_TAG_UINT64:
+ if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_ULONG))
+ arg.v_uint64 = g_value_get_ulong (value);
+ else
+ arg.v_uint64 = g_value_get_uint64 (value);
+ break;
+ case GI_TYPE_TAG_UNICHAR:
+ arg.v_uint32 = g_value_get_schar (value);
+ break;
+ case GI_TYPE_TAG_FLOAT:
+ arg.v_float = g_value_get_float (value);
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ arg.v_double = g_value_get_double (value);
+ break;
+ case GI_TYPE_TAG_GTYPE:
+ arg.v_size = g_value_get_gtype (value);
+ break;
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ /* Callers are responsible for ensuring the GValue stays alive
+ * long enough for the string to be copied. */
+ arg.v_string = (char *)g_value_get_string (value);
+ break;
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ case GI_TYPE_TAG_ARRAY:
+ case GI_TYPE_TAG_GHASH:
+ if (G_VALUE_HOLDS_BOXED (value))
+ arg.v_pointer = g_value_get_boxed (value);
+ else
+ /* e. g. GSettings::change-event */
+ arg.v_pointer = g_value_get_pointer (value);
+ break;
+ case GI_TYPE_TAG_INTERFACE:
+ {
+ GIBaseInfo *info;
+ GIInfoType info_type;
+
+ info = g_type_info_get_interface (type_info);
+ info_type = g_base_info_get_type (info);
+
+ g_base_info_unref (info);
+
+ switch (info_type) {
+ case GI_INFO_TYPE_FLAGS:
+ arg.v_uint = g_value_get_flags (value);
+ break;
+ case GI_INFO_TYPE_ENUM:
+ arg.v_int = g_value_get_enum (value);
+ break;
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_OBJECT:
+ if (G_VALUE_HOLDS_PARAM (value))
+ arg.v_pointer = g_value_get_param (value);
+ else
+ arg.v_pointer = g_value_get_object (value);
+ break;
+ case GI_INFO_TYPE_BOXED:
+ case GI_INFO_TYPE_STRUCT:
+ case GI_INFO_TYPE_UNION:
+ if (G_VALUE_HOLDS (value, G_TYPE_BOXED)) {
+ arg.v_pointer = g_value_get_boxed (value);
+ } else if (G_VALUE_HOLDS (value, G_TYPE_VARIANT)) {
+ arg.v_pointer = g_value_get_variant (value);
+ } else if (G_VALUE_HOLDS (value, G_TYPE_POINTER)) {
+ arg.v_pointer = g_value_get_pointer (value);
+ } else {
+ PyErr_Format (PyExc_NotImplementedError,
+ "Converting GValue's of type '%s' is not implemented.",
+ g_type_name (G_VALUE_TYPE (value)));
+ }
+ break;
+ default:
+ PyErr_Format (PyExc_NotImplementedError,
+ "Converting GValue's of type '%s' is not implemented.",
+ g_info_type_to_string (info_type));
+ break;
+ }
+ break;
+ }
+ case GI_TYPE_TAG_ERROR:
+ arg.v_pointer = g_value_get_boxed (value);
+ break;
+ case GI_TYPE_TAG_VOID:
+ arg.v_pointer = g_value_get_pointer (value);
+ break;
+ default:
+ break;
+ }
+
+ return arg;
+}
+
+
+/* Ignore g_value_array deprecations. Although they are deprecated,
+ * we still need to support the marshaling of them in PyGObject.
+ */
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+static int
+pyg_value_array_from_pyobject(GValue *value,
+ PyObject *obj,
+ const GParamSpecValueArray *pspec)
+{
+ Py_ssize_t seq_len;
+ GValueArray *value_array;
+ guint len, i;
+
+ seq_len = PySequence_Length(obj);
+ if (seq_len == -1) {
+ PyErr_Clear();
+ return -1;
+ }
+ len = (guint)seq_len;
+
+ 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;
+
+ 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;
+ }
+ }
+
+ if (type == G_TYPE_VALUE) {
+ const GValue * item_value = pyg_boxed_get(item, GValue);
+ g_value_array_append(value_array, item_value);
+ } else {
+ GValue item_value = { 0, };
+ int status;
+
+ 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;
+}
+
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+static int
+pyg_array_from_pyobject(GValue *value,
+ PyObject *obj)
+{
+ Py_ssize_t len, i;
+ GArray *array;
+
+ 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)
+{
+ 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:
+ {
+ gint8 temp;
+ if (pygi_gschar_from_py (obj, &temp)) {
+ g_value_set_schar (value, temp);
+ return 0;
+ } else
+ return -1;
+ }
+ case G_TYPE_UCHAR:
+ {
+ guchar temp;
+ if (pygi_guchar_from_py (obj, &temp)) {
+ g_value_set_uchar (value, temp);
+ return 0;
+ } else
+ return -1;
+ }
+ case G_TYPE_BOOLEAN:
+ {
+ gboolean temp;
+ if (pygi_gboolean_from_py (obj, &temp)) {
+ g_value_set_boolean (value, temp);
+ return 0;
+ } else
+ return -1;
+ }
+ case G_TYPE_INT:
+ {
+ gint temp;
+ if (pygi_gint_from_py (obj, &temp)) {
+ g_value_set_int (value, temp);
+ return 0;
+ } else
+ return -1;
+ }
+ case G_TYPE_UINT:
+ {
+ guint temp;
+ if (pygi_guint_from_py (obj, &temp)) {
+ g_value_set_uint (value, temp);
+ return 0;
+ } else
+ return -1;
+ }
+ case G_TYPE_LONG:
+ {
+ glong temp;
+ if (pygi_glong_from_py (obj, &temp)) {
+ g_value_set_long (value, temp);
+ return 0;
+ } else
+ return -1;
+ }
+ case G_TYPE_ULONG:
+ {
+ gulong temp;
+ if (pygi_gulong_from_py (obj, &temp)) {
+ g_value_set_ulong (value, temp);
+ return 0;
+ } else
+ return -1;
+ }
+ case G_TYPE_INT64:
+ {
+ gint64 temp;
+ if (pygi_gint64_from_py (obj, &temp)) {
+ g_value_set_int64 (value, temp);
+ return 0;
+ } else
+ return -1;
+ }
+ case G_TYPE_UINT64:
+ {
+ guint64 temp;
+ if (pygi_guint64_from_py (obj, &temp)) {
+ g_value_set_uint64 (value, temp);
+ return 0;
+ } else
+ return -1;
+ }
+ 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);
+ return 0;
+ }
+ break;
+ case G_TYPE_FLOAT:
+ {
+ gfloat temp;
+ if (pygi_gfloat_from_py (obj, &temp)) {
+ g_value_set_float (value, temp);
+ return 0;
+ } else
+ return -1;
+ }
+ case G_TYPE_DOUBLE:
+ {
+ gdouble temp;
+ if (pygi_gdouble_from_py (obj, &temp)) {
+ g_value_set_double (value, temp);
+ return 0;
+ } else
+ return -1;
+ }
+ case G_TYPE_STRING:
+ {
+ gchar *temp;
+ if (pygi_utf8_from_py (obj, &temp)) {
+ g_value_take_string (value, temp);
+ return 0;
+ } else {
+ /* also allows setting anything implementing __str__ */
+ PyObject* str;
+ PyErr_Clear ();
+ str = PyObject_Str (obj);
+ if (str == NULL)
+ return -1;
+ if (pygi_utf8_from_py (str, &temp)) {
+ Py_DECREF (str);
+ g_value_take_string (value, temp);
+ return 0;
+ }
+ Py_DECREF (str);
+ return -1;
+ }
+ }
+ 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 (PyCapsule_CheckExact (obj))
+ g_value_set_pointer(value, PyCapsule_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;
+ gboolean holds_value_array;
+
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ holds_value_array = G_VALUE_HOLDS(value, PYGI_TYPE_VALUE_ARRAY);
+ G_GNUC_END_IGNORE_DEPRECATIONS
+
+ 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) && holds_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 (PyUnicode_Check (obj) &&
+ G_VALUE_HOLDS(value, G_TYPE_GSTRING)) {
+ GString *string;
+ char *buffer;
+ Py_ssize_t len;
+ buffer = PyUnicode_AsUTF8AndSize (obj, &len);
+ if (buffer == NULL)
+ 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 (PyCapsule_CheckExact (obj))
+ g_value_set_boxed(value, PyCapsule_GetPointer (obj, NULL));
+ else {
+ PyErr_SetString(PyExc_TypeError, "Expected Boxed");
+ return -1;
+ }
+ break;
+ }
+ case G_TYPE_PARAM:
+ /* we need to support both the wrapped _gi.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 (pyg_param_spec_check (obj))
+ g_value_set_param(value, PyCapsule_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;
+}
+
+/**
+ * pygi_value_to_py_basic_type:
+ * @value: the GValue object.
+ * @handled: (out): TRUE if the return value is defined
+ *
+ * This function creates/returns a Python wrapper object that
+ * represents the GValue passed as an argument limited to supporting basic types
+ * like ints, bools, and strings.
+ *
+ * Returns: a PyObject representing the value.
+ */
+PyObject *
+pygi_value_to_py_basic_type (const GValue *value, GType fundamental, gboolean *handled)
+{
+ *handled = TRUE;
+ switch (fundamental) {
+ case G_TYPE_CHAR:
+ return PyLong_FromLong (g_value_get_schar (value));
+ case G_TYPE_UCHAR:
+ return PyLong_FromLong (g_value_get_uchar (value));
+ case G_TYPE_BOOLEAN:
+ return pygi_gboolean_to_py (g_value_get_boolean (value));
+ case G_TYPE_INT:
+ return pygi_gint_to_py (g_value_get_int (value));
+ case G_TYPE_UINT:
+ return pygi_guint_to_py (g_value_get_uint (value));
+ case G_TYPE_LONG:
+ return pygi_glong_to_py (g_value_get_long(value));
+ case G_TYPE_ULONG:
+ return pygi_gulong_to_py (g_value_get_ulong (value));
+ case G_TYPE_INT64:
+ return pygi_gint64_to_py (g_value_get_int64 (value));
+ case G_TYPE_UINT64:
+ return pygi_guint64_to_py (g_value_get_uint64 (value));
+ 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 pygi_gfloat_to_py (g_value_get_float (value));
+ case G_TYPE_DOUBLE:
+ return pygi_gdouble_to_py (g_value_get_double (value));
+ case G_TYPE_STRING:
+ return pygi_utf8_to_py (g_value_get_string (value));
+ default:
+ *handled = FALSE;
+ return NULL;
+ }
+}
+
+/**
+ * value_to_py_structured_type:
+ * @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 or NULL and sets an error;
+ */
+static PyObject *
+value_to_py_structured_type (const GValue *value, GType fundamental, gboolean copy_boxed)
+{
+ const gchar *type_name;
+
+ switch (fundamental) {
+ 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_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;
+ gboolean holds_value_array;
+
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ holds_value_array = G_VALUE_HOLDS(value, PYGI_TYPE_VALUE_ARRAY);
+ G_GNUC_END_IGNORE_DEPRECATIONS
+
+ 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 (holds_value_array) {
+ GValueArray *array = (GValueArray *) g_value_get_boxed(value);
+ Py_ssize_t n_values = array ? array->n_values : 0;
+ PyObject *ret = PyList_New(n_values);
+ int i;
+ for (i = 0; i < 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 = 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 pygi_gboxed_new(G_VALUE_TYPE(value),
+ g_value_get_boxed(value), TRUE, TRUE);
+ else
+ return pygi_gboxed_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 pygi_struct_new_from_g_type (G_TYPE_VARIANT, g_variant_ref(v), FALSE);
+ }
+ default:
+ {
+ PyGTypeMarshal *bm;
+ if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))))
+ return bm->fromvalue(value);
+ break;
+ }
+ }
+
+ type_name = g_type_name (G_VALUE_TYPE (value));
+ if (type_name == NULL) {
+ type_name = "(null)";
+ }
+ PyErr_Format (PyExc_TypeError, "unknown type %s", type_name);
+ return NULL;
+}
+
+
+/**
+ * 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 or %NULL and sets an exception.
+ */
+PyObject *
+pyg_value_as_pyobject (const GValue *value, gboolean copy_boxed)
+{
+ PyObject *pyobj;
+ gboolean handled;
+ GType fundamental = G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value));
+
+ /* HACK: special case char and uchar to return PyBytes intstead of integers
+ * in the general case. Property access will skip this by calling
+ * pygi_value_to_py_basic_type() directly.
+ * See: https://bugzilla.gnome.org/show_bug.cgi?id=733893 */
+ if (fundamental == G_TYPE_CHAR) {
+ gint8 val = g_value_get_schar(value);
+ return PyUnicode_FromStringAndSize ((char *)&val, 1);
+ } else if (fundamental == G_TYPE_UCHAR) {
+ guint8 val = g_value_get_uchar(value);
+ return PyBytes_FromStringAndSize ((char *)&val, 1);
+ }
+
+ pyobj = pygi_value_to_py_basic_type (value, fundamental, &handled);
+ if (handled)
+ return pyobj;
+
+ pyobj = value_to_py_structured_type (value, fundamental, copy_boxed);
+ return pyobj;
+}
+
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+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 (PYGI_IS_PARAM_SPEC_VALUE_ARRAY(pspec))
+ return pyg_value_array_from_pyobject(value, py_obj,
+ PYGI_PARAM_SPEC_VALUE_ARRAY(pspec));
+ else {
+ return pyg_value_from_pyobject(value, py_obj);
+ }
+}
+
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+PyObject*
+pyg_param_gvalue_as_pyobject(const GValue* gvalue,
+ gboolean copy_boxed,
+ const GParamSpec* pspec)
+{
+ if (G_IS_PARAM_SPEC_UNICHAR(pspec)) {
+ gunichar u;
+ gchar *encoded;
+ PyObject *retval;
+
+ u = g_value_get_uint (gvalue);
+ encoded = g_ucs4_to_utf8 (&u, 1, NULL, NULL, NULL);
+ if (encoded == NULL) {
+ PyErr_SetString (PyExc_ValueError, "Failed to decode");
+ return NULL;
+ }
+ retval = PyUnicode_FromString (encoded);
+ g_free (encoded);
+ return retval;
+ }
+ else {
+ return pyg_value_as_pyobject(gvalue, copy_boxed);
+ }
+}
+
+PyObject *
+pyg__gvalue_get(PyObject *module, PyObject *pygvalue)
+{
+ if (!pyg_boxed_check (pygvalue, G_TYPE_VALUE)) {
+ PyErr_SetString (PyExc_TypeError, "Expected GValue argument.");
+ return NULL;
+ }
+
+ return pyg_value_as_pyobject (pyg_boxed_get(pygvalue, GValue),
+ /*copy_boxed=*/ TRUE);
+}
+
+PyObject *
+pyg__gvalue_get_type(PyObject *module, PyObject *pygvalue)
+{
+ GValue *value;
+ GType type;
+
+ if (!pyg_boxed_check (pygvalue, G_TYPE_VALUE)) {
+ PyErr_SetString (PyExc_TypeError, "Expected GValue argument.");
+ return NULL;
+ }
+
+ value = pyg_boxed_get (pygvalue, GValue);
+ type = G_VALUE_TYPE (value);
+ return pyg_type_wrapper_new (type);
+}
+
+PyObject *
+pyg__gvalue_set(PyObject *module, PyObject *args)
+{
+ PyObject *pygvalue;
+ PyObject *pyobject;
+
+ if (!PyArg_ParseTuple (args, "OO:_gi._gvalue_set",
+ &pygvalue, &pyobject))
+ return NULL;
+
+ if (!pyg_boxed_check (pygvalue, G_TYPE_VALUE)) {
+ PyErr_SetString (PyExc_TypeError, "Expected GValue argument.");
+ return NULL;
+ }
+
+ if (pyg_value_from_pyobject_with_error (pyg_boxed_get (pygvalue, GValue),
+ pyobject) == -1)
+ return NULL;
+
+ Py_RETURN_NONE;
+}