Imported Upstream version 3.19.91
[platform/upstream/python-gobject.git] / gi / pygi-struct.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-struct.c: wrapper to handle non-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, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "pygi-private.h"
23 #include "pygobject-private.h"
24
25 #include <girepository.h>
26 #include <pyglib-python-compat.h>
27
28
29 static GIBaseInfo *
30 _struct_get_info (PyObject *self)
31 {
32     PyObject *py_info;
33     GIBaseInfo *info = NULL;
34
35     py_info = PyObject_GetAttrString (self, "__info__");
36     if (py_info == NULL) {
37         return NULL;
38     }
39     if (!PyObject_TypeCheck (py_info, &PyGIStructInfo_Type) &&
40             !PyObject_TypeCheck (py_info, &PyGIUnionInfo_Type)) {
41         PyErr_Format (PyExc_TypeError, "attribute '__info__' must be %s or %s, not %s",
42                       PyGIStructInfo_Type.tp_name,
43                       PyGIUnionInfo_Type.tp_name,
44                       Py_TYPE(py_info)->tp_name);
45         goto out;
46     }
47
48     info = ( (PyGIBaseInfo *) py_info)->info;
49     g_base_info_ref (info);
50
51 out:
52     Py_DECREF (py_info);
53
54     return info;
55 }
56
57 static void
58 _struct_dealloc (PyGIStruct *self)
59 {
60     GIBaseInfo *info = _struct_get_info ( (PyObject *) self );
61
62     if (info != NULL && g_struct_info_is_foreign ( (GIStructInfo *) info)) {
63         pygi_struct_foreign_release (info, pyg_pointer_get_ptr (self));
64     } else if (self->free_on_dealloc) {
65         g_free (pyg_pointer_get_ptr (self));
66     }
67
68     if (info != NULL) {
69         g_base_info_unref (info);
70     }
71
72     Py_TYPE (self)->tp_free ((PyObject *)self);
73 }
74
75 static PyObject *
76 _struct_new (PyTypeObject *type,
77              PyObject     *args,
78              PyObject     *kwargs)
79 {
80     static char *kwlist[] = { NULL };
81
82     GIBaseInfo *info;
83     gsize size;
84     gpointer pointer;
85     PyObject *self = NULL;
86
87     if (!PyArg_ParseTupleAndKeywords (args, kwargs, "", kwlist)) {
88         return NULL;
89     }
90
91     info = _struct_get_info ( (PyObject *) type );
92     if (info == NULL) {
93         if (PyErr_ExceptionMatches (PyExc_AttributeError)) {
94             PyErr_Format (PyExc_TypeError, "missing introspection information");
95         }
96         return NULL;
97     }
98
99     size = g_struct_info_get_size ( (GIStructInfo *) info);
100     if (size == 0) {
101         PyErr_Format (PyExc_TypeError,
102             "struct cannot be created directly; try using a constructor, see: help(%s.%s)",
103             g_base_info_get_namespace (info),
104             g_base_info_get_name (info));
105         goto out;
106     }
107     pointer = g_try_malloc0 (size);
108     if (pointer == NULL) {
109         PyErr_NoMemory();
110         goto out;
111     }
112
113     self = _pygi_struct_new (type, pointer, TRUE);
114     if (self == NULL) {
115         g_free (pointer);
116     }
117
118 out:
119     g_base_info_unref (info);
120
121     return (PyObject *) self;
122 }
123
124 static int
125 _struct_init (PyObject *self,
126               PyObject *args,
127               PyObject *kwargs)
128 {
129     /* Don't call PyGPointer's init, which raises an exception. */
130     return 0;
131 }
132
133 PYGLIB_DEFINE_TYPE("gi.Struct", PyGIStruct_Type, PyGIStruct);
134
135
136 PyObject *
137 _pygi_struct_new_from_g_type (GType g_type,
138                               gpointer      pointer,
139                               gboolean      free_on_dealloc)
140 {
141     PyGIStruct *self;
142     PyTypeObject *type;
143
144     type = (PyTypeObject *)pygi_type_import_by_g_type (g_type);
145
146     if (!type)
147         type = (PyTypeObject *)&PyGIStruct_Type; /* fallback */
148
149     if (!PyType_IsSubtype (type, &PyGIStruct_Type)) {
150         PyErr_SetString (PyExc_TypeError, "must be a subtype of gi.Struct");
151         return NULL;
152     }
153
154     self = (PyGIStruct *) type->tp_alloc (type, 0);
155     if (self == NULL) {
156         return NULL;
157     }
158
159     pyg_pointer_set_ptr (self, pointer);
160     ( (PyGPointer *) self)->gtype = g_type;
161     self->free_on_dealloc = free_on_dealloc;
162
163     return (PyObject *) self;
164 }
165
166
167 PyObject *
168 _pygi_struct_new (PyTypeObject *type,
169                   gpointer      pointer,
170                   gboolean      free_on_dealloc)
171 {
172     PyGIStruct *self;
173     GType g_type;
174
175     if (!PyType_IsSubtype (type, &PyGIStruct_Type)) {
176         PyErr_SetString (PyExc_TypeError, "must be a subtype of gi.Struct");
177         return NULL;
178     }
179
180     self = (PyGIStruct *) type->tp_alloc (type, 0);
181     if (self == NULL) {
182         return NULL;
183     }
184
185     g_type = pyg_type_from_object ( (PyObject *) type);
186
187     pyg_pointer_set_ptr (self, pointer);
188     ( (PyGPointer *) self)->gtype = g_type;
189     self->free_on_dealloc = free_on_dealloc;
190
191     return (PyObject *) self;
192 }
193
194 static PyObject *
195 _struct_repr(PyGIStruct *self)
196 {
197     PyObject* repr;
198     GIBaseInfo *info;
199     PyGPointer *pointer = (PyGPointer *)self;
200
201     info = _struct_get_info ((PyObject *)self);
202     if (info == NULL)
203         return NULL;
204
205     repr = PYGLIB_PyUnicode_FromFormat ("<%s.%s object at %p (%s at %p)>",
206                                         g_base_info_get_namespace (info),
207                                         g_base_info_get_name (info),
208                                         self, g_type_name (pointer->gtype),
209                                         pointer->pointer);
210
211     g_base_info_unref (info);
212
213     return repr;
214 }
215
216 void
217 _pygi_struct_register_types (PyObject *m)
218 {
219     Py_TYPE(&PyGIStruct_Type) = &PyType_Type;
220     PyGIStruct_Type.tp_base = &PyGPointer_Type;
221     PyGIStruct_Type.tp_new = (newfunc) _struct_new;
222     PyGIStruct_Type.tp_init = (initproc) _struct_init;
223     PyGIStruct_Type.tp_dealloc = (destructor) _struct_dealloc;
224     PyGIStruct_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE);
225     PyGIStruct_Type.tp_repr = (reprfunc)_struct_repr;
226
227     if (PyType_Ready (&PyGIStruct_Type))
228         return;
229     if (PyModule_AddObject (m, "Struct", (PyObject *) &PyGIStruct_Type))
230         return;
231 }