Merge fix for lost focus bug soc.2012.gg

Fri, 17 Aug 2012 17:22:23 +0200

author
Tomasz Wasilczyk <tomkiewicz@cpw.pidgin.im>
date
Fri, 17 Aug 2012 17:22:23 +0200
branch
soc.2012.gg
changeset 33341
481258ec30de
parent 33340
5f00ed891179 (current diff)
parent 33284
e3155594ea98 (diff)
child 33342
26ba5e4e8c24

Merge fix for lost focus bug

libpurple/protocols/gg/gg.c file | annotate | diff | comparison | revisions
--- a/COPYRIGHT	Fri Aug 17 11:00:00 2012 +0200
+++ b/COPYRIGHT	Fri Aug 17 17:22:23 2012 +0200
@@ -342,6 +342,7 @@
 Robert McQueen
 Mihály Mészáros
 Robert Mibus
+David Michael
 Lars T. Mikkelsen
 Benjamin Miller
 Kevin Miller
--- a/ChangeLog	Fri Aug 17 11:00:00 2012 +0200
+++ b/ChangeLog	Fri Aug 17 17:22:23 2012 +0200
@@ -49,8 +49,6 @@
 	* Invalid user moods can no longer be sent to the server.
 
 	Plugins:
-	* The Voice/Video Settings plugin supports using the sndio GStreamer
-	  backends. (Brad Smith) (#14414)
 	* The Offline Message Emulation plugin now adds a note that the message
 	  was an offline message. (Flavius Anton) (#2497)
 
@@ -59,6 +57,10 @@
 	* Fix a crash at startup with large contact list. Avatar support for
 	  buddies will be disabled till 3.0.0. (#15226, #14305)
 
+	Gadu-Gadu:
+	* Fix a crash at startup with large contact list. Avatar support for
+	  buddies will be disabled till 3.0.0. (#15226, #14305)
+
 	MSN:
 	* Fix a crash when removing a user before its icon is loaded. (Mark
 	  Barfield) (#15217)
@@ -67,6 +69,10 @@
 	* Fix a double-free in profile/picture loading code. (Mihai Serban)
 	  (#15053)
 
+	Plugins:
+	* The Voice/Video Settings plugin supports using the sndio GStreamer
+	 backends. (Brad Smith) (#14414)
+
 version 2.10.6 (07/06/2012):
 	Pidgin:
 	* Fix a bug that requires a triple-click to open a conversation
--- a/libpurple/media/enum-types.h	Fri Aug 17 11:00:00 2012 +0200
+++ b/libpurple/media/enum-types.h	Fri Aug 17 17:22:23 2012 +0200
@@ -44,7 +44,7 @@
 	PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX,
 	PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX,
 	PURPLE_MEDIA_CANDIDATE_TYPE_RELAY,
-	PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST,
+	PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST
 } PurpleMediaCandidateType;
 
 /** Media caps */
@@ -56,14 +56,14 @@
 	PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION = 1 << 3,
 	PURPLE_MEDIA_CAPS_AUDIO_VIDEO = 1 << 4,
 	PURPLE_MEDIA_CAPS_MODIFY_SESSION = 1 << 5,
-	PURPLE_MEDIA_CAPS_CHANGE_DIRECTION = 1 << 6,
+	PURPLE_MEDIA_CAPS_CHANGE_DIRECTION = 1 << 6
 } PurpleMediaCaps;
 
 /** Media component types */
 typedef enum {
 	PURPLE_MEDIA_COMPONENT_NONE = 0,
 	PURPLE_MEDIA_COMPONENT_RTP = 1,
-	PURPLE_MEDIA_COMPONENT_RTCP = 2,
+	PURPLE_MEDIA_COMPONENT_RTCP = 2
 } PurpleMediaComponentType;
 
 /** Media info types */
@@ -76,13 +76,13 @@
 	PURPLE_MEDIA_INFO_PAUSE,
 	PURPLE_MEDIA_INFO_UNPAUSE,
 	PURPLE_MEDIA_INFO_HOLD,
-	PURPLE_MEDIA_INFO_UNHOLD,
+	PURPLE_MEDIA_INFO_UNHOLD
 } PurpleMediaInfoType;
 
 /** Media network protocols */
 typedef enum {
 	PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
-	PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
+	PURPLE_MEDIA_NETWORK_PROTOCOL_TCP
 } PurpleMediaNetworkProtocol;
 
 /** Media session types */
@@ -100,7 +100,7 @@
 typedef enum {
 	PURPLE_MEDIA_STATE_NEW = 0,
 	PURPLE_MEDIA_STATE_CONNECTED,
-	PURPLE_MEDIA_STATE_END,
+	PURPLE_MEDIA_STATE_END
 } PurpleMediaState;
 
 /**
--- a/pidgin/gtk3compat.h	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtk3compat.h	Fri Aug 17 17:22:23 2012 +0200
@@ -25,9 +25,17 @@
  * Also, any public API should not depend on this file.
  */
 
+#if !GTK_CHECK_VERSION(3,2,0)
+
+#define GTK_FONT_CHOOSER GTK_FONT_SELECTION_DIALOG
+#define gtk_font_chooser_dialog_new(x,y) gtk_font_selection_dialog_new(x)
+#define gtk_font_chooser_get_font gtk_font_selection_dialog_get_font_name
+#define gtk_font_chooser_set_font gtk_font_selection_dialog_set_font_name
+
 #if !GTK_CHECK_VERSION(3,0,0)
 
 #define gdk_x11_window_get_xid GDK_WINDOW_XWINDOW
+#define gtk_widget_get_preferred_size(x,y,z) gtk_widget_size_request(x,z)
 
 #if !GTK_CHECK_VERSION(2,24,0)
 
@@ -36,6 +44,7 @@
 #define GtkComboBoxText GtkComboBox
 #define GTK_COMBO_BOX_TEXT GTK_COMBO_BOX
 #define gtk_combo_box_text_new gtk_combo_box_new_text
+#define gtk_combo_box_text_new_with_entry gtk_combo_box_entry_new_text
 #define gtk_combo_box_text_append_text gtk_combo_box_append_text
 #define gtk_combo_box_text_get_active_text gtk_combo_box_get_active_text
 #define gtk_combo_box_text_remove gtk_combo_box_remove_text
@@ -168,5 +177,7 @@
 
 #endif /* 3.0.0 */
 
+#endif /* 3.2.0 */
+
 #endif /* _PIDGINGTK3COMPAT_H_ */
 
--- a/pidgin/gtkaccount.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkaccount.c	Fri Aug 17 17:22:23 2012 +0200
@@ -917,12 +917,13 @@
 				if (str_hints)
 				{
 					const GSList *hint_it = str_hints;
-					entry = gtk_combo_box_entry_new_text();
+					entry = gtk_combo_box_text_new_with_entry();
 					while (hint_it)
 					{
 						const gchar *hint = hint_it->data;
-						hint_it = g_list_next(hint_it);
-						gtk_combo_box_append_text(GTK_COMBO_BOX(entry), hint);
+						hint_it = g_slist_next(hint_it);
+						gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(entry),
+						                               hint);
 					}
 				}
 				else
@@ -941,7 +942,8 @@
 				}
 
 				if (str_value != NULL && str_hints)
-					gtk_entry_set_text(GTK_ENTRY(GTK_BIN(entry)->child), str_value);
+					gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry))),
+					                   str_value);
 				else
 					gtk_entry_set_text(GTK_ENTRY(entry), str_value);
 
@@ -1474,7 +1476,7 @@
 			switch (opt_entry->type) {
 				case PURPLE_PREF_STRING:
 					if (GTK_IS_COMBO_BOX(opt_entry->widget))
-						value = gtk_combo_box_get_active_text(GTK_COMBO_BOX(opt_entry->widget));
+						value = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(opt_entry->widget));
 					else
 						value = gtk_entry_get_text(GTK_ENTRY(opt_entry->widget));
 					purple_account_set_string(account, opt_entry->setting, value);
--- a/pidgin/gtkblist.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkblist.c	Fri Aug 17 17:22:23 2012 +0200
@@ -2965,7 +2965,11 @@
 static gboolean
 pidgin_blist_paint_tip(GtkWidget *widget, cairo_t *cr, gpointer null)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+	GtkStyleContext *context;
+#else
 	GtkStyle *style;
+#endif
 	int current_height, max_width;
 	int max_text_width;
 	int max_avatar_width;
@@ -2977,7 +2981,12 @@
 	if(gtkblist->tooltipdata == NULL)
 		return FALSE;
 
+#if GTK_CHECK_VERSION(3,0,0)
+	context = gtk_widget_get_style_context(gtkblist->tipwindow);
+	gtk_style_context_add_class(context, GTK_STYLE_CLASS_TOOLTIP);
+#else
 	style = gtk_widget_get_style(gtkblist->tipwindow);
+#endif
 
 	max_text_width = 0;
 	max_avatar_width = 0;
@@ -3007,27 +3016,34 @@
 		if (td->avatar && pidgin_gdk_pixbuf_is_opaque(td->avatar))
 		{
 #if GTK_CHECK_VERSION(3,0,0)
-			if (dir == GTK_TEXT_DIR_RTL)
-				gtk_paint_flat_box(style, cr, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-				                   gtkblist->tipwindow, "tooltip",
+			gtk_style_context_save(context);
+			gtk_style_context_add_class(context, GTK_STYLE_CLASS_FRAME);
+			if (dir == GTK_TEXT_DIR_RTL) {
+				gtk_render_frame(context, cr,
+				                 TOOLTIP_BORDER - 1, current_height - 1,
+				                 td->avatar_width + 2, td->avatar_height + 2);
+			} else {
+				gtk_render_frame(context, cr,
+				                 max_width - (td->avatar_width + TOOLTIP_BORDER) - 1,
+				                 current_height - 1,
+				                 td->avatar_width + 2, td->avatar_height + 2);
+			}
+			gtk_style_context_restore(context);
+#else
+			if (dir == GTK_TEXT_DIR_RTL) {
+				gtk_paint_flat_box(style, gtkblist->tipwindow->window,
+				                   GTK_STATE_NORMAL, GTK_SHADOW_OUT,
+				                   NULL, gtkblist->tipwindow, "tooltip",
 				                   TOOLTIP_BORDER - 1, current_height - 1,
 				                   td->avatar_width + 2, td->avatar_height + 2);
-			else
-				gtk_paint_flat_box(style, cr, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-				                   gtkblist->tipwindow, "tooltip",
+			} else {
+				gtk_paint_flat_box(style, gtkblist->tipwindow->window,
+				                   GTK_STATE_NORMAL, GTK_SHADOW_OUT,
+				                   NULL, gtkblist->tipwindow, "tooltip",
 				                   max_width - (td->avatar_width + TOOLTIP_BORDER) - 1,
-				                   current_height - 1,
-				                   td->avatar_width + 2, td->avatar_height + 2);
-#else
-			if (dir == GTK_TEXT_DIR_RTL)
-				gtk_paint_flat_box(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-				                   NULL, gtkblist->tipwindow, "tooltip",
-				                   TOOLTIP_BORDER -1, current_height -1, td->avatar_width +2, td->avatar_height + 2);
-			else
-				gtk_paint_flat_box(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-				                   NULL, gtkblist->tipwindow, "tooltip",
-				                   max_width - (td->avatar_width+ TOOLTIP_BORDER)-1,
-				                   current_height-1,td->avatar_width+2, td->avatar_height+2);
+				                   current_height - 1, td->avatar_width + 2,
+				                   td->avatar_height + 2);
+			}
 #endif
 		}
 
@@ -3067,14 +3083,13 @@
 		if (td->name_layout) {
 #if GTK_CHECK_VERSION(3,0,0)
 			if (dir == GTK_TEXT_DIR_RTL) {
-				gtk_paint_layout(style, cr, GTK_STATE_NORMAL, FALSE,
-				                 gtkblist->tipwindow, "tooltip",
-				                 max_width - (TOOLTIP_BORDER + status_size + SMALL_SPACE) - PANGO_PIXELS(300000),
-				                 current_height, td->name_layout);
+				gtk_render_layout(context, cr,
+				                  max_width - (TOOLTIP_BORDER + status_size + SMALL_SPACE) - PANGO_PIXELS(300000),
+				                  current_height, td->name_layout);
 			} else {
-				gtk_paint_layout(style, cr, GTK_STATE_NORMAL, FALSE,
-				                 gtkblist->tipwindow, "tooltip",
-				                 TOOLTIP_BORDER + status_size + SMALL_SPACE, current_height, td->name_layout);
+				gtk_render_layout(context, cr,
+				                  TOOLTIP_BORDER + status_size + SMALL_SPACE,
+				                  current_height, td->name_layout);
 			}
 #else
 			if (dir == GTK_TEXT_DIR_RTL) {
@@ -3093,21 +3108,22 @@
 		if (td->layout) {
 #if GTK_CHECK_VERSION(3,0,0)
 			if (dir != GTK_TEXT_DIR_RTL) {
-				gtk_paint_layout(style, cr, GTK_STATE_NORMAL, FALSE,
-				                 gtkblist->tipwindow, "tooltip",
-				                 TOOLTIP_BORDER + status_size + SMALL_SPACE, current_height + td->name_height, td->layout);
+				gtk_render_layout(context, cr,
+				                  TOOLTIP_BORDER + status_size + SMALL_SPACE,
+				                  current_height + td->name_height,
+				                  td->layout);
 			} else {
-				gtk_paint_layout(style, cr, GTK_STATE_NORMAL, FALSE,
-				                 gtkblist->tipwindow, "tooltip",
-				                 max_width - (TOOLTIP_BORDER + status_size + SMALL_SPACE) - PANGO_PIXELS(300000),
-				                 current_height + td->name_height,
-				                 td->layout);
+				gtk_render_layout(context, cr,
+				                  max_width - (TOOLTIP_BORDER + status_size + SMALL_SPACE) - PANGO_PIXELS(300000),
+				                  current_height + td->name_height,
+				                  td->layout);
 			}
 #else
 			if (dir != GTK_TEXT_DIR_RTL) {
 				gtk_paint_layout(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, FALSE,
 				                 NULL, gtkblist->tipwindow, "tooltip",
-				                 TOOLTIP_BORDER + status_size + SMALL_SPACE, current_height + td->name_height, td->layout);
+				                 TOOLTIP_BORDER + status_size + SMALL_SPACE,
+				                 current_height + td->name_height, td->layout);
 			} else {
 				gtk_paint_layout(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, FALSE,
 				                 NULL, gtkblist->tipwindow, "tooltip",
--- a/pidgin/gtkcellrendererexpander.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkcellrendererexpander.c	Fri Aug 17 17:22:23 2012 +0200
@@ -271,6 +271,9 @@
 	gint ypad;
 	gboolean is_expanded;
 	GtkAllocation allocation;
+#if GTK_CHECK_VERSION(3,0,0)
+	GtkStyleContext *context;
+#endif
 
 	if (!cellexpander->is_expander)
 		return;
@@ -294,12 +297,18 @@
 	height -= ypad*2;
 
 #if GTK_CHECK_VERSION(3,0,0)
-	gtk_paint_expander(gtk_widget_get_style(widget),
-	                   cr, state,
-	                   widget, "treeview",
-	                   cell_area->x + xpad + (width / 2),
-	                   cell_area->y + ypad + (height / 2),
-	                   is_expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED);
+	if (is_expanded)
+		state |= GTK_STATE_ACTIVE;
+	else
+		state &= ~GTK_STATE_ACTIVE;
+
+	context = gtk_widget_get_style_context(widget);
+	gtk_style_context_add_class(context, GTK_STYLE_CLASS_VIEW);
+	gtk_style_context_add_class(context, GTK_STYLE_CLASS_EXPANDER);
+	gtk_style_context_set_state(context, state);
+	gtk_render_expander(context, cr,
+	                    cell_area->x + xpad, cell_area->y + ypad,
+	                    width, height);
 #else
 	gtk_paint_expander(gtk_widget_get_style(widget),
 	                   window, state,
@@ -315,7 +324,7 @@
 
 #if GTK_CHECK_VERSION(3,0,0)
 	if (is_expanded && !set)
-		gtk_paint_hline(gtk_widget_get_style(widget), cr, state, widget, NULL, 0,
+		gtk_render_line(context, cr, 0, cell_area->y + cell_area->height,
 		                allocation.width, cell_area->y + cell_area->height);
 #else
 	if (is_expanded && !set)
--- a/pidgin/gtkconv.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkconv.c	Fri Aug 17 17:22:23 2012 +0200
@@ -171,6 +171,8 @@
 	{"application/x-im-contact", 0, PIDGIN_DRAG_IM_CONTACT}
 };
 
+static GtkTargetList *webkit_dnd_targets = NULL;
+
 typedef struct {
 	GtkWidget *window;
 
@@ -337,7 +339,11 @@
 conversation_entry_clear(PidginConversation *gtkconv)
 {
 	GtkWebView *webview = GTK_WEBVIEW(gtkconv->entry);
-	gtk_webview_load_html_string(webview, "");
+
+	//XXX: hotfix for not focused entry after sending a message
+	//gtk_webview_load_html_string(webview, "");
+	gtk_webview_load_html_string_with_selection(webview, "<div id='caret'></div>");
+
 #if 0
 	/* TODO WebKit */
 	gtk_source_undo_manager_begin_not_undoable_action(webview->undo_manager);
@@ -704,6 +710,7 @@
 
 	conversation_entry_clear(gtkconv);
 	gtkconv_set_unseen(gtkconv, PIDGIN_UNSEEN_NONE);
+	gtk_widget_grab_focus(gtkconv->entry); // XXX: doesn't work
 }
 
 static void
@@ -1618,38 +1625,49 @@
 	gtk_widget_grab_focus(PIDGIN_CONVERSATION(conv)->entry);
 }
 
-static GtkTextMark *
+static char *
+get_class_for_user(const char *who)
+{
+	return g_strconcat("-pidgin-user:", who, NULL);
+}
+
+static WebKitDOMNode *
 get_mark_for_user(PidginConversation *gtkconv, const char *who)
 {
-#if 0
-	/* TODO WebKit */
-	GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->webview));
-	char *tmp = g_strconcat("user:", who, NULL);
-	GtkTextMark *mark = gtk_text_buffer_get_mark(buf, tmp);
-
+	WebKitDOMDocument *doc;
+	WebKitDOMNodeList *nodes;
+	WebKitDOMNode *node = NULL;
+	gulong len;
+	char *tmp;
+
+	doc = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(gtkconv->webview));
+
+	tmp = get_class_for_user(who);
+	nodes = webkit_dom_document_get_elements_by_class_name(doc, tmp);
 	g_free(tmp);
-	return mark;
-#else
-	return NULL;
-#endif
+
+	if (nodes != NULL) {
+		len = webkit_dom_node_list_get_length(nodes);
+		if (len > 0)
+			node = webkit_dom_node_list_item(nodes, len - 1);
+	}
+
+	return node;
 }
 
 static void
 menu_last_said_cb(GtkWidget *w, PidginConversation *gtkconv)
 {
-/* TODO WEBKIT: This doesn't work yet, of course... */
-#if 0
-	GtkTextMark *mark;
+	WebKitDOMNode *node;
 	const char *who;
 
 	who = g_object_get_data(G_OBJECT(w), "user_data");
-	mark = get_mark_for_user(gtkconv, who);
-
-	if (mark != NULL)
-		gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0);
+	node = get_mark_for_user(gtkconv, who);
+
+	if (node != NULL)
+		webkit_dom_element_scroll_into_view(WEBKIT_DOM_ELEMENT(node), TRUE);
 	else
 		g_return_if_reached();
-#endif /* if 0 */
 }
 
 static GtkWidget *
@@ -1855,13 +1873,11 @@
 		chat_do_im(gtkconv, who);
 	} else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) {
 		/* Move to user's anchor */
-/* TODO WEBKIT: This isn't implemented yet. */
-#if 0
-		GtkTextMark *mark = get_mark_for_user(gtkconv, who);
-
-		if(mark != NULL)
-			gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0);
-#endif /* if 0 */
+		WebKitDOMNode *node = get_mark_for_user(gtkconv, who);
+
+		if (node != NULL)
+			webkit_dom_element_scroll_into_view(WEBKIT_DOM_ELEMENT(node), TRUE);
+
 	} else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
 		GtkWidget *menu = create_chat_menu (conv, who, gc);
 		gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
@@ -5527,7 +5543,6 @@
 	PurpleAccount *convaccount = purple_conversation_get_account(conv);
 	PurpleConnection *gc = purple_account_get_connection(convaccount);
 	PurplePluginProtocolInfo *prpl_info = gc ? PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc)) : NULL;
-	GdkAtom target = gtk_selection_data_get_target(sd);
 	const guchar *data = gtk_selection_data_get_data(sd);
 
 	if (info == PIDGIN_DRAG_BLIST_NODE)
@@ -5630,7 +5645,7 @@
 		gtk_drag_finish(dc, TRUE,
 		                gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t);
 	}
-	else if (target == gdk_atom_intern("text/uri-list", FALSE)) {
+	else if (info == WEBKIT_WEB_VIEW_TARGET_INFO_URI_LIST) {
 		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
 			pidgin_dnd_file_manage(sd, convaccount, purple_conversation_get_name(conv));
 		gtk_drag_finish(dc, TRUE,
@@ -5641,12 +5656,6 @@
 }
 
 
-static const GtkTargetEntry te[] =
-{
-	{"PURPLE_BLIST_NODE", GTK_TARGET_SAME_APP, PIDGIN_DRAG_BLIST_NODE},
-	{"application/x-im-contact", 0, PIDGIN_DRAG_IM_CONTACT}
-};
-
 static PidginConversation *
 pidgin_conv_find_gtkconv(PurpleConversation * conv)
 {
@@ -5756,6 +5765,7 @@
 	GtkWidget *pane = NULL;
 	GtkWidget *tab_cont;
 	PurpleBlistNode *convnode;
+	GtkTargetList *targets;
 
 	if (conv_type == PURPLE_CONV_TYPE_IM && (gtkconv = pidgin_conv_find_gtkconv(conv))) {
 		purple_conversation_set_ui_data(conv, gtkconv);
@@ -5804,33 +5814,45 @@
 	}
 
 	/* Setup drag-and-drop */
-	gtk_drag_dest_set(pane,
-	                  GTK_DEST_DEFAULT_MOTION |
-	                  GTK_DEST_DEFAULT_DROP,
-	                  te, sizeof(te) / sizeof(GtkTargetEntry),
-	                  GDK_ACTION_COPY);
-	gtk_drag_dest_set(pane,
-	                  GTK_DEST_DEFAULT_MOTION |
-	                  GTK_DEST_DEFAULT_DROP,
-	                  te, sizeof(te) / sizeof(GtkTargetEntry),
-	                  GDK_ACTION_COPY);
-	gtk_drag_dest_set(gtkconv->webview, 0,
-	                  te, sizeof(te) / sizeof(GtkTargetEntry),
-	                  GDK_ACTION_COPY);
-
-	gtk_drag_dest_set(gtkconv->entry, 0,
-	                  te, sizeof(te) / sizeof(GtkTargetEntry),
-	                  GDK_ACTION_COPY);
+	gtk_drag_dest_set(pane, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
+	                  NULL, 0, GDK_ACTION_COPY);
+	targets = gtk_target_list_new(dnd_targets, G_N_ELEMENTS(dnd_targets));
+	gtk_target_list_add(targets, gdk_atom_intern("text/uri-list", FALSE), 0,
+	                    WEBKIT_WEB_VIEW_TARGET_INFO_URI_LIST);
+	gtk_drag_dest_set_target_list(pane, targets);
+
+	if (webkit_dnd_targets) {
+		targets = webkit_dnd_targets;
+	} else {
+		GtkTargetEntry *entries;
+		gint count;
+
+		targets = webkit_web_view_get_paste_target_list(WEBKIT_WEB_VIEW(gtkconv->webview));
+		entries = gtk_target_table_new_from_list(targets, &count);
+		targets = gtk_target_list_new(entries, count);
+		gtk_target_table_free(entries, count);
+
+		gtk_target_list_add_table(targets, dnd_targets, G_N_ELEMENTS(dnd_targets));
+		webkit_dnd_targets = targets;
+	}
+
+	gtk_drag_dest_set(gtkconv->webview, 0, NULL, 0, GDK_ACTION_COPY);
+	gtk_drag_dest_set_target_list(gtkconv->webview, targets);
+
+	gtk_drag_dest_set(gtkconv->entry, 0, NULL, 0, GDK_ACTION_COPY);
+	gtk_drag_dest_set_target_list(gtkconv->entry, targets);
 
 	g_signal_connect(G_OBJECT(pane), "button_press_event",
 	                 G_CALLBACK(ignore_middle_click), NULL);
-// TODO: this crashes with webkit, fix it
-//	g_signal_connect(G_OBJECT(pane), "drag_data_received",
-//	                 G_CALLBACK(conv_dnd_recv), gtkconv);
-//	g_signal_connect(G_OBJECT(gtkconv->webview), "drag_data_received",
-//	                 G_CALLBACK(conv_dnd_recv), gtkconv);
-//	g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received",
-//	                 G_CALLBACK(conv_dnd_recv), gtkconv);
+	g_signal_connect(G_OBJECT(pane), "drag-data-received",
+	                 G_CALLBACK(conv_dnd_recv), gtkconv);
+#if 0
+	/* FIXME: WebKit confuses the dnd source when this is enabled */
+	g_signal_connect(G_OBJECT(gtkconv->webview), "drag-data-received",
+	                 G_CALLBACK(conv_dnd_recv), gtkconv);
+	g_signal_connect(G_OBJECT(gtkconv->entry), "drag-data-received",
+	                 G_CALLBACK(conv_dnd_recv), gtkconv);
+#endif
 
 	g_signal_connect(gtkconv->webview, "style-set", G_CALLBACK(set_typing_font), gtkconv);
 
@@ -6228,6 +6250,7 @@
 			replace = message;
 
 		} else if (g_str_has_prefix(cur, "%messageClasses%")) {
+			char *user;
 			GString *classes = g_string_new(NULL);
 #define ADD_CLASS(f, class) \
 			if (flags & f) \
@@ -6239,6 +6262,9 @@
 			ADD_CLASS(PURPLE_MESSAGE_DELAYED, "history ");
 			ADD_CLASS(PURPLE_MESSAGE_NICK, "mention ");
 #undef ADD_CLASS
+			user = get_class_for_user(name);
+			g_string_append(classes, user);
+			g_free(user);
 
 			replace = freeval = g_string_free(classes, FALSE);
 
@@ -6308,6 +6334,11 @@
 
 			replace = freeval = g_string_free(classes, FALSE);
 
+		} else if (g_str_has_prefix(cur, "%variant%")) {
+			replace = pidgin_conversation_theme_get_variant(PIDGIN_CONVERSATION(conv)->theme);
+			replace = freeval = g_strdup(replace);
+			purple_util_chrreplace(freeval, ' ', '_');
+
 		} else {
 			cur++;
 			continue;
@@ -9021,9 +9052,12 @@
 }
 
 static void
-notebook_init_grab(PidginWindow *gtkwin, GtkWidget *widget)
+notebook_init_grab(PidginWindow *gtkwin, GtkWidget *widget, GdkEvent *event)
 {
 	static GdkCursor *cursor = NULL;
+#if GTK_CHECK_VERSION(3,0,0)
+	GdkDevice *device;
+#endif
 
 	gtkwin->in_drag = TRUE;
 
@@ -9038,6 +9072,14 @@
 
 	/* Grab the pointer */
 	gtk_grab_add(gtkwin->notebook);
+#if GTK_CHECK_VERSION(3,0,0)
+	device = gdk_event_get_device(event);
+	if (!gdk_display_device_is_grabbed(gdk_device_get_display(device), device))
+		gdk_device_grab(device, gtk_widget_get_window(gtkwin->notebook),
+		                GDK_OWNERSHIP_WINDOW, FALSE,
+		                GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
+		                cursor, gdk_event_get_time(event));
+#else
 #ifndef _WIN32
 	/* Currently for win32 GTK+ (as of 2.2.1), gdk_pointer_is_grabbed will
 	   always be true after a button press. */
@@ -9045,7 +9087,8 @@
 #endif
 		gdk_pointer_grab(gtk_widget_get_window(gtkwin->notebook), FALSE,
 		                 GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
-		                 NULL, cursor, GDK_CURRENT_TIME);
+		                 NULL, cursor, gdk_event_get_time(event));
+#endif
 }
 
 static gboolean
@@ -9063,7 +9106,7 @@
 		    e->y_root >= win->drag_max_y) {
 
 			    win->in_predrag = FALSE;
-			    notebook_init_grab(win, widget);
+			    notebook_init_grab(win, widget, (GdkEvent *)e);
 		    }
 	}
 	else { /* Otherwise, draw the arrows. */
@@ -9075,7 +9118,7 @@
 		gboolean to_right = FALSE;
 
 		/* Get the window that the cursor is over. */
-		dest_win = pidgin_conv_window_get_at_xy(e->x_root, e->y_root);
+		dest_win = pidgin_conv_window_get_at_event((GdkEvent *)e);
 
 		if (dest_win == NULL) {
 			dnd_hints_hide_all();
@@ -9139,9 +9182,9 @@
 	    e->y_root <  win->drag_min_y ||
 	    e->y_root >= win->drag_max_y) {
 
-		    win->in_predrag = FALSE;
-		    notebook_init_grab(win, widget);
-	    }
+		win->in_predrag = FALSE;
+		notebook_init_grab(win, widget, (GdkEvent *)e);
+	}
 
 	return TRUE;
 }
@@ -9306,11 +9349,14 @@
 {
 	PidginWindow *dest_win;
 	GtkNotebook *dest_notebook;
-	PurpleConversation *conv;
+	PidginConversation *active_gtkconv;
 	PidginConversation *gtkconv;
 	gint dest_page_num = 0;
 	gboolean new_window = FALSE;
 	gboolean to_right = FALSE;
+#if GTK_CHECK_VERSION(3,0,0)
+	GdkDevice *device;
+#endif
 
 	/*
 	* Don't check to make sure that the event's window matches the
@@ -9320,10 +9366,18 @@
 	if (e->button != 1 && e->type != GDK_BUTTON_RELEASE)
 		return FALSE;
 
+#if GTK_CHECK_VERSION(3,0,0)
+	device = gdk_event_get_device((GdkEvent *)e);
+	if (gdk_display_device_is_grabbed(gdk_device_get_display(device), device)) {
+		gdk_device_ungrab(device, gdk_event_get_time((GdkEvent *)e));
+		gtk_grab_remove(widget);
+	}
+#else
 	if (gdk_pointer_is_grabbed()) {
-		gdk_pointer_ungrab(GDK_CURRENT_TIME);
+		gdk_pointer_ungrab(gdk_event_get_time((GdkEvent *)e));
 		gtk_grab_remove(widget);
 	}
+#endif
 
 	if (!win->in_predrag && !win->in_drag)
 		return FALSE;
@@ -9360,9 +9414,9 @@
 
 	dnd_hints_hide_all();
 
-	dest_win = pidgin_conv_window_get_at_xy(e->x_root, e->y_root);
-
-	conv = pidgin_conv_window_get_active_conversation(win);
+	dest_win = pidgin_conv_window_get_at_event((GdkEvent *)e);
+
+	active_gtkconv = pidgin_conv_window_get_active_gtkconv(win);
 
 	if (dest_win == NULL) {
 		/* If the current window doesn't have any other conversations,
@@ -9416,7 +9470,7 @@
 		}
 	}
 
-	gtk_widget_grab_focus(PIDGIN_CONVERSATION(conv)->entry);
+	gtk_widget_grab_focus(active_gtkconv->entry);
 
 	return TRUE;
 }
@@ -10045,18 +10099,20 @@
 void
 pidgin_conv_window_destroy(PidginWindow *win)
 {
-	purple_prefs_disconnect_by_handle(win);
-	window_list = g_list_remove(window_list, win);
+	PidginConversation *gtkconv;
+	GList *iter;
 
 	if (win->gtkconvs) {
-		while (win->gtkconvs) {
-			gboolean last = (win->gtkconvs->next == NULL);
-			close_conv_cb(NULL, win->gtkconvs->data);
-			if (last)
-				break;
+		for (iter = win->gtkconvs; iter != NULL; iter = iter->next) {
+			gtkconv = iter->data;
+			close_conv_cb(NULL, gtkconv);
 		}
 		return;
 	}
+
+	purple_prefs_disconnect_by_handle(win);
+	window_list = g_list_remove(window_list, win);
+
 	gtk_widget_destroy(win->notebook_menu);
 	gtk_widget_destroy(win->window);
 
@@ -10365,13 +10421,19 @@
 }
 
 PidginWindow *
-pidgin_conv_window_get_at_xy(int x, int y)
+pidgin_conv_window_get_at_event(GdkEvent *event)
 {
 	PidginWindow *win;
 	GdkWindow *gdkwin;
 	GList *l;
-
+	int x, y;
+
+#if GTK_CHECK_VERSION(3,0,0)
+	gdkwin = gdk_device_get_window_at_position(gdk_event_get_device(event),
+	                                           &x, &y);
+#else
 	gdkwin = gdk_window_at_pointer(&x, &y);
+#endif
 
 	if (gdkwin)
 		gdkwin = gdk_window_get_toplevel(gdkwin);
--- a/pidgin/gtkconvwin.h	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkconvwin.h	Fri Aug 17 17:22:23 2012 +0200
@@ -119,7 +119,7 @@
 PurpleConversation *pidgin_conv_window_get_active_conversation(const PidginWindow *win);
 gboolean pidgin_conv_window_is_active_conversation(const PurpleConversation *conv);
 gboolean pidgin_conv_window_has_focus(PidginWindow *win);
-PidginWindow *pidgin_conv_window_get_at_xy(int x, int y);
+PidginWindow *pidgin_conv_window_get_at_event(GdkEvent *event);
 GList *pidgin_conv_window_get_gtkconvs(PidginWindow *win);
 guint pidgin_conv_window_get_gtkconv_count(PidginWindow *win);
 
--- a/pidgin/gtkimhtml.h	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkimhtml.h	Fri Aug 17 17:22:23 2012 +0200
@@ -171,7 +171,7 @@
 	GTK_IMHTML_USE_POINTSIZE       = 1 << 8,
 	GTK_IMHTML_NO_FORMATTING       = 1 << 9,
 	GTK_IMHTML_USE_SMOOTHSCROLLING = 1 << 10,
-	GTK_IMHTML_NO_SMILEY           = 1 << 11,
+	GTK_IMHTML_NO_SMILEY           = 1 << 11
 } GtkIMHtmlOptions;
 
 enum {
--- a/pidgin/gtkmedia.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkmedia.c	Fri Aug 17 17:22:23 2012 +0200
@@ -443,7 +443,7 @@
 
 		gtk_widget_destroy(widget);
 
-		gtk_widget_size_request(GTK_WIDGET(gtkmedia), &req);
+		gtk_widget_get_preferred_size(GTK_WIDGET(gtkmedia), NULL, &req);
 		gtk_window_resize(GTK_WINDOW(gtkmedia), req.width, req.height);
 	}
 }
--- a/pidgin/gtkplugin.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkplugin.c	Fri Aug 17 17:22:23 2012 +0200
@@ -565,9 +565,9 @@
 {
 	PangoLayout *layout = g_object_get_data(G_OBJECT(tipwindow), "tooltip-plugin");
 #if GTK_CHECK_VERSION(3,0,0)
-	gtk_paint_layout(gtk_widget_get_style(tipwindow), cr, GTK_STATE_NORMAL, FALSE,
-	                 tipwindow, "tooltip",
-	                 6, 6, layout);
+	GtkStyleContext *context = gtk_widget_get_style_context(tipwindow);
+	gtk_style_context_add_class(context, GTK_STYLE_CLASS_TOOLTIP);
+	gtk_render_layout(context, cr, 6, 6, layout);
 #else
 	gtk_paint_layout(tipwindow->style, tipwindow->window, GTK_STATE_NORMAL, FALSE,
 	                 NULL, tipwindow, "tooltip",
--- a/pidgin/gtkroomlist.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkroomlist.c	Fri Aug 17 17:22:23 2012 +0200
@@ -356,12 +356,19 @@
 {
 	PurpleRoomlist *list = user_data;
 	PidginRoomlist *grl = purple_roomlist_get_ui_data(list);
-	GtkStyle *style;
 	int current_height, max_width;
 	int max_text_width;
 	GtkTextDirection dir = gtk_widget_get_direction(GTK_WIDGET(grl->tree));
+#if GTK_CHECK_VERSION(3,0,0)
+	GtkStyleContext *context;
+
+	context = gtk_widget_get_style_context(grl->tipwindow);
+	gtk_style_context_add_class(context, GTK_STYLE_CLASS_TOOLTIP);
+#else
+	GtkStyle *style;
 
 	style = gtk_widget_get_style(grl->tipwindow);
+#endif
 
 	max_text_width = MAX(grl->tip_width, grl->tip_name_width);
 	max_width = TOOLTIP_BORDER + SMALL_SPACE + max_text_width + TOOLTIP_BORDER;
@@ -370,30 +377,26 @@
 
 #if GTK_CHECK_VERSION(3,0,0)
 	if (dir == GTK_TEXT_DIR_RTL) {
-		gtk_paint_layout(style, cr, GTK_STATE_NORMAL, FALSE,
-		                 grl->tipwindow, "tooltip",
-		                 max_width - (TOOLTIP_BORDER + SMALL_SPACE) - PANGO_PIXELS(600000),
-		                 current_height,
-		                 grl->tip_name_layout);
+		gtk_render_layout(context, cr,
+		                  max_width - (TOOLTIP_BORDER + SMALL_SPACE) - PANGO_PIXELS(600000),
+		                  current_height,
+		                  grl->tip_name_layout);
 	} else {
-		gtk_paint_layout(style, cr, GTK_STATE_NORMAL, FALSE,
-		                 grl->tipwindow, "tooltip",
-		                 TOOLTIP_BORDER + SMALL_SPACE,
-		                 current_height,
-		                 grl->tip_name_layout);
+		gtk_render_layout(context, cr,
+		                  TOOLTIP_BORDER + SMALL_SPACE,
+		                  current_height,
+		                  grl->tip_name_layout);
 	}
 	if (dir != GTK_TEXT_DIR_RTL) {
-		gtk_paint_layout(style, cr, GTK_STATE_NORMAL, FALSE,
-		                 grl->tipwindow, "tooltip",
-		                 TOOLTIP_BORDER + SMALL_SPACE,
-		                 current_height + grl->tip_name_height,
-		                 grl->tip_layout);
+		gtk_render_layout(context, cr,
+		                  TOOLTIP_BORDER + SMALL_SPACE,
+		                  current_height + grl->tip_name_height,
+		                  grl->tip_layout);
 	} else {
-		gtk_paint_layout(style, cr, GTK_STATE_NORMAL, FALSE,
-		                 grl->tipwindow, "tooltip",
-		                 max_width - (TOOLTIP_BORDER + SMALL_SPACE) - PANGO_PIXELS(600000),
-		                 current_height + grl->tip_name_height,
-		                 grl->tip_layout);
+		gtk_render_layout(context, cr,
+		                  max_width - (TOOLTIP_BORDER + SMALL_SPACE) - PANGO_PIXELS(600000),
+		                  current_height + grl->tip_name_height,
+		                  grl->tip_layout);
 	}
 #else
 	if (dir == GTK_TEXT_DIR_RTL) {
--- a/pidgin/gtkstatusbox.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkstatusbox.c	Fri Aug 17 17:22:23 2012 +0200
@@ -95,8 +95,8 @@
 static void pidgin_status_box_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
 static void pidgin_status_box_redisplay_buddy_icon(PidginStatusBox *status_box);
 static void pidgin_status_box_forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data);
-static void pidgin_status_box_popup(PidginStatusBox *box);
-static void pidgin_status_box_popdown(PidginStatusBox *box);
+static void pidgin_status_box_popup(PidginStatusBox *box, GdkEvent *event);
+static void pidgin_status_box_popdown(PidginStatusBox *box, GdkEvent *event);
 
 static void do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift);
 static void icon_choose_cb(const char *filename, gpointer data);
@@ -1136,7 +1136,7 @@
 static gboolean
 combo_box_scroll_event_cb(GtkWidget *w, GdkEventScroll *event, GtkWebView *webview)
 {
-	pidgin_status_box_popup(PIDGIN_STATUS_BOX(w));
+	pidgin_status_box_popup(PIDGIN_STATUS_BOX(w), (GdkEvent *)event);
 	return TRUE;
 }
 
@@ -1331,7 +1331,7 @@
 	             "hscrollbar-policy", hpolicy,
 	             "vscrollbar-policy", vpolicy,
 	             NULL);
-	gtk_widget_size_request(status_box->popup_frame, &popup_req);
+	gtk_widget_get_preferred_size(status_box->popup_frame, NULL, &popup_req);
 
 	if (popup_req.width > *width) {
 		hpolicy = GTK_POLICY_ALWAYS;
@@ -1339,7 +1339,7 @@
 		             "hscrollbar-policy", hpolicy,
 		             "vscrollbar-policy", vpolicy,
 		             NULL);
-		gtk_widget_size_request(status_box->popup_frame, &popup_req);
+		gtk_widget_get_preferred_size(status_box->popup_frame, NULL, &popup_req);
 	}
 
 	*height = popup_req.height;
@@ -1381,28 +1381,52 @@
 }
 
 static gboolean
-popup_grab_on_window (GdkWindow *window,
-		      guint32    activate_time)
+popup_grab_on_window(GdkWindow *window, GdkEvent *event)
 {
-	if ((gdk_pointer_grab (window, TRUE,
-			 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
-			 GDK_POINTER_MOTION_MASK,
-			 NULL, NULL, activate_time) == 0))
+	guint32 activate_time = gdk_event_get_time(event);
+#if GTK_CHECK_VERSION(3,0,0)
+	GdkDevice *device = gdk_event_get_device(event);
+	GdkGrabStatus status;
+
+	status = gdk_device_grab(device, window, GDK_OWNERSHIP_WINDOW, TRUE,
+	                         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+	                         GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK |
+	                         GDK_KEY_RELEASE_MASK, NULL, activate_time);
+	if (status == GDK_GRAB_SUCCESS) {
+		status = gdk_device_grab(gdk_device_get_associated_device(device),
+		                         window, GDK_OWNERSHIP_WINDOW, TRUE,
+		                         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+		                         GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK |
+		                         GDK_KEY_RELEASE_MASK, NULL, activate_time);
+		if (status == GDK_GRAB_SUCCESS)
+			return TRUE;
+		else
+			gdk_device_ungrab(device, activate_time);
+	}
+
+	return FALSE;
+#else
+	if ((gdk_pointer_grab(window, TRUE,
+	                      GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+	                      GDK_POINTER_MOTION_MASK,
+	                      NULL, NULL, activate_time) == 0))
 	{
-		if (gdk_keyboard_grab (window, TRUE, activate_time) == 0)
+		if (gdk_keyboard_grab(window, TRUE, activate_time) == 0)
 			return TRUE;
 		else {
-			gdk_display_pointer_ungrab (gdk_window_get_display (window), activate_time);
+			gdk_display_pointer_ungrab(gdk_window_get_display(window),
+			                           activate_time);
 			return FALSE;
 		}
 	}
 
 	return FALSE;
+#endif
 }
 
 
 static void
-pidgin_status_box_popup(PidginStatusBox *box)
+pidgin_status_box_popup(PidginStatusBox *box, GdkEvent *event)
 {
 	int width, height, x, y;
 	pidgin_status_box_list_position (box, &x, &y, &width, &height);
@@ -1411,8 +1435,7 @@
 	gtk_window_move (GTK_WINDOW (box->popup_window), x, y);
 	gtk_widget_show(box->popup_window);
 	gtk_widget_grab_focus (box->tree_view);
-	if (!popup_grab_on_window (gtk_widget_get_window(box->popup_window),
-				   GDK_CURRENT_TIME)) {
+	if (!popup_grab_on_window(gtk_widget_get_window(box->popup_window), event)) {
 		gtk_widget_hide (box->popup_window);
 		return;
 	}
@@ -1429,15 +1452,25 @@
 }
 
 static void
-pidgin_status_box_popdown(PidginStatusBox *box)
+pidgin_status_box_popdown(PidginStatusBox *box, GdkEvent *event)
 {
+	guint32 time;
+#if GTK_CHECK_VERSION(3,0,0)
+	GdkDevice *device;
+#endif
 	gtk_widget_hide(box->popup_window);
 	box->popup_in_progress = FALSE;
-	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (box->toggle_button),
-				      FALSE);
-	gtk_grab_remove (box->popup_window);
-	gdk_pointer_ungrab(GDK_CURRENT_TIME);
-	gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(box->toggle_button), FALSE);
+	gtk_grab_remove(box->popup_window);
+	time = gdk_event_get_time(event);
+#if GTK_CHECK_VERSION(3,0,0)
+	device = gdk_event_get_device(event);
+	gdk_device_ungrab(device, time);
+	gdk_device_ungrab(gdk_device_get_associated_device(device), time);
+#else
+	gdk_pointer_ungrab(time);
+	gdk_keyboard_ungrab(time);
+#endif
 }
 
 static gboolean
@@ -1449,10 +1482,10 @@
 		case GDK_KEY_KP_Space:
 		case GDK_KEY_space:
 			if (!box->popup_in_progress) {
-				pidgin_status_box_popup (box);
+				pidgin_status_box_popup(box, (GdkEvent *)event);
 				box->popup_in_progress = TRUE;
 			} else {
-				pidgin_status_box_popdown(box);
+				pidgin_status_box_popdown(box, (GdkEvent *)event);
 			}
 			return TRUE;
 		default:
@@ -1464,9 +1497,9 @@
 toggled_cb(GtkWidget *widget, GdkEventButton *event, PidginStatusBox *box)
 {
 	if (!box->popup_in_progress)
-		pidgin_status_box_popup (box);
+		pidgin_status_box_popup(box, (GdkEvent *)event);
 	else
-		pidgin_status_box_popdown(box);
+		pidgin_status_box_popdown(box, (GdkEvent *)event);
 	return TRUE;
 }
 
@@ -1574,13 +1607,13 @@
 }
 
 static void
-treeview_activate_current_selection(PidginStatusBox *status_box, GtkTreePath *path)
+treeview_activate_current_selection(PidginStatusBox *status_box, GtkTreePath *path, GdkEvent *event)
 {
 	if (status_box->active_row)
 		gtk_tree_row_reference_free(status_box->active_row);
 
 	status_box->active_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(status_box->dropdown_store), path);
-	pidgin_status_box_popdown (status_box);
+	pidgin_status_box_popdown(status_box, event);
 	pidgin_status_box_changed(status_box);
 }
 
@@ -1596,7 +1629,7 @@
 }
 
 static void
-tree_view_delete_current_selection(PidginStatusBox *status_box, GtkTreePath *path)
+tree_view_delete_current_selection(PidginStatusBox *status_box, GtkTreePath *path, GdkEvent *event)
 {
 	GtkTreeIter iter;
 	gpointer data;
@@ -1631,7 +1664,7 @@
 
 	g_free(msg);
 
-	pidgin_status_box_popdown(status_box);
+	pidgin_status_box_popdown(status_box, event);
 }
 
 static gboolean
@@ -1645,7 +1678,7 @@
 		if (ewidget == status_box->toggle_button &&
 		    status_box->popup_in_progress &&
 		    gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (status_box->toggle_button))) {
-			pidgin_status_box_popdown (status_box);
+			pidgin_status_box_popdown(status_box, (GdkEvent *)event);
 			return TRUE;
 		} else if (ewidget == status_box->toggle_button) {
 			status_box->popup_in_progress = TRUE;
@@ -1653,7 +1686,7 @@
 
 		/* released outside treeview */
 		if (ewidget != status_box->toggle_button) {
-				pidgin_status_box_popdown (status_box);
+				pidgin_status_box_popdown(status_box, (GdkEvent *)event);
 				return TRUE;
 		}
 
@@ -1668,7 +1701,7 @@
 	if (!ret)
 		return TRUE; /* clicked outside window? */
 
-	treeview_activate_current_selection(status_box, path);
+	treeview_activate_current_selection(status_box, path, (GdkEvent *)event);
 	gtk_tree_path_free (path);
 
 	return TRUE;
@@ -1680,7 +1713,7 @@
 {
 	if (box->popup_in_progress) {
 		if (event->keyval == GDK_KEY_Escape) {
-			pidgin_status_box_popdown(box);
+			pidgin_status_box_popdown(box, (GdkEvent *)event);
 			return TRUE;
 		} else {
 			GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(box->tree_view));
@@ -1691,9 +1724,9 @@
 				gboolean ret = TRUE;
 				path = gtk_tree_model_get_path(GTK_TREE_MODEL(box->dropdown_store), &iter);
 				if (event->keyval == GDK_KEY_Return) {
-					treeview_activate_current_selection(box, path);
+					treeview_activate_current_selection(box, path, (GdkEvent *)event);
 				} else if (event->keyval == GDK_KEY_Delete) {
-					tree_view_delete_current_selection(box, path);
+					tree_view_delete_current_selection(box, path, (GdkEvent *)event);
 				} else
 					ret = FALSE;
 
@@ -2038,7 +2071,7 @@
 	GtkAllocation parent_alc, box_alc, icon_alc;
 	gint border_width = gtk_container_get_border_width(GTK_CONTAINER (widget));
 
-	gtk_widget_size_request(status_box->toggle_button, &req);
+	gtk_widget_get_preferred_size(status_box->toggle_button, NULL, &req);
 	/* Make this icon the same size as other buddy icons in the list; unless it already wants to be bigger */
 
 	req.height = MAX(req.height, 34);
@@ -2064,7 +2097,7 @@
 		icon_alc = parent_alc;
 		icon_alc.height = MAX(1, icon_alc.height) - 2;
 		icon_alc.width = icon_alc.height;
-		icon_alc.x = allocation->width - (icon_alc.width + border_width + 1);
+		icon_alc.x += allocation->width - (icon_alc.width + border_width + 1);
 		icon_alc.y += 1;
 
 		if (status_box->icon_size != icon_alc.height)
@@ -2087,11 +2120,12 @@
 
 	if (status_box->icon_box && status_box->icon_opaque) {
 		GtkAllocation allocation;
+		GtkStyleContext *context;
 
 		gtk_widget_get_allocation(status_box->icon_box, &allocation);
-		gtk_paint_box(gtk_widget_get_style(widget), cr, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-				status_box->icon_box, "button", allocation.x-1, allocation.y-1,
-				34, 34);
+		context = gtk_widget_get_style_context(widget);
+		gtk_style_context_add_class(context, GTK_STYLE_CLASS_BUTTON);
+		gtk_render_frame(context, cr, allocation.x-1, allocation.y-1, 34, 34);
 	}
 	return FALSE;
 }
--- a/pidgin/gtkutils.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkutils.c	Fri Aug 17 17:22:23 2012 +0200
@@ -62,8 +62,6 @@
 
 #include "gtkconv.h"
 #include "gtkdialogs.h"
-#include "gtkimhtml.h"
-#include "gtkimhtmltoolbar.h"
 #include "pidginstock.h"
 #include "gtkthemes.h"
 #include "gtkutils.h"
@@ -103,49 +101,13 @@
 	return TRUE;
 }
 
-static GtkIMHtmlFuncs gtkimhtml_cbs = {
-	(GtkIMHtmlGetImageFunc)purple_imgstore_find_by_id,
-	(GtkIMHtmlGetImageDataFunc)purple_imgstore_get_data,
-	(GtkIMHtmlGetImageSizeFunc)purple_imgstore_get_size,
-	(GtkIMHtmlGetImageFilenameFunc)purple_imgstore_get_filename,
-	purple_imgstore_ref_by_id,
-	purple_imgstore_unref_by_id,
-};
-
-void
-pidgin_setup_imhtml(GtkWidget *imhtml)
-{
-	g_return_if_fail(imhtml != NULL);
-	g_return_if_fail(GTK_IS_IMHTML(imhtml));
-
-	pidgin_themes_smiley_themeize(imhtml);
-
-	gtk_imhtml_set_funcs(GTK_IMHTML(imhtml), &gtkimhtml_cbs);
-
-#ifdef _WIN32
-	if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font")) {
-		PangoFontDescription *desc;
-		const char *font = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font");
-		desc = pango_font_description_from_string(font);
-		if (desc) {
-			gtk_widget_modify_font(imhtml, desc);
-			pango_font_description_free(desc);
-		}
-	}
-#endif
-
-}
-
 void
 pidgin_setup_webview(GtkWidget *webview)
 {
 	g_return_if_fail(webview != NULL);
 	g_return_if_fail(GTK_IS_WEBVIEW(webview));
 
-#if 0
-/* TODO: WebKit this stuff... */
 	pidgin_themes_smiley_themeize(webview);
-#endif
 
 #ifdef _WIN32
 	if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font")) {
@@ -252,66 +214,6 @@
 }
 
 GtkWidget *
-pidgin_create_imhtml(gboolean editable, GtkWidget **imhtml_ret, GtkWidget **toolbar_ret, GtkWidget **sw_ret)
-{
-	GtkWidget *frame;
-	GtkWidget *imhtml;
-	GtkWidget *sep;
-	GtkWidget *sw;
-	GtkWidget *toolbar = NULL;
-	GtkWidget *vbox;
-
-	frame = gtk_frame_new(NULL);
-	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
-
-	vbox = gtk_vbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_widget_show(vbox);
-
-	if (editable) {
-		toolbar = gtk_imhtmltoolbar_new();
-		gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
-		gtk_widget_show(toolbar);
-
-		sep = gtk_hseparator_new();
-		gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
-		g_signal_connect_swapped(G_OBJECT(toolbar), "show", G_CALLBACK(gtk_widget_show), sep);
-		g_signal_connect_swapped(G_OBJECT(toolbar), "hide", G_CALLBACK(gtk_widget_hide), sep);
-		gtk_widget_show(sep);
-	}
-
-	imhtml = gtk_imhtml_new(NULL, NULL);
-	gtk_imhtml_set_editable(GTK_IMHTML(imhtml), editable);
-	gtk_imhtml_set_format_functions(GTK_IMHTML(imhtml), GTK_IMHTML_ALL ^ GTK_IMHTML_IMAGE);
-	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR);
-#ifdef USE_GTKSPELL
-	if (editable && purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/spellcheck"))
-		pidgin_setup_gtkspell(GTK_TEXT_VIEW(imhtml));
-#endif
-	gtk_widget_show(imhtml);
-
-	if (editable) {
-		gtk_imhtmltoolbar_attach(GTK_IMHTMLTOOLBAR(toolbar), imhtml);
-		gtk_imhtmltoolbar_associate_smileys(GTK_IMHTMLTOOLBAR(toolbar), "default");
-	}
-	pidgin_setup_imhtml(imhtml);
-
-	sw = pidgin_make_scrollable(imhtml, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_NONE, -1, -1);
-	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-
-	if (imhtml_ret != NULL)
-		*imhtml_ret = imhtml;
-
-	if (editable && (toolbar_ret != NULL))
-		*toolbar_ret = toolbar;
-
-	if (sw_ret != NULL)
-		*sw_ret = sw;
-
-	return frame;
-}
-
-GtkWidget *
 pidgin_create_webview(gboolean editable, GtkWidget **webview_ret, GtkWidget **toolbar_ret, GtkWidget **sw_ret)
 {
 	GtkWidget *frame;
@@ -1299,7 +1201,7 @@
 	 * if a size_request was queued while we weren't popped up,
 	 * the requisition won't have been recomputed yet.
 	 */
-	gtk_widget_size_request (widget, &requisition);
+	gtk_widget_get_preferred_size(widget, NULL, &requisition);
 
 	monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
 
@@ -1460,7 +1362,6 @@
 	GError *err = NULL;
 	PurpleConversation *conv;
 	PidginConversation *gtkconv;
-	GtkTextIter iter;
 	int id;
 	PurpleBuddy *buddy;
 	PurpleContact *contact;
@@ -1512,9 +1413,7 @@
 		shortname = shortname ? shortname + 1 : data->filename;
 		id = purple_imgstore_add_with_id(filedata, size, shortname);
 
-		gtk_text_buffer_get_iter_at_mark(GTK_IMHTML(gtkconv->entry)->text_buffer, &iter,
-						 gtk_text_buffer_get_insert(GTK_IMHTML(gtkconv->entry)->text_buffer));
-		gtk_imhtml_insert_image_at_iter(GTK_IMHTML(gtkconv->entry), id, &iter);
+		gtk_webview_insert_image(GTK_WEBVIEW(gtkconv->entry), id);
 		purple_imgstore_unref_by_id(id);
 
 		break;
@@ -1677,9 +1576,9 @@
 			case PURPLE_DESKTOP_ITEM_TYPE_LINK:
 				conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, who);
 				gtkconv =  PIDGIN_CONVERSATION(conv);
-				gtk_imhtml_insert_link(GTK_IMHTML(gtkconv->entry),
-						       gtk_text_buffer_get_insert(GTK_IMHTML(gtkconv->entry)->text_buffer),
-						       purple_desktop_item_get_string(item, "URL"), itemname);
+				gtk_webview_insert_link(GTK_WEBVIEW(gtkconv->entry),
+				                        purple_desktop_item_get_string(item, "URL"),
+				                        itemname);
 				break;
 			default:
 				/* I don't know if we really want to do anything here.  Most of
@@ -3312,12 +3211,12 @@
 
 	if (code == SE_ERR_ASSOCINCOMPLETE || code == SE_ERR_NOASSOC)
 	{
-		purple_notify_error(imhtml, NULL,
+		purple_notify_error(webview, NULL,
 				_("There is no application configured to open this type of file."), NULL);
 	}
 	else if (code < 32)
 	{
-		purple_notify_error(imhtml, NULL,
+		purple_notify_error(webview, NULL,
 				_("An error occurred while opening the file."), NULL);
 		purple_debug_warning("gtkutils", "filename: %s; code: %d\n", uri, code);
 	}
--- a/pidgin/gtkutils.h	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkutils.h	Fri Aug 17 17:22:23 2012 +0200
@@ -79,34 +79,6 @@
 G_BEGIN_DECLS
 
 /**
- * Sets up a gtkimhtml widget, loads it with smileys, and sets the
- * default signal handlers.
- *
- * @param imhtml The gtkimhtml widget to setup.
- */
-void pidgin_setup_imhtml(GtkWidget *imhtml);
-
-/**
- * Create an GtkIMHtml widget and associated GtkIMHtmlToolbar widget.  This
- * functions puts both widgets in a nice GtkFrame.  They're separate by an
- * attractive GtkSeparator.
- *
- * @param editable @c TRUE if this imhtml should be editable.  If this is @c FALSE,
- *        then the toolbar will NOT be created.  If this imthml should be
- *        read-only at first, but may become editable later, then pass in
- *        @c TRUE here and then manually call gtk_imhtml_set_editable() later.
- * @param imhtml_ret A pointer to a pointer to a GtkWidget.  This pointer
- *        will be set to the imhtml when this function exits.
- * @param toolbar_ret A pointer to a pointer to a GtkWidget.  If editable is
- *        TRUE then this will be set to the toolbar when this function exits.
- *        Otherwise this will be set to @c NULL.
- * @param sw_ret This will be filled with a pointer to the scrolled window
- *        widget which contains the imhtml.
- * @return The GtkFrame containing the toolbar and imhtml.
- */
-GtkWidget *pidgin_create_imhtml(gboolean editable, GtkWidget **imhtml_ret, GtkWidget **toolbar_ret, GtkWidget **sw_ret);
-
-/**
  * Sets up a gtkwebview widget, loads it with smileys, and sets the
  * default signal handlers.
  *
@@ -115,7 +87,7 @@
 void pidgin_setup_webview(GtkWidget *webview);
 
 /**
- * Create an GtkWebView widget and associated GtkIMHtmlToolbar widget.  This
+ * Create an GtkWebView widget and associated GtkWebViewToolbar widget.  This
  * function puts both widgets in a nice GtkFrame.  They're separated by an
  * attractive GtkSeparator.
  *
--- a/pidgin/gtkwebviewtoolbar.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkwebviewtoolbar.c	Fri Aug 17 17:22:23 2012 +0200
@@ -43,6 +43,8 @@
 
 #include <gdk/gdkkeysyms.h>
 
+#include "gtk3compat.h"
+
 #define GTK_WEBVIEWTOOLBAR_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE((obj), GTK_TYPE_WEBVIEWTOOLBAR, GtkWebViewToolbarPriv))
 
@@ -160,27 +162,22 @@
 	gtk_widget_grab_focus(toolbar->webview);
 }
 
-static gboolean
-destroy_toolbar_font(GtkWidget *widget, GdkEvent *event,
-					 GtkWebViewToolbar *toolbar)
+static void
+destroy_toolbar_font(GtkWebViewToolbar *toolbar)
 {
 	GtkWebViewToolbarPriv *priv = GTK_WEBVIEWTOOLBAR_GET_PRIVATE(toolbar);
 
-	if (widget != NULL)
-		gtk_webview_toggle_fontface(GTK_WEBVIEW(toolbar->webview), "");
-
 	if (priv->font_dialog != NULL)
 	{
 		gtk_widget_destroy(priv->font_dialog);
 		priv->font_dialog = NULL;
 	}
-
-	return FALSE;
 }
 
 static void
 realize_toolbar_font(GtkWidget *widget, GtkWebViewToolbar *toolbar)
 {
+#if !GTK_CHECK_VERSION(3,2,0)
 	GtkWebViewToolbarPriv *priv = GTK_WEBVIEWTOOLBAR_GET_PRIVATE(toolbar);
 	GtkFontSelection *sel;
 
@@ -193,40 +190,38 @@
 		gtk_font_selection_get_family_list(sel)));
 	gtk_widget_show(gtk_widget_get_parent(gtk_widget_get_parent(
 		gtk_font_selection_get_family_list(sel))));
-}
-
-static void
-cancel_toolbar_font(GtkWidget *widget, GtkWebViewToolbar *toolbar)
-{
-	destroy_toolbar_font(widget, NULL, toolbar);
+#endif
 }
 
 static void
-apply_font(GtkWidget *widget, GtkWebViewToolbar *toolbar)
+apply_font(GtkDialog *dialog, gint response, GtkWebViewToolbar *toolbar)
 {
 	/* this could be expanded to include font size, weight, etc.
 	   but for now only works with font face */
-	GtkWebViewToolbarPriv *priv = GTK_WEBVIEWTOOLBAR_GET_PRIVATE(toolbar);
-	GtkFontSelectionDialog *fontsel = GTK_FONT_SELECTION_DIALOG(priv->font_dialog);
-	gchar *fontname = gtk_font_selection_dialog_get_font_name(fontsel);
+	gchar *fontname = NULL;
+
+	if (response == GTK_RESPONSE_OK)
+		fontname = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(dialog));
 
 	if (fontname) {
-		const gchar *family_name = NULL;
-		PangoFontDescription *desc = NULL;
+		PangoFontDescription *desc;
+		const gchar *family_name;
 
 		desc = pango_font_description_from_string(fontname);
 		family_name = pango_font_description_get_family(desc);
 
 		if (family_name) {
 			gtk_webview_toggle_fontface(GTK_WEBVIEW(toolbar->webview),
-			                           family_name);
+			                            family_name);
 		}
 
 		pango_font_description_free(desc);
 		g_free(fontname);
+	} else {
+		gtk_webview_toggle_fontface(GTK_WEBVIEW(toolbar->webview), "");
 	}
 
-	cancel_toolbar_font(NULL, toolbar);
+	destroy_toolbar_font(toolbar);
 }
 
 static void
@@ -238,35 +233,31 @@
 		char *fontname = gtk_webview_get_current_fontface(GTK_WEBVIEW(toolbar->webview));
 
 		if (!priv->font_dialog) {
-			priv->font_dialog = gtk_font_selection_dialog_new(_("Select Font"));
+			GtkWindow *window;
+			window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(toolbar)));
+			priv->font_dialog = gtk_font_chooser_dialog_new(_("Select Font"), window);
 
 			if (fontname) {
 				char *fonttif = g_strdup_printf("%s 12", fontname);
-				gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(priv->font_dialog),
-														fonttif);
+				gtk_font_chooser_set_font(GTK_FONT_CHOOSER(priv->font_dialog),
+				                          fonttif);
 				g_free(fonttif);
 			} else {
-				gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(priv->font_dialog),
-														DEFAULT_FONT_FACE);
+				gtk_font_chooser_set_font(GTK_FONT_CHOOSER(priv->font_dialog),
+				                          DEFAULT_FONT_FACE);
 			}
 
-			g_signal_connect(G_OBJECT(priv->font_dialog), "delete_event",
-							 G_CALLBACK(destroy_toolbar_font), toolbar);
-			g_signal_connect(G_OBJECT(
-				gtk_font_selection_dialog_get_ok_button(GTK_FONT_SELECTION_DIALOG(priv->font_dialog))),
-				"clicked", G_CALLBACK(apply_font), toolbar);
-			g_signal_connect(G_OBJECT(
-				gtk_font_selection_dialog_get_cancel_button(GTK_FONT_SELECTION_DIALOG(priv->font_dialog))),
-				"clicked", G_CALLBACK(cancel_toolbar_font), toolbar);
+			g_signal_connect(G_OBJECT(priv->font_dialog), "response",
+			                 G_CALLBACK(apply_font), toolbar);
 			g_signal_connect_after(G_OBJECT(priv->font_dialog), "realize",
-							 G_CALLBACK(realize_toolbar_font), toolbar);
+			                       G_CALLBACK(realize_toolbar_font), toolbar);
 		}
 
 		gtk_window_present(GTK_WINDOW(priv->font_dialog));
 
 		g_free(fontname);
 	} else {
-		cancel_toolbar_font(GTK_WIDGET(toolbar), toolbar);
+		destroy_toolbar_font(toolbar);
 	}
 
 	gtk_widget_grab_focus(toolbar->webview);
@@ -695,7 +686,7 @@
 	it_last = ls; /* list iterators */
 	image = gtk_image_new_from_file(filename);
 
-	gtk_widget_size_request(image, &size);
+	gtk_widget_get_preferred_size(image, NULL, &size);
 
 	if ((size.width > 24)
 	 && (gtk_webview_smiley_get_flags(smiley) & GTK_WEBVIEW_SMILEY_CUSTOM)) {
@@ -721,7 +712,7 @@
 					GDK_INTERP_HYPER);
 
 			gtk_image_set_from_pixbuf(GTK_IMAGE(image), resized); /* This unrefs pixbuf */
-			gtk_widget_size_request(image, &size);
+			gtk_widget_get_preferred_size(image, NULL, &size);
 			g_object_unref(G_OBJECT(resized));
 		}
 	}
@@ -903,7 +894,7 @@
 			g_signal_connect_swapped(G_OBJECT(manage), "clicked",
 					G_CALLBACK(gtk_widget_destroy), dialog);
 			gtk_box_pack_end(GTK_BOX(vbox), manage, FALSE, TRUE, 0);
-			gtk_widget_size_request(manage, &req);
+			gtk_widget_get_preferred_size(manage, NULL, &req);
 			button_width = req.width;
 		}
 
@@ -955,7 +946,7 @@
 	/* show everything */
 	gtk_widget_show_all(dialog);
 
-	gtk_widget_size_request(viewport, &req);
+	gtk_widget_get_preferred_size(viewport, NULL, &req);
 	gtk_widget_set_size_request(scrolled, MIN(300, req.width), MIN(290, req.height));
 
 	/* The window has to be made resizable, and the scrollbars in the scrolled window
@@ -1164,7 +1155,7 @@
 	int savy;
 
 	gtk_widget_get_allocation(widget, &allocation);
-	gtk_widget_size_request(GTK_WIDGET(menu), &menu_req);
+	gtk_widget_get_preferred_size(GTK_WIDGET(menu), NULL, &menu_req);
 	gdk_window_get_origin(gtk_widget_get_window(widget), x, y);
 	*x += allocation.x;
 	*y += allocation.y + allocation.height;
@@ -1263,12 +1254,10 @@
 		priv->image_dialog = NULL;
 	}
 
-	destroy_toolbar_font(NULL, NULL, toolbar);
+	destroy_toolbar_font(toolbar);
 	if (priv->smiley_dialog != NULL) {
-#if 0
 		g_signal_handlers_disconnect_by_func(G_OBJECT(priv->smiley_dialog), close_smiley_dialog, toolbar);
 		destroy_smiley_dialog(toolbar);
-#endif
 	}
 	destroy_toolbar_bgcolor(NULL, NULL, toolbar);
 	destroy_toolbar_fgcolor(NULL, NULL, toolbar);
--- a/pidgin/gtkwhiteboard.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/gtkwhiteboard.c	Fri Aug 17 17:22:23 2012 +0200
@@ -491,7 +491,12 @@
 	GList *draw_list = purple_whiteboard_get_draw_list(wb);
 
 	if(event->is_hint)
+#if GTK_CHECK_VERSION(3,0,0)
+		gdk_window_get_device_position(event->window, event->device, &x, &y,
+		                               &state);
+#else
 		gdk_window_get_pointer(event->window, &x, &y, &state);
+#endif
 	else
 	{
 		x = event->x;
--- a/pidgin/pidginstock.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/pidginstock.c	Fri Aug 17 17:22:23 2012 +0200
@@ -520,8 +520,13 @@
 
 		if (stock_icons[i].dir == NULL) {
 			/* GTK+ Stock icon */
+#if GTK_CHECK_VERSION(3,0,0)
+			iconset = gtk_style_context_lookup_icon_set(gtk_widget_get_style_context(win),
+			                                            stock_icons[i].filename);
+#else
 			iconset = gtk_style_lookup_icon_set(gtk_widget_get_style(win),
-					stock_icons[i].filename);
+			                                    stock_icons[i].filename);
+#endif
 		} else {
 			filename = find_file(stock_icons[i].dir, stock_icons[i].filename);
 
--- a/pidgin/pidgintooltip.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/pidgintooltip.c	Fri Aug 17 17:22:23 2012 +0200
@@ -109,10 +109,10 @@
 	gtk_widget_get_allocation(widget, &allocation);
 
 	if (pidgin_tooltip.paint_tooltip) {
-		gtk_paint_flat_box(gtk_widget_get_style(widget), cr,
-		                   GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-		                   widget, "tooltip",
-		                   0, 0, allocation.width, allocation.height);
+		GtkStyleContext *context = gtk_widget_get_style_context(widget);
+		gtk_style_context_add_class(context, GTK_STYLE_CLASS_TOOLTIP);
+		gtk_render_background(context, cr,
+		                      0, 0, allocation.width, allocation.height);
 		pidgin_tooltip.paint_tooltip(widget, cr, data);
 	}
 	return FALSE;
--- a/pidgin/plugins/disco/gtkdisco.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/plugins/disco/gtkdisco.c	Fri Aug 17 17:22:23 2012 +0200
@@ -431,11 +431,9 @@
 {
 	PangoLayout *layout = g_object_get_data(G_OBJECT(tipwindow), "tooltip-plugin");
 #if GTK_CHECK_VERSION(3,0,0)
-	gtk_paint_layout(gtk_widget_get_style(tipwindow),
-	                 cr,
-	                 GTK_STATE_NORMAL, FALSE,
-	                 tipwindow, "tooltip",
-	                 6, 6, layout);
+	GtkStyleContext *context = gtk_widget_get_style_context(tipwindow);
+	gtk_style_context_add_class(context, GTK_STYLE_CLASS_TOOLTIP);
+	gtk_render_layout(context, cr, 6, 6, layout);
 #else
 	gtk_paint_layout(gtk_widget_get_style(tipwindow),
 	                 gtk_widget_get_window(tipwindow),
--- a/pidgin/plugins/gestures/stroke-draw.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/plugins/gestures/stroke-draw.c	Fri Aug 17 17:22:23 2012 +0200
@@ -119,8 +119,11 @@
 	timer_id = 0;
 
 	if( event != NULL )
+#if GTK_CHECK_VERSION(3,0,0)
+		gdk_device_ungrab(gdk_event_get_device(event), event->button.time);
+#else
 		gdk_pointer_ungrab (event->button.time);
-
+#endif
 
 	if (gstroke_draw_strokes() && gstroke_disp != NULL) {
 	    /* get rid of the invisible stroke window */
@@ -158,9 +161,16 @@
 	  if (cursor == NULL)
 		  cursor = gdk_cursor_new(GDK_PENCIL);
 
+#if GTK_CHECK_VERSION(3,0,0)
+      gdk_device_grab(gdk_event_get_device(event),
+                      gtk_widget_get_window(widget), GDK_OWNERSHIP_WINDOW,
+                      FALSE, GDK_BUTTON_RELEASE_MASK, cursor,
+                      event->button.time);
+#else
       gdk_pointer_grab (gtk_widget_get_window(widget), FALSE,
 			GDK_BUTTON_RELEASE_MASK, NULL, cursor,
 			event->button.time);
+#endif
       timer_id = g_timeout_add (GSTROKE_TIMEOUT_DURATION,
 				  gstroke_timeout, widget);
       return TRUE;
@@ -179,7 +189,11 @@
       last_mouse_position.invalid = TRUE;
       original_widget = NULL;
       g_source_remove (timer_id);
+#if GTK_CHECK_VERSION(3,0,0)
+      gdk_device_ungrab(gdk_event_get_device(event), event->button.time);
+#else
       gdk_pointer_ungrab (event->button.time);
+#endif
       timer_id = 0;
 
       {
--- a/pidgin/plugins/perl/common/GtkConvWin.xs	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/plugins/perl/common/GtkConvWin.xs	Fri Aug 17 17:22:23 2012 +0200
@@ -59,11 +59,6 @@
 pidgin_conv_window_has_focus(win)
 	Pidgin::Conversation::Window win
 
-Pidgin::Conversation::Window
-pidgin_conv_window_get_at_xy(x, y)
-	int x
-	int y
-
 void
 pidgin_conv_window_get_gtkconvs(win)
 	Pidgin::Conversation::Window win
--- a/pidgin/plugins/pidginrc.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/plugins/pidginrc.c	Fri Aug 17 17:22:23 2012 +0200
@@ -31,6 +31,8 @@
 #include "util.h"
 #include "version.h"
 
+#include "gtk3compat.h"
+
 static guint pref_callback;
 
 static const gchar *color_prefs[] = {
@@ -306,7 +308,7 @@
 			prefpath = font_prefs[subscript];
 		}
 
-		fontname = gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(font_dialog));
+		fontname = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(font_dialog));
 
 		purple_prefs_set_string(prefpath, fontname);
 		g_free(fontname);
@@ -318,6 +320,7 @@
 purplerc_set_font(GtkWidget *widget, gpointer data)
 {
 	gchar title[128];
+	GtkWindow *window;
 	GtkWidget *font_dialog = NULL;
 	gint subscript = GPOINTER_TO_INT(data);
 	const gchar *pref = NULL, *prefpath = NULL;
@@ -331,14 +334,15 @@
 		prefpath = font_prefs[subscript];
 	}
 
-	font_dialog = gtk_font_selection_dialog_new(title);
+	window = GTK_WINDOW(gtk_widget_get_toplevel(widget));
+	font_dialog = gtk_font_chooser_dialog_new(title, window);
 	g_signal_connect(G_OBJECT(font_dialog), "response",
 	                 G_CALLBACK(purplerc_font_response), data);
 
 	pref = purple_prefs_get_string(prefpath);
 
 	if (pref != NULL && strcmp(pref, "")) {
-		gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(font_dialog), pref);
+		gtk_font_chooser_set_font(GTK_FONT_CHOOSER(font_dialog), pref);
 	}
 
 	gtk_window_present(GTK_WINDOW(font_dialog));
--- a/pidgin/plugins/themeedit.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/plugins/themeedit.c	Fri Aug 17 17:22:23 2012 +0200
@@ -22,6 +22,8 @@
 #include "pidgin.h"
 #include "version.h"
 
+#include "gtk3compat.h"
+
 #include "theme-manager.h"
 
 #include "gtkblist.h"
@@ -98,7 +100,7 @@
 theme_font_face_selected(GtkWidget *dialog, gint response, gpointer font)
 {
 	if (response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY) {
-		const char *fontname = gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(dialog));
+		const char *fontname = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(dialog));
 		pidgin_theme_font_set_font_face(font, fontname);
 		pidgin_blist_refresh(purple_get_blist());
 	}
@@ -108,6 +110,7 @@
 static void
 theme_font_select_face(GtkWidget *widget, gpointer prop)
 {
+	GtkWindow *window;
 	GtkWidget *dialog;
 	PidginBlistTheme *theme;
 	PidginThemeFont *font = NULL;
@@ -124,10 +127,10 @@
 	}
 
 	face = pidgin_theme_font_get_font_face(font);
-	dialog = gtk_font_selection_dialog_new(_("Select Font"));
+	window = GTK_WINDOW(gtk_widget_get_toplevel(widget));
+	dialog = gtk_font_chooser_dialog_new(_("Select Font"), window);
 	if (face && *face)
-		gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(dialog),
-				face);
+		gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), face);
 	g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(theme_font_face_selected),
 			font);
 	gtk_widget_show_all(dialog);
--- a/pidgin/plugins/ticker/gtkticker.c	Fri Aug 17 11:00:00 2012 +0200
+++ b/pidgin/plugins/ticker/gtkticker.c	Fri Aug 17 17:22:23 2012 +0200
@@ -294,7 +294,11 @@
 	GdkWindowAttr attributes;
 	gint attributes_mask;
 	GdkWindow *window;
+#if GTK_CHECK_VERSION(3,0,0)
+	GtkStyleContext *context;
+#else
 	GtkStyle *style;
+#endif
 	GtkAllocation allocation;
 
 	g_return_if_fail (widget != NULL);
@@ -327,9 +331,16 @@
 	gtk_widget_set_window (widget, window);
 	gdk_window_set_user_data (window, widget);
 
+#if GTK_CHECK_VERSION(3,0,0)
+	context = gtk_widget_get_style_context(widget);
+	gtk_style_context_add_class(context, GTK_STYLE_CLASS_BACKGROUND);
+	gtk_style_context_set_state(context, GTK_STATE_NORMAL);
+	gtk_style_context_set_background(context, window);
+#else
 	style = gtk_style_attach (gtk_widget_get_style (widget), window);
 	gtk_widget_set_style (widget, style);
 	gtk_style_set_background (style, window, GTK_STATE_NORMAL);
+#endif
 }
 
 #if GTK_CHECK_VERSION(3,0,0)
@@ -469,7 +480,7 @@
 
 		child->x = 0;
 		if (gtk_widget_get_visible (child->widget)) {
-			gtk_widget_get_child_requisition (child->widget, &child_requisition);
+			gtk_widget_get_preferred_size (child->widget, NULL, &child_requisition);
 			child->offset = ticker->total;
 			ticker->total +=
 				child_requisition.width + border_width + ticker->spacing;
@@ -521,7 +532,7 @@
 		child->x -= ticker->scootch;
 
 		if (gtk_widget_get_visible (child->widget)) {
-			gtk_widget_get_child_requisition (child->widget, &child_requisition);
+			gtk_widget_get_preferred_size (child->widget, NULL, &child_requisition);
 			child_allocation.width = child_requisition.width;
 			child_allocation.x = child->offset + border_width + child->x;
 			if ( ( child_allocation.x + child_allocation.width ) < allocation->x  ) {

mercurial