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 | { |
35 | static GType etype = 0; |
36 | |
37 | if (g_once_init_enter (&etype)) |
38 | { |
39 | static const GFlagsValue values[] = { |
40 | { G_IO_IN, "G_IO_IN" , "in" }, |
41 | { G_IO_OUT, "G_IO_OUT" , "out" }, |
42 | { G_IO_PRI, "G_IO_PRI" , "pri" }, |
43 | { G_IO_ERR, "G_IO_ERR" , "err" }, |
44 | { G_IO_HUP, "G_IO_HUP" , "hup" }, |
45 | { G_IO_NVAL, "G_IO_NVAL" , "nval" }, |
46 | { 0, NULL, NULL } |
47 | }; |
48 | GType type_id = g_flags_register_static (name: "GIOCondition" , const_static_values: values); |
49 | g_once_init_leave (&etype, type_id); |
50 | } |
51 | return etype; |
52 | } |
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 | { |
65 | GSourceFunc callback; |
66 | GCClosure *cc = (GCClosure*) closure; |
67 | gboolean v_return; |
68 | |
69 | g_return_if_fail (return_value != NULL); |
70 | g_return_if_fail (n_param_values == 0); |
71 | |
72 | callback = (GSourceFunc) (marshal_data ? marshal_data : cc->callback); |
73 | |
74 | v_return = callback (closure->data); |
75 | |
76 | g_value_set_boolean (value: return_value, v_boolean: v_return); |
77 | } |
78 | |
79 | static gboolean |
80 | io_watch_closure_callback (GIOChannel *channel, |
81 | GIOCondition condition, |
82 | gpointer data) |
83 | { |
84 | GClosure *closure = data; |
85 | |
86 | GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT }; |
87 | GValue result_value = G_VALUE_INIT; |
88 | gboolean result; |
89 | |
90 | g_value_init (value: &result_value, G_TYPE_BOOLEAN); |
91 | g_value_init (value: ¶ms[0], G_TYPE_IO_CHANNEL); |
92 | g_value_set_boxed (value: ¶ms[0], v_boxed: channel); |
93 | |
94 | g_value_init (value: ¶ms[1], G_TYPE_IO_CONDITION); |
95 | g_value_set_flags (value: ¶ms[1], v_flags: condition); |
96 | |
97 | g_closure_invoke (closure, return_value: &result_value, n_param_values: 2, param_values: params, NULL); |
98 | |
99 | result = g_value_get_boolean (value: &result_value); |
100 | g_value_unset (value: &result_value); |
101 | g_value_unset (value: ¶ms[0]); |
102 | g_value_unset (value: ¶ms[1]); |
103 | |
104 | return result; |
105 | } |
106 | |
107 | static gboolean |
108 | g_child_watch_closure_callback (GPid pid, |
109 | gint status, |
110 | gpointer data) |
111 | { |
112 | GClosure *closure = data; |
113 | |
114 | GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT }; |
115 | GValue result_value = G_VALUE_INIT; |
116 | gboolean result; |
117 | |
118 | g_value_init (value: &result_value, G_TYPE_BOOLEAN); |
119 | |
120 | #ifdef G_OS_UNIX |
121 | g_value_init (value: ¶ms[0], G_TYPE_ULONG); |
122 | g_value_set_ulong (value: ¶ms[0], v_ulong: pid); |
123 | #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 | g_value_init (value: ¶ms[1], G_TYPE_INT); |
130 | g_value_set_int (value: ¶ms[1], v_int: status); |
131 | |
132 | g_closure_invoke (closure, return_value: &result_value, n_param_values: 2, param_values: params, NULL); |
133 | |
134 | result = g_value_get_boolean (value: &result_value); |
135 | g_value_unset (value: &result_value); |
136 | g_value_unset (value: ¶ms[0]); |
137 | g_value_unset (value: ¶ms[1]); |
138 | |
139 | return result; |
140 | } |
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 | { |
148 | GClosure *closure = data; |
149 | |
150 | GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT }; |
151 | GValue result_value = G_VALUE_INIT; |
152 | gboolean result; |
153 | |
154 | g_value_init (value: &result_value, G_TYPE_BOOLEAN); |
155 | |
156 | g_value_init (value: ¶ms[0], G_TYPE_INT); |
157 | g_value_set_int (value: ¶ms[0], v_int: fd); |
158 | |
159 | g_value_init (value: ¶ms[1], G_TYPE_IO_CONDITION); |
160 | g_value_set_flags (value: ¶ms[1], v_flags: condition); |
161 | |
162 | g_closure_invoke (closure, return_value: &result_value, n_param_values: 2, param_values: params, NULL); |
163 | |
164 | result = g_value_get_boolean (value: &result_value); |
165 | g_value_unset (value: &result_value); |
166 | g_value_unset (value: ¶ms[0]); |
167 | g_value_unset (value: ¶ms[1]); |
168 | |
169 | return result; |
170 | } |
171 | #endif |
172 | |
173 | static gboolean |
174 | source_closure_callback (gpointer data) |
175 | { |
176 | GClosure *closure = data; |
177 | GValue result_value = G_VALUE_INIT; |
178 | gboolean result; |
179 | |
180 | g_value_init (value: &result_value, G_TYPE_BOOLEAN); |
181 | |
182 | g_closure_invoke (closure, return_value: &result_value, n_param_values: 0, NULL, NULL); |
183 | |
184 | result = g_value_get_boolean (value: &result_value); |
185 | g_value_unset (value: &result_value); |
186 | |
187 | return result; |
188 | } |
189 | |
190 | static void |
191 | closure_callback_get (gpointer cb_data, |
192 | GSource *source, |
193 | GSourceFunc *func, |
194 | gpointer *data) |
195 | { |
196 | GSourceFunc closure_callback = source->source_funcs->closure_callback; |
197 | |
198 | if (!closure_callback) |
199 | { |
200 | if (source->source_funcs == &g_io_watch_funcs) |
201 | closure_callback = (GSourceFunc)io_watch_closure_callback; |
202 | else if (source->source_funcs == &g_child_watch_funcs) |
203 | closure_callback = (GSourceFunc)g_child_watch_closure_callback; |
204 | #ifdef G_OS_UNIX |
205 | else if (source->source_funcs == &g_unix_fd_source_funcs) |
206 | closure_callback = (GSourceFunc)g_unix_fd_source_closure_callback; |
207 | #endif |
208 | else if (source->source_funcs == &g_timeout_funcs || |
209 | #ifdef G_OS_UNIX |
210 | source->source_funcs == &g_unix_signal_funcs || |
211 | #endif |
212 | source->source_funcs == &g_idle_funcs) |
213 | closure_callback = source_closure_callback; |
214 | } |
215 | |
216 | *func = closure_callback; |
217 | *data = cb_data; |
218 | } |
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 | { |
230 | g_source_destroy (source: user_data); |
231 | } |
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 | { |
248 | g_return_if_fail (source != NULL); |
249 | g_return_if_fail (closure != NULL); |
250 | |
251 | if (!source->source_funcs->closure_callback && |
252 | #ifdef G_OS_UNIX |
253 | source->source_funcs != &g_unix_fd_source_funcs && |
254 | source->source_funcs != &g_unix_signal_funcs && |
255 | #endif |
256 | source->source_funcs != &g_child_watch_funcs && |
257 | source->source_funcs != &g_io_watch_funcs && |
258 | source->source_funcs != &g_timeout_funcs && |
259 | source->source_funcs != &g_idle_funcs) |
260 | { |
261 | g_critical (G_STRLOC ": closure cannot be set on GSource without GSourceFuncs::closure_callback" ); |
262 | return; |
263 | } |
264 | |
265 | g_closure_ref (closure); |
266 | g_closure_sink (closure); |
267 | g_source_set_callback_indirect (source, callback_data: closure, callback_funcs: &closure_callback_funcs); |
268 | |
269 | g_closure_add_invalidate_notifier (closure, notify_data: source, notify_func: closure_invalidated); |
270 | |
271 | if (G_CLOSURE_NEEDS_MARSHAL (closure)) |
272 | { |
273 | GClosureMarshal marshal = (GClosureMarshal)source->source_funcs->closure_marshal; |
274 | if (marshal) |
275 | g_closure_set_marshal (closure, marshal); |
276 | else if (source->source_funcs == &g_idle_funcs || |
277 | #ifdef G_OS_UNIX |
278 | source->source_funcs == &g_unix_signal_funcs || |
279 | #endif |
280 | source->source_funcs == &g_timeout_funcs) |
281 | g_closure_set_marshal (closure, marshal: source_closure_marshal_BOOLEAN__VOID); |
282 | else |
283 | g_closure_set_marshal (closure, marshal: g_cclosure_marshal_generic); |
284 | } |
285 | } |
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 | { |
295 | if (G_VALUE_HOLDS_BOOLEAN (return_value)) |
296 | g_value_set_boolean (value: return_value, TRUE); |
297 | } |
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 | { |
317 | GClosure *closure; |
318 | |
319 | closure = g_closure_new_simple (sizeof_closure: sizeof (GClosure), NULL); |
320 | g_closure_set_meta_marshal (closure, NULL, meta_marshal: dummy_closure_marshal); |
321 | g_source_set_closure (source, closure); |
322 | } |
323 | |