Imported Upstream version 3.1.0
[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 /* 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             arg.v_int8 = g_value_get_schar (&value);
125             break;
126         case GI_TYPE_TAG_INT16:
127         case GI_TYPE_TAG_INT32:
128             if (G_VALUE_HOLDS_LONG (&value))
129                 arg.v_long = g_value_get_long (&value);
130             else
131                 arg.v_int = g_value_get_int (&value);
132             break;
133         case GI_TYPE_TAG_INT64:
134             if (G_VALUE_HOLDS_LONG (&value))
135                 arg.v_long = g_value_get_long (&value);
136             else
137                 arg.v_int64 = g_value_get_int64 (&value);
138             break;
139         case GI_TYPE_TAG_UINT8:
140             arg.v_uint8 = g_value_get_uchar (&value);
141             break;
142         case GI_TYPE_TAG_UINT16:
143         case GI_TYPE_TAG_UINT32:
144             if (G_VALUE_HOLDS_ULONG (&value))
145                 arg.v_ulong = g_value_get_ulong (&value);
146             else
147                 arg.v_uint = g_value_get_uint (&value);
148             break;
149         case GI_TYPE_TAG_UINT64:
150             if (G_VALUE_HOLDS_ULONG (&value))
151                 arg.v_ulong = g_value_get_ulong (&value);
152             else
153                 arg.v_uint64 = g_value_get_uint64 (&value);
154             break;
155         case GI_TYPE_TAG_FLOAT:
156             arg.v_float = g_value_get_float (&value);
157             break;
158         case GI_TYPE_TAG_DOUBLE:
159             arg.v_double = g_value_get_double (&value);
160             break;
161         case GI_TYPE_TAG_GTYPE:
162             arg.v_size = g_value_get_gtype (&value);
163             break;
164         case GI_TYPE_TAG_UTF8:
165         case GI_TYPE_TAG_FILENAME:
166             arg.v_string = g_value_dup_string (&value);
167             break;
168         case GI_TYPE_TAG_INTERFACE:
169         {
170             GIBaseInfo *info;
171             GIInfoType info_type;
172             GType type;
173
174             info = g_type_info_get_interface (type_info);
175             type = g_registered_type_info_get_g_type (info);
176             info_type = g_base_info_get_type (info);
177
178             g_base_info_unref (info);
179
180             switch (info_type) {
181                 case GI_INFO_TYPE_ENUM:
182                     arg.v_int32 = g_value_get_enum (&value);
183                     break;
184                 case GI_INFO_TYPE_INTERFACE:
185                 case GI_INFO_TYPE_OBJECT:
186                     arg.v_pointer = g_value_get_object (&value);
187                     break;
188                 case GI_INFO_TYPE_BOXED:
189                 case GI_INFO_TYPE_STRUCT:
190                 case GI_INFO_TYPE_UNION:
191
192                     if (g_type_is_a (type, G_TYPE_BOXED)) {
193                         arg.v_pointer = g_value_get_boxed (&value);
194                     } else if (g_type_is_a (type, G_TYPE_POINTER)) {
195                         arg.v_pointer = g_value_get_pointer (&value);
196                     } else {
197                         PyErr_Format (PyExc_NotImplementedError,
198                                       "Retrieving properties of type '%s' is not implemented",
199                                       g_type_name (type));
200                     }
201                     break;
202                 default:
203                     PyErr_Format (PyExc_NotImplementedError,
204                                   "Retrieving properties of type '%s' is not implemented",
205                                   g_type_name (type));
206                     goto out;
207             }
208             break;
209         }
210         case GI_TYPE_TAG_GHASH:
211             arg.v_pointer = g_value_get_boxed (&value);
212             break;
213         case GI_TYPE_TAG_GLIST:
214             arg.v_pointer = g_value_get_pointer (&value);
215             break;
216         default:
217             PyErr_Format (PyExc_NotImplementedError,
218                           "Retrieving properties of type %s is not implemented",
219                           g_type_tag_to_string (g_type_info_get_tag (type_info)));
220             goto out;
221     }
222
223     py_value = _pygi_argument_to_object (&arg, type_info, transfer);
224
225 out:
226     g_free (property_name);
227     if (property_info != NULL)
228         g_base_info_unref (property_info);
229     if (type_info != NULL)
230         g_base_info_unref (type_info);
231
232     return py_value;
233 }
234
235 gint
236 pygi_set_property_value_real (PyGObject *instance,
237                               const gchar *attr_name,
238                               PyObject *py_value)
239 {
240     GType g_type;
241     GIPropertyInfo *property_info = NULL;
242     char *property_name = g_strdup (attr_name);
243     GITypeInfo *type_info = NULL;
244     GITypeTag type_tag;
245     GITransfer transfer;
246     GValue value = { 0, };
247     GIArgument arg = { 0, };
248     GParamSpec *pspec = NULL;
249     gint ret_value = -1;
250
251     canonicalize_key (property_name);
252
253     g_type = pyg_type_from_object ((PyObject *)instance);
254     property_info = _pygi_lookup_property_from_g_type (g_type, property_name);
255
256     if (property_info == NULL)
257         goto out;
258
259     pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (instance->obj),
260                                           attr_name);
261     if (pspec == NULL)
262         goto out;
263
264     if (! (pspec->flags & G_PARAM_WRITABLE))
265         goto out;
266
267     type_info = g_property_info_get_type (property_info);
268     transfer = g_property_info_get_ownership_transfer (property_info);
269     arg = _pygi_argument_from_object (py_value, type_info, transfer);
270
271     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
272
273     // FIXME: Lots of types still unhandled
274     type_tag = g_type_info_get_tag (type_info);
275     switch (type_tag) {
276         case GI_TYPE_TAG_INTERFACE:
277         {
278             GIBaseInfo *info;
279             GIInfoType info_type;
280             GType type;
281
282             info = g_type_info_get_interface (type_info);
283             type = g_registered_type_info_get_g_type (info);
284             info_type = g_base_info_get_type (info);
285
286             g_base_info_unref (info);
287
288             switch (info_type) {
289                 case GI_INFO_TYPE_ENUM:
290                     g_value_set_enum (&value, arg.v_int32);
291                     break;
292                 case GI_INFO_TYPE_INTERFACE:
293                 case GI_INFO_TYPE_OBJECT:
294                     g_value_set_object (&value, arg.v_pointer);
295                     break;
296                 case GI_INFO_TYPE_BOXED:
297                 case GI_INFO_TYPE_STRUCT:
298                 case GI_INFO_TYPE_UNION:
299                     if (g_type_is_a (type, G_TYPE_BOXED)) {
300                         g_value_set_boxed (&value, arg.v_pointer);
301                     } else {
302                         PyErr_Format (PyExc_NotImplementedError,
303                                       "Setting properties of type '%s' is not implemented",
304                                       g_type_name (type));
305                     }
306                     break;
307                 default:
308                     PyErr_Format (PyExc_NotImplementedError,
309                                   "Setting properties of type '%s' is not implemented",
310                                   g_type_name (type));
311                     goto out;
312             }
313             break;
314         }
315         case GI_TYPE_TAG_BOOLEAN:
316             g_value_set_boolean (&value, arg.v_boolean);
317             break;
318         case GI_TYPE_TAG_INT8:
319             g_value_set_schar (&value, arg.v_int8);
320             break;
321         case GI_TYPE_TAG_INT16:
322         case GI_TYPE_TAG_INT32:
323             if (G_VALUE_HOLDS_LONG (&value))
324                 g_value_set_long (&value, arg.v_long);
325             else
326                 g_value_set_int (&value, arg.v_int);
327             break;
328         case GI_TYPE_TAG_INT64:
329             if (G_VALUE_HOLDS_LONG (&value))
330                 g_value_set_long (&value, arg.v_long);
331             else
332                 g_value_set_int64 (&value, arg.v_int64);
333             break;
334         case GI_TYPE_TAG_UINT8:
335             g_value_set_uchar (&value, arg.v_uint8);
336             break;
337         case GI_TYPE_TAG_UINT16:
338         case GI_TYPE_TAG_UINT32:
339             if (G_VALUE_HOLDS_ULONG (&value))
340                 g_value_set_ulong (&value, arg.v_ulong);
341             else
342                 g_value_set_uint (&value, arg.v_uint);
343             break;
344         case GI_TYPE_TAG_UINT64:
345             if (G_VALUE_HOLDS_ULONG (&value))
346                 g_value_set_ulong (&value, arg.v_ulong);
347             else
348                 g_value_set_uint64 (&value, arg.v_uint64);
349             break;
350         case GI_TYPE_TAG_FLOAT:
351             g_value_set_float (&value, arg.v_float);
352             break;
353         case GI_TYPE_TAG_DOUBLE:
354             g_value_set_double (&value, arg.v_double);
355             break;
356         case GI_TYPE_TAG_GTYPE:
357             g_value_set_gtype (&value, arg.v_size);
358             break;
359         case GI_TYPE_TAG_UTF8:
360         case GI_TYPE_TAG_FILENAME:
361             g_value_set_string (&value, arg.v_string);
362             break;
363         case GI_TYPE_TAG_GHASH:
364             g_value_set_boxed (&value, arg.v_pointer);
365             break;
366         case GI_TYPE_TAG_GLIST:
367             g_value_set_pointer (&value, arg.v_pointer);
368             break;
369         default:
370             PyErr_Format (PyExc_NotImplementedError,
371                           "Setting properties of type %s is not implemented",
372                           g_type_tag_to_string (g_type_info_get_tag (type_info)));
373             goto out;
374     }
375
376     g_object_set_property (instance->obj, attr_name, &value);
377
378     ret_value = 0;
379
380 out:
381     g_free (property_name);
382     if (property_info != NULL)
383         g_base_info_unref (property_info);
384     if (type_info != NULL)
385         g_base_info_unref (type_info);
386
387     return ret_value;
388 }
389