/* -*- 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 .
*/
#include
#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;
}