From 5d8e439bc597159e3c9f0a8b65c0ae869dead3a8 Mon Sep 17 00:00:00 2001 From: Matthew Fennell Date: Sat, 27 Dec 2025 12:40:20 +0000 Subject: Import Upstream version 43.0 --- src/core/gtd-plugin-manager.c | 323 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 src/core/gtd-plugin-manager.c (limited to 'src/core/gtd-plugin-manager.c') diff --git a/src/core/gtd-plugin-manager.c b/src/core/gtd-plugin-manager.c new file mode 100644 index 0000000..e159916 --- /dev/null +++ b/src/core/gtd-plugin-manager.c @@ -0,0 +1,323 @@ +/* gtd-plugin-manager.c + * + * Copyright (C) 2015-2020 Georges Basile Stavracas Neto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define G_LOG_DOMAIN "GtdPluginManager" + +#include "gtd-activatable.h" +#include "gtd-manager.h" +#include "gtd-panel.h" +#include "gtd-provider.h" +#include "gtd-plugin-manager.h" + +#include + +struct _GtdPluginManager +{ + GtdObject parent; + + GHashTable *info_to_extension; +}; + +G_DEFINE_TYPE (GtdPluginManager, gtd_plugin_manager, GTD_TYPE_OBJECT) + +enum +{ + PLUGIN_LOADED, + PLUGIN_UNLOADED, + NUM_SIGNALS +}; + +static guint signals[NUM_SIGNALS] = { 0, }; + +static const gchar * const default_plugins[] = { + "all-tasks-panel", + "eds", + "task-lists-workspace", + "today-panel", + "inbox-panel", + "next-week-panel", + "peace", +}; + +static gboolean +gtd_str_equal0 (gconstpointer a, + gconstpointer b) +{ + if (a == b) + return TRUE; + else if (!a || !b) + return FALSE; + else + return g_str_equal (a, b); +} + +static gchar** +get_loaded_extensions (const gchar **extensions) +{ + g_autoptr (GPtrArray) loaded_plugins = NULL; + gsize i; + + loaded_plugins = g_ptr_array_new (); + + for (i = 0; extensions && extensions[i]; i++) + g_ptr_array_add (loaded_plugins, g_strdup (extensions[i])); + + for (i = 0; i < G_N_ELEMENTS (default_plugins); i++) + { + if (g_ptr_array_find_with_equal_func (loaded_plugins, + default_plugins[i], + gtd_str_equal0, + NULL)) + { + continue; + } + + g_ptr_array_add (loaded_plugins, g_strdup (default_plugins[i])); + } + + g_ptr_array_add (loaded_plugins, NULL); + + return (gchar**) g_ptr_array_free (g_steal_pointer (&loaded_plugins), FALSE); +} + +static gboolean +from_gsetting_to_property_func (GValue *value, + GVariant *variant, + gpointer user_data) +{ + g_autofree const gchar **extensions = NULL; + g_autofree gchar **loaded_extensions = NULL; + + extensions = g_variant_get_strv (variant, NULL); + loaded_extensions = get_loaded_extensions (extensions); + + g_value_take_boxed (value, g_steal_pointer (&loaded_extensions)); + + return TRUE; +} + +static GVariant* +from_property_to_gsetting_func (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + g_autofree gchar **loaded_extensions = NULL; + const gchar **extensions = NULL; + + extensions = g_value_get_boxed (value); + loaded_extensions = get_loaded_extensions (extensions); + + return g_variant_new_strv ((const gchar * const *)loaded_extensions, -1); +} + +static void +on_plugin_unloaded_cb (PeasEngine *engine, + PeasPluginInfo *info, + GtdPluginManager *self) +{ + GtdActivatable *activatable; + + activatable = g_hash_table_lookup (self->info_to_extension, info); + + if (!activatable) + return; + + /* Deactivates the extension */ + gtd_activatable_deactivate (activatable); + + /* Emit the signal */ + g_signal_emit (self, signals[PLUGIN_UNLOADED], 0, info, activatable); + + g_hash_table_remove (self->info_to_extension, info); + + /* Destroy the extension */ + g_clear_object (&activatable); +} + +static void +on_plugin_loaded_cb (PeasEngine *engine, + PeasPluginInfo *info, + GtdPluginManager *self) +{ + if (peas_engine_provides_extension (engine, info, GTD_TYPE_ACTIVATABLE)) + { + GtdActivatable *activatable; + PeasExtension *extension; + + /* + * Actually create the plugin object, + * which should load all the providers. + */ + extension = peas_engine_create_extension (engine, + info, + GTD_TYPE_ACTIVATABLE, + NULL); + + /* All extensions shall be GtdActivatable impls */ + activatable = GTD_ACTIVATABLE (extension); + + g_hash_table_insert (self->info_to_extension, + info, + extension); + + /* Activate extension */ + gtd_activatable_activate (activatable); + + /* Emit the signal */ + g_signal_emit (self, signals[PLUGIN_LOADED], 0, info, extension); + } +} + +static void +setup_engine (GtdPluginManager *self) +{ + PeasEngine *engine; + gchar *plugin_dir; + + engine = peas_engine_get_default (); + + /* Enable Python3 plugins */ + peas_engine_enable_loader (engine, "python3"); + + /* Let Peas search for plugins in the specified directory */ + plugin_dir = g_build_filename (PACKAGE_LIB_DIR, + "plugins", + NULL); + + peas_engine_add_search_path (engine, + plugin_dir, + NULL); + + g_free (plugin_dir); + + /* User-installed plugins shall be detected too */ + plugin_dir = g_build_filename (g_get_home_dir (), + ".local", + "lib", + "endeavour", + "plugins", + NULL); + + peas_engine_add_search_path (engine, plugin_dir, NULL); + peas_engine_prepend_search_path (engine, + "resource:///org/gnome/todo/plugins", + "resource:///org/gnome/todo/plugins"); + + g_free (plugin_dir); + + /* Hear about loaded plugins */ + g_signal_connect_after (engine, "load-plugin", G_CALLBACK (on_plugin_loaded_cb), self); + g_signal_connect (engine, "unload-plugin",G_CALLBACK (on_plugin_unloaded_cb), self); +} + +static void +gtd_plugin_manager_finalize (GObject *object) +{ + GtdPluginManager *self = (GtdPluginManager *)object; + + g_clear_pointer (&self->info_to_extension, g_hash_table_destroy); + + G_OBJECT_CLASS (gtd_plugin_manager_parent_class)->finalize (object); +} + +static void +gtd_plugin_manager_class_init (GtdPluginManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gtd_plugin_manager_finalize; + + signals[PLUGIN_LOADED] = g_signal_new ("plugin-loaded", + GTD_TYPE_PLUGIN_MANAGER, + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 2, + PEAS_TYPE_PLUGIN_INFO, + GTD_TYPE_ACTIVATABLE); + + signals[PLUGIN_UNLOADED] = g_signal_new ("plugin-unloaded", + GTD_TYPE_PLUGIN_MANAGER, + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 2, + PEAS_TYPE_PLUGIN_INFO, + GTD_TYPE_ACTIVATABLE); +} + +static void +gtd_plugin_manager_init (GtdPluginManager *self) +{ + self->info_to_extension = g_hash_table_new (g_direct_hash, g_direct_equal); + + gtd_object_push_loading (GTD_OBJECT (self)); + + setup_engine (self); + + gtd_object_pop_loading (GTD_OBJECT (self)); +} + +GtdPluginManager* +gtd_plugin_manager_new (void) +{ + return g_object_new (GTD_TYPE_PLUGIN_MANAGER, NULL); +} + +void +gtd_plugin_manager_load_plugins (GtdPluginManager *self) +{ + PeasEngine *engine; + GSettings *settings; + + engine = peas_engine_get_default (); + settings = gtd_manager_get_settings (gtd_manager_get_default ()); + + g_settings_bind_with_mapping (settings, + "active-extensions", + engine, + "loaded-plugins", + G_SETTINGS_BIND_DEFAULT, + from_gsetting_to_property_func, + from_property_to_gsetting_func, + self, + NULL); +} + +GtdActivatable* +gtd_plugin_manager_get_plugin (GtdPluginManager *self, + PeasPluginInfo *info) +{ + g_return_val_if_fail (GTD_IS_PLUGIN_MANAGER (self), NULL); + + return g_hash_table_lookup (self->info_to_extension, info); +} + +GList* +gtd_plugin_manager_get_loaded_plugins (GtdPluginManager *self) +{ + g_return_val_if_fail (GTD_IS_PLUGIN_MANAGER (self), NULL); + + return g_hash_table_get_values (self->info_to_extension); +} -- cgit v1.2.3