Change directories right before the command is executed, instead of when GitCommand's
[anjuta-git-plugin.git] / libanjuta / anjuta-plugin-manager.c
blobe5177c77046e577a8a3303cc7f1b2673f193ce05
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;
1366 static void
1367 on_is_active_plugins_foreach (gpointer key, gpointer data, gpointer user_data)
1369 AnjutaPluginHandle *handle = ANJUTA_PLUGIN_HANDLE (key);
1370 gchar const **search_iface = (gchar const **)user_data;
1372 if (*search_iface != NULL)
1374 GList *interfaces;
1375 GList *found;
1377 interfaces = anjuta_plugin_handle_get_interfaces (handle);
1379 for (found = g_list_first (interfaces); found != NULL; found = g_list_next (found))
1383 found = g_list_find_custom (interfaces, *search_iface, (GCompareFunc)strcmp);
1385 if (found != NULL) *search_iface = NULL;
1390 * anjuta_plugin_manager_is_active_plugin:
1391 * @plugin_manager: A #AnjutaPluginManager object
1392 * @iface_name: The interface implemented by the object to be found
1394 * Searches if a currently loaded plugins implements
1395 * the given interface.
1397 * Return value: True is the plugin is currently loaded.
1400 gboolean
1401 anjuta_plugin_manager_is_active_plugin (AnjutaPluginManager *plugin_manager,
1402 const gchar *iface_name)
1404 const gchar *search_iface = iface_name;
1406 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
1408 g_hash_table_foreach (plugin_manager->priv->activated_plugins,
1409 on_is_active_plugins_foreach,
1410 &search_iface);
1412 return search_iface == NULL;
1416 * anjuta_plugin_manager_get_plugin:
1417 * @plugin_manager: A #AnjutaPluginManager object
1418 * @iface_name: The interface implemented by the object to be found
1420 * Searches the currently available plugins to find the one which
1421 * implements the given interface as primary interface and returns it. If
1422 * the plugin is not yet loaded, it will be loaded and activated.
1423 * The returned object is garanteed to be an implementor of the
1424 * interface (as exported by the plugin metafile). It only searches
1425 * from the pool of plugin objects loaded in this shell and can only search
1426 * by primary interface. If there are more objects implementing this primary
1427 * interface, user might be prompted to select one from them (and might give
1428 * the option to use it as default for future queries). A typical usage of this
1429 * function is:
1430 * <programlisting>
1431 * GObject *docman =
1432 * anjuta_plugin_manager_get_plugin (plugin_manager, "IAnjutaDocumentManager", error);
1433 * </programlisting>
1434 * Notice that this function takes the interface name string as string, unlike
1435 * anjuta_plugins_get_interface() which takes the type directly.
1437 * Return value: The plugin object (subclass of #AnjutaPlugin) which implements
1438 * the given interface. See #AnjutaPlugin for more detail on interfaces
1439 * implemented by plugins.
1441 GObject *
1442 anjuta_plugin_manager_get_plugin (AnjutaPluginManager *plugin_manager,
1443 const gchar *iface_name)
1445 AnjutaPluginManagerPriv *priv;
1446 AnjutaPluginHandle *plugin;
1447 GList *valid_plugins, *node;
1449 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1450 g_return_val_if_fail (iface_name != NULL, NULL);
1452 priv = plugin_manager->priv;
1453 plugin = NULL;
1455 /* Find all plugins implementing this (primary) interface. */
1456 valid_plugins = g_hash_table_lookup (priv->plugins_by_interfaces, iface_name);
1458 /* Find the first installed plugin from the valid plugins */
1459 node = valid_plugins;
1460 while (node)
1462 GObject *obj;
1463 plugin = node->data;
1464 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1465 if (obj)
1466 return obj;
1467 node = g_list_next (node);
1470 /* If no plugin is installed yet, do something */
1471 if (valid_plugins && g_list_length (valid_plugins) == 1)
1473 /* If there is just one plugin, consider it selected */
1474 GObject *obj;
1475 plugin = valid_plugins->data;
1477 /* Install and return it */
1478 plugin_set_update (plugin_manager, plugin, TRUE);
1479 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1481 return obj;
1483 else if (valid_plugins)
1485 /* Prompt the user to select one of these plugins */
1486 GObject *obj;
1487 GList *descs = NULL;
1488 node = valid_plugins;
1489 while (node)
1491 plugin = node->data;
1492 descs = g_list_prepend (descs, anjuta_plugin_handle_get_description (plugin));
1493 node = g_list_next (node);
1495 descs = g_list_reverse (descs);
1496 obj = anjuta_plugin_manager_select_and_activate (plugin_manager,
1497 _("Select a plugin"),
1498 _("Please select a plugin to activate"),
1499 descs);
1500 g_list_free (descs);
1501 return obj;
1504 /* No plugin implementing this interface found */
1505 g_warning ("No plugin found implementing %s Interface.", iface_name);
1506 return NULL;
1509 GObject *
1510 anjuta_plugin_manager_get_plugin_by_id (AnjutaPluginManager *plugin_manager,
1511 const gchar *plugin_id)
1513 AnjutaPluginManagerPriv *priv;
1514 AnjutaPluginHandle *plugin;
1516 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1517 g_return_val_if_fail (plugin_id != NULL, NULL);
1519 priv = plugin_manager->priv;
1520 plugin = g_hash_table_lookup (priv->plugins_by_name, plugin_id);
1521 if (plugin)
1523 GObject *obj;
1524 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1525 if (obj)
1527 return obj;
1528 } else
1530 plugin_set_update (plugin_manager, plugin, TRUE);
1531 obj = g_hash_table_lookup (priv->activated_plugins, plugin);
1532 return obj;
1535 g_warning ("No plugin found with id \"%s\".", plugin_id);
1536 return NULL;
1539 static void
1540 on_activated_plugins_foreach (gpointer key, gpointer data, gpointer user_data)
1542 AnjutaPluginHandle *plugin = ANJUTA_PLUGIN_HANDLE (key);
1543 GList **active_plugins = (GList **)user_data;
1544 *active_plugins = g_list_prepend (*active_plugins,
1545 anjuta_plugin_handle_get_description (plugin));
1548 static void
1549 on_activated_plugin_objects_foreach (gpointer key, gpointer data, gpointer user_data)
1551 GList **active_plugins = (GList **)user_data;
1552 *active_plugins = g_list_prepend (*active_plugins,
1553 data);
1556 GList*
1557 anjuta_plugin_manager_get_active_plugins (AnjutaPluginManager *plugin_manager)
1559 GList *active_plugins = NULL;
1561 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1562 g_hash_table_foreach (plugin_manager->priv->activated_plugins,
1563 on_activated_plugins_foreach,
1564 &active_plugins);
1565 return g_list_reverse (active_plugins);
1568 GList*
1569 anjuta_plugin_manager_get_active_plugin_objects (AnjutaPluginManager *plugin_manager)
1571 GList *active_plugins = NULL;
1573 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1574 g_hash_table_foreach (plugin_manager->priv->activated_plugins,
1575 on_activated_plugin_objects_foreach,
1576 &active_plugins);
1577 return g_list_reverse (active_plugins);
1580 gboolean
1581 anjuta_plugin_manager_unload_plugin_by_id (AnjutaPluginManager *plugin_manager,
1582 const gchar *plugin_id)
1584 AnjutaPluginManagerPriv *priv;
1585 AnjutaPluginHandle *plugin;
1587 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
1588 g_return_val_if_fail (plugin_id != NULL, FALSE);
1590 priv = plugin_manager->priv;
1592 plugin = g_hash_table_lookup (priv->plugins_by_name, plugin_id);
1593 if (plugin)
1595 plugin_set_update (plugin_manager, plugin, FALSE);
1597 /* Check if the plugin has been indeed unloaded */
1598 if (!g_hash_table_lookup (priv->activated_plugins, plugin))
1599 return TRUE;
1600 else
1601 return FALSE;
1603 g_warning ("No plugin found with id \"%s\".", plugin_id);
1604 return FALSE;
1607 static gboolean
1608 find_plugin_for_object (gpointer key, gpointer value, gpointer data)
1610 if (value == data)
1612 g_object_set_data (G_OBJECT (data), "__plugin_plugin", key);
1613 return TRUE;
1615 return FALSE;
1618 gboolean
1619 anjuta_plugin_manager_unload_plugin (AnjutaPluginManager *plugin_manager,
1620 GObject *plugin_object)
1622 AnjutaPluginManagerPriv *priv;
1623 AnjutaPluginHandle *plugin;
1625 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
1626 g_return_val_if_fail (ANJUTA_IS_PLUGIN (plugin_object), FALSE);
1628 priv = plugin_manager->priv;
1630 plugin = NULL;
1632 /* Find the plugin that correspond to this plugin object */
1633 g_hash_table_find (priv->activated_plugins, find_plugin_for_object,
1634 plugin_object);
1635 plugin = g_object_get_data (G_OBJECT (plugin_object), "__plugin_plugin");
1637 if (plugin)
1639 plugin_set_update (plugin_manager, plugin, FALSE);
1641 /* Check if the plugin has been indeed unloaded */
1642 if (!g_hash_table_lookup (priv->activated_plugins, plugin))
1643 return TRUE;
1644 else
1645 return FALSE;
1647 g_warning ("No plugin found with object \"%p\".", plugin_object);
1648 return FALSE;
1651 GList*
1652 anjuta_plugin_manager_query (AnjutaPluginManager *plugin_manager,
1653 const gchar *section_name,
1654 const gchar *attribute_name,
1655 const gchar *attribute_value,
1656 ...)
1658 AnjutaPluginManagerPriv *priv;
1659 va_list var_args;
1660 GList *secs = NULL;
1661 GList *anames = NULL;
1662 GList *avalues = NULL;
1663 const gchar *sec = section_name;
1664 const gchar *aname = attribute_name;
1665 const gchar *avalue = attribute_value;
1666 GList *selected_plugins = NULL;
1667 GList *available;
1670 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
1672 priv = plugin_manager->priv;
1673 available = priv->available_plugins;
1675 if (section_name == NULL)
1677 /* If no query is given, select all plugins */
1678 while (available)
1680 AnjutaPluginHandle *plugin = available->data;
1681 AnjutaPluginDescription *desc =
1682 anjuta_plugin_handle_get_description (plugin);
1683 selected_plugins = g_list_prepend (selected_plugins, desc);
1684 available = g_list_next (available);
1686 return g_list_reverse (selected_plugins);
1689 g_return_val_if_fail (section_name != NULL, NULL);
1690 g_return_val_if_fail (attribute_name != NULL, NULL);
1691 g_return_val_if_fail (attribute_value != NULL, NULL);
1693 secs = g_list_prepend (secs, g_strdup (section_name));
1694 anames = g_list_prepend (anames, g_strdup (attribute_name));
1695 avalues = g_list_prepend (avalues, g_strdup (attribute_value));
1697 va_start (var_args, attribute_value);
1698 while (sec)
1700 sec = va_arg (var_args, const gchar *);
1701 if (sec)
1703 aname = va_arg (var_args, const gchar *);
1704 if (aname)
1706 avalue = va_arg (var_args, const gchar *);
1707 if (avalue)
1709 secs = g_list_prepend (secs, g_strdup (sec));
1710 anames = g_list_prepend (anames, g_strdup (aname));
1711 avalues = g_list_prepend (avalues, g_strdup (avalue));
1716 va_end (var_args);
1718 secs = g_list_reverse (secs);
1719 anames = g_list_reverse (anames);
1720 avalues = g_list_reverse (avalues);
1722 while (available)
1724 GList* s_node = secs;
1725 GList* n_node = anames;
1726 GList* v_node = avalues;
1728 gboolean satisfied = FALSE;
1730 AnjutaPluginHandle *plugin = available->data;
1731 AnjutaPluginDescription *desc =
1732 anjuta_plugin_handle_get_description (plugin);
1734 while (s_node)
1736 gchar *val;
1737 GList *vals;
1738 GList *node;
1739 gboolean found = FALSE;
1741 satisfied = TRUE;
1743 sec = s_node->data;
1744 aname = n_node->data;
1745 avalue = v_node->data;
1747 if (!anjuta_plugin_description_get_string (desc, sec, aname, &val))
1749 satisfied = FALSE;
1750 break;
1753 vals = property_to_list (val);
1754 g_free (val);
1756 node = vals;
1757 while (node)
1759 if (strchr(node->data, '*') != NULL)
1761 // Star match.
1762 gchar **segments;
1763 gchar **seg_ptr;
1764 const gchar *cursor;
1766 segments = g_strsplit (node->data, "*", -1);
1768 seg_ptr = segments;
1769 cursor = avalue;
1770 while (*seg_ptr != NULL)
1772 if (strlen (*seg_ptr) > 0) {
1773 cursor = strstr (cursor, *seg_ptr);
1774 if (cursor == NULL)
1775 break;
1777 cursor += strlen (*seg_ptr);
1778 seg_ptr++;
1780 if (*seg_ptr == NULL)
1781 found = TRUE;
1782 g_strfreev (segments);
1784 else if (g_ascii_strcasecmp (node->data, avalue) == 0)
1786 // String match.
1787 found = TRUE;
1789 g_free (node->data);
1790 node = g_list_next (node);
1792 g_list_free (vals);
1793 if (!found)
1795 satisfied = FALSE;
1796 break;
1798 s_node = g_list_next (s_node);
1799 n_node = g_list_next (n_node);
1800 v_node = g_list_next (v_node);
1802 if (satisfied)
1804 selected_plugins = g_list_prepend (selected_plugins, desc);
1805 /* DEBUG_PRINT ("Satisfied, Adding %s",
1806 anjuta_plugin_handle_get_name (plugin));*/
1808 available = g_list_next (available);
1810 anjuta_util_glist_strings_free (secs);
1811 anjuta_util_glist_strings_free (anames);
1812 anjuta_util_glist_strings_free (avalues);
1814 return g_list_reverse (selected_plugins);
1817 enum {
1818 PIXBUF_COLUMN,
1819 PLUGIN_COLUMN,
1820 PLUGIN_DESCRIPTION_COLUMN,
1821 N_COLUMNS
1824 static void
1825 on_plugin_list_row_activated (GtkTreeView *tree_view,
1826 GtkTreePath *path,
1827 GtkTreeViewColumn *column,
1828 GtkDialog *dialog)
1830 gtk_dialog_response (dialog, GTK_RESPONSE_OK);
1833 AnjutaPluginDescription *
1834 anjuta_plugin_manager_select (AnjutaPluginManager *plugin_manager,
1835 gchar *title, gchar *description,
1836 GList *plugin_descriptions)
1838 AnjutaPluginDescription *desc;
1839 AnjutaPluginManagerPriv *priv;
1840 GtkWidget *dlg;
1841 GtkTreeModel *model;
1842 GtkWidget *view;
1843 GtkTreeViewColumn *column;
1844 GtkCellRenderer *renderer;
1845 GList *node;
1846 GtkWidget *label;
1847 GtkWidget *sc;
1848 GtkWidget *remember_checkbox;
1849 gint response;
1850 GtkTreeIter selected;
1851 GtkTreeSelection *selection;
1852 GtkTreeModel *store;
1853 GList *selection_ids = NULL;
1854 GString *remember_key = g_string_new ("");
1856 g_return_val_if_fail (title != NULL, NULL);
1857 g_return_val_if_fail (description != NULL, NULL);
1858 g_return_val_if_fail (plugin_descriptions != NULL, NULL);
1860 priv = plugin_manager->priv;
1862 if (g_list_length (plugin_descriptions) <= 0)
1863 return NULL;
1865 dlg = gtk_dialog_new_with_buttons (title, GTK_WINDOW (priv->shell),
1866 GTK_DIALOG_DESTROY_WITH_PARENT,
1867 GTK_STOCK_CANCEL,
1868 GTK_RESPONSE_CANCEL,
1869 GTK_STOCK_OK, GTK_RESPONSE_OK,
1870 NULL);
1871 gtk_widget_set_size_request (dlg, 400, 300);
1872 gtk_window_set_default_size (GTK_WINDOW (dlg), 400, 300);
1874 label = gtk_label_new (description);
1875 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1876 gtk_widget_show (label);
1877 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), label,
1878 FALSE, FALSE, 5);
1880 sc = gtk_scrolled_window_new (NULL, NULL);
1881 gtk_widget_show (sc);
1882 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sc),
1883 GTK_SHADOW_IN);
1884 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sc),
1885 GTK_POLICY_AUTOMATIC,
1886 GTK_POLICY_AUTOMATIC);
1888 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dlg)->vbox), sc,
1889 TRUE, TRUE, 5);
1891 model = GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS, GDK_TYPE_PIXBUF,
1892 G_TYPE_STRING, G_TYPE_POINTER));
1893 view = gtk_tree_view_new_with_model (model);
1894 gtk_widget_show (view);
1895 gtk_container_add (GTK_CONTAINER (sc), view);
1897 column = gtk_tree_view_column_new ();
1898 gtk_tree_view_column_set_sizing (column,
1899 GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1900 gtk_tree_view_column_set_title (column, _("Available Plugins"));
1902 renderer = gtk_cell_renderer_pixbuf_new ();
1903 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1904 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
1905 PIXBUF_COLUMN);
1907 renderer = gtk_cell_renderer_text_new ();
1908 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1909 gtk_tree_view_column_add_attribute (column, renderer, "markup",
1910 PLUGIN_COLUMN);
1912 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
1913 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (view), column);
1915 g_signal_connect (view, "row-activated",
1916 G_CALLBACK (on_plugin_list_row_activated),
1917 GTK_DIALOG(dlg));
1918 remember_checkbox =
1919 gtk_check_button_new_with_label (_("Remember this selection"));
1920 gtk_container_set_border_width (GTK_CONTAINER (remember_checkbox), 10);
1921 gtk_widget_show (remember_checkbox);
1922 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dlg)->vbox), remember_checkbox,
1923 FALSE, FALSE, 0);
1925 node = plugin_descriptions;
1926 while (node)
1928 GdkPixbuf *icon_pixbuf = NULL;
1929 gchar *plugin_name = NULL;
1930 gchar *plugin_desc = NULL;
1931 gchar *icon_filename = NULL;
1932 gchar *location = NULL;
1934 desc = (AnjutaPluginDescription*)node->data;
1936 if (anjuta_plugin_description_get_string (desc,
1937 "Anjuta Plugin",
1938 "Icon",
1939 &icon_filename))
1941 gchar *icon_path = NULL;
1942 icon_path = g_strconcat (PACKAGE_PIXMAPS_DIR"/",
1943 icon_filename, NULL);
1944 /* DEBUG_PRINT ("Icon: %s", icon_path); */
1945 icon_pixbuf =
1946 gdk_pixbuf_new_from_file (icon_path, NULL);
1947 if (icon_pixbuf == NULL)
1949 g_warning ("Plugin pixmap not found: %s", plugin_name);
1951 g_free (icon_path);
1953 else
1955 g_warning ("Plugin does not define Icon attribute");
1957 if (!anjuta_plugin_description_get_locale_string (desc,
1958 "Anjuta Plugin",
1959 "Name",
1960 &plugin_name))
1962 g_warning ("Plugin does not define Name attribute");
1964 if (!anjuta_plugin_description_get_locale_string (desc,
1965 "Anjuta Plugin",
1966 "Description",
1967 &plugin_desc))
1969 g_warning ("Plugin does not define Description attribute");
1971 if (!anjuta_plugin_description_get_string (desc,
1972 "Anjuta Plugin",
1973 "Location",
1974 &location))
1976 g_warning ("Plugin does not define Location attribute");
1979 if (plugin_name && plugin_desc)
1981 GtkTreeIter iter;
1982 gchar *text;
1984 text = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s", plugin_name, plugin_desc);
1986 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1987 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1988 PLUGIN_COLUMN, text,
1989 PLUGIN_DESCRIPTION_COLUMN, desc, -1);
1990 if (icon_pixbuf) {
1991 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1992 PIXBUF_COLUMN, icon_pixbuf, -1);
1993 g_object_unref (icon_pixbuf);
1995 g_free (text);
1997 selection_ids = g_list_prepend (selection_ids, location);
1999 node = g_list_next (node);
2002 /* Prepare remembering key */
2003 selection_ids = g_list_sort (selection_ids,
2004 (GCompareFunc)strcmp);
2005 node = selection_ids;
2006 while (node)
2008 g_string_append (remember_key, (gchar*)node->data);
2009 g_string_append (remember_key, ",");
2010 node = g_list_next (node);
2012 g_list_foreach (selection_ids, (GFunc) g_free, NULL);
2013 g_list_free (selection_ids);
2015 /* Find if the selection is remembered */
2016 desc = g_hash_table_lookup (priv->remember_plugins, remember_key->str);
2017 if (desc)
2019 g_string_free (remember_key, TRUE);
2020 gtk_widget_destroy (dlg);
2021 return desc;
2024 /* Prompt dialog */
2025 response = gtk_dialog_run (GTK_DIALOG (dlg));
2026 switch (response)
2028 case GTK_RESPONSE_OK:
2029 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
2030 if (gtk_tree_selection_get_selected (selection, &store,
2031 &selected))
2033 gtk_tree_model_get (model, &selected,
2034 PLUGIN_DESCRIPTION_COLUMN, &desc, -1);
2035 if (desc)
2037 /* Remember selection */
2038 if (gtk_toggle_button_get_active
2039 (GTK_TOGGLE_BUTTON (remember_checkbox)))
2041 /* DEBUG_PRINT ("Remembering selection '%s'",
2042 remember_key->str);*/
2043 g_hash_table_insert (priv->remember_plugins,
2044 g_strdup (remember_key->str), desc);
2046 g_string_free (remember_key, TRUE);
2047 gtk_widget_destroy (dlg);
2048 return desc;
2051 break;
2053 g_string_free (remember_key, TRUE);
2054 gtk_widget_destroy (dlg);
2055 return NULL;
2058 GObject*
2059 anjuta_plugin_manager_select_and_activate (AnjutaPluginManager *plugin_manager,
2060 gchar *title,
2061 gchar *description,
2062 GList *plugin_descriptions)
2064 AnjutaPluginDescription *d;
2066 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), NULL);
2068 d = anjuta_plugin_manager_select (plugin_manager, title, description,
2069 plugin_descriptions);
2070 if (d)
2072 GObject *plugin = NULL;
2073 gchar *location = NULL;
2075 anjuta_plugin_description_get_string (d,
2076 "Anjuta Plugin",
2077 "Location",
2078 &location);
2079 g_return_val_if_fail (location != NULL, NULL);
2080 plugin =
2081 anjuta_plugin_manager_get_plugin_by_id (plugin_manager, location);
2082 g_free (location);
2083 return plugin;
2085 return NULL;
2088 /* Plugin manager */
2090 static void
2091 anjuta_plugin_manager_init (AnjutaPluginManager *object)
2093 object->priv = g_new0 (AnjutaPluginManagerPriv, 1);
2094 object->priv->plugins_by_name = g_hash_table_new (g_str_hash, g_str_equal);
2095 object->priv->plugins_by_interfaces = g_hash_table_new_full (g_str_hash,
2096 g_str_equal,
2097 NULL,
2098 (GDestroyNotify) g_list_free);
2099 object->priv->plugins_by_description = g_hash_table_new (g_direct_hash,
2100 g_direct_equal);
2101 object->priv->activated_plugins = g_hash_table_new (g_direct_hash,
2102 g_direct_equal);
2103 object->priv->plugins_cache = g_hash_table_new (g_direct_hash,
2104 g_direct_equal);
2105 object->priv->remember_plugins = g_hash_table_new_full (g_str_hash,
2106 g_str_equal,
2107 g_free, NULL);
2110 static void
2111 anjuta_plugin_manager_finalize (GObject *object)
2113 AnjutaPluginManagerPriv *priv;
2114 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2115 if (priv->available_plugins)
2117 /* anjuta_plugin_manager_unload_all_plugins (ANJUTA_PLUGIN_MANAGER (object)); */
2118 g_list_foreach (priv->available_plugins, (GFunc)g_object_unref, NULL);
2119 g_list_free (priv->available_plugins);
2120 priv->available_plugins = NULL;
2122 if (priv->activated_plugins)
2124 g_hash_table_destroy (priv->activated_plugins);
2125 priv->activated_plugins = NULL;
2127 if (priv->plugins_cache)
2129 g_hash_table_destroy (priv->plugins_cache);
2130 priv->plugins_cache = NULL;
2132 if (priv->plugins_by_name)
2134 g_hash_table_destroy (priv->plugins_by_name);
2135 priv->plugins_by_name = NULL;
2137 if (priv->plugins_by_description)
2139 g_hash_table_destroy (priv->plugins_by_description);
2140 priv->plugins_by_description = NULL;
2142 if (priv->plugins_by_interfaces)
2144 g_hash_table_destroy (priv->plugins_by_interfaces);
2145 priv->plugins_by_interfaces = NULL;
2147 if (priv->plugin_dirs)
2149 g_list_foreach (priv->plugin_dirs, (GFunc)g_free, NULL);
2150 g_list_free (priv->plugin_dirs);
2151 priv->plugin_dirs = NULL;
2153 #if 0
2154 if (anjuta_c_plugin_factory)
2156 g_object_unref (anjuta_c_plugin_factory);
2157 anjuta_c_plugin_factory = NULL;
2159 #endif
2160 G_OBJECT_CLASS (parent_class)->finalize (object);
2163 static void
2164 anjuta_plugin_manager_set_property (GObject *object, guint prop_id,
2165 const GValue *value, GParamSpec *pspec)
2167 AnjutaPluginManagerPriv *priv;
2169 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object));
2170 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2172 switch (prop_id)
2174 case PROP_STATUS:
2175 priv->status = g_value_get_object (value);
2176 break;
2177 case PROP_SHELL:
2178 priv->shell = g_value_get_object (value);
2179 break;
2180 default:
2181 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2182 break;
2186 static void
2187 anjuta_plugin_manager_get_property (GObject *object, guint prop_id,
2188 GValue *value, GParamSpec *pspec)
2190 AnjutaPluginManagerPriv *priv;
2192 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object));
2193 priv = ANJUTA_PLUGIN_MANAGER (object)->priv;
2195 switch (prop_id)
2197 case PROP_SHELL:
2198 g_value_set_object (value, priv->shell);
2199 break;
2200 case PROP_STATUS:
2201 g_value_set_object (value, priv->status);
2202 break;
2203 case PROP_AVAILABLE_PLUGINS:
2204 g_value_set_pointer (value, priv->available_plugins);
2205 break;
2206 case PROP_ACTIVATED_PLUGINS:
2207 g_value_set_pointer (value, priv->activated_plugins);
2208 break;
2209 default:
2210 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2211 break;
2214 static void
2215 anjuta_plugin_manager_plugin_activated (AnjutaPluginManager *self,
2216 AnjutaPluginDescription* plugin_desc,
2217 GObject *plugin)
2219 /* TODO: Add default signal handler implementation here */
2222 static void
2223 anjuta_plugin_manager_plugin_deactivated (AnjutaPluginManager *self,
2224 AnjutaPluginDescription* plugin_desc,
2225 GObject *plugin)
2227 /* TODO: Add default signal handler implementation here */
2230 static void
2231 anjuta_plugin_manager_class_init (AnjutaPluginManagerClass *klass)
2233 GObjectClass* object_class = G_OBJECT_CLASS (klass);
2234 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
2236 object_class->finalize = anjuta_plugin_manager_finalize;
2237 object_class->set_property = anjuta_plugin_manager_set_property;
2238 object_class->get_property = anjuta_plugin_manager_get_property;
2240 klass->plugin_activated = anjuta_plugin_manager_plugin_activated;
2241 klass->plugin_deactivated = anjuta_plugin_manager_plugin_deactivated;
2243 g_object_class_install_property (object_class,
2244 PROP_PROFILES,
2245 g_param_spec_pointer ("profiles",
2246 _("Profiles"),
2247 _("Current stack of profiles"),
2248 G_PARAM_READABLE));
2249 g_object_class_install_property (object_class,
2250 PROP_AVAILABLE_PLUGINS,
2251 g_param_spec_pointer ("available-plugins",
2252 _("Available plugins"),
2253 _("Currently available plugins found in plugin paths"),
2254 G_PARAM_READABLE));
2256 g_object_class_install_property (object_class,
2257 PROP_ACTIVATED_PLUGINS,
2258 g_param_spec_pointer ("activated-plugins",
2259 _("Activated plugins"),
2260 _("Currently activated plugins"),
2261 G_PARAM_READABLE));
2262 g_object_class_install_property (object_class,
2263 PROP_SHELL,
2264 g_param_spec_object ("shell",
2265 _("Anjuta Shell"),
2266 _("Anjuta shell for which the plugins are"),
2267 G_TYPE_OBJECT,
2268 G_PARAM_READABLE |
2269 G_PARAM_WRITABLE |
2270 G_PARAM_CONSTRUCT));
2271 g_object_class_install_property (object_class,
2272 PROP_STATUS,
2273 g_param_spec_object ("status",
2274 _("Anjuta Status"),
2275 _("Anjuta status to use in loading and unloading of plugins"),
2276 ANJUTA_TYPE_STATUS,
2277 G_PARAM_READABLE |
2278 G_PARAM_WRITABLE |
2279 G_PARAM_CONSTRUCT));
2281 plugin_manager_signals[PLUGIN_ACTIVATED] =
2282 g_signal_new ("plugin-activated",
2283 G_OBJECT_CLASS_TYPE (klass),
2284 G_SIGNAL_RUN_FIRST,
2285 G_STRUCT_OFFSET (AnjutaPluginManagerClass,
2286 plugin_activated),
2287 NULL, NULL,
2288 anjuta_cclosure_marshal_VOID__POINTER_OBJECT,
2289 G_TYPE_NONE, 2,
2290 G_TYPE_POINTER, ANJUTA_TYPE_PLUGIN);
2292 plugin_manager_signals[PLUGIN_DEACTIVATED] =
2293 g_signal_new ("plugin-deactivated",
2294 G_OBJECT_CLASS_TYPE (klass),
2295 G_SIGNAL_RUN_FIRST,
2296 G_STRUCT_OFFSET (AnjutaPluginManagerClass,
2297 plugin_deactivated),
2298 NULL, NULL,
2299 anjuta_cclosure_marshal_VOID__POINTER_OBJECT,
2300 G_TYPE_NONE, 2,
2301 G_TYPE_POINTER, ANJUTA_TYPE_PLUGIN);
2304 GType
2305 anjuta_plugin_manager_get_type (void)
2307 static GType our_type = 0;
2309 if(our_type == 0)
2311 static const GTypeInfo our_info =
2313 sizeof (AnjutaPluginManagerClass), /* class_size */
2314 (GBaseInitFunc) NULL, /* base_init */
2315 (GBaseFinalizeFunc) NULL, /* base_finalize */
2316 (GClassInitFunc) anjuta_plugin_manager_class_init, /* class_init */
2317 (GClassFinalizeFunc) NULL, /* class_finalize */
2318 NULL /* class_data */,
2319 sizeof (AnjutaPluginManager), /* instance_size */
2320 0, /* n_preallocs */
2321 (GInstanceInitFunc) anjuta_plugin_manager_init, /* instance_init */
2322 NULL /* value_table */
2324 our_type = g_type_register_static (G_TYPE_OBJECT,
2325 "AnjutaPluginManager",
2326 &our_info, 0);
2329 return our_type;
2332 AnjutaPluginManager*
2333 anjuta_plugin_manager_new (GObject *shell, AnjutaStatus *status,
2334 GList* plugins_directories)
2336 GObject *manager_object;
2337 AnjutaPluginManager *plugin_manager;
2338 GList *cycles = NULL;
2339 const char *gnome2_path;
2340 char **pathv;
2341 char **p;
2342 GList *node;
2343 GList *plugin_dirs = NULL;
2345 /* Initialize the anjuta plugin system */
2346 manager_object = g_object_new (ANJUTA_TYPE_PLUGIN_MANAGER,
2347 "shell", shell, "status", status, NULL);
2348 plugin_manager = ANJUTA_PLUGIN_MANAGER (manager_object);
2350 if (anjuta_plugin_factory == NULL)
2352 anjuta_plugin_factory = anjuta_c_plugin_factory_new ();
2355 gnome2_path = g_getenv ("GNOME2_PATH");
2356 if (gnome2_path) {
2357 pathv = g_strsplit (gnome2_path, ":", 1);
2359 for (p = pathv; *p != NULL; p++) {
2360 char *path = g_strdup (*p);
2361 plugin_dirs = g_list_prepend (plugin_dirs, path);
2363 g_strfreev (pathv);
2366 node = plugins_directories;
2367 while (node) {
2368 if (!node->data)
2369 continue;
2370 char *path = g_strdup (node->data);
2371 plugin_dirs = g_list_prepend (plugin_dirs, path);
2372 node = g_list_next (node);
2374 plugin_dirs = g_list_reverse (plugin_dirs);
2375 /* load_plugins (); */
2377 node = plugin_dirs;
2378 while (node)
2380 load_plugins_from_directory (plugin_manager, (char*)node->data);
2381 node = g_list_next (node);
2383 resolve_dependencies (plugin_manager, &cycles);
2384 g_list_foreach(plugin_dirs, (GFunc) g_free, NULL);
2385 g_list_free(plugin_dirs);
2386 return plugin_manager;
2389 void
2390 anjuta_plugin_manager_activate_plugins (AnjutaPluginManager *plugin_manager,
2391 GList *plugins_to_activate)
2393 AnjutaPluginManagerPriv *priv;
2394 GdkPixbuf *icon_pixbuf;
2395 GList *node;
2397 priv = plugin_manager->priv;
2399 /* Freeze shell operations */
2400 anjuta_shell_freeze (ANJUTA_SHELL (priv->shell), NULL);
2401 if (plugins_to_activate)
2403 anjuta_status_progress_add_ticks (ANJUTA_STATUS (priv->status),
2404 g_list_length (plugins_to_activate));
2406 node = plugins_to_activate;
2407 while (node)
2409 AnjutaPluginDescription *d;
2410 gchar *plugin_id;
2411 gchar *icon_filename, *label;
2412 gchar *icon_path = NULL;
2414 d = node->data;
2416 icon_pixbuf = NULL;
2417 label = NULL;
2418 if (anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2419 "Icon",
2420 &icon_filename))
2422 gchar *title /*, *description */;
2423 anjuta_plugin_description_get_locale_string (d, "Anjuta Plugin",
2424 "Name",
2425 &title);
2427 anjuta_plugin_description_get_locale_string (d, "Anjuta Plugin",
2428 "Description",
2429 &description);
2431 icon_path = g_strconcat (PACKAGE_PIXMAPS_DIR"/",
2432 icon_filename, NULL);
2433 /* DEBUG_PRINT ("Icon: %s", icon_path); */
2434 label = g_strconcat (_("Loaded: "), title, "...", NULL);
2435 icon_pixbuf = gdk_pixbuf_new_from_file (icon_path, NULL);
2436 if (!icon_pixbuf)
2437 g_warning ("Plugin does not define Icon: No such file %s",
2438 icon_path);
2439 g_free (icon_path);
2440 g_free (icon_filename);
2441 g_free (title);
2444 if (anjuta_plugin_description_get_string (d, "Anjuta Plugin",
2445 "Location", &plugin_id))
2447 GObject *plugin_obj;
2449 plugin_obj =
2450 anjuta_plugin_manager_get_plugin_by_id (plugin_manager,
2451 plugin_id);
2452 g_free (plugin_id);
2454 anjuta_status_progress_tick (ANJUTA_STATUS (priv->status),
2455 icon_pixbuf, label);
2456 g_free (label);
2457 if (icon_pixbuf)
2458 g_object_unref (icon_pixbuf);
2460 node = g_list_next (node);
2463 /* Thaw shell operations */
2464 anjuta_shell_thaw (ANJUTA_SHELL (priv->shell), NULL);
2467 static void
2468 on_collect (gpointer key, gpointer value, gpointer user_data)
2470 gchar *id;
2471 gchar *query = (gchar*) key;
2472 AnjutaPluginDescription *desc = (AnjutaPluginDescription *) value;
2473 GString *write_buffer = (GString *) user_data;
2475 anjuta_plugin_description_get_string (desc, "Anjuta Plugin", "Location",
2476 &id);
2477 g_string_append_printf (write_buffer, "%s=%s;", query, id);
2478 g_free (id);
2481 gchar*
2482 anjuta_plugin_manager_get_remembered_plugins (AnjutaPluginManager *plugin_manager)
2484 AnjutaPluginManagerPriv *priv;
2485 GString *write_buffer = g_string_new ("");
2487 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager), FALSE);
2489 priv = plugin_manager->priv;
2490 g_hash_table_foreach (priv->remember_plugins, on_collect,
2491 write_buffer);
2492 return g_string_free (write_buffer, FALSE);
2495 static gboolean
2496 on_foreach_remove_true (gpointer k, gpointer v, gpointer d)
2498 return TRUE;
2501 void
2502 anjuta_plugin_manager_set_remembered_plugins (AnjutaPluginManager *plugin_manager,
2503 const gchar *remembered_plugins)
2505 AnjutaPluginManagerPriv *priv;
2506 gchar **strv_lines, **line_idx;
2508 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager));
2509 g_return_if_fail (remembered_plugins != NULL);
2511 priv = plugin_manager->priv;
2513 g_hash_table_foreach_remove (priv->remember_plugins,
2514 on_foreach_remove_true, NULL);
2516 strv_lines = g_strsplit (remembered_plugins, ";", -1);
2517 line_idx = strv_lines;
2518 while (*line_idx)
2520 gchar **strv_keyvals;
2521 strv_keyvals = g_strsplit (*line_idx, "=", -1);
2522 if (strv_keyvals && strv_keyvals[0] && strv_keyvals[1])
2524 AnjutaPluginHandle *plugin;
2525 plugin = g_hash_table_lookup (priv->plugins_by_name,
2526 strv_keyvals[1]);
2527 if (plugin)
2529 AnjutaPluginDescription *desc;
2530 desc = anjuta_plugin_handle_get_description (plugin);
2532 DEBUG_PRINT ("Restoring remember plugin: %s=%s",
2533 strv_keyvals[0],
2534 strv_keyvals[1]);
2536 g_hash_table_insert (priv->remember_plugins,
2537 g_strdup (strv_keyvals[0]), desc);
2539 g_strfreev (strv_keyvals);
2541 line_idx++;
2543 g_strfreev (strv_lines);