]> spindle.queued.net Git - midori/commitdiff
Initial refactoring work, regressions expected
authorChristian Dywan <christian@twotoasts.de>
Mon, 10 Mar 2008 21:26:09 +0000 (22:26 +0100)
committerChristian Dywan <christian@twotoasts.de>
Mon, 10 Mar 2008 21:26:09 +0000 (22:26 +0100)
The 'browser' struct is superseded by MidoriBrowser, which actually
represents a window that holds pages, i.e. tabs. The tabs are currently
of the type MidoriWebView, which is a slightly enhanced WebView. Also
MidoriWebSettings is introduced to hold additional settings that Midori
needs.

The other two new classes are MidoriTrash, representing closed tabs and
windows and MidoriPanel, representing the side panel.

The refactoring allows for several features to be much more easily
implemented, such as full support for multiple windows and instant
saving of modified files, such as bookmarks or the session. Regressions
are expected and not everything is done yet.

30 files changed:
HACKING
katze/katze-throbber.c
katze/katze-throbber.h
src/Makefile.am
src/browser.c [deleted file]
src/browser.h [deleted file]
src/global.h
src/helpers.c
src/helpers.h
src/main.c [changed mode: 0755->0644]
src/midori-browser.c [new file with mode: 0644]
src/midori-browser.h [new file with mode: 0644]
src/midori-panel.c [new file with mode: 0644]
src/midori-panel.h [new file with mode: 0644]
src/midori-trash.c [new file with mode: 0644]
src/midori-trash.h [new file with mode: 0644]
src/midori-websettings.c [new file with mode: 0644]
src/midori-websettings.h [new file with mode: 0644]
src/midori-webview.c [new file with mode: 0644]
src/midori-webview.h [new file with mode: 0644]
src/prefs.c
src/prefs.h
src/search.c
src/sokoke.c
src/sokoke.h
src/ui.h
src/webSearch.c
src/webSearch.h
src/webView.c [deleted file]
src/webView.h [deleted file]

diff --git a/HACKING b/HACKING
index 22c846aa20b0ffe429c1f376fbb627db8656c88a..ae54476f879f12b0e9cd5521d8aab18695223a27 100644 (file)
--- a/HACKING
+++ b/HACKING
@@ -21,16 +21,16 @@ Source file example:
             return;
 
         #ifdef BAR_STRICT
-        if(bar == FOO_N)
+        if (bar == FOO_N)
         {
-            g_print("illegal value for 'bar'.\n");
+            g_print ("illegal value for 'bar'.\n");
             return;
         }
         #endif
 
         // this is an example
         gint n;
-        switch(bar)
+        switch (bar)
         {
         case FOO_FOO:
             n = bar + 1;
@@ -43,9 +43,9 @@ Source file example:
         }
 
         guint i;
-        for(i = 0; i < n; i++)
+        for (i = 0; i < n; i++)
         {
-            g_print("%s\n", foo);
+            g_print ("%s\n", foo);
         }
     }
 
@@ -74,12 +74,18 @@ Header file example:
 
     typedef struct
     {
-        FooEnum fooBar;
+        FooEnum foo_bar;
     } FooStruct;
 
     // -- Declarations
 
     void
-    foobar(FooEnum, const gchar*);
+    foo_bar           (FooEnum      bar,
+                       const gchar* foo);
+
+    const gchar*
+    foo_foo           (FooStruct foo_struct,
+                       guint     number,
+                       gboolean  flag);
 
     #endif /* !__FOO_H__ */
index fcaae5e6bd3de91ae103ba172c5c57bc8cefe9dd..0565f345fe94ecfd93726735a84fd1b4de34401d 100644 (file)
@@ -222,11 +222,9 @@ katze_throbber_destroy (GtkObject *object)
     KatzeThrobberPrivate* priv = throbber->priv;
 
     katze_assign (priv->icon_name, NULL);
-    if (priv->pixbuf)
-        katze_object_assign (priv->pixbuf, NULL);
+    katze_object_assign (priv->pixbuf, NULL);
     katze_assign (priv->static_icon_name, NULL);
-    if (priv->static_pixbuf)
-        katze_object_assign (priv->static_pixbuf, NULL);
+    katze_object_assign (priv->static_pixbuf, NULL);
     katze_assign (priv->static_stock_id, NULL);
 
     GTK_OBJECT_CLASS (katze_throbber_parent_class)->destroy (object);
index 17f570b83bc6de3544a5bc0fba9c1e26e6d2be48..6f1be411daa143279b539054195ceeecb876fe40 100644 (file)
@@ -38,7 +38,8 @@ typedef struct _KatzeThrobberClass           KatzeThrobberClass;
 
 struct _KatzeThrobber
 {
-    GtkMisc parent_object;
+    GtkMisc parent_instance;
+
     KatzeThrobberPrivate* priv;
 };
 
index 2b98976af8cd4fb598a959c19739be91be948bfb..82951045f54549d4c71991bb29e2d7c66b956e40 100644 (file)
@@ -15,11 +15,14 @@ bin_PROGRAMS = \
 
 midori_SOURCES = \
     main.c      main.h      \
-    browser.c   browser.h   \
+    midori-browser.c     midori-browser.h     \
+    midori-panel.c       midori-panel.h       \
+    midori-trash.c       midori-trash.h       \
+    midori-webview.c     midori-webview.h     \
+    midori-websettings.c midori-websettings.h \
     prefs.c     prefs.h     \
     webSearch.c webSearch.h \
     helpers.c   helpers.h   \
-    webView.c   webView.h   \
     sokoke.c    sokoke.h    \
     conf.c      conf.h      \
     search.c    search.h    \
diff --git a/src/browser.c b/src/browser.c
deleted file mode 100644 (file)
index 88044e3..0000000
+++ /dev/null
@@ -1,1775 +0,0 @@
-/*
- Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
-
- 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 "browser.h"
-
-#include "helpers.h"
-#include "prefs.h"
-#include "sokoke.h"
-#include "ui.h"
-#include "webView.h"
-#include "webSearch.h"
-#include "../katze/katze.h"
-
-#include <gdk/gdkkeysyms.h>
-#include <string.h>
-
-// -- GTK+ signal handlers begin here
-
-void on_action_window_new_activate(GtkAction* action, CBrowser* browser)
-{
-    browser_new(NULL);
-}
-
-void on_action_tab_new_activate(GtkAction* action, CBrowser* browser)
-{
-    browser_new(browser);
-    update_browser_actions(browser);
-}
-
-void on_action_open_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkWidget* dialog = gtk_file_chooser_dialog_new("Open file"
-        , GTK_WINDOW(browser->window)
-        , GTK_FILE_CHOOSER_ACTION_OPEN
-        , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL
-        , GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT
-        , NULL);
-     gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_OPEN);
-     if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
-     {
-         gchar* sFilename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
-         webView_open(get_nth_webView(-1, browser), sFilename);
-         g_free(sFilename);
-     }
-    gtk_widget_destroy(dialog);
-}
-
-void on_action_tab_close_activate(GtkAction* action, CBrowser* browser)
-{
-    webView_close(get_nth_webView(-1, browser), browser);
-}
-
-void on_action_window_close_activate(GtkAction* action, CBrowser* browser)
-{
-    gtk_widget_destroy(browser->window);
-}
-
-void on_action_quit_activate(GtkAction* action, CBrowser* browser)
-{
-    gtk_main_quit();
-}
-
-void on_action_edit_activate(GtkAction* action, CBrowser* browser)
-{
-    update_edit_items(browser);
-}
-
-void on_action_cut_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window));
-    if(G_LIKELY(widget))
-        g_signal_emit_by_name(widget, "cut-clipboard");
-}
-
-void on_action_copy_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window));
-    if(G_LIKELY(widget))
-        g_signal_emit_by_name(widget, "copy-clipboard");
-}
-
-void on_action_paste_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window));
-    if(G_LIKELY(widget))
-        g_signal_emit_by_name(widget, "paste-clipboard");
-}
-
-void on_action_delete_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window));
-    if(G_LIKELY(widget))
-    {
-        if(WEBKIT_IS_WEB_VIEW(widget))
-            webkit_web_view_delete_selection(WEBKIT_WEB_VIEW(widget));
-        else if(GTK_IS_EDITABLE(widget))
-            gtk_editable_delete_selection(GTK_EDITABLE(widget));
-    }
-}
-
-void on_action_selectAll_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window));
-    if(G_LIKELY(widget))
-    {
-        if(GTK_IS_ENTRY(widget))
-            gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1);
-        else
-            g_signal_emit_by_name(widget, "select-all");
-    }
-}
-
-void on_action_find_activate(GtkAction* action, CBrowser* browser)
-{
-    if(GTK_WIDGET_VISIBLE(browser->findbox))
-    {
-        GtkWidget* webView = get_nth_webView(-1, browser);
-        webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(webView));
-        gtk_toggle_tool_button_set_active(
-         GTK_TOGGLE_TOOL_BUTTON(browser->findbox_highlight), FALSE);
-        gtk_widget_hide(browser->findbox);
-    }
-    else
-    {
-        GtkWidget* icon = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU);
-        sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->findbox_text)
-         , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(icon));
-        gtk_entry_set_text(GTK_ENTRY(browser->findbox_text), "");
-        gtk_widget_show(browser->findbox);
-        gtk_widget_grab_focus(GTK_WIDGET(browser->findbox_text));
-    }
-}
-
-static void findbox_find(gboolean forward, CBrowser* browser)
-{
-    const gchar* text = gtk_entry_get_text(GTK_ENTRY(browser->findbox_text));
-    const gboolean caseSensitive = gtk_toggle_tool_button_get_active(
-     GTK_TOGGLE_TOOL_BUTTON(browser->findbox_case));
-    GtkWidget* webView = get_nth_webView(-1, browser);
-    if(GTK_WIDGET_VISIBLE(browser->findbox))
-        webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(webView));
-    gboolean found = webkit_web_view_search_text(WEBKIT_WEB_VIEW(webView)
-     , text, caseSensitive, forward, TRUE);
-    if(GTK_WIDGET_VISIBLE(browser->findbox))
-    {
-        GtkWidget* icon;
-        if(found)
-            icon = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU);
-        else
-            icon = gtk_image_new_from_stock(GTK_STOCK_STOP, GTK_ICON_SIZE_MENU);
-        sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->findbox_text)
-         , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(icon));
-        webkit_web_view_mark_text_matches(WEBKIT_WEB_VIEW(webView), text, caseSensitive, 0);
-        const gboolean highlight = gtk_toggle_tool_button_get_active(
-         GTK_TOGGLE_TOOL_BUTTON(browser->findbox_highlight));
-        webkit_web_view_set_highlight_text_matches(WEBKIT_WEB_VIEW(webView), highlight);
-    }
-}
-
-void on_action_find_next_activate(GtkAction* action, CBrowser* browser)
-{
-    findbox_find(TRUE, browser);
-}
-
-void on_action_find_previous_activate(GtkAction* action, CBrowser* browser)
-{
-    findbox_find(FALSE, browser);
-}
-
-void on_findbox_highlight_toggled(GtkToggleToolButton* toolitem, CBrowser* browser)
-{
-    GtkWidget* webView = get_nth_webView(-1, browser);
-    const gboolean highlight = gtk_toggle_tool_button_get_active(toolitem);
-    webkit_web_view_set_highlight_text_matches(WEBKIT_WEB_VIEW(webView), highlight);
-}
-
-void on_findbox_button_close_clicked(GtkWidget* widget, CBrowser* browser)
-{
-    gtk_widget_hide(browser->findbox);
-}
-
-void on_action_preferences_activate(GtkAction* action, CBrowser* browser)
-{
-    // Show the preferences dialog. Create it if necessary.
-    static GtkWidget* dialog;
-    if(GTK_IS_DIALOG(dialog))
-        gtk_window_present(GTK_WINDOW(dialog));
-    else
-    {
-        dialog = prefs_preferences_dialog_new(browser);
-        gtk_widget_show(dialog);
-    }
-}
-
-static void on_toolbar_navigation_notify_style(GObject* object, GParamSpec* arg1
- , CBrowser* browser)
-{
-    if(config->toolbarStyle == CONFIG_TOOLBAR_DEFAULT)
-    {
-        gtk_toolbar_set_style(GTK_TOOLBAR(browser->navibar)
-         , config_to_toolbarstyle(config->toolbarStyle));
-    }
-}
-
-void on_action_toolbar_navigation_activate(GtkToggleAction* action, CBrowser* browser)
-{
-    config->toolbarNavigation = gtk_toggle_action_get_active(action);
-    sokoke_widget_set_visible(browser->navibar, config->toolbarNavigation);
-}
-
-void on_action_toolbar_bookmarks_activate(GtkToggleAction* action, CBrowser* browser)
-{
-    config->toolbarBookmarks = gtk_toggle_action_get_active(action);
-    sokoke_widget_set_visible(browser->bookmarkbar, config->toolbarBookmarks);
-}
-
-void on_action_toolbar_downloads_activate(GtkToggleAction* action, CBrowser* browser)
-{
-    /*config->toolbarDownloads = gtk_toggle_action_get_active(action);
-    sokoke_widget_set_visible(browser->downloadbar, config->toolbarDownloads);*/
-}
-
-void on_action_toolbar_status_activate(GtkToggleAction* action, CBrowser* browser)
-{
-    config->toolbarStatus = gtk_toggle_action_get_active(action);
-    sokoke_widget_set_visible(browser->statusbar, config->toolbarStatus);
-}
-
-void on_action_refresh_activate(GtkAction* action, CBrowser* browser)
-{
-    /*GdkModifierType state = (GdkModifierType)0;
-    gint x, y; gdk_window_get_pointer(NULL, &x, &y, &state);
-    gboolean fromCache = state & GDK_SHIFT_MASK;*/
-    webkit_web_view_reload(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser)));
-}
-
-void on_action_refresh_stop_activate(GtkAction* action, CBrowser* browser)
-{
-    gchar* stockId; g_object_get(action, "stock-id", &stockId, NULL);
-    // Refresh or stop, depending on the stock id
-    if(!strcmp(stockId, GTK_STOCK_REFRESH))
-    {
-        /*GdkModifierType state = (GdkModifierType)0;
-        gint x, y; gdk_window_get_pointer(NULL, &x, &y, &state);
-        gboolean fromCache = state & GDK_SHIFT_MASK;*/
-        webkit_web_view_reload(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser)));
-    }
-    else
-        webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser)));
-    g_free(stockId);
-}
-
-void on_action_stop_activate(GtkAction* action, CBrowser* browser)
-{
-    webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser)));
-}
-
-void on_action_zoom_in_activate(GtkAction* action, CBrowser* browser)
-{
-    /*GtkWidget* webView = get_nth_webView(-1, browser);
-    const gfloat zoom = webkit_web_view_get_text_multiplier(WEBKIT_WEB_VIEW(webView));
-    webkit_web_view_set_text_multiplier(WEBKIT_WEB_VIEW(webView), zoom + 0.1);*/
-}
-
-void on_action_zoom_out_activate(GtkAction* action, CBrowser* browser)
-{
-    /*GtkWidget* webView = get_nth_webView(-1, browser);
-    const gfloat zoom = webView_get_text_size(WEBKIT_WEB_VIEW(webView));
-    webkit_web_view_set_text_multiplier(WEBKIT_WEB_VIEW(webView), zoom - 0.1);*/
-}
-
-void on_action_zoom_normal_activate(GtkAction* action, CBrowser* browser)
-{
-    //webkit_web_view_set_text_multiplier(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser)), 1);
-}
-
-void on_action_source_view_activate(GtkAction* action, CBrowser* browser)
-{
-    /*GtkWidget* webView = get_nth_webView(-1, browser);
-    gchar* source = webkit_web_view_copy_source(WEBKIT_WEB_VIEW(webView));
-    webkit_web_view_load_html_string(WEBKIT_WEB_VIEW(webView), source, "");
-    g_free(source);*/
-}
-
-void on_action_fullscreen_activate(GtkAction* action, CBrowser* browser)
-{
-    GdkWindowState state = gdk_window_get_state(browser->window->window);
-    if(state & GDK_WINDOW_STATE_FULLSCREEN)
-        gtk_window_unfullscreen(GTK_WINDOW(browser->window));
-    else
-        gtk_window_fullscreen(GTK_WINDOW(browser->window));
-}
-
-void on_action_back_activate(GtkAction* action, CBrowser* browser)
-{
-    webkit_web_view_go_back(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser)));
-}
-
-void on_action_forward_activate(GtkAction* action, CBrowser* browser)
-{
-    webkit_web_view_go_forward(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser)));
-}
-
-void on_action_home_activate(GtkAction* action, CBrowser* browser)
-{
-    webView_open(get_nth_webView(-1, browser), config->homepage);
-}
-
-void on_action_location_activate(GtkAction* action, CBrowser* browser)
-{
-    if(GTK_WIDGET_VISIBLE(browser->navibar))
-        gtk_widget_grab_focus(browser->location);
-    else
-    {
-        // TODO: We should offer all of the toolbar location's features here
-        GtkWidget* dialog;
-        dialog = gtk_dialog_new_with_buttons("Open location"
-            , GTK_WINDOW(browser->window)
-            , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR
-            , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL
-            , GTK_STOCK_JUMP_TO, GTK_RESPONSE_ACCEPT
-            , NULL);
-        gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_JUMP_TO);
-        gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
-        gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 5);
-        GtkWidget* hbox = gtk_hbox_new(FALSE, 8);
-        gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
-        GtkWidget* label = gtk_label_new_with_mnemonic("_Location:");
-        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-        GtkWidget* entry = gtk_entry_new();
-        gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
-        gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
-        gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
-        gtk_widget_show_all(hbox);
-        gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
-        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
-        {
-            gtk_entry_set_text(GTK_ENTRY(browser->location)
-             , gtk_entry_get_text(GTK_ENTRY(entry)));
-            GdkEventKey event;
-            event.keyval = GDK_Return;
-            on_location_key_down(browser->location, &event, browser);
-        }
-        gtk_widget_destroy(dialog);
-    }
-}
-
-void on_action_webSearch_activate(GtkAction* action, CBrowser* browser)
-{
-    if(GTK_WIDGET_VISIBLE(browser->webSearch)
-     && GTK_WIDGET_VISIBLE(browser->navibar))
-        gtk_widget_grab_focus(browser->webSearch);
-    else
-    {
-        // TODO: We should offer all of the toolbar search's features here
-        GtkWidget* dialog = gtk_dialog_new_with_buttons("Web search"
-            , GTK_WINDOW(browser->window)
-            , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR
-            , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL
-            , GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT
-            , NULL);
-        gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_FIND);
-        gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
-        gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 5);
-        GtkWidget* hbox = gtk_hbox_new(FALSE, 8);
-        gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
-        GtkWidget* label = gtk_label_new_with_mnemonic("_Location:");
-        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-        GtkWidget* entry = gtk_entry_new();
-        gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
-        gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
-        gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
-        gtk_widget_show_all(hbox);
-        gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
-        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
-        {
-            gtk_entry_set_text(GTK_ENTRY(browser->webSearch)
-             , gtk_entry_get_text(GTK_ENTRY(entry)));
-            on_webSearch_activate(browser->webSearch, browser);
-        }
-        gtk_widget_destroy(dialog);
-    }
-}
-
-void on_menu_tabsClosed_activate(GtkWidget* widget, CBrowser* browser)
-{
-    GtkWidget* menu = gtk_menu_new();
-    guint n = katze_xbel_folder_get_n_items(tabtrash);
-    GtkWidget* menuitem;
-    guint i;
-    for(i = 0; i < n; i++)
-    {
-        KatzeXbelItem* item = katze_xbel_folder_get_nth_item(tabtrash, i);
-        const gchar* title = katze_xbel_item_get_title(item);
-        const gchar* uri = katze_xbel_bookmark_get_href(item);
-        menuitem = gtk_image_menu_item_new_with_label(title ? title : uri);
-        // FIXME: Get the real icon
-        GtkWidget* icon = gtk_image_new_from_stock(GTK_STOCK_FILE, GTK_ICON_SIZE_MENU);
-        gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), icon);
-        gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-        g_object_set_data(G_OBJECT(menuitem), "KatzeXbelItem", item);
-        g_signal_connect(menuitem, "activate", G_CALLBACK(on_menu_tabsClosed_item_activate), browser);
-        gtk_widget_show(menuitem);
-    }
-
-    menuitem = gtk_separator_menu_item_new();
-    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-    gtk_widget_show(menuitem);
-    GtkAction* action = gtk_action_group_get_action(
-     browser->actiongroup, "TabsClosedClear");
-    menuitem = gtk_action_create_menu_item(action);
-    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-    gtk_widget_show(menuitem);
-    sokoke_widget_popup(widget, GTK_MENU(menu), NULL);
-}
-
-void on_menu_tabsClosed_item_activate(GtkWidget* menuitem, CBrowser* browser)
-{
-    // Create a new webView with an uri which has been closed before
-    KatzeXbelItem* item = g_object_get_data(G_OBJECT(menuitem), "KatzeXbelItem");
-    const gchar* uri = katze_xbel_bookmark_get_href(item);
-    CBrowser* curBrowser = browser_new(browser);
-    webView_open(curBrowser->webView, uri);
-    katze_xbel_item_unref(item);
-    update_browser_actions(curBrowser);
-}
-
-void on_action_tabsClosed_undo_activate(GtkAction* action, CBrowser* browser)
-{
-    // Open the most recent tabtrash item
-    KatzeXbelItem* item = katze_xbel_folder_get_nth_item(tabtrash, 0);
-    const gchar* uri = katze_xbel_bookmark_get_href(item);
-    CBrowser* curBrowser = browser_new(browser);
-    webView_open(curBrowser->webView, uri);
-    katze_xbel_item_unref(item);
-    update_browser_actions(curBrowser);
-}
-
-void on_action_tabsClosed_clear_activate(GtkAction* action, CBrowser* browser)
-{
-    // Clear the closed tabs list
-    katze_xbel_item_unref(tabtrash);
-    tabtrash = katze_xbel_folder_new();
-    update_browser_actions(browser);
-}
-
-void on_action_link_tab_new_activate(GtkAction* action, CBrowser* browser)
-{
-    CBrowser* curBrowser = browser_new(browser);
-    webView_open(curBrowser->webView, browser->elementUri);
-}
-
-void on_action_link_tab_current_activate(GtkAction* action, CBrowser* browser)
-{
-    webView_open(get_nth_webView(-1, browser), browser->elementUri);
-}
-
-void on_action_link_window_new_activate(GtkAction* action, CBrowser* browser)
-{
-    CBrowser* curBrowser = browser_new(NULL);
-    webView_open(curBrowser->webView, browser->elementUri);
-}
-
-void on_action_link_saveWith_activate(GtkAction* action, CBrowser* browser)
-{
-    spawn_protocol_command("download", browser->elementUri);
-}
-
-void on_action_link_copy_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
-    gtk_clipboard_set_text(clipboard, browser->elementUri, -1);
-}
-
-static void browser_editBookmark_dialog_new(KatzeXbelItem* bookmark, CBrowser* browser)
-{
-    gboolean newBookmark = !bookmark;
-    GtkWidget* dialog = gtk_dialog_new_with_buttons(
-        newBookmark ? "New bookmark" : "Edit bookmark"
-        , GTK_WINDOW(browser->window)
-        , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR
-        , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL
-        , newBookmark ? GTK_STOCK_ADD : GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT
-        , NULL);
-    gtk_window_set_icon_name(GTK_WINDOW(dialog)
-     , newBookmark ? GTK_STOCK_ADD : GTK_STOCK_REMOVE);
-    gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
-    gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 5);
-    GtkSizeGroup* sizegroup =  gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-
-    if(newBookmark)
-        bookmark = katze_xbel_bookmark_new();
-
-    GtkWidget* hbox = gtk_hbox_new(FALSE, 8);
-    gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
-    GtkWidget* label = gtk_label_new_with_mnemonic("_Title:");
-    gtk_size_group_add_widget(sizegroup, label);
-    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-    GtkWidget* entry_title = gtk_entry_new();
-    gtk_entry_set_activates_default(GTK_ENTRY(entry_title), TRUE);
-    if(!newBookmark)
-    {
-        const gchar* title = katze_xbel_item_get_title(bookmark);
-        gtk_entry_set_text(GTK_ENTRY(entry_title), title ? title : "");
-    }
-    gtk_box_pack_start(GTK_BOX(hbox), entry_title, TRUE, TRUE, 0);
-    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
-    gtk_widget_show_all(hbox);
-
-    hbox = gtk_hbox_new(FALSE, 8);
-    gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
-    label = gtk_label_new_with_mnemonic("_Description:");
-    gtk_size_group_add_widget(sizegroup, label);
-    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-    GtkWidget* entry_desc = gtk_entry_new();
-    gtk_entry_set_activates_default(GTK_ENTRY(entry_desc), TRUE);
-    if(!newBookmark)
-    {
-        const gchar* desc = katze_xbel_item_get_desc(bookmark);
-        gtk_entry_set_text(GTK_ENTRY(entry_desc), desc ? desc : "");
-    }
-    gtk_box_pack_start(GTK_BOX(hbox), entry_desc, TRUE, TRUE, 0);
-    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
-    gtk_widget_show_all(hbox);
-
-    GtkWidget* entry_uri = NULL;
-    if(katze_xbel_item_is_bookmark(bookmark))
-    {
-        hbox = gtk_hbox_new(FALSE, 8);
-        gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
-        label = gtk_label_new_with_mnemonic("_Uri:");
-        gtk_size_group_add_widget(sizegroup, label);
-        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-        entry_uri = gtk_entry_new();
-        gtk_entry_set_activates_default(GTK_ENTRY(entry_uri), TRUE);
-        if(!newBookmark)
-            gtk_entry_set_text(GTK_ENTRY(entry_uri), katze_xbel_bookmark_get_href(bookmark));
-        gtk_box_pack_start(GTK_BOX(hbox), entry_uri, TRUE, TRUE, 0);
-        gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
-        gtk_widget_show_all(hbox);
-    }
-
-    GtkWidget* combo_folder = NULL;
-    if(newBookmark)
-    {
-        hbox = gtk_hbox_new(FALSE, 8);
-        gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
-        label = gtk_label_new_with_mnemonic("_Folder:");
-        gtk_size_group_add_widget(sizegroup, label);
-        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-        combo_folder = gtk_combo_box_new_text();
-        gtk_combo_box_append_text(GTK_COMBO_BOX(combo_folder), "Root");
-        gtk_widget_set_sensitive(combo_folder, FALSE);
-        gtk_box_pack_start(GTK_BOX(hbox), combo_folder, TRUE, TRUE, 0);
-        gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
-        gtk_widget_show_all(hbox);
-    }
-
-    gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
-    if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
-    {
-        katze_xbel_item_set_title(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_title)));
-        katze_xbel_item_set_desc(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_desc)));
-        if(katze_xbel_item_is_bookmark(bookmark))
-            katze_xbel_bookmark_set_href(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_uri)));
-
-        // FIXME: We want to choose a folder
-        if(newBookmark)
-        {
-            katze_xbel_folder_append_item(bookmarks, bookmark);
-            GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks);
-            GtkTreeModel* treemodel = gtk_tree_view_get_model(treeview);
-            GtkTreeIter iter;
-            gtk_tree_store_insert_with_values(GTK_TREE_STORE(treemodel)
-             , &iter, NULL, G_MAXINT, 0, bookmark, -1);
-            katze_xbel_item_ref(bookmark);
-        }
-
-        // FIXME: update toolbar
-        // FIXME: Update panels in other windows
-    }
-    gtk_widget_destroy(dialog);
-}
-
-static void on_panel_bookmarks_row_activated(GtkTreeView* treeview
- , GtkTreePath* path, GtkTreeViewColumn* column, CBrowser* browser)
-{
-    GtkTreeModel* model = gtk_tree_view_get_model(treeview);
-    GtkTreeIter iter;
-    if(gtk_tree_model_get_iter(model, &iter, path))
-    {
-        KatzeXbelItem* item;
-        gtk_tree_model_get(model, &iter, 0, &item, -1);
-        if(katze_xbel_item_is_bookmark(item))
-            webView_open(get_nth_webView(-1, browser), katze_xbel_bookmark_get_href(item));
-    }
-}
-
-static void on_panel_bookmarks_cursor_or_row_changed(GtkTreeView* treeview
- , CBrowser* browser)
-{
-    GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
-    if(selection)
-    {
-        GtkTreeModel* model;
-        GtkTreeIter iter;
-        if(gtk_tree_selection_get_selected(selection, &model, &iter))
-        {
-            KatzeXbelItem* item;
-            gtk_tree_model_get(model, &iter, 0, &item, -1);
-
-            gboolean isSeparator = katze_xbel_item_is_separator(item);
-            action_set_sensitive("BookmarkEdit", !isSeparator, browser);
-            action_set_sensitive("BookmarkDelete", TRUE, browser);
-        }
-        else
-        {
-            action_set_sensitive("BookmarkEdit", FALSE, browser);
-            action_set_sensitive("BookmarkDelete", FALSE, browser);
-        }
-    }
-}
-
-static void panel_bookmarks_popup(GtkWidget* widget, GdkEventButton* event
- , KatzeXbelItem* item, CBrowser* browser)
-{
-    gboolean isBookmark = katze_xbel_item_is_bookmark(item);
-
-    action_set_sensitive("BookmarkOpen", isBookmark, browser);
-    action_set_sensitive("BookmarkOpenTab", isBookmark, browser);
-    action_set_sensitive("BookmarkOpenWindow", isBookmark, browser);
-
-    sokoke_widget_popup(widget, GTK_MENU(browser->popup_bookmark), event);
-}
-
-static gboolean on_panel_bookmarks_button_release(GtkWidget* widget
- , GdkEventButton* event, CBrowser* browser)
-{
-    if(event->button != 2 && event->button != 3)
-        return FALSE;
-
-    GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
-    if(selection)
-    {
-        GtkTreeModel* model;
-        GtkTreeIter iter;
-        if(gtk_tree_selection_get_selected(selection, &model, &iter))
-        {
-            KatzeXbelItem* item;
-            gtk_tree_model_get(model, &iter, 0, &item, -1);
-            if(event->button == 2 && katze_xbel_item_is_bookmark(item))
-            {
-                CBrowser* newBrowser = browser_new(browser);
-                const gchar* uri = katze_xbel_bookmark_get_href(item);
-                webView_open(newBrowser->webView, uri);
-            }
-            else
-                panel_bookmarks_popup(widget, event, item, browser);
-            return TRUE;
-        }
-    }
-    return FALSE;
-}
-
-void on_panel_bookmarks_popup(GtkWidget* widget, CBrowser* browser)
-{
-    GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
-    if(selection)
-    {
-        GtkTreeModel* model;
-        GtkTreeIter iter;
-        if(gtk_tree_selection_get_selected(selection, &model, &iter))
-        {
-            KatzeXbelItem* item;
-            gtk_tree_model_get(model, &iter, 0, &item, -1);
-            panel_bookmarks_popup(widget, NULL, item, browser);
-        }
-    }
-}
-
-void on_action_bookmarkOpen_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks);
-    GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
-    if(selection)
-    {
-        GtkTreeModel* model;
-        GtkTreeIter iter;
-        if(gtk_tree_selection_get_selected(selection, &model, &iter))
-        {
-            KatzeXbelItem* item;
-            gtk_tree_model_get(model, &iter, 0, &item, -1);
-            if(katze_xbel_item_is_bookmark(item))
-                webView_open(get_nth_webView(-1, browser)
-                 , katze_xbel_bookmark_get_href(item));
-        }
-    }
-}
-
-void on_action_bookmarkOpenTab_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks);
-    GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
-    if(selection)
-    {
-        GtkTreeModel* model;
-        GtkTreeIter iter;
-        if(gtk_tree_selection_get_selected(selection, &model, &iter))
-        {
-            KatzeXbelItem* item;
-            gtk_tree_model_get(model, &iter, 0, &item, -1);
-            if(katze_xbel_item_is_bookmark(item))
-            {
-                CBrowser* newBrowser = browser_new(browser);
-                const gchar* uri = katze_xbel_bookmark_get_href(item);
-                webView_open(newBrowser->webView, uri);
-            }
-        }
-    }
-}
-
-void on_action_bookmarkOpenWindow_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks);
-    GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
-    if(selection)
-    {
-        GtkTreeModel* model;
-        GtkTreeIter iter;
-        if(gtk_tree_selection_get_selected(selection, &model, &iter))
-        {
-            KatzeXbelItem* item;
-            gtk_tree_model_get(model, &iter, 0, &item, -1);
-            if(katze_xbel_item_is_bookmark(item))
-            {
-                CBrowser* newBrowser = browser_new(NULL);
-                const gchar* uri = katze_xbel_bookmark_get_href(item);
-                webView_open(newBrowser->webView, uri);
-            }
-        }
-    }
-}
-
-void on_action_bookmarkEdit_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks);
-    GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
-    if(selection)
-    {
-        GtkTreeModel* model;
-        GtkTreeIter iter;
-        if(gtk_tree_selection_get_selected(selection, &model, &iter))
-        {
-            KatzeXbelItem* item;
-            gtk_tree_model_get(model, &iter, 0, &item, -1);
-            if(!katze_xbel_item_is_separator(item))
-                browser_editBookmark_dialog_new(item, browser);
-        }
-    }
-}
-
-void on_action_bookmarkDelete_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks);
-    GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
-    if(selection)
-    {
-        GtkTreeModel* model;
-        GtkTreeIter iter;
-        if(gtk_tree_selection_get_selected(selection, &model, &iter))
-        {
-            KatzeXbelItem* item;
-            gtk_tree_model_get(model, &iter, 0, &item, -1);
-            KatzeXbelItem* parent = katze_xbel_item_get_parent(item);
-            katze_xbel_folder_remove_item(parent, item);
-            katze_xbel_item_unref(item);
-        }
-    }
-}
-
-static void tree_store_insert_folder(GtkTreeStore* treestore, GtkTreeIter* parent
- , KatzeXbelItem* folder)
-{
-    guint n = katze_xbel_folder_get_n_items(folder);
-    guint i;
-    for(i = 0; i < n; i++)
-    {
-        KatzeXbelItem* item = katze_xbel_folder_get_nth_item(folder, i);
-        GtkTreeIter iter;
-        gtk_tree_store_insert_with_values(treestore, &iter, parent, n, 0, item, -1);
-        katze_xbel_item_ref(item);
-        if(katze_xbel_item_is_folder(item))
-            tree_store_insert_folder(treestore, &iter, item);
-    }
-}
-
-static void on_bookmarks_item_render_icon(GtkTreeViewColumn* column
- , GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter
- , GtkWidget* treeview)
-{
-    KatzeXbelItem* item;
-    gtk_tree_model_get(model, iter, 0, &item, -1);
-
-    if(G_UNLIKELY(!item))
-        return;
-    if(G_UNLIKELY(!katze_xbel_item_get_parent(item)))
-    {
-        gtk_tree_store_remove(GTK_TREE_STORE(model), iter);
-        katze_xbel_item_unref(item);
-        return;
-    }
-
-    // TODO: Would it be better to not do this on every redraw?
-    GdkPixbuf* pixbuf = NULL;
-    if(katze_xbel_item_is_bookmark(item))
-        pixbuf = gtk_widget_render_icon(treeview, STOCK_BOOKMARK
-         , GTK_ICON_SIZE_MENU, NULL);
-    else if(katze_xbel_item_is_folder(item))
-        pixbuf = gtk_widget_render_icon(treeview, GTK_STOCK_DIRECTORY
-         , GTK_ICON_SIZE_MENU, NULL);
-    g_object_set(renderer, "pixbuf", pixbuf, NULL);
-    if(pixbuf)
-        g_object_unref(pixbuf);
-}
-
-static void on_bookmarks_item_render_text(GtkTreeViewColumn* column
- , GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter
- , GtkWidget* treeview)
-{
-    KatzeXbelItem* item;
-    gtk_tree_model_get(model, iter, 0, &item, -1);
-
-    if(G_UNLIKELY(!item))
-        return;
-    if(G_UNLIKELY(!katze_xbel_item_get_parent(item)))
-    {
-        gtk_tree_store_remove(GTK_TREE_STORE(model), iter);
-        katze_xbel_item_unref(item);
-        return;
-    }
-
-    if(katze_xbel_item_is_separator(item))
-        g_object_set(renderer
-         , "markup", "<i>Separator</i>", NULL);
-    else
-        g_object_set(renderer
-         , "markup", NULL, "text", katze_xbel_item_get_title(item), NULL);
-}
-
-static void create_bookmark_menu(KatzeXbelItem*, GtkWidget*, CBrowser*);
-
-static void on_bookmark_menu_folder_activate(GtkWidget* menuitem, CBrowser* browser)
-{
-    GtkWidget* menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem));
-    gtk_container_foreach(GTK_CONTAINER(menu), (GtkCallback)gtk_widget_destroy, NULL);//...
-    KatzeXbelItem* folder = (KatzeXbelItem*)g_object_get_data(G_OBJECT(menuitem), "KatzeXbelItem");
-    create_bookmark_menu(folder, menu, browser);
-    // Remove all menuitems when the menu is hidden.
-    // FIXME: We really *want* the line below, but it won't work like that
-    //g_signal_connect_after(menu, "hide", G_CALLBACK(gtk_container_foreach), gtk_widget_destroy);
-    gtk_widget_show(menuitem);
-}
-
-static void on_bookmark_toolbar_folder_activate(GtkToolItem* toolitem, CBrowser* browser)
-{
-    GtkWidget* menu = gtk_menu_new();
-    KatzeXbelItem* folder = (KatzeXbelItem*)g_object_get_data(G_OBJECT(toolitem), "KatzeXbelItem");
-    create_bookmark_menu(folder, menu, browser);
-    // Remove all menuitems when the menu is hidden.
-    // FIXME: We really *should* run the line below, but it won't work like that
-    //g_signal_connect(menu, "hide", G_CALLBACK(gtk_container_foreach), gtk_widget_destroy);
-    sokoke_widget_popup(GTK_WIDGET(toolitem), GTK_MENU(menu), NULL);
-}
-
-void on_menu_bookmarks_item_activate(GtkWidget* widget, CBrowser* browser)
-{
-    KatzeXbelItem* item = (KatzeXbelItem*)g_object_get_data(G_OBJECT(widget), "KatzeXbelItem");
-    webView_open(get_nth_webView(-1, browser), katze_xbel_bookmark_get_href(item));
-}
-
-static void create_bookmark_menu(KatzeXbelItem* folder, GtkWidget* menu, CBrowser* browser)
-{
-    guint n = katze_xbel_folder_get_n_items(folder);
-    guint i;
-    for(i = 0; i < n; i++)
-    {
-        KatzeXbelItem* item = katze_xbel_folder_get_nth_item(folder, i);
-        const gchar* title = katze_xbel_item_is_separator(item) ? "" : katze_xbel_item_get_title(item);
-        //const gchar* desc = katze_xbel_item_is_separator(item) ? "" : katze_xbel_item_get_desc(item);
-        GtkWidget* menuitem = NULL;
-        switch(katze_xbel_item_get_kind(item))
-        {
-        case KATZE_XBEL_ITEM_KIND_FOLDER:
-            // FIXME: what about katze_xbel_folder_is_folded?
-            menuitem = gtk_image_menu_item_new_with_label(title);
-            gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem)
-             , gtk_image_new_from_stock(GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU));
-            GtkWidget* _menu = gtk_menu_new();
-            gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), _menu);
-            g_signal_connect(menuitem, "activate"
-             , G_CALLBACK(on_bookmark_menu_folder_activate), browser);
-            g_object_set_data(G_OBJECT(menuitem), "KatzeXbelItem", item);
-            break;
-        case KATZE_XBEL_ITEM_KIND_BOOKMARK:
-            menuitem = menu_item_new(title, STOCK_BOOKMARK
-             , G_CALLBACK(on_menu_bookmarks_item_activate), TRUE, browser);
-            g_object_set_data(G_OBJECT(menuitem), "KatzeXbelItem", item);
-            break;
-        case KATZE_XBEL_ITEM_KIND_SEPARATOR:
-            menuitem = gtk_separator_menu_item_new();
-            break;
-        default:
-            g_warning("Unknown xbel item kind");
-         }
-         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-         gtk_widget_show(menuitem);
-    }
-}
-
-void on_action_bookmark_new_activate(GtkAction* action, CBrowser* browser)
-{
-    browser_editBookmark_dialog_new(NULL, browser);
-}
-
-void on_action_manageSearchEngines_activate(GtkAction* action, CBrowser* browser)
-{
-    // Show the Manage search engines dialog. Create it if necessary.
-    static GtkWidget* dialog;
-    if(GTK_IS_DIALOG(dialog))
-        gtk_window_present(GTK_WINDOW(dialog));
-    else
-    {
-        dialog = webSearch_manageSearchEngines_dialog_new(browser);
-        gtk_widget_show(dialog);
-    }
-}
-
-void on_action_tab_previous_activate(GtkAction* action, CBrowser* browser)
-{
-    gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(browser->webViews));
-    gtk_notebook_set_current_page(GTK_NOTEBOOK(browser->webViews), page - 1);
-}
-
-void on_action_tab_next_activate(GtkAction* action, CBrowser* browser)
-{
-    // Advance one tab or jump to the first one if we are at the last one
-    gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(browser->webViews));
-    if(page == gtk_notebook_get_n_pages(GTK_NOTEBOOK(browser->webViews)) - 1)
-        page = -1;
-    gtk_notebook_set_current_page(GTK_NOTEBOOK(browser->webViews), page + 1);
-}
-
-void on_window_menu_item_activate(GtkImageMenuItem* widget, CBrowser* browser)
-{
-    gint page = get_webView_index(browser->webView, browser);
-    gtk_notebook_set_current_page(GTK_NOTEBOOK(browser->webViews), page);
-}
-
-void on_action_about_activate(GtkAction* action, CBrowser* browser)
-{
-    gtk_show_about_dialog(GTK_WINDOW(browser->window)
-        , "logo-icon-name", gtk_window_get_icon_name(GTK_WINDOW(browser->window))
-        , "name", PACKAGE_NAME
-        , "version", PACKAGE_VERSION
-        , "comments", "A lightweight web browser."
-        , "copyright", "Copyright Â© 2007 Christian Dywan"
-        , "website", "http://software.twotoasts.de"
-        , "authors", credits_authors
-        , "documenters", credits_documenters
-        , "artists", credits_artists
-        , "license", license
-        , "wrap-license", TRUE
-        //, "translator-credits", _("translator-credits")
-        , NULL);
-}
-
-gboolean on_location_key_down(GtkWidget* widget, GdkEventKey* event, CBrowser* browser)
-{
-    switch(event->keyval)
-    {
-    case GDK_Return:
-    {
-        const gchar* uri = gtk_entry_get_text(GTK_ENTRY(widget));
-        if(uri)
-        {
-            gchar* newUri = magic_uri(uri, TRUE);
-            // TODO: Use newUrl intermediately when completion is better
-            /* TODO Completion should be generated from history, that is
-                    the uri as well as the title. */
-            entry_completion_append(GTK_ENTRY(widget), uri);
-            webView_open(get_nth_webView(-1, browser), newUri);
-            g_free(newUri);
-        }
-        return TRUE;
-    }
-    case GDK_Escape:
-    {
-        GtkWidget* webView = get_nth_webView(-1, browser);
-        WebKitWebFrame* frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(webView));
-        const gchar* uri = webkit_web_frame_get_uri(frame);
-        if(uri && *uri)
-            gtk_entry_set_text(GTK_ENTRY(widget), uri);
-        return TRUE;
-    }
-    }
-    return FALSE;
-}
-
-void on_location_changed(GtkWidget* widget, CBrowser* browser)
-{
-    // Preserve changes to the uri
-    /*const gchar* newUri = gtk_entry_get_text(GTK_ENTRY(widget));
-    katze_xbel_bookmark_set_href(browser->sessionItem, newUri);*/
-    // FIXME: If we want this feature, this is the wrong approach
-}
-
-void on_action_panels_activate(GtkToggleAction* action, CBrowser* browser)
-{
-    config->panelShow = gtk_toggle_action_get_active(action);
-    sokoke_widget_set_visible(browser->panels, config->panelShow);
-}
-
-void on_action_panel_item_activate(GtkRadioAction* action
- , GtkRadioAction* currentAction, CBrowser* browser)
-{
-    g_return_if_fail(GTK_IS_ACTION(action));
-    // TODO: Activating again should hide the contents; how?
-    //gint iValue; gint iCurrentValue;
-    //g_object_get(G_OBJECT(action), "value", &iValue, NULL);
-    //g_object_get(G_OBJECT(currentAction), "value", &iCurrentValue, NULL);
-    //GtkWidget* parent = gtk_widget_get_parent(browser->panels_notebook);
-    //sokoke_widget_set_visible(parent, iCurrentValue == iValue);
-    /*gtk_paned_set_position(GTK_PANED(gtk_widget_get_parent(browser->panels))
-     , iCurrentValue == iValue ? config->iPanelPos : 0);*/
-    config->panelActive = gtk_radio_action_get_current_value(action);
-    gint page = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(currentAction), "iPage"));
-    gtk_notebook_set_current_page(GTK_NOTEBOOK(browser->panels_notebook), page);
-    // This is a special case where activation was not user requested.
-    if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "once-silent")))
-    {
-        config->panelShow = TRUE;
-        gtk_widget_show(browser->panels);
-    }
-    else
-        g_object_set_data(G_OBJECT(action), "once-silent", NULL);
-}
-
-void on_action_openInPanel_activate(GtkAction* action, CBrowser* browser)
-{
-    GtkWidget* webView = get_nth_webView(-1, browser);
-    WebKitWebFrame* frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(webView));
-    const gchar* uri = webkit_web_frame_get_uri(frame);
-    katze_assign(config->panelPageholder, g_strdup(uri));
-    GtkAction* action_pageholder =
-     gtk_action_group_get_action(browser->actiongroup, "PanelPageholder");
-    gint value;
-    g_object_get(G_OBJECT(action_pageholder), "value", &value, NULL);
-    sokoke_radio_action_set_current_value(GTK_RADIO_ACTION(action_pageholder), value);
-    gtk_widget_show(browser->panels);
-    webView_open(browser->panel_pageholder, config->panelPageholder);
-}
-
-
-static void on_panels_notify_position(GObject* object, GParamSpec* arg1
- , CBrowser* browser)
-{
-    config->winPanelPos = gtk_paned_get_position(GTK_PANED(object));
-}
-
-void on_panels_button_close_clicked(GtkWidget* widget, CBrowser* browser)
-{
-    config->panelShow = FALSE;
-    gtk_widget_hide(browser->panels);
-}
-
-gboolean on_notebook_tab_mouse_up(GtkWidget* widget, GdkEventButton* event
- , CBrowser* browser)
-{
-    if(event->button == 1 && event->type == GDK_2BUTTON_PRESS)
-    {
-        // Toggle the label visibility on double click
-        GtkWidget* child = gtk_bin_get_child(GTK_BIN(widget));
-        GList* children = gtk_container_get_children(GTK_CONTAINER(child));
-        child = (GtkWidget*)g_list_nth_data(children, 1);
-        gboolean visible = gtk_widget_get_child_visible(GTK_WIDGET(child));
-        gtk_widget_set_child_visible(GTK_WIDGET(child), !visible);
-        gint a, b; sokoke_widget_get_text_size(browser->webView_name, "M", &a, &b);
-        gtk_widget_set_size_request(child, !visible
-         ? a * config->tabSize : 0, !visible ? -1 : 0);
-        g_list_free(children);
-        return TRUE;
-    }
-    else if(event->button == 2)
-    {
-        // Close the webView on middle click
-        webView_close(browser->webView, browser);
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-gboolean on_notebook_tab_close_clicked(GtkWidget* widget, CBrowser* browser)
-{
-    webView_close(browser->webView, browser);
-    return TRUE;
-}
-
-void on_notebook_switch_page(GtkWidget* widget, GtkNotebookPage* page
- , guint page_num, CBrowser* browser)
-{
-    GtkWidget* webView = get_nth_webView(page_num, browser);
-    browser = get_browser_from_webView(webView);
-    const gchar* uri = katze_xbel_bookmark_get_href(browser->sessionItem);
-    gtk_entry_set_text(GTK_ENTRY(browser->location), uri);
-    const gchar* title = katze_xbel_item_get_title(browser->sessionItem);
-    const gchar* effectiveTitle = title ? title : uri;
-    gchar* windowTitle = g_strconcat(effectiveTitle, " - ", PACKAGE_NAME, NULL);
-    gtk_window_set_title(GTK_WINDOW(browser->window), windowTitle);
-    g_free(windowTitle);
-    update_favicon(browser);
-    update_security(browser);
-    update_gui_state(browser);
-    update_statusbar(browser);
-    update_feeds(browser);
-    update_search_engines(browser);
-}
-
-static void on_window_state_changed(GtkWidget* widget
- , GdkEventWindowState* event, CBrowser* browser)
-{
-    if(event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
-    {
-        if(event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)
-        {
-            gtk_widget_hide(browser->menubar);
-            g_object_set(browser->fullscreen, "stock-id"
-             , GTK_STOCK_LEAVE_FULLSCREEN, NULL);
-            gtk_widget_show(browser->fullscreen);
-        }
-        else
-        {
-            gtk_widget_show(browser->menubar);
-            gtk_widget_hide(browser->fullscreen);
-            g_object_set(browser->fullscreen, "stock-id"
-             , GTK_STOCK_FULLSCREEN, NULL);
-        }
-    }
-}
-
-static void on_window_size_allocate(GtkWidget* widget, GtkAllocation* allocation
- , CBrowser* browser)
-{
-     if(GTK_WIDGET_REALIZED(widget))
-     {
-         GdkWindowState state = gdk_window_get_state(widget->window);
-         if(!(state & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)))
-         {
-             config->winWidth = allocation->width;
-             config->winHeight = allocation->height;
-         }
-     }
-}
-
-gboolean on_window_destroy(GtkWidget* widget, GdkEvent* event, CBrowser* browser)
-{
-    gboolean proceed = TRUE;
-    // TODO: What if there are multiple windows?
-    // TODO: Smart dialog, Ã  la 'Session?: Save, Discard, Cancel'
-    // TODO: Pref startup: session, ask, homepage, blank <-- ask
-    // TODO: Pref quit: session, ask, none <-- ask
-
-    if(0 /*g_list_length(browser_list) > 1*/)
-    {
-        GtkDialog* dialog;
-        dialog = GTK_DIALOG(gtk_message_dialog_new(GTK_WINDOW(browser->window)
-         , GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO
-         , "There is more than one tab open. Do you want to close anyway?"));
-        gtk_window_set_title(GTK_WINDOW(dialog), PACKAGE_NAME);
-        gtk_dialog_set_default_response(dialog, GTK_RESPONSE_YES);
-        proceed = gtk_dialog_run(dialog) == GTK_RESPONSE_YES;
-        gtk_widget_destroy(GTK_WIDGET(dialog));
-    }
-    return !proceed;
-}
-
-// -- Browser creation begins here
-
-CBrowser* browser_new(CBrowser* oldBrowser)
-{
-    CBrowser* browser = g_new0(CBrowser, 1);
-    browsers = g_list_prepend(browsers, browser);
-    browser->sessionItem = katze_xbel_bookmark_new();
-    katze_xbel_item_set_title(browser->sessionItem, "about:blank");
-    katze_xbel_folder_append_item(session, browser->sessionItem);
-
-    GtkWidget* scrolled;
-
-    if(!oldBrowser)
-    {
-
-    GtkWidget* label; GtkWidget* hbox;
-
-    // Setup the window metrics
-    browser->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    g_signal_connect(browser->window, "window-state-event"
-     , G_CALLBACK(on_window_state_changed), browser);
-    GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(browser->window));
-    const gint defaultWidth = (gint)gdk_screen_get_width(screen) / 1.7;
-    const gint defaultHeight = (gint)gdk_screen_get_height(screen) / 1.7;
-    if(config->rememberWinSize)
-    {
-        if(!config->winWidth && !config->winHeight)
-        {
-            config->winWidth = defaultWidth;
-            config->winHeight = defaultWidth;
-        }
-        gtk_window_set_default_size(GTK_WINDOW(browser->window)
-         , config->winWidth, config->winHeight);
-    }
-    else
-        gtk_window_set_default_size(GTK_WINDOW(browser->window)
-         , defaultWidth, defaultHeight);
-    g_signal_connect(browser->window, "size-allocate"
-     , G_CALLBACK(on_window_size_allocate), browser);
-    // FIXME: Use custom program icon
-    gtk_window_set_icon_name(GTK_WINDOW(browser->window), "web-browser");
-    gtk_window_set_title(GTK_WINDOW(browser->window), g_get_application_name());
-    gtk_window_add_accel_group(GTK_WINDOW(browser->window), accel_group);
-    g_signal_connect(browser->window, "delete-event"
-     , G_CALLBACK(on_window_destroy), browser);
-    GtkWidget* vbox = gtk_vbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(browser->window), vbox);
-    gtk_widget_show(vbox);
-
-    // Let us see some ui manager magic
-    browser->actiongroup = gtk_action_group_new("Browser");
-    gtk_action_group_add_actions(browser->actiongroup, entries, entries_n, browser);
-    gtk_action_group_add_toggle_actions(browser->actiongroup
-     , toggle_entries, toggle_entries_n, browser);
-    gtk_action_group_add_radio_actions(browser->actiongroup
-     , refreshevery_entries, refreshevery_entries_n
-     , 300, NULL/*G_CALLBACK(activate_refreshevery_period_action)*/, browser);
-    gtk_action_group_add_radio_actions(browser->actiongroup
-     , panel_entries, panel_entries_n, -1
-     , G_CALLBACK(on_action_panel_item_activate), browser);
-    GtkUIManager* ui_manager = gtk_ui_manager_new();
-    gtk_ui_manager_insert_action_group(ui_manager, browser->actiongroup, 0);
-    gtk_window_add_accel_group(GTK_WINDOW(browser->window)
-     , gtk_ui_manager_get_accel_group(ui_manager));
-
-    GError* error = NULL;
-    if(!gtk_ui_manager_add_ui_from_string(ui_manager, ui_markup, -1, &error))
-    {
-        // TODO: Should this be a message dialog? When does this happen?
-        g_message("User interface couldn't be created: %s", error->message);
-        g_error_free(error);
-    }
-
-    GtkAction* action;
-    // Make all actions except toplevel menus which lack a callback insensitive
-    // This will vanish once all actions are implemented
-    guint i;
-    for(i = 0; i < entries_n; i++)
-    {
-        action = gtk_action_group_get_action(browser->actiongroup, entries[i].name);
-        gtk_action_set_sensitive(action, entries[i].callback || !entries[i].tooltip);
-    }
-    for(i = 0; i < toggle_entries_n; i++)
-    {
-        action = gtk_action_group_get_action(browser->actiongroup
-         , toggle_entries[i].name);
-        gtk_action_set_sensitive(action, toggle_entries[i].callback != NULL);
-    }
-    for(i = 0; i < refreshevery_entries_n; i++)
-    {
-        action = gtk_action_group_get_action(browser->actiongroup
-         , refreshevery_entries[i].name);
-        gtk_action_set_sensitive(action, FALSE);
-    }
-
-    //action_set_active("ToolbarDownloads", config->bToolbarDownloads, browser);
-
-    // Create the menubar
-    browser->menubar = gtk_ui_manager_get_widget(ui_manager, "/menubar");
-    GtkWidget* menuitem = gtk_menu_item_new();
-    gtk_widget_show(menuitem);
-    browser->throbber = katze_throbber_new();
-    gtk_widget_show(browser->throbber);
-    gtk_container_add(GTK_CONTAINER(menuitem), browser->throbber);
-    gtk_widget_set_sensitive(menuitem, FALSE);
-    gtk_menu_item_set_right_justified(GTK_MENU_ITEM(menuitem), TRUE);
-    gtk_menu_shell_append(GTK_MENU_SHELL(browser->menubar), menuitem);
-    gtk_box_pack_start(GTK_BOX(vbox), browser->menubar, FALSE, FALSE, 0);
-    menuitem = gtk_ui_manager_get_widget(ui_manager, "/menubar/Go/TabsClosed");
-    g_signal_connect(menuitem, "activate"
-     , G_CALLBACK(on_menu_tabsClosed_activate), browser);
-    browser->menu_bookmarks = gtk_menu_item_get_submenu(
-     GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui_manager, "/menubar/Bookmarks")));
-    menuitem = gtk_separator_menu_item_new();
-    gtk_widget_show(menuitem);
-    gtk_menu_shell_append(GTK_MENU_SHELL(browser->menu_bookmarks), menuitem);
-    browser->popup_bookmark = gtk_ui_manager_get_widget(ui_manager, "/popup_bookmark");
-    g_object_ref(browser->popup_bookmark);
-    browser->menu_window = gtk_menu_item_get_submenu(
-     GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui_manager, "/menubar/Window")));
-    menuitem = gtk_separator_menu_item_new();
-    gtk_widget_show(menuitem);
-    gtk_menu_shell_append(GTK_MENU_SHELL(browser->menu_window), menuitem);
-    gtk_widget_show(browser->menubar);
-    action_set_sensitive("PrivateBrowsing", FALSE, browser); //...
-    action_set_sensitive("WorkOffline", FALSE, browser); //...
-    browser->popup_webView = gtk_ui_manager_get_widget(ui_manager, "/popup_webView");
-    g_object_ref(browser->popup_webView);
-    browser->popup_element = gtk_ui_manager_get_widget(ui_manager, "/popup_element");
-    g_object_ref(browser->popup_element);
-    browser->popup_editable = gtk_ui_manager_get_widget(ui_manager, "/popup_editable");
-    g_object_ref(browser->popup_editable);
-
-    // Create the navigation toolbar
-    browser->navibar = gtk_ui_manager_get_widget(ui_manager, "/toolbar_navigation");
-    gtk_toolbar_set_style(GTK_TOOLBAR(browser->navibar)
-     , config_to_toolbarstyle(config->toolbarStyle));
-    g_signal_connect(gtk_settings_get_default(), "notify::gtk-toolbar-style"
-     , G_CALLBACK(on_toolbar_navigation_notify_style), browser);
-    gtk_toolbar_set_icon_size(GTK_TOOLBAR(browser->navibar)
-     , config_to_toolbariconsize(config->toolbarSmall));
-    gtk_toolbar_set_show_arrow(GTK_TOOLBAR(browser->navibar), TRUE);
-    gtk_box_pack_start(GTK_BOX(vbox), browser->navibar, FALSE, FALSE, 0);
-    browser->newTab = gtk_ui_manager_get_widget(ui_manager, "/toolbar_navigation/TabNew");
-    action = gtk_action_group_get_action(browser->actiongroup, "Back");
-    g_object_set(action, "is-important", TRUE, NULL);
-
-    // Location entry
-    browser->location = sexy_icon_entry_new();
-    entry_setup_completion(GTK_ENTRY(browser->location));
-    sokoke_entry_set_can_undo(GTK_ENTRY(browser->location), TRUE);
-    browser->location_icon = gtk_image_new();
-    sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->location)
-     , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(browser->location_icon));
-    sexy_icon_entry_add_clear_button(SEXY_ICON_ENTRY(browser->location));
-    g_signal_connect(browser->location, "key-press-event"
-     , G_CALLBACK(on_location_key_down), browser);
-    g_signal_connect(browser->location, "changed"
-     , G_CALLBACK(on_location_changed), browser);
-    GtkToolItem* toolitem = gtk_tool_item_new();
-    gtk_tool_item_set_expand(GTK_TOOL_ITEM(toolitem), TRUE);
-    gtk_container_add(GTK_CONTAINER(toolitem), browser->location);
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->navibar), toolitem, -1);
-
-    // Search entry
-    browser->webSearch = sexy_icon_entry_new();
-    sexy_icon_entry_set_icon_highlight(SEXY_ICON_ENTRY(browser->webSearch)
-     , SEXY_ICON_ENTRY_PRIMARY, TRUE);
-    // TODO: Make this actively resizable or enlarge to fit contents?
-    // FIXME: The interface is somewhat awkward and ought to be rethought
-    // TODO: Display "show in context menu" search engines as "completion actions"
-    entry_setup_completion(GTK_ENTRY(browser->webSearch));
-    sokoke_entry_set_can_undo(GTK_ENTRY(browser->webSearch), TRUE);
-    update_searchEngine(config->searchEngine, browser);
-    g_signal_connect(browser->webSearch, "icon-released"
-     , G_CALLBACK(on_webSearch_icon_released), browser);
-    g_signal_connect(browser->webSearch, "key-press-event"
-     , G_CALLBACK(on_webSearch_key_down), browser);
-    g_signal_connect(browser->webSearch, "scroll-event"
-     , G_CALLBACK(on_webSearch_scroll), browser);
-    g_signal_connect(browser->webSearch, "activate"
-     , G_CALLBACK(on_webSearch_activate), browser);
-    toolitem = gtk_tool_item_new();
-    gtk_container_add(GTK_CONTAINER(toolitem), browser->webSearch);
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->navibar), toolitem, -1);
-    action = gtk_action_group_get_action(browser->actiongroup, "TabsClosed");
-    browser->closedTabs = gtk_action_create_tool_item(action);
-    g_signal_connect(browser->closedTabs, "clicked"
-     , G_CALLBACK(on_menu_tabsClosed_activate), browser);
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->navibar)
-     , GTK_TOOL_ITEM(browser->closedTabs), -1);
-    sokoke_container_show_children(GTK_CONTAINER(browser->navibar));
-    action = gtk_action_group_get_action(browser->actiongroup, "Fullscreen");
-    browser->fullscreen = gtk_action_create_tool_item(action);
-    gtk_widget_hide(browser->fullscreen);
-    g_signal_connect(browser->fullscreen, "clicked"
-     , G_CALLBACK(on_action_fullscreen_activate), browser);
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->navibar)
-     , GTK_TOOL_ITEM(browser->fullscreen), -1);
-    action_set_active("ToolbarNavigation", config->toolbarNavigation, browser);
-
-    // Bookmarkbar
-    browser->bookmarkbar = gtk_toolbar_new();
-    gtk_toolbar_set_icon_size(GTK_TOOLBAR(browser->bookmarkbar), GTK_ICON_SIZE_MENU);
-    gtk_toolbar_set_style(GTK_TOOLBAR(browser->bookmarkbar), GTK_TOOLBAR_BOTH_HORIZ);
-    create_bookmark_menu(bookmarks, browser->menu_bookmarks, browser);
-    for(i = 0; i < katze_xbel_folder_get_n_items(bookmarks); i++)
-    {
-        KatzeXbelItem* item = katze_xbel_folder_get_nth_item(bookmarks, i);
-        const gchar* title = katze_xbel_item_is_separator(item)
-         ? "" : katze_xbel_item_get_title(item);
-        const gchar* desc = katze_xbel_item_is_separator(item)
-         ? "" : katze_xbel_item_get_desc(item);
-        switch(katze_xbel_item_get_kind(item))
-        {
-        case KATZE_XBEL_ITEM_KIND_FOLDER:
-            toolitem = tool_button_new(title, GTK_STOCK_DIRECTORY, TRUE, TRUE
-             , G_CALLBACK(on_bookmark_toolbar_folder_activate), desc, browser);
-            g_object_set_data(G_OBJECT(toolitem), "KatzeXbelItem", item);
-            break;
-        case KATZE_XBEL_ITEM_KIND_BOOKMARK:
-            toolitem = tool_button_new(title, STOCK_BOOKMARK, TRUE, TRUE
-             , G_CALLBACK(on_menu_bookmarks_item_activate), desc, browser);
-            g_object_set_data(G_OBJECT(toolitem), "KatzeXbelItem", item);
-            break;
-        case KATZE_XBEL_ITEM_KIND_SEPARATOR:
-            toolitem = gtk_separator_tool_item_new();
-            break;
-        default:
-            g_warning("Unknown item kind");
-        }
-        gtk_toolbar_insert(GTK_TOOLBAR(browser->bookmarkbar), toolitem, -1);
-    }
-    sokoke_container_show_children(GTK_CONTAINER(browser->bookmarkbar));
-    gtk_box_pack_start(GTK_BOX(vbox), browser->bookmarkbar, FALSE, FALSE, 0);
-    action_set_active("ToolbarBookmarks", config->toolbarBookmarks, browser);
-
-    // Superuser warning
-    if((hbox = sokoke_superuser_warning_new()))
-        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-
-    // Create the panels
-    GtkWidget* hpaned = gtk_hpaned_new();
-    gtk_paned_set_position(GTK_PANED(hpaned), config->winPanelPos);
-    g_signal_connect(hpaned, "notify::position"
-     , G_CALLBACK(on_panels_notify_position), browser);
-    gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0);
-    gtk_widget_show(hpaned);
-
-    browser->panels = gtk_hbox_new(FALSE, 0);
-    gtk_paned_pack1(GTK_PANED(hpaned), browser->panels, FALSE, FALSE);
-    sokoke_widget_set_visible(browser->panels, config->panelShow);
-
-    // Create the panel toolbar
-    GtkWidget* panelbar = gtk_ui_manager_get_widget(ui_manager, "/toolbar_panels");
-    gtk_toolbar_set_style(GTK_TOOLBAR(panelbar), GTK_TOOLBAR_BOTH);
-    gtk_toolbar_set_icon_size(GTK_TOOLBAR(panelbar), GTK_ICON_SIZE_BUTTON);
-    gtk_toolbar_set_orientation(GTK_TOOLBAR(panelbar), GTK_ORIENTATION_VERTICAL); 
-    gtk_box_pack_start(GTK_BOX(browser->panels), panelbar, FALSE, FALSE, 0);
-    action_set_active("Panels", config->panelShow, browser);
-
-    GtkWidget* cbox = gtk_vbox_new(FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(browser->panels), cbox, TRUE, TRUE, 0);
-    gtk_widget_show(cbox);
-
-    // Panels titlebar
-    GtkWidget* labelbar = gtk_toolbar_new();
-    gtk_toolbar_set_icon_size(GTK_TOOLBAR(labelbar), GTK_ICON_SIZE_MENU);
-    gtk_toolbar_set_style(GTK_TOOLBAR(labelbar), GTK_TOOLBAR_ICONS);
-    toolitem = gtk_tool_item_new();
-    gtk_tool_item_set_expand(toolitem, TRUE);
-    label = gtk_label_new_with_mnemonic("_Panels");
-    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-    gtk_container_add(GTK_CONTAINER(toolitem), label);
-    gtk_container_set_border_width(GTK_CONTAINER(toolitem), 6);
-    gtk_toolbar_insert(GTK_TOOLBAR(labelbar), toolitem, -1);
-    // TODO: Does 'goto top' actually indicate 'detach'?
-    toolitem = tool_button_new(NULL, GTK_STOCK_GOTO_TOP, FALSE, TRUE
-     , NULL/*G_CALLBACK(on_panels_button_float_clicked)*/, "Detach panel", browser);
-    gtk_toolbar_insert(GTK_TOOLBAR(labelbar), toolitem, -1);
-    toolitem = tool_button_new(NULL, GTK_STOCK_CLOSE, FALSE, TRUE
-     , G_CALLBACK(on_panels_button_close_clicked), "Close panel", browser);
-    gtk_toolbar_insert(GTK_TOOLBAR(labelbar), toolitem, -1);
-    gtk_box_pack_start(GTK_BOX(cbox), labelbar, FALSE, FALSE, 0);
-    gtk_widget_show_all(labelbar);
-
-    // Notebook, containing all panels
-    browser->panels_notebook = gtk_notebook_new();
-    gtk_notebook_set_show_border(GTK_NOTEBOOK(browser->panels_notebook), FALSE);
-    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(browser->panels_notebook), FALSE);
-      gint page;
-      // Dummy: This is the "fallback" panel for now
-      page = gtk_notebook_append_page(GTK_NOTEBOOK(browser->panels_notebook)
-       , gtk_label_new("empty"), NULL);
-      // Bookmarks
-      GtkWidget* box = gtk_vbox_new(FALSE, 0);
-      GtkWidget* toolbar = gtk_ui_manager_get_widget(ui_manager, "/toolbar_bookmarks");
-      gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar), GTK_ICON_SIZE_MENU);
-      gtk_box_pack_start(GTK_BOX(box), toolbar, FALSE, FALSE, 0);
-      gtk_widget_show(toolbar);
-      GtkTreeViewColumn* column;
-      GtkCellRenderer* renderer_text; GtkCellRenderer* renderer_pixbuf;
-      GtkTreeStore* treestore = gtk_tree_store_new(1, KATZE_TYPE_XBEL_ITEM);
-      GtkWidget* treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(treestore));
-      gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(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)on_bookmarks_item_render_icon, 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)on_bookmarks_item_render_text, treeview, NULL);
-      gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
-      GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL);
-      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled)
-       , GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-      gtk_container_add(GTK_CONTAINER(scrolled), treeview);
-      gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
-      tree_store_insert_folder(GTK_TREE_STORE(treestore), NULL, bookmarks);
-      g_object_unref(treestore);
-      g_signal_connect(treeview, "row-activated"
-       , G_CALLBACK(on_panel_bookmarks_row_activated), browser);
-      g_signal_connect(treeview, "cursor-changed"
-       , G_CALLBACK(on_panel_bookmarks_cursor_or_row_changed), browser);
-      g_signal_connect(treeview, "columns-changed"
-       , G_CALLBACK(on_panel_bookmarks_cursor_or_row_changed), browser);
-      on_panel_bookmarks_cursor_or_row_changed(GTK_TREE_VIEW(treeview), browser);
-      g_signal_connect(treeview, "button-release-event"
-       , G_CALLBACK(on_panel_bookmarks_button_release), browser);
-      g_signal_connect(treeview, "popup-menu"
-       , G_CALLBACK(on_panel_bookmarks_popup), browser);
-      browser->panel_bookmarks = treeview;
-      gtk_box_pack_start(GTK_BOX(box), scrolled, TRUE, TRUE, 0);
-      gtk_widget_show(box);
-      page = gtk_notebook_append_page(GTK_NOTEBOOK(browser->panels_notebook)
-       , box, NULL);
-      action = gtk_action_group_get_action(browser->actiongroup, "PanelBookmarks");
-      g_object_set_data(G_OBJECT(action), "iPage", GINT_TO_POINTER(page));
-      // Pageholder
-      browser->panel_pageholder = webView_new(&scrolled);
-      page = gtk_notebook_append_page(GTK_NOTEBOOK(browser->panels_notebook)
-       , scrolled, NULL);
-      //webView_load_from_uri(browser->panel_pageholder, config->panelPageholder);
-      action = gtk_action_group_get_action(browser->actiongroup, "PanelPageholder");
-      g_object_set_data(G_OBJECT(action), "iPage", GINT_TO_POINTER(page));
-    GtkWidget* frame = gtk_frame_new(NULL);
-    gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
-    gtk_container_add(GTK_CONTAINER(frame), browser->panels_notebook);
-    gtk_box_pack_start(GTK_BOX(cbox), frame, TRUE, TRUE, 0);
-    gtk_widget_show_all(gtk_widget_get_parent(browser->panels_notebook));
-    action = gtk_action_group_get_action(browser->actiongroup, "PanelDownloads");
-    g_object_set_data(G_OBJECT(action), "once-silent", GINT_TO_POINTER(1));
-    sokoke_radio_action_set_current_value(GTK_RADIO_ACTION(action), config->panelActive);
-    sokoke_widget_set_visible(browser->panels, config->panelShow);
-    g_object_unref(ui_manager);
-
-    // Notebook, containing all webViews
-    browser->webViews = gtk_notebook_new();
-    gtk_notebook_set_scrollable(GTK_NOTEBOOK(browser->webViews), TRUE);
-    #if GTK_CHECK_VERSION(2, 10, 0)
-    //gtk_notebook_set_group_id(GTK_NOTEBOOK(browser->webViews), 0);
-    #endif
-    gtk_paned_pack2(GTK_PANED(hpaned), browser->webViews, FALSE, FALSE);
-    gtk_widget_show(browser->webViews);
-
-    // Incremental findbar
-    browser->findbox = gtk_toolbar_new();
-    gtk_toolbar_set_icon_size(GTK_TOOLBAR(browser->findbox), GTK_ICON_SIZE_MENU);
-    gtk_toolbar_set_style(GTK_TOOLBAR(browser->findbox), GTK_TOOLBAR_BOTH_HORIZ);
-    toolitem = gtk_tool_item_new();
-    gtk_container_set_border_width(GTK_CONTAINER(toolitem), 6);
-    gtk_container_add(GTK_CONTAINER(toolitem)
-     , gtk_label_new_with_mnemonic("_Inline find:"));
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1);
-    browser->findbox_text = sexy_icon_entry_new();
-    GtkWidget* icon = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU);
-    sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->findbox_text)
-     , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(icon));
-    sexy_icon_entry_add_clear_button(SEXY_ICON_ENTRY(browser->findbox_text));
-    sokoke_entry_set_can_undo(GTK_ENTRY(browser->findbox_text), TRUE);
-    g_signal_connect(browser->findbox_text, "activate"
-     , G_CALLBACK(on_action_find_next_activate), browser);
-    toolitem = gtk_tool_item_new();
-    gtk_container_add(GTK_CONTAINER(toolitem), browser->findbox_text);
-    gtk_tool_item_set_expand(GTK_TOOL_ITEM(toolitem), TRUE);
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1);
-    toolitem = tool_button_new(NULL, GTK_STOCK_GO_BACK, TRUE, TRUE
-     , G_CALLBACK(on_action_find_previous_activate), NULL, browser);
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1);
-    toolitem = tool_button_new(NULL, GTK_STOCK_GO_FORWARD, TRUE, TRUE
-     , G_CALLBACK(on_action_find_next_activate), NULL, browser);
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1);
-    browser->findbox_case = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_SPELL_CHECK);
-    gtk_tool_button_set_label(GTK_TOOL_BUTTON(browser->findbox_case), "Match Case");
-    gtk_tool_item_set_is_important(GTK_TOOL_ITEM(browser->findbox_case), TRUE);
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), browser->findbox_case, -1);
-    browser->findbox_highlight = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_SELECT_ALL);
-    g_signal_connect(browser->findbox_highlight, "toggled"
-     , G_CALLBACK(on_findbox_highlight_toggled), browser);
-    gtk_tool_button_set_label(GTK_TOOL_BUTTON(browser->findbox_highlight), "Highlight Matches");
-    gtk_tool_item_set_is_important(GTK_TOOL_ITEM(browser->findbox_highlight), TRUE);
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), browser->findbox_highlight, -1);
-    toolitem = gtk_separator_tool_item_new();
-    gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
-    gtk_tool_item_set_expand(GTK_TOOL_ITEM(toolitem), TRUE);
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1);
-    toolitem = tool_button_new(NULL, GTK_STOCK_CLOSE, FALSE, TRUE
-     , G_CALLBACK(on_findbox_button_close_clicked), "Close Findbar", browser);
-    gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1);
-    sokoke_container_show_children(GTK_CONTAINER(browser->findbox));
-    gtk_box_pack_start(GTK_BOX(vbox), browser->findbox, FALSE, FALSE, 0);
-
-    // Statusbar
-    // TODO: fix children overlapping statusbar border
-    browser->statusbar = gtk_statusbar_new();
-    gtk_box_pack_start(GTK_BOX(vbox), browser->statusbar, FALSE, FALSE, 0);
-    browser->progress = gtk_progress_bar_new();
-    // Setting the progressbar's height to 1 makes it fit in the statusbar
-    gtk_widget_set_size_request(browser->progress, -1, 1);
-    gtk_box_pack_start(GTK_BOX(browser->statusbar), browser->progress
-     , FALSE, FALSE, 3);
-    browser->icon_security = gtk_image_new();
-    gtk_box_pack_start(GTK_BOX(browser->statusbar)
-     , browser->icon_security, FALSE, FALSE, 0);
-    gtk_widget_show(browser->icon_security);
-    browser->icon_newsfeed = gtk_image_new_from_icon_name(STOCK_NEWSFEED
-     , GTK_ICON_SIZE_MENU);
-    gtk_box_pack_start(GTK_BOX(browser->statusbar)
-     , browser->icon_newsfeed, FALSE, FALSE, 0);
-    action_set_active("ToolbarStatus", config->toolbarStatus, browser);
-
-    }
-    else
-    {
-
-    browser->window = oldBrowser->window;
-    browser->actiongroup = oldBrowser->actiongroup;
-    browser->menubar = oldBrowser->menubar;
-    browser->menu_bookmarks = oldBrowser->menu_bookmarks;
-    browser->popup_bookmark = oldBrowser->popup_bookmark;
-    browser->menu_window = oldBrowser->menu_window;
-    browser->popup_webView = oldBrowser->popup_webView;
-    browser->popup_element = oldBrowser->popup_element;
-    browser->popup_editable = oldBrowser->popup_editable;
-    browser->throbber = oldBrowser->throbber;
-    browser->navibar = oldBrowser->navibar;
-    browser->newTab = oldBrowser->newTab;
-    browser->location_icon = oldBrowser->location_icon;
-    browser->location = oldBrowser->location;
-    browser->webSearch = oldBrowser->webSearch;
-    browser->closedTabs = oldBrowser->closedTabs;
-    browser->fullscreen = oldBrowser->fullscreen;
-    browser->bookmarkbar = oldBrowser->bookmarkbar;
-    browser->panels = oldBrowser->panels;
-    browser->panels_notebook = oldBrowser->panels_notebook;
-    browser->panel_pageholder = oldBrowser->panel_pageholder;
-    browser->webViews = oldBrowser->webViews;
-    browser->findbox = oldBrowser->findbox;
-    browser->findbox_case = oldBrowser->findbox_case;
-    browser->findbox_highlight = oldBrowser->findbox_highlight;
-    browser->statusbar = oldBrowser->statusbar;
-    browser->progress = oldBrowser->progress;
-    browser->icon_security = oldBrowser->icon_security;
-    browser->icon_newsfeed = oldBrowser->icon_newsfeed;
-
-    }
-
-    // Define some default values
-    browser->hasMenubar = TRUE;
-    browser->hasToolbar = TRUE;
-    browser->hasLocation = TRUE;
-    browser->hasStatusbar = TRUE;
-    browser->elementUri = NULL;
-    browser->loadedPercent = -1; // initially "not loading"
-
-    // Add a window menu item
-    // TODO: Menu items should be ordered like the notebook tabs
-    // TODO: Watch tab reordering in >= gtk 2.10
-    browser->webView_menu = menu_item_new("about:blank", GTK_STOCK_FILE
-     , G_CALLBACK(on_window_menu_item_activate), TRUE, browser);
-    gtk_widget_show(browser->webView_menu);
-    gtk_menu_shell_append(GTK_MENU_SHELL(browser->menu_window), browser->webView_menu);
-
-    // Create a new tab label
-    GtkWidget* eventbox = gtk_event_box_new();
-    gtk_event_box_set_visible_window(GTK_EVENT_BOX(eventbox), FALSE);
-    g_signal_connect(eventbox, "button-release-event"
-     , G_CALLBACK(on_notebook_tab_mouse_up), browser);
-    GtkWidget* hbox = gtk_hbox_new(FALSE, 1);
-    gtk_container_add(GTK_CONTAINER(eventbox), GTK_WIDGET(hbox));
-    browser->webView_icon = katze_throbber_new();
-    katze_throbber_set_static_stock_id(KATZE_THROBBER(browser->webView_icon)
-     , GTK_STOCK_FILE);
-    gtk_box_pack_start(GTK_BOX(hbox), browser->webView_icon, FALSE, FALSE, 0);
-    browser->webView_name = gtk_label_new(katze_xbel_item_get_title(browser->sessionItem));
-    gtk_misc_set_alignment(GTK_MISC(browser->webView_name), 0.0, 0.5);
-    // TODO: make the tab initially look "unvisited" until it's focused
-    // TODO: gtk's tab scrolling is weird?
-    gint w, h;
-    sokoke_widget_get_text_size(browser->webView_name, "M", &w, &h);
-    gtk_widget_set_size_request(GTK_WIDGET(browser->webView_name)
-     , w * config->tabSize, -1);
-    gtk_label_set_ellipsize(GTK_LABEL(browser->webView_name), PANGO_ELLIPSIZE_END);
-    gtk_box_pack_start(GTK_BOX(hbox), browser->webView_name, FALSE, FALSE, 0);
-    browser->webView_close = gtk_button_new();
-    gtk_button_set_relief(GTK_BUTTON(browser->webView_close), GTK_RELIEF_NONE);
-    gtk_button_set_focus_on_click(GTK_BUTTON(browser->webView_close), FALSE);
-    GtkRcStyle* rcstyle = gtk_rc_style_new();
-    rcstyle->xthickness = rcstyle->ythickness = 0;
-    gtk_widget_modify_style(browser->webView_close, rcstyle);
-    GtkWidget* image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
-    gtk_button_set_image(GTK_BUTTON(browser->webView_close), image);
-    gtk_box_pack_start(GTK_BOX(hbox), browser->webView_close, FALSE, FALSE, 0);
-    GtkSettings* gtksettings = gtk_settings_get_default();
-    gint height;
-    gtk_icon_size_lookup_for_settings(gtksettings, GTK_ICON_SIZE_BUTTON, 0, &height);
-    gtk_widget_set_size_request(browser->webView_close, -1, height);
-    gtk_widget_show_all(GTK_WIDGET(eventbox));
-    sokoke_widget_set_visible(browser->webView_close, config->tabClose);
-    g_signal_connect(browser->webView_close, "clicked"
-     , G_CALLBACK(on_notebook_tab_close_clicked), browser);
-
-    // Create a webView inside a scrolled window
-    browser->webView = webView_new(&scrolled);
-    gtk_widget_show(GTK_WIDGET(scrolled));
-    gtk_widget_show(GTK_WIDGET(browser->webView));
-    gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(browser->webViews));
-    page = gtk_notebook_insert_page(GTK_NOTEBOOK(browser->webViews)
-     , scrolled, GTK_WIDGET(eventbox), page + 1);
-    g_signal_connect_after(browser->webViews, "switch-page"
-     , G_CALLBACK(on_notebook_switch_page), browser);
-    #if GTK_CHECK_VERSION(2, 10, 0)
-    gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(browser->webViews), scrolled, TRUE);
-    gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(browser->webViews), scrolled, TRUE);
-    #endif
-
-    // Connect signals
-    #define DOC_CONNECT(__sig, __func) g_signal_connect \
-     (browser->webView, __sig, G_CALLBACK(__func), browser);
-    #define DOC_CONNECTA(__sig, __func) g_signal_connect_after \
-     (browser->webView, __sig, G_CALLBACK(__func), browser);
-    DOC_CONNECT  ("navigation-requested"        , on_webView_navigation_requested)
-    DOC_CONNECT  ("title-changed"               , on_webView_title_changed)
-    DOC_CONNECT  ("icon-loaded"                 , on_webView_icon_changed)
-    DOC_CONNECT  ("load-started"                , on_webView_load_started)
-    DOC_CONNECT  ("load-committed"              , on_webView_load_committed)
-    DOC_CONNECT  ("load-progress-changed"       , on_webView_load_changed)
-    DOC_CONNECT  ("load-finished"               , on_webView_load_finished)
-    DOC_CONNECT  ("status-bar-text-changed"     , on_webView_status_message)
-    DOC_CONNECT  ("hovering-over-link"          , on_webView_link_hover)
-    DOC_CONNECT  ("console-message"             , on_webView_console_message)
-
-    DOC_CONNECT  ("button-press-event"          , on_webView_button_press)
-    DOC_CONNECTA ("button-press-event"          , on_webView_button_press_after)
-    DOC_CONNECT  ("popup-menu"                  , on_webView_popup);
-    DOC_CONNECT  ("scroll-event"                , on_webView_scroll);
-    DOC_CONNECT  ("leave-notify-event"          , on_webView_leave)
-    DOC_CONNECT  ("destroy"                     , on_webView_destroy)
-    #undef DOC_CONNECT
-    #undef DOC_CONNECTA
-
-    webkit_web_view_set_settings(WEBKIT_WEB_VIEW(browser->webView), webSettings);
-
-    // Eventually pack and display everything
-    sokoke_widget_set_visible(browser->navibar, config->toolbarNavigation);
-    sokoke_widget_set_visible(browser->newTab, config->toolbarNewTab);
-    sokoke_widget_set_visible(browser->webSearch, config->toolbarWebSearch);
-    sokoke_widget_set_visible(browser->closedTabs, config->toolbarClosedTabs);
-    sokoke_widget_set_visible(browser->bookmarkbar, config->toolbarBookmarks);
-    sokoke_widget_set_visible(browser->statusbar, config->toolbarStatus);
-    if(!config->openTabsInTheBackground)
-        gtk_notebook_set_current_page(GTK_NOTEBOOK(browser->webViews), page);
-
-    update_browser_actions(browser);
-    gtk_widget_show(browser->window);
-    gtk_widget_grab_focus(GTK_WIDGET(browser->location));
-
-    return browser;
-}
diff --git a/src/browser.h b/src/browser.h
deleted file mode 100644 (file)
index a3c4f3d..0000000
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
-
- 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 __BROWSER_H__
-#define __BROWSER_H__ 1
-
-#include "global.h"
-
-#include <gtk/gtk.h>
-
-// -- Types
-
-typedef struct _CBrowser
-{
-    // shared widgets
-    GtkWidget* window;
-    GtkActionGroup* actiongroup;
-    // menus
-    GtkWidget* menubar;
-    GtkWidget* menu_bookmarks;
-    GtkWidget* popup_bookmark;
-    GtkWidget* menu_window;
-    GtkWidget* popup_webView;
-    GtkWidget* popup_element;
-    GtkWidget* popup_editable;
-    GtkWidget* throbber;
-    // navibar
-    GtkWidget* navibar;
-    GtkWidget* newTab;
-    GtkWidget* location_icon;
-    GtkWidget* location;
-    GtkWidget* webSearch;
-    GtkWidget* closedTabs;
-    GtkWidget* fullscreen;
-    GtkWidget* bookmarkbar;
-    // panels
-    GtkWidget* panels;
-    GtkWidget* panels_notebook;
-    GtkWidget* panel_bookmarks;
-    GtkWidget* panel_pageholder;
-    GtkWidget* webViews;
-    // findbox
-    GtkWidget* findbox;
-    GtkWidget* findbox_text;
-    GtkToolItem* findbox_case;
-    GtkToolItem* findbox_highlight;
-    GtkWidget* statusbar;
-    GtkWidget* progress;
-    GtkWidget* icon_security;
-    GtkWidget* icon_newsfeed;
-
-    // view specific widgets
-    GtkWidget* webView_menu;
-    GtkWidget* webView_icon;
-    GtkWidget* webView_name;
-    GtkWidget* webView_close;
-    GtkWidget* webView;
-
-    // view specific values
-    gboolean hasMenubar;
-    gboolean hasToolbar;
-    gboolean hasLocation;
-    gboolean hasStatusbar;
-    gchar* elementUri; // the element the mouse is hovering on
-    gint loadedPercent; // -1 means "not loading"
-    //UNDEFINED favicon;
-    guint security;
-    gchar* statusMessage; // message from a webView
-    KatzeXbelItem* sessionItem;
-} CBrowser;
-
-enum
-{
-    SEARCH_COL_ICON,
-    SEARCH_COL_TEXT,
-    SEARCH_COL_N
-};
-
-// -- Declarations
-
-void
-on_action_window_new_activate(GtkAction*, CBrowser*);
-
-void
-on_action_tab_new_activate(GtkAction*, CBrowser*);
-
-void
-on_action_open_activate(GtkAction*, CBrowser*);
-
-void
-on_action_tab_close_activate(GtkAction*, CBrowser*);
-
-void
-on_action_window_close_activate(GtkAction*, CBrowser*);
-
-void
-on_action_quit_activate(GtkAction*, CBrowser*);
-
-void
-on_action_edit_activate(GtkAction*, CBrowser*);
-
-void
-on_action_cut_activate(GtkAction*, CBrowser*);
-
-void
-on_action_copy_activate(GtkAction*, CBrowser*);
-
-void
-on_action_paste_activate(GtkAction*, CBrowser*);
-
-void
-on_action_delete_activate(GtkAction*, CBrowser*);
-
-void
-on_action_selectAll_activate(GtkAction*, CBrowser*);
-
-void
-on_action_find_activate(GtkAction*, CBrowser*);
-
-void
-on_action_find_next_activate(GtkAction*, CBrowser*);
-
-void
-on_action_find_previous_activate(GtkAction*, CBrowser*);
-
-void
-on_action_preferences_activate(GtkAction*, CBrowser*);
-
-void
-on_action_toolbar_navigation_activate(GtkToggleAction*, CBrowser*);
-
-void
-on_action_toolbar_bookmarks_activate(GtkToggleAction*, CBrowser*);
-
-void
-on_action_panels_activate(GtkToggleAction*, CBrowser*);
-
-void
-on_action_toolbar_status_activate(GtkToggleAction*, CBrowser*);
-
-void
-on_action_refresh_stop_activate(GtkAction*, CBrowser*);
-
-void
-on_action_zoom_in_activate(GtkAction*, CBrowser*);
-
-void
-on_action_zoom_out_activate(GtkAction*, CBrowser*);
-
-void
-on_action_zoom_normal_activate(GtkAction*, CBrowser*);
-
-void
-on_action_source_view_activate(GtkAction*, CBrowser*);
-
-void
-on_action_fullscreen_activate(GtkAction*, CBrowser*);
-
-void
-on_action_back_activate(GtkAction*, CBrowser*);
-
-void
-on_action_forward_activate(GtkAction*, CBrowser*);
-
-void
-on_action_home_activate(GtkAction*, CBrowser*);
-
-void
-on_action_location_activate(GtkAction*, CBrowser*);
-
-void
-on_action_webSearch_activate(GtkAction*, CBrowser*);
-
-void
-on_action_openInPanel_activate(GtkAction*, CBrowser*);
-
-void
-on_menu_tabsClosed_activate(GtkWidget*, CBrowser*);
-
-void
-on_menu_tabsClosed_item_activate(GtkWidget*, CBrowser*);
-
-void
-on_action_tabsClosed_clear_activate(GtkAction*, CBrowser*);
-
-void
-on_action_tabsClosed_undo_activate(GtkAction*, CBrowser*);
-
-void
-on_action_link_tab_new_activate(GtkAction*, CBrowser*);
-
-void
-on_action_link_tab_current_activate(GtkAction*, CBrowser*);
-
-void
-on_action_link_window_new_activate(GtkAction*, CBrowser*);
-
-void
-on_action_link_saveWith_activate(GtkAction*, CBrowser*);
-
-void
-on_action_link_copy_activate(GtkAction*, CBrowser*);
-
-void
-on_action_bookmarkOpen_activate(GtkAction*, CBrowser*);
-
-void
-on_action_bookmarkOpenTab_activate(GtkAction*, CBrowser*);
-
-void
-on_action_bookmarkOpenWindow_activate(GtkAction*, CBrowser*);
-
-void
-on_action_bookmarkEdit_activate(GtkAction*, CBrowser*);
-
-void
-on_action_bookmarkDelete_activate(GtkAction*, CBrowser*);
-
-void
-on_menu_bookmarks_item_activate(GtkWidget*, CBrowser*);
-
-void
-on_action_bookmark_new_activate(GtkAction*, CBrowser*);
-
-void
-on_action_manageSearchEngines_activate(GtkAction*, CBrowser*);
-
-void
-on_action_tab_previous_activate(GtkAction*, CBrowser*);
-
-void
-on_action_tab_next_activate(GtkAction*, CBrowser*);
-
-void
-on_action_about_activate(GtkAction*, CBrowser*);
-
-gboolean
-on_location_key_down(GtkWidget*, GdkEventKey*, CBrowser*);
-
-CBrowser*
-browser_new(CBrowser*);
-
-// -- Action definitions
-
-// TODO: Fill in a good description for each 'hm?'
-static const GtkActionEntry entries[] = {
- { "File", NULL, "_File" },
- { "WindowNew", STOCK_WINDOW_NEW
- , NULL, "<Ctrl>n"
- , "Open a new window", G_CALLBACK(on_action_window_new_activate) },
- { "TabNew", STOCK_TAB_NEW
- , NULL, "<Ctrl>t"
- , "Open a new tab", G_CALLBACK(on_action_tab_new_activate) },
- { "Open", GTK_STOCK_OPEN
- , NULL, "<Ctrl>o"
- , "Open a file", G_CALLBACK(on_action_open_activate) },
- { "SaveAs", GTK_STOCK_SAVE_AS
- , NULL, "<Ctrl>s"
- , "Save to a file", NULL/*G_CALLBACK(on_action_saveas_activate)*/ },
- { "TabClose", STOCK_TAB_CLOSE
- , NULL, "<Ctrl>w"
- , "Close the current tab", G_CALLBACK(on_action_tab_close_activate) },
- { "WindowClose", STOCK_WINDOW_CLOSE
- , NULL, "<Ctrl><Shift>w"
- , "Close this window", G_CALLBACK(on_action_window_close_activate) },
- { "PageSetup", GTK_STOCK_PROPERTIES
- , "Pa_ge Setup", ""
- , "hm?", NULL/*G_CALLBACK(on_action_page_setup_activate)*/ },
- { "PrintPreview", GTK_STOCK_PRINT_PREVIEW
- , NULL, ""
- , "hm?", NULL/*G_CALLBACK(on_action_print_preview_activate)*/ },
- { "Print", GTK_STOCK_PRINT
- , NULL, "<Ctrl>p"
- , "hm?", NULL/*G_CALLBACK(on_action_print_activate)*/ },
- { "Quit", GTK_STOCK_QUIT
- , NULL, "<Ctrl>q"
- , "Quit the application", G_CALLBACK(on_action_quit_activate) },
-
- { "Edit", NULL, "_Edit", NULL, NULL, G_CALLBACK(on_action_edit_activate) },
- { "Undo", GTK_STOCK_UNDO
- , NULL, "<Ctrl>z"
- , "Undo the last modification", NULL/*G_CALLBACK(on_action_undo_activate)*/ },
- { "Redo", GTK_STOCK_REDO
- , NULL, "<Ctrl><Shift>z"
- , "Redo the last modification", NULL/*G_CALLBACK(on_action_redo_activate)*/ },
- { "Cut", GTK_STOCK_CUT
- , NULL, "<Ctrl>x"
- , "Cut the selected text", G_CALLBACK(on_action_cut_activate) },
- { "Copy", GTK_STOCK_COPY
- , NULL, "<Ctrl>c"
- , "Copy the selected text", G_CALLBACK(on_action_copy_activate) },
- { "Copy_", GTK_STOCK_COPY
- , NULL, "<Ctrl>c"
- , "Copy the selected text", G_CALLBACK(on_action_copy_activate) },
- { "Paste", GTK_STOCK_PASTE
- , NULL, "<Ctrl>v"
- , "Paste text from the clipboard", G_CALLBACK(on_action_paste_activate) },
- { "Delete", GTK_STOCK_DELETE
- , NULL, NULL
- , "Delete the selected text", G_CALLBACK(on_action_delete_activate) },
- { "SelectAll", GTK_STOCK_SELECT_ALL
- , NULL, "<Ctrl>a"
- , "Selected all text", G_CALLBACK(on_action_selectAll_activate) },
- { "FormFill", STOCK_FORM_FILL
- , NULL, ""
- , "hm?", NULL/*G_CALLBACK(on_action_formfill_activate)*/ },
- { "Find", GTK_STOCK_FIND
- , NULL, "<Ctrl>f"
- , "hm?", G_CALLBACK(on_action_find_activate) },
- { "FindNext", GTK_STOCK_GO_FORWARD
- , "Find _Next", "<Ctrl>g"
- , "hm?", G_CALLBACK(on_action_find_next_activate) },
- { "FindPrevious", GTK_STOCK_GO_BACK
- , "Find _Previous", "<Ctrl><Shift>g"
- , "hm?", G_CALLBACK(on_action_find_previous_activate) },
- { "FindQuick", GTK_STOCK_FIND
- , "_Quick Find", "period"
- , "hm?", NULL/*G_CALLBACK(on_action_find_quick_activate)*/ },
- { "ManageSearchEngines", GTK_STOCK_PROPERTIES
- , "_Manage Search Engines", "<Ctrl><Alt>s"
- , "hm?", G_CALLBACK(on_action_manageSearchEngines_activate) }, 
- { "Preferences", GTK_STOCK_PREFERENCES
- , NULL, "<Ctrl><Alt>p"
- , "hm?", G_CALLBACK(on_action_preferences_activate) },
-
- { "View", NULL, "_View" },
- { "Toolbars", NULL, "_Toolbars" },
- { "Refresh", GTK_STOCK_REFRESH
- , NULL, "<Ctrl>r"
- , "Refresh the current page", G_CALLBACK(on_action_refresh_stop_activate) },
- // TODO: Is appointment-new a good choice?
- // TODO: What if it isn't available?
- { "RefreshEvery", "appointment-new"
- , "Refresh _Every...", ""
- , "Refresh the current page", G_CALLBACK(on_action_refresh_stop_activate) },
- { "Stop", GTK_STOCK_STOP
- , NULL, "Escape"
- , "Stop loading of the current page", G_CALLBACK(on_action_refresh_stop_activate) },
- { "RefreshStop", GTK_STOCK_REFRESH
- , NULL, ""
- , NULL, G_CALLBACK(on_action_refresh_stop_activate) },
- { "ZoomIn", GTK_STOCK_ZOOM_IN
- , NULL, "<Ctrl>plus"
- , "hm?", G_CALLBACK(on_action_zoom_in_activate) },
- { "ZoomOut", GTK_STOCK_ZOOM_OUT
- , NULL, "<Ctrl>minus"
- , "hm?", G_CALLBACK(on_action_zoom_out_activate) },
- { "ZoomNormal", GTK_STOCK_ZOOM_100
- , NULL, "<Ctrl>0"
- , "hm?", G_CALLBACK(on_action_zoom_normal_activate) },
- { "BackgroundImage", STOCK_IMAGE
- , "_Background Image", ""
- , "hm?", NULL/*G_CALLBACK(on_action_background_image_activate)*/ },
- { "SourceView", STOCK_SOURCE_VIEW
- , NULL, ""
- , "hm?", /*G_CALLBACK(on_action_source_view_activate)*/ },
- { "SelectionSourceView", STOCK_SOURCE_VIEW
- , "View Selection Source", ""
- , "hm?", NULL/*G_CALLBACK(on_action_selection_source_view_activate)*/ },
- { "Properties", GTK_STOCK_PROPERTIES
- , NULL, ""
- , "hm?", NULL/*G_CALLBACK(on_action_properties_activate)*/ },
- { "Fullscreen", GTK_STOCK_FULLSCREEN
- , NULL, "F11"
- , "Toggle fullscreen view", G_CALLBACK(on_action_fullscreen_activate) },
-
- { "Go", NULL, "_Go" },
- { "Back", GTK_STOCK_GO_BACK
- , NULL, "<Alt>Left"
- , "hm?", G_CALLBACK(on_action_back_activate) },
- { "Forward", GTK_STOCK_GO_FORWARD
- , NULL, "<Alt>Right"
- , "hm?", G_CALLBACK(on_action_forward_activate) },
- { "Home", STOCK_HOMEPAGE
- , NULL, "<Alt>Home"
- , "hm?", G_CALLBACK(on_action_home_activate) },
- { "Location", GTK_STOCK_JUMP_TO
- , "Location...", "<Ctrl>l"
- , "hm?", G_CALLBACK(on_action_location_activate) },
- { "Websearch", GTK_STOCK_FIND
- , "Websearch...", "<Ctrl><Shift>f"
- , "hm?", G_CALLBACK(on_action_webSearch_activate) },
- { "OpenInPageholder", GTK_STOCK_JUMP_TO
- , "Open in Page_holder...", ""
- , "hm?", G_CALLBACK(on_action_openInPanel_activate) },
- { "TabsClosed", STOCK_USER_TRASH
- , "Closed Tabs", ""
- , "hm?", NULL },
- { "TabsClosedClear", GTK_STOCK_CLEAR
- , "Clear List of Closed Tabs", ""
- , "hm?", G_CALLBACK(on_action_tabsClosed_clear_activate) },
- { "UndoTabClose", GTK_STOCK_UNDELETE
- , "Undo Close Tab", ""
- , "hm?", G_CALLBACK(on_action_tabsClosed_undo_activate) },
- { "LinkTabNew", STOCK_TAB_NEW
- , "Open Link in New Tab", ""
- , "hm?", G_CALLBACK(on_action_link_tab_new_activate) },
- { "LinkTabCurrent", NULL
- , "Open Link in Current Tab", ""
- , "hm?", G_CALLBACK(on_action_link_tab_current_activate) },
- { "LinkWindowNew", STOCK_WINDOW_NEW
- , "Open Link in New Window", ""
- , "hm?", G_CALLBACK(on_action_link_window_new_activate) },
- { "LinkBookmarkNew", STOCK_BOOKMARK_NEW
- , NULL, ""
- , "Bookmark this link", NULL/*G_CALLBACK(on_action_link_bookmark_activate)*/ },
- { "LinkSaveAs", GTK_STOCK_SAVE
- , "Save Destination as...", ""
- , "Save destination to a file", NULL/*G_CALLBACK(on_action_link_saveas_activate)*/ },
- { "LinkSaveWith", STOCK_DOWNLOADS
- , "Download Destination", ""
- , "Save destination with the chosen download manager", G_CALLBACK(on_action_link_saveWith_activate) },
- { "LinkCopy", GTK_STOCK_COPY
- , "Copy Link Address", ""
- , "Copy the link address to the clipboard", G_CALLBACK(on_action_link_copy_activate) },
- { "SelectionLinksNewTabs", NULL
- , "Open Selected Links in Tabs", ""
- , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ },
- { "SelectionTextTabNew", STOCK_TAB_NEW
- , "Open <Selection> in New Tab", ""
- , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ },
- { "SelectionTextTabCurrent", NULL
- , "Open <Selection> in Current Tab", ""
- , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ },
- { "SelectionTextWindowNew", STOCK_WINDOW_NEW
- , "Open <Selection> in New Qindow", ""
- , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ },
- { "SelectionSearch", GTK_STOCK_FIND
- , "Search for <Selection>", ""
- , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ },
- { "SelectionSearchWith", GTK_STOCK_FIND
- , "Search for <Selection> with...", ""
- , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ },
- { "ImageViewTabNew", STOCK_TAB_NEW
- , "View Image in New Tab", ""
- , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ },
- { "ImageViewTabCurrent", NULL
- , "View image in current tab", ""
- , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ },
- { "ImageSaveAs", GTK_STOCK_SAVE
- , "Save Image as...", ""
- , "Save image to a file", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ },
- { "ImageSaveWith", STOCK_DOWNLOADS
- , "Download Image", ""
- , "Save image with the chosen download manager", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ },
- { "ImageCopy", GTK_STOCK_COPY
- , "Copy Image Address", ""
- , "Copy the image address to the clipboard", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ },
-
- { "Bookmarks", NULL, "_Bookmarks" },
- { "BookmarkNew", STOCK_BOOKMARK_NEW
- , NULL, "<Ctrl>d"
- , "hm?", G_CALLBACK(on_action_bookmark_new_activate) },
- { "BookmarksManage", STOCK_BOOKMARKS
- , "_Manage Bookmarks", "<Ctrl>b"
- , "hm?", NULL/*G_CALLBACK(on_action_bookmarks_manage_activate)*/ },
- { "BookmarkOpen", GTK_STOCK_OPEN
- , NULL, ""
- , "hm?", G_CALLBACK(on_action_bookmarkOpen_activate) },
- { "BookmarkOpenTab", STOCK_TAB_NEW
- , "Open in New _Tab", ""
- , "hm?", G_CALLBACK(on_action_bookmarkOpenTab_activate) },
- { "BookmarkOpenWindow", STOCK_WINDOW_NEW
- , "Open in New _Window", ""
- , "hm?", G_CALLBACK(on_action_bookmarkOpenWindow_activate) },
- { "BookmarkEdit", GTK_STOCK_EDIT
- , NULL, ""
- , "hm?", G_CALLBACK(on_action_bookmarkEdit_activate) },
- { "BookmarkDelete", GTK_STOCK_DELETE
- , NULL, ""
- , "hm?", G_CALLBACK(on_action_bookmarkDelete_activate) },
-
- { "Tools", NULL, "_Tools" },
-
- { "Window", NULL, "_Window" },
- { "SessionLoad", GTK_STOCK_REVERT_TO_SAVED
- , "_Load Session", ""
- , "hm?", NULL/*G_CALLBACK(on_action_session_load_activate)*/ },
- { "SessionSave", GTK_STOCK_SAVE_AS
- , "_Save Session", ""
- , "hm?", NULL/*G_CALLBACK(on_action_session_save_activate)*/ },
- { "TabPrevious", GTK_STOCK_GO_BACK
- , "_Previous Tab", "<Ctrl>Page_Up"
- , "hm?", G_CALLBACK(on_action_tab_previous_activate) },
- { "TabNext", GTK_STOCK_GO_FORWARD
- , "_Next Tab", "<Ctrl>Page_Down"
- , "hm?", G_CALLBACK(on_action_tab_next_activate) },
- { "TabOverview", NULL
- , "Tab _Overview", ""
- , "hm?", NULL/*G_CALLBACK(on_action_tab_overview_activate)*/ },
-
- { "Help", NULL, "_Help" },
- { "HelpContents", GTK_STOCK_HELP
- , "_Contents", "F1"
- , "hm?", NULL/*G_CALLBACK(on_action_help_contents_activate)*/ },
- { "About", GTK_STOCK_ABOUT
- , NULL, ""
- , "hm?", G_CALLBACK(on_action_about_activate) },
- };
- static const guint entries_n = G_N_ELEMENTS(entries);
-
-static const GtkToggleActionEntry toggle_entries[] = {
- { "PrivateBrowsing", NULL
- , "P_rivate Browsing", ""
- , "hm?", NULL/*G_CALLBACK(on_action_private_browsing_activate)*/
- , FALSE },
- { "WorkOffline", GTK_STOCK_DISCONNECT
- , "_Work Offline", ""
- , "hm?", NULL/*G_CALLBACK(on_action_work_offline_activate)*/
- , FALSE },
-
- { "ToolbarNavigation", NULL
- , "_Navigationbar", ""
- , "hm?", G_CALLBACK(on_action_toolbar_navigation_activate)
- , FALSE },
- { "Panels", NULL
- , "_Panels", "F9"
- , "hm?", G_CALLBACK(on_action_panels_activate)
- , FALSE },
- { "ToolbarBookmarks", NULL
- , "_Bookmarkbar", ""
- , "hm?", G_CALLBACK(on_action_toolbar_bookmarks_activate)
- , FALSE },
- { "ToolbarDownloads", NULL
- , "_Downloadbar", ""
- , "hm?", NULL/*G_CALLBACK(on_action_toolbar_downloads_activate)*/
- , FALSE },
- { "ToolbarStatus", NULL
- , "_Statusbar", ""
- , "hm?", G_CALLBACK(on_action_toolbar_status_activate)
- , FALSE },
- { "RefreshEveryEnable", NULL
- , "_Enabled", ""
- , "hm?", NULL/*G_CALLBACK(on_action_reloadevery_enable_activate)*/
- , FALSE },
- { "ReloadEveryActive", NULL
- , "_Active", ""
- , "hm?", NULL/*G_CALLBACK(on_action_reloadevery_active_activate)*/
- , FALSE },
- };
- static const guint toggle_entries_n = G_N_ELEMENTS(toggle_entries);
-
-static const GtkRadioActionEntry refreshevery_entries[] = {
- { "RefreshEvery30", NULL
- , "30 seconds", ""
- , "Refresh Every _30 Seconds", 30 },
- { "RefreshEvery60", NULL
- , "60 seconds", ""
- , "Refresh Every _60 Seconds", 60 },
- { "RefreshEvery300", NULL
- , "5 minutes", ""
- , "Refresh Every _5 Minutes", 300 },
- { "RefreshEvery900", NULL
- , "15 minutes", ""
- , "Refresh Every _15 Minutes", 900 },
- { "RefreshEvery1800", NULL
- , "30 minutes", ""
- , "Refresh Every 3_0 Minutes", 1800 },
- { "RefreshEveryCustom", NULL
- , "Custom...", ""
- , "Refresh by a _Custom Period", 0 },
- };
- static const guint refreshevery_entries_n = G_N_ELEMENTS(refreshevery_entries);
-
-static const GtkRadioActionEntry panel_entries[] = {
- { "PanelDownloads", STOCK_DOWNLOADS
- , NULL, ""
- , "hm?", 0 },
- { "PanelBookmarks", STOCK_BOOKMARKS
- , "_Bookmarks", ""
- , "hm?", 1 },
- { "PanelConsole", STOCK_CONSOLE
- , NULL, ""
- , "hm?", 2 },
- { "PanelExtensions", STOCK_EXTENSIONS
- , NULL, ""
- , "hm?", 3 },
- { "PanelHistory", STOCK_HISTORY
- , "_History", ""
- , "hm?", 4 },
- // TODO: We want a better icon here, but which one?
- { "PanelTabs", STOCK_TAB_NEW
- , "_Tabs", ""
- , "hm?", 5 },
- // TODO: We probably want another icon here
- { "PanelPageholder", GTK_STOCK_CONVERT
- , "_Pageholder", ""
- , "hm?", 6 },
- };
- static const guint panel_entries_n = G_N_ELEMENTS(panel_entries);
-
-#endif /* !__BROWSER_H__ */
index 868ebd68525a8495400584ff023be97328fb4dc3..e27125c98d46fb2f9a3f6fb36230060fd0b2e397 100644 (file)
 #define __GLOBAL_H__ 1
 
 #include "conf.h"
+
+#include "midori-websettings.h"
 #include "../katze/katze.h"
 
 #include <gtk/gtk.h>
 #include <webkit/webkit.h>
 
-// -- globals
+// FIXME: Remove these globals
 
-CConfig* config;
 GList* searchEngines; // Items of type 'SearchEngine'
-GList* browsers; // Items of type 'CBrowser'
-WebKitWebSettings* webSettings;
-GtkAccelGroup* accel_group;
 KatzeXbelItem* bookmarks;
-KatzeXbelItem* session;
-KatzeXbelItem* tabtrash;
+CConfig* config;
+MidoriWebSettings* webSettings;
 
 // Custom stock items
 
@@ -37,13 +35,7 @@ KatzeXbelItem* tabtrash;
          in order to reduce the amount of warnings :D */
 
 #define STOCK_BOOKMARK           GTK_STOCK_FILE // "stock_bookmark" // "bookmark-web"
-#define STOCK_BOOKMARKS          "bookmark-view"
-#define STOCK_DOWNLOADS          "package" // "download"
-#define STOCK_CONSOLE            "terminal" // "console" // MISSING
-#define STOCK_EXTENSIONS         "extension" // MISSING
 #define STOCK_FORM_FILL          "insert-text" // "form-fill" // MISSING
-#define STOCK_HISTORY            "document-open-recent"
-#define STOCK_HISTORY_           "history-view"
 #define STOCK_LOCATION           "location-entry"
 #define STOCK_NEWSFEED           "gtk-index" // "newsfeed" // MISSING
 #define STOCK_PLUGINS            "plugin" // MISSING
index 04b668374df3480d0f6be1f1471b04a3aa0f42b6..489b8d7ed61827f5bb536d3876fb3b3f22663a03 100644 (file)
 
 #include "helpers.h"
 
+#include "global.h"
 #include "search.h"
 #include "sokoke.h"
-#include "../katze/katze.h"
+
+#include "midori-webview.h"
+#include <katze/katze.h>
 
 #include <string.h>
 #include <webkit/webkit.h>
 
-GtkIconTheme* get_icon_theme(GtkWidget* widget)
-{
-    return gtk_icon_theme_get_for_screen(gtk_widget_get_screen(widget));
-}
-
-GtkWidget* menu_item_new(const gchar* text, const gchar* icon
- , GCallback signal, gboolean sensitive, gpointer userdata)
-{
-    GtkWidget* menuitem;
-    if(text)
-        menuitem = gtk_image_menu_item_new_with_mnemonic(text);
-    else
-        menuitem = gtk_image_menu_item_new_from_stock(icon, NULL);
-    if(icon)
-    {
-        GtkWidget* image = gtk_image_new_from_stock(icon, GTK_ICON_SIZE_MENU);
-        if(gtk_image_get_storage_type(GTK_IMAGE(image)) == GTK_IMAGE_EMPTY)
-            image = gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_MENU);
-        if(gtk_image_get_storage_type(GTK_IMAGE(image)) != GTK_IMAGE_EMPTY)
-            gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
-        else
-            g_print("Note: The icon %s is not available.", icon);
-    }
-    if(signal)
-        g_signal_connect(menuitem, "activate", signal, userdata);
-    gtk_widget_set_sensitive(GTK_WIDGET(menuitem), sensitive && signal);
-    return menuitem;
-}
-
-GtkToolItem* tool_button_new(const gchar* text, const gchar* icon
- , gboolean important, gboolean sensitive, GCallback signal
- , const gchar* tooltip, gpointer userdata)
-{
-    GtkToolItem* toolbutton = gtk_tool_button_new(NULL, NULL);
-    GtkStockItem stockItem;
-    if(gtk_stock_lookup(icon, &stockItem))
-        toolbutton = gtk_tool_button_new_from_stock(icon);
-    else
-    {
-        GtkIconTheme* iconTheme = get_icon_theme(GTK_WIDGET(toolbutton));
-        if(gtk_icon_theme_has_icon(iconTheme, icon))
-            gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolbutton), icon);
-        else
-            gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(toolbutton), GTK_STOCK_MISSING_IMAGE);
-    }
-    if(text)
-        gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolbutton), text);
-    if(important)
-        gtk_tool_item_set_is_important(toolbutton, TRUE);
-    if(signal)
-        g_signal_connect(toolbutton, "clicked", signal, userdata);
-    gtk_widget_set_sensitive(GTK_WIDGET(toolbutton), sensitive && signal);
-    if(tooltip)
-        sokoke_tool_item_set_tooltip_text(toolbutton, tooltip);
-    return toolbutton;
-}
-
 GtkWidget* check_menu_item_new(const gchar* text
- , GCallback signal, gboolean sensitive, gboolean active, CBrowser* browser)
+ , GCallback signal, gboolean sensitive, gboolean active, gpointer userdata)
 {
     GtkWidget* menuitem = gtk_check_menu_item_new_with_mnemonic(text);
     gtk_widget_set_sensitive(menuitem, sensitive && signal);
     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), active);
     if(signal)
-        g_signal_connect(menuitem, "activate", signal, browser);
+        g_signal_connect(menuitem, "activate", signal, userdata);
     return menuitem;
 }
 
@@ -91,10 +37,10 @@ GtkWidget* radio_button_new(GtkRadioButton* radio_button, const gchar* label)
     return gtk_radio_button_new_with_mnemonic_from_widget(radio_button, label);
 }
 
-void show_error(const gchar* text, const gchar* text2, CBrowser* browser)
+void show_error(const gchar* text, const gchar* text2, MidoriBrowser* browser)
 {
     GtkWidget* dialog = gtk_message_dialog_new(
-     browser ? GTK_WINDOW(browser->window) : NULL
+     browser ? GTK_WINDOW(browser) : NULL
       , 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, text);
     if(text2)
         gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), text2);
@@ -191,223 +137,6 @@ void entry_completion_append(GtkEntry* entry, const gchar* text)
     gtk_list_store_set(GTK_LIST_STORE(completion_store), &iter, 0, text, -1);
 }
 
-GtkWidget* get_nth_webView(gint n, CBrowser* browser)
-{
-    if(n < 0)
-        n = gtk_notebook_get_current_page(GTK_NOTEBOOK(browser->webViews));
-    GtkWidget* scrolled = gtk_notebook_get_nth_page(GTK_NOTEBOOK(browser->webViews), n);
-    return gtk_bin_get_child(GTK_BIN(scrolled));
-}
-
-gint get_webView_index(GtkWidget* webView, CBrowser* browser)
-{
-    GtkWidget* scrolled = gtk_widget_get_parent(webView);
-    return gtk_notebook_page_num(GTK_NOTEBOOK(browser->webViews), scrolled);
-}
-
-CBrowser* get_browser_from_webView(GtkWidget* webView)
-{
-    // FIXME: g_list_first
-    CBrowser* browser = NULL; GList* item = g_list_first(browsers);
-    do
-    {
-        browser = (CBrowser*)item->data;
-        if(browser->webView == webView)
-            return browser;
-    }
-    while((item = g_list_next(item)));
-    return NULL;
-}
-
-void update_favicon(CBrowser* browser)
-{
-    if(browser->loadedPercent == -1)
-    {
-        if(0) //browser->favicon // Has favicon?
-        {
-            // TODO: use custom icon
-            // gtk_image_set_from_file(GTK_IMAGE(browser->icon_page), "image");
-        }
-        else if(0) // Known mime-type?
-        {
-            // TODO: Retrieve mime type and load icon; don't forget ftp listings
-        }
-        else
-            katze_throbber_set_static_stock_id(KATZE_THROBBER(browser->webView_icon)
-             , GTK_STOCK_FILE);
-    }
-    katze_throbber_set_animated(KATZE_THROBBER(browser->webView_icon)
-     , browser->loadedPercent != -1);
-}
-
-void update_security(CBrowser* browser)
-{
-    const gchar* uri = katze_xbel_bookmark_get_href(browser->sessionItem);
-    // TODO: This check is bogus, until webkit tells us how secure a page is
-    if(g_str_has_prefix(uri, "https://"))
-    {
-        // TODO: highlighted entry indicates security, find an alternative
-        gtk_widget_modify_base(browser->location, GTK_STATE_NORMAL
-         , &browser->location->style->base[GTK_STATE_SELECTED]);
-        gtk_widget_modify_text(browser->location, GTK_STATE_NORMAL
-         , &browser->location->style->text[GTK_STATE_SELECTED]);
-        gtk_image_set_from_stock(GTK_IMAGE(browser->icon_security)
-         , GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_MENU);
-    }
-    else
-    {
-        gtk_widget_modify_base(browser->location, GTK_STATE_NORMAL, NULL);
-        gtk_widget_modify_text(browser->location, GTK_STATE_NORMAL, NULL);
-        gtk_image_set_from_stock(GTK_IMAGE(browser->icon_security)
-         , GTK_STOCK_INFO, GTK_ICON_SIZE_MENU);
-    }
-}
-
-void update_visibility(CBrowser* browser, gboolean visibility)
-{
-    // A tabbed window shouldn't be manipulatable
-    if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(browser->webViews)) > 1)
-        return;
-
-    // SHOULD SCRIPTS BE ABLE TO HIDE WINDOWS AT ALL?
-    if(0 && !visibility)
-    {
-        gtk_widget_hide(browser->window);
-        return;
-    }
-    else if(!visibility)
-        g_print("Window was not hidden.\n");
-
-    sokoke_widget_set_visible(browser->menubar, browser->hasMenubar);
-    sokoke_widget_set_visible(browser->navibar, browser->hasToolbar);
-    sokoke_widget_set_visible(browser->location, browser->hasLocation);
-    sokoke_widget_set_visible(browser->webSearch, browser->hasLocation);
-    sokoke_widget_set_visible(browser->statusbar, browser->hasStatusbar);
-}
-
-void action_set_active(const gchar* name, gboolean active, CBrowser* browser)
-{
-    // This shortcut toggles activity state by an action name
-    GtkAction* action = gtk_action_group_get_action(browser->actiongroup, name);
-    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), active);
-}
-
-void action_set_sensitive(const gchar* name, gboolean sensitive, CBrowser* browser)
-{
-    // This shortcut toggles sensitivity by an action name
-    GtkAction* action = gtk_action_group_get_action(browser->actiongroup, name);
-    gtk_action_set_sensitive(action, sensitive);
-}
-
-void action_set_visible(const gchar* name, gboolean visible, CBrowser* browser)
-{
-    // This shortcut toggles visibility by an action name
-    GtkAction* action = gtk_action_group_get_action(browser->actiongroup, name);
-    gtk_action_set_visible(action, visible);
-}
-
-void update_statusbar(CBrowser* browser)
-{
-    gtk_statusbar_pop(GTK_STATUSBAR(browser->statusbar), 1);
-    gtk_statusbar_push(GTK_STATUSBAR(browser->statusbar), 1
-     , browser->statusMessage ? browser->statusMessage : "");
-    if(browser->loadedPercent > -1)
-    {
-        if(browser->loadedPercent > -1)
-            gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(browser->progress)
-             , browser->loadedPercent ? browser->loadedPercent / 100.0 : 0);
-        else
-            gtk_progress_bar_pulse(GTK_PROGRESS_BAR(browser->progress));
-        gchar* message = g_strdup_printf("%d%% loaded", browser->loadedPercent);
-        gtk_progress_bar_set_text(GTK_PROGRESS_BAR(browser->progress), message);
-        g_free(message);
-    }
-}
-
-void update_edit_items(CBrowser* browser)
-{
-    GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window));
-    gboolean canCut = FALSE; gboolean canCopy = FALSE; gboolean canPaste = FALSE;
-    if(widget && (WEBKIT_IS_WEB_VIEW(widget) || GTK_IS_EDITABLE(widget)))
-    {
-        gboolean hasSelection = WEBKIT_IS_WEB_VIEW(widget)
-         ? webkit_web_view_has_selection(WEBKIT_WEB_VIEW(widget))
-         : gtk_editable_get_selection_bounds(GTK_EDITABLE(widget), NULL, NULL);
-        canCut = WEBKIT_IS_WEB_VIEW(widget)
-         ? webkit_web_view_can_cut_clipboard(WEBKIT_WEB_VIEW(widget))
-         : hasSelection && gtk_editable_get_editable(GTK_EDITABLE(widget));
-        canCopy = WEBKIT_IS_WEB_VIEW(widget)
-         ? webkit_web_view_can_copy_clipboard(WEBKIT_WEB_VIEW(widget))
-         : hasSelection;
-        canPaste = WEBKIT_IS_WEB_VIEW(widget)
-         ? webkit_web_view_can_paste_clipboard(WEBKIT_WEB_VIEW(widget))
-         : gtk_editable_get_editable(GTK_EDITABLE(widget));
-        action_set_sensitive("SelectAll", TRUE, browser);
-    }
-    else
-        action_set_sensitive("SelectAll", FALSE, browser);
-    action_set_sensitive("Cut", canCut, browser);
-    action_set_sensitive("Copy", canCopy, browser);
-    action_set_sensitive("Paste", canPaste, browser);
-    action_set_sensitive("Delete", canCut, browser);
-}
-
-void update_gui_state(CBrowser* browser)
-{
-    GtkWidget* webView = get_nth_webView(-1, browser);
-    action_set_sensitive("ZoomIn", FALSE, browser);//webkit_web_view_can_increase_text_size(WEBKIT_WEB_VIEW(webView), browser);
-    action_set_sensitive("ZoomOut", FALSE, browser);//webkit_web_view_can_decrease_text_size(WEBKIT_WEB_VIEW(webView)), browser);
-    action_set_sensitive("ZoomNormal", FALSE, browser);//webkit_web_view_get_text_size(WEBKIT_WEB_VIEW(webView)) != 1, browser);
-    action_set_sensitive("Back", webkit_web_view_can_go_back(WEBKIT_WEB_VIEW(webView)), browser);
-    action_set_sensitive("Forward", webkit_web_view_can_go_forward(WEBKIT_WEB_VIEW(webView)), browser);
-    action_set_sensitive("Refresh", browser->loadedPercent == -1, browser);
-    action_set_sensitive("Stop", browser->loadedPercent != -1, browser);
-
-    GtkAction* action = gtk_action_group_get_action(browser->actiongroup, "RefreshStop");
-    if(browser->loadedPercent == -1)
-    {
-        gtk_widget_set_sensitive(browser->throbber, FALSE);
-        g_object_set(action, "stock-id", GTK_STOCK_REFRESH, NULL);
-        g_object_set(action, "tooltip", "Refresh the current page", NULL);
-        gtk_widget_hide(browser->progress);
-    }
-    else
-    {
-        gtk_widget_set_sensitive(browser->throbber, TRUE);
-        g_object_set(action, "stock-id", GTK_STOCK_STOP, NULL);
-        g_object_set(action, "tooltip", "Stop loading the current page", NULL);
-        gtk_widget_show(browser->progress);
-    }
-    katze_throbber_set_animated(KATZE_THROBBER(browser->throbber)
-     , browser->loadedPercent != -1);
-
-    gtk_image_set_from_stock(GTK_IMAGE(browser->location_icon), GTK_STOCK_FILE
-     , GTK_ICON_SIZE_MENU);
-}
-
-void update_feeds(CBrowser* browser)
-{
-    // TODO: Look for available feeds, requires dom access
-}
-
-void update_search_engines(CBrowser* browser)
-{
-    // TODO: Look for available search engines, requires dom access
-}
-
-void update_browser_actions(CBrowser* browser)
-{
-    gboolean active = gtk_notebook_get_n_pages(GTK_NOTEBOOK(browser->webViews)) > 1;
-    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(browser->webViews), active);
-    action_set_sensitive("TabClose", active, browser);
-    action_set_sensitive("TabPrevious", active, browser);
-    action_set_sensitive("TabNext", active, browser);
-
-    gboolean tabtrashEmpty = katze_xbel_folder_is_empty(tabtrash);
-    action_set_sensitive("UndoTabClose", !tabtrashEmpty, browser);
-    action_set_sensitive("TabsClosed", !tabtrashEmpty, browser);
-}
-
 gchar* magic_uri(const gchar* uri, gboolean search)
 {
     // Add file:// if we have a local path
index c1812166eccf34bc18ac9c04bafd0c969de902f8..0db7400f71df5cc28f09a95192759ef487cfdf7c 100644 (file)
 #ifndef __HELPERS_H__
 #define __HELPERS_H__ 1
 
-#include "browser.h"
-
 #include <gtk/gtk.h>
 
-GtkIconTheme*
-get_icon_theme(GtkWidget*);
-
-GtkWidget*
-menu_item_new(const gchar*, const gchar*, GCallback, gboolean, gpointer);
-
-GtkToolItem*
-tool_button_new(const gchar*, const gchar*
- , gboolean, gboolean, GCallback, const gchar*, gpointer);
+#include "midori-browser.h"
 
 GtkWidget*
-check_menu_item_new(const gchar*, GCallback, gboolean, gboolean, CBrowser*);
+check_menu_item_new(const gchar*, GCallback, gboolean, gboolean, gpointer);
 
 GtkWidget*
 radio_button_new(GtkRadioButton*, const gchar*);
 
 void
-show_error(const gchar*, const gchar*, CBrowser*);
+show_error(const gchar*, const gchar*, MidoriBrowser*);
 
 gboolean
 spawn_protocol_command(const gchar*, const gchar*);
@@ -47,51 +37,6 @@ entry_setup_completion(GtkEntry*);
 void
 entry_completion_append(GtkEntry*, const gchar*);
 
-GtkWidget*
-get_nth_webView(gint, CBrowser*);
-
-gint
-get_webView_index(GtkWidget*, CBrowser*);
-
-CBrowser*
-get_browser_from_webView(GtkWidget*);
-
-void
-update_favicon(CBrowser*);
-
-void
-update_security(CBrowser*);
-
-void
-update_visibility(CBrowser*, gboolean);
-
-void
-action_set_active(const gchar*, gboolean, CBrowser*);
-
-void
-action_set_sensitive(const gchar*, gboolean, CBrowser*);
-
-void
-action_set_visible(const gchar*, gboolean, CBrowser*);
-
-void
-update_statusbar(CBrowser*);
-
-void
-update_edit_items(CBrowser*);
-
-void
-update_gui_state(CBrowser*);
-
-void
-update_feeds(CBrowser*);
-
-void
-update_search_engines(CBrowser*);
-
-void
-update_browser_actions(CBrowser*);
-
 gchar*
 magic_uri(const gchar*, gboolean bSearch);
 
old mode 100755 (executable)
new mode 100644 (file)
index 55e2348..2fdf185
 
 #include "main.h"
 
-#include "browser.h"
 #include "global.h"
 #include "helpers.h"
 #include "sokoke.h"
 #include "search.h"
-#include "webView.h"
-#include "../katze/katze.h"
+
+#include "midori-websettings.h"
+#include "midori-trash.h"
+#include "midori-browser.h"
+#include <katze/katze.h>
 
 #include <string.h>
 #include <gtk/gtk.h>
-#include <webkit/webkit.h>
 
 #include "config.h"
 
@@ -40,12 +41,7 @@ static void stock_items_init(void)
 
         { STOCK_BOOKMARK,       "Bookmark", 0, 0, NULL },
         { STOCK_BOOKMARK_NEW,   "New Bookmark", 0, 0, NULL },
-        { STOCK_BOOKMARKS,      "_Bookmarks", 0, 0, NULL },
-        { STOCK_DOWNLOADS,      "_Downloads", 0, 0, NULL },
-        { STOCK_CONSOLE,        "_Console", 0, 0, NULL },
-        { STOCK_EXTENSIONS,     "_Extensions", 0, 0, NULL },
         { STOCK_FORM_FILL,      "_Form Fill", 0, 0, NULL },
-        { STOCK_HISTORY,        "History", 0, 0, NULL },
         { STOCK_HOMEPAGE,       "Homepage", 0, 0, NULL },
         { STOCK_LOCATION,       "Location Entry", 0, 0, NULL },
         { STOCK_NEWSFEED,       "Newsfeed", 0, 0, NULL },
@@ -81,7 +77,46 @@ static void stock_items_init(void)
     g_object_unref(factory);
 }
 
-// -- main function
+static gboolean
+midori_browser_delete_event_cb (MidoriBrowser* browser,
+                                GdkEvent*      event,
+                                GList*         browsers)
+{
+    browsers = g_list_remove (browsers, browser);
+    if (g_list_nth (browsers, 0))
+        return FALSE;
+    gtk_main_quit ();
+    return TRUE;
+}
+
+static void
+midori_browser_quit_cb (MidoriBrowser* browser,
+                        GdkEvent*      event,
+                        GList*         browsers)
+{
+    gtk_main_quit ();
+}
+
+static void
+midori_browser_new_window_cb (MidoriBrowser* browser,
+                              const gchar*   uri,
+                              GList*         browsers)
+{
+    MidoriBrowser* new_browser = g_object_new (MIDORI_TYPE_BROWSER,
+                                               // "settings", settings,
+                                               // "trash", trash,
+                                               NULL);
+    // gtk_window_add_accel_group (GTK_WINDOW (browser), accel_group);
+    g_object_connect (new_browser,
+        "signal::new-window", midori_browser_new_window_cb, browsers,
+        "signal::delete-event", midori_browser_delete_event_cb, browsers,
+        "signal::quit", midori_browser_quit_cb, browsers,
+        NULL);
+    browsers = g_list_prepend(browsers, new_browser);
+    gtk_widget_show (GTK_WIDGET (new_browser));
+
+    midori_browser_append_uri (new_browser, uri);
+}
 
 int main(int argc, char** argv)
 {
@@ -105,7 +140,7 @@ int main(int argc, char** argv)
 
     if(version)
     {
-        g_print(PACKAGE_STRING " - Copyright (c) 2007 Christian Dywan\n\n"
+        g_print(PACKAGE_STRING " - Copyright (c) 2007-2008 Christian Dywan\n\n"
          "GTK+2:      " GTK_VER "\n"
          "WebKit:     " WEBKIT_VER "\n"
          "Libsexy:    " LIBSEXY_VER "\n"
@@ -128,7 +163,7 @@ int main(int argc, char** argv)
     g_mkdir_with_parents(configPath, 0755);
     gchar* configFile = g_build_filename(configPath, "config", NULL);
     error = NULL;
-    config = config_new();
+    /*CConfig* */config = config_new();
     if(!config_from_file(config, configFile, &error))
     {
         if(error->code != G_FILE_ERROR_NOENT)
@@ -178,9 +213,9 @@ int main(int argc, char** argv)
         g_free(configFile);
     }
     configFile = g_build_filename(configPath, "tabtrash.xbel", NULL);
-    tabtrash = katze_xbel_folder_new();
+    KatzeXbelItem* xbel_trash = katze_xbel_folder_new();
     error = NULL;
-    if(!katze_xbel_folder_from_file(tabtrash, configFile, &error))
+    if(!katze_xbel_folder_from_file(xbel_trash, configFile, &error))
     {
         if(error->code != G_FILE_ERROR_NOENT)
             g_string_append_printf(errorMessages
@@ -211,6 +246,7 @@ int main(int argc, char** argv)
             search_engines_free(searchEngines);
             katze_xbel_item_unref(bookmarks);
             katze_xbel_item_unref(_session);
+            katze_xbel_item_unref(xbel_trash);
             g_string_free(errorMessages, TRUE);
             return 0;
         }
@@ -245,37 +281,68 @@ int main(int argc, char** argv)
     }
     g_free(configPath);
 
-    accel_group = gtk_accel_group_new();
     stock_items_init();
-    browsers = NULL;
 
-    webSettings = g_object_new(WEBKIT_TYPE_WEB_SETTINGS
-     , "default-font-family" , config->defaultFontFamily
-     , "default-font-size"   , config->defaultFontSize
-     , "minimum-font-size"   , config->minimumFontSize
-     , "default-encoding"    , config->defaultEncoding
-     , "auto-load-images"    , config->autoLoadImages
-     , "auto-shrink-images"  , config->autoShrinkImages
-     , "print-backgrounds"   , config->printBackgrounds
-     , "resizable-text-areas", config->resizableTextAreas
-     , "user-stylesheet-uri" , config->userStylesheet ? config->userStylesheetUri : NULL
-     , "enable-scripts"      , config->enableScripts
-     , "enable-plugins"      , config->enablePlugins
-     , NULL);
+    MidoriWebSettings* settings;
+    settings = g_object_new (MIDORI_TYPE_WEB_SETTINGS,
+                             "default-font-family", config->defaultFontFamily,
+                             "default-font-size", config->defaultFontSize,
+                             "minimum-font-size", config->minimumFontSize,
+                             "default-encoding", config->defaultEncoding,
+                             "auto-load-images", config->autoLoadImages,
+                             "auto-shrink-images", config->autoShrinkImages,
+                             "print-backgrounds", config->printBackgrounds,
+                             "resizable-text-areas", config->resizableTextAreas,
+                             "user-stylesheet-uri",
+                             config->userStylesheet ?
+                             config->userStylesheetUri : NULL,
+                             "enable-scripts", config->enableScripts,
+                             "enable-plugins", config->enablePlugins,
+                             "tab-label-size", config->tabSize,
+                             "close-button", config->tabClose,
+                             "middle-click-goto", config->middleClickGoto,
+                             NULL);
+    webSettings = settings;
 
-    session = katze_xbel_folder_new();
-    CBrowser* browser = NULL;
-    guint n = katze_xbel_folder_get_n_items(_session);
+    MidoriTrash* trash = g_object_new (MIDORI_TYPE_TRASH,
+                                       "limit", 10,
+                                       NULL);
     guint i;
-    for(i = 0; i < n; i++)
+    guint n = katze_xbel_folder_get_n_items (xbel_trash);
+    for (i = 0; i < n; i++)
     {
-        KatzeXbelItem* item = katze_xbel_folder_get_nth_item(_session, i);
-        browser = browser_new(browser);
-        webView_open(browser->webView, katze_xbel_bookmark_get_href(item));
+        KatzeXbelItem* item = katze_xbel_folder_get_nth_item (xbel_trash, i);
+        midori_trash_prepend_xbel_item (trash, item);
     }
-    katze_xbel_item_unref(_session);
 
-    gtk_main();
+    GtkAccelGroup* accel_group = gtk_accel_group_new();
+    GList* browsers = NULL;
+
+    MidoriBrowser* browser = g_object_new (MIDORI_TYPE_BROWSER,
+                                           "settings", settings,
+                                           "trash", trash,
+                                           NULL);
+    gtk_window_add_accel_group (GTK_WINDOW (browser), accel_group);
+    g_object_connect (browser,
+        "signal::new-window", midori_browser_new_window_cb, browsers,
+        "signal::delete-event", midori_browser_delete_event_cb, browsers,
+        "signal::quit", midori_browser_quit_cb, browsers,
+        NULL);
+    browsers = g_list_prepend(browsers, browser);
+    gtk_widget_show (GTK_WIDGET (browser));
+
+    KatzeXbelItem* session = katze_xbel_folder_new ();
+    n = katze_xbel_folder_get_n_items (_session);
+    for (i = 0; i < n; i++)
+    {
+        KatzeXbelItem* item = katze_xbel_folder_get_nth_item (_session, i);
+        midori_browser_append_xbel_item (browser, item);
+    }
+    katze_xbel_item_unref (_session);
+
+    gtk_main ();
+
+    g_object_unref (accel_group);
 
     // Save configuration files
     configPath = g_build_filename(g_get_user_config_dir(), PACKAGE_NAME, NULL);
@@ -300,13 +367,13 @@ int main(int argc, char** argv)
     g_free(configFile);
     configFile = g_build_filename(configPath, "tabtrash.xbel", NULL);
     error = NULL;
-    if(!katze_xbel_folder_to_file(tabtrash, configFile, &error))
+    if (!katze_xbel_folder_to_file (xbel_trash, configFile, &error))
     {
-        g_warning("Tabtrash couldn't be saved. %s", error->message);
-        g_error_free(error);
+        g_warning ("Tabtrash couldn't be saved. %s", error->message);
+        g_error_free (error);
     }
-    katze_xbel_item_unref(tabtrash);
-    g_free(configFile);
+    katze_xbel_item_unref (xbel_trash);
+    g_free (configFile);
     if(config->startup == CONFIG_STARTUP_SESSION)
     {
         configFile = g_build_filename(configPath, "session.xbel", NULL);
diff --git a/src/midori-browser.c b/src/midori-browser.c
new file mode 100644 (file)
index 0000000..21e5476
--- /dev/null
@@ -0,0 +1,2986 @@
+/*
+ Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
+
+ 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-browser.h"
+
+#include "global.h"
+#include "conf.h"
+#include "helpers.h"
+#include "webSearch.h"
+#include "prefs.h"
+
+#include "sokoke.h"
+#include "midori-webview.h"
+#include "midori-panel.h"
+#include "midori-trash.h"
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include <libsexy/sexy.h>
+#include <string.h>
+
+G_DEFINE_TYPE (MidoriBrowser, midori_browser, GTK_TYPE_WINDOW)
+
+struct _MidoriBrowserPrivate
+{
+    GtkActionGroup* action_group;
+    GtkWidget* menubar;
+    GtkWidget* menu_bookmarks;
+    GtkWidget* menu_tools;
+    GtkWidget* menu_window;
+    GtkWidget* popup_bookmark;
+    GtkWidget* throbber;
+    GtkWidget* navigationbar;
+    GtkWidget* button_tab_new;
+    GtkWidget* location_icon;
+    GtkWidget* location;
+    GtkWidget* search;
+    GtkWidget* button_trash;
+    GtkWidget* button_fullscreen;
+    GtkWidget* bookmarkbar;
+
+    GtkWidget* panel;
+    GtkWidget* panel_bookmarks;
+    GtkWidget* panel_pageholder;
+    GtkWidget* notebook;
+
+    GtkWidget* find;
+    GtkWidget* find_text;
+    GtkToolItem* find_case;
+    GtkToolItem* find_highlight;
+
+    GtkWidget* statusbar;
+    GtkWidget* progressbar;
+
+    gchar* uri;
+    gchar* title;
+    gchar* statusbar_text;
+    MidoriWebSettings* settings;
+
+    KatzeXbelItem* proxy_xbel_folder;
+    MidoriTrash* trash;
+};
+
+#define MIDORI_BROWSER_GET_PRIVATE(obj) \
+    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+     MIDORI_TYPE_BROWSER, MidoriBrowserPrivate))
+
+enum
+{
+    PROP_0,
+
+    PROP_SETTINGS,
+    PROP_STATUSBAR_TEXT,
+    PROP_TRASH
+};
+
+enum {
+    NEW_WINDOW,
+    STATUSBAR_TEXT_CHANGED,
+    ELEMENT_MOTION,
+    QUIT,
+
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+midori_browser_finalize (GObject* object);
+
+static void
+midori_browser_set_property (GObject* object,
+                             guint prop_id,
+                             const GValue* value,
+                             GParamSpec* pspec);
+
+static void
+midori_browser_get_property (GObject* object,
+                             guint prop_id,
+                             GValue* value,
+                             GParamSpec* pspec);
+
+static GtkAction*
+_action_by_name (MidoriBrowser* browser,
+                 const gchar*   name)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    return gtk_action_group_get_action (priv->action_group, name);
+}
+
+static void
+_action_set_sensitive (MidoriBrowser* browser,
+                       const gchar*   name,
+                       gboolean       sensitive)
+{
+    gtk_action_set_sensitive (_action_by_name (browser, name), sensitive);
+}
+
+static void
+_action_set_active (MidoriBrowser* browser,
+                    const gchar*   name,
+                    gboolean       active)
+{
+    GtkAction* action = _action_by_name (browser, name);
+    gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active);
+}
+
+static void
+_midori_browser_update_actions (MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    guint n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+    gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), n > 1);
+    _action_set_sensitive (browser, "TabClose", n > 1);
+    _action_set_sensitive (browser, "TabPrevious", n > 1);
+    _action_set_sensitive (browser, "TabNext", n > 1);
+
+    if (priv->trash)
+    {
+        gboolean trash_empty = midori_trash_is_empty (priv->trash);
+        _action_set_sensitive (browser, "UndoTabClose", !trash_empty);
+        _action_set_sensitive (browser, "Trash", !trash_empty);
+    }
+}
+
+static void
+_midori_browser_update_interface (MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    gboolean loading = midori_web_view_is_loading (MIDORI_WEB_VIEW (web_view));
+    /*_action_set_sensitive (browser, "ZoomIn",
+        webkit_web_view_can_increase_text_size (WEBKIT_WEB_VIEW (web_view)));
+    _action_set_sensitive (browser, "ZoomOut",
+        webkit_web_view_can_decrease_text_size (WEBKIT_WEB_VIEW (web_view)));
+    _action_set_sensitive (browser, "ZoomNormal",
+        webkit_web_view_get_text_size (WEBKIT_WEB_VIEW (web_view)) != 1);*/
+    _action_set_sensitive (browser, "Back",
+        webkit_web_view_can_go_back (WEBKIT_WEB_VIEW (web_view)));
+    _action_set_sensitive (browser, "Back",
+        webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW (web_view)));
+    _action_set_sensitive (browser, "Reload", loading);
+    _action_set_sensitive (browser, "Stop", !loading);
+
+    GtkAction* action = gtk_action_group_get_action (priv->action_group,
+                                                     "ReloadStop");
+    if (!loading)
+    {
+        gtk_widget_set_sensitive (priv->throbber, FALSE);
+        g_object_set (action,
+                      "stock-id", GTK_STOCK_REFRESH,
+                      "tooltip", "Reload the current page", NULL);
+        gtk_widget_hide (priv->progressbar);
+    }
+    else
+    {
+        gtk_widget_set_sensitive (priv->throbber, TRUE);
+        g_object_set (action,
+                      "stock-id", GTK_STOCK_STOP,
+                      "tooltip", "Stop loading the current page", NULL);
+        gtk_widget_show (priv->progressbar);
+    }
+    katze_throbber_set_animated (KATZE_THROBBER (priv->throbber), loading);
+    gtk_image_set_from_stock (GTK_IMAGE (priv->location_icon),
+                              GTK_STOCK_FILE, GTK_ICON_SIZE_MENU);
+}
+
+static GtkWidget*
+_midori_browser_scrolled_for_child (MidoriBrowser* panel,
+                                    GtkWidget*     child)
+{
+    GtkWidget* scrolled = gtk_widget_get_parent (child);
+    if (GTK_IS_VIEWPORT (scrolled))
+        scrolled = gtk_widget_get_parent (scrolled);
+    return scrolled;
+}
+
+static GtkWidget*
+_midori_browser_child_for_scrolled (MidoriBrowser* panel,
+                                    GtkWidget*     scrolled)
+{
+    GtkWidget* child = gtk_bin_get_child (GTK_BIN (scrolled));
+    if (GTK_IS_VIEWPORT (child))
+        child = gtk_bin_get_child (GTK_BIN (child));
+    return child;
+}
+
+static WebKitNavigationResponse
+midori_web_view_navigation_requested_cb (GtkWidget*            web_view,
+                                         WebKitWebFrame*       web_frame,
+                                         WebKitNetworkRequest* request)
+{
+    WebKitNavigationResponse response = WEBKIT_NAVIGATION_RESPONSE_ACCEPT;
+    // FIXME: This isn't the place for uri scheme handling
+    const gchar* uri = webkit_network_request_get_uri (request);
+    gchar* protocol = strtok (g_strdup (uri), ":");
+    if (spawn_protocol_command (protocol, uri))
+        response = WEBKIT_NAVIGATION_RESPONSE_IGNORE;
+    g_free (protocol);
+    return response;
+}
+
+static void
+_midori_browser_set_statusbar_text (MidoriBrowser* browser,
+                                    const gchar*   text)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    katze_assign (priv->statusbar_text, g_strdup (text));
+    gtk_statusbar_pop (GTK_STATUSBAR (priv->statusbar), 1);
+    gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar), 1,
+                        priv->statusbar_text ? priv->statusbar_text : "");
+}
+
+static void
+_midori_browser_update_progress (MidoriBrowser* browser,
+                                 gint           progress)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    if (progress > -1)
+    {
+        gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progressbar),
+                                       progress ? progress / 100.0 : 0);
+        gchar* message = g_strdup_printf ("%d%% loaded", progress);
+        gtk_progress_bar_set_text (GTK_PROGRESS_BAR (priv->progressbar),
+                                   message);
+        g_free (message);
+    }
+    else
+    {
+            gtk_progress_bar_pulse (GTK_PROGRESS_BAR (priv->progressbar));
+            gtk_progress_bar_set_text (GTK_PROGRESS_BAR (priv->progressbar),
+                                       NULL);
+    }
+}
+
+static void
+midori_web_view_load_started_cb (GtkWidget*      web_view,
+                                 WebKitWebFrame* web_frame,
+                                 MidoriBrowser*  browser)
+{
+    if (web_view == midori_browser_get_current_web_view (browser))
+    {
+        _midori_browser_update_interface (browser);
+        _midori_browser_set_statusbar_text (browser, NULL);
+    }
+}
+
+static void
+midori_web_view_progress_started_cb (GtkWidget*     web_view,
+                                     guint          progress,
+                                     MidoriBrowser* browser)
+{
+    if (web_view == midori_browser_get_current_web_view (browser))
+        _midori_browser_update_progress (browser, progress);
+}
+
+static void
+midori_web_view_progress_changed_cb (GtkWidget*     web_view,
+                                     guint          progress,
+                                     MidoriBrowser* browser)
+{
+    if (web_view == midori_browser_get_current_web_view (browser))
+        _midori_browser_update_progress (browser, progress);
+}
+
+static void
+midori_web_view_progress_done_cb (GtkWidget*     web_view,
+                                  guint          progress,
+                                  MidoriBrowser* browser)
+{
+    if (web_view == midori_browser_get_current_web_view (browser))
+        _midori_browser_update_progress (browser, progress);
+}
+
+static void
+midori_web_view_load_done_cb (GtkWidget*      web_view,
+                              WebKitWebFrame* web_frame,
+                              MidoriBrowser*  browser)
+{
+    if (web_view == midori_browser_get_current_web_view (browser))
+    {
+        _midori_browser_update_interface (browser);
+        _midori_browser_set_statusbar_text (browser, NULL);
+    }
+}
+
+static void
+midori_web_view_title_changed_cb (GtkWidget*      web_view,
+                                  WebKitWebFrame* web_frame,
+                                  const gchar*    title,
+                                  MidoriBrowser*  browser)
+{
+    if (web_view == midori_browser_get_current_web_view (browser))
+    {
+        const gchar* title = midori_web_view_get_display_title (
+            MIDORI_WEB_VIEW (web_view));
+        gchar* window_title = g_strconcat (title, " - ",
+            g_get_application_name (), NULL);
+        gtk_window_set_title (GTK_WINDOW (browser), window_title);
+        g_free (window_title);
+    }
+}
+
+static void
+midori_web_view_statusbar_text_changed_cb (MidoriWebView*  web_view,
+                                           const gchar*    text,
+                                           MidoriBrowser*  browser)
+{
+    _midori_browser_set_statusbar_text (browser, text);
+}
+
+static void
+midori_web_view_element_motion_cb (MidoriWebView* web_View,
+                                   const gchar*   link_uri,
+                                   MidoriBrowser* browser)
+{
+    _midori_browser_set_statusbar_text (browser, link_uri);
+}
+
+static void
+midori_web_view_load_committed_cb (GtkWidget*      web_view,
+                                   WebKitWebFrame* web_frame,
+                                   MidoriBrowser*  browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    if (web_view == midori_browser_get_current_web_view (browser))
+    {
+        const gchar* uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view));
+        gtk_entry_set_text (GTK_ENTRY (priv->location), uri);
+        _midori_browser_set_statusbar_text (browser, NULL);
+    }
+}
+
+static gboolean
+midori_web_view_console_message_cb (GtkWidget*     web_view,
+                                    const gchar*   message,
+                                    gint           line,
+                                    const gchar*   sourceId,
+                                    MidoriBrowser* browser)
+{
+    // FIXME: We want this to appear in a panel
+    return FALSE;
+}
+
+static void
+midori_web_view_populate_popup_cb (GtkWidget*     web_view,
+                                   GtkWidget*     menu,
+                                   MidoriBrowser* browser)
+{
+    const gchar* uri = midori_web_view_get_link_uri (MIDORI_WEB_VIEW (web_view));
+    if (uri)
+    {
+        // TODO: bookmark link
+    }
+
+    if (webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view)))
+    {
+        // TODO: view selection source
+    }
+
+    if (!uri && !webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view)))
+    {
+        // TODO: menu items
+        // undo close tab
+        // sep
+        // BookmarkNew
+        // SaveAs
+        // SourceView
+        // Print
+    }
+}
+
+static gboolean
+midori_web_view_leave_notify_event_cb (GtkWidget*        web_view,
+                                       GdkEventCrossing* event,
+                                       MidoriBrowser*    browser)
+{
+    _midori_browser_set_statusbar_text (browser, NULL);
+    return TRUE;
+}
+
+static void
+midori_web_view_new_tab_cb (GtkWidget*     web_view,
+                            const gchar*   uri,
+                            MidoriBrowser* browser)
+{
+    midori_browser_append_uri (browser, uri);
+}
+
+static void
+midori_web_view_new_window_cb (GtkWidget*     web_view,
+                               const gchar*   uri,
+                               MidoriBrowser* browser)
+{
+    g_signal_emit (browser, signals[NEW_WINDOW], 0, uri);
+}
+
+static void
+midori_web_view_close_cb (GtkWidget*     web_view,
+                          MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    if (priv->proxy_xbel_folder)
+    {
+        KatzeXbelItem* xbel_item = midori_web_view_get_proxy_xbel_item (
+            MIDORI_WEB_VIEW (web_view));
+        const gchar* uri = katze_xbel_bookmark_get_href (xbel_item);
+        if (priv->trash && uri && *uri)
+            midori_trash_prepend_xbel_item (priv->trash, xbel_item);
+        katze_xbel_folder_remove_item (priv->proxy_xbel_folder, xbel_item);
+        katze_xbel_item_unref (xbel_item);
+    }
+    GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, web_view);
+    guint n = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), scrolled);
+    gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook), n);
+
+    _midori_browser_update_actions (browser);
+}
+
+static gboolean
+midori_web_view_destroy_cb (GtkWidget*     widget,
+                            MidoriBrowser* browser)
+{
+    _midori_browser_update_actions (browser);
+    return FALSE;
+}
+
+static void
+midori_browser_class_init (MidoriBrowserClass* class)
+{
+
+    signals[QUIT] = g_signal_new(
+        "quit",
+        G_TYPE_FROM_CLASS(class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        0,
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__VOID,
+        G_TYPE_NONE, 0);
+
+    signals[NEW_WINDOW] = g_signal_new(
+        "new-window",
+        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);
+
+    GObjectClass* gobject_class = G_OBJECT_CLASS (class);
+    gobject_class->finalize = midori_browser_finalize;
+    gobject_class->set_property = midori_browser_set_property;
+    gobject_class->get_property = midori_browser_get_property;
+
+    GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
+
+    /**
+    * MidoriBrowser::settings
+    *
+    * An associated settings instance that is shared among all web views.
+    *
+    * Setting this value is propagated to every present web view. Also
+    * every newly created web view will use this instance automatically.
+    */
+    g_object_class_install_property (gobject_class,
+                                     PROP_SETTINGS,
+                                     g_param_spec_object (
+                                     "settings",
+                                     "Settings",
+                                     "The associated settings",
+                                     MIDORI_TYPE_WEB_SETTINGS,
+                                     G_PARAM_READWRITE));
+
+    /**
+    * MidoriBrowser::statusbar-text
+    *
+    * The text that is displayed in the statusbar.
+    *
+    * This value reflects changes to the text visible in the statusbar, such
+    * as the uri of a hyperlink the mouse hovers over or the description of
+    * a menuitem.
+    *
+    * Setting this value changes the displayed text until the next change.
+    */
+    g_object_class_install_property (gobject_class,
+                                     PROP_STATUSBAR_TEXT,
+                                     g_param_spec_string (
+                                     "statusbar-text",
+                                     "Statusbar Text",
+                                     "The text that is displayed in the statusbar",
+                                     "",
+                                     flags));
+
+    /**
+    * MidoriBrowser::trash
+    *
+    * The trash, that collects all closed tabs and windows.
+    *
+    * This is actually a reference to a trash instance, so if a trash should
+    * be used it must be initially set.
+    *
+    * Note: In the future the trash might collect other types of items.
+    */
+    g_object_class_install_property (gobject_class,
+                                     PROP_TRASH,
+                                     g_param_spec_object (
+                                     "trash",
+                                     "Trash",
+                                     "The trash, collecting recently closed tabs and windows",
+                                     MIDORI_TYPE_TRASH,
+                                     G_PARAM_READWRITE));
+
+    g_type_class_add_private (class, sizeof (MidoriBrowserPrivate));
+}
+
+static void
+_action_window_new_activate (GtkAction*     action,
+                             MidoriBrowser* browser)
+{
+    g_signal_emit (browser, signals[NEW_WINDOW], 0, "about:blank");
+}
+
+static void
+_action_tab_new_activate (GtkAction*     action,
+                          MidoriBrowser* browser)
+{
+    midori_browser_append_uri (browser, "about:blank");
+}
+
+static void
+_action_open_activate (GtkAction*     action,
+                       MidoriBrowser* browser)
+{
+    GtkWidget* dialog = gtk_file_chooser_dialog_new (
+        "Open file", GTK_WINDOW (browser),
+        GTK_FILE_CHOOSER_ACTION_OPEN,
+        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+        GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+        NULL);
+     gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_OPEN);
+     if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+     {
+         gchar* uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
+         GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+         g_object_set (web_view, "uri", uri, NULL);
+         g_free (uri);
+     }
+    gtk_widget_destroy (dialog);
+}
+
+static void
+_action_tab_close_activate (GtkAction*     action,
+                            MidoriBrowser* browser)
+{
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    gtk_widget_destroy (web_view);
+}
+
+static void
+_action_window_close_activate (GtkAction*     action,
+                               MidoriBrowser* browser)
+{
+    gtk_widget_destroy (GTK_WIDGET (browser));
+}
+
+static void
+_action_quit_activate (GtkAction*     action,
+                       MidoriBrowser* browser)
+{
+    gtk_main_quit ();
+}
+
+static void
+_action_edit_activate(GtkAction*     action,
+                      MidoriBrowser* browser)
+{
+    GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser));
+    gboolean can_cut = FALSE, can_copy = FALSE, can_paste = FALSE;
+    gboolean has_selection;
+
+    if (WEBKIT_IS_WEB_VIEW (widget))
+    {
+        WebKitWebView* web_view = WEBKIT_WEB_VIEW (widget);
+        can_cut = webkit_web_view_can_cut_clipboard (web_view);
+        can_copy = webkit_web_view_can_copy_clipboard (web_view);
+        can_paste = webkit_web_view_can_paste_clipboard (web_view);
+    }
+    else if (GTK_IS_EDITABLE (widget))
+    {
+        GtkEditable* editable = GTK_EDITABLE (widget);
+        has_selection = gtk_editable_get_selection_bounds (editable, NULL, NULL);
+        can_cut = has_selection && gtk_editable_get_editable (editable);
+        can_copy = has_selection;
+        can_paste = gtk_editable_get_editable (editable);
+    }
+
+    _action_set_sensitive (browser, "Cut", can_cut);
+    _action_set_sensitive (browser, "Copy", can_copy);
+    _action_set_sensitive (browser, "Paste", can_paste);
+    _action_set_sensitive (browser, "Delete", can_cut);
+    _action_set_sensitive (browser, "SelectAll", FALSE);
+}
+
+static void
+_action_cut_activate(GtkAction*     action,
+                     MidoriBrowser* browser)
+{
+    GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser));
+    if (G_LIKELY (widget))
+        g_signal_emit_by_name (widget, "cut-clipboard");
+}
+
+static void
+_action_copy_activate(GtkAction*     action,
+                      MidoriBrowser* browser)
+{
+    GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser));
+    if (G_LIKELY (widget))
+        g_signal_emit_by_name (widget, "copy-clipboard");
+}
+
+static void
+_action_paste_activate(GtkAction*     action,
+                       MidoriBrowser* browser)
+{
+    GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser));
+    if (G_LIKELY (widget))
+        g_signal_emit_by_name (widget, "paste-clipboard");
+}
+
+static void
+_action_delete_activate(GtkAction*     action,
+                        MidoriBrowser* browser)
+{
+    GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser));
+    if (G_LIKELY (widget))
+    {
+        if (WEBKIT_IS_WEB_VIEW (widget))
+            webkit_web_view_delete_selection (WEBKIT_WEB_VIEW (widget));
+        else if (GTK_IS_EDITABLE(widget))
+            gtk_editable_delete_selection (GTK_EDITABLE (widget));
+    }
+}
+
+static void
+_action_select_all_activate(GtkAction*     action,
+                            MidoriBrowser* browser)
+{
+    GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser));
+    if (G_LIKELY (widget))
+    {
+        if (GTK_IS_ENTRY (widget))
+            gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
+        else
+            g_signal_emit_by_name (widget, "select-all");
+    }
+}
+
+static void
+_action_find_activate(GtkAction*     action,
+                      MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    if (GTK_WIDGET_VISIBLE (priv->find))
+    {
+        GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+        webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (web_view));
+        gtk_toggle_tool_button_set_active (
+            GTK_TOGGLE_TOOL_BUTTON (priv->find_highlight), FALSE);
+        gtk_widget_hide (priv->find);
+    }
+    else
+    {
+        GtkWidget* icon = gtk_image_new_from_stock (GTK_STOCK_FIND,
+                                                    GTK_ICON_SIZE_MENU);
+        sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (priv->find_text),
+                                  SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE (icon));
+        gtk_entry_set_text (GTK_ENTRY (priv->find_text), "");
+        gtk_widget_show (priv->find);
+        gtk_widget_grab_focus (GTK_WIDGET (priv->find_text));
+    }
+}
+
+static void
+_midori_browser_find (MidoriBrowser* browser,
+                      gboolean       forward)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    const gchar* text = gtk_entry_get_text (GTK_ENTRY (priv->find_text));
+    const gboolean case_sensitive = gtk_toggle_tool_button_get_active (
+        GTK_TOGGLE_TOOL_BUTTON(priv->find_case));
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    if (GTK_WIDGET_VISIBLE (priv->find))
+        webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (web_view));
+    gboolean found = webkit_web_view_search_text (WEBKIT_WEB_VIEW (web_view),
+        text, case_sensitive, forward, TRUE);
+    if (GTK_WIDGET_VISIBLE (priv->find))
+    {
+        GtkWidget* icon;
+        if (found)
+            icon = gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU);
+        else
+            icon = gtk_image_new_from_stock (GTK_STOCK_STOP, GTK_ICON_SIZE_MENU);
+        sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (priv->find_text),
+            SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(icon));
+        webkit_web_view_mark_text_matches (WEBKIT_WEB_VIEW (web_view), text,
+                                           case_sensitive, 0);
+        const gboolean highlight = gtk_toggle_tool_button_get_active (
+            GTK_TOGGLE_TOOL_BUTTON (priv->find_highlight));
+        webkit_web_view_set_highlight_text_matches (WEBKIT_WEB_VIEW (web_view),
+                                                    highlight);
+    }
+}
+
+static void
+_action_find_next_activate (GtkAction*     action,
+                            MidoriBrowser* browser)
+{
+    _midori_browser_find (browser, TRUE);
+}
+
+static void
+_action_find_previous_activate (GtkAction*     action,
+                                MidoriBrowser* browser)
+{
+    _midori_browser_find (browser, FALSE);
+}
+
+static void
+_find_highlight_toggled (GtkToggleToolButton* toolitem,
+                         MidoriBrowser*       browser)
+{
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    const gboolean highlight = gtk_toggle_tool_button_get_active (toolitem);
+    webkit_web_view_set_highlight_text_matches (WEBKIT_WEB_VIEW (web_view),
+                                                highlight);
+}
+
+static void
+midori_browser_find_button_close_clicked_cb (GtkWidget*     widget,
+                                             MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    gtk_widget_hide (priv->find);
+}
+
+static void
+midori_browser_navigationbar_notify_style_cb (GObject*       object,
+                                              GParamSpec*    arg1,
+                                              MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    if (config->toolbarStyle == CONFIG_TOOLBAR_DEFAULT)
+    {
+        gtk_toolbar_set_style (GTK_TOOLBAR(priv->navigationbar),
+                               config_to_toolbarstyle (config->toolbarStyle));
+    }
+}
+
+static void
+midori_browser_menu_trash_item_activate_cb (GtkWidget*     menuitem,
+                                            MidoriBrowser* browser)
+{
+    // Create a new web view with an uri which has been closed before
+    KatzeXbelItem* item = g_object_get_data (G_OBJECT (menuitem),
+                                             "KatzeXbelItem");
+    const gchar* uri = katze_xbel_bookmark_get_href (item);
+    midori_browser_append_uri (browser, uri);
+    katze_xbel_item_unref (item);
+}
+
+static void
+midori_browser_menu_trash_activate_cb (GtkWidget*     widget,
+                                       MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkWidget* menu = gtk_menu_new ();
+    guint n = midori_trash_get_n_items (priv->trash);
+    GtkWidget* menuitem;
+    guint i;
+    for (i = 0; i < n; i++)
+    {
+        KatzeXbelItem* item = midori_trash_get_nth_xbel_item (priv->trash, i);
+        const gchar* title = katze_xbel_item_get_title (item);
+        const gchar* uri = katze_xbel_bookmark_get_href (item);
+        menuitem = gtk_image_menu_item_new_with_label (title ? title : uri);
+        // FIXME: Get the real icon
+        GtkWidget* icon = gtk_image_new_from_stock (GTK_STOCK_FILE,
+                                                    GTK_ICON_SIZE_MENU);
+        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
+        gtk_menu_shell_append(GTK_MENU_SHELL (menu), menuitem);
+        g_object_set_data (G_OBJECT (menuitem), "KatzeXbelItem", item);
+        g_signal_connect (menuitem, "activate",
+            G_CALLBACK (midori_browser_menu_trash_item_activate_cb), browser);
+        gtk_widget_show (menuitem);
+    }
+
+    menuitem = gtk_separator_menu_item_new ();
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+    gtk_widget_show (menuitem);
+    GtkAction* action = gtk_action_group_get_action (priv->action_group,
+                                                     "TrashEmpty");
+    menuitem = gtk_action_create_menu_item (action);
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+    gtk_widget_show (menuitem);
+    sokoke_widget_popup (widget, GTK_MENU (menu), NULL);
+}
+
+static void
+_action_preferences_activate (GtkAction*     action,
+                              MidoriBrowser* browser)
+{
+    // Show the preferences dialog. Create it if necessary.
+    static GtkWidget* dialog = NULL;
+    if (GTK_IS_DIALOG (dialog))
+        gtk_window_present (GTK_WINDOW (dialog));
+    else
+    {
+        dialog = prefs_preferences_dialog_new (browser);
+        gtk_widget_show (dialog);
+    }
+}
+
+static void
+_action_navigationbar_activate (GtkToggleAction* action,
+                                MidoriBrowser*   browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    config->toolbarNavigation = gtk_toggle_action_get_active (action);
+    sokoke_widget_set_visible (priv->navigationbar, config->toolbarNavigation);
+}
+
+static void
+_action_bookmarkbar_activate (GtkToggleAction* action,
+                              MidoriBrowser*   browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    config->toolbarBookmarks = gtk_toggle_action_get_active (action);
+    sokoke_widget_set_visible (priv->bookmarkbar, config->toolbarBookmarks);
+}
+
+static void
+_action_statusbar_activate (GtkToggleAction* action,
+                            MidoriBrowser*   browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    config->toolbarStatus = gtk_toggle_action_get_active (action);
+    sokoke_widget_set_visible (priv->statusbar, config->toolbarStatus);
+}
+
+static void
+_action_reload_stop_activate (GtkAction*     action,
+                              MidoriBrowser* browser)
+{
+    gchar* stock_id;
+    g_object_get (action, "stock-id", &stock_id, NULL);
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    // Refresh or stop, depending on the stock id
+    if (!strcmp (stock_id, GTK_STOCK_REFRESH))
+    {
+        /*GdkModifierType state = (GdkModifierType)0;
+        gint x, y;
+        gdk_window_get_pointer (NULL, &x, &y, &state);
+        gboolean from_cache = state & GDK_SHIFT_MASK;*/
+        webkit_web_view_reload (WEBKIT_WEB_VIEW (web_view));
+    }
+    else
+        webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view));
+    g_free (stock_id);
+}
+
+/*static void
+_action_zoom_in_activate (GtkAction*     action,
+                          MidoriBrowser* browser)
+{
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    const gfloat zoom = webkit_web_view_get_text_multiplier (
+        WEBKIT_WEB_VIEW (web_view));
+    webkit_web_view_set_text_multiplier (WEBKIT_WEB_VIEW (web_view), zoom + 0.1);
+}*/
+
+/*static void
+_action_zoom_out_activate (GtkAction*     action,
+                           MidoriBrowser* browser)
+{
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    const gfloat zoom = webkit_web_view_get_text_multiplier (
+        WEBKIT_WEB_VIEW (web_view));
+    webkit_web_view_set_text_multiplier (WEBKIT_WEB_VIEW (web_view), zoom - 0.1);
+}*/
+
+/*static void
+_action_zoom_normal_activate (GtkAction*     action,
+                              MidoriBrowser* browser)
+{
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    webkit_web_view_set_text_multiplier (WEBKIT_WEB_VIEW (web_View, 1));
+}*/
+
+/*static void
+_action_source_view_activate (GtkAction*     action,
+                              MidoriBrowser* browser)
+{
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    gchar* source = webkit_web_view_copy_source (WEBKIT_WEB_VIEW (web_view));
+    webkit_web_view_load_html_string (WEBKIT_WEB_VIEW (web_view), source, "");
+    g_free (source);
+}*/
+
+static void
+_action_fullscreen_activate (GtkAction*     action,
+                             MidoriBrowser* browser)
+{
+    GdkWindowState state = gdk_window_get_state (GTK_WIDGET (browser)->window);
+    if (state & GDK_WINDOW_STATE_FULLSCREEN)
+        gtk_window_unfullscreen (GTK_WINDOW (browser));
+    else
+        gtk_window_fullscreen (GTK_WINDOW (browser));
+}
+
+static void
+_action_back_activate (GtkAction*     action,
+                       MidoriBrowser* browser)
+{
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    webkit_web_view_go_back (WEBKIT_WEB_VIEW (web_view));
+}
+
+static void
+_action_forward_activate (GtkAction*     action,
+                          MidoriBrowser* browser)
+{
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    webkit_web_view_go_forward (WEBKIT_WEB_VIEW (web_view));
+}
+
+static void
+_action_home_activate (GtkAction*     action,
+                       MidoriBrowser* browser)
+{
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    g_object_set (web_view, "uri", config->homepage, NULL);
+}
+
+static gboolean
+midori_browser_location_key_press_event_cb (GtkWidget*     widget,
+                                            GdkEventKey*   event,
+                                            MidoriBrowser* browser)
+{
+    switch (event->keyval)
+    {
+    case GDK_Return:
+    {
+        const gchar* uri = gtk_entry_get_text (GTK_ENTRY (widget));
+        if (uri)
+        {
+            gchar* new_uri = magic_uri (uri, TRUE);
+            // TODO: Use new_uri intermediately when completion is better
+            /* TODO Completion should be generated from history, that is
+                    the uri as well as the title. */
+            entry_completion_append (GTK_ENTRY (widget), uri);
+            GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+            g_object_set (web_view, "uri", new_uri, NULL);
+            g_free (new_uri);
+        }
+        return TRUE;
+    }
+    case GDK_Escape:
+    {
+        GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+        const gchar* uri = midori_web_view_get_display_uri (
+            MIDORI_WEB_VIEW (web_view));
+        gtk_entry_set_text (GTK_ENTRY (widget), uri);
+        return TRUE;
+    }
+    }
+    return FALSE;
+}
+
+static void
+_action_location_activate (GtkAction*     action,
+                           MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    if (GTK_WIDGET_VISIBLE (priv->navigationbar))
+        gtk_widget_grab_focus (priv->location);
+    else
+    {
+        // TODO: We should offer all of the location's features here
+        GtkWidget* dialog;
+        dialog = gtk_dialog_new_with_buttons ("Open location"
+            , GTK_WINDOW (browser)
+            , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR
+            , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL
+            , GTK_STOCK_JUMP_TO, GTK_RESPONSE_ACCEPT
+            , NULL);
+        gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_JUMP_TO);
+        gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+        gtk_container_set_border_width (
+            GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 5);
+        GtkWidget* hbox = gtk_hbox_new (FALSE, 8);
+        gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+        GtkWidget* label = gtk_label_new_with_mnemonic ("_Location:");
+        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+        GtkWidget* entry = gtk_entry_new ();
+        gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
+        gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
+        gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
+        gtk_widget_show_all( hbox);
+        gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+                                         GTK_RESPONSE_ACCEPT);
+        if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+        {
+            gtk_entry_set_text (GTK_ENTRY (priv->location)
+             , gtk_entry_get_text (GTK_ENTRY (entry)));
+            GdkEventKey event;
+            event.keyval = GDK_Return;
+            midori_browser_location_key_press_event_cb (priv->location,
+                                                        &event, browser);
+        }
+        gtk_widget_destroy (dialog);
+    }
+}
+
+static void
+_action_search_activate (GtkAction*     action,
+                         MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    if (GTK_WIDGET_VISIBLE (priv->search)
+     && GTK_WIDGET_VISIBLE (priv->navigationbar))
+        gtk_widget_grab_focus (priv->search);
+    else
+    {
+        // TODO: We should offer all of the search's features here
+        GtkWidget* dialog = gtk_dialog_new_with_buttons ("Web search"
+            , GTK_WINDOW (browser)
+            , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR
+            , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL
+            , GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT
+            , NULL);
+        gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_FIND);
+        gtk_container_set_border_width(GTK_CONTAINER (dialog), 5);
+        gtk_container_set_border_width (
+            GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 5);
+        GtkWidget* hbox = gtk_hbox_new (FALSE, 8);
+        gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+        GtkWidget* label = gtk_label_new_with_mnemonic ("_Location:");
+        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+        GtkWidget* entry = gtk_entry_new ();
+        gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
+        gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
+        gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
+        gtk_widget_show_all (hbox);
+        gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+                                         GTK_RESPONSE_ACCEPT);
+        if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+        {
+            gtk_entry_set_text (GTK_ENTRY (priv->search)
+             , gtk_entry_get_text (GTK_ENTRY (entry)));
+            on_webSearch_activate (priv->search, browser);
+        }
+        gtk_widget_destroy (dialog);
+    }
+}
+
+static void
+midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,
+                                         KatzeXbelItem* bookmark)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    gboolean new_bookmark = !bookmark;
+    GtkWidget* dialog = gtk_dialog_new_with_buttons (
+        new_bookmark ? "New bookmark" : "Edit bookmark",
+        GTK_WINDOW (browser),
+        GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+        new_bookmark ? GTK_STOCK_ADD : GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+        NULL);
+    gtk_window_set_icon_name (GTK_WINDOW (dialog),
+        new_bookmark ? GTK_STOCK_ADD : GTK_STOCK_REMOVE);
+    gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+    gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 5);
+    GtkSizeGroup* sizegroup =  gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+    if (new_bookmark)
+        bookmark = katze_xbel_bookmark_new ();
+
+    GtkWidget* hbox = gtk_hbox_new (FALSE, 8);
+    gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+    GtkWidget* label = gtk_label_new_with_mnemonic ("_Title:");
+    gtk_size_group_add_widget (sizegroup, label);
+    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+    GtkWidget* entry_title = gtk_entry_new ();
+    gtk_entry_set_activates_default (GTK_ENTRY (entry_title), TRUE);
+    if (!new_bookmark)
+    {
+        const gchar* title = katze_xbel_item_get_title (bookmark);
+        gtk_entry_set_text (GTK_ENTRY (entry_title), title ? title : "");
+    }
+    gtk_box_pack_start (GTK_BOX (hbox), entry_title, TRUE, TRUE, 0);
+    gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
+    gtk_widget_show_all (hbox);
+
+    hbox = gtk_hbox_new (FALSE, 8);
+    gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+    label = gtk_label_new_with_mnemonic ("_Description:");
+    gtk_size_group_add_widget (sizegroup, label);
+    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+    GtkWidget* entry_desc = gtk_entry_new ();
+    gtk_entry_set_activates_default (GTK_ENTRY (entry_desc), TRUE);
+    if (!new_bookmark)
+    {
+        const gchar* desc = katze_xbel_item_get_desc (bookmark);
+        gtk_entry_set_text (GTK_ENTRY (entry_desc), desc ? desc : "");
+    }
+    gtk_box_pack_start (GTK_BOX (hbox), entry_desc, TRUE, TRUE, 0);
+    gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
+    gtk_widget_show_all (hbox);
+
+    GtkWidget* entry_uri = NULL;
+    if (katze_xbel_item_is_bookmark (bookmark))
+    {
+        hbox = gtk_hbox_new (FALSE, 8);
+        gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+        label = gtk_label_new_with_mnemonic ("_Uri:");
+        gtk_size_group_add_widget (sizegroup, label);
+        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+        entry_uri = gtk_entry_new ();
+        gtk_entry_set_activates_default (GTK_ENTRY (entry_uri), TRUE);
+        if (!new_bookmark)
+            gtk_entry_set_text (GTK_ENTRY (entry_uri),
+                                katze_xbel_bookmark_get_href (bookmark));
+        gtk_box_pack_start (GTK_BOX(hbox), entry_uri, TRUE, TRUE, 0);
+        gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
+        gtk_widget_show_all (hbox);
+    }
+
+    GtkWidget* combo_folder = NULL;
+    if (new_bookmark)
+    {
+        hbox = gtk_hbox_new (FALSE, 8);
+        gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+        label = gtk_label_new_with_mnemonic ("_Folder:");
+        gtk_size_group_add_widget (sizegroup, label);
+        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+        combo_folder = gtk_combo_box_new_text ();
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_folder), "Root");
+        gtk_widget_set_sensitive (combo_folder, FALSE);
+        gtk_box_pack_start (GTK_BOX (hbox), combo_folder, TRUE, TRUE, 0);
+        gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
+        gtk_widget_show_all (hbox);
+    }
+
+    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+    {
+        katze_xbel_item_set_title (bookmark,
+            gtk_entry_get_text (GTK_ENTRY (entry_title)));
+        katze_xbel_item_set_desc (bookmark,
+            gtk_entry_get_text(GTK_ENTRY(entry_desc)));
+        if (katze_xbel_item_is_bookmark (bookmark))
+            katze_xbel_bookmark_set_href (bookmark,
+                gtk_entry_get_text (GTK_ENTRY (entry_uri)));
+
+        // FIXME: We want to choose a folder
+        if (new_bookmark)
+        {
+            katze_xbel_folder_append_item (bookmarks, bookmark);
+            GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks);
+            GtkTreeModel* treemodel = gtk_tree_view_get_model (treeview);
+            GtkTreeIter iter;
+            gtk_tree_store_insert_with_values (GTK_TREE_STORE (treemodel),
+                &iter, NULL, G_MAXINT, 0, bookmark, -1);
+            katze_xbel_item_ref (bookmark);
+        }
+
+        // FIXME: update navigationbar
+        // FIXME: Update panel in other windows
+    }
+    gtk_widget_destroy (dialog);
+}
+
+static void
+midori_panel_bookmarks_row_activated_cb (GtkTreeView*       treeview,
+                                         GtkTreePath*       path,
+                                         GtkTreeViewColumn* column,
+                                         MidoriBrowser*     browser)
+{
+    GtkTreeModel* model = gtk_tree_view_get_model (treeview);
+    GtkTreeIter iter;
+    if (gtk_tree_model_get_iter (model, &iter, path))
+    {
+        KatzeXbelItem* item;
+        gtk_tree_model_get (model, &iter, 0, &item, -1);
+        if (katze_xbel_item_is_bookmark (item))
+        {
+            GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+            const gchar* uri = katze_xbel_bookmark_get_href (item);
+            g_object_set (web_view, "uri", uri, NULL);
+        }
+    }
+}
+
+static void
+midori_panel_bookmarks_cursor_or_row_changed_cb (GtkTreeView*   treeview,
+                                                 MidoriBrowser* browser)
+{
+    GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview);
+    if (selection)
+    {
+        GtkTreeModel* model;
+        GtkTreeIter iter;
+        if (gtk_tree_selection_get_selected (selection, &model, &iter))
+        {
+            KatzeXbelItem* item;
+            gtk_tree_model_get (model, &iter, 0, &item, -1);
+
+            gboolean is_separator = katze_xbel_item_is_separator (item);
+            _action_set_sensitive (browser, "BookmarkEdit", !is_separator);
+            _action_set_sensitive (browser, "BookmarkDelete", TRUE);
+        }
+        else
+        {
+            _action_set_sensitive (browser, "BookmarkEdit", FALSE);
+            _action_set_sensitive (browser, "BookmarkDelete", FALSE);
+        }
+    }
+}
+
+static void
+_midori_panel_bookmarks_popup (GtkWidget*      widget,
+                               GdkEventButton* event,
+                               KatzeXbelItem*  item,
+                               MidoriBrowser*  browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    gboolean is_bookmark = katze_xbel_item_is_bookmark (item);
+
+    _action_set_sensitive (browser, "BookmarkOpen", is_bookmark);
+    _action_set_sensitive (browser, "BookmarkOpenTab", is_bookmark);
+    _action_set_sensitive (browser, "BookmarkOpenWindow", is_bookmark);
+
+    sokoke_widget_popup (widget, GTK_MENU (priv->popup_bookmark), event);
+}
+
+static gboolean
+midori_panel_bookmarks_button_release_event_cb (GtkWidget*      widget,
+                                                GdkEventButton* event,
+                                                MidoriBrowser*  browser)
+{
+    if (event->button != 2 && event->button != 3)
+        return FALSE;
+
+    GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
+    if (selection)
+    {
+        GtkTreeModel* model;
+        GtkTreeIter iter;
+        if (gtk_tree_selection_get_selected(selection, &model, &iter))
+        {
+            KatzeXbelItem* item;
+            gtk_tree_model_get(model, &iter, 0, &item, -1);
+            if (event->button == 2 && katze_xbel_item_is_bookmark(item))
+            {
+                const gchar* uri = katze_xbel_bookmark_get_href(item);
+                midori_browser_append_uri (browser, uri);
+            }
+            else
+                _midori_panel_bookmarks_popup(widget, event, item, browser);
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+static void
+midori_panel_bookmarks_popup_menu_cb (GtkWidget*     widget,
+                                      MidoriBrowser* browser)
+{
+    GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
+    if (selection)
+    {
+        GtkTreeModel* model;
+        GtkTreeIter iter;
+        if (gtk_tree_selection_get_selected(selection, &model, &iter))
+        {
+            KatzeXbelItem* item;
+            gtk_tree_model_get(model, &iter, 0, &item, -1);
+            _midori_panel_bookmarks_popup(widget, NULL, item, browser);
+        }
+    }
+}
+
+static void
+_tree_store_insert_folder (GtkTreeStore* treestore,
+                           GtkTreeIter* parent,
+                           KatzeXbelItem* folder)
+{
+    guint n = katze_xbel_folder_get_n_items (folder);
+    guint i;
+    for (i = 0; i < n; i++)
+    {
+        KatzeXbelItem* item = katze_xbel_folder_get_nth_item (folder, i);
+        GtkTreeIter iter;
+        gtk_tree_store_insert_with_values (treestore, &iter, parent, n,
+                                           0, item, -1);
+        katze_xbel_item_ref (item);
+        if (katze_xbel_item_is_folder (item))
+            _tree_store_insert_folder (treestore, &iter, item);
+    }
+}
+
+static void
+midori_browser_bookmarks_item_render_icon_cb (GtkTreeViewColumn* column,
+                                              GtkCellRenderer*   renderer,
+                                              GtkTreeModel*      model,
+                                              GtkTreeIter*       iter,
+                                              GtkWidget*         treeview)
+{
+    KatzeXbelItem* item;
+    gtk_tree_model_get (model, iter, 0, &item, -1);
+
+    if (G_UNLIKELY (!item))
+        return;
+    if (G_UNLIKELY (!katze_xbel_item_get_parent (item)))
+    {
+        gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
+        katze_xbel_item_unref (item);
+        return;
+    }
+
+    // TODO: Would it be better to not do this on every redraw?
+    GdkPixbuf* pixbuf = NULL;
+    if (katze_xbel_item_is_bookmark (item))
+        pixbuf = gtk_widget_render_icon (treeview, STOCK_BOOKMARK,
+                                         GTK_ICON_SIZE_MENU, NULL);
+    else if (katze_xbel_item_is_folder (item))
+        pixbuf = gtk_widget_render_icon (treeview, GTK_STOCK_DIRECTORY,
+                                         GTK_ICON_SIZE_MENU, NULL);
+    g_object_set (renderer, "pixbuf", pixbuf, NULL);
+    if (pixbuf)
+        g_object_unref (pixbuf);
+}
+
+static void
+midori_browser_bookmarks_item_render_text_cb (GtkTreeViewColumn* column,
+                                              GtkCellRenderer*   renderer,
+                                              GtkTreeModel*      model,
+                                              GtkTreeIter*       iter,
+                                              GtkWidget*         treeview)
+{
+    KatzeXbelItem* item;
+    gtk_tree_model_get (model, iter, 0, &item, -1);
+
+    if (G_UNLIKELY (!item))
+        return;
+    if (G_UNLIKELY (!katze_xbel_item_get_parent (item)))
+    {
+        gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
+        katze_xbel_item_unref (item);
+        return;
+    }
+
+    if (katze_xbel_item_is_separator (item))
+        g_object_set (renderer, "markup", "<i>Separator</i>", NULL);
+    else
+        g_object_set (renderer, "markup", NULL,
+                      "text", katze_xbel_item_get_title(item), NULL);
+}
+
+static void
+_midori_browser_create_bookmark_menu (MidoriBrowser* browser,
+                                      KatzeXbelItem* folder,
+                                      GtkWidget*     menu);
+
+static void
+midori_browser_bookmark_menu_folder_activate_cb (GtkWidget*     menuitem,
+                                                 MidoriBrowser* browser)
+{
+    GtkWidget* menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menuitem));
+    gtk_container_foreach(GTK_CONTAINER (menu), (GtkCallback) gtk_widget_destroy, NULL);//...
+    KatzeXbelItem* folder = (KatzeXbelItem*)g_object_get_data(G_OBJECT (menuitem), "KatzeXbelItem");
+    _midori_browser_create_bookmark_menu (browser, folder, menu);
+    // Remove all menuitems when the menu is hidden.
+    // FIXME: We really *want* the line below, but it won't work like that
+    //g_signal_connect_after (menu, "hide", G_CALLBACK (gtk_container_foreach), gtk_widget_destroy);
+    gtk_widget_show (menuitem);
+}
+
+static void
+midori_browser_bookmarkbar_folder_activate_cb (GtkToolItem*   toolitem,
+                                               MidoriBrowser* browser)
+{
+    GtkWidget* menu = gtk_menu_new();
+    KatzeXbelItem* folder = (KatzeXbelItem*)g_object_get_data (
+        G_OBJECT (toolitem), "KatzeXbelItem");
+    _midori_browser_create_bookmark_menu (browser, folder, menu);
+    // Remove all menuitems when the menu is hidden.
+    // FIXME: We really *should* run the line below, but it won't work like that
+    /*g_signal_connect (menu, "hide", G_CALLBACK (gtk_container_foreach),
+                      gtk_widget_destroy);*/
+    sokoke_widget_popup (GTK_WIDGET (toolitem), GTK_MENU (menu), NULL);
+}
+
+static void
+midori_browser_menu_bookmarks_item_activate_cb (GtkWidget*     widget,
+                                                MidoriBrowser* browser)
+{
+    KatzeXbelItem* item = (KatzeXbelItem*)g_object_get_data(G_OBJECT(widget), "KatzeXbelItem");
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    g_object_set (web_view, "uri", katze_xbel_bookmark_get_href (item), NULL);
+}
+
+static void
+_midori_browser_create_bookmark_menu (MidoriBrowser* browser,
+                                      KatzeXbelItem* folder,
+                                      GtkWidget*     menu)
+{
+    guint n = katze_xbel_folder_get_n_items (folder);
+    guint i;
+    for (i = 0; i < n; i++)
+    {
+        KatzeXbelItem* item = katze_xbel_folder_get_nth_item (folder, i);
+        const gchar* title = katze_xbel_item_is_separator (item)
+            ? "" : katze_xbel_item_get_title (item);
+        /* const gchar* desc = katze_xbel_item_is_separator (item)
+            ? "" : katze_xbel_item_get_desc (item); */
+        GtkWidget* menuitem = NULL;
+        switch (katze_xbel_item_get_kind (item))
+        {
+        case KATZE_XBEL_ITEM_KIND_FOLDER:
+            // FIXME: what about katze_xbel_folder_is_folded?
+            menuitem = gtk_image_menu_item_new_with_label (title);
+            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem),
+                gtk_image_new_from_stock (GTK_STOCK_DIRECTORY,
+                                          GTK_ICON_SIZE_MENU));
+            GtkWidget* _menu = gtk_menu_new ();
+            gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), _menu);
+            g_signal_connect (menuitem, "activate",
+                G_CALLBACK (midori_browser_bookmark_menu_folder_activate_cb),
+                browser);
+            g_object_set_data (G_OBJECT (menuitem), "KatzeXbelItem", item);
+            break;
+        case KATZE_XBEL_ITEM_KIND_BOOKMARK:
+            menuitem = gtk_image_menu_item_new_with_label (title);
+            GtkWidget* image = gtk_image_new_from_stock (STOCK_BOOKMARK,
+                                                         GTK_ICON_SIZE_MENU);
+            gtk_widget_show (image);
+            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem),
+                                           image);
+            g_signal_connect (menuitem, "activate",
+                G_CALLBACK (midori_browser_menu_bookmarks_item_activate_cb),
+                browser);
+            g_object_set_data (G_OBJECT (menuitem), "KatzeXbelItem", item);
+            break;
+        case KATZE_XBEL_ITEM_KIND_SEPARATOR:
+            menuitem = gtk_separator_menu_item_new ();
+            break;
+        default:
+            g_warning ("Unknown xbel item kind");
+         }
+         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+         gtk_widget_show (menuitem);
+    }
+}
+
+static void
+_action_bookmark_new_activate (GtkAction*     action,
+                               MidoriBrowser* browser)
+{
+    midori_browser_edit_bookmark_dialog_new (browser, NULL);
+}
+
+static void
+_action_manage_search_engines_activate (GtkAction*     action,
+                                        MidoriBrowser* browser)
+{
+    // Show the Manage search engines dialog. Create it if necessary.
+    static GtkWidget* dialog;
+    if (GTK_IS_DIALOG (dialog))
+        gtk_window_present (GTK_WINDOW (dialog));
+    else
+    {
+        dialog = webSearch_manageSearchEngines_dialog_new (browser);
+        gtk_widget_show (dialog);
+    }
+}
+
+static void
+_action_tab_previous_activate (GtkAction*     action,
+                               MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    gint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+    gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n - 1);
+}
+
+static void
+_action_tab_next_activate (GtkAction*     action,
+                           MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    // Advance one tab or jump to the first one if we are at the last one
+    gint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+    if (n == gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)) - 1)
+        n = -1;
+    gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n + 1);
+}
+
+static void
+midori_browser_window_menu_item_activate_cb (GtkWidget* widget,
+                                             GtkWidget* web_view)
+{
+    MidoriBrowser* browser = MIDORI_BROWSER (gtk_widget_get_toplevel (web_view));
+    if (!browser)
+    {
+        g_warning ("Orphaned web view");
+        return;
+    }
+
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, web_view);
+    guint n = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), scrolled);
+    gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n);
+}
+
+static const gchar* credits_authors[] = {
+    "Christian Dywan <christian@twotoasts.de>", NULL };
+static const gchar* credits_documenters/*[]*/ = /*{
+    */NULL/* }*/;
+static const gchar* credits_artists[] = {
+    "Nancy Runge <nancy@twotoasts.de>", NULL };
+
+static const gchar* license =
+ "This library is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU Lesser General Public\n"
+ "License as published by the Free Software Foundation; either\n"
+ "version 2.1 of the License, or (at your option) any later version.\n";
+
+static void
+_action_about_activate (GtkAction*     action,
+                        MidoriBrowser* browser)
+{
+    gtk_show_about_dialog (GTK_WINDOW (browser),
+        "logo-icon-name", gtk_window_get_icon_name (GTK_WINDOW (browser)),
+        "name", PACKAGE_NAME,
+        "version", PACKAGE_VERSION,
+        "comments", "A lightweight web browser.",
+        "copyright", "Copyright Â© 2007-2008 Christian Dywan",
+        "website", "http://software.twotoasts.de",
+        "authors", credits_authors,
+        "documenters", credits_documenters,
+        "artists", credits_artists,
+        "license", license,
+        "wrap-license", TRUE,
+        // "translator-credits", _("translator-credits"),
+        NULL);
+}
+
+static void
+midori_browser_location_changed_cb (GtkWidget*     widget,
+                                    MidoriBrowser* browser)
+{
+    // Preserve changes to the uri
+    /*const gchar* newUri = gtk_entry_get_text(GTK_ENTRY(widget));
+    katze_xbel_bookmark_set_href(browser->sessionItem, newUri);*/
+    // FIXME: If we want this feature, this is the wrong approach
+}
+
+static void
+_action_panel_activate (GtkToggleAction* action,
+                        MidoriBrowser*   browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    config->panelShow = gtk_toggle_action_get_active (action);
+    sokoke_widget_set_visible (priv->panel, config->panelShow);
+}
+
+static void
+_action_open_in_panel_activate (GtkAction*     action,
+                                MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    const gchar* uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view));
+    katze_assign (config->panelPageholder, g_strdup (uri));
+    gint n = midori_panel_page_num (MIDORI_PANEL (priv->panel),
+                                    priv->panel_pageholder);
+    midori_panel_set_current_page (MIDORI_PANEL (priv->panel), n);
+    gtk_widget_show (priv->panel);
+    g_object_set (priv->panel_pageholder, "uri", config->panelPageholder, NULL);
+}
+
+
+static void
+midori_panel_notify_position_cb (GObject*       object,
+                                 GParamSpec*    arg1,
+                                 MidoriBrowser* browser)
+{
+    config->winPanelPos = gtk_paned_get_position (GTK_PANED (object));
+}
+
+static gboolean
+midori_panel_close_cb (MidoriPanel*   panel,
+                       MidoriBrowser* browser)
+{
+    config->panelShow = FALSE;
+    return FALSE;
+}
+
+static void
+gtk_notebook_switch_page_cb (GtkWidget*       widget,
+                             GtkNotebookPage* page,
+                             guint            page_num,
+                             MidoriBrowser*   browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    const gchar* uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view));
+    gtk_entry_set_text (GTK_ENTRY (priv->location), uri);
+    const gchar* title = midori_web_view_get_display_title (
+        MIDORI_WEB_VIEW (web_view));
+    gchar* window_title = g_strconcat (title, " - ",
+                                       g_get_application_name (), NULL);
+    gtk_window_set_title (GTK_WINDOW (browser), window_title);
+    g_free (window_title);
+    _midori_browser_set_statusbar_text (browser, NULL);
+    _midori_browser_update_interface (browser);
+}
+
+static void
+_action_bookmark_open_activate (GtkAction*     action,
+                                MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks);
+    GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview);
+    if (selection)
+    {
+        GtkTreeModel* model;
+        GtkTreeIter iter;
+        if (gtk_tree_selection_get_selected (selection, &model, &iter))
+        {
+            KatzeXbelItem* item;
+            gtk_tree_model_get (model, &iter, 0, &item, -1);
+            if (katze_xbel_item_is_bookmark (item))
+                g_object_set(midori_browser_get_current_web_view (browser),
+                             "uri", katze_xbel_bookmark_get_href(item), NULL);
+        }
+    }
+}
+
+static void
+_action_bookmark_open_tab_activate (GtkAction*     action,
+                                    MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks);
+    GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview);
+    if (selection)
+    {
+        GtkTreeModel* model;
+        GtkTreeIter iter;
+        if (gtk_tree_selection_get_selected (selection, &model, &iter))
+        {
+            KatzeXbelItem* item;
+            gtk_tree_model_get (model, &iter, 0, &item, -1);
+            if (katze_xbel_item_is_bookmark (item))
+                midori_browser_append_xbel_item (browser, item);
+        }
+    }
+}
+
+static void
+_action_bookmark_open_window_activate (GtkAction*     action,
+                                       MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks);
+    GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview);
+    if (selection)
+    {
+        GtkTreeModel* model;
+        GtkTreeIter iter;
+        if (gtk_tree_selection_get_selected (selection, &model, &iter))
+        {
+            KatzeXbelItem* item;
+            gtk_tree_model_get (model, &iter, 0, &item, -1);
+            if (katze_xbel_item_is_bookmark (item))
+                midori_browser_append_xbel_item (browser, item);
+        }
+    }
+}
+
+static void
+_action_bookmark_edit_activate (GtkAction*     action,
+                                MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks);
+    GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview);
+    if (selection)
+    {
+        GtkTreeModel* model;
+        GtkTreeIter iter;
+        if (gtk_tree_selection_get_selected (selection, &model, &iter))
+        {
+            KatzeXbelItem* item;
+            gtk_tree_model_get (model, &iter, 0, &item, -1);
+            if (!katze_xbel_item_is_separator (item))
+                midori_browser_edit_bookmark_dialog_new (browser, item);
+        }
+    }
+}
+
+static void
+_action_trash_undo_activate (GtkAction*     action,
+                             MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    // Reopen the most recent trash item
+    KatzeXbelItem* item = midori_trash_get_nth_xbel_item (priv->trash, 0);
+    midori_browser_append_xbel_item (browser, item);
+    midori_trash_remove_nth_item (priv->trash, 0);
+    _midori_browser_update_actions (browser);
+}
+
+static void
+_action_trash_empty_activate (GtkAction*     action,
+                              MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    midori_trash_empty (priv->trash);
+    _midori_browser_update_actions (browser);
+}
+
+static void
+_action_bookmark_delete_activate (GtkAction* action,
+                                MidoriBrowser* browser)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks);
+    GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview);
+    if (selection)
+    {
+        GtkTreeModel* model;
+        GtkTreeIter iter;
+        if (gtk_tree_selection_get_selected (selection, &model, &iter))
+        {
+            KatzeXbelItem* item;
+            gtk_tree_model_get (model, &iter, 0, &item, -1);
+            KatzeXbelItem* parent = katze_xbel_item_get_parent (item);
+            katze_xbel_folder_remove_item (parent, item);
+            katze_xbel_item_unref (item);
+        }
+    }
+}
+
+// FIXME: Fill in a good description for each 'hm?'
+static const GtkActionEntry entries[] = {
+ { "File", NULL, "_File" },
+ { "WindowNew", STOCK_WINDOW_NEW,
+   NULL, "<Ctrl>n",
+   "Open a new window", G_CALLBACK (_action_window_new_activate) },
+ { "TabNew", STOCK_TAB_NEW,
+   NULL, "<Ctrl>t",
+   "Open a new tab", G_CALLBACK (_action_tab_new_activate) },
+ { "Open", GTK_STOCK_OPEN,
+   NULL, "<Ctrl>o",
+   "Open a file", G_CALLBACK (_action_open_activate) },
+ { "SaveAs", GTK_STOCK_SAVE_AS,
+   NULL, "<Ctrl>s",
+   "Save to a file", NULL/*G_CALLBACK (_action_saveas_activate)*/ },
+ { "TabClose", STOCK_TAB_CLOSE,
+   NULL, "<Ctrl>w",
+   "Close the current tab", G_CALLBACK (_action_tab_close_activate) },
+ { "WindowClose", STOCK_WINDOW_CLOSE,
+   NULL, "<Ctrl><Shift>w",
+   "Close this window", G_CALLBACK (_action_window_close_activate) },
+ { "PageSetup", GTK_STOCK_PROPERTIES,
+   "Pa_ge Setup", "",
+   "hm?", NULL/*G_CALLBACK (_action_page_setup_activate)*/ },
+ { "PrintPreview", GTK_STOCK_PRINT_PREVIEW,
+   NULL, "",
+   "hm?", NULL/*G_CALLBACK (_action_print_preview_activate)*/ },
+ { "Print", GTK_STOCK_PRINT,
+   NULL, "<Ctrl>p",
+   "hm?", NULL/*G_CALLBACK (_action_print_activate)*/ },
+ { "Quit", GTK_STOCK_QUIT,
+   NULL, "<Ctrl>q",
+   "Quit the application", G_CALLBACK (_action_quit_activate) },
+
+ { "Edit", NULL, "_Edit", NULL, NULL, G_CALLBACK (_action_edit_activate) },
+ { "Undo", GTK_STOCK_UNDO,
+   NULL, "<Ctrl>z",
+   "Undo the last modification", NULL/*G_CALLBACK (_action_undo_activate)*/ },
+ { "Redo", GTK_STOCK_REDO,
+   NULL, "<Ctrl><Shift>z",
+   "Redo the last modification", NULL/*G_CALLBACK (_action_redo_activate)*/ },
+ { "Cut", GTK_STOCK_CUT,
+   NULL, "<Ctrl>x",
+   "Cut the selected text", G_CALLBACK (_action_cut_activate) },
+ { "Copy", GTK_STOCK_COPY,
+   NULL, "<Ctrl>c",
+   "Copy the selected text", G_CALLBACK (_action_copy_activate) },
+ { "Copy_", GTK_STOCK_COPY,
+   NULL, "<Ctrl>c",
+   "Copy the selected text", G_CALLBACK (_action_copy_activate) },
+ { "Paste", GTK_STOCK_PASTE,
+   NULL, "<Ctrl>v",
+   "Paste text from the clipboard", G_CALLBACK (_action_paste_activate) },
+ { "Delete", GTK_STOCK_DELETE,
+   NULL, NULL,
+   "Delete the selected text", G_CALLBACK (_action_delete_activate) },
+ { "SelectAll", GTK_STOCK_SELECT_ALL,
+   NULL, "<Ctrl>a",
+   "Selected all text", G_CALLBACK (_action_select_all_activate) },
+ { "FormFill", STOCK_FORM_FILL,
+   NULL, "",
+   "hm?", NULL/*G_CALLBACK (_action_form_fill_activate)*/ },
+ { "Find", GTK_STOCK_FIND,
+   NULL, "<Ctrl>f",
+   "hm?", G_CALLBACK (_action_find_activate) },
+ { "FindNext", GTK_STOCK_GO_FORWARD,
+   "Find _Next", "<Ctrl>g",
+   "hm?", G_CALLBACK (_action_find_next_activate) },
+ { "FindPrevious", GTK_STOCK_GO_BACK,
+   "Find _Previous", "<Ctrl><Shift>g",
+   "hm?", G_CALLBACK (_action_find_previous_activate) },
+ { "FindQuick", GTK_STOCK_FIND,
+   "_Quick Find", "period",
+   "hm?", NULL/*G_CALLBACK (_action_find_quick_activate)*/ },
+ { "Preferences", GTK_STOCK_PREFERENCES,
+   NULL, "<Ctrl><Alt>p",
+   "hm?", G_CALLBACK (_action_preferences_activate) },
+
+ { "View", NULL, "_View" },
+ { "Toolbars", NULL, "_Toolbars" },
+ { "Reload", GTK_STOCK_REFRESH,
+   NULL, "<Ctrl>r",
+   "Reload the current page", G_CALLBACK (_action_reload_stop_activate) },
+ { "Stop", GTK_STOCK_REFRESH,
+   NULL, "<Ctrl>r",
+   "Stop loading the current page", G_CALLBACK (_action_reload_stop_activate) },
+ { "ReloadStop", GTK_STOCK_STOP,
+   NULL, "<Ctrl>r",
+   "Reload the current page", G_CALLBACK (_action_reload_stop_activate) },
+ { "ZoomIn", GTK_STOCK_ZOOM_IN,
+   NULL, "<Ctrl>plus",
+   "hm?", NULL/*G_CALLBACK (_action_zoom_in_activate)*/ },
+ { "ZoomOut", GTK_STOCK_ZOOM_OUT,
+   NULL, "<Ctrl>minus",
+   "hm?", NULL/*G_CALLBACK (_action_zoom_out_activate)*/ },
+ { "ZoomNormal", GTK_STOCK_ZOOM_100,
+   NULL, "<Ctrl>0",
+   "hm?", NULL/*G_CALLBACK (_action_zoom_normal_activate)*/ },
+ { "SourceView", STOCK_SOURCE_VIEW,
+   NULL, "",
+   "hm?", /*G_CALLBACK (_action_source_view_activate)*/ },
+ { "SelectionSourceView", STOCK_SOURCE_VIEW,
+   "View Selection Source", "",
+   "hm?", NULL/*G_CALLBACK (_action_selection_source_view_activate)*/ },
+ { "Fullscreen", GTK_STOCK_FULLSCREEN,
+   NULL, "F11",
+   "Toggle fullscreen view", G_CALLBACK (_action_fullscreen_activate) },
+
+ { "Go", NULL, "_Go" },
+ { "Back", GTK_STOCK_GO_BACK,
+   NULL, "<Alt>Left",
+   "hm?", G_CALLBACK (_action_back_activate) },
+ { "Forward", GTK_STOCK_GO_FORWARD,
+   NULL, "<Alt>Right",
+   "hm?", G_CALLBACK (_action_forward_activate) },
+ { "Home", STOCK_HOMEPAGE,
+   NULL, "<Alt>Home",
+   "hm?", G_CALLBACK (_action_home_activate) },
+ { "Location", GTK_STOCK_JUMP_TO,
+   "Location...", "<Ctrl>l",
+   "hm?", G_CALLBACK (_action_location_activate) },
+ { "Search", GTK_STOCK_FIND,
+   "Web Search...", "<Ctrl><Shift>f",
+   "hm?", G_CALLBACK (_action_search_activate) },
+ { "OpenInPageholder", GTK_STOCK_JUMP_TO,
+   "Open in Page_holder...", "",
+   "hm?", G_CALLBACK (_action_open_in_panel_activate) },
+ { "Trash", STOCK_USER_TRASH,
+   "Closed Tabs and Windows", "",
+   "Reopen a previously closed tab or window", NULL },
+ { "TrashEmpty", GTK_STOCK_CLEAR,
+   "Empty Trash", "",
+   "hm?", G_CALLBACK (_action_trash_empty_activate) },
+
+ { "Bookmarks", NULL, "_Bookmarks" },
+ { "BookmarkNew", STOCK_BOOKMARK_NEW,
+   NULL, "<Ctrl>d",
+   "hm?", G_CALLBACK (_action_bookmark_new_activate) },
+ { "BookmarksManage", NULL,
+   "_Manage Bookmarks", "<Ctrl>b",
+   "hm?", NULL/*G_CALLBACK (_action_bookmarks_manage_activate)*/ },
+ { "BookmarkOpen", GTK_STOCK_OPEN,
+   NULL, "",
+   "hm?", G_CALLBACK (_action_bookmark_open_activate) },
+ { "BookmarkOpenTab", STOCK_TAB_NEW,
+   "Open in New _Tab", "",
+   "hm?", G_CALLBACK (_action_bookmark_open_tab_activate) },
+ { "BookmarkOpenWindow", STOCK_WINDOW_NEW,
+   "Open in New _Window", "",
+   "hm?", G_CALLBACK (_action_bookmark_open_window_activate) },
+ { "BookmarkEdit", GTK_STOCK_EDIT,
+   NULL, "",
+   "hm?", G_CALLBACK (_action_bookmark_edit_activate) },
+ { "BookmarkDelete", GTK_STOCK_DELETE,
+   NULL, "",
+   "hm?", G_CALLBACK (_action_bookmark_delete_activate) },
+
+ { "Tools", NULL, "_Tools" },
+ { "ManageSearchEngines", GTK_STOCK_PROPERTIES,
+   "_Manage Search Engines", "<Ctrl><Alt>s",
+   "Add, edit and remove search engines...",
+   G_CALLBACK (_action_manage_search_engines_activate) },
+
+ { "Window", NULL, "_Window" },
+ { "TabPrevious", GTK_STOCK_GO_BACK,
+   "_Previous Tab", "<Ctrl>Page_Up",
+   "hm?", G_CALLBACK (_action_tab_previous_activate) },
+ { "TabNext", GTK_STOCK_GO_FORWARD,
+   "_Next Tab", "<Ctrl>Page_Down",
+   "hm?", G_CALLBACK (_action_tab_next_activate) },
+ { "TabOverview", NULL,
+   "Tab _Overview", "",
+   "hm?", NULL/*G_CALLBACK (_action_tab_overview_activate)*/ },
+
+ { "Help", NULL, "_Help" },
+ { "HelpContents", GTK_STOCK_HELP,
+   "_Contents", "F1",
+   "hm?", NULL/*G_CALLBACK (_action_help_contents_activate)*/ },
+ { "About", GTK_STOCK_ABOUT,
+   NULL, "",
+   "hm?", G_CALLBACK (_action_about_activate) },
+ };
+ static const guint entries_n = G_N_ELEMENTS(entries);
+
+static const GtkToggleActionEntry toggle_entries[] = {
+ { "PrivateBrowsing", NULL,
+   "P_rivate Browsing", "",
+   "hm?", NULL/*G_CALLBACK (_action_private_browsing_activate)*/,
+   FALSE },
+ { "WorkOffline", GTK_STOCK_DISCONNECT,
+   "_Work Offline", "",
+   "hm?", NULL/*G_CALLBACK (_action_work_offline_activate)*/,
+   FALSE },
+
+ { "Navigationbar", NULL,
+   "_Navigationbar", "",
+   "hm?", G_CALLBACK (_action_navigationbar_activate),
+   FALSE },
+ { "Panel", NULL,
+   "_Panel", "F9",
+   "hm?", G_CALLBACK (_action_panel_activate),
+   FALSE },
+ { "Bookmarkbar", NULL,
+   "_Bookmarkbar", "",
+   "hm?", G_CALLBACK (_action_bookmarkbar_activate),
+   FALSE },
+ { "Downloadbar", NULL,
+   "_Downloadbar", "",
+   "hm?", NULL/*G_CALLBACK (_action_downloadbar_activate)*/,
+   FALSE },
+ { "Statusbar", NULL,
+   "_Statusbar", "",
+   "hm?", G_CALLBACK (_action_statusbar_activate),
+   FALSE },
+ };
+ static const guint toggle_entries_n = G_N_ELEMENTS(toggle_entries);
+
+static void
+midori_browser_window_state_event_cb (MidoriBrowser*       browser,
+                                      GdkEventWindowState* event)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
+    {
+        if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)
+        {
+            gtk_widget_hide (priv->menubar);
+            g_object_set (priv->button_fullscreen,
+                          "stock-id", GTK_STOCK_LEAVE_FULLSCREEN, NULL);
+            gtk_widget_show (priv->button_fullscreen);
+        }
+        else
+        {
+            gtk_widget_show (priv->menubar);
+            gtk_widget_hide (priv->button_fullscreen);
+            g_object_set (priv->button_fullscreen,
+                          "stock-id", GTK_STOCK_FULLSCREEN, NULL);
+        }
+    }
+}
+
+static void
+midori_browser_size_allocate_cb (MidoriBrowser* browser,
+                                 GtkAllocation* allocation)
+{
+    GtkWidget* widget = GTK_WIDGET (browser);
+
+    if (GTK_WIDGET_REALIZED (widget))
+    {
+        GdkWindowState state = gdk_window_get_state (widget->window);
+        if (!(state & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)))
+        {
+            config->winWidth = allocation->width;
+            config->winHeight = allocation->height;
+        }
+    }
+}
+
+static const gchar* ui_markup =
+ "<ui>"
+  "<menubar>"
+   "<menu action='File'>"
+    "<menuitem action='WindowNew'/>"
+    "<menuitem action='TabNew'/>"
+    "<separator/>"
+    "<menuitem action='Open'/>"
+    "<separator/>"
+    "<menuitem action='SaveAs'/>"
+    "<separator/>"
+    "<menuitem action='TabClose'/>"
+    "<menuitem action='WindowClose'/>"
+    "<separator/>"
+    "<menuitem action='PageSetup'/>"
+    "<menuitem action='PrintPreview'/>"
+    "<menuitem action='Print'/>"
+    "<separator/>"
+    "<menuitem action='PrivateBrowsing'/>"
+    "<menuitem action='WorkOffline'/>"
+    "<separator/>"
+    "<menuitem action='Quit'/>"
+   "</menu>"
+   "<menu action='Edit'>"
+    "<menuitem action='Undo'/>"
+    "<menuitem action='Redo'/>"
+    "<separator/>"
+    "<menuitem action='Cut'/>"
+    "<menuitem action='Copy'/>"
+    "<menuitem action='Paste'/>"
+    "<menuitem action='Delete'/>"
+    "<separator/>"
+    "<menuitem action='SelectAll'/>"
+    "<separator/>"
+    "<menuitem action='Preferences'/>"
+   "</menu>"
+   "<menu action='View'>"
+    "<menu action='Toolbars'>"
+     "<menuitem action='Navigationbar'/>"
+     "<menuitem action='Bookmarkbar'/>"
+     "<menuitem action='Downloadbar'/>"
+     "<menuitem action='Statusbar'/>"
+    "</menu>"
+    "<menuitem action='Panel'/>"
+    "<separator/>"
+    "<menuitem action='Reload'/>"
+    "<menuitem action='Stop'/>"
+    "<separator/>"
+    "<menuitem action='ZoomIn'/>"
+    "<menuitem action='ZoomOut'/>"
+    "<menuitem action='ZoomNormal'/>"
+    "<separator/>"
+    "<menuitem action='SourceView'/>"
+    "<menuitem action='Fullscreen'/>"
+   "</menu>"
+   "<menu action='Go'>"
+    "<menuitem action='Back'/>"
+    "<menuitem action='Forward'/>"
+    "<menuitem action='Home'/>"
+    "<menuitem action='Location'/>"
+    "<menuitem action='Search'/>"
+    "<menuitem action='OpenInPageholder'/>"
+    "<menu action='Trash'>"
+    // Closed tabs shall be prepended here
+     "<separator/>"
+     "<menuitem action='TrashEmpty'/>"
+    "</menu>"
+    "<separator/>"
+    "<menuitem action='Find'/>"
+    "<menuitem action='FindNext'/>"
+    "<menuitem action='FindPrevious'/>"
+    "<separator/>"
+    "<menuitem action='FormFill'/>"
+   "</menu>"
+   "<menu action='Bookmarks'>"
+    "<menuitem action='BookmarkNew'/>"
+    "<menuitem action='BookmarksManage'/>"
+    "<separator/>"
+    // Bookmarks shall be appended here
+   "</menu>"
+   "<menu action='Tools'>"
+    "<menuitem action='ManageSearchEngines'/>"
+    // Panel items shall be appended here
+   "</menu>"
+   "<menu action='Window'>"
+    "<menuitem action='TabPrevious'/>"
+    "<menuitem action='TabNext'/>"
+    "<menuitem action='TabOverview'/>"
+    "<separator/>"
+    // All open tabs shall be appended here
+   "</menu>"
+   "<menu action='Help'>"
+    "<menuitem action='HelpContents'/>"
+    "<menuitem action='About'/>"
+   "</menu>"
+  "</menubar>"
+  "<toolbar name='toolbar_navigation'>"
+   "<toolitem action='TabNew'/>"
+   "<toolitem action='Back'/>"
+   "<toolitem action='Forward'/>"
+   "<toolitem action='ReloadStop'/>"
+   "<toolitem action='Home'/>"
+   "<toolitem action='FormFill'/>"
+   "<placeholder name='Location'/>"
+   "<placeholder name='Search'/>"
+   "<placeholder name='TabTrash'/>"
+  "</toolbar>"
+  "<toolbar name='toolbar_bookmarks'>"
+   "<toolitem action='BookmarkNew'/>"
+   "<toolitem action='BookmarkEdit'/>"
+   "<toolitem action='BookmarkDelete'/>"
+  "</toolbar>"
+  "<popup name='popup_bookmark'>"
+   "<menuitem action='BookmarkOpen'/>"
+   "<menuitem action='BookmarkOpenTab'/>"
+   "<menuitem action='BookmarkOpenWindow'/>"
+   "<separator/>"
+   "<menuitem action='BookmarkEdit'/>"
+   "<menuitem action='BookmarkDelete'/>"
+  "</popup>"
+ "</ui>";
+
+static void
+midori_browser_init (MidoriBrowser* browser)
+{
+    browser->priv = MIDORI_BROWSER_GET_PRIVATE (browser);
+
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    // Setup the window metrics
+    g_signal_connect (browser, "window-state-event",
+                      G_CALLBACK (midori_browser_window_state_event_cb), NULL);
+    GdkScreen* screen = gtk_window_get_screen (GTK_WINDOW (browser));
+    const gint default_width = (gint)gdk_screen_get_width (screen) / 1.7;
+    const gint default_height = (gint)gdk_screen_get_height (screen) / 1.7;
+    if (config->rememberWinSize)
+    {
+        if (!config->winWidth && !config->winHeight)
+        {
+            config->winWidth = default_width;
+            config->winHeight = default_width;
+        }
+        gtk_window_set_default_size (GTK_WINDOW (browser),
+                                     config->winWidth, config->winHeight);
+    }
+    else
+        gtk_window_set_default_size (GTK_WINDOW(browser),
+                                     default_width, default_height);
+    g_signal_connect (browser, "size-allocate",
+                      G_CALLBACK (midori_browser_size_allocate_cb), NULL);
+    // FIXME: Use custom program icon
+    gtk_window_set_icon_name (GTK_WINDOW (browser), "web-browser");
+    gtk_window_set_title (GTK_WINDOW (browser), g_get_application_name ());
+    GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
+    gtk_container_add (GTK_CONTAINER (browser), vbox);
+    gtk_widget_show (vbox);
+
+    // Let us see some ui manager magic
+    priv->action_group = gtk_action_group_new ("Browser");
+    gtk_action_group_add_actions (priv->action_group,
+                                  entries, entries_n, browser);
+    gtk_action_group_add_toggle_actions (priv->action_group,
+        toggle_entries, toggle_entries_n, browser);
+    GtkUIManager* ui_manager = gtk_ui_manager_new ();
+    gtk_ui_manager_insert_action_group (ui_manager, priv->action_group, 0);
+    gtk_window_add_accel_group (GTK_WINDOW (browser),
+                                gtk_ui_manager_get_accel_group (ui_manager));
+
+    GError* error = NULL;
+    if (!gtk_ui_manager_add_ui_from_string(ui_manager, ui_markup, -1, &error))
+    {
+        // TODO: Should this be a message dialog? When does this happen?
+        g_message ("User interface couldn't be created: %s", error->message);
+        g_error_free (error);
+    }
+
+    GtkAction* action;
+    // Make all actions except toplevel menus which lack a callback insensitive
+    // This will vanish once all actions are implemented
+    guint i;
+    for (i = 0; i < entries_n; i++)
+    {
+        action = gtk_action_group_get_action(priv->action_group,
+                                             entries[i].name);
+        gtk_action_set_sensitive (action,
+                                  entries[i].callback || !entries[i].tooltip);
+    }
+    for (i = 0; i < toggle_entries_n; i++)
+    {
+        action = gtk_action_group_get_action (priv->action_group,
+                                              toggle_entries[i].name);
+        gtk_action_set_sensitive (action, toggle_entries[i].callback != NULL);
+    }
+
+    //_action_set_active(browser, "Downloadbar", config->toolbarDownloads);
+
+    // Create the menubar
+    priv->menubar = gtk_ui_manager_get_widget (ui_manager, "/menubar");
+    GtkWidget* menuitem = gtk_menu_item_new();
+    gtk_widget_show (menuitem);
+    priv->throbber = katze_throbber_new();
+    gtk_widget_show(priv->throbber);
+    gtk_container_add (GTK_CONTAINER (menuitem), priv->throbber);
+    gtk_widget_set_sensitive (menuitem, FALSE);
+    gtk_menu_item_set_right_justified (GTK_MENU_ITEM (menuitem), TRUE);
+    gtk_menu_shell_append (GTK_MENU_SHELL (priv->menubar), menuitem);
+    gtk_box_pack_start (GTK_BOX (vbox), priv->menubar, FALSE, FALSE, 0);
+    menuitem = gtk_ui_manager_get_widget (ui_manager, "/menubar/Go/Trash");
+    g_signal_connect (menuitem, "activate",
+                      G_CALLBACK (midori_browser_menu_trash_activate_cb),
+                      browser);
+    priv->menu_bookmarks = gtk_menu_item_get_submenu (GTK_MENU_ITEM (
+        gtk_ui_manager_get_widget (ui_manager, "/menubar/Bookmarks")));
+    menuitem = gtk_separator_menu_item_new ();
+    gtk_widget_show (menuitem);
+    gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu_bookmarks), menuitem);
+    priv->popup_bookmark = gtk_ui_manager_get_widget (
+        ui_manager, "/popup_bookmark");
+    g_object_ref (priv->popup_bookmark);
+    priv->menu_tools = gtk_menu_item_get_submenu (GTK_MENU_ITEM (
+        gtk_ui_manager_get_widget (ui_manager, "/menubar/Tools")));
+    menuitem = gtk_separator_menu_item_new();
+    gtk_widget_show (menuitem);
+    gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu_tools), menuitem);
+    priv->menu_window = gtk_menu_item_get_submenu (GTK_MENU_ITEM (
+        gtk_ui_manager_get_widget (ui_manager, "/menubar/Window")));
+    menuitem = gtk_separator_menu_item_new();
+    gtk_widget_show (menuitem);
+    gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu_window), menuitem);
+    gtk_widget_show (priv->menubar);
+    _action_set_sensitive (browser, "PrivateBrowsing", FALSE);
+    _action_set_sensitive (browser, "WorkOffline", FALSE);
+
+    // Create the navigationbar
+    priv->navigationbar = gtk_ui_manager_get_widget (
+        ui_manager, "/toolbar_navigation");
+    gtk_toolbar_set_style (GTK_TOOLBAR (priv->navigationbar),
+                           config_to_toolbarstyle (config->toolbarStyle));
+    GtkSettings* gtk_settings = gtk_widget_get_settings (priv->navigationbar);
+    g_signal_connect (gtk_settings, "notify::gtk-toolbar-style",
+                      G_CALLBACK (midori_browser_navigationbar_notify_style_cb),
+                      browser);
+    gtk_toolbar_set_icon_size (GTK_TOOLBAR (priv->navigationbar),
+                               config_to_toolbariconsize (config->toolbarSmall));
+    gtk_toolbar_set_show_arrow (GTK_TOOLBAR (priv->navigationbar), TRUE);
+    gtk_box_pack_start (GTK_BOX (vbox), priv->navigationbar, FALSE, FALSE, 0);
+    priv->button_tab_new = gtk_ui_manager_get_widget (
+        ui_manager, "/toolbar_navigation/TabNew");
+    g_object_set (_action_by_name (browser, "Back"), "is-important", TRUE, NULL);
+
+    // Location
+    priv->location = sexy_icon_entry_new();
+    entry_setup_completion (GTK_ENTRY (priv->location));
+    priv->location_icon = gtk_image_new ();
+    sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (priv->location)
+     , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE (priv->location_icon));
+    sexy_icon_entry_add_clear_button (SEXY_ICON_ENTRY (priv->location));
+    g_signal_connect (priv->location, "key-press-event",
+                      G_CALLBACK (midori_browser_location_key_press_event_cb),
+                      browser);
+    g_signal_connect (priv->location, "changed",
+                      G_CALLBACK (midori_browser_location_changed_cb), browser);
+    GtkToolItem* toolitem = gtk_tool_item_new ();
+    gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE);
+    gtk_container_add (GTK_CONTAINER(toolitem), priv->location);
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->navigationbar), toolitem, -1);
+
+    // Search
+    priv->search = sexy_icon_entry_new ();
+    sexy_icon_entry_set_icon_highlight (SEXY_ICON_ENTRY (priv->search),
+                                        SEXY_ICON_ENTRY_PRIMARY, TRUE);
+    // TODO: Make this actively resizable or enlarge to fit contents?
+    // FIXME: The interface is somewhat awkward and ought to be rethought
+    // TODO: Display "show in context menu" search engines as "completion actions"
+    entry_setup_completion (GTK_ENTRY (priv->search));
+    update_searchEngine (config->searchEngine, priv->search);
+    g_object_connect (priv->search,
+                      "signal::icon-released",
+                      on_webSearch_icon_released, browser,
+                      "signal::key-press-event",
+                      on_webSearch_key_down, browser,
+                      "signal::scroll-event",
+                      on_webSearch_scroll, browser,
+                      "signal::activate",
+                      on_webSearch_activate, browser,
+                      NULL);
+    toolitem = gtk_tool_item_new ();
+    gtk_container_add (GTK_CONTAINER (toolitem), priv->search);
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->navigationbar), toolitem, -1);
+    action = gtk_action_group_get_action (priv->action_group, "Trash");
+    priv->button_trash = gtk_action_create_tool_item (action);
+    g_signal_connect (priv->button_trash, "clicked",
+                      G_CALLBACK (midori_browser_menu_trash_activate_cb), browser);
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->navigationbar),
+                        GTK_TOOL_ITEM (priv->button_trash), -1);
+    sokoke_container_show_children (GTK_CONTAINER (priv->navigationbar));
+    action = gtk_action_group_get_action (priv->action_group, "Fullscreen");
+    priv->button_fullscreen = gtk_action_create_tool_item (action);
+    gtk_widget_hide (priv->button_fullscreen);
+    g_signal_connect (priv->button_fullscreen, "clicked",
+                      G_CALLBACK (_action_fullscreen_activate), browser);
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->navigationbar),
+                        GTK_TOOL_ITEM (priv->button_fullscreen), -1);
+    _action_set_active (browser, "Navigationbar", config->toolbarNavigation);
+
+    // Bookmarkbar
+    priv->bookmarkbar = gtk_toolbar_new ();
+    gtk_toolbar_set_icon_size (GTK_TOOLBAR (priv->bookmarkbar),
+                               GTK_ICON_SIZE_MENU);
+    gtk_toolbar_set_style (GTK_TOOLBAR(priv->bookmarkbar),
+                           GTK_TOOLBAR_BOTH_HORIZ);
+    _midori_browser_create_bookmark_menu (browser, bookmarks,
+                                          priv->menu_bookmarks);
+    for (i = 0; i < katze_xbel_folder_get_n_items (bookmarks); i++)
+    {
+        KatzeXbelItem* item = katze_xbel_folder_get_nth_item (bookmarks, i);
+        const gchar* title = katze_xbel_item_is_separator (item)
+         ? "" : katze_xbel_item_get_title (item);
+        const gchar* desc = katze_xbel_item_is_separator (item)
+         ? "" : katze_xbel_item_get_desc (item);
+        switch (katze_xbel_item_get_kind (item))
+        {
+        case KATZE_XBEL_ITEM_KIND_FOLDER:
+            toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_DIRECTORY);
+            gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), title);
+            gtk_tool_item_set_is_important(toolitem, TRUE);
+            g_signal_connect (toolitem, "clicked",
+                G_CALLBACK (midori_browser_bookmarkbar_folder_activate_cb),
+                browser);
+            sokoke_tool_item_set_tooltip_text(toolitem, desc);
+            g_object_set_data (G_OBJECT (toolitem), "KatzeXbelItem", item);
+            break;
+        case KATZE_XBEL_ITEM_KIND_BOOKMARK:
+            toolitem = gtk_tool_button_new_from_stock (STOCK_BOOKMARK);
+            gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), title);
+            gtk_tool_item_set_is_important(toolitem, TRUE);
+            g_signal_connect (toolitem, "clicked",
+                G_CALLBACK (midori_browser_menu_bookmarks_item_activate_cb),
+                browser);
+            sokoke_tool_item_set_tooltip_text(toolitem, desc);
+            g_object_set_data (G_OBJECT (toolitem), "KatzeXbelItem", item);
+            break;
+        case KATZE_XBEL_ITEM_KIND_SEPARATOR:
+            toolitem = gtk_separator_tool_item_new ();
+            break;
+        default:
+            g_warning ("Unknown item kind");
+        }
+        gtk_toolbar_insert (GTK_TOOLBAR (priv->bookmarkbar), toolitem, -1);
+    }
+    sokoke_container_show_children (GTK_CONTAINER (priv->bookmarkbar));
+    gtk_box_pack_start (GTK_BOX (vbox), priv->bookmarkbar, FALSE, FALSE, 0);
+    _action_set_active (browser, "Bookmarkbar", config->toolbarBookmarks);
+
+    // Superuser warning
+    GtkWidget* hbox;
+    if ((hbox = sokoke_superuser_warning_new ()))
+        gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+    // Create the panel
+    GtkWidget* hpaned = gtk_hpaned_new ();
+    gtk_paned_set_position (GTK_PANED (hpaned), config->winPanelPos);
+    g_signal_connect (hpaned, "notify::position",
+                      G_CALLBACK (midori_panel_notify_position_cb),
+                      browser);
+    gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
+    gtk_widget_show (hpaned);
+    priv->panel = g_object_new (MIDORI_TYPE_PANEL,
+                                "shadow-type", GTK_SHADOW_IN,
+                                "menu", priv->menu_tools,
+                                NULL);
+    g_signal_connect (priv->panel, "close",
+                      G_CALLBACK (midori_panel_close_cb), browser);
+    gtk_paned_pack1 (GTK_PANED (hpaned), priv->panel, FALSE, FALSE);
+    sokoke_widget_set_visible (priv->panel, config->panelShow);
+    _action_set_active (browser, "Panel", config->panelShow);
+
+    // Bookmarks
+    GtkWidget* box = gtk_vbox_new (FALSE, 0);
+    GtkWidget* toolbar = gtk_ui_manager_get_widget (ui_manager, "/toolbar_bookmarks");
+    gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_MENU);
+    gtk_box_pack_start (GTK_BOX (box), toolbar, FALSE, FALSE, 0);
+    GtkTreeViewColumn* column;
+    GtkCellRenderer* renderer_text;
+    GtkCellRenderer* renderer_pixbuf;
+    GtkTreeStore* treestore = gtk_tree_store_new (1, KATZE_TYPE_XBEL_ITEM);
+    GtkWidget* treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (treestore));
+    gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (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_browser_bookmarks_item_render_icon_cb,
+        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_browser_bookmarks_item_render_text_cb,
+        treeview, NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+    _tree_store_insert_folder (GTK_TREE_STORE (treestore), NULL, bookmarks);
+    g_object_unref (treestore);
+    g_object_connect (treeview,
+                      "signal::row-activated",
+                      midori_panel_bookmarks_row_activated_cb, browser,
+                      "signal::cursor-changed",
+                      midori_panel_bookmarks_cursor_or_row_changed_cb, browser,
+                      "signal::columns-changed",
+                      midori_panel_bookmarks_cursor_or_row_changed_cb, browser,
+                      "signal::button-release-event",
+                      midori_panel_bookmarks_button_release_event_cb, browser,
+                      "signal::popup-menu",
+                      midori_panel_bookmarks_popup_menu_cb, browser,
+                      NULL);
+    midori_panel_bookmarks_cursor_or_row_changed_cb (GTK_TREE_VIEW (treeview),
+                                                     browser);
+    gtk_box_pack_start (GTK_BOX (box), treeview, FALSE, FALSE, 0);
+    priv->panel_bookmarks = treeview;
+    gtk_widget_show_all (box);
+    midori_panel_append_page (MIDORI_PANEL (priv->panel),
+                              box, "vcard", "Bookmarks");
+    action = _action_by_name (browser, "PanelBookmarks");
+
+    // Downloads
+    priv->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW,
+                                           "uri", "about:blank",
+                                           NULL);
+    gtk_widget_show (priv->panel_pageholder);
+    midori_panel_append_page (MIDORI_PANEL (priv->panel),
+                              priv->panel_pageholder,
+                              "package", "Downloads");
+
+    // Console
+    priv->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW,
+                                           "uri", "about:blank",
+                                           NULL);
+    gtk_widget_show (priv->panel_pageholder);
+    midori_panel_append_page (MIDORI_PANEL (priv->panel),
+                              priv->panel_pageholder,
+                              "terminal", "Console");
+
+    // History
+    priv->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW,
+                                           "uri", "about:blank",
+                                           NULL);
+    gtk_widget_show (priv->panel_pageholder);
+    midori_panel_append_page (MIDORI_PANEL (priv->panel),
+                              priv->panel_pageholder,
+                              "document-open-recent", "History");
+
+    // Pageholder
+    priv->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW,
+                                           "uri", config->panelPageholder,
+                                           NULL);
+    gtk_widget_show (priv->panel_pageholder);
+    midori_panel_append_page (MIDORI_PANEL (priv->panel),
+                              priv->panel_pageholder,
+                              GTK_STOCK_CONVERT, "Pageholder");
+
+    midori_panel_set_current_page (MIDORI_PANEL (priv->panel),
+                                   config->panelActive);
+    sokoke_widget_set_visible (priv->panel, config->panelShow);
+
+    // Notebook, containing all web_views
+    priv->notebook = gtk_notebook_new ();
+    gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE);
+    gtk_paned_pack2 (GTK_PANED (hpaned), priv->notebook, FALSE, FALSE);
+    g_signal_connect_after (priv->notebook, "switch-page",
+                            G_CALLBACK (gtk_notebook_switch_page_cb),
+                            browser);
+    gtk_widget_show (priv->notebook);
+
+    // Incremental findbar
+    priv->find = gtk_toolbar_new ();
+    gtk_toolbar_set_icon_size (GTK_TOOLBAR (priv->find), GTK_ICON_SIZE_MENU);
+    gtk_toolbar_set_style (GTK_TOOLBAR (priv->find), GTK_TOOLBAR_BOTH_HORIZ);
+    toolitem = gtk_tool_item_new ();
+    gtk_container_set_border_width (GTK_CONTAINER (toolitem), 6);
+    gtk_container_add (GTK_CONTAINER (toolitem),
+                       gtk_label_new_with_mnemonic ("_Inline find:"));
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->find), toolitem, -1);
+    priv->find_text = sexy_icon_entry_new ();
+    GtkWidget* icon = gtk_image_new_from_stock (GTK_STOCK_FIND,
+                                                GTK_ICON_SIZE_MENU);
+    sexy_icon_entry_set_icon (SEXY_ICON_ENTRY(priv->find_text),
+                              SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(icon));
+    sexy_icon_entry_add_clear_button (SEXY_ICON_ENTRY(priv->find_text));
+    g_signal_connect (priv->find_text, "activate",
+        G_CALLBACK (_action_find_next_activate), browser);
+    toolitem = gtk_tool_item_new ();
+    gtk_container_add (GTK_CONTAINER (toolitem), priv->find_text);
+    gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE);
+    gtk_toolbar_insert (GTK_TOOLBAR(priv->find), toolitem, -1);
+    toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_GO_BACK);
+    gtk_tool_item_set_is_important (toolitem, TRUE);
+    g_signal_connect (toolitem, "clicked",
+        G_CALLBACK (_action_find_previous_activate), browser);
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->find), toolitem, -1);
+    toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD);
+    gtk_tool_item_set_is_important (toolitem, TRUE);
+    g_signal_connect (toolitem, "clicked",
+        G_CALLBACK (_action_find_next_activate), browser);
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->find), toolitem, -1);
+    priv->find_case = gtk_toggle_tool_button_new_from_stock (
+        GTK_STOCK_SPELL_CHECK);
+    gtk_tool_button_set_label (GTK_TOOL_BUTTON (priv->find_case), "Match Case");
+    gtk_tool_item_set_is_important (GTK_TOOL_ITEM (priv->find_case), TRUE);
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->find), priv->find_case, -1);
+    priv->find_highlight = gtk_toggle_tool_button_new_from_stock (
+        GTK_STOCK_SELECT_ALL);
+    g_signal_connect (priv->find_highlight, "toggled",
+                      G_CALLBACK (_find_highlight_toggled), browser);
+    gtk_tool_button_set_label (GTK_TOOL_BUTTON (priv->find_highlight),
+                               "Highlight Matches");
+    gtk_tool_item_set_is_important (GTK_TOOL_ITEM (priv->find_highlight), TRUE);
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->find), priv->find_highlight, -1);
+    toolitem = gtk_separator_tool_item_new ();
+    gtk_separator_tool_item_set_draw (
+        GTK_SEPARATOR_TOOL_ITEM (toolitem), FALSE);
+    gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE);
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->find), toolitem, -1);
+    toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_CLOSE);
+    gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), "Close Findbar");
+    g_signal_connect (toolitem, "clicked",
+        G_CALLBACK (midori_browser_find_button_close_clicked_cb), browser);
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->find), toolitem, -1);
+    sokoke_container_show_children (GTK_CONTAINER (priv->find));
+    gtk_box_pack_start (GTK_BOX (vbox), priv->find, FALSE, FALSE, 0);
+
+    // Statusbar
+    // TODO: fix children overlapping statusbar border
+    priv->statusbar = gtk_statusbar_new ();
+    gtk_box_pack_start (GTK_BOX (vbox), priv->statusbar, FALSE, FALSE, 0);
+    priv->progressbar = gtk_progress_bar_new ();
+    // Setting the progressbar's height to 1 makes it fit in the statusbar
+    gtk_widget_set_size_request (priv->progressbar, -1, 1);
+    gtk_box_pack_start (GTK_BOX (priv->statusbar), priv->progressbar,
+                        FALSE, FALSE, 3);
+    _action_set_active (browser, "Statusbar", config->toolbarStatus);
+
+    g_object_unref (ui_manager);
+
+    sokoke_widget_set_visible (priv->button_tab_new, config->toolbarNewTab);
+    sokoke_widget_set_visible (priv->search, config->toolbarWebSearch);
+    sokoke_widget_set_visible (priv->button_trash, config->toolbarClosedTabs);
+}
+
+static void
+midori_browser_finalize (GObject* object)
+{
+    MidoriBrowser* browser = MIDORI_BROWSER (object);
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    g_free (priv->uri);
+    g_free (priv->title);
+    g_free (priv->statusbar_text);
+
+    if (priv->proxy_xbel_folder)
+        katze_xbel_item_unref (priv->proxy_xbel_folder);
+
+    if (priv->settings)
+        g_object_unref (priv->settings);
+    if (priv->trash)
+        g_object_unref (priv->trash);
+
+    G_OBJECT_CLASS (midori_browser_parent_class)->finalize (object);
+}
+
+static void
+midori_browser_set_property (GObject*      object,
+                             guint         prop_id,
+                             const GValue* value,
+                             GParamSpec*   pspec)
+{
+    MidoriBrowser* browser = MIDORI_BROWSER (object);
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    switch (prop_id)
+    {
+    case PROP_STATUSBAR_TEXT:
+        _midori_browser_set_statusbar_text (browser, g_value_get_string (value));
+        break;
+    case PROP_SETTINGS:
+        katze_object_assign (priv->settings, g_value_get_object (value));
+        g_object_ref (priv->settings);
+        // FIXME: Assign settings to each web view
+        break;
+    case PROP_TRASH:
+        ; // FIXME: Disconnect handlers
+        katze_object_assign (priv->trash, g_value_get_object (value));
+        g_object_ref (priv->trash);
+        // FIXME: Connect to updates
+        _midori_browser_update_actions (browser);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+midori_browser_get_property (GObject*    object,
+                             guint       prop_id,
+                             GValue*     value,
+                             GParamSpec* pspec)
+{
+    MidoriBrowser* browser = MIDORI_BROWSER (object);
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    switch (prop_id)
+    {
+    case PROP_STATUSBAR_TEXT:
+        g_value_set_string (value, priv->statusbar_text);
+        break;
+    case PROP_SETTINGS:
+        g_value_set_object (value, priv->settings);
+        break;
+    case PROP_TRASH:
+        g_value_set_object (value, priv->trash);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+/**
+ * midori_browser_new:
+ *
+ * Creates a new browser widget.
+ *
+ * A browser is a window with toolbars and one or multiple web views.
+ *
+ * Return value: a new #MidoriBrowser
+ **/
+GtkWidget*
+midori_browser_new (void)
+{
+    MidoriBrowser* browser = g_object_new (MIDORI_TYPE_BROWSER,
+                                           NULL);
+
+    return GTK_WIDGET (browser);
+}
+
+/**
+ * midori_browser_append_tab:
+ * @browser: a #MidoriBrowser
+ * @widget: a tab
+ *
+ * Appends an arbitrary widget in the form of a new tab and creates an
+ * according item in the Window menu.
+ *
+ * Return value: the index of the new tab, or -1 in case of an error
+ **/
+gint
+midori_browser_append_tab (MidoriBrowser* browser,
+                           GtkWidget*     widget)
+{
+    g_return_val_if_fail (GTK_IS_WIDGET (widget), -1);
+
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkWidget* scrolled = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                    GTK_POLICY_AUTOMATIC,
+                                    GTK_POLICY_AUTOMATIC);
+    GTK_WIDGET_SET_FLAGS (scrolled, GTK_CAN_FOCUS);
+    GtkWidget* child;
+    GObjectClass* gobject_class = G_OBJECT_GET_CLASS (widget);
+    if (GTK_WIDGET_CLASS (gobject_class)->set_scroll_adjustments_signal)
+        child = widget;
+    else
+    {
+        child = gtk_viewport_new (NULL, NULL);
+        gtk_widget_show (child);
+        gtk_container_add (GTK_CONTAINER (child), widget);
+    }
+    gtk_container_add (GTK_CONTAINER (scrolled), child);
+    gtk_widget_show (scrolled);
+
+    GtkWidget* label = NULL;
+    GtkWidget* menuitem = NULL;
+
+    if (MIDORI_IS_WEB_VIEW (widget))
+    {
+        label = midori_web_view_get_proxy_tab_label (MIDORI_WEB_VIEW (widget));
+
+        menuitem = midori_web_view_get_proxy_menu_item (MIDORI_WEB_VIEW (widget));
+
+        if (priv->proxy_xbel_folder)
+        {
+            KatzeXbelItem* xbel_item = midori_web_view_get_proxy_xbel_item (
+                MIDORI_WEB_VIEW (widget));
+            katze_xbel_item_ref (xbel_item);
+            katze_xbel_folder_append_item (priv->proxy_xbel_folder, xbel_item);
+        }
+
+        g_object_connect (widget,
+                          "signal::navigation-requested",
+                          midori_web_view_navigation_requested_cb, browser,
+                          "signal::load-started",
+                          midori_web_view_load_started_cb, browser,
+                          "signal::load-committed",
+                          midori_web_view_load_committed_cb, browser,
+                          "signal::progress-started",
+                          midori_web_view_progress_started_cb, browser,
+                          "signal::progress-changed",
+                          midori_web_view_progress_changed_cb, browser,
+                          "signal::progress-done",
+                          midori_web_view_progress_done_cb, browser,
+                          "signal::load-done",
+                          midori_web_view_load_done_cb, browser,
+                          "signal::title-changed",
+                          midori_web_view_title_changed_cb, browser,
+                          "signal::status-bar-text-changed",
+                          midori_web_view_statusbar_text_changed_cb, browser,
+                          "signal::element-motion",
+                          midori_web_view_element_motion_cb, browser,
+                          "signal::console-message",
+                          midori_web_view_console_message_cb, browser,
+                          "signal::close",
+                          midori_web_view_close_cb, browser,
+                          "signal::new-tab",
+                          midori_web_view_new_tab_cb, browser,
+                          "signal::new-window",
+                          midori_web_view_new_window_cb, browser,
+                          "signal::populate-popup",
+                          midori_web_view_populate_popup_cb, browser,
+                          "signal::leave-notify-event",
+                          midori_web_view_leave_notify_event_cb, browser,
+                          "signal::destroy",
+                          midori_web_view_destroy_cb, browser,
+                          NULL);
+    }
+
+    if (menuitem)
+    {
+        gtk_widget_show (menuitem);
+        g_signal_connect (menuitem, "activate",
+            G_CALLBACK (midori_browser_window_menu_item_activate_cb), browser);
+        gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu_window), menuitem);
+    }
+
+    guint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+    gtk_notebook_insert_page (GTK_NOTEBOOK (priv->notebook), scrolled,
+                              label, n + 1);
+    #if GTK_CHECK_VERSION(2, 10, 0)
+    gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (priv->notebook),
+                                      scrolled, TRUE);
+    gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (priv->notebook),
+                                     scrolled, TRUE);
+    #endif
+    _midori_browser_update_actions (browser);
+
+    n = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), scrolled);
+    if (!config->openTabsInTheBackground)
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n);
+    return n;
+}
+
+/**
+ * midori_browser_remove_tab:
+ * @browser: a #MidoriBrowser
+ * @widget: a tab
+ *
+ * Removes an existing tab from the browser, including an associated menu item.
+ **/
+void
+midori_browser_remove_tab (MidoriBrowser* browser,
+                           GtkWidget*     widget)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, widget);
+    gtk_container_remove (GTK_CONTAINER (priv->notebook), scrolled);
+
+    // FIXME: Remove the menuitem if this is a web view
+}
+
+/**
+ * midori_browser_append_xbel_item:
+ * @browser: a #MidoriBrowser
+ * @xbel_item: a bookmark
+ *
+ * Appends a #KatzeXbelItem in the form of a new tab.
+ *
+ * Return value: the index of the new tab, or -1 in case of an error
+ **/
+gint
+midori_browser_append_xbel_item (MidoriBrowser* browser,
+                                 KatzeXbelItem* xbel_item)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    g_return_val_if_fail (katze_xbel_item_is_bookmark (xbel_item), -1);
+
+    const gchar* uri = katze_xbel_bookmark_get_href (xbel_item);
+    const gchar* title = katze_xbel_item_get_title (xbel_item);
+    GtkWidget* web_view = g_object_new (MIDORI_TYPE_WEB_VIEW,
+                                        "uri", uri,
+                                        "title", title,
+                                        "settings", priv->settings,
+                                        NULL);
+    gtk_widget_show (web_view);
+
+    return midori_browser_append_tab (browser, web_view);
+}
+
+/**
+ * midori_browser_append_uri:
+ *
+ * Appends an uri in the form of a new tab.
+ *
+ * Return value: the index of the new tab, or -1
+ **/
+gint
+midori_browser_append_uri (MidoriBrowser* browser,
+                           const gchar*   uri)
+{
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    GtkWidget* web_view = g_object_new (MIDORI_TYPE_WEB_VIEW,
+                                        "uri", uri,
+                                        "settings", priv->settings,
+                                        NULL);
+    gtk_widget_show (web_view);
+
+    return midori_browser_append_tab (browser, web_view);
+}
+
+/**
+ * midori_browser_get_current_page:
+ * @browser: a #MidoriBrowser
+ *
+ * Determines the currently selected page.
+ *
+ * If there is no page present at all, %NULL is returned.
+ *
+ * Return value: the selected page, or %NULL
+ **/
+GtkWidget*
+midori_browser_get_current_page (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;
+}
+
+/**
+ * midori_browser_get_current_web_view:
+ * @browser: a #MidoriBrowser
+ *
+ * Determines the currently selected web view.
+ *
+ * If there is no web view selected or if there is no tab present
+ * at all, %NULL is returned.
+ *
+ * See also midori_browser_get_current_page
+ *
+ * Return value: the selected web view, or %NULL
+ **/
+GtkWidget*
+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);
+    return MIDORI_IS_WEB_VIEW (web_view) ? web_view : NULL;
+}
+
+/**
+ * midori_browser_get_proxy_xbel_folder:
+ * @browser: a #MidoriBrowser
+ *
+ * Retrieves a proxy xbel folder representing the respective proxy xbel items
+ * of the present web views that can be used for session management.
+ *
+ * The folder is created on the first call and will be updated to reflect
+ * changes to all items automatically.
+ *
+ * Note that this implicitly creates proxy xbel items of all web views.
+ *
+ * Return value: the proxy #KatzeXbelItem
+ **/
+KatzeXbelItem*
+midori_browser_get_proxy_xbel_folder (MidoriBrowser* browser)
+{
+    g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL);
+
+    MidoriBrowserPrivate* priv = browser->priv;
+
+    if (!priv->proxy_xbel_folder)
+    {
+        priv->proxy_xbel_folder = katze_xbel_folder_new ();
+        // FIXME: Fill in xbel items of all present web views
+    }
+    return priv->proxy_xbel_folder;
+}
diff --git a/src/midori-browser.h b/src/midori-browser.h
new file mode 100644 (file)
index 0000000..1853563
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
+
+ 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_BROWSER_H__
+#define __MIDORI_BROWSER_H__
+
+#include <webkit/webkit.h>
+
+#include <katze/katze.h>
+
+G_BEGIN_DECLS
+
+#define MIDORI_TYPE_BROWSER \
+    (midori_browser_get_type ())
+#define MIDORI_BROWSER(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_BROWSER, MidoriBrowser))
+#define MIDORI_BROWSER_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_BROWSER, MidoriBrowserClass))
+#define MIDORI_IS_BROWSER(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_BROWSER))
+#define MIDORI_IS_BROWSER_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_BROWSER))
+#define MIDORI_BROWSER_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_BROWSER, MidoriBrowserClass))
+
+typedef struct _MidoriBrowser                MidoriBrowser;
+typedef struct _MidoriBrowserPrivate         MidoriBrowserPrivate;
+typedef struct _MidoriBrowserClass           MidoriBrowserClass;
+
+struct _MidoriBrowser
+{
+    GtkWindow parent_instance;
+
+    MidoriBrowserPrivate* priv;
+};
+
+struct _MidoriBrowserClass
+{
+    GtkWindowClass parent_class;
+
+    /* Signals */
+    void
+    (*quit)                    (MidoriBrowser*       browser);
+    void
+    (*new_window)              (MidoriBrowser*       browser,
+                                const gchar*         uri);
+};
+
+GType
+midori_browser_get_type               (void);
+
+GtkWidget*
+midori_browser_new                    (void);
+
+gint
+midori_browser_append_tab             (MidoriBrowser*     browser,
+                                       GtkWidget*         widget);
+
+void
+midori_browser_remove_tab             (MidoriBrowser*     browser,
+                                       GtkWidget*         widget);
+
+gint
+midori_browser_append_xbel_item       (MidoriBrowser*     browser,
+                                       KatzeXbelItem*     xbel_item);
+
+gint
+midori_browser_append_uri             (MidoriBrowser*     browser,
+                                       const gchar*       uri);
+
+GtkWidget*
+midori_browser_get_current_page       (MidoriBrowser*     browser);
+
+GtkWidget*
+midori_browser_get_current_web_view   (MidoriBrowser*     browser);
+
+KatzeXbelItem*
+midori_browser_get_proxy_xbel_folder  (MidoriBrowser*     browser);
+
+G_END_DECLS
+
+#endif /* __MIDORI_BROWSER_H__ */
diff --git a/src/midori-panel.c b/src/midori-panel.c
new file mode 100644 (file)
index 0000000..4ff4277
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
+
+ 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 "midori-panel.h"
+
+#include "sokoke.h"
+
+G_DEFINE_TYPE (MidoriPanel, midori_panel, GTK_TYPE_HBOX)
+
+struct _MidoriPanelPrivate
+{
+    GtkWidget* toolbar;
+    GtkWidget* toolbar_label;
+    GtkWidget* frame;
+    GtkWidget* notebook;
+    GSList*    group;
+    GtkMenu*   menu;
+};
+
+#define MIDORI_PANEL_GET_PRIVATE(obj) \
+    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+     MIDORI_TYPE_PANEL, MidoriPanelPrivate))
+
+enum
+{
+    PROP_0,
+
+    PROP_SHADOW_TYPE,
+    PROP_MENU,
+    PROP_PAGE
+};
+
+enum {
+    CLOSE,
+    SWITCH_PAGE,
+
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+midori_panel_finalize (GObject* object);
+
+static void
+midori_panel_set_property (GObject* object,
+                           guint prop_id,
+                           const GValue* value,
+                           GParamSpec* pspec);
+
+static void
+midori_panel_get_property (GObject* object,
+                           guint prop_id,
+                           GValue* value,
+                           GParamSpec* pspec);
+
+static gboolean
+midori_panel_close_cb (MidoriPanel* panel)
+{
+    gtk_widget_hide (GTK_WIDGET (panel));
+    return FALSE;
+}
+
+static void
+midori_cclosure_marshal_BOOLEAN__VOID (GClosure* closure, GValue* return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data)
+{
+    typedef gboolean(*GMarshalFunc_BOOLEAN__VOID) (gpointer  data1,
+                                                 gpointer  data2);
+    register GMarshalFunc_BOOLEAN__VOID callback;
+    register GCClosure* cc = (GCClosure*) closure;
+    register gpointer data1, data2;
+    gboolean v_return;
+
+    g_return_if_fail(return_value != NULL);
+    g_return_if_fail(n_param_values == 1);
+
+    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_BOOLEAN__VOID) (marshal_data ? marshal_data : cc->callback);
+    v_return = callback(data1, data2);
+    g_value_set_boolean (return_value, v_return);
+}
+
+static void
+midori_panel_class_init (MidoriPanelClass* class)
+{
+
+    signals[CLOSE] = g_signal_new (
+        "close",
+        G_TYPE_FROM_CLASS (class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriPanelClass, close),
+        g_signal_accumulator_true_handled,
+        NULL,
+        midori_cclosure_marshal_BOOLEAN__VOID,
+        G_TYPE_BOOLEAN, 0);
+
+    signals[SWITCH_PAGE] = g_signal_new (
+        "switch-page",
+        G_TYPE_FROM_CLASS (class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriPanelClass, switch_page),
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__INT,
+        G_TYPE_NONE, 1,
+        G_TYPE_INT);
+
+    class->close = midori_panel_close_cb;
+
+    GObjectClass* gobject_class = G_OBJECT_CLASS (class);
+    gobject_class->finalize = midori_panel_finalize;
+    gobject_class->set_property = midori_panel_set_property;
+    gobject_class->get_property = midori_panel_get_property;
+
+    GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_SHADOW_TYPE,
+                                     g_param_spec_enum (
+                                     "shadow-type",
+                                     "Shadow Type",
+                                     "Appearance of the shadow around each panel",
+                                     GTK_TYPE_SHADOW_TYPE,
+                                     GTK_SHADOW_NONE,
+                                     flags));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_MENU,
+                                     g_param_spec_object (
+                                     "menu",
+                                     "Menu",
+                                     "Menu to hold panel items",
+                                     GTK_TYPE_MENU,
+                                     G_PARAM_READWRITE));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_PAGE,
+                                     g_param_spec_int (
+                                     "page",
+                                     "Page",
+                                     "The index of the current page",
+                                     -1, G_MAXINT, -1,
+                                     flags));
+
+    g_type_class_add_private (class, sizeof (MidoriPanelPrivate));
+}
+
+static void
+midori_panel_button_close_clicked_cb (MidoriPanel* panel)
+{
+    g_signal_emit (panel, signals[CLOSE], 0);
+}
+
+static void
+midori_panel_init (MidoriPanel* panel)
+{
+    panel->priv = MIDORI_PANEL_GET_PRIVATE (panel);
+
+    MidoriPanelPrivate* priv = panel->priv;
+
+    // Create the sidebar
+    priv->toolbar = gtk_toolbar_new ();
+    gtk_toolbar_set_style (GTK_TOOLBAR (priv->toolbar), GTK_TOOLBAR_BOTH);
+    gtk_toolbar_set_icon_size (GTK_TOOLBAR (priv->toolbar),
+                               GTK_ICON_SIZE_BUTTON);
+    gtk_toolbar_set_orientation (GTK_TOOLBAR (priv->toolbar),
+                                 GTK_ORIENTATION_VERTICAL);
+    gtk_box_pack_start (GTK_BOX (panel), priv->toolbar, FALSE, FALSE, 0);
+    gtk_widget_show_all (priv->toolbar);
+    GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
+    gtk_box_pack_start (GTK_BOX (panel), vbox, TRUE, TRUE, 0);
+
+    // Create the titlebar
+    GtkWidget* labelbar = gtk_toolbar_new ();
+    gtk_toolbar_set_icon_size (GTK_TOOLBAR (labelbar), GTK_ICON_SIZE_MENU);
+    gtk_toolbar_set_style (GTK_TOOLBAR (labelbar), GTK_TOOLBAR_ICONS);
+    GtkToolItem* toolitem = gtk_tool_item_new ();
+    gtk_tool_item_set_expand (toolitem, TRUE);
+    priv->toolbar_label = gtk_label_new (NULL);
+    gtk_misc_set_alignment (GTK_MISC (priv->toolbar_label), 0, 0.5);
+    gtk_container_add (GTK_CONTAINER (toolitem), priv->toolbar_label);
+    gtk_container_set_border_width (GTK_CONTAINER (toolitem), 6);
+    gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
+    toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_CLOSE);
+    gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), "Close panel");
+    sokoke_tool_item_set_tooltip_text (GTK_TOOL_ITEM (toolitem), "Close panel");
+    g_signal_connect (toolitem, "clicked",
+        G_CALLBACK (midori_panel_button_close_clicked_cb), panel);
+    gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
+    gtk_box_pack_start (GTK_BOX (vbox), labelbar, FALSE, FALSE, 0);
+    gtk_widget_show_all (vbox);
+
+    // Create the notebook
+    priv->notebook = gtk_notebook_new ();
+    gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->notebook), FALSE);
+    gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE);
+    priv->frame = gtk_frame_new (NULL);
+    gtk_container_add (GTK_CONTAINER (priv->frame), priv->notebook);
+    gtk_box_pack_start (GTK_BOX (vbox), priv->frame, TRUE, TRUE, 0);
+    gtk_widget_show_all (priv->frame);
+}
+
+static void
+midori_panel_finalize (GObject* object)
+{
+    MidoriPanel* panel = MIDORI_PANEL (object);
+    MidoriPanelPrivate* priv = panel->priv;
+
+    if (priv->menu)
+    {
+        // FIXME: Remove all menu items
+    }
+
+    G_OBJECT_CLASS (midori_panel_parent_class)->finalize (object);
+}
+
+static void
+midori_panel_set_property (GObject*      object,
+                           guint         prop_id,
+                           const GValue* value,
+                           GParamSpec*   pspec)
+{
+    MidoriPanel* panel = MIDORI_PANEL (object);
+    MidoriPanelPrivate* priv = panel->priv;
+
+    switch (prop_id)
+    {
+    case PROP_SHADOW_TYPE:
+        gtk_frame_set_shadow_type (GTK_FRAME (priv->frame),
+                                   g_value_get_enum (value));
+        break;
+    case PROP_MENU:
+        katze_object_assign (priv->menu, g_value_get_object (value));
+        // FIXME: Move existing items to the new menu
+        break;
+    case PROP_PAGE:
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook),
+                                       g_value_get_int (value));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+midori_panel_get_property (GObject*    object,
+                           guint       prop_id,
+                           GValue*     value,
+                           GParamSpec* pspec)
+{
+    MidoriPanel* panel = MIDORI_PANEL (object);
+    MidoriPanelPrivate* priv = panel->priv;
+
+    switch (prop_id)
+    {
+    case PROP_SHADOW_TYPE:
+        g_value_set_enum (value,
+            gtk_frame_get_shadow_type (GTK_FRAME (priv->frame)));
+        break;
+    case PROP_MENU:
+        g_value_set_object (value, priv->menu);
+        break;
+    case PROP_PAGE:
+        g_value_set_int (value,
+            gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+/**
+ * midori_panel_new:
+ *
+ * Creates a new empty panel.
+ *
+ * Return value: a new #MidoriPanel
+ **/
+GtkWidget*
+midori_panel_new (void)
+{
+    MidoriPanel* panel = g_object_new (MIDORI_TYPE_PANEL,
+                                       NULL);
+
+    return GTK_WIDGET (panel);
+}
+
+static void
+midori_panel_menu_item_activate_cb (GtkWidget*   widget,
+                                    MidoriPanel* panel)
+{
+    GtkWidget* child = g_object_get_data (G_OBJECT (widget), "page");
+    guint n = midori_panel_page_num (panel, child);
+    midori_panel_set_current_page (panel, n);
+    g_signal_emit (panel, signals[SWITCH_PAGE], 0, n);
+}
+
+/**
+ * midori_panel_append_page:
+ * @panel: a #MidoriPanel
+ * @child: the child widget
+ * @icon: a stock ID or icon name, or %NULL
+ * @label: a string to use as the label, or %NULL
+ *
+ * Appends a new page to the panel.
+ *
+ * If @icon is an icon name, the according image is used as an
+ * icon for this page.
+ *
+ * If @label is given, it is used as the label of this page.
+ *
+ * In the case of an error, -1 is returned.
+ *
+ * Return value: the index of the new page, or -1
+ **/
+gint
+midori_panel_append_page (MidoriPanel* panel,
+                          GtkWidget*   child,
+                          const gchar* icon,
+                          const gchar* label)
+{
+    g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
+    g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
+
+    MidoriPanelPrivate* priv = panel->priv;
+
+    GtkWidget* scrolled = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                    GTK_POLICY_AUTOMATIC,
+                                    GTK_POLICY_AUTOMATIC);
+    GTK_WIDGET_SET_FLAGS (scrolled, GTK_CAN_FOCUS);
+    gtk_widget_show (scrolled);
+    GtkWidget* widget;
+    GObjectClass* gobject_class = G_OBJECT_GET_CLASS (child);
+    if (GTK_WIDGET_CLASS (gobject_class)->set_scroll_adjustments_signal)
+        widget = child;
+    else
+    {
+        widget = gtk_viewport_new (NULL, NULL);
+        gtk_widget_show (widget);
+        gtk_container_add (GTK_CONTAINER (widget), child);
+    }
+    gtk_container_add (GTK_CONTAINER (scrolled), widget);
+    gtk_container_add (GTK_CONTAINER (priv->notebook), scrolled);
+
+    guint n = midori_panel_page_num (panel, child);
+
+    const gchar* text = label ? label : "Untitled";
+
+    GtkWidget* image;
+    GtkToolItem* toolitem = gtk_radio_tool_button_new (priv->group);
+    priv->group = gtk_radio_tool_button_get_group (GTK_RADIO_TOOL_BUTTON (
+                                                   toolitem));
+    gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), text);
+    if (icon)
+    {
+        image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_BUTTON);
+        gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image);
+    }
+    g_object_set_data (G_OBJECT (toolitem), "page", child);
+    g_signal_connect (toolitem, "clicked",
+                      G_CALLBACK (midori_panel_menu_item_activate_cb), panel);
+    gtk_widget_show_all (GTK_WIDGET (toolitem));
+    gtk_toolbar_insert (GTK_TOOLBAR (priv->toolbar), toolitem, -1);
+
+    if (priv->menu)
+    {
+        GtkWidget* menuitem = gtk_image_menu_item_new_with_label (text);
+        if (icon)
+        {
+            image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU);
+            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem),
+                                           image);
+        }
+        gtk_widget_show_all (menuitem);
+        g_object_set_data (G_OBJECT (menuitem), "page", child);
+        g_signal_connect (menuitem, "activate",
+                          G_CALLBACK (midori_panel_menu_item_activate_cb),
+                          panel);
+        gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menuitem);
+    }
+
+    return n;
+}
+
+/**
+ * midori_panel_get_current_page:
+ * @panel: a #MidoriPanel
+ *
+ * Retrieves the index of the currently selected page.
+ *
+ * If @panel has no children, -1 is returned.
+ *
+ * Return value: the index of the current page, or -1
+ **/
+gint
+midori_panel_get_current_page (MidoriPanel* panel)
+{
+    g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
+
+    MidoriPanelPrivate* priv = panel->priv;
+
+    return gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+}
+
+/**
+ * midori_panel_get_nth_page:
+ * @panel: a #MidoriPanel
+ *
+ * Retrieves the child widget of the nth page.
+ *
+ * If @panel has no children, -1 is returned.
+ *
+ * Return value: the child widget of the new page, or -1
+ **/
+GtkWidget*
+midori_panel_get_nth_page (MidoriPanel* panel,
+                           guint        page_num)
+{
+    g_return_val_if_fail (MIDORI_IS_PANEL (panel), NULL);
+
+    MidoriPanelPrivate* priv = panel->priv;
+
+    return gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), page_num);
+}
+
+/**
+ * midori_panel_get_n_pages:
+ * @panel: a #MidoriPanel
+ *
+ * Retrieves the number of pages contained in the panel.
+ *
+ * Return value: the number of pages
+ **/
+guint
+midori_panel_get_n_pages (MidoriPanel* panel)
+{
+    g_return_val_if_fail (MIDORI_IS_PANEL (panel), 0);
+
+    MidoriPanelPrivate* priv = panel->priv;
+
+    return gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+}
+
+static GtkWidget*
+_midori_panel_scrolled_for_child (MidoriPanel* panel,
+                                  GtkWidget*   child)
+{
+    GtkWidget* scrolled = gtk_widget_get_parent (GTK_WIDGET (child));
+    if (GTK_IS_VIEWPORT (scrolled))
+        scrolled = gtk_widget_get_parent (scrolled);
+    return scrolled;
+}
+
+/**
+ * midori_panel_page_num:
+ * @panel: a #MidoriPanel
+ *
+ * Retrieves the index of the page associated to @widget.
+ *
+ * If @panel has no children, -1 is returned.
+ *
+ * Return value: the index of page associated to @widget, or -1
+ **/
+gint
+midori_panel_page_num (MidoriPanel* panel,
+                       GtkWidget*   child)
+{
+    g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
+
+    MidoriPanelPrivate* priv = panel->priv;
+
+    GtkWidget* scrolled = _midori_panel_scrolled_for_child (panel, child);
+    return gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), scrolled);
+}
+
+/**
+ * midori_panel_set_current_page:
+ * @panel: a #MidoriPanel
+ * @n: index of the page to switch to, or -1 to mean the last page
+ *
+ * Switches to the page with the given index.
+ *
+ * The child must be visible, otherwise the underlying GtkNotebook will
+ * silently ignore the attempt to switch the page.
+ **/
+void
+midori_panel_set_current_page (MidoriPanel* panel,
+                               gint         n)
+{
+    g_return_if_fail (MIDORI_IS_PANEL (panel));
+
+    MidoriPanelPrivate* priv = panel->priv;
+
+    gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n);
+}
diff --git a/src/midori-panel.h b/src/midori-panel.h
new file mode 100644 (file)
index 0000000..c477203
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
+
+ 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_PANEL_H__
+#define __MIDORI_PANEL_H__
+
+#include <gtk/gtk.h>
+
+#include <katze/katze.h>
+
+G_BEGIN_DECLS
+
+#define MIDORI_TYPE_PANEL \
+    (midori_panel_get_type ())
+#define MIDORI_PANEL(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_PANEL, MidoriPanel))
+#define MIDORI_PANEL_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_PANEL, MidoriPanelClass))
+#define MIDORI_IS_PANEL(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_PANEL))
+#define MIDORI_IS_PANEL_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_PANEL))
+#define MIDORI_PANEL_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_PANEL, MidoriPanelClass))
+
+typedef struct _MidoriPanel                MidoriPanel;
+typedef struct _MidoriPanelPrivate         MidoriPanelPrivate;
+typedef struct _MidoriPanelClass           MidoriPanelClass;
+
+struct _MidoriPanel
+{
+    GtkFrame parent_instance;
+
+    MidoriPanelPrivate* priv;
+};
+
+struct _MidoriPanelClass
+{
+    GtkFrameClass parent_class;
+
+    /* Signals */
+    gboolean
+    (*close)                  (MidoriPanel*          panel);
+
+    void
+    (*switch_page)            (MidoriPanel*          panel,
+                               gint                  page);
+};
+
+GType
+midori_panel_get_type               (void);
+
+GtkWidget*
+midori_panel_new                    (void);
+
+gint
+midori_panel_append_page            (MidoriPanel*       panel,
+                                     GtkWidget*         child,
+                                     const gchar*       icon,
+                                     const gchar*       label);
+
+gint
+midori_panel_get_current_page       (MidoriPanel*       panel);
+
+GtkWidget*
+midori_panel_get_nth_page           (MidoriPanel*       panel,
+                                     guint              page_num);
+
+guint
+midori_panel_get_n_pages            (MidoriPanel*       panel);
+
+gint
+midori_panel_page_num               (MidoriPanel*       panel,
+                                     GtkWidget*         child);
+
+void
+midori_panel_set_current_page       (MidoriPanel*       panel,
+                                     gint               n);
+
+G_END_DECLS
+
+#endif /* __MIDORI_PANEL_H__ */
diff --git a/src/midori-trash.c b/src/midori-trash.c
new file mode 100644 (file)
index 0000000..d3f8f6a
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
+
+ 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 "midori-trash.h"
+
+#include "sokoke.h"
+
+G_DEFINE_TYPE (MidoriTrash, midori_trash, G_TYPE_OBJECT)
+
+struct _MidoriTrashPrivate
+{
+    guint limit;
+    KatzeXbelItem* xbel_folder;
+};
+
+#define MIDORI_TRASH_GET_PRIVATE(obj) \
+    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+     MIDORI_TYPE_TRASH, MidoriTrashPrivate))
+
+enum
+{
+    PROP_0,
+
+    PROP_LIMIT
+};
+
+enum {
+    INSERTED,
+    REMOVED,
+
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+midori_trash_finalize (GObject* object);
+
+static void
+midori_trash_set_property (GObject* object,
+                           guint prop_id,
+                           const GValue* value,
+                           GParamSpec* pspec);
+
+static void
+midori_trash_get_property (GObject* object,
+                           guint prop_id,
+                           GValue* value,
+                           GParamSpec* pspec);
+
+static void
+midori_trash_class_init (MidoriTrashClass* class)
+{
+    signals[INSERTED] = g_signal_new(
+        "inserted",
+        G_TYPE_FROM_CLASS(class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriTrashClass, inserted),
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__UINT,
+        G_TYPE_NONE, 1,
+        G_TYPE_UINT);
+
+    signals[REMOVED] = g_signal_new(
+        "removed",
+        G_TYPE_FROM_CLASS(class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriTrashClass, removed),
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__UINT,
+        G_TYPE_NONE, 1,
+        G_TYPE_UINT);
+
+    GObjectClass* gobject_class = G_OBJECT_CLASS (class);
+    gobject_class->finalize = midori_trash_finalize;
+    gobject_class->set_property = midori_trash_set_property;
+    gobject_class->get_property = midori_trash_get_property;
+
+    GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_LIMIT,
+                                     g_param_spec_uint (
+                                     "limit",
+                                     "Limit",
+                                     "The maximum number of items",
+                                     0, G_MAXUINT, 10,
+                                     flags));
+
+    g_type_class_add_private (class, sizeof (MidoriTrashPrivate));
+}
+
+
+
+static void
+midori_trash_init (MidoriTrash* trash)
+{
+    trash->priv = MIDORI_TRASH_GET_PRIVATE (trash);
+
+    MidoriTrashPrivate* priv = trash->priv;
+
+    priv->xbel_folder = katze_xbel_folder_new ();
+}
+
+static void
+midori_trash_finalize (GObject* object)
+{
+    MidoriTrash* trash = MIDORI_TRASH (object);
+    MidoriTrashPrivate* priv = trash->priv;
+
+    katze_xbel_item_unref (priv->xbel_folder);
+
+    G_OBJECT_CLASS (midori_trash_parent_class)->finalize (object);
+}
+
+static void
+midori_trash_set_property (GObject*      object,
+                           guint         prop_id,
+                           const GValue* value,
+                           GParamSpec*   pspec)
+{
+    MidoriTrash* trash = MIDORI_TRASH (object);
+    MidoriTrashPrivate* priv = trash->priv;
+
+    switch (prop_id)
+    {
+    case PROP_LIMIT:
+        priv->limit = g_value_get_uint (value);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+midori_trash_get_property (GObject*    object,
+                           guint       prop_id,
+                           GValue*     value,
+                           GParamSpec* pspec)
+{
+    MidoriTrash* trash = MIDORI_TRASH (object);
+    MidoriTrashPrivate* priv = trash->priv;
+
+    switch (prop_id)
+    {
+    case PROP_LIMIT:
+        g_value_set_uint (value, priv->limit);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+/**
+ * midori_trash_new:
+ * @limit: the maximum number of items
+ *
+ * Creates a new #MidoriTrash that can contain a specified number of items,
+ * meaning that each additional item will replace the oldest existing item.
+ *
+ * The value 0 for @limit actually means that there is no limit.
+ *
+ * You will typically want to assign this to a #MidoriBrowser.
+ *
+ * Return value: a new #MidoriTrash
+ **/
+MidoriTrash*
+midori_trash_new (guint limit)
+{
+    MidoriTrash* trash = g_object_new (MIDORI_TYPE_TRASH,
+                                       "limit", limit,
+                                       NULL);
+
+    return trash;
+}
+
+/**
+ * midori_trash_is_empty:
+ * @trash: a #MidoriTrash
+ *
+ * Determines whether the @trash contains no items.
+ *
+ * Return value: %TRUE if there are no items, %FALSE otherwise
+ **/
+gboolean
+midori_trash_is_empty (MidoriTrash* trash)
+{
+    g_return_val_if_fail (MIDORI_IS_TRASH (trash), FALSE);
+
+    MidoriTrashPrivate* priv = trash->priv;
+
+    return katze_xbel_folder_is_empty (priv->xbel_folder);
+}
+
+/**
+ * midori_trash_get_n_items:
+ * @trash: a #MidoriTrash
+ *
+ * Determines the number of items in @trash.
+ *
+ * Return value: the current number of items
+ **/
+guint
+midori_trash_get_n_items (MidoriTrash* trash)
+{
+    g_return_val_if_fail (MIDORI_IS_TRASH (trash), 0);
+
+    MidoriTrashPrivate* priv = trash->priv;
+
+    return katze_xbel_folder_get_n_items (priv->xbel_folder);
+}
+
+/**
+ * midori_trash_get_nth_xbel_item:
+ * @trash: a #MidoriTrash
+ * @n: the index of an item
+ *
+ * Retrieve an item contained in @trash by its index.
+ *
+ * Note that you mustn't unref this item.
+ *
+ * Return value: the index at the given index or %NULL
+ **/
+KatzeXbelItem*
+midori_trash_get_nth_xbel_item (MidoriTrash* trash,
+                                guint        n)
+{
+    g_return_val_if_fail (MIDORI_IS_TRASH (trash), 0);
+
+    MidoriTrashPrivate* priv = trash->priv;
+
+    return katze_xbel_folder_get_nth_item (priv->xbel_folder, n);
+}
+
+/**
+ * midori_trash_prepend_xbel_item:
+ * @trash: a #MidoriTrash
+ * @xbel_item: a #KatzeXbelItem
+ *
+ * Prepends a #KatzeXbelItem to @trash.
+ *
+ * The item is copied. If there is a limit set, the oldest item is
+ * removed automatically.
+ *
+ * Return value: %TRUE if there are no items, %FALSE otherwise
+ **/
+void
+midori_trash_prepend_xbel_item (MidoriTrash*   trash,
+                                KatzeXbelItem* xbel_item)
+{
+    g_return_if_fail (MIDORI_IS_TRASH (trash));
+
+    MidoriTrashPrivate* priv = trash->priv;
+
+    KatzeXbelItem* copy = katze_xbel_item_copy (xbel_item);
+    katze_xbel_folder_prepend_item (priv->xbel_folder, copy);
+    g_signal_emit (trash, signals[INSERTED], 0, 0);
+    guint n = katze_xbel_folder_get_n_items (priv->xbel_folder);
+    if (n > 10)
+    {
+        KatzeXbelItem* item = katze_xbel_folder_get_nth_item (priv->xbel_folder,
+                                                              n - 1);
+        g_signal_emit (trash, signals[REMOVED], 0, n - 1);
+        katze_xbel_item_unref (item);
+    }
+}
+
+/**
+ * midori_trash_remove_nth_item:
+ * @trash: a #MidoriTrash
+ * @n: the index of an item
+ *
+ * Removes the item at the specified position from @trash.
+ *
+ * Nothing happens if the function fails.
+ **/
+void
+midori_trash_remove_nth_item (MidoriTrash*   trash,
+                              guint          n)
+{
+    g_return_if_fail (MIDORI_IS_TRASH (trash));
+
+    MidoriTrashPrivate* priv = trash->priv;
+
+    KatzeXbelItem* item = katze_xbel_folder_get_nth_item (priv->xbel_folder, n);
+    if (!n)
+        return;
+    katze_xbel_folder_remove_item (priv->xbel_folder, item);
+    g_signal_emit (trash, signals[REMOVED], 0, n);
+    katze_xbel_item_unref (item);
+}
+
+/**
+ * midori_trash_empty:
+ * @trash: a #MidoriTrash
+ *
+ * Deletes all items currently contained in @trash.
+ **/
+void
+midori_trash_empty (MidoriTrash*   trash)
+{
+    g_return_if_fail (MIDORI_IS_TRASH (trash));
+
+    MidoriTrashPrivate* priv = trash->priv;
+
+    guint n = katze_xbel_folder_get_n_items (priv->xbel_folder);
+    guint i;
+    for (i = 0; i < n; i++)
+    {
+        KatzeXbelItem* item = katze_xbel_folder_get_nth_item (priv->xbel_folder,
+                                                              i);
+        g_signal_emit (trash, signals[REMOVED], 0, i);
+        katze_xbel_item_unref (item);
+    }
+}
diff --git a/src/midori-trash.h b/src/midori-trash.h
new file mode 100644 (file)
index 0000000..bc71179
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
+
+ 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_TRASH_H__
+#define __MIDORI_TRASH_H__
+
+#include <katze/katze.h>
+
+G_BEGIN_DECLS
+
+#define MIDORI_TYPE_TRASH \
+    (midori_trash_get_type ())
+#define MIDORI_TRASH(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_TRASH, MidoriTrash))
+#define MIDORI_TRASH_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_TRASH, MidoriTrashClass))
+#define MIDORI_IS_TRASH(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_TRASH))
+#define MIDORI_IS_TRASH_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_TRASH))
+#define MIDORI_TRASH_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_TRASH, MidoriTrashClass))
+
+typedef struct _MidoriTrash                MidoriTrash;
+typedef struct _MidoriTrashPrivate         MidoriTrashPrivate;
+typedef struct _MidoriTrashClass           MidoriTrashClass;
+
+struct _MidoriTrash
+{
+    GObject parent_instance;
+
+    MidoriTrashPrivate* priv;
+};
+
+struct _MidoriTrashClass
+{
+    GObjectClass parent_class;
+
+    /* Signals */
+    void
+    (*inserted)               (MidoriTrash* trash,
+                               guint        n);
+    void
+    (*removed)                (MidoriTrash* trash,
+                               guint        n);
+};
+
+GType
+midori_trash_get_type               (void);
+
+MidoriTrash*
+midori_trash_new                    (guint limit);
+
+gboolean
+midori_trash_is_empty               (MidoriTrash*   trash);
+
+guint
+midori_trash_get_n_items            (MidoriTrash* trash);
+
+KatzeXbelItem*
+midori_trash_get_nth_xbel_item      (MidoriTrash* trash,
+                                     guint        n);
+
+void
+midori_trash_prepend_xbel_item      (MidoriTrash*   trash,
+                                     KatzeXbelItem* xbel_item);
+
+void
+midori_trash_remove_nth_item        (MidoriTrash*   trash,
+                                     guint          n);
+
+void
+midori_trash_empty                  (MidoriTrash*   trash);
+
+G_END_DECLS
+
+#endif /* __MIDORI_TRASH_H__ */
diff --git a/src/midori-websettings.c b/src/midori-websettings.c
new file mode 100644 (file)
index 0000000..0fd34eb
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
+
+ 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 "midori-webview.h"
+
+#include "sokoke.h"
+
+G_DEFINE_TYPE (MidoriWebSettings, midori_web_settings, WEBKIT_TYPE_WEB_SETTINGS)
+
+struct _MidoriWebSettingsPrivate
+{
+    gint tab_label_size;
+    gboolean close_button;
+    gboolean middle_click_goto;
+};
+
+#define MIDORI_WEB_SETTINGS_GET_PRIVATE(obj) \
+    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+     MIDORI_TYPE_WEB_SETTINGS, MidoriWebSettingsPrivate))
+
+enum
+{
+    PROP_0,
+
+    PROP_TAB_LABEL_SIZE,
+    PROP_CLOSE_BUTTON,
+    PROP_MIDDLE_CLICK_GOTO
+};
+
+static void
+midori_web_settings_finalize (GObject* object);
+
+static void
+midori_web_settings_set_property (GObject* object,
+                                  guint prop_id,
+                                  const GValue* value,
+                                  GParamSpec* pspec);
+
+static void
+midori_web_settings_get_property (GObject* object,
+                                  guint prop_id,
+                                  GValue* value,
+                                  GParamSpec* pspec);
+
+static void
+midori_web_settings_class_init (MidoriWebSettingsClass* class)
+{
+    GObjectClass* gobject_class = G_OBJECT_CLASS (class);
+    gobject_class->finalize = midori_web_settings_finalize;
+    gobject_class->set_property = midori_web_settings_set_property;
+    gobject_class->get_property = midori_web_settings_get_property;
+
+    GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_TAB_LABEL_SIZE,
+                                     g_param_spec_int (
+                                     "tab-label-size",
+                                     "Tab Label Size",
+                                     "The desired tab label size",
+                                     0, G_MAXINT, 10,
+                                     flags));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_CLOSE_BUTTON,
+                                     g_param_spec_boolean (
+                                     "close-button",
+                                     "Close Button",
+                                     "Whether the associated tab has a close button",
+                                     FALSE,
+                                     flags));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_MIDDLE_CLICK_GOTO,
+                                     g_param_spec_boolean (
+                                     "middle-click-goto",
+                                     "Middle Click Goto",
+                                     "Load an uri from the selection via middle click",
+                                     FALSE,
+                                     flags));
+
+    g_type_class_add_private (class, sizeof (MidoriWebSettingsPrivate));
+}
+
+
+
+static void
+midori_web_settings_init (MidoriWebSettings* web_settings)
+{
+    web_settings->priv = MIDORI_WEB_SETTINGS_GET_PRIVATE (web_settings);
+}
+
+static void
+midori_web_settings_finalize (GObject* object)
+{
+    G_OBJECT_CLASS (midori_web_settings_parent_class)->finalize (object);
+}
+
+static void
+midori_web_settings_set_property (GObject*      object,
+                                  guint         prop_id,
+                                  const GValue* value,
+                                  GParamSpec*   pspec)
+{
+    MidoriWebSettings* web_settings = MIDORI_WEB_SETTINGS (object);
+    MidoriWebSettingsPrivate* priv = web_settings->priv;
+
+    switch (prop_id)
+    {
+    case PROP_TAB_LABEL_SIZE:
+        priv->tab_label_size = g_value_get_int (value);
+        break;
+    case PROP_CLOSE_BUTTON:
+        priv->close_button = g_value_get_boolean (value);
+        break;
+    case PROP_MIDDLE_CLICK_GOTO:
+        priv->middle_click_goto = g_value_get_boolean (value);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+midori_web_settings_get_property (GObject*    object,
+                                  guint       prop_id,
+                                  GValue*     value,
+                                  GParamSpec* pspec)
+{
+    MidoriWebSettings* web_settings = MIDORI_WEB_SETTINGS (object);
+    MidoriWebSettingsPrivate* priv = web_settings->priv;
+
+    switch (prop_id)
+    {
+    case PROP_TAB_LABEL_SIZE:
+        g_value_set_int (value, priv->tab_label_size);
+        break;
+    case PROP_CLOSE_BUTTON:
+        g_value_set_boolean (value, priv->close_button);
+        break;
+    case PROP_MIDDLE_CLICK_GOTO:
+        g_value_set_boolean (value, priv->middle_click_goto);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+/**
+ * midori_web_settings_new:
+ *
+ * Creates a new #MidoriWebSettings instance with default values.
+ *
+ * You will typically want to assign this to a #MidoriWebView or #MidoriBrowser.
+ *
+ * Return value: a new #MidoriWebSettings
+ **/
+MidoriWebSettings*
+midori_web_settings_new (void)
+{
+    MidoriWebSettings* web_settings = g_object_new (MIDORI_TYPE_WEB_SETTINGS,
+                                                    NULL);
+
+    return web_settings;
+}
+
+/**
+ * midori_web_settings_copy:
+ *
+ * Copies an existing #MidoriWebSettings instance.
+ *
+ * Return value: a new #MidoriWebSettings
+ **/
+MidoriWebSettings*
+midori_web_settings_copy (MidoriWebSettings* web_settings)
+{
+    g_return_val_if_fail (MIDORI_IS_WEB_SETTINGS (web_settings), NULL);
+
+    MidoriWebSettingsPrivate* priv = web_settings->priv;
+
+    MidoriWebSettings* copy;
+    copy = MIDORI_WEB_SETTINGS (webkit_web_settings_copy (WEBKIT_WEB_SETTINGS (web_settings)));
+    g_object_set (copy,
+                 "tab-label-size", priv->tab_label_size,
+                 "close-button", priv->close_button,
+                 "middle-click-goto", priv->middle_click_goto,
+                 NULL);
+
+    return copy;
+}
diff --git a/src/midori-websettings.h b/src/midori-websettings.h
new file mode 100644 (file)
index 0000000..8ea4020
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
+
+ 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_WEB_SETTINGS_H__
+#define __MIDORI_WEB_SETTINGS_H__
+
+#include <webkit/webkit.h>
+
+#include <katze/katze.h>
+
+G_BEGIN_DECLS
+
+#define MIDORI_TYPE_WEB_SETTINGS \
+    (midori_web_settings_get_type ())
+#define MIDORI_WEB_SETTINGS(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_WEB_SETTINGS, MidoriWebSettings))
+#define MIDORI_WEB_SETTINGS_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_WEB_SETTINGS, MidoriWebSettingsClass))
+#define MIDORI_IS_WEB_SETTINGS(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_WEB_SETTINGS))
+#define MIDORI_IS_WEB_SETTINGS_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_WEB_SETTINGS))
+#define MIDORI_WEB_SETTINGS_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_WEB_SETTINGS, MidoriWebSettingsClass))
+
+typedef struct _MidoriWebSettings                MidoriWebSettings;
+typedef struct _MidoriWebSettingsPrivate         MidoriWebSettingsPrivate;
+typedef struct _MidoriWebSettingsClass           MidoriWebSettingsClass;
+
+struct _MidoriWebSettings
+{
+    WebKitWebSettings parent_instance;
+
+    MidoriWebSettingsPrivate* priv;
+};
+
+struct _MidoriWebSettingsClass
+{
+    WebKitWebSettingsClass parent_class;
+
+    /* Signals */
+    void
+    (*progress_started)       (MidoriWebSettings*    web_settings,
+                               guint                 progress);
+    void
+    (*progress_changed)       (MidoriWebSettings*    web_settings,
+                               guint                 progress);
+    void
+    (*progress_done)          (MidoriWebSettings*    web_settings,
+                               guint                 progress);
+    void
+    (*load_done)              (MidoriWebSettings*    web_settings,
+                               WebKitWebFrame*       frame);
+    void
+    (*statusbar_text_changed) (MidoriWebSettings*    web_settings,
+                               const gchar*          text);
+    void
+    (*element_motion)         (MidoriWebSettings*    web_settings,
+                               const gchar*          link_uri);
+    void
+    (*close)                  (MidoriWebSettings*    web_settings);
+    void
+    (*new_tab)                (MidoriWebSettings*    web_settings,
+                               const gchar*          uri);
+    void
+    (*new_window)             (MidoriWebSettings*    web_settings,
+                               const gchar*          uri);
+};
+
+GType
+midori_web_settings_get_type               (void);
+
+MidoriWebSettings*
+midori_web_settings_new                    (void);
+
+MidoriWebSettings*
+midori_web_settings_copy                   (MidoriWebSettings* web_settings);
+
+G_END_DECLS
+
+#endif /* __MIDORI_WEB_SETTINGS_H__ */
diff --git a/src/midori-webview.c b/src/midori-webview.c
new file mode 100644 (file)
index 0000000..60f3349
--- /dev/null
@@ -0,0 +1,1039 @@
+/*
+ Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
+
+ 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 "midori-webview.h"
+
+#include "sokoke.h"
+
+#include <webkit/webkitwebframe.h>
+#include <string.h>
+
+G_DEFINE_TYPE (MidoriWebView, midori_web_view, WEBKIT_TYPE_WEB_VIEW)
+
+struct _MidoriWebViewPrivate
+{
+    GtkWidget* tab_icon;
+    GtkWidget* tab_label;
+    GtkWidget* tab_close;
+    GdkPixbuf* icon;
+    gchar* uri;
+    gchar* title;
+    gboolean is_loading;
+    gint progress;
+    gchar* statusbar_text;
+    gchar* link_uri;
+
+    gint tab_label_size;
+    gboolean close_button;
+    gboolean middle_click_goto;
+    MidoriWebSettings* settings;
+
+    GtkWidget* proxy_menu_item;
+    GtkWidget* proxy_tab_label;
+    KatzeXbelItem* proxy_xbel_item;
+};
+
+#define MIDORI_WEB_VIEW_GET_PRIVATE(obj) \
+    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+     MIDORI_TYPE_WEB_VIEW, MidoriWebViewPrivate))
+
+enum
+{
+    PROP_0,
+
+    PROP_ICON,
+    PROP_URI,
+    PROP_TITLE,
+    PROP_STATUSBAR_TEXT,
+    PROP_SETTINGS
+};
+
+enum {
+    LOAD_STARTED,
+    PROGRESS_STARTED,
+    PROGRESS_CHANGED,
+    PROGRESS_DONE,
+    LOAD_DONE,
+    ELEMENT_MOTION,
+    CLOSE,
+    NEW_TAB,
+    NEW_WINDOW,
+
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+midori_web_view_finalize (GObject* object);
+
+static void
+midori_web_view_set_property (GObject* object,
+                              guint prop_id,
+                              const GValue* value,
+                              GParamSpec* pspec);
+
+static void
+midori_web_view_get_property (GObject* object,
+                              guint prop_id,
+                              GValue* value,
+                              GParamSpec* pspec);
+
+/*static WebKitWebView*
+midori_web_view_create_web_view (WebKitWebView* web_view)
+{
+    MidoriWebView* new_web_view = NULL;
+    g_signal_emit (web_view, signals[NEW_WINDOW], 0, &new_web_view);
+    if (new_web_view)
+        return WEBKIT_WEB_VIEW (new_web_view);
+    return WEBKIT_WEB_VIEW (midori_web_view_new ());
+}*/
+
+static void
+midori_web_view_class_init (MidoriWebViewClass* class)
+{
+    signals[PROGRESS_STARTED] = g_signal_new (
+        "progress-started",
+        G_TYPE_FROM_CLASS(class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriWebViewClass, progress_started),
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__INT,
+        G_TYPE_NONE, 1,
+        G_TYPE_INT);
+
+    signals[PROGRESS_CHANGED] = g_signal_new (
+        "progress-changed",
+        G_TYPE_FROM_CLASS(class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriWebViewClass, progress_changed),
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__INT,
+        G_TYPE_NONE, 1,
+        G_TYPE_INT);
+
+    signals[PROGRESS_DONE] = g_signal_new (
+        "progress-done",
+        G_TYPE_FROM_CLASS(class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriWebViewClass, progress_done),
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__INT,
+        G_TYPE_NONE, 1,
+        G_TYPE_INT);
+
+    signals[LOAD_DONE] = g_signal_new (
+        "load-done",
+        G_TYPE_FROM_CLASS(class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriWebViewClass, load_done),
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__OBJECT,
+        G_TYPE_NONE, 1,
+        WEBKIT_TYPE_WEB_FRAME);
+
+    signals[ELEMENT_MOTION] = g_signal_new(
+        "element-motion",
+        G_TYPE_FROM_CLASS(class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriWebViewClass, element_motion),
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__STRING,
+        G_TYPE_NONE, 1,
+        G_TYPE_STRING);
+
+    signals[CLOSE] = g_signal_new(
+        "close",
+        G_TYPE_FROM_CLASS(class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriWebViewClass, close),
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__VOID,
+        G_TYPE_NONE, 0);
+
+    signals[NEW_TAB] = g_signal_new(
+        "new-tab",
+        G_TYPE_FROM_CLASS(class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriWebViewClass, new_tab),
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__VOID,
+        G_TYPE_NONE, 0);
+
+    signals[NEW_WINDOW] = g_signal_new(
+        "new-window",
+        G_TYPE_FROM_CLASS(class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        G_STRUCT_OFFSET (MidoriWebViewClass, new_window),
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__STRING,
+        G_TYPE_NONE, 1,
+        G_TYPE_STRING);
+
+    /*WEBKIT_WEB_VIEW_CLASS (class)->create_web_view = g_signal_new ("create-web-view",
+            G_TYPE_FROM_CLASS(class),
+            (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+            G_STRUCT_OFFSET(MidoriWebViewClass, create_web_view),
+            0,
+            NULL,
+            g_cclosure_marshal_VOID__OBJECT,
+            G_TYPE_NONE, 1,
+            MIDORI_TYPE_WEB_VIEW);*/
+
+    GObjectClass* gobject_class = G_OBJECT_CLASS (class);
+    gobject_class->finalize = midori_web_view_finalize;
+    gobject_class->set_property = midori_web_view_set_property;
+    gobject_class->get_property = midori_web_view_get_property;
+
+    GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_ICON,
+                                     g_param_spec_object (
+                                     "icon",
+                                     "Icon",
+                                     "The icon of the loaded page",
+                                     GDK_TYPE_PIXBUF,
+                                     G_PARAM_READWRITE));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_URI,
+                                     g_param_spec_string (
+                                     "uri",
+                                     "Uri",
+                                     "The current uri of the loaded page",
+                                     "about:blank",
+                                     flags));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_TITLE,
+                                     g_param_spec_string (
+                                     "title",
+                                     "Title",
+                                     "The current title of the loaded page",
+                                     NULL,
+                                     flags));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_STATUSBAR_TEXT,
+                                     g_param_spec_string (
+                                     "statusbar-text",
+                                     "Statusbar Text",
+                                     "The text that is displayed in the statusbar",
+                                     "",
+                                     flags));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_SETTINGS,
+                                     g_param_spec_object (
+                                     "settings",
+                                     "Settings",
+                                     "The associated settings",
+                                     MIDORI_TYPE_WEB_SETTINGS,
+                                     G_PARAM_READWRITE));
+
+    g_type_class_add_private (class, sizeof (MidoriWebViewPrivate));
+}
+
+/*static void
+webkit_web_view_load_started (MidoriWebView* web_view,
+                              WebKitWebFrame* web_frame)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    priv->is_loading = TRUE;
+    priv->progress = -1;
+    katze_throbber_set_animated(KATZE_THROBBER(priv->tab_icon), TRUE);
+}*/
+
+static void
+_midori_web_view_set_uri (MidoriWebView* web_view,
+                          const gchar*   uri)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    katze_assign (priv->uri, g_strdup (uri));
+    if (priv->proxy_xbel_item)
+    {
+        const gchar* uri = midori_web_view_get_display_uri (web_view);
+        katze_xbel_bookmark_set_href (priv->proxy_xbel_item, uri);
+    }
+    g_object_set (web_view, "title", NULL, NULL);
+}
+
+static void
+webkit_web_view_load_committed (MidoriWebView*  web_view,
+                                WebKitWebFrame* web_frame)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    priv->progress = 0;
+    const gchar* uri = webkit_web_frame_get_uri (web_frame);
+    _midori_web_view_set_uri (web_view, uri);
+}
+
+static void
+webkit_web_view_load_started (MidoriWebView*  web_view,
+                              WebKitWebFrame* web_frame)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    // FIXME: This is a hack, until signals are fixed upstream
+    priv->is_loading = TRUE;
+    if (priv->tab_icon)
+        katze_throbber_set_animated (KATZE_THROBBER (priv->tab_icon), TRUE);
+
+    priv->progress = 0;
+    g_signal_emit (web_view, signals[PROGRESS_STARTED], 0, priv->progress);
+}
+
+static void
+webkit_web_view_progress_changed (MidoriWebView* web_view, gint progress)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    priv->progress = progress;
+    g_signal_emit (web_view, signals[PROGRESS_CHANGED], 0, priv->progress);
+}
+
+static void
+webkit_web_view_load_finished (MidoriWebView* web_view)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    priv->progress = 100;
+    g_signal_emit (web_view, signals[PROGRESS_DONE], 0, priv->progress);
+}
+
+static void
+webkit_web_frame_load_done (WebKitWebFrame* web_frame, gboolean success,
+                            MidoriWebView*  web_view)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    priv->is_loading = FALSE;
+    priv->progress = -1;
+    if (priv->tab_icon)
+        katze_throbber_set_animated (KATZE_THROBBER (priv->tab_icon), FALSE);
+    g_signal_emit (web_view, signals[LOAD_DONE], 0, web_frame);
+}
+
+static void
+webkit_web_view_title_changed (MidoriWebView*  web_view,
+                               WebKitWebFrame* web_frame, const gchar* title)
+{
+    g_object_set (web_view, "title", title, NULL);
+}
+
+static void
+webkit_web_view_statusbar_text_changed (MidoriWebView*  web_view,
+                                        const gchar*    text)
+{
+    g_object_set (web_view, "statusbar-text", text, NULL);
+}
+
+static void
+webkit_web_view_hovering_over_link (MidoriWebView* web_view,
+                                    const gchar*   tooltip,
+                                    const gchar*   link_uri)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    katze_assign (priv->link_uri, g_strdup (link_uri));
+    g_signal_emit (web_view, signals[ELEMENT_MOTION], 0, link_uri);
+}
+
+static gboolean
+gtk_widget_button_press_event (MidoriWebView*  web_view,
+                               GdkEventButton* event)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    GdkModifierType state = (GdkModifierType)0;
+    gint x, y;
+    gdk_window_get_pointer (NULL, &x, &y, &state);
+    switch (event->button)
+    {
+    case 1:
+        if (!priv->link_uri)
+            return FALSE;
+        if (state & GDK_SHIFT_MASK)
+        {
+            // Open link in new window
+            g_signal_emit (web_view, signals[NEW_WINDOW], 0, priv->link_uri);
+            return TRUE;
+        }
+        else if(state & GDK_MOD1_MASK)
+        {
+            // Open link in new tab
+            g_signal_emit (web_view, signals[NEW_TAB], 0, priv->link_uri);
+            return TRUE;
+        }
+        break;
+    case 2:
+        if (state & GDK_CONTROL_MASK)
+        {
+            // FIXME: Reset font multiplier or zoom level
+            return TRUE;
+        }
+        else
+        {
+            if (!priv->link_uri)
+                return FALSE;
+            // Open link in new tab
+            g_signal_emit (web_view, signals[NEW_TAB], 0, priv->link_uri);
+            return TRUE;
+        }
+        break;
+    case 3:
+        return FALSE;
+    }
+    return FALSE;
+}
+
+static gboolean
+gtk_widget_button_press_event_after (MidoriWebView*  web_view,
+                                     GdkEventButton* event)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    if (event->button == 2 && priv->middle_click_goto)
+    {
+        GtkClipboard* clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
+        gchar* uri = gtk_clipboard_wait_for_text (clipboard);
+        if (uri && strchr (uri, '.') && !strchr (uri, ' '))
+        {
+            g_object_set (web_view, "uri", uri, NULL);
+            g_free (uri);
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+static gboolean
+gtk_widget_scroll_event (MidoriWebView*  web_view,
+                         GdkEventScroll* event)
+{
+    GdkModifierType state = (GdkModifierType)0;
+    gint x, y;
+    gdk_window_get_pointer (NULL, &x, &y, &state);
+    if (state & GDK_CONTROL_MASK)
+    {
+        // FIXME: Increase or decrease the font multiplier or zoom level
+        if (event->direction == GDK_SCROLL_DOWN)
+            ;
+        else if(event->direction == GDK_SCROLL_UP)
+            ;
+        return TRUE;
+    }
+    else
+        return FALSE;
+}
+
+static void
+midori_web_view_menu_new_tab_activate (GtkWidget*     action,
+                                       MidoriBrowser* browser)
+{
+    // FIXME: Open a new tab and load the uri
+}
+
+static void
+webkit_web_view_populate_popup_cb (GtkWidget*     web_view,
+                                   GtkWidget*     menu)
+{
+    const gchar* uri = midori_web_view_get_link_uri (MIDORI_WEB_VIEW (web_view));
+    if (uri)
+    {
+        // new tab
+    }
+
+    if (webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view)))
+    {
+        // selected uri in tab
+    }
+}
+
+static void
+_midori_web_view_update_tab_label_size (MidoriWebView* web_view)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    if (priv->tab_label)
+    {
+        if (priv->tab_label_size > -1)
+        {
+            gint width, height;
+            sokoke_widget_get_text_size (priv->tab_label, "M",
+                                         &width, &height);
+            gtk_widget_set_size_request (priv->tab_label,
+                                         width * priv->tab_label_size, -1);
+            gtk_label_set_ellipsize (GTK_LABEL (priv->tab_label),
+                                     PANGO_ELLIPSIZE_END);
+        }
+        else
+        {
+            gtk_widget_set_size_request (priv->tab_label, -1, -1);
+            gtk_label_set_ellipsize (GTK_LABEL (priv->tab_label),
+                                     PANGO_ELLIPSIZE_NONE);
+        }
+    }
+}
+
+static void
+_midori_web_view_update_settings (MidoriWebView* web_view)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    g_object_get (G_OBJECT (priv->settings),
+                  "tab-label-size", &priv->tab_label_size,
+                  "close-button", &priv->close_button,
+                  "middle-click-goto", &priv->middle_click_goto,
+                  NULL);
+}
+
+static void
+midori_web_view_settings_notify (MidoriWebSettings* web_settings,
+                                 GParamSpec*        pspec,
+                                 MidoriWebView*     web_view)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    const gchar* name = g_intern_string (pspec->name);
+    GValue value = {0, };
+    g_value_init (&value, pspec->value_type);
+    g_object_get_property (G_OBJECT (priv->settings), name, &value);
+
+    if (name == g_intern_string ("tab-label-size"))
+    {
+        priv->tab_label_size = g_value_get_int (&value);
+        _midori_web_view_update_tab_label_size (web_view);
+    }
+    else if (name == g_intern_string ("close-button"))
+    {
+        priv->close_button = g_value_get_boolean (&value);
+        if (priv->tab_close)
+            sokoke_widget_set_visible (priv->tab_close, priv->close_button);
+    }
+    else if (name == g_intern_string ("middle-click-goto"))
+        priv->middle_click_goto = g_value_get_boolean (&value);
+    else if (!g_object_class_find_property (G_OBJECT_GET_CLASS (web_settings),
+                                            name))
+        g_warning("Unexpected setting '%s'", name);
+    g_value_unset(&value);
+}
+
+static void
+midori_web_view_init (MidoriWebView* web_view)
+{
+    web_view->priv = MIDORI_WEB_VIEW_GET_PRIVATE (web_view);
+
+    MidoriWebViewPrivate* priv = web_view->priv;
+    priv->is_loading = FALSE;
+    priv->progress = -1;
+
+    priv->settings = midori_web_settings_new ();
+    _midori_web_view_update_settings (web_view);
+    g_signal_connect (priv->settings, "notify",
+                      G_CALLBACK(midori_web_view_settings_notify), web_view);
+
+    WebKitWebFrame* web_frame;
+    web_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+
+    g_object_connect (web_view,
+                      //"signal::load-started",
+                      //webkit_web_view_load_started, NULL,
+                      "signal::load-committed",
+                      webkit_web_view_load_committed, NULL,
+                      "signal::load-started",
+                      webkit_web_view_load_started, NULL,
+                      "signal::load-progress-changed",
+                      webkit_web_view_progress_changed, NULL,
+                      "signal::load-finished",
+                      webkit_web_view_load_finished, NULL,
+                      //"signal::load-done",
+                      //webkit_web_view_load_done, NULL,
+                      "signal::title-changed",
+                      webkit_web_view_title_changed, NULL,
+                      "signal::status-bar-text-changed",
+                      webkit_web_view_statusbar_text_changed, NULL,
+                      "signal::hovering-over-link",
+                      webkit_web_view_hovering_over_link, NULL,
+                      "signal::button-press-event",
+                      gtk_widget_button_press_event, NULL,
+                      "signal_after::button-press-event",
+                      gtk_widget_button_press_event_after, NULL,
+                      "signal::scroll-event",
+                      gtk_widget_scroll_event, NULL,
+                      "signal::populate-popup",
+                      webkit_web_view_populate_popup_cb, browser,
+                      NULL);
+    g_object_connect (web_frame,
+                      "signal::load-done",
+                      webkit_web_frame_load_done, web_view,
+                      NULL);
+}
+
+static void
+midori_web_view_finalize (GObject* object)
+{
+    MidoriWebView* web_view = MIDORI_WEB_VIEW (object);
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    if (priv->icon)
+        g_object_unref (priv->icon);
+    g_free (priv->uri);
+    g_free (priv->title);
+    g_free (priv->statusbar_text);
+    g_free (priv->link_uri);
+
+    if (priv->proxy_menu_item)
+        gtk_widget_destroy (priv->proxy_menu_item);
+    if (priv->proxy_xbel_item)
+        katze_xbel_item_unref (priv->proxy_xbel_item);
+
+    if (priv->settings)
+        g_object_unref (priv->settings);
+
+    G_OBJECT_CLASS (midori_web_view_parent_class)->finalize (object);
+}
+
+static void
+midori_web_view_set_property (GObject*      object,
+                              guint         prop_id,
+                              const GValue* value,
+                              GParamSpec*   pspec)
+{
+    MidoriWebView* web_view = MIDORI_WEB_VIEW (object);
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    switch (prop_id)
+    {
+    case PROP_ICON:
+        katze_object_assign (priv->icon, g_value_get_object (value));
+        g_object_ref (priv->icon);
+        if (priv->tab_icon)
+            katze_throbber_set_static_pixbuf (KATZE_THROBBER (priv->tab_icon),
+                                              priv->icon);
+        break;
+    case PROP_URI:
+        // FIXME: Autocomplete the uri
+        webkit_web_view_open (WEBKIT_WEB_VIEW (web_view),
+                              g_value_get_string (value));
+        break;
+    case PROP_TITLE:
+        katze_assign (priv->title, g_value_dup_string (value));
+        const gchar* title = midori_web_view_get_display_title (web_view);
+        if (priv->tab_label)
+        {
+            gtk_label_set_text (GTK_LABEL (priv->tab_label), title);
+            sokoke_widget_set_tooltip_text (priv->tab_label, title);
+        }
+        if (priv->proxy_menu_item)
+            gtk_label_set_text (GTK_LABEL (gtk_bin_get_child (GTK_BIN (
+                                priv->proxy_menu_item))), title);
+        if (priv->proxy_xbel_item)
+            katze_xbel_item_set_title (priv->proxy_xbel_item, title);
+        break;
+    case PROP_STATUSBAR_TEXT:
+        katze_assign (priv->statusbar_text, g_value_dup_string (value));
+        break;
+    case PROP_SETTINGS:
+        g_signal_handlers_disconnect_by_func (priv->settings,
+                                              midori_web_view_settings_notify,
+                                              web_view);
+        katze_object_assign (priv->settings, g_value_get_object (value));
+        g_object_ref (priv->settings);
+        _midori_web_view_update_settings (web_view);
+        g_signal_connect (priv->settings, "notify",
+                          G_CALLBACK (midori_web_view_settings_notify), web_view);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+midori_web_view_get_property (GObject*    object,
+                              guint       prop_id,
+                              GValue*     value,
+                              GParamSpec* pspec)
+{
+    MidoriWebView* web_view = MIDORI_WEB_VIEW (object);
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    switch (prop_id)
+    {
+    case PROP_ICON:
+        g_value_set_object (value, priv->icon);
+        break;
+    case PROP_URI:
+        g_value_set_string (value, priv->uri);
+        break;
+    case PROP_TITLE:
+        g_value_set_string (value, priv->title);
+        break;
+    case PROP_STATUSBAR_TEXT:
+        g_value_set_string (value, priv->statusbar_text);
+        break;
+    case PROP_SETTINGS:
+        g_value_set_object (value, priv->settings);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+/**
+ * midori_web_view_new:
+ *
+ * Creates a new web view widget.
+ *
+ * Return value: a new #MidoriWebView
+ **/
+GtkWidget*
+midori_web_view_new (void)
+{
+    MidoriWebView* web_view = g_object_new (MIDORI_TYPE_WEB_VIEW,
+                                            NULL);
+
+    return GTK_WIDGET (web_view);
+}
+
+/**
+ * midori_web_view_get_proxy_menu_item:
+ * @web_view: a #MidoriWebView
+ *
+ * Retrieves a proxy menu item that is typically added to a Window menu
+ * and which on activation switches to the right window/ tab.
+ *
+ * The item is created on the first call and will be updated to reflect
+ * changes to the icon and title automatically.
+ *
+ * Note: The item is only valid as the web view is embedded in a #GtkNotebook.
+ *
+ * Return value: the proxy #GtkMenuItem or %NULL
+ **/
+GtkWidget*
+midori_web_view_get_proxy_menu_item (MidoriWebView* web_view)
+{
+    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), FALSE);
+
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    if (!priv->proxy_menu_item)
+    {
+        const gchar* title = midori_web_view_get_display_title (web_view);
+        GtkWidget* menu_item = gtk_image_menu_item_new_with_label (title);
+        GtkWidget* icon = gtk_image_new_from_stock (GTK_STOCK_FILE,
+                                                    GTK_ICON_SIZE_MENU);
+        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), icon);
+
+        priv->proxy_menu_item = menu_item;
+    }
+    return priv->proxy_menu_item;
+}
+
+/**
+ * midori_web_view_get_proxy_tab_icon:
+ * @web_view: a #MidoriWebView
+ *
+ * Retrieves a proxy tab icon that is typically used in a tab label.
+ *
+ * The icon is created on the first call and will be updated to reflect
+ * loading progress and changes of the actual icon.
+ *
+ * Note: If a proxy tab label has been created before, this represents
+ * the existing icon used in the label.
+ *
+ * Return value: the proxy #GtkImage
+ **/
+GtkWidget*
+midori_web_view_get_proxy_tab_icon (MidoriWebView* web_view)
+{
+    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL);
+
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    if (!priv->tab_icon)
+    {
+        priv->tab_icon = katze_throbber_new ();
+        katze_throbber_set_pixbuf (KATZE_THROBBER(priv->tab_icon), priv->icon);
+    }
+    return priv->tab_icon;
+}
+
+static gboolean
+midori_web_view_tab_label_button_release_event (GtkWidget* tab_label,
+                                                GdkEventButton* event,
+                                                MidoriWebView* web_view)
+{
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
+    {
+        // Toggle the label visibility on double click
+        GtkWidget* child = gtk_bin_get_child (GTK_BIN (tab_label));
+        GList* children = gtk_container_get_children (GTK_CONTAINER (child));
+        child = (GtkWidget*)g_list_nth_data (children, 1);
+        gboolean visible = gtk_widget_get_child_visible (GTK_WIDGET (child));
+        gtk_widget_set_child_visible (GTK_WIDGET (child), !visible);
+        gint width, height;
+        sokoke_widget_get_text_size(tab_label, "M", &width, &height);
+        gtk_widget_set_size_request (child, !visible
+         ? width * priv->tab_label_size : 0, !visible ? -1 : 0);
+        g_list_free (children);
+        return TRUE;
+    }
+    else if (event->button == 2)
+    {
+        // Close the web view on middle click
+        g_signal_emit (web_view, signals[CLOSE], 0);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static void
+midori_web_view_tab_close_style_set (GtkWidget*     tab_close,
+                                     GtkStyle*      previous_style,
+                                     MidoriWebView* web_view)
+{
+    GtkSettings* gtk_settings = gtk_widget_get_settings (tab_close);
+    gint width, height;
+    gtk_icon_size_lookup_for_settings (gtk_settings, GTK_ICON_SIZE_BUTTON,
+                                       &width, &height);
+    gtk_widget_set_size_request (tab_close, width + 2, height + 2);
+}
+
+static void
+midori_web_view_tab_close_clicked (GtkWidget*     tab_close,
+                                   MidoriWebView* web_view)
+{
+    g_signal_emit (web_view, signals[CLOSE], 0);
+}
+
+/**
+ * midori_web_view_get_proxy_tab_label:
+ * @web_view: a #MidoriWebView
+ *
+ * Retrieves a proxy tab label that is typically used as the label of
+ * a #GtkNotebook page.
+ *
+ * The label is created on the first call and will be updated to reflect
+ * changes to the icon and title automatically.
+ *
+ * The icon embedded in the label will reflect the loading status of the
+ * web view.
+ *
+ * Note: This fails if a proxy tab icon has been created already.
+ *
+ * Return value: the proxy #GtkEventBox
+ **/
+GtkWidget*
+midori_web_view_get_proxy_tab_label (MidoriWebView* web_view)
+{
+    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL);
+
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    GtkWidget* proxy_tab_icon = priv->tab_icon;
+    g_return_val_if_fail (!proxy_tab_icon, NULL);
+
+    if (!priv->proxy_tab_label)
+    {
+        priv->tab_icon = katze_throbber_new ();
+        katze_throbber_set_pixbuf (KATZE_THROBBER(priv->tab_icon), priv->icon);
+
+        GtkWidget* event_box = gtk_event_box_new ();
+        gtk_event_box_set_visible_window(GTK_EVENT_BOX (event_box), FALSE);
+        GtkWidget* hbox = gtk_hbox_new (FALSE, 1);
+        gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (hbox));
+        gtk_box_pack_start (GTK_BOX (hbox), priv->tab_icon, FALSE, FALSE, 0);
+        const gchar* title = midori_web_view_get_display_title (web_view);
+        priv->tab_label = gtk_label_new (title);
+        gtk_misc_set_alignment (GTK_MISC (priv->tab_label), 0.0, 0.5);
+        // TODO: make the tab initially look "unvisited" until it's focused
+        gtk_box_pack_start (GTK_BOX (hbox), priv->tab_label, FALSE, FALSE, 0);
+        priv->proxy_tab_label = event_box;
+        _midori_web_view_update_tab_label_size (web_view);
+
+        GtkWidget* close_button = gtk_button_new ();
+        gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
+        gtk_button_set_focus_on_click (GTK_BUTTON (close_button), FALSE);
+        GtkRcStyle* rcstyle = gtk_rc_style_new ();
+        rcstyle->xthickness = rcstyle->ythickness = 0;
+        gtk_widget_modify_style(close_button, rcstyle);
+        GtkWidget* image = gtk_image_new_from_stock (GTK_STOCK_CLOSE,
+                                                     GTK_ICON_SIZE_MENU);
+        gtk_button_set_image (GTK_BUTTON(close_button), image);
+        gtk_box_pack_start (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
+        gtk_widget_show_all (GTK_WIDGET (event_box));
+        if (!priv->close_button)
+            gtk_widget_hide (close_button);
+        priv->tab_close = close_button;
+
+        g_signal_connect(priv->proxy_tab_label, "button-release-event",
+                         G_CALLBACK(midori_web_view_tab_label_button_release_event),
+                         web_view);
+        g_signal_connect(priv->tab_close, "style-set",
+                         G_CALLBACK(midori_web_view_tab_close_style_set),
+                         web_view);
+        g_signal_connect(priv->tab_close, "clicked",
+                         G_CALLBACK(midori_web_view_tab_close_clicked),
+                         web_view);
+    }
+    return priv->proxy_tab_label;
+}
+
+/**
+ * midori_web_view_get_proxy_xbel_item:
+ * @web_view: a #MidoriWebView
+ *
+ * Retrieves a proxy xbel item that can be used for bookmark storage as
+ * well as session management.
+ *
+ * The item is created on the first call and will be updated to reflect
+ * changes to the title and href automatically.
+ *
+ * Note: Currently the item is always a bookmark, but this might change
+ * in the future.
+ *
+ * Return value: the proxy #KatzeXbelItem
+ **/
+KatzeXbelItem*
+midori_web_view_get_proxy_xbel_item (MidoriWebView* web_view)
+{
+    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL);
+
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    if (!priv->proxy_xbel_item)
+    {
+        priv->proxy_xbel_item = katze_xbel_bookmark_new ();
+        const gchar* uri = midori_web_view_get_display_uri (web_view);
+        katze_xbel_bookmark_set_href (priv->proxy_xbel_item, uri);
+        const gchar* title = midori_web_view_get_display_title (web_view);
+        katze_xbel_item_set_title (priv->proxy_xbel_item, title);
+    }
+    return priv->proxy_xbel_item;
+}
+
+/**
+ * midori_web_view_is_loading:
+ * @web_view: a #MidoriWebView
+ *
+ * Determines whether currently a page is being loaded or not.
+ *
+ * Return value: %TRUE if a page is being loaded, %FALSE otherwise
+ **/
+gint
+midori_web_view_is_loading (MidoriWebView* web_view)
+{
+    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), -1);
+
+    MidoriWebViewPrivate* priv = web_view->priv;
+    return priv->is_loading;
+}
+
+/**
+ * midori_web_view_get_progress:
+ * @web_view: a #MidoriWebView
+ *
+ * Retrieves the current loading progress in percent or -1 if no data
+ * has been loaded so far.
+ *
+ * The value is undefined if no loading is in progress.
+ *
+ * Return value: the current loading progress or -1
+ **/
+gint
+midori_web_view_get_progress (MidoriWebView* web_view)
+{
+    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), -1);
+
+    MidoriWebViewPrivate* priv = web_view->priv;
+    return priv->progress;
+}
+
+/**
+ * midori_web_view_get_uri:
+ * @web_view: a #MidoriWebView
+ *
+ * Retrieves a string that is suitable for displaying, particularly an
+ * empty uri is represented as "about:blank".
+ *
+ * You can assume that the string is not %NULL.
+ *
+ * Return value: an uri string
+ **/
+const gchar*
+midori_web_view_get_display_uri (MidoriWebView* web_view)
+{
+    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), "about:blank");
+
+    MidoriWebViewPrivate* priv = web_view->priv;
+    return priv->uri ? priv->uri : "about:blank";
+}
+
+/**
+ * midori_web_view_get_display_title:
+ * @web_view: a #MidoriWebView
+ *
+ * Retrieves a string that is suitable for displaying as a title. Most of the
+ * time this will be the title or the current uri.
+ *
+ * You can assume that the string is not %NULL.
+ *
+ * Return value: a title string
+ **/
+const gchar*
+midori_web_view_get_display_title (MidoriWebView* web_view)
+{
+    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), "about:blank");
+
+    MidoriWebViewPrivate* priv = web_view->priv;
+
+    if (priv->title)
+        return priv->title;
+    if (priv->uri)
+        return priv->uri;
+    return "about:blank";
+}
+
+/**
+ * midori_web_view_get_link_uri:
+ * @web_view: a #MidoriWebView
+ *
+ * Retrieves the uri of the currently focused link, particularly while the
+ * mouse hovers a link or a context menu is being opened.
+ *
+ * Return value: an uri string, or %NULL if there is no link focussed
+ **/
+const gchar*
+midori_web_view_get_link_uri (MidoriWebView* web_view)
+{
+    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL);
+
+    MidoriWebViewPrivate* priv = web_view->priv;
+    return priv->link_uri;
+}
diff --git a/src/midori-webview.h b/src/midori-webview.h
new file mode 100644 (file)
index 0000000..5b50621
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
+
+ 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_WEB_VIEW_H__
+#define __MIDORI_WEB_VIEW_H__
+
+#include <webkit/webkit.h>
+
+#include <katze/katze.h>
+#include "midori-websettings.h"
+
+G_BEGIN_DECLS
+
+#define MIDORI_TYPE_WEB_VIEW \
+    (midori_web_view_get_type ())
+#define MIDORI_WEB_VIEW(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_WEB_VIEW, MidoriWebView))
+#define MIDORI_WEB_VIEW_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_WEB_VIEW, MidoriWebViewClass))
+#define MIDORI_IS_WEB_VIEW(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_WEB_VIEW))
+#define MIDORI_IS_WEB_VIEW_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_WEB_VIEW))
+#define MIDORI_WEB_VIEW_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_WEB_VIEW, MidoriWebViewClass))
+
+typedef struct _MidoriWebView                MidoriWebView;
+typedef struct _MidoriWebViewPrivate         MidoriWebViewPrivate;
+typedef struct _MidoriWebViewClass           MidoriWebViewClass;
+
+struct _MidoriWebView
+{
+    WebKitWebView parent_instance;
+
+    MidoriWebViewPrivate* priv;
+};
+
+struct _MidoriWebViewClass
+{
+    WebKitWebViewClass parent_class;
+
+    /* Signals */
+    void
+    (*progress_started)       (MidoriWebView*        web_view,
+                               guint                 progress);
+    void
+    (*progress_changed)       (MidoriWebView*        web_view,
+                               guint                 progress);
+    void
+    (*progress_done)          (MidoriWebView*        web_view,
+                               guint                 progress);
+    void
+    (*load_done)              (MidoriWebView*        web_view,
+                               WebKitWebFrame*       frame);
+    void
+    (*statusbar_text_changed) (MidoriWebView*        web_view,
+                               const gchar*          text);
+    void
+    (*element_motion)         (MidoriWebView*        web_view,
+                               const gchar*          link_uri);
+    void
+    (*close)                  (MidoriWebView*        web_view);
+    void
+    (*new_tab)                (MidoriWebView*        web_view,
+                               const gchar*          uri);
+    void
+    (*new_window)             (MidoriWebView*        web_view,
+                               const gchar*          uri);
+    void
+    (*create_web_view)        (MidoriWebView*        web_view,
+                               MidoriWebView*        new_web_view);
+};
+
+GType
+midori_web_view_get_type               (void);
+
+GtkWidget*
+midori_web_view_new                    (void);
+
+void
+midori_web_view_set_settings           (MidoriWebView*     web_view,
+                                        MidoriWebSettings* web_settings);
+
+GtkWidget*
+midori_web_view_get_proxy_menu_item    (MidoriWebView*     web_view);
+
+GtkWidget*
+midori_web_view_get_proxy_tab_label    (MidoriWebView*     web_view);
+
+KatzeXbelItem*
+midori_web_view_get_proxy_xbel_item    (MidoriWebView*     web_view);
+
+gboolean
+midori_web_view_is_loading             (MidoriWebView*     web_view);
+
+gint
+midori_web_view_get_progress           (MidoriWebView*     web_view);
+
+const gchar*
+midori_web_view_get_display_uri        (MidoriWebView*     web_view);
+
+const gchar*
+midori_web_view_get_display_title      (MidoriWebView*     web_view);
+
+const gchar*
+midori_web_view_get_link_uri           (MidoriWebView*     web_view);
+
+G_END_DECLS
+
+#endif /* __MIDORI_WEB_VIEW_H__ */
index d5bcc6d77588beaa62f873e3a54e31ad5ba3b333..e4cd08360f281b8106f054c1b9164451292cb4dd 100644 (file)
@@ -152,62 +152,45 @@ static void on_prefs_userStylesheetUri_file_set(GtkWidget* widget, CPrefs* prefs
 static void on_prefs_toolbarstyle_changed(GtkWidget* widget, CPrefs* prefs)
 {
     config->toolbarStyle = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
-    gtk_toolbar_set_style(GTK_TOOLBAR(prefs->browser->navibar)
-     , config_to_toolbarstyle(config->toolbarStyle));
+    /*gtk_toolbar_set_style(GTK_TOOLBAR(prefs->browser->navibar)
+     , config_to_toolbarstyle(config->toolbarStyle));*/
 }
 
 static void on_prefs_toolbarSmall_toggled(GtkWidget* widget, CPrefs* prefs)
 {
     config->toolbarSmall = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-    gtk_toolbar_set_icon_size(GTK_TOOLBAR(prefs->browser->navibar)
-     , config_to_toolbariconsize(config->toolbarSmall));
+    /*gtk_toolbar_set_icon_size(GTK_TOOLBAR(prefs->browser->navibar)
+     , config_to_toolbariconsize(config->toolbarSmall));*/
 }
 
 static void on_prefs_tabClose_toggled(GtkWidget* widget, CPrefs* prefs)
 {
     config->tabClose = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-    GList* items = browsers;
-    do
-    {
-        CBrowser* browser = (CBrowser*)items->data;
-        sokoke_widget_set_visible(browser->webView_close, config->tabClose);
-    }
-    while((items = g_list_next(items)));
-    g_list_free(items);
+    g_object_set(webSettings, "close-button", config->tabClose, NULL);
 }
 
 static void on_prefs_tabSize_changed(GtkWidget* widget, CPrefs* prefs)
 {
     config->tabSize = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
-    gint w, h;
-    sokoke_widget_get_text_size(prefs->browser->webView_name, "M", &w, &h);
-    GList* items = browsers;
-    do
-    {
-        CBrowser* browser = (CBrowser*)items->data;
-        gtk_widget_set_size_request(GTK_WIDGET(browser->webView_name)
-         , w * config->tabSize, -1);
-    }
-    while((items = g_list_next(items)));
-    g_list_free(items);
+    g_object_set(webSettings, "tab-label-size", config->tabSize, NULL);
 }
 
 static void on_prefs_toolbarWebSearch_toggled(GtkWidget* widget, CPrefs* prefs)
 {
     config->toolbarWebSearch = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-    sokoke_widget_set_visible(prefs->browser->webSearch, config->toolbarWebSearch);
+    //sokoke_widget_set_visible(prefs->browser->webSearch, config->toolbarWebSearch);
 }
 
 static void on_prefs_toolbarNewTab_toggled(GtkWidget* widget, CPrefs* prefs)
 {
     config->toolbarNewTab = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-    sokoke_widget_set_visible(prefs->browser->newTab, config->toolbarNewTab);
+    //sokoke_widget_set_visible(prefs->browser->newTab, config->toolbarNewTab);
 }
 
 static void on_prefs_toolbarClosedTabs_toggled(GtkWidget* widget, CPrefs* prefs)
 {
     config->toolbarClosedTabs = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-    sokoke_widget_set_visible(prefs->browser->closedTabs, config->toolbarClosedTabs);
+    //sokoke_widget_set_visible(prefs->browser->closedTabs, config->toolbarClosedTabs);
 }
 
 static gboolean on_prefs_locationsearch_focus_out(GtkWidget* widget
@@ -233,7 +216,10 @@ static void on_prefs_protocols_render_icon(GtkTreeViewColumn* column
         gchar* path;
         if((path = g_find_program_in_path(binary)))
         {
-            GtkIconTheme* icon_theme = get_icon_theme(prefs->treeview);
+            GdkScreen* screen = gtk_widget_get_screen(prefs->treeview);
+            if(!screen)
+                screen = gdk_screen_get_default();
+            GtkIconTheme* icon_theme = gtk_icon_theme_get_for_screen(screen);
             if(g_path_is_absolute(binary))
             {
                 g_free(path); path = g_path_get_basename(binary);
@@ -308,16 +294,14 @@ static void on_prefs_protocols_combobox_changed(GtkWidget* widget, CPrefs* prefs
     gtk_widget_set_sensitive(prefs->add, command == NULL);
 }
 
-GtkWidget* prefs_preferences_dialog_new(CBrowser* browser)
+GtkWidget* prefs_preferences_dialog_new(MidoriBrowser* browser)
 {
     gchar* dialogTitle = g_strdup_printf("%s Preferences", g_get_application_name());
     GtkWidget* dialog = gtk_dialog_new_with_buttons(dialogTitle
-        , GTK_WINDOW(browser->window)
+        , GTK_WINDOW(browser)
         , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR
-        , GTK_STOCK_HELP
-        , GTK_RESPONSE_HELP
-        , GTK_STOCK_CLOSE
-        , GTK_RESPONSE_CLOSE
+        , GTK_STOCK_HELP, GTK_RESPONSE_HELP
+        , GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE
         , NULL);
     gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_PREFERENCES);
     // TODO: Implement some kind of help function
@@ -326,7 +310,6 @@ GtkWidget* prefs_preferences_dialog_new(CBrowser* browser)
 
     CPrefs* prefs = g_new0(CPrefs, 1);
     prefs->browser = browser;
-    //prefs->window = dialog;
     g_signal_connect(dialog, "response", G_CALLBACK(g_free), prefs);
 
     // TODO: Do we want tooltips for explainations or can we omit that?
@@ -334,7 +317,7 @@ GtkWidget* prefs_preferences_dialog_new(CBrowser* browser)
     // TODO: Take multiple windows into account when applying changes
     GtkWidget* xfce_heading;
     if((xfce_heading = sokoke_xfce_header_new(
-     gtk_window_get_icon_name(GTK_WINDOW(browser->window)), dialogTitle)))
+     gtk_window_get_icon_name(GTK_WINDOW(browser)), dialogTitle)))
         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox)
          , xfce_heading, FALSE, FALSE, 0);
     g_free(dialogTitle);
index 7576095e04866391e9a71c0beb927abd1e575cc4..e56d2087573c8a75e8dfee51f653351f15181b35 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef __PREFS_H__
 #define __PREFS_H__ 1
 
-#include "browser.h"
+#include "midori-browser.h"
 
 #include <gtk/gtk.h>
 
@@ -20,8 +20,7 @@
 
 typedef struct
 {
-    CBrowser* browser;
-    //GtkWidget* window;
+    MidoriBrowser* browser;
     GtkWidget* userStylesheetUri;
     GtkWidget* treeview;
     GtkWidget* combobox;
@@ -38,6 +37,6 @@ enum
 // -- Declarations
 
 GtkWidget*
-prefs_preferences_dialog_new(CBrowser*);
+prefs_preferences_dialog_new(MidoriBrowser*);
 
 #endif /* !__PREFS_H__ */
index a40a10d3af896a04953c242a39f04c909a6489a8..26afcb5eac1ea5add8a08af3fa79c9f4f19c45ad 100644 (file)
@@ -12,7 +12,7 @@
 #include "search.h"
 
 #include "sokoke.h"
-#include "../katze/katze.h"
+#include <katze/katze.h>
 
 #include <stdio.h>
 #include <string.h>
index ea0c6f49487ad7df3fc64359485341bc7544d45e..8bcca67f695ca96c7ff0cee2b83edfd8b14d1233 100644 (file)
@@ -34,18 +34,6 @@ void sokoke_combo_box_add_strings(GtkComboBox* combobox
     va_end(args);
 }
 
-void sokoke_radio_action_set_current_value(GtkRadioAction* action
- , gint currentValue)
-{
-    // Activates the group member with the given value
-    #if GTK_CHECK_VERSION(2, 10, 0)
-    gtk_radio_action_set_current_value(action, currentValue);
-    #else
-    // TODO: Implement this for older gtk
-    UNIMPLEMENTED
-    #endif
-}
-
 void sokoke_widget_set_visible(GtkWidget* widget, gboolean visible)
 {
     // Show or hide the widget
@@ -304,86 +292,3 @@ void sokoke_menu_item_set_accel(GtkMenuItem* menuitem, const gchar* path
         g_free(accel);
     }
 }
-
-gboolean sokoke_entry_can_undo(GtkEntry* entry)
-{
-    // TODO: Can we undo the last input?
-    return FALSE;
-}
-
-gboolean sokoke_entry_can_redo(GtkEntry* entry)
-{
-    // TODO: Can we redo the last input?
-    return FALSE;
-}
-
-void sokoke_entry_undo(GtkEntry* entry)
-{
-    // TODO: Implement undo
-    UNIMPLEMENTED
-}
-
-void sokoke_entry_redo(GtkEntry* entry)
-{
-    // TODO: Implement redo
-    UNIMPLEMENTED
-}
-
-static gboolean sokoke_on_undo_entry_key_down(GtkEntry* widget, GdkEventKey* event
- , gpointer userdata)
-{
-    switch(event->keyval)
-    {
-    case GDK_Undo:
-        sokoke_entry_undo(widget);
-        return FALSE;
-    case GDK_Redo:
-        sokoke_entry_redo(widget);
-        return FALSE;
-    default:
-        return FALSE;
-    }
-}
-
-static void sokoke_on_undo_entry_populate_popup(GtkEntry* entry, GtkMenu* menu
- , gpointer userdata)
-{
-    // Enhance the entry's menu with undo and redo items.
-    GtkWidget* menuitem = gtk_separator_menu_item_new();
-    gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuitem);
-    gtk_widget_show(menuitem);
-    menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_REDO, NULL);
-    g_signal_connect(menuitem, "activate", G_CALLBACK(sokoke_entry_redo), userdata);
-    gtk_widget_set_sensitive(menuitem, sokoke_entry_can_redo(entry));
-    gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuitem);
-    gtk_widget_show(menuitem);
-    menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_UNDO, NULL);
-    g_signal_connect(menuitem, "activate", G_CALLBACK(sokoke_entry_undo), userdata);
-    gtk_widget_set_sensitive(menuitem, sokoke_entry_can_undo(entry));
-    gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuitem);
-    gtk_widget_show(menuitem);
-}
-
-gboolean sokoke_entry_get_can_undo(GtkEntry* entry)
-{
-    // TODO: Is this entry undo enabled?
-    return FALSE;
-}
-
-void sokoke_entry_set_can_undo(GtkEntry* entry, gboolean canUndo)
-{
-    if(canUndo)
-    {
-        g_signal_connect(entry, "key-press-event"
-         , G_CALLBACK(sokoke_on_undo_entry_key_down), NULL);
-        g_signal_connect(entry, "populate-popup"
-         , G_CALLBACK(sokoke_on_undo_entry_populate_popup), NULL);
-    }
-    else
-    {
-        g_signal_handlers_disconnect_by_func(entry
-         , G_CALLBACK(sokoke_on_undo_entry_key_down), NULL);
-        g_signal_handlers_disconnect_by_func(entry
-         , G_CALLBACK(sokoke_on_undo_entry_populate_popup), NULL);
-    }
-}
index 995e2481c1f71841bfaf9e02843b607591faf3a5..74e751be2f3fd6824a4998ed0379aa7f8075533d 100644 (file)
@@ -20,9 +20,6 @@
 void
 sokoke_combo_box_add_strings(GtkComboBox*, const gchar*, ...);
 
-void
-sokoke_radio_action_set_current_value(GtkRadioAction*, gint);
-
 void
 sokoke_widget_set_visible(GtkWidget*, gboolean);
 
@@ -70,22 +67,4 @@ sokoke_widget_get_text_size(GtkWidget*, const gchar*, gint*, gint*);
 void
 sokoke_menu_item_set_accel(GtkMenuItem*, const gchar*, const gchar*, GdkModifierType);
 
-gboolean
-sokoke_entry_can_undo(GtkEntry*);
-
-gboolean
-sokoke_entry_can_redo(GtkEntry*);
-
-void
-sokoke_entry_undo(GtkEntry*);
-
-void
-sokoke_entry_redo(GtkEntry*);
-
-gboolean
-sokoke_entry_get_can_undo(GtkEntry*);
-
-void
-sokoke_entry_set_can_undo(GtkEntry*, gboolean);
-
 #endif /* !__SOKOKE_H__ */
index 787fdd41f99a97933fe09bba9ae71cf0115187c9..bc5d6a8b09d194ae3f0c8b54f8352dee8fbda1e5 100644 (file)
--- a/src/ui.h
+++ b/src/ui.h
 #ifndef __UI_H__
 #define __UI_H__ 1
 
-// -- Credits
-
-static const gchar* credits_authors[] = { "Christian Dywan <christian@twotoasts.de>", NULL };
-static const gchar* credits_documenters/*[]*/ = /*{ */NULL/* }*/;
-static const gchar* credits_artists[] = { "Nancy Runge <nancy@twotoasts.de>", NULL };
-
-// -- Licenses
-
-static const gchar* license =
- "This library is free software; you can redistribute it and/or\n"
- "modify it under the terms of the GNU Lesser General Public\n"
- "License as published by the Free Software Foundation; either\n"
- "version 2.1 of the License, or (at your option) any later version.\n";
-
-// -- User interface description
-
-static const gchar* ui_markup =
- "<ui>"
-  "<menubar>"
-   "<menu action='File'>"
-    "<menuitem action='WindowNew'/>"
-    "<menuitem action='TabNew'/>"
-    "<separator/>"
-    "<menuitem action='Open'/>"
-    "<separator/>"
-    "<menuitem action='SaveAs'/>"
-    "<separator/>"
-    "<menuitem action='TabClose'/>"
-    "<menuitem action='WindowClose'/>"
-    "<separator/>"
-    "<menuitem action='PageSetup'/>"
-    "<menuitem action='PrintPreview'/>"
-    "<menuitem action='Print'/>"
-    "<separator/>"
-    "<menuitem action='PrivateBrowsing'/>"
-    "<menuitem action='WorkOffline'/>"
-    "<separator/>"
-    "<menuitem action='Quit'/>"
-   "</menu>"
-   "<menu action='Edit'>"
-    "<menuitem action='Undo'/>"
-    "<menuitem action='Redo'/>"
-    "<separator/>"
-    "<menuitem action='Cut'/>"
-    "<menuitem action='Copy'/>"
-    "<menuitem action='Paste'/>"
-    "<menuitem action='Delete'/>"
-    "<separator/>"
-    "<menuitem action='SelectAll'/>"
-    "<separator/>"
-    "<menuitem action='ManageSearchEngines'/>"
-    "<menuitem action='Preferences'/>"
-   "</menu>"
-   "<menu action='View'>"
-    "<menu action='Toolbars'>"
-     "<menuitem action='ToolbarNavigation'/>"
-     "<menuitem action='ToolbarBookmarks'/>"
-     "<menuitem action='ToolbarDownloads'/>"
-     "<menuitem action='ToolbarStatus'/>"
-    "</menu>"
-    "<menuitem action='Panels'/>"
-    "<separator/>"
-    "<menuitem action='Refresh'/>"
-    "<menuitem action='Stop'/>"
-    "<menu action='RefreshEvery'>"
-     "<menuitem action='RefreshEveryEnable'/>"
-     "<separator/>"
-     "<menuitem action='RefreshEvery30'/>"
-     "<menuitem action='RefreshEvery60'/>"
-     "<menuitem action='RefreshEvery300'/>"
-     "<menuitem action='RefreshEvery900'/>"
-     "<menuitem action='RefreshEvery1800'/>"
-     "<menuitem action='RefreshEveryCustom'/>"
-    "</menu>"
-    "<separator/>"
-    "<menuitem action='ZoomIn'/>"
-    "<menuitem action='ZoomOut'/>"
-    "<menuitem action='ZoomNormal'/>"
-    "<separator/>"
-    "<menuitem action='SourceView'/>"
-    "<menuitem action='Fullscreen'/>"
-   "</menu>"
-   "<menu action='Go'>"
-    "<menuitem action='Back'/>"
-    "<menuitem action='Forward'/>"
-    "<menuitem action='Home'/>"
-    "<menuitem action='Location'/>"
-    "<menuitem action='Websearch'/>"
-    "<menuitem action='OpenInPageholder'/>"
-    "<menu action='TabsClosed'>"
-    // Closed tabs shall be prepended here
-     "<separator/>"
-     "<menuitem action='TabsClosedClear'/>"
-    "</menu>"
-    "<separator/>"
-    "<menuitem action='Find'/>"
-    "<menuitem action='FindNext'/>"
-    "<menuitem action='FindPrevious'/>"
-    "<separator/>"
-    "<menuitem action='FormFill'/>"
-   "</menu>"
-   "<menu action='Bookmarks'>"
-    "<menuitem action='BookmarkNew'/>"
-    "<menuitem action='BookmarksManage'/>"
-    "<separator/>"
-    // Bookmarks shall be appended here
-   "</menu>"
-   "<menu action='Tools'>"
-    "<menuitem action='PanelDownloads'/>"
-    "<menuitem action='PanelBookmarks'/>"
-    "<menuitem action='PanelHistory'/>"
-    "<menuitem action='PanelTabs'/>"
-    "<menuitem action='PanelPageholder'/>"
-    "<menuitem action='PanelExtensions'/>"
-    "<menuitem action='PanelConsole'/>"
-    "<separator/>"
-    // TODO: Insert widgets and custom tools here
-   "</menu>"
-   "<menu action='Window'>"
-    "<menuitem action='SessionLoad'/>"
-    "<menuitem action='SessionSave'/>"
-    "<separator/>"
-    "<menuitem action='TabPrevious'/>"
-    "<menuitem action='TabNext'/>"
-    "<menuitem action='TabOverview'/>"
-    "<separator/>"
-    // All open tabs shall be appended here
-   "</menu>"
-   "<menu action='Help'>"
-    "<menuitem action='HelpContents'/>"
-    "<menuitem action='About'/>"
-   "</menu>"
-  "</menubar>"
-  "<toolbar name='toolbar_navigation'>"
-   "<toolitem action='TabNew'/>"
-   "<toolitem action='Back'/>"
-   "<toolitem action='Forward'/>"
-   "<toolitem action='RefreshStop'/>"
-   "<toolitem action='Home'/>"
-   "<toolitem action='FormFill'/>"
-   "<placeholder name='Location'/>"
-   "<placeholder name='WebSearch'/>"
-   "<placeholder name='TabTrash'/>"
-  "</toolbar>"
-  "<toolbar name='toolbar_panels'>"
-   "<toolitem action='PanelDownloads'/>"
-   "<toolitem action='PanelBookmarks'/>"
-   "<toolitem action='PanelHistory'/>"
-   "<toolitem action='PanelTabs'/>"
-   "<toolitem action='PanelPageholder'/>"
-   "<toolitem action='PanelExtensions'/>"
-   "<toolitem action='PanelConsole'/>"
-  "</toolbar>"
-  "<toolbar name='toolbar_bookmarks'>"
-   "<toolitem action='BookmarkNew'/>"
-   "<toolitem action='BookmarkEdit'/>"
-   "<toolitem action='BookmarkDelete'/>"
-  "</toolbar>"
-  "<popup name='popup_bookmark'>"
-   "<menuitem action='BookmarkOpen'/>"
-   "<menuitem action='BookmarkOpenTab'/>"
-   "<menuitem action='BookmarkOpenWindow'/>"
-   "<separator/>"
-   "<menuitem action='BookmarkEdit'/>"
-   "<menuitem action='BookmarkDelete'/>"
-  "</popup>"
-  "<popup name='popup_webView'>"
-   "<menuitem action='Back'/>"
-   "<menuitem action='Forward'/>"
-   "<menuitem action='Refresh'/>"
-   "<menuitem action='Stop'/>"
-   "<menu action='RefreshEvery'>"
-    "<menuitem action='RefreshEveryEnable'/>"
-    "<separator/>"
-    "<menuitem action='RefreshEvery30'/>"
-    "<menuitem action='RefreshEvery60'/>"
-    "<menuitem action='RefreshEvery300'/>"
-    "<menuitem action='RefreshEvery900'/>"
-    "<menuitem action='RefreshEvery1800'/>"
-    "<menuitem action='RefreshEveryCustom'/>"
-   "</menu>"
-   "<separator/>"
-   "<menuitem action='SelectionLinksNewTabs'/>"
-   "<menuitem action='SelectionTextTabNew'/>"
-   "<menuitem action='SelectionTextTabCurrent'/>"
-   "<menuitem action='SelectionTextWindowNew'/>"
-   "<separator/>"
-   "<menuitem action='UndoTabClose'/>"
-   "<menuitem action='SaveAs'/>"
-   "<menuitem action='BookmarkNew'/>"
-   "<menuitem action='Print'/>"
-   "<separator/>"
-   "<menuitem action='SelectAll'/>"
-   "<separator/>"
-   "<menuitem action='BackgroundImage'/>"
-   "<menuitem action='SourceView'/>"
-   "<menuitem action='Properties'/>"
-  "</popup>"
-  "<popup name='popup_element'>"
-   "<menuitem action='LinkTabNew'/>"
-   "<menuitem action='LinkTabCurrent'/>"
-   "<menuitem action='LinkWindowNew'/>"
-   "<separator/>"
-   "<menuitem action='LinkSaveAs'/>"
-   "<menuitem action='LinkSaveWith'/>"
-   "<menuitem action='LinkCopy'/>"
-   "<menuitem action='LinkBookmarkNew'/>"
-   "<separator/>"
-   "<menuitem action='SelectionLinksNewTabs'/>"
-   "<menuitem action='SelectionTextTabNew'/>"
-   "<menuitem action='SelectionTextTabCurrent'/>"
-   "<menuitem action='SelectionTextWindowNew'/>"
-   "<separator/>"
-   "<menuitem action='ImageViewTabNew'/>"
-   "<menuitem action='ImageViewTabCurrent'/>"
-   "<menuitem action='ImageSaveAs'/>"
-   "<menuitem action='ImageSaveWith'/>"
-   "<menuitem action='ImageCopy'/>"
-   "<separator/>"
-   "<menuitem action='ImageViewTabNew'/>"
-   "<menuitem action='ImageViewTabCurrent'/>"
-   "<separator/>"
-   "<menuitem action='Copy_'/>"
-   "<menuitem action='SelectionSearch'/>"
-   "<menuitem action='SelectionSearchWith'/>"
-   "<menuitem action='SelectionSourceView'/>"
-   "<separator/>"
-   "<menuitem action='Properties'/>"
-  "</popup>"
-  "<popup name='popup_editable'>"
-   "<menuitem action='Undo'/>"
-   "<menuitem action='Redo'/>"
-   "<separator/>"
-   "<menuitem action='Cut'/>"
-   "<menuitem action='Copy'/>"
-   "<menuitem action='Paste'/>"
-   "<menuitem action='Delete'/>"
-   "<separator/>"
-   "<menuitem action='SelectAll'/>"
-  "</popup>"
- "</ui>";
-
 #endif /* !__UI_H__ */
index 8390571cfdee7150a2f4ad547abf1af14576238c..a7a4d6ae976132825d9a9a150f8b0ccd60e8b074 100644 (file)
 #include <string.h>
 #include <gdk/gdkkeysyms.h>
 
-void update_searchEngine(guint index, CBrowser* browser)
+void update_searchEngine(guint index, GtkWidget* search)
 {
     guint n = g_list_length(searchEngines);
     // Display a default icon in case we have no engines
     if(!n)
-        sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->webSearch), SEXY_ICON_ENTRY_PRIMARY
+        sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(search), SEXY_ICON_ENTRY_PRIMARY
          , GTK_IMAGE(gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU)));
     // Change the icon and default text according to the chosen engine
     else
@@ -34,24 +34,24 @@ void update_searchEngine(guint index, CBrowser* browser)
             index = 0;
         SearchEngine* engine = (SearchEngine*)g_list_nth_data(searchEngines, index);
         GdkPixbuf* pixbuf = load_web_icon(search_engine_get_icon(engine)
-         , GTK_ICON_SIZE_MENU, browser->navibar);
-        sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->webSearch)
+         , GTK_ICON_SIZE_MENU, search);
+        sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(search)
          , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(gtk_image_new_from_pixbuf(pixbuf)));
         g_object_unref(pixbuf);
-        sokoke_entry_set_default_text(GTK_ENTRY(browser->webSearch)
+        sokoke_entry_set_default_text(GTK_ENTRY(search)
          , search_engine_get_short_name(engine));
         config->searchEngine = index;
     }
 }
 
-void on_webSearch_engine_activate(GtkWidget* widget, CBrowser* browser)
+void on_webSearch_engine_activate(GtkWidget* widget, MidoriBrowser* browser)
 {
     guint index = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget), "engine"));
-    update_searchEngine(index, browser);
+    update_searchEngine(index, widget);
 }
 
 void on_webSearch_icon_released(GtkWidget* widget, SexyIconEntryPosition* pos
- , gint button, CBrowser* browser)
+ , gint button, MidoriBrowser* browser)
 {
     GtkWidget* menu = gtk_menu_new();
     guint n = g_list_length(searchEngines);
@@ -84,14 +84,14 @@ void on_webSearch_icon_released(GtkWidget* widget, SexyIconEntryPosition* pos
         gtk_widget_show(menuitem);
     }
 
-    menuitem = gtk_separator_menu_item_new();
+    /*menuitem = gtk_separator_menu_item_new();
     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
     gtk_widget_show(menuitem);
     GtkAction* action = gtk_action_group_get_action(
      browser->actiongroup, "ManageSearchEngines");
     menuitem = gtk_action_create_menu_item(action);
     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-    gtk_widget_show(menuitem);
+    gtk_widget_show(menuitem);*/
     sokoke_widget_popup(widget, GTK_MENU(menu), NULL);
 }
 
@@ -299,16 +299,16 @@ static void on_webSearch_remove(GtkWidget* widget, CWebSearch* webSearch)
     gtk_list_store_remove(GTK_LIST_STORE(liststore), &iter);
     search_engine_free(searchEngine);
     searchEngines = g_list_remove(searchEngines, searchEngine);
-    update_searchEngine(config->searchEngine, webSearch->browser);
+    //update_searchEngine(config->searchEngine, webSearch->browser);
     webSearch_toggle_edit_buttons(g_list_nth(searchEngines, 0) != NULL, webSearch);
     // FIXME: we want to allow undo of some kind
 }
 
-GtkWidget* webSearch_manageSearchEngines_dialog_new(CBrowser* browser)
+GtkWidget* webSearch_manageSearchEngines_dialog_new(MidoriBrowser* browser)
 {
     const gchar* dialogTitle = "Manage search engines";
     GtkWidget* dialog = gtk_dialog_new_with_buttons(dialogTitle
-        , GTK_WINDOW(browser->window)
+        , GTK_WINDOW(browser)
         , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR
         , GTK_STOCK_HELP
         , GTK_RESPONSE_HELP
@@ -394,7 +394,7 @@ GtkWidget* webSearch_manageSearchEngines_dialog_new(CBrowser* browser)
     return dialog;
 }
 
-gboolean on_webSearch_key_down(GtkWidget* widget, GdkEventKey* event, CBrowser* browser)
+gboolean on_webSearch_key_down(GtkWidget* widget, GdkEventKey* event, MidoriBrowser* browser)
 {
     GdkModifierType state = (GdkModifierType)0;
     gint x, y; gdk_window_get_pointer(NULL, &x, &y, &state);
@@ -403,25 +403,25 @@ gboolean on_webSearch_key_down(GtkWidget* widget, GdkEventKey* event, CBrowser*
     switch(event->keyval)
     {
     case GDK_Up:
-        update_searchEngine(config->searchEngine - 1, browser);
+        //update_searchEngine(config->searchEngine - 1, browser);
         return TRUE;
     case GDK_Down:
-        update_searchEngine(config->searchEngine + 1, browser);
+        //update_searchEngine(config->searchEngine + 1, browser);
         return TRUE;
     }
     return FALSE;
 }
 
-gboolean on_webSearch_scroll(GtkWidget* webView, GdkEventScroll* event, CBrowser* browser)
+gboolean on_webSearch_scroll(GtkWidget* webView, GdkEventScroll* event, MidoriBrowser* browser)
 {
     if(event->direction == GDK_SCROLL_DOWN)
-        update_searchEngine(config->searchEngine + 1, browser);
+        ;//update_searchEngine(config->searchEngine + 1, browser);
     else if(event->direction == GDK_SCROLL_UP)
-        update_searchEngine(config->searchEngine - 1, browser);
+        ;//update_searchEngine(config->searchEngine - 1, browser);
     return TRUE;
 }
 
-void on_webSearch_activate(GtkWidget* widget, CBrowser* browser)
+void on_webSearch_activate(GtkWidget* widget, MidoriBrowser* browser)
 {
     const gchar* keywords = gtk_entry_get_text(GTK_ENTRY(widget));
     gchar* url;
@@ -436,6 +436,7 @@ void on_webSearch_activate(GtkWidget* widget, CBrowser* browser)
     else
      search = g_strconcat(url, " ", keywords, NULL);
     entry_completion_append(GTK_ENTRY(widget), keywords);
-    webkit_web_view_open(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser)), search);
+    GtkWidget* webView = midori_browser_get_current_web_view(browser);
+    webkit_web_view_open(WEBKIT_WEB_VIEW(webView), search);
     g_free(search);
 }
index 3cefc395755495ddbb5cb6170fe4bfffa1a570dc..cefa89be8488ea080cd593a81a6dcd72e4bafe20 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef __WEBSEARCH_H__
 #define __WEBSEARCH_H__ 1
 
-#include "browser.h"
+#include "midori-browser.h"
 
 #include <gtk/gtk.h>
 #include <libsexy/sexy.h>
@@ -22,7 +22,7 @@
 
 typedef struct
 {
-    CBrowser* browser;
+    MidoriBrowser* browser;
     GtkWidget* window;
     GtkWidget* treeview;
     GtkWidget* edit;
@@ -38,24 +38,24 @@ enum
 // -- Declarations
 
 void
-update_searchEngine(guint, CBrowser*);
+update_searchEngine(guint, GtkWidget*);
 
 void
-on_webSearch_icon_released(GtkWidget*, SexyIconEntryPosition*, gint, CBrowser*);
+on_webSearch_icon_released(GtkWidget*, SexyIconEntryPosition*, gint, MidoriBrowser*);
 
 void
-on_webSearch_engine_activate(GtkWidget*, CBrowser*);
+on_webSearch_engine_activate(GtkWidget*, MidoriBrowser*);
 
 void
-on_webSearch_activate(GtkWidget*, CBrowser*);
+on_webSearch_activate(GtkWidget*, MidoriBrowser*);
 
 GtkWidget*
-webSearch_manageSearchEngines_dialog_new(CBrowser*);
+webSearch_manageSearchEngines_dialog_new(MidoriBrowser*);
 
 gboolean
-on_webSearch_key_down(GtkWidget*, GdkEventKey*, CBrowser*);
+on_webSearch_key_down(GtkWidget*, GdkEventKey*, MidoriBrowser*);
 
 gboolean
-on_webSearch_scroll(GtkWidget*, GdkEventScroll*, CBrowser*);
+on_webSearch_scroll(GtkWidget*, GdkEventScroll*, MidoriBrowser*);
 
 #endif /* !__WEBSEARCH_H__ */
diff --git a/src/webView.c b/src/webView.c
deleted file mode 100644 (file)
index be91e22..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
-
- 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 "webView.h"
-
-#include "helpers.h"
-#include "sokoke.h"
-#include "../katze/katze.h"
-
-#include <string.h>
-
-WebKitNavigationResponse on_webView_navigation_requested(GtkWidget* webView
- , WebKitWebFrame* frame, WebKitNetworkRequest* networkRequest)
-{
-    WebKitNavigationResponse response = WEBKIT_NAVIGATION_RESPONSE_ACCEPT;
-    // TODO: Ask webkit wether it knows the protocol for "unknown protcol"
-    // TODO: This isn't the place for uri scheme handling
-    const gchar* uri = webkit_network_request_get_uri(networkRequest);
-    gchar* protocol = strtok(g_strdup(uri), ":");
-    if(spawn_protocol_command(protocol, uri))
-        response = WEBKIT_NAVIGATION_RESPONSE_IGNORE;
-    g_free(protocol);
-    return response;
-}
-
-void on_webView_title_changed(GtkWidget* webView, WebKitWebFrame* frame
- , const gchar* title, CBrowser* browser)
-{
-    const gchar* newTitle;
-    if(title)
-        newTitle = title;
-    else
-        newTitle = webkit_web_frame_get_uri(frame);
-    katze_xbel_item_set_title(browser->sessionItem, newTitle);
-    gtk_label_set_text(GTK_LABEL(browser->webView_name), newTitle);
-    sokoke_widget_set_tooltip_text(gtk_widget_get_parent(
-     gtk_widget_get_parent(browser->webView_name)), newTitle);
-    gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
-     browser->webView_menu))), newTitle);
-    if(webView == get_nth_webView(-1, browser))
-    {
-        gchar* windowTitle = g_strconcat(newTitle, " - ", PACKAGE_NAME, NULL);
-        gtk_window_set_title(GTK_WINDOW(browser->window), windowTitle);
-        g_free(windowTitle);
-    }
-}
-
-void on_webView_icon_changed(GtkWidget* webView, WebKitWebFrame* widget
- , CBrowser* browser)
-{
-    // TODO: Implement icon updates; currently this isn't ever called anyway
-    const gchar* icon = NULL;
-    UNIMPLEMENTED
-    if(icon)
-    {
-        gtk_label_set_text(GTK_LABEL(browser->webView_name), "icon");
-        gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
-         browser->webView_menu))), "icon");
-        if(webView == get_nth_webView(-1, browser))
-        {
-            gchar* windowTitle = g_strconcat("icon", " - ", PACKAGE_NAME, NULL);
-            gtk_window_set_title(GTK_WINDOW(browser->window), windowTitle);
-            g_free(windowTitle);
-        }
-    }
-}
-
-void on_webView_load_started(GtkWidget* webView, WebKitWebFrame* widget
- , CBrowser* browser)
-{
-    browser->loadedPercent = 0;
-    update_favicon(browser);
-    if(webView == get_nth_webView(-1, browser))
-    {
-        update_gui_state(browser);
-        update_statusbar(browser);
-    }
-}
-
-void on_webView_load_committed(GtkWidget* webView, WebKitWebFrame* frame
- , CBrowser* browser)
-{
-    const gchar* uri = webkit_web_frame_get_uri(frame);
-    gchar* newUri = g_strdup(uri ? uri : "");
-    katze_xbel_bookmark_set_href(browser->sessionItem, newUri);
-    if(webView == get_nth_webView(-1, browser))
-    {
-        gtk_entry_set_text(GTK_ENTRY(browser->location), newUri);
-        gtk_label_set_text(GTK_LABEL(browser->webView_name), newUri);
-        katze_assign(browser->statusMessage, NULL);
-    }
-}
-
-void on_webView_load_changed(GtkWidget* webView, gint progress, CBrowser* browser)
-{
-    browser->loadedPercent = progress;
-    if(webView == get_nth_webView(-1, browser))
-        update_statusbar(browser);
-}
-
-void on_webView_load_finished(GtkWidget* webView, WebKitWebFrame* widget
- , CBrowser* browser)
-{
-    browser->loadedPercent = -1;
-    update_favicon(browser);
-    if(webView == get_nth_webView(-1, browser))
-        update_gui_state(browser);
-}
-
-void on_webView_status_message(GtkWidget* webView, const gchar* text, CBrowser* browser)
-{
-    katze_assign(browser->statusMessage, g_strdup(text));
-    update_statusbar(browser);
-}
-
-void on_webView_selection_changed(GtkWidget* webView, CBrowser* browser)
-{
-    UNIMPLEMENTED
-}
-
-gboolean on_webView_console_message(GtkWidget* webView
- , const gchar* message, gint line, const gchar* sourceId, CBrowser* browser)
-{
-    return FALSE;
-}
-
-void on_webView_link_hover(GtkWidget* webView, const gchar* tooltip
- , const gchar* uri, CBrowser* browser)
-{
-    katze_assign(browser->statusMessage, g_strdup(uri));
-    update_statusbar(browser);
-    katze_assign(browser->elementUri, g_strdup(uri));
-}
-
-/*
-GtkWidget* on_webView_window_open(GtkWidget* webView, const gchar* sUri
- , CBrowser* browser)
-{
-    // A window is created
-    // TODO: Respect config->iNewPages
-    // TODO: Find out if this comes from a script or a click
-    // TODO: Block scripted popups, return NULL and show status icon
-    CBrowser* newBrowser = browser_new(config->openPopupsInTabs ? browser : NULL);
-    return newBrowser->webView;
-}
-*/
-
-void webView_popup(GtkWidget* webView, GdkEventButton* event, CBrowser* browser)
-{
-    gboolean isLink = browser->elementUri != NULL; // Did we right-click a link?
-    gboolean haveLinks = FALSE; // TODO: Are several links selected?
-    gboolean isImage = FALSE; // TODO: Did we right-click an image?
-    gboolean isEditable = webkit_web_view_can_paste_clipboard(WEBKIT_WEB_VIEW(webView));
-    gboolean hasSelection = webkit_web_view_has_selection(WEBKIT_WEB_VIEW(webView));
-
-    update_edit_items(browser);
-
-    // Download manager available?
-    const gchar* downloadManager = g_datalist_get_data(&config->protocols_commands, "download");
-    gboolean canDownload = downloadManager && *downloadManager;
-
-    action_set_visible("LinkTabNew", isLink, browser);
-    action_set_visible("LinkTabCurrent", isLink, browser);
-    action_set_visible("LinkWindowNew", isLink, browser);
-
-    action_set_visible("LinkSaveAs", isLink, browser);
-    action_set_visible("LinkSaveWith", isLink && canDownload, browser);
-    action_set_visible("LinkCopy", isLink, browser);
-    action_set_visible("LinkBookmarkNew", isLink, browser);
-
-    action_set_visible("SelectionLinksNewTabs", haveLinks && hasSelection, browser);
-    action_set_visible("SelectionTextTabNew", haveLinks && hasSelection, browser);
-    action_set_visible("SelectionTextTabCurrent", haveLinks && hasSelection, browser);
-    action_set_visible("SelectionTextWindowNew", haveLinks && hasSelection, browser);
-
-    action_set_visible("ImageViewTabNew", isImage, browser);
-    action_set_visible("ImageViewTabCurrent", isImage, browser);
-    action_set_visible("ImageSaveAs", isImage, browser);
-    action_set_visible("ImageSaveWith", isImage && canDownload, browser);
-    action_set_visible("ImageCopy", isImage, browser);
-
-    action_set_visible("Copy_", hasSelection || isEditable, browser);
-    action_set_visible("SelectionSearch", hasSelection, browser);
-    action_set_visible("SelectionSearchWith", hasSelection, browser);
-    action_set_visible("SelectionSourceView", hasSelection, browser);
-
-    action_set_visible("SourceView", !hasSelection, browser);
-
-    if(isEditable)
-        sokoke_widget_popup(webView, GTK_MENU(browser->popup_editable), event);
-    else if(isLink || isImage || hasSelection)
-        sokoke_widget_popup(webView, GTK_MENU(browser->popup_element), event);
-    else
-        sokoke_widget_popup(webView, GTK_MENU(browser->popup_webView), event);
-}
-
-gboolean on_webView_button_press(GtkWidget* webView, GdkEventButton* event
- , CBrowser* browser)
-{
-    GdkModifierType state = (GdkModifierType)0;
-    gint x, y;
-    gdk_window_get_pointer(NULL, &x, &y, &state);
-    switch(event->button)
-    {
-    case 1:
-        if(!browser->elementUri)
-            return FALSE;
-        if(state & GDK_SHIFT_MASK)
-        {
-            // Open link in new window
-            CBrowser* curBrowser = browser_new(NULL);
-            webkit_web_view_open(WEBKIT_WEB_VIEW(curBrowser->webView), browser->elementUri);
-            return TRUE;
-        }
-        else if(state & GDK_MOD1_MASK)
-        {
-            // Open link in new tab
-            CBrowser* curBrowser = browser_new(browser);
-            webkit_web_view_open(WEBKIT_WEB_VIEW(curBrowser->webView), browser->elementUri);
-            return TRUE;
-        }
-        break;
-    case 2:
-        if(state & GDK_CONTROL_MASK)
-        {
-            //webkit_web_view_set_text_size(WEBKIT_WEB_VIEW(webView), 1);
-            return TRUE;
-        }
-        else
-        {
-            if(!browser->elementUri)
-                return FALSE;
-            // Open link in new tab
-            CBrowser* curBrowser = browser_new(browser);
-            webkit_web_view_open(WEBKIT_WEB_VIEW(curBrowser->webView), browser->elementUri);
-            return TRUE;
-        }
-        break;
-    case 3:
-        webView_popup(webView, event, browser);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-gboolean on_webView_button_press_after(GtkWidget* webView, GdkEventButton* event
- , CBrowser* browser)
-{
-    if(event->button == 2 && config->middleClickGoto)
-    {
-        GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
-        gchar* text = gtk_clipboard_wait_for_text(clipboard);
-        gchar* uri = NULL;
-        if(text && strchr(text, '.') && !strchr(text, ' '))
-            uri = magic_uri(text, FALSE);
-        g_free(text);
-        if(uri)
-        {
-            webkit_web_view_open(WEBKIT_WEB_VIEW(browser->webView), uri);
-            g_free(uri);
-            return TRUE;
-        }
-    }
-    return FALSE;
-}
-
-void on_webView_popup(GtkWidget* webView, CBrowser* browser)
-{
-    webView_popup(webView, NULL, browser);
-}
-
-gboolean on_webView_scroll(GtkWidget* webView, GdkEventScroll* event
- , CBrowser* browser)
-{
-    GdkModifierType state = (GdkModifierType)0;
-    gint x, y;
-    gdk_window_get_pointer(NULL, &x, &y, &state);
-    if(state & GDK_CONTROL_MASK)
-    {
-        /*const gfloat size = webkit_web_view_get_text_size(WEBKIT_WEB_VIEW(webView));
-        if(event->direction == GDK_SCROLL_DOWN)
-            webkit_web_view_set_text_size(WEBKIT_WEB_VIEW(webView), size + 0.1);
-        else if(event->direction == GDK_SCROLL_UP)
-            webView_set_text_size(WEBKIT_WEB_VIEW(webView), size - 0.1);*/
-        return TRUE;
-    }
-    else
-        return FALSE;
-}
-
-gboolean on_webView_leave(GtkWidget* webView, GdkEventCrossing* event, CBrowser* browser)
-{
-    katze_assign(browser->statusMessage, NULL);
-    update_statusbar(browser);
-    return TRUE;
-}
-
-void on_webView_destroy(GtkWidget* widget, CBrowser* browser)
-{
-    // Update browser list, free memory and possibly quit
-    GList* tmp = g_list_find(browsers, browser);
-    browsers = g_list_delete_link(browsers, tmp);
-    g_free(browser->elementUri);
-    g_free(browser->statusMessage);
-    // FIXME: Multiple windows are not taken into account
-    if(!g_list_nth(browsers, 0))
-    {
-        g_object_unref(browser->actiongroup);
-        g_object_unref(browser->popup_bookmark);
-        g_object_unref(browser->popup_webView);
-        g_object_unref(browser->popup_element);
-        g_object_unref(browser->popup_editable);
-        guint i;
-        guint n = katze_xbel_folder_get_n_items(bookmarks);
-        for(i = 0; i < n; i++)
-            katze_xbel_item_unref(katze_xbel_folder_get_nth_item(bookmarks, i));
-        gtk_main_quit();
-    }
-}
-
-// webView actions begin here
-
-GtkWidget* webView_new(GtkWidget** scrolled)
-{
-    *scrolled = gtk_scrolled_window_new(NULL, NULL);
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(*scrolled)
-     , GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-    GTK_WIDGET_SET_FLAGS(*scrolled, GTK_CAN_FOCUS);
-    GtkWidget* webView = webkit_web_view_new();
-    gtk_container_add(GTK_CONTAINER(*scrolled), webView);
-    return webView;
-}
-
-void webView_open(GtkWidget* webView, const gchar* uri)
-{
-    webkit_web_view_open(WEBKIT_WEB_VIEW(webView), uri);
-    // We need to check the browser first
-    // No browser means this is a panel
-    CBrowser* browser = get_browser_from_webView(webView);
-    if(browser)
-    {
-        katze_xbel_bookmark_set_href(browser->sessionItem, uri);
-        katze_xbel_item_set_title(browser->sessionItem, "");
-    }
-}
-
-void webView_close(GtkWidget* webView, CBrowser* browser)
-{
-    browser = get_browser_from_webView(webView);
-    const gchar* uri = katze_xbel_bookmark_get_href(browser->sessionItem);
-    katze_xbel_folder_remove_item(session, browser->sessionItem);
-    if(uri && *uri)
-    {
-        katze_xbel_folder_prepend_item(tabtrash, browser->sessionItem);
-        guint n = katze_xbel_folder_get_n_items(tabtrash);
-        if(n > 10)
-        {
-            KatzeXbelItem* item = katze_xbel_folder_get_nth_item(tabtrash, n - 1);
-            katze_xbel_item_unref(item);
-        }
-    }
-    else
-        katze_xbel_item_unref(browser->sessionItem);
-    gtk_widget_destroy(browser->webView_menu);
-    gtk_notebook_remove_page(GTK_NOTEBOOK(browser->webViews)
-     , get_webView_index(webView, browser));
-    update_browser_actions(browser);
-}
diff --git a/src/webView.h b/src/webView.h
deleted file mode 100644 (file)
index 552b571..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
-
- 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 __webView_H__
-#define __webView_H__ 1
-
-#include <gtk/gtk.h>
-#include "browser.h"
-#include "debug.h"
-
-#include <webkit/webkit.h>
-
-WebKitNavigationResponse
-on_webView_navigation_requested(GtkWidget* webView, WebKitWebFrame* frame
- , WebKitNetworkRequest* networkRequest);
-
-void
-on_webView_title_changed(GtkWidget*, WebKitWebFrame*, const gchar*, CBrowser*);
-
-void
-on_webView_icon_changed(GtkWidget*, WebKitWebFrame*, CBrowser*);
-
-void
-on_webView_load_started(GtkWidget* , WebKitWebFrame*, CBrowser*);
-
-void
-on_webView_load_committed(GtkWidget* , WebKitWebFrame*, CBrowser*);
-
-void
-on_webView_load_changed(GtkWidget*, gint progress, CBrowser*);
-
-void
-on_webView_load_finished(GtkWidget*, WebKitWebFrame*, CBrowser*);
-
-void
-on_webView_status_message(GtkWidget*, const gchar*, CBrowser*);
-
-void
-on_webView_selection_changed(GtkWidget*, CBrowser*);
-
-gboolean
-on_webView_console_message(GtkWidget*, const gchar*, gint, const gchar*, CBrowser*);
-
-void
-on_webView_link_hover(GtkWidget*, const gchar*, const gchar*, CBrowser*);
-
-/*
-GtkWidget*
-on_webView_window_open(GtkWidget*, const gchar*, CBrowser*);
-*/
-
-gboolean
-on_webView_button_press(GtkWidget*, GdkEventButton*, CBrowser*);
-
-gboolean
-on_webView_button_press_after(GtkWidget*, GdkEventButton*, CBrowser*);
-
-void
-on_webView_popup(GtkWidget*, CBrowser*);
-
-gboolean
-on_webView_scroll(GtkWidget*, GdkEventScroll*, CBrowser*);
-
-gboolean
-on_webView_leave(GtkWidget*, GdkEventCrossing*, CBrowser*);
-
-void
-on_webView_destroy(GtkWidget*, CBrowser*);
-
-GtkWidget*
-webView_new(GtkWidget**);
-
-void
-webView_open(GtkWidget*, const gchar*);
-
-void
-webView_close(GtkWidget*, CBrowser*);
-
-#endif /* !__webView_H__ */