/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*- * * mooplugin.c * * Copyright (C) 2004-2005 by Yevgen Muntyan * * 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. * * See COPYING file that comes with this distribution. */ #ifdef HAVE_CONFIG_H #include #endif #include "mooedit/mooplugin.h" #include "mooedit/moopluginprefs-glade.h" #include "mooedit/plugins/mooeditplugins.h" #include "mooutils/mooprefsdialog.h" #include "mooutils/moostock.h" #include #include #define PLUGIN_PREFS_ENABLED "enabled" typedef struct { MooEditor *editor; GSList *list; /* MooPlugin* */ GHashTable *names; } PluginStore; static PluginStore *plugin_store = NULL; static void plugin_store_init (void); static void plugin_store_add (MooPlugin *plugin); static void some_plugin_class_init (gpointer klass); static gboolean plugin_init (MooPlugin *plugin); static void plugin_deinit (MooPlugin *plugin); static void plugin_attach_win (MooPlugin *plugin, MooEditWindow *window); static void plugin_detach_win (MooPlugin *plugin, MooEditWindow *window); static void plugin_attach_doc (MooPlugin *plugin, MooEditWindow *window, MooEdit *doc); static void plugin_detach_doc (MooPlugin *plugin, MooEditWindow *window, MooEdit *doc); static gboolean plugin_info_check (MooPluginInfo *info); static char *make_prefs_key (MooPlugin *plugin, const char *key); static GQuark make_id_quark (MooPlugin *plugin); static MooWinPlugin *window_get_plugin (MooEditWindow *window, MooPlugin *plugin); static MooDocPlugin *doc_get_plugin (MooEdit *doc, MooPlugin *plugin); static void window_set_plugin (MooEditWindow *window, MooPlugin *plugin, MooWinPlugin *win_plugin); static void doc_set_plugin (MooEdit *doc, MooPlugin *plugin, MooDocPlugin *doc_plugin); static gboolean moo_plugin_registered (GType type); static gpointer parent_class = NULL; GType moo_plugin_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GTypeInfo info = { sizeof (MooPluginClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) some_plugin_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (MooPlugin), 0, /* n_preallocs */ NULL, NULL /* value_table */ }; type = g_type_register_static (G_TYPE_OBJECT, "MooPlugin", &info, 0); } return type; } GType moo_win_plugin_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GTypeInfo info = { sizeof (MooWinPluginClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) some_plugin_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (MooWinPlugin), 0, /* n_preallocs */ NULL, NULL /* value_table */ }; type = g_type_register_static (G_TYPE_OBJECT, "MooWinPlugin", &info, 0); } return type; } GType moo_doc_plugin_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GTypeInfo info = { sizeof (MooDocPluginClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) some_plugin_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (MooDocPlugin), 0, /* n_preallocs */ NULL, NULL /* value_table */ }; type = g_type_register_static (G_TYPE_OBJECT, "MooDocPlugin", &info, 0); } return type; } static void some_plugin_class_init (gpointer klass) { parent_class = g_type_class_peek_parent (klass); } gboolean moo_plugin_register (GType type) { MooPluginClass *klass; MooPlugin *plugin; char *prefs_key; GSList *l, *windows; g_return_val_if_fail (g_type_is_a (type, MOO_TYPE_PLUGIN), FALSE); klass = g_type_class_ref (type); g_return_val_if_fail (klass != NULL, FALSE); if (klass->plugin_system_version != MOO_PLUGIN_CURRENT_VERSION) { g_message ("%s: plugin %s of version %d is incompatible with " "current version %d", G_STRLOC, g_type_name (type), klass->plugin_system_version, MOO_PLUGIN_CURRENT_VERSION); return FALSE; } if (moo_plugin_registered (type)) { g_warning ("%s: plugin %s already registered", G_STRLOC, g_type_name (type)); return FALSE; } plugin = g_object_new (type, NULL); if (!plugin_info_check (plugin->info)) { g_warning ("%s: invalid info in plugin %s", G_STRLOC, g_type_name (type)); g_object_unref (plugin); return FALSE; } if (moo_plugin_lookup (moo_plugin_id (plugin))) { g_warning ("%s: plugin with id %s already registered", G_STRLOC, moo_plugin_id (plugin)); g_object_unref (plugin); return FALSE; } plugin->id_quark = make_id_quark (plugin); prefs_key = make_prefs_key (plugin, PLUGIN_PREFS_ENABLED); moo_prefs_new_key_bool (prefs_key, moo_plugin_enabled (plugin)); plugin->info->params->enabled = moo_prefs_get_bool (prefs_key); g_free (prefs_key); if (!plugin_init (plugin)) { g_object_unref (plugin); return FALSE; } plugin_store_add (plugin); windows = moo_editor_list_windows (plugin_store->editor); for (l = windows; l != NULL; l = l->next) plugin_attach_win (plugin, l->data); g_slist_free (windows); return TRUE; } static gboolean plugin_init (MooPlugin *plugin) { MooPluginClass *klass; g_return_val_if_fail (MOO_IS_PLUGIN (plugin), FALSE); if (!moo_plugin_enabled (plugin) || plugin->initialized) return TRUE; klass = MOO_PLUGIN_GET_CLASS (plugin); if (!klass->init || klass->init (plugin)) { plugin->initialized = TRUE; return TRUE; } else { return FALSE; } } static void plugin_deinit (MooPlugin *plugin) { MooPluginClass *klass; g_return_if_fail (MOO_IS_PLUGIN (plugin)); if (!plugin->initialized) return; klass = MOO_PLUGIN_GET_CLASS (plugin); if (klass->deinit) klass->deinit (plugin); plugin->initialized = FALSE; } static void plugin_attach_win (MooPlugin *plugin, MooEditWindow *window) { MooPluginClass *klass; MooWinPluginClass *wklass; MooWinPlugin *win_plugin; GType wtype; GSList *l, *docs; g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); g_return_if_fail (MOO_IS_PLUGIN (plugin)); if (!moo_plugin_enabled (plugin)) return; klass = MOO_PLUGIN_GET_CLASS (plugin); if (klass->attach_win) klass->attach_win (plugin, window); wtype = plugin->win_plugin_type; if (wtype && g_type_is_a (wtype, MOO_TYPE_WIN_PLUGIN)) { win_plugin = g_object_new (wtype, NULL); g_return_if_fail (win_plugin != NULL); win_plugin->plugin = plugin; win_plugin->window = window; wklass = MOO_WIN_PLUGIN_GET_CLASS (win_plugin); if (!wklass->create || wklass->create (win_plugin)) window_set_plugin (window, plugin, win_plugin); else g_object_unref (win_plugin); } docs = moo_edit_window_list_docs (window); for (l = docs; l != NULL; l = l->next) plugin_attach_doc (plugin, window, l->data); g_slist_free (docs); } static void plugin_detach_win (MooPlugin *plugin, MooEditWindow *window) { MooPluginClass *klass; MooWinPluginClass *wklass; MooWinPlugin *win_plugin; GSList *l, *docs; g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); g_return_if_fail (MOO_IS_PLUGIN (plugin)); if (!moo_plugin_enabled (plugin)) return; docs = moo_edit_window_list_docs (window); for (l = docs; l != NULL; l = l->next) plugin_detach_doc (plugin, window, l->data); g_slist_free (docs); win_plugin = window_get_plugin (window, plugin); if (win_plugin) { wklass = MOO_WIN_PLUGIN_GET_CLASS (win_plugin); if (wklass->destroy) wklass->destroy (win_plugin); g_object_unref (win_plugin); window_set_plugin (window, plugin, NULL); } klass = MOO_PLUGIN_GET_CLASS (plugin); if (klass->detach_win) klass->detach_win (plugin, window); } static void plugin_attach_doc (MooPlugin *plugin, MooEditWindow *window, MooEdit *doc) { MooPluginClass *klass; MooDocPluginClass *dklass; MooDocPlugin *doc_plugin; GType dtype; g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); g_return_if_fail (MOO_IS_EDIT (doc)); g_return_if_fail (MOO_IS_PLUGIN (plugin)); if (!moo_plugin_enabled (plugin)) return; klass = MOO_PLUGIN_GET_CLASS (plugin); if (klass->attach_doc) klass->attach_doc (plugin, doc, window); dtype = plugin->doc_plugin_type; if (dtype && g_type_is_a (dtype, MOO_TYPE_DOC_PLUGIN)) { doc_plugin = g_object_new (dtype, NULL); g_return_if_fail (doc_plugin != NULL); doc_plugin->plugin = plugin; doc_plugin->window = window; doc_plugin->doc = doc; dklass = MOO_DOC_PLUGIN_GET_CLASS (doc_plugin); if (!dklass->create || dklass->create (doc_plugin)) doc_set_plugin (doc, plugin, doc_plugin); else g_object_unref (doc_plugin); } } static void plugin_detach_doc (MooPlugin *plugin, MooEditWindow *window, MooEdit *doc) { MooPluginClass *klass; MooDocPluginClass *dklass; MooDocPlugin *doc_plugin; g_return_if_fail (MOO_IS_PLUGIN (plugin)); g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); g_return_if_fail (MOO_IS_EDIT (doc)); if (!moo_plugin_enabled (plugin)) return; doc_plugin = doc_get_plugin (doc, plugin); if (doc_plugin) { dklass = MOO_DOC_PLUGIN_GET_CLASS (doc_plugin); if (dklass->destroy) dklass->destroy (doc_plugin); g_object_unref (doc_plugin); doc_set_plugin (doc, plugin, NULL); } klass = MOO_PLUGIN_GET_CLASS (plugin); if (klass->detach_doc) klass->detach_doc (plugin, doc, window); } static MooWinPlugin* window_get_plugin (MooEditWindow *window, MooPlugin *plugin) { g_return_val_if_fail (MOO_IS_EDIT_WINDOW (window), NULL); g_return_val_if_fail (MOO_IS_PLUGIN (plugin), NULL); return g_object_get_qdata (G_OBJECT (window), plugin->id_quark); } static MooDocPlugin* doc_get_plugin (MooEdit *doc, MooPlugin *plugin) { g_return_val_if_fail (MOO_IS_EDIT (doc), NULL); g_return_val_if_fail (MOO_IS_PLUGIN (plugin), NULL); return g_object_get_qdata (G_OBJECT (doc), plugin->id_quark); } static void window_set_plugin (MooEditWindow *window, MooPlugin *plugin, MooWinPlugin *win_plugin) { g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); g_return_if_fail (MOO_IS_PLUGIN (plugin)); g_return_if_fail (!win_plugin || MOO_IS_WIN_PLUGIN (win_plugin)); g_object_set_qdata (G_OBJECT (window), plugin->id_quark, win_plugin); } static void doc_set_plugin (MooEdit *doc, MooPlugin *plugin, MooDocPlugin *doc_plugin) { g_return_if_fail (MOO_IS_EDIT (doc)); g_return_if_fail (MOO_IS_PLUGIN (plugin)); g_return_if_fail (!doc_plugin || MOO_IS_DOC_PLUGIN (doc_plugin)); g_object_set_qdata (G_OBJECT (doc), plugin->id_quark, doc_plugin); } static void plugin_store_init (void) { if (!plugin_store) { static PluginStore store; store.editor = moo_editor_instance (); store.list = NULL; store.names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); plugin_store = &store; } } static void plugin_store_add (MooPlugin *plugin) { g_return_if_fail (MOO_IS_PLUGIN (plugin)); plugin_store_init (); g_return_if_fail (!g_hash_table_lookup (plugin_store->names, moo_plugin_id (plugin))); plugin_store->list = g_slist_append (plugin_store->list, plugin); g_hash_table_insert (plugin_store->names, g_strdup (moo_plugin_id (plugin)), plugin); } static void plugin_store_remove (MooPlugin *plugin) { g_return_if_fail (plugin_store != NULL); g_return_if_fail (MOO_IS_PLUGIN (plugin)); plugin_store->list = g_slist_remove (plugin_store->list, plugin); g_hash_table_remove (plugin_store->names, moo_plugin_id (plugin)); } MooPlugin* moo_plugin_get (GType type) { GSList *l; g_return_val_if_fail (g_type_is_a (type, MOO_TYPE_PLUGIN), NULL); plugin_store_init (); for (l = plugin_store->list; l != NULL; l = l->next) if (G_OBJECT_TYPE (l->data) == type) return l->data; return NULL; } static gboolean moo_plugin_registered (GType type) { return moo_plugin_get (type) != NULL; } gpointer moo_win_plugin_lookup (const char *plugin_id, MooEditWindow *window) { MooPlugin *plugin; g_return_val_if_fail (plugin_id != NULL, NULL); g_return_val_if_fail (MOO_IS_EDIT_WINDOW (window), NULL); plugin = moo_plugin_lookup (plugin_id); return plugin ? window_get_plugin (window, plugin) : NULL; } gpointer moo_doc_plugin_lookup (const char *plugin_id, MooEdit *doc) { MooPlugin *plugin; g_return_val_if_fail (plugin_id != NULL, NULL); g_return_val_if_fail (MOO_IS_EDIT (doc), NULL); plugin = moo_plugin_lookup (plugin_id); return plugin ? doc_get_plugin (doc, plugin) : NULL; } static gboolean plugin_info_check (MooPluginInfo *info) { return info && info->id && info->id[0] && g_utf8_validate (info->id, -1, NULL) && info->name && g_utf8_validate (info->name, -1, NULL) && info->description && g_utf8_validate (info->description, -1, NULL) && info->params && info->prefs_params; } static char* make_prefs_key (MooPlugin *plugin, const char *key) { g_return_val_if_fail (MOO_IS_PLUGIN (plugin), NULL); g_return_val_if_fail (key != NULL, NULL); return moo_prefs_make_key (MOO_PLUGIN_PREFS_ROOT, moo_plugin_id (plugin), PLUGIN_PREFS_ENABLED, NULL); } static GQuark make_id_quark (MooPlugin *plugin) { char *string; GQuark quark; g_return_val_if_fail (MOO_IS_PLUGIN (plugin), 0); string = g_strdup_printf ("MooPlugin::%s", moo_plugin_id (plugin)); quark = g_quark_from_string (string); g_free (string); return quark; } gboolean moo_plugin_initialized (MooPlugin *plugin) { g_return_val_if_fail (MOO_IS_PLUGIN (plugin), FALSE); return plugin->initialized; } gboolean moo_plugin_enabled (MooPlugin *plugin) { g_return_val_if_fail (MOO_IS_PLUGIN (plugin), FALSE); return plugin->info->params->enabled; } static gboolean plugin_enable (MooPlugin *plugin) { GSList *l, *windows; g_return_val_if_fail (MOO_IS_PLUGIN (plugin), FALSE); if (moo_plugin_enabled (plugin)) return TRUE; g_assert (!plugin->initialized); plugin->info->params->enabled = TRUE; if (!plugin_init (plugin)) { plugin->info->params->enabled = FALSE; return FALSE; } windows = moo_editor_list_windows (plugin_store->editor); for (l = windows; l != NULL; l = l->next) plugin_attach_win (plugin, l->data); g_slist_free (windows); return TRUE; } static void plugin_disable (MooPlugin *plugin) { GSList *l, *windows; g_return_if_fail (MOO_IS_PLUGIN (plugin)); if (!moo_plugin_enabled (plugin)) return; g_assert (plugin->initialized); windows = moo_editor_list_windows (plugin_store->editor); for (l = windows; l != NULL; l = l->next) plugin_detach_win (plugin, l->data); g_slist_free (windows); plugin_deinit (plugin); plugin->info->params->enabled = FALSE; } gboolean moo_plugin_set_enabled (MooPlugin *plugin, gboolean enabled) { g_return_val_if_fail (MOO_IS_PLUGIN (plugin), FALSE); if (enabled) { return plugin_enable (plugin); } else { plugin_disable (plugin); return TRUE; } } void moo_plugin_unregister (GType type) { MooPlugin *plugin = moo_plugin_get (type); g_return_if_fail (plugin != NULL); moo_plugin_set_enabled (plugin, FALSE); plugin_store_remove (plugin); g_object_unref (plugin); } gpointer moo_plugin_lookup (const char *plugin_id) { g_return_val_if_fail (plugin_id != NULL, NULL); plugin_store_init (); return g_hash_table_lookup (plugin_store->names, plugin_id); } GSList* moo_list_plugins (void) { plugin_store_init (); return g_slist_copy (plugin_store->list); } #define DEFINE_GETTER(what) \ const char* \ moo_plugin_##what (MooPlugin *plugin) \ { \ g_return_val_if_fail (MOO_IS_PLUGIN (plugin), NULL); \ return plugin->info->what; \ } DEFINE_GETTER(id) DEFINE_GETTER(name) DEFINE_GETTER(description) DEFINE_GETTER(version) DEFINE_GETTER(author) #undef DEFINE_GETTER static gboolean moo_plugin_read_module (GModule *module, const char *name) { MooPluginModuleInitFunc init_func; char *init_func_name; gboolean result = FALSE; g_return_val_if_fail (module != NULL, FALSE); g_return_val_if_fail (name != NULL, FALSE); init_func_name = g_strdup_printf ("%s_init", name); if (!g_module_symbol (module, init_func_name, (gpointer*) &init_func)) goto out; if (!init_func ()) goto out; result = TRUE; out: g_free (init_func_name); return result; } static void moo_plugin_read_dir (const char *path) { GDir *dir; const char *name; g_return_if_fail (path != NULL); dir = g_dir_open (path, 0, NULL); if (!dir) return; while ((name = g_dir_read_name (dir))) { char *module_path, *prefix, *suffix; GModule *module; if (!g_str_has_suffix (name, "." G_MODULE_SUFFIX)) continue; suffix = g_strrstr (name, "." G_MODULE_SUFFIX); prefix = g_strndup (name, suffix - name); module_path = g_build_filename (path, name, NULL); module = g_module_open (module_path, 0); if (module) { if (!moo_plugin_read_module (module, prefix)) g_module_close (module); } else { g_message ("%s: %s", G_STRLOC, g_module_error ()); } g_free (prefix); g_free (module_path); } g_dir_close (dir); } void moo_plugin_read_dirs (char **dirs) { for ( ; dirs && *dirs; ++dirs) moo_plugin_read_dir (*dirs); } void _moo_window_attach_plugins (MooEditWindow *window) { GSList *l; g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); plugin_store_init (); for (l = plugin_store->list; l != NULL; l = l->next) plugin_attach_win (l->data, window); } void _moo_window_detach_plugins (MooEditWindow *window) { GSList *l; g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); plugin_store_init (); for (l = plugin_store->list; l != NULL; l = l->next) plugin_detach_win (l->data, window); } void _moo_doc_attach_plugins (MooEditWindow *window, MooEdit *doc) { GSList *l; g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); g_return_if_fail (MOO_IS_EDIT (doc)); plugin_store_init (); for (l = plugin_store->list; l != NULL; l = l->next) plugin_attach_doc (l->data, window, doc); } void _moo_doc_detach_plugins (MooEditWindow *window, MooEdit *doc) { GSList *l; g_return_if_fail (MOO_IS_EDIT_WINDOW (window)); g_return_if_fail (MOO_IS_EDIT (doc)); plugin_store_init (); for (l = plugin_store->list; l != NULL; l = l->next) plugin_detach_doc (l->data, window, doc); } void moo_plugin_init_builtin (void) { #ifndef __WIN32__ moo_find_plugin_init (); moo_file_selector_plugin_init (); #endif moo_active_strings_plugin_init (); } static gboolean moo_plugin_visible (MooPlugin *plugin) { g_return_val_if_fail (MOO_IS_PLUGIN (plugin), FALSE); return plugin->info->params->visible ? TRUE : FALSE; } /***************************************************************************/ /* Preferences dialog */ enum { COLUMN_ENABLED, COLUMN_PLUGIN_ID, COLUMN_PLUGIN_NAME, N_COLUMNS }; static void selection_changed (GtkTreeSelection *selection, MooPrefsDialogPage *page) { MooPlugin *plugin = NULL; GtkTreeModel *model; GtkTreeIter iter; GtkWidget *info; GtkLabel *version, *author, *description; if (gtk_tree_selection_get_selected (selection, &model, &iter)) { char *id = NULL; gtk_tree_model_get (model, &iter, COLUMN_PLUGIN_ID, &id, -1); plugin = moo_plugin_lookup (id); g_free (id); } info = moo_glade_xml_get_widget (page->xml, "info"); author = moo_glade_xml_get_widget (page->xml, "author"); version = moo_glade_xml_get_widget (page->xml, "version"); description = moo_glade_xml_get_widget (page->xml, "description"); gtk_widget_set_sensitive (info, plugin != NULL); if (plugin) { gtk_label_set_text (author, moo_plugin_author (plugin)); gtk_label_set_text (version, moo_plugin_version (plugin)); gtk_label_set_text (description, moo_plugin_description (plugin)); } else { gtk_label_set_text (author, ""); gtk_label_set_text (version, ""); gtk_label_set_text (description, ""); } } static int cmp_page_and_id (GObject *page, const char *id) { const char *page_id = g_object_get_data (page, "moo-plugin-id"); return page_id ? strcmp (id, page_id) : 1; } static void sync_pages (MooPrefsDialog *dialog, MooPrefsDialogPage *main_page) { GSList *old_plugin_pages, *plugin_pages, *plugin_ids, *l, *plugins; plugins = moo_list_plugins (); plugin_ids = NULL; for (l = plugins; l != NULL; l = l->next) { MooPlugin *plugin = l->data; plugin_ids = g_slist_append (plugin_ids, g_strdup (moo_plugin_id (plugin))); } old_plugin_pages = g_object_get_data (G_OBJECT (dialog), "moo-plugin-prefs-pages"); plugin_pages = NULL; for (l = plugins; l != NULL; l = l->next) { MooPlugin *plugin = l->data; if (moo_plugin_enabled (l->data) && MOO_PLUGIN_GET_CLASS(plugin)->create_prefs_page) { GSList *link = g_slist_find_custom (old_plugin_pages, moo_plugin_id (l->data), (GCompareFunc) cmp_page_and_id); if (link) { plugin_pages = g_slist_append (plugin_pages, link->data); } else { GtkWidget *plugin_page = MOO_PLUGIN_GET_CLASS(plugin)->create_prefs_page (plugin); if (plugin_page) { g_object_set_data_full (G_OBJECT (plugin_page), "moo-plugin-id", g_strdup (moo_plugin_id (plugin)), g_free); plugin_pages = g_slist_append (plugin_pages, plugin_page); moo_prefs_dialog_insert_page (dialog, plugin_page, GTK_WIDGET (main_page), -1); } } } } for (l = old_plugin_pages; l != NULL; l = l->next) if (!g_slist_find (plugin_pages, l->data)) moo_prefs_dialog_remove_page (dialog, l->data); g_object_set_data_full (G_OBJECT (dialog), "moo-plugin-prefs-pages", plugin_pages, (GDestroyNotify) g_slist_free); g_slist_foreach (plugin_ids, (GFunc) g_free, NULL); g_slist_free (plugin_ids); g_slist_free (plugins); } static void prefs_init (MooPrefsDialog *dialog, MooPrefsDialogPage *page) { GtkTreeView *treeview; GtkListStore *store; GtkTreeModel *model; GSList *l, *plugins; treeview = moo_glade_xml_get_widget (page->xml, "treeview"); model = gtk_tree_view_get_model (treeview); store = GTK_LIST_STORE (model); gtk_list_store_clear (store); plugins = moo_list_plugins (); for (l = plugins; l != NULL; l = l->next) { GtkTreeIter iter; MooPlugin *plugin = l->data; if (moo_plugin_visible (plugin)) { gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, COLUMN_ENABLED, moo_plugin_enabled (plugin), COLUMN_PLUGIN_ID, moo_plugin_id (plugin), COLUMN_PLUGIN_NAME, moo_plugin_name (plugin), -1); } } selection_changed (gtk_tree_view_get_selection (treeview), page); g_slist_free (plugins); sync_pages (dialog, page); } static void prefs_apply (MooPrefsDialog *dialog, MooPrefsDialogPage *page) { GtkTreeView *treeview; GtkTreeModel *model; GtkTreeIter iter; treeview = moo_glade_xml_get_widget (page->xml, "treeview"); model = gtk_tree_view_get_model (treeview); if (gtk_tree_model_get_iter_first (model, &iter)) do { MooPlugin *plugin; gboolean enabled; char *id = NULL; char *prefs_key; gtk_tree_model_get (model, &iter, COLUMN_ENABLED, &enabled, COLUMN_PLUGIN_ID, &id, -1); g_return_if_fail (id != NULL); plugin = moo_plugin_lookup (id); g_return_if_fail (plugin != NULL); moo_plugin_set_enabled (plugin, enabled); prefs_key = make_prefs_key (plugin, PLUGIN_PREFS_ENABLED); moo_prefs_set_bool (prefs_key, enabled); g_free (prefs_key); g_free (id); } while (gtk_tree_model_iter_next (model, &iter)); sync_pages (dialog, page); } static void enable_toggled (GtkCellRendererToggle *cell, gchar *tree_path, GtkListStore *store) { GtkTreePath *path = gtk_tree_path_new_from_string (tree_path); GtkTreeIter iter; if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path)) gtk_list_store_set (store, &iter, COLUMN_ENABLED, !gtk_cell_renderer_toggle_get_active (cell), -1); gtk_tree_path_free (path); } void _moo_plugin_attach_prefs (GtkWidget *dialog) { GtkWidget *page; MooGladeXML *xml; GtkTreeView *treeview; GtkCellRenderer *cell; GtkListStore *store; GtkTreeSelection *selection; g_return_if_fail (MOO_IS_PREFS_DIALOG (dialog)); page = moo_prefs_dialog_page_new_from_xml ("Plugins", MOO_STOCK_PLUGINS, MOO_PLUGIN_PREFS_GLADE_UI, -1, "page", MOO_PLUGIN_PREFS_ROOT); g_return_if_fail (page != NULL); xml = MOO_PREFS_DIALOG_PAGE(page)->xml; treeview = moo_glade_xml_get_widget (xml, "treeview"); selection = gtk_tree_view_get_selection (treeview); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); g_signal_connect (selection, "changed", G_CALLBACK (selection_changed), page); store = gtk_list_store_new (N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (store)); g_object_unref (store); cell = gtk_cell_renderer_toggle_new (); g_object_set (cell, "activatable", TRUE, NULL); g_signal_connect (cell, "toggled", G_CALLBACK (enable_toggled), store); gtk_tree_view_insert_column_with_attributes (treeview, 0, "Enabled", cell, "active", COLUMN_ENABLED, NULL); cell = gtk_cell_renderer_text_new (); gtk_tree_view_insert_column_with_attributes (treeview, 1, "Plugin", cell, "text", COLUMN_PLUGIN_NAME, NULL); g_signal_connect (dialog, "init", G_CALLBACK (prefs_init), page); g_signal_connect (dialog, "apply", G_CALLBACK (prefs_apply), page); moo_prefs_dialog_append_page (MOO_PREFS_DIALOG (dialog), page); }