summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gobject/Makefile.am1
-rw-r--r--gobject/gobjectmodule.c53
-rw-r--r--gobject/pygiochannel.c2
-rw-r--r--gobject/pygobject-private.h7
-rw-r--r--gobject/pygsource.c865
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/test_source.py66
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()