Use JavaScriptCore for evaluation, with Uzbl.run()
authorDequis <dx@dxzone.com.ar>
Mon, 15 Jun 2009 23:37:55 +0000 (20:37 -0300)
committerDequis <dx@dxzone.com.ar>
Mon, 15 Jun 2009 23:37:55 +0000 (20:37 -0300)
Both "js" and "script" commands use eval_js(), which creates an instance
of the Uzbl object class (created by js_init()) which right now provides
only a run() method (handled by js_run_command()). After evaluating the
code, eval_js() removes the object so the scripts from the loaded page
can't access it.

eval_js() supports returning a string result, and you can use it with
uzblctrl to query the DOM. Uzbl.run() also returns a string, but the
only useful thing you can do right now with that is to print @uri or
other variables.

uzbl.c
uzbl.h

diff --git a/uzbl.c b/uzbl.c
index 8500d9e..a596b0e 100644 (file)
--- a/uzbl.c
+++ b/uzbl.c
@@ -45,6 +45,7 @@
 #include <sys/time.h>
 #include <webkit/webkit.h>
 #include <libsoup/soup.h>
+#include <JavaScriptCore/JavaScript.h>
 
 #include <stdio.h>
 #include <string.h>
@@ -760,12 +761,106 @@ load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
     }
 }
 
+
+/* Javascript*/
+
+static JSValueRef
+js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject,
+                size_t argumentCount, const JSValueRef arguments[],
+                JSValueRef* exception) {
+    (void) function;
+    (void) thisObject;
+    (void) exception;
+    
+    JSStringRef js_result_string;
+    GString *result = g_string_new("");
+
+    if (argumentCount >= 1) {
+        JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL);
+        size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg);
+        char ctl_line[arg_size];
+        JSStringGetUTF8CString(arg, ctl_line, arg_size);
+
+        parse_cmd_line(ctl_line, result);
+
+        JSStringRelease(arg);
+    }
+    js_result_string = JSStringCreateWithUTF8CString(result->str);
+
+    g_string_free(result, TRUE);
+
+    return JSValueMakeString(ctx, js_result_string);
+}
+
+static JSStaticFunction js_static_functions[] = {
+    {"run", js_run_command, kJSPropertyAttributeNone},
+};
+
+static void
+js_init() {
+    /* This function creates the class and its definition, only once */
+    if (!uzbl.js.initialized) {
+        /* it would be pretty cool to make this dynamic */
+        uzbl.js.classdef = kJSClassDefinitionEmpty;
+        uzbl.js.classdef.staticFunctions = js_static_functions;
+
+        uzbl.js.classref = JSClassCreate(&uzbl.js.classdef);
+    }
+}
+
+
+static void 
+eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
+    WebKitWebFrame *frame;
+    JSGlobalContextRef context;
+    JSObjectRef globalobject;
+    JSStringRef var_name;
+
+    JSStringRef js_script;
+    JSValueRef js_result;
+    JSStringRef js_result_string;
+    size_t js_result_size;
+    
+    js_init();
+
+    frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view));
+    context = webkit_web_frame_get_global_context(frame);
+    globalobject = JSContextGetGlobalObject(context);
+    
+    /* uzbl javascript namespace */
+    var_name = JSStringCreateWithUTF8CString("Uzbl");
+    JSObjectSetProperty(context, globalobject, var_name,
+                        JSObjectMake(context, uzbl.js.classref, NULL),  
+                        kJSClassAttributeNone, NULL);
+    
+    /* evaluate the script and get return value*/ 
+    js_script = JSStringCreateWithUTF8CString(script);
+    js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL);
+    if (js_result && !JSValueIsUndefined(context, js_result)) {
+        js_result_string = JSValueToStringCopy(context, js_result, NULL);
+        js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
+
+        if (js_result_size) {
+            char js_result_utf8[js_result_size];
+            JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size);
+            g_string_assign(result, js_result_utf8);
+        }
+
+        JSStringRelease(js_result_string);
+    }
+
+    /* cleanup */
+    JSObjectDeleteProperty(context, globalobject, var_name, NULL);
+
+    JSStringRelease(var_name);
+    JSStringRelease(js_script);
+}
+
 static void
 run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
-    (void) result;
-    /* TODO: result! */
+
     if (argv_idx(argv, 0))
-        webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
+        eval_js(web_view, argv_idx(argv, 0), result);
 }
 
 static void
@@ -796,7 +891,7 @@ run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
             g_free (js);
             js = newjs;
         }
-        webkit_web_view_execute_script (web_view, js);
+        eval_js (web_view, js, result);
         g_free (js);
         g_array_free (lines, TRUE);
     }
diff --git a/uzbl.h b/uzbl.h
index 2b36edd..2cf0346 100644 (file)
--- a/uzbl.h
+++ b/uzbl.h
@@ -176,6 +176,12 @@ typedef struct {
     GHashTable* commands;
 } Behaviour;
 
+/* javascript */
+typedef struct {
+    gboolean            initialized;
+    JSClassDefinition   classdef;
+    JSClassRef          classref;
+} Javascript;
 
 /* main uzbl data structure */
 typedef struct {
@@ -184,6 +190,7 @@ typedef struct {
     Network       net;
     Behaviour     behave;
     Communication comm;
+    Javascript    js;
 
     Window        xwin;
     GScanner      *scan;
@@ -458,6 +465,9 @@ static void
 dehilight (WebKitWebView *page, GArray *argv, GString *result);
 
 static void
+eval_js(WebKitWebView * web_view, gchar *script, GString *result);
+
+static void
 run_js (WebKitWebView * web_view, GArray *argv, GString *result);
 
 static void