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"
25 #include "pygi-type.h"
26 #include "pygi-basictype.h"
27 #include "pygi-python-compat.h"
29 #include <girepository.h>
32 boxed_dealloc (PyGIBoxed
*self
)
34 Py_TYPE (self
)->tp_free ((PyObject
*)self
);
38 boxed_del (PyGIBoxed
*self
)
41 gpointer boxed
= pyg_boxed_get_ptr (self
);
43 if ( ( (PyGBoxed
*) self
)->free_on_dealloc
&& boxed
!= NULL
) {
44 if (self
->slice_allocated
) {
45 g_slice_free1 (self
->size
, boxed
);
46 self
->slice_allocated
= FALSE
;
49 g_type
= pyg_type_from_object ( (PyObject
*) self
);
50 g_boxed_free (g_type
, boxed
);
53 pyg_boxed_set_ptr (self
, NULL
);
59 pygi_boxed_alloc (GIBaseInfo
*info
, gsize
*size_out
)
61 gpointer boxed
= NULL
;
64 switch (g_base_info_get_type (info
)) {
65 case GI_INFO_TYPE_UNION
:
66 size
= g_union_info_get_size ( (GIUnionInfo
*) info
);
68 case GI_INFO_TYPE_BOXED
:
69 case GI_INFO_TYPE_STRUCT
:
70 size
= g_struct_info_get_size ( (GIStructInfo
*) info
);
73 PyErr_Format (PyExc_TypeError
,
74 "info should be Boxed or Union, not '%d'",
75 g_base_info_get_type (info
));
80 PyErr_Format (PyExc_TypeError
,
81 "boxed cannot be created directly; try using a constructor, see: help(%s.%s)",
82 g_base_info_get_namespace (info
),
83 g_base_info_get_name (info
));
90 boxed
= g_slice_alloc0 (size
);
97 boxed_new (PyTypeObject
*type
,
104 PyGIBoxed
*self
= NULL
;
106 info
= _pygi_object_get_gi_info ( (PyObject
*) type
, &PyGIBaseInfo_Type
);
108 if (PyErr_ExceptionMatches (PyExc_AttributeError
)) {
109 PyErr_Format (PyExc_TypeError
, "missing introspection information");
114 boxed
= pygi_boxed_alloc (info
, &size
);
119 self
= (PyGIBoxed
*) pygi_boxed_new (type
, boxed
, TRUE
, size
);
121 g_slice_free1 (size
, boxed
);
126 self
->slice_allocated
= TRUE
;
129 g_base_info_unref (info
);
131 return (PyObject
*) self
;
135 boxed_init (PyObject
*self
,
139 static char *kwlist
[] = { NULL
};
141 if (!PyArg_ParseTupleAndKeywords (args
, kwargs
, "", kwlist
)) {
143 PyErr_Warn (PyExc_DeprecationWarning
,
144 "Passing arguments to gi.types.Boxed.__init__() is deprecated. "
145 "All arguments passed will be ignored.");
148 /* Don't call PyGBoxed's init, which raises an exception. */
152 PYGLIB_DEFINE_TYPE("gi.Boxed", PyGIBoxed_Type
, PyGIBoxed
);
155 pygi_boxed_new (PyTypeObject
*type
,
157 gboolean free_on_dealloc
,
158 gsize allocated_slice
)
166 if (!PyType_IsSubtype (type
, &PyGIBoxed_Type
)) {
167 PyErr_SetString (PyExc_TypeError
, "must be a subtype of gi.Boxed");
171 self
= (PyGIBoxed
*) type
->tp_alloc (type
, 0);
176 ( (PyGBoxed
*) self
)->gtype
= pyg_type_from_object ( (PyObject
*) type
);
177 ( (PyGBoxed
*) self
)->free_on_dealloc
= free_on_dealloc
;
178 pyg_boxed_set_ptr (self
, boxed
);
179 if (allocated_slice
> 0) {
180 self
->size
= allocated_slice
;
181 self
->slice_allocated
= TRUE
;
184 self
->slice_allocated
= FALSE
;
187 return (PyObject
*) self
;
191 boxed_get_free_on_dealloc(PyGIBoxed
*self
, void *closure
)
193 return pygi_gboolean_to_py( ((PyGBoxed
*)self
)->free_on_dealloc
);
197 boxed_get_is_valid (PyGIBoxed
*self
, void *closure
)
199 return pygi_gboolean_to_py (pyg_boxed_get_ptr (self
) != NULL
);
203 * pygi_boxed_copy_in_place:
205 * Replace the boxed pointer held by this wrapper with a boxed copy
206 * freeing the previously held pointer (when free_on_dealloc is TRUE).
207 * This can be used in cases where Python is passed a reference which
208 * it does not own and the wrapper is held by the Python program
209 * longer than the duration of a callback it was passed to.
212 pygi_boxed_copy_in_place (PyGIBoxed
*self
)
214 PyGBoxed
*pygboxed
= (PyGBoxed
*)self
;
215 gpointer ptr
= pyg_boxed_get_ptr (self
);
216 gpointer copy
= NULL
;
219 copy
= g_boxed_copy (pygboxed
->gtype
, ptr
);
222 pyg_boxed_set_ptr (pygboxed
, copy
);
223 pygboxed
->free_on_dealloc
= TRUE
;
226 static PyGetSetDef pygi_boxed_getsets
[] = {
227 { "_free_on_dealloc", (getter
)boxed_get_free_on_dealloc
, (setter
)0 },
228 { "_is_valid", (getter
)boxed_get_is_valid
, (setter
)0 },
232 static PyMethodDef boxed_methods
[] = {
233 { "__del__", (PyCFunction
)boxed_del
, METH_NOARGS
},
238 * Returns 0 on success, or -1 and sets an exception.
241 pygi_boxed_register_types (PyObject
*m
)
243 Py_TYPE(&PyGIBoxed_Type
) = &PyType_Type
;
244 g_assert (Py_TYPE (&PyGBoxed_Type
) != NULL
);
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
) < 0)
255 Py_INCREF ((PyObject
*) &PyGIBoxed_Type
);
256 if (PyModule_AddObject (m
, "Boxed", (PyObject
*) &PyGIBoxed_Type
) < 0) {
257 Py_DECREF ((PyObject
*) &PyGIBoxed_Type
);