changeset 32725:e53eb11ff985

propagate from branch 'im.pidgin.cpw.qulogic.gtk3' (head 48830f0ec00f34eaac1edbb7f4d702bb04410b05) to branch 'im.pidgin.pidgin' (head 9174da183193795cce221fd1aa868986fc775148)
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Mon, 27 Feb 2012 22:45:47 +0000
parents c631931c3794 (diff) 42b3e6ded93b (current diff)
children c47349fcd270
files pidgin/gtkprefs.c
diffstat 36 files changed, 1870 insertions(+), 878 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/jabber/Makefile.am	Mon Feb 27 06:44:05 2012 +0000
+++ b/libpurple/protocols/jabber/Makefile.am	Mon Feb 27 22:45:47 2012 +0000
@@ -103,19 +103,25 @@
 
 st = -DPURPLE_STATIC_PRPL
 noinst_LTLIBRARIES   = libjabber.la
-libjabber_la_SOURCES = $(JABBERSOURCES) libxmpp.c
+libjabber_la_SOURCES = $(JABBERSOURCES) libfacebook.c libgtalk.c libxmpp.c
 libjabber_la_CFLAGS  = $(AM_CFLAGS)
 
 else
 
 st =
-pkg_LTLIBRARIES      = libjabber.la libxmpp.la
+pkg_LTLIBRARIES      = libjabber.la libfacebook.la libgtalk.la libxmpp.la
 libjabber_la_SOURCES = $(JABBERSOURCES)
 libjabber_la_LIBADD  = $(GLIB_LIBS) $(SASL_LIBS) $(LIBXML_LIBS) $(IDN_LIBS)\
 	$(FARSIGHT_LIBS) \
 	$(GSTREAMER_LIBS) \
 	$(GSTINTERFACES_LIBS)
 
+libfacebook_la_SOURCES = libfacebook.c
+libfacebook_la_LIBADD = libjabber.la
+
+libgtalk_la_SOURCES = libgtalk.c
+libgtalk_la_LIBADD = libjabber.la
+
 libxmpp_la_SOURCES = libxmpp.c
 libxmpp_la_LIBADD = libjabber.la
 
--- a/libpurple/protocols/jabber/Makefile.mingw	Mon Feb 27 06:44:05 2012 +0000
+++ b/libpurple/protocols/jabber/Makefile.mingw	Mon Feb 27 22:45:47 2012 +0000
@@ -8,6 +8,8 @@
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
 TARGET = libjabber
+FACEBOOK_TARGET = libfacebook
+GTALK_TARGET = libgtalk
 XMPP_TARGET = libxmpp
 TYPE = PLUGIN
 
@@ -90,6 +92,12 @@
 
 OBJECTS = $(C_SRC:%.c=%.o)
 
+FACEBOOK_C_SRC = libfacebook.c
+FACEBOOK_OBJECTS = $(FACEBOOK_C_SRC:%.c=%.o)
+
+GTALK_C_SRC = libgtalk.c
+GTALK_OBJECTS = $(GTALK_C_SRC:%.c=%.o)
+
 XMPP_C_SRC = libxmpp.c
 XMPP_OBJECTS = $(XMPP_C_SRC:%.c=%.o)
 
@@ -129,9 +137,11 @@
 ##
 .PHONY: all install clean
 
-all: $(TARGET).dll $(XMPP_TARGET).dll
+all: $(TARGET).dll $(FACEBOOK_TARGET).dll $(GTALK_TARGET).dll $(XMPP_TARGET).dll
 
 install: all $(DLL_INSTALL_DIR)
+	cp $(FACEBOOK_TARGET).dll $(DLL_INSTALL_DIR)
+	cp $(GTALK_TARGET).dll $(DLL_INSTALL_DIR)
 	cp $(XMPP_TARGET).dll $(DLL_INSTALL_DIR)
 	cp $(TARGET).dll $(PURPLE_INSTALL_DIR)
 ifeq ($(CYRUS_SASL), 1)
@@ -145,6 +155,12 @@
 $(TARGET).dll $(TARGET).dll.a: $(PURPLE_DLL).a $(OBJECTS)
 	$(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--out-implib,$(TARGET).dll.a -o $(TARGET).dll
 
+$(FACEBOOK_TARGET).dll: $(TARGET).dll.a $(FACEBOOK_OBJECTS)
+	$(CC) -shared $(FACEBOOK_OBJECTS) $(LIB_PATHS) $(LIBS) -ljabber $(DLL_LD_FLAGS) -o $(FACEBOOK_TARGET).dll
+
+$(GTALK_TARGET).dll: $(TARGET).dll.a $(GTALK_OBJECTS)
+	$(CC) -shared $(GTALK_OBJECTS) $(LIB_PATHS) $(LIBS) -ljabber $(DLL_LD_FLAGS) -o $(GTALK_TARGET).dll
+
 $(XMPP_TARGET).dll: $(TARGET).dll.a $(XMPP_OBJECTS)
 	$(CC) -shared $(XMPP_OBJECTS) $(LIB_PATHS) $(LIBS) -ljabber $(DLL_LD_FLAGS) -o $(XMPP_TARGET).dll
 
@@ -153,6 +169,8 @@
 ##
 clean:
 	rm -f $(OBJECTS) $(TARGET).dll $(TARGET).dll.a
+	rm -f $(FACEBOOK_OBJECTS) $(FACEBOOK_TARGET).dll
+	rm -f $(GTALK_OBJECTS) $(GTALK_TARGET).dll
 	rm -f $(XMPP_OBJECTS) $(XMPP_TARGET).dll
 
 include $(PIDGIN_COMMON_TARGETS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/libfacebook.c	Mon Feb 27 22:45:47 2012 +0000
@@ -0,0 +1,326 @@
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+/* libfacebook is the Facebook XMPP protocol plugin. It is linked against
+ * libjabbercommon, which may be used to support other protocols (Bonjour)
+ * which may need to share code.
+ */
+
+#include "internal.h"
+
+#include "accountopt.h"
+#include "core.h"
+#include "debug.h"
+#include "version.h"
+
+#include "iq.h"
+#include "jabber.h"
+#include "chat.h"
+#include "disco.h"
+#include "message.h"
+#include "roster.h"
+#include "si.h"
+#include "message.h"
+#include "presence.h"
+#include "google/google.h"
+#include "pep.h"
+#include "usermood.h"
+#include "usertune.h"
+#include "caps.h"
+#include "data.h"
+#include "ibb.h"
+
+static const char *
+facebook_list_icon(PurpleAccount *a, PurpleBuddy *b)
+{
+	return "facebook";
+}
+
+static PurplePlugin *my_protocol = NULL;
+
+static PurplePluginProtocolInfo prpl_info =
+{
+	sizeof(PurplePluginProtocolInfo),       /* struct_size */
+	OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_MAIL_CHECK |
+#ifdef HAVE_CYRUS_SASL
+	OPT_PROTO_PASSWORD_OPTIONAL |
+#endif
+	OPT_PROTO_SLASH_COMMANDS_NATIVE,
+	NULL,							/* user_splits */
+	NULL,							/* protocol_options */
+	{"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_SEND | PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
+	facebook_list_icon,				/* list_icon */
+	jabber_list_emblem,			/* list_emblems */
+	jabber_status_text,				/* status_text */
+	jabber_tooltip_text,			/* tooltip_text */
+	jabber_status_types,			/* status_types */
+	jabber_blist_node_menu,			/* blist_node_menu */
+	jabber_chat_info,				/* chat_info */
+	jabber_chat_info_defaults,		/* chat_info_defaults */
+	jabber_login,					/* login */
+	jabber_close,					/* close */
+	jabber_message_send_im,			/* send_im */
+	jabber_set_info,				/* set_info */
+	jabber_send_typing,				/* send_typing */
+	jabber_buddy_get_info,			/* get_info */
+	jabber_set_status,				/* set_status */
+	jabber_idle_set,				/* set_idle */
+	NULL,							/* change_passwd */
+	NULL,							/* add_buddy */
+	NULL,							/* add_buddies */
+	NULL,							/* remove_buddy */
+	NULL,							/* remove_buddies */
+	NULL,							/* add_permit */
+	NULL,							/* add_deny */
+	NULL,							/* rem_permit */
+	NULL,							/* rem_deny */
+	NULL,							/* set_permit_deny */
+	jabber_chat_join,				/* join_chat */
+	NULL,							/* reject_chat */
+	jabber_get_chat_name,			/* get_chat_name */
+	jabber_chat_invite,				/* chat_invite */
+	jabber_chat_leave,				/* chat_leave */
+	NULL,							/* chat_whisper */
+	jabber_message_send_chat,		/* chat_send */
+	jabber_keepalive,				/* keepalive */
+	NULL,							/* register_user */
+	NULL,							/* get_cb_info */
+	NULL,							/* alias_buddy */
+	NULL,							/* group_buddy */
+	NULL,							/* rename_group */
+	NULL,							/* buddy_free */
+	jabber_convo_closed,			/* convo_closed */
+	jabber_normalize,				/* normalize */
+	jabber_set_buddy_icon,			/* set_buddy_icon */
+	NULL,							/* remove_group */
+	jabber_chat_buddy_real_name,	/* get_cb_real_name */
+	jabber_chat_set_topic,			/* set_chat_topic */
+	jabber_find_blist_chat,			/* find_blist_chat */
+	jabber_roomlist_get_list,		/* roomlist_get_list */
+	jabber_roomlist_cancel,			/* roomlist_cancel */
+	NULL,							/* roomlist_expand_category */
+	NULL,							/* can_receive_file */
+	NULL,							/* send_file */
+	NULL,							/* new_xfer */
+	jabber_offline_message,			/* offline_message */
+	NULL,							/* whiteboard_prpl_ops */
+	jabber_prpl_send_raw,			/* send_raw */
+	jabber_roomlist_room_serialize, /* roomlist_room_serialize */
+	NULL,							/* unregister_user */
+	NULL,							/* send_attention */
+	NULL,							/* attention_types */
+	NULL, /* get_account_text_table */
+	NULL,							/* initiate_media */
+	NULL,							/* get_media_caps */
+	NULL,							/* get_moods */
+	NULL, /* set_public_alias */
+	NULL  /* get_public_alias */
+};
+
+static gboolean load_plugin(PurplePlugin *plugin)
+{
+	jabber_plugin_init(plugin);
+
+	return TRUE;
+}
+
+static gboolean unload_plugin(PurplePlugin *plugin)
+{
+	jabber_plugin_uninit(plugin);
+
+	return TRUE;
+}
+
+static PurplePluginInfo info =
+{
+	PURPLE_PLUGIN_MAGIC,
+	PURPLE_MAJOR_VERSION,
+	PURPLE_MINOR_VERSION,
+	PURPLE_PLUGIN_PROTOCOL,                         /**< type           */
+	NULL,                                           /**< ui_requirement */
+	0,                                              /**< flags          */
+	NULL,                                           /**< dependencies   */
+	PURPLE_PRIORITY_DEFAULT,                        /**< priority       */
+
+	"prpl-facebook-xmpp",                           /**< id             */
+	"Facebook (XMPP)",                              /**< name           */
+	DISPLAY_VERSION,                                /**< version        */
+	                                                /**  summary        */
+	N_("Facebook XMPP Protocol Plugin"),
+	                                                /**  description    */
+	N_("Facebook XMPP Protocol Plugin"),
+	NULL,                                           /**< author         */
+	PURPLE_WEBSITE,                                 /**< homepage       */
+
+	load_plugin,                                    /**< load           */
+	unload_plugin,                                  /**< unload         */
+	NULL,                                           /**< destroy        */
+
+	NULL,                                           /**< ui_info        */
+	&prpl_info,                                     /**< extra_info     */
+	NULL,                                           /**< prefs_info     */
+	jabber_actions,
+
+	/* padding */
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+static PurpleAccount *find_acct(const char *prpl, const char *acct_id)
+{
+	PurpleAccount *acct = NULL;
+
+	/* If we have a specific acct, use it */
+	if (acct_id) {
+		acct = purple_accounts_find(acct_id, prpl);
+		if (acct && !purple_account_is_connected(acct))
+			acct = NULL;
+	} else { /* Otherwise find an active account for the protocol */
+		GList *l = purple_accounts_get_all();
+		while (l) {
+			if (!strcmp(prpl, purple_account_get_protocol_id(l->data))
+					&& purple_account_is_connected(l->data)) {
+				acct = l->data;
+				break;
+			}
+			l = l->next;
+		}
+	}
+
+	return acct;
+}
+
+static gboolean xmpp_uri_handler(const char *proto, const char *user, GHashTable *params)
+{
+	char *acct_id = params ? g_hash_table_lookup(params, "account") : NULL;
+	PurpleAccount *acct;
+
+	if (g_ascii_strcasecmp(proto, "xmpp"))
+		return FALSE;
+
+	acct = find_acct(purple_plugin_get_id(my_protocol), acct_id);
+
+	if (!acct)
+		return FALSE;
+
+	/* xmpp:romeo@montague.net?message;subject=Test%20Message;body=Here%27s%20a%20test%20message */
+	/* params is NULL if the URI has no '?' (or anything after it) */
+	if (!params || g_hash_table_lookup_extended(params, "message", NULL, NULL)) {
+		char *body = g_hash_table_lookup(params, "body");
+		if (user && *user) {
+			PurpleConversation *conv =
+					purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, user);
+			purple_conversation_present(conv);
+			if (body && *body)
+				purple_conv_send_confirm(conv, body);
+		}
+	} else if (g_hash_table_lookup_extended(params, "roster", NULL, NULL)) {
+		char *name = g_hash_table_lookup(params, "name");
+		if (user && *user)
+			purple_blist_request_add_buddy(acct, user, NULL, name);
+	} else if (g_hash_table_lookup_extended(params, "join", NULL, NULL)) {
+		PurpleConnection *gc = purple_account_get_connection(acct);
+		if (user && *user) {
+			GHashTable *params = jabber_chat_info_defaults(gc, user);
+			jabber_chat_join(gc, params);
+		}
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void
+init_plugin(PurplePlugin *plugin)
+{
+	PurpleAccountUserSplit *split;
+	PurpleAccountOption *option;
+	GList *encryption_values = NULL;
+
+	/* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */
+	split = purple_account_user_split_new(_("Domain"), "chat.facebook.com", '@');
+	purple_account_user_split_set_reverse(split, FALSE);
+	prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
+
+	split = purple_account_user_split_new(_("Resource"), "", '/');
+	purple_account_user_split_set_reverse(split, FALSE);
+	prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
+
+#define ADD_VALUE(list, desc, v) { \
+	PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \
+	kvp->key = g_strdup((desc)); \
+	kvp->value = g_strdup((v)); \
+	list = g_list_prepend(list, kvp); \
+}
+
+	ADD_VALUE(encryption_values, _("Use encryption if available"), "opportunistic_tls");
+	ADD_VALUE(encryption_values, _("Require encryption"), "require_tls");
+	ADD_VALUE(encryption_values, _("Use old-style SSL"), "old_ssl");
+#if 0
+	ADD_VALUE(encryption_values, "None", "none");
+#endif
+	encryption_values = g_list_reverse(encryption_values);
+
+#undef ADD_VALUE
+
+	option = purple_account_option_list_new(_("Connection security"), "connection_security", encryption_values);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+						   option);
+
+	option = purple_account_option_bool_new(
+						_("Allow plaintext auth over unencrypted streams"),
+						"auth_plain_in_clear", FALSE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+						   option);
+
+	option = purple_account_option_int_new(_("Connect port"), "port", 5222);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+						   option);
+
+	option = purple_account_option_string_new(_("Connect server"),
+						  "connect_server", NULL);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+						  option);
+
+	option = purple_account_option_string_new(_("BOSH URL"),
+						  "bosh_url", NULL);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+						  option);
+
+	/* this should probably be part of global smiley theme settings later on,
+	  shared with MSN */
+	option = purple_account_option_bool_new(_("Show Custom Smileys"),
+		"custom_smileys", TRUE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+		option);
+
+	my_protocol = plugin;
+
+	purple_signal_connect(purple_get_core(), "uri-handler", plugin,
+		PURPLE_CALLBACK(xmpp_uri_handler), NULL);
+}
+
+PURPLE_INIT_PLUGIN(facebookxmpp, init_plugin, info);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/libgtalk.c	Mon Feb 27 22:45:47 2012 +0000
@@ -0,0 +1,334 @@
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ *
+ */
+
+/* libgtalk is the Google Talk XMPP protocol plugin. It is linked against
+ * libjabbercommon, which may be used to support other protocols (Bonjour) which
+ * may need to share code.
+ */
+
+#include "internal.h"
+
+#include "accountopt.h"
+#include "core.h"
+#include "debug.h"
+#include "version.h"
+
+#include "iq.h"
+#include "jabber.h"
+#include "chat.h"
+#include "disco.h"
+#include "message.h"
+#include "roster.h"
+#include "si.h"
+#include "message.h"
+#include "presence.h"
+#include "google/google.h"
+#include "pep.h"
+#include "usermood.h"
+#include "usertune.h"
+#include "caps.h"
+#include "data.h"
+#include "ibb.h"
+
+static const char *
+gtalk_list_icon(PurpleAccount *a, PurpleBuddy *b)
+{
+	return "google-talk";
+}
+
+static PurplePlugin *my_protocol = NULL;
+
+static PurplePluginProtocolInfo prpl_info =
+{
+	sizeof(PurplePluginProtocolInfo),       /* struct_size */
+	OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_MAIL_CHECK |
+#ifdef HAVE_CYRUS_SASL
+	OPT_PROTO_PASSWORD_OPTIONAL |
+#endif
+	OPT_PROTO_SLASH_COMMANDS_NATIVE,
+	NULL,							/* user_splits */
+	NULL,							/* protocol_options */
+	{"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_SEND | PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
+	gtalk_list_icon,				/* list_icon */
+	jabber_list_emblem,			/* list_emblems */
+	jabber_status_text,				/* status_text */
+	jabber_tooltip_text,			/* tooltip_text */
+	jabber_status_types,			/* status_types */
+	jabber_blist_node_menu,			/* blist_node_menu */
+	jabber_chat_info,				/* chat_info */
+	jabber_chat_info_defaults,		/* chat_info_defaults */
+	jabber_login,					/* login */
+	jabber_close,					/* close */
+	jabber_message_send_im,			/* send_im */
+	jabber_set_info,				/* set_info */
+	jabber_send_typing,				/* send_typing */
+	jabber_buddy_get_info,			/* get_info */
+	jabber_set_status,				/* set_status */
+	jabber_idle_set,				/* set_idle */
+	NULL,							/* change_passwd */
+	jabber_roster_add_buddy,		/* add_buddy */
+	NULL,							/* add_buddies */
+	jabber_roster_remove_buddy,		/* remove_buddy */
+	NULL,							/* remove_buddies */
+	NULL,							/* add_permit */
+	jabber_add_deny,				/* add_deny */
+	NULL,							/* rem_permit */
+	jabber_rem_deny,				/* rem_deny */
+	NULL,							/* set_permit_deny */
+	jabber_chat_join,				/* join_chat */
+	NULL,							/* reject_chat */
+	jabber_get_chat_name,			/* get_chat_name */
+	jabber_chat_invite,				/* chat_invite */
+	jabber_chat_leave,				/* chat_leave */
+	NULL,							/* chat_whisper */
+	jabber_message_send_chat,		/* chat_send */
+	jabber_keepalive,				/* keepalive */
+	NULL,							/* register_user */
+	NULL,							/* get_cb_info */
+	jabber_roster_alias_change,		/* alias_buddy */
+	jabber_roster_group_change,		/* group_buddy */
+	jabber_roster_group_rename,		/* rename_group */
+	NULL,							/* buddy_free */
+	jabber_convo_closed,			/* convo_closed */
+	jabber_normalize,				/* normalize */
+	jabber_set_buddy_icon,			/* set_buddy_icon */
+	NULL,							/* remove_group */
+	jabber_chat_buddy_real_name,	/* get_cb_real_name */
+	jabber_chat_set_topic,			/* set_chat_topic */
+	jabber_find_blist_chat,			/* find_blist_chat */
+	jabber_roomlist_get_list,		/* roomlist_get_list */
+	jabber_roomlist_cancel,			/* roomlist_cancel */
+	NULL,							/* roomlist_expand_category */
+	jabber_can_receive_file,		/* can_receive_file */
+	jabber_si_xfer_send,			/* send_file */
+	jabber_si_new_xfer,				/* new_xfer */
+	jabber_offline_message,			/* offline_message */
+	NULL,							/* whiteboard_prpl_ops */
+	jabber_prpl_send_raw,			/* send_raw */
+	jabber_roomlist_room_serialize, /* roomlist_room_serialize */
+	NULL,							/* unregister_user */
+	jabber_send_attention,			/* send_attention */
+	jabber_attention_types,			/* attention_types */
+	NULL, /* get_account_text_table */
+	jabber_initiate_media,          /* initiate_media */
+	jabber_get_media_caps,                  /* get_media_caps */
+	jabber_get_moods,  							/* get_moods */
+	NULL, /* set_public_alias */
+	NULL  /* get_public_alias */
+};
+
+static gboolean load_plugin(PurplePlugin *plugin)
+{
+	jabber_plugin_init(plugin);
+
+	return TRUE;
+}
+
+static gboolean unload_plugin(PurplePlugin *plugin)
+{
+	jabber_plugin_uninit(plugin);
+
+	return TRUE;
+}
+
+static PurplePluginInfo info =
+{
+	PURPLE_PLUGIN_MAGIC,
+	PURPLE_MAJOR_VERSION,
+	PURPLE_MINOR_VERSION,
+	PURPLE_PLUGIN_PROTOCOL,                         /**< type           */
+	NULL,                                           /**< ui_requirement */
+	0,                                              /**< flags          */
+	NULL,                                           /**< dependencies   */
+	PURPLE_PRIORITY_DEFAULT,                        /**< priority       */
+
+	"prpl-gtalk",                                   /**< id             */
+	"Google Talk (XMPP)",                           /**< name           */
+	DISPLAY_VERSION,                                /**< version        */
+	                                                /**  summary        */
+	N_("Google Talk Protocol Plugin"),
+	                                                /**  description    */
+	N_("Google Talk Protocol Plugin"),
+	NULL,                                           /**< author         */
+	PURPLE_WEBSITE,                                 /**< homepage       */
+
+	load_plugin,                                    /**< load           */
+	unload_plugin,                                  /**< unload         */
+	NULL,                                           /**< destroy        */
+
+	NULL,                                           /**< ui_info        */
+	&prpl_info,                                     /**< extra_info     */
+	NULL,                                           /**< prefs_info     */
+	jabber_actions,
+
+	/* padding */
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+static PurpleAccount *find_acct(const char *prpl, const char *acct_id)
+{
+	PurpleAccount *acct = NULL;
+
+	/* If we have a specific acct, use it */
+	if (acct_id) {
+		acct = purple_accounts_find(acct_id, prpl);
+		if (acct && !purple_account_is_connected(acct))
+			acct = NULL;
+	} else { /* Otherwise find an active account for the protocol */
+		GList *l = purple_accounts_get_all();
+		while (l) {
+			if (!strcmp(prpl, purple_account_get_protocol_id(l->data))
+					&& purple_account_is_connected(l->data)) {
+				acct = l->data;
+				break;
+			}
+			l = l->next;
+		}
+	}
+
+	return acct;
+}
+
+static gboolean xmpp_uri_handler(const char *proto, const char *user, GHashTable *params)
+{
+	char *acct_id = params ? g_hash_table_lookup(params, "account") : NULL;
+	PurpleAccount *acct;
+
+	if (g_ascii_strcasecmp(proto, "xmpp"))
+		return FALSE;
+
+	acct = find_acct(purple_plugin_get_id(my_protocol), acct_id);
+
+	if (!acct)
+		return FALSE;
+
+	/* xmpp:romeo@montague.net?message;subject=Test%20Message;body=Here%27s%20a%20test%20message */
+	/* params is NULL if the URI has no '?' (or anything after it) */
+	if (!params || g_hash_table_lookup_extended(params, "message", NULL, NULL)) {
+		char *body = g_hash_table_lookup(params, "body");
+		if (user && *user) {
+			PurpleConversation *conv =
+					purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, user);
+			purple_conversation_present(conv);
+			if (body && *body)
+				purple_conv_send_confirm(conv, body);
+		}
+	} else if (g_hash_table_lookup_extended(params, "roster", NULL, NULL)) {
+		char *name = g_hash_table_lookup(params, "name");
+		if (user && *user)
+			purple_blist_request_add_buddy(acct, user, NULL, name);
+	} else if (g_hash_table_lookup_extended(params, "join", NULL, NULL)) {
+		PurpleConnection *gc = purple_account_get_connection(acct);
+		if (user && *user) {
+			GHashTable *params = jabber_chat_info_defaults(gc, user);
+			jabber_chat_join(gc, params);
+		}
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void
+init_plugin(PurplePlugin *plugin)
+{
+	PurpleAccountUserSplit *split;
+	PurpleAccountOption *option;
+	GList *encryption_values = NULL;
+
+	/* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */
+	split = purple_account_user_split_new(_("Domain"), "gmail.com", '@');
+	purple_account_user_split_set_reverse(split, FALSE);
+	prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
+
+	split = purple_account_user_split_new(_("Resource"), "", '/');
+	purple_account_user_split_set_reverse(split, FALSE);
+	prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
+
+#define ADD_VALUE(list, desc, v) { \
+	PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \
+	kvp->key = g_strdup((desc)); \
+	kvp->value = g_strdup((v)); \
+	list = g_list_prepend(list, kvp); \
+}
+
+	ADD_VALUE(encryption_values, _("Require encryption"), "require_tls");
+	ADD_VALUE(encryption_values, _("Use encryption if available"), "opportunistic_tls");
+	ADD_VALUE(encryption_values, _("Use old-style SSL"), "old_ssl");
+#if 0
+	ADD_VALUE(encryption_values, "None", "none");
+#endif
+	encryption_values = g_list_reverse(encryption_values);
+
+#undef ADD_VALUE
+
+	option = purple_account_option_list_new(_("Connection security"), "connection_security", encryption_values);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+						   option);
+
+	option = purple_account_option_bool_new(
+						_("Allow plaintext auth over unencrypted streams"),
+						"auth_plain_in_clear", FALSE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+						   option);
+
+	option = purple_account_option_int_new(_("Connect port"), "port", 5222);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+						   option);
+
+	option = purple_account_option_string_new(_("Connect server"),
+						  "connect_server", NULL);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+						  option);
+
+	option = purple_account_option_string_new(_("File transfer proxies"),
+						  "ft_proxies",
+						/* TODO: Is this an acceptable default?
+						 * Also, keep this in sync as they add more servers */
+						  JABBER_DEFAULT_FT_PROXIES);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+						  option);
+
+	option = purple_account_option_string_new(_("BOSH URL"),
+						  "bosh_url", NULL);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+						  option);
+
+	/* this should probably be part of global smiley theme settings later on,
+	  shared with MSN */
+	option = purple_account_option_bool_new(_("Show Custom Smileys"),
+		"custom_smileys", TRUE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+		option);
+
+	my_protocol = plugin;
+
+	purple_signal_connect(purple_get_core(), "uri-handler", plugin,
+		PURPLE_CALLBACK(xmpp_uri_handler), NULL);
+}
+
+PURPLE_INIT_PLUGIN(gtalk, init_plugin, info);
+
--- a/pidgin/gtkaccount.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkaccount.c	Mon Feb 27 22:45:47 2012 +0000
@@ -220,7 +220,7 @@
 }
 
 static void
-set_account_protocol_cb(GtkWidget *item, const char *id,
+set_account_protocol_cb(GtkWidget *widget, const char *id,
 						AccountPrefsDialog *dialog)
 {
 	PurplePlugin *new_plugin;
@@ -247,8 +247,7 @@
 
 	gtk_widget_grab_focus(dialog->protocol_menu);
 
-	if (!dialog->prpl_info || !dialog->prpl_info->register_user ||
-	    g_object_get_data(G_OBJECT(item), "fake")) {
+	if (!dialog->prpl_info || !dialog->prpl_info->register_user) {
 		gtk_widget_hide(dialog->register_button);
 	} else {
 		if (dialog->prpl_info != NULL &&
@@ -424,8 +423,6 @@
 	GtkWidget *hbox;
 	GtkWidget *vbox;
 	GtkWidget *entry;
-	GtkWidget *menu;
-	GtkWidget *item;
 	GList *user_splits;
 	GList *l, *l2;
 	char *username = NULL;
@@ -563,17 +560,6 @@
 		if (value == NULL)
 			value = purple_account_user_split_get_default_value(split);
 
-		/* Google Talk default domain hackery! */
-		menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(dialog->protocol_menu));
-		item = gtk_menu_get_active(GTK_MENU(menu));
-		if (value == NULL && g_object_get_data(G_OBJECT(item), "fakegoogle") &&
-			!strcmp(purple_account_user_split_get_text(split), _("Domain")))
-			value = "gmail.com";
-
-		if (value == NULL && g_object_get_data(G_OBJECT(item), "fakefacebook") &&
-			!strcmp(purple_account_user_split_get_text(split), _("Domain")))
-			value = "chat.facebook.com";
-
 		if (value != NULL)
 			gtk_entry_set_text(GTK_ENTRY(entry), value);
 	}
@@ -769,7 +755,7 @@
 {
 	PurpleAccountOption *option;
 	PurpleAccount *account;
-	GtkWidget *vbox, *check, *entry, *combo, *menu, *item;
+	GtkWidget *vbox, *check, *entry, *combo;
 	GList *list, *node;
 	gint i, idx, int_value;
 	GtkListStore *model;
@@ -808,9 +794,6 @@
 			gtk_label_new_with_mnemonic(_("Ad_vanced")), 1);
 	gtk_widget_show(vbox);
 
-	menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(dialog->protocol_menu));
-	item = gtk_menu_get_active(GTK_MENU(menu));
-
 	for (l = dialog->prpl_info->protocol_options; l != NULL; l = l->next)
 	{
 		option = (PurpleAccountOption *)l->data;
@@ -925,10 +908,6 @@
 				model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
 				opt_entry->widget = combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
 
-				if (g_object_get_data(G_OBJECT(item), "fakefacebook") &&
-					!strcmp(opt_entry->setting, "connection_security"))
-					str_value = "opportunistic_tls";
-
 				/* Loop through list of PurpleKeyValuePair items */
 				for (node = list; node != NULL; node = node->next) {
 					if (node->data != NULL) {
@@ -1213,8 +1192,12 @@
 		gtk_widget_show_all(dialog->voice_frame);
 	}
 
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->suppression_check),
-								purple_account_get_silence_suppression(dialog->account));
+	if (dialog->account) {
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->suppression_check),
+		                             purple_account_get_silence_suppression(dialog->account));
+	} else {
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->suppression_check), FALSE);
+	}
 #endif
 }
 
@@ -2726,4 +2709,3 @@
 	purple_signals_unregister_by_instance(pidgin_account_get_handle());
 }
 
-
--- a/pidgin/gtkblist.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkblist.c	Mon Feb 27 22:45:47 2012 +0000
@@ -124,6 +124,11 @@
 #define PIDGIN_BUDDY_LIST_GET_PRIVATE(list) \
 	((PidginBuddyListPrivate *)((list)->priv))
 
+#if !GTK_CHECK_VERSION(2,18,0)
+#define gtk_widget_get_visible(x) GTK_WIDGET_VISIBLE(x)
+#define gtk_widget_has_focus(x) GTK_WIDGET_HAS_FOCUS(x)
+#endif
+
 static GtkWidget *accountmenu = NULL;
 
 static guint visibility_manager_count = 0;
@@ -138,6 +143,9 @@
 static void sort_method_alphabetical(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
 static void sort_method_status(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
 static void sort_method_log_activity(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
+static guint sort_merge_id;
+static GtkActionGroup *sort_action_group = NULL;
+
 static PidginBuddyList *gtkblist = NULL;
 
 static GList *groups_tree(void);
@@ -148,7 +156,6 @@
 static void pidgin_blist_update_group(PurpleBuddyList *list, PurpleBlistNode *node);
 static void pidgin_blist_update_contact(PurpleBuddyList *list, PurpleBlistNode *node);
 static char *pidgin_get_tooltip_text(PurpleBlistNode *node, gboolean full);
-static const char *item_factory_translate_func (const char *path, gpointer func_data);
 static gboolean get_iter_from_node(PurpleBlistNode *node, GtkTreeIter *iter);
 static gboolean buddy_is_displayable(PurpleBuddy *buddy);
 static void redo_buddy_list(PurpleBuddyList *list, gboolean remove, gboolean rerender);
@@ -242,7 +249,7 @@
 
 	/* check for visibility because when we aren't visible, this will   *
 	 * give us bogus (0,0) coordinates.                      - xOr      */
-	if (GTK_WIDGET_VISIBLE(w))
+	if (gtk_widget_get_visible(w))
 		gtk_window_get_position(GTK_WINDOW(w), &x, &y);
 	else
 		return FALSE; /* carry on normally */
@@ -2012,64 +2019,70 @@
 	return handled;
 }
 
-static void pidgin_blist_buddy_details_cb(gpointer data, guint action, GtkWidget *item)
+static void gtk_blist_show_xfer_dialog_cb(GtkAction *item, gpointer data)
+{
+	pidgin_xfer_dialog_show(NULL);
+}
+
+static void pidgin_blist_buddy_details_cb(GtkToggleAction *item, gpointer data)
 {
 	pidgin_set_cursor(gtkblist->window, GDK_WATCH);
 
 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons",
-			    gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)));
+			gtk_toggle_action_get_active(item));
 
 	pidgin_clear_cursor(gtkblist->window);
 }
 
-static void pidgin_blist_show_idle_time_cb(gpointer data, guint action, GtkWidget *item)
+static void pidgin_blist_show_idle_time_cb(GtkToggleAction *item, gpointer data)
 {
 	pidgin_set_cursor(gtkblist->window, GDK_WATCH);
 
 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time",
-			    gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)));
+			gtk_toggle_action_get_active(item));
 
 	pidgin_clear_cursor(gtkblist->window);
 }
 
-static void pidgin_blist_show_protocol_icons_cb(gpointer data, guint action, GtkWidget *item)
+static void pidgin_blist_show_protocol_icons_cb(GtkToggleAction *item, gpointer data)
 {
 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons",
-			      gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)));
-}
-
-static void pidgin_blist_show_empty_groups_cb(gpointer data, guint action, GtkWidget *item)
+			gtk_toggle_action_get_active(item));
+}
+
+static void pidgin_blist_show_empty_groups_cb(GtkToggleAction *item, gpointer data)
 {
 	pidgin_set_cursor(gtkblist->window, GDK_WATCH);
 
 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_empty_groups",
-			gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)));
+			gtk_toggle_action_get_active(item));
 
 	pidgin_clear_cursor(gtkblist->window);
 }
 
-static void pidgin_blist_edit_mode_cb(gpointer callback_data, guint callback_action,
-		GtkWidget *checkitem)
+static void pidgin_blist_edit_mode_cb(GtkToggleAction *checkitem, gpointer data)
 {
 	pidgin_set_cursor(gtkblist->window, GDK_WATCH);
 
 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/show_offline_buddies",
-			gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(checkitem)));
+			gtk_toggle_action_get_active(checkitem));
 
 	pidgin_clear_cursor(gtkblist->window);
 }
 
-static void pidgin_blist_mute_sounds_cb(gpointer data, guint action, GtkWidget *item)
-{
-	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute", GTK_CHECK_MENU_ITEM(item)->active);
-}
+static void pidgin_blist_mute_sounds_cb(GtkToggleAction *item, gpointer data)
+{
+	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute",
+			gtk_toggle_action_get_active(item));
+}
+
 
 static void
 pidgin_blist_mute_pref_cb(const char *name, PurplePrefType type,
 							gconstpointer value, gpointer data)
 {
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item(gtkblist->ift,
-						N_("/Tools/Mute Sounds"))),	(gboolean)GPOINTER_TO_INT(value));
+	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui,
+						"/BList/ToolsMenu/MuteSounds")), (gboolean)GPOINTER_TO_INT(value));
 }
 
 static void
@@ -2081,7 +2094,7 @@
 	if(!strcmp(value, "none"))
 		sensitive = FALSE;
 
-	gtk_widget_set_sensitive(gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Mute Sounds")), sensitive);
+	gtk_action_set_sensitive(gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/MuteSounds"), sensitive);
 }
 
 static void
@@ -2926,6 +2939,7 @@
 pidgin_blist_paint_tip(GtkWidget *widget, gpointer null)
 {
 	GtkStyle *style;
+	cairo_t *cr;
 	int current_height, max_width;
 	int max_text_width;
 	int max_avatar_width;
@@ -2959,6 +2973,7 @@
 	else
 		prpl_col = TOOLTIP_BORDER + status_size + SMALL_SPACE + max_text_width - PRPL_SIZE;
 
+	cr = gdk_cairo_create(GDK_DRAWABLE(gtk_widget_get_window(gtkblist->tipwindow)));
 	current_height = 12;
 	for(l = gtkblist->tooltipdata; l; l = l->next)
 	{
@@ -2978,30 +2993,37 @@
 		}
 
 		if (td->status_icon) {
-			if (dir == GTK_TEXT_DIR_RTL)
-				gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->status_icon,
-				                0, 0, max_width - TOOLTIP_BORDER - status_size, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
-			else
-				gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->status_icon,
-				                0, 0, TOOLTIP_BORDER, current_height, -1 , -1, GDK_RGB_DITHER_NONE, 0, 0);
+			if (dir == GTK_TEXT_DIR_RTL) {
+				gdk_cairo_set_source_pixbuf(cr, td->status_icon,
+				                            max_width - TOOLTIP_BORDER - status_size,
+				                            current_height);
+				cairo_paint(cr);
+			} else {
+				gdk_cairo_set_source_pixbuf(cr, td->status_icon,
+				                            TOOLTIP_BORDER, current_height);
+				cairo_paint(cr);
+			}
 		}
 
 		if(td->avatar) {
-			if (dir == GTK_TEXT_DIR_RTL)
-				gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL,
-						td->avatar, 0, 0, TOOLTIP_BORDER, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
-			else
-				gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL,
-						td->avatar, 0, 0, max_width - (td->avatar_width + TOOLTIP_BORDER),
-						current_height, -1 , -1, GDK_RGB_DITHER_NONE, 0, 0);
-		}
-
-		if (!td->avatar_is_prpl_icon && td->prpl_icon)
-			gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->prpl_icon,
-					0, 0,
-					prpl_col,
-					current_height + ((td->name_height / 2) - (PRPL_SIZE / 2)),
-					-1 , -1, GDK_RGB_DITHER_NONE, 0, 0);
+			if (dir == GTK_TEXT_DIR_RTL) {
+				gdk_cairo_set_source_pixbuf(cr, td->avatar,
+				                            TOOLTIP_BORDER, current_height);
+				cairo_paint(cr);
+			} else {
+				gdk_cairo_set_source_pixbuf(cr, td->avatar,
+				                            max_width - (td->avatar_width + TOOLTIP_BORDER),
+				                            current_height);
+				cairo_paint(cr);
+			}
+		}
+
+		if (!td->avatar_is_prpl_icon && td->prpl_icon) {
+			gdk_cairo_set_source_pixbuf(cr, td->prpl_icon, prpl_col,
+			                            current_height +
+			                               (td->name_height - PRPL_SIZE) / 2);
+			cairo_paint(cr);
+		}
 
 		if (td->name_layout) {
 			if (dir == GTK_TEXT_DIR_RTL) {
@@ -3032,6 +3054,8 @@
 
 		current_height += MAX(td->name_height + td->height, td->avatar_height) + td->padding;
 	}
+
+	cairo_destroy(cr);
 	return FALSE;
 }
 
@@ -3595,64 +3619,121 @@
 /***************************************************
  *            Crap                                 *
  ***************************************************/
-static GtkItemFactoryEntry blist_menu[] =
-{
+/* TODO: fill out tooltips... */
+static const GtkActionEntry blist_menu_entries[] = {
 /* NOTE: Do not set any accelerator to Control+O. It is mapped by
    gtk_blist_key_press_cb to "Get User Info" on the selected buddy. */
-
 	/* Buddies menu */
-	{ N_("/_Buddies"), NULL, NULL, 0, "<Branch>", NULL },
-	{ N_("/Buddies/New Instant _Message..."), "<CTL>M", pidgin_dialogs_im, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW },
-	{ N_("/Buddies/Join a _Chat..."), "<CTL>C", pidgin_blist_joinchat_show, 0, "<StockItem>", PIDGIN_STOCK_CHAT },
-	{ N_("/Buddies/Get User _Info..."), "<CTL>I", pidgin_dialogs_info, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_USER_INFO },
-	{ N_("/Buddies/View User _Log..."), "<CTL>L", pidgin_dialogs_log, 0, "<Item>", NULL },
-	{ "/Buddies/sep1", NULL, NULL, 0, "<Separator>", NULL },
-	{ N_("/Buddies/Sh_ow"), NULL, NULL, 0, "<Branch>", NULL},
-	{ N_("/Buddies/Show/_Offline Buddies"), NULL, pidgin_blist_edit_mode_cb, 1, "<CheckItem>", NULL },
-	{ N_("/Buddies/Show/_Empty Groups"), NULL, pidgin_blist_show_empty_groups_cb, 1, "<CheckItem>", NULL },
-	{ N_("/Buddies/Show/Buddy _Details"), NULL, pidgin_blist_buddy_details_cb, 1, "<CheckItem>", NULL },
-	{ N_("/Buddies/Show/Idle _Times"), NULL, pidgin_blist_show_idle_time_cb, 1, "<CheckItem>", NULL },
-	{ N_("/Buddies/Show/_Protocol Icons"), NULL, pidgin_blist_show_protocol_icons_cb, 1, "<CheckItem>", NULL },
-	{ N_("/Buddies/_Sort Buddies"), NULL, NULL, 0, "<Branch>", NULL },
-	{ "/Buddies/sep2", NULL, NULL, 0, "<Separator>", NULL },
-	{ N_("/Buddies/_Add Buddy..."), "<CTL>B", pidgin_blist_add_buddy_cb, 0, "<StockItem>", GTK_STOCK_ADD },
-	{ N_("/Buddies/Add C_hat..."), NULL, pidgin_blist_add_chat_cb, 0, "<StockItem>", GTK_STOCK_ADD },
-	{ N_("/Buddies/Add _Group..."), NULL, purple_blist_request_add_group, 0, "<StockItem>", GTK_STOCK_ADD },
-	{ "/Buddies/sep3", NULL, NULL, 0, "<Separator>", NULL },
-	{ N_("/Buddies/_Quit"), "<CTL>Q", purple_core_quit, 0, "<StockItem>", GTK_STOCK_QUIT },
+	{ "BuddiesMenu", NULL, N_("_Buddies"), NULL, NULL, NULL },
+	{ "NewInstantMessage", PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW, N_("New Instant _Message..."), "<control>M", NULL, pidgin_dialogs_im },
+	{ "JoinAChat", PIDGIN_STOCK_CHAT, N_("Join a _Chat..."), "<control>C", NULL, pidgin_blist_joinchat_show },
+	{ "GetUserInfo", PIDGIN_STOCK_TOOLBAR_USER_INFO, N_("Get User _Info..."), "<control>I", NULL, pidgin_dialogs_info },
+	{ "ViewUserLog", NULL, N_("View User _Log..."), "<control>L", NULL, pidgin_dialogs_log },
+	{ "ShowMenu", NULL, N_("Sh_ow"), NULL, NULL, NULL },
+	{ "SortMenu", NULL, N_("_Sort Buddies"), NULL, NULL, NULL },
+	{ "AddBuddy", GTK_STOCK_ADD, N_("_Add Buddy..."), "<control>B", NULL, pidgin_blist_add_buddy_cb },
+	{ "AddChat", GTK_STOCK_ADD, N_("Add C_hat..."), NULL, NULL, pidgin_blist_add_chat_cb },
+	{ "AddGroup", GTK_STOCK_ADD, N_("Add _Group..."), NULL, NULL, purple_blist_request_add_group },
+	{ "Quit", GTK_STOCK_QUIT, N_("_Quit"), "<control>Q", NULL, purple_core_quit },
 
 	/* Accounts menu */
-	{ N_("/_Accounts"), NULL, NULL, 0, "<Branch>", NULL },
-	{ N_("/Accounts/Manage Accounts"), "<CTL>A", pidgin_accounts_window_show, 0, "<Item>", NULL },
+	{ "AccountsMenu", NULL, N_("_Accounts"), NULL, NULL, NULL },
+	{ "ManageAccounts", NULL, N_("Manage Accounts"), "<control>A", NULL, pidgin_accounts_window_show },
 
 	/* Tools */
-	{ N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL },
-	{ N_("/Tools/Buddy _Pounces"), NULL, pidgin_pounces_manager_show, 1, "<Item>", NULL },
-	{ N_("/Tools/_Certificates"), NULL, pidgin_certmgr_show, 0, "<Item>", NULL },
-	{ N_("/Tools/Custom Smile_ys"), "<CTL>Y", pidgin_smiley_manager_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SMILEY },
-	{ N_("/Tools/Plu_gins"), "<CTL>U", pidgin_plugin_dialog_show, 2, "<StockItem>", PIDGIN_STOCK_TOOLBAR_PLUGINS },
-	{ N_("/Tools/Pr_eferences"), "<CTL>P", pidgin_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES },
-	{ N_("/Tools/Pr_ivacy"), NULL, pidgin_privacy_dialog_show, 0, "<Item>", NULL },
-	{ N_("/Tools/Set _Mood"), "<CTL>D", set_mood_show, 0, "<Item>", NULL },
-	{ "/Tools/sep2", NULL, NULL, 0, "<Separator>", NULL },
-	{ N_("/Tools/_File Transfers"), "<CTL>T", pidgin_xfer_dialog_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_TRANSFER },
-	{ N_("/Tools/R_oom List"), NULL, pidgin_roomlist_dialog_show, 0, "<Item>", NULL },
-	{ N_("/Tools/System _Log"), NULL, gtk_blist_show_systemlog_cb, 3, "<Item>", NULL },
-	{ "/Tools/sep3", NULL, NULL, 0, "<Separator>", NULL },
-	{ N_("/Tools/Mute _Sounds"), NULL, pidgin_blist_mute_sounds_cb, 0, "<CheckItem>", NULL },
+	{ "ToolsMenu", NULL, N_("_Tools"), NULL, NULL, NULL },
+	{ "BuddyPounces", NULL, N_("Buddy _Pounces"), NULL, NULL, pidgin_pounces_manager_show },
+	{ "Certificates", NULL, N_("_Certificates"), NULL, NULL, pidgin_certmgr_show },
+	{ "CustomSmileys", PIDGIN_STOCK_TOOLBAR_SMILEY, N_("Custom Smile_ys"), "<control>Y", NULL, pidgin_smiley_manager_show },
+	{ "Plugins", PIDGIN_STOCK_TOOLBAR_PLUGINS, N_("Plu_gins"), "<control>U", NULL, pidgin_plugin_dialog_show },
+	{ "Preferences", GTK_STOCK_PREFERENCES, N_("Pr_eferences"), "<control>P", NULL, pidgin_prefs_show },
+	{ "Privacy", NULL, N_("Pr_ivacy"), NULL, NULL, pidgin_privacy_dialog_show },
+	{ "SetMood", NULL, N_("Set _Mood"), "<control>D", NULL, set_mood_show },
+	{ "FileTransfers", PIDGIN_STOCK_TOOLBAR_TRANSFER, N_("_File Transfers"), "<control>T", NULL, G_CALLBACK(gtk_blist_show_xfer_dialog_cb) },
+	{ "RoomList", NULL, N_("R_oom List"), NULL, NULL, pidgin_roomlist_dialog_show },
+	{ "SystemLog", NULL, N_("System _Log"), NULL, NULL, gtk_blist_show_systemlog_cb },
+
 	/* Help */
-	{ N_("/_Help"), NULL, NULL, 0, "<Branch>", NULL },
-	{ N_("/Help/Online _Help"), "F1", gtk_blist_show_onlinehelp_cb, 0, "<StockItem>", GTK_STOCK_HELP },
-	{ "/Help/sep1", NULL, NULL, 0, "<Separator>", NULL },
-	{ N_("/Help/_Build Information"), NULL, pidgin_dialogs_buildinfo, 0, "<Item>", NULL },
-	{ N_("/Help/_Debug Window"), NULL, toggle_debug, 0, "<Item>", NULL },
-	{ N_("/Help/De_veloper Information"), NULL, pidgin_dialogs_developers, 0, "<Item>", NULL },
-	{ N_("/Help/_Plugin Information"), NULL, pidgin_dialogs_plugins_info, 0, "<Item>", NULL },
-	{ N_("/Help/_Translator Information"), NULL, pidgin_dialogs_translators, 0, "<Item>", NULL },
-	{ "/Help/sep2", NULL, NULL, 0, "<Separator>", NULL },
-	{ N_("/Help/_About"), NULL, pidgin_dialogs_about, 4,  "<StockItem>", GTK_STOCK_ABOUT },
+	{ "HelpMenu", NULL, N_("_Help"), NULL, NULL, NULL },
+	{ "OnlineHelp", GTK_STOCK_HELP, N_("Online _Help"), "F1", NULL, gtk_blist_show_onlinehelp_cb },
+	{ "BuildInformation", NULL, N_("_Build Information"), NULL, NULL, pidgin_dialogs_buildinfo },
+	{ "DebugWindow", NULL, N_("_Debug Window"), NULL, NULL, toggle_debug },
+	{ "DeveloperInformation", NULL, N_("De_veloper Information"), NULL, NULL, pidgin_dialogs_developers },
+	{ "PluginInformation", NULL, N_("_Plugin Information"), NULL, NULL, pidgin_dialogs_plugins_info },
+	{ "TranslatorInformation", NULL, N_("_Translator Information"), NULL, NULL, pidgin_dialogs_translators },
+	{ "About", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL, pidgin_dialogs_about },
+};
+
+/* Toggle items */
+static const GtkToggleActionEntry blist_menu_toggle_entries[] = {
+	/* Buddies->Show menu */
+	{ "ShowOffline", NULL, N_("_Offline Buddies"), NULL, NULL, G_CALLBACK(pidgin_blist_edit_mode_cb), FALSE },
+	{ "ShowEmptyGroups", NULL, N_("_Empty Groups"), NULL, NULL, G_CALLBACK(pidgin_blist_show_empty_groups_cb), FALSE },
+	{ "ShowBuddyDetails", NULL, N_("Buddy _Details"), NULL, NULL, G_CALLBACK(pidgin_blist_buddy_details_cb), FALSE },
+	{ "ShowIdleTimes", NULL, N_("Idle _Times"), NULL, NULL, G_CALLBACK(pidgin_blist_show_idle_time_cb), FALSE },
+	{ "ShowProtocolIcons", NULL, N_("_Protocol Icons"), NULL, NULL, G_CALLBACK(pidgin_blist_show_protocol_icons_cb), FALSE },
+
+	/* Tools menu */
+	{ "MuteSounds", NULL, N_("Mute _Sounds"), NULL, NULL, G_CALLBACK(pidgin_blist_mute_sounds_cb), FALSE },
 };
 
+static const char *blist_menu =
+"<ui>"
+	"<menubar name='BList'>"
+		"<menu action='BuddiesMenu'>"
+			"<menuitem action='NewInstantMessage'/>"
+			"<menuitem action='JoinAChat'/>"
+			"<menuitem action='GetUserInfo'/>"
+			"<menuitem action='ViewUserLog'/>"
+			"<separator/>"
+			"<menu action='ShowMenu'>"
+				"<menuitem action='ShowOffline'/>"
+				"<menuitem action='ShowEmptyGroups'/>"
+				"<menuitem action='ShowBuddyDetails'/>"
+				"<menuitem action='ShowIdleTimes'/>"
+				"<menuitem action='ShowProtocolIcons'/>"
+			"</menu>"
+			"<menu action='SortMenu'/>"
+			"<separator/>"
+			"<menuitem action='AddBuddy'/>"
+			"<menuitem action='AddChat'/>"
+			"<menuitem action='AddGroup'/>"
+			"<separator/>"
+			"<menuitem action='Quit'/>"
+		"</menu>"
+		"<menu action='AccountsMenu'>"
+			"<menuitem action='ManageAccounts'/>"
+		"</menu>"
+		"<menu action='ToolsMenu'>"
+			"<menuitem action='BuddyPounces'/>"
+			"<menuitem action='Certificates'/>"
+			"<menuitem action='CustomSmileys'/>"
+			"<menuitem action='Plugins'/>"
+			"<menuitem action='Preferences'/>"
+			"<menuitem action='Privacy'/>"
+			"<menuitem action='SetMood'/>"
+			"<separator/>"
+			"<menuitem action='FileTransfers'/>"
+			"<menuitem action='RoomList'/>"
+			"<menuitem action='SystemLog'/>"
+			"<separator/>"
+			"<menuitem action='MuteSounds'/>"
+			"<placeholder name='PluginActions'/>"
+		"</menu>"
+		"<menu action='HelpMenu'>"
+			"<menuitem action='OnlineHelp'/>"
+			"<separator/>"
+			"<menuitem action='BuildInformation'/>"
+			"<menuitem action='DebugWindow'/>"
+			"<menuitem action='DeveloperInformation'/>"
+			"<menuitem action='PluginInformation'/>"
+			"<menuitem action='TranslatorInformation'/>"
+			"<separator/>"
+			"<menuitem action='About'/>"
+		"</menu>"
+	"</menubar>"
+"</ui>";
+
 /*********************************************************
  * Private Utility functions                             *
  *********************************************************/
@@ -4386,7 +4467,7 @@
 	/* if the window exists, is hidden, we're saving positions, and the
 	 * position is sane... */
 	if (gtkblist && gtkblist->window &&
-		!GTK_WIDGET_VISIBLE(gtkblist->window) && blist_width != 0) {
+		!gtk_widget_get_visible(gtkblist->window) && blist_width != 0) {
 
 		blist_x      = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/x");
 		blist_y      = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/y");
@@ -4416,7 +4497,7 @@
 	PurpleBlistNode *gnode, *cnode;
 
 	if (gtk_blist_visibility == GDK_VISIBILITY_FULLY_OBSCURED
-			|| !GTK_WIDGET_VISIBLE(gtkblist->window))
+			|| !gtk_widget_get_visible(gtkblist->window))
 		return TRUE;
 
 	for(gnode = list->root; gnode; gnode = gnode->next) {
@@ -4462,12 +4543,13 @@
 
 static const char *require_connection[] =
 {
-	N_("/Buddies/New Instant Message..."),
-	N_("/Buddies/Join a Chat..."),
-	N_("/Buddies/Get User Info..."),
-	N_("/Buddies/Add Buddy..."),
-	N_("/Buddies/Add Chat..."),
-	N_("/Buddies/Add Group..."),
+	"/BList/BuddiesMenu/NewInstantMessage",
+	"/BList/BuddiesMenu/JoinAChat",
+	"/BList/BuddiesMenu/GetUserInfo",
+	"/BList/BuddiesMenu/AddBuddy",
+	"/BList/BuddiesMenu/AddChat",
+	"/BList/BuddiesMenu/AddGroup",
+	"/BList/ToolsMenu/Privacy",
 };
 
 static const int require_connection_size = sizeof(require_connection)
@@ -4480,7 +4562,7 @@
 static void
 update_menu_bar(PidginBuddyList *gtkblist)
 {
-	GtkWidget *widget;
+	GtkAction *action;
 	gboolean sensitive;
 	int i;
 
@@ -4492,21 +4574,18 @@
 
 	for (i = 0; i < require_connection_size; i++)
 	{
-		widget = gtk_item_factory_get_widget(gtkblist->ift, require_connection[i]);
-		gtk_widget_set_sensitive(widget, sensitive);
-	}
-
-	widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Buddies/Join a Chat..."));
-	gtk_widget_set_sensitive(widget, pidgin_blist_joinchat_is_showable());
-
-	widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Buddies/Add Chat..."));
-	gtk_widget_set_sensitive(widget, pidgin_blist_joinchat_is_showable());
-
-	widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Privacy"));
-	gtk_widget_set_sensitive(widget, sensitive);
-
-	widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Room List"));
-	gtk_widget_set_sensitive(widget, pidgin_roomlist_is_showable());
+		action = gtk_ui_manager_get_action(gtkblist->ui, require_connection[i]);
+		gtk_action_set_sensitive(action, sensitive);
+	}
+
+	action = gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/JoinAChat");
+	gtk_action_set_sensitive(action, pidgin_blist_joinchat_is_showable());
+
+	action = gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/AddChat");
+	gtk_action_set_sensitive(action, pidgin_blist_joinchat_is_showable());
+
+	action = gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/RoomList");
+	gtk_action_set_sensitive(action, pidgin_roomlist_is_showable());
 }
 
 static void
@@ -4798,12 +4877,6 @@
 	NUM_TARGETS
 };
 
-static const char *
-item_factory_translate_func (const char *path, gpointer func_data)
-{
-	return _((char *)path);
-}
-
 void pidgin_blist_setup_sort_methods()
 {
 	const char *id;
@@ -5453,8 +5526,28 @@
 headline_style_set (GtkWidget *widget,
 		    GtkStyle  *prev_style)
 {
+	GtkStyle *style;
+#if GTK_CHECK_VERSION(2,12,0)
+	GtkWidget *window;
+
+	if (gtkblist->changing_style)
+		return;
+
+	/* This is a hack needed to use the tooltip background colour */
+	window = gtk_window_new(GTK_WINDOW_POPUP);
+	gtk_widget_set_name(window, "gtk-tooltip");
+	gtk_widget_ensure_style(window);
+	style = gtk_widget_get_style(window);
+
+	gtkblist->changing_style = TRUE;
+	gtk_widget_set_style(gtkblist->headline_hbox, style);
+	gtkblist->changing_style = FALSE;
+
+	gtk_widget_destroy(window);
+
+	gtk_widget_queue_draw(gtkblist->headline_hbox);
+#else
 	GtkTooltips *tooltips;
-	GtkStyle *style;
 
 	if (gtkblist->changing_style)
 		return;
@@ -5463,9 +5556,6 @@
 	g_object_ref_sink (tooltips);
 
 	gtk_tooltips_force_window (tooltips);
-#if GTK_CHECK_VERSION(2, 12, 0)
-	gtk_widget_set_name (tooltips->tip_window, "gtk-tooltips");
-#endif
 	gtk_widget_ensure_style (tooltips->tip_window);
 	style = gtk_widget_get_style (tooltips->tip_window);
 
@@ -5474,6 +5564,7 @@
 	gtkblist->changing_style = FALSE;
 
 	g_object_unref (tooltips);
+#endif
 }
 
 /******************************************/
@@ -5710,6 +5801,8 @@
 	GtkWidget *close;
 	char *pretty, *tmp;
 	const char *theme_name;
+	GtkActionGroup *action_group;
+	GError *error;
 	GtkAccelGroup *accel_group;
 	GtkTreeSelection *selection;
 	GtkTargetEntry dte[] = {{"PURPLE_BLIST_NODE", GTK_TARGET_SAME_APP, DRAG_ROW},
@@ -5759,27 +5852,45 @@
 	gtk_widget_add_events(gtkblist->window, GDK_VISIBILITY_NOTIFY_MASK);
 
 	/******************************* Menu bar *************************************/
-	accel_group = gtk_accel_group_new();
-	gtk_window_add_accel_group(GTK_WINDOW (gtkblist->window), accel_group);
-	g_object_unref(accel_group);
-	gtkblist->ift = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<PurpleMain>", accel_group);
-	gtk_item_factory_set_translate_func(gtkblist->ift,
-										(GtkTranslateFunc)item_factory_translate_func,
-										NULL, NULL);
-	gtk_item_factory_create_items(gtkblist->ift, sizeof(blist_menu) / sizeof(*blist_menu),
-								  blist_menu, NULL);
+	action_group = gtk_action_group_new("BListActions");
+	gtk_action_group_add_actions(action_group,
+	                             blist_menu_entries,
+	                             G_N_ELEMENTS(blist_menu_entries),
+	                             GTK_WINDOW(gtkblist->window));
+	gtk_action_group_add_toggle_actions(action_group,
+	                                    blist_menu_toggle_entries,
+	                                    G_N_ELEMENTS(blist_menu_toggle_entries),
+	                                    GTK_WINDOW(gtkblist->window));
+#ifdef ENABLE_NLS
+	gtk_action_group_set_translation_domain(action_group,
+	                                        PACKAGE);
+#endif
+
+	gtkblist->ui = gtk_ui_manager_new();
+	gtk_ui_manager_insert_action_group(gtkblist->ui, action_group, 0);
+
+	accel_group = gtk_ui_manager_get_accel_group(gtkblist->ui);
+	gtk_window_add_accel_group(GTK_WINDOW(gtkblist->window), accel_group);
 	pidgin_load_accels();
 	g_signal_connect(G_OBJECT(accel_group), "accel-changed", G_CALLBACK(pidgin_save_accels_cb), NULL);
 
-	menu = gtk_item_factory_get_widget(gtkblist->ift, "<PurpleMain>");
+	error = NULL;
+	if (!gtk_ui_manager_add_ui_from_string(gtkblist->ui, blist_menu, -1, &error))
+	{
+		g_message("building menus failed: %s", error->message);
+		g_error_free(error);
+		exit(EXIT_FAILURE);
+	}
+
+	menu = gtk_ui_manager_get_widget(gtkblist->ui, "/BList");
 	gtkblist->menutray = pidgin_menu_tray_new();
 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtkblist->menutray);
 	gtk_widget_show(gtkblist->menutray);
 	gtk_widget_show(menu);
 	gtk_box_pack_start(GTK_BOX(gtkblist->main_vbox), menu, FALSE, FALSE, 0);
 
-	accountmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Accounts"));
-
+	menu = gtk_ui_manager_get_widget(gtkblist->ui, "/BList/AccountsMenu");
+	accountmenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu));
 
 	/****************************** Notebook *************************************/
 	gtkblist->notebook = gtk_notebook_new();
@@ -5967,26 +6078,26 @@
 	/* set the Show Offline Buddies option. must be done
 	 * after the treeview or faceprint gets mad. -Robot101
 	 */
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show/Offline Buddies"))),
+	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowOffline")),
 			purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_offline_buddies"));
 
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show/Empty Groups"))),
+	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowEmptyGroups")),
 			purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_empty_groups"));
 
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Tools/Mute Sounds"))),
+	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/MuteSounds")),
 			purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/sound/mute"));
 
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show/Buddy Details"))),
+	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowBuddyDetails")),
 			purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"));
 
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show/Idle Times"))),
+	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowIdleTimes")),
 			purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_idle_time"));
 
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item (gtkblist->ift, N_("/Buddies/Show/Protocol Icons"))),
+	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_ui_manager_get_action(gtkblist->ui, "/BList/BuddiesMenu/ShowMenu/ShowProtocolIcons")),
 			purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"));
 
 	if(!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method"), "none"))
-		gtk_widget_set_sensitive(gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Mute Sounds")), FALSE);
+		gtk_action_set_sensitive(gtk_ui_manager_get_action(gtkblist->ui, "/BList/ToolsMenu/MuteSounds"), FALSE);
 
 	/* Update some dynamic things */
 	update_menu_bar(gtkblist);
@@ -6843,7 +6954,7 @@
 	purple_signals_disconnect_by_handle(gtkblist);
 
 	if (gtkblist->headline_close)
-		gdk_pixbuf_unref(gtkblist->headline_close);
+		g_object_unref(G_OBJECT(gtkblist->headline_close));
 
 	gtk_widget_destroy(gtkblist->window);
 
@@ -6862,7 +6973,7 @@
 	gtkblist->window = gtkblist->vbox = gtkblist->treeview = NULL;
 	g_object_unref(G_OBJECT(gtkblist->treemodel));
 	gtkblist->treemodel = NULL;
-	g_object_unref(G_OBJECT(gtkblist->ift));
+	g_object_unref(G_OBJECT(gtkblist->ui));
 	g_object_unref(G_OBJECT(gtkblist->empty_avatar));
 
 	gdk_cursor_unref(gtkblist->hand_cursor);
@@ -6887,7 +6998,7 @@
 		return;
 
 	if (show) {
-		if(!PIDGIN_WINDOW_ICONIFIED(gtkblist->window) && !GTK_WIDGET_VISIBLE(gtkblist->window))
+		if(!PIDGIN_WINDOW_ICONIFIED(gtkblist->window) && !gtk_widget_get_visible(gtkblist->window))
 			purple_signal_emit(pidgin_blist_get_handle(), "gtkblist-unhiding", gtkblist);
 		pidgin_blist_restore_position();
 		gtk_window_present(GTK_WINDOW(gtkblist->window));
@@ -6896,7 +7007,7 @@
 			purple_signal_emit(pidgin_blist_get_handle(), "gtkblist-hiding", gtkblist);
 			gtk_widget_hide(gtkblist->window);
 		} else {
-			if (!GTK_WIDGET_VISIBLE(gtkblist->window))
+			if (!gtk_widget_get_visible(gtkblist->window))
 				gtk_widget_show(gtkblist->window);
 			gtk_window_iconify(GTK_WINDOW(gtkblist->window));
 		}
@@ -7302,7 +7413,7 @@
 pidgin_blist_toggle_visibility()
 {
 	if (gtkblist && gtkblist->window) {
-		if (GTK_WIDGET_VISIBLE(gtkblist->window)) {
+		if (gtk_widget_get_visible(gtkblist->window)) {
 			/* make the buddy list visible if it is iconified or if it is
 			 * obscured and not currently focused (the focus part ensures
 			 * that we do something reasonable if the buddy list is obscured
@@ -7367,7 +7478,7 @@
 static void
 set_urgent(void)
 {
-	if (gtkblist->window && !GTK_WIDGET_HAS_FOCUS(gtkblist->window))
+	if (gtkblist->window && !gtk_widget_has_focus(gtkblist->window))
 		pidgin_set_urgent(GTK_WINDOW(gtkblist->window), TRUE);
 }
 
@@ -7902,40 +8013,43 @@
 }
 
 static void
-build_plugin_actions(GtkWidget *menu, PurplePlugin *plugin,
-		gpointer context)
-{
-	GtkWidget *menuitem;
+build_plugin_actions(GtkActionGroup *action_group, GString *ui, char *parent,
+		PurplePlugin *plugin, gpointer context)
+{
+	GtkAction *menuaction;
 	PurplePluginAction *action = NULL;
 	GList *actions, *l;
+	char *name;
+	int count = 0;
 
 	actions = PURPLE_PLUGIN_ACTIONS(plugin, context);
 
-	for (l = actions; l != NULL; l = l->next)
-	{
-		if (l->data)
-		{
-			action = (PurplePluginAction *) l->data;
+	for (l = actions; l != NULL; l = l->next) {
+		if (l->data) {
+			action = (PurplePluginAction *)l->data;
 			action->plugin = plugin;
 			action->context = context;
 
-			menuitem = gtk_menu_item_new_with_label(action->label);
-			gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-
-			g_signal_connect(G_OBJECT(menuitem), "activate",
+			name = g_strdup_printf("%s-action-%d", parent, count++);
+			menuaction = gtk_action_new(name, action->label, NULL, NULL);
+			gtk_action_group_add_action(action_group, menuaction);
+			g_string_append_printf(ui, "<menuitem action='%s'/>", name);
+
+			g_signal_connect(G_OBJECT(menuaction), "activate",
 					G_CALLBACK(plugin_act), action);
-			g_object_set_data_full(G_OBJECT(menuitem), "plugin_action",
+			g_object_set_data_full(G_OBJECT(menuaction), "plugin_action",
 								   action,
 								   (GDestroyNotify)purple_plugin_action_free);
-			gtk_widget_show(menuitem);
+			g_free(name);
 		}
 		else
-			pidgin_separator(menu);
+			g_string_append(ui, "<separator/>");
 	}
 
 	g_list_free(actions);
 }
 
+
 static void
 modify_account_cb(GtkWidget *widget, gpointer data)
 {
@@ -7962,14 +8076,12 @@
 	purple_account_set_enabled(account, PIDGIN_UI, FALSE);
 }
 
-
-
 void
 pidgin_blist_update_accounts_menu(void)
 {
-	GtkWidget *menuitem = NULL, *submenu = NULL;
-	GtkAccelGroup *accel_group = NULL;
-	GList *l = NULL, *accounts = NULL;
+	GtkWidget *menuitem, *submenu;
+	GtkAccelGroup *accel_group;
+	GList *l, *accounts;
 	gboolean disabled_accounts = FALSE;
 	gboolean enabled_accounts = FALSE;
 
@@ -7980,10 +8092,12 @@
 	for (l = gtk_container_get_children(GTK_CONTAINER(accountmenu)); l; l = g_list_delete_link(l, l)) {
 		menuitem = l->data;
 
-		if (menuitem != gtk_item_factory_get_widget(gtkblist->ift, N_("/Accounts/Manage Accounts")))
+		if (menuitem != gtk_ui_manager_get_widget(gtkblist->ui, "/BList/AccountsMenu/ManageAccounts"))
 			gtk_widget_destroy(menuitem);
 	}
 
+	accel_group = gtk_menu_get_accel_group(GTK_MENU(accountmenu));
+
 	for (accounts = purple_accounts_get_all(); accounts; accounts = accounts->next) {
 		char *buf = NULL;
 		GtkWidget *image = NULL;
@@ -7992,14 +8106,14 @@
 
 		account = accounts->data;
 
-		if(!purple_account_get_enabled(account, PIDGIN_UI)) {
+		if (!purple_account_get_enabled(account, PIDGIN_UI)) {
 			if (!disabled_accounts) {
 				menuitem = gtk_menu_item_new_with_label(_("Enable Account"));
 				gtk_menu_shell_append(GTK_MENU_SHELL(accountmenu), menuitem);
 
 				submenu = gtk_menu_new();
 				gtk_menu_set_accel_group(GTK_MENU(submenu), accel_group);
-				gtk_menu_set_accel_path(GTK_MENU(submenu), N_("<PurpleMain>/Accounts/Enable Account"));
+				gtk_menu_set_accel_path(GTK_MENU(submenu), "<Actions>/BListActions/EnableAccount");
 				gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
 
 				disabled_accounts = TRUE;
@@ -8009,9 +8123,9 @@
 				purple_account_get_protocol_name(account), ")", NULL);
 			menuitem = gtk_image_menu_item_new_with_label(buf);
 			g_free(buf);
+
 			pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
-			if (pixbuf != NULL)
-			{
+			if (pixbuf != NULL) {
 				if (!purple_account_is_connected(account))
 					gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE);
 				image = gtk_image_new_from_pixbuf(pixbuf);
@@ -8019,9 +8133,11 @@
 				gtk_widget_show(image);
 				gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
 			}
+
 			g_signal_connect(G_OBJECT(menuitem), "activate",
 				G_CALLBACK(enable_account_cb), account);
 			gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
+
 		} else {
 			enabled_accounts = TRUE;
 		}
@@ -8033,7 +8149,6 @@
 	}
 
 	pidgin_separator(accountmenu);
-	accel_group = gtk_menu_get_accel_group(GTK_MENU(accountmenu));
 
 	for (accounts = purple_accounts_get_all(); accounts; accounts = accounts->next) {
 		char *buf = NULL;
@@ -8053,8 +8168,9 @@
 		buf = g_strconcat(purple_account_get_username(account), " (",
 				purple_account_get_protocol_name(account), ")", NULL);
 		menuitem = gtk_image_menu_item_new_with_label(buf);
-		accel_path_buf = g_strconcat(N_("<PurpleMain>/Accounts/"), buf, NULL);
+		accel_path_buf = g_strconcat("<Actions>/AccountActions/", buf, NULL);
 		g_free(buf);
+
 		pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
 		if (pixbuf != NULL) {
 			if (!purple_account_is_connected(account))
@@ -8065,6 +8181,7 @@
 			gtk_widget_show(image);
 			gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
 		}
+
 		gtk_menu_shell_append(GTK_MENU_SHELL(accountmenu), menuitem);
 
 		submenu = gtk_menu_new();
@@ -8073,7 +8190,6 @@
 		g_free(accel_path_buf);
 		gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
 
-
 		menuitem = gtk_menu_item_new_with_mnemonic(_("_Edit Account"));
 		g_signal_connect(G_OBJECT(menuitem), "activate",
 				G_CALLBACK(modify_account_cb), account);
@@ -8098,8 +8214,37 @@
 					gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
 				}
 			}
+
 			if (PURPLE_PLUGIN_HAS_ACTIONS(plugin)) {
-				build_plugin_actions(submenu, plugin, gc);
+				GtkWidget *menuitem;
+				PurplePluginAction *action = NULL;
+				GList *actions, *l;
+
+				actions = PURPLE_PLUGIN_ACTIONS(plugin, gc);
+
+				for (l = actions; l != NULL; l = l->next)
+				{
+					if (l->data)
+					{
+						action = (PurplePluginAction *) l->data;
+						action->plugin = plugin;
+						action->context = gc;
+
+						menuitem = gtk_menu_item_new_with_label(action->label);
+						gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
+
+						g_signal_connect(G_OBJECT(menuitem), "activate",
+								G_CALLBACK(plugin_act), action);
+						g_object_set_data_full(G_OBJECT(menuitem), "plugin_action",
+											   action,
+											   (GDestroyNotify)purple_plugin_action_free);
+						gtk_widget_show(menuitem);
+					}
+					else
+						pidgin_separator(submenu);
+				}
+
+				g_list_free(actions);
 			}
 		} else {
 			menuitem = gtk_menu_item_new_with_label(_("No actions available"));
@@ -8114,36 +8259,45 @@
 				G_CALLBACK(disable_account_cb), account);
 		gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
 	}
+
 	gtk_widget_show_all(accountmenu);
 }
 
-static GList *plugin_submenus = NULL;
+static guint plugins_merge_id;
+static GtkActionGroup *plugins_action_group = NULL;
 
 void
 pidgin_blist_update_plugin_actions(void)
 {
-	GtkWidget *menuitem, *submenu;
 	PurplePlugin *plugin = NULL;
 	GList *l;
-	GtkAccelGroup *accel_group;
-
-	GtkWidget *pluginmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools"));
-
-	g_return_if_fail(pluginmenu != NULL);
-
-	/* Remove old plugin action submenus from the Tools menu */
-	for (l = plugin_submenus; l; l = l->next)
-		gtk_widget_destroy(GTK_WIDGET(l->data));
-	g_list_free(plugin_submenus);
-	plugin_submenus = NULL;
-
-	accel_group = gtk_menu_get_accel_group(GTK_MENU(pluginmenu));
+
+	GtkAction *action;
+	GString *plugins_ui;
+	gchar *ui_string;
+	int count = 0;
+
+	if ((gtkblist == NULL) || (gtkblist->ui == NULL))
+		return;
+
+	/* Clear the old menu */
+	if (plugins_action_group) {
+		gtk_ui_manager_remove_ui(gtkblist->ui, plugins_merge_id);
+		gtk_ui_manager_remove_action_group(gtkblist->ui, plugins_action_group);
+		g_object_unref(G_OBJECT(plugins_action_group));
+	}
+
+	plugins_action_group = gtk_action_group_new("PluginActions");
+#ifdef ENABLE_NLS
+	gtk_action_group_set_translation_domain(plugins_action_group, PACKAGE);
+#endif
+	plugins_ui = g_string_new(NULL);
 
 	/* Add a submenu for each plugin with custom actions */
 	for (l = purple_plugins_get_loaded(); l; l = l->next) {
-		char *path;
-
-		plugin = (PurplePlugin *) l->data;
+		char *name;
+
+		plugin = (PurplePlugin *)l->data;
 
 		if (PURPLE_IS_PROTOCOL_PLUGIN(plugin))
 			continue;
@@ -8151,28 +8305,34 @@
 		if (!PURPLE_PLUGIN_HAS_ACTIONS(plugin))
 			continue;
 
-		menuitem = gtk_image_menu_item_new_with_label(_(plugin->info->name));
-		gtk_menu_shell_append(GTK_MENU_SHELL(pluginmenu), menuitem);
-
-		plugin_submenus = g_list_append(plugin_submenus, menuitem);
-
-		submenu = gtk_menu_new();
-		gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
-
-		gtk_menu_set_accel_group(GTK_MENU(submenu), accel_group);
-		path = g_strdup_printf("%s/Tools/%s", gtkblist->ift->path, plugin->info->name);
-		gtk_menu_set_accel_path(GTK_MENU(submenu), path);
-		g_free(path);
-
-		build_plugin_actions(submenu, plugin, NULL);
-	}
-	gtk_widget_show_all(pluginmenu);
+		name = g_strdup_printf("plugin%d", count);
+		action = gtk_action_new(name, plugin->info->name, NULL, NULL);
+		gtk_action_group_add_action(plugins_action_group, action);
+		g_string_append_printf(plugins_ui, "<menu action='%s'>", name);
+
+		build_plugin_actions(plugins_action_group, plugins_ui, name, plugin, NULL);
+
+		g_string_append(plugins_ui, "</menu>");
+		count++;
+
+		g_free(name);
+	}
+
+	ui_string = g_strconcat("<ui><menubar action='BList'><menu action='ToolsMenu'><placeholder name='PluginActions'>",
+	                        plugins_ui->str,
+	                        "</placeholder></menu></menubar></ui>",
+	                        NULL);
+	gtk_ui_manager_insert_action_group(gtkblist->ui, plugins_action_group, 1);
+	plugins_merge_id = gtk_ui_manager_add_ui_from_string(gtkblist->ui, ui_string, -1, NULL);
+
+	g_string_free(plugins_ui, TRUE);
+	g_free(ui_string);
 }
 
 static void
-sortmethod_act(GtkCheckMenuItem *checkmenuitem, char *id)
-{
-	if (gtk_check_menu_item_get_active(checkmenuitem))
+sortmethod_act(GtkRadioAction *action, GtkRadioAction *current, char *id)
+{
+	if (action == current)
 	{
 		pidgin_set_cursor(gtkblist->window, GDK_WATCH);
 		/* This is redundant. I think. */
@@ -8186,40 +8346,58 @@
 void
 pidgin_blist_update_sort_methods(void)
 {
-	GtkWidget *menuitem = NULL, *activeitem = NULL;
 	PidginBlistSortMethod *method = NULL;
 	GList *l;
 	GSList *sl = NULL;
-	GtkWidget *sortmenu;
 	const char *m = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/sort_type");
 
-	if ((gtkblist == NULL) || (gtkblist->ift == NULL))
-		return;
-
-	g_return_if_fail(m != NULL);
-
-	sortmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Buddies/Sort Buddies"));
-
-	if (sortmenu == NULL)
+	GtkRadioAction *action;
+	GString *ui_string;
+
+	if ((gtkblist == NULL) || (gtkblist->ui == NULL))
 		return;
 
 	/* Clear the old menu */
-	for (l = gtk_container_get_children(GTK_CONTAINER(sortmenu)); l; l = g_list_delete_link(l, l)) {
-		menuitem = l->data;
-		gtk_widget_destroy(GTK_WIDGET(menuitem));
-	}
+	if (sort_action_group) {
+		gtk_ui_manager_remove_ui(gtkblist->ui, sort_merge_id);
+		gtk_ui_manager_remove_action_group(gtkblist->ui, sort_action_group);
+		g_object_unref(G_OBJECT(sort_action_group));
+	}
+
+	sort_action_group = gtk_action_group_new("SortMethods");
+#ifdef ENABLE_NLS
+	gtk_action_group_set_translation_domain(sort_action_group, PACKAGE);
+#endif
+	ui_string = g_string_new("<ui><menubar name='BList'>"
+	                         "<menu action='BuddiesMenu'><menu action='SortMenu'>");
 
 	for (l = pidgin_blist_sort_methods; l; l = l->next) {
-		method = (PidginBlistSortMethod *) l->data;
-		menuitem = gtk_radio_menu_item_new_with_label(sl, _(method->name));
-		if (g_str_equal(m, method->id))
-			activeitem = menuitem;
-		sl = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menuitem));
-		gtk_menu_shell_append(GTK_MENU_SHELL(sortmenu), menuitem);
-		g_signal_connect(G_OBJECT(menuitem), "toggled",
-				 G_CALLBACK(sortmethod_act), method->id);
-		gtk_widget_show(menuitem);
-	}
-	if (activeitem)
-		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(activeitem), TRUE);
-}
+		method = (PidginBlistSortMethod *)l->data;
+
+		g_string_append_printf(ui_string, "<menuitem action='%s'/>", method->id);
+		action = gtk_radio_action_new(method->id,
+		                              method->name,
+		                              NULL,
+		                              NULL,
+		                              0);
+		gtk_action_group_add_action_with_accel(sort_action_group, GTK_ACTION(action), NULL);
+
+		gtk_radio_action_set_group(action, sl);
+		sl = gtk_radio_action_get_group(action);
+
+		if (!strcmp(m, method->id))
+			gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+		else
+			gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), FALSE);
+
+		g_signal_connect(G_OBJECT(action), "changed",
+		                 G_CALLBACK(sortmethod_act), method->id);
+	}
+
+	g_string_append(ui_string, "</menu></menu></menubar></ui>");
+	gtk_ui_manager_insert_action_group(gtkblist->ui, sort_action_group, 1);
+	sort_merge_id = gtk_ui_manager_add_ui_from_string(gtkblist->ui, ui_string->str, -1, NULL);
+
+	g_string_free(ui_string, TRUE);
+}
+
--- a/pidgin/gtkblist.h	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkblist.h	Mon Feb 27 22:45:47 2012 +0000
@@ -82,7 +82,7 @@
 
 	GtkCellRenderer *text_rend;
 
-	GtkItemFactory *ift;
+	GtkUIManager *ui;
 	GtkWidget *menutray;            /**< The menu tray widget. */
 	GtkWidget *menutrayicon;        /**< The menu tray icon. */
 
--- a/pidgin/gtkcellrendererexpander.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkcellrendererexpander.c	Mon Feb 27 22:45:47 2012 +0000
@@ -250,8 +250,13 @@
 		state = GTK_STATE_INSENSITIVE;
 	else if (flags & GTK_CELL_RENDERER_PRELIT)
 		state = GTK_STATE_PRELIGHT;
+#if GTK_CHECK_VERSION(2,18,0)
+	else if (gtk_widget_has_focus (widget) && flags & GTK_CELL_RENDERER_SELECTED)
+		state = GTK_STATE_ACTIVE;
+#else
 	else if (GTK_WIDGET_HAS_FOCUS (widget) && flags & GTK_CELL_RENDERER_SELECTED)
 		state = GTK_STATE_ACTIVE;
+#endif
 	else
 		state = GTK_STATE_NORMAL;
 
--- a/pidgin/gtkconv.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkconv.c	Mon Feb 27 22:45:47 2012 +0000
@@ -80,6 +80,15 @@
 
 #include "gtknickcolors.h"
 
+#if !GTK_CHECK_VERSION(2,20,0)
+#define gtk_widget_get_realized(x) GTK_WIDGET_REALIZED(x)
+
+#if !GTK_CHECK_VERSION(2,18,0)
+#define gtk_widget_get_visible(x) GTK_WIDGET_VISIBLE(x)
+#define gtk_widget_is_drawable(x) GTK_WIDGET_DRAWABLE(x)
+#endif
+#endif
+
 /**
  * A GTK+ Instant Message pane.
  */
@@ -198,7 +207,6 @@
 static void gtkconv_set_unseen(PidginConversation *gtkconv, PidginUnseenState state);
 static void update_typing_icon(PidginConversation *gtkconv);
 static void update_typing_message(PidginConversation *gtkconv, const char *message);
-static const char *item_factory_translate_func (const char *path, gpointer func_data);
 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);
@@ -943,7 +951,9 @@
 		                                GTK_RESPONSE_OK);
 		gtk_container_set_border_width(GTK_CONTAINER(invite_dialog), PIDGIN_HIG_BOX_SPACE);
 		gtk_window_set_resizable(GTK_WINDOW(invite_dialog), FALSE);
+#if !GTK_CHECK_VERSION(2,22,0)
 		gtk_dialog_set_has_separator(GTK_DIALOG(invite_dialog), FALSE);
+#endif
 
 		info->window = GTK_WIDGET(invite_dialog);
 
@@ -1040,13 +1050,13 @@
 }
 
 static void
-menu_new_conv_cb(gpointer data, guint action, GtkWidget *widget)
+menu_new_conv_cb(GtkAction *action, gpointer data)
 {
 	pidgin_dialogs_im();
 }
 
 static void
-menu_join_chat_cb(gpointer data, guint action, GtkWidget *widget)
+menu_join_chat_cb(GtkAction *action, gpointer data)
 {
 	pidgin_blist_joinchat_show();
 }
@@ -1090,7 +1100,7 @@
  * plaintext v. HTML file.
  */
 static void
-menu_save_as_cb(gpointer data, guint action, GtkWidget *widget)
+menu_save_as_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
@@ -1121,7 +1131,7 @@
 }
 
 static void
-menu_view_log_cb(gpointer data, guint action, GtkWidget *widget)
+menu_view_log_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
@@ -1148,7 +1158,6 @@
 	gdk_window_set_cursor(gtkblist->window->window, cursor);
 	gdk_window_set_cursor(win->window->window, cursor);
 	gdk_cursor_unref(cursor);
-	gdk_display_flush(gdk_drawable_get_display(GDK_DRAWABLE(widget->window)));
 
 	name = purple_conversation_get_name(conv);
 	account = purple_conversation_get_account(conv);
@@ -1175,7 +1184,7 @@
 }
 
 static void
-menu_clear_cb(gpointer data, guint action, GtkWidget *widget)
+menu_clear_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
@@ -1185,7 +1194,7 @@
 }
 
 static void
-menu_find_cb(gpointer data, guint action, GtkWidget *widget)
+menu_find_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *gtkwin = data;
 	PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(gtkwin);
@@ -1195,7 +1204,7 @@
 
 #ifdef USE_VV
 static void
-menu_initiate_media_call_cb(gpointer data, guint action, GtkWidget *widget)
+menu_initiate_media_call_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = (PidginWindow *)data;
 	PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
@@ -1203,15 +1212,15 @@
 
 	purple_prpl_initiate_media(account,
 			purple_conversation_get_name(conv),
-			action == 0 ? PURPLE_MEDIA_AUDIO :
-			action == 1 ? PURPLE_MEDIA_VIDEO :
-			action == 2 ? PURPLE_MEDIA_AUDIO |
+			action == win->audio_call ? PURPLE_MEDIA_AUDIO :
+			action == win->video_call ? PURPLE_MEDIA_VIDEO :
+			action == win->audio_video_call ? PURPLE_MEDIA_AUDIO |
 			PURPLE_MEDIA_VIDEO : PURPLE_MEDIA_NONE);
 }
 #endif
 
 static void
-menu_send_file_cb(gpointer data, guint action, GtkWidget *widget)
+menu_send_file_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
@@ -1223,24 +1232,24 @@
 }
 
 static void
-menu_get_attention_cb(gpointer data, guint action, GtkWidget *widget)
+menu_get_attention_cb(GObject *obj, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
 
 	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
 		int index;
-		if (widget == win->menu.get_attention)
+		if ((GtkAction *)obj == win->menu.get_attention)
 			index = 0;
 		else
-			index = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "index"));
+			index = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(obj), "index"));
 		purple_prpl_send_attention(purple_conversation_get_connection(conv),
 			purple_conversation_get_name(conv), index);
 	}
 }
 
 static void
-menu_add_pounce_cb(gpointer data, guint action, GtkWidget *widget)
+menu_add_pounce_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
@@ -1252,7 +1261,7 @@
 }
 
 static void
-menu_insert_link_cb(gpointer data, guint action, GtkWidget *widget)
+menu_insert_link_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PidginConversation *gtkconv;
@@ -1266,7 +1275,7 @@
 }
 
 static void
-menu_insert_image_cb(gpointer data, guint action, GtkWidget *widget)
+menu_insert_image_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PidginConversation *gtkconv;
@@ -1281,7 +1290,7 @@
 
 
 static void
-menu_alias_cb(gpointer data, guint action, GtkWidget *widget)
+menu_alias_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
@@ -1308,7 +1317,7 @@
 }
 
 static void
-menu_get_info_cb(gpointer data, guint action, GtkWidget *widget)
+menu_get_info_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
@@ -1319,7 +1328,7 @@
 }
 
 static void
-menu_invite_cb(gpointer data, guint action, GtkWidget *widget)
+menu_invite_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
@@ -1330,7 +1339,7 @@
 }
 
 static void
-menu_block_cb(gpointer data, guint action, GtkWidget *widget)
+menu_block_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
@@ -1341,7 +1350,7 @@
 }
 
 static void
-menu_unblock_cb(gpointer data, guint action, GtkWidget *widget)
+menu_unblock_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
@@ -1352,7 +1361,7 @@
 }
 
 static void
-menu_add_remove_cb(gpointer data, guint action, GtkWidget *widget)
+menu_add_remove_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
@@ -1397,7 +1406,7 @@
 }
 
 static void
-menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget)
+menu_close_conv_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 
@@ -1405,7 +1414,7 @@
 }
 
 static void
-menu_logging_cb(gpointer data, guint action, GtkWidget *widget)
+menu_logging_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
@@ -1417,7 +1426,7 @@
 	if (conv == NULL)
 		return;
 
-	logging = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
+	logging = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
 
 	if (logging == purple_conversation_is_logging(conv))
 		return;
@@ -1468,14 +1477,14 @@
 }
 
 static void
-menu_toolbar_cb(gpointer data, guint action, GtkWidget *widget)
+menu_toolbar_cb(GtkAction *action, gpointer data)
 {
 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/show_formatting_toolbar",
-	                    gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
-}
-
-static void
-menu_sounds_cb(gpointer data, guint action, GtkWidget *widget)
+	                    gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
+}
+
+static void
+menu_sounds_cb(GtkAction *action, gpointer data)
 {
 	PidginWindow *win = data;
 	PurpleConversation *conv;
@@ -1490,17 +1499,17 @@
 	gtkconv = PIDGIN_CONVERSATION(conv);
 
 	gtkconv->make_sound =
-		gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
+		gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
 	node = get_conversation_blist_node(conv);
 	if (node)
 		purple_blist_node_set_bool(node, "gtk-mute-sound", !gtkconv->make_sound);
 }
 
 static void
-menu_timestamps_cb(gpointer data, guint action, GtkWidget *widget)
+menu_timestamps_cb(GtkAction *action, gpointer data)
 {
 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/conversations/show_timestamps",
-		gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
+		gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
 }
 
 static void
@@ -2299,7 +2308,7 @@
 	gtkconv->active_conv = conv;
 
 	purple_conversation_set_logging(conv,
-		gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(gtkconv->win->menu.logging)));
+		gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(gtkconv->win->menu.logging)));
 
 	entry = GTK_IMHTML(gtkconv->entry);
 	protocol_name = purple_account_get_protocol_name(purple_conversation_get_account(conv));
@@ -3114,91 +3123,98 @@
 	return gtkconv->win;
 }
 
-static GtkItemFactoryEntry menu_items[] =
+static GtkActionEntry menu_entries[] =
+/* TODO: fill out tooltips... */
 {
 	/* Conversation menu */
-	{ N_("/_Conversation"), NULL, NULL, 0, "<Branch>", NULL },
-
-	{ N_("/Conversation/New Instant _Message..."), "<CTL>M", menu_new_conv_cb,
-			0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW },
-	{ N_("/Conversation/Join a _Chat..."), NULL, menu_join_chat_cb,
-			0, "<StockItem>", PIDGIN_STOCK_CHAT },
-
-	{ "/Conversation/sep0", NULL, NULL, 0, "<Separator>", NULL },
-
-	{ N_("/Conversation/_Find..."), NULL, menu_find_cb, 0,
-			"<StockItem>", GTK_STOCK_FIND },
-	{ N_("/Conversation/View _Log"), NULL, menu_view_log_cb, 0, "<Item>", NULL },
-	{ N_("/Conversation/_Save As..."), NULL, menu_save_as_cb, 0,
-			"<StockItem>", GTK_STOCK_SAVE_AS },
-	{ N_("/Conversation/Clea_r Scrollback"), "<CTL>L", menu_clear_cb, 0, "<StockItem>", GTK_STOCK_CLEAR },
-
-	{ "/Conversation/sep1", NULL, NULL, 0, "<Separator>", NULL },
+	{ "ConversationMenu", NULL, N_("_Conversation"), NULL, NULL, NULL },
+	{ "NewInstantMessage", PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW, N_("New Instant _Message..."), "<control>M", NULL, G_CALLBACK(menu_new_conv_cb) },
+	{ "JoinAChat", PIDGIN_STOCK_CHAT, N_("Join a _Chat..."), NULL, NULL, G_CALLBACK(menu_join_chat_cb) },
+	{ "Find", GTK_STOCK_FIND, N_("_Find..."), NULL, NULL, G_CALLBACK(menu_find_cb) },
+	{ "ViewLog", NULL, N_("View _Log"), NULL, NULL, G_CALLBACK(menu_view_log_cb) },
+	{ "SaveAs", GTK_STOCK_SAVE_AS, N_("_Save As..."), NULL, NULL, G_CALLBACK(menu_save_as_cb) },
+	{ "ClearScrollback", GTK_STOCK_CLEAR, N_("Clea_r Scrollback"), "<control>L", NULL, G_CALLBACK(menu_clear_cb) },
 
 #ifdef USE_VV
-	{ N_("/Conversation/M_edia"), NULL, NULL, 0, "<Branch>", NULL },
-
-	{ N_("/Conversation/Media/_Audio Call"), NULL, menu_initiate_media_call_cb, 0,
-		"<StockItem>", PIDGIN_STOCK_TOOLBAR_AUDIO_CALL },
-	{ N_("/Conversation/Media/_Video Call"), NULL, menu_initiate_media_call_cb, 1,
-		"<StockItem>", PIDGIN_STOCK_TOOLBAR_VIDEO_CALL },
-	{ N_("/Conversation/Media/Audio\\/Video _Call"), NULL, menu_initiate_media_call_cb, 2,
-		"<StockItem>", PIDGIN_STOCK_TOOLBAR_VIDEO_CALL },
+	{ "MediaMenu", NULL, N_("M_edia"), NULL, NULL, NULL },
+	{ "AudioCall", PIDGIN_STOCK_TOOLBAR_AUDIO_CALL, N_("_Audio Call"), NULL, NULL, G_CALLBACK(menu_initiate_media_call_cb) },
+	{ "VideoCall", PIDGIN_STOCK_TOOLBAR_VIDEO_CALL, N_("_Video Call"), NULL, NULL, G_CALLBACK(menu_initiate_media_call_cb) },
+	{ "AudioVideoCall", PIDGIN_STOCK_TOOLBAR_VIDEO_CALL, N_("Audio/Video _Call"), NULL, NULL, G_CALLBACK(menu_initiate_media_call_cb) },
 #endif
 
-	{ N_("/Conversation/Se_nd File..."), NULL, menu_send_file_cb, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SEND_FILE },
-	{ N_("/Conversation/Get _Attention"), NULL, menu_get_attention_cb, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SEND_ATTENTION },
-	{ N_("/Conversation/Add Buddy _Pounce..."), NULL, menu_add_pounce_cb,
-			0, "<Item>", NULL },
-	{ N_("/Conversation/_Get Info"), "<CTL>O", menu_get_info_cb, 0,
-			"<StockItem>", PIDGIN_STOCK_TOOLBAR_USER_INFO },
-	{ N_("/Conversation/In_vite..."), NULL, menu_invite_cb, 0,
-			"<Item>", NULL },
-	{ N_("/Conversation/M_ore"), NULL, NULL, 0, "<Branch>", NULL },
-
-	{ "/Conversation/sep2", NULL, NULL, 0, "<Separator>", NULL },
-
-	{ N_("/Conversation/Al_ias..."), NULL, menu_alias_cb, 0,
-			"<Item>", NULL },
-	{ N_("/Conversation/_Block..."), NULL, menu_block_cb, 0,
-			"<StockItem>", PIDGIN_STOCK_TOOLBAR_BLOCK },
-	{ N_("/Conversation/_Unblock..."), NULL, menu_unblock_cb, 0,
-			"<StockItem>", PIDGIN_STOCK_TOOLBAR_UNBLOCK },
-	{ N_("/Conversation/_Add..."), NULL, menu_add_remove_cb, 0,
-			"<StockItem>", GTK_STOCK_ADD },
-	{ N_("/Conversation/_Remove..."), NULL, menu_add_remove_cb, 0,
-			"<StockItem>", GTK_STOCK_REMOVE },
-
-	{ "/Conversation/sep3", NULL, NULL, 0, "<Separator>", NULL },
-
-	{ N_("/Conversation/Insert Lin_k..."), NULL, menu_insert_link_cb, 0,
-		"<StockItem>", PIDGIN_STOCK_TOOLBAR_INSERT_LINK },
-	{ N_("/Conversation/Insert Imag_e..."), NULL, menu_insert_image_cb, 0,
-		"<StockItem>", PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE },
-
-	{ "/Conversation/sep4", NULL, NULL, 0, "<Separator>", NULL },
-
-
-	{ N_("/Conversation/_Close"), NULL, menu_close_conv_cb, 0,
-			"<StockItem>", GTK_STOCK_CLOSE },
+	{ "SendFile", PIDGIN_STOCK_TOOLBAR_SEND_FILE, N_("Se_nd File..."), NULL, NULL, G_CALLBACK(menu_send_file_cb) },
+	{ "GetAttention", PIDGIN_STOCK_TOOLBAR_SEND_ATTENTION, N_("Get _Attention"), NULL, NULL, G_CALLBACK(menu_get_attention_cb) },
+	{ "AddBuddyPounce", NULL, N_("Add Buddy _Pounce..."), NULL, NULL, G_CALLBACK(menu_add_pounce_cb) },
+	{ "GetInfo", PIDGIN_STOCK_TOOLBAR_USER_INFO, N_("_Get Info"), "<control>O", NULL, G_CALLBACK(menu_get_info_cb) },
+	{ "Invite", NULL, N_("In_vite..."), NULL, NULL, G_CALLBACK(menu_invite_cb) },
+	{ "MoreMenu", NULL, N_("M_ore"), NULL, NULL, NULL },
+	{ "Alias", NULL, N_("Al_ias..."), NULL, NULL, G_CALLBACK(menu_alias_cb) },
+	{ "Block", PIDGIN_STOCK_TOOLBAR_BLOCK, N_("_Block..."), NULL, NULL, G_CALLBACK(menu_block_cb) },
+	{ "Unblock", PIDGIN_STOCK_TOOLBAR_UNBLOCK, N_("_Unblock..."), NULL, NULL, G_CALLBACK(menu_unblock_cb) },
+	{ "Add", GTK_STOCK_ADD, N_("_Add..."), NULL, NULL, G_CALLBACK(menu_add_remove_cb) },
+	{ "Remove", GTK_STOCK_REMOVE, N_("_Remove..."), NULL, NULL, G_CALLBACK(menu_add_remove_cb) },
+	{ "InsertLink", PIDGIN_STOCK_TOOLBAR_INSERT_LINK, N_("Insert Lin_k..."), NULL, NULL, G_CALLBACK(menu_insert_link_cb) },
+	{ "InsertImage", PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE, N_("Insert Imag_e..."), NULL, NULL, G_CALLBACK(menu_insert_image_cb) },
+	{ "Close", GTK_STOCK_CLOSE, N_("_Close"), NULL, NULL, G_CALLBACK(menu_close_conv_cb) },
 
 	/* Options */
-	{ N_("/_Options"), NULL, NULL, 0, "<Branch>", NULL },
-	{ N_("/Options/Enable _Logging"), NULL, menu_logging_cb, 0, "<CheckItem>", NULL },
-	{ N_("/Options/Enable _Sounds"), NULL, menu_sounds_cb, 0, "<CheckItem>", NULL },
-	{ "/Options/sep0", NULL, NULL, 0, "<Separator>", NULL },
-	{ N_("/Options/Show Formatting _Toolbars"), NULL, menu_toolbar_cb, 0, "<CheckItem>", NULL },
-	{ N_("/Options/Show Ti_mestamps"), NULL, menu_timestamps_cb, 0, "<CheckItem>", NULL },
+	{ "OptionsMenu", NULL, N_("_Options"), NULL, NULL, NULL },
+};
+
+/* Toggle items */
+static const GtkToggleActionEntry menu_toggle_entries[] = {
+	{ "EnableLogging", NULL, N_("Enable _Logging"), NULL, NULL, G_CALLBACK(menu_logging_cb), FALSE },
+	{ "EnableSounds", NULL, N_("Enable _Sounds"), NULL, NULL, G_CALLBACK(menu_sounds_cb), FALSE },
+	{ "ShowFormattingToolbars", NULL, N_("Show Formatting _Toolbars"), NULL, NULL, G_CALLBACK(menu_toolbar_cb), FALSE },
+	{ "ShowTimestamps", NULL, N_("Show Ti_mestamps"), NULL, NULL, G_CALLBACK(menu_timestamps_cb), FALSE },
 };
 
-static const int menu_item_count =
-sizeof(menu_items) / sizeof(*menu_items);
-
-static const char *
-item_factory_translate_func (const char *path, gpointer func_data)
-{
-	return _(path);
-}
+static const char *conversation_menu =
+"<ui>"
+	"<menubar name='Conversation'>"
+		"<menu action='ConversationMenu'>"
+			"<menuitem action='NewInstantMessage'/>"
+			"<menuitem action='JoinAChat'/>"
+			"<separator/>"
+			"<menuitem action='Find'/>"
+			"<menuitem action='ViewLog'/>"
+			"<menuitem action='SaveAs'/>"
+			"<menuitem action='ClearScrollback'/>"
+			"<separator/>"
+#ifdef USE_VV
+			"<menu action='MediaMenu'>"
+				"<menuitem action='AudioCall'/>"
+				"<menuitem action='VideoCall'/>"
+				"<menuitem action='AudioVideoCall'/>"
+			"</menu>"
+#endif
+			"<menuitem action='SendFile'/>"
+			"<menuitem action='GetAttention'/>"
+			"<menuitem action='AddBuddyPounce'/>"
+			"<menuitem action='GetInfo'/>"
+			"<menuitem action='Invite'/>"
+			"<menu action='MoreMenu'/>"
+			"<separator/>"
+			"<menuitem action='Alias'/>"
+			"<menuitem action='Block'/>"
+			"<menuitem action='Unblock'/>"
+			"<menuitem action='Add'/>"
+			"<menuitem action='Remove'/>"
+			"<separator/>"
+			"<menuitem action='InsertLink'/>"
+			"<menuitem action='InsertImage'/>"
+			"<separator/>"
+			"<menuitem action='Close'/>"
+		"</menu>"
+		"<menu action='OptionsMenu'>"
+			"<menuitem action='EnableLogging'/>"
+			"<menuitem action='EnableSounds'/>"
+			"<separator/>"
+			"<menuitem action='ShowFormattingToolbars'/>"
+			"<menuitem action='ShowTimestamps'/>"
+		"</menu>"
+	"</menubar>"
+"</ui>";
 
 static void
 sound_method_pref_changed_cb(const char *name, PurplePrefType type,
@@ -3209,19 +3225,18 @@
 
 	if (!strcmp(method, "none"))
 	{
-		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.sounds),
-		                               FALSE);
-		gtk_widget_set_sensitive(win->menu.sounds, FALSE);
+		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.sounds),
+		                             FALSE);
+		gtk_action_set_sensitive(win->menu.sounds, FALSE);
 	}
 	else
 	{
 		PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(win);
 
 		if (gtkconv != NULL)
-			gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.sounds),
-			                               gtkconv->make_sound);
-		gtk_widget_set_sensitive(win->menu.sounds, TRUE);
-
+			gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.sounds),
+			                             gtkconv->make_sound);
+		gtk_action_set_sensitive(win->menu.sounds, TRUE);
 	}
 }
 
@@ -3351,25 +3366,25 @@
 				purple_prpl_get_media_caps(account,
 				purple_conversation_get_name(conv));
 
-		gtk_widget_set_sensitive(win->audio_call,
+		gtk_action_set_sensitive(win->audio_call,
 				caps & PURPLE_MEDIA_CAPS_AUDIO
 				? TRUE : FALSE);
-		gtk_widget_set_sensitive(win->video_call,
+		gtk_action_set_sensitive(win->video_call,
 				caps & PURPLE_MEDIA_CAPS_VIDEO
 				? TRUE : FALSE);
-		gtk_widget_set_sensitive(win->audio_video_call,
+		gtk_action_set_sensitive(win->audio_video_call,
 				caps & PURPLE_MEDIA_CAPS_AUDIO_VIDEO
 				? TRUE : FALSE);
 	} else if (purple_conversation_get_type(conv)
 			== PURPLE_CONV_TYPE_CHAT) {
 		/* for now, don't care about chats... */
-		gtk_widget_set_sensitive(win->audio_call, FALSE);
-		gtk_widget_set_sensitive(win->video_call, FALSE);
-		gtk_widget_set_sensitive(win->audio_video_call, FALSE);
+		gtk_action_set_sensitive(win->audio_call, FALSE);
+		gtk_action_set_sensitive(win->video_call, FALSE);
+		gtk_action_set_sensitive(win->audio_video_call, FALSE);
 	} else {
-		gtk_widget_set_sensitive(win->audio_call, FALSE);
-		gtk_widget_set_sensitive(win->video_call, FALSE);
-		gtk_widget_set_sensitive(win->audio_video_call, FALSE);
+		gtk_action_set_sensitive(win->audio_call, FALSE);
+		gtk_action_set_sensitive(win->video_call, FALSE);
+		gtk_action_set_sensitive(win->audio_video_call, FALSE);
 	}
 #endif
 }
@@ -3377,6 +3392,7 @@
 static void
 regenerate_attention_items(PidginWindow *win)
 {
+	GtkWidget *attention;
 	GtkWidget *menu;
 	PurpleConversation *conv;
 	PurpleConnection *pc;
@@ -3388,8 +3404,11 @@
 	if (!conv)
 		return;
 
+	attention = gtk_ui_manager_get_widget(win->menu.ui,
+	                                      "/Conversation/ConversationMenu/GetAttention");
+
 	/* Remove the previous entries */
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(win->menu.get_attention), NULL);
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(attention), NULL);
 
 	pc = purple_conversation_get_connection(conv);
 	if (pc != NULL)
@@ -3422,7 +3441,7 @@
 				list = g_list_delete_link(list, list);
 			}
 
-			gtk_menu_item_set_submenu(GTK_MENU_ITEM(win->menu.get_attention), menu);
+			gtk_menu_item_set_submenu(GTK_MENU_ITEM(attention), menu);
 			gtk_widget_show_all(menu);
 		}
 	}
@@ -3434,9 +3453,13 @@
 	GtkWidget *menu;
 	PidginConversation *gtkconv;
 	GList *list;
+	GtkWidget *more_menu;
 
 	gtkconv = pidgin_conv_window_get_active_gtkconv(win);
-	menu = gtk_item_factory_get_widget(win->menu.item_factory, N_("/Conversation/More"));
+	more_menu = gtk_ui_manager_get_widget(win->menu.ui,
+	                                      "/Conversation/ConversationMenu/MoreMenu");
+	gtk_widget_show(more_menu);
+	menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(more_menu));
 
 	/* Remove the previous entries */
 	for (list = gtk_container_get_children(GTK_CONTAINER(menu)); list; )
@@ -3492,7 +3515,8 @@
 		action_items = g_list_delete_link(action_items, action_items);
 	}
 
-	menu = gtk_item_factory_get_widget(win->menu.item_factory, N_("/Options"));
+	item = gtk_ui_manager_get_widget(win->menu.ui, "/Conversation/OptionsMenu");
+	menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(item));
 
 	list = purple_conversation_get_extended_menu(conv);
 	if (list) {
@@ -3529,7 +3553,7 @@
 {
 	/* The menubar has been deactivated. Make sure the 'More' submenu is regenerated next time
 	 * the 'Conversation' menu pops up. */
-	GtkWidget *menuitem = gtk_item_factory_get_item(win->menu.item_factory, N_("/Conversation"));
+	GtkWidget *menuitem = gtk_ui_manager_get_widget(win->menu.ui, "/Conversation/ConversationMenu");
 	g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), G_CALLBACK(menubar_activated), win);
 	g_signal_handlers_disconnect_by_func(G_OBJECT(win->menu.menubar),
 				G_CALLBACK(focus_out_from_menubar), win);
@@ -3540,130 +3564,145 @@
 {
 	GtkAccelGroup *accel_group;
 	const char *method;
+	GtkActionGroup *action_group;
+	GError *error;
 	GtkWidget *menuitem;
 
-	accel_group = gtk_accel_group_new ();
+	action_group = gtk_action_group_new("ConversationActions");
+	gtk_action_group_add_actions(action_group,
+	                             menu_entries,
+	                             G_N_ELEMENTS(menu_entries),
+	                             win);
+	gtk_action_group_add_toggle_actions(action_group,
+	                                    menu_toggle_entries,
+	                                    G_N_ELEMENTS(menu_toggle_entries),
+	                                    win);
+#ifdef ENABLE_NLS
+	gtk_action_group_set_translation_domain(action_group,
+	                                        PACKAGE);
+#endif
+
+	win->menu.ui = gtk_ui_manager_new();
+	gtk_ui_manager_insert_action_group(win->menu.ui, action_group, 0);
+
+	accel_group = gtk_ui_manager_get_accel_group(win->menu.ui);
 	gtk_window_add_accel_group(GTK_WINDOW(win->window), accel_group);
-	g_object_unref(accel_group);
-
-	win->menu.item_factory =
-		gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
-
-	gtk_item_factory_set_translate_func(win->menu.item_factory,
-	                                    (GtkTranslateFunc)item_factory_translate_func,
-	                                    NULL, NULL);
-
-	gtk_item_factory_create_items(win->menu.item_factory, menu_item_count,
-	                              menu_items, win);
 	g_signal_connect(G_OBJECT(accel_group), "accel-changed",
 	                 G_CALLBACK(pidgin_save_accels_cb), NULL);
 
+	error = NULL;
+	if (!gtk_ui_manager_add_ui_from_string(win->menu.ui, conversation_menu, -1, &error))
+	{
+		g_message("building menus failed: %s", error->message);
+		g_error_free(error);
+		exit(EXIT_FAILURE);
+	}
+
+	win->menu.menubar =
+		gtk_ui_manager_get_widget(win->menu.ui, "/Conversation");
+
 	/* Make sure the 'Conversation -> More' menuitems are regenerated whenever
 	 * the 'Conversation' menu pops up because the entries can change after the
 	 * conversation is created. */
-	menuitem = gtk_item_factory_get_item(win->menu.item_factory, N_("/Conversation"));
+	menuitem = gtk_ui_manager_get_widget(win->menu.ui, "/Conversation/ConversationMenu");
 	g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menubar_activated), win);
 
-	win->menu.menubar =
-		gtk_item_factory_get_widget(win->menu.item_factory, "<main>");
-
 	win->menu.view_log =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Conversation/View Log"));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/ConversationMenu/ViewLog");
 
 #ifdef USE_VV
 	win->audio_call =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-					    N_("/Conversation/Media/Audio Call"));
+		gtk_ui_manager_get_action(win->menu.ui,
+					    "/Conversation/ConversationMenu/MediaMenu/AudioCall");
 	win->video_call =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-					    N_("/Conversation/Media/Video Call"));
+		gtk_ui_manager_get_action(win->menu.ui,
+					    "/Conversation/ConversationMenu/MediaMenu/VideoCall");
 	win->audio_video_call =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-					    N_("/Conversation/Media/Audio\\/Video Call"));
+		gtk_ui_manager_get_action(win->menu.ui,
+					    "/Conversation/ConversationMenu/MediaMenu/AudioVideoCall");
 #endif
 
 	/* --- */
 
 	win->menu.send_file =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Conversation/Send File..."));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/ConversationMenu/SendFile");
 
 	win->menu.get_attention =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-			                    N_("/Conversation/Get Attention"));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/ConversationMenu/GetAttention");
 
 	win->menu.add_pounce =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Conversation/Add Buddy Pounce..."));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/ConversationMenu/AddBuddyPounce");
 
 	/* --- */
 
 	win->menu.get_info =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Conversation/Get Info"));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/ConversationMenu/GetInfo");
 
 	win->menu.invite =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Conversation/Invite..."));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/ConversationMenu/Invite");
 
 	/* --- */
 
 	win->menu.alias =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Conversation/Alias..."));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/ConversationMenu/Alias");
 
 	win->menu.block =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Conversation/Block..."));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/ConversationMenu/Block");
 
 	win->menu.unblock =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-					    N_("/Conversation/Unblock..."));
+		gtk_ui_manager_get_action(win->menu.ui,
+					    "/Conversation/ConversationMenu/Unblock");
 
 	win->menu.add =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Conversation/Add..."));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/ConversationMenu/Add");
 
 	win->menu.remove =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Conversation/Remove..."));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/ConversationMenu/Remove");
 
 	/* --- */
 
 	win->menu.insert_link =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-				N_("/Conversation/Insert Link..."));
+		gtk_ui_manager_get_action(win->menu.ui,
+				"/Conversation/ConversationMenu/InsertLink");
 
 	win->menu.insert_image =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-				N_("/Conversation/Insert Image..."));
+		gtk_ui_manager_get_action(win->menu.ui,
+				"/Conversation/ConversationMenu/InsertImage");
 
 	/* --- */
 
 	win->menu.logging =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Options/Enable Logging"));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/OptionsMenu/EnableLogging");
 	win->menu.sounds =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Options/Enable Sounds"));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/OptionsMenu/EnableSounds");
 	method = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method");
 	if (method != NULL && !strcmp(method, "none"))
 	{
-		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.sounds),
+		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.sounds),
 		                               FALSE);
-		gtk_widget_set_sensitive(win->menu.sounds, FALSE);
+		gtk_action_set_sensitive(win->menu.sounds, FALSE);
 	}
 	purple_prefs_connect_callback(win, PIDGIN_PREFS_ROOT "/sound/method",
 				    sound_method_pref_changed_cb, win);
 
 	win->menu.show_formatting_toolbar =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Options/Show Formatting Toolbars"));
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/OptionsMenu/ShowFormattingToolbars");
 	win->menu.show_timestamps =
-		gtk_item_factory_get_widget(win->menu.item_factory,
-		                            N_("/Options/Show Timestamps"));
-	win->menu.show_icon = NULL;
+		gtk_ui_manager_get_action(win->menu.ui,
+		                          "/Conversation/OptionsMenu/ShowTimestamps");
 
 	win->menu.tray = pidgin_menu_tray_new();
 	gtk_menu_shell_append(GTK_MENU_SHELL(win->menu.menubar),
@@ -3846,7 +3885,6 @@
 	if (!(b = purple_find_buddy(account, purple_conversation_get_name(conv))))
 		return FALSE;
 
-
 	gtk_widget_show(win->menu.send_to);
 
 	menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(win->menu.send_to));
@@ -5017,8 +5055,12 @@
 
 	close = pidgin_create_small_button(gtk_label_new("×"));
 	gtk_box_pack_start(GTK_BOX(widget), close, FALSE, FALSE, 0);
+#if GTK_CHECK_VERSION(2,12,0)
+	gtk_widget_set_tooltip_text(close, _("Close Find bar"));
+#else
 	gtk_tooltips_set_tip(gtkconv->tooltips, close,
 	                     _("Close Find bar"), NULL);
+#endif
 
 	label = gtk_label_new(_("Find:"));
 	gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 10);
@@ -5691,7 +5733,9 @@
 	gtkconv->send_history = g_list_append(NULL, NULL);
 
 	/* Setup some initial variables. */
+#if !GTK_CHECK_VERSION(2,12,0)
 	gtkconv->tooltips = gtk_tooltips_new();
+#endif
 	gtkconv->unseen_state = PIDGIN_UNSEEN_NONE;
 	gtkconv->unseen_count = 0;
 	theme = purple_theme_manager_find_theme(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/theme"), "conversation");
@@ -5890,7 +5934,9 @@
 		g_free(gtkconv->u.chat);
 	}
 
+#if !GTK_CHECK_VERSION(2,12,0)
 	gtk_object_sink(GTK_OBJECT(gtkconv->tooltips));
+#endif
 
 	gtkconv->send_history = g_list_first(gtkconv->send_history);
 	g_list_foreach(gtkconv->send_history, (GFunc)g_free, NULL);
@@ -7005,57 +7051,57 @@
 		/* Show stuff that applies to IMs, hide stuff that applies to chats */
 
 		/* Deal with menu items */
-		gtk_widget_show(win->menu.view_log);
-		gtk_widget_show(win->menu.send_file);
-		gtk_widget_show(win->menu.get_attention);
-		gtk_widget_show(win->menu.add_pounce);
-		gtk_widget_show(win->menu.get_info);
-		gtk_widget_hide(win->menu.invite);
-		gtk_widget_show(win->menu.alias);
+		gtk_action_set_visible(win->menu.view_log, TRUE);
+		gtk_action_set_visible(win->menu.send_file, TRUE);
+		gtk_action_set_visible(win->menu.get_attention, TRUE);
+		gtk_action_set_visible(win->menu.add_pounce, TRUE);
+		gtk_action_set_visible(win->menu.get_info, TRUE);
+		gtk_action_set_visible(win->menu.invite, FALSE);
+		gtk_action_set_visible(win->menu.alias, TRUE);
 		if (purple_privacy_check(account, purple_conversation_get_name(conv))) {
-			gtk_widget_hide(win->menu.unblock);
-			gtk_widget_show(win->menu.block);
+			gtk_action_set_visible(win->menu.unblock, FALSE);
+			gtk_action_set_visible(win->menu.block, TRUE);
 		} else {
-			gtk_widget_hide(win->menu.block);
-			gtk_widget_show(win->menu.unblock);
+			gtk_action_set_visible(win->menu.block, FALSE);
+			gtk_action_set_visible(win->menu.unblock, TRUE);
 		}
 
 		if ((account == NULL) || purple_find_buddy(account, purple_conversation_get_name(conv)) == NULL) {
-			gtk_widget_show(win->menu.add);
-			gtk_widget_hide(win->menu.remove);
+			gtk_action_set_visible(win->menu.add, TRUE);
+			gtk_action_set_visible(win->menu.remove, FALSE);
 		} else {
-			gtk_widget_show(win->menu.remove);
-			gtk_widget_hide(win->menu.add);
-		}
-
-		gtk_widget_show(win->menu.insert_link);
-		gtk_widget_show(win->menu.insert_image);
+			gtk_action_set_visible(win->menu.remove, TRUE);
+			gtk_action_set_visible(win->menu.add, FALSE);
+		}
+
+		gtk_action_set_visible(win->menu.insert_link, TRUE);
+		gtk_action_set_visible(win->menu.insert_image, TRUE);
 	} else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
 		/* Show stuff that applies to Chats, hide stuff that applies to IMs */
 
 		/* Deal with menu items */
-		gtk_widget_show(win->menu.view_log);
-		gtk_widget_hide(win->menu.send_file);
-		gtk_widget_hide(win->menu.get_attention);
-		gtk_widget_hide(win->menu.add_pounce);
-		gtk_widget_hide(win->menu.get_info);
-		gtk_widget_show(win->menu.invite);
-		gtk_widget_show(win->menu.alias);
-		gtk_widget_hide(win->menu.block);
-		gtk_widget_hide(win->menu.unblock);
+		gtk_action_set_visible(win->menu.view_log, TRUE);
+		gtk_action_set_visible(win->menu.send_file, FALSE);
+		gtk_action_set_visible(win->menu.get_attention, FALSE);
+		gtk_action_set_visible(win->menu.add_pounce, FALSE);
+		gtk_action_set_visible(win->menu.get_info, FALSE);
+		gtk_action_set_visible(win->menu.invite, TRUE);
+		gtk_action_set_visible(win->menu.alias, TRUE);
+		gtk_action_set_visible(win->menu.block, FALSE);
+		gtk_action_set_visible(win->menu.unblock, FALSE);
 
 		if ((account == NULL) || purple_blist_find_chat(account, purple_conversation_get_name(conv)) == NULL) {
 			/* If the chat is NOT in the buddy list */
-			gtk_widget_show(win->menu.add);
-			gtk_widget_hide(win->menu.remove);
+			gtk_action_set_visible(win->menu.add, TRUE);
+			gtk_action_set_visible(win->menu.remove, FALSE);
 		} else {
 			/* If the chat IS in the buddy list */
-			gtk_widget_hide(win->menu.add);
-			gtk_widget_show(win->menu.remove);
-		}
-
-		gtk_widget_show(win->menu.insert_link);
-		gtk_widget_show(win->menu.insert_image);
+			gtk_action_set_visible(win->menu.add, FALSE);
+			gtk_action_set_visible(win->menu.remove, TRUE);
+		}
+
+		gtk_action_set_visible(win->menu.insert_link, TRUE);
+		gtk_action_set_visible(win->menu.insert_image, TRUE);
 	}
 
 	/*
@@ -7104,30 +7150,30 @@
 			gtk_imhtmltoolbar_associate_smileys(GTK_IMHTMLTOOLBAR(gtkconv->toolbar), purple_account_get_protocol_id(account));
 
 		/* Deal with menu items */
-		gtk_widget_set_sensitive(win->menu.view_log, TRUE);
-		gtk_widget_set_sensitive(win->menu.add_pounce, TRUE);
-		gtk_widget_set_sensitive(win->menu.get_info, (prpl_info->get_info != NULL));
-		gtk_widget_set_sensitive(win->menu.invite, (prpl_info->chat_invite != NULL));
-		gtk_widget_set_sensitive(win->menu.insert_link, (features & PURPLE_CONNECTION_HTML));
-		gtk_widget_set_sensitive(win->menu.insert_image, !(features & PURPLE_CONNECTION_NO_IMAGES));
+		gtk_action_set_sensitive(win->menu.view_log, TRUE);
+		gtk_action_set_sensitive(win->menu.add_pounce, TRUE);
+		gtk_action_set_sensitive(win->menu.get_info, (prpl_info->get_info != NULL));
+		gtk_action_set_sensitive(win->menu.invite, (prpl_info->chat_invite != NULL));
+		gtk_action_set_sensitive(win->menu.insert_link, (features & PURPLE_CONNECTION_HTML));
+		gtk_action_set_sensitive(win->menu.insert_image, !(features & PURPLE_CONNECTION_NO_IMAGES));
 
 		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
 		{
-			gtk_widget_set_sensitive(win->menu.add, (prpl_info->add_buddy != NULL));
-			gtk_widget_set_sensitive(win->menu.remove, (prpl_info->remove_buddy != NULL));
-			gtk_widget_set_sensitive(win->menu.send_file,
+			gtk_action_set_sensitive(win->menu.add, (prpl_info->add_buddy != NULL));
+			gtk_action_set_sensitive(win->menu.remove, (prpl_info->remove_buddy != NULL));
+			gtk_action_set_sensitive(win->menu.send_file,
 									 (prpl_info->send_file != NULL && (!prpl_info->can_receive_file ||
 									  prpl_info->can_receive_file(gc, purple_conversation_get_name(conv)))));
-			gtk_widget_set_sensitive(win->menu.get_attention, (prpl_info->send_attention != NULL));
-			gtk_widget_set_sensitive(win->menu.alias,
+			gtk_action_set_sensitive(win->menu.get_attention, (prpl_info->send_attention != NULL));
+			gtk_action_set_sensitive(win->menu.alias,
 									 (account != NULL) &&
 									 (purple_find_buddy(account, purple_conversation_get_name(conv)) != NULL));
 		}
 		else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
 		{
-			gtk_widget_set_sensitive(win->menu.add, (prpl_info->join_chat != NULL));
-			gtk_widget_set_sensitive(win->menu.remove, (prpl_info->join_chat != NULL));
-			gtk_widget_set_sensitive(win->menu.alias,
+			gtk_action_set_sensitive(win->menu.add, (prpl_info->join_chat != NULL));
+			gtk_action_set_sensitive(win->menu.remove, (prpl_info->join_chat != NULL));
+			gtk_action_set_sensitive(win->menu.alias,
 									 (account != NULL) &&
 									 (purple_blist_find_chat(account, purple_conversation_get_name(conv)) != NULL));
 		}
@@ -7137,17 +7183,17 @@
 		/* Or it's a chat that we've left. */
 
 		/* Then deal with menu items */
-		gtk_widget_set_sensitive(win->menu.view_log, TRUE);
-		gtk_widget_set_sensitive(win->menu.send_file, FALSE);
-		gtk_widget_set_sensitive(win->menu.get_attention, FALSE);
-		gtk_widget_set_sensitive(win->menu.add_pounce, TRUE);
-		gtk_widget_set_sensitive(win->menu.get_info, FALSE);
-		gtk_widget_set_sensitive(win->menu.invite, FALSE);
-		gtk_widget_set_sensitive(win->menu.alias, FALSE);
-		gtk_widget_set_sensitive(win->menu.add, FALSE);
-		gtk_widget_set_sensitive(win->menu.remove, FALSE);
-		gtk_widget_set_sensitive(win->menu.insert_link, TRUE);
-		gtk_widget_set_sensitive(win->menu.insert_image, FALSE);
+		gtk_action_set_sensitive(win->menu.view_log, TRUE);
+		gtk_action_set_sensitive(win->menu.send_file, FALSE);
+		gtk_action_set_sensitive(win->menu.get_attention, FALSE);
+		gtk_action_set_sensitive(win->menu.add_pounce, TRUE);
+		gtk_action_set_sensitive(win->menu.get_info, FALSE);
+		gtk_action_set_sensitive(win->menu.invite, FALSE);
+		gtk_action_set_sensitive(win->menu.alias, FALSE);
+		gtk_action_set_sensitive(win->menu.add, FALSE);
+		gtk_action_set_sensitive(win->menu.remove, FALSE);
+		gtk_action_set_sensitive(win->menu.insert_link, TRUE);
+		gtk_action_set_sensitive(win->menu.insert_image, FALSE);
 	}
 
 	/*
@@ -7228,8 +7274,13 @@
 			topic = purple_conv_chat_get_topic(chat);
 
 			gtk_entry_set_text(GTK_ENTRY(gtkchat->topic_text), topic ? topic : "");
+#if GTK_CHECK_VERSION(2,12,0)
+			gtk_widget_set_tooltip_text(gtkchat->topic_text,
+			                            topic ? topic : "");
+#else
 			gtk_tooltips_set_tip(gtkconv->tooltips, gtkchat->topic_text,
 			                     topic ? topic : "", NULL);
+#endif
 		}
 	}
 
@@ -7291,7 +7342,7 @@
 		if (title != markup)
 			g_free(markup);
 
-		if (!GTK_WIDGET_REALIZED(gtkconv->tab_label))
+		if (!gtk_widget_get_realized(gtkconv->tab_label))
 			gtk_widget_realize(gtkconv->tab_label);
 
 		accessibility_obj = gtk_widget_get_accessible(gtkconv->tab_cont);
@@ -7685,7 +7736,7 @@
 		tab = gtk_notebook_get_tab_label(GTK_NOTEBOOK(notebook), page);
 
 		/* Make sure the tab is not hidden beyond an arrow */
-		if (!GTK_WIDGET_DRAWABLE(tab) && gtk_notebook_get_show_tabs(notebook))
+		if (!gtk_widget_is_drawable(tab) && gtk_notebook_get_show_tabs(notebook))
 			continue;
 
 		if (horiz) {
@@ -7810,8 +7861,8 @@
 		gtkconv = PIDGIN_CONVERSATION(conv);
 		win     = gtkconv->win;
 
-		gtk_check_menu_item_set_active(
-		        GTK_CHECK_MENU_ITEM(win->menu.show_timestamps),
+		gtk_toggle_action_set_active(
+		        GTK_TOGGLE_ACTION(win->menu.show_timestamps),
 		        (gboolean)GPOINTER_TO_INT(value));
 
 /* TODO WEBKIT: Use WebKit version of this. */
@@ -7841,8 +7892,8 @@
 		gtkconv = PIDGIN_CONVERSATION(conv);
 		win     = gtkconv->win;
 
-		gtk_check_menu_item_set_active(
-		        GTK_CHECK_MENU_ITEM(win->menu.show_formatting_toolbar),
+		gtk_toggle_action_set_active(
+		        GTK_TOGGLE_ACTION(win->menu.show_formatting_toolbar),
 		        (gboolean)GPOINTER_TO_INT(value));
 
 		if ((gboolean)GPOINTER_TO_INT(value))
@@ -8810,8 +8861,9 @@
 	gtk_container_set_border_width(GTK_CONTAINER(warn_close_dialog),
 	                               6);
 	gtk_window_set_resizable(GTK_WINDOW(warn_close_dialog), FALSE);
-	gtk_dialog_set_has_separator(GTK_DIALOG(warn_close_dialog),
-	                             FALSE);
+#if !GTK_CHECK_VERSION(2,22,0)
+	gtk_dialog_set_has_separator(GTK_DIALOG(warn_close_dialog), FALSE);
+#endif
 
 	/* Setup the outside spacing. */
 	vbox = GTK_DIALOG(warn_close_dialog)->vbox;
@@ -9113,9 +9165,9 @@
 		/* Right click was pressed. Popup the context menu. */
 		GtkWidget *menu = gtk_menu_new(), *sub;
 		gboolean populated = populate_menu_with_options(menu, gtkconv, TRUE);
+
 		sub = gtk_menu_item_get_submenu(GTK_MENU_ITEM(gtkconv->win->menu.send_to));
-
-		if (sub && GTK_WIDGET_IS_SENSITIVE(gtkconv->win->menu.send_to)) {
+		if (sub && gtk_widget_is_sensitive(gtkconv->win->menu.send_to)) {
 			GtkWidget *item = gtk_menu_item_new_with_mnemonic(_("S_end To"));
 			if (populated)
 				pidgin_separator(menu);
@@ -9548,7 +9600,7 @@
 	PurpleConversation *conv = gtkconv->active_conv;
 	const char *text = NULL;
 
-	if (!GTK_WIDGET_VISIBLE(gtkconv->infopane)) {
+	if (!gtk_widget_get_visible(gtkconv->infopane)) {
 		/* There's already an entry for alias. Let's not create another one. */
 		return FALSE;
 	}
@@ -9632,8 +9684,8 @@
 
 	/* Update the menubar */
 
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkconv->win->menu.logging),
-	                               purple_conversation_is_logging(conv));
+	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtkconv->win->menu.logging),
+	                             purple_conversation_is_logging(conv));
 
 	generate_send_to_items(win);
 	regenerate_options_items(win);
@@ -9643,14 +9695,14 @@
 
 	sound_method = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method");
 	if (strcmp(sound_method, "none") != 0)
-		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.sounds),
-		                               gtkconv->make_sound);
-
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.show_formatting_toolbar),
-	                               purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_formatting_toolbar"));
-
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.show_timestamps),
-	                               purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_timestamps"));
+		gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.sounds),
+		                             gtkconv->make_sound);
+
+	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.show_formatting_toolbar),
+	                             purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_formatting_toolbar"));
+
+	gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(win->menu.show_timestamps),
+	                             purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_timestamps"));
 
 	/*
 	 * We pause icons when they are not visible.  If this icon should
@@ -9708,7 +9760,7 @@
 static gboolean gtk_conv_configure_cb(GtkWidget *w, GdkEventConfigure *event, gpointer data) {
 	int x, y;
 
-	if (GTK_WIDGET_VISIBLE(w))
+	if (gtk_widget_get_visible(w))
 		gtk_window_get_position(GTK_WINDOW(w), &x, &y);
 	else
 		return FALSE; /* carry on normally */
@@ -9743,7 +9795,7 @@
 	 /* if the window exists, is hidden, we're saving positions, and the
           * position is sane... */
 	if (win && win->window &&
-			!GTK_WIDGET_VISIBLE(win->window) && conv_width != 0) {
+			!gtk_widget_get_visible(win->window) && conv_width != 0) {
 
 #ifdef _WIN32  /* only override window manager placement on Windows */
 		/* ...check position is on screen... */
@@ -9898,7 +9950,7 @@
 	}
 	gtk_widget_destroy(win->window);
 
-	g_object_unref(G_OBJECT(win->menu.item_factory));
+	g_object_unref(G_OBJECT(win->menu.ui));
 
 	purple_notify_close_with_handle(win);
 	purple_signals_disconnect_by_handle(win);
@@ -9976,8 +10028,12 @@
 
 	/* Close button. */
 	gtkconv->close = pidgin_create_small_button(gtk_label_new("×"));
+#if GTK_CHECK_VERSION(2,12,0)
+	gtk_widget_set_tooltip_text(gtkconv->close, _("Close conversation"));
+#else
 	gtk_tooltips_set_tip(gtkconv->tooltips, gtkconv->close,
 	                     _("Close conversation"), NULL);
+#endif
 
 	g_signal_connect(gtkconv->close, "clicked", G_CALLBACK (close_conv_cb), gtkconv);
 
@@ -10113,9 +10169,9 @@
 		gtk_notebook_set_tab_label(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont, ebox);
 	}
 
-	gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont,
-					   !tabs_side && !angle,
-					   TRUE, GTK_PACK_START);
+	gtk_container_child_set(GTK_CONTAINER(win->notebook), gtkconv->tab_cont,
+	                        "tab-expand", !tabs_side && !angle,
+	                        "tab-fill", TRUE, NULL);
 
 	if (pidgin_conv_window_get_gtkconv_count(win) == 1)
 		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook),
@@ -10139,8 +10195,7 @@
 
 	index = gtk_notebook_page_num(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont);
 
-	g_object_ref(gtkconv->tab_cont);
-	gtk_object_sink(GTK_OBJECT(gtkconv->tab_cont));
+	g_object_ref_sink(G_OBJECT(gtkconv->tab_cont));
 
 	gtk_notebook_remove_page(GTK_NOTEBOOK(win->notebook), index);
 
@@ -10345,7 +10400,7 @@
 	PurpleConversationType type = purple_conversation_get_type(conv->active_conv);
 	GList *all;
 
-	if (GTK_WIDGET_VISIBLE(w))
+	if (gtk_widget_get_visible(w))
 		gtk_window_get_position(GTK_WINDOW(w), &x, &y);
 	else
 		return FALSE; /* carry on normally */
--- a/pidgin/gtkconv.h	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkconv.h	Mon Feb 27 22:45:47 2012 +0000
@@ -90,7 +90,11 @@
 
 	gboolean make_sound;
 
+#if GTK_CHECK_VERSION(2,12,0)
+	gpointer depr2;
+#else
 	GtkTooltips *tooltips;
+#endif
 
 	GtkWidget *tab_cont;
 	GtkWidget *tabby;
--- a/pidgin/gtkconvwin.h	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkconvwin.h	Mon Feb 27 22:45:47 2012 +0000
@@ -48,28 +48,27 @@
 	{
 		GtkWidget *menubar;
 
-		GtkWidget *view_log;
+		GtkAction *view_log;
 
-		GtkWidget *send_file;
-		GtkWidget *get_attention;
-		GtkWidget *add_pounce;
-		GtkWidget *get_info;
-		GtkWidget *invite;
+		GtkAction *send_file;
+		GtkAction *get_attention;
+		GtkAction *add_pounce;
+		GtkAction *get_info;
+		GtkAction *invite;
 
-		GtkWidget *alias;
-		GtkWidget *block;
-		GtkWidget *unblock;
-		GtkWidget *add;
-		GtkWidget *remove;
+		GtkAction *alias;
+		GtkAction *block;
+		GtkAction *unblock;
+		GtkAction *add;
+		GtkAction *remove;
 
-		GtkWidget *insert_link;
-		GtkWidget *insert_image;
+		GtkAction *insert_link;
+		GtkAction *insert_image;
 
-		GtkWidget *logging;
-		GtkWidget *sounds;
-		GtkWidget *show_formatting_toolbar;
-		GtkWidget *show_timestamps;
-		GtkWidget *show_icon;
+		GtkAction *logging;
+		GtkAction *sounds;
+		GtkAction *show_formatting_toolbar;
+		GtkAction *show_timestamps;
 
 		GtkWidget *send_to;
 
@@ -77,7 +76,7 @@
 
 		GtkWidget *typing_icon;
 
-		GtkItemFactory *item_factory;
+		GtkUIManager *ui;
 
 	} menu;
 
@@ -99,9 +98,9 @@
 	gint drag_leave_signal;
 
 	/* Media menu options. */
-	GtkWidget *audio_call;
-	GtkWidget *video_call;
-	GtkWidget *audio_video_call;
+	GtkAction *audio_call;
+	GtkAction *video_call;
+	GtkAction *audio_video_call;
 };
 
 /*@}*/
--- a/pidgin/gtkdebug.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkdebug.c	Mon Feb 27 22:45:47 2012 +0000
@@ -128,7 +128,11 @@
 static gboolean
 configure_cb(GtkWidget *w, GdkEventConfigure *event, DebugWindow *win)
 {
+#if GTK_CHECK_VERSION(2,18,0)
+	if (gtk_widget_get_visible(w)) {
+#else
 	if (GTK_WIDGET_VISIBLE(w)) {
+#endif
 		purple_prefs_set_int(PIDGIN_PREFS_ROOT "/debug/width",  event->width);
 		purple_prefs_set_int(PIDGIN_PREFS_ROOT "/debug/height", event->height);
 	}
@@ -186,7 +190,9 @@
 
 	gtk_container_set_border_width(GTK_CONTAINER(win->find), PIDGIN_HIG_BOX_SPACE);
 	gtk_window_set_resizable(GTK_WINDOW(win->find), FALSE);
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(win->find), FALSE);
+#endif
 	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(win->find)->vbox), PIDGIN_HIG_BORDER);
 	gtk_container_set_border_width(
 		GTK_CONTAINER(GTK_DIALOG(win->find)->vbox), PIDGIN_HIG_BOX_SPACE);
@@ -623,7 +629,11 @@
 static void
 regex_key_release_cb(GtkWidget *w, GdkEventKey *e, DebugWindow *win) {
 	if(e->keyval == GDK_Return &&
+#if GTK_CHECK_VERSION(2,18,0)
+	   gtk_widget_is_sensitive(win->filter) &&
+#else
 	   GTK_WIDGET_IS_SENSITIVE(win->filter) &&
+#endif
 	   !gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter)))
 	{
 		gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter), TRUE);
--- a/pidgin/gtkdialogs.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkdialogs.c	Mon Feb 27 22:45:47 2012 +0000
@@ -466,7 +466,11 @@
 	button = pidgin_dialog_add_button(GTK_DIALOG(win), GTK_STOCK_CLOSE,
 	                G_CALLBACK(destroy_win), win);
 
+#if GTK_CHECK_VERSION(2,18,0)
+	gtk_widget_set_can_default(button, TRUE);
+#else
 	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+#endif
 	gtk_widget_grab_default(button);
 
 	gtk_widget_show_all(win);
@@ -972,7 +976,9 @@
 
 	gtk_container_set_border_width (GTK_CONTAINER(window), PIDGIN_HIG_BOX_SPACE);
 	gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(window), FALSE);
+#endif
 	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(window)->vbox), PIDGIN_HIG_BORDER);
 	gtk_container_set_border_width (GTK_CONTAINER(GTK_DIALOG(window)->vbox), PIDGIN_HIG_BOX_SPACE);
 
--- a/pidgin/gtkdnd-hints.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkdnd-hints.c	Mon Feb 27 22:45:47 2012 +0000
@@ -62,19 +62,20 @@
 	GdkBitmap *bitmap;
 	GtkWidget *pix;
 	GtkWidget *win;
+	GdkColormap *colormap;
 
 	pixbuf = gdk_pixbuf_new_from_file(fname, NULL);
 	g_return_val_if_fail(pixbuf, NULL);
 
-	gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap, &bitmap, 128);
+	win = gtk_window_new(GTK_WINDOW_POPUP);
+	colormap = gtk_widget_get_colormap(win);
+	gdk_pixbuf_render_pixmap_and_mask_for_colormap(pixbuf, colormap,
+	                                               &pixmap, &bitmap, 128);
 	g_object_unref(G_OBJECT(pixbuf));
 
-	gtk_widget_push_colormap(gdk_rgb_get_colormap());
-	win = gtk_window_new(GTK_WINDOW_POPUP);
 	pix = gtk_image_new_from_pixmap(pixmap, bitmap);
 	gtk_container_add(GTK_CONTAINER(win), pix);
 	gtk_widget_shape_combine_mask(win, bitmap, 0, 0);
-	gtk_widget_pop_colormap();
 
 	g_object_unref(G_OBJECT(pixmap));
 	g_object_unref(G_OBJECT(bitmap));
--- a/pidgin/gtkdocklet.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkdocklet.c	Mon Feb 27 22:45:47 2012 +0000
@@ -564,7 +564,7 @@
 		new_menu_item_with_status_icon(menu,
 			purple_status_type_get_name(status_type),
 			prim, G_CALLBACK(activate_status_account_cb),
-			status_type, 0, 0, NULL);
+			GINT_TO_POINTER(status_type), 0, 0, NULL);
 	}
 }
 
--- a/pidgin/gtkidle.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkidle.c	Mon Feb 27 22:45:47 2012 +0000
@@ -107,14 +107,16 @@
 	int event_base, error_base;
 
 	if (has_extension == -1)
-		has_extension = XScreenSaverQueryExtension(GDK_DISPLAY(), &event_base, &error_base);
+		has_extension = XScreenSaverQueryExtension(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
+		                                           &event_base, &error_base);
 
 	if (has_extension)
 	{
 		if (mit_info == NULL)
 			mit_info = XScreenSaverAllocInfo();
 
-		XScreenSaverQueryInfo(GDK_DISPLAY(), GDK_ROOT_WINDOW(), mit_info);
+		XScreenSaverQueryInfo(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
+		                      GDK_ROOT_WINDOW(), mit_info);
 		return (mit_info->idle) / 1000;
 	}
 	else
--- a/pidgin/gtkimhtml.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkimhtml.c	Mon Feb 27 22:45:47 2012 +0000
@@ -65,6 +65,16 @@
 
 #define TOOLTIP_TIMEOUT 500
 
+#if !GTK_CHECK_VERSION(2,20,0)
+#define gtk_widget_get_realized(x) GTK_WIDGET_REALIZED(x)
+
+#if !GTK_CHECK_VERSION(2,18,0)
+#define gtk_widget_get_has_window(x) !GTK_WIDGET_NO_WINDOW(x)
+#define gtk_widget_get_state(x) GTK_WIDGET_STATE(x)
+#define gtk_widget_is_drawable(x) GTK_WIDGET_DRAWABLE(x)
+#endif
+#endif
+
 static GtkTextViewClass *parent_class = NULL;
 
 struct scalable_data {
@@ -458,7 +468,7 @@
 
 	/* Don't scroll here if we're in the middle of a smooth scroll */
 	if (scroll && imhtml->scroll_time == NULL &&
-	    GTK_WIDGET_REALIZED(imhtml))
+	    gtk_widget_get_realized(GTK_WIDGET(imhtml)))
 		gtk_imhtml_scroll_to_end(imhtml, FALSE);
 }
 
@@ -575,7 +585,7 @@
 
 	g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE);
 
-	if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) {
+	if (!imhtml->tip || !gtk_widget_is_drawable (GTK_WIDGET(imhtml))) {
 		imhtml->tip_timer = 0;
 		return FALSE;
 	}
@@ -628,7 +638,7 @@
 	h = 8 + baseline_skip;
 
 	gdk_window_get_pointer (NULL, &x, &y, NULL);
-	if (GTK_WIDGET_NO_WINDOW (GTK_WIDGET(imhtml)))
+	if (!gtk_widget_get_has_window (GTK_WIDGET(imhtml)))
 		y += GTK_WIDGET(imhtml)->allocation.y;
 
 	scr_w = gdk_screen_width();
@@ -824,7 +834,7 @@
 			gdk_color_parse(GTK_IMHTML(widget)->edit.background, &gcolor);
 			gdk_cairo_set_source_color(cr, &gcolor);
 		} else {
-			gdk_cairo_set_source_color(cr, &(widget->style->base[GTK_WIDGET_STATE(widget)]));
+			gdk_cairo_set_source_color(cr, &(widget->style->base[gtk_widget_get_state(widget)]));
 		}
 
 		cairo_rectangle(cr,
--- a/pidgin/gtkimhtmltoolbar.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Mon Feb 27 22:45:47 2012 +0000
@@ -43,6 +43,11 @@
 
 #include <gdk/gdkkeysyms.h>
 
+#if !GTK_CHECK_VERSION(2,18,0)
+#define gtk_widget_get_visible(x) GTK_WIDGET_VISIBLE(x)
+#define gtk_widget_is_sensitive(x) GTK_WIDGET_IS_SENSITIVE(x)
+#endif
+
 static GtkHBoxClass *parent_class = NULL;
 
 static void toggle_button_set_active_block(GtkToggleButton *button,
@@ -658,7 +663,11 @@
 	g_object_set_data(G_OBJECT(button), "smiley_text", face);
 	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(insert_smiley_text), toolbar);
 
+#if GTK_CHECK_VERSION(2,12,0)
+	gtk_widget_set_tooltip_text(button, face);
+#else
 	gtk_tooltips_set_tip(toolbar->tooltips, button, face, NULL);
+#endif
 
 	/* these look really weird with borders */
 	gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
@@ -672,7 +681,11 @@
 		g_snprintf(tip, sizeof(tip),
 			_("This smiley is disabled because a custom smiley exists for this shortcut:\n %s"),
 			face);
+#if GTK_CHECK_VERSION(2,12,0)
+		gtk_widget_set_tooltip_text(button, tip);
+#else
 		gtk_tooltips_set_tip(toolbar->tooltips, button, tip, NULL);
+#endif
 		gtk_widget_set_sensitive(button, FALSE);
 	} else if (psmiley) {
 		/* Remove the button if the smiley is destroyed */
@@ -1155,7 +1168,9 @@
 	}
 
 	g_free(toolbar->sml);
+#if !GTK_CHECK_VERSION(2,12,0)
 	gtk_object_sink(GTK_OBJECT(toolbar->tooltips));
+#endif
 
 	menu = g_object_get_data(object, "font_menu");
 	if (menu)
@@ -1186,7 +1201,7 @@
 	if (event->button != 3)
 		return FALSE;
 
-	wide = GTK_WIDGET_VISIBLE(toolbar->bold);
+	wide = gtk_widget_get_visible(toolbar->bold);
 
 	menu = gtk_menu_new();
 	item = gtk_menu_item_new_with_mnemonic(wide ? _("Group Items") : _("Ungroup Items"));
@@ -1253,7 +1268,11 @@
 			g_signal_connect(G_OBJECT(button), "clicked",
 					 G_CALLBACK(buttons[iter].callback), toolbar);
 			*(buttons[iter].button) = button;
+#if GTK_CHECK_VERSION(2,12,0)
+			gtk_widget_set_tooltip_text(button, buttons[iter].tooltip);
+#else
 			gtk_tooltips_set_tip(toolbar->tooltips, button, buttons[iter].tooltip, NULL);
+#endif
 		} else
 			button = gtk_vseparator_new();
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
@@ -1266,7 +1285,7 @@
 static void
 button_visibility_changed(GtkWidget *button, gpointer dontcare, GtkWidget *item)
 {
-	if (GTK_WIDGET_VISIBLE(button))
+	if (gtk_widget_get_visible(button))
 		gtk_widget_hide(item);
 	else
 		gtk_widget_show(item);
@@ -1275,7 +1294,7 @@
 static void
 button_sensitiveness_changed(GtkWidget *button, gpointer dontcare, GtkWidget *item)
 {
-	gtk_widget_set_sensitive(item, GTK_WIDGET_IS_SENSITIVE(button));
+	gtk_widget_set_sensitive(item, gtk_widget_is_sensitive(button));
 }
 
 static void
@@ -1353,7 +1372,9 @@
 	toolbar->smiley_dialog = NULL;
 	toolbar->image_dialog = NULL;
 
+#if !GTK_CHECK_VERSION(2,12,0)
 	toolbar->tooltips = gtk_tooltips_new();
+#endif
 
 	gtk_box_set_spacing(GTK_BOX(toolbar), 3);
 
--- a/pidgin/gtkimhtmltoolbar.h	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkimhtmltoolbar.h	Mon Feb 27 22:45:47 2012 +0000
@@ -44,7 +44,11 @@
 
 	GtkWidget *imhtml;
 
+#if GTK_CHECK_VERSION(2,12,0)
+	gpointer depr1;
+#else
 	GtkTooltips *tooltips;
+#endif
 
 	GtkWidget *bold;
 	GtkWidget *italic;
--- a/pidgin/gtklog.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtklog.c	Mon Feb 27 22:45:47 2012 +0000
@@ -575,7 +575,9 @@
 	gtk_dialog_add_button(GTK_DIALOG(lv->window), _("_Browse logs folder"), GTK_RESPONSE_HELP);
 #endif
 	gtk_container_set_border_width (GTK_CONTAINER(lv->window), PIDGIN_HIG_BOX_SPACE);
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(lv->window), FALSE);
+#endif
 	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(lv->window)->vbox), 0);
 	g_signal_connect(G_OBJECT(lv->window), "response",
 					 G_CALLBACK(destroy_cb), ht);
--- a/pidgin/gtkmenutray.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkmenutray.c	Mon Feb 27 22:45:47 2012 +0000
@@ -40,6 +40,10 @@
  * Internal Stuff
  *****************************************************************************/
 
+#if !GTK_CHECK_VERSION(2,18,0)
+#define gtk_widget_get_has_window(x) !GTK_WIDGET_NO_WINDOW(x)
+#endif
+
 /******************************************************************************
  * Item Stuff
  *****************************************************************************/
@@ -92,7 +96,9 @@
 static void
 pidgin_menu_tray_finalize(GObject *obj)
 {
+#if !GTK_CHECK_VERSION(2,12,0)
 	PidginMenuTray *tray = PIDGIN_MENU_TRAY(obj);
+#endif
 #if 0
 	/* This _might_ be leaking, but I have a sneaking suspicion that the widget is
 	 * getting destroyed in GtkContainer's finalize function.  But if were are
@@ -104,9 +110,11 @@
 		gtk_widget_destroy(GTK_WIDGET(tray->tray));
 #endif
 
+#if !GTK_CHECK_VERSION(2,12,0)
 	if (tray->tooltips) {
 		gtk_object_sink(GTK_OBJECT(tray->tooltips));
 	}
+#endif
 
 	G_OBJECT_CLASS(parent_class)->finalize(obj);
 }
@@ -205,7 +213,7 @@
 	g_return_if_fail(PIDGIN_IS_MENU_TRAY(menu_tray));
 	g_return_if_fail(GTK_IS_WIDGET(widget));
 
-	if (GTK_WIDGET_NO_WINDOW(widget))
+	if (!gtk_widget_get_has_window(widget))
 	{
 		GtkWidget *event;
 
@@ -238,21 +246,27 @@
 void
 pidgin_menu_tray_set_tooltip(PidginMenuTray *menu_tray, GtkWidget *widget, const char *tooltip)
 {
+#if !GTK_CHECK_VERSION(2,12,0)
 	if (!menu_tray->tooltips)
 		menu_tray->tooltips = gtk_tooltips_new();
+#endif
 
 	/* Should we check whether widget is a child of menu_tray? */
 
 	/*
-	 * If the widget does not have it's own window, then it
+	 * If the widget does not have its own window, then it
 	 * must have automatically been added to an event box
 	 * when it was added to the menu tray.  If this is the
 	 * case, we want to set the tooltip on the widget's parent,
 	 * not on the widget itself.
 	 */
-	if (GTK_WIDGET_NO_WINDOW(widget))
+	if (!gtk_widget_get_has_window(widget))
 		widget = widget->parent;
 
+#if GTK_CHECK_VERSION(2,12,0)
+	gtk_widget_set_tooltip_text(widget, tooltip);
+#else
 	gtk_tooltips_set_tip(menu_tray->tooltips, widget, tooltip, NULL);
+#endif
 }
 
--- a/pidgin/gtkmenutray.h	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkmenutray.h	Mon Feb 27 22:45:47 2012 +0000
@@ -40,7 +40,9 @@
 struct _PidginMenuTray {
 	GtkMenuItem gparent;					/**< The parent instance */
 	GtkWidget *tray;						/**< The tray */
+#if !GTK_CHECK_VERSION(2,12,0)
 	GtkTooltips *tooltips;					/**< Tooltips */
+#endif
 };
 
 /** A PidginMenuTrayClass */
--- a/pidgin/gtknotify.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtknotify.c	Mon Feb 27 22:45:47 2012 +0000
@@ -534,7 +534,9 @@
 
 	gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER);
 	gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+#endif
 	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
 	gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE);
 
@@ -784,7 +786,11 @@
 		gtk_tree_selection_select_iter(sel, &iter);
 	}
 
+#if GTK_CHECK_VERSION(2,18,0)
+	if (!gtk_widget_get_visible(mail_dialog->dialog)) {
+#else
 	if (!GTK_WIDGET_VISIBLE(mail_dialog->dialog)) {
+#endif
 		GdkPixbuf *pixbuf = gtk_widget_render_icon(mail_dialog->dialog, PIDGIN_STOCK_DIALOG_MAIL,
 							   gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL), NULL);
 		char *label_text = g_strdup_printf(ngettext("<b>%d new email.</b>",
@@ -800,7 +806,11 @@
 		g_free(label_text);
 		if (pixbuf)
 			g_object_unref(pixbuf);
+#if GTK_CHECK_VERSION(2,18,0)
+	} else if (!gtk_widget_has_focus(mail_dialog->dialog))
+#else
 	} else if (!GTK_WIDGET_HAS_FOCUS(mail_dialog->dialog))
+#endif
 		pidgin_set_urgent(GTK_WINDOW(mail_dialog->dialog), TRUE);
 
 	return data;
@@ -1503,7 +1513,9 @@
 	/* Setup the dialog */
 	gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE);
 	gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE);
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+#endif
 	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
 
 	/* Vertical box */
--- a/pidgin/gtkpounce.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkpounce.c	Mon Feb 27 22:45:47 2012 +0000
@@ -1018,7 +1018,11 @@
 static gboolean
 pounces_manager_configure_cb(GtkWidget *widget, GdkEventConfigure *event, PouncesManager *dialog)
 {
+#if GTK_CHECK_VERSION(2,18,0)
+	if (gtk_widget_get_visible(widget)) {
+#else
 	if (GTK_WIDGET_VISIBLE(widget)) {
+#endif
 		purple_prefs_set_int(PIDGIN_PREFS_ROOT "/pounces/dialog/width",  event->width);
 		purple_prefs_set_int(PIDGIN_PREFS_ROOT "/pounces/dialog/height", event->height);
 	}
--- a/pidgin/gtkprefs.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkprefs.c	Mon Feb 27 22:45:47 2012 +0000
@@ -187,29 +187,49 @@
 	return pidgin_add_widget_to_vbox(GTK_BOX(page), title, sg, entry, TRUE, NULL);
 }
 
+/* TODO: Maybe move this up somewheres... */
+enum {
+	PREF_DROPDOWN_TEXT,
+	PREF_DROPDOWN_VALUE,
+	PREF_DROPDOWN_COUNT
+};
 
 static void
 dropdown_set(GObject *w, const char *key)
 {
 	const char *str_value;
 	int int_value;
+	gboolean bool_value;
 	PurplePrefType type;
+	GtkTreeIter iter;
+	GtkTreeModel *tree_model;
+
+	tree_model = gtk_combo_box_get_model(GTK_COMBO_BOX(w));
+	if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w), &iter))
+		return;
 
 	type = GPOINTER_TO_INT(g_object_get_data(w, "type"));
 
 	if (type == PURPLE_PREF_INT) {
-		int_value = GPOINTER_TO_INT(g_object_get_data(w, "value"));
+		gtk_tree_model_get(tree_model, &iter,
+		                   PREF_DROPDOWN_VALUE, &int_value,
+		                   -1);
 
 		purple_prefs_set_int(key, int_value);
 	}
 	else if (type == PURPLE_PREF_STRING) {
-		str_value = (const char *)g_object_get_data(w, "value");
+		gtk_tree_model_get(tree_model, &iter,
+		                   PREF_DROPDOWN_VALUE, &str_value,
+		                   -1);
 
 		purple_prefs_set_string(key, str_value);
 	}
 	else if (type == PURPLE_PREF_BOOLEAN) {
-		purple_prefs_set_bool(key,
-				GPOINTER_TO_INT(g_object_get_data(w, "value")));
+		gtk_tree_model_get(tree_model, &iter,
+		                   PREF_DROPDOWN_VALUE, &bool_value,
+		                   -1);
+
+		purple_prefs_set_bool(key, bool_value);
 	}
 }
 
@@ -217,69 +237,89 @@
 pidgin_prefs_dropdown_from_list(GtkWidget *box, const gchar *title,
 		PurplePrefType type, const char *key, GList *menuitems)
 {
-	GtkWidget  *dropdown, *opt, *menu;
+	GtkWidget  *dropdown;
 	GtkWidget  *label = NULL;
 	gchar      *text;
 	const char *stored_str = NULL;
 	int         stored_int = 0;
+	gboolean    stored_bool = FALSE;
 	int         int_value  = 0;
 	const char *str_value  = NULL;
-	int         o = 0;
+	gboolean    bool_value = FALSE;
+	GtkListStore *store = NULL;
+	GtkTreeIter iter;
+	GtkTreeIter active;
+	GtkCellRenderer *renderer;
 
 	g_return_val_if_fail(menuitems != NULL, NULL);
 
-	dropdown = gtk_option_menu_new();
-	menu = gtk_menu_new();
-
-	if (type == PURPLE_PREF_INT)
+	if (type == PURPLE_PREF_INT) {
+		store = gtk_list_store_new(PREF_DROPDOWN_COUNT, G_TYPE_STRING, G_TYPE_INT);
 		stored_int = purple_prefs_get_int(key);
-	else if (type == PURPLE_PREF_STRING)
+	} else if (type == PURPLE_PREF_STRING) {
+		store = gtk_list_store_new(PREF_DROPDOWN_COUNT, G_TYPE_STRING, G_TYPE_STRING);
 		stored_str = purple_prefs_get_string(key);
-
-	while (menuitems != NULL && (text = (char *) menuitems->data) != NULL) {
+	} else if (type == PURPLE_PREF_BOOLEAN) {
+		store = gtk_list_store_new(PREF_DROPDOWN_COUNT, G_TYPE_STRING, G_TYPE_BOOLEAN);
+		stored_bool = purple_prefs_get_bool(key);
+	} else {
+		g_warn_if_reached();
+		return NULL;
+	}
+
+	dropdown = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
+	g_object_set_data(G_OBJECT(dropdown), "type", GINT_TO_POINTER(type));
+
+	while (menuitems != NULL && (text = (char *)menuitems->data) != NULL) {
 		menuitems = g_list_next(menuitems);
 		g_return_val_if_fail(menuitems != NULL, NULL);
 
-		opt = gtk_menu_item_new_with_label(text);
-
-		g_object_set_data(G_OBJECT(opt), "type", GINT_TO_POINTER(type));
+		gtk_list_store_append(store, &iter);
+		gtk_list_store_set(store, &iter,
+		                   PREF_DROPDOWN_TEXT, text,
+		                   -1);
 
 		if (type == PURPLE_PREF_INT) {
 			int_value = GPOINTER_TO_INT(menuitems->data);
-			g_object_set_data(G_OBJECT(opt), "value",
-							  GINT_TO_POINTER(int_value));
+			gtk_list_store_set(store, &iter,
+			                   PREF_DROPDOWN_VALUE, int_value,
+			                   -1);
 		}
 		else if (type == PURPLE_PREF_STRING) {
 			str_value = (const char *)menuitems->data;
-
-			g_object_set_data(G_OBJECT(opt), "value", (char *)str_value);
+			gtk_list_store_set(store, &iter,
+			                   PREF_DROPDOWN_VALUE, str_value,
+			                   -1);
 		}
 		else if (type == PURPLE_PREF_BOOLEAN) {
-			g_object_set_data(G_OBJECT(opt), "value",
-					menuitems->data);
+			bool_value = (gboolean)GPOINTER_TO_INT(menuitems->data);
+			gtk_list_store_set(store, &iter,
+			                   PREF_DROPDOWN_VALUE, bool_value,
+			                   -1);
 		}
 
-		g_signal_connect(G_OBJECT(opt), "activate",
-						 G_CALLBACK(dropdown_set), (char *)key);
-
-		gtk_widget_show(opt);
-		gtk_menu_shell_append(GTK_MENU_SHELL(menu), opt);
-
 		if ((type == PURPLE_PREF_INT && stored_int == int_value) ||
 			(type == PURPLE_PREF_STRING && stored_str != NULL &&
 			 !strcmp(stored_str, str_value)) ||
 			(type == PURPLE_PREF_BOOLEAN &&
-			 (purple_prefs_get_bool(key) == GPOINTER_TO_INT(menuitems->data)))) {
-
-			gtk_menu_set_active(GTK_MENU(menu), o);
+			 (stored_bool == bool_value))) {
+
+			active = iter;
 		}
 
 		menuitems = g_list_next(menuitems);
-
-		o++;
 	}
 
-	gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu);
+	renderer = gtk_cell_renderer_text_new();
+	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dropdown), renderer, TRUE);
+	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dropdown), renderer,
+	                               "text", 0,
+	                               NULL);
+
+	gtk_combo_box_set_active_iter(GTK_COMBO_BOX(dropdown), &active);
+
+	g_signal_connect(G_OBJECT(dropdown), "changed",
+	                 G_CALLBACK(dropdown_set), (char *)key);
 
 	pidgin_add_widget_to_vbox(GTK_BOX(box), title, NULL, dropdown, FALSE, &label);
 
--- a/pidgin/gtkrequest.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkrequest.c	Mon Feb 27 22:45:47 2012 +0000
@@ -45,6 +45,21 @@
 #include <gcr/gcr-simple-certificate.h>
 #endif
 
+#if !GTK_CHECK_VERSION(2,18,0)
+#define gtk_widget_set_can_default(x,y) do {\
+	if (y) \
+		GTK_WIDGET_SET_FLAGS(x, GTK_CAN_DEFAULT); \
+	else \
+		GTK_WIDGET_UNSET_FLAGS(x, GTK_CAN_DEFAULT); \
+} while(0)
+#define gtk_widget_set_can_focus(x,y) do {\
+	if (y) \
+		GTK_WIDGET_SET_FLAGS(x, GTK_CAN_FOCUS); \
+	else \
+		GTK_WIDGET_UNSET_FLAGS(x, GTK_CAN_FOCUS); \
+} while(0)
+#endif
+
 static GtkWidget * create_account_field(PurpleRequestField *field);
 
 typedef struct
@@ -92,7 +107,9 @@
 {
 	GtkWidget *image;
 	GdkPixbuf *pixbuf;
+#if !GTK_CHECK_VERSION(2,12,0)
 	GtkTooltips *tips;
+#endif
 
 	if (!account)
 		return;
@@ -101,8 +118,12 @@
 	image = gtk_image_new_from_pixbuf(pixbuf);
 	g_object_unref(G_OBJECT(pixbuf));
 
+#if GTK_CHECK_VERSION(2,12,0)
+	gtk_widget_set_tooltip_text(image, purple_account_get_username(account));
+#else
 	tips = gtk_tooltips_new();
 	gtk_tooltips_set_tip(tips, image, purple_account_get_username(account), NULL);
+#endif
 
 	if (GTK_IS_DIALOG(cont)) {
 		gtk_box_pack_start(GTK_BOX(GTK_DIALOG(cont)->action_area), image, FALSE, TRUE, 0);
@@ -263,7 +284,11 @@
 {
 	generic_response_start(data);
 
+#if GTK_CHECK_VERSION(2,18,0)
+	if (!gtk_widget_has_focus(button))
+#else
 	if (!GTK_WIDGET_HAS_FOCUS(button))
+#endif
 		gtk_widget_grab_focus(button);
 
 	if (data->cbs[0] != NULL)
@@ -362,7 +387,9 @@
 	gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER/2);
 	if (!multiline)
 		gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+#endif
 	gtk_dialog_set_default_response(GTK_DIALOG(dialog), 0);
 	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
 
@@ -528,7 +555,9 @@
 	gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER/2);
 	gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER/2);
 	gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+#endif
 	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
 
 	/* Setup the main horizontal box */
@@ -650,7 +679,9 @@
 	gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER/2);
 	gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER/2);
 	gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+#endif
 	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
 
 	/* Setup the main horizontal box */
@@ -721,8 +752,8 @@
 
 
 	if (default_action == PURPLE_DEFAULT_ACTION_NONE) {
-		GTK_WIDGET_SET_FLAGS(img, GTK_CAN_DEFAULT);
-		GTK_WIDGET_SET_FLAGS(img, GTK_CAN_FOCUS);
+		gtk_widget_set_can_default(img, TRUE);
+		gtk_widget_set_can_focus(img, TRUE);
 		gtk_widget_grab_focus(img);
 		gtk_widget_grab_default(img);
 	} else
@@ -1305,12 +1336,12 @@
 
 	/* Cancel button */
 	button = pidgin_dialog_add_button(GTK_DIALOG(win), text_to_stock(cancel_text), G_CALLBACK(multifield_cancel_cb), data);
-	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+	gtk_widget_set_can_default(button, TRUE);
 
 	/* OK button */
 	button = pidgin_dialog_add_button(GTK_DIALOG(win), text_to_stock(ok_text), G_CALLBACK(multifield_ok_cb), data);
 	data->ok_button = button;
-	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+	gtk_widget_set_can_default(button, TRUE);
 	gtk_window_set_default(GTK_WINDOW(win), button);
 
 	pidgin_widget_decorate_account(hbox, account);
--- a/pidgin/gtksavedstatuses.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtksavedstatuses.c	Mon Feb 27 22:45:47 2012 +0000
@@ -524,7 +524,11 @@
 static gboolean
 configure_cb(GtkWidget *widget, GdkEventConfigure *event, StatusWindow *dialog)
 {
+#if GTK_CHECK_VERSION(2,18,0)
+	if (gtk_widget_get_visible(widget))
+#else
 	if (GTK_WIDGET_VISIBLE(widget))
+#endif
 	{
 		purple_prefs_set_int(PIDGIN_PREFS_ROOT "/status/dialog/width",  event->width);
 		purple_prefs_set_int(PIDGIN_PREFS_ROOT "/status/dialog/height", event->height);
--- a/pidgin/gtkscrollbook.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkscrollbook.c	Mon Feb 27 22:45:47 2012 +0000
@@ -147,7 +147,7 @@
 }
 
 static void
-switch_page_cb(GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, PidginScrollBook *scroll_book)
+switch_page_cb(GtkNotebook *notebook, GtkWidget *page, guint page_num, PidginScrollBook *scroll_book)
 {
 	int count;
 	count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(scroll_book->notebook));
--- a/pidgin/gtkstatusbox.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkstatusbox.c	Mon Feb 27 22:45:47 2012 +0000
@@ -70,6 +70,16 @@
 /* Timeout for typing notifications in seconds */
 #define TYPING_TIMEOUT 4
 
+#if !GTK_CHECK_VERSION(2,18,0)
+#define gtk_widget_is_sensitive(x) GTK_WIDGET_IS_SENSITIVE(x)
+#define gtk_widget_set_has_window(x, y) do { \
+	if (y) \
+		GTK_WIDGET_UNSET_FLAGS(x, GTK_WIDGET_NO_WINDOW); \
+	else \
+		GTK_WIDGET_SET_FLAGS(x, GTK_WIDGET_NO_WINDOW); \
+} while (0)
+#endif
+
 static void imhtml_changed_cb(GtkTextBuffer *buffer, void *data);
 static void imhtml_format_changed_cb(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons, void *data);
 static void remove_typing_cb(PidginStatusBox *box);
@@ -1749,7 +1759,7 @@
 	GtkWidget *toplevel;
 	GtkTreeSelection *sel;
 
-	GTK_WIDGET_SET_FLAGS (status_box, GTK_NO_WINDOW);
+	gtk_widget_set_has_window(GTK_WIDGET(status_box), FALSE);
 	status_box->imhtml_visible = FALSE;
 	status_box->network_available = purple_network_is_available();
 	status_box->connecting = FALSE;
@@ -2625,7 +2635,7 @@
 		purple_timeout_remove(status_box->typing);
 	status_box->typing = 0;
 
-	if (GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(status_box)))
+	if (gtk_widget_is_sensitive(GTK_WIDGET(status_box)))
 	{
 		if (type == PIDGIN_STATUS_BOX_TYPE_POPULAR || type == PIDGIN_STATUS_BOX_TYPE_SAVED_POPULAR)
 		{
@@ -2687,7 +2697,7 @@
 	}
 	g_list_free(accounts);
 
-	if (GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(status_box)))
+	if (gtk_widget_is_sensitive(GTK_WIDGET(status_box)))
 	{
 		if (status_box->imhtml_visible)
 		{
@@ -2743,7 +2753,7 @@
 static void imhtml_changed_cb(GtkTextBuffer *buffer, void *data)
 {
 	PidginStatusBox *status_box = (PidginStatusBox*)data;
-	if (GTK_WIDGET_IS_SENSITIVE(GTK_WIDGET(status_box)))
+	if (gtk_widget_is_sensitive(GTK_WIDGET(status_box)))
 	{
 		if (status_box->typing != 0) {
 			pidgin_status_box_pulse_typing(status_box);
--- a/pidgin/gtkutils.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/gtkutils.c	Mon Feb 27 22:45:47 2012 +0000
@@ -71,8 +71,20 @@
 #include "gtkwebviewtoolbar.h"
 #include "pidgin/minidialog.h"
 
+#if !GTK_CHECK_VERSION(2,18,0)
+#define gtk_widget_get_visible(x) GTK_WIDGET_VISIBLE(x)
+#define gtk_widget_is_sensitive(x) GTK_WIDGET_IS_SENSITIVE(x)
+#endif
+
+enum {
+	AOP_ICON_COLUMN,
+	AOP_NAME_COLUMN,
+	AOP_DATA_COLUMN,
+	AOP_COLUMN_COUNT
+};
+
 typedef struct {
-	GtkWidget *menu;
+	GtkTreeModel *model;
 	gint default_item;
 } AopMenu;
 
@@ -381,7 +393,7 @@
 	if (to_toggle == NULL)
 		return;
 
-	sensitivity = GTK_WIDGET_IS_SENSITIVE(to_toggle);
+	sensitivity = gtk_widget_is_sensitive(to_toggle);
 
 	gtk_widget_set_sensitive(to_toggle, !sensitivity);
 }
@@ -398,7 +410,7 @@
 		if (element == NULL)
 			continue;
 
-		sensitivity = GTK_WIDGET_IS_SENSITIVE(element);
+		sensitivity = gtk_widget_is_sensitive(element);
 
 		gtk_widget_set_sensitive(element, !sensitivity);
 	}
@@ -410,7 +422,7 @@
 	if (to_toggle == NULL)
 		return;
 
-	if (GTK_WIDGET_VISIBLE(to_toggle))
+	if (gtk_widget_get_visible(to_toggle))
 		gtk_widget_hide(to_toggle);
 	else
 		gtk_widget_show(to_toggle);
@@ -611,68 +623,36 @@
 }
 
 static gpointer
-aop_option_menu_get_selected(GtkWidget *optmenu, GtkWidget **p_item)
+aop_option_menu_get_selected(GtkWidget *optmenu)
 {
-	GtkWidget *menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu));
-	GtkWidget *item = gtk_menu_get_active(GTK_MENU(menu));
-	if (p_item)
-		(*p_item) = item;
-	return item ? g_object_get_data(G_OBJECT(item), "aop_per_item_data") : NULL;
+	gpointer data = NULL;
+	GtkTreeIter iter;
+
+	g_return_val_if_fail(optmenu != NULL, NULL);
+
+	if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(optmenu), &iter))
+		gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(optmenu)),
+		                   &iter, AOP_DATA_COLUMN, &data, -1);
+
+	return data;
 }
 
 static void
 aop_menu_cb(GtkWidget *optmenu, GCallback cb)
 {
-	GtkWidget *item;
-	gpointer per_item_data;
-
-	per_item_data = aop_option_menu_get_selected(optmenu, &item);
-
 	if (cb != NULL) {
-		((void (*)(GtkWidget *, gpointer, gpointer))cb)(item, per_item_data, g_object_get_data(G_OBJECT(optmenu), "user_data"));
+		((void (*)(GtkWidget *, gpointer, gpointer))cb)(optmenu,
+			aop_option_menu_get_selected(optmenu),
+			g_object_get_data(G_OBJECT(optmenu), "user_data"));
 	}
 }
 
-static GtkWidget *
-aop_menu_item_new(GtkSizeGroup *sg, GdkPixbuf *pixbuf, const char *lbl, gpointer per_item_data, const char *data)
+static void
+aop_option_menu_replace_menu(GtkWidget *optmenu, AopMenu *new_aop_menu)
 {
-	GtkWidget *item;
-	GtkWidget *hbox;
-	GtkWidget *image;
-	GtkWidget *label;
-
-	item = gtk_menu_item_new();
-	gtk_widget_show(item);
-
-	hbox = gtk_hbox_new(FALSE, 4);
-	gtk_widget_show(hbox);
-
-	/* Create the image */
-	if (pixbuf == NULL)
-		image = gtk_image_new();
-	else
-		image = gtk_image_new_from_pixbuf(pixbuf);
-	gtk_widget_show(image);
-
-	if (sg)
-		gtk_size_group_add_widget(sg, image);
-
-	/* Create the label */
-	label = gtk_label_new (lbl);
-	gtk_widget_show (label);
-	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
-	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-
-	gtk_container_add(GTK_CONTAINER(item), hbox);
-	gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
-
-	g_object_set_data(G_OBJECT (item), data, per_item_data);
-	g_object_set_data(G_OBJECT (item), "aop_per_item_data", per_item_data);
-
-	pidgin_set_accessible_label(item, label);
-
-	return item;
+	gtk_combo_box_set_model(GTK_COMBO_BOX(optmenu), new_aop_menu->model);
+	gtk_combo_box_set_active(GTK_COMBO_BOX(optmenu), new_aop_menu->default_item);
+	g_free(new_aop_menu);
 }
 
 static GdkPixbuf *
@@ -713,16 +693,17 @@
 static GtkWidget *
 aop_option_menu_new(AopMenu *aop_menu, GCallback cb, gpointer user_data)
 {
-	GtkWidget *optmenu;
-
-	optmenu = gtk_option_menu_new();
+	GtkWidget *optmenu = NULL;
+	GtkCellRenderer *cr = NULL;
+
+	optmenu = gtk_combo_box_new();
 	gtk_widget_show(optmenu);
-	gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), aop_menu->menu);
-
-	if (aop_menu->default_item != -1)
-		gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), aop_menu->default_item);
-
-	g_object_set_data_full(G_OBJECT(optmenu), "aop_menu", aop_menu, (GDestroyNotify)g_free);
+	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(optmenu), cr = gtk_cell_renderer_pixbuf_new(), FALSE);
+	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(optmenu), cr, "pixbuf", AOP_ICON_COLUMN);
+	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(optmenu), cr = gtk_cell_renderer_text_new(), TRUE);
+	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(optmenu), cr, "text", AOP_NAME_COLUMN);
+
+	aop_option_menu_replace_menu(optmenu, aop_menu);
 	g_object_set_data(G_OBJECT(optmenu), "user_data", user_data);
 
 	g_signal_connect(G_OBJECT(optmenu), "changed", G_CALLBACK(aop_menu_cb), cb);
@@ -731,32 +712,20 @@
 }
 
 static void
-aop_option_menu_replace_menu(GtkWidget *optmenu, AopMenu *new_aop_menu)
-{
-	if (gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)))
-		gtk_option_menu_remove_menu(GTK_OPTION_MENU(optmenu));
-
-	gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), new_aop_menu->menu);
-
-	if (new_aop_menu->default_item != -1)
-		gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), new_aop_menu->default_item);
-
-	g_object_set_data_full(G_OBJECT(optmenu), "aop_menu", new_aop_menu, (GDestroyNotify)g_free);
-}
-
-static void
 aop_option_menu_select_by_data(GtkWidget *optmenu, gpointer data)
 {
-	guint idx;
-	GList *llItr = NULL;
-
-	for (idx = 0, llItr = GTK_MENU_SHELL(gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)))->children;
-	     llItr != NULL;
-	     llItr = llItr->next, idx++) {
-		if (data == g_object_get_data(G_OBJECT(llItr->data), "aop_per_item_data")) {
-			gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), idx);
-			break;
-		}
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gpointer iter_data;
+	model = gtk_combo_box_get_model(GTK_COMBO_BOX(optmenu));
+	if (gtk_tree_model_get_iter_first(model, &iter)) {
+		do {
+			gtk_tree_model_get(model, &iter, AOP_DATA_COLUMN, &iter_data, -1);
+			if (iter_data == data) {
+				gtk_combo_box_set_active_iter(GTK_COMBO_BOX(optmenu), &iter);
+				return;
+			}
+		} while (gtk_tree_model_iter_next(model, &iter));
 	}
 }
 
@@ -766,21 +735,16 @@
 	AopMenu *aop_menu = NULL;
 	PurplePlugin *plugin;
 	GdkPixbuf *pixbuf = NULL;
-	GtkSizeGroup *sg;
+	GtkTreeIter iter;
+	GtkListStore *ls;
 	GList *p;
-	const char *gtalk_name = NULL, *facebook_name = NULL;
 	int i;
 
+	ls = gtk_list_store_new(AOP_COLUMN_COUNT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
+
 	aop_menu = g_malloc0(sizeof(AopMenu));
-	aop_menu->default_item = -1;
-	aop_menu->menu = gtk_menu_new();
-	gtk_widget_show(aop_menu->menu);
-	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-
-	if (purple_find_prpl("prpl-jabber")) {
-		gtalk_name = _("Google Talk");
-		facebook_name = _("Facebook (XMPP)");
-	}
+	aop_menu->default_item = 0;
+	aop_menu->model = GTK_TREE_MODEL(ls);
 
 	for (p = purple_plugins_get_protocols(), i = 0;
 		 p != NULL;
@@ -788,48 +752,14 @@
 
 		plugin = (PurplePlugin *)p->data;
 
-		if (gtalk_name && strcmp(gtalk_name, plugin->info->name) < 0) {
-			char *filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols",
-			                                  "16", "google-talk.png", NULL);
-			GtkWidget *item;
-
-			pixbuf = pidgin_pixbuf_new_from_file(filename);
-			g_free(filename);
-
-			gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu),
-				item = aop_menu_item_new(sg, pixbuf, gtalk_name, "prpl-jabber", "protocol"));
-			g_object_set_data(G_OBJECT(item), "fakegoogle", GINT_TO_POINTER(1));
-
-			if (pixbuf)
-				g_object_unref(pixbuf);
-
-			gtalk_name = NULL;
-			i++;
-		}
-
-		if (facebook_name && strcmp(facebook_name, plugin->info->name) < 0) {
-			char *filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols",
-			                                  "16", "facebook.png", NULL);
-			GtkWidget *item;
-
-			pixbuf = pidgin_pixbuf_new_from_file(filename);
-			g_free(filename);
-
-			gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu),
-				item = aop_menu_item_new(sg, pixbuf, facebook_name, "prpl-jabber", "protocol"));
-			g_object_set_data(G_OBJECT(item), "fakefacebook", GINT_TO_POINTER(1));
-
-			if (pixbuf)
-				g_object_unref(pixbuf);
-
-			facebook_name = NULL;
-			i++;
-		}
-
 		pixbuf = pidgin_create_prpl_icon_from_prpl(plugin, PIDGIN_PRPL_ICON_SMALL, NULL);
 
-		gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu),
-			aop_menu_item_new(sg, pixbuf, plugin->info->name, plugin->info->id, "protocol"));
+		gtk_list_store_append(ls, &iter);
+		gtk_list_store_set(ls, &iter,
+		                   AOP_ICON_COLUMN, pixbuf,
+		                   AOP_NAME_COLUMN, plugin->info->name,
+		                   AOP_DATA_COLUMN, plugin->info->id,
+		                   -1);
 
 		if (pixbuf)
 			g_object_unref(pixbuf);
@@ -838,8 +768,6 @@
 			aop_menu->default_item = i;
 	}
 
-	g_object_unref(sg);
-
 	return aop_menu;
 }
 
@@ -853,13 +781,13 @@
 const char *
 pidgin_protocol_option_menu_get_selected(GtkWidget *optmenu)
 {
-	return (const char *)aop_option_menu_get_selected(optmenu, NULL);
+	return (const char *)aop_option_menu_get_selected(optmenu);
 }
 
 PurpleAccount *
 pidgin_account_option_menu_get_selected(GtkWidget *optmenu)
 {
-	return (PurpleAccount *)aop_option_menu_get_selected(optmenu, NULL);
+	return (PurpleAccount *)aop_option_menu_get_selected(optmenu);
 }
 
 static AopMenu *
@@ -871,7 +799,8 @@
 	GdkPixbuf *pixbuf = NULL;
 	GList *list;
 	GList *p;
-	GtkSizeGroup *sg;
+	GtkListStore *ls;
+	GtkTreeIter iter;
 	int i;
 	char buf[256];
 
@@ -880,11 +809,11 @@
 	else
 		list = purple_connections_get_all();
 
+	ls = gtk_list_store_new(AOP_COLUMN_COUNT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
+
 	aop_menu = g_malloc0(sizeof(AopMenu));
-	aop_menu->default_item = -1;
-	aop_menu->menu = gtk_menu_new();
-	gtk_widget_show(aop_menu->menu);
-	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+	aop_menu->default_item = 0;
+	aop_menu->model = GTK_TREE_MODEL(ls);
 
 	for (p = list, i = 0; p != NULL; p = p->next, i++) {
 		if (show_all)
@@ -919,8 +848,12 @@
 					   purple_account_get_protocol_name(account));
 		}
 
-		gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu),
-			aop_menu_item_new(sg, pixbuf, buf, account, "account"));
+		gtk_list_store_append(ls, &iter);
+		gtk_list_store_set(ls, &iter, 
+		                   AOP_ICON_COLUMN, pixbuf,
+		                   AOP_NAME_COLUMN, buf,
+		                   AOP_DATA_COLUMN, account,
+		                   -1);
 
 		if (pixbuf)
 			g_object_unref(pixbuf);
@@ -929,8 +862,6 @@
 			aop_menu->default_item = i;
 	}
 
-	g_object_unref(sg);
-
 	return aop_menu;
 }
 
@@ -941,7 +872,7 @@
 	PurpleAccount *account;
 	PurpleFilterAccountFunc filter_func;
 
-	account = (PurpleAccount *)aop_option_menu_get_selected(optmenu, NULL);
+	account = (PurpleAccount *)aop_option_menu_get_selected(optmenu);
 	show_all = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(optmenu), "show_all"));
 	filter_func = g_object_get_data(G_OBJECT(optmenu), "filter_func");
 
@@ -1965,6 +1896,15 @@
 	return menuitem;
 }
 
+enum {
+	COMPLETION_DISPLAYED_COLUMN,  /* displayed completion value */
+	COMPLETION_BUDDY_COLUMN,      /* buddy name */
+	COMPLETION_NORMALIZED_COLUMN, /* UTF-8 normalized & casefolded buddy name */
+	COMPLETION_COMPARISON_COLUMN, /* UTF-8 normalized & casefolded value for comparison */
+	COMPLETION_ACCOUNT_COLUMN,    /* account */
+	COMPLETION_COLUMN_COUNT
+};
+
 typedef struct
 {
 	GtkWidget *entry;
@@ -1984,10 +1924,10 @@
 	GValue val2;
 	const char *tmp;
 
-	model = gtk_entry_completion_get_model (completion);
+	model = gtk_entry_completion_get_model(completion);
 
 	val1.g_type = 0;
-	gtk_tree_model_get_value(model, iter, 2, &val1);
+	gtk_tree_model_get_value(model, iter, COMPLETION_NORMALIZED_COLUMN, &val1);
 	tmp = g_value_get_string(&val1);
 	if (tmp != NULL && purple_str_has_prefix(tmp, key))
 	{
@@ -1997,7 +1937,7 @@
 	g_value_unset(&val1);
 
 	val2.g_type = 0;
-	gtk_tree_model_get_value(model, iter, 3, &val2);
+	gtk_tree_model_get_value(model, iter, COMPLETION_COMPARISON_COLUMN, &val2);
 	tmp = g_value_get_string(&val2);
 	if (tmp != NULL && purple_str_has_prefix(tmp, key))
 	{
@@ -2017,11 +1957,11 @@
 	PurpleAccount *account;
 
 	val.g_type = 0;
-	gtk_tree_model_get_value(model, iter, 1, &val);
+	gtk_tree_model_get_value(model, iter, COMPLETION_BUDDY_COLUMN, &val);
 	gtk_entry_set_text(GTK_ENTRY(data->entry), g_value_get_string(&val));
 	g_value_unset(&val);
 
-	gtk_tree_model_get_value(model, iter, 4, &val);
+	gtk_tree_model_get_value(model, iter, COMPLETION_ACCOUNT_COLUMN, &val);
 	account = g_value_get_pointer(&val);
 	g_value_unset(&val);
 
@@ -2058,11 +1998,11 @@
 
 		gtk_list_store_append(store, &iter);
 		gtk_list_store_set(store, &iter,
-				0, completion_entry,
-				1, buddyname,
-				2, normalized_buddyname,
-				3, tmp,
-				4, account,
+				COMPLETION_DISPLAYED_COLUMN, completion_entry,
+				COMPLETION_BUDDY_COLUMN, buddyname,
+				COMPLETION_NORMALIZED_COLUMN, normalized_buddyname,
+				COMPLETION_COMPARISON_COLUMN, tmp,
+				COMPLETION_ACCOUNT_COLUMN, account,
 				-1);
 		g_free(completion_entry);
 		g_free(tmp);
@@ -2083,11 +2023,11 @@
 
 			gtk_list_store_append(store, &iter);
 			gtk_list_store_set(store, &iter,
-					0, completion_entry,
-					1, buddyname,
-					2, normalized_buddyname,
-					3, tmp,
-					4, account,
+					COMPLETION_DISPLAYED_COLUMN, completion_entry,
+					COMPLETION_BUDDY_COLUMN, buddyname,
+					COMPLETION_NORMALIZED_COLUMN, normalized_buddyname,
+					COMPLETION_COMPARISON_COLUMN, tmp,
+					COMPLETION_ACCOUNT_COLUMN, account,
 					-1);
 			g_free(completion_entry);
 			g_free(tmp);
@@ -2099,11 +2039,11 @@
 		/* Add the buddy's name. */
 		gtk_list_store_append(store, &iter);
 		gtk_list_store_set(store, &iter,
-				0, buddyname,
-				1, buddyname,
-				2, normalized_buddyname,
-				3, NULL,
-				4, account,
+				COMPLETION_DISPLAYED_COLUMN, buddyname,
+				COMPLETION_BUDDY_COLUMN, buddyname,
+				COMPLETION_NORMALIZED_COLUMN, normalized_buddyname,
+				COMPLETION_COMPARISON_COLUMN, NULL,
+				COMPLETION_ACCOUNT_COLUMN, account,
 				-1);
 	}
 
@@ -2201,7 +2141,9 @@
 	GtkEntryCompletion *completion;
 
 	data = g_new0(PidginCompletionData, 1);
-	store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
+	store = gtk_list_store_new(COMPLETION_COLUMN_COUNT, G_TYPE_STRING,
+	                           G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+	                           G_TYPE_POINTER);
 
 	data->entry = entry;
 	data->accountopt = accountopt;
@@ -2218,7 +2160,8 @@
 
 	/* Sort the completion list by buddy name */
 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
-	                                     1, GTK_SORT_ASCENDING);
+	                                     COMPLETION_BUDDY_COLUMN,
+	                                     GTK_SORT_ASCENDING);
 
 	completion = gtk_entry_completion_new();
 	gtk_entry_completion_set_match_func(completion, buddyname_completion_match_func, NULL, NULL);
@@ -2232,7 +2175,7 @@
 	gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store));
 	g_object_unref(store);
 
-	gtk_entry_completion_set_text_column(completion, 0);
+	gtk_entry_completion_set_text_column(completion, COMPLETION_DISPLAYED_COLUMN);
 
 	purple_signal_connect(purple_connections_get_handle(), "signed-on", entry,
 						PURPLE_CALLBACK(repopulate_autocomplete), data);
@@ -3067,7 +3010,7 @@
 		windows = g_list_delete_link(windows, windows);
 
 		if (window == widget ||
-				!GTK_WIDGET_VISIBLE(window))
+				!gtk_widget_get_visible(window))
 			continue;
 
 		if (!gdk_property_get(window->window, _WindowTime, _Cardinal, 0, sizeof(time_t), FALSE,
@@ -3121,7 +3064,7 @@
 		windows = g_list_delete_link(windows, windows);
 
 		if (window == widget ||
-				!GTK_WIDGET_VISIBLE(window)) {
+				!gtk_widget_get_visible(window)) {
 			continue;
 		}
 
@@ -3762,4 +3705,3 @@
 	gtk_imhtml_class_register_protocol("mailto:", NULL, NULL);
 	gtk_imhtml_class_register_protocol("gopher://", NULL, NULL);
 }
-
--- a/pidgin/plugins/contact_priority.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/plugins/contact_priority.c	Mon Feb 27 22:45:47 2012 +0000
@@ -35,11 +35,11 @@
 }
 
 static void
-account_update(GtkWidget *widget, GtkOptionMenu *optmenu)
+account_update(GtkWidget *widget, GtkWidget *optmenu)
 {
 	PurpleAccount *account = NULL;
 
-	account = g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(optmenu)))), "account");
+	account = pidgin_account_option_menu_get_selected(optmenu);
 	purple_account_set_int(account, "score", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)));
 }
 
@@ -147,8 +147,7 @@
 	gtk_box_pack_start(GTK_BOX(hbox), optmenu, FALSE, FALSE, 0);
 
 	/* this is where we set up the spin button we made above */
-	account = g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu))))),
-	                            "account");
+	account = pidgin_account_option_menu_get_selected(optmenu);
 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin),
 	                          (gdouble)purple_account_get_int(account, "score", 0));
 	gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(spin), GTK_ADJUSTMENT(adj));
--- a/pidgin/plugins/gestures/gestures.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/plugins/gestures/gestures.c	Mon Feb 27 22:45:47 2012 +0000
@@ -145,7 +145,6 @@
 }
 
 #if 0
-#if GTK_CHECK_VERSION(2,4,0)
 static void
 mouse_button_menu_cb(GtkComboBox *opt, gpointer data)
 {
@@ -153,15 +152,6 @@
 
 	gstroke_set_mouse_button(button + 2);
 }
-#else
-static void
-mouse_button_menu_cb(GtkMenuItem *item, gpointer data)
-{
-	int button = (int)data;
-
-	gstroke_set_mouse_button(button + 2);
-}
-#endif
 #endif
 
 static void
@@ -230,9 +220,6 @@
 	GtkWidget *toggle;
 #if 0
 	GtkWidget *opt;
-#if GTK_CHECK_VERSION(2,4,0)
-	GtkWidget *menu, *item;
-#endif
 #endif
 
 	/* Outside container */
@@ -243,7 +230,6 @@
 	vbox = pidgin_make_frame(ret, _("Mouse Gestures Configuration"));
 
 #if 0
-#if GTK_CHECK_VERSION(2,4,0)
 	/* Mouse button drop-down menu */
 	opt = gtk_combo_box_new_text();
 
@@ -255,26 +241,6 @@
 	gtk_box_pack_start(GTK_BOX(vbox), opt, FALSE, FALSE, 0);
 	gtk_combo_box_set_active(GTK_COMBO_BOX(opt),
 							gstroke_get_mouse_button() - 2);
-#else
-	/* Mouse button drop-down menu */
-	menu = gtk_menu_new();
-	opt = gtk_option_menu_new();
-
-	item = gtk_menu_item_new_with_label(_("Middle mouse button"));
-	g_signal_connect(G_OBJECT(item), "activate",
-					 G_CALLBACK(mouse_button_menu_cb), opt);
-	gtk_menu_append(menu, item);
-
-	item = gtk_menu_item_new_with_label(_("Right mouse button"));
-	g_signal_connect(G_OBJECT(item), "activate",
-					 G_CALLBACK(mouse_button_menu_cb), opt);
-	gtk_menu_append(menu, item);
-
-	gtk_box_pack_start(GTK_BOX(vbox), opt, FALSE, FALSE, 0);
-	gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
-	gtk_option_menu_set_history(GTK_OPTION_MENU(opt),
-								gstroke_get_mouse_button() - 2);
-#endif
 #endif
 
 	/* "Visual gesture display" checkbox */
--- a/pidgin/plugins/themeedit.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/plugins/themeedit.c	Mon Feb 27 22:45:47 2012 +0000
@@ -306,7 +306,9 @@
 		}
 	}
 
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(dialog), TRUE);
+#endif
 #ifdef NOT_SADRUL
 	pidgin_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_SAVE, G_CALLBACK(save_blist_theme), dialog);
 #endif
--- a/pidgin/plugins/ticker/gtkticker.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/plugins/ticker/gtkticker.c	Mon Feb 27 22:45:47 2012 +0000
@@ -21,28 +21,24 @@
  * GtkTicker Copyright 2000 Syd Logan
  */
 
-/* FIXME: GTK+ deprecated GTK_WIDGET_MAPPED/REALIZED, but don't provide
-          accessor functions yet. */
-#undef GSEAL_ENABLE
-
 #include "gtkticker.h"
 #include <gtk/gtk.h>
 
-/* These don't seem to be in a release yet. See BZ #69872 */
-#define gtk_widget_is_mapped(x) GTK_WIDGET_MAPPED(x)
-#define gtk_widget_is_realized(x) GTK_WIDGET_REALIZED(x)
+#if !GTK_CHECK_VERSION(2,20,0)
+#define gtk_widget_get_mapped(x) GTK_WIDGET_MAPPED(x)
+#define gtk_widget_set_mapped(x,y) do {\
+	if (y) \
+		GTK_WIDGET_SET_FLAGS(x, GTK_MAPPED); \
+	else \
+		GTK_WIDGET_UNSET_FLAGS(x, GTK_MAPPED); \
+} while(0)
+#define gtk_widget_get_realized(x) GTK_WIDGET_REALIZED(x)
 #define gtk_widget_set_realized(x,y) do {\
 	if (y) \
 		GTK_WIDGET_SET_FLAGS(x, GTK_REALIZED); \
 	else \
 		GTK_WIDGET_UNSET_FLAGS(x, GTK_REALIZED); \
 } while(0)
-#define gtk_widget_set_mapped(x,y) do {\
-	if (y) \
-		GTK_WIDGET_SET_FLAGS(x, GTK_MAPPED); \
-	else \
-		GTK_WIDGET_UNSET_FLAGS(x, GTK_MAPPED); \
-} while(0)
 
 #if !GTK_CHECK_VERSION(2,18,0)
 #define gtk_widget_get_visible(x) GTK_WIDGET_VISIBLE(x)
@@ -51,6 +47,7 @@
 #define gtk_widget_get_window(x) x->window
 #endif
 #endif
+#endif
 
 static void gtk_ticker_compute_offsets (GtkTicker    *ticker);
 static void gtk_ticker_class_init    (GtkTickerClass    *klass);
@@ -181,13 +178,13 @@
 
 	ticker->children = g_list_append (ticker->children, child_info);
 
-	if (gtk_widget_is_realized (ticker))
+	if (gtk_widget_get_realized (GTK_WIDGET (ticker)))
 		gtk_widget_realize (widget);
 
 	if (gtk_widget_get_visible (GTK_WIDGET (ticker)) &&
 		gtk_widget_get_visible (widget))
 	{
-		if (gtk_widget_is_mapped (GTK_WIDGET (ticker)))
+		if (gtk_widget_get_mapped (GTK_WIDGET (ticker)))
 			gtk_widget_map (widget);
 
 		gtk_widget_queue_resize (GTK_WIDGET (ticker));
@@ -298,7 +295,7 @@
 		children = children->next;
 
 		if (gtk_widget_get_visible (child->widget) &&
-				!gtk_widget_is_mapped (child->widget))
+				!gtk_widget_get_mapped (child->widget))
 			gtk_widget_map (child->widget);
 	}
 
@@ -474,7 +471,7 @@
 #else
 	widget->allocation = *allocation;
 #endif
-	if (gtk_widget_is_realized (widget))
+	if (gtk_widget_get_realized (widget))
 		gdk_window_move_resize (gtk_widget_get_window (widget),
 				allocation->x,
 				allocation->y,
--- a/pidgin/plugins/vvconfig.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/plugins/vvconfig.c	Mon Feb 27 22:45:47 2012 +0000
@@ -629,7 +629,7 @@
 }
 
 static void
-voice_test_frame_destroy_cb(GtkObject *w, GstElement *pipeline)
+voice_test_frame_destroy_cb(GtkWidget *w, GstElement *pipeline)
 {
 	g_return_if_fail(GST_IS_ELEMENT(pipeline));
 
@@ -704,7 +704,7 @@
 
 	gtk_range_set_value(GTK_RANGE(volume),
 			purple_prefs_get_int("/purple/media/audio/volume/input"));
-	gtk_widget_set(volume, "draw-value", FALSE, NULL);
+	gtk_scale_set_draw_value(GTK_SCALE(volume), FALSE);
 
 	gtk_range_set_value(GTK_RANGE(threshold),
 			purple_prefs_get_int("/purple/media/audio/silence_threshold"));
--- a/pidgin/plugins/xmppconsole.c	Mon Feb 27 06:44:05 2012 +0000
+++ b/pidgin/plugins/xmppconsole.c	Mon Feb 27 22:45:47 2012 +0000
@@ -274,7 +274,9 @@
 							GTK_STOCK_OK,
 							GTK_RESPONSE_ACCEPT,
 							NULL);
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+#endif
 	gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
 	gtk_container_set_border_width(GTK_CONTAINER(dialog), 12);
 #if GTK_CHECK_VERSION(2,14,0)
@@ -362,7 +364,9 @@
 							GTK_STOCK_OK,
 							GTK_RESPONSE_ACCEPT,
 							NULL);
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+#endif
 	gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
 	gtk_container_set_border_width(GTK_CONTAINER(dialog), 12);
 #if GTK_CHECK_VERSION(2,14,0)
@@ -520,7 +524,9 @@
 							GTK_STOCK_OK,
 							GTK_RESPONSE_ACCEPT,
 							NULL);
+#if !GTK_CHECK_VERSION(2,22,0)
 	gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+#endif
 	gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
 	gtk_container_set_border_width(GTK_CONTAINER(dialog), 12);
 #if GTK_CHECK_VERSION(2,14,0)