Index: gobject/gsignal.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/gsignal.c,v
retrieving revision 1.53
diff -u -p -r1.53 gsignal.c
--- gobject/gsignal.c	12 Sep 2003 20:33:31 -0000	1.53
+++ gobject/gsignal.c	23 Jun 2004 05:47:25 -0000
@@ -113,6 +113,7 @@ static	      void		handler_insert		(guin
 							 Handler	 *handler);
 static	      Handler*		handler_lookup		(gpointer	  instance,
 							 gulong		  handler_id,
+							 GClosure        *closure,
 							 guint		 *signal_id_p);
 static inline HandlerMatch*	handler_match_prepend	(HandlerMatch	 *list,
 							 Handler	 *handler,
@@ -150,6 +151,12 @@ static	      gboolean		signal_emit_unloc
 							 gpointer	  instance,
 							 GValue		 *return_value,
 							 const GValue	 *instance_and_params);
+static       void               add_invalid_closure_notify    (Handler         *handler,
+							       gpointer         instance);
+static       void               remove_invalid_closure_notify (Handler         *handler,
+							       gpointer         instance);
+static       void               invalid_closure_notify  (gpointer         data,
+							 GClosure        *closure);
 static const gchar *            type_debug_name         (GType            type);
 
 
@@ -220,6 +227,7 @@ struct _Handler
   guint         block_count : 12;
 #define HANDLER_MAX_BLOCK_COUNT (1 << 12)
   guint         after : 1;
+  guint         has_invalid_closure_notify : 1;
   GClosure     *closure;
 };
 struct _HandlerMatch
@@ -385,9 +393,10 @@ handler_list_lookup (guint    signal_id,
 }
 
 static Handler*
-handler_lookup (gpointer instance,
-		gulong   handler_id,
-		guint   *signal_id_p)
+handler_lookup (gpointer  instance,
+		gulong    handler_id,
+		GClosure *closure,
+		guint    *signal_id_p)
 {
   GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
   
@@ -401,7 +410,8 @@ handler_lookup (gpointer instance,
           Handler *handler;
           
           for (handler = hlist->handlers; handler; handler = handler->next)
-            if (handler->sequential_number == handler_id)
+            if (handler->sequential_number == handler_id ||
+		(closure && handler->closure == closure))
               {
                 if (signal_id_p)
                   *signal_id_p = hlist->signal_id;
@@ -587,6 +597,7 @@ handler_unref_R (guint    signal_id,
           hlist->handlers = handler->next;
         }
       SIGNAL_UNLOCK ();
+      remove_invalid_closure_notify (handler, instance);
       g_closure_unref (handler->closure);
       SIGNAL_LOCK ();
       g_generic_node_free (&g_handler_ts, handler);
@@ -1559,6 +1570,7 @@ g_signal_connect_closure_by_id (gpointer
 	  handler->detail = detail;
 	  handler->closure = g_closure_ref (closure);
 	  g_closure_sink (closure);
+	  add_invalid_closure_notify (handler, instance);
 	  handler_insert (signal_id, instance, handler);
 	  if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (closure))
 	    g_closure_set_marshal (closure, node->c_marshaller);
@@ -1605,6 +1617,7 @@ g_signal_connect_closure (gpointer     i
 	  handler->detail = detail;
 	  handler->closure = g_closure_ref (closure);
 	  g_closure_sink (closure);
+	  add_invalid_closure_notify (handler, instance);
 	  handler_insert (signal_id, instance, handler);
 	  if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (handler->closure))
 	    g_closure_set_marshal (handler->closure, node->c_marshaller);
@@ -1679,7 +1692,7 @@ g_signal_handler_block (gpointer instanc
   g_return_if_fail (handler_id > 0);
   
   SIGNAL_LOCK ();
-  handler = handler_lookup (instance, handler_id, NULL);
+  handler = handler_lookup (instance, handler_id, NULL, NULL);
   if (handler)
     {
 #ifndef G_DISABLE_CHECKS
@@ -1703,7 +1716,7 @@ g_signal_handler_unblock (gpointer insta
   g_return_if_fail (handler_id > 0);
   
   SIGNAL_LOCK ();
-  handler = handler_lookup (instance, handler_id, NULL);
+  handler = handler_lookup (instance, handler_id, NULL, NULL);
   if (handler)
     {
       if (handler->block_count)
@@ -1727,7 +1740,7 @@ g_signal_handler_disconnect (gpointer in
   g_return_if_fail (handler_id > 0);
   
   SIGNAL_LOCK ();
-  handler = handler_lookup (instance, handler_id, &signal_id);
+  handler = handler_lookup (instance, handler_id, NULL, &signal_id);
   if (handler)
     {
       handler->sequential_number = 0;
@@ -1750,7 +1763,7 @@ g_signal_handler_is_connected (gpointer 
   g_return_val_if_fail (handler_id > 0, FALSE);
 
   SIGNAL_LOCK ();
-  handler = handler_lookup (instance, handler_id, NULL);
+  handler = handler_lookup (instance, handler_id, NULL, NULL);
   connected = handler != NULL;
   SIGNAL_UNLOCK ();
 
@@ -1789,6 +1802,7 @@ g_signal_handlers_destroy (gpointer inst
               tmp->prev = tmp;
               if (tmp->sequential_number)
 		{
+		  remove_invalid_closure_notify (tmp, instance);
 		  tmp->sequential_number = 0;
 		  handler_unref_R (0, NULL, tmp);
 		}
@@ -2315,6 +2329,7 @@ signal_emit_unlocked_R (SignalNode   *no
   
   SIGNAL_LOCK ();
   signal_id = node->signal_id;
+
   if (node->flags & G_SIGNAL_NO_RECURSE)
     {
       Emission *node = emission_find (g_restart_emissions, signal_id, detail, instance);
@@ -2572,6 +2587,41 @@ signal_emit_unlocked_R (SignalNode   *no
     g_value_unset (&accu);
   
   return return_value_altered;
+}
+
+static void
+add_invalid_closure_notify (Handler  *handler,
+			    gpointer  instance)
+{
+  g_closure_add_invalidate_notifier (handler->closure, instance, invalid_closure_notify);
+  handler->has_invalid_closure_notify = 1;
+}
+
+static void
+remove_invalid_closure_notify (Handler  *handler,
+			       gpointer  instance)
+{
+  if (handler->has_invalid_closure_notify)
+    {
+      g_closure_remove_invalidate_notifier (handler->closure, instance, invalid_closure_notify);
+      handler->has_invalid_closure_notify = 0;
+    }
+}
+
+static void
+invalid_closure_notify (gpointer  instance,
+		        GClosure *closure)
+{
+  Handler *handler;
+  guint signal_id;
+
+  SIGNAL_LOCK ();
+
+  handler = handler_lookup (instance, 0, closure, &signal_id);
+  /* GClosure removes our notifier when we're done */
+  handler_unref_R (signal_id, instance, handler);
+
+  SIGNAL_UNLOCK ();
 }
 
 static const gchar*
