/* * peas-plugin-info.c * This file is part of libpeas * * Copyright (C) 2002-2005 - Paolo Maggi * Copyright (C) 2007 - Steve Frécinaux * * libpeas is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * libpeas 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "config.h" #include #include "peas-i18n-priv.h" #include "peas-plugin-info-priv.h" #include "peas-utils.h" #ifdef G_OS_WIN32 #define OS_HELP_KEY "Help-Windows" #elif defined(OS_OSX) #define OS_HELP_KEY "Help-MacOS-X" #else #define OS_HELP_KEY "Help-GNOME" #endif /** * PeasPluginInfo: * * A #PeasPluginInfo contains all the information available about a plugin. * * All this information comes from the related plugin info file, whose file * extension is ".plugin". Here is an example of such a plugin file, in the * [struct@GLib.KeyFile] format: * * ```toml * [Plugin] * Module=helloworld * Depends=foo;bar;baz * Loader=python * Name=Hello World * Description=Displays "Hello World" * Authors=Steve Frécinaux <code@istique.net> * Copyright=Copyright © 2009-10 Steve Frécinaux * Website=https://wiki.gnome.org/Projects/Libpeas * Help=http://library.gnome.org/devel/libpeas/stable/ * Hidden=false * ``` **/ G_DEFINE_QUARK (peas-plugin-info-error, peas_plugin_info_error) G_DEFINE_FINAL_TYPE (PeasPluginInfo, peas_plugin_info, G_TYPE_OBJECT) enum { PROP_0, PROP_AUTHORS, PROP_BUILTIN, PROP_COPYRIGHT, PROP_DEPENDENCIES, PROP_DESCRIPTION, PROP_HELP_URI, PROP_HIDDEN, PROP_ICON_NAME, PROP_LOADED, PROP_MODULE_DIR, PROP_MODULE_NAME, PROP_NAME, PROP_VERSION, PROP_WEBSITE, N_PROPS }; static GParamSpec *properties [N_PROPS]; static void peas_plugin_info_finalize (GObject *object) { PeasPluginInfo *info = PEAS_PLUGIN_INFO (object); g_clear_pointer (&info->filename, g_free); g_clear_pointer (&info->module_dir, g_free); g_clear_pointer (&info->data_dir, g_free); g_clear_pointer (&info->embedded, g_free); g_clear_pointer (&info->module_name, g_free); g_clear_pointer (&info->dependencies, g_strfreev); g_clear_pointer (&info->name, g_free); g_clear_pointer (&info->desc, g_free); g_clear_pointer (&info->icon_name, g_free); g_clear_pointer (&info->website, g_free); g_clear_pointer (&info->copyright, g_free); g_clear_pointer (&info->version, g_free); g_clear_pointer (&info->help_uri, g_free); g_clear_pointer (&info->authors, g_strfreev); g_clear_pointer (&info->schema_source, g_settings_schema_source_unref); g_clear_pointer (&info->external_data, g_hash_table_unref); g_clear_pointer (&info->error, g_error_free); g_clear_pointer (&info->resources, g_ptr_array_unref); G_OBJECT_CLASS (peas_plugin_info_parent_class)->finalize (object); } static void peas_plugin_info_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { PeasPluginInfo *info = PEAS_PLUGIN_INFO (object); switch (prop_id) { case PROP_AUTHORS: g_value_set_boxed (value, peas_plugin_info_get_authors (info)); break; case PROP_BUILTIN: g_value_set_boolean (value, peas_plugin_info_is_builtin (info)); break; case PROP_COPYRIGHT: g_value_set_string (value, peas_plugin_info_get_copyright (info)); break; case PROP_DEPENDENCIES: g_value_set_boxed (value, peas_plugin_info_get_dependencies (info)); break; case PROP_DESCRIPTION: g_value_set_string (value, peas_plugin_info_get_description (info)); break; case PROP_HELP_URI: g_value_set_string (value, peas_plugin_info_get_help_uri (info)); break; case PROP_HIDDEN: g_value_set_boolean (value, peas_plugin_info_is_hidden (info)); break; case PROP_ICON_NAME: g_value_set_string (value, peas_plugin_info_get_icon_name (info)); break; case PROP_LOADED: g_value_set_boolean (value, peas_plugin_info_is_loaded (info)); break; case PROP_MODULE_DIR: g_value_set_string (value, peas_plugin_info_get_module_dir (info)); break; case PROP_MODULE_NAME: g_value_set_string (value, peas_plugin_info_get_module_name (info)); break; case PROP_NAME: g_value_set_string (value, peas_plugin_info_get_name (info)); break; case PROP_VERSION: g_value_set_string (value, peas_plugin_info_get_version (info)); break; case PROP_WEBSITE: g_value_set_string (value, peas_plugin_info_get_website (info)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void peas_plugin_info_class_init (PeasPluginInfoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = peas_plugin_info_finalize; object_class->get_property = peas_plugin_info_get_property; properties[PROP_BUILTIN] = g_param_spec_boolean (I_("builtin"), NULL, NULL, FALSE, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_LOADED] = g_param_spec_boolean (I_("loaded"), NULL, NULL, FALSE, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_MODULE_NAME] = g_param_spec_string (I_("module-name"), NULL, NULL, NULL, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_MODULE_DIR] = g_param_spec_string (I_("module-dir"), NULL, NULL, NULL, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_NAME] = g_param_spec_string (I_("name"), NULL, NULL, NULL, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_COPYRIGHT] = g_param_spec_string (I_("copyright"), NULL, NULL, NULL, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_DESCRIPTION] = g_param_spec_string (I_("description"), NULL, NULL, NULL, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_ICON_NAME] = g_param_spec_string (I_("icon-name"), NULL, NULL, NULL, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_WEBSITE] = g_param_spec_string (I_("website"), NULL, NULL, NULL, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_VERSION] = g_param_spec_string (I_("version"), NULL, NULL, NULL, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_HIDDEN] = g_param_spec_boolean (I_("hidden"), NULL, NULL, FALSE, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_HELP_URI] = g_param_spec_string (I_("help-uri"), NULL, NULL, NULL, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_DEPENDENCIES] = g_param_spec_boxed (I_("dependencies"), NULL, NULL, G_TYPE_STRV, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_AUTHORS] = g_param_spec_boxed (I_("authors"), NULL, NULL, G_TYPE_STRV, (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_properties (object_class, N_PROPS, properties); } static void peas_plugin_info_init (PeasPluginInfo *info) { } /* * _peas_plugin_info_new: * @filename: The filename where to read the plugin information. * @module_dir: The module directory. * @data_dir: The data directory. * * Creates a new #PeasPluginInfo from a file on the disk. * * Returns: a newly created #PeasPluginInfo. */ PeasPluginInfo * _peas_plugin_info_new (const char *filename, const char *module_dir, const char *data_dir) { gsize i; gboolean is_resource; char *loader = NULL; char **strv, **keys; PeasPluginInfo *info; GKeyFile *plugin_file; GBytes *bytes = NULL; GError *error = NULL; g_return_val_if_fail (filename != NULL, NULL); is_resource = g_str_has_prefix (filename, "resource://"); info = g_object_new (PEAS_TYPE_PLUGIN_INFO, NULL); plugin_file = g_key_file_new (); if (is_resource) { bytes = g_resources_lookup_data (filename + strlen ("resource://"), G_RESOURCE_LOOKUP_FLAGS_NONE, &error); } else { char *content; gsize length; if (g_file_get_contents (filename, &content, &length, &error)) bytes = g_bytes_new_take (content, length); } if (bytes == NULL || !g_key_file_load_from_data (plugin_file, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), G_KEY_FILE_NONE, &error)) { g_warning ("Bad plugin file '%s': %s", filename, error->message); g_error_free (error); goto error; } /* Get module name */ info->module_name = g_key_file_get_string (plugin_file, "Plugin", "Module", NULL); if (info->module_name == NULL || *info->module_name == '\0') { g_warning ("Could not find 'Module' in '[Plugin]' section in '%s'", filename); goto error; } /* Get Name */ info->name = g_key_file_get_locale_string (plugin_file, "Plugin", "Name", NULL, NULL); if (info->name == NULL || *info->name == '\0') { g_warning ("Could not find 'Name' in '[Plugin]' section in '%s'", filename); goto error; } /* Get the loader for this plugin */ loader = g_key_file_get_string (plugin_file, "Plugin", "Loader", NULL); if (loader == NULL || *loader == '\0') { /* Default to the C loader */ info->loader_id = PEAS_UTILS_C_LOADER_ID; } else { info->loader_id = peas_utils_get_loader_id (loader); if (info->loader_id == -1) { g_warning ("Unkown 'Loader' in '[Plugin]' section in '%s': %s", filename, loader); goto error; } } /* Get Embedded */ info->embedded = g_key_file_get_string (plugin_file, "Plugin", "Embedded", NULL); if (info->embedded != NULL) { if (info->loader_id != PEAS_UTILS_C_LOADER_ID) { g_warning ("Bad plugin file '%s': embedded plugins " "must use the C plugin loader", filename); goto error; } if (!is_resource) { g_warning ("Bad plugin file '%s': embedded plugins " "must be a resource", filename); goto error; } } else if (is_resource) { g_warning ("Bad plugin file '%s': resource plugins must be embedded", filename); goto error; } /* Get the dependency list */ info->dependencies = g_key_file_get_string_list (plugin_file, "Plugin", "Depends", NULL, NULL); if (info->dependencies == NULL) info->dependencies = g_new0 (char *, 1); /* Get Description */ info->desc = g_key_file_get_locale_string (plugin_file, "Plugin", "Description", NULL, NULL); /* Get Icon */ info->icon_name = g_key_file_get_locale_string (plugin_file, "Plugin", "Icon", NULL, NULL); /* Get Authors */ info->authors = g_key_file_get_string_list (plugin_file, "Plugin", "Authors", NULL, NULL); if (info->authors == NULL) info->authors = g_new0 (char *, 1); /* Get Copyright */ strv = g_key_file_get_string_list (plugin_file, "Plugin", "Copyright", NULL, NULL); if (strv != NULL) { info->copyright = g_strjoinv ("\n", strv); g_strfreev (strv); } /* Get Website */ info->website = g_key_file_get_string (plugin_file, "Plugin", "Website", NULL); /* Get Version */ info->version = g_key_file_get_string (plugin_file, "Plugin", "Version", NULL); /* Get Help URI */ info->help_uri = g_key_file_get_string (plugin_file, "Plugin", OS_HELP_KEY, NULL); if (info->help_uri == NULL) info->help_uri = g_key_file_get_string (plugin_file, "Plugin", "Help", NULL); /* Get Builtin */ info->builtin = g_key_file_get_boolean (plugin_file, "Plugin", "Builtin", NULL); /* Get Hidden */ info->hidden = g_key_file_get_boolean (plugin_file, "Plugin", "Hidden", NULL); keys = g_key_file_get_keys (plugin_file, "Plugin", NULL, NULL); for (i = 0; keys[i] != NULL; ++i) { if (!g_str_has_prefix (keys[i], "X-")) continue; if (info->external_data == NULL) info->external_data = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free); g_hash_table_insert (info->external_data, g_strdup (keys[i] + 2), g_key_file_get_string (plugin_file, "Plugin", keys[i], NULL)); } g_strfreev (keys); g_free (loader); g_bytes_unref (bytes); g_key_file_free (plugin_file); info->filename = g_strdup (filename); info->module_dir = g_strdup (module_dir); info->data_dir = g_build_path (is_resource ? "/" : G_DIR_SEPARATOR_S, data_dir, info->module_name, NULL); /* If we know nothing about the availability of the plugin, set it as available */ info->available = TRUE; return info; error: g_object_unref (info); g_free (loader); g_clear_pointer (&bytes, g_bytes_unref); g_key_file_free (plugin_file); return NULL; } /** * peas_plugin_info_is_loaded: * @info: A #PeasPluginInfo. * * Check if the plugin is loaded. * * Returns: %TRUE if the plugin is loaded. */ gboolean peas_plugin_info_is_loaded (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, FALSE); return info->available && info->loaded; } /** * peas_plugin_info_is_available: * @info: A #PeasPluginInfo. * @error: A #GError. * * Check if the plugin is available. * * A plugin is marked as not available when there is no loader available to * load it, or when there has been an error when trying to load it previously. * If not available then @error will be set. * * Returns: %TRUE if the plugin is available. */ gboolean peas_plugin_info_is_available (const PeasPluginInfo *info, GError **error) { g_return_val_if_fail (info != NULL, FALSE); /* Uses g_propagate_error() so we get the right warning * in the case that *error != NULL */ if (error != NULL && info->error != NULL) g_propagate_error (error, g_error_copy (info->error)); return info->available != FALSE; } /** * peas_plugin_info_is_builtin: * @info: A #PeasPluginInfo. * * Check if the plugin is a builtin plugin. * * A builtin plugin is a plugin which cannot be enabled or disabled by the user * through a plugin manager (like * [PeasGtkPluginManager](https://gnome.pages.gitlab.gnome.org/libpeas/libpeas-gtk-1.0/class.PluginManager.html)). * Loading or unloading such plugins is the responsibility of the application * alone. Most applications will usually load those plugins immediately after * the initialization of the #PeasEngine. * * The relevant key in the plugin info file is "Builtin". * * Returns: %TRUE if the plugin is a builtin plugin, %FALSE * if not. **/ gboolean peas_plugin_info_is_builtin (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, TRUE); return info->builtin; } /** * peas_plugin_info_is_hidden: * @info: A #PeasPluginInfo. * * Check if the plugin is a hidden plugin. * * A hidden plugin is a plugin which cannot be seen by a * user through a plugin manager (like * [PeasGtkPluginManager](https://gnome.pages.gitlab.gnome.org/libpeas/libpeas-gtk-1.0/class.PluginManager.html)). * Loading and * unloading such plugins is the responsibility of the application alone or * through plugins that depend on them. * * The relevant key in the plugin info file is "Hidden". * * Returns: %TRUE if the plugin is a hidden plugin, %FALSE * if not. **/ gboolean peas_plugin_info_is_hidden (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, FALSE); return info->hidden; } /** * peas_plugin_info_get_module_name: * @info: A #PeasPluginInfo. * * Gets the module name. * * The module name will be used to find the actual plugin. The way this value * will be used depends on the loader (i.e. on the language) of the plugin. * This value is also used to uniquely identify a particular plugin. * * The relevant key in the plugin info file is "Module". * * Returns: the module name. */ const char * peas_plugin_info_get_module_name (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, NULL); return info->module_name; } /** * peas_plugin_info_get_module_dir: * @info: A #PeasPluginInfo. * * Gets the module directory. * * The module directory is the directory where the plugin file was found. This * is not a value from the [struct@GLib.KeyFile], but rather a value provided by the * [class@Engine]. * * Returns: the module directory. */ const char * peas_plugin_info_get_module_dir (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, NULL); return info->module_dir; } /** * peas_plugin_info_get_data_dir: * @info: A #PeasPluginInfo. * * Gets the data dir of the plugin. * * The module data directory is the directory where a plugin should find its * runtime data. This is not a value read from the [struct@GLib.KeyFile], but * rather a value provided by the [class@Engine], depending on where the plugin * file was found. * * Returns: the plugin's data dir. */ const char * peas_plugin_info_get_data_dir (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, NULL); return info->data_dir; } /** * peas_plugin_info_get_settings: * @info: A #PeasPluginInfo. * @schema_id: (allow-none): The schema id. * * Creates a new [class@Gio.Settings] for the given @schema_id and if * gschemas.compiled is not in the module directory an attempt * will be made to create it. * * Returns: (transfer full) (nullable): a new #GSettings. * * Since: 1.4 */ GSettings * peas_plugin_info_get_settings (const PeasPluginInfo *info, const char *schema_id) { GSettingsSchema *schema; GSettings *settings; g_return_val_if_fail (info != NULL, NULL); if (info->schema_source == NULL) { GFile *module_dir_location; GFile *gschema_compiled; GSettingsSchemaSource *default_source; module_dir_location = g_file_new_for_path (info->module_dir); gschema_compiled = g_file_get_child (module_dir_location, "gschemas.compiled"); if (!g_file_query_exists (gschema_compiled, NULL)) { const char *argv[] = { "glib-compile-schemas", "--targetdir", info->module_dir, info->module_dir, NULL }; g_spawn_sync (NULL, (char **) argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, NULL, NULL); } g_object_unref (gschema_compiled); g_object_unref (module_dir_location); default_source = g_settings_schema_source_get_default (); ((PeasPluginInfo *) info)->schema_source = g_settings_schema_source_new_from_directory (info->module_dir, default_source, FALSE, NULL); /* glib-compile-schemas already outputted a message */ if (info->schema_source == NULL) return NULL; } if (schema_id == NULL) schema_id = info->module_name; schema = g_settings_schema_source_lookup (info->schema_source, schema_id, FALSE); if (schema == NULL) return NULL; settings = g_settings_new_full (schema, NULL, NULL); g_settings_schema_unref (schema); return settings; } /** * peas_plugin_info_get_dependencies: * @info: A #PeasPluginInfo. * * Gets the dependencies of the plugin. * * The [class@Engine] will always ensure that the dependencies of a plugin are * loaded when the said plugin is loaded. It means that dependencies are * loaded before the plugin, and unloaded after it. Circular dependencies of * plugins lead to undefined loading order. * * The relevant key in the plugin info file is "Depends". * * Returns: (transfer none): the plugin's dependencies. */ const char * const * peas_plugin_info_get_dependencies (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, NULL); return (const char * const *) info->dependencies; } /** * peas_plugin_info_has_dependency: * @info: A #PeasPluginInfo. * @module_name: The name of the plugin to check. * * Check if the plugin depends on another plugin. * * Returns: whether the plugin depends on the plugin @module_name. */ gboolean peas_plugin_info_has_dependency (const PeasPluginInfo *info, const char *module_name) { guint i; g_return_val_if_fail (info != NULL, FALSE); g_return_val_if_fail (module_name != NULL, FALSE); for (i = 0; info->dependencies[i] != NULL; i++) { if (g_ascii_strcasecmp (module_name, info->dependencies[i]) == 0) return TRUE; } return FALSE; } /** * peas_plugin_info_get_name: * @info: A #PeasPluginInfo. * * Gets the name of the plugin. * * The name of a plugin should be a nice short string to be presented in UIs. * * The relevant key in the plugin info file is "Name". * * Returns: the plugin's name. */ const char * peas_plugin_info_get_name (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, NULL); return info->name; } /** * peas_plugin_info_get_description: * @info: A #PeasPluginInfo. * * Gets the description of the plugin. * * The description of the plugin should be a string presenting the purpose of * the plugin. It will typically be presented in a plugin's about box. * * The relevant key in the plugin info file is "Description". * * Returns: the plugin's description. */ const char * peas_plugin_info_get_description (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, NULL); return info->desc; } /** * peas_plugin_info_get_icon_name: * @info: A #PeasPluginInfo. * * Gets the icon name of the plugin. * * The icon of the plugin will be presented in the plugin manager UI. If no * icon is specified, the default green puzzle icon will be used. * * The relevant key in the plugin info file is "Icon". * * Returns: the plugin's icon name. */ const char * peas_plugin_info_get_icon_name (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, NULL); if (info->icon_name != NULL) return info->icon_name; return "libpeas-plugin"; } /** * peas_plugin_info_get_authors: * @info: A #PeasPluginInfo. * * Gets a %NULL-terminated array of strings with the authors of the plugin. * * The relevant key in the plugin info file is "Authors". * * Returns: (transfer none) (array zero-terminated=1): the plugin's author list. */ const char * const * peas_plugin_info_get_authors (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, (const char **) NULL); return (const char * const *) info->authors; } /** * peas_plugin_info_get_website: * @info: A #PeasPluginInfo. * * Gets the website of the plugin. * * The relevant key in the plugin info file is "Website". * * Returns: the plugin's associated website. */ const char * peas_plugin_info_get_website (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, NULL); return info->website; } /** * peas_plugin_info_get_copyright: * @info: A #PeasPluginInfo. * * Gets the copyright of the plugin. * * The relevant key in the plugin info file is "Copyright". * * Returns: the plugin's copyright information. */ const char * peas_plugin_info_get_copyright (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, NULL); return info->copyright; } /** * peas_plugin_info_get_version: * @info: A #PeasPluginInfo. * * Gets the version of the plugin. * * The relevant key in the plugin info file is "Version". * * Returns: the plugin's version. */ const char * peas_plugin_info_get_version (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, NULL); return info->version; } /** * peas_plugin_info_get_help_uri: * @info: A #PeasPluginInfo. * * Gets the help URI of the plugin. * * The Help URI of a plugin will typically be presented by the plugin manager * as a "Help" button linking to the URI. It can either be a HTTP URL on some * website or a ghelp: URI if a Gnome help page is available for the plugin. * * The relevant key in the plugin info file is "Help". Other platform-specific * keys exist for platform-specific help files. Those are "Help-GNOME", * "Help-Windows" and "Help-MacOS-X". * * Returns: the plugin's help URI. */ const char * peas_plugin_info_get_help_uri (const PeasPluginInfo *info) { g_return_val_if_fail (info != NULL, NULL); return info->help_uri; } /** * peas_plugin_info_get_external_data: * @info: A #PeasPluginInfo. * @key: The key to lookup. * * Gets external data specified for the plugin. * * External data is specified in the plugin info file prefixed with X-. For * example, if a key/value pair `X-Peas=1` is specified in the key file, you * can use "Peas" for @key to retrieve the value "1". * * Note: that you can omit the X- prefix when retrieving the value, * but not when specifying the value in the file. * * Returns: (nullable): the external data, or %NULL if the external data could not be found. * * Since: 1.6 */ const char * peas_plugin_info_get_external_data (const PeasPluginInfo *info, const char *key) { g_return_val_if_fail (info != NULL, NULL); g_return_val_if_fail (key != NULL, NULL); if (info->external_data == NULL) return NULL; if (g_str_has_prefix (key, "X-")) key += 2; return g_hash_table_lookup (info->external_data, key); } /** * peas_plugin_info_get_resource: * @info: A #PeasPluginInfo. * @filename: (allow-none): The filename of the resource, or %NULL. * @error: a #GError for error reporting, or %NULL. * * Creates a new #GResource for the given @filename * located in the module directory. If @filename is %NULL * then "${module_name}.gresource" will be loaded. * * Returns: (transfer full): a new #GResource, or %NULL. */ GResource * peas_plugin_info_get_resource (const PeasPluginInfo *info, const char *filename, GError **error) { char *default_filename = NULL; char *full_filename; GResource *resource; g_return_val_if_fail (info != NULL, NULL); g_return_val_if_fail (filename == NULL || filename[0] != '\0', NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); if (filename == NULL) { default_filename = g_strconcat (info->module_name, ".gresource", NULL); filename = (const char *) default_filename; } full_filename = g_build_filename (info->module_dir, filename, NULL); resource = g_resource_load (full_filename, error); g_free (full_filename); g_free (default_filename); return resource; } /** * peas_plugin_info_load_resource: * @info: A #PeasPluginInfo. * @filename: (allow-none): The filename of the resource, or %NULL. * @error: a #GError for error reporting, or %NULL. * * Loads the resource using peas_plugin_info_get_resource() and * registers it. The resource's lifetime will be automatically * handled by @info. * * See peas_plugin_info_get_resource() for more information. */ void peas_plugin_info_load_resource (const PeasPluginInfo *info, const char *filename, GError **error) { GResource *resource; PeasPluginInfo *info_ = (PeasPluginInfo *) info; resource = peas_plugin_info_get_resource (info, filename, error); if (resource == NULL) return; if (info_->resources == NULL) { info_->resources = g_ptr_array_new (); g_ptr_array_set_free_func (info_->resources, (GDestroyNotify) g_resources_unregister); } g_resources_register (resource); g_ptr_array_add (info_->resources, resource); g_resource_unref (resource); }