[Xfce4-commits] <midori:master> Move normal, web and private app to frontend

Christian Dywan noreply at xfce.org
Sun Dec 2 16:34:04 CET 2012


Updating branch refs/heads/master
         to ec63fc7795bf951b92645a96b8014c4649517ae4 (commit)
       from 912291ecf85d59486cd71393d703f26cf46de541 (commit)

commit ec63fc7795bf951b92645a96b8014c4649517ae4
Author: Christian Dywan <christian at twotoasts.de>
Date:   Sun Dec 2 13:32:25 2012 +0100

    Move normal, web and private app to frontend
    
    Allow resetting runtime mode in unit tests to allow
    running all modes fully in tests.

 katze/midori-paths.vala  |    6 +
 midori/main.c            |  433 ++-----------------------------------
 midori/midori-app.c      |  181 +---------------
 midori/midori-app.h      |   16 --
 midori/midori-frontend.c |  554 ++++++++++++++++++++++++++++++++++++++++++++++
 midori/midori-frontend.h |   49 ++++
 midori/midori.h          |    1 +
 midori/midori.vapi       |    9 +
 po/POTFILES.in           |    1 +
 tests/app.vala           |   56 +++++
 10 files changed, 691 insertions(+), 615 deletions(-)

diff --git a/katze/midori-paths.vala b/katze/midori-paths.vala
index 8f51a5d..e88c0ac 100644
--- a/katze/midori-paths.vala
+++ b/katze/midori-paths.vala
@@ -43,6 +43,12 @@ namespace Midori {
         static string? user_data_dir_for_reading = null;
         static string? tmp_dir = null;
 
+        namespace Test {
+            public void reset_runtime_mode () {
+                mode = RuntimeMode.UNDEFINED;
+            }
+        }
+
         public static string get_config_dir_for_reading () {
             assert (mode != RuntimeMode.UNDEFINED);
             return readonly_dir ?? config_dir;
diff --git a/midori/main.c b/midori/main.c
index 2140074..7fb8a7a 100644
--- a/midori/main.c
+++ b/midori/main.c
@@ -10,16 +10,8 @@
  See the file COPYING for the full license text.
 */
 
-#include "midori-app.h"
-#include "midori-array.h"
-#include "midori-bookmarks.h"
-#include "panels/midori-bookmarks.h"
-#include "midori-history.h"
-#include "panels/midori-history.h"
-#include "midori-transfers.h"
-#include "midori-panel.h"
+#include "midori-frontend.h"
 #include "midori-platform.h"
-#include "midori-preferences.h"
 #include "midori-privatedata.h"
 #include "midori-searchaction.h"
 #include "midori/midori-session.h"
@@ -38,186 +30,6 @@
 #include <webkit/webkit.h>
 #include <sqlite3.h>
 
-static void
-midori_trash_add_item_no_save_cb (KatzeArray* trash,
-                                  GObject*    item)
-{
-    if (katze_array_get_nth_item (trash, 10))
-    {
-        KatzeItem* obsolete_item = katze_array_get_nth_item (trash, 0);
-        katze_array_remove_item (trash, obsolete_item);
-    }
-}
-
-static void
-midori_trash_remove_item_cb (KatzeArray* trash,
-                             GObject*    item)
-{
-    gchar* config_file = midori_paths_get_config_filename_for_writing ("tabtrash.xbel");
-    GError* error = NULL;
-    midori_trash_add_item_no_save_cb (trash, item);
-    if (!midori_array_to_file (trash, config_file, "xbel", &error))
-    {
-        /* i18n: Trash, or wastebin, containing closed tabs */
-        g_warning (_("The trash couldn't be saved. %s"), error->message);
-        g_error_free (error);
-    }
-    g_free (config_file);
-}
-
-static void
-midori_trash_add_item_cb (KatzeArray* trash,
-                          GObject*    item)
-{
-    midori_trash_remove_item_cb (trash, item);
-}
-
-static void
-midori_browser_show_preferences_cb (MidoriBrowser*    browser,
-                                    KatzePreferences* preferences,
-                                    MidoriApp*        app)
-{
-    midori_preferences_add_extension_category (preferences, app);
-}
-
-static void
-midori_browser_privacy_preferences_cb (MidoriBrowser*    browser,
-                                       KatzePreferences* preferences,
-                                       MidoriApp*        app)
-{
-    MidoriWebSettings* settings = midori_browser_get_settings (browser);
-    midori_preferences_add_privacy_category (preferences, settings);
-}
-
-static void
-midori_app_add_browser_cb (MidoriApp*     app,
-                           MidoriBrowser* browser,
-                           KatzeNet*      net)
-{
-    GtkWidget* panel;
-    GtkWidget* addon;
-
-    panel = katze_object_get_object (browser, "panel");
-
-    addon = g_object_new (MIDORI_TYPE_BOOKMARKS, "app", app, "visible", TRUE, NULL);
-    midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
-
-    addon = g_object_new (MIDORI_TYPE_HISTORY, "app", app, "visible", TRUE, NULL);
-    midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
-
-    addon = g_object_new (MIDORI_TYPE_TRANSFERS, "app", app, "visible", TRUE, NULL);
-    midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
-
-    /* Extensions */
-    g_signal_connect (browser, "show-preferences",
-        G_CALLBACK (midori_browser_privacy_preferences_cb), app);
-    g_signal_connect (browser, "show-preferences",
-        G_CALLBACK (midori_browser_show_preferences_cb), app);
-
-    g_object_unref (panel);
-}
-
-static void
-button_modify_preferences_clicked_cb (GtkWidget*         button,
-                                      MidoriWebSettings* settings)
-{
-    GtkWidget* dialog = midori_preferences_new (
-        GTK_WINDOW (gtk_widget_get_toplevel (button)), settings);
-    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_DELETE_EVENT)
-        gtk_widget_destroy (dialog);
-}
-
-static void
-button_disable_extensions_clicked_cb (GtkWidget* button,
-                                      MidoriApp* app)
-{
-    /* Reset frozen list of active extensions */
-    g_object_set_data (G_OBJECT (app), "extensions", NULL);
-    gtk_widget_set_sensitive (button, FALSE);
-}
-
-static MidoriStartup
-midori_show_diagnostic_dialog (MidoriWebSettings* settings,
-                               KatzeArray*        session)
-{
-    GtkWidget* dialog;
-    GtkWidget* content_area;
-    GtkWidget* align;
-    GtkWidget* box;
-    GtkWidget* button;
-    MidoriApp* app = katze_item_get_parent (KATZE_ITEM (session));
-    MidoriStartup load_on_startup = katze_object_get_enum (settings, "load-on-startup");
-    gint response;
-
-    dialog = gtk_message_dialog_new (
-        NULL, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
-        _("Midori seems to have crashed the last time it was opened. "
-          "If this happened repeatedly, try one of the following options "
-          "to solve the problem."));
-    gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE);
-    gtk_window_set_title (GTK_WINDOW (dialog), g_get_application_name ());
-    content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-    align = gtk_alignment_new (0.5, 0.5, 0.5, 0.5);
-    gtk_container_add (GTK_CONTAINER (content_area), align);
-    box = gtk_hbox_new (FALSE, 0);
-    gtk_container_add (GTK_CONTAINER (align), box);
-    button = gtk_button_new_with_mnemonic (_("Modify _preferences"));
-    g_signal_connect (button, "clicked",
-        G_CALLBACK (button_modify_preferences_clicked_cb), settings);
-    gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 4);
-    button = gtk_button_new_with_mnemonic (_("Disable all _extensions"));
-    if (g_object_get_data (G_OBJECT (app), "extensions"))
-        g_signal_connect (button, "clicked",
-            G_CALLBACK (button_disable_extensions_clicked_cb), app);
-    else
-        gtk_widget_set_sensitive (button, FALSE);
-    gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 4);
-    gtk_widget_show_all (align);
-    button = katze_property_proxy (settings, "show-crash-dialog", NULL);
-    gtk_button_set_label (GTK_BUTTON (button), _("Show a dialog after Midori crashed"));
-    gtk_widget_show (button);
-    gtk_container_add (GTK_CONTAINER (content_area), button);
-    gtk_container_set_focus_child (GTK_CONTAINER (dialog), gtk_dialog_get_action_area (GTK_DIALOG (dialog)));
-    gtk_dialog_add_buttons (GTK_DIALOG (dialog),
-        _("Discard old tabs"), MIDORI_STARTUP_BLANK_PAGE,
-        _("Show last tabs without loading"), MIDORI_STARTUP_DELAYED_PAGES,
-        _("Show last open tabs"), MIDORI_STARTUP_LAST_OPEN_PAGES,
-        NULL);
-    gtk_dialog_set_default_response (GTK_DIALOG (dialog),
-        load_on_startup == MIDORI_STARTUP_HOMEPAGE
-        ? MIDORI_STARTUP_BLANK_PAGE : load_on_startup);
-    if (1)
-    {
-        /* GtkLabel can't wrap the text properly. Until some day
-           this works, we implement this hack to do it ourselves. */
-        GtkWidget* hbox;
-        GtkWidget* vbox;
-        GtkWidget* label;
-        GList* ch;
-        GtkRequisition req;
-
-        ch = gtk_container_get_children (GTK_CONTAINER (content_area));
-        hbox = (GtkWidget*)g_list_nth_data (ch, 0);
-        g_list_free (ch);
-        ch = gtk_container_get_children (GTK_CONTAINER (hbox));
-        vbox = (GtkWidget*)g_list_nth_data (ch, 1);
-        g_list_free (ch);
-        ch = gtk_container_get_children (GTK_CONTAINER (vbox));
-        label = (GtkWidget*)g_list_nth_data (ch, 0);
-        g_list_free (ch);
-        gtk_widget_size_request (content_area, &req);
-        gtk_widget_set_size_request (label, req.width * 0.9, -1);
-    }
-
-    response = gtk_dialog_run (GTK_DIALOG (dialog));
-    gtk_widget_destroy (dialog);
-    if (response == GTK_RESPONSE_DELETE_EVENT)
-        response = G_MAXINT;
-    else if (response == MIDORI_STARTUP_BLANK_PAGE)
-        katze_array_clear (session);
-    return response;
-}
-
 #define HAVE_OFFSCREEN GTK_CHECK_VERSION (2, 20, 0)
 
 static void
@@ -260,8 +72,7 @@ main (int    argc,
     gboolean private;
     gboolean portable;
     gboolean plain;
-    gboolean diagnostic_dialog;
-    gboolean back_from_crash;
+    gboolean diagnostic_dialog = FALSE;
     gboolean run;
     gchar* snapshot;
     gboolean execute;
@@ -270,9 +81,6 @@ main (int    argc,
     gchar** uris;
     gchar* block_uris;
     gint inactivity_reset;
-    MidoriApp* app;
-    gboolean result;
-    GError* error;
     GOptionEntry entries[] =
     {
        { "app", 'a', 0, G_OPTION_ARG_STRING, &webapp,
@@ -310,29 +118,6 @@ main (int    argc,
        #endif
      { NULL }
     };
-    GString* error_messages;
-    gchar** extensions;
-    MidoriWebSettings* settings;
-    gchar* config_file;
-    MidoriSpeedDial* dial;
-    MidoriStartup load_on_startup;
-    KatzeArray* search_engines;
-    KatzeArray* bookmarks;
-    KatzeArray* history;
-    KatzeArray* session;
-    KatzeArray* trash;
-    guint i;
-    gchar* uri;
-    KatzeItem* item;
-    gchar* uri_ready;
-    gchar* errmsg;
-    #ifdef G_ENABLE_DEBUG
-        gboolean startup_timer = midori_debug ("startup");
-        #define midori_startup_timer(tmrmsg) if (startup_timer) \
-            g_debug (tmrmsg, (g_test_timer_last () - g_test_timer_elapsed ()) * -1)
-    #else
-        #define midori_startup_timer(tmrmsg)
-    #endif
 
     /* Parse cli options */
     webapp = NULL;
@@ -340,8 +125,6 @@ main (int    argc,
     private = FALSE;
     portable = FALSE;
     plain = FALSE;
-    back_from_crash = FALSE;
-    diagnostic_dialog = FALSE;
     run = FALSE;
     snapshot = NULL;
     execute = FALSE;
@@ -350,7 +133,6 @@ main (int    argc,
     uris = NULL;
     block_uris = NULL;
     inactivity_reset = 0;
-    error = NULL;
     midori_app_setup (&argc, &argv, entries);
 
     g_set_application_name (_("Midori"));
@@ -413,21 +195,20 @@ main (int    argc,
 
     if (snapshot)
     {
+        GError* error = NULL;
         gchar* filename;
-        gint fd;
         GtkWidget* web_view;
         gchar* uri;
         #if HAVE_OFFSCREEN
         GtkWidget* offscreen;
         GdkScreen* screen;
 
-        fd = g_file_open_tmp ("snapshot-XXXXXX.png", &filename, &error);
+        gint fd = g_file_open_tmp ("snapshot-XXXXXX.png", &filename, &error);
         #else
-        fd = g_file_open_tmp ("snapshot-XXXXXX.pdf", &filename, &error);
+        gint fd = g_file_open_tmp ("snapshot-XXXXXX.pdf", &filename, &error);
         #endif
         close (fd);
 
-        error = NULL;
         if (error)
         {
             g_error ("%s", error->message);
@@ -489,18 +270,15 @@ main (int    argc,
 
     midori_private_data_register_built_ins ();
 
-    if (webapp || private || run)
-        midori_startup_timer ("Browser: \t%f");
-
     if (run)
     {
         gchar* script = NULL;
-        error = NULL;
+        GError* error = NULL;
 
         if (g_file_get_contents (uris ? *uris : NULL, &script, NULL, &error))
         {
             MidoriBrowser* browser = midori_browser_new ();
-            settings = midori_browser_get_settings (browser);
+            MidoriWebSettings* settings = midori_browser_get_settings (browser);
             g_object_set_data (G_OBJECT (webkit_get_default_session ()), "pass-through-console", (void*)1);
             midori_load_soup_session (settings);
 
@@ -533,7 +311,6 @@ main (int    argc,
     {
         midori_private_app_new (config, webapp,
             execute ? NULL : uris, execute ? uris : NULL, inactivity_reset, block_uris);
-        midori_startup_timer ("Private App created: \t%f");
         gtk_main ();
         return 0;
     }
@@ -542,201 +319,19 @@ main (int    argc,
     {
         midori_web_app_new (config, webapp,
             execute ? NULL : uris, execute ? uris : NULL, inactivity_reset, block_uris);
-        midori_startup_timer ("Web App created: \t%f");
         gtk_main ();
         return 0;
     }
 
-    if (portable)
-        midori_paths_init (MIDORI_RUNTIME_MODE_PORTABLE, config);
-    else
-        midori_paths_init (MIDORI_RUNTIME_MODE_NORMAL, config);
-
-    app = midori_app_new ();
-    midori_startup_timer ("App created: \t%f");
-
-    /* FIXME: The app might be 'running' but actually showing a dialog
-              after a crash, so running a new window isn't a good idea. */
-    if (midori_app_instance_is_running (app))
-    {
-        GtkWidget* dialog;
-
-        if (execute)
-            result = midori_app_send_command (app, uris);
-        else if (uris)
-            result = midori_app_instance_send_uris (app, uris);
-        else
-            result = midori_app_instance_send_new_browser (app);
-
-        if (result)
-            return 0;
-
-        sokoke_message_dialog (GTK_MESSAGE_INFO,
-            _("An instance of Midori is already running but not responding.\n"),
-            "", TRUE);
-        /* FIXME: Allow killing the existing instance */
+    MidoriApp* app = midori_normal_app_new (config, portable, diagnostic_dialog, webapp,
+        execute ? NULL : uris, execute ? uris : NULL, inactivity_reset, block_uris);
+    if (app == NULL)
+        return 0;
+    if (app == (void*)0xdeadbeef)
         return 1;
-    }
-
-    katze_assign (config, g_strdup (midori_paths_get_config_dir_for_writing ()));
-    /* Load configuration file */
-    error_messages = g_string_new (NULL);
-    error = NULL;
-    settings = midori_settings_new_full (&extensions);
-    g_object_set (settings,
-                  "enable-developer-extras", TRUE,
-                  "enable-html5-database", TRUE,
-                  "block-uris", block_uris,
-                  NULL);
-    if (inactivity_reset > 0)
-        g_object_set (settings, "inactivity-reset", inactivity_reset, NULL);
-    midori_startup_timer ("Config and accels read: \t%f");
-
-    /* Load search engines */
-    search_engines = midori_search_engines_new_from_folder (error_messages);
-    /* Pick first search engine as default if not set */
-    g_object_get (settings, "location-entry-search", &uri, NULL);
-    if (!(uri && *uri) && !katze_array_is_empty (search_engines))
-    {
-        item = katze_array_get_nth_item (search_engines, 0);
-        g_object_set (settings, "location-entry-search",
-                      katze_item_get_uri (item), NULL);
-    }
-    g_free (uri);
-    midori_startup_timer ("Search read: \t%f");
-
-    errmsg = NULL;
-    if (!(bookmarks = midori_bookmarks_new (&errmsg)))
-    {
-        g_string_append_printf (error_messages,
-            _("Bookmarks couldn't be loaded: %s\n"), errmsg);
-        katze_assign (errmsg, NULL);
-    }
-    midori_startup_timer ("Bookmarks read: \t%f");
-
-    config_file = NULL;
-    session = katze_array_new (KATZE_TYPE_ITEM);
-    load_on_startup = katze_object_get_enum (settings, "load-on-startup");
-    if (load_on_startup >= MIDORI_STARTUP_LAST_OPEN_PAGES)
-    {
-        katze_assign (config_file, midori_paths_get_config_filename_for_reading ("session.xbel"));
-        error = NULL;
-        if (!midori_array_from_file (session, config_file, "xbel", &error))
-        {
-            if (error->code != G_FILE_ERROR_NOENT)
-                g_string_append_printf (error_messages,
-                    _("The session couldn't be loaded: %s\n"), error->message);
-            g_error_free (error);
-        }
-    }
-    midori_startup_timer ("Session read: \t%f");
-
-    trash = katze_array_new (KATZE_TYPE_ITEM);
-    g_signal_connect_after (trash, "add-item",
-        G_CALLBACK (midori_trash_add_item_cb), NULL);
-    g_signal_connect_after (trash, "remove-item",
-        G_CALLBACK (midori_trash_remove_item_cb), NULL);
-    katze_assign (config_file, g_build_filename (config, "tabtrash.xbel", NULL));
-    error = NULL;
-    if (!midori_array_from_file (trash, config_file, "xbel", &error))
-    {
-        if (error->code != G_FILE_ERROR_NOENT)
-            g_string_append_printf (error_messages,
-                _("The trash couldn't be loaded: %s\n"), error->message);
-        g_error_free (error);
-    }
-    midori_startup_timer ("Trash read: \t%f");
-
-    if (!(history = midori_history_new (&errmsg)))
-    {
-        g_string_append_printf (error_messages,
-            _("The history couldn't be loaded: %s\n"), errmsg);
-        katze_assign (errmsg, NULL);
-    }
-    midori_startup_timer ("History read: \t%f");
-
-    katze_assign (config_file, g_build_filename (config, "speeddial", NULL));
-    dial = midori_speed_dial_new (config_file, NULL);
-
-    /* In case of errors */
-    if (error_messages->len)
-    {
-        GtkWidget* dialog = gtk_message_dialog_new (
-            NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE,
-            _("The following errors occured:"));
-        gtk_message_dialog_format_secondary_text (
-            GTK_MESSAGE_DIALOG (dialog), "%s", error_messages->str);
-        gtk_dialog_add_buttons (GTK_DIALOG (dialog),
-                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                _("_Ignore"), GTK_RESPONSE_ACCEPT,
-                                NULL);
-        if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT)
-            return 0;
-        gtk_widget_destroy (dialog);
-        /* FIXME: Since we will overwrite files that could not be loaded
-                  , would we want to make backups? */
-    }
-    g_string_free (error_messages, TRUE);
-
-    /* If -e or --execute was specified, "uris" refers to the command. */
-    if (execute)
-        g_object_set_data (G_OBJECT (app), "execute-commands", uris);
-    else
-        g_object_set_data (G_OBJECT (app), "open-uris", uris);
-    g_object_set_data_full (G_OBJECT (app), "extensions", extensions, (GDestroyNotify)g_strfreev);
-    katze_item_set_parent (KATZE_ITEM (session), app);
-
-    katze_assign (config_file, g_build_filename (config, "search", NULL));
-    midori_search_engines_set_filename (search_engines, config_file);
-
-    if (midori_app_get_crashed (app)
-     && katze_object_get_boolean (settings, "show-crash-dialog")
-     && uris && *uris && !execute)
-        diagnostic_dialog = TRUE;
-    if (diagnostic_dialog)
-    {
-        load_on_startup = midori_show_diagnostic_dialog (settings, session);
-        if (load_on_startup == G_MAXINT)
-            return 0;
-    }
-    g_object_set_data (G_OBJECT (settings), "load-on-startup", GINT_TO_POINTER (load_on_startup));
-    midori_startup_timer ("Signal setup: \t%f");
-
-    g_object_set (app, "settings", settings,
-                       "bookmarks", bookmarks,
-                       "trash", trash,
-                       "search-engines", search_engines,
-                       "history", history,
-                       "speed-dial", dial,
-                       NULL);
-    g_object_unref (history);
-    g_object_unref (search_engines);
-    g_object_unref (bookmarks);
-    g_object_unref (trash);
-    g_signal_connect (app, "add-browser",
-        G_CALLBACK (midori_app_add_browser_cb), NULL);
-    midori_startup_timer ("App prepared: \t%f");
-
-    g_idle_add (midori_load_soup_session_full, settings);
-    g_idle_add (midori_load_extensions, app);
-    g_idle_add (midori_load_session, session);
 
     gtk_main ();
-
-    g_object_notify (G_OBJECT (settings), "load-on-startup");
-    midori_bookmarks_on_quit (bookmarks);
-    midori_history_on_quit (history, settings);
-    midori_private_data_on_quit (settings);
-    /* Removing KatzeHttpCookies makes it save outstanding changes */
-    soup_session_remove_feature_by_type (webkit_get_default_session (),
-                                         KATZE_TYPE_HTTP_COOKIES);
-
-    load_on_startup = katze_object_get_int (settings, "load-on-startup");
-    if (load_on_startup < MIDORI_STARTUP_LAST_OPEN_PAGES)
-    {
-        katze_assign (config_file, midori_paths_get_config_filename_for_writing ("session.xbel"));
-        g_unlink (config_file);
-    }
-
+    midori_normal_app_on_quit (app);
     return 0;
 }
+
diff --git a/midori/midori-app.c b/midori/midori-app.c
index d4ab919..495dfd8 100644
--- a/midori/midori-app.c
+++ b/midori/midori-app.c
@@ -22,8 +22,6 @@
 #include "midori-app.h"
 #include "midori-platform.h"
 #include "midori-core.h"
-#include "midori-session.h"
-#include "midori-searchaction.h"
 
 #include <string.h>
 #include <gtk/gtk.h>
@@ -1010,183 +1008,6 @@ midori_app_new (void)
     return app;
 }
 
-static MidoriBrowser*
-midori_web_app_browser_new_window_cb (MidoriBrowser* browser,
-                                      MidoriBrowser* new_browser,
-                                      gpointer       user_data)
-{
-    if (new_browser == NULL)
-        new_browser = midori_browser_new ();
-    g_object_set (new_browser,
-        "settings", midori_browser_get_settings (browser),
-        NULL);
-    gtk_widget_show (GTK_WIDGET (new_browser));
-    return new_browser;
-}
-
-void
-midori_web_app_new (const gchar* config,
-                    const gchar* webapp,
-                    gchar**      open_uris,
-                    gchar**      execute_commands,
-                    gint         inactivity_reset,
-                    const gchar* block_uris)
-{
-    midori_paths_init (MIDORI_RUNTIME_MODE_APP, config);
-    g_object_set_data (G_OBJECT (webkit_get_default_session ()), "pass-through-console", (void*)1);
-
-    MidoriBrowser* browser = midori_browser_new ();
-    g_signal_connect (browser, "new-window",
-        G_CALLBACK (midori_web_app_browser_new_window_cb), NULL);
-
-    gchar* tmp_uri = sokoke_prepare_uri (webapp);
-    midori_browser_set_action_visible (browser, "Menubar", FALSE);
-    midori_browser_set_action_visible (browser, "CompactMenu", FALSE);
-
-    MidoriWebSettings* settings = midori_browser_get_settings (browser);
-    g_object_set (settings,
-                  "show-menubar", FALSE,
-                  "show-navigationbar", FALSE,
-                  "toolbar-items", "Back,Forward,ReloadStop,Location,Homepage",
-                  "show-statusbar", FALSE,
-                  "homepage", tmp_uri,
-                  "show-panel", FALSE,
-                  "last-window-state", MIDORI_WINDOW_NORMAL,
-                  "inactivity-reset", inactivity_reset,
-                  "block-uris", block_uris,
-                  NULL);
-    midori_load_soup_session (settings);
-
-    KatzeArray* search_engines = midori_search_engines_new_from_folder (NULL);
-    g_object_set (browser,
-                  "show-tabs", open_uris != NULL,
-                  NULL);
-    midori_browser_set_action_visible (browser, "Panel", FALSE);
-    g_object_unref (search_engines);
-
-    midori_browser_add_uri (browser, tmp_uri);
-    g_free (tmp_uri);
-    g_signal_connect (browser, "quit", G_CALLBACK (gtk_main_quit), NULL);
-    g_signal_connect (browser, "destroy", G_CALLBACK (gtk_main_quit), NULL);
-    gtk_widget_show (GTK_WIDGET (browser));
-
-    guint i;
-    if (open_uris != NULL)
-        for (i = 0; open_uris[i] != NULL; i++)
-        {
-            gchar* new_uri = sokoke_prepare_uri (open_uris[i]);
-            midori_browser_add_uri (browser, new_uri);
-            g_free (new_uri);
-        }
-
-    if (execute_commands != NULL)
-        for (i = 0; execute_commands[i] != NULL; i++)
-            midori_browser_activate_action (browser, execute_commands[i]);
-}
-
-static void
-midori_trash_add_item_no_save_cb (KatzeArray* trash,
-                                  GObject*    item)
-{
-    if (katze_array_get_nth_item (trash, 10))
-    {
-        KatzeItem* obsolete_item = katze_array_get_nth_item (trash, 0);
-        katze_array_remove_item (trash, obsolete_item);
-    }
-}
-
-void
-midori_private_app_new (const gchar* config,
-                        const gchar* webapp,
-                        gchar**      open_uris,
-                        gchar**      execute_commands,
-                        gint         inactivity_reset,
-                        const gchar* block_uris)
-{
-    midori_paths_init (MIDORI_RUNTIME_MODE_PRIVATE, config);
-    g_object_set_data (G_OBJECT (webkit_get_default_session ()), "pass-through-console", (void*)1);
-
-    /* Mask the timezone, which can be read by Javascript */
-    g_setenv ("TZ", "UTC", TRUE);
-
-    MidoriBrowser* browser = midori_browser_new ();
-    g_signal_connect (browser, "new-window",
-        G_CALLBACK (midori_web_app_browser_new_window_cb), NULL);
-
-    MidoriWebSettings* settings = midori_settings_new_full (NULL);
-    g_object_set (settings,
-                  "preferred-languages", "en",
-                  "enable-private-browsing", TRUE,
-    #ifdef HAVE_LIBSOUP_2_29_91
-                  "first-party-cookies-only", TRUE,
-    #endif
-                  "enable-html5-database", FALSE,
-                  "enable-html5-local-storage", FALSE,
-                  "enable-offline-web-application-cache", FALSE,
-    /* Arguably DNS prefetching is or isn't a privacy concern. For the
-     * lack of more fine-grained control we'll go the safe route. */
-    #if WEBKIT_CHECK_VERSION (1, 3, 11)
-                  "enable-dns-prefetching", FALSE,
-    #endif
-                  "strip-referer", TRUE,
-                  "show-panel", FALSE,
-                  "last-window-state", MIDORI_WINDOW_NORMAL,
-                  "inactivity-reset", inactivity_reset,
-                  "block-uris", block_uris,
-                  NULL);
-    midori_load_soup_session (settings);
-
-    /* In-memory trash for re-opening closed tabs */
-    KatzeArray* trash = katze_array_new (KATZE_TYPE_ITEM);
-    g_signal_connect_after (trash, "add-item",
-      G_CALLBACK (midori_trash_add_item_no_save_cb), NULL);
-
-    KatzeArray* search_engines = midori_search_engines_new_from_folder (NULL);
-    g_object_set (browser,
-                  "settings", settings,
-                  "trash", trash,
-                  "search-engines", search_engines,
-                  NULL);
-    g_object_unref (settings);
-    g_object_unref (trash);
-    g_object_unref (search_engines);
-
-    midori_browser_set_action_visible (browser, "Tools", FALSE);
-    midori_browser_set_action_visible (browser, "ClearPrivateData", FALSE);
-    midori_browser_set_action_visible (browser, "Panel", FALSE);
-    #if GTK_CHECK_VERSION (3, 0, 0)
-    g_object_set (gtk_widget_get_settings (GTK_WIDGET (browser)),
-                  "gtk-application-prefer-dark-theme", TRUE,
-                  NULL);
-    #endif
-
-    if (webapp != NULL)
-    {
-        gchar* tmp_uri = sokoke_prepare_uri (webapp);
-        midori_browser_add_uri (browser, tmp_uri);
-        g_free (tmp_uri);
-    }
-    else if (open_uris == NULL)
-        midori_browser_add_uri (browser, "about:private");
-
-    g_signal_connect (browser, "quit", G_CALLBACK (gtk_main_quit), NULL);
-    g_signal_connect (browser, "destroy", G_CALLBACK (gtk_main_quit), NULL);
-    gtk_widget_show (GTK_WIDGET (browser));
-
-    guint i;
-    if (open_uris != NULL)
-        for (i = 0; open_uris[i] != NULL; i++)
-        {
-            gchar* new_uri = sokoke_prepare_uri (open_uris[i]);
-            midori_browser_add_uri (browser, new_uri);
-            g_free (new_uri);
-        }
-
-    if (execute_commands != NULL)
-        for (i = 0; execute_commands[i] != NULL; i++)
-            midori_browser_activate_action (browser, execute_commands[i]);
-}
-
 /**
  * midori_app_instance_is_running:
  * @app: a #MidoriApp
@@ -1378,7 +1199,7 @@ midori_app_send_command (MidoriApp* app,
     UniqueResponse response;
     #endif
 
-    /* g_return_val_if_fail (MIDORI_IS_APP (app), FALSE); */
+    g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
     g_return_val_if_fail (command != NULL, FALSE);
 
     if (midori_app_instance_is_running (app))
diff --git a/midori/midori-app.h b/midori/midori-app.h
index e89bcb4..b63034d 100644
--- a/midori/midori-app.h
+++ b/midori/midori-app.h
@@ -41,22 +41,6 @@ midori_app_get_type               (void) G_GNUC_CONST;
 MidoriApp*
 midori_app_new                    (void);
 
-void
-midori_web_app_new (const gchar* config,
-                    const gchar* webapp,
-                    gchar**      open_uris,
-                    gchar**      execute_commands,
-                    gint         inactivity_reset,
-                    const gchar* block_uris);
-
-void
-midori_private_app_new (const gchar* config,
-                        const gchar* webapp,
-                        gchar**      open_uris,
-                        gchar**      execute_commands,
-                        gint         inactivity_reset,
-                        const gchar* block_uris);
-
 const gchar*
 midori_app_get_name               (MidoriApp*         app);
 
diff --git a/midori/midori-frontend.c b/midori/midori-frontend.c
new file mode 100644
index 0000000..b6c68b9
--- /dev/null
+++ b/midori/midori-frontend.c
@@ -0,0 +1,554 @@
+/*
+ Copyright (C) 2008-2012 Christian Dywan <christian at twotoasts.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ See the file COPYING for the full license text.
+*/
+
+#include "midori-array.h"
+#include "midori-bookmarks.h"
+#include "midori-history.h"
+#include "midori-preferences.h"
+#include "midori-privatedata.h"
+#include "midori-session.h"
+#include "midori-searchaction.h"
+#include "midori-panel.h"
+#include "panels/midori-bookmarks.h"
+#include "panels/midori-history.h"
+#include "panels/midori-transfers.h"
+#include "sokoke.h"
+#include <glib/gi18n-lib.h>
+
+static MidoriBrowser*
+midori_frontend_browser_new_window_cb (MidoriBrowser* browser,
+                                       MidoriBrowser* new_browser,
+                                       gpointer       user_data)
+{
+    if (new_browser == NULL)
+        new_browser = midori_browser_new ();
+    g_object_set (new_browser,
+        "settings", midori_browser_get_settings (browser),
+        NULL);
+    gtk_widget_show (GTK_WIDGET (new_browser));
+    return new_browser;
+}
+
+void
+midori_web_app_new (const gchar* config,
+                    const gchar* webapp,
+                    gchar**      open_uris,
+                    gchar**      execute_commands,
+                    gint         inactivity_reset,
+                    const gchar* block_uris)
+{
+    midori_paths_init (MIDORI_RUNTIME_MODE_APP, config);
+    g_object_set_data (G_OBJECT (webkit_get_default_session ()), "pass-through-console", (void*)1);
+
+    MidoriBrowser* browser = midori_browser_new ();
+    g_signal_connect (browser, "new-window",
+        G_CALLBACK (midori_frontend_browser_new_window_cb), NULL);
+
+    midori_browser_set_action_visible (browser, "Menubar", FALSE);
+    midori_browser_set_action_visible (browser, "CompactMenu", FALSE);
+
+    MidoriWebSettings* settings = midori_browser_get_settings (browser);
+    g_object_set (settings,
+                  "show-menubar", FALSE,
+                  "show-navigationbar", FALSE,
+                  "toolbar-items", "Back,Forward,ReloadStop,Location,Homepage",
+                  "show-statusbar", FALSE,
+                  "show-panel", FALSE,
+                  "last-window-state", MIDORI_WINDOW_NORMAL,
+                  "inactivity-reset", inactivity_reset,
+                  "block-uris", block_uris,
+                  NULL);
+    midori_load_soup_session (settings);
+
+    KatzeArray* search_engines = midori_search_engines_new_from_folder (NULL);
+    g_object_set (browser,
+                  "show-tabs", open_uris != NULL,
+                  NULL);
+    midori_browser_set_action_visible (browser, "Panel", FALSE);
+    g_object_unref (search_engines);
+
+    if (webapp != NULL)
+    {
+        gchar* tmp_uri = sokoke_prepare_uri (webapp);
+        g_object_set (settings, "homepage", tmp_uri, NULL);
+        midori_browser_add_uri (browser, tmp_uri);
+        g_free (tmp_uri);
+    }
+    else if (open_uris == NULL)
+        midori_browser_add_uri (browser, "about:private");
+
+    g_signal_connect (browser, "quit", G_CALLBACK (gtk_main_quit), NULL);
+    g_signal_connect (browser, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+    gtk_widget_show (GTK_WIDGET (browser));
+
+    guint i;
+    if (open_uris != NULL)
+        for (i = 0; open_uris[i] != NULL; i++)
+        {
+            gchar* new_uri = sokoke_prepare_uri (open_uris[i]);
+            midori_browser_add_uri (browser, new_uri);
+            g_free (new_uri);
+        }
+
+    if (execute_commands != NULL)
+        for (i = 0; execute_commands[i] != NULL; i++)
+            midori_browser_activate_action (browser, execute_commands[i]);
+}
+
+static void
+midori_trash_add_item_no_save_cb (KatzeArray* trash,
+                                  GObject*    item)
+{
+    if (katze_array_get_nth_item (trash, 10))
+    {
+        KatzeItem* obsolete_item = katze_array_get_nth_item (trash, 0);
+        katze_array_remove_item (trash, obsolete_item);
+    }
+}
+
+static void
+midori_trash_remove_item_cb (KatzeArray* trash,
+                             GObject*    item)
+{
+    gchar* config_file = midori_paths_get_config_filename_for_writing ("tabtrash.xbel");
+    GError* error = NULL;
+    midori_trash_add_item_no_save_cb (trash, item);
+    if (!midori_array_to_file (trash, config_file, "xbel", &error))
+    {
+        /* i18n: Trash, or wastebin, containing closed tabs */
+        g_warning (_("The trash couldn't be saved. %s"), error->message);
+        g_error_free (error);
+    }
+    g_free (config_file);
+}
+
+static void
+midori_trash_add_item_cb (KatzeArray* trash,
+                          GObject*    item)
+{
+    midori_trash_remove_item_cb (trash, item);
+}
+
+void
+midori_private_app_new (const gchar* config,
+                        const gchar* webapp,
+                        gchar**      open_uris,
+                        gchar**      execute_commands,
+                        gint         inactivity_reset,
+                        const gchar* block_uris)
+{
+    midori_paths_init (MIDORI_RUNTIME_MODE_PRIVATE, config);
+    g_object_set_data (G_OBJECT (webkit_get_default_session ()), "pass-through-console", (void*)1);
+
+    /* Mask the timezone, which can be read by Javascript */
+    g_setenv ("TZ", "UTC", TRUE);
+
+    MidoriBrowser* browser = midori_browser_new ();
+    g_signal_connect (browser, "new-window",
+        G_CALLBACK (midori_frontend_browser_new_window_cb), NULL);
+
+    MidoriWebSettings* settings = midori_settings_new_full (NULL);
+    g_object_set (settings,
+                  "preferred-languages", "en",
+                  "enable-private-browsing", TRUE,
+    #ifdef HAVE_LIBSOUP_2_29_91
+                  "first-party-cookies-only", TRUE,
+    #endif
+                  "enable-html5-database", FALSE,
+                  "enable-html5-local-storage", FALSE,
+                  "enable-offline-web-application-cache", FALSE,
+    /* Arguably DNS prefetching is or isn't a privacy concern. For the
+     * lack of more fine-grained control we'll go the safe route. */
+    #if WEBKIT_CHECK_VERSION (1, 3, 11)
+                  "enable-dns-prefetching", FALSE,
+    #endif
+                  "strip-referer", TRUE,
+                  "show-panel", FALSE,
+                  "last-window-state", MIDORI_WINDOW_NORMAL,
+                  "inactivity-reset", inactivity_reset,
+                  "block-uris", block_uris,
+                  NULL);
+    midori_load_soup_session (settings);
+
+    /* In-memory trash for re-opening closed tabs */
+    KatzeArray* trash = katze_array_new (KATZE_TYPE_ITEM);
+    g_signal_connect_after (trash, "add-item",
+      G_CALLBACK (midori_trash_add_item_no_save_cb), NULL);
+
+    KatzeArray* search_engines = midori_search_engines_new_from_folder (NULL);
+    g_object_set (browser,
+                  "settings", settings,
+                  "trash", trash,
+                  "search-engines", search_engines,
+                  NULL);
+    g_object_unref (settings);
+    g_object_unref (trash);
+    g_object_unref (search_engines);
+
+    midori_browser_set_action_visible (browser, "Tools", FALSE);
+    midori_browser_set_action_visible (browser, "ClearPrivateData", FALSE);
+    midori_browser_set_action_visible (browser, "Panel", FALSE);
+    #if GTK_CHECK_VERSION (3, 0, 0)
+    g_object_set (gtk_widget_get_settings (GTK_WIDGET (browser)),
+                  "gtk-application-prefer-dark-theme", TRUE,
+                  NULL);
+    #endif
+
+    if (webapp != NULL)
+    {
+        gchar* tmp_uri = sokoke_prepare_uri (webapp);
+        g_object_set (settings, "homepage", tmp_uri, NULL);
+        midori_browser_add_uri (browser, tmp_uri);
+        g_free (tmp_uri);
+    }
+    else if (open_uris == NULL)
+        midori_browser_add_uri (browser, "about:private");
+
+    g_signal_connect (browser, "quit", G_CALLBACK (gtk_main_quit), NULL);
+    g_signal_connect (browser, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+    gtk_widget_show (GTK_WIDGET (browser));
+
+    guint i;
+    if (open_uris != NULL)
+        for (i = 0; open_uris[i] != NULL; i++)
+        {
+            gchar* new_uri = sokoke_prepare_uri (open_uris[i]);
+            midori_browser_add_uri (browser, new_uri);
+            g_free (new_uri);
+        }
+
+    if (execute_commands != NULL)
+        for (i = 0; execute_commands[i] != NULL; i++)
+            midori_browser_activate_action (browser, execute_commands[i]);
+}
+
+static void
+midori_browser_show_preferences_cb (MidoriBrowser*    browser,
+                                    KatzePreferences* preferences,
+                                    MidoriApp*        app)
+{
+    midori_preferences_add_extension_category (preferences, app);
+}
+
+static void
+midori_browser_privacy_preferences_cb (MidoriBrowser*    browser,
+                                       KatzePreferences* preferences,
+                                       MidoriApp*        app)
+{
+    MidoriWebSettings* settings = midori_browser_get_settings (browser);
+    midori_preferences_add_privacy_category (preferences, settings);
+}
+
+static void
+midori_app_add_browser_cb (MidoriApp*     app,
+                           MidoriBrowser* browser,
+                           KatzeNet*      net)
+{
+    GtkWidget* panel;
+    GtkWidget* addon;
+
+    panel = katze_object_get_object (browser, "panel");
+
+    addon = g_object_new (MIDORI_TYPE_BOOKMARKS, "app", app, "visible", TRUE, NULL);
+    midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
+
+    addon = g_object_new (MIDORI_TYPE_HISTORY, "app", app, "visible", TRUE, NULL);
+    midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
+
+    addon = g_object_new (MIDORI_TYPE_TRANSFERS, "app", app, "visible", TRUE, NULL);
+    midori_panel_append_page (MIDORI_PANEL (panel), MIDORI_VIEWABLE (addon));
+
+    /* Extensions */
+    g_signal_connect (browser, "show-preferences",
+        G_CALLBACK (midori_browser_privacy_preferences_cb), app);
+    g_signal_connect (browser, "show-preferences",
+        G_CALLBACK (midori_browser_show_preferences_cb), app);
+
+    g_object_unref (panel);
+}
+
+static void
+button_disable_extensions_clicked_cb (GtkWidget* button,
+                                      MidoriApp* app)
+{
+    /* Reset frozen list of active extensions */
+    g_object_set_data (G_OBJECT (app), "extensions", NULL);
+    gtk_widget_set_sensitive (button, FALSE);
+}
+
+static void
+button_modify_preferences_clicked_cb (GtkWidget*         button,
+                                      MidoriWebSettings* settings)
+{
+    GtkWidget* dialog = midori_preferences_new (
+        GTK_WINDOW (gtk_widget_get_toplevel (button)), settings);
+    if (midori_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_DELETE_EVENT)
+        gtk_widget_destroy (dialog);
+}
+
+static MidoriStartup
+midori_frontend_diagnostic_dialog (MidoriApp*         app,
+                                   MidoriWebSettings* settings,
+                                   KatzeArray*        session)
+{
+    GtkWidget* dialog;
+    GtkWidget* content_area;
+    GtkWidget* align;
+    GtkWidget* box;
+    GtkWidget* button;
+    MidoriStartup load_on_startup = katze_object_get_enum (settings, "load-on-startup");
+    gint response;
+
+    dialog = gtk_message_dialog_new (
+        NULL, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
+        _("Midori seems to have crashed the last time it was opened. "
+          "If this happened repeatedly, try one of the following options "
+          "to solve the problem."));
+    gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE);
+    gtk_window_set_title (GTK_WINDOW (dialog), g_get_application_name ());
+    content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+    align = gtk_alignment_new (0.5, 0.5, 0.5, 0.5);
+    gtk_container_add (GTK_CONTAINER (content_area), align);
+    box = gtk_hbox_new (FALSE, 0);
+    gtk_container_add (GTK_CONTAINER (align), box);
+    button = gtk_button_new_with_mnemonic (_("Modify _preferences"));
+    g_signal_connect (button, "clicked",
+        G_CALLBACK (button_modify_preferences_clicked_cb), settings);
+    gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 4);
+    button = gtk_button_new_with_mnemonic (_("Disable all _extensions"));
+    if (g_object_get_data (G_OBJECT (app), "extensions"))
+        g_signal_connect (button, "clicked",
+            G_CALLBACK (button_disable_extensions_clicked_cb), app);
+    else
+        gtk_widget_set_sensitive (button, FALSE);
+    gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 4);
+    gtk_widget_show_all (align);
+    button = katze_property_proxy (settings, "show-crash-dialog", NULL);
+    gtk_button_set_label (GTK_BUTTON (button), _("Show a dialog after Midori crashed"));
+    gtk_widget_show (button);
+    gtk_container_add (GTK_CONTAINER (content_area), button);
+    gtk_container_set_focus_child (GTK_CONTAINER (dialog), gtk_dialog_get_action_area (GTK_DIALOG (dialog)));
+    gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+        _("Discard old tabs"), MIDORI_STARTUP_BLANK_PAGE,
+        _("Show last tabs without loading"), MIDORI_STARTUP_DELAYED_PAGES,
+        _("Show last open tabs"), MIDORI_STARTUP_LAST_OPEN_PAGES,
+        NULL);
+    gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+        load_on_startup == MIDORI_STARTUP_HOMEPAGE
+        ? MIDORI_STARTUP_BLANK_PAGE : load_on_startup);
+
+    /* GtkLabel can't wrap the text properly. Until some day
+       this works, we implement this hack to do it ourselves. */
+    GList* ch = gtk_container_get_children (GTK_CONTAINER (content_area));
+    GtkWidget* hbox = (GtkWidget*)g_list_nth_data (ch, 0);
+    g_list_free (ch);
+    ch = gtk_container_get_children (GTK_CONTAINER (hbox));
+    GtkWidget* vbox = (GtkWidget*)g_list_nth_data (ch, 1);
+    g_list_free (ch);
+    ch = gtk_container_get_children (GTK_CONTAINER (vbox));
+    GtkWidget* label = (GtkWidget*)g_list_nth_data (ch, 0);
+    g_list_free (ch);
+    GtkRequisition req;
+    gtk_widget_size_request (content_area, &req);
+    gtk_widget_set_size_request (label, req.width * 0.9, -1);
+
+    response = midori_dialog_run (GTK_DIALOG (dialog));
+    gtk_widget_destroy (dialog);
+    if (response == GTK_RESPONSE_DELETE_EVENT)
+        response = G_MAXINT;
+    else if (response == MIDORI_STARTUP_BLANK_PAGE)
+        katze_array_clear (session);
+    return response;
+}
+
+MidoriApp*
+midori_normal_app_new (const gchar* config,
+                       gboolean     portable,
+                       gboolean     diagnostic_dialog,
+                       const gchar* webapp,
+                       gchar**      open_uris,
+                       gchar**      execute_commands,
+                       gint         inactivity_reset,
+                       const gchar* block_uris)
+{
+    if (portable)
+        midori_paths_init (MIDORI_RUNTIME_MODE_PORTABLE, config);
+    else
+        midori_paths_init (MIDORI_RUNTIME_MODE_NORMAL, config);
+
+    MidoriApp* app = midori_app_new ();
+    if (midori_app_instance_is_running (app))
+    {
+        gboolean result = FALSE;
+        GtkWidget* dialog;
+
+        if (execute_commands != NULL && midori_app_send_command (app, open_uris))
+            return NULL;
+        if (open_uris != NULL && midori_app_instance_send_uris (app, open_uris))
+            return NULL;
+        if (!execute_commands && !open_uris && midori_app_instance_send_new_browser (app))
+            return NULL;
+
+        sokoke_message_dialog (GTK_MESSAGE_INFO,
+            _("An instance of Midori is already running but not responding.\n"),
+            "", TRUE);
+        return (void*)0xdeadbeef;
+    }
+
+    GString* error_messages = g_string_new (NULL);
+    GError* error = NULL;
+    gchar** extensions;
+    MidoriWebSettings* settings = midori_settings_new_full (&extensions);
+    g_object_set (settings,
+                  "enable-developer-extras", TRUE,
+                  "enable-html5-database", TRUE,
+                  "block-uris", block_uris,
+                  NULL);
+    if (inactivity_reset > 0)
+        g_object_set (settings, "inactivity-reset", inactivity_reset, NULL);
+
+    KatzeArray* search_engines = midori_search_engines_new_from_folder (error_messages);
+    /* Pick first search engine as default if not set */
+    gchar* uri = katze_object_get_string (settings, "location-entry-search");
+    if (!(uri && *uri) && !katze_array_is_empty (search_engines))
+    {
+        KatzeItem* item = katze_array_get_nth_item (search_engines, 0);
+        g_object_set (settings, "location-entry-search",
+                      katze_item_get_uri (item), NULL);
+    }
+    g_free (uri);
+
+    KatzeArray* bookmarks;
+    gchar* errmsg = NULL;
+    if (!(bookmarks = midori_bookmarks_new (&errmsg)))
+    {
+        g_string_append_printf (error_messages,
+            _("Bookmarks couldn't be loaded: %s\n"), errmsg);
+        katze_assign (errmsg, NULL);
+    }
+
+    gchar* config_file = NULL;
+    KatzeArray* session = katze_array_new (KATZE_TYPE_ITEM);
+    MidoriStartup load_on_startup = katze_object_get_enum (settings, "load-on-startup");
+    if (load_on_startup >= MIDORI_STARTUP_LAST_OPEN_PAGES)
+    {
+        katze_assign (config_file, midori_paths_get_config_filename_for_reading ("session.xbel"));
+        error = NULL;
+        if (!midori_array_from_file (session, config_file, "xbel", &error))
+        {
+            if (error->code != G_FILE_ERROR_NOENT)
+                g_string_append_printf (error_messages,
+                    _("The session couldn't be loaded: %s\n"), error->message);
+            g_error_free (error);
+        }
+    }
+
+    KatzeArray* trash = katze_array_new (KATZE_TYPE_ITEM);
+    g_signal_connect_after (trash, "add-item",
+        G_CALLBACK (midori_trash_add_item_cb), NULL);
+    g_signal_connect_after (trash, "remove-item",
+        G_CALLBACK (midori_trash_remove_item_cb), NULL);
+    katze_assign (config_file, g_build_filename (config, "tabtrash.xbel", NULL));
+    error = NULL;
+    if (!midori_array_from_file (trash, config_file, "xbel", &error))
+    {
+        if (error->code != G_FILE_ERROR_NOENT)
+            g_string_append_printf (error_messages,
+                _("The trash couldn't be loaded: %s\n"), error->message);
+        g_error_free (error);
+    }
+
+    KatzeArray* history;
+    if (!(history = midori_history_new (&errmsg)))
+    {
+        g_string_append_printf (error_messages,
+            _("The history couldn't be loaded: %s\n"), errmsg);
+        katze_assign (errmsg, NULL);
+    }
+
+    katze_assign (config_file, midori_paths_get_config_filename_for_reading ("speeddial"));
+    MidoriSpeedDial* dial = midori_speed_dial_new (config_file, NULL);
+
+    if (error_messages->len)
+    {
+        GtkWidget* dialog = gtk_message_dialog_new (
+            NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE,
+            _("The following errors occured:"));
+        gtk_message_dialog_format_secondary_text (
+            GTK_MESSAGE_DIALOG (dialog), "%s", error_messages->str);
+        gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                _("_Ignore"), GTK_RESPONSE_ACCEPT,
+                                NULL);
+        if (midori_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT)
+            return (void*)0xdeadbeef;
+        gtk_widget_destroy (dialog);
+    }
+    g_string_free (error_messages, TRUE);
+
+    g_object_set_data (G_OBJECT (app), "execute-commands", execute_commands);
+    g_object_set_data (G_OBJECT (app), "open-uris", open_uris);
+    g_object_set_data_full (G_OBJECT (app), "extensions", extensions, (GDestroyNotify)g_strfreev);
+    katze_item_set_parent (KATZE_ITEM (session), app);
+
+    katze_assign (config_file, midori_paths_get_config_filename_for_reading ("search"));
+    midori_search_engines_set_filename (search_engines, config_file);
+
+    if ((midori_app_get_crashed (app)
+     && katze_object_get_boolean (settings, "show-crash-dialog")
+     && open_uris && !execute_commands)
+     || diagnostic_dialog)
+    {
+        load_on_startup = midori_frontend_diagnostic_dialog (app, settings, session);
+        if (load_on_startup == G_MAXINT)
+            return NULL;
+    }
+    g_object_set_data (G_OBJECT (settings), "load-on-startup", GINT_TO_POINTER (load_on_startup));
+
+    g_object_set (app, "settings", settings,
+                       "bookmarks", bookmarks,
+                       "trash", trash,
+                       "search-engines", search_engines,
+                       "history", history,
+                       "speed-dial", dial,
+                       NULL);
+    g_signal_connect (app, "add-browser",
+        G_CALLBACK (midori_app_add_browser_cb), NULL);
+
+    g_idle_add (midori_load_soup_session_full, settings);
+    g_idle_add (midori_load_extensions, app);
+    g_idle_add (midori_load_session, session);
+    return app;
+}
+
+void
+midori_normal_app_on_quit (MidoriApp* app)
+{
+    MidoriWebSettings* settings = katze_object_get_object (app, "settings");
+    KatzeArray* bookmarks = katze_object_get_object (app, "bookmarks");
+    KatzeArray* history = katze_object_get_object (app, "history");
+
+    g_object_notify (G_OBJECT (settings), "load-on-startup");
+    midori_bookmarks_on_quit (bookmarks);
+    midori_history_on_quit (history, settings);
+    midori_private_data_on_quit (settings);
+    /* Removing KatzeHttpCookies makes it save outstanding changes */
+    soup_session_remove_feature_by_type (webkit_get_default_session (),
+                                         KATZE_TYPE_HTTP_COOKIES);
+
+    MidoriStartup load_on_startup = katze_object_get_int (settings, "load-on-startup");
+    if (load_on_startup < MIDORI_STARTUP_LAST_OPEN_PAGES)
+    {
+        gchar* config_file = midori_paths_get_config_filename_for_writing ("session.xbel");
+        g_unlink (config_file);
+    }
+}
+
diff --git a/midori/midori-frontend.h b/midori/midori-frontend.h
new file mode 100644
index 0000000..a421caa
--- /dev/null
+++ b/midori/midori-frontend.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2012 Christian Dywan <christian at 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_FRONTEND_H__
+#define __MIDORI_FRONTEND_H__
+
+#include "midori/midori-app.h"
+
+void
+midori_web_app_new (const gchar* config,
+                    const gchar* webapp,
+                    gchar**      open_uris,
+                    gchar**      execute_commands,
+                    gint         inactivity_reset,
+                    const gchar* block_uris);
+
+void
+midori_private_app_new (const gchar* config,
+                        const gchar* webapp,
+                        gchar**      open_uris,
+                        gchar**      execute_commands,
+                        gint         inactivity_reset,
+                        const gchar* block_uris);
+
+MidoriApp*
+midori_normal_app_new (const gchar* config,
+                       gboolean     portable,
+                       gboolean     diagnostic_dialog,
+                       const gchar* webapp,
+                       gchar**      open_uris,
+                       gchar**      execute_commands,
+                       gint         inactivity_reset,
+                       const gchar* block_uris);
+
+void
+midori_normal_app_on_quit (MidoriApp* app);
+
+G_END_DECLS
+
+#endif /* __MIDORI_FRONTEND_H__ */
+
diff --git a/midori/midori.h b/midori/midori.h
index 7c4e616..ba2e068 100644
--- a/midori/midori.h
+++ b/midori/midori.h
@@ -17,6 +17,7 @@
 #include "midori-bookmarks.h"
 #include "midori-browser.h"
 #include "midori-extension.h"
+#include "midori-frontend.h"
 #include "midori-locationaction.h"
 #include "midori-panel.h"
 #include "midori-preferences.h"
diff --git a/midori/midori.vapi b/midori/midori.vapi
index 03d3cac..2d7bb01 100644
--- a/midori/midori.vapi
+++ b/midori/midori.vapi
@@ -9,6 +9,15 @@ namespace Midori {
     }
 
     [CCode (cheader_filename = "midori/midori.h")]
+    public static void web_app_new (string? config,
+        string? webapp, [CCode (array_length = false)] string[]? uris, [CCode (array_length = false)] string[]? commands, int reset, string? block);
+    public static void private_app_new (string? config,
+        string? webapp, [CCode (array_length = false)] string[]? uris, [CCode (array_length = false)] string[]? commands, int reset, string? block);
+    public static App normal_app_new (string? config, bool portable, bool diagnostic,
+        string? webapp, [CCode (array_length = false)] string[]? uris, [CCode (array_length = false)] string[]? commands, int reset, string? block);
+    public static void normal_app_on_quit (App app);
+
+    [CCode (cheader_filename = "midori/midori.h")]
     public class App : GLib.Object {
         public App ();
         public static void setup ([CCode (array_length_pos = 0.9)] ref unowned string[] args, [CCode (array_length = false)] GLib.OptionEntry[]? entries);
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9aa905b..5af5366 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -80,3 +80,4 @@ midori/midori-history.c
 midori/midori-bookmarks.c
 midori/midori-session.c
 extensions/nsplugin-manager.vala
+midori/midori-frontend.c
diff --git a/tests/app.vala b/tests/app.vala
new file mode 100644
index 0000000..36af15c
--- /dev/null
+++ b/tests/app.vala
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2012 Christian Dywan <christian at 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.
+*/
+
+void app_normal () {
+    Midori.Paths.Test.reset_runtime_mode ();
+    var app = Midori.normal_app_new (null, false, false, null, null, null, -1, null);
+    var loop = MainContext.default ();
+    do { loop.iteration (true); } while (loop.pending ());
+    Midori.normal_app_on_quit (app);
+}
+
+void app_custom_config () {
+    /*
+    Test.log_set_fatal_handler ((domain, log_levels, message)=> {
+        return !message.contains("Error loading theme icon");
+        });
+
+    Midori.Paths.Test.reset_runtime_mode ();
+    var app = Midori.normal_app_new ("/tmp/mylittlepony", false, false, null, null, null, -1, null);
+    var loop = MainContext.default ();
+    do { loop.iteration (true); } while (loop.pending ());
+    Midori.normal_app_on_quit (app);
+    */
+}
+void app_private () {
+    Midori.Paths.Test.reset_runtime_mode ();
+    Midori.private_app_new (null, null, null, null, -1, null);
+    var loop = MainContext.default ();
+    do { loop.iteration (true); } while (loop.pending ());
+}
+
+void app_web () {
+    Midori.Paths.Test.reset_runtime_mode ();
+    Midori.web_app_new (null, null, null, null, -1, null);
+    var loop = MainContext.default ();
+    do { loop.iteration (true); } while (loop.pending ());
+}
+
+void main (string[] args) {
+    Test.init (ref args);
+    Midori.App.setup (ref args, null);
+    Test.add_func ("/app/normal", app_normal);
+    Test.add_func ("/app/custom-config", app_custom_config);
+    Test.add_func ("/app/private", app_private);
+    Test.add_func ("/app/web", app_web);
+    Test.run ();
+}
+


More information about the Xfce4-commits mailing list