Title: [203271] trunk/Tools
Revision
203271
Author
[email protected]
Date
2016-07-15 02:25:15 -0700 (Fri, 15 Jul 2016)

Log Message

[GTK] Add basic tabs support to MiniBrowser
https://bugs.webkit.org/show_bug.cgi?id=159803

Reviewed by Sergio Villar Senin.

It's quite common to have issues with web views loaded in secondary tabs, and we need to use an external browser
like epiphany to debug those issues. It would be a lot easier to work on those bugs if we could use the MiniBrowser.

* MiniBrowser/gtk/BrowserTab.c: Added.
(titleChanged):
(isLoadingChanged):
(decidePolicy):
(removeChildIfInfoBar):
(loadChanged):
(createInfoBarQuestionMessage):
(tlsErrorsDialogResponse):
(loadFailedWithTLSerrors):
(permissionRequestDialogResponse):
(decidePermissionRequest):
(colorChooserRGBAChanged):
(popoverColorClosed):
(colorChooserRequestFinished):
(runColorChooserCallback):
(inspectorOpenedInWindow):
(inspectorClosed):
(browserTabSetProperty):
(browserTabFinalize):
(browser_tab_init):
(browserTabConstructed):
(browser_tab_class_init):
(getInternalURI):
(browser_tab_new):
(browser_tab_get_web_view):
(browser_tab_load_uri):
(browser_tab_get_title_widget):
(browser_tab_set_status_text):
(browser_tab_toggle_inspector):
(browser_tab_start_search):
(browser_tab_stop_search):
(browser_tab_add_accelerators):
(fullScreenMessageTimeoutCallback):
(browser_tab_enter_fullscreen):
(browser_tab_leave_fullscreen):
* MiniBrowser/gtk/BrowserTab.h: Added.
* MiniBrowser/gtk/BrowserWindow.c:
(getExternalURI):
(browserWindowSetStatusText):
(reloadOrStopCallback):
(goBackCallback):
(goForwardCallback):
(settingsCallback):
(webViewURIChanged):
(browserWindowHistoryItemActivated):
(browserWindowUpdateNavigationActions):
(webViewCreate):
(webViewEnterFullScreen):
(webViewLeaveFullScreen):
(webViewDecidePolicy):
(browserWindowCanZoomIn):
(browserWindowCanZoomOut):
(browserWindowZoomIn):
(browserWindowZoomOut):
(scrollEventCallback):
(faviconChanged):
(webViewIsLoadingChanged):
(defaultZoomCallback):
(searchCallback):
(newTabCallback):
(toggleWebInspector):
(reloadPage):
(reloadPageIgnoringCache):
(stopPageLoad):
(loadHomePage):
(editingCommandCallback):
(insertImageCommandCallback):
(insertLinkCommandCallback):
(browserWindowSetupEditorToolbar):
(browserWindowSwitchTab):
(browserWindowTabAddedOrRemoved):
(browser_window_init):
(browserWindowConstructed):
(browserWindowSaveSession):
(browserWindowDeleteEvent):
(browser_window_new):
(browser_window_append_view):
(browser_window_load_uri):
(browser_window_load_session):
(browser_window_set_background_color):
(resetStatusText): Deleted.
(activateUriEntryCallback): Deleted.
(webViewTitleChanged): Deleted.
(resetEntryProgress): Deleted.
(browserWindowCreateBackForwardMenu): Deleted.
(webViewReadyToShow): Deleted.
(webViewLoadFailed): Deleted.
(webViewMouseTargetChanged): Deleted.
(browserWindowUpdateZoomActions): Deleted.
(webViewZoomLevelChanged): Deleted.
(updateUriEntryIcon): Deleted.
(zoomInCallback): Deleted.
(zoomOutCallback): Deleted.
(toggleFullScreen): Deleted.
(browserWindowEditingCommandToggleButtonSetActive): Deleted.
(browserWindowFinalize): Deleted.
(browser_window_class_init): Deleted.
* MiniBrowser/gtk/BrowserWindow.h:
* MiniBrowser/gtk/CMakeLists.txt:
* MiniBrowser/gtk/main.c:
(createBrowserTab):
(aboutURISchemeRequestCallback):
(main):
(parseBackgroundColor): Deleted.

Modified Paths

Added Paths

Diff

Modified: trunk/Tools/ChangeLog (203270 => 203271)


--- trunk/Tools/ChangeLog	2016-07-15 06:03:25 UTC (rev 203270)
+++ trunk/Tools/ChangeLog	2016-07-15 09:25:15 UTC (rev 203271)
@@ -1,3 +1,118 @@
+2016-07-15  Carlos Garcia Campos  <[email protected]>
+
+        [GTK] Add basic tabs support to MiniBrowser
+        https://bugs.webkit.org/show_bug.cgi?id=159803
+
+        Reviewed by Sergio Villar Senin.
+
+        It's quite common to have issues with web views loaded in secondary tabs, and we need to use an external browser
+        like epiphany to debug those issues. It would be a lot easier to work on those bugs if we could use the MiniBrowser.
+
+        * MiniBrowser/gtk/BrowserTab.c: Added.
+        (titleChanged):
+        (isLoadingChanged):
+        (decidePolicy):
+        (removeChildIfInfoBar):
+        (loadChanged):
+        (createInfoBarQuestionMessage):
+        (tlsErrorsDialogResponse):
+        (loadFailedWithTLSerrors):
+        (permissionRequestDialogResponse):
+        (decidePermissionRequest):
+        (colorChooserRGBAChanged):
+        (popoverColorClosed):
+        (colorChooserRequestFinished):
+        (runColorChooserCallback):
+        (inspectorOpenedInWindow):
+        (inspectorClosed):
+        (browserTabSetProperty):
+        (browserTabFinalize):
+        (browser_tab_init):
+        (browserTabConstructed):
+        (browser_tab_class_init):
+        (getInternalURI):
+        (browser_tab_new):
+        (browser_tab_get_web_view):
+        (browser_tab_load_uri):
+        (browser_tab_get_title_widget):
+        (browser_tab_set_status_text):
+        (browser_tab_toggle_inspector):
+        (browser_tab_start_search):
+        (browser_tab_stop_search):
+        (browser_tab_add_accelerators):
+        (fullScreenMessageTimeoutCallback):
+        (browser_tab_enter_fullscreen):
+        (browser_tab_leave_fullscreen):
+        * MiniBrowser/gtk/BrowserTab.h: Added.
+        * MiniBrowser/gtk/BrowserWindow.c:
+        (getExternalURI):
+        (browserWindowSetStatusText):
+        (reloadOrStopCallback):
+        (goBackCallback):
+        (goForwardCallback):
+        (settingsCallback):
+        (webViewURIChanged):
+        (browserWindowHistoryItemActivated):
+        (browserWindowUpdateNavigationActions):
+        (webViewCreate):
+        (webViewEnterFullScreen):
+        (webViewLeaveFullScreen):
+        (webViewDecidePolicy):
+        (browserWindowCanZoomIn):
+        (browserWindowCanZoomOut):
+        (browserWindowZoomIn):
+        (browserWindowZoomOut):
+        (scrollEventCallback):
+        (faviconChanged):
+        (webViewIsLoadingChanged):
+        (defaultZoomCallback):
+        (searchCallback):
+        (newTabCallback):
+        (toggleWebInspector):
+        (reloadPage):
+        (reloadPageIgnoringCache):
+        (stopPageLoad):
+        (loadHomePage):
+        (editingCommandCallback):
+        (insertImageCommandCallback):
+        (insertLinkCommandCallback):
+        (browserWindowSetupEditorToolbar):
+        (browserWindowSwitchTab):
+        (browserWindowTabAddedOrRemoved):
+        (browser_window_init):
+        (browserWindowConstructed):
+        (browserWindowSaveSession):
+        (browserWindowDeleteEvent):
+        (browser_window_new):
+        (browser_window_append_view):
+        (browser_window_load_uri):
+        (browser_window_load_session):
+        (browser_window_set_background_color):
+        (resetStatusText): Deleted.
+        (activateUriEntryCallback): Deleted.
+        (webViewTitleChanged): Deleted.
+        (resetEntryProgress): Deleted.
+        (browserWindowCreateBackForwardMenu): Deleted.
+        (webViewReadyToShow): Deleted.
+        (webViewLoadFailed): Deleted.
+        (webViewMouseTargetChanged): Deleted.
+        (browserWindowUpdateZoomActions): Deleted.
+        (webViewZoomLevelChanged): Deleted.
+        (updateUriEntryIcon): Deleted.
+        (zoomInCallback): Deleted.
+        (zoomOutCallback): Deleted.
+        (toggleFullScreen): Deleted.
+        (browserWindowEditingCommandToggleButtonSetActive): Deleted.
+        (browserWindowFinalize): Deleted.
+        (browser_window_class_init): Deleted.
+        * MiniBrowser/gtk/BrowserWindow.h:
+        * MiniBrowser/gtk/CMakeLists.txt:
+        * MiniBrowser/gtk/main.c:
+        (createBrowserTab):
+        (aboutURISchemeRequestCallback):
+        (main):
+        (parseBackgroundColor): Deleted.
+
 2016-07-14  Alex Christensen  <[email protected]>
 
         Allow RefPtrs of const RefCounted types

Added: trunk/Tools/MiniBrowser/gtk/BrowserTab.c (0 => 203271)


--- trunk/Tools/MiniBrowser/gtk/BrowserTab.c	                        (rev 0)
+++ trunk/Tools/MiniBrowser/gtk/BrowserTab.c	2016-07-15 09:25:15 UTC (rev 203271)
@@ -0,0 +1,550 @@
+/*
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE)
+#include "cmakeconfig.h"
+#endif
+#include "BrowserTab.h"
+
+#include "BrowserSearchBar.h"
+#include "BrowserWindow.h"
+#include <string.h>
+
+enum {
+    PROP_0,
+
+    PROP_VIEW
+};
+
+struct _BrowserTab {
+    GtkBox parent;
+
+    WebKitWebView *webView;
+    BrowserSearchBar *searchBar;
+    GtkWidget *statusLabel;
+    gboolean wasSearchingWhenEnteredFullscreen;
+    gboolean inspectorIsVisible;
+    GtkWidget *fullScreenMessageLabel;
+    guint fullScreenMessageLabelId;
+
+    /* Tab Title */
+    GtkWidget *titleBox;
+    GtkWidget *titleLabel;
+    GtkWidget *titleSpinner;
+    GtkWidget *titleCloseButton;
+};
+
+struct _BrowserTabClass {
+    GtkBoxClass parent;
+};
+
+G_DEFINE_TYPE(BrowserTab, browser_tab, GTK_TYPE_BOX)
+
+static void titleChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserTab *tab)
+{
+    const char *title = webkit_web_view_get_title(webView);
+    if (title && *title)
+        gtk_label_set_text(GTK_LABEL(tab->titleLabel), title);
+}
+
+static void isLoadingChanged(WebKitWebView *webView, GParamSpec *paramSpec, BrowserTab *tab)
+{
+    if (webkit_web_view_is_loading(webView)) {
+        gtk_spinner_start(GTK_SPINNER(tab->titleSpinner));
+        gtk_widget_show(tab->titleSpinner);
+    } else {
+        gtk_spinner_stop(GTK_SPINNER(tab->titleSpinner));
+        gtk_widget_hide(tab->titleSpinner);
+    }
+}
+
+static gboolean decidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, BrowserTab *tab)
+{
+    if (decisionType != WEBKIT_POLICY_DECISION_TYPE_RESPONSE)
+        return FALSE;
+
+    WebKitResponsePolicyDecision *responseDecision = WEBKIT_RESPONSE_POLICY_DECISION(decision);
+    if (webkit_response_policy_decision_is_mime_type_supported(responseDecision))
+        return FALSE;
+
+    WebKitWebResource *mainResource = webkit_web_view_get_main_resource(webView);
+    WebKitURIRequest *request = webkit_response_policy_decision_get_request(responseDecision);
+    const char *requestURI = webkit_uri_request_get_uri(request);
+    if (g_strcmp0(webkit_web_resource_get_uri(mainResource), requestURI))
+        return FALSE;
+
+    webkit_policy_decision_download(decision);
+    return TRUE;
+}
+
+static void removeChildIfInfoBar(GtkWidget *child, GtkContainer *tab)
+{
+    if (GTK_IS_INFO_BAR(child))
+        gtk_container_remove(tab, child);
+}
+
+static void loadChanged(WebKitWebView *webView, WebKitLoadEvent loadEvent, BrowserTab *tab)
+{
+    if (loadEvent != WEBKIT_LOAD_STARTED)
+        return;
+
+    gtk_container_foreach(GTK_CONTAINER(tab), (GtkCallback)removeChildIfInfoBar, tab);
+}
+
+static GtkWidget *createInfoBarQuestionMessage(const char *title, const char *text)
+{
+    GtkWidget *dialog = gtk_info_bar_new_with_buttons("No", GTK_RESPONSE_NO, "Yes", GTK_RESPONSE_YES, NULL);
+    gtk_info_bar_set_message_type(GTK_INFO_BAR(dialog), GTK_MESSAGE_QUESTION);
+
+    GtkWidget *contentBox = gtk_info_bar_get_content_area(GTK_INFO_BAR(dialog));
+    gtk_orientable_set_orientation(GTK_ORIENTABLE(contentBox), GTK_ORIENTATION_VERTICAL);
+    gtk_box_set_spacing(GTK_BOX(contentBox), 0);
+
+    GtkWidget *label = gtk_label_new(NULL);
+    gchar *markup = g_strdup_printf("<span size='xx-large' weight='bold'>%s</span>", title);
+    gtk_label_set_markup(GTK_LABEL(label), markup);
+    g_free(markup);
+    gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+    gtk_label_set_selectable(GTK_LABEL(label), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5);
+    gtk_box_pack_start(GTK_BOX(contentBox), label, FALSE, FALSE, 2);
+    gtk_widget_show(label);
+
+    label = gtk_label_new(text);
+    gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+    gtk_label_set_selectable(GTK_LABEL(label), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5);
+    gtk_box_pack_start(GTK_BOX(contentBox), label, FALSE, FALSE, 0);
+    gtk_widget_show(label);
+
+    return dialog;
+}
+
+static void tlsErrorsDialogResponse(GtkWidget *dialog, gint response, BrowserTab *tab)
+{
+    if (response == GTK_RESPONSE_YES) {
+        const char *failingURI = (const char *)g_object_get_data(G_OBJECT(dialog), "failingURI");
+        GTlsCertificate *certificate = (GTlsCertificate *)g_object_get_data(G_OBJECT(dialog), "certificate");
+        SoupURI *uri = soup_uri_new(failingURI);
+        webkit_web_context_allow_tls_certificate_for_host(webkit_web_view_get_context(tab->webView), certificate, uri->host);
+        soup_uri_free(uri);
+        webkit_web_view_load_uri(tab->webView, failingURI);
+    }
+    gtk_widget_destroy(dialog);
+}
+
+static gboolean loadFailedWithTLSerrors(WebKitWebView *webView, const char *failingURI, GTlsCertificate *certificate, GTlsCertificateFlags errors, BrowserTab *tab)
+{
+    gchar *text = g_strdup_printf("Failed to load %s: Do you want to continue ignoring the TLS errors?", failingURI);
+    GtkWidget *dialog = createInfoBarQuestionMessage("Invalid TLS Certificate", text);
+    g_free(text);
+    g_object_set_data_full(G_OBJECT(dialog), "failingURI", g_strdup(failingURI), g_free);
+    g_object_set_data_full(G_OBJECT(dialog), "certificate", g_object_ref(certificate), g_object_unref);
+
+    g_signal_connect(dialog, "response", G_CALLBACK(tlsErrorsDialogResponse), tab);
+
+    gtk_box_pack_start(GTK_BOX(tab), dialog, FALSE, FALSE, 0);
+    gtk_box_reorder_child(GTK_BOX(tab), dialog, 0);
+    gtk_widget_show(dialog);
+
+    return TRUE;
+}
+
+static void permissionRequestDialogResponse(GtkWidget *dialog, gint response, WebKitPermissionRequest *request)
+{
+    switch (response) {
+    case GTK_RESPONSE_YES:
+        webkit_permission_request_allow(request);
+        break;
+    default:
+        webkit_permission_request_deny(request);
+        break;
+    }
+
+    gtk_widget_destroy(dialog);
+    g_object_unref(request);
+}
+
+static gboolean decidePermissionRequest(WebKitWebView *webView, WebKitPermissionRequest *request, BrowserTab *tab)
+{
+    const gchar *title = NULL;
+    gchar *text = NULL;
+
+    if (WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(request)) {
+        title = "Geolocation request";
+        text = g_strdup("Allow geolocation request?");
+    } else if (WEBKIT_IS_NOTIFICATION_PERMISSION_REQUEST(request)) {
+        title = "Notification request";
+        text = g_strdup("Allow notifications request?");
+    } else if (WEBKIT_IS_USER_MEDIA_PERMISSION_REQUEST(request)) {
+        title = "UserMedia request";
+        gboolean is_for_audio_device = webkit_user_media_permission_is_for_audio_device(WEBKIT_USER_MEDIA_PERMISSION_REQUEST(request));
+        gboolean is_for_video_device = webkit_user_media_permission_is_for_video_device(WEBKIT_USER_MEDIA_PERMISSION_REQUEST(request));
+        const char *mediaType = NULL;
+        if (is_for_audio_device) {
+            if (is_for_video_device)
+                mediaType = "audio/video";
+            else
+                mediaType = "audio";
+        } else if (is_for_video_device)
+            mediaType = "video";
+        text = g_strdup_printf("Allow access to %s device?", mediaType);
+    } else if (WEBKIT_IS_INSTALL_MISSING_MEDIA_PLUGINS_PERMISSION_REQUEST(request)) {
+        title = "Media plugin missing request";
+        text = g_strdup_printf("The media backend was unable to find a plugin to play the requested media:\n%s.\nAllow to search and install the missing plugin?",
+            webkit_install_missing_media_plugins_permission_request_get_description(WEBKIT_INSTALL_MISSING_MEDIA_PLUGINS_PERMISSION_REQUEST(request)));
+    } else
+        return FALSE;
+
+    GtkWidget *dialog = createInfoBarQuestionMessage(title, text);
+    g_free(text);
+    g_signal_connect(dialog, "response", G_CALLBACK(permissionRequestDialogResponse), g_object_ref(request));
+
+    gtk_box_pack_start(GTK_BOX(tab), dialog, FALSE, FALSE, 0);
+    gtk_box_reorder_child(GTK_BOX(tab), dialog, 0);
+    gtk_widget_show(dialog);
+}
+
+#if GTK_CHECK_VERSION(3, 12, 0)
+static void colorChooserRGBAChanged(GtkColorChooser *colorChooser, GParamSpec *paramSpec, WebKitColorChooserRequest *request)
+{
+    GdkRGBA rgba;
+    gtk_color_chooser_get_rgba(colorChooser, &rgba);
+    webkit_color_chooser_request_set_rgba(request, &rgba);
+}
+
+static void popoverColorClosed(GtkWidget *popover, WebKitColorChooserRequest *request)
+{
+    webkit_color_chooser_request_finish(request);
+}
+
+static void colorChooserRequestFinished(WebKitColorChooserRequest *request, GtkWidget *popover)
+{
+    g_object_unref(request);
+    gtk_widget_destroy(popover);
+}
+
+static gboolean runColorChooserCallback(WebKitWebView *webView, WebKitColorChooserRequest *request, BrowserTab *tab)
+{
+    GtkWidget *popover = gtk_popover_new(GTK_WIDGET(webView));
+
+    GdkRectangle rectangle;
+    webkit_color_chooser_request_get_element_rectangle(request, &rectangle);
+    gtk_popover_set_pointing_to(GTK_POPOVER(popover), &rectangle);
+
+    GtkWidget *colorChooser = gtk_color_chooser_widget_new();
+    GdkRGBA rgba;
+    webkit_color_chooser_request_get_rgba(request, &rgba);
+    gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(colorChooser), &rgba);
+    g_signal_connect(colorChooser, "notify::rgba", G_CALLBACK(colorChooserRGBAChanged), request);
+    gtk_container_add(GTK_CONTAINER(popover), colorChooser);
+    gtk_widget_show(colorChooser);
+
+    g_object_ref(request);
+    g_signal_connect_object(popover, "hide", G_CALLBACK(popoverColorClosed), request, 0);
+    g_signal_connect_object(request, "finished", G_CALLBACK(colorChooserRequestFinished), popover, 0);
+
+    gtk_widget_show(popover);
+
+    return TRUE;
+}
+#endif /* GTK_CHECK_VERSION(3, 12, 0) */
+
+static gboolean inspectorOpenedInWindow(WebKitWebInspector *inspector, BrowserTab *tab)
+{
+    tab->inspectorIsVisible = TRUE;
+    return FALSE;
+}
+
+static gboolean inspectorClosed(WebKitWebInspector *inspector, BrowserTab *tab)
+{
+    tab->inspectorIsVisible = FALSE;
+    return FALSE;
+}
+
+static void browserTabSetProperty(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
+{
+    BrowserTab *tab = BROWSER_TAB(object);
+
+    switch (propId) {
+    case PROP_VIEW:
+        tab->webView = g_value_get_object(value);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
+    }
+}
+
+static void browserTabFinalize(GObject *gObject)
+{
+    BrowserTab *tab = BROWSER_TAB(gObject);
+
+    if (tab->fullScreenMessageLabelId)
+        g_source_remove(tab->fullScreenMessageLabelId);
+
+    G_OBJECT_CLASS(browser_tab_parent_class)->finalize(gObject);
+}
+
+static void browser_tab_init(BrowserTab *tab)
+{
+    gtk_orientable_set_orientation(GTK_ORIENTABLE(tab), GTK_ORIENTATION_VERTICAL);
+}
+
+static void browserTabConstructed(GObject *gObject)
+{
+    BrowserTab *tab = BROWSER_TAB(gObject);
+
+    G_OBJECT_CLASS(browser_tab_parent_class)->constructed(gObject);
+
+    tab->searchBar = BROWSER_SEARCH_BAR(browser_search_bar_new(tab->webView));
+    gtk_box_pack_start(GTK_BOX(tab), GTK_WIDGET(tab->searchBar), FALSE, FALSE, 0);
+
+    GtkWidget *overlay = gtk_overlay_new();
+    gtk_box_pack_start(GTK_BOX(tab), overlay, TRUE, TRUE, 0);
+    gtk_widget_show(overlay);
+
+    tab->statusLabel = gtk_label_new(NULL);
+    gtk_widget_set_halign(tab->statusLabel, GTK_ALIGN_START);
+    gtk_widget_set_valign(tab->statusLabel, GTK_ALIGN_END);
+    gtk_widget_set_margin_left(tab->statusLabel, 1);
+    gtk_widget_set_margin_right(tab->statusLabel, 1);
+    gtk_widget_set_margin_top(tab->statusLabel, 1);
+    gtk_widget_set_margin_bottom(tab->statusLabel, 1);
+    gtk_overlay_add_overlay(GTK_OVERLAY(overlay), tab->statusLabel);
+
+    tab->fullScreenMessageLabel = gtk_label_new(NULL);
+    gtk_widget_set_halign(tab->fullScreenMessageLabel, GTK_ALIGN_CENTER);
+    gtk_widget_set_valign(tab->fullScreenMessageLabel, GTK_ALIGN_CENTER);
+    gtk_widget_set_no_show_all(tab->fullScreenMessageLabel, TRUE);
+    gtk_overlay_add_overlay(GTK_OVERLAY(overlay), tab->fullScreenMessageLabel);
+
+    gtk_container_add(GTK_CONTAINER(overlay), GTK_WIDGET(tab->webView));
+    gtk_widget_show(GTK_WIDGET(tab->webView));
+
+    tab->titleBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
+
+    GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
+    gtk_widget_set_halign(hbox, GTK_ALIGN_CENTER);
+
+    tab->titleSpinner = gtk_spinner_new();
+    gtk_box_pack_start(GTK_BOX(hbox), tab->titleSpinner, FALSE, FALSE, 0);
+
+    tab->titleLabel = gtk_label_new(NULL);
+    gtk_label_set_ellipsize(GTK_LABEL(tab->titleLabel), PANGO_ELLIPSIZE_END);
+    gtk_label_set_single_line_mode(GTK_LABEL(tab->titleLabel), TRUE);
+    gtk_misc_set_padding(GTK_MISC(tab->titleLabel), 0, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), tab->titleLabel, FALSE, FALSE, 0);
+    gtk_widget_show(tab->titleLabel);
+
+    gtk_box_pack_start(GTK_BOX(tab->titleBox), hbox, TRUE, TRUE, 0);
+    gtk_widget_show(hbox);
+
+    tab->titleCloseButton = gtk_button_new();
+    g_signal_connect_swapped(tab->titleCloseButton, "clicked", G_CALLBACK(gtk_widget_destroy), tab);
+    gtk_button_set_relief(GTK_BUTTON(tab->titleCloseButton), GTK_RELIEF_NONE);
+    gtk_button_set_focus_on_click(GTK_BUTTON(tab->titleCloseButton), FALSE);
+
+    GtkWidget *image = gtk_image_new_from_icon_name("window-close-symbolic", GTK_ICON_SIZE_MENU);
+    gtk_container_add(GTK_CONTAINER(tab->titleCloseButton), image);
+    gtk_widget_show(image);
+
+    gtk_box_pack_start(GTK_BOX(tab->titleBox), tab->titleCloseButton, FALSE, FALSE, 0);
+    gtk_widget_show(tab->titleCloseButton);
+
+    g_signal_connect(tab->webView, "notify::title", G_CALLBACK(titleChanged), tab);
+    g_signal_connect(tab->webView, "notify::is-loading", G_CALLBACK(isLoadingChanged), tab);
+    g_signal_connect(tab->webView, "decide-policy", G_CALLBACK(decidePolicy), tab);
+    g_signal_connect(tab->webView, "load-changed", G_CALLBACK(loadChanged), tab);
+    g_signal_connect(tab->webView, "load-failed-with-tls-errors", G_CALLBACK(loadFailedWithTLSerrors), tab);
+    g_signal_connect(tab->webView, "permission-request", G_CALLBACK(decidePermissionRequest), tab);
+#if GTK_CHECK_VERSION(3, 12, 0)
+    g_signal_connect(tab->webView, "run-color-chooser", G_CALLBACK(runColorChooserCallback), tab);
+#endif
+
+    WebKitWebInspector *inspector = webkit_web_view_get_inspector(tab->webView);
+    g_signal_connect(inspector, "open-window", G_CALLBACK(inspectorOpenedInWindow), tab);
+    g_signal_connect(inspector, "closed", G_CALLBACK(inspectorClosed), tab);
+
+    if (webkit_web_view_is_editable(tab->webView))
+        webkit_web_view_load_html(tab->webView, "<html></html>", "file:///");
+}
+
+static void browser_tab_class_init(BrowserTabClass *klass)
+{
+    GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
+    gobjectClass->constructed = browserTabConstructed;
+    gobjectClass->set_property = browserTabSetProperty;
+    gobjectClass->finalize = browserTabFinalize;
+
+    g_object_class_install_property(
+        gobjectClass,
+        PROP_VIEW,
+        g_param_spec_object(
+            "view",
+            "View",
+            "The web view of this tab",
+            WEBKIT_TYPE_WEB_VIEW,
+            G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static char *getInternalURI(const char *uri)
+{
+    /* Internally we use minibrowser-about: as about: prefix is ignored by WebKit. */
+    if (g_str_has_prefix(uri, "about:") && !g_str_equal(uri, "about:blank"))
+        return g_strconcat(BROWSER_ABOUT_SCHEME, uri + strlen ("about"), NULL);
+
+    return g_strdup(uri);
+}
+
+/* Public API. */
+GtkWidget *browser_tab_new(WebKitWebView *view)
+{
+    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(view), NULL);
+
+    return GTK_WIDGET(g_object_new(BROWSER_TYPE_TAB, "view", view, NULL));
+}
+
+WebKitWebView *browser_tab_get_web_view(BrowserTab *tab)
+{
+    g_return_val_if_fail(BROWSER_IS_TAB(tab), NULL);
+
+    return tab->webView;
+}
+
+void browser_tab_load_uri(BrowserTab *tab, const char *uri)
+{
+    g_return_if_fail(BROWSER_IS_TAB(tab));
+    g_return_if_fail(uri);
+
+    if (!g_str_has_prefix(uri, "_javascript_:")) {
+        char *internalURI = getInternalURI(uri);
+        webkit_web_view_load_uri(tab->webView, internalURI);
+        g_free(internalURI);
+        return;
+    }
+
+    webkit_web_view_run_javascript(tab->webView, strstr(uri, "_javascript_:"), NULL, NULL, NULL);
+}
+
+GtkWidget *browser_tab_get_title_widget(BrowserTab *tab)
+{
+    g_return_val_if_fail(BROWSER_IS_TAB(tab), NULL);
+
+    return tab->titleBox;
+}
+
+void browser_tab_set_status_text(BrowserTab *tab, const char *text)
+{
+    g_return_if_fail(BROWSER_IS_TAB(tab));
+
+    gtk_label_set_text(GTK_LABEL(tab->statusLabel), text);
+    gtk_widget_set_visible(tab->statusLabel, !!text);
+}
+
+void browser_tab_toggle_inspector(BrowserTab *tab)
+{
+    g_return_if_fail(BROWSER_IS_TAB(tab));
+
+    WebKitWebInspector *inspector = webkit_web_view_get_inspector(tab->webView);
+    if (!tab->inspectorIsVisible) {
+        webkit_web_inspector_show(inspector);
+        tab->inspectorIsVisible = TRUE;
+    } else
+        webkit_web_inspector_close(inspector);
+}
+
+void browser_tab_start_search(BrowserTab *tab)
+{
+    g_return_if_fail(BROWSER_IS_TAB(tab));
+
+    if (!gtk_widget_get_visible(GTK_WIDGET(tab->searchBar)))
+        browser_search_bar_open(tab->searchBar);
+}
+
+void browser_tab_stop_search(BrowserTab *tab)
+{
+    g_return_if_fail(BROWSER_IS_TAB(tab));
+
+    if (gtk_widget_get_visible(GTK_WIDGET(tab->searchBar)))
+        browser_search_bar_close(tab->searchBar);
+}
+
+void browser_tab_add_accelerators(BrowserTab *tab, GtkAccelGroup *accelGroup)
+{
+    g_return_if_fail(BROWSER_IS_TAB(tab));
+    g_return_if_fail(GTK_IS_ACCEL_GROUP(accelGroup));
+
+    browser_search_bar_add_accelerators(tab->searchBar, accelGroup);
+}
+
+static gboolean fullScreenMessageTimeoutCallback(BrowserTab *tab)
+{
+    gtk_widget_hide(tab->fullScreenMessageLabel);
+    tab->fullScreenMessageLabelId = 0;
+    return FALSE;
+}
+
+void browser_tab_enter_fullscreen(BrowserTab *tab)
+{
+    g_return_if_fail(BROWSER_IS_TAB(tab));
+
+    const gchar *titleOrURI = webkit_web_view_get_title(tab->webView);
+    if (!titleOrURI || !titleOrURI[0])
+        titleOrURI = webkit_web_view_get_uri(tab->webView);
+
+    gchar *message = g_strdup_printf("%s is now full screen. Press ESC or f to exit.", titleOrURI);
+    gtk_label_set_text(GTK_LABEL(tab->fullScreenMessageLabel), message);
+    g_free(message);
+
+    gtk_widget_show(tab->fullScreenMessageLabel);
+
+    tab->fullScreenMessageLabelId = g_timeout_add_seconds(2, (GSourceFunc)fullScreenMessageTimeoutCallback, tab);
+    g_source_set_name_by_id(tab->fullScreenMessageLabelId, "[WebKit] fullScreenMessageTimeoutCallback");
+
+    tab->wasSearchingWhenEnteredFullscreen = gtk_widget_get_visible(GTK_WIDGET(tab->searchBar));
+    browser_tab_stop_search(tab);
+}
+
+void browser_tab_leave_fullscreen(BrowserTab *tab)
+{
+    g_return_if_fail(BROWSER_IS_TAB(tab));
+
+    if (tab->fullScreenMessageLabelId) {
+        g_source_remove(tab->fullScreenMessageLabelId);
+        tab->fullScreenMessageLabelId = 0;
+    }
+
+    gtk_widget_hide(tab->fullScreenMessageLabel);
+
+    if (tab->wasSearchingWhenEnteredFullscreen) {
+        /* Opening the search bar steals the focus. Usually, we want
+         * this but not when coming back from fullscreen.
+         */
+        GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(tab)));
+        GtkWidget *focusWidget = gtk_window_get_focus(window);
+        browser_tab_start_search(tab);
+        gtk_window_set_focus(window, focusWidget);
+    }
+}

Copied: trunk/Tools/MiniBrowser/gtk/BrowserTab.h (from rev 203270, trunk/Tools/MiniBrowser/gtk/BrowserWindow.h) (0 => 203271)


--- trunk/Tools/MiniBrowser/gtk/BrowserTab.h	                        (rev 0)
+++ trunk/Tools/MiniBrowser/gtk/BrowserTab.h	2016-07-15 09:25:15 UTC (rev 203271)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BrowserTab_h
+#define BrowserTab_h
+
+#include <gtk/gtk.h>
+#include <webkit2/webkit2.h>
+
+G_BEGIN_DECLS
+
+#define BROWSER_TYPE_TAB            (browser_tab_get_type())
+#define BROWSER_TAB(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), BROWSER_TYPE_TAB, BrowserTab))
+#define BROWSER_TAB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  BROWSER_TYPE_TAB, BrowserTabClass))
+#define BROWSER_IS_TAB(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), BROWSER_TYPE_TAB))
+#define BROWSER_IS_TAB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  BROWSER_TYPE_TAB))
+#define BROWSER_TAB_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  BROWSER_TYPE_TAB, BrowserTabClass))
+
+typedef struct _BrowserTab        BrowserTab;
+typedef struct _BrowserTabClass   BrowserTabClass;
+
+GType browser_tab_get_type(void);
+
+GtkWidget* browser_tab_new(WebKitWebView*);
+WebKitWebView* browser_tab_get_web_view(BrowserTab*);
+void browser_tab_load_uri(BrowserTab*, const char* uri);
+GtkWidget *browser_tab_get_title_widget(BrowserTab*);
+void browser_tab_set_status_text(BrowserTab*, const char* text);
+void browser_tab_toggle_inspector(BrowserTab*);
+void browser_tab_start_search(BrowserTab*);
+void browser_tab_stop_search(BrowserTab*);
+void browser_tab_add_accelerators(BrowserTab*, GtkAccelGroup*);
+void browser_tab_enter_fullscreen(BrowserTab*);
+void browser_tab_leave_fullscreen(BrowserTab*);
+
+G_END_DECLS
+
+#endif

Modified: trunk/Tools/MiniBrowser/gtk/BrowserWindow.c (203270 => 203271)


--- trunk/Tools/MiniBrowser/gtk/BrowserWindow.c	2016-07-15 06:03:25 UTC (rev 203270)
+++ trunk/Tools/MiniBrowser/gtk/BrowserWindow.c	2016-07-15 09:25:15 UTC (rev 203271)
@@ -33,15 +33,10 @@
 #include "BrowserDownloadsBar.h"
 #include "BrowserSearchBar.h"
 #include "BrowserSettingsDialog.h"
+#include "BrowserTab.h"
 #include <gdk/gdkkeysyms.h>
 #include <string.h>
 
-enum {
-    PROP_0,
-
-    PROP_VIEW
-};
-
 struct _BrowserWindow {
     GtkWindow parent;
 
@@ -57,19 +52,15 @@
     GtkWidget *italicItem;
     GtkWidget *underlineItem;
     GtkWidget *strikethroughItem;
-    GtkWidget *statusLabel;
     GtkWidget *settingsDialog;
-    WebKitWebView *webView;
+    GtkWidget *notebook;
+    BrowserTab *activeTab;
     GtkWidget *downloadsBar;
-    BrowserSearchBar *searchBar;
     gboolean searchBarVisible;
-    gboolean inspectorWindowIsVisible;
     gboolean fullScreenIsEnabled;
     GdkPixbuf *favicon;
     GtkWidget *reloadOrStopButton;
-    GtkWidget *fullScreenMessageLabel;
     GtkWindow *parentWindow;
-    guint fullScreenMessageLabelId;
     guint resetEntryProgressTimeoutId;
     gchar *sessionFile;
 };
@@ -79,7 +70,6 @@
 };
 
 static const char *defaultWindowTitle = "WebKitGTK+ MiniBrowser";
-static const char *miniBrowserAboutScheme = "minibrowser-about";
 static const gdouble minimumZoomLevel = 0.5;
 static const gdouble maximumZoomLevel = 3;
 static const gdouble defaultZoomLevel = 1;
@@ -88,20 +78,11 @@
 
 G_DEFINE_TYPE(BrowserWindow, browser_window, GTK_TYPE_WINDOW)
 
-static char *getInternalURI(const char *uri)
-{
-    // Internally we use minibrowser-about: as about: prefix is ignored by WebKit.
-    if (g_str_has_prefix(uri, "about:") && !g_str_equal(uri, "about:blank"))
-        return g_strconcat(miniBrowserAboutScheme, uri + strlen ("about"), NULL);
-
-    return g_strdup(uri);
-}
-
 static char *getExternalURI(const char *uri)
 {
-    // From the user point of view we support about: prefix.
-    if (g_str_has_prefix(uri, miniBrowserAboutScheme))
-        return g_strconcat("about", uri + strlen(miniBrowserAboutScheme), NULL);
+    /* From the user point of view we support about: prefix. */
+    if (uri && g_str_has_prefix(uri, BROWSER_ABOUT_SCHEME))
+        return g_strconcat("about", uri + strlen(BROWSER_ABOUT_SCHEME), NULL);
 
     return g_strdup(uri);
 }
@@ -108,8 +89,7 @@
 
 static void browserWindowSetStatusText(BrowserWindow *window, const char *text)
 {
-    gtk_label_set_text(GTK_LABEL(window->statusLabel), text);
-    gtk_widget_set_visible(window->statusLabel, !!text);
+    browser_tab_set_status_text(window->activeTab, text);
 }
 
 static void resetStatusText(GtkWidget *widget, BrowserWindow *window)
@@ -124,20 +104,23 @@
 
 static void reloadOrStopCallback(BrowserWindow *window)
 {
-    if (webkit_web_view_is_loading(window->webView))
-        webkit_web_view_stop_loading(window->webView);
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    if (webkit_web_view_is_loading(webView))
+        webkit_web_view_stop_loading(webView);
     else
-        webkit_web_view_reload(window->webView);
+        webkit_web_view_reload(webView);
 }
 
 static void goBackCallback(BrowserWindow *window)
 {
-    webkit_web_view_go_back(window->webView);
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    webkit_web_view_go_back(webView);
 }
 
 static void goForwardCallback(BrowserWindow *window)
 {
-    webkit_web_view_go_forward(window->webView);
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    webkit_web_view_go_forward(webView);
 }
 
 static void settingsCallback(BrowserWindow *window)
@@ -147,7 +130,8 @@
         return;
     }
 
-    window->settingsDialog = browser_settings_dialog_new(webkit_web_view_get_settings(window->webView));
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    window->settingsDialog = browser_settings_dialog_new(webkit_web_view_get_settings(webView));
     gtk_window_set_transient_for(GTK_WINDOW(window->settingsDialog), GTK_WINDOW(window));
     g_object_add_weak_pointer(G_OBJECT(window->settingsDialog), (gpointer *)&window->settingsDialog);
     gtk_widget_show(window->settingsDialog);
@@ -156,8 +140,11 @@
 static void webViewURIChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
 {
     char *externalURI = getExternalURI(webkit_web_view_get_uri(webView));
-    gtk_entry_set_text(GTK_ENTRY(window->uriEntry), externalURI);
-    g_free(externalURI);
+    if (externalURI) {
+        gtk_entry_set_text(GTK_ENTRY(window->uriEntry), externalURI);
+        g_free(externalURI);
+    } else
+        gtk_entry_set_text(GTK_ENTRY(window->uriEntry), "");
 }
 
 static void webViewTitleChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
@@ -207,7 +194,8 @@
     if (!item)
         return;
 
-    webkit_web_view_go_to_back_forward_list_item(window->webView, item);
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    webkit_web_view_go_to_back_forward_list_item(webView, item);
 }
 
 static GtkWidget *browserWindowCreateBackForwardMenu(BrowserWindow *window, GList *list)
@@ -241,8 +229,9 @@
 
 static void browserWindowUpdateNavigationActions(BrowserWindow *window, WebKitBackForwardList *backForwadlist)
 {
-    gtk_widget_set_sensitive(window->backItem, webkit_web_view_can_go_back(window->webView));
-    gtk_widget_set_sensitive(window->forwardItem, webkit_web_view_can_go_forward(window->webView));
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    gtk_widget_set_sensitive(window->backItem, webkit_web_view_can_go_back(webView));
+    gtk_widget_set_sensitive(window->forwardItem, webkit_web_view_can_go_forward(webView));
 
     GList *list = g_list_reverse(webkit_back_forward_list_get_back_list_with_limit(backForwadlist, 10));
     gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(window->backItem),
@@ -260,21 +249,6 @@
     browserWindowUpdateNavigationActions(window, backForwadlist);
 }
 
-static void permissionRequestDialogCallback(GtkDialog *dialog, gint response, WebKitPermissionRequest *request)
-{
-    switch (response) {
-    case GTK_RESPONSE_YES:
-        webkit_permission_request_allow(request);
-        break;
-    default:
-        webkit_permission_request_deny(request);
-        break;
-    }
-
-    gtk_widget_destroy(GTK_WIDGET(dialog));
-    g_object_unref(request);
-}
-
 static void webViewClose(WebKitWebView *webView, BrowserWindow *window)
 {
     gtk_widget_destroy(GTK_WIDGET(window));
@@ -308,65 +282,33 @@
     gtk_widget_show(GTK_WIDGET(window));
 }
 
-static gboolean fullScreenMessageTimeoutCallback(BrowserWindow *window)
+static GtkWidget *webViewCreate(WebKitWebView *webView, WebKitNavigationAction *navigation, BrowserWindow *window)
 {
-    gtk_widget_hide(window->fullScreenMessageLabel);
-    window->fullScreenMessageLabelId = 0;
-    return FALSE;
+    WebKitWebView *newWebView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_view(webView));
+    webkit_web_view_set_settings(newWebView, webkit_web_view_get_settings(webView));
+
+    GtkWidget *newWindow = browser_window_new(GTK_WINDOW(window));
+    browser_window_append_view(BROWSER_WINDOW(newWindow), newWebView);
+    g_signal_connect(newWebView, "ready-to-show", G_CALLBACK(webViewReadyToShow), newWindow);
+    g_signal_connect(newWebView, "run-as-modal", G_CALLBACK(webViewRunAsModal), newWindow);
+    g_signal_connect(newWebView, "close", G_CALLBACK(webViewClose), newWindow);
+    return GTK_WIDGET(newWebView);
 }
 
 static gboolean webViewEnterFullScreen(WebKitWebView *webView, BrowserWindow *window)
 {
-    gchar *titleOrURI = g_strdup(webkit_web_view_get_title(window->webView));
-    if (!titleOrURI)
-        titleOrURI = getExternalURI(webkit_web_view_get_uri(window->webView));
-    gchar *message = g_strdup_printf("%s is now full screen. Press ESC or f to exit.", titleOrURI);
-    gtk_label_set_text(GTK_LABEL(window->fullScreenMessageLabel), message);
-    g_free(titleOrURI);
-    g_free(message);
-
-    gtk_widget_show(window->fullScreenMessageLabel);
-
-    window->fullScreenMessageLabelId = g_timeout_add_seconds(2, (GSourceFunc)fullScreenMessageTimeoutCallback, window);
-    g_source_set_name_by_id(window->fullScreenMessageLabelId, "[WebKit] fullScreenMessageTimeoutCallback");
     gtk_widget_hide(window->toolbar);
-    window->searchBarVisible = gtk_widget_get_visible(GTK_WIDGET(window->searchBar));
-    browser_search_bar_close(window->searchBar);
-
+    browser_tab_enter_fullscreen(window->activeTab);
     return FALSE;
 }
 
 static gboolean webViewLeaveFullScreen(WebKitWebView *webView, BrowserWindow *window)
 {
-    if (window->fullScreenMessageLabelId) {
-        g_source_remove(window->fullScreenMessageLabelId);
-        window->fullScreenMessageLabelId = 0;
-    }
-    gtk_widget_hide(window->fullScreenMessageLabel);
+    browser_tab_leave_fullscreen(window->activeTab);
     gtk_widget_show(window->toolbar);
-    if (window->searchBarVisible) {
-        // Opening the search bar steals the focus. Usually, we want
-        // this but not when coming back from fullscreen.
-        GtkWidget *focusWidget = gtk_window_get_focus(GTK_WINDOW(window));
-        browser_search_bar_open(window->searchBar);
-        gtk_window_set_focus(GTK_WINDOW(window), focusWidget);
-    }
-
     return FALSE;
 }
 
-static GtkWidget *webViewCreate(WebKitWebView *webView, WebKitNavigationAction *navigation, BrowserWindow *window)
-{
-    WebKitWebView *newWebView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_view(webView));
-    webkit_web_view_set_settings(newWebView, webkit_web_view_get_settings(webView));
-
-    GtkWidget *newWindow = browser_window_new(newWebView, GTK_WINDOW(window));
-    g_signal_connect(newWebView, "ready-to-show", G_CALLBACK(webViewReadyToShow), newWindow);
-    g_signal_connect(newWebView, "run-as-modal", G_CALLBACK(webViewRunAsModal), newWindow);
-    g_signal_connect(newWebView, "close", G_CALLBACK(webViewClose), newWindow);
-    return GTK_WIDGET(newWebView);
-}
-
 static gboolean webViewLoadFailed(WebKitWebView *webView, WebKitLoadEvent loadEvent, const char *failingURI, GError *error, BrowserWindow *window)
 {
     gtk_entry_set_progress_fraction(GTK_ENTRY(window->uriEntry), 0.);
@@ -373,104 +315,26 @@
     return FALSE;
 }
 
-static gboolean webViewLoadFailedWithTLSerrors(WebKitWebView *webView, const char *failingURI, GTlsCertificate *certificate, GTlsCertificateFlags errors, BrowserWindow *window)
-{
-    GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-        GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "%s", "Invalid TLS Certificate");
-    gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "Failed to load %s: Do you want to continue ignoring the TLS errors?", failingURI);
-    int response = gtk_dialog_run(GTK_DIALOG(dialog));
-    gtk_widget_destroy(dialog);
-
-    if (response == GTK_RESPONSE_YES) {
-        SoupURI *uri = soup_uri_new(failingURI);
-        webkit_web_context_allow_tls_certificate_for_host(webkit_web_view_get_context(webView), certificate, uri->host);
-        soup_uri_free(uri);
-        webkit_web_view_load_uri(webView, failingURI);
-    }
-
-    return TRUE;
-}
-
 static gboolean webViewDecidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, BrowserWindow *window)
 {
-    switch (decisionType) {
-    case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: {
-        WebKitNavigationAction *navigationAction = webkit_navigation_policy_decision_get_navigation_action(WEBKIT_NAVIGATION_POLICY_DECISION(decision));
-        if (webkit_navigation_action_get_navigation_type(navigationAction) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED
-            || webkit_navigation_action_get_mouse_button(navigationAction) != GDK_BUTTON_MIDDLE)
-            return FALSE;
+    if (decisionType != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
+        return FALSE;
 
-        // Opening a new window if link clicked with the middle button.
-        WebKitWebView *newWebView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(webkit_web_view_get_context(webView)));
-        GtkWidget *newWindow = browser_window_new(newWebView, GTK_WINDOW(window));
-        webkit_web_view_load_request(newWebView, webkit_navigation_action_get_request(navigationAction));
-        gtk_widget_show(newWindow);
-
-        webkit_policy_decision_ignore(decision);
-        return TRUE;
-    }
-    case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: {
-        WebKitResponsePolicyDecision *responseDecision = WEBKIT_RESPONSE_POLICY_DECISION(decision);
-        if (webkit_response_policy_decision_is_mime_type_supported(responseDecision))
-            return FALSE;
-
-        WebKitWebResource *mainResource = webkit_web_view_get_main_resource(webView);
-        WebKitURIRequest *request = webkit_response_policy_decision_get_request(responseDecision);
-        const char *requestURI = webkit_uri_request_get_uri(request);
-        if (g_strcmp0(webkit_web_resource_get_uri(mainResource), requestURI))
-            return FALSE;
-
-        webkit_policy_decision_download(decision);
-        return TRUE;
-    }
-    case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
-    default:
+    WebKitNavigationAction *navigationAction = webkit_navigation_policy_decision_get_navigation_action(WEBKIT_NAVIGATION_POLICY_DECISION(decision));
+    if (webkit_navigation_action_get_navigation_type(navigationAction) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED
+        || webkit_navigation_action_get_mouse_button(navigationAction) != GDK_BUTTON_MIDDLE)
         return FALSE;
-    }
-}
 
-static gboolean webViewDecidePermissionRequest(WebKitWebView *webView, WebKitPermissionRequest *request, BrowserWindow *window)
-{
-    const gchar *dialog_title = NULL;
-    const gchar *dialog_message = NULL;
-    const gchar *dialog_message_format = NULL;
-
-    if (WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(request)) {
-        dialog_title = "Geolocation request";
-        dialog_message_format = "%s";
-        dialog_message = "Allow geolocation request?";
-    } else if (WEBKIT_IS_NOTIFICATION_PERMISSION_REQUEST(request)) {
-        dialog_title = "Notification request";
-        dialog_message_format = "%s";
-        dialog_message = "Allow notifications request?";
-    } else if (WEBKIT_IS_USER_MEDIA_PERMISSION_REQUEST(request)) {
-        dialog_message_format = "Allow access to %s device?";
-        gboolean is_for_audio_device = webkit_user_media_permission_is_for_audio_device(WEBKIT_USER_MEDIA_PERMISSION_REQUEST(request));
-        gboolean is_for_video_device = webkit_user_media_permission_is_for_video_device(WEBKIT_USER_MEDIA_PERMISSION_REQUEST(request));
-        dialog_title = "UserMedia request";
-        if (is_for_audio_device) {
-            if (is_for_video_device)
-                dialog_message = "audio/video";
-            else
-                dialog_message = "audio";
-        } else if (is_for_video_device)
-            dialog_message = "video";
-    } else if (WEBKIT_IS_INSTALL_MISSING_MEDIA_PLUGINS_PERMISSION_REQUEST(request)) {
-        dialog_title = "Media plugin missing request";
-        dialog_message_format = "The media backend was unable to find a plugin to play the requested media:\n%s.\nAllow to search and install the missing plugin?";
-        dialog_message = webkit_install_missing_media_plugins_permission_request_get_description(WEBKIT_INSTALL_MISSING_MEDIA_PLUGINS_PERMISSION_REQUEST(request));
-    } else
+    /* Multiple tabs are not allowed in editor mode. */
+    if (webkit_web_view_is_editable(webView))
         return FALSE;
 
-    GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window),
-        GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-        GTK_MESSAGE_QUESTION,
-        GTK_BUTTONS_YES_NO,
-        "%s", dialog_title);
+    /* Opening a new tab if link clicked with the middle button. */
+    WebKitWebView *newWebView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(webkit_web_view_get_context(webView)));
+    browser_window_append_view(window, newWebView);
+    webkit_web_view_load_request(newWebView, webkit_navigation_action_get_request(navigationAction));
 
-    gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), dialog_message_format, dialog_message);
-    g_signal_connect(dialog, "response", G_CALLBACK(permissionRequestDialogCallback), g_object_ref(request));
-    gtk_widget_show(dialog);
+    webkit_policy_decision_ignore(decision);
     return TRUE;
 }
 
@@ -485,13 +349,15 @@
 
 static gboolean browserWindowCanZoomIn(BrowserWindow *window)
 {
-    gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) * zoomStep;
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    gdouble zoomLevel = webkit_web_view_get_zoom_level(webView) * zoomStep;
     return zoomLevel < maximumZoomLevel;
 }
 
 static gboolean browserWindowCanZoomOut(BrowserWindow *window)
 {
-    gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) / zoomStep;
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    gdouble zoomLevel = webkit_web_view_get_zoom_level(webView) / zoomStep;
     return zoomLevel > minimumZoomLevel;
 }
 
@@ -498,8 +364,9 @@
 static gboolean browserWindowZoomIn(BrowserWindow *window)
 {
     if (browserWindowCanZoomIn(window)) {
-        gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) * zoomStep;
-        webkit_web_view_set_zoom_level(window->webView, zoomLevel);
+        WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+        gdouble zoomLevel = webkit_web_view_get_zoom_level(webView) * zoomStep;
+        webkit_web_view_set_zoom_level(webView, zoomLevel);
         return TRUE;
     }
     return FALSE;
@@ -508,8 +375,9 @@
 static gboolean browserWindowZoomOut(BrowserWindow *window)
 {
     if (browserWindowCanZoomOut(window)) {
-        gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) / zoomStep;
-        webkit_web_view_set_zoom_level(window->webView, zoomLevel);
+        WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+        gdouble zoomLevel = webkit_web_view_get_zoom_level(webView) / zoomStep;
+        webkit_web_view_set_zoom_level(webView, zoomLevel);
         return TRUE;
     }
     return FALSE;
@@ -521,58 +389,13 @@
 
     if ((event->state & mod) != GDK_CONTROL_MASK)
         return FALSE;
-    
+
     if (event->delta_y < 0)
         return browserWindowZoomIn(window);
-    
+
     return browserWindowZoomOut(window);
 }
 
-#if GTK_CHECK_VERSION(3, 12, 0)
-static void colorChooserRGBAChanged(GtkColorChooser *colorChooser, GParamSpec *paramSpec, WebKitColorChooserRequest *request)
-{
-    GdkRGBA rgba;
-    gtk_color_chooser_get_rgba(colorChooser, &rgba);
-    webkit_color_chooser_request_set_rgba(request, &rgba);
-}
-
-static void popoverColorClosed(GtkWidget *popover, WebKitColorChooserRequest *request)
-{
-    webkit_color_chooser_request_finish(request);
-}
-
-static void colorChooserRequestFinished(WebKitColorChooserRequest *request, GtkWidget *popover)
-{
-    g_object_unref(request);
-    gtk_widget_destroy(popover);
-}
-
-static gboolean runColorChooserCallback(WebKitWebView *webView, WebKitColorChooserRequest *request, BrowserWindow *window)
-{
-    GtkWidget *popover = gtk_popover_new(GTK_WIDGET(webView));
-
-    GdkRectangle rectangle;
-    webkit_color_chooser_request_get_element_rectangle(request, &rectangle);
-    gtk_popover_set_pointing_to(GTK_POPOVER(popover), &rectangle);
-
-    GtkWidget *colorChooser = gtk_color_chooser_widget_new();
-    GdkRGBA rgba;
-    webkit_color_chooser_request_get_rgba(request, &rgba);
-    gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(colorChooser), &rgba);
-    g_signal_connect(colorChooser, "notify::rgba", G_CALLBACK(colorChooserRGBAChanged), request);
-    gtk_container_add(GTK_CONTAINER(popover), colorChooser);
-    gtk_widget_show(colorChooser);
-
-    g_object_ref(request);
-    g_signal_connect_object(popover, "hide", G_CALLBACK(popoverColorClosed), request, 0);
-    g_signal_connect_object(request, "finished", G_CALLBACK(colorChooserRequestFinished), popover, 0);
-
-    gtk_widget_show(popover);
-
-    return TRUE;
-}
-#endif /* GTK_CHECK_VERSION(3, 12, 0) */
-
 static void browserWindowUpdateZoomActions(BrowserWindow *window)
 {
     gtk_widget_set_sensitive(window->zoomInItem, browserWindowCanZoomIn(window));
@@ -593,10 +416,10 @@
         gtk_entry_set_icon_from_stock(entry, GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_NEW);
 }
 
-static void faviconChanged(GObject *object, GParamSpec *paramSpec, BrowserWindow *window)
+static void faviconChanged(WebKitWebView *webView, GParamSpec *paramSpec, BrowserWindow *window)
 {
     GdkPixbuf *favicon = NULL;
-    cairo_surface_t *surface = webkit_web_view_get_favicon(window->webView);
+    cairo_surface_t *surface = webkit_web_view_get_favicon(webView);
 
     if (surface) {
         int width = cairo_image_surface_get_width(surface);
@@ -611,24 +434,12 @@
     updateUriEntryIcon(window);
 }
 
-static void webViewIsLoadingChanged(GObject *object, GParamSpec *paramSpec, BrowserWindow *window)
+static void webViewIsLoadingChanged(WebKitWebView *webView, GParamSpec *paramSpec, BrowserWindow *window)
 {
-    gboolean isLoading = webkit_web_view_is_loading(window->webView);
+    gboolean isLoading = webkit_web_view_is_loading(webView);
     gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(window->reloadOrStopButton), isLoading ? GTK_STOCK_STOP : GTK_STOCK_REFRESH);
 }
 
-static gboolean inspectorWasOpenedInAnotherWindow(WebKitWebInspector *inspectorWindow, BrowserWindow *window)
-{
-    window->inspectorWindowIsVisible = TRUE;
-    return FALSE;
-}
-
-static gboolean inspectorWasClosed(WebKitWebInspector *inspectorWindow, BrowserWindow *window)
-{
-    window->inspectorWindowIsVisible = FALSE;
-    return FALSE;
-}
-
 static void zoomInCallback(BrowserWindow *window)
 {
     browserWindowZoomIn(window);
@@ -641,49 +452,54 @@
 
 static void defaultZoomCallback(BrowserWindow *window)
 {
-    webkit_web_view_set_zoom_level(window->webView, defaultZoomLevel);
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    webkit_web_view_set_zoom_level(webView, defaultZoomLevel);
 }
 
 static void searchCallback(BrowserWindow *window)
 {
-    browser_search_bar_open(window->searchBar);
+    browser_tab_start_search(window->activeTab);
 }
 
-static gboolean toggleWebInspector(BrowserWindow *window, gpointer user_data)
+static void newTabCallback(BrowserWindow *window)
 {
-    WebKitWebInspector *inspectorWindow;
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    if (webkit_web_view_is_editable(webView))
+        return;
+    WebKitSettings *settings = webkit_web_view_get_settings(webView);
+    browser_window_append_view(window, WEBKIT_WEB_VIEW(webkit_web_view_new_with_settings(settings)));
+    gtk_notebook_set_current_page(GTK_NOTEBOOK(window->notebook), -1);
+}
 
-    inspectorWindow = webkit_web_view_get_inspector(WEBKIT_WEB_VIEW(window->webView));
-    if (!window->inspectorWindowIsVisible) {
-        webkit_web_inspector_show(inspectorWindow);
-        window->inspectorWindowIsVisible = TRUE;
-    } else
-        webkit_web_inspector_close(inspectorWindow);
-
-    return TRUE;
+static void toggleWebInspector(BrowserWindow *window)
+{
+    browser_tab_toggle_inspector(window->activeTab);
 }
 
-static void reloadPage(BrowserWindow *window, gpointer user_data)
+static void reloadPage(BrowserWindow *window)
 {
-    webkit_web_view_reload(window->webView);
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    webkit_web_view_reload(webView);
 }
 
-static void reloadPageIgnoringCache(BrowserWindow *window, gpointer user_data)
+static void reloadPageIgnoringCache(BrowserWindow *window)
 {
-    webkit_web_view_reload_bypass_cache(window->webView);
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    webkit_web_view_reload_bypass_cache(webView);
 }
 
-static void stopPageLoad(BrowserWindow *window, gpointer user_data)
+static void stopPageLoad(BrowserWindow *window)
 {
-    if (gtk_widget_get_visible(GTK_WIDGET(window->searchBar))) 
-        browser_search_bar_close(window->searchBar);
-    else if (webkit_web_view_is_loading(window->webView))
-        webkit_web_view_stop_loading(window->webView);
+    browser_tab_stop_search(window->activeTab);
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    if (webkit_web_view_is_loading(webView))
+        webkit_web_view_stop_loading(webView);
 }
 
-static void loadHomePage(BrowserWindow *window, gpointer user_data)
+static void loadHomePage(BrowserWindow *window)
 {
-    webkit_web_view_load_uri(window->webView, BROWSER_DEFAULT_URL);
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    webkit_web_view_load_uri(webView, BROWSER_DEFAULT_URL);
 }
 
 static gboolean toggleFullScreen(BrowserWindow *window, gpointer user_data)
@@ -702,7 +518,8 @@
 
 static void editingCommandCallback(GtkWidget*widget, BrowserWindow *window)
 {
-    webkit_web_view_execute_editing_command(window->webView, gtk_widget_get_name(widget));
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    webkit_web_view_execute_editing_command(webView, gtk_widget_get_name(widget));
 }
 
 static void insertImageCommandCallback(GtkWidget*widget, BrowserWindow *window)
@@ -718,7 +535,8 @@
     if (gtk_dialog_run(GTK_DIALOG(fileChooser)) == GTK_RESPONSE_ACCEPT) {
         char *uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(fileChooser));
         if (uri) {
-            webkit_web_view_execute_editing_command_with_argument(window->webView, WEBKIT_EDITING_COMMAND_INSERT_IMAGE, uri);
+            WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+            webkit_web_view_execute_editing_command_with_argument(webView, WEBKIT_EDITING_COMMAND_INSERT_IMAGE, uri);
             g_free(uri);
         }
     }
@@ -738,8 +556,10 @@
 
     if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
         const char *url = ""
-        if (url && *url)
-            webkit_web_view_execute_editing_command_with_argument(window->webView, WEBKIT_EDITING_COMMAND_CREATE_LINK, url);
+        if (url && *url) {
+            WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+            webkit_web_view_execute_editing_command_with_argument(webView, WEBKIT_EDITING_COMMAND_CREATE_LINK, url);
+        }
     }
 
     gtk_widget_destroy(dialog);
@@ -774,9 +594,6 @@
         window->accelGroup = NULL;
     }
 
-    if (window->fullScreenMessageLabelId)
-        g_source_remove(window->fullScreenMessageLabelId);
-
     if (window->resetEntryProgressTimeoutId)
         g_source_remove(window->resetEntryProgressTimeoutId);
 
@@ -788,32 +605,6 @@
         gtk_main_quit();
 }
 
-static void browserWindowGetProperty(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
-{
-    BrowserWindow *window = BROWSER_WINDOW(object);
-
-    switch (propId) {
-    case PROP_VIEW:
-        g_value_set_object(value, browser_window_get_view(window));
-        break;
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
-    }
-}
-
-static void browserWindowSetProperty(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
-{
-    BrowserWindow* window = BROWSER_WINDOW(object);
-
-    switch (propId) {
-    case PROP_VIEW:
-        window->webView = g_value_get_object(value);
-        break;
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
-    }
-}
-
 static void browserWindowSetupEditorToolbar(BrowserWindow *window)
 {
     GtkWidget *toolbar = gtk_toolbar_new();
@@ -943,9 +734,66 @@
     gtk_widget_show(GTK_WIDGET(item));
 
     gtk_box_pack_start(GTK_BOX(window->mainBox), toolbar, FALSE, FALSE, 0);
+    gtk_box_reorder_child(GTK_BOX(window->mainBox), toolbar, 1);
     gtk_widget_show(toolbar);
 }
 
+static void browserWindowSwitchTab(GtkNotebook *notebook, BrowserTab *tab, guint tabIndex, BrowserWindow *window)
+{
+    if (window->activeTab == tab)
+        return;
+
+    if (window->activeTab) {
+        browser_tab_set_status_text(window->activeTab, NULL);
+        g_clear_object(&window->favicon);
+
+        WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+        g_signal_handlers_disconnect_by_data(webView, window);
+
+        WebKitBackForwardList *backForwadlist = webkit_web_view_get_back_forward_list(webView);
+        g_signal_handlers_disconnect_by_data(backForwadlist, window);
+    }
+
+    window->activeTab = tab;
+
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    if (webkit_web_view_is_editable(webView)) {
+        browserWindowSetupEditorToolbar(window);
+        g_signal_connect(webkit_web_view_get_editor_state(webView), "notify::typing-attributes", G_CALLBACK(typingAttributesChanged), window);
+    }
+    webViewURIChanged(webView, NULL, window);
+    webViewTitleChanged(webView, NULL, window);
+    webViewIsLoadingChanged(webView, NULL, window);
+    faviconChanged(webView, NULL, window);
+    browserWindowUpdateZoomActions(window);
+    if (webkit_web_view_is_loading(webView))
+        webViewLoadProgressChanged(webView, NULL, window);
+
+    g_signal_connect(webView, "notify::uri", G_CALLBACK(webViewURIChanged), window);
+    g_signal_connect(webView, "notify::estimated-load-progress", G_CALLBACK(webViewLoadProgressChanged), window);
+    g_signal_connect(webView, "notify::title", G_CALLBACK(webViewTitleChanged), window);
+    g_signal_connect(webView, "notify::is-loading", G_CALLBACK(webViewIsLoadingChanged), window);
+    g_signal_connect(webView, "create", G_CALLBACK(webViewCreate), window);
+    g_signal_connect(webView, "close", G_CALLBACK(webViewClose), window);
+    g_signal_connect(webView, "load-failed", G_CALLBACK(webViewLoadFailed), window);
+    g_signal_connect(webView, "decide-policy", G_CALLBACK(webViewDecidePolicy), window);
+    g_signal_connect(webView, "mouse-target-changed", G_CALLBACK(webViewMouseTargetChanged), window);
+    g_signal_connect(webView, "notify::zoom-level", G_CALLBACK(webViewZoomLevelChanged), window);
+    g_signal_connect(webView, "notify::favicon", G_CALLBACK(faviconChanged), window);
+    g_signal_connect(webView, "enter-fullscreen", G_CALLBACK(webViewEnterFullScreen), window);
+    g_signal_connect(webView, "leave-fullscreen", G_CALLBACK(webViewLeaveFullScreen), window);
+    g_signal_connect(webView, "scroll-event", G_CALLBACK(scrollEventCallback), window);
+
+    WebKitBackForwardList *backForwadlist = webkit_web_view_get_back_forward_list(webView);
+    browserWindowUpdateNavigationActions(window, backForwadlist);
+    g_signal_connect(backForwadlist, "changed", G_CALLBACK(backForwadlistChanged), window);
+}
+
+static void browserWindowTabAddedOrRemoved(GtkNotebook *notebook, BrowserTab *tab, guint tabIndex, BrowserWindow *window)
+{
+    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(window->notebook), gtk_notebook_get_n_pages(notebook) > 1);
+}
+
 static void browser_window_init(BrowserWindow *window)
 {
     g_atomic_int_inc(&windowCount);
@@ -968,7 +816,7 @@
     gtk_accel_group_connect(window->accelGroup, GDK_KEY_F12, 0, GTK_ACCEL_VISIBLE,
         g_cclosure_new_swap(G_CALLBACK(toggleWebInspector), window, NULL));
 
-    /* Reload page */ 
+    /* Reload page */
     gtk_accel_group_connect(window->accelGroup, GDK_KEY_F5, 0, GTK_ACCEL_VISIBLE,
         g_cclosure_new_swap(G_CALLBACK(reloadPage), window, NULL));
     gtk_accel_group_connect(window->accelGroup, GDK_KEY_R, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
@@ -980,13 +828,13 @@
     gtk_accel_group_connect(window->accelGroup, GDK_KEY_R, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE,
         g_cclosure_new_swap(G_CALLBACK(reloadPageIgnoringCache), window, NULL));
 
-    /* Stop page load */ 
+    /* Stop page load */
     gtk_accel_group_connect(window->accelGroup, GDK_KEY_F6, 0, GTK_ACCEL_VISIBLE,
         g_cclosure_new_swap(G_CALLBACK(stopPageLoad), window, NULL));
     gtk_accel_group_connect(window->accelGroup, GDK_KEY_Escape, 0, GTK_ACCEL_VISIBLE,
         g_cclosure_new_swap(G_CALLBACK(stopPageLoad), window, NULL));
 
-    /* Load home page */ 
+    /* Load home page */
     gtk_accel_group_connect(window->accelGroup, GDK_KEY_Home, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE,
         g_cclosure_new_swap(G_CALLBACK(loadHomePage), window, NULL));
 
@@ -1004,7 +852,7 @@
     gtk_accel_group_connect(window->accelGroup, GDK_KEY_KP_0, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
         g_cclosure_new_swap(G_CALLBACK(defaultZoomCallback), window, NULL));
 
-    /* Toggle fullscreen */ 
+    /* Toggle fullscreen */
     gtk_accel_group_connect(window->accelGroup, GDK_KEY_F11, 0, GTK_ACCEL_VISIBLE,
         g_cclosure_new_swap(G_CALLBACK(toggleFullScreen), window, NULL));
 
@@ -1014,6 +862,8 @@
     gtk_accel_group_connect(window->accelGroup, GDK_KEY_W, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
         g_cclosure_new_swap(G_CALLBACK(gtk_widget_destroy), window, NULL));
 
+    g_signal_connect(webkit_web_context_get_default(), "download-started", G_CALLBACK(downloadStarted), window);
+
     GtkWidget *toolbar = gtk_toolbar_new();
     window->toolbar = toolbar;
     gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL);
@@ -1062,6 +912,12 @@
     gtk_widget_add_accelerator(GTK_WIDGET(item), "clicked", window->accelGroup, GDK_KEY_Home, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
     gtk_widget_show(GTK_WIDGET(item));
 
+    item = gtk_tool_button_new(gtk_image_new_from_icon_name("tab-new", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL);
+    g_signal_connect_swapped(item, "clicked", G_CALLBACK(newTabCallback), window);
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+    gtk_widget_add_accelerator(GTK_WIDGET(item), "clicked", window->accelGroup, GDK_KEY_T, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
+    gtk_widget_show_all(GTK_WIDGET(item));
+
     item = gtk_tool_item_new();
     gtk_tool_item_set_expand(item, TRUE);
     gtk_container_add(GTK_CONTAINER(item), window->uriEntry);
@@ -1081,6 +937,15 @@
     gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
     gtk_widget_show(toolbar);
 
+    window->notebook = gtk_notebook_new();
+    g_signal_connect(window->notebook, "switch-page", G_CALLBACK(browserWindowSwitchTab), window);
+    g_signal_connect(window->notebook, "page-added", G_CALLBACK(browserWindowTabAddedOrRemoved), window);
+    g_signal_connect(window->notebook, "page-removed", G_CALLBACK(browserWindowTabAddedOrRemoved), window);
+    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(window->notebook), FALSE);
+    gtk_notebook_set_show_border(GTK_NOTEBOOK(window->notebook), FALSE);
+    gtk_box_pack_start(GTK_BOX(window->mainBox), window->notebook, TRUE, TRUE, 0);
+    gtk_widget_show(window->notebook);
+
     gtk_container_add(GTK_CONTAINER(window), vbox);
     gtk_widget_show(vbox);
 }
@@ -1089,69 +954,7 @@
 {
     BrowserWindow *window = BROWSER_WINDOW(gObject);
 
-    browserWindowUpdateZoomActions(window);
-    if (webkit_web_view_is_editable(window->webView)) {
-        browserWindowSetupEditorToolbar(window);
-        g_signal_connect(webkit_web_view_get_editor_state(window->webView), "notify::typing-attributes", G_CALLBACK(typingAttributesChanged), window);
-    }
-
-    g_signal_connect(window->webView, "notify::uri", G_CALLBACK(webViewURIChanged), window);
-    g_signal_connect(window->webView, "notify::estimated-load-progress", G_CALLBACK(webViewLoadProgressChanged), window);
-    g_signal_connect(window->webView, "notify::title", G_CALLBACK(webViewTitleChanged), window);
-    g_signal_connect(window->webView, "create", G_CALLBACK(webViewCreate), window);
-    g_signal_connect(window->webView, "close", G_CALLBACK(webViewClose), window);
-    g_signal_connect(window->webView, "load-failed", G_CALLBACK(webViewLoadFailed), window);
-    g_signal_connect(window->webView, "load-failed-with-tls-errors", G_CALLBACK(webViewLoadFailedWithTLSerrors), window);
-    g_signal_connect(window->webView, "decide-policy", G_CALLBACK(webViewDecidePolicy), window);
-    g_signal_connect(window->webView, "permission-request", G_CALLBACK(webViewDecidePermissionRequest), window);
-    g_signal_connect(window->webView, "mouse-target-changed", G_CALLBACK(webViewMouseTargetChanged), window);
-    g_signal_connect(window->webView, "notify::zoom-level", G_CALLBACK(webViewZoomLevelChanged), window);
-    g_signal_connect(window->webView, "notify::favicon", G_CALLBACK(faviconChanged), window);
-    g_signal_connect(window->webView, "enter-fullscreen", G_CALLBACK(webViewEnterFullScreen), window);
-    g_signal_connect(window->webView, "leave-fullscreen", G_CALLBACK(webViewLeaveFullScreen), window);
-    g_signal_connect(window->webView, "notify::is-loading", G_CALLBACK(webViewIsLoadingChanged), window);
-    g_signal_connect(window->webView, "scroll-event", G_CALLBACK(scrollEventCallback), window);
-#if GTK_CHECK_VERSION(3, 12, 0)
-    g_signal_connect(window->webView, "run-color-chooser", G_CALLBACK(runColorChooserCallback), window);
-#endif
-
-    g_signal_connect(webkit_web_view_get_context(window->webView), "download-started", G_CALLBACK(downloadStarted), window);
-
-    window->searchBar = BROWSER_SEARCH_BAR(browser_search_bar_new(window->webView));
-    browser_search_bar_add_accelerators(window->searchBar, window->accelGroup);
-    gtk_box_pack_start(GTK_BOX(window->mainBox), GTK_WIDGET(window->searchBar), FALSE, FALSE, 0);
-
-    WebKitBackForwardList *backForwadlist = webkit_web_view_get_back_forward_list(window->webView);
-    g_signal_connect(backForwadlist, "changed", G_CALLBACK(backForwadlistChanged), window);
-
-    WebKitWebInspector *inspectorWindow = webkit_web_view_get_inspector(WEBKIT_WEB_VIEW(window->webView));
-    g_signal_connect(inspectorWindow, "open-window", G_CALLBACK(inspectorWasOpenedInAnotherWindow), window);
-    g_signal_connect(inspectorWindow, "closed", G_CALLBACK(inspectorWasClosed), window);
-
-    GtkWidget *overlay = gtk_overlay_new();
-    gtk_box_pack_start(GTK_BOX(window->mainBox), overlay, TRUE, TRUE, 0);
-    gtk_widget_show(overlay);
-
-    window->statusLabel = gtk_label_new(NULL);
-    gtk_widget_set_halign(window->statusLabel, GTK_ALIGN_START);
-    gtk_widget_set_valign(window->statusLabel, GTK_ALIGN_END);
-    gtk_widget_set_margin_left(window->statusLabel, 1);
-    gtk_widget_set_margin_right(window->statusLabel, 1);
-    gtk_widget_set_margin_top(window->statusLabel, 1);
-    gtk_widget_set_margin_bottom(window->statusLabel, 1);
-    gtk_overlay_add_overlay(GTK_OVERLAY(overlay), window->statusLabel);
-
-    gtk_container_add(GTK_CONTAINER(overlay), GTK_WIDGET(window->webView));
-
-    window->fullScreenMessageLabel = gtk_label_new(NULL);
-    gtk_widget_set_halign(window->fullScreenMessageLabel, GTK_ALIGN_CENTER);
-    gtk_widget_set_valign(window->fullScreenMessageLabel, GTK_ALIGN_CENTER);
-    gtk_widget_set_no_show_all(window->fullScreenMessageLabel, TRUE);
-    gtk_overlay_add_overlay(GTK_OVERLAY(overlay), window->fullScreenMessageLabel);
-    gtk_widget_show(GTK_WIDGET(window->webView));
-
-    if (webkit_web_view_is_editable(window->webView))
-        webkit_web_view_load_html(window->webView, "<html></html>", "file:///");
+    G_OBJECT_CLASS(browser_window_parent_class)->constructed(gObject);
 }
 
 static void browserWindowSaveSession(BrowserWindow *window)
@@ -1159,7 +962,8 @@
     if (!window->sessionFile)
         return;
 
-    WebKitWebViewSessionState *state = webkit_web_view_get_session_state(window->webView);
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    WebKitWebViewSessionState *state = webkit_web_view_get_session_state(webView);
     GBytes *bytes = webkit_web_view_session_state_serialize(state);
     webkit_web_view_session_state_unref(state);
     g_file_set_contents(window->sessionFile, g_bytes_get_data(bytes, NULL), g_bytes_get_size(bytes), NULL);
@@ -1170,7 +974,8 @@
 {
     BrowserWindow *window = BROWSER_WINDOW(widget);
     browserWindowSaveSession(window);
-    webkit_web_view_try_close(window->webView);
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+    webkit_web_view_try_close(webView);
     return TRUE;
 }
 
@@ -1179,29 +984,17 @@
     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
 
     gobjectClass->constructed = browserWindowConstructed;
-    gobjectClass->get_property = browserWindowGetProperty;
-    gobjectClass->set_property = browserWindowSetProperty;
     gobjectClass->finalize = browserWindowFinalize;
 
     GtkWidgetClass *widgetClass = GTK_WIDGET_CLASS(klass);
     widgetClass->delete_event = browserWindowDeleteEvent;
-
-    g_object_class_install_property(gobjectClass,
-                                    PROP_VIEW,
-                                    g_param_spec_object("view",
-                                                        "View",
-                                                        "The web view of this window",
-                                                        WEBKIT_TYPE_WEB_VIEW,
-                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
-// Public API.
-GtkWidget *browser_window_new(WebKitWebView *view, GtkWindow *parent)
+/* Public API. */
+GtkWidget *browser_window_new(GtkWindow *parent)
 {
-    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(view), 0);
-
     BrowserWindow *window = BROWSER_WINDOW(g_object_new(BROWSER_TYPE_WINDOW,
-        "type", GTK_WINDOW_TOPLEVEL, "view", view, NULL));
+        "type", GTK_WINDOW_TOPLEVEL, NULL));
 
     if (parent) {
         window->parentWindow = parent;
@@ -1211,11 +1004,21 @@
     return GTK_WIDGET(window);
 }
 
-WebKitWebView *browser_window_get_view(BrowserWindow *window)
+void browser_window_append_view(BrowserWindow *window, WebKitWebView *webView)
 {
-    g_return_val_if_fail(BROWSER_IS_WINDOW(window), 0);
+    g_return_if_fail(BROWSER_IS_WINDOW(window));
+    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
 
-    return window->webView;
+    if (window->activeTab && webkit_web_view_is_editable(browser_tab_get_web_view(window->activeTab))) {
+        g_warning("Only one tab is allowed in editable mode");
+        return;
+    }
+
+    GtkWidget *tab = browser_tab_new(webView);
+    browser_tab_add_accelerators(BROWSER_TAB(tab), window->accelGroup);
+    gtk_notebook_append_page(GTK_NOTEBOOK(window->notebook), tab, browser_tab_get_title_widget(BROWSER_TAB(tab)));
+    gtk_container_child_set(GTK_CONTAINER(window->notebook), tab, "tab-expand", TRUE, NULL);
+    gtk_widget_show(tab);
 }
 
 void browser_window_load_uri(BrowserWindow *window, const char *uri)
@@ -1223,14 +1026,7 @@
     g_return_if_fail(BROWSER_IS_WINDOW(window));
     g_return_if_fail(uri);
 
-    if (!g_str_has_prefix(uri, "_javascript_:")) {
-        char *internalURI = getInternalURI(uri);
-        webkit_web_view_load_uri(window->webView, internalURI);
-        g_free(internalURI);
-        return;
-    }
-
-    webkit_web_view_run_javascript(window->webView, strstr(uri, "_javascript_:"), NULL, NULL, NULL);
+    browser_tab_load_uri(window->activeTab, uri);
 }
 
 void browser_window_load_session(BrowserWindow *window, const char *sessionFile)
@@ -1238,6 +1034,7 @@
     g_return_if_fail(BROWSER_IS_WINDOW(window));
     g_return_if_fail(sessionFile);
 
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
     window->sessionFile = g_strdup(sessionFile);
     gchar *data = ""
     gsize dataLength;
@@ -1247,17 +1044,17 @@
         g_bytes_unref(bytes);
 
         if (state) {
-            webkit_web_view_restore_session_state(window->webView, state);
+            webkit_web_view_restore_session_state(webView, state);
             webkit_web_view_session_state_unref(state);
         }
     }
 
-    WebKitBackForwardList *bfList = webkit_web_view_get_back_forward_list(window->webView);
+    WebKitBackForwardList *bfList = webkit_web_view_get_back_forward_list(webView);
     WebKitBackForwardListItem *item = webkit_back_forward_list_get_current_item(bfList);
     if (item)
-        webkit_web_view_go_to_back_forward_list_item(window->webView, item);
+        webkit_web_view_go_to_back_forward_list_item(webView, item);
     else
-        webkit_web_view_load_uri(window->webView, BROWSER_DEFAULT_URL);
+        webkit_web_view_load_uri(webView, BROWSER_DEFAULT_URL);
 
 }
 
@@ -1266,8 +1063,9 @@
     g_return_if_fail(BROWSER_IS_WINDOW(window));
     g_return_if_fail(rgba);
 
+    WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
     GdkRGBA viewRGBA;
-    webkit_web_view_get_background_color(window->webView, &viewRGBA);
+    webkit_web_view_get_background_color(webView, &viewRGBA);
     if (gdk_rgba_equal(rgba, &viewRGBA))
         return;
 
@@ -1280,5 +1078,5 @@
         gtk_widget_set_app_paintable(GTK_WIDGET(window), TRUE);
     }
 
-    webkit_web_view_set_background_color(window->webView, rgba);
+    webkit_web_view_set_background_color(webView, rgba);
 }

Modified: trunk/Tools/MiniBrowser/gtk/BrowserWindow.h (203270 => 203271)


--- trunk/Tools/MiniBrowser/gtk/BrowserWindow.h	2016-07-15 06:03:25 UTC (rev 203270)
+++ trunk/Tools/MiniBrowser/gtk/BrowserWindow.h	2016-07-15 09:25:15 UTC (rev 203271)
@@ -38,6 +38,7 @@
 #define BROWSER_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  BROWSER_TYPE_WINDOW))
 #define BROWSER_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  BROWSER_TYPE_WINDOW, BrowserWindowClass))
 #define BROWSER_DEFAULT_URL            "http://www.webkitgtk.org/"
+#define BROWSER_ABOUT_SCHEME           "minibrowser-about"
 
 typedef struct _BrowserWindow        BrowserWindow;
 typedef struct _BrowserWindowClass   BrowserWindowClass;
@@ -44,9 +45,9 @@
 
 GType browser_window_get_type(void);
 
-GtkWidget* browser_window_new(WebKitWebView*, GtkWindow*);
-WebKitWebView* browser_window_get_view(BrowserWindow*);
-void browser_window_load_uri(BrowserWindow *, const char *uri);
+GtkWidget* browser_window_new(GtkWindow*);
+void browser_window_append_view(BrowserWindow*, WebKitWebView*);
+void browser_window_load_uri(BrowserWindow*, const char *uri);
 void browser_window_load_session(BrowserWindow *, const char *sessionFile);
 void browser_window_set_background_color(BrowserWindow*, GdkRGBA*);
 

Modified: trunk/Tools/MiniBrowser/gtk/CMakeLists.txt (203270 => 203271)


--- trunk/Tools/MiniBrowser/gtk/CMakeLists.txt	2016-07-15 06:03:25 UTC (rev 203270)
+++ trunk/Tools/MiniBrowser/gtk/CMakeLists.txt	2016-07-15 09:25:15 UTC (rev 203271)
@@ -13,6 +13,8 @@
     ${MINIBROWSER_DIR}/BrowserSearchBar.h
     ${MINIBROWSER_DIR}/BrowserSettingsDialog.c
     ${MINIBROWSER_DIR}/BrowserSettingsDialog.h
+    ${MINIBROWSER_DIR}/BrowserTab.c
+    ${MINIBROWSER_DIR}/BrowserTab.h
     ${MINIBROWSER_DIR}/BrowserWindow.c
     ${MINIBROWSER_DIR}/BrowserWindow.h
     ${MINIBROWSER_DIR}/main.c

Modified: trunk/Tools/MiniBrowser/gtk/main.c (203270 => 203271)


--- trunk/Tools/MiniBrowser/gtk/main.c	2016-07-15 06:03:25 UTC (rev 203270)
+++ trunk/Tools/MiniBrowser/gtk/main.c	2016-07-15 09:25:15 UTC (rev 203271)
@@ -36,7 +36,6 @@
 #define MINI_BROWSER_ERROR (miniBrowserErrorQuark())
 
 static const gchar **uriArguments = NULL;
-static const char *miniBrowserAboutScheme = "minibrowser-about";
 static GdkRGBA *backgroundColor;
 static gboolean editorMode;
 static const char *sessionFile;
@@ -60,32 +59,16 @@
     return fileURL;
 }
 
-static void createBrowserWindow(const gchar *uri, WebKitSettings *webkitSettings, gboolean shouldLoadSession)
+static WebKitWebView *createBrowserTab(BrowserWindow *window, WebKitSettings *webkitSettings)
 {
-    GtkWidget *webView = webkit_web_view_new();
+    WebKitWebView *webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+    if (webkitSettings)
+        webkit_web_view_set_settings(webView, webkitSettings);
     if (editorMode)
-        webkit_web_view_set_editable(WEBKIT_WEB_VIEW(webView), TRUE);
-    GtkWidget *mainWindow = browser_window_new(WEBKIT_WEB_VIEW(webView), NULL);
-    if (backgroundColor)
-        browser_window_set_background_color(BROWSER_WINDOW(mainWindow), backgroundColor);
-    if (geometry)
-        gtk_window_parse_geometry(GTK_WINDOW(mainWindow), geometry);
+        webkit_web_view_set_editable(webView, TRUE);
 
-    if (webkitSettings)
-        webkit_web_view_set_settings(WEBKIT_WEB_VIEW(webView), webkitSettings);
-
-    if (!editorMode) {
-        if (shouldLoadSession && sessionFile)
-            browser_window_load_session(BROWSER_WINDOW(mainWindow), sessionFile);
-        else {
-            gchar *url = ""
-            browser_window_load_uri(BROWSER_WINDOW(mainWindow), url);
-            g_free(url);
-        }
-    }
-
-    gtk_widget_grab_focus(webView);
-    gtk_widget_show(mainWindow);
+    browser_window_append_view(window, webView);
+    return webView;
 }
 
 static gboolean parseBackgroundColor(const char *optionName, const char *value, gpointer data, GError **error)
@@ -242,8 +225,7 @@
     return TRUE;
 }
 
-static void
-aboutURISchemeRequestCallback(WebKitURISchemeRequest *request, gpointer userData)
+static void aboutURISchemeRequestCallback(WebKitURISchemeRequest *request, gpointer userData)
 {
     GInputStream *stream;
     gsize streamLength;
@@ -303,16 +285,42 @@
     // Enable the favicon database, by specifying the default directory.
     webkit_web_context_set_favicon_database_directory(webkit_web_context_get_default(), NULL);
 
-    webkit_web_context_register_uri_scheme(webkit_web_context_get_default(), miniBrowserAboutScheme, aboutURISchemeRequestCallback, NULL, NULL);
+    webkit_web_context_register_uri_scheme(webkit_web_context_get_default(), BROWSER_ABOUT_SCHEME, aboutURISchemeRequestCallback, NULL, NULL);
 
+    BrowserWindow *mainWindow = BROWSER_WINDOW(browser_window_new(NULL));
+    if (geometry)
+        gtk_window_parse_geometry(GTK_WINDOW(mainWindow), geometry);
+
+    GtkWidget *firstTab = NULL;
     if (uriArguments) {
         int i;
 
-        for (i = 0; uriArguments[i]; i++)
-            createBrowserWindow(uriArguments[i], webkitSettings, FALSE);
-    } else
-        createBrowserWindow(BROWSER_DEFAULT_URL, webkitSettings, TRUE);
+        for (i = 0; uriArguments[i]; i++) {
+            WebKitWebView *webView = createBrowserTab(mainWindow, webkitSettings);
+            if (!i)
+                firstTab = GTK_WIDGET(webView);
+            gchar *url = ""
+            webkit_web_view_load_uri(webView, url);
+            g_free(url);
+        }
+    } else {
+        WebKitWebView *webView = createBrowserTab(mainWindow, webkitSettings);
+        firstTab = GTK_WIDGET(webView);
 
+        if (backgroundColor)
+            browser_window_set_background_color(mainWindow, backgroundColor);
+
+        if (!editorMode) {
+            if (sessionFile)
+                browser_window_load_session(mainWindow, sessionFile);
+            else
+                webkit_web_view_load_uri(webView, BROWSER_DEFAULT_URL);
+        }
+    }
+
+    gtk_widget_grab_focus(firstTab);
+    gtk_widget_show(GTK_WIDGET(mainWindow));
+
     g_clear_object(&webkitSettings);
 
     gtk_main();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to