diff --git a/src/Makefile.am b/src/Makefile.am index 82208d26..dee2ba7e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 00000000..f7e2320e --- /dev/null +++ b/src/gjs.c @@ -0,0 +1,399 @@ +/* + Copyright (C) 2008 Christian Dywan + + 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 + +#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 index 00000000..75d846c1 --- /dev/null +++ b/src/gjs.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2008 Christian Dywan + + 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 +#include + +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__ */ diff --git a/src/main.c b/src/main.c index 884e30ab..f319c3d1 100644 --- a/src/main.c +++ b/src/main.c @@ -18,6 +18,7 @@ #include "midori-trash.h" #include "midori-browser.h" #include +#include "gjs.h" #include #include @@ -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 diff --git a/src/midori-addons.c b/src/midori-addons.c index 552f7972..b83f7c7c 100644 --- a/src/midori-addons.c +++ b/src/midori-addons.c @@ -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) +static gboolean +_js_script_from_file (JSContextRef js_context, + const gchar* filename, + gchar** 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) -{ - 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);