changeset 12797:eda1572c788b

[gaim-migrate @ 15144] SF Patch #1390008 from Sadrul "GaimGtkConv: Update tab icons, and some other small changes" This seems to make the Send To menu update better. I haven't seen this patch make anything worse yet, so I'm committing it. If you start seeing weird update errors, let Sadrul or me know. I thought I had a case of the Send To menu not updating even with this patch, but I haven't yet been able to duplicate it. Sadrul's description: '1. Fixes the tab-icons/send-to menu updates by listening for the appropriate signals. This patch removes the "updated" field from conversation-uiops. There is an existing "-updated" signal which can replace the uiops. 2. If having conversations with more than one accounts of a contact, and the buddy-icon of an inactive account is changed, then the new icon is showed (I think), even though it is not the buddy icon for the currently active conversation. This patch fixes that. 3. Emit "buddy-typing" and "-stopped" signal whenever the typing-state is changed. Currently, the typing-state of a conversation is sometimes changed without emitting the signal. This patch fixes that.' I rejected #4. '5. Emits the "chat-left" signal *after* setting "chat->left" to TRUE. 6. Show a buddy for an account only once in the SendTo menu (currently Gaim shows the same buddy more than once if the buddy exists in more than one groups). This is done by keeping a list of GaimPresence -- since that's the only thing the blist-nodes for the same buddy share.' committer: Tailor Script <tailor@pidgin.im>
author Richard Laager <rlaager@wiktel.com>
date Mon, 09 Jan 2006 21:29:53 +0000
parents e8db8f94a2db
children 09d4ea834370
files plugins/ChangeLog.API src/blist.c src/conversation.c src/conversation.h src/gtkblist.c src/gtkconv.c src/gtkdialogs.c src/protocols/yahoo/yahoo.c src/server.c src/status.c
diffstat 10 files changed, 323 insertions(+), 185 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/ChangeLog.API	Mon Jan 09 16:04:04 2006 +0000
+++ b/plugins/ChangeLog.API	Mon Jan 09 21:29:53 2006 +0000
@@ -132,6 +132,7 @@
 	* GaimConvImFlags and GaimConvChatFlags; use GaimMessageFlags instead
 	* cb and user_data from the ops in GaimNotifyUiOps: This is now handled
 	  by the notify API in the core.
+	* GaimConversationUiOps.updated: use the conversation-updated signal
 
 	Added:
 	* gaim_prefs_disconnect_by_handle()
@@ -226,19 +227,20 @@
 	* Signal propagation now stops after a handler returns a non-NULL value.
 	  This value is now returned.  Previously, all registered handlers were
 	  called and the value from the last handler was used.
+	* "buddy-typing" and "buddy-typing-stopped": replaced the GaimConversation*
+	  with GaimAccount*, const char *name.  Also, the signal is now emitted
+	  regardless of whether a conversation exists and regardless of whether
+	  the user is on the buddy list.
+	* "chat-invited" handlers can now return a value to control what happens
+	  to the invite (accept, reject, prompt the user).
+	* "chat-left": Emitted *after* setting chat->left to TRUE.
+	* "drawing-tooltip": the second argument is now a GString* instead of
+	  a char**
+	* "drawing-tooltip": added the "full" argument
 	* "received-im-msg" and "received-chat-msg" to match, both now pass a
 	  conversation pointer and flags
 	* "receiving-im-msg" and "receving-chat-msg" to match, both now pass a
 	  conversation pointer and a pointer to the flags.
-	* "drawing-tooltip": the second argument is now a GString* instead of
-	  a char**
-	* "drawing-tooltip": added the "full" argument
-	* "chat-invited" handlers can now return a value to control what happens
-	  to the invite (accept, reject, prompt the user).
-	* "buddy-typing" and "buddy-typing-stopped": replaced the GaimConversation*
-	  with GaimAccount*, const char *name.  Also, the signal is now emitted
-	  regardless of whether a conversation exists and regardless of whether
-	  the user is on the buddy list.
 
 	Signals - Added:  (See the Doxygen docs for details on all signals.)
 	* "account-disabled"
@@ -275,7 +277,7 @@
 	* "buddy-idle": replaced by buddy-idle-changed
 	* "buddy-unidle": replaced by buddy-idle-changed
 	* "buddy-icon-cached": replaced by buddy-icon-changed
-	* "conversation-drag-end": replaced by "conversation-dragging"
+	* "conversation-drag-end": replaced by conversation-dragging
 	* "conversation-switching"
 
 version 1.5.0 (8/11/2005):
--- a/src/blist.c	Mon Jan 09 16:04:04 2006 +0000
+++ b/src/blist.c	Mon Jan 09 21:29:53 2006 +0000
@@ -741,7 +741,6 @@
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 	GaimPresence *presence;
 	GaimStatus *status;
-	GaimConversation *conv;
 
 	g_return_if_fail(buddy != NULL);
 
@@ -785,9 +784,6 @@
 	gaim_contact_invalidate_priority_buddy(gaim_buddy_get_contact(buddy));
 	if (ops && ops->update)
 		ops->update(gaimbuddylist, (GaimBlistNode *)buddy);
-
-	if ((conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, buddy->name, buddy->account)))
-		gaim_conversation_update(conv, GAIM_CONV_UPDATE_AWAY);
 }
 
 void gaim_blist_update_buddy_icon(GaimBuddy *buddy)
--- a/src/conversation.c	Mon Jan 09 16:04:04 2006 +0000
+++ b/src/conversation.c	Mon Jan 09 21:29:53 2006 +0000
@@ -943,15 +943,8 @@
 void
 gaim_conversation_update(GaimConversation *conv, GaimConvUpdateType type)
 {
-	GaimConversationUiOps *ops;
-
 	g_return_if_fail(conv != NULL);
 
-	ops = gaim_conversation_get_ui_ops(conv);
-
-	if (ops != NULL && ops->updated != NULL)
-		ops->updated(conv, type);
-
 	gaim_signal_emit(gaim_conversations_get_handle(),
 					 "conversation-updated", conv, type);
 }
@@ -997,7 +990,21 @@
 {
 	g_return_if_fail(im != NULL);
 
-	im->typing_state = state;
+	if (im->typing_state != state)
+	{
+		im->typing_state = state;
+
+		if (state == GAIM_TYPING)
+		{
+			gaim_signal_emit(gaim_conversations_get_handle(),
+							 "buddy-typing", im->conv->account, im->conv->name);
+		}
+		else
+		{
+			gaim_signal_emit(gaim_conversations_get_handle(),
+							 "buddy-typing-stopped", im->conv->account, im->conv->name);
+		}
+	}
 }
 
 GaimTypingState
--- a/src/conversation.h	Mon Jan 09 16:04:04 2006 +0000
+++ b/src/conversation.h	Mon Jan 09 21:29:53 2006 +0000
@@ -169,10 +169,6 @@
 	void (*custom_smiley_write)(GaimConversation *conv, const char *smile,
 	                            const guchar *data, gsize size);
 	void (*custom_smiley_close)(GaimConversation *conv, const char *smile);
-
-	/* Events */
-	void (*updated)(GaimConversation *conv, GaimConvUpdateType type);
-
 };
 
 /**
--- a/src/gtkblist.c	Mon Jan 09 16:04:04 2006 +0000
+++ b/src/gtkblist.c	Mon Jan 09 21:29:53 2006 +0000
@@ -2550,7 +2550,7 @@
 	{ N_("/Buddies/_Add Buddy..."), "<CTL>B", gaim_gtk_blist_add_buddy_cb, 0, "<StockItem>", GTK_STOCK_ADD },
 	{ N_("/Buddies/Add C_hat..."), NULL, gaim_gtk_blist_add_chat_cb, 0, "<StockItem>", GTK_STOCK_ADD },
 	{ N_("/Buddies/Add _Group..."), NULL, gaim_blist_request_add_group, 0, "<StockItem>", GTK_STOCK_ADD },
-	{ "/Buddies/sep2", NULL, NULL, 0, "<Separator>", NULL },
+	{ "/Buddies/sep3", NULL, NULL, 0, "<Separator>" },
 	{ N_("/Buddies/_Quit"), "<CTL>Q", gaim_core_quit, 0, "<StockItem>", GTK_STOCK_QUIT }, 
 
 	/* Accounts menu */
@@ -4213,7 +4213,7 @@
 
 static void gaim_gtk_blist_update(GaimBuddyList *list, GaimBlistNode *node)
 {
-	if(!gtkblist)
+	if(!gtkblist || !node)
 		return;
 
 	switch(node->type) {
@@ -4383,7 +4383,6 @@
 		c = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, who, data->account);
 		if (c != NULL) {
 			gaim_buddy_icon_update(gaim_conv_im_get_icon(GAIM_CONV_IM(c)));
-			gaim_conversation_update(c, GAIM_CONV_UPDATE_ADD);
 		}
 	}
 
@@ -4534,8 +4533,6 @@
 	GaimChat *chat;
 	GaimGroup *group;
 	const char *group_name;
-	char *chat_name = NULL;
-	GaimConversation *conv = NULL;
 	const char *value;
 
 	components = g_hash_table_new_full(g_str_hash, g_str_equal,
@@ -4575,20 +4572,6 @@
 	if (chat != NULL)
 	{
 		gaim_blist_add_chat(chat, group, NULL);
-
-		if (GAIM_PLUGIN_PROTOCOL_INFO(data->account->gc->prpl)->get_chat_name != NULL)
-			chat_name = GAIM_PLUGIN_PROTOCOL_INFO(
-							data->account->gc->prpl)->get_chat_name(chat->components);
-
-		if (chat_name != NULL) {
-			conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
-													   chat_name,
-													   data->account);
-			g_free(chat_name);
-		}
-
-		if (conv != NULL)
-			gaim_conversation_update(conv, GAIM_CONV_UPDATE_ADD);
 	}
 
 	gtk_widget_destroy(data->window);
@@ -5014,21 +4997,12 @@
 static gboolean buddy_signonoff_timeout_cb(GaimBuddy *buddy)
 {
 	struct _gaim_gtk_blist_node *gtknode = ((GaimBlistNode*)buddy)->ui_data;
-	GaimConversation *conv;
 
 	gtknode->recent_signonoff = FALSE;
 	gtknode->recent_signonoff_timer = 0;
 
 	gaim_gtk_blist_update(NULL, (GaimBlistNode*)buddy);
 
-	if((conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, buddy->name, buddy->account))) {
-		if(GAIM_BUDDY_IS_ONLINE(buddy)) {
-			gaim_conversation_update(conv, GAIM_CONV_ACCOUNT_ONLINE);
-		} else {
-			gaim_conversation_update(conv, GAIM_CONV_ACCOUNT_OFFLINE);
-		}
-	}
-
 	return FALSE;
 }
 
--- a/src/gtkconv.c	Mon Jan 09 16:04:04 2006 +0000
+++ b/src/gtkconv.c	Mon Jan 09 21:29:53 2006 +0000
@@ -70,6 +70,19 @@
 
 #define AUTO_RESPONSE "&lt;AUTO-REPLY&gt; : "
 
+typedef  enum
+{
+	GAIM_GTKCONV_SET_TITLE 			= 1 << 0,
+	GAIM_GTKCONV_BUDDY_ICON			= 1 << 1,
+	GAIM_GTKCONV_MENU				= 1 << 2,
+	GAIM_GTKCONV_TAB_ICON			= 1 << 3,
+	GAIM_GTKCONV_TOPIC				= 1 << 4,
+	GAIM_GTKCONV_SMILEY_THEME		= 1 << 5,
+	GAIM_GTKCONV_COLORIZE_TITLE		= 1 << 6
+}GaimGtkConvFields;
+
+#define	GAIM_GTKCONV_ALL	((1 << 7) - 1)
+
 #define SEND_COLOR "#204a87"
 #define RECV_COLOR "#cc0000"
 #define HIGHLIGHT_COLOR "#AF7F00"
@@ -152,6 +165,7 @@
 static void gaim_gtkconv_custom_smiley_closed(GdkPixbufLoader *loader, gpointer user_data);
 static GdkColor* generate_nick_colors(guint numcolors, GdkColor background);
 static gboolean color_is_visible(GdkColor foreground, GdkColor background, int color_contrast, int brightness_contrast);
+static void gaim_gtkconv_update_fields(GaimConversation *conv, GaimGtkConvFields fields);
 
 static GdkColor *get_nick_color(GaimGtkConversation *gtkconv, const char *name) {
 	static GdkColor col;
@@ -2006,7 +2020,6 @@
 	gtk_window_set_title(GTK_WINDOW(gtkconv->win->window),
 	                     gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
 
-	gaim_conversation_update(conv, GAIM_CONV_UPDATE_ACCOUNT);
 	gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->entry),
 	                             gaim_account_get_protocol_name(conv->account));
 }
@@ -2131,6 +2144,9 @@
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
 	win = gtkconv->win;
+	if (conv != gtkconv->active_conv)
+		return;
+
 	name = gaim_conversation_get_name(conv);
 	account = gaim_conversation_get_account(conv);
 
@@ -3014,6 +3030,7 @@
 		}
 		else
 		{
+			GList *list = NULL, *iter;
 			for (l = buds; l != NULL; l = l->next)
 			{
 				GaimBlistNode *node;
@@ -3030,10 +3047,25 @@
 
 					account = gaim_buddy_get_account(buddy);
 					if (gaim_account_is_connected(account))
-						create_sendto_item(menu, sg, &group, buddy, account, gaim_buddy_get_name(buddy));
+					{
+						/* Use the GaimPresence to get unique buddies. */
+						GaimPresence *presence = gaim_buddy_get_presence(buddy);
+						if (!g_list_find(list, presence))
+							list = g_list_prepend(list, presence);
+					}
 				}
 			}
 
+			/* Loop over the list backwards so we get the items in the right order,
+			 * since we did a g_list_prepend() earlier. */
+			for (iter = g_list_last(list); iter != NULL; iter = iter->prev)
+			{
+				GaimPresence *pre = iter->data;
+				GaimBuddy *buddy = gaim_presence_get_buddies(pre)->data;
+				create_sendto_item(menu, sg, &group, buddy,
+							gaim_buddy_get_account(buddy), gaim_buddy_get_name(buddy));
+			}
+			g_list_free(list);
 			g_slist_free(buds);
 		}
 	}
@@ -4140,7 +4172,7 @@
 		if (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_IM)
 			continue;
 
-		gaim_conversation_update(conv, GAIM_CONV_ACCOUNT_ONLINE);
+		gaim_gtkconv_update_fields(conv, GAIM_GTKCONV_MENU);
 	}
 }
 
@@ -5417,42 +5449,61 @@
 	}
 }
 
-
 static void
-gaim_gtkconv_updated(GaimConversation *conv, GaimConvUpdateType type)
-{
+gaim_gtkconv_update_fields(GaimConversation *conv, GaimGtkConvFields fields)
+{
+	GaimGtkConversation *gtkconv;
 	GaimGtkWindow *win;
-	GaimGtkConversation *gtkconv;
-	GaimGtkChatPane *gtkchat;
-	GaimConvChat *chat;
-
-	g_return_if_fail(conv != NULL);
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
-	win     = gtkconv->win;
-	conv = gtkconv->active_conv; /* Gross hack */
-	/* Maybe we should just ignore it if conv != gtkconv->active_conv,
-	 * instead of the gross hack?
-	*/
-
-	if (type == GAIM_CONV_UPDATE_ACCOUNT)
+	if (!gtkconv)
+		return;
+	win = gaim_gtkconv_get_window(gtkconv);
+	if (!win)
+		return;
+	
+	if (fields & GAIM_GTKCONV_SET_TITLE)
 	{
 		gaim_conversation_autoset_title(conv);
-
+	}
+
+	if (fields & GAIM_GTKCONV_BUDDY_ICON)
+	{
 		if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
 			gaim_gtkconv_update_buddy_icon(conv);
-
-		gaim_gtkconv_update_buttons_by_protocol(conv);
-
-		update_send_to_selection(win);
-
-		gaim_gtkthemes_smiley_themeize(gtkconv->imhtml);
-
+	}
+
+	if (fields & GAIM_GTKCONV_MENU)
+	{
+		gray_stuff_out(GAIM_GTK_CONVERSATION(conv));
+		generate_send_to_items(win);
+	}
+
+	if (fields & GAIM_GTKCONV_TAB_ICON)
+	{
 		update_tab_icon(conv);
-	}
-	else if (type == GAIM_CONV_UPDATE_TYPING ||
-	         type == GAIM_CONV_UPDATE_UNSEEN ||
-	         type == GAIM_CONV_UPDATE_TITLE)
+		generate_send_to_items(win);		/* To update the icons in SendTo menu */
+	}
+
+	if ((fields & GAIM_GTKCONV_TOPIC) &&
+				gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)
+	{
+		const char *topic;
+		GaimConvChat *chat = GAIM_CONV_CHAT(conv);
+		GaimGtkChatPane *gtkchat = gtkconv->u.chat;
+
+		topic = gaim_conv_chat_get_topic(chat);
+
+		gtk_entry_set_text(GTK_ENTRY(gtkchat->topic_text), topic ? topic : "");
+		gtk_tooltips_set_tip(gtkconv->tooltips, gtkchat->topic_text,
+		                     topic ? topic : "", NULL);
+	}
+
+	if (fields & GAIM_GTKCONV_SMILEY_THEME)
+		gaim_gtkthemes_smiley_themeize(GAIM_GTK_CONVERSATION(conv)->imhtml);
+
+	if ((fields & GAIM_GTKCONV_COLORIZE_TITLE) || 
+			(fields & GAIM_GTKCONV_SET_TITLE))
 	{
 		char *title;
 		GaimConvIm *im = NULL;
@@ -5516,52 +5567,60 @@
 		if (gaim_gtk_conv_window_is_active_conversation(conv))
 			update_typing_icon(gtkconv);
 
-		if (type == GAIM_CONV_UPDATE_TITLE) {
-			gtk_label_set_text(GTK_LABEL(gtkconv->menu_label), title);
-			if (gaim_gtk_conv_window_is_active_conversation(conv))
-				gtk_window_set_title(GTK_WINDOW(win->window), title);
-		}
+		gtk_label_set_text(GTK_LABEL(gtkconv->menu_label), title);
+		if (gaim_gtk_conv_window_is_active_conversation(conv))
+			gtk_window_set_title(GTK_WINDOW(win->window), title);
 
 		g_free(title);
 	}
+}
+
+static void
+gaim_gtkconv_updated(GaimConversation *conv, GaimConvUpdateType type)
+{
+	GaimGtkConvFields flags = 0;
+
+	g_return_if_fail(conv != NULL);
+
+	if (type == GAIM_CONV_UPDATE_ACCOUNT)
+	{
+		flags = GAIM_GTKCONV_ALL;
+	}
+	else if (type == GAIM_CONV_UPDATE_TYPING ||
+	         type == GAIM_CONV_UPDATE_UNSEEN ||
+	         type == GAIM_CONV_UPDATE_TITLE)
+	{
+		flags = GAIM_GTKCONV_COLORIZE_TITLE;
+	}
 	else if (type == GAIM_CONV_UPDATE_TOPIC)
 	{
-		const char *topic;
-		chat = GAIM_CONV_CHAT(conv);
-		gtkchat = gtkconv->u.chat;
-
-		topic = gaim_conv_chat_get_topic(chat);
-
-		gtk_entry_set_text(GTK_ENTRY(gtkchat->topic_text), topic ? topic : "");
-		gtk_tooltips_set_tip(gtkconv->tooltips, gtkchat->topic_text,
-		                     topic ? topic : "", NULL);
+		flags = GAIM_GTKCONV_TOPIC;
 	}
 	else if (type == GAIM_CONV_ACCOUNT_ONLINE ||
-			 type == GAIM_CONV_ACCOUNT_OFFLINE)
+	         type == GAIM_CONV_ACCOUNT_OFFLINE)
 	{
-		gray_stuff_out(GAIM_GTK_CONVERSATION(gaim_gtk_conv_window_get_active_conversation(win)));
-		generate_send_to_items(win);
-		update_tab_icon(conv);
-		gaim_conversation_autoset_title(conv);
+		flags = GAIM_GTKCONV_MENU | GAIM_GTKCONV_TAB_ICON | GAIM_GTKCONV_SET_TITLE;
 	}
 	else if (type == GAIM_CONV_UPDATE_AWAY)
 	{
-		update_tab_icon(conv);
-	}
-	else if (type == GAIM_CONV_UPDATE_ADD || type == GAIM_CONV_UPDATE_REMOVE ||
+		flags = GAIM_GTKCONV_TAB_ICON;
+	}
+	else if (type == GAIM_CONV_UPDATE_ADD ||
+	         type == GAIM_CONV_UPDATE_REMOVE ||
 	         type == GAIM_CONV_UPDATE_CHATLEFT)
 	{
-		gaim_conversation_autoset_title(conv);
-		gray_stuff_out(GAIM_GTK_CONVERSATION(conv));
+		flags = GAIM_GTKCONV_SET_TITLE | GAIM_GTKCONV_MENU;
 	}
 	else if (type == GAIM_CONV_UPDATE_ICON)
 	{
-		gaim_gtkconv_update_buddy_icon(conv);
+		flags = GAIM_GTKCONV_BUDDY_ICON;
 	}
 	else if (type == GAIM_CONV_UPDATE_FEATURES)
 	{
-		gray_stuff_out(GAIM_GTK_CONVERSATION(conv));
-	}
+		flags = GAIM_GTKCONV_MENU;
+	}
+
+	gaim_gtkconv_update_fields(conv, flags);
 }
 
 static GaimConversationUiOps conversation_ui_ops =
@@ -5580,8 +5639,7 @@
 	gaim_gtkconv_has_focus,          /* has_focus            */
 	gaim_gtkconv_custom_smiley_add,  /* custom_smiley_add    */
 	gaim_gtkconv_custom_smiley_write, /* custom_smiley_write */
-	gaim_gtkconv_custom_smiley_close, /* custom_smiley_close */
-	gaim_gtkconv_updated             /* updated              */
+	gaim_gtkconv_custom_smiley_close  /* custom_smiley_close */
 };
 
 GaimConversationUiOps *
@@ -5626,6 +5684,8 @@
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
 	win = gtkconv->win;
+	if (conv != gtkconv->active_conv)
+		return;
 
 	if (!gtkconv->u.im->show_icon)
 		return;
@@ -6082,6 +6142,24 @@
 	gaim_gtkconv_placement_set_current_func(func);
 }
 
+static GaimGtkConversation *
+get_gtkconv_with_contact(GaimContact *contact)
+{
+	GaimBlistNode *node;
+
+	node = ((GaimBlistNode*)contact)->child;
+
+	for (; node; node = node->next)
+	{
+		GaimBuddy *buddy = (GaimBuddy*)node;
+		GaimConversation *conv;
+		conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, buddy->name, buddy->account);
+		if (conv)
+			return GAIM_GTK_CONVERSATION(conv);
+	}
+	return NULL;
+}
+
 static void
 account_signed_off_cb(GaimConnection *gc, gpointer event)
 {
@@ -6094,9 +6172,119 @@
 	{
 		GaimConversation *conv = iter->data;
 
-		if (gaim_conversation_get_account(conv) == account)
-			gaim_conversation_update(conv, GPOINTER_TO_INT(event));
-	}
+		/* This seems fine in theory, but we also need to cover the
+		 * case of this account matching one of the other buddies in
+		 * one of the contacts containing the buddy corresponding to
+		 * a conversation.  It's easier to just update them all. */
+		/* if (gaim_conversation_get_account(conv) == account) */
+			gaim_gtkconv_update_fields(conv, GAIM_GTKCONV_TAB_ICON |
+							GAIM_GTKCONV_MENU | GAIM_GTKCONV_COLORIZE_TITLE);
+	}
+}
+
+static gboolean
+update_buddy_status_timeout(GaimBuddy *buddy)
+{
+	/* To remove the signing-on/off door icon */
+	GaimConversation *conv;
+
+	conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, buddy->name, buddy->account);
+	if (conv)
+		gaim_gtkconv_update_fields(conv, GAIM_GTKCONV_TAB_ICON);
+
+	return FALSE;
+}
+
+static void
+update_buddy_status_changed(GaimBuddy *buddy, GaimStatus *old, GaimStatus *newstatus)
+{
+	GaimGtkConversation *gtkconv;
+	GaimConversation *conv;
+
+	gtkconv = get_gtkconv_with_contact(gaim_buddy_get_contact(buddy));
+	if (gtkconv)
+	{
+		conv = gtkconv->active_conv;
+		gaim_gtkconv_update_fields(conv, GAIM_GTKCONV_TAB_ICON | GAIM_GTKCONV_COLORIZE_TITLE);
+		if ((gaim_status_is_online(old) ^ gaim_status_is_online(newstatus)) != 0)
+			gaim_gtkconv_update_fields(conv, GAIM_GTKCONV_MENU);
+	}
+
+	/* In case a conversation is started after the buddy has signed-on/off */
+	g_timeout_add(11000, (GSourceFunc)update_buddy_status_timeout, buddy);
+}
+
+static void
+update_buddy_idle_changed(GaimBuddy *buddy, gboolean old, gboolean newidle)
+{
+	GaimConversation *conv;
+
+	conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, buddy->name, buddy->account);
+	if (conv)
+		gaim_gtkconv_update_fields(conv, GAIM_GTKCONV_TAB_ICON);
+}
+	
+static void
+update_buddy_icon(GaimBuddy *buddy)
+{
+	GaimConversation *conv;
+
+	conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, buddy->name, buddy->account);
+	if (conv)
+		gaim_gtkconv_update_fields(conv, GAIM_GTKCONV_BUDDY_ICON);
+}
+
+static void
+update_buddy_sign(GaimBuddy *buddy, const char *which)
+{
+	GaimPresence *presence;
+	GaimStatus *on, *off;
+
+	presence = gaim_buddy_get_presence(buddy);
+	if (!presence)
+		return;
+	off = gaim_presence_get_status(presence, "offline");
+	on = gaim_presence_get_status(presence, "available");
+
+	if (*(which+1) == 'f')
+		update_buddy_status_changed(buddy, on, off);
+	else
+		update_buddy_status_changed(buddy, off, on);
+}
+
+static void
+update_conversation_switched(GaimConversation *conv)
+{
+	gaim_gtkconv_update_fields(conv, GAIM_GTKCONV_TAB_ICON | GAIM_GTKCONV_SET_TITLE |
+					GAIM_GTKCONV_MENU | GAIM_GTKCONV_BUDDY_ICON);
+}
+
+static void
+update_buddy_typing(GaimAccount *account, const char *who)
+{
+	GaimConversation *conv;
+	GaimGtkConversation *gtkconv;
+
+	conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, who, account);
+	if (!conv)
+		return;
+
+	gtkconv = GAIM_GTK_CONVERSATION(conv);
+	if (gtkconv && gtkconv->active_conv == conv)
+		gaim_gtkconv_update_fields(conv, GAIM_GTKCONV_COLORIZE_TITLE);
+}
+
+static void
+update_chat(GaimConversation *conv)
+{
+	gaim_gtkconv_update_fields(conv, GAIM_GTKCONV_TOPIC |
+					GAIM_GTKCONV_MENU | GAIM_GTKCONV_SET_TITLE);
+}
+
+static void
+update_chat_topic(GaimConversation *conv, const char *old, const char *new)
+{
+	gaim_gtkconv_update_fields(conv, GAIM_GTKCONV_TOPIC);
 }
 
 void *
@@ -6276,11 +6464,6 @@
 						G_CALLBACK(account_signed_off_cb),
 						GINT_TO_POINTER(GAIM_CONV_ACCOUNT_OFFLINE));
 	
-	gaim_signal_connect(blist_handle, "buddy-added", handle,
-						G_CALLBACK(buddy_update_cb), NULL);
-	gaim_signal_connect(blist_handle, "buddy-removed", handle,
-						G_CALLBACK(buddy_update_cb), NULL);
-
 	gaim_signal_connect(gaim_conversations_get_handle(), "received-im-msg",
 						handle, G_CALLBACK(received_im_msg_cb), NULL);
 
@@ -6291,6 +6474,36 @@
 
 	gaim_signal_connect(gaim_accounts_get_handle(), "account-status-changed",
                         handle, GAIM_CALLBACK(account_status_changed_cb), NULL);
+
+	/* Callbacks to update a conversation */
+	gaim_signal_connect(blist_handle, "buddy-added", handle,
+						G_CALLBACK(buddy_update_cb), NULL);
+	gaim_signal_connect(blist_handle, "buddy-removed", handle,
+						G_CALLBACK(buddy_update_cb), NULL);
+	gaim_signal_connect(blist_handle, "buddy-signed-on",
+						handle, GAIM_CALLBACK(update_buddy_sign), "on");
+	gaim_signal_connect(blist_handle, "buddy-signed-off",
+						handle, GAIM_CALLBACK(update_buddy_sign), "off");
+	gaim_signal_connect(blist_handle, "buddy-status-changed",
+						handle, GAIM_CALLBACK(update_buddy_status_changed), NULL);
+	gaim_signal_connect(blist_handle, "buddy-idle-changed",
+						handle, GAIM_CALLBACK(update_buddy_idle_changed), NULL);
+	gaim_signal_connect(blist_handle, "buddy-icon-changed",
+						handle, GAIM_CALLBACK(update_buddy_icon), NULL);
+	gaim_signal_connect(gaim_conversations_get_handle(), "buddy-typing",
+						handle, GAIM_CALLBACK(update_buddy_typing), NULL);
+	gaim_signal_connect(gaim_conversations_get_handle(), "buddy-typing-stopped",
+						handle, GAIM_CALLBACK(update_buddy_typing), NULL);
+	gaim_signal_connect(gaim_gtk_conversations_get_handle(), "conversation-switched",
+						handle, GAIM_CALLBACK(update_conversation_switched), NULL);
+	gaim_signal_connect(gaim_conversations_get_handle(), "chat-left", handle,
+						GAIM_CALLBACK(update_chat), NULL);
+	gaim_signal_connect(gaim_conversations_get_handle(), "chat-joined", handle,
+						GAIM_CALLBACK(update_chat), NULL);
+	gaim_signal_connect(gaim_conversations_get_handle(), "chat-topic-changed", handle,
+						GAIM_CALLBACK(update_chat_topic), NULL);
+	gaim_signal_connect(gaim_conversations_get_handle(), "conversation-updated", handle,
+						GAIM_CALLBACK(gaim_gtkconv_updated), NULL);
 }
 
 void
@@ -6487,8 +6700,7 @@
 			gtkconv->unseen_state = state;
 	}
 
-	/* emit update signal to notify of count and possible unseen state change */
-	gaim_conversation_update(gtkconv->active_conv, GAIM_CONV_UPDATE_UNSEEN);
+	gaim_gtkconv_update_fields(gtkconv->active_conv, GAIM_GTKCONV_COLORIZE_TITLE);
 }
 
 /*
--- a/src/gtkdialogs.c	Mon Jan 09 16:04:04 2006 +0000
+++ b/src/gtkdialogs.c	Mon Jan 09 21:29:53 2006 +0000
@@ -886,18 +886,11 @@
 			while (bnode) {
 				GaimBuddy *buddy;
 				if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
-					GaimConversation *conv;
 					buddy = (GaimBuddy*)bnode;
 					bnode = bnode->next;
-					conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM,
-															   buddy->name,
-															   buddy->account);
 					if (gaim_account_is_connected(buddy->account)) {
 						gaim_account_remove_buddy(buddy->account, buddy, group);
 						gaim_blist_remove_buddy(buddy);
-						if (conv)
-							gaim_conversation_update(conv,
-									GAIM_CONV_UPDATE_REMOVE);
 					}
 				} else {
 					bnode = bnode->next;
@@ -938,7 +931,6 @@
 gaim_gtkdialogs_remove_buddy_cb(GaimBuddy *buddy)
 {
 	GaimGroup *group;
-	GaimConversation *conv;
 	gchar *name;
 	GaimAccount *account;
 
@@ -951,10 +943,6 @@
 	gaim_account_remove_buddy(buddy->account, buddy, group);
 	gaim_blist_remove_buddy(buddy);
 
-	conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, account);
-	if (conv != NULL)
-		gaim_conversation_update(conv, GAIM_CONV_UPDATE_REMOVE);
-
 	g_free(name);
 }
 
@@ -978,24 +966,7 @@
 static void
 gaim_gtkdialogs_remove_chat_cb(GaimChat *chat)
 {
-	char *name = NULL;
-	GaimAccount *account;
-	GaimConversation *conv = NULL;
-
-	account = chat->account;
-
-	if (GAIM_PLUGIN_PROTOCOL_INFO(account->gc->prpl)->get_chat_name != NULL)
-		name = GAIM_PLUGIN_PROTOCOL_INFO(account->gc->prpl)->get_chat_name(chat->components);
-
 	gaim_blist_remove_chat(chat);
-
-	if (name != NULL) {
-		conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT, name, account);
-		g_free(name);
-	}
-
-	if (conv != NULL)
-		gaim_conversation_update(conv, GAIM_CONV_UPDATE_REMOVE);
 }
 
 void
--- a/src/protocols/yahoo/yahoo.c	Mon Jan 09 16:04:04 2006 +0000
+++ b/src/protocols/yahoo/yahoo.c	Mon Jan 09 21:29:53 2006 +0000
@@ -1706,7 +1706,6 @@
 
 static void ignore_buddy(GaimBuddy *buddy) {
 	GaimGroup *group;
-	GaimConversation *conv;
 	GaimAccount *account;
 	gchar *name;
 
@@ -1724,12 +1723,6 @@
 
 	serv_add_deny(account->gc, name);
 
-	/* The follow should really be done by the core... */
-	conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, account);
-
-	if (conv != NULL)
-		gaim_conversation_update(conv, GAIM_CONV_UPDATE_REMOVE);
-
 	g_free(name);
 }
 
--- a/src/server.c	Mon Jan 09 16:04:04 2006 +0000
+++ b/src/server.c	Mon Jan 09 21:29:53 2006 +0000
@@ -593,17 +593,17 @@
 
 		gaim_conv_im_set_typing_state(im, state);
 		gaim_conv_im_update_typing(im);
-	}
-
-	if (state == GAIM_TYPING)
-	{
-		gaim_signal_emit(gaim_conversations_get_handle(),
-						 "buddy-typing", gc->account, name);
-	}
-	else
-	{
-		gaim_signal_emit(gaim_conversations_get_handle(),
-						 "buddy-typing-stopped", gc->account, name);
+	} else {
+		if (state == GAIM_TYPING)
+		{
+			gaim_signal_emit(gaim_conversations_get_handle(),
+							 "buddy-typing", gc->account, name);
+		}
+		else
+		{
+			gaim_signal_emit(gaim_conversations_get_handle(),
+							 "buddy-typing-stopped", gc->account, name);
+		}
 	}
 
 	if (conv != NULL && timeout > 0)
@@ -719,7 +719,6 @@
 
 	gaim_conv_chat_set_id(chat, id);
 
-
 	gaim_signal_emit(gaim_conversations_get_handle(), "chat-joined", conv);
 
 	return conv;
@@ -748,14 +747,14 @@
 	if (!conv)
 		return;
 
-	gaim_signal_emit(gaim_conversations_get_handle(), "chat-left", conv);
-
 	gaim_debug(GAIM_DEBUG_INFO, "server", "Leaving room: %s\n",
 			   gaim_conversation_get_name(conv));
 
 	g->buddy_chats = g_slist_remove(g->buddy_chats, conv);
 
 	gaim_conv_chat_left(GAIM_CONV_CHAT(conv));
+
+	gaim_signal_emit(gaim_conversations_get_handle(), "chat-left", conv);
 }
 
 void serv_got_chat_in(GaimConnection *g, int id, const char *who,
--- a/src/status.c	Mon Jan 09 16:04:04 2006 +0000
+++ b/src/status.c	Mon Jan 09 21:29:53 2006 +0000
@@ -1275,7 +1275,6 @@
 		time_t current_time, gboolean old_idle, gboolean idle)
 {
 	GaimBlistUiOps *ops = gaim_get_blist()->ui_ops;
-	GaimConversation *conv;
 
 	if (!old_idle && idle)
 	{
@@ -1316,17 +1315,6 @@
 
 	if (ops != NULL && ops->update != NULL)
 		ops->update(gaim_get_blist(), (GaimBlistNode *)buddy);
-
-	conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM,
-					gaim_buddy_get_name(buddy),
-					gaim_buddy_get_account(buddy));
-	if (conv)
-	{
-		GaimConversationUiOps *conv_ops;
-		conv_ops = gaim_conversation_get_ui_ops(conv);
-		if (conv_ops && conv_ops->updated)
-			conv_ops->updated(conv, GAIM_CONV_UPDATE_AWAY);
-	}
 }
 
 void