changeset 10810:9a1ced2bc585

[gaim-migrate @ 12463] This makes conversations contact aware, or is a start to it anyway. All messages from the same contact will appear in the same IM tab. Whoever messaged you last is who your messages go to. Don't forget to run make install in the top level src directory, or some plugin will likely crash gaim, as I changed a struct they use. Known bugs include a crash if you close the convo window (clicking the X on the tab doesn't crash however [actually it used to, but i fixed that one already]), and the history plugin inserting history when it shouldn't. There's probably many more tiny bugs. If you're wondering "how does it handle X?" the answer is probably it doesn't. However, I think this is all stuff our CPWs can handle, if I don't have time to fix it first (and I probably won't til friday). committer: Tailor Script <tailor@pidgin.im>
author Tim Ringenbach <marv@pidgin.im>
date Mon, 11 Apr 2005 02:20:34 +0000
parents f9e01ccd6046
children dc59482c8d37
files src/gtkconv.c src/gtkconv.h
diffstat 2 files changed, 204 insertions(+), 169 deletions(-) [+]
line wrap: on
line diff
--- a/src/gtkconv.c	Mon Apr 11 00:47:04 2005 +0000
+++ b/src/gtkconv.c	Mon Apr 11 02:20:34 2005 +0000
@@ -113,12 +113,12 @@
 static GtkWidget *invite_dialog = NULL;
 
 /* Prototypes. <-- because Paco-Paco hates this comment. */
-static void got_typing_keypress(GaimConversation *conv, gboolean first);
+static void got_typing_keypress(GaimGtkConversation *gtkconv, gboolean first);
 static GList *generate_invite_user_names(GaimConnection *gc);
 static void add_chat_buddy_common(GaimConversation *conv,
 								  const char *name);
 static gboolean tab_complete(GaimConversation *conv);
-static void update_typing_icon(GaimConversation *conv);
+static void update_typing_icon(GaimGtkConversation *gtkconv);
 static gboolean update_send_as_selection(GaimConvWindow *win);
 static char *item_factory_translate_func (const char *path, gpointer func_data);
 
@@ -136,19 +136,26 @@
 }
 
 static gint
-close_conv_cb(GtkWidget *w, gpointer d)
+close_conv_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
 {
-	GaimConversation *conv = (GaimConversation *)d;
-
-	gaim_conversation_destroy(conv);
-
+	GList *list = g_list_copy(gtkconv->convs), *l;
+	
+	l = list;
+	while (l) {
+		GaimConversation *conv = l->data;
+		gaim_conversation_destroy(conv);
+		l = l->next;
+	}
+	
+	g_list_free(list);
+	
 	return TRUE;
 }
 
 static gboolean
-size_allocate_cb(GtkWidget *w, GtkAllocation *allocation, GaimConversation *conv)
+size_allocate_cb(GtkWidget *w, GtkAllocation *allocation, GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimConvWindow *win = gaim_conversation_get_window(conv);
 	
 	if (!GTK_WIDGET_VISIBLE(w))
@@ -157,8 +164,6 @@
 	if (!GAIM_IS_GTK_CONVERSATION(conv))
 		return FALSE;
 
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-
 	/* I find that I resize the window when it has a bunch of conversations in it, mostly so that the tab bar
 	 * will fit, but then I don't want new windows taking up the entire screen.  I check to see if there is only one
 	 * conversation in the window.  This way we'll be setting new windows to the size of the last resized new window. */
@@ -196,9 +201,9 @@
 }
 
 static void
-default_formatize(GaimConversation *conv)
+default_formatize(GaimGtkConversation *c)
 {
-	GaimGtkConversation *c = GAIM_GTK_CONVERSATION(conv);
+	GaimConversation *conv = c->active_conv;
 		
 	if (conv->features & GAIM_CONNECTION_HTML)
 	{
@@ -451,14 +456,13 @@
 }
 
 static void
-send_cb(GtkWidget *widget, GaimConversation *conv)
+send_cb(GtkWidget *widget, GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimAccount *account;
 	GaimConnection *gc;
 	char *buf, *clean;
 
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
 	account = gaim_conversation_get_account(conv);
 
 	if (!gaim_account_is_connected(account))
@@ -470,7 +474,7 @@
 
 	if (check_for_and_do_command(conv)) {
 		gtk_imhtml_clear(GTK_IMHTML(gtkconv->entry));
-		default_formatize(conv);
+		default_formatize(gtkconv);
 		return;
 	}
 
@@ -512,14 +516,15 @@
 	g_free(buf);
 
 	gtk_imhtml_clear(GTK_IMHTML(gtkconv->entry));
-	default_formatize(conv);
+	default_formatize(gtkconv);
 }
 
 static void
-add_remove_cb(GtkWidget *widget, GaimConversation *conv)
+add_remove_cb(GtkWidget *widget, GaimGtkConversation *gtkconv)
 {
 	GaimAccount *account;
 	const char *name;
+	GaimConversation *conv = gtkconv->active_conv;
 
 	account = gaim_conversation_get_account(conv);
 	name    = gaim_conversation_get_name(conv);
@@ -545,8 +550,9 @@
 	gtk_widget_grab_focus(GAIM_GTK_CONVERSATION(conv)->entry);
 }
 
-static void chat_do_info(GaimConversation *conv, const char *who)
+static void chat_do_info(GaimGtkConversation *gtkconv, const char *who)
 {
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimPluginProtocolInfo *prpl_info = NULL;
 	GaimConnection *gc;
 
@@ -569,11 +575,9 @@
 
 
 static void
-info_cb(GtkWidget *widget, GaimConversation *conv)
+info_cb(GtkWidget *widget, GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
-
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
+	GaimConversation *conv = gtkconv->active_conv;
 
 	if (gaim_conversation_get_type(conv) == GAIM_CONV_IM) {
 		serv_get_info(gaim_conversation_get_gc(conv),
@@ -598,14 +602,15 @@
 		else
 			return;
 
-		chat_do_info(conv, name);
+		chat_do_info(gtkconv, name);
 		g_free(name);
 	}
 }
 
 static void
-block_cb(GtkWidget *widget, GaimConversation *conv)
+block_cb(GtkWidget *widget, GaimGtkConversation *gtkconv)
 {
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimAccount *account;
 
 	account = gaim_conversation_get_account(conv);
@@ -717,8 +722,9 @@
 };
 
 static void
-invite_cb(GtkWidget *widget, GaimConversation *conv)
+invite_cb(GtkWidget *widget, GaimGtkConversation *gtkconv)
 {
+	GaimConversation *conv = gtkconv->active_conv;
 	InviteBuddyInfo *info = NULL;
 
 	if (invite_dialog == NULL) {
@@ -861,6 +867,9 @@
 	gaim_gtkdialogs_im();
 }
 
+/* XXX change how this works, unless someone can justify it, i think
+ * it's really stupid, lets just grab the text from the imhtml, not
+ * keep an extra copy of it! */
 static void
 savelog_writefile_cb(void *user_data, const char *filename)
 {
@@ -1119,7 +1128,7 @@
 
 	conv = gaim_conv_window_get_active_conversation(win);
 
-	info_cb(NULL, conv);
+	info_cb(NULL, GAIM_GTK_CONVERSATION(conv));
 }
 
 static void
@@ -1130,7 +1139,7 @@
 
 	conv = gaim_conv_window_get_active_conversation(win);
 
-	invite_cb(NULL, conv);
+	invite_cb(NULL, GAIM_GTK_CONVERSATION(conv));
 }
 
 static void
@@ -1156,7 +1165,7 @@
 
 	conv = gaim_conv_window_get_active_conversation(win);
 
-	block_cb(NULL, conv);
+	block_cb(NULL, GAIM_GTK_CONVERSATION(conv));
 }
 
 static void
@@ -1167,7 +1176,7 @@
 
 	conv = gaim_conv_window_get_active_conversation(win);
 
-	add_remove_cb(NULL, conv);
+	add_remove_cb(NULL, GAIM_GTK_CONVERSATION(conv));
 }
 
 static void
@@ -1175,7 +1184,7 @@
 {
 	GaimConvWindow *win = (GaimConvWindow *)data;
 
-	close_conv_cb(NULL, gaim_conv_window_get_active_conversation(win));
+	close_conv_cb(NULL, GAIM_GTK_CONVERSATION(gaim_conv_window_get_active_conversation(win)));
 }
 
 static void
@@ -1250,8 +1259,9 @@
 }
 
 static void
-chat_do_im(GaimConversation *conv, const char *who)
+chat_do_im(GaimGtkConversation *gtkconv, const char *who)
 {
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimAccount *account;
 	GaimConnection *gc;
 	GaimPluginProtocolInfo *prpl_info = NULL;
@@ -1280,16 +1290,14 @@
 }
 
 static void
-chat_im_button_cb(GtkWidget *widget, GaimConversation *conv)
+chat_im_button_cb(GtkWidget *widget, GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
 	GaimGtkChatPane *gtkchat;
 	GtkTreeIter iter;
 	GtkTreeModel *model;
 	GtkTreeSelection *sel;
 	char *name;
 
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
 	gtkchat = gtkconv->u.chat;
 
 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list));
@@ -1300,14 +1308,14 @@
 	else
 		return;
 
-	chat_do_im(conv, name);
+	chat_do_im(gtkconv, name);
 	g_free(name);
 }
 
 static void
-ignore_cb(GtkWidget *w, GaimConversation *conv)
+ignore_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimGtkChatPane *gtkchat;
 	GaimConvChat *chat;
 	GtkTreeIter iter;
@@ -1316,7 +1324,6 @@
 	char *name;
 
 	chat    = GAIM_CONV_CHAT(conv);
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
 	gtkchat = gtkconv->u.chat;
 
 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list));
@@ -1339,16 +1346,17 @@
 }
 
 static void
-menu_chat_im_cb(GtkWidget *w, GaimConversation *conv)
+menu_chat_im_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
 {
 	const char *who = g_object_get_data(G_OBJECT(w), "user_data");
 
-	chat_do_im(conv, who);
+	chat_do_im(gtkconv, who);
 }
 
 static void
-menu_chat_send_file_cb(GtkWidget *w, GaimConversation *conv)
+menu_chat_send_file_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
 {
+	GaimConversation *conv = gtkconv->active_conv;
 	const char *who = g_object_get_data(G_OBJECT(w), "user_data");
 	GaimConnection *gc  = gaim_conversation_get_gc(conv);
 
@@ -1356,18 +1364,19 @@
 }
 
 static void
-menu_chat_info_cb(GtkWidget *w, GaimConversation *conv)
+menu_chat_info_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
 {
 	char *who;
 
 	who = g_object_get_data(G_OBJECT(w), "user_data");
 
-	chat_do_info(conv, who);
+	chat_do_info(gtkconv, who);
 }
 
 static void
-menu_chat_get_away_cb(GtkWidget *w, GaimConversation *conv)
+menu_chat_get_away_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
 {
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimPluginProtocolInfo *prpl_info = NULL;
 	GaimConnection *gc;
 	char *who;
@@ -1391,8 +1400,9 @@
 }
 
 static void
-menu_chat_add_remove_cb(GtkWidget *w, GaimConversation *conv)
+menu_chat_add_remove_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
 {
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimAccount *account;
 	GaimBuddy *b;
 	char *name;
@@ -1475,9 +1485,9 @@
 
 
 static gint
-gtkconv_chat_popup_menu_cb(GtkWidget *widget, GaimConversation *conv)
+gtkconv_chat_popup_menu_cb(GtkWidget *widget, GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimPluginProtocolInfo *prpl_info = NULL;
 	GaimGtkChatPane *gtkchat;
 	GaimConnection *gc;
@@ -1515,9 +1525,9 @@
 
 static gint
 right_click_chat_cb(GtkWidget *widget, GdkEventButton *event,
-					GaimConversation *conv)
+					GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimPluginProtocolInfo *prpl_info = NULL;
 	GaimGtkChatPane *gtkchat;
 	GaimConnection *gc;
@@ -1529,7 +1539,6 @@
 	gchar *who;
 	int x, y;
 
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
 	gtkchat = gtkconv->u.chat;
 	account = gaim_conversation_get_account(conv);
 	gc      = account->gc;
@@ -1552,7 +1561,7 @@
 	gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &who, -1);
 
 	if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) {
-		chat_do_im(conv, who);
+		chat_do_im(gtkconv, who);
 	} else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
 		GtkWidget *menu = create_chat_menu (conv, who, prpl_info, gc);
 		gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
@@ -1632,8 +1641,8 @@
 	int numconvs;
 	int curconv;
 
-	conv     = (GaimConversation *)data;
-	gtkconv  = GAIM_GTK_CONVERSATION(conv);
+	gtkconv  = (GaimGtkConversation *)data;
+	conv     = gtkconv->active_conv;;
 	win      = gaim_conversation_get_window(conv);
 	gtkwin   = GAIM_GTK_WINDOW(win);
 	numconvs = gaim_conv_window_get_conversation_count(win);
@@ -1837,32 +1846,38 @@
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
 	gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->entry),
-								 gaim_account_get_protocol_name(conv->account));
+	                             gaim_account_get_protocol_name(conv->account));
 }
 
 static void
 insert_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *position,
 			   gchar *new_text, gint new_text_length, gpointer user_data)
 {
-	GaimConversation *conv = (GaimConversation *)user_data;
-
-	g_return_if_fail(conv != NULL);
+	GaimGtkConversation *gtkconv = (GaimGtkConversation *)user_data;
+	GaimConversation *conv;
+
+	g_return_if_fail(gtkconv != NULL);
+	
+	conv = gtkconv->active_conv;
 
 	if (!gaim_prefs_get_bool("/core/conversations/im/send_typing"))
 		return;
 
-	got_typing_keypress(conv, (gtk_text_iter_is_start(position) &&
-							   gtk_text_iter_is_end(position)));
+	got_typing_keypress(gtkconv, (gtk_text_iter_is_start(position) &&
+	                    gtk_text_iter_is_end(position)));
 }
 
 static void
 delete_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *start_pos,
 			   GtkTextIter *end_pos, gpointer user_data)
 {
-	GaimConversation *conv = (GaimConversation *)user_data;
+	GaimGtkConversation *gtkconv = (GaimGtkConversation *)user_data;
+	GaimConversation *conv;
 	GaimConvIm *im;
 
-	g_return_if_fail(conv != NULL);
+	g_return_if_fail(gtkconv != NULL);
+	
+	conv = gtkconv->active_conv;
 
 	if (!gaim_prefs_get_bool("/core/conversations/im/send_typing"))
 		return;
@@ -1881,7 +1896,7 @@
 	}
 	else {
 		/* We're deleting, but not all of it, so it counts as typing. */
-		got_typing_keypress(conv, FALSE);
+		got_typing_keypress(gtkconv, FALSE);
 	}
 }
 
@@ -2369,8 +2384,8 @@
 static gboolean
 redraw_icon(gpointer data)
 {
-	GaimConversation *conv = (GaimConversation *)data;
-	GaimGtkConversation *gtkconv;
+	GaimGtkConversation *gtkconv = (GaimGtkConversation *)data;
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimAccount *account;
 	GaimPluginProtocolInfo *prpl_info = NULL;
 
@@ -2427,16 +2442,11 @@
 }
 
 static void
-start_anim(GtkObject *obj, GaimConversation *conv)
+start_anim(GtkObject *obj, GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
+	GaimConversation *conv = gtkconv->active_conv;
 	int delay;
 
-	if (!GAIM_IS_GTK_CONVERSATION(conv))
-		return;
-
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-
 	if (gtkconv->u.im->anim == NULL)
 		return;
 
@@ -2451,19 +2461,12 @@
 	if (delay < 100)
 		delay = 100;
 
-    gtkconv->u.im->icon_timer = g_timeout_add(delay, redraw_icon, conv);
+	gtkconv->u.im->icon_timer = g_timeout_add(delay, redraw_icon, conv);
 }
 
 static void
-stop_anim(GtkObject *obj, GaimConversation *conv)
+stop_anim(GtkObject *obj, GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
-
-	if (!GAIM_IS_GTK_CONVERSATION(conv))
-		return;
-
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-
 	if (gtkconv->u.im->icon_timer != 0)
 		g_source_remove(gtkconv->u.im->icon_timer);
 
@@ -2471,34 +2474,25 @@
 }
 
 static void
-toggle_icon_animate_cb(GtkWidget *w, GaimConversation *conv)
+toggle_icon_animate_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
-
-	if (!GAIM_IS_GTK_CONVERSATION(conv))
-		return;
-
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-
 	gtkconv->u.im->animate =
 		gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
 
 	if (gtkconv->u.im->animate)
-		start_anim(NULL, conv);
+		start_anim(NULL, gtkconv);
 	else
-		stop_anim(NULL, conv);
+		stop_anim(NULL, gtkconv);
 }
 
 static void
-remove_icon(GaimConversation *conv)
+remove_icon(GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
+	GaimConversation *conv = gtkconv->active_conv;;
 	GaimGtkWindow *gtkwin;
 
 	g_return_if_fail(conv != NULL);
 
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-
 	if (gtkconv->u.im->icon_container != NULL)
 		gtk_widget_destroy(gtkconv->u.im->icon_container);
 
@@ -2525,7 +2519,8 @@
 static void
 saveicon_writefile_cb(void *user_data, const char *filename)
 {
-	GaimConversation *conv = (GaimConversation *)user_data;
+	GaimGtkConversation *gtkconv = (GaimGtkConversation *)user_data;
+	GaimConversation *conv = gtkconv->active_conv;
 	FILE *fp;
 	GaimBuddyIcon *icon;
 	const void *data;
@@ -2549,8 +2544,9 @@
 }
 
 static void
-icon_menu_save_cb(GtkWidget *widget, GaimConversation *conv)
+icon_menu_save_cb(GtkWidget *widget, GaimGtkConversation *gtkconv)
 {
+	GaimConversation *conv = gtkconv->active_conv;
 	gchar *buf;
 
 	g_return_if_fail(conv != NULL);
@@ -2568,17 +2564,15 @@
 }
 
 static gboolean
-icon_menu(GtkObject *obj, GdkEventButton *e, GaimConversation *conv)
+icon_menu(GtkObject *obj, GdkEventButton *e, GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
+	GaimConversation *conv = gtkconv->active_conv;
 	static GtkWidget *menu = NULL;
 	GtkWidget *button;
 
 	if (e->button != 3 || e->type != GDK_BUTTON_PRESS)
 		return FALSE;
 
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-
 	/*
 	 * If a menu already exists, destroy it before creating a new one,
 	 * thus freeing-up the memory it occupied.
@@ -2633,7 +2627,7 @@
 	if (active)
 		gaim_gtkconv_update_buddy_icon(conv);
 	else
-		remove_icon(conv);
+		remove_icon(gtkconv);
 }
 
 /**************************************************************************
@@ -2647,11 +2641,11 @@
  * account signs on or off.
  */
 static void
-gray_stuff_out(GaimConversation *conv)
+gray_stuff_out(GaimGtkConversation *gtkconv)
 {
 	GaimConvWindow *win;
 	GaimGtkWindow *gtkwin;
-	GaimGtkConversation *gtkconv;
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimConnection *gc;
 	GaimPluginProtocolInfo *prpl_info = NULL;
 	GdkPixbuf *window_icon = NULL;
@@ -2852,7 +2846,7 @@
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
 
-	stop_anim(NULL, conv);
+	stop_anim(NULL, gtkconv);
 }
 
 static void
@@ -2875,9 +2869,9 @@
 	gaim_conversation_set_unseen(conv, GAIM_UNSEEN_NONE);
 
 	/* Update the menubar */
-	gray_stuff_out(conv);
-
-	update_typing_icon(conv);
+	gray_stuff_out(gtkconv);
+
+	update_typing_icon(gtkconv);
 
 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.logging),
 				       gaim_conversation_is_logging(conv));
@@ -2901,7 +2895,7 @@
 	 */
 	if ((gaim_conversation_get_type(conv) == GAIM_CONV_IM) &&
 		(gtkconv->u.im->animate))
-		start_anim(NULL, conv);
+		start_anim(NULL, gtkconv);
 
 	gtk_window_set_title(GTK_WINDOW(gtkwin->window),
 			     gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
@@ -2912,8 +2906,9 @@
  **************************************************************************/
 
 static void
-got_typing_keypress(GaimConversation *conv, gboolean first)
+got_typing_keypress(GaimGtkConversation *gtkconv, gboolean first)
 {
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimConvIm *im;
 
 	/*
@@ -2943,12 +2938,12 @@
 }
 
 static void
-update_typing_icon(GaimConversation *conv)
+update_typing_icon(GaimGtkConversation *gtkconv)
 {
 	GaimGtkWindow *gtkwin;
 	GaimConvIm *im = NULL;
-	GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv);
-
+	GaimConversation *conv = gtkconv->active_conv;
+	
 	gtkwin = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv));
 
 	if(gaim_conversation_get_type(conv) == GAIM_CONV_IM)
@@ -3710,11 +3705,11 @@
 	return gtkwin->menu.menubar;
 }
 
-static void topic_callback(GtkWidget *w, GaimConversation *conv)
+static void topic_callback(GtkWidget *w, GaimGtkConversation *gtkconv)
 {
 	GaimPluginProtocolInfo *prpl_info = NULL;
 	GaimConnection *gc;
-	GaimGtkConversation *gtkconv;
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimGtkChatPane *gtkchat;
 	const char *new_topic;
 	const char *current_topic;
@@ -3766,10 +3761,10 @@
 }
 
 static GtkWidget *
-setup_chat_pane(GaimConversation *conv)
+setup_chat_pane(GaimGtkConversation *gtkconv)
 {
 	GaimPluginProtocolInfo *prpl_info = NULL;
-	GaimGtkConversation *gtkconv;
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimGtkChatPane *gtkchat;
 	GaimConnection *gc;
 	GtkWidget *vpaned, *hpaned;
@@ -3784,7 +3779,6 @@
 	GtkTreeViewColumn *col;
 	GList *focus_chain = NULL;
 
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
 	gtkchat = gtkconv->u.chat;
 	gc      = gaim_conversation_get_gc(conv);
 
@@ -3816,7 +3810,7 @@
 			gtk_editable_set_editable(GTK_EDITABLE(gtkchat->topic_text), FALSE);
 		} else {
 			g_signal_connect(GTK_OBJECT(gtkchat->topic_text), "activate",
-					G_CALLBACK(topic_callback), conv);
+					G_CALLBACK(topic_callback), gtkconv);
 		}
 
 		gtk_box_pack_start(GTK_BOX(hbox), gtkchat->topic_text, TRUE, TRUE, 0);
@@ -3839,7 +3833,7 @@
 			gaim_prefs_get_int("/gaim/gtk/conversations/chat/default_width"),
 			gaim_prefs_get_int("/gaim/gtk/conversations/chat/default_height"));
 	g_signal_connect(G_OBJECT(gtkconv->imhtml), "size-allocate",
-					 G_CALLBACK(size_allocate_cb), conv);
+					 G_CALLBACK(size_allocate_cb), gtkconv);
 
 	g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event",
 						   G_CALLBACK(entry_stop_rclick_cb), NULL);
@@ -3918,7 +3912,7 @@
 	gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
 	gtk_tooltips_set_tip(gtkconv->tooltips, button, _("IM the user"), NULL);
 	g_signal_connect(G_OBJECT(button), "clicked",
-					 G_CALLBACK(chat_im_button_cb), conv);
+					 G_CALLBACK(chat_im_button_cb), gtkconv);
 
 	gtk_widget_show(button);
 
@@ -3931,7 +3925,7 @@
 	gtk_tooltips_set_tip(gtkconv->tooltips, button,
 						 _("Ignore the user"), NULL);
 	g_signal_connect(G_OBJECT(button), "clicked",
-					 G_CALLBACK(ignore_cb), conv);
+					 G_CALLBACK(ignore_cb), gtkconv);
 	gtk_widget_show(button);
 
 	/* Info */
@@ -3943,7 +3937,7 @@
 	gtk_tooltips_set_tip(gtkconv->tooltips, button,
 						 _("Get the user's information"), NULL);
 	g_signal_connect(G_OBJECT(button), "clicked",
-					 G_CALLBACK(info_cb), conv);
+	                 G_CALLBACK(info_cb), gtkconv);
 
 	gtk_widget_show(button);
 
@@ -3972,18 +3966,18 @@
 			gaim_prefs_get_int("/gaim/gtk/conversations/chat/entry_height"));
 	gtkconv->entry_buffer =
 		gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->entry));
-	g_object_set_data(G_OBJECT(gtkconv->entry_buffer), "user_data", conv);
+	g_object_set_data(G_OBJECT(gtkconv->entry_buffer), "user_data", gtkconv);
 
 	g_signal_connect(G_OBJECT(gtkconv->entry), "key_press_event",
-					 G_CALLBACK(entry_key_press_cb), conv);
+	                 G_CALLBACK(entry_key_press_cb), gtkconv);
 	g_signal_connect(G_OBJECT(gtkconv->entry), "message_send",
-			 G_CALLBACK(send_cb), conv);
+	                 G_CALLBACK(send_cb), gtkconv);
 	g_signal_connect_after(G_OBJECT(gtkconv->entry), "button_press_event",
-						   G_CALLBACK(entry_stop_rclick_cb), NULL);
+	                       G_CALLBACK(entry_stop_rclick_cb), NULL);
 	g_signal_connect(G_OBJECT(gtkconv->entry), "size-allocate",
-					 G_CALLBACK(size_allocate_cb), conv);
-
-	default_formatize(conv);
+	                 G_CALLBACK(size_allocate_cb), gtkconv);
+
+	default_formatize(gtkconv);
 
 	/*
 	 * Focus for chat windows should be as follows:
@@ -3997,19 +3991,15 @@
 }
 
 static GtkWidget *
-setup_im_pane(GaimConversation *conv)
+setup_im_pane(GaimGtkConversation *gtkconv)
 {
-	GaimGtkConversation *gtkconv;
-	GaimGtkImPane *gtkim;
+	GaimConversation *conv = gtkconv->active_conv;
 	GtkWidget *frame;
 	GtkWidget *paned;
 	GtkWidget *vbox;
 	GtkWidget *vbox2;
 	GList *focus_chain = NULL;
 
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-	gtkim   = gtkconv->u.im;
-
 	/* Setup the outer pane */
 	paned = gtk_vpaned_new();
 	gtk_widget_show(paned);
@@ -4030,14 +4020,14 @@
 			gaim_prefs_get_int("/gaim/gtk/conversations/im/default_width"),
 			gaim_prefs_get_int("/gaim/gtk/conversations/im/default_height"));
 	g_signal_connect(G_OBJECT(gtkconv->imhtml), "size-allocate",
-					 G_CALLBACK(size_allocate_cb), conv);
+	                 G_CALLBACK(size_allocate_cb), gtkconv);
 
 	g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event",
-						   G_CALLBACK(entry_stop_rclick_cb), NULL);
+	                       G_CALLBACK(entry_stop_rclick_cb), NULL);
 	g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_press_event",
-						   G_CALLBACK(refocus_entry_cb), gtkconv);
+	                 G_CALLBACK(refocus_entry_cb), gtkconv);
 	g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_release_event",
-						   G_CALLBACK(refocus_entry_cb), gtkconv);
+	                 G_CALLBACK(refocus_entry_cb), gtkconv);
 
 	/* Setup the bottom half of the conversation window */
 	vbox2 = gtk_vbox_new(FALSE, 6);
@@ -4064,25 +4054,25 @@
 			gaim_prefs_get_int("/gaim/gtk/conversations/im/entry_height"));
 	gtkconv->entry_buffer =
 		gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->entry));
-	g_object_set_data(G_OBJECT(gtkconv->entry_buffer), "user_data", conv);
+	g_object_set_data(G_OBJECT(gtkconv->entry_buffer), "user_data", gtkconv);
 
 	g_signal_connect(G_OBJECT(gtkconv->entry), "key_press_event",
-			 G_CALLBACK(entry_key_press_cb), conv);
-	g_signal_connect(G_OBJECT(gtkconv->entry), "message_send", G_CALLBACK(send_cb), conv);
+	                 G_CALLBACK(entry_key_press_cb), gtkconv);
+	g_signal_connect(G_OBJECT(gtkconv->entry), "message_send", G_CALLBACK(send_cb), gtkconv);
 	g_signal_connect_after(G_OBJECT(gtkconv->entry), "button_press_event",
-						   G_CALLBACK(entry_stop_rclick_cb), NULL);
+	                       G_CALLBACK(entry_stop_rclick_cb), NULL);
 	g_signal_connect(G_OBJECT(gtkconv->entry), "size-allocate",
-					 G_CALLBACK(size_allocate_cb), conv);
+	                 G_CALLBACK(size_allocate_cb), gtkconv);
 
 	g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "insert_text",
-					 G_CALLBACK(insert_text_cb), conv);
+	                 G_CALLBACK(insert_text_cb), gtkconv);
 	g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "delete_range",
-					 G_CALLBACK(delete_text_cb), conv);
+	                 G_CALLBACK(delete_text_cb), gtkconv);
 
 	/* had to move this after the imtoolbar is attached so that the
 	 * signals get fired to toggle the buttons on the toolbar as well.
 	 */
-	default_formatize(conv);
+	default_formatize(gtkconv);
 
 	gtkconv->u.im->animate = gaim_prefs_get_bool("/gaim/gtk/conversations/im/animate_buddy_icons");
 	gtkconv->u.im->show_icon = TRUE;
@@ -4099,9 +4089,10 @@
 
 static void
 conv_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y,
-			  GtkSelectionData *sd, guint info, guint t,
-			  GaimConversation *conv)
+              GtkSelectionData *sd, guint info, guint t,
+              GaimGtkConversation *gtkconv)
 {
+	GaimConversation *conv = gtkconv->active_conv;
 	GaimConvWindow *win = conv->window;
 	GaimConversation *c;
 	if (sd->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE))
@@ -4313,6 +4304,31 @@
 	{"application/x-im-contact", 0, GTK_IMHTML_DRAG_NUM + 1}
 };
 
+static GaimGtkConversation *
+gaim_gtk_conv_find_gtkconv(GaimConversation * conv)
+{
+	GaimBuddy *bud = gaim_find_buddy(conv->account, conv->name), *b;
+	GaimContact *c;
+	GaimBlistNode *cn;
+	
+	if (!bud)
+		return NULL;
+	
+	if (!(c = gaim_buddy_get_contact(bud)))
+		return NULL;
+	
+	cn = (GaimBlistNode *)c;
+	for (b = (GaimBuddy *)cn->child; b; b = (GaimBuddy *) ((GaimBlistNode *)b)->next) {
+		GaimConversation *conv;
+		if ((conv = gaim_find_conversation_with_account(GAIM_CONV_IM, b->name, b->account))) {
+			if (conv->ui_data)
+				return conv->ui_data;
+		}
+	}
+	
+	return NULL;
+}
+
 static void
 gaim_gtk_add_conversation(GaimConvWindow *win, GaimConversation *conv)
 {
@@ -4338,10 +4354,17 @@
 		tab_cont = gtkconv->tab_cont;
 
 		new_ui = FALSE;
-	}
-	else {
+	} else if (conv_type == GAIM_CONV_IM && (gtkconv = gaim_gtk_conv_find_gtkconv(conv))) {
+		conv->ui_data = gtkconv;
+		gtkconv->active_conv = conv;
+		if (!g_list_find(gtkconv->convs, conv))
+			gtkconv->convs = g_list_prepend(gtkconv->convs, conv);
+		return;
+	} else {
 		gtkconv = g_malloc0(sizeof(GaimGtkConversation));
 		conv->ui_data = gtkconv;
+		gtkconv->active_conv = conv;
+		gtkconv->convs = g_list_prepend(gtkconv->convs, conv);
 
 		/* Setup some initial variables. */
 		gtkconv->sg       = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
@@ -4351,12 +4374,12 @@
 			gtkconv->u.im = g_malloc0(sizeof(GaimGtkImPane));
 			gtkconv->u.im->a_virgin = TRUE;
 
-			pane = setup_im_pane(conv);
+			pane = setup_im_pane(gtkconv);
 		}
 		else if (conv_type == GAIM_CONV_CHAT) {
 			gtkconv->u.chat = g_malloc0(sizeof(GaimGtkChatPane));
 
-			pane = setup_chat_pane(conv);
+			pane = setup_chat_pane(gtkconv);
 		}
 
 		if (pane == NULL) {
@@ -4389,11 +4412,11 @@
 				  GDK_ACTION_COPY);
 
 		g_signal_connect(G_OBJECT(pane), "drag_data_received",
-				 G_CALLBACK(conv_dnd_recv), conv);
+				 G_CALLBACK(conv_dnd_recv), gtkconv);
 		g_signal_connect(G_OBJECT(gtkconv->imhtml), "drag_data_received",
-				 G_CALLBACK(conv_dnd_recv), conv);
+				 G_CALLBACK(conv_dnd_recv), gtkconv);
 		g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received",
-				 G_CALLBACK(conv_dnd_recv), conv);
+				 G_CALLBACK(conv_dnd_recv), gtkconv);
 
 		/* Setup the container for the tab. */
 		gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, 6);
@@ -4414,8 +4437,8 @@
 		gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), TRUE);
 
 		g_signal_connect_swapped(G_OBJECT(pane), "focus",
-								 G_CALLBACK(gtk_widget_grab_focus),
-								 gtkconv->entry);
+		                         G_CALLBACK(gtk_widget_grab_focus),
+		                         gtkconv->entry);
 	}
 
 	gtkconv->tabby = tabby = gtk_hbox_new(FALSE, 6);
@@ -4445,14 +4468,14 @@
 						 _("Close conversation"), NULL);
 
 	g_signal_connect(G_OBJECT(gtkconv->close), "clicked",
-					 G_CALLBACK(close_conv_cb), conv);
+	                 G_CALLBACK(close_conv_cb), gtkconv);
 
 	/*
 	 * I love Galeon. They have a fix for that stupid annoying visible
 	 * border bug. I love you guys! -- ChipX86
 	 */
 	g_signal_connect(G_OBJECT(gtkconv->close), "state_changed",
-					 G_CALLBACK(tab_close_button_state_changed_cb), NULL);
+	                 G_CALLBACK(tab_close_button_state_changed_cb), NULL);
 
 	/* Status icon. */
 	gtkconv->icon = gtk_image_new();
@@ -4575,7 +4598,7 @@
 }
 
 static int
-gaim_gtk_get_active_index(const GaimConvWindow *win)
+gaim_gtk_get_active_index(const GaimConvWindow *win) /* FIXME: XXX: This is wrong due to contact aware convo changes */
 {
 	GaimGtkWindow *gtkwin;
 	int index;
@@ -4634,6 +4657,11 @@
 {
 	GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv);
 
+	gtkconv->convs = g_list_remove(gtkconv->convs, conv);
+	/* Don't destroy ourselves until all our convos are gone */
+	if (gtkconv->convs)
+		return;
+	
 	/* If the "Save Conversation" or "Save Icon" dialogs are open then close them */
 	gaim_request_close_with_handle(conv);
 
@@ -4669,6 +4697,7 @@
 	gboolean has_focus;
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
+	gtkconv->active_conv = conv;
 	gaimwin = gaim_conversation_get_window(conv);
 	gtkwin = GAIM_GTK_WINDOW(gaimwin);
 
@@ -4706,6 +4735,7 @@
 	gboolean has_focus;
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
+	gtkconv->active_conv = conv;
 	gaimwin = gaim_conversation_get_window(conv);
 	gtkwin = GAIM_GTK_WINDOW(gaimwin);
 
@@ -4754,6 +4784,7 @@
 	size_t length = strlen(message) + 1;
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
+	gtkconv->active_conv = conv;
 	gc = gaim_conversation_get_gc(conv);
 
 	win = gaim_conversation_get_window(conv);
@@ -5300,6 +5331,7 @@
 	win     = gaim_conversation_get_window(conv);
 	gtkwin  = GAIM_GTK_WINDOW(win);
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
+	conv = gtkconv->active_conv; /* Gross hack */
 
 	if (type == GAIM_CONV_UPDATE_ACCOUNT)
 	{
@@ -5377,7 +5409,7 @@
 			gtk_label_set_text(GTK_LABEL(gtkconv->tab_label), title);
 
 		if (conv == gaim_conv_window_get_active_conversation(win))
-			update_typing_icon(conv);
+			update_typing_icon(gtkconv);
 
 		if (type == GAIM_CONV_UPDATE_TITLE) {
 			gtk_label_set_text(GTK_LABEL(gtkconv->menu_label), title);
@@ -5402,7 +5434,7 @@
 	else if (type == GAIM_CONV_ACCOUNT_ONLINE ||
 			 type == GAIM_CONV_ACCOUNT_OFFLINE)
 	{
-		gray_stuff_out(gaim_conv_window_get_active_conversation(win));
+		gray_stuff_out(GAIM_GTK_CONVERSATION(gaim_conv_window_get_active_conversation(win)));
 		generate_send_as_items(win, NULL);
 		update_tab_icon(conv);
 		gaim_conversation_autoset_title(conv);
@@ -5415,7 +5447,7 @@
 	         type == GAIM_CONV_UPDATE_CHATLEFT)
 	{
 		gaim_conversation_autoset_title(conv);
-		gray_stuff_out(conv);
+		gray_stuff_out(GAIM_GTK_CONVERSATION(conv));
 	}
 	else if (type == GAIM_CONV_UPDATE_ICON)
 	{
@@ -5423,7 +5455,7 @@
 	}
 	else if (type == GAIM_CONV_UPDATE_FEATURES)
 	{
-		gray_stuff_out(conv);
+		gray_stuff_out(GAIM_GTK_CONVERSATION(conv));
 	}
 }
 
@@ -5558,7 +5590,7 @@
 			gdk_pixbuf_animation_get_iter(gtkconv->u.im->anim, NULL); /* LEAK */
 		buf = gdk_pixbuf_animation_iter_get_pixbuf(gtkconv->u.im->iter);
 		if (gtkconv->u.im->animate)
-			start_anim(NULL, conv);
+			start_anim(NULL, gtkconv);
 	}
 
 	gaim_gtk_buddy_icon_get_scale_size(buf, prpl_info ? &prpl_info->icon_spec :
@@ -5621,7 +5653,7 @@
 	win = gaim_conversation_get_window(conv);
 
 	if (win != NULL && gaim_conv_window_get_active_conversation(win) == conv)
-		gray_stuff_out(conv);
+		gray_stuff_out(GAIM_GTK_CONVERSATION(conv));
 }
 
 GaimConvWindow *
--- a/src/gtkconv.h	Mon Apr 11 00:47:04 2005 +0000
+++ b/src/gtkconv.h	Mon Apr 11 02:20:34 2005 +0000
@@ -154,6 +154,9 @@
  */
 struct _GaimGtkConversation
 {
+	GaimConversation *active_conv;
+	GList *convs;
+	
 	gboolean make_sound;
 	gboolean show_formatting_toolbar;
 	gboolean show_timestamps;