]> spindle.queued.net Git - midori/commitdiff
First attempt at an extension interface.
authorChristian Dywan <christian@twotoasts.de>
Fri, 2 May 2008 20:30:26 +0000 (22:30 +0200)
committerChristian Dywan <christian@twotoasts.de>
Fri, 2 May 2008 20:30:26 +0000 (22:30 +0200)
src/midori-addons.c
src/midori-browser.c
src/midori-browser.h
src/midori-websettings.c

index f2f38d220541ad4b68ec9ce9ffd529a4bf2854fa..c5cbe6e1568be93e01683e2066979580f4d93e7e 100644 (file)
@@ -54,15 +54,34 @@ midori_addons_class_init (MidoriAddonsClass* class)
     g_type_class_add_private (class, sizeof (MidoriAddonsPrivate));
 }
 
+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_addons_button_add_clicked_cb (GtkToolItem*  toolitem,
                                      MidoriAddons* addons)
 {
+    MidoriAddonsPrivate* priv = addons->priv;
+
     GtkWidget* dialog = gtk_message_dialog_new (
         GTK_WINDOW (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");
+        "Put scripts in the folder ~/.local/share/midori/%s",
+        _folder_for_kind (priv->kind));
     gtk_dialog_run (GTK_DIALOG (dialog));
     gtk_widget_destroy (dialog);
 }
@@ -119,37 +138,6 @@ midori_addons_treeview_row_activated_cb (GtkTreeView*       treeview,
     }*/
 }
 
-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)
 {
@@ -173,7 +161,6 @@ _js_class_get_property_names_cb (JSContextRef                 js_context,
         gint i;
         for (i = 0; i < n_properties; i++)
         {
-            GType type = G_PARAM_SPEC_TYPE (pspecs[i]);
             const gchar* property = g_param_spec_get_name (pspecs[i]);
             JSStringRef js_property = JSStringCreateWithUTF8CString (property);
             JSPropertyNameAccumulatorAddName (js_properties, js_property);
@@ -187,25 +174,83 @@ _js_class_has_property_cb (JSContextRef js_context,
                            JSObjectRef  js_object,
                            JSStringRef  js_property)
 {
-    GObject* object = JSObjectGetPrivate (js_object);
     bool result = false;
+    gchar* property = _js_string_utf8 (js_property);
+    GObject* object = JSObjectGetPrivate (js_object);
     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);
     }
+    else if (js_object == JSContextGetGlobalObject (js_context))
+    {
+        gchar* property = _js_string_utf8 (js_property);
+        GType type = g_type_from_name (property);
+        result = type ? type : false;
+    }
+    g_free (property);
     return result;
 }
 
+static JSObjectRef
+_js_object_new (JSContextRef js_context,
+                gpointer     object);
+
+static void
+_js_object_set_property (JSContextRef js_context,
+                         JSObjectRef  js_object,
+                         const gchar* name,
+                         JSValueRef   js_value)
+{
+    JSStringRef js_name = JSStringCreateWithUTF8CString (name);
+    JSObjectSetProperty(js_context, js_object, js_name, js_value,
+                        kJSPropertyAttributeNone, NULL);
+    JSStringRelease (js_name);
+}
+
+static JSObjectRef
+_js_object_call_as_constructor_cb (JSContextRef     js_context,
+                                   JSObjectRef      js_object,
+                                   size_t           n_arguments,
+                                   const JSValueRef js_arguments[],
+                                   JSValueRef*      js_exception)
+{
+    gchar* type_name = JSObjectGetPrivate (js_object);
+    if (type_name)
+    {
+        GType type = g_type_from_name (type_name);
+        if (type)
+        {
+            GObject* object = g_object_new (type, NULL);
+            JSObjectRef js_object = _js_object_new (js_context, object);
+            return js_object;
+        }
+    }
+    return JSValueMakeNull (js_context);
+}
+
 static JSValueRef
 _js_class_get_property_cb (JSContextRef js_context,
                            JSObjectRef  js_object,
                            JSStringRef  js_property,
                            JSValueRef*  js_exception)
 {
+    if (js_object == JSContextGetGlobalObject (js_context))
+    {
+        gchar* property = _js_string_utf8 (js_property);
+        GType type = g_type_from_name (property);
+        if (type)
+        {
+            JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
+            js_class_def.className = g_strdup (property);
+            js_class_def.callAsConstructor = _js_object_call_as_constructor_cb;
+            JSClassRef js_class = JSClassCreate (&js_class_def);
+            return JSObjectMake (js_context, js_class, property);
+        }
+        g_free (property);
+        return JSValueMakeNull (js_context);
+    }
     GObject* object = JSObjectGetPrivate (js_object);
     JSValueRef js_result = NULL;
     if (object)
@@ -221,27 +266,56 @@ _js_class_get_property_cb (JSContextRef js_context,
             *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);
-            JSStringRef js_string = JSStringCreateWithUTF8CString (value);
-            js_result = JSValueMakeString (js_context, js_string);
+            if (value)
+            {
+                JSStringRef js_string = JSStringCreateWithUTF8CString (value);
+                js_result = JSValueMakeString (js_context, js_string);
+            }
         }
-        else
+        else if (type == G_TYPE_PARAM_INT
+            || type == G_TYPE_PARAM_UINT)
         {
-            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);
+            gint value;
+            g_object_get (object, property, &value, NULL);
+            js_result = JSValueMakeNumber (js_context, value);
         }
+        else if (type == G_TYPE_PARAM_BOOLEAN)
+        {
+            gboolean value;
+            g_object_get (object, property, &value, NULL);
+            js_result = JSValueMakeBoolean (js_context, value ? true : false);
+        }
+        else if (type == G_TYPE_PARAM_OBJECT)
+        {
+            GObject* value;
+            g_object_get (object, property, &value, NULL);
+            if (value)
+                js_result = _js_object_new (js_context, value);
+        }
+        else if (type == G_TYPE_PARAM_ENUM)
+        {
+            gint value;
+            g_object_get (object, property, &value, NULL);
+            js_result = JSValueMakeNumber (js_context, value);
+        }
+        else
+            js_result = JSValueMakeUndefined (js_context);
         g_free (property);
     }
-    return js_result;
+    return js_result ? js_result : JSValueMakeNull (js_context);
 }
 
 static bool
@@ -266,6 +340,8 @@ _js_class_set_property_cb (JSContextRef js_context,
             *js_exception = JSValueMakeString (js_context, js_message);
             JSStringRelease (js_message);
             g_free (message);
+            g_free (property);
+            return false;
         }
         if (!(pspec->flags & G_PARAM_WRITABLE))
         {
@@ -275,13 +351,42 @@ _js_class_set_property_cb (JSContextRef js_context,
         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)
+            JSStringRef js_string_value = JSValueToStringCopy (js_context,
+                js_value, js_exception);
+            if (js_string_value)
+            {
+                gchar* string_value = _js_string_utf8 (js_string_value);
+                g_object_set (object, property, string_value, NULL);
+                g_free (string_value);
+            }
+        }
+        else if (type == G_TYPE_PARAM_INT
+            || type == G_TYPE_PARAM_UINT)
+        {
+            int value = JSValueToNumber (js_context, js_value,
+                                          js_exception);
+            g_object_set (object, property, value, NULL);
+        }
+        else if (type == G_TYPE_PARAM_BOOLEAN)
+        {
+            bool value = JSValueToBoolean (js_context, js_value);
+            g_object_set (object, property, value ? TRUE : FALSE, NULL);
+        }
+        else if (type == G_TYPE_PARAM_OBJECT)
+        {
+            JSObjectRef js_object_value = JSValueToObject (
+                js_context, js_value, NULL);
+            GObject* object_value = JSObjectGetPrivate (js_object_value);
+            if (object_value)
+                g_object_set (object, property, object_value, NULL);
+            else
             {
-                gchar* string = _js_string_utf8 (js_string);
-                g_object_set (object, property, string, NULL);
-                g_free (string);
+                gchar* message = g_strdup_printf (_("%s cannot be assigned to %s.%s"),
+                "[object]", KATZE_OBJECT_NAME (object), property);
+                JSStringRef js_message = JSStringCreateWithUTF8CString (message);
+                *js_exception = JSValueMakeString (js_context, js_message);
+                JSStringRelease (js_message);
+                g_free (message);
             }
         }
         else
@@ -298,9 +403,49 @@ _js_class_set_property_cb (JSContextRef js_context,
     return result;
 }
 
+static JSValueRef
+_js_foo_call_as_function_cb (JSContextRef     js_context,
+                             JSObjectRef      js_function,
+                             JSObjectRef      js_this,
+                             size_t           n_arguments,
+                             const JSValueRef js_arguments[],
+                             JSValueRef*      js_exception)
+{
+    GObject* object = JSObjectGetPrivate (js_this);
+    if (object)
+    {
+        if (!n_arguments)
+        {
+            gtk_widget_show (GTK_WIDGET (object));
+        }
+        else if (n_arguments == 1)
+        {
+            JSObjectRef js_arg1 = JSValueToObject (
+                js_context, js_arguments[0], NULL);
+            GObject* arg1 = JSObjectGetPrivate (js_arg1);
+            if (arg1)
+                gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (arg1));
+        }
+    }
+
+    return JSValueMakeUndefined (js_context);
+}
+
+static void
+_js_foo_add_function (JSContextRef js_context,
+                      JSObjectRef  js_object,
+                      const gchar* func)
+{
+    JSStringRef js_func = JSStringCreateWithUTF8CString (func);
+    JSObjectRef js_function = JSObjectMakeFunctionWithCallback (
+        js_context, js_func, _js_foo_call_as_function_cb);
+    JSStringRelease (js_func);
+    _js_object_set_property (js_context, js_object, func, js_function);
+}
+
 static JSObjectRef
 _js_object_new (JSContextRef js_context,
-                GObject*     object)
+                gpointer     object)
 {
     JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
     js_class_def.className = g_strdup (KATZE_OBJECT_NAME (object));
@@ -308,21 +453,17 @@ _js_object_new (JSContextRef js_context,
     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);
+    JSObjectRef js_object = JSObjectMake (js_context, js_class, object);
+    if (GTK_IS_WIDGET (object))
+    {
+        _js_foo_add_function (js_context, js_object, "show");
+    }
+    if (GTK_IS_CONTAINER (object))
+    {
+        _js_foo_add_function (js_context, js_object, "add");
+    }
+    return js_object;
 }
 
 static JSValueRef
@@ -331,21 +472,45 @@ _js_eval (JSContextRef js_context,
           gchar**      exception)
 {
     JSStringRef js_script = JSStringCreateWithUTF8CString (script);
-    JSValueRef js_exception;
+    JSValueRef js_exception = NULL;
     JSValueRef js_value = JSEvaluateScript (js_context, js_script,
-        JSContextGetGlobalObject (js_context),
-        NULL, 0, &js_exception);
+        JSContextGetGlobalObject (js_context), NULL, 0, &js_exception);
     if (!js_value && exception)
     {
         JSStringRef js_message = JSValueToStringCopy (js_context,
                                                       js_exception, NULL);
         *exception = _js_string_utf8 (js_message);
         JSStringRelease (js_message);
+        js_value = JSValueMakeNull (js_context);
     }
     JSStringRelease (js_script);
     return js_value;
 }
 
+static bool
+_js_check_syntax (JSContextRef js_context,
+                  const gchar* script,
+                  const gchar* source_id,
+                  int          line,
+                  gchar**      exception)
+{
+    JSStringRef js_script = JSStringCreateWithUTF8CString (script);
+    JSStringRef js_source_id = JSStringCreateWithUTF8CString (source_id);
+    JSValueRef js_exception = NULL;
+    bool result = JSCheckScriptSyntax (js_context, js_script, js_source_id,
+                                       line, &js_exception);
+    if (!result && exception)
+    {
+        JSStringRef js_message = JSValueToStringCopy (js_context,
+                                                      js_exception, NULL);
+        *exception = _js_string_utf8 (js_message);
+        JSStringRelease (js_message);
+    }
+    JSStringRelease (js_source_id);
+    JSStringRelease (js_script);
+    return result;
+}
+
 static gboolean
 _js_document_load_script_file (JSContextRef js_context,
                                const gchar* filename,
@@ -368,19 +533,122 @@ _js_document_load_script_file (JSContextRef js_context,
     return result;
 }
 
-static const gchar* _folder_for_kind (MidoriAddonKind kind)
+static void
+midori_addons_init (MidoriAddons* addons)
 {
-    switch (kind)
+    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 JSValueRef
+_js_info_call_as_function_cb (JSContextRef     js_context,
+                              JSObjectRef      js_function,
+                              JSObjectRef      js_this,
+                              size_t           n_arguments,
+                              const JSValueRef js_arguments[],
+                              JSValueRef*      js_exception)
+{
+    if (n_arguments > 0) {
+        JSStringRef js_string = JSValueToStringCopy (
+            js_context, js_arguments[0], NULL);
+        gchar* string = _js_string_utf8 (js_string);
+        // FIXME: Do we want to print this somewhere else?
+        printf ("console.info: %s\n", string);
+        g_free (string);
+        JSStringRelease (js_string);
+    }
+
+    return JSValueMakeUndefined (js_context);
+}
+
+static void
+_midori_addons_extensions_main (MidoriAddons* addons,
+                                GtkWidget*    web_widget)
+{
+    MidoriAddonsPrivate* priv = addons->priv;
+
+    JSClassDefinition js_global_def = kJSClassDefinitionEmpty;
+    js_global_def.getPropertyNames = _js_class_get_property_names_cb;
+    js_global_def.hasProperty = _js_class_has_property_cb;
+    js_global_def.getProperty = _js_class_get_property_cb;
+    JSClassRef js_global_class = JSClassCreate (&js_global_def);
+    JSGlobalContextRef js_context = JSGlobalContextCreate (js_global_class);
+    JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
+    js_class_def.className = g_strdup ("console");
+    JSClassRef js_class = JSClassCreate (&js_class_def);
+    JSObjectRef js_console = JSObjectMake (js_context, js_class, NULL);
+    JSStringRef js_info = JSStringCreateWithUTF8CString ("info");
+    JSObjectRef js_info_function = JSObjectMakeFunctionWithCallback (
+        js_context, js_info, _js_info_call_as_function_cb);
+    JSObjectSetProperty (js_context, js_console, js_info, js_info_function,
+                         kJSPropertyAttributeNone, NULL);
+    JSStringRelease (js_info);
+    _js_object_set_property (js_context,
+                             JSContextGetGlobalObject (js_context),
+                             "console", js_console);
+
+    GtkWidget* browser = gtk_widget_get_toplevel (GTK_WIDGET (web_widget));
+    if (GTK_WIDGET_TOPLEVEL (browser))
     {
-    case MIDORI_ADDON_EXTENSIONS:
-        return "extensions";
-    case MIDORI_ADDON_USER_SCRIPTS:
-        return "scripts";
-    case MIDORI_ADDON_USER_STYLES:
-        return "styles";
-    default:
-        return NULL;
+        // FIXME: Midori should be backed up by a real GObject
+        JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
+        js_class_def.className = g_strdup ("Midori");
+        JSClassRef js_class = JSClassCreate (&js_class_def);
+        JSObjectRef js_midori = JSObjectMake (js_context, js_class, NULL);
+        _js_object_set_property (js_context,
+                                 JSContextGetGlobalObject (js_context),
+                                 "midori", js_midori);
+        JSObjectRef js_browser = _js_object_new (js_context, browser);
+        _js_object_set_property (js_context,
+                                 js_midori,
+                                 "browser", js_browser);
     }
+
+    // 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 = NULL;
+            _js_document_load_script_file (js_context, fullname, &exception);
+            if (exception)
+            // FIXME: Do we want to print this somewhere else?
+            // FIXME Convert the filename to UTF8
+                printf ("%s - Exception: %s\n", filename, exception);
+            g_free (fullname);
+        }
+        g_dir_close (addon_dir);
+    }
+    JSGlobalContextRelease (js_context);
 }
 
 static void
@@ -392,13 +660,6 @@ midori_web_widget_window_object_cleared_cb (GtkWidget*         web_widget,
 {
     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);
@@ -453,7 +714,9 @@ midori_addons_new (GtkWidget*      web_widget,
     MidoriAddonsPrivate* priv = addons->priv;
     priv->kind = kind;
 
-    if (kind == MIDORI_ADDON_USER_SCRIPTS)
+    if (kind == MIDORI_ADDON_EXTENSIONS)
+        _midori_addons_extensions_main (addons, web_widget);
+    else if (kind == MIDORI_ADDON_USER_SCRIPTS)
         g_signal_connect (web_widget, "window-object-cleared",
             G_CALLBACK (midori_web_widget_window_object_cleared_cb), addons);
 
index e1b52f495e8167103f53063dec85ba6672a3d8da..a8889a93edf239129d73c5e5f3c3d3f0e81bf587 100644 (file)
@@ -81,6 +81,10 @@ enum
 {
     PROP_0,
 
+    PROP_MENUBAR,
+    PROP_NAVIGATIONBAR,
+    PROP_TAB,
+    PROP_STATUSBAR,
     PROP_SETTINGS,
     PROP_STATUSBAR_TEXT,
     PROP_TRASH
@@ -595,6 +599,62 @@ midori_browser_class_init (MidoriBrowserClass* class)
 
     GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
 
+    /**
+    * MidoriBrowser::menubar
+    *
+    * The menubar.
+    */
+    g_object_class_install_property (gobject_class,
+                                     PROP_MENUBAR,
+                                     g_param_spec_object (
+                                     "menubar",
+                                     _("Menubar"),
+                                     _("The menubar"),
+                                     GTK_TYPE_MENU_BAR,
+                                     G_PARAM_READABLE));
+
+    /**
+    * MidoriBrowser::navigationbar
+    *
+    * The navigationbar.
+    */
+    g_object_class_install_property (gobject_class,
+                                     PROP_NAVIGATIONBAR,
+                                     g_param_spec_object (
+                                     "navigationbar",
+                                     _("Navigationbar"),
+                                     _("The navigationbar"),
+                                     GTK_TYPE_TOOLBAR,
+                                     G_PARAM_READABLE));
+
+    /**
+    * MidoriBrowser::tab
+    *
+    * The current tab.
+    */
+    g_object_class_install_property (gobject_class,
+                                     PROP_TAB,
+                                     g_param_spec_object (
+                                     "tab",
+                                     _("Tab"),
+                                     _("The current tab"),
+                                     GTK_TYPE_WIDGET,
+                                     G_PARAM_READWRITE));
+
+    /**
+    * MidoriBrowser::statusbar
+    *
+    * The statusbar.
+    */
+    g_object_class_install_property (gobject_class,
+                                     PROP_STATUSBAR,
+                                     g_param_spec_object (
+                                     "statusbar",
+                                     _("Statusbar"),
+                                     _("The statusbar"),
+                                     GTK_TYPE_STATUSBAR,
+                                     G_PARAM_READABLE));
+
     /**
     * MidoriBrowser::settings
     *
@@ -607,7 +667,7 @@ midori_browser_class_init (MidoriBrowserClass* class)
                                      PROP_SETTINGS,
                                      g_param_spec_object (
                                      "settings",
-                                     "Settings",
+                                     _("Settings"),
                                      _("The associated settings"),
                                      MIDORI_TYPE_WEB_SETTINGS,
                                      G_PARAM_READWRITE));
@@ -627,7 +687,7 @@ midori_browser_class_init (MidoriBrowserClass* class)
                                      PROP_STATUSBAR_TEXT,
                                      g_param_spec_string (
                                      "statusbar-text",
-                                     "Statusbar Text",
+                                     _("Statusbar Text"),
                                      _("The text that is displayed in the statusbar"),
                                      "",
                                      flags));
@@ -646,7 +706,7 @@ midori_browser_class_init (MidoriBrowserClass* class)
                                      PROP_TRASH,
                                      g_param_spec_object (
                                      "trash",
-                                     "Trash",
+                                     _("Trash"),
                                      _("The trash, collecting recently closed tabs and windows"),
                                      MIDORI_TYPE_TRASH,
                                      G_PARAM_READWRITE));
@@ -697,7 +757,7 @@ static void
 _action_tab_close_activate (GtkAction*     action,
                             MidoriBrowser* browser)
 {
-    GtkWidget* widget = midori_browser_get_current_page (browser);
+    GtkWidget* widget = midori_browser_get_current_tab (browser);
     GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, widget);
     gtk_widget_destroy (scrolled);
 }
@@ -2651,14 +2711,7 @@ 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"));*/
+    // Userscripts
     panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_USER_SCRIPTS);
     gtk_widget_show (panel);
     toolbar = midori_addons_get_toolbar (MIDORI_ADDONS (panel));
@@ -2666,6 +2719,7 @@ midori_browser_init (MidoriBrowser* browser)
     midori_panel_append_page (MIDORI_PANEL (priv->panel),
                               panel, toolbar,
                               "", _("Userscripts"));
+    // Userstyles
     /*panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_USER_STYLES);
     gtk_widget_show (panel);
     toolbar = midori_addons_get_toolbar (MIDORI_ADDONS (panel));
@@ -2750,6 +2804,15 @@ midori_browser_init (MidoriBrowser* browser)
     gtk_box_pack_start (GTK_BOX (priv->statusbar), priv->progressbar,
                         FALSE, FALSE, 3);
 
+    // Extensions
+    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"));
+
     g_object_unref (ui_manager);
 }
 
@@ -2921,6 +2984,9 @@ midori_browser_set_property (GObject*      object,
 
     switch (prop_id)
     {
+    case PROP_TAB:
+        midori_browser_set_current_tab (browser, g_value_get_object (value));
+        break;
     case PROP_STATUSBAR_TEXT:
         _midori_browser_set_statusbar_text (browser, g_value_get_string (value));
         break;
@@ -2962,6 +3028,18 @@ midori_browser_get_property (GObject*    object,
 
     switch (prop_id)
     {
+    case PROP_MENUBAR:
+        g_value_set_object (value, priv->menubar);
+        break;
+    case PROP_NAVIGATIONBAR:
+        g_value_set_object (value, priv->navigationbar);
+        break;
+    case PROP_TAB:
+        g_value_set_object (value, midori_browser_get_current_tab (browser));
+        break;
+    case PROP_STATUSBAR:
+        g_value_set_object (value, priv->statusbar);
+        break;
     case PROP_STATUSBAR_TEXT:
         g_value_set_string (value, priv->statusbar_text);
         break;
@@ -3217,7 +3295,6 @@ midori_browser_set_current_page (MidoriBrowser* browser,
     gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n);
     GtkWidget* scrolled = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), n);
     GtkWidget* widget = _midori_browser_child_for_scrolled (browser, scrolled);
-    printf ("_nth_page: %s\n", G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (widget)));
     if (widget && MIDORI_IS_WEB_VIEW (widget)
         && !strcmp (midori_web_view_get_display_uri (
         MIDORI_WEB_VIEW (widget)), ""))
@@ -3234,19 +3311,70 @@ midori_browser_set_current_page (MidoriBrowser* browser,
  *
  * If there is no page present at all, %NULL is returned.
  *
- * Return value: the selected page, or %NULL
+ * Return value: the selected page, or -1
  **/
-GtkWidget*
+gint
 midori_browser_get_current_page (MidoriBrowser* browser)
+{
+    g_return_val_if_fail (MIDORI_IS_BROWSER (browser), -1);
+
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    return gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+}
+
+/**
+ * midori_browser_set_current_tab:
+ * @browser: a #MidoriBrowser
+ * @widget: a #GtkWidget
+ *
+ * Switches to the page containing @widget.
+ *
+ * The widget will also grab the focus automatically.
+ **/
+void
+midori_browser_set_current_tab (MidoriBrowser* browser,
+                                GtkWidget*     widget)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, widget);
+    gint n = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), scrolled);
+    gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n);
+    if (widget && MIDORI_IS_WEB_VIEW (widget)
+        && !strcmp (midori_web_view_get_display_uri (
+        MIDORI_WEB_VIEW (widget)), ""))
+        gtk_widget_grab_focus (priv->location);
+    else
+        gtk_widget_grab_focus (widget);
+}
+
+/**
+ * midori_browser_get_current_tab:
+ * @browser: a #MidoriBrowser
+ *
+ * Retrieves the currently selected tab.
+ *
+ * If there is no tab present at all, %NULL is returned.
+ *
+ * Return value: the selected tab, or %NULL
+ **/
+GtkWidget*
+midori_browser_get_current_tab (MidoriBrowser* browser)
 {
     g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL);
 
     MidoriBrowserPrivate* priv = browser->priv;
 
     gint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
-    GtkWidget* widget = _midori_browser_child_for_scrolled (browser,
-        gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), n));
-    return widget;
+    if (n >= 0)
+    {
+        GtkWidget* widget = _midori_browser_child_for_scrolled (browser,
+            gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), n));
+        return widget;
+    }
+    else
+        return NULL;
 }
 
 /**
@@ -3267,7 +3395,7 @@ midori_browser_get_current_web_view (MidoriBrowser* browser)
 {
     g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL);
 
-    GtkWidget* web_view = midori_browser_get_current_page (browser);
+    GtkWidget* web_view = midori_browser_get_current_tab (browser);
     return MIDORI_IS_WEB_VIEW (web_view) ? web_view : NULL;
 }
 
index e7194235ec9645ffd1bf3f2bc21abed0252d9cf5..6dda0b43c95742b2e522e2b8cf84c4f08e114b48 100644 (file)
@@ -95,9 +95,16 @@ void
 midori_browser_set_current_page       (MidoriBrowser*     browser,
                                        gint               n);
 
-GtkWidget*
+gint
 midori_browser_get_current_page       (MidoriBrowser*     browser);
 
+void
+midori_browser_set_current_tab        (MidoriBrowser*     browser,
+                                       GtkWidget*         widget);
+
+GtkWidget*
+midori_browser_get_current_tab        (MidoriBrowser*     browser);
+
 GtkWidget*
 midori_browser_get_current_web_view   (MidoriBrowser*     browser);
 
index 6f6ba7b3a62b97f0eb71165f9aeb97d028427331..4b1fdf4d6956ac90ca830ab83b5b54f23b75e3d9 100644 (file)
@@ -463,7 +463,7 @@ midori_web_settings_class_init (MidoriWebSettingsClass* class)
                                      "close-buttons-on-tabs",
                                      _("Close Buttons on Tabs"),
                                      _("Whether tabs have close buttons"),
-                                     FALSE,
+                                     TRUE,
                                      flags));
 
     g_object_class_install_property (gobject_class,