From 28258efc5b743fb8ef6eec1ac5466dc8038e3f6f Mon Sep 17 00:00:00 2001 From: Jonny Lamb Date: Fri, 30 Jan 2009 17:16:02 +0000 Subject: 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 svn path=/trunk/; revision=2306 --- libempathy/empathy-dispatcher.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) (limited to 'libempathy') diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index e8f7b8c7e..a8e0b1844 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -57,6 +57,9 @@ typedef struct 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 @@ new_dispatcher_request_data (EmpathyDispatcher *dispatcher, { 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 @@ free_dispatcher_request_data (DispatcherRequestData *r) { 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 @@ dispatcher_channel_invalidated_cb (TpProxy *proxy, 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 @@ dispatch_operation_ready_cb (EmpathyDispatchOperation *operation, 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 @@ dispatch_operation_ready_cb (EmpathyDispatchOperation *operation, g_signal_emit (dispatcher, signals[DISPATCH], 0, operation); } + g_object_unref (dispatcher); } static void @@ -549,6 +559,8 @@ dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, 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 @@ dispatcher_connection_ready_cb (TpConnection *connection, 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 @@ static void 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 @@ empathy_dispatcher_init (EmpathyDispatcher *dispatcher) 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 @@ dispatcher_connection_new_requested_channel (EmpathyDispatcher *dispatcher, 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); -- cgit v1.2.3