diff options
Diffstat (limited to 'gi/pygi-boxed.c')
-rw-r--r-- | gi/pygi-boxed.c | 168 |
1 files changed, 118 insertions, 50 deletions
diff --git a/gi/pygi-boxed.c b/gi/pygi-boxed.c index 5bf2c19..9deb62a 100644 --- a/gi/pygi-boxed.c +++ b/gi/pygi-boxed.c @@ -16,38 +16,66 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pygi-private.h" +#include "pygi-boxed.h" +#include "pygi-info.h" +#include "pygboxed.h" +#include "pygi-type.h" +#include "pygi-basictype.h" +#include "pygi-util.h" -#include <pygobject.h> #include <girepository.h> -#include <pyglib-python-compat.h> + +struct _PyGIBoxed { + PyGBoxed base; + gboolean slice_allocated; + gsize size; +}; static void -_boxed_dealloc (PyGIBoxed *self) +boxed_clear (PyGIBoxed *self) { - GType g_type; + gpointer boxed = pyg_boxed_get_ptr (self); + GType g_type = ((PyGBoxed *)self)->gtype; - if ( ( (PyGBoxed *) self)->free_on_dealloc) { + if ( ( (PyGBoxed *) self)->free_on_dealloc && boxed != NULL) { if (self->slice_allocated) { - g_slice_free1 (self->size, ( (PyGBoxed *) self)->boxed); + if (g_type && g_type_is_a (g_type, G_TYPE_VALUE)) + g_value_unset (boxed); + g_slice_free1 (self->size, boxed); + self->slice_allocated = FALSE; + self->size = 0; } else { - g_type = pyg_type_from_object ( (PyObject *) self); - g_boxed_free (g_type, ( (PyGBoxed *) self)->boxed); + g_boxed_free (g_type, boxed); } } + pyg_boxed_set_ptr (self, NULL); +} - Py_TYPE( (PyGObject *) self)->tp_free ( (PyObject *) self); +static PyObject * +boxed_clear_wrapper (PyGIBoxed *self) +{ + boxed_clear (self); + + Py_RETURN_NONE; +} + + +static void +boxed_dealloc (PyGIBoxed *self) +{ + boxed_clear (self); + + Py_TYPE (self)->tp_free ((PyObject *)self); } void * -_pygi_boxed_alloc (GIBaseInfo *info, gsize *size_out) +pygi_boxed_alloc (GIBaseInfo *info, gsize *size_out) { - gsize size; + gpointer boxed = NULL; + gsize size = 0; switch (g_base_info_get_type (info)) { case GI_INFO_TYPE_UNION: @@ -64,28 +92,33 @@ _pygi_boxed_alloc (GIBaseInfo *info, gsize *size_out) return NULL; } + if (size == 0) { + PyErr_Format (PyExc_TypeError, + "boxed cannot be created directly; try using a constructor, see: help(%s.%s)", + g_base_info_get_namespace (info), + g_base_info_get_name (info)); + return NULL; + } + if( size_out != NULL) *size_out = size; - return g_slice_alloc0 (size); + boxed = g_slice_alloc0 (size); + if (boxed == NULL) + PyErr_NoMemory(); + return boxed; } static PyObject * -_boxed_new (PyTypeObject *type, +boxed_new (PyTypeObject *type, PyObject *args, PyObject *kwargs) { - static char *kwlist[] = { NULL }; - GIBaseInfo *info; gsize size = 0; gpointer boxed; PyGIBoxed *self = NULL; - if (!PyArg_ParseTupleAndKeywords (args, kwargs, "", kwlist)) { - return NULL; - } - info = _pygi_object_get_gi_info ( (PyObject *) type, &PyGIBaseInfo_Type); if (info == NULL) { if (PyErr_ExceptionMatches (PyExc_AttributeError)) { @@ -94,13 +127,12 @@ _boxed_new (PyTypeObject *type, return NULL; } - boxed = _pygi_boxed_alloc (info, &size); + boxed = pygi_boxed_alloc (info, &size); if (boxed == NULL) { - PyErr_NoMemory(); goto out; } - self = (PyGIBoxed *) _pygi_boxed_new (type, boxed, TRUE, size); + self = (PyGIBoxed *) pygi_boxed_new (type, boxed, TRUE, size); if (self == NULL) { g_slice_free1 (size, boxed); goto out; @@ -116,21 +148,30 @@ out: } static int -_boxed_init (PyObject *self, +boxed_init (PyObject *self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { NULL }; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "", kwlist)) { + PyErr_Clear (); + PyErr_Warn (PyExc_DeprecationWarning, + "Passing arguments to gi.types.Boxed.__init__() is deprecated. " + "All arguments passed will be ignored."); + } + /* Don't call PyGBoxed's init, which raises an exception. */ return 0; } -PYGLIB_DEFINE_TYPE("gi.Boxed", PyGIBoxed_Type, PyGIBoxed); +PYGI_DEFINE_TYPE("gi.Boxed", PyGIBoxed_Type, PyGIBoxed); PyObject * -_pygi_boxed_new (PyTypeObject *type, - gpointer boxed, - gboolean free_on_dealloc, - gsize allocated_slice) +pygi_boxed_new (PyTypeObject *type, + gpointer boxed, + gboolean free_on_dealloc, + gsize allocated_slice) { PyGIBoxed *self; @@ -149,8 +190,8 @@ _pygi_boxed_new (PyTypeObject *type, } ( (PyGBoxed *) self)->gtype = pyg_type_from_object ( (PyObject *) type); - ( (PyGBoxed *) self)->boxed = boxed; ( (PyGBoxed *) self)->free_on_dealloc = free_on_dealloc; + pyg_boxed_set_ptr (self, boxed); if (allocated_slice > 0) { self->size = allocated_slice; self->slice_allocated = TRUE; @@ -162,30 +203,57 @@ _pygi_boxed_new (PyTypeObject *type, return (PyObject *) self; } -static PyObject * -_pygi_boxed_get_free_on_dealloc(PyGIBoxed *self, void *closure) +/** + * pygi_boxed_copy_in_place: + * + * Replace the boxed pointer held by this wrapper with a boxed copy + * freeing the previously held pointer (when free_on_dealloc is TRUE). + * This can be used in cases where Python is passed a reference which + * it does not own and the wrapper is held by the Python program + * longer than the duration of a callback it was passed to. + */ +void +pygi_boxed_copy_in_place (PyGIBoxed *self) { - return PyBool_FromLong( ((PyGBoxed *)self)->free_on_dealloc ); + PyGBoxed *pygboxed = (PyGBoxed *)self; + gpointer ptr = pyg_boxed_get_ptr (self); + gpointer copy = NULL; + + if (ptr) + copy = g_boxed_copy (pygboxed->gtype, ptr); + + boxed_clear (self); + pyg_boxed_set_ptr (pygboxed, copy); + pygboxed->free_on_dealloc = TRUE; } -static PyGetSetDef pygi_boxed_getsets[] = { - { "_free_on_dealloc", (getter)_pygi_boxed_get_free_on_dealloc, (setter)0 }, - { NULL, 0, 0 } +static PyMethodDef boxed_methods[] = { + { "_clear_boxed", (PyCFunction)boxed_clear_wrapper, METH_NOARGS }, + { NULL, NULL, 0 } }; -void -_pygi_boxed_register_types (PyObject *m) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_boxed_register_types (PyObject *m) { - Py_TYPE(&PyGIBoxed_Type) = &PyType_Type; + Py_SET_TYPE(&PyGIBoxed_Type, &PyType_Type); + g_assert (Py_TYPE (&PyGBoxed_Type) != NULL); PyGIBoxed_Type.tp_base = &PyGBoxed_Type; - PyGIBoxed_Type.tp_new = (newfunc) _boxed_new; - PyGIBoxed_Type.tp_init = (initproc) _boxed_init; - PyGIBoxed_Type.tp_dealloc = (destructor) _boxed_dealloc; + PyGIBoxed_Type.tp_new = (newfunc) boxed_new; + PyGIBoxed_Type.tp_init = (initproc) boxed_init; + PyGIBoxed_Type.tp_dealloc = (destructor) boxed_dealloc; PyGIBoxed_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); - PyGIBoxed_Type.tp_getset = pygi_boxed_getsets; + PyGIBoxed_Type.tp_methods = boxed_methods; - if (PyType_Ready (&PyGIBoxed_Type)) - return; - if (PyModule_AddObject (m, "Boxed", (PyObject *) &PyGIBoxed_Type)) - return; + if (PyType_Ready (&PyGIBoxed_Type) < 0) + return -1; + Py_INCREF ((PyObject *) &PyGIBoxed_Type); + if (PyModule_AddObject (m, "Boxed", (PyObject *) &PyGIBoxed_Type) < 0) { + Py_DECREF ((PyObject *) &PyGIBoxed_Type); + return -1; + } + + return 0; } |