Imported Upstream version 3.9.91
[platform/upstream/python-gobject.git] / gi / pygi-source.c
1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /*
3  * Copyright (C) 1998-2003  James Henstridge
4  * Copyright (C) 2005       Oracle
5  * Copyright (c) 2012       Canonical Ltd.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to
9  * deal in the Software without restriction, including without limitation the
10  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11  * sell copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23  * IN THE SOFTWARE.
24  */
25
26 #define NO_IMPORT
27 #include "pygobject.h"
28
29 #include "pygi-private.h"
30 #include "pyglib.h"
31 #include "pyglib-private.h"
32 #include "pygi-source.h"
33
34 typedef struct
35 {
36     GSource source;
37     PyObject *obj;
38 } PyGRealSource;
39
40 static gboolean
41 pyg_source_prepare(GSource *source, gint *timeout)
42 {
43     PyGRealSource *pysource = (PyGRealSource *)source;
44     PyObject *t;
45     gboolean ret = FALSE;
46     gboolean got_err = TRUE;
47     PyGILState_STATE state;
48
49     state = pyglib_gil_state_ensure();
50
51     t = PyObject_CallMethod(pysource->obj, "prepare", NULL);
52
53     if (t == NULL) {
54         goto bail;
55     } else if (!PyObject_IsTrue(t)) {
56         got_err = FALSE;
57         goto bail;
58     } else if (!PyTuple_Check(t)) {
59         PyErr_SetString(PyExc_TypeError,
60                         "source prepare function must return a tuple or False");
61         goto bail;
62     } else if (PyTuple_Size(t) != 2) {
63         PyErr_SetString(PyExc_TypeError,
64                         "source prepare function return tuple must be exactly "
65                         "2 elements long");
66         goto bail;
67     }
68
69     ret = PyObject_IsTrue(PyTuple_GET_ITEM(t, 0));
70         *timeout = PYGLIB_PyLong_AsLong(PyTuple_GET_ITEM(t, 1));
71
72         if (*timeout == -1 && PyErr_Occurred()) {
73             ret = FALSE;
74             goto bail;
75         }
76
77     got_err = FALSE;
78
79 bail:
80     if (got_err)
81         PyErr_Print();
82
83     Py_XDECREF(t);
84
85     pyglib_gil_state_release(state);
86
87     return ret;
88 }
89
90 static gboolean
91 pyg_source_check(GSource *source)
92 {
93     PyGRealSource *pysource = (PyGRealSource *)source;
94     PyObject *t;
95     gboolean ret;
96     PyGILState_STATE state;
97
98     state = pyglib_gil_state_ensure();
99
100     t = PyObject_CallMethod(pysource->obj, "check", NULL);
101
102     if (t == NULL) {
103         PyErr_Print();
104         ret = FALSE;
105     } else {
106         ret = PyObject_IsTrue(t);
107         Py_DECREF(t);
108     }
109
110     pyglib_gil_state_release(state);
111
112     return ret;
113 }
114
115 static gboolean
116 pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
117 {
118     PyGRealSource *pysource = (PyGRealSource *)source;
119     PyObject *func, *args, *tuple, *t;
120     gboolean ret;
121     PyGILState_STATE state;
122
123     state = pyglib_gil_state_ensure();
124
125     if (callback) {
126         tuple = user_data;
127
128         func = PyTuple_GetItem(tuple, 0);
129         args = PyTuple_GetItem(tuple, 1);
130     } else {
131         func = Py_None;
132         args = Py_None;
133     }
134
135     t = PyObject_CallMethod(pysource->obj, "dispatch", "OO", func, args);
136
137     if (t == NULL) {
138         PyErr_Print();
139         ret = FALSE;
140     } else {
141         ret = PyObject_IsTrue(t);
142         Py_DECREF(t);
143     }
144
145     pyglib_gil_state_release(state);
146
147     return ret;
148 }
149
150 static void
151 pyg_source_finalize(GSource *source)
152 {
153     PyGRealSource *pysource = (PyGRealSource *)source;
154     PyObject *func, *t;
155     PyGILState_STATE state;
156
157     state = pyglib_gil_state_ensure();
158
159     func = PyObject_GetAttrString(pysource->obj, "finalize");
160     if (func) {
161         t = PyObject_CallObject(func, NULL);
162         Py_DECREF(func);
163
164         if (t == NULL) {
165             PyErr_Print();
166         } else {
167             Py_DECREF(t);
168         }
169     }
170
171     pyglib_gil_state_release(state);
172 }
173
174 static GSourceFuncs pyg_source_funcs =
175 {
176     pyg_source_prepare,
177     pyg_source_check,
178     pyg_source_dispatch,
179     pyg_source_finalize
180 };
181
182 PyObject *
183 pyg_source_set_callback(PyGObject *self_module, PyObject *args)
184 {
185     PyObject *self, *first, *callback, *cbargs = NULL, *data;
186     gint len;
187
188     len = PyTuple_Size (args);
189     if (len < 2) {
190         PyErr_SetString(PyExc_TypeError,
191                         "set_callback requires at least 2 arguments");
192         return NULL;
193     }
194
195     first = PySequence_GetSlice(args, 0, 2);
196     if (!PyArg_ParseTuple(first, "OO:set_callback", &self, &callback)) {
197         Py_DECREF (first);
198         return NULL;
199     }
200     Py_DECREF(first);
201     
202     if (!pyg_boxed_check (self, G_TYPE_SOURCE)) {
203         PyErr_SetString(PyExc_TypeError, "first argument is not a GLib.Source");
204         return NULL;
205     }
206
207     if (!PyCallable_Check(callback)) {
208         PyErr_SetString(PyExc_TypeError, "second argument not callable");
209         return NULL;
210     }
211
212     cbargs = PySequence_GetSlice(args, 2, len);
213     if (cbargs == NULL)
214         return NULL;
215
216     data = Py_BuildValue("(ON)", callback, cbargs);
217     if (data == NULL)
218         return NULL;
219
220     g_source_set_callback(pyg_boxed_get (self, GSource),
221                           _pyglib_handler_marshal, data,
222                           _pyglib_destroy_notify);
223
224     Py_INCREF(Py_None);
225     return Py_None;
226 }
227
228 /**
229  * pyg_source_new:
230  *
231  * Wrap the un-bindable g_source_new() and provide wrapper callbacks in the
232  * GSourceFuncs which call back to Python.
233  */
234 PyObject*
235 pyg_source_new (void)
236 {
237     PyGRealSource *source = NULL;
238     PyObject      *py_type;
239
240     source = (PyGRealSource*) g_source_new (&pyg_source_funcs, sizeof (PyGRealSource));
241
242     py_type = _pygi_type_import_by_name ("GLib", "Source");
243     /* g_source_new uses malloc, not slices */
244     source->obj = _pygi_boxed_new ( (PyTypeObject *) py_type, source, FALSE, 0);
245
246     return source->obj;
247 }