]> Pileus Git - ~andy/gtk/blob - gtk/gtksignal.c
Fix C++ comment.
[~andy/gtk] / gtk / gtksignal.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * 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
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <stdarg.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include "gtksignal.h"
31 #include "gtkargcollector.c"
32
33
34 #define SIGNAL_BLOCK_SIZE               (100)
35 #define HANDLER_BLOCK_SIZE              (200)
36 #define EMISSION_BLOCK_SIZE             (100)
37 #define DISCONNECT_INFO_BLOCK_SIZE      (64)
38 #define MAX_SIGNAL_PARAMS               (31)
39
40 enum
41 {
42   EMISSION_CONTINUE,
43   EMISSION_RESTART,
44   EMISSION_DONE
45 };
46
47 #define GTK_RUN_TYPE(x)  ((x) & GTK_RUN_BOTH)
48
49
50 typedef struct _GtkSignal               GtkSignal;
51 typedef struct _GtkSignalHash           GtkSignalHash;
52 typedef struct _GtkHandler              GtkHandler;
53 typedef struct _GtkEmission             GtkEmission;
54 typedef struct _GtkEmissionHookData     GtkEmissionHookData;
55 typedef struct _GtkDisconnectInfo       GtkDisconnectInfo;
56
57 typedef void (*GtkSignalMarshaller0) (GtkObject *object,
58                                       gpointer   data);
59
60 struct _GtkSignal
61 {
62   guint               signal_id;
63   GtkType             object_type;
64   gchar              *name;
65   guint               function_offset;
66   GtkSignalMarshaller marshaller;
67   GtkType             return_val;
68   guint               signal_flags : 16;
69   guint               nparams : 16;
70   GtkType            *params;
71   GHookList          *hook_list;
72 };
73
74 struct _GtkSignalHash
75 {
76   GtkType object_type;
77   GQuark  quark;
78   guint   signal_id;
79 };
80
81 struct _GtkHandler
82 {
83   guint            id;
84   GtkHandler      *next;
85   GtkHandler      *prev;
86   guint            blocked : 20;
87   guint            object_signal : 1;
88   guint            after : 1;
89   guint            no_marshal : 1;
90   guint16          ref_count;
91   guint16          signal_id;
92   GtkSignalFunc    func;
93   gpointer         func_data;
94   GtkSignalDestroy destroy_func;
95 };
96
97 struct _GtkEmission
98 {
99   GtkObject   *object;
100   guint16      signal_id;
101   guint        in_hook : 1;
102   GtkEmission *next;
103 };
104
105 struct _GtkEmissionHookData
106 {
107   GtkObject *object;
108   guint signal_id;
109   guint n_params;
110   GtkArg *params;
111 };
112
113 struct _GtkDisconnectInfo
114 {
115   GtkObject     *object1;
116   guint          disconnect_handler1;
117   guint          signal_handler;
118   GtkObject     *object2;
119   guint          disconnect_handler2;
120 };
121
122
123 static guint        gtk_signal_hash            (gconstpointer h);
124 static gint         gtk_signal_compare         (gconstpointer h1,
125                                                 gconstpointer h2);
126 static GtkHandler*  gtk_signal_handler_new     (void);
127 static void         gtk_signal_handler_ref     (GtkHandler    *handler);
128 static void         gtk_signal_handler_unref   (GtkHandler    *handler,
129                                                 GtkObject     *object);
130 static void         gtk_signal_handler_insert  (GtkObject     *object,
131                                                 GtkHandler    *handler);
132 static void         gtk_signal_real_emit       (GtkObject     *object,
133                                                 guint          signal_id,
134                                                 GtkArg        *params);
135 static guint        gtk_signal_connect_by_type (GtkObject     *object,
136                                                 guint          signal_id,
137                                                 GtkSignalFunc  func,
138                                                 gpointer       func_data,
139                                                 GtkSignalDestroy destroy_func,
140                                                 gint           object_signal,
141                                                 gint           after,
142                                                 gint           no_marshal);
143 static guint        gtk_alive_disconnecter     (GtkDisconnectInfo *info);
144 static GtkEmission* gtk_emission_new           (void);
145 static void         gtk_emission_add           (GtkEmission   **emissions,
146                                                 GtkObject      *object,
147                                                 guint           signal_type);
148 static void         gtk_emission_remove        (GtkEmission   **emissions,
149                                                 GtkObject      *object,
150                                                 guint           signal_type);
151 static gint         gtk_emission_check         (GtkEmission    *emissions,
152                                                 GtkObject      *object,
153                                                 guint           signal_type);
154 static gint         gtk_handlers_run           (GtkHandler     *handlers,
155                                                 GtkSignal      *signal,
156                                                 GtkObject      *object,
157                                                 GtkArg         *params,
158                                                 gint            after);
159 static gboolean gtk_emission_hook_marshaller   (GHook          *hook,
160                                                 gpointer        data);
161 static gboolean gtk_signal_collect_params      (GtkArg         *params,
162                                                 guint           nparams,
163                                                 GtkType        *param_types,
164                                                 GtkType         return_type,
165                                                 va_list         var_args);
166
167 #define LOOKUP_SIGNAL_ID(signal_id)     ( \
168   signal_id > 0 && signal_id < _gtk_private_n_signals ? \
169     (GtkSignal*) _gtk_private_signals + signal_id : \
170     (GtkSignal*) 0 \
171 )
172
173
174 static GtkSignalMarshal global_marshaller = NULL;
175 static GtkSignalDestroy global_destroy_notify = NULL;
176
177 static guint                     gtk_handler_id = 1;
178 static guint                     gtk_handler_quark = 0;
179 static GHashTable               *gtk_signal_hash_table = NULL;
180 #ifdef G_OS_WIN32
181 #define EXPORT __declspec(dllexport)
182 #else
183 #define EXPORT
184 #endif
185 EXPORT GtkSignal                *_gtk_private_signals = NULL;
186 EXPORT guint                     _gtk_private_n_signals = 0;
187 static GMemChunk                *gtk_signal_hash_mem_chunk = NULL;
188 static GMemChunk                *gtk_disconnect_info_mem_chunk = NULL;
189 static GtkHandler               *gtk_handler_free_list = NULL;
190 static GtkEmission              *gtk_free_emissions = NULL;
191
192
193
194 static GtkEmission *current_emissions = NULL;
195 static GtkEmission *stop_emissions = NULL;
196 static GtkEmission *restart_emissions = NULL;
197
198 static GtkSignal*
199 gtk_signal_next_and_invalidate (void)
200 {
201   static guint gtk_n_free_signals = 0;
202   register GtkSignal *signal;
203   register guint new_signal_id;
204   
205   /* don't keep *any* GtkSignal pointers across invokation of this function!!!
206    */
207   
208   if (gtk_n_free_signals == 0)
209     {
210       register guint i;
211       register guint size;
212       
213       /* nearest pow
214        */
215       size = _gtk_private_n_signals + SIGNAL_BLOCK_SIZE;
216       size *= sizeof (GtkSignal);
217       i = 1;
218       while (i < size)
219         i <<= 1;
220       size = i;
221       
222       _gtk_private_signals = g_realloc (_gtk_private_signals, size);
223       
224       gtk_n_free_signals = size / sizeof (GtkSignal) - _gtk_private_n_signals;
225       
226       memset (_gtk_private_signals + _gtk_private_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
227     }
228   
229   new_signal_id = _gtk_private_n_signals++;
230   gtk_n_free_signals--;
231
232   g_assert (_gtk_private_n_signals < 65535);
233   
234   signal = LOOKUP_SIGNAL_ID (new_signal_id);
235   if (signal)
236     signal->signal_id = new_signal_id;
237   
238   return signal;
239 }
240
241 static inline GtkHandler*
242 gtk_signal_get_handlers (GtkObject *object,
243                          guint      signal_id)
244 {
245   GtkHandler *handlers;
246   
247   handlers = gtk_object_get_data_by_id (object, gtk_handler_quark);
248   
249   while (handlers)
250     {
251       if (handlers->signal_id == signal_id)
252         return handlers;
253       handlers = handlers->next;
254     }
255   
256   return NULL;
257 }
258
259 void
260 gtk_signal_init (void)
261 {
262   if (!gtk_handler_quark)
263     {
264       GtkSignal *zero;
265       
266       zero = gtk_signal_next_and_invalidate ();
267       g_assert (zero == NULL);
268       
269       gtk_handler_quark = g_quark_from_static_string ("gtk-signal-handlers");
270       
271       gtk_signal_hash_mem_chunk =
272         g_mem_chunk_new ("GtkSignalHash mem chunk",
273                          sizeof (GtkSignalHash),
274                          sizeof (GtkSignalHash) * SIGNAL_BLOCK_SIZE,
275                          G_ALLOC_ONLY);
276       gtk_disconnect_info_mem_chunk =
277         g_mem_chunk_new ("GtkDisconnectInfo mem chunk",
278                          sizeof (GtkDisconnectInfo),
279                          sizeof (GtkDisconnectInfo) * DISCONNECT_INFO_BLOCK_SIZE,
280                          G_ALLOC_AND_FREE);
281       gtk_handler_free_list = NULL;
282       gtk_free_emissions = NULL;
283       
284       gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash,
285                                                 gtk_signal_compare);
286     }
287 }
288
289 guint
290 gtk_signal_newv (const gchar         *r_name,
291                  GtkSignalRunType     signal_flags,
292                  GtkType              object_type,
293                  guint                function_offset,
294                  GtkSignalMarshaller  marshaller,
295                  GtkType              return_val,
296                  guint                nparams,
297                  GtkType             *params)
298 {
299   GtkSignal *signal;
300   GtkSignalHash *hash;
301   GQuark quark;
302   guint i;
303   gchar *name;
304   
305   g_return_val_if_fail (r_name != NULL, 0);
306   g_return_val_if_fail (marshaller != NULL, 0);
307   g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
308   if (nparams)
309     g_return_val_if_fail (params != NULL, 0);
310   
311   if (!gtk_handler_quark)
312     gtk_signal_init ();
313
314
315   name = g_strdup (r_name);
316   g_strdelimit (name, NULL, '_');
317
318   quark = gtk_signal_lookup (name, object_type);
319   if (quark)
320     {
321       g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
322                  r_name,
323                  gtk_type_name (object_type));
324       g_free (name);
325       return 0;
326     }
327   
328   if (return_val != GTK_TYPE_NONE &&
329       (signal_flags & GTK_RUN_BOTH) == GTK_RUN_FIRST)
330     {
331       g_warning ("gtk_signal_newv(): signal \"%s\" - return value `%s' incompatible with GTK_RUN_FIRST",
332                  name, gtk_type_name (return_val));
333       g_free (name);
334       return 0;
335     }
336   
337   signal = gtk_signal_next_and_invalidate ();
338   
339   /* signal->signal_id already set */
340   
341   signal->object_type = object_type;
342   signal->name = name;
343   signal->function_offset = function_offset;
344   signal->marshaller = marshaller;
345   signal->return_val = return_val;
346   signal->signal_flags = signal_flags;
347   signal->nparams = nparams;
348   signal->hook_list = NULL;
349   
350   if (nparams > 0)
351     {
352       signal->params = g_new (GtkType, nparams);
353       
354       for (i = 0; i < nparams; i++)
355         signal->params[i] = params[i];
356     }
357   else
358     signal->params = NULL;
359
360   /* insert "signal_name" into hash table
361    */
362   hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
363   hash->object_type = object_type;
364   hash->quark = g_quark_from_string (signal->name);
365   hash->signal_id = signal->signal_id;
366   g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
367
368   /* insert "signal-name" into hash table
369    */
370   g_strdelimit (signal->name, NULL, '-');
371   quark = g_quark_from_static_string (signal->name);
372   if (quark != hash->quark)
373     {
374       hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
375       hash->object_type = object_type;
376       hash->quark = quark;
377       hash->signal_id = signal->signal_id;
378       g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
379     }
380   
381   return signal->signal_id;
382 }
383
384 guint
385 gtk_signal_new (const gchar         *name,
386                 GtkSignalRunType     signal_flags,
387                 GtkType              object_type,
388                 guint                function_offset,
389                 GtkSignalMarshaller  marshaller,
390                 GtkType              return_val,
391                 guint                nparams,
392                 ...)
393 {
394   GtkType *params;
395   guint i;
396   va_list args;
397   guint signal_id;
398   
399   g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
400   
401   if (nparams > 0)
402     {
403       params = g_new (GtkType, nparams);
404       
405       va_start (args, nparams);
406       
407       for (i = 0; i < nparams; i++)
408         params[i] = va_arg (args, GtkType);
409       
410       va_end (args);
411     }
412   else
413     params = NULL;
414   
415   signal_id = gtk_signal_newv (name,
416                                signal_flags,
417                                object_type,
418                                function_offset,
419                                marshaller,
420                                return_val,
421                                nparams,
422                                params);
423   
424   g_free (params);
425   
426   return signal_id;
427 }
428
429 guint
430 gtk_signal_lookup (const gchar *name,
431                    GtkType      object_type)
432 {
433   GtkSignalHash hash;
434   GtkType lookup_type;
435   gpointer class = NULL;
436
437   g_return_val_if_fail (name != NULL, 0);
438   g_return_val_if_fail (GTK_TYPE_IS_OBJECT (object_type), 0);
439   
440  relookup:
441
442   lookup_type = object_type;
443   hash.quark = g_quark_try_string (name);
444   if (hash.quark)
445     {
446       while (lookup_type)
447         {
448           guint signal_id;
449           
450           hash.object_type = lookup_type;
451           
452           signal_id = GPOINTER_TO_UINT (g_hash_table_lookup (gtk_signal_hash_table, &hash));
453           if (signal_id)
454             return signal_id;
455           
456           lookup_type = gtk_type_parent (lookup_type);
457         }
458     }
459
460   if (!class)
461     {
462       class = gtk_type_class (object_type);
463       goto relookup;
464     }
465
466   return 0;
467 }
468
469 GtkSignalQuery*
470 gtk_signal_query (guint signal_id)
471 {
472   GtkSignalQuery *query;
473   GtkSignal *signal;
474   
475   g_return_val_if_fail (signal_id >= 1, NULL);
476   
477   signal = LOOKUP_SIGNAL_ID (signal_id);
478   if (signal)
479     {
480       query = g_new (GtkSignalQuery, 1);
481       
482       query->object_type = signal->object_type;
483       query->signal_id = signal_id;
484       query->signal_name = signal->name;
485       query->is_user_signal = signal->function_offset == 0;
486       query->signal_flags = signal->signal_flags;
487       query->return_val = signal->return_val;
488       query->nparams = signal->nparams;
489       query->params = signal->params;
490     }
491   else
492     query = NULL;
493   
494   return query;
495 }
496
497 gchar*
498 gtk_signal_name (guint signal_id)
499 {
500   GtkSignal *signal;
501   
502   g_return_val_if_fail (signal_id >= 1, NULL);
503   
504   signal = LOOKUP_SIGNAL_ID (signal_id);
505   if (signal)
506     return signal->name;
507   
508   return NULL;
509 }
510
511 void
512 gtk_signal_emitv (GtkObject           *object,
513                   guint                signal_id,
514                   GtkArg              *params)
515 {
516   GtkSignal *signal;
517
518   g_return_if_fail (object != NULL);
519   g_return_if_fail (signal_id >= 1);
520   
521   signal = LOOKUP_SIGNAL_ID (signal_id);
522   g_return_if_fail (signal != NULL);
523   g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
524
525   if (signal->nparams > 0)
526     g_return_if_fail (params != NULL);
527
528   gtk_signal_real_emit (object, signal_id, params);
529 }
530
531 void
532 gtk_signal_emit (GtkObject *object,
533                  guint      signal_id,
534                  ...)
535 {
536   GtkSignal *signal;
537   va_list    args;
538   GtkArg     params[MAX_SIGNAL_PARAMS + 1];
539   gboolean   abort;
540
541   g_return_if_fail (object != NULL);
542   g_return_if_fail (signal_id >= 1);
543   
544   signal = LOOKUP_SIGNAL_ID (signal_id);
545   g_return_if_fail (signal != NULL);
546   g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
547
548   va_start (args, signal_id);
549   abort = gtk_signal_collect_params (params,
550                                      signal->nparams,
551                                      signal->params,
552                                      signal->return_val,
553                                      args);
554   va_end (args);
555
556   if (!abort)
557     gtk_signal_real_emit (object, signal_id, params);
558 }
559
560 void
561 gtk_signal_emitv_by_name (GtkObject           *object,
562                           const gchar         *name,
563                           GtkArg              *params)
564 {
565   guint signal_id;
566   
567   g_return_if_fail (object != NULL);
568   g_return_if_fail (name != NULL);
569   g_return_if_fail (params != NULL);
570   
571   signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
572   
573   if (signal_id >= 1)
574     {
575       GtkSignal *signal;
576       
577       signal = LOOKUP_SIGNAL_ID (signal_id);
578       g_return_if_fail (signal != NULL);
579       g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
580
581       gtk_signal_real_emit (object, signal_id, params);
582     }
583   else
584     {
585       g_warning ("gtk_signal_emitv_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
586                  name,
587                  gtk_type_name (GTK_OBJECT_TYPE (object)));
588     }
589 }
590
591 void
592 gtk_signal_emit_by_name (GtkObject       *object,
593                          const gchar     *name,
594                          ...)
595 {
596   guint signal_id;
597   
598   g_return_if_fail (object != NULL);
599   g_return_if_fail (name != NULL);
600   
601   signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
602   
603   if (signal_id >= 1)
604     {
605       GtkSignal *signal;
606       GtkArg     params[MAX_SIGNAL_PARAMS + 1];
607       va_list    args;
608       gboolean   abort;
609       
610       signal = LOOKUP_SIGNAL_ID (signal_id);
611       g_return_if_fail (signal != NULL);
612       g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
613
614       va_start (args, name);
615       abort = gtk_signal_collect_params (params,
616                                          signal->nparams,
617                                          signal->params,
618                                          signal->return_val,
619                                          args);
620       va_end (args);
621
622       if (!abort)
623         gtk_signal_real_emit (object, signal_id, params);
624     }
625   else
626     {
627       g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
628                  name,
629                  gtk_type_name (GTK_OBJECT_TYPE (object)));
630     }
631 }
632
633 void
634 gtk_signal_emit_stop (GtkObject *object,
635                       guint       signal_id)
636 {
637   gint state;
638
639   g_return_if_fail (object != NULL);
640   g_return_if_fail (signal_id >= 1);
641   
642   state = gtk_emission_check (current_emissions, object, signal_id);
643   if (state > 1)
644     g_warning ("gtk_signal_emit_stop(): emission (%u) for object `%s' cannot be stopped from emission hook",
645                signal_id,
646                gtk_type_name (GTK_OBJECT_TYPE (object)));
647   else if (state)
648     {
649       if (!gtk_emission_check (stop_emissions, object, signal_id))
650         gtk_emission_add (&stop_emissions, object, signal_id);
651     }
652   else
653     g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
654                signal_id,
655                gtk_type_name (GTK_OBJECT_TYPE (object)));
656 }
657
658 void
659 gtk_signal_emit_stop_by_name (GtkObject       *object,
660                               const gchar     *name)
661 {
662   guint signal_id;
663   
664   g_return_if_fail (object != NULL);
665   g_return_if_fail (name != NULL);
666   
667   signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
668   if (signal_id)
669     gtk_signal_emit_stop (object, signal_id);
670   else
671     g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
672                name,
673                gtk_type_name (GTK_OBJECT_TYPE (object)));
674 }
675
676 guint
677 gtk_signal_n_emissions (GtkObject  *object,
678                         guint       signal_id)
679 {
680   GtkEmission *emission;
681   guint n;
682   
683   g_return_val_if_fail (object != NULL, 0);
684   g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
685   
686   n = 0;
687   for (emission = current_emissions; emission; emission = emission->next)
688     {
689       if (emission->object == object && emission->signal_id == signal_id)
690         n++;
691     }
692   
693   return n;
694 }
695
696 guint
697 gtk_signal_n_emissions_by_name (GtkObject       *object,
698                                 const gchar     *name)
699 {
700   guint signal_id;
701   guint n;
702   
703   g_return_val_if_fail (object != NULL, 0);
704   g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
705   g_return_val_if_fail (name != NULL, 0);
706   
707   signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
708   if (signal_id)
709     n = gtk_signal_n_emissions (object, signal_id);
710   else
711     {
712       g_warning ("gtk_signal_n_emissions_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
713                  name,
714                  gtk_type_name (GTK_OBJECT_TYPE (object)));
715       n = 0;
716     }
717   
718   return n;
719 }
720
721 guint
722 gtk_signal_connect (GtkObject     *object,
723                     const gchar   *name,
724                     GtkSignalFunc  func,
725                     gpointer       func_data)
726 {
727   guint signal_id;
728   
729   g_return_val_if_fail (object != NULL, 0);
730   g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
731   
732   signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
733   if (!signal_id)
734     {
735       g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
736                  name,
737                  gtk_type_name (GTK_OBJECT_TYPE (object)));
738       return 0;
739     }
740   
741   return gtk_signal_connect_by_type (object, signal_id, 
742                                      func, func_data, NULL,
743                                      FALSE, FALSE, FALSE);
744 }
745
746 guint
747 gtk_signal_connect_after (GtkObject     *object,
748                           const gchar   *name,
749                           GtkSignalFunc  func,
750                           gpointer       func_data)
751 {
752   guint signal_id;
753   
754   g_return_val_if_fail (object != NULL, 0);
755   
756   signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
757   if (!signal_id)
758     {
759       g_warning ("gtk_signal_connect_after(): could not find signal \"%s\" in the `%s' class ancestry",
760                  name,
761                  gtk_type_name (GTK_OBJECT_TYPE (object)));
762       return 0;
763     }
764   
765   return gtk_signal_connect_by_type (object, signal_id, 
766                                      func, func_data, NULL,
767                                      FALSE, TRUE, FALSE);
768 }
769
770 guint   
771 gtk_signal_connect_full (GtkObject           *object,
772                          const gchar         *name,
773                          GtkSignalFunc        func,
774                          GtkCallbackMarshal   marshal,
775                          gpointer             func_data,
776                          GtkDestroyNotify     destroy_func,
777                          gint                 object_signal,
778                          gint                 after)
779 {
780   guint signal_id;
781   
782   g_return_val_if_fail (object != NULL, 0);
783   
784   signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
785   if (!signal_id)
786     {
787       g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
788                  name,
789                  gtk_type_name (GTK_OBJECT_TYPE (object)));
790       return 0;
791     }
792   
793   if (marshal)
794     return gtk_signal_connect_by_type (object, signal_id, (GtkSignalFunc) marshal, 
795                                        func_data, destroy_func, 
796                                        object_signal, after, TRUE);
797   else
798     return gtk_signal_connect_by_type (object, signal_id, func, 
799                                        func_data, destroy_func, 
800                                        object_signal, after, FALSE);
801 }
802
803 guint
804 gtk_signal_connect_object (GtkObject     *object,
805                            const gchar   *name,
806                            GtkSignalFunc  func,
807                            GtkObject     *slot_object)
808 {
809   guint signal_id;
810   
811   g_return_val_if_fail (object != NULL, 0);
812   /* slot_object needs to be treated as ordinary pointer
813    */
814   
815   signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
816   if (!signal_id)
817     {
818       g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
819                  name,
820                  gtk_type_name (GTK_OBJECT_TYPE (object)));
821       return 0;
822     }
823   
824   return gtk_signal_connect_by_type (object, signal_id, 
825                                      func, slot_object, NULL,
826                                      TRUE, FALSE, FALSE);
827 }
828
829 guint
830 gtk_signal_connect_object_after (GtkObject     *object,
831                                  const gchar   *name,
832                                  GtkSignalFunc  func,
833                                  GtkObject     *slot_object)
834 {
835   guint signal_id;
836   
837   g_return_val_if_fail (object != NULL, 0);
838   
839   signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
840   if (!signal_id)
841     {
842       g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
843                  name,
844                  gtk_type_name (GTK_OBJECT_TYPE (object)));
845       return 0;
846     }
847   
848   return gtk_signal_connect_by_type (object, signal_id, 
849                                      func, slot_object, NULL,
850                                      TRUE, TRUE, FALSE);
851 }
852
853 void
854 gtk_signal_connect_while_alive (GtkObject        *object,
855                                 const gchar      *signal,
856                                 GtkSignalFunc     func,
857                                 gpointer          func_data,
858                                 GtkObject        *alive_object)
859 {
860   GtkDisconnectInfo *info;
861   
862   g_return_if_fail (object != NULL);
863   g_return_if_fail (GTK_IS_OBJECT (object));
864   g_return_if_fail (signal != NULL);
865   g_return_if_fail (func != NULL);
866   g_return_if_fail (alive_object != NULL);
867   g_return_if_fail (GTK_IS_OBJECT (alive_object));
868   
869   info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
870   info->object1 = object;
871   info->object2 = alive_object;
872   
873   info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
874   info->disconnect_handler1 =
875     gtk_signal_connect_object (info->object1,
876                                "destroy",
877                                GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
878                                (GtkObject*) info);
879   info->disconnect_handler2 =
880     gtk_signal_connect_object (info->object2,
881                                "destroy",
882                                GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
883                                (GtkObject*) info);
884 }
885
886 void
887 gtk_signal_connect_object_while_alive (GtkObject        *object,
888                                        const gchar      *signal,
889                                        GtkSignalFunc     func,
890                                        GtkObject        *alive_object)
891 {
892   GtkDisconnectInfo *info;
893   
894   g_return_if_fail (object != NULL);
895   g_return_if_fail (GTK_IS_OBJECT (object));
896   g_return_if_fail (signal != NULL);
897   g_return_if_fail (func != NULL);
898   g_return_if_fail (alive_object != NULL);
899   g_return_if_fail (GTK_IS_OBJECT (alive_object));
900   
901   info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
902   info->object1 = object;
903   info->object2 = alive_object;
904   
905   info->signal_handler = gtk_signal_connect_object (object, signal, func, alive_object);
906   info->disconnect_handler1 =
907     gtk_signal_connect_object (info->object1,
908                                "destroy",
909                                GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
910                                (GtkObject*) info);
911   info->disconnect_handler2 =
912     gtk_signal_connect_object (info->object2,
913                                "destroy",
914                                GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
915                                (GtkObject*) info);
916 }
917
918 void
919 gtk_signal_disconnect (GtkObject *object,
920                        guint      handler_id)
921 {
922   GtkHandler *handler;
923   
924   g_return_if_fail (object != NULL);
925   g_return_if_fail (handler_id > 0);
926   
927   handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
928   
929   while (handler)
930     {
931       if (handler->id == handler_id)
932         {
933           handler->id = 0;
934           handler->blocked += 1;
935           gtk_signal_handler_unref (handler, object);
936           return;
937         }
938       handler = handler->next;
939     }
940   
941   g_warning ("gtk_signal_disconnect(): could not find handler (%u)", handler_id);
942 }
943
944 void
945 gtk_signal_disconnect_by_func (GtkObject     *object,
946                                GtkSignalFunc  func,
947                                gpointer       data)
948 {
949   GtkHandler *handler;
950   gint found_one;
951   
952   g_return_if_fail (object != NULL);
953   g_return_if_fail (func != NULL);
954   
955   found_one = FALSE;
956   handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
957   
958   while (handler)
959     {
960       GtkHandler *handler_next;
961       
962       handler_next = handler->next;
963       if ((handler->id > 0) &&
964           (handler->func == func) &&
965           (handler->func_data == data))
966         {
967           found_one = TRUE;
968           handler->id = 0;
969           handler->blocked += 1;
970           gtk_signal_handler_unref (handler, object);
971         }
972       handler = handler_next;
973     }
974   
975   if (!found_one)
976     g_warning ("gtk_signal_disconnect_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
977 }
978
979 void
980 gtk_signal_disconnect_by_data (GtkObject *object,
981                                gpointer   data)
982 {
983   GtkHandler *handler;
984   gint found_one;
985   
986   g_return_if_fail (object != NULL);
987   
988   found_one = FALSE;
989   handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
990   
991   while (handler)
992     {
993       GtkHandler *handler_next;
994       
995       handler_next = handler->next;
996       if ((handler->id > 0) &&
997           (handler->func_data == data))
998         {
999           found_one = TRUE;
1000           handler->id = 0;
1001           handler->blocked += 1;
1002           gtk_signal_handler_unref (handler, object);
1003         }
1004       handler = handler_next;
1005     }
1006   
1007   if (!found_one)
1008     g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1009 }
1010
1011 void
1012 gtk_signal_handler_block (GtkObject *object,
1013                           guint      handler_id)
1014 {
1015   GtkHandler *handler;
1016   
1017   g_return_if_fail (object != NULL);
1018   g_return_if_fail (handler_id > 0);
1019   
1020   handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1021   
1022   while (handler)
1023     {
1024       if (handler->id == handler_id)
1025         {
1026           handler->blocked += 1;
1027           return;
1028         }
1029       handler = handler->next;
1030     }
1031   
1032   g_warning ("gtk_signal_handler_block(): could not find handler (%u)", handler_id);
1033 }
1034
1035 void
1036 gtk_signal_handler_block_by_func (GtkObject     *object,
1037                                   GtkSignalFunc  func,
1038                                   gpointer       data)
1039 {
1040   GtkHandler *handler;
1041   gint found_one;
1042   
1043   g_return_if_fail (object != NULL);
1044   g_return_if_fail (func != NULL);
1045   
1046   found_one = FALSE;
1047   handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1048   
1049   while (handler)
1050     {
1051       if ((handler->id > 0) &&
1052           (handler->func == func) &&
1053           (handler->func_data == data))
1054         {
1055           found_one = TRUE;
1056           handler->blocked += 1;
1057         }
1058       handler = handler->next;
1059     }
1060   
1061   if (!found_one)
1062     g_warning ("gtk_signal_handler_block_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1063 }
1064
1065 void
1066 gtk_signal_handler_block_by_data (GtkObject *object,
1067                                   gpointer   data)
1068 {
1069   GtkHandler *handler;
1070   gint found_one;
1071   
1072   g_return_if_fail (object != NULL);
1073   
1074   found_one = FALSE;
1075   handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1076   
1077   while (handler)
1078     {
1079       if ((handler->id > 0) &&
1080           (handler->func_data == data))
1081         {
1082           found_one = TRUE;
1083           handler->blocked += 1;
1084         }
1085       handler = handler->next;
1086     }
1087   
1088   if (!found_one)
1089     g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1090 }
1091
1092 void
1093 gtk_signal_handler_unblock (GtkObject *object,
1094                             guint      handler_id)
1095 {
1096   GtkHandler *handler;
1097   
1098   g_return_if_fail (object != NULL);
1099   g_return_if_fail (handler_id > 0);
1100   
1101   handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1102   
1103   while (handler)
1104     {
1105       if (handler->id == handler_id)
1106         {
1107           if (handler->blocked > 0)
1108             handler->blocked -= 1;
1109           else
1110             g_warning ("gtk_signal_handler_unblock(): handler (%u) is not blocked", handler_id);
1111           return;
1112         }
1113       handler = handler->next;
1114     }
1115   
1116   g_warning ("gtk_signal_handler_unblock(): could not find handler (%u)", handler_id);
1117 }
1118
1119 void
1120 gtk_signal_handler_unblock_by_func (GtkObject     *object,
1121                                     GtkSignalFunc  func,
1122                                     gpointer       data)
1123 {
1124   GtkHandler *handler;
1125   gint found_one;
1126   
1127   g_return_if_fail (object != NULL);
1128   g_return_if_fail (func != NULL);
1129   
1130   found_one = FALSE;
1131   handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1132   
1133   while (handler)
1134     {
1135       if ((handler->id > 0) &&
1136           (handler->func == func) &&
1137           (handler->func_data == data) &&
1138           (handler->blocked > 0))
1139         {
1140           handler->blocked -= 1;
1141           found_one = TRUE;
1142         }
1143       handler = handler->next;
1144     }
1145   
1146   if (!found_one)
1147     g_warning ("gtk_signal_handler_unblock_by_func(): could not find blocked handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1148 }
1149
1150 void
1151 gtk_signal_handler_unblock_by_data (GtkObject *object,
1152                                     gpointer   data)
1153 {
1154   GtkHandler *handler;
1155   gint found_one;
1156   
1157   g_return_if_fail (object != NULL);
1158   
1159   found_one = FALSE;
1160   handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1161   
1162   while (handler)
1163     {
1164       if ((handler->id > 0) &&
1165           (handler->func_data == data) &&
1166           (handler->blocked > 0))
1167         {
1168           handler->blocked -= 1;
1169           found_one = TRUE;
1170         }
1171       handler = handler->next;
1172     }
1173   
1174   if (!found_one)
1175     g_warning ("gtk_signal_handler_unblock_by_data(): could not find blocked handler containing data (0x%0lX)", (long) data);
1176 }
1177
1178 void
1179 gtk_signal_handlers_destroy (GtkObject *object)
1180 {
1181   GtkHandler *handler;
1182   
1183   /* we make the "optimization" of destroying the first handler in the last
1184    * place, since we don't want gtk_signal_handler_unref() to reset the objects
1185    * handler_key data on each removal
1186    */
1187   
1188   handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1189   if (handler)
1190     {
1191       handler = handler->next;
1192       while (handler)
1193         {
1194           GtkHandler *next;
1195           
1196           next = handler->next;
1197           if (handler->id > 0)
1198             {
1199               handler->id = 0;
1200               handler->blocked += 1;
1201               gtk_signal_handler_unref (handler, object);
1202             }
1203           handler = next;
1204         }
1205       handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1206       if (handler->id > 0)
1207         {
1208           handler->id = 0;
1209           handler->blocked += 1;
1210           gtk_signal_handler_unref (handler, object);
1211         }
1212     }
1213 }
1214
1215 void
1216 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
1217                       GtkSignalDestroy destroy_func)
1218 {
1219   global_marshaller = marshal_func;
1220   global_destroy_notify = destroy_func;
1221 }
1222
1223 static guint
1224 gtk_signal_hash (gconstpointer h)
1225 {
1226   register const GtkSignalHash *hash = h;
1227   
1228   return hash->object_type ^ hash->quark;
1229 }
1230
1231 static gint
1232 gtk_signal_compare (gconstpointer h1,
1233                     gconstpointer h2)
1234 {
1235   register const GtkSignalHash *hash1 = h1;
1236   register const GtkSignalHash *hash2 = h2;
1237   
1238   return (hash1->quark == hash2->quark &&
1239           hash1->object_type == hash2->object_type);
1240 }
1241
1242 static guint
1243 gtk_alive_disconnecter (GtkDisconnectInfo *info)
1244 {
1245   g_return_val_if_fail (info != NULL, 0);
1246   
1247   gtk_signal_disconnect (info->object1, info->disconnect_handler1);
1248   gtk_signal_disconnect (info->object1, info->signal_handler);
1249   gtk_signal_disconnect (info->object2, info->disconnect_handler2);
1250   
1251   g_mem_chunk_free (gtk_disconnect_info_mem_chunk, info);
1252   
1253   return 0;
1254 }
1255
1256 static GtkHandler*
1257 gtk_signal_handler_new (void)
1258 {
1259   GtkHandler *handler;
1260
1261   if (!gtk_handler_free_list)
1262     {
1263       GtkHandler *handler_block;
1264       guint i;
1265
1266       handler_block = g_new0 (GtkHandler, HANDLER_BLOCK_SIZE);
1267       for (i = 1; i < HANDLER_BLOCK_SIZE; i++)
1268         {
1269           (handler_block + i)->next = gtk_handler_free_list;
1270           gtk_handler_free_list = (handler_block + i);
1271         }
1272       
1273       handler = handler_block;
1274     }
1275   else
1276     {
1277       handler = gtk_handler_free_list;
1278       gtk_handler_free_list = handler->next;
1279     }
1280   
1281   handler->id = 0;
1282   handler->blocked = 0;
1283   handler->signal_id = 0;
1284   handler->object_signal = FALSE;
1285   handler->after = FALSE;
1286   handler->no_marshal = FALSE;
1287   handler->ref_count = 1;
1288   handler->func = NULL;
1289   handler->func_data = NULL;
1290   handler->destroy_func = NULL;
1291   handler->prev = NULL;
1292   handler->next = NULL;
1293   
1294   return handler;
1295 }
1296
1297 static void
1298 gtk_signal_handler_ref (GtkHandler *handler)
1299 {
1300   handler->ref_count += 1;
1301 }
1302
1303 static void
1304 gtk_signal_handler_unref (GtkHandler *handler,
1305                           GtkObject  *object)
1306 {
1307   if (!handler->ref_count)
1308     {
1309       /* FIXME: i wanna get removed somewhen */
1310       g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
1311       return;
1312     }
1313   
1314   handler->ref_count -= 1;
1315   
1316   if (handler->ref_count == 0)
1317     {
1318       if (handler->destroy_func)
1319         (* handler->destroy_func) (handler->func_data);
1320       else if (!handler->func && global_destroy_notify)
1321         (* global_destroy_notify) (handler->func_data);
1322       
1323       if (handler->prev)
1324         handler->prev->next = handler->next;
1325       else if (handler->next)
1326         gtk_object_set_data_by_id (object, gtk_handler_quark, handler->next);
1327       else
1328         {
1329           GTK_OBJECT_UNSET_FLAGS (object, GTK_CONNECTED);
1330           gtk_object_set_data_by_id (object, gtk_handler_quark, NULL);
1331         }
1332       if (handler->next)
1333         handler->next->prev = handler->prev;
1334       
1335       handler->next = gtk_handler_free_list;
1336       gtk_handler_free_list = handler;
1337     }
1338 }
1339
1340 static void
1341 gtk_signal_handler_insert (GtkObject  *object,
1342                            GtkHandler *handler)
1343 {
1344   GtkHandler *tmp;
1345   
1346   /* FIXME: remove */ g_assert (handler->next == NULL);
1347   /* FIXME: remove */ g_assert (handler->prev == NULL);
1348   
1349   tmp = gtk_object_get_data_by_id (object, gtk_handler_quark);
1350   if (!tmp)
1351     {
1352       GTK_OBJECT_SET_FLAGS (object, GTK_CONNECTED);
1353       gtk_object_set_data_by_id (object, gtk_handler_quark, handler);
1354     }
1355   else
1356     while (tmp)
1357       {
1358         if (tmp->signal_id < handler->signal_id)
1359           {
1360             if (tmp->prev)
1361               {
1362                 tmp->prev->next = handler;
1363                 handler->prev = tmp->prev;
1364               }
1365             else
1366               gtk_object_set_data_by_id (object, gtk_handler_quark, handler);
1367             tmp->prev = handler;
1368             handler->next = tmp;
1369             break;
1370           }
1371         
1372         if (!tmp->next)
1373           {
1374             tmp->next = handler;
1375             handler->prev = tmp;
1376             break;
1377           }
1378         tmp = tmp->next;
1379       }
1380 }
1381
1382
1383 #ifdef  G_ENABLE_DEBUG
1384 /* value typically set via gdb */
1385 static GtkObject *gtk_trace_signal_object = NULL;
1386 #endif  /* G_ENABLE_DEBUG */
1387
1388
1389 static void
1390 gtk_signal_real_emit (GtkObject *object,
1391                       guint      signal_id,
1392                       GtkArg    *params)
1393 {
1394   GtkSignal     signal;
1395   GtkHandler    *handlers;
1396   GtkSignalFunc  signal_func;
1397   GtkEmission   *emission;
1398
1399   /* gtk_handlers_run() expects a reentrant GtkSignal*, so we allocate
1400    * it locally on the stack. we save some lookups ourselves with this as well.
1401    */
1402   signal = *LOOKUP_SIGNAL_ID (signal_id);
1403   if (signal.function_offset)
1404     signal_func = G_STRUCT_MEMBER (GtkSignalFunc, ((GTypeInstance*) object)->g_class, signal.function_offset);
1405   else
1406     signal_func = NULL;
1407   
1408 #ifdef  G_ENABLE_DEBUG
1409   if (gtk_debug_flags & GTK_DEBUG_SIGNALS ||
1410       object == gtk_trace_signal_object)
1411     g_message ("%s::%s emitted (object=%p class-method=%p)\n",
1412                gtk_type_name (GTK_OBJECT_TYPE (object)),
1413                signal.name,
1414                object,
1415                signal_func);
1416 #endif  /* G_ENABLE_DEBUG */
1417   
1418   if (signal.signal_flags & GTK_RUN_NO_RECURSE)
1419     {
1420       gint state;
1421       
1422       state = gtk_emission_check (current_emissions, object, signal_id);
1423       if (state)
1424         {
1425           if (state > 1)
1426             g_warning ("gtk_signal_real_emit(): emission (%u) for object `%s' cannot be restarted from emission hook",
1427                        signal_id,
1428                        gtk_type_name (GTK_OBJECT_TYPE (object)));
1429           else if (!gtk_emission_check (restart_emissions, object, signal_id))
1430             gtk_emission_add (&restart_emissions, object, signal_id);
1431           
1432           return;
1433         }
1434     }
1435   
1436   gtk_object_ref (object);
1437   
1438   gtk_emission_add (&current_emissions, object, signal_id);
1439   emission = current_emissions;
1440   
1441  emission_restart:
1442   
1443   if (signal.signal_flags & GTK_RUN_FIRST && signal_func)
1444     {
1445       signal.marshaller (object, signal_func, NULL, params);
1446       
1447       if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
1448         {
1449           gtk_emission_remove (&stop_emissions, object, signal_id);
1450           goto emission_done;
1451         }
1452       else if (restart_emissions &&
1453                signal.signal_flags & GTK_RUN_NO_RECURSE &&
1454                gtk_emission_check (restart_emissions, object, signal_id))
1455         {
1456           gtk_emission_remove (&restart_emissions, object, signal_id);
1457           
1458           goto emission_restart;
1459         }
1460     }
1461   
1462   if (signal.hook_list && !GTK_OBJECT_DESTROYED (object))
1463     {
1464       GtkEmissionHookData data;
1465
1466       data.object = object;
1467       data.n_params = signal.nparams;
1468       data.params = params;
1469       data.signal_id = signal_id;
1470       emission->in_hook = 1;
1471       g_hook_list_marshal_check (signal.hook_list, TRUE, gtk_emission_hook_marshaller, &data);
1472       emission->in_hook = 0;
1473     }
1474
1475   if (GTK_OBJECT_CONNECTED (object))
1476     {
1477       handlers = gtk_signal_get_handlers (object, signal_id);
1478       if (handlers)
1479         {
1480           gint return_val;
1481           
1482           return_val = gtk_handlers_run (handlers, &signal, object, params, FALSE);
1483           switch (return_val)
1484             {
1485             case EMISSION_CONTINUE:
1486               break;
1487             case EMISSION_RESTART:
1488               goto emission_restart;
1489             case EMISSION_DONE:
1490               goto emission_done;
1491             }
1492         }
1493     }
1494   
1495   if (signal.signal_flags & GTK_RUN_LAST && signal_func)
1496     {
1497       signal.marshaller (object, signal_func, NULL, params);
1498       
1499       if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
1500         {
1501           gtk_emission_remove (&stop_emissions, object, signal_id);
1502           goto emission_done;
1503         }
1504       else if (restart_emissions &&
1505                signal.signal_flags & GTK_RUN_NO_RECURSE &&
1506                gtk_emission_check (restart_emissions, object, signal_id))
1507         {
1508           gtk_emission_remove (&restart_emissions, object, signal_id);
1509           
1510           goto emission_restart;
1511         }
1512     }
1513   
1514   if (GTK_OBJECT_CONNECTED (object))
1515     {
1516       handlers = gtk_signal_get_handlers (object, signal_id);
1517       if (handlers)
1518         {
1519           gint return_val;
1520           
1521           return_val = gtk_handlers_run (handlers, &signal, object, params, TRUE);
1522           switch (return_val)
1523             {
1524             case  EMISSION_CONTINUE:
1525               break;
1526             case  EMISSION_RESTART:
1527               goto emission_restart;
1528             case  EMISSION_DONE:
1529               goto emission_done;
1530             }
1531         }
1532     }
1533   
1534  emission_done:
1535   if (restart_emissions && signal.signal_flags & GTK_RUN_NO_RECURSE)
1536     gtk_emission_remove (&restart_emissions, object, signal_id);
1537   
1538   gtk_emission_remove (&current_emissions, object, signal_id);
1539   
1540   gtk_object_unref (object);
1541 }
1542
1543 guint
1544 gtk_signal_handler_pending (GtkObject           *object,
1545                             guint                signal_id,
1546                             gboolean             may_be_blocked)
1547 {
1548   GtkHandler *handlers;
1549   guint handler_id;
1550   
1551   g_return_val_if_fail (object != NULL, 0);
1552   g_return_val_if_fail (signal_id >= 1, 0);
1553
1554   if (GTK_OBJECT_CONNECTED (object))
1555     handlers = gtk_signal_get_handlers (object, signal_id);
1556   else
1557     return 0;
1558   
1559   handler_id = 0;
1560   while (handlers && handlers->signal_id == signal_id)
1561     {
1562       if (handlers->id > 0 &&
1563           (may_be_blocked || handlers->blocked == FALSE))
1564         {
1565           handler_id = handlers->id;
1566           break;
1567         }
1568       
1569       handlers = handlers->next;
1570     }
1571   
1572   return handler_id;
1573 }
1574
1575 guint
1576 gtk_signal_handler_pending_by_func (GtkObject           *object,
1577                                     guint                signal_id,
1578                                     gboolean             may_be_blocked,
1579                                     GtkSignalFunc        func,
1580                                     gpointer             data)
1581 {
1582   GtkHandler *handlers;
1583   guint handler_id;
1584   
1585   g_return_val_if_fail (object != NULL, 0);
1586   g_return_val_if_fail (func != NULL, 0);
1587   g_return_val_if_fail (signal_id >= 1, 0);
1588
1589   if (GTK_OBJECT_CONNECTED (object))
1590     handlers = gtk_signal_get_handlers (object, signal_id);
1591   else
1592     return 0;
1593   
1594   handler_id = 0;
1595   while (handlers && handlers->signal_id == signal_id)
1596     {
1597       if (handlers->id > 0 &&
1598           handlers->func == func &&
1599           handlers->func_data == data &&
1600           (may_be_blocked || handlers->blocked == 0))
1601         {
1602           handler_id = handlers->id;
1603           break;
1604         }
1605       
1606       handlers = handlers->next;
1607     }
1608   
1609   return handler_id;
1610 }
1611
1612 gint
1613 gtk_signal_handler_pending_by_id (GtkObject *object,
1614                                   guint      handler_id,
1615                                   gboolean   may_be_blocked)
1616 {
1617   GtkHandler *handlers;
1618   
1619   g_return_val_if_fail (object != NULL, FALSE);
1620   g_return_val_if_fail (handler_id >= 1, FALSE);
1621
1622   if (GTK_OBJECT_CONNECTED (object))
1623     handlers = gtk_object_get_data_by_id (object, gtk_handler_quark);
1624   else
1625     return FALSE;
1626   
1627   while (handlers)
1628     {
1629       if (handlers->id == handler_id)
1630         return may_be_blocked || handlers->blocked == 0;
1631       
1632       handlers = handlers->next;
1633     }
1634   
1635   return FALSE;
1636 }
1637
1638 guint
1639 gtk_signal_add_emission_hook (guint           signal_id,
1640                               GtkEmissionHook hook_func,
1641                               gpointer        data)
1642 {
1643   return gtk_signal_add_emission_hook_full (signal_id, hook_func, data, NULL);
1644 }
1645
1646 guint
1647 gtk_signal_add_emission_hook_full (guint           signal_id,
1648                                    GtkEmissionHook hook_func,
1649                                    gpointer        data,
1650                                    GDestroyNotify  destroy)
1651 {
1652   static guint seq_hook_id = 1;
1653   GtkSignal *signal;
1654   GHook *hook;
1655
1656   g_return_val_if_fail (signal_id > 0, 0);
1657   g_return_val_if_fail (hook_func != NULL, 0);
1658   
1659   signal = LOOKUP_SIGNAL_ID (signal_id);
1660   g_return_val_if_fail (signal != NULL, 0);
1661   if (signal->signal_flags & GTK_RUN_NO_HOOKS)
1662     {
1663       g_warning ("gtk_signal_add_emission_hook_full(): signal \"%s\" does not support emission hooks",
1664                  signal->name);
1665       return 0;
1666     }
1667
1668   if (!signal->hook_list)
1669     {
1670       signal->hook_list = g_new (GHookList, 1);
1671       g_hook_list_init (signal->hook_list, sizeof (GHook));
1672     }
1673
1674   hook = g_hook_alloc (signal->hook_list);
1675   hook->data = data;
1676   hook->func = hook_func;
1677   hook->destroy = destroy;
1678
1679   signal->hook_list->seq_id = seq_hook_id;
1680   g_hook_prepend (signal->hook_list, hook);
1681   seq_hook_id = signal->hook_list->seq_id;
1682
1683   return hook->hook_id;
1684 }
1685
1686 void
1687 gtk_signal_remove_emission_hook (guint signal_id,
1688                                  guint hook_id)
1689 {
1690   GtkSignal *signal;
1691
1692   g_return_if_fail (signal_id > 0);
1693   g_return_if_fail (hook_id > 0);
1694
1695   signal = LOOKUP_SIGNAL_ID (signal_id);
1696   g_return_if_fail (signal != NULL);
1697
1698   if (!signal->hook_list || !g_hook_destroy (signal->hook_list, hook_id))
1699     g_warning ("gtk_signal_remove_emission_hook(): could not find hook (%u)", hook_id);
1700 }
1701
1702 static gboolean
1703 gtk_emission_hook_marshaller (GHook   *hook,
1704                               gpointer data_p)
1705 {
1706   GtkEmissionHookData *data = data_p;
1707   GtkEmissionHook func;
1708
1709   func = hook->func;
1710
1711   if (!GTK_OBJECT_DESTROYED (data->object))
1712     return func (data->object, data->signal_id,
1713                  data->n_params, data->params,
1714                  hook->data);
1715   else
1716     return TRUE;
1717 }
1718
1719 static guint
1720 gtk_signal_connect_by_type (GtkObject       *object,
1721                             guint            signal_id,
1722                             GtkSignalFunc    func,
1723                             gpointer         func_data,
1724                             GtkSignalDestroy destroy_func,
1725                             gint             object_signal,
1726                             gint             after,
1727                             gint             no_marshal)
1728 {
1729   GtkObjectClass *class;
1730   GtkHandler *handler;
1731   gint found_it;
1732   GtkSignal *signal;
1733  
1734   g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
1735   
1736   signal = LOOKUP_SIGNAL_ID (signal_id);
1737
1738   /* Search through the signals for this object and make
1739    *  sure the one we are adding is valid. We need to perform
1740    *  the lookup on the objects parents as well. If it isn't
1741    *  valid then issue a warning and return.
1742    * As of now (1998-05-27) this lookup shouldn't be neccessarry
1743    *  anymore since gtk_signal_lookup() has been reworked to only
1744    *  return correct signal ids per class-branch.
1745    */
1746   found_it = FALSE;
1747   class = GTK_OBJECT_GET_CLASS (object);
1748   while (class)
1749     {
1750       GtkType parent;
1751       guint *object_signals;
1752       guint nsignals;
1753       guint i;
1754       
1755       object_signals = class->signals;
1756       nsignals = class->nsignals;
1757       
1758       for (i = 0; i < nsignals; i++)
1759         if (object_signals[i] == signal_id)
1760           {
1761             found_it = TRUE;
1762             break;
1763           }
1764       
1765       parent = g_type_parent (GTK_CLASS_TYPE (class));
1766       if (GTK_TYPE_IS_OBJECT (parent))
1767         class = g_type_class_peek (parent);
1768       else
1769         class = NULL;
1770     }
1771   
1772   if (!found_it)
1773     {
1774       g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
1775                  signal_id,
1776                  GTK_OBJECT_TYPE_NAME (object));
1777       return 0;
1778     }
1779   
1780   handler = gtk_signal_handler_new ();
1781   handler->id = gtk_handler_id++;
1782   handler->signal_id = signal_id;
1783   handler->object_signal = object_signal != FALSE;
1784   handler->func = func;
1785   handler->func_data = func_data;
1786   handler->destroy_func = destroy_func;
1787   handler->after = after != FALSE;
1788   handler->no_marshal = no_marshal;
1789   
1790   gtk_signal_handler_insert (object, handler);
1791   return handler->id;
1792 }
1793
1794 static GtkEmission*
1795 gtk_emission_new (void)
1796 {
1797   GtkEmission *emission;
1798   
1799   if (!gtk_free_emissions)
1800     {
1801       GtkEmission *emission_block;
1802       guint i;
1803
1804       emission_block = g_new0 (GtkEmission, EMISSION_BLOCK_SIZE);
1805       for (i = 1; i < EMISSION_BLOCK_SIZE; i++)
1806         {
1807           (emission_block + i)->next = gtk_free_emissions;
1808           gtk_free_emissions = (emission_block + i);
1809         }
1810
1811       emission = emission_block;
1812     }
1813   else
1814     {
1815       emission = gtk_free_emissions;
1816       gtk_free_emissions = emission->next;
1817     }
1818
1819   emission->object = NULL;
1820   emission->signal_id = 0;
1821   emission->in_hook = 0;
1822   emission->next = NULL;
1823   
1824   return emission;
1825 }
1826
1827 static void
1828 gtk_emission_add (GtkEmission **emissions,
1829                   GtkObject    *object,
1830                   guint         signal_id)
1831 {
1832   GtkEmission *emission;
1833   
1834   g_return_if_fail (emissions != NULL);
1835   g_return_if_fail (object != NULL);
1836   
1837   emission = gtk_emission_new ();
1838   emission->object = object;
1839   emission->signal_id = signal_id;
1840
1841   emission->next = *emissions;
1842   *emissions = emission;
1843 }
1844
1845 static void
1846 gtk_emission_remove (GtkEmission **emissions,
1847                      GtkObject    *object,
1848                      guint         signal_id)
1849 {
1850   GtkEmission *emission, *last;
1851   
1852   g_return_if_fail (emissions != NULL);
1853
1854   last = NULL;
1855   emission = *emissions;
1856   while (emission)
1857     {
1858       if (emission->object == object && emission->signal_id == signal_id)
1859         {
1860           if (last)
1861             last->next = emission->next;
1862           else
1863             *emissions = emission->next;
1864
1865           emission->next = gtk_free_emissions;
1866           gtk_free_emissions = emission;
1867           break;
1868         }
1869
1870       last = emission;
1871       emission = last->next;
1872     }
1873 }
1874
1875 static gint
1876 gtk_emission_check (GtkEmission *emission,
1877                     GtkObject   *object,
1878                     guint        signal_id)
1879 {
1880   while (emission)
1881     {
1882       if (emission->object == object && emission->signal_id == signal_id)
1883         return 1 + emission->in_hook;
1884       emission = emission->next;
1885     }
1886   return FALSE;
1887 }
1888
1889 static gint
1890 gtk_handlers_run (GtkHandler     *handlers,
1891                   GtkSignal      *signal,
1892                   GtkObject      *object,
1893                   GtkArg         *params,
1894                   gint            after)
1895 {
1896   /* *signal is a local copy on the stack of gtk_signal_real_emit(),
1897    * so we don't need to look it up every time we invoked a function.
1898    */
1899   while (handlers && handlers->signal_id == signal->signal_id)
1900     {
1901       GtkHandler *handlers_next;
1902       
1903       gtk_signal_handler_ref (handlers);
1904       
1905       if (!handlers->blocked && handlers->after == after)
1906         {
1907           if (handlers->func)
1908             {
1909               if (handlers->no_marshal)
1910                 (* (GtkCallbackMarshal) handlers->func) (object,
1911                                                          handlers->func_data,
1912                                                          signal->nparams,
1913                                                          params);
1914               else if (handlers->object_signal)
1915                 /* don't cast with GTK_OBJECT () */
1916                 (* signal->marshaller) ((GtkObject*) handlers->func_data,
1917                                         handlers->func,
1918                                         object,
1919                                         params);
1920               else
1921                 (* signal->marshaller) (object,
1922                                         handlers->func,
1923                                         handlers->func_data,
1924                                         params);
1925             }
1926           else if (global_marshaller)
1927             (* global_marshaller) (object,
1928                                    handlers->func_data,
1929                                    signal->nparams,
1930                                    params,
1931                                    signal->params,
1932                                    signal->return_val);
1933           
1934           if (stop_emissions && gtk_emission_check (stop_emissions,
1935                                                     object,
1936                                                     signal->signal_id))
1937             {
1938               gtk_emission_remove (&stop_emissions, object, signal->signal_id);
1939               
1940               gtk_signal_handler_unref (handlers, object);
1941
1942               return EMISSION_DONE;
1943             }
1944           else if (restart_emissions &&
1945                    signal->signal_flags & GTK_RUN_NO_RECURSE &&
1946                    gtk_emission_check (restart_emissions, object, signal->signal_id))
1947             {
1948               gtk_emission_remove (&restart_emissions, object, signal->signal_id);
1949
1950               gtk_signal_handler_unref (handlers, object);
1951
1952               return EMISSION_RESTART;
1953             }
1954         }
1955       
1956       handlers_next = handlers->next;
1957       gtk_signal_handler_unref (handlers, object);
1958       handlers = handlers_next;
1959     }
1960   
1961   return EMISSION_CONTINUE;
1962 }
1963
1964 static gboolean
1965 gtk_signal_collect_params (GtkArg              *params,
1966                            guint                n_params,
1967                            GtkType             *param_types,
1968                            GtkType              return_type,
1969                            va_list              var_args)
1970 {
1971   register GtkArg *last_param;
1972   register gboolean failed = FALSE;
1973
1974   for (last_param = params + n_params; params < last_param; params++)
1975     {
1976       register gchar *error;
1977
1978       params->name = NULL;
1979       params->type = *(param_types++);
1980       GTK_ARG_COLLECT_VALUE (params,
1981                              var_args,
1982                              error);
1983       if (error)
1984         {
1985           failed = TRUE;
1986           g_warning ("gtk_signal_collect_params(): %s", error);
1987           g_free (error);
1988         }
1989     }
1990
1991   params->type = return_type;
1992   params->name = NULL;
1993
1994   return_type = GTK_FUNDAMENTAL_TYPE (return_type);
1995   if (return_type != GTK_TYPE_NONE)
1996     {
1997       if (return_type != 0) /* FIXME: check for IS_PARAM */
1998         {
1999           GTK_VALUE_POINTER (*params) = va_arg (var_args, gpointer);
2000           
2001           if (GTK_VALUE_POINTER (*params) == NULL)
2002             {
2003               failed = TRUE;
2004               g_warning ("gtk_signal_collect_params(): invalid NULL pointer for return argument type `%s'",
2005                          gtk_type_name (params->type));
2006             }
2007         }
2008       else
2009         {
2010           failed = TRUE;
2011           g_warning ("gtk_signal_collect_params(): unsupported return argument type `%s'",
2012                      gtk_type_name (params->type));
2013         }
2014     }
2015   else
2016     GTK_VALUE_POINTER (*params) = NULL;
2017
2018   return failed;
2019 }