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