changeset 11581:9b3833da6840

[gaim-migrate @ 13851] goodbye GaimConvWindow. Still some problems with this patch: - Scarey warnings console with gaim -d when closing tab - I tried to seperate gtkconv and gtkconvwin, but failed, as a result it has its own header, but the code is in the same file, which is rather weird. Also some code got moved around for no good reason. Feel free to move it back or reorganize it. - I broke the gesters plugin, and just disabled it. Hopefully someone with more time will fix it, it shouldn't take long, but I didn't feel like bothering. - This list is incomplete. committer: Tailor Script <tailor@pidgin.im>
author Tim Ringenbach <marv@pidgin.im>
date Sun, 02 Oct 2005 00:32:49 +0000
parents 24169af08585
children d35e4f1e9f43
files plugins/Makefile.am plugins/extplacement.c plugins/gestures/gestures.c plugins/notify.c plugins/perl/common/Conversation.xs plugins/perl/common/module.h src/Makefile.am src/conversation.c src/conversation.h src/gtkconv.c src/gtkconv.h src/gtkconvwin.h src/gtkdialogs.c src/gtkmain.c src/gtkprefs.c src/gtksound.c src/protocols/oscar/oscar.c src/server.c
diffstat 18 files changed, 2328 insertions(+), 3080 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/Makefile.am	Fri Sep 30 05:07:03 2005 +0000
+++ b/plugins/Makefile.am	Sun Oct 02 00:32:49 2005 +0000
@@ -20,7 +20,7 @@
 endif
 
 SUBDIRS = \
-	docklet $(GEVOLUTION_DIR) gestures \
+	docklet $(GEVOLUTION_DIR) \
 	$(PERL_DIR) ssl $(TCL_DIR) ticker \
 	$(MUSICMESSAGING_DIR)
 
--- a/plugins/extplacement.c	Fri Sep 30 05:07:03 2005 +0000
+++ b/plugins/extplacement.c	Sun Oct 02 00:32:49 2005 +0000
@@ -25,48 +25,50 @@
 #include "conversation.h"
 #include "version.h"
 #include "gtkplugin.h"
+#include "gtkconv.h"
+#include "gtkconvwin.h"
 
 static void
-conv_placement_by_number(GaimConversation *conv)
+conv_placement_by_number(GaimGtkConversation *conv)
 {
-	GaimConvWindow *win = NULL;
+	GaimGtkWindow *win = NULL;
 
 	if (gaim_prefs_get_bool("/plugins/gtk/extplacement/placement_number_separate"))
-		win = gaim_get_last_window_with_type(gaim_conversation_get_type(conv));
+		win = gaim_gtk_conv_window_last_with_type(gaim_conversation_get_type(conv->active_conv));
 	else
-		win = g_list_last(gaim_get_windows())->data;
+		win = g_list_last(gaim_gtk_conv_windows_get_list())->data;
 
 	if (win == NULL) {
-		win = gaim_conv_window_new();
+		win = gaim_gtk_conv_window_new();
 
-		gaim_conv_window_add_conversation(win, conv);
-		gaim_conv_window_show(win);
+		gaim_gtk_conv_window_add_gtkconv(win, conv);
+		gaim_gtk_conv_window_show(win);
 	} else {
 		int max_count = gaim_prefs_get_int("/plugins/gtk/extplacement/placement_number");
-		int count = gaim_conv_window_get_conversation_count(win);
+		int count = gaim_gtk_conv_window_get_gtkconv_count(win);
 
 		if (count < max_count)
-			gaim_conv_window_add_conversation(win, conv);
+			gaim_gtk_conv_window_add_gtkconv(win, conv);
 		else {
 			GList *l = NULL;
 
-			for (l = gaim_get_windows(); l != NULL; l = l->next) {
-				win = (GaimConvWindow *)l->data;
+			for (l = gaim_gtk_conv_windows_get_list(); l != NULL; l = l->next) {
+				win = l->data;
 
 				if (gaim_prefs_get_bool("/plugins/gtk/extplacement/placement_number_separate") &&
-					gaim_conversation_get_type(gaim_conv_window_get_active_conversation(win)) != gaim_conversation_get_type(conv))
+					gaim_conversation_get_type(gaim_gtk_conv_window_get_active_conversation(win)) != gaim_conversation_get_type(conv->active_conv))
 					continue;
 
-				count = gaim_conv_window_get_conversation_count(win);
+				count = gaim_gtk_conv_window_get_gtkconv_count(win);
 				if (count < max_count) {
-					gaim_conv_window_add_conversation(win, conv);
+					gaim_gtk_conv_window_add_gtkconv(win, conv);
 					return;
 				}
 			}
-			win = gaim_conv_window_new();
+			win = gaim_gtk_conv_window_new();
 
-			gaim_conv_window_add_conversation(win, conv);
-			gaim_conv_window_show(win);
+			gaim_gtk_conv_window_add_gtkconv(win, conv);
+			gaim_gtk_conv_window_show(win);
 		}
 	}
 }
@@ -74,7 +76,7 @@
 static gboolean
 plugin_load(GaimPlugin *plugin)
 {
-	gaim_conv_placement_add_fnc("number", _("By conversation count"),
+	gaim_gtkconv_placement_add_fnc("number", _("By conversation count"),
 							   &conv_placement_by_number);
 	gaim_prefs_trigger_callback("/gaim/gtk/conversations/placement");
 	return TRUE;
@@ -83,7 +85,7 @@
 static gboolean
 plugin_unload(GaimPlugin *plugin)
 {
-	gaim_conv_placement_remove_fnc("number");
+	gaim_gtkconv_placement_remove_fnc("number");
 	gaim_prefs_trigger_callback("/gaim/gtk/conversations/placement");
 	return TRUE;
 }
--- a/plugins/gestures/gestures.c	Fri Sep 30 05:07:03 2005 +0000
+++ b/plugins/gestures/gestures.c	Sun Oct 02 00:32:49 2005 +0000
@@ -56,23 +56,25 @@
 stroke_prev_tab(GtkWidget *widget, void *data)
 {
 	GaimConversation *conv;
-	GaimConvWindow *win;
+	GaimGtkConveration *gtkconv;
+	GaimGtkWindow *win;
 	GList *conversations;
 
 	conv  = (GaimConversation *)data;
-	win   = gaim_conversation_get_window(conv);
+	gtkconv = GAIM_GTK_CONVERSATION(conv);
+	win   = gtkconv->win;
 
-	for (conversations = gaim_conv_window_get_conversations(win);
+	for (conversations = win->gtkconvs;
 			conversations != NULL;
 			conversations = conversations->next)
 	{
-		if (conversations->data == conv)
+		if (conversations->data == gtkconv)
 		{
 			if (conversations->prev != NULL) {
-				gaim_conv_window_switch_conversation(win,
+				gaim_gtk_conv_window_switch_gtkconv(win,
 						conversations->prev->data);
 			} else {
-				gaim_conv_window_switch_conversation(win,
+				gaim_gtk_conv_window_switch_gtkconv(win,
 						g_list_last(conversations)->data);
 			}
 
--- a/plugins/notify.c	Fri Sep 30 05:07:03 2005 +0000
+++ b/plugins/notify.c	Sun Oct 02 00:32:49 2005 +0000
@@ -40,7 +40,7 @@
  * blank or something.
  * 22:23:53 <deryni> Also I think gaim might re-set that sort of frequently,
  * but I'd have to look.
- * 22:25:16 <seanegan> deryni: I keep my conversations in one workspace and am 
+ * 22:25:16 <seanegan> deryni: I keep my conversations in one workspace and am
  * frequently in an another, and the icon flashing in the pager would be a
  * neat visual clue.
  */
@@ -97,6 +97,7 @@
 #include "prefs.h"
 #include "signals.h"
 #include "version.h"
+#include "debug.h"
 
 #include "gtkplugin.h"
 #include "gtkutils.h"
@@ -111,7 +112,7 @@
 
 /* notification set/unset */
 static int notify(GaimConversation *conv, gboolean increment);
-static void notify_win(GaimConvWindow *gaimwin);
+static void notify_win(GaimGtkWindow *gaimwin);
 static void unnotify(GaimConversation *conv, gboolean reset);
 static int unnotify_cb(GtkWidget *widget, gpointer data, GaimConversation *conv);
 
@@ -124,30 +125,31 @@
 static void apply_notify();
 
 /* string function */
-static void handle_string(GaimConvWindow *gaimwin);
+static void handle_string(GaimGtkWindow *gaimwin);
 
 /* count function */
-static void handle_count(GaimConvWindow *gaimwin);
+static void handle_count(GaimGtkWindow *gaimwin);
 
 /* urgent function */
-static void handle_urgent(GaimConvWindow *gaimwin, gboolean add);
+static void handle_urgent(GaimGtkWindow *gaimwin, gboolean add);
 
 /* raise function */
-static void handle_raise(GaimConvWindow *gaimwin);
+static void handle_raise(GaimGtkWindow *gaimwin);
 
 /****************************************/
 /* Begin doing stuff below this line... */
 /****************************************/
 static int
-count_messages(GaimConvWindow *gaimwin)
+count_messages(GaimGtkWindow *gaimwin)
 {
 	gint count = 0;
-	GList *convs = NULL;
+	GList *convs = NULL, *l;
 
-	for (convs = gaim_conv_window_get_conversations(gaimwin);
-	     convs != NULL; convs = convs->next) {
-		GaimConversation *conv = convs->data;
-		count += GPOINTER_TO_INT(gaim_conversation_get_data(conv, "notify-message-count"));
+	for (convs = gaimwin->gtkconvs; convs != NULL; convs = convs->next) {
+		GaimGtkConversation *conv = convs->data;
+		for (l = conv->convs; l != NULL; l = l->next) {
+			count += GPOINTER_TO_INT(gaim_conversation_get_data(l->data, "notify-message-count"));
+		}
 	}
 
 	return count;
@@ -156,7 +158,7 @@
 static int
 notify(GaimConversation *conv, gboolean increment)
 {
-	GaimConvWindow *gaimwin = NULL;
+	GaimGtkWindow *gaimwin = NULL;
 	gint count;
 	gboolean has_focus;
 
@@ -166,7 +168,7 @@
 	/* We want to remove the notifications, but not reset the counter */
 	unnotify(conv, FALSE);
 
-	gaimwin = gaim_conversation_get_window(conv);
+	gaimwin = GAIM_GTK_CONVERSATION(conv)->win;
 
 	/* If we aren't doing notifications for this type of conversation, return */
 	if (((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) &&
@@ -175,7 +177,7 @@
 	     !gaim_prefs_get_bool("/plugins/gtk/X11/notify/type_chat")))
 		return 0;
 
-	g_object_get(G_OBJECT(GAIM_GTK_WINDOW(gaimwin)->window),
+	g_object_get(G_OBJECT(gaimwin->window),
 	             "has-toplevel-focus", &has_focus, NULL);
 
 	if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/type_focused") ||
@@ -193,7 +195,7 @@
 }
 
 static void
-notify_win(GaimConvWindow *gaimwin)
+notify_win(GaimGtkWindow *gaimwin)
 {
 	if (count_messages(gaimwin) <= 0)
 		return;
@@ -212,12 +214,12 @@
 unnotify(GaimConversation *conv, gboolean reset)
 {
 	GaimConversation *active_conv = NULL;
-	GaimConvWindow *gaimwin = NULL;
+	GaimGtkWindow *gaimwin = NULL;
 
 	g_return_if_fail(conv != NULL);
 
-	gaimwin = gaim_conversation_get_window(conv);
-	active_conv = gaim_conv_window_get_active_conversation(gaimwin);
+	gaimwin = GAIM_GTK_CONVERSATION(conv)->win;
+	active_conv = gaim_gtk_conv_window_get_active_conversation(gaimwin);
 
 	/* reset the conversation window title */
 	gaim_conversation_autoset_title(active_conv);
@@ -293,7 +295,12 @@
 	guint id;
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
-	gtkwin  = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv));
+	if (!gtkconv) {
+		gaim_debug_misc("notify", "Failed to find gtkconv\n");
+		return 0;
+	}
+
+	gtkwin  = gtkconv->win;
 
 	if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_focus")) {
 		/* TODO should really find a way to make this work no matter where the
@@ -343,7 +350,9 @@
 	GSList *ids = NULL;
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
-	gtkwin  = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv));
+	if (!gtkconv)
+		return;
+	gtkwin  = gtkconv->win;
 
 	ids = gaim_conversation_get_data(conv, "notify-window-signals");
 	for (; ids != NULL; ids = ids->next)
@@ -367,16 +376,6 @@
 static void
 conv_created(GaimConversation *conv)
 {
-	GaimConvWindow *gaimwin = NULL;
-	GaimGtkWindow *gtkwin = NULL;
-
-	gaimwin = gaim_conversation_get_window(conv);
-
-	if (gaimwin == NULL)
-		return;
-
-	gtkwin = GAIM_GTK_WINDOW(gaimwin);
-
 	gaim_conversation_set_data(conv, "notify-message-count", GINT_TO_POINTER(0));
 
 	/* always attach the signals, notify() will take care of conversation type
@@ -388,7 +387,7 @@
 conv_switched(GaimConversation *old_conv, GaimConversation *new_conv)
 {
 #if 0
-	GaimConvWindow *gaimwin = gaim_conversation_get_window(new_conv);
+	GaimGtkWindow *gaimwin = gaim_conversation_get_window(new_conv);
 #endif
 
 	/*
@@ -414,22 +413,25 @@
 static void
 deleting_conv(GaimConversation *conv)
 {
-	GaimConvWindow *gaimwin = NULL;
+	GaimGtkWindow *gaimwin = NULL;
 
 	detach_signals(conv);
 
 	unnotify(conv, TRUE);
 
-	gaimwin = gaim_conversation_get_window(conv);
+	gaimwin = GAIM_GTK_CONVERSATION(conv)->win;
+#if 0
+	/* i think this line crashes */
 	if (count_messages(gaimwin))
 		notify_win(gaimwin);
+#endif
 }
 
 #if 0
 static void
 conversation_dragging(GaimConversation *active_conv,
-                        GaimConvWindow *old_gaimwin,
-                        GaimConvWindow *new_gaimwin)
+                        GaimGtkWindow *old_gaimwin,
+                        GaimGtkWindow *new_gaimwin)
 {
 	if (old_gaimwin != new_gaimwin) {
 		if (old_gaimwin == NULL) {
@@ -475,14 +477,14 @@
 #endif
 
 static void
-handle_string(GaimConvWindow *gaimwin)
+handle_string(GaimGtkWindow *gaimwin)
 {
 	GtkWindow *window = NULL;
 	gchar newtitle[256];
 
 	g_return_if_fail(gaimwin != NULL);
 
-	window = GTK_WINDOW(GAIM_GTK_WINDOW(gaimwin)->window);
+	window = GTK_WINDOW(gaimwin->window);
 	g_return_if_fail(window != NULL);
 
 	g_snprintf(newtitle, sizeof(newtitle), "%s%s",
@@ -492,14 +494,14 @@
 }
 
 static void
-handle_count(GaimConvWindow *gaimwin)
+handle_count(GaimGtkWindow *gaimwin)
 {
 	GtkWindow *window;
 	char newtitle[256];
 
 	g_return_if_fail(gaimwin != NULL);
 
-	window = GTK_WINDOW(GAIM_GTK_WINDOW(gaimwin)->window);
+	window = GTK_WINDOW(gaimwin->window);
 	g_return_if_fail(window != NULL);
 
 	g_snprintf(newtitle, sizeof(newtitle), "[%d] %s",
@@ -508,30 +510,29 @@
 }
 
 static void
-handle_urgent(GaimConvWindow *gaimwin, gboolean add)
+handle_urgent(GaimGtkWindow *win, gboolean add)
 {
 	XWMHints *hints;
-	GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(gaimwin);
 
-	g_return_if_fail(gtkwin != NULL);
-	g_return_if_fail(gtkwin->window != NULL);
-	g_return_if_fail(gtkwin->window->window != NULL);
+	g_return_if_fail(win != NULL);
+	g_return_if_fail(win->window != NULL);
+	g_return_if_fail(win->window->window != NULL);
 
-	hints = XGetWMHints(GDK_WINDOW_XDISPLAY(gtkwin->window->window),
-	                    GDK_WINDOW_XWINDOW(gtkwin->window->window));
+	hints = XGetWMHints(GDK_WINDOW_XDISPLAY(win->window->window),
+	                    GDK_WINDOW_XWINDOW(win->window->window));
 	if (add)
 		hints->flags |= XUrgencyHint;
 	else
 		hints->flags &= ~XUrgencyHint;
-	XSetWMHints(GDK_WINDOW_XDISPLAY(gtkwin->window->window),
-	            GDK_WINDOW_XWINDOW(gtkwin->window->window), hints);
+	XSetWMHints(GDK_WINDOW_XDISPLAY(win->window->window),
+	            GDK_WINDOW_XWINDOW(win->window->window), hints);
 	XFree(hints);
 }
 
 static void
-handle_raise(GaimConvWindow *gaimwin)
+handle_raise(GaimGtkWindow *gaimwin)
 {
-	gaim_conv_window_raise(gaimwin);
+	gaim_gtk_conv_window_raise(gaimwin);
 }
 
 static void
@@ -596,7 +597,7 @@
 static void
 apply_method() {
 	GList *convs = gaim_get_conversations();
-	GaimConvWindow *gaimwin = NULL;
+	GaimGtkWindow *gaimwin = NULL;
 
 	for (convs = gaim_get_conversations(); convs != NULL; convs = convs->next) {
 		GaimConversation *conv = (GaimConversation *)convs->data;
@@ -604,7 +605,7 @@
 		/* remove notifications */
 		unnotify(conv, FALSE);
 
-		gaimwin = gaim_conversation_get_window(conv);
+		gaimwin = GAIM_GTK_CONVERSATION(conv)->win;
 		if (GPOINTER_TO_INT(gaim_conversation_get_data(conv, "notify-message-count")) != 0)
 			/* reattach appropriate notifications */
 			notify(conv, FALSE);
--- a/plugins/perl/common/Conversation.xs	Fri Sep 30 05:07:03 2005 +0000
+++ b/plugins/perl/common/Conversation.xs	Sun Oct 02 00:32:49 2005 +0000
@@ -1,99 +1,16 @@
 #include "module.h"
 
-MODULE = Gaim::Conv  PACKAGE = Gaim::Conv::Window  PREFIX = gaim_conv_window_
-PROTOTYPES: ENABLE
-
-void 
-gaim_conversations_set_win_ui_ops(ops)
-	Gaim::ConvWindow::UiOps ops
-
-Gaim::ConvWindow::UiOps
-gaim_conversations_get_win_ui_ops()
-
-void
-gaim_conv_window_get_conversations(win)
-	Gaim::ConvWindow win
-PREINIT:
-	GList *l;
-PPCODE:
-	for (l = gaim_conv_window_get_conversations(win); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(gaim_perl_bless_object(l->data, "Gaim::ListEntry")));
-	}
-
-Gaim::ConvWindow
-gaim_conv_window_new()
-
-void 
-gaim_conv_window_destroy(win)
-	Gaim::ConvWindow win
-
-void 
-gaim_conv_window_show(win)
-	Gaim::ConvWindow win
-
-void 
-gaim_conv_window_hide(win)
-	Gaim::ConvWindow win
-
-void 
-gaim_conv_window_raise(win)
-	Gaim::ConvWindow win
-
-size_t 
-gaim_conv_window_get_conversation_count(win)
-	Gaim::ConvWindow win
-
-gboolean 
-gaim_conv_window_has_focus(win)
-	Gaim::ConvWindow win
-
-Gaim::ConvWindow::UiOps
-gaim_conv_window_get_ui_ops(win)
-	Gaim::ConvWindow win
-
-Gaim::ConvWindow
-get_first_window_with_type(type)
-	Gaim::ConversationType type
-CODE:
-	RETVAL = gaim_get_first_window_with_type(type);
-OUTPUT:
-	RETVAL
-
-Gaim::ConvWindow
-get_last_window_with_type(type)
-	Gaim::ConversationType type
-CODE:
-	RETVAL = gaim_get_last_window_with_type(type);
-OUTPUT:
-	RETVAL
-
-int
-gaim_conv_window_add_conversation(win, conv)
-	Gaim::ConvWindow win
-	Gaim::Conversation conv
-
-
 MODULE = Gaim::Conv  PACKAGE = Gaim::Conv  PREFIX = gaim_conversation_
 PROTOTYPES: ENABLE
 
 void *
 gaim_conversations_get_handle()
 
-void 
+void
 gaim_conversations_init()
 
-void 
-gaim_conversations_uninit()
-
 void
-gaim_conv_placement_get_options()
-PREINIT:
-	GList *l;
-PPCODE:
-	for (l = gaim_conv_placement_get_options(); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(gaim_perl_bless_object(l->data, "Gaim::ListEntry")));
-	}
-
+gaim_conversations_uninit()
 
 void
 get_ims()
@@ -114,15 +31,6 @@
 	}
 
 void
-get_windows()
-PREINIT:
-	GList *l;
-PPCODE:
-	for (l = gaim_get_windows(); l != NULL; l = l->next) {
-		XPUSHs(sv_2mortal(gaim_perl_bless_object(l->data, "Gaim::ListEntry")));
-	}
-
-void
 get_chats()
 PREINIT:
 	GList *l;
@@ -141,11 +49,11 @@
 		XPUSHs(sv_2mortal(gaim_perl_bless_object(l->data, "Gaim::ListEntry")));
 	}
 
-void 
+void
 gaim_conversation_destroy(conv)
 	Gaim::Conversation conv
 
-Gaim::ConversationType 
+Gaim::ConversationType
 gaim_conversation_get_type(conv)
 	Gaim::Conversation conv
 
@@ -157,7 +65,7 @@
 gaim_conversation_get_gc(conv)
 	Gaim::Conversation conv
 
-void 
+void
 gaim_conversation_set_title(conv, title);
 	Gaim::Conversation conv
 	const char * title
@@ -166,15 +74,15 @@
 gaim_conversation_get_title(conv)
 	Gaim::Conversation conv
 
-void 
+void
 gaim_conversation_autoset_title(conv)
 	Gaim::Conversation conv
 
-Gaim::UnseenState 
+Gaim::UnseenState
 gaim_conversation_get_unseen(conv)
 	Gaim::Conversation conv
 
-void 
+void
 gaim_conversation_set_name(conv, name)
 	Gaim::Conversation conv
 	const char *name
@@ -182,21 +90,17 @@
 const char *
 gaim_conversation_get_name(conv)
 	Gaim::Conversation conv
-	
-void 
+
+void
 gaim_conversation_set_logging(conv, log)
 	Gaim::Conversation conv
 	gboolean log
 
-gboolean 
+gboolean
 gaim_conversation_is_logging(conv)
 	Gaim::Conversation conv
 
 
-Gaim::ConvWindow
-gaim_conversation_get_window(conv)
-	Gaim::Conversation conv
-
 Gaim::Conversation::IM
 gaim_conversation_get_im_data(conv)
 	Gaim::Conversation conv
@@ -205,40 +109,40 @@
 gaim_conversation_get_chat_data(conv)
 	Gaim::Conversation conv
 
-gpointer 
+gpointer
 gaim_conversation_get_data(conv, key)
 	Gaim::Conversation conv
 	const char * key
 
-Gaim::ConnectionFlags 
+Gaim::ConnectionFlags
 gaim_conversation_get_features(conv)
 	Gaim::Conversation conv
 
-void 
+void
 gaim_conversation_update_progress(conv, percent)
 	Gaim::Conversation conv
 	float percent
-	
-gboolean 
+
+gboolean
 gaim_conversation_has_focus(conv)
 	Gaim::Conversation conv
 
-void 
+void
 gaim_conversation_update(conv, type)
 	Gaim::Conversation conv
 	Gaim::ConvUpdateType type
-	
-Gaim::Conversation 
+
+Gaim::Conversation
 gaim_conversation_new(type, account, name)
-	Gaim::ConversationType type		  
+	Gaim::ConversationType type
 	Gaim::Account account
 	const char *name
 
-void 
+void
 gaim_conversation_set_account(conv, account);
 	Gaim::Conversation conv
 	Gaim::Account account
-	
+
 
 
 MODULE = Gaim::Conv  PACKAGE = Gaim::Conv::IM  PREFIX = gaim_conv_im_
@@ -248,7 +152,7 @@
 gaim_conv_im_get_conversation(im)
 	Gaim::Conversation::IM im
 
-void 
+void
 gaim_conv_im_set_icon(im, icon)
 	Gaim::Conversation::IM im
 	Gaim::Buddy::Icon icon
@@ -257,29 +161,29 @@
 gaim_conv_im_get_icon(im)
 	Gaim::Conversation::IM im
 
-void 
+void
 gaim_conv_im_set_typing_state(im, state)
 	Gaim::Conversation::IM im
 	Gaim::TypingState state
 
-Gaim::TypingState 
+Gaim::TypingState
 gaim_conv_im_get_typing_state(im)
 	Gaim::Conversation::IM im
 
-void 
+void
 gaim_conv_im_start_typing_timeout(im, timeout)
 	Gaim::Conversation::IM im
 	int timeout
 
-void 
+void
 gaim_conv_im_stop_typing_timeout(im)
 	Gaim::Conversation::IM im
 
-guint 
+guint
 gaim_conv_im_get_typing_timeout(im)
 	Gaim::Conversation::IM im
 
-void 
+void
 gaim_conv_im_set_type_again(im, val)
 	Gaim::Conversation::IM im
 	time_t val
@@ -288,30 +192,30 @@
 gaim_conv_im_get_type_again(im)
 	Gaim::Conversation::IM im
 
-void 
+void
 gaim_conv_im_start_type_again_timeout(im)
 	Gaim::Conversation::IM im
 
-void 
+void
 gaim_conv_im_stop_type_again_timeout(im)
 	Gaim::Conversation::IM im
 
-guint 
+guint
 gaim_conv_im_get_type_again_timeout(im)
 	Gaim::Conversation::IM im
 
 
-void 
+void
 gaim_conv_im_update_typing(im)
 	Gaim::Conversation::IM im
 
 
-void 
+void
 gaim_conv_im_send(im, message)
 	Gaim::Conversation::IM im
 	const char *message
 
-void 
+void
 gaim_conv_im_write(im, who, message, flags, mtime)
 	Gaim::Conversation::IM im
 	const char *who
@@ -323,13 +227,13 @@
 MODULE = Gaim::Conv  PACKAGE = Gaim::Conv  PREFIX = gaim_conv_
 PROTOTYPES: ENABLE
 
-gboolean 
+gboolean
 gaim_conv_present_error(who, account, what)
 	const char *who
 	Gaim::Account account
  	const char *what
 
-void 
+void
 gaim_conv_custom_smiley_close(conv, smile)
 	Gaim::Conversation conv
 	const char *smile
@@ -376,17 +280,17 @@
 		XPUSHs(sv_2mortal(gaim_perl_bless_object(l->data, "Gaim::ListEntry")));
 	}
 
-void 
+void
 gaim_conv_chat_ignore(chat, name)
 	Gaim::Conversation::Chat chat
 	const char *name
 
-void 
+void
 gaim_conv_chat_unignore(chat, name)
 	Gaim::Conversation::Chat chat
 	const char *name
 
-void 
+void
 gaim_conv_chat_set_ignored(chat, ignored)
 	Gaim::Conversation::Chat chat
 	SV * ignored
@@ -422,21 +326,21 @@
 
 
 
-void 
+void
 gaim_conv_chat_set_id(chat, id)
 	Gaim::Conversation::Chat chat
 	int id
 
-int 
+int
 gaim_conv_chat_get_id(chat)
 	Gaim::Conversation::Chat chat
 
-void 
+void
 gaim_conv_chat_send(chat, message)
 	Gaim::Conversation::Chat chat
 	const char * message
 
-void 
+void
 gaim_conv_chat_add_users(chat, users, extra_msgs, flags, new_arrivals)
 	Gaim::Conversation::Chat chat
 	SV * users
@@ -472,9 +376,9 @@
 	}
 
 	gaim_conv_chat_add_users(chat, t_GL_users, t_GL_extra_msgs, t_GL_flags, new_arrivals);
-	
+
 
-gboolean 
+gboolean
 gaim_conv_chat_find_user(chat, user)
 	Gaim::Conversation::Chat chat
 	const char * user
@@ -510,6 +414,6 @@
 gaim_conv_chat_cb_get_name(cb)
 	Gaim::Conversation::ChatBuddy cb
 
-void 
+void
 gaim_conv_chat_cb_destroy(cb);
 	Gaim::Conversation::ChatBuddy cb
--- a/plugins/perl/common/module.h	Fri Sep 30 05:07:03 2005 +0000
+++ b/plugins/perl/common/module.h	Sun Oct 02 00:32:49 2005 +0000
@@ -99,8 +99,8 @@
 typedef GaimTypingState			Gaim__TypingState;
 typedef GaimMessageFlags	  	Gaim__MessageFlags;
 typedef GaimConvChatBuddyFlags	  	Gaim__ConvChatBuddyFlags;
-typedef GaimConvWindowUiOps *			Gaim__ConvWindow__UiOps;
-typedef GaimConvWindow *      			Gaim__ConvWindow;
+//typedef GaimConvWindowUiOps *			Gaim__ConvWindow__UiOps;
+//typedef GaimConvWindow *      			Gaim__ConvWindow;
 typedef GaimConversationUiOps *			Gaim__Conversation__UiOps;
 typedef GaimConversation *			Gaim__Conversation;
 typedef GaimConvIm *          			Gaim__Conversation__IM;
--- a/src/Makefile.am	Fri Sep 30 05:07:03 2005 +0000
+++ b/src/Makefile.am	Sun Oct 02 00:32:49 2005 +0000
@@ -235,47 +235,14 @@
 
 bin_PROGRAMS = gaim $(gaim_clientbP)
 
-gaim_SOURCES = \
-	$(gaim_coresources) \
-	$(dbus_sources) \
-	gtkcombobox.c \
-	gtkcelllayout.c \
-	gtkcellview.c \
-	gtkcellviewmenuitem.c \
-	gtkaccount.c \
-	gtkcellrendererprogress.c \
-	gtkblist.c \
-	gtkconn.c \
-	gtkconv.c \
-	gtkdebug.c \
-	gtkdialogs.c \
-	gtkdnd-hints.c \
-	gtkgaim-disclosure.c \
-	gtkeventloop.c \
-	gtkft.c \
-	gtkimhtml.c \
-	gtkimhtmltoolbar.c \
-	gtklog.c \
-	gtkmain.c \
-	gtkmenutray.c \
-	gtknotify.c \
-	gtkplugin.c \
-	gtkpluginpref.c \
-	gtkprefs.c \
-	gtkprivacy.c \
-	gtkpounce.c \
-	gtkrequest.c \
-	gtkroomlist.c \
-	gtksavedstatuses.c \
-	gtksound.c \
-	gtksourceiter.c \
-	gtkstatusbox.c \
-	gtkstock.c \
-	gtkthemes.c \
-	gtkutils.c \
-	idle.c \
-	session.c \
-	gtkwhiteboard.c
+gaim_SOURCES = $(gaim_coresources) 	$(dbus_sources) 	gtkcombobox.c \
+		gtkcelllayout.c 	gtkcellview.c 	gtkcellviewmenuitem.c 	gtkaccount.c \
+		gtkcellrendererprogress.c 	gtkblist.c 	gtkconn.c 	gtkconv.c 	gtkdebug.c 	gtkdialogs.c \
+		gtkdnd-hints.c 	gtkgaim-disclosure.c 	gtkeventloop.c 	gtkft.c 	gtkimhtml.c \
+		gtkimhtmltoolbar.c 	gtklog.c 	gtkmain.c 	gtkmenutray.c 	gtknotify.c 	gtkplugin.c \
+		gtkpluginpref.c 	gtkprefs.c 	gtkprivacy.c 	gtkpounce.c 	gtkrequest.c 	gtkroomlist.c \
+		gtksavedstatuses.c 	gtksound.c 	gtksourceiter.c 	gtkstatusbox.c 	gtkstock.c 	gtkthemes.c \
+		gtkutils.c 	idle.c 	session.c 	gtkwhiteboard.c gtkconvwin.c
 
 gaim_headers = \
 	$(dbus_headers) \
--- a/src/conversation.c	Fri Sep 30 05:07:03 2005 +0000
+++ b/src/conversation.c	Sun Oct 02 00:32:49 2005 +0000
@@ -31,27 +31,19 @@
 #include "signals.h"
 #include "util.h"
 
-typedef struct
-{
-	char *id;
-	char *name;
-	GaimConvPlacementFunc fnc;
-
-} ConvPlacementData;
-
 #define SEND_TYPED_TIMEOUT 5000
 
-static GaimConvWindowUiOps *win_ui_ops = NULL;
-
 static GList *conversations = NULL;
 static GList *ims = NULL;
 static GList *chats = NULL;
-static GList *windows = NULL;
-static GList *conv_placement_fncs = NULL;
-static GaimConvPlacementFunc place_conv = NULL;
-
-static void ensure_default_funcs(void);
-static void conv_placement_last_created_win(GaimConversation *conv);
+static GaimConversationUiOps *default_ops = NULL;
+
+
+void
+gaim_conversations_set_ui_ops(GaimConversationUiOps *ops)
+{
+	default_ops = ops;
+}
 
 static gboolean
 reset_typing(gpointer data)
@@ -237,359 +229,6 @@
 	g_free(sent);
 }
 
-GaimConvWindow *
-gaim_conv_window_new(void)
-{
-	GaimConvWindow *win;
-
-	win = g_new0(GaimConvWindow, 1);
-	GAIM_DBUS_REGISTER_POINTER(win, GaimConvWindow);
-
-	windows = g_list_append(windows, win);
-
-	win->ui_ops = gaim_conversations_get_win_ui_ops();
-
-	if (win->ui_ops != NULL && win->ui_ops->new_window != NULL)
-		win->ui_ops->new_window(win);
-
-	return win;
-}
-
-void
-gaim_conv_window_destroy(GaimConvWindow *win)
-{
-	GaimConvWindowUiOps *ops;
-	GList *node;
-
-	g_return_if_fail(win != NULL);
-
-	ops = gaim_conv_window_get_ui_ops(win);
-
-	/*
-	 * If there are any conversations in this, destroy them all. The last
-	 * conversation will call gaim_conv_window_destroy(), but this time, this
-	 * check will fail and the window will actually be destroyed.
-	 *
-	 * This is needed because chats may not close right away. They may
-	 * wait for notification first. When they get that, the window is
-	 * already destroyed, and gaim either crashes or spits out gtk warnings.
-	 * The problem is fixed with this check.
-	 */
-	if (gaim_conv_window_get_conversation_count(win) > 0) {
-
-		node = g_list_first(gaim_conv_window_get_conversations(win));
-		while(node != NULL)
-		{
-			GaimConversation *conv = node->data;
-
-			node = g_list_next(node);
-
-			gaim_conversation_destroy(conv);
-		}
-	}
-	else
-	{
-		if (ops != NULL && ops->destroy_window != NULL)
-			ops->destroy_window(win);
-
-		g_list_free(gaim_conv_window_get_conversations(win));
-
-		windows = g_list_remove(windows, win);
-
-		GAIM_DBUS_UNREGISTER_POINTER(win);
-		g_free(win);
-	}
-}
-
-void
-gaim_conv_window_show(GaimConvWindow *win)
-{
-	GaimConvWindowUiOps *ops;
-
-	g_return_if_fail(win != NULL);
-
-	ops = gaim_conv_window_get_ui_ops(win);
-
-	if (ops == NULL || ops->show == NULL)
-		return;
-
-	ops->show(win);
-}
-
-void
-gaim_conv_window_hide(GaimConvWindow *win)
-{
-	GaimConvWindowUiOps *ops;
-
-	g_return_if_fail(win != NULL);
-
-	ops = gaim_conv_window_get_ui_ops(win);
-
-	if (ops == NULL || ops->hide == NULL)
-		return;
-
-	ops->hide(win);
-}
-
-void
-gaim_conv_window_raise(GaimConvWindow *win)
-{
-	GaimConvWindowUiOps *ops;
-
-	g_return_if_fail(win != NULL);
-
-	ops = gaim_conv_window_get_ui_ops(win);
-
-	if (ops == NULL || ops->raise == NULL)
-		return;
-
-	ops->raise(win);
-}
-
-gboolean
-gaim_conv_window_has_focus(GaimConvWindow *win)
-{
-	gboolean ret = FALSE;
-	GaimConvWindowUiOps *ops;
-
-	g_return_val_if_fail(win != NULL, FALSE);
-
-	ops = gaim_conv_window_get_ui_ops(win);
-
-	if (ops != NULL && ops->has_focus != NULL)
-		ret = ops->has_focus(win);
-
-	return ret;
-}
-
-void
-gaim_conv_window_set_ui_ops(GaimConvWindow *win, GaimConvWindowUiOps *ops)
-{
-	GaimConversationUiOps *conv_ops = NULL;
-	GList *l;
-
-	g_return_if_fail(win != NULL);
-
-	if (win->ui_ops == ops)
-		return;
-
-	if (ops != NULL && ops->get_conversation_ui_ops != NULL)
-		conv_ops = ops->get_conversation_ui_ops();
-
-	if (win->ui_ops != NULL && win->ui_ops->destroy_window != NULL)
-		win->ui_ops->destroy_window(win);
-
-	win->ui_ops = ops;
-
-	if (win->ui_ops != NULL && win->ui_ops->new_window != NULL)
-		win->ui_ops->new_window(win);
-
-	for (l = gaim_conv_window_get_conversations(win);
-		 l != NULL;
-		 l = l->next) {
-
-		GaimConversation *conv = (GaimConversation *)l;
-
-		gaim_conversation_set_ui_ops(conv, conv_ops);
-
-		if (win->ui_ops != NULL && win->ui_ops->add_conversation != NULL)
-			win->ui_ops->add_conversation(win, conv);
-	}
-}
-
-GaimConvWindowUiOps *
-gaim_conv_window_get_ui_ops(const GaimConvWindow *win)
-{
-	g_return_val_if_fail(win != NULL, NULL);
-
-	return win->ui_ops;
-}
-
-int
-gaim_conv_window_add_conversation(GaimConvWindow *win, GaimConversation *conv)
-{
-	GaimConvWindowUiOps *ops;
-
-	g_return_val_if_fail(win  != NULL, -1);
-	g_return_val_if_fail(conv != NULL, -1);
-
-	if (gaim_conversation_get_window(conv) != NULL) {
-		gaim_conv_window_remove_conversation(
-			gaim_conversation_get_window(conv),
-			conv);
-	}
-
-	ops = gaim_conv_window_get_ui_ops(win);
-
-	win->conversations = g_list_append(win->conversations, conv);
-	win->conversation_count++;
-
-	if (ops != NULL) {
-		conv->window = win;
-
-		if (ops->get_conversation_ui_ops != NULL)
-			gaim_conversation_set_ui_ops(conv, ops->get_conversation_ui_ops());
-
-		if (ops->add_conversation != NULL)
-			ops->add_conversation(win, conv);
-	}
-
-	return win->conversation_count - 1;
-}
-
-GaimConversation *
-gaim_conv_window_remove_conversation(GaimConvWindow *win, GaimConversation *conv)
-{
-	GaimConvWindowUiOps *ops;
-	GList *node;
-
-	g_return_val_if_fail(win != NULL, NULL);
-	g_return_val_if_fail(conv != NULL, NULL);
-
-	ops = gaim_conv_window_get_ui_ops(win);
-
-	node = g_list_find(gaim_conv_window_get_conversations(win), conv);
-
-	if (!node)
-		return NULL;
-	
-	if (ops != NULL && ops->remove_conversation != NULL)
-		ops->remove_conversation(win, conv);
-
-	win->conversations = g_list_remove_link(win->conversations, node);
-
-	g_list_free_1(node);
-
-	win->conversation_count--;
-
-	conv->window = NULL;
-
-	if (gaim_conv_window_get_conversation_count(win) == 0)
-		gaim_conv_window_destroy(win);
-
-	return conv;
-}
-
-size_t
-gaim_conv_window_get_conversation_count(const GaimConvWindow *win)
-{
-	g_return_val_if_fail(win != NULL, 0);
-
-	return win->conversation_count;
-}
-
-void
-gaim_conv_window_switch_conversation(GaimConvWindow *win, GaimConversation *conv)
-{
-	GaimConvWindowUiOps *ops;
-	GaimConversation *old_conv;
-
-	g_return_if_fail(win != NULL);
-	g_return_if_fail(conv != NULL);
-
-	old_conv = gaim_conv_window_get_active_conversation(win);
-
-	gaim_signal_emit(gaim_conversations_get_handle(),
-					 "conversation-switching", old_conv, conv);
-
-	ops = gaim_conv_window_get_ui_ops(win);
-
-	if (ops != NULL && ops->switch_conversation != NULL)
-		ops->switch_conversation(win, conv);
-
-	gaim_signal_emit(gaim_conversations_get_handle(),
-					 "conversation-switched", old_conv, conv);
-}
-
-GaimConversation *
-gaim_conv_window_get_active_conversation(const GaimConvWindow *win)
-{
-	GaimConvWindowUiOps *ops;
-
-	g_return_val_if_fail(win != NULL, NULL);
-
-	if (gaim_conv_window_get_conversation_count(win) == 0)
-		return NULL;
-
-	ops = gaim_conv_window_get_ui_ops(win);
-
-	if (ops != NULL && ops->get_active_conversation != NULL)
-		return ops->get_active_conversation(win);
-
-	return NULL;
-}
-
-GList *
-gaim_conv_window_get_conversations(const GaimConvWindow *win)
-{
-	g_return_val_if_fail(win != NULL, NULL);
-
-	return win->conversations;
-}
-
-GList *
-gaim_get_windows(void)
-{
-	return windows;
-}
-
-GaimConvWindow *
-gaim_get_first_window_with_type(GaimConversationType type)
-{
-	GList *wins, *convs;
-	GaimConvWindow *win;
-	GaimConversation *conv;
-
-	if (type == GAIM_CONV_TYPE_UNKNOWN)
-		return NULL;
-
-	for (wins = gaim_get_windows(); wins != NULL; wins = wins->next) {
-		win = (GaimConvWindow *)wins->data;
-
-		for (convs = gaim_conv_window_get_conversations(win);
-			 convs != NULL;
-			 convs = convs->next) {
-
-			conv = (GaimConversation *)convs->data;
-
-			if (gaim_conversation_get_type(conv) == type)
-				return win;
-		}
-	}
-
-	return NULL;
-}
-
-GaimConvWindow *
-gaim_get_last_window_with_type(GaimConversationType type)
-{
-	GList *wins, *convs;
-	GaimConvWindow *win;
-	GaimConversation *conv;
-
-	if (type == GAIM_CONV_TYPE_UNKNOWN)
-		return NULL;
-
-	for (wins = g_list_last(gaim_get_windows());
-		 wins != NULL;
-		 wins = wins->prev) {
-
-		win = (GaimConvWindow *)wins->data;
-
-		for (convs = gaim_conv_window_get_conversations(win);
-			 convs != NULL;
-			 convs = convs->next) {
-
-			conv = (GaimConversation *)convs->data;
-
-			if (gaim_conversation_get_type(conv) == type)
-				return win;
-		}
-	}
-
-	return NULL;
-}
-
 /**************************************************************************
  * Conversation API
  **************************************************************************/
@@ -630,6 +269,7 @@
 {
 	GaimConversation *conv;
 	GaimConnection *gc;
+	GaimConversationUiOps *ops;
 
 	g_return_val_if_fail(type    != GAIM_CONV_TYPE_UNKNOWN, NULL);
 	g_return_val_if_fail(account != NULL, NULL);
@@ -666,7 +306,10 @@
 									  conv, time(NULL)));
 	/* copy features from the connection. */
 	conv->features = gc->flags;
-	
+
+	ops  = conv->ui_ops = default_ops;
+	if (ops != NULL && ops->create_conversation != NULL)
+		ops->create_conversation(conv);
 
 	if (type == GAIM_CONV_TYPE_IM)
 	{
@@ -707,39 +350,6 @@
 	/* Auto-set the title. */
 	gaim_conversation_autoset_title(conv);
 
-	/*
-	 * Place the conversation somewhere.  If there are no conversation
-	 * windows open, or if tabbed conversations are not enabled, then
-	 * place the conversation in a new window by itself.  Otherwise use
-	 * the chosen conversation placement function.
-	 */
-	if ((windows == NULL) || (!gaim_prefs_get_bool("/gaim/gtk/conversations/tabs")))
-	{
-		GaimConvWindow *win;
-
-		win = gaim_conv_window_new();
-
-		gaim_conv_window_add_conversation(win, conv);
-
-		/* Ensure the window is visible. */
-		gaim_conv_window_show(win);
-	}
-	else
-	{
-		if (place_conv == NULL)
-		{
-			ensure_default_funcs();
-
-			place_conv = conv_placement_last_created_win;
-		}
-
-		if (place_conv == NULL)
-			gaim_debug(GAIM_DEBUG_ERROR, "conversation",
-					   "This is about to suck.\n");
-
-		place_conv(conv);
-	}
-
 	gaim_signal_emit(gaim_conversations_get_handle(),
 					 "conversation-created", conv);
 
@@ -750,7 +360,6 @@
 gaim_conversation_destroy(GaimConversation *conv)
 {
 	GaimPluginProtocolInfo *prpl_info = NULL;
-	GaimConvWindow *win;
 	GaimConversationUiOps *ops;
 	GaimConnection *gc;
 	const char *name;
@@ -758,7 +367,6 @@
 
 	g_return_if_fail(conv != NULL);
 
-	win  = gaim_conversation_get_window(conv);
 	ops  = gaim_conversation_get_ui_ops(conv);
 	gc   = gaim_conversation_get_gc(conv);
 	name = gaim_conversation_get_name(conv);
@@ -899,10 +507,6 @@
 	g_hash_table_destroy(conv->data);
 	conv->data = NULL;
 
-	if (win != NULL) {
-		gaim_conv_window_remove_conversation(win, conv);
-	}
-
 	if (ops != NULL && ops->destroy_conversation != NULL)
 		ops->destroy_conversation(conv);
 
@@ -926,7 +530,7 @@
 
 	ops = conv->ui_ops;
 	if(ops && ops->updated)
-		ops->updated(conv, GAIM_CONV_UPDATE_FEATURES);	
+		ops->updated(conv, GAIM_CONV_UPDATE_FEATURES);
 }
 
 
@@ -1054,7 +658,7 @@
 		if(account && ((chat = gaim_blist_find_chat(account, name)) != NULL))
 			text = chat->alias;
 	}
-	
+
 
 	if(text == NULL)
 		text = name;
@@ -1142,14 +746,6 @@
 	return conv->send_history;
 }
 
-GaimConvWindow *
-gaim_conversation_get_window(const GaimConversation *conv)
-{
-	g_return_val_if_fail(conv != NULL, NULL);
-
-	return conv->window;
-}
-
 GaimConvIm *
 gaim_conversation_get_im_data(const GaimConversation *conv)
 {
@@ -1253,7 +849,6 @@
 	GaimAccount *account;
 	GaimConversationUiOps *ops;
 	const char *alias;
-	GaimConvWindow *win;
 	GaimBuddy *b;
 	GaimUnseenState unseen;
 	/* int logging_font_options = 0; */
@@ -1322,7 +917,6 @@
 	}
 	ops->write_conv(conv, who, alias, message, flags, mtime);
 
-	win = gaim_conversation_get_window(conv);
 
 	/* Tab highlighting */
 	if (!(flags & GAIM_MESSAGE_RECV) && !(flags & GAIM_MESSAGE_SYSTEM) && !(flags & GAIM_MESSAGE_ERROR))
@@ -1333,12 +927,6 @@
 			gaim_conv_im_set_typing_state(GAIM_CONV_IM(conv), GAIM_NOT_TYPING);
 	}
 
-	if (gaim_conv_window_has_focus(win) &&
-		gaim_conv_window_get_active_conversation(win) == conv)
-	{
-		unseen = GAIM_UNSEEN_NONE;
-	}
-	else
 	{
 		if ((flags & GAIM_MESSAGE_NICK) == GAIM_MESSAGE_NICK ||
 				gaim_conversation_get_unseen(conv) == GAIM_UNSEEN_NICK)
@@ -1352,66 +940,16 @@
 	}
 
 	gaim_conversation_set_unseen(conv, unseen);
-
-	/*
-	 * TODO: This is #if 0'ed out because we don't have a way of
-	 *       telling if a conversation window is minimized.  This
-	 *       should probably be done in gtkconv.c anyway.
-	 */
-#if 0
-	/*
-	 * This is auto-tab switching.
-	 *
-	 * If we received an IM, and the GaimConvWindow is not active,
-	 * then make this conversation the active tab in this GaimConvWindow.
-	 *
-	 * We do this so that, when the user comes back to the conversation
-	 * window, the first thing they'll see is the new message.  This is
-	 * especially important when the IM window is flashing in their
-	 * taskbar--we want the title of the window to be set to the name
-	 * of the person that IMed them most recently.
-	 */
-	if ((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) &&
-		(flags & (GAIM_MESSAGE_RECV | GAIM_MESSAGE_ERROR)) &&
-		(!gaim_conv_window_has_focus(win)) &&
-		(gaim_conv_window_is_minimized(win)))
-	{
-		gaim_conv_window_switch_conversation(win, conv);
-	}
-#endif
-}
-
-void
-gaim_conversation_update_progress(GaimConversation *conv, float percent)
-{
-	GaimConversationUiOps *ops;
-
-	g_return_if_fail(conv != NULL);
-	g_return_if_fail(percent >= 0 && percent <= 1);
-
-	/*
-	 * NOTE: A percent == 1 indicates that the progress bar should be
-	 *       closed.
-	 */
-	ops = gaim_conversation_get_ui_ops(conv);
-
-	if (ops != NULL && ops->update_progress != NULL)
-		ops->update_progress(conv, percent);
 }
 
 gboolean
 gaim_conversation_has_focus(GaimConversation *conv)
 {
 	gboolean ret = FALSE;
-	GaimConvWindow *win;
 	GaimConversationUiOps *ops;
 
 	g_return_val_if_fail(conv != NULL, FALSE);
 
-	win = gaim_conversation_get_window(conv);
-	if (gaim_conv_window_get_active_conversation(win) != conv)
-		return FALSE;
-
 	ops = gaim_conversation_get_ui_ops(conv);
 
 	if (ops != NULL && ops->has_focus != NULL)
@@ -1606,7 +1144,6 @@
 gboolean gaim_conv_present_error(const char *who, GaimAccount *account, const char *what)
 {
 	GaimConversation *conv;
-	GaimConvWindow *window;
 
 	g_return_val_if_fail(who != NULL, FALSE);
 	g_return_val_if_fail(account !=NULL, FALSE);
@@ -1617,17 +1154,6 @@
 		gaim_conversation_write(conv, NULL, what, GAIM_MESSAGE_ERROR, time(NULL));
 	else
 		return FALSE;
-	window = gaim_conversation_get_window(conv);
-
-	/*
-	 * Change the active conversation to this conversation unless the
-	 * user is already using this window.
-	 * TODO: There's a good chance this is no longer necessary
-	 */
-	if (!gaim_conv_window_has_focus(window))
-		gaim_conv_window_switch_conversation(window, conv);
-
-	gaim_conv_window_raise(window);
 
 	return TRUE;
 }
@@ -1914,7 +1440,7 @@
 	GList *users = g_list_append(NULL, (char *)user);
 	GList *extra_msgs = g_list_append(NULL, (char *)extra_msg);
 	GList *flags2 = g_list_append(NULL, GINT_TO_POINTER(flags));
-	
+
 	gaim_conv_chat_add_users(chat, users, extra_msgs, flags2, new_arrival);
 
 	g_list_free(users);
@@ -2087,10 +1613,10 @@
 		} else {
 			const char *old_alias = old_user;
 			const char *new_alias = new_user;
-		
+
 			if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
 				GaimBuddy *buddy;
-	
+
 				if ((buddy = gaim_find_buddy(gc->account, old_user)) != NULL)
 					old_alias = gaim_buddy_get_contact_alias(buddy);
 				if ((buddy = gaim_find_buddy(gc->account, new_user)) != NULL)
@@ -2443,321 +1969,6 @@
 	return cb->name;
 }
 
-/**************************************************************************
- * Conversation placement functions
- **************************************************************************/
-/* This one places conversations in the last made window. */
-static void
-conv_placement_last_created_win(GaimConversation *conv)
-{
-	GaimConvWindow *win;
-
-	win = g_list_last(gaim_get_windows())->data;
-
-	if (win == NULL) {
-		win = gaim_conv_window_new();
-
-		gaim_conv_window_add_conversation(win, conv);
-		gaim_conv_window_show(win);
-	}
-	else
-		gaim_conv_window_add_conversation(win, conv);
-}
-
-/* This one places conversations in the last made window of the same type. */
-static void
-conv_placement_last_created_win_type(GaimConversation *conv)
-{
-	GaimConvWindow *win;
-
-	win = gaim_get_last_window_with_type(gaim_conversation_get_type(conv));
-
-	if (win == NULL) {
-		win = gaim_conv_window_new();
-
-		gaim_conv_window_add_conversation(win, conv);
-		gaim_conv_window_show(win);
-	}
-	else
-		gaim_conv_window_add_conversation(win, conv);
-}
-
-/* This one places each conversation in its own window. */
-static void
-conv_placement_new_window(GaimConversation *conv)
-{
-	GaimConvWindow *win;
-
-	win = gaim_conv_window_new();
-
-	gaim_conv_window_add_conversation(win, conv);
-
-	gaim_conv_window_show(win);
-}
-
-static GaimGroup *
-conv_get_group(GaimConversation *conv)
-{
-	GaimGroup *group = NULL;
-
-	if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
-	{
-		GaimBuddy *buddy;
-
-		buddy = gaim_find_buddy(gaim_conversation_get_account(conv),
-								gaim_conversation_get_name(conv));
-
-		if (buddy != NULL)
-			group = gaim_find_buddys_group(buddy);
-
-	}
-	else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)
-	{
-		GaimChat *chat;
-
-		chat = gaim_blist_find_chat(gaim_conversation_get_account(conv),
-									gaim_conversation_get_name(conv));
-
-		if (chat != NULL)
-			group = gaim_chat_get_group(chat);
-	}
-
-	return group;
-}
-
-/*
- * This groups things by, well, group. Buddies from groups will always be
- * grouped together, and a buddy from a group not belonging to any currently
- * open windows will get a new window.
- */
-static void
-conv_placement_by_group(GaimConversation *conv)
-{
-	GaimConversationType type;
-	GaimGroup *group = NULL;
-	GList *wl, *cl;
-
-	type = gaim_conversation_get_type(conv);
-
-	group = conv_get_group(conv);
-
-	/* Go through the list of IMs and find one with this group. */
-	for (wl = gaim_get_windows(); wl != NULL; wl = wl->next)
-	{
-		GaimConvWindow *win2;
-		GaimConversation *conv2;
-		GaimGroup *group2 = NULL;
-
-		win2 = (GaimConvWindow *)wl->data;
-
-		for (cl = gaim_conv_window_get_conversations(win2);
-			 cl != NULL;
-			 cl = cl->next)
-		{
-			conv2 = (GaimConversation *)cl->data;
-
-			group2 = conv_get_group(conv2);
-
-			if (group == group2)
-			{
-				gaim_conv_window_add_conversation(win2, conv);
-
-				return;
-			}
-		}
-	}
-
-	/* Make a new window. */
-	conv_placement_new_window(conv);
-}
-
-/* This groups things by account.  Otherwise, the same semantics as above */
-static void
-conv_placement_by_account(GaimConversation *conv)
-{
-	GaimConversationType type;
-	GList *wins, *convs;
-	GaimAccount *account;
-
-	account = gaim_conversation_get_account(conv);
-	type = gaim_conversation_get_type(conv);
-
-	/* Go through the list of IMs and find one with this group. */
-	for (wins = gaim_get_windows(); wins != NULL; wins = wins->next)
-	{
-		GaimConvWindow *win2;
-		GaimConversation *conv2;
-
-		win2 = (GaimConvWindow *)wins->data;
-
-		for (convs = gaim_conv_window_get_conversations(win2);
-			 convs != NULL;
-			 convs = convs->next)
-		{
-			conv2 = (GaimConversation *)convs->data;
-
-			if (account == gaim_conversation_get_account(conv2))
-			{
-				gaim_conv_window_add_conversation(win2, conv);
-				return;
-			}
-		}
-	}
-
-	/* Make a new window. */
-	conv_placement_new_window(conv);
-}
-
-static ConvPlacementData *
-get_conv_placement_data(const char *id)
-{
-	ConvPlacementData *data = NULL;
-	GList *n;
-
-	for(n = conv_placement_fncs; n; n = n->next) {
-		data = n->data;
-		if(!strcmp(data->id, id))
-			return data;
-	}
-
-	return NULL;
-}
-
-static void
-add_conv_placement_fnc(const char *id, const char *name,
-					   GaimConvPlacementFunc fnc)
-{
-	ConvPlacementData *data;
-
-	data = g_new(ConvPlacementData, 1);
-
-	data->id = g_strdup(id);
-	data->name = g_strdup(name);
-	data->fnc  = fnc;
-
-	conv_placement_fncs = g_list_append(conv_placement_fncs, data);
-}
-
-static void
-ensure_default_funcs(void)
-{
-	if (conv_placement_fncs == NULL)
-	{
-		add_conv_placement_fnc("last", _("Last created window"),
-							   conv_placement_last_created_win);
-		add_conv_placement_fnc("im_chat", _("Separate IM and Chat windows"),
-							   conv_placement_last_created_win_type);
-		add_conv_placement_fnc("new", _("New window"),
-							   conv_placement_new_window);
-		add_conv_placement_fnc("group", _("By group"),
-							   conv_placement_by_group);
-		add_conv_placement_fnc("account", _("By account"),
-							   conv_placement_by_account);
-	}
-}
-
-GList *
-gaim_conv_placement_get_options(void)
-{
-	GList *n, *list = NULL;
-	ConvPlacementData *data;
-
-	ensure_default_funcs();
-
-	for (n = conv_placement_fncs; n; n = n->next) {
-		data = n->data;
-		list = g_list_append(list, data->name);
-		list = g_list_append(list, data->id);
-	}
-
-	return list;
-}
-
-
-void
-gaim_conv_placement_add_fnc(const char *id, const char *name,
-							GaimConvPlacementFunc fnc)
-{
-	g_return_if_fail(id   != NULL);
-	g_return_if_fail(name != NULL);
-	g_return_if_fail(fnc  != NULL);
-
-	ensure_default_funcs();
-
-	add_conv_placement_fnc(id, name, fnc);
-}
-
-void
-gaim_conv_placement_remove_fnc(const char *id)
-{
-	ConvPlacementData *data = get_conv_placement_data(id);
-
-	if (data == NULL)
-		return;
-
-	conv_placement_fncs = g_list_remove(conv_placement_fncs, data);
-
-	g_free(data->id);
-	g_free(data->name);
-	g_free(data);
-}
-
-const char *
-gaim_conv_placement_get_name(const char *id)
-{
-	ConvPlacementData *data;
-
-	ensure_default_funcs();
-
-	data = get_conv_placement_data(id);
-
-	if (data == NULL)
-		return NULL;
-
-	return data->name;
-}
-
-GaimConvPlacementFunc
-gaim_conv_placement_get_fnc(const char *id)
-{
-	ConvPlacementData *data;
-
-	ensure_default_funcs();
-
-	data = get_conv_placement_data(id);
-
-	if (data == NULL)
-		return NULL;
-
-	return data->fnc;
-}
-
-void
-gaim_conv_placement_set_current_func(GaimConvPlacementFunc func)
-{
-	g_return_if_fail(func != NULL);
-
-	place_conv = func;
-}
-
-GaimConvPlacementFunc
-gaim_conv_placement_get_current_func(void)
-{
-	return place_conv;
-}
-
-void
-gaim_conversations_set_win_ui_ops(GaimConvWindowUiOps *ops)
-{
-	win_ui_ops = ops;
-}
-
-GaimConvWindowUiOps *
-gaim_conversations_get_win_ui_ops(void)
-{
-	return win_ui_ops;
-}
-
 void *
 gaim_conversations_get_handle(void)
 {
--- a/src/conversation.h	Fri Sep 30 05:07:03 2005 +0000
+++ b/src/conversation.h	Sun Oct 02 00:32:49 2005 +0000
@@ -31,8 +31,7 @@
 /** Data Structures                                                       */
 /**************************************************************************/
 
-typedef struct _GaimConvWindowUiOps   GaimConvWindowUiOps;
-typedef struct _GaimConvWindow        GaimConvWindow;
+
 typedef struct _GaimConversationUiOps GaimConversationUiOps;
 typedef struct _GaimConversation      GaimConversation;
 typedef struct _GaimConvIm            GaimConvIm;
@@ -135,7 +134,7 @@
 	GAIM_CBFLAGS_OP            = 0x0004, /**< Channel Op or Moderator      */
 	GAIM_CBFLAGS_FOUNDER       = 0x0008, /**< Channel Founder              */
 	GAIM_CBFLAGS_TYPING        = 0x0010, /**< Currently typing             */
-	
+
 
 } GaimConvChatBuddyFlags;
 
@@ -145,31 +144,6 @@
 #include "server.h"
 
 /**
- * Conversation window operations.
- *
- * Any UI representing a window must assign a filled-out gaim_conv_window_ops
- * structure to the GaimConvWindow.
- */
-struct _GaimConvWindowUiOps
-{
-	GaimConversationUiOps *(*get_conversation_ui_ops)(void);
-
-	void (*new_window)(GaimConvWindow *win);
-	void (*destroy_window)(GaimConvWindow *win);
-
-	void (*show)(GaimConvWindow *win);
-	void (*hide)(GaimConvWindow *win);
-	void (*raise)(GaimConvWindow *win);
-
-	void (*switch_conversation)(GaimConvWindow *win, GaimConversation *conv);
-	void (*add_conversation)(GaimConvWindow *win, GaimConversation *conv);
-	void (*remove_conversation)(GaimConvWindow *win, GaimConversation *conv);
-
-	GaimConversation *(*get_active_conversation)(const GaimConvWindow *win);
-	gboolean (*has_focus)(GaimConvWindow *win);
-};
-
-/**
  * Conversation operations and events.
  *
  * Any UI representing a conversation must assign a filled-out
@@ -177,6 +151,7 @@
  */
 struct _GaimConversationUiOps
 {
+	void (*create_conversation)(GaimConversation *conv);
 	void (*destroy_conversation)(GaimConversation *conv);
 	void (*write_chat)(GaimConversation *conv, const char *who,
 	                   const char *message, GaimMessageFlags flags,
@@ -195,7 +170,6 @@
 	void (*chat_remove_users)(GaimConversation *conv, GList *users);
 	void (*chat_update_user)(GaimConversation *conv, const char *user);
 
-	void (*update_progress)(GaimConversation *conv, float percent);
 
 	gboolean (*has_focus)(GaimConversation *conv);
 
@@ -211,19 +185,6 @@
 };
 
 /**
- * A core representation of a graphical window containing one or more
- * conversations.
- */
-struct _GaimConvWindow
-{
-	GList *conversations;              /**< The conversations in the window. */
-	size_t conversation_count;         /**< The number of conversations.     */
-
-	GaimConvWindowUiOps *ui_ops;       /**< UI-specific window operations.   */
-	void *ui_data;                     /**< UI-specific data.                */
-};
-
-/**
  * Data specific to Instant Messages.
  */
 struct _GaimConvIm
@@ -267,17 +228,14 @@
 /**
  * A core representation of a conversation between two or more people.
  *
- * The conversation can be an IM or a chat. Each conversation is kept
- * in a GaimConvWindow and has a UI representation.
+ * The conversation can be an IM or a chat.
  */
 struct _GaimConversation
 {
 	GaimConversationType type;  /**< The type of conversation.          */
 
 	GaimAccount *account;       /**< The user using this conversation.  */
-	GaimConvWindow *window;     /**< The parent window.                 */
 
-	int conversation_pos;       /**< The position in the window's list. */
 
 	char *name;                 /**< The name of the conversation.      */
 	char *title;                /**< The window title.                  */
@@ -307,170 +265,11 @@
 
 };
 
-typedef void (*GaimConvPlacementFunc)(GaimConversation *);
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**************************************************************************/
-/** @name Conversation Window API                                         */
-/**************************************************************************/
-/*@{*/
-
-/**
- * Creates a new conversation window.
- *
- * This window is added to the list of windows, but is not shown until
- * gaim_conv_window_show() is called.
- *
- * @return The new conversation window.
- */
-GaimConvWindow *gaim_conv_window_new(void);
-
-/**
- * Destroys the specified conversation window and all conversations in it.
- *
- * @param win The window to destroy.
- */
-void gaim_conv_window_destroy(GaimConvWindow *win);
-
-/**
- * Shows the specified conversation window.
- *
- * @param win The window.
- */
-void gaim_conv_window_show(GaimConvWindow *win);
-
-/**
- * Hides the specified conversation window.
- *
- * @param win The window.
- */
-void gaim_conv_window_hide(GaimConvWindow *win);
-
-/**
- * Raises the specified conversation window.
- *
- * @param win The window.
- */
-void gaim_conv_window_raise(GaimConvWindow *win);
-
-/**
- * Sets the specified window's UI window operations structure.
- *
- * @param win The window.
- * @param ops The UI window operations structure.
- */
-void gaim_conv_window_set_ui_ops(GaimConvWindow *win,
-                                 GaimConvWindowUiOps *ops);
-
-/**
- * Returns the specified window's UI window operations structure.
- *
- * @param win The window.
- *
- * @return The UI window operations structure.
- */
-GaimConvWindowUiOps *gaim_conv_window_get_ui_ops(const GaimConvWindow *win);
-
-/**
- * Adds a conversation to this window.
- *
- * If the conversation already has a parent window, this will do nothing.
- *
- * @param win  The window.
- * @param conv The conversation.
- *
- * @return The new index of the conversation in the window.
- */
-int gaim_conv_window_add_conversation(GaimConvWindow *win,
-                                      GaimConversation *conv);
-
-/**
- * Removes the conversation from the window.
- *
- * @param win   The window.
- * @param conv The conversation.
- *
- * @return The conversation removed.
- */
-GaimConversation *gaim_conv_window_remove_conversation(GaimConvWindow *win,
-                                                       GaimConversation *conv);
-/**
- * Returns the number of conversations in the window.
- *
- * @param win The window.
- *
- * @return The number of conversations.
- */
-size_t gaim_conv_window_get_conversation_count(const GaimConvWindow *win);
-
-/**
- * Switches the active conversation to the one at the specified index.
- *
- * @param win  The window.
- * @param conv The converstion to switch to.
- */
-void gaim_conv_window_switch_conversation(GaimConvWindow *win,
-                                          GaimConversation *conv);
-
-/**
- * Returns the active conversation in the window.
- *
- * @param win The window.
- *
- * @return The active conversation.
- */
-GaimConversation *gaim_conv_window_get_active_conversation(
-		const GaimConvWindow *win);
-
-/**
- * Determines if a conversation window has focus
- *
- * @param win The window.
- *
- * @return @c TRUE if the conversation window has focus, @c FALSE if
- * it does not or the UI does not have a concept of window focus
- */
-gboolean gaim_conv_window_has_focus(GaimConvWindow *win);
-
-/**
- * Returns the list of conversations in the specified window.
- *
- * @param win The window.
- *
- * @return The list of conversations.
- */
-GList *gaim_conv_window_get_conversations(const GaimConvWindow *win);
-
-/**
- * Returns a list of all windows.
- *
- * @return A list of windows.
- */
-GList *gaim_get_windows(void);
-
-/**
- * Returns the first window containing a conversation of the specified type.
- *
- * @param type The conversation type.
- *
- * @return The window if found, or @c NULL if not found.
- */
-GaimConvWindow *gaim_get_first_window_with_type(GaimConversationType type);
-/**
- * Returns the last window containing a conversation of the specified type.
- *
- * @param type The conversation type.
- *
- * @return The window if found, or @c NULL if not found.
- */
-GaimConvWindow *gaim_get_last_window_with_type(GaimConversationType type);
-
-/*@}*/
-
-/**************************************************************************/
 /** @name Conversation API                                                */
 /**************************************************************************/
 /*@{*/
@@ -519,6 +318,13 @@
 								  GaimConversationUiOps *ops);
 
 /**
+ * Sets the default conversation UI operations structure.
+ *
+ * @param ops  The UI conversation operations structure.
+ */
+void gaim_conversations_set_ui_ops(GaimConversationUiOps *ops);
+
+/**
  * Returns the specified conversation's UI operations structure.
  *
  * @param conv The conversation.
@@ -652,15 +458,6 @@
 GList *gaim_conversation_get_send_history(const GaimConversation *conv);
 
 /**
- * Returns the specified conversation's parent window.
- *
- * @param conv The conversation.
- *
- * @return The conversation's parent window.
- */
-GaimConvWindow *gaim_conversation_get_window(const GaimConversation *conv);
-
-/**
  * Returns the specified conversation's IM-specific data.
  *
  * If the conversation type is not GAIM_CONV_TYPE_IM, this will return @c NULL.
@@ -780,19 +577,7 @@
 	Get the features supported by the given conversation.
 	@param conv  The conversation
 */
-GaimConnectionFlags gaim_conversation_get_features(GaimConversation *conv);		    
-
-
-/**
- * Updates the progress bar on a conversation window
- * (if one exists in the UI).
- *
- * This is used for loading images typically.
- *
- * @param conv    The conversation.
- * @param percent The percentage.
- */
-void gaim_conversation_update_progress(GaimConversation *conv, float percent);
+GaimConnectionFlags gaim_conversation_get_features(GaimConversation *conv);
 
 /**
  * Determines if a conversation has focus
@@ -961,7 +746,7 @@
 
 /**
  * Presents an IM-error to the user
- * 
+ *
  * This is a helper function to find a conversation, write an error to it, and
  * raise the window.  If a conversation with this user doesn't already exist,
  * the function will return FALSE and the calling function can attempt to present
@@ -1375,97 +1160,6 @@
 /*@}*/
 
 /**************************************************************************/
-/** @name Conversation Placement API                                      */
-/**************************************************************************/
-/*@{*/
-
-/**
- * Returns a GList containing the IDs and Names of the registered placement
- * functions.
- *
- * @return The list of IDs and names.
- */
-GList *gaim_conv_placement_get_options(void);
-
-/**
- * Adds a conversation placement function to the list of possible functions.
- *
- * @param id   The unique ID of the placement function.
- * @param name The name of the function.
- * @param fnc  A pointer to the function.
- */
-void gaim_conv_placement_add_fnc(const char *id, const char *name,
-								 GaimConvPlacementFunc fnc);
-
-/**
- * Removes a conversation placement function from the list of possible
- * functions.
- *
- * @param id The id of the function.
- */
-void gaim_conv_placement_remove_fnc(const char *id);
-
-/**
- * Returns the name of the conversation placement function at the
- * specified id.
- *
- * @param id The id.
- *
- * @return The name of the function, or @c NULL if this id is invalid.
- */
-const char *gaim_conv_placement_get_name(const char *id);
-
-/**
- * Returns a pointer to the conversation placement function at the
- * specified id.
- *
- * @param id The id.
- *
- * @return A pointer to the function.
- */
-GaimConvPlacementFunc gaim_conv_placement_get_fnc(const char *id);
-
-/**
- * Sets the current conversation placement function.
- *
- * @param func The new conversation placement function.
- */
-void gaim_conv_placement_set_current_func(GaimConvPlacementFunc func);
-
-/**
- * Returns the current conversation placement function.
- *
- * @return The current conversation placement function.
- */
-GaimConvPlacementFunc gaim_conv_placement_get_current_func(void);
-
-/*@}*/
-
-/**************************************************************************/
-/** @name UI Registration Functions                                       */
-/**************************************************************************/
-/*@{*/
-
-/**
- * Sets the UI operations structure to be used in all gaim conversation
- * windows.
- *
- * @param ops The UI operations structure.
- */
-void gaim_conversations_set_win_ui_ops(GaimConvWindowUiOps *ops);
-
-/**
- * Returns the gaim window UI operations structure to be used in
- * new windows.
- *
- * @return A filled-out GaimConvWindowUiOps structure.
- */
-GaimConvWindowUiOps *gaim_conversations_get_win_ui_ops(void);
-
-
-/*@}*/
-
-/**************************************************************************/
 /** @name Conversations Subsystem                                         */
 /**************************************************************************/
 /*@{*/
--- a/src/gtkconv.c	Fri Sep 30 05:07:03 2005 +0000
+++ b/src/gtkconv.c	Sun Oct 02 00:32:49 2005 +0000
@@ -52,6 +52,7 @@
 #include "gtkdnd-hints.h"
 #include "gtkblist.h"
 #include "gtkconv.h"
+#include "gtkconvwin.c"
 #include "gtkdialogs.h"
 #include "gtkimhtml.h"
 #include "gtkimhtmltoolbar.h"
@@ -100,8 +101,7 @@
 
 #define NUM_NICK_COLORS (sizeof(nick_colors) / sizeof(*nick_colors))
 
-typedef struct
-{
+typedef struct {
 	GtkWidget *window;
 
 	GtkWidget *entry;
@@ -114,6 +114,11 @@
 static GtkWidget *invite_dialog = NULL;
 static GtkWidget *warn_close_dialog = NULL;
 
+static gboolean update_send_as_selection(GaimGtkWindow *win);
+static void generate_send_as_items(GaimGtkWindow *win, GaimConversation *deleted_conv);
+
+
+
 /* Prototypes. <-- because Paco-Paco hates this comment. */
 static void got_typing_keypress(GaimGtkConversation *gtkconv, gboolean first);
 static GList *generate_invite_user_names(GaimConnection *gc);
@@ -121,7 +126,6 @@
 								  const char *alias, const char *old_name);
 static gboolean tab_complete(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);
 
 static GdkColor *get_nick_color(GaimGtkConversation *gtkconv, const char *name) {
@@ -143,116 +147,9 @@
 	return &col;
 }
 
-static void
-do_close(GtkWidget *w, int resp, GaimConvWindow *win)
-{
-	gtk_widget_destroy(warn_close_dialog);
-	warn_close_dialog = NULL;
-
-	if (resp == GTK_RESPONSE_OK)
-		gaim_conv_window_destroy(win);
-}
-
-static void build_warn_close_dialog(GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin;
-	GtkWidget *label;
-	GtkWidget *vbox, *hbox;
-	GtkWidget *img;
-
-	g_return_if_fail(warn_close_dialog == NULL);
-
-	gtkwin = GAIM_GTK_WINDOW(win);
-
-	warn_close_dialog = gtk_dialog_new_with_buttons(
-		_("Confirm close"),
-		GTK_WINDOW(gtkwin->window), GTK_DIALOG_MODAL,
-		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-		GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL);
-
-	gtk_dialog_set_default_response(GTK_DIALOG(warn_close_dialog),
-					GTK_RESPONSE_OK);
-
-	gtk_container_set_border_width(GTK_CONTAINER(warn_close_dialog),
-				       6);
-	gtk_window_set_resizable(GTK_WINDOW(warn_close_dialog), FALSE);
-	gtk_dialog_set_has_separator(GTK_DIALOG(warn_close_dialog),
-				     FALSE);
-
-	/* Setup the outside spacing. */
-	vbox = GTK_DIALOG(warn_close_dialog)->vbox;
-
-	gtk_box_set_spacing(GTK_BOX(vbox), 12);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
-
-	img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_WARNING,
-				       GTK_ICON_SIZE_DIALOG);
-	/* Setup the inner hbox and put the dialog's icon in it. */
-	hbox = gtk_hbox_new(FALSE, 12);
-	gtk_container_add(GTK_CONTAINER(vbox), hbox);
-	gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
-	gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
-
-	/* Setup the right vbox. */
-	vbox = gtk_vbox_new(FALSE, 12);
-	gtk_container_add(GTK_CONTAINER(hbox), vbox);
-
-	label = gtk_label_new(_("You have unread messages. Are you sure you want to close the window?"));
-	gtk_widget_set_size_request(label, 350, -1);
-	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
-	/* Connect the signals. */
-	g_signal_connect(G_OBJECT(warn_close_dialog), "response",
-			 G_CALLBACK(do_close), win);
-
-}
-
 /**************************************************************************
  * Callbacks
  **************************************************************************/
-static gboolean
-close_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d)
-{
-	GaimConvWindow *win = (GaimConvWindow *)d;
-	GList *l;
-
-	/* If there are unread messages then show a warning dialog */
-	for (l = gaim_conv_window_get_conversations(win);
-	     l != NULL; l = l->next)
-	{
-		GaimConversation *conv = l->data;
-		if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM &&
-		    gaim_conversation_get_unseen(conv) == GAIM_UNSEEN_TEXT)
-		{
-			build_warn_close_dialog(win);
-			gtk_widget_show_all(warn_close_dialog);
-
-			return TRUE;
-		}
-	}
-
-	gaim_conv_window_destroy(win);
-
-	return TRUE;
-}
-
-/*
- * When a conversation window is focused, we know the user
- * has looked at it so we know there are no longer unseen
- * messages.
- */
-static gint
-focus_win_cb(GtkWidget *w, GdkEventFocus *e, gpointer d)
-{
-	GaimConvWindow *win = (GaimConvWindow *)d;
-	GaimConversation *conv = gaim_conv_window_get_active_conversation(win);
-
-	gaim_conversation_set_unseen(conv, GAIM_UNSEEN_NONE);
-
-	return FALSE;
-}
 
 static gint
 close_conv_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
@@ -308,14 +205,6 @@
 	return FALSE;
 }
 
-/* Courtesy of Galeon! */
-static void
-tab_close_button_state_changed_cb(GtkWidget *widget, GtkStateType prev_state)
-{
-	if (GTK_WIDGET_STATE(widget) == GTK_STATE_ACTIVE)
-		gtk_widget_set_state(widget, GTK_STATE_NORMAL);
-}
-
 static void
 default_formatize(GaimGtkConversation *c)
 {
@@ -859,7 +748,6 @@
 
 	if (invite_dialog == NULL) {
 		GaimConnection *gc;
-		GaimConvWindow *win;
 		GaimGtkWindow *gtkwin;
 		GtkWidget *label;
 		GtkWidget *vbox, *hbox;
@@ -867,14 +755,13 @@
 		GtkWidget *img;
 
 		img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION,
-									   GTK_ICON_SIZE_DIALOG);
+		                               GTK_ICON_SIZE_DIALOG);
 
 		info = g_new0(InviteBuddyInfo, 1);
 		info->conv = conv;
 
-		gc     = gaim_conversation_get_gc(conv);
-		win    = gaim_conversation_get_window(conv);
-		gtkwin = GAIM_GTK_WINDOW(win);
+		gc        = gaim_conversation_get_gc(conv);
+		gtkwin    = gaim_gtkconv_get_window(gtkconv);
 
 		/* Create the new dialog. */
 		invite_dialog = gtk_dialog_new_with_buttons(
@@ -884,7 +771,7 @@
 			GAIM_STOCK_INVITE, GTK_RESPONSE_OK, NULL);
 
 		gtk_dialog_set_default_response(GTK_DIALOG(invite_dialog),
-										GTK_RESPONSE_OK);
+		                                GTK_RESPONSE_OK);
 		gtk_container_set_border_width(GTK_CONTAINER(invite_dialog), GAIM_HIG_BOX_SPACE);
 		gtk_window_set_resizable(GTK_WINDOW(invite_dialog), FALSE);
 		gtk_dialog_set_has_separator(GTK_DIALOG(invite_dialog), FALSE);
@@ -1030,8 +917,8 @@
 static void
 menu_save_as_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
-	GaimConversation *conv = gaim_conv_window_get_active_conversation(win);
+	GaimGtkWindow *win = data;
+	GaimConversation *conv = gaim_gtk_conv_window_get_active_conversation(win);
 	gchar *buf;
 
 	buf = g_strdup_printf("%s.html", gaim_normalize(conv->account, conv->name));
@@ -1045,14 +932,14 @@
 static void
 menu_view_log_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 	GaimLogType type;
 	const char *name;
 	GaimAccount *account;
 	GSList *buddies, *cur;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
 		type = GAIM_LOG_IM;
@@ -1083,11 +970,11 @@
 static void
 menu_clear_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 	GaimGtkConversation *gtkconv;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
 
 	gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
@@ -1119,9 +1006,8 @@
 static void
 menu_find_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
-	GaimConversation *conv = gaim_conv_window_get_active_conversation(win);
-	GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(win);
+	GaimGtkWindow *gtkwin = data;
+	GaimConversation *conv = gaim_gtk_conv_window_get_active_conversation(gtkwin);
 	GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv);
 	GtkWidget *hbox;
 	GtkWidget *img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION,
@@ -1181,8 +1067,8 @@
 static void
 menu_send_file_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
-	GaimConversation *conv = gaim_conv_window_get_active_conversation(win);
+	GaimGtkWindow *win = data;
+	GaimConversation *conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) {
 		serv_send_file(gaim_conversation_get_gc(conv), gaim_conversation_get_name(conv), NULL);
@@ -1193,25 +1079,23 @@
 static void
 menu_add_pounce_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_gtkconv(win)->active_conv;
 
 	gaim_gtkpounce_dialog_show(gaim_conversation_get_account(conv),
-							   gaim_conversation_get_name(conv), NULL);
+	                           gaim_conversation_get_name(conv), NULL);
 }
 
 static void
 menu_insert_link_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
-	GaimConversation *conv;
+	GaimGtkWindow *win = data;
 	GaimGtkConversation *gtkconv;
 	GtkIMHtmlToolbar *toolbar;
 
-	conv    = gaim_conv_window_get_active_conversation(win);
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
+	gtkconv    = gaim_gtk_conv_window_get_active_gtkconv(win);
 	toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar);
 
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->link),
@@ -1221,13 +1105,13 @@
 static void
 menu_insert_image_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 	GaimGtkConversation *gtkconv;
 	GtkIMHtmlToolbar *toolbar;
 
-	conv    = gaim_conv_window_get_active_conversation(win);
-	gtkconv = GAIM_GTK_CONVERSATION(gaim_conv_window_get_active_conversation(win));
+	gtkconv = gaim_gtk_conv_window_get_active_gtkconv(win);
+	conv    = gtkconv->active_conv;
 	toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar);
 
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->image),
@@ -1237,12 +1121,12 @@
 static void
 menu_alias_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 	GaimAccount *account;
 	const char *name;
 
-	conv    = gaim_conv_window_get_active_conversation(win);
+	conv    = gaim_gtk_conv_window_get_active_conversation(win);
 	account = gaim_conversation_get_account(conv);
 	name    = gaim_conversation_get_name(conv);
 
@@ -1264,10 +1148,10 @@
 static void
 menu_get_info_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	info_cb(NULL, GAIM_GTK_CONVERSATION(conv));
 }
@@ -1275,10 +1159,10 @@
 static void
 menu_invite_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	invite_cb(NULL, GAIM_GTK_CONVERSATION(conv));
 }
@@ -1286,10 +1170,10 @@
 static void
 menu_block_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	block_cb(NULL, GAIM_GTK_CONVERSATION(conv));
 }
@@ -1297,10 +1181,10 @@
 static void
 menu_add_remove_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	add_remove_cb(NULL, GAIM_GTK_CONVERSATION(conv));
 }
@@ -1308,34 +1192,34 @@
 static void
 menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
-
-	close_conv_cb(NULL, GAIM_GTK_CONVERSATION(gaim_conv_window_get_active_conversation(win)));
+	GaimGtkWindow *win = data;
+
+	close_conv_cb(NULL, GAIM_GTK_CONVERSATION(gaim_gtk_conv_window_get_active_conversation(win)));
 }
 
 static void
 menu_logging_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	if (conv == NULL)
 		return;
 
 	gaim_conversation_set_logging(conv,
-			gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
+	                              gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
 }
 
 static void
 menu_toolbar_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 	GaimGtkConversation *gtkconv;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	if (conv == NULL)
 		return;
@@ -1343,17 +1227,17 @@
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
 
 	gaim_prefs_set_bool("/gaim/gtk/conversations/show_formatting_toolbar",
-			    gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
+	                    gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
 }
 
 static void
 menu_sounds_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 	GaimGtkConversation *gtkconv;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	if (!conv)
 		return;
@@ -1367,11 +1251,11 @@
 static void
 menu_timestamps_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 	GaimGtkConversation *gtkconv;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	if (!conv)
 		return;
@@ -1713,17 +1597,17 @@
 move_to_next_unread_tab(GaimGtkConversation *gtkconv, gboolean forward)
 {
 	GaimGtkConversation *next_gtkconv = NULL;
-	GaimConvWindow *win;
+	GaimGtkWindow *win;
 	GList *l;
 	int index, i, total, found = 0;
 
-	win   = gaim_conversation_get_window(gtkconv->active_conv);
-	index = gtk_notebook_page_num(GTK_NOTEBOOK(GAIM_GTK_WINDOW(win)->notebook), gtkconv->tab_cont);
-	total = gaim_conv_window_get_conversation_count(win);
+	win   = gtkconv->win;
+	index = gtk_notebook_page_num(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont);
+	total = gaim_gtk_conv_window_get_gtkconv_count(win);
 
 	/* First check the tabs after (forward) or before (!forward) this position. */
 	for (i = index;
-		 !found && (next_gtkconv = gaim_gtk_get_gtkconv_at_index(win, i));
+		 !found && (next_gtkconv = gaim_gtk_conv_window_get_gtkconv_at_index(win, i));
 		 forward ? i++ : i--) {
 		if (i == -1) {
 			break;
@@ -1741,7 +1625,7 @@
 	if (!found) {
 		/* Now check from the beginning up to (forward) or end back to (!forward) this position. */
 		for (i = forward ? 0 : total - 1;
-			 !found && (forward ? i < index : i >= 0) && (next_gtkconv = gaim_gtk_get_gtkconv_at_index(win, i));
+			 !found && (forward ? i < index : i >= 0) && (next_gtkconv = gaim_gtk_conv_window_get_gtkconv_at_index(win, i));
 			 forward ? i++ : i--) {
 			for (l = next_gtkconv->convs; l; l = forward ? l->next : l->prev) {
 				GaimConversation *c = l->data;
@@ -1760,29 +1644,27 @@
 			else {
 				index = (index == 0) ? total - 1 : index - 1;
 			}
-			if (!(next_gtkconv = gaim_gtk_get_gtkconv_at_index(win, index)))
-				next_gtkconv = gaim_gtk_get_gtkconv_at_index(win, 0);
+			if (!(next_gtkconv = gaim_gtk_conv_window_get_gtkconv_at_index(win, index)))
+				next_gtkconv = gaim_gtk_conv_window_get_gtkconv_at_index(win, 0);
 		}
 	}
 
 	if (next_gtkconv != NULL && next_gtkconv != gtkconv)
-		gaim_conv_window_switch_conversation(win,next_gtkconv->active_conv);
+		gaim_gtk_conv_window_switch_gtkconv(win, next_gtkconv);
 }
 
 static gboolean
 entry_key_press_cb(GtkWidget *entry, GdkEventKey *event, gpointer data)
 {
-	GaimConvWindow *win;
+	GaimGtkWindow *win;
 	GaimConversation *conv;
 	GaimGtkConversation *gtkconv;
-	GaimGtkWindow *gtkwin;
 	int curconv;
 
 	gtkconv  = (GaimGtkConversation *)data;
 	conv     = gtkconv->active_conv;
-	win      = gaim_conversation_get_window(conv);
-	gtkwin   = GAIM_GTK_WINDOW(win);
-	curconv = gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkwin->notebook));
+	win      = gtkconv->win;
+	curconv = gtk_notebook_get_current_page(GTK_NOTEBOOK(win->notebook));
 
 	/* If CTRL was held down... */
 	if (event->state & GDK_CONTROL_MASK) {
@@ -1878,19 +1760,19 @@
 
 			case GDK_Page_Down:
 			case ']':
-				if (!gaim_gtk_get_gtkconv_at_index(win, curconv + 1))
-					gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), 0);
+				if (!gaim_gtk_conv_window_get_gtkconv_at_index(win, curconv + 1))
+					gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), 0);
 				else
-					gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), curconv + 1);
+					gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), curconv + 1);
 				return TRUE;
 				break;
 
 			case GDK_Page_Up:
 			case '[':
-				if (!gaim_gtk_get_gtkconv_at_index(win, curconv - 1))
-					gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), -1);
+				if (!gaim_gtk_conv_window_get_gtkconv_at_index(win, curconv - 1))
+					gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), -1);
 				else
-					gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), curconv - 1);
+					gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), curconv - 1);
 				return TRUE;
 				break;
 
@@ -1906,15 +1788,15 @@
 				break;
 
 			case GDK_comma:
-				gtk_notebook_reorder_child(GTK_NOTEBOOK(gtkwin->notebook),
-						gtk_notebook_get_nth_page(GTK_NOTEBOOK(gtkwin->notebook), curconv),
+				gtk_notebook_reorder_child(GTK_NOTEBOOK(win->notebook),
+						gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), curconv),
 						curconv - 1);
 				break;
 
 			case GDK_period:
-				gtk_notebook_reorder_child(GTK_NOTEBOOK(gtkwin->notebook),
-						gtk_notebook_get_nth_page(GTK_NOTEBOOK(gtkwin->notebook), curconv),
-						(curconv + 1) % gtk_notebook_get_n_pages(GTK_NOTEBOOK(gtkwin->notebook)));
+				gtk_notebook_reorder_child(GTK_NOTEBOOK(win->notebook),
+						gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), curconv),
+						(curconv + 1) % gtk_notebook_get_n_pages(GTK_NOTEBOOK(win->notebook)));
 				break;
 
 		} /* End of switch */
@@ -1926,8 +1808,8 @@
 		if (event->keyval > '0' && event->keyval <= '9')
 		{
 			int switchto = event->keyval - '1';
-			if (switchto < gaim_conv_window_get_conversation_count(win))
-				gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), switchto);
+			if (switchto < gaim_gtk_conv_window_get_gtkconv_count(win))
+				gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), switchto);
 
 			return TRUE;
 		}
@@ -2016,7 +1898,7 @@
 static void
 menu_conv_sel_send_cb(GObject *m, gpointer data)
 {
-	GaimConvWindow *win = g_object_get_data(m, "user_data");
+	GaimGtkWindow *win = g_object_get_data(m, "user_data");
 	GaimAccount *account = g_object_get_data(m, "gaim_account");
 	GaimConversation *conv;
 	GaimGtkConversation *gtkconv;
@@ -2024,7 +1906,7 @@
 	if (gtk_check_menu_item_get_active((GtkCheckMenuItem*) m) == FALSE)
 		return;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	gaim_conversation_set_account(conv, account);
 
@@ -2084,353 +1966,11 @@
 	}
 }
 
-static void
-notebook_init_grab(GaimGtkWindow *gtkwin, GtkWidget *widget)
-{
-	static GdkCursor *cursor = NULL;
-
-	gtkwin->in_drag = TRUE;
-
-	if (gtkwin->drag_leave_signal) {
-		g_signal_handler_disconnect(G_OBJECT(widget),
-									gtkwin->drag_leave_signal);
-
-		gtkwin->drag_leave_signal = 0;
-	}
-
-	if (cursor == NULL)
-		cursor = gdk_cursor_new(GDK_FLEUR);
-
-	/* Grab the pointer */
-	gtk_grab_add(gtkwin->notebook);
-#ifndef _WIN32
-	/* Currently for win32 GTK+ (as of 2.2.1), gdk_pointer_is_grabbed will
-	   always be true after a button press. */
-	if (!gdk_pointer_is_grabbed())
-#endif
-		gdk_pointer_grab(gtkwin->notebook->window, FALSE,
-						 GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
-						 NULL, cursor, GDK_CURRENT_TIME);
-}
-
-static gboolean
-notebook_motion_cb(GtkWidget *widget, GdkEventButton *e, GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin;
-
-	gtkwin = GAIM_GTK_WINDOW(win);
-
-	/*
-	 * Make sure the user moved the mouse far enough for the
-	 * drag to be initiated.
-	 */
-	if (gtkwin->in_predrag) {
-		if (e->x_root <  gtkwin->drag_min_x ||
-			e->x_root >= gtkwin->drag_max_x ||
-			e->y_root <  gtkwin->drag_min_y ||
-			e->y_root >= gtkwin->drag_max_y) {
-
-			gtkwin->in_predrag = FALSE;
-			notebook_init_grab(gtkwin, widget);
-		}
-	}
-	else { /* Otherwise, draw the arrows. */
-		GaimConvWindow *dest_win;
-		GaimGtkWindow *dest_gtkwin;
-		GtkNotebook *dest_notebook;
-		GtkWidget *tab;
-		gint nb_x, nb_y, page_num;
-		gint arrow1_x, arrow1_y, arrow2_x, arrow2_y;
-		gboolean horiz_tabs = FALSE;
-
-		/* Get the window that the cursor is over. */
-		dest_win = gaim_gtkwin_get_at_xy(e->x_root, e->y_root);
-
-		if (dest_win == NULL) {
-			dnd_hints_hide_all();
-
-			return TRUE;
-		}
-
-		dest_gtkwin = GAIM_GTK_WINDOW(dest_win);
-
-		dest_notebook = GTK_NOTEBOOK(dest_gtkwin->notebook);
-
-		gdk_window_get_origin(GTK_WIDGET(dest_notebook)->window, &nb_x, &nb_y);
-
-		arrow1_x = arrow2_x = nb_x;
-		arrow1_y = arrow2_y = nb_y;
-
-		page_num = gaim_gtkconv_get_tab_at_xy(dest_win,
-												   e->x_root, e->y_root);
-
-		if (gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_TOP ||
-			gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_BOTTOM) {
-
-			horiz_tabs = TRUE;
-		}
-
-		tab = gaim_gtk_get_gtkconv_at_index(dest_win, page_num)->tabby;
-
-		if (horiz_tabs) {
-			arrow1_x = arrow2_x = nb_x + tab->allocation.x;
-
-			if ((gpointer)gtkwin == (gpointer)dest_gtkwin && gtkwin->drag_tab < page_num) {
-				arrow1_x += tab->allocation.width;
-				arrow2_x += tab->allocation.width;
-			}
-
-			arrow1_y = nb_y + tab->allocation.y;
-			arrow2_y = nb_y + tab->allocation.y +
-							  tab->allocation.height;
-		}
-		else {
-			arrow1_x = nb_x + tab->allocation.x;
-			arrow2_x = nb_x + tab->allocation.x +
-							  tab->allocation.width;
-			arrow1_y = arrow2_y = nb_y + tab->allocation.y + tab->allocation.height/2;
-
-			if ((gpointer)gtkwin == (gpointer)dest_win && gtkwin->drag_tab < page_num) {
-				arrow1_y += tab->allocation.height;
-				arrow2_y += tab->allocation.height;
-			}
-		}
-
-		if (horiz_tabs) {
-			dnd_hints_show(HINT_ARROW_DOWN, arrow1_x, arrow1_y);
-			dnd_hints_show(HINT_ARROW_UP,   arrow2_x, arrow2_y);
-		}
-		else {
-			dnd_hints_show(HINT_ARROW_RIGHT, arrow1_x, arrow1_y);
-			dnd_hints_show(HINT_ARROW_LEFT,  arrow2_x, arrow2_y);
-		}
-	}
-
-	return TRUE;
-}
-
-static gboolean
-notebook_leave_cb(GtkWidget *widget, GdkEventCrossing *e, GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin;
-
-	gtkwin = GAIM_GTK_WINDOW(win);
-
-	if (gtkwin->in_drag)
-		return FALSE;
-
-	if (e->x_root <  gtkwin->drag_min_x ||
-		e->x_root >= gtkwin->drag_max_x ||
-		e->y_root <  gtkwin->drag_min_y ||
-		e->y_root >= gtkwin->drag_max_y) {
-
-		gtkwin->in_predrag = FALSE;
-		notebook_init_grab(gtkwin, widget);
-	}
-
-	return TRUE;
-}
-
-/*
- * THANK YOU GALEON!
- */
-static gboolean
-notebook_press_cb(GtkWidget *widget, GdkEventButton *e, GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin;
-	gint nb_x, nb_y, x_rel, y_rel;
-	int tab_clicked;
-	GtkWidget *page;
-	GtkWidget *tab;
-
-	if (e->button != 1 || e->type != GDK_BUTTON_PRESS)
-		return FALSE;
-
-	gtkwin = GAIM_GTK_WINDOW(win);
-
-	if (gtkwin->in_drag) {
-		gaim_debug(GAIM_DEBUG_WARNING, "gtkconv",
-				   "Already in the middle of a window drag at tab_press_cb\n");
-		return TRUE;
-	}
-
-	/*
-	 * Make sure a tab was actually clicked. The arrow buttons
-	 * mess things up.
-	 */
-	tab_clicked = gaim_gtkconv_get_tab_at_xy(win, e->x_root, e->y_root);
-
-	if (tab_clicked == -1)
-		return FALSE;
-
-	/*
-	 * Get the relative position of the press event, with regards to
-	 * the position of the notebook.
-	 */
-	gdk_window_get_origin(gtkwin->notebook->window, &nb_x, &nb_y);
-
-	x_rel = e->x_root - nb_x;
-	y_rel = e->y_root - nb_y;
-
-	/* Reset the min/max x/y */
-	gtkwin->drag_min_x = 0;
-	gtkwin->drag_min_y = 0;
-	gtkwin->drag_max_x = 0;
-	gtkwin->drag_max_y = 0;
-
-	/* Find out which tab was dragged. */
-	page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(gtkwin->notebook), tab_clicked);
-	tab = gtk_notebook_get_tab_label(GTK_NOTEBOOK(gtkwin->notebook), page);
-
-	gtkwin->drag_min_x = tab->allocation.x      + nb_x;
-	gtkwin->drag_min_y = tab->allocation.y      + nb_y;
-	gtkwin->drag_max_x = tab->allocation.width  + gtkwin->drag_min_x;
-	gtkwin->drag_max_y = tab->allocation.height + gtkwin->drag_min_y;
-
-	/* Make sure the click occurred in the tab. */
-	if (e->x_root <  gtkwin->drag_min_x ||
-		e->x_root >= gtkwin->drag_max_x ||
-		e->y_root <  gtkwin->drag_min_y ||
-		e->y_root >= gtkwin->drag_max_y) {
-
-		return FALSE;
-	}
-
-	gtkwin->in_predrag = TRUE;
-	gtkwin->drag_tab = tab_clicked;
-
-	/* Connect the new motion signals. */
-	gtkwin->drag_motion_signal =
-		g_signal_connect(G_OBJECT(widget), "motion_notify_event",
-						 G_CALLBACK(notebook_motion_cb), win);
-
-	gtkwin->drag_leave_signal =
-		g_signal_connect(G_OBJECT(widget), "leave_notify_event",
-						 G_CALLBACK(notebook_leave_cb), win);
-
-	return FALSE;
-}
-
-static gboolean
-notebook_release_cb(GtkWidget *widget, GdkEventButton *e, GaimConvWindow *win)
-{
-	GaimConvWindow *dest_win;
-	GaimGtkWindow *gtkwin;
-	GaimConversation *conv;
-	GaimGtkConversation *gtkconv;
-	gint dest_page_num = 0;
-	gboolean new_window = FALSE;
-
-	/*
-	 * Don't check to make sure that the event's window matches the
-	 * widget's, because we may be getting an event passed on from the
-	 * close button.
-	 */
-	if (e->button != 1 && e->type != GDK_BUTTON_RELEASE)
-		return FALSE;
-
-	if (gdk_pointer_is_grabbed()) {
-		gdk_pointer_ungrab(GDK_CURRENT_TIME);
-		gtk_grab_remove(widget);
-	}
-
-	gtkwin = GAIM_GTK_WINDOW(win);
-
-	if (!gtkwin->in_predrag && !gtkwin->in_drag)
-		return FALSE;
-
-	/* Disconnect the motion signal. */
-	if (gtkwin->drag_motion_signal) {
-		g_signal_handler_disconnect(G_OBJECT(widget),
-			gtkwin->drag_motion_signal);
-
-		gtkwin->drag_motion_signal = 0;
-	}
-
-	/*
-	 * If we're in a pre-drag, we'll also need to disconnect the leave
-	 * signal.
-	 */
-	if (gtkwin->in_predrag) {
-		gtkwin->in_predrag = FALSE;
-
-		if (gtkwin->drag_leave_signal) {
-			g_signal_handler_disconnect(G_OBJECT(widget),
-				gtkwin->drag_leave_signal);
-
-			gtkwin->drag_leave_signal = 0;
-		}
-	}
-
-	/* If we're not in drag...        */
-	/* We're perfectly normal people! */
-	if (!gtkwin->in_drag)
-		return FALSE;
-
-	gtkwin->in_drag = FALSE;
-
-	dnd_hints_hide_all();
-
-	dest_win = gaim_gtkwin_get_at_xy(e->x_root, e->y_root);
-
-	conv = gaim_conv_window_get_active_conversation(win);
-
-	if (dest_win == NULL) {
-		/* If the current window doesn't have any other conversations,
-		 * there isn't much point transferring the conv to a new window. */
-		if (gaim_conv_window_get_conversation_count(win) > 1) {
-			/* Make a new window to stick this to. */
-			dest_win = gaim_conv_window_new();
-			new_window = TRUE;
-		}
-	}
-
-	if (dest_win == NULL)
-		return FALSE;
-
-	gaim_signal_emit(gaim_gtk_conversations_get_handle(),
-		"conversation-dragging", win, dest_win);
-
-	/* Get the destination page number. */
-	if (!new_window)
-		dest_page_num = gaim_gtkconv_get_tab_at_xy(dest_win,
-			e->x_root, e->y_root);
-
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-
-	if (win == dest_win) {
-		gtk_notebook_reorder_child(GTK_NOTEBOOK(gtkwin->notebook), gtkconv->tab_cont, dest_page_num);
-	}
-	else {
-		gaim_conv_window_remove_conversation(win, conv);
-		gaim_conv_window_add_conversation(dest_win, conv);
-		gtk_notebook_reorder_child(GTK_NOTEBOOK(GAIM_GTK_WINDOW(dest_win)->notebook), gtkconv->tab_cont, dest_page_num);
-		gaim_conv_window_switch_conversation(dest_win, conv);
-		if (new_window) {
-			GaimGtkWindow *dest_gtkwin = GAIM_GTK_WINDOW(dest_win);
-			gint win_width, win_height;
-
-			gtk_window_get_size(GTK_WINDOW(dest_gtkwin->window),
-				&win_width, &win_height);
-
-			gtk_window_move(GTK_WINDOW(dest_gtkwin->window),
-				e->x_root - (win_width  / 2),
-				e->y_root - (win_height / 2));
-
-			gaim_conv_window_show(dest_win);
-		}
-	}
-
-	gtk_widget_grab_focus(GAIM_GTK_CONVERSATION(conv)->entry);
-
-	return TRUE;
-}
-
 /**************************************************************************
  * A bunch of buddy icon functions
  **************************************************************************/
-static GdkPixbuf *
-get_tab_icon(GaimConversation *conv, gboolean small_icon)
+GdkPixbuf *
+gaim_gtkconv_get_tab_icon(GaimConversation *conv, gboolean small_icon)
 {
 	GaimAccount *account = NULL;
 	const char *name = NULL;
@@ -2472,7 +2012,7 @@
 update_tab_icon(GaimConversation *conv)
 {
 	GaimGtkConversation *gtkconv;
-	GaimConvWindow *win = gaim_conversation_get_window(conv);
+	GaimGtkWindow *win;
 	GaimAccount *account;
 	const char *name;
 	GdkPixbuf *status = NULL;
@@ -2480,10 +2020,11 @@
 	g_return_if_fail(conv != NULL);
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
+	win = gtkconv->win;
 	name = gaim_conversation_get_name(conv);
 	account = gaim_conversation_get_account(conv);
 
-	status = get_tab_icon(conv, TRUE);
+	status = gaim_gtkconv_get_tab_icon(conv, TRUE);
 
 	g_return_if_fail(status != NULL);
 
@@ -2493,13 +2034,13 @@
 	if (status != NULL)
 		g_object_unref(status);
 
-	if (gaim_conv_window_get_active_conversation(win) == conv &&
+	if (gaim_gtk_conv_window_get_active_conversation(win) == conv &&
 		(gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_IM ||
 		 gtkconv->u.im->anim == NULL))
 	{
-		status = get_tab_icon(conv, FALSE);
-
-		gtk_window_set_icon(GTK_WINDOW(GAIM_GTK_WINDOW(win)->window), status);
+		status = gaim_gtkconv_get_tab_icon(conv, FALSE);
+
+		gtk_window_set_icon(GTK_WINDOW(win->window), status);
 
 		if (status != NULL)
 			g_object_unref(status);
@@ -2590,27 +2131,6 @@
 }
 
 static void
-stop_anim(GtkObject *obj, GaimGtkConversation *gtkconv)
-{
-	if (gtkconv->u.im->icon_timer != 0)
-		g_source_remove(gtkconv->u.im->icon_timer);
-
-	gtkconv->u.im->icon_timer = 0;
-}
-
-static void
-toggle_icon_animate_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
-{
-	gtkconv->u.im->animate =
-		gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
-
-	if (gtkconv->u.im->animate)
-		start_anim(NULL, gtkconv);
-	else
-		stop_anim(NULL, gtkconv);
-}
-
-static void
 remove_icon(GaimGtkConversation *gtkconv)
 {
 	GaimConversation *conv = gtkconv->active_conv;
@@ -2637,7 +2157,7 @@
 	gtkconv->u.im->icon_container = NULL;
 	gtkconv->u.im->show_icon = FALSE;
 
-	gtkwin = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv));
+	gtkwin = gtkconv->win;
 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.show_icon), FALSE);
 }
 
@@ -2689,6 +2209,28 @@
 	g_free(buf);
 }
 
+static void
+stop_anim(GtkObject *obj, GaimGtkConversation *gtkconv)
+{
+	if (gtkconv->u.im->icon_timer != 0)
+		g_source_remove(gtkconv->u.im->icon_timer);
+
+	gtkconv->u.im->icon_timer = 0;
+}
+
+
+static void
+toggle_icon_animate_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
+{
+	gtkconv->u.im->animate =
+		gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
+
+	if (gtkconv->u.im->animate)
+		start_anim(NULL, gtkconv);
+	else
+		stop_anim(NULL, gtkconv);
+}
+
 static gboolean
 icon_menu(GtkObject *obj, GdkEventButton *e, GaimGtkConversation *gtkconv)
 {
@@ -2734,12 +2276,12 @@
 static void
 menu_buddyicon_cb(gpointer data, guint action, GtkWidget *widget)
 {
-	GaimConvWindow *win = (GaimConvWindow *)data;
+	GaimGtkWindow *win = data;
 	GaimConversation *conv;
 	GaimGtkConversation *gtkconv;
 	gboolean active;
 
-	conv = gaim_conv_window_get_active_conversation(win);
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	if (!conv)
 		return;
@@ -2760,272 +2302,189 @@
  * End of the bunch of buddy icon functions
  **************************************************************************/
 
-
-/*
- * Makes sure all the menu items and all the buttons are hidden/shown and
- * sensitive/insensitive.  This is called after changing tabs and when an
- * account signs on or off.
- */
-static void
-gray_stuff_out(GaimGtkConversation *gtkconv)
-{
-	GaimConvWindow *win;
-	GaimGtkWindow *gtkwin;
-	GaimConversation *conv = gtkconv->active_conv;
-	GaimConnection *gc;
-	GaimPluginProtocolInfo *prpl_info = NULL;
-	GdkPixbuf *window_icon = NULL;
-	GtkIMHtmlButtons buttons;
-	GaimAccount *account;
-
-	win     = gaim_conversation_get_window(conv);
-	gtkwin  = GAIM_GTK_WINDOW(win);
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-	gc      = gaim_conversation_get_gc(conv);
-	account = gaim_conversation_get_account(conv);
-
-	if (gc != NULL)
-		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
-
-	if (gtkwin->menu.send_as != NULL)
-		g_timeout_add(0, (GSourceFunc)update_send_as_selection, win);
-
-	/*
-	 * Handle hiding and showing stuff based on what type of conv this is.
-	 * Stuff that Gaim IMs support in general should be shown for IM
-	 * conversations.  Stuff that Gaim chats support in general should be
-	 * shown for chat conversations.  It doesn't matter whether the PRPL
-	 * supports it or not--that only affects if the button or menu item
-	 * is sensitive or not.
-	 */
-	if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) {
-		/* Show stuff that applies to IMs, hide stuff that applies to chats */
-
-		/* Deal with menu items */
-		gtk_widget_show(gtkwin->menu.view_log);
-		gtk_widget_show(gtkwin->menu.send_file);
-		gtk_widget_show(gtkwin->menu.add_pounce);
-		gtk_widget_show(gtkwin->menu.get_info);
-		gtk_widget_hide(gtkwin->menu.invite);
-		gtk_widget_show(gtkwin->menu.alias);
-		gtk_widget_show(gtkwin->menu.block);
-
-		if (gaim_find_buddy(account, gaim_conversation_get_name(conv)) == NULL) {
-			gtk_widget_show(gtkwin->menu.add);
-			gtk_widget_hide(gtkwin->menu.remove);
-		} else {
-			gtk_widget_show(gtkwin->menu.remove);
-			gtk_widget_hide(gtkwin->menu.add);
-		}
-
-		gtk_widget_show(gtkwin->menu.insert_link);
-		gtk_widget_show(gtkwin->menu.insert_image);
-		gtk_widget_show(gtkwin->menu.show_icon);
-	} else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
-		/* Show stuff that applies to Chats, hide stuff that applies to IMs */
-
-		/* Deal with menu items */
-		gtk_widget_show(gtkwin->menu.view_log);
-		gtk_widget_hide(gtkwin->menu.send_file);
-		gtk_widget_hide(gtkwin->menu.add_pounce);
-		gtk_widget_hide(gtkwin->menu.get_info);
-		gtk_widget_show(gtkwin->menu.invite);
-		gtk_widget_show(gtkwin->menu.alias);
-		gtk_widget_hide(gtkwin->menu.block);
-		gtk_widget_hide(gtkwin->menu.show_icon);
-
-		if (gaim_blist_find_chat(account, gaim_conversation_get_name(conv)) == NULL) {
-			/* If the chat is NOT in the buddy list */
-			gtk_widget_show(gtkwin->menu.add);
-			gtk_widget_hide(gtkwin->menu.remove);
-		} else {
-			/* If the chat IS in the buddy list */
-			gtk_widget_hide(gtkwin->menu.add);
-			gtk_widget_show(gtkwin->menu.remove);
-		}
-
-		gtk_widget_show(gtkwin->menu.insert_link);
-		gtk_widget_hide(gtkwin->menu.insert_image);
-	}
-
-	/*
-	 * Handle graying stuff out based on whether an account is connected
-	 * and what features that account supports.
-	 */
-	if ((gc != NULL) &&
-	   ( (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_CHAT) ||
-	    !gaim_conv_chat_has_left(GAIM_CONV_CHAT(conv)) )) {
-		/* Account is online */
-		/* Deal with the toolbar */
-		if (conv->features & GAIM_CONNECTION_HTML) {
-			buttons = GTK_IMHTML_ALL;    /* Everything on */
-			if (!(prpl_info->options & OPT_PROTO_IM_IMAGE) ||
-			    conv->features & GAIM_CONNECTION_NO_IMAGES)
-				buttons &= ~GTK_IMHTML_IMAGE;
-			if (conv->features & GAIM_CONNECTION_NO_BGCOLOR)
-				buttons &= ~GTK_IMHTML_BACKCOLOR;
-			if (conv->features & GAIM_CONNECTION_NO_FONTSIZE) {
-				buttons &= ~GTK_IMHTML_GROW;
-				buttons &= ~GTK_IMHTML_SHRINK;
-			}
-			if (conv->features & GAIM_CONNECTION_NO_URLDESC)
-				buttons &= ~GTK_IMHTML_LINKDESC;
-		} else {
-			buttons = GTK_IMHTML_SMILEY;
-		}
-		gtk_imhtml_set_format_functions(GTK_IMHTML(gtkconv->entry), buttons);
-		gtk_imhtmltoolbar_associate_smileys(GTK_IMHTMLTOOLBAR(gtkconv->toolbar), gaim_account_get_protocol_id(account));
-
-		/* Deal with menu items */
-		gtk_widget_set_sensitive(gtkwin->menu.view_log, TRUE);
-		gtk_widget_set_sensitive(gtkwin->menu.add_pounce, TRUE);
-		gtk_widget_set_sensitive(gtkwin->menu.get_info, (prpl_info->get_info != NULL));
-		gtk_widget_set_sensitive(gtkwin->menu.invite, (prpl_info->chat_invite != NULL));
-		gtk_widget_set_sensitive(gtkwin->menu.block, (prpl_info->add_deny != NULL));
-		gtk_widget_set_sensitive(gtkwin->menu.insert_link, (conv->features & GAIM_CONNECTION_HTML));
-		gtk_widget_set_sensitive(gtkwin->menu.insert_image, (prpl_info->options & OPT_PROTO_IM_IMAGE));
-
-		if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) {
-			gtk_widget_set_sensitive(gtkwin->menu.add, (prpl_info->add_buddy != NULL));
-			gtk_widget_set_sensitive(gtkwin->menu.remove, (prpl_info->remove_buddy != NULL));
-			gtk_widget_set_sensitive(gtkwin->menu.send_file,
-					(prpl_info->send_file != NULL && (!prpl_info->can_receive_file ||
-					 prpl_info->can_receive_file(gc, gaim_conversation_get_name(conv)))));
-			gtk_widget_set_sensitive(gtkwin->menu.alias,
-					(gaim_find_buddy(account, gaim_conversation_get_name(conv)) != NULL));
-		} else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
-			gtk_widget_set_sensitive(gtkwin->menu.add, (prpl_info->join_chat != NULL));
-			gtk_widget_set_sensitive(gtkwin->menu.remove, (prpl_info->join_chat != NULL));
-			gtk_widget_set_sensitive(gtkwin->menu.alias,
-					(gaim_blist_find_chat(account, gaim_conversation_get_name(conv)) != NULL));
-		}
-
-		/* Deal with chat userlist buttons */
-		if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)
-		{
-			gtk_widget_set_sensitive(gtkconv->u.chat->userlist_im, TRUE);
-			gtk_widget_set_sensitive(gtkconv->u.chat->userlist_ignore, TRUE);
-			gtk_widget_set_sensitive(gtkconv->u.chat->userlist_info, (prpl_info->get_info != NULL));
-		}
-	} else {
-		/* Account is offline */
-		/* Or it's a chat that we've left. */
-
-		/* Then deal with menu items */
-		gtk_widget_set_sensitive(gtkwin->menu.view_log, TRUE);
-		gtk_widget_set_sensitive(gtkwin->menu.send_file, FALSE);
-		gtk_widget_set_sensitive(gtkwin->menu.add_pounce, TRUE);
-		gtk_widget_set_sensitive(gtkwin->menu.get_info, FALSE);
-		gtk_widget_set_sensitive(gtkwin->menu.invite, FALSE);
-		gtk_widget_set_sensitive(gtkwin->menu.alias, FALSE);
-		gtk_widget_set_sensitive(gtkwin->menu.block, FALSE);
-		gtk_widget_set_sensitive(gtkwin->menu.add, FALSE);
-		gtk_widget_set_sensitive(gtkwin->menu.remove, FALSE);
-		gtk_widget_set_sensitive(gtkwin->menu.insert_link, TRUE);
-		gtk_widget_set_sensitive(gtkwin->menu.insert_image, FALSE);
-
-		/* Deal with chat userlist buttons */
-		if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)
-		{
-			gtk_widget_set_sensitive(gtkconv->u.chat->userlist_im, FALSE);
-			gtk_widget_set_sensitive(gtkconv->u.chat->userlist_ignore, FALSE);
-			gtk_widget_set_sensitive(gtkconv->u.chat->userlist_info, FALSE);
-		}
-	}
-
-	/*
-	 * Update the window's icon
-	 */
-	if ((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) &&
-		(gtkconv->u.im->anim))
-	{
-		window_icon =
-			gdk_pixbuf_animation_get_static_image(gtkconv->u.im->anim);
-		g_object_ref(window_icon);
-	} else {
-		window_icon = get_tab_icon(conv, FALSE);
-	}
-	gtk_window_set_icon(GTK_WINDOW(gtkwin->window), window_icon);
-	if (window_icon != NULL)
-		g_object_unref(G_OBJECT(window_icon));
-}
-
-static void
-before_switch_conv_cb(GtkNotebook *notebook, GtkWidget *page, gint page_num,
-				gpointer user_data)
-{
-	GaimConvWindow *win;
-	GaimConversation *conv;
-	GaimGtkConversation *gtkconv;
-
-	win = (GaimConvWindow *)user_data;
-	conv = gaim_conv_window_get_active_conversation(win);
-
-	g_return_if_fail(conv != NULL);
-
-	if (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_IM)
-		return;
-
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-
-	stop_anim(NULL, gtkconv);
-}
-
-static void
-switch_conv_cb(GtkNotebook *notebook, GtkWidget *page, gint page_num,
-				gpointer user_data)
-{
-	GaimConvWindow *win;
-	GaimConversation *conv;
-	GaimGtkConversation *gtkconv;
-	GaimGtkWindow *gtkwin;
-
-	win = (GaimConvWindow *)user_data;
-	gtkconv = gaim_gtk_get_gtkconv_at_index(win, page_num);
-	conv = gtkconv->active_conv;
-
-	g_return_if_fail(conv != NULL);
-
-	gtkwin  = GAIM_GTK_WINDOW(win);
-
-	/*
-	 * Only set "unseen" to "none" if the window has focus
-	 */
-	if (gaim_conv_window_has_focus(win))
-		gaim_conversation_set_unseen(conv, GAIM_UNSEEN_NONE);
-
-	/* Update the menubar */
-	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));
-
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.sounds),
-				       gtkconv->make_sound);
-
-	gtk_check_menu_item_set_active(
-			GTK_CHECK_MENU_ITEM(gtkwin->menu.show_formatting_toolbar),
-			gaim_prefs_get_bool("/gaim/gtk/conversations/show_formatting_toolbar"));
-
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.show_timestamps),
-				       gtkconv->show_timestamps);
-
-	if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
-		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.show_icon),
-								       gtkconv->u.im->show_icon);
-	/*
-	 * We pause icons when they are not visible.  If this icon should
-	 * be animated then start it back up again.
-	 */
-	if ((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) &&
-		(gtkconv->u.im->animate))
-		start_anim(NULL, gtkconv);
-
-	gtk_window_set_title(GTK_WINDOW(gtkwin->window),
-			     gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
-}
+GaimGtkWindow *
+gaim_gtkconv_get_window(GaimGtkConversation *gtkconv)
+{
+	g_return_val_if_fail(gtkconv != NULL, NULL);
+	return gtkconv->win;
+}
+
+static GtkItemFactoryEntry menu_items[] =
+{
+	/* Conversation menu */
+	{ N_("/_Conversation"), NULL, NULL, 0, "<Branch>" },
+
+	{ N_("/Conversation/New Instant _Message..."), "<CTL>M", menu_new_conv_cb,
+			0, "<StockItem>", GAIM_STOCK_IM },
+
+	{ "/Conversation/sep0", NULL, NULL, 0, "<Separator>" },
+
+	{ N_("/Conversation/_Find..."), NULL, menu_find_cb, 0,
+			"<StockItem>", GTK_STOCK_FIND },
+	{ N_("/Conversation/View _Log"), NULL, menu_view_log_cb, 0, NULL },
+	{ N_("/Conversation/_Save As..."), NULL, menu_save_as_cb, 0,
+			"<StockItem>", GTK_STOCK_SAVE_AS },
+	{ N_("/Conversation/Clear"), "<CTL>L", menu_clear_cb, 0, "<StockItem>", GTK_STOCK_CLEAR },
+
+	{ "/Conversation/sep1", NULL, NULL, 0, "<Separator>" },
+
+	{ N_("/Conversation/Se_nd File..."), NULL, menu_send_file_cb, 0, "<StockItem>", GAIM_STOCK_FILE_TRANSFER },
+	{ N_("/Conversation/Add Buddy _Pounce..."), NULL, menu_add_pounce_cb,
+			0, NULL },
+	{ N_("/Conversation/_Get Info"), "<CTL>O", menu_get_info_cb, 0,
+			"<StockItem>", GAIM_STOCK_INFO },
+	{ N_("/Conversation/In_vite..."), NULL, menu_invite_cb, 0,
+			"<StockItem>", GAIM_STOCK_INVITE },
+
+	{ "/Conversation/sep2", NULL, NULL, 0, "<Separator>" },
+
+	{ N_("/Conversation/Al_ias..."), NULL, menu_alias_cb, 0,
+			"<StockItem>", GAIM_STOCK_EDIT },
+	{ N_("/Conversation/_Block..."), NULL, menu_block_cb, 0,
+			"<StockItem>", GAIM_STOCK_BLOCK },
+	{ N_("/Conversation/_Add..."), NULL, menu_add_remove_cb, 0,
+			"<StockItem>", GTK_STOCK_ADD },
+	{ N_("/Conversation/_Remove..."), NULL, menu_add_remove_cb, 0,
+			"<StockItem>", GTK_STOCK_REMOVE },
+
+	{ "/Conversation/sep3", NULL, NULL, 0, "<Separator>" },
+
+	{ N_("/Conversation/Insert Lin_k..."), NULL, menu_insert_link_cb, 0,
+			"<StockItem>", GAIM_STOCK_LINK },
+	{ N_("/Conversation/Insert Imag_e..."), NULL, menu_insert_image_cb, 0,
+			"<StockItem>", GAIM_STOCK_IMAGE },
+
+	{ "/Conversation/sep4", NULL, NULL, 0, "<Separator>" },
+
+	{ N_("/Conversation/_Close"), NULL, menu_close_conv_cb, 0,
+			"<StockItem>", GTK_STOCK_CLOSE },
+
+	/* Options */
+	{ N_("/_Options"), NULL, NULL, 0, "<Branch>" },
+	{ N_("/Options/Enable _Logging"), NULL, menu_logging_cb, 0, "<CheckItem>" },
+	{ N_("/Options/Enable _Sounds"), NULL, menu_sounds_cb, 0, "<CheckItem>" },
+	{ N_("/Options/Show Formatting _Toolbars"), NULL, menu_toolbar_cb, 0, "<CheckItem>" },
+	{ N_("/Options/Show Ti_mestamps"), "F2", menu_timestamps_cb, 0, "<CheckItem>" },
+	{ N_("/Options/Show Buddy _Icon"), NULL, menu_buddyicon_cb, 0, "<CheckItem>" },
+};
+
+static const int menu_item_count =
+sizeof(menu_items) / sizeof(*menu_items);
+
+static char *
+item_factory_translate_func (const char *path, gpointer func_data)
+{
+	return _((char *)path);
+}
+
+static GtkWidget *
+setup_menubar(GaimGtkWindow *win)
+{
+	GtkAccelGroup *accel_group;
+
+	accel_group = gtk_accel_group_new ();
+	gtk_window_add_accel_group(GTK_WINDOW(win->window), accel_group);
+	g_object_unref(accel_group);
+
+	win->menu.item_factory =
+		gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
+
+	gtk_item_factory_set_translate_func(win->menu.item_factory,
+	                                    item_factory_translate_func,
+	                                    NULL, NULL);
+
+	gtk_item_factory_create_items(win->menu.item_factory, menu_item_count,
+	                              menu_items, win);
+	g_signal_connect(G_OBJECT(accel_group), "accel-changed",
+	                 G_CALLBACK(gaim_gtk_save_accels_cb), NULL);
+
+
+	win->menu.menubar =
+		gtk_item_factory_get_widget(win->menu.item_factory, "<main>");
+
+
+	win->menu.view_log =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Conversation/View Log"));
+
+	/* --- */
+
+	win->menu.send_file =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Conversation/Send File..."));
+
+	win->menu.add_pounce =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Conversation/Add Buddy Pounce..."));
+
+	/* --- */
+
+	win->menu.get_info =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Conversation/Get Info"));
+
+	win->menu.invite =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Conversation/Invite..."));
+
+	/* --- */
+
+	win->menu.alias =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Conversation/Alias..."));
+
+	win->menu.block =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Conversation/Block..."));
+
+	win->menu.add =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Conversation/Add..."));
+
+	win->menu.remove =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Conversation/Remove..."));
+
+	/* --- */
+
+	win->menu.insert_link =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Conversation/Insert Link..."));
+
+	win->menu.insert_image =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Conversation/Insert Image..."));
+
+	/* --- */
+
+	win->menu.logging =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Options/Enable Logging"));
+	win->menu.sounds =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Options/Enable Sounds"));
+	win->menu.show_formatting_toolbar =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Options/Show Formatting Toolbars"));
+	win->menu.show_timestamps =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Options/Show Timestamps"));
+	win->menu.show_icon =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+		                            N_("/Options/Show Buddy Icon"));
+
+	generate_send_as_items(win, NULL);
+
+	win->menu.tray = gaim_gtk_menu_tray_new();
+	gtk_menu_shell_append(GTK_MENU_SHELL(win->menu.menubar),
+	                      win->menu.tray);
+	gtk_widget_show(win->menu.tray);
+
+	gtk_widget_show(win->menu.menubar);
+
+	return win->menu.menubar;
+}
+
 
 /**************************************************************************
  * Utility functions
@@ -3070,7 +2529,7 @@
 	GaimConvIm *im = NULL;
 	GaimConversation *conv = gtkconv->active_conv;
 
-	gtkwin = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv));
+	gtkwin = gtkconv->win;
 
 	if(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
 		im = GAIM_CONV_IM(conv);
@@ -3099,32 +2558,33 @@
 }
 
 static gboolean
-update_send_as_selection(GaimConvWindow *win)
+update_send_as_selection(GaimGtkWindow *win)
 {
 	GaimAccount *account;
 	GaimConversation *conv;
-	GaimGtkWindow *gtkwin;
 	GtkWidget *menu;
 	GList *child;
 
-	if (g_list_find(gaim_get_windows(), win) == NULL)
+	/* what does this do again? */
+	/*
+	if (g_list_find(gaim_gtk_get_windows(), win) == NULL)
 		return FALSE;
-
-	conv = gaim_conv_window_get_active_conversation(win);
+	*/
+
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
 
 	if (conv == NULL)
 		return FALSE;
 
 	account = gaim_conversation_get_account(conv);
-	gtkwin  = GAIM_GTK_WINDOW(win);
-
-	if (gtkwin->menu.send_as == NULL)
+
+	if (win->menu.send_as == NULL)
 		return FALSE;
 
-	gtk_widget_show(gtkwin->menu.send_as);
+	gtk_widget_show(win->menu.send_as);
 
 	menu = gtk_menu_item_get_submenu(
-		GTK_MENU_ITEM(gtkwin->menu.send_as));
+		GTK_MENU_ITEM(win->menu.send_as));
 
 	for (child = gtk_container_get_children(GTK_CONTAINER(menu));
 		 child != NULL;
@@ -3144,9 +2604,8 @@
 }
 
 static void
-generate_send_as_items(GaimConvWindow *win, GaimConversation *deleted_conv)
-{
-	GaimGtkWindow *gtkwin;
+generate_send_as_items(GaimGtkWindow *win, GaimConversation *deleted_conv)
+{
 	GtkWidget *menu;
 	GtkWidget *menuitem;
 	GList *gcs;
@@ -3156,10 +2615,8 @@
 	gboolean found_online = FALSE;
 	GtkSizeGroup *sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
 
-	gtkwin = GAIM_GTK_WINDOW(win);
-
-	if (gtkwin->menu.send_as != NULL)
-		gtk_widget_destroy(gtkwin->menu.send_as);
+	if (win->menu.send_as != NULL)
+		gtk_widget_destroy(win->menu.send_as);
 
 	/* See if we have > 1 connection active. */
 	if (g_list_length(gaim_connections_get_all()) < 2) {
@@ -3167,8 +2624,8 @@
 		gboolean found_offline = FALSE;
 
 		for (convs = gaim_get_conversations();
-			 convs != NULL;
-			 convs = convs->next) {
+		     convs != NULL;
+		     convs = convs->next) {
 
 			GaimConversation *conv;
 			GaimAccount *account;
@@ -3183,19 +2640,19 @@
 		}
 
 		if (!found_offline) {
-			gtkwin->menu.send_as = NULL;
+			win->menu.send_as = NULL;
 			return;
 		}
 	}
 
 	/* Build the Send As menu */
-	gtkwin->menu.send_as = gtk_menu_item_new_with_mnemonic(_("_Send As"));
-	gtk_widget_show(gtkwin->menu.send_as);
+	win->menu.send_as = gtk_menu_item_new_with_mnemonic(_("_Send As"));
+	gtk_widget_show(win->menu.send_as);
 
 	menu = gtk_menu_new();
-	gtk_menu_shell_insert(GTK_MENU_SHELL(gtkwin->menu.menubar),
-						  gtkwin->menu.send_as, 2);
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(gtkwin->menu.send_as), menu);
+	gtk_menu_shell_insert(GTK_MENU_SHELL(win->menu.menubar),
+	                      win->menu.send_as, 2);
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(win->menu.send_as), menu);
 
 	gtk_widget_show(menu);
 
@@ -3348,7 +2805,7 @@
 
 	g_object_unref(sg);
 
-	gtk_widget_show(gtkwin->menu.send_as);
+	gtk_widget_show(win->menu.send_as);
 	update_send_as_selection(win);
 }
 
@@ -3691,185 +3148,6 @@
 	return TRUE;
 }
 
-static GtkItemFactoryEntry menu_items[] =
-{
-	/* Conversation menu */
-	{ N_("/_Conversation"), NULL, NULL, 0, "<Branch>" },
-
-	{ N_("/Conversation/New Instant _Message..."), "<CTL>M", menu_new_conv_cb,
-	  0, "<StockItem>", GAIM_STOCK_IM },
-
-	{ "/Conversation/sep0", NULL, NULL, 0, "<Separator>" },
-
-	{ N_("/Conversation/_Find..."), NULL, menu_find_cb, 0,
-	  "<StockItem>", GTK_STOCK_FIND },
-	{ N_("/Conversation/View _Log"), NULL, menu_view_log_cb, 0, NULL },
-	{ N_("/Conversation/_Save As..."), NULL, menu_save_as_cb, 0,
-	  "<StockItem>", GTK_STOCK_SAVE_AS },
-	{ N_("/Conversation/Clear"), "<CTL>L", menu_clear_cb, 0, "<StockItem>", GTK_STOCK_CLEAR },
-
-	{ "/Conversation/sep1", NULL, NULL, 0, "<Separator>" },
-
-	{ N_("/Conversation/Se_nd File..."), NULL, menu_send_file_cb, 0, "<StockItem>", GAIM_STOCK_FILE_TRANSFER },
-	{ N_("/Conversation/Add Buddy _Pounce..."), NULL, menu_add_pounce_cb,
-		0, NULL },
-	{ N_("/Conversation/_Get Info"), "<CTL>O", menu_get_info_cb, 0,
-	  "<StockItem>", GAIM_STOCK_INFO },
-	{ N_("/Conversation/In_vite..."), NULL, menu_invite_cb, 0,
-	  "<StockItem>", GAIM_STOCK_INVITE },
-
-	{ "/Conversation/sep2", NULL, NULL, 0, "<Separator>" },
-
-	{ N_("/Conversation/Al_ias..."), NULL, menu_alias_cb, 0,
-	  "<StockItem>", GAIM_STOCK_EDIT },
-	{ N_("/Conversation/_Block..."), NULL, menu_block_cb, 0,
-	  "<StockItem>", GAIM_STOCK_BLOCK },
-	{ N_("/Conversation/_Add..."), NULL, menu_add_remove_cb, 0,
-	  "<StockItem>", GTK_STOCK_ADD },
-	{ N_("/Conversation/_Remove..."), NULL, menu_add_remove_cb, 0,
-	  "<StockItem>", GTK_STOCK_REMOVE },
-
-	{ "/Conversation/sep3", NULL, NULL, 0, "<Separator>" },
-
-	{ N_("/Conversation/Insert Lin_k..."), NULL, menu_insert_link_cb, 0,
-	  "<StockItem>", GAIM_STOCK_LINK },
-	{ N_("/Conversation/Insert Imag_e..."), NULL, menu_insert_image_cb, 0,
-	  "<StockItem>", GAIM_STOCK_IMAGE },
-
-	{ "/Conversation/sep4", NULL, NULL, 0, "<Separator>" },
-
-	{ N_("/Conversation/_Close"), NULL, menu_close_conv_cb, 0,
-	  "<StockItem>", GTK_STOCK_CLOSE },
-
-	/* Options */
-	{ N_("/_Options"), NULL, NULL, 0, "<Branch>" },
-	{ N_("/Options/Enable _Logging"), NULL, menu_logging_cb, 0, "<CheckItem>" },
-	{ N_("/Options/Enable _Sounds"), NULL, menu_sounds_cb, 0, "<CheckItem>" },
-	{ N_("/Options/Show Formatting _Toolbars"), NULL, menu_toolbar_cb, 0, "<CheckItem>" },
-	{ N_("/Options/Show Ti_mestamps"), "F2", menu_timestamps_cb, 0, "<CheckItem>" },
-	{ N_("/Options/Show Buddy _Icon"), NULL, menu_buddyicon_cb, 0, "<CheckItem>" },
-};
-
-static const int menu_item_count =
-	sizeof(menu_items) / sizeof(*menu_items);
-
-static char *
-item_factory_translate_func (const char *path, gpointer func_data)
-{
-	return _((char *)path);
-}
-
-static GtkWidget *
-setup_menubar(GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin;
-	GtkAccelGroup *accel_group;
-
-	gtkwin = GAIM_GTK_WINDOW(win);
-
-	accel_group = gtk_accel_group_new ();
-	gtk_window_add_accel_group (GTK_WINDOW (gtkwin->window), accel_group);
-	g_object_unref (accel_group);
-
-	gtkwin->menu.item_factory =
-		gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
-
-	gtk_item_factory_set_translate_func(gtkwin->menu.item_factory,
-										item_factory_translate_func,
-										NULL, NULL);
-
-	gtk_item_factory_create_items(gtkwin->menu.item_factory, menu_item_count,
-								  menu_items, win);
-	g_signal_connect(G_OBJECT(accel_group), "accel-changed",
-									 G_CALLBACK(gaim_gtk_save_accels_cb), NULL);
-
-
-	gtkwin->menu.menubar =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory, "<main>");
-
-
-	gtkwin->menu.view_log =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Conversation/View Log"));
-
-	/* --- */
-
-	gtkwin->menu.send_file =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Conversation/Send File..."));
-
-	gtkwin->menu.add_pounce =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Conversation/Add Buddy Pounce..."));
-
-	/* --- */
-
-	gtkwin->menu.get_info =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Conversation/Get Info"));
-
-	gtkwin->menu.invite =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Conversation/Invite..."));
-
-	/* --- */
-
-	gtkwin->menu.alias =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Conversation/Alias..."));
-
-	gtkwin->menu.block =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Conversation/Block..."));
-
-	gtkwin->menu.add =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Conversation/Add..."));
-
-	gtkwin->menu.remove =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Conversation/Remove..."));
-
-	/* --- */
-
-	gtkwin->menu.insert_link =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Conversation/Insert Link..."));
-
-	gtkwin->menu.insert_image =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Conversation/Insert Image..."));
-
-	/* --- */
-
-	gtkwin->menu.logging =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Options/Enable Logging"));
-	gtkwin->menu.sounds =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Options/Enable Sounds"));
-	gtkwin->menu.show_formatting_toolbar =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Options/Show Formatting Toolbars"));
-	gtkwin->menu.show_timestamps =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Options/Show Timestamps"));
-	gtkwin->menu.show_icon =
-		gtk_item_factory_get_widget(gtkwin->menu.item_factory,
-									N_("/Options/Show Buddy Icon"));
-
-	generate_send_as_items(win, NULL);
-
-	gtkwin->menu.tray = gaim_gtk_menu_tray_new();
-	gtk_menu_shell_append(GTK_MENU_SHELL(gtkwin->menu.menubar),
-						  gtkwin->menu.tray);
-	gtk_widget_show(gtkwin->menu.tray);
-
-	gtk_widget_show(gtkwin->menu.menubar);
-
-	return gtkwin->menu.menubar;
-}
-
 static void topic_callback(GtkWidget *w, GaimGtkConversation *gtkconv)
 {
 	GaimPluginProtocolInfo *prpl_info = NULL;
@@ -4438,12 +3716,13 @@
               GaimGtkConversation *gtkconv)
 {
 	GaimConversation *conv = gtkconv->active_conv;
-	GaimConvWindow *win = conv->window;
+	GaimGtkWindow *win = gtkconv->win;
 	GaimConversation *c;
 	if (sd->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE))
 	{
 		GaimBlistNode *n = NULL;
 		GaimBuddy *b;
+		GaimGtkConversation *gtkconv = NULL;
 
 		memcpy(&n, sd->data, sizeof(n));
 
@@ -4461,19 +3740,21 @@
 		 */
 		c = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, b->name, b->account);
 		if (c != NULL) {
-			GaimConvWindow *oldwin;
-			oldwin = gaim_conversation_get_window(c);
+			GaimGtkWindow *oldwin;
+			gtkconv = GAIM_GTK_CONVERSATION(c);
+			oldwin = gtkconv->win;
 			if (oldwin != win) {
-				gaim_conv_window_remove_conversation(oldwin, c);
-				gaim_conv_window_add_conversation(win, c);
+				gaim_gtk_conv_window_remove_gtkconv(oldwin, gtkconv);
+				gaim_gtk_conv_window_add_gtkconv(win, gtkconv);
 			}
 		} else {
 			c = gaim_conversation_new(GAIM_CONV_TYPE_IM, b->account, b->name);
-			gaim_conv_window_add_conversation(win, c);
+			gtkconv = GAIM_GTK_CONVERSATION(c);
+			gaim_gtk_conv_window_add_gtkconv(win, gtkconv);
 		}
 
 		/* Make this conversation the active conversation */
-		gaim_conv_window_switch_conversation(win, c);
+		gaim_gtk_conv_window_switch_gtkconv(win, gtkconv);
 
 		gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t);
 	}
@@ -4482,6 +3763,7 @@
 		char *protocol = NULL;
 		char *username = NULL;
 		GaimAccount *account;
+		GaimGtkConversation *gtkconv;
 
 		if (gaim_gtk_parse_x_im_contact((const char *)sd->data, FALSE, &account,
 						&protocol, &username, NULL))
@@ -4495,7 +3777,8 @@
 			else
 			{
 				c = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, username);
-				gaim_conv_window_add_conversation(win, c);
+				gtkconv = GAIM_GTK_CONVERSATION(c);
+				gaim_gtk_conv_window_add_gtkconv(win, gtkconv);
 			}
 		}
 
@@ -4513,126 +3796,6 @@
 		gtk_drag_finish(dc, FALSE, FALSE, t);
 }
 
-/**************************************************************************
- * GTK+ window ops
- **************************************************************************/
-static void
-gaim_gtk_new_window(GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin;
-	GtkPositionType pos;
-	GtkWidget *testidea;
-	GtkWidget *menubar;
-
-	gtkwin = g_malloc0(sizeof(GaimGtkWindow));
-
-	win->ui_data = gtkwin;
-
-	/* Create the window. */
-	gtkwin->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-	gtk_window_set_role(GTK_WINDOW(gtkwin->window), "conversation");
-	gtk_window_set_resizable(GTK_WINDOW(gtkwin->window), TRUE);
-	gtk_container_set_border_width(GTK_CONTAINER(gtkwin->window), 0);
-	GTK_WINDOW(gtkwin->window)->allow_shrink = TRUE;
-
-	g_signal_connect(G_OBJECT(gtkwin->window), "delete_event",
-					 G_CALLBACK(close_win_cb), win);
-
-	g_signal_connect(G_OBJECT(gtkwin->window), "focus_in_event",
-					 G_CALLBACK(focus_win_cb), win);
-
-	/* Create the notebook. */
-	gtkwin->notebook = gtk_notebook_new();
-
-	pos = gaim_prefs_get_int("/gaim/gtk/conversations/tab_side");
-
-#if 0
-	gtk_notebook_set_tab_hborder(GTK_NOTEBOOK(gtkwin->notebook), 0);
-	gtk_notebook_set_tab_vborder(GTK_NOTEBOOK(gtkwin->notebook), 0);
-#endif
-	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkwin->notebook), pos);
-	gtk_notebook_set_scrollable(GTK_NOTEBOOK(gtkwin->notebook), TRUE);
-	gtk_notebook_popup_enable(GTK_NOTEBOOK(gtkwin->notebook));
-	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkwin->notebook), FALSE);
-	gtk_notebook_set_show_border(GTK_NOTEBOOK(gtkwin->notebook), FALSE);
-
-	gtk_widget_show(gtkwin->notebook);
-
-	g_signal_connect(G_OBJECT(gtkwin->notebook), "switch_page",
-					 G_CALLBACK(before_switch_conv_cb), win);
-	g_signal_connect_after(G_OBJECT(gtkwin->notebook), "switch_page",
-						   G_CALLBACK(switch_conv_cb), win);
-
-	/* Setup the tab drag and drop signals. */
-	gtk_widget_add_events(gtkwin->notebook,
-				GDK_BUTTON1_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
-	g_signal_connect(G_OBJECT(gtkwin->notebook), "button_press_event",
-					 G_CALLBACK(notebook_press_cb), win);
-	g_signal_connect(G_OBJECT(gtkwin->notebook), "button_release_event",
-					 G_CALLBACK(notebook_release_cb), win);
-
-	testidea = gtk_vbox_new(FALSE, 0);
-
-	/* Setup the menubar. */
-	menubar = setup_menubar(win);
-	gtk_box_pack_start(GTK_BOX(testidea), menubar, FALSE, TRUE, 0);
-
-	gtk_box_pack_start(GTK_BOX(testidea), gtkwin->notebook, TRUE, TRUE, 0);
-
-	gtk_container_add(GTK_CONTAINER(gtkwin->window), testidea);
-
-	gtk_widget_show(testidea);
-}
-
-static void
-gaim_gtk_destroy_window(GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(win);
-
-	gtk_widget_destroy(gtkwin->window);
-
-	g_object_unref(G_OBJECT(gtkwin->menu.item_factory));
-
-	g_free(gtkwin);
-	win->ui_data = NULL;
-}
-
-static void
-gaim_gtk_show(GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(win);
-
-	gtk_widget_show(gtkwin->window);
-}
-
-static void
-gaim_gtk_hide(GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(win);
-
-	gtk_widget_hide(gtkwin->window);
-}
-
-static void
-gaim_gtk_raise(GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(win);
-
-	gtk_widget_show(gtkwin->window);
-	gtk_window_deiconify(GTK_WINDOW(gtkwin->window));
-	gdk_window_raise(gtkwin->window->window);
-}
-
-static void
-gaim_gtk_switch_conversation(GaimConvWindow *win, GaimConversation *conv)
-{
-	GaimGtkWindow *gtkwin;
-	GaimGtkConversation *gtkconv = conv->ui_data;
-
-	gtkwin = GAIM_GTK_WINDOW(win);
-
-	gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), gtk_notebook_page_num(GTK_NOTEBOOK(gtkwin->notebook), gtkconv->tab_cont));
-}
 
 static const GtkTargetEntry te[] =
 {
@@ -4666,329 +3829,105 @@
 	return NULL;
 }
 
-static void
-gaim_gtk_add_conversation(GaimConvWindow *win, GaimConversation *conv)
-{
-	GaimGtkWindow *gtkwin;
-	GaimGtkConversation *gtkconv, *focus_gtkconv;
-	GaimConversation *focus_conv;
+/**************************************************************************
+ * Conversation UI operations
+ **************************************************************************/
+void
+gaim_gtkconv_new(GaimConversation *conv)
+{
+	GaimGtkConversation *gtkconv;
+	GaimConversationType conv_type = gaim_conversation_get_type(conv);
 	GtkWidget *pane = NULL;
 	GtkWidget *tab_cont;
-	GtkWidget *tabby, *menu_tabby;
-	GtkWidget *close_image;
-	gboolean new_ui;
-	GaimConversationType conv_type;
-	const char *name;
-	const gchar *tmp_lab;
-	gint close_button_width, close_button_height, focus_width, focus_pad;
-
-	name      = gaim_conversation_get_name(conv);
-	conv_type = gaim_conversation_get_type(conv);
-	gtkwin    = GAIM_GTK_WINDOW(win);
-
-	if (conv->ui_data != NULL) {
-		gtkconv = (GaimGtkConversation *)conv->ui_data;
-
-		tab_cont = gtkconv->tab_cont;
-
-		new_ui = FALSE;
-	} else if (conv_type == GAIM_CONV_TYPE_IM && (gtkconv = gaim_gtk_conv_find_gtkconv(conv))) {
+
+	if (conv_type == GAIM_CONV_TYPE_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);
-		gtkconv->tooltips = gtk_tooltips_new();
-
-		if (conv_type == GAIM_CONV_TYPE_IM) {
-			gtkconv->u.im = g_malloc0(sizeof(GaimGtkImPane));
-			gtkconv->u.im->a_virgin = TRUE;
-
-			pane = setup_im_pane(gtkconv);
-		}
-		else if (conv_type == GAIM_CONV_TYPE_CHAT) {
-			gtkconv->u.chat = g_malloc0(sizeof(GaimGtkChatPane));
-
-			pane = setup_chat_pane(gtkconv);
-		}
-
-		if (pane == NULL) {
-			if      (conv_type == GAIM_CONV_TYPE_CHAT) g_free(gtkconv->u.chat);
-			else if (conv_type == GAIM_CONV_TYPE_IM)   g_free(gtkconv->u.im);
-
-			g_free(gtkconv);
-			conv->ui_data = NULL;
-
-			return;
-		}
-
-		/* Setup drag-and-drop */
-		gtk_drag_dest_set(pane,
-				  GTK_DEST_DEFAULT_MOTION |
-				  GTK_DEST_DEFAULT_DROP,
-				  te, sizeof(te) / sizeof(GtkTargetEntry),
-				  GDK_ACTION_COPY);
-		gtk_drag_dest_set(pane,
-				  GTK_DEST_DEFAULT_MOTION |
-				  GTK_DEST_DEFAULT_DROP,
-				  te, sizeof(te) / sizeof(GtkTargetEntry),
-				  GDK_ACTION_COPY);
-		gtk_drag_dest_set(gtkconv->imhtml, 0,
-				  te, sizeof(te) / sizeof(GtkTargetEntry),
-				  GDK_ACTION_COPY);
-
-		gtk_drag_dest_set(gtkconv->entry, 0,
-				  te, sizeof(te) / sizeof(GtkTargetEntry),
-				  GDK_ACTION_COPY);
-
-		g_signal_connect(G_OBJECT(pane), "drag_data_received",
-				 G_CALLBACK(conv_dnd_recv), gtkconv);
-		g_signal_connect(G_OBJECT(gtkconv->imhtml), "drag_data_received",
-				 G_CALLBACK(conv_dnd_recv), gtkconv);
-		g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received",
-				 G_CALLBACK(conv_dnd_recv), gtkconv);
-
-		/* Setup the container for the tab. */
-		gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
-		g_object_set_data(G_OBJECT(tab_cont), "GaimGtkConversation", gtkconv);
-		gtk_container_set_border_width(GTK_CONTAINER(tab_cont), GAIM_HIG_BOX_SPACE);
-		gtk_container_add(GTK_CONTAINER(tab_cont), pane);
-		gtk_widget_show(pane);
-
-		new_ui = TRUE;
-
-		gtkconv->make_sound = TRUE;
-
-		if (gaim_prefs_get_bool("/gaim/gtk/conversations/show_formatting_toolbar"))
-			gtk_widget_show(gtkconv->toolbar);
-		else
-			gtk_widget_hide(gtkconv->toolbar);
-
-		gtkconv->show_timestamps = TRUE;
-		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);
 	}
 
-	gtkconv->tabby = tabby = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
-	gtkconv->menu_tabby = menu_tabby = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
-
-	/* Close button. */
-	gtkconv->close = gtk_button_new();
-	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &close_button_width, &close_button_height);
-	if (gtk_check_version(2, 4, 2) == NULL)
-	{
-		/* Need to account for extra padding around the gtkbutton */
-		gtk_widget_style_get(GTK_WIDGET(gtkconv->close),
-							 "focus-line-width", &focus_width,
-							 "focus-padding", &focus_pad,
-							 NULL);
-		close_button_width += (focus_width + focus_pad) * 2;
-		close_button_height += (focus_width + focus_pad) * 2;
+	gtkconv = g_new0(GaimGtkConversation, 1);
+	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);
+	gtkconv->tooltips = gtk_tooltips_new();
+
+	if (conv_type == GAIM_CONV_TYPE_IM) {
+		gtkconv->u.im = g_malloc0(sizeof(GaimGtkImPane));
+		gtkconv->u.im->a_virgin = TRUE;
+
+		pane = setup_im_pane(gtkconv);
+	} else if (conv_type == GAIM_CONV_TYPE_CHAT) {
+		gtkconv->u.chat = g_malloc0(sizeof(GaimGtkChatPane));
+		pane = setup_chat_pane(gtkconv);
+	}
+
+	if (pane == NULL) {
+		if (conv_type == GAIM_CONV_TYPE_CHAT)
+			g_free(gtkconv->u.chat);
+		else if (conv_type == GAIM_CONV_TYPE_IM)
+			g_free(gtkconv->u.im);
+
+		g_free(gtkconv);
+		conv->ui_data = NULL;
+		return;
 	}
-	gtk_widget_set_size_request(GTK_WIDGET(gtkconv->close),
-								close_button_width, close_button_height);
-
-	gtk_button_set_relief(GTK_BUTTON(gtkconv->close), GTK_RELIEF_NONE);
-	close_image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
-	gtk_widget_show(close_image);
-	gtk_container_add(GTK_CONTAINER(gtkconv->close), close_image);
-	gtk_tooltips_set_tip(gtkconv->tooltips, gtkconv->close,
-						 _("Close conversation"), NULL);
-
-	g_signal_connect(G_OBJECT(gtkconv->close), "clicked",
-	                 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);
-
-	/* Status icon. */
-	gtkconv->icon = gtk_image_new();
-	gtkconv->menu_icon = gtk_image_new();
-	update_tab_icon(conv);
-
-	/* Tab label. */
-	gtkconv->tab_label = gtk_label_new(tmp_lab = gaim_conversation_get_title(conv));
-#if GTK_CHECK_VERSION(2,6,0)
-	g_object_set(G_OBJECT(gtkconv->tab_label), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-	gtk_label_set_width_chars(GTK_LABEL(gtkconv->tab_label), 6);
-#endif
-	gtkconv->menu_label = gtk_label_new(gaim_conversation_get_title(conv));
-#if 0
-	gtk_misc_set_alignment(GTK_MISC(gtkconv->tab_label), 0.00, 0.5);
-	gtk_misc_set_padding(GTK_MISC(gtkconv->tab_label), 4, 0);
-#endif
-
-	/* Pack it all together. */
-	gtk_box_pack_start(GTK_BOX(tabby), gtkconv->icon, FALSE, FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(menu_tabby), gtkconv->menu_icon,
-					   FALSE, FALSE, 0);
-
-	gtk_widget_show_all(gtkconv->icon);
-	gtk_widget_show_all(gtkconv->menu_icon);
-
-	gtk_box_pack_start(GTK_BOX(tabby), gtkconv->tab_label, TRUE, TRUE, 0);
-	gtk_box_pack_start(GTK_BOX(menu_tabby), gtkconv->menu_label, TRUE, TRUE, 0);
-	gtk_widget_show(gtkconv->tab_label);
-	gtk_widget_show(gtkconv->menu_label);
-	gtk_misc_set_alignment(GTK_MISC(gtkconv->menu_label), 0, 0);
-
-	gtk_box_pack_start(GTK_BOX(tabby), gtkconv->close, FALSE, FALSE, 0);
-	if (gaim_prefs_get_bool("/gaim/gtk/conversations/close_on_tabs"))
-		gtk_widget_show(gtkconv->close);
-
-	gtk_widget_show(tabby);
-	gtk_widget_show(menu_tabby);
-
-	if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
-		gaim_gtkconv_update_buddy_icon(conv);
-
-	/* Add this pane to the conversation's notebook. */
-	gtk_notebook_append_page_menu(GTK_NOTEBOOK(gtkwin->notebook), tab_cont, tabby, menu_tabby);
-	gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(gtkwin->notebook), tab_cont, TRUE, TRUE, GTK_PACK_START);
-
-
-	gtk_widget_show(tab_cont);
-
-	if (gaim_conv_window_get_conversation_count(win) == 1) {
-		/* Er, bug in notebooks? Switch to the page manually. */
-		gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), 0);
-
-		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkwin->notebook),
-				gaim_prefs_get_bool("/gaim/gtk/conversations/tabs"));
-	}
+
+	/* Setup drag-and-drop */
+	gtk_drag_dest_set(pane,
+	                  GTK_DEST_DEFAULT_MOTION |
+	                  GTK_DEST_DEFAULT_DROP,
+	                  te, sizeof(te) / sizeof(GtkTargetEntry),
+	                  GDK_ACTION_COPY);
+	gtk_drag_dest_set(pane,
+	                  GTK_DEST_DEFAULT_MOTION |
+	                  GTK_DEST_DEFAULT_DROP,
+	                  te, sizeof(te) / sizeof(GtkTargetEntry),
+	                  GDK_ACTION_COPY);
+	gtk_drag_dest_set(gtkconv->imhtml, 0,
+	                  te, sizeof(te) / sizeof(GtkTargetEntry),
+	                  GDK_ACTION_COPY);
+
+	gtk_drag_dest_set(gtkconv->entry, 0,
+	                  te, sizeof(te) / sizeof(GtkTargetEntry),
+	                  GDK_ACTION_COPY);
+
+	g_signal_connect(G_OBJECT(pane), "drag_data_received",
+	                 G_CALLBACK(conv_dnd_recv), gtkconv);
+	g_signal_connect(G_OBJECT(gtkconv->imhtml), "drag_data_received",
+	                 G_CALLBACK(conv_dnd_recv), gtkconv);
+	g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received",
+	                 G_CALLBACK(conv_dnd_recv), gtkconv);
+
+	/* Setup the container for the tab. */
+	gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
+	g_object_set_data(G_OBJECT(tab_cont), "GaimGtkConversation", gtkconv);
+	gtk_container_set_border_width(GTK_CONTAINER(tab_cont), GAIM_HIG_BOX_SPACE);
+	gtk_container_add(GTK_CONTAINER(tab_cont), pane);
+	gtk_widget_show(pane);
+
+	gtkconv->make_sound = TRUE;
+
+	if (gaim_prefs_get_bool("/gaim/gtk/conversations/show_formatting_toolbar"))
+		gtk_widget_show(gtkconv->toolbar);
 	else
-		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkwin->notebook), TRUE);
-
-	focus_conv = g_list_nth_data(gaim_conv_window_get_conversations(win),
-			gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkwin->notebook)));
-	focus_gtkconv = GAIM_GTK_CONVERSATION(focus_conv);
-	gtk_widget_grab_focus(focus_gtkconv->entry);
-
-	if (!new_ui)
-		g_object_unref(gtkconv->tab_cont);
-
-	if (gaim_conv_window_get_conversation_count(win) == 1)
-		g_timeout_add(0, (GSourceFunc)update_send_as_selection, win);
-}
-
-static void
-gaim_gtk_remove_conversation(GaimConvWindow *win, GaimConversation *conv)
-{
-	GaimGtkWindow *gtkwin;
-	GaimGtkConversation *gtkconv;
-	unsigned int index;
-	GaimConversationType conv_type;
-
-	conv_type = gaim_conversation_get_type(conv);
-	gtkwin  = GAIM_GTK_WINDOW(win);
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-	index = gtk_notebook_page_num(GTK_NOTEBOOK(gtkwin->notebook), gtkconv->tab_cont);
-
-	g_object_ref(gtkconv->tab_cont);
-	gtk_object_sink(GTK_OBJECT(gtkconv->tab_cont));
-
-	gtk_notebook_remove_page(GTK_NOTEBOOK(gtkwin->notebook), index);
-
-	/* go back to tabless if need be */
-	if (gaim_conv_window_get_conversation_count(win) <= 2) {
-		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkwin->notebook),
-				gaim_prefs_get_bool("/gaim/gtk/conversations/tabs"));
-	}
-
-
-	/* If this window is setup with an inactive gc, regenerate the menu. */
-	if (conv_type == GAIM_CONV_TYPE_IM &&
-		gaim_conversation_get_gc(conv) == NULL) {
-
-		generate_send_as_items(win, conv);
-	}
-}
-
-GaimGtkConversation *
-gaim_gtk_get_gtkconv_at_index(const GaimConvWindow *win, int index)
-{
-	GaimGtkWindow *gtkwin;
-	GtkWidget *tab_cont;
-
-	gtkwin = GAIM_GTK_WINDOW(win);
-
-	if (index == -1)
-		index = 0;
-	tab_cont = gtk_notebook_get_nth_page(GTK_NOTEBOOK(gtkwin->notebook), index);
-	return g_object_get_data(G_OBJECT(tab_cont), "GaimGtkConversation");
-}
-
-static GaimConversation *
-gaim_gtk_get_active_conversation(const GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin;
-	GaimGtkConversation *gtkconv;
-	int index;
-	GtkWidget *tab_cont;
-
-	gtkwin = GAIM_GTK_WINDOW(win);
-
-	index = gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkwin->notebook));
-	if (index == -1)
-		index = 0;
-	tab_cont = gtk_notebook_get_nth_page(GTK_NOTEBOOK(gtkwin->notebook), index);
-	if (!tab_cont)
-		return NULL;
-	gtkconv = g_object_get_data(G_OBJECT(tab_cont), "GaimGtkConversation");
-	return gtkconv->active_conv;
-}
-
-static gboolean
-gaim_gtk_has_focus(GaimConvWindow *win)
-{
-	GaimGtkWindow *gtkwin;
-	gboolean has_focus = FALSE;
-
-	gtkwin = GAIM_GTK_WINDOW(win);
-	g_object_get(G_OBJECT(gtkwin->window), "has-toplevel-focus", &has_focus, NULL);
-
-	return has_focus;
-}
-
-static GaimConvWindowUiOps window_ui_ops =
-{
-	gaim_gtk_conversations_get_conv_ui_ops,
-	gaim_gtk_new_window,
-	gaim_gtk_destroy_window,
-	gaim_gtk_show,
-	gaim_gtk_hide,
-	gaim_gtk_raise,
-	gaim_gtk_switch_conversation,
-	gaim_gtk_add_conversation,
-	gaim_gtk_remove_conversation,
-	gaim_gtk_get_active_conversation,
-	gaim_gtk_has_focus
-};
-
-GaimConvWindowUiOps *
-gaim_gtk_conversations_get_win_ui_ops(void)
-{
-	return &window_ui_ops;
-}
-
-/**************************************************************************
- * Conversation UI operations
- **************************************************************************/
+		gtk_widget_hide(gtkconv->toolbar);
+
+	gtkconv->show_timestamps = TRUE;
+	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);
+
+	gaim_gtkconv_placement_place(gtkconv);
+}
+
 static void
 gaim_gtkconv_destroy(GaimConversation *conv)
 {
@@ -4999,6 +3938,11 @@
 	if (gtkconv->convs)
 		return;
 
+	gaim_gtk_conv_window_remove_gtkconv(gtkconv->win, gtkconv);
+	/* should we be doing this here or in gaim_gtk_conv_window_remove_gtkconv()? */
+	if (!gtkconv->win->gtkconvs)
+		gaim_gtk_conv_window_destroy(gtkconv->win);
+
 	/* If the "Save Conversation" or "Save Icon" dialogs are open then close them */
 	gaim_request_close_with_handle(conv);
 
@@ -5013,8 +3957,7 @@
 			g_object_unref(G_OBJECT(gtkconv->u.im->anim));
 
 		g_free(gtkconv->u.im);
-	}
-	else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
+	} else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
 		gaim_signals_disconnect_by_handle(gtkconv->u.chat);
 		g_free(gtkconv->u.chat);
 	}
@@ -5138,7 +4081,7 @@
 						time_t mtime)
 {
 	GaimGtkConversation *gtkconv;
-	GaimConvWindow *win;
+	GaimGtkWindow *win;
 	GaimConnection *gc;
 	GaimAccount *account;
 	GaimPluginProtocolInfo *prpl_info;
@@ -5155,10 +4098,14 @@
 	size_t length = strlen(message) + 1;
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
+
+	/* Set the active conversation to the one that just messaged us. */
+	/* TODO: consider not doing this if the account is offline or something */
 	gtkconv->active_conv = conv;
+
 	gc = gaim_conversation_get_gc(conv);
 	account = gaim_conversation_get_account(conv);
-	win = gaim_conversation_get_window(conv);
+	win = gtkconv->win;
 	prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
 
 	line_count = gtk_text_buffer_get_line_count(
@@ -5305,7 +4252,7 @@
 		     gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
 
 			/* Bold buddies to make them stand out from non-buddies. */
-			if (flags & GAIM_MESSAGE_SEND || 
+			if (flags & GAIM_MESSAGE_SEND ||
 			    flags & GAIM_MESSAGE_NICK ||
 			    gaim_find_buddy(account, name) != NULL) {
 				g_snprintf(buf2, BUF_LONG,
@@ -5610,17 +4557,16 @@
 	g_free(alias);
 }
 
-static gboolean
+gboolean
 gaim_gtkconv_has_focus(GaimConversation *conv)
 {
-	GaimConvWindow *win;
-	GaimGtkWindow *gtkwin;
+	GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv);
+	GaimGtkWindow *win;
 	gboolean has_focus;
 
-	win = gaim_conversation_get_window(conv);
-	gtkwin = GAIM_GTK_WINDOW(win);
-
-	g_object_get(G_OBJECT(gtkwin->window), "has-toplevel-focus", &has_focus, NULL);
+	win = gtkconv->win;
+
+	g_object_get(G_OBJECT(win->window), "has-toplevel-focus", &has_focus, NULL);
 
 	return has_focus;
 }
@@ -5784,22 +4730,209 @@
 	smiley->loader = NULL;
 }
 
+/*
+ * Makes sure all the menu items and all the buttons are hidden/shown and
+ * sensitive/insensitive.  This is called after changing tabs and when an
+ * account signs on or off.
+ */
+static void
+gray_stuff_out(GaimGtkConversation *gtkconv)
+{
+	GaimGtkWindow *win;
+	GaimConversation *conv = gtkconv->active_conv;
+	GaimConnection *gc;
+	GaimPluginProtocolInfo *prpl_info = NULL;
+	GdkPixbuf *window_icon = NULL;
+	GtkIMHtmlButtons buttons;
+	GaimAccount *account;
+
+	win     = gaim_gtkconv_get_window(gtkconv);
+	gc      = gaim_conversation_get_gc(conv);
+	account = gaim_conversation_get_account(conv);
+
+	if (gc != NULL)
+		prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
+
+	if (win->menu.send_as != NULL)
+		g_timeout_add(0, (GSourceFunc)update_send_as_selection, win);
+
+	/*
+	 * Handle hiding and showing stuff based on what type of conv this is.
+	 * Stuff that Gaim IMs support in general should be shown for IM
+	 * conversations.  Stuff that Gaim chats support in general should be
+	 * shown for chat conversations.  It doesn't matter whether the PRPL
+	 * supports it or not--that only affects if the button or menu item
+	 * is sensitive or not.
+	 */
+	if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) {
+		/* Show stuff that applies to IMs, hide stuff that applies to chats */
+
+		/* Deal with menu items */
+		gtk_widget_show(win->menu.view_log);
+		gtk_widget_show(win->menu.send_file);
+		gtk_widget_show(win->menu.add_pounce);
+		gtk_widget_show(win->menu.get_info);
+		gtk_widget_hide(win->menu.invite);
+		gtk_widget_show(win->menu.alias);
+		gtk_widget_show(win->menu.block);
+
+		if (gaim_find_buddy(account, gaim_conversation_get_name(conv)) == NULL) {
+			gtk_widget_show(win->menu.add);
+			gtk_widget_hide(win->menu.remove);
+		} else {
+			gtk_widget_show(win->menu.remove);
+			gtk_widget_hide(win->menu.add);
+		}
+
+		gtk_widget_show(win->menu.insert_link);
+		gtk_widget_show(win->menu.insert_image);
+		gtk_widget_show(win->menu.show_icon);
+	} else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
+		/* Show stuff that applies to Chats, hide stuff that applies to IMs */
+
+		/* Deal with menu items */
+		gtk_widget_show(win->menu.view_log);
+		gtk_widget_hide(win->menu.send_file);
+		gtk_widget_hide(win->menu.add_pounce);
+		gtk_widget_hide(win->menu.get_info);
+		gtk_widget_show(win->menu.invite);
+		gtk_widget_show(win->menu.alias);
+		gtk_widget_hide(win->menu.block);
+		gtk_widget_hide(win->menu.show_icon);
+
+		if (gaim_blist_find_chat(account, gaim_conversation_get_name(conv)) == NULL) {
+			/* If the chat is NOT in the buddy list */
+			gtk_widget_show(win->menu.add);
+			gtk_widget_hide(win->menu.remove);
+		} else {
+			/* If the chat IS in the buddy list */
+			gtk_widget_hide(win->menu.add);
+			gtk_widget_show(win->menu.remove);
+		}
+
+		gtk_widget_show(win->menu.insert_link);
+		gtk_widget_hide(win->menu.insert_image);
+	}
+
+	/*
+	 * Handle graying stuff out based on whether an account is connected
+	 * and what features that account supports.
+	 */
+	if ((gc != NULL) &&
+	    ( (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_CHAT) ||
+	      !gaim_conv_chat_has_left(GAIM_CONV_CHAT(conv)) )) {
+		/* Account is online */
+		/* Deal with the toolbar */
+		      if (conv->features & GAIM_CONNECTION_HTML) {
+			      buttons = GTK_IMHTML_ALL;    /* Everything on */
+			      if (!(prpl_info->options & OPT_PROTO_IM_IMAGE) ||
+			          conv->features & GAIM_CONNECTION_NO_IMAGES)
+				      buttons &= ~GTK_IMHTML_IMAGE;
+			      if (conv->features & GAIM_CONNECTION_NO_BGCOLOR)
+				      buttons &= ~GTK_IMHTML_BACKCOLOR;
+			      if (conv->features & GAIM_CONNECTION_NO_FONTSIZE) {
+				      buttons &= ~GTK_IMHTML_GROW;
+				      buttons &= ~GTK_IMHTML_SHRINK;
+			      }
+			      if (conv->features & GAIM_CONNECTION_NO_URLDESC)
+				      buttons &= ~GTK_IMHTML_LINKDESC;
+		      } else {
+			      buttons = GTK_IMHTML_SMILEY;
+		      }
+		      gtk_imhtml_set_format_functions(GTK_IMHTML(gtkconv->entry), buttons);
+		      gtk_imhtmltoolbar_associate_smileys(GTK_IMHTMLTOOLBAR(gtkconv->toolbar), gaim_account_get_protocol_id(account));
+
+		/* Deal with menu items */
+		      gtk_widget_set_sensitive(win->menu.view_log, TRUE);
+		      gtk_widget_set_sensitive(win->menu.add_pounce, TRUE);
+		      gtk_widget_set_sensitive(win->menu.get_info, (prpl_info->get_info != NULL));
+		      gtk_widget_set_sensitive(win->menu.invite, (prpl_info->chat_invite != NULL));
+		      gtk_widget_set_sensitive(win->menu.block, (prpl_info->add_deny != NULL));
+		      gtk_widget_set_sensitive(win->menu.insert_link, (conv->features & GAIM_CONNECTION_HTML));
+		      gtk_widget_set_sensitive(win->menu.insert_image, (prpl_info->options & OPT_PROTO_IM_IMAGE));
+
+		      if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) {
+			      gtk_widget_set_sensitive(win->menu.add, (prpl_info->add_buddy != NULL));
+			      gtk_widget_set_sensitive(win->menu.remove, (prpl_info->remove_buddy != NULL));
+			      gtk_widget_set_sensitive(win->menu.send_file,
+			                               (prpl_info->send_file != NULL && (!prpl_info->can_receive_file ||
+				                               prpl_info->can_receive_file(gc, gaim_conversation_get_name(conv)))));
+			      gtk_widget_set_sensitive(win->menu.alias,
+			                               (gaim_find_buddy(account, gaim_conversation_get_name(conv)) != NULL));
+		      } else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
+			      gtk_widget_set_sensitive(win->menu.add, (prpl_info->join_chat != NULL));
+			      gtk_widget_set_sensitive(win->menu.remove, (prpl_info->join_chat != NULL));
+			      gtk_widget_set_sensitive(win->menu.alias,
+			                               (gaim_blist_find_chat(account, gaim_conversation_get_name(conv)) != NULL));
+		      }
+
+		/* Deal with chat userlist buttons */
+		      if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)
+		      {
+			      gtk_widget_set_sensitive(gtkconv->u.chat->userlist_im, TRUE);
+			      gtk_widget_set_sensitive(gtkconv->u.chat->userlist_ignore, TRUE);
+			      gtk_widget_set_sensitive(gtkconv->u.chat->userlist_info, (prpl_info->get_info != NULL));
+		      }
+	      } else {
+		/* Account is offline */
+		/* Or it's a chat that we've left. */
+
+		/* Then deal with menu items */
+		      gtk_widget_set_sensitive(win->menu.view_log, TRUE);
+		      gtk_widget_set_sensitive(win->menu.send_file, FALSE);
+		      gtk_widget_set_sensitive(win->menu.add_pounce, TRUE);
+		      gtk_widget_set_sensitive(win->menu.get_info, FALSE);
+		      gtk_widget_set_sensitive(win->menu.invite, FALSE);
+		      gtk_widget_set_sensitive(win->menu.alias, FALSE);
+		      gtk_widget_set_sensitive(win->menu.block, FALSE);
+		      gtk_widget_set_sensitive(win->menu.add, FALSE);
+		      gtk_widget_set_sensitive(win->menu.remove, FALSE);
+		      gtk_widget_set_sensitive(win->menu.insert_link, TRUE);
+		      gtk_widget_set_sensitive(win->menu.insert_image, FALSE);
+
+		/* Deal with chat userlist buttons */
+		      if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)
+		      {
+			      gtk_widget_set_sensitive(gtkconv->u.chat->userlist_im, FALSE);
+			      gtk_widget_set_sensitive(gtkconv->u.chat->userlist_ignore, FALSE);
+			      gtk_widget_set_sensitive(gtkconv->u.chat->userlist_info, FALSE);
+		      }
+	      }
+
+	/*
+	 * Update the window's icon
+	 */
+	if ((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) &&
+	    (gtkconv->u.im->anim))
+	{
+		window_icon =
+			gdk_pixbuf_animation_get_static_image(gtkconv->u.im->anim);
+		g_object_ref(window_icon);
+	} else {
+		window_icon = gaim_gtkconv_get_tab_icon(conv, FALSE);
+	}
+	gtk_window_set_icon(GTK_WINDOW(win->window), window_icon);
+	if (window_icon != NULL)
+		g_object_unref(G_OBJECT(window_icon));
+}
+
 
 static void
 gaim_gtkconv_updated(GaimConversation *conv, GaimConvUpdateType type)
 {
-	GaimConvWindow *win;
-	GaimGtkWindow *gtkwin;
+	GaimGtkWindow *win;
 	GaimGtkConversation *gtkconv;
 	GaimGtkChatPane *gtkchat;
 	GaimConvChat *chat;
 
 	g_return_if_fail(conv != NULL);
 
-	win     = gaim_conversation_get_window(conv);
-	gtkwin  = GAIM_GTK_WINDOW(win);
 	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)
 	{
@@ -5876,13 +5009,13 @@
 		else
 			gtk_label_set_text(GTK_LABEL(gtkconv->tab_label), title);
 
-		if (conv == gaim_conv_window_get_active_conversation(win))
+		if (conv == gaim_gtk_conv_window_get_active_conversation(win))
 			update_typing_icon(gtkconv);
 
 		if (type == GAIM_CONV_UPDATE_TITLE) {
 			gtk_label_set_text(GTK_LABEL(gtkconv->menu_label), title);
-			if (conv == gaim_conv_window_get_active_conversation(win))
-				gtk_window_set_title(GTK_WINDOW(gtkwin->window), title);
+			if (conv == gaim_gtk_conv_window_get_active_conversation(win))
+				gtk_window_set_title(GTK_WINDOW(win->window), title);
 		}
 
 		g_free(title);
@@ -5902,7 +5035,7 @@
 	else if (type == GAIM_CONV_ACCOUNT_ONLINE ||
 			 type == GAIM_CONV_ACCOUNT_OFFLINE)
 	{
-		gray_stuff_out(GAIM_GTK_CONVERSATION(gaim_conv_window_get_active_conversation(win)));
+		gray_stuff_out(GAIM_GTK_CONVERSATION(gaim_gtk_conv_window_get_active_conversation(win)));
 		generate_send_as_items(win, NULL);
 		update_tab_icon(conv);
 		gaim_conversation_autoset_title(conv);
@@ -5929,6 +5062,7 @@
 
 static GaimConversationUiOps conversation_ui_ops =
 {
+	gaim_gtkconv_new,
 	gaim_gtkconv_destroy,            /* destroy_conversation */
 	gaim_gtkconv_write_chat,         /* write_chat           */
 	gaim_gtkconv_write_im,           /* write_im             */
@@ -5938,7 +5072,6 @@
 	gaim_gtkconv_chat_remove_user,   /* chat_remove_user     */
 	gaim_gtkconv_chat_remove_users,  /* chat_remove_users    */
 	gaim_gtkconv_chat_update_user,   /* chat_update_user     */
-	NULL,                            /* update_progress      */
 	gaim_gtkconv_has_focus,          /* has_focus            */
 	gaim_gtkconv_custom_smiley_add,  /* custom_smiley_add */
 	gaim_gtkconv_custom_smiley_write, /* custom_smiley_write */
@@ -5959,7 +5092,7 @@
 gaim_gtkconv_update_buddy_icon(GaimConversation *conv)
 {
 	GaimGtkConversation *gtkconv;
-	GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv));
+	GaimGtkWindow *win;
 
 	GdkPixbufLoader *loader;
 	GdkPixbufAnimation *anim;
@@ -5987,6 +5120,7 @@
 	g_return_if_fail(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM);
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
+	win = gtkconv->win;
 
 	if (!gtkconv->u.im->show_icon)
 		return;
@@ -6105,56 +5239,27 @@
 
 	/* The buddy icon code needs badly to be fixed. */
 	buf = gdk_pixbuf_animation_get_static_image(gtkconv->u.im->anim);
-	if(conv == gaim_conv_window_get_active_conversation(gaim_conversation_get_window(conv)))
-		gtk_window_set_icon(GTK_WINDOW(gtkwin->window), buf);
+	if(conv == gaim_gtk_conv_window_get_active_conversation(gtkconv->win))
+		gtk_window_set_icon(GTK_WINDOW(win->window), buf);
 }
 
 void
 gaim_gtkconv_update_buttons_by_protocol(GaimConversation *conv)
 {
-	GaimConvWindow *win;
+	GaimGtkWindow *win;
 
 	if (!GAIM_IS_GTK_CONVERSATION(conv))
 		return;
 
-	win = gaim_conversation_get_window(conv);
-
-	if (win != NULL && gaim_conv_window_get_active_conversation(win) == conv)
+	win = GAIM_GTK_CONVERSATION(conv)->win;
+
+	if (win != NULL && gaim_gtk_conv_window_is_active_conversation(conv))
 		gray_stuff_out(GAIM_GTK_CONVERSATION(conv));
 }
 
-GaimConvWindow *
-gaim_gtkwin_get_at_xy(int x, int y)
-{
-	GaimConvWindow *win = NULL;
-	GaimGtkWindow *gtkwin;
-	GdkWindow *gdkwin;
-	GList *l;
-
-	gdkwin = gdk_window_at_pointer(&x, &y);
-
-	if (gdkwin)
-		gdkwin = gdk_window_get_toplevel(gdkwin);
-
-	for (l = gaim_get_windows(); l != NULL; l = l->next) {
-		win = (GaimConvWindow *)l->data;
-
-		if (!GAIM_IS_GTK_WINDOW(win))
-			continue;
-
-		gtkwin = GAIM_GTK_WINDOW(win);
-
-		if (gdkwin == gtkwin->window->window)
-			return win;
-	}
-
-	return NULL;
-}
-
 int
-gaim_gtkconv_get_tab_at_xy(GaimConvWindow *win, int x, int y)
-{
-	GaimGtkWindow *gtkwin;
+gaim_gtkconv_get_tab_at_xy(GaimGtkWindow *win, int x, int y)
+{
 	gint nb_x, nb_y, x_rel, y_rel;
 	GtkNotebook *notebook;
 	GtkWidget *page, *tab;
@@ -6162,13 +5267,9 @@
 	gint count;
 	gboolean horiz;
 
-	if (!GAIM_IS_GTK_WINDOW(win))
-		return -1;
-
-	gtkwin = GAIM_GTK_WINDOW(win);
-	notebook = GTK_NOTEBOOK(gtkwin->notebook);
-
-	gdk_window_get_origin(gtkwin->notebook->window, &nb_x, &nb_y);
+	notebook = GTK_NOTEBOOK(win->notebook);
+
+	gdk_window_get_origin(win->notebook->window, &nb_x, &nb_y);
 	x_rel = x - nb_x;
 	y_rel = y - nb_y;
 
@@ -6258,20 +5359,14 @@
 {
 	GList *l;
 	GtkPositionType pos;
-	GaimConvWindow *win;
-	GaimGtkWindow *gtkwin;
+	GaimGtkWindow *win;
 
 	pos = GPOINTER_TO_INT(value);
 
-	for (l = gaim_get_windows(); l != NULL; l = l->next) {
-		win = (GaimConvWindow *)l->data;
-
-		if (!GAIM_IS_GTK_WINDOW(win))
-			continue;
-
-		gtkwin = GAIM_GTK_WINDOW(win);
-
-		gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkwin->notebook), pos);
+	for (l = gaim_gtk_conv_windows_get_list(); l != NULL; l = l->next) {
+		win = l->data;
+
+		gtk_notebook_set_tab_pos(GTK_NOTEBOOK(win->notebook), pos);
 	}
 }
 
@@ -6282,8 +5377,7 @@
 	GList *l;
 	GaimConversation *conv;
 	GaimGtkConversation *gtkconv;
-	GaimConvWindow *win;
-	GaimGtkWindow *gtkwin;
+	GaimGtkWindow *win;
 
 	for (l = gaim_get_conversations(); l != NULL; l = l->next)
 	{
@@ -6293,12 +5387,11 @@
 			continue;
 
 		gtkconv = GAIM_GTK_CONVERSATION(conv);
-		win     = gaim_conversation_get_window(conv);
-		gtkwin  = GAIM_GTK_WINDOW(win);
+		win     = gtkconv->win;
 
 		gtk_check_menu_item_set_active(
-				GTK_CHECK_MENU_ITEM(gtkwin->menu.show_formatting_toolbar),
-				(gboolean)GPOINTER_TO_INT(value));
+		        GTK_CHECK_MENU_ITEM(win->menu.show_formatting_toolbar),
+		        (gboolean)GPOINTER_TO_INT(value));
 
 		if ((gboolean)GPOINTER_TO_INT(value))
 			gtk_widget_show(gtkconv->toolbar);
@@ -6314,7 +5407,7 @@
 	GList *l;
 	GaimConversation *conv;
 	GaimGtkConversation *gtkconv;
-	GaimConvWindow *win;
+	GaimGtkWindow *win;
 
 	if (!gaim_prefs_get_bool("/gaim/gtk/conversations/im/show_buddy_icons"))
 		return;
@@ -6327,9 +5420,9 @@
 	}
 
 	/* Now either stop or start animation for the active conversation in each window */
-	for (l = gaim_get_windows(); l != NULL; l = l->next) {
-		win = (GaimConvWindow *)l->data;
-		conv = gaim_conv_window_get_active_conversation(win);
+	for (l = gaim_gtk_conv_windows_get_list(); l != NULL; l = l->next) {
+		win = l->data;
+		conv = gaim_gtk_conv_window_get_active_conversation(win);
 		gaim_gtkconv_update_buddy_icon(conv);
 	}
 }
@@ -6357,12 +5450,12 @@
 	if (strcmp(name, "/gaim/gtk/conversations/placement"))
 		return;
 
-	func = gaim_conv_placement_get_fnc(value);
+	func = gaim_gtkconv_placement_get_fnc(value);
 
 	if (func == NULL)
 		return;
 
-	gaim_conv_placement_set_current_func(func);
+	gaim_gtkconv_placement_set_current_func(func);
 }
 
 void *
@@ -6465,6 +5558,8 @@
 	gaim_cmd_register("help", "w", GAIM_CMD_P_DEFAULT,
 	                  GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, NULL,
 	                  help_command_cb, _("help &lt;command&gt;:  Help on a specific command."), NULL);
+
+	gaim_conversations_set_ui_ops(&conversation_ui_ops);
 }
 
 void
@@ -6473,3 +5568,1330 @@
 	gaim_prefs_disconnect_by_handle(gaim_gtk_conversations_get_handle());
 	gaim_signals_unregister_by_instance(gaim_gtk_conversations_get_handle());
 }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* down here is where gtkconvwin.c ought to start. except they share like every freaking function,
+ * and touch each others' private members all day long */
+
+/**
+ * @file gtkconvwin.c GTK+ Conversation Window API
+ * @ingroup gtkui
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include "internal.h"
+#include "gtkgaim.h"
+
+
+#include <gdk/gdkkeysyms.h>
+
+#include "account.h"
+#include "cmds.h"
+#include "debug.h"
+#include "imgstore.h"
+#include "log.h"
+#include "notify.h"
+#include "prpl.h"
+#include "request.h"
+#include "util.h"
+
+#include "gtkdnd-hints.h"
+#include "gtkblist.h"
+#include "gtkconv.h"
+#include "gtkdialogs.h"
+#include "gtkmenutray.h"
+#include "gtkpounce.h"
+#include "gtkprefs.h"
+#include "gtkprivacy.h"
+#include "gtkutils.h"
+#include "gtkstock.h"
+#include "gtkimhtml.h"
+#include "gtkimhtmltoolbar.h"
+
+
+
+
+
+static void
+do_close(GtkWidget *w, int resp, GaimGtkWindow *win)
+{
+	gtk_widget_destroy(warn_close_dialog);
+	warn_close_dialog = NULL;
+
+	if (resp == GTK_RESPONSE_OK)
+		gaim_gtk_conv_window_destroy(win);
+}
+
+static void
+build_warn_close_dialog(GaimGtkWindow *gtkwin)
+{
+	GtkWidget *label;
+	GtkWidget *vbox, *hbox;
+	GtkWidget *img;
+
+	g_return_if_fail(warn_close_dialog == NULL);
+
+
+	warn_close_dialog = gtk_dialog_new_with_buttons(
+	                                                 _("Confirm close"),
+	                                                 GTK_WINDOW(gtkwin->window), GTK_DIALOG_MODAL,
+	                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+	                                                 GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL);
+
+	gtk_dialog_set_default_response(GTK_DIALOG(warn_close_dialog),
+	                                GTK_RESPONSE_OK);
+
+	gtk_container_set_border_width(GTK_CONTAINER(warn_close_dialog),
+	                               6);
+	gtk_window_set_resizable(GTK_WINDOW(warn_close_dialog), FALSE);
+	gtk_dialog_set_has_separator(GTK_DIALOG(warn_close_dialog),
+	                             FALSE);
+
+	/* Setup the outside spacing. */
+	vbox = GTK_DIALOG(warn_close_dialog)->vbox;
+
+	gtk_box_set_spacing(GTK_BOX(vbox), 12);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+
+	img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_WARNING,
+	                               GTK_ICON_SIZE_DIALOG);
+	/* Setup the inner hbox and put the dialog's icon in it. */
+	hbox = gtk_hbox_new(FALSE, 12);
+	gtk_container_add(GTK_CONTAINER(vbox), hbox);
+	gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
+	gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
+
+	/* Setup the right vbox. */
+	vbox = gtk_vbox_new(FALSE, 12);
+	gtk_container_add(GTK_CONTAINER(hbox), vbox);
+
+	label = gtk_label_new(_("You have unread messages. Are you sure you want to close the window?"));
+	gtk_widget_set_size_request(label, 350, -1);
+	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+
+	/* Connect the signals. */
+	g_signal_connect(G_OBJECT(warn_close_dialog), "response",
+	                 G_CALLBACK(do_close), gtkwin);
+
+}
+
+/**************************************************************************
+ * Callbacks
+ **************************************************************************/
+
+static gboolean
+close_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d)
+{
+	GaimGtkWindow *win = d;
+	GList *l, *j;
+
+	/* If there are unread messages then show a warning dialog */
+	for (l = gaim_gtk_conv_window_get_gtkconvs(win);
+	     l != NULL; l = l->next)
+	{
+		GaimGtkConversation *gtkconv = l->data;
+
+		for (j = gtkconv->convs; j != NULL; j = j->next) {
+			GaimConversation *conv = j->data;
+			if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM &&
+			    gaim_conversation_get_unseen(conv) == GAIM_UNSEEN_TEXT)
+			{
+				build_warn_close_dialog(win);
+				gtk_widget_show_all(warn_close_dialog);
+
+				return TRUE;
+			}
+		}
+	}
+
+	gaim_gtk_conv_window_destroy(win);
+
+	return TRUE;
+}
+
+/*
+ * When a conversation window is focused, we know the user
+ * has looked at it so we know there are no longer unseen
+ * messages.
+ */
+static gint
+focus_win_cb(GtkWidget *w, GdkEventFocus *e, gpointer d)
+{
+	GaimGtkWindow *win = d;
+	GaimConversation *conv = gaim_gtk_conv_window_get_active_conversation(win);
+
+	gaim_conversation_set_unseen(conv, GAIM_UNSEEN_NONE);
+
+	return FALSE;
+}
+
+/* Courtesy of Galeon! */
+static void
+tab_close_button_state_changed_cb(GtkWidget *widget, GtkStateType prev_state)
+{
+	if (GTK_WIDGET_STATE(widget) == GTK_STATE_ACTIVE)
+		gtk_widget_set_state(widget, GTK_STATE_NORMAL);
+}
+
+
+
+
+static void
+notebook_init_grab(GaimGtkWindow *gtkwin, GtkWidget *widget)
+{
+	static GdkCursor *cursor = NULL;
+
+	gtkwin->in_drag = TRUE;
+
+	if (gtkwin->drag_leave_signal) {
+		g_signal_handler_disconnect(G_OBJECT(widget),
+		                            gtkwin->drag_leave_signal);
+		gtkwin->drag_leave_signal = 0;
+	}
+
+	if (cursor == NULL)
+		cursor = gdk_cursor_new(GDK_FLEUR);
+
+	/* Grab the pointer */
+	gtk_grab_add(gtkwin->notebook);
+#ifndef _WIN32
+	/* Currently for win32 GTK+ (as of 2.2.1), gdk_pointer_is_grabbed will
+	   always be true after a button press. */
+	if (!gdk_pointer_is_grabbed())
+#endif
+		gdk_pointer_grab(gtkwin->notebook->window, FALSE,
+		                 GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
+		                 NULL, cursor, GDK_CURRENT_TIME);
+}
+
+static gboolean
+notebook_motion_cb(GtkWidget *widget, GdkEventButton *e, GaimGtkWindow *win)
+{
+
+	/*
+	* Make sure the user moved the mouse far enough for the
+	* drag to be initiated.
+	*/
+	if (win->in_predrag) {
+		if (e->x_root <  win->drag_min_x ||
+		    e->x_root >= win->drag_max_x ||
+		    e->y_root <  win->drag_min_y ||
+		    e->y_root >= win->drag_max_y) {
+
+			    win->in_predrag = FALSE;
+			    notebook_init_grab(win, widget);
+		    }
+	}
+	else { /* Otherwise, draw the arrows. */
+		GaimGtkWindow *dest_win;
+		GtkNotebook *dest_notebook;
+		GtkWidget *tab;
+		gint nb_x, nb_y, page_num;
+		gint arrow1_x, arrow1_y, arrow2_x, arrow2_y;
+		gboolean horiz_tabs = FALSE;
+
+		/* Get the window that the cursor is over. */
+		dest_win = gaim_gtk_conv_window_get_at_xy(e->x_root, e->y_root);
+
+		if (dest_win == NULL) {
+			dnd_hints_hide_all();
+
+			return TRUE;
+		}
+
+
+		dest_notebook = GTK_NOTEBOOK(dest_win->notebook);
+
+		gdk_window_get_origin(GTK_WIDGET(dest_notebook)->window, &nb_x, &nb_y);
+
+		arrow1_x = arrow2_x = nb_x;
+		arrow1_y = arrow2_y = nb_y;
+
+		page_num = gaim_gtkconv_get_tab_at_xy(dest_win,
+		                                      e->x_root, e->y_root);
+
+		if (gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_TOP ||
+		    gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_BOTTOM) {
+
+			    horiz_tabs = TRUE;
+		    }
+
+		tab = gaim_gtk_conv_window_get_gtkconv_at_index(dest_win, page_num)->tabby;
+
+		if (horiz_tabs) {
+			arrow1_x = arrow2_x = nb_x + tab->allocation.x;
+
+			if ((gpointer)win == (gpointer)dest_win && win->drag_tab < page_num) {
+				arrow1_x += tab->allocation.width;
+				arrow2_x += tab->allocation.width;
+			}
+
+			arrow1_y = nb_y + tab->allocation.y;
+			arrow2_y = nb_y + tab->allocation.y +
+				tab->allocation.height;
+		} else {
+			arrow1_x = nb_x + tab->allocation.x;
+			arrow2_x = nb_x + tab->allocation.x +
+				tab->allocation.width;
+			arrow1_y = arrow2_y = nb_y + tab->allocation.y + tab->allocation.height/2;
+
+			if ((gpointer)win == (gpointer)dest_win && win->drag_tab < page_num) {
+				arrow1_y += tab->allocation.height;
+				arrow2_y += tab->allocation.height;
+			}
+		}
+
+		if (horiz_tabs) {
+			dnd_hints_show(HINT_ARROW_DOWN, arrow1_x, arrow1_y);
+			dnd_hints_show(HINT_ARROW_UP,   arrow2_x, arrow2_y);
+		} else {
+			dnd_hints_show(HINT_ARROW_RIGHT, arrow1_x, arrow1_y);
+			dnd_hints_show(HINT_ARROW_LEFT,  arrow2_x, arrow2_y);
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean
+notebook_leave_cb(GtkWidget *widget, GdkEventCrossing *e, GaimGtkWindow *win)
+{
+	if (win->in_drag)
+		return FALSE;
+
+	if (e->x_root <  win->drag_min_x ||
+	    e->x_root >= win->drag_max_x ||
+	    e->y_root <  win->drag_min_y ||
+	    e->y_root >= win->drag_max_y) {
+
+		    win->in_predrag = FALSE;
+		    notebook_init_grab(win, widget);
+	    }
+
+	return TRUE;
+}
+
+/*
+ * THANK YOU GALEON!
+ */
+static gboolean
+notebook_press_cb(GtkWidget *widget, GdkEventButton *e, GaimGtkWindow *win)
+{
+	gint nb_x, nb_y, x_rel, y_rel;
+	int tab_clicked;
+	GtkWidget *page;
+	GtkWidget *tab;
+
+	if (e->button != 1 || e->type != GDK_BUTTON_PRESS)
+		return FALSE;
+
+
+	if (win->in_drag) {
+		gaim_debug(GAIM_DEBUG_WARNING, "gtkconv",
+		           "Already in the middle of a window drag at tab_press_cb\n");
+		return TRUE;
+	}
+
+	/*
+	* Make sure a tab was actually clicked. The arrow buttons
+	* mess things up.
+	*/
+	tab_clicked = gaim_gtkconv_get_tab_at_xy(win, e->x_root, e->y_root);
+
+	if (tab_clicked == -1)
+		return FALSE;
+
+	/*
+	* Get the relative position of the press event, with regards to
+	* the position of the notebook.
+	*/
+	gdk_window_get_origin(win->notebook->window, &nb_x, &nb_y);
+
+	x_rel = e->x_root - nb_x;
+	y_rel = e->y_root - nb_y;
+
+	/* Reset the min/max x/y */
+	win->drag_min_x = 0;
+	win->drag_min_y = 0;
+	win->drag_max_x = 0;
+	win->drag_max_y = 0;
+
+	/* Find out which tab was dragged. */
+	page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), tab_clicked);
+	tab = gtk_notebook_get_tab_label(GTK_NOTEBOOK(win->notebook), page);
+
+	win->drag_min_x = tab->allocation.x      + nb_x;
+	win->drag_min_y = tab->allocation.y      + nb_y;
+	win->drag_max_x = tab->allocation.width  + win->drag_min_x;
+	win->drag_max_y = tab->allocation.height + win->drag_min_y;
+
+	/* Make sure the click occurred in the tab. */
+	if (e->x_root <  win->drag_min_x ||
+	    e->x_root >= win->drag_max_x ||
+	    e->y_root <  win->drag_min_y ||
+	    e->y_root >= win->drag_max_y) {
+
+		    return FALSE;
+	    }
+
+	win->in_predrag = TRUE;
+	win->drag_tab = tab_clicked;
+
+	/* Connect the new motion signals. */
+	win->drag_motion_signal =
+		g_signal_connect(G_OBJECT(widget), "motion_notify_event",
+		                 G_CALLBACK(notebook_motion_cb), win);
+
+	win->drag_leave_signal =
+		g_signal_connect(G_OBJECT(widget), "leave_notify_event",
+		                 G_CALLBACK(notebook_leave_cb), win);
+
+	return FALSE;
+}
+
+static gboolean
+notebook_release_cb(GtkWidget *widget, GdkEventButton *e, GaimGtkWindow *win)
+{
+	GaimGtkWindow *dest_win;
+	GaimConversation *conv;
+	GaimGtkConversation *gtkconv;
+	gint dest_page_num = 0;
+	gboolean new_window = FALSE;
+
+	/*
+	* Don't check to make sure that the event's window matches the
+	* widget's, because we may be getting an event passed on from the
+	* close button.
+	*/
+	if (e->button != 1 && e->type != GDK_BUTTON_RELEASE)
+		return FALSE;
+
+	if (gdk_pointer_is_grabbed()) {
+		gdk_pointer_ungrab(GDK_CURRENT_TIME);
+		gtk_grab_remove(widget);
+	}
+
+	if (!win->in_predrag && !win->in_drag)
+		return FALSE;
+
+	/* Disconnect the motion signal. */
+	if (win->drag_motion_signal) {
+		g_signal_handler_disconnect(G_OBJECT(widget),
+		                            win->drag_motion_signal);
+
+		win->drag_motion_signal = 0;
+	}
+
+	/*
+	* If we're in a pre-drag, we'll also need to disconnect the leave
+	* signal.
+	*/
+	if (win->in_predrag) {
+		win->in_predrag = FALSE;
+
+		if (win->drag_leave_signal) {
+			g_signal_handler_disconnect(G_OBJECT(widget),
+			                            win->drag_leave_signal);
+
+			win->drag_leave_signal = 0;
+		}
+	}
+
+	/* If we're not in drag...        */
+	/* We're perfectly normal people! */
+	if (!win->in_drag)
+		return FALSE;
+
+	win->in_drag = FALSE;
+
+	dnd_hints_hide_all();
+
+	dest_win = gaim_gtk_conv_window_get_at_xy(e->x_root, e->y_root);
+
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
+
+	if (dest_win == NULL) {
+		/* If the current window doesn't have any other conversations,
+		* there isn't much point transferring the conv to a new window. */
+		if (gaim_gtk_conv_window_get_gtkconv_count(win) > 1) {
+			/* Make a new window to stick this to. */
+			dest_win = gaim_gtk_conv_window_new();
+			new_window = TRUE;
+		}
+	}
+
+	if (dest_win == NULL)
+		return FALSE;
+
+	gaim_signal_emit(gaim_gtk_conversations_get_handle(),
+	                 "conversation-dragging", win, dest_win);
+
+	/* Get the destination page number. */
+	if (!new_window)
+		dest_page_num = gaim_gtkconv_get_tab_at_xy(dest_win,
+		                                           e->x_root, e->y_root);
+
+	gtkconv = GAIM_GTK_CONVERSATION(conv);
+
+	if (win == dest_win) {
+		gtk_notebook_reorder_child(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont, dest_page_num);
+	} else {
+		gaim_gtk_conv_window_remove_gtkconv(win, gtkconv);
+		gaim_gtk_conv_window_add_gtkconv(dest_win, gtkconv);
+		gtk_notebook_reorder_child(GTK_NOTEBOOK(dest_win->notebook), gtkconv->tab_cont, dest_page_num);
+		gaim_gtk_conv_window_switch_gtkconv(dest_win, gtkconv);
+		if (new_window) {
+			gint win_width, win_height;
+
+			gtk_window_get_size(GTK_WINDOW(dest_win->window),
+			                    &win_width, &win_height);
+
+			gtk_window_move(GTK_WINDOW(dest_win->window),
+			                e->x_root - (win_width  / 2),
+			                e->y_root - (win_height / 2));
+
+			gaim_gtk_conv_window_show(dest_win);
+		}
+	}
+
+	gtk_widget_grab_focus(GAIM_GTK_CONVERSATION(conv)->entry);
+
+	return TRUE;
+}
+
+
+static void
+before_switch_conv_cb(GtkNotebook *notebook, GtkWidget *page, gint page_num,
+                      gpointer user_data)
+{
+	GaimGtkWindow *win;
+	GaimConversation *conv;
+	GaimGtkConversation *gtkconv;
+
+	win = user_data;
+	conv = gaim_gtk_conv_window_get_active_conversation(win);
+
+	g_return_if_fail(conv != NULL);
+
+	if (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_IM)
+		return;
+
+	gtkconv = GAIM_GTK_CONVERSATION(conv);
+
+	stop_anim(NULL, gtkconv);
+}
+
+static void
+switch_conv_cb(GtkNotebook *notebook, GtkWidget *page, gint page_num,
+               gpointer user_data)
+{
+	GaimGtkWindow *win;
+	GaimConversation *conv;
+	GaimGtkConversation *gtkconv;
+
+	win = user_data;
+	gtkconv = gaim_gtk_conv_window_get_gtkconv_at_index(win, page_num);
+	conv = gtkconv->active_conv;
+
+	g_return_if_fail(conv != NULL);
+
+	/*
+	 * Only set "unseen" to "none" if the window has focus
+	 */
+	if (gaim_gtk_conv_window_has_focus(win))
+		gaim_conversation_set_unseen(conv, GAIM_UNSEEN_NONE);
+
+	/* Update the menubar */
+	gray_stuff_out(gtkconv);
+
+	update_typing_icon(gtkconv);
+
+	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.logging),
+	                               gaim_conversation_is_logging(conv));
+
+	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.sounds),
+	                               gtkconv->make_sound);
+
+	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.show_formatting_toolbar),
+	                               gaim_prefs_get_bool("/gaim/gtk/conversations/show_formatting_toolbar"));
+
+	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.show_timestamps),
+	                               gtkconv->show_timestamps);
+
+	if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
+		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.show_icon),
+		                               gtkconv->u.im->show_icon);
+	/*
+	 * We pause icons when they are not visible.  If this icon should
+	 * be animated then start it back up again.
+	 */
+	if ((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) &&
+	    (gtkconv->u.im->animate))
+		start_anim(NULL, gtkconv);
+
+	gtk_window_set_title(GTK_WINDOW(win->window),
+	                     gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
+}
+
+/**************************************************************************
+ * GTK+ window ops
+ **************************************************************************/
+
+static GList *window_list = NULL;
+
+GList *
+gaim_gtk_conv_windows_get_list()
+{
+	return window_list;
+}
+
+GaimGtkWindow *
+gaim_gtk_conv_window_new()
+{
+	GaimGtkWindow *win;
+	GtkPositionType pos;
+	GtkWidget *testidea;
+	GtkWidget *menubar;
+
+	win = g_malloc0(sizeof(GaimGtkWindow));
+
+	window_list = g_list_append(window_list, win);
+
+	/* Create the window. */
+	win->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_role(GTK_WINDOW(win->window), "conversation");
+	gtk_window_set_resizable(GTK_WINDOW(win->window), TRUE);
+	gtk_container_set_border_width(GTK_CONTAINER(win->window), 0);
+	GTK_WINDOW(win->window)->allow_shrink = TRUE;
+
+	g_signal_connect(G_OBJECT(win->window), "delete_event",
+	                 G_CALLBACK(close_win_cb), win);
+
+	g_signal_connect(G_OBJECT(win->window), "focus_in_event",
+	                 G_CALLBACK(focus_win_cb), win);
+
+	/* Create the notebook. */
+	win->notebook = gtk_notebook_new();
+
+	pos = gaim_prefs_get_int("/gaim/gtk/conversations/tab_side");
+
+#if 0
+	gtk_notebook_set_tab_hborder(GTK_NOTEBOOK(win->notebook), 0);
+	gtk_notebook_set_tab_vborder(GTK_NOTEBOOK(win->notebook), 0);
+#endif
+	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(win->notebook), pos);
+	gtk_notebook_set_scrollable(GTK_NOTEBOOK(win->notebook), TRUE);
+	gtk_notebook_popup_enable(GTK_NOTEBOOK(win->notebook));
+	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook), FALSE);
+	gtk_notebook_set_show_border(GTK_NOTEBOOK(win->notebook), FALSE);
+
+	gtk_widget_show(win->notebook);
+
+	g_signal_connect(G_OBJECT(win->notebook), "switch_page",
+	                 G_CALLBACK(before_switch_conv_cb), win);
+	g_signal_connect_after(G_OBJECT(win->notebook), "switch_page",
+	                       G_CALLBACK(switch_conv_cb), win);
+
+	/* Setup the tab drag and drop signals. */
+	gtk_widget_add_events(win->notebook,
+	                      GDK_BUTTON1_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
+	g_signal_connect(G_OBJECT(win->notebook), "button_press_event",
+	                 G_CALLBACK(notebook_press_cb), win);
+	g_signal_connect(G_OBJECT(win->notebook), "button_release_event",
+	                 G_CALLBACK(notebook_release_cb), win);
+
+	testidea = gtk_vbox_new(FALSE, 0);
+
+	/* Setup the menubar. */
+	menubar = setup_menubar(win);
+	gtk_box_pack_start(GTK_BOX(testidea), menubar, FALSE, TRUE, 0);
+
+	gtk_box_pack_start(GTK_BOX(testidea), win->notebook, TRUE, TRUE, 0);
+
+	gtk_container_add(GTK_CONTAINER(win->window), testidea);
+
+	gtk_widget_show(testidea);
+
+	return win;
+}
+
+void
+gaim_gtk_conv_window_destroy(GaimGtkWindow *win)
+{
+	window_list = g_list_remove(window_list, win);
+
+	gtk_widget_destroy(win->window);
+
+	g_object_unref(G_OBJECT(win->menu.item_factory));
+
+	g_free(win);
+}
+
+void
+gaim_gtk_conv_window_show(GaimGtkWindow *win)
+{
+	gtk_widget_show(win->window);
+}
+
+void
+gaim_gtk_conv_window_hide(GaimGtkWindow *win)
+{
+	gtk_widget_hide(win->window);
+}
+
+void
+gaim_gtk_conv_window_raise(GaimGtkWindow *win)
+{
+	gtk_widget_show(win->window);
+	gtk_window_deiconify(GTK_WINDOW(win->window));
+	gdk_window_raise(win->window->window);
+}
+
+void
+gaim_gtk_conv_window_switch_gtkconv(GaimGtkWindow *win, GaimGtkConversation *gtkconv)
+{
+	gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook),
+	                              gtk_notebook_page_num(GTK_NOTEBOOK(win->notebook),
+		                              gtkconv->tab_cont));
+}
+
+void
+gaim_gtk_conv_window_add_gtkconv(GaimGtkWindow *win, GaimGtkConversation *gtkconv)
+{
+	GaimConversation *conv = gtkconv->active_conv;
+	GaimGtkConversation *focus_gtkconv;
+	GtkWidget *tabby, *menu_tabby;
+	GtkWidget *tab_cont = gtkconv->tab_cont;
+	GtkWidget *close_image;
+	GaimConversationType conv_type;
+	const char *name;
+	const gchar *tmp_lab;
+	gint close_button_width, close_button_height, focus_width, focus_pad;
+
+	name      = gaim_conversation_get_name(conv);
+	conv_type = gaim_conversation_get_type(conv);
+
+
+	win->gtkconvs = g_list_append(win->gtkconvs, gtkconv);
+	gtkconv->win = win;
+
+	gtkconv->tabby = tabby = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
+	gtkconv->menu_tabby = menu_tabby = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
+
+	/* Close button. */
+	gtkconv->close = gtk_button_new();
+	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &close_button_width, &close_button_height);
+	if (gtk_check_version(2, 4, 2) == NULL) {
+		/* Need to account for extra padding around the gtkbutton */
+		gtk_widget_style_get(GTK_WIDGET(gtkconv->close),
+		                     "focus-line-width", &focus_width,
+		                     "focus-padding", &focus_pad,
+		                     NULL);
+		close_button_width += (focus_width + focus_pad) * 2;
+		close_button_height += (focus_width + focus_pad) * 2;
+	}
+	gtk_widget_set_size_request(GTK_WIDGET(gtkconv->close),
+	                            close_button_width, close_button_height);
+
+	gtk_button_set_relief(GTK_BUTTON(gtkconv->close), GTK_RELIEF_NONE);
+	close_image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
+	gtk_widget_show(close_image);
+	gtk_container_add(GTK_CONTAINER(gtkconv->close), close_image);
+	gtk_tooltips_set_tip(gtkconv->tooltips, gtkconv->close,
+	                     _("Close conversation"), NULL);
+
+	g_signal_connect(G_OBJECT(gtkconv->close), "clicked",
+	                 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);
+
+	/* Status icon. */
+	gtkconv->icon = gtk_image_new();
+	gtkconv->menu_icon = gtk_image_new();
+	update_tab_icon(conv);
+
+	/* Tab label. */
+	gtkconv->tab_label = gtk_label_new(tmp_lab = gaim_conversation_get_title(conv));
+#if GTK_CHECK_VERSION(2,6,0)
+	g_object_set(G_OBJECT(gtkconv->tab_label), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+	gtk_label_set_width_chars(GTK_LABEL(gtkconv->tab_label), 6);
+#endif
+	gtkconv->menu_label = gtk_label_new(gaim_conversation_get_title(conv));
+#if 0
+	gtk_misc_set_alignment(GTK_MISC(gtkconv->tab_label), 0.00, 0.5);
+	gtk_misc_set_padding(GTK_MISC(gtkconv->tab_label), 4, 0);
+#endif
+
+	/* Pack it all together. */
+	gtk_box_pack_start(GTK_BOX(tabby), gtkconv->icon, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(menu_tabby), gtkconv->menu_icon,
+	                   FALSE, FALSE, 0);
+
+	gtk_widget_show_all(gtkconv->icon);
+	gtk_widget_show_all(gtkconv->menu_icon);
+
+	gtk_box_pack_start(GTK_BOX(tabby), gtkconv->tab_label, TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(menu_tabby), gtkconv->menu_label, TRUE, TRUE, 0);
+	gtk_widget_show(gtkconv->tab_label);
+	gtk_widget_show(gtkconv->menu_label);
+	gtk_misc_set_alignment(GTK_MISC(gtkconv->menu_label), 0, 0);
+
+	gtk_box_pack_start(GTK_BOX(tabby), gtkconv->close, FALSE, FALSE, 0);
+	if (gaim_prefs_get_bool("/gaim/gtk/conversations/close_on_tabs"))
+		gtk_widget_show(gtkconv->close);
+
+	gtk_widget_show(tabby);
+	gtk_widget_show(menu_tabby);
+
+	if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
+		gaim_gtkconv_update_buddy_icon(conv);
+
+	/* Add this pane to the conversation's notebook. */
+	gtk_notebook_append_page_menu(GTK_NOTEBOOK(win->notebook), tab_cont, tabby, menu_tabby);
+	gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(win->notebook), tab_cont, TRUE, TRUE, GTK_PACK_START);
+
+
+	gtk_widget_show(tab_cont);
+
+	if (gaim_gtk_conv_window_get_gtkconv_count(win) == 1) {
+		/* Er, bug in notebooks? Switch to the page manually. */
+		gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), 0);
+
+		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook),
+		                           gaim_prefs_get_bool("/gaim/gtk/conversations/tabs"));
+	} else
+		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook), TRUE);
+
+	focus_gtkconv = g_list_nth_data(gaim_gtk_conv_window_get_gtkconvs(win),
+	                             gtk_notebook_get_current_page(GTK_NOTEBOOK(win->notebook)));
+	gtk_widget_grab_focus(focus_gtkconv->entry);
+
+	if (gaim_gtk_conv_window_get_gtkconv_count(win) == 1)
+		g_timeout_add(0, (GSourceFunc)update_send_as_selection, win);
+}
+
+void
+gaim_gtk_conv_window_remove_gtkconv(GaimGtkWindow *win, GaimGtkConversation *gtkconv)
+{
+	unsigned int index;
+	GaimConversationType conv_type;
+
+	conv_type = gaim_conversation_get_type(gtkconv->active_conv);
+	index = gtk_notebook_page_num(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont);
+
+	g_object_ref(gtkconv->tab_cont);
+	gtk_object_sink(GTK_OBJECT(gtkconv->tab_cont));
+
+	gtk_notebook_remove_page(GTK_NOTEBOOK(win->notebook), index);
+
+	/* go back to tabless if need be */
+	if (gaim_gtk_conv_window_get_gtkconv_count(win) <= 2) {
+		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook),
+		                           gaim_prefs_get_bool("/gaim/gtk/conversations/tabs"));
+	}
+
+
+	/* If this window is setup with an inactive gc, regenerate the menu. */
+
+	if (conv_type == GAIM_CONV_TYPE_IM &&
+	    gaim_conversation_get_gc(gtkconv->active_conv) == NULL) {
+		    generate_send_as_items(win, gtkconv->active_conv);
+	    }
+
+	win->gtkconvs = g_list_remove(win->gtkconvs, gtkconv);
+}
+
+GaimGtkConversation *
+gaim_gtk_conv_window_get_gtkconv_at_index(const GaimGtkWindow *win, int index)
+{
+	GtkWidget *tab_cont;
+
+	if (index == -1)
+		index = 0;
+	tab_cont = gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), index);
+	return g_object_get_data(G_OBJECT(tab_cont), "GaimGtkConversation");
+}
+
+GaimGtkConversation *
+gaim_gtk_conv_window_get_active_gtkconv(const GaimGtkWindow *win)
+{
+	int index;
+	GtkWidget *tab_cont;
+
+	index = gtk_notebook_get_current_page(GTK_NOTEBOOK(win->notebook));
+	if (index == -1)
+		index = 0;
+	tab_cont = gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), index);
+	if (!tab_cont)
+		return NULL;
+	return g_object_get_data(G_OBJECT(tab_cont), "GaimGtkConversation");
+}
+
+
+GaimConversation *
+gaim_gtk_conv_window_get_active_conversation(const GaimGtkWindow *win)
+{
+	GaimGtkConversation *gtkconv;
+
+	gtkconv = gaim_gtk_conv_window_get_active_gtkconv(win);
+	return gtkconv ? gtkconv->active_conv : NULL;
+}
+
+gboolean
+gaim_gtk_conv_window_is_active_conversation(const GaimConversation *conv)
+{
+	return conv == gaim_gtk_conv_window_get_active_conversation(GAIM_GTK_CONVERSATION(conv)->win);
+}
+
+gboolean
+gaim_gtk_conv_window_has_focus(GaimGtkWindow *win)
+{
+	gboolean has_focus = FALSE;
+
+	g_object_get(G_OBJECT(win->window), "has-toplevel-focus", &has_focus, NULL);
+
+	return has_focus;
+}
+
+GaimGtkWindow *
+gaim_gtk_conv_window_get_at_xy(int x, int y)
+{
+	GaimGtkWindow *win;
+	GdkWindow *gdkwin;
+	GList *l;
+
+	gdkwin = gdk_window_at_pointer(&x, &y);
+
+	if (gdkwin)
+		gdkwin = gdk_window_get_toplevel(gdkwin);
+
+	for (l = gaim_gtk_conv_windows_get_list(); l != NULL; l = l->next) {
+		win = l->data;
+
+		if (gdkwin == win->window->window)
+			return win;
+	}
+
+	return NULL;
+}
+
+GList *
+gaim_gtk_conv_window_get_gtkconvs(GaimGtkWindow *win)
+{
+	return win->gtkconvs;
+}
+
+guint
+gaim_gtk_conv_window_get_gtkconv_count(GaimGtkWindow *win)
+{
+	return g_list_length(win->gtkconvs);
+}
+
+GaimGtkWindow *
+gaim_gtk_conv_window_first_with_type(GaimConversationType type)
+{
+	GList *wins, *convs;
+	GaimGtkWindow *win;
+	GaimGtkConversation *conv;
+
+	if (type == GAIM_CONV_TYPE_UNKNOWN)
+		return NULL;
+
+	for (wins = gaim_gtk_conv_windows_get_list(); wins != NULL; wins = wins->next) {
+		win = wins->data;
+
+		for (convs = win->gtkconvs;
+		     convs != NULL;
+		     convs = convs->next) {
+
+			conv = convs->data;
+
+			if (gaim_conversation_get_type(conv->active_conv) == type)
+				return win;
+		}
+	}
+
+	return NULL;
+}
+
+GaimGtkWindow *
+gaim_gtk_conv_window_last_with_type(GaimConversationType type)
+{
+	GList *wins, *convs;
+	GaimGtkWindow *win;
+	GaimGtkConversation *conv;
+
+	if (type == GAIM_CONV_TYPE_UNKNOWN)
+		return NULL;
+
+	for (wins = g_list_last(gaim_gtk_conv_windows_get_list());
+	     wins != NULL;
+	     wins = wins->prev) {
+
+		win = wins->data;
+
+		for (convs = win->gtkconvs;
+		     convs != NULL;
+		     convs = convs->next) {
+
+			conv = convs->data;
+
+			if (gaim_conversation_get_type(conv->active_conv) == type)
+				return win;
+		}
+	}
+
+	return NULL;
+}
+
+
+/**************************************************************************
+ * Conversation placement functions
+ **************************************************************************/
+typedef struct
+{
+	char *id;
+	char *name;
+	GaimConvPlacementFunc fnc;
+
+} ConvPlacementData;
+
+static GList *conv_placement_fncs = NULL;
+static GaimConvPlacementFunc place_conv = NULL;
+
+/* This one places conversations in the last made window. */
+static void
+conv_placement_last_created_win(GaimGtkConversation *conv)
+{
+	GaimGtkWindow *win;
+
+	GList *l = g_list_last(gaim_gtk_conv_windows_get_list());
+	win = l ? l->data : NULL;;
+
+	if (win == NULL) {
+		win = gaim_gtk_conv_window_new();
+
+		gaim_gtk_conv_window_add_gtkconv(win, conv);
+		gaim_gtk_conv_window_show(win);
+	} else {
+		gaim_gtk_conv_window_add_gtkconv(win, conv);
+	}
+}
+
+/* This one places conversations in the last made window of the same type. */
+static void
+conv_placement_last_created_win_type(GaimGtkConversation *conv)
+{
+	GaimGtkWindow *win;
+
+	win = gaim_gtk_conv_window_last_with_type(gaim_conversation_get_type(conv->active_conv));
+
+	if (win == NULL) {
+		win = gaim_gtk_conv_window_new();
+
+		gaim_gtk_conv_window_add_gtkconv(win, conv);
+		gaim_gtk_conv_window_show(win);
+	} else
+		gaim_gtk_conv_window_add_gtkconv(win, conv);
+}
+
+/* This one places each conversation in its own window. */
+static void
+conv_placement_new_window(GaimGtkConversation *conv)
+{
+	GaimGtkWindow *win;
+
+	win = gaim_gtk_conv_window_new();
+
+	gaim_gtk_conv_window_add_gtkconv(win, conv);
+
+	gaim_gtk_conv_window_show(win);
+}
+
+static GaimGroup *
+conv_get_group(GaimGtkConversation *conv)
+{
+	GaimGroup *group = NULL;
+
+	if (gaim_conversation_get_type(conv->active_conv) == GAIM_CONV_TYPE_IM) {
+		GaimBuddy *buddy;
+
+		buddy = gaim_find_buddy(gaim_conversation_get_account(conv->active_conv),
+		                        gaim_conversation_get_name(conv->active_conv));
+
+		if (buddy != NULL)
+			group = gaim_find_buddys_group(buddy);
+
+	} else if (gaim_conversation_get_type(conv->active_conv) == GAIM_CONV_TYPE_CHAT) {
+		GaimChat *chat;
+
+		chat = gaim_blist_find_chat(gaim_conversation_get_account(conv->active_conv),
+		                            gaim_conversation_get_name(conv->active_conv));
+
+		if (chat != NULL)
+			group = gaim_chat_get_group(chat);
+	}
+
+	return group;
+}
+
+/*
+ * This groups things by, well, group. Buddies from groups will always be
+ * grouped together, and a buddy from a group not belonging to any currently
+ * open windows will get a new window.
+ */
+static void
+conv_placement_by_group(GaimGtkConversation *conv)
+{
+	GaimConversationType type;
+	GaimGroup *group = NULL;
+	GList *wl, *cl;
+
+	type = gaim_conversation_get_type(conv->active_conv);
+
+	group = conv_get_group(conv);
+
+	/* Go through the list of IMs and find one with this group. */
+	for (wl = gaim_gtk_conv_windows_get_list(); wl != NULL; wl = wl->next) {
+		GaimGtkWindow *win2;
+		GaimGtkConversation *conv2;
+		GaimGroup *group2 = NULL;
+
+		win2 = wl->data;
+
+		for (cl = win2->gtkconvs;
+		     cl != NULL;
+		     cl = cl->next) {
+			conv2 = cl->data;
+
+			group2 = conv_get_group(conv2);
+
+			if (group == group2) {
+				gaim_gtk_conv_window_add_gtkconv(win2, conv);
+
+				return;
+			}
+		}
+	}
+
+	/* Make a new window. */
+	conv_placement_new_window(conv);
+}
+
+/* This groups things by account.  Otherwise, the same semantics as above */
+static void
+conv_placement_by_account(GaimGtkConversation *conv)
+{
+	GaimConversationType type;
+	GList *wins, *convs;
+	GaimAccount *account;
+
+	account = gaim_conversation_get_account(conv->active_conv);
+	type = gaim_conversation_get_type(conv->active_conv);
+
+	/* Go through the list of IMs and find one with this group. */
+	for (wins = gaim_gtk_conv_windows_get_list(); wins != NULL; wins = wins->next) {
+		GaimGtkWindow *win2;
+		GaimGtkConversation *conv2;
+
+		win2 = wins->data;
+
+		for (convs = win2->gtkconvs;
+		     convs != NULL;
+		     convs = convs->next) {
+			conv2 = convs->data;
+
+			if (account == gaim_conversation_get_account(conv2->active_conv)) {
+				gaim_gtk_conv_window_add_gtkconv(win2, conv);
+				return;
+			}
+		}
+	}
+
+	/* Make a new window. */
+	conv_placement_new_window(conv);
+}
+
+static ConvPlacementData *
+get_conv_placement_data(const char *id)
+{
+	ConvPlacementData *data = NULL;
+	GList *n;
+
+	for (n = conv_placement_fncs; n; n = n->next) {
+		data = n->data;
+		if (!strcmp(data->id, id))
+			return data;
+	}
+
+	return NULL;
+}
+
+static void
+add_conv_placement_fnc(const char *id, const char *name,
+                       GaimConvPlacementFunc fnc)
+{
+	ConvPlacementData *data;
+
+	data = g_new(ConvPlacementData, 1);
+
+	data->id = g_strdup(id);
+	data->name = g_strdup(name);
+	data->fnc  = fnc;
+
+	conv_placement_fncs = g_list_append(conv_placement_fncs, data);
+}
+
+static void
+ensure_default_funcs(void)
+{
+	if (conv_placement_fncs == NULL) {
+		add_conv_placement_fnc("last", _("Last created window"),
+		                       conv_placement_last_created_win);
+		add_conv_placement_fnc("im_chat", _("Separate IM and Chat windows"),
+		                       conv_placement_last_created_win_type);
+		add_conv_placement_fnc("new", _("New window"),
+		                       conv_placement_new_window);
+		add_conv_placement_fnc("group", _("By group"),
+		                       conv_placement_by_group);
+		add_conv_placement_fnc("account", _("By account"),
+		                       conv_placement_by_account);
+	}
+}
+
+GList *
+gaim_gtkconv_placement_get_options(void)
+{
+	GList *n, *list = NULL;
+	ConvPlacementData *data;
+
+	ensure_default_funcs();
+
+	for (n = conv_placement_fncs; n; n = n->next) {
+		data = n->data;
+		list = g_list_append(list, data->name);
+		list = g_list_append(list, data->id);
+	}
+
+	return list;
+}
+
+
+void
+gaim_gtkconv_placement_add_fnc(const char *id, const char *name,
+                            GaimConvPlacementFunc fnc)
+{
+	g_return_if_fail(id   != NULL);
+	g_return_if_fail(name != NULL);
+	g_return_if_fail(fnc  != NULL);
+
+	ensure_default_funcs();
+
+	add_conv_placement_fnc(id, name, fnc);
+}
+
+void
+gaim_gtkconv_placement_remove_fnc(const char *id)
+{
+	ConvPlacementData *data = get_conv_placement_data(id);
+
+	if (data == NULL)
+		return;
+
+	conv_placement_fncs = g_list_remove(conv_placement_fncs, data);
+
+	g_free(data->id);
+	g_free(data->name);
+	g_free(data);
+}
+
+const char *
+gaim_gtkconv_placement_get_name(const char *id)
+{
+	ConvPlacementData *data;
+
+	ensure_default_funcs();
+
+	data = get_conv_placement_data(id);
+
+	if (data == NULL)
+		return NULL;
+
+	return data->name;
+}
+
+GaimConvPlacementFunc
+gaim_gtkconv_placement_get_fnc(const char *id)
+{
+	ConvPlacementData *data;
+
+	ensure_default_funcs();
+
+	data = get_conv_placement_data(id);
+
+	if (data == NULL)
+		return NULL;
+
+	return data->fnc;
+}
+
+void
+gaim_gtkconv_placement_set_current_func(GaimConvPlacementFunc func)
+{
+	g_return_if_fail(func != NULL);
+
+	place_conv = func;
+}
+
+GaimConvPlacementFunc
+gaim_gtkconv_placement_get_current_func(void)
+{
+	return place_conv;
+}
+
+void
+gaim_gtkconv_placement_place(GaimGtkConversation *gtkconv)
+{
+	if (place_conv)
+		place_conv(gtkconv);
+}
--- a/src/gtkconv.h	Fri Sep 30 05:07:03 2005 +0000
+++ b/src/gtkconv.h	Sun Oct 02 00:32:49 2005 +0000
@@ -25,7 +25,6 @@
 #ifndef _GAIM_GTKCONVERSATION_H_
 #define _GAIM_GTKCONVERSATION_H_
 
-typedef struct _GaimGtkWindow       GaimGtkWindow;
 typedef struct _GaimGtkImPane       GaimGtkImPane;
 typedef struct _GaimGtkChatPane     GaimGtkChatPane;
 typedef struct _GaimGtkConversation GaimGtkConversation;
@@ -40,21 +39,16 @@
 	CHAT_USERS_COLUMNS
 };
 
-#define GAIM_GTK_WINDOW(win) \
-	((GaimGtkWindow *)(win)->ui_data)
-
 #define GAIM_GTK_CONVERSATION(conv) \
 	((GaimGtkConversation *)(conv)->ui_data)
 
-#define GAIM_IS_GTK_WINDOW(win) \
-	(gaim_conv_window_get_ui_ops(win) == gaim_gtk_conversations_get_win_ui_ops())
-
 #define GAIM_IS_GTK_CONVERSATION(conv) \
 	(gaim_conversation_get_ui_ops(conv) == \
 	 gaim_gtk_conversations_get_conv_ui_ops())
 
 #include "gtkgaim.h"
 #include "conversation.h"
+#include "gtkconvwin.h"
 
 /**************************************************************************
  * @name Structures
@@ -65,57 +59,6 @@
  * A GTK+ representation of a graphical window containing one or more
  * conversations.
  */
-struct _GaimGtkWindow
-{
-	GtkWidget *window;           /**< The window.                      */
-	GtkWidget *notebook;         /**< The notebook of conversations.   */
-
-	struct
-	{
-		GtkWidget *menubar;
-
-		GtkWidget *view_log;
-
-		GtkWidget *send_file;
-		GtkWidget *add_pounce;
-		GtkWidget *get_info;
-		GtkWidget *invite;
-
-		GtkWidget *alias;
-		GtkWidget *block;
-		GtkWidget *add;
-		GtkWidget *remove;
-
-		GtkWidget *insert_link;
-		GtkWidget *insert_image;
-
-		GtkWidget *logging;
-		GtkWidget *sounds;
-		GtkWidget *show_formatting_toolbar;
-		GtkWidget *show_timestamps;
-		GtkWidget *show_icon;
-
-		GtkWidget *send_as;
-
-		GtkWidget *tray;
-
-		GtkWidget *typing_icon;
-
-		GtkItemFactory *item_factory;
-
-	} menu;
-
-	/* Tab dragging stuff. */
-	gboolean in_drag;
-	gboolean in_predrag;
-
-	gint drag_tab;
-
-	gint drag_min_x, drag_max_x, drag_min_y, drag_max_y;
-
-	gint drag_motion_signal;
-	gint drag_leave_signal;
-};
 
 /**
  * A GTK+ Instant Message pane.
@@ -161,7 +104,9 @@
 {
 	GaimConversation *active_conv;
 	GList *convs;
-	
+
+	GaimGtkWindow *win;
+
 	gboolean make_sound;
 	gboolean show_formatting_toolbar;
 	gboolean show_timestamps;
@@ -210,13 +155,6 @@
 /*@{*/
 
 /**
- * Returns the UI operations structure for GTK+ windows.
- *
- * @return The GTK+ window operations structure.
- */
-GaimConvWindowUiOps *gaim_gtk_conversations_get_win_ui_ops(void);
-
-/**
  * Returns the UI operations structure for GTK+ conversations.
  *
  * @return The GTK+ conversation operations structure.
@@ -243,30 +181,9 @@
  */
 void gaim_gtkconv_update_buttons_by_protocol(GaimConversation *conv);
 
-/**
- * Returns the window at the specified X, Y location.
- *
- * If the window is not a GTK+ window, @c NULL is returned.
- *
- * @param x The X coordinate.
- * @param y The Y coordinate.
- *
- * @return The GTK+ window at the location, if it exists, or @c NULL otherwise.
- */
-GaimConvWindow *gaim_gtkwin_get_at_xy(int x, int y);
-
-/**
- * Returns the index of the tab at the specified X, Y location in a notebook.
- *
- * @param win The GTK+ window containing the notebook.
- * @param x   The X coordinate.
- * @param y   The Y coordinate.
- *
- * @return The index of the tab at the location.
- */
-int gaim_gtkconv_get_tab_at_xy(GaimConvWindow *win, int x, int y);
-
-GaimGtkConversation *gaim_gtk_get_gtkconv_at_index(const GaimConvWindow *win, int index);
+GaimGtkWindow *gaim_gtkconv_get_window(GaimGtkConversation *gtkconv);
+GdkPixbuf *gaim_gtkconv_get_tab_icon(GaimConversation *conv, gboolean small_icon);
+void gaim_gtkconv_new(GaimConversation *conv);
 /*@}*/
 
 /**************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gtkconvwin.h	Sun Oct 02 00:32:49 2005 +0000
@@ -0,0 +1,141 @@
+/**
+ * @file gtkconvwin.h GTK+ Conversation Window API
+ * @ingroup gtkui
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _GAIM_GTKCONVERSATION_WINDOW_H_
+#define _GAIM_GTKCONVERSATION_WINDOW_H_
+
+typedef struct _GaimGtkWindow       GaimGtkWindow;
+
+
+/**************************************************************************
+ * @name Structures
+ **************************************************************************/
+/*@{*/
+
+/**
+ * A GTK+ representation of a graphical window containing one or more
+ * conversations.
+ */
+struct _GaimGtkWindow
+{
+	GtkWidget *window;           /**< The window.                      */
+	GtkWidget *notebook;         /**< The notebook of conversations.   */
+	GList *gtkconvs;
+
+	struct
+	{
+		GtkWidget *menubar;
+
+		GtkWidget *view_log;
+
+		GtkWidget *send_file;
+		GtkWidget *add_pounce;
+		GtkWidget *get_info;
+		GtkWidget *invite;
+
+		GtkWidget *alias;
+		GtkWidget *block;
+		GtkWidget *add;
+		GtkWidget *remove;
+
+		GtkWidget *insert_link;
+		GtkWidget *insert_image;
+
+		GtkWidget *logging;
+		GtkWidget *sounds;
+		GtkWidget *show_formatting_toolbar;
+		GtkWidget *show_timestamps;
+		GtkWidget *show_icon;
+
+		GtkWidget *send_as;
+
+		GtkWidget *tray;
+
+		GtkWidget *typing_icon;
+
+		GtkItemFactory *item_factory;
+
+	} menu;
+
+	/* Tab dragging stuff. */
+	gboolean in_drag;
+	gboolean in_predrag;
+
+	gint drag_tab;
+
+	gint drag_min_x, drag_max_x, drag_min_y, drag_max_y;
+
+	gint drag_motion_signal;
+	gint drag_leave_signal;
+};
+
+/*@}*/
+
+/**************************************************************************
+ * @name GTK+ Conversation Window API
+ **************************************************************************/
+/*@{*/
+
+GaimGtkWindow * gaim_gtk_conv_window_new();
+void gaim_gtk_conv_window_destroy(GaimGtkWindow *win);
+GList *gaim_gtk_conv_windows_get_list();
+void gaim_gtk_conv_window_show(GaimGtkWindow *win);
+void gaim_gtk_conv_window_hide(GaimGtkWindow *win);
+void gaim_gtk_conv_window_raise(GaimGtkWindow *win);
+void gaim_gtk_conv_window_switch_gtkconv(GaimGtkWindow *win, GaimGtkConversation *gtkconv);
+void gaim_gtk_conv_window_add_gtkconv(GaimGtkWindow *win, GaimGtkConversation *gtkconv);
+void gaim_gtk_conv_window_remove_gtkconv(GaimGtkWindow *win, GaimGtkConversation *gtkconv);
+GaimGtkConversation *gaim_gtk_conv_window_get_gtkconv_at_index(const GaimGtkWindow *win, int index);
+GaimGtkConversation *gaim_gtk_conv_window_get_active_gtkconv(const GaimGtkWindow *win);
+GaimConversation *gaim_gtk_conv_window_get_active_conversation(const GaimGtkWindow *win);
+gboolean gaim_gtk_conv_window_is_active_conversation(const GaimConversation *conv);
+gboolean gaim_gtk_conv_window_has_focus(GaimGtkWindow *win);
+GaimGtkWindow *gaim_gtk_conv_window_get_at_xy(int x, int y);
+GList *gaim_gtk_conv_window_get_gtkconvs(GaimGtkWindow *win);
+guint gaim_gtk_conv_window_get_gtkconv_count(GaimGtkWindow *win);
+
+GaimGtkWindow *gaim_gtk_conv_window_first_with_type(GaimConversationType type);
+GaimGtkWindow *gaim_gtk_conv_window_last_with_type(GaimConversationType type);
+
+/*@}*/
+
+/**************************************************************************
+ * @name GTK+ Conversation Placement API
+ **************************************************************************/
+/*@{*/
+
+typedef void (*GaimConvPlacementFunc)(GaimGtkConversation *);
+
+GList *gaim_gtkconv_placement_get_options(void);
+void gaim_gtkconv_placement_add_fnc(const char *id, const char *name, GaimConvPlacementFunc fnc);
+void gaim_gtkconv_placement_remove_fnc(const char *id);
+const char *gaim_gtkconv_placement_get_name(const char *id);
+GaimConvPlacementFunc gaim_gtkconv_placement_get_fnc(const char *id);
+void gaim_gtkconv_placement_set_current_func(GaimConvPlacementFunc func);
+GaimConvPlacementFunc gaim_gtkconv_placement_get_current_func(void);
+void gaim_gtkconv_placement_place(GaimGtkConversation *gtkconv);
+
+/*@}*/
+
+#endif /* _GAIM_GTKCONVERSATION_WINDOW_H_ */
--- a/src/gtkdialogs.c	Fri Sep 30 05:07:03 2005 +0000
+++ b/src/gtkdialogs.c	Sun Oct 02 00:32:49 2005 +0000
@@ -511,8 +511,7 @@
 gaim_gtkdialogs_im_with_user(GaimAccount *account, const char *username)
 {
 	GaimConversation *conv;
-	GaimConvWindow *win;
-	GaimGtkWindow *gtkwin;
+	GaimGtkWindow *win;
 
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(username != NULL);
@@ -522,11 +521,10 @@
 	if (conv == NULL)
 		conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, username);
 
-	win = gaim_conversation_get_window(conv);
-	gtkwin = GAIM_GTK_WINDOW(win);
+	win = GAIM_GTK_CONVERSATION(conv)->win;
 
-	gtk_window_present(GTK_WINDOW(gtkwin->window));
-	gaim_conv_window_switch_conversation(win, conv);
+	gtk_window_present(GTK_WINDOW(win->window));
+	gaim_gtk_conv_window_switch_gtkconv(win, GAIM_GTK_CONVERSATION(conv));
 }
 
 static gboolean
--- a/src/gtkmain.c	Fri Sep 30 05:07:03 2005 +0000
+++ b/src/gtkmain.c	Sun Oct 02 00:32:49 2005 +0000
@@ -251,7 +251,6 @@
 {
 	/* Set the UI operation structures. */
 	gaim_accounts_set_ui_ops(gaim_gtk_accounts_get_ui_ops());
-	gaim_conversations_set_win_ui_ops(gaim_gtk_conversations_get_win_ui_ops());
 	gaim_xfers_set_ui_ops(gaim_gtk_xfers_get_ui_ops());
 	gaim_blist_set_ui_ops(gaim_gtk_blist_get_ui_ops());
 	gaim_notify_set_ui_ops(gaim_gtk_notify_get_ui_ops());
--- a/src/gtkprefs.c	Fri Sep 30 05:07:03 2005 +0000
+++ b/src/gtkprefs.c	Sun Oct 02 00:32:49 2005 +0000
@@ -1018,7 +1018,7 @@
 			_("Right"), GTK_POS_RIGHT,
 			NULL);
 
-	names = gaim_conv_placement_get_options();
+	names = gaim_gtkconv_placement_get_options();
 	label = gaim_gtk_prefs_dropdown_from_list(hbox, _("N_ew conversations:"),
 			GAIM_PREF_STRING, "/gaim/gtk/conversations/placement", names);
 	g_list_free(names);
--- a/src/gtksound.c	Fri Sep 30 05:07:03 2005 +0000
+++ b/src/gtksound.c	Sun Oct 02 00:32:49 2005 +0000
@@ -116,22 +116,20 @@
 play_conv_event(GaimConversation *conv, GaimSoundEventID event)
 {
 	GaimGtkConversation *gtkconv;
-	GaimConvWindow *gaimwin;
-	GaimGtkWindow *gtkwin;
+	GaimGtkWindow *win;
 	gboolean has_focus;
 
 	if (conv==NULL)
 		gaim_sound_play_event(event);
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
-	gaimwin = gaim_conversation_get_window(conv);
-	gtkwin = GAIM_GTK_WINDOW(gaimwin);
+	win = gtkconv->win;
 
-	g_object_get(G_OBJECT(gtkwin->window), "has-toplevel-focus", 
+	g_object_get(G_OBJECT(win->window), "has-toplevel-focus",
 				 &has_focus, NULL);
 
-	if (gtkconv->make_sound && 
-		!((gaim_conv_window_get_active_conversation(gaimwin) == conv) &&
+	if (gtkconv->make_sound &&
+		!((gaim_gtk_conv_window_get_active_conversation(win) == conv) &&
 		!gaim_prefs_get_bool("/gaim/gtk/sound/conv_focus") && has_focus)) {
 
 		gaim_sound_play_event(event);
@@ -146,7 +144,7 @@
 
 static void
 im_msg_received_cb(GaimAccount *account, char *sender,
-				   char *message, GaimConversation *conv, 
+				   char *message, GaimConversation *conv,
 				   int flags, GaimSoundEventID event)
 {
 	if (conv==NULL)
@@ -168,7 +166,7 @@
 chat_buddy_join_cb(GaimConversation *conv, const char *name,
 				   GaimConvChatBuddyFlags flags, GaimSoundEventID event)
 {
-	if (!chat_nick_matches_name(conv, name)) 
+	if (!chat_nick_matches_name(conv, name))
 		play_conv_event(conv, event);
 }
 
@@ -176,7 +174,7 @@
 chat_buddy_left_cb(GaimConversation *conv, const char *name,
 				   const char *reason, GaimSoundEventID event)
 {
-	if (!chat_nick_matches_name(conv, name)) 
+	if (!chat_nick_matches_name(conv, name))
 		play_conv_event(conv, event);
 }
 
@@ -187,7 +185,7 @@
 	GaimConnection *conn = gaim_account_get_connection(account);
 	GaimConversation *conv = NULL;
 
-	if (conn!=NULL) 
+	if (conn!=NULL)
 		conv = gaim_find_chat(conn,id);
 
 	play_conv_event(conv, event);
--- a/src/protocols/oscar/oscar.c	Fri Sep 30 05:07:03 2005 +0000
+++ b/src/protocols/oscar/oscar.c	Sun Oct 02 00:32:49 2005 +0000
@@ -962,7 +962,6 @@
         
 	if (conv) {
 		gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL));
-		gaim_conversation_update_progress(conv, 0);
 	} else {
 		gaim_notify_error(dim->gc, NULL, _("Direct Connect failed"), buf);
 	}
@@ -1194,7 +1193,6 @@
 	double percent;
 	GaimConnection *gc = sess->aux_data;
 	OscarData *od = (OscarData *)gc->proto_data;
-	GaimConversation *c;
 	struct oscar_direct_im *dim;
 
 	va_start(ap, fr);
@@ -1210,10 +1208,6 @@
 		dim->watcher = 0;
 	}
 
-	c = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, sn,
-		gaim_connection_get_account(gc));
-	if (c != NULL)
-		gaim_conversation_update_progress(c, percent);
 	dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ,
 				      oscar_callback, dim->conn);
 
--- a/src/server.c	Fri Sep 30 05:07:03 2005 +0000
+++ b/src/server.c	Sun Oct 02 00:32:49 2005 +0000
@@ -1041,8 +1041,6 @@
 
 	gaim_conv_chat_set_id(chat, id);
 
-	gaim_conv_window_show(gaim_conversation_get_window(conv));
-	gaim_conv_window_switch_conversation(gaim_conversation_get_window(conv), conv);
 
 	gaim_signal_emit(gaim_conversations_get_handle(), "chat-joined", conv);