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