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