changeset 32059:fe75cd926073

Webkit Message views. This commit is a squashed commit of the series of commits from my git repository which I was using for development. (git://github.com/tdrhq/pidgin-clone.git, branch webkit)
author tdrhq@soc.pidgin.im
date Fri, 24 Jul 2009 01:18:07 +0000
parents ed3184cc557d
children 67143ecbddb1
files configure.ac pidgin/Makefile.am pidgin/gtkconv.c pidgin/gtkconv.h pidgin/gtkdialogs.c pidgin/gtklog.c pidgin/gtklog.h pidgin/gtknotify.c pidgin/gtkthemes.c pidgin/gtkthemes.h pidgin/plugins/Makefile.am
diffstat 11 files changed, 172 insertions(+), 565 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Thu Jul 23 04:05:31 2009 +0000
+++ b/configure.ac	Fri Jul 24 01:18:07 2009 +0000
@@ -700,6 +700,8 @@
 
 #AC_CHECK_FUNC(wcwidth, [AC_DEFINE([HAVE_WCWIDTH], [1], [Define to 1 if you have wcwidth function.])])
 
+PKG_CHECK_MODULES(WEBKIT, [webkit-1.0 >= 1.1.1]);
+
 dnl #######################################################################
 dnl # Check for LibXML2 (required)
 dnl #######################################################################
@@ -2476,6 +2478,7 @@
 		   pidgin/pixmaps/emotes/none/Makefile
 		   pidgin/pixmaps/emotes/small/16/Makefile
 		   pidgin/plugins/Makefile
+		   pidgin/plugins/adiumthemes/Makefile
 		   pidgin/plugins/cap/Makefile
 		   pidgin/plugins/disco/Makefile
 		   pidgin/plugins/gestures/Makefile
--- a/pidgin/Makefile.am	Thu Jul 23 04:05:31 2009 +0000
+++ b/pidgin/Makefile.am	Fri Jul 24 01:18:07 2009 +0000
@@ -125,9 +125,11 @@
 	gtkstatusbox.c \
 	gtkthemes.c \
 	gtkutils.c \
+	gtkwebview.c \
 	gtkwhiteboard.c \
 	minidialog.c \
-	pidgintooltip.c
+	pidgintooltip.c \
+	smileyparser.c
 
 pidgin_headers = \
 	eggtrayicon.h \
@@ -183,10 +185,12 @@
 	pidginstock.h \
 	gtkthemes.h \
 	gtkutils.h \
+	gtkwebview.h \
 	gtkwhiteboard.h \
 	minidialog.h \
 	pidgintooltip.h \
-	pidgin.h
+	pidgin.h \
+	smileyparser.h
 
 pidginincludedir=$(includedir)/pidgin
 pidgininclude_HEADERS = \
@@ -206,6 +210,7 @@
 	$(GTKSPELL_LIBS) \
 	$(STARTUP_NOTIFICATION_LIBS) \
 	$(LIBXML_LIBS) \
+	$(WEBKIT_LIBS) \
 	$(GTK_LIBS) \
 	$(top_builddir)/libpurple/libpurple.la
 
@@ -231,5 +236,6 @@
 	$(GTKSPELL_CFLAGS) \
 	$(STARTUP_NOTIFICATION_CFLAGS) \
 	$(LIBXML_CFLAGS) \
+	$(WEBKIT_CFLAGS) \
 	$(INTGG_CFLAGS)
 endif  # ENABLE_GTK
--- a/pidgin/gtkconv.c	Thu Jul 23 04:05:31 2009 +0000
+++ b/pidgin/gtkconv.c	Fri Jul 24 01:18:07 2009 +0000
@@ -69,6 +69,7 @@
 #include "gtkprivacy.h"
 #include "gtkthemes.h"
 #include "gtkutils.h"
+#include "gtkwebview.h"
 #include "pidginstock.h"
 #include "pidgintooltip.h"
 
@@ -164,7 +165,6 @@
 gboolean pidgin_conv_has_focus(PurpleConversation *conv);
 static GdkColor* generate_nick_colors(guint *numcolors, GdkColor background);
 static gboolean color_is_visible(GdkColor foreground, GdkColor background, int color_contrast, int brightness_contrast);
-static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag, gboolean create);
 static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields);
 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win);
 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv);
@@ -178,7 +178,7 @@
 static const GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name)
 {
 	static GdkColor col;
-	GtkStyle *style = gtk_widget_get_style(gtkconv->imhtml);
+	GtkStyle *style = gtk_widget_get_style(gtkconv->webview);
 	float scale;
 
 	col = nick_colors[g_str_hash(name) % nbr_nick_colors];
@@ -353,7 +353,7 @@
 
 	gtkconv = PIDGIN_CONVERSATION(conv);
 
-	gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
+	webkit_web_view_load_html_string (WEBKIT_WEB_VIEW (gtkconv->webview), "", "");
 	for (iter = gtkconv->convs; iter; iter = iter->next)
 		purple_conversation_clear_message_history(iter->data);
 }
@@ -961,32 +961,7 @@
 static void
 savelog_writefile_cb(void *user_data, const char *filename)
 {
-	PurpleConversation *conv = (PurpleConversation *)user_data;
-	FILE *fp;
-	const char *name;
-	char **lines;
-	gchar *text;
-
-	if ((fp = g_fopen(filename, "w+")) == NULL) {
-		purple_notify_error(PIDGIN_CONVERSATION(conv), NULL, _("Unable to open file."), NULL);
-		return;
-	}
-
-	name = purple_conversation_get_name(conv);
-	fprintf(fp, "<html>\n<head>\n");
-	fprintf(fp, "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
-	fprintf(fp, "<title>%s</title>\n</head>\n<body>\n", name);
-	fprintf(fp, _("<h1>Conversation with %s</h1>\n"), name);
-
-	lines = gtk_imhtml_get_markup_lines(
-		GTK_IMHTML(PIDGIN_CONVERSATION(conv)->imhtml));
-	text = g_strjoinv("<br>\n", lines);
-	fprintf(fp, "%s", text);
-	g_free(text);
-	g_strfreev(lines);
-
-	fprintf(fp, "\n</body>\n</html>\n");
-	fclose(fp);
+	/* TODO: I don't know how to support this using webkit yet. */
 }
 
 /*
@@ -1116,12 +1091,16 @@
 
 				if (gtkconv != gtk_active_conv)
 				{
-					gtk_imhtml_search_clear(GTK_IMHTML(gtkconv->imhtml));
+					webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (gtkconv->webview));
 				}
 				else
 				{
-					gtk_imhtml_search_find(GTK_IMHTML(gtk_active_conv->imhtml),
-					                       gtk_entry_get_text(GTK_ENTRY(s->entry)));
+					webkit_web_view_mark_text_matches (WEBKIT_WEB_VIEW (gtkconv->webview), 
+									   gtk_entry_get_text (GTK_ENTRY(s->entry)), TRUE, 0);
+					webkit_web_view_set_highlight_text_matches (WEBKIT_WEB_VIEW (gtkconv->webview),
+										    true);
+					webkit_web_view_search_text (WEBKIT_WEB_VIEW (gtkconv->webview),
+								     gtk_entry_get_text (GTK_ENTRY(s->entry)), FALSE, TRUE, FALSE);
 				}
 			}
 			break;
@@ -1132,7 +1111,7 @@
 			for (iter = pidgin_conv_window_get_gtkconvs(s->gtkwin); iter; iter=iter->next)
 			{
 				PidginConversation *gconv = iter->data;
-				gtk_imhtml_search_clear(GTK_IMHTML(gconv->imhtml));
+				webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW(gconv->webview));
 			}
 
 			gtk_widget_destroy(s->gtkwin->dialogs.search);
@@ -1635,30 +1614,11 @@
 	gtk_widget_grab_focus(PIDGIN_CONVERSATION(conv)->entry);
 }
 
-static GtkTextMark *
-get_mark_for_user(PidginConversation *gtkconv, const char *who)
-{
-	GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml));
-	char *tmp = g_strconcat("user:", who, NULL);
-	GtkTextMark *mark = gtk_text_buffer_get_mark(buf, tmp);
-
-	g_free(tmp);
-	return mark;
-}
-
 static void
 menu_last_said_cb(GtkWidget *w, PidginConversation *gtkconv)
 {
-	GtkTextMark *mark;
-	const char *who;
-
-	who = g_object_get_data(G_OBJECT(w), "user_data");
-	mark = get_mark_for_user(gtkconv, who);
-
-	if (mark != NULL)
-		gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0);
-	else
-		g_return_if_reached();
+	/* I don't know what this is! */
+	return;
 }
 
 static GtkWidget *
@@ -1773,8 +1733,6 @@
 	button = pidgin_new_item_from_stock(menu, _("Last Said"), GTK_STOCK_INDEX,
 						G_CALLBACK(menu_last_said_cb), PIDGIN_CONVERSATION(conv), 0, 0, NULL);
 	g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
-	if (!get_mark_for_user(PIDGIN_CONVERSATION(conv), who))
-		gtk_widget_set_sensitive(button, FALSE);
 
 	if (buddy != NULL)
 	{
@@ -1864,10 +1822,10 @@
 		chat_do_im(gtkconv, who);
 	} else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) {
 		/* Move to user's anchor */
-		GtkTextMark *mark = get_mark_for_user(gtkconv, who);
-
-		if(mark != NULL)
-			gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0);
+		//GtkTextMark *mark = get_mark_for_user(gtkconv, who);
+
+		//if(mark != NULL)
+		//	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0);
 	} else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
 		GtkWidget *menu = create_chat_menu (conv, who, gc);
 		gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
@@ -1943,8 +1901,8 @@
 		GtkWidget *from;
 		GtkWidget *to;
 	} transitions[] = {
-		{gtkconv->entry, gtkconv->imhtml},
-		{gtkconv->imhtml, chat ? gtkconv->u.chat->list : gtkconv->entry},
+		{gtkconv->entry, gtkconv->webview},
+		{gtkconv->webview, chat ? gtkconv->u.chat->list : gtkconv->entry},
 		{chat ? gtkconv->u.chat->list : NULL, gtkconv->entry},
 		{NULL, NULL}
 	}, *ptr;
@@ -2200,12 +2158,12 @@
 			break;
 
 		case GDK_Page_Up:
-			gtk_imhtml_page_up(GTK_IMHTML(gtkconv->imhtml));
+			//gtk_imhtml_page_up(GTK_IMHTML(gtkconv->imhtml));
 			return TRUE;
 			break;
 
 		case GDK_Page_Down:
-			gtk_imhtml_page_down(GTK_IMHTML(gtkconv->imhtml));
+			//gtk_imhtml_page_down(GTK_IMHTML(gtkconv->imhtml));
 			return TRUE;
 			break;
 
@@ -2308,7 +2266,7 @@
 	entry = GTK_IMHTML(gtkconv->entry);
 	protocol_name = purple_account_get_protocol_name(conv->account);
 	gtk_imhtml_set_protocol_name(entry, protocol_name);
-	gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml), protocol_name);
+	//gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml), protocol_name);
 
 	if (!(conv->features & PURPLE_CONNECTION_HTML))
 		gtk_imhtml_clear_formatting(GTK_IMHTML(gtkconv->entry));
@@ -3250,11 +3208,11 @@
 	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
 		chat = purple_blist_find_chat(conv->account, conv->name);
 
-		if ((chat == NULL) && (gtkconv->imhtml != NULL)) {
-			chat = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_chat");
-		}
-
-		if ((chat == NULL) && (gtkconv->imhtml != NULL)) {
+		if ((chat == NULL) && (gtkconv->webview != NULL)) {
+			chat = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_chat");
+		}
+
+		if ((chat == NULL) && (gtkconv->webview != NULL)) {
 			GHashTable *components;
 			PurpleAccount *account = purple_conversation_get_account(conv);
 			PurplePlugin *prpl = purple_find_prpl(purple_account_get_protocol_id(account));
@@ -3272,7 +3230,7 @@
 			chat = purple_chat_new(conv->account, NULL, components);
 			purple_blist_node_set_flags((PurpleBlistNode *)chat,
 					PURPLE_BLIST_NODE_FLAG_NO_SAVE);
-			g_object_set_data_full(G_OBJECT(gtkconv->imhtml), "transient_chat",
+			g_object_set_data_full(G_OBJECT(gtkconv->webview), "transient_chat",
 					chat, (GDestroyNotify)purple_blist_remove_chat);
 		}
 	} else {
@@ -3284,15 +3242,15 @@
 		/* gotta remain bug-compatible :( libpurple < 2.0.2 didn't handle
 		 * removing "isolated" buddy nodes well */
 		if (purple_version_check(2, 0, 2) == NULL) {
-			if ((buddy == NULL) && (gtkconv->imhtml != NULL)) {
-				buddy = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_buddy");
+			if ((buddy == NULL) && (gtkconv->webview != NULL)) {
+				buddy = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_buddy");
 			}
 
-			if ((buddy == NULL) && (gtkconv->imhtml != NULL)) {
+			if ((buddy == NULL) && (gtkconv->webview != NULL)) {
 				buddy = purple_buddy_new(conv->account, conv->name, NULL);
 				purple_blist_node_set_flags((PurpleBlistNode *)buddy,
 						PURPLE_BLIST_NODE_FLAG_NO_SAVE);
-				g_object_set_data_full(G_OBJECT(gtkconv->imhtml), "transient_buddy",
+				g_object_set_data_full(G_OBJECT(gtkconv->webview), "transient_buddy",
 						buddy, (GDestroyNotify)purple_buddy_destroy);
 			}
 		}
@@ -3643,38 +3601,7 @@
 static void
 update_typing_message(PidginConversation *gtkconv, const char *message)
 {
-	GtkTextBuffer *buffer;
-	GtkTextMark *stmark, *enmark;
-
-	if (g_object_get_data(G_OBJECT(gtkconv->imhtml), "disable-typing-notification"))
-		return;
-
-	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml));
-	stmark = gtk_text_buffer_get_mark(buffer, "typing-notification-start");
-	enmark = gtk_text_buffer_get_mark(buffer, "typing-notification-end");
-	if (stmark && enmark) {
-		GtkTextIter start, end;
-		gtk_text_buffer_get_iter_at_mark(buffer, &start, stmark);
-		gtk_text_buffer_get_iter_at_mark(buffer, &end, enmark);
-		gtk_text_buffer_delete_mark(buffer, stmark);
-		gtk_text_buffer_delete_mark(buffer, enmark);
-		gtk_text_buffer_delete(buffer, &start, &end);
-	} else if (message && *message == '\n' && message[1] == ' ' && message[2] == '\0')
-		message = NULL;
-
-#ifdef RESERVE_LINE
-	if (!message)
-		message = "\n ";   /* The blank space is required to avoid a GTK+/Pango bug */
-#endif
-
-	if (message) {
-		GtkTextIter iter;
-		gtk_text_buffer_get_end_iter(buffer, &iter);
-		gtk_text_buffer_create_mark(buffer, "typing-notification-start", &iter, TRUE);
-		gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, message, -1, "TYPING-NOTIFICATION", NULL);
-		gtk_text_buffer_get_end_iter(buffer, &iter);
-		gtk_text_buffer_create_mark(buffer, "typing-notification-end", &iter, TRUE);
-	}
+	/* this is not handled at all */
 }
 
 static void
@@ -3991,7 +3918,6 @@
 	gboolean is_buddy;
 	gchar *tmp, *alias_key, *name, *alias;
 	int flags;
-	GdkColor *color = NULL;
 
 	alias = cb->alias;
 	name  = cb->name;
@@ -4018,20 +3944,6 @@
 	alias_key = g_utf8_collate_key(tmp, -1);
 	g_free(tmp);
 
-	if (is_me) {
-		GtkTextTag *tag = gtk_text_tag_table_lookup(
-				gtk_text_buffer_get_tag_table(GTK_IMHTML(gtkconv->imhtml)->text_buffer),
-				"send-name");
-		g_object_get(tag, "foreground-gdk", &color, NULL);
-	} else {
-		GtkTextTag *tag;
-		if ((tag = get_buddy_tag(conv, name, 0, FALSE)))
-			g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_NORMAL, NULL);
-		if ((tag = get_buddy_tag(conv, name, PURPLE_MESSAGE_NICK, FALSE)))
-			g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_NORMAL, NULL);
-		color = (GdkColor*)get_nick_color(gtkconv, name);
-	}
-
 #if GTK_CHECK_VERSION(2,6,0)
 	gtk_list_store_insert_with_values(ls, &iter,
 /*
@@ -4047,7 +3959,6 @@
 			CHAT_USERS_ALIAS_KEY_COLUMN, alias_key,
 			CHAT_USERS_NAME_COLUMN,  name,
 			CHAT_USERS_FLAGS_COLUMN, flags,
-			CHAT_USERS_COLOR_COLUMN, color,
 			CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
 			-1);
 #else
@@ -4058,13 +3969,10 @@
 			CHAT_USERS_ALIAS_KEY_COLUMN, alias_key,
 			CHAT_USERS_NAME_COLUMN,  name,
 			CHAT_USERS_FLAGS_COLUMN, flags,
-			CHAT_USERS_COLOR_COLUMN, color,
 			CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
 			-1);
 #endif
 
-	if (is_me && color)
-		gdk_color_free(color);
 	g_free(alias_key);
 }
 
@@ -4458,7 +4366,6 @@
 	GtkTreeModel *model;
 	char *normalized_name;
 	GtkTreeIter iter;
-	GtkTextTag *texttag;
 	int f;
 
 	g_return_if_fail(buddy != NULL);
@@ -4497,10 +4404,6 @@
 
 	blist_node_aliased_cb((PurpleBlistNode *)buddy, NULL, conv);
 
-	texttag = get_buddy_tag(conv, purple_buddy_get_name(buddy), 0, FALSE); /* XXX: do we want the normalized name? */
-	if (texttag) {
-		g_object_set(texttag, "weight", is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, NULL);
-	}
 }
 
 static void
@@ -4532,7 +4435,7 @@
 }
 
 static void
-entry_popup_menu_cb(GtkIMHtml *imhtml, GtkMenu *menu, gpointer data)
+entry_popup_menu_cb(GtkIMHtml *imhtml /* this is for ->entry, fine! */, GtkMenu *menu, gpointer data)
 {
 	GtkWidget *menuitem;
 	PidginConversation *gtkconv = data;
@@ -4560,7 +4463,7 @@
 	GdkRectangle oneline;
 	int height, diff;
 	int pad_top, pad_inside, pad_bottom;
-	int total_height = (gtkconv->imhtml->allocation.height + gtkconv->entry->allocation.height);
+	int total_height = (gtkconv->webview->allocation.height + gtkconv->entry->allocation.height);
 	int max_height = total_height / 2;
 	int min_lines = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/minimum_entry_lines");
 	int min_height;
@@ -4796,13 +4699,13 @@
 	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
 		node = (PurpleBlistNode*)(purple_blist_find_chat(conv->account, conv->name));
 		if (!node)
-			node = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_chat");
+			node = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_chat");
 	} else {
 		node = (PurpleBlistNode*)(purple_find_buddy(conv->account, conv->name));
 #if 0
 		/* Using the transient blist nodes to show the tooltip doesn't quite work yet. */
 		if (!node)
-			node = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_buddy");
+			node = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_buddy");
 #endif
 	}
 
@@ -4814,13 +4717,13 @@
 static GtkWidget *
 setup_common_pane(PidginConversation *gtkconv)
 {
-	GtkWidget *vbox, *frame, *imhtml_sw, *event_box;
+	GtkWidget *vbox, *frame, *webview_sw, *event_box;
 	GtkCellRenderer *rend;
 	GtkTreePath *path;
 	PurpleConversation *conv = gtkconv->active_conv;
 	PurpleBuddy *buddy;
 	gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT);
-	GtkPolicyType imhtml_sw_hscroll;
+	GtkPolicyType webview_sw_hscroll;
 	int buddyicon_size = 0;
 
 	/* Setup the top part of the pane */
@@ -4916,8 +4819,15 @@
 	g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL);
 
 	/* Setup the gtkimhtml widget */
-	frame = pidgin_create_imhtml(FALSE, &gtkconv->imhtml, NULL, &imhtml_sw);
-	gtk_widget_set_size_request(gtkconv->imhtml, -1, 0);
+	webview_sw = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(webview_sw), GTK_SHADOW_IN);
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (webview_sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+	gtkconv->webview = gtk_webview_new ();
+	gtk_container_add (GTK_CONTAINER (webview_sw), gtkconv->webview);
+	
+	gtk_widget_set_size_request(gtkconv->webview, -1, 0);
+
 	if (chat) {
 		GtkWidget *hpaned;
 
@@ -4928,29 +4838,28 @@
 		hpaned = gtk_hpaned_new();
 		gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0);
 		gtk_widget_show(hpaned);
-		gtk_paned_pack1(GTK_PANED(hpaned), frame, TRUE, TRUE);
+		gtk_paned_pack1(GTK_PANED(hpaned), webview_sw, TRUE, TRUE);
 
 		/* Now add the userlist */
 		setup_chat_userlist(gtkconv, hpaned);
 	} else {
-		gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
-	}
-	gtk_widget_show(frame);
-
-	gtk_widget_set_name(gtkconv->imhtml, "pidgin_conv_imhtml");
-	gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml),TRUE);
-	g_object_set_data(G_OBJECT(gtkconv->imhtml), "gtkconv", gtkconv);
-
-	gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(imhtml_sw),
-	                               &imhtml_sw_hscroll, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(imhtml_sw),
-	                               imhtml_sw_hscroll, GTK_POLICY_ALWAYS);
-
-	g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event",
+		gtk_box_pack_start(GTK_BOX(vbox), webview_sw, TRUE, TRUE, 0);
+	}
+	gtk_widget_show_all(webview_sw);
+
+	gtk_widget_set_name(gtkconv->webview, "pidgin_conv_webview");
+	g_object_set_data(G_OBJECT(gtkconv->webview), "gtkconv", gtkconv);
+
+	gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(webview_sw),
+	                               &webview_sw_hscroll, NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(webview_sw),
+	                               webview_sw_hscroll, GTK_POLICY_ALWAYS);
+
+	g_signal_connect_after(G_OBJECT(gtkconv->webview), "button_press_event",
 	                       G_CALLBACK(entry_stop_rclick_cb), NULL);
-	g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_press_event",
+	g_signal_connect(G_OBJECT(gtkconv->webview), "key_press_event",
 	                 G_CALLBACK(refocus_entry_cb), gtkconv);
-	g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_release_event",
+	g_signal_connect(G_OBJECT(gtkconv->webview), "key_release_event",
 	                 G_CALLBACK(refocus_entry_cb), gtkconv);
 
 	gtkconv->lower_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
@@ -5189,36 +5098,6 @@
 
 static void set_typing_font(GtkWidget *widget, GtkStyle *style, PidginConversation *gtkconv)
 {
-	static PangoFontDescription *font_desc = NULL;
-	static GdkColor *color = NULL;
-	static gboolean enable = TRUE;
-
-	if (font_desc == NULL) {
-		char *string = NULL;
-		gtk_widget_style_get(widget,
-				"typing-notification-font", &string,
-				"typing-notification-color", &color,
-				"typing-notification-enable", &enable,
-				NULL);
-		font_desc = pango_font_description_from_string(string);
-		g_free(string);
-		if (color == NULL) {
-			GdkColor def = {0, 0x8888, 0x8888, 0x8888};
-			color = gdk_color_copy(&def);
-		}
-	}
-
-	gtk_text_buffer_create_tag(GTK_IMHTML(widget)->text_buffer, "TYPING-NOTIFICATION",
-			"foreground-gdk", color,
-			"font-desc", font_desc,
-			NULL);
-
-	if (!enable) {
-		g_object_set_data(G_OBJECT(widget), "disable-typing-notification", GINT_TO_POINTER(TRUE));
-		/* or may be 'gtkconv->disable_typing = TRUE;' instead? */
-	}
-
-	g_signal_handlers_disconnect_by_func(G_OBJECT(widget), set_typing_font, gtkconv);
 }
 
 /**************************************************************************
@@ -5260,9 +5139,6 @@
 	}
 	pane = setup_common_pane(gtkconv);
 
-	gtk_imhtml_set_format_functions(GTK_IMHTML(gtkconv->imhtml),
-			gtk_imhtml_get_format_functions(GTK_IMHTML(gtkconv->imhtml)) | GTK_IMHTML_IMAGE);
-
 	if (pane == NULL) {
 		if (conv_type == PURPLE_CONV_TYPE_CHAT)
 			g_free(gtkconv->u.chat);
@@ -5285,7 +5161,7 @@
 	                  GTK_DEST_DEFAULT_DROP,
 	                  te, sizeof(te) / sizeof(GtkTargetEntry),
 	                  GDK_ACTION_COPY);
-	gtk_drag_dest_set(gtkconv->imhtml, 0,
+	gtk_drag_dest_set(gtkconv->webview, 0,
 	                  te, sizeof(te) / sizeof(GtkTargetEntry),
 	                  GDK_ACTION_COPY);
 
@@ -5297,12 +5173,12 @@
 	                 G_CALLBACK(ignore_middle_click), NULL);
 	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_signal_connect(G_OBJECT(gtkconv->webview), "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);
 
-	g_signal_connect(gtkconv->imhtml, "style-set", G_CALLBACK(set_typing_font), gtkconv);
+	g_signal_connect(gtkconv->webview, "style-set", G_CALLBACK(set_typing_font), gtkconv);
 
 	/* Setup the container for the tab. */
 	gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
@@ -5332,10 +5208,6 @@
 	else
 		gtk_widget_hide(gtkconv->infopane_hbox);
 
-	gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml),
-		purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_timestamps"));
-	gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml),
-								 purple_account_get_protocol_name(conv->account));
 
 	g_signal_connect_swapped(G_OBJECT(pane), "focus",
 	                         G_CALLBACK(gtk_widget_grab_focus),
@@ -5348,7 +5220,7 @@
 
 	if (nick_colors == NULL) {
 		nbr_nick_colors = NUM_NICK_COLORS;
-		nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->imhtml)->base[GTK_STATE_NORMAL]);
+		nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->webview)->base[GTK_STATE_NORMAL]);
 	}
 
 	if (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY)
@@ -5547,43 +5419,6 @@
 	return FALSE;
 }
 
-static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag,
-		gboolean create)
-{
-	PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
-	GtkTextTag *buddytag;
-	gchar *str;
-	gboolean highlight = (flag & PURPLE_MESSAGE_NICK);
-	GtkTextBuffer *buffer = GTK_IMHTML(gtkconv->imhtml)->text_buffer;
-
-	str = g_strdup_printf(highlight ? "HILIT %s" : "BUDDY %s", who);
-
-	buddytag = gtk_text_tag_table_lookup(
-			gtk_text_buffer_get_tag_table(buffer), str);
-
-	if (buddytag == NULL && create) {
-		if (highlight)
-			buddytag = gtk_text_buffer_create_tag(buffer, str,
-					"foreground", get_text_tag_color(gtk_text_tag_table_lookup(
-							gtk_text_buffer_get_tag_table(buffer), "highlight-name")),
-					"weight", PANGO_WEIGHT_BOLD,
-					NULL);
-		else
-			buddytag = gtk_text_buffer_create_tag(
-					buffer, str,
-					"foreground-gdk", get_nick_color(gtkconv, who),
-					"weight", purple_find_buddy(purple_conversation_get_account(conv), who) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
-					NULL);
-
-		g_signal_connect(G_OBJECT(buddytag), "event",
-				G_CALLBACK(buddytag_event), conv);
-	}
-
-	g_free(str);
-
-	return buddytag;
-}
-
 static void pidgin_conv_calculate_newday(PidginConversation *gtkconv, time_t mtime)
 {
 	struct tm *tm = localtime(&mtime);
@@ -5640,10 +5475,6 @@
 	PurpleConnection *gc;
 	PurpleAccount *account;
 	PurplePluginProtocolInfo *prpl_info;
-	int gtk_font_options = 0;
-	int gtk_font_options_all = 0;
-	int max_scrollback_lines;
-	int line_count;
 	char buf2[BUF_LONG];
 	gboolean show_date;
 	char *mdate;
@@ -5654,8 +5485,6 @@
 	PurpleConversationType type;
 	char *displaying;
 	gboolean plugin_return;
-	char *bracket;
-	int tag_count = 0;
 	gboolean is_rtl_message = FALSE;
 
 	g_return_if_fail(conv != NULL);
@@ -5713,59 +5542,13 @@
 	}
 	length = strlen(displaying) + 1;
 
-	/* Awful hack to work around GtkIMHtml's inefficient rendering of messages with lots of formatting changes.
-	 * If a message has over 100 '<' characters, strip formatting before appending it. Hopefully nobody actually
-	 * needs that much formatting, anyway.
-	 */
-	for (bracket = strchr(displaying, '<'); bracket && *(bracket + 1); bracket = strchr(bracket + 1, '<'))
-		tag_count++;
-
-	if (tag_count > 100) {
-		char *tmp = displaying;
-		displaying = purple_markup_strip_html(tmp);
-		g_free(tmp);
-	}
 
 	win = gtkconv->win;
 	prpl_info = gc ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL;
 
-	line_count = gtk_text_buffer_get_line_count(
-			gtk_text_view_get_buffer(GTK_TEXT_VIEW(
-				gtkconv->imhtml)));
-
-	max_scrollback_lines = purple_prefs_get_int(
-		PIDGIN_PREFS_ROOT "/conversations/scrollback_lines");
-	/* If we're sitting at more than 100 lines more than the
-	   max scrollback, trim down to max scrollback */
-	if (max_scrollback_lines > 0
-			&& line_count > (max_scrollback_lines + 100)) {
-		GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(
-			GTK_TEXT_VIEW(gtkconv->imhtml));
-		GtkTextIter start, end;
-
-		gtk_text_buffer_get_start_iter(text_buffer, &start);
-		gtk_text_buffer_get_iter_at_line(text_buffer, &end,
-			(line_count - max_scrollback_lines));
-		gtk_imhtml_delete(GTK_IMHTML(gtkconv->imhtml), &start, &end);
-	}
-
-	if (type == PURPLE_CONV_TYPE_CHAT)
-	{
-		/* Create anchor for user */
-		GtkTextIter iter;
-		char *tmp = g_strconcat("user:", name, NULL);
-
-		gtk_text_buffer_get_end_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)), &iter);
-		gtk_text_buffer_create_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)),
-								tmp, &iter, TRUE);
-		g_free(tmp);
-	}
-
-	if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_smooth_scrolling"))
-		gtk_font_options_all |= GTK_IMHTML_USE_SMOOTHSCROLLING;
-
-	if (gtk_text_buffer_get_char_count(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml))))
-		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR>", gtk_font_options_all | GTK_IMHTML_NO_SCROLL);
+	/* if the buffer is not empty add a <br> */
+	if (!gtk_webview_is_empty (GTK_WEBVIEW(gtkconv->webview)))
+		gtk_webview_append_html (GTK_WEBVIEW(gtkconv->webview), "<br />");
 
 	/* First message in a conversation. */
 	if (gtkconv->newday == 0)
@@ -5801,47 +5584,29 @@
 
 	sml_attrib = g_strdup_printf("sml=\"%s\"", purple_account_get_protocol_name(account));
 
-	gtk_font_options |= GTK_IMHTML_NO_COMMENTS;
-
-	if ((flags & PURPLE_MESSAGE_RECV) &&
-			!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting"))
-		gtk_font_options |= GTK_IMHTML_NO_COLOURS | GTK_IMHTML_NO_FONTS | GTK_IMHTML_NO_SIZES | GTK_IMHTML_NO_FORMATTING;
-
-	/* this is gonna crash one day, I can feel it. */
-	if (PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(conv->account)))->options &
-	    OPT_PROTO_USE_POINTSIZE) {
-		gtk_font_options |= GTK_IMHTML_USE_POINTSIZE;
-	}
-
-	if (!(flags & PURPLE_MESSAGE_RECV) && (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY))
-	{
-		/* We want to see our own smileys. Need to revert it after send*/
-		pidgin_themes_smiley_themeize_custom(gtkconv->imhtml);
-	}
-
 	/* TODO: These colors should not be hardcoded so log.c can use them */
 	if (flags & PURPLE_MESSAGE_RAW) {
-		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), message, gtk_font_options_all);
+		gtk_webview_append_html (GTK_WEBVIEW(gtkconv->webview), message);
 	} else if (flags & PURPLE_MESSAGE_SYSTEM) {
 		g_snprintf(buf2, sizeof(buf2),
-			   "<FONT %s><FONT SIZE=\"2\"><!--%s --></FONT><B>%s</B></FONT>",
+			   "<font %s><font size=\"2\"><span class='timestamp'>%s</span></font><b>%s</b></font>",
 			   sml_attrib ? sml_attrib : "", mdate, displaying);
 
-		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all);
+		gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2);
 
 	} else if (flags & PURPLE_MESSAGE_ERROR) {
 		g_snprintf(buf2, sizeof(buf2),
-			   "<FONT COLOR=\"#ff0000\"><FONT %s><FONT SIZE=\"2\"><!--%s --></FONT><B>%s</B></FONT></FONT>",
+			   "<font color=\"#ff0000\"><font %s><font size=\"2\"><span class='timestamp'>%s</span> </font><b>%s</b></font></font>",
 			   sml_attrib ? sml_attrib : "", mdate, displaying);
 
-		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all);
+		gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2);
 
 	} else if (flags & PURPLE_MESSAGE_NO_LOG) {
 		g_snprintf(buf2, BUF_LONG,
-			   "<B><FONT %s COLOR=\"#777777\">%s</FONT></B>",
+			   "<b><font %s color=\"#777777\">%s</font></b>",
 			   sml_attrib ? sml_attrib : "", displaying);
 
-		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all);
+		gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2);
 	} else {
 		char *new_message = g_memdup(displaying, length);
 		char *alias_escaped = (alias ? g_markup_escape_text(alias, strlen(alias)) : g_strdup(""));
@@ -5851,11 +5616,6 @@
 		int tag_end_offset = 0;
 		const char *tagname = NULL;
 
-		GtkTextIter start, end;
-		GtkTextMark *mark;
-		GtkTextTag *tag;
-		GtkTextBuffer *buffer = GTK_IMHTML(gtkconv->imhtml)->text_buffer;
-
 		/* Enforce direction on alias */
 		if (is_rtl_message)
 			str_embed_direction_chars(&alias_escaped);
@@ -5916,55 +5676,27 @@
 
 		g_free(alias_escaped);
 
-		if (tagname)
-			tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), tagname);
-		else
-			tag = get_buddy_tag(conv, name, flags, TRUE);
-
-		if (GTK_IMHTML(gtkconv->imhtml)->show_comments) {
-			/* The color for the timestamp has to be set in the font-tags, unfortunately.
-			 * Applying the nick-tag to timestamps would work, but that can make it
-			 * bold. I thought applying the "comment" tag again, which has "weight" set
-			 * to PANGO_WEIGHT_NORMAL, would remove the boldness. But it doesn't. So
-			 * this will have to do. I don't terribly like it.  -- sadrul */
-			const char *color = get_text_tag_color(tag);
-			g_snprintf(buf2, BUF_LONG, "<FONT %s%s%s SIZE=\"2\"><!--%s --></FONT>",
-					color ? "COLOR=\"" : "", color ? color : "", color ? "\"" : "", mdate);
-			gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL);
-		}
-
-		gtk_text_buffer_get_end_iter(buffer, &end);
-		mark = gtk_text_buffer_create_mark(buffer, NULL, &end, TRUE);
-
-		g_snprintf(buf2, BUF_LONG, "<FONT %s>%s</FONT> ", sml_attrib ? sml_attrib : "", str);
-		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL);
-
-		gtk_text_buffer_get_end_iter(buffer, &end);
-		gtk_text_buffer_get_iter_at_mark(buffer, &start, mark);
-		gtk_text_buffer_apply_tag(buffer, tag, &start, &end);
-		gtk_text_buffer_delete_mark(buffer, mark);
+		/* timestamp */ 
+		{
+			g_snprintf (buf2, BUF_LONG, "<font size='2'>%s </font>", mdate);
+
+			gtk_webview_append_html (GTK_WEBVIEW(gtkconv->webview), buf2);
+		}
+		g_snprintf(buf2, BUF_LONG, "<font %s>%s</font> ", sml_attrib ? sml_attrib : "", str);
+		gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2);
 
 		g_free(str);
 
 		if(gc){
 			char *pre = g_strdup_printf("<font %s>", sml_attrib ? sml_attrib : "");
 			char *post = "</font>";
-			int pre_len = strlen(pre);
-			int post_len = strlen(post);
-
-			with_font_tag = g_malloc(length + pre_len + post_len + 1);
-
-			strcpy(with_font_tag, pre);
-			memcpy(with_font_tag + pre_len, new_message, length);
-			strcpy(with_font_tag + pre_len + length, post);
-
-			length += pre_len + post_len;
+			with_font_tag = g_strdup_printf ("%s%s%s", pre, new_message, post);
 			g_free(pre);
 		} else
 			with_font_tag = g_memdup(new_message, length);
 
-		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml),
-							 with_font_tag, gtk_font_options | gtk_font_options_all);
+		gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview),
+							 with_font_tag);
 
 		g_free(with_font_tag);
 		g_free(new_message);
@@ -5991,12 +5723,6 @@
 		gtkconv_set_unseen(gtkconv, unseen);
 	}
 
-	if (!(flags & PURPLE_MESSAGE_RECV) && (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY))
-	{
-		/* Restore the smiley-data */
-		pidgin_themes_smiley_themeize(gtkconv->imhtml);
-	}
-
 	purple_signal_emit(pidgin_conversations_get_handle(),
 		(type == PURPLE_CONV_TYPE_IM ? "displayed-im-msg" : "displayed-chat-msg"),
 		account, name, displaying, conv, flags);
@@ -6088,10 +5814,6 @@
 		g_free(val);
 	}
 
-	if ((tag = get_buddy_tag(conv, old_name, 0, FALSE)))
-		g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL);
-	if ((tag = get_buddy_tag(conv, old_name, PURPLE_MESSAGE_NICK, FALSE)))
-		g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL);
 
 	if (!purple_conv_chat_find_user(chat, old_name))
 		return;
@@ -6149,10 +5871,7 @@
 			g_free(val);
 		} while (f);
 
-		if ((tag = get_buddy_tag(conv, l->data, 0, FALSE)))
-			g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL);
-		if ((tag = get_buddy_tag(conv, l->data, PURPLE_MESSAGE_NICK, FALSE)))
-			g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL);
+
 	}
 
 	g_snprintf(tmp, sizeof(tmp),
@@ -6256,99 +5975,17 @@
 	return TRUE;
 }
 
-static gboolean
-pidgin_conv_custom_smiley_add(PurpleConversation *conv, const char *smile, gboolean remote)
-{
-	PidginConversation *gtkconv;
-	struct smiley_list *list;
-	const char *sml = NULL, *conv_sml;
-
-	if (!conv || !smile || !*smile) {
-		return FALSE;
-	}
-
-	/* If smileys are off, return false */
-	if (pidgin_themes_smileys_disabled())
-		return FALSE;
-
-	/* If possible add this smiley to the current theme.
-	 * The addition is only temporary: custom smilies aren't saved to disk. */
-	conv_sml = purple_account_get_protocol_name(conv->account);
-	gtkconv = PIDGIN_CONVERSATION(conv);
-
-	for (list = (struct smiley_list *)current_smiley_theme->list; list; list = list->next) {
-		if (!strcmp(list->sml, conv_sml)) {
-			sml = list->sml;
-			break;
-		}
-	}
-
-	if (!add_custom_smiley_for_imhtml(GTK_IMHTML(gtkconv->imhtml), sml, smile))
-		return FALSE;
-
-	if (!remote)	/* If it's a local custom smiley, then add it for the entry */
-		if (!add_custom_smiley_for_imhtml(GTK_IMHTML(gtkconv->entry), sml, smile))
-			return FALSE;
-
-	return TRUE;
-}
-
 static void
 pidgin_conv_custom_smiley_write(PurpleConversation *conv, const char *smile,
                                       const guchar *data, gsize size)
 {
-	PidginConversation *gtkconv;
-	GtkIMHtmlSmiley *smiley;
-	GdkPixbufLoader *loader;
-	const char *sml;
-
-	sml = purple_account_get_protocol_name(conv->account);
-	gtkconv = PIDGIN_CONVERSATION(conv);
-	smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile);
-
-	if (!smiley)
-		return;
-
-	smiley->data = g_realloc(smiley->data, smiley->datasize + size);
-	g_memmove((guchar *)smiley->data + smiley->datasize, data, size);
-	smiley->datasize += size;
-
-	loader = smiley->loader;
-	if (!loader)
-		return;
-
-	gdk_pixbuf_loader_write(loader, data, size, NULL);
+	return;
 }
 
 static void
 pidgin_conv_custom_smiley_close(PurpleConversation *conv, const char *smile)
 {
-	PidginConversation *gtkconv;
-	GtkIMHtmlSmiley *smiley;
-	GdkPixbufLoader *loader;
-	const char *sml;
-
-	g_return_if_fail(conv  != NULL);
-	g_return_if_fail(smile != NULL);
-
-	sml = purple_account_get_protocol_name(conv->account);
-	gtkconv = PIDGIN_CONVERSATION(conv);
-	smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile);
-
-	if (!smiley)
-		return;
-
-	loader = smiley->loader;
-
-	if (!loader)
-		return;
-
-
-
-	purple_debug_info("gtkconv", "About to close the smiley pixbuf\n");
-
-	gdk_pixbuf_loader_close(loader, NULL);
-
+	return;
 }
 
 static void
@@ -6646,8 +6283,6 @@
 		}
 	}
 
-	if (fields & PIDGIN_CONV_SMILEY_THEME)
-		pidgin_themes_smiley_themeize(PIDGIN_CONVERSATION(conv)->imhtml);
 
 	if ((fields & PIDGIN_CONV_COLORIZE_TITLE) ||
 			(fields & PIDGIN_CONV_SET_TITLE) ||
@@ -6872,7 +6507,7 @@
 	pidgin_conv_chat_update_user,     /* chat_update_user     */
 	pidgin_conv_present_conversation, /* present              */
 	pidgin_conv_has_focus,            /* has_focus            */
-	pidgin_conv_custom_smiley_add,    /* custom_smiley_add    */
+	NULL,    /* custom_smiley_add    */
 	pidgin_conv_custom_smiley_write,  /* custom_smiley_write  */
 	pidgin_conv_custom_smiley_close,  /* custom_smiley_close  */
 	pidgin_conv_send_confirm,         /* send_confirm         */
@@ -7278,8 +6913,6 @@
 		        GTK_CHECK_MENU_ITEM(win->menu.show_timestamps),
 		        (gboolean)GPOINTER_TO_INT(value));
 
-		gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml),
-			(gboolean)GPOINTER_TO_INT(value));
 	}
 }
 
@@ -7674,7 +7307,7 @@
 	while (gtkconv->attach.current && count < 100) {  /* XXX: 100 is a random value here */
 		PurpleConvMessage *msg = gtkconv->attach.current->data;
 		if (!im && when && when < msg->when) {
-			gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0);
+			gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), "<BR><HR>");
 			g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
 		}
 		pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when);
@@ -7709,7 +7342,7 @@
 			PurpleConvMessage *msg = msgs->data;
 			pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when);
 		}
-		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0);
+		gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), "<BR><HR>");
 		g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
 	}
 
--- a/pidgin/gtkconv.h	Thu Jul 23 04:05:31 2009 +0000
+++ b/pidgin/gtkconv.h	Fri Jul 24 01:18:07 2009 +0000
@@ -128,7 +128,7 @@
 	GtkWidget *tabby;
 	GtkWidget *menu_tabby;
 
-	GtkWidget *imhtml;
+	GtkWidget *webview;
 	GtkTextBuffer *entry_buffer;
 	GtkWidget *entry;
 	gboolean auto_resize;   /* this is set to TRUE if the conversation
--- a/pidgin/gtkdialogs.c	Thu Jul 23 04:05:31 2009 +0000
+++ b/pidgin/gtkdialogs.c	Fri Jul 24 01:18:07 2009 +0000
@@ -37,12 +37,13 @@
 
 #include "gtkblist.h"
 #include "gtkdialogs.h"
-#include "gtkimhtml.h"
-#include "gtkimhtmltoolbar.h"
 #include "gtklog.h"
 #include "gtkutils.h"
+#include "gtkwebview.h"
 #include "pidginstock.h"
 
+
+
 static GList *dialogwindows = NULL;
 
 static GtkWidget *about = NULL;
@@ -398,10 +399,10 @@
 {
 	GtkWidget *vbox;
 	GtkWidget *logo;
-	GtkWidget *frame;
-	GtkWidget *text;
+	GtkWidget *scrolled_window;
 	GtkWidget *button;
-	GtkTextIter iter;
+	GtkWidget *web_view;
+
 	GString *str;
 	AtkObject *obj;
 	char* filename, *tmp;
@@ -439,9 +440,14 @@
 	g_free(tmp);
 	gtk_box_pack_start(GTK_BOX(vbox), logo, FALSE, FALSE, 0);
 
-	frame = pidgin_create_imhtml(FALSE, &text, NULL, NULL);
-	gtk_imhtml_set_format_functions(GTK_IMHTML(text), GTK_IMHTML_ALL ^ GTK_IMHTML_SMILEY);
-	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
+	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+	web_view = gtk_webview_new ();
+	gtk_container_add (GTK_CONTAINER (scrolled_window), web_view);
+
+	gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
 
 	str = g_string_sized_new(4096);
 
@@ -682,11 +688,9 @@
 
 	/* End of not to be translated section */
 
-	gtk_imhtml_append_text(GTK_IMHTML(text), str->str, GTK_IMHTML_NO_SCROLL);
+	webkit_web_view_load_html_string (WEBKIT_WEB_VIEW(web_view), str->str, "");
 	g_string_free(str, TRUE);
 
-	gtk_text_buffer_get_start_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), &iter);
-	gtk_text_buffer_place_cursor(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), &iter);
 
 	/* Close Button */
 	button = pidgin_dialog_add_button(GTK_DIALOG(about), GTK_STOCK_CLOSE,
--- a/pidgin/gtklog.c	Thu Jul 23 04:05:31 2009 +0000
+++ b/pidgin/gtklog.c	Fri Jul 24 01:18:07 2009 +0000
@@ -35,9 +35,9 @@
 
 #include "pidginstock.h"
 #include "gtkblist.h"
-#include "gtkimhtml.h"
 #include "gtklog.h"
 #include "gtkutils.h"
+#include "gtkwebview.h"
 
 static GHashTable *log_viewers = NULL;
 static void populate_log_tree(PidginLogViewer *lv);
@@ -130,7 +130,7 @@
 		populate_log_tree(lv);
 		g_free(lv->search);
 		lv->search = NULL;
-		gtk_imhtml_search_clear(GTK_IMHTML(lv->imhtml));
+		webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(lv->web_view)); 
 		select_first_log(lv);
 		return;
 	}
@@ -138,7 +138,7 @@
 	if (lv->search != NULL && !strcmp(lv->search, search_term))
 	{
 		/* Searching for the same term acts as "Find Next" */
-		gtk_imhtml_search_find(GTK_IMHTML(lv->imhtml), lv->search);
+		webkit_web_view_search_text (WEBKIT_WEB_VIEW(lv->web_view), lv->search, FALSE, TRUE, TRUE);
 		return;
 	}
 
@@ -148,7 +148,7 @@
 	lv->search = g_strdup(search_term);
 
 	gtk_tree_store_clear(lv->treestore);
-	gtk_imhtml_clear(GTK_IMHTML(lv->imhtml));
+	webkit_web_view_open (WEBKIT_WEB_VIEW (lv->web_view), "about:blank"); /* clear the view */
 
 	for (logs = lv->logs; logs != NULL; logs = logs->next) {
 		char *read = purple_log_read((PurpleLog*)logs->data, NULL);
@@ -422,7 +422,9 @@
 static gboolean search_find_cb(gpointer data)
 {
 	PidginLogViewer *viewer = data;
-	gtk_imhtml_search_find(GTK_IMHTML(viewer->imhtml), viewer->search);
+	webkit_web_view_mark_text_matches (WEBKIT_WEB_VIEW (viewer->web_view), viewer->search, FALSE, 0);
+	webkit_web_view_set_highlight_text_matches (WEBKIT_WEB_VIEW (viewer->web_view), TRUE);
+	webkit_web_view_search_text (WEBKIT_WEB_VIEW (viewer->web_view), viewer->search, FALSE, TRUE, TRUE);
 	return FALSE;
 }
 
@@ -463,19 +465,15 @@
 	read = purple_log_read(log, &flags);
 	viewer->flags = flags;
 
-	gtk_imhtml_clear(GTK_IMHTML(viewer->imhtml));
-	gtk_imhtml_set_protocol_name(GTK_IMHTML(viewer->imhtml),
-	                            purple_account_get_protocol_name(log->account));
+	webkit_web_view_open (WEBKIT_WEB_VIEW(viewer->web_view), "about:blank");
 
 	purple_signal_emit(pidgin_log_get_handle(), "log-displaying", viewer, log);
 
-	gtk_imhtml_append_text(GTK_IMHTML(viewer->imhtml), read,
-			       GTK_IMHTML_NO_COMMENTS | GTK_IMHTML_NO_TITLE | GTK_IMHTML_NO_SCROLL |
-			       ((flags & PURPLE_LOG_READ_NO_NEWLINE) ? GTK_IMHTML_NO_NEWLINE : 0));
+	webkit_web_view_load_html_string (WEBKIT_WEB_VIEW(viewer->web_view), read, "");
 	g_free(read);
 
 	if (viewer->search != NULL) {
-		gtk_imhtml_search_clear(GTK_IMHTML(viewer->imhtml));
+		webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(viewer->web_view));
 		g_idle_add(search_find_cb, viewer);
 	}
 
@@ -658,11 +656,16 @@
 	gtk_paned_add2(GTK_PANED(pane), vbox);
 
 	/* Viewer ************/
-	frame = pidgin_create_imhtml(FALSE, &lv->imhtml, NULL, NULL);
-	gtk_widget_set_name(lv->imhtml, "pidgin_log_imhtml");
-	gtk_widget_set_size_request(lv->imhtml, 320, 200);
-	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
-	gtk_widget_show(frame);
+	sw = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
+
+	lv->web_view = gtk_webview_new ();
+	gtk_container_add (GTK_CONTAINER (sw), lv->web_view);
+	gtk_widget_set_name(lv->web_view, "pidgin_log_web_view");
+	gtk_widget_set_size_request(lv->web_view, 320, 200);
+	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
+	gtk_widget_show(sw);
 
 	/* Search box **********/
 	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
--- a/pidgin/gtklog.h	Thu Jul 23 04:05:31 2009 +0000
+++ b/pidgin/gtklog.h	Fri Jul 24 01:18:07 2009 +0000
@@ -43,7 +43,7 @@
 	GtkWidget        *window;    /**< The viewer's window                      */
 	GtkTreeStore     *treestore; /**< The treestore containing said logs       */
 	GtkWidget        *treeview;  /**< The treeview representing said treestore */
-	GtkWidget        *imhtml;    /**< The imhtml to display said logs          */
+	GtkWidget        *web_view;  /**< The webkit web view to display said logs */
 	GtkWidget        *entry;     /**< The search entry, in which search terms
 	                              *   are entered                              */
 	PurpleLogReadFlags flags;      /**< The most recently used log flags         */
--- a/pidgin/gtknotify.c	Thu Jul 23 04:05:31 2009 +0000
+++ b/pidgin/gtknotify.c	Fri Jul 24 01:18:07 2009 +0000
@@ -36,10 +36,10 @@
 #include "util.h"
 
 #include "gtkblist.h"
-#include "gtkimhtml.h"
 #include "gtknotify.h"
 #include "gtkpounce.h"
 #include "gtkutils.h"
+#include "gtkwebview.h"
 
 typedef struct
 {
@@ -738,21 +738,6 @@
 	return FALSE;
 }
 
-static GtkIMHtmlOptions
-notify_imhtml_options(void)
-{
-	GtkIMHtmlOptions options = 0;
-
-	if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting"))
-		options |= GTK_IMHTML_NO_COLOURS | GTK_IMHTML_NO_FONTS | GTK_IMHTML_NO_SIZES;
-
-	options |= GTK_IMHTML_NO_COMMENTS;
-	options |= GTK_IMHTML_NO_TITLE;
-	options |= GTK_IMHTML_NO_NEWLINE;
-	options |= GTK_IMHTML_NO_SCROLL;
-	return options;
-}
-
 static void *
 pidgin_notify_formatted(const char *title, const char *primary,
 						  const char *secondary, const char *text)
@@ -761,8 +746,8 @@
 	GtkWidget *vbox;
 	GtkWidget *label;
 	GtkWidget *button;
-	GtkWidget *imhtml;
-	GtkWidget *frame;
+	GtkWidget *web_view;
+	GtkWidget *scrolled_window;
 	char label_text[2048];
 	char *linked_text, *primary_esc, *secondary_esc;
 
@@ -797,14 +782,18 @@
 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
 	gtk_widget_show(label);
 
-	/* Add the imhtml */
-	frame = pidgin_create_imhtml(FALSE, &imhtml, NULL, NULL);
-	gtk_widget_set_name(imhtml, "pidgin_notify_imhtml");
-	gtk_imhtml_set_format_functions(GTK_IMHTML(imhtml),
-			gtk_imhtml_get_format_functions(GTK_IMHTML(imhtml)) | GTK_IMHTML_IMAGE);
-	gtk_widget_set_size_request(imhtml, 300, 250);
-	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
-	gtk_widget_show(frame);
+	/* Add the webview */
+	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+	web_view = gtk_webview_new ();
+	gtk_container_add (GTK_CONTAINER (scrolled_window), web_view);
+
+	gtk_widget_set_name(web_view, "pidgin_notify_webview");
+	gtk_widget_set_size_request(web_view, 300, 250);
+	gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
+	gtk_widget_show_all(scrolled_window);
 
 	/* Add the Close button. */
 	button = gtk_dialog_add_button(GTK_DIALOG(window), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
@@ -817,10 +806,10 @@
 
 	/* Make sure URLs are clickable */
 	linked_text = purple_markup_linkify(text);
-	gtk_imhtml_append_text(GTK_IMHTML(imhtml), linked_text, notify_imhtml_options());
+	webkit_web_view_load_html_string (WEBKIT_WEB_VIEW (web_view), linked_text, "");
 	g_free(linked_text);
 
-	g_object_set_data(G_OBJECT(window), "info-widget", imhtml);
+	g_object_set_data(G_OBJECT(window), "webview-widget", web_view);
 
 	/* Show the window */
 	pidgin_auto_parent_window(window);
@@ -1079,10 +1068,11 @@
 	info = purple_notify_user_info_get_text_with_newline(user_info, "<br />");
 	pinfo = g_hash_table_lookup(userinfo, key);
 	if (pinfo != NULL) {
-		GtkIMHtml *imhtml = g_object_get_data(G_OBJECT(pinfo->window), "info-widget");
+		GtkWidget *webview = g_object_get_data(G_OBJECT(pinfo->window), "webview-widget");
 		char *linked_text = purple_markup_linkify(info);
-		gtk_imhtml_clear(imhtml);
-		gtk_imhtml_append_text(imhtml, linked_text, notify_imhtml_options());
+		g_assert (webview);
+		printf ("%s\n", linked_text);
+		gtk_webview_load_html_string_with_imgstore (GTK_WEBVIEW (webview), linked_text);
 		g_free(linked_text);
 		g_free(key);
 		ui_handle = pinfo->window;
--- a/pidgin/gtkthemes.c	Thu Jul 23 04:05:31 2009 +0000
+++ b/pidgin/gtkthemes.c	Fri Jul 24 01:18:07 2009 +0000
@@ -270,6 +270,8 @@
 		if (*i == '[' && strchr(i, ']') && load) {
 			struct smiley_list *child = g_new0(struct smiley_list, 1);
 			child->sml = g_strndup(i+1, strchr(i, ']') - i - 1);
+			child->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
 			if (theme->list)
 				list->next = child;
 			else
@@ -320,6 +322,7 @@
 				} else {
 					GtkIMHtmlSmiley *smiley = gtk_imhtml_smiley_create(sfile, l, hidden, 0);
 					list->smileys = g_slist_prepend(list->smileys, smiley);
+					g_hash_table_insert (list->files, g_strdup(l), g_strdup(sfile));
 				}
 				while (isspace(*i))
 					i++;
@@ -361,7 +364,6 @@
 
 			if (PIDGIN_IS_PIDGIN_CONVERSATION(conv)) {
 				/* We want to see our custom smileys on our entry if we write the shortcut */
-				pidgin_themes_smiley_themeize(PIDGIN_CONVERSATION(conv)->imhtml);
 				pidgin_themes_smiley_themeize_custom(PIDGIN_CONVERSATION(conv)->entry);
 			}
 		}
--- a/pidgin/gtkthemes.h	Thu Jul 23 04:05:31 2009 +0000
+++ b/pidgin/gtkthemes.h	Fri Jul 24 01:18:07 2009 +0000
@@ -29,6 +29,7 @@
 struct smiley_list {
 	char *sml;
 	GSList *smileys;
+	GHashTable *files; /**< map from smiley shortcut to filename */
 	struct smiley_list *next;
 };
 
--- a/pidgin/plugins/Makefile.am	Thu Jul 23 04:05:31 2009 +0000
+++ b/pidgin/plugins/Makefile.am	Fri Jul 24 01:18:07 2009 +0000
@@ -1,4 +1,4 @@
-DIST_SUBDIRS = cap disco gestures gevolution musicmessaging perl ticker
+DIST_SUBDIRS = adiumthemes cap disco gestures gevolution musicmessaging perl ticker
 
 if BUILD_GEVOLUTION
 GEVOLUTION_DIR = gevolution
@@ -16,9 +16,6 @@
 PERL_DIR = perl
 endif
 
-if ENABLE_GESTURES
-GESTURE_DIR = gestures
-endif
 
 SUBDIRS = \
 	$(CAP_DIR) \
@@ -27,7 +24,8 @@
 	$(MUSICMESSAGING_DIR) \
 	$(PERL_DIR) \
 	disco \
-	ticker
+	ticker \
+	adiumthemes
 
 plugindir = $(libdir)/pidgin
 
@@ -36,17 +34,12 @@
 extplacement_la_LDFLAGS     = -module -avoid-version
 gtk_signals_test_la_LDFLAGS = -module -avoid-version
 gtkbuddynote_la_LDFLAGS     = -module -avoid-version
-history_la_LDFLAGS          = -module -avoid-version
 iconaway_la_LDFLAGS         = -module -avoid-version
-markerline_la_LDFLAGS       = -module -avoid-version
-notify_la_LDFLAGS           = -module -avoid-version
 pidginrc_la_LDFLAGS         = -module -avoid-version
 relnot_la_LDFLAGS           = -module -avoid-version
 sendbutton_la_LDFLAGS       = -module -avoid-version
 spellchk_la_LDFLAGS         = -module -avoid-version
 themeedit_la_LDFLAGS        = -module -avoid-version
-timestamp_la_LDFLAGS        = -module -avoid-version
-timestamp_format_la_LDFLAGS = -module -avoid-version
 xmppconsole_la_LDFLAGS      = -module -avoid-version
 
 if PLUGINS
@@ -55,17 +48,12 @@
 	convcolors.la       \
 	extplacement.la     \
 	gtkbuddynote.la     \
-	history.la          \
 	iconaway.la         \
-	markerline.la       \
-	notify.la           \
 	pidginrc.la         \
 	relnot.la           \
 	sendbutton.la       \
 	spellchk.la         \
 	themeedit.la         \
-	timestamp.la        \
-	timestamp_format.la \
 	xmppconsole.la
 
 noinst_LTLIBRARIES = \
@@ -77,35 +65,12 @@
 extplacement_la_SOURCES     = extplacement.c
 gtk_signals_test_la_SOURCES = gtk-signals-test.c
 gtkbuddynote_la_SOURCES     = gtkbuddynote.c
-history_la_SOURCES          = history.c
 iconaway_la_SOURCES         = iconaway.c
-markerline_la_SOURCES       = markerline.c
-notify_la_SOURCES           = notify.c
 pidginrc_la_SOURCES         = pidginrc.c
 relnot_la_SOURCES           = relnot.c
 sendbutton_la_SOURCES       = sendbutton.c
 spellchk_la_SOURCES         = spellchk.c
 themeedit_la_SOURCES        = themeedit.c themeedit-icon.c themeedit-icon.h
-timestamp_la_SOURCES        = timestamp.c
-timestamp_format_la_SOURCES = timestamp_format.c
-xmppconsole_la_SOURCES      = xmppconsole.c
-
-convcolors_la_LIBADD        = $(GTK_LIBS)
-contact_priority_la_LIBADD  = $(GTK_LIBS)
-extplacement_la_LIBADD      = $(GTK_LIBS)
-gtk_signals_test_la_LIBADD  = $(GTK_LIBS)
-gtkbuddynote_la_LIBADD      = $(GTK_LIBS)
-history_la_LIBADD           = $(GTK_LIBS)
-iconaway_la_LIBADD          = $(GTK_LIBS)
-markerline_la_LIBADD        = $(GTK_LIBS)
-notify_la_LIBADD            = $(GTK_LIBS)
-pidginrc_la_LIBADD          = $(GTK_LIBS)
-relnot_la_LIBADD            = $(GLIB_LIBS)
-sendbutton_la_LIBADD        = $(GTK_LIBS)
-spellchk_la_LIBADD          = $(GTK_LIBS)
-themeedit_la_LIBADD         = $(GTK_LIBS)
-timestamp_la_LIBADD         = $(GTK_LIBS)
-timestamp_format_la_LIBADD  = $(GTK_LIBS)
 xmppconsole_la_LIBADD       = $(GTK_LIBS)
 
 endif # PLUGINS