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