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