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