]> Pileus Git - ~andy/gtk/blob - gtk/gtksignal.c
remove an invalid cast that shows up with debugging enabled only.
[~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 Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include <stdarg.h>
19 #include "gtksignal.h"
20
21
22 #define MAX_PARAMS       20
23 #define DONE             1
24 #define RESTART          2
25
26 #define GTK_RUN_TYPE(x)  ((x) & GTK_RUN_MASK)
27
28
29 typedef struct _GtkSignal       GtkSignal;
30 typedef struct _GtkSignalInfo   GtkSignalInfo;
31 typedef struct _GtkHandler      GtkHandler;
32 typedef struct _GtkHandlerInfo  GtkHandlerInfo;
33 typedef struct _GtkEmission     GtkEmission;
34
35 typedef void (*GtkSignalMarshaller0) (GtkObject *object,
36                                       gpointer   data);
37
38 struct _GtkSignalInfo
39 {
40   gchar *name;
41   gint object_type;
42   gint signal_type;
43 };
44
45 struct _GtkSignal
46 {
47   GtkSignalInfo info;
48   gint function_offset;
49   GtkSignalRunType run_type;
50   GtkSignalMarshaller marshaller;
51   GtkType return_val;
52   GtkType *params;
53   gint nparams;
54 };
55
56 struct _GtkHandler
57 {
58   guint16 id;
59   guint signal_type : 13;
60   guint object_signal : 1;
61   guint blocked : 1;
62   guint after : 1;
63   guint no_marshal : 1;
64   GtkSignalFunc func;
65   gpointer func_data;
66   GtkSignalDestroy destroy_func;
67   GtkHandler *next;
68 };
69
70 struct _GtkHandlerInfo
71 {
72   GtkObject *object;
73   GtkSignalMarshaller marshaller;
74   GtkArg *params;
75   GtkType *param_types;
76   GtkType return_val;
77   GtkSignalRunType run_type;
78   gint nparams;
79   gint signal_type;
80 };
81
82 struct _GtkEmission
83 {
84   GtkObject *object;
85   gint signal_type;
86 };
87
88
89 static void         gtk_signal_init            (void);
90 static guint        gtk_signal_hash            (gint          *key);
91 static gint         gtk_signal_compare         (gint          *a,
92                                                 gint          *b);
93 static guint        gtk_signal_info_hash       (GtkSignalInfo *a);
94 static gint         gtk_signal_info_compare    (GtkSignalInfo *a,
95                                                 GtkSignalInfo *b);
96 static GtkHandler*  gtk_signal_handler_new     (void);
97 static void         gtk_signal_handler_destroy (GtkHandler    *handler);
98 static void         gtk_signal_handler_insert  (GtkObject     *object,
99                                                 GtkHandler    *handler);
100 static gint         gtk_signal_real_emit       (GtkObject     *object,
101                                                 gint           signal_type,
102                                                 va_list        args);
103 static GtkHandler*  gtk_signal_get_handlers    (GtkObject     *object,
104                                                 gint           signal_type);
105 static gint         gtk_signal_connect_by_type (GtkObject     *object,
106                                                 gint           signal_type,
107                                                 gint           object_signal,
108                                                 GtkSignalFunc  func,
109                                                 gpointer       func_data,
110                                                 GtkSignalDestroy destroy_func,
111                                                 gint           after,
112                                                 gint           no_marshal);
113 static GtkEmission* gtk_emission_new           (void);
114 static void         gtk_emission_destroy       (GtkEmission    *emission);
115 static void         gtk_emission_add           (GList         **emissions,
116                                                 GtkObject      *object,
117                                                 gint            signal_type);
118 static void         gtk_emission_remove        (GList         **emissions,
119                                                 GtkObject      *object,
120                                                 gint            signal_type);
121 static gint         gtk_emission_check         (GList          *emissions,
122                                                 GtkObject      *object,
123                                                 gint            signal_type);
124 static gint         gtk_handlers_run           (GtkHandler     *handlers,
125                                                 GtkHandlerInfo *info,
126                                                 gint            after);
127 static void         gtk_params_get             (GtkArg         *params,
128                                                 gint            nparams,
129                                                 GtkType        *param_types,
130                                                 GtkType         return_val,
131                                                 va_list         args);
132
133
134 static gint initialize = TRUE;
135 static GHashTable *signal_hash_table = NULL;
136 static GHashTable *signal_info_hash_table = NULL;
137 static gint next_signal = 1;
138 static gint next_handler_id = 1;
139
140 static const char *handler_key = "signal_handlers";
141
142 static GMemChunk *handler_mem_chunk = NULL;
143 static GMemChunk *emission_mem_chunk = NULL;
144
145 static GList *current_emissions = NULL;
146 static GList *stop_emissions = NULL;
147 static GList *restart_emissions = NULL;
148
149 static GtkSignalMarshal marshal = NULL;
150 static GtkSignalDestroy destroy = NULL;
151
152
153 gint
154 gtk_signal_new (const gchar         *name,
155                 GtkSignalRunType     run_type,
156                 gint                 object_type,
157                 gint                 function_offset,
158                 GtkSignalMarshaller  marshaller,
159                 GtkType              return_val,
160                 gint                 nparams,
161                 ...)
162 {
163   GtkType *params;
164   GtkSignal *signal;
165   GtkSignalInfo info;
166   gint *type;
167   gint i;
168   va_list args;
169
170   g_return_val_if_fail (name != NULL, 0);
171   g_return_val_if_fail (marshaller != NULL, 0);
172   g_return_val_if_fail (nparams < 10, 0);
173
174   if (initialize)
175     gtk_signal_init ();
176
177   info.name = (char*)name;
178   info.object_type = object_type;
179
180   type = g_hash_table_lookup (signal_info_hash_table, &info);
181   if (type)
182     {
183       g_warning ("signal \"%s\" already exists in the \"%s\" class ancestry\n",
184                  name, gtk_type_name (object_type));
185       return 0;
186     }
187
188   signal = g_new (GtkSignal, 1);
189   signal->info.name = g_strdup(name);
190   signal->info.object_type = object_type;
191   signal->info.signal_type = next_signal++;
192   signal->function_offset = function_offset;
193   signal->run_type = run_type;
194   signal->marshaller = marshaller;
195   signal->return_val = return_val;
196   signal->params = NULL;
197   signal->nparams = nparams;
198
199   g_hash_table_insert (signal_hash_table, &signal->info.signal_type, signal);
200   g_hash_table_insert (signal_info_hash_table, &signal->info, &signal->info.signal_type);
201
202   if (nparams > 0)
203     {
204       signal->params = g_new (GtkType, nparams);
205       params = signal->params;
206
207       va_start (args, nparams);
208
209       for (i = 0; i < nparams; i++)
210         params[i] = va_arg (args, GtkType);
211
212       va_end (args);
213     }
214
215   return signal->info.signal_type;
216 }
217
218 gint
219 gtk_signal_lookup (const gchar *name,
220                    gint         object_type)
221 {
222   GtkSignalInfo info;
223   gint *type;
224
225   g_return_val_if_fail (name != NULL, 0);
226
227   if (initialize)
228     gtk_signal_init ();
229
230   info.name = (char*)name;
231
232   while (object_type)
233     {
234       info.object_type = object_type;
235
236       type = g_hash_table_lookup (signal_info_hash_table, &info);
237       if (type)
238         return *type;
239
240       object_type = gtk_type_parent (object_type);
241     }
242
243   return 0;
244 }
245
246 gchar*
247 gtk_signal_name (gint signal_num)
248 {
249   GtkSignal *signal;
250
251   signal = g_hash_table_lookup (signal_hash_table, &signal_num);
252   if (signal)
253     return signal->info.name;
254
255   return NULL;
256 }
257
258 gint
259 gtk_signal_emit (GtkObject *object,
260                  gint       signal_type,
261                  ...)
262 {
263   gint return_val;
264
265   va_list args;
266
267   g_return_val_if_fail (object != NULL, FALSE);
268
269   if (initialize)
270     gtk_signal_init ();
271
272   va_start (args, signal_type);
273
274   return_val = gtk_signal_real_emit (object, signal_type, args);
275
276   va_end (args);
277
278   return return_val;
279 }
280
281 gint
282 gtk_signal_emit_by_name (GtkObject       *object,
283                          const gchar     *name,
284                          ...)
285 {
286   gint return_val;
287   gint type;
288   va_list args;
289
290   g_return_val_if_fail (object != NULL, FALSE);
291
292   if (initialize)
293     gtk_signal_init ();
294
295   return_val = TRUE;
296   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
297
298   if (type)
299     {
300       va_start (args, name);
301
302       return_val = gtk_signal_real_emit (object, type, args);
303
304       va_end (args);
305     }
306
307   return return_val;
308 }
309
310 void
311 gtk_signal_emit_stop (GtkObject *object,
312                       gint       signal_type)
313 {
314   g_return_if_fail (object != NULL);
315   g_return_if_fail (signal_type >= 1);
316
317   if (initialize)
318     gtk_signal_init ();
319
320   if (gtk_emission_check (current_emissions, object, signal_type))
321     gtk_emission_add (&stop_emissions, object, signal_type);
322 }
323
324 void
325 gtk_signal_emit_stop_by_name (GtkObject       *object,
326                               const gchar     *name)
327 {
328   gint type;
329
330   g_return_if_fail (object != NULL);
331   g_return_if_fail (name != NULL);
332
333   if (initialize)
334     gtk_signal_init ();
335
336   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
337   if (type)
338     gtk_signal_emit_stop (object, type);
339 }
340
341 gint
342 gtk_signal_connect (GtkObject     *object,
343                     const gchar   *name,
344                     GtkSignalFunc  func,
345                     gpointer       func_data)
346 {
347   gint type;
348
349   g_return_val_if_fail (object != NULL, 0);
350
351   if (initialize)
352     gtk_signal_init ();
353
354   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
355   if (!type)
356     {
357       g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry",
358                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
359       return 0;
360     }
361
362   return gtk_signal_connect_by_type (object, type, FALSE,
363                                      func, func_data, NULL,
364                                      FALSE, FALSE);
365 }
366
367 gint
368 gtk_signal_connect_after (GtkObject     *object,
369                           const gchar   *name,
370                           GtkSignalFunc  func,
371                           gpointer       func_data)
372 {
373   gint type;
374
375   g_return_val_if_fail (object != NULL, 0);
376
377   if (initialize)
378     gtk_signal_init ();
379
380   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
381   if (!type)
382     {
383       g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry",
384                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
385       return 0;
386     }
387
388   return gtk_signal_connect_by_type (object, type, FALSE,
389                                      func, func_data, NULL,
390                                      TRUE, FALSE);
391 }
392
393 gint
394 gtk_signal_connect_interp (GtkObject         *object,
395                            gchar             *name,
396                            GtkCallbackMarshal func,
397                            gpointer           func_data,
398                            GtkDestroyNotify   destroy_func,
399                            gint               after)
400 {
401   gint type;
402
403   g_return_val_if_fail (object != NULL, 0);
404
405   if (initialize)
406     gtk_signal_init ();
407
408   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
409   if (!type)
410     {
411       g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry",
412                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
413       return 0;
414     }
415
416   return gtk_signal_connect_by_type (object, type, FALSE,
417                                      (GtkSignalFunc) func, func_data,
418                                      destroy_func, after, TRUE);
419 }
420
421 gint
422 gtk_signal_connect_object (GtkObject     *object,
423                            const gchar   *name,
424                            GtkSignalFunc  func,
425                            GtkObject     *slot_object)
426 {
427   gint type;
428
429   g_return_val_if_fail (object != NULL, 0);
430
431   if (initialize)
432     gtk_signal_init ();
433
434   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
435   if (!type)
436     {
437       g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry",
438                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
439       return 0;
440     }
441
442   return gtk_signal_connect_by_type (object, type, TRUE,
443                                      func, slot_object, NULL,
444                                      FALSE, FALSE);
445 }
446
447 gint
448 gtk_signal_connect_object_after (GtkObject     *object,
449                                  const gchar   *name,
450                                  GtkSignalFunc  func,
451                                  GtkObject     *slot_object)
452 {
453   gint type;
454
455   g_return_val_if_fail (object != NULL, 0);
456
457   if (initialize)
458     gtk_signal_init ();
459
460   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
461   if (!type)
462     {
463       g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry",
464                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
465       return 0;
466     }
467
468   return gtk_signal_connect_by_type (object, type, TRUE,
469                                      func, slot_object, NULL,
470                                      TRUE, FALSE);
471 }
472
473 void
474 gtk_signal_disconnect (GtkObject *object,
475                        gint       anid)
476 {
477   GtkHandler *tmp;
478   GtkHandler *prev;
479
480   g_return_if_fail (object != NULL);
481
482   if (initialize)
483     gtk_signal_init ();
484
485   prev = NULL;
486   tmp = gtk_object_get_data (object, handler_key);
487
488   while (tmp)
489     {
490       if (tmp->id == anid)
491         {
492           if (prev)
493             prev->next = tmp->next;
494           else
495             gtk_object_set_data (object, handler_key, tmp->next);
496           gtk_signal_handler_destroy (tmp);
497           return;
498         }
499
500       prev = tmp;
501       tmp = tmp->next;
502     }
503
504   g_warning ("could not find handler (%d)", anid);
505 }
506
507 void
508 gtk_signal_disconnect_by_data (GtkObject *object,
509                                gpointer   data)
510 {
511   GtkHandler *start;
512   GtkHandler *tmp;
513   GtkHandler *prev;
514   gint found_one;
515
516   g_return_if_fail (object != NULL);
517
518   if (initialize)
519     gtk_signal_init ();
520
521   prev = NULL;
522   start = gtk_object_get_data (object, handler_key);
523   tmp = start;
524   found_one = FALSE;
525
526   while (tmp)
527     {
528       if (tmp->func_data == data)
529         {
530           found_one = TRUE;
531
532           if (prev)
533             prev->next = tmp->next;
534           else
535             start = tmp->next;
536
537           gtk_signal_handler_destroy (tmp);
538
539           if (prev)
540             {
541               tmp = prev->next;
542             }
543           else
544             {
545               prev = NULL;
546               tmp = start;
547             }
548         }
549       else
550         {
551           prev = tmp;
552           tmp = tmp->next;
553         }
554     }
555
556   gtk_object_set_data (object, handler_key, start);
557
558   if (!found_one)
559     g_warning ("could not find handler containing data (0x%0lX)", (long) data);
560 }
561
562 void
563 gtk_signal_handler_block (GtkObject *object,
564                           gint      anid)
565 {
566   GtkHandler *tmp;
567
568   g_return_if_fail (object != NULL);
569
570   if (initialize)
571     gtk_signal_init ();
572
573   tmp = gtk_object_get_data (object, handler_key);
574
575   while (tmp)
576     {
577       if (tmp->id == anid)
578         {
579           tmp->blocked = TRUE;
580           return;
581         }
582
583       tmp = tmp->next;
584     }
585
586   g_warning ("could not find handler (%d)", anid);
587 }
588
589 void
590 gtk_signal_handler_block_by_data (GtkObject *object,
591                                   gpointer   data)
592 {
593   GtkHandler *tmp;
594   gint found_one;
595
596   g_return_if_fail (object != NULL);
597
598   if (initialize)
599     gtk_signal_init ();
600
601   found_one = FALSE;
602   tmp = gtk_object_get_data (object, handler_key);
603
604   while (tmp)
605     {
606       if (tmp->func_data == data)
607         {
608           tmp->blocked = TRUE;
609           found_one = TRUE;
610         }
611
612       tmp = tmp->next;
613     }
614
615   if (!found_one)
616     g_warning ("could not find handler containing data (0x%0lX)", (long) data);
617 }
618
619 void
620 gtk_signal_handler_unblock (GtkObject *object,
621                             gint       anid)
622 {
623   GtkHandler *tmp;
624
625   g_return_if_fail (object != NULL);
626
627   if (initialize)
628     gtk_signal_init ();
629
630   tmp = gtk_object_get_data (object, handler_key);
631
632   while (tmp)
633     {
634       if (tmp->id == anid)
635         {
636           tmp->blocked = FALSE;
637           return;
638         }
639
640       tmp = tmp->next;
641     }
642
643   g_warning ("could not find handler (%d)", anid);
644 }
645
646 void
647 gtk_signal_handler_unblock_by_data (GtkObject *object,
648                                     gpointer   data)
649 {
650   GtkHandler *tmp;
651   gint found_one;
652
653   g_return_if_fail (object != NULL);
654
655   if (initialize)
656     gtk_signal_init ();
657
658   found_one = FALSE;
659   tmp = gtk_object_get_data (object, handler_key);
660
661   while (tmp)
662     {
663       if (tmp->func_data == data)
664         {
665           tmp->blocked = FALSE;
666           found_one = TRUE;
667         }
668
669       tmp = tmp->next;
670     }
671
672   if (!found_one)
673     g_warning ("could not find handler containing data (0x%0lX)", (long) data);
674 }
675
676 void
677 gtk_signal_handlers_destroy (GtkObject *object)
678 {
679   GtkHandler *list;
680   GtkHandler *handler;
681
682   list = gtk_object_get_data (object, handler_key);
683   if (list)
684     {
685       while (list)
686         {
687           handler = list->next;
688           gtk_signal_handler_destroy (list);
689           list = handler;
690         }
691
692       gtk_object_remove_data (object, handler_key);
693     }
694 }
695
696 void
697 gtk_signal_default_marshaller (GtkObject      *object,
698                                GtkSignalFunc   func,
699                                gpointer        func_data,
700                                GtkArg         *params)
701 {
702   GtkSignalMarshaller0 rfunc;
703
704   rfunc = (GtkSignalMarshaller0) func;
705
706   (* rfunc) (object, func_data);
707 }
708
709 void
710 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
711                       GtkSignalDestroy destroy_func)
712 {
713   marshal = marshal_func;
714   destroy = destroy_func;
715 }
716
717
718 static void
719 gtk_signal_init ()
720 {
721   if (initialize)
722     {
723       initialize = FALSE;
724       signal_hash_table = g_hash_table_new ((GHashFunc) gtk_signal_hash,
725                                             (GCompareFunc) gtk_signal_compare);
726       signal_info_hash_table = g_hash_table_new ((GHashFunc) gtk_signal_info_hash,
727                                                  (GCompareFunc) gtk_signal_info_compare);
728     }
729 }
730
731 static guint
732 gtk_signal_hash (gint *key)
733 {
734   return (guint) *key;
735 }
736
737 static gint
738 gtk_signal_compare (gint *a,
739                     gint *b)
740 {
741   return (*a == *b);
742 }
743
744 static guint
745 gtk_signal_info_hash (GtkSignalInfo *a)
746 {
747   return (g_string_hash (a->name) + a->object_type);
748 }
749
750 static gint
751 gtk_signal_info_compare (GtkSignalInfo *a,
752                          GtkSignalInfo *b)
753 {
754   return ((a->object_type == b->object_type) &&
755           g_string_equal (a->name, b->name));
756 }
757
758 static GtkHandler*
759 gtk_signal_handler_new ()
760 {
761   GtkHandler *handler;
762
763   if (!handler_mem_chunk)
764     handler_mem_chunk = g_mem_chunk_new ("handler mem chunk", sizeof (GtkHandler),
765                                          1024, G_ALLOC_AND_FREE);
766
767   handler = g_chunk_new (GtkHandler, handler_mem_chunk);
768
769   handler->id = 0;
770   handler->signal_type = 0;
771   handler->object_signal = FALSE;
772   handler->blocked = FALSE;
773   handler->after = FALSE;
774   handler->no_marshal = FALSE;
775   handler->func = NULL;
776   handler->func_data = NULL;
777   handler->destroy_func = NULL;
778   handler->next = NULL;
779
780   return handler;
781 }
782
783 static void
784 gtk_signal_handler_destroy (GtkHandler *handler)
785 {
786   if (!handler->func && destroy)
787     (* destroy) (handler->func_data);
788   else if (handler->destroy_func)
789     (* handler->destroy_func) (handler->func_data);
790   g_mem_chunk_free (handler_mem_chunk, handler);
791 }
792
793 static void
794 gtk_signal_handler_insert (GtkObject  *object,
795                            GtkHandler *handler)
796 {
797   GtkHandler *start;
798   GtkHandler *tmp;
799   GtkHandler *prev;
800
801   start = gtk_object_get_data (object, handler_key);
802   if (!start)
803     {
804       gtk_object_set_data (object, handler_key, handler);
805     }
806   else
807     {
808       prev = NULL;
809       tmp = start;
810
811       while (tmp)
812         {
813           if (tmp->signal_type < handler->signal_type)
814             {
815               if (prev)
816                 prev->next = handler;
817               else
818                 gtk_object_set_data (object, handler_key, handler);
819               handler->next = tmp;
820               break;
821             }
822
823           if (!tmp->next)
824             {
825               tmp->next = handler;
826               break;
827             }
828
829           prev = tmp;
830           tmp = tmp->next;
831         }
832     }
833 }
834
835 static gint
836 gtk_signal_real_emit (GtkObject *object,
837                       gint       signal_type,
838                       va_list    args)
839 {
840   gint old_value;
841   GtkSignal *signal;
842   GtkHandler *handlers;
843   GtkHandlerInfo info;
844   guchar **signal_func_offset;
845   gint being_destroyed;
846   GtkArg         params[MAX_PARAMS];
847
848   g_return_val_if_fail (object != NULL, FALSE);
849   g_return_val_if_fail (signal_type >= 1, TRUE);
850
851   being_destroyed = GTK_OBJECT_BEING_DESTROYED (object);
852   if (!GTK_OBJECT_NEED_DESTROY (object))
853     {
854       signal = g_hash_table_lookup (signal_hash_table, &signal_type);
855       g_return_val_if_fail (signal != NULL, TRUE);
856       g_return_val_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->info.object_type), TRUE);
857
858       if ((signal->run_type & GTK_RUN_NO_RECURSE) &&
859           gtk_emission_check (current_emissions, object, signal_type))
860         {
861           gtk_emission_add (&restart_emissions, object, signal_type);
862           return TRUE;
863         }
864
865       old_value = GTK_OBJECT_IN_CALL (object);
866       GTK_OBJECT_SET_FLAGS (object, GTK_IN_CALL);
867
868       gtk_params_get (params, signal->nparams, signal->params, signal->return_val, args);
869
870       gtk_emission_add (&current_emissions, object, signal_type);
871
872     restart:
873       if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_LAST)
874         {
875           signal_func_offset = (guchar**) ((guchar*) object->klass + signal->function_offset);
876           if (*signal_func_offset)
877             (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset, NULL, params);
878           if (GTK_OBJECT_NEED_DESTROY (object))
879             goto done;
880         }
881
882       info.object = object;
883       info.marshaller = signal->marshaller;
884       info.params = params;
885       info.param_types = signal->params;
886       info.return_val = signal->return_val;
887       info.nparams = signal->nparams;
888       info.run_type = signal->run_type;
889       info.signal_type = signal_type;
890
891       handlers = gtk_signal_get_handlers (object, signal_type);
892       switch (gtk_handlers_run (handlers, &info, FALSE))
893         {
894         case DONE:
895           goto done;
896         case RESTART:
897           goto restart;
898         }
899
900       if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_FIRST)
901         {
902           signal_func_offset = (guchar**) ((guchar*) object->klass + signal->function_offset);
903           if (*signal_func_offset)
904             (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset, NULL, params);
905           if (being_destroyed || GTK_OBJECT_NEED_DESTROY (object))
906             goto done;
907         }
908
909       switch (gtk_handlers_run (handlers, &info, TRUE))
910         {
911         case DONE:
912           goto done;
913         case RESTART:
914           goto restart;
915         }
916
917     done:
918       gtk_emission_remove (&current_emissions, object, signal_type);
919
920       if (signal->run_type & GTK_RUN_NO_RECURSE)
921         gtk_emission_remove (&restart_emissions, object, signal_type);
922
923       if (!being_destroyed && !old_value)
924         GTK_OBJECT_UNSET_FLAGS (object, GTK_IN_CALL);
925     }
926
927   if (!being_destroyed && GTK_OBJECT_NEED_DESTROY (object) && !GTK_OBJECT_IN_CALL (object))
928     {
929       gtk_object_destroy (object);
930       return FALSE;
931     }
932
933   return TRUE;
934 }
935
936 static GtkHandler*
937 gtk_signal_get_handlers (GtkObject *object,
938                          gint       signal_type)
939 {
940   GtkHandler *handlers;
941
942   g_return_val_if_fail (object != NULL, NULL);
943   g_return_val_if_fail (signal_type >= 1, NULL);
944
945   handlers = gtk_object_get_data (object, handler_key);
946
947   while (handlers)
948     {
949       if (handlers->signal_type == signal_type)
950         return handlers;
951       handlers = handlers->next;
952     }
953
954   return NULL;
955 }
956
957 static gint
958 gtk_signal_connect_by_type (GtkObject       *object,
959                             gint             signal_type,
960                             gint             object_signal,
961                             GtkSignalFunc    func,
962                             gpointer         func_data,
963                             GtkSignalDestroy destroy_func,
964                             gint             after,
965                             gint             no_marshal)
966 {
967   GtkHandler *handler;
968   gint *object_signals;
969   gint nsignals;
970   gint found_it;
971   gint i;
972
973   g_return_val_if_fail (object != NULL, 0);
974   g_return_val_if_fail (object->klass != NULL, 0);
975   g_return_val_if_fail (object->klass->signals != NULL, 0);
976
977   /* Search through the signals for this object and make
978    *  sure the one we are adding is valid. If it isn't then
979    *  issue a warning and return.
980    */
981   object_signals = object->klass->signals;
982   nsignals = object->klass->nsignals;
983   found_it = FALSE;
984
985   for (i = 0; i < nsignals; i++)
986     if (object_signals[i] == signal_type)
987       {
988         found_it = TRUE;
989         break;
990       }
991
992   if (!found_it)
993     {
994       g_warning ("could not find signal (%d) in object's list of signals", signal_type);
995       return 0;
996     }
997
998   handler = gtk_signal_handler_new ();
999   handler->id = next_handler_id++;
1000   handler->signal_type = signal_type;
1001   handler->object_signal = object_signal;
1002   handler->func = func;
1003   handler->func_data = func_data;
1004   handler->destroy_func = destroy_func;
1005
1006   if (after)
1007     handler->after = TRUE;
1008   handler->no_marshal = no_marshal;
1009
1010   gtk_signal_handler_insert (object, handler);
1011   return handler->id;
1012 }
1013
1014 static GtkEmission*
1015 gtk_emission_new ()
1016 {
1017   GtkEmission *emission;
1018
1019   if (!emission_mem_chunk)
1020     emission_mem_chunk = g_mem_chunk_new ("emission mem chunk", sizeof (GtkEmission),
1021                                           1024, G_ALLOC_AND_FREE);
1022
1023   emission = g_chunk_new (GtkEmission, emission_mem_chunk);
1024
1025   emission->object = NULL;
1026   emission->signal_type = 0;
1027
1028   return emission;
1029 }
1030
1031 static void
1032 gtk_emission_destroy (GtkEmission *emission)
1033 {
1034   g_mem_chunk_free (emission_mem_chunk, emission);
1035 }
1036
1037 static void
1038 gtk_emission_add (GList     **emissions,
1039                   GtkObject  *object,
1040                   gint        signal_type)
1041 {
1042   GtkEmission *emission;
1043
1044   g_return_if_fail (emissions != NULL);
1045   g_return_if_fail (object != NULL);
1046
1047   emission = gtk_emission_new ();
1048   emission->object = object;
1049   emission->signal_type = signal_type;
1050
1051   *emissions = g_list_prepend (*emissions, emission);
1052 }
1053
1054 static void
1055 gtk_emission_remove (GList     **emissions,
1056                      GtkObject  *object,
1057                      gint        signal_type)
1058 {
1059   GtkEmission *emission;
1060   GList *tmp;
1061
1062   g_return_if_fail (emissions != NULL);
1063   g_return_if_fail (object != NULL);
1064
1065   tmp = *emissions;
1066   while (tmp)
1067     {
1068       emission = tmp->data;
1069
1070       if ((emission->object == object) &&
1071           (emission->signal_type == signal_type))
1072         {
1073           gtk_emission_destroy (emission);
1074           *emissions = g_list_remove_link (*emissions, tmp);
1075           g_list_free (tmp);
1076           break;
1077         }
1078
1079       tmp = tmp->next;
1080     }
1081 }
1082
1083 static gint
1084 gtk_emission_check (GList     *emissions,
1085                     GtkObject *object,
1086                     gint       signal_type)
1087 {
1088   GtkEmission *emission;
1089   GList *tmp;
1090
1091   g_return_val_if_fail (object != NULL, FALSE);
1092
1093   tmp = emissions;
1094   while (tmp)
1095     {
1096       emission = tmp->data;
1097       tmp = tmp->next;
1098
1099       if ((emission->object == object) &&
1100           (emission->signal_type == signal_type))
1101         return TRUE;
1102     }
1103   return FALSE;
1104 }
1105
1106 static gint
1107 gtk_handlers_run (GtkHandler     *handlers,
1108                   GtkHandlerInfo *info,
1109                   gint            after)
1110 {
1111   while (handlers && (handlers->signal_type == info->signal_type))
1112     {
1113       if (!handlers->blocked && (handlers->after == after))
1114         {
1115           if (handlers->func)
1116             {
1117               if (handlers->no_marshal)
1118                 (* (GtkCallbackMarshal)handlers->func) (info->object,
1119                                                         handlers->func_data,
1120                                                         info->nparams,
1121                                                         info->params);
1122               else if (handlers->object_signal)
1123                 (* info->marshaller) ((GtkObject*) handlers->func_data, /* don't GTK_OBJECT() cast */
1124                                       handlers->func,
1125                                       handlers->func_data,
1126                                       info->params);
1127               else
1128                 (* info->marshaller) (info->object,
1129                                       handlers->func,
1130                                       handlers->func_data,
1131                                       info->params);
1132             }
1133           else if (marshal)
1134             (* marshal) (info->object,
1135                          handlers->func_data,
1136                          info->nparams,
1137                          info->params,
1138                          info->param_types,
1139                          info->return_val);
1140
1141           if (GTK_OBJECT_NEED_DESTROY (info->object))
1142             return DONE;
1143           else if (gtk_emission_check (stop_emissions, info->object, info->signal_type))
1144             {
1145               gtk_emission_remove (&stop_emissions, info->object, info->signal_type);
1146
1147               if (info->run_type & GTK_RUN_NO_RECURSE)
1148                 gtk_emission_remove (&restart_emissions, info->object, info->signal_type);
1149               return DONE;
1150             }
1151           else if ((info->run_type & GTK_RUN_NO_RECURSE) &&
1152                    gtk_emission_check (restart_emissions, info->object, info->signal_type))
1153             {
1154               gtk_emission_remove (&restart_emissions, info->object, info->signal_type);
1155               return RESTART;
1156             }
1157         }
1158
1159       handlers = handlers->next;
1160     }
1161
1162   return 0;
1163 }
1164
1165 static void
1166 gtk_params_get (GtkArg         *params,
1167                 gint            nparams,
1168                 GtkType        *param_types,
1169                 GtkType         return_val,
1170                 va_list         args)
1171 {
1172   int i;
1173
1174   for (i = 0; i < nparams; i++)
1175     {
1176       params[i].type = param_types[i];
1177       params[i].name = NULL;
1178
1179       switch (GTK_FUNDAMENTAL_TYPE (param_types[i]))
1180         {
1181         case GTK_TYPE_INVALID:
1182           break;
1183         case GTK_TYPE_NONE:
1184           break;
1185         case GTK_TYPE_CHAR:
1186           GTK_VALUE_CHAR(params[i]) = va_arg (args, gint);
1187           break;
1188         case GTK_TYPE_BOOL:
1189           GTK_VALUE_BOOL(params[i]) = va_arg (args, gint);
1190           break;
1191         case GTK_TYPE_INT:
1192           GTK_VALUE_INT(params[i]) = va_arg (args, gint);
1193           break;
1194         case GTK_TYPE_UINT:
1195           GTK_VALUE_UINT(params[i]) = va_arg (args, guint);
1196           break;
1197         case GTK_TYPE_ENUM:
1198           GTK_VALUE_ENUM(params[i]) = va_arg (args, gint);
1199           break;
1200         case GTK_TYPE_FLAGS:
1201           GTK_VALUE_FLAGS(params[i]) = va_arg (args, gint);
1202           break;
1203         case GTK_TYPE_LONG:
1204           GTK_VALUE_LONG(params[i]) = va_arg (args, glong);
1205           break;
1206         case GTK_TYPE_ULONG:
1207           GTK_VALUE_ULONG(params[i]) = va_arg (args, gulong);
1208           break;
1209         case GTK_TYPE_FLOAT:
1210           GTK_VALUE_FLOAT(params[i]) = va_arg (args, gfloat);
1211           break;
1212         case GTK_TYPE_STRING:
1213           GTK_VALUE_STRING(params[i]) = va_arg (args, gchar*);
1214           break;
1215         case GTK_TYPE_POINTER:
1216           GTK_VALUE_POINTER(params[i]) = va_arg (args, gpointer);
1217           break;
1218         case GTK_TYPE_BOXED:
1219           GTK_VALUE_BOXED(params[i]) = va_arg (args, gpointer);
1220           break;
1221         case GTK_TYPE_SIGNAL:
1222           GTK_VALUE_SIGNAL(params[i]).f = va_arg (args, GtkFunction);
1223           GTK_VALUE_SIGNAL(params[i]).d = va_arg (args, gpointer);
1224           break;
1225         case GTK_TYPE_FOREIGN:
1226           GTK_VALUE_FOREIGN(params[i]).data = va_arg (args, gpointer);
1227           GTK_VALUE_FOREIGN(params[i]).notify = 
1228             va_arg (args, GtkDestroyNotify);
1229           break;
1230         case GTK_TYPE_CALLBACK:
1231           GTK_VALUE_CALLBACK(params[i]).marshal = 
1232             va_arg (args, GtkCallbackMarshal);
1233           GTK_VALUE_CALLBACK(params[i]).data = va_arg (args, gpointer);
1234           GTK_VALUE_CALLBACK(params[i]).notify =
1235             va_arg (args, GtkDestroyNotify);
1236           break;
1237         case GTK_TYPE_C_CALLBACK:
1238           GTK_VALUE_C_CALLBACK(params[i]).func = va_arg (args, GtkFunction);
1239           GTK_VALUE_C_CALLBACK(params[i]).func_data = va_arg (args, gpointer);
1240           break;
1241         case GTK_TYPE_ARGS:
1242           GTK_VALUE_ARGS(params[i]).n_args = va_arg (args, int);
1243           GTK_VALUE_ARGS(params[i]).args = va_arg (args, GtkArg*);
1244           break;
1245         case GTK_TYPE_OBJECT:
1246           GTK_VALUE_OBJECT(params[i]) = va_arg (args, GtkObject*);
1247           g_assert (GTK_VALUE_OBJECT(params[i]) == NULL ||
1248                     GTK_CHECK_TYPE (GTK_VALUE_OBJECT(params[i]),
1249                                     params[i].type));
1250           break;
1251         default:
1252           g_error ("unsupported type %s in signal arg",
1253                    gtk_type_name (params[i].type));
1254           break;
1255         }
1256     }
1257
1258   params[i].type = return_val;
1259   params[i].name = NULL;
1260
1261   switch (GTK_FUNDAMENTAL_TYPE (return_val))
1262     {
1263     case GTK_TYPE_INVALID:
1264       break;
1265     case GTK_TYPE_NONE:
1266       break;
1267     case GTK_TYPE_CHAR:
1268       params[i].d.pointer_data = va_arg (args, gchar*);
1269       break;
1270     case GTK_TYPE_BOOL:
1271       params[i].d.pointer_data = va_arg (args, gint*);
1272       break;
1273     case GTK_TYPE_INT:
1274       params[i].d.pointer_data = va_arg (args, gint*);
1275       break;
1276     case GTK_TYPE_UINT:
1277       params[i].d.pointer_data = va_arg (args, guint*);
1278       break;
1279     case GTK_TYPE_ENUM:
1280       params[i].d.pointer_data = va_arg (args, gint*);
1281       break;
1282     case GTK_TYPE_FLAGS:
1283       params[i].d.pointer_data = va_arg (args, gint*);
1284       break;
1285     case GTK_TYPE_LONG:
1286       params[i].d.pointer_data = va_arg (args, glong*);
1287       break;
1288     case GTK_TYPE_ULONG:
1289       params[i].d.pointer_data = va_arg (args, gulong*);
1290       break;
1291     case GTK_TYPE_FLOAT:
1292       params[i].d.pointer_data = va_arg (args, gfloat*);
1293       break;
1294     case GTK_TYPE_STRING:
1295       params[i].d.pointer_data = va_arg (args, gchar**);
1296       break;
1297     case GTK_TYPE_POINTER:
1298       params[i].d.pointer_data = va_arg (args, gpointer*);
1299       break;
1300     case GTK_TYPE_BOXED:
1301       params[i].d.pointer_data = va_arg (args, gpointer*);
1302       break;
1303     case GTK_TYPE_OBJECT:
1304       params[i].d.pointer_data = va_arg (args, GtkObject**);
1305       break;
1306     case GTK_TYPE_SIGNAL:
1307     case GTK_TYPE_FOREIGN:
1308     case GTK_TYPE_CALLBACK:
1309     case GTK_TYPE_C_CALLBACK:
1310     case GTK_TYPE_ARGS:
1311     default:
1312       g_error ("unsupported type %s in signal return",
1313                gtk_type_name (return_val));
1314       break;
1315     }
1316 }