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.
26 #define G_HOOKS_PREALLOC (16)
29 /* --- functions --- */
31 g_hook_list_init (GHookList *hook_list,
34 g_return_if_fail (hook_list != NULL);
35 g_return_if_fail (hook_size >= sizeof (GHook));
37 hook_list->seq_id = 1;
38 hook_list->hook_size = hook_size;
39 hook_list->is_setup = TRUE;
40 hook_list->hooks = NULL;
41 hook_list->hook_memchunk = g_mem_chunk_new ("GHook Memchunk",
43 hook_size * G_HOOKS_PREALLOC,
48 g_hook_list_clear (GHookList *hook_list)
50 g_return_if_fail (hook_list != NULL);
52 if (hook_list->is_setup)
56 hook_list->is_setup = FALSE;
58 hook = hook_list->hooks;
61 g_mem_chunk_destroy (hook_list->hook_memchunk);
62 hook_list->hook_memchunk = NULL;
69 g_hook_ref (hook_list, hook);
70 g_hook_destroy_link (hook_list, hook);
72 g_hook_unref (hook_list, hook);
80 g_hook_alloc (GHookList *hook_list)
84 g_return_val_if_fail (hook_list != NULL, NULL);
85 g_return_val_if_fail (hook_list->is_setup, NULL);
87 hook = g_chunk_new0 (GHook, hook_list->hook_memchunk);
91 hook->flags = G_HOOK_ACTIVE;
101 g_hook_free (GHookList *hook_list,
104 g_return_if_fail (hook_list != NULL);
105 g_return_if_fail (hook_list->is_setup);
106 g_return_if_fail (hook != NULL);
107 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
109 g_chunk_free (hook, hook_list->hook_memchunk);
113 g_hook_destroy_link (GHookList *hook_list,
116 g_return_if_fail (hook_list != NULL);
117 g_return_if_fail (hook != NULL);
122 hook->flags &= ~G_HOOK_ACTIVE;
125 register GDestroyNotify destroy;
127 destroy = hook->destroy;
128 hook->destroy = NULL;
129 destroy (hook->data);
131 g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */
136 g_hook_destroy (GHookList *hook_list,
141 g_return_val_if_fail (hook_list != NULL, FALSE);
142 g_return_val_if_fail (id > 0, FALSE);
144 hook = g_hook_get (hook_list, id);
147 g_hook_destroy_link (hook_list, hook);
155 g_hook_unref (GHookList *hook_list,
158 g_return_if_fail (hook_list != NULL);
159 g_return_if_fail (hook != NULL);
160 g_return_if_fail (hook->ref_count > 0);
163 if (!hook->ref_count)
165 g_return_if_fail (hook->id == 0);
166 g_return_if_fail (!G_HOOK_IS_IN_CALL (hook));
169 hook->prev->next = hook->next;
171 hook_list->hooks = hook->next;
174 hook->next->prev = hook->prev;
179 g_chunk_free (hook, hook_list->hook_memchunk);
181 if (!hook_list->hooks &&
182 !hook_list->is_setup)
184 g_mem_chunk_destroy (hook_list->hook_memchunk);
185 hook_list->hook_memchunk = NULL;
191 g_hook_ref (GHookList *hook_list,
194 g_return_if_fail (hook_list != NULL);
195 g_return_if_fail (hook != NULL);
196 g_return_if_fail (hook->ref_count > 0);
202 g_hook_prepend (GHookList *hook_list,
205 g_return_if_fail (hook_list != NULL);
207 g_hook_insert_before (hook_list, hook_list->hooks, hook);
211 g_hook_insert_before (GHookList *hook_list,
215 g_return_if_fail (hook_list != NULL);
216 g_return_if_fail (hook_list->is_setup);
217 g_return_if_fail (hook != NULL);
218 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
219 g_return_if_fail (hook->func != NULL);
221 hook->id = hook_list->seq_id++;
222 hook->ref_count = 1; /* counterpart to g_hook_destroy_link */
228 hook->prev = sibling->prev;
229 hook->prev->next = hook;
230 hook->next = sibling;
231 sibling->prev = hook;
235 hook_list->hooks = hook;
236 hook->next = sibling;
237 sibling->prev = hook;
242 if (hook_list->hooks)
244 sibling = hook_list->hooks;
245 while (sibling->next)
246 sibling = sibling->next;
247 hook->prev = sibling;
248 sibling->next = hook;
251 hook_list->hooks = hook;
256 g_hook_list_invoke (GHookList *hook_list,
257 gboolean may_recurse)
261 g_return_if_fail (hook_list != NULL);
262 g_return_if_fail (hook_list->is_setup);
264 hook = g_hook_first_valid (hook_list);
268 register GHookFunc func;
269 gboolean was_in_call;
271 g_hook_ref (hook_list, hook);
274 was_in_call = G_HOOK_IS_IN_CALL (hook);
275 hook->flags |= G_HOOK_IN_CALL;
278 hook->flags &= ~G_HOOK_IN_CALL;
281 tmp = g_hook_next_valid (hook);
284 tmp = g_hook_next_valid (hook);
285 while (tmp && G_HOOK_IS_IN_CALL (tmp));
287 g_hook_unref (hook_list, hook);
293 g_hook_list_invoke_check (GHookList *hook_list,
294 gboolean may_recurse)
298 g_return_if_fail (hook_list != NULL);
299 g_return_if_fail (hook_list->is_setup);
301 hook = g_hook_first_valid (hook_list);
305 register GHookCheckFunc func;
306 gboolean was_in_call;
307 register gboolean need_destroy;
309 g_hook_ref (hook_list, hook);
312 was_in_call = G_HOOK_IS_IN_CALL (hook);
313 hook->flags |= G_HOOK_IN_CALL;
314 need_destroy = !func (hook->data);
316 hook->flags &= ~G_HOOK_IN_CALL;
318 g_hook_destroy_link (hook_list, hook);
321 tmp = g_hook_next_valid (hook);
324 tmp = g_hook_next_valid (hook);
325 while (tmp && G_HOOK_IS_IN_CALL (tmp));
327 g_hook_unref (hook_list, hook);
333 g_hook_list_marshall (GHookList *hook_list,
334 gboolean may_recurse,
335 GHookMarshaller marshaller,
340 g_return_if_fail (hook_list != NULL);
341 g_return_if_fail (hook_list->is_setup);
342 g_return_if_fail (marshaller != NULL);
344 hook = g_hook_first_valid (hook_list);
348 gboolean was_in_call;
350 g_hook_ref (hook_list, hook);
352 was_in_call = G_HOOK_IS_IN_CALL (hook);
353 hook->flags |= G_HOOK_IN_CALL;
354 marshaller (hook, data);
356 hook->flags &= ~G_HOOK_IN_CALL;
359 tmp = g_hook_next_valid (hook);
362 tmp = g_hook_next_valid (hook);
363 while (tmp && G_HOOK_IS_IN_CALL (tmp));
365 g_hook_unref (hook_list, hook);
371 g_hook_first_valid (GHookList *hook_list)
373 g_return_val_if_fail (hook_list != NULL, NULL);
375 if (hook_list->is_setup)
379 hook = hook_list->hooks;
382 if (G_HOOK_IS_VALID (hook))
385 return g_hook_next_valid (hook);
393 g_hook_next_valid (GHook *hook)
401 if (G_HOOK_IS_VALID (hook))
410 g_hook_get (GHookList *hook_list,
415 g_return_val_if_fail (hook_list != NULL, NULL);
416 g_return_val_if_fail (id > 0, NULL);
418 hook = hook_list->hooks;
430 g_hook_find (GHookList *hook_list,
431 gboolean need_valids,
437 g_return_val_if_fail (hook_list != NULL, NULL);
438 g_return_val_if_fail (func != NULL, NULL);
440 hook = g_hook_first_valid (hook_list);
445 g_hook_ref (hook_list, hook);
447 if (func (hook, data) && hook->id && (!need_valids || G_HOOK_IS_ACTIVE (hook)))
449 g_hook_unref (hook_list, hook);
453 tmp = g_hook_next_valid (hook);
454 g_hook_unref (hook_list, hook);
462 g_hook_find_data (GHookList *hook_list,
463 gboolean need_valids,
466 register GHook *hook;
468 g_return_val_if_fail (hook_list != NULL, NULL);
470 hook = g_hook_first_valid (hook_list);
473 if (hook->data == data && hook->id && (!need_valids || G_HOOK_IS_ACTIVE (hook)))
476 hook = g_hook_next_valid (hook);
483 g_hook_find_func (GHookList *hook_list,
484 gboolean need_valids,
487 register GHook *hook;
489 g_return_val_if_fail (hook_list != NULL, NULL);
490 g_return_val_if_fail (func != NULL, NULL);
492 hook = g_hook_first_valid (hook_list);
495 if (hook->func == func && hook->id && (!need_valids || G_HOOK_IS_ACTIVE (hook)))
498 hook = g_hook_next_valid (hook);
505 g_hook_find_func_data (GHookList *hook_list,
506 gboolean need_valids,
510 register GHook *hook;
512 g_return_val_if_fail (hook_list != NULL, NULL);
513 g_return_val_if_fail (func != NULL, NULL);
515 hook = g_hook_first_valid (hook_list);
518 if (hook->data == data && hook->func == func && hook->id && (!need_valids || G_HOOK_IS_ACTIVE (hook)))
521 hook = g_hook_next_valid (hook);
528 g_hook_insert_sorted (GHookList *hook_list,
530 GHookCompareFunc func)
534 g_return_if_fail (hook_list != NULL);
535 g_return_if_fail (hook_list->is_setup);
536 g_return_if_fail (hook != NULL);
537 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
538 g_return_if_fail (hook->func != NULL);
539 g_return_if_fail (func != NULL);
541 sibling = g_hook_first_valid (hook_list);
547 g_hook_ref (hook_list, sibling);
548 if (func (hook, sibling) <= 0 && sibling->id)
550 g_hook_unref (hook_list, sibling);
553 tmp = g_hook_next_valid (sibling);
554 g_hook_unref (hook_list, sibling);
558 g_hook_insert_before (hook_list, sibling, hook);
562 g_hook_compare_ids (GHook *new_hook,
565 return ((glong) new_hook->id) - ((glong) sibling->id);