diff options
author | Jonny Lamb <jonny.lamb@collabora.co.uk> | 2009-01-31 01:16:02 +0800 |
---|---|---|
committer | Xavier Claessens <xclaesse@src.gnome.org> | 2009-01-31 01:16:02 +0800 |
commit | 28258efc5b743fb8ef6eec1ac5466dc8038e3f6f (patch) | |
tree | 41f2fc4a49561d99bc844eb0854cfa12ea43484b | |
parent | 287688f54b5580b08db118478bd16bca1a1c6347 (diff) | |
download | gsoc2013-empathy-28258efc5b743fb8ef6eec1ac5466dc8038e3f6f.tar gsoc2013-empathy-28258efc5b743fb8ef6eec1ac5466dc8038e3f6f.tar.gz gsoc2013-empathy-28258efc5b743fb8ef6eec1ac5466dc8038e3f6f.tar.bz2 gsoc2013-empathy-28258efc5b743fb8ef6eec1ac5466dc8038e3f6f.tar.lz gsoc2013-empathy-28258efc5b743fb8ef6eec1ac5466dc8038e3f6f.tar.xz gsoc2013-empathy-28258efc5b743fb8ef6eec1ac5466dc8038e3f6f.tar.zst gsoc2013-empathy-28258efc5b743fb8ef6eec1ac5466dc8038e3f6f.zip |
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>
svn path=/trunk/; revision=2306
-rw-r--r-- | libempathy/empathy-dispatcher.c | 37 |
1 files changed, 35 insertions, 2 deletions
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); |