1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3 * anjuta-plugin-manager.c
4 * Copyright (C) Naba Kumar <naba@gnome.org>
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
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
34 #include <sys/types.h>
38 #include <libanjuta/anjuta-plugin-manager.h>
39 #include <libanjuta/anjuta-marshal.h>
40 #include <libanjuta/anjuta-debug.h>
41 #include <libanjuta/anjuta-plugin-handle.h>
42 #include <libanjuta/anjuta-plugin.h>
43 #include <libanjuta/anjuta-c-plugin-factory.h>
44 #include <libanjuta/interfaces/ianjuta-plugin-factory.h>
45 #include <libanjuta/interfaces/ianjuta-preferences.h>
55 PROP_AVAILABLE_PLUGINS
,
56 PROP_ACTIVATED_PLUGINS
71 struct _AnjutaPluginManagerPriv
76 GList
*available_plugins
;
78 /* Indexes => plugin handles */
79 GHashTable
*plugins_by_interfaces
;
80 GHashTable
*plugins_by_name
;
81 GHashTable
*plugins_by_description
;
83 /* Plugins that are currently activated */
84 GHashTable
*activated_plugins
;
86 /* Plugins that have been previously loaded but current deactivated */
87 GHashTable
*plugins_cache
;
89 /* Remember plugin selection */
90 GHashTable
*remember_plugins
;
93 /* Available plugins page treeview */
103 /* Remembered plugins page treeview */
111 /* Plugin class types */
113 static AnjutaCPluginFactory
*anjuta_plugin_factory
= NULL
;
115 static GObjectClass
* parent_class
= NULL
;
116 static guint plugin_manager_signals
[LAST_SIGNAL
] = { 0 };
118 static void plugin_set_update (AnjutaPluginManager
*plugin_manager
,
119 AnjutaPluginHandle
* selected_plugin
,
122 static IAnjutaPluginFactory
* get_plugin_factory (AnjutaPluginManager
*plugin_manager
,
123 const gchar
*language
, GError
**error
);
126 anjuta_plugin_manager_error_quark (void)
128 static GQuark quark
= 0;
131 quark
= g_quark_from_static_string ("anjuta-plugin-manager-quark");
136 /** Dependency Resolution **/
139 collect_cycle (AnjutaPluginManager
*plugin_manager
,
140 AnjutaPluginHandle
*base_plugin
, AnjutaPluginHandle
*cur_plugin
,
143 AnjutaPluginManagerPriv
*priv
;
146 priv
= plugin_manager
->priv
;
148 for (l
= anjuta_plugin_handle_get_dependency_names (cur_plugin
);
149 l
!= NULL
; l
= l
->next
)
151 AnjutaPluginHandle
*dep
= g_hash_table_lookup (priv
->plugins_by_name
,
155 if (dep
== base_plugin
)
157 *cycle
= g_list_prepend (NULL
, dep
);
158 /* DEBUG_PRINT ("%s", anjuta_plugin_handle_get_name (dep)); */
163 if (collect_cycle (plugin_manager
, base_plugin
, dep
, cycle
))
165 *cycle
= g_list_prepend (*cycle
, dep
);
166 /* DEBUG_PRINT ("%s", anjuta_plugin_handle_get_name (dep)); */
176 add_dependency (AnjutaPluginHandle
*dependent
, AnjutaPluginHandle
*dependency
)
178 g_hash_table_insert (anjuta_plugin_handle_get_dependents (dependency
),
179 dependent
, dependency
);
180 g_hash_table_insert (anjuta_plugin_handle_get_dependencies (dependent
),
181 dependency
, dependent
);
185 child_dep_foreach_cb (gpointer key
, gpointer value
, gpointer user_data
)
187 add_dependency (ANJUTA_PLUGIN_HANDLE (user_data
),
188 ANJUTA_PLUGIN_HANDLE (key
));
191 /* Resolves dependencies for a single module recursively. Shortcuts if
192 * the module has already been resolved. Returns a list representing
193 * any cycles found, or NULL if no cycles are found. If a cycle is found,
194 * the graph is left unresolved.
197 resolve_for_module (AnjutaPluginManager
*plugin_manager
,
198 AnjutaPluginHandle
*plugin
, int pass
)
200 AnjutaPluginManagerPriv
*priv
;
204 priv
= plugin_manager
->priv
;
206 if (anjuta_plugin_handle_get_checked (plugin
))
211 if (anjuta_plugin_handle_get_resolve_pass (plugin
) == pass
)
214 g_warning ("cycle found: %s on pass %d",
215 anjuta_plugin_handle_get_name (plugin
),
216 anjuta_plugin_handle_get_resolve_pass (plugin
));
217 collect_cycle (plugin_manager
, plugin
, plugin
, &cycle
);
221 if (anjuta_plugin_handle_get_resolve_pass (plugin
) != -1)
226 anjuta_plugin_handle_set_can_load (plugin
, TRUE
);
227 anjuta_plugin_handle_set_resolve_pass (plugin
, pass
);
229 for (l
= anjuta_plugin_handle_get_dependency_names (plugin
);
230 l
!= NULL
; l
= l
->next
)
233 AnjutaPluginHandle
*child
=
234 g_hash_table_lookup (priv
->plugins_by_name
, dep
);
237 ret
= resolve_for_module (plugin_manager
, child
, pass
);
243 /* Add the dependency's dense dependency list
244 * to the current module's dense dependency list */
245 g_hash_table_foreach (anjuta_plugin_handle_get_dependencies (child
),
246 child_dep_foreach_cb
, plugin
);
247 add_dependency (plugin
, child
);
249 /* If the child can't load due to dependency problems,
250 * the current module can't either */
251 anjuta_plugin_handle_set_can_load (plugin
,
252 anjuta_plugin_handle_get_can_load (child
));
254 g_warning ("Dependency %s not found.\n", dep
);
255 anjuta_plugin_handle_set_can_load (plugin
, FALSE
);
259 anjuta_plugin_handle_set_checked (plugin
, TRUE
);
264 /* Clean up the results of a resolving run */
266 unresolve_dependencies (AnjutaPluginManager
*plugin_manager
)
268 AnjutaPluginManagerPriv
*priv
;
271 priv
= plugin_manager
->priv
;
273 for (l
= priv
->available_plugins
; l
!= NULL
; l
= l
->next
)
275 AnjutaPluginHandle
*plugin
= l
->data
;
276 anjuta_plugin_handle_unresolve_dependencies (plugin
);
283 prune_modules (AnjutaPluginManager
*plugin_manager
, GList
*modules
)
285 AnjutaPluginManagerPriv
*priv
;
288 priv
= plugin_manager
->priv
;
290 for (l
= modules
; l
!= NULL
; l
= l
->next
) {
291 AnjutaPluginHandle
*plugin
= l
->data
;
293 g_hash_table_remove (priv
->plugins_by_name
,
294 anjuta_plugin_handle_get_id (plugin
));
295 priv
->available_plugins
= g_list_remove (priv
->available_plugins
, plugin
);
300 dependency_compare (AnjutaPluginHandle
*plugin_a
,
301 AnjutaPluginHandle
*plugin_b
)
303 int a
= g_hash_table_size (anjuta_plugin_handle_get_dependencies (plugin_a
));
304 int b
= g_hash_table_size (anjuta_plugin_handle_get_dependencies (plugin_b
));
309 /* Resolves the dependencies of the priv->available_plugins list. When this
310 * function is complete, the following will be true:
312 * 1) The dependencies and dependents hash tables of the modules will
315 * 2) Cycles in the graph will be removed.
317 * 3) Modules which cannot be loaded due to failed dependencies will
320 * 4) priv->available_plugins will be sorted such that no module depends on a
323 * If a cycle in the graph is found, it is pruned from the tree and
324 * returned as a list stored in the cycles list.
327 resolve_dependencies (AnjutaPluginManager
*plugin_manager
, GList
**cycles
)
329 AnjutaPluginManagerPriv
*priv
;
333 priv
= plugin_manager
->priv
;
336 /* Try resolving dependencies. If there is a cycle, prune the
337 * cycle and try to resolve again */
342 for (l
= priv
->available_plugins
; l
!= NULL
&& !cycle
; l
= l
->next
) {
343 cycle
= resolve_for_module (plugin_manager
, l
->data
, pass
++);
347 *cycles
= g_list_prepend (*cycles
, cycle
);
348 prune_modules (plugin_manager
, cycle
);
349 unresolve_dependencies (plugin_manager
);
353 /* Now that there is a fully resolved dependency tree, sort
354 * priv->available_plugins to create a valid load order */
355 priv
->available_plugins
= g_list_sort (priv
->available_plugins
,
356 (GCompareFunc
)dependency_compare
);
359 /* Plugins loading */
362 str_has_suffix (const char *haystack
, const char *needle
)
366 if (needle
== NULL
) {
369 if (haystack
== NULL
) {
370 return needle
[0] == '\0';
373 /* Eat one character at a time. */
374 h
= haystack
+ strlen(haystack
);
375 n
= needle
+ strlen(needle
);
383 } while (*--h
== *--n
);
388 load_plugin (AnjutaPluginManager
*plugin_manager
,
389 const gchar
*plugin_desc_path
)
391 AnjutaPluginManagerPriv
*priv
;
392 AnjutaPluginHandle
*plugin_handle
;
394 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
));
395 priv
= plugin_manager
->priv
;
397 plugin_handle
= anjuta_plugin_handle_new (plugin_desc_path
);
400 if (g_hash_table_lookup (priv
->plugins_by_name
,
401 anjuta_plugin_handle_get_id (plugin_handle
)))
403 g_object_unref (plugin_handle
);
408 /* Available plugin */
409 priv
->available_plugins
= g_list_prepend (priv
->available_plugins
,
412 g_hash_table_insert (priv
->plugins_by_name
,
413 (gchar
*)anjuta_plugin_handle_get_id (plugin_handle
),
416 /* Index by description */
417 g_hash_table_insert (priv
->plugins_by_description
,
418 anjuta_plugin_handle_get_description (plugin_handle
),
421 /* Index by interfaces exported by this plugin */
422 node
= anjuta_plugin_handle_get_interfaces (plugin_handle
);
431 objs
= (GList
*)g_hash_table_lookup (priv
->plugins_by_interfaces
, iface
);
437 if (obj_node
->data
== plugin_handle
)
442 obj_node
= g_list_next (obj_node
);
446 g_hash_table_steal (priv
->plugins_by_interfaces
, iface
);
447 objs
= g_list_prepend (objs
, plugin_handle
);
448 g_hash_table_insert (priv
->plugins_by_interfaces
, iface
, objs
);
450 node
= g_list_next (node
);
458 load_plugins_from_directory (AnjutaPluginManager
* plugin_manager
,
459 const gchar
*dirname
)
462 struct dirent
*entry
;
464 dir
= opendir (dirname
);
471 for (entry
= readdir (dir
); entry
!= NULL
; entry
= readdir (dir
))
473 if (str_has_suffix (entry
->d_name
, ".plugin"))
476 pathname
= g_strdup_printf ("%s/%s", dirname
, entry
->d_name
);
477 load_plugin (plugin_manager
,pathname
);
484 /* Plugin activation and deactivation */
487 on_plugin_activated (AnjutaPlugin
*plugin_object
, AnjutaPluginHandle
*plugin
)
489 AnjutaPluginManager
*plugin_manager
;
490 AnjutaPluginManagerPriv
*priv
;
492 /* FIXME: Pass plugin_manager directly in signal arguments */
493 plugin_manager
= anjuta_shell_get_plugin_manager (plugin_object
->shell
, NULL
);
495 g_return_if_fail(plugin_manager
!= NULL
);
497 priv
= plugin_manager
->priv
;
499 g_hash_table_insert (priv
->activated_plugins
, plugin
,
500 g_object_ref (plugin_object
));
501 g_hash_table_remove (priv
->plugins_cache
, plugin
);
503 g_signal_emit_by_name (plugin_manager
, "plugin-activated",
504 anjuta_plugin_handle_get_description (plugin
),
509 on_plugin_deactivated (AnjutaPlugin
*plugin_object
, AnjutaPluginHandle
*plugin
)
511 AnjutaPluginManager
*plugin_manager
;
512 AnjutaPluginManagerPriv
*priv
;
514 /* FIXME: Pass plugin_manager directly in signal arguments */
515 plugin_manager
= anjuta_shell_get_plugin_manager (plugin_object
->shell
, NULL
);
517 g_return_if_fail (plugin_manager
!= NULL
);
519 priv
= plugin_manager
->priv
;
521 g_hash_table_insert (priv
->plugins_cache
, plugin
, g_object_ref (plugin_object
));
522 g_hash_table_remove (priv
->activated_plugins
, plugin
);
524 g_signal_emit_by_name (plugin_manager
, "plugin-deactivated",
525 anjuta_plugin_handle_get_description (plugin
),
530 activate_plugin (AnjutaPluginManager
*plugin_manager
,
531 AnjutaPluginHandle
*handle
, GError
**error
)
533 AnjutaPluginManagerPriv
*priv
;
534 IAnjutaPluginFactory
* factory
;
535 AnjutaPlugin
*plugin
;
536 const gchar
*language
;
538 priv
= plugin_manager
->priv
;
540 language
= anjuta_plugin_handle_get_language (handle
);
542 factory
= get_plugin_factory (plugin_manager
, language
, error
);
543 if (factory
== NULL
) return NULL
;
545 plugin
= ianjuta_plugin_factory_new_plugin (factory
, handle
, ANJUTA_SHELL (priv
->shell
), error
);
551 g_signal_connect (plugin
, "activated",
552 G_CALLBACK (on_plugin_activated
), handle
);
553 g_signal_connect (plugin
, "deactivated",
554 G_CALLBACK (on_plugin_deactivated
), handle
);
560 * anjuta_plugin_manager_unload_all_plugins:
561 * @plugin_manager: A #AnjutaPluginManager object
563 * Unload all plugins. Do not take care of the dependencies because all plugins
564 * are unloaded anyway.
567 anjuta_plugin_manager_unload_all_plugins (AnjutaPluginManager
*plugin_manager
)
569 AnjutaPluginManagerPriv
*priv
;
571 priv
= plugin_manager
->priv
;
572 if (g_hash_table_size (priv
->activated_plugins
) > 0 ||
573 g_hash_table_size (priv
->plugins_cache
) > 0)
575 if (g_hash_table_size (priv
->activated_plugins
) > 0)
578 for (node
= g_list_last (priv
->available_plugins
); node
; node
= g_list_previous (node
))
580 AnjutaPluginHandle
*selected_plugin
= node
->data
;
581 AnjutaPlugin
*plugin
;
583 plugin
= g_hash_table_lookup (priv
->activated_plugins
, selected_plugin
);
586 DEBUG_PRINT ("Deactivating plugin: %s",
587 anjuta_plugin_handle_get_id (selected_plugin
));
588 anjuta_plugin_deactivate (plugin
);
591 g_hash_table_remove_all (priv
->activated_plugins
);
593 if (g_hash_table_size (priv
->plugins_cache
) > 0)
597 for (node
= g_list_last (priv
->available_plugins
); node
; node
= g_list_previous (node
))
599 AnjutaPluginHandle
*selected_plugin
= node
->data
;
601 g_hash_table_remove (priv
->plugins_cache
, selected_plugin
);
603 g_hash_table_remove_all (priv
->plugins_cache
);
608 /* Return true if plugin should be unloaded when plugin_to_unloaded is unloaded.
609 * It can be because plugin is or need plugin_to_unload. */
611 should_unload (GHashTable
*activated_plugins
, AnjutaPluginHandle
*plugin_to_unload
,
612 AnjutaPluginHandle
*plugin
)
614 GObject
*plugin_obj
= g_hash_table_lookup (activated_plugins
, plugin
);
619 if (plugin_to_unload
== plugin
)
623 GPOINTER_TO_INT (g_hash_table_lookup (anjuta_plugin_handle_get_dependents (plugin_to_unload
),
628 /* Return true if plugin should be loaded when plugin_to_loaded is loaded.
629 * It can be because plugin_to_load is or need plugin. */
631 should_load (GHashTable
*activated_plugins
, AnjutaPluginHandle
*plugin_to_load
,
632 AnjutaPluginHandle
*plugin
)
634 GObject
*plugin_obj
= g_hash_table_lookup (activated_plugins
, plugin
);
639 if (plugin_to_load
== plugin
)
640 return anjuta_plugin_handle_get_can_load (plugin
);
642 gboolean dependency
=
643 GPOINTER_TO_INT (g_hash_table_lookup (anjuta_plugin_handle_get_dependencies (plugin_to_load
),
645 return (dependency
&& anjuta_plugin_handle_get_can_load (plugin
));
648 static AnjutaPluginHandle
*
649 plugin_for_iter (GtkListStore
*store
, GtkTreeIter
*iter
)
651 AnjutaPluginHandle
*plugin
;
653 gtk_tree_model_get (GTK_TREE_MODEL (store
), iter
, COL_PLUGIN
, &plugin
, -1);
658 update_enabled (GtkTreeModel
*model
, GHashTable
*activated_plugins
)
662 if (gtk_tree_model_get_iter_first (model
, &iter
)) {
664 AnjutaPluginHandle
*plugin
;
668 plugin
= plugin_for_iter(GTK_LIST_STORE(model
), &iter
);
669 plugin_obj
= g_hash_table_lookup (activated_plugins
, plugin
);
670 installed
= (plugin_obj
!= NULL
) ? TRUE
: FALSE
;
671 gtk_tree_model_get (model
, &iter
, COL_PLUGIN
, &plugin
, -1);
672 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
673 COL_ENABLED
, installed
, -1);
674 } while (gtk_tree_model_iter_next (model
, &iter
));
679 plugin_set_update (AnjutaPluginManager
*plugin_manager
,
680 AnjutaPluginHandle
* selected_plugin
,
683 AnjutaPluginManagerPriv
*priv
;
687 priv
= plugin_manager
->priv
;
689 /* Plugins can be loaded or unloaded implicitely because they need or are
690 * needed by another plugin so it is possible that we try to load or unload
691 * respectively an already loaded or already unloaded plugin. */
692 loaded
= g_hash_table_lookup (priv
->activated_plugins
, selected_plugin
) != NULL
;
693 if ((load
&& loaded
) || (!load
&& !loaded
)) return;
696 anjuta_status_busy_push (priv
->status
);
700 /* visit priv->available_plugins in reverse order when unloading, so
701 * that plugins are unloaded in the right order */
702 for (l
= g_list_last(priv
->available_plugins
); l
!= NULL
; l
= l
->prev
)
704 AnjutaPluginHandle
*plugin
= l
->data
;
705 if (should_unload (priv
->activated_plugins
, selected_plugin
, plugin
))
707 AnjutaPlugin
*plugin_obj
= ANJUTA_PLUGIN (g_hash_table_lookup (priv
->activated_plugins
, plugin
));
708 if (!anjuta_plugin_deactivate (plugin_obj
))
710 anjuta_util_dialog_info (GTK_WINDOW (priv
->shell
),
711 dgettext (GETTEXT_PACKAGE
, "Plugin '%s' does not want to be deactivated"),
712 anjuta_plugin_handle_get_name (plugin
));
719 for (l
= priv
->available_plugins
; l
!= NULL
; l
= l
->next
)
721 AnjutaPluginHandle
*plugin
= l
->data
;
722 if (should_load (priv
->activated_plugins
, selected_plugin
, plugin
))
724 AnjutaPlugin
*plugin_obj
;
725 GError
*error
= NULL
;
726 plugin_obj
= g_hash_table_lookup (priv
->plugins_cache
, plugin
);
728 g_object_ref (plugin_obj
);
731 plugin_obj
= activate_plugin (plugin_manager
, plugin
,
737 anjuta_plugin_activate (ANJUTA_PLUGIN (plugin_obj
));
738 g_object_unref (plugin_obj
);
744 gchar
* message
= g_strdup_printf (dgettext (GETTEXT_PACKAGE
, "Could not load %s\n"
745 "This usually means that your installation is corrupted. The "
746 "error message leading to this was:\n%s"),
747 anjuta_plugin_handle_get_name (selected_plugin
),
749 anjuta_util_dialog_error (GTK_WINDOW(plugin_manager
->priv
->shell
),
751 g_error_free (error
);
759 anjuta_status_busy_pop (priv
->status
);
765 plugin_toggled (GtkCellRendererToggle
*cell
, char *path_str
, gpointer data
)
767 AnjutaPluginManager
*plugin_manager
;
768 AnjutaPluginManagerPriv
*priv
;
769 GtkListStore
*store
= GTK_LIST_STORE (data
);
772 AnjutaPluginHandle
*plugin
;
774 GList
*activated_plugins
;
776 AnjutaPlugin
* plugin_object
;
778 path
= gtk_tree_path_new_from_string (path_str
);
780 plugin_manager
= g_object_get_data (G_OBJECT (store
), "plugin-manager");
781 priv
= plugin_manager
->priv
;
783 gtk_tree_model_get_iter (GTK_TREE_MODEL (store
), &iter
, path
);
784 gtk_tree_model_get (GTK_TREE_MODEL (store
), &iter
,
785 COL_ENABLED
, &enabled
,
789 /* Activate one plugin can force the loading of other ones, instead of
790 * searching which plugins have to be activated, we just unmerge all
791 * current plugins and merge all plugins after the modification */
793 /* unmerge all plugins */
794 activated_plugins
= g_hash_table_get_values (priv
->activated_plugins
);
795 for (node
= g_list_first (activated_plugins
); node
!= NULL
; node
= g_list_next (node
))
797 plugin_object
= (AnjutaPlugin
*)node
->data
;
799 IANJUTA_IS_PREFERENCES(plugin_object
))
801 ianjuta_preferences_unmerge (IANJUTA_PREFERENCES (plugin_object
),
802 anjuta_shell_get_preferences (ANJUTA_SHELL (priv
->shell
), NULL
),
806 g_list_free (activated_plugins
);
808 plugin_set_update (plugin_manager
, plugin
, !enabled
);
810 /* Make sure that it appears in the preferences. This method
811 can only be called when the preferences dialog is active so
814 activated_plugins
= g_hash_table_get_values (priv
->activated_plugins
);
815 for (node
= g_list_first (activated_plugins
); node
!= NULL
; node
= g_list_next (node
))
817 plugin_object
= (AnjutaPlugin
*)node
->data
;
819 IANJUTA_IS_PREFERENCES(plugin_object
))
821 ianjuta_preferences_merge (IANJUTA_PREFERENCES (plugin_object
),
822 anjuta_shell_get_preferences (ANJUTA_SHELL (priv
->shell
), NULL
),
826 g_list_free (activated_plugins
);
828 update_enabled (GTK_TREE_MODEL (store
), priv
->activated_plugins
);
829 gtk_tree_path_free (path
);
834 selection_changed (GtkTreeSelection
*selection
, GtkListStore
*store
)
838 if (gtk_tree_selection_get_selected (selection
, NULL
,
840 GtkTextBuffer
*buffer
;
842 GtkWidget
*txt
= g_object_get_data (G_OBJECT (store
),
845 GtkWidget
*image
= g_object_get_data (G_OBJECT (store
),
847 AnjutaPluginHandle
*plugin
= plugin_for_iter (store
, &iter
);
849 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (txt
));
850 gtk_text_buffer_set_text (buffer
, plugin
->about
, -1);
852 if (plugin
->icon_path
) {
853 gtk_image_set_from_file (GTK_IMAGE (image
),
855 gtk_widget_show (GTK_WIDGET (image
));
857 gtk_widget_hide (GTK_WIDGET (image
));
864 create_plugin_tree (void)
868 GtkCellRenderer
*renderer
;
869 GtkTreeViewColumn
*column
;
871 store
= gtk_list_store_new (N_COLS
,
877 tree
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (store
));
879 renderer
= gtk_cell_renderer_toggle_new ();
880 g_signal_connect (G_OBJECT (renderer
), "toggled",
881 G_CALLBACK (plugin_toggled
), store
);
882 column
= gtk_tree_view_column_new_with_attributes (dgettext (GETTEXT_PACKAGE
, "Load"),
889 gtk_tree_view_append_column (GTK_TREE_VIEW (tree
), column
);
890 gtk_tree_view_column_set_sizing (column
,
891 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
893 column
= gtk_tree_view_column_new ();
894 renderer
= gtk_cell_renderer_pixbuf_new ();
895 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
896 gtk_tree_view_column_add_attribute (column
, renderer
, "pixbuf",
898 renderer
= gtk_cell_renderer_text_new ();
899 g_object_set(renderer
, "ellipsize", PANGO_ELLIPSIZE_END
, NULL
);
900 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
901 gtk_tree_view_column_add_attribute (column
, renderer
, "markup",
903 gtk_tree_view_column_set_sizing (column
,
904 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
905 gtk_tree_view_column_set_title (column
, dgettext (GETTEXT_PACKAGE
, "Available Plugins"));
906 gtk_tree_view_append_column (GTK_TREE_VIEW (tree
), column
);
907 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (tree
), column
);
909 g_object_unref (store
);
913 /* Sort function for plugins */
915 sort_plugins(gconstpointer a
, gconstpointer b
)
917 g_return_val_if_fail (a
!= NULL
, 0);
918 g_return_val_if_fail (b
!= NULL
, 0);
920 AnjutaPluginHandle
* plugin_a
= ANJUTA_PLUGIN_HANDLE (a
);
921 AnjutaPluginHandle
* plugin_b
= ANJUTA_PLUGIN_HANDLE (b
);
923 return strcmp (anjuta_plugin_handle_get_name (plugin_a
),
924 anjuta_plugin_handle_get_name (plugin_b
));
927 /* If show_all == FALSE, show only user activatable plugins
928 * If show_all == TRUE, show all plugins
931 populate_plugin_model (AnjutaPluginManager
*plugin_manager
,
933 GHashTable
*plugins_to_show
,
934 GHashTable
*activated_plugins
,
937 AnjutaPluginManagerPriv
*priv
;
938 GList
*sorted_plugins
, *l
;
940 priv
= plugin_manager
->priv
;
941 gtk_list_store_clear (store
);
943 sorted_plugins
= g_list_copy (priv
->available_plugins
);
944 sorted_plugins
= g_list_sort (sorted_plugins
, sort_plugins
);
946 for (l
= sorted_plugins
; l
!= NULL
; l
= l
->next
)
948 AnjutaPluginHandle
*plugin
= l
->data
;
950 /* If plugins to show is NULL, show all available plugins */
951 if (plugins_to_show
== NULL
||
952 g_hash_table_lookup (plugins_to_show
, plugin
))
955 gboolean enable
= FALSE
;
956 if (g_hash_table_lookup (activated_plugins
, plugin
))
959 if (anjuta_plugin_handle_get_name (plugin
) &&
960 anjuta_plugin_handle_get_description (plugin
) &&
961 (anjuta_plugin_handle_get_user_activatable (plugin
) ||
967 text
= g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
968 anjuta_plugin_handle_get_name (plugin
),
969 anjuta_plugin_handle_get_about (plugin
));
971 gtk_list_store_append (store
, &iter
);
972 gtk_list_store_set (store
, &iter
,
974 anjuta_plugin_handle_get_user_activatable (plugin
),
979 if (anjuta_plugin_handle_get_icon_path (plugin
))
982 icon
= gdk_pixbuf_new_from_file_at_size (anjuta_plugin_handle_get_icon_path (plugin
),
985 gtk_list_store_set (store
, &iter
,
987 g_object_unref (icon
);
995 g_list_free (sorted_plugins
);
999 create_remembered_plugins_tree (void)
1001 GtkListStore
*store
;
1003 GtkCellRenderer
*renderer
;
1004 GtkTreeViewColumn
*column
;
1006 store
= gtk_list_store_new (N_REM_COLS
, GDK_TYPE_PIXBUF
, G_TYPE_STRING
,
1008 tree
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (store
));
1010 column
= gtk_tree_view_column_new ();
1011 renderer
= gtk_cell_renderer_pixbuf_new ();
1012 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
1013 gtk_tree_view_column_add_attribute (column
, renderer
, "pixbuf",
1015 renderer
= gtk_cell_renderer_text_new ();
1016 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
1017 gtk_tree_view_column_add_attribute (column
, renderer
, "markup",
1019 gtk_tree_view_column_set_sizing (column
,
1020 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
1021 gtk_tree_view_column_set_title (column
, dgettext (GETTEXT_PACKAGE
, "Preferred plugins"));
1022 gtk_tree_view_append_column (GTK_TREE_VIEW (tree
), column
);
1023 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (tree
), column
);
1025 g_object_unref (store
);
1030 foreach_remembered_plugin (gpointer key
, gpointer value
, gpointer user_data
)
1032 AnjutaPluginDescription
*desc
= (AnjutaPluginDescription
*) value
;
1033 GtkListStore
*store
= GTK_LIST_STORE (user_data
);
1034 AnjutaPluginManager
*manager
= g_object_get_data (G_OBJECT (store
),
1036 AnjutaPluginHandle
*plugin
=
1037 g_hash_table_lookup (manager
->priv
->plugins_by_description
, desc
);
1038 g_return_if_fail (plugin
!= NULL
);
1040 if (anjuta_plugin_handle_get_name (plugin
) &&
1041 anjuta_plugin_handle_get_description (plugin
))
1046 text
= g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
1047 anjuta_plugin_handle_get_name (plugin
),
1048 anjuta_plugin_handle_get_about (plugin
));
1050 gtk_list_store_append (store
, &iter
);
1051 gtk_list_store_set (store
, &iter
,
1053 COL_REM_PLUGIN_KEY
, key
,
1055 if (anjuta_plugin_handle_get_icon_path (plugin
))
1058 icon
= gdk_pixbuf_new_from_file_at_size (anjuta_plugin_handle_get_icon_path (plugin
),
1061 gtk_list_store_set (store
, &iter
,
1062 COL_REM_ICON
, icon
, -1);
1063 g_object_unref (icon
);
1071 populate_remembered_plugins_model (AnjutaPluginManager
*plugin_manager
,
1072 GtkListStore
*store
)
1074 AnjutaPluginManagerPriv
*priv
= plugin_manager
->priv
;
1075 gtk_list_store_clear (store
);
1076 g_hash_table_foreach (priv
->remember_plugins
, foreach_remembered_plugin
,
1081 on_show_all_plugins_toggled (GtkToggleButton
*button
, GtkListStore
*store
)
1083 AnjutaPluginManager
*plugin_manager
;
1085 plugin_manager
= g_object_get_data (G_OBJECT (button
), "__plugin_manager");
1087 populate_plugin_model (plugin_manager
, store
, NULL
,
1088 plugin_manager
->priv
->activated_plugins
,
1089 !gtk_toggle_button_get_active (button
));
1093 on_forget_plugin_clicked (GtkWidget
*button
, GtkTreeView
*view
)
1096 GtkTreeModel
*model
;
1097 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (view
);
1098 if (gtk_tree_selection_get_selected (selection
, &model
, &iter
))
1101 AnjutaPluginManager
*manager
= g_object_get_data (G_OBJECT (model
),
1103 gtk_tree_model_get (model
, &iter
, COL_REM_PLUGIN_KEY
, &plugin_key
, -1);
1104 g_hash_table_remove (manager
->priv
->remember_plugins
, plugin_key
);
1105 gtk_list_store_remove (GTK_LIST_STORE (model
), &iter
);
1106 g_free (plugin_key
);
1111 on_forget_plugin_sel_changed (GtkTreeSelection
*selection
,
1116 if (gtk_tree_selection_get_selected (selection
, NULL
, &iter
))
1117 gtk_widget_set_sensitive (button
, TRUE
);
1119 gtk_widget_set_sensitive (button
, FALSE
);
1123 anjuta_plugin_manager_get_plugins_page (AnjutaPluginManager
*plugin_manager
)
1126 GtkWidget
*checkbutton
;
1128 GtkWidget
*scrolled
;
1130 GtkToolItem
*toolitem
;
1131 GtkListStore
*store
;
1134 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
1135 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 6);
1137 scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
1138 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled
),
1140 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
),
1142 GTK_POLICY_AUTOMATIC
);
1143 gtk_style_context_set_junction_sides (gtk_widget_get_style_context (scrolled
), GTK_JUNCTION_BOTTOM
);
1144 gtk_box_pack_start (GTK_BOX (vbox
), scrolled
, TRUE
, TRUE
, 0);
1146 toolbar
= gtk_toolbar_new ();
1147 gtk_style_context_add_class (gtk_widget_get_style_context (toolbar
), GTK_STYLE_CLASS_INLINE_TOOLBAR
);
1148 gtk_style_context_set_junction_sides (gtk_widget_get_style_context (toolbar
), GTK_JUNCTION_TOP
);
1149 gtk_box_pack_start (GTK_BOX (vbox
), toolbar
, FALSE
, FALSE
, 0);
1150 gtk_widget_show (toolbar
);
1152 toolitem
= gtk_tool_item_new ();
1153 gtk_toolbar_insert (GTK_TOOLBAR (toolbar
), GTK_TOOL_ITEM (toolitem
), 0);
1154 gtk_widget_show (GTK_WIDGET(toolitem
));
1156 checkbutton
= gtk_check_button_new_with_label (dgettext (GETTEXT_PACKAGE
, "Only show user activatable plugins"));
1157 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton
), TRUE
);
1158 gtk_container_add (GTK_CONTAINER (toolitem
), checkbutton
);
1160 tree
= create_plugin_tree ();
1161 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree
), TRUE
);
1162 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree
), FALSE
);
1163 store
= GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree
)));
1165 populate_plugin_model (plugin_manager
, store
, NULL
,
1166 plugin_manager
->priv
->activated_plugins
, FALSE
);
1168 gtk_container_add (GTK_CONTAINER (scrolled
), tree
);
1169 g_object_set_data (G_OBJECT (store
), "plugin-manager", plugin_manager
);
1172 g_object_set_data (G_OBJECT (checkbutton
), "__plugin_manager", plugin_manager
);
1173 g_signal_connect (G_OBJECT (checkbutton
), "toggled",
1174 G_CALLBACK (on_show_all_plugins_toggled
),
1176 gtk_widget_show_all (vbox
);
1181 anjuta_plugin_manager_get_remembered_plugins_page (AnjutaPluginManager
*plugin_manager
)
1185 GtkWidget
*scrolled
;
1186 GtkListStore
*store
;
1188 GtkWidget
*display_label
;
1189 GtkWidget
*forget_button
;
1190 GtkTreeSelection
*selection
;
1192 /* Remembered plugin */
1193 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 10);
1194 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 10);
1196 display_label
= gtk_label_new (dgettext (GETTEXT_PACKAGE
, "These are the plugins selected by you "
1197 "when you have been prompted to choose one of "
1198 "many suitable plugins. Removing the "
1199 "preferred plugin will let you "
1200 "choose a different plugin."));
1201 gtk_label_set_line_wrap (GTK_LABEL (display_label
), TRUE
);
1202 gtk_box_pack_start (GTK_BOX (vbox
), display_label
, FALSE
, FALSE
, 0);
1204 scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
1205 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled
),
1207 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
),
1208 GTK_POLICY_AUTOMATIC
,
1209 GTK_POLICY_AUTOMATIC
);
1210 gtk_box_pack_start (GTK_BOX (vbox
), scrolled
, TRUE
, TRUE
, 0);
1212 tree
= create_remembered_plugins_tree ();
1213 store
= GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree
)));
1215 gtk_container_add (GTK_CONTAINER (scrolled
), tree
);
1216 g_object_set_data (G_OBJECT (store
), "plugin-manager", plugin_manager
);
1217 populate_remembered_plugins_model (plugin_manager
, store
);
1219 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 0);
1220 gtk_container_set_border_width (GTK_CONTAINER (hbox
), 5);
1221 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 0);
1222 forget_button
= gtk_button_new_with_label (dgettext (GETTEXT_PACKAGE
, "Forget selected plugin"));
1223 gtk_widget_set_sensitive (forget_button
, FALSE
);
1224 gtk_box_pack_end (GTK_BOX (hbox
), forget_button
, FALSE
, FALSE
, 0);
1226 g_signal_connect (forget_button
, "clicked",
1227 G_CALLBACK (on_forget_plugin_clicked
),
1229 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (tree
));
1230 g_signal_connect (selection
, "changed",
1231 G_CALLBACK (on_forget_plugin_sel_changed
),
1233 gtk_widget_show_all (vbox
);
1238 property_to_list (const char *value
)
1244 split_str
= g_strsplit (value
, ",", -1);
1245 for (p
= split_str
; *p
!= NULL
; p
++) {
1246 l
= g_list_prepend (l
, g_strdup (g_strstrip (*p
)));
1248 g_strfreev (split_str
);
1252 static IAnjutaPluginFactory
*
1253 get_plugin_factory (AnjutaPluginManager
*plugin_manager
,
1254 const gchar
*language
,
1257 AnjutaPluginManagerPriv
*priv
;
1258 AnjutaPluginHandle
*plugin
;
1259 GList
*loader_plugins
, *node
;
1260 GList
*valid_plugins
;
1261 GObject
*obj
= NULL
;
1263 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), G_TYPE_INVALID
);
1266 if ((language
== NULL
) || (g_ascii_strcasecmp (language
, "C") == 0))
1268 /* Support of C plugin is built-in */
1269 return IANJUTA_PLUGIN_FACTORY (anjuta_plugin_factory
);
1272 priv
= plugin_manager
->priv
;
1275 /* Find all plugins implementing the IAnjutaPluginLoader interface. */
1276 loader_plugins
= g_hash_table_lookup (priv
->plugins_by_interfaces
, "IAnjutaPluginLoader");
1278 /* Create a list of loader supporting this language */
1279 node
= loader_plugins
;
1280 valid_plugins
= NULL
;
1283 AnjutaPluginDescription
*desc
;
1289 plugin
= node
->data
;
1291 desc
= anjuta_plugin_handle_get_description (plugin
);
1292 if (anjuta_plugin_description_get_string (desc
, "Plugin Loader", "SupportedLanguage", &val
))
1296 vals
= property_to_list (val
);
1305 if (!found
&& (g_ascii_strcasecmp (l_node
->data
, language
) == 0))
1309 g_free (l_node
->data
);
1310 l_node
= g_list_next (l_node
);
1316 valid_plugins
= g_list_prepend (valid_plugins
, plugin
);
1319 node
= g_list_next (node
);
1322 /* Find the first installed plugin from the valid plugins */
1323 node
= valid_plugins
;
1326 plugin
= node
->data
;
1327 obj
= g_hash_table_lookup (priv
->activated_plugins
, plugin
);
1329 node
= g_list_next (node
);
1332 /* If no plugin is installed yet, do something */
1333 if ((obj
== NULL
) && valid_plugins
&& g_list_length (valid_plugins
) == 1)
1335 /* If there is just one plugin, consider it selected */
1336 plugin
= valid_plugins
->data
;
1338 /* Install and return it */
1339 plugin_set_update (plugin_manager
, plugin
, TRUE
);
1340 obj
= g_hash_table_lookup (priv
->activated_plugins
, plugin
);
1342 else if ((obj
== NULL
) && valid_plugins
)
1344 /* Prompt the user to select one of these plugins */
1346 GList
*descs
= NULL
;
1347 node
= valid_plugins
;
1350 plugin
= node
->data
;
1351 descs
= g_list_prepend (descs
, anjuta_plugin_handle_get_description (plugin
));
1352 node
= g_list_next (node
);
1354 descs
= g_list_reverse (descs
);
1355 obj
= anjuta_plugin_manager_select_and_activate (plugin_manager
,
1356 dgettext (GETTEXT_PACKAGE
, "Select a plugin"),
1357 dgettext (GETTEXT_PACKAGE
, "Please select a plugin to activate"),
1359 g_list_free (descs
);
1361 g_list_free (valid_plugins
);
1365 return IANJUTA_PLUGIN_FACTORY (obj
);
1368 /* No plugin implementing this interface found */
1369 g_set_error (error
, ANJUTA_PLUGIN_MANAGER_ERROR
,
1370 ANJUTA_PLUGIN_MANAGER_MISSING_FACTORY
,
1371 dgettext (GETTEXT_PACKAGE
, "No plugin is able to load other plugins in %s"), language
);
1377 on_is_active_plugins_foreach (gpointer key
, gpointer data
, gpointer user_data
)
1379 AnjutaPluginHandle
*handle
= ANJUTA_PLUGIN_HANDLE (key
);
1380 gchar
const **search_iface
= (gchar
const **)user_data
;
1382 if (*search_iface
!= NULL
)
1387 interfaces
= anjuta_plugin_handle_get_interfaces (handle
);
1389 for (found
= g_list_first (interfaces
); found
!= NULL
; found
= g_list_next (found
))
1393 found
= g_list_find_custom (interfaces
, *search_iface
, (GCompareFunc
)strcmp
);
1395 if (found
!= NULL
) *search_iface
= NULL
;
1400 * anjuta_plugin_manager_is_active_plugin:
1401 * @plugin_manager: A #AnjutaPluginManager object
1402 * @iface_name: The interface implemented by the object to be found
1404 * Searches if a currently loaded plugins implements
1405 * the given interface.
1407 * Return value: True is the plugin is currently loaded.
1411 anjuta_plugin_manager_is_active_plugin (AnjutaPluginManager
*plugin_manager
,
1412 const gchar
*iface_name
)
1414 const gchar
*search_iface
= iface_name
;
1416 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), FALSE
);
1418 g_hash_table_foreach (plugin_manager
->priv
->activated_plugins
,
1419 on_is_active_plugins_foreach
,
1422 return search_iface
== NULL
;
1426 * anjuta_plugin_manager_get_plugin:
1427 * @plugin_manager: A #AnjutaPluginManager object
1428 * @iface_name: The interface implemented by the object to be found
1430 * Searches the currently available plugins to find the one which
1431 * implements the given interface as primary interface and returns it. If
1432 * the plugin is not yet loaded, it will be loaded and activated.
1434 * from the pool of plugin objects loaded in this shell and can only search
1435 * by primary interface. If there are more objects implementing this primary
1436 * interface, user might be prompted to select one from them (and might give
1437 * the option to use it as default for future queries). A typical usage of this
1441 * anjuta_plugin_manager_get_plugin (plugin_manager, "IAnjutaDocumentManager", error);
1443 * Notice that this function takes the interface name string as string, unlike
1444 * anjuta_plugins_get_interface() which takes the type directly.
1445 * If no plugin implementing this interface can be found, returns NULL.
1447 * Return value: The plugin object (subclass of #AnjutaPlugin) which implements
1448 * the given interface or NULL. See #AnjutaPlugin for more detail on interfaces
1449 * implemented by plugins.
1452 anjuta_plugin_manager_get_plugin (AnjutaPluginManager
*plugin_manager
,
1453 const gchar
*iface_name
)
1455 AnjutaPluginManagerPriv
*priv
;
1456 AnjutaPluginHandle
*plugin
;
1457 GList
*valid_plugins
, *node
;
1459 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
1460 g_return_val_if_fail (iface_name
!= NULL
, NULL
);
1462 priv
= plugin_manager
->priv
;
1465 /* Find all plugins implementing this (primary) interface. */
1466 valid_plugins
= g_hash_table_lookup (priv
->plugins_by_interfaces
, iface_name
);
1468 /* Find the first installed plugin from the valid plugins */
1469 node
= valid_plugins
;
1473 plugin
= node
->data
;
1474 obj
= g_hash_table_lookup (priv
->activated_plugins
, plugin
);
1477 node
= g_list_next (node
);
1480 /* If no plugin is installed yet, do something */
1481 if (valid_plugins
&& g_list_length (valid_plugins
) == 1)
1483 /* If there is just one plugin, consider it selected */
1485 plugin
= valid_plugins
->data
;
1487 /* Install and return it */
1488 plugin_set_update (plugin_manager
, plugin
, TRUE
);
1489 obj
= g_hash_table_lookup (priv
->activated_plugins
, plugin
);
1493 else if (valid_plugins
)
1495 /* Prompt the user to select one of these plugins */
1497 GList
*descs
= NULL
;
1498 node
= valid_plugins
;
1501 plugin
= node
->data
;
1502 descs
= g_list_prepend (descs
, anjuta_plugin_handle_get_description (plugin
));
1503 node
= g_list_next (node
);
1505 descs
= g_list_reverse (descs
);
1506 obj
= anjuta_plugin_manager_select_and_activate (plugin_manager
,
1507 dgettext (GETTEXT_PACKAGE
, "Select a plugin"),
1508 dgettext (GETTEXT_PACKAGE
, "<b>Please select a plugin to activate</b>"),
1510 g_list_free (descs
);
1514 /* No plugin implementing this interface found */
1519 * anjuta_plugin_manager_get_plugin_by_id:
1520 * @plugin_manager: A #AnjutaPluginManager object
1521 * @plugin_id: The plugin id
1523 * Searches the currently available plugins to find the one with the
1524 * specified identifier. If the plugin is not yet loaded, it will be loaded
1527 * Return value: The plugin object (subclass of #AnjutaPlugin)
1530 anjuta_plugin_manager_get_plugin_by_id (AnjutaPluginManager
*plugin_manager
,
1531 const gchar
*plugin_id
)
1533 AnjutaPluginManagerPriv
*priv
;
1534 AnjutaPluginHandle
*plugin
;
1536 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
1537 g_return_val_if_fail (plugin_id
!= NULL
, NULL
);
1539 priv
= plugin_manager
->priv
;
1540 plugin
= g_hash_table_lookup (priv
->plugins_by_name
, plugin_id
);
1544 obj
= g_hash_table_lookup (priv
->activated_plugins
, plugin
);
1550 plugin_set_update (plugin_manager
, plugin
, TRUE
);
1551 obj
= g_hash_table_lookup (priv
->activated_plugins
, plugin
);
1555 g_warning ("No plugin found with id \"%s\".", plugin_id
);
1560 on_activated_plugins_foreach (gpointer key
, gpointer data
, gpointer user_data
)
1562 AnjutaPluginHandle
*plugin
= ANJUTA_PLUGIN_HANDLE (key
);
1563 GList
**active_plugins
= (GList
**)user_data
;
1564 *active_plugins
= g_list_prepend (*active_plugins
,
1565 anjuta_plugin_handle_get_description (plugin
));
1569 on_activated_plugin_objects_foreach (gpointer key
, gpointer data
, gpointer user_data
)
1571 GList
**active_plugins
= (GList
**)user_data
;
1572 *active_plugins
= g_list_prepend (*active_plugins
,
1577 anjuta_plugin_manager_get_active_plugins (AnjutaPluginManager
*plugin_manager
)
1579 GList
*active_plugins
= NULL
;
1581 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
1582 g_hash_table_foreach (plugin_manager
->priv
->activated_plugins
,
1583 on_activated_plugins_foreach
,
1585 return g_list_reverse (active_plugins
);
1589 anjuta_plugin_manager_get_active_plugin_objects (AnjutaPluginManager
*plugin_manager
)
1591 GList
*active_plugins
= NULL
;
1593 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
1594 g_hash_table_foreach (plugin_manager
->priv
->activated_plugins
,
1595 on_activated_plugin_objects_foreach
,
1597 return g_list_reverse (active_plugins
);
1601 * anjuta_plugin_manager_unload_plugin_by_id:
1602 * @plugin_manager: A #AnjutaPluginManager object
1603 * @plugin_id: The plugin identifier
1605 * Unload the plugin corresponding to the given identifier. If the plugin is
1606 * already unloaded, nothing will be done.
1608 * Return value: %TRUE is the plugin is unloaded. %FALSE if a corresponding
1609 * plugin does not exist or if the plugin cannot be unloaded.
1612 anjuta_plugin_manager_unload_plugin_by_id (AnjutaPluginManager
*plugin_manager
,
1613 const gchar
*plugin_id
)
1615 AnjutaPluginManagerPriv
*priv
;
1616 AnjutaPluginHandle
*plugin
;
1618 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), FALSE
);
1619 g_return_val_if_fail (plugin_id
!= NULL
, FALSE
);
1621 priv
= plugin_manager
->priv
;
1623 plugin
= g_hash_table_lookup (priv
->plugins_by_name
, plugin_id
);
1626 plugin_set_update (plugin_manager
, plugin
, FALSE
);
1628 /* Check if the plugin has been indeed unloaded */
1629 if (!g_hash_table_lookup (priv
->activated_plugins
, plugin
))
1634 g_warning ("No plugin found with id \"%s\".", plugin_id
);
1639 find_plugin_for_object (gpointer key
, gpointer value
, gpointer data
)
1643 g_object_set_data (G_OBJECT (data
), "__plugin_plugin", key
);
1650 * anjuta_plugin_manager_unload_plugin:
1651 * @plugin_manager: A #AnjutaPluginManager object
1652 * @plugin_object: A #AnjutaPlugin object
1654 * Unload the corresponding plugin. The plugin has to be loaded.
1656 * Return value: %TRUE if the plugin has been unloaded. %FALSE if the plugin is
1657 * already or cannot be unloaded.
1660 anjuta_plugin_manager_unload_plugin (AnjutaPluginManager
*plugin_manager
,
1661 GObject
*plugin_object
)
1663 AnjutaPluginManagerPriv
*priv
;
1664 AnjutaPluginHandle
*plugin
;
1666 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), FALSE
);
1667 g_return_val_if_fail (ANJUTA_IS_PLUGIN (plugin_object
), FALSE
);
1669 priv
= plugin_manager
->priv
;
1673 /* Find the plugin that correspond to this plugin object */
1674 g_hash_table_find (priv
->activated_plugins
, find_plugin_for_object
,
1676 plugin
= g_object_get_data (G_OBJECT (plugin_object
), "__plugin_plugin");
1680 plugin_set_update (plugin_manager
, plugin
, FALSE
);
1682 /* Check if the plugin has been indeed unloaded */
1683 if (!g_hash_table_lookup (priv
->activated_plugins
, plugin
))
1688 g_warning ("No plugin found with object \"%p\".", plugin_object
);
1693 anjuta_plugin_manager_list_query (AnjutaPluginManager
*plugin_manager
,
1698 AnjutaPluginManagerPriv
*priv
;
1699 GList
*selected_plugins
= NULL
;
1702 const gchar
*avalue
;
1705 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
1707 priv
= plugin_manager
->priv
;
1708 available
= priv
->available_plugins
;
1712 /* If no query is given, select all plugins */
1715 AnjutaPluginHandle
*plugin
= available
->data
;
1716 AnjutaPluginDescription
*desc
=
1717 anjuta_plugin_handle_get_description (plugin
);
1718 selected_plugins
= g_list_prepend (selected_plugins
, desc
);
1719 available
= g_list_next (available
);
1721 return g_list_reverse (selected_plugins
);
1724 g_return_val_if_fail (secs
!= NULL
, NULL
);
1725 g_return_val_if_fail (anames
!= NULL
, NULL
);
1726 g_return_val_if_fail (avalues
!= NULL
, NULL
);
1730 GList
* s_node
= secs
;
1731 GList
* n_node
= anames
;
1732 GList
* v_node
= avalues
;
1734 gboolean satisfied
= FALSE
;
1736 AnjutaPluginHandle
*plugin
= available
->data
;
1737 AnjutaPluginDescription
*desc
=
1738 anjuta_plugin_handle_get_description (plugin
);
1745 gboolean found
= FALSE
;
1750 aname
= n_node
->data
;
1751 avalue
= v_node
->data
;
1753 if (!anjuta_plugin_description_get_string (desc
, sec
, aname
, &val
))
1759 vals
= property_to_list (val
);
1765 if (strchr(node
->data
, '*') != NULL
)
1770 const gchar
*cursor
;
1772 segments
= g_strsplit (node
->data
, "*", -1);
1776 while (*seg_ptr
!= NULL
)
1778 if (strlen (*seg_ptr
) > 0) {
1779 cursor
= strstr (cursor
, *seg_ptr
);
1783 cursor
+= strlen (*seg_ptr
);
1786 if (*seg_ptr
== NULL
)
1788 g_strfreev (segments
);
1790 else if (g_ascii_strcasecmp (node
->data
, avalue
) == 0)
1795 g_free (node
->data
);
1796 node
= g_list_next (node
);
1804 s_node
= g_list_next (s_node
);
1805 n_node
= g_list_next (n_node
);
1806 v_node
= g_list_next (v_node
);
1810 selected_plugins
= g_list_prepend (selected_plugins
, desc
);
1811 /* DEBUG_PRINT ("Satisfied, Adding %s",
1812 anjuta_plugin_handle_get_name (plugin));*/
1814 available
= g_list_next (available
);
1817 return g_list_reverse (selected_plugins
);
1821 anjuta_plugin_manager_query (AnjutaPluginManager
*plugin_manager
,
1822 const gchar
*section_name
,
1823 const gchar
*attribute_name
,
1824 const gchar
*attribute_value
,
1829 GList
*anames
= NULL
;
1830 GList
*avalues
= NULL
;
1833 const gchar
*avalue
;
1834 GList
*selected_plugins
;
1837 if (section_name
== NULL
)
1839 /* If no query is given, select all plugins */
1840 return anjuta_plugin_manager_list_query (plugin_manager
, NULL
, NULL
, NULL
);
1843 g_return_val_if_fail (section_name
!= NULL
, NULL
);
1844 g_return_val_if_fail (attribute_name
!= NULL
, NULL
);
1845 g_return_val_if_fail (attribute_value
!= NULL
, NULL
);
1847 secs
= g_list_prepend (secs
, g_strdup (section_name
));
1848 anames
= g_list_prepend (anames
, g_strdup (attribute_name
));
1849 avalues
= g_list_prepend (avalues
, g_strdup (attribute_value
));
1851 va_start (var_args
, attribute_value
);
1854 sec
= va_arg (var_args
, const gchar
*);
1857 aname
= va_arg (var_args
, const gchar
*);
1860 avalue
= va_arg (var_args
, const gchar
*);
1863 secs
= g_list_prepend (secs
, g_strdup (sec
));
1864 anames
= g_list_prepend (anames
, g_strdup (aname
));
1865 avalues
= g_list_prepend (avalues
, g_strdup (avalue
));
1873 secs
= g_list_reverse (secs
);
1874 anames
= g_list_reverse (anames
);
1875 avalues
= g_list_reverse (avalues
);
1877 selected_plugins
= anjuta_plugin_manager_list_query (plugin_manager
,
1882 anjuta_util_glist_strings_free (secs
);
1883 anjuta_util_glist_strings_free (anames
);
1884 anjuta_util_glist_strings_free (avalues
);
1886 return selected_plugins
;
1892 PLUGIN_DESCRIPTION_COLUMN
,
1897 on_plugin_list_row_activated (GtkTreeView
*tree_view
,
1899 GtkTreeViewColumn
*column
,
1902 gtk_dialog_response (dialog
, GTK_RESPONSE_OK
);
1907 on_plugin_list_show (GtkTreeView
*view
,
1908 GtkDirectionType direction
,
1911 GtkTreeSelection
*selection
;
1912 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
1914 g_signal_emit_by_name (G_OBJECT (selection
), "changed", GTK_DIALOG(dialog
), NULL
);
1919 on_plugin_list_selection_changed (GtkTreeSelection
*tree_selection
,
1922 GtkContainer
*action_area
;
1924 GtkButton
*bt
= NULL
;
1926 action_area
= GTK_CONTAINER (gtk_dialog_get_action_area (dialog
));
1927 list
= gtk_container_get_children (action_area
);
1928 for (; list
; list
= list
->next
) {
1930 if (!strcmp("gtk-ok", gtk_button_get_label (bt
)))
1933 if (bt
&& gtk_tree_selection_get_selected (tree_selection
, NULL
, NULL
))
1934 gtk_widget_set_sensitive ((GtkWidget
*) bt
, TRUE
);
1936 gtk_widget_set_sensitive ((GtkWidget
*) bt
, FALSE
);
1941 * anjuta_plugin_manager_select:
1942 * @plugin_manager: #AnjutaPluginManager object
1943 * @title: Title of the dialog
1944 * @description: label shown on the dialog
1945 * @plugin_descriptions: List of #AnjutaPluginDescription
1947 * Show a dialog where the user can choose between the given plugins
1949 * Returns: The chosen plugin description
1951 AnjutaPluginDescription
*
1952 anjuta_plugin_manager_select (AnjutaPluginManager
*plugin_manager
,
1953 gchar
*title
, gchar
*description
,
1954 GList
*plugin_descriptions
)
1956 AnjutaPluginDescription
*desc
;
1957 AnjutaPluginManagerPriv
*priv
;
1959 GtkTreeModel
*model
;
1961 GtkTreeViewColumn
*column
;
1962 GtkCellRenderer
*renderer
;
1965 GtkWidget
*content_area
;
1967 GtkWidget
*remember_checkbox
;
1969 GtkTreeIter selected
;
1970 GtkTreeSelection
*selection
;
1971 GtkTreeModel
*store
;
1972 GList
*selection_ids
= NULL
;
1973 GString
*remember_key
= g_string_new ("");
1975 g_return_val_if_fail (title
!= NULL
, NULL
);
1976 g_return_val_if_fail (description
!= NULL
, NULL
);
1977 g_return_val_if_fail (plugin_descriptions
!= NULL
, NULL
);
1979 priv
= plugin_manager
->priv
;
1981 if (g_list_length (plugin_descriptions
) <= 0)
1984 dlg
= gtk_dialog_new_with_buttons (title
, GTK_WINDOW (priv
->shell
),
1985 GTK_DIALOG_DESTROY_WITH_PARENT
,
1987 GTK_RESPONSE_CANCEL
,
1988 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
1990 gtk_window_set_default_size (GTK_WINDOW (dlg
), 400, 300);
1992 label
= gtk_label_new (description
);
1993 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
1994 gtk_widget_show (label
);
1995 content_area
= gtk_dialog_get_content_area (GTK_DIALOG (dlg
));
1996 gtk_box_pack_start (GTK_BOX (content_area
), label
,
1999 sc
= gtk_scrolled_window_new (NULL
, NULL
);
2000 gtk_widget_show (sc
);
2001 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sc
),
2003 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sc
),
2004 GTK_POLICY_AUTOMATIC
,
2005 GTK_POLICY_AUTOMATIC
);
2007 gtk_box_pack_start (GTK_BOX (content_area
), sc
,
2010 model
= GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS
, GDK_TYPE_PIXBUF
,
2011 G_TYPE_STRING
, G_TYPE_POINTER
));
2012 view
= gtk_tree_view_new_with_model (model
);
2013 gtk_widget_show (view
);
2014 gtk_container_add (GTK_CONTAINER (sc
), view
);
2016 column
= gtk_tree_view_column_new ();
2017 gtk_tree_view_column_set_sizing (column
,
2018 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
2019 gtk_tree_view_column_set_title (column
, dgettext (GETTEXT_PACKAGE
, "Available Plugins"));
2021 renderer
= gtk_cell_renderer_pixbuf_new ();
2022 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
2023 gtk_tree_view_column_add_attribute (column
, renderer
, "pixbuf",
2026 renderer
= gtk_cell_renderer_text_new ();
2027 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
2028 gtk_tree_view_column_add_attribute (column
, renderer
, "markup",
2031 gtk_tree_view_append_column (GTK_TREE_VIEW (view
), column
);
2032 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (view
), column
);
2034 g_signal_connect (view
, "row-activated",
2035 G_CALLBACK (on_plugin_list_row_activated
),
2037 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
2038 g_signal_connect(selection
, "changed",
2039 G_CALLBACK(on_plugin_list_selection_changed
),
2041 g_signal_connect(view
, "focus",
2042 G_CALLBACK(on_plugin_list_show
),
2046 gtk_check_button_new_with_label (dgettext (GETTEXT_PACKAGE
, "Remember this selection"));
2047 gtk_container_set_border_width (GTK_CONTAINER (remember_checkbox
), 10);
2048 gtk_widget_show (remember_checkbox
);
2049 gtk_box_pack_start (GTK_BOX (content_area
), remember_checkbox
,
2052 node
= plugin_descriptions
;
2055 GdkPixbuf
*icon_pixbuf
= NULL
;
2056 gchar
*plugin_name
= NULL
;
2057 gchar
*plugin_desc
= NULL
;
2058 gchar
*icon_filename
= NULL
;
2059 gchar
*location
= NULL
;
2061 desc
= (AnjutaPluginDescription
*)node
->data
;
2063 if (anjuta_plugin_description_get_string (desc
,
2068 gchar
*icon_path
= NULL
;
2069 icon_path
= g_strconcat (PACKAGE_PIXMAPS_DIR
"/",
2070 icon_filename
, NULL
);
2071 g_free (icon_filename
);
2072 /* DEBUG_PRINT ("Icon: %s", icon_path); */
2074 gdk_pixbuf_new_from_file (icon_path
, NULL
);
2075 if (icon_pixbuf
== NULL
)
2077 g_warning ("Plugin pixmap not found: %s", plugin_name
);
2083 g_warning ("Plugin does not define Icon attribute");
2085 if (!anjuta_plugin_description_get_locale_string (desc
,
2090 g_warning ("Plugin does not define Name attribute");
2092 if (!anjuta_plugin_description_get_locale_string (desc
,
2097 g_warning ("Plugin does not define Description attribute");
2099 if (plugin_name
&& plugin_desc
)
2104 if (!anjuta_plugin_description_get_string (desc
,
2109 g_warning ("Plugin does not define Location attribute");
2113 text
= g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s", plugin_name
, plugin_desc
);
2115 gtk_list_store_append (GTK_LIST_STORE (model
), &iter
);
2116 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
2117 PLUGIN_COLUMN
, text
,
2118 PLUGIN_DESCRIPTION_COLUMN
, desc
, -1);
2120 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
2121 PIXBUF_COLUMN
, icon_pixbuf
, -1);
2122 g_object_unref (icon_pixbuf
);
2126 selection_ids
= g_list_prepend (selection_ids
, location
);
2128 g_free (plugin_name
);
2129 g_free (plugin_desc
);
2130 node
= g_list_next (node
);
2133 /* Prepare remembering key */
2134 selection_ids
= g_list_sort (selection_ids
,
2135 (GCompareFunc
)strcmp
);
2136 node
= selection_ids
;
2139 g_string_append (remember_key
, (gchar
*)node
->data
);
2140 g_string_append (remember_key
, ",");
2141 node
= g_list_next (node
);
2143 g_list_foreach (selection_ids
, (GFunc
) g_free
, NULL
);
2144 g_list_free (selection_ids
);
2146 /* Find if the selection is remembered */
2147 desc
= g_hash_table_lookup (priv
->remember_plugins
, remember_key
->str
);
2150 g_string_free (remember_key
, TRUE
);
2151 gtk_widget_destroy (dlg
);
2156 response
= gtk_dialog_run (GTK_DIALOG (dlg
));
2159 case GTK_RESPONSE_OK
:
2160 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
2161 if (gtk_tree_selection_get_selected (selection
, &store
,
2164 gtk_tree_model_get (model
, &selected
,
2165 PLUGIN_DESCRIPTION_COLUMN
, &desc
, -1);
2168 /* Remember selection */
2169 if (gtk_toggle_button_get_active
2170 (GTK_TOGGLE_BUTTON (remember_checkbox
)))
2172 /* DEBUG_PRINT ("Remembering selection '%s'",
2173 remember_key->str);*/
2174 g_hash_table_insert (priv
->remember_plugins
,
2175 g_strdup (remember_key
->str
), desc
);
2177 g_string_free (remember_key
, TRUE
);
2178 gtk_widget_destroy (dlg
);
2184 g_string_free (remember_key
, TRUE
);
2185 gtk_widget_destroy (dlg
);
2190 anjuta_plugin_manager_select_and_activate (AnjutaPluginManager
*plugin_manager
,
2193 GList
*plugin_descriptions
)
2195 AnjutaPluginDescription
*d
;
2197 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
2199 d
= anjuta_plugin_manager_select (plugin_manager
, title
, description
,
2200 plugin_descriptions
);
2203 GObject
*plugin
= NULL
;
2204 gchar
*location
= NULL
;
2206 anjuta_plugin_description_get_string (d
,
2210 g_return_val_if_fail (location
!= NULL
, NULL
);
2212 anjuta_plugin_manager_get_plugin_by_id (plugin_manager
, location
);
2220 * anjuta_plugin_manager_get_plugin_description:
2221 * @plugin_manager: #AnjutaPluginManager object
2222 * @plugin: #AnjutaPlugin object
2224 * Get the description corresponding to the plugin or %NULL if the plugin is not
2227 * Returns: A #AnjutaPluginDescription or %NULL.
2229 AnjutaPluginDescription
*
2230 anjuta_plugin_manager_get_plugin_description (AnjutaPluginManager
*plugin_manager
,
2233 GHashTableIter iter
;
2234 gpointer key
, value
;
2236 g_hash_table_iter_init (&iter
, plugin_manager
->priv
->activated_plugins
);
2237 while (g_hash_table_iter_next (&iter
, &key
, &value
))
2239 if (G_OBJECT(value
) == plugin
)
2241 return anjuta_plugin_handle_get_description (ANJUTA_PLUGIN_HANDLE (key
));
2249 /* Plugin manager */
2252 anjuta_plugin_manager_init (AnjutaPluginManager
*object
)
2254 object
->priv
= g_new0 (AnjutaPluginManagerPriv
, 1);
2255 object
->priv
->plugins_by_name
= g_hash_table_new (g_str_hash
, g_str_equal
);
2256 object
->priv
->plugins_by_interfaces
= g_hash_table_new_full (g_str_hash
,
2259 (GDestroyNotify
) g_list_free
);
2260 object
->priv
->plugins_by_description
= g_hash_table_new (g_direct_hash
,
2262 object
->priv
->activated_plugins
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
2263 NULL
, g_object_unref
);
2264 object
->priv
->plugins_cache
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
2265 NULL
, g_object_unref
);
2266 object
->priv
->remember_plugins
= g_hash_table_new_full (g_str_hash
,
2272 anjuta_plugin_manager_dispose (GObject
*object
)
2274 AnjutaPluginManagerPriv
*priv
;
2275 priv
= ANJUTA_PLUGIN_MANAGER (object
)->priv
;
2277 if (priv
->available_plugins
)
2279 g_list_foreach (priv
->available_plugins
, (GFunc
)g_object_unref
, NULL
);
2280 g_list_free (priv
->available_plugins
);
2281 priv
->available_plugins
= NULL
;
2283 if (priv
->activated_plugins
)
2285 g_hash_table_destroy (priv
->activated_plugins
);
2286 priv
->activated_plugins
= NULL
;
2288 if (priv
->plugins_cache
)
2290 g_hash_table_destroy (priv
->plugins_cache
);
2291 priv
->plugins_cache
= NULL
;
2293 if (priv
->plugins_by_name
)
2295 g_hash_table_destroy (priv
->plugins_by_name
);
2296 priv
->plugins_by_name
= NULL
;
2298 if (priv
->plugins_by_description
)
2300 g_hash_table_destroy (priv
->plugins_by_description
);
2301 priv
->plugins_by_description
= NULL
;
2303 if (priv
->plugins_by_interfaces
)
2305 g_hash_table_destroy (priv
->plugins_by_interfaces
);
2306 priv
->plugins_by_interfaces
= NULL
;
2308 if (priv
->plugin_dirs
)
2310 g_list_foreach (priv
->plugin_dirs
, (GFunc
)g_free
, NULL
);
2311 g_list_free (priv
->plugin_dirs
);
2312 priv
->plugin_dirs
= NULL
;
2315 if (anjuta_c_plugin_factory
)
2317 g_object_unref (anjuta_c_plugin_factory
);
2318 anjuta_c_plugin_factory
= NULL
;
2321 G_OBJECT_CLASS (parent_class
)->dispose (object
);
2325 anjuta_plugin_manager_set_property (GObject
*object
, guint prop_id
,
2326 const GValue
*value
, GParamSpec
*pspec
)
2328 AnjutaPluginManagerPriv
*priv
;
2330 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object
));
2331 priv
= ANJUTA_PLUGIN_MANAGER (object
)->priv
;
2336 priv
->status
= g_value_get_object (value
);
2339 priv
->shell
= g_value_get_object (value
);
2342 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
2348 anjuta_plugin_manager_get_property (GObject
*object
, guint prop_id
,
2349 GValue
*value
, GParamSpec
*pspec
)
2351 AnjutaPluginManagerPriv
*priv
;
2353 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object
));
2354 priv
= ANJUTA_PLUGIN_MANAGER (object
)->priv
;
2359 g_value_set_object (value
, priv
->shell
);
2362 g_value_set_object (value
, priv
->status
);
2364 case PROP_AVAILABLE_PLUGINS
:
2365 g_value_set_pointer (value
, priv
->available_plugins
);
2367 case PROP_ACTIVATED_PLUGINS
:
2368 g_value_set_pointer (value
, priv
->activated_plugins
);
2371 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
2376 anjuta_plugin_manager_plugin_activated (AnjutaPluginManager
*self
,
2377 AnjutaPluginDescription
* plugin_desc
,
2380 /* TODO: Add default signal handler implementation here */
2384 anjuta_plugin_manager_plugin_deactivated (AnjutaPluginManager
*self
,
2385 AnjutaPluginDescription
* plugin_desc
,
2388 /* TODO: Add default signal handler implementation here */
2392 anjuta_plugin_manager_class_init (AnjutaPluginManagerClass
*klass
)
2394 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
2395 parent_class
= G_OBJECT_CLASS (g_type_class_peek_parent (klass
));
2397 object_class
->dispose
= anjuta_plugin_manager_dispose
;
2398 object_class
->set_property
= anjuta_plugin_manager_set_property
;
2399 object_class
->get_property
= anjuta_plugin_manager_get_property
;
2401 klass
->plugin_activated
= anjuta_plugin_manager_plugin_activated
;
2402 klass
->plugin_deactivated
= anjuta_plugin_manager_plugin_deactivated
;
2404 g_object_class_install_property (object_class
,
2406 g_param_spec_pointer ("profiles",
2407 dgettext (GETTEXT_PACKAGE
, "Profiles"),
2408 dgettext (GETTEXT_PACKAGE
, "Current stack of profiles"),
2410 g_object_class_install_property (object_class
,
2411 PROP_AVAILABLE_PLUGINS
,
2412 g_param_spec_pointer ("available-plugins",
2413 dgettext (GETTEXT_PACKAGE
, "Available plugins"),
2414 dgettext (GETTEXT_PACKAGE
, "Currently available plugins found in plugin paths"),
2417 g_object_class_install_property (object_class
,
2418 PROP_ACTIVATED_PLUGINS
,
2419 g_param_spec_pointer ("activated-plugins",
2420 dgettext (GETTEXT_PACKAGE
, "Activated plugins"),
2421 dgettext (GETTEXT_PACKAGE
, "Currently activated plugins"),
2423 g_object_class_install_property (object_class
,
2425 g_param_spec_object ("shell",
2426 dgettext (GETTEXT_PACKAGE
, "Anjuta Shell"),
2427 dgettext (GETTEXT_PACKAGE
, "Anjuta shell for which the plugins are made"),
2431 G_PARAM_CONSTRUCT
));
2432 g_object_class_install_property (object_class
,
2434 g_param_spec_object ("status",
2435 dgettext (GETTEXT_PACKAGE
, "Anjuta Status"),
2436 dgettext (GETTEXT_PACKAGE
, "Anjuta status to use in loading and unloading of plugins"),
2440 G_PARAM_CONSTRUCT
));
2442 plugin_manager_signals
[PLUGIN_ACTIVATED
] =
2443 g_signal_new ("plugin-activated",
2444 G_OBJECT_CLASS_TYPE (klass
),
2446 G_STRUCT_OFFSET (AnjutaPluginManagerClass
,
2449 anjuta_cclosure_marshal_VOID__POINTER_OBJECT
,
2451 G_TYPE_POINTER
, ANJUTA_TYPE_PLUGIN
);
2453 plugin_manager_signals
[PLUGIN_DEACTIVATED
] =
2454 g_signal_new ("plugin-deactivated",
2455 G_OBJECT_CLASS_TYPE (klass
),
2457 G_STRUCT_OFFSET (AnjutaPluginManagerClass
,
2458 plugin_deactivated
),
2460 anjuta_cclosure_marshal_VOID__POINTER_OBJECT
,
2462 G_TYPE_POINTER
, ANJUTA_TYPE_PLUGIN
);
2466 anjuta_plugin_manager_get_type (void)
2468 static GType our_type
= 0;
2472 static const GTypeInfo our_info
=
2474 sizeof (AnjutaPluginManagerClass
), /* class_size */
2475 (GBaseInitFunc
) NULL
, /* base_init */
2476 (GBaseFinalizeFunc
) NULL
, /* base_finalize */
2477 (GClassInitFunc
) anjuta_plugin_manager_class_init
, /* class_init */
2478 (GClassFinalizeFunc
) NULL
, /* class_finalize */
2479 NULL
/* class_data */,
2480 sizeof (AnjutaPluginManager
), /* instance_size */
2481 0, /* n_preallocs */
2482 (GInstanceInitFunc
) anjuta_plugin_manager_init
, /* instance_init */
2483 NULL
/* value_table */
2485 our_type
= g_type_register_static (G_TYPE_OBJECT
,
2486 "AnjutaPluginManager",
2493 AnjutaPluginManager
*
2494 anjuta_plugin_manager_new (GObject
*shell
, AnjutaStatus
*status
,
2495 GList
* plugins_directories
)
2497 GObject
*manager_object
;
2498 AnjutaPluginManager
*plugin_manager
;
2499 GList
*cycles
= NULL
;
2500 const char *gnome2_path
;
2504 GList
*plugin_dirs
= NULL
;
2506 /* Initialize the anjuta plugin system */
2507 manager_object
= g_object_new (ANJUTA_TYPE_PLUGIN_MANAGER
,
2508 "shell", shell
, "status", status
, NULL
);
2509 plugin_manager
= ANJUTA_PLUGIN_MANAGER (manager_object
);
2511 if (anjuta_plugin_factory
== NULL
)
2513 anjuta_plugin_factory
= anjuta_c_plugin_factory_new ();
2516 gnome2_path
= g_getenv ("GNOME2_PATH");
2518 pathv
= g_strsplit (gnome2_path
, ":", 1);
2520 for (p
= pathv
; *p
!= NULL
; p
++) {
2521 char *path
= g_strdup (*p
);
2522 plugin_dirs
= g_list_prepend (plugin_dirs
, path
);
2527 node
= plugins_directories
;
2531 char *path
= g_strdup (node
->data
);
2532 plugin_dirs
= g_list_prepend (plugin_dirs
, path
);
2533 node
= g_list_next (node
);
2535 plugin_dirs
= g_list_reverse (plugin_dirs
);
2536 /* load_plugins (); */
2541 load_plugins_from_directory (plugin_manager
, (char*)node
->data
);
2542 node
= g_list_next (node
);
2544 resolve_dependencies (plugin_manager
, &cycles
);
2545 g_list_foreach(plugin_dirs
, (GFunc
) g_free
, NULL
);
2546 g_list_free(plugin_dirs
);
2547 return plugin_manager
;
2551 anjuta_plugin_manager_activate_plugins (AnjutaPluginManager
*plugin_manager
,
2552 GList
*plugins_to_activate
)
2554 AnjutaPluginManagerPriv
*priv
;
2555 GdkPixbuf
*icon_pixbuf
;
2558 priv
= plugin_manager
->priv
;
2560 /* Freeze shell operations */
2561 anjuta_shell_freeze (ANJUTA_SHELL (priv
->shell
), NULL
);
2562 if (plugins_to_activate
)
2564 anjuta_status_progress_add_ticks (ANJUTA_STATUS (priv
->status
),
2565 g_list_length (plugins_to_activate
));
2567 node
= plugins_to_activate
;
2570 AnjutaPluginDescription
*d
;
2572 gchar
*icon_filename
, *label
;
2573 gchar
*icon_path
= NULL
;
2579 if (anjuta_plugin_description_get_string (d
, "Anjuta Plugin",
2583 gchar
*title
/*, *description */;
2584 anjuta_plugin_description_get_locale_string (d
, "Anjuta Plugin",
2588 anjuta_plugin_description_get_locale_string (d, "Anjuta Plugin",
2592 icon_path
= g_strconcat (PACKAGE_PIXMAPS_DIR
"/",
2593 icon_filename
, NULL
);
2594 /* DEBUG_PRINT ("Icon: %s", icon_path); */
2595 /* Avoid space in translated string */
2596 label
= g_strconcat (dgettext (GETTEXT_PACKAGE
, "Loading:"), " ", title
, "...", NULL
);
2597 icon_pixbuf
= gdk_pixbuf_new_from_file (icon_path
, NULL
);
2599 g_warning ("Plugin does not define Icon: No such file %s",
2602 g_free (icon_filename
);
2606 anjuta_status_progress_tick (ANJUTA_STATUS (priv
->status
),
2607 icon_pixbuf
, label
);
2610 g_object_unref (icon_pixbuf
);
2612 if (anjuta_plugin_description_get_string (d
, "Anjuta Plugin",
2613 "Location", &plugin_id
))
2615 /* Activate the plugin */
2616 anjuta_plugin_manager_get_plugin_by_id (plugin_manager
,
2621 node
= g_list_next (node
);
2624 /* Thaw shell operations */
2625 anjuta_shell_thaw (ANJUTA_SHELL (priv
->shell
), NULL
);
2629 on_collect (gpointer key
, gpointer value
, gpointer user_data
)
2632 gchar
*query
= (gchar
*) key
;
2633 AnjutaPluginDescription
*desc
= (AnjutaPluginDescription
*) value
;
2634 GString
*write_buffer
= (GString
*) user_data
;
2636 anjuta_plugin_description_get_string (desc
, "Anjuta Plugin", "Location",
2638 g_string_append_printf (write_buffer
, "%s=%s;", query
, id
);
2643 * anjuta_plugin_manager_get_remembered_plugins:
2644 * @plugin_manager: A #AnjutaPluginManager object
2646 * Get the list of plugins loaded when there is a choice between several
2647 * ones without asking the user.
2649 * The list format is returned as a string with the format detailed in
2650 * anjuta_plugin_manager_set_remembered_plugins().
2652 * Return value: a newly-allocated string that must be freed with g_free().
2656 anjuta_plugin_manager_get_remembered_plugins (AnjutaPluginManager
*plugin_manager
)
2658 AnjutaPluginManagerPriv
*priv
;
2659 GString
*write_buffer
= g_string_new ("");
2661 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), FALSE
);
2663 priv
= plugin_manager
->priv
;
2664 g_hash_table_foreach (priv
->remember_plugins
, on_collect
,
2666 return g_string_free (write_buffer
, FALSE
);
2670 * anjuta_plugin_manager_set_remembered_plugins:
2671 * @plugin_manager: A #AnjutaPluginManager object
2672 * @remembered_plugins: A list of prefered plugins
2674 * Set the list of plugins loaded when there is a choice between several
2675 * ones without asking the user.
2676 * The list is a string composed of elements separated by ';'. Each element
2677 * is defined with "key=value", where key is the list of possible plugins and
2678 * the value is the choosen plugin.
2680 * By the example the following element
2682 * anjuta-symbol-browser:SymbolBrowserPlugin,anjuta-symbol-db:SymbolDBPlugin,=anjuta-symbol-db:SymbolDBPlugin;
2684 * means if Anjuta has to choose between SymbolBrowserPlugin and
2685 * SymbolDBPlugin, it will choose SymbolDBPlugin.
2688 anjuta_plugin_manager_set_remembered_plugins (AnjutaPluginManager
*plugin_manager
,
2689 const gchar
*remembered_plugins
)
2691 AnjutaPluginManagerPriv
*priv
;
2692 gchar
**strv_lines
, **line_idx
;
2694 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
));
2695 g_return_if_fail (remembered_plugins
!= NULL
);
2697 priv
= plugin_manager
->priv
;
2699 g_hash_table_remove_all (priv
->remember_plugins
);
2701 strv_lines
= g_strsplit (remembered_plugins
, ";", -1);
2702 line_idx
= strv_lines
;
2705 gchar
**strv_keyvals
;
2706 strv_keyvals
= g_strsplit (*line_idx
, "=", -1);
2707 if (strv_keyvals
&& strv_keyvals
[0] && strv_keyvals
[1])
2709 AnjutaPluginHandle
*plugin
;
2710 plugin
= g_hash_table_lookup (priv
->plugins_by_name
,
2714 AnjutaPluginDescription
*desc
;
2715 desc
= anjuta_plugin_handle_get_description (plugin
);
2717 DEBUG_PRINT ("Restoring remember plugin: %s=%s",
2721 g_hash_table_insert (priv
->remember_plugins
,
2722 g_strdup (strv_keyvals
[0]), desc
);
2724 g_strfreev (strv_keyvals
);
2728 g_strfreev (strv_lines
);