1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
3 * Copyright (c) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 #include "pygi-private.h"
25 #include "pygi-value.h"
26 #include "pygparamspec.h"
28 #include <girepository.h>
30 static GIPropertyInfo *
31 lookup_property_from_object_info (GIObjectInfo *info, const gchar *attr_name)
36 n_infos = g_object_info_get_n_properties (info);
37 for (i = 0; i < n_infos; i++) {
38 GIPropertyInfo *property_info;
40 property_info = g_object_info_get_property (info, i);
41 g_assert (info != NULL);
43 if (strcmp (attr_name, g_base_info_get_name (property_info)) == 0) {
47 g_base_info_unref (property_info);
53 static GIPropertyInfo *
54 lookup_property_from_interface_info (GIInterfaceInfo *info,
55 const gchar *attr_name)
60 n_infos = g_interface_info_get_n_properties (info);
61 for (i = 0; i < n_infos; i++) {
62 GIPropertyInfo *property_info;
64 property_info = g_interface_info_get_property (info, i);
65 g_assert (info != NULL);
67 if (strcmp (attr_name, g_base_info_get_name (property_info)) == 0) {
71 g_base_info_unref (property_info);
77 static GIPropertyInfo *
78 _pygi_lookup_property_from_g_type (GType g_type, const gchar *attr_name)
80 GIPropertyInfo *ret = NULL;
81 GIRepository *repository;
84 repository = g_irepository_get_default();
85 info = g_irepository_find_by_gtype (repository, g_type);
89 if (GI_IS_OBJECT_INFO (info))
90 ret = lookup_property_from_object_info ((GIObjectInfo *) info,
92 else if (GI_IS_INTERFACE_INFO (info))
93 ret = lookup_property_from_interface_info ((GIInterfaceInfo *) info,
96 g_base_info_unref (info);
101 pygi_call_do_get_property (PyObject *instance, GParamSpec *pspec)
106 py_pspec = pyg_param_spec_new (pspec);
107 retval = PyObject_CallMethod (instance, "do_get_property", "O", py_pspec);
108 if (retval == NULL) {
112 Py_DECREF (py_pspec);
121 pygi_get_property_value (PyGObject *instance, GParamSpec *pspec)
123 GIPropertyInfo *property_info = NULL;
124 GValue value = { 0, };
125 PyObject *py_value = NULL;
128 if (!(pspec->flags & G_PARAM_READABLE)) {
129 PyErr_Format(PyExc_TypeError, "property %s is not readable",
130 g_param_spec_get_name (pspec));
134 /* Fast path which calls the Python getter implementation directly.
135 * See: https://bugzilla.gnome.org/show_bug.cgi?id=723872 */
136 if (pyg_gtype_is_custom (pspec->owner_type)) {
137 return pygi_call_do_get_property ((PyObject *)instance, pspec);
140 Py_BEGIN_ALLOW_THREADS;
141 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
142 g_object_get_property (instance->obj, pspec->name, &value);
143 fundamental = G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (&value));
144 Py_END_ALLOW_THREADS;
147 /* Fast path basic types which don't need GI type info. */
148 py_value = pygi_value_to_py_basic_type (&value, fundamental);
153 /* Attempt to marshal through GI.
154 * The owner_type of the pspec gives us the exact type that introduced the
155 * property, even if it is a parent class of the instance in question. */
156 property_info = _pygi_lookup_property_from_g_type (pspec->owner_type, pspec->name);
158 GITypeInfo *type_info = NULL;
159 gboolean free_array = FALSE;
160 GIArgument arg = { 0, };
162 type_info = g_property_info_get_type (property_info);
163 arg = _pygi_argument_from_g_value (&value, type_info);
165 /* Arrays are special cased, see note in _pygi_argument_to_array. */
166 if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_ARRAY) {
167 arg.v_pointer = _pygi_argument_to_array (&arg, NULL, NULL, NULL,
168 type_info, &free_array);
171 py_value = _pygi_argument_to_object (&arg, type_info, GI_TRANSFER_NOTHING);
174 g_array_free (arg.v_pointer, FALSE);
177 g_base_info_unref (type_info);
178 g_base_info_unref (property_info);
181 /* Fallback to GValue marshalling. */
182 if (py_value == NULL) {
183 py_value = pyg_param_gvalue_as_pyobject (&value, TRUE, pspec);
187 g_value_unset (&value);
192 pygi_get_property_value_by_name (PyGObject *self, gchar *param_name)
196 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS(self->obj),
199 PyErr_Format (PyExc_TypeError,
200 "object of type `%s' does not have property `%s'",
201 g_type_name (G_OBJECT_TYPE (self->obj)), param_name);
205 return pygi_get_property_value (self, pspec);
209 pygi_set_property_value (PyGObject *instance,
213 GIPropertyInfo *property_info = NULL;
214 GITypeInfo *type_info = NULL;
217 GValue value = { 0, };
218 GIArgument arg = { 0, };
221 /* The owner_type of the pspec gives us the exact type that introduced the
222 * property, even if it is a parent class of the instance in question. */
223 property_info = _pygi_lookup_property_from_g_type (pspec->owner_type,
225 if (property_info == NULL)
228 if (! (pspec->flags & G_PARAM_WRITABLE))
231 type_info = g_property_info_get_type (property_info);
232 transfer = g_property_info_get_ownership_transfer (property_info);
233 arg = _pygi_argument_from_object (py_value, type_info, transfer);
235 if (PyErr_Occurred())
238 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
240 /* FIXME: Lots of types still unhandled */
241 type_tag = g_type_info_get_tag (type_info);
243 case GI_TYPE_TAG_INTERFACE:
246 GIInfoType info_type;
249 info = g_type_info_get_interface (type_info);
250 type = g_registered_type_info_get_g_type (info);
251 info_type = g_base_info_get_type (info);
253 g_base_info_unref (info);
256 case GI_INFO_TYPE_ENUM:
257 g_value_set_enum (&value, arg.v_int);
259 case GI_INFO_TYPE_INTERFACE:
260 case GI_INFO_TYPE_OBJECT:
261 g_value_set_object (&value, arg.v_pointer);
263 case GI_INFO_TYPE_BOXED:
264 case GI_INFO_TYPE_STRUCT:
265 case GI_INFO_TYPE_UNION:
266 if (g_type_is_a (type, G_TYPE_BOXED)) {
267 g_value_set_boxed (&value, arg.v_pointer);
268 } else if (g_type_is_a (type, G_TYPE_VARIANT)) {
269 g_value_set_variant (&value, arg.v_pointer);
271 PyErr_Format (PyExc_NotImplementedError,
272 "Setting properties of type '%s' is not implemented",
278 PyErr_Format (PyExc_NotImplementedError,
279 "Setting properties of type '%s' is not implemented",
285 case GI_TYPE_TAG_BOOLEAN:
286 g_value_set_boolean (&value, arg.v_boolean);
288 case GI_TYPE_TAG_INT8:
289 g_value_set_schar (&value, arg.v_int8);
291 case GI_TYPE_TAG_INT16:
292 case GI_TYPE_TAG_INT32:
293 if (G_VALUE_HOLDS_LONG (&value))
294 g_value_set_long (&value, arg.v_long);
296 g_value_set_int (&value, arg.v_int);
298 case GI_TYPE_TAG_INT64:
299 if (G_VALUE_HOLDS_LONG (&value))
300 g_value_set_long (&value, arg.v_long);
302 g_value_set_int64 (&value, arg.v_int64);
304 case GI_TYPE_TAG_UINT8:
305 g_value_set_uchar (&value, arg.v_uint8);
307 case GI_TYPE_TAG_UINT16:
308 case GI_TYPE_TAG_UINT32:
309 if (G_VALUE_HOLDS_ULONG (&value))
310 g_value_set_ulong (&value, arg.v_ulong);
312 g_value_set_uint (&value, arg.v_uint);
314 case GI_TYPE_TAG_UINT64:
315 if (G_VALUE_HOLDS_ULONG (&value))
316 g_value_set_ulong (&value, arg.v_ulong);
318 g_value_set_uint64 (&value, arg.v_uint64);
320 case GI_TYPE_TAG_FLOAT:
321 g_value_set_float (&value, arg.v_float);
323 case GI_TYPE_TAG_DOUBLE:
324 g_value_set_double (&value, arg.v_double);
326 case GI_TYPE_TAG_GTYPE:
327 g_value_set_gtype (&value, arg.v_size);
329 case GI_TYPE_TAG_UTF8:
330 case GI_TYPE_TAG_FILENAME:
331 g_value_set_string (&value, arg.v_string);
333 case GI_TYPE_TAG_GHASH:
334 g_value_set_boxed (&value, arg.v_pointer);
336 case GI_TYPE_TAG_GLIST:
337 if (G_VALUE_HOLDS_BOXED(&value))
338 g_value_set_boxed (&value, arg.v_pointer);
340 g_value_set_pointer (&value, arg.v_pointer);
342 case GI_TYPE_TAG_ARRAY:
344 /* This is assumes GI_TYPE_TAG_ARRAY is always a GStrv
345 * https://bugzilla.gnome.org/show_bug.cgi?id=688232
347 GArray *arg_items = (GArray*) arg.v_pointer;
351 if (arg_items == NULL)
354 strings = g_new0 (char*, arg_items->len + 1);
355 for (i = 0; i < arg_items->len; ++i) {
356 strings[i] = g_array_index (arg_items, GIArgument, i).v_string;
358 strings[arg_items->len] = NULL;
359 g_value_take_boxed (&value, strings);
360 g_array_free (arg_items, TRUE);
364 PyErr_Format (PyExc_NotImplementedError,
365 "Setting properties of type %s is not implemented",
366 g_type_tag_to_string (g_type_info_get_tag (type_info)));
370 g_object_set_property (instance->obj, pspec->name, &value);
371 g_value_unset (&value);
376 if (property_info != NULL)
377 g_base_info_unref (property_info);
378 if (type_info != NULL)
379 g_base_info_unref (type_info);