comparison src/gtkplugin.c @ 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 bba0faa37f3a
children 71fbe885c50b
comparison
equal deleted inserted replaced
12926:2c4f20ff387c 12927:3cc18baeaca3
26 #include "gtkgaim.h" 26 #include "gtkgaim.h"
27 #include "gtkplugin.h" 27 #include "gtkplugin.h"
28 #include "gtkpluginpref.h" 28 #include "gtkpluginpref.h"
29 #include "debug.h" 29 #include "debug.h"
30 #include "prefs.h" 30 #include "prefs.h"
31 #include "request.h"
31 32
32 #include <string.h> 33 #include <string.h>
33 34
34 #define GAIM_RESPONSE_CONFIGURE 98121 35 #define GAIM_RESPONSE_CONFIGURE 98121
36
37 static void plugin_toggled_stage_two(GaimPlugin *plug, GtkTreeModel *model,
38 GtkTreeIter *iter, gboolean unload);
35 39
36 static GtkWidget *expander = NULL; 40 static GtkWidget *expander = NULL;
37 static GtkWidget *plugin_dialog = NULL; 41 static GtkWidget *plugin_dialog = NULL;
38 static GtkWidget *plugin_details = NULL; 42 static GtkWidget *plugin_details = NULL;
39 static GtkWidget *pref_button = NULL; 43 static GtkWidget *pref_button = NULL;
149 2, plug, 153 2, plug,
150 3, gaim_plugin_is_unloadable(plug), 154 3, gaim_plugin_is_unloadable(plug),
151 -1); 155 -1);
152 g_free(desc); 156 g_free(desc);
153 } 157 }
158 }
159
160 static void plugin_loading_common(GaimPlugin *plugin, GtkTreeView *view, gboolean loaded)
161 {
162 GtkTreeIter iter;
163 GtkTreeModel *model = gtk_tree_view_get_model(view);
164
165 if (gtk_tree_model_get_iter_first(model, &iter)) {
166 do {
167 GaimPlugin *plug;
168 GtkTreeSelection *sel;
169
170 gtk_tree_model_get(model, &iter, 2, &plug, -1);
171
172 if (plug != plugin)
173 continue;
174
175 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, loaded, -1);
176
177 /* If the loaded/unloaded plugin is the selected row,
178 * update the pref_button. */
179 sel = gtk_tree_view_get_selection(view);
180 if (gtk_tree_selection_get_selected(sel, &model, &iter))
181 {
182 gtk_tree_model_get(model, &iter, 2, &plug, -1);
183 if (plug == plugin)
184 {
185 gtk_widget_set_sensitive(pref_button,
186 loaded
187 && ((GAIM_IS_GTK_PLUGIN(plug) && plug->info->ui_info
188 && GAIM_GTK_PLUGIN_UI_INFO(plug)->get_config_frame)
189 || (plug->info->prefs_info
190 && plug->info->prefs_info->get_plugin_pref_frame)));
191 }
192 }
193
194 break;
195 } while (gtk_tree_model_iter_next(model, &iter));
196 }
197 }
198
199 static void plugin_load_cb(GaimPlugin *plugin, gpointer data)
200 {
201 GtkTreeView *view = (GtkTreeView *)data;
202 plugin_loading_common(plugin, view, TRUE);
203 }
204
205 static void plugin_unload_cb(GaimPlugin *plugin, gpointer data)
206 {
207 GtkTreeView *view = (GtkTreeView *)data;
208 plugin_loading_common(plugin, view, FALSE);
154 } 209 }
155 210
156 static void pref_dialog_response_cb(GtkWidget *d, int response, GaimPlugin *plug) 211 static void pref_dialog_response_cb(GtkWidget *d, int response, GaimPlugin *plug)
157 { 212 {
158 switch (response) { 213 switch (response) {
166 gtk_widget_destroy(d); 221 gtk_widget_destroy(d);
167 break; 222 break;
168 } 223 }
169 } 224 }
170 225
171 static void plugin_load (GtkCellRendererToggle *cell, gchar *pth, gpointer data) 226 static void plugin_unload_confirm_cb(gpointer *data)
227 {
228 GaimPlugin *plugin = (GaimPlugin *)data[0];
229 GtkTreeModel *model = (GtkTreeModel *)data[1];
230 GtkTreeIter *iter = (GtkTreeIter *)data[2];
231
232 plugin_toggled_stage_two(plugin, model, iter, TRUE);
233
234 g_free(data);
235 }
236
237 static void plugin_toggled(GtkCellRendererToggle *cell, gchar *pth, gpointer data)
172 { 238 {
173 GtkTreeModel *model = (GtkTreeModel *)data; 239 GtkTreeModel *model = (GtkTreeModel *)data;
174 GtkTreeIter iter; 240 GtkTreeIter *iter = g_new(GtkTreeIter, 1);
175 GtkTreePath *path = gtk_tree_path_new_from_string(pth); 241 GtkTreePath *path = gtk_tree_path_new_from_string(pth);
176 GaimPlugin *plug; 242 GaimPlugin *plug;
177 gchar buf[1024];
178 gchar *name = NULL, *description = NULL;
179 GtkWidget *dialog = NULL; 243 GtkWidget *dialog = NULL;
180 GdkCursor *wait; 244
181 245 gtk_tree_model_get_iter(model, iter, path);
182 gtk_tree_model_get_iter (model, &iter, path); 246 gtk_tree_path_free(path);
183 gtk_tree_model_get (model, &iter, 2, &plug, -1); 247 gtk_tree_model_get(model, iter, 2, &plug, -1);
184 248
185 /* Apparently, GTK+ won't honor the sensitive flag on cell renderers for booleans. */ 249 /* Apparently, GTK+ won't honor the sensitive flag on cell renderers for booleans. */
186 if (gaim_plugin_is_unloadable(plug)) 250 if (gaim_plugin_is_unloadable(plug))
251 {
252 g_free(iter);
187 return; 253 return;
188 254 }
189 wait = gdk_cursor_new (GDK_WATCH);
190 gdk_window_set_cursor(plugin_dialog->window, wait);
191 gdk_cursor_unref(wait);
192 255
193 if (!gaim_plugin_is_loaded(plug)) 256 if (!gaim_plugin_is_loaded(plug))
257 {
258 GdkCursor *wait = gdk_cursor_new (GDK_WATCH);
259 gdk_window_set_cursor(plugin_dialog->window, wait);
260 gdk_cursor_unref(wait);
261
194 gaim_plugin_load(plug); 262 gaim_plugin_load(plug);
195 else { 263 plugin_toggled_stage_two(plug, model, iter, FALSE);
264
265 gdk_window_set_cursor(plugin_dialog->window, NULL);
266 }
267 else
268 {
196 if (plugin_pref_dialogs != NULL && 269 if (plugin_pref_dialogs != NULL &&
197 (dialog = g_hash_table_lookup(plugin_pref_dialogs, plug))) 270 (dialog = g_hash_table_lookup(plugin_pref_dialogs, plug)))
198 pref_dialog_response_cb(dialog, GTK_RESPONSE_DELETE_EVENT, plug); 271 pref_dialog_response_cb(dialog, GTK_RESPONSE_DELETE_EVENT, plug);
272
273 if (plug->dependent_plugins != NULL)
274 {
275 GString *tmp = g_string_new(_("The following plugins will be unloaded."));
276 GList *l;
277 gpointer *cb_data;
278
279 for (l = plug->dependent_plugins ; l != NULL ; l = l->next)
280 {
281 const char *dep_name = (const char *)l->data;
282 GaimPlugin *dep_plugin = gaim_plugins_find_with_id(dep_name);
283 g_return_if_fail(dep_plugin != NULL);
284
285 g_string_append_printf(tmp, "\n\t%s\n", _(dep_plugin->info->name));
286 }
287
288 cb_data = g_new(gpointer, 3);
289 cb_data[0] = plug;
290 cb_data[1] = model;
291 cb_data[2] = iter;
292
293 gaim_request_action(plugin_dialog, NULL,
294 _("Multiple plugins will be unloaded."),
295 tmp->str, 0, cb_data, 2,
296 _("Unload Plugins"), G_CALLBACK(plugin_unload_confirm_cb),
297 _("Cancel"), NULL);
298 g_string_free(tmp, TRUE);
299 }
300 else
301 plugin_toggled_stage_two(plug, model, iter, TRUE);
302 }
303 }
304
305 static void plugin_toggled_stage_two(GaimPlugin *plug, GtkTreeModel *model, GtkTreeIter *iter, gboolean unload)
306 {
307 gchar *name = NULL;
308 gchar *description = NULL;
309
310 if (unload)
311 {
312 GdkCursor *wait = gdk_cursor_new (GDK_WATCH);
313 gdk_window_set_cursor(plugin_dialog->window, wait);
314 gdk_cursor_unref(wait);
315
199 gaim_plugin_unload(plug); 316 gaim_plugin_unload(plug);
317
318 gdk_window_set_cursor(plugin_dialog->window, NULL);
200 } 319 }
201 320
202 gtk_widget_set_sensitive(pref_button, 321 gtk_widget_set_sensitive(pref_button,
203 gaim_plugin_is_loaded(plug) 322 gaim_plugin_is_loaded(plug)
204 && ((GAIM_IS_GTK_PLUGIN(plug) && plug->info->ui_info 323 && ((GAIM_IS_GTK_PLUGIN(plug) && plug->info->ui_info
205 && GAIM_GTK_PLUGIN_UI_INFO(plug)->get_config_frame) 324 && GAIM_GTK_PLUGIN_UI_INFO(plug)->get_config_frame)
206 || (plug->info->prefs_info 325 || (plug->info->prefs_info
207 && plug->info->prefs_info->get_plugin_pref_frame))); 326 && plug->info->prefs_info->get_plugin_pref_frame)));
208 327
209 gdk_window_set_cursor(plugin_dialog->window, NULL);
210
211 name = g_markup_escape_text(_(plug->info->name), -1); 328 name = g_markup_escape_text(_(plug->info->name), -1);
212 description = g_markup_escape_text(_(plug->info->description), -1); 329 description = g_markup_escape_text(_(plug->info->description), -1);
213 330
214 if (plug->error != NULL) { 331 if (plug->error != NULL) {
215 gchar *error = g_markup_escape_text(plug->error, -1); 332 gchar *error = g_markup_escape_text(plug->error, -1);
216 gchar *desc; 333 gchar *desc;
217 g_snprintf(buf, sizeof(buf), 334 gchar *text = g_strdup_printf(
218 "<span size=\"larger\">%s %s</span>\n\n" 335 "<span size=\"larger\">%s %s</span>\n\n"
219 "<span weight=\"bold\" color=\"red\">%s</span>\n\n" 336 "<span weight=\"bold\" color=\"red\">%s</span>\n\n"
220 "%s", 337 "%s",
221 name, plug->info->version, error, description); 338 name, plug->info->version, error, description);
222 desc = g_strdup_printf("<b>%s</b> %s\n<span weight=\"bold\" color=\"red\"%s</span>", 339 desc = g_strdup_printf("<b>%s</b> %s\n<span weight=\"bold\" color=\"red\"%s</span>",
223 plug->info->name, plug->info->version, error); 340 plug->info->name, plug->info->version, error);
224 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 341 gtk_list_store_set(GTK_LIST_STORE (model), iter,
225 1, desc, 342 1, desc,
226 -1); 343 -1);
227 g_free(desc); 344 g_free(desc);
228 g_free(error); 345 g_free(error);
229 gtk_label_set_markup(GTK_LABEL(plugin_details), buf); 346 gtk_label_set_markup(GTK_LABEL(plugin_details), text);
347 g_free(text);
230 } 348 }
231 g_free(name); 349 g_free(name);
232 g_free(description); 350 g_free(description);
233 351
234 352
235 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 353 gtk_list_store_set(GTK_LIST_STORE (model), iter,
236 0, gaim_plugin_is_loaded(plug), 354 0, gaim_plugin_is_loaded(plug),
237 -1); 355 -1);
238 356 g_free(iter);
239 gtk_tree_path_free(path); 357
240 gaim_gtk_plugins_save(); 358 gaim_gtk_plugins_save();
241 } 359 }
242 360
243 static gboolean ensure_plugin_visible(void *data) 361 static gboolean ensure_plugin_visible(void *data)
244 { 362 {
339 GtkTreeIter iter; 457 GtkTreeIter iter;
340 458
341 switch (response) { 459 switch (response) {
342 case GTK_RESPONSE_CLOSE: 460 case GTK_RESPONSE_CLOSE:
343 case GTK_RESPONSE_DELETE_EVENT: 461 case GTK_RESPONSE_DELETE_EVENT:
462 gaim_request_close_with_handle(plugin_dialog);
463 gaim_signals_disconnect_by_handle(plugin_dialog);
344 gtk_widget_destroy(d); 464 gtk_widget_destroy(d);
345 if (plugin_pref_dialogs != NULL) { 465 if (plugin_pref_dialogs != NULL) {
346 g_hash_table_destroy(plugin_pref_dialogs); 466 g_hash_table_destroy(plugin_pref_dialogs);
347 plugin_pref_dialogs = NULL; 467 plugin_pref_dialogs = NULL;
348 } 468 }
433 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); 553 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
434 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); 554 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
435 555
436 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(plugin_dialog)->vbox), sw, TRUE, TRUE, 0); 556 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(plugin_dialog)->vbox), sw, TRUE, TRUE, 0);
437 557
438 ls = gtk_list_store_new (4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN); 558 ls = gtk_list_store_new(4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
439 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls), 559 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls),
440 1, GTK_SORT_ASCENDING); 560 1, GTK_SORT_ASCENDING);
441 561
442 update_plugin_list(ls); 562 update_plugin_list(ls);
443 563
444 event_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(ls)); 564 event_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ls));
445 565
446 g_signal_connect(G_OBJECT(event_view), "row-activated", 566 g_signal_connect(G_OBJECT(event_view), "row-activated",
447 G_CALLBACK(show_plugin_prefs_cb), event_view); 567 G_CALLBACK(show_plugin_prefs_cb), event_view);
568
569 gaim_signal_connect(gaim_plugins_get_handle(), "plugin-load", plugin_dialog,
570 GAIM_CALLBACK(plugin_load_cb), event_view);
571 gaim_signal_connect(gaim_plugins_get_handle(), "plugin-unload", plugin_dialog,
572 GAIM_CALLBACK(plugin_unload_cb), event_view);
448 573
449 rend = gtk_cell_renderer_toggle_new(); 574 rend = gtk_cell_renderer_toggle_new();
450 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_view)); 575 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_view));
451 576
452 col = gtk_tree_view_column_new_with_attributes (_("Enabled"), 577 col = gtk_tree_view_column_new_with_attributes (_("Enabled"),
453 rend, 578 rend,
454 "active", 0, 579 "active", 0,
455 NULL); 580 NULL);
456 gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col); 581 gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col);
457 gtk_tree_view_column_set_sort_column_id(col, 0); 582 gtk_tree_view_column_set_sort_column_id(col, 0);
458 g_signal_connect (G_OBJECT(rend), "toggled", 583 g_signal_connect(G_OBJECT(rend), "toggled",
459 G_CALLBACK(plugin_load), ls); 584 G_CALLBACK(plugin_toggled), ls);
460 585
461 rendt = gtk_cell_renderer_text_new(); 586 rendt = gtk_cell_renderer_text_new();
462 g_object_set(rendt, 587 g_object_set(rendt,
463 "foreground", "#c0c0c0", 588 "foreground", "#c0c0c0",
464 NULL); 589 NULL);