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.
24 * Modified by the GLib Team and others 1997-1999. See the AUTHORS
25 * file for a list of people on the GLib Team. See the ChangeLog
26 * files for a list of changes. These files are distributed with
27 * GLib at ftp://ftp.gtk.org/pub/gtk/.
38 #define G_HOOKS_PREALLOC (16)
41 /* --- functions --- */
43 g_hook_list_init (GHookList *hook_list,
46 g_return_if_fail (hook_list != NULL);
47 g_return_if_fail (hook_size >= sizeof (GHook));
49 hook_list->seq_id = 1;
50 hook_list->hook_size = hook_size;
51 hook_list->is_setup = TRUE;
52 hook_list->hooks = NULL;
53 hook_list->hook_memchunk = g_mem_chunk_new ("GHook Memchunk",
55 hook_size * G_HOOKS_PREALLOC,
57 hook_list->hook_free = NULL;
58 hook_list->hook_destroy = NULL;
62 g_hook_list_clear (GHookList *hook_list)
64 g_return_if_fail (hook_list != NULL);
66 if (hook_list->is_setup)
70 hook_list->is_setup = FALSE;
72 hook = hook_list->hooks;
75 g_mem_chunk_destroy (hook_list->hook_memchunk);
76 hook_list->hook_memchunk = NULL;
83 g_hook_ref (hook_list, hook);
84 g_hook_destroy_link (hook_list, hook);
86 g_hook_unref (hook_list, hook);
94 g_hook_alloc (GHookList *hook_list)
98 g_return_val_if_fail (hook_list != NULL, NULL);
99 g_return_val_if_fail (hook_list->is_setup, NULL);
101 hook = g_chunk_new0 (GHook, hook_list->hook_memchunk);
105 hook->flags = G_HOOK_FLAG_ACTIVE;
109 hook->destroy = NULL;
115 g_hook_free (GHookList *hook_list,
118 g_return_if_fail (hook_list != NULL);
119 g_return_if_fail (hook_list->is_setup);
120 g_return_if_fail (hook != NULL);
121 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
123 if (hook_list->hook_free)
124 hook_list->hook_free (hook_list, hook);
126 g_chunk_free (hook, hook_list->hook_memchunk);
130 g_hook_destroy_link (GHookList *hook_list,
133 g_return_if_fail (hook_list != NULL);
134 g_return_if_fail (hook != NULL);
139 hook->flags &= ~G_HOOK_FLAG_ACTIVE;
140 if (hook_list->hook_destroy)
142 if (hook_list->hook_destroy != G_HOOK_DEFERRED_DESTROY)
143 hook_list->hook_destroy (hook_list, hook);
145 else if (hook->destroy)
147 hook->destroy (hook->data);
150 hook->destroy = NULL;
152 g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */
157 g_hook_destroy (GHookList *hook_list,
162 g_return_val_if_fail (hook_list != NULL, FALSE);
163 g_return_val_if_fail (hook_id > 0, FALSE);
165 hook = g_hook_get (hook_list, hook_id);
168 g_hook_destroy_link (hook_list, hook);
176 g_hook_unref (GHookList *hook_list,
179 g_return_if_fail (hook_list != NULL);
180 g_return_if_fail (hook != NULL);
181 g_return_if_fail (hook->ref_count > 0);
184 if (!hook->ref_count)
186 g_return_if_fail (hook->hook_id == 0);
187 g_return_if_fail (!G_HOOK_IN_CALL (hook));
190 hook->prev->next = hook->next;
192 hook_list->hooks = hook->next;
195 hook->next->prev = hook->prev;
200 g_hook_free (hook_list, hook);
202 if (!hook_list->hooks &&
203 !hook_list->is_setup)
205 g_mem_chunk_destroy (hook_list->hook_memchunk);
206 hook_list->hook_memchunk = NULL;
212 g_hook_ref (GHookList *hook_list,
215 g_return_if_fail (hook_list != NULL);
216 g_return_if_fail (hook != NULL);
217 g_return_if_fail (hook->ref_count > 0);
223 g_hook_prepend (GHookList *hook_list,
226 g_return_if_fail (hook_list != NULL);
228 g_hook_insert_before (hook_list, hook_list->hooks, hook);
232 g_hook_insert_before (GHookList *hook_list,
236 g_return_if_fail (hook_list != NULL);
237 g_return_if_fail (hook_list->is_setup);
238 g_return_if_fail (hook != NULL);
239 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
240 g_return_if_fail (hook->func != NULL);
242 hook->hook_id = hook_list->seq_id++;
243 hook->ref_count = 1; /* counterpart to g_hook_destroy_link */
249 hook->prev = sibling->prev;
250 hook->prev->next = hook;
251 hook->next = sibling;
252 sibling->prev = hook;
256 hook_list->hooks = hook;
257 hook->next = sibling;
258 sibling->prev = hook;
263 if (hook_list->hooks)
265 sibling = hook_list->hooks;
266 while (sibling->next)
267 sibling = sibling->next;
268 hook->prev = sibling;
269 sibling->next = hook;
272 hook_list->hooks = hook;
277 g_hook_list_invoke (GHookList *hook_list,
278 gboolean may_recurse)
282 g_return_if_fail (hook_list != NULL);
283 g_return_if_fail (hook_list->is_setup);
285 hook = g_hook_first_valid (hook_list, may_recurse);
289 gboolean was_in_call;
291 func = (GHookFunc) hook->func;
293 was_in_call = G_HOOK_IN_CALL (hook);
294 hook->flags |= G_HOOK_FLAG_IN_CALL;
297 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
299 hook = g_hook_next_valid (hook_list, hook, may_recurse);
304 g_hook_list_invoke_check (GHookList *hook_list,
305 gboolean may_recurse)
309 g_return_if_fail (hook_list != NULL);
310 g_return_if_fail (hook_list->is_setup);
312 hook = g_hook_first_valid (hook_list, may_recurse);
316 gboolean was_in_call;
317 gboolean need_destroy;
319 func = (GHookCheckFunc) hook->func;
321 was_in_call = G_HOOK_IN_CALL (hook);
322 hook->flags |= G_HOOK_FLAG_IN_CALL;
323 need_destroy = !func (hook->data);
325 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
327 g_hook_destroy_link (hook_list, hook);
329 hook = g_hook_next_valid (hook_list, hook, may_recurse);
334 g_hook_list_marshal_check (GHookList *hook_list,
335 gboolean may_recurse,
336 GHookCheckMarshaller marshaller,
341 g_return_if_fail (hook_list != NULL);
342 g_return_if_fail (hook_list->is_setup);
343 g_return_if_fail (marshaller != NULL);
345 hook = g_hook_first_valid (hook_list, may_recurse);
348 gboolean was_in_call;
349 gboolean need_destroy;
351 was_in_call = G_HOOK_IN_CALL (hook);
352 hook->flags |= G_HOOK_FLAG_IN_CALL;
353 need_destroy = !marshaller (hook, data);
355 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
357 g_hook_destroy_link (hook_list, hook);
359 hook = g_hook_next_valid (hook_list, hook, may_recurse);
364 g_hook_list_marshal (GHookList *hook_list,
365 gboolean may_recurse,
366 GHookMarshaller marshaller,
371 g_return_if_fail (hook_list != NULL);
372 g_return_if_fail (hook_list->is_setup);
373 g_return_if_fail (marshaller != NULL);
375 hook = g_hook_first_valid (hook_list, may_recurse);
378 gboolean was_in_call;
380 was_in_call = G_HOOK_IN_CALL (hook);
381 hook->flags |= G_HOOK_FLAG_IN_CALL;
382 marshaller (hook, data);
384 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
386 hook = g_hook_next_valid (hook_list, hook, may_recurse);
391 g_hook_first_valid (GHookList *hook_list,
392 gboolean may_be_in_call)
394 g_return_val_if_fail (hook_list != NULL, NULL);
396 if (hook_list->is_setup)
400 hook = hook_list->hooks;
403 g_hook_ref (hook_list, hook);
404 if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
407 return g_hook_next_valid (hook_list, hook, may_be_in_call);
415 g_hook_next_valid (GHookList *hook_list,
417 gboolean may_be_in_call)
421 g_return_val_if_fail (hook_list != NULL, NULL);
429 if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
431 g_hook_ref (hook_list, hook);
432 g_hook_unref (hook_list, ohook);
438 g_hook_unref (hook_list, ohook);
444 g_hook_get (GHookList *hook_list,
449 g_return_val_if_fail (hook_list != NULL, NULL);
450 g_return_val_if_fail (hook_id > 0, NULL);
452 hook = hook_list->hooks;
455 if (hook->hook_id == hook_id)
464 g_hook_find (GHookList *hook_list,
465 gboolean need_valids,
471 g_return_val_if_fail (hook_list != NULL, NULL);
472 g_return_val_if_fail (func != NULL, NULL);
474 hook = hook_list->hooks;
479 /* test only non-destroyed hooks */
486 g_hook_ref (hook_list, hook);
488 if (func (hook, data) && hook->hook_id && (!need_valids || G_HOOK_ACTIVE (hook)))
490 g_hook_unref (hook_list, hook);
496 g_hook_unref (hook_list, hook);
504 g_hook_find_data (GHookList *hook_list,
505 gboolean need_valids,
510 g_return_val_if_fail (hook_list != NULL, NULL);
512 hook = hook_list->hooks;
515 /* test only non-destroyed hooks */
516 if (hook->data == data &&
518 (!need_valids || G_HOOK_ACTIVE (hook)))
528 g_hook_find_func (GHookList *hook_list,
529 gboolean need_valids,
534 g_return_val_if_fail (hook_list != NULL, NULL);
535 g_return_val_if_fail (func != NULL, NULL);
537 hook = hook_list->hooks;
540 /* test only non-destroyed hooks */
541 if (hook->func == func &&
543 (!need_valids || G_HOOK_ACTIVE (hook)))
553 g_hook_find_func_data (GHookList *hook_list,
554 gboolean need_valids,
560 g_return_val_if_fail (hook_list != NULL, NULL);
561 g_return_val_if_fail (func != NULL, NULL);
563 hook = hook_list->hooks;
566 /* test only non-destroyed hooks */
567 if (hook->data == data &&
568 hook->func == func &&
570 (!need_valids || G_HOOK_ACTIVE (hook)))
580 g_hook_insert_sorted (GHookList *hook_list,
582 GHookCompareFunc func)
586 g_return_if_fail (hook_list != NULL);
587 g_return_if_fail (hook_list->is_setup);
588 g_return_if_fail (hook != NULL);
589 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
590 g_return_if_fail (hook->func != NULL);
591 g_return_if_fail (func != NULL);
593 /* first non-destroyed hook */
594 sibling = hook_list->hooks;
595 while (sibling && !sibling->hook_id)
596 sibling = sibling->next;
602 g_hook_ref (hook_list, sibling);
603 if (func (hook, sibling) <= 0 && sibling->hook_id)
605 g_hook_unref (hook_list, sibling);
609 /* next non-destroyed hook */
611 while (tmp && !tmp->hook_id)
614 g_hook_unref (hook_list, sibling);
618 g_hook_insert_before (hook_list, sibling, hook);
622 g_hook_compare_ids (GHook *new_hook,
625 return ((glong) new_hook->hook_id) - ((glong) sibling->hook_id);