]> git.0d.be Git - empathy.git/commitdiff
Fix ref counting of tp_file, make it singleton per channel, and add a _keep_alive...
authorXavier Claessens <xclaesse@src.gnome.org>
Fri, 21 Nov 2008 16:24:36 +0000 (16:24 +0000)
committerXavier Claessens <xclaesse@src.gnome.org>
Fri, 21 Nov 2008 16:24:36 +0000 (16:24 +0000)
svn path=/trunk/; revision=1904

libempathy/empathy-dispatcher.c
libempathy/empathy-tp-file.c
libempathy/empathy-tp-file.h
src/empathy-ft-manager.c
src/empathy.c

index 4691ef6c1241c02cf080366c1b80c3baa0c9d4b0..21b6bcccbe250fbf0dfcec180967d70a8713ed46 100644 (file)
@@ -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);
index c885e0f2018e044e615122aa75ae1eef71a4a038..420182f5fc9f589d4f5313587c931acbf3088473 100644 (file)
@@ -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)
       &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)
 {
index 7c656d2aa6a0e9915a9c46f3443a5f8365cc1aa9..e6c0dae7d3535b0283801e92a994a813757a925f 100644 (file)
@@ -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);
index b9839c4e35d303dba72a1ba63e6bdd14dfe20e96..2a9d1b229f42715e8a1245398ee4c9db9d3ad191 100644 (file)
@@ -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);
 }
index c05f005acc8dbec017a90d9df24e112b42dca6c9..fc9640556d54e8e0827aeaee36641cc6ba37589d 100644 (file)
@@ -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);