diff options
Diffstat (limited to 'libempathy/empathy-tp-file.c')
-rw-r--r-- | libempathy/empathy-tp-file.c | 73 |
1 files changed, 68 insertions, 5 deletions
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 { @@ -326,6 +327,18 @@ empathy_tp_file_init (EmpathyTpFile *tp_file) } 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, gint code, @@ -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) { |