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