Merged soc.2013.gobjectification branch soc.2013.gobjectification.plugins

Thu, 24 Oct 2013 23:56:44 +0530

author
Ankit Vani <a@nevitus.org>
date
Thu, 24 Oct 2013 23:56:44 +0530
branch
soc.2013.gobjectification.plugins
changeset 36929
eed15b8d51a1
parent 36928
ae920fa34143 (current diff)
parent 35046
01aafc96f36e (diff)
child 36930
c1b0e75051e3

Merged soc.2013.gobjectification branch

ChangeLog.API file | annotate | diff | comparison | revisions
finch/gntplugin.c file | annotate | diff | comparison | revisions
finch/plugins/gnttinyurl.c file | annotate | diff | comparison | revisions
libpurple/plugins.c file | annotate | diff | comparison | revisions
libpurple/plugins.h file | annotate | diff | comparison | revisions
libpurple/plugins/autoaccept.c file | annotate | diff | comparison | revisions
libpurple/plugins/joinpart.c file | annotate | diff | comparison | revisions
libpurple/plugins/log_reader.c file | annotate | diff | comparison | revisions
libpurple/plugins/newline.c file | annotate | diff | comparison | revisions
libpurple/plugins/offlinemsg.c file | annotate | diff | comparison | revisions
libpurple/plugins/perl/perl.c file | annotate | diff | comparison | revisions
libpurple/plugins/pluginpref_example.c file | annotate | diff | comparison | revisions
libpurple/plugins/psychic.c file | annotate | diff | comparison | revisions
libpurple/plugins/statenotify.c file | annotate | diff | comparison | revisions
libpurple/util.c file | annotate | diff | comparison | revisions
libpurple/util.h file | annotate | diff | comparison | revisions
pidgin/gtkplugin.c file | annotate | diff | comparison | revisions
pidgin/gtkplugin.h file | annotate | diff | comparison | revisions
pidgin/plugins/extplacement.c file | annotate | diff | comparison | revisions
pidgin/plugins/markerline.c file | annotate | diff | comparison | revisions
--- a/ChangeLog.API	Thu Oct 24 18:21:35 2013 +0530
+++ b/ChangeLog.API	Thu Oct 24 23:56:44 2013 +0530
@@ -86,6 +86,7 @@
 		* purple_plugin_info_get_license_text
 		* purple_plugin_info_get_license_url
 		* purple_plugin_info_get_pref_frame_callback
+		* purple_plugin_info_get_pref_request_callback
 		* purple_plugin_info_get_ui_data
 		* purple_plugin_info_set_ui_data
 		* purple_plugin_register_type
--- a/finch/gntplugin.c	Thu Oct 24 18:21:35 2013 +0530
+++ b/finch/gntplugin.c	Thu Oct 24 23:56:44 2013 +0530
@@ -65,7 +65,20 @@
 	GntWidget *conf;
 } plugins;
 
-static GHashTable *confwins;
+typedef struct
+{
+	enum
+	{
+		FINCH_PLUGIN_UI_DATA_TYPE_WINDOW,
+		FINCH_PLUGIN_UI_DATA_TYPE_REQUEST
+	} type;
+
+	union
+	{
+		GntWidget *window;
+		gpointer request_handle;
+	} u;
+} FinchPluginUiData;
 
 static GntWidget *process_pref_frame(PurplePluginPrefFrame *frame);
 
@@ -167,26 +180,66 @@
 	g_list_free(list);
 }
 
+static gboolean
+has_prefs(PurplePlugin *plugin)
+{
+	PurplePluginInfo *info = purple_plugin_get_info(plugin);
+	FinchPluginInfoPrivate *priv = NULL;
+	gboolean ret;
+
+	g_return_val_if_fail(plugin != NULL, FALSE);
+
+	if (!purple_plugin_is_loaded(plugin))
+		return FALSE;
+
+	if (FINCH_IS_PLUGIN_INFO(info))
+		priv = FINCH_PLUGIN_INFO_GET_PRIVATE(info);
+
+	ret = ((priv && priv->get_pref_frame) ||
+			purple_plugin_info_get_pref_frame_callback(info) ||
+			purple_plugin_info_get_pref_request_callback(info));
+
+	return ret;
+}
+
 static void
 decide_conf_button(PurplePlugin *plugin)
 {
-	gboolean visible = FALSE;
-	PurplePluginInfo *info = purple_plugin_get_info(plugin);
+	if (has_prefs(plugin))
+		gnt_widget_set_visible(plugins.conf, TRUE);
+	else
+		gnt_widget_set_visible(plugins.conf, FALSE);
+
+	gnt_box_readjust(GNT_BOX(plugins.window));
+	gnt_widget_draw(plugins.window);
+}
 
-	if (purple_plugin_is_loaded(plugin)) {
-		FinchPluginInfoPrivate *priv = NULL;
-		if (FINCH_IS_PLUGIN_INFO(info))
-			priv = FINCH_PLUGIN_INFO_GET_PRIVATE(info);
+static void
+finch_plugin_pref_close(PurplePlugin *plugin)
+{
+	PurplePluginInfo *info;
+	FinchPluginUiData *ui_data;
+
+	g_return_if_fail(plugin != NULL);
 
-		if ((priv && priv->get_pref_frame) ||
-			(purple_plugin_info_get_pref_frame_callback(info))) {
-			visible = TRUE;
-		}
+	info = purple_plugin_get_info(plugin);
+	ui_data = purple_plugin_info_get_ui_data(info);
+
+	if (!ui_data)
+		return;
+
+	if (ui_data->type == FINCH_PLUGIN_UI_DATA_TYPE_REQUEST) {
+		purple_request_close(PURPLE_REQUEST_FIELDS,
+			ui_data->u.request_handle);
+		return;
 	}
 
-	gnt_widget_set_visible(plugins.conf, visible);
-	gnt_box_readjust(GNT_BOX(plugins.window));
-	gnt_widget_draw(plugins.window);
+	g_return_if_fail(ui_data->type == FINCH_PLUGIN_UI_DATA_TYPE_WINDOW);
+
+	gnt_widget_destroy(ui_data->u.window);
+
+	g_free(ui_data);
+	purple_plugin_info_set_ui_data(info, NULL);
 }
 
 static void
@@ -204,8 +257,6 @@
 	}
 	else
 	{
-		GntWidget *win;
-
 		if (!purple_plugin_unload(plugin, &error)) {
 			purple_notify_error(NULL, _("ERROR"), _("unloading plugin failed"), error->message, NULL);
 			purple_plugin_disable(plugin);
@@ -213,10 +264,7 @@
 			g_error_free(error);
 		}
 
-		if (confwins && (win = g_hash_table_lookup(confwins, plugin)) != NULL)
-		{
-			gnt_widget_destroy(win);
-		}
+		finch_plugin_pref_close(plugin);
 	}
 	decide_conf_button(plugin);
 	finch_plugins_save_loaded();
@@ -309,15 +357,13 @@
 }
 
 static void
-confwin_init(void)
+remove_confwin(GntWidget *window, gpointer _plugin)
 {
-	confwins = g_hash_table_new(g_direct_hash, g_direct_equal);
-}
+	PurplePlugin *plugin = _plugin;
+	PurplePluginInfo *info = purple_plugin_get_info(plugin);
 
-static void
-remove_confwin(GntWidget *window, gpointer plugin)
-{
-	g_hash_table_remove(confwins, plugin);
+	g_free(info->ui_data);
+	purple_plugin_info_set_ui_data(info, NULL);
 }
 
 static void
@@ -326,6 +372,7 @@
 	PurplePlugin *plugin;
 	PurplePluginInfo *info;
 	FinchPluginInfoPrivate *priv = NULL;
+	FinchPluginUiData *ui_data;
 
 	g_return_if_fail(plugins.tree != NULL);
 
@@ -337,10 +384,13 @@
 		return;
 	}
 
-	if (confwins && g_hash_table_lookup(confwins, plugin))
+	info = purple_plugin_get_info(plugin);
+
+	if (purple_plugin_info_get_ui_data(info))
 		return;
+	ui_data = g_new0(FinchPluginUiData, 1);
+	purple_plugin_info_set_ui_data(info, ui_data);
 
-	info = purple_plugin_get_info(plugin);
 	if (FINCH_IS_PLUGIN_INFO(info))
 		priv = FINCH_PLUGIN_INFO_GET_PRIVATE(info);
 
@@ -368,23 +418,35 @@
 
 		gnt_widget_show(window);
 
-		if (confwins == NULL)
-			confwin_init();
-		g_hash_table_insert(confwins, plugin, window);
+		ui_data->type = FINCH_PLUGIN_UI_DATA_TYPE_WINDOW;
+		ui_data->u.window = window;
+	}
+	else if (purple_plugin_info_get_pref_request_callback(info))
+	{
+		PurplePluginPrefRequestCallback get_pref_request = purple_plugin_info_get_pref_request_callback(info);
+		gpointer handle;
+
+		ui_data->type = FINCH_PLUGIN_UI_DATA_TYPE_REQUEST;
+		ui_data->u.request_handle = handle = get_pref_request(plugin);
+		purple_request_add_close_notify(handle,
+			purple_callback_set_zero, &info->ui_data);
+		purple_request_add_close_notify(handle, g_free, ui_data);
 	}
 	else if (purple_plugin_info_get_pref_frame_callback(info))
 	{
 		PurplePluginPrefFrameCallback get_pref_frame = purple_plugin_info_get_pref_frame_callback(info);
 		GntWidget *win = process_pref_frame(get_pref_frame(plugin));
-		if (confwins == NULL)
-			confwin_init();
 		g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(remove_confwin), plugin);
-		g_hash_table_insert(confwins, plugin, win);
+
+		ui_data->type = FINCH_PLUGIN_UI_DATA_TYPE_WINDOW;
+		ui_data->u.window = win;
 	}
 	else
 	{
-		purple_notify_info(plugin, _("Error"),
-			_("No configuration options for this plugin."), NULL, NULL);
+		purple_notify_info(plugin, _("Error"), _("No configuration "
+			"options for this plugin."), NULL, NULL);
+		g_free(ui_data);
+		purple_plugin_info_set_ui_data(info, NULL);
 	}
 }
 
--- a/libpurple/plugins.c	Thu Oct 24 18:21:35 2013 +0530
+++ b/libpurple/plugins.c	Thu Oct 24 23:56:44 2013 +0530
@@ -48,6 +48,9 @@
 	/** Callback that returns a preferences frame for a plugin */
 	PurplePluginPrefFrameCallback get_pref_frame;
 
+	/** Callback that returns a preferences request handle for a plugin */
+	PurplePluginPrefRequestCallback get_pref_request;
+
 	/** TRUE if a plugin has been unloaded at least once. Auto-load
 	 *  plugins that have been unloaded once will not be auto-loaded again. */
 	gboolean unloaded;
@@ -59,6 +62,7 @@
 	PROP_UI_REQUIREMENT,
 	PROP_GET_ACTIONS,
 	PROP_PREFERENCES_FRAME,
+	PROP_PREFERENCES_REQUEST,
 	PROP_FLAGS,
 	PROP_LAST
 };
@@ -377,6 +381,9 @@
 		case PROP_PREFERENCES_FRAME:
 			priv->get_pref_frame = g_value_get_pointer(value);
 			break;
+		case PROP_PREFERENCES_REQUEST:
+			priv->get_pref_request = g_value_get_pointer(value);
+			break;
 		case PROP_FLAGS:
 			priv->flags = g_value_get_flags(value);
 			break;
@@ -402,6 +409,10 @@
 			g_value_set_pointer(value,
 					purple_plugin_info_get_pref_frame_callback(info));
 			break;
+		case PROP_PREFERENCES_REQUEST:
+			g_value_set_pointer(value,
+					purple_plugin_info_get_pref_request_callback(info));
+			break;
 		case PROP_FLAGS:
 			g_value_set_flags(value, purple_plugin_info_get_flags(info));
 			break;
@@ -496,6 +507,12 @@
 		                  _("The callback that returns the preferences frame"),
 		                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
+	g_object_class_install_property(obj_class, PROP_PREFERENCES_REQUEST,
+		g_param_spec_pointer("preferences-request",
+		                  _("Preferences request callback"),
+		                  _("Callback that returns preferences request handle"),
+		                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
 	g_object_class_install_property(obj_class, PROP_FLAGS,
 		g_param_spec_flags("flags",
 		                  _("Plugin flags"),
@@ -752,6 +769,16 @@
 	return priv->get_pref_frame;
 }
 
+PurplePluginPrefRequestCallback
+purple_plugin_info_get_pref_request_callback(const PurplePluginInfo *info)
+{
+	PurplePluginInfoPrivate *priv = PURPLE_PLUGIN_INFO_GET_PRIVATE(info);
+
+	g_return_val_if_fail(priv != NULL, NULL);
+
+	return priv->get_pref_request;
+}
+
 PurplePluginInfoFlags
 purple_plugin_info_get_flags(const PurplePluginInfo *info)
 {
--- a/libpurple/plugins.h	Thu Oct 24 18:21:35 2013 +0530
+++ b/libpurple/plugins.h	Thu Oct 24 23:56:44 2013 +0530
@@ -98,6 +98,7 @@
 typedef void (*PurplePluginActionCallback)(PurplePluginAction *);
 typedef GList *(*PurplePluginGetActionsCallback)(PurplePlugin *);
 typedef PurplePluginPrefFrame *(*PurplePluginPrefFrameCallback)(PurplePlugin *);
+typedef gpointer (*PurplePluginPrefRequestCallback)(PurplePlugin *);
 
 /**
  * Flags that can be used to treat plugins differently.
@@ -500,35 +501,37 @@
  *
  * All properties except "id" and "purple-abi" are optional.
  *
- * Valid property names are:                                                 \n
- * "id"                 (string) The ID of the plugin.                       \n
- * "name"               (string) The translated name of the plugin.          \n
- * "version"            (string) Version of the plugin.                      \n
- * "category"           (string) Primary category of the plugin.             \n
- * "summary"            (string) Brief summary of the plugin.                \n
- * "description"        (string) Full description of the plugin.             \n
- * "authors"            (const gchar * const *) A NULL-terminated list of
- *                               plugin authors.
- *                               format: First Last <user@domain.com>        \n
- * "website"            (string) Website of the plugin.                      \n
- * "icon"               (string) Path to a plugin's icon.                    \n
- * "license-id"         (string) Short name of the plugin's license. This
+ * Valid property names are:                                                  \n
+ * "id"                  (string) The ID of the plugin.                       \n
+ * "name"                (string) The translated name of the plugin.          \n
+ * "version"             (string) Version of the plugin.                      \n
+ * "category"            (string) Primary category of the plugin.             \n
+ * "summary"             (string) Brief summary of the plugin.                \n
+ * "description"         (string) Full description of the plugin.             \n
+ * "authors"             (const gchar * const *) A NULL-terminated list of
+ *                                plugin authors.
+ *                                format: First Last <user@domain.com>        \n
+ * "website"             (string) Website of the plugin.                      \n
+ * "icon"                (string) Path to a plugin's icon.                    \n
+ * "license-id"          (string) Short name of the plugin's license. This
  *                        should either be an identifier of the license from
  *                        http://dep.debian.net/deps/dep5/#license-specification
- *                        or "Other" for custom licenses.                    \n
- * "license-text"       (string) The text of the plugin's license, if
- *                               unlisted on DEP5.                           \n
- * "license-url"        (string) The plugin's license URL, if unlisted on
- *                               DEP5.                                       \n
- * "dependencies"       (const gchar * const *) A NULL-terminated list of
- *                               plugin IDs required by the plugin.          \n
- * "abi-version"        (guint32) The ABI version required by the plugin.    \n
- * "get-actions"        (PurplePluginGetActionsCallback) Callback that
- *                               returns a list of actions the plugin can
- *                               perform.                                    \n
- * "preferences-frame"  (PurplePluginPrefFrameCallback) Callback that returns
- *                               a preferences frame for the plugin.
- * "flags"              (PurplePluginInfoFlags) The flags for a plugin.      \n
+ *                        or "Other" for custom licenses.                     \n
+ * "license-text"        (string) The text of the plugin's license, if
+ *                                unlisted on DEP5.                           \n
+ * "license-url"         (string) The plugin's license URL, if unlisted on
+ *                                DEP5.                                       \n
+ * "dependencies"        (const gchar * const *) A NULL-terminated list of
+ *                                plugin IDs required by the plugin.          \n
+ * "abi-version"         (guint32) The ABI version required by the plugin.    \n
+ * "get-actions"         (PurplePluginGetActionsCallback) Callback that
+ *                                returns a list of actions the plugin can
+ *                                perform.                                    \n
+ * "preferences-frame"   (PurplePluginPrefFrameCallback) Callback that returns
+ *                                a preferences frame for the plugin.
+ * "preferences-request" (PurplePluginPrefRequestCallback) Callback that returns
+ *                                a preferences request handle for the plugin.
+ * "flags"               (PurplePluginInfoFlags) The flags for a plugin.      \n
  *
  * @param first_property  The first property name
  * @param ...  The value of the first property, followed optionally by more
@@ -693,6 +696,17 @@
 purple_plugin_info_get_pref_frame_callback(const PurplePluginInfo *info);
 
 /**
+ * Returns the callback that retrieves the preferences request handle for a
+ * plugin.
+ *
+ * @param info The plugin info to get the callback from.
+ *
+ * @return The callback that returns the preferences request handle.
+ */
+PurplePluginPrefRequestCallback
+purple_plugin_info_get_pref_request_callback(const PurplePluginInfo *info);
+
+/**
  * Returns the plugin's flags.
  *
  * @param info The plugin's info instance.
--- a/libpurple/plugins/perl/perl.c	Thu Oct 24 18:21:35 2013 +0530
+++ b/libpurple/plugins/perl/perl.c	Thu Oct 24 23:56:44 2013 +0530
@@ -117,6 +117,8 @@
 static PurplePluginUiInfo ui_info =
 {
 	purple_perl_get_plugin_frame,
+	NULL,
+
 	/* Padding */
 	NULL,
 	NULL,
--- a/libpurple/util.c	Thu Oct 24 18:21:35 2013 +0530
+++ b/libpurple/util.c	Thu Oct 24 23:56:44 2013 +0530
@@ -4743,6 +4743,15 @@
 			(tmp >> 16) & 0xFFFF, g_random_int());
 }
 
+void purple_callback_set_zero(gpointer data)
+{
+	gpointer *ptr = data;
+
+	g_return_if_fail(ptr != NULL);
+
+	*ptr = NULL;
+}
+
 GValue *
 purple_value_new(GType type)
 {
--- a/libpurple/util.h	Thu Oct 24 18:21:35 2013 +0530
+++ b/libpurple/util.h	Thu Oct 24 23:56:44 2013 +0530
@@ -1432,6 +1432,15 @@
 gchar *purple_uuid_random(void);
 
 /**
+ * Sets given pointer to NULL.
+ *
+ * Function designed to be used as a GDestroyNotify callback.
+ *
+ * @param data A pointer to variable, which should be set to NULL.
+ */
+void purple_callback_set_zero(gpointer data);
+
+/**
  * Creates a new GValue of the specified type.
  *
  * @param type  The type of data to be held by the GValue
--- a/pidgin/gtkplugin.c	Thu Oct 24 18:21:35 2013 +0530
+++ b/pidgin/gtkplugin.c	Thu Oct 24 23:56:44 2013 +0530
@@ -54,6 +54,26 @@
 	PROP_LAST
 };
 
+typedef struct
+{
+	enum
+	{
+		PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME,
+		PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST
+	} type;
+
+	union
+	{
+		struct
+		{
+			GtkWidget *dialog;
+			PurplePluginPrefFrame *pref_frame;
+		} frame;
+
+		gpointer request_handle;
+	} u;
+} PidginPluginUiData;
+
 static void plugin_toggled_stage_two(PurplePlugin *plug, GtkTreeModel *model,
                                   GtkTreeIter *iter, GError *error, gboolean unload);
 
@@ -69,7 +89,6 @@
 static GtkLabel *plugin_filename = NULL;
 
 static GtkWidget *pref_button = NULL;
-static GHashTable *plugin_pref_dialogs = NULL;
 
 /* Set method for GObject properties */
 static void
@@ -162,8 +181,31 @@
 	return PIDGIN_PLUGIN_INFO(info);
 }
 
-GtkWidget *
-pidgin_plugin_get_config_frame(PurplePlugin *plugin)
+static gboolean
+pidgin_plugin_has_prefs(PurplePlugin *plugin)
+{
+	PurplePluginInfo *info = purple_plugin_get_info(plugin);
+	PidginPluginInfoPrivate *priv = NULL;
+	gboolean ret;
+
+	g_return_val_if_fail(plugin != NULL, FALSE);
+
+	if (!purple_plugin_is_loaded(plugin))
+		return FALSE;
+
+	if (PIDGIN_IS_PLUGIN_INFO(info))
+		priv = PIDGIN_PLUGIN_INFO_GET_PRIVATE(info);
+
+	ret = ((priv && priv->get_config_frame) ||
+			purple_plugin_info_get_pref_frame_callback(info) ||
+			purple_plugin_info_get_pref_request_callback(info));
+
+	return ret;
+}
+
+static GtkWidget *
+pidgin_plugin_get_config_frame(PurplePlugin *plugin,
+	PurplePluginPrefFrame **purple_pref_frame)
 {
 	GtkWidget *config = NULL;
 	PurplePluginInfo *info;
@@ -175,20 +217,10 @@
 	if (PIDGIN_IS_PLUGIN_INFO(info))
 		priv = PIDGIN_PLUGIN_INFO_GET_PRIVATE(info);
 
-	if (priv && priv->get_config_frame)
-	{
+	if (priv)
 		config = priv->get_config_frame(plugin);
 
-		if (purple_plugin_info_get_pref_frame_callback(info))
-		{
-			purple_debug_warning("gtkplugin",
-				"Plugin %s contains both, ui_info and "
-				"prefs_info preferences; prefs_info will be "
-				"ignored.",
-				purple_plugin_info_get_name(info));
-		}
-	}
-	else if (purple_plugin_info_get_pref_frame_callback(info))
+	if (!config && purple_plugin_info_get_pref_frame_callback(info))
 	{
 		PurplePluginPrefFrame *frame;
 		PurplePluginPrefFrameCallback get_pref_frame =
@@ -198,28 +230,143 @@
 
 		config = pidgin_plugin_pref_create_frame(frame);
 
-		purple_plugin_info_set_ui_data(info, frame);
+		*purple_pref_frame = frame;
 	}
 
 	return config;
 }
 
-static gboolean
-pidgin_plugin_has_config_frame(PurplePlugin *plugin)
+static void
+pref_dialog_close(PurplePlugin *plugin)
 {
-	PurplePluginInfo *info = purple_plugin_get_info(plugin);
+	PurplePluginInfo *info;
+	PidginPluginUiData *ui_data;
+
+	g_return_if_fail(plugin != NULL);
+
+	info = purple_plugin_get_info(plugin);
+
+	ui_data = purple_plugin_info_get_ui_data(info);
+	if (ui_data == NULL)
+		return;
+
+	if (ui_data->type == PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST) {
+		purple_request_close(PURPLE_REQUEST_FIELDS,
+			ui_data->u.request_handle);
+		return;
+	}
+
+	g_return_if_fail(ui_data->type == PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME);
+
+	gtk_widget_destroy(ui_data->u.frame.dialog);
+
+	if (ui_data->u.frame.pref_frame)
+		purple_plugin_pref_frame_destroy(ui_data->u.frame.pref_frame);
+
+	g_free(ui_data);
+	purple_plugin_info_set_ui_data(info, NULL);
+}
+
+
+static void
+pref_dialog_response_cb(GtkWidget *dialog, int response, PurplePlugin *plugin)
+{
+	if (response == GTK_RESPONSE_CLOSE ||
+		response == GTK_RESPONSE_DELETE_EVENT)
+	{
+		pref_dialog_close(plugin);
+	}
+}
+
+static void
+pidgin_plugin_open_config(PurplePlugin *plugin, GtkWindow *parent)
+{
+	PurplePluginInfo *info;
 	PidginPluginInfoPrivate *priv = NULL;
-	gboolean ret;
+	PidginPluginUiData *ui_data;
+	PurplePluginPrefFrameCallback get_pref_frame;
+	PurplePluginPrefRequestCallback get_pref_request;
+	PidginPluginConfigFrame get_pidgin_frame = NULL;
+	gint prefs_count;
+
+	g_return_if_fail(plugin != NULL);
 
-	g_return_val_if_fail(plugin != NULL, FALSE);
+	info = purple_plugin_get_info(plugin);
+
+	if (!pidgin_plugin_has_prefs(plugin)) {
+		purple_debug_warning("gtkplugin", "Plugin has no prefs");
+		return;
+	}
+
+	if (purple_plugin_info_get_ui_data(info))
+		return;
 
 	if (PIDGIN_IS_PLUGIN_INFO(info))
 		priv = PIDGIN_PLUGIN_INFO_GET_PRIVATE(info);
 
-	ret = ((priv && priv->get_config_frame) ||
-			purple_plugin_info_get_pref_frame_callback(info));
+	get_pref_frame = purple_plugin_info_get_pref_frame_callback(info);
+	get_pref_request = purple_plugin_info_get_pref_request_callback(info);
+
+	if (priv)
+		get_pidgin_frame = priv->get_config_frame;
+
+	prefs_count = 0;
+	if (get_pref_frame)
+		prefs_count++;
+	if (get_pref_request)
+		prefs_count++;
+	if (get_pidgin_frame)
+		prefs_count++;
+
+	if (prefs_count > 1) {
+		purple_debug_warning("gtkplugin", "Plugin %s contains more than"
+			" one prefs callback, some will be ignored.",
+			purple_plugin_info_get_name(info));
+	}
+	g_return_if_fail(prefs_count > 0);
+
+	ui_data = g_new0(PidginPluginUiData, 1);
+	purple_plugin_info_set_ui_data(info, ui_data);
 
-	return ret;
+	/* Priority: pidgin frame > purple request > purple frame
+	 * Purple frame could be replaced with purple request some day.
+	 */
+	if (get_pref_request && !get_pidgin_frame) {
+		ui_data->type = PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST;
+		ui_data->u.request_handle = get_pref_request(plugin);
+		purple_request_add_close_notify(ui_data->u.request_handle,
+			purple_callback_set_zero, &info->ui_data);
+		purple_request_add_close_notify(ui_data->u.request_handle,
+			g_free, ui_data);
+	} else {
+		GtkWidget *box, *dialog;
+
+		ui_data->type = PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME;
+
+		box = pidgin_plugin_get_config_frame(plugin,
+			&ui_data->u.frame.pref_frame);
+		if (box == NULL) {
+			purple_debug_error("gtkplugin",
+				"Failed to display prefs frame");
+			g_free(ui_data);
+			purple_plugin_info_set_ui_data(info, NULL);
+			return;
+		}
+
+		ui_data->u.frame.dialog = dialog = gtk_dialog_new_with_buttons(
+			PIDGIN_ALERT_TITLE, parent,
+			GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE,
+			GTK_RESPONSE_CLOSE, NULL);
+
+		g_signal_connect(G_OBJECT(dialog), "response",
+			G_CALLBACK(pref_dialog_response_cb), plugin);
+		gtk_container_add(GTK_CONTAINER(
+			gtk_dialog_get_content_area(GTK_DIALOG(dialog))), box);
+		gtk_window_set_role(GTK_WINDOW(dialog), "plugin_config");
+		gtk_window_set_title(GTK_WINDOW(dialog),
+			_(purple_plugin_info_get_name(info)));
+		gtk_widget_show_all(dialog);
+	}
 }
 
 void
@@ -328,7 +475,7 @@
 				if (plug == plugin)
 				{
 					gtk_widget_set_sensitive(pref_button,
-							loaded && pidgin_plugin_has_config_frame(plug));
+						pidgin_plugin_has_prefs(plug));
 				}
 			}
 
@@ -349,29 +496,6 @@
 	plugin_loading_common(plugin, view, FALSE);
 }
 
-static void pref_dialog_response_cb(GtkWidget *d, int response, PurplePlugin *plug)
-{
-	PurplePluginInfo *info = purple_plugin_get_info(plug);
-
-	switch (response) {
-	case GTK_RESPONSE_CLOSE:
-	case GTK_RESPONSE_DELETE_EVENT:
-		g_hash_table_remove(plugin_pref_dialogs, plug);
-		if (g_hash_table_size(plugin_pref_dialogs) == 0) {
-			g_hash_table_destroy(plugin_pref_dialogs);
-			plugin_pref_dialogs = NULL;
-		}
-		gtk_widget_destroy(d);
-
-		if (purple_plugin_info_get_pref_frame_callback(info) && info->ui_data) {
-			purple_plugin_pref_frame_destroy(info->ui_data);
-			purple_plugin_info_set_ui_data(info, NULL);
-		}
-
-		break;
-	}
-}
-
 static void plugin_unload_confirm_cb(gpointer *data)
 {
 	PurplePlugin *plugin = (PurplePlugin *)data[0];
@@ -390,7 +514,6 @@
 	GtkTreePath *path = gtk_tree_path_new_from_string(pth);
 	PurplePlugin *plug;
 	GError *error = NULL;
-	GtkWidget *dialog = NULL;
 
 	gtk_tree_model_get_iter(model, iter, path);
 	gtk_tree_path_free(path);
@@ -407,9 +530,7 @@
 	}
 	else
 	{
-		if (plugin_pref_dialogs != NULL &&
-			(dialog = g_hash_table_lookup(plugin_pref_dialogs, plug)))
-			pref_dialog_response_cb(dialog, GTK_RESPONSE_DELETE_EVENT, plug);
+		pref_dialog_close(plug);
 
 		if (purple_plugin_get_dependent_plugins(plug) != NULL)
 		{
@@ -474,8 +595,7 @@
 		purple_notify_warning(NULL, NULL, _("Could not load plugin"), error->message, NULL);
 	}
 
-	gtk_widget_set_sensitive(pref_button,
-		purple_plugin_is_loaded(plug) && pidgin_plugin_has_config_frame(plug));
+	gtk_widget_set_sensitive(pref_button, pidgin_plugin_has_prefs(plug));
 
 	if (error != NULL)
 	{
@@ -616,8 +736,7 @@
 		g_free(tmp);
 	}
 
-	gtk_widget_set_sensitive(pref_button,
-		purple_plugin_is_loaded(plug) && pidgin_plugin_has_config_frame(plug));
+	gtk_widget_set_sensitive(pref_button, pidgin_plugin_has_prefs(plug));
 
 	/* Make sure the selected plugin is still visible */
 	g_idle_add(ensure_plugin_visible, sel);
@@ -627,22 +746,22 @@
 
 static void plugin_dialog_response_cb(GtkWidget *d, int response, GtkTreeSelection *sel)
 {
-	PurplePlugin *plug;
-	GtkWidget *dialog, *box;
+	PurplePlugin *plugin;
 	GtkTreeModel *model;
 	GValue val;
 	GtkTreeIter iter;
+	GList *list, *it;
 
 	switch (response) {
 	case GTK_RESPONSE_CLOSE:
 	case GTK_RESPONSE_DELETE_EVENT:
 		purple_request_close_with_handle(plugin_dialog);
 		purple_signals_disconnect_by_handle(plugin_dialog);
+		list = purple_plugins_find_all();
+		for (it = list; it; it = g_list_next(it))
+			pref_dialog_close(it->data);
+		g_list_free(list);
 		gtk_widget_destroy(d);
-		if (plugin_pref_dialogs != NULL) {
-			g_hash_table_destroy(plugin_pref_dialogs);
-			plugin_pref_dialogs = NULL;
-		}
 		plugin_dialog = NULL;
 		break;
 	case PIDGIN_RESPONSE_CONFIGURE:
@@ -650,32 +769,12 @@
 			return;
 		val.g_type = 0;
 		gtk_tree_model_get_value(model, &iter, 2, &val);
-		plug = g_value_get_pointer(&val);
-		if (plug == NULL)
-			break;
-		if (plugin_pref_dialogs != NULL &&
-			g_hash_table_lookup(plugin_pref_dialogs, plug))
-			break;
-		box = pidgin_plugin_get_config_frame(plug);
-		if (box == NULL)
+		plugin = g_value_get_pointer(&val);
+		g_value_unset(&val);
+		if (plugin == NULL)
 			break;
 
-		dialog = gtk_dialog_new_with_buttons(PIDGIN_ALERT_TITLE, GTK_WINDOW(d),
-						     GTK_DIALOG_DESTROY_WITH_PARENT,
-						     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
-						     NULL);
-		if (plugin_pref_dialogs == NULL)
-			plugin_pref_dialogs = g_hash_table_new(NULL, NULL);
-
-		g_hash_table_insert(plugin_pref_dialogs, plug, dialog);
-
-		g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(pref_dialog_response_cb), plug);
-		gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), box);
-		gtk_window_set_role(GTK_WINDOW(dialog), "plugin_config");
-		gtk_window_set_title(GTK_WINDOW(dialog),
-				_(purple_plugin_info_get_name(purple_plugin_get_info(plug))));
-		gtk_widget_show_all(dialog);
-		g_value_unset(&val);
+		pidgin_plugin_open_config(plugin, GTK_WINDOW(d));
 
 		break;
 	}
--- a/pidgin/gtkplugin.h	Thu Oct 24 18:21:35 2013 +0530
+++ b/pidgin/gtkplugin.h	Thu Oct 24 23:56:44 2013 +0530
@@ -94,17 +94,6 @@
                   G_GNUC_NULL_TERMINATED;
 
 /**
- * Returns the configuration frame widget for a GTK+ plugin, if one
- * exists.
- *
- * @param plugin The plugin.
- *
- * @return The frame, if the plugin is a GTK+ plugin and provides a
- *         configuration frame.
- */
-GtkWidget *pidgin_plugin_get_config_frame(PurplePlugin *plugin);
-
-/**
  * Saves all loaded plugins.
  */
 void pidgin_plugins_save(void);

mercurial