Imported Upstream version 3.21.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 #include "pygi-info.h"
27 #include "pygi-boxed.h"
28 #include "pygi-type.h"
29 #include "pyglib.h"
30 #include "pygboxed.h"
31 #include "pygi-source.h"
32
33 typedef struct
34 {
35     GSource source;
36     PyObject *obj;
37 } PyGRealSource;
38
39 static gboolean
40 pyg_source_prepare(GSource *source, gint *timeout)
41 {
42     PyGRealSource *pysource = (PyGRealSource *)source;
43     PyObject *t;
44     gboolean ret = FALSE;
45     gboolean got_err = TRUE;
46     PyGILState_STATE state;
47
48     state = pyglib_gil_state_ensure();
49
50     t = PyObject_CallMethod(pysource->obj, "prepare", NULL);
51
52     if (t == NULL) {
53         goto bail;
54     } else if (!PyObject_IsTrue(t)) {
55         got_err = FALSE;
56         goto bail;
57     } else if (!PyTuple_Check(t)) {
58         PyErr_SetString(PyExc_TypeError,
59                         "source prepare function must return a tuple or False");
60         goto bail;
61     } else if (PyTuple_Size(t) != 2) {
62         PyErr_SetString(PyExc_TypeError,
63                         "source prepare function return tuple must be exactly "
64                         "2 elements long");
65         goto bail;
66     }
67
68     ret = PyObject_IsTrue(PyTuple_GET_ITEM(t, 0));
69         *timeout = PYGLIB_PyLong_AsLong(PyTuple_GET_ITEM(t, 1));
70
71         if (*timeout == -1 && PyErr_Occurred()) {
72             ret = FALSE;
73             goto bail;
74         }
75
76     got_err = FALSE;
77
78 bail:
79     if (got_err)
80         PyErr_Print();
81
82     Py_XDECREF(t);
83
84     pyglib_gil_state_release(state);
85
86     return ret;
87 }
88
89 static gboolean
90 pyg_source_check(GSource *source)
91 {
92     PyGRealSource *pysource = (PyGRealSource *)source;
93     PyObject *t;
94     gboolean ret;
95     PyGILState_STATE state;
96
97     state = pyglib_gil_state_ensure();
98
99     t = PyObject_CallMethod(pysource->obj, "check", NULL);
100
101     if (t == NULL) {
102         PyErr_Print();
103         ret = FALSE;
104     } else {
105         ret = PyObject_IsTrue(t);
106         Py_DECREF(t);
107     }
108
109     pyglib_gil_state_release(state);
110
111     return ret;
112 }
113
114 static gboolean
115 pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
116 {
117     PyGRealSource *pysource = (PyGRealSource *)source;
118     PyObject *func, *args, *tuple, *t;
119     gboolean ret;
120     PyGILState_STATE state;
121
122     state = pyglib_gil_state_ensure();
123
124     if (callback) {
125         tuple = user_data;
126
127         func = PyTuple_GetItem(tuple, 0);
128         args = PyTuple_GetItem(tuple, 1);
129     } else {
130         func = Py_None;
131         args = Py_None;
132     }
133
134     t = PyObject_CallMethod(pysource->obj, "dispatch", "OO", func, args);
135
136     if (t == NULL) {
137         PyErr_Print();
138         ret = FALSE;
139     } else {
140         ret = PyObject_IsTrue(t);
141         Py_DECREF(t);
142     }
143
144     pyglib_gil_state_release(state);
145
146     return ret;
147 }
148
149 static void
150 pyg_source_finalize(GSource *source)
151 {
152     PyGRealSource *pysource = (PyGRealSource *)source;
153     PyObject *func, *t;
154     PyGILState_STATE state;
155
156     state = pyglib_gil_state_ensure();
157
158     func = PyObject_GetAttrString(pysource->obj, "finalize");
159     if (func) {
160         t = PyObject_CallObject(func, NULL);
161         Py_DECREF(func);
162
163         if (t == NULL) {
164             PyErr_Print();
165         } else {
166             Py_DECREF(t);
167         }
168     }
169
170     pyglib_gil_state_release(state);
171 }
172
173 static GSourceFuncs pyg_source_funcs =
174 {
175     pyg_source_prepare,
176     pyg_source_check,
177     pyg_source_dispatch,
178     pyg_source_finalize
179 };
180
181 PyObject *
182 pyg_source_set_callback(PyGObject *self_module, PyObject *args)
183 {
184     PyObject *self, *first, *callback, *cbargs = NULL, *data;
185     gint len;
186
187     len = PyTuple_Size (args);
188     if (len < 2) {
189         PyErr_SetString(PyExc_TypeError,
190                         "set_callback requires at least 2 arguments");
191         return NULL;
192     }
193
194     first = PySequence_GetSlice(args, 0, 2);
195     if (!PyArg_ParseTuple(first, "OO:set_callback", &self, &callback)) {
196         Py_DECREF (first);
197         return NULL;
198     }
199     Py_DECREF(first);
200     
201     if (!pyg_boxed_check (self, G_TYPE_SOURCE)) {
202         PyErr_SetString(PyExc_TypeError, "first argument is not a GLib.Source");
203         return NULL;
204     }
205
206     if (!PyCallable_Check(callback)) {
207         PyErr_SetString(PyExc_TypeError, "second argument not callable");
208         return NULL;
209     }
210
211     cbargs = PySequence_GetSlice(args, 2, len);
212     if (cbargs == NULL)
213         return NULL;
214
215     data = Py_BuildValue("(ON)", callback, cbargs);
216     if (data == NULL)
217         return NULL;
218
219     g_source_set_callback(pyg_boxed_get (self, GSource),
220                           _pyglib_handler_marshal, data,
221                           _pyglib_destroy_notify);
222
223     Py_INCREF(Py_None);
224     return Py_None;
225 }
226
227 /**
228  * pyg_source_new:
229  *
230  * Wrap the un-bindable g_source_new() and provide wrapper callbacks in the
231  * GSourceFuncs which call back to Python.
232  */
233 PyObject*
234 pyg_source_new (void)
235 {
236     PyGRealSource *source = NULL;
237     PyObject      *py_type;
238
239     source = (PyGRealSource*) g_source_new (&pyg_source_funcs, sizeof (PyGRealSource));
240
241     py_type = _pygi_type_import_by_name ("GLib", "Source");
242     /* Full ownership transfer of the source, this will be free'd with g_boxed_free. */
243     source->obj = _pygi_boxed_new ( (PyTypeObject *) py_type, source,
244                                     FALSE, /* copy_boxed */
245                                     0);    /* slice_allocated */
246
247     return source->obj;
248 }