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-property.h"
25 #include "pygi-value.h"
26 #include "pygi-argument.h"
27 #include "pygparamspec.h"
28 #include "pygi-type.h"
30 #include <girepository.h>
32 static GIPropertyInfo
*
33 lookup_property_from_object_info (GIObjectInfo
*info
, const gchar
*attr_name
)
38 n_infos
= g_object_info_get_n_properties (info
);
39 for (i
= 0; i
< n_infos
; i
++) {
40 GIPropertyInfo
*property_info
;
42 property_info
= g_object_info_get_property (info
, i
);
43 g_assert (info
!= NULL
);
45 if (strcmp (attr_name
, g_base_info_get_name (property_info
)) == 0) {
49 g_base_info_unref (property_info
);
55 static GIPropertyInfo
*
56 lookup_property_from_interface_info (GIInterfaceInfo
*info
,
57 const gchar
*attr_name
)
62 n_infos
= g_interface_info_get_n_properties (info
);
63 for (i
= 0; i
< n_infos
; i
++) {
64 GIPropertyInfo
*property_info
;
66 property_info
= g_interface_info_get_property (info
, i
);
67 g_assert (info
!= NULL
);
69 if (strcmp (attr_name
, g_base_info_get_name (property_info
)) == 0) {
73 g_base_info_unref (property_info
);
79 static GIPropertyInfo
*
80 _pygi_lookup_property_from_g_type (GType g_type
, const gchar
*attr_name
)
82 GIPropertyInfo
*ret
= NULL
;
83 GIRepository
*repository
;
86 repository
= g_irepository_get_default();
87 info
= g_irepository_find_by_gtype (repository
, g_type
);
91 if (GI_IS_OBJECT_INFO (info
))
92 ret
= lookup_property_from_object_info ((GIObjectInfo
*) info
,
94 else if (GI_IS_INTERFACE_INFO (info
))
95 ret
= lookup_property_from_interface_info ((GIInterfaceInfo
*) info
,
98 g_base_info_unref (info
);
103 pygi_call_do_get_property (PyObject
*instance
, GParamSpec
*pspec
)
108 py_pspec
= pyg_param_spec_new (pspec
);
109 retval
= PyObject_CallMethod (instance
, "do_get_property", "O", py_pspec
);
110 Py_DECREF (py_pspec
);
115 pygi_get_property_value (PyGObject
*instance
, GParamSpec
*pspec
)
117 GIPropertyInfo
*property_info
= NULL
;
118 GValue value
= { 0, };
119 PyObject
*py_value
= NULL
;
123 if (!(pspec
->flags
& G_PARAM_READABLE
)) {
124 PyErr_Format(PyExc_TypeError
, "property %s is not readable",
125 g_param_spec_get_name (pspec
));
129 /* Fast path which calls the Python getter implementation directly.
130 * See: https://bugzilla.gnome.org/show_bug.cgi?id=723872 */
131 if (pyg_gtype_is_custom (pspec
->owner_type
)) {
132 return pygi_call_do_get_property ((PyObject
*)instance
, pspec
);
135 Py_BEGIN_ALLOW_THREADS
;
136 g_value_init (&value
, G_PARAM_SPEC_VALUE_TYPE (pspec
));
137 g_object_get_property (instance
->obj
, pspec
->name
, &value
);
138 fundamental
= G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (&value
));
139 Py_END_ALLOW_THREADS
;
142 /* Fast path basic types which don't need GI type info. */
143 py_value
= pygi_value_to_py_basic_type (&value
, fundamental
, &handled
);
148 /* Attempt to marshal through GI.
149 * The owner_type of the pspec gives us the exact type that introduced the
150 * property, even if it is a parent class of the instance in question. */
151 property_info
= _pygi_lookup_property_from_g_type (pspec
->owner_type
, pspec
->name
);
153 GITypeInfo
*type_info
= NULL
;
154 gboolean free_array
= FALSE
;
155 GIArgument arg
= { 0, };
156 GITransfer transfer
= GI_TRANSFER_NOTHING
;
158 type_info
= g_property_info_get_type (property_info
);
159 arg
= _pygi_argument_from_g_value (&value
, type_info
);
161 /* Arrays are special cased, see note in _pygi_argument_to_array. */
162 if (g_type_info_get_tag (type_info
) == GI_TYPE_TAG_ARRAY
) {
163 arg
.v_pointer
= _pygi_argument_to_array (&arg
, NULL
, NULL
, NULL
,
164 type_info
, &free_array
);
165 } else if (g_type_is_a (pspec
->value_type
, G_TYPE_BOXED
)) {
166 arg
.v_pointer
= g_value_dup_boxed (&value
);
167 transfer
= GI_TRANSFER_EVERYTHING
;
170 py_value
= _pygi_argument_to_object (&arg
, type_info
, transfer
);
173 g_array_free (arg
.v_pointer
, FALSE
);
176 g_base_info_unref (type_info
);
177 g_base_info_unref (property_info
);
180 /* Fallback to GValue marshalling. */
181 if (py_value
== NULL
) {
182 py_value
= pyg_param_gvalue_as_pyobject (&value
, TRUE
, pspec
);
186 g_value_unset (&value
);
191 pygi_get_property_value_by_name (PyGObject
*self
, gchar
*param_name
)
195 pspec
= g_object_class_find_property (G_OBJECT_GET_CLASS(self
->obj
),
198 PyErr_Format (PyExc_TypeError
,
199 "object of type `%s' does not have property `%s'",
200 g_type_name (G_OBJECT_TYPE (self
->obj
)), param_name
);
204 return pygi_get_property_value (self
, pspec
);
208 pygi_set_property_value (PyGObject
*instance
,
212 GIPropertyInfo
*property_info
= NULL
;
213 GITypeInfo
*type_info
= NULL
;
216 GValue value
= { 0, };
217 GIArgument arg
= { 0, };
220 /* The owner_type of the pspec gives us the exact type that introduced the
221 * property, even if it is a parent class of the instance in question. */
222 property_info
= _pygi_lookup_property_from_g_type (pspec
->owner_type
,
224 if (property_info
== NULL
)
227 if (! (pspec
->flags
& G_PARAM_WRITABLE
))
230 type_info
= g_property_info_get_type (property_info
);
231 transfer
= g_property_info_get_ownership_transfer (property_info
);
232 arg
= _pygi_argument_from_object (py_value
, type_info
, transfer
);
234 if (PyErr_Occurred())
237 g_value_init (&value
, G_PARAM_SPEC_VALUE_TYPE (pspec
));
239 /* FIXME: Lots of types still unhandled */
240 type_tag
= g_type_info_get_tag (type_info
);
242 case GI_TYPE_TAG_INTERFACE
:
245 GIInfoType info_type
;
248 info
= g_type_info_get_interface (type_info
);
249 type
= g_registered_type_info_get_g_type (info
);
250 info_type
= g_base_info_get_type (info
);
252 g_base_info_unref (info
);
255 case GI_INFO_TYPE_ENUM
:
256 g_value_set_enum (&value
, arg
.v_int
);
258 case GI_INFO_TYPE_FLAGS
:
259 g_value_set_flags (&value
, arg
.v_uint
);
261 case GI_INFO_TYPE_INTERFACE
:
262 case GI_INFO_TYPE_OBJECT
:
263 g_value_set_object (&value
, arg
.v_pointer
);
265 case GI_INFO_TYPE_BOXED
:
266 case GI_INFO_TYPE_STRUCT
:
267 case GI_INFO_TYPE_UNION
:
268 if (g_type_is_a (type
, G_TYPE_BOXED
)) {
269 g_value_set_boxed (&value
, arg
.v_pointer
);
270 } else if (g_type_is_a (type
, G_TYPE_VARIANT
)) {
271 g_value_set_variant (&value
, arg
.v_pointer
);
273 PyErr_Format (PyExc_NotImplementedError
,
274 "Setting properties of type '%s' is not implemented",
280 PyErr_Format (PyExc_NotImplementedError
,
281 "Setting properties of type '%s' is not implemented",
287 case GI_TYPE_TAG_BOOLEAN
:
288 g_value_set_boolean (&value
, arg
.v_boolean
);
290 case GI_TYPE_TAG_INT8
:
291 g_value_set_schar (&value
, arg
.v_int8
);
293 case GI_TYPE_TAG_INT16
:
294 case GI_TYPE_TAG_INT32
:
295 if (G_VALUE_HOLDS_LONG (&value
))
296 g_value_set_long (&value
, arg
.v_long
);
298 g_value_set_int (&value
, arg
.v_int
);
300 case GI_TYPE_TAG_INT64
:
301 if (G_VALUE_HOLDS_LONG (&value
))
302 g_value_set_long (&value
, arg
.v_long
);
304 g_value_set_int64 (&value
, arg
.v_int64
);
306 case GI_TYPE_TAG_UINT8
:
307 g_value_set_uchar (&value
, arg
.v_uint8
);
309 case GI_TYPE_TAG_UINT16
:
310 case GI_TYPE_TAG_UINT32
:
311 if (G_VALUE_HOLDS_ULONG (&value
))
312 g_value_set_ulong (&value
, arg
.v_ulong
);
314 g_value_set_uint (&value
, arg
.v_uint
);
316 case GI_TYPE_TAG_UINT64
:
317 if (G_VALUE_HOLDS_ULONG (&value
))
318 g_value_set_ulong (&value
, arg
.v_ulong
);
320 g_value_set_uint64 (&value
, arg
.v_uint64
);
322 case GI_TYPE_TAG_FLOAT
:
323 g_value_set_float (&value
, arg
.v_float
);
325 case GI_TYPE_TAG_DOUBLE
:
326 g_value_set_double (&value
, arg
.v_double
);
328 case GI_TYPE_TAG_GTYPE
:
329 g_value_set_gtype (&value
, arg
.v_size
);
331 case GI_TYPE_TAG_UTF8
:
332 case GI_TYPE_TAG_FILENAME
:
333 g_value_set_string (&value
, arg
.v_string
);
335 case GI_TYPE_TAG_GHASH
:
336 g_value_set_boxed (&value
, arg
.v_pointer
);
338 case GI_TYPE_TAG_GLIST
:
339 if (G_VALUE_HOLDS_BOXED(&value
))
340 g_value_set_boxed (&value
, arg
.v_pointer
);
342 g_value_set_pointer (&value
, arg
.v_pointer
);
344 case GI_TYPE_TAG_ARRAY
:
346 /* This is assumes GI_TYPE_TAG_ARRAY is always a GStrv
347 * https://bugzilla.gnome.org/show_bug.cgi?id=688232
349 GArray
*arg_items
= (GArray
*) arg
.v_pointer
;
353 if (arg_items
== NULL
)
356 strings
= g_new0 (char*, arg_items
->len
+ 1);
357 for (i
= 0; i
< arg_items
->len
; ++i
) {
358 strings
[i
] = g_array_index (arg_items
, GIArgument
, i
).v_string
;
360 strings
[arg_items
->len
] = NULL
;
361 g_value_take_boxed (&value
, strings
);
362 g_array_free (arg_items
, TRUE
);
366 PyErr_Format (PyExc_NotImplementedError
,
367 "Setting properties of type %s is not implemented",
368 g_type_tag_to_string (g_type_info_get_tag (type_info
)));
372 g_object_set_property (instance
->obj
, pspec
->name
, &value
);
373 g_value_unset (&value
);
378 if (property_info
!= NULL
)
379 g_base_info_unref (property_info
);
380 if (type_info
!= NULL
)
381 g_base_info_unref (type_info
);