Update to 2.28 for TINF-96
[profile/ivi/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 /* Copied from glib */
29 static void
30 canonicalize_key (gchar *key)
31 {
32     gchar *p;
33
34     for (p = key; *p != 0; p++)
35     {
36         gchar c = *p;
37
38         if (c != '-' &&
39             (c < '0' || c > '9') &&
40             (c < 'A' || c > 'Z') &&
41             (c < 'a' || c > 'z'))
42                 *p = '-';
43     }
44 }
45
46 static GIPropertyInfo *
47 _pygi_lookup_property_from_g_type (GType g_type, const gchar *attr_name)
48 {
49     GIRepository *repository;
50     GIBaseInfo *info;
51     gssize n_infos;
52     gssize i;
53     GType parent;
54
55     repository = g_irepository_get_default();
56     info = g_irepository_find_by_gtype (repository, g_type);
57     if (info == NULL) {
58         return NULL;
59     }
60
61     n_infos = g_object_info_get_n_properties ( (GIObjectInfo *) info);
62     for (i = 0; i < n_infos; i++) {
63         GIPropertyInfo *property_info;
64
65         property_info = g_object_info_get_property ( (GIObjectInfo *) info, i);
66         g_assert (info != NULL);
67
68         if (strcmp (attr_name, g_base_info_get_name (property_info)) == 0) {
69             g_base_info_unref (info);
70             return property_info;
71         }
72
73         g_base_info_unref (property_info);
74     }
75
76     g_base_info_unref (info);
77
78     parent = g_type_parent (g_type);
79     if (parent > 0)
80         return _pygi_lookup_property_from_g_type (parent, attr_name);
81
82     return NULL;
83 }
84
85 PyObject *
86 pygi_get_property_value_real (PyGObject *instance,
87                               const gchar *attr_name)
88 {
89     GType g_type;
90     GIPropertyInfo *property_info = NULL;
91     char *property_name = g_strdup (attr_name);
92     GParamSpec *pspec = NULL;
93     GValue value = { 0, };
94     GIArgument arg = { 0, };
95     PyObject *py_value = NULL;
96     GITypeInfo *type_info = NULL;
97     GITransfer transfer;
98
99     canonicalize_key (property_name);
100
101     g_type = pyg_type_from_object ((PyObject *)instance);
102     property_info = _pygi_lookup_property_from_g_type (g_type, property_name);
103
104     if (property_info == NULL)
105         goto out;
106
107     pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (instance->obj),
108                                           attr_name);
109     if (pspec == NULL)
110         goto out;
111
112     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
113     g_object_get_property (instance->obj, attr_name, &value);
114
115     type_info = g_property_info_get_type (property_info);
116     transfer = g_property_info_get_ownership_transfer (property_info);
117
118     GITypeTag type_tag = g_type_info_get_tag (type_info);
119     switch (type_tag) {
120         case GI_TYPE_TAG_BOOLEAN:
121             arg.v_boolean = g_value_get_boolean (&value);
122             break;
123         case GI_TYPE_TAG_INT8:
124         case GI_TYPE_TAG_INT16:
125         case GI_TYPE_TAG_INT32:
126         case GI_TYPE_TAG_INT64:
127             arg.v_int = g_value_get_int (&value);
128             break;
129         case GI_TYPE_TAG_UINT8:
130         case GI_TYPE_TAG_UINT16:
131         case GI_TYPE_TAG_UINT32:
132         case GI_TYPE_TAG_UINT64:
133             arg.v_uint = g_value_get_uint (&value);
134             break;
135         case GI_TYPE_TAG_FLOAT:
136             arg.v_float = g_value_get_float (&value);
137             break;
138         case GI_TYPE_TAG_DOUBLE:
139             arg.v_double = g_value_get_double (&value);
140             break;
141         case GI_TYPE_TAG_GTYPE:
142             arg.v_size = g_value_get_gtype (&value);
143             break;
144         case GI_TYPE_TAG_UTF8:
145         case GI_TYPE_TAG_FILENAME:
146             arg.v_string = g_value_dup_string (&value);
147             break;
148         case GI_TYPE_TAG_INTERFACE:
149         {
150             GIBaseInfo *info;
151             GIInfoType info_type;
152             GType type;
153
154             info = g_type_info_get_interface (type_info);
155             type = g_registered_type_info_get_g_type (info);
156             info_type = g_base_info_get_type (info);
157
158             g_base_info_unref (info);
159
160             switch (info_type) {
161                 case GI_INFO_TYPE_ENUM:
162                     arg.v_int32 = g_value_get_enum (&value);
163                     break;
164                 case GI_INFO_TYPE_INTERFACE:
165                 case GI_INFO_TYPE_OBJECT:
166                     arg.v_pointer = g_value_get_object (&value);
167                     break;
168                 case GI_INFO_TYPE_BOXED:
169                 case GI_INFO_TYPE_STRUCT:
170                 case GI_INFO_TYPE_UNION:
171
172                     if (g_type_is_a (type, G_TYPE_BOXED)) {
173                         arg.v_pointer = g_value_get_boxed (&value);
174                     } else if (g_type_is_a (type, G_TYPE_POINTER)) {
175                         arg.v_pointer = g_value_get_pointer (&value);
176                     } else {
177                         PyErr_Format (PyExc_NotImplementedError,
178                                       "Retrieving properties of type '%s' is not implemented",
179                                       g_type_name (type));
180                     }
181                     break;
182                 default:
183                     PyErr_Format (PyExc_NotImplementedError,
184                                   "Retrieving properties of type '%s' is not implemented",
185                                   g_type_name (type));
186                     goto out;
187             }
188             break;
189         }
190         case GI_TYPE_TAG_GHASH:
191             arg.v_pointer = g_value_get_boxed (&value);
192             break;
193         case GI_TYPE_TAG_GLIST:
194             arg.v_pointer = g_value_get_pointer (&value);
195             break;
196         default:
197             PyErr_Format (PyExc_NotImplementedError,
198                           "Retrieving properties of type %s is not implemented",
199                           g_type_tag_to_string (g_type_info_get_tag (type_info)));
200             goto out;
201     }
202
203     py_value = _pygi_argument_to_object (&arg, type_info, transfer);
204
205 out:
206     g_free (property_name);
207     if (property_info != NULL)
208         g_base_info_unref (property_info);
209     if (type_info != NULL)
210         g_base_info_unref (type_info);
211
212     return py_value;
213 }
214
215 gint
216 pygi_set_property_value_real (PyGObject *instance,
217                               const gchar *attr_name,
218                               PyObject *py_value)
219 {
220     GType g_type;
221     GIPropertyInfo *property_info = NULL;
222     char *property_name = g_strdup (attr_name);
223     GITypeInfo *type_info = NULL;
224     GITypeTag type_tag;
225     GITransfer transfer;
226     GValue value = { 0, };
227     GIArgument arg = { 0, };
228     GParamSpec *pspec = NULL;
229     gint ret_value = -1;
230
231     canonicalize_key (property_name);
232
233     g_type = pyg_type_from_object ((PyObject *)instance);
234     property_info = _pygi_lookup_property_from_g_type (g_type, property_name);
235
236     if (property_info == NULL)
237         goto out;
238
239     pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (instance->obj),
240                                           attr_name);
241     if (pspec == NULL)
242         goto out;
243
244     if (! (pspec->flags & G_PARAM_WRITABLE))
245         goto out;
246
247     type_info = g_property_info_get_type (property_info);
248     transfer = g_property_info_get_ownership_transfer (property_info);
249     arg = _pygi_argument_from_object (py_value, type_info, transfer);
250
251     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
252
253     // FIXME: Lots of types still unhandled
254     type_tag = g_type_info_get_tag (type_info);
255     switch (type_tag) {
256         case GI_TYPE_TAG_INTERFACE:
257         {
258             GIBaseInfo *info;
259             GIInfoType info_type;
260             GType type;
261
262             info = g_type_info_get_interface (type_info);
263             type = g_registered_type_info_get_g_type (info);
264             info_type = g_base_info_get_type (info);
265
266             g_base_info_unref (info);
267
268             switch (info_type) {
269                 case GI_INFO_TYPE_ENUM:
270                     g_value_set_enum (&value, arg.v_int32);
271                     break;
272                 case GI_INFO_TYPE_INTERFACE:
273                 case GI_INFO_TYPE_OBJECT:
274                     g_value_set_object (&value, arg.v_pointer);
275                     break;
276                 case GI_INFO_TYPE_BOXED:
277                 case GI_INFO_TYPE_STRUCT:
278                 case GI_INFO_TYPE_UNION:
279                     if (g_type_is_a (type, G_TYPE_BOXED)) {
280                         g_value_set_boxed (&value, arg.v_pointer);
281                     } else {
282                         PyErr_Format (PyExc_NotImplementedError,
283                                       "Setting properties of type '%s' is not implemented",
284                                       g_type_name (type));
285                     }
286                     break;
287                 default:
288                     PyErr_Format (PyExc_NotImplementedError,
289                                   "Setting properties of type '%s' is not implemented",
290                                   g_type_name (type));
291                     goto out;
292             }
293             break;
294         }
295         case GI_TYPE_TAG_BOOLEAN:
296             g_value_set_boolean (&value, arg.v_boolean);
297             break;
298         case GI_TYPE_TAG_INT8:
299         case GI_TYPE_TAG_INT16:
300         case GI_TYPE_TAG_INT32:
301         case GI_TYPE_TAG_INT64:
302             g_value_set_int (&value, arg.v_int);
303             break;
304         case GI_TYPE_TAG_UINT8:
305         case GI_TYPE_TAG_UINT16:
306         case GI_TYPE_TAG_UINT32:
307         case GI_TYPE_TAG_UINT64:
308             g_value_set_uint (&value, arg.v_uint);
309             break;
310         case GI_TYPE_TAG_FLOAT:
311             g_value_set_float (&value, arg.v_float);
312             break;
313         case GI_TYPE_TAG_DOUBLE:
314             g_value_set_double (&value, arg.v_double);
315             break;
316         case GI_TYPE_TAG_GTYPE:
317             g_value_set_gtype (&value, arg.v_size);
318             break;
319         case GI_TYPE_TAG_UTF8:
320         case GI_TYPE_TAG_FILENAME:
321             g_value_set_string (&value, arg.v_string);
322             break;
323         case GI_TYPE_TAG_GHASH:
324             g_value_set_boxed (&value, arg.v_pointer);
325             break;
326         case GI_TYPE_TAG_GLIST:
327             g_value_set_pointer (&value, arg.v_pointer);
328             break;
329         default:
330             PyErr_Format (PyExc_NotImplementedError,
331                           "Setting properties of type %s is not implemented",
332                           g_type_tag_to_string (g_type_info_get_tag (type_info)));
333             goto out;
334     }
335
336     g_object_set_property (instance->obj, attr_name, &value);
337
338     ret_value = 0;
339
340 out:
341     g_free (property_name);
342     if (property_info != NULL)
343         g_base_info_unref (property_info);
344     if (type_info != NULL)
345         g_base_info_unref (type_info);
346
347     return ret_value;
348 }
349