functions: revert the function init order to make pylint happy again. See #217
[pygobject.git] / gi / pygi-property.c
blob595167bb24a5f841f892b3b0436209f36c954261
1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /*
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
21 * IN THE SOFTWARE.
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)
35 gssize n_infos;
36 gint i;
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) {
46 return property_info;
49 g_base_info_unref (property_info);
52 return NULL;
55 static GIPropertyInfo *
56 lookup_property_from_interface_info (GIInterfaceInfo *info,
57 const gchar *attr_name)
59 gssize n_infos;
60 gint i;
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) {
70 return property_info;
73 g_base_info_unref (property_info);
76 return NULL;
79 static GIPropertyInfo *
80 _pygi_lookup_property_from_g_type (GType g_type, const gchar *attr_name)
82 GIPropertyInfo *ret = NULL;
83 GIRepository *repository;
84 GIBaseInfo *info;
86 repository = g_irepository_get_default();
87 info = g_irepository_find_by_gtype (repository, g_type);
88 if (info == NULL)
89 return NULL;
91 if (GI_IS_OBJECT_INFO (info))
92 ret = lookup_property_from_object_info ((GIObjectInfo *) info,
93 attr_name);
94 else if (GI_IS_INTERFACE_INFO (info))
95 ret = lookup_property_from_interface_info ((GIInterfaceInfo *) info,
96 attr_name);
98 g_base_info_unref (info);
99 return ret;
102 PyObject *
103 pygi_call_do_get_property (PyObject *instance, GParamSpec *pspec)
105 PyObject *py_pspec;
106 PyObject *retval;
108 py_pspec = pyg_param_spec_new (pspec);
109 retval = PyObject_CallMethod (instance, "do_get_property", "O", py_pspec);
110 Py_DECREF (py_pspec);
111 return retval;
114 PyObject *
115 pygi_get_property_value (PyGObject *instance, GParamSpec *pspec)
117 GIPropertyInfo *property_info = NULL;
118 GValue value = { 0, };
119 PyObject *py_value = NULL;
120 GType fundamental;
121 gboolean handled;
123 if (!(pspec->flags & G_PARAM_READABLE)) {
124 PyErr_Format(PyExc_TypeError, "property %s is not readable",
125 g_param_spec_get_name (pspec));
126 return NULL;
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);
144 if (handled) {
145 goto out;
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);
152 if (property_info) {
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);
172 if (free_array) {
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);
185 out:
186 g_value_unset (&value);
187 return py_value;
190 PyObject *
191 pygi_get_property_value_by_name (PyGObject *self, gchar *param_name)
193 GParamSpec *pspec;
195 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS(self->obj),
196 param_name);
197 if (!pspec) {
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);
201 return NULL;
204 return pygi_get_property_value (self, pspec);
207 gint
208 pygi_set_property_value (PyGObject *instance,
209 GParamSpec *pspec,
210 PyObject *py_value)
212 GIPropertyInfo *property_info = NULL;
213 GITypeInfo *type_info = NULL;
214 GITypeTag type_tag;
215 GITransfer transfer;
216 GValue value = { 0, };
217 GIArgument arg = { 0, };
218 gint ret_value = -1;
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,
223 pspec->name);
224 if (property_info == NULL)
225 goto out;
227 if (! (pspec->flags & G_PARAM_WRITABLE))
228 goto out;
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())
235 goto out;
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);
241 switch (type_tag) {
242 case GI_TYPE_TAG_INTERFACE:
244 GIBaseInfo *info;
245 GIInfoType info_type;
246 GType 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);
254 switch (info_type) {
255 case GI_INFO_TYPE_ENUM:
256 g_value_set_enum (&value, arg.v_int);
257 break;
258 case GI_INFO_TYPE_FLAGS:
259 g_value_set_flags (&value, arg.v_uint);
260 break;
261 case GI_INFO_TYPE_INTERFACE:
262 case GI_INFO_TYPE_OBJECT:
263 g_value_set_object (&value, arg.v_pointer);
264 break;
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);
272 } else {
273 PyErr_Format (PyExc_NotImplementedError,
274 "Setting properties of type '%s' is not implemented",
275 g_type_name (type));
276 goto out;
278 break;
279 default:
280 PyErr_Format (PyExc_NotImplementedError,
281 "Setting properties of type '%s' is not implemented",
282 g_type_name (type));
283 goto out;
285 break;
287 case GI_TYPE_TAG_BOOLEAN:
288 g_value_set_boolean (&value, arg.v_boolean);
289 break;
290 case GI_TYPE_TAG_INT8:
291 g_value_set_schar (&value, arg.v_int8);
292 break;
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);
297 else
298 g_value_set_int (&value, arg.v_int);
299 break;
300 case GI_TYPE_TAG_INT64:
301 if (G_VALUE_HOLDS_LONG (&value))
302 g_value_set_long (&value, arg.v_long);
303 else
304 g_value_set_int64 (&value, arg.v_int64);
305 break;
306 case GI_TYPE_TAG_UINT8:
307 g_value_set_uchar (&value, arg.v_uint8);
308 break;
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);
313 else
314 g_value_set_uint (&value, arg.v_uint);
315 break;
316 case GI_TYPE_TAG_UINT64:
317 if (G_VALUE_HOLDS_ULONG (&value))
318 g_value_set_ulong (&value, arg.v_ulong);
319 else
320 g_value_set_uint64 (&value, arg.v_uint64);
321 break;
322 case GI_TYPE_TAG_FLOAT:
323 g_value_set_float (&value, arg.v_float);
324 break;
325 case GI_TYPE_TAG_DOUBLE:
326 g_value_set_double (&value, arg.v_double);
327 break;
328 case GI_TYPE_TAG_GTYPE:
329 g_value_set_gtype (&value, arg.v_size);
330 break;
331 case GI_TYPE_TAG_UTF8:
332 case GI_TYPE_TAG_FILENAME:
333 g_value_set_string (&value, arg.v_string);
334 break;
335 case GI_TYPE_TAG_GHASH:
336 g_value_set_boxed (&value, arg.v_pointer);
337 break;
338 case GI_TYPE_TAG_GLIST:
339 if (G_VALUE_HOLDS_BOXED(&value))
340 g_value_set_boxed (&value, arg.v_pointer);
341 else
342 g_value_set_pointer (&value, arg.v_pointer);
343 break;
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;
350 gchar** strings;
351 guint i;
353 if (arg_items == NULL)
354 goto out;
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);
363 break;
365 default:
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)));
369 goto out;
372 g_object_set_property (instance->obj, pspec->name, &value);
373 g_value_unset (&value);
375 ret_value = 0;
377 out:
378 if (property_info != NULL)
379 g_base_info_unref (property_info);
380 if (type_info != NULL)
381 g_base_info_unref (type_info);
383 return ret_value;