2008-05-01 Johannes Schmid <jhs@gnome.org>
[anjuta-git-plugin.git] / libanjuta / anjuta-plugin-manager.c
blob3f6082ef7fdf7e1271d194c9478614eb1a86c5f2
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-plugin-manager.c
4 * Copyright (C) Naba Kumar <naba@gnome.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 /**
22 * SECTION:anjuta-plugin-manager
23 * @short_description: Plugins management and activation
24 * @see_also: #AnjutaPlugin, #AnjutaProfileManager
25 * @stability: Unstable
26 * @include: libanjuta/anjuta-plugin-manager.h
30 #include <sys/types.h>
31 #include <dirent.h>
32 #include <string.h>
33 #include <libgnomevfs/gnome-vfs.h>
35 #include <libanjuta/anjuta-plugin-manager.h>
36 #include <libanjuta/anjuta-marshal.h>
37 #include <libanjuta/anjuta-debug.h>
38 #include <libanjuta/anjuta-plugin-handle.h>
39 #include <libanjuta/anjuta-plugin.h>
40 #include <libanjuta/anjuta-c-plugin-factory.h>
41 #include <libanjuta/interfaces/ianjuta-plugin-factory.h>
42 #include <libanjuta/interfaces/ianjuta-preferences.h>
45 enum
47 PROP_0,
49 PROP_SHELL,
50 PROP_STATUS,
51 PROP_PROFILES,
52 PROP_AVAILABLE_PLUGINS,
53 PROP_ACTIVATED_PLUGINS
56 enum
58 PROFILE_PUSHED,
59 PROFILE_POPPED,
60 PLUGINS_TO_LOAD,
61 PLUGINS_TO_UNLOAD,
62 PLUGIN_ACTIVATED,
63 PLUGIN_DEACTIVATED,
65 LAST_SIGNAL
68 struct _AnjutaPluginManagerPriv
70 GObject *shell;
71 AnjutaStatus *status;
72 GList *plugin_dirs;
73 GList *available_plugins;
75 /* Indexes => plugin handles */
76 GHashTable *plugins_by_interfaces;
77 GHashTable *plugins_by_name;
78 GHashTable *plugins_by_description;
80 /* Plugins that are currently activated */
81 GHashTable *activated_plugins;
83 /* Plugins that have been previously loaded but current deactivated */
84 GHashTable *plugins_cache;
86 /* Remember plugin selection */
87 GHashTable *remember_plugins;
90 /* Available plugins page treeview */
91 enum {
92 COL_ACTIVABLE,
93 COL_ENABLED,
94 COL_ICON,
95 COL_NAME,
96 COL_PLUGIN,
97 N_COLS
100 /* Remembered plugins page treeview */
101 enum {
102 COL_REM_ICON,
103 COL_REM_NAME,
104 COL_REM_PLUGIN_KEY,
105 N_REM_COLS
108 /* Plugin class types */
110 static AnjutaCPluginFactory *anjuta_plugin_factory = NULL;
112 static GObjectClass* parent_class = NULL;
113 static guint plugin_manager_signals[LAST_SIGNAL] = { 0 };
115 static GHashTable* plugin_set_update (AnjutaPluginManager *plugin_manager,
116 AnjutaPluginHandle* selected_plugin,
117 gboolean load);
119 static IAnjutaPluginFactory* get_plugin_factory (AnjutaPluginManager *plugin_manager,
120 const gchar *language, GError **error);
122 GQuark
123 anjuta_plugin_manager_error_quark (void)
125 static GQuark quark = 0;
127 if (quark == 0) {
128 quark = g_quark_from_static_string ("anjuta-plugin-manager-quark");
130 return quark;
133 /** Dependency Resolution **/
135 static gboolean
136 collect_cycle (AnjutaPluginManager *plugin_manager,
137 AnjutaPluginHandle *base_plugin, AnjutaPluginHandle *cur_plugin,
138 GList **cycle)
140 AnjutaPluginManagerPriv *priv;
141 GList *l;
143 priv = plugin_manager->priv;
145 for (l = anjuta_plugin_handle_get_dependency_names (cur_plugin);
146 l != NULL; l = l->next)
148 AnjutaPluginHandle *dep = g_hash_table_lookup (priv->plugins_by_name,
149 l->data);
150 if (dep)
152 if (dep == base_plugin)
154 *cycle = g_list_prepend (NULL, dep);
155 /* DEBUG_PRINT ("%s ", anjuta_plugin_handle_get_name (dep)); */
156 return TRUE;
158 else
160 if (collect_cycle (plugin_manager, base_plugin, dep, cycle))
162 *cycle = g_list_prepend (*cycle, dep);
163 /* DEBUG_PRINT ("%s ", anjuta_plugin_handle_get_name (dep)); */
164 return TRUE;
169 return FALSE;
172 static void
173 add_dependency (AnjutaPluginHandle *dependent, AnjutaPluginHandle *dependency)
175 g_hash_table_insert (anjuta_plugin_handle_get_dependents (dependency),
176 dependent, dependency);
177 g_hash_table_insert (anjuta_plugin_handle_get_dependencies (dependent),
178 dependency, dependent);
181 static void
182 child_dep_foreach_cb (gpointer key, gpointer value, gpointer user_data)
184 add_dependency (ANJUTA_PLUGIN_HANDLE (user_data),
185 ANJUTA_PLUGIN_HANDLE (key));
188 /* Resolves dependencies for a single module recursively. Shortcuts if
189 * the module has already been resolved. Returns a list representing
190 * any cycles found, or NULL if no cycles are found. If a cycle is found,
191 * the graph is left unresolved.
193 static GList*
194 resolve_for_module (AnjutaPluginManager *plugin_manager,
195 AnjutaPluginHandle *plugin, int pass)
197 AnjutaPluginManagerPriv *priv;
198 GList *l;
199 GList *ret = NULL;
201 priv = plugin_manager->priv;
203 if (anjuta_plugin_handle_get_checked (plugin))
205 return NULL;
208 if (anjuta_plugin_handle_get_resolve_pass (plugin) == pass)
210 GList *cycle = NULL;
211 g_warning ("cycle found: %s on pass %d",
212 anjuta_plugin_handle_get_name (plugin),
213 anjuta_plugin_handle_get_resolve_pass (plugin));
214 collect_cycle (plugin_manager, plugin, plugin, &cycle);
215 return cycle;
218 if (anjuta_plugin_handle_get_resolve_pass (plugin) != -1)
220 return NULL;
223 anjuta_plugin_handle_set_can_load (plugin, TRUE);
224 anjuta_plugin_handle_set_resolve_pass (plugin, pass);
226 for (l = anjuta_plugin_handle_get_dependency_names (plugin);
227 l != NULL; l = l->next)
229 char *dep = l->data;
230 AnjutaPluginHandle *child =
231 g_hash_table_lookup (priv->plugins_by_name, dep);
232 if (child)
234 ret = resolve_for_module (plugin_manager, child, pass);
235 if (ret)
237 break;
240 /* Add the dependency's dense dependency list
241 * to the current module's dense dependency list */
242 g_hash_table_foreach (anjuta_plugin_handle_get_dependencies (child),
243 child_dep_foreach_cb, plugin);
244 add_dependency (plugin, child);
246 /* If the child can't load due to dependency problems,
247 * the current module can't either */
248 anjuta_plugin_handle_set_can_load (plugin,
249 anjuta_plugin_handle_get_can_load (child));
250 } else {
251 g_warning ("Dependency %s not found.\n", dep);
252 anjuta_plugin_handle_set_can_load (plugin, FALSE);
253 ret = NULL;
256 anjuta_plugin_handle_set_checked (plugin, TRUE);
258 return ret;
261 /* Clean up the results of a resolving run */
262 static void
263 unresolve_dependencies (AnjutaPluginManager *plugin_manager)
265 AnjutaPluginManagerPriv *priv;
266 GList *l;
268 priv = plugin_manager->priv;
270 for (l = priv->available_plugins; l != NULL; l = l->next)
272 AnjutaPluginHandle *plugin = l->data;
273 anjuta_plugin_handle_unresolve_dependencies (plugin);
277 /* done upto here */
279 static void
280 prune_modules (AnjutaPluginManager *plugin_manager, GList *modules)
282 AnjutaPluginManagerPriv *priv;
283 GList *l;
285 priv = plugin_manager->priv;
287 for (l = modules; l != NULL; l = l->next) {
288 AnjutaPluginHandle *plugin = l->data;
290 g_hash_table_remove (priv->plugins_by_name,
291 anjuta_plugin_handle_get_id (plugin));
292 priv->available_plugins = g_list_remove (priv->available_plugins, plugin);
296 static int
297 dependency_compare (AnjutaPluginHandle *plugin_a,
298 AnjutaPluginHandle *plugin_b)
300 int a = g_hash_table_size (anjuta_plugin_handle_get_dependencies (plugin_a));
301 int b = g_hash_table_size (anjuta_plugin_handle_get_dependencies (plugin_b));
303 return a - b;
306 /* Resolves the dependencies of the priv->available_plugins list. When this
307 * function is complete, the following will be true:
309 * 1) The dependencies and dependents hash tables of the modules will
310 * be filled.
312 * 2) Cycles in the graph will be removed.
314 * 3) Modules which cannot be loaded due to failed dependencies will
315 * be marked as such.
317 * 4) priv->available_plugins will be sorted such that no module depends on a
318 * module after it.
320 * If a cycle in the graph is found, it is pruned from the tree and
321 * returned as a list stored in the cycles list.
323 static void
324 resolve_dependencies (AnjutaPluginManager *plugin_manager, GList **cycles)
326 AnjutaPluginManagerPriv *priv;
327 GList *cycle = NULL;
328 GList *l;
330 priv = plugin_manager->priv;
331 *cycles = NULL;
333 /* Try resolving dependencies. If there is a cycle, prune the
334 * cycle and try to resolve again */
337 int pass = 1;
338 cycle = NULL;
339 for (l = priv->available_plugins; l != NULL && !cycle; l = l->next) {
340 cycle = resolve_for_module (plugin_manager, l->data, pass++);
341 cycle = NULL;
343 if (cycle) {
344 *cycles = g_list_prepend (*cycles, cycle);
345 prune_modules (plugin_manager, cycle);
346 unresolve_dependencies (plugin_manager);
348 } while (cycle);
350 /* Now that there is a fully resolved dependency tree, sort
351 * priv->available_plugins to create a valid load order */
352 priv->available_plugins = g_list_sort (priv->available_plugins,
353 (GCompareFunc)dependency_compare);
356 /* Plugins loading */
358 static gboolean
359 str_has_suffix (const char *haystack, const char *needle)
361 const char *h, *n;
363 if (needle == NULL) {
364 return TRUE;
366 if (haystack == NULL) {
367 return needle[0] == '\0';
370 /* Eat one character at a time. */
371 h = haystack + strlen(haystack);
372 n = needle + strlen(needle);
373 do {
374 if (n == needle) {
375 return TRUE;
377 if (h == haystack) {
378 return FALSE;
380 } while (*--h == *--n);
381 return FALSE;
384 static void
385 load_plugin (AnjutaPluginManager *plugin_manager,
386 const gchar *plugin_desc_path)
388 AnjutaPluginManagerPriv *priv;
389 AnjutaPluginHandle *plugin_handle;
391 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager));
392 priv = plugin_manager->priv;
394 plugin_handle = anjuta_plugin_handle_new (plugin_desc_path);
395 if (plugin_handle)
397 if (g_hash_table_lookup (priv->plugins_by_name,
398 anjuta_plugin_handle_get_id (plugin_handle)))
400 g_object_unref (plugin_handle);
402 else
404 GList *node;
405 /* Available plugin */
406 priv->available_plugins = g_list_prepend (priv->available_plugins,
407 plugin_handle);
408 /* Index by id */
409 g_hash_table_insert (priv->plugins_by_name,
410 (gchar *)anjuta_plugin_handle_get_id (plugin_handle),
411 plugin_handle);
413 /* Index by description */
414 g_hash_table_insert (priv->plugins_by_description,
415 anjuta_plugin_handle_get_description (plugin_handle),
416 plugin_handle);
418 /* Index by interfaces exported by this plugin */
419 node = anjuta_plugin_handle_get_interfaces (plugin_handle);
420 while (node)
422 GList *objs;
423 gchar *iface;
424 GList *obj_node;
425 gboolean found;
427 iface = node->data;
428 objs = (GList*)g_hash_table_lookup (priv->plugins_by_interfaces, iface);
430 obj_node = objs;
431 found = FALSE;
432 while (obj_node)
434 if (obj_node->data == plugin_handle)
436 found = TRUE;
437 break;
439 obj_node = g_list_next (obj_node);
441 if (!found)
443 g_hash_table_steal (priv->plugins_by_interfaces, iface);
444 objs = g_list_prepend (objs, plugin_handle);
445 g_hash_table_insert (priv->plugins_by_interfaces, iface, objs);
447 node = g_list_next (node);
451 return;
454 static void
455 load_plugins_from_directory (AnjutaPluginManager* plugin_manager,
456 const gchar *dirname)
458 DIR *dir;
459 struct dirent *entry;
461 dir = opendir (dirname);
463 if (!dir)
465 return;
468 for (entry = readdir (dir); entry != NULL; entry = readdir (dir))
470 if (str_has_suffix (entry->d_name, ".plugin"))
472 gchar *pathname;
473 pathname = g_strdup_printf ("%s/%s", dirname, entry->d_name);
474 load_plugin (plugin_manager,pathname);
475 g_free (pathname);
478 closedir (dir);
481 /* Plugin activation and deactivation */
483 static void
484 on_plugin_activated (AnjutaPlugin *plugin_object, AnjutaPluginHandle *plugin)
486 AnjutaPluginManager *plugin_manager;
487 AnjutaPluginManagerPriv *priv;
489 /* FIXME: Pass plugin_manager directly in signal arguments */
490 plugin_manager = anjuta_shell_get_plugin_manager (plugin_object->shell, NULL);
492 g_return_if_fail(plugin_manager != NULL);
494 priv = plugin_manager->priv;
496 g_hash_table_insert (priv->activated_plugins, plugin,
497 G_OBJECT (plugin_object));
498 if (g_hash_table_lookup (priv->plugins_cache, plugin))
499 g_hash_table_remove (priv->plugins_cache, plugin);
501 g_signal_emit_by_name (plugin_manager, "plugin-activated",
502 anjuta_plugin_handle_get_description (plugin),
503 plugin_object);
506 static void
507 on_plugin_deactivated (AnjutaPlugin *plugin_object, AnjutaPluginHandle *plugin)
509 AnjutaPluginManager *plugin_manager;
510 AnjutaPluginManagerPriv *priv;
512 /* FIXME: Pass plugin_manager directly in signal arguments */
513 plugin_manager = anjuta_shell_get_plugin_manager (plugin_object->shell, NULL);
515 g_return_if_fail (plugin_manager != NULL);
517 priv = plugin_manager->priv;
519 g_hash_table_insert (priv->plugins_cache, plugin, G_OBJECT (plugin_object));
520 g_hash_table_remove (priv->activated_plugins, plugin);
522 g_signal_emit_by_name (plugin_manager, "plugin-deactivated",
523 anjuta_plugin_handle_get_description (plugin),
524 plugin_object);
527 static AnjutaPlugin*
528 activate_plugin (AnjutaPluginManager *plugin_manager,
529 AnjutaPluginHandle *handle, GError **error)
531 AnjutaPluginManagerPriv *priv;
532 IAnjutaPluginFactory* factory;
533 AnjutaPlugin *plugin;
534 const gchar *plugin_id;
535 const gchar *language;
536 gboolean resident;
538 priv = plugin_manager->priv;
540 plugin_id = anjuta_plugin_handle_get_id (handle);
542 resident = anjuta_plugin_handle_get_resident (handle);
543 language = anjuta_plugin_handle_get_language (handle);
545 factory = get_plugin_factory (plugin_manager, language, error);
546 if (factory == NULL) return NULL;
548 plugin = ianjuta_plugin_factory_new_plugin (factory, handle, ANJUTA_SHELL (priv->shell), error);
550 if (plugin == NULL)
552 return NULL;
554 g_signal_connect (plugin, "activated",
555 G_CALLBACK (on_plugin_activated), handle);
556 g_signal_connect (plugin, "deactivated",
557 G_CALLBACK (on_plugin_deactivated), handle);
559 return plugin;
562 static gboolean
563 g_hashtable_foreach_true (gpointer key, gpointer value, gpointer user_data)
565 return TRUE;
568 void
569 anjuta_plugin_manager_unload_all_plugins (AnjutaPluginManager *plugin_manager)
571 AnjutaPluginManagerPriv *priv;
573 priv = plugin_manager->priv;
574 if (g_hash_table_size (priv->activated_plugins) > 0 ||
575 g_hash_table_size (priv->plugins_cache) > 0)
577 priv->available_plugins = g_list_reverse (priv->available_plugins);
578 if (g_hash_table_size (priv->activated_plugins) > 0)
580 GList *node;
581 node = priv->available_plugins;
582 while (node)
584 AnjutaPluginHandle *selected_plugin = node->data;
585 if (g_hash_table_lookup (priv->activated_plugins, selected_plugin))
587 plugin_set_update (plugin_manager, selected_plugin, FALSE);
588 /* DEBUG_PRINT ("Unloading plugin: %s",
589 anjuta_plugin_handle_get_id (selected_plugin));
592 node = g_list_next (node);
594 g_hash_table_foreach_remove (priv->activated_plugins,
595 g_hashtable_foreach_true, NULL);
597 if (g_hash_table_size (priv->plugins_cache) > 0)
599 GList *node;
600 node = priv->available_plugins;
601 while (node)
603 GObject *plugin_obj;
604 AnjutaPluginHandle *selected_plugin = node->data;
606 plugin_obj = g_hash_table_lookup (priv->plugins_cache,
607 selected_plugin);
608 if (plugin_obj)
610 /* DEBUG_PRINT ("Destroying plugin: %s",
611 anjuta_plugin_handle_get_id (selected_plugin));
613 g_object_unref (plugin_obj);
615 node = g_list_next (node);
617 g_hash_table_foreach_remove (priv->plugins_cache,
618 g_hashtable_foreach_true, NULL);
620 priv->available_plugins = g_list_reverse (priv->available_plugins);
624 static gboolean
625 should_unload (GHashTable *activated_plugins, AnjutaPluginHandle *plugin_to_unload,
626 AnjutaPluginHandle *plugin)
628 GObject *plugin_obj = g_hash_table_lookup (activated_plugins, plugin);
630 if (!plugin_obj)
631 return FALSE;
633 if (plugin_to_unload == plugin)
634 return TRUE;
636 gboolean dependent =
637 GPOINTER_TO_INT (g_hash_table_lookup (anjuta_plugin_handle_get_dependents (plugin),
638 plugin));
639 return dependent;
642 static gboolean
643 should_load (GHashTable *activated_plugins, AnjutaPluginHandle *plugin_to_load,
644 AnjutaPluginHandle *plugin)
646 GObject *plugin_obj = g_hash_table_lookup (activated_plugins, plugin);
648 if (plugin_obj)
649 return FALSE;
651 if (plugin_to_load == plugin)
652 return anjuta_plugin_handle_get_can_load (plugin);
654 gboolean dependency =
655 GPOINTER_TO_INT (g_hash_table_lookup (anjuta_plugin_handle_get_dependencies (plugin_to_load),
656 plugin));
657 return (dependency && anjuta_plugin_handle_get_can_load (plugin));
660 static AnjutaPluginHandle *
661 plugin_for_iter (GtkListStore *store, GtkTreeIter *iter)
663 AnjutaPluginHandle *plugin;
665 gtk_tree_model_get (GTK_TREE_MODEL (store), iter, COL_PLUGIN, &plugin, -1);
666 return plugin;
669 static void
670 update_enabled (GtkTreeModel *model, GHashTable *activated_plugins)
672 GtkTreeIter iter;
674 if (gtk_tree_model_get_iter_first (model, &iter)) {
675 do {
676 AnjutaPluginHandle *plugin;
677 GObject *plugin_obj;
678 gboolean installed;
680 plugin = plugin_for_iter(GTK_LIST_STORE(model), &iter);
681 plugin_obj = g_hash_table_lookup (activated_plugins, plugin);
682 installed = (plugin_obj != NULL) ? TRUE : FALSE;
683 gtk_tree_model_get (model, &iter, COL_PLUGIN, &plugin, -1);
684 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
685 COL_ENABLED, installed, -1);
686 } while (gtk_tree_model_iter_next (model, &iter));
690 static GHashTable*
691 plugin_set_update (AnjutaPluginManager *plugin_manager,
692 AnjutaPluginHandle* selected_plugin,
693 gboolean load)
695 AnjutaPluginManagerPriv *priv;
696 GObject *plugin_obj;
697 GList *l;
699 priv = plugin_manager->priv;
700 plugin_obj = g_hash_table_lookup (priv->activated_plugins, selected_plugin);
702 if (plugin_obj && load)
704 g_warning ("Trying to install already installed plugin '%s'",
705 anjuta_plugin_handle_get_name (selected_plugin));
706 return priv->activated_plugins;
708 if (!plugin_obj && !load)
710 g_warning ("Trying to uninstall a not installed plugin '%s'",
711 anjuta_plugin_handle_get_name (selected_plugin));
712 return priv->activated_plugins;
715 if (priv->status)
716 anjuta_status_busy_push (priv->status);
718 if (!load)
720 /* reverse priv->available_plugins when unloading, so that plugins are
721 * unloaded in the right order */
722 priv->available_plugins = g_list_reverse (priv->available_plugins);
724 for (l = priv->available_plugins; l != NULL; l = l->next)
726 AnjutaPluginHandle *plugin = l->data;
727 if (should_unload (priv->activated_plugins, selected_plugin, plugin))
729 /* FIXME: Unload the class and sharedlib if possible */
730 AnjutaPlugin *anjuta_plugin = ANJUTA_PLUGIN (plugin_obj);
731 if (!anjuta_plugin_deactivate (ANJUTA_PLUGIN (anjuta_plugin)))
733 anjuta_util_dialog_info (GTK_WINDOW (priv->shell),
734 "Plugin '%s' do not want to be deactivated",
735 anjuta_plugin_handle_get_name (plugin));
739 priv->available_plugins = g_list_reverse (priv->available_plugins);
741 else
743 for (l = priv->available_plugins; l != NULL; l = l->next)
745 AnjutaPluginHandle *plugin = l->data;
746 if (should_load (priv->activated_plugins, selected_plugin, plugin))
748 AnjutaPlugin *plugin_obj;
749 GError *error = NULL;
750 plugin_obj = g_hash_table_lookup (priv->plugins_cache, plugin);
751 if (!plugin_obj)
753 plugin_obj = activate_plugin (plugin_manager, plugin,
754 &error);
757 if (plugin_obj)
759 anjuta_plugin_activate (ANJUTA_PLUGIN (plugin_obj));
761 else
763 if (error)
765 gchar* message = g_strdup_printf (_("Could not load %s\n"
766 "This usually means that your installation is corrupted. The "
767 "error message leading to this was:\n%s"),
768 anjuta_plugin_handle_get_name (selected_plugin),
769 error->message);
770 anjuta_util_dialog_error (GTK_WINDOW(plugin_manager->priv->shell),
771 message);
772 g_error_free (error);
773 g_free(message);
779 if (priv->status)
780 anjuta_status_busy_pop (priv->status);
781 return priv->activated_plugins;
784 static void
785 plugin_toggled (GtkCellRendererToggle *cell, char *path_str, gpointer data)
787 AnjutaPluginManager *plugin_manager;
788 AnjutaPluginManagerPriv *priv;
789 GtkListStore *store = GTK_LIST_STORE (data);
790 GtkTreeIter iter;
791 GtkTreePath *path;
792 AnjutaPluginHandle *plugin;
793 gboolean enabled;
794 GHashTable *activated_plugins;
795 AnjutaPlugin* plugin_object;
797 path = gtk_tree_path_new_from_string (path_str);
799 plugin_manager = g_object_get_data (G_OBJECT (store), "plugin-manager");
800 priv = plugin_manager->priv;
802 gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
803 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
804 COL_ENABLED, &enabled,
805 COL_PLUGIN, &plugin,
806 -1);
808 if (enabled)
810 plugin_object = g_hash_table_lookup (priv->activated_plugins, plugin);
811 if (plugin_object &&
812 IANJUTA_IS_PREFERENCES(plugin_object))
814 ianjuta_preferences_unmerge (IANJUTA_PREFERENCES (plugin_object),
815 anjuta_shell_get_preferences (ANJUTA_SHELL (priv->shell), NULL),
816 NULL);
819 enabled = !enabled;
821 activated_plugins = plugin_set_update (plugin_manager, plugin, enabled);
822 plugin_object = g_hash_table_lookup (priv->activated_plugins, plugin);
824 /* Make sure that it appears in the preferences. This method
825 can only be called when the preferences dialog is active so
826 it should be save
828 if (plugin_object &&
829 IANJUTA_IS_PREFERENCES(plugin_object))
831 ianjuta_preferences_merge (IANJUTA_PREFERENCES (plugin_object),
832 anjuta_shell_get_preferences (ANJUTA_SHELL (priv->shell), NULL),
833 NULL);
836 update_enabled (GTK_TREE_MODEL (store), activated_plugins);
837 gtk_tree_path_free (path);
840 #if 0
841 static void
842 selection_changed (GtkTreeSelection *selection, GtkListStore *store)
844 GtkTreeIter iter;
846 if (gtk_tree_selection_get_selected (selection, NULL,
847 &iter)) {
848 GtkTextBuffer *buffer;
850 GtkWidget *txt = g_object_get_data (G_OBJECT (store),
851 "AboutText");
853 GtkWidget *image = g_object_get_data (G_OBJECT (store),
854 "Icon");
855 AnjutaPluginHandle *plugin = plugin_for_iter (store, &iter);
857 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (txt));
858 gtk_text_buffer_set_text (buffer, plugin->about, -1);
860 if (plugin->icon_path) {
861 gtk_image_set_from_file (GTK_IMAGE (image),
862 plugin->icon_path);
863 gtk_widget_show (GTK_WIDGET (image));
864 } else {
865 gtk_widget_hide (GTK_WIDGET (image));
869 #endif
871 static GtkWidget *
872 create_plugin_tree (void)
874 GtkListStore *store;
875 GtkWidget *tree;
876 GtkCellRenderer *renderer;
877 GtkTreeViewColumn *column;
879 store = gtk_list_store_new (N_COLS,
880 G_TYPE_BOOLEAN,
881 G_TYPE_BOOLEAN,
882 GDK_TYPE_PIXBUF,
883 G_TYPE_STRING,
884 G_TYPE_POINTER);
885 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
887 renderer = gtk_cell_renderer_toggle_new ();
888 g_signal_connect (G_OBJECT (renderer), "toggled",
889 G_CALLBACK (plugin_toggled), store);
890 column = gtk_tree_view_column_new_with_attributes (_("Load"),
891 renderer,
892 "active",
893 COL_ENABLED,
894 "activatable",
895 COL_ACTIVABLE,
896 NULL);
897 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
898 gtk_tree_view_column_set_sizing (column,
899 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
901 column = gtk_tree_view_column_new ();
902 renderer = gtk_cell_renderer_pixbuf_new ();
903 gtk_tree_view_column_pack_start (column, renderer, FALSE);
904 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
905 COL_ICON);
906 renderer = gtk_cell_renderer_text_new ();
907 gtk_tree_view_column_pack_start (column, renderer, FALSE);
908 gtk_tree_view_column_add_attribute (column, renderer, "markup",
909 COL_NAME);
910 gtk_tree_view_column_set_sizing (column,
911 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
912 gtk_tree_view_column_set_title (column, _("Available Plugins"));
913 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
914 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (tree), column);
916 g_object_unref (store);
917 return tree;
920 /* Sort function for plugins */
921 static gint
922 sort_plugins(gconstpointer a, gconstpointer b)
924 g_return_val_if_fail (a != NULL, 0);
925 g_return_val_if_fail (b != NULL, 0);
927 AnjutaPluginHandle* plugin_a = ANJUTA_PLUGIN_HANDLE (a);
928 AnjutaPluginHandle* plugin_b = ANJUTA_PLUGIN_HANDLE (b);
930 return strcmp (anjuta_plugin_handle_get_name (plugin_a),
931 anjuta_plugin_handle_get_name (plugin_b));
934 /* If show_all == FALSE, show only user activatable plugins
935 * If show_all == TRUE, show all plugins
937 static void
938 populate_plugin_model (AnjutaPluginManager *plugin_manager,
939 GtkListStore *store,
940 GHashTable *plugins_to_show,
941 GHashTable *activated_plugins,
942 gboolean show_all)
944 AnjutaPluginManagerPriv *priv;
945 GList *l;
947 priv = plugin_manager->priv;
948 gtk_list_store_clear (store);
950 priv->available_plugins = g_list_sort (priv->available_plugins, sort_plugins);
952 for (l = priv->available_plugins; l != NULL; l = l->next)
954 AnjutaPluginHandle *plugin = l->data;
956 /* If plugins to show is NULL, show all available plugins */
957 if (plugins_to_show == NULL ||
958 g_hash_table_lookup (plugins_to_show, plugin))
961 gboolean enable = FALSE;
962 if (g_hash_table_lookup (activated_plugins, plugin))
963 enable = TRUE;
965 if (anjuta_plugin_handle_get_name (plugin) &&
966 anjuta_plugin_handle_get_description (plugin) &&
967 (anjuta_plugin_handle_get_user_activatable (plugin) ||
968 show_all))
970 GtkTreeIter iter;
971 gchar *text;
973 text = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
974 anjuta_plugin_handle_get_name (plugin),
975 anjuta_plugin_handle_get_about (plugin));
977 gtk_list_store_append (store, &iter);
978 gtk_list_store_set (store, &iter,
979 COL_ACTIVABLE,
980 anjuta_plugin_handle_get_user_activatable (plugin),
981 COL_ENABLED, enable,
982 COL_NAME, text,
983 COL_PLUGIN, plugin,
984 -1);
985 if (anjuta_plugin_handle_get_icon_path (plugin))
987 GdkPixbuf *icon;
988 icon = gdk_pixbuf_new_from_file_at_size (anjuta_plugin_handle_get_icon_path (plugin),
989 48, 48, NULL);
990 if (icon) {
991 gtk_list_store_set (store, &iter,
992 COL_ICON, icon, -1);
993 gdk_pixbuf_unref (icon);
996 g_free (text);
1002 static GtkWidget *
1003 create_remembered_plugins_tree (void)
1005 GtkListStore *store;
1006 GtkWidget *tree;
1007 GtkCellRenderer *renderer;
1008 GtkTreeViewColumn *column;
1010 store = gtk_list_store_new (N_REM_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING,
1011 G_TYPE_STRING);
1012 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1014 column = gtk_tree_view_column_new ();
1015 renderer = gtk_cell_renderer_pixbuf_new ();
1016 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1017 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
1018 COL_REM_ICON);
1019 renderer = gtk_cell_renderer_text_new ();
1020 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1021 gtk_tree_view_column_add_attribute (column, renderer, "markup",
1022 COL_REM_NAME);
1023 gtk_tree_view_column_set_sizing (column,
1024 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1025 gtk_tree_view_column_set_title (column, _("Preferred plugins"));
1026 gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
1027 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (tree), column);
1029 g_object_unref (store);
1030 return tree;
1033 static void
1034 foreach_remembered_plugin (gpointer key, gpointer value, gpointer user_data)
1036 AnjutaPluginDescription *desc = (AnjutaPluginDescription *) value;
1037 GtkListStore *store = GTK_LIST_STORE (user_data);
1038 AnjutaPluginManager *manager = g_object_get_data (G_OBJECT (store),
1039 "plugin-manager");
1040 AnjutaPluginHandle *plugin =
1041 g_hash_table_lookup (manager->priv->plugins_by_description, desc);
1042 g_return_if_fail (plugin != NULL);
1044 if (anjuta_plugin_handle_get_name (plugin) &&
1045 anjuta_plugin_handle_get_description (plugin))
1047 GtkTreeIter iter;
1048 gchar *text;
1050 text = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
1051 anjuta_plugin_handle_get_name (plugin),
1052 anjuta_plugin_handle_get_about (plugin));
1054 gtk_list_store_append (store, &iter);
1055 gtk_list_store_set (store, &iter,
1056 COL_REM_NAME, text,
1057 COL_REM_PLUGIN_KEY, key,
1058 -1);
1059 if (anjuta_plugin_handle_get_icon_path (plugin))
1061 GdkPixbuf *icon;
1062 icon = gdk_pixbuf_new_from_file_at_size (anjuta_plugin_handle_get_icon_path (plugin),
1063 48, 48, NULL);
1064 if (icon) {
1065 gtk_list_store_set (store, &iter,
1066 COL_REM_ICON, icon, -1);
1067 gdk_pixbuf_unref (icon);
1070 g_free (text);
1074 static void
1075 populate_remembered_plugins_model (AnjutaPluginManager *plugin_manager,
1076 GtkListStore *store)
1078 AnjutaPluginManagerPriv *priv = plugin_manager->priv;
1079 gtk_list_store_clear (store);
1080 g_hash_table_foreach (priv->remember_plugins, foreach_remembered_plugin,
1081 store);
1084 static void
1085 on_show_all_plugins_toggled (GtkToggleButton *button, GtkListStore *store)
1087 AnjutaPluginManager *plugin_manager;
1089 plugin_manager = g_object_get_data (G_OBJECT (button), "__plugin_manager");
1091 populate_plugin_model (plugin_manager, store, NULL,
1092 plugin_manager->priv->activated_plugins,
1093 !gtk_toggle_button_get_active (button));
1096 static void
1097 on_forget_plugin_clicked (GtkWidget *button, GtkTreeView *view)
1099 GtkTreeIter iter;
1100 GtkTreeModel *model;
1101 GtkTreeSelection *selection = gtk_tree_view_get_selection (view);
1102 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1104 gchar *plugin_key;
1105 AnjutaPluginManager *manager = g_object_get_data (G_OBJECT (model),
1106 "plugin-manager");
1107 gtk_tree_model_get (model, &iter, COL_REM_PLUGIN_KEY, &plugin_key, -1);
1108 g_hash_table_remove (manager->priv->remember_plugins, plugin_key);
1109 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1110 g_free (plugin_key);
1114 static void
1115 on_forget_plugin_sel_changed (GtkTreeSelection *selection,
1116 GtkWidget *button)
1118 GtkTreeIter iter;
1120 if (gtk_tree_selection_get_selected (selection, NULL, &iter))
1121 gtk_widget_set_sensitive (button, TRUE);
1122 else
1123 gtk_widget_set_sensitive (button, FALSE);
1126 GtkWidget *
1127 anjuta_plugin_manager_get_plugins_page (AnjutaPluginManager *plugin_manager)
1129 GtkWidget *vbox;
1130 GtkWidget *checkbutton;
1131 GtkWidget *tree;
1132 GtkWidget *scrolled;
1133 GtkListStore *store;
1135 /* Plugins page */
1136 vbox = gtk_vbox_new (FALSE, 0);
1137 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
1139 checkbutton = gtk_check_button_new_with_label (_("Only show user activatable plugins"));
1140 gtk_container_set_border_width (GTK_CONTAINER (checkbutton), 10);
1141 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), TRUE);
1142 gtk_box_pack_start (GTK_BOX (vbox), checkbutton, FALSE, FALSE, 0);
1144 scrolled = gtk_scrolled_window_new (NULL, NULL);
1145 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
1146 GTK_SHADOW_IN);
1147 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1148 GTK_POLICY_AUTOMATIC,
1149 GTK_POLICY_AUTOMATIC);
1150 gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
1152 tree = create_plugin_tree ();
1153 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree)));
1155 populate_plugin_model (plugin_manager, store, NULL,
1156 plugin_manager->priv->activated_plugins, FALSE);
1158 gtk_container_add (GTK_CONTAINER (scrolled), tree);
1159 g_object_set_data (G_OBJECT (store), "plugin-manager", plugin_manager);
1162 g_object_set_data (G_OBJECT (checkbutton), "__plugin_manager", plugin_manager);
1163 g_signal_connect (G_OBJECT (checkbutton), "toggled",
1164 G_CALLBACK (on_show_all_plugins_toggled),
1165 store);
1166 gtk_widget_show_all (vbox);
1167 return vbox;
1170 GtkWidget *
1171 anjuta_plugin_manager_get_remembered_plugins_page (AnjutaPluginManager *plugin_manager)
1173 GtkWidget *vbox;
1174 GtkWidget *tree;
1175 GtkWidget *scrolled;
1176 GtkListStore *store;
1177 GtkWidget *hbox;
1178 GtkWidget *display_label;
1179 GtkWidget *forget_button;
1180 GtkTreeSelection *selection;
1182 /* Remembered plugin */
1183 vbox = gtk_vbox_new (FALSE, 10);
1184 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
1186 display_label = gtk_label_new (_("These are the plugins selected by you "
1187 "when Anjuta prompted to choose one of "
1188 "many suitable plugins. Removing the "
1189 "preferred plugin will let Anjuta prompt "
1190 "you again to choose different plugin."));
1191 gtk_label_set_line_wrap (GTK_LABEL (display_label), TRUE);
1192 gtk_box_pack_start (GTK_BOX (vbox), display_label, FALSE, FALSE, 0);
1194 scrolled = gtk_scrolled_window_new (NULL, NULL);
1195 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
1196 GTK_SHADOW_IN);
1197 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1198 GTK_POLICY_AUTOMATIC,
1199 GTK_POLICY_AUTOMATIC);
1200 gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
1202 tree = create_remembered_plugins_tree ();
1203 store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree)));
1205 gtk_container_add (GTK_CONTAINER (scrolled), tree);
1206 g_object_set_data (G_OBJECT (store), "plugin-manager", plugin_manager);
1207 populate_remembered_plugins_model (plugin_manager, store);
1209 hbox = gtk_hbox_new (FALSE, 0);
1210 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
1211 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1212 forget_button = gtk_button_new_with_label ("Forget selected plugin");
1213 gtk_widget_set_sensitive (forget_button, FALSE);
1214 gtk_box_pack_end (GTK_BOX (hbox), forget_button, FALSE, FALSE, 0);
1216 g_signal_connect (forget_button, "clicked",
1217 G_CALLBACK (on_forget_plugin_clicked),
1218 tree);
1219 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
1220 g_signal_connect (selection, "changed",
1221 G_CALLBACK (on_forget_plugin_sel_changed),
1222 forget_button);
1223 gtk_widget_show_all (vbox);
1224 return vbox;
1227 static GList *
1228 property_to_list (const char *value)
1230 GList *l = NULL;
1231 char **split_str;
1232 char **p;
1234 split_str = g_strsplit (value, ",", -1);
1235 for (p = split_str; *p != NULL; p++) {
1236 l = g_list_prepend (l, g_strdup (g_strstrip (*p)));
1238 g_strfreev (split_str);
1239 return l;
1242 static IAnjutaPluginFactory*
1243 get_plugin_factory (AnjutaPluginManager *plugin_manager,
1244 const gchar *language,
1245 GError **error)
1247 AnjutaPluginManagerPriv *priv;
1248 AnjutaPluginHandle *plugin;
1249 GList *loader_plugins, *node;
1250 GList *valid_plugins;
1251 GObject *obj = NULL;
1253 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), G_TYPE_INVALID);
1256 if ((language == NULL) || (g_ascii_strcasecmp (language, "C") == 0))
1258 /* Support of C plugin is built-in */
1259 return IANJUTA_PLUGIN_FACTORY (anjuta_plugin_factory);
1262 priv = plugin_manager->priv;
1263 plugin = NULL;
1265 /* Find all plugins implementing the IAnjutaPluginLoader interface. */
1266 loader_plugins = g_hash_table_lookup (priv->plugins_by_interfaces, "IAnjutaPluginLoader");
1268 /* Create a list of loader supporting this language */
1269 node = loader_plugins;
1270 valid_plugins = NULL;
1271 while (node)
1273 AnjutaPluginDescription *desc;
1274 gchar *val;
1275 GList *vals = NULL;
1276 GList *l_node;
1277 gboolean found;
1279 plugin = node->data;
1281 desc = anjuta_plugin_handle_get_description (plugin);
1282 if (anjuta_plugin_description_get_string (desc, "Plugin Loader", "SupportedLanguage", &val))
1284 if (val != NULL)
1286 vals = property_to_list (val);
1287 g_free (val);
1291 found = FALSE;
1292 l_node = vals;
1293 while (l_node)
1295 if (!found && (g_ascii_strcasecmp (l_node->data, language) == 0))
1297 found = TRUE;
1299 g_free (l_node->data);
1300 l_node = g_list_next (l_node);
1302 g_list_free (vals);
1304 if (found)
1306 valid_plugins = g_list_prepend (valid_plugins, plugin);
1309 node = g_list_next (node);
1312 /* Find the first installed plugin from the valid plugins */
1313 node = valid_plugins;
1314 while (node)
1316 plugin = node->data;
1317 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1318 if (obj) break;
1319 node = g_list_next (node);
1322 /* If no plugin is installed yet, do something */
1323 if ((obj == NULL) && valid_plugins && g_list_length (valid_plugins) == 1)
1325 /* If there is just one plugin, consider it selected */
1326 plugin = valid_plugins->data;
1328 /* Install and return it */
1329 plugin_set_update (plugin_manager, plugin, TRUE);
1330 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1332 else if ((obj == NULL) && valid_plugins)
1334 /* Prompt the user to select one of these plugins */
1336 GList *descs = NULL;
1337 node = valid_plugins;
1338 while (node)
1340 plugin = node->data;
1341 descs = g_list_prepend (descs, anjuta_plugin_handle_get_description (plugin));
1342 node = g_list_next (node);
1344 descs = g_list_reverse (descs);
1345 obj = anjuta_plugin_manager_select_and_activate (plugin_manager,
1346 _("Select a plugin"),
1347 _("Please select a plugin to activate"),
1348 descs);
1349 g_list_free (descs);
1351 g_list_free (valid_plugins);
1353 if (obj != NULL)
1355 return IANJUTA_PLUGIN_FACTORY (obj);
1358 /* No plugin implementing this interface found */
1359 g_set_error (error, ANJUTA_PLUGIN_MANAGER_ERROR,
1360 ANJUTA_PLUGIN_MANAGER_MISSING_FACTORY,
1361 _("No plugin able to load other plugins in %s"), language);
1363 return NULL;
1367 * anjuta_plugin_manager_get_plugin:
1368 * @plugin_manager: A #AnjutaPluginManager object
1369 * @iface_name: The interface implemented by the object to be found
1371 * Searches the currently available plugins to find the one which
1372 * implements the given interface as primary interface and returns it. If
1373 * the plugin is not yet loaded, it will be loaded and activated.
1374 * The returned object is garanteed to be an implementor of the
1375 * interface (as exported by the plugin metafile). It only searches
1376 * from the pool of plugin objects loaded in this shell and can only search
1377 * by primary interface. If there are more objects implementing this primary
1378 * interface, user might be prompted to select one from them (and might give
1379 * the option to use it as default for future queries). A typical usage of this
1380 * function is:
1381 * <programlisting>
1382 * GObject *docman =
1383 * anjuta_plugin_manager_get_plugin (plugin_manager, "IAnjutaDocumentManager", error);
1384 * </programlisting>
1385 * Notice that this function takes the interface name string as string, unlike
1386 * anjuta_plugins_get_interface() which takes the type directly.
1388 * Return value: The plugin object (subclass of #AnjutaPlugin) which implements
1389 * the given interface. See #AnjutaPlugin for more detail on interfaces
1390 * implemented by plugins.
1392 GObject *
1393 anjuta_plugin_manager_get_plugin (AnjutaPluginManager *plugin_manager,
1394 const gchar *iface_name)
1396 AnjutaPluginManagerPriv *priv;
1397 AnjutaPluginHandle *plugin;
1398 GList *valid_plugins, *node;
1400 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1401 g_return_val_if_fail (iface_name != NULL, NULL);
1403 priv = plugin_manager->priv;
1404 plugin = NULL;
1406 /* Find all plugins implementing this (primary) interface. */
1407 valid_plugins = g_hash_table_lookup (priv->plugins_by_interfaces, iface_name);
1409 /* Find the first installed plugin from the valid plugins */
1410 node = valid_plugins;
1411 while (node)
1413 GObject *obj;
1414 plugin = node->data;
1415 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1416 if (obj)
1417 return obj;
1418 node = g_list_next (node);
1421 /* If no plugin is installed yet, do something */
1422 if (valid_plugins && g_list_length (valid_plugins) == 1)
1424 /* If there is just one plugin, consider it selected */
1425 GObject *obj;
1426 plugin = valid_plugins->data;
1428 /* Install and return it */
1429 plugin_set_update (plugin_manager, plugin, TRUE);
1430 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1432 return obj;
1434 else if (valid_plugins)
1436 /* Prompt the user to select one of these plugins */
1437 GObject *obj;
1438 GList *descs = NULL;
1439 node = valid_plugins;
1440 while (node)
1442 plugin = node->data;
1443 descs = g_list_prepend (descs, anjuta_plugin_handle_get_description (plugin));
1444 node = g_list_next (node);
1446 descs = g_list_reverse (descs);
1447 obj = anjuta_plugin_manager_select_and_activate (plugin_manager,
1448 _("Select a plugin"),
1449 _("Please select a plugin to activate"),
1450 descs);
1451 g_list_free (descs);
1452 return obj;
1455 /* No plugin implementing this interface found */
1456 g_warning ("No plugin found implementing %s Interface.", iface_name);
1457 return NULL;
1460 GObject *
1461 anjuta_plugin_manager_get_plugin_by_id (AnjutaPluginManager *plugin_manager,
1462 const gchar *plugin_id)
1464 AnjutaPluginManagerPriv *priv;
1465 AnjutaPluginHandle *plugin;
1467 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1468 g_return_val_if_fail (plugin_id != NULL, NULL);
1470 priv = plugin_manager->priv;
1471 plugin = g_hash_table_lookup (priv->plugins_by_name, plugin_id);
1472 if (plugin)
1474 GObject *obj;
1475 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1476 if (obj)
1478 return obj;
1479 } else
1481 plugin_set_update (plugin_manager, plugin, TRUE);
1482 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1483 return obj;
1486 g_warning ("No plugin found with id \"%s\".", plugin_id);
1487 return NULL;
1490 static void
1491 on_activated_plugins_foreach (gpointer key, gpointer data, gpointer user_data)
1493 AnjutaPluginHandle *plugin = ANJUTA_PLUGIN_HANDLE (key);
1494 GList **active_plugins = (GList **)user_data;
1495 *active_plugins = g_list_prepend (*active_plugins,
1496 anjuta_plugin_handle_get_description (plugin));
1499 static void
1500 on_activated_plugin_objects_foreach (gpointer key, gpointer data, gpointer user_data)
1502 GList **active_plugins = (GList **)user_data;
1503 *active_plugins = g_list_prepend (*active_plugins,
1504 data);
1507 GList*
1508 anjuta_plugin_manager_get_active_plugins (AnjutaPluginManager *plugin_manager)
1510 GList *active_plugins = NULL;
1512 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1513 g_hash_table_foreach (plugin_manager->priv->activated_plugins,
1514 on_activated_plugins_foreach,
1515 &active_plugins);
1516 return g_list_reverse (active_plugins);
1519 GList*
1520 anjuta_plugin_manager_get_active_plugin_objects (AnjutaPluginManager *plugin_manager)
1522 GList *active_plugins = NULL;
1524 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1525 g_hash_table_foreach (plugin_manager->priv->activated_plugins,
1526 on_activated_plugin_objects_foreach,
1527 &active_plugins);
1528 return g_list_reverse (active_plugins);
1531 gboolean
1532 anjuta_plugin_manager_unload_plugin_by_id (AnjutaPluginManager *plugin_manager,
1533 const gchar *plugin_id)
1535 AnjutaPluginManagerPriv *priv;
1536 AnjutaPluginHandle *plugin;
1538 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
1539 g_return_val_if_fail (plugin_id != NULL, FALSE);
1541 priv = plugin_manager->priv;
1543 plugin = g_hash_table_lookup (priv->plugins_by_name, plugin_id);
1544 if (plugin)
1546 plugin_set_update (plugin_manager, plugin, FALSE);
1548 /* Check if the plugin has been indeed unloaded */
1549 if (!g_hash_table_lookup (priv->activated_plugins, plugin))
1550 return TRUE;
1551 else
1552 return FALSE;
1554 g_warning ("No plugin found with id \"%s\".", plugin_id);
1555 return FALSE;
1558 static gboolean
1559 find_plugin_for_object (gpointer key, gpointer value, gpointer data)
1561 if (value == data)
1563 g_object_set_data (G_OBJECT (data), "__plugin_plugin", key);
1564 return TRUE;
1566 return FALSE;
1569 gboolean
1570 anjuta_plugin_manager_unload_plugin (AnjutaPluginManager *plugin_manager,
1571 GObject *plugin_object)
1573 AnjutaPluginManagerPriv *priv;
1574 AnjutaPluginHandle *plugin;
1576 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
1577 g_return_val_if_fail (ANJUTA_IS_PLUGIN (plugin_object), FALSE);
1579 priv = plugin_manager->priv;
1581 plugin = NULL;
1583 /* Find the plugin that correspond to this plugin object */
1584 g_hash_table_find (priv->activated_plugins, find_plugin_for_object,
1585 plugin_object);
1586 plugin = g_object_get_data (G_OBJECT (plugin_object), "__plugin_plugin");
1588 if (plugin)
1590 plugin_set_update (plugin_manager, plugin, FALSE);
1592 /* Check if the plugin has been indeed unloaded */
1593 if (!g_hash_table_lookup (priv->activated_plugins, plugin))
1594 return TRUE;
1595 else
1596 return FALSE;
1598 g_warning ("No plugin found with object \"%p\".", plugin_object);
1599 return FALSE;
1602 GList*
1603 anjuta_plugin_manager_query (AnjutaPluginManager *plugin_manager,
1604 const gchar *section_name,
1605 const gchar *attribute_name,
1606 const gchar *attribute_value,
1607 ...)
1609 AnjutaPluginManagerPriv *priv;
1610 va_list var_args;
1611 GList *secs = NULL;
1612 GList *anames = NULL;
1613 GList *avalues = NULL;
1614 const gchar *sec = section_name;
1615 const gchar *aname = attribute_name;
1616 const gchar *avalue = attribute_value;
1617 GList *selected_plugins = NULL;
1618 GList *available;
1621 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1623 priv = plugin_manager->priv;
1624 available = priv->available_plugins;
1626 if (section_name == NULL)
1628 /* If no query is given, select all plugins */
1629 while (available)
1631 AnjutaPluginHandle *plugin = available->data;
1632 AnjutaPluginDescription *desc =
1633 anjuta_plugin_handle_get_description (plugin);
1634 selected_plugins = g_list_prepend (selected_plugins, desc);
1635 available = g_list_next (available);
1637 return g_list_reverse (selected_plugins);
1640 g_return_val_if_fail (section_name != NULL, NULL);
1641 g_return_val_if_fail (attribute_name != NULL, NULL);
1642 g_return_val_if_fail (attribute_value != NULL, NULL);
1644 secs = g_list_prepend (secs, g_strdup (section_name));
1645 anames = g_list_prepend (anames, g_strdup (attribute_name));
1646 avalues = g_list_prepend (avalues, g_strdup (attribute_value));
1648 va_start (var_args, attribute_value);
1649 while (sec)
1651 sec = va_arg (var_args, const gchar *);
1652 if (sec)
1654 aname = va_arg (var_args, const gchar *);
1655 if (aname)
1657 avalue = va_arg (var_args, const gchar *);
1658 if (avalue)
1660 secs = g_list_prepend (secs, g_strdup (sec));
1661 anames = g_list_prepend (anames, g_strdup (aname));
1662 avalues = g_list_prepend (avalues, g_strdup (avalue));
1667 va_end (var_args);
1669 secs = g_list_reverse (secs);
1670 anames = g_list_reverse (anames);
1671 avalues = g_list_reverse (avalues);
1673 while (available)
1675 GList* s_node = secs;
1676 GList* n_node = anames;
1677 GList* v_node = avalues;
1679 gboolean satisfied = FALSE;
1681 AnjutaPluginHandle *plugin = available->data;
1682 AnjutaPluginDescription *desc =
1683 anjuta_plugin_handle_get_description (plugin);
1685 while (s_node)
1687 gchar *val;
1688 GList *vals;
1689 GList *node;
1690 gboolean found = FALSE;
1692 satisfied = TRUE;
1694 sec = s_node->data;
1695 aname = n_node->data;
1696 avalue = v_node->data;
1698 if (!anjuta_plugin_description_get_string (desc, sec, aname, &val))
1700 satisfied = FALSE;
1701 break;
1704 vals = property_to_list (val);
1705 g_free (val);
1707 node = vals;
1708 while (node)
1710 if (strchr(node->data, '*') != NULL)
1712 // Star match.
1713 gchar **segments;
1714 gchar **seg_ptr;
1715 const gchar *cursor;
1717 segments = g_strsplit (node->data, "*", -1);
1719 seg_ptr = segments;
1720 cursor = avalue;
1721 while (*seg_ptr != NULL)
1723 if (strlen (*seg_ptr) > 0) {
1724 cursor = strstr (cursor, *seg_ptr);
1725 if (cursor == NULL)
1726 break;
1728 cursor += strlen (*seg_ptr);
1729 seg_ptr++;
1731 if (*seg_ptr == NULL)
1732 found = TRUE;
1733 g_strfreev (segments);
1735 else if (g_ascii_strcasecmp (node->data, avalue) == 0)
1737 // String match.
1738 found = TRUE;
1740 g_free (node->data);
1741 node = g_list_next (node);
1743 g_list_free (vals);
1744 if (!found)
1746 satisfied = FALSE;
1747 break;
1749 s_node = g_list_next (s_node);
1750 n_node = g_list_next (n_node);
1751 v_node = g_list_next (v_node);
1753 if (satisfied)
1755 selected_plugins = g_list_prepend (selected_plugins, desc);
1756 /* DEBUG_PRINT ("Satisfied, Adding %s",
1757 anjuta_plugin_handle_get_name (plugin));*/
1759 available = g_list_next (available);
1761 anjuta_util_glist_strings_free (secs);
1762 anjuta_util_glist_strings_free (anames);
1763 anjuta_util_glist_strings_free (avalues);
1765 return g_list_reverse (selected_plugins);
1768 enum {
1769 PIXBUF_COLUMN,
1770 PLUGIN_COLUMN,
1771 PLUGIN_DESCRIPTION_COLUMN,
1772 N_COLUMNS
1775 static void
1776 on_plugin_list_row_activated (GtkTreeView *tree_view,
1777 GtkTreePath *path,
1778 GtkTreeViewColumn *column,
1779 GtkDialog *dialog)
1781 gtk_dialog_response (dialog, GTK_RESPONSE_OK);
1784 AnjutaPluginDescription *
1785 anjuta_plugin_manager_select (AnjutaPluginManager *plugin_manager,
1786 gchar *title, gchar *description,
1787 GList *plugin_descriptions)
1789 AnjutaPluginDescription *desc;
1790 AnjutaPluginManagerPriv *priv;
1791 GtkWidget *dlg;
1792 GtkTreeModel *model;
1793 GtkWidget *view;
1794 GtkTreeViewColumn *column;
1795 GtkCellRenderer *renderer;
1796 GList *node;
1797 GtkWidget *label;
1798 GtkWidget *sc;
1799 GtkWidget *remember_checkbox;
1800 gint response;
1801 GtkTreeIter selected;
1802 GtkTreeSelection *selection;
1803 GtkTreeModel *store;
1804 GList *selection_ids = NULL;
1805 GString *remember_key = g_string_new ("");
1807 g_return_val_if_fail (title != NULL, NULL);
1808 g_return_val_if_fail (description != NULL, NULL);
1809 g_return_val_if_fail (plugin_descriptions != NULL, NULL);
1811 priv = plugin_manager->priv;
1813 if (g_list_length (plugin_descriptions) <= 0)
1814 return NULL;
1816 dlg = gtk_dialog_new_with_buttons (title, GTK_WINDOW (priv->shell),
1817 GTK_DIALOG_DESTROY_WITH_PARENT,
1818 GTK_STOCK_CANCEL,
1819 GTK_RESPONSE_CANCEL,
1820 GTK_STOCK_OK, GTK_RESPONSE_OK,
1821 NULL);
1822 gtk_widget_set_size_request (dlg, 400, 300);
1823 gtk_window_set_default_size (GTK_WINDOW (dlg), 400, 300);
1825 label = gtk_label_new (description);
1826 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1827 gtk_widget_show (label);
1828 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), label,
1829 FALSE, FALSE, 5);
1831 sc = gtk_scrolled_window_new (NULL, NULL);
1832 gtk_widget_show (sc);
1833 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sc),
1834 GTK_SHADOW_IN);
1835 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sc),
1836 GTK_POLICY_AUTOMATIC,
1837 GTK_POLICY_AUTOMATIC);
1839 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dlg)->vbox), sc,
1840 TRUE, TRUE, 5);
1842 model = GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS, GDK_TYPE_PIXBUF,
1843 G_TYPE_STRING, G_TYPE_POINTER));
1844 view = gtk_tree_view_new_with_model (model);
1845 gtk_widget_show (view);
1846 gtk_container_add (GTK_CONTAINER (sc), view);
1848 column = gtk_tree_view_column_new ();
1849 gtk_tree_view_column_set_sizing (column,
1850 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1851 gtk_tree_view_column_set_title (column, _("Available Plugins"));
1853 renderer = gtk_cell_renderer_pixbuf_new ();
1854 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1855 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
1856 PIXBUF_COLUMN);
1858 renderer = gtk_cell_renderer_text_new ();
1859 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1860 gtk_tree_view_column_add_attribute (column, renderer, "markup",
1861 PLUGIN_COLUMN);
1863 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
1864 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (view), column);
1866 g_signal_connect (view, "row-activated",
1867 G_CALLBACK (on_plugin_list_row_activated),
1868 GTK_DIALOG(dlg));
1869 remember_checkbox =
1870 gtk_check_button_new_with_label (_("Remember this selection"));
1871 gtk_container_set_border_width (GTK_CONTAINER (remember_checkbox), 10);
1872 gtk_widget_show (remember_checkbox);
1873 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dlg)->vbox), remember_checkbox,
1874 FALSE, FALSE, 0);
1876 node = plugin_descriptions;
1877 while (node)
1879 GdkPixbuf *icon_pixbuf = NULL;
1880 gchar *plugin_name = NULL;
1881 gchar *plugin_desc = NULL;
1882 gchar *icon_filename = NULL;
1883 gchar *location = NULL;
1885 desc = (AnjutaPluginDescription*)node->data;
1887 if (anjuta_plugin_description_get_string (desc,
1888 "Anjuta Plugin",
1889 "Icon",
1890 &icon_filename))
1892 gchar *icon_path = NULL;
1893 icon_path = g_strconcat (PACKAGE_PIXMAPS_DIR"/",
1894 icon_filename, NULL);
1895 /* DEBUG_PRINT ("Icon: %s", icon_path); */
1896 icon_pixbuf =
1897 gdk_pixbuf_new_from_file (icon_path, NULL);
1898 if (icon_pixbuf == NULL)
1900 g_warning ("Plugin pixmap not found: %s", plugin_name);
1902 g_free (icon_path);
1904 else
1906 g_warning ("Plugin does not define Icon attribute");
1908 if (!anjuta_plugin_description_get_locale_string (desc,
1909 "Anjuta Plugin",
1910 "Name",
1911 &plugin_name))
1913 g_warning ("Plugin does not define Name attribute");
1915 if (!anjuta_plugin_description_get_locale_string (desc,
1916 "Anjuta Plugin",
1917 "Description",
1918 &plugin_desc))
1920 g_warning ("Plugin does not define Description attribute");
1922 if (!anjuta_plugin_description_get_string (desc,
1923 "Anjuta Plugin",
1924 "Location",
1925 &location))
1927 g_warning ("Plugin does not define Location attribute");
1930 if (plugin_name && plugin_desc)
1932 GtkTreeIter iter;
1933 gchar *text;
1935 text = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s", plugin_name, plugin_desc);
1937 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1938 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1939 PLUGIN_COLUMN, text,
1940 PLUGIN_DESCRIPTION_COLUMN, desc, -1);
1941 if (icon_pixbuf) {
1942 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1943 PIXBUF_COLUMN, icon_pixbuf, -1);
1944 g_object_unref (icon_pixbuf);
1946 g_free (text);
1948 selection_ids = g_list_prepend (selection_ids, location);
1950 node = g_list_next (node);
1953 /* Prepare remembering key */
1954 selection_ids = g_list_sort (selection_ids,
1955 (GCompareFunc)strcmp);
1956 node = selection_ids;
1957 while (node)
1959 g_string_append (remember_key, (gchar*)node->data);
1960 g_string_append (remember_key, ",");
1961 node = g_list_next (node);
1963 g_list_foreach (selection_ids, (GFunc) g_free, NULL);
1964 g_list_free (selection_ids);
1966 /* Find if the selection is remembered */
1967 desc = g_hash_table_lookup (priv->remember_plugins, remember_key->str);
1968 if (desc)
1970 g_string_free (remember_key, TRUE);
1971 gtk_widget_destroy (dlg);
1972 return desc;
1975 /* Prompt dialog */
1976 response = gtk_dialog_run (GTK_DIALOG (dlg));
1977 switch (response)
1979 case GTK_RESPONSE_OK:
1980 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
1981 if (gtk_tree_selection_get_selected (selection, &store,
1982 &selected))
1984 gtk_tree_model_get (model, &selected,
1985 PLUGIN_DESCRIPTION_COLUMN, &desc, -1);
1986 if (desc)
1988 /* Remember selection */
1989 if (gtk_toggle_button_get_active
1990 (GTK_TOGGLE_BUTTON (remember_checkbox)))
1992 /* DEBUG_PRINT ("Remembering selection '%s'",
1993 remember_key->str);*/
1994 g_hash_table_insert (priv->remember_plugins,
1995 g_strdup (remember_key->str), desc);
1997 g_string_free (remember_key, TRUE);
1998 gtk_widget_destroy (dlg);
1999 return desc;
2002 break;
2004 g_string_free (remember_key, TRUE);
2005 gtk_widget_destroy (dlg);
2006 return NULL;
2009 GObject*
2010 anjuta_plugin_manager_select_and_activate (AnjutaPluginManager *plugin_manager,
2011 gchar *title,
2012 gchar *description,
2013 GList *plugin_descriptions)
2015 AnjutaPluginDescription *d;
2017 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
2019 d = anjuta_plugin_manager_select (plugin_manager, title, description,
2020 plugin_descriptions);
2021 if (d)
2023 GObject *plugin = NULL;
2024 gchar *location = NULL;
2026 anjuta_plugin_description_get_string (d,
2027 "Anjuta Plugin",
2028 "Location",
2029 &location);
2030 g_return_val_if_fail (location != NULL, NULL);
2031 plugin =
2032 anjuta_plugin_manager_get_plugin_by_id (plugin_manager, location);
2033 g_free (location);
2034 return plugin;
2036 return NULL;
2039 /* Plugin manager */
2041 static void
2042 anjuta_plugin_manager_init (AnjutaPluginManager *object)
2044 object->priv = g_new0 (AnjutaPluginManagerPriv, 1);
2045 object->priv->plugins_by_name = g_hash_table_new (g_str_hash, g_str_equal);
2046 object->priv->plugins_by_interfaces = g_hash_table_new_full (g_str_hash,
2047 g_str_equal,
2048 NULL,
2049 (GDestroyNotify) g_list_free);
2050 object->priv->plugins_by_description = g_hash_table_new (g_direct_hash,
2051 g_direct_equal);
2052 object->priv->activated_plugins = g_hash_table_new (g_direct_hash,
2053 g_direct_equal);
2054 object->priv->plugins_cache = g_hash_table_new (g_direct_hash,
2055 g_direct_equal);
2056 object->priv->remember_plugins = g_hash_table_new_full (g_str_hash,
2057 g_str_equal,
2058 g_free, NULL);
2061 static void
2062 anjuta_plugin_manager_finalize (GObject *object)
2064 AnjutaPluginManagerPriv *priv;
2065 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2066 if (priv->available_plugins)
2068 /* anjuta_plugin_manager_unload_all_plugins (ANJUTA_PLUGIN_MANAGER (object)); */
2069 g_list_foreach (priv->available_plugins, (GFunc)g_object_unref, NULL);
2070 g_list_free (priv->available_plugins);
2071 priv->available_plugins = NULL;
2073 if (priv->activated_plugins)
2075 g_hash_table_destroy (priv->activated_plugins);
2076 priv->activated_plugins = NULL;
2078 if (priv->plugins_cache)
2080 g_hash_table_destroy (priv->plugins_cache);
2081 priv->plugins_cache = NULL;
2083 if (priv->plugins_by_name)
2085 g_hash_table_destroy (priv->plugins_by_name);
2086 priv->plugins_by_name = NULL;
2088 if (priv->plugins_by_description)
2090 g_hash_table_destroy (priv->plugins_by_description);
2091 priv->plugins_by_description = NULL;
2093 if (priv->plugins_by_interfaces)
2095 g_hash_table_destroy (priv->plugins_by_interfaces);
2096 priv->plugins_by_interfaces = NULL;
2098 if (priv->plugin_dirs)
2100 g_list_foreach (priv->plugin_dirs, (GFunc)g_free, NULL);
2101 g_list_free (priv->plugin_dirs);
2102 priv->plugin_dirs = NULL;
2104 #if 0
2105 if (anjuta_c_plugin_factory)
2107 g_object_unref (anjuta_c_plugin_factory);
2108 anjuta_c_plugin_factory = NULL;
2110 #endif
2111 G_OBJECT_CLASS (parent_class)->finalize (object);
2114 static void
2115 anjuta_plugin_manager_set_property (GObject *object, guint prop_id,
2116 const GValue *value, GParamSpec *pspec)
2118 AnjutaPluginManagerPriv *priv;
2120 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object));
2121 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2123 switch (prop_id)
2125 case PROP_STATUS:
2126 priv->status = g_value_get_object (value);
2127 break;
2128 case PROP_SHELL:
2129 priv->shell = g_value_get_object (value);
2130 break;
2131 default:
2132 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2133 break;
2137 static void
2138 anjuta_plugin_manager_get_property (GObject *object, guint prop_id,
2139 GValue *value, GParamSpec *pspec)
2141 AnjutaPluginManagerPriv *priv;
2143 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object));
2144 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2146 switch (prop_id)
2148 case PROP_SHELL:
2149 g_value_set_object (value, priv->shell);
2150 break;
2151 case PROP_STATUS:
2152 g_value_set_object (value, priv->status);
2153 break;
2154 case PROP_AVAILABLE_PLUGINS:
2155 g_value_set_pointer (value, priv->available_plugins);
2156 break;
2157 case PROP_ACTIVATED_PLUGINS:
2158 g_value_set_pointer (value, priv->activated_plugins);
2159 break;
2160 default:
2161 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2162 break;
2165 static void
2166 anjuta_plugin_manager_plugin_activated (AnjutaPluginManager *self,
2167 AnjutaPluginDescription* plugin_desc,
2168 GObject *plugin)
2170 /* TODO: Add default signal handler implementation here */
2173 static void
2174 anjuta_plugin_manager_plugin_deactivated (AnjutaPluginManager *self,
2175 AnjutaPluginDescription* plugin_desc,
2176 GObject *plugin)
2178 /* TODO: Add default signal handler implementation here */
2181 static void
2182 anjuta_plugin_manager_class_init (AnjutaPluginManagerClass *klass)
2184 GObjectClass* object_class = G_OBJECT_CLASS (klass);
2185 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
2187 object_class->finalize = anjuta_plugin_manager_finalize;
2188 object_class->set_property = anjuta_plugin_manager_set_property;
2189 object_class->get_property = anjuta_plugin_manager_get_property;
2191 klass->plugin_activated = anjuta_plugin_manager_plugin_activated;
2192 klass->plugin_deactivated = anjuta_plugin_manager_plugin_deactivated;
2194 g_object_class_install_property (object_class,
2195 PROP_PROFILES,
2196 g_param_spec_pointer ("profiles",
2197 _("Profiles"),
2198 _("Current stack of profiles"),
2199 G_PARAM_READABLE));
2200 g_object_class_install_property (object_class,
2201 PROP_AVAILABLE_PLUGINS,
2202 g_param_spec_pointer ("available-plugins",
2203 _("Available plugins"),
2204 _("Currently available plugins found in plugin paths"),
2205 G_PARAM_READABLE));
2207 g_object_class_install_property (object_class,
2208 PROP_ACTIVATED_PLUGINS,
2209 g_param_spec_pointer ("activated-plugins",
2210 _("Activated plugins"),
2211 _("Currently activated plugins"),
2212 G_PARAM_READABLE));
2213 g_object_class_install_property (object_class,
2214 PROP_SHELL,
2215 g_param_spec_object ("shell",
2216 _("Anjuta Shell"),
2217 _("Anjuta shell for which the plugins are"),
2218 G_TYPE_OBJECT,
2219 G_PARAM_READABLE |
2220 G_PARAM_WRITABLE |
2221 G_PARAM_CONSTRUCT));
2222 g_object_class_install_property (object_class,
2223 PROP_STATUS,
2224 g_param_spec_object ("status",
2225 _("Anjuta Status"),
2226 _("Anjuta status to use in loading and unloading of plugins"),
2227 ANJUTA_TYPE_STATUS,
2228 G_PARAM_READABLE |
2229 G_PARAM_WRITABLE |
2230 G_PARAM_CONSTRUCT));
2232 plugin_manager_signals[PLUGIN_ACTIVATED] =
2233 g_signal_new ("plugin-activated",
2234 G_OBJECT_CLASS_TYPE (klass),
2235 G_SIGNAL_RUN_FIRST,
2236 G_STRUCT_OFFSET (AnjutaPluginManagerClass,
2237 plugin_activated),
2238 NULL, NULL,
2239 anjuta_cclosure_marshal_VOID__POINTER_OBJECT,
2240 G_TYPE_NONE, 2,
2241 G_TYPE_POINTER, ANJUTA_TYPE_PLUGIN);
2243 plugin_manager_signals[PLUGIN_DEACTIVATED] =
2244 g_signal_new ("plugin-deactivated",
2245 G_OBJECT_CLASS_TYPE (klass),
2246 G_SIGNAL_RUN_FIRST,
2247 G_STRUCT_OFFSET (AnjutaPluginManagerClass,
2248 plugin_deactivated),
2249 NULL, NULL,
2250 anjuta_cclosure_marshal_VOID__POINTER_OBJECT,
2251 G_TYPE_NONE, 2,
2252 G_TYPE_POINTER, ANJUTA_TYPE_PLUGIN);
2255 GType
2256 anjuta_plugin_manager_get_type (void)
2258 static GType our_type = 0;
2260 if(our_type == 0)
2262 static const GTypeInfo our_info =
2264 sizeof (AnjutaPluginManagerClass), /* class_size */
2265 (GBaseInitFunc) NULL, /* base_init */
2266 (GBaseFinalizeFunc) NULL, /* base_finalize */
2267 (GClassInitFunc) anjuta_plugin_manager_class_init, /* class_init */
2268 (GClassFinalizeFunc) NULL, /* class_finalize */
2269 NULL /* class_data */,
2270 sizeof (AnjutaPluginManager), /* instance_size */
2271 0, /* n_preallocs */
2272 (GInstanceInitFunc) anjuta_plugin_manager_init, /* instance_init */
2273 NULL /* value_table */
2275 our_type = g_type_register_static (G_TYPE_OBJECT,
2276 "AnjutaPluginManager",
2277 &our_info, 0);
2280 return our_type;
2283 AnjutaPluginManager*
2284 anjuta_plugin_manager_new (GObject *shell, AnjutaStatus *status,
2285 GList* plugins_directories)
2287 GObject *manager_object;
2288 AnjutaPluginManager *plugin_manager;
2289 GList *cycles = NULL;
2290 const char *gnome2_path;
2291 char **pathv;
2292 char **p;
2293 GList *node;
2294 GList *plugin_dirs = NULL;
2296 /* Initialize the anjuta plugin system */
2297 manager_object = g_object_new (ANJUTA_TYPE_PLUGIN_MANAGER,
2298 "shell", shell, "status", status, NULL);
2299 plugin_manager = ANJUTA_PLUGIN_MANAGER (manager_object);
2301 if (anjuta_plugin_factory == NULL)
2303 anjuta_plugin_factory = anjuta_c_plugin_factory_new ();
2306 gnome2_path = g_getenv ("GNOME2_PATH");
2307 if (gnome2_path) {
2308 pathv = g_strsplit (gnome2_path, ":", 1);
2310 for (p = pathv; *p != NULL; p++) {
2311 char *path = g_strdup (*p);
2312 plugin_dirs = g_list_prepend (plugin_dirs, path);
2314 g_strfreev (pathv);
2317 node = plugins_directories;
2318 while (node) {
2319 if (!node->data)
2320 continue;
2321 char *path = g_strdup (node->data);
2322 plugin_dirs = g_list_prepend (plugin_dirs, path);
2323 node = g_list_next (node);
2325 plugin_dirs = g_list_reverse (plugin_dirs);
2326 /* load_plugins (); */
2328 node = plugin_dirs;
2329 while (node)
2331 load_plugins_from_directory (plugin_manager, (char*)node->data);
2332 node = g_list_next (node);
2334 resolve_dependencies (plugin_manager, &cycles);
2335 g_list_foreach(plugin_dirs, (GFunc) g_free, NULL);
2336 g_list_free(plugin_dirs);
2337 return plugin_manager;
2340 void
2341 anjuta_plugin_manager_activate_plugins (AnjutaPluginManager *plugin_manager,
2342 GList *plugins_to_activate)
2344 AnjutaPluginManagerPriv *priv;
2345 GdkPixbuf *icon_pixbuf;
2346 GList *node;
2348 priv = plugin_manager->priv;
2350 /* Freeze shell operations */
2351 anjuta_shell_freeze (ANJUTA_SHELL (priv->shell), NULL);
2352 if (plugins_to_activate)
2354 anjuta_status_progress_add_ticks (ANJUTA_STATUS (priv->status),
2355 g_list_length (plugins_to_activate));
2357 node = plugins_to_activate;
2358 while (node)
2360 AnjutaPluginDescription *d;
2361 gchar *plugin_id;
2362 gchar *icon_filename, *label;
2363 gchar *icon_path = NULL;
2365 d = node->data;
2367 icon_pixbuf = NULL;
2368 label = NULL;
2369 if (anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2370 "Icon",
2371 &icon_filename))
2373 gchar *title /*, *description */;
2374 anjuta_plugin_description_get_locale_string (d, "Anjuta Plugin",
2375 "Name",
2376 &title);
2378 anjuta_plugin_description_get_locale_string (d, "Anjuta Plugin",
2379 "Description",
2380 &description);
2382 icon_path = g_strconcat (PACKAGE_PIXMAPS_DIR"/",
2383 icon_filename, NULL);
2384 /* DEBUG_PRINT ("Icon: %s", icon_path); */
2385 label = g_strconcat (_("Loaded: "), title, "...", NULL);
2386 icon_pixbuf = gdk_pixbuf_new_from_file (icon_path, NULL);
2387 if (!icon_pixbuf)
2388 g_warning ("Plugin does not define Icon: No such file %s",
2389 icon_path);
2390 g_free (icon_path);
2391 g_free (icon_filename);
2392 g_free (title);
2395 if (anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2396 "Location", &plugin_id))
2398 GObject *plugin_obj;
2400 plugin_obj =
2401 anjuta_plugin_manager_get_plugin_by_id (plugin_manager,
2402 plugin_id);
2403 g_free (plugin_id);
2405 anjuta_status_progress_tick (ANJUTA_STATUS (priv->status),
2406 icon_pixbuf, label);
2407 g_free (label);
2408 if (icon_pixbuf)
2409 g_object_unref (icon_pixbuf);
2411 node = g_list_next (node);
2414 /* Thaw shell operations */
2415 anjuta_shell_thaw (ANJUTA_SHELL (priv->shell), NULL);
2418 static void
2419 on_collect (gpointer key, gpointer value, gpointer user_data)
2421 gchar *id;
2422 gchar *query = (gchar*) key;
2423 AnjutaPluginDescription *desc = (AnjutaPluginDescription *) value;
2424 GString *write_buffer = (GString *) user_data;
2426 anjuta_plugin_description_get_string (desc, "Anjuta Plugin", "Location",
2427 &id);
2428 g_string_append_printf (write_buffer, "%s=%s;", query, id);
2429 g_free (id);
2432 gchar*
2433 anjuta_plugin_manager_get_remembered_plugins (AnjutaPluginManager *plugin_manager)
2435 AnjutaPluginManagerPriv *priv;
2436 GString *write_buffer = g_string_new ("");
2438 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
2440 priv = plugin_manager->priv;
2441 g_hash_table_foreach (priv->remember_plugins, on_collect,
2442 write_buffer);
2443 return g_string_free (write_buffer, FALSE);
2446 static gboolean
2447 on_foreach_remove_true (gpointer k, gpointer v, gpointer d)
2449 return TRUE;
2452 void
2453 anjuta_plugin_manager_set_remembered_plugins (AnjutaPluginManager *plugin_manager,
2454 const gchar *remembered_plugins)
2456 AnjutaPluginManagerPriv *priv;
2457 gchar **strv_lines, **line_idx;
2459 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager));
2460 g_return_if_fail (remembered_plugins != NULL);
2462 priv = plugin_manager->priv;
2464 g_hash_table_foreach_remove (priv->remember_plugins,
2465 on_foreach_remove_true, NULL);
2467 strv_lines = g_strsplit (remembered_plugins, ";", -1);
2468 line_idx = strv_lines;
2469 while (*line_idx)
2471 gchar **strv_keyvals;
2472 strv_keyvals = g_strsplit (*line_idx, "=", -1);
2473 if (strv_keyvals && strv_keyvals[0] && strv_keyvals[1])
2475 AnjutaPluginHandle *plugin;
2476 plugin = g_hash_table_lookup (priv->plugins_by_name,
2477 strv_keyvals[1]);
2478 if (plugin)
2480 AnjutaPluginDescription *desc;
2481 desc = anjuta_plugin_handle_get_description (plugin);
2483 DEBUG_PRINT ("Restoring remember plugin: %s=%s",
2484 strv_keyvals[0],
2485 strv_keyvals[1]);
2487 g_hash_table_insert (priv->remember_plugins,
2488 g_strdup (strv_keyvals[0]), desc);
2490 g_strfreev (strv_keyvals);
2492 line_idx++;
2494 g_strfreev (strv_lines);