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 (hook_id > 0, FALSE);
144 hook = g_hook_get (hook_list, hook_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->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->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);
265 hook = g_hook_first_valid (hook_list);
268 hook = g_hook_first_valid (hook_list);
269 while (hook && G_HOOK_IS_IN_CALL (hook));
273 register GHookFunc func;
274 gboolean was_in_call;
276 g_hook_ref (hook_list, hook);
279 was_in_call = G_HOOK_IS_IN_CALL (hook);
280 hook->flags |= G_HOOK_IN_CALL;
283 hook->flags &= ~G_HOOK_IN_CALL;
286 tmp = g_hook_next_valid (hook);
289 tmp = g_hook_next_valid (hook);
290 while (tmp && G_HOOK_IS_IN_CALL (tmp));
292 g_hook_unref (hook_list, hook);
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);
307 hook = g_hook_first_valid (hook_list);
310 hook = g_hook_first_valid (hook_list);
311 while (hook && G_HOOK_IS_IN_CALL (hook));
315 register GHookCheckFunc func;
316 gboolean was_in_call;
317 register gboolean need_destroy;
319 g_hook_ref (hook_list, hook);
322 was_in_call = G_HOOK_IS_IN_CALL (hook);
323 hook->flags |= G_HOOK_IN_CALL;
324 need_destroy = !func (hook->data);
326 hook->flags &= ~G_HOOK_IN_CALL;
328 g_hook_destroy_link (hook_list, hook);
331 tmp = g_hook_next_valid (hook);
334 tmp = g_hook_next_valid (hook);
335 while (tmp && G_HOOK_IS_IN_CALL (tmp));
337 g_hook_unref (hook_list, hook);
343 g_hook_list_marshal (GHookList *hook_list,
344 gboolean may_recurse,
345 GHookMarshaller marshaller,
350 g_return_if_fail (hook_list != NULL);
351 g_return_if_fail (hook_list->is_setup);
352 g_return_if_fail (marshaller != NULL);
355 hook = g_hook_first_valid (hook_list);
358 hook = g_hook_first_valid (hook_list);
359 while (hook && G_HOOK_IS_IN_CALL (hook));
363 gboolean was_in_call;
365 g_hook_ref (hook_list, hook);
367 was_in_call = G_HOOK_IS_IN_CALL (hook);
368 hook->flags |= G_HOOK_IN_CALL;
369 marshaller (hook, data);
371 hook->flags &= ~G_HOOK_IN_CALL;
374 tmp = g_hook_next_valid (hook);
377 tmp = g_hook_next_valid (hook);
378 while (tmp && G_HOOK_IS_IN_CALL (tmp));
380 g_hook_unref (hook_list, hook);
386 g_hook_first_valid (GHookList *hook_list)
388 g_return_val_if_fail (hook_list != NULL, NULL);
390 if (hook_list->is_setup)
394 hook = hook_list->hooks;
397 if (G_HOOK_IS_VALID (hook))
400 return g_hook_next_valid (hook);
408 g_hook_next_valid (GHook *hook)
416 if (G_HOOK_IS_VALID (hook))
425 g_hook_get (GHookList *hook_list,
430 g_return_val_if_fail (hook_list != NULL, NULL);
431 g_return_val_if_fail (hook_id > 0, NULL);
433 hook = hook_list->hooks;
436 if (hook->hook_id == hook_id)
445 g_hook_find (GHookList *hook_list,
446 gboolean need_valids,
452 g_return_val_if_fail (hook_list != NULL, NULL);
453 g_return_val_if_fail (func != NULL, NULL);
455 hook = g_hook_first_valid (hook_list);
460 g_hook_ref (hook_list, hook);
462 if (func (hook, data) && hook->hook_id && (!need_valids || G_HOOK_IS_ACTIVE (hook)))
464 g_hook_unref (hook_list, hook);
468 tmp = g_hook_next_valid (hook);
469 g_hook_unref (hook_list, hook);
477 g_hook_find_data (GHookList *hook_list,
478 gboolean need_valids,
481 register GHook *hook;
483 g_return_val_if_fail (hook_list != NULL, NULL);
485 hook = g_hook_first_valid (hook_list);
488 if (hook->data == data && hook->hook_id && (!need_valids || G_HOOK_IS_ACTIVE (hook)))
491 hook = g_hook_next_valid (hook);
498 g_hook_find_func (GHookList *hook_list,
499 gboolean need_valids,
502 register GHook *hook;
504 g_return_val_if_fail (hook_list != NULL, NULL);
505 g_return_val_if_fail (func != NULL, NULL);
507 hook = g_hook_first_valid (hook_list);
510 if (hook->func == func && hook->hook_id && (!need_valids || G_HOOK_IS_ACTIVE (hook)))
513 hook = g_hook_next_valid (hook);
520 g_hook_find_func_data (GHookList *hook_list,
521 gboolean need_valids,
525 register GHook *hook;
527 g_return_val_if_fail (hook_list != NULL, NULL);
528 g_return_val_if_fail (func != NULL, NULL);
530 hook = g_hook_first_valid (hook_list);
533 if (hook->data == data && hook->func == func && hook->hook_id && (!need_valids || G_HOOK_IS_ACTIVE (hook)))
536 hook = g_hook_next_valid (hook);
543 g_hook_insert_sorted (GHookList *hook_list,
545 GHookCompareFunc func)
549 g_return_if_fail (hook_list != NULL);
550 g_return_if_fail (hook_list->is_setup);
551 g_return_if_fail (hook != NULL);
552 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
553 g_return_if_fail (hook->func != NULL);
554 g_return_if_fail (func != NULL);
556 sibling = g_hook_first_valid (hook_list);
562 g_hook_ref (hook_list, sibling);
563 if (func (hook, sibling) <= 0 && sibling->hook_id)
565 g_hook_unref (hook_list, sibling);
568 tmp = g_hook_next_valid (sibling);
569 g_hook_unref (hook_list, sibling);
573 g_hook_insert_before (hook_list, sibling, hook);
577 g_hook_compare_ids (GHook *new_hook,
580 return ((glong) new_hook->hook_id) - ((glong) sibling->hook_id);