Imported Upstream version 3.7.3
[platform/upstream/python-gobject.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             arg.v_pointer = g_value_get_pointer (&value);
221             break;
222         case GI_TYPE_TAG_ARRAY:
223         {
224             gchar** strings;
225             GArray *arg_items;
226             int i;
227
228             strings = g_value_get_boxed (&value);
229             if (strings == NULL)
230                 arg.v_pointer = NULL;
231             else {
232                 arg_items = g_array_sized_new (TRUE, TRUE, sizeof (GIArgument), g_strv_length (strings));
233                 g_array_set_size (arg_items, g_strv_length (strings));
234                 for (i = 0; strings[i] != NULL; ++i) {
235                     g_array_index (arg_items, GIArgument, i).v_string = strings[i];
236                 }
237                 arg.v_pointer = arg_items;
238             }
239             break;
240         }
241         default:
242             PyErr_Format (PyExc_NotImplementedError,
243                           "Retrieving properties of type %s is not implemented",
244                           g_type_tag_to_string (g_type_info_get_tag (type_info)));
245             goto out;
246     }
247
248     py_value = _pygi_argument_to_object (&arg, type_info, transfer);
249
250 out:
251     if (property_info != NULL)
252         g_base_info_unref (property_info);
253     if (type_info != NULL)
254         g_base_info_unref (type_info);
255
256     return py_value;
257 }
258
259 gint
260 pygi_set_property_value_real (PyGObject *instance,
261                               GParamSpec *pspec,
262                               PyObject *py_value)
263 {
264     GIPropertyInfo *property_info = NULL;
265     GITypeInfo *type_info = NULL;
266     GITypeTag type_tag;
267     GITransfer transfer;
268     GValue value = { 0, };
269     GIArgument arg = { 0, };
270     gint ret_value = -1;
271
272     /* The owner_type of the pspec gives us the exact type that introduced the
273      * property, even if it is a parent class of the instance in question. */
274     property_info = _pygi_lookup_property_from_g_type (pspec->owner_type,
275                                                        pspec->name);
276     if (property_info == NULL)
277         goto out;
278
279     if (! (pspec->flags & G_PARAM_WRITABLE))
280         goto out;
281
282     type_info = g_property_info_get_type (property_info);
283     transfer = g_property_info_get_ownership_transfer (property_info);
284     arg = _pygi_argument_from_object (py_value, type_info, transfer);
285
286     if (PyErr_Occurred())
287         goto out;
288
289     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
290
291     // FIXME: Lots of types still unhandled
292     type_tag = g_type_info_get_tag (type_info);
293     switch (type_tag) {
294         case GI_TYPE_TAG_INTERFACE:
295         {
296             GIBaseInfo *info;
297             GIInfoType info_type;
298             GType type;
299
300             info = g_type_info_get_interface (type_info);
301             type = g_registered_type_info_get_g_type (info);
302             info_type = g_base_info_get_type (info);
303
304             g_base_info_unref (info);
305
306             switch (info_type) {
307                 case GI_INFO_TYPE_ENUM:
308                     g_value_set_enum (&value, arg.v_int32);
309                     break;
310                 case GI_INFO_TYPE_INTERFACE:
311                 case GI_INFO_TYPE_OBJECT:
312                     g_value_set_object (&value, arg.v_pointer);
313                     break;
314                 case GI_INFO_TYPE_BOXED:
315                 case GI_INFO_TYPE_STRUCT:
316                 case GI_INFO_TYPE_UNION:
317                     if (g_type_is_a (type, G_TYPE_BOXED)) {
318                         g_value_set_boxed (&value, arg.v_pointer);
319                     } else if (g_type_is_a (type, G_TYPE_VARIANT)) {
320                         g_value_set_variant (&value, arg.v_pointer);
321                     } else {
322                         PyErr_Format (PyExc_NotImplementedError,
323                                       "Setting properties of type '%s' is not implemented",
324                                       g_type_name (type));
325                     }
326                     goto out;
327                 default:
328                     PyErr_Format (PyExc_NotImplementedError,
329                                   "Setting properties of type '%s' is not implemented",
330                                   g_type_name (type));
331                     goto out;
332             }
333             break;
334         }
335         case GI_TYPE_TAG_BOOLEAN:
336             g_value_set_boolean (&value, arg.v_boolean);
337             break;
338         case GI_TYPE_TAG_INT8:
339             g_value_set_schar (&value, arg.v_int8);
340             break;
341         case GI_TYPE_TAG_INT16:
342         case GI_TYPE_TAG_INT32:
343             if (G_VALUE_HOLDS_LONG (&value))
344                 g_value_set_long (&value, arg.v_long);
345             else
346                 g_value_set_int (&value, arg.v_int);
347             break;
348         case GI_TYPE_TAG_INT64:
349             if (G_VALUE_HOLDS_LONG (&value))
350                 g_value_set_long (&value, arg.v_long);
351             else
352                 g_value_set_int64 (&value, arg.v_int64);
353             break;
354         case GI_TYPE_TAG_UINT8:
355             g_value_set_uchar (&value, arg.v_uint8);
356             break;
357         case GI_TYPE_TAG_UINT16:
358         case GI_TYPE_TAG_UINT32:
359             if (G_VALUE_HOLDS_ULONG (&value))
360                 g_value_set_ulong (&value, arg.v_ulong);
361             else
362                 g_value_set_uint (&value, arg.v_uint);
363             break;
364         case GI_TYPE_TAG_UINT64:
365             if (G_VALUE_HOLDS_ULONG (&value))
366                 g_value_set_ulong (&value, arg.v_ulong);
367             else
368                 g_value_set_uint64 (&value, arg.v_uint64);
369             break;
370         case GI_TYPE_TAG_FLOAT:
371             g_value_set_float (&value, arg.v_float);
372             break;
373         case GI_TYPE_TAG_DOUBLE:
374             g_value_set_double (&value, arg.v_double);
375             break;
376         case GI_TYPE_TAG_GTYPE:
377             g_value_set_gtype (&value, arg.v_size);
378             break;
379         case GI_TYPE_TAG_UTF8:
380         case GI_TYPE_TAG_FILENAME:
381             g_value_set_string (&value, arg.v_string);
382             break;
383         case GI_TYPE_TAG_GHASH:
384             g_value_set_boxed (&value, arg.v_pointer);
385             break;
386         case GI_TYPE_TAG_GLIST:
387             g_value_set_pointer (&value, arg.v_pointer);
388             break;
389         case GI_TYPE_TAG_ARRAY:
390         {
391             /* This is assumes GI_TYPE_TAG_ARRAY is always a GStrv
392              * https://bugzilla.gnome.org/show_bug.cgi?id=688232
393              */
394             GArray *arg_items = (GArray*) arg.v_pointer;
395             gchar** strings;
396             int i;
397
398             if (arg_items == NULL)
399                 goto out;
400
401             strings = g_new0 (char*, arg_items->len + 1);
402             for (i = 0; i < arg_items->len; ++i) {
403                 strings[i] = g_array_index (arg_items, GIArgument, i).v_string;
404             }
405             strings[arg_items->len] = NULL;
406             g_value_set_boxed (&value, strings);
407             g_array_free (arg_items, TRUE);
408             break;
409         }
410         default:
411             PyErr_Format (PyExc_NotImplementedError,
412                           "Setting properties of type %s is not implemented",
413                           g_type_tag_to_string (g_type_info_get_tag (type_info)));
414             goto out;
415     }
416
417     g_object_set_property (instance->obj, pspec->name, &value);
418
419     ret_value = 0;
420
421 out:
422     if (property_info != NULL)
423         g_base_info_unref (property_info);
424     if (type_info != NULL)
425         g_base_info_unref (type_info);
426
427     return ret_value;
428 }
429