changeset 31821:17a4b32f4d46

propagate from branch 'im.pidgin.pidgin' (head 8480ab9498b0e22b164f3a40c100f59e2d6dd916) to branch 'im.pidgin.pidgin.next.minor' (head 490036a7b4ce807cb851ded91af7d959fe1c029e)
author Paul Aurich <paul@darkrain42.org>
date Sun, 30 Jan 2011 17:52:06 +0000
parents 28e27a37e4b4 (diff) 24d62d6f72cc (current diff)
children 6c660dc7cb6a
files ChangeLog configure.ac libpurple/mediamanager.c pidgin/gtkstatusbox.c pidgin/gtkutils.c
diffstat 43 files changed, 345 insertions(+), 387 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Jan 30 17:51:40 2011 +0000
+++ b/ChangeLog	Sun Jan 30 17:52:06 2011 +0000
@@ -1,5 +1,14 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.8.0 (??/??/????):
+	libpurple:
+	* media: Allow obtaining active local and remote candidates. (#11830)
+	* media: Allow getting/setting video capabilities. (Jakub Adam) (half of
+	  #13095)
+
+	Pidgin:
+	* Duplicate code cleanup.  (Gabriel Schulhof) (#10599)
+
 version 2.7.10 (??/??/????):
 	General:
 	* Force video sources to all have the same capabilities.  This reduces the
--- a/ChangeLog.API	Sun Jan 30 17:51:40 2011 +0000
+++ b/ChangeLog.API	Sun Jan 30 17:52:06 2011 +0000
@@ -1,5 +1,20 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.8.0 (??/??/????):
+	libpurple:
+		Added:
+		* account-authorization-requested-with-message signal (Stefan Ott)
+		  (#8690)
+		* purple_notify_user_info_add_pair_plaintext
+		* purple_media_get_active_local_candidates
+		* purple_media_get_active_remote_candidates
+		* purple_media_manager_get_video_caps (Jakub Adam) (#13095)
+		* purple_media_manager_set_video_caps (Jakub Adam) (#13095)
+
+	Pidgin:
+		Added:
+		* pidgin_make_scrollable (Gabriel Schulhof) (#10599)
+
 version 2.7.9 (??/??/????):
 	* No changes
 
--- a/configure.ac	Sun Jan 30 17:51:40 2011 +0000
+++ b/configure.ac	Sun Jan 30 17:52:06 2011 +0000
@@ -43,10 +43,10 @@
 #
 # Make sure to update finch/libgnt/configure.ac with libgnt version changes.
 #
-m4_define([purple_lt_current], [7])
+m4_define([purple_lt_current], [8])
 m4_define([purple_major_version], [2])
-m4_define([purple_minor_version], [7])
-m4_define([purple_micro_version], [10])
+m4_define([purple_minor_version], [8])
+m4_define([purple_micro_version], [0])
 m4_define([purple_version_suffix], [devel])
 m4_define([purple_version],
           [purple_major_version.purple_minor_version.purple_micro_version])
--- a/doc/account-signals.dox	Sun Jan 30 17:51:40 2011 +0000
+++ b/doc/account-signals.dox	Sun Jan 30 17:52:06 2011 +0000
@@ -14,6 +14,7 @@
   @signal account-actions-changed
   @signal account-alias-changed
   @signal account-authorization-requested
+  @signal account-authorization-requested-with-message
   @signal account-authorization-denied
   @signal account-authorization-granted
   @signal account-error-changed
@@ -158,6 +159,23 @@
   @since 2.3.0
  @endsignaldef
 
+ @signaldef account-authorization-requested-with-message
+  @signalproto
+int (*account_authorization_requested)(PurpleAccount *account, const char *user, const char *message);
+  @endsignalproto
+  @signaldesc
+   Emitted when a user requests authorization.
+  @param account The account.
+  @param user    The name of the user requesting authorization.
+  @param message The authorization request message
+  @return PURPLE_ACCOUNT_RESPONSE_IGNORE to silently ignore the request,
+          PURPLE_ACCOUNT_RESPONSE_DENY to block the request (the sender might
+          get informed, PURPLE_ACCOUNT_RESPONSE_ACCEPT if the request should be
+          granted. If PURPLE_ACCOUNT_RESPONSE_PASS is returned, then the user
+          will be prompted with the request.
+  @since 2.8.0
+ @endsignaldef
+
  @signaldef account-authorization-denied
   @signalproto
 void (*account_authorization_denied)(PurpleAccount *account, const char *user);
--- a/libpurple/account.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/account.c	Sun Jan 30 17:52:06 2011 +0000
@@ -1441,6 +1441,27 @@
 		return NULL;
 	}
 
+	plugin_return = GPOINTER_TO_INT(
+			purple_signal_emit_return_1(
+				purple_accounts_get_handle(),
+				"account-authorization-requested-with-message",
+				account, remote_user, message
+			));
+
+	switch (plugin_return)
+	{
+		case PURPLE_ACCOUNT_RESPONSE_IGNORE:
+			return NULL;
+		case PURPLE_ACCOUNT_RESPONSE_ACCEPT:
+			if (auth_cb != NULL)
+				auth_cb(user_data);
+			return NULL;
+		case PURPLE_ACCOUNT_RESPONSE_DENY:
+			if (deny_cb != NULL)
+				deny_cb(user_data);
+			return NULL;
+	}
+
 	if (ui_ops != NULL && ui_ops->request_authorize != NULL) {
 		info            = g_new0(PurpleAccountRequestInfo, 1);
 		info->type      = PURPLE_ACCOUNT_REQUEST_AUTHORIZATION;
@@ -3046,6 +3067,13 @@
 										PURPLE_SUBTYPE_ACCOUNT),
 						purple_value_new(PURPLE_TYPE_STRING));
 
+	purple_signal_register(handle, "account-authorization-requested-with-message",
+						purple_marshal_INT__POINTER_POINTER_POINTER,
+						purple_value_new(PURPLE_TYPE_INT), 3,
+						purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						purple_value_new(PURPLE_TYPE_STRING),
+						purple_value_new(PURPLE_TYPE_STRING));
 	purple_signal_register(handle, "account-authorization-denied",
 						purple_marshal_VOID__POINTER_POINTER, NULL, 2,
 						purple_value_new(PURPLE_TYPE_SUBTYPE,
--- a/libpurple/account.h	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/account.h	Sun Jan 30 17:52:06 2011 +0000
@@ -59,6 +59,16 @@
 	PURPLE_ACCOUNT_REQUEST_AUTHORIZATION = 0 /* Account authorization request */
 } PurpleAccountRequestType;
 
+/**
+ * Account request response types
+ */
+typedef enum
+{
+	PURPLE_ACCOUNT_RESPONSE_IGNORE = -2,
+	PURPLE_ACCOUNT_RESPONSE_DENY = -1,
+	PURPLE_ACCOUNT_RESPONSE_PASS = 0,
+	PURPLE_ACCOUNT_RESPONSE_ACCEPT = 1
+} PurpleAccountRequestResponse;
 
 /**  Account UI operations, used to notify the user of status changes and when
  *   buddies add this account to their buddy lists.
--- a/libpurple/media-gst.h	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/media-gst.h	Sun Jan 30 17:52:06 2011 +0000
@@ -159,6 +159,31 @@
 PurpleMediaElementInfo *purple_media_manager_get_active_element(
 		PurpleMediaManager *manager, PurpleMediaElementType type);
 
+/**
+ * Reduces media formats supported by the video source to given set.
+ *
+ * Useful to force negotiation of smaller picture resolution more suitable for
+ * use with particular codec and communication protocol without rescaling.
+ *
+ * @param manager The media manager to set the media formats.
+ * @param caps Set of allowed media formats.
+ *
+ * @since 2.8.0
+ */
+void purple_media_manager_set_video_caps(PurpleMediaManager *manager,
+		GstCaps *caps);
+
+/**
+ * Returns current set of media formats limiting the output from video source.
+ *
+ * @param manager The media manager to get the media formats from.
+ *
+ * @return @c GstCaps limiting the video source's formats.
+ *
+ * @since 2.8.0
+ */
+GstCaps *purple_media_manager_get_video_caps(PurpleMediaManager *manager);
+
 gchar *purple_media_element_info_get_id(PurpleMediaElementInfo *info);
 gchar *purple_media_element_info_get_name(PurpleMediaElementInfo *info);
 PurpleMediaElementType purple_media_element_info_get_element_type(
--- a/libpurple/media.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/media.c	Sun Jan 30 17:52:06 2011 +0000
@@ -1151,12 +1151,6 @@
 #endif
 }
 
-#if 0
-/*
- * These two functions aren't being used and I'd rather not lock in the API
- * until they are needed. If they ever are.
- */
-
 GList *
 purple_media_get_active_local_candidates(PurpleMedia *media,
 		const gchar *sess_id, const gchar *participant)
@@ -1186,7 +1180,6 @@
 	return NULL;
 #endif
 }
-#endif
 
 gboolean
 purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id,
--- a/libpurple/media.h	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/media.h	Sun Jan 30 17:52:06 2011 +0000
@@ -230,12 +230,6 @@
 					 const gchar *sess_id,
 					 const gchar *participant);
 
-#if 0
-/*
- * These two functions aren't being used and I'd rather not lock in the API
- * until they are needed. If they ever are.
- */
-
 /**
  * Gets the active local candidates for the stream.
  *
@@ -245,6 +239,8 @@
  *                    from.
  *
  * @return The active candidates retrieved.
+ *
+ * @since 2.8.0
  */
 GList *purple_media_get_active_local_candidates(PurpleMedia *media,
 		const gchar *sess_id, const gchar *participant);
@@ -258,10 +254,11 @@
  *                    from.
  *
  * @return The remote candidates retrieved.
+ *
+ * @since 2.8.0
  */
 GList *purple_media_get_active_remote_candidates(PurpleMedia *media,
 		const gchar *sess_id, const gchar *participant);
-#endif
 
 /**
  * Sets remote candidates from the stream.
--- a/libpurple/mediamanager.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/mediamanager.c	Sun Jan 30 17:52:06 2011 +0000
@@ -419,7 +419,30 @@
 
 #ifdef USE_GSTREAMER
 
-static GstCaps *
+void
+purple_media_manager_set_video_caps(PurpleMediaManager *manager, GstCaps *caps)
+{
+#ifdef USE_VV
+	if (manager->priv->video_caps)
+		gst_caps_unref(manager->priv->video_caps);
+
+	manager->priv->video_caps = caps;
+
+	if (manager->priv->pipeline && manager->priv->video_src) {
+		gchar *id = purple_media_element_info_get_id(manager->priv->video_src);
+		GstElement *src = gst_bin_get_by_name(GST_BIN(manager->priv->pipeline), id);
+
+		if (src) {
+			GstElement *capsfilter = gst_bin_get_by_name(GST_BIN(src), "prpl_video_caps");
+			g_object_set(G_OBJECT(capsfilter), "caps", caps, NULL);
+		}
+
+		g_free(id);
+	}
+#endif
+}
+
+GstCaps *
 purple_media_manager_get_video_caps(PurpleMediaManager *manager)
 {
 #ifdef USE_VV
--- a/libpurple/notify.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/notify.c	Sun Jan 30 17:52:06 2011 +0000
@@ -602,6 +602,18 @@
 }
 
 void
+purple_notify_user_info_add_pair_plaintext(PurpleNotifyUserInfo *user_info, const char *label, const char *value)
+{
+	gchar *escaped;
+	PurpleNotifyUserInfoEntry *entry;
+
+	escaped = g_markup_escape_text(value, -1);
+	entry = purple_notify_user_info_entry_new(label, escaped);
+	g_free(escaped);
+	user_info->user_info_entries = g_list_append(user_info->user_info_entries, entry);
+}
+
+void
 purple_notify_user_info_prepend_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value)
 {
 	PurpleNotifyUserInfoEntry *entry;
--- a/libpurple/notify.h	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/notify.h	Sun Jan 30 17:52:06 2011 +0000
@@ -540,13 +540,28 @@
  *                   a colon.  If NULL, value will be displayed without a
  *                   label.
  * @param value      The value, which might be displayed by a UI after
- *                   the label.  If NULL, label will still be displayed;
- *                   the UI should then treat label as independent and not
+ *                   the label.  This should be valid HTML.  If you want
+ *                   to insert plaintext then use
+ *                   purple_notify_user_info_add_pair_plaintext(), instead.
+ *                   If this is NULL the label will still be displayed;
+ *                   the UI should treat label as independent and not
  *                   include a colon if it would otherwise.
  */
+/*
+ * TODO: In 3.0.0 this function should be renamed to
+ *       purple_notify_user_info_add_pair_html().  And optionally
+ *       purple_notify_user_info_add_pair_plaintext() could be renamed to
+ *       purple_notify_user_info_add_pair().
+ */
 void purple_notify_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value);
 
 /**
+ * Like purple_notify_user_info_add_pair, but value should be plaintext
+ * and will be escaped using g_markup_escape_text().
+ */
+void purple_notify_user_info_add_pair_plaintext(PurpleNotifyUserInfo *user_info, const char *label, const char *value);
+
+/**
  * Prepend a label/value pair to a PurpleNotifyUserInfo object
  *
  * @param user_info  The PurpleNotifyUserInfo
--- a/libpurple/protocols/jabber/buddy.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Sun Jan 30 17:52:06 2011 +0000
@@ -1021,7 +1021,7 @@
 				if (!serverside_alias)
 					serverside_alias = g_strdup(text);
 
-				purple_notify_user_info_add_pair(user_info, _("Full Name"), text);
+				purple_notify_user_info_add_pair_plaintext(user_info, _("Full Name"), text);
 			} else if(!strcmp(child->name, "N")) {
 				for(child2 = child->child; child2; child2 = child2->next)
 				{
@@ -1032,11 +1032,11 @@
 
 					text2 = xmlnode_get_data(child2);
 					if(text2 && !strcmp(child2->name, "FAMILY")) {
-						purple_notify_user_info_add_pair(user_info, _("Family Name"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Family Name"), text2);
 					} else if(text2 && !strcmp(child2->name, "GIVEN")) {
-						purple_notify_user_info_add_pair(user_info, _("Given Name"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Given Name"), text2);
 					} else if(text2 && !strcmp(child2->name, "MIDDLE")) {
-						purple_notify_user_info_add_pair(user_info, _("Middle Name"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Middle Name"), text2);
 					}
 					g_free(text2);
 				}
@@ -1047,10 +1047,10 @@
 					g_free(serverside_alias);
 					serverside_alias = g_strdup(text);
 
-					purple_notify_user_info_add_pair(user_info, _("Nickname"), text);
+					purple_notify_user_info_add_pair_plaintext(user_info, _("Nickname"), text);
 				}
 			} else if(text && !strcmp(child->name, "BDAY")) {
-				purple_notify_user_info_add_pair(user_info, _("Birthday"), text);
+				purple_notify_user_info_add_pair_plaintext(user_info, _("Birthday"), text);
 			} else if(!strcmp(child->name, "ADR")) {
 				gboolean address_line_added = FALSE;
 
@@ -1074,25 +1074,25 @@
 					}
 
 					if(!strcmp(child2->name, "POBOX")) {
-						purple_notify_user_info_add_pair(user_info, _("P.O. Box"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("P.O. Box"), text2);
 					} else if (g_str_equal(child2->name, "EXTADD") || g_str_equal(child2->name, "EXTADR")) {
 						/*
 						 * EXTADD is correct, EXTADR is generated by other
 						 * clients. The next time someone reads this, remove
 						 * EXTADR.
 						 */
-						purple_notify_user_info_add_pair(user_info, _("Extended Address"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Extended Address"), text2);
 					} else if(!strcmp(child2->name, "STREET")) {
-						purple_notify_user_info_add_pair(user_info, _("Street Address"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Street Address"), text2);
 					} else if(!strcmp(child2->name, "LOCALITY")) {
-						purple_notify_user_info_add_pair(user_info, _("Locality"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Locality"), text2);
 					} else if(!strcmp(child2->name, "REGION")) {
-						purple_notify_user_info_add_pair(user_info, _("Region"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Region"), text2);
 					} else if(!strcmp(child2->name, "PCODE")) {
-						purple_notify_user_info_add_pair(user_info, _("Postal Code"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Postal Code"), text2);
 					} else if(!strcmp(child2->name, "CTRY")
 								|| !strcmp(child2->name, "COUNTRY")) {
-						purple_notify_user_info_add_pair(user_info, _("Country"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Country"), text2);
 					}
 					g_free(text2);
 				}
@@ -1106,13 +1106,13 @@
 					/* show what kind of number it is */
 					number = xmlnode_get_data(child2);
 					if(number) {
-						purple_notify_user_info_add_pair(user_info, _("Telephone"), number);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Telephone"), number);
 						g_free(number);
 					}
 				} else if((number = xmlnode_get_data(child))) {
 					/* lots of clients (including purple) do this, but it's
 					 * out of spec */
-					purple_notify_user_info_add_pair(user_info, _("Telephone"), number);
+					purple_notify_user_info_add_pair_plaintext(user_info, _("Telephone"), number);
 					g_free(number);
 				}
 			} else if(!strcmp(child->name, "EMAIL")) {
@@ -1153,18 +1153,18 @@
 
 					text2 = xmlnode_get_data(child2);
 					if(text2 && !strcmp(child2->name, "ORGNAME")) {
-						purple_notify_user_info_add_pair(user_info, _("Organization Name"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Organization Name"), text2);
 					} else if(text2 && !strcmp(child2->name, "ORGUNIT")) {
-						purple_notify_user_info_add_pair(user_info, _("Organization Unit"), text2);
+						purple_notify_user_info_add_pair_plaintext(user_info, _("Organization Unit"), text2);
 					}
 					g_free(text2);
 				}
 			} else if(text && !strcmp(child->name, "TITLE")) {
-				purple_notify_user_info_add_pair(user_info, _("Job Title"), text);
+				purple_notify_user_info_add_pair_plaintext(user_info, _("Job Title"), text);
 			} else if(text && !strcmp(child->name, "ROLE")) {
-				purple_notify_user_info_add_pair(user_info, _("Role"), text);
+				purple_notify_user_info_add_pair_plaintext(user_info, _("Role"), text);
 			} else if(text && !strcmp(child->name, "DESC")) {
-				purple_notify_user_info_add_pair(user_info, _("Description"), text);
+				purple_notify_user_info_add_pair_plaintext(user_info, _("Description"), text);
 			} else if(!strcmp(child->name, "PHOTO") ||
 					!strcmp(child->name, "LOGO")) {
 				char *bintext = NULL;
--- a/libpurple/protocols/msn/msn.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/protocols/msn/msn.c	Sun Jan 30 17:52:06 2011 +0000
@@ -1042,7 +1042,6 @@
 		const char *psm, *name;
 		const char *mediatype = NULL;
 		char *currentmedia = NULL;
-		char *tmp;
 
 		psm = purple_status_get_attr_string(status, "message");
 		if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
@@ -1086,9 +1085,7 @@
 			}
 
 			if (psm != NULL && *psm) {
-				tmp = g_markup_escape_text(psm, -1);
-				purple_notify_user_info_add_pair(user_info, tmp2, tmp);
-				g_free(tmp);
+				purple_notify_user_info_add_pair_plaintext(user_info, tmp2, psm);
 			} else {
 				purple_notify_user_info_add_pair(user_info, _("Status"), tmp2);
 			}
@@ -1096,13 +1093,11 @@
 			g_free(tmp2);
 		} else {
 			if (psm != NULL && *psm) {
-				tmp = g_markup_escape_text(psm, -1);
 				if (purple_presence_is_idle(presence)) {
-					purple_notify_user_info_add_pair(user_info, _("Idle"), tmp);
+					purple_notify_user_info_add_pair_plaintext(user_info, _("Idle"), psm);
 				} else {
-					purple_notify_user_info_add_pair(user_info, _("Status"), tmp);
+					purple_notify_user_info_add_pair_plaintext(user_info, _("Status"), psm);
 				}
-				g_free(tmp);
 			} else {
 				if (purple_presence_is_idle(presence)) {
 					purple_notify_user_info_add_pair(user_info, _("Status"),
@@ -2305,9 +2300,7 @@
 		alias = purple_buddy_get_local_buddy_alias(b);
 		if (alias && alias[0])
 		{
-			char *aliastext = g_markup_escape_text(alias, -1);
-			purple_notify_user_info_add_pair(user_info, _("Alias"), aliastext);
-			g_free(aliastext);
+			purple_notify_user_info_add_pair_plaintext(user_info, _("Alias"), alias);
 		}
 
 		if ((alias = purple_buddy_get_server_alias(b)) != NULL)
--- a/libpurple/protocols/yahoo/libymsg.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/protocols/yahoo/libymsg.c	Sun Jan 30 17:52:06 2011 +0000
@@ -3985,7 +3985,6 @@
 void yahoo_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
 {
 	YahooFriend *f;
-	char *escaped;
 	char *status = NULL;
 	const char *presence = NULL;
 	PurpleAccount *account;
@@ -4024,14 +4023,12 @@
 	}
 
 	if (status != NULL) {
-		escaped = g_markup_escape_text(status, strlen(status));
-		purple_notify_user_info_add_pair(user_info, _("Status"), escaped);
+		purple_notify_user_info_add_pair_plaintext(user_info, _("Status"), status);
 		g_free(status);
-		g_free(escaped);
 	}
 
 	if (presence != NULL)
-		purple_notify_user_info_add_pair(user_info, _("Presence"), presence);
+		purple_notify_user_info_add_pair_plaintext(user_info, _("Presence"), presence);
 
 	if (f && full) {
 		YahooPersonalDetails *ypd = &f->ypd;
--- a/libpurple/protocols/yahoo/yahoo_profile.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/protocols/yahoo/yahoo_profile.c	Sun Jan 30 17:52:06 2011 +0000
@@ -701,14 +701,12 @@
 	if (b) {
 		const char *balias = purple_buddy_get_local_buddy_alias(b);
 		if(balias && balias[0]) {
-			char *aliastext = g_markup_escape_text(balias, -1);
-			purple_notify_user_info_add_pair(user_info, _("Alias"), aliastext);
-			g_free(aliastext);
+			purple_notify_user_info_add_pair_plaintext(user_info, _("Alias"), balias);
 		}
 		#if 0
 		if (b->idle > 0) {
 			char *idletime = purple_str_seconds_to_string(time(NULL) - b->idle);
-			purple_notify_user_info_add_pair(user_info, _("Idle"), idletime);
+			purple_notify_user_info_add_pair_plaintext(user_info, _("Idle"), idletime);
 			g_free(idletime);
 		}
 		#endif
@@ -719,7 +717,7 @@
 		if ((f = yahoo_friend_find(info_data->gc, purple_buddy_get_name(b)))) {
 			const char *ip;
 			if ((ip = yahoo_friend_get_ip(f)))
-				purple_notify_user_info_add_pair(user_info, _("IP Address"), ip);
+				purple_notify_user_info_add_pair_plaintext(user_info, _("IP Address"), ip);
 		}
 	}
 }
--- a/libpurple/signals.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/signals.c	Sun Jan 30 17:52:06 2011 +0000
@@ -818,6 +818,21 @@
 		*return_val = GINT_TO_POINTER(ret_val);
 }
 
+	void
+purple_marshal_INT__POINTER_POINTER_POINTER(
+		PurpleCallback cb, va_list args, void *data, void **return_val)
+{
+	gint ret_val;
+	void *arg1 = va_arg(args, void *);
+	void *arg2 = va_arg(args, void *);
+	void *arg3 = va_arg(args, void *);
+
+	ret_val = ((gint (*)(void *, void *, void *, void *))cb)(arg1, arg2, arg3, data);
+
+	if (return_val != NULL)
+		*return_val = GINT_TO_POINTER(ret_val);
+}
+
 void
 purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER(
 		PurpleCallback cb, va_list args, void *data, void **return_val)
--- a/libpurple/signals.h	Sun Jan 30 17:51:40 2011 +0000
+++ b/libpurple/signals.h	Sun Jan 30 17:52:06 2011 +0000
@@ -330,6 +330,8 @@
 		PurpleCallback cb, va_list args, void *data, void **return_val);
 void purple_marshal_INT__POINTER_POINTER(
 		PurpleCallback cb, va_list args, void *data, void **return_val);
+void purple_marshal_INT__POINTER_POINTER_POINTER(
+		PurpleCallback cb, va_list args, void *data, void **return_val);
 void purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER(
 		PurpleCallback cb, va_list args, void *data, void **return_val);
 
--- a/pidgin/gtkaccount.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkaccount.c	Sun Jan 30 17:52:06 2011 +0000
@@ -2141,7 +2141,6 @@
 create_accounts_list(AccountsWindow *dialog)
 {
 	GtkWidget *frame;
-	GtkWidget *sw;
 	GtkWidget *label;
 	GtkWidget *treeview;
 	GtkTreeSelection *sel;
@@ -2181,16 +2180,6 @@
 	gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
 	gtk_notebook_append_page(GTK_NOTEBOOK(accounts_window->notebook), label, NULL);
 
-	/* Create the scrolled window. */
-	sw = gtk_scrolled_window_new(0, 0);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-					GTK_POLICY_AUTOMATIC,
-					GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-					GTK_SHADOW_NONE);
-	gtk_notebook_append_page(GTK_NOTEBOOK(accounts_window->notebook), sw, NULL);
-	gtk_widget_show(sw);
-
 	/* Create the list model. */
 	dialog->model = gtk_list_store_new(NUM_COLUMNS,
 					GDK_TYPE_PIXBUF,   /* COLUMN_ICON */
@@ -2216,7 +2205,9 @@
 	g_signal_connect(G_OBJECT(treeview), "button_press_event",
 					 G_CALLBACK(account_treeview_double_click_cb), dialog);
 
-	gtk_container_add(GTK_CONTAINER(sw), treeview);
+	gtk_notebook_append_page(GTK_NOTEBOOK(accounts_window->notebook),
+		pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_NONE, -1, -1), 
+		NULL);
 
 	add_columns(treeview, dialog);
 	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(treeview));
--- a/pidgin/gtkblist.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkblist.c	Sun Jan 30 17:52:06 2011 +0000
@@ -5731,7 +5731,6 @@
 	GtkTreeViewColumn *column;
 	GtkWidget *menu;
 	GtkWidget *ebox;
-	GtkWidget *sw;
 	GtkWidget *sep;
 	GtkWidget *label;
 	GtkWidget *close;
@@ -5882,11 +5881,6 @@
 	g_signal_connect(G_OBJECT(ebox), "button-press-event", G_CALLBACK(headline_box_press_cb), gtkblist);
 
 	/****************************** GtkTreeView **********************************/
-	sw = gtk_scrolled_window_new(NULL,NULL);
-	gtk_widget_show(sw);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_NONE);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
 	gtkblist->treemodel = gtk_tree_store_new(BLIST_COLUMNS,
 						 GDK_TYPE_PIXBUF, /* Status icon */
 						 G_TYPE_BOOLEAN,  /* Status icon visible */
@@ -5966,8 +5960,9 @@
 	gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(gtkblist->treeview),
 			pidgin_blist_search_equal_func, NULL, NULL);
 
-	gtk_box_pack_start(GTK_BOX(gtkblist->vbox), sw, TRUE, TRUE, 0);
-	gtk_container_add(GTK_CONTAINER(sw), gtkblist->treeview);
+	gtk_box_pack_start(GTK_BOX(gtkblist->vbox), 
+		pidgin_make_scrollable(gtkblist->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_NONE, -1, -1), 
+		TRUE, TRUE, 0);
 
 	sep = gtk_hseparator_new();
 	gtk_box_pack_start(GTK_BOX(gtkblist->vbox), sep, FALSE, FALSE, 0);
--- a/pidgin/gtkcertmgr.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkcertmgr.c	Sun Jan 30 17:52:06 2011 +0000
@@ -390,7 +390,6 @@
 {
 	GtkWidget *bbox;
 	GtkListStore *store;
-	GtkWidget *sw;
 
 	/* This block of variables will end up in tpm_dat */
 	GtkTreeView *listview;
@@ -417,16 +416,6 @@
 	g_signal_connect(G_OBJECT(mgmt_widget), "destroy",
 			 G_CALLBACK(tls_peers_mgmt_destroy), NULL);
 
-	/* Scrolled window */
-	sw = gtk_scrolled_window_new(NULL,NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-			GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
-	gtk_box_pack_start(GTK_BOX(mgmt_widget), GTK_WIDGET(sw),
-			TRUE, TRUE, /* Take up lots of space */
-			0);
-	gtk_widget_show(GTK_WIDGET(sw));
-
 	/* List view */
 	store = gtk_list_store_new(TPM_N_COLUMNS, G_TYPE_STRING);
 
@@ -463,7 +452,10 @@
 	g_signal_connect(G_OBJECT(select), "changed",
 			 G_CALLBACK(tls_peers_mgmt_select_chg_cb), NULL);
 
-	gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(listview));
+	gtk_box_pack_start(GTK_BOX(mgmt_widget), 
+			pidgin_make_scrollable(GTK_WIDGET(listview), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1),
+			TRUE, TRUE, /* Take up lots of space */
+			0);
 	gtk_widget_show(GTK_WIDGET(listview));
 
 	/* Fill the list for the first time */
--- a/pidgin/gtkconv.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkconv.c	Sun Jan 30 17:52:06 2011 +0000
@@ -4695,7 +4695,7 @@
 setup_chat_userlist(PidginConversation *gtkconv, GtkWidget *hpaned)
 {
 	PidginChatPane *gtkchat = gtkconv->u.chat;
-	GtkWidget *lbox, *sw, *list;
+	GtkWidget *lbox, *list;
 	GtkListStore *ls;
 	GtkCellRenderer *rend;
 	GtkTreeViewColumn *col;
@@ -4715,12 +4715,6 @@
 	gtk_widget_show(gtkchat->count);
 
 	/* Setup the list of users. */
-	sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-								   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
-	gtk_box_pack_start(GTK_BOX(lbox), sw, TRUE, TRUE, 0);
-	gtk_widget_show(sw);
 
 	ls = gtk_list_store_new(CHAT_USERS_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING,
 							G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT,
@@ -4790,7 +4784,9 @@
 
 	gtkchat->list = list;
 
-	gtk_container_add(GTK_CONTAINER(sw), list);
+	gtk_box_pack_start(GTK_BOX(lbox), 
+		pidgin_make_scrollable(list, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1),
+		TRUE, TRUE, 0);
 }
 
 static gboolean
@@ -4897,7 +4893,6 @@
 	PurpleConversation *conv = gtkconv->active_conv;
 	PurpleBuddy *buddy;
 	gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT);
-	GtkPolicyType imhtml_sw_hscroll;
 	int buddyicon_size = 0;
 
 	/* Setup the top part of the pane */
@@ -5014,10 +5009,7 @@
 	gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml),TRUE);
 	g_object_set_data(G_OBJECT(gtkconv->imhtml), "gtkconv", gtkconv);
 
-	gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(imhtml_sw),
-	                               &imhtml_sw_hscroll, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(imhtml_sw),
-	                               imhtml_sw_hscroll, GTK_POLICY_ALWAYS);
+	g_object_set(G_OBJECT(imhtml_sw), "vscrollbar-policy", GTK_POLICY_ALWAYS, NULL);
 
 	g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event",
 	                       G_CALLBACK(entry_stop_rclick_cb), NULL);
--- a/pidgin/gtkft.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkft.c	Sun Jan 30 17:52:06 2011 +0000
@@ -557,22 +557,12 @@
 static GtkWidget *
 setup_tree(PidginXferDialog *dialog)
 {
-	GtkWidget *sw;
 	GtkWidget *tree;
 	GtkListStore *model;
 	GtkCellRenderer *renderer;
 	GtkTreeViewColumn *column;
 	GtkTreeSelection *selection;
 
-	/* Create the scrolled window. */
-	sw = gtk_scrolled_window_new(0, 0);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-						GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-					GTK_POLICY_AUTOMATIC,
-					GTK_POLICY_AUTOMATIC);
-	gtk_widget_show(sw);
-
 	/* Build the tree model */
 	/* Transfer type, Progress Bar, Filename, Size, Remaining */
 	model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_INT,
@@ -636,10 +626,9 @@
 
 	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(tree));
 
-	gtk_container_add(GTK_CONTAINER(sw), tree);
 	gtk_widget_show(tree);
 
-	return sw;
+	return tree;
 }
 
 static GtkWidget *
@@ -713,7 +702,6 @@
 	PidginXferDialog *dialog;
 	GtkWidget *window;
 	GtkWidget *vbox1, *vbox2;
-	GtkWidget *sw;
 	GtkWidget *expander;
 	GtkWidget *alignment;
 	GtkWidget *table;
@@ -744,9 +732,9 @@
 	gtk_widget_show(vbox2);
 
 	/* Setup the listbox */
-	sw = setup_tree(dialog);
-	gtk_box_pack_start(GTK_BOX(vbox2), sw, TRUE, TRUE, 0);
-	gtk_widget_set_size_request(sw,-1, 140);
+	gtk_box_pack_start(GTK_BOX(vbox2), 
+		pidgin_make_scrollable(setup_tree(dialog), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, 140), 
+		TRUE, TRUE, 0);
 
 	/* "Close this window when all transfers finish" */
 	checkbox = gtk_check_button_new_with_mnemonic(
--- a/pidgin/gtkimhtmltoolbar.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Sun Jan 30 17:52:06 2011 +0000
@@ -858,14 +858,9 @@
 		g_signal_connect(G_OBJECT(dialog), "button-press-event", (GCallback)smiley_dialog_input_cb, toolbar);
 	}
 
-	scrolled = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_NONE);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled),
-			GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+
+	scrolled = pidgin_make_scrollable(smiley_table, GTK_POLICY_NEVER, GTK_POLICY_NEVER, GTK_SHADOW_NONE, -1, -1);
 	gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0);
-	gtk_widget_show(scrolled);
-
-	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), smiley_table);
 	gtk_widget_show(smiley_table);
 
 	viewport = gtk_widget_get_parent(smiley_table);
@@ -890,8 +885,10 @@
 	 * makes one or both scrollbars visible (sometimes).
 	 * I too think this hack is gross. But I couldn't find a better way -- sadrul */
 	gtk_window_set_resizable(GTK_WINDOW(dialog), TRUE);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled),
-			GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	g_object_set(G_OBJECT(scrolled),
+		"hscrollbar-policy", GTK_POLICY_AUTOMATIC,
+		"vscrollbar-policy", GTK_POLICY_AUTOMATIC,
+		NULL);
 
 #ifdef _WIN32
 	winpidgin_ensure_onscreen(dialog);
--- a/pidgin/gtklog.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtklog.c	Sun Jan 30 17:52:06 2011 +0000
@@ -531,7 +531,6 @@
 	GtkWidget *title_box;
 	char *text;
 	GtkWidget *pane;
-	GtkWidget *sw;
 	GtkCellRenderer *rend;
 	GtkTreeViewColumn *col;
 	GtkTreeSelection *sel;
@@ -614,10 +613,6 @@
 	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lv->window)->vbox), pane, TRUE, TRUE, 0);
 
 	/* List *************/
-	sw = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-	gtk_paned_add1(GTK_PANED(pane), sw);
 	lv->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
 	lv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (lv->treestore));
 	g_object_unref(G_OBJECT(lv->treestore));
@@ -625,7 +620,8 @@
 	col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL);
 	gtk_tree_view_append_column (GTK_TREE_VIEW(lv->treeview), col);
 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (lv->treeview), FALSE);
-	gtk_container_add (GTK_CONTAINER (sw), lv->treeview);
+	gtk_paned_add1(GTK_PANED(pane), 
+		pidgin_make_scrollable(lv->treeview, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1));
 
 	populate_log_tree(lv);
 
--- a/pidgin/gtknotify.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtknotify.c	Sun Jan 30 17:52:06 2011 +0000
@@ -956,7 +956,6 @@
 
 	GtkWidget *vbox;
 	GtkWidget *label;
-	GtkWidget *sw;
 	PidginNotifySearchResultsData *data;
 	char *label_text;
 	char *primary_esc, *secondary_esc;
@@ -1012,15 +1011,6 @@
 	model = gtk_list_store_newv(col_num, col_types);
 	g_free(col_types);
 
-	/* Setup the scrolled window containing the treeview */
-	sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-								   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-										GTK_SHADOW_IN);
-	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-	gtk_widget_show(sw);
-
 	/* Setup the treeview */
 	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
 	g_object_unref(G_OBJECT(model));
@@ -1029,7 +1019,9 @@
 	gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
 								GTK_SELECTION_SINGLE);
 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);
-	gtk_container_add(GTK_CONTAINER(sw), treeview);
+	gtk_box_pack_start(GTK_BOX(vbox),
+		pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1),
+		TRUE, TRUE, 0);
 	gtk_widget_show(treeview);
 
 	renderer = gtk_cell_renderer_pixbuf_new();
@@ -1488,7 +1480,6 @@
 	GtkTreeStore *model = NULL;
 	GtkWidget *dialog = NULL;
 	GtkWidget *label = NULL;
-	GtkWidget *sw;
 	GtkCellRenderer *rend;
 	GtkTreeViewColumn *column;
 	GtkWidget *button = NULL;
@@ -1526,10 +1517,6 @@
 	/* Golden ratio it up! */
 	gtk_widget_set_size_request(dialog, 550, 400);
 
-	sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-
 	spec_dialog = g_new0(PidginNotifyDialog, 1);
 	spec_dialog->dialog = dialog;
 
@@ -1538,7 +1525,6 @@
 	g_object_unref(G_OBJECT(model));
 
 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(spec_dialog->treeview), TRUE);
-	gtk_container_add(GTK_CONTAINER(sw), spec_dialog->treeview);
 
 	if (type == PIDGIN_NOTIFY_MAIL) {
 		gtk_window_set_title(GTK_WINDOW(dialog), _("New Mail"));
@@ -1653,7 +1639,9 @@
 	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 2);
+	gtk_box_pack_start(GTK_BOX(vbox), 
+		pidgin_make_scrollable(spec_dialog->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1),
+		TRUE, TRUE, 2);
 
 	return spec_dialog;
 }
--- a/pidgin/gtkplugin.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkplugin.c	Sun Jan 30 17:52:06 2011 +0000
@@ -706,7 +706,6 @@
 
 void pidgin_plugin_dialog_show()
 {
-	GtkWidget *sw;
 	GtkWidget *event_view;
 	GtkListStore *ls;
 	GtkCellRenderer *rend, *rendt;
@@ -729,12 +728,6 @@
 	gtk_widget_set_sensitive(pref_button, FALSE);
 	gtk_window_set_role(GTK_WINDOW(plugin_dialog), "plugins");
 
-	sw = gtk_scrolled_window_new(NULL,NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
-
-	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(plugin_dialog)->vbox), sw, TRUE, TRUE, 0);
-
 	ls = gtk_list_store_new(4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls),
 					     1, GTK_SORT_ASCENDING);
@@ -779,7 +772,9 @@
 	gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col);
 	gtk_tree_view_column_set_sort_column_id(col, 1);
 	g_object_unref(G_OBJECT(ls));
-	gtk_container_add(GTK_CONTAINER(sw), event_view);
+	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(plugin_dialog)->vbox), 
+		pidgin_make_scrollable(event_view, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1), 
+		TRUE, TRUE, 0);
 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(event_view), 1);
 	gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(event_view),
 				pidgin_tree_view_search_equal_func, NULL, NULL);
--- a/pidgin/gtkpounce.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkpounce.c	Sun Jan 30 17:52:06 2011 +0000
@@ -1221,21 +1221,11 @@
 static GtkWidget *
 create_pounces_list(PouncesManager *dialog)
 {
-	GtkWidget *sw;
 	GtkWidget *treeview;
 	GtkTreeSelection *sel;
 	GtkTreeViewColumn *column;
 	GtkCellRenderer *renderer;
 
-	/* Create the scrolled window */
-	sw = gtk_scrolled_window_new(0, 0);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-					GTK_POLICY_AUTOMATIC,
-					GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-						GTK_SHADOW_IN);
-	gtk_widget_show(sw);
-
 	/* Create the list model */
 	dialog->model = gtk_list_store_new(POUNCES_MANAGER_NUM_COLUMNS,
 									   G_TYPE_POINTER,
@@ -1259,7 +1249,6 @@
 	/* Handle double-clicking */
 	g_signal_connect(G_OBJECT(treeview), "button_press_event",
 					 G_CALLBACK(pounce_double_click_cb), dialog);
-	gtk_container_add(GTK_CONTAINER(sw), treeview);
 	gtk_widget_show(treeview);
 
 	/* Pouncee Column */
@@ -1319,7 +1308,7 @@
 	/* Populate list */
 	populate_pounces_list(dialog);
 
-	return sw;
+	return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1);
 }
 
 void
--- a/pidgin/gtkprefs.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkprefs.c	Sun Jan 30 17:52:06 2011 +0000
@@ -2513,12 +2513,6 @@
 			vbox->parent->parent, TRUE, TRUE, 0, GTK_PACK_START);
 
 	/* SOUND SELECTION */
-	sw = gtk_scrolled_window_new(NULL,NULL);
-	gtk_widget_set_size_request(sw, -1, 100);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
-
-	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
 	event_store = gtk_list_store_new (4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
 
 	for (j=0; j < PURPLE_NUM_SOUNDS; j++) {
@@ -2567,7 +2561,9 @@
 							NULL);
 	gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col);
 	g_object_unref(G_OBJECT(event_store));
-	gtk_container_add(GTK_CONTAINER(sw), event_view);
+	gtk_box_pack_start(GTK_BOX(vbox),
+		pidgin_make_scrollable(event_view, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, 100),
+		TRUE, TRUE, 0);
 
 	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
--- a/pidgin/gtkprivacy.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkprivacy.c	Sun Jan 30 17:52:06 2011 +0000
@@ -133,12 +133,6 @@
 	GtkTreeViewColumn *column;
 	GtkTreeSelection *sel;
 
-	sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-					GTK_POLICY_AUTOMATIC,
-					GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
-
 	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
 	*ret_treeview = treeview;
 
@@ -150,7 +144,7 @@
 	gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(column), TRUE);
 	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
-	gtk_container_add(GTK_CONTAINER(sw), treeview);
+	sw = pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, 200);
 
 	gtk_widget_show(treeview);
 
@@ -159,8 +153,6 @@
 	g_signal_connect(G_OBJECT(sel), "changed",
 					 G_CALLBACK(user_selected_cb), dialog);
 
-	gtk_widget_set_size_request(sw, -1, 200);
-
 	return sw;
 }
 
--- a/pidgin/gtkrequest.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkrequest.c	Sun Jan 30 17:52:06 2011 +0000
@@ -419,16 +419,6 @@
 	}
 	else {
 		if (multiline) {
-			GtkWidget *sw;
-
-			sw = gtk_scrolled_window_new(NULL, NULL);
-			gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-										   GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-			gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-												GTK_SHADOW_IN);
-
-			gtk_widget_set_size_request(sw, 320, 130);
-
 			/* GtkTextView */
 			entry = gtk_text_view_new();
 			gtk_text_view_set_editable(GTK_TEXT_VIEW(entry), TRUE);
@@ -442,12 +432,12 @@
 
 			gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(entry), GTK_WRAP_WORD_CHAR);
 
-			gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-
 			if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/spellcheck"))
 				pidgin_setup_gtkspell(GTK_TEXT_VIEW(entry));
 
-			gtk_container_add(GTK_CONTAINER(sw), entry);
+			gtk_box_pack_start(GTK_BOX(vbox), 
+				pidgin_make_scrollable(entry, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, 320, 130),
+				TRUE, TRUE, 0);
 		}
 		else {
 			entry = gtk_entry_new();
@@ -852,12 +842,6 @@
 	{
 		GtkWidget *textview;
 
-		widget = gtk_scrolled_window_new(NULL, NULL);
-		gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget),
-											GTK_SHADOW_IN);
-		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
-									   GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-
 		textview = gtk_text_view_new();
 		gtk_text_view_set_editable(GTK_TEXT_VIEW(textview),
 								   TRUE);
@@ -867,11 +851,8 @@
 		if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/spellcheck"))
 			pidgin_setup_gtkspell(GTK_TEXT_VIEW(textview));
 
-		gtk_container_add(GTK_CONTAINER(widget), textview);
 		gtk_widget_show(textview);
 
-		gtk_widget_set_size_request(widget, -1, 75);
-
 		if (value != NULL)
 		{
 			GtkTextBuffer *buffer;
@@ -893,6 +874,8 @@
 			g_signal_connect(G_OBJECT(buffer), "changed",
 							 G_CALLBACK(req_entry_field_changed_cb), field);
 	    }
+
+		widget = pidgin_make_scrollable(textview, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, 75);
 	}
 	else
 	{
@@ -1093,7 +1076,6 @@
 static GtkWidget *
 create_list_field(PurpleRequestField *field)
 {
-	GtkWidget *sw;
 	GtkWidget *treeview;
 	GtkListStore *store;
 	GtkCellRenderer *renderer;
@@ -1105,14 +1087,6 @@
 
 	icons = purple_request_field_list_get_icons(field);
 
-	/* Create the scrolled window */
-	sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-				       GTK_POLICY_AUTOMATIC,
-				       GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-										GTK_SHADOW_IN);
-	gtk_widget_show(sw);
 
 	/* Create the list store */
 	if (icons)
@@ -1188,10 +1162,9 @@
 	g_signal_connect(G_OBJECT(sel), "changed",
 					 G_CALLBACK(list_field_select_changed_cb), field);
 
-	gtk_container_add(GTK_CONTAINER(sw), treeview);
 	gtk_widget_show(treeview);
 
-	return sw;
+	return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1);
 }
 
 static void *
@@ -1212,7 +1185,6 @@
 	GtkWidget *table;
 	GtkWidget *button;
 	GtkWidget *img;
-	GtkWidget *sw;
 	GtkSizeGroup *sg;
 	GList *gl, *fl;
 	PurpleRequestFieldGroup *group;
@@ -1297,18 +1269,10 @@
 	if(total_fields > 9) {
 		GtkWidget *hbox_for_spacing, *vbox_for_spacing;
 
-		sw = gtk_scrolled_window_new(NULL, NULL);
-		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-				GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-		gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-				GTK_SHADOW_NONE);
-		gtk_widget_set_size_request(sw, -1, 200);
-		gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-		gtk_widget_show(sw);
-
 		hbox_for_spacing = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER);
-		gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw),
-				hbox_for_spacing);
+		gtk_box_pack_start(GTK_BOX(vbox), 
+			pidgin_make_scrollable(hbox_for_spacing, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, GTK_SHADOW_NONE, -1, 200), 
+			TRUE, TRUE, 0);
 		gtk_widget_show(hbox_for_spacing);
 
 		vbox_for_spacing = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
--- a/pidgin/gtkroomlist.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkroomlist.c	Sun Jan 30 17:52:06 2011 +0000
@@ -548,15 +548,8 @@
 	pidgin_add_widget_to_vbox(GTK_BOX(vbox2), _("_Account:"), NULL, dialog->account_widget, TRUE, NULL);
 
 	/* scrolled window */
-	dialog->sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(dialog->sw),
-	                                    GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dialog->sw),
-	                               GTK_POLICY_AUTOMATIC,
-	                               GTK_POLICY_AUTOMATIC);
+	dialog->sw = pidgin_make_scrollable(NULL, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, 250);
 	gtk_box_pack_start(GTK_BOX(vbox2), dialog->sw, TRUE, TRUE, 0);
-	gtk_widget_set_size_request(dialog->sw, -1, 250);
-	gtk_widget_show(dialog->sw);
 
 	/* progress bar */
 	dialog->progress = gtk_progress_bar_new();
--- a/pidgin/gtksavedstatuses.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtksavedstatuses.c	Sun Jan 30 17:52:06 2011 +0000
@@ -438,20 +438,11 @@
 static GtkWidget *
 create_saved_status_list(StatusWindow *dialog)
 {
-	GtkWidget *sw;
 	GtkWidget *treeview;
 	GtkTreeSelection *sel;
 	GtkTreeViewColumn *column;
 	GtkCellRenderer *renderer;
 
-	/* Create the scrolled window */
-	sw = gtk_scrolled_window_new(0, 0);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-								   GTK_POLICY_AUTOMATIC,
-								   GTK_POLICY_ALWAYS);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-										GTK_SHADOW_IN);
-
 	/* Create the list model */
 	dialog->model = gtk_list_store_new(STATUS_WINDOW_NUM_COLUMNS,
 									   G_TYPE_STRING,
@@ -472,8 +463,6 @@
 	g_signal_connect(G_OBJECT(sel), "changed",
 					 G_CALLBACK(status_selected_cb), dialog);
 
-	gtk_container_add(GTK_CONTAINER(sw), treeview);
-
 	/* Add columns */
 	column = gtk_tree_view_column_new();
 	gtk_tree_view_column_set_title(column, _("Title"));
@@ -527,9 +516,9 @@
 	/* Populate list */
 	populate_saved_status_list(dialog);
 
-	gtk_widget_show_all(sw);
+	gtk_widget_show_all(treeview);
 
-	return sw;
+	return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1);
 }
 
 static gboolean
@@ -1092,7 +1081,6 @@
 	GtkWidget *entry;
 	GtkWidget *frame;
 	GtkWidget *hbox;
-	GtkWidget *sw;
 	GtkWidget *text;
 	GtkWidget *toolbar;
 	GtkWidget *vbox;
@@ -1181,14 +1169,6 @@
 	dbox = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
 	gtk_container_add(GTK_CONTAINER(expander), dbox);
 
-	/* Different status message treeview */
-	sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-								   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-										GTK_SHADOW_IN);
-	gtk_box_pack_start(GTK_BOX(dbox), sw, TRUE, TRUE, 0);
-
 	/* Create the list model */
 	dialog->model = gtk_list_store_new(STATUS_EDITOR_NUM_COLUMNS,
 									   G_TYPE_POINTER,
@@ -1205,7 +1185,9 @@
 	dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE);
 	gtk_widget_set_size_request(dialog->treeview, -1, 150);
-	gtk_container_add(GTK_CONTAINER(sw), dialog->treeview);
+	gtk_box_pack_start(GTK_BOX(dbox), 
+		pidgin_make_scrollable(dialog->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1),
+		TRUE, TRUE, 0);
 
 	/* Add columns */
 	status_editor_add_columns(dialog);
--- a/pidgin/gtksmiley.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtksmiley.c	Sun Jan 30 17:52:06 2011 +0000
@@ -774,7 +774,6 @@
 
 static GtkWidget *smiley_list_create(SmileyManager *dialog)
 {
-	GtkWidget *sw;
 	GtkWidget *treeview;
 	GtkTreeSelection *sel;
 	GtkTargetEntry te[3] = {
@@ -783,14 +782,6 @@
 		{"STRING", 0, 2}
 	};
 
-	sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-			GTK_POLICY_AUTOMATIC,
-			GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-			GTK_SHADOW_IN);
-	gtk_widget_show(sw);
-
 	/* Create the list model */
 	dialog->model = gtk_list_store_new(N_COL,
 			GDK_TYPE_PIXBUF,	/* ICON */
@@ -807,7 +798,6 @@
 
 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
-	gtk_container_add(GTK_CONTAINER(sw), treeview);
 
 	g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(smile_selected_cb), dialog);
 	g_signal_connect(G_OBJECT(treeview), "row_activated", G_CALLBACK(smiley_edit_cb), dialog);
@@ -822,7 +812,7 @@
 	add_columns(treeview, dialog);
 	populate_smiley_list(dialog);
 
-	return sw;
+	return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1);
 }
 
 static void refresh_list()
--- a/pidgin/gtkstatusbox.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkstatusbox.c	Sun Jan 30 17:52:06 2011 +0000
@@ -1308,15 +1308,19 @@
   *width = GTK_WIDGET(status_box)->allocation.width;
 
   hpolicy = vpolicy = GTK_POLICY_NEVER;
-  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (status_box->scrolled_window),
-				  hpolicy, vpolicy);
+	g_object_set(G_OBJECT(status_box->scrolled_window),
+		"hscrollbar-policy", hpolicy,
+		"vscrollbar-policy", vpolicy,
+		NULL);
   gtk_widget_size_request (status_box->popup_frame, &popup_req);
 
   if (popup_req.width > *width)
     {
       hpolicy = GTK_POLICY_ALWAYS;
-      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (status_box->scrolled_window),
-				      hpolicy, vpolicy);
+			g_object_set(G_OBJECT(status_box->scrolled_window),
+				"hscrollbar-policy", hpolicy,
+				"vscrollbar-policy", vpolicy,
+				NULL);
       gtk_widget_size_request (status_box->popup_frame, &popup_req);
     }
 
@@ -1351,8 +1355,10 @@
     {
       vpolicy = GTK_POLICY_ALWAYS;
 
-      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (status_box->scrolled_window),
-				      hpolicy, vpolicy);
+			g_object_set(G_OBJECT(status_box->scrolled_window),
+				"hscrollbar-policy", hpolicy,
+				"vscrollbar-policy", vpolicy,
+				NULL);
     }
 }
 
@@ -1795,19 +1801,6 @@
 
 	gtk_widget_show (status_box->popup_frame);
 
-	status_box->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
-
-	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (status_box->scrolled_window),
-			GTK_POLICY_NEVER,
-			GTK_POLICY_NEVER);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (status_box->scrolled_window),
-			GTK_SHADOW_NONE);
-
-	gtk_widget_show (status_box->scrolled_window);
-
-	gtk_container_add (GTK_CONTAINER (status_box->popup_frame),
-			status_box->scrolled_window);
-
 	status_box->tree_view = gtk_tree_view_new ();
 	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (status_box->tree_view));
 	gtk_tree_selection_set_mode (sel, GTK_SELECTION_BROWSE);
@@ -1826,7 +1819,11 @@
 	gtk_tree_view_column_set_attributes(status_box->column, icon_rend, "stock-id", ICON_STOCK_COLUMN, NULL);
 	gtk_tree_view_column_set_attributes(status_box->column, text_rend, "markup", TEXT_COLUMN, NULL);
 	gtk_tree_view_column_set_attributes(status_box->column, emblem_rend, "stock-id", EMBLEM_COLUMN, "visible", EMBLEM_VISIBLE_COLUMN, NULL);
-	gtk_container_add(GTK_CONTAINER(status_box->scrolled_window), status_box->tree_view);
+
+	status_box->scrolled_window = pidgin_make_scrollable(status_box->tree_view, GTK_POLICY_NEVER, GTK_POLICY_NEVER, GTK_SHADOW_NONE, -1, -1);
+	gtk_container_add (GTK_CONTAINER (status_box->popup_frame),
+			status_box->scrolled_window);
+
 	gtk_widget_show(status_box->tree_view);
 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(status_box->tree_view), TEXT_COLUMN);
 	gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(status_box->tree_view),
--- a/pidgin/gtkutils.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkutils.c	Sun Jan 30 17:52:06 2011 +0000
@@ -245,12 +245,6 @@
 		gtk_widget_show(sep);
 	}
 
-	sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-								   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-	gtk_widget_show(sw);
-
 	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);
@@ -267,7 +261,8 @@
 	}
 	pidgin_setup_imhtml(imhtml);
 
-	gtk_container_add(GTK_CONTAINER(sw), 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;
@@ -3495,6 +3490,29 @@
 }
 #endif
 
+GtkWidget *
+pidgin_make_scrollable(GtkWidget *child, GtkPolicyType hscrollbar_policy, GtkPolicyType vscrollbar_policy, GtkShadowType shadow_type, int width, int height)
+{
+	GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL);
+
+	if (G_LIKELY(sw)) {
+		gtk_widget_show(sw);
+		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), hscrollbar_policy, vscrollbar_policy);
+		gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), shadow_type);
+		if (width != -1 || height != -1)
+			gtk_widget_set_size_request(sw, width, height);
+		if (child) {
+			if (GTK_WIDGET_GET_CLASS(child)->set_scroll_adjustments_signal)
+				gtk_container_add(GTK_CONTAINER(sw), child);
+			else
+				gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), child);
+		}
+		return sw;
+	}
+
+	return child;
+}
+
 void pidgin_utils_init(void)
 {
 	gtk_imhtml_class_register_protocol("http://", url_clicked_cb, link_context_menu);
--- a/pidgin/gtkutils.h	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/gtkutils.h	Sun Jan 30 17:52:06 2011 +0000
@@ -845,6 +845,19 @@
 GdkPixbuf *pidgin_pixbuf_from_imgstore(PurpleStoredImage *image);
 
 /**
+ * Add scrollbars to a widget
+ * @param widget      The child widget
+ * @hscrollbar_policy Horizontal scrolling policy
+ * @vscrollbar_policy Vertical scrolling policy
+ * @shadow            Shadow type
+ * @width             Desired widget width, or -1 for default
+ * @height            Desired widget height, or -1 for default
+ *
+ * @since 2.8.0
+ */
+GtkWidget *pidgin_make_scrollable(GtkWidget *child, GtkPolicyType hscrollbar_policy, GtkPolicyType vscrollbar_policy, GtkShadowType shadow_type, int width, int height);
+
+/**
  * Initialize some utility functions.
  *
  * @since 2.6.0
--- a/pidgin/plugins/disco/gtkdisco.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/plugins/disco/gtkdisco.c	Sun Jan 30 17:52:06 2011 +0000
@@ -651,15 +651,8 @@
 	pidgin_add_widget_to_vbox(GTK_BOX(vbox2), _("_Account:"), NULL, dialog->account_widget, TRUE, NULL);
 
 	/* scrolled window */
-	dialog->sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(dialog->sw),
-	                                    GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dialog->sw),
-	                               GTK_POLICY_AUTOMATIC,
-	                               GTK_POLICY_AUTOMATIC);
+	dialog->sw = pidgin_make_scrollable(NULL, GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, 250);
 	gtk_box_pack_start(GTK_BOX(vbox2), dialog->sw, TRUE, TRUE, 0);
-	gtk_widget_set_size_request(dialog->sw, -1, 250);
-	gtk_widget_show(dialog->sw);
 
 	/* progress bar */
 	dialog->progress = gtk_progress_bar_new();
--- a/pidgin/plugins/gevolution/add_buddy_dialog.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/plugins/gevolution/add_buddy_dialog.c	Sun Jan 30 17:52:06 2011 +0000
@@ -430,7 +430,6 @@
 {
 	GevoAddBuddyDialog *dialog;
 	GtkWidget *button;
-	GtkWidget *sw;
 	GtkWidget *label;
 	GtkWidget *vbox;
 	GtkWidget *hbox;
@@ -510,16 +509,6 @@
 	g_signal_connect(G_OBJECT(button), "clicked",
 					 G_CALLBACK(clear_cb), dialog);
 
-	/* Scrolled Window */
-	sw = gtk_scrolled_window_new(0, 0);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-								   GTK_POLICY_AUTOMATIC,
-								   GTK_POLICY_ALWAYS);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-										GTK_SHADOW_IN);
-	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-	gtk_widget_show(sw);
-
 	/* Create the list model for the treeview. */
 	dialog->model = gtk_list_store_new(NUM_COLUMNS,
 									   G_TYPE_STRING, GDK_TYPE_PIXBUF,
@@ -529,7 +518,9 @@
 	dialog->treeview =
 		gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE);
-	gtk_container_add(GTK_CONTAINER(sw), dialog->treeview);
+	gtk_box_pack_start(GTK_BOX(vbox), 
+		pidgin_make_scrollable(dialog->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1), 
+		TRUE, TRUE, 0);
 	gtk_widget_show(dialog->treeview);
 
 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
--- a/pidgin/plugins/gevolution/assoc-buddy.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/plugins/gevolution/assoc-buddy.c	Sun Jan 30 17:52:06 2011 +0000
@@ -314,7 +314,6 @@
 {
 	GevoAssociateBuddyDialog *dialog;
 	GtkWidget *button;
-	GtkWidget *sw;
 	GtkWidget *label;
 	GtkWidget *vbox;
 	GtkWidget *hbox;
@@ -389,16 +388,6 @@
 	g_signal_connect(G_OBJECT(button), "clicked",
 					 G_CALLBACK(clear_cb), dialog);
 
-	/* Scrolled Window */
-	sw = gtk_scrolled_window_new(0, 0);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-								   GTK_POLICY_AUTOMATIC,
-								   GTK_POLICY_ALWAYS);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-										GTK_SHADOW_IN);
-	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-	gtk_widget_show(sw);
-
 	/* Create the list model for the treeview. */
 	dialog->model = gtk_list_store_new(NUM_COLUMNS,
 									   G_TYPE_STRING, G_TYPE_POINTER);
@@ -407,7 +396,9 @@
 	dialog->treeview = gtk_tree_view_new_with_model(
 			GTK_TREE_MODEL(dialog->model));
 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE);
-	gtk_container_add(GTK_CONTAINER(sw), dialog->treeview);
+	gtk_box_pack_start(GTK_BOX(vbox),
+		pidgin_make_scrollable(dialog->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1),
+		TRUE, TRUE, 0);
 	gtk_widget_show(dialog->treeview);
 
 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
@@ -437,19 +428,10 @@
 	 * User details
 	 */
 
-	/* Scrolled Window */
-	sw = gtk_scrolled_window_new(0, 0);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-								   GTK_POLICY_NEVER,
-								   GTK_POLICY_ALWAYS);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-										GTK_SHADOW_IN);
-	gtk_container_add(GTK_CONTAINER(expander), sw);
-	gtk_widget_show(sw);
-
 	/* Textview */
 	dialog->imhtml = gtk_imhtml_new(NULL, NULL);
-	gtk_container_add(GTK_CONTAINER(sw), dialog->imhtml);
+	gtk_container_add(GTK_CONTAINER(expander), 
+		pidgin_make_scrollable(dialog->imhtml, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1));
 	gtk_widget_show(dialog->imhtml);
 
 	/* Separator. */
--- a/pidgin/plugins/gevolution/gevolution.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/plugins/gevolution/gevolution.c	Sun Jan 30 17:52:06 2011 +0000
@@ -417,7 +417,6 @@
 	GtkWidget *ret;
 	GtkWidget *vbox;
 	GtkWidget *label;
-	GtkWidget *sw;
 	GtkWidget *treeview;
 	GtkTreeViewColumn *column;
 	GtkCellRenderer *renderer;
@@ -439,17 +438,6 @@
 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
 	gtk_widget_show(label);
 
-	/* Scrolled window */
-	sw = gtk_scrolled_window_new(0, 0);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-								   GTK_POLICY_AUTOMATIC,
-								   GTK_POLICY_ALWAYS);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
-										GTK_SHADOW_IN);
-	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-	gtk_widget_set_size_request(sw, 300, 300);
-	gtk_widget_show(sw);
-
 	/* Create the list model for the treeview. */
 	model = gtk_list_store_new(NUM_COLUMNS,
 							   G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
@@ -458,7 +446,9 @@
 	/* Setup the treeview */
 	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
-	gtk_container_add(GTK_CONTAINER(sw), treeview);
+	gtk_box_pack_start(GTK_BOX(vbox),
+		pidgin_make_scrollable(treeview, GTK_POLICY_AUTO, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, 300, 300),
+		TRUE, TRUE, 0);
 	gtk_widget_show(treeview);
 
 	/* Setup the column */
--- a/pidgin/plugins/spellchk.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/plugins/spellchk.c	Sun Jan 30 17:52:06 2011 +0000
@@ -2156,7 +2156,7 @@
 static GtkWidget *
 get_config_frame(PurplePlugin *plugin)
 {
-	GtkWidget *ret, *vbox, *win;
+	GtkWidget *ret, *vbox;
 	GtkWidget *hbox;
 	GtkWidget *button;
 	GtkSizeGroup *sg;
@@ -2173,15 +2173,6 @@
 	gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
 	gtk_widget_show(vbox);
 
-	win = gtk_scrolled_window_new(0, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), win, TRUE, TRUE, 0);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(win),
-										GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(win),
-			GTK_POLICY_NEVER,
-			GTK_POLICY_ALWAYS);
-	gtk_widget_show(win);
-
 	tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE);
 	gtk_widget_set_size_request(tree, -1, 200);
@@ -2240,7 +2231,9 @@
 
 	gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)),
 		 GTK_SELECTION_MULTIPLE);
-	gtk_container_add(GTK_CONTAINER(win), tree);
+	gtk_box_pack_start(GTK_BOX(vbox), 
+		pidgin_make_scrollable(tree, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1), 
+		TRUE, TRUE, 0);
 	gtk_widget_show(tree);
 
 	hbox = gtk_hbutton_box_new();
--- a/pidgin/plugins/xmppconsole.c	Sun Jan 30 17:51:40 2011 +0000
+++ b/pidgin/plugins/xmppconsole.c	Sun Jan 30 17:52:06 2011 +0000
@@ -744,7 +744,6 @@
 create_console(PurplePluginAction *action)
 {
 	GtkWidget *vbox = gtk_vbox_new(FALSE, 6);
-	GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL);
 	GtkWidget *label;
 	GtkTextBuffer *buffer;
 	GtkWidget *toolbar;
@@ -784,16 +783,13 @@
 	gtk_box_pack_start(GTK_BOX(console->hbox), console->dropdown, TRUE, TRUE, 0);
 	g_signal_connect(G_OBJECT(console->dropdown), "changed", G_CALLBACK(dropdown_changed_cb), NULL);
 
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-				       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
 	console->imhtml = gtk_imhtml_new(NULL, NULL);
-	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
 	if (console->count == 0)
 		gtk_imhtml_append_text(GTK_IMHTML(console->imhtml),
 				       _("<font color='#777777'>Not connected to XMPP</font>"), 0);
-	gtk_container_add(GTK_CONTAINER(sw), console->imhtml);
+	gtk_box_pack_start(GTK_BOX(vbox), 
+		pidgin_make_scrollable(console->imhtml, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_ETCHED_IN, -1, -1),
+		TRUE, TRUE, 0);
 
 	toolbar = gtk_toolbar_new();
 	button = gtk_tool_button_new(NULL, "<iq/>");
@@ -810,21 +806,16 @@
 
 	gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
 
-	sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-				       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
 	console->entry = gtk_imhtml_new(NULL, NULL);
 	gtk_imhtml_set_whole_buffer_formatting_only(GTK_IMHTML(console->entry), TRUE);
 	g_signal_connect(G_OBJECT(console->entry),"message_send", G_CALLBACK(message_send_cb), console);
 
-	gtk_box_pack_start(GTK_BOX(vbox), sw, FALSE, FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(sw), console->entry);
+	console->sw = pidgin_make_scrollable(console->entry, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_ETCHED_IN, -1, -1);
+	gtk_box_pack_start(GTK_BOX(vbox), console->sw, FALSE, FALSE, 0);
 	gtk_imhtml_set_editable(GTK_IMHTML(console->entry), TRUE);
 	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(console->entry));
 	g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(entry_changed_cb), NULL);
-	console->sw = sw;
+
 	entry_changed_cb(buffer, NULL);
 
 	gtk_widget_show_all(console->window);