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 GHashTable
*disable_plugins
;
96 /* Available plugins page treeview */
106 /* Remembered plugins page treeview */
114 /* Plugin class types */
116 static AnjutaCPluginFactory
*anjuta_plugin_factory
= NULL
;
118 static GObjectClass
* parent_class
= NULL
;
119 static guint plugin_manager_signals
[LAST_SIGNAL
] = { 0 };
121 static void plugin_set_update (AnjutaPluginManager
*plugin_manager
,
122 AnjutaPluginHandle
* selected_plugin
,
125 static IAnjutaPluginFactory
* get_plugin_factory (AnjutaPluginManager
*plugin_manager
,
126 const gchar
*language
, GError
**error
);
129 anjuta_plugin_manager_error_quark (void)
131 static GQuark quark
= 0;
134 quark
= g_quark_from_static_string ("anjuta-plugin-manager-quark");
139 /** Dependency Resolution **/
142 collect_cycle (AnjutaPluginManager
*plugin_manager
,
143 AnjutaPluginHandle
*base_plugin
, AnjutaPluginHandle
*cur_plugin
,
146 AnjutaPluginManagerPriv
*priv
;
149 priv
= plugin_manager
->priv
;
151 for (l
= anjuta_plugin_handle_get_dependency_names (cur_plugin
);
152 l
!= NULL
; l
= l
->next
)
154 AnjutaPluginHandle
*dep
= g_hash_table_lookup (priv
->plugins_by_name
,
158 if (dep
== base_plugin
)
160 *cycle
= g_list_prepend (NULL
, dep
);
161 /* DEBUG_PRINT ("%s", anjuta_plugin_handle_get_name (dep)); */
166 if (collect_cycle (plugin_manager
, base_plugin
, dep
, cycle
))
168 *cycle
= g_list_prepend (*cycle
, dep
);
169 /* DEBUG_PRINT ("%s", anjuta_plugin_handle_get_name (dep)); */
179 add_dependency (AnjutaPluginHandle
*dependent
, AnjutaPluginHandle
*dependency
)
181 g_hash_table_insert (anjuta_plugin_handle_get_dependents (dependency
),
182 dependent
, dependency
);
183 g_hash_table_insert (anjuta_plugin_handle_get_dependencies (dependent
),
184 dependency
, dependent
);
188 child_dep_foreach_cb (gpointer key
, gpointer value
, gpointer user_data
)
190 add_dependency (ANJUTA_PLUGIN_HANDLE (user_data
),
191 ANJUTA_PLUGIN_HANDLE (key
));
194 /* Resolves dependencies for a single module recursively. Shortcuts if
195 * the module has already been resolved. Returns a list representing
196 * any cycles found, or NULL if no cycles are found. If a cycle is found,
197 * the graph is left unresolved.
200 resolve_for_module (AnjutaPluginManager
*plugin_manager
,
201 AnjutaPluginHandle
*plugin
, int pass
)
203 AnjutaPluginManagerPriv
*priv
;
207 priv
= plugin_manager
->priv
;
209 if (anjuta_plugin_handle_get_checked (plugin
))
214 if (anjuta_plugin_handle_get_resolve_pass (plugin
) == pass
)
217 g_warning ("cycle found: %s on pass %d",
218 anjuta_plugin_handle_get_name (plugin
),
219 anjuta_plugin_handle_get_resolve_pass (plugin
));
220 collect_cycle (plugin_manager
, plugin
, plugin
, &cycle
);
224 if (anjuta_plugin_handle_get_resolve_pass (plugin
) != -1)
229 anjuta_plugin_handle_set_can_load (plugin
, TRUE
);
230 anjuta_plugin_handle_set_resolve_pass (plugin
, pass
);
232 for (l
= anjuta_plugin_handle_get_dependency_names (plugin
);
233 l
!= NULL
; l
= l
->next
)
236 AnjutaPluginHandle
*child
=
237 g_hash_table_lookup (priv
->plugins_by_name
, dep
);
240 ret
= resolve_for_module (plugin_manager
, child
, pass
);
246 /* Add the dependency's dense dependency list
247 * to the current module's dense dependency list */
248 g_hash_table_foreach (anjuta_plugin_handle_get_dependencies (child
),
249 child_dep_foreach_cb
, plugin
);
250 add_dependency (plugin
, child
);
252 /* If the child can't load due to dependency problems,
253 * the current module can't either */
254 anjuta_plugin_handle_set_can_load (plugin
,
255 anjuta_plugin_handle_get_can_load (child
));
257 g_warning ("Dependency %s not found.\n", dep
);
258 anjuta_plugin_handle_set_can_load (plugin
, FALSE
);
262 anjuta_plugin_handle_set_checked (plugin
, TRUE
);
267 /* Clean up the results of a resolving run */
269 unresolve_dependencies (AnjutaPluginManager
*plugin_manager
)
271 AnjutaPluginManagerPriv
*priv
;
274 priv
= plugin_manager
->priv
;
276 for (l
= priv
->available_plugins
; l
!= NULL
; l
= l
->next
)
278 AnjutaPluginHandle
*plugin
= l
->data
;
279 anjuta_plugin_handle_unresolve_dependencies (plugin
);
286 prune_modules (AnjutaPluginManager
*plugin_manager
, GList
*modules
)
288 AnjutaPluginManagerPriv
*priv
;
291 priv
= plugin_manager
->priv
;
293 for (l
= modules
; l
!= NULL
; l
= l
->next
) {
294 AnjutaPluginHandle
*plugin
= l
->data
;
296 g_hash_table_remove (priv
->plugins_by_name
,
297 anjuta_plugin_handle_get_id (plugin
));
298 priv
->available_plugins
= g_list_remove (priv
->available_plugins
, plugin
);
303 dependency_compare (AnjutaPluginHandle
*plugin_a
,
304 AnjutaPluginHandle
*plugin_b
)
306 int a
= g_hash_table_size (anjuta_plugin_handle_get_dependencies (plugin_a
));
307 int b
= g_hash_table_size (anjuta_plugin_handle_get_dependencies (plugin_b
));
312 /* Resolves the dependencies of the priv->available_plugins list. When this
313 * function is complete, the following will be true:
315 * 1) The dependencies and dependents hash tables of the modules will
318 * 2) Cycles in the graph will be removed.
320 * 3) Modules which cannot be loaded due to failed dependencies will
323 * 4) priv->available_plugins will be sorted such that no module depends on a
326 * If a cycle in the graph is found, it is pruned from the tree and
327 * returned as a list stored in the cycles list.
330 resolve_dependencies (AnjutaPluginManager
*plugin_manager
, GList
**cycles
)
332 AnjutaPluginManagerPriv
*priv
;
336 priv
= plugin_manager
->priv
;
339 /* Try resolving dependencies. If there is a cycle, prune the
340 * cycle and try to resolve again */
345 for (l
= priv
->available_plugins
; l
!= NULL
&& !cycle
; l
= l
->next
) {
346 cycle
= resolve_for_module (plugin_manager
, l
->data
, pass
++);
350 *cycles
= g_list_prepend (*cycles
, cycle
);
351 prune_modules (plugin_manager
, cycle
);
352 unresolve_dependencies (plugin_manager
);
356 /* Now that there is a fully resolved dependency tree, sort
357 * priv->available_plugins to create a valid load order */
358 priv
->available_plugins
= g_list_sort (priv
->available_plugins
,
359 (GCompareFunc
)dependency_compare
);
362 /* Plugins loading */
365 str_has_suffix (const char *haystack
, const char *needle
)
369 if (needle
== NULL
) {
372 if (haystack
== NULL
) {
373 return needle
[0] == '\0';
376 /* Eat one character at a time. */
377 h
= haystack
+ strlen(haystack
);
378 n
= needle
+ strlen(needle
);
386 } while (*--h
== *--n
);
391 load_plugin (AnjutaPluginManager
*plugin_manager
,
392 const gchar
*plugin_desc_path
)
394 AnjutaPluginManagerPriv
*priv
;
395 AnjutaPluginHandle
*plugin_handle
;
397 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
));
398 priv
= plugin_manager
->priv
;
400 plugin_handle
= anjuta_plugin_handle_new (plugin_desc_path
);
403 if (g_hash_table_lookup (priv
->plugins_by_name
,
404 anjuta_plugin_handle_get_id (plugin_handle
)))
406 g_object_unref (plugin_handle
);
411 /* Available plugin */
412 priv
->available_plugins
= g_list_prepend (priv
->available_plugins
,
415 g_hash_table_insert (priv
->plugins_by_name
,
416 (gchar
*)anjuta_plugin_handle_get_id (plugin_handle
),
419 /* Index by description */
420 g_hash_table_insert (priv
->plugins_by_description
,
421 anjuta_plugin_handle_get_description (plugin_handle
),
424 /* Index by interfaces exported by this plugin */
425 node
= anjuta_plugin_handle_get_interfaces (plugin_handle
);
434 objs
= (GList
*)g_hash_table_lookup (priv
->plugins_by_interfaces
, iface
);
440 if (obj_node
->data
== plugin_handle
)
445 obj_node
= g_list_next (obj_node
);
449 g_hash_table_steal (priv
->plugins_by_interfaces
, iface
);
450 objs
= g_list_prepend (objs
, plugin_handle
);
451 g_hash_table_insert (priv
->plugins_by_interfaces
, iface
, objs
);
453 node
= g_list_next (node
);
461 load_plugins_from_directory (AnjutaPluginManager
* plugin_manager
,
462 const gchar
*dirname
)
465 struct dirent
*entry
;
467 dir
= opendir (dirname
);
474 for (entry
= readdir (dir
); entry
!= NULL
; entry
= readdir (dir
))
476 if (str_has_suffix (entry
->d_name
, ".plugin"))
479 pathname
= g_strdup_printf ("%s/%s", dirname
, entry
->d_name
);
480 load_plugin (plugin_manager
,pathname
);
487 /* Plugin activation and deactivation */
490 on_plugin_activated (AnjutaPlugin
*plugin_object
, AnjutaPluginHandle
*plugin
)
492 AnjutaPluginManager
*plugin_manager
;
493 AnjutaPluginManagerPriv
*priv
;
495 /* FIXME: Pass plugin_manager directly in signal arguments */
496 plugin_manager
= anjuta_shell_get_plugin_manager (plugin_object
->shell
, NULL
);
498 g_return_if_fail(plugin_manager
!= NULL
);
500 priv
= plugin_manager
->priv
;
502 g_hash_table_insert (priv
->activated_plugins
, plugin
,
503 g_object_ref (plugin_object
));
504 g_hash_table_remove (priv
->plugins_cache
, plugin
);
506 g_signal_emit_by_name (plugin_manager
, "plugin-activated",
512 on_plugin_deactivated (AnjutaPlugin
*plugin_object
, AnjutaPluginHandle
*plugin
)
514 AnjutaPluginManager
*plugin_manager
;
515 AnjutaPluginManagerPriv
*priv
;
517 /* FIXME: Pass plugin_manager directly in signal arguments */
518 plugin_manager
= anjuta_shell_get_plugin_manager (plugin_object
->shell
, NULL
);
520 g_return_if_fail (plugin_manager
!= NULL
);
522 priv
= plugin_manager
->priv
;
524 g_hash_table_insert (priv
->plugins_cache
, plugin
, g_object_ref (plugin_object
));
525 g_hash_table_remove (priv
->activated_plugins
, plugin
);
527 g_signal_emit_by_name (plugin_manager
, "plugin-deactivated",
533 activate_plugin (AnjutaPluginManager
*plugin_manager
,
534 AnjutaPluginHandle
*handle
, GError
**error
)
536 AnjutaPluginManagerPriv
*priv
;
537 IAnjutaPluginFactory
* factory
;
538 AnjutaPlugin
*plugin
;
539 const gchar
*language
;
541 priv
= plugin_manager
->priv
;
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
);
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
);
563 * anjuta_plugin_manager_unload_all_plugins:
564 * @plugin_manager: A #AnjutaPluginManager object
566 * Unload all plugins. Do not take care of the dependencies because all plugins
567 * are unloaded anyway.
570 anjuta_plugin_manager_unload_all_plugins (AnjutaPluginManager
*plugin_manager
)
572 AnjutaPluginManagerPriv
*priv
;
574 priv
= plugin_manager
->priv
;
575 if (g_hash_table_size (priv
->activated_plugins
) > 0 ||
576 g_hash_table_size (priv
->plugins_cache
) > 0)
578 if (g_hash_table_size (priv
->activated_plugins
) > 0)
581 for (node
= g_list_last (priv
->available_plugins
); node
; node
= g_list_previous (node
))
583 AnjutaPluginHandle
*selected_plugin
= node
->data
;
584 AnjutaPlugin
*plugin
;
586 plugin
= g_hash_table_lookup (priv
->activated_plugins
, selected_plugin
);
589 DEBUG_PRINT ("Deactivating plugin: %s",
590 anjuta_plugin_handle_get_id (selected_plugin
));
591 anjuta_plugin_deactivate (plugin
);
594 g_hash_table_remove_all (priv
->activated_plugins
);
596 if (g_hash_table_size (priv
->plugins_cache
) > 0)
600 for (node
= g_list_last (priv
->available_plugins
); node
; node
= g_list_previous (node
))
602 AnjutaPluginHandle
*selected_plugin
= node
->data
;
604 g_hash_table_remove (priv
->plugins_cache
, selected_plugin
);
606 g_hash_table_remove_all (priv
->plugins_cache
);
611 /* Return true if plugin should be unloaded when plugin_to_unloaded is unloaded.
612 * It can be because plugin is or need plugin_to_unload. */
614 should_unload (GHashTable
*activated_plugins
, AnjutaPluginHandle
*plugin_to_unload
,
615 AnjutaPluginHandle
*plugin
)
617 GObject
*plugin_obj
= g_hash_table_lookup (activated_plugins
, plugin
);
622 if (plugin_to_unload
== plugin
)
626 GPOINTER_TO_INT (g_hash_table_lookup (anjuta_plugin_handle_get_dependents (plugin_to_unload
),
631 /* Return true if plugin should be loaded when plugin_to_loaded is loaded.
632 * It can be because plugin_to_load is or need plugin. */
634 should_load (GHashTable
*activated_plugins
, AnjutaPluginHandle
*plugin_to_load
,
635 AnjutaPluginHandle
*plugin
)
637 GObject
*plugin_obj
= g_hash_table_lookup (activated_plugins
, plugin
);
642 if (plugin_to_load
== plugin
)
643 return anjuta_plugin_handle_get_can_load (plugin
);
645 gboolean dependency
=
646 GPOINTER_TO_INT (g_hash_table_lookup (anjuta_plugin_handle_get_dependencies (plugin_to_load
),
648 return (dependency
&& anjuta_plugin_handle_get_can_load (plugin
));
651 static AnjutaPluginHandle
*
652 plugin_for_iter (GtkListStore
*store
, GtkTreeIter
*iter
)
654 AnjutaPluginHandle
*plugin
;
656 gtk_tree_model_get (GTK_TREE_MODEL (store
), iter
, COL_PLUGIN
, &plugin
, -1);
661 update_enabled (GtkTreeModel
*model
, GHashTable
*activated_plugins
)
665 if (gtk_tree_model_get_iter_first (model
, &iter
)) {
667 AnjutaPluginHandle
*plugin
;
671 plugin
= plugin_for_iter(GTK_LIST_STORE(model
), &iter
);
672 plugin_obj
= g_hash_table_lookup (activated_plugins
, plugin
);
673 installed
= (plugin_obj
!= NULL
) ? TRUE
: FALSE
;
674 gtk_tree_model_get (model
, &iter
, COL_PLUGIN
, &plugin
, -1);
675 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
676 COL_ENABLED
, installed
, -1);
677 } while (gtk_tree_model_iter_next (model
, &iter
));
682 plugin_set_update (AnjutaPluginManager
*plugin_manager
,
683 AnjutaPluginHandle
* selected_plugin
,
686 AnjutaPluginManagerPriv
*priv
;
690 priv
= plugin_manager
->priv
;
692 /* Plugins can be loaded or unloaded implicitely because they need or are
693 * needed by another plugin so it is possible that we try to load or unload
694 * respectively an already loaded or already unloaded plugin. */
695 loaded
= g_hash_table_lookup (priv
->activated_plugins
, selected_plugin
) != NULL
;
696 if ((load
&& loaded
) || (!load
&& !loaded
)) return;
699 anjuta_status_busy_push (priv
->status
);
703 /* visit priv->available_plugins in reverse order when unloading, so
704 * that plugins are unloaded in the right order */
705 for (l
= g_list_last(priv
->available_plugins
); l
!= NULL
; l
= l
->prev
)
707 AnjutaPluginHandle
*plugin
= l
->data
;
708 if (should_unload (priv
->activated_plugins
, selected_plugin
, plugin
))
710 AnjutaPlugin
*plugin_obj
= ANJUTA_PLUGIN (g_hash_table_lookup (priv
->activated_plugins
, plugin
));
711 if (!anjuta_plugin_deactivate (plugin_obj
))
713 anjuta_util_dialog_info (GTK_WINDOW (priv
->shell
),
714 dgettext (GETTEXT_PACKAGE
, "Plugin '%s' does not want to be deactivated"),
715 anjuta_plugin_handle_get_name (plugin
));
722 for (l
= priv
->available_plugins
; l
!= NULL
; l
= l
->next
)
724 AnjutaPluginHandle
*plugin
= l
->data
;
725 if (should_load (priv
->activated_plugins
, selected_plugin
, plugin
))
727 AnjutaPlugin
*plugin_obj
;
728 GError
*error
= NULL
;
729 plugin_obj
= g_hash_table_lookup (priv
->plugins_cache
, plugin
);
731 g_object_ref (plugin_obj
);
734 plugin_obj
= activate_plugin (plugin_manager
, plugin
,
740 anjuta_plugin_activate (ANJUTA_PLUGIN (plugin_obj
));
741 g_object_unref (plugin_obj
);
747 gchar
* message
= g_strdup_printf (dgettext (GETTEXT_PACKAGE
, "Could not load %s\n"
748 "This usually means that your installation is corrupted. The "
749 "error message leading to this was:\n%s"),
750 anjuta_plugin_handle_get_name (selected_plugin
),
752 anjuta_util_dialog_error (GTK_WINDOW(plugin_manager
->priv
->shell
),
754 g_error_free (error
);
762 anjuta_status_busy_pop (priv
->status
);
768 plugin_toggled (GtkCellRendererToggle
*cell
, char *path_str
, gpointer data
)
770 AnjutaPluginManager
*plugin_manager
;
771 AnjutaPluginManagerPriv
*priv
;
772 GtkListStore
*store
= GTK_LIST_STORE (data
);
775 AnjutaPluginHandle
*plugin
;
777 GList
*activated_plugins
;
779 AnjutaPlugin
* plugin_object
;
781 path
= gtk_tree_path_new_from_string (path_str
);
783 plugin_manager
= g_object_get_data (G_OBJECT (store
), "plugin-manager");
784 priv
= plugin_manager
->priv
;
786 gtk_tree_model_get_iter (GTK_TREE_MODEL (store
), &iter
, path
);
787 gtk_tree_model_get (GTK_TREE_MODEL (store
), &iter
,
788 COL_ENABLED
, &enabled
,
792 /* Activate one plugin can force the loading of other ones, instead of
793 * searching which plugins have to be activated, we just unmerge all
794 * current plugins and merge all plugins after the modification */
796 /* unmerge all plugins */
797 activated_plugins
= g_hash_table_get_values (priv
->activated_plugins
);
798 for (node
= g_list_first (activated_plugins
); node
!= NULL
; node
= g_list_next (node
))
800 plugin_object
= (AnjutaPlugin
*)node
->data
;
802 IANJUTA_IS_PREFERENCES(plugin_object
))
804 ianjuta_preferences_unmerge (IANJUTA_PREFERENCES (plugin_object
),
805 anjuta_shell_get_preferences (ANJUTA_SHELL (priv
->shell
), NULL
),
809 g_list_free (activated_plugins
);
811 plugin_set_update (plugin_manager
, plugin
, !enabled
);
813 /* Make sure that it appears in the preferences. This method
814 can only be called when the preferences dialog is active so
817 activated_plugins
= g_hash_table_get_values (priv
->activated_plugins
);
818 for (node
= g_list_first (activated_plugins
); node
!= NULL
; node
= g_list_next (node
))
820 plugin_object
= (AnjutaPlugin
*)node
->data
;
822 IANJUTA_IS_PREFERENCES(plugin_object
))
824 ianjuta_preferences_merge (IANJUTA_PREFERENCES (plugin_object
),
825 anjuta_shell_get_preferences (ANJUTA_SHELL (priv
->shell
), NULL
),
829 g_list_free (activated_plugins
);
831 update_enabled (GTK_TREE_MODEL (store
), priv
->activated_plugins
);
832 gtk_tree_path_free (path
);
837 selection_changed (GtkTreeSelection
*selection
, GtkListStore
*store
)
841 if (gtk_tree_selection_get_selected (selection
, NULL
,
843 GtkTextBuffer
*buffer
;
845 GtkWidget
*txt
= g_object_get_data (G_OBJECT (store
),
848 GtkWidget
*image
= g_object_get_data (G_OBJECT (store
),
850 AnjutaPluginHandle
*plugin
= plugin_for_iter (store
, &iter
);
852 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (txt
));
853 gtk_text_buffer_set_text (buffer
, plugin
->about
, -1);
855 if (plugin
->icon_path
) {
856 gtk_image_set_from_file (GTK_IMAGE (image
),
858 gtk_widget_show (GTK_WIDGET (image
));
860 gtk_widget_hide (GTK_WIDGET (image
));
867 create_plugin_tree (void)
871 GtkCellRenderer
*renderer
;
872 GtkTreeViewColumn
*column
;
874 store
= gtk_list_store_new (N_COLS
,
880 tree
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (store
));
882 renderer
= gtk_cell_renderer_toggle_new ();
883 g_signal_connect (G_OBJECT (renderer
), "toggled",
884 G_CALLBACK (plugin_toggled
), store
);
885 column
= gtk_tree_view_column_new_with_attributes (dgettext (GETTEXT_PACKAGE
, "Load"),
892 gtk_tree_view_append_column (GTK_TREE_VIEW (tree
), column
);
893 gtk_tree_view_column_set_sizing (column
,
894 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
896 column
= gtk_tree_view_column_new ();
897 renderer
= gtk_cell_renderer_pixbuf_new ();
898 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
899 gtk_tree_view_column_add_attribute (column
, renderer
, "pixbuf",
901 renderer
= gtk_cell_renderer_text_new ();
902 g_object_set(renderer
, "ellipsize", PANGO_ELLIPSIZE_END
, NULL
);
903 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
904 gtk_tree_view_column_add_attribute (column
, renderer
, "markup",
906 gtk_tree_view_column_set_sizing (column
,
907 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
908 gtk_tree_view_column_set_title (column
, dgettext (GETTEXT_PACKAGE
, "Available Plugins"));
909 gtk_tree_view_append_column (GTK_TREE_VIEW (tree
), column
);
910 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (tree
), column
);
912 g_object_unref (store
);
916 /* Sort function for plugins */
918 sort_plugins(gconstpointer a
, gconstpointer b
)
920 g_return_val_if_fail (a
!= NULL
, 0);
921 g_return_val_if_fail (b
!= NULL
, 0);
923 AnjutaPluginHandle
* plugin_a
= ANJUTA_PLUGIN_HANDLE (a
);
924 AnjutaPluginHandle
* plugin_b
= ANJUTA_PLUGIN_HANDLE (b
);
926 return strcmp (anjuta_plugin_handle_get_name (plugin_a
),
927 anjuta_plugin_handle_get_name (plugin_b
));
930 /* If show_all == FALSE, show only user activatable plugins
931 * If show_all == TRUE, show all plugins
934 populate_plugin_model (AnjutaPluginManager
*plugin_manager
,
936 GHashTable
*plugins_to_show
,
937 GHashTable
*activated_plugins
,
940 AnjutaPluginManagerPriv
*priv
;
941 GList
*sorted_plugins
, *l
;
943 priv
= plugin_manager
->priv
;
944 gtk_list_store_clear (store
);
946 sorted_plugins
= g_list_copy (priv
->available_plugins
);
947 sorted_plugins
= g_list_sort (sorted_plugins
, sort_plugins
);
949 for (l
= sorted_plugins
; l
!= NULL
; l
= l
->next
)
951 AnjutaPluginHandle
*plugin
= l
->data
;
953 /* If plugins to show is NULL, show all available plugins */
954 if (plugins_to_show
== NULL
||
955 g_hash_table_lookup (plugins_to_show
, plugin
))
958 gboolean enable
= FALSE
;
959 if (g_hash_table_lookup (activated_plugins
, plugin
))
962 if (anjuta_plugin_handle_get_name (plugin
) &&
963 anjuta_plugin_handle_get_description (plugin
) &&
964 (anjuta_plugin_handle_get_user_activatable (plugin
) ||
966 (g_hash_table_lookup (plugin_manager
->priv
->disable_plugins
, plugin
) == NULL
))
971 text
= g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
972 anjuta_plugin_handle_get_name (plugin
),
973 anjuta_plugin_handle_get_about (plugin
));
975 gtk_list_store_append (store
, &iter
);
976 gtk_list_store_set (store
, &iter
,
978 anjuta_plugin_handle_get_user_activatable (plugin
),
983 if (anjuta_plugin_handle_get_icon_path (plugin
))
986 icon
= gdk_pixbuf_new_from_file_at_size (anjuta_plugin_handle_get_icon_path (plugin
),
989 gtk_list_store_set (store
, &iter
,
991 g_object_unref (icon
);
999 g_list_free (sorted_plugins
);
1003 create_remembered_plugins_tree (void)
1005 GtkListStore
*store
;
1007 GtkCellRenderer
*renderer
;
1008 GtkTreeViewColumn
*column
;
1010 store
= gtk_list_store_new (N_REM_COLS
, GDK_TYPE_PIXBUF
, 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",
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",
1023 gtk_tree_view_column_set_sizing (column
,
1024 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
1025 gtk_tree_view_column_set_title (column
, dgettext (GETTEXT_PACKAGE
, "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
);
1034 foreach_remembered_plugin (gpointer key
, gpointer value
, gpointer user_data
)
1036 AnjutaPluginHandle
*handle
= (AnjutaPluginHandle
*) value
;
1037 GtkListStore
*store
= GTK_LIST_STORE (user_data
);
1038 AnjutaPluginManager
*manager
= g_object_get_data (G_OBJECT (store
),
1041 if (anjuta_plugin_handle_get_name (handle
) &&
1042 anjuta_plugin_handle_get_description (handle
))
1047 text
= g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s",
1048 anjuta_plugin_handle_get_name (handle
),
1049 anjuta_plugin_handle_get_about (handle
));
1051 gtk_list_store_append (store
, &iter
);
1052 gtk_list_store_set (store
, &iter
,
1054 COL_REM_PLUGIN_KEY
, key
,
1056 if (anjuta_plugin_handle_get_icon_path (handle
))
1059 icon
= gdk_pixbuf_new_from_file_at_size (anjuta_plugin_handle_get_icon_path (handle
),
1062 gtk_list_store_set (store
, &iter
,
1063 COL_REM_ICON
, icon
, -1);
1064 g_object_unref (icon
);
1072 populate_remembered_plugins_model (AnjutaPluginManager
*plugin_manager
,
1073 GtkListStore
*store
)
1075 AnjutaPluginManagerPriv
*priv
= plugin_manager
->priv
;
1076 gtk_list_store_clear (store
);
1077 g_hash_table_foreach (priv
->remember_plugins
, foreach_remembered_plugin
,
1082 on_show_all_plugins_toggled (GtkToggleButton
*button
, GtkListStore
*store
)
1084 AnjutaPluginManager
*plugin_manager
;
1086 plugin_manager
= g_object_get_data (G_OBJECT (button
), "__plugin_manager");
1088 populate_plugin_model (plugin_manager
, store
, NULL
,
1089 plugin_manager
->priv
->activated_plugins
,
1090 !gtk_toggle_button_get_active (button
));
1094 on_forget_plugin_clicked (GtkWidget
*button
, GtkTreeView
*view
)
1097 GtkTreeModel
*model
;
1098 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (view
);
1099 if (gtk_tree_selection_get_selected (selection
, &model
, &iter
))
1102 AnjutaPluginManager
*manager
= g_object_get_data (G_OBJECT (model
),
1104 gtk_tree_model_get (model
, &iter
, COL_REM_PLUGIN_KEY
, &plugin_key
, -1);
1105 g_hash_table_remove (manager
->priv
->remember_plugins
, plugin_key
);
1106 gtk_list_store_remove (GTK_LIST_STORE (model
), &iter
);
1107 g_free (plugin_key
);
1112 on_forget_plugin_sel_changed (GtkTreeSelection
*selection
,
1117 if (gtk_tree_selection_get_selected (selection
, NULL
, &iter
))
1118 gtk_widget_set_sensitive (button
, TRUE
);
1120 gtk_widget_set_sensitive (button
, FALSE
);
1124 anjuta_plugin_manager_get_plugins_page (AnjutaPluginManager
*plugin_manager
)
1127 GtkWidget
*checkbutton
;
1129 GtkWidget
*scrolled
;
1131 GtkToolItem
*toolitem
;
1132 GtkListStore
*store
;
1135 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
1136 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 6);
1138 scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
1139 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled
),
1141 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
),
1143 GTK_POLICY_AUTOMATIC
);
1144 gtk_style_context_set_junction_sides (gtk_widget_get_style_context (scrolled
), GTK_JUNCTION_BOTTOM
);
1145 gtk_box_pack_start (GTK_BOX (vbox
), scrolled
, TRUE
, TRUE
, 0);
1147 toolbar
= gtk_toolbar_new ();
1148 gtk_style_context_add_class (gtk_widget_get_style_context (toolbar
), GTK_STYLE_CLASS_INLINE_TOOLBAR
);
1149 gtk_style_context_set_junction_sides (gtk_widget_get_style_context (toolbar
), GTK_JUNCTION_TOP
);
1150 gtk_box_pack_start (GTK_BOX (vbox
), toolbar
, FALSE
, FALSE
, 0);
1151 gtk_widget_show (toolbar
);
1153 toolitem
= gtk_tool_item_new ();
1154 gtk_toolbar_insert (GTK_TOOLBAR (toolbar
), GTK_TOOL_ITEM (toolitem
), 0);
1155 gtk_widget_show (GTK_WIDGET(toolitem
));
1157 checkbutton
= gtk_check_button_new_with_label (dgettext (GETTEXT_PACKAGE
, "Only show user activatable plugins"));
1158 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton
), TRUE
);
1159 gtk_container_add (GTK_CONTAINER (toolitem
), checkbutton
);
1161 tree
= create_plugin_tree ();
1162 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree
), TRUE
);
1163 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree
), FALSE
);
1164 store
= GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree
)));
1166 populate_plugin_model (plugin_manager
, store
, NULL
,
1167 plugin_manager
->priv
->activated_plugins
, FALSE
);
1169 gtk_container_add (GTK_CONTAINER (scrolled
), tree
);
1170 g_object_set_data (G_OBJECT (store
), "plugin-manager", plugin_manager
);
1173 g_object_set_data (G_OBJECT (checkbutton
), "__plugin_manager", plugin_manager
);
1174 g_signal_connect (G_OBJECT (checkbutton
), "toggled",
1175 G_CALLBACK (on_show_all_plugins_toggled
),
1177 gtk_widget_show_all (vbox
);
1182 anjuta_plugin_manager_get_remembered_plugins_page (AnjutaPluginManager
*plugin_manager
)
1186 GtkWidget
*scrolled
;
1187 GtkListStore
*store
;
1189 GtkWidget
*display_label
;
1190 GtkWidget
*forget_button
;
1191 GtkTreeSelection
*selection
;
1193 /* Remembered plugin */
1194 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 10);
1195 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 10);
1197 display_label
= gtk_label_new (dgettext (GETTEXT_PACKAGE
, "These are the plugins selected by you "
1198 "when you have been prompted to choose one of "
1199 "many suitable plugins. Removing the "
1200 "preferred plugin will let you "
1201 "choose a different plugin."));
1202 gtk_label_set_line_wrap (GTK_LABEL (display_label
), TRUE
);
1203 gtk_box_pack_start (GTK_BOX (vbox
), display_label
, FALSE
, FALSE
, 0);
1205 scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
1206 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled
),
1208 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
),
1209 GTK_POLICY_AUTOMATIC
,
1210 GTK_POLICY_AUTOMATIC
);
1211 gtk_box_pack_start (GTK_BOX (vbox
), scrolled
, TRUE
, TRUE
, 0);
1213 tree
= create_remembered_plugins_tree ();
1214 store
= GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree
)));
1216 gtk_container_add (GTK_CONTAINER (scrolled
), tree
);
1217 g_object_set_data (G_OBJECT (store
), "plugin-manager", plugin_manager
);
1218 populate_remembered_plugins_model (plugin_manager
, store
);
1220 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 0);
1221 gtk_container_set_border_width (GTK_CONTAINER (hbox
), 5);
1222 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 0);
1223 forget_button
= gtk_button_new_with_label (dgettext (GETTEXT_PACKAGE
, "Forget selected plugin"));
1224 gtk_widget_set_sensitive (forget_button
, FALSE
);
1225 gtk_box_pack_end (GTK_BOX (hbox
), forget_button
, FALSE
, FALSE
, 0);
1227 g_signal_connect (forget_button
, "clicked",
1228 G_CALLBACK (on_forget_plugin_clicked
),
1230 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (tree
));
1231 g_signal_connect (selection
, "changed",
1232 G_CALLBACK (on_forget_plugin_sel_changed
),
1234 gtk_widget_show_all (vbox
);
1239 property_to_list (const char *value
)
1245 split_str
= g_strsplit (value
, ",", -1);
1246 for (p
= split_str
; *p
!= NULL
; p
++) {
1247 l
= g_list_prepend (l
, g_strdup (g_strstrip (*p
)));
1249 g_strfreev (split_str
);
1253 static IAnjutaPluginFactory
*
1254 get_plugin_factory (AnjutaPluginManager
*plugin_manager
,
1255 const gchar
*language
,
1258 AnjutaPluginManagerPriv
*priv
;
1259 AnjutaPluginHandle
*plugin
;
1260 GList
*loader_plugins
, *node
;
1261 GList
*valid_plugins
;
1262 GObject
*obj
= NULL
;
1264 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), G_TYPE_INVALID
);
1267 if ((language
== NULL
) || (g_ascii_strcasecmp (language
, "C") == 0))
1269 /* Support of C plugin is built-in */
1270 return IANJUTA_PLUGIN_FACTORY (anjuta_plugin_factory
);
1273 priv
= plugin_manager
->priv
;
1276 /* Find all plugins implementing the IAnjutaPluginLoader interface. */
1277 loader_plugins
= g_hash_table_lookup (priv
->plugins_by_interfaces
, "IAnjutaPluginLoader");
1279 /* Create a list of loader supporting this language */
1280 node
= loader_plugins
;
1281 valid_plugins
= NULL
;
1284 AnjutaPluginDescription
*desc
;
1290 plugin
= node
->data
;
1292 desc
= anjuta_plugin_handle_get_description (plugin
);
1293 if (anjuta_plugin_description_get_string (desc
, "Plugin Loader", "SupportedLanguage", &val
))
1297 vals
= property_to_list (val
);
1306 if (!found
&& (g_ascii_strcasecmp (l_node
->data
, language
) == 0))
1310 g_free (l_node
->data
);
1311 l_node
= g_list_next (l_node
);
1317 valid_plugins
= g_list_prepend (valid_plugins
, plugin
);
1320 node
= g_list_next (node
);
1323 /* Find the first installed plugin from the valid plugins */
1324 node
= valid_plugins
;
1327 plugin
= node
->data
;
1328 obj
= g_hash_table_lookup (priv
->activated_plugins
, plugin
);
1330 node
= g_list_next (node
);
1333 /* If no plugin is installed yet, do something */
1334 if ((obj
== NULL
) && valid_plugins
&& g_list_length (valid_plugins
) == 1)
1336 /* If there is just one plugin, consider it selected */
1337 plugin
= valid_plugins
->data
;
1339 /* Install and return it */
1340 plugin_set_update (plugin_manager
, plugin
, TRUE
);
1341 obj
= g_hash_table_lookup (priv
->activated_plugins
, plugin
);
1343 else if ((obj
== NULL
) && valid_plugins
)
1345 /* Prompt the user to select one of these plugins */
1347 GList
*handles
= NULL
;
1348 node
= valid_plugins
;
1351 plugin
= node
->data
;
1352 handles
= g_list_prepend (handles
, plugin
);
1353 node
= g_list_next (node
);
1355 handles
= g_list_reverse (handles
);
1356 obj
= anjuta_plugin_manager_select_and_activate (plugin_manager
,
1357 dgettext (GETTEXT_PACKAGE
, "Select a plugin"),
1358 dgettext (GETTEXT_PACKAGE
, "Please select a plugin to activate"),
1360 g_list_free (handles
);
1362 g_list_free (valid_plugins
);
1366 return IANJUTA_PLUGIN_FACTORY (obj
);
1369 /* No plugin implementing this interface found */
1370 g_set_error (error
, ANJUTA_PLUGIN_MANAGER_ERROR
,
1371 ANJUTA_PLUGIN_MANAGER_MISSING_FACTORY
,
1372 dgettext (GETTEXT_PACKAGE
, "No plugin is able to load other plugins in %s"), language
);
1378 on_is_active_plugins_foreach (gpointer key
, gpointer data
, gpointer user_data
)
1380 AnjutaPluginHandle
*handle
= ANJUTA_PLUGIN_HANDLE (key
);
1381 gchar
const **search_iface
= (gchar
const **)user_data
;
1383 if (*search_iface
!= NULL
)
1388 interfaces
= anjuta_plugin_handle_get_interfaces (handle
);
1390 for (found
= g_list_first (interfaces
); found
!= NULL
; found
= g_list_next (found
))
1394 found
= g_list_find_custom (interfaces
, *search_iface
, (GCompareFunc
)strcmp
);
1396 if (found
!= NULL
) *search_iface
= NULL
;
1401 * anjuta_plugin_manager_is_active_plugin:
1402 * @plugin_manager: A #AnjutaPluginManager object
1403 * @iface_name: The interface implemented by the object to be found
1405 * Searches if a currently loaded plugins implements
1406 * the given interface.
1408 * Return value: %TRUE is the plugin is currently loaded.
1412 anjuta_plugin_manager_is_active_plugin (AnjutaPluginManager
*plugin_manager
,
1413 const gchar
*iface_name
)
1415 const gchar
*search_iface
= iface_name
;
1417 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), FALSE
);
1419 g_hash_table_foreach (plugin_manager
->priv
->activated_plugins
,
1420 on_is_active_plugins_foreach
,
1423 return search_iface
== NULL
;
1427 * anjuta_plugin_manager_get_plugin:
1428 * @plugin_manager: A #AnjutaPluginManager object
1429 * @iface_name: The interface implemented by the object to be found
1431 * Searches the currently available plugins to find the one which
1432 * implements the given interface as primary interface and returns it. If
1433 * the plugin is not yet loaded, it will be loaded and activated.
1435 * from the pool of plugin objects loaded in this shell and can only search
1436 * by primary interface. If there are more objects implementing this primary
1437 * interface, user might be prompted to select one from them (and might give
1438 * the option to use it as default for future queries). A typical usage of this
1442 * anjuta_plugin_manager_get_plugin (plugin_manager, "IAnjutaDocumentManager", error);
1444 * Notice that this function takes the interface name string as string, unlike
1445 * anjuta_plugins_get_interface() which takes the type directly.
1446 * If no plugin implementing this interface can be found, returns %NULL.
1448 * Return value: The plugin object (subclass of #AnjutaPlugin) which implements
1449 * the given interface or %NULL. See #AnjutaPlugin for more detail on interfaces
1450 * implemented by plugins.
1453 anjuta_plugin_manager_get_plugin (AnjutaPluginManager
*plugin_manager
,
1454 const gchar
*iface_name
)
1456 AnjutaPluginManagerPriv
*priv
;
1457 AnjutaPluginHandle
*plugin
;
1458 GList
*valid_plugins
, *node
;
1460 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
1461 g_return_val_if_fail (iface_name
!= NULL
, NULL
);
1463 priv
= plugin_manager
->priv
;
1466 /* Find all plugins implementing this (primary) interface. */
1467 valid_plugins
= g_hash_table_lookup (priv
->plugins_by_interfaces
, iface_name
);
1469 /* Find the first installed plugin from the valid plugins */
1470 node
= valid_plugins
;
1474 plugin
= node
->data
;
1475 obj
= g_hash_table_lookup (priv
->activated_plugins
, plugin
);
1478 node
= g_list_next (node
);
1481 /* Filter disable plugins */
1482 valid_plugins
= g_list_copy (valid_plugins
);
1483 node
= valid_plugins
;
1486 GList
*next
= g_list_next (node
);
1488 if ((g_hash_table_lookup (priv
->disable_plugins
, node
->data
) != NULL
) &&
1489 (g_hash_table_lookup (priv
->activated_plugins
, node
->data
) == NULL
))
1492 valid_plugins
= g_list_delete_link (valid_plugins
, node
);
1497 /* If no plugin is installed yet, do something */
1498 if (valid_plugins
&&
1499 (g_list_length (valid_plugins
) == 1))
1501 /* If there is just one plugin, consider it selected */
1503 plugin
= valid_plugins
->data
;
1504 g_list_free (valid_plugins
);
1506 /* Install and return it */
1507 plugin_set_update (plugin_manager
, plugin
, TRUE
);
1508 obj
= g_hash_table_lookup (priv
->activated_plugins
, plugin
);
1512 else if (valid_plugins
)
1514 /* Prompt the user to select one of these plugins */
1516 obj
= anjuta_plugin_manager_select_and_activate (plugin_manager
,
1517 dgettext (GETTEXT_PACKAGE
, "Select a plugin"),
1518 dgettext (GETTEXT_PACKAGE
, "<b>Please select a plugin to activate</b>"),
1520 g_list_free (valid_plugins
);
1524 /* No plugin implementing this interface found */
1529 * anjuta_plugin_manager_get_plugin_by_handle:
1530 * @plugin_manager: A #AnjutaPluginManager object
1531 * @handle: A #AnjutaPluginHandle
1533 * Searches the currently available plugins to find the one with the
1534 * specified handle. If the plugin is not yet loaded, it will be loaded
1537 * Return value: The plugin object (subclass of #AnjutaPlugin)
1540 anjuta_plugin_manager_get_plugin_by_handle (AnjutaPluginManager
*plugin_manager
,
1541 AnjutaPluginHandle
*handle
)
1543 AnjutaPluginManagerPriv
*priv
;
1546 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
1547 g_return_val_if_fail (handle
!= NULL
, NULL
);
1549 priv
= plugin_manager
->priv
;
1550 obj
= g_hash_table_lookup (priv
->activated_plugins
, handle
);
1553 plugin_set_update (plugin_manager
, handle
, TRUE
);
1554 obj
= g_hash_table_lookup (priv
->activated_plugins
, handle
);
1561 on_activated_plugins_foreach (gpointer key
, gpointer data
, gpointer user_data
)
1563 AnjutaPluginHandle
*plugin
= ANJUTA_PLUGIN_HANDLE (key
);
1564 GList
**active_plugins
= (GList
**)user_data
;
1565 *active_plugins
= g_list_prepend (*active_plugins
,
1570 on_activated_plugin_objects_foreach (gpointer key
, gpointer data
, gpointer user_data
)
1572 GList
**active_plugins
= (GList
**)user_data
;
1573 *active_plugins
= g_list_prepend (*active_plugins
,
1578 anjuta_plugin_manager_get_active_plugins (AnjutaPluginManager
*plugin_manager
)
1580 GList
*active_plugins
= NULL
;
1582 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
1583 g_hash_table_foreach (plugin_manager
->priv
->activated_plugins
,
1584 on_activated_plugins_foreach
,
1586 return g_list_reverse (active_plugins
);
1590 anjuta_plugin_manager_get_active_plugin_objects (AnjutaPluginManager
*plugin_manager
)
1592 GList
*active_plugins
= NULL
;
1594 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
1595 g_hash_table_foreach (plugin_manager
->priv
->activated_plugins
,
1596 on_activated_plugin_objects_foreach
,
1598 return g_list_reverse (active_plugins
);
1602 * anjuta_plugin_manager_unload_plugin_by_handle:
1603 * @plugin_manager: A #AnjutaPluginManager object
1604 * @handle: A #AnjutaPluginHandle
1606 * Unload the plugin corresponding to the given handle. If the plugin is
1607 * already unloaded, nothing will be done.
1609 * Return value: %TRUE is the plugin is unloaded. %FALSE if a corresponding
1610 * plugin does not exist or if the plugin cannot be unloaded.
1613 anjuta_plugin_manager_unload_plugin_by_handle (AnjutaPluginManager
*plugin_manager
,
1614 AnjutaPluginHandle
*handle
)
1616 AnjutaPluginManagerPriv
*priv
;
1618 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), FALSE
);
1619 g_return_val_if_fail (handle
!= NULL
, FALSE
);
1621 priv
= plugin_manager
->priv
;
1622 plugin_set_update (plugin_manager
, handle
, FALSE
);
1624 /* Check if the plugin has been indeed unloaded */
1625 return g_hash_table_lookup (priv
->activated_plugins
, handle
) == NULL
;
1629 find_plugin_for_object (gpointer key
, gpointer value
, gpointer data
)
1633 g_object_set_data (G_OBJECT (data
), "__plugin_plugin", key
);
1640 * anjuta_plugin_manager_unload_plugin:
1641 * @plugin_manager: A #AnjutaPluginManager object
1642 * @plugin_object: A #AnjutaPlugin object
1644 * Unload the corresponding plugin. The plugin has to be loaded.
1646 * Return value: %TRUE if the plugin has been unloaded. %FALSE if the plugin is
1647 * already or cannot be unloaded.
1650 anjuta_plugin_manager_unload_plugin (AnjutaPluginManager
*plugin_manager
,
1651 GObject
*plugin_object
)
1653 AnjutaPluginManagerPriv
*priv
;
1654 AnjutaPluginHandle
*plugin
;
1656 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), FALSE
);
1657 g_return_val_if_fail (ANJUTA_IS_PLUGIN (plugin_object
), FALSE
);
1659 priv
= plugin_manager
->priv
;
1663 /* Find the plugin that correspond to this plugin object */
1664 g_hash_table_find (priv
->activated_plugins
, find_plugin_for_object
,
1666 plugin
= g_object_get_data (G_OBJECT (plugin_object
), "__plugin_plugin");
1670 plugin_set_update (plugin_manager
, plugin
, FALSE
);
1672 /* Check if the plugin has been indeed unloaded */
1673 if (!g_hash_table_lookup (priv
->activated_plugins
, plugin
))
1678 g_warning ("No plugin found with object \"%p\".", plugin_object
);
1683 anjuta_plugin_manager_list_query (AnjutaPluginManager
*plugin_manager
,
1688 AnjutaPluginManagerPriv
*priv
;
1689 GList
*selected_plugins
= NULL
;
1692 const gchar
*avalue
;
1695 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
1697 priv
= plugin_manager
->priv
;
1698 available
= priv
->available_plugins
;
1702 /* If no query is given, select all plugins */
1705 AnjutaPluginHandle
*plugin
= available
->data
;
1706 if ((g_hash_table_lookup (plugin_manager
->priv
->disable_plugins
, plugin
) == NULL
) ||
1707 (g_hash_table_lookup (plugin_manager
->priv
->activated_plugins
, plugin
) != NULL
))
1708 selected_plugins
= g_list_prepend (selected_plugins
, plugin
);
1709 available
= g_list_next (available
);
1711 return g_list_reverse (selected_plugins
);
1714 g_return_val_if_fail (secs
!= NULL
, NULL
);
1715 g_return_val_if_fail (anames
!= NULL
, NULL
);
1716 g_return_val_if_fail (avalues
!= NULL
, NULL
);
1718 for (;available
; available
= g_list_next (available
))
1720 GList
* s_node
= secs
;
1721 GList
* n_node
= anames
;
1722 GList
* v_node
= avalues
;
1724 gboolean satisfied
= FALSE
;
1726 AnjutaPluginHandle
*plugin
= available
->data
;
1727 AnjutaPluginDescription
*desc
=
1728 anjuta_plugin_handle_get_description (plugin
);
1730 if ((g_hash_table_lookup (plugin_manager
->priv
->disable_plugins
, plugin
) != NULL
) &&
1731 (g_hash_table_lookup (plugin_manager
->priv
->activated_plugins
, plugin
) == NULL
))
1739 gboolean found
= FALSE
;
1744 aname
= n_node
->data
;
1745 avalue
= v_node
->data
;
1747 if (!anjuta_plugin_description_get_string (desc
, sec
, aname
, &val
))
1753 vals
= property_to_list (val
);
1759 if (strchr(node
->data
, '*') != NULL
)
1764 const gchar
*cursor
;
1766 segments
= g_strsplit (node
->data
, "*", -1);
1770 while (*seg_ptr
!= NULL
)
1772 if (strlen (*seg_ptr
) > 0) {
1773 cursor
= strstr (cursor
, *seg_ptr
);
1777 cursor
+= strlen (*seg_ptr
);
1780 if (*seg_ptr
== NULL
)
1782 g_strfreev (segments
);
1784 else if (g_ascii_strcasecmp (node
->data
, avalue
) == 0)
1789 g_free (node
->data
);
1790 node
= g_list_next (node
);
1798 s_node
= g_list_next (s_node
);
1799 n_node
= g_list_next (n_node
);
1800 v_node
= g_list_next (v_node
);
1804 selected_plugins
= g_list_prepend (selected_plugins
, plugin
);
1805 /* DEBUG_PRINT ("Satisfied, Adding %s",
1806 anjuta_plugin_handle_get_name (plugin));*/
1810 return g_list_reverse (selected_plugins
);
1814 anjuta_plugin_manager_query (AnjutaPluginManager
*plugin_manager
,
1815 const gchar
*section_name
,
1816 const gchar
*attribute_name
,
1817 const gchar
*attribute_value
,
1822 GList
*anames
= NULL
;
1823 GList
*avalues
= NULL
;
1826 const gchar
*avalue
;
1827 GList
*selected_plugins
;
1830 if (section_name
== NULL
)
1832 /* If no query is given, select all plugins */
1833 return anjuta_plugin_manager_list_query (plugin_manager
, NULL
, NULL
, NULL
);
1836 g_return_val_if_fail (section_name
!= NULL
, NULL
);
1837 g_return_val_if_fail (attribute_name
!= NULL
, NULL
);
1838 g_return_val_if_fail (attribute_value
!= NULL
, NULL
);
1840 secs
= g_list_prepend (secs
, g_strdup (section_name
));
1841 anames
= g_list_prepend (anames
, g_strdup (attribute_name
));
1842 avalues
= g_list_prepend (avalues
, g_strdup (attribute_value
));
1844 va_start (var_args
, attribute_value
);
1847 sec
= va_arg (var_args
, const gchar
*);
1850 aname
= va_arg (var_args
, const gchar
*);
1853 avalue
= va_arg (var_args
, const gchar
*);
1856 secs
= g_list_prepend (secs
, g_strdup (sec
));
1857 anames
= g_list_prepend (anames
, g_strdup (aname
));
1858 avalues
= g_list_prepend (avalues
, g_strdup (avalue
));
1866 secs
= g_list_reverse (secs
);
1867 anames
= g_list_reverse (anames
);
1868 avalues
= g_list_reverse (avalues
);
1870 selected_plugins
= anjuta_plugin_manager_list_query (plugin_manager
,
1875 anjuta_util_glist_strings_free (secs
);
1876 anjuta_util_glist_strings_free (anames
);
1877 anjuta_util_glist_strings_free (avalues
);
1879 return selected_plugins
;
1885 PLUGIN_HANDLE_COLUMN
,
1890 on_plugin_list_row_activated (GtkTreeView
*tree_view
,
1892 GtkTreeViewColumn
*column
,
1895 gtk_dialog_response (dialog
, GTK_RESPONSE_OK
);
1900 on_plugin_list_show (GtkTreeView
*view
,
1901 GtkDirectionType direction
,
1904 GtkTreeSelection
*selection
;
1905 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
1907 g_signal_emit_by_name (G_OBJECT (selection
), "changed", GTK_DIALOG(dialog
), NULL
);
1912 on_plugin_list_selection_changed (GtkTreeSelection
*tree_selection
,
1915 GtkContainer
*action_area
;
1917 GtkButton
*bt
= NULL
;
1919 action_area
= GTK_CONTAINER (gtk_dialog_get_action_area (dialog
));
1920 list
= gtk_container_get_children (action_area
);
1921 for (; list
; list
= list
->next
) {
1923 if (!strcmp("gtk-ok", gtk_button_get_label (bt
)))
1926 if (bt
&& gtk_tree_selection_get_selected (tree_selection
, NULL
, NULL
))
1927 gtk_widget_set_sensitive ((GtkWidget
*) bt
, TRUE
);
1929 gtk_widget_set_sensitive ((GtkWidget
*) bt
, FALSE
);
1934 * anjuta_plugin_manager_select:
1935 * @plugin_manager: #AnjutaPluginManager object
1936 * @title: Title of the dialog
1937 * @description: label shown on the dialog
1938 * @plugin_handles: List of #AnjutaPluginHandle
1940 * Show a dialog where the user can choose between the given plugins
1942 * Returns: The chosen plugin handle
1944 AnjutaPluginHandle
*
1945 anjuta_plugin_manager_select (AnjutaPluginManager
*plugin_manager
,
1946 gchar
*title
, gchar
*description
,
1947 GList
*plugin_handles
)
1949 AnjutaPluginManagerPriv
*priv
;
1951 AnjutaPluginHandle
*handle
;
1953 GtkTreeModel
*model
;
1955 GtkTreeViewColumn
*column
;
1956 GtkCellRenderer
*renderer
;
1959 GtkWidget
*content_area
;
1961 GtkWidget
*remember_checkbox
;
1963 GtkTreeIter selected
;
1964 GtkTreeSelection
*selection
;
1965 GtkTreeModel
*store
;
1966 GList
*selection_ids
= NULL
;
1967 GString
*remember_key
= g_string_new ("");
1969 g_return_val_if_fail (title
!= NULL
, NULL
);
1970 g_return_val_if_fail (description
!= NULL
, NULL
);
1971 g_return_val_if_fail (plugin_handles
!= NULL
, NULL
);
1973 priv
= plugin_manager
->priv
;
1975 plugin_count
= g_list_length (plugin_handles
);
1976 if (plugin_count
<= 0)
1979 dlg
= gtk_dialog_new_with_buttons (title
, GTK_WINDOW (priv
->shell
),
1980 GTK_DIALOG_DESTROY_WITH_PARENT
,
1982 GTK_RESPONSE_CANCEL
,
1983 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
1984 GTK_STOCK_HELP
, GTK_RESPONSE_HELP
,
1986 gtk_window_set_default_size (GTK_WINDOW (dlg
), 520, 200 + (plugin_count
> 6 ? 300 : plugin_count
* 60));
1988 label
= gtk_label_new (description
);
1989 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
1990 gtk_widget_show (label
);
1991 content_area
= gtk_dialog_get_content_area (GTK_DIALOG (dlg
));
1992 gtk_box_pack_start (GTK_BOX (content_area
), label
,
1995 sc
= gtk_scrolled_window_new (NULL
, NULL
);
1996 gtk_widget_show (sc
);
1997 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sc
),
1999 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sc
),
2000 GTK_POLICY_AUTOMATIC
,
2001 GTK_POLICY_AUTOMATIC
);
2003 gtk_box_pack_start (GTK_BOX (content_area
), sc
,
2006 model
= GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS
, GDK_TYPE_PIXBUF
,
2007 G_TYPE_STRING
, G_TYPE_POINTER
));
2008 view
= gtk_tree_view_new_with_model (model
);
2009 gtk_widget_show (view
);
2010 gtk_container_add (GTK_CONTAINER (sc
), view
);
2012 column
= gtk_tree_view_column_new ();
2013 gtk_tree_view_column_set_sizing (column
,
2014 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
2015 gtk_tree_view_column_set_title (column
, dgettext (GETTEXT_PACKAGE
, "Available Plugins"));
2017 renderer
= gtk_cell_renderer_pixbuf_new ();
2018 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
2019 gtk_tree_view_column_add_attribute (column
, renderer
, "pixbuf",
2022 renderer
= gtk_cell_renderer_text_new ();
2023 g_object_set (G_OBJECT (renderer
), "wrap-mode", PANGO_WRAP_WORD_CHAR
,
2024 "wrap-width", 450, NULL
);
2025 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
2026 gtk_tree_view_column_add_attribute (column
, renderer
, "markup",
2029 gtk_tree_view_append_column (GTK_TREE_VIEW (view
), column
);
2030 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (view
), column
);
2032 g_signal_connect (view
, "row-activated",
2033 G_CALLBACK (on_plugin_list_row_activated
),
2035 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
2036 g_signal_connect(selection
, "changed",
2037 G_CALLBACK(on_plugin_list_selection_changed
),
2039 g_signal_connect(view
, "focus",
2040 G_CALLBACK(on_plugin_list_show
),
2044 gtk_check_button_new_with_label (dgettext (GETTEXT_PACKAGE
, "Remember this selection"));
2045 gtk_container_set_border_width (GTK_CONTAINER (remember_checkbox
), 10);
2046 gtk_widget_show (remember_checkbox
);
2047 gtk_box_pack_start (GTK_BOX (content_area
), remember_checkbox
,
2050 node
= plugin_handles
;
2053 const gchar
*filename
;
2054 GdkPixbuf
*icon_pixbuf
= NULL
;
2055 const gchar
*name
= NULL
;
2056 AnjutaPluginDescription
*desc
;
2058 handle
= (AnjutaPluginHandle
*)node
->data
;
2060 filename
= anjuta_plugin_handle_get_icon_path (handle
);
2061 if (filename
!= NULL
)
2063 icon_pixbuf
= gdk_pixbuf_new_from_file (filename
, NULL
);
2065 g_warning ("Plugin does not define Icon: No such file %s",
2070 g_warning ("Plugin does not define Icon attribute");
2073 name
= anjuta_plugin_handle_get_name (handle
);
2074 desc
= anjuta_plugin_handle_get_description (handle
);
2075 if ((name
!= NULL
) && (desc
!= NULL
))
2081 if (!anjuta_plugin_description_get_locale_string (desc
,
2086 g_warning ("Plugin does not define Description attribute");
2088 text
= g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n%s", name
, plugin_desc
);
2089 g_free (plugin_desc
);
2091 gtk_list_store_append (GTK_LIST_STORE (model
), &iter
);
2092 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
2093 PLUGIN_COLUMN
, text
,
2094 PLUGIN_HANDLE_COLUMN
, handle
, -1);
2096 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
2097 PIXBUF_COLUMN
, icon_pixbuf
, -1);
2101 selection_ids
= g_list_prepend (selection_ids
, (gpointer
)anjuta_plugin_handle_get_id (handle
));
2105 g_warning ("Plugin does not define Name attribute");
2109 g_object_unref (icon_pixbuf
);
2111 node
= g_list_next (node
);
2114 /* Prepare remembering key */
2115 selection_ids
= g_list_sort (selection_ids
,
2116 (GCompareFunc
)strcmp
);
2117 node
= selection_ids
;
2120 g_string_append (remember_key
, (gchar
*)node
->data
);
2121 g_string_append (remember_key
, ",");
2122 node
= g_list_next (node
);
2124 g_list_free (selection_ids
);
2126 /* Find if the selection is remembered */
2127 handle
= g_hash_table_lookup (priv
->remember_plugins
, remember_key
->str
);
2130 g_string_free (remember_key
, TRUE
);
2131 gtk_widget_destroy (dlg
);
2136 response
= gtk_dialog_run (GTK_DIALOG (dlg
));
2139 case GTK_RESPONSE_OK
:
2140 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
2141 if (gtk_tree_selection_get_selected (selection
, &store
,
2144 gtk_tree_model_get (model
, &selected
,
2145 PLUGIN_HANDLE_COLUMN
, &handle
, -1);
2148 /* Remember selection */
2149 if (gtk_toggle_button_get_active
2150 (GTK_TOGGLE_BUTTON (remember_checkbox
)))
2152 /* DEBUG_PRINT ("Remembering selection '%s'",
2153 remember_key->str);*/
2154 g_hash_table_insert (priv
->remember_plugins
,
2155 g_strdup (remember_key
->str
), handle
);
2157 g_string_free (remember_key
, TRUE
);
2158 gtk_widget_destroy (dlg
);
2164 g_string_free (remember_key
, TRUE
);
2165 gtk_widget_destroy (dlg
);
2170 anjuta_plugin_manager_select_and_activate (AnjutaPluginManager
*plugin_manager
,
2173 GList
*plugin_handles
)
2175 AnjutaPluginHandle
*handle
;
2176 GObject
*plugin
= NULL
;
2178 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), NULL
);
2180 handle
= anjuta_plugin_manager_select (plugin_manager
, title
, description
,
2182 plugin
= anjuta_plugin_manager_get_plugin_by_handle (plugin_manager
, handle
);
2188 * anjuta_plugin_manager_get_plugin_handle:
2189 * @plugin_manager: #AnjutaPluginManager object
2190 * @plugin: #AnjutaPlugin object
2192 * Get the handle corresponding to the plugin or %NULL if the plugin is not
2195 * Returns: (transfer none) (allow-none): A #AnjutaPluginHandle or %NULL.
2198 anjuta_plugin_manager_get_plugin_handle (AnjutaPluginManager
*plugin_manager
,
2201 GHashTableIter iter
;
2202 gpointer key
, value
;
2204 g_hash_table_iter_init (&iter
, plugin_manager
->priv
->activated_plugins
);
2205 while (g_hash_table_iter_next (&iter
, &key
, &value
))
2207 if (G_OBJECT(value
) == plugin
)
2209 return ANJUTA_PLUGIN_HANDLE (key
);
2217 /* Plugin manager */
2220 anjuta_plugin_manager_init (AnjutaPluginManager
*object
)
2222 object
->priv
= g_new0 (AnjutaPluginManagerPriv
, 1);
2223 object
->priv
->plugins_by_name
= g_hash_table_new (g_str_hash
, g_str_equal
);
2224 object
->priv
->plugins_by_interfaces
= g_hash_table_new_full (g_str_hash
,
2227 (GDestroyNotify
) g_list_free
);
2228 object
->priv
->plugins_by_description
= g_hash_table_new (g_direct_hash
,
2230 object
->priv
->activated_plugins
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
2231 NULL
, g_object_unref
);
2232 object
->priv
->plugins_cache
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
2233 NULL
, g_object_unref
);
2234 object
->priv
->remember_plugins
= g_hash_table_new_full (g_str_hash
,
2237 object
->priv
->disable_plugins
= g_hash_table_new (g_direct_hash
,
2242 anjuta_plugin_manager_dispose (GObject
*object
)
2244 AnjutaPluginManagerPriv
*priv
;
2245 priv
= ANJUTA_PLUGIN_MANAGER (object
)->priv
;
2247 if (priv
->available_plugins
)
2249 g_list_foreach (priv
->available_plugins
, (GFunc
)g_object_unref
, NULL
);
2250 g_list_free (priv
->available_plugins
);
2251 priv
->available_plugins
= NULL
;
2253 if (priv
->activated_plugins
)
2255 g_hash_table_destroy (priv
->activated_plugins
);
2256 priv
->activated_plugins
= NULL
;
2258 if (priv
->plugins_cache
)
2260 g_hash_table_destroy (priv
->plugins_cache
);
2261 priv
->plugins_cache
= NULL
;
2263 if (priv
->disable_plugins
)
2265 g_hash_table_destroy (priv
->disable_plugins
);
2266 priv
->disable_plugins
= NULL
;
2268 if (priv
->plugins_by_name
)
2270 g_hash_table_destroy (priv
->plugins_by_name
);
2271 priv
->plugins_by_name
= NULL
;
2273 if (priv
->plugins_by_description
)
2275 g_hash_table_destroy (priv
->plugins_by_description
);
2276 priv
->plugins_by_description
= NULL
;
2278 if (priv
->plugins_by_interfaces
)
2280 g_hash_table_destroy (priv
->plugins_by_interfaces
);
2281 priv
->plugins_by_interfaces
= NULL
;
2283 if (priv
->plugin_dirs
)
2285 g_list_foreach (priv
->plugin_dirs
, (GFunc
)g_free
, NULL
);
2286 g_list_free (priv
->plugin_dirs
);
2287 priv
->plugin_dirs
= NULL
;
2290 if (anjuta_c_plugin_factory
)
2292 g_object_unref (anjuta_c_plugin_factory
);
2293 anjuta_c_plugin_factory
= NULL
;
2296 G_OBJECT_CLASS (parent_class
)->dispose (object
);
2300 anjuta_plugin_manager_set_property (GObject
*object
, guint prop_id
,
2301 const GValue
*value
, GParamSpec
*pspec
)
2303 AnjutaPluginManagerPriv
*priv
;
2305 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object
));
2306 priv
= ANJUTA_PLUGIN_MANAGER (object
)->priv
;
2311 priv
->status
= g_value_get_object (value
);
2314 priv
->shell
= g_value_get_object (value
);
2317 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
2323 anjuta_plugin_manager_get_property (GObject
*object
, guint prop_id
,
2324 GValue
*value
, GParamSpec
*pspec
)
2326 AnjutaPluginManagerPriv
*priv
;
2328 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (object
));
2329 priv
= ANJUTA_PLUGIN_MANAGER (object
)->priv
;
2334 g_value_set_object (value
, priv
->shell
);
2337 g_value_set_object (value
, priv
->status
);
2339 case PROP_AVAILABLE_PLUGINS
:
2340 g_value_set_pointer (value
, priv
->available_plugins
);
2342 case PROP_ACTIVATED_PLUGINS
:
2343 g_value_set_pointer (value
, priv
->activated_plugins
);
2346 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
2351 anjuta_plugin_manager_plugin_activated (AnjutaPluginManager
*self
,
2352 AnjutaPluginHandle
* handle
,
2355 /* TODO: Add default signal handler implementation here */
2359 anjuta_plugin_manager_plugin_deactivated (AnjutaPluginManager
*self
,
2360 AnjutaPluginHandle
* handle
,
2363 /* TODO: Add default signal handler implementation here */
2367 anjuta_plugin_manager_class_init (AnjutaPluginManagerClass
*klass
)
2369 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
2370 parent_class
= G_OBJECT_CLASS (g_type_class_peek_parent (klass
));
2372 object_class
->dispose
= anjuta_plugin_manager_dispose
;
2373 object_class
->set_property
= anjuta_plugin_manager_set_property
;
2374 object_class
->get_property
= anjuta_plugin_manager_get_property
;
2376 klass
->plugin_activated
= anjuta_plugin_manager_plugin_activated
;
2377 klass
->plugin_deactivated
= anjuta_plugin_manager_plugin_deactivated
;
2379 g_object_class_install_property (object_class
,
2381 g_param_spec_pointer ("profiles",
2382 dgettext (GETTEXT_PACKAGE
, "Profiles"),
2383 dgettext (GETTEXT_PACKAGE
, "Current stack of profiles"),
2385 g_object_class_install_property (object_class
,
2386 PROP_AVAILABLE_PLUGINS
,
2387 g_param_spec_pointer ("available-plugins",
2388 dgettext (GETTEXT_PACKAGE
, "Available plugins"),
2389 dgettext (GETTEXT_PACKAGE
, "Currently available plugins found in plugin paths"),
2392 g_object_class_install_property (object_class
,
2393 PROP_ACTIVATED_PLUGINS
,
2394 g_param_spec_pointer ("activated-plugins",
2395 dgettext (GETTEXT_PACKAGE
, "Activated plugins"),
2396 dgettext (GETTEXT_PACKAGE
, "Currently activated plugins"),
2398 g_object_class_install_property (object_class
,
2400 g_param_spec_object ("shell",
2401 dgettext (GETTEXT_PACKAGE
, "Anjuta Shell"),
2402 dgettext (GETTEXT_PACKAGE
, "Anjuta shell for which the plugins are made"),
2406 G_PARAM_CONSTRUCT
));
2407 g_object_class_install_property (object_class
,
2409 g_param_spec_object ("status",
2410 dgettext (GETTEXT_PACKAGE
, "Anjuta Status"),
2411 dgettext (GETTEXT_PACKAGE
, "Anjuta status to use in loading and unloading of plugins"),
2415 G_PARAM_CONSTRUCT
));
2417 plugin_manager_signals
[PLUGIN_ACTIVATED
] =
2418 g_signal_new ("plugin-activated",
2419 G_OBJECT_CLASS_TYPE (klass
),
2421 G_STRUCT_OFFSET (AnjutaPluginManagerClass
,
2424 anjuta_cclosure_marshal_VOID__POINTER_OBJECT
,
2426 G_TYPE_POINTER
, ANJUTA_TYPE_PLUGIN
);
2428 plugin_manager_signals
[PLUGIN_DEACTIVATED
] =
2429 g_signal_new ("plugin-deactivated",
2430 G_OBJECT_CLASS_TYPE (klass
),
2432 G_STRUCT_OFFSET (AnjutaPluginManagerClass
,
2433 plugin_deactivated
),
2435 anjuta_cclosure_marshal_VOID__POINTER_OBJECT
,
2437 G_TYPE_POINTER
, ANJUTA_TYPE_PLUGIN
);
2441 anjuta_plugin_manager_get_type (void)
2443 static GType our_type
= 0;
2447 static const GTypeInfo our_info
=
2449 sizeof (AnjutaPluginManagerClass
), /* class_size */
2450 (GBaseInitFunc
) NULL
, /* base_init */
2451 (GBaseFinalizeFunc
) NULL
, /* base_finalize */
2452 (GClassInitFunc
) anjuta_plugin_manager_class_init
, /* class_init */
2453 (GClassFinalizeFunc
) NULL
, /* class_finalize */
2454 NULL
/* class_data */,
2455 sizeof (AnjutaPluginManager
), /* instance_size */
2456 0, /* n_preallocs */
2457 (GInstanceInitFunc
) anjuta_plugin_manager_init
, /* instance_init */
2458 NULL
/* value_table */
2460 our_type
= g_type_register_static (G_TYPE_OBJECT
,
2461 "AnjutaPluginManager",
2468 AnjutaPluginManager
*
2469 anjuta_plugin_manager_new (GObject
*shell
, AnjutaStatus
*status
,
2470 GList
* plugins_directories
)
2472 GObject
*manager_object
;
2473 AnjutaPluginManager
*plugin_manager
;
2474 GList
*cycles
= NULL
;
2475 const char *gnome2_path
;
2479 GList
*plugin_dirs
= NULL
;
2481 /* Initialize the anjuta plugin system */
2482 manager_object
= g_object_new (ANJUTA_TYPE_PLUGIN_MANAGER
,
2483 "shell", shell
, "status", status
, NULL
);
2484 plugin_manager
= ANJUTA_PLUGIN_MANAGER (manager_object
);
2486 if (anjuta_plugin_factory
== NULL
)
2488 anjuta_plugin_factory
= anjuta_c_plugin_factory_new ();
2491 gnome2_path
= g_getenv ("GNOME2_PATH");
2493 pathv
= g_strsplit (gnome2_path
, ":", 1);
2495 for (p
= pathv
; *p
!= NULL
; p
++) {
2496 char *path
= g_strdup (*p
);
2497 plugin_dirs
= g_list_prepend (plugin_dirs
, path
);
2502 node
= plugins_directories
;
2506 char *path
= g_strdup (node
->data
);
2507 plugin_dirs
= g_list_prepend (plugin_dirs
, path
);
2508 node
= g_list_next (node
);
2510 plugin_dirs
= g_list_reverse (plugin_dirs
);
2511 /* load_plugins (); */
2516 load_plugins_from_directory (plugin_manager
, (char*)node
->data
);
2517 node
= g_list_next (node
);
2519 resolve_dependencies (plugin_manager
, &cycles
);
2520 g_list_foreach(plugin_dirs
, (GFunc
) g_free
, NULL
);
2521 g_list_free(plugin_dirs
);
2522 return plugin_manager
;
2526 anjuta_plugin_manager_activate_plugins (AnjutaPluginManager
*plugin_manager
,
2527 GList
*plugins_to_activate
)
2529 AnjutaPluginManagerPriv
*priv
;
2532 priv
= plugin_manager
->priv
;
2534 /* Freeze shell operations */
2535 anjuta_shell_freeze (ANJUTA_SHELL (priv
->shell
), NULL
);
2536 if (plugins_to_activate
)
2538 anjuta_status_progress_add_ticks (ANJUTA_STATUS (priv
->status
),
2539 g_list_length (plugins_to_activate
));
2541 node
= plugins_to_activate
;
2544 AnjutaPluginHandle
*handle
;
2545 const gchar
*filename
;
2546 GdkPixbuf
*icon_pixbuf
= NULL
;
2550 handle
= node
->data
;
2552 filename
= anjuta_plugin_handle_get_icon_path (handle
);
2553 if (filename
!= NULL
)
2555 icon_pixbuf
= gdk_pixbuf_new_from_file (filename
, NULL
);
2557 g_warning ("Plugin does not define Icon: No such file %s",
2561 name
= anjuta_plugin_handle_get_name (handle
);
2564 label
= g_strconcat (dgettext (GETTEXT_PACKAGE
, "Loading:"), " ", name
, "...", NULL
);
2567 anjuta_status_progress_tick (ANJUTA_STATUS (priv
->status
),
2568 icon_pixbuf
, label
);
2571 g_object_unref (icon_pixbuf
);
2573 /* Activate the plugin */
2574 anjuta_plugin_manager_get_plugin_by_handle (plugin_manager
, handle
);
2576 node
= g_list_next (node
);
2579 /* Thaw shell operations */
2580 anjuta_shell_thaw (ANJUTA_SHELL (priv
->shell
), NULL
);
2584 on_collect (gpointer key
, gpointer value
, gpointer user_data
)
2587 gchar
*query
= (gchar
*) key
;
2588 AnjutaPluginHandle
*handle
= (AnjutaPluginHandle
*) value
;
2589 GString
*write_buffer
= (GString
*) user_data
;
2591 id
= anjuta_plugin_handle_get_id (handle
);
2592 g_string_append_printf (write_buffer
, "%s=%s;", query
, id
);
2596 * anjuta_plugin_manager_get_remembered_plugins:
2597 * @plugin_manager: A #AnjutaPluginManager object
2599 * Get the list of plugins loaded when there is a choice between several
2600 * ones without asking the user.
2602 * The list format is returned as a string with the format detailed in
2603 * anjuta_plugin_manager_set_remembered_plugins().
2605 * Return value: (transfer full): a newly-allocated string that must be freed
2610 anjuta_plugin_manager_get_remembered_plugins (AnjutaPluginManager
*plugin_manager
)
2612 AnjutaPluginManagerPriv
*priv
;
2613 GString
*write_buffer
= g_string_new ("");
2615 g_return_val_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
), FALSE
);
2617 priv
= plugin_manager
->priv
;
2618 g_hash_table_foreach (priv
->remember_plugins
, on_collect
,
2620 return g_string_free (write_buffer
, FALSE
);
2624 * anjuta_plugin_manager_set_remembered_plugins:
2625 * @plugin_manager: A #AnjutaPluginManager object
2626 * @remembered_plugins: A list of prefered plugins
2628 * Set the list of plugins loaded when there is a choice between several
2629 * ones without asking the user.
2630 * The list is a string composed of elements separated by ';'. Each element
2631 * is defined with "key=value", where key is the list of possible plugins and
2632 * the value is the choosen plugin.
2634 * By the example the following element
2636 * anjuta-symbol-browser:SymbolBrowserPlugin,anjuta-symbol-db:SymbolDBPlugin,=anjuta-symbol-db:SymbolDBPlugin;
2638 * means if Anjuta has to choose between SymbolBrowserPlugin and
2639 * SymbolDBPlugin, it will choose SymbolDBPlugin.
2642 anjuta_plugin_manager_set_remembered_plugins (AnjutaPluginManager
*plugin_manager
,
2643 const gchar
*remembered_plugins
)
2645 AnjutaPluginManagerPriv
*priv
;
2646 gchar
**strv_lines
, **line_idx
;
2648 g_return_if_fail (ANJUTA_IS_PLUGIN_MANAGER (plugin_manager
));
2649 g_return_if_fail (remembered_plugins
!= NULL
);
2651 priv
= plugin_manager
->priv
;
2653 g_hash_table_remove_all (priv
->remember_plugins
);
2655 strv_lines
= g_strsplit (remembered_plugins
, ";", -1);
2656 line_idx
= strv_lines
;
2659 gchar
**strv_keyvals
;
2660 strv_keyvals
= g_strsplit (*line_idx
, "=", -1);
2661 if (strv_keyvals
&& strv_keyvals
[0] && strv_keyvals
[1])
2663 AnjutaPluginHandle
*handle
;
2664 handle
= g_hash_table_lookup (priv
->plugins_by_name
,
2668 g_hash_table_insert (priv
->remember_plugins
,
2669 g_strdup (strv_keyvals
[0]), handle
);
2671 g_strfreev (strv_keyvals
);
2675 g_strfreev (strv_lines
);
2679 * anjuta_plugin_manager_set_disable_plugins:
2680 * @plugin_manager: A #AnjutaPluginManager object
2681 * @plugins_list: A list of plugins to disable or reenable
2682 * @hide: %TRUE to disable, %FALSE to re-enable plugins in the list
2684 * Disable or re-enable plugins. By default, all plugins are enabled but they
2685 * can be disabled and they will not be proposed when a plugin is requested.
2688 anjuta_plugin_manager_set_disable_plugins (AnjutaPluginManager
*plugin_manager
,
2689 GList
*plugin_handles
,
2696 for (item
= g_list_first (plugin_handles
); item
!= NULL
; item
= g_list_next (item
))
2698 g_hash_table_add (plugin_manager
->priv
->disable_plugins
, item
->data
);
2703 for (item
= g_list_first (plugin_handles
); item
!= NULL
; item
= g_list_next (item
))
2705 g_hash_table_remove (plugin_manager
->priv
->disable_plugins
, item
->data
);