gsignal.c revision 65c423b458d9fd1338cab0de7951092c09ab1686
1/* GObject - GLib Type, Object, Parameter and Signal Library
2 * Copyright (C) 2000 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General
15 * Public License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307, USA.
18 *
19 * this code is based on the original GtkSignal implementation
20 * for the Gtk+ library by Peter Mattis <petm@xcf.berkeley.edu>
21 */
22#include <string.h>
23
24#include        "gsignal.h"
25
26#include        "gbsearcharray.h"
27
28
29/* pre allocation configurations
30 */
31#define BSA_PRE_ALLOC           (20)
32#define HANDLER_PRE_ALLOC       (48)
33#define EMISSION_PRE_ALLOC      (16)
34
35#define TIGHT_MEMORY    (1)
36
37#define REPORT_BUG      "please report occourance circumstances to gtk-devel-list@gnome.org"
38
39
40/* --- generic allocation --- */
41/* we can special case allocations generically by replacing
42 * these functions with more speed/memory aware variants
43 */
44static inline gpointer
45g_generic_node_alloc (GTrashStack **trash_stack_p,
46                      guint         sizeof_node,
47                      guint         nodes_pre_alloc)
48{
49  gpointer node = g_trash_stack_pop (trash_stack_p);
50
51  if (!node)
52    {
53      guint8 *block;
54
55      nodes_pre_alloc = MAX (nodes_pre_alloc, 1);
56      block = g_malloc (sizeof_node * nodes_pre_alloc);
57      while (--nodes_pre_alloc)
58        {
59          g_trash_stack_push (trash_stack_p, block);
60          block += sizeof_node;
61        }
62      node = block;
63    }
64
65  return node;
66}
67static inline void
68g_generic_node_free (GTrashStack **trash_stack_p,
69                     gpointer      node)
70{
71  g_trash_stack_push (trash_stack_p, node);
72}
73
74
75/* --- typedefs --- */
76typedef struct _SignalNode  SignalNode;
77typedef struct _SignalKey   SignalKey;
78typedef struct _Emission    Emission;
79typedef struct _Handler     Handler;
80typedef struct _HandlerList HandlerList;
81typedef enum
82{
83  EMISSION_STOP,
84  EMISSION_RUN,
85  EMISSION_HOOK,
86  EMISSION_RESTART
87} EmissionState;
88
89
90/* --- prototypes --- */
91static inline guint             signal_id_lookup      (GQuark           quark,
92						       GType            itype);
93static        void              signal_destroy_R      (SignalNode      *signal_node);
94static inline HandlerList*      handler_list_ensure   (guint            signal_id,
95						       gpointer         instance);
96static inline HandlerList*      handler_list_lookup   (guint            signal_id,
97						       gpointer         instance);
98static inline Handler*          handler_new           (gboolean         after);
99static        void              handler_insert        (guint            signal_id,
100						       gpointer         instance,
101						       Handler         *handler);
102static        Handler*          handler_lookup        (gpointer         instance,
103						       guint            handler_id,
104						       guint           *signal_id_p);
105static        Handler*          handler_find          (gpointer         instance,
106						       GSignalMatchType mask,
107						       guint            signal_id,
108						       GQuark		detail,
109						       GClosure        *closure,
110						       gpointer         func,
111						       gpointer         data);
112static inline void              handler_ref           (Handler         *handler);
113static inline void              handler_unref_R       (guint            signal_id,
114						       gpointer         instance,
115						       Handler         *handler);
116static inline void              emission_push         (Emission       **emission_list_p,
117						       guint            signal_id,
118						       GQuark		detail,
119						       gpointer         instance,
120						       EmissionState   *state_p);
121static inline void              emission_pop          (Emission       **emission_list_p,
122						       EmissionState   *state_p);
123static inline Emission*         emission_find         (Emission        *emission_list,
124						       guint            signal_id,
125						       GQuark		detail,
126						       gpointer         instance);
127static	      void		signal_emit_R	      (SignalNode      *node,
128						       GQuark		detail,
129						       gpointer		instance,
130						       GValue	       *return_value,
131						       const GValue    *instance_and_params);
132
133
134/* --- structures --- */
135struct _SignalNode
136{
137  /* permanent portion */
138  guint              signal_id;
139  GType              itype;
140  gchar             *name;
141  guint              destroyed : 1;
142
143  /* reinitializable portion */
144  guint              flags : 8;
145  guint              n_params : 8;
146  GType		    *param_types;
147  GType		     return_type;
148  GClosure          *class_closure;
149  GSignalAccumulator accumulator;
150  GSignalCMarshaller c_marshaller;
151  GHookList         *emission_hooks;
152};
153
154struct _SignalKey
155{
156  GType  itype;
157  GQuark quark;
158  guint  signal_id;
159};
160
161struct _Emission
162{
163  Emission      *next;
164  guint          signal_id;
165  GQuark	 detail;
166  gpointer       instance;
167  EmissionState *state_p;
168};
169
170struct _HandlerList
171{
172  guint    signal_id;
173  Handler *handlers;
174};
175
176struct _Handler
177{
178  guint         id;
179  Handler      *next;
180  Handler      *prev;
181  GQuark	detail;
182  guint         ref_count : 16;
183#define HANDLER_MAX_REF_COUNT   (1 << 16)
184  guint         block_count : 12;
185#define HANDLER_MAX_BLOCK_COUNT (1 << 12)
186  guint         after : 1;
187  GClosure     *closure;
188};
189
190
191/* --- variables --- */
192static GBSearchArray  g_signal_key_bsa = { NULL, 0, 0, 0, NULL };
193static GHashTable    *g_handler_list_bsa_ht = NULL;
194static Emission      *g_recursive_emissions = NULL;
195static Emission      *g_restart_emissions = NULL;
196static GTrashStack   *g_bsa_ts = NULL;
197static GTrashStack   *g_handler_ts = NULL;
198static GTrashStack   *g_emission_ts = NULL;
199G_LOCK_DEFINE_STATIC (g_signal_mutex);
200
201
202/* --- signal nodes --- */
203static guint          g_n_signal_nodes = 0;
204static SignalNode   **g_signal_nodes = NULL;
205
206static inline SignalNode*
207LOOKUP_SIGNAL_NODE (register guint signal_id)
208{
209  if (signal_id < g_n_signal_nodes)
210    return g_signal_nodes[signal_id];
211  else
212    return NULL;
213}
214
215
216/* --- functions --- */
217static inline guint
218signal_id_lookup (GQuark quark,
219		  GType  itype)
220{
221  do
222    {
223      SignalKey key, *signal_key;
224
225      key.itype = itype;
226      key.quark = quark;
227
228      signal_key = g_bsearch_array_lookup (&g_signal_key_bsa, &key);
229
230      if (signal_key)
231	return signal_key->signal_id;
232
233      itype = g_type_parent (itype);
234    }
235  while (itype);
236
237  return 0;
238}
239
240static gint
241handler_lists_cmp (gconstpointer node1,
242                   gconstpointer node2)
243{
244  const HandlerList *hlist1 = node1, *hlist2 = node2;
245
246  return G_BSEARCH_ARRAY_CMP (hlist1->signal_id, hlist2->signal_id);
247}
248
249static inline HandlerList*
250handler_list_ensure (guint    signal_id,
251		     gpointer instance)
252{
253  GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
254  HandlerList key;
255
256  if (!hlbsa)
257    {
258      hlbsa = g_generic_node_alloc (&g_bsa_ts,
259                                    sizeof (GBSearchArray),
260                                    BSA_PRE_ALLOC);
261      hlbsa->cmp_func = handler_lists_cmp;
262      hlbsa->sizeof_node = sizeof (HandlerList);
263      hlbsa->flags = G_BSEARCH_DEFER_SHRINK;
264      hlbsa->n_nodes = 0;
265      hlbsa->nodes = NULL;
266      g_hash_table_insert (g_handler_list_bsa_ht, instance, hlbsa);
267    }
268  key.signal_id = signal_id;
269  key.handlers = NULL;
270
271  return g_bsearch_array_insert (hlbsa, &key, FALSE);
272}
273
274static inline HandlerList*
275handler_list_lookup (guint    signal_id,
276		     gpointer instance)
277{
278  GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
279  HandlerList key;
280
281  key.signal_id = signal_id;
282
283  return hlbsa ? g_bsearch_array_lookup (hlbsa, &key) : NULL;
284}
285
286static Handler*
287handler_lookup (gpointer instance,
288		guint    handler_id,
289		guint   *signal_id_p)
290{
291  GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
292
293  if (hlbsa)
294    {
295      guint i;
296
297      for (i = 0; i < hlbsa->n_nodes; i++)
298        {
299          HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i);
300          Handler *handler;
301
302          for (handler = hlist->handlers; handler; handler = handler->next)
303            if (handler->id == handler_id)
304              {
305                if (signal_id_p)
306                  *signal_id_p = hlist->signal_id;
307
308                return handler;
309              }
310        }
311    }
312
313  return NULL;
314}
315
316static Handler*
317handler_find (gpointer         instance,
318	      GSignalMatchType mask,
319	      guint            signal_id,
320	      GQuark	       detail,
321	      GClosure        *closure,
322	      gpointer         func,
323	      gpointer         data)
324{
325  if (mask & G_SIGNAL_MATCH_ID)
326    {
327      HandlerList *hlist = handler_list_lookup (signal_id, instance);
328      Handler *handler;
329      SignalNode *node;
330
331      if (mask & G_SIGNAL_MATCH_FUNC)
332	{
333	  node = LOOKUP_SIGNAL_NODE (signal_id);
334	  if (!node || !node->c_marshaller)
335	    return NULL;
336	}
337
338      mask = ~mask;
339      for (handler = hlist ? hlist->handlers : NULL; handler; handler = handler->next)
340        if (((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
341	    ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
342            ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
343	    ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
344	    ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
345					      handler->closure->meta_marshal == 0 &&
346					      ((GCClosure*) handler->closure)->callback == func)))
347          return handler;
348    }
349  else
350    {
351      GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
352
353      mask = ~mask;
354      if (hlbsa)
355        {
356          guint i;
357
358          for (i = 0; i < hlbsa->n_nodes; i++)
359            {
360              HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i);
361	      SignalNode *node;
362              Handler *handler;
363
364	      if (!(mask & G_SIGNAL_MATCH_FUNC))
365		{
366		  node = LOOKUP_SIGNAL_NODE (hlist->signal_id);
367		  if (!node->c_marshaller)
368		    continue;
369		}
370
371              for (handler = hlist->handlers; handler; handler = handler->next)
372		if (((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
373                    ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
374                    ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
375		    ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
376		    ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
377						      handler->closure->meta_marshal == 0 &&
378						      ((GCClosure*) handler->closure)->callback == func)))
379                  return handler;
380            }
381        }
382    }
383
384  return NULL;
385}
386
387static inline Handler*
388handler_new (gboolean after)
389{
390  static guint handler_id = 1;
391  Handler *handler = g_generic_node_alloc (&g_handler_ts,
392                                           sizeof (Handler),
393                                           HANDLER_PRE_ALLOC);
394#ifndef G_DISABLE_CHECKS
395  if (handler_id == 0)
396    g_error (G_STRLOC ": handler id overflow, %s", REPORT_BUG);
397#endif
398
399  handler->id = handler_id++;
400  handler->prev = NULL;
401  handler->next = NULL;
402  handler->detail = 0;
403  handler->ref_count = 1;
404  handler->block_count = 0;
405  handler->after = after != FALSE;
406  handler->closure = NULL;
407
408  return handler;
409}
410
411static inline void
412handler_ref (Handler *handler)
413{
414  g_return_if_fail (handler->ref_count > 0);
415
416#ifndef G_DISABLE_CHECKS
417  if (handler->ref_count >= HANDLER_MAX_REF_COUNT - 1)
418    g_error (G_STRLOC ": handler ref_count overflow, %s", REPORT_BUG);
419#endif
420
421  handler->ref_count += 1;
422}
423
424static inline void
425handler_unref_R (guint    signal_id,
426		 gpointer instance,
427		 Handler *handler)
428{
429  g_return_if_fail (handler->ref_count > 0);
430
431  handler->ref_count -= 1;
432  if (!handler->ref_count)
433    {
434      if (handler->next)
435        handler->next->prev = handler->prev;
436      if (handler->prev)	/* watch out for g_signal_handlers_destroy()! */
437        handler->prev->next = handler->next;
438      else
439        {
440          HandlerList *hlist = handler_list_lookup (signal_id, instance);
441
442          hlist->handlers = handler->next;
443        }
444      G_UNLOCK (g_signal_mutex);
445      g_closure_unref (handler->closure);
446      G_LOCK (g_signal_mutex);
447      g_generic_node_free (&g_handler_ts, handler);
448    }
449}
450
451static void
452handler_insert (guint    signal_id,
453		gpointer instance,
454		Handler  *handler)
455{
456  HandlerList *hlist;
457
458  g_assert (handler->prev == NULL && handler->next == NULL); // FIXME: paranoid
459
460  hlist = handler_list_ensure (signal_id, instance);
461  if (!hlist->handlers)
462    hlist->handlers = handler;
463  else if (hlist->handlers->after && !handler->after)
464    {
465      handler->next = hlist->handlers;
466      hlist->handlers->prev = handler;
467      hlist->handlers = handler;
468    }
469  else
470    {
471      Handler *tmp = hlist->handlers;
472
473      if (handler->after)
474        while (tmp->next)
475          tmp = tmp->next;
476      else
477        while (tmp->next && !tmp->next->after)
478          tmp = tmp->next;
479      if (tmp->next)
480        tmp->next->prev = handler;
481      handler->next = tmp->next;
482      handler->prev = tmp;
483      tmp->next = handler;
484    }
485}
486
487static inline void
488emission_push (Emission     **emission_list_p,
489	       guint          signal_id,
490	       GQuark	      detail,
491	       gpointer       instance,
492	       EmissionState *state_p)
493{
494  Emission *emission = g_generic_node_alloc (&g_emission_ts,
495                                             sizeof (Emission),
496                                             EMISSION_PRE_ALLOC);
497  emission->next = *emission_list_p;
498  emission->signal_id = signal_id;
499  emission->detail = detail;
500  emission->instance = instance;
501  emission->state_p = state_p;
502  *emission_list_p = emission;
503}
504
505static inline void
506emission_pop (Emission     **emission_list_p,
507	      EmissionState *state_p)
508{
509  Emission **loc = emission_list_p, *emission = *loc;
510
511  while (emission->state_p != state_p)
512    {
513      loc = &emission->next;
514      emission = *loc;
515    }
516  *loc = emission->next;
517  g_generic_node_free (&g_emission_ts, emission);
518}
519
520static inline Emission*
521emission_find (Emission *emission_list,
522	       guint     signal_id,
523	       GQuark    detail,
524	       gpointer  instance)
525{
526  Emission *emission;
527
528  for (emission = emission_list; emission; emission = emission->next)
529    if (emission->instance == instance &&
530	emission->signal_id == signal_id &&
531	emission->detail == detail)
532      return emission;
533  return NULL;
534}
535
536static gint
537signal_key_cmp (gconstpointer node1,
538                gconstpointer node2)
539{
540  const SignalKey *key1 = node1, *key2 = node2;
541
542  if (key1->itype == key2->itype)
543    return G_BSEARCH_ARRAY_CMP (key1->quark, key2->quark);
544  else
545    return G_BSEARCH_ARRAY_CMP (key1->itype, key2->itype);
546}
547
548void
549g_signal_init (void) /* sync with gtype.c */
550{
551  G_LOCK (g_signal_mutex);
552  if (!g_n_signal_nodes)
553    {
554      /* setup signal key array */
555      g_signal_key_bsa.cmp_func = signal_key_cmp;
556      g_signal_key_bsa.sizeof_node = sizeof (SignalKey);
557      g_signal_key_bsa.flags = 0; /* alloc-only */
558
559      /* setup handler list binary searchable array hash table (in german, that'd be one word ;) */
560      g_handler_list_bsa_ht = g_hash_table_new (g_direct_hash, NULL);
561
562      /* invalid (0) signal_id */
563      g_n_signal_nodes = 1;
564      g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
565      g_signal_nodes[0] = NULL;
566    }
567  G_UNLOCK (g_signal_mutex);
568}
569
570void
571g_signals_destroy (GType itype)
572{
573  guint i;
574  gboolean found_one = FALSE;
575
576  G_LOCK (g_signal_mutex);
577  for (i = 0; i < g_n_signal_nodes; i++)
578    {
579      SignalNode *node = g_signal_nodes[i];
580
581      if (node->itype == itype)
582        {
583          if (node->destroyed)
584            g_warning (G_STRLOC ": signal \"%s\" of type `%s' already destroyed",
585                       node->name,
586                       g_type_name (node->itype));
587          else
588            {
589              found_one = TRUE;
590              signal_destroy_R (node);
591            }
592        }
593    }
594  if (!found_one)
595    g_warning (G_STRLOC ": type `%s' has no signals that could be destroyed",
596               g_type_name (itype));
597  G_UNLOCK (g_signal_mutex);
598}
599
600void
601g_signal_stop_emission (gpointer instance,
602                        guint    signal_id,
603			GQuark   detail)
604{
605  SignalNode *node;
606
607  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
608  g_return_if_fail (signal_id > 0);
609
610  G_LOCK (g_signal_mutex);
611  node = LOOKUP_SIGNAL_NODE (signal_id);
612  if (node && detail && !(node->flags & G_SIGNAL_DETAILED))
613    {
614      g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
615      G_UNLOCK (g_signal_mutex);
616      return;
617    }
618  if (node && g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype))
619    {
620      Emission *emission_list = node->flags & G_SIGNAL_NO_RECURSE ? g_restart_emissions : g_recursive_emissions;
621      Emission *emission = emission_find (emission_list, signal_id, detail, instance);
622
623      if (emission)
624        {
625          if (*emission->state_p == EMISSION_HOOK)
626            g_warning (G_STRLOC ": emission of signal \"%s\" for instance `%p' cannot be stopped from emission hook",
627                       node->name, instance);
628          else if (*emission->state_p == EMISSION_RUN)
629            *emission->state_p = EMISSION_STOP;
630        }
631      else
632        g_warning (G_STRLOC ": no emission of signal \"%s\" to stop for instance `%p'",
633                   node->name, instance);
634    }
635  else
636    g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
637  G_UNLOCK (g_signal_mutex);
638}
639
640guint
641g_signal_lookup (const gchar *name,
642                 GType        itype)
643{
644  guint signal_id;
645
646  g_return_val_if_fail (name != NULL, 0);
647  g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
648
649  G_LOCK (g_signal_mutex);
650  signal_id = signal_id_lookup (g_quark_try_string (name), itype);
651  G_UNLOCK (g_signal_mutex);
652
653  return signal_id;
654}
655
656gchar*
657g_signal_name (guint signal_id)
658{
659  SignalNode *node;
660  gchar *name;
661
662  G_LOCK (g_signal_mutex);
663  node = LOOKUP_SIGNAL_NODE (signal_id);
664  name = node ? node->name : NULL;
665  G_UNLOCK (g_signal_mutex);
666
667  return name;
668}
669
670void
671g_signal_query (guint         signal_id,
672		GSignalQuery *query)
673{
674  SignalNode *node;
675
676  g_return_if_fail (query != NULL);
677
678  G_LOCK (g_signal_mutex);
679  node = LOOKUP_SIGNAL_NODE (signal_id);
680  if (!node || node->destroyed)
681    query->signal_id = 0;
682  else
683    {
684      query->signal_id = node->signal_id;
685      query->signal_name = node->name;
686      query->itype = node->itype;
687      query->signal_flags = node->flags;
688      query->return_type = node->return_type;
689      query->n_params = node->n_params;
690      query->param_types = node->param_types;
691    }
692  G_UNLOCK (g_signal_mutex);
693}
694
695/**
696 * g_signal_list_ids:
697 * @itype: an
698 * @n_ids: location to store number of signal ids for @itype
699 *
700 * List all signals for a given type.
701 *
702 * Return value: Newly allocated array of signal ids.
703 **/
704guint*
705g_signal_list_ids (GType  itype,
706		   guint *n_ids)
707{
708  SignalKey *keys;
709  GArray *result;
710  guint n_nodes;
711  guint i;
712
713  g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), NULL);
714  g_return_val_if_fail (n_ids != NULL, NULL);
715
716  G_LOCK (g_signal_mutex);
717
718  keys = g_signal_key_bsa.nodes;
719  n_nodes  = g_signal_key_bsa.n_nodes;
720  result = g_array_new (FALSE, FALSE, sizeof (guint));
721
722  for (i = 0; i < n_nodes; i++)
723    if (keys[i].itype == itype)
724      {
725	gchar *name = g_quark_to_string (keys[i].quark);
726
727	/* Signal names with "_" in them are aliases to the same
728	 * name with "-" instead of "_".
729	 */
730	if (!strchr (name, '_'))
731	  g_array_append_val (result, keys[i].signal_id);
732      }
733
734  *n_ids = result->len;
735
736  G_UNLOCK (g_signal_mutex);
737
738  return (guint *) g_array_free (result, FALSE);
739}
740
741guint
742g_signal_newv (const gchar       *signal_name,
743               GType              itype,
744               GSignalFlags       signal_flags,
745               GClosure          *class_closure,
746               GSignalAccumulator accumulator,
747               GSignalCMarshaller c_marshaller,
748               GType		  return_type,
749               guint              n_params,
750               GType		 *param_types)
751{
752  gchar *name;
753  guint signal_id, i;
754  SignalNode *node;
755
756  g_return_val_if_fail (signal_name != NULL, 0);
757  g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
758  if (n_params)
759    g_return_val_if_fail (param_types != NULL, 0);
760  if (return_type != G_TYPE_NONE)
761    g_return_val_if_fail (accumulator == NULL, 0);
762
763  name = g_strdup (signal_name);
764  g_strdelimit (name, G_STR_DELIMITERS ":^", '_');  // FIXME do character checks like for types
765
766  G_LOCK (g_signal_mutex);
767
768  signal_id = signal_id_lookup (g_quark_try_string (name), itype);
769  node = LOOKUP_SIGNAL_NODE (signal_id);
770  if (node && !node->destroyed)
771    {
772      g_warning (G_STRLOC ": signal \"%s\" already exists in the `%s' %s",
773                 name,
774                 g_type_name (node->itype),
775                 G_TYPE_IS_INTERFACE (node->itype) ? "interface" : "class ancestry");
776      g_free (name);
777      G_UNLOCK (g_signal_mutex);
778      return 0;
779    }
780  if (node && node->itype != itype)
781    {
782      g_warning (G_STRLOC ": signal \"%s\" for type `%s' was previously created for type `%s'",
783                 name,
784                 g_type_name (itype),
785                 g_type_name (node->itype));
786      g_free (name);
787      G_UNLOCK (g_signal_mutex);
788      return 0;
789    }
790  for (i = 0; i < n_params; i++)
791    if (!G_TYPE_IS_VALUE (param_types[i]) ||
792	param_types[i] == G_TYPE_ENUM || param_types[i] == G_TYPE_FLAGS) /* FIXME: kludge */
793      {
794	g_warning (G_STRLOC ": parameter %d of type `%s' for signal \"%s::%s\" is not a value type",
795		   i + 1, g_type_name (param_types[i]), g_type_name (itype), name);
796	g_free (name);
797	G_UNLOCK (g_signal_mutex);
798	return 0;
799      }
800  if (return_type != G_TYPE_NONE && !G_TYPE_IS_VALUE (return_type))
801    {
802      g_warning (G_STRLOC ": return value of type `%s' for signal \"%s::%s\" is not a value type",
803		 g_type_name (param_types[i]), g_type_name (itype), name);
804      g_free (name);
805      G_UNLOCK (g_signal_mutex);
806      return 0;
807    }
808
809  /* setup permanent portion of signal node */
810  if (!node)
811    {
812      SignalKey key;
813
814      signal_id = g_n_signal_nodes++;
815      node = g_new (SignalNode, 1);
816      node->signal_id = signal_id;
817      g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
818      g_signal_nodes[signal_id] = node;
819      node->itype = itype;
820      node->name = name;
821      key.itype = itype;
822      key.quark = g_quark_from_string (node->name);
823      key.signal_id = signal_id;
824      g_bsearch_array_insert (&g_signal_key_bsa, &key, FALSE);
825      g_strdelimit (node->name, "_", '-');
826      key.quark = g_quark_from_static_string (node->name);
827      g_bsearch_array_insert (&g_signal_key_bsa, &key, FALSE);
828    }
829  node->destroyed = FALSE;
830
831  /* setup reinitializable portion */
832  node->flags = signal_flags & G_SIGNAL_FLAGS_MASK;
833  node->n_params = n_params;
834  node->param_types = g_memdup (param_types, sizeof (GType) * n_params);
835  node->return_type = return_type;
836  node->class_closure = class_closure ? g_closure_ref (class_closure) : NULL;
837  node->accumulator = accumulator;
838  node->c_marshaller = c_marshaller;
839  node->emission_hooks = NULL;
840  if (node->c_marshaller && class_closure && G_CLOSURE_NEEDS_MARSHAL (class_closure))
841    g_closure_set_marshal (class_closure, node->c_marshaller);
842
843  G_UNLOCK (g_signal_mutex);
844  return signal_id;
845}
846
847static void
848signal_destroy_R (SignalNode *signal_node)
849{
850  SignalNode node = *signal_node;
851
852  signal_node->destroyed = TRUE;
853
854  /* reentrancy caution, zero out real contents first */
855  signal_node->n_params = 0;
856  signal_node->param_types = NULL;
857  signal_node->return_type = 0;
858  signal_node->class_closure = NULL;
859  signal_node->accumulator = NULL;
860  signal_node->c_marshaller = NULL;
861  signal_node->emission_hooks = NULL;
862
863#ifndef G_DISABLE_CHECKS
864  /* check current emissions */
865  {
866    Emission *emission;
867
868    for (emission = (node.flags & G_SIGNAL_NO_RECURSE) ? g_restart_emissions : g_recursive_emissions;
869         emission; emission = emission->next)
870      if (emission->signal_id == node.signal_id)
871        g_critical (G_STRLOC ": signal \"%s\" being destroyed is currently in emission (instance `%p')",
872                    node.name, emission->instance);
873  }
874#endif
875
876  /* free contents that need to
877   */
878  G_UNLOCK (g_signal_mutex);
879  g_free (node.param_types);
880  g_closure_unref (node.class_closure);
881  if (node.emission_hooks)
882    {
883      g_hook_list_clear (node.emission_hooks);
884      g_free (node.emission_hooks);
885    }
886  G_LOCK (g_signal_mutex);
887}
888
889guint
890g_signal_connect_closure (gpointer  instance,
891			  guint     signal_id,
892			  GQuark    detail,
893			  GClosure *closure,
894			  gboolean  after)
895{
896  SignalNode *node;
897  guint handler_id = 0;
898
899  g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
900  g_return_val_if_fail (signal_id > 0, 0);
901  g_return_val_if_fail (closure != NULL, 0);
902
903  G_LOCK (g_signal_mutex);
904  node = LOOKUP_SIGNAL_NODE (signal_id);
905  if (node && detail && !(node->flags & G_SIGNAL_DETAILED))
906    {
907      g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
908      G_UNLOCK (g_signal_mutex);
909      return 0;
910    }
911  if (node && g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype))
912    {
913      Handler *handler = handler_new (after);
914
915      handler_id = handler->id;
916      handler->detail = detail;
917      handler->closure = g_closure_ref (closure);
918      handler_insert (signal_id, instance, handler);
919      if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (closure))
920	g_closure_set_marshal (closure, node->c_marshaller);
921    }
922  else
923    g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
924  G_UNLOCK (g_signal_mutex);
925
926  return handler_id;
927}
928
929void
930g_signal_handler_disconnect (gpointer instance,
931                             guint    handler_id)
932{
933  Handler *handler;
934  guint signal_id;
935
936  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
937  g_return_if_fail (handler_id > 0);
938
939  G_LOCK (g_signal_mutex);
940  handler = handler_lookup (instance, handler_id, &signal_id);
941  if (handler)
942    {
943      handler->id = 0;
944      handler->block_count = 1;
945      handler_unref_R (signal_id, instance, handler);
946    }
947  else
948    g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id);
949  G_UNLOCK (g_signal_mutex);
950}
951
952void
953g_signal_handlers_destroy (gpointer instance)
954{
955  GBSearchArray *hlbsa;
956
957  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
958
959  G_LOCK (g_signal_mutex);
960  hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
961  if (hlbsa)
962    {
963      guint i;
964
965      /* reentrancy caution, delete instance trace first */
966      g_hash_table_remove (g_handler_list_bsa_ht, instance);
967
968      for (i = 0; i < hlbsa->n_nodes; i++)
969        {
970          HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i);
971          Handler *handler = hlist->handlers;
972
973          while (handler)
974            {
975              Handler *tmp = handler;
976
977              handler = tmp->next;
978              tmp->block_count = 1;
979              /* cruel unlink, this works because _all_ handlers vanish */
980              tmp->next = NULL;
981              tmp->prev = tmp;
982              if (tmp->id)
983		{
984		  tmp->id = 0;
985		  handler_unref_R (0, NULL, tmp);
986		}
987            }
988        }
989      g_free (hlbsa->nodes);
990      g_generic_node_free (&g_bsa_ts, hlbsa);
991    }
992  G_UNLOCK (g_signal_mutex);
993}
994
995void
996g_signal_handler_block (gpointer instance,
997                        guint    handler_id)
998{
999  Handler *handler;
1000
1001  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
1002  g_return_if_fail (handler_id > 0);
1003
1004  G_LOCK (g_signal_mutex);
1005  handler = handler_lookup (instance, handler_id, NULL);
1006  if (handler)
1007    {
1008#ifndef G_DISABLE_CHECKS
1009      if (handler->block_count >= HANDLER_MAX_BLOCK_COUNT - 1)
1010        g_error (G_STRLOC ": handler block_count overflow, %s", REPORT_BUG);
1011#endif
1012
1013      handler->block_count += 1;
1014    }
1015  else
1016    g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id);
1017  G_UNLOCK (g_signal_mutex);
1018}
1019
1020void
1021g_signal_handler_unblock (gpointer instance,
1022                          guint    handler_id)
1023{
1024  Handler *handler;
1025
1026  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
1027  g_return_if_fail (handler_id > 0);
1028
1029  G_LOCK (g_signal_mutex);
1030  handler = handler_lookup (instance, handler_id, NULL);
1031  if (handler)
1032    {
1033      if (handler->block_count)
1034        handler->block_count -= 1;
1035      else
1036        g_warning (G_STRLOC ": handler `%u' of instance `%p' is not blocked", handler_id, instance);
1037    }
1038  else
1039    g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id);
1040  G_UNLOCK (g_signal_mutex);
1041}
1042
1043guint
1044g_signal_handler_find (gpointer         instance,
1045                       GSignalMatchType mask,
1046                       guint            signal_id,
1047		       GQuark		detail,
1048                       GClosure        *closure,
1049                       gpointer         func,
1050                       gpointer         data)
1051{
1052  Handler *handler = NULL;
1053  guint handler_id;
1054
1055  g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
1056  g_return_val_if_fail ((mask & ~G_SIGNAL_MATCH_MASK) == 0, 0);
1057
1058  G_LOCK (g_signal_mutex);
1059  handler = handler_find (instance, mask, signal_id, detail, closure, func, data);
1060  handler_id = handler ? handler->id : 0;
1061  G_UNLOCK (g_signal_mutex);
1062
1063  return handler_id;
1064}
1065
1066gboolean
1067g_signal_handler_pending (gpointer instance,
1068                          guint    signal_id,
1069			  GQuark   detail,
1070                          gboolean may_be_blocked)
1071{
1072  Handler *handler = NULL;
1073
1074  g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), FALSE);
1075  g_return_val_if_fail (signal_id > 0, FALSE);
1076
1077  G_LOCK (g_signal_mutex);
1078  if (detail)
1079    {
1080      SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id);
1081
1082      if (!(node->flags & G_SIGNAL_DETAILED))
1083	{
1084	  g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
1085	  G_UNLOCK (g_signal_mutex);
1086	  return FALSE;
1087	}
1088    }
1089  handler = handler_find (instance,
1090			  (G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL |
1091			   (may_be_blocked ? 0 : G_SIGNAL_MATCH_UNBLOCKED)),
1092			  signal_id, detail, NULL, NULL, NULL);
1093  G_UNLOCK (g_signal_mutex);
1094
1095  return handler != NULL;
1096}
1097
1098void
1099g_signal_emitv (const GValue *instance_and_params,
1100		guint         signal_id,
1101		GQuark	      detail,
1102		GValue       *return_value)
1103{
1104  SignalNode *node;
1105  gpointer instance;
1106  const GValue *param_values;
1107  guint i;
1108
1109  g_return_if_fail (instance_and_params != NULL);
1110  instance = g_value_get_as_pointer (instance_and_params);
1111  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
1112  g_return_if_fail (signal_id > 0);
1113
1114  param_values = instance_and_params + 1;
1115
1116  G_LOCK (g_signal_mutex);
1117  node = LOOKUP_SIGNAL_NODE (signal_id);
1118#ifndef G_DISABLE_CHECKS
1119  if (!node || !g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype))
1120    g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
1121  if (detail && !(node->flags & G_SIGNAL_DETAILED))
1122    {
1123      g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
1124      G_UNLOCK (g_signal_mutex);
1125      return;
1126    }
1127  for (i = 0; i < node->n_params; i++)
1128    if (!G_VALUE_HOLDS (param_values + i, node->param_types[i]))
1129      {
1130	g_critical (G_STRLOC ": value for `%s' parameter %u for signal \"%s\" is of type `%s'",
1131		    g_type_name (node->param_types[i]),
1132		    i,
1133		    node->name,
1134		    G_VALUE_TYPE_NAME (param_values + i));
1135	G_UNLOCK (g_signal_mutex);
1136	return;
1137      }
1138  if (node->return_type != G_TYPE_NONE)
1139    {
1140      if (!return_value)
1141	{
1142	  g_critical (G_STRLOC ": return value `%s' for signal \"%s\" is (NULL)",
1143		      g_type_name (node->return_type),
1144		      node->name);
1145	  G_UNLOCK (g_signal_mutex);
1146	  return;
1147	}
1148      else if (!node->accumulator && !G_VALUE_HOLDS (return_value, node->return_type))
1149	{
1150	  g_critical (G_STRLOC ": return value `%s' for signal \"%s\" is of type `%s'",
1151		      g_type_name (node->return_type),
1152		      node->name,
1153		      G_VALUE_TYPE_NAME (return_value));
1154	  G_UNLOCK (g_signal_mutex);
1155	  return;
1156	}
1157    }
1158  else
1159    return_value = NULL;
1160#endif	/* !G_DISABLE_CHECKS */
1161
1162  signal_emit_R (node, detail, instance, return_value, instance_and_params);
1163
1164  G_UNLOCK (g_signal_mutex);
1165}
1166
1167static void
1168signal_emit_R (SignalNode   *node,
1169	       GQuark	     detail,
1170	       gpointer      instance,
1171	       GValue	    *return_value,
1172	       const GValue *instance_and_params)
1173{
1174  EmissionState emission_state = 0;
1175  GSignalAccumulator accumulator;
1176  GSignalInvocationHint ihint;
1177  GClosure *class_closure;
1178  HandlerList *hlist;
1179  Handler *handler_list = NULL;
1180  GValue accu;
1181  gboolean accu_used = FALSE;
1182  guint signal_id = node->signal_id;
1183
1184  if (node->flags & G_SIGNAL_NO_RECURSE)
1185    {
1186      Emission *emission = emission_find (g_restart_emissions, signal_id, detail, instance);
1187
1188      if (emission)
1189	{
1190	  *emission->state_p = EMISSION_RESTART;
1191	  return;
1192	}
1193    }
1194  ihint.signal_id = node->signal_id;
1195  ihint.detail = detail;
1196  accumulator = node->accumulator;
1197  if (accumulator)
1198    {
1199      G_UNLOCK (g_signal_mutex);
1200      g_value_init (&accu, node->return_type);
1201      G_LOCK (g_signal_mutex);
1202    }
1203  emission_push ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions,
1204		 signal_id, detail, instance, &emission_state);
1205  class_closure = node->class_closure;
1206
1207 EMIT_RESTART:
1208
1209  if (handler_list)
1210    handler_unref_R (signal_id, instance, handler_list);
1211  hlist = handler_list_lookup (signal_id, instance);
1212  handler_list = hlist ? hlist->handlers : NULL;
1213  if (handler_list)
1214    handler_ref (handler_list);
1215
1216  ihint.run_type = G_SIGNAL_RUN_FIRST;
1217
1218  if ((node->flags & G_SIGNAL_RUN_FIRST) && class_closure)
1219    {
1220      emission_state = EMISSION_RUN;
1221
1222      G_UNLOCK (g_signal_mutex);
1223      if (accumulator)
1224	{
1225	  if (accu_used)
1226	    g_value_reset (&accu);
1227	  g_closure_invoke (class_closure,
1228			    &accu,
1229			    node->n_params + 1,
1230			    instance_and_params,
1231			    &ihint);
1232	  if (!accumulator (&ihint, return_value, &accu) &&
1233	      emission_state == EMISSION_RUN)
1234	    emission_state = EMISSION_STOP;
1235	  accu_used = TRUE;
1236	}
1237      else
1238	g_closure_invoke (class_closure,
1239			  return_value,
1240			  node->n_params + 1,
1241			  instance_and_params,
1242			  &ihint);
1243      G_LOCK (g_signal_mutex);
1244
1245      if (emission_state == EMISSION_STOP)
1246	goto EMIT_CLEANUP;
1247      else if (emission_state == EMISSION_RESTART)
1248	goto EMIT_RESTART;
1249    }
1250
1251  if (node->emission_hooks)
1252    {
1253      emission_state = EMISSION_HOOK;
1254
1255      G_UNLOCK (g_signal_mutex);
1256      g_print ("emission_hooks()\n");
1257      G_LOCK (g_signal_mutex);
1258
1259      if (emission_state == EMISSION_RESTART)
1260	goto EMIT_RESTART;
1261    }
1262
1263  if (handler_list)
1264    {
1265      Handler *handler = handler_list;
1266
1267      emission_state = EMISSION_RUN;
1268      handler_ref (handler);
1269      do
1270	{
1271	  Handler *tmp;
1272
1273	  if (handler->after)
1274	    {
1275	      handler_unref_R (signal_id, instance, handler_list);
1276	      handler_list = handler;
1277	      break;
1278	    }
1279	  else if (!handler->block_count && (!handler->detail || handler->detail == detail))
1280	    {
1281	      G_UNLOCK (g_signal_mutex);
1282	      if (accumulator)
1283		{
1284		  if (accu_used)
1285		    g_value_reset (&accu);
1286		  g_closure_invoke (handler->closure,
1287				    &accu,
1288				    node->n_params + 1,
1289				    instance_and_params,
1290				    &ihint);
1291		  if (!accumulator (&ihint, return_value, &accu) &&
1292		      emission_state == EMISSION_RUN)
1293		    emission_state = EMISSION_STOP;
1294		  accu_used = TRUE;
1295		}
1296	      else
1297		g_closure_invoke (handler->closure,
1298				  return_value,
1299				  node->n_params + 1,
1300				  instance_and_params,
1301				  &ihint);
1302	      G_LOCK (g_signal_mutex);
1303
1304	      tmp = emission_state == EMISSION_RUN ? handler->next : NULL;
1305	    }
1306	  else
1307	    tmp = handler->next;
1308
1309	  if (tmp)
1310	    handler_ref (tmp);
1311	  handler_unref_R (signal_id, instance, handler_list);
1312	  handler_list = handler;
1313	  handler = tmp;
1314	}
1315      while (handler);
1316
1317      if (emission_state == EMISSION_STOP)
1318	goto EMIT_CLEANUP;
1319      else if (emission_state == EMISSION_RESTART)
1320	goto EMIT_RESTART;
1321    }
1322
1323  ihint.run_type = G_SIGNAL_RUN_LAST;
1324
1325  if ((node->flags & G_SIGNAL_RUN_LAST) && class_closure)
1326    {
1327      emission_state = EMISSION_RUN;
1328
1329      G_UNLOCK (g_signal_mutex);
1330      if (accumulator)
1331	{
1332	  if (accu_used)
1333	    g_value_reset (&accu);
1334	  g_closure_invoke (class_closure,
1335			    &accu,
1336			    node->n_params + 1,
1337			    instance_and_params,
1338			    &ihint);
1339          if (!accumulator (&ihint, return_value, &accu) &&
1340	      emission_state == EMISSION_RUN)
1341	    emission_state = EMISSION_STOP;
1342	  accu_used = TRUE;
1343	}
1344      else
1345	g_closure_invoke (class_closure,
1346			  return_value,
1347			  node->n_params + 1,
1348			  instance_and_params,
1349			  &ihint);
1350      G_LOCK (g_signal_mutex);
1351
1352      if (emission_state == EMISSION_STOP)
1353	goto EMIT_CLEANUP;
1354      else if (emission_state == EMISSION_RESTART)
1355	goto EMIT_RESTART;
1356    }
1357
1358  if (handler_list)
1359    {
1360      Handler *handler = handler_list;
1361
1362      emission_state = EMISSION_RUN;
1363      handler_ref (handler);
1364      do
1365	{
1366	  Handler *tmp;
1367
1368	  if (handler->after && !handler->block_count && (!handler->detail || handler->detail == detail))
1369	    {
1370	      G_UNLOCK (g_signal_mutex);
1371              if (accumulator)
1372		{
1373		  if (accu_used)
1374		    g_value_reset (&accu);
1375		  g_closure_invoke (handler->closure,
1376				    &accu,
1377				    node->n_params + 1,
1378				    instance_and_params,
1379				    &ihint);
1380		  if (!accumulator (&ihint, return_value, &accu) &&
1381		      emission_state == EMISSION_RUN)
1382		    emission_state = EMISSION_STOP;
1383		  accu_used = TRUE;
1384		}
1385	      else
1386		g_closure_invoke (handler->closure,
1387				  return_value,
1388				  node->n_params + 1,
1389				  instance_and_params,
1390				  &ihint);
1391	      G_LOCK (g_signal_mutex);
1392
1393	      tmp = emission_state == EMISSION_RUN ? handler->next : NULL;
1394	    }
1395	  else
1396	    tmp = handler->next;
1397
1398	  if (tmp)
1399	    handler_ref (tmp);
1400	  handler_unref_R (signal_id, instance, handler);
1401	  handler = tmp;
1402	}
1403      while (handler);
1404
1405      if (emission_state == EMISSION_STOP)
1406	goto EMIT_CLEANUP;
1407      else if (emission_state == EMISSION_RESTART)
1408	goto EMIT_RESTART;
1409    }
1410
1411 EMIT_CLEANUP:
1412
1413  ihint.run_type = G_SIGNAL_RUN_CLEANUP;
1414
1415  if ((node->flags & G_SIGNAL_RUN_CLEANUP) && class_closure)
1416    {
1417      gboolean need_unset = FALSE;
1418
1419      emission_state = EMISSION_STOP;
1420
1421      G_UNLOCK (g_signal_mutex);
1422      if (node->return_type != G_TYPE_NONE)
1423	{
1424	  if (!accumulator)
1425	    {
1426	      g_value_init (&accu, node->return_type);
1427	      need_unset = TRUE;
1428	    }
1429	  else if (accu_used)
1430	    g_value_reset (&accu);
1431	}
1432      g_closure_invoke (class_closure,
1433			node->return_type != G_TYPE_NONE ? &accu : NULL,
1434			node->n_params + 1,
1435			instance_and_params,
1436			&ihint);
1437      if (need_unset)
1438	g_value_unset (&accu);
1439      G_LOCK (g_signal_mutex);
1440
1441      if (emission_state == EMISSION_RESTART)
1442	goto EMIT_RESTART;
1443    }
1444
1445  if (handler_list)
1446    handler_unref_R (signal_id, instance, handler_list);
1447
1448  emission_pop ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions, &emission_state);
1449  if (accumulator)
1450    {
1451      G_UNLOCK (g_signal_mutex);
1452      g_value_unset (&accu);
1453      G_LOCK (g_signal_mutex);
1454    }
1455}
1456