setup.py: Provide a os.path.samefile fallback for Python 2 under Windows
[pygobject.git] / gi / pygi-boxed.c
blobe9014f20e7e44424dc71ce1c842d958d8012b462
1 /* -*- Mode: C; c-basic-offset: 4 -*-
2 * vim: tabstop=4 shiftwidth=4 expandtab
4 * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
6 * pygi-boxed.c: wrapper to handle registered structures.
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.
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.
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/>.
22 #include "pygi-boxed.h"
23 #include "pygi-info.h"
24 #include "pygboxed.h"
25 #include "pygtype.h"
27 #include <girepository.h>
28 #include <pyglib-python-compat.h>
30 static void
31 _boxed_dealloc (PyGIBoxed *self)
33 Py_TYPE (self)->tp_free ((PyObject *)self);
36 static PyObject *
37 boxed_del (PyGIBoxed *self)
39 GType g_type;
40 gpointer boxed = pyg_boxed_get_ptr (self);
42 if ( ( (PyGBoxed *) self)->free_on_dealloc && boxed != NULL) {
43 if (self->slice_allocated) {
44 g_slice_free1 (self->size, boxed);
45 } else {
46 g_type = pyg_type_from_object ( (PyObject *) self);
47 g_boxed_free (g_type, boxed);
50 pyg_boxed_set_ptr (self, NULL);
52 Py_RETURN_NONE;
55 void *
56 _pygi_boxed_alloc (GIBaseInfo *info, gsize *size_out)
58 gpointer boxed = NULL;
59 gsize size = 0;
61 switch (g_base_info_get_type (info)) {
62 case GI_INFO_TYPE_UNION:
63 size = g_union_info_get_size ( (GIUnionInfo *) info);
64 break;
65 case GI_INFO_TYPE_BOXED:
66 case GI_INFO_TYPE_STRUCT:
67 size = g_struct_info_get_size ( (GIStructInfo *) info);
68 break;
69 default:
70 PyErr_Format (PyExc_TypeError,
71 "info should be Boxed or Union, not '%d'",
72 g_base_info_get_type (info));
73 return NULL;
76 if (size == 0) {
77 PyErr_Format (PyExc_TypeError,
78 "boxed cannot be created directly; try using a constructor, see: help(%s.%s)",
79 g_base_info_get_namespace (info),
80 g_base_info_get_name (info));
81 return NULL;
84 if( size_out != NULL)
85 *size_out = size;
87 boxed = g_slice_alloc0 (size);
88 if (boxed == NULL)
89 PyErr_NoMemory();
90 return boxed;
93 static PyObject *
94 _boxed_new (PyTypeObject *type,
95 PyObject *args,
96 PyObject *kwargs)
98 GIBaseInfo *info;
99 gsize size = 0;
100 gpointer boxed;
101 PyGIBoxed *self = NULL;
103 info = _pygi_object_get_gi_info ( (PyObject *) type, &PyGIBaseInfo_Type);
104 if (info == NULL) {
105 if (PyErr_ExceptionMatches (PyExc_AttributeError)) {
106 PyErr_Format (PyExc_TypeError, "missing introspection information");
108 return NULL;
111 boxed = _pygi_boxed_alloc (info, &size);
112 if (boxed == NULL) {
113 goto out;
116 self = (PyGIBoxed *) _pygi_boxed_new (type, boxed, FALSE, size);
117 if (self == NULL) {
118 g_slice_free1 (size, boxed);
119 goto out;
122 self->size = size;
123 self->slice_allocated = TRUE;
125 out:
126 g_base_info_unref (info);
128 return (PyObject *) self;
131 static int
132 _boxed_init (PyObject *self,
133 PyObject *args,
134 PyObject *kwargs)
136 static char *kwlist[] = { NULL };
138 if (!PyArg_ParseTupleAndKeywords (args, kwargs, "", kwlist)) {
139 PyErr_Clear ();
140 PyErr_Warn (PyExc_TypeError,
141 "Passing arguments to gi.types.Boxed.__init__() is deprecated. "
142 "All arguments passed will be ignored.");
145 /* Don't call PyGBoxed's init, which raises an exception. */
146 return 0;
149 PYGLIB_DEFINE_TYPE("gi.Boxed", PyGIBoxed_Type, PyGIBoxed);
151 PyObject *
152 _pygi_boxed_new (PyTypeObject *pytype,
153 gpointer boxed,
154 gboolean copy_boxed,
155 gsize allocated_slice)
157 PyGIBoxed *self;
158 GType gtype;
160 if (!boxed) {
161 Py_RETURN_NONE;
164 if (!PyType_IsSubtype (pytype, &PyGIBoxed_Type)) {
165 PyErr_SetString (PyExc_TypeError, "must be a subtype of gi.Boxed");
166 return NULL;
169 gtype = pyg_type_from_object ((PyObject *)pytype);
171 /* Boxed objects with slice allocation means they come from caller allocated
172 * out arguments. In this case copy_boxed does not make sense because we
173 * already own the slice allocated memory and we should be receiving full
174 * ownership transfer. */
175 if (copy_boxed) {
176 g_assert (allocated_slice == 0);
177 boxed = g_boxed_copy (gtype, boxed);
180 self = (PyGIBoxed *) pytype->tp_alloc (pytype, 0);
181 if (self == NULL) {
182 return NULL;
185 /* We always free on dealloc because we always own the memory due to:
186 * 1) copy_boxed == TRUE
187 * 2) allocated_slice > 0
188 * 3) otherwise the mode is assumed "transfer everything".
190 ((PyGBoxed *)self)->free_on_dealloc = TRUE;
191 ((PyGBoxed *)self)->gtype = gtype;
192 pyg_boxed_set_ptr (self, boxed);
194 if (allocated_slice > 0) {
195 self->size = allocated_slice;
196 self->slice_allocated = TRUE;
197 } else {
198 self->size = 0;
199 self->slice_allocated = FALSE;
202 return (PyObject *) self;
205 static PyObject *
206 _pygi_boxed_get_free_on_dealloc(PyGIBoxed *self, void *closure)
208 return PyBool_FromLong( ((PyGBoxed *)self)->free_on_dealloc );
212 * _pygi_boxed_copy_in_place:
214 * Replace the boxed pointer held by this wrapper with a boxed copy
215 * freeing the previously held pointer (when free_on_dealloc is TRUE).
216 * This can be used in cases where Python is passed a reference which
217 * it does not own and the wrapper is held by the Python program
218 * longer than the duration of a callback it was passed to.
220 void
221 _pygi_boxed_copy_in_place (PyGIBoxed *self)
223 PyGBoxed *pygboxed = (PyGBoxed *)self;
224 gpointer copy = g_boxed_copy (pygboxed->gtype, pyg_boxed_get_ptr (self));
226 boxed_del (self);
227 pyg_boxed_set_ptr (pygboxed, copy);
228 pygboxed->free_on_dealloc = TRUE;
231 static PyGetSetDef pygi_boxed_getsets[] = {
232 { "_free_on_dealloc", (getter)_pygi_boxed_get_free_on_dealloc, (setter)0 },
233 { NULL, 0, 0 }
236 static PyMethodDef boxed_methods[] = {
237 { "__del__", (PyCFunction)boxed_del, METH_NOARGS },
238 { NULL, NULL, 0 }
241 void
242 _pygi_boxed_register_types (PyObject *m)
244 Py_TYPE(&PyGIBoxed_Type) = &PyType_Type;
245 PyGIBoxed_Type.tp_base = &PyGBoxed_Type;
246 PyGIBoxed_Type.tp_new = (newfunc) _boxed_new;
247 PyGIBoxed_Type.tp_init = (initproc) _boxed_init;
248 PyGIBoxed_Type.tp_dealloc = (destructor) _boxed_dealloc;
249 PyGIBoxed_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE);
250 PyGIBoxed_Type.tp_getset = pygi_boxed_getsets;
251 PyGIBoxed_Type.tp_methods = boxed_methods;
253 if (PyType_Ready (&PyGIBoxed_Type))
254 return;
255 if (PyModule_AddObject (m, "Boxed", (PyObject *) &PyGIBoxed_Type))
256 return;