/* -*- 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. */ #include "pygi-info.h" #include "pygi-boxed.h" #include "pygi-type.h" #include "pygi-basictype.h" #include "pygboxed.h" #include "pygi-source.h" typedef struct { GSource source; PyObject *obj; } PyGRealSource; static gboolean source_prepare(GSource *source, gint *timeout) { PyGRealSource *pysource = (PyGRealSource *)source; PyObject *t; gboolean ret = FALSE; gboolean got_err = TRUE; PyGILState_STATE state; state = PyGILState_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; } if (!pygi_gboolean_from_py (PyTuple_GET_ITEM(t, 0), &ret)) { ret = FALSE; goto bail; } if (!pygi_gint_from_py (PyTuple_GET_ITEM(t, 1), timeout)) { ret = FALSE; goto bail; } got_err = FALSE; bail: if (got_err) PyErr_Print(); Py_XDECREF(t); PyGILState_Release(state); return ret; } static gboolean source_check(GSource *source) { PyGRealSource *pysource = (PyGRealSource *)source; PyObject *t; gboolean ret; PyGILState_STATE state; state = PyGILState_Ensure(); t = PyObject_CallMethod(pysource->obj, "check", NULL); if (t == NULL) { PyErr_Print(); ret = FALSE; } else { ret = PyObject_IsTrue(t); Py_DECREF(t); } PyGILState_Release(state); return ret; } static gboolean source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { PyGRealSource *pysource = (PyGRealSource *)source; PyObject *func, *args, *tuple, *t; gboolean ret; PyGILState_STATE state; state = PyGILState_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); } PyGILState_Release(state); return ret; } static void source_finalize(GSource *source) { PyGRealSource *pysource = (PyGRealSource *)source; PyObject *func, *t; PyGILState_STATE state; state = PyGILState_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); } } else { PyErr_Clear (); } PyGILState_Release(state); } static GSourceFuncs pyg_source_funcs = { source_prepare, source_check, source_dispatch, source_finalize }; /** * _pyglib_destroy_notify: * @user_data: a PyObject pointer. * * A function that can be used as a GDestroyNotify callback that will * call Py_DECREF on the data. */ static void destroy_notify(gpointer user_data) { PyObject *obj = (PyObject *)user_data; PyGILState_STATE state; state = PyGILState_Ensure(); Py_DECREF(obj); PyGILState_Release(state); } static gboolean handler_marshal(gpointer user_data) { PyObject *tuple, *ret; gboolean res; PyGILState_STATE state; g_return_val_if_fail(user_data != NULL, FALSE); state = PyGILState_Ensure(); tuple = (PyObject *)user_data; ret = PyObject_CallObject(PyTuple_GetItem(tuple, 0), PyTuple_GetItem(tuple, 1)); if (!ret) { PyErr_Print(); res = FALSE; } else { res = PyObject_IsTrue(ret); Py_DECREF(ret); } PyGILState_Release(state); return res; } PyObject * pygi_source_set_callback (PyGObject *self_module, PyObject *args) { PyObject *self, *first, *callback, *cbargs = NULL, *data; Py_ssize_t 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), handler_marshal, data, destroy_notify); Py_INCREF(Py_None); return Py_None; } /** * pygi_source_new: * * Wrap the un-bindable g_source_new() and provide wrapper callbacks in the * GSourceFuncs which call back to Python. * * Returns NULL on error and sets an exception. */ PyObject* pygi_source_new (PyObject *self, PyObject *args) { PyGRealSource *source; PyObject *py_type, *boxed; g_assert (args == NULL); py_type = pygi_type_import_by_name ("GLib", "Source"); if (!py_type) return NULL; source = (PyGRealSource*) g_source_new (&pyg_source_funcs, sizeof (PyGRealSource)); /* g_source_new uses malloc, not slices */ boxed = pygi_boxed_new ( (PyTypeObject *) py_type, source, TRUE, 0); Py_DECREF (py_type); if (!boxed) { g_source_unref ((GSource *)source); return NULL; } source->obj = boxed; return source->obj; }