empathy r2306 - trunk/libempathy



Author: xclaesse
Date: Fri Jan 30 17:16:02 2009
New Revision: 2306
URL: http://svn.gnome.org/viewvc/empathy?rev=2306&view=rev

Log:
Allow the dispatcher to be freed once a request is finished.

Previously, if there was no ref to the dispatcher, it would be freed
before the request could be satisfied. By keeping a ref in the
DispatcherRequestData, it is freed at the right time. This also
disconnects the signal handler from all channels and connections
when freeing the dispatcher as the "invalidated" signal callback can be
called after the dispatcher has been freed.

Signed-off-by: Jonny Lamb <jonny lamb collabora co uk>

Modified:
   trunk/libempathy/empathy-dispatcher.c

Modified: trunk/libempathy/empathy-dispatcher.c
==============================================================================
--- trunk/libempathy/empathy-dispatcher.c	(original)
+++ trunk/libempathy/empathy-dispatcher.c	Fri Jan 30 17:16:02 2009
@@ -57,6 +57,9 @@
   GHashTable *accounts;
   gpointer token;
   GSList *tubes;
+
+  /* channels which the dispatcher is listening "invalidated" */
+  GList *channels;
 } EmpathyDispatcherPriv;
 
 G_DEFINE_TYPE (EmpathyDispatcher, empathy_dispatcher, G_TYPE_OBJECT);
@@ -142,7 +145,7 @@
 {
   DispatcherRequestData *result = g_slice_new0 (DispatcherRequestData);
 
-  result->dispatcher = dispatcher;
+  result->dispatcher = g_object_ref (dispatcher);
   result->connection = connection;
 
   result->channel_type = g_strdup (channel_type);
@@ -164,6 +167,9 @@
 {
   g_free (r->channel_type);
 
+  if (r->dispatcher != NULL)
+    g_object_unref (r->dispatcher);
+
   if (r->contact != NULL)
     g_object_unref (r->contact);
 
@@ -306,6 +312,8 @@
   g_hash_table_remove (cd->dispatched_channels, object_path);
   g_hash_table_remove (cd->dispatching_channels, object_path);
 
+  priv->channels = g_list_remove (priv->channels, proxy);
+
   operation = g_hash_table_lookup (cd->outstanding_channels, object_path);
   if (operation != NULL)
     {
@@ -387,6 +395,7 @@
   g_object_unref (G_OBJECT (connection));
 
   g_object_ref (operation);
+  g_object_ref (dispatcher);
 
   dispatch_operation_flush_requests (dispatcher, operation, NULL, cd);
   status = empathy_dispatch_operation_get_status (operation);
@@ -409,6 +418,7 @@
       g_signal_emit (dispatcher, signals[DISPATCH], 0, operation);
     }
 
+  g_object_unref (dispatcher);
 }
 
 static void
@@ -549,6 +559,8 @@
     G_CALLBACK (dispatcher_channel_invalidated_cb),
     dispatcher);
 
+  priv->channels = g_list_append (priv->channels, channel);
+
   if (handle_type == TP_CONN_HANDLE_TYPE_CONTACT)
     {
       EmpathyContactFactory *factory = empathy_contact_factory_dup_singleton ();
@@ -755,7 +767,6 @@
   g_signal_connect (connection, "invalidated",
     G_CALLBACK (dispatcher_connection_invalidated_cb), dispatcher);
 
-
   if (tp_proxy_has_interface_by_id (TP_PROXY (connection),
       TP_IFACE_QUARK_CONNECTION_INTERFACE_REQUESTS))
     {
@@ -866,10 +877,28 @@
 dispatcher_finalize (GObject *object)
 {
   EmpathyDispatcherPriv *priv = GET_PRIV (object);
+  GList *l;
+  GHashTableIter iter;
+  gpointer connection;
 
   g_signal_handlers_disconnect_by_func (priv->account_manager,
       dispatcher_account_connection_cb, object);
 
+  for (l = priv->channels; l; l = l->next)
+    {
+      g_signal_handlers_disconnect_by_func (l->data,
+          dispatcher_channel_invalidated_cb, object);
+    }
+
+  g_list_free (priv->channels);
+
+  g_hash_table_iter_init (&iter, priv->connections);
+  while (g_hash_table_iter_next (&iter, &connection, NULL))
+    {
+      g_signal_handlers_disconnect_by_func (connection,
+          dispatcher_connection_invalidated_cb, object);
+    }
+
   g_object_unref (priv->account_manager);
   g_object_unref (priv->mc);
 
@@ -941,6 +970,8 @@
   priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal,
     g_object_unref, (GDestroyNotify) free_connection_data);
 
+  priv->channels = NULL;
+
   accounts = mc_accounts_list_by_enabled (TRUE);
 
   for (l = accounts; l; l = l->next)
@@ -1034,6 +1065,8 @@
             G_CALLBACK (dispatcher_channel_invalidated_cb),
             request_data->dispatcher);
 
+          priv->channels = g_list_append (priv->channels, channel);
+
           operation = empathy_dispatch_operation_new (request_data->connection,
              channel, request_data->contact, FALSE);
           g_object_unref (channel);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]