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 Lesser 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 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser 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-2000. 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_list->hook_memchunk != NULL);
181 g_return_if_fail (hook != NULL);
182 g_return_if_fail (hook->ref_count > 0);
185 if (!hook->ref_count)
187 g_return_if_fail (hook->hook_id == 0);
188 g_return_if_fail (!G_HOOK_IN_CALL (hook));
191 hook->prev->next = hook->next;
193 hook_list->hooks = hook->next;
196 hook->next->prev = hook->prev;
201 if (!hook_list->is_setup)
203 hook_list->is_setup = TRUE;
204 g_hook_free (hook_list, hook);
205 hook_list->is_setup = FALSE;
207 if (!hook_list->hooks)
209 g_mem_chunk_destroy (hook_list->hook_memchunk);
210 hook_list->hook_memchunk = NULL;
214 g_hook_free (hook_list, hook);
219 g_hook_ref (GHookList *hook_list,
222 g_return_if_fail (hook_list != NULL);
223 g_return_if_fail (hook != NULL);
224 g_return_if_fail (hook->ref_count > 0);
230 g_hook_prepend (GHookList *hook_list,
233 g_return_if_fail (hook_list != NULL);
235 g_hook_insert_before (hook_list, hook_list->hooks, hook);
239 g_hook_insert_before (GHookList *hook_list,
243 g_return_if_fail (hook_list != NULL);
244 g_return_if_fail (hook_list->is_setup);
245 g_return_if_fail (hook != NULL);
246 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
247 g_return_if_fail (hook->func != NULL);
249 hook->hook_id = hook_list->seq_id++;
250 hook->ref_count = 1; /* counterpart to g_hook_destroy_link */
256 hook->prev = sibling->prev;
257 hook->prev->next = hook;
258 hook->next = sibling;
259 sibling->prev = hook;
263 hook_list->hooks = hook;
264 hook->next = sibling;
265 sibling->prev = hook;
270 if (hook_list->hooks)
272 sibling = hook_list->hooks;
273 while (sibling->next)
274 sibling = sibling->next;
275 hook->prev = sibling;
276 sibling->next = hook;
279 hook_list->hooks = hook;
284 g_hook_list_invoke (GHookList *hook_list,
285 gboolean may_recurse)
289 g_return_if_fail (hook_list != NULL);
290 g_return_if_fail (hook_list->is_setup);
292 hook = g_hook_first_valid (hook_list, may_recurse);
296 gboolean was_in_call;
298 func = (GHookFunc) hook->func;
300 was_in_call = G_HOOK_IN_CALL (hook);
301 hook->flags |= G_HOOK_FLAG_IN_CALL;
304 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
306 hook = g_hook_next_valid (hook_list, hook, may_recurse);
311 g_hook_list_invoke_check (GHookList *hook_list,
312 gboolean may_recurse)
316 g_return_if_fail (hook_list != NULL);
317 g_return_if_fail (hook_list->is_setup);
319 hook = g_hook_first_valid (hook_list, may_recurse);
323 gboolean was_in_call;
324 gboolean need_destroy;
326 func = (GHookCheckFunc) hook->func;
328 was_in_call = G_HOOK_IN_CALL (hook);
329 hook->flags |= G_HOOK_FLAG_IN_CALL;
330 need_destroy = !func (hook->data);
332 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
334 g_hook_destroy_link (hook_list, hook);
336 hook = g_hook_next_valid (hook_list, hook, may_recurse);
341 g_hook_list_marshal_check (GHookList *hook_list,
342 gboolean may_recurse,
343 GHookCheckMarshaller marshaller,
348 g_return_if_fail (hook_list != NULL);
349 g_return_if_fail (hook_list->is_setup);
350 g_return_if_fail (marshaller != NULL);
352 hook = g_hook_first_valid (hook_list, may_recurse);
355 gboolean was_in_call;
356 gboolean need_destroy;
358 was_in_call = G_HOOK_IN_CALL (hook);
359 hook->flags |= G_HOOK_FLAG_IN_CALL;
360 need_destroy = !marshaller (hook, data);
362 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
364 g_hook_destroy_link (hook_list, hook);
366 hook = g_hook_next_valid (hook_list, hook, may_recurse);
371 g_hook_list_marshal (GHookList *hook_list,
372 gboolean may_recurse,
373 GHookMarshaller marshaller,
378 g_return_if_fail (hook_list != NULL);
379 g_return_if_fail (hook_list->is_setup);
380 g_return_if_fail (marshaller != NULL);
382 hook = g_hook_first_valid (hook_list, may_recurse);
385 gboolean was_in_call;
387 was_in_call = G_HOOK_IN_CALL (hook);
388 hook->flags |= G_HOOK_FLAG_IN_CALL;
389 marshaller (hook, data);
391 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
393 hook = g_hook_next_valid (hook_list, hook, may_recurse);
398 g_hook_first_valid (GHookList *hook_list,
399 gboolean may_be_in_call)
401 g_return_val_if_fail (hook_list != NULL, NULL);
403 if (hook_list->is_setup)
407 hook = hook_list->hooks;
410 g_hook_ref (hook_list, hook);
411 if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
414 return g_hook_next_valid (hook_list, hook, may_be_in_call);
422 g_hook_next_valid (GHookList *hook_list,
424 gboolean may_be_in_call)
428 g_return_val_if_fail (hook_list != NULL, NULL);
436 if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
438 g_hook_ref (hook_list, hook);
439 g_hook_unref (hook_list, ohook);
445 g_hook_unref (hook_list, ohook);
451 g_hook_get (GHookList *hook_list,
456 g_return_val_if_fail (hook_list != NULL, NULL);
457 g_return_val_if_fail (hook_id > 0, NULL);
459 hook = hook_list->hooks;
462 if (hook->hook_id == hook_id)
471 g_hook_find (GHookList *hook_list,
472 gboolean need_valids,
478 g_return_val_if_fail (hook_list != NULL, NULL);
479 g_return_val_if_fail (func != NULL, NULL);
481 hook = hook_list->hooks;
486 /* test only non-destroyed hooks */
493 g_hook_ref (hook_list, hook);
495 if (func (hook, data) && hook->hook_id && (!need_valids || G_HOOK_ACTIVE (hook)))
497 g_hook_unref (hook_list, hook);
503 g_hook_unref (hook_list, hook);
511 g_hook_find_data (GHookList *hook_list,
512 gboolean need_valids,
517 g_return_val_if_fail (hook_list != NULL, NULL);
519 hook = hook_list->hooks;
522 /* test only non-destroyed hooks */
523 if (hook->data == data &&
525 (!need_valids || G_HOOK_ACTIVE (hook)))
535 g_hook_find_func (GHookList *hook_list,
536 gboolean need_valids,
541 g_return_val_if_fail (hook_list != NULL, NULL);
542 g_return_val_if_fail (func != NULL, NULL);
544 hook = hook_list->hooks;
547 /* test only non-destroyed hooks */
548 if (hook->func == func &&
550 (!need_valids || G_HOOK_ACTIVE (hook)))
560 g_hook_find_func_data (GHookList *hook_list,
561 gboolean need_valids,
567 g_return_val_if_fail (hook_list != NULL, NULL);
568 g_return_val_if_fail (func != NULL, NULL);
570 hook = hook_list->hooks;
573 /* test only non-destroyed hooks */
574 if (hook->data == data &&
575 hook->func == func &&
577 (!need_valids || G_HOOK_ACTIVE (hook)))
587 g_hook_insert_sorted (GHookList *hook_list,
589 GHookCompareFunc func)
593 g_return_if_fail (hook_list != NULL);
594 g_return_if_fail (hook_list->is_setup);
595 g_return_if_fail (hook != NULL);
596 g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
597 g_return_if_fail (hook->func != NULL);
598 g_return_if_fail (func != NULL);
600 /* first non-destroyed hook */
601 sibling = hook_list->hooks;
602 while (sibling && !sibling->hook_id)
603 sibling = sibling->next;
609 g_hook_ref (hook_list, sibling);
610 if (func (hook, sibling) <= 0 && sibling->hook_id)
612 g_hook_unref (hook_list, sibling);
616 /* next non-destroyed hook */
618 while (tmp && !tmp->hook_id)
621 g_hook_unref (hook_list, sibling);
625 g_hook_insert_before (hook_list, sibling, hook);
629 g_hook_compare_ids (GHook *new_hook,
632 return ((glong) new_hook->hook_id) - ((glong) sibling->hook_id);