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