mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-31 08:22:16 +01:00 
			
		
		
		
	Try to avoid casting variables to potentially smaller types to fit defined probes. This can truncate values and lead to wrong results. Also make sure that signedness matches. Since GType can be even 128 bit on CHERI architecture, cast all these various types used based on platform to uintmax_t which SystemTap properly processes.
		
			
				
	
	
		
			4203 lines
		
	
	
		
			129 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			4203 lines
		
	
	
		
			129 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* GObject - GLib Type, Object, Parameter and Signal Library
 | ||
|  * Copyright (C) 2000-2001 Red Hat, Inc.
 | ||
|  *
 | ||
|  * SPDX-License-Identifier: LGPL-2.1-or-later
 | ||
|  *
 | ||
|  * This library is free software; you can redistribute it and/or
 | ||
|  * modify it under the terms of the GNU Lesser General Public
 | ||
|  * License as published by the Free Software Foundation; either
 | ||
|  * version 2.1 of the License, or (at your option) any later version.
 | ||
|  *
 | ||
|  * This library is distributed in the hope that it will be useful,
 | ||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | ||
|  * Lesser General Public License for more details.
 | ||
|  *
 | ||
|  * You should have received a copy of the GNU Lesser General
 | ||
|  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | ||
|  *
 | ||
|  * this code is based on the original GtkSignal implementation
 | ||
|  * for the Gtk+ library by Peter Mattis <petm@xcf.berkeley.edu>
 | ||
|  */
 | ||
| 
 | ||
| /*
 | ||
|  * MT safe
 | ||
|  */
 | ||
| 
 | ||
| #include "config.h"
 | ||
| 
 | ||
| #include <signal.h>
 | ||
| #include <stdint.h>
 | ||
| #include <string.h>
 | ||
| 
 | ||
| #include "gsignal.h"
 | ||
| #include "gtype-private.h"
 | ||
| #include "gbsearcharray.h"
 | ||
| #include "gvaluecollector.h"
 | ||
| #include "gvaluetypes.h"
 | ||
| #include "gobject.h"
 | ||
| #include "genums.h"
 | ||
| #include "gobject_trace.h"
 | ||
| 
 | ||
| 
 | ||
| #define REPORT_BUG      "please report occurrence circumstances to https://gitlab.gnome.org/GNOME/glib/issues/new"
 | ||
| 
 | ||
| /* --- typedefs --- */
 | ||
| typedef struct _SignalNode   SignalNode;
 | ||
| typedef struct _SignalKey    SignalKey;
 | ||
| typedef struct _Emission     Emission;
 | ||
| typedef struct _Handler      Handler;
 | ||
| typedef struct _HandlerList  HandlerList;
 | ||
| typedef struct _HandlerMatch HandlerMatch;
 | ||
| typedef enum
 | ||
| {
 | ||
|   EMISSION_STOP,
 | ||
|   EMISSION_RUN,
 | ||
|   EMISSION_HOOK,
 | ||
|   EMISSION_RESTART
 | ||
| } EmissionState;
 | ||
| 
 | ||
| 
 | ||
| /* --- prototypes --- */
 | ||
| static inline guint   signal_id_lookup  (const gchar *name,
 | ||
|                                          GType        itype);
 | ||
| static	      void		signal_destroy_R	(SignalNode	 *signal_node);
 | ||
| static inline HandlerList*	handler_list_ensure	(guint		  signal_id,
 | ||
| 							 gpointer	  instance);
 | ||
| static inline HandlerList*	handler_list_lookup	(guint		  signal_id,
 | ||
| 							 gpointer	  instance);
 | ||
| static inline Handler*		handler_new		(guint            signal_id,
 | ||
| 							 gpointer         instance,
 | ||
|                                                          gboolean	  after);
 | ||
| static	      void		handler_insert		(guint		  signal_id,
 | ||
| 							 gpointer	  instance,
 | ||
| 							 Handler	 *handler);
 | ||
| static	      Handler*		handler_lookup		(gpointer	  instance,
 | ||
| 							 gulong		  handler_id,
 | ||
| 							 GClosure        *closure,
 | ||
| 							 guint		 *signal_id_p);
 | ||
| static inline HandlerMatch*	handler_match_prepend	(HandlerMatch	 *list,
 | ||
| 							 Handler	 *handler,
 | ||
| 							 guint		  signal_id);
 | ||
| static inline HandlerMatch*	handler_match_free1_R	(HandlerMatch	 *node,
 | ||
| 							 gpointer	  instance);
 | ||
| static	      HandlerMatch*	handlers_find		(gpointer	  instance,
 | ||
| 							 GSignalMatchType mask,
 | ||
| 							 guint		  signal_id,
 | ||
| 							 GQuark		  detail,
 | ||
| 							 GClosure	 *closure,
 | ||
| 							 gpointer	  func,
 | ||
| 							 gpointer	  data,
 | ||
| 							 gboolean	  one_and_only);
 | ||
| static inline void		handler_ref		(Handler	 *handler);
 | ||
| static inline void		handler_unref_R		(guint		  signal_id,
 | ||
| 							 gpointer	  instance,
 | ||
| 							 Handler	 *handler);
 | ||
| static gint			handler_lists_cmp	(gconstpointer	  node1,
 | ||
| 							 gconstpointer	  node2);
 | ||
| static inline void		emission_push		(Emission	 *emission);
 | ||
| static inline void		emission_pop		(Emission	 *emission);
 | ||
| static inline Emission*		emission_find		(guint		  signal_id,
 | ||
| 							 GQuark		  detail,
 | ||
| 							 gpointer	  instance);
 | ||
| static gint			class_closures_cmp	(gconstpointer	  node1,
 | ||
| 							 gconstpointer	  node2);
 | ||
| static gint			signal_key_cmp		(gconstpointer	  node1,
 | ||
| 							 gconstpointer	  node2);
 | ||
| static	      gboolean		signal_emit_unlocked_R	(SignalNode	 *node,
 | ||
| 							 GQuark		  detail,
 | ||
| 							 gpointer	  instance,
 | ||
| 							 GValue		 *return_value,
 | ||
| 							 const GValue	 *instance_and_params);
 | ||
| static       void               add_invalid_closure_notify    (Handler         *handler,
 | ||
| 							       gpointer         instance);
 | ||
| static       void               remove_invalid_closure_notify (Handler         *handler,
 | ||
| 							       gpointer         instance);
 | ||
| static       void               invalid_closure_notify  (gpointer         data,
 | ||
| 							 GClosure        *closure);
 | ||
| static const gchar *            type_debug_name         (GType            type);
 | ||
| static void                     node_check_deprecated   (const SignalNode *node);
 | ||
| static void                     node_update_single_va_closure (SignalNode *node);
 | ||
| 
 | ||
| 
 | ||
| /* --- structures --- */
 | ||
| typedef struct
 | ||
| {
 | ||
|   GSignalAccumulator func;
 | ||
|   gpointer           data;
 | ||
| } SignalAccumulator;
 | ||
| typedef struct
 | ||
| {
 | ||
|   GHook hook;
 | ||
|   GQuark detail;
 | ||
| } SignalHook;
 | ||
| #define	SIGNAL_HOOK(hook)	((SignalHook*) (hook))
 | ||
| 
 | ||
| struct _SignalNode
 | ||
| {
 | ||
|   /* permanent portion */
 | ||
|   guint              signal_id;
 | ||
|   GType              itype;
 | ||
|   const gchar       *name;
 | ||
|   guint              destroyed : 1;
 | ||
|   
 | ||
|   /* reinitializable portion */
 | ||
|   guint              flags : 9;
 | ||
|   guint              n_params : 8;
 | ||
|   guint              single_va_closure_is_valid : 1;
 | ||
|   guint              single_va_closure_is_after : 1;
 | ||
|   GType		    *param_types; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
 | ||
|   GType		     return_type; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
 | ||
|   GBSearchArray     *class_closure_bsa;
 | ||
|   SignalAccumulator *accumulator;
 | ||
|   GSignalCMarshaller c_marshaller;
 | ||
|   GSignalCVaMarshaller va_marshaller;
 | ||
|   GHookList         *emission_hooks;
 | ||
| 
 | ||
|   GClosure *single_va_closure;
 | ||
| };
 | ||
| 
 | ||
| #define	SINGLE_VA_CLOSURE_EMPTY_MAGIC GINT_TO_POINTER(1)	/* indicates single_va_closure is valid but empty */
 | ||
| 
 | ||
| struct _SignalKey
 | ||
| {
 | ||
|   GType  itype;
 | ||
|   GQuark quark;
 | ||
|   guint  signal_id;
 | ||
| };
 | ||
| 
 | ||
| struct _Emission
 | ||
| {
 | ||
|   Emission             *next;
 | ||
|   gpointer              instance;
 | ||
|   GSignalInvocationHint ihint;
 | ||
|   EmissionState         state;
 | ||
|   GType			chain_type;
 | ||
| };
 | ||
| 
 | ||
| struct _HandlerList
 | ||
| {
 | ||
|   guint    signal_id;
 | ||
|   Handler *handlers;
 | ||
|   Handler *tail_before;  /* normal signal handlers are appended here  */
 | ||
|   Handler *tail_after;   /* CONNECT_AFTER handlers are appended here  */
 | ||
| };
 | ||
| 
 | ||
| struct _Handler
 | ||
| {
 | ||
|   gulong        sequential_number;
 | ||
|   Handler      *next;
 | ||
|   Handler      *prev;
 | ||
|   GQuark	detail;
 | ||
|   guint         signal_id;
 | ||
|   guint         ref_count;
 | ||
|   guint         block_count : 16;
 | ||
| #define HANDLER_MAX_BLOCK_COUNT (1 << 16)
 | ||
|   guint         after : 1;
 | ||
|   guint         has_invalid_closure_notify : 1;
 | ||
|   GClosure     *closure;
 | ||
|   gpointer      instance;
 | ||
| };
 | ||
| struct _HandlerMatch
 | ||
| {
 | ||
|   Handler      *handler;
 | ||
|   HandlerMatch *next;
 | ||
|   guint         signal_id;
 | ||
| };
 | ||
| 
 | ||
| typedef struct
 | ||
| {
 | ||
|   GType     instance_type; /* 0 for default closure */
 | ||
|   GClosure *closure;
 | ||
| } ClassClosure;
 | ||
| 
 | ||
| 
 | ||
| /* --- variables --- */
 | ||
| static GBSearchArray *g_signal_key_bsa = NULL;
 | ||
| static const GBSearchConfig g_signal_key_bconfig = {
 | ||
|   sizeof (SignalKey),
 | ||
|   signal_key_cmp,
 | ||
|   G_BSEARCH_ARRAY_ALIGN_POWER2,
 | ||
| };
 | ||
| static GBSearchConfig g_signal_hlbsa_bconfig = {
 | ||
|   sizeof (HandlerList),
 | ||
|   handler_lists_cmp,
 | ||
|   0,
 | ||
| };
 | ||
| static GBSearchConfig g_class_closure_bconfig = {
 | ||
|   sizeof (ClassClosure),
 | ||
|   class_closures_cmp,
 | ||
|   0,
 | ||
| };
 | ||
| static GHashTable    *g_handler_list_bsa_ht = NULL;
 | ||
| static Emission      *g_emissions = NULL;
 | ||
| static gulong         g_handler_sequential_number = 1;
 | ||
| static GHashTable    *g_handlers = NULL;
 | ||
| 
 | ||
| G_LOCK_DEFINE_STATIC (g_signal_mutex);
 | ||
| #define	SIGNAL_LOCK()		G_LOCK (g_signal_mutex)
 | ||
| #define	SIGNAL_UNLOCK()		G_UNLOCK (g_signal_mutex)
 | ||
| 
 | ||
| 
 | ||
| /* --- signal nodes --- */
 | ||
| static guint          g_n_signal_nodes = 0;
 | ||
| static SignalNode   **g_signal_nodes = NULL;
 | ||
| 
 | ||
| static inline SignalNode*
 | ||
| LOOKUP_SIGNAL_NODE (guint signal_id)
 | ||
| {
 | ||
|   if (signal_id < g_n_signal_nodes)
 | ||
|     return g_signal_nodes[signal_id];
 | ||
|   else
 | ||
|     return NULL;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /* --- functions --- */
 | ||
| /* @key must have already been validated with is_valid()
 | ||
|  * Modifies @key in place. */
 | ||
| static void
 | ||
| canonicalize_key (gchar *key)
 | ||
| {
 | ||
|   gchar *p;
 | ||
| 
 | ||
|   for (p = key; *p != 0; p++)
 | ||
|     {
 | ||
|       gchar c = *p;
 | ||
| 
 | ||
|       if (c == '_')
 | ||
|         *p = '-';
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| /* @key must have already been validated with is_valid() */
 | ||
| static gboolean
 | ||
| is_canonical (const gchar *key)
 | ||
| {
 | ||
|   return (strchr (key, '_') == NULL);
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_is_valid_name:
 | ||
|  * @name: the canonical name of the signal
 | ||
|  *
 | ||
|  * Validate a signal name. This can be useful for dynamically-generated signals
 | ||
|  * which need to be validated at run-time before actually trying to create them.
 | ||
|  *
 | ||
|  * See [func@GObject.signal_new] for details of the rules for valid names.
 | ||
|  * The rules for signal names are the same as those for property names.
 | ||
|  *
 | ||
|  * Returns: %TRUE if @name is a valid signal name, %FALSE otherwise.
 | ||
|  * Since: 2.66
 | ||
|  */
 | ||
| gboolean
 | ||
| g_signal_is_valid_name (const gchar *name)
 | ||
| {
 | ||
|   /* FIXME: We allow this, against our own documentation (the leading `-` is
 | ||
|    * invalid), because GTK has historically used this. */
 | ||
|   if (g_str_equal (name, "-gtk-private-changed"))
 | ||
|     return TRUE;
 | ||
| 
 | ||
|   return g_param_spec_is_valid_name (name);
 | ||
| }
 | ||
| 
 | ||
| static inline guint
 | ||
| signal_id_lookup (const gchar *name,
 | ||
|                   GType  itype)
 | ||
| {
 | ||
|   GQuark quark;
 | ||
|   GType *ifaces, type = itype;
 | ||
|   SignalKey key;
 | ||
|   guint n_ifaces;
 | ||
| 
 | ||
|   quark = g_quark_try_string (name);
 | ||
|   key.quark = quark;
 | ||
| 
 | ||
|   /* try looking up signals for this type and its ancestors */
 | ||
|   do
 | ||
|     {
 | ||
|       SignalKey *signal_key;
 | ||
|       
 | ||
|       key.itype = type;
 | ||
|       signal_key = g_bsearch_array_lookup (g_signal_key_bsa, &g_signal_key_bconfig, &key);
 | ||
|       
 | ||
|       if (signal_key)
 | ||
| 	return signal_key->signal_id;
 | ||
|       
 | ||
|       type = g_type_parent (type);
 | ||
|     }
 | ||
|   while (type);
 | ||
| 
 | ||
|   /* no luck, try interfaces it exports */
 | ||
|   ifaces = g_type_interfaces (itype, &n_ifaces);
 | ||
|   while (n_ifaces--)
 | ||
|     {
 | ||
|       SignalKey *signal_key;
 | ||
| 
 | ||
|       key.itype = ifaces[n_ifaces];
 | ||
|       signal_key = g_bsearch_array_lookup (g_signal_key_bsa, &g_signal_key_bconfig, &key);
 | ||
| 
 | ||
|       if (signal_key)
 | ||
| 	{
 | ||
| 	  g_free (ifaces);
 | ||
| 	  return signal_key->signal_id;
 | ||
| 	}
 | ||
|     }
 | ||
|   g_free (ifaces);
 | ||
| 
 | ||
|   /* If the @name is non-canonical, try again. This is the slow path — people
 | ||
|    * should use canonical names in their queries if they want performance. */
 | ||
|   if (!is_canonical (name))
 | ||
|     {
 | ||
|       guint signal_id;
 | ||
|       gchar *name_copy = g_strdup (name);
 | ||
|       canonicalize_key (name_copy);
 | ||
| 
 | ||
|       signal_id = signal_id_lookup (name_copy, itype);
 | ||
| 
 | ||
|       g_free (name_copy);
 | ||
| 
 | ||
|       return signal_id;
 | ||
|     }
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| static gint
 | ||
| class_closures_cmp (gconstpointer node1,
 | ||
| 		    gconstpointer node2)
 | ||
| {
 | ||
|   const ClassClosure *c1 = node1, *c2 = node2;
 | ||
|   
 | ||
|   return G_BSEARCH_ARRAY_CMP (c1->instance_type, c2->instance_type);
 | ||
| }
 | ||
| 
 | ||
| static gint
 | ||
| handler_lists_cmp (gconstpointer node1,
 | ||
|                    gconstpointer node2)
 | ||
| {
 | ||
|   const HandlerList *hlist1 = node1, *hlist2 = node2;
 | ||
|   
 | ||
|   return G_BSEARCH_ARRAY_CMP (hlist1->signal_id, hlist2->signal_id);
 | ||
| }
 | ||
| 
 | ||
| static inline HandlerList*
 | ||
| handler_list_ensure (guint    signal_id,
 | ||
| 		     gpointer instance)
 | ||
| {
 | ||
|   GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
 | ||
|   HandlerList key;
 | ||
|   
 | ||
|   key.signal_id = signal_id;
 | ||
|   key.handlers    = NULL;
 | ||
|   key.tail_before = NULL;
 | ||
|   key.tail_after  = NULL;
 | ||
|   if (!hlbsa)
 | ||
|     {
 | ||
|       hlbsa = g_bsearch_array_create (&g_signal_hlbsa_bconfig);
 | ||
|     }
 | ||
|   hlbsa = g_bsearch_array_insert (hlbsa, &g_signal_hlbsa_bconfig, &key);
 | ||
|   g_hash_table_insert (g_handler_list_bsa_ht, instance, hlbsa);
 | ||
|   return g_bsearch_array_lookup (hlbsa, &g_signal_hlbsa_bconfig, &key);
 | ||
| }
 | ||
| 
 | ||
| static inline HandlerList*
 | ||
| handler_list_lookup (guint    signal_id,
 | ||
| 		     gpointer instance)
 | ||
| {
 | ||
|   GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
 | ||
|   HandlerList key;
 | ||
|   
 | ||
|   key.signal_id = signal_id;
 | ||
|   
 | ||
|   return hlbsa ? g_bsearch_array_lookup (hlbsa, &g_signal_hlbsa_bconfig, &key) : NULL;
 | ||
| }
 | ||
| 
 | ||
| static guint
 | ||
| handler_hash (gconstpointer key)
 | ||
| {
 | ||
|   return (guint)((Handler*)key)->sequential_number;
 | ||
| }
 | ||
| 
 | ||
| static gboolean
 | ||
| handler_equal (gconstpointer a, gconstpointer b)
 | ||
| {
 | ||
|   Handler *ha = (Handler *)a;
 | ||
|   Handler *hb = (Handler *)b;
 | ||
|   return (ha->sequential_number == hb->sequential_number) &&
 | ||
|       (ha->instance  == hb->instance);
 | ||
| }
 | ||
| 
 | ||
| static Handler*
 | ||
| handler_lookup (gpointer  instance,
 | ||
| 		gulong    handler_id,
 | ||
| 		GClosure *closure,
 | ||
| 		guint    *signal_id_p)
 | ||
| {
 | ||
|   GBSearchArray *hlbsa;
 | ||
| 
 | ||
|   if (handler_id)
 | ||
|     {
 | ||
|       Handler key;
 | ||
|       key.sequential_number = handler_id;
 | ||
|       key.instance = instance;
 | ||
|       return g_hash_table_lookup (g_handlers, &key);
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
|   hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
 | ||
|   
 | ||
|   if (hlbsa)
 | ||
|     {
 | ||
|       guint i;
 | ||
|       
 | ||
|       for (i = 0; i < hlbsa->n_nodes; i++)
 | ||
|         {
 | ||
|           HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, &g_signal_hlbsa_bconfig, i);
 | ||
|           Handler *handler;
 | ||
|           
 | ||
|           for (handler = hlist->handlers; handler; handler = handler->next)
 | ||
|             if (closure ? (handler->closure == closure) : (handler->sequential_number == handler_id))
 | ||
|               {
 | ||
|                 if (signal_id_p)
 | ||
|                   *signal_id_p = hlist->signal_id;
 | ||
| 
 | ||
|                 return handler;
 | ||
|               }
 | ||
|         }
 | ||
|     }
 | ||
|   
 | ||
|   return NULL;
 | ||
| }
 | ||
| 
 | ||
| static inline HandlerMatch*
 | ||
| handler_match_prepend (HandlerMatch *list,
 | ||
| 		       Handler      *handler,
 | ||
| 		       guint	     signal_id)
 | ||
| {
 | ||
|   HandlerMatch *node;
 | ||
|   
 | ||
|   node = g_slice_new (HandlerMatch);
 | ||
|   node->handler = handler;
 | ||
|   node->next = list;
 | ||
|   node->signal_id = signal_id;
 | ||
|   handler_ref (handler);
 | ||
|   
 | ||
|   return node;
 | ||
| }
 | ||
| static inline HandlerMatch*
 | ||
| handler_match_free1_R (HandlerMatch *node,
 | ||
| 		       gpointer      instance)
 | ||
| {
 | ||
|   HandlerMatch *next = node->next;
 | ||
|   
 | ||
|   handler_unref_R (node->signal_id, instance, node->handler);
 | ||
|   g_slice_free (HandlerMatch, node);
 | ||
|   
 | ||
|   return next;
 | ||
| }
 | ||
| 
 | ||
| static HandlerMatch*
 | ||
| handlers_find (gpointer         instance,
 | ||
| 	       GSignalMatchType mask,
 | ||
| 	       guint            signal_id,
 | ||
| 	       GQuark           detail,
 | ||
| 	       GClosure        *closure,
 | ||
| 	       gpointer         func,
 | ||
| 	       gpointer         data,
 | ||
| 	       gboolean         one_and_only)
 | ||
| {
 | ||
|   HandlerMatch *mlist = NULL;
 | ||
|   
 | ||
|   if (mask & G_SIGNAL_MATCH_ID)
 | ||
|     {
 | ||
|       HandlerList *hlist = handler_list_lookup (signal_id, instance);
 | ||
|       Handler *handler;
 | ||
|       SignalNode *node = NULL;
 | ||
|       
 | ||
|       if (mask & G_SIGNAL_MATCH_FUNC)
 | ||
| 	{
 | ||
| 	  node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
| 	  if (!node || !node->c_marshaller)
 | ||
| 	    return NULL;
 | ||
| 	}
 | ||
|       
 | ||
|       mask = ~mask;
 | ||
|       for (handler = hlist ? hlist->handlers : NULL; handler; handler = handler->next)
 | ||
|         if (handler->sequential_number &&
 | ||
| 	    ((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
 | ||
| 	    ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
 | ||
|             ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
 | ||
| 	    ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
 | ||
| 	    ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
 | ||
| 					      G_REAL_CLOSURE (handler->closure)->meta_marshal == NULL &&
 | ||
| 					      ((GCClosure*) handler->closure)->callback == func)))
 | ||
| 	  {
 | ||
| 	    mlist = handler_match_prepend (mlist, handler, signal_id);
 | ||
| 	    if (one_and_only)
 | ||
| 	      return mlist;
 | ||
| 	  }
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
 | ||
|       
 | ||
|       mask = ~mask;
 | ||
|       if (hlbsa)
 | ||
|         {
 | ||
|           guint i;
 | ||
|           
 | ||
|           for (i = 0; i < hlbsa->n_nodes; i++)
 | ||
|             {
 | ||
|               HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, &g_signal_hlbsa_bconfig, i);
 | ||
| 	      SignalNode *node = NULL;
 | ||
|               Handler *handler;
 | ||
|               
 | ||
| 	      if (!(mask & G_SIGNAL_MATCH_FUNC))
 | ||
| 		{
 | ||
| 		  node = LOOKUP_SIGNAL_NODE (hlist->signal_id);
 | ||
| 		  if (!node->c_marshaller)
 | ||
| 		    continue;
 | ||
| 		}
 | ||
| 	      
 | ||
|               for (handler = hlist->handlers; handler; handler = handler->next)
 | ||
| 		if (handler->sequential_number &&
 | ||
| 		    ((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
 | ||
|                     ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
 | ||
|                     ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
 | ||
| 		    ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
 | ||
| 		    ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
 | ||
| 						      G_REAL_CLOSURE (handler->closure)->meta_marshal == NULL &&
 | ||
| 						      ((GCClosure*) handler->closure)->callback == func)))
 | ||
| 		  {
 | ||
| 		    mlist = handler_match_prepend (mlist, handler, hlist->signal_id);
 | ||
| 		    if (one_and_only)
 | ||
| 		      return mlist;
 | ||
| 		  }
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
|   
 | ||
|   return mlist;
 | ||
| }
 | ||
| 
 | ||
| static inline Handler*
 | ||
| handler_new (guint signal_id, gpointer instance, gboolean after)
 | ||
| {
 | ||
|   Handler *handler = g_slice_new (Handler);
 | ||
| #ifndef G_DISABLE_CHECKS
 | ||
|   if (g_handler_sequential_number < 1)
 | ||
|     g_error (G_STRLOC ": handler id overflow, %s", REPORT_BUG);
 | ||
| #endif
 | ||
|   
 | ||
|   handler->sequential_number = g_handler_sequential_number++;
 | ||
|   handler->prev = NULL;
 | ||
|   handler->next = NULL;
 | ||
|   handler->detail = 0;
 | ||
|   handler->signal_id = signal_id;
 | ||
|   handler->instance = instance;
 | ||
|   handler->ref_count = 1;
 | ||
|   handler->block_count = 0;
 | ||
|   handler->after = after != FALSE;
 | ||
|   handler->closure = NULL;
 | ||
|   handler->has_invalid_closure_notify = 0;
 | ||
| 
 | ||
|   g_hash_table_add (g_handlers, handler);
 | ||
|   
 | ||
|   return handler;
 | ||
| }
 | ||
| 
 | ||
| static inline void
 | ||
| handler_ref (Handler *handler)
 | ||
| {
 | ||
|   g_return_if_fail (handler->ref_count > 0);
 | ||
|   
 | ||
|   handler->ref_count++;
 | ||
| }
 | ||
| 
 | ||
| static inline void
 | ||
| handler_unref_R (guint    signal_id,
 | ||
| 		 gpointer instance,
 | ||
| 		 Handler *handler)
 | ||
| {
 | ||
|   g_return_if_fail (handler->ref_count > 0);
 | ||
| 
 | ||
|   handler->ref_count--;
 | ||
| 
 | ||
|   if (G_UNLIKELY (handler->ref_count == 0))
 | ||
|     {
 | ||
|       HandlerList *hlist = NULL;
 | ||
| 
 | ||
|       if (handler->next)
 | ||
|         handler->next->prev = handler->prev;
 | ||
|       if (handler->prev)    /* watch out for g_signal_handlers_destroy()! */
 | ||
|         handler->prev->next = handler->next;
 | ||
|       else
 | ||
|         {
 | ||
|           hlist = handler_list_lookup (signal_id, instance);
 | ||
|           g_assert (hlist != NULL);
 | ||
|           hlist->handlers = handler->next;
 | ||
|         }
 | ||
| 
 | ||
|       if (instance)
 | ||
|         {
 | ||
|           /*  check if we are removing the handler pointed to by tail_before  */
 | ||
|           if (!handler->after && (!handler->next || handler->next->after))
 | ||
|             {
 | ||
|               if (!hlist)
 | ||
|                 hlist = handler_list_lookup (signal_id, instance);
 | ||
|               if (hlist)
 | ||
|                 {
 | ||
|                   g_assert (hlist->tail_before == handler); /* paranoid */
 | ||
|                   hlist->tail_before = handler->prev;
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|           /*  check if we are removing the handler pointed to by tail_after  */
 | ||
|           if (!handler->next)
 | ||
|             {
 | ||
|               if (!hlist)
 | ||
|                 hlist = handler_list_lookup (signal_id, instance);
 | ||
|               if (hlist)
 | ||
|                 {
 | ||
|                   g_assert (hlist->tail_after == handler); /* paranoid */
 | ||
|                   hlist->tail_after = handler->prev;
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       g_closure_unref (handler->closure);
 | ||
|       SIGNAL_LOCK ();
 | ||
|       g_slice_free (Handler, handler);
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| handler_insert (guint    signal_id,
 | ||
| 		gpointer instance,
 | ||
| 		Handler  *handler)
 | ||
| {
 | ||
|   HandlerList *hlist;
 | ||
|   
 | ||
|   g_assert (handler->prev == NULL && handler->next == NULL); /* paranoid */
 | ||
| 
 | ||
|   hlist = handler_list_ensure (signal_id, instance);
 | ||
|   if (!hlist->handlers)
 | ||
|     {
 | ||
|       hlist->handlers = handler;
 | ||
|       if (!handler->after)
 | ||
|         hlist->tail_before = handler;
 | ||
|     }
 | ||
|   else if (handler->after)
 | ||
|     {
 | ||
|       handler->prev = hlist->tail_after;
 | ||
|       hlist->tail_after->next = handler;
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       if (hlist->tail_before)
 | ||
|         {
 | ||
|           handler->next = hlist->tail_before->next;
 | ||
|           if (handler->next)
 | ||
|             handler->next->prev = handler;
 | ||
|           handler->prev = hlist->tail_before;
 | ||
|           hlist->tail_before->next = handler;
 | ||
|         }
 | ||
|       else /* insert !after handler into a list of only after handlers */
 | ||
|         {
 | ||
|           handler->next = hlist->handlers;
 | ||
|           if (handler->next)
 | ||
|             handler->next->prev = handler;
 | ||
|           hlist->handlers = handler;
 | ||
|         }
 | ||
|       hlist->tail_before = handler;
 | ||
|     }
 | ||
| 
 | ||
|   if (!handler->next)
 | ||
|     hlist->tail_after = handler;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| node_update_single_va_closure (SignalNode *node)
 | ||
| {
 | ||
|   GClosure *closure = NULL;
 | ||
|   gboolean is_after = FALSE;
 | ||
| 
 | ||
|   /* Fast path single-handler without boxing the arguments in GValues */
 | ||
|   if (G_TYPE_IS_OBJECT (node->itype) &&
 | ||
|       (node->flags & (G_SIGNAL_MUST_COLLECT)) == 0 &&
 | ||
|       (node->emission_hooks == NULL || node->emission_hooks->hooks == NULL))
 | ||
|     {
 | ||
|       GSignalFlags run_type;
 | ||
|       ClassClosure * cc; 
 | ||
|       GBSearchArray *bsa = node->class_closure_bsa;
 | ||
| 
 | ||
|       if (bsa == NULL || bsa->n_nodes == 0)
 | ||
| 	closure = SINGLE_VA_CLOSURE_EMPTY_MAGIC;
 | ||
|       else if (bsa->n_nodes == 1)
 | ||
| 	{
 | ||
| 	  /* Look for default class closure (can't support non-default as it
 | ||
| 	     chains up using GValues */
 | ||
| 	  cc = g_bsearch_array_get_nth (bsa, &g_class_closure_bconfig, 0);
 | ||
| 	  if (cc->instance_type == 0)
 | ||
| 	    {
 | ||
| 	      run_type = node->flags & (G_SIGNAL_RUN_FIRST|G_SIGNAL_RUN_LAST|G_SIGNAL_RUN_CLEANUP);
 | ||
| 	      /* Only support *one* of run-first or run-last, not multiple or cleanup */
 | ||
| 	      if (run_type == G_SIGNAL_RUN_FIRST ||
 | ||
| 		  run_type == G_SIGNAL_RUN_LAST)
 | ||
| 		{
 | ||
| 		  closure = cc->closure;
 | ||
| 		  is_after = (run_type == G_SIGNAL_RUN_LAST);
 | ||
| 		}
 | ||
| 	    }
 | ||
| 	}
 | ||
|     }
 | ||
| 
 | ||
|   node->single_va_closure_is_valid = TRUE;
 | ||
|   node->single_va_closure = closure;
 | ||
|   node->single_va_closure_is_after = (guint) is_after;
 | ||
| }
 | ||
| 
 | ||
| static inline void
 | ||
| emission_push (Emission  *emission)
 | ||
| {
 | ||
|   emission->next = g_emissions;
 | ||
|   g_emissions = emission;
 | ||
| }
 | ||
| 
 | ||
| static inline void
 | ||
| emission_pop (Emission  *emission)
 | ||
| {
 | ||
|   Emission *node, *last = NULL;
 | ||
| 
 | ||
|   for (node = g_emissions; node; last = node, node = last->next)
 | ||
|     if (node == emission)
 | ||
|       {
 | ||
| 	if (last)
 | ||
| 	  last->next = node->next;
 | ||
| 	else
 | ||
| 	  g_emissions = node->next;
 | ||
| 	return;
 | ||
|       }
 | ||
|   g_assert_not_reached ();
 | ||
| }
 | ||
| 
 | ||
| static inline Emission*
 | ||
| emission_find (guint     signal_id,
 | ||
| 	       GQuark    detail,
 | ||
| 	       gpointer  instance)
 | ||
| {
 | ||
|   Emission *emission;
 | ||
|   
 | ||
|   for (emission = g_emissions; emission; emission = emission->next)
 | ||
|     if (emission->instance == instance &&
 | ||
| 	emission->ihint.signal_id == signal_id &&
 | ||
| 	emission->ihint.detail == detail)
 | ||
|       return emission;
 | ||
|   return NULL;
 | ||
| }
 | ||
| 
 | ||
| static inline Emission*
 | ||
| emission_find_innermost (gpointer instance)
 | ||
| {
 | ||
|   Emission *emission;
 | ||
|   
 | ||
|   for (emission = g_emissions; emission; emission = emission->next)
 | ||
|     if (emission->instance == instance)
 | ||
|       return emission;
 | ||
| 
 | ||
|   return NULL;
 | ||
| }
 | ||
| 
 | ||
| static gint
 | ||
| signal_key_cmp (gconstpointer node1,
 | ||
|                 gconstpointer node2)
 | ||
| {
 | ||
|   const SignalKey *key1 = node1, *key2 = node2;
 | ||
|   
 | ||
|   if (key1->itype == key2->itype)
 | ||
|     return G_BSEARCH_ARRAY_CMP (key1->quark, key2->quark);
 | ||
|   else
 | ||
|     return G_BSEARCH_ARRAY_CMP (key1->itype, key2->itype);
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| _g_signal_init (void)
 | ||
| {
 | ||
|   SIGNAL_LOCK ();
 | ||
|   if (!g_n_signal_nodes)
 | ||
|     {
 | ||
|       /* setup handler list binary searchable array hash table (in german, that'd be one word ;) */
 | ||
|       g_handler_list_bsa_ht = g_hash_table_new (g_direct_hash, NULL);
 | ||
|       g_signal_key_bsa = g_bsearch_array_create (&g_signal_key_bconfig);
 | ||
|       
 | ||
|       /* invalid (0) signal_id */
 | ||
|       g_n_signal_nodes = 1;
 | ||
|       g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
 | ||
|       g_signal_nodes[0] = NULL;
 | ||
|       g_handlers = g_hash_table_new (handler_hash, handler_equal);
 | ||
|     }
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| _g_signals_destroy (GType itype)
 | ||
| {
 | ||
|   guint i;
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   for (i = 1; i < g_n_signal_nodes; i++)
 | ||
|     {
 | ||
|       SignalNode *node = g_signal_nodes[i];
 | ||
|       
 | ||
|       if (node->itype == itype)
 | ||
|         {
 | ||
|           if (node->destroyed)
 | ||
|             g_critical (G_STRLOC ": signal \"%s\" of type '%s' already destroyed",
 | ||
|                         node->name,
 | ||
|                         type_debug_name (node->itype));
 | ||
|           else
 | ||
| 	    signal_destroy_R (node);
 | ||
|         }
 | ||
|     }
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_stop_emission:
 | ||
|  * @instance: (type GObject.Object): the object whose signal handlers you wish to stop.
 | ||
|  * @signal_id: the signal identifier, as returned by g_signal_lookup().
 | ||
|  * @detail: the detail which the signal was emitted with.
 | ||
|  *
 | ||
|  * Stops a signal's current emission.
 | ||
|  *
 | ||
|  * This will prevent the default method from running, if the signal was
 | ||
|  * %G_SIGNAL_RUN_LAST and you connected normally (i.e. without the "after"
 | ||
|  * flag).
 | ||
|  *
 | ||
|  * Prints a warning if used on a signal which isn't being emitted.
 | ||
|  */
 | ||
| void
 | ||
| g_signal_stop_emission (gpointer instance,
 | ||
|                         guint    signal_id,
 | ||
| 			GQuark   detail)
 | ||
| {
 | ||
|   SignalNode *node;
 | ||
|   
 | ||
|   g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
 | ||
|   g_return_if_fail (signal_id > 0);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   if (node && detail && !(node->flags & G_SIGNAL_DETAILED))
 | ||
|     {
 | ||
|       g_critical ("%s: signal id '%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       return;
 | ||
|     }
 | ||
|   if (node && g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype))
 | ||
|     {
 | ||
|       Emission *emission = emission_find (signal_id, detail, instance);
 | ||
|       
 | ||
|       if (emission)
 | ||
|         {
 | ||
|           if (emission->state == EMISSION_HOOK)
 | ||
|             g_critical (G_STRLOC ": emission of signal \"%s\" for instance '%p' cannot be stopped from emission hook",
 | ||
|                         node->name, instance);
 | ||
|           else if (emission->state == EMISSION_RUN)
 | ||
|             emission->state = EMISSION_STOP;
 | ||
|         }
 | ||
|       else
 | ||
|         g_critical (G_STRLOC ": no emission of signal \"%s\" to stop for instance '%p'",
 | ||
|                     node->name, instance);
 | ||
|     }
 | ||
|   else
 | ||
|     g_critical ("%s: signal id '%u' is invalid for instance '%p'", G_STRLOC, signal_id, instance);
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| signal_finalize_hook (GHookList *hook_list,
 | ||
| 		      GHook     *hook)
 | ||
| {
 | ||
|   GDestroyNotify destroy = hook->destroy;
 | ||
| 
 | ||
|   if (destroy)
 | ||
|     {
 | ||
|       hook->destroy = NULL;
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       destroy (hook->data);
 | ||
|       SIGNAL_LOCK ();
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_add_emission_hook:
 | ||
|  * @signal_id: the signal identifier, as returned by g_signal_lookup().
 | ||
|  * @detail: the detail on which to call the hook.
 | ||
|  * @hook_func: (not nullable): a #GSignalEmissionHook function.
 | ||
|  * @hook_data: (nullable) (closure hook_func): user data for @hook_func.
 | ||
|  * @data_destroy: (nullable) (destroy hook_data): a #GDestroyNotify for @hook_data.
 | ||
|  *
 | ||
|  * Adds an emission hook for a signal, which will get called for any emission
 | ||
|  * of that signal, independent of the instance. This is possible only
 | ||
|  * for signals which don't have %G_SIGNAL_NO_HOOKS flag set.
 | ||
|  *
 | ||
|  * Returns: the hook id, for later use with g_signal_remove_emission_hook().
 | ||
|  */
 | ||
| gulong
 | ||
| g_signal_add_emission_hook (guint               signal_id,
 | ||
| 			    GQuark              detail,
 | ||
| 			    GSignalEmissionHook hook_func,
 | ||
| 			    gpointer            hook_data,
 | ||
| 			    GDestroyNotify      data_destroy)
 | ||
| {
 | ||
|   static gulong seq_hook_id = 1;
 | ||
|   SignalNode *node;
 | ||
|   GHook *hook;
 | ||
|   SignalHook *signal_hook;
 | ||
| 
 | ||
|   g_return_val_if_fail (signal_id > 0, 0);
 | ||
|   g_return_val_if_fail (hook_func != NULL, 0);
 | ||
| 
 | ||
|   SIGNAL_LOCK ();
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   if (!node || node->destroyed)
 | ||
|     {
 | ||
|       g_critical ("%s: invalid signal id '%u'", G_STRLOC, signal_id);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       return 0;
 | ||
|     }
 | ||
|   if (node->flags & G_SIGNAL_NO_HOOKS) 
 | ||
|     {
 | ||
|       g_critical ("%s: signal id '%u' does not support emission hooks (G_SIGNAL_NO_HOOKS flag set)", G_STRLOC, signal_id);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       return 0;
 | ||
|     }
 | ||
|   if (detail && !(node->flags & G_SIGNAL_DETAILED))
 | ||
|     {
 | ||
|       g_critical ("%s: signal id '%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       return 0;
 | ||
|     }
 | ||
|     node->single_va_closure_is_valid = FALSE;
 | ||
|   if (!node->emission_hooks)
 | ||
|     {
 | ||
|       node->emission_hooks = g_new (GHookList, 1);
 | ||
|       g_hook_list_init (node->emission_hooks, sizeof (SignalHook));
 | ||
|       node->emission_hooks->finalize_hook = signal_finalize_hook;
 | ||
|     }
 | ||
| 
 | ||
|   node_check_deprecated (node);
 | ||
| 
 | ||
|   hook = g_hook_alloc (node->emission_hooks);
 | ||
|   hook->data = hook_data;
 | ||
|   hook->func = (gpointer) hook_func;
 | ||
|   hook->destroy = data_destroy;
 | ||
|   signal_hook = SIGNAL_HOOK (hook);
 | ||
|   signal_hook->detail = detail;
 | ||
|   node->emission_hooks->seq_id = seq_hook_id;
 | ||
|   g_hook_append (node->emission_hooks, hook);
 | ||
|   seq_hook_id = node->emission_hooks->seq_id;
 | ||
| 
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|   return hook->hook_id;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_remove_emission_hook:
 | ||
|  * @signal_id: the id of the signal
 | ||
|  * @hook_id: the id of the emission hook, as returned by
 | ||
|  *  g_signal_add_emission_hook()
 | ||
|  *
 | ||
|  * Deletes an emission hook.
 | ||
|  */
 | ||
| void
 | ||
| g_signal_remove_emission_hook (guint  signal_id,
 | ||
| 			       gulong hook_id)
 | ||
| {
 | ||
|   SignalNode *node;
 | ||
| 
 | ||
|   g_return_if_fail (signal_id > 0);
 | ||
|   g_return_if_fail (hook_id > 0);
 | ||
| 
 | ||
|   SIGNAL_LOCK ();
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   if (!node || node->destroyed)
 | ||
|     {
 | ||
|       g_critical ("%s: invalid signal id '%u'", G_STRLOC, signal_id);
 | ||
|       goto out;
 | ||
|     }
 | ||
|   else if (!node->emission_hooks || !g_hook_destroy (node->emission_hooks, hook_id))
 | ||
|     g_critical ("%s: signal \"%s\" had no hook (%lu) to remove", G_STRLOC, node->name, hook_id);
 | ||
| 
 | ||
|   node->single_va_closure_is_valid = FALSE;
 | ||
| 
 | ||
|  out:
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| static inline guint
 | ||
| signal_parse_name (const gchar *name,
 | ||
| 		   GType        itype,
 | ||
| 		   GQuark      *detail_p,
 | ||
| 		   gboolean     force_quark)
 | ||
| {
 | ||
|   const gchar *colon = strchr (name, ':');
 | ||
|   guint signal_id;
 | ||
|   
 | ||
|   if (!colon)
 | ||
|     {
 | ||
|       signal_id = signal_id_lookup (name, itype);
 | ||
|       if (signal_id && detail_p)
 | ||
| 	*detail_p = 0;
 | ||
|     }
 | ||
|   else if (colon[1] == ':')
 | ||
|     {
 | ||
|       gchar buffer[32];
 | ||
|       size_t l = (size_t) (colon - name);
 | ||
|       
 | ||
|       if (colon[2] == '\0')
 | ||
|         return 0;
 | ||
| 
 | ||
|       if (l < 32)
 | ||
| 	{
 | ||
| 	  memcpy (buffer, name, l);
 | ||
| 	  buffer[l] = 0;
 | ||
| 	  signal_id = signal_id_lookup (buffer, itype);
 | ||
| 	}
 | ||
|       else
 | ||
| 	{
 | ||
| 	  gchar *signal = g_new (gchar, l + 1);
 | ||
| 	  
 | ||
| 	  memcpy (signal, name, l);
 | ||
| 	  signal[l] = 0;
 | ||
| 	  signal_id = signal_id_lookup (signal, itype);
 | ||
| 	  g_free (signal);
 | ||
| 	}
 | ||
|       
 | ||
|       if (signal_id && detail_p)
 | ||
|         *detail_p = (force_quark ? g_quark_from_string : g_quark_try_string) (colon + 2);
 | ||
|     }
 | ||
|   else
 | ||
|     signal_id = 0;
 | ||
|   return signal_id;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_parse_name:
 | ||
|  * @detailed_signal: a string of the form "signal-name::detail".
 | ||
|  * @itype: The interface/instance type that introduced "signal-name".
 | ||
|  * @signal_id_p: (out): Location to store the signal id.
 | ||
|  * @detail_p: (out): Location to store the detail quark.
 | ||
|  * @force_detail_quark: %TRUE forces creation of a #GQuark for the detail.
 | ||
|  *
 | ||
|  * Internal function to parse a signal name into its @signal_id
 | ||
|  * and @detail quark.
 | ||
|  *
 | ||
|  * Returns: Whether the signal name could successfully be parsed and @signal_id_p and @detail_p contain valid return values.
 | ||
|  */
 | ||
| gboolean
 | ||
| g_signal_parse_name (const gchar *detailed_signal,
 | ||
| 		     GType        itype,
 | ||
| 		     guint       *signal_id_p,
 | ||
| 		     GQuark      *detail_p,
 | ||
| 		     gboolean	  force_detail_quark)
 | ||
| {
 | ||
|   SignalNode *node;
 | ||
|   GQuark detail = 0;
 | ||
|   guint signal_id;
 | ||
|   
 | ||
|   g_return_val_if_fail (detailed_signal != NULL, FALSE);
 | ||
|   g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), FALSE);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   signal_id = signal_parse_name (detailed_signal, itype, &detail, force_detail_quark);
 | ||
| 
 | ||
|   node = signal_id ? LOOKUP_SIGNAL_NODE (signal_id) : NULL;
 | ||
| 
 | ||
|   if (!node || node->destroyed ||
 | ||
|       (detail && !(node->flags & G_SIGNAL_DETAILED)))
 | ||
|     {
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       return FALSE;
 | ||
|     }
 | ||
| 
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|   if (signal_id_p)
 | ||
|     *signal_id_p = signal_id;
 | ||
|   if (detail_p)
 | ||
|     *detail_p = detail;
 | ||
|   
 | ||
|   return TRUE;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_stop_emission_by_name:
 | ||
|  * @instance: (type GObject.Object): the object whose signal handlers you wish to stop.
 | ||
|  * @detailed_signal: a string of the form "signal-name::detail".
 | ||
|  *
 | ||
|  * Stops a signal's current emission.
 | ||
|  *
 | ||
|  * This is just like g_signal_stop_emission() except it will look up the
 | ||
|  * signal id for you.
 | ||
|  */
 | ||
| void
 | ||
| g_signal_stop_emission_by_name (gpointer     instance,
 | ||
| 				const gchar *detailed_signal)
 | ||
| {
 | ||
|   guint signal_id;
 | ||
|   GQuark detail = 0;
 | ||
|   GType itype;
 | ||
|   
 | ||
|   g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
 | ||
|   g_return_if_fail (detailed_signal != NULL);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   itype = G_TYPE_FROM_INSTANCE (instance);
 | ||
|   signal_id = signal_parse_name (detailed_signal, itype, &detail, TRUE);
 | ||
|   if (signal_id)
 | ||
|     {
 | ||
|       SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|       
 | ||
|       if (detail && !(node->flags & G_SIGNAL_DETAILED))
 | ||
| 	g_critical ("%s: signal '%s' does not support details", G_STRLOC, detailed_signal);
 | ||
|       else if (!g_type_is_a (itype, node->itype))
 | ||
|         g_critical ("%s: signal '%s' is invalid for instance '%p' of type '%s'",
 | ||
|                     G_STRLOC, detailed_signal, instance, g_type_name (itype));
 | ||
|       else
 | ||
| 	{
 | ||
| 	  Emission *emission = emission_find (signal_id, detail, instance);
 | ||
| 	  
 | ||
| 	  if (emission)
 | ||
| 	    {
 | ||
| 	      if (emission->state == EMISSION_HOOK)
 | ||
| 		g_critical (G_STRLOC ": emission of signal \"%s\" for instance '%p' cannot be stopped from emission hook",
 | ||
| 			    node->name, instance);
 | ||
| 	      else if (emission->state == EMISSION_RUN)
 | ||
| 		emission->state = EMISSION_STOP;
 | ||
| 	    }
 | ||
| 	  else
 | ||
| 	    g_critical (G_STRLOC ": no emission of signal \"%s\" to stop for instance '%p'",
 | ||
| 		        node->name, instance);
 | ||
| 	}
 | ||
|     }
 | ||
|   else
 | ||
|     g_critical ("%s: signal '%s' is invalid for instance '%p' of type '%s'",
 | ||
|                 G_STRLOC, detailed_signal, instance, g_type_name (itype));
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_lookup:
 | ||
|  * @name: the signal's name.
 | ||
|  * @itype: the type that the signal operates on.
 | ||
|  *
 | ||
|  * Given the name of the signal and the type of object it connects to, gets
 | ||
|  * the signal's identifying integer. Emitting the signal by number is
 | ||
|  * somewhat faster than using the name each time.
 | ||
|  *
 | ||
|  * Also tries the ancestors of the given type.
 | ||
|  *
 | ||
|  * The type class passed as @itype must already have been instantiated (for
 | ||
|  * example, using g_type_class_ref()) for this function to work, as signals are
 | ||
|  * always installed during class initialization.
 | ||
|  *
 | ||
|  * See g_signal_new() for details on allowed signal names.
 | ||
|  *
 | ||
|  * Returns: the signal's identifying number, or 0 if no signal was found.
 | ||
|  */
 | ||
| guint
 | ||
| g_signal_lookup (const gchar *name,
 | ||
|                  GType        itype)
 | ||
| {
 | ||
|   guint signal_id;
 | ||
|   g_return_val_if_fail (name != NULL, 0);
 | ||
|   g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   signal_id = signal_id_lookup (name, itype);
 | ||
|   SIGNAL_UNLOCK ();
 | ||
|   if (!signal_id)
 | ||
|     {
 | ||
|       /* give elaborate warnings */
 | ||
|       if (!g_type_name (itype))
 | ||
| 	g_critical (G_STRLOC ": unable to look up signal \"%s\" for invalid type id '%"G_GUINTPTR_FORMAT"'",
 | ||
| 		    name, (guintptr) itype);
 | ||
|       else if (!g_signal_is_valid_name (name))
 | ||
|         g_critical (G_STRLOC ": unable to look up invalid signal name \"%s\" on type '%s'",
 | ||
|                     name, g_type_name (itype));
 | ||
|     }
 | ||
|   
 | ||
|   return signal_id;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_list_ids:
 | ||
|  * @itype: Instance or interface type.
 | ||
|  * @n_ids: Location to store the number of signal ids for @itype.
 | ||
|  *
 | ||
|  * Lists the signals by id that a certain instance or interface type
 | ||
|  * created. Further information about the signals can be acquired through
 | ||
|  * g_signal_query().
 | ||
|  *
 | ||
|  * Returns: (array length=n_ids) (transfer full): Newly allocated array of signal IDs.
 | ||
|  */
 | ||
| guint*
 | ||
| g_signal_list_ids (GType  itype,
 | ||
| 		   guint *n_ids)
 | ||
| {
 | ||
|   SignalKey *keys;
 | ||
|   GArray *result;
 | ||
|   guint n_nodes;
 | ||
|   guint i;
 | ||
|   
 | ||
|   g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), NULL);
 | ||
|   g_return_val_if_fail (n_ids != NULL, NULL);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   keys = g_bsearch_array_get_nth (g_signal_key_bsa, &g_signal_key_bconfig, 0);
 | ||
|   n_nodes = g_bsearch_array_get_n_nodes (g_signal_key_bsa);
 | ||
|   result = g_array_new (FALSE, FALSE, sizeof (guint));
 | ||
|   
 | ||
|   for (i = 0; i < n_nodes; i++)
 | ||
|     if (keys[i].itype == itype)
 | ||
|       {
 | ||
|         g_array_append_val (result, keys[i].signal_id);
 | ||
|       }
 | ||
|   *n_ids = result->len;
 | ||
|   SIGNAL_UNLOCK ();
 | ||
|   if (!n_nodes)
 | ||
|     {
 | ||
|       /* give elaborate warnings */
 | ||
|       if (!g_type_name (itype))
 | ||
| 	g_critical (G_STRLOC ": unable to list signals for invalid type id '%"G_GUINTPTR_FORMAT"'",
 | ||
| 		    (guintptr) itype);
 | ||
|       else if (!G_TYPE_IS_INSTANTIATABLE (itype) && !G_TYPE_IS_INTERFACE (itype))
 | ||
| 	g_critical (G_STRLOC ": unable to list signals of non instantiatable type '%s'",
 | ||
| 		    g_type_name (itype));
 | ||
|       else if (!g_type_class_peek (itype) && !G_TYPE_IS_INTERFACE (itype))
 | ||
| 	g_critical (G_STRLOC ": unable to list signals of unloaded type '%s'",
 | ||
| 		    g_type_name (itype));
 | ||
|     }
 | ||
|   
 | ||
|   return (guint*) g_array_free (result, FALSE);
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_name:
 | ||
|  * @signal_id: the signal's identifying number.
 | ||
|  *
 | ||
|  * Given the signal's identifier, finds its name.
 | ||
|  *
 | ||
|  * Two different signals may have the same name, if they have differing types.
 | ||
|  *
 | ||
|  * Returns: (nullable): the signal name, or %NULL if the signal number was invalid.
 | ||
|  */
 | ||
| const gchar *
 | ||
| g_signal_name (guint signal_id)
 | ||
| {
 | ||
|   SignalNode *node;
 | ||
|   const gchar *name;
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   name = node ? node->name : NULL;
 | ||
|   SIGNAL_UNLOCK ();
 | ||
|   
 | ||
|   return (char*) name;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_query:
 | ||
|  * @signal_id: The signal id of the signal to query information for.
 | ||
|  * @query: (out caller-allocates) (not optional): A user provided structure that is
 | ||
|  *  filled in with constant values upon success.
 | ||
|  *
 | ||
|  * Queries the signal system for in-depth information about a
 | ||
|  * specific signal. This function will fill in a user-provided
 | ||
|  * structure to hold signal-specific information. If an invalid
 | ||
|  * signal id is passed in, the @signal_id member of the #GSignalQuery
 | ||
|  * is 0. All members filled into the #GSignalQuery structure should
 | ||
|  * be considered constant and have to be left untouched.
 | ||
|  */
 | ||
| void
 | ||
| g_signal_query (guint         signal_id,
 | ||
| 		GSignalQuery *query)
 | ||
| {
 | ||
|   SignalNode *node;
 | ||
|   
 | ||
|   g_return_if_fail (query != NULL);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   if (!node || node->destroyed)
 | ||
|     query->signal_id = 0;
 | ||
|   else
 | ||
|     {
 | ||
|       query->signal_id = node->signal_id;
 | ||
|       query->signal_name = node->name;
 | ||
|       query->itype = node->itype;
 | ||
|       query->signal_flags = node->flags;
 | ||
|       query->return_type = node->return_type;
 | ||
|       query->n_params = node->n_params;
 | ||
|       query->param_types = node->param_types;
 | ||
|     }
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_new:
 | ||
|  * @signal_name: the name for the signal
 | ||
|  * @itype: the type this signal pertains to. It will also pertain to
 | ||
|  *  types which are derived from this type.
 | ||
|  * @signal_flags: a combination of #GSignalFlags specifying detail of when
 | ||
|  *  the default handler is to be invoked. You should at least specify
 | ||
|  *  %G_SIGNAL_RUN_FIRST or %G_SIGNAL_RUN_LAST.
 | ||
|  * @class_offset: The offset of the function pointer in the class structure
 | ||
|  *  for this type. Used to invoke a class method generically. Pass 0 to
 | ||
|  *  not associate a class method slot with this signal.
 | ||
|  * @accumulator: (nullable) (scope forever): the accumulator for this signal; may be %NULL.
 | ||
|  * @accu_data: (nullable) (closure accumulator): user data for the @accumulator.
 | ||
|  * @c_marshaller: (nullable): the function to translate arrays of parameter
 | ||
|  *  values to signal emissions into C language callback invocations or %NULL.
 | ||
|  * @return_type: the type of return value, or %G_TYPE_NONE for a signal
 | ||
|  *  without a return value.
 | ||
|  * @n_params: the number of parameter types to follow.
 | ||
|  * @...: a list of types, one for each parameter.
 | ||
|  *
 | ||
|  * Creates a new signal. (This is usually done in the class initializer.)
 | ||
|  *
 | ||
|  * A signal name consists of segments consisting of ASCII letters and
 | ||
|  * digits, separated by either the `-` or `_` character. The first
 | ||
|  * character of a signal name must be a letter. Names which violate these
 | ||
|  * rules lead to undefined behaviour. These are the same rules as for property
 | ||
|  * naming (see g_param_spec_internal()).
 | ||
|  *
 | ||
|  * When registering a signal and looking up a signal, either separator can
 | ||
|  * be used, but they cannot be mixed. Using `-` is considerably more efficient.
 | ||
|  * Using `_` is discouraged.
 | ||
|  *
 | ||
|  * If 0 is used for @class_offset subclasses cannot override the class handler
 | ||
|  * in their class_init method by doing super_class->signal_handler = my_signal_handler.
 | ||
|  * Instead they will have to use g_signal_override_class_handler().
 | ||
|  *
 | ||
|  * If @c_marshaller is %NULL, g_cclosure_marshal_generic() will be used as
 | ||
|  * the marshaller for this signal. In some simple cases, g_signal_new()
 | ||
|  * will use a more optimized c_marshaller and va_marshaller for the signal
 | ||
|  * instead of g_cclosure_marshal_generic().
 | ||
|  *
 | ||
|  * If @c_marshaller is non-%NULL, you need to also specify a va_marshaller
 | ||
|  * using g_signal_set_va_marshaller() or the generic va_marshaller will
 | ||
|  * be used.
 | ||
|  *
 | ||
|  * Returns: the signal id
 | ||
|  */
 | ||
| guint
 | ||
| g_signal_new (const gchar	 *signal_name,
 | ||
| 	      GType		  itype,
 | ||
| 	      GSignalFlags	  signal_flags,
 | ||
| 	      guint               class_offset,
 | ||
| 	      GSignalAccumulator  accumulator,
 | ||
| 	      gpointer		  accu_data,
 | ||
| 	      GSignalCMarshaller  c_marshaller,
 | ||
| 	      GType		  return_type,
 | ||
| 	      guint		  n_params,
 | ||
| 	      ...)
 | ||
| {
 | ||
|   va_list args;
 | ||
|   guint signal_id;
 | ||
| 
 | ||
|   g_return_val_if_fail (signal_name != NULL, 0);
 | ||
|   
 | ||
|   va_start (args, n_params);
 | ||
| 
 | ||
|   signal_id = g_signal_new_valist (signal_name, itype, signal_flags,
 | ||
|                                    class_offset ? g_signal_type_cclosure_new (itype, class_offset) : NULL,
 | ||
| 				   accumulator, accu_data, c_marshaller,
 | ||
|                                    return_type, n_params, args);
 | ||
| 
 | ||
|   va_end (args);
 | ||
| 
 | ||
|   return signal_id;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_new_class_handler:
 | ||
|  * @signal_name: the name for the signal
 | ||
|  * @itype: the type this signal pertains to. It will also pertain to
 | ||
|  *  types which are derived from this type.
 | ||
|  * @signal_flags: a combination of #GSignalFlags specifying detail of when
 | ||
|  *  the default handler is to be invoked. You should at least specify
 | ||
|  *  %G_SIGNAL_RUN_FIRST or %G_SIGNAL_RUN_LAST.
 | ||
|  * @class_handler: (nullable) (scope forever): a #GCallback which acts as class implementation of
 | ||
|  *  this signal. Used to invoke a class method generically. Pass %NULL to
 | ||
|  *  not associate a class method with this signal.
 | ||
|  * @accumulator: (nullable) (scope forever): the accumulator for this signal; may be %NULL.
 | ||
|  * @accu_data: (nullable) (closure accumulator): user data for the @accumulator.
 | ||
|  * @c_marshaller: (nullable): the function to translate arrays of parameter
 | ||
|  *  values to signal emissions into C language callback invocations or %NULL.
 | ||
|  * @return_type: the type of return value, or %G_TYPE_NONE for a signal
 | ||
|  *  without a return value.
 | ||
|  * @n_params: the number of parameter types to follow.
 | ||
|  * @...: a list of types, one for each parameter.
 | ||
|  *
 | ||
|  * Creates a new signal. (This is usually done in the class initializer.)
 | ||
|  *
 | ||
|  * This is a variant of g_signal_new() that takes a C callback instead
 | ||
|  * of a class offset for the signal's class handler. This function
 | ||
|  * doesn't need a function pointer exposed in the class structure of
 | ||
|  * an object definition, instead the function pointer is passed
 | ||
|  * directly and can be overridden by derived classes with
 | ||
|  * g_signal_override_class_closure() or
 | ||
|  * g_signal_override_class_handler() and chained to with
 | ||
|  * g_signal_chain_from_overridden() or
 | ||
|  * g_signal_chain_from_overridden_handler().
 | ||
|  *
 | ||
|  * See g_signal_new() for information about signal names.
 | ||
|  *
 | ||
|  * If c_marshaller is %NULL, g_cclosure_marshal_generic() will be used as
 | ||
|  * the marshaller for this signal.
 | ||
|  *
 | ||
|  * Returns: the signal id
 | ||
|  *
 | ||
|  * Since: 2.18
 | ||
|  */
 | ||
| guint
 | ||
| g_signal_new_class_handler (const gchar        *signal_name,
 | ||
|                             GType               itype,
 | ||
|                             GSignalFlags        signal_flags,
 | ||
|                             GCallback           class_handler,
 | ||
|                             GSignalAccumulator  accumulator,
 | ||
|                             gpointer            accu_data,
 | ||
|                             GSignalCMarshaller  c_marshaller,
 | ||
|                             GType               return_type,
 | ||
|                             guint               n_params,
 | ||
|                             ...)
 | ||
| {
 | ||
|   va_list args;
 | ||
|   guint signal_id;
 | ||
| 
 | ||
|   g_return_val_if_fail (signal_name != NULL, 0);
 | ||
| 
 | ||
|   va_start (args, n_params);
 | ||
| 
 | ||
|   signal_id = g_signal_new_valist (signal_name, itype, signal_flags,
 | ||
|                                    class_handler ? g_cclosure_new (class_handler, NULL, NULL) : NULL,
 | ||
|                                    accumulator, accu_data, c_marshaller,
 | ||
|                                    return_type, n_params, args);
 | ||
| 
 | ||
|   va_end (args);
 | ||
| 
 | ||
|   return signal_id;
 | ||
| }
 | ||
| 
 | ||
| static inline ClassClosure*
 | ||
| signal_find_class_closure (SignalNode *node,
 | ||
| 			   GType       itype)
 | ||
| {
 | ||
|   GBSearchArray *bsa = node->class_closure_bsa;
 | ||
|   ClassClosure *cc;
 | ||
| 
 | ||
|   if (bsa)
 | ||
|     {
 | ||
|       ClassClosure key;
 | ||
| 
 | ||
|       /* cc->instance_type is 0 for default closure */
 | ||
| 
 | ||
|       if (g_bsearch_array_get_n_nodes (bsa) == 1)
 | ||
|         {
 | ||
|           cc = g_bsearch_array_get_nth (bsa, &g_class_closure_bconfig, 0);
 | ||
|           if (cc && cc->instance_type == 0) /* check for default closure */
 | ||
|             return cc;
 | ||
|         }
 | ||
| 
 | ||
|       key.instance_type = itype;
 | ||
|       cc = g_bsearch_array_lookup (bsa, &g_class_closure_bconfig, &key);
 | ||
|       while (!cc && key.instance_type)
 | ||
| 	{
 | ||
| 	  key.instance_type = g_type_parent (key.instance_type);
 | ||
| 	  cc = g_bsearch_array_lookup (bsa, &g_class_closure_bconfig, &key);
 | ||
| 	}
 | ||
|     }
 | ||
|   else
 | ||
|     cc = NULL;
 | ||
|   return cc;
 | ||
| }
 | ||
| 
 | ||
| static inline GClosure*
 | ||
| signal_lookup_closure (SignalNode    *node,
 | ||
| 		       GTypeInstance *instance)
 | ||
| {
 | ||
|   ClassClosure *cc;
 | ||
| 
 | ||
|   cc = signal_find_class_closure (node, G_TYPE_FROM_INSTANCE (instance));
 | ||
|   return cc ? cc->closure : NULL;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| signal_add_class_closure (SignalNode *node,
 | ||
| 			  GType       itype,
 | ||
| 			  GClosure   *closure)
 | ||
| {
 | ||
|   ClassClosure key;
 | ||
| 
 | ||
|   node->single_va_closure_is_valid = FALSE;
 | ||
| 
 | ||
|   if (!node->class_closure_bsa)
 | ||
|     node->class_closure_bsa = g_bsearch_array_create (&g_class_closure_bconfig);
 | ||
|   key.instance_type = itype;
 | ||
|   key.closure = g_closure_ref (closure);
 | ||
|   node->class_closure_bsa = g_bsearch_array_insert (node->class_closure_bsa,
 | ||
| 						    &g_class_closure_bconfig,
 | ||
| 						    &key);
 | ||
|   g_closure_sink (closure);
 | ||
|   if (node->c_marshaller && closure && G_CLOSURE_NEEDS_MARSHAL (closure))
 | ||
|     {
 | ||
|       g_closure_set_marshal (closure, node->c_marshaller);
 | ||
|       if (node->va_marshaller)
 | ||
| 	_g_closure_set_va_marshal (closure, node->va_marshaller);
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_newv:
 | ||
|  * @signal_name: the name for the signal
 | ||
|  * @itype: the type this signal pertains to. It will also pertain to
 | ||
|  *     types which are derived from this type
 | ||
|  * @signal_flags: a combination of #GSignalFlags specifying detail of when
 | ||
|  *     the default handler is to be invoked. You should at least specify
 | ||
|  *     %G_SIGNAL_RUN_FIRST or %G_SIGNAL_RUN_LAST
 | ||
|  * @class_closure: (nullable): The closure to invoke on signal emission;
 | ||
|  *     may be %NULL
 | ||
|  * @accumulator: (nullable) (scope forever): the accumulator for this signal; may be %NULL
 | ||
|  * @accu_data: (nullable) (closure accumulator): user data for the @accumulator
 | ||
|  * @c_marshaller: (nullable): the function to translate arrays of
 | ||
|  *     parameter values to signal emissions into C language callback
 | ||
|  *     invocations or %NULL
 | ||
|  * @return_type: the type of return value, or %G_TYPE_NONE for a signal
 | ||
|  *     without a return value
 | ||
|  * @n_params: the length of @param_types
 | ||
|  * @param_types: (array length=n_params) (nullable): an array of types, one for
 | ||
|  *     each parameter (may be %NULL if @n_params is zero)
 | ||
|  *
 | ||
|  * Creates a new signal. (This is usually done in the class initializer.)
 | ||
|  *
 | ||
|  * See g_signal_new() for details on allowed signal names.
 | ||
|  *
 | ||
|  * If c_marshaller is %NULL, g_cclosure_marshal_generic() will be used as
 | ||
|  * the marshaller for this signal.
 | ||
|  *
 | ||
|  * Returns: the signal id
 | ||
|  */
 | ||
| guint
 | ||
| g_signal_newv (const gchar       *signal_name,
 | ||
|                GType              itype,
 | ||
|                GSignalFlags       signal_flags,
 | ||
|                GClosure          *class_closure,
 | ||
|                GSignalAccumulator accumulator,
 | ||
| 	       gpointer		  accu_data,
 | ||
|                GSignalCMarshaller c_marshaller,
 | ||
|                GType		  return_type,
 | ||
|                guint              n_params,
 | ||
|                GType		 *param_types)
 | ||
| {
 | ||
|   const gchar *name;
 | ||
|   gchar *signal_name_copy = NULL;
 | ||
|   guint signal_id, i;
 | ||
|   SignalNode *node;
 | ||
|   GSignalCMarshaller builtin_c_marshaller;
 | ||
|   GSignalCVaMarshaller builtin_va_marshaller;
 | ||
|   GSignalCVaMarshaller va_marshaller;
 | ||
|   
 | ||
|   g_return_val_if_fail (signal_name != NULL, 0);
 | ||
|   g_return_val_if_fail (g_signal_is_valid_name (signal_name), 0);
 | ||
|   g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
 | ||
|   if (n_params)
 | ||
|     g_return_val_if_fail (param_types != NULL, 0);
 | ||
|   g_return_val_if_fail ((return_type & G_SIGNAL_TYPE_STATIC_SCOPE) == 0, 0);
 | ||
|   if (return_type == (G_TYPE_NONE & ~G_SIGNAL_TYPE_STATIC_SCOPE))
 | ||
|     g_return_val_if_fail (accumulator == NULL, 0);
 | ||
|   if (!accumulator)
 | ||
|     g_return_val_if_fail (accu_data == NULL, 0);
 | ||
|   g_return_val_if_fail ((signal_flags & G_SIGNAL_ACCUMULATOR_FIRST_RUN) == 0, 0);
 | ||
| 
 | ||
|   if (!is_canonical (signal_name))
 | ||
|     {
 | ||
|       signal_name_copy = g_strdup (signal_name);
 | ||
|       canonicalize_key (signal_name_copy);
 | ||
|       name = signal_name_copy;
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       name = signal_name;
 | ||
|     }
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   
 | ||
|   signal_id = signal_id_lookup (name, itype);
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   if (node && !node->destroyed)
 | ||
|     {
 | ||
|       g_critical (G_STRLOC ": signal \"%s\" already exists in the '%s' %s",
 | ||
|                   name,
 | ||
|                   type_debug_name (node->itype),
 | ||
|                   G_TYPE_IS_INTERFACE (node->itype) ? "interface" : "class ancestry");
 | ||
|       g_free (signal_name_copy);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       return 0;
 | ||
|     }
 | ||
|   if (node && node->itype != itype)
 | ||
|     {
 | ||
|       g_critical (G_STRLOC ": signal \"%s\" for type '%s' was previously created for type '%s'",
 | ||
|                   name,
 | ||
|                   type_debug_name (itype),
 | ||
|                   type_debug_name (node->itype));
 | ||
|       g_free (signal_name_copy);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       return 0;
 | ||
|     }
 | ||
|   for (i = 0; i < n_params; i++)
 | ||
|     if (!G_TYPE_IS_VALUE (param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE))
 | ||
|       {
 | ||
| 	g_critical (G_STRLOC ": parameter %d of type '%s' for signal \"%s::%s\" is not a value type",
 | ||
| 		    i + 1, type_debug_name (param_types[i]), type_debug_name (itype), name);
 | ||
| 	g_free (signal_name_copy);
 | ||
| 	SIGNAL_UNLOCK ();
 | ||
| 	return 0;
 | ||
|       }
 | ||
|   if (return_type != G_TYPE_NONE && !G_TYPE_IS_VALUE (return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE))
 | ||
|     {
 | ||
|       g_critical (G_STRLOC ": return value of type '%s' for signal \"%s::%s\" is not a value type",
 | ||
| 		  type_debug_name (return_type), type_debug_name (itype), name);
 | ||
|       g_free (signal_name_copy);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       return 0;
 | ||
|     }
 | ||
|   
 | ||
|   /* setup permanent portion of signal node */
 | ||
|   if (!node)
 | ||
|     {
 | ||
|       SignalKey key;
 | ||
|       
 | ||
|       signal_id = g_n_signal_nodes++;
 | ||
|       node = g_new (SignalNode, 1);
 | ||
|       node->signal_id = signal_id;
 | ||
|       g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
 | ||
|       g_signal_nodes[signal_id] = node;
 | ||
|       node->itype = itype;
 | ||
|       key.itype = itype;
 | ||
|       key.signal_id = signal_id;
 | ||
|       node->name = g_intern_string (name);
 | ||
|       key.quark = g_quark_from_string (name);
 | ||
|       g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key);
 | ||
| 
 | ||
|       TRACE (GOBJECT_SIGNAL_NEW (signal_id, name, (uintmax_t) itype));
 | ||
|     }
 | ||
|   node->destroyed = FALSE;
 | ||
| 
 | ||
|   /* setup reinitializable portion */
 | ||
|   node->single_va_closure_is_valid = FALSE;
 | ||
|   node->flags = signal_flags & G_SIGNAL_FLAGS_MASK;
 | ||
|   node->n_params = n_params;
 | ||
|   node->param_types = g_memdup2 (param_types, sizeof (GType) * n_params);
 | ||
|   node->return_type = return_type;
 | ||
|   node->class_closure_bsa = NULL;
 | ||
|   if (accumulator)
 | ||
|     {
 | ||
|       node->accumulator = g_new (SignalAccumulator, 1);
 | ||
|       node->accumulator->func = accumulator;
 | ||
|       node->accumulator->data = accu_data;
 | ||
|     }
 | ||
|   else
 | ||
|     node->accumulator = NULL;
 | ||
| 
 | ||
|   builtin_c_marshaller = NULL;
 | ||
|   builtin_va_marshaller = NULL;
 | ||
| 
 | ||
|   /* Pick up built-in va marshallers for standard types, and
 | ||
|      instead of generic marshaller if no marshaller specified */
 | ||
|   if (n_params == 0 && return_type == G_TYPE_NONE)
 | ||
|     {
 | ||
|       builtin_c_marshaller = g_cclosure_marshal_VOID__VOID;
 | ||
|       builtin_va_marshaller = g_cclosure_marshal_VOID__VOIDv;
 | ||
|     }
 | ||
|   else if (n_params == 1 && return_type == G_TYPE_NONE)
 | ||
|     {
 | ||
| #define ADD_CHECK(__type__) \
 | ||
|       else if (g_type_is_a (param_types[0] & ~G_SIGNAL_TYPE_STATIC_SCOPE, G_TYPE_ ##__type__))         \
 | ||
| 	{                                                                \
 | ||
| 	  builtin_c_marshaller = g_cclosure_marshal_VOID__ ## __type__;  \
 | ||
| 	  builtin_va_marshaller = g_cclosure_marshal_VOID__ ## __type__ ##v;     \
 | ||
| 	}
 | ||
| 
 | ||
|       if (0) {}
 | ||
|       ADD_CHECK (BOOLEAN)
 | ||
|       ADD_CHECK (CHAR)
 | ||
|       ADD_CHECK (UCHAR)
 | ||
|       ADD_CHECK (INT)
 | ||
|       ADD_CHECK (UINT)
 | ||
|       ADD_CHECK (LONG)
 | ||
|       ADD_CHECK (ULONG)
 | ||
|       ADD_CHECK (ENUM)
 | ||
|       ADD_CHECK (FLAGS)
 | ||
|       ADD_CHECK (FLOAT)
 | ||
|       ADD_CHECK (DOUBLE)
 | ||
|       ADD_CHECK (STRING)
 | ||
|       ADD_CHECK (PARAM)
 | ||
|       ADD_CHECK (BOXED)
 | ||
|       ADD_CHECK (POINTER)
 | ||
|       ADD_CHECK (OBJECT)
 | ||
|       ADD_CHECK (VARIANT)
 | ||
|     }
 | ||
| 
 | ||
|   if (c_marshaller == NULL)
 | ||
|     {
 | ||
|       if (builtin_c_marshaller)
 | ||
|         {
 | ||
| 	  c_marshaller = builtin_c_marshaller;
 | ||
|           va_marshaller = builtin_va_marshaller;
 | ||
|         }
 | ||
|       else
 | ||
| 	{
 | ||
| 	  c_marshaller = g_cclosure_marshal_generic;
 | ||
| 	  va_marshaller = g_cclosure_marshal_generic_va;
 | ||
| 	}
 | ||
|     }
 | ||
|   else
 | ||
|     va_marshaller = NULL;
 | ||
| 
 | ||
|   node->c_marshaller = c_marshaller;
 | ||
|   node->va_marshaller = va_marshaller;
 | ||
|   node->emission_hooks = NULL;
 | ||
|   if (class_closure)
 | ||
|     signal_add_class_closure (node, 0, class_closure);
 | ||
| 
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|   g_free (signal_name_copy);
 | ||
| 
 | ||
|   return signal_id;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_set_va_marshaller:
 | ||
|  * @signal_id: the signal id
 | ||
|  * @instance_type: the instance type on which to set the marshaller.
 | ||
|  * @va_marshaller: the marshaller to set.
 | ||
|  *
 | ||
|  * Change the #GSignalCVaMarshaller used for a given signal.  This is a
 | ||
|  * specialised form of the marshaller that can often be used for the
 | ||
|  * common case of a single connected signal handler and avoids the
 | ||
|  * overhead of #GValue.  Its use is optional.
 | ||
|  *
 | ||
|  * Since: 2.32
 | ||
|  */
 | ||
| void
 | ||
| g_signal_set_va_marshaller (guint              signal_id,
 | ||
| 			    GType              instance_type,
 | ||
| 			    GSignalCVaMarshaller va_marshaller)
 | ||
| {
 | ||
|   SignalNode *node;
 | ||
|   
 | ||
|   g_return_if_fail (signal_id > 0);
 | ||
|   g_return_if_fail (va_marshaller != NULL);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   if (node)
 | ||
|     {
 | ||
|       node->va_marshaller = va_marshaller;
 | ||
|       if (node->class_closure_bsa)
 | ||
| 	{
 | ||
| 	  ClassClosure *cc = g_bsearch_array_get_nth (node->class_closure_bsa, &g_class_closure_bconfig, 0);
 | ||
| 	  if (cc->closure->marshal == node->c_marshaller)
 | ||
| 	    _g_closure_set_va_marshal (cc->closure, va_marshaller);
 | ||
| 	}
 | ||
| 
 | ||
|       node->single_va_closure_is_valid = FALSE;
 | ||
|     }
 | ||
| 
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_new_valist:
 | ||
|  * @signal_name: the name for the signal
 | ||
|  * @itype: the type this signal pertains to. It will also pertain to
 | ||
|  *  types which are derived from this type.
 | ||
|  * @signal_flags: a combination of #GSignalFlags specifying detail of when
 | ||
|  *  the default handler is to be invoked. You should at least specify
 | ||
|  *  %G_SIGNAL_RUN_FIRST or %G_SIGNAL_RUN_LAST.
 | ||
|  * @class_closure: (nullable): The closure to invoke on signal emission; may be %NULL.
 | ||
|  * @accumulator: (nullable) (scope forever): the accumulator for this signal; may be %NULL.
 | ||
|  * @accu_data: (nullable) (closure accumulator): user data for the @accumulator.
 | ||
|  * @c_marshaller: (nullable): the function to translate arrays of parameter
 | ||
|  *  values to signal emissions into C language callback invocations or %NULL.
 | ||
|  * @return_type: the type of return value, or %G_TYPE_NONE for a signal
 | ||
|  *  without a return value.
 | ||
|  * @n_params: the number of parameter types in @args.
 | ||
|  * @args: va_list of #GType, one for each parameter.
 | ||
|  *
 | ||
|  * Creates a new signal. (This is usually done in the class initializer.)
 | ||
|  *
 | ||
|  * See g_signal_new() for details on allowed signal names.
 | ||
|  *
 | ||
|  * If c_marshaller is %NULL, g_cclosure_marshal_generic() will be used as
 | ||
|  * the marshaller for this signal.
 | ||
|  *
 | ||
|  * Returns: the signal id
 | ||
|  */
 | ||
| guint
 | ||
| g_signal_new_valist (const gchar       *signal_name,
 | ||
|                      GType              itype,
 | ||
|                      GSignalFlags       signal_flags,
 | ||
|                      GClosure          *class_closure,
 | ||
|                      GSignalAccumulator accumulator,
 | ||
|                      gpointer           accu_data,
 | ||
|                      GSignalCMarshaller c_marshaller,
 | ||
|                      GType              return_type,
 | ||
|                      guint              n_params,
 | ||
|                      va_list            args)
 | ||
| {
 | ||
|   /* Somewhat arbitrarily reserve 200 bytes. That should cover the majority
 | ||
|    * of cases where n_params is small and still be small enough for what we
 | ||
|    * want to put on the stack. */
 | ||
|   GType param_types_stack[200 / sizeof (GType)];
 | ||
|   GType *param_types_heap = NULL;
 | ||
|   GType *param_types;
 | ||
|   guint i;
 | ||
|   guint signal_id;
 | ||
| 
 | ||
|   param_types = param_types_stack;
 | ||
|   if (n_params > 0)
 | ||
|     {
 | ||
|       if (G_UNLIKELY (n_params > G_N_ELEMENTS (param_types_stack)))
 | ||
|         {
 | ||
|           param_types_heap = g_new (GType, n_params);
 | ||
|           param_types = param_types_heap;
 | ||
|         }
 | ||
| 
 | ||
|       for (i = 0; i < n_params; i++)
 | ||
|         param_types[i] = va_arg (args, GType);
 | ||
|     }
 | ||
| 
 | ||
|   signal_id = g_signal_newv (signal_name, itype, signal_flags,
 | ||
|                              class_closure, accumulator, accu_data, c_marshaller,
 | ||
|                              return_type, n_params, param_types);
 | ||
|   g_free (param_types_heap);
 | ||
| 
 | ||
|   return signal_id;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| signal_destroy_R (SignalNode *signal_node)
 | ||
| {
 | ||
|   SignalNode node = *signal_node;
 | ||
| 
 | ||
|   signal_node->destroyed = TRUE;
 | ||
|   
 | ||
|   /* reentrancy caution, zero out real contents first */
 | ||
|   signal_node->single_va_closure_is_valid = FALSE;
 | ||
|   signal_node->n_params = 0;
 | ||
|   signal_node->param_types = NULL;
 | ||
|   signal_node->return_type = 0;
 | ||
|   signal_node->class_closure_bsa = NULL;
 | ||
|   signal_node->accumulator = NULL;
 | ||
|   signal_node->c_marshaller = NULL;
 | ||
|   signal_node->va_marshaller = NULL;
 | ||
|   signal_node->emission_hooks = NULL;
 | ||
|   
 | ||
| #ifdef	G_ENABLE_DEBUG
 | ||
|   /* check current emissions */
 | ||
|   {
 | ||
|     Emission *emission;
 | ||
|     
 | ||
|     for (emission = g_emissions; emission; emission = emission->next)
 | ||
|       if (emission->ihint.signal_id == node.signal_id)
 | ||
|         g_critical (G_STRLOC ": signal \"%s\" being destroyed is currently in emission (instance '%p')",
 | ||
|                     node.name, emission->instance);
 | ||
|   }
 | ||
| #endif
 | ||
|   
 | ||
|   /* free contents that need to
 | ||
|    */
 | ||
|   SIGNAL_UNLOCK ();
 | ||
|   g_free (node.param_types);
 | ||
|   if (node.class_closure_bsa)
 | ||
|     {
 | ||
|       guint i;
 | ||
| 
 | ||
|       for (i = 0; i < node.class_closure_bsa->n_nodes; i++)
 | ||
| 	{
 | ||
| 	  ClassClosure *cc = g_bsearch_array_get_nth (node.class_closure_bsa, &g_class_closure_bconfig, i);
 | ||
| 
 | ||
| 	  g_closure_unref (cc->closure);
 | ||
| 	}
 | ||
|       g_bsearch_array_free (node.class_closure_bsa, &g_class_closure_bconfig);
 | ||
|     }
 | ||
|   g_free (node.accumulator);
 | ||
|   if (node.emission_hooks)
 | ||
|     {
 | ||
|       g_hook_list_clear (node.emission_hooks);
 | ||
|       g_free (node.emission_hooks);
 | ||
|     }
 | ||
|   SIGNAL_LOCK ();
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_override_class_closure:
 | ||
|  * @signal_id: the signal id
 | ||
|  * @instance_type: the instance type on which to override the class closure
 | ||
|  *  for the signal.
 | ||
|  * @class_closure: the closure.
 | ||
|  *
 | ||
|  * Overrides the class closure (i.e. the default handler) for the given signal
 | ||
|  * for emissions on instances of @instance_type. @instance_type must be derived
 | ||
|  * from the type to which the signal belongs.
 | ||
|  *
 | ||
|  * See g_signal_chain_from_overridden() and
 | ||
|  * g_signal_chain_from_overridden_handler() for how to chain up to the
 | ||
|  * parent class closure from inside the overridden one.
 | ||
|  */
 | ||
| void
 | ||
| g_signal_override_class_closure (guint     signal_id,
 | ||
| 				 GType     instance_type,
 | ||
| 				 GClosure *class_closure)
 | ||
| {
 | ||
|   SignalNode *node;
 | ||
|   
 | ||
|   g_return_if_fail (signal_id > 0);
 | ||
|   g_return_if_fail (class_closure != NULL);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   node_check_deprecated (node);
 | ||
|   if (!g_type_is_a (instance_type, node->itype))
 | ||
|     g_critical ("%s: type '%s' cannot be overridden for signal id '%u'", G_STRLOC, type_debug_name (instance_type), signal_id);
 | ||
|   else
 | ||
|     {
 | ||
|       ClassClosure *cc = signal_find_class_closure (node, instance_type);
 | ||
|       
 | ||
|       if (cc && cc->instance_type == instance_type)
 | ||
| 	g_critical ("%s: type '%s' is already overridden for signal id '%u'", G_STRLOC, type_debug_name (instance_type), signal_id);
 | ||
|       else
 | ||
| 	signal_add_class_closure (node, instance_type, class_closure);
 | ||
|     }
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_override_class_handler:
 | ||
|  * @signal_name: the name for the signal
 | ||
|  * @instance_type: the instance type on which to override the class handler
 | ||
|  *  for the signal.
 | ||
|  * @class_handler: (scope forever): the handler.
 | ||
|  *
 | ||
|  * Overrides the class closure (i.e. the default handler) for the
 | ||
|  * given signal for emissions on instances of @instance_type with
 | ||
|  * callback @class_handler. @instance_type must be derived from the
 | ||
|  * type to which the signal belongs.
 | ||
|  *
 | ||
|  * See g_signal_chain_from_overridden() and
 | ||
|  * g_signal_chain_from_overridden_handler() for how to chain up to the
 | ||
|  * parent class closure from inside the overridden one.
 | ||
|  *
 | ||
|  * Since: 2.18
 | ||
|  */
 | ||
| void
 | ||
| g_signal_override_class_handler (const gchar *signal_name,
 | ||
| 				 GType        instance_type,
 | ||
| 				 GCallback    class_handler)
 | ||
| {
 | ||
|   guint signal_id;
 | ||
| 
 | ||
|   g_return_if_fail (signal_name != NULL);
 | ||
|   g_return_if_fail (instance_type != G_TYPE_NONE);
 | ||
|   g_return_if_fail (class_handler != NULL);
 | ||
| 
 | ||
|   signal_id = g_signal_lookup (signal_name, instance_type);
 | ||
| 
 | ||
|   if (signal_id)
 | ||
|     g_signal_override_class_closure (signal_id, instance_type,
 | ||
|                                      g_cclosure_new (class_handler, NULL, NULL));
 | ||
|   else
 | ||
|     g_critical ("%s: signal name '%s' is invalid for type id '%"G_GUINTPTR_FORMAT"'",
 | ||
|                 G_STRLOC, signal_name, (guintptr) instance_type);
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_chain_from_overridden:
 | ||
|  * @instance_and_params: (array): the argument list of the signal emission.
 | ||
|  *  The first element in the array is a #GValue for the instance the signal
 | ||
|  *  is being emitted on. The rest are any arguments to be passed to the signal.
 | ||
|  * @return_value: Location for the return value.
 | ||
|  *
 | ||
|  * Calls the original class closure of a signal. This function should only
 | ||
|  * be called from an overridden class closure; see
 | ||
|  * g_signal_override_class_closure() and
 | ||
|  * g_signal_override_class_handler().
 | ||
|  */
 | ||
| void
 | ||
| g_signal_chain_from_overridden (const GValue *instance_and_params,
 | ||
| 				GValue       *return_value)
 | ||
| {
 | ||
|   GType chain_type = 0, restore_type = 0;
 | ||
|   Emission *emission = NULL;
 | ||
|   GClosure *closure = NULL;
 | ||
|   guint n_params = 0;
 | ||
|   gpointer instance;
 | ||
|   
 | ||
|   g_return_if_fail (instance_and_params != NULL);
 | ||
|   instance = g_value_peek_pointer (instance_and_params);
 | ||
|   g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   emission = emission_find_innermost (instance);
 | ||
|   if (emission)
 | ||
|     {
 | ||
|       SignalNode *node = LOOKUP_SIGNAL_NODE (emission->ihint.signal_id);
 | ||
|       
 | ||
|       g_assert (node != NULL);	/* paranoid */
 | ||
|       
 | ||
|       /* we should probably do the same parameter checks as g_signal_emit() here.
 | ||
|        */
 | ||
|       if (emission->chain_type != G_TYPE_NONE)
 | ||
| 	{
 | ||
| 	  ClassClosure *cc = signal_find_class_closure (node, emission->chain_type);
 | ||
| 	  
 | ||
| 	  g_assert (cc != NULL);	/* closure currently in call stack */
 | ||
| 
 | ||
| 	  n_params = node->n_params;
 | ||
| 	  restore_type = cc->instance_type;
 | ||
| 	  cc = signal_find_class_closure (node, g_type_parent (cc->instance_type));
 | ||
| 	  if (cc && cc->instance_type != restore_type)
 | ||
| 	    {
 | ||
| 	      closure = cc->closure;
 | ||
| 	      chain_type = cc->instance_type;
 | ||
| 	    }
 | ||
| 	}
 | ||
|       else
 | ||
| 	g_critical ("%s: signal id '%u' cannot be chained from current emission stage for instance '%p'", G_STRLOC, node->signal_id, instance);
 | ||
|     }
 | ||
|   else
 | ||
|     g_critical ("%s: no signal is currently being emitted for instance '%p'", G_STRLOC, instance);
 | ||
| 
 | ||
|   if (closure)
 | ||
|     {
 | ||
|       emission->chain_type = chain_type;
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       g_closure_invoke (closure,
 | ||
| 			return_value,
 | ||
| 			n_params + 1,
 | ||
| 			instance_and_params,
 | ||
| 			&emission->ihint);
 | ||
|       SIGNAL_LOCK ();
 | ||
|       emission->chain_type = restore_type;
 | ||
|     }
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_chain_from_overridden_handler: (skip)
 | ||
|  * @instance: (type GObject.TypeInstance): the instance the signal is being
 | ||
|  *    emitted on.
 | ||
|  * @...: parameters to be passed to the parent class closure, followed by a
 | ||
|  *  location for the return value. If the return type of the signal
 | ||
|  *  is %G_TYPE_NONE, the return value location can be omitted.
 | ||
|  *
 | ||
|  * Calls the original class closure of a signal. This function should
 | ||
|  * only be called from an overridden class closure; see
 | ||
|  * g_signal_override_class_closure() and
 | ||
|  * g_signal_override_class_handler().
 | ||
|  *
 | ||
|  * Since: 2.18
 | ||
|  */
 | ||
| void
 | ||
| g_signal_chain_from_overridden_handler (gpointer instance,
 | ||
|                                         ...)
 | ||
| {
 | ||
|   GType chain_type = 0, restore_type = 0;
 | ||
|   Emission *emission = NULL;
 | ||
|   GClosure *closure = NULL;
 | ||
|   SignalNode *node = NULL;
 | ||
|   guint n_params = 0;
 | ||
| 
 | ||
|   g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
 | ||
| 
 | ||
|   SIGNAL_LOCK ();
 | ||
|   emission = emission_find_innermost (instance);
 | ||
|   if (emission)
 | ||
|     {
 | ||
|       node = LOOKUP_SIGNAL_NODE (emission->ihint.signal_id);
 | ||
| 
 | ||
|       g_assert (node != NULL);	/* paranoid */
 | ||
| 
 | ||
|       /* we should probably do the same parameter checks as g_signal_emit() here.
 | ||
|        */
 | ||
|       if (emission->chain_type != G_TYPE_NONE)
 | ||
| 	{
 | ||
| 	  ClassClosure *cc = signal_find_class_closure (node, emission->chain_type);
 | ||
| 
 | ||
| 	  g_assert (cc != NULL);	/* closure currently in call stack */
 | ||
| 
 | ||
| 	  n_params = node->n_params;
 | ||
| 	  restore_type = cc->instance_type;
 | ||
| 	  cc = signal_find_class_closure (node, g_type_parent (cc->instance_type));
 | ||
| 	  if (cc && cc->instance_type != restore_type)
 | ||
| 	    {
 | ||
| 	      closure = cc->closure;
 | ||
| 	      chain_type = cc->instance_type;
 | ||
| 	    }
 | ||
| 	}
 | ||
|       else
 | ||
| 	g_critical ("%s: signal id '%u' cannot be chained from current emission stage for instance '%p'", G_STRLOC, node->signal_id, instance);
 | ||
|     }
 | ||
|   else
 | ||
|     g_critical ("%s: no signal is currently being emitted for instance '%p'", G_STRLOC, instance);
 | ||
| 
 | ||
|   if (closure)
 | ||
|     {
 | ||
|       GValue *instance_and_params;
 | ||
|       GType signal_return_type;
 | ||
|       GValue *param_values;
 | ||
|       va_list var_args;
 | ||
|       guint i;
 | ||
| 
 | ||
|       va_start (var_args, instance);
 | ||
| 
 | ||
|       signal_return_type = node->return_type;
 | ||
|       instance_and_params = g_newa0 (GValue, n_params + 1);
 | ||
|       param_values = instance_and_params + 1;
 | ||
| 
 | ||
|       for (i = 0; i < node->n_params; i++)
 | ||
|         {
 | ||
|           gchar *error;
 | ||
|           GType ptype = node->param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE;
 | ||
|           gboolean static_scope = node->param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE;
 | ||
| 
 | ||
|           SIGNAL_UNLOCK ();
 | ||
|           G_VALUE_COLLECT_INIT (param_values + i, ptype,
 | ||
| 				var_args,
 | ||
| 				static_scope ? G_VALUE_NOCOPY_CONTENTS : 0,
 | ||
| 				&error);
 | ||
|           if (error)
 | ||
|             {
 | ||
|               g_critical ("%s: %s", G_STRLOC, error);
 | ||
|               g_free (error);
 | ||
| 
 | ||
|               /* we purposely leak the value here, it might not be
 | ||
|                * in a correct state if an error condition occurred
 | ||
|                */
 | ||
|               while (i--)
 | ||
|                 g_value_unset (param_values + i);
 | ||
| 
 | ||
|               va_end (var_args);
 | ||
|               return;
 | ||
|             }
 | ||
|           SIGNAL_LOCK ();
 | ||
|         }
 | ||
| 
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       g_value_init_from_instance (instance_and_params, instance);
 | ||
|       SIGNAL_LOCK ();
 | ||
| 
 | ||
|       emission->chain_type = chain_type;
 | ||
|       SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|       if (signal_return_type == G_TYPE_NONE)
 | ||
|         {
 | ||
|           g_closure_invoke (closure,
 | ||
|                             NULL,
 | ||
|                             n_params + 1,
 | ||
|                             instance_and_params,
 | ||
|                             &emission->ihint);
 | ||
|         }
 | ||
|       else
 | ||
|         {
 | ||
|           GValue return_value = G_VALUE_INIT;
 | ||
|           gchar *error = NULL;
 | ||
|           GType rtype = signal_return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE;
 | ||
|           gboolean static_scope = signal_return_type & G_SIGNAL_TYPE_STATIC_SCOPE;
 | ||
| 
 | ||
|           g_value_init (&return_value, rtype);
 | ||
| 
 | ||
|           g_closure_invoke (closure,
 | ||
|                             &return_value,
 | ||
|                             n_params + 1,
 | ||
|                             instance_and_params,
 | ||
|                             &emission->ihint);
 | ||
| 
 | ||
|           G_VALUE_LCOPY (&return_value,
 | ||
|                          var_args,
 | ||
|                          static_scope ? G_VALUE_NOCOPY_CONTENTS : 0,
 | ||
|                          &error);
 | ||
|           if (!error)
 | ||
|             {
 | ||
|               g_value_unset (&return_value);
 | ||
|             }
 | ||
|           else
 | ||
|             {
 | ||
|               g_critical ("%s: %s", G_STRLOC, error);
 | ||
|               g_free (error);
 | ||
| 
 | ||
|               /* we purposely leak the value here, it might not be
 | ||
|                * in a correct state if an error condition occurred
 | ||
|                */
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|       for (i = 0; i < n_params; i++)
 | ||
|         g_value_unset (param_values + i);
 | ||
|       g_value_unset (instance_and_params);
 | ||
| 
 | ||
|       va_end (var_args);
 | ||
| 
 | ||
|       SIGNAL_LOCK ();
 | ||
|       emission->chain_type = restore_type;
 | ||
|     }
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_get_invocation_hint:
 | ||
|  * @instance: (type GObject.Object): the instance to query
 | ||
|  *
 | ||
|  * Returns the invocation hint of the innermost signal emission of instance.
 | ||
|  *
 | ||
|  * Returns: (transfer none) (nullable): the invocation hint of the innermost
 | ||
|  *     signal emission, or %NULL if not found.
 | ||
|  */
 | ||
| GSignalInvocationHint*
 | ||
| g_signal_get_invocation_hint (gpointer instance)
 | ||
| {
 | ||
|   Emission *emission = NULL;
 | ||
|   
 | ||
|   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), NULL);
 | ||
| 
 | ||
|   SIGNAL_LOCK ();
 | ||
|   emission = emission_find_innermost (instance);
 | ||
|   SIGNAL_UNLOCK ();
 | ||
|   
 | ||
|   return emission ? &emission->ihint : NULL;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_connect_closure_by_id:
 | ||
|  * @instance: (type GObject.Object): the instance to connect to.
 | ||
|  * @signal_id: the id of the signal.
 | ||
|  * @detail: the detail.
 | ||
|  * @closure: (not nullable): the closure to connect.
 | ||
|  * @after: whether the handler should be called before or after the
 | ||
|  *  default handler of the signal.
 | ||
|  *
 | ||
|  * Connects a closure to a signal for a particular object.
 | ||
|  *
 | ||
|  * If @closure is a floating reference (see g_closure_sink()), this function
 | ||
|  * takes ownership of @closure.
 | ||
|  *
 | ||
|  * This function cannot fail. If the given signal name doesn’t exist,
 | ||
|  * a critical warning is emitted. No validation is performed on the
 | ||
|  * ‘detail’ string when specified in @detailed_signal, other than a
 | ||
|  * non-empty check.
 | ||
|  *
 | ||
|  * Refer to the [signals documentation](signals.html) for more
 | ||
|  * details.
 | ||
|  *
 | ||
|  * Returns: the handler ID (always greater than 0)
 | ||
|  */
 | ||
| gulong
 | ||
| g_signal_connect_closure_by_id (gpointer  instance,
 | ||
| 				guint     signal_id,
 | ||
| 				GQuark    detail,
 | ||
| 				GClosure *closure,
 | ||
| 				gboolean  after)
 | ||
| {
 | ||
|   SignalNode *node;
 | ||
|   gulong handler_seq_no = 0;
 | ||
|   
 | ||
|   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
 | ||
|   g_return_val_if_fail (signal_id > 0, 0);
 | ||
|   g_return_val_if_fail (closure != NULL, 0);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   if (node)
 | ||
|     {
 | ||
|       if (detail && !(node->flags & G_SIGNAL_DETAILED))
 | ||
| 	g_critical ("%s: signal id '%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
 | ||
|       else if (!g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype))
 | ||
| 	g_critical ("%s: signal id '%u' is invalid for instance '%p'", G_STRLOC, signal_id, instance);
 | ||
|       else
 | ||
| 	{
 | ||
| 	  Handler *handler = handler_new (signal_id, instance, after);
 | ||
| 
 | ||
|           if (G_TYPE_IS_OBJECT (node->itype))
 | ||
|             _g_object_set_has_signal_handler ((GObject *) instance, signal_id);
 | ||
| 
 | ||
|           handler_seq_no = handler->sequential_number;
 | ||
| 	  handler->detail = detail;
 | ||
| 	  handler->closure = g_closure_ref (closure);
 | ||
| 	  g_closure_sink (closure);
 | ||
| 	  add_invalid_closure_notify (handler, instance);
 | ||
| 	  handler_insert (signal_id, instance, handler);
 | ||
| 	  if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (closure))
 | ||
| 	    {
 | ||
| 	      g_closure_set_marshal (closure, node->c_marshaller);
 | ||
| 	      if (node->va_marshaller)
 | ||
| 		_g_closure_set_va_marshal (closure, node->va_marshaller);
 | ||
| 	    }
 | ||
| 	}
 | ||
|     }
 | ||
|   else
 | ||
|     g_critical ("%s: signal id '%u' is invalid for instance '%p'", G_STRLOC, signal_id, instance);
 | ||
|   SIGNAL_UNLOCK ();
 | ||
|   
 | ||
|   return handler_seq_no;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_connect_closure:
 | ||
|  * @instance: (type GObject.Object): the instance to connect to.
 | ||
|  * @detailed_signal: a string of the form "signal-name::detail".
 | ||
|  * @closure: (not nullable): the closure to connect.
 | ||
|  * @after: whether the handler should be called before or after the
 | ||
|  *  default handler of the signal.
 | ||
|  *
 | ||
|  * Connects a closure to a signal for a particular object.
 | ||
|  *
 | ||
|  * If @closure is a floating reference (see g_closure_sink()), this function
 | ||
|  * takes ownership of @closure.
 | ||
|  *
 | ||
|  * This function cannot fail. If the given signal name doesn’t exist,
 | ||
|  * a critical warning is emitted. No validation is performed on the
 | ||
|  * ‘detail’ string when specified in @detailed_signal, other than a
 | ||
|  * non-empty check.
 | ||
|  *
 | ||
|  * Refer to the [signals documentation](signals.html) for more
 | ||
|  * details.
 | ||
|  *
 | ||
|  * Returns: the handler ID (always greater than 0)
 | ||
|  */
 | ||
| gulong
 | ||
| g_signal_connect_closure (gpointer     instance,
 | ||
| 			  const gchar *detailed_signal,
 | ||
| 			  GClosure    *closure,
 | ||
| 			  gboolean     after)
 | ||
| {
 | ||
|   guint signal_id;
 | ||
|   gulong handler_seq_no = 0;
 | ||
|   GQuark detail = 0;
 | ||
|   GType itype;
 | ||
| 
 | ||
|   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
 | ||
|   g_return_val_if_fail (detailed_signal != NULL, 0);
 | ||
|   g_return_val_if_fail (closure != NULL, 0);
 | ||
| 
 | ||
|   SIGNAL_LOCK ();
 | ||
|   itype = G_TYPE_FROM_INSTANCE (instance);
 | ||
|   signal_id = signal_parse_name (detailed_signal, itype, &detail, TRUE);
 | ||
|   if (signal_id)
 | ||
|     {
 | ||
|       SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
| 
 | ||
|       if (detail && !(node->flags & G_SIGNAL_DETAILED))
 | ||
| 	g_critical ("%s: signal '%s' does not support details", G_STRLOC, detailed_signal);
 | ||
|       else if (!g_type_is_a (itype, node->itype))
 | ||
|         g_critical ("%s: signal '%s' is invalid for instance '%p' of type '%s'",
 | ||
|                     G_STRLOC, detailed_signal, instance, g_type_name (itype));
 | ||
|       else
 | ||
| 	{
 | ||
| 	  Handler *handler = handler_new (signal_id, instance, after);
 | ||
| 
 | ||
|           if (G_TYPE_IS_OBJECT (node->itype))
 | ||
|             _g_object_set_has_signal_handler ((GObject *) instance, signal_id);
 | ||
| 
 | ||
|           handler_seq_no = handler->sequential_number;
 | ||
| 	  handler->detail = detail;
 | ||
| 	  handler->closure = g_closure_ref (closure);
 | ||
| 	  g_closure_sink (closure);
 | ||
| 	  add_invalid_closure_notify (handler, instance);
 | ||
| 	  handler_insert (signal_id, instance, handler);
 | ||
| 	  if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (handler->closure))
 | ||
| 	    {
 | ||
| 	      g_closure_set_marshal (handler->closure, node->c_marshaller);
 | ||
| 	      if (node->va_marshaller)
 | ||
| 		_g_closure_set_va_marshal (handler->closure, node->va_marshaller);
 | ||
| 	    }
 | ||
| 	}
 | ||
|     }
 | ||
|   else
 | ||
|     g_critical ("%s: signal '%s' is invalid for instance '%p' of type '%s'",
 | ||
|                 G_STRLOC, detailed_signal, instance, g_type_name (itype));
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|   return handler_seq_no;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| node_check_deprecated (const SignalNode *node)
 | ||
| {
 | ||
|   static const gchar * g_enable_diagnostic = NULL;
 | ||
| 
 | ||
|   if (G_UNLIKELY (!g_enable_diagnostic))
 | ||
|     {
 | ||
|       g_enable_diagnostic = g_getenv ("G_ENABLE_DIAGNOSTIC");
 | ||
|       if (!g_enable_diagnostic)
 | ||
|         g_enable_diagnostic = "0";
 | ||
|     }
 | ||
| 
 | ||
|   if (g_enable_diagnostic[0] == '1')
 | ||
|     {
 | ||
|       if (node->flags & G_SIGNAL_DEPRECATED)
 | ||
|         {
 | ||
|           g_warning ("The signal %s::%s is deprecated and shouldn't be used "
 | ||
|                      "anymore. It will be removed in a future version.",
 | ||
|                      type_debug_name (node->itype), node->name);
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_connect_data:
 | ||
|  * @instance: (type GObject.Object): the instance to connect to.
 | ||
|  * @detailed_signal: a string of the form "signal-name::detail".
 | ||
|  * @c_handler: (not nullable): the #GCallback to connect.
 | ||
|  * @data: (nullable) (closure c_handler): data to pass to @c_handler calls.
 | ||
|  * @destroy_data: (nullable) (destroy data): a #GClosureNotify for @data.
 | ||
|  * @connect_flags: a combination of #GConnectFlags.
 | ||
|  *
 | ||
|  * Connects a #GCallback function to a signal for a particular object. Similar
 | ||
|  * to g_signal_connect(), but allows to provide a #GClosureNotify for the data
 | ||
|  * which will be called when the signal handler is disconnected and no longer
 | ||
|  * used. Specify @connect_flags if you need `..._after()` or
 | ||
|  * `..._swapped()` variants of this function.
 | ||
|  *
 | ||
|  * This function cannot fail. If the given signal name doesn’t exist,
 | ||
|  * a critical warning is emitted. No validation is performed on the
 | ||
|  * ‘detail’ string when specified in @detailed_signal, other than a
 | ||
|  * non-empty check.
 | ||
|  *
 | ||
|  * Refer to the [signals documentation](signals.html) for more
 | ||
|  * details.
 | ||
|  *
 | ||
|  * Returns: the handler ID (always greater than 0)
 | ||
|  */
 | ||
| gulong
 | ||
| g_signal_connect_data (gpointer       instance,
 | ||
| 		       const gchar   *detailed_signal,
 | ||
| 		       GCallback      c_handler,
 | ||
| 		       gpointer       data,
 | ||
| 		       GClosureNotify destroy_data,
 | ||
| 		       GConnectFlags  connect_flags)
 | ||
| {
 | ||
|   guint signal_id;
 | ||
|   gulong handler_seq_no = 0;
 | ||
|   GQuark detail = 0;
 | ||
|   GType itype;
 | ||
|   gboolean swapped, after;
 | ||
|   
 | ||
|   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
 | ||
|   g_return_val_if_fail (detailed_signal != NULL, 0);
 | ||
|   g_return_val_if_fail (c_handler != NULL, 0);
 | ||
| 
 | ||
|   swapped = (connect_flags & G_CONNECT_SWAPPED) != FALSE;
 | ||
|   after = (connect_flags & G_CONNECT_AFTER) != FALSE;
 | ||
| 
 | ||
|   SIGNAL_LOCK ();
 | ||
|   itype = G_TYPE_FROM_INSTANCE (instance);
 | ||
|   signal_id = signal_parse_name (detailed_signal, itype, &detail, TRUE);
 | ||
|   if (signal_id)
 | ||
|     {
 | ||
|       SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
| 
 | ||
|       node_check_deprecated (node);
 | ||
| 
 | ||
|       if (detail && !(node->flags & G_SIGNAL_DETAILED))
 | ||
| 	g_critical ("%s: signal '%s' does not support details", G_STRLOC, detailed_signal);
 | ||
|       else if (!g_type_is_a (itype, node->itype))
 | ||
|         g_critical ("%s: signal '%s' is invalid for instance '%p' of type '%s'",
 | ||
|                     G_STRLOC, detailed_signal, instance, g_type_name (itype));
 | ||
|       else
 | ||
| 	{
 | ||
| 	  Handler *handler = handler_new (signal_id, instance, after);
 | ||
| 
 | ||
|           if (G_TYPE_IS_OBJECT (node->itype))
 | ||
|             _g_object_set_has_signal_handler ((GObject *) instance, signal_id);
 | ||
| 
 | ||
| 	  handler_seq_no = handler->sequential_number;
 | ||
| 	  handler->detail = detail;
 | ||
| 	  handler->closure = g_closure_ref ((swapped ? g_cclosure_new_swap : g_cclosure_new) (c_handler, data, destroy_data));
 | ||
| 	  g_closure_sink (handler->closure);
 | ||
| 	  handler_insert (signal_id, instance, handler);
 | ||
| 	  if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (handler->closure))
 | ||
| 	    {
 | ||
| 	      g_closure_set_marshal (handler->closure, node->c_marshaller);
 | ||
| 	      if (node->va_marshaller)
 | ||
| 		_g_closure_set_va_marshal (handler->closure, node->va_marshaller);
 | ||
| 	    }
 | ||
|         }
 | ||
|     }
 | ||
|   else
 | ||
|     g_critical ("%s: signal '%s' is invalid for instance '%p' of type '%s'",
 | ||
|                 G_STRLOC, detailed_signal, instance, g_type_name (itype));
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|   return handler_seq_no;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| signal_handler_block_unlocked (gpointer instance,
 | ||
|                                gulong   handler_id);
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_handler_block:
 | ||
|  * @instance: (type GObject.Object): The instance to block the signal handler of.
 | ||
|  * @handler_id: Handler id of the handler to be blocked.
 | ||
|  *
 | ||
|  * Blocks a handler of an instance so it will not be called during any
 | ||
|  * signal emissions unless it is unblocked again. Thus "blocking" a
 | ||
|  * signal handler means to temporarily deactivate it, a signal handler
 | ||
|  * has to be unblocked exactly the same amount of times it has been
 | ||
|  * blocked before to become active again.
 | ||
|  *
 | ||
|  * The @handler_id has to be a valid signal handler id, connected to a
 | ||
|  * signal of @instance.
 | ||
|  */
 | ||
| void
 | ||
| g_signal_handler_block (gpointer instance,
 | ||
|                         gulong   handler_id)
 | ||
| {
 | ||
|   g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
 | ||
|   g_return_if_fail (handler_id > 0);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   signal_handler_block_unlocked (instance, handler_id);
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| signal_handler_block_unlocked (gpointer instance,
 | ||
|                                gulong   handler_id)
 | ||
| {
 | ||
|   Handler *handler;
 | ||
| 
 | ||
|   handler = handler_lookup (instance, handler_id, NULL, NULL);
 | ||
|   if (handler)
 | ||
|     {
 | ||
| #ifndef G_DISABLE_CHECKS
 | ||
|       if (handler->block_count >= HANDLER_MAX_BLOCK_COUNT - 1)
 | ||
|         g_error (G_STRLOC ": handler block_count overflow, %s", REPORT_BUG);
 | ||
| #endif
 | ||
|       handler->block_count += 1;
 | ||
|     }
 | ||
|   else
 | ||
|     g_critical ("%s: instance '%p' has no handler with id '%lu'", G_STRLOC, instance, handler_id);
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| signal_handler_unblock_unlocked (gpointer instance,
 | ||
|                                  gulong   handler_id);
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_handler_unblock:
 | ||
|  * @instance: (type GObject.Object): The instance to unblock the signal handler of.
 | ||
|  * @handler_id: Handler id of the handler to be unblocked.
 | ||
|  *
 | ||
|  * Undoes the effect of a previous g_signal_handler_block() call.  A
 | ||
|  * blocked handler is skipped during signal emissions and will not be
 | ||
|  * invoked, unblocking it (for exactly the amount of times it has been
 | ||
|  * blocked before) reverts its "blocked" state, so the handler will be
 | ||
|  * recognized by the signal system and is called upon future or
 | ||
|  * currently ongoing signal emissions (since the order in which
 | ||
|  * handlers are called during signal emissions is deterministic,
 | ||
|  * whether the unblocked handler in question is called as part of a
 | ||
|  * currently ongoing emission depends on how far that emission has
 | ||
|  * proceeded yet).
 | ||
|  *
 | ||
|  * The @handler_id has to be a valid id of a signal handler that is
 | ||
|  * connected to a signal of @instance and is currently blocked.
 | ||
|  */
 | ||
| void
 | ||
| g_signal_handler_unblock (gpointer instance,
 | ||
|                           gulong   handler_id)
 | ||
| {
 | ||
|   g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
 | ||
|   g_return_if_fail (handler_id > 0);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   signal_handler_unblock_unlocked (instance, handler_id);
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| signal_handler_unblock_unlocked (gpointer instance,
 | ||
|                                  gulong   handler_id)
 | ||
| {
 | ||
|   Handler *handler;
 | ||
| 
 | ||
|   handler = handler_lookup (instance, handler_id, NULL, NULL);
 | ||
|   if (handler)
 | ||
|     {
 | ||
|       if (handler->block_count)
 | ||
|         handler->block_count -= 1;
 | ||
|       else
 | ||
|         g_critical (G_STRLOC ": handler '%lu' of instance '%p' is not blocked", handler_id, instance);
 | ||
|     }
 | ||
|   else
 | ||
|     g_critical ("%s: instance '%p' has no handler with id '%lu'", G_STRLOC, instance, handler_id);
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| signal_handler_disconnect_unlocked (gpointer instance,
 | ||
|                                     gulong   handler_id);
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_handler_disconnect:
 | ||
|  * @instance: (type GObject.Object): The instance to remove the signal handler from.
 | ||
|  * @handler_id: Handler id of the handler to be disconnected.
 | ||
|  *
 | ||
|  * Disconnects a handler from an instance so it will not be called during
 | ||
|  * any future or currently ongoing emissions of the signal it has been
 | ||
|  * connected to. The @handler_id becomes invalid and may be reused.
 | ||
|  *
 | ||
|  * The @handler_id has to be a valid signal handler id, connected to a
 | ||
|  * signal of @instance.
 | ||
|  */
 | ||
| void
 | ||
| g_signal_handler_disconnect (gpointer instance,
 | ||
|                              gulong   handler_id)
 | ||
| {
 | ||
|   g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
 | ||
|   g_return_if_fail (handler_id > 0);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   signal_handler_disconnect_unlocked (instance, handler_id);
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| signal_handler_disconnect_unlocked (gpointer instance,
 | ||
|                                     gulong   handler_id)
 | ||
| {
 | ||
|   Handler *handler;
 | ||
| 
 | ||
|   handler = handler_lookup (instance, handler_id, 0, 0);
 | ||
|   if (handler)
 | ||
|     {
 | ||
|       g_hash_table_remove (g_handlers, handler);
 | ||
|       handler->sequential_number = 0;
 | ||
|       handler->block_count = 1;
 | ||
|       remove_invalid_closure_notify (handler, instance);
 | ||
|       handler_unref_R (handler->signal_id, instance, handler);
 | ||
|     }
 | ||
|   else
 | ||
|     g_critical ("%s: instance '%p' has no handler with id '%lu'", G_STRLOC, instance, handler_id);
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_handler_is_connected:
 | ||
|  * @instance: (type GObject.Object): The instance where a signal handler is sought.
 | ||
|  * @handler_id: the handler ID.
 | ||
|  *
 | ||
|  * Returns whether @handler_id is the ID of a handler connected to @instance.
 | ||
|  *
 | ||
|  * Returns: whether @handler_id identifies a handler connected to @instance.
 | ||
|  */
 | ||
| gboolean
 | ||
| g_signal_handler_is_connected (gpointer instance,
 | ||
| 			       gulong   handler_id)
 | ||
| {
 | ||
|   Handler *handler;
 | ||
|   gboolean connected;
 | ||
| 
 | ||
|   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), FALSE);
 | ||
| 
 | ||
|   SIGNAL_LOCK ();
 | ||
|   handler = handler_lookup (instance, handler_id, NULL, NULL);
 | ||
|   connected = handler != NULL;
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|   return connected;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_handlers_destroy:
 | ||
|  * @instance: (type GObject.Object): The instance whose signal handlers are destroyed
 | ||
|  *
 | ||
|  * Destroy all signal handlers of a type instance. This function is
 | ||
|  * an implementation detail of the #GObject dispose implementation,
 | ||
|  * and should not be used outside of the type system.
 | ||
|  */
 | ||
| void
 | ||
| g_signal_handlers_destroy (gpointer instance)
 | ||
| {
 | ||
|   GBSearchArray *hlbsa;
 | ||
|   
 | ||
|   g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
|   hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
 | ||
|   if (hlbsa)
 | ||
|     {
 | ||
|       guint i;
 | ||
|       
 | ||
|       /* reentrancy caution, delete instance trace first */
 | ||
|       g_hash_table_remove (g_handler_list_bsa_ht, instance);
 | ||
|       
 | ||
|       for (i = 0; i < hlbsa->n_nodes; i++)
 | ||
|         {
 | ||
|           HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, &g_signal_hlbsa_bconfig, i);
 | ||
|           Handler *handler = hlist->handlers;
 | ||
| 	  
 | ||
|           while (handler)
 | ||
|             {
 | ||
|               Handler *tmp = handler;
 | ||
| 	      
 | ||
|               handler = tmp->next;
 | ||
|               tmp->block_count = 1;
 | ||
|               /* cruel unlink, this works because _all_ handlers vanish */
 | ||
|               tmp->next = NULL;
 | ||
|               tmp->prev = tmp;
 | ||
|               if (tmp->sequential_number)
 | ||
| 		{
 | ||
|                   g_hash_table_remove (g_handlers, tmp);
 | ||
| 		  remove_invalid_closure_notify (tmp, instance);
 | ||
| 		  tmp->sequential_number = 0;
 | ||
| 		  handler_unref_R (0, NULL, tmp);
 | ||
| 		}
 | ||
|             }
 | ||
|         }
 | ||
|       g_bsearch_array_free (hlbsa, &g_signal_hlbsa_bconfig);
 | ||
|     }
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_handler_find:
 | ||
|  * @instance: (type GObject.Object): The instance owning the signal handler to be found.
 | ||
|  * @mask: Mask indicating which of @signal_id, @detail, @closure, @func
 | ||
|  *  and/or @data the handler has to match.
 | ||
|  * @signal_id: Signal the handler has to be connected to.
 | ||
|  * @detail: Signal detail the handler has to be connected to.
 | ||
|  * @closure: (nullable): The closure the handler will invoke.
 | ||
|  * @func: The C closure callback of the handler (useless for non-C closures).
 | ||
|  * @data: (nullable) (closure closure): The closure data of the handler's closure.
 | ||
|  *
 | ||
|  * Finds the first signal handler that matches certain selection criteria.
 | ||
|  * The criteria mask is passed as an OR-ed combination of #GSignalMatchType
 | ||
|  * flags, and the criteria values are passed as arguments.
 | ||
|  * The match @mask has to be non-0 for successful matches.
 | ||
|  * If no handler was found, 0 is returned.
 | ||
|  *
 | ||
|  * Returns: A valid non-0 signal handler id for a successful match.
 | ||
|  */
 | ||
| gulong
 | ||
| g_signal_handler_find (gpointer         instance,
 | ||
|                        GSignalMatchType mask,
 | ||
|                        guint            signal_id,
 | ||
| 		       GQuark		detail,
 | ||
|                        GClosure        *closure,
 | ||
|                        gpointer         func,
 | ||
|                        gpointer         data)
 | ||
| {
 | ||
|   gulong handler_seq_no = 0;
 | ||
|   
 | ||
|   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
 | ||
|   g_return_val_if_fail ((mask & (unsigned) ~G_SIGNAL_MATCH_MASK) == 0, 0);
 | ||
|   
 | ||
|   if (mask & G_SIGNAL_MATCH_MASK)
 | ||
|     {
 | ||
|       HandlerMatch *mlist;
 | ||
|       
 | ||
|       SIGNAL_LOCK ();
 | ||
|       mlist = handlers_find (instance, mask, signal_id, detail, closure, func, data, TRUE);
 | ||
|       if (mlist)
 | ||
| 	{
 | ||
| 	  handler_seq_no = mlist->handler->sequential_number;
 | ||
| 	  handler_match_free1_R (mlist, instance);
 | ||
| 	}
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|     }
 | ||
|   
 | ||
|   return handler_seq_no;
 | ||
| }
 | ||
| 
 | ||
| typedef void (*CallbackHandlerFunc) (gpointer instance, gulong handler_seq_no);
 | ||
| 
 | ||
| static guint
 | ||
| signal_handlers_foreach_matched_unlocked_R (gpointer             instance,
 | ||
|                                             GSignalMatchType     mask,
 | ||
|                                             guint                signal_id,
 | ||
|                                             GQuark               detail,
 | ||
|                                             GClosure            *closure,
 | ||
|                                             gpointer             func,
 | ||
|                                             gpointer             data,
 | ||
|                                             CallbackHandlerFunc  callback)
 | ||
| {
 | ||
|   HandlerMatch *mlist;
 | ||
|   guint n_handlers = 0;
 | ||
| 
 | ||
|   mlist = handlers_find (instance, mask, signal_id, detail, closure, func, data, FALSE);
 | ||
|   while (mlist)
 | ||
|     {
 | ||
|       n_handlers++;
 | ||
|       if (mlist->handler->sequential_number)
 | ||
|         callback (instance, mlist->handler->sequential_number);
 | ||
| 
 | ||
|       mlist = handler_match_free1_R (mlist, instance);
 | ||
|     }
 | ||
| 
 | ||
|   return n_handlers;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_handlers_block_matched:
 | ||
|  * @instance: (type GObject.Object): The instance to block handlers from.
 | ||
|  * @mask: Mask indicating which of @signal_id, @detail, @closure, @func
 | ||
|  *  and/or @data the handlers have to match.
 | ||
|  * @signal_id: Signal the handlers have to be connected to.
 | ||
|  * @detail: Signal detail the handlers have to be connected to.
 | ||
|  * @closure: (nullable): The closure the handlers will invoke.
 | ||
|  * @func: The C closure callback of the handlers (useless for non-C closures).
 | ||
|  * @data: (nullable) (closure closure): The closure data of the handlers' closures.
 | ||
|  *
 | ||
|  * Blocks all handlers on an instance that match a certain selection criteria.
 | ||
|  *
 | ||
|  * The criteria mask is passed as a combination of #GSignalMatchType flags, and
 | ||
|  * the criteria values are passed as arguments. A handler must match on all
 | ||
|  * flags set in @mask to be blocked (i.e. the match is conjunctive).
 | ||
|  *
 | ||
|  * Passing at least one of the %G_SIGNAL_MATCH_ID, %G_SIGNAL_MATCH_CLOSURE,
 | ||
|  * %G_SIGNAL_MATCH_FUNC
 | ||
|  * or %G_SIGNAL_MATCH_DATA match flags is required for successful matches.
 | ||
|  * If no handlers were found, 0 is returned, the number of blocked handlers
 | ||
|  * otherwise.
 | ||
|  *
 | ||
|  * Support for %G_SIGNAL_MATCH_ID was added in GLib 2.78.
 | ||
|  *
 | ||
|  * Returns: The number of handlers that matched.
 | ||
|  */
 | ||
| guint
 | ||
| g_signal_handlers_block_matched (gpointer         instance,
 | ||
| 				 GSignalMatchType mask,
 | ||
| 				 guint            signal_id,
 | ||
| 				 GQuark           detail,
 | ||
| 				 GClosure        *closure,
 | ||
| 				 gpointer         func,
 | ||
| 				 gpointer         data)
 | ||
| {
 | ||
|   guint n_handlers = 0;
 | ||
|   
 | ||
|   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
 | ||
|   g_return_val_if_fail ((mask & (unsigned) ~G_SIGNAL_MATCH_MASK) == 0, 0);
 | ||
|   
 | ||
|   if (mask & (G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_CLOSURE | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA))
 | ||
|     {
 | ||
|       SIGNAL_LOCK ();
 | ||
|       n_handlers =
 | ||
|         signal_handlers_foreach_matched_unlocked_R (instance, mask, signal_id, detail,
 | ||
|                                                     closure, func, data,
 | ||
|                                                     signal_handler_block_unlocked);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|     }
 | ||
|   
 | ||
|   return n_handlers;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_handlers_unblock_matched:
 | ||
|  * @instance: (type GObject.Object): The instance to unblock handlers from.
 | ||
|  * @mask: Mask indicating which of @signal_id, @detail, @closure, @func
 | ||
|  *  and/or @data the handlers have to match.
 | ||
|  * @signal_id: Signal the handlers have to be connected to.
 | ||
|  * @detail: Signal detail the handlers have to be connected to.
 | ||
|  * @closure: (nullable): The closure the handlers will invoke.
 | ||
|  * @func: The C closure callback of the handlers (useless for non-C closures).
 | ||
|  * @data: (nullable) (closure closure): The closure data of the handlers' closures.
 | ||
|  *
 | ||
|  * Unblocks all handlers on an instance that match a certain selection
 | ||
|  * criteria.
 | ||
|  *
 | ||
|  * The criteria mask is passed as a combination of #GSignalMatchType flags, and
 | ||
|  * the criteria values are passed as arguments. A handler must match on all
 | ||
|  * flags set in @mask to be unblocked (i.e. the match is conjunctive).
 | ||
|  *
 | ||
|  * Passing at least one of the %G_SIGNAL_MATCH_ID, %G_SIGNAL_MATCH_CLOSURE,
 | ||
|  * %G_SIGNAL_MATCH_FUNC
 | ||
|  * or %G_SIGNAL_MATCH_DATA match flags is required for successful matches.
 | ||
|  * If no handlers were found, 0 is returned, the number of unblocked handlers
 | ||
|  * otherwise. The match criteria should not apply to any handlers that are
 | ||
|  * not currently blocked.
 | ||
|  *
 | ||
|  * Support for %G_SIGNAL_MATCH_ID was added in GLib 2.78.
 | ||
|  *
 | ||
|  * Returns: The number of handlers that matched.
 | ||
|  */
 | ||
| guint
 | ||
| g_signal_handlers_unblock_matched (gpointer         instance,
 | ||
| 				   GSignalMatchType mask,
 | ||
| 				   guint            signal_id,
 | ||
| 				   GQuark           detail,
 | ||
| 				   GClosure        *closure,
 | ||
| 				   gpointer         func,
 | ||
| 				   gpointer         data)
 | ||
| {
 | ||
|   guint n_handlers = 0;
 | ||
|   
 | ||
|   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
 | ||
|   g_return_val_if_fail ((mask & (unsigned) ~G_SIGNAL_MATCH_MASK) == 0, 0);
 | ||
|   
 | ||
|   if (mask & (G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_CLOSURE | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA))
 | ||
|     {
 | ||
|       SIGNAL_LOCK ();
 | ||
|       n_handlers =
 | ||
|         signal_handlers_foreach_matched_unlocked_R (instance, mask, signal_id, detail,
 | ||
|                                                     closure, func, data,
 | ||
|                                                     signal_handler_unblock_unlocked);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|     }
 | ||
|   
 | ||
|   return n_handlers;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_handlers_disconnect_matched:
 | ||
|  * @instance: (type GObject.Object): The instance to remove handlers from.
 | ||
|  * @mask: Mask indicating which of @signal_id, @detail, @closure, @func
 | ||
|  *  and/or @data the handlers have to match.
 | ||
|  * @signal_id: Signal the handlers have to be connected to.
 | ||
|  * @detail: Signal detail the handlers have to be connected to.
 | ||
|  * @closure: (nullable): The closure the handlers will invoke.
 | ||
|  * @func: The C closure callback of the handlers (useless for non-C closures).
 | ||
|  * @data: (nullable) (closure closure): The closure data of the handlers' closures.
 | ||
|  *
 | ||
|  * Disconnects all handlers on an instance that match a certain
 | ||
|  * selection criteria.
 | ||
|  *
 | ||
|  * The criteria mask is passed as a combination of #GSignalMatchType flags, and
 | ||
|  * the criteria values are passed as arguments. A handler must match on all
 | ||
|  * flags set in @mask to be disconnected (i.e. the match is conjunctive).
 | ||
|  *
 | ||
|  * Passing at least one of the %G_SIGNAL_MATCH_ID, %G_SIGNAL_MATCH_CLOSURE,
 | ||
|  * %G_SIGNAL_MATCH_FUNC or
 | ||
|  * %G_SIGNAL_MATCH_DATA match flags is required for successful
 | ||
|  * matches.  If no handlers were found, 0 is returned, the number of
 | ||
|  * disconnected handlers otherwise.
 | ||
|  *
 | ||
|  * Support for %G_SIGNAL_MATCH_ID was added in GLib 2.78.
 | ||
|  *
 | ||
|  * Returns: The number of handlers that matched.
 | ||
|  */
 | ||
| guint
 | ||
| g_signal_handlers_disconnect_matched (gpointer         instance,
 | ||
| 				      GSignalMatchType mask,
 | ||
| 				      guint            signal_id,
 | ||
| 				      GQuark           detail,
 | ||
| 				      GClosure        *closure,
 | ||
| 				      gpointer         func,
 | ||
| 				      gpointer         data)
 | ||
| {
 | ||
|   guint n_handlers = 0;
 | ||
|   
 | ||
|   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
 | ||
|   g_return_val_if_fail ((mask & (unsigned) ~G_SIGNAL_MATCH_MASK) == 0, 0);
 | ||
|   
 | ||
|   if (mask & (G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_CLOSURE | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA))
 | ||
|     {
 | ||
|       SIGNAL_LOCK ();
 | ||
|       n_handlers =
 | ||
|         signal_handlers_foreach_matched_unlocked_R (instance, mask, signal_id, detail,
 | ||
|                                                     closure, func, data,
 | ||
|                                                     signal_handler_disconnect_unlocked);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|     }
 | ||
|   
 | ||
|   return n_handlers;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_has_handler_pending:
 | ||
|  * @instance: (type GObject.Object): the object whose signal handlers are sought.
 | ||
|  * @signal_id: the signal id.
 | ||
|  * @detail: the detail.
 | ||
|  * @may_be_blocked: whether blocked handlers should count as match.
 | ||
|  *
 | ||
|  * Returns whether there are any handlers connected to @instance for the
 | ||
|  * given signal id and detail.
 | ||
|  *
 | ||
|  * If @detail is 0 then it will only match handlers that were connected
 | ||
|  * without detail.  If @detail is non-zero then it will match handlers
 | ||
|  * connected both without detail and with the given detail.  This is
 | ||
|  * consistent with how a signal emitted with @detail would be delivered
 | ||
|  * to those handlers.
 | ||
|  *
 | ||
|  * Since 2.46 this also checks for a non-default class closure being
 | ||
|  * installed, as this is basically always what you want.
 | ||
|  *
 | ||
|  * One example of when you might use this is when the arguments to the
 | ||
|  * signal are difficult to compute. A class implementor may opt to not
 | ||
|  * emit the signal if no one is attached anyway, thus saving the cost
 | ||
|  * of building the arguments.
 | ||
|  *
 | ||
|  * Returns: %TRUE if a handler is connected to the signal, %FALSE
 | ||
|  *          otherwise.
 | ||
|  */
 | ||
| gboolean
 | ||
| g_signal_has_handler_pending (gpointer instance,
 | ||
| 			      guint    signal_id,
 | ||
| 			      GQuark   detail,
 | ||
| 			      gboolean may_be_blocked)
 | ||
| {
 | ||
|   HandlerMatch *mlist;
 | ||
|   gboolean has_pending;
 | ||
|   SignalNode *node;
 | ||
|   
 | ||
|   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), FALSE);
 | ||
|   g_return_val_if_fail (signal_id > 0, FALSE);
 | ||
|   
 | ||
|   SIGNAL_LOCK ();
 | ||
| 
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   if (detail)
 | ||
|     {
 | ||
|       if (!(node->flags & G_SIGNAL_DETAILED))
 | ||
| 	{
 | ||
| 	  g_critical ("%s: signal id '%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
 | ||
| 	  SIGNAL_UNLOCK ();
 | ||
| 	  return FALSE;
 | ||
| 	}
 | ||
|     }
 | ||
|   mlist = handlers_find (instance,
 | ||
| 			 (G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | (may_be_blocked ? 0 : G_SIGNAL_MATCH_UNBLOCKED)),
 | ||
| 			 signal_id, detail, NULL, NULL, NULL, TRUE);
 | ||
|   if (mlist)
 | ||
|     {
 | ||
|       has_pending = TRUE;
 | ||
|       handler_match_free1_R (mlist, instance);
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       ClassClosure *class_closure = signal_find_class_closure (node, G_TYPE_FROM_INSTANCE (instance));
 | ||
|       if (class_closure != NULL && class_closure->instance_type != 0)
 | ||
|         has_pending = TRUE;
 | ||
|       else
 | ||
|         has_pending = FALSE;
 | ||
|     }
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|   return has_pending;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| signal_emitv_unlocked (const GValue *instance_and_params,
 | ||
|                        guint         signal_id,
 | ||
|                        GQuark        detail,
 | ||
|                        GValue       *return_value);
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_emitv:
 | ||
|  * @instance_and_params: (array): argument list for the signal emission.
 | ||
|  *  The first element in the array is a #GValue for the instance the signal
 | ||
|  *  is being emitted on. The rest are any arguments to be passed to the signal.
 | ||
|  * @signal_id: the signal id
 | ||
|  * @detail: the detail
 | ||
|  * @return_value: (inout) (optional): Location to
 | ||
|  * store the return value of the signal emission. This must be provided if the
 | ||
|  * specified signal returns a value, but may be ignored otherwise.
 | ||
|  *
 | ||
|  * Emits a signal. Signal emission is done synchronously.
 | ||
|  * The method will only return control after all handlers are called or signal emission was stopped.
 | ||
|  *
 | ||
|  * Note that g_signal_emitv() doesn't change @return_value if no handlers are
 | ||
|  * connected, in contrast to g_signal_emit() and g_signal_emit_valist().
 | ||
|  */
 | ||
| void
 | ||
| g_signal_emitv (const GValue *instance_and_params,
 | ||
| 		guint         signal_id,
 | ||
| 		GQuark	      detail,
 | ||
| 		GValue       *return_value)
 | ||
| {
 | ||
|   SIGNAL_LOCK ();
 | ||
|   signal_emitv_unlocked (instance_and_params, signal_id, detail, return_value);
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| signal_emitv_unlocked (const GValue *instance_and_params,
 | ||
|                        guint         signal_id,
 | ||
|                        GQuark        detail,
 | ||
|                        GValue       *return_value)
 | ||
| {
 | ||
|   gpointer instance;
 | ||
|   SignalNode *node;
 | ||
| #ifdef G_ENABLE_DEBUG
 | ||
|   const GValue *param_values;
 | ||
|   guint i;
 | ||
| #endif
 | ||
|   
 | ||
|   g_return_if_fail (instance_and_params != NULL);
 | ||
|   instance = g_value_peek_pointer (instance_and_params);
 | ||
|   g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
 | ||
|   g_return_if_fail (signal_id > 0);
 | ||
| 
 | ||
| #ifdef G_ENABLE_DEBUG
 | ||
|   param_values = instance_and_params + 1;
 | ||
| #endif
 | ||
| 
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   if (!node || !g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype))
 | ||
|     {
 | ||
|       g_critical ("%s: signal id '%u' is invalid for instance '%p'", G_STRLOC, signal_id, instance);
 | ||
|       return;
 | ||
|     }
 | ||
| #ifdef G_ENABLE_DEBUG
 | ||
|   if (detail && !(node->flags & G_SIGNAL_DETAILED))
 | ||
|     {
 | ||
|       g_critical ("%s: signal id '%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
 | ||
|       return;
 | ||
|     }
 | ||
|   for (i = 0; i < node->n_params; i++)
 | ||
|     if (!G_TYPE_CHECK_VALUE_TYPE (param_values + i, node->param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE))
 | ||
|       {
 | ||
| 	g_critical ("%s: value for '%s' parameter %u for signal \"%s\" is of type '%s'",
 | ||
| 		    G_STRLOC,
 | ||
| 		    type_debug_name (node->param_types[i]),
 | ||
| 		    i,
 | ||
| 		    node->name,
 | ||
| 		    G_VALUE_TYPE_NAME (param_values + i));
 | ||
| 	return;
 | ||
|       }
 | ||
|   if (node->return_type != G_TYPE_NONE)
 | ||
|     {
 | ||
|       if (!return_value)
 | ||
| 	{
 | ||
| 	  g_critical ("%s: return value '%s' for signal \"%s\" is (NULL)",
 | ||
| 		      G_STRLOC,
 | ||
| 		      type_debug_name (node->return_type),
 | ||
| 		      node->name);
 | ||
| 	  return;
 | ||
| 	}
 | ||
|       else if (!node->accumulator && !G_TYPE_CHECK_VALUE_TYPE (return_value, node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE))
 | ||
| 	{
 | ||
| 	  g_critical ("%s: return value '%s' for signal \"%s\" is of type '%s'",
 | ||
| 		      G_STRLOC,
 | ||
| 		      type_debug_name (node->return_type),
 | ||
| 		      node->name,
 | ||
| 		      G_VALUE_TYPE_NAME (return_value));
 | ||
| 	  return;
 | ||
| 	}
 | ||
|     }
 | ||
|   else
 | ||
|     return_value = NULL;
 | ||
| #endif	/* G_ENABLE_DEBUG */
 | ||
| 
 | ||
|   /* optimize NOP emissions */
 | ||
|   if (!node->single_va_closure_is_valid)
 | ||
|     node_update_single_va_closure (node);
 | ||
| 
 | ||
|   if (node->single_va_closure != NULL &&
 | ||
|       (node->single_va_closure == SINGLE_VA_CLOSURE_EMPTY_MAGIC ||
 | ||
|        _g_closure_is_void (node->single_va_closure, instance)))
 | ||
|     {
 | ||
|       HandlerList* hlist;
 | ||
| 
 | ||
|       /* single_va_closure is only true for GObjects, so fast path if no handler ever connected to the signal */
 | ||
|       if (_g_object_has_signal_handler ((GObject *)instance))
 | ||
|         hlist = handler_list_lookup (node->signal_id, instance);
 | ||
|       else
 | ||
|         hlist = NULL;
 | ||
| 
 | ||
|       if (hlist == NULL || hlist->handlers == NULL)
 | ||
| 	{
 | ||
| 	  /* nothing to do to emit this signal */
 | ||
| 	  /* g_printerr ("omitting emission of \"%s\"\n", node->name); */
 | ||
| 	  return;
 | ||
| 	}
 | ||
|     }
 | ||
| 
 | ||
|   /* Pass a stable node pointer, whose address can't change even if the
 | ||
|    * g_signal_nodes array gets reallocated. */
 | ||
|   SignalNode node_copy = *node;
 | ||
|   signal_emit_unlocked_R (&node_copy, detail, instance, return_value, instance_and_params);
 | ||
| }
 | ||
| 
 | ||
| static inline gboolean
 | ||
| accumulate (GSignalInvocationHint *ihint,
 | ||
| 	    GValue                *return_accu,
 | ||
| 	    GValue	          *handler_return,
 | ||
| 	    SignalAccumulator     *accumulator)
 | ||
| {
 | ||
|   gboolean continue_emission;
 | ||
| 
 | ||
|   if (!accumulator)
 | ||
|     return TRUE;
 | ||
| 
 | ||
|   continue_emission = accumulator->func (ihint, return_accu, handler_return, accumulator->data);
 | ||
|   g_value_reset (handler_return);
 | ||
| 
 | ||
|   ihint->run_type &= (unsigned) ~G_SIGNAL_ACCUMULATOR_FIRST_RUN;
 | ||
| 
 | ||
|   return continue_emission;
 | ||
| }
 | ||
| 
 | ||
| static gboolean
 | ||
| signal_emit_valist_unlocked (gpointer instance,
 | ||
|                              guint    signal_id,
 | ||
|                              GQuark   detail,
 | ||
|                              va_list  var_args);
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_emit_valist: (skip)
 | ||
|  * @instance: (type GObject.TypeInstance): the instance the signal is being
 | ||
|  *    emitted on.
 | ||
|  * @signal_id: the signal id
 | ||
|  * @detail: the detail
 | ||
|  * @var_args: a list of parameters to be passed to the signal, followed by a
 | ||
|  *  location for the return value. If the return type of the signal
 | ||
|  *  is %G_TYPE_NONE, the return value location can be omitted.
 | ||
|  *
 | ||
|  * Emits a signal. Signal emission is done synchronously.
 | ||
|  * The method will only return control after all handlers are called or signal emission was stopped.
 | ||
|  *
 | ||
|  * Note that g_signal_emit_valist() resets the return value to the default
 | ||
|  * if no handlers are connected, in contrast to g_signal_emitv().
 | ||
|  */
 | ||
| void
 | ||
| g_signal_emit_valist (gpointer instance,
 | ||
| 		      guint    signal_id,
 | ||
| 		      GQuark   detail,
 | ||
| 		      va_list  var_args)
 | ||
| {
 | ||
|   SIGNAL_LOCK ();
 | ||
|   if (signal_emit_valist_unlocked (instance, signal_id, detail, var_args))
 | ||
|     SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| /*<private>
 | ||
|  * signal_emit_valist_unlocked:
 | ||
|  * @instance: The instance to emit from
 | ||
|  * @signal_id: Signal id to emit
 | ||
|  * @detail: Signal detail
 | ||
|  * @var_args: Call arguments
 | ||
|  *
 | ||
|  * Returns: %TRUE if the signal mutex has been left locked
 | ||
|  */
 | ||
| static gboolean
 | ||
| signal_emit_valist_unlocked (gpointer instance,
 | ||
|                              guint    signal_id,
 | ||
|                              GQuark   detail,
 | ||
|                              va_list  var_args)
 | ||
| {
 | ||
|   GValue *instance_and_params;
 | ||
|   GValue *param_values;
 | ||
|   SignalNode *node;
 | ||
|   guint i;
 | ||
| 
 | ||
|   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), TRUE);
 | ||
|   g_return_val_if_fail (signal_id > 0, TRUE);
 | ||
| 
 | ||
|   node = LOOKUP_SIGNAL_NODE (signal_id);
 | ||
|   if (!node || !g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype))
 | ||
|     {
 | ||
|       g_critical ("%s: signal id '%u' is invalid for instance '%p'", G_STRLOC, signal_id, instance);
 | ||
|       return TRUE;
 | ||
|     }
 | ||
| #ifndef G_DISABLE_CHECKS
 | ||
|   if (detail && !(node->flags & G_SIGNAL_DETAILED))
 | ||
|     {
 | ||
|       g_critical ("%s: signal id '%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
 | ||
|       return TRUE;
 | ||
|     }
 | ||
| #endif  /* !G_DISABLE_CHECKS */
 | ||
| 
 | ||
|   if (!node->single_va_closure_is_valid)
 | ||
|     node_update_single_va_closure (node);
 | ||
| 
 | ||
|   /* There's no need to deep copy this, because a SignalNode instance won't
 | ||
|    * ever be destroyed, given that _g_signals_destroy() is not called in any
 | ||
|    * real program, however the SignalNode pointer could change, so just store
 | ||
|    * the struct contents references, so that we won't try to deference a
 | ||
|    * potentially invalid (or changed) pointer;
 | ||
|    */
 | ||
|   SignalNode node_copy = *node;
 | ||
| 
 | ||
|   if (node->single_va_closure != NULL)
 | ||
|     {
 | ||
|       HandlerList* hlist;
 | ||
|       Handler *fastpath_handler = NULL;
 | ||
|       Handler *l;
 | ||
|       GClosure *closure = NULL;
 | ||
|       gboolean fastpath = TRUE;
 | ||
|       GSignalFlags run_type = G_SIGNAL_RUN_FIRST;
 | ||
| 
 | ||
|       if (node->single_va_closure != SINGLE_VA_CLOSURE_EMPTY_MAGIC &&
 | ||
| 	  !_g_closure_is_void (node->single_va_closure, instance))
 | ||
| 	{
 | ||
| 	  if (_g_closure_supports_invoke_va (node->single_va_closure))
 | ||
| 	    {
 | ||
| 	      closure = node->single_va_closure;
 | ||
| 	      if (node->single_va_closure_is_after)
 | ||
| 		run_type = G_SIGNAL_RUN_LAST;
 | ||
| 	      else
 | ||
| 		run_type = G_SIGNAL_RUN_FIRST;
 | ||
| 	    }
 | ||
| 	  else
 | ||
| 	    fastpath = FALSE;
 | ||
| 	}
 | ||
| 
 | ||
|       /* single_va_closure is only true for GObjects, so fast path if no handler ever connected to the signal */
 | ||
|       if (_g_object_has_signal_handler ((GObject *)instance))
 | ||
|         hlist = handler_list_lookup (node->signal_id, instance);
 | ||
|       else
 | ||
|         hlist = NULL;
 | ||
| 
 | ||
|       for (l = hlist ? hlist->handlers : NULL; fastpath && l != NULL; l = l->next)
 | ||
| 	{
 | ||
| 	  if (!l->block_count &&
 | ||
| 	      (!l->detail || l->detail == detail))
 | ||
| 	    {
 | ||
| 	      if (closure != NULL || !_g_closure_supports_invoke_va (l->closure))
 | ||
| 		{
 | ||
| 		  fastpath = FALSE;
 | ||
| 		  break;
 | ||
| 		}
 | ||
| 	      else
 | ||
| 		{
 | ||
|                   fastpath_handler = l;
 | ||
| 		  closure = l->closure;
 | ||
| 		  if (l->after)
 | ||
| 		    run_type = G_SIGNAL_RUN_LAST;
 | ||
| 		  else
 | ||
| 		    run_type = G_SIGNAL_RUN_FIRST;
 | ||
| 		}
 | ||
| 	    }
 | ||
| 	}
 | ||
| 
 | ||
|       if (fastpath && closure == NULL && node_copy.return_type == G_TYPE_NONE)
 | ||
|         return TRUE;
 | ||
| 
 | ||
|       /* Don't allow no-recurse emission as we might have to restart, which means
 | ||
| 	 we will run multiple handlers and thus must ref all arguments */
 | ||
|       if (closure != NULL && (node_copy.flags & (G_SIGNAL_NO_RECURSE)) != 0)
 | ||
| 	fastpath = FALSE;
 | ||
|       
 | ||
|       if (fastpath)
 | ||
| 	{
 | ||
| 	  Emission emission;
 | ||
| 	  GValue *return_accu, accu = G_VALUE_INIT;
 | ||
| 	  GType instance_type = G_TYPE_FROM_INSTANCE (instance);
 | ||
| 	  GValue emission_return = G_VALUE_INIT;
 | ||
|           GType rtype = node_copy.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE;
 | ||
| 	  gboolean static_scope = node_copy.return_type & G_SIGNAL_TYPE_STATIC_SCOPE;
 | ||
| 
 | ||
| 	  if (rtype == G_TYPE_NONE)
 | ||
| 	    return_accu = NULL;
 | ||
| 	  else if (node_copy.accumulator)
 | ||
| 	    return_accu = &accu;
 | ||
| 	  else
 | ||
| 	    return_accu = &emission_return;
 | ||
| 
 | ||
| 	  emission.instance = instance;
 | ||
| 	  emission.ihint.signal_id = signal_id;
 | ||
| 	  emission.ihint.detail = detail;
 | ||
| 	  emission.ihint.run_type = run_type | G_SIGNAL_ACCUMULATOR_FIRST_RUN;
 | ||
| 	  emission.state = EMISSION_RUN;
 | ||
| 	  emission.chain_type = instance_type;
 | ||
| 	  emission_push (&emission);
 | ||
| 
 | ||
|           if (fastpath_handler)
 | ||
|             handler_ref (fastpath_handler);
 | ||
| 
 | ||
| 	  if (closure != NULL)
 | ||
| 	    {
 | ||
|               TRACE (GOBJECT_SIGNAL_EMIT (signal_id, detail, instance, (uintmax_t) instance_type));
 | ||
| 
 | ||
|               SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|               if (rtype != G_TYPE_NONE)
 | ||
|                 g_value_init (&emission_return, rtype);
 | ||
| 
 | ||
|               if (node_copy.accumulator)
 | ||
|                 g_value_init (&accu, rtype);
 | ||
| 
 | ||
|               /*
 | ||
|                * Coverity doesn’t understand the paired ref/unref here and seems
 | ||
|                * to ignore the ref, thus reports every call to g_signal_emit()
 | ||
|                * as causing a double-free. That’s incorrect, but I can’t get a
 | ||
|                * model file to work for avoiding the false positives, so instead
 | ||
|                * comment out the ref/unref when doing static analysis.
 | ||
|                */
 | ||
| #ifndef __COVERITY__
 | ||
| 	      g_object_ref (instance);
 | ||
| #endif
 | ||
| 	      _g_closure_invoke_va (closure,
 | ||
| 				    return_accu,
 | ||
| 				    instance,
 | ||
| 				    var_args,
 | ||
|                                     node_copy.n_params,
 | ||
|                                     node_copy.param_types);
 | ||
| 	      accumulate (&emission.ihint, &emission_return, &accu, node_copy.accumulator);
 | ||
| 
 | ||
|               if (node_copy.accumulator)
 | ||
|                 g_value_unset (&accu);
 | ||
| 
 | ||
|               SIGNAL_LOCK ();
 | ||
|             }
 | ||
| 
 | ||
| 	  emission.chain_type = G_TYPE_NONE;
 | ||
| 	  emission_pop (&emission);
 | ||
| 
 | ||
|           if (fastpath_handler)
 | ||
|             handler_unref_R (signal_id, instance, fastpath_handler);
 | ||
| 
 | ||
|           SIGNAL_UNLOCK ();
 | ||
| 
 | ||
| 	  if (rtype != G_TYPE_NONE)
 | ||
| 	    {
 | ||
| 	      gchar *error = NULL;
 | ||
|               for (i = 0; i < node_copy.n_params; i++)
 | ||
| 		{
 | ||
|                   GType ptype = node_copy.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE;
 | ||
| 		  G_VALUE_COLLECT_SKIP (ptype, var_args);
 | ||
| 		}
 | ||
| 
 | ||
|               if (closure == NULL)
 | ||
|                 g_value_init (&emission_return, rtype);
 | ||
| 
 | ||
| 	      G_VALUE_LCOPY (&emission_return,
 | ||
| 			     var_args,
 | ||
| 			     static_scope ? G_VALUE_NOCOPY_CONTENTS : 0,
 | ||
| 			     &error);
 | ||
| 	      if (!error)
 | ||
| 		g_value_unset (&emission_return);
 | ||
| 	      else
 | ||
| 		{
 | ||
| 		  g_critical ("%s: %s", G_STRLOC, error);
 | ||
| 		  g_free (error);
 | ||
| 		  /* we purposely leak the value here, it might not be
 | ||
| 		   * in a correct state if an error condition occurred
 | ||
| 		   */
 | ||
| 		}
 | ||
| 	    }
 | ||
| 
 | ||
|           TRACE (GOBJECT_SIGNAL_EMIT_END (signal_id, detail, instance, (uintmax_t) instance_type));
 | ||
| 
 | ||
|           /* See comment above paired ref above */
 | ||
| #ifndef __COVERITY__
 | ||
|           if (closure != NULL)
 | ||
|             g_object_unref (instance);
 | ||
| #endif
 | ||
| 
 | ||
| 	  return FALSE;
 | ||
| 	}
 | ||
|     }
 | ||
| 
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|   instance_and_params = g_newa0 (GValue, node_copy.n_params + 1);
 | ||
|   param_values = instance_and_params + 1;
 | ||
| 
 | ||
|   for (i = 0; i < node_copy.n_params; i++)
 | ||
|     {
 | ||
|       gchar *error;
 | ||
|       GType ptype = node_copy.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE;
 | ||
|       gboolean static_scope = node_copy.param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE;
 | ||
| 
 | ||
|       G_VALUE_COLLECT_INIT (param_values + i, ptype,
 | ||
| 			    var_args,
 | ||
| 			    static_scope ? G_VALUE_NOCOPY_CONTENTS : 0,
 | ||
| 			    &error);
 | ||
|       if (error)
 | ||
| 	{
 | ||
| 	  g_critical ("%s: %s", G_STRLOC, error);
 | ||
| 	  g_free (error);
 | ||
| 
 | ||
| 	  /* we purposely leak the value here, it might not be
 | ||
| 	   * in a correct state if an error condition occurred
 | ||
| 	   */
 | ||
| 	  while (i--)
 | ||
| 	    g_value_unset (param_values + i);
 | ||
| 
 | ||
|           return FALSE;
 | ||
| 	}
 | ||
|     }
 | ||
| 
 | ||
|   g_value_init_from_instance (instance_and_params, instance);
 | ||
|   if (node_copy.return_type == G_TYPE_NONE)
 | ||
|     {
 | ||
|       SIGNAL_LOCK ();
 | ||
|       signal_emit_unlocked_R (&node_copy, detail, instance, NULL, instance_and_params);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       GValue return_value = G_VALUE_INIT;
 | ||
|       gchar *error = NULL;
 | ||
|       GType rtype = node_copy.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE;
 | ||
|       gboolean static_scope = node_copy.return_type & G_SIGNAL_TYPE_STATIC_SCOPE;
 | ||
|       
 | ||
|       g_value_init (&return_value, rtype);
 | ||
| 
 | ||
|       SIGNAL_LOCK ();
 | ||
|       signal_emit_unlocked_R (&node_copy, detail, instance, &return_value, instance_and_params);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|       G_VALUE_LCOPY (&return_value,
 | ||
| 		     var_args,
 | ||
| 		     static_scope ? G_VALUE_NOCOPY_CONTENTS : 0,
 | ||
| 		     &error);
 | ||
|       if (!error)
 | ||
| 	g_value_unset (&return_value);
 | ||
|       else
 | ||
| 	{
 | ||
| 	  g_critical ("%s: %s", G_STRLOC, error);
 | ||
| 	  g_free (error);
 | ||
| 	  
 | ||
| 	  /* we purposely leak the value here, it might not be
 | ||
| 	   * in a correct state if an error condition occurred
 | ||
| 	   */
 | ||
| 	}
 | ||
|     }
 | ||
|   for (i = 0; i < node_copy.n_params; i++)
 | ||
|     g_value_unset (param_values + i);
 | ||
|   g_value_unset (instance_and_params);
 | ||
| 
 | ||
|   return FALSE;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_emit:
 | ||
|  * @instance: (type GObject.Object): the instance the signal is being emitted on.
 | ||
|  * @signal_id: the signal id
 | ||
|  * @detail: the detail
 | ||
|  * @...: parameters to be passed to the signal, followed by a
 | ||
|  *  location for the return value. If the return type of the signal
 | ||
|  *  is %G_TYPE_NONE, the return value location can be omitted.
 | ||
|  *
 | ||
|  * Emits a signal. Signal emission is done synchronously.
 | ||
|  * The method will only return control after all handlers are called or signal emission was stopped.
 | ||
|  *
 | ||
|  * Note that g_signal_emit() resets the return value to the default
 | ||
|  * if no handlers are connected, in contrast to g_signal_emitv().
 | ||
|  */
 | ||
| void
 | ||
| g_signal_emit (gpointer instance,
 | ||
| 	       guint    signal_id,
 | ||
| 	       GQuark   detail,
 | ||
| 	       ...)
 | ||
| {
 | ||
|   va_list var_args;
 | ||
| 
 | ||
|   va_start (var_args, detail);
 | ||
|   g_signal_emit_valist (instance, signal_id, detail, var_args);
 | ||
|   va_end (var_args);
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_emit_by_name:
 | ||
|  * @instance: (type GObject.Object): the instance the signal is being emitted on.
 | ||
|  * @detailed_signal: a string of the form "signal-name::detail".
 | ||
|  * @...: parameters to be passed to the signal, followed by a
 | ||
|  *  location for the return value. If the return type of the signal
 | ||
|  *  is %G_TYPE_NONE, the return value location can be omitted. The
 | ||
|  *  number of parameters to pass to this function is defined when creating the signal.
 | ||
|  *
 | ||
|  * Emits a signal. Signal emission is done synchronously.
 | ||
|  * The method will only return control after all handlers are called or signal emission was stopped.
 | ||
|  *
 | ||
|  * Note that g_signal_emit_by_name() resets the return value to the default
 | ||
|  * if no handlers are connected, in contrast to g_signal_emitv().
 | ||
|  */
 | ||
| void
 | ||
| g_signal_emit_by_name (gpointer     instance,
 | ||
| 		       const gchar *detailed_signal,
 | ||
| 		       ...)
 | ||
| {
 | ||
|   GQuark detail = 0;
 | ||
|   guint signal_id;
 | ||
|   GType itype;
 | ||
| 
 | ||
|   g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
 | ||
|   g_return_if_fail (detailed_signal != NULL);
 | ||
| 
 | ||
|   itype = G_TYPE_FROM_INSTANCE (instance);
 | ||
| 
 | ||
|   SIGNAL_LOCK ();
 | ||
|   signal_id = signal_parse_name (detailed_signal, itype, &detail, TRUE);
 | ||
| 
 | ||
|   if (signal_id)
 | ||
|     {
 | ||
|       va_list var_args;
 | ||
| 
 | ||
|       va_start (var_args, detailed_signal);
 | ||
|       if (signal_emit_valist_unlocked (instance, signal_id, detail, var_args))
 | ||
|         SIGNAL_UNLOCK ();
 | ||
|       va_end (var_args);
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|       g_critical ("%s: signal name '%s' is invalid for instance '%p' of type '%s'",
 | ||
|                   G_STRLOC, detailed_signal, instance, g_type_name (itype));
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| G_ALWAYS_INLINE static inline GValue *
 | ||
| maybe_init_accumulator_unlocked (SignalNode *node,
 | ||
|                                  GValue     *emission_return,
 | ||
|                                  GValue     *accumulator_value)
 | ||
| {
 | ||
|   if (node->accumulator)
 | ||
|     {
 | ||
|       if (accumulator_value->g_type)
 | ||
|         return accumulator_value;
 | ||
| 
 | ||
|       g_value_init (accumulator_value,
 | ||
|                     node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
 | ||
|       return accumulator_value;
 | ||
|     }
 | ||
| 
 | ||
|   return emission_return;
 | ||
| }
 | ||
| 
 | ||
| static gboolean
 | ||
| signal_emit_unlocked_R (SignalNode   *node,
 | ||
| 			GQuark	      detail,
 | ||
| 			gpointer      instance,
 | ||
| 			GValue	     *emission_return,
 | ||
| 			const GValue *instance_and_params)
 | ||
| {
 | ||
|   SignalAccumulator *accumulator;
 | ||
|   Emission emission;
 | ||
|   GClosure *class_closure;
 | ||
|   HandlerList *hlist;
 | ||
|   Handler *handler_list = NULL;
 | ||
|   GValue *return_accu, accu = G_VALUE_INIT;
 | ||
|   guint signal_id;
 | ||
|   gulong max_sequential_handler_number;
 | ||
|   gboolean return_value_altered = FALSE;
 | ||
|   guint n_params;
 | ||
| 
 | ||
|   TRACE(GOBJECT_SIGNAL_EMIT(node->signal_id, detail, instance, G_TYPE_FROM_INSTANCE (instance)));
 | ||
| 
 | ||
|   /* We expect this function to be called with a stable SignalNode pointer
 | ||
|    * that cannot change location, so accessing its stable members should
 | ||
|    * always work even after a lock/unlock.
 | ||
|    */
 | ||
|   signal_id = node->signal_id;
 | ||
|   n_params = node->n_params + 1;
 | ||
| 
 | ||
|   if (node->flags & G_SIGNAL_NO_RECURSE)
 | ||
|     {
 | ||
|       Emission *emission_node = emission_find (signal_id, detail, instance);
 | ||
| 
 | ||
|       if (emission_node)
 | ||
|         {
 | ||
|           emission_node->state = EMISSION_RESTART;
 | ||
|           return return_value_altered;
 | ||
|         }
 | ||
|     }
 | ||
|   accumulator = node->accumulator;
 | ||
|   emission.instance = instance;
 | ||
|   emission.ihint.signal_id = node->signal_id;
 | ||
|   emission.ihint.detail = detail;
 | ||
|   emission.ihint.run_type = 0;
 | ||
|   emission.state = 0;
 | ||
|   emission.chain_type = G_TYPE_NONE;
 | ||
|   emission_push (&emission);
 | ||
|   class_closure = signal_lookup_closure (node, instance);
 | ||
|   
 | ||
|  EMIT_RESTART:
 | ||
|   
 | ||
|   if (handler_list)
 | ||
|     handler_unref_R (signal_id, instance, handler_list);
 | ||
|   max_sequential_handler_number = g_handler_sequential_number;
 | ||
|   hlist = handler_list_lookup (signal_id, instance);
 | ||
|   handler_list = hlist ? hlist->handlers : NULL;
 | ||
|   if (handler_list)
 | ||
|     handler_ref (handler_list);
 | ||
|   
 | ||
|   emission.ihint.run_type = G_SIGNAL_RUN_FIRST | G_SIGNAL_ACCUMULATOR_FIRST_RUN;
 | ||
|   
 | ||
|   if ((node->flags & G_SIGNAL_RUN_FIRST) && class_closure)
 | ||
|     {
 | ||
|       emission.state = EMISSION_RUN;
 | ||
| 
 | ||
|       emission.chain_type = G_TYPE_FROM_INSTANCE (instance);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       return_accu = maybe_init_accumulator_unlocked (node, emission_return, &accu);
 | ||
|       g_closure_invoke (class_closure,
 | ||
| 			return_accu,
 | ||
|                         n_params,
 | ||
| 			instance_and_params,
 | ||
| 			&emission.ihint);
 | ||
|       if (!accumulate (&emission.ihint, emission_return, &accu, accumulator) &&
 | ||
| 	  emission.state == EMISSION_RUN)
 | ||
| 	emission.state = EMISSION_STOP;
 | ||
|       SIGNAL_LOCK ();
 | ||
|       emission.chain_type = G_TYPE_NONE;
 | ||
|       return_value_altered = TRUE;
 | ||
|       
 | ||
|       if (emission.state == EMISSION_STOP)
 | ||
| 	goto EMIT_CLEANUP;
 | ||
|       else if (emission.state == EMISSION_RESTART)
 | ||
| 	goto EMIT_RESTART;
 | ||
|     }
 | ||
| 
 | ||
|   if (node->emission_hooks)
 | ||
|     {
 | ||
|       GHook *hook;
 | ||
|       GHook *static_emission_hooks[3];
 | ||
|       size_t n_emission_hooks = 0;
 | ||
|       const gboolean may_recurse = TRUE;
 | ||
|       guint i;
 | ||
| 
 | ||
|       emission.state = EMISSION_HOOK;
 | ||
| 
 | ||
|       /* Quick check to determine whether any hooks match this emission,
 | ||
|        * before committing to the more complex work of calling those hooks.
 | ||
|        * We save a few of them into a static array, to try to avoid further
 | ||
|        * allocations.
 | ||
|        */
 | ||
|       hook = g_hook_first_valid (node->emission_hooks, may_recurse);
 | ||
|       while (hook)
 | ||
| 	{
 | ||
| 	  SignalHook *signal_hook = SIGNAL_HOOK (hook);
 | ||
| 
 | ||
| 	  if (!signal_hook->detail || signal_hook->detail == detail)
 | ||
|             {
 | ||
|               if (n_emission_hooks < G_N_ELEMENTS (static_emission_hooks))
 | ||
|                 {
 | ||
|                   static_emission_hooks[n_emission_hooks] =
 | ||
|                     g_hook_ref (node->emission_hooks, hook);
 | ||
|                 }
 | ||
| 
 | ||
|               n_emission_hooks += 1;
 | ||
|             }
 | ||
| 
 | ||
| 	  hook = g_hook_next_valid (node->emission_hooks, hook, may_recurse);
 | ||
| 	}
 | ||
| 
 | ||
|       /* Re-iterate back through the matching hooks and copy them into
 | ||
|        * an array which won’t change when we unlock to call the
 | ||
|        * user-provided hook functions.
 | ||
|        * These functions may change hook configuration for this signal,
 | ||
|        * add / remove signal handlers, etc.
 | ||
|        */
 | ||
|       if G_UNLIKELY (n_emission_hooks > 0)
 | ||
|         {
 | ||
|           guint8 static_hook_returns[G_N_ELEMENTS (static_emission_hooks)];
 | ||
|           GHook **emission_hooks = NULL;
 | ||
|           guint8 *hook_returns = NULL;
 | ||
| 
 | ||
|           if G_LIKELY (n_emission_hooks <= G_N_ELEMENTS (static_emission_hooks))
 | ||
|             {
 | ||
|               emission_hooks = static_emission_hooks;
 | ||
|               hook_returns = static_hook_returns;
 | ||
|             }
 | ||
|           else
 | ||
|             {
 | ||
|               emission_hooks = g_newa (GHook *, n_emission_hooks);
 | ||
|               hook_returns = g_newa (guint8, n_emission_hooks);
 | ||
| 
 | ||
|               /* We can't just memcpy the ones we have in the static array,
 | ||
|                * to the alloca()'d one because otherwise we'd get an invalid
 | ||
|                * ID assertion during unref
 | ||
|                */
 | ||
|               i = 0;
 | ||
|               for (hook = g_hook_first_valid (node->emission_hooks, may_recurse);
 | ||
|                    hook != NULL;
 | ||
|                    hook = g_hook_next_valid (node->emission_hooks, hook, may_recurse))
 | ||
|                 {
 | ||
|                   SignalHook *signal_hook = SIGNAL_HOOK (hook);
 | ||
| 
 | ||
|                   if (!signal_hook->detail || signal_hook->detail == detail)
 | ||
|                     {
 | ||
|                        if (i < G_N_ELEMENTS (static_emission_hooks))
 | ||
|                          {
 | ||
|                             emission_hooks[i] = g_steal_pointer (&static_emission_hooks[i]);
 | ||
|                             g_assert (emission_hooks[i] == hook);
 | ||
|                          }
 | ||
|                        else
 | ||
|                          {
 | ||
|                             emission_hooks[i] = g_hook_ref (node->emission_hooks, hook);
 | ||
|                          }
 | ||
| 
 | ||
|                       i += 1;
 | ||
|                     }
 | ||
|                 }
 | ||
| 
 | ||
|                g_assert (i == n_emission_hooks);
 | ||
|             }
 | ||
| 
 | ||
|             SIGNAL_UNLOCK ();
 | ||
| 
 | ||
|             for (i = 0; i < n_emission_hooks; ++i)
 | ||
|               {
 | ||
|                 GSignalEmissionHook hook_func;
 | ||
|                 gboolean need_destroy;
 | ||
|                 guint old_flags;
 | ||
| 
 | ||
|                 hook = emission_hooks[i];
 | ||
|                 hook_func = (GSignalEmissionHook) hook->func;
 | ||
| 
 | ||
|                 old_flags = g_atomic_int_or (&hook->flags, G_HOOK_FLAG_IN_CALL);
 | ||
|                 need_destroy = !hook_func (&emission.ihint, n_params,
 | ||
|                                            instance_and_params, hook->data);
 | ||
| 
 | ||
|                 if (!(old_flags & G_HOOK_FLAG_IN_CALL))
 | ||
|                   {
 | ||
|                     g_atomic_int_compare_and_exchange ((gint *) &hook->flags,
 | ||
|                                                        (gint) old_flags | G_HOOK_FLAG_IN_CALL,
 | ||
|                                                        (gint) old_flags);
 | ||
|                   }
 | ||
| 
 | ||
|                 hook_returns[i] = !!need_destroy;
 | ||
|               }
 | ||
| 
 | ||
|             SIGNAL_LOCK ();
 | ||
| 
 | ||
|             for (i = 0; i < n_emission_hooks; i++)
 | ||
|               {
 | ||
|                 hook = emission_hooks[i];
 | ||
| 
 | ||
|                 g_hook_unref (node->emission_hooks, hook);
 | ||
| 
 | ||
|                 if (hook_returns[i])
 | ||
|                   g_hook_destroy_link (node->emission_hooks, hook);
 | ||
|               }
 | ||
| 	}
 | ||
| 
 | ||
|       if (emission.state == EMISSION_RESTART)
 | ||
| 	goto EMIT_RESTART;
 | ||
|     }
 | ||
|   
 | ||
|   if (handler_list)
 | ||
|     {
 | ||
|       Handler *handler = handler_list;
 | ||
|       
 | ||
|       emission.state = EMISSION_RUN;
 | ||
|       handler_ref (handler);
 | ||
|       do
 | ||
| 	{
 | ||
| 	  Handler *tmp;
 | ||
| 	  
 | ||
| 	  if (handler->after)
 | ||
| 	    {
 | ||
| 	      handler_unref_R (signal_id, instance, handler_list);
 | ||
| 	      handler_list = handler;
 | ||
| 	      break;
 | ||
| 	    }
 | ||
| 	  else if (!handler->block_count && (!handler->detail || handler->detail == detail) &&
 | ||
| 		   handler->sequential_number < max_sequential_handler_number)
 | ||
| 	    {
 | ||
| 	      SIGNAL_UNLOCK ();
 | ||
| 	      return_accu = maybe_init_accumulator_unlocked (node, emission_return, &accu);
 | ||
| 	      g_closure_invoke (handler->closure,
 | ||
| 				return_accu,
 | ||
|                                 n_params,
 | ||
| 				instance_and_params,
 | ||
| 				&emission.ihint);
 | ||
| 	      if (!accumulate (&emission.ihint, emission_return, &accu, accumulator) &&
 | ||
| 		  emission.state == EMISSION_RUN)
 | ||
| 		emission.state = EMISSION_STOP;
 | ||
| 	      SIGNAL_LOCK ();
 | ||
| 	      return_value_altered = TRUE;
 | ||
| 	      
 | ||
| 	      tmp = emission.state == EMISSION_RUN ? handler->next : NULL;
 | ||
| 	    }
 | ||
| 	  else
 | ||
| 	    tmp = handler->next;
 | ||
| 	  
 | ||
| 	  if (tmp)
 | ||
| 	    handler_ref (tmp);
 | ||
| 	  handler_unref_R (signal_id, instance, handler_list);
 | ||
| 	  handler_list = handler;
 | ||
| 	  handler = tmp;
 | ||
| 	}
 | ||
|       while (handler);
 | ||
|       
 | ||
|       if (emission.state == EMISSION_STOP)
 | ||
| 	goto EMIT_CLEANUP;
 | ||
|       else if (emission.state == EMISSION_RESTART)
 | ||
| 	goto EMIT_RESTART;
 | ||
|     }
 | ||
|   
 | ||
|   emission.ihint.run_type &= (unsigned) ~G_SIGNAL_RUN_FIRST;
 | ||
|   emission.ihint.run_type |= G_SIGNAL_RUN_LAST;
 | ||
|   
 | ||
|   if ((node->flags & G_SIGNAL_RUN_LAST) && class_closure)
 | ||
|     {
 | ||
|       emission.state = EMISSION_RUN;
 | ||
|       
 | ||
|       emission.chain_type = G_TYPE_FROM_INSTANCE (instance);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       return_accu = maybe_init_accumulator_unlocked (node, emission_return, &accu);
 | ||
|       g_closure_invoke (class_closure,
 | ||
| 			return_accu,
 | ||
|                         n_params,
 | ||
| 			instance_and_params,
 | ||
| 			&emission.ihint);
 | ||
|       if (!accumulate (&emission.ihint, emission_return, &accu, accumulator) &&
 | ||
| 	  emission.state == EMISSION_RUN)
 | ||
| 	emission.state = EMISSION_STOP;
 | ||
|       SIGNAL_LOCK ();
 | ||
|       emission.chain_type = G_TYPE_NONE;
 | ||
|       return_value_altered = TRUE;
 | ||
|       
 | ||
|       if (emission.state == EMISSION_STOP)
 | ||
| 	goto EMIT_CLEANUP;
 | ||
|       else if (emission.state == EMISSION_RESTART)
 | ||
| 	goto EMIT_RESTART;
 | ||
|     }
 | ||
|   
 | ||
|   if (handler_list)
 | ||
|     {
 | ||
|       Handler *handler = handler_list;
 | ||
|       
 | ||
|       emission.state = EMISSION_RUN;
 | ||
|       handler_ref (handler);
 | ||
|       do
 | ||
| 	{
 | ||
| 	  Handler *tmp;
 | ||
| 	  
 | ||
| 	  if (handler->after && !handler->block_count && (!handler->detail || handler->detail == detail) &&
 | ||
| 	      handler->sequential_number < max_sequential_handler_number)
 | ||
| 	    {
 | ||
| 	      SIGNAL_UNLOCK ();
 | ||
| 	      return_accu = maybe_init_accumulator_unlocked (node, emission_return, &accu);
 | ||
| 	      g_closure_invoke (handler->closure,
 | ||
| 				return_accu,
 | ||
|                                 n_params,
 | ||
| 				instance_and_params,
 | ||
| 				&emission.ihint);
 | ||
| 	      if (!accumulate (&emission.ihint, emission_return, &accu, accumulator) &&
 | ||
| 		  emission.state == EMISSION_RUN)
 | ||
| 		emission.state = EMISSION_STOP;
 | ||
| 	      SIGNAL_LOCK ();
 | ||
| 	      return_value_altered = TRUE;
 | ||
| 	      
 | ||
| 	      tmp = emission.state == EMISSION_RUN ? handler->next : NULL;
 | ||
| 	    }
 | ||
| 	  else
 | ||
| 	    tmp = handler->next;
 | ||
| 	  
 | ||
| 	  if (tmp)
 | ||
| 	    handler_ref (tmp);
 | ||
| 	  handler_unref_R (signal_id, instance, handler);
 | ||
| 	  handler = tmp;
 | ||
| 	}
 | ||
|       while (handler);
 | ||
|       
 | ||
|       if (emission.state == EMISSION_STOP)
 | ||
| 	goto EMIT_CLEANUP;
 | ||
|       else if (emission.state == EMISSION_RESTART)
 | ||
| 	goto EMIT_RESTART;
 | ||
|     }
 | ||
|   
 | ||
|  EMIT_CLEANUP:
 | ||
|   
 | ||
|   emission.ihint.run_type &= (unsigned) ~G_SIGNAL_RUN_LAST;
 | ||
|   emission.ihint.run_type |= G_SIGNAL_RUN_CLEANUP;
 | ||
|   
 | ||
|   if ((node->flags & G_SIGNAL_RUN_CLEANUP) && class_closure)
 | ||
|     {
 | ||
|       gboolean need_unset = FALSE;
 | ||
|       
 | ||
|       emission.state = EMISSION_STOP;
 | ||
|       
 | ||
|       emission.chain_type = G_TYPE_FROM_INSTANCE (instance);
 | ||
|       SIGNAL_UNLOCK ();
 | ||
|       if (node->return_type != G_TYPE_NONE && !accumulator)
 | ||
| 	{
 | ||
| 	  g_value_init (&accu, node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
 | ||
| 	  need_unset = TRUE;
 | ||
| 	}
 | ||
|       g_closure_invoke (class_closure,
 | ||
| 			node->return_type != G_TYPE_NONE ? &accu : NULL,
 | ||
|                         n_params,
 | ||
| 			instance_and_params,
 | ||
| 			&emission.ihint);
 | ||
|       if (!accumulate (&emission.ihint, emission_return, &accu, accumulator) &&
 | ||
|           emission.state == EMISSION_RUN)
 | ||
|         emission.state = EMISSION_STOP;
 | ||
|       if (need_unset)
 | ||
| 	g_value_unset (&accu);
 | ||
|       SIGNAL_LOCK ();
 | ||
|       return_value_altered = TRUE;
 | ||
| 
 | ||
|       emission.chain_type = G_TYPE_NONE;
 | ||
|       
 | ||
|       if (emission.state == EMISSION_RESTART)
 | ||
| 	goto EMIT_RESTART;
 | ||
|     }
 | ||
|   
 | ||
|   if (handler_list)
 | ||
|     handler_unref_R (signal_id, instance, handler_list);
 | ||
|   
 | ||
|   emission_pop (&emission);
 | ||
|   if (accumulator)
 | ||
|     g_value_unset (&accu);
 | ||
| 
 | ||
|   TRACE(GOBJECT_SIGNAL_EMIT_END(node->signal_id, detail, instance, G_TYPE_FROM_INSTANCE (instance)));
 | ||
| 
 | ||
|   return return_value_altered;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| add_invalid_closure_notify (Handler  *handler,
 | ||
| 			    gpointer  instance)
 | ||
| {
 | ||
|   g_closure_add_invalidate_notifier (handler->closure, instance, invalid_closure_notify);
 | ||
|   handler->has_invalid_closure_notify = 1;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| remove_invalid_closure_notify (Handler  *handler,
 | ||
| 			       gpointer  instance)
 | ||
| {
 | ||
|   if (handler->has_invalid_closure_notify)
 | ||
|     {
 | ||
|       g_closure_remove_invalidate_notifier (handler->closure, instance, invalid_closure_notify);
 | ||
|       handler->has_invalid_closure_notify = 0;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| invalid_closure_notify (gpointer  instance,
 | ||
| 		        GClosure *closure)
 | ||
| {
 | ||
|   Handler *handler;
 | ||
|   guint signal_id;
 | ||
| 
 | ||
|   SIGNAL_LOCK ();
 | ||
| 
 | ||
|   handler = handler_lookup (instance, 0, closure, &signal_id);
 | ||
|   /* See https://bugzilla.gnome.org/show_bug.cgi?id=730296 for discussion about this... */
 | ||
|   g_assert (handler != NULL);
 | ||
|   g_assert (handler->closure == closure);
 | ||
| 
 | ||
|   g_hash_table_remove (g_handlers, handler);
 | ||
|   handler->sequential_number = 0;
 | ||
|   handler->block_count = 1;
 | ||
|   handler_unref_R (signal_id, instance, handler);
 | ||
| 
 | ||
|   SIGNAL_UNLOCK ();
 | ||
| }
 | ||
| 
 | ||
| static const gchar*
 | ||
| type_debug_name (GType type)
 | ||
| {
 | ||
|   if (type)
 | ||
|     {
 | ||
|       const char *name = g_type_name (type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
 | ||
|       return name ? name : "<unknown>";
 | ||
|     }
 | ||
|   else
 | ||
|     return "<invalid>";
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_accumulator_true_handled:
 | ||
|  * @ihint: standard #GSignalAccumulator parameter
 | ||
|  * @return_accu: standard #GSignalAccumulator parameter
 | ||
|  * @handler_return: standard #GSignalAccumulator parameter
 | ||
|  * @dummy: standard #GSignalAccumulator parameter
 | ||
|  *
 | ||
|  * A predefined #GSignalAccumulator for signals that return a
 | ||
|  * boolean values. The behavior that this accumulator gives is
 | ||
|  * that a return of %TRUE stops the signal emission: no further
 | ||
|  * callbacks will be invoked, while a return of %FALSE allows
 | ||
|  * the emission to continue. The idea here is that a %TRUE return
 | ||
|  * indicates that the callback handled the signal, and no further
 | ||
|  * handling is needed.
 | ||
|  *
 | ||
|  * Since: 2.4
 | ||
|  *
 | ||
|  * Returns: standard #GSignalAccumulator result
 | ||
|  */
 | ||
| gboolean
 | ||
| g_signal_accumulator_true_handled (GSignalInvocationHint *ihint,
 | ||
| 				   GValue                *return_accu,
 | ||
| 				   const GValue          *handler_return,
 | ||
| 				   gpointer               dummy)
 | ||
| {
 | ||
|   gboolean continue_emission;
 | ||
|   gboolean signal_handled;
 | ||
|   
 | ||
|   signal_handled = g_value_get_boolean (handler_return);
 | ||
|   g_value_set_boolean (return_accu, signal_handled);
 | ||
|   continue_emission = !signal_handled;
 | ||
|   
 | ||
|   return continue_emission;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_signal_accumulator_first_wins:
 | ||
|  * @ihint: standard #GSignalAccumulator parameter
 | ||
|  * @return_accu: standard #GSignalAccumulator parameter
 | ||
|  * @handler_return: standard #GSignalAccumulator parameter
 | ||
|  * @dummy: standard #GSignalAccumulator parameter
 | ||
|  *
 | ||
|  * A predefined #GSignalAccumulator for signals intended to be used as a
 | ||
|  * hook for application code to provide a particular value.  Usually
 | ||
|  * only one such value is desired and multiple handlers for the same
 | ||
|  * signal don't make much sense (except for the case of the default
 | ||
|  * handler defined in the class structure, in which case you will
 | ||
|  * usually want the signal connection to override the class handler).
 | ||
|  *
 | ||
|  * This accumulator will use the return value from the first signal
 | ||
|  * handler that is run as the return value for the signal and not run
 | ||
|  * any further handlers (ie: the first handler "wins").
 | ||
|  *
 | ||
|  * Returns: standard #GSignalAccumulator result
 | ||
|  *
 | ||
|  * Since: 2.28
 | ||
|  **/
 | ||
| gboolean
 | ||
| g_signal_accumulator_first_wins (GSignalInvocationHint *ihint,
 | ||
|                                  GValue                *return_accu,
 | ||
|                                  const GValue          *handler_return,
 | ||
|                                  gpointer               dummy)
 | ||
| {
 | ||
|   g_value_copy (handler_return, return_accu);
 | ||
|   return FALSE;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  * g_clear_signal_handler:
 | ||
|  * @handler_id_ptr: A pointer to a handler ID (of type #gulong) of the handler to be disconnected.
 | ||
|  * @instance: (type GObject.Object): The instance to remove the signal handler from.
 | ||
|  *   This pointer may be %NULL or invalid, if the handler ID is zero.
 | ||
|  *
 | ||
|  * Disconnects a handler from @instance so it will not be called during
 | ||
|  * any future or currently ongoing emissions of the signal it has been
 | ||
|  * connected to. The @handler_id_ptr is then set to zero, which is never a valid handler ID value (see g_signal_connect()).
 | ||
|  *
 | ||
|  * If the handler ID is 0 then this function does nothing.
 | ||
|  *
 | ||
|  * There is also a macro version of this function so that the code
 | ||
|  * will be inlined.
 | ||
|  *
 | ||
|  * Since: 2.62
 | ||
|  */
 | ||
| void
 | ||
| (g_clear_signal_handler) (gulong   *handler_id_ptr,
 | ||
|                           gpointer  instance)
 | ||
| {
 | ||
|   g_return_if_fail (handler_id_ptr != NULL);
 | ||
| 
 | ||
| #ifndef g_clear_signal_handler
 | ||
| #error g_clear_signal_handler() macro is not defined
 | ||
| #endif
 | ||
| 
 | ||
|   g_clear_signal_handler (handler_id_ptr, instance);
 | ||
| }
 |