Mercurial > pidgin
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); |
