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