|
1 /* GObject - GLib Type, Object, Parameter and Signal Library |
|
2 * Copyright (C) 2000-2001 Red Hat, Inc. |
|
3 * Copyright (C) 2005 Imendio AB |
|
4 * Portions copyright (c) 2006 Nokia Corporation. All rights reserved. |
|
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 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, write to the |
|
18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
|
19 * Boston, MA 02111-1307, USA. |
|
20 */ |
|
21 #include "gclosure.h" |
|
22 |
|
23 /* |
|
24 * MT safe with regards to reference counting. |
|
25 */ |
|
26 |
|
27 #include "gvalue.h" |
|
28 #include "gobjectalias.h" |
|
29 #include <string.h> |
|
30 |
|
31 |
|
32 #define CLOSURE_MAX_REF_COUNT ((1 << 15) - 1) |
|
33 #define CLOSURE_MAX_N_GUARDS ((1 << 1) - 1) |
|
34 #define CLOSURE_MAX_N_FNOTIFIERS ((1 << 2) - 1) |
|
35 #define CLOSURE_MAX_N_INOTIFIERS ((1 << 8) - 1) |
|
36 #define CLOSURE_N_MFUNCS(cl) ((cl)->meta_marshal + \ |
|
37 ((cl)->n_guards << 1L)) |
|
38 /* same as G_CLOSURE_N_NOTIFIERS() (keep in sync) */ |
|
39 #define CLOSURE_N_NOTIFIERS(cl) (CLOSURE_N_MFUNCS (cl) + \ |
|
40 (cl)->n_fnotifiers + \ |
|
41 (cl)->n_inotifiers) |
|
42 |
|
43 typedef union { |
|
44 GClosure closure; |
|
45 volatile gint vint; |
|
46 } ClosureInt; |
|
47 |
|
48 #define CHANGE_FIELD(_closure, _field, _OP, _value, _must_set, _SET_OLD, _SET_NEW) \ |
|
49 G_STMT_START { \ |
|
50 ClosureInt *cunion = (ClosureInt*) _closure; \ |
|
51 gint new_int, old_int, success; \ |
|
52 do \ |
|
53 { \ |
|
54 ClosureInt tmp; \ |
|
55 tmp.vint = old_int = cunion->vint; \ |
|
56 _SET_OLD tmp.closure._field; \ |
|
57 tmp.closure._field _OP _value; \ |
|
58 _SET_NEW tmp.closure._field; \ |
|
59 new_int = tmp.vint; \ |
|
60 success = g_atomic_int_compare_and_exchange (FIX_CASTING(int *)&cunion->vint, old_int, new_int); \ |
|
61 } \ |
|
62 while (!success && _must_set); \ |
|
63 } G_STMT_END |
|
64 |
|
65 #define SWAP(_closure, _field, _value, _oldv) CHANGE_FIELD (_closure, _field, =, _value, TRUE, *(_oldv) =, (void) ) |
|
66 #define SET(_closure, _field, _value) CHANGE_FIELD (_closure, _field, =, _value, TRUE, (void), (void) ) |
|
67 #define INC(_closure, _field) CHANGE_FIELD (_closure, _field, +=, 1, TRUE, (void), (void) ) |
|
68 #define INC_ASSIGN(_closure, _field, _newv) CHANGE_FIELD (_closure, _field, +=, 1, TRUE, (void), *(_newv) = ) |
|
69 #define DEC(_closure, _field) CHANGE_FIELD (_closure, _field, -=, 1, TRUE, (void), (void) ) |
|
70 #define DEC_ASSIGN(_closure, _field, _newv) CHANGE_FIELD (_closure, _field, -=, 1, TRUE, (void), *(_newv) = ) |
|
71 |
|
72 #if 0 /* for non-thread-safe closures */ |
|
73 #define SWAP(cl,f,v,o) (void) (*(o) = cl->f, cl->f = v) |
|
74 #define SET(cl,f,v) (void) (cl->f = v) |
|
75 #define INC(cl,f) (void) (cl->f += 1) |
|
76 #define INC_ASSIGN(cl,f,n) (void) (cl->f += 1, *(n) = cl->f) |
|
77 #define DEC(cl,f) (void) (cl->f -= 1) |
|
78 #define DEC_ASSIGN(cl,f,n) (void) (cl->f -= 1, *(n) = cl->f) |
|
79 #endif |
|
80 |
|
81 enum { |
|
82 FNOTIFY, |
|
83 INOTIFY, |
|
84 PRE_NOTIFY, |
|
85 POST_NOTIFY |
|
86 }; |
|
87 |
|
88 |
|
89 /* --- functions --- */ |
|
90 EXPORT_C GClosure* |
|
91 g_closure_new_simple (guint sizeof_closure, |
|
92 gpointer data) |
|
93 { |
|
94 GClosure *closure; |
|
95 |
|
96 g_return_val_if_fail (sizeof_closure >= sizeof (GClosure), NULL); |
|
97 closure = g_malloc0 (sizeof_closure); |
|
98 SET (closure, ref_count, 1); |
|
99 SET (closure, meta_marshal, 0); |
|
100 SET (closure, n_guards, 0); |
|
101 SET (closure, n_fnotifiers, 0); |
|
102 SET (closure, n_inotifiers, 0); |
|
103 SET (closure, in_inotify, FALSE); |
|
104 SET (closure, floating, TRUE); |
|
105 SET (closure, derivative_flag, 0); |
|
106 SET (closure, in_marshal, FALSE); |
|
107 SET (closure, is_invalid, FALSE); |
|
108 closure->marshal = NULL; |
|
109 closure->data = data; |
|
110 closure->notifiers = NULL; |
|
111 memset (G_STRUCT_MEMBER_P (closure, sizeof (*closure)), 0, sizeof_closure - sizeof (*closure)); |
|
112 |
|
113 return closure; |
|
114 } |
|
115 |
|
116 static inline void |
|
117 closure_invoke_notifiers (GClosure *closure, |
|
118 guint notify_type) |
|
119 { |
|
120 /* notifier layout: |
|
121 * meta_marshal n_guards n_guards n_fnotif. n_inotifiers |
|
122 * ->[[meta_marshal][pre_guards][post_guards][fnotifiers][inotifiers]] |
|
123 * |
|
124 * CLOSURE_N_MFUNCS(cl) = meta_marshal + n_guards + n_guards; |
|
125 * CLOSURE_N_NOTIFIERS(cl) = CLOSURE_N_MFUNCS(cl) + n_fnotifiers + n_inotifiers |
|
126 * |
|
127 * constrains/catches: |
|
128 * - closure->notifiers may be reloacted during callback |
|
129 * - closure->n_fnotifiers and closure->n_inotifiers may change during callback |
|
130 * - i.e. callbacks can be removed/added during invocation |
|
131 * - must prepare for callback removal during FNOTIFY and INOTIFY (done via ->marshal= & ->data=) |
|
132 * - must distinguish (->marshal= & ->data=) for INOTIFY vs. FNOTIFY (via ->in_inotify) |
|
133 * + closure->n_guards is const during PRE_NOTIFY & POST_NOTIFY |
|
134 * + closure->meta_marshal is const for all cases |
|
135 * + none of the callbacks can cause recursion |
|
136 * + closure->n_inotifiers is const 0 during FNOTIFY |
|
137 */ |
|
138 switch (notify_type) |
|
139 { |
|
140 GClosureNotifyData *ndata; |
|
141 guint i, offs; |
|
142 case FNOTIFY: |
|
143 while (closure->n_fnotifiers) |
|
144 { |
|
145 guint n; |
|
146 DEC_ASSIGN (closure, n_fnotifiers, &n); |
|
147 |
|
148 ndata = closure->notifiers + CLOSURE_N_MFUNCS (closure) + n; |
|
149 closure->marshal = (GClosureMarshal) ndata->notify; |
|
150 closure->data = ndata->data; |
|
151 ndata->notify (ndata->data, closure); |
|
152 } |
|
153 closure->marshal = NULL; |
|
154 closure->data = NULL; |
|
155 break; |
|
156 case INOTIFY: |
|
157 SET (closure, in_inotify, TRUE); |
|
158 while (closure->n_inotifiers) |
|
159 { |
|
160 guint n; |
|
161 DEC_ASSIGN (closure, n_inotifiers, &n); |
|
162 |
|
163 ndata = closure->notifiers + CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers + n; |
|
164 closure->marshal = (GClosureMarshal) ndata->notify; |
|
165 closure->data = ndata->data; |
|
166 ndata->notify (ndata->data, closure); |
|
167 } |
|
168 closure->marshal = NULL; |
|
169 closure->data = NULL; |
|
170 SET (closure, in_inotify, FALSE); |
|
171 break; |
|
172 case PRE_NOTIFY: |
|
173 i = closure->n_guards; |
|
174 offs = closure->meta_marshal; |
|
175 while (i--) |
|
176 { |
|
177 ndata = closure->notifiers + offs + i; |
|
178 ndata->notify (ndata->data, closure); |
|
179 } |
|
180 break; |
|
181 case POST_NOTIFY: |
|
182 i = closure->n_guards; |
|
183 offs = closure->meta_marshal + i; |
|
184 while (i--) |
|
185 { |
|
186 ndata = closure->notifiers + offs + i; |
|
187 ndata->notify (ndata->data, closure); |
|
188 } |
|
189 break; |
|
190 } |
|
191 } |
|
192 |
|
193 EXPORT_C void |
|
194 g_closure_set_meta_marshal (GClosure *closure, |
|
195 gpointer marshal_data, |
|
196 GClosureMarshal meta_marshal) |
|
197 { |
|
198 GClosureNotifyData *notifiers; |
|
199 |
|
200 g_return_if_fail (closure != NULL); |
|
201 g_return_if_fail (meta_marshal != NULL); |
|
202 g_return_if_fail (closure->is_invalid == FALSE); |
|
203 g_return_if_fail (closure->in_marshal == FALSE); |
|
204 g_return_if_fail (closure->meta_marshal == 0); |
|
205 |
|
206 notifiers = closure->notifiers; |
|
207 closure->notifiers = g_renew (GClosureNotifyData, NULL, CLOSURE_N_NOTIFIERS (closure) + 1); |
|
208 if (notifiers) |
|
209 { |
|
210 /* usually the meta marshal will be setup right after creation, so the |
|
211 * g_memmove() should be rare-case scenario |
|
212 */ |
|
213 g_memmove (closure->notifiers + 1, notifiers, CLOSURE_N_NOTIFIERS (closure) * sizeof (notifiers[0])); |
|
214 g_free (notifiers); |
|
215 } |
|
216 closure->notifiers[0].data = marshal_data; |
|
217 closure->notifiers[0].notify = (GClosureNotify) meta_marshal; |
|
218 SET (closure, meta_marshal, 1); |
|
219 } |
|
220 |
|
221 EXPORT_C void |
|
222 g_closure_add_marshal_guards (GClosure *closure, |
|
223 gpointer pre_marshal_data, |
|
224 GClosureNotify pre_marshal_notify, |
|
225 gpointer post_marshal_data, |
|
226 GClosureNotify post_marshal_notify) |
|
227 { |
|
228 guint i; |
|
229 |
|
230 g_return_if_fail (closure != NULL); |
|
231 g_return_if_fail (pre_marshal_notify != NULL); |
|
232 g_return_if_fail (post_marshal_notify != NULL); |
|
233 g_return_if_fail (closure->is_invalid == FALSE); |
|
234 g_return_if_fail (closure->in_marshal == FALSE); |
|
235 g_return_if_fail (closure->n_guards < CLOSURE_MAX_N_GUARDS); |
|
236 closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 2); |
|
237 |
|
238 if (closure->n_inotifiers) |
|
239 closure->notifiers[(CLOSURE_N_MFUNCS (closure) + |
|
240 closure->n_fnotifiers + |
|
241 closure->n_inotifiers + 1)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) + |
|
242 closure->n_fnotifiers + 0)]; |
|
243 if (closure->n_inotifiers > 1) |
|
244 closure->notifiers[(CLOSURE_N_MFUNCS (closure) + |
|
245 closure->n_fnotifiers + |
|
246 closure->n_inotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) + |
|
247 closure->n_fnotifiers + 1)]; |
|
248 if (closure->n_fnotifiers) |
|
249 closure->notifiers[(CLOSURE_N_MFUNCS (closure) + |
|
250 closure->n_fnotifiers + 1)] = closure->notifiers[CLOSURE_N_MFUNCS (closure) + 0]; |
|
251 if (closure->n_fnotifiers > 1) |
|
252 closure->notifiers[(CLOSURE_N_MFUNCS (closure) + |
|
253 closure->n_fnotifiers)] = closure->notifiers[CLOSURE_N_MFUNCS (closure) + 1]; |
|
254 if (closure->n_guards) |
|
255 closure->notifiers[(closure->meta_marshal + |
|
256 closure->n_guards + |
|
257 closure->n_guards + 1)] = closure->notifiers[closure->meta_marshal + closure->n_guards]; |
|
258 i = closure->n_guards; |
|
259 closure->notifiers[closure->meta_marshal + i].data = pre_marshal_data; |
|
260 closure->notifiers[closure->meta_marshal + i].notify = pre_marshal_notify; |
|
261 closure->notifiers[closure->meta_marshal + i + 1].data = post_marshal_data; |
|
262 closure->notifiers[closure->meta_marshal + i + 1].notify = post_marshal_notify; |
|
263 INC (closure, n_guards); |
|
264 } |
|
265 |
|
266 EXPORT_C void |
|
267 g_closure_add_finalize_notifier (GClosure *closure, |
|
268 gpointer notify_data, |
|
269 GClosureNotify notify_func) |
|
270 { |
|
271 guint i; |
|
272 |
|
273 g_return_if_fail (closure != NULL); |
|
274 g_return_if_fail (notify_func != NULL); |
|
275 g_return_if_fail (closure->n_fnotifiers < CLOSURE_MAX_N_FNOTIFIERS); |
|
276 closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 1); |
|
277 if (closure->n_inotifiers) |
|
278 closure->notifiers[(CLOSURE_N_MFUNCS (closure) + |
|
279 closure->n_fnotifiers + |
|
280 closure->n_inotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) + |
|
281 closure->n_fnotifiers + 0)]; |
|
282 i = CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers; |
|
283 closure->notifiers[i].data = notify_data; |
|
284 closure->notifiers[i].notify = notify_func; |
|
285 INC (closure, n_fnotifiers); |
|
286 } |
|
287 |
|
288 EXPORT_C void |
|
289 g_closure_add_invalidate_notifier (GClosure *closure, |
|
290 gpointer notify_data, |
|
291 GClosureNotify notify_func) |
|
292 { |
|
293 guint i; |
|
294 |
|
295 g_return_if_fail (closure != NULL); |
|
296 g_return_if_fail (notify_func != NULL); |
|
297 g_return_if_fail (closure->is_invalid == FALSE); |
|
298 g_return_if_fail (closure->n_inotifiers < CLOSURE_MAX_N_INOTIFIERS); |
|
299 closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 1); |
|
300 i = CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers + closure->n_inotifiers; |
|
301 closure->notifiers[i].data = notify_data; |
|
302 closure->notifiers[i].notify = notify_func; |
|
303 INC (closure, n_inotifiers); |
|
304 } |
|
305 |
|
306 static inline gboolean |
|
307 closure_try_remove_inotify (GClosure *closure, |
|
308 gpointer notify_data, |
|
309 GClosureNotify notify_func) |
|
310 { |
|
311 GClosureNotifyData *ndata, *nlast; |
|
312 |
|
313 nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (closure) - 1; |
|
314 for (ndata = nlast + 1 - closure->n_inotifiers; ndata <= nlast; ndata++) |
|
315 if (ndata->notify == notify_func && ndata->data == notify_data) |
|
316 { |
|
317 DEC (closure, n_inotifiers); |
|
318 if (ndata < nlast) |
|
319 *ndata = *nlast; |
|
320 |
|
321 return TRUE; |
|
322 } |
|
323 return FALSE; |
|
324 } |
|
325 |
|
326 static inline gboolean |
|
327 closure_try_remove_fnotify (GClosure *closure, |
|
328 gpointer notify_data, |
|
329 GClosureNotify notify_func) |
|
330 { |
|
331 GClosureNotifyData *ndata, *nlast; |
|
332 |
|
333 nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (closure) - closure->n_inotifiers - 1; |
|
334 for (ndata = nlast + 1 - closure->n_fnotifiers; ndata <= nlast; ndata++) |
|
335 if (ndata->notify == notify_func && ndata->data == notify_data) |
|
336 { |
|
337 DEC (closure, n_fnotifiers); |
|
338 if (ndata < nlast) |
|
339 *ndata = *nlast; |
|
340 if (closure->n_inotifiers) |
|
341 closure->notifiers[(CLOSURE_N_MFUNCS (closure) + |
|
342 closure->n_fnotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) + |
|
343 closure->n_fnotifiers + |
|
344 closure->n_inotifiers)]; |
|
345 return TRUE; |
|
346 } |
|
347 return FALSE; |
|
348 } |
|
349 |
|
350 EXPORT_C GClosure* |
|
351 g_closure_ref (GClosure *closure) |
|
352 { |
|
353 guint new_ref_count; |
|
354 g_return_val_if_fail (closure != NULL, NULL); |
|
355 g_return_val_if_fail (closure->ref_count > 0, NULL); |
|
356 g_return_val_if_fail (closure->ref_count < CLOSURE_MAX_REF_COUNT, NULL); |
|
357 |
|
358 INC_ASSIGN (closure, ref_count, &new_ref_count); |
|
359 g_return_val_if_fail (new_ref_count > 1, NULL); |
|
360 |
|
361 return closure; |
|
362 } |
|
363 |
|
364 EXPORT_C void |
|
365 g_closure_invalidate (GClosure *closure) |
|
366 { |
|
367 g_return_if_fail (closure != NULL); |
|
368 |
|
369 if (!closure->is_invalid) |
|
370 { |
|
371 gboolean was_invalid; |
|
372 g_closure_ref (closure); /* preserve floating flag */ |
|
373 SWAP (closure, is_invalid, TRUE, &was_invalid); |
|
374 /* invalidate only once */ |
|
375 if (!was_invalid) |
|
376 closure_invoke_notifiers (closure, INOTIFY); |
|
377 g_closure_unref (closure); |
|
378 } |
|
379 } |
|
380 |
|
381 EXPORT_C void |
|
382 g_closure_unref (GClosure *closure) |
|
383 { |
|
384 guint new_ref_count; |
|
385 |
|
386 g_return_if_fail (closure != NULL); |
|
387 g_return_if_fail (closure->ref_count > 0); |
|
388 |
|
389 if (closure->ref_count == 1) /* last unref, invalidate first */ |
|
390 g_closure_invalidate (closure); |
|
391 |
|
392 DEC_ASSIGN (closure, ref_count, &new_ref_count); |
|
393 |
|
394 if (new_ref_count == 0) |
|
395 { |
|
396 closure_invoke_notifiers (closure, FNOTIFY); |
|
397 g_free (closure->notifiers); |
|
398 g_free (closure); |
|
399 } |
|
400 } |
|
401 |
|
402 EXPORT_C void |
|
403 g_closure_sink (GClosure *closure) |
|
404 { |
|
405 g_return_if_fail (closure != NULL); |
|
406 g_return_if_fail (closure->ref_count > 0); |
|
407 |
|
408 /* floating is basically a kludge to avoid creating closures |
|
409 * with a ref_count of 0. so the intial ref_count a closure has |
|
410 * is unowned. with invoking g_closure_sink() code may |
|
411 * indicate that it takes over that intiial ref_count. |
|
412 */ |
|
413 if (closure->floating) |
|
414 { |
|
415 gboolean was_floating; |
|
416 SWAP (closure, floating, FALSE, &was_floating); |
|
417 /* unref floating flag only once */ |
|
418 if (was_floating) |
|
419 g_closure_unref (closure); |
|
420 } |
|
421 } |
|
422 |
|
423 EXPORT_C void |
|
424 g_closure_remove_invalidate_notifier (GClosure *closure, |
|
425 gpointer notify_data, |
|
426 GClosureNotify notify_func) |
|
427 { |
|
428 g_return_if_fail (closure != NULL); |
|
429 g_return_if_fail (notify_func != NULL); |
|
430 |
|
431 if (closure->is_invalid && closure->in_inotify && /* account removal of notify_func() while its called */ |
|
432 ((gpointer) closure->marshal) == ((gpointer) notify_func) && |
|
433 closure->data == notify_data) |
|
434 closure->marshal = NULL; |
|
435 else if (!closure_try_remove_inotify (closure, notify_data, notify_func)) |
|
436 g_warning (G_STRLOC ": unable to remove uninstalled invalidation notifier: %p (%p)", |
|
437 notify_func, notify_data); |
|
438 } |
|
439 |
|
440 EXPORT_C void |
|
441 g_closure_remove_finalize_notifier (GClosure *closure, |
|
442 gpointer notify_data, |
|
443 GClosureNotify notify_func) |
|
444 { |
|
445 g_return_if_fail (closure != NULL); |
|
446 g_return_if_fail (notify_func != NULL); |
|
447 |
|
448 if (closure->is_invalid && !closure->in_inotify && /* account removal of notify_func() while its called */ |
|
449 ((gpointer) closure->marshal) == ((gpointer) notify_func) && |
|
450 closure->data == notify_data) |
|
451 closure->marshal = NULL; |
|
452 else if (!closure_try_remove_fnotify (closure, notify_data, notify_func)) |
|
453 g_warning (G_STRLOC ": unable to remove uninstalled finalization notifier: %p (%p)", |
|
454 notify_func, notify_data); |
|
455 } |
|
456 |
|
457 EXPORT_C void |
|
458 g_closure_invoke (GClosure *closure, |
|
459 GValue /*out*/ *return_value, |
|
460 guint n_param_values, |
|
461 const GValue *param_values, |
|
462 gpointer invocation_hint) |
|
463 { |
|
464 g_return_if_fail (closure != NULL); |
|
465 |
|
466 g_closure_ref (closure); /* preserve floating flag */ |
|
467 if (!closure->is_invalid) |
|
468 { |
|
469 GClosureMarshal marshal; |
|
470 gpointer marshal_data; |
|
471 gboolean in_marshal = closure->in_marshal; |
|
472 |
|
473 g_return_if_fail (closure->marshal || closure->meta_marshal); |
|
474 |
|
475 SET (closure, in_marshal, TRUE); |
|
476 if (closure->meta_marshal) |
|
477 { |
|
478 marshal_data = closure->notifiers[0].data; |
|
479 marshal = (GClosureMarshal) closure->notifiers[0].notify; |
|
480 } |
|
481 else |
|
482 { |
|
483 marshal_data = NULL; |
|
484 marshal = closure->marshal; |
|
485 } |
|
486 if (!in_marshal) |
|
487 closure_invoke_notifiers (closure, PRE_NOTIFY); |
|
488 marshal (closure, |
|
489 return_value, |
|
490 n_param_values, param_values, |
|
491 invocation_hint, |
|
492 marshal_data); |
|
493 if (!in_marshal) |
|
494 closure_invoke_notifiers (closure, POST_NOTIFY); |
|
495 SET (closure, in_marshal, in_marshal); |
|
496 } |
|
497 g_closure_unref (closure); |
|
498 } |
|
499 |
|
500 EXPORT_C void |
|
501 g_closure_set_marshal (GClosure *closure, |
|
502 GClosureMarshal marshal) |
|
503 { |
|
504 g_return_if_fail (closure != NULL); |
|
505 g_return_if_fail (marshal != NULL); |
|
506 |
|
507 if (closure->marshal && closure->marshal != marshal) |
|
508 g_warning ("attempt to override closure->marshal (%p) with new marshal (%p)", |
|
509 closure->marshal, marshal); |
|
510 else |
|
511 closure->marshal = marshal; |
|
512 } |
|
513 |
|
514 EXPORT_C GClosure* |
|
515 g_cclosure_new (GCallback callback_func, |
|
516 gpointer user_data, |
|
517 GClosureNotify destroy_data) |
|
518 { |
|
519 GClosure *closure; |
|
520 |
|
521 g_return_val_if_fail (callback_func != NULL, NULL); |
|
522 |
|
523 closure = g_closure_new_simple (sizeof (GCClosure), user_data); |
|
524 if (destroy_data) |
|
525 g_closure_add_finalize_notifier (closure, user_data, destroy_data); |
|
526 ((GCClosure*) closure)->callback = (gpointer) callback_func; |
|
527 |
|
528 return closure; |
|
529 } |
|
530 |
|
531 EXPORT_C GClosure* |
|
532 g_cclosure_new_swap (GCallback callback_func, |
|
533 gpointer user_data, |
|
534 GClosureNotify destroy_data) |
|
535 { |
|
536 GClosure *closure; |
|
537 |
|
538 g_return_val_if_fail (callback_func != NULL, NULL); |
|
539 |
|
540 closure = g_closure_new_simple (sizeof (GCClosure), user_data); |
|
541 if (destroy_data) |
|
542 g_closure_add_finalize_notifier (closure, user_data, destroy_data); |
|
543 ((GCClosure*) closure)->callback = (gpointer) callback_func; |
|
544 SET (closure, derivative_flag, TRUE); |
|
545 |
|
546 return closure; |
|
547 } |
|
548 |
|
549 static void |
|
550 g_type_class_meta_marshal (GClosure *closure, |
|
551 GValue /*out*/ *return_value, |
|
552 guint n_param_values, |
|
553 const GValue *param_values, |
|
554 gpointer invocation_hint, |
|
555 gpointer marshal_data) |
|
556 { |
|
557 GTypeClass *class; |
|
558 gpointer callback; |
|
559 /* GType itype = (GType) closure->data; */ |
|
560 guint offset = GPOINTER_TO_UINT (marshal_data); |
|
561 |
|
562 class = G_TYPE_INSTANCE_GET_CLASS (g_value_peek_pointer (param_values + 0), itype, GTypeClass); |
|
563 callback = G_STRUCT_MEMBER (gpointer, class, offset); |
|
564 if (callback) |
|
565 closure->marshal (closure, |
|
566 return_value, |
|
567 n_param_values, param_values, |
|
568 invocation_hint, |
|
569 callback); |
|
570 } |
|
571 |
|
572 static void |
|
573 g_type_iface_meta_marshal (GClosure *closure, |
|
574 GValue /*out*/ *return_value, |
|
575 guint n_param_values, |
|
576 const GValue *param_values, |
|
577 gpointer invocation_hint, |
|
578 gpointer marshal_data) |
|
579 { |
|
580 GTypeClass *class; |
|
581 gpointer callback; |
|
582 GType itype = (GType) closure->data; |
|
583 guint offset = GPOINTER_TO_UINT (marshal_data); |
|
584 |
|
585 class = G_TYPE_INSTANCE_GET_INTERFACE (g_value_peek_pointer (param_values + 0), itype, GTypeClass); |
|
586 callback = G_STRUCT_MEMBER (gpointer, class, offset); |
|
587 if (callback) |
|
588 closure->marshal (closure, |
|
589 return_value, |
|
590 n_param_values, param_values, |
|
591 invocation_hint, |
|
592 callback); |
|
593 } |
|
594 |
|
595 EXPORT_C GClosure* |
|
596 g_signal_type_cclosure_new (GType itype, |
|
597 guint struct_offset) |
|
598 { |
|
599 GClosure *closure; |
|
600 |
|
601 g_return_val_if_fail (G_TYPE_IS_CLASSED (itype) || G_TYPE_IS_INTERFACE (itype), NULL); |
|
602 g_return_val_if_fail (struct_offset >= sizeof (GTypeClass), NULL); |
|
603 |
|
604 closure = g_closure_new_simple (sizeof (GClosure), (gpointer) itype); |
|
605 if (G_TYPE_IS_INTERFACE (itype)) |
|
606 g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_iface_meta_marshal); |
|
607 else |
|
608 g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal); |
|
609 |
|
610 return closure; |
|
611 } |
|
612 |
|
613 #define __G_CLOSURE_C__ |
|
614 #include "gobjectaliasdef.c" |