Tizen 2.1 base
[platform/upstream/glib2.0.git] / glib / ghook.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GHook: Callback maintenance functions
5  * Copyright (C) 1998 Tim Janik
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 /*
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/.
28  */
29
30 /*
31  * MT safe
32  */
33
34 #include "config.h"
35
36 #include "ghook.h"
37
38 #include "gtestutils.h"
39 #include "gslice.h"
40
41 /**
42  * SECTION:hooks
43  * @title: Hook Functions
44  * @short_description: support for manipulating lists of hook functions
45  *
46  * The #GHookList, #GHook and their related functions provide support for
47  * lists of hook functions. Functions can be added and removed from the lists,
48  * and the list of hook functions can be invoked.
49  */
50
51 /**
52  * GHookList:
53  * @seq_id: the next free #GHook id
54  * @hook_size: the size of the #GHookList elements, in bytes
55  * @is_setup: 1 if the #GHookList has been initialized
56  * @hooks: the first #GHook element in the list
57  * @dummy3: unused
58  * @finalize_hook: the function to call to finalize a #GHook element.
59  *     The default behaviour is to call the hooks @destroy function
60  * @dummy: unused
61  *
62  * The <structname>GHookList</structname> struct represents a
63  * list of hook functions.
64  */
65
66 /**
67  * GHookFinalizeFunc:
68  * @hook_list: a #GHookList
69  * @hook: the hook in @hook_list that gets finalized
70  *
71  * Defines the type of function to be called when a hook in a
72  * list of hooks gets finalized.
73  */
74
75 /**
76  * GHookFlagMask:
77  * @G_HOOK_FLAG_ACTIVE: set if the hook has not been destroyed
78  * @G_HOOK_FLAG_IN_CALL: set if the hook is currently being run
79  * @G_HOOK_FLAG_MASK: A mask covering all bits reserved for
80  *   hook flags; see %G_HOOK_FLAG_USER_SHIFT
81  *
82  * Flags used internally in the #GHook implementation.
83  */
84
85 /**
86  * G_HOOK_FLAGS:
87  * @hook: a #GHook
88  *
89  * Gets the flags of a hook.
90  */
91
92 /**
93  * G_HOOK_FLAG_USER_SHIFT:
94  *
95  * The position of the first bit which is not reserved for internal
96  * use be the #GHook implementation, i.e.
97  * <literal>1 &lt;&lt; G_HOOK_FLAG_USER_SHIFT</literal> is the first
98  * bit which can be used for application-defined flags.
99  */
100
101 /**
102  * G_HOOK:
103  * @hook: a pointer
104  *
105  * Casts a pointer to a <literal>GHook*</literal>.
106  */
107
108 /**
109  * G_HOOK_IS_VALID:
110  * @hook: a #GHook
111  *
112  * Returns %TRUE if the #GHook is valid, i.e. it is in a #GHookList,
113  * it is active and it has not been destroyed.
114  *
115  * Returns: %TRUE if the #GHook is valid
116  */
117
118 /**
119  * G_HOOK_ACTIVE:
120  * @hook: a #GHook
121  *
122  * Returns %TRUE if the #GHook is active, which is normally the case
123  * until the #GHook is destroyed.
124  *
125  * Returns: %TRUE if the #GHook is active
126  */
127
128 /**
129  * G_HOOK_IN_CALL:
130  * @hook: a #GHook
131  *
132  * Returns %TRUE if the #GHook function is currently executing.
133  *
134  * Returns: %TRUE if the #GHook function is currently executing
135  */
136
137 /**
138  * G_HOOK_IS_UNLINKED:
139  * @hook: a #GHook
140  *
141  * Returns %TRUE if the #GHook is not in a #GHookList.
142  
143  * Returns: %TRUE if the #GHook is not in a #GHookList
144  */
145
146 /**
147  * GHook:
148  * @data: data which is passed to func when this hook is invoked
149  * @next: pointer to the next hook in the list
150  * @prev: pointer to the previous hook in the list
151  * @ref_count: the reference count of this hook
152  * @hook_id: the id of this hook, which is unique within its list
153  * @flags: flags which are set for this hook. See #GHookFlagMask for
154  *     predefined flags
155  * @func: the function to call when this hook is invoked. The possible
156  *     signatures for this function are #GHookFunc and #GHookCheckFunc
157  * @destroy: the default @finalize_hook function of a #GHookList calls
158  *     this member of the hook that is being finalized
159  *
160  * The <structname>GHook</structname> struct represents a single hook
161  * function in a #GHookList.
162  */
163
164 /**
165  * GHookFunc:
166  * @data: the data field of the #GHook is passed to the hook function here
167  *
168  * Defines the type of a hook function that can be invoked
169  * by g_hook_list_invoke().
170  */
171
172 /**
173  * GHookCheckFunc:
174  * @data: the data field of the #GHook is passed to the hook function here
175  *
176  * Defines the type of a hook function that can be invoked
177  * by g_hook_list_invoke_check().
178  *
179  * Returns: %FALSE if the #GHook should be destroyed
180  */
181
182 /* --- functions --- */
183 static void
184 default_finalize_hook (GHookList *hook_list,
185                        GHook     *hook)
186 {
187   GDestroyNotify destroy = hook->destroy;
188
189   if (destroy)
190     {
191       hook->destroy = NULL;
192       destroy (hook->data);
193     }
194 }
195
196 /**
197  * g_hook_list_init:
198  * @hook_list: a #GHookList
199  * @hook_size: the size of each element in the #GHookList,
200  *     typically <literal>sizeof (GHook)</literal>
201  *
202  * Initializes a #GHookList.
203  * This must be called before the #GHookList is used.
204  */
205 void
206 g_hook_list_init (GHookList *hook_list,
207                   guint      hook_size)
208 {
209   g_return_if_fail (hook_list != NULL);
210   g_return_if_fail (hook_size >= sizeof (GHook));
211   
212   hook_list->seq_id = 1;
213   hook_list->hook_size = hook_size;
214   hook_list->is_setup = TRUE;
215   hook_list->hooks = NULL;
216   hook_list->dummy3 = NULL;
217   hook_list->finalize_hook = default_finalize_hook;
218   hook_list->dummy[0] = NULL;
219   hook_list->dummy[1] = NULL;
220 }
221
222 /**
223  * g_hook_list_clear:
224  * @hook_list: a #GHookList
225  *
226  * Removes all the #GHook elements from a #GHookList.
227  */
228 void
229 g_hook_list_clear (GHookList *hook_list)
230 {
231   g_return_if_fail (hook_list != NULL);
232   
233   if (hook_list->is_setup)
234     {
235       GHook *hook;
236       
237       hook_list->is_setup = FALSE;
238       
239       hook = hook_list->hooks;
240       if (!hook)
241         {
242           /* destroy hook_list->hook_memchunk */
243         }
244       else
245         do
246           {
247             GHook *tmp;
248             
249             g_hook_ref (hook_list, hook);
250             g_hook_destroy_link (hook_list, hook);
251             tmp = hook->next;
252             g_hook_unref (hook_list, hook);
253             hook = tmp;
254           }
255         while (hook);
256     }
257 }
258
259 /**
260  * g_hook_alloc:
261  * @hook_list: a #GHookList
262  *
263  * Allocates space for a #GHook and initializes it.
264  *
265  * Returns: a new #GHook
266  */
267 GHook*
268 g_hook_alloc (GHookList *hook_list)
269 {
270   GHook *hook;
271   
272   g_return_val_if_fail (hook_list != NULL, NULL);
273   g_return_val_if_fail (hook_list->is_setup, NULL);
274   
275   hook = g_slice_alloc0 (hook_list->hook_size);
276   hook->data = NULL;
277   hook->next = NULL;
278   hook->prev = NULL;
279   hook->flags = G_HOOK_FLAG_ACTIVE;
280   hook->ref_count = 0;
281   hook->hook_id = 0;
282   hook->func = NULL;
283   hook->destroy = NULL;
284   
285   return hook;
286 }
287 /**
288  * g_hook_free:
289  * @hook_list: a #GHookList
290  * @hook: the #GHook to free
291  *
292  * Calls the #GHookList @finalize_hook function if it exists,
293  * and frees the memory allocated for the #GHook.
294  */
295 void
296 g_hook_free (GHookList *hook_list,
297              GHook     *hook)
298 {
299   g_return_if_fail (hook_list != NULL);
300   g_return_if_fail (hook_list->is_setup);
301   g_return_if_fail (hook != NULL);
302   g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
303   g_return_if_fail (!G_HOOK_IN_CALL (hook));
304
305   if(hook_list->finalize_hook != NULL)
306       hook_list->finalize_hook (hook_list, hook);
307   g_slice_free1 (hook_list->hook_size, hook);
308 }
309
310 /**
311  * g_hook_destroy_link:
312  * @hook_list: a #GHookList
313  * @hook: the #GHook to remove
314  *
315  * Removes one #GHook from a #GHookList, marking it
316  * inactive and calling g_hook_unref() on it.
317  */
318 void
319 g_hook_destroy_link (GHookList *hook_list,
320                      GHook     *hook)
321 {
322   g_return_if_fail (hook_list != NULL);
323   g_return_if_fail (hook != NULL);
324
325   hook->flags &= ~G_HOOK_FLAG_ACTIVE;
326   if (hook->hook_id)
327     {
328       hook->hook_id = 0;
329       g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */
330     }
331 }
332
333 /**
334  * g_hook_destroy:
335  * @hook_list: a #GHookList
336  * @hook_id: a hook ID
337  *
338  * Destroys a #GHook, given its ID.
339  *
340  * Returns: %TRUE if the #GHook was found in the #GHookList and destroyed
341  */
342 gboolean
343 g_hook_destroy (GHookList   *hook_list,
344                 gulong       hook_id)
345 {
346   GHook *hook;
347   
348   g_return_val_if_fail (hook_list != NULL, FALSE);
349   g_return_val_if_fail (hook_id > 0, FALSE);
350   
351   hook = g_hook_get (hook_list, hook_id);
352   if (hook)
353     {
354       g_hook_destroy_link (hook_list, hook);
355       return TRUE;
356     }
357   
358   return FALSE;
359 }
360
361 /**
362  * g_hook_unref:
363  * @hook_list: a #GHookList
364  * @hook: the #GHook to unref
365  *
366  * Decrements the reference count of a #GHook.
367  * If the reference count falls to 0, the #GHook is removed
368  * from the #GHookList and g_hook_free() is called to free it.
369  */
370 void
371 g_hook_unref (GHookList *hook_list,
372               GHook     *hook)
373 {
374   g_return_if_fail (hook_list != NULL);
375   g_return_if_fail (hook != NULL);
376   g_return_if_fail (hook->ref_count > 0);
377   
378   hook->ref_count--;
379   if (!hook->ref_count)
380     {
381       g_return_if_fail (hook->hook_id == 0);
382       g_return_if_fail (!G_HOOK_IN_CALL (hook));
383
384       if (hook->prev)
385         hook->prev->next = hook->next;
386       else
387         hook_list->hooks = hook->next;
388       if (hook->next)
389         {
390           hook->next->prev = hook->prev;
391           hook->next = NULL;
392         }
393       hook->prev = NULL;
394
395       if (!hook_list->is_setup)
396         {
397           hook_list->is_setup = TRUE;
398           g_hook_free (hook_list, hook);
399           hook_list->is_setup = FALSE;
400       
401           if (!hook_list->hooks)
402             {
403               /* destroy hook_list->hook_memchunk */
404             }
405         }
406       else
407         g_hook_free (hook_list, hook);
408     }
409 }
410
411 /**
412  * g_hook_ref:
413  * @hook_list: a #GHookList
414  * @hook: the #GHook to increment the reference count of
415  *
416  * Increments the reference count for a #GHook.
417  *
418  * Returns: the @hook that was passed in (since 2.6)
419  */
420 GHook *
421 g_hook_ref (GHookList *hook_list,
422             GHook     *hook)
423 {
424   g_return_val_if_fail (hook_list != NULL, NULL);
425   g_return_val_if_fail (hook != NULL, NULL);
426   g_return_val_if_fail (hook->ref_count > 0, NULL);
427   
428   hook->ref_count++;
429
430   return hook;
431 }
432
433 /**
434  * g_hook_append:
435  * @hook_list: a #GHookList
436  * @hook: the #GHook to add to the end of @hook_list
437  *
438  * Appends a #GHook onto the end of a #GHookList.
439  */
440
441 /**
442  * g_hook_prepend:
443  * @hook_list: a #GHookList
444  * @hook: the #GHook to add to the start of @hook_list
445  *
446  * Prepends a #GHook on the start of a #GHookList.
447  */
448 void
449 g_hook_prepend (GHookList *hook_list,
450                 GHook     *hook)
451 {
452   g_return_if_fail (hook_list != NULL);
453   
454   g_hook_insert_before (hook_list, hook_list->hooks, hook);
455 }
456
457 /**
458  * g_hook_insert_before:
459  * @hook_list: a #GHookList
460  * @sibling: the #GHook to insert the new #GHook before
461  * @hook: the #GHook to insert
462  *
463  * Inserts a #GHook into a #GHookList, before a given #GHook.
464  */
465 void
466 g_hook_insert_before (GHookList *hook_list,
467                       GHook     *sibling,
468                       GHook     *hook)
469 {
470   g_return_if_fail (hook_list != NULL);
471   g_return_if_fail (hook_list->is_setup);
472   g_return_if_fail (hook != NULL);
473   g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
474   g_return_if_fail (hook->ref_count == 0);
475   
476   hook->hook_id = hook_list->seq_id++;
477   hook->ref_count = 1; /* counterpart to g_hook_destroy_link */
478   
479   if (sibling)
480     {
481       if (sibling->prev)
482         {
483           hook->prev = sibling->prev;
484           hook->prev->next = hook;
485           hook->next = sibling;
486           sibling->prev = hook;
487         }
488       else
489         {
490           hook_list->hooks = hook;
491           hook->next = sibling;
492           sibling->prev = hook;
493         }
494     }
495   else
496     {
497       if (hook_list->hooks)
498         {
499           sibling = hook_list->hooks;
500           while (sibling->next)
501             sibling = sibling->next;
502           hook->prev = sibling;
503           sibling->next = hook;
504         }
505       else
506         hook_list->hooks = hook;
507     }
508 }
509
510 /**
511  * g_hook_list_invoke:
512  * @hook_list: a #GHookList
513  * @may_recurse: %TRUE if functions which are already running
514  *     (e.g. in another thread) can be called. If set to %FALSE,
515  *     these are skipped
516  *
517  * Calls all of the #GHook functions in a #GHookList.
518  */
519 void
520 g_hook_list_invoke (GHookList *hook_list,
521                     gboolean   may_recurse)
522 {
523   GHook *hook;
524   
525   g_return_if_fail (hook_list != NULL);
526   g_return_if_fail (hook_list->is_setup);
527
528   hook = g_hook_first_valid (hook_list, may_recurse);
529   while (hook)
530     {
531       GHookFunc func;
532       gboolean was_in_call;
533       
534       func = (GHookFunc) hook->func;
535       
536       was_in_call = G_HOOK_IN_CALL (hook);
537       hook->flags |= G_HOOK_FLAG_IN_CALL;
538       func (hook->data);
539       if (!was_in_call)
540         hook->flags &= ~G_HOOK_FLAG_IN_CALL;
541       
542       hook = g_hook_next_valid (hook_list, hook, may_recurse);
543     }
544 }
545
546 /**
547  * g_hook_list_invoke_check:
548  * @hook_list: a #GHookList
549  * @may_recurse: %TRUE if functions which are already running
550  *     (e.g. in another thread) can be called. If set to %FALSE,
551  *     these are skipped
552  *
553  * Calls all of the #GHook functions in a #GHookList.
554  * Any function which returns %FALSE is removed from the #GHookList.
555  */
556 void
557 g_hook_list_invoke_check (GHookList *hook_list,
558                           gboolean   may_recurse)
559 {
560   GHook *hook;
561   
562   g_return_if_fail (hook_list != NULL);
563   g_return_if_fail (hook_list->is_setup);
564   
565   hook = g_hook_first_valid (hook_list, may_recurse);
566   while (hook)
567     {
568       GHookCheckFunc func;
569       gboolean was_in_call;
570       gboolean need_destroy;
571       
572       func = (GHookCheckFunc) hook->func;
573       
574       was_in_call = G_HOOK_IN_CALL (hook);
575       hook->flags |= G_HOOK_FLAG_IN_CALL;
576       need_destroy = !func (hook->data);
577       if (!was_in_call)
578         hook->flags &= ~G_HOOK_FLAG_IN_CALL;
579       if (need_destroy)
580         g_hook_destroy_link (hook_list, hook);
581       
582       hook = g_hook_next_valid (hook_list, hook, may_recurse);
583     }
584 }
585
586 /**
587  * GHookCheckMarshaller:
588  * @hook: a #GHook
589  * @marshal_data: user data
590  *
591  * Defines the type of function used by g_hook_list_marshal_check().
592  *
593  * Returns: %FALSE if @hook should be destroyed
594  */
595
596 /**
597  * g_hook_list_marshal_check:
598  * @hook_list: a #GHookList
599  * @may_recurse: %TRUE if hooks which are currently running
600  *     (e.g. in another thread) are considered valid. If set to %FALSE,
601  *     these are skipped
602  * @marshaller: the function to call for each #GHook
603  * @marshal_data: data to pass to @marshaller
604  *
605  * Calls a function on each valid #GHook and destroys it if the
606  * function returns %FALSE.
607  */
608 void
609 g_hook_list_marshal_check (GHookList           *hook_list,
610                            gboolean             may_recurse,
611                            GHookCheckMarshaller marshaller,
612                            gpointer             data)
613 {
614   GHook *hook;
615   
616   g_return_if_fail (hook_list != NULL);
617   g_return_if_fail (hook_list->is_setup);
618   g_return_if_fail (marshaller != NULL);
619   
620   hook = g_hook_first_valid (hook_list, may_recurse);
621   while (hook)
622     {
623       gboolean was_in_call;
624       gboolean need_destroy;
625       
626       was_in_call = G_HOOK_IN_CALL (hook);
627       hook->flags |= G_HOOK_FLAG_IN_CALL;
628       need_destroy = !marshaller (hook, data);
629       if (!was_in_call)
630         hook->flags &= ~G_HOOK_FLAG_IN_CALL;
631       if (need_destroy)
632         g_hook_destroy_link (hook_list, hook);
633       
634       hook = g_hook_next_valid (hook_list, hook, may_recurse);
635     }
636 }
637
638 /**
639  * GHookMarshaller:
640  * @hook: a #GHook
641  * @marshal_data: user data
642  *
643  * Defines the type of function used by g_hook_list_marshal().
644  */
645
646 /**
647  * g_hook_list_marshal:
648  * @hook_list: a #GHookList
649  * @may_recurse: %TRUE if hooks which are currently running
650  *     (e.g. in another thread) are considered valid. If set to %FALSE,
651  *     these are skipped
652  * @marshaller: the function to call for each #GHook
653  * @marshal_data: data to pass to @marshaller
654  *
655  * Calls a function on each valid #GHook.
656  */
657 void
658 g_hook_list_marshal (GHookList               *hook_list,
659                      gboolean                 may_recurse,
660                      GHookMarshaller          marshaller,
661                      gpointer                 data)
662 {
663   GHook *hook;
664   
665   g_return_if_fail (hook_list != NULL);
666   g_return_if_fail (hook_list->is_setup);
667   g_return_if_fail (marshaller != NULL);
668   
669   hook = g_hook_first_valid (hook_list, may_recurse);
670   while (hook)
671     {
672       gboolean was_in_call;
673       
674       was_in_call = G_HOOK_IN_CALL (hook);
675       hook->flags |= G_HOOK_FLAG_IN_CALL;
676       marshaller (hook, data);
677       if (!was_in_call)
678         hook->flags &= ~G_HOOK_FLAG_IN_CALL;
679       
680       hook = g_hook_next_valid (hook_list, hook, may_recurse);
681     }
682 }
683
684 /**
685  * g_hook_first_valid:
686  * @hook_list: a #GHookList
687  * @may_be_in_call: %TRUE if hooks which are currently running
688  *     (e.g. in another thread) are considered valid. If set to %FALSE,
689  *     these are skipped
690  *
691  * Returns the first #GHook in a #GHookList which has not been destroyed.
692  * The reference count for the #GHook is incremented, so you must call
693  * g_hook_unref() to restore it when no longer needed. (Or call
694  * g_hook_next_valid() if you are stepping through the #GHookList.)
695  *
696  * Returns: the first valid #GHook, or %NULL if none are valid
697  */
698 GHook*
699 g_hook_first_valid (GHookList *hook_list,
700                     gboolean   may_be_in_call)
701 {
702   g_return_val_if_fail (hook_list != NULL, NULL);
703   
704   if (hook_list->is_setup)
705     {
706       GHook *hook;
707       
708       hook = hook_list->hooks;
709       if (hook)
710         {
711           g_hook_ref (hook_list, hook);
712           if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
713             return hook;
714           else
715             return g_hook_next_valid (hook_list, hook, may_be_in_call);
716         }
717     }
718   
719   return NULL;
720 }
721
722 /**
723  * g_hook_next_valid:
724  * @hook_list: a #GHookList
725  * @hook: the current #GHook
726  * @may_be_in_call: %TRUE if hooks which are currently running
727  *     (e.g. in another thread) are considered valid. If set to %FALSE,
728  *     these are skipped
729  *
730  * Returns the next #GHook in a #GHookList which has not been destroyed.
731  * The reference count for the #GHook is incremented, so you must call
732  * g_hook_unref() to restore it when no longer needed. (Or continue to call
733  * g_hook_next_valid() until %NULL is returned.)
734  *
735  * Returns: the next valid #GHook, or %NULL if none are valid
736  */
737 GHook*
738 g_hook_next_valid (GHookList *hook_list,
739                    GHook     *hook,
740                    gboolean   may_be_in_call)
741 {
742   GHook *ohook = hook;
743
744   g_return_val_if_fail (hook_list != NULL, NULL);
745
746   if (!hook)
747     return NULL;
748   
749   hook = hook->next;
750   while (hook)
751     {
752       if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
753         {
754           g_hook_ref (hook_list, hook);
755           g_hook_unref (hook_list, ohook);
756           
757           return hook;
758         }
759       hook = hook->next;
760     }
761   g_hook_unref (hook_list, ohook);
762
763   return NULL;
764 }
765
766 /**
767  * g_hook_get:
768  * @hook_list: a #GHookList
769  * @hook_id: a hook id
770  *
771  * Returns the #GHook with the given id, or %NULL if it is not found.
772  *
773  * Returns: the #GHook with the given id, or %NULL if it is not found
774  */
775 GHook*
776 g_hook_get (GHookList *hook_list,
777             gulong     hook_id)
778 {
779   GHook *hook;
780   
781   g_return_val_if_fail (hook_list != NULL, NULL);
782   g_return_val_if_fail (hook_id > 0, NULL);
783   
784   hook = hook_list->hooks;
785   while (hook)
786     {
787       if (hook->hook_id == hook_id)
788         return hook;
789       hook = hook->next;
790     }
791   
792   return NULL;
793 }
794
795 /**
796  * GHookFindFunc:
797  * @hook: a #GHook
798  * @data: user data passed to g_hook_find_func()
799  *
800  * Defines the type of the function passed to g_hook_find().
801  *
802  * Returns: %TRUE if the required #GHook has been found
803  */
804
805 /**
806  * g_hook_find:
807  * @hook_list: a #GHookList
808  * @need_valids: %TRUE if #GHook elements which have been destroyed
809  *     should be skipped
810  * @func: the function to call for each #GHook, which should return
811  *     %TRUE when the #GHook has been found
812  * @data: the data to pass to @func
813  *
814  * Finds a #GHook in a #GHookList using the given function to
815  * test for a match.
816  *
817  * Returns: the found #GHook or %NULL if no matching #GHook is found
818  */
819 GHook*
820 g_hook_find (GHookList    *hook_list,
821              gboolean      need_valids,
822              GHookFindFunc func,
823              gpointer      data)
824 {
825   GHook *hook;
826   
827   g_return_val_if_fail (hook_list != NULL, NULL);
828   g_return_val_if_fail (func != NULL, NULL);
829   
830   hook = hook_list->hooks;
831   while (hook)
832     {
833       GHook *tmp;
834
835       /* test only non-destroyed hooks */
836       if (!hook->hook_id)
837         {
838           hook = hook->next;
839           continue;
840         }
841       
842       g_hook_ref (hook_list, hook);
843       
844       if (func (hook, data) && hook->hook_id && (!need_valids || G_HOOK_ACTIVE (hook)))
845         {
846           g_hook_unref (hook_list, hook);
847           
848           return hook;
849         }
850
851       tmp = hook->next;
852       g_hook_unref (hook_list, hook);
853       hook = tmp;
854     }
855   
856   return NULL;
857 }
858
859 /**
860  * g_hook_find_data:
861  * @hook_list: a #GHookList
862  * @need_valids: %TRUE if #GHook elements which have been destroyed
863  *     should be skipped
864  * @data: the data to find
865  *
866  * Finds a #GHook in a #GHookList with the given data.
867  *
868  * Returns: the #GHook with the given @data or %NULL if no matching
869  *     #GHook is found
870  */
871 GHook*
872 g_hook_find_data (GHookList *hook_list,
873                   gboolean   need_valids,
874                   gpointer   data)
875 {
876   GHook *hook;
877   
878   g_return_val_if_fail (hook_list != NULL, NULL);
879   
880   hook = hook_list->hooks;
881   while (hook)
882     {
883       /* test only non-destroyed hooks */
884       if (hook->data == data &&
885           hook->hook_id &&
886           (!need_valids || G_HOOK_ACTIVE (hook)))
887         return hook;
888
889       hook = hook->next;
890     }
891   
892   return NULL;
893 }
894
895 /**
896  * g_hook_find_func:
897  * @hook_list: a #GHookList
898  * @need_valids: %TRUE if #GHook elements which have been destroyed
899  *     should be skipped
900  * @func: the function to find
901  *
902  * Finds a #GHook in a #GHookList with the given function.
903  *
904  * Returns: the #GHook with the given @func or %NULL if no matching
905  *     #GHook is found
906  */
907 GHook*
908 g_hook_find_func (GHookList *hook_list,
909                   gboolean   need_valids,
910                   gpointer   func)
911 {
912   GHook *hook;
913   
914   g_return_val_if_fail (hook_list != NULL, NULL);
915   g_return_val_if_fail (func != NULL, NULL);
916   
917   hook = hook_list->hooks;
918   while (hook)
919     {
920       /* test only non-destroyed hooks */
921       if (hook->func == func &&
922           hook->hook_id &&
923           (!need_valids || G_HOOK_ACTIVE (hook)))
924         return hook;
925
926       hook = hook->next;
927     }
928   
929   return NULL;
930 }
931
932 /**
933  * g_hook_find_func_data:
934  * @hook_list: a #GHookList
935  * @need_valids: %TRUE if #GHook elements which have been destroyed
936  *     should be skipped
937  * @func: the function to find
938  * @data: the data to find
939  *
940  * Finds a #GHook in a #GHookList with the given function and data.
941  *
942  * Returns: the #GHook with the given @func and @data or %NULL if
943  *     no matching #GHook is found
944  */
945 GHook*
946 g_hook_find_func_data (GHookList *hook_list,
947                        gboolean   need_valids,
948                        gpointer   func,
949                        gpointer   data)
950 {
951   GHook *hook;
952   
953   g_return_val_if_fail (hook_list != NULL, NULL);
954   g_return_val_if_fail (func != NULL, NULL);
955   
956   hook = hook_list->hooks;
957   while (hook)
958     {
959       /* test only non-destroyed hooks */
960       if (hook->data == data &&
961           hook->func == func &&
962           hook->hook_id &&
963           (!need_valids || G_HOOK_ACTIVE (hook)))
964         return hook;
965
966       hook = hook->next;
967     }
968   
969   return NULL;
970 }
971
972 /**
973  * GHookCompareFunc:
974  * @new_hook: the #GHook being inserted
975  * @sibling: the #GHook to compare with @new_hook
976  *
977  * Defines the type of function used to compare #GHook elements in
978  * g_hook_insert_sorted().
979  *
980  * Returns: a value &lt;= 0 if @new_hook should be before @sibling
981  */
982
983 /**
984  * g_hook_insert_sorted:
985  * @hook_list: a #GHookList
986  * @hook: the #GHook to insert
987  * @func: the comparison function used to sort the #GHook elements
988  *
989  * Inserts a #GHook into a #GHookList, sorted by the given function.
990  */
991 void
992 g_hook_insert_sorted (GHookList       *hook_list,
993                       GHook           *hook,
994                       GHookCompareFunc func)
995 {
996   GHook *sibling;
997   
998   g_return_if_fail (hook_list != NULL);
999   g_return_if_fail (hook_list->is_setup);
1000   g_return_if_fail (hook != NULL);
1001   g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
1002   g_return_if_fail (hook->func != NULL);
1003   g_return_if_fail (func != NULL);
1004
1005   /* first non-destroyed hook */
1006   sibling = hook_list->hooks;
1007   while (sibling && !sibling->hook_id)
1008     sibling = sibling->next;
1009   
1010   while (sibling)
1011     {
1012       GHook *tmp;
1013       
1014       g_hook_ref (hook_list, sibling);
1015       if (func (hook, sibling) <= 0 && sibling->hook_id)
1016         {
1017           g_hook_unref (hook_list, sibling);
1018           break;
1019         }
1020
1021       /* next non-destroyed hook */
1022       tmp = sibling->next;
1023       while (tmp && !tmp->hook_id)
1024         tmp = tmp->next;
1025
1026       g_hook_unref (hook_list, sibling);
1027       sibling = tmp;
1028    
1029  }
1030   
1031   g_hook_insert_before (hook_list, sibling, hook);
1032 }
1033
1034 /**
1035  * g_hook_compare_ids:
1036  * @new_hook: a #GHook
1037  * @sibling: a #GHook to compare with @new_hook
1038  *
1039  * Compares the ids of two #GHook elements, returning a negative value
1040  * if the second id is greater than the first.
1041  *
1042  * Returns: a value &lt;= 0 if the id of @sibling is >= the id of @new_hook
1043  */
1044 gint
1045 g_hook_compare_ids (GHook *new_hook,
1046                     GHook *sibling)
1047 {
1048   if (new_hook->hook_id < sibling->hook_id)
1049     return -1;
1050   else if (new_hook->hook_id > sibling->hook_id)
1051     return 1;
1052   
1053   return 0;
1054 }