2fd446c55c93165b8e045a8716f24e51351a1c47
[platform/upstream/python-gobject.git] / gi / pygi-boxed.c
1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * vim: tabstop=4 shiftwidth=4 expandtab
3  *
4  * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
5  *
6  *   pygi-boxed.c: wrapper to handle registered structures.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21  * USA
22  */
23
24 #include "pygi-private.h"
25
26 #include <pygobject.h>
27 #include <girepository.h>
28 #include <pyglib-python-compat.h>
29
30 static void
31 _boxed_dealloc (PyGIBoxed *self)
32 {
33     GType g_type;
34
35     PyObject_GC_UnTrack ( (PyObject *) self);
36
37     PyObject_ClearWeakRefs ( (PyObject *) self);
38
39     if ( ( (PyGBoxed *) self)->free_on_dealloc) {
40         if (self->slice_allocated) {
41             g_slice_free1 (self->size, ( (PyGBoxed *) self)->boxed);
42         } else {
43             g_type = pyg_type_from_object ( (PyObject *) self);
44             g_boxed_free (g_type, ( (PyGBoxed *) self)->boxed);
45         }
46     }
47
48     Py_TYPE( (PyGObject *) self)->tp_free ( (PyObject *) self);
49 }
50
51 void *
52 _pygi_boxed_alloc (GIBaseInfo *info, gsize *size_out)
53 {
54     gsize size;
55
56     /* FIXME: Remove when bgo#622711 is fixed */
57     if (g_registered_type_info_get_g_type (info) == G_TYPE_VALUE) {
58         size = sizeof (GValue);
59     } else {
60         switch (g_base_info_get_type (info)) {
61             case GI_INFO_TYPE_UNION:
62                 size = g_union_info_get_size ( (GIUnionInfo *) info);
63                 break;
64             case GI_INFO_TYPE_BOXED:
65             case GI_INFO_TYPE_STRUCT:
66                 size = g_struct_info_get_size ( (GIStructInfo *) info);
67                 break;
68             default:
69                 PyErr_Format (PyExc_TypeError,
70                               "info should be Boxed or Union, not '%d'",
71                               g_base_info_get_type (info));
72                 return NULL;
73         }
74     }
75
76     if( size_out != NULL)
77         *size_out = size;
78
79     return g_slice_alloc0 (size);
80 }
81
82 static PyObject *
83 _boxed_new (PyTypeObject *type,
84             PyObject     *args,
85             PyObject     *kwargs)
86 {
87     static char *kwlist[] = { NULL };
88
89     GIBaseInfo *info;
90     gsize size = 0;
91     gpointer boxed;
92     PyGIBoxed *self = NULL;
93
94     if (!PyArg_ParseTupleAndKeywords (args, kwargs, "", kwlist)) {
95         return NULL;
96     }
97
98     info = _pygi_object_get_gi_info ( (PyObject *) type, &PyGIBaseInfo_Type);
99     if (info == NULL) {
100         if (PyErr_ExceptionMatches (PyExc_AttributeError)) {
101             PyErr_Format (PyExc_TypeError, "missing introspection information");
102         }
103         return NULL;
104     }
105
106     boxed = _pygi_boxed_alloc (info, &size);
107     if (boxed == NULL) {
108         PyErr_NoMemory();
109         goto out;
110     }
111
112     self = (PyGIBoxed *) _pygi_boxed_new (type, boxed, TRUE);
113     if (self == NULL) {
114         g_slice_free1 (size, boxed);
115         goto out;
116     }
117
118     self->size = size;
119     self->slice_allocated = TRUE;
120
121 out:
122     g_base_info_unref (info);
123
124     return (PyObject *) self;
125 }
126
127 static int
128 _boxed_init (PyObject *self,
129              PyObject *args,
130              PyObject *kwargs)
131 {
132     /* Don't call PyGBoxed's init, which raises an exception. */
133     return 0;
134 }
135
136 PYGLIB_DEFINE_TYPE("gi.Boxed", PyGIBoxed_Type, PyGIBoxed);
137
138 PyObject *
139 _pygi_boxed_new (PyTypeObject *type,
140                  gpointer      boxed,
141                  gboolean      free_on_dealloc)
142 {
143     PyGIBoxed *self;
144
145     if (!boxed) {
146         Py_RETURN_NONE;
147     }
148
149     if (!PyType_IsSubtype (type, &PyGIBoxed_Type)) {
150         PyErr_SetString (PyExc_TypeError, "must be a subtype of gi.Boxed");
151         return NULL;
152     }
153
154     self = (PyGIBoxed *) type->tp_alloc (type, 0);
155     if (self == NULL) {
156         return NULL;
157     }
158
159     ( (PyGBoxed *) self)->gtype = pyg_type_from_object ( (PyObject *) type);
160     ( (PyGBoxed *) self)->boxed = boxed;
161     ( (PyGBoxed *) self)->free_on_dealloc = free_on_dealloc;
162     self->size = 0;
163     self->slice_allocated = FALSE;
164
165     return (PyObject *) self;
166 }
167
168 void
169 _pygi_boxed_register_types (PyObject *m)
170 {
171     Py_TYPE(&PyGIBoxed_Type) = &PyType_Type;
172     PyGIBoxed_Type.tp_base = &PyGBoxed_Type;
173     PyGIBoxed_Type.tp_new = (newfunc) _boxed_new;
174     PyGIBoxed_Type.tp_init = (initproc) _boxed_init;
175     PyGIBoxed_Type.tp_dealloc = (destructor) _boxed_dealloc;
176     PyGIBoxed_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE);
177
178     if (PyType_Ready (&PyGIBoxed_Type))
179         return;
180     if (PyModule_AddObject (m, "Boxed", (PyObject *) &PyGIBoxed_Type))
181         return;
182 }