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:
parent
750d9d5b01
commit
4a829b0ab0
5 changed files with 507 additions and 484 deletions
|
@ -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
|
||||
|
|
399
src/gjs.c
Normal file
399
src/gjs.c
Normal 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
47
src/gjs.h
Normal 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__ */
|
38
src/main.c
38
src/main.c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
*exception = g_strdup (error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
g_dir_close (addon_dir);
|
||||
}
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue