1 /* -*- Mode: C; c-basic-offset: 4 -*-
2 * pygtk- Python bindings for the GTK toolkit.
3 * Copyright (C) 1998-2003 James Henstridge
4 * Copyright (C) 2005 Oracle
6 * Author: Manish Singh <manish.singh@oracle.com>
8 * pygsource.c: GSource wrapper
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
32 #include <structmember.h> /* for PyMemberDef */
34 #include "pyglib-private.h"
35 #include "pygmaincontext.h"
36 #include "pygsource.h"
38 #define CHECK_DESTROYED(self, ret) G_STMT_START { \
39 if ((self)->source == NULL) { \
40 PyErr_SetString(PyExc_RuntimeError, "source is destroyed"); \
50 PyObject *weakreflist;
51 gboolean python_source;
62 PYGLIB_DEFINE_TYPE("gi._glib.Source", PyGSource_Type, PyGSource)
65 source_repr(PyGSource *self, const char *type)
67 gchar buf[256], *desc;
70 if (g_source_get_context(self->source))
79 g_snprintf(buf, sizeof(buf), "<%s glib %s source at 0x%lx>",
80 desc, type, (long) self);
82 g_snprintf(buf, sizeof(buf), "<%s glib source at 0x%lx>",
85 return PYGLIB_PyUnicode_FromString(buf);
89 pyg_source_attach(PyGSource *self, PyObject *args, PyObject *kwargs)
91 static char *kwlist[] = { "context", NULL };
92 PyGMainContext *py_context = NULL;
93 GMainContext *context = NULL;
96 if (!PyArg_ParseTupleAndKeywords (args, kwargs,
98 &PyGMainContext_Type, &py_context))
102 context = py_context->context;
104 CHECK_DESTROYED(self, NULL);
106 if (self->python_source) {
107 PyGRealSource *pysource = (PyGRealSource *)self->source;
108 Py_INCREF(pysource->obj);
111 id = g_source_attach(self->source, context);
112 return PYGLIB_PyLong_FromLong(id);
116 pyg_source_destroy(PyGSource *self)
118 CHECK_DESTROYED(self, NULL);
120 if (self->python_source && self->source->context) {
121 PyGRealSource *pysource = (PyGRealSource *)self->source;
122 Py_DECREF(pysource->obj);
125 g_source_destroy(self->source);
133 pyg_source_is_destroyed(PyGSource *self)
137 if (self->source == NULL || g_source_is_destroyed(self->source))
147 pyg_source_set_callback(PyGSource *self, PyObject *args)
149 PyObject *first, *callback, *cbargs = NULL, *data;
152 CHECK_DESTROYED(self, NULL);
154 len = PyTuple_Size (args);
156 PyErr_SetString(PyExc_TypeError,
157 "set_callback requires at least 1 argument");
161 first = PySequence_GetSlice(args, 0, 1);
162 if (!PyArg_ParseTuple(first, "O:set_callback", &callback)) {
168 if (!PyCallable_Check(callback)) {
169 PyErr_SetString(PyExc_TypeError, "first argument not callable");
173 cbargs = PySequence_GetSlice(args, 1, len);
177 data = Py_BuildValue("(ON)", callback, cbargs);
181 g_source_set_callback(self->source,
182 _pyglib_handler_marshal, data,
183 _pyglib_destroy_notify);
190 pyg_source_get_context(PyGSource *self)
192 GMainContext *context;
194 CHECK_DESTROYED(self, NULL);
196 context = g_source_get_context(self->source);
199 return pyg_main_context_new(context);
207 pyg_source_add_poll(PyGSource *self, PyObject *args, PyObject *kwargs)
209 static char *kwlist[] = { "fd", NULL };
212 if (!self->python_source) {
213 PyErr_SetString(PyExc_TypeError,
214 "add_poll can only be used with sources "
215 "implemented in python");
219 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
220 "O!:add_poll", kwlist,
221 &PyGPollFD_Type, &fd))
224 CHECK_DESTROYED(self, NULL);
226 g_source_add_poll(self->source, &fd->pollfd);
233 pyg_source_remove_poll(PyGSource *self, PyObject *args, PyObject *kwargs)
235 static char *kwlist[] = { "fd", NULL };
238 if (!self->python_source) {
239 PyErr_SetString(PyExc_TypeError,
240 "remove_poll can only be used with sources "
241 "implemented in python");
245 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
246 "O!:remove_poll", kwlist,
247 &PyGPollFD_Type, &fd))
250 CHECK_DESTROYED(self, NULL);
252 g_source_remove_poll(self->source, &fd->pollfd);
259 pyg_source_get_current_time(PyGSource *self)
263 CHECK_DESTROYED(self, NULL);
265 ret = g_get_real_time() * 0.000001;
266 return PyFloat_FromDouble(ret);
269 static PyMethodDef pyg_source_methods[] = {
270 { "attach", (PyCFunction)pyg_source_attach, METH_VARARGS|METH_KEYWORDS },
271 { "destroy", (PyCFunction)pyg_source_destroy, METH_NOARGS },
272 { "is_destroyed", (PyCFunction)pyg_source_is_destroyed, METH_NOARGS },
273 { "set_callback", (PyCFunction)pyg_source_set_callback, METH_VARARGS },
274 { "get_context", (PyCFunction)pyg_source_get_context, METH_NOARGS },
275 { "add_poll", (PyCFunction)pyg_source_add_poll, METH_KEYWORDS },
276 { "remove_poll", (PyCFunction)pyg_source_remove_poll, METH_VARARGS|METH_KEYWORDS },
277 { "get_current_time", (PyCFunction)pyg_source_get_current_time, METH_NOARGS },
282 pyg_source_get_dict(PyGSource *self, void *closure)
284 if (self->inst_dict == NULL) {
285 self->inst_dict = PyDict_New();
286 if (self->inst_dict == NULL)
290 Py_INCREF(self->inst_dict);
291 return self->inst_dict;
295 pyg_source_get_priority(PyGSource *self, void *closure)
297 CHECK_DESTROYED(self, NULL);
299 return PYGLIB_PyLong_FromLong(g_source_get_priority(self->source));
303 pyg_source_set_priority(PyGSource *self, PyObject *value, void *closure)
305 CHECK_DESTROYED(self, -1);
308 PyErr_SetString(PyExc_TypeError, "cannot delete priority");
312 if (!PYGLIB_PyLong_Check(value)) {
313 PyErr_SetString(PyExc_TypeError, "type mismatch");
317 g_source_set_priority(self->source, PYGLIB_PyLong_AsLong(value));
323 pyg_source_get_can_recurse(PyGSource *self, void *closure)
325 CHECK_DESTROYED(self, NULL);
327 return PyBool_FromLong(g_source_get_can_recurse(self->source));
331 pyg_source_set_can_recurse(PyGSource *self, PyObject *value, void *closure)
333 CHECK_DESTROYED(self, -1);
336 PyErr_SetString(PyExc_TypeError, "cannot delete can_recurse");
340 g_source_set_can_recurse(self->source, PyObject_IsTrue(value));
346 pyg_source_get_id(PyGSource *self, void *closure)
348 CHECK_DESTROYED(self, NULL);
350 if (g_source_get_context(self->source) == NULL) {
351 PyErr_SetString(PyExc_RuntimeError, "source is not attached");
355 return PYGLIB_PyLong_FromLong(g_source_get_id(self->source));
358 static PyGetSetDef pyg_source_getsets[] = {
359 { "__dict__", (getter)pyg_source_get_dict, (setter)0 },
360 {"priority", (getter)pyg_source_get_priority, (setter)pyg_source_set_priority },
361 {"can_recurse", (getter)pyg_source_get_can_recurse, (setter)pyg_source_set_can_recurse },
362 {"id", (getter)pyg_source_get_id, (setter)0 },
367 pyg_source_repr(PyGSource *self)
369 return source_repr(self, NULL);
373 pyg_source_traverse(PyGSource *self, visitproc visit, void *arg)
377 if (self->inst_dict) ret = visit(self->inst_dict, arg);
378 if (ret != 0) return ret;
384 pyg_source_clear(PyGSource *self)
388 tmp = self->inst_dict;
389 self->inst_dict = NULL;
393 g_source_unref(self->source);
401 pyg_source_dealloc(PyGSource *self)
403 /* Must be done first, so that there is no chance of Python's GC being
404 * called while tracking this half-deallocated object */
405 PyObject_GC_UnTrack((PyObject *)self);
407 PyObject_ClearWeakRefs((PyObject *)self);
409 pyg_source_clear(self);
411 PyObject_GC_Del(self);
415 pyg_source_prepare(GSource *source, gint *timeout)
417 PyGRealSource *pysource = (PyGRealSource *)source;
419 gboolean ret = FALSE;
420 gboolean got_err = TRUE;
421 PyGILState_STATE state;
423 state = pyglib_gil_state_ensure();
425 t = PyObject_CallMethod(pysource->obj, "prepare", NULL);
429 } else if (!PyObject_IsTrue(t)) {
432 } else if (!PyTuple_Check(t)) {
433 PyErr_SetString(PyExc_TypeError,
434 "source prepare function must return a tuple or False");
436 } else if (PyTuple_Size(t) != 2) {
437 PyErr_SetString(PyExc_TypeError,
438 "source prepare function return tuple must be exactly "
443 ret = PyObject_IsTrue(PyTuple_GET_ITEM(t, 0));
444 *timeout = PYGLIB_PyLong_AsLong(PyTuple_GET_ITEM(t, 1));
446 if (*timeout == -1 && PyErr_Occurred()) {
459 pyglib_gil_state_release(state);
465 pyg_source_check(GSource *source)
467 PyGRealSource *pysource = (PyGRealSource *)source;
470 PyGILState_STATE state;
472 state = pyglib_gil_state_ensure();
474 t = PyObject_CallMethod(pysource->obj, "check", NULL);
480 ret = PyObject_IsTrue(t);
484 pyglib_gil_state_release(state);
490 pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
492 PyGRealSource *pysource = (PyGRealSource *)source;
493 PyObject *func, *args, *tuple, *t;
495 PyGILState_STATE state;
497 state = pyglib_gil_state_ensure();
502 func = PyTuple_GetItem(tuple, 0);
503 args = PyTuple_GetItem(tuple, 1);
509 t = PyObject_CallMethod(pysource->obj, "dispatch", "OO", func, args);
515 ret = PyObject_IsTrue(t);
519 pyglib_gil_state_release(state);
525 pyg_source_finalize(GSource *source)
527 PyGRealSource *pysource = (PyGRealSource *)source;
529 PyGILState_STATE state;
531 state = pyglib_gil_state_ensure();
533 func = PyObject_GetAttrString(pysource->obj, "finalize");
535 t = PyObject_CallObject(func, NULL);
545 pyglib_gil_state_release(state);
548 static GSourceFuncs pyg_source_funcs =
557 pyg_source_init(PyGSource *self, PyObject *args, PyObject *kwargs)
559 PyGRealSource *pysource;
561 self->source = g_source_new(&pyg_source_funcs, sizeof(PyGRealSource));
563 pysource = (PyGRealSource *)self->source;
564 pysource->obj = (PyObject*)self;
566 self->inst_dict = NULL;
567 self->weakreflist = NULL;
569 self->python_source = TRUE;
575 pyg_source_free(PyObject *op)
582 PYGLIB_DEFINE_TYPE("gi._glib.Idle", PyGIdle_Type, PyGSource)
585 pyg_idle_repr(PyGSource *self)
587 return source_repr(self, "idle");
591 pyg_idle_init(PyGSource *self, PyObject *args, PyObject *kwargs)
593 static char *kwlist[] = { "priority", NULL };
594 gint priority = G_PRIORITY_DEFAULT_IDLE;
596 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
597 "|i:gi._glib.Idle.__init__", kwlist,
601 self->source = g_idle_source_new ();
603 if (priority != G_PRIORITY_DEFAULT_IDLE)
604 g_source_set_priority(self->source, priority);
606 self->inst_dict = NULL;
607 self->weakreflist = NULL;
609 self->python_source = FALSE;
616 PYGLIB_DEFINE_TYPE("gi._glib.Timeout", PyGTimeout_Type, PyGSource)
619 pyg_timeout_repr(PyGSource *self)
621 return source_repr(self, "timeout");
625 pyg_timeout_init(PyGSource *self, PyObject *args, PyObject *kwargs)
627 static char *kwlist[] = { "interval", "priority", NULL };
628 gint priority = G_PRIORITY_DEFAULT;
631 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
632 "I|i:gi._glib.Timeout.__init__", kwlist,
633 &interval, &priority))
636 self->source = g_timeout_source_new(interval);
638 if (priority != G_PRIORITY_DEFAULT)
639 g_source_set_priority(self->source, priority);
641 self->inst_dict = NULL;
642 self->weakreflist = NULL;
644 self->python_source = FALSE;
651 PYGLIB_DEFINE_TYPE("gi._glib.PollFD", PyGPollFD_Type, PyGPollFD)
653 static PyMemberDef pyg_poll_fd_members[] = {
654 { "fd", T_INT, offsetof(PyGPollFD, pollfd.fd), READONLY },
655 { "events", T_USHORT, offsetof(PyGPollFD, pollfd.events), READONLY },
656 { "revents", T_USHORT, offsetof(PyGPollFD, pollfd.revents), READONLY },
661 pyg_poll_fd_dealloc(PyGPollFD *self)
663 Py_XDECREF(self->fd_obj);
668 pyg_poll_fd_repr(PyGPollFD *self)
670 return PYGLIB_PyUnicode_FromFormat("<GPollFD %d (%d) at 0x%lx>",
671 self->pollfd.fd, self->pollfd.events,
676 pyg_poll_fd_init(PyGPollFD *self, PyObject *args, PyObject *kwargs)
678 static char *kwlist[] = { "fd", "events", NULL };
683 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
684 "OH:gi._glib.PollFD.__init__", kwlist,
688 fd = PyObject_AsFileDescriptor(o);
692 self->pollfd.fd = fd;
693 self->pollfd.events = events;
694 self->pollfd.revents = 0;
703 pyglib_source_register_types(PyObject *d)
705 PyGSource_Type.tp_flags = (Py_TPFLAGS_DEFAULT |
706 Py_TPFLAGS_BASETYPE |
708 PyGSource_Type.tp_init = (initproc)pyg_source_init;
709 PyGSource_Type.tp_free = (freefunc)pyg_source_free;
710 PyGSource_Type.tp_dealloc = (destructor)pyg_source_dealloc;
711 PyGSource_Type.tp_methods = pyg_source_methods;
712 PyGSource_Type.tp_repr = (reprfunc)pyg_source_repr;
713 PyGSource_Type.tp_traverse = (traverseproc)pyg_source_traverse;
714 PyGSource_Type.tp_clear = (inquiry)pyg_source_clear;
715 PyGSource_Type.tp_getset = pyg_source_getsets;
716 PyGSource_Type.tp_weaklistoffset = offsetof(PyGSource, weakreflist);
717 PyGSource_Type.tp_dictoffset = offsetof(PyGSource, inst_dict);
718 PYGLIB_REGISTER_TYPE(d, PyGSource_Type, "Source");
720 PyGIdle_Type.tp_repr = (reprfunc)pyg_idle_repr;
721 PyGIdle_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
722 PyGIdle_Type.tp_base = (PyTypeObject *)&PyGSource_Type;
723 PyGIdle_Type.tp_init = (initproc)pyg_idle_init;
724 PYGLIB_REGISTER_TYPE(d, PyGIdle_Type, "Idle");
726 PyGTimeout_Type.tp_repr = (reprfunc)pyg_timeout_repr;
727 PyGTimeout_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
728 PyGTimeout_Type.tp_base = (PyTypeObject *)&PyGSource_Type;
729 PyGTimeout_Type.tp_init = (initproc)pyg_timeout_init;
730 PYGLIB_REGISTER_TYPE(d, PyGTimeout_Type, "Timeout");
732 PyGPollFD_Type.tp_dealloc = (destructor)pyg_poll_fd_dealloc;
733 PyGPollFD_Type.tp_repr = (reprfunc)pyg_poll_fd_repr;
734 PyGPollFD_Type.tp_flags = Py_TPFLAGS_DEFAULT;
735 PyGPollFD_Type.tp_members = pyg_poll_fd_members;
736 PyGPollFD_Type.tp_init = (initproc)pyg_poll_fd_init;
737 PYGLIB_REGISTER_TYPE(d, PyGPollFD_Type, "PollFD");