aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy/empathy-dispatcher.c
diff options
context:
space:
mode:
authorJonny Lamb <jonny.lamb@collabora.co.uk>2009-01-31 01:16:02 +0800
committerXavier Claessens <xclaesse@src.gnome.org>2009-01-31 01:16:02 +0800
commit28258efc5b743fb8ef6eec1ac5466dc8038e3f6f (patch)
tree41f2fc4a49561d99bc844eb0854cfa12ea43484b /libempathy/empathy-dispatcher.c
parent287688f54b5580b08db118478bd16bca1a1c6347 (diff)
downloadgsoc2013-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
Diffstat (limited to 'libempathy/empathy-dispatcher.c')
-rw-r--r--libempathy/empathy-dispatcher.c37
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);