]> spindle.queued.net Git - midori/commitdiff
Implement tabs in individual processes
authorChristian Dywan <christian@twotoasts.de>
Fri, 26 Sep 2008 21:13:46 +0000 (23:13 +0200)
committerChristian Dywan <christian@twotoasts.de>
Fri, 26 Sep 2008 21:30:52 +0000 (23:30 +0200)
The approach is rather plump, Midori can be
run in a plug mode that creates a GtkPlug,
while the normal instance knows how to embed it.

Communication between browser and tabs is
done via named pipes which are portable.

The feature is not complete right now, there
are expected regressions, but it works.

As a bonus, we implement Not found pages.

13 files changed:
midori/Makefile.am
midori/main.c
midori/midori-browser.c
midori/midori-browser.h
midori/midori-panel.c
midori/midori-source.c [new file with mode: 0644]
midori/midori-source.h [new file with mode: 0644]
midori/midori-view.c [new file with mode: 0644]
midori/midori-view.h [new file with mode: 0644]
midori/midori-webview.c [deleted file]
midori/midori-webview.h [deleted file]
midori/sokoke.c
midori/sokoke.h

index ffe49e566b0407660cead1793dc693f74d818a7d..3c327a3fe6d1652ef2441b7e966396c16afb653f 100644 (file)
@@ -28,7 +28,8 @@ midori_SOURCES = \
     midori-panel.c         midori-panel.h         \
     midori-addons.c        midori-addons.h        \
     midori-console.c       midori-console.h       \
-    midori-webview.c       midori-webview.h       \
+    midori-view.c          midori-view.h          \
+    midori-source.c        midori-source.h        \
     midori-websettings.c   midori-websettings.h   \
     midori-preferences.c   midori-preferences.h   \
     midori-searchentry.c   midori-searchentry.h   \
index de898e2de216d0cd81806b4779b50008a32d0402..fac85f03250ce466d92243df475da8589a3aa867 100644 (file)
@@ -13,6 +13,7 @@
     #include <config.h>
 #endif
 
+#include "midori-view.h"
 #include "midori-app.h"
 #include "midori-websettings.h"
 #include "midori-browser.h"
@@ -367,25 +368,76 @@ _simple_xml_element (const gchar* name,
 }
 
 static gchar*
-katze_xbel_array_to_xml (KatzeArray* array,
-                         GError**    error)
+katze_item_to_data (KatzeItem* item)
+{
+    gchar* markup;
+
+    g_return_val_if_fail (KATZE_IS_ITEM (item), NULL);
+
+    markup = NULL;
+    if (KATZE_IS_ARRAY (item))
+    {
+        GString* _markup = g_string_new (NULL);
+        guint n = katze_array_get_length (KATZE_ARRAY (item));
+        guint i;
+        for (i = 0; i < n; i++)
+        {
+            KatzeItem* _item = katze_array_get_nth_item (KATZE_ARRAY (item), i);
+            gchar* item_markup = katze_item_to_data (_item);
+            g_string_append (_markup, item_markup);
+            g_free (item_markup);
+        }
+        /* gchar* folded = item->folded ? NULL : g_strdup_printf (" folded=\"no\""); */
+        gchar* title = _simple_xml_element ("title", katze_item_get_name (item));
+        gchar* desc = _simple_xml_element ("desc", katze_item_get_text (item));
+        markup = g_strdup_printf ("<folder%s>\n%s%s%s</folder>\n",
+                                  "" /* folded ? folded : "" */,
+                                  title, desc,
+                                  g_string_free (_markup, FALSE));
+        /* g_free (folded); */
+        g_free (title);
+        g_free (desc);
+    }
+    else if (katze_item_get_uri (item))
+    {
+        gchar* href_escaped = g_markup_escape_text (katze_item_get_uri (item), -1);
+        gchar* href = g_strdup_printf (" href=\"%s\"", href_escaped);
+        g_free (href_escaped);
+        gchar* title = _simple_xml_element ("title", katze_item_get_name (item));
+        gchar* desc = _simple_xml_element ("desc", katze_item_get_text (item));
+        markup = g_strdup_printf ("<bookmark%s>\n%s%s%s</bookmark>\n",
+                                  href,
+                                  title, desc,
+                                  "");
+        g_free (href);
+        g_free (title);
+        g_free (desc);
+    }
+    else
+        markup = g_strdup ("<separator/>\n");
+    return markup;
+}
+
+static gchar*
+katze_array_to_xml (KatzeArray* array,
+                    GError**    error)
 {
     GString* inner_markup;
     guint i, n;
-    KatzeXbelItem* item;
+    KatzeItem* item;
     gchar* item_xml;
     gchar* title;
     gchar* desc;
     gchar* outer_markup;
 
-    g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_XBEL_ITEM), NULL);
+    g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_ITEM), NULL);
 
     inner_markup = g_string_new (NULL);
     n = katze_array_get_length (array);
     for (i = 0; i < n; i++)
     {
         item = katze_array_get_nth_item (array, i);
-        item_xml = katze_xbel_item_to_data (item);
+        item_xml = katze_item_to_data (item);
         g_string_append (inner_markup, item_xml);
         g_free (item_xml);
     }
@@ -415,10 +467,10 @@ katze_array_to_file (KatzeArray*  array,
     gchar* data;
     FILE* fp;
 
-    g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_XBEL_ITEM), FALSE);
+    g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_ITEM), FALSE);
     g_return_val_if_fail (filename, FALSE);
 
-    if (!(data = katze_xbel_array_to_xml (array, error)))
+    if (!(data = katze_array_to_xml (array, error)))
         return FALSE;
     if (!(fp = fopen (filename, "w")))
     {
@@ -468,6 +520,7 @@ int
 main (int    argc,
       char** argv)
 {
+    guint socket_id;
     gboolean version;
     gchar** uris;
     MidoriApp* app;
@@ -475,12 +528,16 @@ main (int    argc,
     GError* error;
     GOptionEntry entries[] =
     {
-     { "version", 'v', 0, G_OPTION_ARG_NONE, &version,
+       { "id", 'i', 0, G_OPTION_ARG_INT, &socket_id,
+       N_("Internal identifier"), NULL },
+       { "version", 'v', 0, G_OPTION_ARG_NONE, &version,
        N_("Display program version"), NULL },
        { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &uris,
        N_("URIs"), NULL },
      { NULL }
     };
+    GtkWidget* view;
+    GtkWidget* plug;
     MidoriStartup load_on_startup;
     gchar* homepage;
     KatzeArray* search_engines;
@@ -498,6 +555,7 @@ main (int    argc,
     g_set_application_name (_("Midori"));
 
     /* Parse cli options */
+    socket_id = 0;
     version = FALSE;
     uris = NULL;
     error = NULL;
@@ -509,6 +567,22 @@ main (int    argc,
         return 1;
     }
 
+    stock_items_init ();
+
+    if (socket_id)
+    {
+        /* If an ID was specified we create a view in a plug.
+           This allows us to open views in separate processes. */
+        view = g_object_new (MIDORI_TYPE_VIEW, "socket-id", socket_id, NULL);
+        gtk_widget_show (view);
+        plug = gtk_plug_new (socket_id);
+        gtk_container_add (GTK_CONTAINER (plug), view);
+        g_signal_connect (plug, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+        gtk_widget_show (plug);
+        gtk_main ();
+        return 0;
+    }
+
     if (version)
     {
         g_print (
@@ -539,6 +613,8 @@ main (int    argc,
         return 1;
     }
 
+    sokoke_remember_argv0 (argv[0]);
+
     app = midori_app_new ();
     if (midori_app_instance_is_running (app))
     {
@@ -691,14 +767,19 @@ main (int    argc,
     }
     g_free (config_path);
 
-    stock_items_init ();
-
-    KatzeArray* trash = katze_array_new (KATZE_TYPE_XBEL_ITEM);
+    KatzeArray* trash = katze_array_new (KATZE_TYPE_ITEM);
     guint n = katze_xbel_folder_get_n_items (xbel_trash);
     for (i = 0; i < n; i++)
     {
-        KatzeXbelItem* item = katze_xbel_folder_get_nth_item (xbel_trash, i);
-        katze_array_add_item (trash, item);
+        KatzeXbelItem* xbel_item = katze_xbel_folder_get_nth_item (xbel_trash, i);
+        if (!katze_xbel_item_is_separator (xbel_item))
+        {
+            KatzeItem* item = g_object_new (KATZE_TYPE_ITEM,
+                "name", katze_xbel_item_get_title (xbel_item),
+                "uri", katze_xbel_bookmark_get_href (xbel_item),
+                NULL);
+            katze_array_add_item (trash, item);
+        }
     }
     katze_xbel_item_unref (xbel_trash);
     g_signal_connect_after (trash, "add-item",
@@ -719,7 +800,7 @@ main (int    argc,
     midori_app_add_browser (app, browser);
     gtk_widget_show (GTK_WIDGET (browser));
 
-    KatzeArray* session = midori_browser_get_proxy_xbel_array (browser);
+    KatzeArray* session = midori_browser_get_proxy_array (browser);
     n = katze_xbel_folder_get_n_items (_session);
     for (i = 0; i < n; i++)
     {
index 9828b507024272f004daceccb33ae48fd917aac9..91c2a9bb7cf2856c39150edf90ad99e0dbca029b 100644 (file)
@@ -15,7 +15,8 @@
 
 #include "midori-browser.h"
 
-#include "midori-webview.h"
+#include "midori-view.h"
+#include "midori-source.h"
 #include "midori-preferences.h"
 #include "midori-panel.h"
 #include "midori-addons.h"
 #endif
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
-#if HAVE_GTKSOURCEVIEW
-#include <gtksourceview/gtksourceview.h>
-#include <gtksourceview/gtksourcelanguagemanager.h>
-#endif
 #include <string.h>
 
 struct _MidoriBrowser
@@ -76,10 +73,8 @@ struct _MidoriBrowser
     gchar* statusbar_text;
     MidoriWebSettings* settings;
     KatzeXbelItem* bookmarks;
-    GList* tab_titles;
-    GList* close_buttons;
 
-    KatzeArray* proxy_xbel_array;
+    KatzeArray* proxy_array;
     KatzeArray* trash;
     KatzeArray* search_engines;
 };
@@ -105,8 +100,6 @@ enum
 enum
 {
     WINDOW_OBJECT_CLEARED,
-    STATUSBAR_TEXT_CHANGED,
-    ELEMENT_MOTION,
     NEW_WINDOW,
 
     ADD_TAB,
@@ -163,56 +156,15 @@ _action_set_active (MidoriBrowser* browser,
     gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active);
 }
 
-static const gchar*
-_midori_browser_get_tab_uri (MidoriBrowser* browser,
-                             GtkWidget*     widget)
-{
-    const gchar* uri;
-
-    if (MIDORI_IS_WEB_VIEW (widget))
-        return midori_web_view_get_display_uri (MIDORI_WEB_VIEW (widget));
-
-    uri = g_object_get_data (G_OBJECT (widget), "browser-tab-uri");
-    return uri ? uri : "file://";
-}
-
-/* Note: The return value is valid only
-         until the next call to this function */
-static const gchar*
-_midori_browser_get_tab_title (MidoriBrowser* browser,
-                               GtkWidget*     widget)
-{
-    const gchar* uri;
-    static gchar* title = NULL;
-
-    if (MIDORI_IS_WEB_VIEW (widget))
-        return midori_web_view_get_display_title (MIDORI_WEB_VIEW (widget));
-
-    uri = g_object_get_data (G_OBJECT (widget), "browser-tab-uri");
-    if (g_str_has_prefix (uri, "view-source:"))
-    {
-        g_free (title);
-        title = g_strconcat (_("Source"), ": ", uri, NULL);
-        return title;
-    }
-    return "untitled";
-}
-
 static void
 _midori_browser_open_uri (MidoriBrowser* browser,
                           const gchar*   uri)
 {
-    GtkWidget* web_view;
-    gint n;
+    GtkWidget* view;
 
-    web_view = midori_browser_get_current_web_view (browser);
-    if (web_view)
-        webkit_web_view_open (WEBKIT_WEB_VIEW (web_view), uri);
-    else
-    {
-        n = midori_browser_add_uri (browser, uri);
-        midori_browser_set_current_page (browser, n);
-    }
+    view = midori_browser_get_current_tab (browser);
+    if (view)
+        midori_view_set_uri (MIDORI_VIEW (view), uri);
 }
 
 static void
@@ -238,35 +190,41 @@ _midori_browser_update_actions (MidoriBrowser* browser)
 static void
 _midori_browser_update_interface (MidoriBrowser* browser)
 {
+    GtkWidget* view;
     gboolean loading;
-    GtkWidget* widget;
-    GtkWidget* web_view;
+    gboolean can_reload;
     GtkAction* action;
 
-    widget = midori_browser_get_current_tab (browser);
-    web_view = widget && MIDORI_IS_WEB_VIEW (widget) ? widget : NULL;
-    loading = web_view != NULL
-        && midori_web_view_get_load_status (MIDORI_WEB_VIEW (web_view))
+    view = midori_browser_get_current_tab (browser);
+    loading = midori_view_get_load_status (MIDORI_VIEW (view))
         != MIDORI_LOAD_FINISHED;
-
-    _action_set_sensitive (browser, "Reload", web_view != NULL && !loading);
-        _action_set_sensitive (browser, "Stop", web_view != NULL && loading);
-    _action_set_sensitive (browser, "Back", web_view != NULL
-        && webkit_web_view_can_go_back (WEBKIT_WEB_VIEW (web_view)));
-    _action_set_sensitive (browser, "Forward", web_view != NULL
-        && webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW (web_view)));
-
-    _action_set_sensitive (browser, "Print", web_view != NULL);
-    _action_set_sensitive (browser, "ZoomIn", web_view != NULL);
-    _action_set_sensitive (browser, "ZoomOut", web_view != NULL);
-    _action_set_sensitive (browser, "ZoomNormal", web_view != NULL
-        && webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view)) != 1.0);
-    #if HAVE_GIO
-    _action_set_sensitive (browser, "SourceView", web_view != NULL);
-    #endif
-    _action_set_sensitive (browser, "FindNext", web_view != NULL);
-    _action_set_sensitive (browser, "FindPrevious", web_view != NULL);
-    /* _action_set_sensitive (browser, "FindQuick", web_view != NULL); */
+    can_reload = midori_view_can_reload (MIDORI_VIEW (view));
+
+    _action_set_sensitive (browser, "Reload", can_reload && !loading);
+    _action_set_sensitive (browser, "Stop", can_reload && loading);
+    _action_set_sensitive (browser, "Back",
+        midori_view_can_go_back (MIDORI_VIEW (view)));
+    _action_set_sensitive (browser, "Forward",
+        midori_view_can_go_forward (MIDORI_VIEW (view)));
+
+    _action_set_sensitive (browser, "Print",
+        midori_view_can_print (MIDORI_VIEW (view)));
+    _action_set_sensitive (browser, "ZoomIn",
+        midori_view_can_zoom_in (MIDORI_VIEW (view)));
+    _action_set_sensitive (browser, "ZoomOut",
+        midori_view_can_zoom_out (MIDORI_VIEW (view)));
+    _action_set_sensitive (browser, "ZoomNormal",
+        midori_view_get_zoom_level (MIDORI_VIEW (view)) != 1.0);
+    _action_set_sensitive (browser, "SourceView",
+        midori_view_can_view_source (MIDORI_VIEW (view)));
+    _action_set_sensitive (browser, "Find",
+        midori_view_can_find (MIDORI_VIEW (view)));
+    _action_set_sensitive (browser, "FindNext",
+        midori_view_can_find (MIDORI_VIEW (view)));
+    _action_set_sensitive (browser, "FindPrevious",
+        midori_view_can_find (MIDORI_VIEW (view)));
+    /* _action_set_sensitive (browser, "FindQuick",
+        midori_view_can_find (MIDORI_VIEW (view))); */
 
     action = gtk_action_group_get_action (browser->action_group, "ReloadStop");
     if (!loading)
@@ -275,7 +233,7 @@ _midori_browser_update_interface (MidoriBrowser* browser)
         g_object_set (action,
                       "stock-id", GTK_STOCK_REFRESH,
                       "tooltip", _("Reload the current page"),
-                      "sensitive", web_view != NULL, NULL);
+                      "sensitive", can_reload, NULL);
         gtk_widget_hide (browser->progressbar);
         if (!GTK_WIDGET_VISIBLE (browser->statusbar))
             if (!sokoke_object_get_boolean (browser->settings,
@@ -294,13 +252,13 @@ _midori_browser_update_interface (MidoriBrowser* browser)
             if (!GTK_WIDGET_VISIBLE (browser->navigationbar))
                 gtk_widget_show (browser->navigationbar);
             g_object_set (_action_by_name (browser, "Location"), "progress",
-                midori_web_view_get_progress (MIDORI_WEB_VIEW (web_view)), NULL);
+                midori_view_get_progress (MIDORI_VIEW (view)), NULL);
         }
     }
     katze_throbber_set_animated (KATZE_THROBBER (browser->throbber), loading);
 
     /* FIXME: This won't work due to a bug in GtkIconEntry */
-    /* if (web_view && midori_web_view_get_news_feeds (MIDORI_WEB_VIEW (web_view)))
+    /* if (view && midori_view_get_news_feeds (MIDORI_VIEW (view)))
         gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (
             gtk_bin_get_child (GTK_BIN (browser->location))),
             GTK_ICON_ENTRY_SECONDARY, STOCK_NEWS_FEED);
@@ -310,26 +268,6 @@ _midori_browser_update_interface (MidoriBrowser* browser)
             GTK_ICON_ENTRY_SECONDARY, NULL);*/
 }
 
-static GtkWidget*
-_midori_browser_scrolled_for_child (MidoriBrowser* browser,
-                                    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* browser,
-                                    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 void
 _midori_browser_set_statusbar_text (MidoriBrowser* browser,
                                     const gchar*   text)
@@ -351,16 +289,16 @@ _midori_browser_set_current_page_smartly (MidoriBrowser* browser,
 
 static void
 _midori_browser_update_progress (MidoriBrowser* browser,
-                                 MidoriWebView* web_view)
+                                 MidoriView*    view)
 {
     MidoriLocationAction* action;
     gdouble progress;
     gchar* message;
 
     action = MIDORI_LOCATION_ACTION (_action_by_name (browser, "Location"));
-    progress = midori_web_view_get_progress (web_view);
+    progress = midori_view_get_progress (view);
     /* When we are finished, we don't want to *see* progress anymore */
-    if (midori_web_view_get_load_status (web_view) == MIDORI_LOAD_FINISHED)
+    if (midori_view_get_load_status (view) == MIDORI_LOAD_FINISHED)
         progress = 0.0;
     if (progress > 0.0)
     {
@@ -383,35 +321,55 @@ _midori_browser_update_progress (MidoriBrowser* browser,
 }
 
 static void
-midori_web_view_window_object_cleared_cb (GtkWidget*         web_view,
-                                          WebKitWebFrame*    web_frame,
-                                          JSGlobalContextRef js_context,
-                                          JSObjectRef        js_window,
-                                          MidoriBrowser*     browser)
+_midori_browser_activate_action (MidoriBrowser* browser,
+                                 const gchar*   name)
+{
+    GtkAction* action = _action_by_name (browser, name);
+    if (action)
+        gtk_action_activate (action);
+    else
+        g_warning (_("Unexpected action '%s'."), name);
+}
+
+static void
+midori_view_notify_icon_cb (MidoriView*    view,
+                            GParamSpec*    pspec,
+                            MidoriBrowser* browser)
 {
-    g_signal_emit (browser, signals[WINDOW_OBJECT_CLEARED], 0,
-                   web_frame, js_context, js_window);
+    const gchar* uri;
+    GtkAction* action;
+
+    uri = midori_view_get_display_uri (MIDORI_VIEW (view));
+    action = _action_by_name (browser, "Location");
+    midori_location_action_set_icon_for_uri (
+        MIDORI_LOCATION_ACTION (action), midori_view_get_icon (view), uri);
 }
 
 static void
-midori_web_view_notify_load_status_cb (GtkWidget*      web_view,
-                                       GParamSpec*     pspec,
-                                       MidoriBrowser*  browser)
+midori_view_notify_load_status_cb (GtkWidget*      view,
+                                   GParamSpec*     pspec,
+                                   MidoriBrowser*  browser)
 {
     const gchar* uri;
     GtkAction* action;
 
-    uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view));
+    uri = midori_view_get_display_uri (MIDORI_VIEW (view));
     action = _action_by_name (browser, "Location");
 
-    if (midori_web_view_get_load_status (MIDORI_WEB_VIEW (web_view))
+    if (midori_view_get_load_status (MIDORI_VIEW (view))
         == MIDORI_LOAD_COMMITTED)
         midori_location_action_add_uri (
             MIDORI_LOCATION_ACTION (action), uri);
+    else if (midori_view_get_load_status (MIDORI_VIEW (view))
+        == MIDORI_LOAD_FINISHED)
+    {
+        /* g_signal_emit (browser, signals[WINDOW_OBJECT_CLEARED], 0,
+                       web_frame, js_context, js_window); */
+    }
 
-    if (web_view == midori_browser_get_current_web_view (browser))
+    if (view == midori_browser_get_current_tab (browser))
     {
-        if (midori_web_view_get_load_status (MIDORI_WEB_VIEW (web_view))
+        if (midori_view_get_load_status (MIDORI_VIEW (view))
             == MIDORI_LOAD_COMMITTED)
         {
             midori_location_action_set_uri (
@@ -427,31 +385,45 @@ midori_web_view_notify_load_status_cb (GtkWidget*      web_view,
 }
 
 static void
-midori_web_view_notify_progress_cb (GtkWidget*     web_view,
-                                    GParamSpec*    pspec,
+midori_view_notify_progress_cb (GtkWidget*     view,
+                                GParamSpec*    pspec,
+                                MidoriBrowser* browser)
+{
+    if (view == midori_browser_get_current_tab (browser))
+        _midori_browser_update_progress (browser, MIDORI_VIEW (view));
+}
+
+/*
+static void
+midori_web_view_news_feed_ready_cb (MidoriWebView* web_view,
+                                    const gchar*   href,
+                                    const gchar*   type,
+                                    const gchar*   title,
                                     MidoriBrowser* browser)
 {
-    if (web_view == midori_browser_get_current_web_view (browser))
-        _midori_browser_update_progress (browser, MIDORI_WEB_VIEW (web_view));
+    if (web_view == (MidoriWebView*)midori_browser_get_current_web_view (browser))
+        midori_location_action_set_secondary_icon (MIDORI_LOCATION_ACTION (
+            _action_by_name (browser, "Location")), STOCK_NEWS_FEED);
 }
+*/
 
 static void
-midori_web_view_notify_title_cb (GtkWidget*     web_view,
-                                 GParamSpec*    pspec,
-                                 MidoriBrowser* browser)
+midori_view_notify_title_cb (GtkWidget*     view,
+                             GParamSpec*    pspec,
+                             MidoriBrowser* browser)
 {
     const gchar* uri;
     const gchar* title;
     GtkAction* action;
     gchar* window_title;
 
-    uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view));
-    title = midori_web_view_get_display_title (MIDORI_WEB_VIEW (web_view));
+    uri = midori_view_get_display_uri (MIDORI_VIEW (view));
+    title = midori_view_get_display_title (MIDORI_VIEW (view));
     action = _action_by_name (browser, "Location");
     midori_location_action_set_title_for_uri (
         MIDORI_LOCATION_ACTION (action), title, uri);
 
-    if (web_view == midori_browser_get_current_web_view (browser))
+    if (view == midori_browser_get_current_tab (browser))
     {
         window_title = g_strconcat (title, " - ",
             g_get_application_name (), NULL);
@@ -461,130 +433,25 @@ midori_web_view_notify_title_cb (GtkWidget*     web_view,
 }
 
 static void
-midori_web_view_notify_zoom_level_cb (GtkWidget*     web_view,
-                                      GParamSpec*    pspec,
-                                      MidoriBrowser* browser)
+midori_view_notify_zoom_level_cb (GtkWidget*     view,
+                                  GParamSpec*    pspec,
+                                  MidoriBrowser* browser)
 {
-    if (web_view == midori_browser_get_current_web_view (browser))
+    if (view == midori_browser_get_current_tab (browser))
         _action_set_sensitive (browser, "ZoomNormal",
-            webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view)) != 1.0);
-}
-
-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_icon_ready_cb (MidoriWebView* web_view,
-                               GdkPixbuf*     icon,
-                               MidoriBrowser* browser)
-{
-    const gchar* uri;
-    GtkAction* action;
-
-    uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view));
-    action = _action_by_name (browser, "Location");
-    midori_location_action_set_icon_for_uri (
-        MIDORI_LOCATION_ACTION (action), icon, uri);
+            midori_view_get_zoom_level (MIDORI_VIEW (view)) != 1.0);
 }
 
 static void
-midori_web_view_news_feed_ready_cb (MidoriWebView* web_view,
-                                    const gchar*   href,
-                                    const gchar*   type,
-                                    const gchar*   title,
-                                    MidoriBrowser* browser)
-{
-    if (web_view == (MidoriWebView*)midori_browser_get_current_web_view (browser))
-        midori_location_action_set_secondary_icon (MIDORI_LOCATION_ACTION (
-            _action_by_name (browser, "Location")), STOCK_NEWS_FEED);
-}
-
-static gboolean
-midori_web_view_console_message_cb (GtkWidget*     web_view,
-                                    const gchar*   message,
-                                    guint          line,
-                                    const gchar*   source_id,
-                                    MidoriBrowser* browser)
-{
-    midori_console_add (MIDORI_CONSOLE (browser->panel_console),
-                        message, line, source_id);
-    return TRUE;
-}
-
-static gboolean
-midori_web_view_button_press_event_cb (MidoriWebView*  web_view,
-                                       GdkEventButton* event,
-                                       MidoriBrowser*  browser)
+midori_view_notify_statusbar_text_cb (MidoriView*    view,
+                                      GParamSpec*    pspec,
+                                      MidoriBrowser* browser)
 {
-    GdkModifierType state = (GdkModifierType)0;
-    gint x, y;
-    const gchar* link_uri;
-    guint n;
-    gboolean background;
+    gchar* text;
 
-    gdk_window_get_pointer (NULL, &x, &y, &state);
-    link_uri = midori_web_view_get_link_uri (web_view);
-
-    switch (event->button)
-    {
-    case 1:
-        if (!link_uri)
-            return FALSE;
-        if (state & GDK_SHIFT_MASK)
-        {
-            /* Open link in new window */
-            g_signal_emit (browser, signals[NEW_WINDOW], 0, link_uri);
-            return TRUE;
-        }
-        else if (state & GDK_MOD1_MASK)
-        {
-            /* Open link in new tab */
-            n = midori_browser_add_uri (browser, link_uri);
-            background = sokoke_object_get_boolean (browser->settings,
-                "open-tabs-in-the-background");
-            if (state & GDK_CONTROL_MASK)
-                background = !background;
-            if (!background)
-                midori_browser_set_current_page (browser, n);
-            return TRUE;
-        }
-        break;
-    case 2:
-        if (link_uri)
-        {
-            /* Open link in new tab */
-            n = midori_browser_add_uri (browser, link_uri);
-            background = sokoke_object_get_boolean (browser->settings,
-                "open-tabs-in-the-background");
-            if (state & GDK_CONTROL_MASK)
-                background = !background;
-            if (!background)
-                midori_browser_set_current_page (browser, n);
-            return TRUE;
-        }
-        else if (state & GDK_CONTROL_MASK)
-        {
-            webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), 1.0);
-            return FALSE; /* Allow Ctrl + Middle click */
-        }
-        break;
-    case 3:
-        return FALSE;
-    }
-    return FALSE;
+    g_object_get (view, "statusbar-text", &text, NULL);
+    _midori_browser_set_statusbar_text (browser, text);
+    g_free (text);
 }
 
 static void
@@ -607,12 +474,12 @@ midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,
 
     if (new_bookmark)
     {
-        GtkWidget* widget = midori_browser_get_current_tab (browser);
+        GtkWidget* view = midori_browser_get_current_tab (browser);
         bookmark = katze_xbel_bookmark_new ();
         katze_xbel_item_set_title (bookmark,
-            _midori_browser_get_tab_title (browser, widget));
+            midori_view_get_display_title (MIDORI_VIEW (view)));
         katze_xbel_bookmark_set_href (bookmark,
-            _midori_browser_get_tab_uri (browser, widget));
+            midori_view_get_display_uri (MIDORI_VIEW (view)));
     }
 
     GtkWidget* hbox = gtk_hbox_new (FALSE, 8);
@@ -707,74 +574,19 @@ midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,
 }
 
 static void
-midori_web_view_bookmark_add_cb (GtkWidget* menuitem,
-                                 GtkWidget* web_view)
+midori_view_add_bookmark_cb (GtkWidget*   menuitem,
+                             const gchar* uri,
+                             GtkWidget*   view)
 {
-    const gchar* uri;
     KatzeXbelItem* xbel_item;
     MidoriBrowser* browser;
 
-    uri = midori_web_view_get_link_uri (MIDORI_WEB_VIEW (web_view));
     xbel_item = katze_xbel_bookmark_new ();
     katze_xbel_bookmark_set_href (xbel_item, uri);
     browser = (MidoriBrowser*)gtk_widget_get_toplevel (menuitem);
     midori_browser_edit_bookmark_dialog_new (browser, xbel_item);
 }
 
-static void
-midori_web_view_populate_popup_cb (GtkWidget*     web_view,
-                                   GtkWidget*     menu,
-                                   MidoriBrowser* browser)
-{
-    gboolean has_selection;
-    const gchar* uri;
-    GtkAction* action;
-    GtkWidget* menuitem;
-
-    if (MIDORI_IS_WEB_VIEW (web_view)
-        && midori_web_view_has_selection (MIDORI_WEB_VIEW (web_view)))
-        has_selection = TRUE;
-    else
-        has_selection = FALSE;
-
-    uri = midori_web_view_get_link_uri (MIDORI_WEB_VIEW (web_view));
-    if (uri)
-    {
-        action = _action_by_name (browser, "BookmarkAdd");
-        menuitem = sokoke_action_create_popup_menu_item (action);
-        g_signal_connect (menuitem, "activate",
-            G_CALLBACK (midori_web_view_bookmark_add_cb), web_view);
-        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-    }
-
-    if (has_selection)
-    {
-        /* TODO: view selection source */
-    }
-
-    if (!uri && !has_selection)
-    {
-        action = _action_by_name (browser, "UndoTabClose");
-        menuitem = sokoke_action_create_popup_menu_item (action);
-        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-        menuitem = gtk_separator_menu_item_new ();
-        gtk_widget_show (menuitem);
-        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-        action = _action_by_name (browser, "BookmarkAdd");
-        menuitem = sokoke_action_create_popup_menu_item (action);
-        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-        action = _action_by_name (browser, "SaveAs");
-        menuitem = sokoke_action_create_popup_menu_item (action);
-        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-        action = _action_by_name (browser, "SourceView");
-        menuitem = sokoke_action_create_popup_menu_item (action);
-        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-        action = _action_by_name (browser, "Print");
-        menuitem = sokoke_action_create_popup_menu_item (action);
-        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-    }
-}
-
 static gboolean
 midori_browser_tab_leave_notify_event_cb (GtkWidget*        widget,
                                           GdkEventCrossing* event,
@@ -785,18 +597,37 @@ midori_browser_tab_leave_notify_event_cb (GtkWidget*        widget,
 }
 
 static void
-midori_web_view_new_tab_cb (GtkWidget*     web_view,
-                            const gchar*   uri,
-                            MidoriBrowser* browser)
+midori_view_activate_action_cb (GtkWidget*     view,
+                                const gchar*   action,
+                                MidoriBrowser* browser)
+{
+    _midori_browser_activate_action (browser, action);
+}
+
+static void
+midori_view_console_message_cb (GtkWidget*     view,
+                                const gchar*   message,
+                                gint           line,
+                                const gchar*   source_id,
+                                MidoriBrowser* browser)
+{
+    midori_console_add (MIDORI_CONSOLE (browser->panel_console),
+                        message, line, source_id);
+}
+
+static void
+midori_view_new_tab_cb (GtkWidget*     view,
+                        const gchar*   uri,
+                        MidoriBrowser* browser)
 {
     gint n = midori_browser_add_uri (browser, uri);
     _midori_browser_set_current_page_smartly (browser, n);
 }
 
 static void
-midori_web_view_new_window_cb (GtkWidget*     web_view,
-                               const gchar*   uri,
-                               MidoriBrowser* browser)
+midori_view_new_window_cb (GtkWidget*     view,
+                           const gchar*   uri,
+                           MidoriBrowser* browser)
 {
     g_signal_emit (browser, signals[NEW_WINDOW], 0, uri);
 }
@@ -805,18 +636,17 @@ static gboolean
 midori_browser_tab_destroy_cb (GtkWidget*     widget,
                                MidoriBrowser* browser)
 {
-    KatzeXbelItem* xbel_item;
+    KatzeItem* item;
     const gchar* uri;
 
-    if (browser->proxy_xbel_array && MIDORI_IS_WEB_VIEW (widget))
+    if (browser->proxy_array && MIDORI_IS_VIEW (widget))
     {
-        xbel_item = midori_web_view_get_proxy_xbel_item (
-            MIDORI_WEB_VIEW (widget));
-        uri = katze_xbel_bookmark_get_href (xbel_item);
+        item = midori_view_get_proxy_item (MIDORI_VIEW (widget));
+        uri = katze_item_get_uri (item);
         if (browser->trash && uri && *uri)
-            katze_array_add_item (browser->trash, xbel_item);
-        katze_array_remove_item (browser->proxy_xbel_array, xbel_item);
-        katze_xbel_item_unref (xbel_item);
+            katze_array_add_item (browser->trash, item);
+        katze_array_remove_item (browser->proxy_array, item);
+        g_object_unref (item);
     }
 
     _midori_browser_update_actions (browser);
@@ -844,243 +674,88 @@ midori_browser_window_menu_item_activate_cb (GtkWidget* menuitem,
     midori_browser_set_current_tab (browser, widget);
 }
 
-static void
-_update_label_size (GtkWidget* label,
-                    gint       size)
-{
-    gint width, height;
-
-    if (size > -1)
-    {
-        sokoke_widget_get_text_size (label, "M", &width, &height);
-        gtk_widget_set_size_request (label, width * size, -1);
-        gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
-    }
-    else
-    {
-        gtk_widget_set_size_request (label, -1, -1);
-        gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_NONE);
-    }
-}
-
-static gboolean
-midori_browser_tab_label_button_release_event (GtkWidget*      tab_label,
-                                               GdkEventButton* event,
-                                               GtkWidget*      widget)
-{
-    if (event->button == 2)
-    {
-        /* Close the widget on middle click */
-        gtk_widget_destroy (widget);
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-static void
-midori_browser_tab_icon_style_set (GtkWidget* tab_icon,
-                                   GtkStyle*  previous_style)
-{
-    GtkSettings* gtk_settings;
-    gint width, height;
-
-    gtk_settings = gtk_widget_get_settings (tab_icon);
-    gtk_icon_size_lookup_for_settings (gtk_settings, GTK_ICON_SIZE_MENU,
-                                       &width, &height);
-    gtk_widget_set_size_request (tab_icon, width + 2, height + 2);
-}
-
-static void
-midori_browser_tab_close_clicked (GtkWidget* tab_close,
-                                  GtkWidget* widget)
-{
-    gtk_widget_destroy (widget);
-}
-
 static void
 _midori_browser_add_tab (MidoriBrowser* browser,
-                         GtkWidget*     widget)
+                         GtkWidget*     view)
 {
-    GtkWidget* scrolled;
-    GtkWidget* child;
-    GObjectClass* gobject_class;
-    GdkPixbuf* icon;
-    GtkWidget* tab_icon;
-    const gchar* title;
-    GtkWidget* tab_title;
+    GtkWidget* tab_label;
     GtkWidget* menuitem;
-    KatzeXbelItem* xbel_item;
-    GtkWidget* event_box;
-    GtkWidget* hbox;
-    GtkWidget* close_button;
-    GtkRcStyle* rcstyle;
-    GtkWidget* image;
+    KatzeItem* item;
     guint n;
 
-    scrolled = gtk_scrolled_window_new (NULL, NULL);
-    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
                                     GTK_POLICY_AUTOMATIC,
                                     GTK_POLICY_AUTOMATIC);
-    GTK_WIDGET_SET_FLAGS (scrolled, GTK_CAN_FOCUS);
-    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
+    GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS);
+    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (view),
                                          GTK_SHADOW_ETCHED_IN);
-    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);
-
-    if (MIDORI_IS_WEB_VIEW (widget))
-    {
-        tab_icon = midori_web_view_get_proxy_tab_icon (MIDORI_WEB_VIEW (widget));
-        tab_title = midori_web_view_get_proxy_tab_title (MIDORI_WEB_VIEW (widget));
-        menuitem = midori_web_view_get_proxy_menu_item (MIDORI_WEB_VIEW (widget));
-
-        if (browser->proxy_xbel_array)
-        {
-            xbel_item = midori_web_view_get_proxy_xbel_item (
-                MIDORI_WEB_VIEW (widget));
-            katze_xbel_item_ref (xbel_item);
-            katze_array_add_item (browser->proxy_xbel_array, xbel_item);
-        }
 
-        g_object_connect (widget,
-                          "signal::window-object-cleared",
-                          midori_web_view_window_object_cleared_cb, browser,
-                          "signal::notify::progress",
-                          midori_web_view_notify_progress_cb, browser,
-                          "signal::notify::mload-status",
-                          midori_web_view_notify_load_status_cb, browser,
-                          "signal::icon-ready",
-                          midori_web_view_icon_ready_cb, browser,
-                          "signal::news-feed-ready",
-                          midori_web_view_news_feed_ready_cb, browser,
-                          "signal::notify::title",
-                          midori_web_view_notify_title_cb, browser,
-                          "signal::notify::zoom-level",
-                          midori_web_view_notify_zoom_level_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::new-tab",
-                          midori_web_view_new_tab_cb, browser,
-                          "signal::new-window",
-                          midori_web_view_new_window_cb, browser,
-                          "signal::button-press-event",
-                          midori_web_view_button_press_event_cb, browser,
-                          "signal::populate-popup",
-                          midori_web_view_populate_popup_cb, browser,
-                          NULL);
-    }
-    else
-    {
-        if (GTK_IS_TEXT_VIEW (widget))
-            icon = gtk_widget_render_icon (widget, GTK_STOCK_EDIT,
-                                           GTK_ICON_SIZE_MENU, NULL);
-        else
-            icon = gtk_widget_render_icon (widget, GTK_STOCK_FILE,
-                                           GTK_ICON_SIZE_MENU, NULL);
-        tab_icon = katze_throbber_new ();
-        katze_throbber_set_static_pixbuf (KATZE_THROBBER (tab_icon), icon);
-        title = _midori_browser_get_tab_title (browser, widget);
-        tab_title = gtk_label_new (title);
-        menuitem = sokoke_image_menu_item_new_ellipsized (title);
-        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem),
-            gtk_image_new_from_pixbuf (icon));
-        g_object_unref (icon);
-
-        if (browser->proxy_xbel_array)
-        {
-            xbel_item = katze_xbel_bookmark_new ();
-            katze_xbel_item_set_title (xbel_item, title);
-            katze_xbel_bookmark_set_href (xbel_item,
-                _midori_browser_get_tab_uri (browser, widget));
-            katze_array_add_item (browser->proxy_xbel_array, xbel_item);
-        }
-    }
-    g_object_set_data (G_OBJECT (widget), "browser-tab-icon", tab_icon);
-    browser->tab_titles = g_list_prepend (browser->tab_titles, tab_title);
+    tab_label = midori_view_get_proxy_tab_label (MIDORI_VIEW (view));
+    menuitem = midori_view_get_proxy_menu_item (MIDORI_VIEW (view));
+
+    if (browser->proxy_array)
+    {
+        item = midori_view_get_proxy_item (MIDORI_VIEW (view));
+        g_object_ref (item);
+        katze_array_add_item (browser->proxy_array, item);
+    }
+
+    g_object_connect (view,
+                      "signal::notify::icon",
+                      midori_view_notify_icon_cb, browser,
+                      "signal::notify::load-status",
+                      midori_view_notify_load_status_cb, browser,
+                      "signal::notify::progress",
+                      midori_view_notify_progress_cb, browser,
+                      /* "signal::news-feed-ready",
+                      midori_view_news_feed_ready_cb, browser, */
+                      "signal::notify::title",
+                      midori_view_notify_title_cb, browser,
+                      "signal::notify::zoom-level",
+                      midori_view_notify_zoom_level_cb, browser,
+                      "signal::notify::statusbar-text",
+                      midori_view_notify_statusbar_text_cb, browser,
+                      "signal::activate-action",
+                      midori_view_activate_action_cb, browser,
+                      "signal::console-message",
+                      midori_view_console_message_cb, browser,
+                      "signal::new-tab",
+                      midori_view_new_tab_cb, browser,
+                      "signal::new-window",
+                      midori_view_new_window_cb, browser,
+                      "signal::add-bookmark",
+                      midori_view_add_bookmark_cb, browser,
+                      NULL);
 
-    g_signal_connect (tab_icon, "style-set",
-        G_CALLBACK (midori_browser_tab_icon_style_set), NULL);
-    g_signal_connect (widget, "leave-notify-event",
+    g_signal_connect (view, "leave-notify-event",
         G_CALLBACK (midori_browser_tab_leave_notify_event_cb), browser);
 
-    event_box = gtk_event_box_new ();
-    gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
-    hbox = gtk_hbox_new (FALSE, 1);
-    gtk_container_border_width (GTK_CONTAINER (hbox), 2);
-    gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (hbox));
-    gtk_misc_set_alignment (GTK_MISC (tab_icon), 0.0, 0.5);
-    gtk_box_pack_start (GTK_BOX (hbox), tab_icon, FALSE, FALSE, 0);
-    gtk_misc_set_alignment (GTK_MISC (tab_title), 0.0, 0.5);
-    /* TODO: make the tab initially look "unvisited" until it's focused */
-    gtk_box_pack_start (GTK_BOX (hbox), tab_title, FALSE, TRUE, 0);
-    _update_label_size (tab_title,
-        sokoke_object_get_int (browser->settings, "tab-label-size"));
-
-    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);
-    rcstyle = gtk_rc_style_new ();
-    rcstyle->xthickness = rcstyle->ythickness = 0;
-    gtk_widget_modify_style (close_button, rcstyle);
-    g_object_unref (rcstyle);
-    image = katze_throbber_new ();
-    katze_throbber_set_static_stock_id (KATZE_THROBBER (image), GTK_STOCK_CLOSE);
-    gtk_button_set_image (GTK_BUTTON (close_button), image);
-    gtk_misc_set_alignment (GTK_MISC (image), 0.0, 0.0);
-    gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
-    gtk_widget_show_all (GTK_WIDGET (event_box));
-    if (!sokoke_object_get_boolean (browser->settings, "close-buttons-on-tabs"))
-        gtk_widget_hide (close_button);
-    browser->close_buttons = g_list_prepend (browser->close_buttons, close_button);
-
-    g_signal_connect (event_box, "button-release-event",
-        G_CALLBACK (midori_browser_tab_label_button_release_event), widget);
-    g_signal_connect (close_button, "style-set",
-        G_CALLBACK (midori_browser_tab_icon_style_set), NULL);
-    g_signal_connect (close_button, "clicked",
-        G_CALLBACK (midori_browser_tab_close_clicked), widget);
-
     if (sokoke_object_get_boolean (browser->settings, "open-tabs-next-to-current"))
     {
         n = gtk_notebook_get_current_page (GTK_NOTEBOOK (browser->notebook));
-        gtk_notebook_insert_page (GTK_NOTEBOOK (browser->notebook), scrolled,
-                                  event_box, n + 1);
+        gtk_notebook_insert_page (GTK_NOTEBOOK (browser->notebook), view,
+                                  tab_label, n + 1);
     }
     else
-        gtk_notebook_append_page (GTK_NOTEBOOK (browser->notebook), scrolled,
-                                  event_box);
+        gtk_notebook_append_page (GTK_NOTEBOOK (browser->notebook), view,
+                                  tab_label);
 
     #if GTK_CHECK_VERSION(2, 10, 0)
     gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (browser->notebook),
-                                      scrolled, TRUE);
+                                      view, TRUE);
     gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (browser->notebook),
-                                     scrolled, TRUE);
+                                     view, TRUE);
     #endif
 
     gtk_widget_show (menuitem);
     g_signal_connect (menuitem, "activate",
-        G_CALLBACK (midori_browser_window_menu_item_activate_cb), scrolled);
+        G_CALLBACK (midori_browser_window_menu_item_activate_cb), view);
     gtk_menu_shell_append (GTK_MENU_SHELL (browser->menu_window), menuitem);
 
     /* We want the tab to be removed if the widget is destroyed */
-    g_signal_connect_swapped (widget, "destroy",
+    g_signal_connect_swapped (view, "destroy",
         G_CALLBACK (gtk_widget_destroy), menuitem);
-    g_signal_connect_swapped (widget, "destroy",
-        G_CALLBACK (gtk_widget_destroy), scrolled);
-    g_signal_connect (widget, "destroy",
+    g_signal_connect (view, "destroy",
         G_CALLBACK (midori_browser_tab_destroy_cb), browser);
 
     _midori_browser_update_actions (browser);
@@ -1088,20 +763,9 @@ _midori_browser_add_tab (MidoriBrowser* browser,
 
 static void
 _midori_browser_remove_tab (MidoriBrowser* browser,
-                            GtkWidget*     widget)
-{
-    gtk_widget_destroy (widget);
-}
-
-static void
-_midori_browser_activate_action (MidoriBrowser* browser,
-                                 const gchar*   name)
+                            GtkWidget*     view)
 {
-    GtkAction* action = _action_by_name (browser, name);
-    if (action)
-        gtk_action_activate (action);
-    else
-        g_warning (_("Unexpected action '%s'."), name);
+    gtk_widget_destroy (view);
 }
 
 static void
@@ -1165,17 +829,6 @@ midori_browser_class_init (MidoriBrowserClass* class)
         G_TYPE_POINTER,
         G_TYPE_POINTER);
 
-    signals[ELEMENT_MOTION] = g_signal_new (
-        "element-motion",
-        G_TYPE_FROM_CLASS (class),
-        (GSignalFlags)(G_SIGNAL_RUN_LAST),
-        G_STRUCT_OFFSET (MidoriBrowserClass, element_motion),
-        0,
-        NULL,
-        g_cclosure_marshal_VOID__STRING,
-        G_TYPE_NONE, 1,
-        G_TYPE_STRING);
-
     signals[NEW_WINDOW] = g_signal_new (
         "new-window",
         G_TYPE_FROM_CLASS (class),
@@ -1415,9 +1068,9 @@ _action_open_activate (GtkAction*     action,
      gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_OPEN);
      gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (browser));
 
-     /* base the start folder on the current web view's uri if it is local */
-     GtkWidget* widget = midori_browser_get_current_tab (browser);
-     if ((uri = (gchar*)_midori_browser_get_tab_uri (browser, widget)))
+     /* base the start folder on the current view's uri if it is local */
+     GtkWidget* view = midori_browser_get_current_tab (browser);
+     if ((uri = (gchar*)midori_view_get_display_uri (MIDORI_VIEW (view))))
      {
          gchar* filename = g_filename_from_uri (uri, NULL, NULL);
          if (filename)
@@ -1469,9 +1122,9 @@ static void
 _action_print_activate (GtkAction*     action,
                         MidoriBrowser* browser)
 {
-    GtkWidget* web_view = midori_browser_get_current_tab (browser);
-    if (web_view)
-        webkit_web_view_execute_script (WEBKIT_WEB_VIEW (web_view), "print ();");
+    GtkWidget* view = midori_browser_get_current_tab (browser);
+    if (view)
+        midori_view_print (MIDORI_VIEW (view));
 }
 
 static void
@@ -1489,12 +1142,12 @@ _action_edit_activate (GtkAction*     action,
     gboolean can_cut = FALSE, can_copy = FALSE, can_paste = FALSE;
     gboolean has_selection, can_select_all = FALSE;
 
-    if (WEBKIT_IS_WEB_VIEW (widget))
+    if (MIDORI_IS_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);
+        MidoriView* view = MIDORI_VIEW (widget);
+        can_cut = midori_view_can_cut_clipboard (view);
+        can_copy = midori_view_can_copy_clipboard (view);
+        can_paste = midori_view_can_paste_clipboard (view);
         can_select_all = TRUE;
     }
     else if (GTK_IS_EDITABLE (widget))
@@ -1725,10 +1378,12 @@ static void
 midori_browser_menu_trash_item_activate_cb (GtkWidget*     menuitem,
                                             MidoriBrowser* browser)
 {
+    KatzeItem* item;
+    gint n;
+
     /* Create a new web view with an uri which has been closed before */
-    KatzeXbelItem* item = g_object_get_data (G_OBJECT (menuitem),
-                                             "KatzeXbelItem");
-    gint n = midori_browser_add_xbel_item (browser, item);
+    item = g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
+    n = midori_browser_add_item (browser, item);
     midori_browser_set_current_page (browser, n);
     katze_array_remove_item (browser->trash, item);
     _midori_browser_update_actions (browser);
@@ -1740,7 +1395,7 @@ midori_browser_menu_trash_activate_cb (GtkWidget*     widget,
 {
     GtkWidget* menu;
     guint i, n;
-    KatzeXbelItem* item;
+    KatzeItem* item;
     const gchar* title;
     const gchar* uri;
     GtkWidget* menuitem;
@@ -1752,14 +1407,14 @@ midori_browser_menu_trash_activate_cb (GtkWidget*     widget,
     for (i = 0; i < n; i++)
     {
         item = katze_array_get_nth_item (browser->trash, i);
-        title = katze_xbel_item_get_title (item);
-        uri = katze_xbel_bookmark_get_href (item);
+        title = katze_item_get_name (item);
+        uri = katze_item_get_uri (item);
         menuitem = sokoke_image_menu_item_new_ellipsized (title ? title : uri);
         /* FIXME: Get the real icon */
         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_object_set_data (G_OBJECT (menuitem), "KatzeItem", item);
         g_signal_connect (menuitem, "activate",
             G_CALLBACK (midori_browser_menu_trash_item_activate_cb), browser);
         gtk_widget_show (menuitem);
@@ -1830,19 +1485,23 @@ _action_reload_stop_activate (GtkAction*     action,
                               MidoriBrowser* browser)
 {
     gchar* stock_id;
+    GtkWidget* view;
+    GdkModifierType state = (GdkModifierType)0;
+    gint x, y;
+    gboolean from_cache;
+
     g_object_get (action, "stock-id", &stock_id, NULL);
-    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
+    view = midori_browser_get_current_tab (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));
+        from_cache = state & GDK_SHIFT_MASK;
+        midori_view_reload (MIDORI_VIEW (view), !from_cache);
     }
     else
-        webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view));
+        midori_view_stop_loading (MIDORI_VIEW (view));
     g_free (stock_id);
 }
 
@@ -1850,139 +1509,50 @@ static void
 _action_zoom_in_activate (GtkAction*     action,
                           MidoriBrowser* browser)
 {
-    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
-    if (web_view)
-        webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view));
+    GtkWidget* view = midori_browser_get_current_tab (browser);
+    if (view)
+        midori_view_set_zoom_level (MIDORI_VIEW (view),
+            midori_view_get_zoom_level (MIDORI_VIEW (view)) + 0.25f);
 }
 
 static void
 _action_zoom_out_activate (GtkAction*     action,
                            MidoriBrowser* browser)
 {
-    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
-    if (web_view)
-        webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view));
+    GtkWidget* view = midori_browser_get_current_tab (browser);
+    if (view)
+        midori_view_set_zoom_level (MIDORI_VIEW (view),
+            midori_view_get_zoom_level (MIDORI_VIEW (view)) - 0.25f);
 }
 
 static void
 _action_zoom_normal_activate (GtkAction*     action,
                               MidoriBrowser* browser)
 {
-    GtkWidget* web_view = midori_browser_get_current_web_view (browser);
-    if (web_view)
-        webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), 1.0);
+    GtkWidget* view = midori_browser_get_current_tab (browser);
+    if (view)
+        midori_view_set_zoom_level (MIDORI_VIEW (view), 1.0f);
 }
 
 static void
 _action_source_view_activate (GtkAction*     action,
                               MidoriBrowser* browser)
 {
-    GtkWidget* web_view;
-    const gchar* uri;
-    #if HAVE_GIO
-    GFile* file;
-    gchar* tag;
-    #if HAVE_GTKSOURCEVIEW
-    GFileInfo* info;
-    const gchar* content_type;
-    #endif
-    #endif
-    gchar* contents;
-    gchar* contents_utf8;
-    #if HAVE_GTKSOURCEVIEW
-    GtkSourceBuffer* buffer;
-    #if HAVE_GIO
-    GtkSourceLanguageManager* language_manager;
-    GtkSourceLanguage* language;
-    #endif
-    #else
-    GtkTextBuffer* buffer;
-    #endif
-    GtkWidget* text_view;
+    GtkWidget* view;
+    GtkWidget* source_view;
+    gchar* uri;
     gint n;
 
-    if (!(web_view = midori_browser_get_current_web_view (browser)))
+    if (!(view = midori_browser_get_current_tab (browser)))
         return;
 
-    uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view));
-
-    contents = NULL;
-
-    #if HAVE_GIO
-    file = g_file_new_for_uri (uri);
-    tag = NULL;
-    #if HAVE_GTKSOURCEVIEW
-    content_type = NULL;
-    #endif
-    if (g_file_load_contents (file, NULL, &contents, NULL, &tag, NULL))
-    {
-        #if HAVE_GTKSOURCEVIEW
-        info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
-                                  G_FILE_QUERY_INFO_NONE, NULL, NULL);
-        content_type = g_file_info_get_content_type (info);
-        #endif
-        g_object_unref (file);
-    }
-    if (contents && !g_utf8_validate (contents, -1, NULL))
-    {
-        contents_utf8 = g_convert (contents, -1, "UTF-8", "ISO-8859-1",
-                                   NULL, NULL, NULL);
-        g_free (contents);
-    }
-    else
-    #endif
-        contents_utf8 = contents;
-
-    #if HAVE_GTKSOURCEVIEW
-    buffer = gtk_source_buffer_new (NULL);
-    gtk_source_buffer_set_highlight_syntax (buffer, TRUE);
-    #if HAVE_GIO
-    if (content_type)
-    {
-        language_manager = gtk_source_language_manager_get_default ();
-        if (!strcmp (content_type, "text/html"))
-        {
-            language = gtk_source_language_manager_get_language (
-                language_manager, "html");
-            gtk_source_buffer_set_language (buffer, language);
-        }
-        else if (!strcmp (content_type, "text/css"))
-        {
-            language = gtk_source_language_manager_get_language (
-                language_manager, "css");
-            gtk_source_buffer_set_language (buffer, language);
-        }
-        else if (!strcmp (content_type, "text/javascript"))
-        {
-            language = gtk_source_language_manager_get_language (
-                language_manager, "js");
-            gtk_source_buffer_set_language (buffer, language);
-        }
-    }
-    #endif
-    #else
-    buffer = gtk_text_buffer_new (NULL);
-    #endif
-    if (contents_utf8)
-        gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), contents_utf8, -1);
-    #if HAVE_GTKSOURCEVIEW
-    text_view = gtk_source_view_new_with_buffer (buffer);
-    gtk_source_view_set_show_line_numbers (GTK_SOURCE_VIEW (text_view), TRUE);
-    #else
-    text_view = gtk_text_view_new_with_buffer (buffer);
-    #endif
-    gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
-    g_object_set_data (G_OBJECT (text_view), "browser-tab-uri",
-        g_strconcat ("view-source:", uri, NULL));
-    gtk_widget_show (text_view);
-    n = midori_browser_add_tab (browser, text_view);
+    uri = g_strdup_printf ("view-source:%s",
+        midori_view_get_display_uri (MIDORI_VIEW (view)));
+    source_view = midori_view_new_with_uri (uri);
+    g_free (uri);
+    gtk_widget_show (source_view);
+    n = midori_browser_add_tab (browser, source_view);
     midori_browser_set_current_page (browser, n);
-
-    g_object_unref (buffer);
-    g_free (contents_utf8);
-    #if HAVE_GIO
-    g_free (tag);
-    #endif
 }
 
 static void
@@ -2000,16 +1570,18 @@ 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));
+    GtkWidget* view = midori_browser_get_current_tab (browser);
+    if (view)
+        midori_view_go_back (MIDORI_VIEW (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));
+    GtkWidget* view = midori_browser_get_current_tab (browser);
+    if (view)
+        midori_view_go_forward (MIDORI_VIEW (view));
 }
 
 static void
@@ -2060,8 +1632,7 @@ _action_location_reset_uri (GtkAction*     action,
 {
     const gchar* uri;
 
-    uri = _midori_browser_get_tab_uri (browser,
-        midori_browser_get_current_tab (browser));
+    uri = midori_browser_get_current_uri (browser);
     midori_location_action_set_uri (MIDORI_LOCATION_ACTION (action), uri);
 }
 
@@ -2109,7 +1680,7 @@ _action_location_secondary_icon_released (GtkAction*     action,
                                           GtkWidget*     widget,
                                           MidoriBrowser* browser)
 {
-    MidoriWebView* web_view;
+    MidoriView* view;
     KatzeArray* news_feeds;
     GtkWidget* menu;
     guint n, i;
@@ -2118,10 +1689,10 @@ _action_location_secondary_icon_released (GtkAction*     action,
     const gchar* title;
     GtkWidget* menuitem;
 
-    web_view = (MidoriWebView*)midori_browser_get_current_web_view (browser);
-    if (web_view)
+    view = (MidoriView*)midori_browser_get_current_tab (browser);
+    if (view)
     {
-        news_feeds = midori_web_view_get_news_feeds (web_view);
+        news_feeds = NULL /* midori_view_get_news_feeds (view) */;
         n = news_feeds ? katze_array_get_length (news_feeds) : 0;
         if (n)
         {
@@ -2565,15 +2136,19 @@ static void
 _action_open_in_panel_activate (GtkAction*     action,
                                 MidoriBrowser* browser)
 {
-    GtkWidget* widget = midori_browser_get_current_tab (browser);
-    const gchar* uri = _midori_browser_get_tab_uri (browser, widget);
+    GtkWidget* view;
+    const gchar* uri;
+    gint n;
+
+    view = midori_browser_get_current_tab (browser);
+    uri = midori_view_get_display_uri (MIDORI_VIEW (view));
     /* FIXME: Don't assign the uri here, update it properly while navigating */
     g_object_set (browser->settings, "last-pageholder-uri", uri, NULL);
-    gint n = midori_panel_page_num (MIDORI_PANEL (browser->panel),
-                                    browser->panel_pageholder);
+    n = midori_panel_page_num (MIDORI_PANEL (browser->panel),
+                               browser->panel_pageholder);
     midori_panel_set_current_page (MIDORI_PANEL (browser->panel), n);
     gtk_widget_show (browser->panel);
-    g_object_set (browser->panel_pageholder, "uri", uri, NULL);
+    midori_view_set_uri (MIDORI_VIEW (browser->panel_pageholder), uri);
 }
 
 
@@ -2600,18 +2175,18 @@ gtk_notebook_switch_page_cb (GtkWidget*       notebook,
                              guint            page_num,
                              MidoriBrowser*   browser)
 {
-    GtkWidget* widget;
+    GtkWidget* view;
     const gchar* uri;
     GtkAction* action;
     const gchar* title;
     gchar* window_title;
 
-    widget = midori_browser_get_current_tab (browser);
-    uri = _midori_browser_get_tab_uri (browser, widget);
+    view = midori_browser_get_current_tab (browser);
+    uri = midori_view_get_display_uri (MIDORI_VIEW (view));
     action = _action_by_name (browser, "Location");
     midori_location_action_set_uri (MIDORI_LOCATION_ACTION (action), uri);
 
-    title = _midori_browser_get_tab_title (browser, widget);
+    title = midori_view_get_display_title (MIDORI_VIEW (view));
     window_title = g_strconcat (title, " - ",
                                 g_get_application_name (), NULL);
     gtk_window_set_title (GTK_WINDOW (browser), window_title);
@@ -2621,8 +2196,7 @@ gtk_notebook_switch_page_cb (GtkWidget*       notebook,
 
     _midori_browser_set_statusbar_text (browser, NULL);
     _midori_browser_update_interface (browser);
-    if (MIDORI_IS_WEB_VIEW (widget))
-        _midori_browser_update_progress (browser, MIDORI_WEB_VIEW (widget));
+    _midori_browser_update_progress (browser, MIDORI_VIEW (view));
 }
 
 static void
@@ -2639,8 +2213,8 @@ _action_bookmark_open_activate (GtkAction*     action,
     {
         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);
+            _midori_browser_open_uri (browser,
+                katze_xbel_bookmark_get_href (item));
     }
 }
 
@@ -2711,13 +2285,13 @@ _action_undo_tab_close_activate (GtkAction*     action,
                                  MidoriBrowser* browser)
 {
     guint last;
-    KatzeXbelItem* item;
+    KatzeItem* item;
     guint n;
 
     /* Reopen the most recent trash item */
     last = katze_array_get_length (browser->trash) - 1;
     item = katze_array_get_nth_item (browser->trash, last);
-    n = midori_browser_add_xbel_item (browser, item);
+    n = midori_browser_add_item (browser, item);
     midori_browser_set_current_page (browser, n);
     katze_array_remove_item (browser->trash, item);
     _midori_browser_update_actions (browser);
@@ -3474,7 +3048,7 @@ midori_browser_init (MidoriBrowser* browser)
                               STOCK_BOOKMARKS, _("Bookmarks"));
 
     /* Transfers */
-    GtkWidget* panel = midori_web_view_new ();
+    GtkWidget* panel = midori_view_new ();
     gtk_widget_show (panel);
     midori_panel_append_page (MIDORI_PANEL (browser->panel),
                               panel, NULL,
@@ -3490,16 +3064,14 @@ midori_browser_init (MidoriBrowser* browser)
                               STOCK_CONSOLE, _("Console"));
 
     /* History */
-    panel = midori_web_view_new ();
+    panel = midori_view_new ();
     gtk_widget_show (panel);
     midori_panel_append_page (MIDORI_PANEL (browser->panel),
                               panel, NULL,
                               STOCK_HISTORY, _("History"));
 
     /* Pageholder */
-    browser->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW,
-                                           "uri", "",
-                                           NULL);
+    browser->panel_pageholder = midori_view_new ();
     gtk_widget_show (browser->panel_pageholder);
     midori_panel_append_page (MIDORI_PANEL (browser->panel),
                               browser->panel_pageholder, NULL,
@@ -3531,7 +3103,7 @@ midori_browser_init (MidoriBrowser* browser)
                               panel, toolbar,
                               STOCK_EXTENSIONS, _("Extensions"));
 
-    /* Notebook, containing all web_views */
+    /* Notebook, containing all views */
     browser->notebook = gtk_notebook_new ();
     /* Remove the inner border between scrollbars and the window border */
     rcstyle = gtk_rc_style_new ();
@@ -3635,9 +3207,6 @@ midori_browser_init (MidoriBrowser* browser)
     _action_set_sensitive (browser, "ZoomIn", FALSE);
     _action_set_sensitive (browser, "ZoomOut", FALSE);
     #endif
-
-    browser->tab_titles = NULL;
-    browser->close_buttons = NULL;
 }
 
 static void
@@ -3646,8 +3215,8 @@ midori_browser_dispose (GObject* object)
     MidoriBrowser* browser = MIDORI_BROWSER (object);
 
     /* We are done, the session mustn't change anymore */
-    if (browser->proxy_xbel_array)
-        katze_object_assign (browser->proxy_xbel_array, NULL);
+    if (browser->proxy_array)
+        katze_object_assign (browser->proxy_array, NULL);
 
     G_OBJECT_CLASS (midori_browser_parent_class)->dispose (object);
 }
@@ -3658,8 +3227,6 @@ midori_browser_finalize (GObject* object)
     MidoriBrowser* browser = MIDORI_BROWSER (object);
 
     g_free (browser->statusbar_text);
-    g_list_free (browser->tab_titles);
-    g_list_free (browser->close_buttons);
 
     if (browser->settings)
         g_object_unref (browser->settings);
@@ -3719,8 +3286,6 @@ _midori_browser_update_settings (MidoriBrowser* browser)
     gint tab_label_size;
     gboolean close_buttons_on_tabs;
 
-    guint i, n;
-
     g_object_get (browser->settings,
                   "remember-last-window-size", &remember_last_window_size,
                   "last-window-width", &last_window_width,
@@ -3770,7 +3335,8 @@ _midori_browser_update_settings (MidoriBrowser* browser)
     gtk_paned_set_position (GTK_PANED (gtk_widget_get_parent (browser->panel)),
                             last_panel_position);
     midori_panel_set_current_page (MIDORI_PANEL (browser->panel), last_panel_page);
-    g_object_set (browser->panel_pageholder, "uri", last_pageholder_uri, NULL);
+    midori_view_set_uri (MIDORI_VIEW (browser->panel_pageholder),
+                         last_pageholder_uri);
 
     _action_set_active (browser, "Navigationbar", show_navigationbar);
     _action_set_active (browser, "Bookmarkbar", show_bookmarkbar);
@@ -3782,16 +3348,6 @@ _midori_browser_update_settings (MidoriBrowser* browser)
     sokoke_widget_set_visible (browser->search, show_web_search);
     sokoke_widget_set_visible (browser->button_trash, show_trash);
 
-    /* We assume that tab_titles has the same length as close_buttons */
-    n = g_list_length (browser->tab_titles);
-    for (i = 0; i < n; i++)
-    {
-        _update_label_size (g_list_nth_data (browser->tab_titles, i),
-                            tab_label_size);
-        sokoke_widget_set_visible (g_list_nth_data (browser->close_buttons, i),
-                                   close_buttons_on_tabs);
-    }
-
     g_free (last_pageholder_uri);
 }
 
@@ -3802,8 +3358,6 @@ midori_browser_settings_notify (MidoriWebSettings* web_settings,
 {
     const gchar* name;
     GValue value = {0, };
-    guint i;
-    guint n;
 
     name = g_intern_string (pspec->name);
     g_value_init (&value, pspec->value_type);
@@ -3823,20 +3377,6 @@ midori_browser_settings_notify (MidoriWebSettings* web_settings,
     else if (name == g_intern_string ("show-trash"))
         sokoke_widget_set_visible (browser->button_trash,
             g_value_get_boolean (&value));
-    else if (name == g_intern_string ("tab-label-size"))
-    {
-        n = g_list_length (browser->tab_titles);
-        for (i = 0; i < n; i++)
-            _update_label_size (g_list_nth_data (browser->tab_titles, i),
-                                g_value_get_int (&value));
-    }
-    else if (name == g_intern_string ("close-buttons-on-tabs"))
-    {
-        n = g_list_length (browser->close_buttons);
-        for (i = 0; i < n; i++)
-            sokoke_widget_set_visible (g_list_nth_data (browser->close_buttons, i),
-                                       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);
@@ -3946,11 +3486,8 @@ midori_browser_set_property (GObject*      object,
         _midori_browser_update_settings (browser);
         g_signal_connect (browser->settings, "notify",
                       G_CALLBACK (midori_browser_settings_notify), browser);
-        /* FIXME: Assigning settings must be conditional, if web view or not */
-        /* FIXME: Assign settings only if the same settings object was used */
         gtk_container_foreach (GTK_CONTAINER (browser->notebook),
-                               (GtkCallback) midori_web_view_set_settings,
-                               browser->settings);
+            (GtkCallback) midori_view_set_settings, browser->settings);
         break;
     case PROP_BOOKMARKS:
         ; /* FIXME: Disconnect handlers */
@@ -4056,63 +3593,100 @@ midori_browser_new (void)
 /**
  * midori_browser_add_tab:
  * @browser: a #MidoriBrowser
- * @widget: a tab
+ * @widget: a view
  *
- * Appends an arbitrary widget in the form of a new tab and creates an
+ * Appends a view 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_add_tab (MidoriBrowser* browser,
-                        GtkWidget*     widget)
+                        GtkWidget*     view)
 {
-    GtkWidget* scrolled;
-
-    g_signal_emit (browser, signals[ADD_TAB], 0, widget);
-    scrolled = _midori_browser_scrolled_for_child (browser, widget);
-    return gtk_notebook_page_num (GTK_NOTEBOOK (browser->notebook), scrolled);
+    g_signal_emit (browser, signals[ADD_TAB], 0, view);
+    return gtk_notebook_page_num (GTK_NOTEBOOK (browser->notebook), view);
 }
 
 /**
  * midori_browser_remove_tab:
  * @browser: a #MidoriBrowser
- * @widget: a tab
+ * @widget: a view
  *
- * Removes an existing tab from the browser, including an associated menu item.
+ * Removes an existing view from the browser,
+ * including an associated menu item.
  **/
 void
 midori_browser_remove_tab (MidoriBrowser* browser,
-                           GtkWidget*     widget)
+                           GtkWidget*     view)
 {
-    g_signal_emit (browser, signals[REMOVE_TAB], 0, widget);
+    g_signal_emit (browser, signals[REMOVE_TAB], 0, view);
 }
 
 /**
- * midori_browser_add_xbel_item:
+ * midori_browser_add_item:
  * @browser: a #MidoriBrowser
- * @xbel_item: a bookmark
+ * @xbel_item: an XBEL item
  *
- * Appends a #KatzeXbelItem in the form of a new tab.
+ * Appends a new view as described by @item.
  *
- * Return value: the index of the new tab, or -1 in case of an error
+ * Note: Currently this will always be a #MidoriWebView.
+ *
+ * Return value: the index of the new view, or -1 in case of an error
  **/
 gint
 midori_browser_add_xbel_item (MidoriBrowser* browser,
-                              KatzeXbelItem* xbel_item)
+                              KatzeXbelItem* item)
+{
+    const gchar* uri;
+    const gchar* title;
+    GtkWidget* view;
+
+    g_return_val_if_fail (katze_xbel_item_is_bookmark (item), -1);
+
+    uri = katze_xbel_bookmark_get_href (item);
+    title = katze_xbel_item_get_title (item);
+    view = g_object_new (MIDORI_TYPE_VIEW,
+                         "title", title,
+                         "settings", browser->settings,
+                         NULL);
+    midori_view_set_uri (MIDORI_VIEW (view), uri);
+    gtk_widget_show (view);
+
+    return midori_browser_add_tab (browser, view);
+}
+
+/**
+ * midori_browser_add_item:
+ * @browser: a #MidoriBrowser
+ * @item: an item
+ *
+ * Appends a new view as described by @item.
+ *
+ * Note: Currently this will always be a #MidoriWebView.
+ *
+ * Return value: the index of the new tab, or -1 in case of an error
+ **/
+gint
+midori_browser_add_item (MidoriBrowser* browser,
+                         KatzeItem*     item)
 {
-    g_return_val_if_fail (katze_xbel_item_is_bookmark (xbel_item), -1);
+    const gchar* uri;
+    const gchar* title;
+    GtkWidget* view;
+
+    g_return_val_if_fail (KATZE_IS_ITEM (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", browser->settings,
-                                        NULL);
-    gtk_widget_show (web_view);
+    uri = katze_item_get_uri (item);
+    title = katze_item_get_name (item);
+    view = g_object_new (MIDORI_TYPE_VIEW,
+                         "title", title,
+                         "settings", browser->settings,
+                         NULL);
+    midori_view_set_uri (MIDORI_VIEW (view), uri);
+    gtk_widget_show (view);
 
-    return midori_browser_add_tab (browser, web_view);
+    return midori_browser_add_tab (browser, view);
 }
 
 /**
@@ -4120,23 +3694,25 @@ midori_browser_add_xbel_item (MidoriBrowser* browser,
  * @browser: a #MidoriBrowser
  * @uri: an URI
  *
- * Appends an uri in the form of a new tab.
+ * Appends an uri in the form of a new view.
  *
- * Return value: the index of the new tab, or -1
+ * Note: Currently this will always be a #MidoriView.
+ *
+ * Return value: the index of the new view, or -1
  **/
 gint
 midori_browser_add_uri (MidoriBrowser* browser,
                         const gchar*   uri)
 {
-    GtkWidget* web_view;
+    GtkWidget* view;
 
-    web_view = g_object_new (MIDORI_TYPE_WEB_VIEW,
-                             "uri", uri,
-                             "settings", browser->settings,
-                             NULL);
-    gtk_widget_show (web_view);
+    view = g_object_new (MIDORI_TYPE_VIEW,
+                         "settings", browser->settings,
+                         NULL);
+    midori_view_set_uri (MIDORI_VIEW (view), uri);
+    gtk_widget_show (view);
 
-    return midori_browser_add_tab (browser, web_view);
+    return midori_browser_add_tab (browser, view);
 }
 
 /**
@@ -4157,21 +3733,21 @@ midori_browser_activate_action (MidoriBrowser* browser,
  * midori_browser_get_current_uri:
  * @browser: a #MidoriBrowser
  *
- * Determines the URI loaded in the current page.
+ * Determines the URI loaded in the current view.
  *
- * If there is no page present at all, %NULL is returned.
+ * If there is no view present at all, %NULL is returned.
  *
  * Return value: the current URI, or %NULL
  **/
 const gchar*
 midori_browser_get_current_uri (MidoriBrowser* browser)
 {
-    GtkWidget* widget;
+    GtkWidget* view;
 
     g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL);
 
-    widget = midori_browser_get_current_web_view (browser);
-    return _midori_browser_get_tab_uri (browser, widget);
+    view = midori_browser_get_current_tab (browser);
+    return midori_view_get_display_uri (MIDORI_VIEW (view));
 }
 
 /**
@@ -4187,13 +3763,14 @@ void
 midori_browser_set_current_page (MidoriBrowser* browser,
                                  gint           n)
 {
+    GtkWidget* view;
+
     gtk_notebook_set_current_page (GTK_NOTEBOOK (browser->notebook), n);
-    GtkWidget* scrolled = gtk_notebook_get_nth_page (GTK_NOTEBOOK (browser->notebook), n);
-    GtkWidget* widget = _midori_browser_child_for_scrolled (browser, scrolled);
-    if (widget && !strcmp (_midori_browser_get_tab_uri (browser, widget), ""))
+    view = gtk_notebook_get_nth_page (GTK_NOTEBOOK (browser->notebook), n);
+    if (view && midori_view_is_blank (MIDORI_VIEW (view)))
         gtk_action_activate (_action_by_name (browser, "Location"));
     else
-        gtk_widget_grab_focus (widget);
+        gtk_widget_grab_focus (view);
 }
 
 /**
@@ -4217,23 +3794,27 @@ midori_browser_get_current_page (MidoriBrowser* browser)
 /**
  * midori_browser_set_current_tab:
  * @browser: a #MidoriBrowser
- * @widget: a #GtkWidget
+ * @view: a #GtkWidget
  *
- * Switches to the page containing @widget.
+ * Switches to the page containing @view.
  *
  * The widget will also grab the focus automatically.
  **/
 void
 midori_browser_set_current_tab (MidoriBrowser* browser,
-                                GtkWidget*     widget)
+                                GtkWidget*     view)
 {
-    GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, widget);
-    gint n = gtk_notebook_page_num (GTK_NOTEBOOK (browser->notebook), scrolled);
+    gint n;
+
+    g_return_if_fail (MIDORI_IS_BROWSER (browser));
+    g_return_if_fail (GTK_IS_WIDGET (view));
+
+    n = gtk_notebook_page_num (GTK_NOTEBOOK (browser->notebook), view);
     gtk_notebook_set_current_page (GTK_NOTEBOOK (browser->notebook), n);
-    if (widget && !strcmp (_midori_browser_get_tab_uri (browser, widget), ""))
+    if (view && midori_view_is_blank (MIDORI_VIEW (view)))
         gtk_action_activate (_action_by_name (browser, "Location"));
     else
-        gtk_widget_grab_focus (widget);
+        gtk_widget_grab_focus (view);
 }
 
 /**
@@ -4244,57 +3825,37 @@ midori_browser_set_current_tab (MidoriBrowser* browser,
  *
  * If there is no tab present at all, %NULL is returned.
  *
+ * See also midori_browser_get_current_page().
+ *
  * Return value: the selected tab, or %NULL
  **/
 GtkWidget*
 midori_browser_get_current_tab (MidoriBrowser* browser)
 {
+    gint n;
+
     g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL);
 
-    gint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (browser->notebook));
+    n = gtk_notebook_get_current_page (GTK_NOTEBOOK (browser->notebook));
     if (n >= 0)
     {
-        GtkWidget* widget = _midori_browser_child_for_scrolled (browser,
-            gtk_notebook_get_nth_page (GTK_NOTEBOOK (browser->notebook), n));
-        return widget;
+        return gtk_notebook_get_nth_page (GTK_NOTEBOOK (browser->notebook), n);
     }
     else
         return NULL;
 }
 
 /**
- * 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_tab (browser);
-    return MIDORI_IS_WEB_VIEW (web_view) ? web_view : NULL;
-}
-
-/**
- * midori_browser_get_proxy_xbel_array:
+ * midori_browser_get_proxy_array:
  * @browser: a #MidoriBrowser
  *
- * Retrieves a proxy xbel array representing the respective proxy xbel items
- * of the present web views that can be used for session management.
+ * Retrieves a proxy array representing the respective proxy items
+ * of the present 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.
+ * Note that this implicitly creates proxy items of all views.
  *
  * Note: Calling this function doesn't add a reference and the browser
  *       may release its reference at some point.
@@ -4302,16 +3863,16 @@ midori_browser_get_current_web_view (MidoriBrowser* browser)
  * Return value: the proxy #KatzeArray
  **/
 KatzeArray*
-midori_browser_get_proxy_xbel_array (MidoriBrowser* browser)
+midori_browser_get_proxy_array (MidoriBrowser* browser)
 {
     g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL);
 
-    if (!browser->proxy_xbel_array)
+    if (!browser->proxy_array)
     {
-        browser->proxy_xbel_array = katze_array_new (KATZE_TYPE_XBEL_ITEM);
-        /* FIXME: Fill in xbel items of all present web views */
+        browser->proxy_array = katze_array_new (KATZE_TYPE_ITEM);
+        /* FIXME: Fill in items of all present views */
     }
-    return browser->proxy_xbel_array;
+    return browser->proxy_array;
 }
 
 /**
index 42bff3f54e43bbada1e24b351bc728ca087acdb6..1a79087fb4955b3a397d5f14718a018f9d20effe 100644 (file)
@@ -56,10 +56,10 @@ struct _MidoriBrowserClass
 
     void
     (*add_tab)                 (MidoriBrowser*       browser,
-                                GtkWidget*           widget);
+                                GtkWidget*           view);
     void
     (*remove_tab)              (MidoriBrowser*       browser,
-                                GtkWidget*           widget);
+                                GtkWidget*           view);
     void
     (*activate_action)         (MidoriBrowser*       browser,
                                 const gchar*         name);
@@ -85,6 +85,10 @@ gint
 midori_browser_add_xbel_item          (MidoriBrowser*     browser,
                                        KatzeXbelItem*     xbel_item);
 
+gint
+midori_browser_add_item               (MidoriBrowser*     browser,
+                                       KatzeItem*         item);
+
 gint
 midori_browser_add_uri                (MidoriBrowser*     browser,
                                        const gchar*       uri);
@@ -110,11 +114,8 @@ midori_browser_set_current_tab        (MidoriBrowser*     browser,
 GtkWidget*
 midori_browser_get_current_tab        (MidoriBrowser*     browser);
 
-GtkWidget*
-midori_browser_get_current_web_view   (MidoriBrowser*     browser);
-
 KatzeArray*
-midori_browser_get_proxy_xbel_array   (MidoriBrowser*     browser);
+midori_browser_get_proxy_array        (MidoriBrowser*     browser);
 
 void
 midori_browser_quit                   (MidoriBrowser*     browser);
index 2e71895d5221acd9bdd24f16f7529b0063dc4e76..10e51b6bfb80cbe4df030d430ae1b5468742be80 100644 (file)
@@ -373,6 +373,10 @@ midori_panel_append_page (MidoriPanel* panel,
     g_return_val_if_fail (stock_id != NULL, -1);
     g_return_val_if_fail (label != NULL, -1);
 
+    if (GTK_IS_SCROLLED_WINDOW (child))
+        scrolled = child;
+    else
+    {
     scrolled = gtk_scrolled_window_new (NULL, NULL);
     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
                                     GTK_POLICY_AUTOMATIC,
@@ -389,6 +393,7 @@ midori_panel_append_page (MidoriPanel* panel,
         gtk_container_add (GTK_CONTAINER (widget), child);
     }
     gtk_container_add (GTK_CONTAINER (scrolled), widget);
+    }
     gtk_container_add (GTK_CONTAINER (panel->notebook), scrolled);
 
     if (!toolbar)
diff --git a/midori/midori-source.c b/midori/midori-source.c
new file mode 100644 (file)
index 0000000..ce3131b
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ 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.
+*/
+
+#if HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include "midori-source.h"
+
+#include <string.h>
+#if HAVE_GIO
+    #include <gio/gio.h>
+#endif
+#include <glib/gi18n.h>
+#if HAVE_GTKSOURCEVIEW
+    #include <gtksourceview/gtksourceview.h>
+    #include <gtksourceview/gtksourcelanguagemanager.h>
+
+    #define MidoriSourceView GtkSourceView
+    #define MidoriSourceViewClass GtkSourceViewClass
+    #define MIDORI_TYPE_SOURCE_VIEW GTK_TYPE_SOURCE_VIEW
+#else
+    #define MidoriSourceView GtkTextView
+    #define MidoriSourceViewClass GtkTextViewClass
+    #define MIDORI_TYPE_SOURCE_VIEW GTK_TYPE_TEXT_VIEW
+#endif
+
+struct _MidoriSource
+{
+    MidoriSourceView parent_instance;
+};
+
+struct _MidoriSourceClass
+{
+    MidoriSourceViewClass parent_class;
+};
+
+G_DEFINE_TYPE (MidoriSource, midori_source, MIDORI_TYPE_SOURCE_VIEW);
+
+static void
+midori_source_finalize (GObject* object);
+
+static void
+midori_source_class_init (MidoriSourceClass* class)
+{
+    GObjectClass* gobject_class;
+
+    gobject_class = G_OBJECT_CLASS (class);
+    gobject_class->finalize = midori_source_finalize;
+}
+
+static void
+midori_source_init (MidoriSource* source)
+{
+    #if HAVE_GTKSOURCEVIEW
+    GtkSourceBuffer* buffer;
+    #else
+    GtkTextBuffer* buffer;
+    #endif
+
+    #if HAVE_GTKSOURCEVIEW
+    buffer = gtk_source_buffer_new (NULL);
+    gtk_source_buffer_set_highlight_syntax (buffer, TRUE);
+    gtk_source_view_set_show_line_numbers (GTK_SOURCE_VIEW (source), TRUE);
+    #else
+    buffer = gtk_text_buffer_new (NULL);
+    #endif
+    gtk_text_view_set_buffer (GTK_TEXT_VIEW (source), GTK_TEXT_BUFFER (buffer));
+    gtk_text_view_set_editable (GTK_TEXT_VIEW (source), FALSE);
+}
+
+static void
+midori_source_finalize (GObject* object)
+{
+    G_OBJECT_CLASS (midori_source_parent_class)->finalize (object);
+}
+
+/**
+ * midori_source_new:
+ * @uri: a view-source: URI
+ *
+ * Creates a new source widget.
+ *
+ * Return value: a new #MidoriSource
+ **/
+GtkWidget*
+midori_source_new (const gchar* uri)
+{
+    MidoriSource* source = g_object_new (MIDORI_TYPE_SOURCE,
+                                         /*"uri", uri,*/
+                                         NULL);
+    midori_source_set_uri (source, uri);
+
+    return GTK_WIDGET (source);
+}
+
+void
+midori_source_set_uri (MidoriSource* source,
+                       const gchar*  uri)
+{
+    #if HAVE_GIO
+    GFile* file;
+    gchar* tag;
+    #if HAVE_GTKSOURCEVIEW
+    GFileInfo* info;
+    const gchar* content_type;
+    #endif
+    #endif
+    gchar* contents;
+    gchar* contents_utf8;
+    GtkTextBuffer* buffer;
+    #if HAVE_GTKSOURCEVIEW
+    #if HAVE_GIO
+    GtkSourceLanguageManager* language_manager;
+    GtkSourceLanguage* language;
+    #endif
+    #endif
+
+    g_return_if_fail (MIDORI_IS_SOURCE (source));
+
+    contents = NULL;
+
+    #if HAVE_GIO
+    file = g_file_new_for_uri (uri);
+    tag = NULL;
+    #if HAVE_GTKSOURCEVIEW
+    content_type = NULL;
+    #endif
+    if (g_file_load_contents (file, NULL, &contents, NULL, &tag, NULL))
+    {
+        #if HAVE_GTKSOURCEVIEW
+        info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                                  G_FILE_QUERY_INFO_NONE, NULL, NULL);
+        content_type = g_file_info_get_content_type (info);
+        #endif
+        g_object_unref (file);
+    }
+    if (contents && !g_utf8_validate (contents, -1, NULL))
+    {
+        contents_utf8 = g_convert (contents, -1, "UTF-8", "ISO-8859-1",
+                                   NULL, NULL, NULL);
+        g_free (contents);
+    }
+    else
+    #endif
+        contents_utf8 = contents;
+
+    buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source));
+    #if HAVE_GTKSOURCEVIEW
+    #if HAVE_GIO
+    if (content_type)
+    {
+        language_manager = gtk_source_language_manager_get_default ();
+        if (!strcmp (content_type, "text/html"))
+        {
+            language = gtk_source_language_manager_get_language (
+                language_manager, "html");
+            gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), language);
+        }
+        else if (!strcmp (content_type, "text/css"))
+        {
+            language = gtk_source_language_manager_get_language (
+                language_manager, "css");
+            gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), language);
+        }
+        else if (!strcmp (content_type, "text/javascript"))
+        {
+            language = gtk_source_language_manager_get_language (
+                language_manager, "js");
+            gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), language);
+        }
+    }
+    #endif
+    #endif
+    if (contents_utf8)
+        gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), contents_utf8, -1);
+
+    g_object_unref (buffer);
+    g_free (contents_utf8);
+    #if HAVE_GIO
+    g_free (tag);
+    #endif
+}
diff --git a/midori/midori-source.h b/midori/midori-source.h
new file mode 100644 (file)
index 0000000..e7b1878
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ 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_SOURCE_H__
+#define __MIDORI_SOURCE_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define MIDORI_TYPE_SOURCE \
+    (midori_source_get_type ())
+#define MIDORI_SOURCE(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_SOURCE, MidoriSource))
+#define MIDORI_SOURCE_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_SOURCE, MidoriSourceClass))
+#define MIDORI_IS_SOURCE(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_SOURCE))
+#define MIDORI_IS_SOURCE_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_SOURCE))
+#define MIDORI_SOURCE_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_SOURCE, MidoriSourceClass))
+
+typedef struct _MidoriSource                MidoriSource;
+typedef struct _MidoriSourceClass           MidoriSourceClass;
+
+GType
+midori_source_get_type            (void);
+
+GtkWidget*
+midori_source_new                 (const gchar*  uri);
+
+void
+midori_source_set_uri             (MidoriSource* source,
+                                   const gchar*  uri);
+
+G_END_DECLS
+
+#endif /* __MIDORI_SOURCE_H__ */
diff --git a/midori/midori-view.c b/midori/midori-view.c
new file mode 100644 (file)
index 0000000..14986c9
--- /dev/null
@@ -0,0 +1,2451 @@
+/*
+ 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.
+*/
+
+#if HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include "midori-view.h"
+#include "midori-source.h"
+
+#include "midori-stock.h"
+
+#include "compat.h"
+#include "sokoke.h"
+#include "gjs.h"
+
+#include <string.h>
+#include <stdlib.h>
+#if HAVE_GIO
+    #include <gio/gio.h>
+#endif
+#include <glib/gi18n.h>
+#include <webkit/webkit.h>
+
+/* This is unstable API, so we need to declare it */
+gchar*
+webkit_web_view_get_selected_text (WebKitWebView* web_view);
+
+struct _MidoriView
+{
+    GtkScrolledWindow parent_instance;
+
+    gint socket_id;
+    GIOChannel* input;
+    FILE* output;
+
+    gchar* command_cache;
+    gchar* premature_uri;
+    gchar* uri;
+    gchar* title;
+    GdkPixbuf* icon;
+    gdouble progress;
+    MidoriLoadStatus load_status;
+    gchar* statusbar_text;
+    gchar* link_uri;
+    gboolean has_selection;
+    gchar* selected_text;
+    gboolean can_cut_clipboard;
+    gboolean can_copy_clipboard;
+    gboolean can_paste_clipboard;
+    gfloat zoom_level;
+    MidoriWebSettings* settings;
+    GtkWidget* web_view;
+    gboolean window_object_cleared;
+
+    gchar* download_manager;
+    gint tab_label_size;
+    gboolean close_buttons_on_tabs;
+
+    GtkWidget* menu_item;
+    GtkWidget* tab_label;
+    GtkWidget* tab_icon;
+    GtkWidget* tab_title;
+    GtkWidget* tab_close;
+    KatzeItem* item;
+};
+
+struct _MidoriViewClass
+{
+    GtkScrolledWindowClass parent_class;
+};
+
+G_DEFINE_TYPE (MidoriView, midori_view, GTK_TYPE_SCROLLED_WINDOW)
+
+GType
+midori_load_status_get_type (void)
+{
+    static GType type = 0;
+    if (!type)
+    {
+        static const GEnumValue values[] = {
+         { MIDORI_LOAD_PROVISIONAL, "MIDORI_LOAD_PROVISIONAL", N_("Load Provisional") },
+         { MIDORI_LOAD_COMMITTED, "MIDORI_LOAD_COMMITTED", N_("Load Committed") },
+         { MIDORI_LOAD_FINISHED, "MIDORI_LOAD_FINISHED", N_("Load Finished") },
+         { 0, NULL, NULL }
+        };
+        type = g_enum_register_static ("MidoriLoadStatus", values);
+    }
+    return type;
+}
+
+enum
+{
+    PROP_0,
+
+    PROP_SOCKET_ID,
+    PROP_URI,
+    PROP_TITLE,
+    PROP_ICON,
+    PROP_LOAD_STATUS,
+    PROP_PROGRESS,
+    PROP_ZOOM_LEVEL,
+    PROP_STATUSBAR_TEXT,
+    PROP_SETTINGS
+};
+
+enum {
+    ACTIVATE_ACTION,
+    CONSOLE_MESSAGE,
+    NEW_TAB,
+    NEW_WINDOW,
+    ADD_BOOKMARK,
+
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+midori_view_finalize (GObject* object);
+
+static void
+midori_view_set_property (GObject*      object,
+                          guint         prop_id,
+                          const GValue* value,
+                          GParamSpec*   pspec);
+
+static void
+midori_view_get_property (GObject*    object,
+                          guint       prop_id,
+                          GValue*     value,
+                          GParamSpec* pspec);
+
+static void
+midori_cclosure_marshal_VOID__STRING_INT_STRING (GClosure*     closure,
+                                                 GValue*       return_value,
+                                                 guint         n_param_values,
+                                                 const GValue* param_values,
+                                                 gpointer      invocation_hint,
+                                                 gpointer      marshal_data)
+{
+    typedef void(*GMarshalFunc_VOID__STRING_INT_STRING) (gpointer  data1,
+                                                         gpointer  arg_1,
+                                                         gint      arg_2,
+                                                         gpointer  arg_3,
+                                                         gpointer  data2);
+    register GMarshalFunc_VOID__STRING_INT_STRING callback;
+    register GCClosure* cc = (GCClosure*) closure;
+    register gpointer data1, data2;
+
+    g_return_if_fail (n_param_values == 4);
+
+    if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+        data1 = closure->data;
+        data2 = g_value_peek_pointer (param_values + 0);
+    }
+    else
+    {
+        data1 = g_value_peek_pointer (param_values + 0);
+        data2 = closure->data;
+    }
+    callback = (GMarshalFunc_VOID__STRING_INT_STRING) (marshal_data
+        ? marshal_data : cc->callback);
+    callback (data1,
+              (gchar*)g_value_get_string (param_values + 1),
+              g_value_get_int (param_values + 2),
+              (gchar*)g_value_get_string (param_values + 3),
+              data2);
+}
+
+static void
+midori_view_class_init (MidoriViewClass* class)
+{
+    GObjectClass* gobject_class;
+    GParamFlags flags;
+
+    signals[ACTIVATE_ACTION] = g_signal_new (
+        "activate-action",
+        G_TYPE_FROM_CLASS (class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        0,
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__STRING,
+        G_TYPE_NONE, 1,
+        G_TYPE_STRING);
+
+    signals[CONSOLE_MESSAGE] = g_signal_new (
+        "console-message",
+        G_TYPE_FROM_CLASS (class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        0,
+        0,
+        NULL,
+        midori_cclosure_marshal_VOID__STRING_INT_STRING,
+        G_TYPE_NONE, 3,
+        G_TYPE_STRING,
+        G_TYPE_INT,
+        G_TYPE_STRING);
+
+    signals[NEW_TAB] = g_signal_new (
+        "new-tab",
+        G_TYPE_FROM_CLASS (class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        0,
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__STRING,
+        G_TYPE_NONE, 1,
+        G_TYPE_STRING);
+
+    signals[NEW_WINDOW] = g_signal_new (
+        "new-window",
+        G_TYPE_FROM_CLASS (class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        0,
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__STRING,
+        G_TYPE_NONE, 1,
+        G_TYPE_STRING);
+
+    signals[ADD_BOOKMARK] = g_signal_new (
+        "add-bookmark",
+        G_TYPE_FROM_CLASS (class),
+        (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+        0,
+        0,
+        NULL,
+        g_cclosure_marshal_VOID__STRING,
+        G_TYPE_NONE, 1,
+        G_TYPE_STRING);
+
+    gobject_class = G_OBJECT_CLASS (class);
+    gobject_class->finalize = midori_view_finalize;
+    gobject_class->set_property = midori_view_set_property;
+    gobject_class->get_property = midori_view_get_property;
+
+    flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_SOCKET_ID,
+                                     g_param_spec_uint (
+                                     "socket-id",
+                                     _("Socket ID"),
+                                     _("The ID of a socket"),
+                                     0,
+                                     G_MAXUINT,
+                                     0,
+                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_URI,
+                                     g_param_spec_string (
+                                     "uri",
+                                     _("Uri"),
+                                     _("The URI of the currently loaded page"),
+                                     "about:blank",
+                                     G_PARAM_READABLE));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_TITLE,
+                                     g_param_spec_string (
+                                     "title",
+                                     _("Title"),
+                                     _("The title of the currently loaded page"),
+                                     NULL,
+                                     G_PARAM_READWRITE));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_ICON,
+                                     g_param_spec_object (
+                                     "icon",
+                                     _("Icon"),
+                                     _("The icon of the view"),
+                                     GDK_TYPE_PIXBUF,
+                                     G_PARAM_READABLE));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_LOAD_STATUS,
+                                     g_param_spec_enum (
+                                     "load-status",
+                                     _("Load Status"),
+                                     _("The current loading status"),
+                                     MIDORI_TYPE_LOAD_STATUS,
+                                     MIDORI_LOAD_FINISHED,
+                                     G_PARAM_READABLE));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_PROGRESS,
+                                     g_param_spec_double (
+                                     "progress",
+                                     _("Progress"),
+                                     _("The current loading progress"),
+                                     0.0, 1.0, 0.0,
+                                     G_PARAM_READABLE));
+
+    g_object_class_install_property (gobject_class,
+                                     PROP_ZOOM_LEVEL,
+                                     g_param_spec_float (
+                                     "zoom-level",
+                                     _("Zoom Level"),
+                                     _("The current zoom level"),
+                                     G_MINFLOAT,
+                                     G_MAXFLOAT,
+                                     1.0f,
+                                     G_PARAM_READWRITE));
+
+    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"),
+                                     "",
+                                     G_PARAM_READWRITE));
+
+    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));
+}
+
+#define midori_view_is_socket(view) !view->socket_id
+#define midori_view_is_plug(view) view->socket_id > 0
+
+#if 0
+    #define midori_debug g_debug
+#else
+    #define midori_debug(...) ;
+#endif
+
+/**
+ * int_to_str
+ * @in: an integer
+ *
+ * Converts an integer to a string.
+ *
+ * The returned string is valid until
+ * the next call to this function.
+ *
+ * Return value: a string
+ **/
+static const gchar*
+int_to_str (gint in)
+{
+    static gchar* out = NULL;
+    g_free (out);
+    out = g_strdup_printf ("%d", in);
+    return out;
+}
+
+/**
+ * float_to_str
+ * @in: a float
+ *
+ * Converts a float to a string.
+ *
+ * The returned string is valid until
+ * the next call to this function.
+ *
+ * Return value: a string
+ **/
+static const gchar*
+float_to_str (gfloat in)
+{
+    static gchar* out = NULL;
+    g_free (out);
+    out = g_strdup_printf ("%f", in);
+    return out;
+}
+
+
+static void
+send_command (MidoriView*  view,
+              const gchar* command,
+              const gchar* argument)
+{
+    gchar* data;
+    gchar* cache;
+
+    if (argument)
+        data = g_strdup_printf ("%s %s", command, argument);
+    else
+        data = g_strdup (command);
+
+    if (!view->output)
+    {
+        /* The output is not ready, so we cache for now */
+        cache = g_strdup_printf ("%s\n%s",
+            view->command_cache ? view->command_cache : "", data);
+        katze_assign (view->command_cache, cache);
+        midori_debug ("!view->output, caching command: %s", command);
+        return;
+    }
+
+    fwrite (data, strlen (data) + 1, 1, view->output);
+    fflush (view->output);
+
+    g_free (data);
+}
+
+static void
+midori_view_notify_uri_cb (MidoriView* view,
+                           GParamSpec  pspec)
+{
+    if (midori_view_is_socket (view) && view->item)
+        katze_item_set_uri (view->item, view->uri);
+
+    if (midori_view_is_plug (view))
+        /* We must not send a NULL string here */
+        send_command (view, "uri", view->uri ? view->uri : "");
+}
+
+static void
+midori_view_notify_icon_cb (MidoriView* view,
+                            GParamSpec  pspec)
+{
+    if (view->tab_icon)
+        katze_throbber_set_static_pixbuf (KATZE_THROBBER (view->tab_icon),
+                                          view->icon);
+    if (view->menu_item)
+        gtk_image_menu_item_set_image (
+            GTK_IMAGE_MENU_ITEM (view->menu_item),
+                gtk_image_new_from_pixbuf (view->icon));
+}
+
+#if HAVE_GIO
+void
+loadable_icon_finish_cb (GdkPixbuf*    icon,
+                         GAsyncResult* res,
+                         MidoriView*   view)
+{
+    GdkPixbuf* pixbuf;
+    GInputStream* stream;
+    GError* error;
+    GdkPixbuf* pixbuf_scaled;
+    gint icon_width, icon_height;
+
+    pixbuf = NULL;
+    stream = g_loadable_icon_load_finish (G_LOADABLE_ICON (icon),
+                                          res, NULL, NULL);
+    if (stream)
+    {
+        error = NULL;
+        pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, &error);
+        if (error)
+            midori_debug ("Icon couldn't be loaded: %s", error->message);
+        g_object_unref (stream);
+    }
+    if (!pixbuf)
+        pixbuf = gtk_widget_render_icon (GTK_WIDGET (view),
+            GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
+
+    gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
+    pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height,
+                                             GDK_INTERP_BILINEAR);
+    g_object_unref (pixbuf);
+    katze_object_assign (view->icon, pixbuf_scaled);
+    g_object_notify (G_OBJECT (view), "icon");
+}
+
+void
+file_info_finish_cb (GFile*        icon_file,
+                     GAsyncResult* res,
+                     MidoriView*   view)
+{
+    GFileInfo* info;
+    const gchar* content_type;
+    GIcon* icon;
+    GFile* parent;
+    GFile* file;
+    GdkPixbuf* pixbuf;
+    gint icon_width, icon_height;
+    GdkPixbuf* pixbuf_scaled;
+
+    info = g_file_query_info_finish (G_FILE (icon_file), res, NULL);
+    if (info)
+    {
+        content_type = g_file_info_get_content_type (info);
+        if (g_str_has_prefix (content_type, "image/"))
+        {
+            icon = g_file_icon_new (icon_file);
+            g_loadable_icon_load_async (G_LOADABLE_ICON (icon),
+                0, NULL, (GAsyncReadyCallback)loadable_icon_finish_cb, view);
+            return;
+        }
+    }
+
+    file = g_file_get_parent (icon_file);
+    parent = g_file_get_parent (file);
+    /* We need to check if file equals the parent due to a GIO bug */
+    if (parent && !g_file_equal (file, parent))
+    {
+        icon_file = g_file_get_child (parent, "favicon.ico");
+        g_file_query_info_async (icon_file,
+            G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+            G_FILE_QUERY_INFO_NONE, 0, NULL,
+            (GAsyncReadyCallback)file_info_finish_cb, view);
+        return;
+    }
+
+    pixbuf = gtk_widget_render_icon (GTK_WIDGET (view),
+        GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
+    gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
+    pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height,
+                                             GDK_INTERP_BILINEAR);
+    g_object_unref (pixbuf);
+
+    view->icon = pixbuf_scaled;
+    g_object_notify (G_OBJECT (view), "icon");
+}
+#endif
+
+static void
+_midori_web_view_load_icon (MidoriView* view)
+{
+    #if HAVE_GIO
+    GFile* file;
+    GFile* icon_file;
+    #endif
+    GdkPixbuf* pixbuf;
+    gint icon_width, icon_height;
+    GdkPixbuf* pixbuf_scaled;
+
+    #if HAVE_GIO
+    if (view->uri)
+    {
+        file = g_file_new_for_uri (view->uri);
+        icon_file = g_file_get_child (file, "favicon.ico");
+        g_file_query_info_async (icon_file,
+            G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+            G_FILE_QUERY_INFO_NONE, 0, NULL,
+            (GAsyncReadyCallback)file_info_finish_cb, view);
+        return;
+    }
+    #endif
+
+    pixbuf = gtk_widget_render_icon (GTK_WIDGET (view),
+        GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
+    gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
+    pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height,
+                                             GDK_INTERP_BILINEAR);
+    g_object_unref (pixbuf);
+
+    view->icon = pixbuf_scaled;
+    g_object_notify (G_OBJECT (view), "icon");
+}
+
+static void
+midori_view_notify_load_status_cb (MidoriView* view,
+                                   GParamSpec  pspec)
+{
+    g_object_get (G_OBJECT (view), "load-status", &view->load_status, NULL);
+
+    if (midori_view_is_socket (view))
+    {
+        if (view->tab_icon)
+            katze_throbber_set_animated (KATZE_THROBBER (view->tab_icon),
+                view->load_status != MIDORI_LOAD_FINISHED);
+    }
+
+    if (midori_view_is_plug (view))
+        send_command (view, "load-status", int_to_str (view->load_status));
+
+    if (!midori_view_is_plug (view))
+        if (view->load_status == MIDORI_LOAD_COMMITTED)
+            _midori_web_view_load_icon (view);
+}
+
+static void
+midori_view_notify_progress_cb (MidoriView* view,
+                                GParamSpec  pspec)
+{
+    g_object_get (G_OBJECT (view), "progress", &view->progress, NULL);
+
+    if (midori_view_is_plug (view))
+        send_command (view, "progress", float_to_str (view->progress));
+}
+
+static void
+midori_view_action_cb (MidoriView*  view,
+                       const gchar* action)
+{
+    if (midori_view_is_socket (view))
+        return;
+
+    send_command (view, "activate-action", action);
+}
+
+static void
+midori_view_console_message_cb (MidoriView*  view,
+                                const gchar* message,
+                                gint         line,
+                                const gchar* source_id)
+{
+    gchar* argument;
+
+    if (midori_view_is_socket (view))
+        return;
+
+    argument = g_strdup_printf ("%s %d %s", message, line, source_id);
+    send_command (view, "console-message", argument);
+    g_free (argument);
+}
+
+static void
+midori_view_new_tab_cb (MidoriView*  view,
+                        const gchar* uri)
+{
+    if (midori_view_is_socket (view))
+        return;
+
+    send_command (view, "new-tab", uri);
+}
+
+static void
+midori_view_new_window_cb (MidoriView*  view,
+                           const gchar* uri)
+{
+    if (midori_view_is_socket (view))
+        return;
+
+    send_command (view, "new-window", uri);
+}
+
+static void
+midori_view_add_bookmark_cb (MidoriView*  view,
+                             const gchar* uri)
+{
+    if (midori_view_is_socket (view))
+        return;
+
+    send_command (view, "add-bookmark", uri);
+}
+
+static void
+receive_status (MidoriView*  view,
+                const gchar* command)
+{
+    if (!strncmp (command, "uri ", 4))
+    {
+        katze_assign (view->uri, g_strdup (&command[4]));
+        g_object_notify (G_OBJECT (view), "uri");
+    }
+    else if (!strncmp (command, "title ", 6))
+    {
+        g_object_set (view, "title", &command[6], NULL);
+    }
+    else if (!strncmp (command, "load-status ", 12))
+    {
+        view->load_status = (MidoriLoadStatus)atoi (&command[12]);
+        g_object_notify (G_OBJECT (view), "load-status");
+    }
+    else if (!strncmp (command, "progress ", 9))
+    {
+        view->progress = atof (&command[9]);
+        g_object_notify (G_OBJECT (view), "progress");
+    }
+    else if (!strncmp (command, "zoom-level ", 11))
+    {
+        view->zoom_level = atof (&command[11]);
+        g_object_notify (G_OBJECT (view), "zoom-level");
+    }
+    else if (!strncmp (command, "statusbar-text ", 15))
+    {
+        g_object_set (view, "statusbar-text", &command[15], NULL);
+    }
+    else if (!strncmp (command, "activate-action ", 16))
+    {
+        g_signal_emit (view, signals[ACTIVATE_ACTION], 0, &command[16]);
+    }
+    else if (!strncmp (command, "console-message ", 16))
+    {
+        /* FIXME: Implement */
+    }
+    else if (!strncmp (command, "new-tab ", 8))
+    {
+        g_signal_emit (view, signals[NEW_TAB], 0, &command[8]);
+    }
+    else if (!strncmp (command, "new-window ", 11))
+    {
+        g_signal_emit (view, signals[NEW_WINDOW], 0, &command[11]);
+    }
+    else if (!strncmp (command, "add-bookmark ", 13))
+    {
+        g_signal_emit (view, signals[ADD_BOOKMARK], 0, &command[13]);
+    }
+    else if (!strncmp (command, "clipboard ", 10))
+    {
+        view->can_cut_clipboard = atof (&command[10]);
+        view->can_copy_clipboard = atof (&command[12]);
+        view->can_paste_clipboard = atof (&command[14]);
+        midori_debug ("clipboards: %s => %d, %d, %d",
+            &command[10],
+            atoi (&command[10]), atoi (&command[12]), atoi (&command[14]));
+    }
+    else if (g_str_has_prefix (command, "**"))
+    {
+        g_print ("%s\n", command);
+    }
+    else
+    {
+        midori_debug ("receive_status: unknown command '%s'", command);
+    }
+}
+
+static void
+receive_command (MidoriView*  view,
+                 const gchar* command)
+{
+    if (!strncmp (command, "set-uri ", 8))
+        midori_view_set_uri (view, &command[8]);
+    else if (!strncmp (command, "set-zoom-level ", 15))
+        midori_view_set_zoom_level (view, atof (&command[15]) / 10);
+    else if (!strncmp (command, "reload ", 7))
+        midori_view_reload (view, atoi (&command[7]));
+    else if (!strncmp (command, "stop-loading", 12))
+        midori_view_stop_loading (view);
+    else if (!strncmp (command, "go-back", 7))
+        midori_view_go_back (view);
+    else if (!strncmp (command, "go-forward", 10))
+        midori_view_go_forward (view);
+    else if (!strncmp (command, "print", 5))
+        midori_view_print (view);
+    else if (!strncmp (command, "download-manager ", 17))
+    {
+        katze_assign (view->download_manager, g_strdup (&command[17]));
+    }
+    else if (g_str_has_prefix (command, "**"))
+        g_print ("%s\n", command);
+    else
+       midori_debug ("receive_command: unknown command '%s'", command);
+}
+
+static gboolean
+io_input_watch_cb (GIOChannel*  source,
+                   GIOCondition condition,
+                   MidoriView*  view)
+{
+    gchar* buffer;
+    GError* error;
+
+    error = NULL;
+    switch (condition)
+    {
+    case G_IO_PRI:
+    case G_IO_IN:
+        if (g_io_channel_read_line (source,
+            &buffer, NULL, NULL, &error) == G_IO_STATUS_NORMAL)
+        {
+            if (view->socket_id)
+                receive_command (view, buffer);
+            else
+                receive_status (view, buffer);
+            g_free (buffer);
+        }
+        else
+        {
+            g_warning ("Communication error: %s", error->message);
+            g_error_free (error);
+        }
+        break;
+    case G_IO_ERR:
+    case G_IO_NVAL:
+        g_warning ("Invalid operation");
+        return FALSE;
+    case G_IO_HUP:
+        midori_debug ("Tab closed");
+        return FALSE;
+    default:
+        g_warning ("Unexpected condition");
+        return FALSE;
+  }
+
+  return TRUE;
+}
+
+static void
+webkit_web_view_load_started_cb (WebKitWebView*  web_view,
+                                 WebKitWebFrame* web_frame,
+                                 MidoriView*     view)
+{
+    view->window_object_cleared = FALSE;
+
+    view->load_status = MIDORI_LOAD_PROVISIONAL;
+    g_object_notify (G_OBJECT (view), "load-status");
+
+    view->progress = 0.0;
+    g_object_notify (G_OBJECT (view), "progress");
+}
+
+static void
+webkit_web_view_window_object_cleared_cb (WebKitWebView*     web_view,
+                                          WebKitWebFrame*    web_frame,
+                                          JSGlobalContextRef js_context,
+                                          JSObjectRef        js_window,
+                                          MidoriView*        view)
+{
+    view->window_object_cleared = TRUE;
+}
+
+static void
+webkit_web_view_load_committed_cb (WebKitWebView*  web_view,
+                                   WebKitWebFrame* web_frame,
+                                   MidoriView*     view)
+{
+    const gchar* uri;
+    GdkPixbuf* icon;
+
+    uri = webkit_web_frame_get_uri (web_frame);
+    katze_assign (view->uri, g_strdup (uri));
+    g_object_notify (G_OBJECT (view), "uri");
+    g_object_set (view, "title", NULL, NULL);
+
+    icon = gtk_widget_render_icon (GTK_WIDGET (view),
+        GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
+    katze_object_assign (view->icon, icon);
+    g_object_notify (G_OBJECT (view), "icon");
+
+    view->load_status = MIDORI_LOAD_COMMITTED;
+    g_object_notify (G_OBJECT (view), "load-status");
+}
+
+static void
+webkit_web_view_progress_changed_cb (WebKitWebView* web_view,
+                                     gint           progress,
+                                     MidoriView*    view)
+{
+    view->progress = progress ? progress / 100.0 : 0.0;
+    g_object_notify (G_OBJECT (view), "progress");
+}
+
+/*
+static void
+gjs_value_links_foreach_cb (GjsValue*   link,
+                            MidoriView* view)
+{
+    const gchar* type;
+#if HAVE_GIO
+    const gchar* rel;
+    GFile* icon_file;
+    GIcon* icon;
+#endif
+
+    if (gjs_value_is_object (link) && gjs_value_has_attribute (link, "href"))
+    {
+        if (gjs_value_has_attribute (link, "type"))
+        {
+            type = gjs_value_get_attribute_string (link, "type");
+            if (!strcmp (type, "application/rss+xml")
+                || !strcmp (type, "application/x.atom+xml")
+                || !strcmp (type, "application/atom+xml"))
+            {
+                katze_array_add_item (view->news_feeds, link);
+                g_signal_emit_by_name (view, "news-feed-ready",
+                    gjs_value_get_attribute_string (link, "href"), type,
+                    gjs_value_has_attribute (link, "title")
+                    ? gjs_value_get_attribute_string (link, "title") : NULL);
+            }
+        }
+#if HAVE_GIO
+        if (gjs_value_has_attribute (link, "rel"))
+        {
+            rel = gjs_value_get_attribute_string (link, "rel");
+            if (!strcmp (rel, "icon") || !strcmp (rel, "shortcut icon"))
+            {
+                icon_file = g_file_new_for_uri (
+                    gjs_value_get_attribute_string (link, "href"));
+                icon = g_file_icon_new (icon_file);
+                g_loadable_icon_load_async (G_LOADABLE_ICON (icon),
+                    0, NULL, (GAsyncReadyCallback)loadable_icon_finish_cb, view);
+            }
+        }
+#endif
+    }
+}
+*/
+
+static void
+webkit_web_frame_load_done_cb (WebKitWebFrame* web_frame,
+                               gboolean        success,
+                               MidoriView*     view)
+{
+    gchar* data;
+    JSContextRef js_context;
+    JSValueRef js_window;
+    /* GjsValue* value;
+    GjsValue* document;
+    GjsValue* links; */
+
+    if (!success)
+    {
+        midori_debug ("'%s' not found.", view->uri);
+        data = g_strdup_printf ("error:404 %s ", view->uri ? view->uri : "");
+        midori_view_set_uri (view, data);
+        g_free (data);
+        return;
+    }
+
+    /* If WebKit didn't emit the signal due to a bug, we will */
+    if (!view->window_object_cleared)
+    {
+        js_context = webkit_web_frame_get_global_context (web_frame);
+        js_window = JSContextGetGlobalObject (js_context);
+        g_signal_emit_by_name (view->web_view, "window-object-cleared",
+            web_frame, js_context, js_window);
+    }
+
+    /* value = gjs_value_new (webkit_web_frame_get_global_context (web_frame), NULL);
+    document = gjs_value_get_by_name (value, "document");
+    links = gjs_value_get_elements_by_tag_name (document, "link");
+    katze_array_clear (web_view->news_feeds);
+    gjs_value_foreach (links, (GjsCallback)gjs_value_links_foreach_cb, web_view);
+    g_object_unref (links);
+    g_object_unref (document);
+    g_object_unref (value); */
+
+    view->load_status = MIDORI_LOAD_FINISHED;
+    g_object_notify (G_OBJECT (view), "load-status");
+}
+
+static void
+webkit_web_view_load_finished_cb (WebKitWebView*  web_view,
+                                  WebKitWebFrame* web_frame,
+                                  MidoriView*     view)
+{
+    view->progress = 1.0;
+    g_object_notify (G_OBJECT (view), "progress");
+}
+
+static void
+webkit_web_view_title_changed_cb (WebKitWebView*  web_view,
+                                  WebKitWebFrame* web_frame,
+                                  const gchar*    title,
+                                  MidoriView*     view)
+{
+    g_object_set (view, "title", title, NULL);
+}
+
+static void
+webkit_web_view_statusbar_text_changed_cb (WebKitWebView* web_view,
+                                           const gchar*   text,
+                                           MidoriView*    view)
+{
+    g_object_set (G_OBJECT (view), "statusbar-text", text, NULL);
+}
+
+static void
+webkit_web_view_hovering_over_link_cb (WebKitWebView* web_view,
+                                       const gchar*   tooltip,
+                                       const gchar*   link_uri,
+                                       MidoriView*    view)
+{
+    katze_assign (view->link_uri, g_strdup (link_uri));
+    g_object_set (G_OBJECT (view), "statusbar-text", link_uri, NULL);
+}
+
+static gboolean
+gtk_widget_button_press_event_cb (WebKitWebView*  web_view,
+                                  GdkEventButton* event,
+                                  MidoriView*     view)
+{
+    GdkModifierType state;
+    gint x, y;
+    GtkClipboard* clipboard;
+    gchar* uri;
+    gchar* new_uri;
+    const gchar* link_uri;
+
+    gdk_window_get_pointer (NULL, &x, &y, &state);
+    link_uri = midori_view_get_link_uri (MIDORI_VIEW (view));
+
+    switch (event->button)
+    {
+    case 1:
+        if (!link_uri)
+            return FALSE;
+        if (state & GDK_SHIFT_MASK)
+        {
+            /* Open link in new window */
+            g_signal_emit_by_name (view, "new-window", link_uri);
+            return TRUE;
+        }
+        else if (state & GDK_MOD1_MASK)
+        {
+            /* Open link in new tab */
+            g_signal_emit_by_name (view, "new-tab", link_uri);
+            /* FIXME: Open in the background as appropriate */
+            /* background = sokoke_object_get_boolean (browser->settings,
+                "open-tabs-in-the-background");
+            if (state & GDK_CONTROL_MASK)
+                background = !background;
+            if (background)
+                open_tab_in_the_background */
+            return TRUE;
+        }
+        break;
+    case 2:
+        if (link_uri)
+        {
+            /* Open link in new tab */
+            g_signal_emit_by_name (view, "new-tab", link_uri);
+            /* FIXME: Open in the background as appropriate */
+            /* background = sokoke_object_get_boolean (browser->settings,
+                "open-tabs-in-the-background");
+            if (state & GDK_CONTROL_MASK)
+                background = !background;
+            if (background)
+                open_tab_in_the_background */
+            return TRUE;
+        }
+        else if (state & GDK_CONTROL_MASK)
+        {
+            midori_view_set_zoom_level (MIDORI_VIEW (view), 1.0);
+            return FALSE; /* Allow Ctrl + Middle click */
+        }
+        else if (TRUE /*middle-click-opens-selection*/)
+        {
+            state = (GdkModifierType) event->state;
+            clipboard = gtk_clipboard_get_for_display (
+                gtk_widget_get_display (GTK_WIDGET (view)),
+                GDK_SELECTION_PRIMARY);
+            uri = gtk_clipboard_wait_for_text (clipboard);
+            if (uri && strchr (uri, '.') && !strchr (uri, ' '))
+            {
+                new_uri = sokoke_magic_uri (uri, NULL);
+                if (state & GDK_CONTROL_MASK)
+                    g_signal_emit_by_name (view, "new-tab", new_uri);
+                else
+                {
+                    midori_view_set_uri (MIDORI_VIEW (view), new_uri);
+                    gtk_widget_grab_focus (GTK_WIDGET (view));
+                }
+                g_free (new_uri);
+                g_free (uri);
+                return TRUE;
+            }
+        }
+        break;
+    }
+
+    return FALSE;
+}
+
+static gboolean
+gtk_widget_button_release_event_cb (WebKitWebView*  web_view,
+                                    GdkEventButton* event,
+                                    MidoriView*     view)
+{
+    GtkClipboard* clipboard;
+    gchar* text;
+
+    /* Emulate the primary clipboard, which WebKit doesn't support */
+    text = webkit_web_view_get_selected_text (WEBKIT_WEB_VIEW (web_view));
+    clipboard = gtk_clipboard_get_for_display (
+        gtk_widget_get_display (GTK_WIDGET (web_view)), GDK_SELECTION_PRIMARY);
+    gtk_clipboard_set_text (clipboard, text, -1);
+    g_free (text);
+    return FALSE;
+}
+
+static gboolean
+gtk_widget_scroll_event_cb (WebKitWebView*  web_view,
+                            GdkEventScroll* event,
+                            MidoriView*     view)
+{
+    GdkModifierType state = (GdkModifierType)0;
+    gint x, y;
+
+    gdk_window_get_pointer (NULL, &x, &y, &state);
+    if (state & GDK_CONTROL_MASK)
+    {
+        if (event->direction == GDK_SCROLL_DOWN)
+            webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view));
+        else if(event->direction == GDK_SCROLL_UP)
+            webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view));
+        return TRUE;
+    }
+    else
+        return FALSE;
+}
+
+static void
+midori_web_view_menu_new_tab_activate_cb (GtkWidget*  widget,
+                                          MidoriView* view)
+{
+    g_signal_emit (view, signals[NEW_TAB], 0, view->link_uri);
+}
+
+static void
+midori_web_view_menu_new_window_activate_cb (GtkWidget*  widget,
+                                             MidoriView* view)
+{
+    g_signal_emit (view, signals[NEW_WINDOW], 0, view->link_uri);
+}
+
+static void
+midori_web_view_menu_download_activate_cb (GtkWidget*  widget,
+                                           MidoriView* view)
+{
+    sokoke_spawn_program (view->download_manager, view->link_uri);
+}
+
+static void
+midori_web_view_menu_add_bookmark_activate_cb (GtkWidget*  widget,
+                                               MidoriView* view)
+{
+    g_signal_emit (view, signals[ADD_BOOKMARK], 0, view->link_uri);
+}
+
+static void
+midori_web_view_menu_action_activate_cb (GtkWidget*  widget,
+                                         MidoriView* view)
+{
+    const gchar* action = g_object_get_data (G_OBJECT (widget), "action");
+    g_signal_emit_by_name (view, "activate-action", action);
+}
+
+static void
+webkit_web_view_populate_popup_cb (WebKitWebView* web_view,
+                                   GtkWidget*     menu,
+                                   MidoriView*    view)
+{
+    GtkWidget* menuitem;
+    GtkWidget* icon;
+    gchar* stock_id;
+    GdkScreen* screen;
+    GtkIconTheme* icon_theme;
+    GList* items;
+
+    /* We do not want to modify the Edit menu.
+       The only reliable indicator is inspecting the first item. */
+    items = gtk_container_get_children (GTK_CONTAINER (menu));
+    menuitem = (GtkWidget*)g_list_nth_data (items, 0);
+    if (GTK_IS_IMAGE_MENU_ITEM (menuitem))
+    {
+        icon = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (menuitem));
+        gtk_image_get_stock (GTK_IMAGE (icon), &stock_id, NULL);
+        if (!strcmp (stock_id, GTK_STOCK_CUT))
+            return;
+    }
+
+    if (view->link_uri)
+    {
+        menuitem = gtk_image_menu_item_new_with_mnemonic (
+            _("Open Link in New _Tab"));
+        screen = gtk_widget_get_screen (GTK_WIDGET (view));
+        icon_theme = gtk_icon_theme_get_for_screen (screen);
+        if (gtk_icon_theme_has_icon (icon_theme, STOCK_TAB_NEW))
+        {
+            icon = gtk_image_new_from_stock (STOCK_TAB_NEW, GTK_ICON_SIZE_MENU);
+            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
+        }
+        gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 1);
+        g_signal_connect (menuitem, "activate",
+            G_CALLBACK (midori_web_view_menu_new_tab_activate_cb), view);
+        gtk_widget_show (menuitem);
+        /* hack to implement New Window */
+        items = gtk_container_get_children (GTK_CONTAINER (menu));
+        menuitem = (GtkWidget*)g_list_nth_data (items, 2);
+        g_signal_connect (menuitem, "activate",
+            G_CALLBACK (midori_web_view_menu_new_window_activate_cb), view);
+        menuitem = (GtkWidget*)g_list_nth_data (items, 3);
+        /* hack to disable non-functional Download File */
+        gtk_widget_set_sensitive (menuitem, FALSE);
+        g_list_free (items);
+        if (view->download_manager && *view->download_manager)
+        {
+            menuitem = gtk_image_menu_item_new_with_mnemonic (
+                _("Download Link with Download _Manager"));
+            icon = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS,
+                                             GTK_ICON_SIZE_MENU);
+            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
+            gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 4);
+            g_signal_connect (menuitem, "activate",
+                G_CALLBACK (midori_web_view_menu_download_activate_cb), view);
+            gtk_widget_show (menuitem);
+        }
+        menuitem = gtk_image_menu_item_new_from_stock (STOCK_BOOKMARK_ADD, NULL);
+        gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 5);
+        g_signal_connect (menuitem, "activate",
+            G_CALLBACK (midori_web_view_menu_add_bookmark_activate_cb), view);
+        gtk_widget_show (menuitem);
+    }
+
+    if (!view->link_uri && midori_view_has_selection (view))
+    {
+        if (strchr (view->selected_text, '.')
+            && !strchr (view->selected_text, ' '))
+        {
+            menuitem = gtk_image_menu_item_new_with_mnemonic (
+                _("Open URL in New _Tab"));
+            icon = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO,
+                                             GTK_ICON_SIZE_MENU);
+            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
+            gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, -1);
+            g_object_set_data (G_OBJECT (menuitem), "uri", view->selected_text);
+            g_signal_connect (menuitem, "activate",
+                G_CALLBACK (midori_web_view_menu_new_tab_activate_cb), view);
+            gtk_widget_show (menuitem);
+        }
+        /* FIXME: view selection source */
+    }
+
+    if (!view->link_uri && !midori_view_has_selection (view))
+    {
+        /* FIXME: Make this sensitive only when there is a tab to undo */
+        menuitem = gtk_image_menu_item_new_with_mnemonic (_("Undo Close Tab"));
+        icon = gtk_image_new_from_stock (GTK_STOCK_UNDELETE, 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), "action", "UndoTabClose");
+        g_signal_connect (menuitem, "activate",
+            G_CALLBACK (midori_web_view_menu_action_activate_cb), view);
+        gtk_widget_show (menuitem);
+        menuitem = gtk_separator_menu_item_new ();
+        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+        gtk_widget_show (menuitem);
+        menuitem = gtk_image_menu_item_new_from_stock (STOCK_BOOKMARK_ADD, NULL);
+        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+        g_object_set_data (G_OBJECT (menuitem), "action", "BookmarkAdd");
+        g_signal_connect (menuitem, "activate",
+            G_CALLBACK (midori_web_view_menu_action_activate_cb), view);
+        gtk_widget_show (menuitem);
+        menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE_AS, NULL);
+        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+        g_object_set_data (G_OBJECT (menuitem), "action", "SaveAs");
+        g_signal_connect (menuitem, "activate",
+            G_CALLBACK (midori_web_view_menu_action_activate_cb), view);
+        gtk_widget_show (menuitem);
+        /* FIXME: Make this sensitive once it's implemented */
+        gtk_widget_set_sensitive (menuitem, FALSE);
+        menuitem = gtk_image_menu_item_new_with_mnemonic (_("View _Source"));
+        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+        g_object_set_data (G_OBJECT (menuitem), "action", "SourceView");
+        g_signal_connect (menuitem, "activate",
+            G_CALLBACK (midori_web_view_menu_action_activate_cb), view);
+        gtk_widget_show (menuitem);
+        #if !HAVE_GIO
+        gtk_widget_set_sensitive (menuitem, FALSE);
+        #endif
+        menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PRINT, NULL);
+        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+        g_object_set_data (G_OBJECT (menuitem), "action", "Print");
+        g_signal_connect (menuitem, "activate",
+            G_CALLBACK (midori_web_view_menu_action_activate_cb), view);
+        gtk_widget_show (menuitem);
+    }
+}
+
+static void
+webkit_web_view_console_message_cb (GtkWidget*   web_view,
+                                    const gchar* message,
+                                    guint        line,
+                                    const gchar* source_id,
+                                    MidoriView*  view)
+{
+    g_signal_emit_by_name (view, "console-message", message, line, source_id);
+}
+
+static gboolean
+gtk_widget_focus_out_event_cb (GtkWidget*     web_view,
+                               GdkEventFocus* event,
+                               MidoriView*    view)
+{
+    gchar* data;
+
+    data = g_strdup_printf ("%d %d %d",
+        midori_view_can_cut_clipboard (view),
+        midori_view_can_copy_clipboard (view),
+        midori_view_can_paste_clipboard (view));
+    send_command (view, "clipboard", data);
+    g_free (data);
+
+    return FALSE;
+}
+
+static void
+midori_view_realize (MidoriView* view)
+{
+    WebKitWebFrame* web_frame;
+
+    view->web_view = webkit_web_view_new ();
+    /* Adjustments are not created automatically */
+    g_object_set (view, "hadjustment", NULL, "vadjustment", NULL, NULL);
+
+    /* FIXME: Strictly we should send a command to query
+       the policy or send it as an argument */
+    /* The socket view is not supposed to scroll at all */
+    if (midori_view_is_socket (view))
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
+            GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+    /* The plug view should use the policy of the socket */
+    if (midori_view_is_plug (view))
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
+            GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+    gtk_widget_show (view->web_view);
+
+    web_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (view->web_view));
+
+    g_object_connect (view->web_view,
+                      "signal::load-started",
+                      webkit_web_view_load_started_cb, view,
+                      "signal::window-object-cleared",
+                      webkit_web_view_window_object_cleared_cb, view,
+                      "signal::load-committed",
+                      webkit_web_view_load_committed_cb, view,
+                      "signal::load-progress-changed",
+                      webkit_web_view_progress_changed_cb, view,
+                      "signal::load-finished",
+                      webkit_web_view_load_finished_cb, view,
+                      "signal::title-changed",
+                      webkit_web_view_title_changed_cb, view,
+                      "signal::status-bar-text-changed",
+                      webkit_web_view_statusbar_text_changed_cb, view,
+                      "signal::hovering-over-link",
+                      webkit_web_view_hovering_over_link_cb, view,
+                      "signal::button-press-event",
+                      gtk_widget_button_press_event_cb, view,
+                      "signal::button-release-event",
+                      gtk_widget_button_release_event_cb, view,
+                      "signal::scroll-event",
+                      gtk_widget_scroll_event_cb, view,
+                      "signal::populate-popup",
+                      webkit_web_view_populate_popup_cb, view,
+                      "signal::console-message",
+                      webkit_web_view_console_message_cb, view,
+                      "signal::focus-out-event",
+                      gtk_widget_focus_out_event_cb, view,
+                      NULL);
+    g_object_connect (web_frame,
+                      "signal::load-done",
+                      webkit_web_frame_load_done_cb, view,
+                      NULL);
+
+    gtk_container_add (GTK_CONTAINER (view), view->web_view);
+    if (view->premature_uri)
+    {
+        midori_debug ("Loading premature uri '%s' now", view->premature_uri);
+        midori_view_set_uri (view, view->premature_uri);
+    }
+    katze_assign (view->premature_uri, NULL);
+}
+
+static void
+gtk_socket_realize_cb (GtkWidget*  socket,
+                       MidoriView* view)
+{
+    gchar* socket_id;
+    GError* error;
+    gboolean success;
+    gint stdin;
+    gint stdout;
+    gchar* argv[] = { NULL, "--id", NULL, NULL };
+
+    /* Sockets are not supported on all platforms,
+       so fallback to working without any socket or plug. */
+    if (!gtk_socket_get_id (GTK_SOCKET (socket)))
+    {
+        gtk_widget_destroy (socket);
+        midori_view_realize (view);
+        return;
+    }
+
+    socket_id = g_strdup_printf ("%d", gtk_socket_get_id (GTK_SOCKET (socket)));
+    argv[0] = (gchar*)sokoke_remember_argv0 (NULL);
+    argv[2] = socket_id;
+    error = NULL;
+    success = g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
+                                        NULL, NULL, NULL,
+                                        &stdin, &stdout, NULL, &error);
+    g_free (socket_id);
+
+    if (!success)
+    {
+        /* Fallback to operating without a socket */
+        view->socket_id = 0;
+        midori_view_realize (view);
+
+        g_error_free (error);
+        return;
+    }
+
+    view->output = fdopen (stdin, "w");
+    view->input = g_io_channel_unix_new (stdout);
+    g_io_channel_set_close_on_unref (view->input, TRUE);
+    g_io_add_watch (view->input,
+                    G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_NVAL | G_IO_HUP,
+                    (GIOFunc)io_input_watch_cb, view);
+
+    if (view->command_cache)
+    {
+        /* Send cached commands if any */
+        fwrite (view->command_cache,
+            strlen (view->command_cache) + 1, 1, view->output);
+        katze_assign (view->command_cache, NULL);
+        fflush (view->output);
+    }
+}
+
+static gboolean
+gtk_socket_plug_removed_cb (GtkWidget*  socket,
+                            MidoriView* view)
+{
+    if (view->output)
+    {
+        fclose (view->output);
+        view->output = NULL;
+    }
+
+    if (view->input)
+    {
+        g_io_channel_unref (view->input);
+        view->input = NULL;
+    }
+
+    midori_debug ("'%s' died.", view->uri);
+    send_command (view, "set-uri error:died", view->uri ? view->uri : "");
+    if (GTK_WIDGET_REALIZED (view))
+        gtk_socket_realize_cb (socket, view);
+
+    return TRUE;
+}
+
+static void
+midori_view_realize_cb (MidoriView* view)
+{
+    GtkWidget* plug;
+    GtkWidget* socket;
+
+    if (midori_view_is_plug (view))
+    {
+        plug = gtk_plug_new (view->socket_id);
+        midori_view_realize (view);
+        gtk_widget_show (plug);
+
+        view->input = g_io_channel_unix_new (0); /* 0 is stdin */
+        g_io_channel_set_close_on_unref (view->input, TRUE);
+        g_io_add_watch (view->input,
+                        G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP,
+                        (GIOFunc)io_input_watch_cb, view);
+        view->output = fdopen (1, "w"); /* 1 is stdout */
+    }
+    else if (midori_view_is_socket (view))
+    {
+        socket = gtk_socket_new ();
+        g_signal_connect (socket, "realize",
+                          G_CALLBACK (gtk_socket_realize_cb), view);
+        g_signal_connect (socket, "plug-removed",
+                          G_CALLBACK (gtk_socket_plug_removed_cb), view);
+        gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (view),
+                                               GTK_WIDGET (socket));
+        gtk_widget_show (socket);
+    }
+}
+
+static void
+midori_view_init (MidoriView* view)
+{
+    view->command_cache = NULL;
+    view->premature_uri = NULL;
+    view->uri = NULL;
+    view->title = NULL;
+    view->icon = gtk_widget_render_icon (GTK_WIDGET (view), GTK_STOCK_FILE,
+                                         GTK_ICON_SIZE_MENU, NULL);
+    view->progress = 0.0;
+    view->load_status = MIDORI_LOAD_FINISHED;
+    view->statusbar_text = NULL;
+    view->link_uri = NULL;
+    view->selected_text = NULL;
+    view->settings = NULL;
+    view->item = NULL;
+
+    view->download_manager = NULL;
+
+    g_object_connect (view,
+                      "signal::notify::uri",
+                      midori_view_notify_uri_cb, NULL,
+                      "signal::notify::icon",
+                      midori_view_notify_icon_cb, NULL,
+                      "signal::notify::load-status",
+                      midori_view_notify_load_status_cb, NULL,
+                      "signal::notify::progress",
+                      midori_view_notify_progress_cb, NULL,
+                      "signal::realize",
+                      midori_view_realize_cb, NULL,
+                      "signal::activate-action",
+                      midori_view_action_cb, NULL,
+                      "signal::console-message",
+                      midori_view_console_message_cb, NULL,
+                      "signal::new-tab",
+                      midori_view_new_tab_cb, NULL,
+                      "signal::new-window",
+                      midori_view_new_window_cb, NULL,
+                      "signal::add-bookmark",
+                      midori_view_add_bookmark_cb, NULL,
+                      NULL);
+}
+
+static void
+midori_view_finalize (GObject* object)
+{
+    MidoriView* view;
+    /* WebKitWebFrame* web_frame; */
+
+    view = MIDORI_VIEW (object);
+
+    g_free (view->command_cache);
+    g_free (view->premature_uri);
+    g_free (view->uri);
+    g_free (view->title);
+    if (view->icon)
+        g_object_unref (view->icon);
+    g_free (view->statusbar_text);
+    g_free (view->link_uri);
+    g_free (view->selected_text);
+    if (view->settings)
+        g_object_unref (view->settings);
+    if (view->item)
+        g_object_unref (view->item);
+
+    g_free (view->download_manager);
+
+    /* web_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (view->web_view));
+    g_signal_handlers_disconnect_by_func (web_frame,
+        webkit_web_frame_load_done, view); */
+
+    G_OBJECT_CLASS (midori_view_parent_class)->finalize (object);
+}
+
+static void
+midori_view_set_property (GObject*      object,
+                          guint         prop_id,
+                          const GValue* value,
+                          GParamSpec*   pspec)
+{
+    MidoriView* view;
+
+    view = MIDORI_VIEW (object);
+
+    switch (prop_id)
+    {
+    case PROP_SOCKET_ID:
+        view->socket_id = g_value_get_uint (value);
+        break;
+    case PROP_TITLE:
+        katze_assign (view->title, g_value_dup_string (value));
+        if (!midori_view_is_plug (view))
+        {
+            #define title midori_view_get_display_title (view)
+            if (view->tab_label)
+            {
+                gtk_label_set_text (GTK_LABEL (view->tab_title), title);
+                gtk_widget_set_tooltip_text (view->tab_title, title);
+            }
+            if (view->menu_item)
+                gtk_label_set_text (GTK_LABEL (gtk_bin_get_child (GTK_BIN (
+                                    view->menu_item))), title);
+            if (view->item)
+                katze_item_set_name (view->item, title);
+            #undef title
+        }
+        if (midori_view_is_plug (view))
+            /* We must not send a NULL string here */
+            send_command (view, "title", view->title ? view->title : "");
+        break;
+    case PROP_ZOOM_LEVEL:
+        midori_view_set_zoom_level (view, g_value_get_float (value));
+        if (midori_view_is_plug (view))
+            send_command (view, "zoom-level", float_to_str (view->zoom_level));
+        break;
+    case PROP_STATUSBAR_TEXT:
+        katze_assign (view->statusbar_text, g_value_dup_string (value));
+        if (midori_view_is_plug (view))
+            /* We must not send a NULL string here */
+            send_command (view, "statusbar-text",
+                view->statusbar_text ? view->statusbar_text : "");
+        break;
+    case PROP_SETTINGS:
+        midori_view_set_settings (view, g_value_get_object (value));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+midori_view_get_property (GObject*    object,
+                          guint       prop_id,
+                          GValue*     value,
+                          GParamSpec* pspec)
+{
+    MidoriView* view = MIDORI_VIEW (object);
+
+    switch (prop_id)
+    {
+    case PROP_SOCKET_ID:
+        g_value_set_uint (value, view->socket_id);
+        break;
+    case PROP_URI:
+        g_value_set_string (value, view->uri);
+        break;
+    case PROP_TITLE:
+        g_value_set_string (value, view->title);
+        break;
+    case PROP_PROGRESS:
+        g_value_set_double (value, midori_view_get_progress (view));
+        break;
+    case PROP_LOAD_STATUS:
+        g_value_set_enum (value, midori_view_get_load_status (view));
+        break;
+    case PROP_ZOOM_LEVEL:
+        g_value_set_float (value, midori_view_get_zoom_level (view));
+        break;
+    case PROP_STATUSBAR_TEXT:
+        g_value_set_string (value, view->statusbar_text);
+        break;
+    case PROP_SETTINGS:
+        g_value_set_object (value, view->settings);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+/**
+ * midori_view_new:
+ * @view: a #MidoriView
+ *
+ * Creates a new view.
+ *
+ * Return value: a new #MidoriView
+ **/
+GtkWidget*
+midori_view_new (void)
+{
+    return g_object_new (MIDORI_TYPE_VIEW, NULL);
+}
+
+/**
+ * midori_view_new_with_uri:
+ * @view: a #MidoriView
+ * @uri: an URI
+ *
+ * Creates a new view with a particular URI.
+ *
+ * This constructor supports opaque views and is
+ * in fact currently the only way to create them.
+ *
+ * The only currently supported opaque view is
+ * the source view, implementing a #MidoriSource.
+ * Pass an URI prefixed with "view-source:" in
+ * order to create a source view.
+ *
+ * Return value: a new #MidoriView
+ **/
+GtkWidget*
+midori_view_new_with_uri (const gchar* uri)
+{
+    MidoriView* view;
+    gchar* title;
+    GtkWidget* widget;
+
+    view = g_object_new (MIDORI_TYPE_VIEW, NULL);
+
+    if (uri && g_str_has_prefix (uri, "view-source:"))
+    {
+        view->socket_id = -1;
+        katze_assign (view->uri, g_strdup (uri));
+        g_object_notify (G_OBJECT (view), "uri");
+        title = g_strdup_printf ("%s - %s", _("Source"), &uri[12]);
+        g_object_set (view, "title", title, NULL);
+        g_free (title);
+        katze_object_assign (view->icon,
+            gtk_widget_render_icon (GTK_WIDGET (view),
+                GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU, NULL));
+        widget = midori_source_new (&uri[12]);
+        /* Adjustments are not created automatically */
+        g_object_set (view, "hadjustment", NULL, "vadjustment", NULL, NULL);
+        gtk_container_add (GTK_CONTAINER (view), widget);
+        gtk_widget_show (widget);
+    }
+    else
+        midori_view_set_uri (view, uri);
+
+    return (GtkWidget*)view;
+}
+
+static void
+_update_label_size (GtkWidget* label,
+                    gint       size)
+{
+    gint width, height;
+
+    if (size > -1)
+    {
+        sokoke_widget_get_text_size (label, "M", &width, &height);
+        gtk_widget_set_size_request (label, width * size, -1);
+        gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+    }
+    else
+    {
+        gtk_widget_set_size_request (label, -1, -1);
+        gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_NONE);
+    }
+}
+
+static void
+_midori_view_update_settings (MidoriView* view)
+{
+    g_object_get (view->settings,
+        "download-manager", &view->download_manager,
+        "close-buttons-on-tabs", &view->close_buttons_on_tabs,
+        NULL);
+
+    if (midori_view_is_socket (view))
+        send_command (view, "download-manager", view->download_manager);
+}
+
+static void
+midori_view_settings_notify_cb (MidoriWebSettings* settings,
+                                GParamSpec*        pspec,
+                                MidoriView*        view)
+{
+    const gchar* name;
+    GValue value = { 0, };
+
+    name = g_intern_string (g_param_spec_get_name (pspec));
+    g_value_init (&value, pspec->value_type);
+    g_object_get_property (G_OBJECT (view->settings), name, &value);
+
+    if (name == g_intern_string ("download-manager"))
+    {
+        katze_assign (view->download_manager, g_value_dup_string (&value));
+        if (midori_view_is_socket (view))
+            send_command (view, "download-manager", view->download_manager);
+    }
+    else if (name == g_intern_string ("tab-label-size"))
+    {
+        view->tab_label_size = g_value_get_int (&value);
+        if (!midori_view_is_plug (view))
+            _update_label_size (view->tab_title,
+                sokoke_object_get_int (view->settings, "tab-label-size"));
+    }
+    else if (name == g_intern_string ("close-buttons-on-tabs"))
+    {
+        view->close_buttons_on_tabs = g_value_get_boolean (&value);
+        sokoke_widget_set_visible (view->tab_close,
+                                   view->close_buttons_on_tabs);
+    }
+
+    g_value_unset (&value);
+}
+
+/**
+ * midori_view_set_settings:
+ * @view: a #MidoriView
+ * @settings: a #MidoriWebSettings
+ *
+ * Assigns a settings instance to the view.
+ **/
+void
+midori_view_set_settings (MidoriView*        view,
+                          MidoriWebSettings* settings)
+{
+    if (view->settings)
+        g_signal_handlers_disconnect_by_func (view->settings,
+            midori_view_settings_notify_cb, view);
+    katze_object_assign (view->settings, g_object_ref (settings));
+    /* FIXME: Propagate settings to the web view */
+    _midori_view_update_settings (view);
+    g_signal_connect (settings, "notify",
+        G_CALLBACK (midori_view_settings_notify_cb), view);
+    g_object_notify (G_OBJECT (view), "settings");
+}
+
+/**
+ * midori_view_load_status:
+ * @web_view: a #MidoriView
+ *
+ * Determines the current loading status of a view.
+ *
+ * Return value: the current #MidoriLoadStatus
+ **/
+MidoriLoadStatus
+midori_view_get_load_status (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), MIDORI_LOAD_FINISHED);
+
+    return view->load_status;
+}
+
+/**
+ * midori_view_get_progress:
+ * @view: a #MidoriView
+ *
+ * Retrieves the current loading progress as
+ * a fraction between 0.0 and 1.0.
+ *
+ * Return value: the current loading progress
+ **/
+gdouble
+midori_view_get_progress (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), 0.0);
+
+    return view->progress;
+}
+
+/**
+ * midori_view_set_uri:
+ * @view: a #MidoriView
+ *
+ * Opens the specified URI in the view.
+ *
+ * FIXME:
+ * If the view doesn't allow changing the URI it
+ * will automatically request a new tab.
+ **/
+void
+midori_view_set_uri (MidoriView*  view,
+                     const gchar* uri)
+{
+    gchar* data;
+
+    g_return_if_fail (MIDORI_IS_VIEW (view));
+
+    if (midori_view_is_socket (view))
+        /* We must not send a NULL string here */
+        send_command (view, "set-uri", uri ? uri : "");
+    else
+    {
+        if (!view->web_view)
+        {
+            /* An URI is requested before the view was realized.
+               We special case this to load it when we are ready. */
+            midori_debug ("Deferring premature uri '%s'", uri);
+            katze_assign (view->premature_uri, g_strdup (uri));
+            return;
+        }
+        midori_debug ("Opening URI: %s", uri);
+        /* This is not prefectly elegant, but creating an
+           error page inline is the simplest solution. */
+        if (g_str_has_prefix (uri, "error:"))
+        {
+            data = NULL;
+            if (!strncmp (uri, "error:died ", 11))
+            {
+                katze_assign (view->uri, g_strdup (&uri[11]));
+                data = g_strdup_printf (
+                    "<html><head><title>Page died - %s</title></head>"
+                    "<body><h1>Page died - %s</h1>"
+                    "<p />The page you were navigating on died."
+                    "<p />Try to <a href=\"%s\">load the page again</a>, "
+                    "or move on to another page."
+                    "</body></html>",
+                    view->uri, view->uri, view->uri);
+            }
+            else if (!strncmp (uri, "error:404 ", 10))
+            {
+                katze_assign (view->uri, g_strdup (&uri[10]));
+                data = g_strdup_printf (
+                    "<html><head><title>Not found - %s</title></head>"
+                    "<body><h1>Not found - %s</h1>"
+                    "<p />The page you were opening doesn't exist."
+                    "<p />Try to <a href=\"%s\">load the page again</a>, "
+                    "or move on to another page."
+                    "</body></html>",
+                    view->uri, view->uri, view->uri);
+            }
+            if (data)
+            {
+                webkit_web_view_load_html_string (
+                    WEBKIT_WEB_VIEW (view->web_view), data, view->uri);
+                g_free (data);
+                g_object_notify (G_OBJECT (view), "uri");
+                return;
+            }
+        }
+        else
+        {
+            katze_assign (view->uri, g_strdup (uri));
+            webkit_web_view_open (WEBKIT_WEB_VIEW (view->web_view), uri);
+        }
+    }
+}
+
+/**
+ * midori_view_is_blank:
+ * @view: a #MidoriView
+ *
+ * Determines whether the view is currently empty.
+ **/
+gboolean
+midori_view_is_blank (MidoriView*  view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), TRUE);
+
+    return !(view->uri && *view->uri);
+}
+
+/**
+ * midori_view_get_icon:
+ * @view: a #MidoriView
+ *
+ * Retrieves the icon of the view.
+ *
+ * Return value: a #GdkPixbuf
+ **/
+GdkPixbuf*
+midori_view_get_icon (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
+
+    return view->icon;
+}
+
+/**
+ * midori_view_get_display_uri:
+ * @view: a #MidoriView
+ *
+ * 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_view_get_display_uri (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), "about:blank");
+
+    if (view->uri && *view->uri)
+        return view->uri;
+    return "about:blank";
+}
+
+/**
+ * midori_view_get_display_title:
+ * @view: a #MidoriView
+ *
+ * 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_view_get_display_title (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), "about:blank");
+
+    if (view->title && *view->title)
+        return view->title;
+    return midori_view_get_display_uri (view);
+}
+
+/**
+ * midori_view_get_link_uri:
+ * @view: a #MidoriView
+ *
+ * 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_view_get_link_uri (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
+
+    return view->link_uri;
+}
+
+/**
+ * midori_view_has_selection:
+ * @view: a #MidoriView
+ *
+ * Determines whether something in the view is selected.
+ *
+ * This function returns %FALSE if there is a selection
+ * that effectively only consists of whitespace.
+ *
+ * Return value: %TRUE if effectively there is a selection
+ **/
+gboolean
+midori_view_has_selection (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE);
+
+    if (midori_view_is_socket (view))
+        return view->has_selection;
+    else
+    {
+        view->selected_text = webkit_web_view_get_selected_text (
+            WEBKIT_WEB_VIEW (view->web_view));
+        if (view->selected_text && *view->selected_text)
+            return TRUE;
+        return FALSE;
+    }
+}
+
+/**
+ * midori_view_get_selected_text:
+ * @view: a #MidoriView
+ *
+ * Retrieves the currently selected text.
+ *
+ * Return value: the selected text, or %NULL
+ **/
+const gchar*
+midori_view_get_selected_text (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
+
+    if (midori_view_is_socket (view))
+        return view->selected_text;
+    else if (midori_view_has_selection (view))
+        return midori_view_get_selected_text (view);
+    else
+        return NULL;
+}
+
+/**
+ * midori_view_can_cut_clipboard:
+ * @view: a #MidoriView
+ *
+ * Determines whether a selection can be cut.
+ *
+ * Return value: %TRUE if a selection can be cut
+ **/
+gboolean
+midori_view_can_cut_clipboard (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE);
+
+    if (midori_view_is_socket (view))
+        return view->can_cut_clipboard;
+    else if (view->web_view)
+    {
+        view->can_cut_clipboard = webkit_web_view_can_cut_clipboard (
+            WEBKIT_WEB_VIEW (view->web_view));
+        return view->can_cut_clipboard;
+    }
+    return FALSE;
+}
+
+/**
+ * midori_view_can_copy_clipboard:
+ * @view: a #MidoriView
+ *
+ * Determines whether a selection can be copied.
+ *
+ * Return value: %TRUE if a selection can be copied
+ **/
+gboolean
+midori_view_can_copy_clipboard (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE);
+
+    if (midori_view_is_socket (view))
+        return view->can_copy_clipboard;
+    else if (view->web_view)
+    {
+        view->can_copy_clipboard = webkit_web_view_can_copy_clipboard (
+            WEBKIT_WEB_VIEW (view->web_view));
+        return view->can_copy_clipboard;
+    }
+    return FALSE;
+}
+
+/**
+ * midori_view_can_paste_clipboard:
+ * @view: a #MidoriView
+ *
+ * Determines whether a selection can be pasted.
+ *
+ * Return value: %TRUE if a selection can be pasted
+ **/
+gboolean
+midori_view_can_paste_clipboard (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE);
+
+    if (midori_view_is_socket (view))
+        return view->can_paste_clipboard;
+    else if (view->web_view)
+    {
+        view->can_paste_clipboard = webkit_web_view_can_paste_clipboard (
+            WEBKIT_WEB_VIEW (view->web_view));
+        return view->can_paste_clipboard;
+    }
+    return FALSE;
+}
+
+/**
+ * midori_view_get_proxy_menu_item:
+ * @view: a #MidoriView
+ *
+ * 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.
+ *
+ * The menu item is valid until it is removed from its container.
+ *
+ * Return value: the proxy #GtkMenuItem
+ **/
+GtkWidget*
+midori_view_get_proxy_menu_item (MidoriView* view)
+{
+    const gchar* title;
+
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
+
+    if (!view->menu_item)
+    {
+        title = midori_view_get_display_title (view);
+        view->menu_item = sokoke_image_menu_item_new_ellipsized (title);
+        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (view->menu_item),
+            gtk_image_new_from_pixbuf (view->icon));
+
+        g_signal_connect (view->menu_item, "destroy",
+                          G_CALLBACK (gtk_widget_destroyed),
+                          &view->menu_item);
+    }
+    return view->menu_item;
+}
+
+static gboolean
+midori_view_tab_label_button_release_event (GtkWidget*      tab_label,
+                                            GdkEventButton* event,
+                                            GtkWidget*      widget)
+{
+    if (event->button == 2)
+    {
+        /* Close the widget on middle click */
+        gtk_widget_destroy (widget);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static void
+midori_view_tab_icon_style_set (GtkWidget* tab_icon,
+                                GtkStyle*  previous_style)
+{
+    GtkSettings* gtk_settings;
+    gint width, height;
+
+    gtk_settings = gtk_widget_get_settings (tab_icon);
+    gtk_icon_size_lookup_for_settings (gtk_settings, GTK_ICON_SIZE_MENU,
+                                       &width, &height);
+    gtk_widget_set_size_request (tab_icon, width + 2, height + 2);
+}
+
+static void
+midori_view_tab_close_clicked (GtkWidget* tab_close,
+                               GtkWidget* widget)
+{
+    gtk_widget_destroy (widget);
+}
+
+/**
+ * midori_view_get_proxy_tab_label:
+ * @view: a #MidoriView
+ *
+ * Retrieves a proxy tab label that is typically used when
+ * adding the view to a notebook.
+ *
+ * The label is created on the first call and will be updated to reflect
+ * changes of the loading progress and title.
+ *
+ * The label is valid until it is removed from its container.
+ *
+ * Return value: the proxy #GtkEventBox
+ **/
+GtkWidget*
+midori_view_get_proxy_tab_label (MidoriView* view)
+{
+    GtkWidget* event_box;
+    GtkWidget* hbox;
+    GtkRcStyle* rcstyle;
+    GtkWidget* image;
+
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
+
+    if (!view->tab_label)
+    {
+        view->tab_icon = katze_throbber_new ();
+        katze_throbber_set_static_pixbuf (KATZE_THROBBER (view->tab_icon),
+            midori_view_get_icon (view));
+
+        view->tab_title = gtk_label_new (midori_view_get_display_title (view));
+
+        event_box = gtk_event_box_new ();
+        gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
+        hbox = gtk_hbox_new (FALSE, 1);
+        gtk_container_border_width (GTK_CONTAINER (hbox), 2);
+        gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (hbox));
+        gtk_misc_set_alignment (GTK_MISC (view->tab_icon), 0.0, 0.5);
+        gtk_box_pack_start (GTK_BOX (hbox), view->tab_icon, FALSE, FALSE, 0);
+        gtk_misc_set_alignment (GTK_MISC (view->tab_title), 0.0, 0.5);
+        /* TODO: make the tab initially look "unvisited" until it's focused */
+        gtk_box_pack_start (GTK_BOX (hbox), view->tab_title, FALSE, TRUE, 0);
+        if (view->settings)
+            _update_label_size (view->tab_title,
+                sokoke_object_get_int (view->settings, "tab-label-size"));
+
+        view->tab_close = gtk_button_new ();
+        gtk_button_set_relief (GTK_BUTTON (view->tab_close), GTK_RELIEF_NONE);
+        gtk_button_set_focus_on_click (GTK_BUTTON (view->tab_close), FALSE);
+        rcstyle = gtk_rc_style_new ();
+        rcstyle->xthickness = rcstyle->ythickness = 0;
+        gtk_widget_modify_style (view->tab_close, rcstyle);
+        g_object_unref (rcstyle);
+        image = katze_throbber_new ();
+        katze_throbber_set_static_stock_id (KATZE_THROBBER (image),
+                                            GTK_STOCK_CLOSE);
+        gtk_button_set_image (GTK_BUTTON (view->tab_close), image);
+        gtk_misc_set_alignment (GTK_MISC (image), 0.0, 0.0);
+        gtk_box_pack_end (GTK_BOX (hbox), view->tab_close, FALSE, FALSE, 0);
+        gtk_widget_show_all (GTK_WIDGET (event_box));
+
+        if (view->settings &&
+            !sokoke_object_get_boolean (view->settings, "close-buttons-on-tabs"))
+            gtk_widget_hide (view->tab_close);
+
+        g_signal_connect (event_box, "button-release-event",
+            G_CALLBACK (midori_view_tab_label_button_release_event), view);
+        g_signal_connect (view->tab_close, "style-set",
+            G_CALLBACK (midori_view_tab_icon_style_set), NULL);
+        g_signal_connect (view->tab_close, "clicked",
+            G_CALLBACK (midori_view_tab_close_clicked), view);
+
+        view->tab_label = event_box;
+        g_signal_connect (view->tab_label, "destroy",
+                          G_CALLBACK (gtk_widget_destroyed),
+                          &view->tab_label);
+    }
+    return view->tab_label;
+}
+
+/**
+ * midori_view_get_proxy_item:
+ * @view: a #MidoriView
+ *
+ * Retrieves a proxy 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 uri automatically.
+ *
+ * Return value: the proxy #KatzeItem
+ **/
+KatzeItem*
+midori_view_get_proxy_item (MidoriView* view)
+{
+    const gchar* uri;
+    const gchar* title;
+
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL);
+
+    if (!view->item)
+    {
+        view->item = katze_item_new ();
+        uri = midori_view_get_display_uri (view);
+        katze_item_set_uri (view->item, uri);
+        title = midori_view_get_display_title (view);
+        katze_item_set_name (view->item, title);
+    }
+    return view->item;
+}
+
+/**
+ * midori_view_get_zoom_level:
+ * @view: a #MidoriView
+ *
+ * Determines the current zoom level of the view.
+ *
+ * Return value: the current zoom level
+ **/
+gfloat
+midori_view_get_zoom_level (MidoriView* view)
+{
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), 1.0);
+
+    if (midori_view_is_socket (view))
+        return view->zoom_level;
+    else if (view->web_view)
+        return webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (view->web_view));
+    return FALSE;
+}
+
+/**
+ * midori_view_set_zoom_level:
+ * @view: a #MidoriView
+ * @zoom_level: the new zoom level
+ *
+ * Sets the current zoom level of the view.
+ **/
+void
+midori_view_set_zoom_level (MidoriView* view,
+                            gfloat      zoom_level)
+{
+    g_return_if_fail (MIDORI_IS_VIEW (view));
+
+    if (midori_view_is_socket (view))
+        send_command (view, "set-zoom-level", float_to_str (zoom_level));
+    else
+        webkit_web_view_set_zoom_level (
+            WEBKIT_WEB_VIEW (view->web_view), zoom_level);
+}
+
+#define can_do(what) \
+gboolean \
+midori_view_can_##what (MidoriView* view) \
+{ \
+    g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE); \
+\
+    return view->socket_id > -1; \
+}
+
+can_do (zoom_in)
+can_do (zoom_out)
+can_do (reload)
+can_do (go_back)
+can_do (go_forward)
+can_do (print)
+#if HAVE_GIO
+    can_do (view_source)
+#else
+    gboolean midori_view_can_view_source (MidoriView* view)
+    {
+        return FALSE;
+    }
+#endif
+can_do (find)
+
+/**
+ * midori_view_reload:
+ * @view: a #MidoriView
+ * @from_cache: whether to allow caching
+ *
+ * Reloads the view.
+ *
+ * Note: The @from_cache value is currently ignored.
+ **/
+void
+midori_view_reload (MidoriView* view,
+                    gboolean    from_cache)
+{
+    g_return_if_fail (MIDORI_IS_VIEW (view));
+
+    if (midori_view_is_socket (view))
+        send_command (view, "reload", int_to_str (from_cache));
+    else
+        webkit_web_view_reload (WEBKIT_WEB_VIEW (view->web_view));
+}
+
+/**
+ * midori_view_stop_loading
+ * @view: a #MidoriView
+ *
+ * Stops loading the view if it is currently loading.
+ **/
+void
+midori_view_stop_loading (MidoriView* view)
+{
+    g_return_if_fail (MIDORI_IS_VIEW (view));
+
+    if (midori_view_is_socket (view))
+        send_command (view, "stop-loading", NULL);
+    else
+        webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (view->web_view));
+}
+
+/**
+ * midori_view_go_back
+ * @view: a #MidoriView
+ *
+ * Goes back one page in the view.
+ **/
+void
+midori_view_go_back (MidoriView* view)
+{
+    g_return_if_fail (MIDORI_IS_VIEW (view));
+
+    if (midori_view_is_socket (view))
+        send_command (view, "go-back", NULL);
+    else
+        webkit_web_view_go_back (WEBKIT_WEB_VIEW (view->web_view));
+}
+
+/**
+ * midori_view_go_forward
+ * @view: a #MidoriView
+ *
+ * Goes forward one page in the view.
+ **/
+void
+midori_view_go_forward (MidoriView* view)
+{
+    g_return_if_fail (MIDORI_IS_VIEW (view));
+
+    if (midori_view_is_socket (view))
+        send_command (view, "go-forward", NULL);
+    else
+        webkit_web_view_go_forward (WEBKIT_WEB_VIEW (view->web_view));
+}
+
+/**
+ * midori_view_print
+ * @view: a #MidoriView
+ *
+ * Prints the contents of the view.
+ **/
+void
+midori_view_print (MidoriView* view)
+{
+    g_return_if_fail (MIDORI_IS_VIEW (view));
+
+    if (midori_view_is_socket (view))
+        send_command (view, "print", NULL);
+    else
+        webkit_web_view_execute_script (
+            WEBKIT_WEB_VIEW (view->web_view), "print();");
+}
diff --git a/midori/midori-view.h b/midori/midori-view.h
new file mode 100644 (file)
index 0000000..96b5d22
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ 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_VIEW_H__
+#define __MIDORI_VIEW_H__
+
+#include "midori-websettings.h"
+
+#include <katze/katze.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+    MIDORI_LOAD_PROVISIONAL,
+    MIDORI_LOAD_COMMITTED,
+    MIDORI_LOAD_FINISHED
+} MidoriLoadStatus;
+
+GType
+midori_load_status_get_type (void) G_GNUC_CONST;
+
+#define MIDORI_TYPE_LOAD_STATUS \
+    (midori_load_status_get_type ())
+
+#define MIDORI_TYPE_VIEW \
+    (midori_view_get_type ())
+#define MIDORI_VIEW(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_VIEW, MidoriView))
+#define MIDORI_VIEW_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_VIEW, MidoriViewClass))
+#define MIDORI_IS_VIEW(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_VIEW))
+#define MIDORI_IS_VIEW_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_VIEW))
+#define MIDORI_VIEW_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_VIEW, MidoriViewClass))
+
+typedef struct _MidoriView                MidoriView;
+typedef struct _MidoriViewClass           MidoriViewClass;
+
+GType
+midori_view_get_type                   (void);
+
+GtkWidget*
+midori_view_new                        (void);
+
+GtkWidget*
+midori_view_new_with_uri               (const gchar*       uri);
+
+void
+midori_view_set_settings               (MidoriView*        view,
+                                        MidoriWebSettings* settings);
+
+gdouble
+midori_view_get_progress               (MidoriView*        view);
+
+MidoriLoadStatus
+midori_view_get_load_status            (MidoriView*        view);
+
+void
+midori_view_set_uri                    (MidoriView*        view,
+                                        const gchar*       uri);
+
+gboolean
+midori_view_is_blank                   (MidoriView*        view);
+
+const gchar*
+midori_view_get_display_uri            (MidoriView*        view);
+
+const gchar*
+midori_view_get_display_title          (MidoriView*        view);
+
+GdkPixbuf*
+midori_view_get_icon                   (MidoriView*        view);
+
+const gchar*
+midori_view_get_link_uri               (MidoriView*        view);
+
+gboolean
+midori_view_has_selection              (MidoriView*        view);
+
+const gchar*
+midori_view_get_selected_text          (MidoriView*        view);
+
+gboolean
+midori_view_can_cut_clipboard          (MidoriView*        view);
+
+gboolean
+midori_view_can_copy_clipboard         (MidoriView*        view);
+
+gboolean
+midori_view_can_paste_clipboard        (MidoriView*        view);
+
+GtkWidget*
+midori_view_get_proxy_menu_item        (MidoriView*        view);
+
+GtkWidget*
+midori_view_get_proxy_tab_label        (MidoriView*        view);
+
+KatzeItem*
+midori_view_get_proxy_item             (MidoriView*        view);
+
+gfloat
+midori_view_get_zoom_level             (MidoriView*        view);
+
+gboolean
+midori_view_can_zoom_in                (MidoriView*        view);
+
+gboolean
+midori_view_can_zoom_out               (MidoriView*        view);
+
+void
+midori_view_set_zoom_level             (MidoriView*        view,
+                                        gfloat             zoom_level);
+
+gboolean
+midori_view_can_reload                 (MidoriView*        view);
+
+void
+midori_view_reload                     (MidoriView*        view,
+                                        gboolean           from_cache);
+
+void
+midori_view_stop_loading               (MidoriView*        view);
+
+gboolean
+midori_view_can_go_back                (MidoriView*        view);
+
+void
+midori_view_go_back                    (MidoriView*        view);
+
+gboolean
+midori_view_can_go_forward             (MidoriView*        view);
+
+void
+midori_view_go_forward                 (MidoriView*        view);
+
+gboolean
+midori_view_can_print                  (MidoriView*        view);
+
+void
+midori_view_print                      (MidoriView*        view);
+
+gboolean
+midori_view_can_view_source            (MidoriView*        view);
+
+gboolean
+midori_view_can_find                   (MidoriView*        view);
+
+G_END_DECLS
+
+#endif /* __MIDORI_VIEW_H__ */
diff --git a/midori/midori-webview.c b/midori/midori-webview.c
deleted file mode 100644 (file)
index 754529b..0000000
+++ /dev/null
@@ -1,1214 +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.
-*/
-
-#if HAVE_CONFIG_H
-    #include <config.h>
-#endif
-
-#include "midori-webview.h"
-#include "midori-stock.h"
-
-#include "compat.h"
-#include "sokoke.h"
-#include "gjs.h"
-
-#include <string.h>
-#if HAVE_GIO
-    #include <gio/gio.h>
-#endif
-#include <glib/gi18n.h>
-#include <webkit/webkit.h>
-
-/* This is unstable API, so we need to declare it */
-gchar*
-webkit_web_view_get_selected_text (WebKitWebView* web_view);
-
-struct _MidoriWebView
-{
-    WebKitWebView parent_instance;
-    gboolean window_object_cleared;
-
-    GdkPixbuf* icon;
-    gchar* uri;
-    gchar* title;
-    gdouble progress;
-    MidoriLoadStatus load_status;
-    gchar* statusbar_text;
-    gchar* link_uri;
-    KatzeArray* news_feeds;
-
-    MidoriWebSettings* settings;
-
-    GtkWidget* menu_item;
-    GtkWidget* tab_icon;
-    GtkWidget* tab_title;
-    KatzeXbelItem* xbel_item;
-};
-
-G_DEFINE_TYPE (MidoriWebView, midori_web_view, WEBKIT_TYPE_WEB_VIEW)
-
-GType
-midori_load_status_get_type (void)
-{
-    static GType type = 0;
-    if (!type)
-    {
-        static const GEnumValue values[] = {
-         { MIDORI_LOAD_PROVISIONAL, "MIDORI_LOAD_PROVISIONAL", N_("Load Provisional") },
-         { MIDORI_LOAD_COMMITTED, "MIDORI_LOAD_COMMITTED", N_("Load Committed") },
-         { MIDORI_LOAD_FINISHED, "MIDORI_LOAD_FINISHED", N_("Load Finished") },
-         { 0, NULL, NULL }
-        };
-        type = g_enum_register_static ("MidoriLoadStatus", values);
-    }
-    return type;
-}
-
-enum
-{
-    PROP_0,
-
-    PROP_URI,
-    PROP_TITLE,
-    PROP_PROGRESS,
-    PROP_MLOAD_STATUS,
-    PROP_STATUSBAR_TEXT,
-    PROP_SETTINGS
-};
-
-enum {
-    ICON_READY,
-    NEWS_FEED_READY,
-    ELEMENT_MOTION,
-    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 void
-midori_cclosure_marshal_VOID__STRING_STRING_STRING (GClosure*     closure,
-                                                    GValue*       return_value,
-                                                    guint         n_param_values,
-                                                    const GValue* param_values,
-                                                    gpointer      invocation_hint,
-                                                    gpointer      marshal_data)
-{
-    typedef void(*GMarshalFunc_VOID__STRING_STRING_STRING) (gpointer      data1,
-                                                            const gchar*  arg_1,
-                                                            const gchar*  arg_2,
-                                                            const gchar*  arg_3,
-                                                            gpointer      data2);
-    register GMarshalFunc_VOID__STRING_STRING_STRING callback;
-    register GCClosure* cc = (GCClosure*) closure;
-    register gpointer data1, data2;
-
-    g_return_if_fail (n_param_values == 4);
-
-    if (G_CCLOSURE_SWAP_DATA (closure))
-    {
-        data1 = closure->data;
-        data2 = g_value_peek_pointer (param_values + 0);
-    }
-    else
-    {
-        data1 = g_value_peek_pointer (param_values + 0);
-        data2 = closure->data;
-    }
-    callback = (GMarshalFunc_VOID__STRING_STRING_STRING) (marshal_data
-        ? marshal_data : cc->callback);
-    callback (data1,
-              g_value_get_string (param_values + 1),
-              g_value_get_string (param_values + 2),
-              g_value_get_string (param_values + 3),
-              data2);
-}
-
-static void
-midori_web_view_class_init (MidoriWebViewClass* class)
-{
-    signals[ICON_READY] = g_signal_new (
-        "icon-ready",
-        G_TYPE_FROM_CLASS (class),
-        (GSignalFlags)(G_SIGNAL_RUN_LAST),
-        G_STRUCT_OFFSET (MidoriWebViewClass, icon_ready),
-        0,
-        NULL,
-        g_cclosure_marshal_VOID__OBJECT,
-        G_TYPE_NONE, 1,
-        GDK_TYPE_PIXBUF);
-
-    signals[NEWS_FEED_READY] = g_signal_new (
-        "news-feed-ready",
-        G_TYPE_FROM_CLASS (class),
-        (GSignalFlags)(G_SIGNAL_RUN_LAST),
-        G_STRUCT_OFFSET (MidoriWebViewClass, news_feed_ready),
-        0,
-        NULL,
-        midori_cclosure_marshal_VOID__STRING_STRING_STRING,
-        G_TYPE_NONE, 3,
-        G_TYPE_STRING,
-        G_TYPE_STRING,
-        G_TYPE_STRING);
-
-    signals[ELEMENT_MOTION] = g_signal_new (
-        "element-motion",
-        G_TYPE_FROM_CLASS (class),
-        (GSignalFlags)(G_SIGNAL_RUN_LAST),
-        G_STRUCT_OFFSET (MidoriWebViewClass, element_motion),
-        0,
-        NULL,
-        g_cclosure_marshal_VOID__STRING,
-        G_TYPE_NONE, 1,
-        G_TYPE_STRING);
-
-    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__STRING,
-        G_TYPE_NONE, 1,
-        G_TYPE_STRING);
-
-    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);
-
-    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;
-
-    if (!g_object_class_find_property (gobject_class, "uri"))
-    g_object_class_install_property (gobject_class,
-                                     PROP_URI,
-                                     g_param_spec_string (
-                                     "uri",
-                                     "Uri",
-                                     _("The URI of the currently loaded page"),
-                                     "",
-                                     flags));
-
-    if (!g_object_class_find_property (gobject_class, "title"))
-    g_object_class_install_property (gobject_class,
-                                     PROP_TITLE,
-                                     g_param_spec_string (
-                                     "title",
-                                     "Title",
-                                     _("The title of the currently loaded page"),
-                                     NULL,
-                                     flags));
-
-    if (!g_object_class_find_property (gobject_class, "progress"))
-    g_object_class_install_property (gobject_class,
-                                     PROP_PROGRESS,
-                                     g_param_spec_double (
-                                     "progress",
-                                     "Progress",
-                                     _("The current loading progress"),
-                                     0.0, 1.0, 0.0,
-                                     G_PARAM_READABLE));
-
-    g_object_class_install_property (gobject_class,
-                                     PROP_MLOAD_STATUS,
-                                     g_param_spec_enum (
-                                     "mload-status",
-                                     "Load Status",
-                                     _("The current loading status"),
-                                     MIDORI_TYPE_LOAD_STATUS,
-                                     MIDORI_LOAD_FINISHED,
-                                     G_PARAM_READABLE));
-
-    if (!g_object_class_find_property (gobject_class, "statusbar-text"))
-    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"),
-                                     "",
-                                     G_PARAM_READABLE));
-
-    g_object_class_override_property (gobject_class,
-                                      PROP_SETTINGS,
-                                      "settings");
-}
-
-static void
-webkit_web_view_load_started (MidoriWebView*  web_view,
-                              WebKitWebFrame* web_frame)
-{
-    web_view->window_object_cleared = FALSE;
-
-    web_view->load_status = MIDORI_LOAD_PROVISIONAL;
-    g_object_notify (G_OBJECT (web_view), "mload-status");
-    if (web_view->tab_icon)
-        katze_throbber_set_animated (KATZE_THROBBER (web_view->tab_icon), TRUE);
-
-    web_view->progress = 0.0;
-    g_object_notify (G_OBJECT (web_view), "progress");
-}
-
-static void
-webkit_web_view_window_object_cleared_cb (MidoriWebView*     web_view,
-                                          WebKitWebFrame*    web_frame,
-                                          JSGlobalContextRef js_context,
-                                          JSObjectRef        js_window)
-{
-    web_view->window_object_cleared = TRUE;
-}
-
-#if HAVE_GIO
-void
-loadable_icon_finish_cb (GdkPixbuf*     icon,
-                         GAsyncResult*  res,
-                         MidoriWebView* web_view)
-{
-    GInputStream* stream;
-    GdkPixbuf* pixbuf;
-    GdkPixbuf* pixbuf_scaled;
-    gint icon_width, icon_height;
-
-    pixbuf = NULL;
-    stream = g_loadable_icon_load_finish (G_LOADABLE_ICON (icon),
-                                          res, NULL, NULL);
-    if (stream)
-    {
-        pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, NULL);
-        g_object_unref (stream);
-    }
-    if (!pixbuf)
-        pixbuf = gtk_widget_render_icon (GTK_WIDGET (web_view),
-            GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
-
-    gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
-    pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height,
-                                             GDK_INTERP_BILINEAR);
-    g_object_unref (pixbuf);
-    web_view->icon = pixbuf_scaled;
-    g_signal_emit (web_view, signals[ICON_READY], 0, web_view->icon);
-}
-
-void
-file_info_finish_cb (GFile*         icon_file,
-                     GAsyncResult*  res,
-                     MidoriWebView* web_view)
-{
-    GFileInfo* info;
-    const gchar* content_type;
-    GIcon* icon;
-    GFile* parent;
-    GFile* file;
-    GdkPixbuf* pixbuf;
-    gint icon_width, icon_height;
-    GdkPixbuf* pixbuf_scaled;
-
-    info = g_file_query_info_finish (G_FILE (icon_file), res, NULL);
-    if (info)
-    {
-        content_type = g_file_info_get_content_type (info);
-        if (g_str_has_prefix (content_type, "image/"))
-        {
-            icon = g_file_icon_new (icon_file);
-            g_loadable_icon_load_async (G_LOADABLE_ICON (icon),
-                0, NULL, (GAsyncReadyCallback)loadable_icon_finish_cb, web_view);
-            return;
-        }
-    }
-
-    file = g_file_get_parent (icon_file);
-    parent = g_file_get_parent (file);
-    /* We need to check if file equals the parent due to a GIO bug */
-    if (parent && !g_file_equal (file, parent))
-    {
-        icon_file = g_file_get_child (parent, "favicon.ico");
-        g_file_query_info_async (icon_file,
-            G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
-            G_FILE_QUERY_INFO_NONE, 0, NULL,
-            (GAsyncReadyCallback)file_info_finish_cb, web_view);
-        return;
-    }
-
-    pixbuf = gtk_widget_render_icon (GTK_WIDGET (web_view),
-        GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
-    gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
-    pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height,
-                                             GDK_INTERP_BILINEAR);
-    g_object_unref (pixbuf);
-
-    web_view->icon = pixbuf_scaled;
-    g_signal_emit (web_view, signals[ICON_READY], 0, web_view->icon);
-}
-#endif
-
-static void
-_midori_web_view_load_icon (MidoriWebView* web_view)
-{
-    #if HAVE_GIO
-    GFile* file;
-    GFile* icon_file;
-    #endif
-    GdkPixbuf* pixbuf;
-    gint icon_width, icon_height;
-    GdkPixbuf* pixbuf_scaled;
-
-    #if HAVE_GIO
-    if (web_view->uri)
-    {
-        file = g_file_new_for_uri (web_view->uri);
-        icon_file = g_file_get_child (file, "favicon.ico");
-        g_file_query_info_async (icon_file,
-            G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
-            G_FILE_QUERY_INFO_NONE, 0, NULL,
-            (GAsyncReadyCallback)file_info_finish_cb, web_view);
-        return;
-    }
-    #endif
-
-    pixbuf = gtk_widget_render_icon (GTK_WIDGET (web_view),
-        GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
-    gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
-    pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height,
-                                             GDK_INTERP_BILINEAR);
-    g_object_unref (pixbuf);
-
-    web_view->icon = pixbuf_scaled;
-    g_signal_emit (web_view, signals[ICON_READY], 0, web_view->icon);
-}
-
-static void
-webkit_web_view_load_committed (MidoriWebView*  web_view,
-                                WebKitWebFrame* web_frame)
-{
-    const gchar* uri;
-    GdkPixbuf* icon;
-
-    uri = webkit_web_frame_get_uri (web_frame);
-    katze_assign (web_view->uri, g_strdup (uri));
-    if (web_view->xbel_item)
-    {
-        uri = midori_web_view_get_display_uri (web_view);
-        katze_xbel_bookmark_set_href (web_view->xbel_item, uri);
-    }
-    g_object_notify (G_OBJECT (web_view), "uri");
-    g_object_set (web_view, "title", NULL, NULL);
-
-    icon = gtk_widget_render_icon (GTK_WIDGET (web_view),
-        GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
-    katze_object_assign (web_view->icon, icon);
-    _midori_web_view_load_icon (web_view);
-
-    if (web_view->tab_icon)
-        katze_throbber_set_static_pixbuf (KATZE_THROBBER (web_view->tab_icon),
-                                          icon);
-
-    if (web_view->menu_item)
-        gtk_image_menu_item_set_image (
-            GTK_IMAGE_MENU_ITEM (web_view->menu_item),
-                gtk_image_new_from_pixbuf (icon));
-
-    web_view->load_status = MIDORI_LOAD_COMMITTED;
-    g_object_notify (G_OBJECT (web_view), "mload-status");
-}
-
-static void
-webkit_web_view_icon_ready (MidoriWebView* web_view,
-                            GdkPixbuf*     icon)
-{
-    if (web_view->tab_icon)
-        katze_throbber_set_static_pixbuf (KATZE_THROBBER (web_view->tab_icon),
-                                          icon);
-    if (web_view->menu_item)
-            gtk_image_menu_item_set_image (
-                GTK_IMAGE_MENU_ITEM (web_view->menu_item),
-                    gtk_image_new_from_pixbuf (icon));
-}
-
-static void
-webkit_web_view_progress_changed (MidoriWebView* web_view, gint progress)
-{
-    web_view->progress = progress ? progress / 100.0 : 0.0;
-    g_object_notify (G_OBJECT (web_view), "progress");
-}
-
-static void
-gjs_value_links_foreach_cb (GjsValue*      link,
-                            MidoriWebView* web_view)
-{
-    const gchar* type;
-#if HAVE_GIO
-    const gchar* rel;
-    GFile* icon_file;
-    GIcon* icon;
-#endif
-
-    if (gjs_value_is_object (link) && gjs_value_has_attribute (link, "href"))
-    {
-        if (gjs_value_has_attribute (link, "type"))
-        {
-            type = gjs_value_get_attribute_string (link, "type");
-            if (!strcmp (type, "application/rss+xml")
-                || !strcmp (type, "application/x.atom+xml")
-                || !strcmp (type, "application/atom+xml"))
-            {
-                katze_array_add_item (web_view->news_feeds, link);
-                g_signal_emit (web_view, signals[NEWS_FEED_READY], 0,
-                    gjs_value_get_attribute_string (link, "href"), type,
-                    gjs_value_has_attribute (link, "title")
-                    ? gjs_value_get_attribute_string (link, "title") : NULL);
-            }
-        }
-#if HAVE_GIO
-        if (gjs_value_has_attribute (link, "rel"))
-        {
-            rel = gjs_value_get_attribute_string (link, "rel");
-            if (!strcmp (rel, "icon") || !strcmp (rel, "shortcut icon"))
-            {
-                icon_file = g_file_new_for_uri (
-                    gjs_value_get_attribute_string (link, "href"));
-                icon = g_file_icon_new (icon_file);
-                g_loadable_icon_load_async (G_LOADABLE_ICON (icon),
-                    0, NULL, (GAsyncReadyCallback)loadable_icon_finish_cb, web_view);
-            }
-        }
-#endif
-    }
-}
-
-static void
-webkit_web_frame_load_done (WebKitWebFrame* web_frame,
-                            gboolean        success,
-                            MidoriWebView*  web_view)
-{
-    JSContextRef js_context;
-    JSValueRef js_window;
-    GjsValue* value;
-    GjsValue* document;
-    GjsValue* links;
-
-    /* If WebKit didn't emit the signal due to a bug, we will */
-    if (!web_view->window_object_cleared)
-    {
-        js_context = webkit_web_frame_get_global_context (web_frame);
-        js_window = JSContextGetGlobalObject (js_context);
-        g_signal_emit_by_name (web_view, "window-object-cleared",
-            web_frame, js_context, js_window);
-    }
-
-    value = gjs_value_new (webkit_web_frame_get_global_context (web_frame), NULL);
-    document = gjs_value_get_by_name (value, "document");
-    links = gjs_value_get_elements_by_tag_name (document, "link");
-    katze_array_clear (web_view->news_feeds);
-    gjs_value_foreach (links, (GjsCallback)gjs_value_links_foreach_cb, web_view);
-    g_object_unref (links);
-    g_object_unref (document);
-    g_object_unref (value);
-
-    if (web_view->tab_icon)
-        katze_throbber_set_animated (KATZE_THROBBER (web_view->tab_icon),
-                                     FALSE);
-    web_view->load_status = MIDORI_LOAD_FINISHED;
-    g_object_notify (G_OBJECT (web_view), "mload-status");
-}
-
-static void
-webkit_web_view_load_finished (MidoriWebView* web_view)
-{
-    web_view->progress = 1.0;
-    g_object_notify (G_OBJECT (web_view), "progress");
-}
-
-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)
-{
-    katze_assign (web_view->statusbar_text, g_strdup (text));
-    g_object_notify (G_OBJECT (web_view), "statusbar-text");
-}
-
-static void
-webkit_web_view_hovering_over_link (MidoriWebView* web_view,
-                                    const gchar*   tooltip,
-                                    const gchar*   link_uri)
-{
-    katze_assign (web_view->link_uri, g_strdup (link_uri));
-    g_signal_emit (web_view, signals[ELEMENT_MOTION], 0, link_uri);
-}
-
-static gboolean
-gtk_widget_button_press_event_after (MidoriWebView*  web_view,
-                                     GdkEventButton* event)
-{
-    GdkModifierType state;
-    GtkClipboard* clipboard;
-    gchar* uri;
-    gchar* new_uri;
-
-    if (event->button == 2 && sokoke_object_get_boolean
-        (web_view->settings, "middle-click-opens-selection"))
-    {
-        state = (GdkModifierType) event->state;
-        clipboard = gtk_clipboard_get_for_display (
-            gtk_widget_get_display (GTK_WIDGET (web_view)),
-            GDK_SELECTION_PRIMARY);
-        uri = gtk_clipboard_wait_for_text (clipboard);
-        if (uri && strchr (uri, '.') && !strchr (uri, ' '))
-        {
-            new_uri = sokoke_magic_uri (uri, NULL);
-            if (state & GDK_CONTROL_MASK)
-                g_signal_emit (web_view, signals[NEW_TAB], 0, new_uri);
-            else
-            {
-                g_object_set (web_view, "uri", new_uri, NULL);
-                gtk_widget_grab_focus (GTK_WIDGET (web_view));
-            }
-            g_free (new_uri);
-            g_free (uri);
-            return TRUE;
-        }
-    }
-    return FALSE;
-}
-
-static gboolean
-gtk_widget_button_release_event (MidoriWebView*  web_view,
-                                 GdkEventButton* event)
-{
-    GtkClipboard* clipboard;
-    gchar* text;
-
-    /* Emulate the primary clipboard, which WebKit doesn't support */
-    text = webkit_web_view_get_selected_text (WEBKIT_WEB_VIEW (web_view));
-    clipboard = gtk_clipboard_get_for_display (
-        gtk_widget_get_display (GTK_WIDGET (web_view)), GDK_SELECTION_PRIMARY);
-    gtk_clipboard_set_text (clipboard, text, -1);
-    g_free (text);
-    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)
-    {
-        if (event->direction == GDK_SCROLL_DOWN)
-            webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view));
-        else if(event->direction == GDK_SCROLL_UP)
-            webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view));
-        return TRUE;
-    }
-    else
-        return FALSE;
-}
-
-static void
-midori_web_view_menu_new_tab_activate_cb (GtkWidget*     widget,
-                                          MidoriWebView* web_view)
-{
-    const gchar* uri = g_object_get_data (G_OBJECT (widget), "uri");
-    g_signal_emit (web_view, signals[NEW_TAB], 0, uri);
-}
-
-static void
-midori_web_view_menu_new_window_activate_cb (GtkWidget*     widget,
-                                             MidoriWebView* web_view)
-{
-    const gchar* uri = g_object_get_data (G_OBJECT (widget), "uri");
-    g_signal_emit (web_view, signals[NEW_WINDOW], 0, uri);
-}
-
-static void
-midori_web_view_menu_download_activate_cb (GtkWidget*     widget,
-                                           MidoriWebView* web_view)
-{
-    gchar* program;
-    const gchar* uri;
-
-    g_object_get (web_view->settings, "download-manager", &program, NULL);
-    uri = g_object_get_data (G_OBJECT (widget), "uri");
-    sokoke_spawn_program (program, uri);
-    g_free (program);
-}
-
-static void
-webkit_web_view_populate_popup_cb (GtkWidget* web_view,
-                                   GtkWidget* menu)
-{
-    const gchar* uri;
-    GtkWidget* menuitem;
-    GdkScreen* screen;
-    GtkIconTheme* icon_theme;
-    GtkWidget* icon;
-    gchar* text;
-    GList* items;
-    gchar* program;
-
-    uri = midori_web_view_get_link_uri (MIDORI_WEB_VIEW (web_view));
-    if (uri)
-    {
-        menuitem = gtk_image_menu_item_new_with_mnemonic (
-            _("Open Link in New _Tab"));
-        screen = gtk_widget_get_screen (web_view);
-        icon_theme = gtk_icon_theme_get_for_screen (screen);
-        if (gtk_icon_theme_has_icon (icon_theme, STOCK_TAB_NEW))
-        {
-            icon = gtk_image_new_from_stock (STOCK_TAB_NEW, GTK_ICON_SIZE_MENU);
-            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
-        }
-        gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 1);
-        g_object_set_data (G_OBJECT (menuitem), "uri", (gchar*)uri);
-        g_signal_connect (menuitem, "activate",
-            G_CALLBACK (midori_web_view_menu_new_tab_activate_cb), web_view);
-        gtk_widget_show (menuitem);
-        /* hack to implement New Window */
-        items = gtk_container_get_children (GTK_CONTAINER (menu));
-        menuitem = (GtkWidget*)g_list_nth_data (items, 2);
-        g_object_set_data (G_OBJECT (menuitem), "uri", (gchar*)uri);
-        g_signal_connect (menuitem, "activate",
-            G_CALLBACK (midori_web_view_menu_new_window_activate_cb), web_view);
-        menuitem = (GtkWidget*)g_list_nth_data (items, 3);
-        /* hack to disable non-functional Download File */
-        gtk_widget_set_sensitive (menuitem, FALSE);
-        g_list_free (items);
-        g_object_get (MIDORI_WEB_VIEW (web_view)->settings,
-            "download-manager", &program, NULL);
-        if (program && *program)
-        {
-            menuitem = gtk_image_menu_item_new_with_mnemonic (
-                _("Download Link with Download _Manager"));
-            icon = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS,
-                                             GTK_ICON_SIZE_MENU);
-            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
-            gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 4);
-            g_object_set_data (G_OBJECT (menuitem), "uri", (gchar*)uri);
-            g_signal_connect (menuitem, "activate",
-                G_CALLBACK (midori_web_view_menu_download_activate_cb), web_view);
-            gtk_widget_show (menuitem);
-        }
-    }
-
-    if (!uri && midori_web_view_has_selection (MIDORI_WEB_VIEW (web_view)))
-    {
-        text = webkit_web_view_get_selected_text (WEBKIT_WEB_VIEW (web_view));
-        if (text && strchr (text, '.') && !strchr (text, ' '))
-        {
-            menuitem = gtk_image_menu_item_new_with_mnemonic (
-                _("Open URL in New _Tab"));
-            icon = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO,
-                                             GTK_ICON_SIZE_MENU);
-            gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon);
-            gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, -1);
-            g_object_set_data (G_OBJECT (menuitem), "uri", text);
-            g_signal_connect (menuitem, "activate",
-                G_CALLBACK (midori_web_view_menu_new_tab_activate_cb), web_view);
-            gtk_widget_show (menuitem);
-        }
-        /* text should be const, but it is allocated, so we must free it */
-        g_free (text);
-    }
-}
-
-static void
-midori_web_view_init (MidoriWebView* web_view)
-{
-    web_view->icon = gtk_widget_render_icon (GTK_WIDGET (web_view),
-        GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
-    web_view->progress = 0.0;
-    web_view->load_status = MIDORI_LOAD_FINISHED;
-    web_view->news_feeds = katze_array_new (GJS_TYPE_VALUE);
-
-    web_view->settings = midori_web_settings_new ();
-    g_object_set (web_view, "WebKitWebView::settings", web_view->settings, NULL);
-
-    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::window-object-cleared",
-                      webkit_web_view_window_object_cleared_cb, NULL,
-                      "signal::load-committed",
-                      webkit_web_view_load_committed, NULL,
-                      "signal::icon-ready",
-                      webkit_web_view_icon_ready, NULL,
-                      "signal::load-progress-changed",
-                      webkit_web_view_progress_changed, NULL,
-                      "signal::load-finished",
-                      webkit_web_view_load_finished, 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_after, NULL,
-                      "signal::button-release-event",
-                      gtk_widget_button_release_event, NULL,
-                      "signal::scroll-event",
-                      gtk_widget_scroll_event, NULL,
-                      "signal::populate-popup",
-                      webkit_web_view_populate_popup_cb, NULL,
-                      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;
-    WebKitWebFrame* web_frame;
-
-    web_view = MIDORI_WEB_VIEW (object);
-
-    if (web_view->icon)
-        g_object_unref (web_view->icon);
-    g_free (web_view->uri);
-    g_free (web_view->title);
-    g_free (web_view->statusbar_text);
-    g_free (web_view->link_uri);
-    g_object_unref (web_view->news_feeds);
-
-    if (web_view->settings)
-        g_object_unref (web_view->settings);
-
-    if (web_view->xbel_item)
-        katze_xbel_item_unref (web_view->xbel_item);
-
-    web_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
-    g_signal_handlers_disconnect_by_func (web_frame,
-        webkit_web_frame_load_done, web_view);
-
-    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);
-
-    switch (prop_id)
-    {
-    case PROP_URI:
-    {
-        const gchar* uri = g_value_get_string (value);
-        if (uri && *uri)
-            webkit_web_view_open (WEBKIT_WEB_VIEW (web_view), uri);
-        break;
-    }
-    case PROP_TITLE:
-        katze_assign (web_view->title, g_value_dup_string (value));
-        const gchar* title = midori_web_view_get_display_title (web_view);
-        if (web_view->tab_title)
-        {
-            gtk_label_set_text (GTK_LABEL (web_view->tab_title), title);
-            gtk_widget_set_tooltip_text (web_view->tab_title, title);
-        }
-        if (web_view->menu_item)
-            gtk_label_set_text (GTK_LABEL (gtk_bin_get_child (GTK_BIN (
-                                web_view->menu_item))), title);
-        if (web_view->xbel_item)
-            katze_xbel_item_set_title (web_view->xbel_item, title);
-        break;
-    case PROP_SETTINGS:
-        katze_object_assign (web_view->settings, g_value_get_object (value));
-        g_object_ref (web_view->settings);
-        g_object_set (object, "WebKitWebView::settings", web_view->settings, NULL);
-        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);
-
-    switch (prop_id)
-    {
-    case PROP_URI:
-        g_value_set_string (value, web_view->uri);
-        break;
-    case PROP_TITLE:
-        g_value_set_string (value, web_view->title);
-        break;
-    case PROP_PROGRESS:
-        g_value_set_double (value, web_view->progress);
-        break;
-    case PROP_MLOAD_STATUS:
-        g_value_set_enum (value, web_view->load_status);
-        break;
-    case PROP_STATUSBAR_TEXT:
-        g_value_set_string (value, web_view->statusbar_text);
-        break;
-    case PROP_SETTINGS:
-        g_value_set_object (value, web_view->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_set_settings:
- * @web_view: a #MidoriWebView
- * @web_settings: a #MidoriWebSettings
- *
- * Assigns a settings instance to the web view.
- **/
-void
-midori_web_view_set_settings (MidoriWebView*     web_view,
-                              MidoriWebSettings* web_settings)
-{
-    g_object_set (web_view, "settings", web_settings, NULL);
-}
-
-/**
- * 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)
-{
-    const gchar* title;
-
-    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), FALSE);
-
-    if (!web_view->menu_item)
-    {
-        title = midori_web_view_get_display_title (web_view);
-        web_view->menu_item = sokoke_image_menu_item_new_ellipsized (title);
-        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (web_view->menu_item),
-            gtk_image_new_from_pixbuf (web_view->icon));
-
-        g_signal_connect (web_view->menu_item, "destroy",
-                          G_CALLBACK (gtk_widget_destroyed),
-                          &web_view->menu_item);
-    }
-    return web_view->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);
-
-    if (!web_view->tab_icon)
-    {
-        web_view->tab_icon = katze_throbber_new ();
-        katze_throbber_set_static_pixbuf (KATZE_THROBBER (web_view->tab_icon),
-                                          web_view->icon);
-
-        g_signal_connect (web_view->tab_icon, "destroy",
-                          G_CALLBACK (gtk_widget_destroyed),
-                          &web_view->tab_icon);
-    }
-    return web_view->tab_icon;
-}
-
-/**
- * midori_web_view_get_proxy_tab_title:
- * @web_view: a #MidoriWebView
- *
- * Retrieves a proxy tab title that is typically used as the label
- * of a #GtkNotebook page.
- *
- * The title is created on the first call and will be updated to
- * reflect changes automatically.
- *
- * Return value: the proxy #GtkLabel
- **/
-GtkWidget*
-midori_web_view_get_proxy_tab_title (MidoriWebView* web_view)
-{
-    const gchar* title;
-
-    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL);
-
-    if (!web_view->tab_title)
-    {
-        title = midori_web_view_get_display_title (web_view);
-        web_view->tab_title = gtk_label_new (title);
-
-        g_signal_connect (web_view->tab_title, "destroy",
-                          G_CALLBACK (gtk_widget_destroyed),
-                          &web_view->tab_title);
-    }
-    return web_view->tab_title;
-}
-
-/**
- * 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)
-{
-    const gchar* uri;
-    const gchar* title;
-
-    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL);
-
-    if (!web_view->xbel_item)
-    {
-        web_view->xbel_item = katze_xbel_bookmark_new ();
-        uri = midori_web_view_get_display_uri (web_view);
-        katze_xbel_bookmark_set_href (web_view->xbel_item, uri);
-        title = midori_web_view_get_display_title (web_view);
-        katze_xbel_item_set_title (web_view->xbel_item, title);
-    }
-    return web_view->xbel_item;
-}
-
-/**
- * midori_web_view_load_status:
- * @web_view: a #MidoriWebView
- *
- * Determines the current loading status of a page.
- *
- * Return value: the current #MidoriLoadStatus
- **/
-MidoriLoadStatus
-midori_web_view_get_load_status (MidoriWebView* web_view)
-{
-    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), MIDORI_LOAD_FINISHED);
-
-    return web_view->load_status;
-}
-
-/**
- * midori_web_view_get_progress:
- * @web_view: a #MidoriWebView
- *
- * Retrieves the current loading progress as
- * a fraction between 0.0 and 1.0.
- *
- * Return value: the current loading progress
- **/
-gdouble
-midori_web_view_get_progress (MidoriWebView* web_view)
-{
-    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), 0.0);
-
-    return web_view->progress;
-}
-
-/**
- * midori_web_view_get_display_uri:
- * @web_view: a #MidoriWebView
- *
- * Retrieves a string that is suitable for displaying, particularly an
- * empty URI is represented as "".
- *
- * 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), "");
-
-    return web_view->uri ? web_view->uri : "";
-}
-
-/**
- * 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");
-
-    if (web_view->title)
-        return web_view->title;
-    if (web_view->uri)
-        return web_view->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);
-
-    return web_view->link_uri;
-}
-
-/**
- * midori_web_view_get_news_feeds:
- * @web_view: a #MidoriWebView
- *
- * Retrieves a list of news feeds for the current page
- * or %NULL if there are no feeds at all.
- *
- * Return value: a #KatzeArray, or %NULL
- **/
-KatzeArray*
-midori_web_view_get_news_feeds (MidoriWebView* web_view)
-{
-    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL);
-
-    if (!katze_array_is_empty (web_view->news_feeds))
-        return web_view->news_feeds;
-    return NULL;
-}
-
-/**
- * midori_web_view_has_selection:
- * @web_view: a #MidoriWebView
- *
- * Determines whether something on the page is selected.
- *
- * By contrast to webkit_web_view_has_selection() this
- * returns %FALSE if there is a selection that
- * effectively only consists of whitespace.
- *
- * Return value: %TRUE if effectively there is a selection
- **/
-gboolean
-midori_web_view_has_selection (MidoriWebView* web_view)
-{
-    gchar* text;
-
-    g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), FALSE);
-
-    text = webkit_web_view_get_selected_text (WEBKIT_WEB_VIEW (web_view));
-    if (text && *text)
-    {
-        g_free (text);
-        return TRUE;
-    }
-    g_free (text);
-    return FALSE;
-}
diff --git a/midori/midori-webview.h b/midori/midori-webview.h
deleted file mode 100644 (file)
index 8773c1e..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- 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 "midori-websettings.h"
-
-#include <katze/katze.h>
-#include <webkit/webkit.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 _MidoriWebViewClass           MidoriWebViewClass;
-
-struct _MidoriWebViewClass
-{
-    WebKitWebViewClass parent_class;
-
-    /* Signals */
-    void
-    (*icon_ready)             (MidoriWebView*        web_view,
-                               GdkPixbuf*            icon);
-    void
-    (*news_feed_ready)        (MidoriWebView*        web_view,
-                               const gchar*          href,
-                               const gchar*          type,
-                               const gchar*          title);
-    void
-    (*load_done)              (MidoriWebView*        web_view,
-                               WebKitWebFrame*       frame);
-    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);
-};
-
-typedef enum
-{
-    MIDORI_LOAD_PROVISIONAL,
-    MIDORI_LOAD_COMMITTED,
-    MIDORI_LOAD_FINISHED
-} MidoriLoadStatus;
-
-GType
-midori_load_status_get_type (void) G_GNUC_CONST;
-
-#define MIDORI_TYPE_LOAD_STATUS \
-    (midori_load_status_get_type ())
-
-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_icon     (MidoriWebView*     web_view);
-
-GtkWidget*
-midori_web_view_get_proxy_tab_title    (MidoriWebView*     web_view);
-
-KatzeXbelItem*
-midori_web_view_get_proxy_xbel_item    (MidoriWebView*     web_view);
-
-gdouble
-midori_web_view_get_progress           (MidoriWebView*     web_view);
-
-MidoriLoadStatus
-midori_web_view_get_load_status        (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);
-
-KatzeArray*
-midori_web_view_get_news_feeds         (MidoriWebView*     web_view);
-
-gboolean
-midori_web_view_has_selection          (MidoriWebView*     web_view);
-
-G_END_DECLS
-
-#endif /* __MIDORI_WEB_VIEW_H__ */
index 9af538b58b7c341f14bb43ffb74932ee2e1e0a0d..4efd01c8879fb2e31f229dc137f60fe859c02553 100644 (file)
 #include <glib/gi18n.h>
 #include <glib/gprintf.h>
 
+/**
+ * sokoke_remember_argv0:
+ * @argv0: the contents of argv[0] or %NULL
+ *
+ * Stores or retrieves the value of argv[0].
+ *
+ * Call it with a string for argv0 to store.
+ *
+ * Passing %NULL for argv0 will preserve
+ * a previously stored value.
+ *
+ * Return value: the contents of argv[0] or %NULL
+ **/
+const gchar*
+sokoke_remember_argv0 (const gchar* argv0)
+{
+    static const gchar* remembered_argv0 = NULL;
+
+    if (argv0)
+        remembered_argv0 = argv0;
+
+    g_return_val_if_fail (remembered_argv0 != NULL, NULL);
+
+    return remembered_argv0;
+}
+
 static void
 error_dialog (const gchar* short_message,
               const gchar* detailed_message)
@@ -260,9 +286,10 @@ sokoke_widget_popup (GtkWidget*      widget,
         event_time = gtk_get_current_event_time ();
     }
 
-    if (!gtk_menu_get_attach_widget(menu))
+    if (!gtk_menu_get_attach_widget (menu))
         gtk_menu_attach_to_widget (menu, widget, NULL);
 
+
     if (widget)
     {
         SokokePopupInfo info = { widget, pos };
@@ -350,7 +377,7 @@ sokoke_superuser_warning_new (void)
         gtk_widget_modify_fg (GTK_WIDGET (label), GTK_STATE_NORMAL,
             &GTK_WIDGET (label)->style->fg[GTK_STATE_SELECTED]);
         gtk_widget_show (label);
-        gtk_container_add (GTK_CONTAINER(hbox), GTK_WIDGET (label));
+        gtk_container_add (GTK_CONTAINER (hbox), GTK_WIDGET (label));
         gtk_widget_show (hbox);
         return hbox;
     }
@@ -399,7 +426,7 @@ sokoke_on_entry_focus_in_event (GtkEntry*      entry,
     if (has_default)
     {
         gtk_entry_set_text (entry, "");
-        g_object_set_data (G_OBJECT(entry), "sokoke_has_default",
+        g_object_set_data (G_OBJECT (entry), "sokoke_has_default",
                            GINT_TO_POINTER (0));
         sokoke_widget_set_pango_font_style (GTK_WIDGET (entry),
                                             PANGO_STYLE_NORMAL);
@@ -418,7 +445,7 @@ sokoke_on_entry_focus_out_event (GtkEntry*      entry,
         const gchar* default_text = (const gchar*)g_object_get_data (
             G_OBJECT (entry), "sokoke_default_text");
         gtk_entry_set_text (entry, default_text);
-        g_object_set_data (G_OBJECT(entry),
+        g_object_set_data (G_OBJECT (entry),
                            "sokoke_has_default", GINT_TO_POINTER (1));
         sokoke_widget_set_pango_font_style (GTK_WIDGET (entry),
                                             PANGO_STYLE_ITALIC);
index c40ba2bda99473e9e104d326d9ff5fb5486e0f3c..46edc48ec2b08a563dd3985f01a5b15ceb1d06e6 100644 (file)
@@ -19,6 +19,9 @@
 /* Many themes need this hack for small toolbars to work */
 #define GTK_ICON_SIZE_SMALL_TOOLBAR GTK_ICON_SIZE_BUTTON
 
+const gchar*
+sokoke_remember_argv0               (const gchar* argv0);
+
 gboolean
 sokoke_spawn_program                (const gchar* command,
                                      const gchar* argument);