diff options
-rw-r--r-- | gobject/Makefile.am | 1 | ||||
-rw-r--r-- | gobject/gobjectmodule.c | 53 | ||||
-rw-r--r-- | gobject/pygiochannel.c | 2 | ||||
-rw-r--r-- | gobject/pygobject-private.h | 7 | ||||
-rw-r--r-- | gobject/pygsource.c | 865 | ||||
-rw-r--r-- | tests/Makefile.am | 3 | ||||
-rw-r--r-- | tests/test_source.py | 66 |
7 files changed, 981 insertions, 16 deletions
diff --git a/gobject/Makefile.am b/gobject/Makefile.am index 78b0e14..2416fd5 100644 --- a/gobject/Makefile.am +++ b/gobject/Makefile.am @@ -29,6 +29,7 @@ gobject_la_SOURCES = \ pygparamspec.c \ pygpointer.c \ pygiochannel.c \ + pygsource.c \ pygtype.c if PLATFORM_WIN32 diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c index 19017ac..7e39334 100644 --- a/gobject/gobjectmodule.c +++ b/gobject/gobjectmodule.c @@ -1685,8 +1685,8 @@ get_handler_priority(gint *priority, PyObject *kwargs) return 0; } -static gboolean -handler_marshal(gpointer user_data) +gboolean +pyg_handler_marshal(gpointer user_data) { PyObject *tuple, *ret; gboolean res; @@ -1740,13 +1740,13 @@ pyg_idle_add(PyObject *self, PyObject *args, PyObject *kwargs) cbargs = PySequence_GetSlice(args, 1, len); if (cbargs == NULL) - return NULL; + return NULL; data = Py_BuildValue("(ON)", callback, cbargs); if (data == NULL) - return NULL; - handler_id = g_idle_add_full(priority, handler_marshal, data, - (GDestroyNotify)pyg_destroy_notify); + return NULL; + handler_id = g_idle_add_full(priority, pyg_handler_marshal, data, + pyg_destroy_notify); return PyInt_FromLong(handler_id); } @@ -1754,8 +1754,8 @@ static PyObject * pyg_timeout_add(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject *first, *callback, *cbargs = NULL, *data; - gint len, priority = G_PRIORITY_DEFAULT, interval; - guint handler_id; + gint len, priority = G_PRIORITY_DEFAULT; + guint interval, handler_id; len = PyTuple_Size(args); if (len < 2) { @@ -1764,7 +1764,7 @@ pyg_timeout_add(PyObject *self, PyObject *args, PyObject *kwargs) return NULL; } first = PySequence_GetSlice(args, 0, 2); - if (!PyArg_ParseTuple(first, "iO:timeout_add", &interval, &callback)) { + if (!PyArg_ParseTuple(first, "IO:timeout_add", &interval, &callback)) { Py_DECREF(first); return NULL; } @@ -1778,13 +1778,14 @@ pyg_timeout_add(PyObject *self, PyObject *args, PyObject *kwargs) cbargs = PySequence_GetSlice(args, 2, len); if (cbargs == NULL) - return NULL; + return NULL; data = Py_BuildValue("(ON)", callback, cbargs); if (data == NULL) - return NULL; - handler_id = g_timeout_add_full(priority, interval, handler_marshal, data, - (GDestroyNotify)pyg_destroy_notify); + return NULL; + handler_id = g_timeout_add_full(priority, interval, + pyg_handler_marshal, data, + pyg_destroy_notify); return PyInt_FromLong(handler_id); } @@ -2241,6 +2242,23 @@ pyg_markup_escape_text(PyObject *unused, PyObject *args, PyObject *kwargs) return retval; } +static PyObject * +pyg_get_current_time(PyObject *unused) +{ + GTimeVal timeval; + double ret; + + g_get_current_time(&timeval); + ret = (double)timeval.tv_sec + (double)timeval.tv_usec * 0.000001; + return PyFloat_FromDouble(ret); +} + +static PyObject * +pyg_main_depth(PyObject *unused) +{ + return PyInt_FromLong(g_main_depth()); +} + static PyMethodDef pygobject_functions[] = { { "type_name", pyg_type_name, METH_VARARGS }, { "type_from_name", pyg_type_from_name, METH_VARARGS }, @@ -2266,6 +2284,8 @@ static PyMethodDef pygobject_functions[] = { { "child_watch_add", (PyCFunction)pyg_child_watch_add, METH_VARARGS|METH_KEYWORDS }, { "spawn_async", (PyCFunction)pyg_spawn_async, METH_VARARGS|METH_KEYWORDS }, { "markup_escape_text", (PyCFunction)pyg_markup_escape_text, METH_VARARGS|METH_KEYWORDS }, + { "get_current_time", (PyCFunction)pyg_get_current_time, METH_NOARGS }, + { "main_depth", (PyCFunction)pyg_main_depth, METH_NOARGS }, { NULL, NULL, 0 } }; @@ -2774,7 +2794,12 @@ initgobject(void) REGISTER_TYPE(d, PyGMainContext_Type, "MainContext"); REGISTER_TYPE(d, PyGIOChannel_Type, "IOChannel"); - + + REGISTER_TYPE(d, PyGSource_Type, "Source"); + REGISTER_TYPE(d, PyGIdle_Type, "Idle"); + REGISTER_TYPE(d, PyGTimeout_Type, "Timeout"); + REGISTER_TYPE(d, PyGPollFD_Type, "PollFD"); + /* glib version */ tuple = Py_BuildValue ("(iii)", glib_major_version, glib_minor_version, glib_micro_version); diff --git a/gobject/pygiochannel.c b/gobject/pygiochannel.c index d161c10..ba3cfa1 100644 --- a/gobject/pygiochannel.c +++ b/gobject/pygiochannel.c @@ -266,7 +266,7 @@ py_io_channel_write_chars(PyGIOChannel* self, PyObject *args, PyObject *kwargs) pyg_unblock_threads(); status = g_io_channel_write_chars(self->channel, buf, buf_len, &count, &error); - pyg_unblock_threads(); + pyg_block_threads(); if (pyg_error_check(&error)) return NULL; diff --git a/gobject/pygobject-private.h b/gobject/pygobject-private.h index 22bcab6..192fde9 100644 --- a/gobject/pygobject-private.h +++ b/gobject/pygobject-private.h @@ -54,6 +54,7 @@ extern GQuark pygpointer_class_key; extern GQuark pygobject_has_updated_constructor_key; void pyg_destroy_notify (gpointer user_data); +gboolean pyg_handler_marshal (gpointer user_data); gboolean pyg_error_check (GError **error); int pygobject_constructv (PyGObject *self, guint n_parameters, @@ -196,5 +197,11 @@ PyObject * pyg_param_spec_new (GParamSpec *pspec); /* pygiochannel.c */ extern PyTypeObject PyGIOChannel_Type; +/* pygsource.c */ +extern PyTypeObject PyGSource_Type; +extern PyTypeObject PyGIdle_Type; +extern PyTypeObject PyGTimeout_Type; +extern PyTypeObject PyGPollFD_Type; + #endif diff --git a/gobject/pygsource.c b/gobject/pygsource.c new file mode 100644 index 0000000..2e49596 --- /dev/null +++ b/gobject/pygsource.c @@ -0,0 +1,865 @@ +/* -*- 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; + +typedef struct +{ + PyObject_HEAD + GPollFD pollfd; + PyObject *fd_obj; +} PyGPollFD; + + +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) +{ + PyGMainContext *py_context; + GMainContext *context; + + CHECK_DESTROYED(self, NULL); + + context = g_source_get_context(self->source); + + if (context) { + py_context = PyObject_NEW(PyGMainContext, &PyGMainContext_Type); + if (py_context == NULL) + return NULL; + + py_context->context = context; + + return (PyObject *)py_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_DECREF(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 */ +}; diff --git a/tests/Makefile.am b/tests/Makefile.am index 25a1a6d..b6ced0e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -30,7 +30,8 @@ tests = \ test_subprocess.py \ test_subtype.py \ test_gdkevent.py \ - test_unknown.py + test_unknown.py \ + test_source.py # This is a hack to make sure a shared library is built testhelper.la: $(testhelper_la_OBJECTS) $(testhelper_la_DEPENDENCIES) diff --git a/tests/test_source.py b/tests/test_source.py new file mode 100644 index 0000000..5e0f01b --- /dev/null +++ b/tests/test_source.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +import exceptions +import os +import sys +import select +import unittest + +from common import gobject + +class Idle(gobject.Idle): + def __init__(self, loop): + gobject.Idle.__init__(self) + self.count = 0 + self.set_callback(self.callback, loop) + + def callback(self, loop): + self.count += 1 + return True + +class MySource(gobject.Source): + def __init__(self): + gobject.Source.__init__(self) + + def prepare(self): + return True, 0 + + def check(self): + return True + + def dispatch(self, callback, args): + return callback(*args) + +class TestSource(unittest.TestCase): + def timeout_callback(self, loop): + loop.quit() + + def my_callback(self, loop): + self.pos += 1 + return True + + def setup_timeout(self, loop): + timeout = gobject.Timeout(500) + timeout.set_callback(self.timeout_callback, loop) + timeout.attach() + + def testSources(self): + loop = gobject.MainLoop() + + self.setup_timeout(loop) + + idle = Idle(loop) + idle.attach() + + self.pos = 0 + + m = MySource() + m.set_callback(self.my_callback, loop) + m.attach() + + loop.run() + + assert self.pos >= 0 and idle.count >= 0 + +if __name__ == '__main__': + unittest.main() |