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"
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 if (retval
== NULL
) {
114 Py_DECREF (py_pspec
);
123 pygi_get_property_value (PyGObject
*instance
, GParamSpec
*pspec
)
125 GIPropertyInfo
*property_info
= NULL
;
126 GValue value
= { 0, };
127 PyObject
*py_value
= NULL
;
130 if (!(pspec
->flags
& G_PARAM_READABLE
)) {
131 PyErr_Format(PyExc_TypeError
, "property %s is not readable",
132 g_param_spec_get_name (pspec
));
136 /* Fast path which calls the Python getter implementation directly.
137 * See: https://bugzilla.gnome.org/show_bug.cgi?id=723872 */
138 if (pyg_gtype_is_custom (pspec
->owner_type
)) {
139 return pygi_call_do_get_property ((PyObject
*)instance
, pspec
);
142 Py_BEGIN_ALLOW_THREADS
;
143 g_value_init (&value
, G_PARAM_SPEC_VALUE_TYPE (pspec
));
144 g_object_get_property (instance
->obj
, pspec
->name
, &value
);
145 fundamental
= G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (&value
));
146 Py_END_ALLOW_THREADS
;
149 /* Fast path basic types which don't need GI type info. */
150 py_value
= pygi_value_to_py_basic_type (&value
, fundamental
);
155 /* Attempt to marshal through GI.
156 * The owner_type of the pspec gives us the exact type that introduced the
157 * property, even if it is a parent class of the instance in question. */
158 property_info
= _pygi_lookup_property_from_g_type (pspec
->owner_type
, pspec
->name
);
160 GITypeInfo
*type_info
= NULL
;
161 gboolean free_array
= FALSE
;
162 GIArgument arg
= { 0, };
164 type_info
= g_property_info_get_type (property_info
);
165 arg
= _pygi_argument_from_g_value (&value
, type_info
);
167 /* Arrays are special cased, see note in _pygi_argument_to_array. */
168 if (g_type_info_get_tag (type_info
) == GI_TYPE_TAG_ARRAY
) {
169 arg
.v_pointer
= _pygi_argument_to_array (&arg
, NULL
, NULL
, NULL
,
170 type_info
, &free_array
);
173 py_value
= _pygi_argument_to_object (&arg
, type_info
, GI_TRANSFER_NOTHING
);
176 g_array_free (arg
.v_pointer
, FALSE
);
179 g_base_info_unref (type_info
);
180 g_base_info_unref (property_info
);
183 /* Fallback to GValue marshalling. */
184 if (py_value
== NULL
) {
185 py_value
= pyg_param_gvalue_as_pyobject (&value
, TRUE
, pspec
);
189 g_value_unset (&value
);
194 pygi_get_property_value_by_name (PyGObject
*self
, gchar
*param_name
)
198 pspec
= g_object_class_find_property (G_OBJECT_GET_CLASS(self
->obj
),
201 PyErr_Format (PyExc_TypeError
,
202 "object of type `%s' does not have property `%s'",
203 g_type_name (G_OBJECT_TYPE (self
->obj
)), param_name
);
207 return pygi_get_property_value (self
, pspec
);
211 pygi_set_property_value (PyGObject
*instance
,
215 GIPropertyInfo
*property_info
= NULL
;
216 GITypeInfo
*type_info
= NULL
;
219 GValue value
= { 0, };
220 GIArgument arg
= { 0, };
223 /* The owner_type of the pspec gives us the exact type that introduced the
224 * property, even if it is a parent class of the instance in question. */
225 property_info
= _pygi_lookup_property_from_g_type (pspec
->owner_type
,
227 if (property_info
== NULL
)
230 if (! (pspec
->flags
& G_PARAM_WRITABLE
))
233 type_info
= g_property_info_get_type (property_info
);
234 transfer
= g_property_info_get_ownership_transfer (property_info
);
235 arg
= _pygi_argument_from_object (py_value
, type_info
, transfer
);
237 if (PyErr_Occurred())
240 g_value_init (&value
, G_PARAM_SPEC_VALUE_TYPE (pspec
));
242 /* FIXME: Lots of types still unhandled */
243 type_tag
= g_type_info_get_tag (type_info
);
245 case GI_TYPE_TAG_INTERFACE
:
248 GIInfoType info_type
;
251 info
= g_type_info_get_interface (type_info
);
252 type
= g_registered_type_info_get_g_type (info
);
253 info_type
= g_base_info_get_type (info
);
255 g_base_info_unref (info
);
258 case GI_INFO_TYPE_ENUM
:
259 g_value_set_enum (&value
, arg
.v_int
);
261 case GI_INFO_TYPE_FLAGS
:
262 g_value_set_flags (&value
, arg
.v_uint
);
264 case GI_INFO_TYPE_INTERFACE
:
265 case GI_INFO_TYPE_OBJECT
:
266 g_value_set_object (&value
, arg
.v_pointer
);
268 case GI_INFO_TYPE_BOXED
:
269 case GI_INFO_TYPE_STRUCT
:
270 case GI_INFO_TYPE_UNION
:
271 if (g_type_is_a (type
, G_TYPE_BOXED
)) {
272 g_value_set_boxed (&value
, arg
.v_pointer
);
273 } else if (g_type_is_a (type
, G_TYPE_VARIANT
)) {
274 g_value_set_variant (&value
, arg
.v_pointer
);
276 PyErr_Format (PyExc_NotImplementedError
,
277 "Setting properties of type '%s' is not implemented",
283 PyErr_Format (PyExc_NotImplementedError
,
284 "Setting properties of type '%s' is not implemented",
290 case GI_TYPE_TAG_BOOLEAN
:
291 g_value_set_boolean (&value
, arg
.v_boolean
);
293 case GI_TYPE_TAG_INT8
:
294 g_value_set_schar (&value
, arg
.v_int8
);
296 case GI_TYPE_TAG_INT16
:
297 case GI_TYPE_TAG_INT32
:
298 if (G_VALUE_HOLDS_LONG (&value
))
299 g_value_set_long (&value
, arg
.v_long
);
301 g_value_set_int (&value
, arg
.v_int
);
303 case GI_TYPE_TAG_INT64
:
304 if (G_VALUE_HOLDS_LONG (&value
))
305 g_value_set_long (&value
, arg
.v_long
);
307 g_value_set_int64 (&value
, arg
.v_int64
);
309 case GI_TYPE_TAG_UINT8
:
310 g_value_set_uchar (&value
, arg
.v_uint8
);
312 case GI_TYPE_TAG_UINT16
:
313 case GI_TYPE_TAG_UINT32
:
314 if (G_VALUE_HOLDS_ULONG (&value
))
315 g_value_set_ulong (&value
, arg
.v_ulong
);
317 g_value_set_uint (&value
, arg
.v_uint
);
319 case GI_TYPE_TAG_UINT64
:
320 if (G_VALUE_HOLDS_ULONG (&value
))
321 g_value_set_ulong (&value
, arg
.v_ulong
);
323 g_value_set_uint64 (&value
, arg
.v_uint64
);
325 case GI_TYPE_TAG_FLOAT
:
326 g_value_set_float (&value
, arg
.v_float
);
328 case GI_TYPE_TAG_DOUBLE
:
329 g_value_set_double (&value
, arg
.v_double
);
331 case GI_TYPE_TAG_GTYPE
:
332 g_value_set_gtype (&value
, arg
.v_size
);
334 case GI_TYPE_TAG_UTF8
:
335 case GI_TYPE_TAG_FILENAME
:
336 g_value_set_string (&value
, arg
.v_string
);
338 case GI_TYPE_TAG_GHASH
:
339 g_value_set_boxed (&value
, arg
.v_pointer
);
341 case GI_TYPE_TAG_GLIST
:
342 if (G_VALUE_HOLDS_BOXED(&value
))
343 g_value_set_boxed (&value
, arg
.v_pointer
);
345 g_value_set_pointer (&value
, arg
.v_pointer
);
347 case GI_TYPE_TAG_ARRAY
:
349 /* This is assumes GI_TYPE_TAG_ARRAY is always a GStrv
350 * https://bugzilla.gnome.org/show_bug.cgi?id=688232
352 GArray
*arg_items
= (GArray
*) arg
.v_pointer
;
356 if (arg_items
== NULL
)
359 strings
= g_new0 (char*, arg_items
->len
+ 1);
360 for (i
= 0; i
< arg_items
->len
; ++i
) {
361 strings
[i
] = g_array_index (arg_items
, GIArgument
, i
).v_string
;
363 strings
[arg_items
->len
] = NULL
;
364 g_value_take_boxed (&value
, strings
);
365 g_array_free (arg_items
, TRUE
);
369 PyErr_Format (PyExc_NotImplementedError
,
370 "Setting properties of type %s is not implemented",
371 g_type_tag_to_string (g_type_info_get_tag (type_info
)));
375 g_object_set_property (instance
->obj
, pspec
->name
, &value
);
376 g_value_unset (&value
);
381 if (property_info
!= NULL
)
382 g_base_info_unref (property_info
);
383 if (type_info
!= NULL
)
384 g_base_info_unref (type_info
);