diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Tools/MiniBrowser/gtk/BrowserWindow.c | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Tools/MiniBrowser/gtk/BrowserWindow.c')
-rw-r--r-- | Tools/MiniBrowser/gtk/BrowserWindow.c | 898 |
1 files changed, 658 insertions, 240 deletions
diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.c b/Tools/MiniBrowser/gtk/BrowserWindow.c index b8a0d056c..b80157fa2 100644 --- a/Tools/MiniBrowser/gtk/BrowserWindow.c +++ b/Tools/MiniBrowser/gtk/BrowserWindow.c @@ -25,23 +25,23 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ +#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE) +#include "cmakeconfig.h" +#endif #include "BrowserWindow.h" #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; + WebKitWebContext *webContext; + GtkAccelGroup *accelGroup; GtkWidget *mainBox; GtkWidget *toolbar; @@ -50,18 +50,21 @@ struct _BrowserWindow { GtkWidget *forwardItem; GtkWidget *zoomInItem; GtkWidget *zoomOutItem; - GtkWidget *statusLabel; + GtkWidget *boldItem; + GtkWidget *italicItem; + GtkWidget *underlineItem; + GtkWidget *strikethroughItem; GtkWidget *settingsDialog; - WebKitWebView *webView; + GtkWidget *notebook; + BrowserTab *activeTab; GtkWidget *downloadsBar; - BrowserSearchBar *searchBar; gboolean searchBarVisible; + gboolean fullScreenIsEnabled; GdkPixbuf *favicon; GtkWidget *reloadOrStopButton; - GtkWidget *fullScreenMessageLabel; GtkWindow *parentWindow; - guint fullScreenMessageLabelId; guint resetEntryProgressTimeoutId; + gchar *sessionFile; }; struct _BrowserWindowClass { @@ -69,36 +72,26 @@ struct _BrowserWindowClass { }; 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; static const gdouble zoomStep = 1.2; static gint windowCount = 0; 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); } 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) @@ -113,20 +106,23 @@ static void activateUriEntryCallback(BrowserWindow *window) 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) @@ -136,7 +132,8 @@ static void settingsCallback(BrowserWindow *window) 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); @@ -145,14 +142,23 @@ static void settingsCallback(BrowserWindow *window) 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) { const char *title = webkit_web_view_get_title(webView); - gtk_window_set_title(GTK_WINDOW(window), title ? title : defaultWindowTitle); + if (!title) + title = defaultWindowTitle; + char *privateTitle = NULL; + if (webkit_web_view_is_ephemeral(webView)) + privateTitle = g_strdup_printf("[Private] %s", title); + gtk_window_set_title(GTK_WINDOW(window), privateTitle ? privateTitle : title); + g_free(privateTitle); } static gboolean resetEntryProgress(BrowserWindow *window) @@ -196,7 +202,8 @@ static void browserWindowHistoryItemActivated(BrowserWindow *window, GtkAction * 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) @@ -230,8 +237,9 @@ static GtkWidget *browserWindowCreateBackForwardMenu(BrowserWindow *window, GLis 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), @@ -249,24 +257,22 @@ static void backForwadlistChanged(WebKitBackForwardList *backForwadlist, WebKitB browserWindowUpdateNavigationActions(window, backForwadlist); } -static void geolocationRequestDialogCallback(GtkDialog *dialog, gint response, WebKitPermissionRequest *request) +static void webViewClose(WebKitWebView *webView, BrowserWindow *window) { - switch (response) { - case GTK_RESPONSE_YES: - webkit_permission_request_allow(request); - break; - default: - webkit_permission_request_deny(request); - break; + int tabsCount = gtk_notebook_get_n_pages(GTK_NOTEBOOK(window->notebook)); + if (tabsCount == 1) { + gtk_widget_destroy(GTK_WIDGET(window)); + return; } - gtk_widget_destroy(GTK_WIDGET(dialog)); - g_object_unref(request); -} - -static void webViewClose(WebKitWebView *webView, BrowserWindow *window) -{ - gtk_widget_destroy(GTK_WIDGET(window)); + int i; + for (i = 0; i < tabsCount; ++i) { + BrowserTab *tab = (BrowserTab *)gtk_notebook_get_nth_page(GTK_NOTEBOOK(window->notebook), i); + if (browser_tab_get_web_view(tab) == webView) { + gtk_widget_destroy(GTK_WIDGET(tab)); + return; + } + } } static void webViewRunAsModal(WebKitWebView *webView, BrowserWindow *window) @@ -297,65 +303,33 @@ static void webViewReadyToShow(WebKitWebView *webView, BrowserWindow *window) 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), window->webContext); + 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, 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.); @@ -364,57 +338,28 @@ static gboolean webViewLoadFailed(WebKitWebView *webView, WebKitLoadEvent loadEv static gboolean webViewDecidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, BrowserWindow *window) { - switch (decisionType) { - case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: { - WebKitNavigationPolicyDecision *navigationDecision = WEBKIT_NAVIGATION_POLICY_DECISION(decision); - if (webkit_navigation_policy_decision_get_navigation_type(navigationDecision) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED - || webkit_navigation_policy_decision_get_mouse_button(navigationDecision) != GDK_BUTTON_MIDDLE) - 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_policy_decision_get_request(navigationDecision)); - 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: + if (decisionType != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION) return FALSE; - } -} -static gboolean webViewDecidePermissionRequest(WebKitWebView *webView, WebKitPermissionRequest *request, BrowserWindow *window) -{ - if (!WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(request)) + 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; - GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - "Geolocation request"); + /* Multiple tabs are not allowed in editor mode. */ + if (webkit_web_view_is_editable(webView)) + return FALSE; - gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "Allow geolocation request?"); - g_signal_connect(dialog, "response", G_CALLBACK(geolocationRequestDialogCallback), g_object_ref(request)); - gtk_widget_show(dialog); + /* Opening a new tab if link clicked with the middle button. */ + WebKitWebView *newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, + "web-context", webkit_web_view_get_context(webView), + "settings", webkit_web_view_get_settings(webView), + "user-content-manager", webkit_web_view_get_user_content_manager(webView), + NULL)); + browser_window_append_view(window, newWebView); + webkit_web_view_load_request(newWebView, webkit_navigation_action_get_request(navigationAction)); + webkit_policy_decision_ignore(decision); return TRUE; } @@ -429,16 +374,53 @@ static void webViewMouseTargetChanged(WebKitWebView *webView, WebKitHitTestResul 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; } +static gboolean browserWindowZoomIn(BrowserWindow *window) +{ + if (browserWindowCanZoomIn(window)) { + 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; +} + +static gboolean browserWindowZoomOut(BrowserWindow *window) +{ + if (browserWindowCanZoomOut(window)) { + 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; +} + +static gboolean scrollEventCallback(WebKitWebView *webView, const GdkEventScroll *event, BrowserWindow *window) +{ + GdkModifierType mod = gtk_accelerator_get_default_mod_mask(); + + if ((event->state & mod) != GDK_CONTROL_MASK) + return FALSE; + + if (event->delta_y < 0) + return browserWindowZoomIn(window); + + return browserWindowZoomOut(window); +} + static void browserWindowUpdateZoomActions(BrowserWindow *window) { gtk_widget_set_sensitive(window->zoomInItem, browserWindowCanZoomIn(window)); @@ -459,10 +441,10 @@ static void updateUriEntryIcon(BrowserWindow *window) 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); @@ -477,32 +459,194 @@ static void faviconChanged(GObject *object, GParamSpec *paramSpec, BrowserWindow 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 void zoomInCallback(BrowserWindow *window) { - gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) * zoomStep; - webkit_web_view_set_zoom_level(window->webView, zoomLevel); + browserWindowZoomIn(window); } static void zoomOutCallback(BrowserWindow *window) { - gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) / zoomStep; - webkit_web_view_set_zoom_level(window->webView, zoomLevel); + browserWindowZoomOut(window); +} + +static void defaultZoomCallback(BrowserWindow *window) +{ + 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 void newTabCallback(BrowserWindow *window) +{ + WebKitWebView *webView = browser_tab_get_web_view(window->activeTab); + if (webkit_web_view_is_editable(webView)) + return; + + browser_window_append_view(window, WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, + "web-context", webkit_web_view_get_context(webView), + "settings", webkit_web_view_get_settings(webView), + "user-content-manager", webkit_web_view_get_user_content_manager(webView), + NULL))); + gtk_notebook_set_current_page(GTK_NOTEBOOK(window->notebook), -1); +} + +static void toggleWebInspector(BrowserWindow *window) +{ + browser_tab_toggle_inspector(window->activeTab); +} + +static void openPrivateWindow(BrowserWindow *window) +{ + WebKitWebView *webView = browser_tab_get_web_view(window->activeTab); + WebKitWebView *newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, + "web-context", webkit_web_view_get_context(webView), + "settings", webkit_web_view_get_settings(webView), + "user-content-manager", webkit_web_view_get_user_content_manager(webView), + "is-ephemeral", TRUE, + NULL)); + GtkWidget *newWindow = browser_window_new(GTK_WINDOW(window), window->webContext); + browser_window_append_view(BROWSER_WINDOW(newWindow), newWebView); + gtk_widget_show(GTK_WIDGET(newWindow)); +} + +static void reloadPage(BrowserWindow *window) +{ + WebKitWebView *webView = browser_tab_get_web_view(window->activeTab); + webkit_web_view_reload(webView); +} + +static void reloadPageIgnoringCache(BrowserWindow *window) +{ + WebKitWebView *webView = browser_tab_get_web_view(window->activeTab); + webkit_web_view_reload_bypass_cache(webView); +} + +static void stopPageLoad(BrowserWindow *window) +{ + 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) +{ + 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) +{ + if (!window->fullScreenIsEnabled) { + gtk_window_fullscreen(GTK_WINDOW(window)); + gtk_widget_hide(window->toolbar); + window->fullScreenIsEnabled = TRUE; + } else { + gtk_window_unfullscreen(GTK_WINDOW(window)); + gtk_widget_show(window->toolbar); + window->fullScreenIsEnabled = FALSE; + } + return TRUE; +} + +static void webKitPrintOperationFailedCallback(WebKitPrintOperation *printOperation, GError *error) +{ + g_warning("Print failed: '%s'", error->message); +} + +static gboolean printPage(BrowserWindow *window, gpointer user_data) +{ + WebKitWebView *webView = browser_tab_get_web_view(window->activeTab); + WebKitPrintOperation *printOperation = webkit_print_operation_new(webView); + + g_signal_connect(printOperation, "failed", G_CALLBACK(webKitPrintOperationFailedCallback), NULL); + webkit_print_operation_run_dialog(printOperation, GTK_WINDOW(window)); + g_object_unref(printOperation); + + return TRUE; +} + +static void editingCommandCallback(GtkWidget *widget, BrowserWindow *window) +{ + 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) +{ + GtkWidget *fileChooser = gtk_file_chooser_dialog_new("Insert Image", GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_OPEN, + "Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL); + + GtkFileFilter *filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, "Images"); + gtk_file_filter_add_pixbuf_formats(filter); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fileChooser), filter); + + if (gtk_dialog_run(GTK_DIALOG(fileChooser)) == GTK_RESPONSE_ACCEPT) { + char *uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(fileChooser)); + if (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); + } + } + + gtk_widget_destroy(fileChooser); +} + +static void insertLinkCommandCallback(GtkWidget *widget, BrowserWindow *window) +{ + GtkWidget *dialog = gtk_dialog_new_with_buttons("Insert Link", GTK_WINDOW(window), GTK_DIALOG_MODAL, "Insert", GTK_RESPONSE_ACCEPT, NULL); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); + GtkWidget *entry = gtk_entry_new(); + gtk_entry_set_placeholder_text(GTK_ENTRY(entry), "URL"); + gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); + gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), entry); + gtk_widget_show(entry); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + const char *url = gtk_entry_get_text(GTK_ENTRY(entry)); + 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); +} + +static void browserWindowEditingCommandToggleButtonSetActive(BrowserWindow *window, GtkWidget *button, gboolean active) +{ + g_signal_handlers_block_by_func(button, G_CALLBACK(editingCommandCallback), window); + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(button), active); + g_signal_handlers_unblock_by_func(button, G_CALLBACK(editingCommandCallback), window); +} + +static void typingAttributesChanged(WebKitEditorState *editorState, GParamSpec *spec, BrowserWindow *window) +{ + unsigned typingAttributes = webkit_editor_state_get_typing_attributes(editorState); + browserWindowEditingCommandToggleButtonSetActive(window, window->boldItem, typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD); + browserWindowEditingCommandToggleButtonSetActive(window, window->italicItem, typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC); + browserWindowEditingCommandToggleButtonSetActive(window, window->underlineItem, typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE); + browserWindowEditingCommandToggleButtonSetActive(window, window->strikethroughItem, typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH); } static void browserWindowFinalize(GObject *gObject) { BrowserWindow *window = BROWSER_WINDOW(gObject); + + g_signal_handlers_disconnect_matched(window->webContext, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, window); + if (window->favicon) { g_object_unref(window->favicon); window->favicon = NULL; @@ -513,42 +657,207 @@ static void browserWindowFinalize(GObject *gObject) window->accelGroup = NULL; } - if (window->fullScreenMessageLabelId) - g_source_remove(window->fullScreenMessageLabelId); - if (window->resetEntryProgressTimeoutId) g_source_remove(window->resetEntryProgressTimeoutId); + g_free(window->sessionFile); + G_OBJECT_CLASS(browser_window_parent_class)->finalize(gObject); if (g_atomic_int_dec_and_test(&windowCount)) gtk_main_quit(); } -static void browserWindowGetProperty(GObject *object, guint propId, GValue *value, GParamSpec *pspec) +static void browserWindowSetupEditorToolbar(BrowserWindow *window) { - BrowserWindow *window = BROWSER_WINDOW(object); + GtkWidget *toolbar = gtk_toolbar_new(); + gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL); + gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ); - 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); - } + GtkToolItem *item = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_BOLD); + window->boldItem = GTK_WIDGET(item); + gtk_widget_set_name(GTK_WIDGET(item), "Bold"); + g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_ITALIC); + window->italicItem = GTK_WIDGET(item); + gtk_widget_set_name(GTK_WIDGET(item), "Italic"); + g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_UNDERLINE); + window->underlineItem = GTK_WIDGET(item); + gtk_widget_set_name(GTK_WIDGET(item), "Underline"); + g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_STRIKETHROUGH); + gtk_widget_set_name(GTK_WIDGET(item), "Strikethrough"); + window->strikethroughItem = GTK_WIDGET(item); + g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_separator_tool_item_new(); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_tool_button_new_from_stock(GTK_STOCK_CUT); + gtk_widget_set_name(GTK_WIDGET(item), WEBKIT_EDITING_COMMAND_CUT); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_tool_button_new_from_stock(GTK_STOCK_COPY); + gtk_widget_set_name(GTK_WIDGET(item), WEBKIT_EDITING_COMMAND_COPY); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_tool_button_new_from_stock(GTK_STOCK_PASTE); + gtk_widget_set_name(GTK_WIDGET(item), WEBKIT_EDITING_COMMAND_PASTE); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_separator_tool_item_new(); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_tool_button_new_from_stock(GTK_STOCK_UNDO); + gtk_widget_set_name(GTK_WIDGET(item), WEBKIT_EDITING_COMMAND_UNDO); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_tool_button_new_from_stock(GTK_STOCK_REDO); + gtk_widget_set_name(GTK_WIDGET(item), WEBKIT_EDITING_COMMAND_REDO); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_separator_tool_item_new(); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_radio_tool_button_new_from_stock(NULL, GTK_STOCK_JUSTIFY_LEFT); + GSList *justifyRadioGroup = gtk_radio_tool_button_get_group(GTK_RADIO_TOOL_BUTTON(item)); + gtk_widget_set_name(GTK_WIDGET(item), "JustifyLeft"); + g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_radio_tool_button_new_from_stock(justifyRadioGroup, GTK_STOCK_JUSTIFY_CENTER); + justifyRadioGroup = gtk_radio_tool_button_get_group(GTK_RADIO_TOOL_BUTTON(item)); + gtk_widget_set_name(GTK_WIDGET(item), "JustifyCenter"); + g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_radio_tool_button_new_from_stock(justifyRadioGroup, GTK_STOCK_JUSTIFY_RIGHT); + gtk_widget_set_name(GTK_WIDGET(item), "JustifyRight"); + g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_separator_tool_item_new(); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_tool_button_new_from_stock(GTK_STOCK_INDENT); + gtk_widget_set_name(GTK_WIDGET(item), "Indent"); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_tool_button_new_from_stock(GTK_STOCK_UNINDENT); + gtk_widget_set_name(GTK_WIDGET(item), "Outdent"); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(editingCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_separator_tool_item_new(); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_tool_button_new(NULL, NULL); + gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "insert-image"); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(insertImageCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + gtk_widget_show(GTK_WIDGET(item)); + + item = gtk_tool_button_new(NULL, NULL); + gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "insert-link"); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(insertLinkCommandCallback), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + 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 browserWindowSetProperty(GObject *object, guint propId, const GValue *value, GParamSpec *pspec) +static void browserWindowSwitchTab(GtkNotebook *notebook, BrowserTab *tab, guint tabIndex, BrowserWindow *window) { - BrowserWindow* window = BROWSER_WINDOW(object); + if (window->activeTab == tab) + return; - switch (propId) { - case PROP_VIEW: - window->webView = g_value_get_object(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec); + 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); + + /* We always want close to be connected even for not active tabs */ + g_signal_connect(webView, "close", G_CALLBACK(webViewClose), 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) @@ -567,6 +876,64 @@ static void browser_window_init(BrowserWindow *window) window->accelGroup = gtk_accel_group_new(); gtk_window_add_accel_group(GTK_WINDOW(window), window->accelGroup); + /* Global accelerators */ + gtk_accel_group_connect(window->accelGroup, GDK_KEY_I, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(toggleWebInspector), window, NULL)); + gtk_accel_group_connect(window->accelGroup, GDK_KEY_F12, 0, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(toggleWebInspector), window, NULL)); + gtk_accel_group_connect(window->accelGroup, GDK_KEY_P, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(openPrivateWindow), window, NULL)); + + /* 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, + g_cclosure_new_swap(G_CALLBACK(reloadPage), window, NULL)); + + /* Reload page ignoring cache */ + gtk_accel_group_connect(window->accelGroup, GDK_KEY_F5, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(reloadPageIgnoringCache), window, NULL)); + 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 */ + 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 */ + gtk_accel_group_connect(window->accelGroup, GDK_KEY_Home, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(loadHomePage), window, NULL)); + + /* Zoom in, zoom out and default zoom*/ + gtk_accel_group_connect(window->accelGroup, GDK_KEY_equal, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(zoomInCallback), window, NULL)); + gtk_accel_group_connect(window->accelGroup, GDK_KEY_KP_Add, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(zoomInCallback), window, NULL)); + gtk_accel_group_connect(window->accelGroup, GDK_KEY_minus, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(zoomOutCallback), window, NULL)); + gtk_accel_group_connect(window->accelGroup, GDK_KEY_KP_Subtract, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(zoomOutCallback), window, NULL)); + gtk_accel_group_connect(window->accelGroup, GDK_KEY_0, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(defaultZoomCallback), window, NULL)); + 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 */ + gtk_accel_group_connect(window->accelGroup, GDK_KEY_F11, 0, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(toggleFullScreen), window, NULL)); + + /* Quit */ + gtk_accel_group_connect(window->accelGroup, GDK_KEY_Q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(gtk_widget_destroy), window, NULL)); + 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)); + + /* Print */ + gtk_accel_group_connect(window->accelGroup, GDK_KEY_P, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, + g_cclosure_new_swap(G_CALLBACK(printPage), window, NULL)); + GtkWidget *toolbar = gtk_toolbar_new(); window->toolbar = toolbar; gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL); @@ -609,6 +976,18 @@ static void browser_window_init(BrowserWindow *window) gtk_widget_add_accelerator(GTK_WIDGET(item), "clicked", window->accelGroup, GDK_KEY_F, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); gtk_widget_show(GTK_WIDGET(item)); + item = gtk_tool_button_new_from_stock(GTK_STOCK_HOME); + g_signal_connect_swapped(item, "clicked", G_CALLBACK(loadHomePage), window); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + 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); @@ -628,60 +1007,44 @@ static void browser_window_init(BrowserWindow *window) 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); } static void browserWindowConstructed(GObject *gObject) { - BrowserWindow *window = BROWSER_WINDOW(gObject); - - browserWindowUpdateZoomActions(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, "load-failed", G_CALLBACK(webViewLoadFailed), 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(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); - - GtkWidget *overlay = gtk_overlay_new(); - gtk_box_pack_start(GTK_BOX(window->mainBox), overlay, TRUE, TRUE, 0); - gtk_widget_show(overlay); + G_OBJECT_CLASS(browser_window_parent_class)->constructed(gObject); +} - 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); +static void browserWindowSaveSession(BrowserWindow *window) +{ + if (!window->sessionFile) + return; - gtk_container_add(GTK_CONTAINER(overlay), GTK_WIDGET(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); + g_bytes_unref(bytes); +} - 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)); +static gboolean browserWindowDeleteEvent(GtkWidget *widget, GdkEventAny* event) +{ + BrowserWindow *window = BROWSER_WINDOW(widget); + browserWindowSaveSession(window); + WebKitWebView *webView = browser_tab_get_web_view(window->activeTab); + webkit_web_view_try_close(webView); + return TRUE; } static void browser_window_class_init(BrowserWindowClass *klass) @@ -689,27 +1052,22 @@ static void browser_window_class_init(BrowserWindowClass *klass) GObjectClass *gobjectClass = G_OBJECT_CLASS(klass); gobjectClass->constructed = browserWindowConstructed; - gobjectClass->get_property = browserWindowGetProperty; - gobjectClass->set_property = browserWindowSetProperty; gobjectClass->finalize = browserWindowFinalize; - 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)); + GtkWidgetClass *widgetClass = GTK_WIDGET_CLASS(klass); + widgetClass->delete_event = browserWindowDeleteEvent; } -// Public API. -GtkWidget *browser_window_new(WebKitWebView *view, GtkWindow *parent) +/* Public API. */ +GtkWidget *browser_window_new(GtkWindow *parent, WebKitWebContext *webContext) { - g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(view), 0); + g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(webContext), NULL); BrowserWindow *window = BROWSER_WINDOW(g_object_new(BROWSER_TYPE_WINDOW, - "type", GTK_WINDOW_TOPLEVEL, "view", view, NULL)); + "type", GTK_WINDOW_TOPLEVEL, NULL)); + window->webContext = webContext; + g_signal_connect(window->webContext, "download-started", G_CALLBACK(downloadStarted), window); if (parent) { window->parentWindow = parent; g_object_add_weak_pointer(G_OBJECT(parent), (gpointer *)&window->parentWindow); @@ -718,11 +1076,28 @@ GtkWidget *browser_window_new(WebKitWebView *view, GtkWindow *parent) return GTK_WIDGET(window); } -WebKitWebView *browser_window_get_view(BrowserWindow *window) +WebKitWebContext *browser_window_get_web_context(BrowserWindow *window) +{ + g_return_val_if_fail(BROWSER_IS_WINDOW(window), NULL); + + return window->webContext; +} + +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) @@ -730,12 +1105,55 @@ void browser_window_load_uri(BrowserWindow *window, const char *uri) 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; + browser_tab_load_uri(window->activeTab, uri); +} + +void browser_window_load_session(BrowserWindow *window, const char *sessionFile) +{ + 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 = NULL; + gsize dataLength; + if (g_file_get_contents(sessionFile, &data, &dataLength, NULL)) { + GBytes *bytes = g_bytes_new_take(data, dataLength); + WebKitWebViewSessionState *state = webkit_web_view_session_state_new(bytes); + g_bytes_unref(bytes); + + if (state) { + webkit_web_view_restore_session_state(webView, state); + webkit_web_view_session_state_unref(state); + } } - webkit_web_view_run_javascript(window->webView, strstr(uri, "javascript:"), NULL, NULL, NULL); + 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(webView, item); + else + webkit_web_view_load_uri(webView, BROWSER_DEFAULT_URL); + +} + +void browser_window_set_background_color(BrowserWindow *window, GdkRGBA *rgba) +{ + 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(webView, &viewRGBA); + if (gdk_rgba_equal(rgba, &viewRGBA)) + return; + + GdkVisual *rgbaVisual = gdk_screen_get_rgba_visual(gtk_window_get_screen(GTK_WINDOW(window))); + if (!rgbaVisual) + return; + + gtk_widget_set_visual(GTK_WIDGET(window), rgbaVisual); + gtk_widget_set_app_paintable(GTK_WIDGET(window), TRUE); + + webkit_web_view_set_background_color(webView, rgba); } |