From 5494cec6064dcb4e9ade4379d154ce1b5262a414 Mon Sep 17 00:00:00 2001 From: Jan Michael Alonzo Date: Tue, 18 Nov 2008 18:23:56 +1100 Subject: [PATCH] Add initial support for defect #12: http://code.google.com/p/pywebkitgtk/issues/detail?id=12 defect #12 - JavaScript execution / evaluation capabilities It's currently turned off by default since we need to modify the way we load the webkit module. You can turn it on by adding --with-gjs to configure or autogen.sh if you're tracking the development repositories. --- Makefile.am | 58 +- configure.ac | 24 + gjs.defs | 120 ++++ gjs.override | 68 +++ gjs/gjs.c | 1046 +++++++++++++++++++++++++++++++++ gjs/gjs.h | 128 ++++ javascriptcore/javascriptcore_types.c | 30 + javascriptcore/javascriptcore_types.h | 22 +- webkit.override | 6 +- webkitmodule.c | 16 +- 10 files changed, 1499 insertions(+), 19 deletions(-) create mode 100644 gjs.defs create mode 100644 gjs.override create mode 100644 gjs/gjs.c create mode 100644 gjs/gjs.h diff --git a/Makefile.am b/Makefile.am index 6622b38..7d49d0e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,14 @@ + +webkit_defs := +webkit_sources := +nodist_webkit_sources := +webkit_override := +webkit_cflags := + +CREATEDEFS = $(PYTHON) $(PYGTK_CODEGENDIR)/createdefs.py + defsdir = $(datadir)/pygtk/2.0/defs -defs_DATA = $(PYWEBKIT_DEFS) +defs_DATA = $(webkit_defs) common_ldflags = -module -avoid-version @@ -10,29 +19,47 @@ webkitdir = $(pkgpyexecdir)/webkit pkgpyexec_LTLIBRARIES = webkit.la -webkit_la_CPPFLAGS = $(PYTHON_INCLUDES) $(DEPS_CPPFLAGS) +webkit_la_CPPFLAGS = $(PYTHON_INCLUDES) $(DEPS_CPPFLAGS) $(webkit_cflags) webkit_la_CFLAGS = $(DEPS_CFLAGS) webkit_la_LDFLAGS = $(common_ldflags) -export-symbols-regex initwebkit webkit_la_LIBADD = $(DEPS_LIBS) -webkit_la_SOURCES = \ +webkit_la_SOURCES = $(webkit_sources) +nodist_webkit_la_SOURCES = $(nodist_webkit_sources) + +webkit_defs += $(PYWEBKIT_DEFS) +webkit_override += $(srcdir)/webkit.override +webkit_sources += \ webkitmodule.c \ javascriptcore/javascriptcore_types.c \ javascriptcore/javascriptcore_types.h -nodist_webkit_la_SOURCES = webkit.c +nodist_webkit_sources += webkit.c + +if HAVE_GJS +webkit_defs += gjs.defs +webkit_override += $(srcdir)/gjs.override +webkit_cflags += -I$(srcdir)/gjs +webkit_sources += gjs/gjs.c +nodist_webkit_sources += gjs.c -webkit.c: .defs.c +gjs.c: gjs.defs gjs.override gjs.defs.c +endif -.defs.c: webkit.override webkit-stable.defs webkit-dev.defs - cp $(PYWEBKIT_DEFS) webkit.defs + +webkit.c: $(PYWEBKIT_DEFS) webkit.override webkit.defs webkit.defs.c + +webkit.defs: $(PYWEBKIT_DEFS) + $(CREATEDEFS) $@ $(PYWEBKIT_DEFS) + +%.defs.c: (cd $(srcdir) \ && $(PYGOBJECT_CODEGEN) \ --register $(PYGTK_DEFSDIR)/gdk-types.defs \ --register $(PYGTK_DEFSDIR)/gtk-types.defs \ - --override webkit.override \ - --prefix pywebkit webkit.defs) 2>&1 >gen-webkit.c | tee webkit.errors \ - && ! grep -q -v "^\*\*\*INFO\*\*\*" webkit.errors \ - && cp gen-webkit.c webkit.c \ - && rm -f gen-webkit.c + --override $(srcdir)/$(*F).override \ + --prefix py$(*F) $(*F).defs) 2>&1 >gen-$(*F).c | tee $(*F).errors \ + && ! grep -q -v "^\*\*\*INFO\*\*\*" $(*F).errors \ + && cp gen-$(*F).c $(*F).c \ + && rm -f gen-$(*F).c dist-hook: ChangeLog @@ -57,10 +84,14 @@ MAINTAINERCLEANFILES = \ CLEANFILES = \ gen-webkit.c \ + gjs.c \ + gen-gjs.c \ webkit.c \ Makefile.in \ webkit.defs \ webkit.errors \ + gjs.errors \ + dummy.0.2 \ pywebkitgtk-1.0.pc EXTRA_DIST = \ @@ -71,7 +102,8 @@ EXTRA_DIST = \ NEWS \ README \ demos/webbrowser.py \ + gjs.defs \ + gjs.override \ webkit.override \ webkit-dev.defs \ webkit-stable.defs - diff --git a/configure.ac b/configure.ac index f2dbd66..6975ae0 100644 --- a/configure.ac +++ b/configure.ac @@ -66,6 +66,27 @@ PYGTK_DEFSDIR=`$PKG_CONFIG --variable=defsdir pygtk-2.0` AC_SUBST(PYGTK_DEFSDIR) AC_MSG_RESULT($PYGTK_DEFSDIR) +dnl check for pygtk codegen dir +AC_MSG_CHECKING(for pygtk codegendir) +PYGTK_CODEGENDIR=`$PKG_CONFIG --variable=codegendir pygtk-2.0` +AC_SUBST(PYGTK_CODEGENDIR) +AC_MSG_RESULT($PYGTK_CODEGENDIR) + +dnl check if Gjs is wanted +AC_MSG_CHECKING([if Gjs will be included]) +AC_ARG_WITH(gjs, + AC_HELP_STRING([--with-gjs=@<:@yes/no@:>@], + [Include GJS JavaScriptCore binding [default=no]]), + [with_gjs="yes"],[with_gjs="no"]) +case "$with_gjs" in + yes|no) ;; + *) AC_MSG_ERROR([Invalid option. Should be 'yes' or 'no']) ;; +esac +if test $with_gjs = "yes"; then + AC_DEFINE([HAVE_GJS],[1],[Define to have GJS Support]) +fi +AC_MSG_RESULT([$with_gjs]) + dnl check which .defs file we should use dnl dnl webkit-stable.defs is for upstream webkit/gtk stable releases @@ -79,6 +100,9 @@ fi AC_SUBST(PYWEBKIT_DEFS) AC_MSG_RESULT($PYWEBKIT_DEFS) +dnl conditionals +AM_CONDITIONAL([HAVE_GJS],[test "$with_gjs" = "yes"]) + dnl output AC_CONFIG_FILES([ Makefile diff --git a/gjs.defs b/gjs.defs new file mode 100644 index 0000000..e5f726f --- /dev/null +++ b/gjs.defs @@ -0,0 +1,120 @@ +;; -*- scheme -*- +;; PyWebKitGtk - Python bindings to WebKit/GTK+ +;; +;; Copyright (C) 2008 Luke Kenneth Carlson Leigh +;; +;; This library is free software; you can redistribute it and/or +;; modify it under the terms of the GNU Library General Public +;; License as published by the Free Software Foundation; either +;; version 2 of the License, or (at your option) any later version. +;; +;; This library is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; Library General Public License for more details. +;; +;; You should have received a copy of the GNU Library General Public +;; License along with this library; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA +;; + +(define-object Value + (in-module "Gjs") + (parent "GObject") + (c-name "GjsValue") + (gtype-id "GJS_TYPE_VALUE") +) + +;(define-method gjs_get_global_context +; (of-object "WebKitWebFrame") +; (c-name "gjs_get_global_context") +; (return-type "GjsValue*") +;) + +;; From "gjs.h" + +(define-method has_attribute + (of-object "GjsValue") + (c-name "gjs_value_has_attribute") + (return-type "gboolean") + (parameters + '("const-gchar*" "name") + ) +) + +(define-method get_attribute + (of-object "GjsValue") + (c-name "gjs_value_get_attribute") + (caller-owns-return #t) + (return-type "GjsValue*") + (parameters + '("const-gchar*" "name") + ) +) + +(define-method get_string + (of-object "GjsValue") + (c-name "gjs_value_get_string") + (caller-owns-return #t) + (return-type "const-gchar*") +) + +(define-method get_attribute_string + (of-object "GjsValue") + (c-name "gjs_value_get_attribute_string") + (caller-owns-return #t) + (return-type "GjsValue*") + (parameters + '("const-gchar*" "name") + ) +) + +(define-method get_nth_attribute + (of-object "GjsValue") + (c-name "gjs_value_get_nth_attribute") + (caller-owns-return #t) + (return-type "GjsValue*") + (parameters + '("gint" "n") + ) +) + +(define-method get_elements_by_tag_name + (of-object "GjsValue") + (c-name "gjs_value_get_elements_by_tag_name") + (caller-owns-return #t) + (return-type "GjsValue*") + (parameters + '("const-gchar*" "name") + ) +) + +;(define-method eval +; (of-object "GjsValue") +; (c-name "gjs_value_eval") +; (caller-owns-return #t) +; (return-type "GjsValue*") +; (parameters +; '("const-gchar*" "script") +; ) +;) + +(define-method execute + (of-object "GjsValue") + (c-name "gjs_value_execute") + (caller-owns-return #t) + (return-type "GjsValue*") + (parameters + '("const-gchar*" "script") + ) +) + +(define-method get_by_name + (of-object "GjsValue") + (c-name "gjs_value_get_by_name") + (caller-owns-return #t) + (return-type "GjsValue*") + (parameters + '("const-gchar*" "name") + ) +) diff --git a/gjs.override b/gjs.override new file mode 100644 index 0000000..453fc43 --- /dev/null +++ b/gjs.override @@ -0,0 +1,68 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- */ +/* + Copyright (C) 2008 Luke Kenneth Carlson Leigh + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +%% +headers +#include +#define NO_IMPORT_PYGOBJECT +#include +#include +#include + +#include "gjs/gjs.h" +%% +body +%% +modulename webkit.gjs +%% +ignore-blob + *_get_type + _* +%% +import gobject.GObject as PyGObject_Type +%% +override gjs_value_execute +static PyObject * +_wrap_gjs_value_execute(PyGObject *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "script", NULL }; + const char *script; + gchar *exception = NULL; + GjsValue *ret; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs,"s:GjsValue.execute", kwlist, &script)) + return NULL; + + ret = gjs_value_execute(GJS_VALUE(self->obj), script, &exception); + + if (exception) + { + PyErr_SetString( + PyExc_RuntimeError, /* TODO: better exception */ + exception); + g_free(exception); + return NULL; + } + + if (ret == NULL) + return NULL; + + /* pygobject_new handles NULL checking */ + return pygobject_new((GObject *)ret); +} diff --git a/gjs/gjs.c b/gjs/gjs.c new file mode 100644 index 0000000..99e4ec5 --- /dev/null +++ b/gjs/gjs.c @@ -0,0 +1,1046 @@ +/* + 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 +#include +/* Needed for versioning macros */ +#include + +struct _GjsValue +{ + GObject parent_instance; + + JSContextRef js_context; + JSValueRef js_value; + gchar* string; +}; + +G_DEFINE_TYPE (GjsValue, gjs_value, G_TYPE_OBJECT) + +static void +gjs_value_finalize (GObject* object) +{ + GjsValue* value = GJS_VALUE (object); + + g_free (value->string); + + G_OBJECT_CLASS (gjs_value_parent_class)->finalize (object); +} + +static void +gjs_value_class_init (GjsValueClass* class) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = gjs_value_finalize; +} + +static void +gjs_value_init (GjsValue* value) +{ + value->js_context = NULL; + value->js_value = NULL; + value->string = NULL; +} + +/** + * gjs_value_new: + * @js_context: a #JSContextRef + * @js_value: a #JSValueRef or %NULL + * + * Creates a new #GjsValue for a #JsValueRef. If @js_value + * is %NULL, the new value represents the global object. + * + * Return value: a new #GjsValue + **/ +GjsValue* +gjs_value_new (JSContextRef js_context, + JSValueRef js_value) +{ + GjsValue* value; + + g_return_val_if_fail (js_context, NULL); + + value = g_object_new (GJS_TYPE_VALUE, NULL); + value->js_context = js_context; + value->js_value = js_value ? js_value : JSContextGetGlobalObject (js_context); + return value; +} + +/** + * gjs_value_is_valid: + * @value: a #GjsValue + * + * Determines whether the value is valid, with regard to + * its internal state. This is primarily useful for API + * to ensure that the value is in a defined condition. + * + * Return value: %TRUE if value is valid + **/ +gboolean +gjs_value_is_valid (GjsValue* value) +{ + g_return_val_if_fail (GJS_IS_VALUE (value), FALSE); + g_return_val_if_fail (value->js_context, FALSE); + g_return_val_if_fail (value->js_value, FALSE); + + return TRUE; +} + +/** + * gjs_value_is_object: + * @value: a #GjsValue + * + * Determines whether the value is an object. + * + * Return value: %TRUE if value is an object + **/ +gboolean +gjs_value_is_object (GjsValue* value) +{ + g_return_val_if_fail (gjs_value_is_valid (value), FALSE); + + return JSValueIsObject (value->js_context, value->js_value) == true; +} + +/** + * gjs_value_has_attribute: + * @value: a #GjsValue + * @name: the name of a attribute + * + * Determines whether the value has the specified attribute. + * + * This can only be used on object values. + * + * Return value: %TRUE if the specified attribute exists + **/ +gboolean +gjs_value_has_attribute (GjsValue* value, + const gchar* name) +{ + JSObjectRef js_object; + JSStringRef js_name; + gboolean result; + + g_return_val_if_fail (gjs_value_is_object (value), FALSE); + g_return_val_if_fail (name, FALSE); + + js_object = JSValueToObject (value->js_context, value->js_value, NULL); + js_name = JSStringCreateWithUTF8CString (name); + result = JSObjectHasProperty (value->js_context, js_object, js_name) == true; + JSStringRelease (js_name); + return result; +} + +/** + * gjs_value_get_attribute: + * @value: a #GjsValue + * @name: the name of a attribute + * + * Retrieves the specified attribute. + * + * This can only be used on object values. + * + * Return value: a new #GjsValue + **/ +GjsValue* +gjs_value_get_attribute (GjsValue* value, + const gchar* name) +{ + JSObjectRef js_object; + JSStringRef js_name; + JSValueRef js_value; + + g_return_val_if_fail (gjs_value_has_attribute (value, name), NULL); + + js_object = JSValueToObject (value->js_context, value->js_value, NULL); + js_name = JSStringCreateWithUTF8CString (name); + js_value = JSObjectGetProperty (value->js_context, js_object, js_name, NULL); + JSStringRelease (js_name); + + return gjs_value_new (value->js_context, js_value); +} + +/** + * gjs_value_get_string: + * @value: a #GjsValue + * + * Retrieves the value in the form of a string. + * + * This can only be used on object values. + * + * Note: The string won't reflect changes to the value. + * + * Return value: the value as a string + **/ +const gchar* +gjs_value_get_string (GjsValue* value) +{ + JSStringRef js_string; + + g_return_val_if_fail (gjs_value_is_valid (value), NULL); + + if (value->string) + return value->string; + + js_string = JSValueToStringCopy (value->js_context, value->js_value, NULL); + value->string = gjs_string_utf8 (js_string); + JSStringRelease (js_string); + return value->string; +} + +void +gjs_value_weak_notify_cb (GjsValue* attribute, + GjsValue* value) +{ + g_object_unref (attribute); +} + +/** + * gjs_value_get_attribute_string: + * @value: a #GjsValue + * @name: the name of a attribute + * + * Retrieves the attribute of the value in the form of a string. + * + * This can only be used on object values. + * + * Note: The string won't reflect changes to the value. + * + * Return value: the value as a string + **/ +const gchar* +gjs_value_get_attribute_string (GjsValue* value, + const gchar* name) +{ + GjsValue* attribute; + + g_return_val_if_fail (gjs_value_has_attribute (value, name), NULL); + + attribute = gjs_value_get_attribute (value, name); + g_object_weak_ref (G_OBJECT (value), + (GWeakNotify)gjs_value_weak_notify_cb, attribute); + return gjs_value_get_string (attribute); +} + +/** + * gjs_value_get_nth_attribute: + * @value: a #GjsValue + * @n: an index + * + * Retrieves the indiced attribute at the specified + * position. This is particularly faster than looking + * up attributes by name. + * + * This can only be used on object values. + * + * Return value: a new #GjsValue, or %NULL + **/ +GjsValue* +gjs_value_get_nth_attribute (GjsValue* value, + guint n) +{ + JSObjectRef js_object; + JSValueRef js_value; + + g_return_val_if_fail (gjs_value_is_object (value), NULL); + + js_object = JSValueToObject (value->js_context, value->js_value, NULL); + js_value = JSObjectGetPropertyAtIndex (value->js_context, js_object, n, NULL); + if (JSValueIsUndefined (value->js_context, js_value)) + return NULL; + + return gjs_value_new (value->js_context, js_value); +} + +/** + * gjs_value_foreach: + * @value: a #GjsValue + * @callback: a callback + * @user_data: user data + * + * Calls the specified callback for each indiced attribute. + * This is a particularly fast way of looping through the + * elements of an array. + * + * This can only be used on object values. + **/ +void +gjs_value_foreach (GjsValue* value, + GjsCallback callback, + gpointer user_data) +{ + guint i; + GjsValue* attribute; + + g_return_if_fail (gjs_value_is_object (value)); + + i = 0; + do + { + attribute = gjs_value_get_nth_attribute (value, i); + if (attribute) + { + callback (attribute, user_data); + g_object_unref (attribute); + } + i++; + } + while (attribute); +} + +/** + * gjs_value_forall: + * @value: a #GjsValue + * @callback: a callback + * @user_data: user data + * + * Calls the specified callback for each attribute. + * + * This can only be used on object values. + **/ +void +gjs_value_forall (GjsValue* value, + GjsCallback callback, + gpointer user_data) +{ + JSObjectRef js_object; + JSPropertyNameArrayRef js_properties; + size_t n_properties; + guint i; + JSStringRef js_property; + gchar* property; + GjsValue* attribute; + + g_return_if_fail (gjs_value_is_object (value)); + + js_object = JSValueToObject (value->js_context, value->js_value, NULL); + js_properties = JSObjectCopyPropertyNames (value->js_context, js_object); + n_properties = JSPropertyNameArrayGetCount (js_properties); + for (i = 0; i < n_properties; i++) + { + js_property = JSPropertyNameArrayGetNameAtIndex (js_properties, i); + property = gjs_string_utf8 (js_property); + if (gjs_value_has_attribute (value, property)) + { + attribute = gjs_value_get_attribute (value, property); + callback (attribute, user_data); + g_object_unref (attribute); + } + g_free (property); + JSStringRelease (js_property); + } + JSPropertyNameArrayRelease (js_properties); +} + +/** + * gjs_value_get_by_name: + * @value: a #GjsValue + * @name: the name of an object + * + * Retrieves a value for the specified name, + * for example "document" or "document.body". + * + * Return value: the value, or %NULL + **/ +GjsValue* +gjs_value_get_by_name (GjsValue* value, + const gchar* name) +{ + gchar* script; + GjsValue* elements; + + g_return_val_if_fail (gjs_value_is_valid (value), NULL); + g_return_val_if_fail (name, NULL); + + script = g_strdup_printf ("return %s;", name); + elements = gjs_value_execute (value, script, NULL); + g_free (script); + return elements; +} + +/** + * gjs_value_get_elements_by_tag_name: + * @value: a #GjsValue + * @name: the tag name + * + * Retrieves all children with the specified tag name. + * + * This can only be used on object values. + * + * Return value: all matching elements + **/ +GjsValue* +gjs_value_get_elements_by_tag_name (GjsValue* value, + const gchar* name) +{ + gchar* script; + GjsValue* elements; + + g_return_val_if_fail (gjs_value_is_object (value), NULL); + g_return_val_if_fail (name, NULL); + + script = g_strdup_printf ("return this.getElementsByTagName ('%s');", name); + elements = gjs_value_execute (value, script, NULL); + g_free (script); + return elements; +} + +/** + * gjs_value_execute: + * @value: a #GjsValue + * @script: javascript code + * + * Executes a piece of javascript code. If @value is an object + * it can be referred to as 'this' in the code. + * + * A 'return' statement in the code will yield the result to + * the return value of this function. + * + * Return value: the return value, or %NULL + **/ +GjsValue* +gjs_value_execute (GjsValue* value, + const gchar* script, + gchar** exception) +{ + JSStringRef js_script; + JSObjectRef js_function; + JSObjectRef js_object; + JSValueRef js_exception; + JSValueRef js_value; + JSStringRef js_message; + + g_return_val_if_fail (gjs_value_is_valid (value), FALSE); + g_return_val_if_fail (script, FALSE); + + js_script = JSStringCreateWithUTF8CString (script); + js_function = JSObjectMakeFunction (value->js_context, NULL, 0, NULL, + js_script, NULL, 1, NULL); + JSStringRelease (js_script); + js_object = JSValueToObject (value->js_context, value->js_value, NULL); + js_exception = NULL; + js_value = JSObjectCallAsFunction (value->js_context, js_function, + js_object, 0, NULL, &js_exception); + if (!js_value && exception) + { + js_message = JSValueToStringCopy (value->js_context, js_exception, NULL); + *exception = gjs_string_utf8 (js_message); + JSStringRelease (js_message); + return NULL; + } + return gjs_value_new (value->js_context, js_value); +} + +JSValueRef +gjs_script_eval (JSContextRef js_context, + const gchar* script, + gchar** exception) +{ + g_return_val_if_fail (js_context, FALSE); + g_return_val_if_fail (script, FALSE); + + 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) +{ + g_return_val_if_fail (js_context, FALSE); + g_return_val_if_fail (script, FALSE); + + 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) +{ + g_return_val_if_fail (js_context, FALSE); + g_return_val_if_fail (filename, FALSE); + + 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 if (error) + { + *exception = g_strdup (error->message); + g_error_free (error); + } + else + *exception = g_strdup (_("An unknown error occured.")); + return result; +} + +gchar* +gjs_string_utf8 (JSStringRef js_string) +{ + size_t size_utf8; + gchar* string_utf8; + + g_return_val_if_fail (js_string, NULL); + + size_utf8 = JSStringGetMaximumUTF8CStringSize (js_string); + string_utf8 = g_new (gchar, size_utf8); + JSStringGetUTF8CString (js_string, string_utf8, size_utf8); + return string_utf8; +} + +#define G_OBJECT_NAME(object) G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object)) + +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; + GParamSpec** pspecs = g_object_class_list_properties ( + G_OBJECT_GET_CLASS (object), &n); + gint i; + for (i = 0; i < n; i++) + { + const gchar* property = g_param_spec_get_name (pspecs[i]); + JSStringRef js_property = JSStringCreateWithUTF8CString (property); + JSPropertyNameAccumulatorAddName (js_properties, js_property); + JSStringRelease (js_property); + } + GType type = G_OBJECT_TYPE (object); + do + { + guint* signals = g_signal_list_ids (type, &n); + for (i = 0; i < n; i++) + { + const gchar* signal = g_signal_name (signals[i]); + JSStringRef js_signal = JSStringCreateWithUTF8CString (signal); + JSPropertyNameAccumulatorAddName (js_properties, js_signal); + JSStringRelease (js_signal); + } + type = g_type_parent (type); + } + while (type); + } +} + +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_signal_lookup (property, G_OBJECT_TYPE (object)) || + 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 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); + const gchar* function = JSObjectGetPrivate (js_function); + + g_return_val_if_fail (G_IS_OBJECT (object), JSValueMakeNull (js_context)); + g_return_val_if_fail (function, JSValueMakeNull (js_context)); + + guint signal_id = g_signal_lookup (function, G_OBJECT_TYPE (object)); + GSignalQuery query; + g_signal_query (signal_id, &query); + GValue* values = g_new0 (GValue, n_arguments + 1); + g_value_init (&values[0], G_OBJECT_TYPE (object)); + g_value_set_instance (&values[0], object); + gint i; + for (i = 0; i < n_arguments; i++) + { + GValue value = {0, }; + GType gtype; + switch (JSValueGetType (js_context, js_arguments[i])) + { + case kJSTypeBoolean: + gtype = G_TYPE_BOOLEAN; + g_value_init (&value, gtype); + g_value_set_boolean (&value, + JSValueToBoolean (js_context, js_arguments[i]) ? TRUE : FALSE); + break; + case kJSTypeNumber: + gtype = G_TYPE_DOUBLE; + g_value_init (&value, gtype); + g_value_set_double (&value, + JSValueToNumber (js_context, js_arguments[i], NULL)); + break; + case kJSTypeString: + gtype = G_TYPE_STRING; + g_value_init (&value, gtype); + JSStringRef js_string = JSValueToStringCopy (js_context, + js_arguments[i], NULL); + gchar* string = gjs_string_utf8 (js_string); + g_value_set_string (&value, string); + g_free (string); + JSStringRelease (js_string); + break; + case kJSTypeObject: + gtype = G_TYPE_OBJECT; + g_value_init (&value, gtype); + JSObjectRef js_object = JSValueToObject (js_context, + js_arguments[i], NULL); + GObject* object_value = JSObjectGetPrivate (js_object); + g_value_set_object (&value, object_value); + break; + case kJSTypeUndefined: + case kJSTypeNull: + default: + gtype = G_TYPE_NONE; + g_value_init (&value, gtype); + } + g_value_init (&values[i + 1], gtype); + if (query.n_params >= i + && g_value_type_compatible (gtype, query.param_types[i])) + /* && g_value_type_transformable (gtype, query.param_types[i]) */ + g_value_copy (&value, &values[i + 1]); + /* g_value_transform (&value, &values[i + 1]); */ + else + { + gchar* value_type = g_strdup_value_contents (&value); + /* FIXME: exception */ + g_print ("wrong value, expected %s\n", value_type); + g_free (value_type); + } + g_value_unset (&value); + } + GValue return_value = {0, }; + if (query.return_type != G_TYPE_NONE) + g_value_init (&return_value, query.return_type); + g_signal_emitv (values, signal_id, 0, &return_value); + + for (i = 0; i < n_arguments; i++) + g_value_unset (&values[i]); + /* FIXME: return value */ + 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); +}*/ + +static JSValueRef +_js_class_get_property_cb (JSContextRef js_context, + JSObjectRef js_object, + JSStringRef js_property, + JSValueRef* js_exception) +{ + GObject* object = JSObjectGetPrivate (js_object); + + g_return_val_if_fail (G_IS_OBJECT (object), JSValueMakeNull (js_context)); + + JSValueRef js_result = NULL; + gchar* property = gjs_string_utf8 (js_property); + guint signal_id; + GParamSpec* pspec; + if ((signal_id = g_signal_lookup (property, G_OBJECT_TYPE (object)))) + { + GSignalQuery query; + g_signal_query (signal_id, &query); + if (query.signal_flags & G_SIGNAL_ACTION) + { + /* We can't use JSObjectMakeFunctionWithCallback + because it doesn't allocate private data */ + JSClassDefinition js_class_def = kJSClassDefinitionEmpty; + js_class_def.className = g_strdup (property); + js_class_def.callAsFunction = _js_object_call_as_function_cb; + JSClassRef js_class = JSClassCreate (&js_class_def); + JSObjectRef js_function = JSObjectMake (js_context, + js_class, property); + return js_function; + } + g_free (property); + return JSValueMakeNull (js_context); + } + else if (!(pspec = g_object_class_find_property ( + G_OBJECT_GET_CLASS (object), property))) + { + 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, + G_OBJECT_NAME (value), 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 void +_js_class_signal_callback (GObject* object, ...) +{ + /* FIXME: Support arbitrary signatures */ + + /* FIXME: Support arbitrary return values */ +} + +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); + + g_return_val_if_fail (G_IS_OBJECT (object), false); + + bool result = false; + gchar* property = gjs_string_utf8 (js_property); + guint signal_id; + GParamSpec* pspec; + if ((signal_id = g_signal_lookup (property, G_OBJECT_TYPE (object)))) + { + g_signal_connect (object, property, + G_CALLBACK (_js_class_signal_callback), (gpointer)js_value); + g_free (property); + return true; + } + else if (!(pspec = g_object_class_find_property ( + G_OBJECT_GET_CLASS (object), property))) + { + 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 (G_IS_OBJECT (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; +} + +JSObjectRef +gjs_object_new (JSContextRef js_context, + const gchar* name, + gpointer instance) +{ + g_return_val_if_fail (js_context, NULL); + g_return_val_if_fail (name, NULL); + + JSClassDefinition js_class_def = kJSClassDefinitionEmpty; + js_class_def.className = g_strdup (name); + 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); + return js_object; +} + +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) +{ + const gchar* type_name = JSObjectGetPrivate (js_object); + + g_return_val_if_fail (type_name, NULL); + + GType type = g_type_from_name (type_name); + if (type) + return gjs_object_new (js_context, type_name, g_object_new (type, NULL)); + return NULL; +} + +static bool +_js_module_has_property_cb (JSContextRef js_context, + JSObjectRef js_object, + JSStringRef js_property) +{ + const gchar* namespace = JSObjectGetPrivate (js_object); + + g_return_val_if_fail (namespace, false); + + gchar* property = gjs_string_utf8 (js_property); + gchar* type_name = g_strdup_printf ("%s%s", namespace, property); + + GType type = g_type_from_name (type_name); + if (!type) + { + GModule* module = g_module_open (NULL, + G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + typedef GType (*gjs_get_type_func)(void); + /* FIXME: Insert a space between each capital letter */ + gchar* type_func_name = g_strdup_printf ("%s_%s_get_type", + namespace, property); + gchar* type_func_name_small = g_utf8_strdown (type_func_name, -1); + gjs_get_type_func type_func; + if (g_module_symbol (module, + (const gchar*)type_func_name_small, (gpointer*)&type_func)) + { + type = type_func (); + g_type_class_peek (type); + } + g_free (type_func_name_small); + g_free (type_func_name); + g_module_close (module); + } + bool result = type ? true : false; + g_free (type_name); + g_free (property); + return result; +} + +static JSValueRef +_js_module_get_property_cb (JSContextRef js_context, + JSObjectRef js_object, + JSStringRef js_property, + JSValueRef* js_exception) +{ + const gchar* namespace = JSObjectGetPrivate (js_object); + + g_return_val_if_fail (namespace, JSValueMakeNull (js_context)); + + gchar* property = gjs_string_utf8 (js_property); + gchar* type_name = g_strdup_printf ("%s%s", namespace, property); + GType type = g_type_from_name (type_name); + JSValueRef result; + if (type) + { + JSClassDefinition js_class_def = kJSClassDefinitionEmpty; + js_class_def.className = g_strdup (type_name); + js_class_def.callAsConstructor = _js_object_call_as_constructor_cb; + JSClassRef js_class = JSClassCreate (&js_class_def); + result = JSObjectMake (js_context, js_class, type_name); + } + else + { + result = JSValueMakeNull (js_context); + g_free (type_name); + } + g_free (property); + return result; +} + +JSObjectRef +gjs_module_new (JSContextRef js_context, + const gchar* namespace) +{ + g_return_val_if_fail (js_context, NULL); + g_return_val_if_fail (namespace, NULL); + + JSClassDefinition js_class_def = kJSClassDefinitionEmpty; + js_class_def.className = g_strdup (namespace); + js_class_def.hasProperty = _js_module_has_property_cb; + js_class_def.getProperty = _js_module_get_property_cb; + JSClassRef js_class = JSClassCreate (&js_class_def); + JSObjectRef js_module = JSObjectMake (js_context, js_class, + (gpointer)namespace); + return js_module; +} + +JSGlobalContextRef +gjs_global_context_new (void) +{ + #ifdef WEBKIT_CHECK_VERSION + #if WEBKIT_CHECK_VERSION (1, 0, 3) + JSGlobalContextRef js_context = JSGlobalContextCreateInGroup (NULL, NULL); + #else + JSGlobalContextRef js_context = JSGlobalContextCreate (NULL); + #endif + #endif + JSObjectRef js_object = gjs_object_new (js_context, "GJS", NULL); + _js_object_set_property (js_context, JSContextGetGlobalObject (js_context), + "gjs", js_object); + + js_object = gjs_module_new (js_context, "Gtk"); + _js_object_set_property (js_context, JSContextGetGlobalObject (js_context), + "Gtk", js_object); + js_object = gjs_module_new (js_context, "WebKit"); + _js_object_set_property (js_context, JSContextGetGlobalObject (js_context), + "WebKit", js_object); + js_object = gjs_module_new (js_context, "Midori"); + _js_object_set_property (js_context, JSContextGetGlobalObject (js_context), + "Midori", js_object); + return js_context; +} diff --git a/gjs/gjs.h b/gjs/gjs.h new file mode 100644 index 0000000..19bf4d4 --- /dev/null +++ b/gjs/gjs.h @@ -0,0 +1,128 @@ +/* + 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 + +#define GJS_TYPE_VALUE \ + (gjs_value_get_type ()) +#define GJS_VALUE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GJS_TYPE_VALUE, GjsValue)) +#define GJS_VALUE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GJS_TYPE_VALUE, GjsValueClass)) +#define GJS_IS_VALUE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GJS_TYPE_VALUE)) +#define GJS_IS_VALUE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GJS_TYPE_VALUE)) +#define GJS_VALUE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GJS_TYPE_VALUE, GjsValueClass)) + +typedef struct _GjsValue GjsValue; +typedef struct _GjsValueClass GjsValueClass; + +struct _GjsValueClass +{ + GObjectClass parent_class; +}; + +GType +gjs_value_get_type (void); + +GjsValue* +gjs_value_new (JSContextRef js_context, + JSValueRef js_value); + +gboolean +gjs_value_is_valid (GjsValue* value); + +gboolean +gjs_value_is_object (GjsValue* value); + +gboolean +gjs_value_has_attribute (GjsValue* value, + const gchar* name); + +GjsValue* +gjs_value_get_attribute (GjsValue* value, + const gchar* name); + +const gchar* +gjs_value_get_string (GjsValue* value); + +const gchar* +gjs_value_get_attribute_string (GjsValue* value, + const gchar* name); + +GjsValue* +gjs_value_get_nth_attribute (GjsValue* value, + guint n); + +typedef void +(*GjsCallback) (GjsValue* value, + gpointer user_data); + +void +gjs_value_foreach (GjsValue* value, + GjsCallback callback, + gpointer user_data); + +void +gjs_value_forall (GjsValue* value, + GjsCallback callback, + gpointer user_data); + +GjsValue* +gjs_value_get_by_name (GjsValue* value, + const gchar* name); + +GjsValue* +gjs_value_get_elements_by_tag_name (GjsValue* value, + const gchar* name); + +GjsValue* +gjs_value_execute (GjsValue* value, + const gchar* script, + gchar** exception); + +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, + const gchar* name, + gpointer instance); + +JSGlobalContextRef +gjs_global_context_new (void); + +G_END_DECLS + +#endif /* __GJS_H__ */ diff --git a/javascriptcore/javascriptcore_types.c b/javascriptcore/javascriptcore_types.c index 6765750..1d2980c 100644 --- a/javascriptcore/javascriptcore_types.c +++ b/javascriptcore/javascriptcore_types.c @@ -34,3 +34,33 @@ PyObject* wrap_JSGlobalContextRef(JSGlobalContextRef jsglobalref) "JSGlobalContextRef", NULL); return (ret); } + +PyObject* wrap_JSContextRef(JSContextRef jsglobalref) +{ + PyObject *ret; + + if (jsglobalref == NULL) { + Py_INCREF (Py_None); + return (Py_None); + } + + ret = PyCObject_FromVoidPtrAndDesc ((void *) jsglobalref, (char *) + "JSContextRef", NULL); + return (ret); +} + +#ifdef HAVE_GJS +PyObject* wrap_GjsValue(GjsValue *value) +{ + PyObject *ret; + + if (value == NULL) { + Py_INCREF (Py_None); + return (Py_None); + } + + ret = PyCObject_FromVoidPtrAndDesc ((void *) value, (char *) + "GjsValue", NULL); + return (ret); +} +#endif diff --git a/javascriptcore/javascriptcore_types.h b/javascriptcore/javascriptcore_types.h index a66d8b8..672bc76 100644 --- a/javascriptcore/javascriptcore_types.h +++ b/javascriptcore/javascriptcore_types.h @@ -22,17 +22,37 @@ #undef _POSIX_C_SOURCE #include - #include +#ifdef HAVE_GJS +#include "gjs/gjs.h" + +typedef struct { + PyObject_HEAD + GjsValue *obj; +} GjsValueRef_object; + +#define GjsValue_get(v) (((v) == Py_None) ? NULL : (((GjsValue_object *)(PyObject_GetAttr(v,PyString_FromString("_o"))))->obj)); + +PyObject* wrap_GjsValue(GjsValue *value); +#endif /* End HAVE_GJS */ + +typedef struct { + PyObject_HEAD + JSContextRef obj; +} JSContextRef_object; + typedef struct { PyObject_HEAD JSGlobalContextRef obj; } JSGlobalContextRef_object; /* Functions to wrap JavaScriptCore Python objects -> JavaScriptCore C objects */ +#define JSContextRef_get(v) (((v) == Py_None) ? NULL : (((JSContextRef_object *)(PyObject_GetAttr(v,PyString_FromString("_o"))))->obj)); + #define JSGlobalContextRef_get(v) (((v) == Py_None) ? NULL : (((JSGlobalContextRef_object *)(PyObject_GetAttr(v,PyString_FromString("_o"))))->obj)); +PyObject* wrap_JSContextRef(JSContextRef jscontextref); PyObject* wrap_JSGlobalContextRef(JSGlobalContextRef jsglobalref); #endif /* PYWEBKITGTK_WRAP_JSC_H */ diff --git a/webkit.override b/webkit.override index 3447dc9..75914eb 100644 --- a/webkit.override +++ b/webkit.override @@ -22,7 +22,7 @@ %% headers #include -#define NO_IMPORT +#define NO_IMPORT_PYGOBJECT #include #include #include @@ -110,8 +110,8 @@ _wrap_webkit_web_back_forward_list_get_forward_list_with_limit (PyGObject *self, int limit; if (! PyArg_ParseTupleAndKeywords (args, kwargs, "i:WebBackForwardList.get_forward_list_with_limit", kwlist, &limit)) - return NULL; - + return NULL; + list = webkit_web_back_forward_list_get_forward_list_with_limit(WEBKIT_WEB_BACK_FORWARD_LIST(self->obj), limit); return _helper_wrap_gobject_glist (list); diff --git a/webkitmodule.c b/webkitmodule.c index af66223..88c58e9 100644 --- a/webkitmodule.c +++ b/webkitmodule.c @@ -30,6 +30,11 @@ extern PyMethodDef pywebkit_functions[]; void pywebkit_register_classes (PyObject *d); +#ifdef HAVE_GJS +extern PyMethodDef pygjs_functions[]; +void pygjs_register_classes (PyObject *d); +#endif + DL_EXPORT(void) initwebkit(void) { @@ -42,13 +47,20 @@ initwebkit(void) init_pygtk(); + /* webkit module */ m = Py_InitModule ("webkit", pywebkit_functions); d = PyModule_GetDict (m); - pywebkit_register_classes (d); +#ifdef HAVE_GJS + /* webkit.gjs module */ + m = Py_InitModule ("webkit.gjs", pygjs_functions); + d = PyModule_GetDict(m); + pygjs_register_classes (d); +#endif + if (PyErr_Occurred ()) { PyErr_Print(); - Py_FatalError ("can't initialise module webkit"); + Py_FatalError ("can't initialise module webkit.gjs"); } } -- 2.11.4.GIT