changeset 13965:df0dba522147

[gaim-migrate @ 16521] Merges soc-2006-chat-speed into trunk. (r16371:r16435) Joining large chat rooms, like IRC rooms, is much quicker. Additional improvment should be seen when using >=GTK+-2.6. committer: Tailor Script <tailor@pidgin.im>
author Aaron Sheldon <aaronsheldon>
date Wed, 19 Jul 2006 20:14:58 +0000
parents 0a0d2a1fd2bc
children 80cbf6c2d562
files src/conversation.c src/conversation.h src/gtkconv.c src/gtkconv.h
diffstat 4 files changed, 166 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/src/conversation.c	Wed Jul 19 07:12:59 2006 +0000
+++ b/src/conversation.c	Wed Jul 19 20:14:58 2006 +0000
@@ -38,7 +38,6 @@
 static GList *chats = NULL;
 static GaimConversationUiOps *default_ops = NULL;
 
-
 void
 gaim_conversations_set_ui_ops(GaimConversationUiOps *ops)
 {
@@ -1441,6 +1440,45 @@
 	g_list_free(flags2);
 }
 
+int
+gaim_conv_chat_cb_compare(GaimConvChatBuddy *a, GaimConvChatBuddy *b)
+{
+	GaimConvChatBuddyFlags f1 = 0, f2 = 0;
+	char *user1 = NULL, *user2 = NULL;
+	gint ret = 0;
+
+	
+	if (a) {
+		f1 = a->flags;
+		if (a->alias_key)
+			user1 = a->alias_key;
+		else if (a->name)
+			user1 = a->name;
+	}
+	
+	if (b) {
+		f2 = b->flags;
+		if (b->alias_key)
+			user2 = b->alias_key;
+		else if (b->name)
+			user2 = b->name;
+	}
+
+	if (user1 == NULL || user2 == NULL) {
+		if (!(user1 == NULL && user2 == NULL))
+			ret = (user1 == NULL) ? -1: 1;
+	} else if (f1 != f2) {
+		/* sort more important users first */
+		ret = (f1 > f2) ? -1 : 1;
+	} else if (a->buddy != b->buddy) { 
+		ret = a->buddy ? -1 : 1;
+	} else {
+		ret = strcasecmp(user1, user2);
+	}
+
+	return ret;
+}
+
 void
 gaim_conv_chat_add_users(GaimConvChat *chat, GList *users, GList *extra_msgs,
 						 GList *flags, gboolean new_arrivals)
@@ -1451,7 +1489,7 @@
 	GaimConnection *gc;
 	GaimPluginProtocolInfo *prpl_info;
 	GList *ul, *fl;
-	GList *aliases = NULL;
+	GList *cbuddies = NULL;
 
 	g_return_if_fail(chat  != NULL);
 	g_return_if_fail(users != NULL);
@@ -1470,9 +1508,12 @@
 		const char *user = (const char *)ul->data;
 		const char *alias = user;
 		gboolean quiet;
+		GaimConvChatBuddy *cbuddy;
 		GaimConvChatBuddyFlags flags = GPOINTER_TO_INT(fl->data);
 		const char *extra_msg = (extra_msgs ? extra_msgs->data : NULL);
 
+		cbuddy = gaim_conv_chat_cb_new(user, NULL, GPOINTER_TO_INT(fl->data));
+
 		if (!strcmp(chat->nick, gaim_normalize(conv->account, user))) {
 			const char *alias2 = gaim_account_get_alias(conv->account);
 			if (alias2 != NULL)
@@ -1493,11 +1534,15 @@
 						 "chat-buddy-joining", conv, user, flags)) |
 				gaim_conv_chat_is_user_ignored(chat, user);
 
-		cb = gaim_conv_chat_cb_new(user, flags);
+		cb = gaim_conv_chat_cb_new(user, NULL, flags);
+		/* This seems dumb. Why should we set users thousands of times? */
 		gaim_conv_chat_set_users(chat,
 				g_list_prepend(gaim_conv_chat_get_users(chat), cb));
-		/* We reverse this later to keep it in the same order as users. */
-		aliases = g_list_prepend(aliases, (char *)alias);
+
+		cbuddy->alias = strdup(alias); /* Should I be doing a strdup? */
+		cbuddy->alias_key = g_utf8_collate_key(alias, strlen(alias));
+		cbuddy->buddy = (gaim_find_buddy(conv->account, cbuddy->name) != NULL);
+		cbuddies = g_list_prepend(cbuddies, cbuddy);
 
 		if (!quiet && new_arrivals) {
 			char *escaped = g_markup_escape_text(alias, -1);
@@ -1525,14 +1570,11 @@
 			extra_msgs = extra_msgs->next;
 	}
 
-	/* This needs to be in the same order as users, but it's faster
-	 * to prepend, so we do that above. */
-	aliases = g_list_reverse(aliases);
-
+	cbuddies = g_list_sort(cbuddies, (GCompareFunc)gaim_conv_chat_cb_compare);
+	
 	if (ops != NULL && ops->chat_add_users != NULL)
-		ops->chat_add_users(conv, users, flags, aliases, new_arrivals);
-
-	g_list_free(aliases);
+		ops->chat_add_users(conv, cbuddies, new_arrivals);
+
 }
 
 void
@@ -1562,7 +1604,7 @@
 	g_return_if_fail(prpl_info != NULL);
 
 	flags = gaim_conv_chat_user_get_flags(chat, old_user);
-	cb = gaim_conv_chat_cb_new(new_user, flags);
+	cb = gaim_conv_chat_cb_new(new_user, NULL, flags);
 	gaim_conv_chat_set_users(chat,
 		g_list_prepend(gaim_conv_chat_get_users(chat), cb));
 
@@ -1873,9 +1915,8 @@
 
 	return chat->left;
 }
-
 GaimConvChatBuddy *
-gaim_conv_chat_cb_new(const char *name, GaimConvChatBuddyFlags flags)
+gaim_conv_chat_cb_new(const char *name, const char *alias, GaimConvChatBuddyFlags flags)
 {
 	GaimConvChatBuddy *cb;
 
@@ -1884,6 +1925,10 @@
 	cb = g_new0(GaimConvChatBuddy, 1);
 	cb->name = g_strdup(name);
 	cb->flags = flags;
+	if (alias)
+		cb->alias = g_strdup(alias);
+	else
+		cb->alias = NULL;
 
 	GAIM_DBUS_REGISTER_POINTER(cb, GaimConvChatBuddy);
 	return cb;
--- a/src/conversation.h	Wed Jul 19 07:12:59 2006 +0000
+++ b/src/conversation.h	Wed Jul 19 20:14:58 2006 +0000
@@ -158,8 +158,8 @@
 	                   const char *message, GaimMessageFlags flags,
 	                   time_t mtime);
 
-	void (*chat_add_users)(GaimConversation *conv, GList *users,
-						   GList *flags, GList *aliases, gboolean new_arrivals);
+	void (*chat_add_users)(GaimConversation *conv, GList *cbuddies, gboolean new_arrivals);	
+	
 	void (*chat_rename_user)(GaimConversation *conv, const char *old_name,
 	                         const char *new_name, const char *new_alias);
 	void (*chat_remove_users)(GaimConversation *conv, GList *users);
@@ -214,6 +214,9 @@
 struct _GaimConvChatBuddy
 {
 	char *name;                      /**< The name                      */
+	char *alias;					 /**< The alias 					*/
+	char *alias_key;				 /**< The alias key					*/
+	gboolean buddy;					 /**< ChatBuddy is on the blist		*/
 	GaimConvChatBuddyFlags flags;    /**< Flags (ops, voice etc.)       */
 };
 
@@ -1133,11 +1136,12 @@
  * Creates a new chat buddy
  *
  * @param name The name.
+ * @param alias The alias.
  * @param flags The flags.
  *
  * @return The new chat buddy
  */
-GaimConvChatBuddy *gaim_conv_chat_cb_new(const char *name,
+GaimConvChatBuddy *gaim_conv_chat_cb_new(const char *name, const char *alias,
 										GaimConvChatBuddyFlags flags);
 
 /**
--- a/src/gtkconv.c	Wed Jul 19 07:12:59 2006 +0000
+++ b/src/gtkconv.c	Wed Jul 19 20:14:58 2006 +0000
@@ -154,8 +154,7 @@
 static void got_typing_keypress(GaimGtkConversation *gtkconv, gboolean first);
 static void gray_stuff_out(GaimGtkConversation *gtkconv);
 static GList *generate_invite_user_names(GaimConnection *gc);
-static void add_chat_buddy_common(GaimConversation *conv, const char *name,
-								  GaimConvChatBuddyFlags flags, const char *alias, const char *old_name);
+static void add_chat_buddy_common(GaimConversation *conv, GaimConvChatBuddy *cb, const char *old_name);
 static gboolean tab_complete(GaimConversation *conv);
 static void gaim_gtkconv_updated(GaimConversation *conv, GaimConvUpdateType type);
 static void gtkconv_set_unseen(GaimGtkConversation *gtkconv, GaimUnseenState state);
@@ -1394,6 +1393,7 @@
 {
 	GaimConversation *conv = gtkconv->active_conv;
 	GaimGtkChatPane *gtkchat;
+	GaimConvChatBuddy *cbuddy;
 	GaimConvChat *chat;
 	GaimConvChatBuddyFlags flags;
 	GtkTreeIter iter;
@@ -1424,7 +1424,9 @@
 	else
 		gaim_conv_chat_ignore(chat, name);
 
-	add_chat_buddy_common(conv, name, flags, alias, NULL);
+	cbuddy = gaim_conv_chat_cb_new(name, alias, flags);
+	
+	add_chat_buddy_common(conv, cbuddy, NULL);
 	g_free(name);
 	g_free(alias);
 }
@@ -3288,7 +3290,7 @@
 }
 
 static void
-add_chat_buddy_common(GaimConversation *conv, const char *name, GaimConvChatBuddyFlags flags, const char *alias, const char *old_name)
+add_chat_buddy_common(GaimConversation *conv, GaimConvChatBuddy *cb, const char *old_name)
 {
 	GaimGtkConversation *gtkconv;
 	GaimGtkChatPane *gtkchat;
@@ -3300,6 +3302,12 @@
 	GtkTreeIter iter;
 	gboolean is_me = FALSE;
 	gboolean is_buddy;
+	gchar *alias_key, *name, *alias;
+	int flags;
+	
+	alias = cb->alias;
+	name  = cb->name;
+	flags = GPOINTER_TO_INT(cb->flags);
 
 	chat    = GAIM_CONV_CHAT(conv);
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
@@ -3318,32 +3326,74 @@
 
 	is_buddy = (gaim_find_buddy(conv->account, name) != NULL);
 
-	gtk_list_store_append(ls, &iter);
+	alias_key = g_utf8_collate_key(alias, strlen(alias));
 
 	if (is_me)
 	{
 		GdkColor send_color;
 		gdk_color_parse(SEND_COLOR, &send_color);
-
+		
+#if GTK_CHECK_VERSION(2,6,0) 
+		gtk_list_store_insert_with_values 
+                                            (ls,
+                                             &iter,
+/* 
+ * The GTK docs are mute about the effects of the "row" value for performance.
+ * X-Chat hardcodes their value to 0 (prepend) and -1 (append), so we will too.
+ * It *might* be faster to search the gtk_list_store and set row accurately,
+ * but no one in #gtk+ seems to know anything about it either.
+ * Inserting in the "wrong" location has no visible ill effects. - F.P.
+ */
+                                             -1, /* "row" */
+							CHAT_USERS_ICON_COLUMN,  pixbuf,
+							CHAT_USERS_ALIAS_COLUMN, alias,
+							CHAT_USERS_ALIAS_KEY_COLUMN, alias_key,
+							CHAT_USERS_NAME_COLUMN,  name,
+							CHAT_USERS_FLAGS_COLUMN, flags,
+							CHAT_USERS_COLOR_COLUMN, &send_color,
+							CHAT_USERS_BUDDY_COLUMN, is_buddy,
+                                             -1);
+ }
+ else {
+		gtk_list_store_insert_with_values
+                                            (ls,
+                                             &iter,
+                                              -1, /* "row" */
+							CHAT_USERS_ICON_COLUMN,  pixbuf,
+							CHAT_USERS_ALIAS_COLUMN, alias,
+							CHAT_USERS_ALIAS_KEY_COLUMN, alias_key,
+							CHAT_USERS_NAME_COLUMN,  name,
+							CHAT_USERS_FLAGS_COLUMN, flags,
+							CHAT_USERS_COLOR_COLUMN, get_nick_color(gtkconv, name),
+							CHAT_USERS_BUDDY_COLUMN, is_buddy,
+							-1);
+	 
+#else
+		gtk_list_store_append(ls, &iter);
 		gtk_list_store_set(ls, &iter,
 							CHAT_USERS_ICON_COLUMN,  pixbuf,
 							CHAT_USERS_ALIAS_COLUMN, alias,
+							CHAT_USERS_ALIAS_KEY_COLUMN, alias_key,
 							CHAT_USERS_NAME_COLUMN,  name,
 							CHAT_USERS_FLAGS_COLUMN, flags,
 							CHAT_USERS_COLOR_COLUMN, &send_color,
 							CHAT_USERS_BUDDY_COLUMN, is_buddy,
 							-1);
 	}
-	else
-	{
+
+	else {
+
+		gtk_list_store_append(ls, &iter);
 		gtk_list_store_set(ls, &iter,
 							CHAT_USERS_ICON_COLUMN,  pixbuf,
 							CHAT_USERS_ALIAS_COLUMN, alias,
+							CHAT_USERS_ALIAS_KEY_COLUMN, alias_key,
 							CHAT_USERS_NAME_COLUMN,  name,
 							CHAT_USERS_FLAGS_COLUMN, flags,
 							CHAT_USERS_COLOR_COLUMN, get_nick_color(gtkconv, name),
 							CHAT_USERS_BUDDY_COLUMN, is_buddy,
 							-1);
+#endif
 	}
 
 	if (pixbuf)
@@ -3601,12 +3651,12 @@
 	gint ret = 0;
 
 	gtk_tree_model_get(model, a,
-						CHAT_USERS_ALIAS_COLUMN, &user1,
+						CHAT_USERS_ALIAS_KEY_COLUMN, &user1,
 						CHAT_USERS_FLAGS_COLUMN, &f1,
 						CHAT_USERS_BUDDY_COLUMN, &buddy1,
 						-1);
 	gtk_tree_model_get(model, b,
-						CHAT_USERS_ALIAS_COLUMN, &user2,
+						CHAT_USERS_ALIAS_KEY_COLUMN, &user2,
 						CHAT_USERS_FLAGS_COLUMN, &f2,
 						CHAT_USERS_BUDDY_COLUMN, &buddy2,
 						-1);
@@ -3620,7 +3670,7 @@
 	} else if (buddy1 != buddy2) {
 		ret = buddy1 ? -1 : 1;
 	} else {
-		ret = gaim_utf8_strcasecmp(user1, user2);
+		ret = strcasecmp(user1, user2);
 	}
 
 	g_free(user1);
@@ -3657,17 +3707,21 @@
 
 		if (!strcmp(normalized_name, gaim_normalize(conv->account, name))) {
 			const char *alias = name;
+			char *alias_key = g_utf8_collate_key(alias, strlen(alias));
 			GaimBuddy *buddy2;
 
 			if (strcmp(chat->nick, gaim_normalize(conv->account, name))) {
 				/* This user is not me, so look into updating the alias. */
 
-				if ((buddy2 = gaim_find_buddy(conv->account, name)) != NULL)
+				if ((buddy2 = gaim_find_buddy(conv->account, name)) != NULL) {
 					alias = gaim_buddy_get_contact_alias(buddy2);
+					alias_key = g_utf8_collate_key(alias, strlen(alias));
+				}
 
 				gtk_list_store_set(GTK_LIST_STORE(model), &iter,
-								   CHAT_USERS_ALIAS_COLUMN, alias,
-								   -1);
+								CHAT_USERS_ALIAS_COLUMN, alias,
+								CHAT_USERS_ALIAS_KEY_COLUMN, alias_key,
+								-1);
 			}
 			g_free(name);
 			break;
@@ -3908,11 +3962,10 @@
 	gtk_widget_show(sw);
 
 	ls = gtk_list_store_new(CHAT_USERS_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING,
-							G_TYPE_STRING, G_TYPE_INT, GDK_TYPE_COLOR, G_TYPE_BOOLEAN);
-	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(ls), CHAT_USERS_ALIAS_COLUMN,
+							G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, 
+							GDK_TYPE_COLOR, G_TYPE_BOOLEAN);
+	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(ls), CHAT_USERS_ALIAS_KEY_COLUMN,
 									sort_chat_users, NULL, NULL);
-	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls), CHAT_USERS_ALIAS_COLUMN,
-										 GTK_SORT_ASCENDING);
 
 	list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ls));
 
@@ -4970,16 +5023,15 @@
 		account, name, message, conv, flags);
 	g_free(displaying);
 }
-
-static void
-gaim_gtkconv_chat_add_users(GaimConversation *conv, GList *users, GList *flags, GList *aliases, gboolean new_arrivals)
+static void
+gaim_gtkconv_chat_add_users(GaimConversation *conv, GList *cbuddies, gboolean new_arrivals)
 {
 	GaimConvChat *chat;
 	GaimGtkConversation *gtkconv;
 	GaimGtkChatPane *gtkchat;
+	GtkListStore *ls;
 	GList *l;
-	GList *ll;
-	GList *lll;
+
 	char tmp[BUF_LONG];
 	int num_users;
 
@@ -4996,15 +5048,22 @@
 
 	gtk_label_set_text(GTK_LABEL(gtkchat->count), tmp);
 
-	l = users;
-	ll = flags;
-	lll = aliases;
-	while (l != NULL && ll != NULL && lll != NULL) {
-		add_chat_buddy_common(conv, (const char *)l->data, GPOINTER_TO_INT(ll->data), (const char *)lll->data, NULL);
+	ls = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list)));
+	
+	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls),  GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
+										 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID); 
+
+	l = cbuddies;
+	while (l != NULL) {
+		add_chat_buddy_common(conv, (GaimConvChatBuddy *)l->data, NULL);
 		l = l->next;
-		ll = ll->next;
-		lll = lll->next;
-	}
+	}
+
+	/* Currently GTK+ maintains our sorted list after it's in the tree. 
+	 * This may change if it turns out we can manage it faster ourselves.
+ 	 */
+	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls),  CHAT_USERS_ALIAS_KEY_COLUMN,
+										 GTK_SORT_ASCENDING);
 }
 
 static void
@@ -5015,6 +5074,7 @@
 	GaimGtkConversation *gtkconv;
 	GaimGtkChatPane *gtkchat;
 	GaimConvChatBuddyFlags flags;
+	GaimConvChatBuddy *cbuddy;
 	GtkTreeIter iter;
 	GtkTreeModel *model;
 	int f = 1;
@@ -5049,7 +5109,9 @@
 
 	g_return_if_fail(new_alias != NULL);
 
-	add_chat_buddy_common(conv, new_name, flags, new_alias, old_name);
+	cbuddy = gaim_conv_chat_cb_new(new_name, new_alias, flags);
+	
+	add_chat_buddy_common(conv, cbuddy, old_name);
 }
 
 static void
@@ -5110,6 +5172,7 @@
 {
 	GaimConvChat *chat;
 	GaimConvChatBuddyFlags flags;
+	GaimConvChatBuddy *cbuddy;
 	GaimGtkConversation *gtkconv;
 	GaimGtkChatPane *gtkchat;
 	GtkTreeIter iter;
@@ -5153,7 +5216,9 @@
 
 	flags = gaim_conv_chat_user_get_flags(chat, user);
 
-	add_chat_buddy_common(conv, user, flags, alias, NULL);
+	cbuddy = gaim_conv_chat_cb_new(user, alias, flags);
+	
+	add_chat_buddy_common(conv, cbuddy, NULL);
 	g_free(alias);
 }
 
--- a/src/gtkconv.h	Wed Jul 19 07:12:59 2006 +0000
+++ b/src/gtkconv.h	Wed Jul 19 20:14:58 2006 +0000
@@ -44,6 +44,7 @@
 enum {
 	CHAT_USERS_ICON_COLUMN,
 	CHAT_USERS_ALIAS_COLUMN,
+	CHAT_USERS_ALIAS_KEY_COLUMN,
 	CHAT_USERS_NAME_COLUMN,
 	CHAT_USERS_FLAGS_COLUMN,
 	CHAT_USERS_COLOR_COLUMN,