gplugin/gplugin

Lots of tweaking and stuff
feature/gjs-cc
2015-09-29, Gary Kramlich
c0bdb3b0512c
Parents 4d963bc9f7a9
Children dee481b2b4ee
Lots of tweaking and stuff
--- a/CMakeLists.txt Tue Jul 14 18:46:53 2015 -0500
+++ b/CMakeLists.txt Tue Sep 29 22:45:21 2015 -0500
@@ -22,7 +22,7 @@
###############################################################################
# Project Info
###############################################################################
-project(gplugin C)
+project(gplugin)
set(GPLUGIN_MAJOR_VERSION 0)
set(GPLUGIN_MINOR_VERSION 0)
@@ -192,6 +192,7 @@
add_subdirectory(plugins)
add_subdirectory(po)
+add_subdirectory(gjs)
add_subdirectory(lua)
add_subdirectory(perl)
add_subdirectory(python)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/CMakeLists.txt Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,43 @@
+option(
+ BUILD_GJS
+ "Whether or not to build the GJS JavaScript plugin loader"
+ "On"
+)
+
+if(BUILD_GJS)
+ remove_definitions(
+ -Wextra
+ -std=c99
+ )
+
+ set(GPLUGIN_GJS_SOURCES
+ gplugin-gjs-core.cc
+ gplugin-gjs-loader.cc
+ gplugin-gjs-plugin.cc
+ )
+
+ set(GPLUGIN_GJS_HEADERS
+ gplugin-gjs-loader.h
+ gplugin-gjs-plugin.h
+ )
+
+ pkg_check_modules(GJS REQUIRED gjs-1.0>=1.32.0)
+ add_library(gplugin-gjs MODULE
+ ${GPLUGIN_GJS_SOURCES}
+ ${GPLUGIN_GJS_HEADERS}
+ )
+ set_target_properties(gplugin-gjs PROPERTIES PREFIX "")
+
+ include_directories(${GJS_INCLUDE_DIRS})
+ target_link_libraries(gplugin-gjs
+ ${GJS_LIBRARIES}
+ gplugin
+ )
+
+ install(TARGETS gplugin-gjs DESTINATION lib/gplugin)
+endif(BUILD_GJS)
+
+if(TESTING_ENABLED)
+ add_subdirectory(tests)
+endif(TESTING_ENABLED)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/gplugin-gjs-core.cc Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gplugin.h>
+#include <gplugin-native.h>
+
+#include "gplugin-gjs-loader.h"
+#include "gplugin-gjs-plugin.h"
+
+extern "C" G_MODULE_EXPORT GPluginPluginInfo *
+gplugin_query(GPLUGIN_UNUSED GError **error) {
+ const gchar * const authors[] = {
+ "Gary Kramlich <grim@reaperworld.com>",
+ NULL
+ };
+
+ return gplugin_plugin_info_new(
+ "gplugin/gjs-loader",
+ GPLUGIN_NATIVE_PLUGIN_ABI_VERSION,
+ "internal", TRUE,
+ "load-on-query", TRUE,
+ "name", "Gjs JavaScript Plugin Loader",
+ "version", GPLUGIN_VERSION,
+ "license-id", "GPL3",
+ "summary", "A plugin that can load Gjs JavaScript plugins",
+ "description", "This plugin allows the loading of plugins written in "
+ "Gjs JavaScript.",
+ "authors", authors,
+ "website", GPLUGIN_WEBSITE,
+ "category", "loaders",
+ NULL
+ );
+}
+
+extern "C" G_MODULE_EXPORT gboolean
+gplugin_load(GPluginNativePlugin *plugin,
+ GPLUGIN_UNUSED GError **error)
+{
+ gplugin_gjs_loader_register(plugin);
+ gplugin_gjs_plugin_register(plugin);
+
+ gplugin_manager_register_loader(gplugin_gjs_loader_get_type());
+
+ return TRUE;
+}
+
+extern "C" G_MODULE_EXPORT gboolean
+gplugin_unload(GPLUGIN_UNUSED GPluginNativePlugin *plugin,
+ GPLUGIN_UNUSED GError **error)
+{
+ return FALSE;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/gplugin-gjs-loader.cc Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gplugin-gjs-loader.h"
+#include "gplugin-gjs-plugin.h"
+
+#include <glib/gi18n.h>
+
+#include <gio/gio.h>
+
+#include <gjs/gjs-module.h>
+#include <gi/object.h>
+
+#include <jsapi.h>
+#include <jspubtd.h>
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GObjectClass *parent_class = NULL;
+static GType type_real = 0;
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static JSFunction *
+gplugin_gjs_loader_find_function(JSContext *jsctx, JSObject *parent,
+ const gchar *name, GError **error)
+{
+ jsval value = JSVAL_VOID;
+
+ g_message("ctx: %p", jsctx);
+ g_message("parent: %p", parent);
+ g_message("name: %s", name);
+
+ if(!JS_GetProperty(jsctx, parent, name, &value)) {
+ if(error) {
+ *error = g_error_new(GPLUGIN_DOMAIN, 0,
+ "Failed to find the function '%s'", name);
+ }
+
+ return NULL;
+ }
+
+ if(JSVAL_IS_VOID(value)) {
+ if(error) {
+ *error = g_error_new(GPLUGIN_DOMAIN, 0, "failed to find %s", name);
+ }
+
+ return NULL;
+ }
+
+ if(JSVAL_IS_OBJECT(value) && !JSVAL_IS_NULL(value)) {
+ return JS_ValueToFunction(jsctx, value);
+ }
+
+ if(error) {
+ *error = g_error_new(GPLUGIN_DOMAIN, 0,
+ "'%s' is not a function", name);
+ }
+
+ return NULL;
+}
+
+static gboolean
+_gplugin_gjs_loader_eval(GjsContext *ctx, JSObject **scope,
+ const gchar *content, gsize content_length,
+ const gchar *filename, gint *exit_code,
+ GError **error)
+{
+ JSContext *jsctx = NULL;
+ JSObject *global = NULL;
+ jsval retval;
+ gboolean ret = TRUE;
+
+ jsctx = (JSContext *)gjs_context_get_native_context(ctx);
+ global = gjs_get_global_object(jsctx);
+
+ JSAutoCompartment ac(jsctx, global);
+ JSAutoRequest ar(jsctx);
+
+ *scope = JS_NewObject(jsctx, NULL, NULL, NULL);
+
+ if(!gjs_eval_with_scope(jsctx, *scope, content, content_length,
+ filename, &retval))
+ {
+ gjs_log_exception(jsctx);
+ g_set_error(error, GPLUGIN_DOMAIN, 0,
+ "JS_EvaluateScript() failed");
+
+ return FALSE;
+ }
+
+ if(exit_code) {
+ if(JSVAL_IS_INT(retval)) {
+ gint ret_code;
+ if(JS_ValueToInt32(jsctx, retval, &ret_code)) {
+ *exit_code = ret_code;
+ }
+ } else {
+ *exit_code = 0;
+ };
+ }
+
+ return ret;
+}
+
+static gboolean
+_gplugin_gjs_loader_eval_file(GjsContext *ctx, JSObject **scope,
+ const char *filename, GError **error)
+{
+ GFile *file = NULL;
+ gchar *contents = NULL;
+ gsize content_length;
+ gboolean ret = FALSE;
+
+ file = g_file_new_for_commandline_arg(filename);
+
+ if(!g_file_query_exists(file, NULL)) {
+ g_object_unref(G_OBJECT(file));
+
+ return FALSE;
+ }
+
+ if(!g_file_load_contents(file, NULL, &contents, &content_length, NULL, error)) {
+ g_object_unref(G_OBJECT(file));
+
+ return FALSE;
+ }
+
+ ret = _gplugin_gjs_loader_eval(ctx, scope, contents, content_length,
+ filename, NULL, error);
+
+ g_object_unref(G_OBJECT(file));
+ g_free(contents);
+
+ return ret;
+}
+
+/******************************************************************************
+ * GPluginLoaderInterface API
+ *****************************************************************************/
+static GSList *
+gplugin_gjs_loader_class_supported_extensions(GPLUGIN_UNUSED const GPluginLoaderClass *klass) {
+ return g_slist_append(NULL, (gpointer)"js");
+}
+
+static GPluginPlugin *
+gplugin_gjs_loader_query(GPluginLoader *loader,
+ const gchar *filename,
+ GError **error)
+{
+ GObject *gobj = NULL;
+ GPluginPluginInfo *info = NULL;
+ GjsContext *context = NULL;
+ JSContext *jsctx = NULL;
+ JSObject *scope = NULL, *jsobj = NULL;
+ JSFunction *query = NULL;
+ jsval value;
+
+ context = gjs_context_new();
+
+ g_message("Scope: %p", scope);
+ if(!_gplugin_gjs_loader_eval_file(context, &scope, filename, error)) {
+ g_object_unref(G_OBJECT(context));
+
+ return NULL;
+ }
+
+ /* grab our context since we're going to pass it to find_function */
+ jsctx = (JSContext *)gjs_context_get_native_context(context);
+
+ /* find the query function */
+ query = gplugin_gjs_loader_find_function(jsctx, scope, "gplugin_query",
+ error);
+
+ g_message("query: %p", query);
+ if(query == NULL) {
+ g_object_unref(G_OBJECT(context));
+
+ return NULL;
+ }
+
+ /* now call the query function */
+ if(!JS_CallFunction(jsctx, scope, query, 0, NULL, &value)) {
+ if(error) {
+ *error = g_error_new(GPLUGIN_DOMAIN, 0,
+ "Failed to call the query function");
+ }
+
+ g_object_unref(G_OBJECT(context));
+
+ return NULL;
+ }
+
+ /* now grab the plugin info */
+ if(!JS_ValueToObject(jsctx, value, &jsobj)) {
+ if(error) {
+ *error = g_error_new(GPLUGIN_DOMAIN, 0,
+ "Query function did not return a GObject");
+ }
+
+ g_object_unref(G_OBJECT(context));
+
+ return NULL;
+ }
+
+ gobj = gjs_g_object_from_object(jsctx, jsobj);
+ if(!GPLUGIN_IS_PLUGIN_INFO(gobj)) {
+ if(error) {
+ *error = g_error_new(GPLUGIN_DOMAIN, 0,
+ "Query function did not return a "
+ "GPluginPluginInfo object");
+ }
+
+ g_object_unref(G_OBJECT(context));
+
+ return NULL;
+ }
+
+ info = GPLUGIN_PLUGIN_INFO(gobj);
+
+ return (GPluginPlugin *)g_object_new(GPLUGIN_TYPE_GJS_PLUGIN,
+ "filename", filename,
+ "loader", loader,
+ "info", info,
+ "context", context,
+ "js-context", jsctx,
+ "global", scope,
+ NULL);
+}
+
+static gboolean
+gplugin_gjs_loader_load_unload(GPLUGIN_UNUSED GPluginLoader *loader,
+ GPluginPlugin *plugin,
+ gboolean load,
+ GPLUGIN_UNUSED GError **error)
+{
+ JSContext *jsctx = NULL;
+ JSFunction *func = NULL;
+ JSObject *global = NULL, *js_plugin = NULL;
+ JSBool ret = FALSE;
+ jsval args[1];
+ jsval rval;
+ const gchar *func_name = (load) ? "gplugin_load" : "gplugin_unload";
+ gchar *filename = NULL;
+
+ g_object_get(G_OBJECT(plugin),
+ "js-context", &jsctx,
+ "global", &global,
+ "filename", &filename,
+ NULL);
+
+ func = gplugin_gjs_loader_find_function(jsctx, global, func_name, error);
+ if(func == NULL) {
+ g_free(filename);
+
+ return FALSE;
+ }
+
+ js_plugin = gjs_object_from_g_object(jsctx, G_OBJECT(plugin));
+
+ args[0] = OBJECT_TO_JSVAL(js_plugin);
+
+ if(!JS_CallFunction(jsctx, global, func, 1, args, &rval)) {
+ if(error) {
+ *error = g_error_new(GPLUGIN_DOMAIN, 0,
+ "Failed to %s %s",
+ (load) ? "load" : "unload", filename);
+ }
+
+ g_free(filename);
+
+ return FALSE;
+ }
+
+ ret = JSVAL_TO_BOOLEAN(rval);
+ if(!ret) {
+ if(error) {
+ *error = g_error_new(GPLUGIN_DOMAIN, 0,
+ "Failed to %s %s",
+ (load) ? "load" : "unload", filename);
+ }
+
+ g_free(filename);
+
+ return FALSE;
+ }
+
+ g_free(filename);
+
+ return TRUE;
+}
+
+static gboolean
+gplugin_gjs_loader_load(GPluginLoader *loader, GPluginPlugin *plugin,
+ GError **error)
+{
+ return gplugin_gjs_loader_load_unload(loader, plugin, TRUE, error);
+}
+
+static gboolean
+gplugin_gjs_loader_unload(GPluginLoader *loader, GPluginPlugin *plugin,
+ GError **error)
+{
+ return gplugin_gjs_loader_load_unload(loader, plugin, FALSE, error);
+}
+
+/******************************************************************************
+ * GObject Stuff
+ *****************************************************************************/
+static void
+gplugin_gjs_loader_class_init(GPluginGjsLoaderClass *klass) {
+ GPluginLoaderClass *loader_class = GPLUGIN_LOADER_CLASS(klass);
+
+ parent_class = (GObjectClass*)g_type_class_peek_parent(klass);
+
+ loader_class->supported_extensions =
+ gplugin_gjs_loader_class_supported_extensions;
+ loader_class->query = gplugin_gjs_loader_query;
+ loader_class->load = gplugin_gjs_loader_load;
+ loader_class->unload = gplugin_gjs_loader_unload;
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+void
+gplugin_gjs_loader_register(GPluginNativePlugin *plugin) {
+ if(g_once_init_enter(&type_real)) {
+ GType type = 0;
+
+ static GTypeInfo info;
+ info.class_size = sizeof(GPluginGjsLoaderClass);
+ info.class_init = (GClassInitFunc)gplugin_gjs_loader_class_init;
+ info.instance_size = sizeof(GPluginGjsLoader);
+
+ type = gplugin_native_plugin_register_type(plugin,
+ GPLUGIN_TYPE_LOADER,
+ "GPluginGjsLoader",
+ &info,
+ (GTypeFlags)0);
+
+ g_once_init_leave(&type_real, type);
+ }
+}
+
+GType
+gplugin_gjs_loader_get_type(void) {
+ if(G_UNLIKELY(type_real == 0)) {
+ g_warning("gplugin_gjs_loader_get_type was called before "
+ "the type was registered!\n");
+ }
+
+ return type_real;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/gplugin-gjs-loader.h Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GPLUGIN_GJS_LOADER_H
+#define GPLUGIN_GJS_LOADER_H
+
+#define GPLUGIN_TYPE_GJS_LOADER (gplugin_gjs_loader_get_type())
+#define GPLUGIN_GJS_LOADER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GPLUGIN_TYPE_GJS_LOADER, GPluginGjsLoader))
+#define GPLUGIN_GJS_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((obj), GPLUGIN_TYPE_GJS_LOADER, GPluginGjsLoaderClass))
+#define GPLUGIN_IS_GJS_LOADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GPLUGIN_TYPE_GJS_LOADER))
+#define GPLUGIN_IS_GJS_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), GPLUGIN_TYPE_GJS_LOADER))
+#define GPLUGIN_GJS_LOADER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GPLUGIN_TYPE_GJS_LOADER, GPluginGjsLoaderClass))
+
+typedef struct _GPluginGjsLoader GPluginGjsLoader;
+typedef struct _GPluginGjsLoaderClass GPluginGjsLoaderClass;
+
+#include <gplugin.h>
+#include <gplugin-native.h>
+
+struct _GPluginGjsLoader {
+ GPluginLoader parent;
+
+ void (*_gplugin_reserved_1)(void);
+ void (*_gplugin_reserved_2)(void);
+ void (*_gplugin_reserved_3)(void);
+ void (*_gplugin_reserved_4)(void);
+};
+
+struct _GPluginGjsLoaderClass {
+ GPluginLoaderClass parent;
+
+ void (*_gplugin_reserved_1)(void);
+ void (*_gplugin_reserved_2)(void);
+ void (*_gplugin_reserved_3)(void);
+ void (*_gplugin_reserved_4)(void);
+};
+
+G_BEGIN_DECLS
+
+void gplugin_gjs_loader_register(GPluginNativePlugin *plugin);
+GType gplugin_gjs_loader_get_type(void);
+
+G_END_DECLS
+
+#endif /* GPLUGIN_GJS_LOADER_H */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/gplugin-gjs-plugin.cc Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gplugin-gjs-plugin.h"
+
+#define GPLUGIN_GJS_PLUGIN_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), GPLUGIN_TYPE_GJS_PLUGIN, GPluginGjsPluginPrivate))
+
+/******************************************************************************
+ * Typedefs
+ *****************************************************************************/
+typedef struct {
+ GjsContext *context;
+ JSObject *global;
+ JSContext *js_context;
+} GPluginGjsPluginPrivate;
+
+/******************************************************************************
+ * Enums
+ *****************************************************************************/
+enum {
+ PROP_ZERO,
+ PROP_CONTEXT,
+ PROP_GLOBAL,
+ PROP_JS_CONTEXT,
+ PROP_LAST,
+};
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GObjectClass *parent_class = NULL;
+static GType type_real = 0;
+
+/******************************************************************************
+ * Private Stuff
+ *****************************************************************************/
+static void
+gplugin_gjs_plugin_set_context(GPluginGjsPlugin *plugin, GjsContext *context) {
+ GPluginGjsPluginPrivate *priv = GPLUGIN_GJS_PLUGIN_GET_PRIVATE(plugin);
+
+ if(priv->context)
+ g_object_unref(G_OBJECT(priv->context));
+
+ if(GJS_IS_CONTEXT(context)) {
+ priv->context = (GjsContext*)g_object_ref(G_OBJECT(context));
+ } else {
+ priv->context = NULL;
+ }
+}
+
+static void
+gplugin_gjs_plugin_set_global_scope(GPluginGjsPlugin *plugin, JSObject *global) {
+ GPluginGjsPluginPrivate *priv = GPLUGIN_GJS_PLUGIN_GET_PRIVATE(plugin);
+
+ priv->global = global;
+}
+
+static void
+gplugin_gjs_plugin_set_js_context(GPluginGjsPlugin *plugin, JSContext *jsctx) {
+ GPluginGjsPluginPrivate *priv = GPLUGIN_GJS_PLUGIN_GET_PRIVATE(plugin);
+
+ priv->js_context = jsctx;
+}
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+gplugin_gjs_plugin_get_property(GObject *obj, guint param_id, GValue *value,
+ GParamSpec *pspec)
+{
+ GPluginGjsPlugin *plugin = GPLUGIN_GJS_PLUGIN(obj);
+
+ switch(param_id) {
+ case PROP_CONTEXT:
+ g_value_set_object(value, gplugin_gjs_plugin_get_context(plugin));
+ break;
+ case PROP_GLOBAL:
+ g_value_set_pointer(value,
+ gplugin_gjs_plugin_get_global_scope(plugin));
+ break;
+ case PROP_JS_CONTEXT:
+ g_value_set_pointer(value,
+ gplugin_gjs_plugin_get_js_context(plugin));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gplugin_gjs_plugin_set_property(GObject *obj, guint param_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GPluginGjsPlugin *plugin = GPLUGIN_GJS_PLUGIN(obj);
+
+ switch(param_id) {
+ case PROP_CONTEXT:
+ gplugin_gjs_plugin_set_context(plugin, (GjsContext*)g_value_get_object(value));
+ break;
+ case PROP_GLOBAL:
+ gplugin_gjs_plugin_set_global_scope(plugin,
+ (JSObject*)g_value_get_pointer(value));
+ break;
+ case PROP_JS_CONTEXT:
+ gplugin_gjs_plugin_set_js_context(plugin,
+ (JSContext*)g_value_get_pointer(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gplugin_gjs_plugin_finalize(GObject *obj) {
+ GPluginGjsPluginPrivate *priv = GPLUGIN_GJS_PLUGIN_GET_PRIVATE(obj);
+
+ if(priv->context)
+ g_object_unref(G_OBJECT(priv->context));
+
+ G_OBJECT_CLASS(parent_class)->finalize(obj);
+}
+
+static void
+gplugin_gjs_plugin_class_init(GPluginGjsPluginClass *klass) {
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+ parent_class = (GObjectClass*)g_type_class_peek_parent(klass);
+
+ g_type_class_add_private(klass, sizeof(GPluginGjsPluginPrivate));
+
+ obj_class->get_property = gplugin_gjs_plugin_get_property;
+ obj_class->set_property = gplugin_gjs_plugin_set_property;
+ obj_class->finalize = gplugin_gjs_plugin_finalize;
+
+ g_object_class_install_property(obj_class, PROP_CONTEXT,
+ g_param_spec_object("context", "context",
+ "The Gjs Context for this plugin",
+ GJS_TYPE_CONTEXT,
+ (GParamFlags)(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS)));
+
+ g_object_class_install_property(obj_class, PROP_GLOBAL,
+ g_param_spec_pointer("global", "global",
+ "The global scope for this plugin",
+ (GParamFlags)(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS)));
+
+ g_object_class_install_property(obj_class, PROP_JS_CONTEXT,
+ g_param_spec_pointer("js-context", "js-context",
+ "The JSContext function for this plugin",
+ (GParamFlags)(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS)));
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+void
+gplugin_gjs_plugin_register(GPluginNativePlugin *plugin) {
+ if(g_once_init_enter(&type_real)) {
+ GType type = 0;
+
+ static GTypeInfo info;
+ info.class_size = sizeof(GPluginGjsPluginClass);
+ info.class_init = (GClassInitFunc)gplugin_gjs_plugin_class_init;
+ info.instance_size = sizeof(GPluginGjsPlugin);
+
+ type = gplugin_native_plugin_register_type(plugin,
+ GPLUGIN_TYPE_PLUGIN,
+ "GPluginGjsPlugin",
+ &info,
+ (GTypeFlags)0);
+
+ g_once_init_leave(&type_real, type);
+ }
+}
+
+GType
+gplugin_gjs_plugin_get_type(void) {
+ if(G_UNLIKELY(type_real == 0)) {
+ g_warning("gplugin_gjs_plugin_get_type was called before "
+ "the type was registered!\n");
+ }
+
+ return type_real;
+}
+
+GjsContext *
+gplugin_gjs_plugin_get_context(const GPluginGjsPlugin *plugin) {
+ GPluginGjsPluginPrivate *priv = NULL;
+
+ g_return_val_if_fail(GPLUGIN_IS_GJS_PLUGIN(plugin), NULL);
+
+ priv = GPLUGIN_GJS_PLUGIN_GET_PRIVATE(plugin);
+
+ return priv->context;
+}
+
+JSObject *
+gplugin_gjs_plugin_get_global_scope(const GPluginGjsPlugin *plugin) {
+ GPluginGjsPluginPrivate *priv = NULL;
+
+ g_return_val_if_fail(GPLUGIN_IS_GJS_PLUGIN(plugin), NULL);
+
+ priv = GPLUGIN_GJS_PLUGIN_GET_PRIVATE(plugin);
+
+ return priv->global;
+}
+
+JSContext *
+gplugin_gjs_plugin_get_js_context(const GPluginGjsPlugin *plugin) {
+ GPluginGjsPluginPrivate *priv = NULL;
+
+ g_return_val_if_fail(GPLUGIN_IS_GJS_PLUGIN(plugin), NULL);
+
+ priv = GPLUGIN_GJS_PLUGIN_GET_PRIVATE(plugin);
+
+ return priv->js_context;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/gplugin-gjs-plugin.h Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GPLUGIN_GJS_PLUGIN_H
+#define GPLUGIN_GJS_PLUGIN_H
+
+#define GPLUGIN_TYPE_GJS_PLUGIN (gplugin_gjs_plugin_get_type())
+#define GPLUGIN_GJS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GPLUGIN_TYPE_GJS_PLUGIN, GPluginGjsPlugin))
+#define GPLUGIN_GJS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((obj), GPLUGIN_TYPE_GJS_PLUGIN, GPluginGjsPluginClass))
+#define GPLUGIN_IS_GJS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GPLUGIN_TYPE_GJS_PLUGIN))
+#define GPLUGIN_IS_GJS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), GPLUGIN_TYPE_GJS_PLUGIN))
+#define GPLUGIN_GJS_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GPLUGIN_TYPE_GJS_PLUGIN, GPluginGjsPluginClass))
+
+typedef struct _GPluginGjsPlugin GPluginGjsPlugin;
+typedef struct _GPluginGjsPluginClass GPluginGjsPluginClass;
+
+#include <gplugin.h>
+#include <gplugin-native.h>
+
+#include <gjs/gjs-module.h>
+
+struct _GPluginGjsPlugin {
+ GPluginPlugin parent;
+};
+
+struct _GPluginGjsPluginClass {
+ GPluginPluginClass parent;
+
+ void (*_gplugin_reserved_1)(void);
+ void (*_gplugin_reserved_2)(void);
+ void (*_gplugin_reserved_3)(void);
+ void (*_gplugin_reserved_4)(void);
+};
+
+G_BEGIN_DECLS
+
+void gplugin_gjs_plugin_register(GPluginNativePlugin *plugin);
+GType gplugin_gjs_plugin_get_type(void);
+
+GjsContext *gplugin_gjs_plugin_get_context(const GPluginGjsPlugin *plugin);
+JSObject *gplugin_gjs_plugin_get_global_scope(const GPluginGjsPlugin *plugin);
+JSContext *gplugin_gjs_plugin_get_js_context(const GPluginGjsPlugin *plugin);
+
+G_END_DECLS
+
+#endif /* GPLUGIN_GJS_PLUGIN_H */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/tests/CMakeLists.txt Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,52 @@
+if(BUILD_GJS)
+
+macro(add_gjs_gtest target)
+ add_executable(${target} ${target}.c)
+ target_link_libraries(${target}
+ ${GLIB_LIBRARIES} ${GJS_LIBRARIES} gplugin
+ )
+ add_dependencies(${target} gplugin-gjs)
+
+ get_target_property(_output_name ${target} RUNTIME_OUTPUT_NAME)
+ if(NOT ${_output_name})
+ get_target_property(_output_name ${target} LOCATION)
+ endif(NOT ${_output_name})
+
+ list(APPEND GJS_TESTS ${_output_name})
+endmacro(add_gjs_gtest)
+
+add_definitions(
+ -DGJS_LOADER_DIR="${CMAKE_BINARY_DIR}/gjs"
+ -DGJS_PLUGIN_DIR="${CMAKE_CURRENT_SOURCE_DIR}/plugins"
+)
+
+add_gjs_gtest(test-gjs-loader)
+target_link_libraries(test-gjs-loader gplugin-loader-tests)
+
+set(GTESTER_GJS_TESTS "${GJS_TESTS}")
+set(GTESTER_GJS_LOG "test-gplugin-gjs.xml")
+set(GTESTER_GJS_JUNIT "test-gplugin-gjs-junit.xml")
+
+add_custom_command(
+ COMMAND ${GTESTER} -k --verbose -o ${GTESTER_GJS_LOG} ${GJS_TESTS}
+ OUTPUT ${GTESTER_GJS_LOG}
+ DEPENDS gplugin gplugin-gjs
+ ${GJS_TESTS} ${CMAKE_CURRENT_SOURCE_DIR}/plugins
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+add_custom_command(
+ COMMAND ${XSLTPROC} -o ${GTESTER_GJS_JUNIT} --nonet
+ ${CMAKE_SOURCE_DIR}/xsl/gtester-junit.xsl
+ ${GTESTER_GJS_LOG}
+ OUTPUT ${GTESTER_GJS_JUNIT}
+ DEPENDS ${GTESTER_GJS_LOG}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+add_custom_target(gjs-tests ALL
+ DEPENDS ${GTESTER_GJS_LOG} ${GTESTER_GJS_JUNIT} ${GJS_TESTS}
+)
+
+endif(BUILD_GJS)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/tests/plugins/basic.js Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ */
+
+const GPlugin = imports.gi.GPlugin;
+
+function gplugin_query() {
+ return new GPlugin.PluginInfo({
+ id: "gplugin/gjs-basic-plugin",
+ abi_version: 0x01020304,
+ name: "basic plugin",
+ authors: ['author1'],
+ category: 'test',
+ version: 'version',
+ license_id: 'license',
+ summary: 'summary',
+ website: 'website',
+ description: 'description'
+ });
+};
+
+function gplugin_load(plugin) {
+ return true;
+};
+
+function gplugin_unload(plugin) {
+ return true;
+};
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/tests/plugins/dependent.js Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ */
+
+const GPlugin = imports.gi.GPlugin;
+
+function gplugin_query() {
+ return new GPlugin.PluginInfo({
+ id: "gplugin/gjs-dependent-plugin",
+ dependencies: ["dependency1", "dependency2"],
+ });
+};
+
+function gplugin_load(plugin) {
+ return false;
+};
+
+function gplugin_unload(plugin) {
+ return false;
+};
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/tests/plugins/load-exception.js Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ */
+
+const GPlugin = imports.gi.GPlugin;
+
+function gplugin_query() {
+ return new GPlugin.PluginInfo({
+ id: "gplugin/gjs-load-exception"
+ });
+};
+
+function gplugin_load(plugin) {
+ throw "boom!";
+};
+
+function gplugin_unload(plugin) {
+ return true;
+};
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/tests/plugins/load-failed.js Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ */
+
+const GPlugin = imports.gi.GPlugin;
+
+var gplugin_query = function() {
+ return new GPlugin.PluginInfo({
+ id: "gplugin/gjs-load-failed"
+ });
+};
+
+var gplugin_load = function(plugin) {
+ return false;
+};
+
+var gplugin_unload = function(plugin) {
+ return true;
+};
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/tests/plugins/unload-failed.js Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ */
+
+const GPlugin = imports.gi.GPlugin;
+
+function gplugin_query() {
+ return new GPlugin.PluginInfo({
+ id: "gplugin/gjs-unload-failed"
+ });
+};
+
+function gplugin_load(plugin) {
+ return true;
+};
+
+function gplugin_unload(plugin) {
+ return false;
+};
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gjs/tests/test-gjs-loader.c Tue Sep 29 22:45:21 2015 -0500
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <gplugin.h>
+
+#include <gplugin/gplugin-loader-tests.h>
+
+gint
+main(gint argc, gchar **argv) {
+ g_test_init(&argc, &argv, NULL);
+
+ gplugin_loader_tests_main(GJS_LOADER_DIR, GJS_PLUGIN_DIR, "gjs");
+
+ return g_test_run();
+}
+