empathy r1904 - in trunk: libempathy src



Author: xclaesse
Date: Fri Nov 21 16:24:36 2008
New Revision: 1904
URL: http://svn.gnome.org/viewvc/empathy?rev=1904&view=rev

Log:
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.

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

Modified: trunk/libempathy/empathy-dispatcher.c
==============================================================================
--- trunk/libempathy/empathy-dispatcher.c	(original)
+++ trunk/libempathy/empathy-dispatcher.c	Fri Nov 21 16:24:36 2008
@@ -957,11 +957,10 @@
 				 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);

Modified: trunk/libempathy/empathy-tp-file.c
==============================================================================
--- trunk/libempathy/empathy-tp-file.c	(original)
+++ trunk/libempathy/empathy-tp-file.c	Fri Nov 21 16:24:36 2008
@@ -297,6 +297,7 @@
   time_t start_time;
   gchar *unix_socket_path;
   GCancellable *cancellable;
+  gboolean keep_alive;
 };
 
 enum {
@@ -326,6 +327,18 @@
 }
 
 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 @@
           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->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 @@
     };
 }
 
+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 @@
       &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)
 {

Modified: trunk/libempathy/empathy-tp-file.h
==============================================================================
--- trunk/libempathy/empathy-tp-file.h	(original)
+++ trunk/libempathy/empathy-tp-file.h	Fri Nov 21 16:24:36 2008
@@ -72,6 +72,7 @@
 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);

Modified: trunk/src/empathy-ft-manager.c
==============================================================================
--- trunk/src/empathy-ft-manager.c	(original)
+++ trunk/src/empathy-ft-manager.c	Fri Nov 21 16:24:36 2008
@@ -186,6 +186,8 @@
       /* 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 @@
 }
 
 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 @@
       else
         empty = TRUE;
     }
-  g_object_unref (tp_file);
 
   /* Select the next row */
   if (!empty)
@@ -494,7 +495,7 @@
   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->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 @@
   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 @@
       empathy_tp_file_get_filename (tp_file));
 
   empathy_tp_file_cancel (tp_file);
+  g_object_unref (tp_file);
 }
 
 static void
@@ -1059,7 +1061,8 @@
   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);
 }

Modified: trunk/src/empathy.c
==============================================================================
--- trunk/src/empathy.c	(original)
+++ trunk/src/empathy.c	Fri Nov 21 16:24:36 2008
@@ -112,6 +112,8 @@
 		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);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]