summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Aurich <darkrain42@pidgin.im>2011-06-22 02:48:46 +0000
committerPaul Aurich <darkrain42@pidgin.im>2011-06-22 02:48:46 +0000
commitde25d0e68933a3742195cbbf9fe6b2e73718f5c5 (patch)
tree4c2b97fac741e9a392106172c47250e9b9714c16
parente76a998595c476b18a74dee67119834dec2fb334 (diff)
downloadpidgin-de25d0e68933a3742195cbbf9fe6b2e73718f5c5.tar.gz
Pluck the performance improvement code needed for large IRC channels.
-rw-r--r--ChangeLog2
-rw-r--r--ChangeLog.API11
-rw-r--r--libpurple/conversation.c64
-rw-r--r--libpurple/conversation.h10
-rw-r--r--libpurple/value.h3
-rw-r--r--pidgin/gtkconv.c111
6 files changed, 132 insertions, 69 deletions
diff --git a/ChangeLog b/ChangeLog
index 4cbfb50b46..4d7a84b20e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,8 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
version 2.9.0 (06/23/2011):
Pidgin:
+ * Significantly improved performance of larger IRC channels (regression
+ introduced in 2.8.0)
* Fix Conversation->Add on AIM and MSN.
* Entries in the chat user list are sorted properly again. This was
inadvertenly broken in 2.8.0.
diff --git a/ChangeLog.API b/ChangeLog.API
index a5545b4d7e..641fc7d3e3 100644
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -1,7 +1,16 @@
Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
version 2.9.0:
- * No changes
+ libpurple:
+ Added:
+ * Hash table to PurpleConvChat struct, used to make
+ purple_conv_chat_cb_find O(1).
+ * ui_data pointer to PurpleConvChatBuddy struct.
+ * deleting-chat-buddy signal (conversation signals)
+
+ Deprecated:
+ * purple_conv_chat_set_users
+ * PurpleConvChat in_room list
version 2.8.0 (06/07/2011):
libpurple:
diff --git a/libpurple/conversation.c b/libpurple/conversation.c
index 2ac306e645..b4c6ffd45c 100644
--- a/libpurple/conversation.c
+++ b/libpurple/conversation.c
@@ -70,6 +70,23 @@ static void _purple_conversations_hconv_free_key(struct _purple_hconv *hc)
g_free(hc);
}
+static guint _purple_conversation_user_hash(gconstpointer data)
+{
+ const gchar *name = data;
+ gchar *collated;
+ guint hash;
+
+ collated = g_utf8_collate_key(name, -1);
+ hash = g_str_hash(collated);
+ g_free(collated);
+ return hash;
+}
+
+static gboolean _purple_conversation_user_equal(gconstpointer a, gconstpointer b)
+{
+ return !g_utf8_collate(a, b);
+}
+
void
purple_conversations_set_ui_ops(PurpleConversationUiOps *ops)
{
@@ -393,6 +410,8 @@ purple_conversation_new(PurpleConversationType type, PurpleAccount *account,
conv->u.chat = g_new0(PurpleConvChat, 1);
conv->u.chat->conv = conv;
+ conv->u.chat->users = g_hash_table_new_full(_purple_conversation_user_hash,
+ _purple_conversation_user_equal, g_free, NULL);
PURPLE_DBUS_REGISTER_POINTER(conv->u.chat, PurpleConvChat);
chats = g_list_prepend(chats, conv);
@@ -547,6 +566,8 @@ purple_conversation_destroy(PurpleConversation *conv)
conv->u.im = NULL;
}
else if (conv->type == PURPLE_CONV_TYPE_CHAT) {
+ g_hash_table_destroy(conv->u.chat->users);
+ conv->u.chat->users = NULL;
g_list_foreach(conv->u.chat->in_room, (GFunc)purple_conv_chat_cb_destroy, NULL);
g_list_free(conv->u.chat->in_room);
@@ -1677,9 +1698,9 @@ purple_conv_chat_add_users(PurpleConvChat *chat, GList *users, GList *extra_msgs
cbuddy = purple_conv_chat_cb_new(user, alias, flag);
cbuddy->buddy = purple_find_buddy(conv->account, user) != NULL;
- /* This seems dumb. Why should we set users thousands of times? */
- purple_conv_chat_set_users(chat,
- g_list_prepend(chat->in_room, cbuddy));
+
+ chat->in_room = g_list_prepend(chat->in_room, cbuddy);
+ g_hash_table_replace(chat->users, g_strdup(cbuddy->name), cbuddy);
cbuddies = g_list_prepend(cbuddies, cbuddy);
@@ -1771,8 +1792,9 @@ purple_conv_chat_rename_user(PurpleConvChat *chat, const char *old_user,
flags = purple_conv_chat_user_get_flags(chat, old_user);
cb = purple_conv_chat_cb_new(new_user, new_alias, flags);
cb->buddy = purple_find_buddy(conv->account, new_user) != NULL;
- purple_conv_chat_set_users(chat,
- g_list_prepend(chat->in_room, cb));
+
+ chat->in_room = g_list_prepend(chat->in_room, cb);
+ g_hash_table_replace(chat->users, g_strdup(cb->name), cb);
if (ops != NULL && ops->chat_rename_user != NULL)
ops->chat_rename_user(conv, old_user, new_user, new_alias);
@@ -1780,8 +1802,8 @@ purple_conv_chat_rename_user(PurpleConvChat *chat, const char *old_user,
cb = purple_conv_chat_cb_find(chat, old_user);
if (cb) {
- purple_conv_chat_set_users(chat,
- g_list_remove(chat->in_room, cb));
+ chat->in_room = g_list_remove(chat->in_room, cb);
+ g_hash_table_remove(chat->users, cb->name);
purple_conv_chat_cb_destroy(cb);
}
@@ -1874,8 +1896,8 @@ purple_conv_chat_remove_users(PurpleConvChat *chat, GList *users, const char *re
cb = purple_conv_chat_cb_find(chat, user);
if (cb) {
- purple_conv_chat_set_users(chat,
- g_list_remove(chat->in_room, cb));
+ chat->in_room = g_list_remove(chat->in_room, cb);
+ g_hash_table_remove(chat->users, cb->name);
purple_conv_chat_cb_destroy(cb);
}
@@ -1955,8 +1977,11 @@ purple_conv_chat_clear_users(PurpleConvChat *chat)
purple_conv_chat_cb_destroy(cb);
}
+ g_hash_table_remove_all(chat->users);
+ chat->users = NULL;
+
g_list_free(users);
- purple_conv_chat_set_users(chat, NULL);
+ chat->in_room = NULL;
}
@@ -2146,19 +2171,10 @@ purple_conv_chat_cb_new(const char *name, const char *alias, PurpleConvChatBuddy
PurpleConvChatBuddy *
purple_conv_chat_cb_find(PurpleConvChat *chat, const char *name)
{
- GList *l;
- PurpleConvChatBuddy *cb = NULL;
-
g_return_val_if_fail(chat != NULL, NULL);
g_return_val_if_fail(name != NULL, NULL);
- for (l = purple_conv_chat_get_users(chat); l; l = l->next) {
- cb = l->data;
- if (!g_utf8_collate(cb->name, name))
- return cb;
- }
-
- return NULL;
+ return g_hash_table_lookup(chat->users, name);
}
void
@@ -2167,6 +2183,9 @@ purple_conv_chat_cb_destroy(PurpleConvChatBuddy *cb)
if (cb == NULL)
return;
+ purple_signal_emit(purple_conversations_get_handle(),
+ "deleting-chat-buddy", cb);
+
g_free(cb->alias);
g_free(cb->alias_key);
g_free(cb->name);
@@ -2573,6 +2592,11 @@ purple_conversations_init(void)
purple_value_new(PURPLE_TYPE_STRING),
purple_value_new(PURPLE_TYPE_STRING));
+ purple_signal_register(handle, "deleting-chat-buddy",
+ purple_marshal_VOID__POINTER, NULL, 1,
+ purple_value_new(PURPLE_TYPE_SUBTYPE,
+ PURPLE_SUBTYPE_CHATBUDDY));
+
purple_signal_register(handle, "chat-inviting-user",
purple_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
purple_value_new(PURPLE_TYPE_SUBTYPE,
diff --git a/libpurple/conversation.h b/libpurple/conversation.h
index b6efa88db7..e01dc19145 100644
--- a/libpurple/conversation.h
+++ b/libpurple/conversation.h
@@ -271,7 +271,9 @@ struct _PurpleConvChat
{
PurpleConversation *conv; /**< The parent conversation. */
- GList *in_room; /**< The users in the room. */
+ GList *in_room; /**< The users in the room.
+ * @deprecated Will be removed in 3.0.0
+ */
GList *ignored; /**< Ignored users. */
char *who; /**< The person who set the topic. */
char *topic; /**< The topic. */
@@ -279,6 +281,9 @@ struct _PurpleConvChat
char *nick; /**< Your nick in this chat. */
gboolean left; /**< We left the chat and kept the window open */
+ GHashTable *users; /**< Hash table of the users in the room.
+ * @since 2.9.0
+ */
};
/**
@@ -304,6 +309,7 @@ struct _PurpleConvChatBuddy
GHashTable *attributes; /**< A hash table of attributes about the user, such as
* real name, user@host, etc.
*/
+ gpointer ui_data; /** < The UI can put whatever it wants here. */
};
/**
@@ -1065,6 +1071,8 @@ PurpleConversation *purple_conv_chat_get_conversation(const PurpleConvChat *chat
* @param users The list of users.
*
* @return The list passed.
+ *
+ * @deprecated This function will be removed in 3.0.0. You shouldn't be using it anyway.
*/
GList *purple_conv_chat_set_users(PurpleConvChat *chat, GList *users);
diff --git a/libpurple/value.h b/libpurple/value.h
index 81ec6f3100..155c0146b4 100644
--- a/libpurple/value.h
+++ b/libpurple/value.h
@@ -79,7 +79,8 @@ typedef enum
PURPLE_SUBTYPE_XMLNODE,
PURPLE_SUBTYPE_USERINFO,
PURPLE_SUBTYPE_STORED_IMAGE,
- PURPLE_SUBTYPE_CERTIFICATEPOOL
+ PURPLE_SUBTYPE_CERTIFICATEPOOL,
+ PURPLE_SUBTYPE_CHATBUDDY
} PurpleSubType;
/**
diff --git a/pidgin/gtkconv.c b/pidgin/gtkconv.c
index e74ab730da..6402147a28 100644
--- a/pidgin/gtkconv.c
+++ b/pidgin/gtkconv.c
@@ -3978,6 +3978,16 @@ get_chat_buddy_status_icon(PurpleConvChat *chat, const char *name, PurpleConvCha
}
static void
+deleting_chat_buddy_cb(PurpleConvChatBuddy *cb)
+{
+ if (cb->ui_data) {
+ GtkTreeRowReference *ref = cb->ui_data;
+ gtk_tree_row_reference_free(ref);
+ cb->ui_data = NULL;
+ }
+}
+
+static void
add_chat_buddy_common(PurpleConversation *conv, PurpleConvChatBuddy *cb, const char *old_name)
{
PidginConversation *gtkconv;
@@ -3985,7 +3995,9 @@ add_chat_buddy_common(PurpleConversation *conv, PurpleConvChatBuddy *cb, const c
PurpleConvChat *chat;
PurpleConnection *gc;
PurplePluginProtocolInfo *prpl_info;
+ GtkTreeModel *tm;
GtkListStore *ls;
+ GtkTreePath *newpath;
const char *stock;
GtkTreeIter iter;
gboolean is_me = FALSE;
@@ -4006,7 +4018,8 @@ add_chat_buddy_common(PurpleConversation *conv, PurpleConvChatBuddy *cb, const c
if (!gc || !(prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)))
return;
- ls = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list)));
+ tm = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list));
+ ls = GTK_LIST_STORE(tm);
stock = get_chat_buddy_status_icon(chat, name, flags);
@@ -4051,6 +4064,15 @@ add_chat_buddy_common(PurpleConversation *conv, PurpleConvChatBuddy *cb, const c
CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
-1);
+ if (cb->ui_data) {
+ GtkTreeRowReference *ref = cb->ui_data;
+ gtk_tree_row_reference_free(ref);
+ }
+
+ newpath = gtk_tree_model_get_path(tm, &iter);
+ cb->ui_data = gtk_tree_row_reference_new(tm, newpath);
+ gtk_tree_path_free(newpath);
+
if (is_me && color)
gdk_color_free(color);
g_free(alias_key);
@@ -6108,6 +6130,28 @@ pidgin_conv_write_conv(PurpleConversation *conv, const char *name, const char *a
update_typing_message(gtkconv, NULL);
}
+static gboolean get_iter_from_chatbuddy(PurpleConvChatBuddy *cb, GtkTreeIter *iter)
+{
+ GtkTreeRowReference *ref = cb->ui_data;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+
+ if (!ref)
+ return FALSE;
+
+ if ((path = gtk_tree_row_reference_get_path(ref)) == NULL)
+ return FALSE;
+
+ model = gtk_tree_row_reference_get_model(ref);
+ if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(model), iter, path)) {
+ gtk_tree_path_free(path);
+ return FALSE;
+ }
+
+ gtk_tree_path_free(path);
+ return TRUE;
+}
+
static void
pidgin_conv_chat_add_users(PurpleConversation *conv, GList *cbuddies, gboolean new_arrivals)
{
@@ -6158,11 +6202,10 @@ pidgin_conv_chat_rename_user(PurpleConversation *conv, const char *old_name,
PurpleConvChat *chat;
PidginConversation *gtkconv;
PidginChatPane *gtkchat;
- PurpleConvChatBuddy *cbuddy;
+ PurpleConvChatBuddy *old_cbuddy, *new_cbuddy;
GtkTreeIter iter;
GtkTreeModel *model;
GtkTextTag *tag;
- int f = 1;
chat = PURPLE_CONV_CHAT(conv);
gtkconv = PIDGIN_CONVERSATION(conv);
@@ -6173,20 +6216,13 @@ pidgin_conv_chat_rename_user(PurpleConversation *conv, const char *old_name,
if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter))
return;
- while (f != 0) {
- char *val;
-
- gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &val, -1);
-
- if (!purple_utf8_strcasecmp(old_name, val)) {
- gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
- g_free(val);
- break;
- }
-
- f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
+ old_cbuddy = purple_conv_chat_cb_find(chat, old_name);
+ if (get_iter_from_chatbuddy(old_cbuddy, &iter)) {
+ GtkTreeRowReference *ref = old_cbuddy->ui_data;
- g_free(val);
+ gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
+ gtk_tree_row_reference_free(ref);
+ old_cbuddy->ui_data = NULL;
}
if ((tag = get_buddy_tag(conv, old_name, 0, FALSE)))
@@ -6194,14 +6230,14 @@ pidgin_conv_chat_rename_user(PurpleConversation *conv, const char *old_name,
if ((tag = get_buddy_tag(conv, old_name, PURPLE_MESSAGE_NICK, FALSE)))
g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL);
- if (!purple_conv_chat_find_user(chat, old_name))
+ if (!old_cbuddy)
return;
g_return_if_fail(new_alias != NULL);
- cbuddy = purple_conv_chat_cb_find(chat, new_name);
+ new_cbuddy = purple_conv_chat_cb_find(chat, new_name);
- add_chat_buddy_common(conv, cbuddy, old_name);
+ add_chat_buddy_common(conv, new_cbuddy, old_name);
}
static void
@@ -6228,6 +6264,7 @@ pidgin_conv_chat_remove_users(PurpleConversation *conv, GList *users)
model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list));
if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter))
+ /* XXX: Break? */
continue;
do {
@@ -6267,8 +6304,6 @@ pidgin_conv_chat_update_user(PurpleConversation *conv, const char *user)
PidginChatPane *gtkchat;
GtkTreeIter iter;
GtkTreeModel *model;
- int f = 1;
- char *alias = NULL;
chat = PURPLE_CONV_CHAT(conv);
gtkconv = PIDGIN_CONVERSATION(conv);
@@ -6279,35 +6314,16 @@ pidgin_conv_chat_update_user(PurpleConversation *conv, const char *user)
if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter))
return;
- while (f != 0) {
- char *val;
-
- gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &val, -1);
-
- if (!purple_utf8_strcasecmp(user, val)) {
- gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_ALIAS_COLUMN, &alias, -1);
- gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
- g_free(val);
- break;
- }
-
- f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
-
- g_free(val);
- }
-
- if (!purple_conv_chat_find_user(chat, user))
- {
- g_free(alias);
- return;
+ cbuddy = purple_conv_chat_cb_find(chat, user);
+ if (get_iter_from_chatbuddy(cbuddy, &iter)) {
+ GtkTreeRowReference *ref = cbuddy->ui_data;
+ gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
+ gtk_tree_row_reference_free(ref);
+ cbuddy->ui_data = NULL;
}
- g_return_if_fail(alias != NULL);
-
- cbuddy = purple_conv_chat_cb_find(chat, user);
if (cbuddy)
add_chat_buddy_common(conv, cbuddy, NULL);
- g_free(alias);
}
gboolean
@@ -8088,6 +8104,9 @@ pidgin_conversations_init(void)
purple_signal_connect(purple_conversations_get_handle(), "cleared-message-history",
handle, G_CALLBACK(clear_conversation_scrollback_cb), NULL);
+ purple_signal_connect(purple_conversations_get_handle(), "deleting-chat-buddy",
+ handle, G_CALLBACK(deleting_chat_buddy_cb), NULL);
+
purple_conversations_set_ui_ops(&conversation_ui_ops);
hidden_convwin = pidgin_conv_window_new();