Added the macros G_(U)?INT_(8|16|32|64)_FORMAT to use for printf and (much
[glib.git] / ghook.c
bloba3e3a78f73421bb2d4285c4d4f1f6176230bc8ac
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/.
30 /*
31 * MT safe
34 #include "glib.h"
37 /* --- defines --- */
38 #define G_HOOKS_PREALLOC (16)
41 /* --- functions --- */
42 void
43 g_hook_list_init (GHookList *hook_list,
44 guint hook_size)
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",
54 hook_size,
55 hook_size * G_HOOKS_PREALLOC,
56 G_ALLOC_AND_FREE);
57 hook_list->hook_free = NULL;
58 hook_list->hook_destroy = NULL;
61 void
62 g_hook_list_clear (GHookList *hook_list)
64 g_return_if_fail (hook_list != NULL);
66 if (hook_list->is_setup)
68 GHook *hook;
70 hook_list->is_setup = FALSE;
72 hook = hook_list->hooks;
73 if (!hook)
75 g_mem_chunk_destroy (hook_list->hook_memchunk);
76 hook_list->hook_memchunk = NULL;
78 else
81 GHook *tmp;
83 g_hook_ref (hook_list, hook);
84 g_hook_destroy_link (hook_list, hook);
85 tmp = hook->next;
86 g_hook_unref (hook_list, hook);
87 hook = tmp;
89 while (hook);
93 GHook*
94 g_hook_alloc (GHookList *hook_list)
96 GHook *hook;
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);
102 hook->data = NULL;
103 hook->next = NULL;
104 hook->prev = NULL;
105 hook->flags = G_HOOK_FLAG_ACTIVE;
106 hook->ref_count = 0;
107 hook->hook_id = 0;
108 hook->func = NULL;
109 hook->destroy = NULL;
111 return hook;
114 void
115 g_hook_free (GHookList *hook_list,
116 GHook *hook)
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);
129 void
130 g_hook_destroy_link (GHookList *hook_list,
131 GHook *hook)
133 g_return_if_fail (hook_list != NULL);
134 g_return_if_fail (hook != NULL);
136 if (hook->hook_id)
138 hook->hook_id = 0;
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);
148 hook->data = NULL;
149 hook->func = NULL;
150 hook->destroy = NULL;
152 g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */
156 gboolean
157 g_hook_destroy (GHookList *hook_list,
158 guint hook_id)
160 GHook *hook;
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);
166 if (hook)
168 g_hook_destroy_link (hook_list, hook);
169 return TRUE;
172 return FALSE;
175 void
176 g_hook_unref (GHookList *hook_list,
177 GHook *hook)
179 g_return_if_fail (hook_list != NULL);
180 g_return_if_fail (hook != NULL);
181 g_return_if_fail (hook->ref_count > 0);
183 hook->ref_count--;
184 if (!hook->ref_count)
186 g_return_if_fail (hook->hook_id == 0);
187 g_return_if_fail (!G_HOOK_IN_CALL (hook));
189 if (hook->prev)
190 hook->prev->next = hook->next;
191 else
192 hook_list->hooks = hook->next;
193 if (hook->next)
195 hook->next->prev = hook->prev;
196 hook->next = NULL;
198 hook->prev = NULL;
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;
211 void
212 g_hook_ref (GHookList *hook_list,
213 GHook *hook)
215 g_return_if_fail (hook_list != NULL);
216 g_return_if_fail (hook != NULL);
217 g_return_if_fail (hook->ref_count > 0);
219 hook->ref_count++;
222 void
223 g_hook_prepend (GHookList *hook_list,
224 GHook *hook)
226 g_return_if_fail (hook_list != NULL);
228 g_hook_insert_before (hook_list, hook_list->hooks, hook);
231 void
232 g_hook_insert_before (GHookList *hook_list,
233 GHook *sibling,
234 GHook *hook)
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 */
245 if (sibling)
247 if (sibling->prev)
249 hook->prev = sibling->prev;
250 hook->prev->next = hook;
251 hook->next = sibling;
252 sibling->prev = hook;
254 else
256 hook_list->hooks = hook;
257 hook->next = sibling;
258 sibling->prev = hook;
261 else
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;
271 else
272 hook_list->hooks = hook;
276 void
277 g_hook_list_invoke (GHookList *hook_list,
278 gboolean may_recurse)
280 GHook *hook;
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);
286 while (hook)
288 GHookFunc func;
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;
295 func (hook->data);
296 if (!was_in_call)
297 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
299 hook = g_hook_next_valid (hook_list, hook, may_recurse);
303 void
304 g_hook_list_invoke_check (GHookList *hook_list,
305 gboolean may_recurse)
307 GHook *hook;
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);
313 while (hook)
315 GHookCheckFunc func;
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);
324 if (!was_in_call)
325 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
326 if (need_destroy)
327 g_hook_destroy_link (hook_list, hook);
329 hook = g_hook_next_valid (hook_list, hook, may_recurse);
333 void
334 g_hook_list_marshal_check (GHookList *hook_list,
335 gboolean may_recurse,
336 GHookCheckMarshaller marshaller,
337 gpointer data)
339 GHook *hook;
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);
346 while (hook)
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);
354 if (!was_in_call)
355 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
356 if (need_destroy)
357 g_hook_destroy_link (hook_list, hook);
359 hook = g_hook_next_valid (hook_list, hook, may_recurse);
363 void
364 g_hook_list_marshal (GHookList *hook_list,
365 gboolean may_recurse,
366 GHookMarshaller marshaller,
367 gpointer data)
369 GHook *hook;
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);
376 while (hook)
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);
383 if (!was_in_call)
384 hook->flags &= ~G_HOOK_FLAG_IN_CALL;
386 hook = g_hook_next_valid (hook_list, hook, may_recurse);
390 GHook*
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)
398 GHook *hook;
400 hook = hook_list->hooks;
401 if (hook)
403 g_hook_ref (hook_list, hook);
404 if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
405 return hook;
406 else
407 return g_hook_next_valid (hook_list, hook, may_be_in_call);
411 return NULL;
414 GHook*
415 g_hook_next_valid (GHookList *hook_list,
416 GHook *hook,
417 gboolean may_be_in_call)
419 GHook *ohook = hook;
421 g_return_val_if_fail (hook_list != NULL, NULL);
423 if (!hook)
424 return NULL;
426 hook = hook->next;
427 while (hook)
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);
434 return hook;
436 hook = hook->next;
438 g_hook_unref (hook_list, ohook);
440 return NULL;
443 GHook*
444 g_hook_get (GHookList *hook_list,
445 guint hook_id)
447 GHook *hook;
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;
453 while (hook)
455 if (hook->hook_id == hook_id)
456 return hook;
457 hook = hook->next;
460 return NULL;
463 GHook*
464 g_hook_find (GHookList *hook_list,
465 gboolean need_valids,
466 GHookFindFunc func,
467 gpointer data)
469 GHook *hook;
471 g_return_val_if_fail (hook_list != NULL, NULL);
472 g_return_val_if_fail (func != NULL, NULL);
474 hook = hook_list->hooks;
475 while (hook)
477 GHook *tmp;
479 /* test only non-destroyed hooks */
480 if (!hook->hook_id)
482 hook = hook->next;
483 continue;
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);
492 return hook;
495 tmp = hook->next;
496 g_hook_unref (hook_list, hook);
497 hook = tmp;
500 return NULL;
503 GHook*
504 g_hook_find_data (GHookList *hook_list,
505 gboolean need_valids,
506 gpointer data)
508 GHook *hook;
510 g_return_val_if_fail (hook_list != NULL, NULL);
512 hook = hook_list->hooks;
513 while (hook)
515 /* test only non-destroyed hooks */
516 if (hook->data == data &&
517 hook->hook_id &&
518 (!need_valids || G_HOOK_ACTIVE (hook)))
519 return hook;
521 hook = hook->next;
524 return NULL;
527 GHook*
528 g_hook_find_func (GHookList *hook_list,
529 gboolean need_valids,
530 gpointer func)
532 GHook *hook;
534 g_return_val_if_fail (hook_list != NULL, NULL);
535 g_return_val_if_fail (func != NULL, NULL);
537 hook = hook_list->hooks;
538 while (hook)
540 /* test only non-destroyed hooks */
541 if (hook->func == func &&
542 hook->hook_id &&
543 (!need_valids || G_HOOK_ACTIVE (hook)))
544 return hook;
546 hook = hook->next;
549 return NULL;
552 GHook*
553 g_hook_find_func_data (GHookList *hook_list,
554 gboolean need_valids,
555 gpointer func,
556 gpointer data)
558 GHook *hook;
560 g_return_val_if_fail (hook_list != NULL, NULL);
561 g_return_val_if_fail (func != NULL, NULL);
563 hook = hook_list->hooks;
564 while (hook)
566 /* test only non-destroyed hooks */
567 if (hook->data == data &&
568 hook->func == func &&
569 hook->hook_id &&
570 (!need_valids || G_HOOK_ACTIVE (hook)))
571 return hook;
573 hook = hook->next;
576 return NULL;
579 void
580 g_hook_insert_sorted (GHookList *hook_list,
581 GHook *hook,
582 GHookCompareFunc func)
584 GHook *sibling;
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;
598 while (sibling)
600 GHook *tmp;
602 g_hook_ref (hook_list, sibling);
603 if (func (hook, sibling) <= 0 && sibling->hook_id)
605 g_hook_unref (hook_list, sibling);
606 break;
609 /* next non-destroyed hook */
610 tmp = sibling->next;
611 while (tmp && !tmp->hook_id)
612 tmp = tmp->next;
614 g_hook_unref (hook_list, sibling);
615 sibling = tmp;
618 g_hook_insert_before (hook_list, sibling, hook);
621 gint
622 g_hook_compare_ids (GHook *new_hook,
623 GHook *sibling)
625 return ((glong) new_hook->hook_id) - ((glong) sibling->hook_id);