diff pidgin/gtkprefs.c @ 27666:a08e84032814

merge of '2348ff22f0ff3453774b8b25b36238465580c609' and 'e76f11543c2a4aa05bdf584f087cbe3439029661'
author Paul Aurich <paul@darkrain42.org>
date Sun, 12 Jul 2009 05:43:38 +0000
parents 5b07c7253ba4
children 85fa979b08c2 da33da2e1a1e
line wrap: on
line diff
--- a/pidgin/gtkprefs.c	Sun Jul 12 05:42:40 2009 +0000
+++ b/pidgin/gtkprefs.c	Sun Jul 12 05:43:38 2009 +0000
@@ -28,6 +28,7 @@
 #include "pidgin.h"
 
 #include "debug.h"
+#include "nat-pmp.h"
 #include "notify.h"
 #include "prefs.h"
 #include "proxy.h"
@@ -36,7 +37,9 @@
 #include "savedstatuses.h"
 #include "sound.h"
 #include "sound-theme.h"
+#include "stun.h"
 #include "theme-manager.h"
+#include "upnp.h"
 #include "util.h"
 #include "network.h"
 
@@ -61,6 +64,12 @@
 
 #define PREFS_OPTIMAL_ICON_SIZE 32
 
+struct theme_info {
+	gchar *type;
+	gchar *extension;
+	gchar *original_name;
+};
+
 static int sound_row_sel = 0;
 static GtkWidget *prefsnotebook;
 
@@ -74,11 +83,13 @@
 static int notebook_page = 0;
 static GtkTreeRowReference *previous_smiley_row = NULL;
 
-static gboolean prefs_themes_unsorted = TRUE;
 static GtkListStore *prefs_sound_themes;
 static GtkListStore *prefs_blist_themes;
 static GtkListStore *prefs_status_icon_themes;
 
+static GtkWidget *prefs_sound_themes_combo_box;
+static GtkWidget *prefs_blist_themes_combo_box;
+static GtkWidget *prefs_status_themes_combo_box;
 
 /*
  * PROTOTYPES
@@ -106,7 +117,7 @@
 
 	val = purple_prefs_get_int(key);
 
-	adjust = gtk_adjustment_new(val, min, max, 1, 1, 1);
+	adjust = gtk_adjustment_new(val, min, max, 1, 1, 0);
 	spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0);
 	g_object_set_data(G_OBJECT(spin), "val", (char *)key);
 	if (max < 10000)
@@ -121,7 +132,8 @@
 }
 
 static void
-entry_set(GtkEntry *entry, gpointer data) {
+entry_set(GtkEntry *entry, gpointer data)
+{
 	const char *key = (const char*)data;
 
 	purple_prefs_set_string(key, gtk_entry_get_text(entry));
@@ -333,7 +345,9 @@
 
 }
 
-static void smiley_sel(GtkTreeSelection *sel, GtkTreeModel *model) {
+static void
+smiley_sel(GtkTreeSelection *sel, GtkTreeModel *model)
+{
 	GtkTreeIter  iter;
 	const char *themename;
 	char *description;
@@ -384,7 +398,8 @@
 	gtk_tree_path_free(path);
 }
 
-static GtkTreeRowReference *theme_refresh_theme_list(void)
+static GtkTreeRowReference *
+theme_refresh_theme_list(void)
 {
 	GdkPixbuf *pixbuf;
 	GSList *themes;
@@ -442,144 +457,9 @@
 	return row_ref;
 }
 
-static void theme_install_theme(char *path, char *extn) {
-#ifndef _WIN32
-	gchar *command;
-#endif
-	gchar *destdir;
-	gchar *tail;
-	GtkTreeRowReference *theme_rowref;
-
-	/* Just to be safe */
-	g_strchomp(path);
-
-	/* I dont know what you are, get out of here */
-	if (extn != NULL)
-		tail = extn;
-	else if ((tail = strrchr(path, '.')) == NULL)
-		return;
-
-	destdir = g_strconcat(purple_user_dir(), G_DIR_SEPARATOR_S "smileys", NULL);
-
-	/* We'll check this just to make sure. This also lets us do something different on
-	 * other platforms, if need be */
-	if (!g_ascii_strcasecmp(tail, ".gz") || !g_ascii_strcasecmp(tail, ".tgz")) {
-#ifndef _WIN32
-		gchar *path_escaped = g_shell_quote(path);
-		gchar *destdir_escaped = g_shell_quote(destdir);
-		command = g_strdup_printf("tar > /dev/null xzf %s -C %s", path_escaped, destdir_escaped);
-		g_free(path_escaped);
-		g_free(destdir_escaped);
-#else
-		if(!winpidgin_gz_untar(path, destdir)) {
-			g_free(destdir);
-			return;
-		}
-#endif
-	}
-	else {
-		g_free(destdir);
-		return;
-	}
-
-#ifndef _WIN32
-	/* Fire! */
-	if (system(command))
-	{
-		purple_notify_error(NULL, NULL, _("Smiley theme failed to unpack."), NULL);
-	}
-
-	g_free(command);
-#endif
-	g_free(destdir);
-
-	theme_rowref = theme_refresh_theme_list();
-	if (theme_rowref != NULL) {
-		GtkTreePath *tp = gtk_tree_row_reference_get_path(theme_rowref);
-
-		if (tp)
-			gtk_tree_selection_select_path(smiley_theme_sel, tp);
-		gtk_tree_row_reference_free(theme_rowref);
-	}
-}
-
-static void
-theme_got_url(PurpleUtilFetchUrlData *url_data, gpointer user_data,
-		const gchar *themedata, size_t len, const gchar *error_message)
-{
-	FILE *f;
-	gchar *path;
-	size_t wc;
-
-	if ((error_message != NULL) || (len == 0))
-		return;
-
-	f = purple_mkstemp(&path, TRUE);
-	wc = fwrite(themedata, len, 1, f);
-	if (wc != 1) {
-		purple_debug_warning("theme_got_url", "Unable to write theme data.\n");
-		fclose(f);
-		g_unlink(path);
-		g_free(path);
-		return;
-	}
-	fclose(f);
-
-	theme_install_theme(path, user_data);
-
-	g_unlink(path);
-	g_free(path);
-}
-
-static void
-theme_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y,
-		GtkSelectionData *sd, guint info, guint t, gpointer data)
-{
-	gchar *name = (gchar *)sd->data;
-
-	if ((sd->length >= 0) && (sd->format == 8)) {
-		/* Well, it looks like the drag event was cool.
-		 * Let's do something with it */
-
-		if (!g_ascii_strncasecmp(name, "file://", 7)) {
-			GError *converr = NULL;
-			gchar *tmp;
-			/* It looks like we're dealing with a local file. Let's
-			 * just untar it in the right place */
-			if(!(tmp = g_filename_from_uri(name, NULL, &converr))) {
-				purple_debug(PURPLE_DEBUG_ERROR, "theme dnd", "%s\n",
-						   (converr ? converr->message :
-							"g_filename_from_uri error"));
-				return;
-			}
-			theme_install_theme(tmp, NULL);
-			g_free(tmp);
-		} else if (!g_ascii_strncasecmp(name, "http://", 7)) {
-			/* Oo, a web drag and drop. This is where things
-			 * will start to get interesting */
-			purple_util_fetch_url(name, TRUE, NULL, FALSE, theme_got_url, ".tgz");
-		} else if (!g_ascii_strncasecmp(name, "https://", 8)) {
-			/* purple_util_fetch_url() doesn't support HTTPS, but we want users
-			 * to be able to drag and drop links from the SF trackers, so
-			 * we'll try it as an HTTP URL. */
-			char *tmp = g_strdup(name + 1);
-			tmp[0] = 'h';
-			tmp[1] = 't';
-			tmp[2] = 't';
-			tmp[3] = 'p';
-			purple_util_fetch_url(tmp, TRUE, NULL, FALSE, theme_got_url, ".tgz");
-			g_free(tmp);
-		}
-
-		gtk_drag_finish(dc, TRUE, FALSE, t);
-	}
-
-	gtk_drag_finish(dc, FALSE, FALSE, t);
-}
-
 /* Rebuild the markup for the sound theme selection for "(Custom)" themes */
 static void
-pref_sound_generate_markup()
+pref_sound_generate_markup(void)
 {
 	gboolean print_custom, customized;
 	const gchar *name, *author, *description, *current_theme;
@@ -596,7 +476,7 @@
 
 			print_custom = customized && g_str_equal(current_theme, name);
 
-			if (g_str_equal(name, ""))
+			if (!name || *name == '\0')
 				markup = g_strdup_printf("<b>(Default)</b>%s%s - None\n<span foreground='dim grey'>The default Pidgin sound theme</span>",
 							 print_custom ? " " : "", print_custom ? "(Custom)" : "");
 			else {
@@ -617,7 +497,7 @@
 	}
 }
 
-/* adds the themes to the theme list from the manager so they can be sisplayed in prefs */
+/* adds the themes to the theme list from the manager so they can be displayed in prefs */
 static void
 prefs_themes_sort(PurpleTheme *theme)
 {
@@ -667,53 +547,389 @@
 		if (pixbuf != NULL)
 			g_object_unref(G_OBJECT(pixbuf));
 	}
-
 }
 
-/* init all the theme variables so that the themes can be sorted later and used by pref pages */
 static void
-prefs_themes_init()
+prefs_set_active_theme_combo(GtkWidget *combo_box, GtkListStore *store, const gchar *current_theme)
+{
+	GtkTreeIter iter;
+	gchar *theme = NULL;
+	gboolean unset = TRUE;
+
+	if (current_theme && *current_theme && gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
+		do {
+			gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 2, &theme, -1);
+
+			if (g_str_equal(current_theme, theme)) {
+				gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter);
+				unset = FALSE;
+			}
+
+			g_free(theme);
+		} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
+	}
+
+	if (unset)
+		gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), 0);
+}
+
+static void
+prefs_themes_refresh(void)
 {
 	GdkPixbuf *pixbuf = NULL;
 	gchar *filename;
 	GtkTreeIter iter;
 
+	/* refresh the list of themes in the manager */
+	purple_theme_manager_refresh();
+
 	filename = g_build_filename(DATADIR, "icons", "hicolor", "32x32", "apps", "pidgin.png", NULL);
 	pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
 	g_free(filename);
 
 	/* sound themes */
-	prefs_sound_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
-
+	gtk_list_store_clear(prefs_sound_themes);
 	gtk_list_store_append(prefs_sound_themes, &iter);
 	gtk_list_store_set(prefs_sound_themes, &iter, 0, pixbuf, 2, "", -1);
 
 	/* blist themes */
-	prefs_blist_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
-
+	gtk_list_store_clear(prefs_blist_themes);
 	gtk_list_store_append(prefs_blist_themes, &iter);
-	gtk_list_store_set(prefs_blist_themes, &iter, 0, pixbuf, 1, "<b>(Default)</b> - None\n<span color='dim grey'>"
-								    "The default Pidgin buddy list theme</span>", 2, "", -1);
+	gtk_list_store_set(prefs_blist_themes, &iter, 0, pixbuf, 1,
+	                   "<b>(Default)</b> - None\n<span color='dim grey'>"
+	                   "The default Pidgin buddy list theme</span>", 2, "", -1);
 
 	/* status icon themes */
-	prefs_status_icon_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
-
+	gtk_list_store_clear(prefs_status_icon_themes);
 	gtk_list_store_append(prefs_status_icon_themes, &iter);
-	gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1, "<b>(Default)</b> - None\n<span color='dim grey'>"
-								    "The default Pidgin status icon theme</span>", 2, "", -1);
-
+	gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1,
+	                   "<b>(Default)</b> - None\n<span color='dim grey'>"
+	                   "The default Pidgin status icon theme</span>", 2, "", -1);
 	g_object_unref(G_OBJECT(pixbuf));
+
+	purple_theme_manager_for_each_theme(prefs_themes_sort);
+	pref_sound_generate_markup();
+
+	/* set active */
+	prefs_set_active_theme_combo(prefs_sound_themes_combo_box, prefs_sound_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme"));
+	prefs_set_active_theme_combo(prefs_blist_themes_combo_box, prefs_blist_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme"));
+	prefs_set_active_theme_combo(prefs_status_themes_combo_box, prefs_status_icon_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme"));
+}
+
+/* init all the theme variables so that the themes can be sorted later and used by pref pages */
+static void
+prefs_themes_init(void)
+{
+	prefs_sound_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
+
+	prefs_blist_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
+
+	prefs_status_icon_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
+}
+
+static PurpleTheme *
+prefs_theme_find_theme(const gchar *path, const gchar *type)
+{
+	PurpleTheme *theme = purple_theme_manager_load_theme(path, type);
+	GDir *dir = g_dir_open(path, 0, NULL);
+	const gchar *next;
+
+	while (!PURPLE_IS_THEME(theme) && (next = g_dir_read_name(dir))) {
+		gchar *next_path = g_build_filename(path, next, NULL);
+
+		if (g_file_test(next_path, G_FILE_TEST_IS_DIR))
+			theme = prefs_theme_find_theme(next_path, type);
+
+		g_free(next_path);
+	}
+
+	g_dir_close(dir);
+
+	return theme;
+}
+
+/* Eww. Seriously ewww. But thanks, grim! This is taken from guifications2 */
+static gboolean
+purple_theme_file_copy(const gchar *source, const gchar *destination)
+{
+	FILE *src, *dest;
+	gint chr = EOF;
+
+	if(!(src = g_fopen(source, "rb")))
+		return FALSE;
+	if(!(dest = g_fopen(destination, "wb"))) {
+		fclose(src);
+		return FALSE;
+	}
+
+	while((chr = fgetc(src)) != EOF) {
+		fputc(chr, dest);
+	}
+
+	fclose(dest);
+	fclose(src);
+
+	return TRUE;
+}
+
+/* installs a theme, info is freed by function */
+static void
+theme_install_theme(char *path, struct theme_info *info)
+{
+#ifndef _WIN32
+	gchar *command;
+#endif
+	gchar *destdir, *tail, *type, *original_name;
+	GtkTreeRowReference *theme_rowref;
+	gboolean is_smiley_theme, is_archive;
+	PurpleTheme *theme = NULL;
+
+	if (info == NULL)
+		return;
+
+	original_name = info->original_name;
+	type = info->type;
+
+	/* check the extension */
+	tail = info->extension ? info->extension : g_strdup(strrchr(path, '.'));
+
+	if (!tail) {
+		g_free(type);
+		g_free(original_name);
+		g_free(info);
+		return;
+	} else g_free(info);
+
+	is_archive = !g_ascii_strcasecmp(tail, ".gz") || !g_ascii_strcasecmp(tail, ".tgz");
+
+	g_free(tail);
+
+	/* Just to be safe */
+	g_strchomp(path);
+
+	if ((is_smiley_theme = g_str_equal(type, "smiley")))
+		destdir = g_build_filename(purple_user_dir(), "smileys", NULL);
+	else destdir = g_build_filename(purple_user_dir(), "themes", "temp", NULL);
+
+	/* We'll check this just to make sure. This also lets us do something different on
+	 * other platforms, if need be */
+	if (is_archive) {
+#ifndef _WIN32
+		gchar *path_escaped = g_shell_quote(path);
+		gchar *destdir_escaped = g_shell_quote(destdir);
+
+		if (!g_file_test(destdir, G_FILE_TEST_IS_DIR))
+			purple_build_dir(destdir, S_IRUSR | S_IWUSR | S_IXUSR);
+
+		command = g_strdup_printf("tar > /dev/null xzf %s -C %s", path_escaped, destdir_escaped);
+		g_free(path_escaped);
+		g_free(destdir_escaped);
+
+		/* Fire! */
+		if (system(command)) {
+			purple_notify_error(NULL, NULL, _("Theme failed to unpack."), NULL);
+			g_free(command);
+			g_free(destdir);
+			g_free(type);
+			g_free(original_name);
+			return;
+		}
+#else
+		if(!winpidgin_gz_untar(path, destdir)) {
+			g_free(destdir);
+			g_free(type);
+			g_free(original_name);
+			return;
+		}
+#endif
+	}
+
+	if (is_smiley_theme) {
+		/* just extract the folder to the smiley directory */
+		theme_rowref = theme_refresh_theme_list();
+
+		if (theme_rowref != NULL) {
+			GtkTreePath *tp = gtk_tree_row_reference_get_path(theme_rowref);
+
+			if (tp)
+				gtk_tree_selection_select_path(smiley_theme_sel, tp);
+
+			gtk_tree_row_reference_free(theme_rowref);
+		}
+
+	} else if (is_archive) {
+		theme = prefs_theme_find_theme(destdir, type);
+
+		if (PURPLE_IS_THEME(theme)) {
+			/* create the location for the theme */
+			gchar *theme_dest = g_build_filename(purple_user_dir(), "themes",
+						 purple_theme_get_name(theme),
+						 "purple", type, NULL);
+
+			if (!g_file_test(theme_dest, G_FILE_TEST_IS_DIR))
+				purple_build_dir(theme_dest, S_IRUSR | S_IWUSR | S_IXUSR);
+
+			g_free(theme_dest);
+			theme_dest = g_build_filename(purple_user_dir(), "themes",
+						 purple_theme_get_name(theme),
+						 "purple", type, NULL);
+
+			/* move the entire directory to new location */
+			g_rename(purple_theme_get_dir(theme), theme_dest);
+
+			g_free(theme_dest);
+			g_remove(destdir);
+			g_object_unref(theme);
+
+			prefs_themes_refresh();
+
+		} else {
+			/* something was wrong with the theme archive */
+			g_unlink(destdir);
+			purple_notify_error(NULL, NULL, _("Theme failed to load."), NULL);
+		}
+
+	} else { /* just a single file so copy it to a new temp directory and attempt to load it*/
+		gchar *temp_path, *temp_file;
+
+		temp_path = g_build_filename(purple_user_dir(), "themes", "temp", "sub_folder", NULL);
+
+		if (original_name != NULL) {
+			/* name was changed from the original (probably a dnd) change it back before loading */
+			temp_file = g_build_filename(temp_path, original_name, NULL);
+
+		} else {
+			gchar *source_name = g_path_get_basename(path);
+			temp_file = g_build_filename(temp_path, source_name, NULL);
+			g_free(source_name);
+		}
+
+		if (!g_file_test(temp_path, G_FILE_TEST_IS_DIR))
+			purple_build_dir(temp_path, S_IRUSR | S_IWUSR | S_IXUSR);
+
+		if (purple_theme_file_copy(path, temp_file)) {
+			/* find the theme, could be in subfolder */
+			theme = prefs_theme_find_theme(temp_path, type);
+
+			if (PURPLE_IS_THEME(theme)) {
+				gchar *theme_dest = g_build_filename(purple_user_dir(), "themes",
+							 purple_theme_get_name(theme),
+							 "purple", type, NULL);
+
+				if(!g_file_test(theme_dest, G_FILE_TEST_IS_DIR))
+					purple_build_dir(theme_dest, S_IRUSR | S_IWUSR | S_IXUSR);
+
+				g_rename(purple_theme_get_dir(theme), theme_dest);
+
+				g_free(theme_dest);
+				g_object_unref(theme);
+
+				prefs_themes_refresh();
+			} else {
+				g_remove(temp_path);
+				purple_notify_error(NULL, NULL, _("Theme failed to load."), NULL);
+			}
+		} else {
+			purple_notify_error(NULL, NULL, _("Theme failed to copy."), NULL);
+		}
+
+		g_free(temp_file);
+		g_free(temp_path);
+	}
+
+	g_free(type);
+	g_free(original_name);
+	g_free(destdir);
+}
+
+static void
+theme_got_url(PurpleUtilFetchUrlData *url_data, gpointer user_data,
+		const gchar *themedata, size_t len, const gchar *error_message)
+{
+	FILE *f;
+	gchar *path;
+	size_t wc;
+
+	if ((error_message != NULL) || (len == 0))
+		return;
+
+	f = purple_mkstemp(&path, TRUE);
+	wc = fwrite(themedata, len, 1, f);
+	if (wc != 1) {
+		purple_debug_warning("theme_got_url", "Unable to write theme data.\n");
+		fclose(f);
+		g_unlink(path);
+		g_free(path);
+		return;
+	}
+	fclose(f);
+
+	theme_install_theme(path, user_data);
+
+	g_unlink(path);
+	g_free(path);
+}
+
+static void
+theme_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y,
+		GtkSelectionData *sd, guint info, guint t, gpointer user_data)
+{
+	gchar *name = g_strchomp((gchar *)sd->data);
+
+	if ((sd->length >= 0) && (sd->format == 8)) {
+		/* Well, it looks like the drag event was cool.
+		 * Let's do something with it */
+		gchar *temp;
+		struct theme_info *info =  g_new0(struct theme_info, 1);
+		info->type = g_strdup((gchar *)user_data);
+		info->extension = g_strdup(g_strrstr(name,"."));
+		temp = g_strrstr(name, "/");
+		info->original_name = temp ? g_strdup(++temp) : NULL;
+
+		if (!g_ascii_strncasecmp(name, "file://", 7)) {
+			GError *converr = NULL;
+			gchar *tmp;
+			/* It looks like we're dealing with a local file. Let's
+			 * just untar it in the right place */
+			if(!(tmp = g_filename_from_uri(name, NULL, &converr))) {
+				purple_debug(PURPLE_DEBUG_ERROR, "theme dnd", "%s\n",
+						   (converr ? converr->message :
+							"g_filename_from_uri error"));
+				return;
+			}
+			theme_install_theme(tmp, info);
+			g_free(tmp);
+		} else if (!g_ascii_strncasecmp(name, "http://", 7)) {
+			/* Oo, a web drag and drop. This is where things
+			 * will start to get interesting */
+			purple_util_fetch_url(name, TRUE, NULL, FALSE, theme_got_url, info);
+		} else if (!g_ascii_strncasecmp(name, "https://", 8)) {
+			/* purple_util_fetch_url() doesn't support HTTPS, but we want users
+			 * to be able to drag and drop links from the SF trackers, so
+			 * we'll try it as an HTTP URL. */
+			char *tmp = g_strdup(name + 1);
+			tmp[0] = 'h';
+			tmp[1] = 't';
+			tmp[2] = 't';
+			tmp[3] = 'p';
+
+			purple_util_fetch_url(tmp, TRUE, NULL, FALSE, theme_got_url, info);
+			g_free(tmp);
+		}
+
+		gtk_drag_finish(dc, TRUE, FALSE, t);
+	}
+
+	gtk_drag_finish(dc, FALSE, FALSE, t);
 }
 
 /* builds a theme combo box from a list store with colums: icon preview, markup, theme name */
 static GtkWidget *
-prefs_build_theme_combo_box(GtkListStore *store, const gchar *current_theme)
+prefs_build_theme_combo_box(GtkListStore *store, const gchar *current_theme, gchar *type)
 {
-	GtkWidget *combo_box;
 	GtkCellRenderer *cell_rend;
-	GtkTreeIter iter;
-	gchar *theme = NULL;
-	gboolean unset = TRUE;
+	GtkWidget *combo_box;
+	GtkTargetEntry te[3] = {{"text/plain", 0, 0},{"text/uri-list", 0, 1},{"STRING", 0, 2}};
 
 	g_return_val_if_fail(store != NULL && current_theme != NULL, NULL);
 
@@ -731,21 +947,10 @@
 			g_object_set(cell_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
 #endif*/
 
-	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
-		do {
-			gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 2, &theme, -1);
-
-			if (g_str_equal(current_theme, theme)) {
-				gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter);
-				unset = FALSE;
-			}
-
-			g_free(theme);
-		} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
-	}
-
-	if (unset)
-		gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), 0);
+	gtk_drag_dest_set(combo_box, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te,
+					sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+	g_signal_connect(G_OBJECT(combo_box), "drag_data_received", G_CALLBACK(theme_dnd_recv), type);
 
 	return combo_box;
 }
@@ -757,32 +962,32 @@
 	gint i;
 	gchar *pref;
 	gchar *new_theme;
-	gboolean success;
 	GtkTreeIter new_iter;
 
-	success = gtk_combo_box_get_active_iter(combo_box, &new_iter);
-	g_return_if_fail(success);
-
-	gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes), &new_iter, 2, &new_theme, -1);
-
-	purple_prefs_set_string(PIDGIN_PREFS_ROOT "/sound/theme", new_theme);
-
-	/* New theme removes all customization */
-	for(i=0; i <  PURPLE_NUM_SOUNDS; i++){
-		pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
-					pidgin_sound_get_event_option(i));
-		purple_prefs_set_path(pref, "");
-		g_free(pref);
+	if(gtk_combo_box_get_active_iter(combo_box, &new_iter)) {
+
+		gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes), &new_iter, 2, &new_theme, -1);
+
+		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/sound/theme", new_theme);
+
+		/* New theme removes all customization */
+		for(i=0; i <  PURPLE_NUM_SOUNDS; i++){
+			pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
+						pidgin_sound_get_event_option(i));
+			purple_prefs_set_path(pref, "");
+			g_free(pref);
+		}
+
+		/* gets rid of the "(Custom)" from the last selection */
+		pref_sound_generate_markup();
+
+		gtk_entry_set_text(GTK_ENTRY(sound_entry), _("(default)"));
+
+		g_free(new_theme);
 	}
-
-	/* gets rid of the "(Custom)" from the last selection */
-	pref_sound_generate_markup();
-
-	gtk_entry_set_text(GTK_ENTRY(sound_entry), _("(default)"));
-
-	g_free(new_theme);
 }
 
+
 /* Does same as normal sort, except "none" is sorted first */
 static gint pidgin_sort_smileys (GtkTreeModel	*model,
 						GtkTreeIter		*a,
@@ -821,13 +1026,20 @@
 static void
 request_theme_file_name_cb(gpointer data, char *theme_file_name)
 {
-	theme_install_theme(theme_file_name, NULL) ;
+	struct theme_info *info = g_new0(struct theme_info, 1);
+	info->type = g_strdup("smiley");
+	info->extension = NULL;
+	info->original_name = NULL;
+
+	theme_install_theme(theme_file_name, info);
+
+	g_free(info);
 }
 
 static void
-add_theme_button_clicked_cb(GtkWidget *widget, gpointer null)
+add_theme_button_clicked_cb(GtkWidget *widget, gpointer user_data)
 {
-	purple_request_file(NULL, _("Install Theme"), NULL, FALSE, (GCallback)request_theme_file_name_cb, NULL, NULL, NULL, NULL, NULL) ;
+	purple_request_file(NULL, _("Install Theme"), NULL, FALSE, (GCallback)request_theme_file_name_cb, NULL, NULL, NULL, NULL, NULL);
 }
 
 static void
@@ -903,7 +1115,7 @@
 	gtk_drag_dest_set(view, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te,
 					sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE);
 
-	g_signal_connect(G_OBJECT(view), "drag_data_received", G_CALLBACK(theme_dnd_recv), smiley_theme_store);
+	g_signal_connect(G_OBJECT(view), "drag_data_received", G_CALLBACK(theme_dnd_recv), "smiley");
 
 	rend = gtk_cell_renderer_pixbuf_new();
 	smiley_theme_sel = sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
@@ -1163,35 +1375,42 @@
 static void
 prefs_set_blist_theme_cb(GtkComboBox *combo_box, gpointer user_data)
 {
-	PidginBlistTheme *theme = NULL;
+	PidginBlistTheme *theme =  NULL;
 	GtkTreeIter iter;
 	gchar *name = NULL;
 
-	g_return_if_fail(gtk_combo_box_get_active_iter(combo_box, &iter));
-	gtk_tree_model_get(GTK_TREE_MODEL(prefs_blist_themes), &iter, 2, &name, -1);
-
-	if (name && *name)
-		theme = PIDGIN_BLIST_THEME(purple_theme_manager_find_theme(name, "blist"));
-	g_free(name);
-
-	pidgin_blist_set_theme(theme);
+	if(gtk_combo_box_get_active_iter(combo_box, &iter)) {
+
+		gtk_tree_model_get(GTK_TREE_MODEL(prefs_blist_themes), &iter, 2, &name, -1);
+
+		if(!name || !g_str_equal(name, ""))
+			theme = PIDGIN_BLIST_THEME(purple_theme_manager_find_theme(name, "blist"));
+
+		g_free(name);
+
+		pidgin_blist_set_theme(theme);
+	}
 }
 
 /* sets the current icon theme */
 static void
 prefs_set_status_icon_theme_cb(GtkComboBox *combo_box, gpointer user_data)
 {
-	PidginStatusIconTheme *theme;
+	PidginStatusIconTheme *theme = NULL;
 	GtkTreeIter iter;
 	gchar *name = NULL;
 
-	g_return_if_fail(gtk_combo_box_get_active_iter(combo_box, &iter));
-	gtk_tree_model_get(GTK_TREE_MODEL(prefs_status_icon_themes), &iter, 2, &name, -1);
-
-	theme = PIDGIN_STATUS_ICON_THEME(purple_theme_manager_find_theme(name, "status-icon"));
-	g_free(name);
-
-	pidgin_stock_load_status_icon_theme(theme);
+	if(gtk_combo_box_get_active_iter(combo_box, &iter)) {
+
+		gtk_tree_model_get(GTK_TREE_MODEL(prefs_status_icon_themes), &iter, 2, &name, -1);
+
+		if(!name || !g_str_equal(name, ""))
+			theme = PIDGIN_STATUS_ICON_THEME(purple_theme_manager_find_theme(name, "status-icon"));
+
+		g_free(name);
+
+		pidgin_stock_load_status_icon_theme(theme);
+	}
 }
 
 static GtkWidget *
@@ -1201,7 +1420,6 @@
 	GtkWidget *vbox;
 	GtkWidget *vbox2;
 	GtkWidget *label;
-	GtkWidget *combo_box;
 	GtkSizeGroup *sg;
 	GList *names = NULL;
 
@@ -1213,14 +1431,20 @@
 	/* Buddy List Themes */
 	vbox = pidgin_make_frame(ret, _("Buddy List Theme"));
 
-	combo_box = prefs_build_theme_combo_box(prefs_blist_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme"));
-	gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0);
-	g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_blist_theme_cb, NULL);
+	prefs_blist_themes_combo_box = prefs_build_theme_combo_box(prefs_blist_themes,
+						purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme"),
+						"blist");
+
+	gtk_box_pack_start(GTK_BOX (vbox), prefs_blist_themes_combo_box, FALSE, FALSE, 0);
+	g_signal_connect(G_OBJECT(prefs_blist_themes_combo_box), "changed", (GCallback)prefs_set_blist_theme_cb, NULL);
 
 	/* Status Icon Themes */
-	combo_box = prefs_build_theme_combo_box(prefs_status_icon_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme"));
-	gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0);
-	g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_status_icon_theme_cb, NULL);
+	prefs_status_themes_combo_box = prefs_build_theme_combo_box(prefs_status_icon_themes,
+						purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme"),
+						"icon");
+
+	gtk_box_pack_start(GTK_BOX (vbox), prefs_status_themes_combo_box, FALSE, FALSE, 0);
+	g_signal_connect(G_OBJECT(prefs_status_themes_combo_box), "changed", (GCallback)prefs_set_status_icon_theme_cb, NULL);
 
 	/* System Tray */
 	vbox = pidgin_make_frame(ret, _("System Tray Icon"));
@@ -1231,9 +1455,9 @@
 					_("Never"), "never",
 					NULL);
 	gtk_size_group_add_widget(sg, label);
-        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-
-	vbox = pidgin_make_frame(ret, _("Conversation Window Hiding"));
+	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+
+	vbox = pidgin_make_frame(ret, _("Conversation Window"));
 	label = pidgin_prefs_dropdown(vbox, _("_Hide new IM conversations:"),
 					PURPLE_PREF_STRING, PIDGIN_PREFS_ROOT "/conversations/im/hide_new",
 					_("Never"), "never",
@@ -1241,8 +1465,11 @@
 					_("Always"), "always",
 					NULL);
 	gtk_size_group_add_widget(sg, label);
-        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-
+	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+
+#ifdef _WIN32
+	pidgin_prefs_checkbox(_("Minimi_ze new conversation windows"), PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", vbox);
+#endif
 
 	/* All the tab options! */
 	vbox = pidgin_make_frame(ret, _("Tabs"));
@@ -1259,7 +1486,7 @@
 	purple_prefs_connect_callback(prefs, PIDGIN_PREFS_ROOT "/conversations/tabs",
 	                            conversation_usetabs_cb, vbox2);
 	if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/tabs"))
-	  gtk_widget_set_sensitive(vbox2, FALSE);
+		gtk_widget_set_sensitive(vbox2, FALSE);
 
 	pidgin_prefs_checkbox(_("Show close b_utton on tabs"),
 				PIDGIN_PREFS_ROOT "/conversations/close_on_tabs", vbox2);
@@ -1276,7 +1503,7 @@
 #endif
 					NULL);
 	gtk_size_group_add_widget(sg, label);
-        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
 
 	names = pidgin_conv_placement_get_options();
 	label = pidgin_prefs_dropdown_from_list(vbox2, _("N_ew conversations:"),
@@ -1287,10 +1514,8 @@
 
 	g_list_free(names);
 
-
 	keyboard_shortcuts(ret);
 
-
 	gtk_widget_show_all(ret);
 	g_object_unref(sg);
 	return ret;
@@ -1353,8 +1578,6 @@
 
 #ifdef _WIN32
 	pidgin_prefs_checkbox(_("F_lash window when IMs are received"), PIDGIN_PREFS_ROOT "/win32/blink_im", vbox);
-
-	pidgin_prefs_checkbox(_("Minimi_ze new conversation windows"), PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", vbox);
 #endif
 
 	pidgin_prefs_labeled_spin_button(vbox,
@@ -1362,7 +1585,6 @@
 		PIDGIN_PREFS_ROOT "/conversations/minimum_entry_lines",
 		1, 8, NULL);
 
-
 #if GTK_CHECK_VERSION(2,4,0)
 	vbox = pidgin_make_frame(ret, _("Font"));
 	if (purple_running_gnome())
@@ -1371,7 +1593,11 @@
 		fontpref = pidgin_prefs_checkbox(_("Use font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox);
 
 	font_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font");
-	font_button = gtk_font_button_new_with_font(font_name ? font_name : NULL);
+	if ((font_name == NULL) || (*font_name == '\0')) {
+		font_button = gtk_font_button_new();
+	} else {
+		font_button = gtk_font_button_new_with_font(font_name);
+	}
 
 	gtk_font_button_set_show_style(GTK_FONT_BUTTON(font_button), TRUE);
 	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Conversation _font:"), NULL, font_button, FALSE, NULL);
@@ -1417,35 +1643,54 @@
 	return ret;
 }
 
-static void network_ip_changed(GtkEntry *entry, gpointer data)
+static void
+network_ip_changed(GtkEntry *entry, gpointer data)
 {
-	/*
-	 * TODO: It would be nice if we could validate this and show a
-	 *       red background in the box when the IP address is invalid
-	 *       and a green background when the IP address is valid.
-	 */
-	purple_network_set_public_ip(gtk_entry_get_text(entry));
+	const gchar *text = gtk_entry_get_text(entry);
+	GdkColor color;
+
+	if (text && *text) {
+		if (purple_ip_address_is_valid(text)) {
+			color.red = 0xAFFF;
+			color.green = 0xFFFF;
+			color.blue = 0xAFFF;
+
+			purple_network_set_public_ip(text);
+		} else {
+			color.red = 0xFFFF;
+			color.green = 0xAFFF;
+			color.blue = 0xAFFF;
+		}
+
+		gtk_widget_modify_base(GTK_WIDGET(entry), GTK_STATE_NORMAL, &color);
+
+	} else {
+		purple_network_set_public_ip("");
+		gtk_widget_modify_base(GTK_WIDGET(entry), GTK_STATE_NORMAL, NULL);
+	}
 }
 
-static gboolean network_stun_server_changed_cb(GtkWidget *widget, 
-	GdkEventFocus *event, gpointer data)
+static gboolean
+network_stun_server_changed_cb(GtkWidget *widget,
+                               GdkEventFocus *event, gpointer data)
 {
 	GtkEntry *entry = GTK_ENTRY(widget);
 	purple_prefs_set_string("/purple/network/stun_server",
 		gtk_entry_get_text(entry));
 	purple_network_set_stun_server(gtk_entry_get_text(entry));
-	
+
 	return FALSE;
 }
 
-static gboolean network_turn_server_changed_cb(GtkWidget *widget, 
-	GdkEventFocus *event, gpointer data)
+static gboolean
+network_turn_server_changed_cb(GtkWidget *widget,
+                               GdkEventFocus *event, gpointer data)
 {
 	GtkEntry *entry = GTK_ENTRY(widget);
 	purple_prefs_set_string("/purple/network/turn_server",
 		gtk_entry_get_text(entry));
 	purple_network_set_turn_server(gtk_entry_get_text(entry));
-	
+
 	return FALSE;
 }
 
@@ -1462,7 +1707,8 @@
 		gtk_widget_hide(frame);
 }
 
-static void proxy_print_option(GtkEntry *entry, int entrynum)
+static void
+proxy_print_option(GtkEntry *entry, int entrynum)
 {
 	if (entrynum == PROXYHOST)
 		purple_prefs_set_string("/purple/proxy/host", gtk_entry_get_text(entry));
@@ -1508,6 +1754,9 @@
 	GtkWidget *proxy_button = NULL, *browser_button = NULL;
 	GtkSizeGroup *sg;
 	PurpleProxyInfo *proxy_info = NULL;
+	const char *ip;
+	PurpleStunNatDiscovery *stun;
+	char *auto_ip_text;
 
 	ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
 	gtk_container_set_border_width (GTK_CONTAINER (ret), PIDGIN_HIG_BORDER);
@@ -1538,8 +1787,30 @@
 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
 	gtk_container_add(GTK_CONTAINER(hbox), label);
 
-	auto_ip_checkbox = pidgin_prefs_checkbox(_("_Autodetect IP address"),
-			"/purple/network/auto_ip", vbox);
+	/* purple_network_get_my_ip will return the IP that was set by the user with
+	   purple_network_set_public_ip, so make a lookup for the auto-detected IP
+	   ourselves. */
+
+	/* Check if STUN discovery was already done */
+	stun = purple_stun_discover(NULL);
+	if ((stun != NULL) && (stun->status == PURPLE_STUN_STATUS_DISCOVERED)) {
+		ip = stun->publicip;
+	} else {
+		/* Attempt to get the IP from a NAT device using UPnP */
+		ip = purple_upnp_get_public_ip();
+		if (ip == NULL) {
+			/* Attempt to get the IP from a NAT device using NAT-PMP */
+			ip = purple_pmp_get_public_ip();
+			if (ip == NULL) {
+				/* Just fetch the IP of the local system */
+				ip = purple_network_get_local_system_ip(-1);
+			}
+		}
+	}
+
+	auto_ip_text = g_strdup_printf(_("Use _automatically detected IP address: %s"), ip);
+	auto_ip_checkbox = pidgin_prefs_checkbox(auto_ip_text, "/purple/network/auto_ip", vbox);
+	g_free(auto_ip_text);
 
 	table = gtk_table_new(2, 2, FALSE);
 	gtk_container_set_border_width(GTK_CONTAINER(table), 0);
@@ -1558,16 +1829,9 @@
 	g_signal_connect(G_OBJECT(entry), "changed",
 					 G_CALLBACK(network_ip_changed), NULL);
 
-	/*
-	 * TODO: This could be better by showing the autodeteced
-	 * IP separately from the user-specified IP.
-	 */
-	if (purple_network_get_my_ip(-1) != NULL)
-		gtk_entry_set_text(GTK_ENTRY(entry),
-		                   purple_network_get_my_ip(-1));
-
-	pidgin_set_accessible_label (entry, label);
-
+	gtk_entry_set_text(GTK_ENTRY(entry), purple_network_get_public_ip());
+
+	pidgin_set_accessible_label(entry, label);
 
 	if (purple_prefs_get_bool("/purple/network/auto_ip")) {
 		gtk_widget_set_sensitive(GTK_WIDGET(table), FALSE);
@@ -1619,7 +1883,7 @@
 
 	pidgin_prefs_labeled_spin_button(hbox, _("_Port:"),
 		"/purple/network/turn_port", 0, 65535, NULL);
-	hbox = pidgin_prefs_labeled_entry(vbox, "_Username:", 
+	hbox = pidgin_prefs_labeled_entry(vbox, "_Username:",
 		"/purple/network/turn_username", sg);
 	pidgin_prefs_labeled_password(hbox, "_Password:",
 		"/purple/network/turn_password", NULL);
@@ -1801,7 +2065,9 @@
 }
 
 #ifndef _WIN32
-static gboolean manual_browser_set(GtkWidget *entry, GdkEventFocus *event, gpointer data) {
+static gboolean
+manual_browser_set(GtkWidget *entry, GdkEventFocus *event, gpointer data)
+{
 	const char *program = gtk_entry_get_text(GTK_ENTRY(entry));
 
 	purple_prefs_set_path(PIDGIN_PREFS_ROOT "/browsers/command", program);
@@ -1810,7 +2076,8 @@
 	return FALSE;
 }
 
-static GList *get_available_browsers(void)
+static GList *
+get_available_browsers(void)
 {
 	struct browser {
 		char *name;
@@ -1977,7 +2244,8 @@
 }
 
 #ifndef _WIN32
-static gint sound_cmd_yeah(GtkEntry *entry, gpointer d)
+static gint
+sound_cmd_yeah(GtkEntry *entry, gpointer d)
 {
 	purple_prefs_set_path(PIDGIN_PREFS_ROOT "/sound/command",
 			gtk_entry_get_text(GTK_ENTRY(entry)));
@@ -2109,7 +2377,8 @@
 	pref_sound_generate_markup();
 }
 
-static void select_sound(GtkWidget *button, gpointer being_NULL_is_fun)
+static void
+select_sound(GtkWidget *button, gpointer being_NULL_is_fun)
 {
 	gchar *pref;
 	const char *filename;
@@ -2129,7 +2398,8 @@
 }
 
 #ifdef USE_GSTREAMER
-static gchar* prefs_sound_volume_format(GtkScale *scale, gdouble val)
+static gchar *
+prefs_sound_volume_format(GtkScale *scale, gdouble val)
 {
 	if(val < 15) {
 		return g_strdup_printf(_("Quietest"));
@@ -2148,14 +2418,17 @@
 	}
 }
 
-static void prefs_sound_volume_changed(GtkRange *range)
+static void
+prefs_sound_volume_changed(GtkRange *range)
 {
 	int val = (int)gtk_range_get_value(GTK_RANGE(range));
 	purple_prefs_set_int(PIDGIN_PREFS_ROOT "/sound/volume", val);
 }
 #endif
 
-static void prefs_sound_sel(GtkTreeSelection *sel, GtkTreeModel *model) {
+static void
+prefs_sound_sel(GtkTreeSelection *sel, GtkTreeModel *model)
+{
 	GtkTreeIter  iter;
 	GValue val;
 	const char *file;
@@ -2202,7 +2475,7 @@
 sound_page(void)
 {
 	GtkWidget *ret;
-	GtkWidget *vbox, *sw, *button, *combo_box;
+	GtkWidget *vbox, *sw, *button;
 	GtkSizeGroup *sg;
 	GtkTreeIter iter;
 	GtkWidget *event_view;
@@ -2308,11 +2581,14 @@
 			vbox->parent->parent, TRUE, TRUE, 0, GTK_PACK_START);
 
 	/* SOUND THEMES */
-	combo_box = prefs_build_theme_combo_box(prefs_sound_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme"));
-	pref_sound_generate_markup();
-	gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0);
-
-	g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_sound_theme_cb, NULL);
+	prefs_sound_themes_combo_box = prefs_build_theme_combo_box(prefs_sound_themes,
+						purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme"),
+						"sound");
+
+
+	gtk_box_pack_start(GTK_BOX (vbox), prefs_sound_themes_combo_box, FALSE, FALSE, 0);
+
+	g_signal_connect(G_OBJECT(prefs_sound_themes_combo_box), "changed", (GCallback)prefs_set_sound_theme_cb, NULL);
 
 	/* SOUND SELECTION */
 	sw = gtk_scrolled_window_new(NULL,NULL);
@@ -2505,10 +2781,8 @@
 }
 
 static int
-prefs_notebook_add_page(const char *text,
-  		        GtkWidget *page,
-			int ind) {
-
+prefs_notebook_add_page(const char *text, GtkWidget *page, int ind)
+{
 #if GTK_CHECK_VERSION(2,4,0)
 	return gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook), page, gtk_label_new(text));
 #else
@@ -2517,7 +2791,9 @@
 #endif
 }
 
-static void prefs_notebook_init(void) {
+static void
+prefs_notebook_init(void)
+{
 	prefs_notebook_add_page(_("Interface"), interface_page(), notebook_page++);
 	prefs_notebook_add_page(_("Conversations"), conv_page(), notebook_page++);
 	prefs_notebook_add_page(_("Smiley Themes"), theme_page(), notebook_page++);
@@ -2534,7 +2810,8 @@
 	prefs_notebook_add_page(_("Status / Idle"), away_page(), notebook_page++);
 }
 
-void pidgin_prefs_show(void)
+void
+pidgin_prefs_show(void)
 {
 	GtkWidget *vbox;
 	GtkWidget *notebook;
@@ -2545,14 +2822,6 @@
 		return;
 	}
 
-	/* Refresh the list of themes before showing the preferences window */
-	purple_theme_manager_refresh();
-
-	/* add everything in the theme manager before the window is loaded */
-	if (prefs_themes_unsorted) {
-		purple_theme_manager_for_each_theme(prefs_themes_sort);
-		prefs_themes_unsorted = FALSE;
-	}
 	/* copy the preferences to tmp values...
 	 * I liked "take affect immediately" Oh well :-( */
 	/* (that should have been "effect," right?) */
@@ -2577,6 +2846,9 @@
 
 	prefs_notebook_init();
 
+	/* Refresh the list of themes before showing the preferences window */
+	prefs_themes_refresh();
+
 	/* Show everything. */
 	gtk_widget_show(prefs);
 }
@@ -2661,7 +2933,8 @@
 	pidgin_prefs_update_old();
 }
 
-void pidgin_prefs_update_old()
+void
+pidgin_prefs_update_old(void)
 {
 	const char *str;