gossip r2770 - in trunk: . libgossip src



Author: mr
Date: Fri Mar 14 17:26:18 2008
New Revision: 2770
URL: http://svn.gnome.org/viewvc/gossip?rev=2770&view=rev

Log:
Don't show offline people on the roster if they have TO subscription,
throttle updates to contacts and don't set groups twice leading to
speed loss


Modified:
   trunk/ChangeLog
   trunk/libgossip/gossip-contact.c
   trunk/libgossip/gossip-contact.h
   trunk/libgossip/gossip-jabber.c
   trunk/src/gossip-contact-list.c

Modified: trunk/libgossip/gossip-contact.c
==============================================================================
--- trunk/libgossip/gossip-contact.c	(original)
+++ trunk/libgossip/gossip-contact.c	Fri Mar 14 17:26:18 2008
@@ -61,8 +61,6 @@
 				   guint               param_id,
 				   const GValue       *value,
 				   GParamSpec         *pspec);
-static void contact_set_type      (GossipContact      *contact,
-				   GossipContactType   type);
 static void contact_set_presences (GossipContact      *contact,
 				   GList              *presences);
 
@@ -298,8 +296,8 @@
 
 	switch (param_id) {
 	case PROP_TYPE:
-		contact_set_type (GOSSIP_CONTACT (object),
-				  g_value_get_int (value));
+		gossip_contact_set_type (GOSSIP_CONTACT (object),
+					 g_value_get_int (value));
 		break;
 	case PROP_NAME:
 		gossip_contact_set_name (GOSSIP_CONTACT (object),
@@ -569,9 +567,9 @@
 	return priv->subscription;
 }
 
-static void
-contact_set_type (GossipContact      *contact,
-		  GossipContactType   type)
+void
+gossip_contact_set_type (GossipContact     *contact,
+			 GossipContactType  type)
 {
 	GossipContactPriv *priv;
 

Modified: trunk/libgossip/gossip-contact.h
==============================================================================
--- trunk/libgossip/gossip-contact.h	(original)
+++ trunk/libgossip/gossip-contact.h	Fri Mar 14 17:26:18 2008
@@ -91,6 +91,8 @@
 GList *            gossip_contact_get_presence_list         (GossipContact      *contact);
 GList *            gossip_contact_get_groups                (GossipContact      *contact);
 GossipSubscription gossip_contact_get_subscription          (GossipContact      *contact);
+void               gossip_contact_set_type                  (GossipContact      *contact,
+							     GossipContactType   type);
 void               gossip_contact_set_id                    (GossipContact      *contact,
 							     const gchar        *id);
 void               gossip_contact_set_name                  (GossipContact      *contact,

Modified: trunk/libgossip/gossip-jabber.c
==============================================================================
--- trunk/libgossip/gossip-jabber.c	(original)
+++ trunk/libgossip/gossip-jabber.c	Fri Mar 14 17:26:18 2008
@@ -2640,12 +2640,9 @@
 		const gchar       *jid_str;
 		const gchar       *subscription;
 		gboolean           added_item = FALSE;
-		gboolean           removed_item = FALSE;
-		LmMessageNode     *subnode;
 		LmMessageNode     *child;
 		GList             *groups;
 		const gchar       *name;
-		GList             *new_groups;
 
 		if (strcmp (node->name, "item") != 0) {
 			continue;
@@ -2663,30 +2660,9 @@
 
 		type = gossip_contact_get_type (contact);
 
-		/* Groups */
-		groups = NULL;
-		for (subnode = node->children; subnode; subnode = subnode->next) {
-			if (strcmp (subnode->name, "group") != 0) {
-				continue;
-			}
-
-			if (subnode->value) {
-				/* FIXME: unescape the markup here: #342927 */
-				groups = g_list_append (groups, subnode->value);
-			}
-		}
-
-		/* FIXME: why is this here if we set the groups below */
-		if (groups) {
-			gossip_contact_set_groups (contact, groups);
-		}
-
-		g_list_free (groups);
-
 		/* Subscription */
 		subscription = lm_message_node_get_attribute (node, "subscription");
 		if (contact && subscription) {
-			GossipContactType  contact_type;
 			GossipSubscription subscription_type;
 
 			if (strcmp (subscription, "remove") == 0) {
@@ -2717,24 +2693,10 @@
 			 * subscription requests for people already on
 			 * the roster with "to" or "from" conditions.
 			 */
-			if (subscription_type != GOSSIP_SUBSCRIPTION_NONE) {
-				g_object_get (contact, "type", &contact_type, NULL);
-				if (contact_type != GOSSIP_CONTACT_TYPE_CONTACTLIST) {
-					added_item = TRUE;
-				}
-				
-				contact_type = GOSSIP_CONTACT_TYPE_CONTACTLIST;
-				g_object_set (contact, "type", contact_type, NULL);
-			} else {
-				g_object_get (contact, "type", &contact_type, NULL);
-				if (contact_type == GOSSIP_CONTACT_TYPE_CONTACTLIST) {
-					removed_item = TRUE;
-				}
-
-				contact_type = GOSSIP_CONTACT_TYPE_TEMPORARY;
-				g_object_set (contact, "type", contact_type, NULL);
-			}
+			
+			added_item = TRUE;
 
+			gossip_contact_set_type (contact, GOSSIP_CONTACT_TYPE_CONTACTLIST);
 			gossip_contact_set_subscription (contact, subscription_type);
 		}
 
@@ -2743,27 +2705,23 @@
 			gossip_contact_set_name (contact, name);
 		}
 
-		new_groups = NULL;
+		groups = NULL;
 		for (child = node->children; child; child = child->next) {
+			/* FIXME: unescape the markup here: #342927 */
 			if (strcmp (child->name, "group") == 0 && child->value) {
-				new_groups = g_list_append (new_groups, child->value);
+				groups = g_list_prepend (groups, child->value);
 			}
 		}
 
-		if (new_groups) {
-			gossip_contact_set_groups (contact, new_groups);
+		if (groups) {
+			groups = g_list_reverse (groups);
+			gossip_contact_set_groups (contact, groups);
+			g_list_free (groups);
 		}
 
-		g_list_free (new_groups);
-
 		if (added_item) {
 			g_signal_emit_by_name (jabber, "contact-added", contact);
 		}
-
-		if (removed_item) {
-			g_signal_emit_by_name (jabber, "contact-removed", contact);
-			g_hash_table_remove (priv->contacts, gossip_contact_get_id (contact));
-		}
 	}
 }
 

Modified: trunk/src/gossip-contact-list.c
==============================================================================
--- trunk/src/gossip-contact-list.c	(original)
+++ trunk/src/gossip-contact-list.c	Fri Mar 14 17:26:18 2008
@@ -63,6 +63,9 @@
 /* Time after connecting which we wait before active users are enabled */
 #define ACTIVE_USER_WAIT_TO_ENABLE_TIME 5000
 
+/* Time to wait before updating a user (i.e. to throttle updates) */
+#define UPDATE_USER_DELAY_TIME 500
+
 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CONTACT_LIST, GossipContactListPriv))
 
 struct _GossipContactListPriv {
@@ -71,6 +74,7 @@
 	GHashTable            *groups;
 	GHashTable            *flash_table;
 	GHashTable            *active_contacts;
+	GHashTable            *update_contacts;
 	GHashTable            *set_group_state;
 
 	GtkUIManager          *ui;
@@ -184,7 +188,7 @@
 							      GossipContact          *contact);
 static void     contact_list_remove_contact                  (GossipContactList      *list,
 							      GossipContact          *contact,
-							      gboolean                remove_flash);
+							      gboolean                shallow_remove);
 static void     contact_list_create_model                    (GossipContactList      *list);
 static void     contact_list_setup_view                      (GossipContactList      *list);
 static void     contact_list_drag_data_received              (GtkWidget              *widget,
@@ -550,6 +554,12 @@
 						       (GDestroyNotify) 
 						       contact_list_contact_set_active_destroy_cb);
 
+	priv->update_contacts = g_hash_table_new_full (gossip_contact_hash,
+						       gossip_contact_equal,
+						       (GDestroyNotify) g_object_unref,
+						       (GDestroyNotify) 
+						       contact_list_contact_set_active_destroy_cb);
+
 	priv->set_group_state = g_hash_table_new_full (g_str_hash,
 						       g_str_equal,
 						       (GDestroyNotify) g_free,
@@ -649,6 +659,7 @@
 	g_hash_table_destroy (priv->flash_table);
 	/* FIXME: Shouldn't we free the groups hash table? */
 	g_hash_table_destroy (priv->active_contacts);
+	g_hash_table_destroy (priv->update_contacts);
 	g_hash_table_destroy (priv->set_group_state);
 
 	g_free (priv->filter_text);
@@ -912,26 +923,6 @@
 			       GossipContact     *contact,
 			       GossipContactList *list)
 {
-	gossip_debug (DEBUG_DOMAIN, 
-		      "Contact:'%s' added",
-		      gossip_contact_get_name (contact));
-
-	g_signal_connect (contact, "notify::groups",
-			  G_CALLBACK (contact_list_contact_groups_updated_cb),
-			  list);
-	g_signal_connect (contact, "notify::presences",
-			  G_CALLBACK (contact_list_contact_updated_cb),
-			  list);
-	g_signal_connect (contact, "notify::name",
-			  G_CALLBACK (contact_list_contact_updated_cb),
-			  list);
-	g_signal_connect (contact, "notify::avatar",
-			  G_CALLBACK (contact_list_contact_updated_cb),
-			  list);
-	g_signal_connect (contact, "notify::type",
-			  G_CALLBACK (contact_list_contact_updated_cb),
-			  list);
-
 	contact_list_add_contact (list, contact);
 }
 
@@ -962,39 +953,72 @@
 	 * would have to check the groups already set up for each
 	 * contact and then see what has been updated.
 	 */
-	contact_list_remove_contact (list, contact, FALSE);
+	contact_list_remove_contact (list, contact, TRUE);
 	contact_list_add_contact (list, contact);
 }
 
-static void
-contact_list_contact_updated_cb (GossipContact     *contact,
-				 GParamSpec        *param,
-				 GossipContactList *list)
+static gboolean
+contact_list_contact_updated_delay_cb (ActiveContactData *data)
 {
+	GossipContactList     *list;
+	GossipContactListPriv *priv;
+	GossipContact         *contact;
+
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	list = data->list;
+	contact = data->contact;
+
+	priv = GET_PRIV (list);
+
+	if (g_hash_table_lookup (priv->update_contacts, contact)) {
+		g_hash_table_remove (priv->update_contacts, contact);
+	}
+
 	gossip_debug (DEBUG_DOMAIN,
 		      "Contact:'%s' updated, checking roster is in sync...",
 		      gossip_contact_get_name (contact));
 
 	contact_list_contact_update (list, contact);
+
+	return FALSE;
 }
 
 static void
-contact_list_contact_removed_cb (GossipSession     *session,
-				 GossipContact     *contact,
+contact_list_contact_updated_cb (GossipContact     *contact,
+				 GParamSpec        *param,
 				 GossipContactList *list)
 {
-	gossip_debug (DEBUG_DOMAIN, 
-		      "Contact:'%s' removed",
-		      gossip_contact_get_name (contact));
+	/* Since we may get many updates at one time, we throttle
+	 * these to make sure we don't over update the roster for the
+	 * same contact.
+	 */ 
 
-	g_signal_handlers_disconnect_by_func (contact, 
-					      G_CALLBACK (contact_list_contact_groups_updated_cb),
-					      list);
-	g_signal_handlers_disconnect_by_func (contact,
-					      G_CALLBACK (contact_list_contact_updated_cb),
-					      list);
+	ActiveContactData     *data;
+	GossipContactListPriv *priv;
+
+	priv = GET_PRIV (list);
+
+	if (g_hash_table_lookup (priv->update_contacts, contact)) {
+		g_hash_table_remove (priv->update_contacts, contact);
+	}
 	
-	contact_list_remove_contact (list, contact, TRUE);
+	data = g_new0 (ActiveContactData, 1);
+	data->list = g_object_ref (list);
+	data->contact = g_object_ref (contact);
+	data->timeout_id = g_timeout_add (UPDATE_USER_DELAY_TIME,
+					  (GSourceFunc) contact_list_contact_updated_delay_cb,
+					  data);
+
+	g_hash_table_insert (priv->update_contacts, g_object_ref (contact), data);
+}
+
+static void
+contact_list_contact_removed_cb (GossipSession     *session,
+				 GossipContact     *contact,
+				 GossipContactList *list)
+{
+	contact_list_remove_contact (list, contact, FALSE);
 }
 
 static void
@@ -1435,9 +1459,47 @@
 	GtkTreeIter            iter, iter_group, iter_separator;
 	GtkTreeModel          *model;
 	GList                 *l, *groups;
+	GList                 *iters;
+
+	/* Note: The shallow_add flag is here so we know if we
+	 * should connect the signal handlers for GossipContact.
+	 * We also use this function with _remove_contact() when we
+	 * update contacts with complex group changes, since it is
+	 * easier.
+	 */
 
 	priv = GET_PRIV (list);
 
+	gossip_debug (DEBUG_DOMAIN, 
+		      "Contact:'%s' adding...",
+		      gossip_contact_get_name (contact));
+
+	iters = contact_list_find_contact (list, contact);
+	if (iters) {
+		gossip_debug (DEBUG_DOMAIN, " - Already exists, not adding");
+	
+		g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL);
+		g_list_free (iters);
+
+		return;
+	}
+	
+	/* Add signals */
+	gossip_debug (DEBUG_DOMAIN, " - Setting signal handlers");
+	
+	g_signal_connect (contact, "notify::groups",
+			  G_CALLBACK (contact_list_contact_groups_updated_cb),
+			  list);
+	g_signal_connect (contact, "notify::presences",
+			  G_CALLBACK (contact_list_contact_updated_cb),
+			  list);
+	g_signal_connect (contact, "notify::name",
+			  G_CALLBACK (contact_list_contact_updated_cb),
+			  list);
+	g_signal_connect (contact, "notify::avatar",
+			  G_CALLBACK (contact_list_contact_updated_cb),
+			  list);
+
 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (list));
 
 	/* If no groups just add it at the top level. */
@@ -1574,12 +1636,23 @@
 static void
 contact_list_remove_contact (GossipContactList *list,
 			     GossipContact     *contact,
-			     gboolean           remove_flash)
+			     gboolean           shallow_remove)
 {
 	GossipContactListPriv *priv;
 	GtkTreeModel          *model;
 	GList                 *iters, *l;
 
+	/* Note: The shallow_remove flag is here so we know if we
+	 * should disconnect the signal handlers for GossipContact.
+	 * We also use this function with _add_contact() when we
+	 * update contacts with complex group changes, since it is
+	 * easier.
+	 */
+
+	gossip_debug (DEBUG_DOMAIN, 
+		      "Contact:'%s' removing...",
+		      gossip_contact_get_name (contact));
+
 	priv = GET_PRIV (list);
 
 	iters = contact_list_find_contact (list, contact);
@@ -1606,6 +1679,8 @@
 				if (children <= 2) {
 					gtk_tree_store_remove (priv->store, &parent_iter);
 				} else {
+					gtk_tree_store_remove (priv->store, l->data);
+
 					/* To make sure the parent is hidden
 					 * correctly if we now have no more
 					 * online contacts, we emit the
@@ -1628,11 +1703,21 @@
 		g_list_free (iters);
 		
 		gossip_debug (DEBUG_DOMAIN, 
-			      "Now %d top level nodes remaining in the tree\n",
+			      " - Now %d top level nodes remaining in the tree\n",
 			      gtk_tree_model_iter_n_children (model, NULL));
 	}
 
-	if (remove_flash) {
+	gossip_debug (DEBUG_DOMAIN, " - Unsetting signal handlers");
+
+	g_signal_handlers_disconnect_by_func (contact, 
+					      contact_list_contact_groups_updated_cb,
+					      list);
+	g_signal_handlers_disconnect_by_func (contact,
+					      contact_list_contact_updated_cb,
+					      list);
+
+	if (!shallow_remove) {
+		gossip_debug (DEBUG_DOMAIN, " - Removing flash information");
 		g_hash_table_remove (priv->flash_table, contact);
 	}
 }
@@ -2657,7 +2742,8 @@
 	has_activity = g_hash_table_lookup (priv->active_contacts, contact) != NULL;
 
 	subscription = gossip_contact_get_subscription (contact);
-	has_no_subscription = subscription != GOSSIP_SUBSCRIPTION_BOTH;
+	has_no_subscription = (subscription == GOSSIP_SUBSCRIPTION_NONE ||
+			       subscription == GOSSIP_SUBSCRIPTION_FROM);
 
 	/* If we have a reason to remain visible in the roster, then
 	 * set visible TRUE (i.e we have events pending, we are
@@ -3271,7 +3357,7 @@
 	iters = contact_list_find_contact (list, contact);
 	if (!iters) {
 		gossip_debug (DEBUG_DOMAIN,
-			      "Contact:'%s' not found in treeview, adding...",
+			      "Contact:'%s' not found in treeview",
 			      gossip_contact_get_name (contact));
 		return;
 	}



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