From 133cd688b96642e935ed060d9a6febb87ad48c2d Mon Sep 17 00:00:00 2001 From: Christian Dywan Date: Mon, 28 Apr 2008 22:38:57 +0200 Subject: [PATCH] Initial addon panel feature, only userscripts for now. --- katze/katze-utils.h | 9 + src/Makefile.am | 3 +- src/main.c | 50 ++--- src/midori-addons.c | 500 +++++++++++++++++++++++++++++++++++++++++++ src/midori-addons.h | 75 +++++++ src/midori-browser.c | 129 ++++++++++- src/midori-browser.h | 11 + src/midori-console.c | 18 +- 8 files changed, 750 insertions(+), 45 deletions(-) create mode 100644 src/midori-addons.c create mode 100644 src/midori-addons.h diff --git a/katze/katze-utils.h b/katze/katze-utils.h index c42267d6..6ff7b863 100644 --- a/katze/katze-utils.h +++ b/katze/katze-utils.h @@ -16,6 +16,15 @@ G_BEGIN_DECLS +/** + * KATZE_OBJECT_NAME: + * @object: an object + * + * Return the name of an object's class structure's type. + **/ +#define KATZE_OBJECT_NAME(object) \ + G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object)) + /** * katze_assign: * @lvalue: a pointer diff --git a/src/Makefile.am b/src/Makefile.am index 042ef9be..82208d26 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,9 +17,10 @@ bin_PROGRAMS = \ midori midori_SOURCES = \ - main.c main.h \ + main.c main.h \ midori-browser.c midori-browser.h \ midori-panel.c midori-panel.h \ + midori-addons.c midori-addons.h \ midori-console.c midori-console.h \ midori-trash.c midori-trash.h \ midori-webview.c midori-webview.h \ diff --git a/src/main.c b/src/main.c index 1933c254..884e30ab 100644 --- a/src/main.c +++ b/src/main.c @@ -253,20 +253,21 @@ settings_save_to_file (MidoriWebSettings* settings, enum_value->value_name); } else - g_warning ("Unhandled settings property '%s'", property); + g_warning (_("Unhandled settings property '%s'"), property); } gboolean saved = sokoke_key_file_save_to_file (key_file, filename, error); g_key_file_free (key_file); return saved; } -int main(int argc, char** argv) +int +main (int argc, char** argv) { MidoriStartup load_on_startup; gchar* homepage; - locale_init(); - g_set_application_name(_("midori")); + locale_init (); + g_set_application_name (_("midori")); // Parse cli options gboolean version = FALSE; @@ -278,15 +279,16 @@ int main(int argc, char** argv) }; GError* error = NULL; - if(!gtk_init_with_args(&argc, &argv, _("[URL]"), entries, GETTEXT_PACKAGE, &error)) + if (!gtk_init_with_args (&argc, &argv, _("[URL]"), entries, + GETTEXT_PACKAGE, &error)) { - g_error_free(error); + g_error_free (error); return 1; } - if(version) + if (version) { - g_print( + g_print ( "%s %s - Copyright (c) 2007-2008 Christian Dywan\n\n" "GTK+2: \t\t%s\n" "WebKit: \t\t%s\n" @@ -403,17 +405,17 @@ int main(int argc, char** argv) // TODO: Handle any number of separate uris from argv // Open as many tabs as we have uris, seperated by pipes - gchar* uri = argc > 1 ? strtok(g_strdup(argv[1]), "|") : NULL; - while(uri != NULL) + gchar* uri = argc > 1 ? strtok (g_strdup(argv[1]), "|") : NULL; + while (uri != NULL) { - KatzeXbelItem* item = katze_xbel_bookmark_new(); - gchar* uriReady = sokoke_magic_uri (uri, NULL); - katze_xbel_bookmark_set_href(item, uriReady); - g_free(uriReady); - katze_xbel_folder_append_item(_session, item); - uri = strtok(NULL, "|"); + KatzeXbelItem* item = katze_xbel_bookmark_new (); + gchar* uri_ready = sokoke_magic_uri (uri, NULL); + katze_xbel_bookmark_set_href (item, uri_ready); + g_free (uri_ready); + katze_xbel_folder_append_item (_session, item); + uri = strtok (NULL, "|"); } - g_free(uri); + g_free (uri); if (katze_xbel_folder_is_empty (_session)) { @@ -484,8 +486,8 @@ int main(int argc, char** argv) error = NULL; if (!search_engines_to_file (searchEngines, config_file, &error)) { - g_warning("The search engines couldn't be saved. %s", error->message); - g_error_free(error); + g_warning (_("The search engines couldn't be saved. %s"), error->message); + g_error_free (error); } search_engines_free(searchEngines); g_free (config_file); @@ -493,8 +495,8 @@ int main(int argc, char** argv) error = NULL; if (!katze_xbel_folder_to_file (bookmarks, config_file, &error)) { - g_warning("The bookmarks couldn't be saved. %s", error->message); - g_error_free(error); + g_warning (_("The bookmarks couldn't be saved. %s"), error->message); + g_error_free (error); } katze_xbel_item_unref(bookmarks); g_free (config_file); @@ -502,7 +504,7 @@ int main(int argc, char** argv) error = NULL; if (!katze_xbel_folder_to_file (xbel_trash, config_file, &error)) { - g_warning ("The trash couldn't be saved. %s", error->message); + g_warning (_("The trash couldn't be saved. %s"), error->message); g_error_free (error); } katze_xbel_item_unref (xbel_trash); @@ -514,7 +516,7 @@ int main(int argc, char** argv) error = NULL; if (!katze_xbel_folder_to_file (session, config_file, &error)) { - g_warning ("The session couldn't be saved. %s", error->message); + g_warning (_("The session couldn't be saved. %s"), error->message); g_error_free (error); } } @@ -523,7 +525,7 @@ int main(int argc, char** argv) error = NULL; if (!settings_save_to_file (settings, config_file, &error)) { - g_warning ("The configuration couldn't be saved. %s", error->message); + g_warning (_("The configuration couldn't be saved. %s"), error->message); g_error_free (error); } katze_assign (config_file, g_build_filename (config_path, "accels", NULL)); diff --git a/src/midori-addons.c b/src/midori-addons.c new file mode 100644 index 00000000..0dd013f0 --- /dev/null +++ b/src/midori-addons.c @@ -0,0 +1,500 @@ +/* + 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 "config.h" + +#include "midori-addons.h" + +#include "sokoke.h" +#include +#include +#include + +G_DEFINE_TYPE (MidoriAddons, midori_addons, GTK_TYPE_VBOX) + +struct _MidoriAddonsPrivate +{ + MidoriAddonKind kind; + GtkWidget* toolbar; + GtkWidget* treeview; +}; + +#define MIDORI_ADDONS_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + MIDORI_TYPE_ADDONS, MidoriAddonsPrivate)) + +GType +midori_addon_kind_get_type (void) +{ + static GType type = 0; + if (!type) + { + static const GEnumValue values[] = { + { MIDORI_ADDON_EXTENSIONS, "MIDORI_ADDON_EXTENSIONS", N_("Extensions") }, + { MIDORI_ADDON_USER_SCRIPTS, "MIDORI_USER_SCRIPTS", N_("Userscripts") }, + { MIDORI_ADDON_USER_STYLES, "MIDORI_USER_STYLES", N_("Userstyles") }, + { 0, NULL, NULL } + }; + type = g_enum_register_static ("MidoriAddonKind", values); + } + return type; +} + +static void +midori_addons_class_init (MidoriAddonsClass* class) +{ + g_type_class_add_private (class, sizeof (MidoriAddonsPrivate)); +} + +static void +midori_addons_button_add_clicked_cb (GtkToolItem* toolitem, + MidoriAddons* addons) +{ + GtkWidget* dialog = gtk_message_dialog_new ( + gtk_widget_get_toplevel (GTK_WIDGET (addons)), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, + "Put scripts in the folder ~/.local/share/midori/scripts"); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); +} + +static void +midori_addons_treeview_render_icon_cb (GtkTreeViewColumn* column, + GtkCellRenderer* renderer, + GtkTreeModel* model, + GtkTreeIter* iter, + GtkWidget* treeview) +{ + // gchar* source_id; + // gtk_tree_model_get (model, iter, 2, &source_id, -1); + + g_object_set (renderer, "stock-id", GTK_STOCK_FILE, NULL); + + // g_free (source_id); +} + +static void +midori_addons_treeview_render_text_cb (GtkTreeViewColumn* column, + GtkCellRenderer* renderer, + GtkTreeModel* model, + GtkTreeIter* iter, + GtkWidget* treeview) +{ + gchar* filename; + gint a; + gchar* b; + gtk_tree_model_get (model, iter, 0, &filename, 1, &a, 2, &b, -1); + + // FIXME: Convert filename to UTF8 + gchar* text = g_strdup_printf ("%s", filename); + g_object_set (renderer, "text", text, NULL); + g_free (text); + + g_free (filename); + g_free (b); +} + +static void +midori_addons_treeview_row_activated_cb (GtkTreeView* treeview, + GtkTreePath* path, + GtkTreeViewColumn* column, + MidoriAddons* addons) +{ + /*GtkTreeModel* model = gtk_tree_view_get_model (treeview); + GtkTreeIter iter; + if (gtk_tree_model_get_iter (model, &iter, path)) + { + gchar* b; + gtk_tree_model_get (model, &iter, 2, &b, -1); + g_free (b); + }*/ +} + +static void +midori_addons_init (MidoriAddons* addons) +{ + addons->priv = MIDORI_ADDONS_GET_PRIVATE (addons); + + MidoriAddonsPrivate* priv = addons->priv; + + GtkTreeViewColumn* column; + GtkCellRenderer* renderer_text; + GtkCellRenderer* renderer_pixbuf; + priv->treeview = gtk_tree_view_new (); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->treeview), FALSE); + column = gtk_tree_view_column_new (); + renderer_pixbuf = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE); + gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf, + (GtkTreeCellDataFunc)midori_addons_treeview_render_icon_cb, + priv->treeview, NULL); + renderer_text = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer_text, FALSE); + gtk_tree_view_column_set_cell_data_func (column, renderer_text, + (GtkTreeCellDataFunc)midori_addons_treeview_render_text_cb, + priv->treeview, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (priv->treeview), column); + g_signal_connect (priv->treeview, "row-activated", + G_CALLBACK (midori_addons_treeview_row_activated_cb), + addons); + gtk_widget_show (priv->treeview); + gtk_box_pack_start (GTK_BOX (addons), priv->treeview, TRUE, TRUE, 0); +} + +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 bool +_js_class_has_property_cb (JSContextRef js_context, + JSObjectRef js_object, + JSStringRef js_property) +{ + GObject* object = JSObjectGetPrivate (js_object); + bool result = false; + if (object) + { + gchar* property = _js_string_utf8 (js_property); + if (g_object_class_find_property (G_OBJECT_GET_CLASS (object), + property)) + result = true; + g_free (property); + } + return result; +} + +static JSValueRef +_js_class_get_property_cb (JSContextRef js_context, + JSObjectRef js_object, + JSStringRef js_property, + JSValueRef* js_exception) +{ + 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); + } + GType type = G_PARAM_SPEC_TYPE (pspec); + if (type == G_TYPE_PARAM_STRING) + { + gchar* value; + g_object_get (object, property, &value, NULL); + JSStringRef js_string = JSStringCreateWithUTF8CString (value); + js_result = JSValueMakeString (js_context, js_string); + } + 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 js_result; +} + +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); + } + 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 = JSValueToStringCopy (js_context, js_value, + js_exception); + if (js_string) + { + gchar* string = _js_string_utf8 (js_string); + g_object_set (object, property, string, NULL); + g_free (string); + } + } + 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 JSObjectRef +_js_object_new (JSContextRef js_context, + GObject* object) +{ + JSClassDefinition js_class_def = kJSClassDefinitionEmpty; + js_class_def.className = g_strdup (KATZE_OBJECT_NAME (object)); + 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; + // js_class_def.staticFunctions = JSStaticFunction*; + JSClassRef js_class = JSClassCreate (&js_class_def); + return JSObjectMake (js_context, js_class, 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 JSValueRef +_js_eval (JSContextRef js_context, + const gchar* script, + gchar** exception) +{ + JSStringRef js_script = JSStringCreateWithUTF8CString (script); + JSValueRef js_exception; + 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); + } + JSStringRelease (js_script); + return js_value; +} + +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)) + { + if (_js_eval (js_context, script, exception)) + result = TRUE; + g_free (script); + } + else + { + *exception = g_strdup (error->message); + g_error_free (error); + } + return result; +} + +static const gchar* _folder_for_kind (MidoriAddonKind kind) +{ + switch (kind) + { + case MIDORI_ADDON_EXTENSIONS: + return "extensions"; + case MIDORI_ADDON_USER_SCRIPTS: + return "scripts"; + case MIDORI_ADDON_USER_STYLES: + return "styles"; + default: + return NULL; + } +} + +static void +midori_web_widget_window_object_cleared_cb (GtkWidget* web_widget, + WebKitWebFrame* web_frame, + JSGlobalContextRef js_context, + JSObjectRef js_window, + MidoriAddons* addons) +{ + MidoriAddonsPrivate* priv = addons->priv; + + GObject* settings; + g_object_get (web_widget, "settings", &settings, NULL); + JSObjectRef js_settings = _js_object_new (js_context, settings); + _js_object_set_property (js_context, + JSContextGetGlobalObject (js_context), + KATZE_OBJECT_NAME (settings), js_settings); + + // FIXME: We want to honor system installed addons as well + gchar* addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME, + _folder_for_kind (priv->kind), NULL); + GDir* addon_dir = g_dir_open (addon_path, 0, NULL); + if (addon_dir) + { + const gchar* filename; + while ((filename = g_dir_read_name (addon_dir))) + { + gchar* fullname = g_build_filename (addon_path, filename, NULL); + gchar* exception; + if (!_js_document_load_script_file (js_context, fullname, + &exception)) + { + gchar* message = g_strdup_printf ("console.error ('%s');", + exception); + _js_eval (js_context, message, NULL); + g_free (message); + g_free (exception); + } + g_free (fullname); + } + g_dir_close (addon_dir); + } +} + +/** + * midori_addons_new: + * @web_widget: a web widget + * @kind: the kind of addon + * @extension: a file extension mask + * + * Creates a new addons widget. + * + * @web_widget can be one of the following: + * %MidoriBrowser, %MidoriWebView, %WebKitWebView + * + * Note: Currently @extension has no effect. + * + * Return value: a new #MidoriAddons + **/ +GtkWidget* +midori_addons_new (GtkWidget* web_widget, + MidoriAddonKind kind) +{ + g_return_val_if_fail (GTK_IS_WIDGET (web_widget), NULL); + + MidoriAddons* addons = g_object_new (MIDORI_TYPE_ADDONS, + // "kind", kind, + NULL); + + MidoriAddonsPrivate* priv = addons->priv; + priv->kind = kind; + + if (kind == MIDORI_ADDON_USER_SCRIPTS) + g_signal_connect (web_widget, "window-object-cleared", + G_CALLBACK (midori_web_widget_window_object_cleared_cb), addons); + + GtkListStore* liststore = gtk_list_store_new (3, G_TYPE_STRING, + G_TYPE_INT, + G_TYPE_STRING); + // FIXME: We want to honor system installed addons as well + gchar* addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME, + _folder_for_kind (priv->kind), NULL); + GDir* addon_dir = g_dir_open (addon_path, 0, NULL); + if (addon_dir) + { + const gchar* filename; + while ((filename = g_dir_read_name (addon_dir))) + { + GtkTreeIter iter; + gtk_list_store_append (liststore, &iter); + gtk_list_store_set (liststore, &iter, + 0, filename, 1, 0, 2, "", -1); + } + g_dir_close (addon_dir); + } + gtk_tree_view_set_model (GTK_TREE_VIEW (priv->treeview), + GTK_TREE_MODEL (liststore)); + + return GTK_WIDGET (addons); +} + +/** + * midori_addons_get_toolbar: + * + * Retrieves the toolbar of the addons. A new widget is created on + * the first call of this function. + * + * Return value: a new #MidoriAddons + **/ +GtkWidget* +midori_addons_get_toolbar (MidoriAddons* addons) +{ + MidoriAddonsPrivate* priv = addons->priv; + + g_return_val_if_fail (MIDORI_IS_ADDONS (addons), NULL); + + if (!priv->toolbar) + { + GtkWidget* toolbar = gtk_toolbar_new (); + gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH_HORIZ); + gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON); + GtkToolItem* toolitem = gtk_tool_item_new (); + gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1); + gtk_widget_show (GTK_WIDGET (toolitem)); + toolitem = gtk_separator_tool_item_new (); + gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (toolitem), + FALSE); + gtk_tool_item_set_expand (toolitem, TRUE); + gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1); + gtk_widget_show (GTK_WIDGET (toolitem)); + toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_ADD); + gtk_tool_item_set_is_important (toolitem, TRUE); + g_signal_connect (toolitem, "clicked", + G_CALLBACK (midori_addons_button_add_clicked_cb), addons); + gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1); + gtk_widget_show (GTK_WIDGET (toolitem)); + priv->toolbar = toolbar; + } + + return priv->toolbar; +} diff --git a/src/midori-addons.h b/src/midori-addons.h new file mode 100644 index 00000000..940ff73c --- /dev/null +++ b/src/midori-addons.h @@ -0,0 +1,75 @@ +/* + 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 __MIDORI_ADDONS_H__ +#define __MIDORI_ADDONS_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define MIDORI_TYPE_ADDONS \ + (midori_addons_get_type ()) +#define MIDORI_ADDONS(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_ADDONS, MidoriAddons)) +#define MIDORI_ADDONS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_ADDONS, MidoriAddonsClass)) +#define MIDORI_IS_ADDONS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_ADDONS)) +#define MIDORI_IS_ADDONS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_ADDONS)) +#define MIDORI_ADDONS_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_ADDONS, MidoriAddonsClass)) + +typedef struct _MidoriAddons MidoriAddons; +typedef struct _MidoriAddonsPrivate MidoriAddonsPrivate; +typedef struct _MidoriAddonsClass MidoriAddonsClass; + +struct _MidoriAddons +{ + GtkVBox parent_instance; + + MidoriAddonsPrivate* priv; +}; + +struct _MidoriAddonsClass +{ + GtkVBoxClass parent_class; +}; + +typedef enum +{ + MIDORI_ADDON_EXTENSIONS, + MIDORI_ADDON_USER_SCRIPTS, + MIDORI_ADDON_USER_STYLES +} MidoriAddonKind; + +GType +midori_addon_kind_get_type (void) G_GNUC_CONST; + +#define MIDORI_TYPE_ADDON_KIND \ + (midori_addon_kind_get_type ()) + +GType +midori_addons_get_type (void); + +GtkWidget* +midori_addons_new (GtkWidget* web_widget, + MidoriAddonKind kind); + +GtkWidget* +midori_addons_get_toolbar (MidoriAddons* console); + +G_END_DECLS + +#endif /* __MIDORI_ADDONS_H__ */ diff --git a/src/midori-browser.c b/src/midori-browser.c index f6e825cc..e1b52f49 100644 --- a/src/midori-browser.c +++ b/src/midori-browser.c @@ -20,6 +20,7 @@ #include "midori-webview.h" #include "midori-preferences.h" #include "midori-panel.h" +#include "midori-addons.h" #include "midori-console.h" #include "midori-trash.h" @@ -87,10 +88,11 @@ enum enum { - NEW_WINDOW, + WINDOW_OBJECT_CLEARED, STATUSBAR_TEXT_CHANGED, ELEMENT_MOTION, QUIT, + NEW_WINDOW, LAST_SIGNAL }; @@ -268,6 +270,17 @@ _midori_browser_update_progress (MidoriBrowser* browser, } } +static void +midori_web_view_window_object_cleared_cb (GtkWidget* web_view, + WebKitWebFrame* web_frame, + JSGlobalContextRef js_context, + JSObjectRef js_window, + MidoriBrowser* browser) +{ + g_signal_emit (browser, signals[WINDOW_OBJECT_CLEARED], 0, + web_frame, js_context, js_window); +} + static void midori_web_view_load_started_cb (GtkWidget* web_view, WebKitWebFrame* web_frame, @@ -477,9 +490,82 @@ midori_web_view_destroy_cb (GtkWidget* widget, return FALSE; } +static void +midori_cclosure_marshal_VOID__OBJECT_POINTER_POINTER (GClosure* closure, + GValue* return_value, + guint n_param_values, + const GValue* param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef gboolean(*GMarshalFunc_VOID__OBJECT_POINTER_POINTER) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer arg_3, + gpointer data2); + register GMarshalFunc_VOID__OBJECT_POINTER_POINTER callback; + register GCClosure* cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_POINTER_POINTER) (marshal_data + ? marshal_data : cc->callback); + + callback (data1, + g_value_get_object (param_values + 1), + g_value_get_pointer (param_values + 2), + g_value_get_pointer (param_values + 3), + data2); +} + static void midori_browser_class_init (MidoriBrowserClass* class) { + signals[WINDOW_OBJECT_CLEARED] = g_signal_new ( + "window-object-cleared", + G_TYPE_FROM_CLASS (class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriBrowserClass, window_object_cleared), + 0, + NULL, + midori_cclosure_marshal_VOID__OBJECT_POINTER_POINTER, + G_TYPE_NONE, 3, + WEBKIT_TYPE_WEB_FRAME, + G_TYPE_POINTER, + G_TYPE_POINTER); + + signals[STATUSBAR_TEXT_CHANGED] = g_signal_new ( + "statusbar-text-changed", + G_TYPE_FROM_CLASS (class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriBrowserClass, statusbar_text_changed), + 0, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + signals[ELEMENT_MOTION] = g_signal_new ( + "element-motion", + G_TYPE_FROM_CLASS (class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriBrowserClass, new_window), + 0, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); signals[QUIT] = g_signal_new ( "quit", @@ -2534,12 +2620,10 @@ midori_browser_init (MidoriBrowser* browser) "vcard", _("Bookmarks")); // Transfers - priv->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW, - "uri", "", - NULL); - gtk_widget_show (priv->panel_pageholder); + GtkWidget* panel = midori_web_view_new (); + gtk_widget_show (panel); midori_panel_append_page (MIDORI_PANEL (priv->panel), - priv->panel_pageholder, NULL, + panel, NULL, "package", _("Transfers")); // Console @@ -2552,12 +2636,10 @@ midori_browser_init (MidoriBrowser* browser) "terminal", _("Console")); // History - priv->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW, - "uri", "", - NULL); - gtk_widget_show (priv->panel_pageholder); + panel = midori_web_view_new (); + gtk_widget_show (panel); midori_panel_append_page (MIDORI_PANEL (priv->panel), - priv->panel_pageholder, NULL, + panel, NULL, "document-open-recent", _("History")); // Pageholder @@ -2569,6 +2651,29 @@ midori_browser_init (MidoriBrowser* browser) priv->panel_pageholder, NULL, GTK_STOCK_CONVERT, _("Pageholder")); + // Addons + /*panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_EXTENSIONS); + gtk_widget_show (panel); + toolbar = midori_addons_get_toolbar (MIDORI_ADDONS (panel)); + gtk_widget_show (toolbar); + midori_panel_append_page (MIDORI_PANEL (priv->panel), + panel, toolbar, + "", _("Extensions"));*/ + panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_USER_SCRIPTS); + gtk_widget_show (panel); + toolbar = midori_addons_get_toolbar (MIDORI_ADDONS (panel)); + gtk_widget_show (toolbar); + midori_panel_append_page (MIDORI_PANEL (priv->panel), + panel, toolbar, + "", _("Userscripts")); + /*panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_USER_STYLES); + gtk_widget_show (panel); + toolbar = midori_addons_get_toolbar (MIDORI_ADDONS (panel)); + gtk_widget_show (toolbar); + midori_panel_append_page (MIDORI_PANEL (priv->panel), + panel, toolbar, + "", _("Userstyles"));*/ + // Notebook, containing all web_views priv->notebook = gtk_notebook_new (); gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE); @@ -2944,6 +3049,8 @@ midori_browser_append_tab (MidoriBrowser* browser, } g_object_connect (widget, + "signal::window-object-cleared", + midori_web_view_window_object_cleared_cb, browser, "signal::load-started", midori_web_view_load_started_cb, browser, "signal::load-committed", diff --git a/src/midori-browser.h b/src/midori-browser.h index a6a797d8..e7194235 100644 --- a/src/midori-browser.h +++ b/src/midori-browser.h @@ -48,6 +48,17 @@ struct _MidoriBrowserClass /* Signals */ void + (*window_object_cleared) (MidoriBrowser* browser, + WebKitWebFrame* web_frame, + JSContextRef* context, + JSObjectRef* window_object); + void + (*statusbar_text_changed) (MidoriBrowser* browser, + const gchar* text); + void + (*element_motion) (MidoriBrowser* browser, + const gchar* link_uri); + void (*quit) (MidoriBrowser* browser); void (*new_window) (MidoriBrowser* browser, diff --git a/src/midori-console.c b/src/midori-console.c index 5eb191de..693608da 100644 --- a/src/midori-console.c +++ b/src/midori-console.c @@ -18,6 +18,7 @@ G_DEFINE_TYPE (MidoriConsole, midori_console, GTK_TYPE_VBOX) struct _MidoriConsolePrivate { + GtkWidget* toolbar; GtkWidget* treeview; }; @@ -156,36 +157,35 @@ midori_console_new (void) GtkWidget* midori_console_get_toolbar (MidoriConsole* console) { - g_return_if_fail (MIDORI_IS_CONSOLE (console)); + g_return_val_if_fail (MIDORI_IS_CONSOLE (console), NULL); MidoriConsolePrivate* priv = console->priv; - static GtkWidget* toolbar = NULL; - - if (!toolbar) + if (!priv->toolbar) { - toolbar = gtk_toolbar_new (); + GtkWidget* toolbar = gtk_toolbar_new (); gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH_HORIZ); gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON); GtkToolItem* toolitem = gtk_tool_item_new (); // TODO: What about a find entry here that filters e.g. by url? gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1); - gtk_widget_show (toolitem); + gtk_widget_show (GTK_WIDGET (toolitem)); toolitem = gtk_separator_tool_item_new (); gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (toolitem), FALSE); gtk_tool_item_set_expand (toolitem, TRUE); gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1); - gtk_widget_show (toolitem); + gtk_widget_show (GTK_WIDGET (toolitem)); toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_CLEAR); gtk_tool_item_set_is_important (toolitem, TRUE); g_signal_connect (toolitem, "clicked", G_CALLBACK (midori_console_button_clear_clicked_cb), console); gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1); - gtk_widget_show (toolitem); + gtk_widget_show (GTK_WIDGET (toolitem)); + priv->toolbar = toolbar; } - return toolbar; + return priv->toolbar; } /**