diff options
author | Christian Hergert <chergert@redhat.com> | 2023-03-21 11:51:46 -0700 |
---|---|---|
committer | Christian Hergert <chergert@redhat.com> | 2023-03-22 16:14:24 -0700 |
commit | 7be1145593f918f902ffbb6a5846a80d557fb89d (patch) | |
tree | a1948de92dc23f3ed89834a1907ba155d19586fd | |
parent | 2f717ec4c98d054a12e4e21a03948eaa930d6c93 (diff) | |
download | libpeas-wip/chergert/gjs-loader.tar.gz |
wip: gjs loaderwip/chergert/gjs-loader
-rw-r--r-- | libpeas/peas-engine.c | 2 | ||||
-rw-r--r-- | libpeas/peas-plugin-info.c | 3 | ||||
-rw-r--r-- | libpeas/peas-utils.c | 5 | ||||
-rw-r--r-- | libpeas/peas-utils.h | 5 | ||||
-rw-r--r-- | loaders/gjs/meson.build | 52 | ||||
-rw-r--r-- | loaders/gjs/peas-gjs.gresource.xml | 6 | ||||
-rw-r--r-- | loaders/gjs/peas-plugin-loader-gjs.cpp | 242 | ||||
-rw-r--r-- | loaders/gjs/peas-plugin-loader-gjs.h | 36 | ||||
-rw-r--r-- | loaders/gjs/plugin.js | 14 | ||||
-rw-r--r-- | loaders/meson.build | 4 | ||||
-rw-r--r-- | meson.build | 4 | ||||
-rw-r--r-- | meson_options.txt | 4 |
12 files changed, 371 insertions, 6 deletions
diff --git a/libpeas/peas-engine.c b/libpeas/peas-engine.c index 2d448f1..34b6376 100644 --- a/libpeas/peas-engine.c +++ b/libpeas/peas-engine.c @@ -967,7 +967,7 @@ get_plugin_loader (PeasEngine *engine, * Enable a loader, enables a loader for plugins. * * The C plugin loader is always enabled. The other plugin - * loaders are: lua5.1, python and python3. + * loaders are: gjs, lua5.1, python and python3. * * For instance, the following code will enable Python 2 plugins * to be loaded: diff --git a/libpeas/peas-plugin-info.c b/libpeas/peas-plugin-info.c index 42058bc..f96a7e9 100644 --- a/libpeas/peas-plugin-info.c +++ b/libpeas/peas-plugin-info.c @@ -387,7 +387,8 @@ _peas_plugin_info_new (const char *filename, goto error; } } - else if (is_resource) + else if (is_resource && + info->loader_id != PEAS_UTILS_GJS_LOADER_ID) { g_warning ("Bad plugin file '%s': resource plugins must be embedded", filename); diff --git a/libpeas/peas-utils.c b/libpeas/peas-utils.c index 433e6cf..5b2691a 100644 --- a/libpeas/peas-utils.c +++ b/libpeas/peas-utils.c @@ -31,17 +31,18 @@ #include "peas-utils.h" static const char *all_plugin_loaders[] = { - "c", "lua5.1", "python", + "c", "lua5.1", "python", "gjs", }; static const char *all_plugin_loader_modules[] = { - "cloader", "lua51loader", "pythonloader", + "cloader", "lua51loader", "pythonloader", "gjsloader", }; static const int conflicting_plugin_loaders[PEAS_UTILS_N_LOADERS][2] = { { -1, -1 }, /* c => {} */ { -1, -1 }, /* lua5.1 => {} */ { -1, -1 }, /* python => {} */ + { -1, -1 }, /* gjs => {} */ }; G_STATIC_ASSERT (G_N_ELEMENTS (all_plugin_loaders) == PEAS_UTILS_N_LOADERS); diff --git a/libpeas/peas-utils.h b/libpeas/peas-utils.h index a01c4b6..a1a4c85 100644 --- a/libpeas/peas-utils.h +++ b/libpeas/peas-utils.h @@ -25,8 +25,9 @@ #include <glib-object.h> -#define PEAS_UTILS_C_LOADER_ID 0 -#define PEAS_UTILS_N_LOADERS 3 +#define PEAS_UTILS_C_LOADER_ID 0 +#define PEAS_UTILS_N_LOADERS 4 +#define PEAS_UTILS_GJS_LOADER_ID 3 G_GNUC_BEGIN_IGNORE_DEPRECATIONS gboolean peas_utils_properties_array_to_parameter_list (GType exten_type, diff --git a/loaders/gjs/meson.build b/loaders/gjs/meson.build new file mode 100644 index 0000000..4d1ffb2 --- /dev/null +++ b/loaders/gjs/meson.build @@ -0,0 +1,52 @@ +add_languages('cpp') + +cxx = meson.get_compiler('cpp') + +gjs_loader_name = 'gjsloader' + +gjs_loader_c = files( + 'peas-plugin-loader-gjs.cpp', +) + +gjs_loader_res = gnome.compile_resources( + 'peas-gjs-resources', + 'peas-gjs.gresource.xml', + export: false, +) + +gjs_loader_deps = [ + libpeas_dep, + gjs_dep, +] + +gjs_loader_c_args = [ + '-DPEAS_LOCALEDIR="@0@"'.format(localedir), +] + +gjs_loader_cpp_args = [] +test_cpp_args = [ + '-Wno-missing-field-initializers', + '-Wno-unused-parameter', +] +foreach arg: test_cpp_args + if cxx.has_multi_arguments(arg) + gjs_loader_cpp_args += arg + endif +endforeach + + +gjs_loader_sha = shared_module( + gjs_loader_name, + gjs_loader_c + gjs_loader_res, + include_directories: rootdir, + dependencies: gjs_loader_deps, + c_args: project_c_args + gjs_loader_c_args, + cpp_args: gjs_loader_cpp_args, + install: true, + install_dir: join_paths( + pkglibdir, + 'loaders', + ), + name_suffix: module_suffix, + gnu_symbol_visibility: 'hidden' +) diff --git a/loaders/gjs/peas-gjs.gresource.xml b/loaders/gjs/peas-gjs.gresource.xml new file mode 100644 index 0000000..a3d6dc8 --- /dev/null +++ b/loaders/gjs/peas-gjs.gresource.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/org/gnome/libpeas/loaders/gjs"> + <file>plugin.js</file> + </gresource> +</gresources> diff --git a/loaders/gjs/peas-plugin-loader-gjs.cpp b/loaders/gjs/peas-plugin-loader-gjs.cpp new file mode 100644 index 0000000..324f4b2 --- /dev/null +++ b/loaders/gjs/peas-plugin-loader-gjs.cpp @@ -0,0 +1,242 @@ +/* + * peas-plugin-loader-gjs.c + * This file is part of libpeas + * + * Copyright 2023 Christian Hergert <chergert@redhat.com> + * + * 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. + */ + +#include "config.h" + +#include <gjs/gjs.h> + +#include <jsapi.h> + +#include <js/Modules.h> +#include <js/String.h> + +#include "peas-plugin-loader-gjs.h" + +#include "libpeas/peas-plugin-info-priv.h" + +struct _PeasPluginLoaderGjs { + PeasPluginLoader parent_instance; + GjsContext *context; +}; + +G_DEFINE_FINAL_TYPE (PeasPluginLoaderGjs, peas_plugin_loader_gjs, PEAS_TYPE_PLUGIN_LOADER) + +static GQuark quark_extension_type; +static const JSClass g_PeasLoader = { "PeasLoader", JSCLASS_GLOBAL_FLAGS, &JS::DefaultGlobalClassOps }; + +G_MODULE_EXPORT void +peas_register_types (PeasObjectModule *module) +{ + peas_object_module_register_extension_type (module, + PEAS_TYPE_PLUGIN_LOADER, + PEAS_TYPE_PLUGIN_LOADER_GJS); +} + +static gboolean +peas_plugin_loader_gjs_provides_extension (PeasPluginLoader *loader, + PeasPluginInfo *info, + GType exten_type) +{ + PeasPluginLoaderGjs *gjsloader = PEAS_PLUGIN_LOADER_GJS (loader); + const char *type_name = g_type_name (exten_type); + const char *module_name = peas_plugin_info_get_module_name (info); + GType the_type = G_TYPE_INVALID; + + g_print ("Checking for %s\n", g_type_name (exten_type)); + +#if 0 + JSContext *cx = (JSContext *)gjs_context_get_native_context (gjsloader->context); + JS::RealmOptions options; + options.creationOptions().setSharedMemoryAndAtomicsEnabled(true); + JS::RootedObject global(cx, JS_NewGlobalObject (cx, &g_PeasLoader, nullptr, JS::OnNewGlobalHookOption::DontFireOnNewGlobalHook, options)); + + + JS::UTF8Chars chars(module_name, strlen (module_name)); + JSString *moduleName = JS_NewStringCopyUTF8N (cx, chars); + JS::HandleObject moduleNameHandle(moduleName); + JSObject *object = JS::GetModuleObject (moduleNameHandle); +#endif + + return the_type != G_TYPE_INVALID; +} + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +static GObject * +peas_plugin_loader_gjs_create_extension (PeasPluginLoader *loader, + PeasPluginInfo *info, + GType exten_type, + guint n_parameters, + GParameter *parameters) +{ + GObject *object = NULL; + GType the_type; + + the_type = G_TYPE_INVALID; + if (the_type == G_TYPE_INVALID) + goto out; + + object = (GObject *)g_object_newv (the_type, n_parameters, parameters); + if (object == NULL) + goto out; + + /* Sink floating references if necessary */ + if (g_object_is_floating (object)) + g_object_ref_sink (object); + + /* We have to remember which interface we are instantiating + * for the deprecated peas_extension_get_extension_type(). + */ + g_object_set_qdata (object, quark_extension_type, + GSIZE_TO_POINTER (exten_type)); + +out: + g_print ("Creating extension %s = %p\n", g_type_name (exten_type), object); + return object; +} +G_GNUC_END_IGNORE_DEPRECATIONS + +static gboolean +peas_plugin_loader_gjs_load (PeasPluginLoader *loader, + PeasPluginInfo *info) +{ + PeasPluginLoaderGjs *gjsloader = PEAS_PLUGIN_LOADER_GJS (loader); + const char *module_dir, *module_name; + JSContext *cx; + char *module_dir_uri = NULL; + char *module_name_js = NULL; + char *module_uri = NULL; + gboolean ret = FALSE; + GError *error = NULL; + + module_dir = peas_plugin_info_get_module_dir (info); + module_name = peas_plugin_info_get_module_name (info); + module_name_js = g_strconcat (module_name, ".js", NULL); + if (g_str_has_prefix (module_dir, "resource://")) + module_dir_uri = g_strdup (module_dir); + else + module_dir_uri = g_strconcat ("file://", module_dir, NULL); + module_uri = g_build_filename (module_dir_uri, module_name_js, NULL); + + cx = gjs_context_get_native_context (gjsloader->context); + + if (!gjs_context_register_module (gjsloader->context, module_name, module_uri, &error)) + { + g_warning ("Registering module %s threw exception: %s", + module_uri, error->message); + g_error_free (error); + goto out; + } + + info->loader_data = gjsloader; + ret = TRUE; + +out: + g_free (module_name_js); + g_free (module_dir_uri); + g_free (module_uri); + + return ret; +} + +static void +peas_plugin_loader_gjs_unload (PeasPluginLoader *loader, + PeasPluginInfo *info) +{ +} + +static void +peas_plugin_loader_gjs_garbage_collect (PeasPluginLoader *loader) +{ + PeasPluginLoaderGjs *gjsloader = PEAS_PLUGIN_LOADER_GJS (loader); + + if (gjsloader->context != NULL) + gjs_context_maybe_gc (gjsloader->context); +} + +static gboolean +peas_plugin_loader_gjs_initialize (PeasPluginLoader *loader) +{ + static const char *search_path[] = { + "resource:///org/gnome/libpeas/loaders/gjs/", + NULL + }; + PeasPluginLoaderGjs *gjsloader = PEAS_PLUGIN_LOADER_GJS (loader); + gboolean ret = FALSE; + + gjsloader->context = (GjsContext *)g_object_new (GJS_TYPE_CONTEXT, + "search-path", search_path, + NULL); + + if (gjsloader->context != NULL) + { + GError *error = NULL; + guint8 status; + + if (!gjs_context_eval_module_file (gjsloader->context, + "resource:///org/gnome/libpeas/loaders/gjs/plugin.js", + &status, + &error)) + { + g_warning ("Failed to load plugin.js: %s", error->message); + g_error_free (error); + goto out; + } + + ret = TRUE; + } + +out: + + return ret; +} + +static void +peas_plugin_loader_gjs_init (PeasPluginLoaderGjs *gjsloader) +{ +} + +static void +peas_plugin_loader_gjs_finalize (GObject *object) +{ + PeasPluginLoaderGjs *gjsloader = PEAS_PLUGIN_LOADER_GJS (object); + + g_clear_object (&gjsloader->context); + + G_OBJECT_CLASS (peas_plugin_loader_gjs_parent_class)->finalize (object); +} + +static void +peas_plugin_loader_gjs_class_init (PeasPluginLoaderGjsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PeasPluginLoaderClass *loader_class = PEAS_PLUGIN_LOADER_CLASS (klass); + + quark_extension_type = g_quark_from_static_string ("peas-extension-type"); + + object_class->finalize = peas_plugin_loader_gjs_finalize; + + loader_class->initialize = peas_plugin_loader_gjs_initialize; + loader_class->load = peas_plugin_loader_gjs_load; + loader_class->unload = peas_plugin_loader_gjs_unload; + loader_class->create_extension = peas_plugin_loader_gjs_create_extension; + loader_class->provides_extension = peas_plugin_loader_gjs_provides_extension; + loader_class->garbage_collect = peas_plugin_loader_gjs_garbage_collect; +} diff --git a/loaders/gjs/peas-plugin-loader-gjs.h b/loaders/gjs/peas-plugin-loader-gjs.h new file mode 100644 index 0000000..8bc4128 --- /dev/null +++ b/loaders/gjs/peas-plugin-loader-gjs.h @@ -0,0 +1,36 @@ +/* + * peas-plugin-loader-gjs.h + * This file is part of libpeas + * + * Copyright 2023 Christian Hergert <chergert@redhat.com> + * + * 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. + */ + +#pragma once + +#include <libpeas.h> + +#include "libpeas/peas-plugin-loader.h" + +G_BEGIN_DECLS + +#define PEAS_TYPE_PLUGIN_LOADER_GJS (peas_plugin_loader_gjs_get_type()) + +G_DECLARE_FINAL_TYPE (PeasPluginLoaderGjs, peas_plugin_loader_gjs, PEAS, PLUGIN_LOADER_GJS, PeasPluginLoader) + +G_MODULE_EXPORT void peas_register_types (PeasObjectModule *module); + +G_END_DECLS diff --git a/loaders/gjs/plugin.js b/loaders/gjs/plugin.js new file mode 100644 index 0000000..aceb86d --- /dev/null +++ b/loaders/gjs/plugin.js @@ -0,0 +1,14 @@ +function providesExtension(moduleName, extensionType) { + const GObject = import('gi://GObject') + const module = import(moduleName); + + for (key in module) { + if ('$gtype' in module[key]) { + if (GObject.type_is_a(module[key]['$gtype'], extensionType)) { + return module[key]['$gtype']; + } + } + } + + return GObject.TYPE_INVALID; +} diff --git a/loaders/meson.build b/loaders/meson.build index 6235ff9..d75c384 100644 --- a/loaders/meson.build +++ b/loaders/meson.build @@ -5,3 +5,7 @@ endif if build_python3_loader == true subdir('python') endif + +if build_gjs_loader == true + subdir('gjs') +endif diff --git a/meson.build b/meson.build index bea1739..cd0ca2d 100644 --- a/meson.build +++ b/meson.build @@ -102,6 +102,7 @@ pygobject_req = '>= 3.2.0' lua_req = '>= 5.1.0' lua_lgi_req = '>= 0.9.0' luajit_req = '>= 2.0' +gjs_req = '>= 1.74' glib_dep = dependency('glib-2.0', version: glib_req) gobject_dep = dependency('gobject-2.0', version: glib_req) @@ -113,6 +114,7 @@ gi_docgen_dep = dependency('gi-docgen', version: '>= 2021.7', fallback: ['gi-docgen', 'dummy_dep'], native: true, required: get_option('gtk_doc')) +gjs_dep = dependency('gjs-1.0', version: gjs_req, required: get_option('gjs')) # From python 3.8 we neeed python3-embed python3_dep = dependency('python3-embed', required: false) @@ -334,6 +336,8 @@ if generate_gir and not introspection_dep.found() generate_gir = false endif +build_gjs_loader = get_option('gjs') + build_lua51_loader = get_option('lua51') lua51_found = (luajit_dep.found() or lua51_dep.found()) and lua_lgi_found if build_lua51_loader and not lua51_found diff --git a/meson_options.txt b/meson_options.txt index 0a07dc9..48a7e8d 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,7 @@ +option('gjs', + type: 'boolean', value: true, + description: 'Enable GJS support (requires gjs-1.0)') + option('lua51', type: 'boolean', value: true, description: 'Enable Lua 5.1 support (requires lua-lgi)') |