7c83eefcd639b2089e37963411e1c3481c46831f
[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 /* 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         case GI_TYPE_TAG_GSLIST:
215             arg.v_pointer = g_value_get_pointer (&value);
216             break;
217         case GI_TYPE_TAG_ARRAY:
218         {
219             gchar** strings;
220             GArray *arg_items;
221             int i;
222
223             strings = g_value_get_boxed (&value);
224             if (strings == NULL)
225                 arg.v_pointer = NULL;
226             else {
227                 arg_items = g_array_sized_new (TRUE, TRUE, sizeof (GIArgument), g_strv_length (strings));
228                 g_array_set_size (arg_items, g_strv_length (strings));
229                 for (i = 0; strings[i] != NULL; ++i) {
230                     g_array_index (arg_items, GIArgument, i).v_string = strings[i];
231                 }
232                 arg.v_pointer = arg_items;
233             }
234             break;
235         }
236         default:
237             PyErr_Format (PyExc_NotImplementedError,
238                           "Retrieving properties of type %s is not implemented",
239                           g_type_tag_to_string (g_type_info_get_tag (type_info)));
240             goto out;
241     }
242
243     py_value = _pygi_argument_to_object (&arg, type_info, transfer);
244
245 out:
246     g_free (property_name);
247     if (property_info != NULL)
248         g_base_info_unref (property_info);
249     if (type_info != NULL)
250         g_base_info_unref (type_info);
251
252     return py_value;
253 }
254
255 gint
256 pygi_set_property_value_real (PyGObject *instance,
257                               const gchar *attr_name,
258                               PyObject *py_value)
259 {
260     GType g_type;
261     GIPropertyInfo *property_info = NULL;
262     char *property_name = g_strdup (attr_name);
263     GITypeInfo *type_info = NULL;
264     GITypeTag type_tag;
265     GITransfer transfer;
266     GValue value = { 0, };
267     GIArgument arg = { 0, };
268     GParamSpec *pspec = NULL;
269     gint ret_value = -1;
270
271     canonicalize_key (property_name);
272
273     g_type = pyg_type_from_object ((PyObject *)instance);
274     property_info = _pygi_lookup_property_from_g_type (g_type, property_name);
275
276     if (property_info == NULL)
277         goto out;
278
279     pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (instance->obj),
280                                           attr_name);
281     if (pspec == NULL)
282         goto out;
283
284     if (! (pspec->flags & G_PARAM_WRITABLE))
285         goto out;
286
287     type_info = g_property_info_get_type (property_info);
288     transfer = g_property_info_get_ownership_transfer (property_info);
289     arg = _pygi_argument_from_object (py_value, type_info, transfer);
290
291     if (PyErr_Occurred())
292         goto out;
293
294     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
295
296     // FIXME: Lots of types still unhandled
297     type_tag = g_type_info_get_tag (type_info);
298     switch (type_tag) {
299         case GI_TYPE_TAG_INTERFACE:
300         {
301             GIBaseInfo *info;
302             GIInfoType info_type;
303             GType type;
304
305             info = g_type_info_get_interface (type_info);
306             type = g_registered_type_info_get_g_type (info);
307             info_type = g_base_info_get_type (info);
308
309             g_base_info_unref (info);
310
311             switch (info_type) {
312                 case GI_INFO_TYPE_ENUM:
313                     g_value_set_enum (&value, arg.v_int32);
314                     break;
315                 case GI_INFO_TYPE_INTERFACE:
316                 case GI_INFO_TYPE_OBJECT:
317                     g_value_set_object (&value, arg.v_pointer);
318                     break;
319                 case GI_INFO_TYPE_BOXED:
320                 case GI_INFO_TYPE_STRUCT:
321                 case GI_INFO_TYPE_UNION:
322                     if (g_type_is_a (type, G_TYPE_BOXED)) {
323                         g_value_set_boxed (&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                     break;
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             g_value_set_pointer (&value, arg.v_pointer);
391             break;
392         case GI_TYPE_TAG_ARRAY:
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);
402             for (i = 0; i < arg_items->len; ++i) {
403                 strings[i] = g_array_index (arg_items, GIArgument, i).v_string;
404             }
405             g_array_free (arg_items, TRUE);
406             g_value_set_boxed (&value, strings);
407             break;
408         }
409         default:
410             PyErr_Format (PyExc_NotImplementedError,
411                           "Setting properties of type %s is not implemented",
412                           g_type_tag_to_string (g_type_info_get_tag (type_info)));
413             goto out;
414     }
415
416     g_object_set_property (instance->obj, attr_name, &value);
417
418     ret_value = 0;
419
420 out:
421     g_free (property_name);
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