changeset 3790:12b29552f1d7

[gaim-migrate @ 3930] Better than cheddar, it's i18n input... committer: Tailor Script <tailor@pidgin.im>
author Rob Flynn <gaim@robflynn.com>
date Wed, 23 Oct 2002 00:12:49 +0000
parents fb519383a058
children 06762b8e1194
files ChangeLog TODO src/buddy_chat.c src/conversation.c src/convo.h src/dialogs.c src/ui.h src/util.c
diffstat 8 files changed, 328 insertions(+), 360 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Oct 22 23:31:49 2002 +0000
+++ b/ChangeLog	Wed Oct 23 00:12:49 2002 +0000
@@ -36,6 +36,7 @@
 		- Alert Dialogs
 		- GtkIMHtml tooltips Pangonated
 		- About Dialog (Nathan Walp)
+		- i18n capable text input widget (thanks paco-paco, david odin, etc)
 	* Notify.c plugin rewritten; check its configure dialog (Thanks,
 	  Etan Reisner)
 	* TOC no longer compiles statically by default--use OSCAR
--- a/TODO	Tue Oct 22 23:31:49 2002 +0000
+++ b/TODO	Wed Oct 23 00:12:49 2002 +0000
@@ -38,7 +38,6 @@
 	need a doc written up for gaim-remote on usage
 
 PORTABILITY/i18n
-input widget
 icq i18n
 info dialog
 irc (patch pending?)
--- a/src/buddy_chat.c	Tue Oct 22 23:31:49 2002 +0000
+++ b/src/buddy_chat.c	Wed Oct 23 00:12:49 2002 +0000
@@ -469,41 +469,52 @@
 
 void tab_complete(struct conversation *c)
 {
-	int pos = GTK_OLD_EDITABLE(c->entry)->current_pos;
-	int start = pos;
+	GtkTextIter cursor, word_start, start_buffer;
+	int start;
 	int most_matched = -1;
 	char *entered, *partial = NULL;
 	char *text;
 	GList *matches = NULL;
-	GList *nicks = c->in_room;
+	GList *nicks = NULL;
+
+	gtk_text_buffer_get_start_iter(c->entry_buffer, &start_buffer);
+	gtk_text_buffer_get_iter_at_mark(c->entry_buffer, &cursor,
+					 gtk_text_buffer_get_insert(c->entry_buffer));
+	word_start = cursor;
 
 	/* if there's nothing there just return */
-	if (!start)
+	if (!gtk_text_iter_compare(&cursor, &start_buffer))
 		return;
 	
-	text = gtk_editable_get_chars(GTK_EDITABLE(c->entry), 0, pos);
+	text = gtk_text_buffer_get_text(c->entry_buffer, &start_buffer, &cursor, FALSE);
 
 	/* if we're at the end of ": " we need to move back 2 spaces */
-	if (start >= 2 && text[start - 1] == ' ' && text[start - 2] == ':')
-		start -= 2;
-	
+	start = strlen(text)-1;
+	if (strlen(text)>=2 && !strncmp(&text[start-1], ": ", 2)) {
+		gtk_text_iter_backward_chars(&word_start, 2);
+	}
+
 	/* find the start of the word that we're tabbing */
-	while (start > 0 && text[start - 1] != ' ')
+	while (start >= 0 && text[start] != ' ') {
+		gtk_text_iter_backward_char(&word_start);
 		start--;
+	}
+	g_free(text);
 
-	entered = text + start;
+	entered = gtk_text_buffer_get_text(c->entry_buffer, &word_start, &cursor, FALSE);
 	if (chat_options & OPT_CHAT_OLD_STYLE_TAB) {
 		if (strlen(entered) >= 2 && !strncmp(": ", entered + strlen(entered) - 2, 2))
 			entered[strlen(entered) - 2] = 0;
 	}
-		
+
 	if (!strlen(entered)) {
-		g_free(text);
+		g_free(entered);
 		return;
 	}
 
 	debug_printf("checking tab-completion for %s\n", entered);
 
+	nicks = c->in_room;
 	while (nicks) {
 		char *nick = nicks->data;
 		/* this checks to see if the current nick could be a completion */
@@ -531,7 +542,7 @@
 
 		/* if we're doing old-style, just fill in the completion */
 		if (chat_options & OPT_CHAT_OLD_STYLE_TAB) {
-		        gtk_editable_delete_text(GTK_EDITABLE(c->entry), start, pos);
+		        gtk_text_buffer_delete(c->entry_buffer, &word_start, &cursor);
 			if (strlen(nick) == strlen(entered)) {
 				nicks = nicks->next ? nicks->next : c->in_room;
 				nick = nicks->data;
@@ -541,24 +552,17 @@
 					nick++;
 			}
 
-			if (start == 0) {
+			gtk_text_buffer_get_start_iter(c->entry_buffer, &start_buffer);
+			gtk_text_buffer_get_iter_at_mark(c->entry_buffer, &cursor,
+							 gtk_text_buffer_get_insert(c->entry_buffer));
+			if (!gtk_text_iter_compare(&cursor, &start_buffer)) {
 				char *tmp = g_strdup_printf("%s: ", nick);
-				int t = start;
-				gtk_editable_insert_text(GTK_EDITABLE(c->entry), tmp, strlen(tmp), &start);
-				if (t == start) {
-					t = start + strlen(tmp);
-					gtk_editable_set_position(GTK_EDITABLE(c->entry), t);
-				}
+				gtk_text_buffer_insert_at_cursor(c->entry_buffer, tmp, -1);
 				g_free(tmp);
 			} else {
-				int t = start;
-				gtk_editable_insert_text(GTK_EDITABLE(c->entry), nick, strlen(nick), &start);
-				if (t == start) {
-					t = start + strlen(nick);
-					gtk_editable_set_position(GTK_EDITABLE(c->entry), t);
-				}
+				gtk_text_buffer_insert_at_cursor(c->entry_buffer, nick, -1);
 			}
-			g_free(text);
+			g_free(entered);
 			return;
 		}
 
@@ -581,30 +585,27 @@
 	/* if there weren't any matches, return */
 	if (!matches) {
 		/* if matches isn't set partials won't be either */
-		g_free(text);
+		g_free(entered);
 		return;
 	}
 	
-	gtk_editable_delete_text(GTK_EDITABLE(c->entry), start, pos);
+	gtk_text_buffer_delete(c->entry_buffer, &word_start, &cursor);
 	if (!matches->next) {
 		/* there was only one match. fill it in. */
-		if (start == 0) {
+		gtk_text_buffer_get_start_iter(c->entry_buffer, &start_buffer);
+		gtk_text_buffer_get_iter_at_mark(c->entry_buffer, &cursor,
+						 gtk_text_buffer_get_insert(c->entry_buffer));
+		if (!gtk_text_iter_compare(&cursor, &start_buffer)) {
 			char *tmp = g_strdup_printf("%s: ", (char *)matches->data);
-			int t = start;
-			gtk_editable_insert_text(GTK_EDITABLE(c->entry), tmp, strlen(tmp), &start);
-			if (t == start) {
-				t = start + strlen(tmp);
-				gtk_editable_set_position(GTK_EDITABLE(c->entry), t);
-			}
+			gtk_text_buffer_insert_at_cursor(c->entry_buffer, tmp, -1);
 			g_free(tmp);
 		} else {
-			gtk_editable_insert_text(GTK_EDITABLE(c->entry), matches->data, strlen(matches->data), &start);
+			gtk_text_buffer_insert_at_cursor(c->entry_buffer, matches->data, -1);
 		}
 		matches = g_list_remove(matches, matches->data);
 	} else {
 		/* there were lots of matches, fill in as much as possible and display all of them */
 		char *addthis = g_malloc0(1);
-		int t = start;
 		while (matches) {
 			char *tmp = addthis;
 			addthis = g_strconcat(tmp, matches->data, " ", NULL);
@@ -612,15 +613,11 @@
 			matches = g_list_remove(matches, matches->data);
 		}
 		write_to_conv(c, addthis, WFLAG_NOLOG, NULL, time(NULL), -1);
-		gtk_editable_insert_text(GTK_EDITABLE(c->entry), partial, strlen(partial), &start);
-		if (t == start) {
-			t = start + strlen(partial);
-			gtk_editable_set_position(GTK_EDITABLE(c->entry), t);
-		}
+		gtk_text_buffer_insert_at_cursor(c->entry_buffer, partial, -1);
 		g_free(addthis);
 	}
-	
-	g_free(text);
+
+	g_free(entered);
 	g_free(partial);
 }
 
@@ -1180,6 +1177,8 @@
 	GtkWidget *win;
 	GtkWidget *cont;
 	GtkWidget *text;
+	/*GtkWidget *close;*/
+	GtkWidget *frame;
 	GtkWidget *chatentry;
 	GtkWidget *lbox;
 	GtkWidget *bbox;
@@ -1383,7 +1382,17 @@
 	gtk_paned_pack2(GTK_PANED(vpaned), vbox, TRUE, FALSE);
 	gtk_widget_show(vbox);
 
-	chatentry = gtk_text_new(NULL, NULL);
+	toolbar = build_conv_toolbar(b);
+	gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
+
+	frame = gtk_frame_new(NULL);
+	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(frame), TRUE, TRUE, 0);
+	gtk_widget_show(frame);
+	
+	b->entry_buffer = gtk_text_buffer_new(NULL);
+	g_object_set_data(G_OBJECT(b->entry_buffer), "user_data", b);
+	chatentry = gtk_text_view_new_with_buffer(b->entry_buffer);
 	b->entry = chatentry;
 	if (!(chat_options & OPT_CHAT_ONE_WINDOW))
 		gtk_window_set_focus(GTK_WINDOW(b->window), b->entry);
@@ -1391,23 +1400,18 @@
 
 	b->makesound = 1; /* Need to do this until we get a menu */
 
-	toolbar = build_conv_toolbar(b);
-	gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
-
-	gtk_object_set_user_data(GTK_OBJECT(chatentry), b);
-	gtk_text_set_editable(GTK_TEXT(chatentry), TRUE);
-	gtk_text_set_word_wrap(GTK_TEXT(chatentry), TRUE);
-	gtk_signal_connect(GTK_OBJECT(chatentry), "activate", GTK_SIGNAL_FUNC(send_callback), b);
-	gtk_signal_connect(GTK_OBJECT(chatentry), "key_press_event", GTK_SIGNAL_FUNC(keypress_callback),
-			   b);
-	gtk_signal_connect(GTK_OBJECT(chatentry), "key_press_event", GTK_SIGNAL_FUNC(entry_key_pressed),
-			   chatentry);
-	if (convo_options & OPT_CONVO_CHECK_SPELLING)
-		gtkspell_attach(GTK_TEXT(chatentry));
-	gtk_box_pack_start(GTK_BOX(vbox), chatentry, TRUE, TRUE, 0);
+	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(b->entry), GTK_WRAP_WORD);
+	g_signal_connect(G_OBJECT(b->entry), "key_press_event", G_CALLBACK(keypress_callback), b);
+	g_signal_connect_after(G_OBJECT(b->entry), "button_press_event", 
+			       G_CALLBACK(stop_rclick_callback), NULL);
+	g_signal_connect_swapped(G_OBJECT(chatentry), "key_press_event", 
+				 G_CALLBACK(entry_key_pressed), chatentry);
+	gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(chatentry));
 	gtk_widget_set_usize(chatentry, buddy_chat_size.width, MAX(buddy_chat_size.entry_height, 25));
 	gtk_window_set_focus(GTK_WINDOW(win), chatentry);
 	gtk_widget_show(chatentry);
+	/*if (convo_options & OPT_CONVO_CHECK_SPELLING)
+		gtkspell_attach(GTK_TEXT(chatentry));*/
 
 	bbox = gtk_hbox_new(FALSE, 5);
 	gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
--- a/src/conversation.c	Tue Oct 22 23:31:49 2002 +0000
+++ b/src/conversation.c	Wed Oct 23 00:12:49 2002 +0000
@@ -79,8 +79,9 @@
 extern GdkColor bgcolor;
 extern GdkColor fgcolor;
 
-void check_everything(GtkWidget *entry);
+void check_everything(GtkTextBuffer *buffer);
 gboolean keypress_callback(GtkWidget *entry, GdkEventKey * event, struct conversation *c);
+gboolean stop_rclick_callback(GtkWidget *widget, GdkEventButton *event, gpointer data);
 
 static void update_icon(struct conversation *);
 static void remove_icon(struct conversation *);
@@ -440,7 +441,6 @@
 	struct conversation *c = gtk_object_get_user_data(obj);
 	const char *name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(wid));
 	const char *filename;
-	int pos;
 	char *buf;
 	struct stat st;
 	int id = g_slist_length(c->images) + 1;
@@ -465,16 +465,8 @@
 	buf = g_strdup_printf ("<IMG SRC=\"file://%s\" ID=\"%d\" DATASIZE=\"%d\">",
 			       filename, id, (int)st.st_size);
 	c->images = g_slist_append(c->images, g_strdup(name));
-
-	if (GTK_OLD_EDITABLE(c->entry)->has_selection) {
-		int finish = GTK_OLD_EDITABLE(c->entry)->selection_end_pos;
-		gtk_editable_insert_text(GTK_EDITABLE(c->entry),
-					 buf, strlen(buf), &finish);
-	} else {
-		pos = GTK_OLD_EDITABLE(c->entry)->current_pos;
-		gtk_editable_insert_text(GTK_EDITABLE(c->entry),
-					 buf, strlen(buf), &pos);
-	}
+	gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(c->entry_buffer),
+					 buf, -1);
 	g_free(buf);
 }
 
@@ -520,8 +512,8 @@
 
 	debug_printf("conversation close callback\n");
 
-	if (convo_options & OPT_CONVO_CHECK_SPELLING)
-		gtkspell_detach(GTK_TEXT(c->entry));
+/*	if (convo_options & OPT_CONVO_CHECK_SPELLING)
+		gtkspell_detach(GTK_TEXT(c->entry));*/
 
 	if (!c->is_chat) {
 		GSList *cn = connections;
@@ -625,7 +617,7 @@
 	c->hasfont = 1;
 
 	pre_fontface = g_strconcat("<FONT FACE=\"", c->fontface, "\">", NULL);
-	surround(c->entry, pre_fontface, "</FONT>");
+	surround(c, pre_fontface, "</FONT>");
 	gtk_widget_grab_focus(c->entry);
 	g_free(pre_fontface);
 }
@@ -821,14 +813,13 @@
 	if (c && c->gc && c->name) {
 		c->type_again = 1;
 		serv_send_typing(c->gc, c->name, TYPED);
+		debug_printf("typed...\n");
 	}
 	return FALSE;
 }
 
-gboolean keypress_callback(GtkWidget *entry, GdkEventKey * event, struct conversation *c)
+gboolean keypress_callback(GtkWidget *entry, GdkEventKey *event, struct conversation *c)
 {
-	int pos;
-
 	if (event->keyval == GDK_Escape) {
 		if (convo_options & OPT_CONVO_ESC_CAN_CLOSE) {
 			gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
@@ -847,47 +838,36 @@
 		gtk_imhtml_show_comments(GTK_IMHTML(c->text), !GTK_IMHTML(c->text)->comments);
 	} else if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter)) {
 		if ((event->state & GDK_CONTROL_MASK) && (convo_options & OPT_CONVO_CTL_ENTER)) {
-			gtk_signal_emit_by_name(GTK_OBJECT(entry), "activate", c);
+			send_callback(NULL, c);
 			gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
 			return TRUE;
 		} else if (!(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) && (convo_options & OPT_CONVO_ENTER_SENDS)) {
-			gtk_signal_emit_by_name(GTK_OBJECT(entry), "activate", c);
+			send_callback(NULL, c);
 			gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
 			return TRUE;
 		} else {
-			int oldpos;
-			gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
-			oldpos = pos = gtk_editable_get_position(GTK_EDITABLE(entry));
-			gtk_editable_insert_text(GTK_EDITABLE(entry), "\n", 1, &pos);
-			if (oldpos == pos)
-				gtk_editable_set_position(GTK_EDITABLE(entry), pos + 1);
-			return TRUE;
+			return FALSE;
 		}
 	} else if ((event->state & GDK_CONTROL_MASK) && (event->keyval == 'm')) {
-		int oldpos;
 		gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
-		oldpos = pos = gtk_editable_get_position(GTK_EDITABLE(entry));
-		gtk_editable_insert_text(GTK_EDITABLE(entry), "\n", 1, &pos);
-		if (oldpos == pos)
-			gtk_editable_set_position(GTK_EDITABLE(entry), pos + 1);
+		gtk_text_buffer_insert_at_cursor(c->entry_buffer, "\n", 1);
 	} else if (event->state & GDK_CONTROL_MASK) {
-		int pos = 0;
 		switch (event->keyval) {
 		case GDK_Up:
 			if (!c->send_history)
 				break;
 			if (!c->send_history->prev) {
+				GtkTextIter start, end;
 				if (c->send_history->data)
 					g_free(c->send_history->data);
-				c->send_history->data = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
+				gtk_text_buffer_get_start_iter(c->entry_buffer, &start);
+				gtk_text_buffer_get_end_iter(c->entry_buffer, &end);
+				c->send_history->data = gtk_text_buffer_get_text(c->entry_buffer,
+										 &start, &end, FALSE);
 			} 
 			if (c->send_history->next && c->send_history->next->data) {
 				c->send_history = c->send_history->next;
-				gtk_editable_delete_text (GTK_EDITABLE(entry),0,-1);
-				gtk_editable_insert_text(GTK_EDITABLE(entry), 
-							 c->send_history->data, 
-							 strlen(c->send_history->data),
-							 &pos);
+				gtk_text_buffer_set_text(c->entry_buffer, c->send_history->data, -1);
 			}
 			
 			break;
@@ -897,10 +877,7 @@
 			if (c->send_history->prev) {
 			  c->send_history = c->send_history->prev;
 				if (c->send_history->data) {
-					gtk_editable_delete_text (GTK_EDITABLE(entry),0,-1);
-					gtk_editable_insert_text (GTK_EDITABLE(entry), c->send_history->data, 
-								  strlen(c->send_history->data), &pos);
-				
+					gtk_text_buffer_set_text(c->entry_buffer, c->send_history->data, -1);
 				}
 			}
 			break;
@@ -911,7 +888,7 @@
 			case 'I':
 				quiet_set(c->italic,
 					  !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(c->italic)));
-				do_italic(c->italic, c->entry);
+				do_italic(c->italic, c);
 				gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
 				break;
 			case 'u':	/* ctl-u is GDK_Clear, which clears the line */
@@ -919,27 +896,27 @@
 				quiet_set(c->underline,
 					  !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
 									(c->underline)));
-				do_underline(c->underline, c->entry);
+				do_underline(c->underline, c);
 				gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
 				break;
 			case 'b':	/* ctl-b is GDK_Left, which moves backwards */
 			case 'B':
 				quiet_set(c->bold,
 					  !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(c->bold)));
-				do_bold(c->bold, c->entry);
+				do_bold(c->bold, c);
 				gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
 				break;
 			case '-':
-				do_small(NULL, c->entry);
+				do_small(NULL, c);
 				gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
 				break;
 			case '=':
 			case '+':
-				do_big(NULL, c->entry);
+				do_big(NULL, c);
 				gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
 				break;	
 			case '0':
-				do_normal(NULL, c->entry);
+				do_normal(NULL, c);
 				gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
 				break;
 			case 'f':
@@ -1005,15 +982,7 @@
 				break;
 			}
 			if (buf[0]) {
-				if (GTK_OLD_EDITABLE(c->entry)->has_selection) {
-					int finish = GTK_OLD_EDITABLE(c->entry)->selection_end_pos;
-					gtk_editable_insert_text(GTK_EDITABLE(c->entry),
-								 buf, strlen(buf), &finish);
-				} else {
-					pos = GTK_OLD_EDITABLE(c->entry)->current_pos;
-					gtk_editable_insert_text(GTK_EDITABLE(c->entry),
-								 buf, strlen(buf), &pos);
-				}
+				gtk_text_buffer_insert_at_cursor(c->entry_buffer, buf, -1);
 				gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event");
 			}
 		}
@@ -1070,6 +1039,20 @@
 	return FALSE;
 }
 
+/* This guy just kills a single right click from being propagated any 
+ * further.  I have no idea *why* we need this, but we do ...  It 
+ * prevents right clicks on the GtkTextView in a convo dialog from
+ * going all the way down to the notebook.  I suspect a bug in 
+ * GtkTextView, but I'm not ready to point any fingers yet. */
+gboolean stop_rclick_callback(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+	if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
+		/* right single click */
+		g_signal_stop_emission_by_name(G_OBJECT(widget), "button_press_event");
+		return TRUE;
+	}
+}
+
 static void got_typing_keypress(struct conversation *c, gboolean first) {
 	/* we know we got something, so we at least have to make sure we don't send
 	 * TYPED any time soon */
@@ -1088,9 +1071,8 @@
 	}
 }
 
-void delete_text_callback(GtkEditable *editable, gint start_pos, gint end_pos, gpointer user_data) {
+void delete_text_callback(GtkTextBuffer *textbuffer, GtkTextIter *start_pos, GtkTextIter *end_pos, gpointer user_data) {
 	struct conversation *c = user_data;
-	gchar *contents;
 
 	if(!c)
 		return;
@@ -1098,8 +1080,7 @@
 	if (misc_options & OPT_MISC_STEALTH_TYPING)
 		return;
 
-	contents = gtk_editable_get_chars(editable, 0, -1);
-	if(start_pos == 0 && (end_pos == strlen(contents) || end_pos == -1)) {
+	if(gtk_text_iter_is_start(start_pos) && gtk_text_iter_is_end(end_pos)) {
 		if(c->type_again_timeout)
 			gtk_timeout_remove(c->type_again_timeout);
 		serv_send_typing(c->gc, c->name, NOT_TYPING);
@@ -1107,12 +1088,10 @@
 		/* we're deleting, but not all of it, so it counts as typing */
 		got_typing_keypress(c, FALSE);
 	}
-	g_free(contents);
 }
 
-void insert_text_callback(GtkEditable *editable, gchar *new_text, gint new_text_length, gint *position, gpointer user_data) {
+void insert_text_callback(GtkTextBuffer *textbuffer, GtkTextIter *position, gchar *new_text, gint new_text_length, gpointer user_data) {
 	struct conversation *c = user_data;
-	gchar *contents;
 
 	if(!c)
 		return;
@@ -1120,9 +1099,7 @@
 	if (misc_options & OPT_MISC_STEALTH_TYPING)
 		return;
 
-	contents = gtk_editable_get_chars(editable, 0, -1);
-	got_typing_keypress(c, (*position == 0 && strlen(contents) == 0));
-	g_free(contents);
+	got_typing_keypress(c, (gtk_text_iter_is_start(position) && gtk_text_iter_is_end(position)));
 }
 
 void send_callback(GtkWidget *widget, struct conversation *c)
@@ -1132,12 +1109,14 @@
 	gulong length=0;
 	int err = 0;
 	GList *first;
+	GtkTextIter start_iter, end_iter;
 
 	if (!c->gc)
 		return;
 
-
-	buf2 = gtk_editable_get_chars(GTK_EDITABLE(c->entry), 0, -1);
+	gtk_text_buffer_get_start_iter(c->entry_buffer, &start_iter);
+	gtk_text_buffer_get_end_iter(c->entry_buffer, &end_iter);
+	buf2 = gtk_text_buffer_get_text(c->entry_buffer, &start_iter, &end_iter, FALSE);
 	limit = 32 * 1024;	/* you shouldn't be sending more than 32k in your messages. that's a book. */
 	buf = g_malloc(limit);
 	g_snprintf(buf, limit, "%s", buf2);
@@ -1223,7 +1202,7 @@
 			return;
 		}
 		if (plugin_return) {
-			gtk_editable_delete_text(GTK_EDITABLE(c->entry), 0, -1);
+			gtk_text_buffer_set_text(c->entry_buffer, "", -1);
 			g_free(buffy);
 			g_free(buf2);
 			g_free(buf);
@@ -1362,7 +1341,7 @@
 		else
 			do_error_dialog(_("Unable to send message"), NULL, GAIM_ERROR);
 	} else {
-		gtk_editable_delete_text(GTK_EDITABLE(c->entry), 0, -1);
+		gtk_text_buffer_set_text(c->entry_buffer, "", -1);
 
 		if ((err > 0) && (away_options & OPT_AWAY_BACK_ON_IM)) {
 			if (awaymessage != NULL) {
@@ -1374,9 +1353,9 @@
 	}
 }
 
-int entry_key_pressed(GtkWidget *w, GtkWidget *entry)
+gboolean entry_key_pressed(GtkTextBuffer *buffer)
 {
-	check_everything(w);
+	check_everything(buffer);
 	return FALSE;
 }
 
@@ -1384,15 +1363,18 @@
 /*  HTML-type stuff                                                       */
 /*------------------------------------------------------------------------*/
 
-int count_tag(GtkWidget *entry, char *s1, char *s2)
+int count_tag(GtkTextBuffer *buffer, char *s1, char *s2)
 {
 	char *p1, *p2;
 	int res = 0;
-	char *tmp, *tmpo, h;
-	tmpo = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
-	h = tmpo[GTK_OLD_EDITABLE(entry)->current_pos];
-	tmpo[GTK_OLD_EDITABLE(entry)->current_pos] = '\0';
-	tmp = tmpo;
+	GtkTextIter start, end;
+	char *tmp, *tmpo;
+
+	gtk_text_buffer_get_start_iter(buffer, &start);
+	gtk_text_buffer_get_iter_at_mark(buffer, &end,
+					 gtk_text_buffer_get_insert(buffer));
+  
+	tmp = tmpo = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
 	do {
 		p1 = strstr(tmp, s1);
 		p2 = strstr(tmp, s2);
@@ -1414,50 +1396,57 @@
 			}
 		}
 	} while (p1 || p2);
-	tmpo[GTK_OLD_EDITABLE(entry)->current_pos] = h;
 	g_free(tmpo);
 	return res;
 }
 
 
-int invert_tags(GtkWidget *entry, char *s1, char *s2, int really)
+gboolean invert_tags(GtkTextBuffer *buffer, char *s1, char *s2, gboolean really)
 {
-	int start = GTK_OLD_EDITABLE(entry)->selection_start_pos;
-	int finish = GTK_OLD_EDITABLE(entry)->selection_end_pos;
-	char *s;
-
-	s = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
-	if (!g_strncasecmp(&s[start], s1, strlen(s1)) &&
-	    !g_strncasecmp(&s[finish - strlen(s2)], s2, strlen(s2))) {
-		if (really) {
-			gtk_editable_delete_text(GTK_EDITABLE(entry), start, start + strlen(s1));
-			gtk_editable_delete_text(GTK_EDITABLE(entry), finish - strlen(s2) - strlen(s1),
-						 finish - strlen(s1));
+	GtkTextIter start1, start2, end1, end2;
+	char *b1, *b2;
+
+	if (gtk_text_buffer_get_selection_bounds(buffer, &start1, &end2)) {
+		start2 = start1; end1 = end2;
+		if (!gtk_text_iter_forward_chars(&start2, strlen(s1)))
+			return FALSE;
+		if (!gtk_text_iter_backward_chars(&end1, strlen(s2)))
+			return FALSE;
+		b1 = gtk_text_buffer_get_text(buffer, &start1, &start2, FALSE);
+		b2 = gtk_text_buffer_get_text(buffer, &end1, &end2, FALSE);
+		if (!g_strncasecmp(b1, s1, strlen(s1)) &&
+		    !g_strncasecmp(b2, s2, strlen(s2))) {
+			if (really) {
+				GtkTextMark *m_end1, *m_end2;
+ 
+				m_end1= gtk_text_buffer_create_mark(buffer, "m1", &end1, TRUE);
+				m_end2= gtk_text_buffer_create_mark(buffer, "m2", &end2, TRUE);
+
+				gtk_text_buffer_delete(buffer, &start1, &start2);
+				gtk_text_buffer_get_iter_at_mark(buffer, &end1, m_end1);
+				gtk_text_buffer_get_iter_at_mark(buffer, &end2, m_end2);
+				gtk_text_buffer_delete(buffer, &end1, &end2);
+				gtk_text_buffer_delete_mark(buffer, m_end1);
+				gtk_text_buffer_delete_mark(buffer, m_end2);
+			}
+			 g_free(b1); g_free(b2);
+			return TRUE;
 		}
-		g_free(s);
-		return 1;
+		g_free(b1);g_free(b2);
 	}
-	g_free(s);
-	return 0;
+	return FALSE;
 }
 
 
-void remove_tags(GtkWidget *entry, char *tag)
+void remove_tags(struct conversation *c, char *tag)
 {
-	char *s, *t;
-	int start = GTK_OLD_EDITABLE(entry)->selection_start_pos;
-	int finish = GTK_OLD_EDITABLE(entry)->selection_end_pos;
-	int temp;
-	s = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
-	t = s;
-
-	if (start > finish) {
-		temp = start;
-		start = finish;
-		finish = temp;
-	}
-
-	if (strstr(tag, "<FONT SIZE=")) {
+	GtkTextIter start, end, m_start, m_end;
+
+	if (!gtk_text_buffer_get_selection_bounds(c->entry_buffer,
+						  &start, &end))
+		return;
+
+	/* FIXMEif (strstr(tag, "<FONT SIZE=")) {
 		while ((t = strstr(t, "<FONT SIZE="))) {
 			if (((t - s) < finish) && ((t - s) >= start)) {
 				gtk_editable_delete_text(GTK_EDITABLE(entry), (t - s),
@@ -1468,19 +1457,12 @@
 			} else
 				t++;
 		}
-	} else {
-		while ((t = strstr(t, tag))) {
-			if (((t - s) < finish) && ((t - s) >= start)) {
-				gtk_editable_delete_text(GTK_EDITABLE(entry), (t - s),
-							 (t - s) + strlen(tag));
-				g_free(s);
-				s = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
-				t = s;
-			} else
-				t++;
+	} else*/ {
+		while (gtk_text_iter_forward_search(&start, tag, 0, &m_start, &m_end, &end)) {
+			gtk_text_buffer_delete(c->entry_buffer, &m_start, &m_end);
+			gtk_text_buffer_get_selection_bounds(c->entry_buffer, &start, &end);
 		}
 	}
-	g_free(s);
 }
 
 static char *html_logize(char *p)
@@ -1524,72 +1506,57 @@
 	return buffer_start;
 }
 
-void surround(GtkWidget *entry, char *pre, char *post)
+void surround(struct conversation *c, char *pre, char *post)
 {
-	int temp, pos = GTK_OLD_EDITABLE(entry)->current_pos;
-	int dummy;
-	int start, finish;
-
-	if (convo_options & OPT_CONVO_CHECK_SPELLING) {
+	GtkTextIter start, end;
+	GtkTextMark *mark_start, *mark_end;
+
+/*	if (convo_options & OPT_CONVO_CHECK_SPELLING) {
 		gtkspell_detach(GTK_TEXT(entry));
-	}
-
-	if (GTK_OLD_EDITABLE(entry)->has_selection) {
-		remove_tags(entry, pre);
-		remove_tags(entry, post);
-		start = GTK_OLD_EDITABLE(entry)->selection_start_pos;
-		finish = GTK_OLD_EDITABLE(entry)->selection_end_pos;
-		if (start > finish) {
-			dummy = finish;
-			finish = start;
-			start = dummy;
-		}
-		dummy = start;
-		gtk_editable_insert_text(GTK_EDITABLE(entry), pre, strlen(pre), &dummy);
-		dummy = finish + strlen(pre);
-		gtk_editable_insert_text(GTK_EDITABLE(entry), post, strlen(post), &dummy);
-		gtk_editable_select_region(GTK_EDITABLE(entry), start,
-					   finish + strlen(pre) + strlen(post));
+	}*/
+
+	if (gtk_text_buffer_get_selection_bounds(c->entry_buffer, &start, &end)) {
+		remove_tags(c, pre);
+		remove_tags(c, post);
+
+		mark_start = gtk_text_buffer_create_mark(c->entry_buffer, "m1", &start, TRUE);
+		mark_end = gtk_text_buffer_create_mark(c->entry_buffer, "m2", &end, FALSE);
+		gtk_text_buffer_insert(c->entry_buffer, &start, pre, -1);
+		gtk_text_buffer_get_selection_bounds(c->entry_buffer, &start, &end);
+		gtk_text_buffer_insert(c->entry_buffer, &end, post, -1);
+		gtk_text_buffer_get_iter_at_mark(c->entry_buffer, &start, mark_start);
+		gtk_text_buffer_move_mark_by_name(c->entry_buffer, "selection_bound", &start);
 	} else {
-		temp = pos;
-		gtk_editable_insert_text(GTK_EDITABLE(entry), pre, strlen(pre), &pos);
-		if (temp == pos) {
-			dummy = pos + strlen(pre);
-			gtk_editable_insert_text(GTK_EDITABLE(entry), post, strlen(post), &dummy);
-			gtk_editable_set_position(GTK_EDITABLE(entry), dummy);
-		} else {
-			dummy = pos;
-			gtk_editable_insert_text(GTK_EDITABLE(entry), post, strlen(post), &dummy);
-			gtk_editable_set_position(GTK_EDITABLE(entry), pos);
-		}
+		gtk_text_buffer_insert(c->entry_buffer, &start, pre, -1);
+		gtk_text_buffer_insert(c->entry_buffer, &start, post, -1);
+		mark_start = gtk_text_buffer_get_insert(c->entry_buffer);
+		gtk_text_buffer_get_iter_at_mark(c->entry_buffer, &start, mark_start);
+		gtk_text_iter_backward_chars(&start, strlen(post));
+		gtk_text_buffer_place_cursor(c->entry_buffer, &start);
 	}
 
-	if (convo_options & OPT_CONVO_CHECK_SPELLING) {
+/*	if (convo_options & OPT_CONVO_CHECK_SPELLING) {
 		gtkspell_attach(GTK_TEXT(entry));
-	}
-
-	gtk_widget_grab_focus(entry);
+	}*/
+
+	gtk_widget_grab_focus(c->entry);
 }
 
-void advance_past(GtkWidget *entry, char *pre, char *post)
+void advance_past(struct conversation *c, char *pre, char *post)
 {
-	char *s, *s2;
-	int pos;
-	if (invert_tags(entry, pre, post, 1))
+	GtkTextIter current_pos, start, end;
+
+	if (invert_tags(c->entry_buffer, pre, post, 1))
 		return;
-	s = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
-	pos = GTK_OLD_EDITABLE(entry)->current_pos;
-	debug_printf(_("Currently at %d, "), pos);
-	s2 = strstr(&s[pos], post);
-	if (s2) {
-		pos = s2 - s + strlen(post);
-	} else {
-		gtk_editable_insert_text(GTK_EDITABLE(entry), post, strlen(post), &pos);
-	}
-	g_free(s);
-	debug_printf(_("Setting position to %d\n"), pos);
-	gtk_editable_set_position(GTK_EDITABLE(entry), pos);
-	gtk_widget_grab_focus(entry);
+
+	gtk_text_buffer_get_iter_at_mark(c->entry_buffer, &current_pos,
+					 gtk_text_buffer_get_insert(c->entry_buffer));
+	if (gtk_text_iter_forward_search(&current_pos, post, 0, &start, &end, NULL))
+		gtk_text_buffer_place_cursor(c->entry_buffer, &end);
+	else
+		gtk_text_buffer_insert_at_cursor(c->entry_buffer, post, -1);
+
+	gtk_widget_grab_focus(c->entry);
 }
 
 void toggle_fg_color(GtkWidget *color, struct conversation *c)
@@ -1601,7 +1568,7 @@
 	else if (c->fg_color_dialog)
 		cancel_fgcolor(color, c);
 	else
-		advance_past(c->entry, "<FONT COLOR>", "</FONT>");
+		advance_past(c, "<FONT COLOR>", "</FONT>");
 }
 
 void toggle_bg_color(GtkWidget *color, struct conversation *c)
@@ -1613,7 +1580,7 @@
 	else if (c->bg_color_dialog)
 		cancel_bgcolor(color, c);
 	else
-		advance_past(c->entry, "<BODY BGCOLOR>", "</BODY>");
+		advance_past(c, "<BODY BGCOLOR>", "</BODY>");
 }
 
 void toggle_font(GtkWidget *font, struct conversation *c)
@@ -1625,7 +1592,7 @@
 	else if (c->font_dialog)
 		cancel_font(font, c);
 	else
-		advance_past(c->entry, "<FONT FACE>", "</FONT>");
+		advance_past(c, "<FONT FACE>", "</FONT>");
 }
 
 void insert_link_cb(GtkWidget *w, struct conversation *c)
@@ -1644,143 +1611,144 @@
 	else if (c->link_dialog)
 		cancel_link(c->link, c);
 	else
-		advance_past(c->entry, "<A HREF>", "</A>");
+		advance_past(c, "<A HREF>", "</A>");
 
 	gtk_widget_grab_focus(c->entry);
 }
 
-void do_strike(GtkWidget *strike, GtkWidget *entry)
+void do_strike(GtkWidget *strike, struct conversation *c)
 {
 	if (state_lock)
 		return;
 
 	if (GTK_TOGGLE_BUTTON(strike)->active)
-		surround(entry, "<STRIKE>", "</STRIKE>");
+		surround(c, "<STRIKE>", "</STRIKE>");
 	else
-		advance_past(entry, "<STRIKE>", "</STRIKE>");
-
+		advance_past(c, "<STRIKE>", "</STRIKE>");
+
+	gtk_widget_grab_focus(c->entry);
 }
 
-void do_bold(GtkWidget *bold, GtkWidget *entry)
+void do_bold(GtkWidget *bold, struct conversation *c)
 {
 	if (state_lock)
 		return;
 	if (GTK_TOGGLE_BUTTON(bold)->active)
-		surround(entry, "<B>", "</B>");
+		surround(c, "<B>", "</B>");
 	else
-		advance_past(entry, "<B>", "</B>");
-
-	gtk_widget_grab_focus(entry);
+		advance_past(c, "<B>", "</B>");
+
+	gtk_widget_grab_focus(c->entry);
 }
 
-void do_underline(GtkWidget *underline, GtkWidget *entry)
+void do_underline(GtkWidget *underline, struct conversation *c)
 {
 	if (state_lock)
 		return;
 	if (GTK_TOGGLE_BUTTON(underline)->active)
-		surround(entry, "<U>", "</U>");
+		surround(c, "<U>", "</U>");
 	else
-		advance_past(entry, "<U>", "</U>");
-
-	gtk_widget_grab_focus(entry);
+		advance_past(c, "<U>", "</U>");
+
+	gtk_widget_grab_focus(c->entry);
 }
 
-void do_italic(GtkWidget *italic, GtkWidget *entry)
+void do_italic(GtkWidget *italic, struct conversation *c)
 {
 	if (state_lock)
 		return;
 	if (GTK_TOGGLE_BUTTON(italic)->active)
-		surround(entry, "<I>", "</I>");
+		surround(c, "<I>", "</I>");
 	else
-		advance_past(entry, "<I>", "</I>");
-
-	gtk_widget_grab_focus(entry);
+		advance_past(c, "<I>", "</I>");
+
+	gtk_widget_grab_focus(c->entry);
 }
 
 /* html code to modify font sizes must all be the same length, */
 /* currently set to 15 chars */
 
-void do_small(GtkWidget *small, GtkWidget *entry)
+void do_small(GtkWidget *small, struct conversation *c)
 {
 	if (state_lock)
 		return;
 
-	surround(entry, "<FONT SIZE=\"1\">", "</FONT>");
-
-	gtk_widget_grab_focus(entry);
+	surround(c, "<FONT SIZE=\"1\">", "</FONT>");
+
+	gtk_widget_grab_focus(c->entry);
 }
 
-void do_normal(GtkWidget *normal, GtkWidget *entry)
+void do_normal(GtkWidget *normal, struct conversation *c)
 {
 	if (state_lock)
 		return;
 
-	surround(entry, "<FONT SIZE=\"3\">", "</FONT>");
-
-	gtk_widget_grab_focus(entry);
+	surround(c, "<FONT SIZE=\"3\">", "</FONT>");
+
+	gtk_widget_grab_focus(c->entry);
 }
 
-void do_big(GtkWidget *big, GtkWidget *entry)
+void do_big(GtkWidget *big, struct conversation *c)
 {
 	if (state_lock)
 		return;
 
-	surround(entry, "<FONT SIZE=\"5\">", "</FONT>");
-
-	gtk_widget_grab_focus(entry);
+	surround(c, "<FONT SIZE=\"5\">", "</FONT>");
+
+	gtk_widget_grab_focus(c->entry);
 }
 
-void check_everything(GtkWidget *entry)
+void check_everything(GtkTextBuffer *buffer)
 {
 	struct conversation *c;
 
-	c = (struct conversation *)gtk_object_get_user_data(GTK_OBJECT(entry));
+	c = (struct conversation *)g_object_get_data(G_OBJECT(buffer), "user_data");
 	if (!c)
 		return;
-	if (invert_tags(entry, "<B>", "</B>", 0))
+	if (invert_tags(c->entry_buffer, "<B>", "</B>", 0))
 		quiet_set(c->bold, TRUE);
-	else if (count_tag(entry, "<B>", "</B>"))
+	else if (count_tag(c->entry_buffer, "<B>", "</B>"))
 		quiet_set(c->bold, TRUE);
 	else
 		quiet_set(c->bold, FALSE);
-	if (invert_tags(entry, "<I>", "</I>", 0))
+	if (invert_tags(c->entry_buffer, "<I>", "</I>", 0))
 		quiet_set(c->italic, TRUE);
-	else if (count_tag(entry, "<I>", "</I>"))
+	else if (count_tag(c->entry_buffer, "<I>", "</I>"))
 		quiet_set(c->italic, TRUE);
 	else
 		quiet_set(c->italic, FALSE);
 
-	if (invert_tags(entry, "<FONT COLOR", "</FONT>", 0))
+	if (invert_tags(c->entry_buffer, "<FONT COLOR", "</FONT>", 0))
 		quiet_set(c->fgcolorbtn, TRUE);
-	else if (count_tag(entry, "<FONT COLOR", "</FONT>"))
+	else if (count_tag(c->entry_buffer, "<FONT COLOR", "</FONT>"))
 		quiet_set(c->fgcolorbtn, TRUE);
 	else
 		quiet_set(c->fgcolorbtn, FALSE);
 
-	if (invert_tags(entry, "<BODY BGCOLOR", "</BODY>", 0))
+	if (invert_tags(c->entry_buffer, "<BODY BGCOLOR", "</BODY>", 0))
 		quiet_set(c->bgcolorbtn, TRUE);
-	else if (count_tag(entry, "<BODY BGCOLOR", "</BODY>"))
+	else if (count_tag(c->entry_buffer, "<BODY BGCOLOR", "</BODY>"))
 		quiet_set(c->bgcolorbtn, TRUE);
 	else
 		quiet_set(c->bgcolorbtn, FALSE);
 
-	if (invert_tags(entry, "<FONT FACE", "</FONT>", 0))
+	if (invert_tags(c->entry_buffer, "<FONT FACE", "</FONT>", 0))
 		quiet_set(c->font, TRUE);
-	else if (count_tag(entry, "<FONT FACE", "</FONT>"))
+	else if (count_tag(c->entry_buffer, "<FONT FACE", "</FONT>"))
 		quiet_set(c->font, TRUE);
 	else
 		quiet_set(c->font, FALSE);
 
-	if (invert_tags(entry, "<A HREF", "</A>", 0))
+	if (invert_tags(c->entry_buffer, "<A HREF", "</A>", 0))
 		quiet_set(c->link, TRUE);
-	else if (count_tag(entry, "<A HREF", "</A>"))
+	else if (count_tag(c->entry_buffer, "<A HREF", "</A>"))
 		quiet_set(c->link, TRUE);
 	else
 		quiet_set(c->link, FALSE);
 
-	if (invert_tags(entry, "<U>", "</U>", 0))
+	if (invert_tags(c->entry_buffer, "<U>", "</U>", 0))
 		quiet_set(c->underline, TRUE);
-	else if (count_tag(entry, "<U>", "</U>"))
+	else if (count_tag(c->entry_buffer, "<U>", "</U>"))
 		quiet_set(c->underline, TRUE);
 	else
 		quiet_set(c->underline, FALSE);
@@ -2249,21 +2217,21 @@
 		button = gaim_pixbuf_toolbar_button_from_stock("gtk-bold");
 		gtk_size_group_add_widget(sg, button);
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_bold), c->entry);
+		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_bold), c);
 		c->bold = button; /* We should remember this */
 
 		/* Italic */
 		button = gaim_pixbuf_toolbar_button_from_stock("gtk-italic");
 		gtk_size_group_add_widget(sg, button);
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_italic), c->entry);
+		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_italic), c);
 		c->italic = button; /* We should remember this */
 
 		/* Underline */
 		button = gaim_pixbuf_toolbar_button_from_stock("gtk-underline");
 		gtk_size_group_add_widget(sg, button);
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_underline), c->entry);
+		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_underline), c);
 		c->underline = button; /* We should remember this */
 
 		/* Sep */
@@ -2274,20 +2242,20 @@
 		button = gaim_pixbuf_toolbar_button_from_file("text_bigger.png");
 		gtk_size_group_add_widget(sg, button);
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_big), c->entry);
+		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_big), c);
 		
 		/* Normal Font Size */
 		button = gaim_pixbuf_toolbar_button_from_file("text_normal.png");
 		gtk_size_group_add_widget(sg, button);
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_normal), c->entry);
+		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_normal), c);
 		c->font = button; /* We should remember this */
 		
 		/* Decrease font size */
 		button = gaim_pixbuf_toolbar_button_from_file("text_smaller.png");
 		gtk_size_group_add_widget(sg, button);
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_small), c->entry);
+		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(do_small), c);
 
 		/* Sep */
 		sep = gtk_vseparator_new();
@@ -2753,6 +2721,7 @@
 	GtkWidget *warn;
 	GtkWidget *block;
 	/*GtkWidget *close;*/
+	GtkWidget *frame;
 	GtkWidget *entry;
 	GtkWidget *bbox;
 	GtkWidget *vbox;
@@ -2904,29 +2873,38 @@
 	gtk_box_pack_start(GTK_BOX(vbox2), c->lbox, FALSE, FALSE, 0);
 	gtk_widget_show(c->lbox);
 
-	entry = gtk_text_new(NULL, NULL);
+	toolbar = build_conv_toolbar(c);
+	gtk_box_pack_start(GTK_BOX(vbox2), toolbar, FALSE, FALSE, 0);
+
+	frame = gtk_frame_new(NULL);
+	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+	gtk_box_pack_start(GTK_BOX(vbox2), frame, TRUE, TRUE, 0);
+	gtk_widget_show(frame);
+	
+	c->entry_buffer = gtk_text_buffer_new(NULL);
+	g_object_set_data(G_OBJECT(c->entry_buffer), "user_data", c);
+	entry = gtk_text_view_new_with_buffer(c->entry_buffer);
 	c->entry = entry;
 	if (!(im_options & OPT_IM_ONE_WINDOW))
 		gtk_window_set_focus(GTK_WINDOW(c->window), c->entry);
 
-	toolbar = build_conv_toolbar(c);
-	gtk_box_pack_start(GTK_BOX(vbox2), toolbar, FALSE, FALSE, 0);
-
-	gtk_object_set_user_data(GTK_OBJECT(entry), c);
-	gtk_text_set_editable(GTK_TEXT(entry), TRUE);
-	gtk_text_set_word_wrap(GTK_TEXT(entry), TRUE);
+	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(c->entry), GTK_WRAP_WORD);
 
 	gtk_widget_set_usize(entry, conv_size.width - 20, MAX(conv_size.entry_height, 25));
 
-	gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(send_callback), c);
-	gtk_signal_connect(GTK_OBJECT(entry), "key_press_event", GTK_SIGNAL_FUNC(keypress_callback), c);
-	gtk_signal_connect(GTK_OBJECT(entry), "insert-text", GTK_SIGNAL_FUNC(insert_text_callback), c);
-	gtk_signal_connect(GTK_OBJECT(entry), "delete-text", GTK_SIGNAL_FUNC(delete_text_callback), c);
-	gtk_signal_connect(GTK_OBJECT(entry), "key_press_event", GTK_SIGNAL_FUNC(entry_key_pressed),
-			   entry);
-	if (convo_options & OPT_CONVO_CHECK_SPELLING)
-		gtkspell_attach(GTK_TEXT(c->entry));
-	gtk_box_pack_start(GTK_BOX(vbox2), entry, TRUE, TRUE, 0);
+	g_signal_connect_swapped(G_OBJECT(c->entry), "key_press_event",
+				 G_CALLBACK(entry_key_pressed), c->entry_buffer);
+	g_signal_connect(G_OBJECT(c->entry), "key_press_event", G_CALLBACK(keypress_callback), c);
+	g_signal_connect_after(G_OBJECT(c->entry), "button_press_event", 
+			       G_CALLBACK(stop_rclick_callback), NULL);
+	g_signal_connect(G_OBJECT(c->entry_buffer), "insert_text",
+			   G_CALLBACK(insert_text_callback), c);
+	g_signal_connect(G_OBJECT(c->entry_buffer), "delete_range",
+			   G_CALLBACK(delete_text_callback), c);
+
+/*	if (convo_options & OPT_CONVO_CHECK_SPELLING)
+		gtkspell_attach(GTK_TEXT(c->entry));*/
+	gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(entry));
 	gtk_widget_show(entry);
 
 	c->bbox = bbox = gtk_hbox_new(FALSE, 5);
@@ -3045,10 +3023,10 @@
 
 	while (cnv) {
 		c = (struct conversation *)cnv->data;
-		if (convo_options & OPT_CONVO_CHECK_SPELLING)
+/*		if (convo_options & OPT_CONVO_CHECK_SPELLING)
 			gtkspell_attach(GTK_TEXT(c->entry));
 		else
-			gtkspell_detach(GTK_TEXT(c->entry));
+			gtkspell_detach(GTK_TEXT(c->entry));*/
 		cnv = cnv->next;
 	}
 
@@ -3057,10 +3035,10 @@
 		cht = gc->buddy_chats;
 		while (cht) {
 			c = (struct conversation *)cht->data;
-			if (convo_options & OPT_CONVO_CHECK_SPELLING)
+/*			if (convo_options & OPT_CONVO_CHECK_SPELLING)
 				gtkspell_attach(GTK_TEXT(c->entry));
 			else
-				gtkspell_detach(GTK_TEXT(c->entry));
+				gtkspell_detach(GTK_TEXT(c->entry));*/
 			cht = cht->next;
 		}
 		con = con->next;
--- a/src/convo.h	Tue Oct 22 23:31:49 2002 +0000
+++ b/src/convo.h	Wed Oct 23 00:12:49 2002 +0000
@@ -56,21 +56,22 @@
 /* now both */
 extern int set_dispstyle (int);
 extern void info_callback(GtkWidget *, struct conversation *);
-extern void do_bold(GtkWidget *, GtkWidget *);
-extern void do_italic(GtkWidget *, GtkWidget *);
-extern void do_underline(GtkWidget *, GtkWidget *);
-extern void do_strike(GtkWidget *, GtkWidget *);
-extern void do_small(GtkWidget *, GtkWidget *);
-extern void do_normal(GtkWidget *, GtkWidget *);
-extern void do_big(GtkWidget *, GtkWidget *);
+extern void do_bold(GtkWidget *, struct conversation *);
+extern void do_italic(GtkWidget *, struct conversation *);
+extern void do_underline(GtkWidget *, struct conversation *);
+extern void do_strike(GtkWidget *, struct conversation *);
+extern void do_small(GtkWidget *, struct conversation *);
+extern void do_normal(GtkWidget *, struct conversation *);
+extern void do_big(GtkWidget *, struct conversation *);
 extern void toggle_font(GtkWidget *, struct conversation *);
 extern void toggle_color(GtkWidget *, struct conversation *);
 extern void toggle_loggle(GtkWidget *, struct conversation *);
 extern void insert_smiley(GtkWidget *, struct conversation *);
 /* sound is handled by set_option */
 extern gboolean keypress_callback(GtkWidget *, GdkEventKey *, struct conversation *);
+extern gboolean stop_rclick_callback(GtkWidget *, GdkEventButton *, gpointer);
 extern void check_spelling( GtkEditable *, gchar *, gint, gint *, gpointer);
-extern int entry_key_pressed(GtkWidget *, GtkWidget *);
+extern int entry_key_pressed(GtkTextBuffer *);
 
 extern void convo_switch(GtkNotebook *, GtkWidget *, gint, gpointer);
 extern gint delete_all_convo(GtkWidget *, GdkEventAny *, gpointer);
--- a/src/dialogs.c	Tue Oct 22 23:31:49 2002 +0000
+++ b/src/dialogs.c	Wed Oct 23 00:12:49 2002 +0000
@@ -2844,7 +2844,7 @@
 	showtext = gtk_entry_get_text(GTK_ENTRY(b->text));
 
 	g_snprintf(open_tag, 2048, "<A HREF=\"%s\">%s", urltext, showtext);
-	surround(b->entry, open_tag, "</A>");
+/* FIXME	surround(b, open_tag, "</A>");*/
 
 	g_free(open_tag);
 	destroy_dialog(NULL, b->window);
@@ -2927,7 +2927,7 @@
 		gtk_window_set_focus(GTK_WINDOW(c->link_dialog), b->url);
 		b->window = c->link_dialog;
 		b->toggle = linky;
-		b->entry = c->entry;
+/* FIXME		b->entry_view = c->entry_view;*/
 		gtk_widget_realize(c->link_dialog);
 
 	}
@@ -2989,7 +2989,7 @@
 	c->hasfg = 1;
 	g_snprintf(open_tag, 23, "<FONT COLOR=\"#%02X%02X%02X\">", text_color.red, text_color.green,
 		   text_color.blue);
-	surround(c->entry, open_tag, "</FONT>");
+	surround(c, open_tag, "</FONT>");
 	debug_printf("#%02X%02X%02X\n", text_color.red, text_color.green, text_color.blue);
 	g_free(open_tag);
 	cancel_fgcolor(NULL, c);
@@ -3016,7 +3016,7 @@
 	c->hasbg = 1;
 	g_snprintf(open_tag, 25, "<BODY BGCOLOR=\"#%02X%02X%02X\">", text_color.red, text_color.green,
 		   text_color.blue);
-	surround(c->entry, open_tag, "</BODY>");
+	surround(c, open_tag, "</BODY>");
 	debug_printf("#%02X%02X%02X\n", text_color.red, text_color.green, text_color.blue);
 	g_free(open_tag);
 	cancel_bgcolor(NULL, c);
@@ -3562,26 +3562,9 @@
 
 void insert_smiley_text(GtkWidget *widget, struct conversation *c)
 {
-	char *smiley_text;
-
-	smiley_text = strdup(current_smiley);
-
-	/* surround(c->entry, smiley_text, ""); */
-
-	if (GTK_OLD_EDITABLE(c->entry)->has_selection) {
-		int finish = GTK_OLD_EDITABLE(c->entry)->selection_end_pos;
-		gtk_editable_insert_text(GTK_EDITABLE(c->entry),
-					 smiley_text, strlen(smiley_text), &finish);
-	} else {
-		int pos = GTK_OLD_EDITABLE(c->entry)->current_pos;
-		gtk_editable_insert_text(GTK_EDITABLE(c->entry), smiley_text, strlen(smiley_text), &pos);
-	}
-
-	g_free(smiley_text);
-
+	gtk_text_buffer_insert_at_cursor(c->entry_buffer,
+					 current_smiley, -1);
 	close_smiley_dialog(NULL, c);
-
-	return;
 }
 
 static void toolbar_add_smiley(struct conversation *c, GtkWidget *bar, char **xpm, GtkWidget *win,
--- a/src/ui.h	Tue Oct 22 23:31:49 2002 +0000
+++ b/src/ui.h	Wed Oct 23 00:12:49 2002 +0000
@@ -102,7 +102,7 @@
 	char name[80];
 	GtkWidget *toolbar;
 	GtkWidget *text;
-	GtkWidget *entry;
+//	GtkWidget *entry;
 	GtkWidget *italic;
 	GtkWidget *bold;
 	GtkWidget *underline;
@@ -181,6 +181,9 @@
 	guint32 icon_timer;
 	GdkPixbufAnimationIter *iter;
 	GtkWidget *save_icon;
+
+	GtkTextBuffer *entry_buffer;
+	GtkWidget     *entry;
 };
 
 struct log_conversation {
@@ -383,23 +386,23 @@
 void set_convo_name(struct conversation *c, const char *nname);
 extern struct conversation *new_conversation(char *);
 extern void delete_conversation(struct conversation *);
-extern void surround(GtkWidget *, char *, char *);
+extern void surround(struct conversation *, char *, char *);
 extern int is_logging(char *);
 extern void set_state_lock(int);
 extern void rm_log(struct log_conversation *);
 extern struct log_conversation *find_log_info(char *);
-extern void remove_tags(GtkWidget *, char *);
+extern void remove_tags(struct conversation *, char *);
 extern void update_log_convs();
 extern void update_transparency();
 extern void update_font_buttons();
 extern void toggle_sensitive(GtkWidget *widget, GtkWidget *to_toggle);
-extern void do_bold(GtkWidget *, GtkWidget *);
-extern void do_italic(GtkWidget *, GtkWidget *);
-extern void do_underline(GtkWidget *, GtkWidget *);
-extern void do_strike(GtkWidget *, GtkWidget *);
-extern void do_small(GtkWidget *, GtkWidget *);
-extern void do_normal(GtkWidget *, GtkWidget *);
-extern void do_big(GtkWidget *, GtkWidget *);
+extern void do_bold(GtkWidget *, struct conversation *);
+extern void do_italic(GtkWidget *, struct conversation *);
+extern void do_underline(GtkWidget *, struct conversation *);
+extern void do_strike(GtkWidget *, struct conversation *);
+extern void do_small(GtkWidget *, struct conversation *);
+extern void do_normal(GtkWidget *, struct conversation *);
+extern void do_big(GtkWidget *, struct conversation *);
 extern void set_font_face(char *, struct conversation *);
 extern void redo_convo_menus();
 extern void convo_menu_remove(struct gaim_connection *);
--- a/src/util.c	Tue Oct 22 23:31:49 2002 +0000
+++ b/src/util.c	Wed Oct 23 00:12:49 2002 +0000
@@ -1304,8 +1304,7 @@
 		g_free(who);
 		if (what) {
 			int finish;
-			gtk_editable_insert_text(GTK_EDITABLE(c->entry),
-					 what, strlen(what), &finish);
+			gtk_text_buffer_insert_at_cursor(c->entry_buffer, what, -1);
 			g_free(what);
 		}
 	} else if (!g_strncasecmp(uri, "aim:addbuddy?", strlen("aim:addbuddy?"))) {