# HG changeset patch # User Paul Aurich # Date 1308630904 0 # Node ID 298685661f894686a9ea5402764ad7588379d377 # Parent f7c3aac5b22bf91ede8c07d9bfb8cb2da69f9427 Add constant-time lookup of row in the userlist by way of PurpleConvChatBuddy ui_data Thanks to elb for pointing out GtkTreeRowReference. Unfortunately, pidgin_conv_chat_remove_users cannot benefit from this because the PCCB struct is destroyed prior to the uiop being called. Joining #pidgin and #ubuntu is now extremely quick. diff -r f7c3aac5b22b -r 298685661f89 ChangeLog --- a/ChangeLog Tue Jun 21 03:34:50 2011 +0000 +++ b/ChangeLog Tue Jun 21 04:35:04 2011 +0000 @@ -1,6 +1,9 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul version 2.9.0 (MM/DD/YYYY): + Pidgin: + * Significantly improved performance of larger IRC channels (regression + introduced in 2.8.0) version 2.8.1 (MM/DD/YYYY): Pidgin: diff -r f7c3aac5b22b -r 298685661f89 ChangeLog.API --- a/ChangeLog.API Tue Jun 21 03:34:50 2011 +0000 +++ b/ChangeLog.API Tue Jun 21 04:35:04 2011 +0000 @@ -5,7 +5,8 @@ Added: * Hash table to PurpleConvChat struct, used to make purple_conv_chat_cb_find O(1). - * ui_data opaque pointer to PurpleConvChatBuddy struct. + * ui_data pointer to PurpleConvChatBuddy struct. + * deleting-chat-buddy signal (conversation signals) Deprecated: * purple_conv_chat_set_users diff -r f7c3aac5b22b -r 298685661f89 libpurple/conversation.c --- a/libpurple/conversation.c Tue Jun 21 03:34:50 2011 +0000 +++ b/libpurple/conversation.c Tue Jun 21 04:35:04 2011 +0000 @@ -2185,6 +2185,9 @@ 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); @@ -2591,6 +2594,11 @@ 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 -r f7c3aac5b22b -r 298685661f89 libpurple/value.h --- a/libpurple/value.h Tue Jun 21 03:34:50 2011 +0000 +++ b/libpurple/value.h Tue Jun 21 04:35:04 2011 +0000 @@ -79,7 +79,8 @@ PURPLE_SUBTYPE_XMLNODE, PURPLE_SUBTYPE_USERINFO, PURPLE_SUBTYPE_STORED_IMAGE, - PURPLE_SUBTYPE_CERTIFICATEPOOL + PURPLE_SUBTYPE_CERTIFICATEPOOL, + PURPLE_SUBTYPE_CHATBUDDY } PurpleSubType; /** diff -r f7c3aac5b22b -r 298685661f89 pidgin/gtkconv.c --- a/pidgin/gtkconv.c Tue Jun 21 03:34:50 2011 +0000 +++ b/pidgin/gtkconv.c Tue Jun 21 04:35:04 2011 +0000 @@ -3978,6 +3978,16 @@ } 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 @@ 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 @@ 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 @@ 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); @@ -6102,6 +6124,28 @@ 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) { @@ -6152,12 +6196,10 @@ PurpleConvChat *chat; PidginConversation *gtkconv; PidginChatPane *gtkchat; - PurpleConvChatBuddyFlags flags; - 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); @@ -6168,20 +6210,13 @@ 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, CHAT_USERS_FLAGS_COLUMN, &flags, -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); - - g_free(val); + old_cbuddy = purple_conv_chat_cb_find(chat, old_name); + if (get_iter_from_chatbuddy(old_cbuddy, &iter)) { + GtkTreeRowReference *ref = old_cbuddy->ui_data; + + 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))) @@ -6189,14 +6224,14 @@ 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); - - add_chat_buddy_common(conv, cbuddy, old_name); + new_cbuddy = purple_conv_chat_cb_find(chat, new_name); + + add_chat_buddy_common(conv, new_cbuddy, old_name); } static void @@ -6223,6 +6258,7 @@ 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 { @@ -6262,8 +6298,6 @@ PidginChatPane *gtkchat; GtkTreeIter iter; GtkTreeModel *model; - int f = 1; - char *alias = NULL; chat = PURPLE_CONV_CHAT(conv); gtkconv = PIDGIN_CONVERSATION(conv); @@ -6274,29 +6308,16 @@ 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); - } - - g_return_if_fail(alias != NULL); - 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; + } + if (cbuddy) add_chat_buddy_common(conv, cbuddy, NULL); - g_free(alias); } gboolean @@ -8077,6 +8098,9 @@ 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();