Make javascript gobject bindings independant.

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.
This commit is contained in:
Christian Dywan 2008-05-06 00:51:04 +02:00
parent 750d9d5b01
commit 4a829b0ab0
5 changed files with 507 additions and 484 deletions

View file

@ -27,5 +27,6 @@ midori_SOURCES = \
midori-websettings.c midori-websettings.h \ midori-websettings.c midori-websettings.h \
midori-preferences.c midori-preferences.h \ midori-preferences.c midori-preferences.h \
webSearch.c webSearch.h \ webSearch.c webSearch.h \
gjs.c gjs.h \
sokoke.c sokoke.h \ sokoke.c sokoke.h \
search.c search.h search.c search.h

399
src/gjs.c Normal file
View file

@ -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;
}

47
src/gjs.h Normal file
View file

@ -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__ */

View file

@ -18,6 +18,7 @@
#include "midori-trash.h" #include "midori-trash.h"
#include "midori-browser.h" #include "midori-browser.h"
#include <katze/katze.h> #include <katze/katze.h>
#include "gjs.h"
#include <string.h> #include <string.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
@ -311,6 +312,19 @@ main (int argc, char** argv)
return 0; 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 // Load configuration files
GString* error_messages = g_string_new (NULL); GString* error_messages = g_string_new (NULL);
gchar* config_path = g_build_filename (g_get_user_config_dir (), 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"); midori_browser_activate_action (browser, "Location");
katze_xbel_item_unref (_session); 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 (); gtk_main ();
JSGlobalContextRelease (js_context);
g_object_unref (accel_group); g_object_unref (accel_group);
// Save configuration files // Save configuration files

View 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 static void
midori_addons_init (MidoriAddons* addons) 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); gtk_box_pack_start (GTK_BOX (addons), priv->treeview, TRUE, TRUE, 0);
} }
static JSValueRef static gboolean
_js_info_call_as_function_cb (JSContextRef js_context, _js_script_from_file (JSContextRef js_context,
JSObjectRef js_function, const gchar* filename,
JSObjectRef js_this, gchar** exception)
size_t n_arguments,
const JSValueRef js_arguments[],
JSValueRef* js_exception)
{ {
if (n_arguments > 0) { gboolean result = FALSE;
JSStringRef js_string = JSValueToStringCopy ( gchar* script;
js_context, js_arguments[0], NULL); GError* error = NULL;
gchar* string = _js_string_utf8 (js_string); if (g_file_get_contents (filename, &script, NULL, &error))
// 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))
{ {
// FIXME: Midori should be backed up by a real GObject // Wrap the script to prevent global variables
JSClassDefinition js_class_def = kJSClassDefinitionEmpty; gchar* wrapped_script = g_strdup_printf (
js_class_def.className = g_strdup ("Midori"); "var wrapped = function () { %s }; wrapped ();", script);
JSClassRef js_class = JSClassCreate (&js_class_def); if (gjs_script_eval (js_context, wrapped_script, exception))
JSObjectRef js_midori = JSObjectMake (js_context, js_class, NULL); result = TRUE;
_js_object_set_property (js_context, g_free (wrapped_script);
JSContextGetGlobalObject (js_context), g_free (script);
"midori", js_midori);
JSObjectRef js_browser = _js_object_new (js_context, browser);
_js_object_set_property (js_context,
js_midori,
"browser", js_browser);
} }
else
// 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)
{ {
const gchar* filename; *exception = g_strdup (error->message);
while ((filename = g_dir_read_name (addon_dir))) g_error_free (error);
{
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); return result;
}
JSGlobalContextRelease (js_context);
} }
static void 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* fullname = g_build_filename (addon_path, filename, NULL);
gchar* exception; gchar* exception;
if (!_js_document_load_script_file (js_context, fullname, if (!_js_script_from_file (js_context, fullname, &exception))
&exception))
{ {
gchar* message = g_strdup_printf ("console.error ('%s');", gchar* message = g_strdup_printf ("console.error ('%s');",
exception); exception);
_js_eval (js_context, message, NULL); gjs_script_eval (js_context, message, NULL);
g_free (message); g_free (message);
g_free (exception); g_free (exception);
} }
@ -717,9 +257,7 @@ midori_addons_new (GtkWidget* web_widget,
MidoriAddonsPrivate* priv = addons->priv; MidoriAddonsPrivate* priv = addons->priv;
priv->kind = kind; priv->kind = kind;
if (kind == MIDORI_ADDON_EXTENSIONS) if (kind == MIDORI_ADDON_USER_SCRIPTS)
_midori_addons_extensions_main (addons, web_widget);
else if (kind == MIDORI_ADDON_USER_SCRIPTS)
g_signal_connect (web_widget, "window-object-cleared", g_signal_connect (web_widget, "window-object-cleared",
G_CALLBACK (midori_web_widget_window_object_cleared_cb), addons); G_CALLBACK (midori_web_widget_window_object_cleared_cb), addons);