/src/glib/gobject/gsourceclosure.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* GObject - GLib Type, Object, Parameter and Signal Library |
2 | | * Copyright (C) 2001 Red Hat, Inc. |
3 | | * |
4 | | * This library is free software; you can redistribute it and/or |
5 | | * modify it under the terms of the GNU Lesser General Public |
6 | | * License as published by the Free Software Foundation; either |
7 | | * version 2.1 of the License, or (at your option) any later version. |
8 | | * |
9 | | * This library is distributed in the hope that it will be useful, |
10 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | | * Lesser General Public License for more details. |
13 | | * |
14 | | * You should have received a copy of the GNU Lesser General |
15 | | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | |
18 | | #include "config.h" |
19 | | |
20 | | #include "gsourceclosure.h" |
21 | | #include "gboxed.h" |
22 | | #include "genums.h" |
23 | | #include "gmarshal.h" |
24 | | #include "gvalue.h" |
25 | | #include "gvaluetypes.h" |
26 | | #ifdef G_OS_UNIX |
27 | | #include "glib-unix.h" |
28 | | #endif |
29 | | |
30 | | G_DEFINE_BOXED_TYPE (GIOChannel, g_io_channel, g_io_channel_ref, g_io_channel_unref) |
31 | | |
32 | | GType |
33 | | g_io_condition_get_type (void) |
34 | 0 | { |
35 | 0 | static GType etype = 0; |
36 | |
|
37 | 0 | if (g_once_init_enter (&etype)) |
38 | 0 | { |
39 | 0 | static const GFlagsValue values[] = { |
40 | 0 | { G_IO_IN, "G_IO_IN", "in" }, |
41 | 0 | { G_IO_OUT, "G_IO_OUT", "out" }, |
42 | 0 | { G_IO_PRI, "G_IO_PRI", "pri" }, |
43 | 0 | { G_IO_ERR, "G_IO_ERR", "err" }, |
44 | 0 | { G_IO_HUP, "G_IO_HUP", "hup" }, |
45 | 0 | { G_IO_NVAL, "G_IO_NVAL", "nval" }, |
46 | 0 | { 0, NULL, NULL } |
47 | 0 | }; |
48 | 0 | GType type_id = g_flags_register_static ("GIOCondition", values); |
49 | 0 | g_once_init_leave (&etype, type_id); |
50 | 0 | } |
51 | 0 | return etype; |
52 | 0 | } |
53 | | |
54 | | /* We need to hand-write this marshaler, since it doesn't have an |
55 | | * instance object. |
56 | | */ |
57 | | static void |
58 | | source_closure_marshal_BOOLEAN__VOID (GClosure *closure, |
59 | | GValue *return_value, |
60 | | guint n_param_values, |
61 | | const GValue *param_values, |
62 | | gpointer invocation_hint, |
63 | | gpointer marshal_data) |
64 | 0 | { |
65 | 0 | GSourceFunc callback; |
66 | 0 | GCClosure *cc = (GCClosure*) closure; |
67 | 0 | gboolean v_return; |
68 | |
|
69 | 0 | g_return_if_fail (return_value != NULL); |
70 | 0 | g_return_if_fail (n_param_values == 0); |
71 | | |
72 | 0 | callback = (GSourceFunc) (marshal_data ? marshal_data : cc->callback); |
73 | |
|
74 | 0 | v_return = callback (closure->data); |
75 | |
|
76 | 0 | g_value_set_boolean (return_value, v_return); |
77 | 0 | } |
78 | | |
79 | | static gboolean |
80 | | io_watch_closure_callback (GIOChannel *channel, |
81 | | GIOCondition condition, |
82 | | gpointer data) |
83 | 0 | { |
84 | 0 | GClosure *closure = data; |
85 | |
|
86 | 0 | GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT }; |
87 | 0 | GValue result_value = G_VALUE_INIT; |
88 | 0 | gboolean result; |
89 | |
|
90 | 0 | g_value_init (&result_value, G_TYPE_BOOLEAN); |
91 | 0 | g_value_init (¶ms[0], G_TYPE_IO_CHANNEL); |
92 | 0 | g_value_set_boxed (¶ms[0], channel); |
93 | | |
94 | 0 | g_value_init (¶ms[1], G_TYPE_IO_CONDITION); |
95 | 0 | g_value_set_flags (¶ms[1], condition); |
96 | |
|
97 | 0 | g_closure_invoke (closure, &result_value, 2, params, NULL); |
98 | |
|
99 | 0 | result = g_value_get_boolean (&result_value); |
100 | 0 | g_value_unset (&result_value); |
101 | 0 | g_value_unset (¶ms[0]); |
102 | 0 | g_value_unset (¶ms[1]); |
103 | |
|
104 | 0 | return result; |
105 | 0 | } |
106 | | |
107 | | static gboolean |
108 | | g_child_watch_closure_callback (GPid pid, |
109 | | gint status, |
110 | | gpointer data) |
111 | 0 | { |
112 | 0 | GClosure *closure = data; |
113 | |
|
114 | 0 | GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT }; |
115 | 0 | GValue result_value = G_VALUE_INIT; |
116 | 0 | gboolean result; |
117 | |
|
118 | 0 | g_value_init (&result_value, G_TYPE_BOOLEAN); |
119 | |
|
120 | 0 | #ifdef G_OS_UNIX |
121 | 0 | g_value_init (¶ms[0], G_TYPE_ULONG); |
122 | 0 | g_value_set_ulong (¶ms[0], pid); |
123 | 0 | #endif |
124 | | #ifdef G_OS_WIN32 |
125 | | g_value_init (¶ms[0], G_TYPE_POINTER); |
126 | | g_value_set_pointer (¶ms[0], pid); |
127 | | #endif |
128 | |
|
129 | 0 | g_value_init (¶ms[1], G_TYPE_INT); |
130 | 0 | g_value_set_int (¶ms[1], status); |
131 | |
|
132 | 0 | g_closure_invoke (closure, &result_value, 2, params, NULL); |
133 | |
|
134 | 0 | result = g_value_get_boolean (&result_value); |
135 | 0 | g_value_unset (&result_value); |
136 | 0 | g_value_unset (¶ms[0]); |
137 | 0 | g_value_unset (¶ms[1]); |
138 | |
|
139 | 0 | return result; |
140 | 0 | } |
141 | | |
142 | | #ifdef G_OS_UNIX |
143 | | static gboolean |
144 | | g_unix_fd_source_closure_callback (int fd, |
145 | | GIOCondition condition, |
146 | | gpointer data) |
147 | 0 | { |
148 | 0 | GClosure *closure = data; |
149 | |
|
150 | 0 | GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT }; |
151 | 0 | GValue result_value = G_VALUE_INIT; |
152 | 0 | gboolean result; |
153 | |
|
154 | 0 | g_value_init (&result_value, G_TYPE_BOOLEAN); |
155 | |
|
156 | 0 | g_value_init (¶ms[0], G_TYPE_INT); |
157 | 0 | g_value_set_int (¶ms[0], fd); |
158 | |
|
159 | 0 | g_value_init (¶ms[1], G_TYPE_IO_CONDITION); |
160 | 0 | g_value_set_flags (¶ms[1], condition); |
161 | |
|
162 | 0 | g_closure_invoke (closure, &result_value, 2, params, NULL); |
163 | |
|
164 | 0 | result = g_value_get_boolean (&result_value); |
165 | 0 | g_value_unset (&result_value); |
166 | 0 | g_value_unset (¶ms[0]); |
167 | 0 | g_value_unset (¶ms[1]); |
168 | |
|
169 | 0 | return result; |
170 | 0 | } |
171 | | #endif |
172 | | |
173 | | static gboolean |
174 | | source_closure_callback (gpointer data) |
175 | 0 | { |
176 | 0 | GClosure *closure = data; |
177 | 0 | GValue result_value = G_VALUE_INIT; |
178 | 0 | gboolean result; |
179 | |
|
180 | 0 | g_value_init (&result_value, G_TYPE_BOOLEAN); |
181 | | |
182 | 0 | g_closure_invoke (closure, &result_value, 0, NULL, NULL); |
183 | |
|
184 | 0 | result = g_value_get_boolean (&result_value); |
185 | 0 | g_value_unset (&result_value); |
186 | |
|
187 | 0 | return result; |
188 | 0 | } |
189 | | |
190 | | static void |
191 | | closure_callback_get (gpointer cb_data, |
192 | | GSource *source, |
193 | | GSourceFunc *func, |
194 | | gpointer *data) |
195 | 0 | { |
196 | 0 | GSourceFunc closure_callback = source->source_funcs->closure_callback; |
197 | |
|
198 | 0 | if (!closure_callback) |
199 | 0 | { |
200 | 0 | if (source->source_funcs == &g_io_watch_funcs) |
201 | 0 | closure_callback = (GSourceFunc)io_watch_closure_callback; |
202 | 0 | else if (source->source_funcs == &g_child_watch_funcs) |
203 | 0 | closure_callback = (GSourceFunc)g_child_watch_closure_callback; |
204 | 0 | #ifdef G_OS_UNIX |
205 | 0 | else if (source->source_funcs == &g_unix_fd_source_funcs) |
206 | 0 | closure_callback = (GSourceFunc)g_unix_fd_source_closure_callback; |
207 | 0 | #endif |
208 | 0 | else if (source->source_funcs == &g_timeout_funcs || |
209 | 0 | #ifdef G_OS_UNIX |
210 | 0 | source->source_funcs == &g_unix_signal_funcs || |
211 | 0 | #endif |
212 | 0 | source->source_funcs == &g_idle_funcs) |
213 | 0 | closure_callback = source_closure_callback; |
214 | 0 | } |
215 | |
|
216 | 0 | *func = closure_callback; |
217 | 0 | *data = cb_data; |
218 | 0 | } |
219 | | |
220 | | static GSourceCallbackFuncs closure_callback_funcs = { |
221 | | (void (*) (gpointer)) g_closure_ref, |
222 | | (void (*) (gpointer)) g_closure_unref, |
223 | | closure_callback_get |
224 | | }; |
225 | | |
226 | | static void |
227 | | closure_invalidated (gpointer user_data, |
228 | | GClosure *closure) |
229 | 0 | { |
230 | 0 | g_source_destroy (user_data); |
231 | 0 | } |
232 | | |
233 | | /** |
234 | | * g_source_set_closure: |
235 | | * @source: the source |
236 | | * @closure: a #GClosure |
237 | | * |
238 | | * Set the callback for a source as a #GClosure. |
239 | | * |
240 | | * If the source is not one of the standard GLib types, the @closure_callback |
241 | | * and @closure_marshal fields of the #GSourceFuncs structure must have been |
242 | | * filled in with pointers to appropriate functions. |
243 | | */ |
244 | | void |
245 | | g_source_set_closure (GSource *source, |
246 | | GClosure *closure) |
247 | 0 | { |
248 | 0 | g_return_if_fail (source != NULL); |
249 | 0 | g_return_if_fail (closure != NULL); |
250 | | |
251 | 0 | if (!source->source_funcs->closure_callback && |
252 | 0 | #ifdef G_OS_UNIX |
253 | 0 | source->source_funcs != &g_unix_fd_source_funcs && |
254 | 0 | source->source_funcs != &g_unix_signal_funcs && |
255 | 0 | #endif |
256 | 0 | source->source_funcs != &g_child_watch_funcs && |
257 | 0 | source->source_funcs != &g_io_watch_funcs && |
258 | 0 | source->source_funcs != &g_timeout_funcs && |
259 | 0 | source->source_funcs != &g_idle_funcs) |
260 | 0 | { |
261 | 0 | g_critical (G_STRLOC ": closure cannot be set on GSource without GSourceFuncs::closure_callback"); |
262 | 0 | return; |
263 | 0 | } |
264 | | |
265 | 0 | g_closure_ref (closure); |
266 | 0 | g_closure_sink (closure); |
267 | 0 | g_source_set_callback_indirect (source, closure, &closure_callback_funcs); |
268 | |
|
269 | 0 | g_closure_add_invalidate_notifier (closure, source, closure_invalidated); |
270 | |
|
271 | 0 | if (G_CLOSURE_NEEDS_MARSHAL (closure)) |
272 | 0 | { |
273 | 0 | GClosureMarshal marshal = (GClosureMarshal)source->source_funcs->closure_marshal; |
274 | 0 | if (marshal) |
275 | 0 | g_closure_set_marshal (closure, marshal); |
276 | 0 | else if (source->source_funcs == &g_idle_funcs || |
277 | 0 | #ifdef G_OS_UNIX |
278 | 0 | source->source_funcs == &g_unix_signal_funcs || |
279 | 0 | #endif |
280 | 0 | source->source_funcs == &g_timeout_funcs) |
281 | 0 | g_closure_set_marshal (closure, source_closure_marshal_BOOLEAN__VOID); |
282 | 0 | else |
283 | 0 | g_closure_set_marshal (closure, g_cclosure_marshal_generic); |
284 | 0 | } |
285 | 0 | } |
286 | | |
287 | | static void |
288 | | dummy_closure_marshal (GClosure *closure, |
289 | | GValue *return_value, |
290 | | guint n_param_values, |
291 | | const GValue *param_values, |
292 | | gpointer invocation_hint, |
293 | | gpointer marshal_data) |
294 | 0 | { |
295 | 0 | if (G_VALUE_HOLDS_BOOLEAN (return_value)) |
296 | 0 | g_value_set_boolean (return_value, TRUE); |
297 | 0 | } |
298 | | |
299 | | /** |
300 | | * g_source_set_dummy_callback: |
301 | | * @source: the source |
302 | | * |
303 | | * Sets a dummy callback for @source. The callback will do nothing, and |
304 | | * if the source expects a #gboolean return value, it will return %TRUE. |
305 | | * (If the source expects any other type of return value, it will return |
306 | | * a 0/%NULL value; whatever g_value_init() initializes a #GValue to for |
307 | | * that type.) |
308 | | * |
309 | | * If the source is not one of the standard GLib types, the |
310 | | * @closure_callback and @closure_marshal fields of the #GSourceFuncs |
311 | | * structure must have been filled in with pointers to appropriate |
312 | | * functions. |
313 | | */ |
314 | | void |
315 | | g_source_set_dummy_callback (GSource *source) |
316 | 0 | { |
317 | 0 | GClosure *closure; |
318 | |
|
319 | 0 | closure = g_closure_new_simple (sizeof (GClosure), NULL); |
320 | 0 | g_closure_set_meta_marshal (closure, NULL, dummy_closure_marshal); |
321 | 0 | g_source_set_closure (source, closure); |
322 | 0 | } |