Imported Upstream version 3.25.1
[platform/upstream/pygobject2.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 = PyGILState_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     PyGILState_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 = PyGILState_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     PyGILState_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 = PyGILState_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     PyGILState_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 = PyGILState_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     } else {
169         PyErr_Clear ();
170     }
171
172     PyGILState_Release(state);
173 }
174
175 static GSourceFuncs pyg_source_funcs =
176 {
177     pyg_source_prepare,
178     pyg_source_check,
179     pyg_source_dispatch,
180     pyg_source_finalize
181 };
182
183 PyObject *
184 pyg_source_set_callback(PyGObject *self_module, PyObject *args)
185 {
186     PyObject *self, *first, *callback, *cbargs = NULL, *data;
187     gint len;
188
189     len = PyTuple_Size (args);
190     if (len < 2) {
191         PyErr_SetString(PyExc_TypeError,
192                         "set_callback requires at least 2 arguments");
193         return NULL;
194     }
195
196     first = PySequence_GetSlice(args, 0, 2);
197     if (!PyArg_ParseTuple(first, "OO:set_callback", &self, &callback)) {
198         Py_DECREF (first);
199         return NULL;
200     }
201     Py_DECREF(first);
202     
203     if (!pyg_boxed_check (self, G_TYPE_SOURCE)) {
204         PyErr_SetString(PyExc_TypeError, "first argument is not a GLib.Source");
205         return NULL;
206     }
207
208     if (!PyCallable_Check(callback)) {
209         PyErr_SetString(PyExc_TypeError, "second argument not callable");
210         return NULL;
211     }
212
213     cbargs = PySequence_GetSlice(args, 2, len);
214     if (cbargs == NULL)
215         return NULL;
216
217     data = Py_BuildValue("(ON)", callback, cbargs);
218     if (data == NULL)
219         return NULL;
220
221     g_source_set_callback(pyg_boxed_get (self, GSource),
222                           _pyglib_handler_marshal, data,
223                           _pyglib_destroy_notify);
224
225     Py_INCREF(Py_None);
226     return Py_None;
227 }
228
229 /**
230  * pyg_source_new:
231  *
232  * Wrap the un-bindable g_source_new() and provide wrapper callbacks in the
233  * GSourceFuncs which call back to Python.
234  */
235 PyObject*
236 pyg_source_new (void)
237 {
238     PyGRealSource *source = NULL;
239     PyObject      *py_type;
240
241     source = (PyGRealSource*) g_source_new (&pyg_source_funcs, sizeof (PyGRealSource));
242
243     py_type = _pygi_type_import_by_name ("GLib", "Source");
244     /* Full ownership transfer of the source, this will be free'd with g_boxed_free. */
245     source->obj = _pygi_boxed_new ( (PyTypeObject *) py_type, source,
246                                     FALSE, /* copy_boxed */
247                                     0);    /* slice_allocated */
248
249     return source->obj;
250 }