diff options
Diffstat (limited to 'gi/pygi-source.c')
-rw-r--r-- | gi/pygi-source.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/gi/pygi-source.c b/gi/pygi-source.c new file mode 100644 index 0000000..66bbc3c --- /dev/null +++ b/gi/pygi-source.c @@ -0,0 +1,247 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 1998-2003 James Henstridge + * Copyright (C) 2005 Oracle + * Copyright (c) 2012 Canonical Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#define NO_IMPORT +#include "pygobject.h" + +#include "pygi-private.h" +#include "pyglib.h" +#include "pyglib-private.h" +#include "pygi-source.h" + +typedef struct +{ + GSource source; + PyObject *obj; +} PyGRealSource; + +static gboolean +pyg_source_prepare(GSource *source, gint *timeout) +{ + PyGRealSource *pysource = (PyGRealSource *)source; + PyObject *t; + gboolean ret = FALSE; + gboolean got_err = TRUE; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + + t = PyObject_CallMethod(pysource->obj, "prepare", NULL); + + if (t == NULL) { + goto bail; + } else if (!PyObject_IsTrue(t)) { + got_err = FALSE; + goto bail; + } else if (!PyTuple_Check(t)) { + PyErr_SetString(PyExc_TypeError, + "source prepare function must return a tuple or False"); + goto bail; + } else if (PyTuple_Size(t) != 2) { + PyErr_SetString(PyExc_TypeError, + "source prepare function return tuple must be exactly " + "2 elements long"); + goto bail; + } + + ret = PyObject_IsTrue(PyTuple_GET_ITEM(t, 0)); + *timeout = PYGLIB_PyLong_AsLong(PyTuple_GET_ITEM(t, 1)); + + if (*timeout == -1 && PyErr_Occurred()) { + ret = FALSE; + goto bail; + } + + got_err = FALSE; + +bail: + if (got_err) + PyErr_Print(); + + Py_XDECREF(t); + + pyglib_gil_state_release(state); + + return ret; +} + +static gboolean +pyg_source_check(GSource *source) +{ + PyGRealSource *pysource = (PyGRealSource *)source; + PyObject *t; + gboolean ret; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + + t = PyObject_CallMethod(pysource->obj, "check", NULL); + + if (t == NULL) { + PyErr_Print(); + ret = FALSE; + } else { + ret = PyObject_IsTrue(t); + Py_DECREF(t); + } + + pyglib_gil_state_release(state); + + return ret; +} + +static gboolean +pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) +{ + PyGRealSource *pysource = (PyGRealSource *)source; + PyObject *func, *args, *tuple, *t; + gboolean ret; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + + if (callback) { + tuple = user_data; + + func = PyTuple_GetItem(tuple, 0); + args = PyTuple_GetItem(tuple, 1); + } else { + func = Py_None; + args = Py_None; + } + + t = PyObject_CallMethod(pysource->obj, "dispatch", "OO", func, args); + + if (t == NULL) { + PyErr_Print(); + ret = FALSE; + } else { + ret = PyObject_IsTrue(t); + Py_DECREF(t); + } + + pyglib_gil_state_release(state); + + return ret; +} + +static void +pyg_source_finalize(GSource *source) +{ + PyGRealSource *pysource = (PyGRealSource *)source; + PyObject *func, *t; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + + func = PyObject_GetAttrString(pysource->obj, "finalize"); + if (func) { + t = PyObject_CallObject(func, NULL); + Py_DECREF(func); + + if (t == NULL) { + PyErr_Print(); + } else { + Py_DECREF(t); + } + } + + pyglib_gil_state_release(state); +} + +static GSourceFuncs pyg_source_funcs = +{ + pyg_source_prepare, + pyg_source_check, + pyg_source_dispatch, + pyg_source_finalize +}; + +PyObject * +pyg_source_set_callback(PyGObject *self_module, PyObject *args) +{ + PyObject *self, *first, *callback, *cbargs = NULL, *data; + gint len; + + len = PyTuple_Size (args); + if (len < 2) { + PyErr_SetString(PyExc_TypeError, + "set_callback requires at least 2 arguments"); + return NULL; + } + + first = PySequence_GetSlice(args, 0, 2); + if (!PyArg_ParseTuple(first, "OO:set_callback", &self, &callback)) { + Py_DECREF (first); + return NULL; + } + Py_DECREF(first); + + if (!pyg_boxed_check (self, G_TYPE_SOURCE)) { + PyErr_SetString(PyExc_TypeError, "first argument is not a GLib.Source"); + return NULL; + } + + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "second argument not callable"); + return NULL; + } + + cbargs = PySequence_GetSlice(args, 2, len); + if (cbargs == NULL) + return NULL; + + data = Py_BuildValue("(ON)", callback, cbargs); + if (data == NULL) + return NULL; + + g_source_set_callback(pyg_boxed_get (self, GSource), + _pyglib_handler_marshal, data, + _pyglib_destroy_notify); + + Py_INCREF(Py_None); + return Py_None; +} + +/** + * pyg_source_new: + * + * Wrap the un-bindable g_source_new() and provide wrapper callbacks in the + * GSourceFuncs which call back to Python. + */ +PyObject* +pyg_source_new (void) +{ + PyGRealSource *source = NULL; + PyObject *py_type; + + source = (PyGRealSource*) g_source_new (&pyg_source_funcs, sizeof (PyGRealSource)); + + py_type = _pygi_type_import_by_name ("GLib", "Source"); + /* g_source_new uses malloc, not slices */ + source->obj = _pygi_boxed_new ( (PyTypeObject *) py_type, source, FALSE, 0); + + return source->obj; +} |