aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libempathy/empathy-dispatcher.c5
-rw-r--r--libempathy/empathy-tp-file.c73
-rw-r--r--libempathy/empathy-tp-file.h1
-rw-r--r--src/empathy-ft-manager.c17
-rw-r--r--src/empathy.c2
5 files changed, 83 insertions, 15 deletions
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 {
@@ -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)
&nothing, 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);
diff --git a/src/empathy-ft-manager.c b/src/empathy-ft-manager.c
index b9839c4e3..2a9d1b229 100644
--- a/src/empathy-ft-manager.c
+++ b/src/empathy-ft-manager.c
@@ -186,6 +186,8 @@ ft_manager_update_buttons (EmpathyFTManager *ft_manager)
/* I can abort if the transfer is not already finished */
abort_enabled = (state != EMP_FILE_TRANSFER_STATE_CANCELLED &&
state != EMP_FILE_TRANSFER_STATE_COMPLETED);
+
+ g_object_unref (tp_file);
}
gtk_widget_set_sensitive (ft_manager->priv->open_button, open_enabled);
@@ -439,7 +441,7 @@ ft_manager_configure_event_cb (GtkWidget *widget,
}
static void
-ft_manager_remove_file_from_list (EmpathyFTManager *ft_manager,
+ft_manager_remove_file_from_model (EmpathyFTManager *ft_manager,
EmpathyTpFile *tp_file)
{
GtkTreeRowReference *row_ref;
@@ -471,7 +473,6 @@ ft_manager_remove_file_from_list (EmpathyFTManager *ft_manager,
else
empty = TRUE;
}
- g_object_unref (tp_file);
/* Select the next row */
if (!empty)
@@ -494,7 +495,7 @@ remove_finished_transfer_foreach (gpointer key,
if (state == EMP_FILE_TRANSFER_STATE_COMPLETED ||
state == EMP_FILE_TRANSFER_STATE_CANCELLED)
{
- ft_manager_remove_file_from_list (self, tp_file);
+ ft_manager_remove_file_from_model (self, tp_file);
return TRUE;
}
@@ -551,9 +552,8 @@ ft_manager_add_tp_file_to_list (EmpathyFTManager *ft_manager,
ft_manager->priv->model), path);
gtk_tree_path_free (path);
- g_object_ref (tp_file);
- g_hash_table_insert (ft_manager->priv->tp_file_to_row_ref, tp_file,
- row_ref);
+ g_hash_table_insert (ft_manager->priv->tp_file_to_row_ref,
+ g_object_ref (tp_file), row_ref);
ft_manager_update_ft_row (ft_manager, tp_file);
@@ -604,6 +604,7 @@ ft_manager_open (EmpathyFTManager *ft_manager)
uri = g_object_get_data (G_OBJECT (tp_file), "uri");
DEBUG ("Opening URI: %s", uri);
empathy_url_show (uri);
+ g_object_unref (tp_file);
}
static void
@@ -627,6 +628,7 @@ ft_manager_stop (EmpathyFTManager *ft_manager)
empathy_tp_file_get_filename (tp_file));
empathy_tp_file_cancel (tp_file);
+ g_object_unref (tp_file);
}
static void
@@ -1059,7 +1061,8 @@ empathy_ft_manager_init (EmpathyFTManager *ft_manager)
ft_manager->priv = priv;
priv->tp_file_to_row_ref = g_hash_table_new_full (g_direct_hash,
- g_direct_equal, NULL, (GDestroyNotify) gtk_tree_row_reference_free);
+ g_direct_equal, (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) gtk_tree_row_reference_free);
ft_manager_build_ui (ft_manager);
}
diff --git a/src/empathy.c b/src/empathy.c
index c05f005ac..fc9640556 100644
--- a/src/empathy.c
+++ b/src/empathy.c
@@ -112,6 +112,8 @@ dispatch_channel_cb (EmpathyDispatcher *dispatcher,
ft_manager = empathy_ft_manager_get_default ();
tp_file = empathy_tp_file_new (channel);
empathy_ft_manager_add_tp_file (ft_manager, tp_file);
+ empathy_tp_file_keep_alive (tp_file);
+ g_object_unref (tp_file);
}
g_free (channel_type);