]> spindle.queued.net Git - midori/commitdiff
Make javascript gobject bindings independant.
authorChristian Dywan <christian@twotoasts.de>
Mon, 5 May 2008 22:51:04 +0000 (00:51 +0200)
committerChristian Dywan <christian@twotoasts.de>
Mon, 5 May 2008 22:51:04 +0000 (00:51 +0200)
Moving the bindings into a single file makes them independant
of addons and midori, requiring only JavaScriptCore and GObject.

This allows for standalone scripts to run independant from
Midori itself. Also extensions will run independant from a
browser instance.
This change removes the 'midori' object.

src/Makefile.am
src/gjs.c [new file with mode: 0644]
src/gjs.h [new file with mode: 0644]
src/main.c
src/midori-addons.c

index 82208d265fba8750ffa43010078c6297e9388dfd..dee2ba7e8bbda0794ca647d17d87c884b44c08c0 100644 (file)
@@ -27,5 +27,6 @@ midori_SOURCES = \
     midori-websettings.c midori-websettings.h \
     midori-preferences.c midori-preferences.h \
     webSearch.c webSearch.h \
+    gjs.c       gjs.h       \
     sokoke.c    sokoke.h    \
     search.c    search.h
diff --git a/src/gjs.c b/src/gjs.c
new file mode 100644 (file)
index 0000000..f7e2320
--- /dev/null
+++ b/src/gjs.c
@@ -0,0 +1,399 @@
+/*
+ Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
+
+ 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.1 of the License, or (at your option) any later version.
+
+ See the file COPYING for the full license text.
+*/
+
+#include "gjs.h"
+
+#include <glib/gi18n.h>
+
+#define G_OBJECT_NAME(object) G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object))
+
+// FIXME: Return a GValue
+JSValueRef
+gjs_script_eval (JSContextRef js_context,
+                 const gchar* script,
+                 gchar**      exception)
+{
+    JSStringRef js_script = JSStringCreateWithUTF8CString (script);
+    JSValueRef js_exception = NULL;
+    JSValueRef js_value = JSEvaluateScript (js_context, js_script,
+        JSContextGetGlobalObject (js_context), NULL, 0, &js_exception);
+    if (!js_value && exception)
+    {
+        JSStringRef js_message = JSValueToStringCopy (js_context,
+                                                      js_exception, NULL);
+        *exception = gjs_string_utf8 (js_message);
+        JSStringRelease (js_message);
+        js_value = JSValueMakeNull (js_context);
+    }
+    JSStringRelease (js_script);
+    return js_value;
+}
+
+gboolean
+gjs_script_check_syntax (JSContextRef js_context,
+                         const gchar* script,
+                         gchar**      exception)
+{
+    JSStringRef js_script = JSStringCreateWithUTF8CString (script);
+    JSValueRef js_exception = NULL;
+    bool result = JSCheckScriptSyntax (js_context, js_script, NULL,
+                                       0, &js_exception);
+    if (!result && exception)
+    {
+        JSStringRef js_message = JSValueToStringCopy (js_context,
+                                                      js_exception, NULL);
+        *exception = gjs_string_utf8 (js_message);
+        JSStringRelease (js_message);
+    }
+    JSStringRelease (js_script);
+    return result ? TRUE : FALSE;
+}
+
+gboolean
+gjs_script_from_file (JSContextRef js_context,
+                      const gchar* filename,
+                      gchar**      exception)
+{
+    gboolean result = FALSE;
+    gchar* script;
+    GError* error = NULL;
+    if (g_file_get_contents (filename, &script, NULL, &error))
+    {
+        if (gjs_script_eval (js_context, script, exception))
+            result = TRUE;
+        g_free (script);
+    }
+    else
+    {
+        *exception = g_strdup (error->message);
+        g_error_free (error);
+    }
+    return result;
+}
+
+gchar*
+gjs_string_utf8 (JSStringRef js_string)
+{
+    size_t size_utf8 = JSStringGetMaximumUTF8CStringSize (js_string);
+    gchar* string_utf8 = g_new (gchar, size_utf8);
+    JSStringGetUTF8CString (js_string, string_utf8, size_utf8);
+    return string_utf8;
+}
+
+static void
+_js_class_get_property_names_cb (JSContextRef                 js_context,
+                                 JSObjectRef                  js_object,
+                                 JSPropertyNameAccumulatorRef js_properties)
+{
+    GObject* object = JSObjectGetPrivate (js_object);
+    if (object)
+    {
+        guint n_properties;
+        GParamSpec** pspecs = g_object_class_list_properties (
+            G_OBJECT_GET_CLASS (object), &n_properties);
+        gint i;
+        for (i = 0; i < n_properties; i++)
+        {
+            const gchar* property = g_param_spec_get_name (pspecs[i]);
+            JSStringRef js_property = JSStringCreateWithUTF8CString (property);
+            JSPropertyNameAccumulatorAddName (js_properties, js_property);
+            JSStringRelease (js_property);
+        }
+    }
+}
+
+static bool
+_js_class_has_property_cb (JSContextRef js_context,
+                           JSObjectRef  js_object,
+                           JSStringRef  js_property)
+{
+    bool result = false;
+    gchar* property = gjs_string_utf8 (js_property);
+    GObject* object = JSObjectGetPrivate (js_object);
+    if (object)
+    {
+        if (g_object_class_find_property (G_OBJECT_GET_CLASS (object),
+                                          property))
+            result = true;
+    }
+    else if (js_object == JSContextGetGlobalObject (js_context))
+    {
+        GType type = g_type_from_name (property);
+        result = type ? type : false;
+    }
+    g_free (property);
+    return result;
+}
+
+static void
+_js_object_set_property (JSContextRef js_context,
+                         JSObjectRef  js_object,
+                         const gchar* name,
+                         JSValueRef   js_value)
+{
+    JSStringRef js_name = JSStringCreateWithUTF8CString (name);
+    JSObjectSetProperty(js_context, js_object, js_name, js_value,
+                        kJSPropertyAttributeNone, NULL);
+    JSStringRelease (js_name);
+}
+
+static JSObjectRef
+_js_object_call_as_constructor_cb (JSContextRef     js_context,
+                                   JSObjectRef      js_object,
+                                   size_t           n_arguments,
+                                   const JSValueRef js_arguments[],
+                                   JSValueRef*      js_exception)
+{
+    gchar* type_name = JSObjectGetPrivate (js_object);
+    if (type_name)
+    {
+        GType type = g_type_from_name (type_name);
+        if (type)
+            return gjs_object_new (js_context, g_object_new (type, NULL));
+    }
+    return JSValueMakeNull (js_context);
+}
+
+static JSValueRef
+_js_class_get_property_cb (JSContextRef js_context,
+                           JSObjectRef  js_object,
+                           JSStringRef  js_property,
+                           JSValueRef*  js_exception)
+{
+    if (js_object == JSContextGetGlobalObject (js_context))
+    {
+        gchar* property = gjs_string_utf8 (js_property);
+        GType type = g_type_from_name (property);
+        if (type)
+        {
+            JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
+            js_class_def.className = g_strdup (property);
+            js_class_def.callAsConstructor = _js_object_call_as_constructor_cb;
+            JSClassRef js_class = JSClassCreate (&js_class_def);
+            return JSObjectMake (js_context, js_class, property);
+        }
+        g_free (property);
+        return JSValueMakeNull (js_context);
+    }
+    GObject* object = JSObjectGetPrivate (js_object);
+    JSValueRef js_result = NULL;
+    if (object)
+    {
+        gchar* property = gjs_string_utf8 (js_property);
+        GParamSpec* pspec = g_object_class_find_property (
+            G_OBJECT_GET_CLASS (object), property);
+        if (!pspec)
+        {
+            gchar* message = g_strdup_printf (_("%s has no property '%s'"),
+                G_OBJECT_NAME (object), property);
+            JSStringRef js_message = JSStringCreateWithUTF8CString (message);
+            *js_exception = JSValueMakeString (js_context, js_message);
+            JSStringRelease (js_message);
+            g_free (message);
+            g_free (property);
+            return JSValueMakeNull (js_context);
+        }
+        if (!(pspec->flags & G_PARAM_READABLE))
+        {
+            g_free (property);
+            return JSValueMakeUndefined (js_context);
+        }
+        GType type = G_PARAM_SPEC_TYPE (pspec);
+        if (type == G_TYPE_PARAM_STRING)
+        {
+            gchar* value;
+            g_object_get (object, property, &value, NULL);
+            if (value)
+            {
+                JSStringRef js_string = JSStringCreateWithUTF8CString (value);
+                js_result = JSValueMakeString (js_context, js_string);
+            }
+        }
+        else if (type == G_TYPE_PARAM_INT
+            || type == G_TYPE_PARAM_UINT)
+        {
+            gint value;
+            g_object_get (object, property, &value, NULL);
+            js_result = JSValueMakeNumber (js_context, value);
+        }
+        else if (type == G_TYPE_PARAM_BOOLEAN)
+        {
+            gboolean value;
+            g_object_get (object, property, &value, NULL);
+            js_result = JSValueMakeBoolean (js_context, value ? true : false);
+        }
+        else if (type == G_TYPE_PARAM_OBJECT)
+        {
+            GObject* value;
+            g_object_get (object, property, &value, NULL);
+            if (value)
+                js_result = gjs_object_new (js_context, value);
+        }
+        else if (type == G_TYPE_PARAM_ENUM)
+        {
+            gint value;
+            g_object_get (object, property, &value, NULL);
+            js_result = JSValueMakeNumber (js_context, value);
+        }
+        else
+            js_result = JSValueMakeUndefined (js_context);
+        g_free (property);
+    }
+    return js_result ? js_result : JSValueMakeNull (js_context);
+}
+
+static bool
+_js_class_set_property_cb (JSContextRef js_context,
+                           JSObjectRef  js_object,
+                           JSStringRef  js_property,
+                           JSValueRef   js_value,
+                           JSValueRef*  js_exception)
+{
+    GObject* object = JSObjectGetPrivate (js_object);
+    bool result = false;
+    if (object)
+    {
+        gchar* property = gjs_string_utf8 (js_property);
+        GParamSpec* pspec = g_object_class_find_property (
+            G_OBJECT_GET_CLASS (object), property);
+        if (!pspec)
+        {
+            gchar* message = g_strdup_printf (_("%s has no property '%s'"),
+                G_OBJECT_NAME (object), property);
+            JSStringRef js_message = JSStringCreateWithUTF8CString (message);
+            *js_exception = JSValueMakeString (js_context, js_message);
+            JSStringRelease (js_message);
+            g_free (message);
+            g_free (property);
+            return false;
+        }
+        if (!(pspec->flags & G_PARAM_WRITABLE))
+        {
+            g_free (property);
+            return false;
+        }
+        GType type = G_PARAM_SPEC_TYPE (pspec);
+        if (type == G_TYPE_PARAM_STRING)
+        {
+            JSStringRef js_string_value = JSValueToStringCopy (js_context,
+                js_value, js_exception);
+            if (js_string_value)
+            {
+                gchar* string_value = gjs_string_utf8 (js_string_value);
+                g_object_set (object, property, string_value, NULL);
+                g_free (string_value);
+            }
+        }
+        else if (type == G_TYPE_PARAM_INT
+            || type == G_TYPE_PARAM_UINT)
+        {
+            int value = JSValueToNumber (js_context, js_value,
+                                          js_exception);
+            g_object_set (object, property, value, NULL);
+        }
+        else if (type == G_TYPE_PARAM_BOOLEAN)
+        {
+            bool value = JSValueToBoolean (js_context, js_value);
+            g_object_set (object, property, value ? TRUE : FALSE, NULL);
+        }
+        else if (type == G_TYPE_PARAM_OBJECT)
+        {
+            JSObjectRef js_object_value = JSValueToObject (
+                js_context, js_value, NULL);
+            GObject* object_value = JSObjectGetPrivate (js_object_value);
+            if (object_value)
+                g_object_set (object, property, object_value, NULL);
+            else
+            {
+                gchar* message = g_strdup_printf (_("%s cannot be assigned to %s.%s"),
+                "[object]", G_OBJECT_NAME (object), property);
+                JSStringRef js_message = JSStringCreateWithUTF8CString (message);
+                *js_exception = JSValueMakeString (js_context, js_message);
+                JSStringRelease (js_message);
+                g_free (message);
+            }
+        }
+        else
+        {
+            gchar* message = g_strdup_printf (_("%s.%s cannot be accessed"),
+                G_OBJECT_NAME (object), property);
+            JSStringRef js_message = JSStringCreateWithUTF8CString (message);
+            *js_exception = JSValueMakeString (js_context, js_message);
+            JSStringRelease (js_message);
+            g_free (message);
+        }
+        g_free (property);
+    }
+    return result;
+}
+
+static JSValueRef
+_js_object_call_as_function_cb (JSContextRef     js_context,
+                                JSObjectRef      js_function,
+                                JSObjectRef      js_this,
+                                size_t           n_arguments,
+                                const JSValueRef js_arguments[],
+                                JSValueRef*      js_exception)
+{
+    GObject* object = JSObjectGetPrivate (js_this);
+    if (object)
+    {
+        if (!n_arguments)
+        {
+            gtk_widget_show (GTK_WIDGET (object));
+        }
+        else if (n_arguments == 1)
+        {
+            JSObjectRef js_arg1 = JSValueToObject (
+                js_context, js_arguments[0], NULL);
+            GObject* arg1 = JSObjectGetPrivate (js_arg1);
+            if (arg1)
+                gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (arg1));
+        }
+    }
+
+    return JSValueMakeUndefined (js_context);
+}
+
+static void
+_js_object_add_function (JSContextRef js_context,
+                         JSObjectRef  js_object,
+                         const gchar* func)
+{
+    JSStringRef js_func = JSStringCreateWithUTF8CString (func);
+    JSObjectRef js_function = JSObjectMakeFunctionWithCallback (
+        js_context, js_func, _js_object_call_as_function_cb);
+    JSStringRelease (js_func);
+    _js_object_set_property (js_context, js_object, func, js_function);
+}
+
+JSObjectRef
+gjs_object_new (JSContextRef js_context,
+                gpointer     instance)
+{
+    JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
+    js_class_def.className = g_strdup (G_OBJECT_NAME (instance));
+    js_class_def.getPropertyNames = _js_class_get_property_names_cb;
+    js_class_def.hasProperty = _js_class_has_property_cb;
+    js_class_def.getProperty = _js_class_get_property_cb;
+    js_class_def.setProperty = _js_class_set_property_cb;
+    JSClassRef js_class = JSClassCreate (&js_class_def);
+    JSObjectRef js_object = JSObjectMake (js_context, js_class, instance);
+    if (instance && G_IS_OBJECT (instance))
+    {
+        // TODO: Add functions dynamically
+        /*if (GTK_IS_WIDGET (instance))
+        {
+            _js_object_add_function (js_context, js_object, "show");
+        }*/
+    }
+    return js_object;
+}
diff --git a/src/gjs.h b/src/gjs.h
new file mode 100644 (file)
index 0000000..75d846c
--- /dev/null
+++ b/src/gjs.h
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
+
+ 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.1 of the License, or (at your option) any later version.
+
+ See the file COPYING for the full license text.
+*/
+
+#ifndef __GJS_H__
+#define __GJS_H__
+
+#include <JavaScriptCore/JavaScript.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+JSValueRef
+gjs_script_eval (JSContextRef js_context,
+                 const gchar* script,
+                 gchar**      exception);
+
+gboolean
+gjs_script_check_syntax (JSContextRef js_context,
+                         const gchar* script,
+                         gchar**      exception);
+
+gboolean
+gjs_script_from_file (JSContextRef js_context,
+                      const gchar* filename,
+                      gchar**      exception);
+
+gchar*
+gjs_string_utf8 (JSStringRef js_string);
+
+JSObjectRef
+gjs_object_new (JSContextRef context,
+                gpointer     instance);
+
+gchar*
+gjs_string_utf8 (JSStringRef       js_string);
+
+G_END_DECLS
+
+#endif /* __GJS_H__ */
index 884e30abc2afb04e77504ce62bcb0241a849ada4..f319c3d1c3f667202c89bb5ad4c30d275daca1a7 100644 (file)
@@ -18,6 +18,7 @@
 #include "midori-trash.h"
 #include "midori-browser.h"
 #include <katze/katze.h>
+#include "gjs.h"
 
 #include <string.h>
 #include <gtk/gtk.h>
@@ -311,6 +312,19 @@ main (int argc, char** argv)
         return 0;
     }
 
+    // Standalone gjs support
+    if (argc > 1 && argv[1] && g_str_has_suffix (argv[1], ".js"))
+    {
+        JSGlobalContextRef js_context = JSGlobalContextCreate (NULL);
+        gchar* exception = NULL;
+        gjs_script_from_file (js_context, argv[1], &exception);
+        JSGlobalContextRelease (js_context);
+        if (!exception)
+            return ;
+        printf ("%s - Exception: %s\n", argv[1], exception);
+        return 1;
+    }
+
     // Load configuration files
     GString* error_messages = g_string_new (NULL);
     gchar* config_path = g_build_filename (g_get_user_config_dir (),
@@ -474,8 +488,32 @@ main (int argc, char** argv)
         midori_browser_activate_action (browser, "Location");
     katze_xbel_item_unref (_session);
 
+    // Load extensions
+    JSGlobalContextRef js_context = JSGlobalContextCreate (NULL);
+    // FIXME: We want to honor system installed addons as well
+    gchar* addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME,
+                                          "extensions", NULL);
+    GDir* addon_dir = g_dir_open (addon_path, 0, NULL);
+    if (addon_dir)
+    {
+        const gchar* filename;
+        while ((filename = g_dir_read_name (addon_dir)))
+        {
+            gchar* fullname = g_build_filename (addon_path, filename, NULL);
+            gchar* exception = NULL;
+            gjs_script_from_file (js_context, fullname, &exception);
+            if (exception)
+            // FIXME: Do we want to print this somewhere else?
+            // FIXME Convert the filename to UTF8
+                printf ("%s - Exception: %s\n", filename, exception);
+            g_free (fullname);
+        }
+        g_dir_close (addon_dir);
+    }
+
     gtk_main ();
 
+    JSGlobalContextRelease (js_context);
     g_object_unref (accel_group);
 
     // Save configuration files
index 552f7972f2d608b29a72f9ed3c7da8d5cac2104f..b83f7c7cc6ffaddabecc1f1b1fd8259493b06817 100644 (file)
@@ -138,404 +138,6 @@ midori_addons_treeview_row_activated_cb (GtkTreeView*       treeview,
     }*/
 }
 
-static gchar*
-_js_string_utf8 (JSStringRef js_string)
-{
-    size_t size_utf8 = JSStringGetMaximumUTF8CStringSize (js_string);
-    gchar* string_utf8 = (gchar*)g_malloc (size_utf8);
-    JSStringGetUTF8CString (js_string, string_utf8, size_utf8);
-    return string_utf8;
-}
-
-static void
-_js_class_get_property_names_cb (JSContextRef                 js_context,
-                                 JSObjectRef                  js_object,
-                                 JSPropertyNameAccumulatorRef js_properties)
-{
-    GObject* object = JSObjectGetPrivate (js_object);
-    if (object)
-    {
-        guint n_properties;
-        GParamSpec** pspecs = g_object_class_list_properties (
-            G_OBJECT_GET_CLASS (object), &n_properties);
-        gint i;
-        for (i = 0; i < n_properties; i++)
-        {
-            const gchar* property = g_param_spec_get_name (pspecs[i]);
-            JSStringRef js_property = JSStringCreateWithUTF8CString (property);
-            JSPropertyNameAccumulatorAddName (js_properties, js_property);
-            JSStringRelease (js_property);
-        }
-    }
-}
-
-static bool
-_js_class_has_property_cb (JSContextRef js_context,
-                           JSObjectRef  js_object,
-                           JSStringRef  js_property)
-{
-    bool result = false;
-    gchar* property = _js_string_utf8 (js_property);
-    GObject* object = JSObjectGetPrivate (js_object);
-    if (object)
-    {
-        if (g_object_class_find_property (G_OBJECT_GET_CLASS (object),
-                                          property))
-            result = true;
-    }
-    else if (js_object == JSContextGetGlobalObject (js_context))
-    {
-        gchar* property = _js_string_utf8 (js_property);
-        GType type = g_type_from_name (property);
-        result = type ? type : false;
-    }
-    g_free (property);
-    return result;
-}
-
-static JSObjectRef
-_js_object_new (JSContextRef js_context,
-                gpointer     object);
-
-static void
-_js_object_set_property (JSContextRef js_context,
-                         JSObjectRef  js_object,
-                         const gchar* name,
-                         JSValueRef   js_value)
-{
-    JSStringRef js_name = JSStringCreateWithUTF8CString (name);
-    JSObjectSetProperty(js_context, js_object, js_name, js_value,
-                        kJSPropertyAttributeNone, NULL);
-    JSStringRelease (js_name);
-}
-
-static JSObjectRef
-_js_object_call_as_constructor_cb (JSContextRef     js_context,
-                                   JSObjectRef      js_object,
-                                   size_t           n_arguments,
-                                   const JSValueRef js_arguments[],
-                                   JSValueRef*      js_exception)
-{
-    gchar* type_name = JSObjectGetPrivate (js_object);
-    if (type_name)
-    {
-        GType type = g_type_from_name (type_name);
-        if (type)
-        {
-            GObject* object = g_object_new (type, NULL);
-            JSObjectRef js_object = _js_object_new (js_context, object);
-            return js_object;
-        }
-    }
-    return JSValueMakeNull (js_context);
-}
-
-static JSValueRef
-_js_class_get_property_cb (JSContextRef js_context,
-                           JSObjectRef  js_object,
-                           JSStringRef  js_property,
-                           JSValueRef*  js_exception)
-{
-    if (js_object == JSContextGetGlobalObject (js_context))
-    {
-        gchar* property = _js_string_utf8 (js_property);
-        GType type = g_type_from_name (property);
-        if (type)
-        {
-            JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
-            js_class_def.className = g_strdup (property);
-            js_class_def.callAsConstructor = _js_object_call_as_constructor_cb;
-            JSClassRef js_class = JSClassCreate (&js_class_def);
-            return JSObjectMake (js_context, js_class, property);
-        }
-        g_free (property);
-        return JSValueMakeNull (js_context);
-    }
-    GObject* object = JSObjectGetPrivate (js_object);
-    JSValueRef js_result = NULL;
-    if (object)
-    {
-        gchar* property = _js_string_utf8 (js_property);
-        GParamSpec* pspec = g_object_class_find_property (
-            G_OBJECT_GET_CLASS (object), property);
-        if (!pspec)
-        {
-            gchar* message = g_strdup_printf (_("%s has no property '%s'"),
-                KATZE_OBJECT_NAME (object), property);
-            JSStringRef js_message = JSStringCreateWithUTF8CString (message);
-            *js_exception = JSValueMakeString (js_context, js_message);
-            JSStringRelease (js_message);
-            g_free (message);
-            g_free (property);
-            return JSValueMakeNull (js_context);
-        }
-        if (!(pspec->flags & G_PARAM_READABLE))
-        {
-            g_free (property);
-            return JSValueMakeUndefined (js_context);
-        }
-        GType type = G_PARAM_SPEC_TYPE (pspec);
-        if (type == G_TYPE_PARAM_STRING)
-        {
-            gchar* value;
-            g_object_get (object, property, &value, NULL);
-            if (value)
-            {
-                JSStringRef js_string = JSStringCreateWithUTF8CString (value);
-                js_result = JSValueMakeString (js_context, js_string);
-            }
-        }
-        else if (type == G_TYPE_PARAM_INT
-            || type == G_TYPE_PARAM_UINT)
-        {
-            gint value;
-            g_object_get (object, property, &value, NULL);
-            js_result = JSValueMakeNumber (js_context, value);
-        }
-        else if (type == G_TYPE_PARAM_BOOLEAN)
-        {
-            gboolean value;
-            g_object_get (object, property, &value, NULL);
-            js_result = JSValueMakeBoolean (js_context, value ? true : false);
-        }
-        else if (type == G_TYPE_PARAM_OBJECT)
-        {
-            GObject* value;
-            g_object_get (object, property, &value, NULL);
-            if (value)
-                js_result = _js_object_new (js_context, value);
-        }
-        else if (type == G_TYPE_PARAM_ENUM)
-        {
-            gint value;
-            g_object_get (object, property, &value, NULL);
-            js_result = JSValueMakeNumber (js_context, value);
-        }
-        else
-            js_result = JSValueMakeUndefined (js_context);
-        g_free (property);
-    }
-    return js_result ? js_result : JSValueMakeNull (js_context);
-}
-
-static bool
-_js_class_set_property_cb (JSContextRef js_context,
-                           JSObjectRef  js_object,
-                           JSStringRef  js_property,
-                           JSValueRef   js_value,
-                           JSValueRef*  js_exception)
-{
-    GObject* object = JSObjectGetPrivate (js_object);
-    bool result = false;
-    if (object)
-    {
-        gchar* property = _js_string_utf8 (js_property);
-        GParamSpec* pspec = g_object_class_find_property (
-            G_OBJECT_GET_CLASS (object), property);
-        if (!pspec)
-        {
-            gchar* message = g_strdup_printf (_("%s has no property '%s'"),
-                KATZE_OBJECT_NAME (object), property);
-            JSStringRef js_message = JSStringCreateWithUTF8CString (message);
-            *js_exception = JSValueMakeString (js_context, js_message);
-            JSStringRelease (js_message);
-            g_free (message);
-            g_free (property);
-            return false;
-        }
-        if (!(pspec->flags & G_PARAM_WRITABLE))
-        {
-            g_free (property);
-            return false;
-        }
-        GType type = G_PARAM_SPEC_TYPE (pspec);
-        if (type == G_TYPE_PARAM_STRING)
-        {
-            JSStringRef js_string_value = JSValueToStringCopy (js_context,
-                js_value, js_exception);
-            if (js_string_value)
-            {
-                gchar* string_value = _js_string_utf8 (js_string_value);
-                g_object_set (object, property, string_value, NULL);
-                g_free (string_value);
-            }
-        }
-        else if (type == G_TYPE_PARAM_INT
-            || type == G_TYPE_PARAM_UINT)
-        {
-            int value = JSValueToNumber (js_context, js_value,
-                                          js_exception);
-            g_object_set (object, property, value, NULL);
-        }
-        else if (type == G_TYPE_PARAM_BOOLEAN)
-        {
-            bool value = JSValueToBoolean (js_context, js_value);
-            g_object_set (object, property, value ? TRUE : FALSE, NULL);
-        }
-        else if (type == G_TYPE_PARAM_OBJECT)
-        {
-            JSObjectRef js_object_value = JSValueToObject (
-                js_context, js_value, NULL);
-            GObject* object_value = JSObjectGetPrivate (js_object_value);
-            if (object_value)
-                g_object_set (object, property, object_value, NULL);
-            else
-            {
-                gchar* message = g_strdup_printf (_("%s cannot be assigned to %s.%s"),
-                "[object]", KATZE_OBJECT_NAME (object), property);
-                JSStringRef js_message = JSStringCreateWithUTF8CString (message);
-                *js_exception = JSValueMakeString (js_context, js_message);
-                JSStringRelease (js_message);
-                g_free (message);
-            }
-        }
-        else
-        {
-            gchar* message = g_strdup_printf (_("%s.%s cannot be accessed"),
-                KATZE_OBJECT_NAME (object), property);
-            JSStringRef js_message = JSStringCreateWithUTF8CString (message);
-            *js_exception = JSValueMakeString (js_context, js_message);
-            JSStringRelease (js_message);
-            g_free (message);
-        }
-        g_free (property);
-    }
-    return result;
-}
-
-static JSValueRef
-_js_foo_call_as_function_cb (JSContextRef     js_context,
-                             JSObjectRef      js_function,
-                             JSObjectRef      js_this,
-                             size_t           n_arguments,
-                             const JSValueRef js_arguments[],
-                             JSValueRef*      js_exception)
-{
-    GObject* object = JSObjectGetPrivate (js_this);
-    if (object)
-    {
-        if (!n_arguments)
-        {
-            gtk_widget_show (GTK_WIDGET (object));
-        }
-        else if (n_arguments == 1)
-        {
-            JSObjectRef js_arg1 = JSValueToObject (
-                js_context, js_arguments[0], NULL);
-            GObject* arg1 = JSObjectGetPrivate (js_arg1);
-            if (arg1)
-                gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (arg1));
-        }
-    }
-
-    return JSValueMakeUndefined (js_context);
-}
-
-static void
-_js_foo_add_function (JSContextRef js_context,
-                      JSObjectRef  js_object,
-                      const gchar* func)
-{
-    JSStringRef js_func = JSStringCreateWithUTF8CString (func);
-    JSObjectRef js_function = JSObjectMakeFunctionWithCallback (
-        js_context, js_func, _js_foo_call_as_function_cb);
-    JSStringRelease (js_func);
-    _js_object_set_property (js_context, js_object, func, js_function);
-}
-
-static JSObjectRef
-_js_object_new (JSContextRef js_context,
-                gpointer     object)
-{
-    JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
-    js_class_def.className = g_strdup (KATZE_OBJECT_NAME (object));
-    js_class_def.getPropertyNames = _js_class_get_property_names_cb;
-    js_class_def.hasProperty = _js_class_has_property_cb;
-    js_class_def.getProperty = _js_class_get_property_cb;
-    js_class_def.setProperty = _js_class_set_property_cb;
-    JSClassRef js_class = JSClassCreate (&js_class_def);
-    JSObjectRef js_object = JSObjectMake (js_context, js_class, object);
-    if (GTK_IS_WIDGET (object))
-    {
-        _js_foo_add_function (js_context, js_object, "show");
-    }
-    if (GTK_IS_CONTAINER (object))
-    {
-        _js_foo_add_function (js_context, js_object, "add");
-    }
-    return js_object;
-}
-
-static JSValueRef
-_js_eval (JSContextRef js_context,
-          const gchar* script,
-          gchar**      exception)
-{
-    JSStringRef js_script = JSStringCreateWithUTF8CString (script);
-    JSValueRef js_exception = NULL;
-    JSValueRef js_value = JSEvaluateScript (js_context, js_script,
-        JSContextGetGlobalObject (js_context), NULL, 0, &js_exception);
-    if (!js_value && exception)
-    {
-        JSStringRef js_message = JSValueToStringCopy (js_context,
-                                                      js_exception, NULL);
-        *exception = _js_string_utf8 (js_message);
-        JSStringRelease (js_message);
-        js_value = JSValueMakeNull (js_context);
-    }
-    JSStringRelease (js_script);
-    return js_value;
-}
-
-static bool
-_js_check_syntax (JSContextRef js_context,
-                  const gchar* script,
-                  const gchar* source_id,
-                  int          line,
-                  gchar**      exception)
-{
-    JSStringRef js_script = JSStringCreateWithUTF8CString (script);
-    JSStringRef js_source_id = JSStringCreateWithUTF8CString (source_id);
-    JSValueRef js_exception = NULL;
-    bool result = JSCheckScriptSyntax (js_context, js_script, js_source_id,
-                                       line, &js_exception);
-    if (!result && exception)
-    {
-        JSStringRef js_message = JSValueToStringCopy (js_context,
-                                                      js_exception, NULL);
-        *exception = _js_string_utf8 (js_message);
-        JSStringRelease (js_message);
-    }
-    JSStringRelease (js_source_id);
-    JSStringRelease (js_script);
-    return result;
-}
-
-static gboolean
-_js_document_load_script_file (JSContextRef js_context,
-                               const gchar* filename,
-                               gchar**      exception)
-{
-    gboolean result = FALSE;
-    gchar* script;
-    GError* error = NULL;
-    if (g_file_get_contents (filename, &script, NULL, &error))
-    {
-        gchar* wrapped_script = g_strdup_printf (
-            "var wrapped = function () { %s }; wrapped ();", script);
-        if (_js_eval (js_context, wrapped_script, exception))
-            result = TRUE;
-        g_free (wrapped_script);
-        g_free (script);
-    }
-    else
-    {
-        *exception = g_strdup (error->message);
-        g_error_free (error);
-    }
-    return result;
-}
-
 static void
 midori_addons_init (MidoriAddons* addons)
 {
@@ -567,91 +169,30 @@ midori_addons_init (MidoriAddons* addons)
     gtk_box_pack_start (GTK_BOX (addons), priv->treeview, TRUE, TRUE, 0);
 }
 
-static JSValueRef
-_js_info_call_as_function_cb (JSContextRef     js_context,
-                              JSObjectRef      js_function,
-                              JSObjectRef      js_this,
-                              size_t           n_arguments,
-                              const JSValueRef js_arguments[],
-                              JSValueRef*      js_exception)
-{
-    if (n_arguments > 0) {
-        JSStringRef js_string = JSValueToStringCopy (
-            js_context, js_arguments[0], NULL);
-        gchar* string = _js_string_utf8 (js_string);
-        // FIXME: Do we want to print this somewhere else?
-        printf ("console.info: %s\n", string);
-        g_free (string);
-        JSStringRelease (js_string);
-    }
-
-    return JSValueMakeUndefined (js_context);
-}
-
-static void
-_midori_addons_extensions_main (MidoriAddons* addons,
-                                GtkWidget*    web_widget)
+static gboolean
+_js_script_from_file (JSContextRef js_context,
+                      const gchar* filename,
+                      gchar**      exception)
 {
-    MidoriAddonsPrivate* priv = addons->priv;
-
-    JSClassDefinition js_global_def = kJSClassDefinitionEmpty;
-    js_global_def.getPropertyNames = _js_class_get_property_names_cb;
-    js_global_def.hasProperty = _js_class_has_property_cb;
-    js_global_def.getProperty = _js_class_get_property_cb;
-    JSClassRef js_global_class = JSClassCreate (&js_global_def);
-    JSGlobalContextRef js_context = JSGlobalContextCreate (js_global_class);
-    JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
-    js_class_def.className = g_strdup ("console");
-    JSClassRef js_class = JSClassCreate (&js_class_def);
-    JSObjectRef js_console = JSObjectMake (js_context, js_class, NULL);
-    JSStringRef js_info = JSStringCreateWithUTF8CString ("info");
-    JSObjectRef js_info_function = JSObjectMakeFunctionWithCallback (
-        js_context, js_info, _js_info_call_as_function_cb);
-    JSObjectSetProperty (js_context, js_console, js_info, js_info_function,
-                         kJSPropertyAttributeNone, NULL);
-    JSStringRelease (js_info);
-    _js_object_set_property (js_context,
-                             JSContextGetGlobalObject (js_context),
-                             "console", js_console);
-
-    GtkWidget* browser = gtk_widget_get_toplevel (GTK_WIDGET (web_widget));
-    if (GTK_WIDGET_TOPLEVEL (browser))
+    gboolean result = FALSE;
+    gchar* script;
+    GError* error = NULL;
+    if (g_file_get_contents (filename, &script, NULL, &error))
     {
-        // FIXME: Midori should be backed up by a real GObject
-        JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
-        js_class_def.className = g_strdup ("Midori");
-        JSClassRef js_class = JSClassCreate (&js_class_def);
-        JSObjectRef js_midori = JSObjectMake (js_context, js_class, NULL);
-        _js_object_set_property (js_context,
-                                 JSContextGetGlobalObject (js_context),
-                                 "midori", js_midori);
-        JSObjectRef js_browser = _js_object_new (js_context, browser);
-        _js_object_set_property (js_context,
-                                 js_midori,
-                                 "browser", js_browser);
+        // Wrap the script to prevent global variables
+        gchar* wrapped_script = g_strdup_printf (
+            "var wrapped = function () { %s }; wrapped ();", script);
+        if (gjs_script_eval (js_context, wrapped_script, exception))
+            result = TRUE;
+        g_free (wrapped_script);
+        g_free (script);
     }
-
-    // FIXME: We want to honor system installed addons as well
-    gchar* addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME,
-                                          _folder_for_kind (priv->kind), NULL);
-    GDir* addon_dir = g_dir_open (addon_path, 0, NULL);
-    if (addon_dir)
+    else
     {
-        const gchar* filename;
-        while ((filename = g_dir_read_name (addon_dir)))
-        {
-            gchar* fullname = g_build_filename (addon_path, filename, NULL);
-            gchar* exception = NULL;
-            _js_document_load_script_file (js_context, fullname, &exception);
-            if (exception)
-            // FIXME: Do we want to print this somewhere else?
-            // FIXME Convert the filename to UTF8
-                printf ("%s - Exception: %s\n", filename, exception);
-            g_free (fullname);
-        }
-        g_dir_close (addon_dir);
+        *exception = g_strdup (error->message);
+        g_error_free (error);
     }
-    JSGlobalContextRelease (js_context);
+    return result;
 }
 
 static void
@@ -674,12 +215,11 @@ midori_web_widget_window_object_cleared_cb (GtkWidget*         web_widget,
         {
             gchar* fullname = g_build_filename (addon_path, filename, NULL);
             gchar* exception;
-            if (!_js_document_load_script_file (js_context, fullname,
-                                                &exception))
+            if (!_js_script_from_file (js_context, fullname, &exception))
             {
                 gchar* message = g_strdup_printf ("console.error ('%s');",
                                                   exception);
-                _js_eval (js_context, message, NULL);
+                gjs_script_eval (js_context, message, NULL);
                 g_free (message);
                 g_free (exception);
             }
@@ -717,9 +257,7 @@ midori_addons_new (GtkWidget*      web_widget,
     MidoriAddonsPrivate* priv = addons->priv;
     priv->kind = kind;
 
-    if (kind == MIDORI_ADDON_EXTENSIONS)
-        _midori_addons_extensions_main (addons, web_widget);
-    else if (kind == MIDORI_ADDON_USER_SCRIPTS)
+    if (kind == MIDORI_ADDON_USER_SCRIPTS)
         g_signal_connect (web_widget, "window-object-cleared",
             G_CALLBACK (midori_web_widget_window_object_cleared_cb), addons);