2e32fea183df01734fa3780ce72c2528db41cc80
[platform/upstream/pygobject2.git] / gi / pygi-property.c
1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /*
3  * Copyright (c) 2010  Collabora Ltd. <http://www.collabora.co.uk/>
4  *
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:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
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.
22  */
23
24 #include "pygi-private.h"
25
26 #include <girepository.h>
27
28 static GIPropertyInfo *
29 lookup_property_from_object_info (GIObjectInfo *info, const gchar *attr_name)
30 {
31     gssize n_infos;
32     gssize i;
33
34     n_infos = g_object_info_get_n_properties (info);
35     for (i = 0; i < n_infos; i++) {
36         GIPropertyInfo *property_info;
37
38         property_info = g_object_info_get_property (info, i);
39         g_assert (info != NULL);
40
41         if (strcmp (attr_name, g_base_info_get_name (property_info)) == 0) {
42             return property_info;
43         }
44
45         g_base_info_unref (property_info);
46     }
47
48     return NULL;
49 }
50
51 static GIPropertyInfo *
52 lookup_property_from_interface_info (GIInterfaceInfo *info,
53                                      const gchar *attr_name)
54 {
55     gssize n_infos;
56     gssize i;
57
58     n_infos = g_interface_info_get_n_properties (info);
59     for (i = 0; i < n_infos; i++) {
60         GIPropertyInfo *property_info;
61
62         property_info = g_interface_info_get_property (info, i);
63         g_assert (info != NULL);
64
65         if (strcmp (attr_name, g_base_info_get_name (property_info)) == 0) {
66             return property_info;
67         }
68
69         g_base_info_unref (property_info);
70     }
71
72     return NULL;
73 }
74
75 static GIPropertyInfo *
76 _pygi_lookup_property_from_g_type (GType g_type, const gchar *attr_name)
77 {
78     GIPropertyInfo *ret = NULL;
79     GIRepository *repository;
80     GIBaseInfo *info;
81
82     repository = g_irepository_get_default();
83     info = g_irepository_find_by_gtype (repository, g_type);
84     if (info == NULL)
85        return NULL;
86
87     if (GI_IS_OBJECT_INFO (info))
88         ret = lookup_property_from_object_info ((GIObjectInfo *) info,
89                                                 attr_name);
90     else if (GI_IS_INTERFACE_INFO (info))
91         ret = lookup_property_from_interface_info ((GIInterfaceInfo *) info,
92                                                    attr_name);
93
94     g_base_info_unref (info);
95     return ret;
96 }
97
98 PyObject *
99 pygi_get_property_value_real (PyGObject *instance, GParamSpec *pspec)
100 {
101     GIPropertyInfo *property_info = NULL;
102     GValue value = { 0, };
103     GIArgument arg = { 0, };
104     PyObject *py_value = NULL;
105     GITypeInfo *type_info = NULL;
106     GITransfer transfer;
107
108     /* The owner_type of the pspec gives us the exact type that introduced the
109      * property, even if it is a parent class of the instance in question. */
110     property_info = _pygi_lookup_property_from_g_type (pspec->owner_type, pspec->name);
111
112     if (property_info == NULL)
113         goto out;
114
115     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
116     g_object_get_property (instance->obj, pspec->name, &value);
117
118     type_info = g_property_info_get_type (property_info);
119     transfer = g_property_info_get_ownership_transfer (property_info);
120
121     GITypeTag type_tag = g_type_info_get_tag (type_info);
122     switch (type_tag) {
123         case GI_TYPE_TAG_BOOLEAN:
124             arg.v_boolean = g_value_get_boolean (&value);
125             break;
126         case GI_TYPE_TAG_INT8:
127             arg.v_int8 = g_value_get_schar (&value);
128             break;
129         case GI_TYPE_TAG_INT16:
130         case GI_TYPE_TAG_INT32:
131             if (G_VALUE_HOLDS_LONG (&value))
132                 arg.v_long = g_value_get_long (&value);
133             else
134                 arg.v_int = g_value_get_int (&value);
135             break;
136         case GI_TYPE_TAG_INT64:
137             if (G_VALUE_HOLDS_LONG (&value))
138                 arg.v_long = g_value_get_long (&value);
139             else
140                 arg.v_int64 = g_value_get_int64 (&value);
141             break;
142         case GI_TYPE_TAG_UINT8:
143             arg.v_uint8 = g_value_get_uchar (&value);
144             break;
145         case GI_TYPE_TAG_UINT16:
146         case GI_TYPE_TAG_UINT32:
147             if (G_VALUE_HOLDS_ULONG (&value))
148                 arg.v_ulong = g_value_get_ulong (&value);
149             else
150                 arg.v_uint = g_value_get_uint (&value);
151             break;
152         case GI_TYPE_TAG_UINT64:
153             if (G_VALUE_HOLDS_ULONG (&value))
154                 arg.v_ulong = g_value_get_ulong (&value);
155             else
156                 arg.v_uint64 = g_value_get_uint64 (&value);
157             break;
158         case GI_TYPE_TAG_FLOAT:
159             arg.v_float = g_value_get_float (&value);
160             break;
161         case GI_TYPE_TAG_DOUBLE:
162             arg.v_double = g_value_get_double (&value);
163             break;
164         case GI_TYPE_TAG_GTYPE:
165             arg.v_size = g_value_get_gtype (&value);
166             break;
167         case GI_TYPE_TAG_UTF8:
168         case GI_TYPE_TAG_FILENAME:
169             arg.v_string = g_value_dup_string (&value);
170             break;
171         case GI_TYPE_TAG_INTERFACE:
172         {
173             GIBaseInfo *info;
174             GIInfoType info_type;
175             GType type;
176
177             info = g_type_info_get_interface (type_info);
178             type = g_registered_type_info_get_g_type (info);
179             info_type = g_base_info_get_type (info);
180
181             g_base_info_unref (info);
182
183             switch (info_type) {
184                 case GI_INFO_TYPE_ENUM:
185                     arg.v_int32 = g_value_get_enum (&value);
186                     break;
187                 case GI_INFO_TYPE_INTERFACE:
188                 case GI_INFO_TYPE_OBJECT:
189                     arg.v_pointer = g_value_get_object (&value);
190                     break;
191                 case GI_INFO_TYPE_BOXED:
192                 case GI_INFO_TYPE_STRUCT:
193                 case GI_INFO_TYPE_UNION:
194
195                     if (g_type_is_a (type, G_TYPE_BOXED)) {
196                         arg.v_pointer = g_value_get_boxed (&value);
197                     } else if (g_type_is_a (type, G_TYPE_POINTER)) {
198                         arg.v_pointer = g_value_get_pointer (&value);
199                     } else if (g_type_is_a (type, G_TYPE_VARIANT)) {
200                         arg.v_pointer = g_value_get_variant (&value);
201                     } else {
202                         PyErr_Format (PyExc_NotImplementedError,
203                                       "Retrieving properties of type '%s' is not implemented",
204                                       g_type_name (type));
205                     }
206                     break;
207                 default:
208                     PyErr_Format (PyExc_NotImplementedError,
209                                   "Retrieving properties of type '%s' is not implemented",
210                                   g_type_name (type));
211                     goto out;
212             }
213             break;
214         }
215         case GI_TYPE_TAG_GHASH:
216             arg.v_pointer = g_value_get_boxed (&value);
217             break;
218         case GI_TYPE_TAG_GLIST:
219         case GI_TYPE_TAG_GSLIST:
220             if (G_VALUE_HOLDS_BOXED(&value))
221                 arg.v_pointer = g_value_get_boxed (&value);
222             else
223                 arg.v_pointer = g_value_get_pointer (&value);
224             break;
225         case GI_TYPE_TAG_ARRAY:
226         {
227             gchar** strings;
228             GArray *arg_items;
229             int i;
230
231             strings = g_value_get_boxed (&value);
232             if (strings == NULL)
233                 arg.v_pointer = NULL;
234             else {
235                 arg_items = g_array_sized_new (TRUE, TRUE, sizeof (GIArgument), g_strv_length (strings));
236                 g_array_set_size (arg_items, g_strv_length (strings));
237                 for (i = 0; strings[i] != NULL; ++i) {
238                     g_array_index (arg_items, GIArgument, i).v_string = strings[i];
239                 }
240                 arg.v_pointer = arg_items;
241             }
242             break;
243         }
244         default:
245             PyErr_Format (PyExc_NotImplementedError,
246                           "Retrieving properties of type %s is not implemented",
247                           g_type_tag_to_string (g_type_info_get_tag (type_info)));
248             goto out;
249     }
250
251     py_value = _pygi_argument_to_object (&arg, type_info, transfer);
252
253 out:
254     if (property_info != NULL)
255         g_base_info_unref (property_info);
256     if (type_info != NULL)
257         g_base_info_unref (type_info);
258
259     return py_value;
260 }
261
262 gint
263 pygi_set_property_value_real (PyGObject *instance,
264                               GParamSpec *pspec,
265                               PyObject *py_value)
266 {
267     GIPropertyInfo *property_info = NULL;
268     GITypeInfo *type_info = NULL;
269     GITypeTag type_tag;
270     GITransfer transfer;
271     GValue value = { 0, };
272     GIArgument arg = { 0, };
273     gint ret_value = -1;
274
275     /* The owner_type of the pspec gives us the exact type that introduced the
276      * property, even if it is a parent class of the instance in question. */
277     property_info = _pygi_lookup_property_from_g_type (pspec->owner_type,
278                                                        pspec->name);
279     if (property_info == NULL)
280         goto out;
281
282     if (! (pspec->flags & G_PARAM_WRITABLE))
283         goto out;
284
285     type_info = g_property_info_get_type (property_info);
286     transfer = g_property_info_get_ownership_transfer (property_info);
287     arg = _pygi_argument_from_object (py_value, type_info, transfer);
288
289     if (PyErr_Occurred())
290         goto out;
291
292     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
293
294     // FIXME: Lots of types still unhandled
295     type_tag = g_type_info_get_tag (type_info);
296     switch (type_tag) {
297         case GI_TYPE_TAG_INTERFACE:
298         {
299             GIBaseInfo *info;
300             GIInfoType info_type;
301             GType type;
302
303             info = g_type_info_get_interface (type_info);
304             type = g_registered_type_info_get_g_type (info);
305             info_type = g_base_info_get_type (info);
306
307             g_base_info_unref (info);
308
309             switch (info_type) {
310                 case GI_INFO_TYPE_ENUM:
311                     g_value_set_enum (&value, arg.v_int32);
312                     break;
313                 case GI_INFO_TYPE_INTERFACE:
314                 case GI_INFO_TYPE_OBJECT:
315                     g_value_set_object (&value, arg.v_pointer);
316                     break;
317                 case GI_INFO_TYPE_BOXED:
318                 case GI_INFO_TYPE_STRUCT:
319                 case GI_INFO_TYPE_UNION:
320                     if (g_type_is_a (type, G_TYPE_BOXED)) {
321                         g_value_set_boxed (&value, arg.v_pointer);
322                     } else if (g_type_is_a (type, G_TYPE_VARIANT)) {
323                         g_value_set_variant (&value, arg.v_pointer);
324                     } else {
325                         PyErr_Format (PyExc_NotImplementedError,
326                                       "Setting properties of type '%s' is not implemented",
327                                       g_type_name (type));
328                     }
329                     goto out;
330                 default:
331                     PyErr_Format (PyExc_NotImplementedError,
332                                   "Setting properties of type '%s' is not implemented",
333                                   g_type_name (type));
334                     goto out;
335             }
336             break;
337         }
338         case GI_TYPE_TAG_BOOLEAN:
339             g_value_set_boolean (&value, arg.v_boolean);
340             break;
341         case GI_TYPE_TAG_INT8:
342             g_value_set_schar (&value, arg.v_int8);
343             break;
344         case GI_TYPE_TAG_INT16:
345         case GI_TYPE_TAG_INT32:
346             if (G_VALUE_HOLDS_LONG (&value))
347                 g_value_set_long (&value, arg.v_long);
348             else
349                 g_value_set_int (&value, arg.v_int);
350             break;
351         case GI_TYPE_TAG_INT64:
352             if (G_VALUE_HOLDS_LONG (&value))
353                 g_value_set_long (&value, arg.v_long);
354             else
355                 g_value_set_int64 (&value, arg.v_int64);
356             break;
357         case GI_TYPE_TAG_UINT8:
358             g_value_set_uchar (&value, arg.v_uint8);
359             break;
360         case GI_TYPE_TAG_UINT16:
361         case GI_TYPE_TAG_UINT32:
362             if (G_VALUE_HOLDS_ULONG (&value))
363                 g_value_set_ulong (&value, arg.v_ulong);
364             else
365                 g_value_set_uint (&value, arg.v_uint);
366             break;
367         case GI_TYPE_TAG_UINT64:
368             if (G_VALUE_HOLDS_ULONG (&value))
369                 g_value_set_ulong (&value, arg.v_ulong);
370             else
371                 g_value_set_uint64 (&value, arg.v_uint64);
372             break;
373         case GI_TYPE_TAG_FLOAT:
374             g_value_set_float (&value, arg.v_float);
375             break;
376         case GI_TYPE_TAG_DOUBLE:
377             g_value_set_double (&value, arg.v_double);
378             break;
379         case GI_TYPE_TAG_GTYPE:
380             g_value_set_gtype (&value, arg.v_size);
381             break;
382         case GI_TYPE_TAG_UTF8:
383         case GI_TYPE_TAG_FILENAME:
384             g_value_set_string (&value, arg.v_string);
385             break;
386         case GI_TYPE_TAG_GHASH:
387             g_value_set_boxed (&value, arg.v_pointer);
388             break;
389         case GI_TYPE_TAG_GLIST:
390             if (G_VALUE_HOLDS_BOXED(&value))
391                 g_value_set_boxed (&value, arg.v_pointer);
392             else
393                 g_value_set_pointer (&value, arg.v_pointer);
394             break;
395         case GI_TYPE_TAG_ARRAY:
396         {
397             /* This is assumes GI_TYPE_TAG_ARRAY is always a GStrv
398              * https://bugzilla.gnome.org/show_bug.cgi?id=688232
399              */
400             GArray *arg_items = (GArray*) arg.v_pointer;
401             gchar** strings;
402             int i;
403
404             if (arg_items == NULL)
405                 goto out;
406
407             strings = g_new0 (char*, arg_items->len + 1);
408             for (i = 0; i < arg_items->len; ++i) {
409                 strings[i] = g_array_index (arg_items, GIArgument, i).v_string;
410             }
411             strings[arg_items->len] = NULL;
412             g_value_set_boxed (&value, strings);
413             g_array_free (arg_items, TRUE);
414             break;
415         }
416         default:
417             PyErr_Format (PyExc_NotImplementedError,
418                           "Setting properties of type %s is not implemented",
419                           g_type_tag_to_string (g_type_info_get_tag (type_info)));
420             goto out;
421     }
422
423     g_object_set_property (instance->obj, pspec->name, &value);
424
425     ret_value = 0;
426
427 out:
428     if (property_info != NULL)
429         g_base_info_unref (property_info);
430     if (type_info != NULL)
431         g_base_info_unref (type_info);
432
433     return ret_value;
434 }
435