]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtksignal.c
Fix some problems with vertical alignment.
[~andy/gtk] / gtk / gtksignal.c
index b7e81d87131379c6c77962f0cf3ff86d147cac14..292315e3d3a17cdc7312e3e9454d599db593c5e3 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
 #include <stdarg.h>
 #include <string.h>
+#include <stdio.h>
 #include "gtksignal.h"
+#include "gtkargcollector.c"
 
 
 #define        SIGNAL_BLOCK_SIZE               (100)
 #define        HANDLER_BLOCK_SIZE              (200)
 #define        EMISSION_BLOCK_SIZE             (100)
 #define        DISCONNECT_INFO_BLOCK_SIZE      (64)
-#define MAX_SIGNAL_PARAMS              (32)
+#define MAX_SIGNAL_PARAMS              (31)
 
 enum
 {
@@ -34,15 +44,14 @@ enum
   EMISSION_DONE
 };
 
-#define GTK_RUN_TYPE(x)         ((x) & GTK_RUN_MASK)
+#define GTK_RUN_TYPE(x)         ((x) & GTK_RUN_BOTH)
 
 
 typedef struct _GtkSignal              GtkSignal;
 typedef struct _GtkSignalHash          GtkSignalHash;
 typedef struct _GtkHandler             GtkHandler;
-typedef struct _GtkHandlerInfo         GtkHandlerInfo;
 typedef struct _GtkEmission            GtkEmission;
-typedef union  _GtkEmissionAllocator   GtkEmissionAllocator;
+typedef struct _GtkEmissionHookData    GtkEmissionHookData;
 typedef struct _GtkDisconnectInfo      GtkDisconnectInfo;
 
 typedef void (*GtkSignalMarshaller0) (GtkObject *object,
@@ -54,23 +63,26 @@ struct _GtkSignal
   GtkType            object_type;
   gchar                     *name;
   guint                      function_offset;
-  GtkSignalRunType    run_type;
   GtkSignalMarshaller marshaller;
   GtkType            return_val;
+  guint                      signal_flags : 16;
+  guint                      nparams : 16;
   GtkType           *params;
-  guint                      nparams;
+  GHookList         *hook_list;
 };
 
 struct _GtkSignalHash
 {
   GtkType object_type;
-  guint          name_key_id;
+  GQuark  quark;
   guint          signal_id;
 };
 
 struct _GtkHandler
 {
   guint                   id;
+  GtkHandler     *next;
+  GtkHandler     *prev;
   guint                   blocked : 20;
   guint                   object_signal : 1;
   guint                   after : 1;
@@ -80,32 +92,22 @@ struct _GtkHandler
   GtkSignalFunc           func;
   gpointer        func_data;
   GtkSignalDestroy destroy_func;
-  GtkHandler     *prev;
-  GtkHandler     *next;
-};
-
-struct _GtkHandlerInfo
-{
-  GtkObject         *object;
-  GtkSignalMarshaller marshaller;
-  GtkArg            *params;
-  GtkType           *param_types;
-  GtkType            return_val;
-  GtkSignalRunType    run_type;
-  guint                      nparams;
-  guint                      signal_id;
 };
 
 struct _GtkEmission
 {
-  GtkObject *object;
-  guint             signal_id;
+  GtkObject   *object;
+  guint16      signal_id;
+  guint               in_hook : 1;
+  GtkEmission *next;
 };
 
-union _GtkEmissionAllocator
+struct _GtkEmissionHookData
 {
-  GtkEmissionAllocator *next;
-  GtkEmission          emission;
+  GtkObject *object;
+  guint signal_id;
+  guint n_params;
+  GtkArg *params;
 };
 
 struct _GtkDisconnectInfo
@@ -118,9 +120,9 @@ struct _GtkDisconnectInfo
 };
 
 
-static guint       gtk_signal_hash            (const gpointer h);
-static gint        gtk_signal_compare         (const gpointer h1,
-                                               const gpointer h2);
+static guint       gtk_signal_hash            (gconstpointer h);
+static gint        gtk_signal_compare         (gconstpointer h1,
+                                               gconstpointer h2);
 static GtkHandler*  gtk_signal_handler_new     (void);
 static void        gtk_signal_handler_ref     (GtkHandler    *handler);
 static void        gtk_signal_handler_unref   (GtkHandler    *handler,
@@ -128,10 +130,8 @@ static void            gtk_signal_handler_unref   (GtkHandler    *handler,
 static void        gtk_signal_handler_insert  (GtkObject     *object,
                                                GtkHandler    *handler);
 static void        gtk_signal_real_emit       (GtkObject     *object,
-                                               GtkSignal     *signal,
+                                               guint          signal_id,
                                                GtkArg        *params);
-static GtkHandler*  gtk_signal_get_handlers    (GtkObject     *object,
-                                               guint          signal_type);
 static guint       gtk_signal_connect_by_type (GtkObject     *object,
                                                guint          signal_id,
                                                GtkSignalFunc  func,
@@ -142,27 +142,31 @@ static guint          gtk_signal_connect_by_type (GtkObject     *object,
                                                gint           no_marshal);
 static guint       gtk_alive_disconnecter     (GtkDisconnectInfo *info);
 static GtkEmission* gtk_emission_new          (void);
-static void        gtk_emission_add           (GList         **emissions,
+static void        gtk_emission_add           (GtkEmission   **emissions,
                                                GtkObject      *object,
                                                guint           signal_type);
-static void        gtk_emission_remove        (GList         **emissions,
+static void        gtk_emission_remove        (GtkEmission   **emissions,
                                                GtkObject      *object,
                                                guint           signal_type);
-static gint        gtk_emission_check         (GList          *emissions,
+static gint        gtk_emission_check         (GtkEmission    *emissions,
                                                GtkObject      *object,
                                                guint           signal_type);
 static gint        gtk_handlers_run           (GtkHandler     *handlers,
-                                               GtkHandlerInfo *info,
+                                               GtkSignal      *signal,
+                                               GtkObject      *object,
+                                               GtkArg         *params,
                                                gint            after);
-static void        gtk_params_get             (GtkArg         *params,
+static gboolean gtk_emission_hook_marshaller   (GHook          *hook,
+                                               gpointer        data);
+static gboolean        gtk_signal_collect_params      (GtkArg         *params,
                                                guint           nparams,
                                                GtkType        *param_types,
-                                               GtkType         return_val,
-                                               va_list         args);
+                                               GtkType         return_type,
+                                               va_list         var_args);
 
 #define LOOKUP_SIGNAL_ID(signal_id)    ( \
-  signal_id > 0 && signal_id < gtk_n_signals ? \
-    (GtkSignal*) gtk_signals + signal_id : \
+  signal_id > 0 && signal_id < _gtk_private_n_signals ? \
+    (GtkSignal*) _gtk_private_signals + signal_id : \
     (GtkSignal*) 0 \
 )
 
@@ -171,20 +175,25 @@ static GtkSignalMarshal global_marshaller = NULL;
 static GtkSignalDestroy global_destroy_notify = NULL;
 
 static guint                    gtk_handler_id = 1;
-static guint                    handler_key_id = 0;
+static guint                    gtk_handler_quark = 0;
 static GHashTable              *gtk_signal_hash_table = NULL;
-static GtkSignal               *gtk_signals = NULL;
-static guint                    gtk_n_signals = 0;
+#ifdef G_OS_WIN32
+#define EXPORT __declspec(dllexport)
+#else
+#define EXPORT
+#endif
+EXPORT GtkSignal               *_gtk_private_signals = NULL;
+EXPORT guint                    _gtk_private_n_signals = 0;
 static GMemChunk               *gtk_signal_hash_mem_chunk = NULL;
 static GMemChunk               *gtk_disconnect_info_mem_chunk = NULL;
 static GtkHandler              *gtk_handler_free_list = NULL;
-static GtkEmissionAllocator    *gtk_emission_free_list = NULL;
+static GtkEmission             *gtk_free_emissions = NULL;
 
 
 
-static GList *current_emissions = NULL;
-static GList *stop_emissions = NULL;
-static GList *restart_emissions = NULL;
+static GtkEmission *current_emissions = NULL;
+static GtkEmission *stop_emissions = NULL;
+static GtkEmission *restart_emissions = NULL;
 
 static GtkSignal*
 gtk_signal_next_and_invalidate (void)
@@ -203,22 +212,24 @@ gtk_signal_next_and_invalidate (void)
       
       /* nearest pow
        */
-      size = gtk_n_signals + SIGNAL_BLOCK_SIZE;
+      size = _gtk_private_n_signals + SIGNAL_BLOCK_SIZE;
       size *= sizeof (GtkSignal);
       i = 1;
       while (i < size)
        i <<= 1;
       size = i;
       
-      gtk_signals = g_realloc (gtk_signals, size);
+      _gtk_private_signals = g_realloc (_gtk_private_signals, size);
       
-      gtk_n_free_signals = size / sizeof (GtkSignal) - gtk_n_signals;
+      gtk_n_free_signals = size / sizeof (GtkSignal) - _gtk_private_n_signals;
       
-      memset (gtk_signals + gtk_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
+      memset (_gtk_private_signals + _gtk_private_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
     }
   
-  new_signal_id = gtk_n_signals++;
+  new_signal_id = _gtk_private_n_signals++;
   gtk_n_free_signals--;
+
+  g_assert (_gtk_private_n_signals < 65535);
   
   signal = LOOKUP_SIGNAL_ID (new_signal_id);
   if (signal)
@@ -227,17 +238,35 @@ gtk_signal_next_and_invalidate (void)
   return signal;
 }
 
+static inline GtkHandler*
+gtk_signal_get_handlers (GtkObject *object,
+                        guint      signal_id)
+{
+  GtkHandler *handlers;
+  
+  handlers = gtk_object_get_data_by_id (object, gtk_handler_quark);
+  
+  while (handlers)
+    {
+      if (handlers->signal_id == signal_id)
+       return handlers;
+      handlers = handlers->next;
+    }
+  
+  return NULL;
+}
+
 void
 gtk_signal_init (void)
 {
-  if (!handler_key_id)
+  if (!gtk_handler_quark)
     {
       GtkSignal *zero;
       
       zero = gtk_signal_next_and_invalidate ();
       g_assert (zero == NULL);
       
-      handler_key_id = gtk_object_data_force_id ("gtk-signal-handlers");
+      gtk_handler_quark = g_quark_from_static_string ("gtk-signal-handlers");
       
       gtk_signal_hash_mem_chunk =
        g_mem_chunk_new ("GtkSignalHash mem chunk",
@@ -250,7 +279,7 @@ gtk_signal_init (void)
                         sizeof (GtkDisconnectInfo) * DISCONNECT_INFO_BLOCK_SIZE,
                         G_ALLOC_AND_FREE);
       gtk_handler_free_list = NULL;
-      gtk_emission_free_list = NULL;
+      gtk_free_emissions = NULL;
       
       gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash,
                                                gtk_signal_compare);
@@ -259,7 +288,7 @@ gtk_signal_init (void)
 
 guint
 gtk_signal_newv (const gchar        *r_name,
-                GtkSignalRunType     run_type,
+                GtkSignalRunType     signal_flags,
                 GtkType              object_type,
                 guint                function_offset,
                 GtkSignalMarshaller  marshaller,
@@ -269,24 +298,25 @@ gtk_signal_newv (const gchar           *r_name,
 {
   GtkSignal *signal;
   GtkSignalHash *hash;
-  guint id;
+  GQuark quark;
   guint i;
   gchar *name;
   
   g_return_val_if_fail (r_name != NULL, 0);
   g_return_val_if_fail (marshaller != NULL, 0);
-  g_return_val_if_fail (nparams <= MAX_SIGNAL_PARAMS, 0);
+  g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
   if (nparams)
     g_return_val_if_fail (params != NULL, 0);
   
-  if (!handler_key_id)
+  if (!gtk_handler_quark)
     gtk_signal_init ();
 
+
   name = g_strdup (r_name);
   g_strdelimit (name, NULL, '_');
-  
-  id = gtk_signal_lookup (name, object_type);
-  if (id)
+
+  quark = gtk_signal_lookup (name, object_type);
+  if (quark)
     {
       g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
                 r_name,
@@ -295,6 +325,15 @@ gtk_signal_newv (const gchar            *r_name,
       return 0;
     }
   
+  if (return_val != GTK_TYPE_NONE &&
+      (signal_flags & GTK_RUN_BOTH) == GTK_RUN_FIRST)
+    {
+      g_warning ("gtk_signal_newv(): signal \"%s\" - return value `%s' incompatible with GTK_RUN_FIRST",
+                name, gtk_type_name (return_val));
+      g_free (name);
+      return 0;
+    }
+  
   signal = gtk_signal_next_and_invalidate ();
   
   /* signal->signal_id already set */
@@ -302,10 +341,11 @@ gtk_signal_newv (const gchar           *r_name,
   signal->object_type = object_type;
   signal->name = name;
   signal->function_offset = function_offset;
-  signal->run_type = run_type;
   signal->marshaller = marshaller;
   signal->return_val = return_val;
+  signal->signal_flags = signal_flags;
   signal->nparams = nparams;
+  signal->hook_list = NULL;
   
   if (nparams > 0)
     {
@@ -321,19 +361,19 @@ gtk_signal_newv (const gchar           *r_name,
    */
   hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
   hash->object_type = object_type;
-  hash->name_key_id = gtk_object_data_force_id (signal->name);
+  hash->quark = g_quark_from_string (signal->name);
   hash->signal_id = signal->signal_id;
   g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
 
   /* insert "signal-name" into hash table
    */
   g_strdelimit (signal->name, NULL, '-');
-  id = gtk_object_data_force_id (signal->name);
-  if (id != hash->name_key_id)
+  quark = g_quark_from_static_string (signal->name);
+  if (quark != hash->quark)
     {
       hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
       hash->object_type = object_type;
-      hash->name_key_id = id;
+      hash->quark = quark;
       hash->signal_id = signal->signal_id;
       g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
     }
@@ -343,7 +383,7 @@ gtk_signal_newv (const gchar             *r_name,
 
 guint
 gtk_signal_new (const gchar        *name,
-               GtkSignalRunType     run_type,
+               GtkSignalRunType     signal_flags,
                GtkType              object_type,
                guint                function_offset,
                GtkSignalMarshaller  marshaller,
@@ -356,7 +396,7 @@ gtk_signal_new (const gchar     *name,
   va_list args;
   guint signal_id;
   
-  g_return_val_if_fail (nparams <= MAX_SIGNAL_PARAMS, 0);
+  g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
   
   if (nparams > 0)
     {
@@ -373,7 +413,7 @@ gtk_signal_new (const gchar     *name,
     params = NULL;
   
   signal_id = gtk_signal_newv (name,
-                              run_type,
+                              signal_flags,
                               object_type,
                               function_offset,
                               marshaller,
@@ -391,27 +431,38 @@ gtk_signal_lookup (const gchar *name,
                   GtkType      object_type)
 {
   GtkSignalHash hash;
-  
+  GtkType lookup_type;
+  gpointer class = NULL;
+
   g_return_val_if_fail (name != NULL, 0);
-  g_return_val_if_fail (gtk_type_is_a (object_type, GTK_TYPE_OBJECT), 0);
+  g_return_val_if_fail (GTK_TYPE_IS_OBJECT (object_type), 0);
   
-  hash.name_key_id = gtk_object_data_try_key (name);
-  if (hash.name_key_id)
+ relookup:
+
+  lookup_type = object_type;
+  hash.quark = g_quark_try_string (name);
+  if (hash.quark)
     {
-      while (object_type)
+      while (lookup_type)
        {
          guint signal_id;
          
-         hash.object_type = object_type;
+         hash.object_type = lookup_type;
          
          signal_id = GPOINTER_TO_UINT (g_hash_table_lookup (gtk_signal_hash_table, &hash));
          if (signal_id)
            return signal_id;
          
-         object_type = gtk_type_parent (object_type);
+         lookup_type = gtk_type_parent (lookup_type);
        }
     }
-  
+
+  if (!class)
+    {
+      class = gtk_type_class (object_type);
+      goto relookup;
+    }
+
   return 0;
 }
 
@@ -432,7 +483,7 @@ gtk_signal_query (guint signal_id)
       query->signal_id = signal_id;
       query->signal_name = signal->name;
       query->is_user_signal = signal->function_offset == 0;
-      query->run_type = signal->run_type;
+      query->signal_flags = signal->signal_flags;
       query->return_val = signal->return_val;
       query->nparams = signal->nparams;
       query->params = signal->params;
@@ -466,13 +517,15 @@ gtk_signal_emitv (GtkObject           *object,
 
   g_return_if_fail (object != NULL);
   g_return_if_fail (signal_id >= 1);
-  g_return_if_fail (params != NULL);
   
   signal = LOOKUP_SIGNAL_ID (signal_id);
   g_return_if_fail (signal != NULL);
   g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
 
-  gtk_signal_real_emit (object, signal, params);
+  if (signal->nparams > 0)
+    g_return_if_fail (params != NULL);
+
+  gtk_signal_real_emit (object, signal_id, params);
 }
 
 void
@@ -482,7 +535,8 @@ gtk_signal_emit (GtkObject *object,
 {
   GtkSignal *signal;
   va_list    args;
-  GtkArg     params[MAX_SIGNAL_PARAMS];
+  GtkArg     params[MAX_SIGNAL_PARAMS + 1];
+  gboolean   abort;
 
   g_return_if_fail (object != NULL);
   g_return_if_fail (signal_id >= 1);
@@ -492,14 +546,15 @@ gtk_signal_emit (GtkObject *object,
   g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
 
   va_start (args, signal_id);
-  gtk_params_get (params,
-                 signal->nparams,
-                 signal->params,
-                 signal->return_val,
-                 args);
+  abort = gtk_signal_collect_params (params,
+                                    signal->nparams,
+                                    signal->params,
+                                    signal->return_val,
+                                    args);
   va_end (args);
 
-  gtk_signal_real_emit (object, signal, params);
+  if (!abort)
+    gtk_signal_real_emit (object, signal_id, params);
 }
 
 void
@@ -523,7 +578,7 @@ gtk_signal_emitv_by_name (GtkObject           *object,
       g_return_if_fail (signal != NULL);
       g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
 
-      gtk_signal_real_emit (object, signal, params);
+      gtk_signal_real_emit (object, signal_id, params);
     }
   else
     {
@@ -548,22 +603,24 @@ gtk_signal_emit_by_name (GtkObject         *object,
   if (signal_id >= 1)
     {
       GtkSignal *signal;
-      GtkArg     params[MAX_SIGNAL_PARAMS];
+      GtkArg     params[MAX_SIGNAL_PARAMS + 1];
       va_list    args;
+      gboolean   abort;
       
       signal = LOOKUP_SIGNAL_ID (signal_id);
       g_return_if_fail (signal != NULL);
       g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
 
       va_start (args, name);
-      gtk_params_get (params,
-                     signal->nparams,
-                     signal->params,
-                     signal->return_val,
-                     args);
+      abort = gtk_signal_collect_params (params,
+                                        signal->nparams,
+                                        signal->params,
+                                        signal->return_val,
+                                        args);
       va_end (args);
 
-      gtk_signal_real_emit (object, signal, params);
+      if (!abort)
+       gtk_signal_real_emit (object, signal_id, params);
     }
   else
     {
@@ -577,11 +634,21 @@ void
 gtk_signal_emit_stop (GtkObject *object,
                      guint       signal_id)
 {
+  gint state;
+
   g_return_if_fail (object != NULL);
   g_return_if_fail (signal_id >= 1);
   
-  if (gtk_emission_check (current_emissions, object, signal_id))
-    gtk_emission_add (&stop_emissions, object, signal_id);
+  state = gtk_emission_check (current_emissions, object, signal_id);
+  if (state > 1)
+    g_warning ("gtk_signal_emit_stop(): emission (%u) for object `%s' cannot be stopped from emission hook",
+              signal_id,
+              gtk_type_name (GTK_OBJECT_TYPE (object)));
+  else if (state)
+    {
+      if (!gtk_emission_check (stop_emissions, object, signal_id))
+       gtk_emission_add (&stop_emissions, object, signal_id);
+    }
   else
     g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
               signal_id,
@@ -610,21 +677,16 @@ guint
 gtk_signal_n_emissions (GtkObject  *object,
                        guint       signal_id)
 {
-  GList *list;
+  GtkEmission *emission;
   guint n;
   
   g_return_val_if_fail (object != NULL, 0);
   g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
   
   n = 0;
-  for (list = current_emissions; list; list = list->next)
+  for (emission = current_emissions; emission; emission = emission->next)
     {
-      GtkEmission *emission;
-      
-      emission = list->data;
-      
-      if ((emission->object == object) &&
-         (emission->signal_id == signal_id))
+      if (emission->object == object && emission->signal_id == signal_id)
        n++;
     }
   
@@ -738,18 +800,6 @@ gtk_signal_connect_full (GtkObject      *object,
                                       object_signal, after, FALSE);
 }
 
-guint
-gtk_signal_connect_interp (GtkObject        *object,
-                          const gchar       *name,
-                          GtkCallbackMarshal func,
-                          gpointer           func_data,
-                          GtkDestroyNotify   destroy_func,
-                          gint               after)
-{
-  return gtk_signal_connect_full (object, name, NULL, func,
-                                 func_data, destroy_func, FALSE, after);
-}
-
 guint
 gtk_signal_connect_object (GtkObject    *object,
                           const gchar   *name,
@@ -874,7 +924,7 @@ gtk_signal_disconnect (GtkObject *object,
   g_return_if_fail (object != NULL);
   g_return_if_fail (handler_id > 0);
   
-  handler = gtk_object_get_data_by_id (object, handler_key_id);
+  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
   
   while (handler)
     {
@@ -903,7 +953,7 @@ gtk_signal_disconnect_by_func (GtkObject     *object,
   g_return_if_fail (func != NULL);
   
   found_one = FALSE;
-  handler = gtk_object_get_data_by_id (object, handler_key_id);
+  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
   
   while (handler)
     {
@@ -936,7 +986,7 @@ gtk_signal_disconnect_by_data (GtkObject *object,
   g_return_if_fail (object != NULL);
   
   found_one = FALSE;
-  handler = gtk_object_get_data_by_id (object, handler_key_id);
+  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
   
   while (handler)
     {
@@ -967,7 +1017,7 @@ gtk_signal_handler_block (GtkObject *object,
   g_return_if_fail (object != NULL);
   g_return_if_fail (handler_id > 0);
   
-  handler = gtk_object_get_data_by_id (object, handler_key_id);
+  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
   
   while (handler)
     {
@@ -994,7 +1044,7 @@ gtk_signal_handler_block_by_func (GtkObject        *object,
   g_return_if_fail (func != NULL);
   
   found_one = FALSE;
-  handler = gtk_object_get_data_by_id (object, handler_key_id);
+  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
   
   while (handler)
     {
@@ -1022,7 +1072,7 @@ gtk_signal_handler_block_by_data (GtkObject *object,
   g_return_if_fail (object != NULL);
   
   found_one = FALSE;
-  handler = gtk_object_get_data_by_id (object, handler_key_id);
+  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
   
   while (handler)
     {
@@ -1048,7 +1098,7 @@ gtk_signal_handler_unblock (GtkObject *object,
   g_return_if_fail (object != NULL);
   g_return_if_fail (handler_id > 0);
   
-  handler = gtk_object_get_data_by_id (object, handler_key_id);
+  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
   
   while (handler)
     {
@@ -1078,7 +1128,7 @@ gtk_signal_handler_unblock_by_func (GtkObject       *object,
   g_return_if_fail (func != NULL);
   
   found_one = FALSE;
-  handler = gtk_object_get_data_by_id (object, handler_key_id);
+  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
   
   while (handler)
     {
@@ -1107,7 +1157,7 @@ gtk_signal_handler_unblock_by_data (GtkObject *object,
   g_return_if_fail (object != NULL);
   
   found_one = FALSE;
-  handler = gtk_object_get_data_by_id (object, handler_key_id);
+  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
   
   while (handler)
     {
@@ -1135,7 +1185,7 @@ gtk_signal_handlers_destroy (GtkObject *object)
    * handler_key data on each removal
    */
   
-  handler = gtk_object_get_data_by_id (object, handler_key_id);
+  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
   if (handler)
     {
       handler = handler->next;
@@ -1144,27 +1194,24 @@ gtk_signal_handlers_destroy (GtkObject *object)
          GtkHandler *next;
          
          next = handler->next;
-         gtk_signal_handler_unref (handler, object);
+         if (handler->id > 0)
+            {
+             handler->id = 0;
+             handler->blocked += 1;
+             gtk_signal_handler_unref (handler, object);
+           }
          handler = next;
        }
-      handler = gtk_object_get_data_by_id (object, handler_key_id);
-      gtk_signal_handler_unref (handler, object);
+      handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
+      if (handler->id > 0)
+        {
+         handler->id = 0;
+         handler->blocked += 1;
+         gtk_signal_handler_unref (handler, object);
+       }
     }
 }
 
-void
-gtk_signal_default_marshaller (GtkObject      *object,
-                              GtkSignalFunc   func,
-                              gpointer        func_data,
-                              GtkArg         *params)
-{
-  GtkSignalMarshaller0 rfunc;
-  
-  rfunc = (GtkSignalMarshaller0) func;
-  
-  (* rfunc) (object, func_data);
-}
-
 void
 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
                      GtkSignalDestroy destroy_func)
@@ -1174,21 +1221,21 @@ gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
 }
 
 static guint
-gtk_signal_hash (const gpointer h)
+gtk_signal_hash (gconstpointer h)
 {
-  register GtkSignalHash *hash = h;
+  register const GtkSignalHash *hash = h;
   
-  return hash->object_type ^ hash->name_key_id;
+  return hash->object_type ^ hash->quark;
 }
 
 static gint
-gtk_signal_compare (const gpointer h1,
-                   const gpointer h2)
+gtk_signal_compare (gconstpointer h1,
+                   gconstpointer h2)
 {
-  register GtkSignalHash *hash1 = h1;
-  register GtkSignalHash *hash2 = h2;
+  register const GtkSignalHash *hash1 = h1;
+  register const GtkSignalHash *hash2 = h2;
   
-  return (hash1->name_key_id == hash2->name_key_id &&
+  return (hash1->quark == hash2->quark &&
          hash1->object_type == hash2->object_type);
 }
 
@@ -1276,11 +1323,11 @@ gtk_signal_handler_unref (GtkHandler *handler,
       if (handler->prev)
        handler->prev->next = handler->next;
       else if (handler->next)
-       gtk_object_set_data_by_id (object, handler_key_id, handler->next);
+       gtk_object_set_data_by_id (object, gtk_handler_quark, handler->next);
       else
        {
          GTK_OBJECT_UNSET_FLAGS (object, GTK_CONNECTED);
-         gtk_object_set_data_by_id (object, handler_key_id, NULL);
+         gtk_object_set_data_by_id (object, gtk_handler_quark, NULL);
        }
       if (handler->next)
        handler->next->prev = handler->prev;
@@ -1299,11 +1346,11 @@ gtk_signal_handler_insert (GtkObject  *object,
   /* FIXME: remove */ g_assert (handler->next == NULL);
   /* FIXME: remove */ g_assert (handler->prev == NULL);
   
-  tmp = gtk_object_get_data_by_id (object, handler_key_id);
+  tmp = gtk_object_get_data_by_id (object, gtk_handler_quark);
   if (!tmp)
     {
       GTK_OBJECT_SET_FLAGS (object, GTK_CONNECTED);
-      gtk_object_set_data_by_id (object, handler_key_id, handler);
+      gtk_object_set_data_by_id (object, gtk_handler_quark, handler);
     }
   else
     while (tmp)
@@ -1316,7 +1363,7 @@ gtk_signal_handler_insert (GtkObject  *object,
                handler->prev = tmp->prev;
              }
            else
-             gtk_object_set_data_by_id (object, handler_key_id, handler);
+             gtk_object_set_data_by_id (object, gtk_handler_quark, handler);
            tmp->prev = handler;
            handler->next = tmp;
            break;
@@ -1332,74 +1379,136 @@ gtk_signal_handler_insert (GtkObject  *object,
       }
 }
 
+
+#ifdef  G_ENABLE_DEBUG
+/* value typically set via gdb */
+static GtkObject *gtk_trace_signal_object = NULL;
+#endif  /* G_ENABLE_DEBUG */
+
+
 static void
 gtk_signal_real_emit (GtkObject *object,
-                     GtkSignal *signal,
+                     guint      signal_id,
                      GtkArg    *params)
 {
+  GtkSignal     signal;
   GtkHandler   *handlers;
-  GtkHandlerInfo info;
-  guchar       **signal_func_offset;
-  register guint signal_id = signal->signal_id;
-  
-  if ((signal->run_type & GTK_RUN_NO_RECURSE) &&
-      gtk_emission_check (current_emissions, object, signal_id))
+  GtkSignalFunc  signal_func;
+  GtkEmission   *emission;
+
+  /* gtk_handlers_run() expects a reentrant GtkSignal*, so we allocate
+   * it locally on the stack. we save some lookups ourselves with this as well.
+   */
+  signal = *LOOKUP_SIGNAL_ID (signal_id);
+  if (signal.function_offset)
+    signal_func = G_STRUCT_MEMBER (GtkSignalFunc, ((GTypeInstance*) object)->g_class, signal.function_offset);
+  else
+    signal_func = NULL;
+  
+#ifdef  G_ENABLE_DEBUG
+  if (gtk_debug_flags & GTK_DEBUG_SIGNALS ||
+      object == gtk_trace_signal_object)
+    g_message ("%s::%s emitted (object=%p class-method=%p)\n",
+              gtk_type_name (GTK_OBJECT_TYPE (object)),
+              signal.name,
+              object,
+              signal_func);
+#endif  /* G_ENABLE_DEBUG */
+  
+  if (signal.signal_flags & GTK_RUN_NO_RECURSE)
     {
-      gtk_emission_add (&restart_emissions, object, signal_id);
-      return;
+      gint state;
+      
+      state = gtk_emission_check (current_emissions, object, signal_id);
+      if (state)
+       {
+         if (state > 1)
+           g_warning ("gtk_signal_real_emit(): emission (%u) for object `%s' cannot be restarted from emission hook",
+                      signal_id,
+                      gtk_type_name (GTK_OBJECT_TYPE (object)));
+         else if (!gtk_emission_check (restart_emissions, object, signal_id))
+           gtk_emission_add (&restart_emissions, object, signal_id);
+         
+         return;
+       }
     }
   
   gtk_object_ref (object);
-
+  
   gtk_emission_add (&current_emissions, object, signal_id);
+  emission = current_emissions;
   
  emission_restart:
-  if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_LAST && signal->function_offset != 0)
+  
+  if (signal.signal_flags & GTK_RUN_FIRST && signal_func)
     {
-      signal_func_offset = (guchar**) ((guchar*) object->klass +
-                                      signal->function_offset);
-      if (*signal_func_offset)
-       (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
-                               NULL, params);
+      signal.marshaller (object, signal_func, NULL, params);
+      
+      if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
+       {
+         gtk_emission_remove (&stop_emissions, object, signal_id);
+         goto emission_done;
+       }
+      else if (restart_emissions &&
+              signal.signal_flags & GTK_RUN_NO_RECURSE &&
+              gtk_emission_check (restart_emissions, object, signal_id))
+       {
+         gtk_emission_remove (&restart_emissions, object, signal_id);
+         
+         goto emission_restart;
+       }
     }
   
+  if (signal.hook_list && !GTK_OBJECT_DESTROYED (object))
+    {
+      GtkEmissionHookData data;
+
+      data.object = object;
+      data.n_params = signal.nparams;
+      data.params = params;
+      data.signal_id = signal_id;
+      emission->in_hook = 1;
+      g_hook_list_marshal_check (signal.hook_list, TRUE, gtk_emission_hook_marshaller, &data);
+      emission->in_hook = 0;
+    }
+
   if (GTK_OBJECT_CONNECTED (object))
     {
       handlers = gtk_signal_get_handlers (object, signal_id);
       if (handlers)
        {
-         info.object = object;
-         info.marshaller = signal->marshaller;
-         info.params = params;
-         info.param_types = signal->params;
-         info.return_val = signal->return_val;
-         info.nparams = signal->nparams;
-         info.run_type = signal->run_type;
-         info.signal_id = signal_id;
-
-         switch (gtk_handlers_run (handlers, &info, FALSE))
+         gint return_val;
+         
+         return_val = gtk_handlers_run (handlers, &signal, object, params, FALSE);
+         switch (return_val)
            {
-           case  EMISSION_CONTINUE:
+           case EMISSION_CONTINUE:
              break;
-           case  EMISSION_RESTART:
+           case EMISSION_RESTART:
              goto emission_restart;
-           case  EMISSION_DONE:
+           case EMISSION_DONE:
              goto emission_done;
            }
        }
-      else
-       info.object = NULL;
     }
-  else
-    info.object = NULL;
   
-  if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_FIRST && signal->function_offset != 0)
+  if (signal.signal_flags & GTK_RUN_LAST && signal_func)
     {
-      signal_func_offset = (guchar**) ((guchar*) object->klass +
-                                      signal->function_offset);
-      if (*signal_func_offset)
-       (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
-                               NULL, params);
+      signal.marshaller (object, signal_func, NULL, params);
+      
+      if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
+       {
+         gtk_emission_remove (&stop_emissions, object, signal_id);
+         goto emission_done;
+       }
+      else if (restart_emissions &&
+              signal.signal_flags & GTK_RUN_NO_RECURSE &&
+              gtk_emission_check (restart_emissions, object, signal_id))
+       {
+         gtk_emission_remove (&restart_emissions, object, signal_id);
+         
+         goto emission_restart;
+       }
     }
   
   if (GTK_OBJECT_CONNECTED (object))
@@ -1407,18 +1516,10 @@ gtk_signal_real_emit (GtkObject *object,
       handlers = gtk_signal_get_handlers (object, signal_id);
       if (handlers)
        {
-         if (!info.object)
-           {
-             info.object = object;
-             info.marshaller = signal->marshaller;
-             info.params = params;
-             info.param_types = signal->params;
-             info.return_val = signal->return_val;
-             info.nparams = signal->nparams;
-             info.run_type = signal->run_type;
-             info.signal_id = signal_id;
-           }
-         switch (gtk_handlers_run (handlers, &info, TRUE))
+         gint return_val;
+         
+         return_val = gtk_handlers_run (handlers, &signal, object, params, TRUE);
+         switch (return_val)
            {
            case  EMISSION_CONTINUE:
              break;
@@ -1431,42 +1532,58 @@ gtk_signal_real_emit (GtkObject *object,
     }
   
  emission_done:
+  if (restart_emissions && signal.signal_flags & GTK_RUN_NO_RECURSE)
+    gtk_emission_remove (&restart_emissions, object, signal_id);
   
   gtk_emission_remove (&current_emissions, object, signal_id);
   
-  if (signal->run_type & GTK_RUN_NO_RECURSE)
-    gtk_emission_remove (&restart_emissions, object, signal_id);
-  
   gtk_object_unref (object);
 }
 
-static GtkHandler*
-gtk_signal_get_handlers (GtkObject *object,
-                        guint      signal_id)
+guint
+gtk_signal_handler_pending (GtkObject          *object,
+                           guint                signal_id,
+                           gboolean             may_be_blocked)
 {
   GtkHandler *handlers;
+  guint handler_id;
   
-  handlers = gtk_object_get_data_by_id (object, handler_key_id);
+  g_return_val_if_fail (object != NULL, 0);
+  g_return_val_if_fail (signal_id >= 1, 0);
+
+  if (GTK_OBJECT_CONNECTED (object))
+    handlers = gtk_signal_get_handlers (object, signal_id);
+  else
+    return 0;
   
-  while (handlers)
+  handler_id = 0;
+  while (handlers && handlers->signal_id == signal_id)
     {
-      if (handlers->signal_id == signal_id)
-       return handlers;
+      if (handlers->id > 0 &&
+         (may_be_blocked || handlers->blocked == FALSE))
+       {
+         handler_id = handlers->id;
+         break;
+       }
+      
       handlers = handlers->next;
     }
   
-  return NULL;
+  return handler_id;
 }
 
 guint
-gtk_signal_handler_pending (GtkObject          *object,
-                           guint                signal_id,
-                           gboolean             may_be_blocked)
+gtk_signal_handler_pending_by_func (GtkObject           *object,
+                                   guint                signal_id,
+                                   gboolean             may_be_blocked,
+                                   GtkSignalFunc        func,
+                                   gpointer             data)
 {
   GtkHandler *handlers;
   guint handler_id;
   
   g_return_val_if_fail (object != NULL, 0);
+  g_return_val_if_fail (func != NULL, 0);
   g_return_val_if_fail (signal_id >= 1, 0);
 
   if (GTK_OBJECT_CONNECTED (object))
@@ -1478,6 +1595,8 @@ gtk_signal_handler_pending (GtkObject             *object,
   while (handlers && handlers->signal_id == signal_id)
     {
       if (handlers->id > 0 &&
+         handlers->func == func &&
+         handlers->func_data == data &&
          (may_be_blocked || handlers->blocked == 0))
        {
          handler_id = handlers->id;
@@ -1490,6 +1609,113 @@ gtk_signal_handler_pending (GtkObject           *object,
   return handler_id;
 }
 
+gint
+gtk_signal_handler_pending_by_id (GtkObject *object,
+                                 guint      handler_id,
+                                 gboolean   may_be_blocked)
+{
+  GtkHandler *handlers;
+  
+  g_return_val_if_fail (object != NULL, FALSE);
+  g_return_val_if_fail (handler_id >= 1, FALSE);
+
+  if (GTK_OBJECT_CONNECTED (object))
+    handlers = gtk_object_get_data_by_id (object, gtk_handler_quark);
+  else
+    return FALSE;
+  
+  while (handlers)
+    {
+      if (handlers->id == handler_id)
+       return may_be_blocked || handlers->blocked == 0;
+      
+      handlers = handlers->next;
+    }
+  
+  return FALSE;
+}
+
+guint
+gtk_signal_add_emission_hook (guint           signal_id,
+                             GtkEmissionHook hook_func,
+                             gpointer        data)
+{
+  return gtk_signal_add_emission_hook_full (signal_id, hook_func, data, NULL);
+}
+
+guint
+gtk_signal_add_emission_hook_full (guint           signal_id,
+                                  GtkEmissionHook hook_func,
+                                  gpointer        data,
+                                  GDestroyNotify  destroy)
+{
+  static guint seq_hook_id = 1;
+  GtkSignal *signal;
+  GHook *hook;
+
+  g_return_val_if_fail (signal_id > 0, 0);
+  g_return_val_if_fail (hook_func != NULL, 0);
+  
+  signal = LOOKUP_SIGNAL_ID (signal_id);
+  g_return_val_if_fail (signal != NULL, 0);
+  if (signal->signal_flags & GTK_RUN_NO_HOOKS)
+    {
+      g_warning ("gtk_signal_add_emission_hook_full(): signal \"%s\" does not support emission hooks",
+                signal->name);
+      return 0;
+    }
+
+  if (!signal->hook_list)
+    {
+      signal->hook_list = g_new (GHookList, 1);
+      g_hook_list_init (signal->hook_list, sizeof (GHook));
+    }
+
+  hook = g_hook_alloc (signal->hook_list);
+  hook->data = data;
+  hook->func = hook_func;
+  hook->destroy = destroy;
+
+  signal->hook_list->seq_id = seq_hook_id;
+  g_hook_prepend (signal->hook_list, hook);
+  seq_hook_id = signal->hook_list->seq_id;
+
+  return hook->hook_id;
+}
+
+void
+gtk_signal_remove_emission_hook (guint signal_id,
+                                guint hook_id)
+{
+  GtkSignal *signal;
+
+  g_return_if_fail (signal_id > 0);
+  g_return_if_fail (hook_id > 0);
+
+  signal = LOOKUP_SIGNAL_ID (signal_id);
+  g_return_if_fail (signal != NULL);
+
+  if (!signal->hook_list || !g_hook_destroy (signal->hook_list, hook_id))
+    g_warning ("gtk_signal_remove_emission_hook(): could not find hook (%u)", hook_id);
+}
+
+static gboolean
+gtk_emission_hook_marshaller (GHook   *hook,
+                             gpointer data_p)
+{
+  GtkEmissionHookData *data = data_p;
+  GtkEmissionHook func;
+
+  func = hook->func;
+
+  if (!GTK_OBJECT_DESTROYED (data->object))
+    return func (data->object, data->signal_id,
+                data->n_params, data->params,
+                hook->data);
+  else
+    return TRUE;
+}
+
 static guint
 gtk_signal_connect_by_type (GtkObject      *object,
                            guint            signal_id,
@@ -1503,17 +1729,22 @@ gtk_signal_connect_by_type (GtkObject       *object,
   GtkObjectClass *class;
   GtkHandler *handler;
   gint found_it;
+  GtkSignal *signal;
+  g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
   
-  g_return_val_if_fail (object != NULL, 0);
-  g_return_val_if_fail (object->klass != NULL, 0);
-  
+  signal = LOOKUP_SIGNAL_ID (signal_id);
+
   /* Search through the signals for this object and make
    *  sure the one we are adding is valid. We need to perform
    *  the lookup on the objects parents as well. If it isn't
    *  valid then issue a warning and return.
+   * As of now (1998-05-27) this lookup shouldn't be neccessarry
+   *  anymore since gtk_signal_lookup() has been reworked to only
+   *  return correct signal ids per class-branch.
    */
   found_it = FALSE;
-  class = object->klass;
+  class = GTK_OBJECT_GET_CLASS (object);
   while (class)
     {
       GtkType parent;
@@ -1531,9 +1762,9 @@ gtk_signal_connect_by_type (GtkObject         *object,
            break;
          }
       
-      parent = gtk_type_parent (class->type);
-      if (parent)
-       class = gtk_type_class (parent);
+      parent = g_type_parent (GTK_CLASS_TYPE (class));
+      if (GTK_TYPE_IS_OBJECT (parent))
+       class = g_type_class_peek (parent);
       else
        class = NULL;
     }
@@ -1542,14 +1773,14 @@ gtk_signal_connect_by_type (GtkObject       *object,
     {
       g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
                 signal_id,
-                gtk_type_name (object->klass->type));
+                GTK_OBJECT_TYPE_NAME (object));
       return 0;
     }
   
   handler = gtk_signal_handler_new ();
   handler->id = gtk_handler_id++;
   handler->signal_id = signal_id;
-  handler->object_signal = object_signal;
+  handler->object_signal = object_signal != FALSE;
   handler->func = func;
   handler->func_data = func_data;
   handler->destroy_func = destroy_func;
@@ -1565,36 +1796,38 @@ gtk_emission_new (void)
 {
   GtkEmission *emission;
   
-  if (!gtk_emission_free_list)
+  if (!gtk_free_emissions)
     {
-      GtkEmissionAllocator *emission_block;
+      GtkEmission *emission_block;
       guint i;
 
-      emission_block = g_new0 (GtkEmissionAllocator, EMISSION_BLOCK_SIZE);
+      emission_block = g_new0 (GtkEmission, EMISSION_BLOCK_SIZE);
       for (i = 1; i < EMISSION_BLOCK_SIZE; i++)
        {
-         (emission_block + i)->next = gtk_emission_free_list;
-         gtk_emission_free_list = (emission_block + i);
+         (emission_block + i)->next = gtk_free_emissions;
+         gtk_free_emissions = (emission_block + i);
        }
 
-      emission = &emission_block->emission;
+      emission = emission_block;
     }
   else
     {
-      emission = &gtk_emission_free_list->emission;
-      gtk_emission_free_list = gtk_emission_free_list->next;
+      emission = gtk_free_emissions;
+      gtk_free_emissions = emission->next;
     }
 
   emission->object = NULL;
   emission->signal_id = 0;
+  emission->in_hook = 0;
+  emission->next = NULL;
   
   return emission;
 }
 
 static void
-gtk_emission_add (GList            **emissions,
-                 GtkObject  *object,
-                 guint       signal_id)
+gtk_emission_add (GtkEmission **emissions,
+                 GtkObject    *object,
+                 guint         signal_id)
 {
   GtkEmission *emission;
   
@@ -1604,289 +1837,183 @@ gtk_emission_add (GList           **emissions,
   emission = gtk_emission_new ();
   emission->object = object;
   emission->signal_id = signal_id;
-  
-  *emissions = g_list_prepend (*emissions, emission);
+
+  emission->next = *emissions;
+  *emissions = emission;
 }
 
 static void
-gtk_emission_remove (GList     **emissions,
-                    GtkObject  *object,
-                    guint       signal_id)
+gtk_emission_remove (GtkEmission **emissions,
+                    GtkObject    *object,
+                    guint         signal_id)
 {
-  GList *tmp;
+  GtkEmission *emission, *last;
   
   g_return_if_fail (emissions != NULL);
-  
-  tmp = *emissions;
-  while (tmp)
+
+  last = NULL;
+  emission = *emissions;
+  while (emission)
     {
-      GtkEmissionAllocator *ea;
-      
-      ea = tmp->data;
-      
-      if ((ea->emission.object == object) &&
-         (ea->emission.signal_id == signal_id))
+      if (emission->object == object && emission->signal_id == signal_id)
        {
-         *emissions = g_list_remove_link (*emissions, tmp);
-         g_list_free (tmp);
+         if (last)
+           last->next = emission->next;
+         else
+           *emissions = emission->next;
 
-         ea->next = gtk_emission_free_list;
-         gtk_emission_free_list = ea;
+         emission->next = gtk_free_emissions;
+         gtk_free_emissions = emission;
          break;
        }
-      
-      tmp = tmp->next;
+
+      last = emission;
+      emission = last->next;
     }
 }
 
 static gint
-gtk_emission_check (GList     *emissions,
-                   GtkObject *object,
-                   guint      signal_id)
+gtk_emission_check (GtkEmission *emission,
+                   GtkObject   *object,
+                   guint        signal_id)
 {
-  GtkEmission *emission;
-  GList *tmp;
-  
-  tmp = emissions;
-  while (tmp)
+  while (emission)
     {
-      emission = tmp->data;
-      tmp = tmp->next;
-      
-      if ((emission->object == object) &&
-         (emission->signal_id == signal_id))
-       return TRUE;
+      if (emission->object == object && emission->signal_id == signal_id)
+       return 1 + emission->in_hook;
+      emission = emission->next;
     }
   return FALSE;
 }
 
 static gint
 gtk_handlers_run (GtkHandler    *handlers,
-                 GtkHandlerInfo *info,
+                 GtkSignal      *signal,
+                 GtkObject      *object,
+                 GtkArg         *params,
                  gint            after)
 {
-  while (handlers && handlers->signal_id == info->signal_id)
+  /* *signal is a local copy on the stack of gtk_signal_real_emit(),
+   * so we don't need to look it up every time we invoked a function.
+   */
+  while (handlers && handlers->signal_id == signal->signal_id)
     {
       GtkHandler *handlers_next;
       
       gtk_signal_handler_ref (handlers);
       
-      if (handlers->blocked == 0 && (handlers->after == after))
+      if (!handlers->blocked && handlers->after == after)
        {
          if (handlers->func)
            {
              if (handlers->no_marshal)
-               (* (GtkCallbackMarshal) handlers->func) (info->object,
+               (* (GtkCallbackMarshal) handlers->func) (object,
                                                         handlers->func_data,
-                                                        info->nparams,
-                                                        info->params);
+                                                        signal->nparams,
+                                                        params);
              else if (handlers->object_signal)
-               (* info->marshaller) ((GtkObject*) handlers->func_data, /* don't GTK_OBJECT() cast */
-                                     handlers->func,
-                                     handlers->func_data,
-                                     info->params);
+               /* don't cast with GTK_OBJECT () */
+               (* signal->marshaller) ((GtkObject*) handlers->func_data,
+                                       handlers->func,
+                                       object,
+                                       params);
              else
-               (* info->marshaller) (info->object,
-                                     handlers->func,
-                                     handlers->func_data,
-                                     info->params);
+               (* signal->marshaller) (object,
+                                       handlers->func,
+                                       handlers->func_data,
+                                       params);
            }
          else if (global_marshaller)
-           (* global_marshaller) (info->object,
+           (* global_marshaller) (object,
                                   handlers->func_data,
-                                  info->nparams,
-                                  info->params,
-                                  info->param_types,
-                                  info->return_val);
+                                  signal->nparams,
+                                  params,
+                                  signal->params,
+                                  signal->return_val);
          
-         if (gtk_emission_check (stop_emissions, info->object,
-                                 info->signal_id))
+         if (stop_emissions && gtk_emission_check (stop_emissions,
+                                                   object,
+                                                   signal->signal_id))
            {
-             gtk_emission_remove (&stop_emissions, info->object,
-                                  info->signal_id);
+             gtk_emission_remove (&stop_emissions, object, signal->signal_id);
              
-             if (info->run_type & GTK_RUN_NO_RECURSE)
-               gtk_emission_remove (&restart_emissions, info->object,
-                                    info->signal_id);
-             gtk_signal_handler_unref (handlers, info->object);
+             gtk_signal_handler_unref (handlers, object);
+
              return EMISSION_DONE;
            }
-         else if ((info->run_type & GTK_RUN_NO_RECURSE) &&
-                  gtk_emission_check (restart_emissions, info->object,
-                                      info->signal_id))
+         else if (restart_emissions &&
+                  signal->signal_flags & GTK_RUN_NO_RECURSE &&
+                  gtk_emission_check (restart_emissions, object, signal->signal_id))
            {
-             gtk_emission_remove (&restart_emissions, info->object,
-                                  info->signal_id);
-             gtk_signal_handler_unref (handlers, info->object);
+             gtk_emission_remove (&restart_emissions, object, signal->signal_id);
+
+             gtk_signal_handler_unref (handlers, object);
+
              return EMISSION_RESTART;
            }
        }
       
       handlers_next = handlers->next;
-      gtk_signal_handler_unref (handlers, info->object);
+      gtk_signal_handler_unref (handlers, object);
       handlers = handlers_next;
     }
   
   return EMISSION_CONTINUE;
 }
 
-static void
-gtk_params_get (GtkArg        *params,
-               guint           nparams,
-               GtkType        *param_types,
-               GtkType         return_val,
-               va_list         args)
+static gboolean
+gtk_signal_collect_params (GtkArg             *params,
+                          guint                n_params,
+                          GtkType             *param_types,
+                          GtkType              return_type,
+                          va_list              var_args)
 {
-  gint i;
-  
-  for (i = 0; i < nparams; i++)
+  register GtkArg *last_param;
+  register gboolean failed = FALSE;
+
+  for (last_param = params + n_params; params < last_param; params++)
     {
-      params[i].type = param_types[i];
-      params[i].name = NULL;
-      
-      switch (GTK_FUNDAMENTAL_TYPE (param_types[i]))
+      register gchar *error;
+
+      params->name = NULL;
+      params->type = *(param_types++);
+      GTK_ARG_COLLECT_VALUE (params,
+                            var_args,
+                            error);
+      if (error)
        {
-       case GTK_TYPE_INVALID:
-         break;
-       case GTK_TYPE_NONE:
-         break;
-       case GTK_TYPE_CHAR:
-         GTK_VALUE_CHAR(params[i]) = va_arg (args, gint);
-         break;
-       case GTK_TYPE_BOOL:
-         GTK_VALUE_BOOL(params[i]) = va_arg (args, gint);
-         break;
-       case GTK_TYPE_INT:
-         GTK_VALUE_INT(params[i]) = va_arg (args, gint);
-         break;
-       case GTK_TYPE_UINT:
-         GTK_VALUE_UINT(params[i]) = va_arg (args, guint);
-         break;
-       case GTK_TYPE_ENUM:
-         GTK_VALUE_ENUM(params[i]) = va_arg (args, gint);
-         break;
-       case GTK_TYPE_FLAGS:
-         GTK_VALUE_FLAGS(params[i]) = va_arg (args, gint);
-         break;
-       case GTK_TYPE_LONG:
-         GTK_VALUE_LONG(params[i]) = va_arg (args, glong);
-         break;
-       case GTK_TYPE_ULONG:
-         GTK_VALUE_ULONG(params[i]) = va_arg (args, gulong);
-         break;
-       case GTK_TYPE_FLOAT:
-         GTK_VALUE_FLOAT(params[i]) = va_arg (args, gfloat);
-         break;
-       case GTK_TYPE_DOUBLE:
-         GTK_VALUE_DOUBLE(params[i]) = va_arg (args, gdouble);
-         break;
-       case GTK_TYPE_STRING:
-         GTK_VALUE_STRING(params[i]) = va_arg (args, gchar*);
-         break;
-       case GTK_TYPE_POINTER:
-         GTK_VALUE_POINTER(params[i]) = va_arg (args, gpointer);
-         break;
-       case GTK_TYPE_BOXED:
-         GTK_VALUE_BOXED(params[i]) = va_arg (args, gpointer);
-         break;
-       case GTK_TYPE_SIGNAL:
-         GTK_VALUE_SIGNAL(params[i]).f = va_arg (args, GtkFunction);
-         GTK_VALUE_SIGNAL(params[i]).d = va_arg (args, gpointer);
-         break;
-       case GTK_TYPE_FOREIGN:
-         GTK_VALUE_FOREIGN(params[i]).data = va_arg (args, gpointer);
-         GTK_VALUE_FOREIGN(params[i]).notify = 
-           va_arg (args, GtkDestroyNotify);
-         break;
-       case GTK_TYPE_CALLBACK:
-         GTK_VALUE_CALLBACK(params[i]).marshal = 
-           va_arg (args, GtkCallbackMarshal);
-         GTK_VALUE_CALLBACK(params[i]).data = va_arg (args, gpointer);
-         GTK_VALUE_CALLBACK(params[i]).notify =
-           va_arg (args, GtkDestroyNotify);
-         break;
-       case GTK_TYPE_C_CALLBACK:
-         GTK_VALUE_C_CALLBACK(params[i]).func = va_arg (args, GtkFunction);
-         GTK_VALUE_C_CALLBACK(params[i]).func_data = va_arg (args, gpointer);
-         break;
-       case GTK_TYPE_ARGS:
-         GTK_VALUE_ARGS(params[i]).n_args = va_arg (args, gint);
-         GTK_VALUE_ARGS(params[i]).args = va_arg (args, GtkArg*);
-         break;
-       case GTK_TYPE_OBJECT:
-         GTK_VALUE_OBJECT(params[i]) = va_arg (args, GtkObject*);
-         if (GTK_VALUE_OBJECT(params[i]) != NULL &&
-             !GTK_CHECK_TYPE (GTK_VALUE_OBJECT(params[i]), params[i].type))
-           g_warning ("signal arg `%s' is not of type `%s'",
-                      gtk_type_name (GTK_OBJECT_TYPE (GTK_VALUE_OBJECT(params[i]))),
-                      gtk_type_name (params[i].type));
-         break;
-       default:
-         g_error ("unsupported type `%s' in signal arg",
-                  gtk_type_name (params[i].type));
-         break;
+         failed = TRUE;
+         g_warning ("gtk_signal_collect_params(): %s", error);
+         g_free (error);
        }
     }
-  
-  params[i].type = return_val;
-  params[i].name = NULL;
-  
-  switch (GTK_FUNDAMENTAL_TYPE (return_val))
+
+  params->type = return_type;
+  params->name = NULL;
+
+  return_type = GTK_FUNDAMENTAL_TYPE (return_type);
+  if (return_type != GTK_TYPE_NONE)
     {
-    case GTK_TYPE_INVALID:
-      break;
-    case GTK_TYPE_NONE:
-      break;
-    case GTK_TYPE_CHAR:
-      params[i].d.pointer_data = va_arg (args, gchar*);
-      break;
-    case GTK_TYPE_BOOL:
-      params[i].d.pointer_data = va_arg (args, gint*);
-      break;
-    case GTK_TYPE_INT:
-      params[i].d.pointer_data = va_arg (args, gint*);
-      break;
-    case GTK_TYPE_UINT:
-      params[i].d.pointer_data = va_arg (args, guint*);
-      break;
-    case GTK_TYPE_ENUM:
-      params[i].d.pointer_data = va_arg (args, gint*);
-      break;
-    case GTK_TYPE_FLAGS:
-      params[i].d.pointer_data = va_arg (args, gint*);
-      break;
-    case GTK_TYPE_LONG:
-      params[i].d.pointer_data = va_arg (args, glong*);
-      break;
-    case GTK_TYPE_ULONG:
-      params[i].d.pointer_data = va_arg (args, gulong*);
-      break;
-    case GTK_TYPE_FLOAT:
-      params[i].d.pointer_data = va_arg (args, gfloat*);
-      break;
-    case GTK_TYPE_DOUBLE:
-      params[i].d.pointer_data = va_arg (args, gdouble*);
-      break;
-    case GTK_TYPE_STRING:
-      params[i].d.pointer_data = va_arg (args, gchar**);
-      break;
-    case GTK_TYPE_POINTER:
-      params[i].d.pointer_data = va_arg (args, gpointer*);
-      break;
-    case GTK_TYPE_BOXED:
-      params[i].d.pointer_data = va_arg (args, gpointer*);
-      break;
-    case GTK_TYPE_OBJECT:
-      params[i].d.pointer_data = va_arg (args, GtkObject**);
-      break;
-    case GTK_TYPE_SIGNAL:
-    case GTK_TYPE_FOREIGN:
-    case GTK_TYPE_CALLBACK:
-    case GTK_TYPE_C_CALLBACK:
-    case GTK_TYPE_ARGS:
-    default:
-      g_error ("unsupported type `%s' in signal return",
-              gtk_type_name (return_val));
-      break;
+      if (return_type != 0) /* FIXME: check for IS_PARAM */
+       {
+         GTK_VALUE_POINTER (*params) = va_arg (var_args, gpointer);
+         
+         if (GTK_VALUE_POINTER (*params) == NULL)
+           {
+             failed = TRUE;
+             g_warning ("gtk_signal_collect_params(): invalid NULL pointer for return argument type `%s'",
+                        gtk_type_name (params->type));
+           }
+       }
+      else
+       {
+         failed = TRUE;
+         g_warning ("gtk_signal_collect_params(): unsupported return argument type `%s'",
+                    gtk_type_name (params->type));
+       }
     }
+  else
+    GTK_VALUE_POINTER (*params) = NULL;
+
+  return failed;
 }