changeset 8713:7024b595b6ae

[gaim-migrate @ 9467] " Expansion from my original protocol prefs to plugin prefs. Things are handled a bit different in this iteration of it, but I have already modified msn and jabber to use it, and included an example plugin to show how to use it. It will also generate pages with doxygen. The example plugin doesn't not contain any translatable strings seeing as we're in the string freeze. And it's an example, whats the point of translating it..? Also, I tweaked the documentation for 2 functions in gtkprefs, gaim_gtk_prefs_dropdown and gaim_gtk_prefs_dropdown_from_list. Nothing major in that, just made it say that the list should be a list of pairs label/value. Also there's 5 new files that will need to be added to cvs: src/pluginpref.h src/pluginpref.c src/gtkpluginpref.h src/gtkpluginpref.c plugins/pluginpref_example.c the tarball already has them structured correctly and contains the diff" --Gary Kramlich - amc_grim and the german translator pointed out that sean missed the novell file for POTFILES.in committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Mon, 19 Apr 2004 21:12:45 +0000
parents a4ff6e79c5fc
children a36f02de8d60
files ChangeLog plugins/Makefile.am plugins/pluginpref_example.c po/POTFILES.in src/Makefile.am src/Makefile.mingw src/gtkpluginpref.c src/gtkpluginpref.h src/gtkprefs.c src/gtkprefs.h src/multi.h src/plugin.h src/pluginpref.c src/pluginpref.h src/protocols/gg/gg.c src/protocols/irc/irc.c src/protocols/jabber/jabber.c src/protocols/msn/msn.c src/protocols/napster/napster.c src/protocols/novell/novell.c src/protocols/oscar/oscar.c src/protocols/toc/toc.c src/protocols/yahoo/yahoo.c src/protocols/zephyr/zephyr.c src/prpl.h
diffstat 25 files changed, 1040 insertions(+), 153 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Apr 19 20:30:56 2004 +0000
+++ b/ChangeLog	Mon Apr 19 21:12:45 2004 +0000
@@ -13,8 +13,10 @@
 	* Rich-text copy and paste
 	* Plugins can now add menu items to the buddy context menu
 	  (Christopher O'Brien)
+	* Plugins can now add preferences (Gary Kramlich)
 
 	Bug Fixes:
+	* Formatting in the Log viewwer is fixed
 	* TOC has been removed from the default build list. I do not support
 	  it, as no one is making sure that the updated code to keep it
 	  compiling actually works, nor is anyone fixing bugs in it.
--- a/plugins/Makefile.am	Mon Apr 19 20:30:56 2004 +0000
+++ b/plugins/Makefile.am	Mon Apr 19 21:12:45 2004 +0000
@@ -57,6 +57,7 @@
 	ChangeLog HOWTO \
 	filectl.c \
 	mailchk.c \
+	pluginpref_example.c \
 	raw.c \
 	signals-test.c \
 	simple.c \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/pluginpref_example.c	Mon Apr 19 21:12:45 2004 +0000
@@ -0,0 +1,149 @@
+/*
+ * Release Notification Plugin
+ *
+ * Copyright (C) 2004, Gary Kramlich <amc_grim@users.sf.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef GAIM_PLUGINS
+# define GAIM_PLUGINS
+#endif
+
+#include "internal.h"
+
+#include "plugin.h"
+#include "pluginpref.h"
+#include "prefs.h"
+
+GaimPluginPrefFrame *
+get_plugin_pref_frame(GaimPlugin *plugin) {
+	GaimPluginPrefFrame *frame;
+	GaimPluginPref *ppref;
+
+	frame = gaim_plugin_pref_frame_new();
+
+	ppref = gaim_plugin_pref_new_with_label("boolean");
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_name_and_label(
+									"/plugins/core/pluginpref_example/bool",
+									"boolean pref");
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_label("integer");
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_name_and_label(
+									"/plugins/core/pluginpref_example/int",
+									"integer pref");
+	gaim_plugin_pref_set_bounds(ppref, 0, 255);
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_name_and_label(
+									"/plugins/core/pluginpref_example/int_choice",
+									"integer choice");
+	gaim_plugin_pref_set_type(ppref, GAIM_PLUGIN_PREF_CHOICE);
+	gaim_plugin_pref_add_choice(ppref, "One", GINT_TO_POINTER(1));
+	gaim_plugin_pref_add_choice(ppref, "Two", GINT_TO_POINTER(2));
+	gaim_plugin_pref_add_choice(ppref, "Four", GINT_TO_POINTER(4));
+	gaim_plugin_pref_add_choice(ppref, "Eight", GINT_TO_POINTER(8));
+	gaim_plugin_pref_add_choice(ppref, "Sixteen", GINT_TO_POINTER(16));
+	gaim_plugin_pref_add_choice(ppref, "Thirty Two", GINT_TO_POINTER(32));
+	gaim_plugin_pref_add_choice(ppref, "Sixty Four", GINT_TO_POINTER(64));
+	gaim_plugin_pref_add_choice(ppref, "One Hundred Twenty Eight", GINT_TO_POINTER(128));
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_label("string");
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_name_and_label(
+								"/plugins/core/pluginpref_example/string",
+								"string pref");
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_name_and_label(
+							"/plugins/core/pluginpref_example/max_string",
+							"string pref\n(max length of 16)");
+	gaim_plugin_pref_set_max_length(ppref, 16);
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_name_and_label(
+							"/plugins/core/pluginpref_example/string_choice",
+							"string choice");
+	gaim_plugin_pref_set_type(ppref, GAIM_PLUGIN_PREF_CHOICE);
+	gaim_plugin_pref_add_choice(ppref, "red", "red");
+	gaim_plugin_pref_add_choice(ppref, "orange", "orange");
+	gaim_plugin_pref_add_choice(ppref, "yellow", "yellow");
+	gaim_plugin_pref_add_choice(ppref, "green", "green");
+	gaim_plugin_pref_add_choice(ppref, "blue", "blue");
+	gaim_plugin_pref_add_choice(ppref, "purple", "purple");
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	return frame;
+}
+
+static GaimPluginUiInfo prefs_info = {
+	get_plugin_pref_frame
+};
+
+static GaimPluginInfo info =
+{
+	2,                                                /**< api_version    */
+	GAIM_PLUGIN_STANDARD,                             /**< type           */
+	NULL,                                             /**< ui_requirement */
+	0,                                                /**< flags          */
+	NULL,                                             /**< dependencies   */
+	GAIM_PRIORITY_DEFAULT,                            /**< priority       */
+
+	"core-pluginpref_example",                     /**< id             */
+	"Pluginpref Example",                           /**< name           */
+	VERSION,                                          /**< version        */
+	                                                  /**  summary        */
+	"An example of how to use pluginprefs",
+	                                                  /**  description    */
+	"An example of how to use pluginprefs",
+	"Gary Kramlich <amc_grim@users.sf.net>",      /**< author         */
+	GAIM_WEBSITE,                                     /**< homepage       */
+
+	NULL,                                             /**< load           */
+	NULL,                                             /**< unload         */
+	NULL,                                             /**< destroy        */
+
+	NULL,                                             /**< ui_info        */
+	NULL,                                             /**< extra_info     */
+	&prefs_info                                       /**< prefs_info     */
+};
+
+static void
+init_plugin(GaimPlugin *plugin)
+{
+	gaim_prefs_add_none("/plugins/core/pluginpref_example");
+	gaim_prefs_add_bool("/plugins/core/pluginpref_example/bool", TRUE);
+	gaim_prefs_add_int("/plugins/core/pluginpref_example/int", 0);
+	gaim_prefs_add_int("/plugins/core/pluginpref_example/int_choice", 1);
+	gaim_prefs_add_string("/plugins/core/pluginpref_example/string",
+							"string");
+	gaim_prefs_add_string("/plugins/core/pluginpref_example/max_string",
+							"max length string");
+	gaim_prefs_add_string("/plugins/core/pluginpref_example/string_choice", "red");
+}
+
+GAIM_INIT_PLUGIN(relnot, init_plugin, info)
--- a/po/POTFILES.in	Mon Apr 19 20:30:56 2004 +0000
+++ b/po/POTFILES.in	Mon Apr 19 21:12:45 2004 +0000
@@ -95,6 +95,7 @@
 src/protocols/msn/state.c
 src/protocols/msn/switchboard.c
 src/protocols/napster/napster.c
+src/protocols/novell/novell.c
 src/protocols/oscar/oscar.c
 src/protocols/toc/toc.c
 src/protocols/trepia/trepia.c
--- a/src/Makefile.am	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/Makefile.am	Mon Apr 19 21:12:45 2004 +0000
@@ -91,6 +91,8 @@
 	notify.h \
 	plugin.c \
 	plugin.h \
+	pluginpref.c \
+	pluginpref.h \
 	pounce.c \
 	pounce.h \
 	privacy.c \
@@ -165,6 +167,8 @@
 	gtknotify.h \
 	gtkplugin.c \
 	gtkplugin.h \
+	gtkpluginpref.c \
+	gtkpluginpref.h \
 	gtkprefs.c \
 	gtkprefs.h \
 	gtkprivacy.c \
--- a/src/Makefile.mingw	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/Makefile.mingw	Mon Apr 19 21:12:45 2004 +0000
@@ -121,6 +121,7 @@
 			network.c \
 			notify.c \
 			plugin.c \
+			pluginpref.c \
 			pounce.c \
 			prefs.c \
 			privacy.c \
@@ -229,5 +230,3 @@
 	rm -rf $(TARGET).dll
 	rm -rf $(TARGET).lib
 	rm -rf $(TARGET).exe
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gtkpluginpref.c	Mon Apr 19 21:12:45 2004 +0000
@@ -0,0 +1,175 @@
+/**
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "debug.h"
+#include "internal.h"
+#include "pluginpref.h"
+#include "prefs.h"
+
+#include "gtkpluginpref.h"
+#include "gtkprefs.h"
+#include "gtkutils.h"
+
+static gboolean
+entry_cb(GtkWidget *entry, gpointer data) {
+	char *pref = data;
+
+	gaim_prefs_set_string(pref, gtk_entry_get_text(GTK_ENTRY(entry)));
+
+	return FALSE;
+}
+
+static void
+make_string_pref(GtkWidget *parent, GaimPluginPref *pref, GtkSizeGroup *sg) {
+	GtkWidget *hbox, *gtk_label, *entry;
+	gchar *pref_name, *pref_label;
+
+	pref_name = gaim_plugin_pref_get_name(pref);
+	pref_label = gaim_plugin_pref_get_label(pref);
+
+	switch(gaim_plugin_pref_get_type(pref)) {
+		case GAIM_PLUGIN_PREF_CHOICE:
+			gtk_label = gaim_gtk_prefs_dropdown_from_list(parent, pref_label,
+											  GAIM_PREF_STRING, pref_name,
+											  gaim_plugin_pref_get_choices(pref));						
+			gtk_misc_set_alignment(GTK_MISC(gtk_label), 0, 0.5);
+
+			if(sg)
+				gtk_size_group_add_widget(sg, gtk_label);
+
+			break;
+		case GAIM_PLUGIN_PREF_NONE:
+		default:
+			hbox = gtk_hbox_new(FALSE, 6);
+			gtk_widget_show(hbox);
+			gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
+
+			gtk_label = gtk_label_new_with_mnemonic(pref_label);
+			gtk_misc_set_alignment(GTK_MISC(gtk_label), 0, 0.5);
+			gtk_widget_show(gtk_label);
+			gtk_box_pack_start(GTK_BOX(hbox), gtk_label, FALSE, FALSE, 0);
+
+			if(sg)
+				gtk_size_group_add_widget(sg, gtk_label);
+
+			entry = gtk_entry_new();
+			gtk_entry_set_text(GTK_ENTRY(entry), gaim_prefs_get_string(pref_name));
+			gtk_entry_set_max_length(GTK_ENTRY(entry),
+									 gaim_plugin_pref_get_max_length(pref));
+			g_signal_connect(G_OBJECT(entry), "changed",
+							 G_CALLBACK(entry_cb),
+							 (gpointer)pref_name);
+			gtk_label_set_mnemonic_widget(GTK_LABEL(gtk_label), entry);
+			gtk_widget_show(entry);
+			gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
+
+			break;
+	}
+}
+
+static void
+make_int_pref(GtkWidget *parent, GaimPluginPref *pref, GtkSizeGroup *sg) {
+	GtkWidget *gtk_label;
+	gchar *pref_name, *pref_label;
+	gint max, min;
+
+	pref_name = gaim_plugin_pref_get_name(pref);
+	pref_label = gaim_plugin_pref_get_label(pref);
+
+	switch(gaim_plugin_pref_get_type(pref)) {
+		case GAIM_PLUGIN_PREF_CHOICE:
+			gtk_label = gaim_gtk_prefs_dropdown_from_list(parent, pref_label,
+											  GAIM_PREF_INT, pref_name,
+											  gaim_plugin_pref_get_choices(pref));
+			gtk_misc_set_alignment(GTK_MISC(gtk_label), 0, 0.5);
+
+			if(sg)
+				gtk_size_group_add_widget(sg, gtk_label);
+
+			break;
+		case GAIM_PLUGIN_PREF_NONE:
+		default:
+			gaim_plugin_pref_get_bounds(pref, &min, &max);
+			gaim_gtk_prefs_labeled_spin_button(parent, pref_label, 
+											   pref_name, min, max, sg);
+			break;
+	}
+}
+
+GtkWidget *
+gaim_gtk_plugin_pref_create_frame(GaimPluginPrefFrame *frame) {
+	GaimPluginPref *pref;
+	GtkWidget *ret, *parent;
+	GtkSizeGroup *sg;
+	GList *pp;
+	gchar *name, *label;
+
+	g_return_val_if_fail(frame, NULL);
+
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+
+	parent = ret = gtk_vbox_new(FALSE, 16);
+	gtk_container_set_border_width(GTK_CONTAINER(ret), 12);
+	gtk_widget_show(ret);
+
+	for(pp = gaim_plugin_pref_frame_get_prefs(frame);
+		pp != NULL;
+		pp = pp->next)
+	{
+		pref = (GaimPluginPref *)pp->data;
+
+		name = gaim_plugin_pref_get_name(pref);
+		label = gaim_plugin_pref_get_label(pref);
+
+		if(name == NULL) {
+			if(label == NULL)
+				continue;
+		
+			parent = gaim_gtk_make_frame(ret, label);
+			gtk_widget_show(parent);
+
+			continue;
+		}
+
+		switch(gaim_prefs_get_type(name)) {
+			case GAIM_PREF_BOOLEAN:
+				gaim_gtk_prefs_checkbox(label, name, parent);
+				break;
+			case GAIM_PREF_INT:
+				make_int_pref(parent, pref, sg);
+				break;
+			case GAIM_PREF_STRING:
+				make_string_pref(parent, pref, sg);
+				break;
+			default:
+				break;
+		}
+	}
+
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gtkpluginpref.h	Mon Apr 19 21:12:45 2004 +0000
@@ -0,0 +1,53 @@
+/**
+ * @file gtkpluginpref.h GTK+ Plugin Preferences
+ * @ingroup gtkui
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef _GTK_PLUGIN_PREF_H_
+#define _GTK_PLUGIN_PREF_H_
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+
+#include "pluginpref.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Creates a Gtk Preference frame for a GaimPluginPrefFrame
+ *
+ * @param frame GaimPluginPrefFrame
+ * @return The gtk preference frame
+ */
+GtkWidget *gaim_gtk_plugin_pref_create_frame(GaimPluginPrefFrame *frame);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GTK_PLUGIN_PREF_H_ */
--- a/src/gtkprefs.c	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/gtkprefs.c	Mon Apr 19 21:12:45 2004 +0000
@@ -40,6 +40,7 @@
 #include "gtkdebug.h"
 #include "gtkimhtml.h"
 #include "gtkplugin.h"
+#include "gtkpluginpref.h"
 #include "gtkprefs.h"
 #include "gtksound.h"
 #include "gtkutils.h"
@@ -75,7 +76,7 @@
 static GtkWidget *prefs = NULL;
 static GtkWidget *debugbutton = NULL;
 static int notebook_page = 0;
-static GtkTreeIter plugin_iter;
+static GtkTreeIter proto_iter, plugin_iter;
 
 static guint browser_pref1_id = 0;
 static guint browser_pref2_id = 0;
@@ -123,6 +124,7 @@
 	gtk_widget_show(hbox);
 
 	label = gtk_label_new_with_mnemonic(title);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
 	gtk_widget_show(label);
 
@@ -199,7 +201,8 @@
 	g_return_val_if_fail(menuitems != NULL, NULL);
 
 	hbox = gtk_hbox_new(FALSE, 5);
-	gtk_container_add (GTK_CONTAINER (box), hbox);
+	/*gtk_container_add (GTK_CONTAINER (box), hbox);*/
+	gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
 	gtk_widget_show(hbox);
 
 	label = gtk_label_new_with_mnemonic(title);
@@ -1713,86 +1716,6 @@
 	return ret;
 }
 
-static gboolean 
-protocol_pref_entry_cb(GtkWidget *entry, GdkEventFocus *event, gpointer data) {
-	char *pref = data;
-	
-	gaim_prefs_set_string(pref, gtk_entry_get_text(GTK_ENTRY(entry)));
-	
-	return FALSE;
-}
-
-static GtkWidget *
-protocol_pref_page(GaimPluginProtocolInfo *prpl_info) {
-	GtkWidget *ret, *parent, *frame, *hbox, *label, *misc;
-	GtkSizeGroup *sg;
-	GList *pp = NULL;
-
-	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-	
-	ret = gtk_vbox_new(FALSE, 18);
-	gtk_container_set_border_width (GTK_CONTAINER (ret), 12);
-	gtk_widget_show(ret);
-	
-	parent = ret;
-
-	for(pp = prpl_info->protocol_prefs; pp != NULL; pp = pp->next) {
-		struct proto_pref *pref = pp->data;
-		
-		if(pref->key != NULL) {
-			switch(gaim_prefs_get_type(pref->key)) {
-				case GAIM_PREF_BOOLEAN:
-					misc = gaim_gtk_prefs_checkbox(pref->label,
-												   pref->key,
-												   parent);
-					break;
-				case GAIM_PREF_INT:
-					misc = gaim_gtk_prefs_labeled_spin_button(parent,
-															  pref->label,
-															  pref->key,
-															  pref->min,
-															  pref->max,
-															  sg);
-					break;
-				case GAIM_PREF_STRING:
-					hbox = gtk_hbox_new(FALSE, 6);
-					gtk_widget_show(hbox);
-					gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
-
-					label = gtk_label_new_with_mnemonic(pref->label);
-					gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
-					gtk_size_group_add_widget(sg, label);
-					gtk_widget_show(label);
-					gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-
-					misc = gtk_entry_new();
-					gtk_entry_set_text(GTK_ENTRY(misc),
-									   gaim_prefs_get_string(pref->key));
-					g_signal_connect(G_OBJECT(misc), "focus-out-event", 
-									 G_CALLBACK(protocol_pref_entry_cb),
-									 (gpointer)pref->key);
-					gtk_label_set_mnemonic_widget(GTK_LABEL(label), misc);
-					gtk_widget_show(misc);
-					gtk_box_pack_start(GTK_BOX(hbox), misc, FALSE, FALSE, 0);
-
-					break;
-				case GAIM_PREF_NONE: /* XXX No use for this, if you want a
-										frame, set key to NULL */
-				case GAIM_PREF_STRING_LIST: /*XXX No one should need this */
-				default:
-					break;
-			}
-		} else {
-			frame = gaim_gtk_make_frame(ret, pref->label);
-			gtk_widget_show(frame);
-
-			parent = frame;
-		}
-	}
-
-	return ret;
-}
-
 static GtkWidget *plugin_description=NULL, *plugin_details=NULL;
 
 static void prefs_plugin_sel (GtkTreeSelection *sel, GtkTreeModel *model) 
@@ -1908,6 +1831,36 @@
 				}
 			}
 		}
+
+		if(GAIM_PLUGIN_HAS_PREF_FRAME(plug)) {
+			GtkTreeIter iter;			
+			GtkWidget *pref_frame;
+			GaimPluginUiInfo *prefs_info;
+
+			if(plug->info->type == GAIM_PLUGIN_PROTOCOL)
+				iter = proto_iter;
+			else
+				iter = plugin_iter;
+
+			prefs_info = GAIM_PLUGIN_UI_INFO(plug);
+			pref_frame = gaim_gtk_plugin_pref_create_frame(prefs_info->get_plugin_pref_frame(plug));
+
+			if(pref_frame != NULL) {
+				prefs_info->iter = g_new0(GtkTreeIter, 1);
+				prefs_notebook_add_page(_(plug->info->name), NULL,
+										pref_frame, prefs_info->iter,
+										&iter, notebook_page++);
+
+				if(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(prefstree), &iter) == 1)
+				{
+					GtkTreePath *path2;
+
+					path2 = gtk_tree_model_get_path(GTK_TREE_MODEL(prefstree), &iter);
+					gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_v), path2, TRUE);
+					gtk_tree_path_free(path2);
+				}
+			}
+		}
 	}
 	else {
 		if (GAIM_IS_GTK_PLUGIN(plug)) {
@@ -1920,6 +1873,16 @@
 				g_free(ui_info->iter);
 				ui_info->iter = NULL;
 			}
+		} else if (GAIM_PLUGIN_HAS_PREF_FRAME(plug)) {
+			GaimPluginUiInfo *prefs_info;
+
+			prefs_info = GAIM_PLUGIN_UI_INFO(plug);
+
+			if(prefs_info != NULL && prefs_info->iter != NULL) {
+				gtk_tree_store_remove(GTK_TREE_STORE(prefstree), prefs_info->iter);
+				g_free(prefs_info->iter);
+				prefs_info->iter = NULL;
+			}
 		}
 
 		gaim_plugin_unload(plug);
@@ -2540,26 +2503,12 @@
 	prefs_notebook_add_page(_("Away / Idle"), NULL, away_page(), &p, NULL, notebook_page++);
 	prefs_notebook_add_page(_("Away Messages"), NULL, away_message_page(), &c, &p, notebook_page++);
 
-	prefs_notebook_add_page(_("Protocols"), NULL, protocol_page(), &p, NULL, notebook_page++);
-	for (l = gaim_plugins_get_protocols(); l != NULL; l = l->next) {
-		plug = l->data;
-
-		if (GAIM_IS_PROTOCOL_PLUGIN(plug)) {
-			GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(plug);
-
-			if (prpl_info->protocol_prefs != NULL) {
-				prefs_notebook_add_page(_(plug->info->name), NULL,
-										protocol_pref_page(prpl_info), &c,
-										&p, notebook_page++);
-			}
-		}
-	}
-
 	if (gaim_plugins_enabled()) {
+		prefs_notebook_add_page(_("Protocols"), NULL, protocol_page(), &proto_iter, NULL, notebook_page++);
 		prefs_notebook_add_page(_("Plugins"), NULL, plugin_page(), &plugin_iter, NULL, notebook_page++);
 
 		for (l = gaim_plugins_get_loaded(); l != NULL; l = l->next) {
-			plug = l->data;
+			plug = (GaimPlugin *)l->data;
 
 			if (GAIM_IS_GTK_PLUGIN(plug)) {
 				GtkWidget *config_frame;
@@ -2575,6 +2524,22 @@
 											&plugin_iter, notebook_page++);
 				}
 			}
+
+			if(GAIM_PLUGIN_HAS_PREF_FRAME(plug)) {
+				GtkWidget *pref_frame;
+				GaimPluginUiInfo *prefs_info;
+
+				prefs_info = GAIM_PLUGIN_UI_INFO(plug);
+				pref_frame = gaim_gtk_plugin_pref_create_frame(prefs_info->get_plugin_pref_frame(plug));
+
+				if(pref_frame != NULL) {
+					prefs_info->iter = g_new0(GtkTreeIter, 1);
+					prefs_notebook_add_page(_(plug->info->name), NULL,
+										pref_frame, prefs_info->iter,
+										(plug->info->type == GAIM_PLUGIN_PROTOCOL) ? &proto_iter : &plugin_iter,
+										notebook_page++);
+				}
+			}
 		}
 	}
 }
@@ -2691,7 +2656,7 @@
 	gtk_widget_show(sep);
 	gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 0);
 
-	/* The buttons^H to press! */
+	/* The buttons to press! */
 	bbox = gtk_hbutton_box_new();
 	gtk_box_set_spacing(GTK_BOX(bbox), 6);
 	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
--- a/src/gtkprefs.h	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/gtkprefs.h	Mon Apr 19 21:12:45 2004 +0000
@@ -87,7 +87,8 @@
  * @param title The text to be displayed as the dropdown label
  * @param type  The type of preference to be stored in the generated dropdown
  * @param key   The key of the pref that will be represented by the dropdown
- * @param ...   The choices to be added to the dropdown
+ * @param ...   The choices to be added to the dropdown, choices should be
+ *              paired as label/value
  */
 GtkWidget *gaim_gtk_prefs_dropdown(GtkWidget *page, const gchar *title,
 		GaimPrefType type, const char *key, ...);
@@ -99,7 +100,8 @@
  * @param title     The text to be displayed as the dropdown label
  * @param type      The type of preference to be stored in the dropdown
  * @param key       The key of the pref that will be represented by the dropdown
- * @param menuitems The choices to be added to the dropdown
+ * @param menuitems The choices to be added to the dropdown, choices should
+ *                  be paired as label/value
  */
 GtkWidget *gaim_gtk_prefs_dropdown_from_list(GtkWidget *page,
 		const gchar * title, GaimPrefType type, const char *key,
--- a/src/multi.h	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/multi.h	Mon Apr 19 21:12:45 2004 +0000
@@ -55,13 +55,6 @@
 	gboolean secret;
 };
 
-struct proto_pref {
-	char *key;
-	char *label;
-	int min;
-	int max;
-};
-
 #endif /* _MULTI_H_ */
 
 /* A big line. */
--- a/src/plugin.h	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/plugin.h	Mon Apr 19 21:12:45 2004 +0000
@@ -29,12 +29,15 @@
 #include "signals.h"
 #include "value.h"
 
-typedef struct _GaimPlugin     GaimPlugin;         /**< GaimPlugin       */
-typedef struct _GaimPluginInfo GaimPluginInfo;     /**< GaimPluginInfo   */
+typedef struct _GaimPlugin           GaimPlugin;         /**< GaimPlugin       */
+typedef struct _GaimPluginInfo       GaimPluginInfo;     /**< GaimPluginInfo   */
+typedef struct _GaimPluginUiInfo     GaimPluginUiInfo;   /**< GaimPluginUiInfo */
 typedef struct _GaimPluginLoaderInfo GaimPluginLoaderInfo;
 
 typedef int GaimPluginPriority; /**< Plugin priority. */
 
+#include "pluginpref.h"
+
 /**
  * Plugin types.
  */
@@ -81,6 +84,7 @@
 
 	void *ui_info;
 	void *extra_info;
+	void *prefs_info;
 };
 
 /**
@@ -114,6 +118,18 @@
 #define GAIM_PLUGIN_LOADER_INFO(plugin) \
 	((GaimPluginLoaderInfo *)(plugin)->info->extra_info)
 
+struct _GaimPluginUiInfo {
+	GaimPluginPrefFrame *(*get_plugin_pref_frame)(GaimPlugin *plugin);
+
+	void *iter;                                           /**< Reserved */
+};
+
+#define GAIM_PLUGIN_HAS_PREF_FRAME(plugin) \
+	((plugin)->info != NULL && (plugin)->info->prefs_info != NULL)
+
+#define GAIM_PLUGIN_UI_INFO(plugin) \
+	((GaimPluginUiInfo*)(plugin)->info->prefs_info)
+
 /**
  * Handles the initialization of modules.
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pluginpref.c	Mon Apr 19 21:12:45 2004 +0000
@@ -0,0 +1,290 @@
+/**
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib.h>
+
+#include "debug.h"
+#include "internal.h"
+#include "pluginpref.h"
+#include "prefs.h"
+
+struct _GaimPluginPrefFrame {
+	GList *prefs;
+};
+
+struct _GaimPluginPref {
+	char *name;
+	char *label;
+
+	GaimPluginPrefType type;
+
+	int min;
+	int max;
+	GList *choices;
+	unsigned int max_length;
+};
+
+GaimPluginPrefFrame *
+gaim_plugin_pref_frame_new() {
+	GaimPluginPrefFrame *frame;
+
+	frame = g_new0(GaimPluginPrefFrame, 1);
+
+	return frame;
+}
+
+void
+gaim_plugin_pref_frame_destroy(GaimPluginPrefFrame *frame) {
+	GaimPluginPref *pref;
+	GList *l, *ll;
+
+	g_return_if_fail(frame);
+
+	for(l = frame->prefs; l != NULL; l = ll) {
+		ll = l->next;
+
+		pref = (GaimPluginPref *)l->data;
+		gaim_plugin_pref_destroy(pref);
+
+		g_list_free_1(l);
+	}
+
+	frame = NULL;
+}
+
+void
+gaim_plugin_pref_frame_add(GaimPluginPrefFrame *frame, GaimPluginPref *pref) {
+	g_return_if_fail(frame);
+	g_return_if_fail(pref);
+
+	frame->prefs = g_list_append(frame->prefs, (gpointer)pref);
+}
+
+GList *
+gaim_plugin_pref_frame_get_prefs(GaimPluginPrefFrame *frame) {
+	return frame->prefs;
+}
+
+GaimPluginPref *
+gaim_plugin_pref_new() {
+	GaimPluginPref *pref;
+
+	pref = g_new0(GaimPluginPref, 1);
+
+	return pref;
+}
+
+GaimPluginPref *
+gaim_plugin_pref_new_with_name(char *name) {
+	GaimPluginPref *pref;
+
+	g_return_val_if_fail(name, NULL);
+
+	pref = g_new0(GaimPluginPref, 1);
+	pref->name = g_strdup(name);
+
+	return pref;
+}
+
+GaimPluginPref *
+gaim_plugin_pref_new_with_label(char *label) {
+	GaimPluginPref *pref;
+
+	g_return_val_if_fail(label, NULL);
+
+	pref = g_new0(GaimPluginPref, 1);
+	pref->label = g_strdup(label);
+
+	return pref;
+}
+
+GaimPluginPref *
+gaim_plugin_pref_new_with_name_and_label(char *name, char *label) {
+	GaimPluginPref *pref;
+
+	g_return_val_if_fail(name, NULL);
+	g_return_val_if_fail(label, NULL);
+
+	pref = g_new0(GaimPluginPref, 1);
+	pref->name = g_strdup(name);
+	pref->label = g_strdup(label);
+
+	return pref;
+}
+
+void
+gaim_plugin_pref_destroy(GaimPluginPref *pref) {
+	GList *l, *ll;
+
+	g_return_if_fail(pref);
+
+	if(pref->name)
+		g_free(pref->name);
+
+	if(pref->label)
+		g_free(pref->label);
+
+	l = pref->choices;
+	while(l) {
+		ll = l->next;
+
+		g_free(l->data);
+		g_list_free_1(l);
+
+		l = l->next;
+	}
+
+	g_free(pref);
+}
+
+void
+gaim_plugin_pref_set_name(GaimPluginPref *pref, char *name) {
+	g_return_if_fail(pref);
+	g_return_if_fail(name);
+
+	if(pref->name)
+		g_free(pref->name);
+
+	pref->name = g_strdup(name);
+}
+
+char *
+gaim_plugin_pref_get_name(GaimPluginPref *pref) {
+	g_return_val_if_fail(pref, NULL);
+
+	return pref->name;
+}
+
+void
+gaim_plugin_pref_set_label(GaimPluginPref *pref, char *label) {
+	g_return_if_fail(pref);
+	g_return_if_fail(label);
+
+	if(pref->label)
+		g_free(pref->label);
+
+	pref->label = g_strdup(label);
+}
+
+char *
+gaim_plugin_pref_get_label(GaimPluginPref *pref) {
+	g_return_val_if_fail(pref, NULL);
+
+	return pref->label;
+}
+
+void
+gaim_plugin_pref_set_bounds(GaimPluginPref *pref, int min, int max) {
+	int tmp;
+
+	g_return_if_fail(pref);
+	g_return_if_fail(pref->name);
+
+	if(gaim_prefs_get_type(pref->name) != GAIM_PREF_INT) {
+		gaim_debug(GAIM_DEBUG_INFO, "pluginpref",
+				"gaim_plugin_pref_set_bounds: %s is not an integer pref\n",
+				pref->name);
+		return;
+	}
+		
+	if(min > max) {
+		tmp = min;
+		min = max;
+		max = tmp;
+	}
+
+	pref->min = min;
+	pref->max = max;
+}
+
+void gaim_plugin_pref_get_bounds(GaimPluginPref *pref, int *min, int *max) {
+	g_return_if_fail(pref);
+	g_return_if_fail(pref->name);
+
+	if(gaim_prefs_get_type(pref->name) != GAIM_PREF_INT) {
+		gaim_debug(GAIM_DEBUG_INFO, "pluginpref",
+				"gaim_plugin_pref_get_bounds: %s is not an integer pref\n",
+				pref->name);
+		return;
+	}
+
+	*min = pref->min;
+	*max = pref->max;
+}
+
+void
+gaim_plugin_pref_set_type(GaimPluginPref *pref, GaimPluginPrefType type) {
+	g_return_if_fail(pref);
+
+	pref->type = type;
+}
+
+GaimPluginPrefType
+gaim_plugin_pref_get_type(GaimPluginPref *pref) {
+	g_return_val_if_fail(pref, GAIM_PLUGIN_PREF_NONE);
+
+	return pref->type;
+}
+
+void
+gaim_plugin_pref_add_choice(GaimPluginPref *pref, char *label, gpointer choice) {
+	g_return_if_fail(pref);
+	g_return_if_fail(label);
+	g_return_if_fail(choice);
+
+	pref->choices = g_list_append(pref->choices, label);
+	pref->choices = g_list_append(pref->choices, choice);
+}
+
+gpointer
+gaim_plugin_pref_get_choice(GaimPluginPref *pref, unsigned int index) {
+	g_return_val_if_fail(pref, NULL);
+
+	if(index > g_list_length(pref->choices))
+		return NULL;
+
+	return g_list_nth_data(pref->choices, index);
+}
+
+GList *
+gaim_plugin_pref_get_choices(GaimPluginPref *pref) {
+	g_return_val_if_fail(pref, NULL);
+
+	return pref->choices;
+}
+
+void
+gaim_plugin_pref_set_max_length(GaimPluginPref *pref, unsigned int max_length) {
+	g_return_if_fail(pref);
+
+	pref->max_length = max_length;
+}
+
+unsigned int
+gaim_plugin_pref_get_max_length(GaimPluginPref *pref) {
+	g_return_val_if_fail(pref, 0);
+
+	return pref->max_length;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pluginpref.h	Mon Apr 19 21:12:45 2004 +0000
@@ -0,0 +1,223 @@
+/**
+ * @file pluginpref.h Plugin Preferences API
+ * @ingroup core
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef _PLUGIN_PREF_H_
+#define _PLUGIN_PREF_H_
+
+typedef struct _GaimPluginPrefFrame		GaimPluginPrefFrame;
+typedef struct _GaimPluginPref			GaimPluginPref;
+
+typedef enum {
+	GAIM_PLUGIN_PREF_NONE,
+	GAIM_PLUGIN_PREF_CHOICE
+} GaimPluginPrefType;
+
+#include <glib.h>
+#include "prefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**************************************************************************/
+/** @name Plugin Preference API                                           */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Create a new plugin preference frame
+ *
+ * @return a new GaimPluginPrefFrame
+ */
+GaimPluginPrefFrame *gaim_plugin_pref_frame_new();
+
+/**
+ * Destroy a plugin preference frame
+ *
+ * @param frame The plugin frame to destroy
+ */
+void gaim_plugin_pref_frame_destroy(GaimPluginPrefFrame *frame);
+
+/**
+ * Adds a plugin preference to a plugin preference frame
+ *
+ * @param frame The plugin frame to add the preference to
+ * @param pref  The preference to add to the frame
+ */
+void gaim_plugin_pref_frame_add(GaimPluginPrefFrame *frame, GaimPluginPref *pref);
+
+/**
+ * Get the plugin preferences from a plugin preference frame
+ *
+ * @param frame The plugin frame to get the plugin preferences from
+ * @return a GList of plugin preferences
+ */
+GList *gaim_plugin_pref_frame_get_prefs(GaimPluginPrefFrame *frame);
+ 
+/**
+ * Create a new plugin preference
+ *
+ * @return a new GaimPluginPref
+ */
+GaimPluginPref *gaim_plugin_pref_new();
+
+/**
+ * Create a new plugin preference with name
+ *
+ * @param name The name of the pref
+ * @return a new GaimPluginPref
+ */
+GaimPluginPref *gaim_plugin_pref_new_with_name(char *name);
+
+/**
+ * Create a new plugin preference with label
+ *
+ * @param label The label to be displayed
+ * @return a new GaimPluginPref
+ */
+GaimPluginPref *gaim_plugin_pref_new_with_label(char *label);
+
+/**
+ * Create a new plugin preference with name and label
+ *
+ * @param name  The name of the pref
+ * @param label The label to be displayed
+ * @return a new GaimPluginPref
+ */
+GaimPluginPref *gaim_plugin_pref_new_with_name_and_label(char *name, char *label);
+
+/**
+ * Destroy a plugin preference
+ *
+ * @param pref The preference to destroy
+ */
+void gaim_plugin_pref_destroy(GaimPluginPref *pref);
+
+/**
+ * Set a plugin pref name
+ *
+ * @param pref The plugin pref
+ * @param name The name of the pref
+ */
+void gaim_plugin_pref_set_name(GaimPluginPref *pref, char *name);
+
+/**
+ * Get a plugin pref name
+ *
+ * @param pref The plugin pref
+ * @return The name of the pref
+ */
+char *gaim_plugin_pref_get_name(GaimPluginPref *pref);
+
+/**
+ * Set a plugin pref label
+ *
+ * @param pref  The plugin pref
+ * @param label The label for the plugin pref
+ */
+void gaim_plugin_pref_set_label(GaimPluginPref *pref, char *label);
+
+/**
+ * Get a plugin pref label
+ *
+ * @param pref The plugin pref
+ * @return The label for the plugin pref
+ */
+char *gaim_plugin_pref_get_label(GaimPluginPref *pref);
+
+/**
+ * Set the bounds for an integer pref
+ *
+ * @param pref The plugin pref
+ * @param min  The min value
+ * @param max  The max value
+ */
+void gaim_plugin_pref_set_bounds(GaimPluginPref *pref, int min, int max);
+
+/**
+ * Get the bounds for an integer pref
+ *
+ * @param pref The plugin pref
+ * @param min  The min value
+ * @param max  The max value
+ */
+void gaim_plugin_pref_get_bounds(GaimPluginPref *pref, int *min, int *max);
+
+/**
+ * Set the type of a plugin pref
+ *
+ * @param pref The plugin pref
+ * @param type The type
+ */
+void gaim_plugin_pref_set_type(GaimPluginPref *pref, GaimPluginPrefType type);
+
+/**
+ * Get the type of a plugin pref
+ *
+ * @param pref The plugin pref
+ * @return The type
+ */
+GaimPluginPrefType gaim_plugin_pref_get_type(GaimPluginPref *pref);
+
+/**
+ * Set the choices for a choices plugin pref
+ *
+ * @param pref  The plugin pref
+ * @param label The label for the choice
+ * @param choice  A gpointer of the choice
+ */
+void gaim_plugin_pref_add_choice(GaimPluginPref *pref, char *label, gpointer choice);
+
+/**
+ * Get the choices for a choices plugin pref
+ *
+ * @param pref The plugin pref
+ * @return GList of the choices 
+ */
+GList *gaim_plugin_pref_get_choices(GaimPluginPref *pref);
+
+/**
+ * Set the max length for a string plugin pref
+ *
+ * @param pref   The plugin pref
+ * @param length The max length of the string
+ */
+void gaim_plugin_pref_set_max_length(GaimPluginPref *pref, unsigned int max_length);
+
+/**
+ * Get the max length for a string plugin pref
+ *
+ * @param pref The plugin pref
+ * @return the max length
+ */
+unsigned int gaim_plugin_pref_get_max_length(GaimPluginPref *pref);
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PLUGIN_PREF_H_ */
--- a/src/protocols/gg/gg.c	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/protocols/gg/gg.c	Mon Apr 19 21:12:45 2004 +0000
@@ -1,6 +1,6 @@
 /*
  * gaim - Gadu-Gadu Protocol Plugin
- * $Id: gg.c 9340 2004-04-06 01:06:45Z thekingant $
+ * $Id: gg.c 9467 2004-04-19 21:12:45Z lschiere $
  *
  * Copyright (C) 2001 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
  *
@@ -1308,7 +1308,6 @@
 	0,
 	NULL,
 	NULL,
-	NULL,
 	agg_list_icon,
 	agg_list_emblems,
 	NULL,
--- a/src/protocols/irc/irc.c	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/protocols/irc/irc.c	Mon Apr 19 21:12:45 2004 +0000
@@ -539,7 +539,6 @@
 	OPT_PROTO_CHAT_TOPIC | OPT_PROTO_PASSWORD_OPTIONAL,
 	NULL,
 	NULL,
-	NULL,
 	irc_blist_icon,
 	irc_blist_emblems,
 	NULL,
--- a/src/protocols/jabber/jabber.c	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/protocols/jabber/jabber.c	Mon Apr 19 21:12:45 2004 +0000
@@ -26,6 +26,7 @@
 #include "message.h"
 #include "multi.h"
 #include "notify.h"
+#include "pluginpref.h"
 #include "prpl.h"
 #include "request.h"
 #include "server.h"
@@ -1261,12 +1262,32 @@
 	}
 }
 
+static GaimPluginPrefFrame *
+get_plugin_pref_frame(GaimPlugin *plugin) {
+	GaimPluginPrefFrame *frame;
+	GaimPluginPref *ppref;
+
+	frame = gaim_plugin_pref_frame_new();
+
+	ppref = gaim_plugin_pref_new_with_label(_("Privacy"));
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_name_and_label("/plugins/prpl/jabber/hide_os",
+													 _("Hide Operating System"));
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	return frame;
+}
+
+static GaimPluginUiInfo prefs_info = {
+	get_plugin_pref_frame
+};
+
 static GaimPluginProtocolInfo prpl_info =
 {
 	OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME,
 	NULL,
 	NULL,
-	NULL,
 	jabber_list_icon,
 	jabber_list_emblems,
 	jabber_status_text,
@@ -1348,7 +1369,8 @@
 	NULL,                                             /**< destroy        */
 
 	NULL,                                             /**< ui_info        */
-	&prpl_info                                        /**< extra_info     */
+	&prpl_info,                                        /**< extra_info     */
+	&prefs_info                                        /**< prefs_info      */
 };
 
 static void
@@ -1356,7 +1378,6 @@
 {
 	GaimAccountUserSplit *split;
 	GaimAccountOption *option;
-	struct proto_pref *ppref;
 
 	split = gaim_account_user_split_new(_("Server"), "jabber.org", '@');
 	prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
@@ -1392,16 +1413,6 @@
 
 	gaim_prefs_add_none("/plugins/prpl/jabber");
 	gaim_prefs_add_bool("/plugins/prpl/jabber/hide_os", FALSE);
-
-	ppref = g_new0(struct proto_pref, 1);
-	ppref->key = NULL;
-	ppref->label = _("Privacy");
-	prpl_info.protocol_prefs = g_list_append(prpl_info.protocol_prefs, ppref);
-
-	ppref = g_new0(struct proto_pref, 1);
-	ppref->key = "/plugins/prpl/jabber/hide_os";
-	ppref->label = _("Hide Operating System");
-	prpl_info.protocol_prefs = g_list_append(prpl_info.protocol_prefs, ppref);
 }
 
 GAIM_INIT_PLUGIN(jabber, init_plugin, info);
--- a/src/protocols/msn/msn.c	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/protocols/msn/msn.c	Mon Apr 19 21:12:45 2004 +0000
@@ -25,6 +25,7 @@
 #include "accountopt.h"
 #include "msg.h"
 #include "page.h"
+#include "pluginpref.h"
 #include "prefs.h"
 #include "session.h"
 #include "state.h"
@@ -1610,12 +1611,38 @@
 	g_free(url);
 }
 
+static GaimPluginPrefFrame *
+get_plugin_pref_frame(GaimPlugin *plugin) {
+	GaimPluginPrefFrame *frame;
+	GaimPluginPref *ppref;
+
+	frame = gaim_plugin_pref_frame_new();
+
+	ppref = gaim_plugin_pref_new_with_label(_("Conversations"));
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_name_and_label(
+								"/plugins/prpl/msn/conv_close_notice",
+								_("Display conversation closed notices"));
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	ppref = gaim_plugin_pref_new_with_name_and_label(
+								"/plugins/prpl/msn/conv_timeout_notice",
+								_("Display timeout notices"));
+	gaim_plugin_pref_frame_add(frame, ppref);
+
+	return frame;
+}
+
+static GaimPluginUiInfo prefs_info = {
+	get_plugin_pref_frame
+};
+
 static GaimPluginProtocolInfo prpl_info =
 {
 	OPT_PROTO_MAIL_CHECK /* | OPT_PROTO_BUDDY_ICON */,
 	NULL,
 	NULL,
-	NULL,
 	msn_list_icon,
 	msn_list_emblems,
 	msn_status_text,
@@ -1697,14 +1724,14 @@
 	NULL,                                             /**< destroy        */
 
 	NULL,                                             /**< ui_info        */
-	&prpl_info                                        /**< extra_info     */
+	&prpl_info,                                        /**< extra_info     */
+	&prefs_info                                        /**< prefs_info     */
 };
 
 static void
 init_plugin(GaimPlugin *plugin)
 {
 	GaimAccountOption *option;
-	struct proto_pref *ppref;
 
 	option = gaim_account_option_string_new(_("Login server"), "server",
 											MSN_SERVER);
@@ -1725,21 +1752,6 @@
 	gaim_prefs_add_none("/plugins/prpl/msn");
 	gaim_prefs_add_bool("/plugins/prpl/msn/conv_close_notice",   TRUE);
 	gaim_prefs_add_bool("/plugins/prpl/msn/conv_timeout_notice", TRUE);
-
-	ppref = g_new0(struct proto_pref, 1);
-	ppref->key = NULL;
-	ppref->label = _("Conversations");
-	prpl_info.protocol_prefs = g_list_append(prpl_info.protocol_prefs, ppref);
-
-	ppref = g_new0(struct proto_pref, 1);
-	ppref->key = "/plugins/prpl/msn/conv_close_notice";
-	ppref->label = _("Display conversation closed notices");
-	prpl_info.protocol_prefs = g_list_append(prpl_info.protocol_prefs, ppref);
-
-	ppref = g_new0(struct proto_pref, 1);
-	ppref->key = "/plugins/prpl/msn/conv_timeout_notice";
-	ppref->label = _("Display timeout notices");
-	prpl_info.protocol_prefs = g_list_append(prpl_info.protocol_prefs, ppref);
 }
 
 GAIM_INIT_PLUGIN(msn, init_plugin, info);
--- a/src/protocols/napster/napster.c	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/protocols/napster/napster.c	Mon Apr 19 21:12:45 2004 +0000
@@ -566,7 +566,6 @@
 	OPT_PROTO_CHAT_TOPIC,
 	NULL,
 	NULL,
-	NULL,
 	nap_list_icon,
 	nap_list_emblems,
 	NULL,
--- a/src/protocols/novell/novell.c	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/protocols/novell/novell.c	Mon Apr 19 21:12:45 2004 +0000
@@ -2339,7 +2339,6 @@
 	0,
 	NULL,
 	NULL,
-	NULL,
 	novell_list_icon,
 	novell_list_emblems,
 	novell_status_text,
--- a/src/protocols/oscar/oscar.c	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/protocols/oscar/oscar.c	Mon Apr 19 21:12:45 2004 +0000
@@ -6917,7 +6917,6 @@
 	OPT_PROTO_MAIL_CHECK | OPT_PROTO_BUDDY_ICON | OPT_PROTO_IM_IMAGE,
 	NULL,
 	NULL,
-	NULL,
 	oscar_list_icon,
 	oscar_list_emblems,
 	oscar_status_text,
--- a/src/protocols/toc/toc.c	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/protocols/toc/toc.c	Mon Apr 19 21:12:45 2004 +0000
@@ -2094,7 +2094,6 @@
 	OPT_PROTO_CORRECT_TIME,
 	NULL,
 	NULL,
-	NULL,
 	toc_list_icon,
 	toc_list_emblems,
 	NULL,
--- a/src/protocols/yahoo/yahoo.c	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/protocols/yahoo/yahoo.c	Mon Apr 19 21:12:45 2004 +0000
@@ -3216,7 +3216,6 @@
 	OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC,
 	NULL, /* user_splits */
 	NULL, /* protocol_options */
-	NULL, /* protocol_prefs */
 	yahoo_list_icon,
 	yahoo_list_emblems,
 	yahoo_status_text,
--- a/src/protocols/zephyr/zephyr.c	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/protocols/zephyr/zephyr.c	Mon Apr 19 21:12:45 2004 +0000
@@ -1300,7 +1300,6 @@
 	OPT_PROTO_CHAT_TOPIC | OPT_PROTO_NO_PASSWORD,
 	NULL,
 	NULL,
-	NULL,
 	zephyr_list_icon,
 	NULL,
 	NULL,
--- a/src/prpl.h	Mon Apr 19 20:30:56 2004 +0000
+++ b/src/prpl.h	Mon Apr 19 21:12:45 2004 +0000
@@ -209,7 +209,6 @@
 
 	GList *user_splits;      /* A GList of GaimAccountUserSplit */
 	GList *protocol_options; /* A GList of GaimAccountOption    */
-	GList *protocol_prefs;   /* protocol specific options */
 
 	/**
 	 * Returns the base icon name for the given buddy and account.