changeset 12927:3cc18baeaca3

[gaim-migrate @ 15280] I've added a confirmation dialog when unloading a plugin on which other plugins depend. Also, I've add plugin-load/plugin-unload signal handlers to update the dialog. This fixes problems that occur when you load a plugin with dependencies (causing the core to load additional plugins). committer: Tailor Script <tailor@pidgin.im>
author Richard Laager <rlaager@wiktel.com>
date Wed, 18 Jan 2006 18:27:06 +0000
parents 2c4f20ff387c
children 4b5822e48b53
files src/gtkplugin.c
diffstat 1 files changed, 152 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/src/gtkplugin.c	Wed Jan 18 18:21:59 2006 +0000
+++ b/src/gtkplugin.c	Wed Jan 18 18:27:06 2006 +0000
@@ -28,11 +28,15 @@
 #include "gtkpluginpref.h"
 #include "debug.h"
 #include "prefs.h"
+#include "request.h"
 
 #include <string.h>
 
 #define GAIM_RESPONSE_CONFIGURE 98121
 
+static void plugin_toggled_stage_two(GaimPlugin *plug, GtkTreeModel *model,
+                                  GtkTreeIter *iter, gboolean unload);
+
 static GtkWidget *expander = NULL;
 static GtkWidget *plugin_dialog = NULL;
 static GtkWidget *plugin_details = NULL;
@@ -153,6 +157,57 @@
 	}
 }
 
+static void plugin_loading_common(GaimPlugin *plugin, GtkTreeView *view, gboolean loaded)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model = gtk_tree_view_get_model(view);
+
+	if (gtk_tree_model_get_iter_first(model, &iter)) {
+		do {
+			GaimPlugin *plug;
+			GtkTreeSelection *sel;
+
+			gtk_tree_model_get(model, &iter, 2, &plug, -1);
+
+			if (plug != plugin)
+				continue;
+
+			gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, loaded, -1);
+
+			/* If the loaded/unloaded plugin is the selected row,
+			 * update the pref_button. */
+			sel = gtk_tree_view_get_selection(view);
+			if (gtk_tree_selection_get_selected(sel, &model, &iter))
+			{
+				gtk_tree_model_get(model, &iter, 2, &plug, -1);
+				if (plug == plugin)
+				{
+					gtk_widget_set_sensitive(pref_button,
+						loaded
+						&& ((GAIM_IS_GTK_PLUGIN(plug) && plug->info->ui_info
+							&& GAIM_GTK_PLUGIN_UI_INFO(plug)->get_config_frame)
+						 || (plug->info->prefs_info
+							&& plug->info->prefs_info->get_plugin_pref_frame)));
+				}
+			}
+
+			break;
+		} while (gtk_tree_model_iter_next(model, &iter));
+	}
+}
+
+static void plugin_load_cb(GaimPlugin *plugin, gpointer data)
+{
+	GtkTreeView *view = (GtkTreeView *)data;
+	plugin_loading_common(plugin, view, TRUE);
+}
+
+static void plugin_unload_cb(GaimPlugin *plugin, gpointer data)
+{
+	GtkTreeView *view = (GtkTreeView *)data;
+	plugin_loading_common(plugin, view, FALSE);
+}
+
 static void pref_dialog_response_cb(GtkWidget *d, int response, GaimPlugin *plug)
 {
 	switch (response) {
@@ -168,35 +223,99 @@
 	}
 }
 
-static void plugin_load (GtkCellRendererToggle *cell, gchar *pth, gpointer data)
+static void plugin_unload_confirm_cb(gpointer *data)
+{
+	GaimPlugin *plugin = (GaimPlugin *)data[0];
+	GtkTreeModel *model = (GtkTreeModel *)data[1];
+	GtkTreeIter *iter = (GtkTreeIter *)data[2];
+
+	plugin_toggled_stage_two(plugin, model, iter, TRUE);
+
+	g_free(data);
+}
+
+static void plugin_toggled(GtkCellRendererToggle *cell, gchar *pth, gpointer data)
 {
 	GtkTreeModel *model = (GtkTreeModel *)data;
-	GtkTreeIter iter;
+	GtkTreeIter *iter = g_new(GtkTreeIter, 1);
 	GtkTreePath *path = gtk_tree_path_new_from_string(pth);
 	GaimPlugin *plug;
-	gchar buf[1024];
-	gchar *name = NULL, *description = NULL;
 	GtkWidget *dialog = NULL;
-	GdkCursor *wait;
 
-	gtk_tree_model_get_iter (model, &iter, path);
-	gtk_tree_model_get (model, &iter, 2, &plug, -1);
+	gtk_tree_model_get_iter(model, iter, path);
+	gtk_tree_path_free(path);
+	gtk_tree_model_get(model, iter, 2, &plug, -1);
 
 	/* Apparently, GTK+ won't honor the sensitive flag on cell renderers for booleans. */
 	if (gaim_plugin_is_unloadable(plug))
+	{
+		g_free(iter);
 		return;
-
-	wait = gdk_cursor_new (GDK_WATCH);
-	gdk_window_set_cursor(plugin_dialog->window, wait);
-	gdk_cursor_unref(wait);
+	}
 
 	if (!gaim_plugin_is_loaded(plug))
+	{
+		GdkCursor *wait = gdk_cursor_new (GDK_WATCH);
+		gdk_window_set_cursor(plugin_dialog->window, wait);
+		gdk_cursor_unref(wait);
+
 		gaim_plugin_load(plug);
-	else {
+		plugin_toggled_stage_two(plug, model, iter, FALSE);
+
+		gdk_window_set_cursor(plugin_dialog->window, NULL);
+	}
+	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);
+
+		if (plug->dependent_plugins != NULL)
+		{
+			GString *tmp = g_string_new(_("The following plugins will be unloaded."));
+			GList *l;
+			gpointer *cb_data;
+
+			for (l = plug->dependent_plugins ; l != NULL ; l = l->next)
+			{
+				const char *dep_name = (const char *)l->data;
+				GaimPlugin *dep_plugin = gaim_plugins_find_with_id(dep_name);
+				g_return_if_fail(dep_plugin != NULL);
+
+				g_string_append_printf(tmp, "\n\t%s\n", _(dep_plugin->info->name));
+			}
+
+			cb_data = g_new(gpointer, 3);
+			cb_data[0] = plug;
+			cb_data[1] = model;
+			cb_data[2] = iter;
+
+			gaim_request_action(plugin_dialog, NULL,
+			                    _("Multiple plugins will be unloaded."),
+			                    tmp->str, 0, cb_data, 2,
+			                    _("Unload Plugins"), G_CALLBACK(plugin_unload_confirm_cb),
+			                    _("Cancel"), NULL);
+			g_string_free(tmp, TRUE);
+		}
+		else
+			plugin_toggled_stage_two(plug, model, iter, TRUE);
+	}
+}
+
+static void plugin_toggled_stage_two(GaimPlugin *plug, GtkTreeModel *model, GtkTreeIter *iter, gboolean unload)
+{
+	gchar *name = NULL;
+	gchar *description = NULL;
+
+	if (unload)
+	{
+		GdkCursor *wait = gdk_cursor_new (GDK_WATCH);
+		gdk_window_set_cursor(plugin_dialog->window, wait);
+		gdk_cursor_unref(wait);
+
 		gaim_plugin_unload(plug);
+
+		gdk_window_set_cursor(plugin_dialog->window, NULL);
 	}
 
 	gtk_widget_set_sensitive(pref_button,
@@ -206,37 +325,36 @@
 		 || (plug->info->prefs_info
 			&& plug->info->prefs_info->get_plugin_pref_frame)));
 
-	gdk_window_set_cursor(plugin_dialog->window, NULL);
-
 	name = g_markup_escape_text(_(plug->info->name), -1);
 	description = g_markup_escape_text(_(plug->info->description), -1);
 
 	if (plug->error != NULL) {
 		gchar *error = g_markup_escape_text(plug->error, -1);
 		gchar *desc;
-		g_snprintf(buf, sizeof(buf),
+		gchar *text = g_strdup_printf(
 				   "<span size=\"larger\">%s %s</span>\n\n"
 				   "<span weight=\"bold\" color=\"red\">%s</span>\n\n"
 				   "%s",
 				   name, plug->info->version, error, description);
 		desc = g_strdup_printf("<b>%s</b> %s\n<span weight=\"bold\" color=\"red\"%s</span>",
 			       plug->info->name, plug->info->version, error);
-		gtk_list_store_set (GTK_LIST_STORE (model), &iter,
-				    1, desc,
-				    -1);
+		gtk_list_store_set(GTK_LIST_STORE (model), iter,
+				   1, desc,
+				   -1);
 		g_free(desc);
 		g_free(error);
-		gtk_label_set_markup(GTK_LABEL(plugin_details), buf);
+		gtk_label_set_markup(GTK_LABEL(plugin_details), text);
+		g_free(text);
 	}
 	g_free(name);
 	g_free(description);
 
 
-	gtk_list_store_set (GTK_LIST_STORE (model), &iter,
-			    0, gaim_plugin_is_loaded(plug),
-			    -1);
+	gtk_list_store_set(GTK_LIST_STORE (model), iter,
+	                   0, gaim_plugin_is_loaded(plug),
+	                   -1);
+	g_free(iter);
 
-	gtk_tree_path_free(path);
 	gaim_gtk_plugins_save();
 }
 
@@ -341,6 +459,8 @@
 	switch (response) {
 	case GTK_RESPONSE_CLOSE:
 	case GTK_RESPONSE_DELETE_EVENT:
+		gaim_request_close_with_handle(plugin_dialog);
+		gaim_signals_disconnect_by_handle(plugin_dialog);
 		gtk_widget_destroy(d);
 		if (plugin_pref_dialogs != NULL) {
 			g_hash_table_destroy(plugin_pref_dialogs);
@@ -435,17 +555,22 @@
 
 	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(plugin_dialog)->vbox), sw, TRUE, TRUE, 0);
 
-	ls = gtk_list_store_new (4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
+	ls = gtk_list_store_new(4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls),
 					     1, GTK_SORT_ASCENDING);
 
 	update_plugin_list(ls);
 
-	event_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(ls));
+	event_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ls));
 
 	g_signal_connect(G_OBJECT(event_view), "row-activated",
 				G_CALLBACK(show_plugin_prefs_cb), event_view);
 
+	gaim_signal_connect(gaim_plugins_get_handle(), "plugin-load", plugin_dialog,
+	                    GAIM_CALLBACK(plugin_load_cb), event_view);
+	gaim_signal_connect(gaim_plugins_get_handle(), "plugin-unload", plugin_dialog,
+	                    GAIM_CALLBACK(plugin_unload_cb), event_view);
+
 	rend = gtk_cell_renderer_toggle_new();
 	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_view));
 
@@ -455,8 +580,8 @@
 							NULL);
 	gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col);
 	gtk_tree_view_column_set_sort_column_id(col, 0);
-	g_signal_connect (G_OBJECT(rend), "toggled",
-			  G_CALLBACK(plugin_load), ls);
+	g_signal_connect(G_OBJECT(rend), "toggled",
+			 G_CALLBACK(plugin_toggled), ls);
 
 	rendt = gtk_cell_renderer_text_new();
 	g_object_set(rendt,