/* -*- Mode: C; c-basic-offset: 4 -*-
* pygtk- Python bindings for the GTK toolkit.
* Copyright (C) 1998-2003 James Henstridge
* Copyright (C) 2005 Oracle
*
* Author: Manish Singh <manish.singh@oracle.com>
*
* pygsource.c: GSource wrapper
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "pygobject-private.h"
#include "pythread.h"
#include <structmember.h>
#define CHECK_DESTROYED(self, ret) G_STMT_START { \
if ((self)->source == NULL) { \
PyErr_SetString(PyExc_RuntimeError, "source is destroyed"); \
return (ret); \
} \
} G_STMT_END
typedef struct {
PyObject_HEAD
GSource *source;
PyObject *inst_dict;
PyObject *weakreflist;
gboolean python_source;
} PyGSource;
typedef struct
{
GSource source;
PyObject *obj;
} PyGRealSource;
static PyObject *
source_repr(PyGSource *self, const char *type)
{
gchar buf[256], *desc;
if (self->source) {
if (g_source_get_context(self->source))
desc = "attached";
else
desc = "unattached";
} else {
desc = "destroyed";
}
if (type)
g_snprintf(buf, sizeof(buf), "<%s glib %s source at 0x%lx>",
desc, type, (long) self);
else
g_snprintf(buf, sizeof(buf), "<%s glib source at 0x%lx>",
desc, (long) self);
return PyString_FromString(buf);
}
static PyObject *
pyg_source_attach(PyGSource *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "context", NULL };
PyGMainContext *py_context = NULL;
GMainContext *context = NULL;
guint id;
if (!PyArg_ParseTupleAndKeywords (args, kwargs,
"|O!:attach", kwlist,
&PyGMainContext_Type, &py_context))
return NULL;
if (py_context)
context = py_context->context;
CHECK_DESTROYED(self, NULL);
if (self->python_source) {
PyGRealSource *pysource = (PyGRealSource *)self->source;
Py_INCREF(pysource->obj);
}
id = g_source_attach(self->source, context);
return PyInt_FromLong(id);
}
static PyObject *
pyg_source_destroy(PyGSource *self)
{
CHECK_DESTROYED(self, NULL);
if (self->python_source && self->source->context) {
PyGRealSource *pysource = (PyGRealSource *)self->source;
Py_DECREF(pysource->obj);
}
g_source_destroy(self->source);
self->source = NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
pyg_source_set_callback(PyGSource *self, PyObject *args)
{
PyObject *first, *callback, *cbargs = NULL, *data;
gint len;
CHECK_DESTROYED(self, NULL);
len = PyTuple_Size (args);
if (len < 1) {
PyErr_SetString(PyExc_TypeError,
"set_callback requires at least 1 argument");
return NULL;
}
first = PySequence_GetSlice(args, 0, 1);
if (!PyArg_ParseTuple(first, "O:set_callback", &callback)) {
Py_DECREF (first);
return NULL;
}
Py_DECREF(first);
if (!PyCallable_Check(callback)) {
PyErr_SetString(PyExc_TypeError, "first argument not callable");
return NULL;
}
cbargs = PySequence_GetSlice(args, 1, len);
if (cbargs == NULL)
return NULL;
data = Py_BuildValue("(ON)", callback, cbargs);
if (data == NULL)
return NULL;
g_source_set_callback(self->source, pyg_handler_marshal, data,
pyg_destroy_notify);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
pyg_source_get_context(PyGSource *self)
{
GMainContext *context;
CHECK_DESTROYED(self, NULL);
context = g_source_get_context(self->source);
if (context) {
return pyg_main_context_new(context);
} else {
Py_INCREF(Py_None);
return Py_None;
}
}
static PyObject *
pyg_source_add_poll(PyGSource *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "fd", NULL };
PyGPollFD *fd;
if (!self->python_source) {
PyErr_SetString(PyExc_TypeError,
"add_poll can only be used with sources "
"implemented in python");
return NULL;
}
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"O!:add_poll", kwlist,
&PyGPollFD_Type, &fd))
return NULL;
CHECK_DESTROYED(self, NULL);
g_source_add_poll(self->source, &fd->pollfd);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
pyg_source_remove_poll(PyGSource *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "fd", NULL };
PyGPollFD *fd;
if (!self->python_source) {
PyErr_SetString(PyExc_TypeError,
"remove_poll can only be used with sources "
"implemented in python");
return NULL;
}
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"O!:remove_poll", kwlist,
&PyGPollFD_Type, &fd))
return NULL;
CHECK_DESTROYED(self, NULL);
g_source_remove_poll(self->source, &fd->pollfd);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
pyg_source_get_current_time(PyGSource *self)
{
GTimeVal timeval;
double ret;
CHECK_DESTROYED(self, NULL);
g_source_get_current_time(self->source, &timeval);
ret = (double)timeval.tv_sec + (double)timeval.tv_usec * 0.000001;
return PyFloat_FromDouble(ret);
}
static PyMethodDef pyg_source_methods[] = {
{ "attach", (PyCFunction)pyg_source_attach, METH_KEYWORDS },
{ "destroy", (PyCFunction)pyg_source_destroy, METH_NOARGS },
{ "set_callback", (PyCFunction)pyg_source_set_callback, METH_VARARGS },
{ "get_context", (PyCFunction)pyg_source_get_context, METH_NOARGS },
{ "add_poll", (PyCFunction)pyg_source_add_poll, METH_KEYWORDS },
{ "remove_poll", (PyCFunction)pyg_source_remove_poll, METH_KEYWORDS },
{ "get_current_time", (PyCFunction)pyg_source_get_current_time, METH_NOARGS },
{ NULL, NULL, 0 }
};
static PyObject *
pyg_source_get_dict(PyGSource *self, void *closure)
{
if (self->inst_dict == NULL) {
self->inst_dict = PyDict_New();
if (self->inst_dict == NULL)
return NULL;
}
Py_INCREF(self->inst_dict);
return self->inst_dict;
}
static PyObject *
pyg_source_get_priority(PyGSource *self, void *closure)
{
CHECK_DESTROYED(self, NULL);
return PyInt_FromLong(g_source_get_priority(self->source));
}
static int
pyg_source_set_priority(PyGSource *self, PyObject *value, void *closure)
{
CHECK_DESTROYED(self, -1);
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "cannot delete priority");
return -1;
}
if (!PyInt_Check(value)) {
PyErr_SetString(PyExc_TypeError, "type mismatch");
return -1;
}
g_source_set_priority(self->source, PyInt_AsLong(value));
return 0;
}
static PyObject *
pyg_source_get_can_recurse(PyGSource *self, void *closure)
{
CHECK_DESTROYED(self, NULL);
return PyBool_FromLong(g_source_get_can_recurse(self->source));
}
static int
pyg_source_set_can_recurse(PyGSource *self, PyObject *value, void *closure)
{
CHECK_DESTROYED(self, -1);
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "cannot delete can_recurse");
return -1;
}
g_source_set_can_recurse(self->source, PyObject_IsTrue(value));
return 0;
}
static PyObject *
pyg_source_get_id(PyGSource *self, void *closure)
{
CHECK_DESTROYED(self, NULL);
if (g_source_get_context(self->source) == NULL) {
PyErr_SetString(PyExc_RuntimeError, "source is not attached");
return NULL;
}
return PyInt_FromLong(g_source_get_id(self->source));
}
static PyGetSetDef pyg_source_getsets[] = {
{ "__dict__", (getter)pyg_source_get_dict, (setter)0 },
{"priority", (getter)pyg_source_get_priority, (setter)pyg_source_set_priority },
{"can_recurse", (getter)pyg_source_get_can_recurse, (setter)pyg_source_set_can_recurse },
{"id", (getter)pyg_source_get_id, (setter)0 },
{NULL, 0, 0}
};
static PyObject *
pyg_source_repr(PyGSource *self)
{
return source_repr(self, NULL);
}
static int
pyg_source_traverse(PyGSource *self, visitproc visit, void *arg)
{
int ret = 0;
if (self->inst_dict) ret = visit(self->inst_dict, arg);
if (ret != 0) return ret;
return 0;
}
static int
pyg_source_clear(PyGSource *self)
{
PyObject *tmp;
tmp = self->inst_dict;
self->inst_dict = NULL;
Py_XDECREF(tmp);
if (self->source) {
g_source_unref(self->source);
self->source = NULL;
}
return 0;
}
static void
pyg_source_dealloc(PyGSource *self)
{
PyObject_ClearWeakRefs((PyObject *)self);
PyObject_GC_UnTrack((PyObject *)self);
pyg_source_clear(self);
PyObject_GC_Del(self);
}
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 = pyg_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));
if (ret) {
*timeout = PyInt_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);
pyg_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 = pyg_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);
}
pyg_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 = pyg_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);
}
pyg_gil_state_release(state);
return ret;
}
static void
pyg_source_finalize(GSource *source)
{
PyGRealSource *pysource = (PyGRealSource *)source;
PyObject *func, *t;
PyGILState_STATE state;
state = pyg_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);
}
}
pyg_gil_state_release(state);
}
static GSourceFuncs pyg_source_funcs =
{
pyg_source_prepare,
pyg_source_check,
pyg_source_dispatch,
pyg_source_finalize
};
static int
pyg_source_init(PyGSource *self, PyObject *args, PyObject *kwargs)
{
PyGRealSource *pysource;
self->source = g_source_new(&pyg_source_funcs, sizeof(PyGRealSource));
pysource = (PyGRealSource *)self->source;
pysource->obj = (PyObject*)self;
self->inst_dict = NULL;
self->weakreflist = NULL;
self->python_source = TRUE;
return 0;
}
static void
pyg_source_free(PyObject *op)
{
PyObject_GC_Del(op);
}
PyTypeObject PyGSource_Type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"gobject.Source", /* tp_name */
sizeof(PyGSource), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)pyg_source_dealloc, /* tp_dealloc */
(printfunc)0, /* tp_print */
(getattrfunc)0, /* tp_getattr */
(setattrfunc)0, /* tp_setattr */
(cmpfunc)0, /* tp_compare */
(reprfunc)pyg_source_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)0, /* tp_hash */
(ternaryfunc)0, /* tp_call */
(reprfunc)0, /* tp_str */
(getattrofunc)0, /* tp_getattro */
(setattrofunc)0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_HAVE_GC, /* tp_flags */
NULL, /* tp_doc */
(traverseproc)pyg_source_traverse, /* tp_traverse */
(inquiry)pyg_source_clear, /* tp_clear */
(richcmpfunc)0, /* tp_richcompare */
offsetof(PyGSource, weakreflist), /* tp_weaklistoffset */
(getiterfunc)0, /* tp_iter */
(iternextfunc)0, /* tp_iternext */
pyg_source_methods, /* tp_methods */
0, /* tp_members */
pyg_source_getsets, /* tp_getset */
(PyTypeObject *)0, /* tp_base */
(PyObject *)0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(PyGSource, inst_dict), /* tp_dictoffset */
(initproc)pyg_source_init, /* tp_init */
(allocfunc)0, /* tp_alloc */
(newfunc)0, /* tp_new */
(freefunc)pyg_source_free, /* tp_free */
(inquiry)0, /* tp_is_gc */
(PyObject *)0, /* tp_bases */
};
static PyObject *
pyg_idle_repr(PyGSource *self)
{
return source_repr(self, "idle");
}
static int
pyg_idle_init(PyGSource *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "priority", NULL };
gint priority = G_PRIORITY_DEFAULT_IDLE;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"|i:gobject.Idle.__init__", kwlist,
&priority))
return -1;
self->source = g_idle_source_new ();
if (priority != G_PRIORITY_DEFAULT_IDLE)
g_source_set_priority(self->source, priority);
self->inst_dict = NULL;
self->weakreflist = NULL;
self->python_source = FALSE;
return 0;
}
PyTypeObject PyGIdle_Type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"gobject.Idle", /* tp_name */
sizeof(PyGSource), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)0, /* tp_dealloc */
(printfunc)0, /* tp_print */
(getattrfunc)0, /* tp_getattr */
(setattrfunc)0, /* tp_setattr */
(cmpfunc)0, /* tp_compare */
(reprfunc)pyg_idle_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)0, /* tp_hash */
(ternaryfunc)0, /* tp_call */
(reprfunc)0, /* tp_str */
(getattrofunc)0, /* tp_getattro */
(setattrofunc)0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_HAVE_GC, /* tp_flags */
NULL, /* tp_doc */
(traverseproc)0, /* tp_traverse */
(inquiry)0, /* tp_clear */
(richcmpfunc)0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)0, /* tp_iter */
(iternextfunc)0, /* tp_iternext */
NULL, /* tp_methods */
NULL, /* tp_members */
NULL, /* tp_getset */
(PyTypeObject *)&PyGSource_Type, /* tp_base */
(PyObject *)0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)pyg_idle_init, /* tp_init */
(allocfunc)0, /* tp_alloc */
(newfunc)0, /* tp_new */
(freefunc)0, /* tp_free */
(inquiry)0, /* tp_is_gc */
(PyObject *)0, /* tp_bases */
};
static PyObject *
pyg_timeout_repr(PyGSource *self)
{
return source_repr(self, "timeout");
}
static int
pyg_timeout_init(PyGSource *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "interval", "priority", NULL };
gint priority = G_PRIORITY_DEFAULT;
guint interval;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"I|i:gobject.Timeout.__init__", kwlist,
&interval, &priority))
return -1;
self->source = g_timeout_source_new(interval);
if (priority != G_PRIORITY_DEFAULT)
g_source_set_priority(self->source, priority);
self->inst_dict = NULL;
self->weakreflist = NULL;
self->python_source = FALSE;
return 0;
}
PyTypeObject PyGTimeout_Type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"gobject.Timeout", /* tp_name */
sizeof(PyGSource), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)0, /* tp_dealloc */
(printfunc)0, /* tp_print */
(getattrfunc)0, /* tp_getattr */
(setattrfunc)0, /* tp_setattr */
(cmpfunc)0, /* tp_compare */
(reprfunc)pyg_timeout_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)0, /* tp_hash */
(ternaryfunc)0, /* tp_call */
(reprfunc)0, /* tp_str */
(getattrofunc)0, /* tp_getattro */
(setattrofunc)0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_HAVE_GC, /* tp_flags */
NULL, /* tp_doc */
(traverseproc)0, /* tp_traverse */
(inquiry)0, /* tp_clear */
(richcmpfunc)0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)0, /* tp_iter */
(iternextfunc)0, /* tp_iternext */
NULL, /* tp_methods */
NULL, /* tp_members */
NULL, /* tp_getset */
(PyTypeObject *)&PyGSource_Type, /* tp_base */
(PyObject *)0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)pyg_timeout_init, /* tp_init */
(allocfunc)0, /* tp_alloc */
(newfunc)0, /* tp_new */
(freefunc)0, /* tp_free */
(inquiry)0, /* tp_is_gc */
(PyObject *)0, /* tp_bases */
};
static PyMemberDef pyg_poll_fd_members[] = {
{ "fd", T_INT, offsetof(PyGPollFD, pollfd.fd), RO },
{ "events", T_USHORT, offsetof(PyGPollFD, pollfd.events), RO },
{ "revents", T_USHORT, offsetof(PyGPollFD, pollfd.revents), RO },
{ NULL, 0, 0, 0 }
};
static void
pyg_poll_fd_dealloc(PyGPollFD *self)
{
Py_XDECREF(self->fd_obj);
PyObject_DEL(self);
}
static PyObject *
pyg_poll_fd_repr(PyGPollFD *self)
{
return PyString_FromFormat("<GPollFD %d (%d) at 0x%lx>",
self->pollfd.fd, self->pollfd.events,
(long)self);
}
static int
pyg_poll_fd_init(PyGPollFD *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "fd", "events", NULL };
PyObject *o;
gint fd;
gushort events;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"OH:gobject.PollFD.__init__", kwlist,
&o, &events))
return -1;
fd = PyObject_AsFileDescriptor(o);
if (fd == -1)
return -1;
self->pollfd.fd = fd;
self->pollfd.events = events;
self->pollfd.revents = 0;
Py_INCREF(o);
self->fd_obj = o;
return 0;
}
PyTypeObject PyGPollFD_Type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"gobject.PollFD", /* tp_name */
sizeof(PyGPollFD), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)pyg_poll_fd_dealloc, /* tp_dealloc */
(printfunc)0, /* tp_print */
(getattrfunc)0, /* tp_getattr */
(setattrfunc)0, /* tp_setattr */
(cmpfunc)0, /* tp_compare */
(reprfunc)pyg_poll_fd_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)0, /* tp_hash */
(ternaryfunc)0, /* tp_call */
(reprfunc)0, /* tp_str */
(getattrofunc)0, /* tp_getattro */
(setattrofunc)0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
NULL, /* tp_doc */
(traverseproc)0, /* tp_traverse */
(inquiry)0, /* tp_clear */
(richcmpfunc)0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)0, /* tp_iter */
(iternextfunc)0, /* tp_iternext */
0, /* tp_methods */
pyg_poll_fd_members, /* tp_members */
0, /* tp_getset */
(PyTypeObject *)0, /* tp_base */
(PyObject *)0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)pyg_poll_fd_init, /* tp_init */
(allocfunc)0, /* tp_alloc */
(newfunc)0, /* tp_new */
(freefunc)0, /* tp_free */
(inquiry)0, /* tp_is_gc */
(PyObject *)0, /* tp_bases */
};
syntax highlighted by Code2HTML, v. 0.9.1