Commit 730edb65 authored by Garrett Regier's avatar Garrett Regier

Remove support for gjs-based Javascript plugins

There have been changes to the gjs bindings and as the issue
has only recently been noticed it is assumed that support for
them is not highly desired.

https://bugzilla.gnome.org/show_bug.cgi?id=711356
parent 85960307
......@@ -75,18 +75,11 @@ Makefile.in
/tests/*/vgdump-*
/tests/libpeas/engine
/tests/libpeas/extension-c
/tests/libpeas/extension-gjs
/tests/libpeas/extension-python
/tests/libpeas/extension-python3
/tests/libpeas/extension-seed
/tests/libpeas/extension-set
/tests/libpeas/plugin-info
/tests/libpeas/plugins/extension-js/extension-gjs.gschema.xml
/tests/libpeas/plugins/extension-js/extension-gjs.js
/tests/libpeas/plugins/extension-js/extension-gjs.plugin
/tests/libpeas/plugins/extension-js/extension-seed.gschema.xml
/tests/libpeas/plugins/extension-js/extension-seed.js
/tests/libpeas/plugins/extension-js/extension-seed.plugin
/tests/libpeas/plugins/extension-python/extension-python.gschema.xml
/tests/libpeas/plugins/extension-python/extension-python.plugin
/tests/libpeas/plugins/extension-python/extension-python.py
......
......@@ -267,43 +267,6 @@ fi
AM_CONDITIONAL([ENABLE_SEED],[test "x$found_seed" = "xyes"])
dnl ================================================================
dnl GJS Javascript Engine
dnl ================================================================
GJS_REQUIRED=1.37.1
AC_ARG_ENABLE(gjs,
AS_HELP_STRING([--enable-gjs],[Enable GJS support]),
[enable_gjs=$enableval],
[enable_gjs=auto])
AC_MSG_CHECKING([for GJS JS availability.])
if test "x$enable_gjs" = "xno"; then
found_gjs="no (disabled, use --enable-gjs to enable)"
else
PKG_CHECK_EXISTS([gjs-internals-1.0 >= $GJS_REQUIRED],
[found_gjs=yes],
[found_gjs=no])
fi
if test "$enable_gjs" = "yes" -a "$found_gjs" = "no"; then
AC_MSG_ERROR([You need to have gjs-internals-1.0 >= $GJS_REQUIRED installed to build libpeas])
fi
AC_MSG_RESULT([$found_gjs])
if test "$found_gjs" = "yes"; then
GJS_CFLAGS=`$PKG_CONFIG --cflags gjs-internals-1.0`
GJS_LIBS=`$PKG_CONFIG --libs gjs-internals-1.0`
AC_SUBST(GJS_CFLAGS)
AC_SUBST(GJS_LIBS)
AC_DEFINE(ENABLE_GJS,1,[Define to compile with GJS support])
fi
AM_CONDITIONAL([ENABLE_GJS],[test "x$found_gjs" = "xyes"])
dnl ================================================================
dnl Python
dnl ================================================================
......@@ -474,7 +437,6 @@ docs/reference/version.xml
libpeas/Makefile
libpeas-gtk/Makefile
loaders/Makefile
loaders/gjs/Makefile
loaders/python/Makefile
loaders/python3/Makefile
loaders/seed/Makefile
......@@ -485,7 +447,6 @@ data/libpeas-1.0.pc
data/libpeas-gtk-1.0.pc
peas-demo/Makefile
peas-demo/plugins/Makefile
peas-demo/plugins/gjshello/Makefile
peas-demo/plugins/helloworld/Makefile
peas-demo/plugins/pythonhello/Makefile
peas-demo/plugins/secondtime/Makefile
......@@ -495,8 +456,8 @@ tests/Makefile
tests/libpeas/Makefile
tests/libpeas/plugins/Makefile
tests/libpeas/plugins/extension-c/Makefile
tests/libpeas/plugins/extension-js/Makefile
tests/libpeas/plugins/extension-python/Makefile
tests/libpeas/plugins/extension-seed/Makefile
tests/libpeas/introspection/Makefile
tests/libpeas/testing/Makefile
tests/libpeas-gtk/Makefile
......@@ -531,6 +492,5 @@ Languages support:
Python 2 support : ${found_python2}
Python 3 support : ${found_python3}
Javascript support (Seed) : ${found_seed}
Javascript support (GJS) : ${found_gjs}
Seed Javascript support : ${found_seed}
"
......@@ -37,8 +37,8 @@
* access the related #PeasPluginInfo, and especially the location where all
* the data of your plugin lives.
*
* Non-C extensions will usually not inherit from this class: Python, Seed
* and GJS plugins automatically get a "plugin_info" attribute that serves
* Non-C extensions will usually not inherit from this class: Python and
* Seed plugins automatically get a "plugin_info" attribute that serves
* the same purpose.
**/
......
SUBDIRS =
if ENABLE_GJS
SUBDIRS += gjs
endif
if ENABLE_PYTHON2
SUBDIRS += python
endif
......
# GJS plugin loader
loaderdir = $(libdir)/libpeas-1.0/loaders
INCLUDES = \
-I$(top_srcdir) \
$(PEAS_CFLAGS) \
$(GCOV_CFLAGS) \
$(WARN_CFLAGS) \
$(DISABLE_DEPRECATED) \
$(GJS_CFLAGS)
loader_LTLIBRARIES = libgjsloader.la
libgjsloader_la_SOURCES = \
peas-extension-gjs.c \
peas-extension-gjs.h \
peas-plugin-loader-gjs.c \
peas-plugin-loader-gjs.h
libgjsloader_la_LDFLAGS = $(LOADER_LIBTOOL_FLAGS) $(GCOV_LDFLAGS)
libgjsloader_la_LIBADD = $(PEAS_LIBS) $(GJS_LIBS)
gcov_sources = $(libgjsloader_la_SOURCES)
include $(top_srcdir)/Makefile.gcov
/*
* peas-extension-gjs.c
* This file is part of libpeas
*
* Copyright (C) 2011 - Garrett Regier, Steve Frécinaux
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <gjs/gjs-module.h>
#include <girepository.h>
#include <gi/arg.h>
#include <gi/value.h>
#include <libpeas/peas-introspection.h>
#include <libpeas/peas-extension-subclasses.h>
#include "peas-extension-gjs.h"
G_DEFINE_TYPE (PeasExtensionGjs, peas_extension_gjs, PEAS_TYPE_EXTENSION_WRAPPER);
typedef struct {
GIArgInfo arg_info;
GITypeInfo type_info;
/* Only used by out arguments */
gpointer ptr;
} CachedArg;
static void
peas_extension_gjs_init (PeasExtensionGjs *gexten)
{
}
static gchar *
convert_property_name (const gchar *pname)
{
gint i;
gchar *prop_name;
prop_name = g_strdup (pname);
for (i = 0; prop_name[i] != '\0'; ++i)
{
if (prop_name[i] == '-')
prop_name[i] = '_';
}
return prop_name;
}
static void
peas_extension_gjs_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PeasExtensionGjs *gexten = PEAS_EXTENSION_GJS (object);
gchar *prop_name;
jsval js_value;
prop_name = convert_property_name (g_param_spec_get_name (pspec));
if (!gjs_value_from_g_value (gexten->js_context, &js_value, value))
{
g_warning ("Error: failed to convert GValue to "
"jsval for property '%s'", prop_name);
}
else if (!JS_SetProperty (gexten->js_context, gexten->js_object,
prop_name, &js_value))
{
g_warning ("Error: failed to set property '%s'", prop_name);
}
g_free (prop_name);
}
static void
peas_extension_gjs_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PeasExtensionGjs *gexten = PEAS_EXTENSION_GJS (object);
gchar *prop_name;
jsval js_value;
prop_name = convert_property_name (g_param_spec_get_name (pspec));
if (!JS_GetProperty (gexten->js_context, gexten->js_object,
prop_name, &js_value))
{
g_warning ("Error: failed to get property '%s'", prop_name);
}
else if (!gjs_value_to_g_value (gexten->js_context, js_value, value))
{
g_warning ("Error: failed to convert jsval to "
"GValue for property '%s'", prop_name);
}
g_free (prop_name);
}
static void
peas_extension_gjs_dispose (GObject *object)
{
PeasExtensionGjs *gexten = PEAS_EXTENSION_GJS (object);
if (gexten->js_context != NULL)
{
JS_RemoveObjectRoot (gexten->js_context, &gexten->js_object);
gexten->js_context = NULL;
gexten->js_object = NULL;
}
G_OBJECT_CLASS (peas_extension_gjs_parent_class)->dispose (object);
}
static gboolean
set_out_arg (JSContext *js_context,
GIFunctionInfo *func_info,
gboolean is_return_value,
GIArgInfo *arg_info,
GITypeInfo *type_info,
gpointer ptr,
jsval js_value)
{
gboolean nullable;
GITransfer transfer;
GIArgument argument;
GjsArgumentType arg_type;
if (is_return_value)
{
arg_type = GJS_ARGUMENT_RETURN_VALUE;
nullable = g_callable_info_may_return_null (func_info);
transfer = g_callable_info_get_caller_owns (func_info);
}
else
{
arg_type = GJS_ARGUMENT_ARGUMENT;
nullable = g_arg_info_may_be_null (arg_info);
transfer = g_arg_info_get_ownership_transfer (arg_info);
}
if (!gjs_value_to_g_argument (js_context, js_value, type_info, NULL,
arg_type, transfer, nullable, &argument))
{
if (is_return_value)
{
g_warning ("Error failed to convert return value to GIArgument");
}
else
{
g_warning ("Error failed to convert OUT argument '%s' from "
"jsval to GIArgument", g_base_info_get_name (arg_info));
}
return FALSE;
}
peas_gi_argument_to_pointer (type_info, &argument, ptr);
return TRUE;
}
static gboolean
peas_extension_gjs_call (PeasExtensionWrapper *exten,
GType exten_type,
GICallableInfo *func_info,
const gchar *method_name,
GIArgument *args,
GIArgument *retval)
{
PeasExtensionGjs *gexten = PEAS_EXTENSION_GJS (exten);
gboolean success = FALSE;
jsval js_method, js_retval;
jsval *js_args;
CachedArg *arg_cache;
gint i, n_args, nth_out_arg;
gint n_in_args = 0;
gint n_out_args = 0;
gint cached_args = 0;
/* Fetch the JS method we want to call */
if (!JS_GetProperty (gexten->js_context, gexten->js_object,
method_name, &js_method) ||
JSVAL_IS_VOID (js_method))
{
g_warning ("Method '%s.%s' was not found",
g_type_name (exten_type), method_name);
return FALSE;
}
if (JSVAL_IS_NULL (js_method) || !JSVAL_IS_OBJECT (js_method) ||
!JS_ObjectIsFunction (gexten->js_context, JSVAL_TO_OBJECT (js_method)))
{
g_warning ("Method '%s.%s' in not a function",
g_type_name (exten_type), method_name);
return FALSE;
}
n_args = g_callable_info_get_n_args (func_info);
if (n_args < 0)
{
g_warn_if_fail (n_args >= 0);
return FALSE;
}
js_args = g_newa (jsval, n_args);
arg_cache = g_newa (CachedArg, n_args + 1);
/* Return value is an out arg */
g_callable_info_load_return_type (func_info, &arg_cache[0].type_info);
if (g_type_info_get_tag (&arg_cache[0].type_info) != GI_TYPE_TAG_VOID)
{
++n_out_args;
arg_cache[cached_args++].ptr = &retval->v_pointer;
}
/* Handle the arguments */
for (i = 0; i < n_args; ++i, ++cached_args)
{
GIDirection direction;
g_callable_info_load_arg (func_info, i, &arg_cache[cached_args].arg_info);
direction = g_arg_info_get_direction (&arg_cache[cached_args].arg_info);
g_arg_info_load_type (&arg_cache[cached_args].arg_info,
&arg_cache[cached_args].type_info);
if (direction == GI_DIRECTION_IN &&
!gjs_value_from_g_argument (gexten->js_context, &js_args[n_in_args++],
&arg_cache[cached_args].type_info,
&args[i], TRUE))
{
g_warning ("Error failed to convert argument '%s'",
g_base_info_get_name (&arg_cache[cached_args].arg_info));
return FALSE;
}
if (direction == GI_DIRECTION_INOUT)
{
GIArgument arg;
peas_gi_pointer_to_argument (&arg_cache[cached_args].type_info,
args[i].v_pointer, &arg);
if (!gjs_value_from_g_argument (gexten->js_context, &js_args[n_in_args++],
&arg_cache[cached_args].type_info, &arg, TRUE))
{
g_warning ("Error failed to convert argument '%s'",
g_base_info_get_name (&arg_cache[cached_args].arg_info));
return FALSE;
}
}
if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
{
++n_out_args;
arg_cache[cached_args].ptr = args[i].v_pointer;
}
}
success = JS_CallFunctionValue (gexten->js_context, gexten->js_object,
js_method, n_in_args, js_args, &js_retval);
if (!success)
{
if (!gjs_log_exception (gexten->js_context))
{
g_warning ("Error while calling '%s.%s'",
g_type_name (exten_type), method_name);
}
return FALSE;
}
/* First we need to release in argument */
for (i = 0; i < cached_args; ++i)
{
GIDirection direction;
/* First cached argument may be the return value */
if (i == 0 && cached_args > n_args)
continue;
direction = g_arg_info_get_direction (&arg_cache[i].arg_info);
if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
{
GITransfer transfer;
transfer = g_arg_info_get_ownership_transfer (&arg_cache[i].arg_info);
if (!gjs_g_argument_release_in_arg (gexten->js_context, transfer,
&arg_cache[i].type_info,
&args[i]))
{
g_warning ("Error failed to release IN argument '%s'",
g_base_info_get_name (&arg_cache[i].arg_info));
}
}
}
/* Check that we have a valid return value */
if (n_out_args > 1)
{
if (!JSVAL_IS_OBJECT (js_retval) ||
!JS_IsArrayObject (gexten->js_context, JSVAL_TO_OBJECT (js_retval)))
{
g_warning ("Error return value is not an array");
return FALSE;
}
}
/* Set out arguments */
for (i = 0, nth_out_arg = 0; i < cached_args && success; ++i)
{
gboolean is_return_value;
is_return_value = i == 0 && cached_args > n_args;
/* Return value does not have a GIArgInfo and is always out */
if (!is_return_value)
{
GIDirection direction;
direction = g_arg_info_get_direction (&arg_cache[i].arg_info);
if (direction == GI_DIRECTION_IN)
continue;
}
if (n_out_args == 1)
{
success = set_out_arg (gexten->js_context, func_info, is_return_value,
&arg_cache[i].arg_info, &arg_cache[i].type_info,
arg_cache[i].ptr, js_retval);
break;
}
else if (n_out_args > 1)
{
jsval js_value;
if (!JS_GetElement (gexten->js_context, JSVAL_TO_OBJECT (js_retval),
nth_out_arg++, &js_value) ||
JSVAL_IS_VOID (js_value))
{
g_warning ("Error failed to get out argument %i", nth_out_arg);
return FALSE;
}
else
{
success = set_out_arg (gexten->js_context, func_info,
is_return_value, &arg_cache[i].arg_info,
&arg_cache[i].type_info, arg_cache[i].ptr,
js_value);
}
}
}
return success;
}
static void
peas_extension_gjs_class_init (PeasExtensionGjsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PeasExtensionWrapperClass *extension_class = PEAS_EXTENSION_WRAPPER_CLASS (klass);
object_class->set_property = peas_extension_gjs_set_property;
object_class->get_property = peas_extension_gjs_get_property;
object_class->dispose = peas_extension_gjs_dispose;
extension_class->call = peas_extension_gjs_call;
}
GObject *
peas_extension_gjs_new (GType exten_type,
GType *interfaces,
JSContext *js_context,
JSObject *js_object)
{
PeasExtensionGjs *gexten;
GType real_type;
g_return_val_if_fail (js_context != NULL, NULL);
g_return_val_if_fail (js_object != NULL, NULL);
real_type = peas_extension_register_subclass (PEAS_TYPE_EXTENSION_GJS,
interfaces);
/* Already Warned */
if (real_type == G_TYPE_INVALID)
{
g_free (interfaces);
return NULL;
}
gexten = PEAS_EXTENSION_GJS (g_object_new (real_type, NULL));
gexten->js_context = js_context;
gexten->js_object = js_object;
PEAS_EXTENSION_WRAPPER (gexten)->exten_type = exten_type;
PEAS_EXTENSION_WRAPPER (gexten)->interfaces = interfaces;
JS_AddObjectRoot (gexten->js_context, &gexten->js_object);
return G_OBJECT (gexten);
}
/*
* peas-extension-gjs.h
* This file is part of libpeas
*
* Copyright (C) 2011 - Garrett Regier, Steve Frécinaux
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PEAS_EXTENSION_GJS_H__
#define __PEAS_EXTENSION_GJS_H__
#include <libpeas/peas-extension-wrapper.h>
#include <gjs/gjs-module.h>
G_BEGIN_DECLS
#define PEAS_TYPE_EXTENSION_GJS (peas_extension_gjs_get_type ())
#define PEAS_EXTENSION_GJS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PEAS_TYPE_EXTENSION_GJS, PeasExtensionGjs))
#define PEAS_EXTENSION_GJS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PEAS_TYPE_EXTENSION_GJS, PeasExtensionGjsClass))
#define PEAS_IS_EXTENSION_GJS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PEAS_TYPE_EXTENSION_GJS))
#define PEAS_IS_EXTENSION_GJS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PEAS_TYPE_EXTENSION_GJS))
#define PEAS_EXTENSION_GJS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PEAS_TYPE_EXTENSION_GJS, PeasExtensionGjsClass))
typedef struct _PeasExtensionGjs PeasExtensionGjs;
typedef struct _PeasExtensionGjsClass PeasExtensionGjsClass;
struct _PeasExtensionGjs {
PeasExtensionWrapper parent;
JSContext *js_context;
JSObject *js_object;
};
struct _PeasExtensionGjsClass {
PeasExtensionWrapperClass parent_class;
};
GType peas_extension_gjs_get_type (void) G_GNUC_CONST;
GObject *peas_extension_gjs_new (GType exten_type,
GType *interfaces,
JSContext *js_context,
JSObject *js_object);
G_END_DECLS
#endif /* __PEAS_EXTENSION_GJS_H__ */
/*
* peas-plugin-loader-gjs.c
* This file is part of libpeas
*
* Copyright (C) 2011 - Garrett Regier, Steve Frécinaux
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gjs/gjs-module.h>
#include <gi/object.h>
#include <gi/repo.h>
#include <gi/value.h>
#include <libpeas/peas-introspection.h>
#include "peas-plugin-loader-gjs.h"
#include "peas-extension-gjs.h"
typedef struct {
JSObject *extensions;
GjsContext *context;
} GjsInfo;
G_DEFINE_TYPE (PeasPluginLoaderGjs, peas_plugin_loader_gjs, PEAS_TYPE_PLUGIN_LOADER);
static gchar *
get_script_filename_for_plugin_info (PeasPluginInfo *info)
{
gchar *basename;
gchar *filename;
basename = g_strconcat (peas_plugin_info_get_module_name (info), ".js", NULL);
filename = g_build_filename (peas_plugin_info_get_module_dir (info), basename, NULL);
g_free (basename);
return filename;
}
static gboolean
peas_plugin_loader_gjs_load (PeasPluginLoader *loader,
PeasPluginInfo *info)
{
PeasPluginLoaderGjs *gloader = PEAS_PLUGIN_LOADER_GJS (loader);
gchar **search_paths;
const gchar *version;
GjsContext *context;
gchar *filename;
GjsInfo *ginfo;
GError *error = NULL;
JSContext *js_context;
JSObject *global;
jsval extensions;
filename = get_script_filename_for_plugin_info (info);
g_debug ("GJS script filename is '%s'", filename);
search_paths = g_new (gchar *, 2);
search_paths[0] = g_strdup (peas_plugin_info_get_module_dir (info));
search_paths[1] = NULL;
version = gjs_context_scan_file_for_js_version (filename);
context = g_object_new (GJS_TYPE_CONTEXT,
"search-path", search_paths,
"js-version", version,
NULL);
gjs_context_eval_file (context, filename, NULL, &error);
g_strfreev (search_paths);
g_free (filename);
if (error != NULL)
{
g_warning ("Error: %s", error->message);
g_error_free (error);
g_object_unref (context);
return FALSE;
}
js_context = gjs_context_get_native_context (context);
global = JS_GetGlobalObject (js_context);
if (!JS_GetProperty (js_context, global, "extensions", &extensions))
{
g_warning ("Error: could not find extensions");
return FALSE;