1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * GHook: Callback maintenance functions
5 * Copyright (C) 1998 Tim Janik
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
31 #define G_HOOKS_PREALLOC (16)
34 /* --- functions --- */
36 g_hook_list_init (GHookList *hook_list,
39 g_return_if_fail (hook_list != NULL);
40 g_return_if_fail (hook_size >= sizeof (GHook));
42 hook_list->seq_id = 1;
43 hook_list->hook_size = hook_size;
44 hook_list->is_setup = TRUE;
45 hook_list->hooks = NULL;
46 hook_list->hook_memchunk = g_mem_chunk_new ("GHook Memchunk",
48 hook_size * G_HOOKS_PREALLOC,
50 hook_list->hook_free = NULL;
51 hook_list->hook_destroy = NULL;
55 g_hook_list_clear (GHookList *hook_list)
57 g_return_if_fail (hook_list != NULL);
59 if (hook_list->is_setup)
63 hook_list->is_setup = FALSE;
65 hook = hook_list->hooks;
68 g_mem_chunk_destroy (hook_list->hook_memchunk);
69 hook_list->hook_memchunk = NULL;
76 g_hook_ref (hook_list, hook);
77 g_hook_destroy_link (hook_list, hook);
79 g_hook_unref (hook_list, hook);
87 g_hook_alloc (GHookList *hook_list)
91 g_return_val_if_fail (hook_list != NULL, NULL);
92 g_return_val_if_fail (hook_list->is_setup, NULL);
94 hook = g_chunk_new0 (GHook, hook_list->hook_memchunk);
98 hook->flags = G_HOOK_FLAG_ACTIVE;
102 hook->destroy = NULL;
108 g_hook_free (GHookList *hook_list,
111 g_return_if_fail (hook_list != NULL);
112 g_return_if_fail (hook_list->is_setup);
113 g_return_if_fail (hook != NULL);
114 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
116 if (hook_list->hook_free)
117 hook_list->hook_free (hook_list, hook);
119 g_chunk_free (hook, hook_list->hook_memchunk);
123 g_hook_destroy_link (GHookList *hook_list,
126 g_return_if_fail (hook_list != NULL);
127 g_return_if_fail (hook != NULL);
132 hook->flags &= ~G_HOOK_FLAG_ACTIVE;
133 if (hook_list->hook_destroy)
135 hook_list->hook_destroy (hook_list, hook);
136 hook->destroy = NULL;
138 else if (hook->destroy)
140 GDestroyNotify destroy;
142 destroy = hook->destroy;
143 hook->destroy = NULL;
144 destroy (hook->data);
146 g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */
151 g_hook_destroy (GHookList *hook_list,
156 g_return_val_if_fail (hook_list != NULL, FALSE);
157 g_return_val_if_fail (hook_id > 0, FALSE);
159 hook = g_hook_get (hook_list, hook_id);
162 g_hook_destroy_link (hook_list, hook);
170 g_hook_unref (GHookList *hook_list,
173 g_return_if_fail (hook_list != NULL);
174 g_return_if_fail (hook != NULL);
175 g_return_if_fail (hook->ref_count > 0);
178 if (!hook->ref_count)
180 g_return_if_fail (hook->hook_id == 0);
181 g_return_if_fail (!G_HOOK_IN_CALL (hook));
184 hook->prev->next = hook->next;
186 hook_list->hooks = hook->next;
189 hook->next->prev = hook->prev;
194 g_hook_free (hook_list, hook);
196 if (!hook_list->hooks &&
197 !hook_list->is_setup)
199 g_mem_chunk_destroy (hook_list->hook_memchunk);
200 hook_list->hook_memchunk = NULL;
206 g_hook_ref (GHookList *hook_list,
209 g_return_if_fail (hook_list != NULL);
210 g_return_if_fail (hook != NULL);
211 g_return_if_fail (hook->ref_count > 0);
217 g_hook_prepend (GHookList *hook_list,
220 g_return_if_fail (hook_list != NULL);
222 g_hook_insert_before (hook_list, hook_list->hooks, hook);
226 g_hook_insert_before (GHookList *hook_list,
230 g_return_if_fail (hook_list != NULL);
231 g_return_if_fail (hook_list->is_setup);
232 g_return_if_fail (hook != NULL);
233 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
234 g_return_if_fail (hook->func != NULL);
236 hook->hook_id = hook_list->seq_id++;
237 hook->ref_count = 1; /* counterpart to g_hook_destroy_link */
243 hook->prev = sibling->prev;
244 hook->prev->next = hook;
245 hook->next = sibling;
246 sibling->prev = hook;
250 hook_list->hooks = hook;
251 hook->next = sibling;
252 sibling->prev = hook;
257 if (hook_list->hooks)
259 sibling = hook_list->hooks;
260 while (sibling->next)
261 sibling = sibling->next;
262 hook->prev = sibling;
263 sibling->next = hook;
266 hook_list->hooks = hook;
271 g_hook_list_invoke (GHookList *hook_list,
272 gboolean may_recurse)
276 g_return_if_fail (hook_list != NULL);
277 g_return_if_fail (hook_list->is_setup);
279 hook = g_hook_first_valid (hook_list, may_recurse);
283 gboolean was_in_call;
285 func = (GHookFunc) hook->func;
287 was_in_call = G_HOOK_IN_CALL (hook);
288 hook->flags |= G_HOOK_FLAG_IN_CALL;
291 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
293 hook = g_hook_next_valid (hook_list, hook, may_recurse);
298 g_hook_list_invoke_check (GHookList *hook_list,
299 gboolean may_recurse)
303 g_return_if_fail (hook_list != NULL);
304 g_return_if_fail (hook_list->is_setup);
306 hook = g_hook_first_valid (hook_list, may_recurse);
310 gboolean was_in_call;
311 gboolean need_destroy;
313 func = (GHookCheckFunc) hook->func;
315 was_in_call = G_HOOK_IN_CALL (hook);
316 hook->flags |= G_HOOK_FLAG_IN_CALL;
317 need_destroy = !func (hook->data);
319 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
321 g_hook_destroy_link (hook_list, hook);
323 hook = g_hook_next_valid (hook_list, hook, may_recurse);
328 g_hook_list_marshal_check (GHookList *hook_list,
329 gboolean may_recurse,
330 GHookCheckMarshaller marshaller,
335 g_return_if_fail (hook_list != NULL);
336 g_return_if_fail (hook_list->is_setup);
337 g_return_if_fail (marshaller != NULL);
339 hook = g_hook_first_valid (hook_list, may_recurse);
342 gboolean was_in_call;
343 gboolean need_destroy;
345 was_in_call = G_HOOK_IN_CALL (hook);
346 hook->flags |= G_HOOK_FLAG_IN_CALL;
347 need_destroy = !marshaller (hook, data);
349 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
351 g_hook_destroy_link (hook_list, hook);
353 hook = g_hook_next_valid (hook_list, hook, may_recurse);
358 g_hook_list_marshal (GHookList *hook_list,
359 gboolean may_recurse,
360 GHookMarshaller marshaller,
365 g_return_if_fail (hook_list != NULL);
366 g_return_if_fail (hook_list->is_setup);
367 g_return_if_fail (marshaller != NULL);
369 hook = g_hook_first_valid (hook_list, may_recurse);
372 gboolean was_in_call;
374 was_in_call = G_HOOK_IN_CALL (hook);
375 hook->flags |= G_HOOK_FLAG_IN_CALL;
376 marshaller (hook, data);
378 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
380 hook = g_hook_next_valid (hook_list, hook, may_recurse);
385 g_hook_first_valid (GHookList *hook_list,
386 gboolean may_be_in_call)
388 g_return_val_if_fail (hook_list != NULL, NULL);
390 if (hook_list->is_setup)
394 hook = hook_list->hooks;
397 g_hook_ref (hook_list, hook);
398 if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
401 return g_hook_next_valid (hook_list, hook, may_be_in_call);
409 g_hook_next_valid (GHookList *hook_list,
411 gboolean may_be_in_call)
415 g_return_val_if_fail (hook_list != NULL, NULL);
423 if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
425 g_hook_ref (hook_list, hook);
426 g_hook_unref (hook_list, ohook);
432 g_hook_unref (hook_list, ohook);
438 g_hook_get (GHookList *hook_list,
443 g_return_val_if_fail (hook_list != NULL, NULL);
444 g_return_val_if_fail (hook_id > 0, NULL);
446 hook = hook_list->hooks;
449 if (hook->hook_id == hook_id)
458 g_hook_find (GHookList *hook_list,
459 gboolean need_valids,
465 g_return_val_if_fail (hook_list != NULL, NULL);
466 g_return_val_if_fail (func != NULL, NULL);
468 hook = hook_list->hooks;
473 /* test only non-destroyed hooks */
480 g_hook_ref (hook_list, hook);
482 if (func (hook, data) && hook->hook_id && (!need_valids || G_HOOK_ACTIVE (hook)))
484 g_hook_unref (hook_list, hook);
490 g_hook_unref (hook_list, hook);
498 g_hook_find_data (GHookList *hook_list,
499 gboolean need_valids,
504 g_return_val_if_fail (hook_list != NULL, NULL);
506 hook = hook_list->hooks;
509 /* test only non-destroyed hooks */
510 if (hook->data == data &&
512 (!need_valids || G_HOOK_ACTIVE (hook)))
522 g_hook_find_func (GHookList *hook_list,
523 gboolean need_valids,
528 g_return_val_if_fail (hook_list != NULL, NULL);
529 g_return_val_if_fail (func != NULL, NULL);
531 hook = hook_list->hooks;
534 /* test only non-destroyed hooks */
535 if (hook->func == func &&
537 (!need_valids || G_HOOK_ACTIVE (hook)))
547 g_hook_find_func_data (GHookList *hook_list,
548 gboolean need_valids,
554 g_return_val_if_fail (hook_list != NULL, NULL);
555 g_return_val_if_fail (func != NULL, NULL);
557 hook = hook_list->hooks;
560 /* test only non-destroyed hooks */
561 if (hook->data == data &&
562 hook->func == func &&
564 (!need_valids || G_HOOK_ACTIVE (hook)))
574 g_hook_insert_sorted (GHookList *hook_list,
576 GHookCompareFunc func)
580 g_return_if_fail (hook_list != NULL);
581 g_return_if_fail (hook_list->is_setup);
582 g_return_if_fail (hook != NULL);
583 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
584 g_return_if_fail (hook->func != NULL);
585 g_return_if_fail (func != NULL);
587 /* first non-destroyed hook */
588 sibling = hook_list->hooks;
589 while (sibling && !sibling->hook_id)
590 sibling = sibling->next;
596 g_hook_ref (hook_list, sibling);
597 if (func (hook, sibling) <= 0 && sibling->hook_id)
599 g_hook_unref (hook_list, sibling);
603 /* next non-destroyed hook */
605 while (tmp && !tmp->hook_id)
608 g_hook_unref (hook_list, sibling);
612 g_hook_insert_before (hook_list, sibling, hook);
616 g_hook_compare_ids (GHook *new_hook,
619 return ((glong) new_hook->hook_id) - ((glong) sibling->hook_id);