From 7b771c7fe5ec0f01ee960d2c8e8e05e1122b2da6 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 21 Nov 2008 16:24:36 +0000 Subject: Fix ref counting of tp_file, make it singleton per channel, and add a _keep_alive method that adds a tmp ref until the transfer finishes. svn path=/trunk/; revision=1904 --- libempathy/empathy-dispatcher.c | 5 ++- libempathy/empathy-tp-file.c | 73 ++++++++++++++++++++++++++++++++++++++--- libempathy/empathy-tp-file.h | 1 + 3 files changed, 71 insertions(+), 8 deletions(-) (limited to 'libempathy') diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index 4691ef6c1..21b6bcccb 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -957,11 +957,10 @@ file_channel_create_cb (TpConnection *connection, request->handle, NULL); - /* FIXME: tp_file is leaked, but we need to keep it alive until the data - * transfer is done. This is not the object that is going to be used - * for the ft manager. */ tp_file = empathy_tp_file_new (channel); empathy_tp_file_offer (tp_file, request->gfile, NULL); + empathy_tp_file_keep_alive (tp_file); + g_object_unref (tp_file); g_object_unref (request->gfile); g_slice_free (FileChannelRequest, request); diff --git a/libempathy/empathy-tp-file.c b/libempathy/empathy-tp-file.c index c885e0f20..420182f5f 100644 --- a/libempathy/empathy-tp-file.c +++ b/libempathy/empathy-tp-file.c @@ -297,6 +297,7 @@ struct _EmpathyTpFilePriv { time_t start_time; gchar *unix_socket_path; GCancellable *cancellable; + gboolean keep_alive; }; enum { @@ -325,6 +326,18 @@ empathy_tp_file_init (EmpathyTpFile *tp_file) tp_file->priv = priv; } +static void +tp_file_check_keep_alive (EmpathyTpFile *tp_file) +{ + if (tp_file->priv->keep_alive && + (tp_file->priv->state == EMP_FILE_TRANSFER_STATE_COMPLETED || + tp_file->priv->state == EMP_FILE_TRANSFER_STATE_CANCELLED)) + { + tp_file->priv->keep_alive = FALSE; + g_object_unref (tp_file); + } +} + static void tp_file_invalidated_cb (TpProxy *proxy, guint domain, @@ -343,14 +356,14 @@ tp_file_invalidated_cb (TpProxy *proxy, EMP_FILE_TRANSFER_STATE_CHANGE_REASON_LOCAL_ERROR; g_object_notify (G_OBJECT (tp_file), "state"); } + + tp_file_check_keep_alive (tp_file); } static void tp_file_finalize (GObject *object) { - EmpathyTpFile *tp_file; - - tp_file = EMPATHY_TP_FILE (object); + EmpathyTpFile *tp_file = EMPATHY_TP_FILE (object); if (tp_file->priv->channel) { @@ -475,6 +488,7 @@ tp_file_state_changed_cb (TpProxy *proxy, tp_file->priv->state_change_reason = reason; g_object_notify (G_OBJECT (tp_file), "state"); + tp_file_check_keep_alive (tp_file); } static void @@ -674,22 +688,50 @@ tp_file_set_property (GObject *object, }; } +static GHashTable *ft_table = NULL; + +static void +tp_file_weak_notify_cb (gpointer channel, + GObject *tp_file) +{ + g_hash_table_remove (ft_table, channel); +} + /** * empathy_tp_file_new: * @channel: a Telepathy channel * - * Creates a new #EmpathyTpFile wrapping @channel. + * Creates a new #EmpathyTpFile wrapping @channel, or return a new ref to an + * existing #EmpathyTpFile for that channel. * * Returns: a new #EmpathyTpFile */ EmpathyTpFile * empathy_tp_file_new (TpChannel *channel) { + EmpathyTpFile *tp_file; + g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL); - return g_object_new (EMPATHY_TYPE_TP_FILE, + if (ft_table != NULL) + { + tp_file = g_hash_table_lookup (ft_table, channel); + if (tp_file != NULL) { + return g_object_ref (tp_file); + } + } + else + ft_table = g_hash_table_new_full (empathy_proxy_hash, + empathy_proxy_equal, (GDestroyNotify) g_object_unref, NULL); + + tp_file = g_object_new (EMPATHY_TYPE_TP_FILE, "channel", channel, NULL); + + g_hash_table_insert (ft_table, g_object_ref (channel), tp_file); + g_object_weak_ref (G_OBJECT (tp_file), tp_file_weak_notify_cb, channel); + + return tp_file; } /** @@ -798,6 +840,27 @@ empathy_tp_file_offer (EmpathyTpFile *tp_file, GFile *gfile, GError **error) ¬hing, tp_file_method_cb, NULL, NULL, G_OBJECT (tp_file)); } +/** + * empathy_tp_file_keep_alive: + * @tp_file: an #EmpathyTpFile + * + * Keep @tp_file alive until the file transfer is COMPLETED or CANCELLED, by + * adding a temporary reference. + */ +void +empathy_tp_file_keep_alive (EmpathyTpFile *tp_file) +{ + g_return_if_fail (EMPATHY_IS_TP_FILE (tp_file)); + + if (tp_file->priv->keep_alive) + return; + + tp_file->priv->keep_alive = TRUE; + if (tp_file->priv->state != EMP_FILE_TRANSFER_STATE_COMPLETED && + tp_file->priv->state != EMP_FILE_TRANSFER_STATE_CANCELLED) + g_object_ref (tp_file); +} + EmpathyContact * empathy_tp_file_get_contact (EmpathyTpFile *tp_file) { diff --git a/libempathy/empathy-tp-file.h b/libempathy/empathy-tp-file.h index 7c656d2aa..e6c0dae7d 100644 --- a/libempathy/empathy-tp-file.h +++ b/libempathy/empathy-tp-file.h @@ -72,6 +72,7 @@ void empathy_tp_file_accept (EmpathyTpFile *tp_file, guint64 offset, void empathy_tp_file_cancel (EmpathyTpFile *tp_file); void empathy_tp_file_offer (EmpathyTpFile *tp_file, GFile *gfile, GError **error); +void empathy_tp_file_keep_alive (EmpathyTpFile *tp_file); guint64 empathy_tp_file_get_transferred_bytes (EmpathyTpFile *tp_file); EmpathyContact *empathy_tp_file_get_contact (EmpathyTpFile *tp_file); -- cgit v1.2.3