d0176abc2020645357606ff8e46b79d47d95adef
[profile/ivi/pygobject2.git] / glib / pygsource.c
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
5  *
6  * Author: Manish Singh <manish.singh@oracle.com>
7  *
8  *   pygsource.c: GSource wrapper
9  *
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.
14  *
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.
19  *
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
23  * USA
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #  include <config.h>
28 #endif
29
30 #include <Python.h>
31 #include <pythread.h>
32 #include <structmember.h> /* for PyMemberDef */
33 #include "pyglib.h"
34 #include "pyglib-private.h"
35 #include "pygmaincontext.h"
36 #include "pygsource.h"
37
38 #define CHECK_DESTROYED(self, ret)                      G_STMT_START {  \
39     if ((self)->source == NULL) {                                       \
40         PyErr_SetString(PyExc_RuntimeError, "source is destroyed");     \
41         return (ret);                                                   \
42     }                                                                   \
43 } G_STMT_END
44
45
46 typedef struct {
47     PyObject_HEAD
48     GSource *source;
49     PyObject *inst_dict;
50     PyObject *weakreflist;
51     gboolean python_source;
52 } PyGSource;
53
54 typedef struct
55 {
56     GSource source;
57     PyObject *obj;
58 } PyGRealSource;
59
60 /* glib.Source */
61
62 PYGLIB_DEFINE_TYPE("glib.Source", PyGSource_Type, PyGSource)
63
64 static PyObject *
65 source_repr(PyGSource *self, const char *type)
66 {
67     gchar buf[256], *desc;
68  
69     if (self->source) {
70         if (g_source_get_context(self->source))
71             desc = "attached";
72         else
73             desc = "unattached";
74     } else {
75         desc = "destroyed";
76     }
77
78     if (type)
79         g_snprintf(buf, sizeof(buf), "<%s glib %s source at 0x%lx>",
80                    desc, type, (long) self);
81     else
82         g_snprintf(buf, sizeof(buf), "<%s glib source at 0x%lx>",
83                    desc, (long) self);
84
85     return PYGLIB_PyUnicode_FromString(buf);
86 }
87
88 static PyObject *
89 pyg_source_attach(PyGSource *self, PyObject *args, PyObject *kwargs)
90 {
91     static char *kwlist[] = { "context", NULL };
92     PyGMainContext *py_context = NULL;
93     GMainContext *context = NULL;
94     guint id;
95
96     if (!PyArg_ParseTupleAndKeywords (args, kwargs,
97                                       "|O!:attach", kwlist,
98                                       &PyGMainContext_Type, &py_context))
99         return NULL;
100
101     if (py_context)
102         context = py_context->context;
103
104     CHECK_DESTROYED(self, NULL);
105
106     if (self->python_source) {
107         PyGRealSource *pysource = (PyGRealSource *)self->source;
108         Py_INCREF(pysource->obj);
109     }
110
111     id = g_source_attach(self->source, context);
112     return PYGLIB_PyLong_FromLong(id);
113 }
114
115 static PyObject *
116 pyg_source_destroy(PyGSource *self)
117 {
118     CHECK_DESTROYED(self, NULL);
119
120     if (self->python_source && self->source->context) {
121         PyGRealSource *pysource = (PyGRealSource *)self->source;
122         Py_DECREF(pysource->obj);
123     }
124
125     g_source_destroy(self->source);
126     self->source = NULL;
127
128     Py_INCREF(Py_None);
129     return Py_None;
130 }
131
132 static PyObject *
133 pyg_source_set_callback(PyGSource *self, PyObject *args)
134 {
135     PyObject *first, *callback, *cbargs = NULL, *data;
136     gint len;
137
138     CHECK_DESTROYED(self, NULL);
139
140     len = PyTuple_Size (args);
141     if (len < 1) {
142         PyErr_SetString(PyExc_TypeError,
143                         "set_callback requires at least 1 argument");
144         return NULL;
145     }
146
147     first = PySequence_GetSlice(args, 0, 1);
148     if (!PyArg_ParseTuple(first, "O:set_callback", &callback)) {
149         Py_DECREF (first);
150         return NULL;
151     }
152     Py_DECREF(first);
153
154     if (!PyCallable_Check(callback)) {
155         PyErr_SetString(PyExc_TypeError, "first argument not callable");
156         return NULL;
157     }
158
159     cbargs = PySequence_GetSlice(args, 1, len);
160     if (cbargs == NULL)
161         return NULL;
162
163     data = Py_BuildValue("(ON)", callback, cbargs);
164     if (data == NULL)
165         return NULL;
166
167     g_source_set_callback(self->source,
168                           _pyglib_handler_marshal, data,
169                           _pyglib_destroy_notify);
170
171     Py_INCREF(Py_None);
172     return Py_None;
173 }
174
175 static PyObject *
176 pyg_source_get_context(PyGSource *self)
177 {
178     GMainContext *context;
179
180     CHECK_DESTROYED(self, NULL);
181
182     context = g_source_get_context(self->source);
183
184     if (context) {
185         return pyg_main_context_new(context);
186     } else {
187         Py_INCREF(Py_None);
188         return Py_None;
189     }
190 }
191
192 static PyObject *
193 pyg_source_add_poll(PyGSource *self, PyObject *args, PyObject *kwargs)
194 {
195     static char *kwlist[] = { "fd", NULL };
196     PyGPollFD *fd;
197
198     if (!self->python_source) {
199         PyErr_SetString(PyExc_TypeError,
200                         "add_poll can only be used with sources "
201                         "implemented in python");
202         return NULL;
203     }
204
205     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
206                                      "O!:add_poll", kwlist,
207                                      &PyGPollFD_Type, &fd))
208         return NULL;
209
210     CHECK_DESTROYED(self, NULL);
211
212     g_source_add_poll(self->source, &fd->pollfd);
213
214     Py_INCREF(Py_None);
215     return Py_None;
216 }
217
218 static PyObject *
219 pyg_source_remove_poll(PyGSource *self, PyObject *args, PyObject *kwargs)
220 {
221     static char *kwlist[] = { "fd", NULL };
222     PyGPollFD *fd;
223
224     if (!self->python_source) {
225         PyErr_SetString(PyExc_TypeError,
226                         "remove_poll can only be used with sources "
227                         "implemented in python");
228         return NULL;
229     }
230
231     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
232                                      "O!:remove_poll", kwlist,
233                                      &PyGPollFD_Type, &fd))
234         return NULL;
235
236     CHECK_DESTROYED(self, NULL);
237
238     g_source_remove_poll(self->source, &fd->pollfd);
239
240     Py_INCREF(Py_None);
241     return Py_None;
242 }
243
244 static PyObject *
245 pyg_source_get_current_time(PyGSource *self)
246 {
247     GTimeVal timeval;
248     double   ret;
249
250     CHECK_DESTROYED(self, NULL);
251
252     g_source_get_current_time(self->source, &timeval);
253     ret = (double)timeval.tv_sec + (double)timeval.tv_usec * 0.000001;
254     return PyFloat_FromDouble(ret);
255 }
256
257 static PyMethodDef pyg_source_methods[] = {
258     { "attach", (PyCFunction)pyg_source_attach, METH_VARARGS|METH_KEYWORDS },
259     { "destroy", (PyCFunction)pyg_source_destroy, METH_NOARGS },
260     { "set_callback", (PyCFunction)pyg_source_set_callback, METH_VARARGS },
261     { "get_context", (PyCFunction)pyg_source_get_context, METH_NOARGS },
262     { "add_poll", (PyCFunction)pyg_source_add_poll, METH_KEYWORDS },
263     { "remove_poll", (PyCFunction)pyg_source_remove_poll, METH_VARARGS|METH_KEYWORDS },
264     { "get_current_time", (PyCFunction)pyg_source_get_current_time, METH_NOARGS },
265     { NULL, NULL, 0 }
266 };
267
268 static PyObject *
269 pyg_source_get_dict(PyGSource *self, void *closure)
270 {
271     if (self->inst_dict == NULL) {
272         self->inst_dict = PyDict_New();
273         if (self->inst_dict == NULL)
274             return NULL;
275     }
276
277     Py_INCREF(self->inst_dict);
278     return self->inst_dict;
279 }
280
281 static PyObject *
282 pyg_source_get_priority(PyGSource *self, void *closure)
283 {
284     CHECK_DESTROYED(self, NULL);
285
286     return PYGLIB_PyLong_FromLong(g_source_get_priority(self->source));
287 }
288
289 static int
290 pyg_source_set_priority(PyGSource *self, PyObject *value, void *closure)
291 {
292     CHECK_DESTROYED(self, -1);
293
294     if (value == NULL) {
295         PyErr_SetString(PyExc_TypeError, "cannot delete priority");
296         return -1;
297     }
298
299     if (!PYGLIB_PyLong_Check(value)) {
300         PyErr_SetString(PyExc_TypeError, "type mismatch");
301         return -1;
302     }
303
304     g_source_set_priority(self->source, PYGLIB_PyLong_AsLong(value));
305
306     return 0;
307 }
308
309 static PyObject *
310 pyg_source_get_can_recurse(PyGSource *self, void *closure)
311 {
312     CHECK_DESTROYED(self, NULL);
313
314     return PyBool_FromLong(g_source_get_can_recurse(self->source));
315 }
316
317 static int
318 pyg_source_set_can_recurse(PyGSource *self, PyObject *value, void *closure)
319 {
320     CHECK_DESTROYED(self, -1);
321
322     if (value == NULL) {
323         PyErr_SetString(PyExc_TypeError, "cannot delete can_recurse");
324         return -1;
325     }
326
327     g_source_set_can_recurse(self->source, PyObject_IsTrue(value));
328
329     return 0;
330 }
331
332 static PyObject *
333 pyg_source_get_id(PyGSource *self, void *closure)
334 {
335     CHECK_DESTROYED(self, NULL);
336
337     if (g_source_get_context(self->source) == NULL) {
338         PyErr_SetString(PyExc_RuntimeError, "source is not attached");
339         return NULL;
340     }
341
342     return PYGLIB_PyLong_FromLong(g_source_get_id(self->source));
343 }
344
345 static PyGetSetDef pyg_source_getsets[] = {
346     { "__dict__", (getter)pyg_source_get_dict,  (setter)0 },
347     {"priority", (getter)pyg_source_get_priority, (setter)pyg_source_set_priority },
348     {"can_recurse", (getter)pyg_source_get_can_recurse, (setter)pyg_source_set_can_recurse },
349     {"id", (getter)pyg_source_get_id, (setter)0 },
350     {NULL, 0, 0}
351 };
352
353 static PyObject *
354 pyg_source_repr(PyGSource *self)
355 {
356     return source_repr(self, NULL);
357 }
358
359 static int
360 pyg_source_traverse(PyGSource *self, visitproc visit, void *arg)
361 {
362     int ret = 0;
363
364     if (self->inst_dict) ret = visit(self->inst_dict, arg);
365     if (ret != 0) return ret;
366
367     return 0;
368 }
369
370 static int
371 pyg_source_clear(PyGSource *self)
372 {
373     PyObject *tmp;
374
375     tmp = self->inst_dict;
376     self->inst_dict = NULL;
377     Py_XDECREF(tmp);
378
379     if (self->source) {
380         g_source_unref(self->source);
381         self->source = NULL;
382     }
383
384     return 0;
385 }
386
387 static void
388 pyg_source_dealloc(PyGSource *self)
389 {
390     /* Must be done first, so that there is no chance of Python's GC being
391      * called while tracking this half-deallocated object */
392     PyObject_GC_UnTrack((PyObject *)self);
393
394     PyObject_ClearWeakRefs((PyObject *)self);
395
396     pyg_source_clear(self);
397
398     PyObject_GC_Del(self);
399 }
400
401 static gboolean
402 pyg_source_prepare(GSource *source, gint *timeout)
403 {
404     PyGRealSource *pysource = (PyGRealSource *)source;
405     PyObject *t;
406     gboolean ret = FALSE;
407     gboolean got_err = TRUE;
408     PyGILState_STATE state;
409
410     state = pyglib_gil_state_ensure();
411
412     t = PyObject_CallMethod(pysource->obj, "prepare", NULL);
413
414     if (t == NULL) {
415         goto bail;
416     } else if (!PyObject_IsTrue(t)) {
417         got_err = FALSE;
418         goto bail;
419     } else if (!PyTuple_Check(t)) {
420         PyErr_SetString(PyExc_TypeError,
421                         "source prepare function must return a tuple or False");
422         goto bail;
423     } else if (PyTuple_Size(t) != 2) {
424         PyErr_SetString(PyExc_TypeError,
425                         "source prepare function return tuple must be exactly "
426                         "2 elements long");
427         goto bail;
428     }
429
430     ret = PyObject_IsTrue(PyTuple_GET_ITEM(t, 0));
431         *timeout = PYGLIB_PyLong_AsLong(PyTuple_GET_ITEM(t, 1));
432
433         if (*timeout == -1 && PyErr_Occurred()) {
434             ret = FALSE;
435             goto bail;
436         }
437
438     got_err = FALSE;
439
440 bail:
441     if (got_err)
442         PyErr_Print();
443
444     Py_XDECREF(t);
445
446     pyglib_gil_state_release(state);
447
448     return ret;
449 }
450
451 static gboolean
452 pyg_source_check(GSource *source)
453 {
454     PyGRealSource *pysource = (PyGRealSource *)source;
455     PyObject *t;
456     gboolean ret;
457     PyGILState_STATE state;
458
459     state = pyglib_gil_state_ensure();
460
461     t = PyObject_CallMethod(pysource->obj, "check", NULL);
462
463     if (t == NULL) {
464         PyErr_Print();
465         ret = FALSE;
466     } else {
467         ret = PyObject_IsTrue(t);
468         Py_DECREF(t);
469     }
470
471     pyglib_gil_state_release(state);
472
473     return ret;
474 }
475
476 static gboolean
477 pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
478 {
479     PyGRealSource *pysource = (PyGRealSource *)source;
480     PyObject *func, *args, *tuple, *t;
481     gboolean ret;
482     PyGILState_STATE state;
483
484     state = pyglib_gil_state_ensure();
485
486     if (callback) {
487         tuple = user_data;
488
489         func = PyTuple_GetItem(tuple, 0);
490         args = PyTuple_GetItem(tuple, 1);
491     } else {
492         func = Py_None;
493         args = Py_None;
494     }
495
496     t = PyObject_CallMethod(pysource->obj, "dispatch", "OO", func, args);
497
498     if (t == NULL) {
499         PyErr_Print();
500         ret = FALSE;
501     } else {
502         ret = PyObject_IsTrue(t);
503         Py_DECREF(t);
504     }
505
506     pyglib_gil_state_release(state);
507
508     return ret;
509 }
510
511 static void
512 pyg_source_finalize(GSource *source)
513 {
514     PyGRealSource *pysource = (PyGRealSource *)source;
515     PyObject *func, *t;
516     PyGILState_STATE state;
517
518     state = pyglib_gil_state_ensure();
519
520     func = PyObject_GetAttrString(pysource->obj, "finalize");
521     if (func) {
522         t = PyObject_CallObject(func, NULL);
523         Py_DECREF(func);
524
525         if (t == NULL) {
526             PyErr_Print();
527         } else {
528             Py_DECREF(t);
529         }
530     }
531
532     pyglib_gil_state_release(state);
533 }
534
535 static GSourceFuncs pyg_source_funcs =
536 {
537     pyg_source_prepare,
538     pyg_source_check,
539     pyg_source_dispatch,
540     pyg_source_finalize
541 };
542
543 static int
544 pyg_source_init(PyGSource *self, PyObject *args, PyObject *kwargs)
545 {
546     PyGRealSource *pysource;
547
548     self->source = g_source_new(&pyg_source_funcs, sizeof(PyGRealSource));
549
550     pysource = (PyGRealSource *)self->source;
551     pysource->obj = (PyObject*)self;
552
553     self->inst_dict = NULL;
554     self->weakreflist = NULL;
555
556     self->python_source = TRUE;
557
558     return 0;
559 }
560
561 static void
562 pyg_source_free(PyObject *op)
563 {
564     PyObject_GC_Del(op);
565 }
566
567 /* glib.Idle */
568
569 PYGLIB_DEFINE_TYPE("glib.Idle", PyGIdle_Type, PyGSource)
570
571 static PyObject *
572 pyg_idle_repr(PyGSource *self)
573 {
574     return source_repr(self, "idle");
575 }
576
577 static int
578 pyg_idle_init(PyGSource *self, PyObject *args, PyObject *kwargs)
579 {
580     static char *kwlist[] = { "priority", NULL };
581     gint priority = G_PRIORITY_DEFAULT_IDLE;
582
583     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
584                                      "|i:glib.Idle.__init__", kwlist,
585                                      &priority))
586         return -1;
587
588     self->source = g_idle_source_new ();
589
590     if (priority != G_PRIORITY_DEFAULT_IDLE)
591         g_source_set_priority(self->source, priority);
592
593     self->inst_dict = NULL;
594     self->weakreflist = NULL;
595
596     self->python_source = FALSE;
597
598     return 0;
599 }
600
601 /* glib.Timeout */
602
603 PYGLIB_DEFINE_TYPE("glib.Timeout", PyGTimeout_Type, PyGSource)
604
605 static PyObject *
606 pyg_timeout_repr(PyGSource *self)
607 {
608     return source_repr(self, "timeout");
609 }
610
611 static int
612 pyg_timeout_init(PyGSource *self, PyObject *args, PyObject *kwargs)
613 {
614     static char *kwlist[] = { "interval", "priority", NULL };
615     gint priority = G_PRIORITY_DEFAULT;
616     guint interval;
617
618     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
619                                      "I|i:glib.Timeout.__init__", kwlist,
620                                      &interval, &priority))
621         return -1;
622
623     self->source = g_timeout_source_new(interval);
624
625     if (priority != G_PRIORITY_DEFAULT)
626         g_source_set_priority(self->source, priority);
627
628     self->inst_dict = NULL;
629     self->weakreflist = NULL;
630
631     self->python_source = FALSE;
632
633     return 0;
634 }
635
636 /* glib.PollFD */
637
638 PYGLIB_DEFINE_TYPE("glib.PollFD", PyGPollFD_Type, PyGPollFD)
639
640 static PyMemberDef pyg_poll_fd_members[] = {
641     { "fd",      T_INT,    offsetof(PyGPollFD, pollfd.fd),      READONLY },
642     { "events",  T_USHORT, offsetof(PyGPollFD, pollfd.events),  READONLY },
643     { "revents", T_USHORT, offsetof(PyGPollFD, pollfd.revents), READONLY },
644     { NULL, 0, 0, 0 }
645 };
646
647 static void
648 pyg_poll_fd_dealloc(PyGPollFD *self)
649 {
650     Py_XDECREF(self->fd_obj);
651     PyObject_DEL(self);
652 }
653
654 static PyObject *
655 pyg_poll_fd_repr(PyGPollFD *self)
656 {
657     return PYGLIB_PyUnicode_FromFormat("<GPollFD %d (%d) at 0x%lx>",
658                                  self->pollfd.fd, self->pollfd.events,
659                                  (long)self);
660 }
661
662 static int
663 pyg_poll_fd_init(PyGPollFD *self, PyObject *args, PyObject *kwargs)
664 {
665     static char *kwlist[] = { "fd", "events", NULL };
666     PyObject *o;
667     gint fd;
668     gushort events;
669
670     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
671                                      "OH:glib.PollFD.__init__", kwlist,
672                                      &o, &events))
673         return -1;
674
675     fd = PyObject_AsFileDescriptor(o);
676     if (fd == -1)
677         return -1;
678
679     self->pollfd.fd = fd;
680     self->pollfd.events = events;
681     self->pollfd.revents = 0;
682
683     Py_INCREF(o);
684     self->fd_obj = o;
685
686     return 0;
687 }
688
689 void
690 pyglib_source_register_types(PyObject *d)
691 {
692     PyGSource_Type.tp_flags = (Py_TPFLAGS_DEFAULT |
693                                Py_TPFLAGS_BASETYPE |
694                                Py_TPFLAGS_HAVE_GC);
695     PyGSource_Type.tp_init = (initproc)pyg_source_init;
696     PyGSource_Type.tp_free = (freefunc)pyg_source_free;
697     PyGSource_Type.tp_dealloc = (destructor)pyg_source_dealloc;
698     PyGSource_Type.tp_methods = pyg_source_methods;
699     PyGSource_Type.tp_repr = (reprfunc)pyg_source_repr;
700     PyGSource_Type.tp_traverse = (traverseproc)pyg_source_traverse;
701     PyGSource_Type.tp_clear = (inquiry)pyg_source_clear;
702     PyGSource_Type.tp_getset = pyg_source_getsets;
703     PyGSource_Type.tp_weaklistoffset = offsetof(PyGSource, weakreflist);
704     PyGSource_Type.tp_dictoffset = offsetof(PyGSource, inst_dict);
705     PYGLIB_REGISTER_TYPE(d, PyGSource_Type, "Source");
706
707     PyGIdle_Type.tp_repr = (reprfunc)pyg_idle_repr;
708     PyGIdle_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
709     PyGIdle_Type.tp_base = (PyTypeObject *)&PyGSource_Type;
710     PyGIdle_Type.tp_init = (initproc)pyg_idle_init;
711     PYGLIB_REGISTER_TYPE(d, PyGIdle_Type, "Idle");
712
713     PyGTimeout_Type.tp_repr = (reprfunc)pyg_timeout_repr;
714     PyGTimeout_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
715     PyGTimeout_Type.tp_base = (PyTypeObject *)&PyGSource_Type;
716     PyGTimeout_Type.tp_init = (initproc)pyg_timeout_init;
717     PYGLIB_REGISTER_TYPE(d, PyGTimeout_Type, "Timeout");
718
719     PyGPollFD_Type.tp_dealloc = (destructor)pyg_poll_fd_dealloc;
720     PyGPollFD_Type.tp_repr = (reprfunc)pyg_poll_fd_repr;
721     PyGPollFD_Type.tp_flags = Py_TPFLAGS_DEFAULT;
722     PyGPollFD_Type.tp_members = pyg_poll_fd_members;
723     PyGPollFD_Type.tp_init = (initproc)pyg_poll_fd_init;
724     PYGLIB_REGISTER_TYPE(d, PyGPollFD_Type, "PollFD");
725 }