# HG changeset patch # User Aaron Sheldon # Date 1153340098 0 # Node ID df0dba522147a6c543170f19fd29d1dbad79753d # Parent 0a0d2a1fd2bcc2bb4dfe5138d1ef79de330a71a8 [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 diff -r 0a0d2a1fd2bc -r df0dba522147 src/conversation.c --- 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; diff -r 0a0d2a1fd2bc -r df0dba522147 src/conversation.h --- 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); /** diff -r 0a0d2a1fd2bc -r df0dba522147 src/gtkconv.c --- 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); } diff -r 0a0d2a1fd2bc -r df0dba522147 src/gtkconv.h --- 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,