diff options
author | Paul Aurich <darkrain42@pidgin.im> | 2011-06-22 02:48:46 +0000 |
---|---|---|
committer | Paul Aurich <darkrain42@pidgin.im> | 2011-06-22 02:48:46 +0000 |
commit | de25d0e68933a3742195cbbf9fe6b2e73718f5c5 (patch) | |
tree | 4c2b97fac741e9a392106172c47250e9b9714c16 | |
parent | e76a998595c476b18a74dee67119834dec2fb334 (diff) | |
download | pidgin-de25d0e68933a3742195cbbf9fe6b2e73718f5c5.tar.gz |
Pluck the performance improvement code needed for large IRC channels.
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | ChangeLog.API | 11 | ||||
-rw-r--r-- | libpurple/conversation.c | 64 | ||||
-rw-r--r-- | libpurple/conversation.h | 10 | ||||
-rw-r--r-- | libpurple/value.h | 3 | ||||
-rw-r--r-- | pidgin/gtkconv.c | 111 |
6 files changed, 132 insertions, 69 deletions
@@ -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(); |