Imported Upstream version 3.3.1
[platform/upstream/pygobject2.git] / gi / _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("gi._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_is_destroyed(PyGSource *self)
134 {
135     PyObject *result;
136
137     if (self->source == NULL || g_source_is_destroyed(self->source))
138         result = Py_True;
139     else
140         result = Py_False;
141
142     Py_INCREF(result);
143     return result;
144 }
145
146 static PyObject *
147 pyg_source_set_callback(PyGSource *self, PyObject *args)
148 {
149     PyObject *first, *callback, *cbargs = NULL, *data;
150     gint len;
151
152     CHECK_DESTROYED(self, NULL);
153
154     len = PyTuple_Size (args);
155     if (len < 1) {
156         PyErr_SetString(PyExc_TypeError,
157                         "set_callback requires at least 1 argument");
158         return NULL;
159     }
160
161     first = PySequence_GetSlice(args, 0, 1);
162     if (!PyArg_ParseTuple(first, "O:set_callback", &callback)) {
163         Py_DECREF (first);
164         return NULL;
165     }
166     Py_DECREF(first);
167
168     if (!PyCallable_Check(callback)) {
169         PyErr_SetString(PyExc_TypeError, "first argument not callable");
170         return NULL;
171     }
172
173     cbargs = PySequence_GetSlice(args, 1, len);
174     if (cbargs == NULL)
175         return NULL;
176
177     data = Py_BuildValue("(ON)", callback, cbargs);
178     if (data == NULL)
179         return NULL;
180
181     g_source_set_callback(self->source,
182                           _pyglib_handler_marshal, data,
183                           _pyglib_destroy_notify);
184
185     Py_INCREF(Py_None);
186     return Py_None;
187 }
188
189 static PyObject *
190 pyg_source_get_context(PyGSource *self)
191 {
192     GMainContext *context;
193
194     CHECK_DESTROYED(self, NULL);
195
196     context = g_source_get_context(self->source);
197
198     if (context) {
199         return pyg_main_context_new(context);
200     } else {
201         Py_INCREF(Py_None);
202         return Py_None;
203     }
204 }
205
206 static PyObject *
207 pyg_source_add_poll(PyGSource *self, PyObject *args, PyObject *kwargs)
208 {
209     static char *kwlist[] = { "fd", NULL };
210     PyGPollFD *fd;
211
212     if (!self->python_source) {
213         PyErr_SetString(PyExc_TypeError,
214                         "add_poll can only be used with sources "
215                         "implemented in python");
216         return NULL;
217     }
218
219     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
220                                      "O!:add_poll", kwlist,
221                                      &PyGPollFD_Type, &fd))
222         return NULL;
223
224     CHECK_DESTROYED(self, NULL);
225
226     g_source_add_poll(self->source, &fd->pollfd);
227
228     Py_INCREF(Py_None);
229     return Py_None;
230 }
231
232 static PyObject *
233 pyg_source_remove_poll(PyGSource *self, PyObject *args, PyObject *kwargs)
234 {
235     static char *kwlist[] = { "fd", NULL };
236     PyGPollFD *fd;
237
238     if (!self->python_source) {
239         PyErr_SetString(PyExc_TypeError,
240                         "remove_poll can only be used with sources "
241                         "implemented in python");
242         return NULL;
243     }
244
245     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
246                                      "O!:remove_poll", kwlist,
247                                      &PyGPollFD_Type, &fd))
248         return NULL;
249
250     CHECK_DESTROYED(self, NULL);
251
252     g_source_remove_poll(self->source, &fd->pollfd);
253
254     Py_INCREF(Py_None);
255     return Py_None;
256 }
257
258 static PyObject *
259 pyg_source_get_current_time(PyGSource *self)
260 {
261     double   ret;
262
263     CHECK_DESTROYED(self, NULL);
264
265     ret = g_get_real_time() * 0.000001;
266     return PyFloat_FromDouble(ret);
267 }
268
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 },
278     { NULL, NULL, 0 }
279 };
280
281 static PyObject *
282 pyg_source_get_dict(PyGSource *self, void *closure)
283 {
284     if (self->inst_dict == NULL) {
285         self->inst_dict = PyDict_New();
286         if (self->inst_dict == NULL)
287             return NULL;
288     }
289
290     Py_INCREF(self->inst_dict);
291     return self->inst_dict;
292 }
293
294 static PyObject *
295 pyg_source_get_priority(PyGSource *self, void *closure)
296 {
297     CHECK_DESTROYED(self, NULL);
298
299     return PYGLIB_PyLong_FromLong(g_source_get_priority(self->source));
300 }
301
302 static int
303 pyg_source_set_priority(PyGSource *self, PyObject *value, void *closure)
304 {
305     CHECK_DESTROYED(self, -1);
306
307     if (value == NULL) {
308         PyErr_SetString(PyExc_TypeError, "cannot delete priority");
309         return -1;
310     }
311
312     if (!PYGLIB_PyLong_Check(value)) {
313         PyErr_SetString(PyExc_TypeError, "type mismatch");
314         return -1;
315     }
316
317     g_source_set_priority(self->source, PYGLIB_PyLong_AsLong(value));
318
319     return 0;
320 }
321
322 static PyObject *
323 pyg_source_get_can_recurse(PyGSource *self, void *closure)
324 {
325     CHECK_DESTROYED(self, NULL);
326
327     return PyBool_FromLong(g_source_get_can_recurse(self->source));
328 }
329
330 static int
331 pyg_source_set_can_recurse(PyGSource *self, PyObject *value, void *closure)
332 {
333     CHECK_DESTROYED(self, -1);
334
335     if (value == NULL) {
336         PyErr_SetString(PyExc_TypeError, "cannot delete can_recurse");
337         return -1;
338     }
339
340     g_source_set_can_recurse(self->source, PyObject_IsTrue(value));
341
342     return 0;
343 }
344
345 static PyObject *
346 pyg_source_get_id(PyGSource *self, void *closure)
347 {
348     CHECK_DESTROYED(self, NULL);
349
350     if (g_source_get_context(self->source) == NULL) {
351         PyErr_SetString(PyExc_RuntimeError, "source is not attached");
352         return NULL;
353     }
354
355     return PYGLIB_PyLong_FromLong(g_source_get_id(self->source));
356 }
357
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 },
363     {NULL, 0, 0}
364 };
365
366 static PyObject *
367 pyg_source_repr(PyGSource *self)
368 {
369     return source_repr(self, NULL);
370 }
371
372 static int
373 pyg_source_traverse(PyGSource *self, visitproc visit, void *arg)
374 {
375     int ret = 0;
376
377     if (self->inst_dict) ret = visit(self->inst_dict, arg);
378     if (ret != 0) return ret;
379
380     return 0;
381 }
382
383 static int
384 pyg_source_clear(PyGSource *self)
385 {
386     PyObject *tmp;
387
388     tmp = self->inst_dict;
389     self->inst_dict = NULL;
390     Py_XDECREF(tmp);
391
392     if (self->source) {
393         g_source_unref(self->source);
394         self->source = NULL;
395     }
396
397     return 0;
398 }
399
400 static void
401 pyg_source_dealloc(PyGSource *self)
402 {
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);
406
407     PyObject_ClearWeakRefs((PyObject *)self);
408
409     pyg_source_clear(self);
410
411     PyObject_GC_Del(self);
412 }
413
414 static gboolean
415 pyg_source_prepare(GSource *source, gint *timeout)
416 {
417     PyGRealSource *pysource = (PyGRealSource *)source;
418     PyObject *t;
419     gboolean ret = FALSE;
420     gboolean got_err = TRUE;
421     PyGILState_STATE state;
422
423     state = pyglib_gil_state_ensure();
424
425     t = PyObject_CallMethod(pysource->obj, "prepare", NULL);
426
427     if (t == NULL) {
428         goto bail;
429     } else if (!PyObject_IsTrue(t)) {
430         got_err = FALSE;
431         goto bail;
432     } else if (!PyTuple_Check(t)) {
433         PyErr_SetString(PyExc_TypeError,
434                         "source prepare function must return a tuple or False");
435         goto bail;
436     } else if (PyTuple_Size(t) != 2) {
437         PyErr_SetString(PyExc_TypeError,
438                         "source prepare function return tuple must be exactly "
439                         "2 elements long");
440         goto bail;
441     }
442
443     ret = PyObject_IsTrue(PyTuple_GET_ITEM(t, 0));
444         *timeout = PYGLIB_PyLong_AsLong(PyTuple_GET_ITEM(t, 1));
445
446         if (*timeout == -1 && PyErr_Occurred()) {
447             ret = FALSE;
448             goto bail;
449         }
450
451     got_err = FALSE;
452
453 bail:
454     if (got_err)
455         PyErr_Print();
456
457     Py_XDECREF(t);
458
459     pyglib_gil_state_release(state);
460
461     return ret;
462 }
463
464 static gboolean
465 pyg_source_check(GSource *source)
466 {
467     PyGRealSource *pysource = (PyGRealSource *)source;
468     PyObject *t;
469     gboolean ret;
470     PyGILState_STATE state;
471
472     state = pyglib_gil_state_ensure();
473
474     t = PyObject_CallMethod(pysource->obj, "check", NULL);
475
476     if (t == NULL) {
477         PyErr_Print();
478         ret = FALSE;
479     } else {
480         ret = PyObject_IsTrue(t);
481         Py_DECREF(t);
482     }
483
484     pyglib_gil_state_release(state);
485
486     return ret;
487 }
488
489 static gboolean
490 pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
491 {
492     PyGRealSource *pysource = (PyGRealSource *)source;
493     PyObject *func, *args, *tuple, *t;
494     gboolean ret;
495     PyGILState_STATE state;
496
497     state = pyglib_gil_state_ensure();
498
499     if (callback) {
500         tuple = user_data;
501
502         func = PyTuple_GetItem(tuple, 0);
503         args = PyTuple_GetItem(tuple, 1);
504     } else {
505         func = Py_None;
506         args = Py_None;
507     }
508
509     t = PyObject_CallMethod(pysource->obj, "dispatch", "OO", func, args);
510
511     if (t == NULL) {
512         PyErr_Print();
513         ret = FALSE;
514     } else {
515         ret = PyObject_IsTrue(t);
516         Py_DECREF(t);
517     }
518
519     pyglib_gil_state_release(state);
520
521     return ret;
522 }
523
524 static void
525 pyg_source_finalize(GSource *source)
526 {
527     PyGRealSource *pysource = (PyGRealSource *)source;
528     PyObject *func, *t;
529     PyGILState_STATE state;
530
531     state = pyglib_gil_state_ensure();
532
533     func = PyObject_GetAttrString(pysource->obj, "finalize");
534     if (func) {
535         t = PyObject_CallObject(func, NULL);
536         Py_DECREF(func);
537
538         if (t == NULL) {
539             PyErr_Print();
540         } else {
541             Py_DECREF(t);
542         }
543     }
544
545     pyglib_gil_state_release(state);
546 }
547
548 static GSourceFuncs pyg_source_funcs =
549 {
550     pyg_source_prepare,
551     pyg_source_check,
552     pyg_source_dispatch,
553     pyg_source_finalize
554 };
555
556 static int
557 pyg_source_init(PyGSource *self, PyObject *args, PyObject *kwargs)
558 {
559     PyGRealSource *pysource;
560
561     self->source = g_source_new(&pyg_source_funcs, sizeof(PyGRealSource));
562
563     pysource = (PyGRealSource *)self->source;
564     pysource->obj = (PyObject*)self;
565
566     self->inst_dict = NULL;
567     self->weakreflist = NULL;
568
569     self->python_source = TRUE;
570
571     return 0;
572 }
573
574 static void
575 pyg_source_free(PyObject *op)
576 {
577     PyObject_GC_Del(op);
578 }
579
580 /* glib.Idle */
581
582 PYGLIB_DEFINE_TYPE("gi._glib.Idle", PyGIdle_Type, PyGSource)
583
584 static PyObject *
585 pyg_idle_repr(PyGSource *self)
586 {
587     return source_repr(self, "idle");
588 }
589
590 static int
591 pyg_idle_init(PyGSource *self, PyObject *args, PyObject *kwargs)
592 {
593     static char *kwlist[] = { "priority", NULL };
594     gint priority = G_PRIORITY_DEFAULT_IDLE;
595
596     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
597                                      "|i:gi._glib.Idle.__init__", kwlist,
598                                      &priority))
599         return -1;
600
601     self->source = g_idle_source_new ();
602
603     if (priority != G_PRIORITY_DEFAULT_IDLE)
604         g_source_set_priority(self->source, priority);
605
606     self->inst_dict = NULL;
607     self->weakreflist = NULL;
608
609     self->python_source = FALSE;
610
611     return 0;
612 }
613
614 /* glib.Timeout */
615
616 PYGLIB_DEFINE_TYPE("gi._glib.Timeout", PyGTimeout_Type, PyGSource)
617
618 static PyObject *
619 pyg_timeout_repr(PyGSource *self)
620 {
621     return source_repr(self, "timeout");
622 }
623
624 static int
625 pyg_timeout_init(PyGSource *self, PyObject *args, PyObject *kwargs)
626 {
627     static char *kwlist[] = { "interval", "priority", NULL };
628     gint priority = G_PRIORITY_DEFAULT;
629     guint interval;
630
631     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
632                                      "I|i:gi._glib.Timeout.__init__", kwlist,
633                                      &interval, &priority))
634         return -1;
635
636     self->source = g_timeout_source_new(interval);
637
638     if (priority != G_PRIORITY_DEFAULT)
639         g_source_set_priority(self->source, priority);
640
641     self->inst_dict = NULL;
642     self->weakreflist = NULL;
643
644     self->python_source = FALSE;
645
646     return 0;
647 }
648
649 /* glib.PollFD */
650
651 PYGLIB_DEFINE_TYPE("gi._glib.PollFD", PyGPollFD_Type, PyGPollFD)
652
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 },
657     { NULL, 0, 0, 0 }
658 };
659
660 static void
661 pyg_poll_fd_dealloc(PyGPollFD *self)
662 {
663     Py_XDECREF(self->fd_obj);
664     PyObject_DEL(self);
665 }
666
667 static PyObject *
668 pyg_poll_fd_repr(PyGPollFD *self)
669 {
670     return PYGLIB_PyUnicode_FromFormat("<GPollFD %d (%d) at 0x%lx>",
671                                  self->pollfd.fd, self->pollfd.events,
672                                  (long)self);
673 }
674
675 static int
676 pyg_poll_fd_init(PyGPollFD *self, PyObject *args, PyObject *kwargs)
677 {
678     static char *kwlist[] = { "fd", "events", NULL };
679     PyObject *o;
680     gint fd;
681     gushort events;
682
683     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
684                                      "OH:gi._glib.PollFD.__init__", kwlist,
685                                      &o, &events))
686         return -1;
687
688     fd = PyObject_AsFileDescriptor(o);
689     if (fd == -1)
690         return -1;
691
692     self->pollfd.fd = fd;
693     self->pollfd.events = events;
694     self->pollfd.revents = 0;
695
696     Py_INCREF(o);
697     self->fd_obj = o;
698
699     return 0;
700 }
701
702 void
703 pyglib_source_register_types(PyObject *d)
704 {
705     PyGSource_Type.tp_flags = (Py_TPFLAGS_DEFAULT |
706                                Py_TPFLAGS_BASETYPE |
707                                Py_TPFLAGS_HAVE_GC);
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");
719
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");
725
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");
731
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");
738 }