From dc90c7f093b810c16bad5430e24b70d1b2939b78 Mon Sep 17 00:00:00 2001 From: Arno Renevier Date: Tue, 30 Mar 2010 22:44:04 +0200 Subject: [PATCH] Use midori_view_get_web_view in extensions --- extensions/adblock.c | 4 +- extensions/formhistory.c | 4 +- extensions/javascript.c | 327 ++++++++++++++++++++++++++++++++++++ extensions/mouse-gestures.c | 4 +- extensions/tab-switcher.c | 3 +- 5 files changed, 335 insertions(+), 7 deletions(-) create mode 100644 extensions/javascript.c diff --git a/extensions/adblock.c b/extensions/adblock.c index 5d9847e2..6112a946 100644 --- a/extensions/adblock.c +++ b/extensions/adblock.c @@ -935,7 +935,7 @@ adblock_add_tab_cb (MidoriBrowser* browser, MidoriView* view, MidoriExtension* extension) { - GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view)); + GtkWidget* web_view = midori_view_get_web_view (view); #if HAVE_WEBKIT_RESOURCE_REQUEST GtkWidget* image = g_object_get_data (G_OBJECT (browser), "status-image"); #endif @@ -1282,7 +1282,7 @@ adblock_deactivate_tabs (MidoriView* view, MidoriBrowser* browser, MidoriExtension* extension) { - GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view)); + GtkWidget* web_view = midori_view_get_web_view (view); #if HAVE_WEBKIT_RESOURCE_REQUEST GtkWidget* image = g_object_get_data (G_OBJECT (browser), "status-image"); #endif diff --git a/extensions/formhistory.c b/extensions/formhistory.c index 9b33300e..f0790af8 100644 --- a/extensions/formhistory.c +++ b/extensions/formhistory.c @@ -306,7 +306,7 @@ formhistory_add_tab_cb (MidoriBrowser* browser, MidoriView* view, MidoriExtension* extension) { - GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view)); + GtkWidget* web_view = midori_view_get_web_view (view); g_signal_connect (web_view, "window-object-cleared", G_CALLBACK (formhistory_window_object_cleared_cb), NULL); #if WEBKIT_CHECK_VERSION (1, 1, 4) @@ -348,7 +348,7 @@ formhistory_deactivate_tabs (MidoriView* view, MidoriBrowser* browser, MidoriExtension* extension) { - GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view)); + GtkWidget* web_view = midori_view_get_web_view (view); g_signal_handlers_disconnect_by_func ( web_view, formhistory_window_object_cleared_cb, NULL); #if WEBKIT_CHECK_VERSION (1, 1, 4) diff --git a/extensions/javascript.c b/extensions/javascript.c new file mode 100644 index 00000000..2b41756a --- /dev/null +++ b/extensions/javascript.c @@ -0,0 +1,327 @@ +/* + Copyright (C) 2009 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. +*/ + +/* +midori.tabs +midori.windows +midori.currentWindow +midori.createAction({name:'Example',label:'_Example',icon:'gtk-info',tooltip:'Examples',activate:function()}) +action = midori.currentWindow.getAction(name) +foreach (window as midori.windows) window.getAction('myaction').activate() +midori.window[i].tabs +midori.addWindow +midori.addTab +midori.removeWindow +midori.removeTab +*/ + +#if HAVE_CONFIG_H + #include +#endif + +#include +#include +#include + +gchar* +sokoke_js_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; +} + +static void +javascript_deactivate_cb (MidoriExtension* extension, + MidoriBrowser* browser) +{ + /* FIXME: Unload all javascript extensions */ +} + +static JSValueRef +midori_javascript_midori_action_cb (JSContextRef js_context, + JSObjectRef js_function, + JSObjectRef js_this, + size_t n_arguments, + const JSValueRef js_arguments[], + JSValueRef* js_exception) +{ + GtkAction* action; + JSObjectRef js_meta; + JSPropertyNameArrayRef js_properties; + size_t n_properties; + guint i; + MidoriApp* app; + + if (n_arguments != 1) + { + *js_exception = JSValueMakeString (js_context, + JSStringCreateWithUTF8CString ( + "MidoriError: Wrong number of arguments; 'midori.createAction ({property:value, ...})'")); + return JSValueMakeNull (js_context); + } + + if (!JSValueIsObject (js_context, js_arguments[0])) + { + *js_exception = JSValueMakeString (js_context, + JSStringCreateWithUTF8CString ( + "MidoriError: Argument is not an object; 'midori.createAction ({property:value, ...})'")); + return JSValueMakeNull (js_context); + } + + action = g_object_new (GTK_TYPE_ACTION, NULL); + js_meta = JSValueToObject (js_context, js_arguments[0], NULL); + js_properties = JSObjectCopyPropertyNames (js_context, js_meta); + n_properties = JSPropertyNameArrayGetCount (js_properties); + for (i = 0; i < n_properties; i++) + { + JSStringRef js_name; + gchar* name; + JSValueRef js_property; + JSStringRef js_string; + gchar* string; + + js_name = JSPropertyNameArrayGetNameAtIndex (js_properties, i); + name = sokoke_js_string_utf8 (js_name); + if (g_str_equal (name, "label")) + { + js_property = JSObjectGetProperty (js_context, js_meta, js_name, NULL); + js_string = JSValueToStringCopy (js_context, js_property, NULL); + string = sokoke_js_string_utf8 (js_string); + JSStringRelease (js_string); + g_object_set (action, "label", string, NULL); + g_free (string); + } + else if (g_str_equal (name, "icon")) + { + js_property = JSObjectGetProperty (js_context, js_meta, js_name, NULL); + js_string = JSValueToStringCopy (js_context, js_property, NULL); + string = sokoke_js_string_utf8 (js_string); + JSStringRelease (js_string); + /* FIXME: stock-id, or icon-name, or URI */ + g_object_set (action, "stock-id", string, NULL); + g_free (string); + } + else if (g_str_equal (name, "tooltip")) + { + js_property = JSObjectGetProperty (js_context, js_meta, js_name, NULL); + js_string = JSValueToStringCopy (js_context, js_property, NULL); + string = sokoke_js_string_utf8 (js_string); + JSStringRelease (js_string); + g_object_set (action, "tooltip", string, NULL); + g_free (string); + } + else if (g_str_equal (name, "activate")) + { + /* FIXME */ + } + else + { + *js_exception = JSValueMakeString (js_context, + JSStringCreateWithUTF8CString ( + "MidoriError: Unknown property; 'midori.createAction ({property:value, ...})'")); + return JSValueMakeNull (js_context); + } + } + + if ((app = JSObjectGetPrivate (js_this))) + { + /* TODO: Offer the user to add a toolbar button */ + } + /* TODO: add action to all existing and future browsers */ + /* gtk_action_connect_accelerator */ + return JSValueMakeNull (js_context); +} + +static JSContextRef +midori_javascript_context (MidoriApp* app) +{ + JSContextRef js_context = JSGlobalContextCreateInGroup (NULL, NULL); + JSClassDefinition js_class_def = kJSClassDefinitionEmpty; + JSClassRef js_class; + JSObjectRef js_object; + JSStringRef js_name; + JSStaticFunction functions[] = { + { "createAction", midori_javascript_midori_action_cb, kJSPropertyAttributeNone }, + { NULL, NULL, 0 } + }; + + js_class_def.className = "midori"; + js_class_def.staticFunctions = functions; + js_class = JSClassCreate (&js_class_def); + js_object = JSObjectMake (js_context, js_class, app); + + js_name = JSStringCreateWithUTF8CString ("midori"); + JSObjectSetProperty (js_context, JSContextGetGlobalObject (js_context), + js_name, js_object, kJSPropertyAttributeNone, NULL); + JSStringRelease (js_name); + + return js_context; +} + +static void +midori_javascript_extension_activate_cb (MidoriExtension* extension, + MidoriApp* app) +{ + gchar* filename = g_object_get_data (G_OBJECT (extension), "filename"); + gchar* fullname = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (), + PACKAGE_NAME, "extensions", filename, NULL); + gchar* script; + GError* error = NULL; + if (g_file_get_contents (fullname, &script, NULL, &error)) + { + JSContextRef js_context = midori_javascript_context (app); + gchar* exception = NULL; + g_free (sokoke_js_script_eval (js_context, script, &exception)); + if (exception) + { + g_object_set (extension, "description", + exception, "version", NULL, NULL); + g_warning ("%s", exception); + g_free (exception); + } + } + else + { + g_object_set (extension, "description", + error->message, "version", NULL, NULL); + g_warning ("%s", error->message); + g_error_free (error); + } + g_free (fullname); + g_free (script); +} + +static void +javascript_load_extensions (gchar** active, + MidoriApp* app, + const gchar* path) +{ + GDir* dir; + + /* TODO: Monitor folder for new files or modifications at runtime */ + if ((dir = g_dir_open (path, 0, NULL))) + { + KatzeArray* extensions = katze_object_get_object (app, "extensions"); + JSContextRef js_context = midori_javascript_context (app); + const gchar* filename; + + while ((filename = g_dir_read_name (dir))) + { + gchar* fullname; + GError* error; + gchar* script; + MidoriExtension* extension; + + /* Ignore files which don't have the correct suffix */ + if (!g_str_has_suffix (filename, ".js")) + continue; + + fullname = g_build_filename (path, filename, NULL); + error = NULL; + extension = g_object_new (MIDORI_TYPE_EXTENSION, "name", filename, NULL); + if (g_file_get_contents (fullname, &script, NULL, &error)) + { + JSStringRef js_script; + JSValueRef js_exception; + + js_script = JSStringCreateWithUTF8CString (script); + if (JSCheckScriptSyntax (js_context, js_script, NULL, + 0, &js_exception)) + { + /* FIXME: Read meta data from .js file */ + g_object_set (extension, "description", "", + "version", "0.1", "authors", "", NULL); + /* Signal that we want the extension to load and save */ + g_object_set_data_full (G_OBJECT (extension), "filename", + g_strdup (filename), g_free); + if (midori_extension_is_prepared (extension)) + midori_extension_get_config_dir (extension); + g_signal_connect (extension, "activate", + G_CALLBACK (midori_javascript_extension_activate_cb), NULL); + } + else + { + JSStringRef js_string = JSValueToStringCopy (js_context, + js_exception, NULL); + gchar* string = sokoke_js_string_utf8 (js_string); + JSStringRelease (js_string); + g_object_set (extension, "description", string, NULL); + g_warning ("%s", string); + g_free (string); + } + } + else + { + g_object_set (extension, "description", error->message, NULL); + g_warning ("%s", error->message); + g_error_free (error); + } + g_free (fullname); + katze_array_add_item (extensions, extension); + if (active) + { + guint i = 0; + gchar* name; + while ((name = active[i++])) + if (!g_strcmp0 (filename, name)) + g_signal_emit_by_name (extension, "activate", app); + } + /* FIXME main.c needs to monitor extensions + g_signal_connect_after (extension, "activate", + G_CALLBACK (extension_activate_cb), app); + g_signal_connect_after (extension, "deactivate", + G_CALLBACK (extension_activate_cb), app); */ + g_object_unref (extension); + } + g_object_unref (extensions); + g_dir_close (dir); + } +} + +static void +javascript_activate_cb (MidoriExtension* extension, + MidoriApp* app) +{ + gchar** active = midori_extension_get_string_list (extension, "extensions", NULL); + /* FIXME Scan system data dirs */ + gchar* path = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (), + PACKAGE_NAME, "extensions", NULL); + javascript_load_extensions (active, app, path); + g_free (path); + g_strfreev (active); + + g_signal_connect (extension, "deactivate", + G_CALLBACK (javascript_deactivate_cb), NULL); +} + +MidoriExtension* +extension_init (void) +{ + MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION, + "name", _("Javascript extensions"), + "description", _("Enable extensions written in Javascript"), + "version", "0.1", + "authors", "Christian Dywan ", + NULL); + midori_extension_install_string_list (extension, "extensions", NULL, G_MAXSIZE); + + g_signal_connect (extension, "activate", + G_CALLBACK (javascript_activate_cb), NULL); + + return extension; +} diff --git a/extensions/mouse-gestures.c b/extensions/mouse-gestures.c index eedaa572..be775588 100644 --- a/extensions/mouse-gestures.c +++ b/extensions/mouse-gestures.c @@ -190,7 +190,7 @@ mouse_gestures_add_tab_cb (MidoriBrowser* browser, MidoriView* view, MidoriExtension* extension) { - GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view)); + GtkWidget* web_view = midori_view_get_web_view (view); g_object_connect (web_view, "signal::button-press-event", @@ -231,7 +231,7 @@ static void mouse_gestures_deactivate_tabs (MidoriView* view, MidoriBrowser* browser) { - GtkWidget* web_view = gtk_bin_get_child (GTK_BIN (view)); + GtkWidget* web_view = midori_view_get_web_view (view); g_object_disconnect (web_view, "any_signal::button-press-event", diff --git a/extensions/tab-switcher.c b/extensions/tab-switcher.c index d4749e83..add09df1 100644 --- a/extensions/tab-switcher.c +++ b/extensions/tab-switcher.c @@ -25,7 +25,8 @@ static GdkPixbuf* tab_selector_get_snapshot(MidoriView* view, gfloat factor; g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL); - web_view = gtk_bin_get_child (GTK_BIN (view)); + + web_view = midori_view_get_web_view (view); if(maxwidth < 0) { maxwidth *= -1;