diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp | 1490 |
1 files changed, 1045 insertions, 445 deletions
diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp index 0abb35e12..eeb439bb2 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2011 Igalia S.L. * Portions Copyright (c) 2011 Motorola Mobility, Inc. All rights reserved. + * Copyright (C) 2014 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -22,6 +23,7 @@ #include "WebKitWebView.h" #include "APIData.h" +#include "APISerializedScriptValue.h" #include "ImageOptions.h" #include "WebCertificateInfo.h" #include "WebContextMenuItem.h" @@ -29,25 +31,28 @@ #include "WebKitAuthenticationDialog.h" #include "WebKitAuthenticationRequestPrivate.h" #include "WebKitBackForwardListPrivate.h" -#include "WebKitCertificateInfoPrivate.h" #include "WebKitContextMenuClient.h" #include "WebKitContextMenuItemPrivate.h" #include "WebKitContextMenuPrivate.h" #include "WebKitDownloadPrivate.h" +#include "WebKitEditorStatePrivate.h" #include "WebKitEnumTypes.h" #include "WebKitError.h" #include "WebKitFaviconDatabasePrivate.h" #include "WebKitFormClient.h" #include "WebKitFullscreenClient.h" #include "WebKitHitTestResultPrivate.h" +#include "WebKitInstallMissingMediaPluginsPermissionRequestPrivate.h" #include "WebKitJavascriptResultPrivate.h" #include "WebKitLoaderClient.h" #include "WebKitMarshal.h" +#include "WebKitNotificationPrivate.h" #include "WebKitPolicyClient.h" #include "WebKitPrintOperationPrivate.h" #include "WebKitPrivate.h" #include "WebKitResponsePolicyDecision.h" #include "WebKitScriptDialogPrivate.h" +#include "WebKitSettingsPrivate.h" #include "WebKitUIClient.h" #include "WebKitURIRequestPrivate.h" #include "WebKitURIResponsePrivate.h" @@ -55,20 +60,24 @@ #include "WebKitWebInspectorPrivate.h" #include "WebKitWebResourcePrivate.h" #include "WebKitWebViewBasePrivate.h" -#include "WebKitWebViewGroupPrivate.h" #include "WebKitWebViewPrivate.h" +#include "WebKitWebViewSessionStatePrivate.h" +#include "WebKitWebsiteDataManagerPrivate.h" #include "WebKitWindowPropertiesPrivate.h" #include <JavaScriptCore/APICast.h> #include <WebCore/CertificateInfo.h> -#include <WebCore/DragIcon.h> #include <WebCore/GUniquePtrGtk.h> #include <WebCore/GUniquePtrSoup.h> #include <WebCore/GtkUtilities.h> #include <WebCore/RefPtrCairo.h> #include <glib/gi18n-lib.h> -#include <wtf/gobject/GRefPtr.h> +#include <wtf/glib/GRefPtr.h> #include <wtf/text/CString.h> +#if USE(LIBNOTIFY) +#include <libnotify/notify.h> +#endif + using namespace WebKit; using namespace WebCore; @@ -124,6 +133,10 @@ enum { AUTHENTICATE, + SHOW_NOTIFICATION, + + RUN_COLOR_CHOOSER, + LAST_SIGNAL }; @@ -132,19 +145,24 @@ enum { PROP_WEB_CONTEXT, PROP_RELATED_VIEW, - PROP_GROUP, + PROP_SETTINGS, + PROP_USER_CONTENT_MANAGER, PROP_TITLE, PROP_ESTIMATED_LOAD_PROGRESS, PROP_FAVICON, PROP_URI, PROP_ZOOM_LEVEL, PROP_IS_LOADING, - PROP_VIEW_MODE + PROP_IS_PLAYING_AUDIO, + PROP_IS_EPHEMERAL, + PROP_EDITABLE }; typedef HashMap<uint64_t, GRefPtr<WebKitWebResource> > LoadingResourcesMap; typedef HashMap<uint64_t, GRefPtr<GTask> > SnapshotResultsMap; +class PageLoadStateObserver; + struct _WebKitWebViewPrivate { ~_WebKitWebViewPrivate() { @@ -156,24 +174,21 @@ struct _WebKitWebViewPrivate { g_main_loop_quit(modalLoop.get()); } - WebKitWebContext* context; WebKitWebView* relatedView; CString title; CString customTextEncoding; - double estimatedLoadProgress; CString activeURI; bool isLoading; - WebKitViewMode viewMode; + bool isEphemeral; - bool waitingForMainResource; - unsigned long mainResourceResponseHandlerID; - WebKitLoadEvent lastDelayedEvent; + std::unique_ptr<PageLoadStateObserver> loadObserver; GRefPtr<WebKitBackForwardList> backForwardList; GRefPtr<WebKitSettings> settings; - unsigned long settingsChangedHandlerID; - GRefPtr<WebKitWebViewGroup> group; + GRefPtr<WebKitUserContentManager> userContentManager; + GRefPtr<WebKitWebContext> context; GRefPtr<WebKitWindowProperties> windowProperties; + GRefPtr<WebKitEditorState> editorState; GRefPtr<GMainLoop> modalLoop; @@ -195,6 +210,8 @@ struct _WebKitWebViewPrivate { SnapshotResultsMap snapshotResultsMap; GRefPtr<WebKitAuthenticationRequest> authenticationRequest; + + GRefPtr<WebKitWebsiteDataManager> websiteDataManager; }; static guint signals[LAST_SIGNAL] = { 0, }; @@ -206,6 +223,87 @@ static inline WebPageProxy* getPage(WebKitWebView* webView) return webkitWebViewBaseGetPage(reinterpret_cast<WebKitWebViewBase*>(webView)); } +static void webkitWebViewSetIsLoading(WebKitWebView* webView, bool isLoading) +{ + if (webView->priv->isLoading == isLoading) + return; + + webView->priv->isLoading = isLoading; + g_object_notify(G_OBJECT(webView), "is-loading"); +} + +void webkitWebViewIsPlayingAudioChanged(WebKitWebView* webView) +{ + g_object_notify(G_OBJECT(webView), "is-playing-audio"); +} + +class PageLoadStateObserver final : public PageLoadState::Observer { +public: + PageLoadStateObserver(WebKitWebView* webView) + : m_webView(webView) + { + } + +private: + void willChangeIsLoading() override + { + g_object_freeze_notify(G_OBJECT(m_webView)); + } + void didChangeIsLoading() override + { + webkitWebViewSetIsLoading(m_webView, getPage(m_webView)->pageLoadState().isLoading()); + g_object_thaw_notify(G_OBJECT(m_webView)); + } + + void willChangeTitle() override + { + g_object_freeze_notify(G_OBJECT(m_webView)); + } + void didChangeTitle() override + { + m_webView->priv->title = getPage(m_webView)->pageLoadState().title().utf8(); + g_object_notify(G_OBJECT(m_webView), "title"); + g_object_thaw_notify(G_OBJECT(m_webView)); + } + + void willChangeActiveURL() override + { + g_object_freeze_notify(G_OBJECT(m_webView)); + } + void didChangeActiveURL() override + { + m_webView->priv->activeURI = getPage(m_webView)->pageLoadState().activeURL().utf8(); + g_object_notify(G_OBJECT(m_webView), "uri"); + g_object_thaw_notify(G_OBJECT(m_webView)); + } + + void willChangeHasOnlySecureContent() override { } + void didChangeHasOnlySecureContent() override { } + + void willChangeEstimatedProgress() override + { + g_object_freeze_notify(G_OBJECT(m_webView)); + } + void didChangeEstimatedProgress() override + { + g_object_notify(G_OBJECT(m_webView), "estimated-load-progress"); + g_object_thaw_notify(G_OBJECT(m_webView)); + } + + void willChangeCanGoBack() override { } + void didChangeCanGoBack() override { } + void willChangeCanGoForward() override { } + void didChangeCanGoForward() override { } + void willChangeNetworkRequestsInProgress() override { } + void didChangeNetworkRequestsInProgress() override { } + void willChangeCertificateInfo() override { } + void didChangeCertificateInfo() override { } + void willChangeWebProcessIsResponsive() override { } + void didChangeWebProcessIsResponsive() override { } + + WebKitWebView* m_webView; +}; + static gboolean webkitWebViewLoadFail(WebKitWebView* webView, WebKitLoadEvent, const char* failingURI, GError* error) { if (g_error_matches(error, WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_CANCELLED) @@ -219,19 +317,22 @@ static gboolean webkitWebViewLoadFail(WebKitWebView* webView, WebKitLoadEvent, c return TRUE; } -static GtkWidget* webkitWebViewCreate(WebKitWebView*) +static GtkWidget* webkitWebViewCreate(WebKitWebView*, WebKitNavigationAction*) { - return 0; + return nullptr; } -static GtkWidget* webkitWebViewCreateJavaScriptDialog(WebKitWebView* webView, GtkMessageType type, GtkButtonsType buttons, int defaultResponse, const char* message) +static GtkWidget* webkitWebViewCreateJavaScriptDialog(WebKitWebView* webView, GtkMessageType type, GtkButtonsType buttons, int defaultResponse, const char* primaryText, const char* secondaryText = nullptr) { GtkWidget* parent = gtk_widget_get_toplevel(GTK_WIDGET(webView)); - GtkWidget* dialog = gtk_message_dialog_new(widgetIsOnscreenToplevelWindow(parent) ? GTK_WINDOW(parent) : 0, - GTK_DIALOG_DESTROY_WITH_PARENT, type, buttons, "%s", message); - GUniquePtr<char> title(g_strdup_printf("JavaScript - %s", webkit_web_view_get_uri(webView))); + GtkWidget* dialog = gtk_message_dialog_new(widgetIsOnscreenToplevelWindow(parent) ? GTK_WINDOW(parent) : nullptr, + GTK_DIALOG_DESTROY_WITH_PARENT, type, buttons, "%s", primaryText); + if (secondaryText) + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", secondaryText); + GUniquePtr<char> title(g_strdup_printf("JavaScript - %s", getPage(webView)->pageLoadState().url().utf8().data())); gtk_window_set_title(GTK_WINDOW(dialog), title.get()); - gtk_dialog_set_default_response(GTK_DIALOG(dialog), defaultResponse); + if (buttons != GTK_BUTTONS_NONE) + gtk_dialog_set_default_response(GTK_DIALOG(dialog), defaultResponse); return dialog; } @@ -249,7 +350,7 @@ static gboolean webkitWebViewScriptDialog(WebKitWebView* webView, WebKitScriptDi dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, scriptDialog->message.data()); scriptDialog->confirmed = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK; break; - case WEBKIT_SCRIPT_DIALOG_PROMPT: + case WEBKIT_SCRIPT_DIALOG_PROMPT: { dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, scriptDialog->message.data()); GtkWidget* entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), scriptDialog->defaultText.data()); @@ -260,13 +361,21 @@ static gboolean webkitWebViewScriptDialog(WebKitWebView* webView, WebKitScriptDi scriptDialog->text = gtk_entry_get_text(GTK_ENTRY(entry)); break; } + case WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM: + dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, GTK_RESPONSE_OK, + _("Are you sure you want to leave this page?"), scriptDialog->message.data()); + gtk_dialog_add_buttons(GTK_DIALOG(dialog), _("Stay on Page"), GTK_RESPONSE_CLOSE, _("Leave Page"), GTK_RESPONSE_OK, nullptr); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); + scriptDialog->confirmed = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK; + break; + } gtk_widget_destroy(dialog); return TRUE; } -static gboolean webkitWebViewDecidePolicy(WebKitWebView* webView, WebKitPolicyDecision* decision, WebKitPolicyDecisionType decisionType) +static gboolean webkitWebViewDecidePolicy(WebKitWebView*, WebKitPolicyDecision* decision, WebKitPolicyDecisionType decisionType) { if (decisionType != WEBKIT_POLICY_DECISION_TYPE_RESPONSE) { webkit_policy_decision_use(decision); @@ -353,7 +462,7 @@ static void webkitWebViewRequestFavicon(WebKitWebView* webView) WebKitWebViewPrivate* priv = webView->priv; priv->faviconCancellable = adoptGRef(g_cancellable_new()); - WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context); + WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context.get()); webkit_favicon_database_get_favicon(database, priv->activeURI.data(), priv->faviconCancellable.get(), gotFaviconCallback, webView); } @@ -366,7 +475,7 @@ static void webkitWebViewUpdateFaviconURI(WebKitWebView* webView, const char* fa webkitWebViewRequestFavicon(webView); } -static void faviconChangedCallback(WebKitFaviconDatabase* database, const char* pageURI, const char* faviconURI, WebKitWebView* webView) +static void faviconChangedCallback(WebKitFaviconDatabase*, const char* pageURI, const char* faviconURI, WebKitWebView* webView) { if (webView->priv->activeURI != pageURI) return; @@ -376,16 +485,18 @@ static void faviconChangedCallback(WebKitFaviconDatabase* database, const char* static void webkitWebViewUpdateSettings(WebKitWebView* webView) { - // We keep a ref of the current settings to disconnect the signals when settings change in the group. - webView->priv->settings = webkit_web_view_get_settings(webView); + // The "settings" property is set on construction, and in that + // case webkit_web_view_set_settings() will be called *before* the + // WebPageProxy has been created so we should do an early return. + WebPageProxy* page = getPage(webView); + if (!page) + return; WebKitSettings* settings = webView->priv->settings.get(); - WebPageProxy* page = getPage(webView); + page->setPreferences(*webkitSettingsGetPreferences(settings)); page->setCanRunModal(webkit_settings_get_allow_modal_dialogs(settings)); page->setCustomUserAgent(String::fromUTF8(webkit_settings_get_user_agent(settings))); - webkitWebViewBaseUpdatePreferences(WEBKIT_WEB_VIEW_BASE(webView)); - g_signal_connect(settings, "notify::allow-modal-dialogs", G_CALLBACK(allowModalDialogsChanged), webView); g_signal_connect(settings, "notify::zoom-text-only", G_CALLBACK(zoomTextOnlyChanged), webView); g_signal_connect(settings, "notify::user-agent", G_CALLBACK(userAgentChanged), webView); @@ -399,35 +510,13 @@ static void webkitWebViewDisconnectSettingsSignalHandlers(WebKitWebView* webView g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(userAgentChanged), webView); } -static void webkitWebViewSettingsChanged(WebKitWebViewGroup* group, GParamSpec*, WebKitWebView* webView) -{ - webkitWebViewDisconnectSettingsSignalHandlers(webView); - webkitWebViewUpdateSettings(webView); -} - -static void webkitWebViewDisconnectSettingsChangedSignalHandler(WebKitWebView* webView) -{ - WebKitWebViewPrivate* priv = webView->priv; - if (priv->settingsChangedHandlerID) - g_signal_handler_disconnect(webkit_web_view_get_group(webView), priv->settingsChangedHandlerID); - priv->settingsChangedHandlerID = 0; -} - -static void webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(WebKitWebView* webView) -{ - WebKitWebViewPrivate* priv = webView->priv; - if (priv->mainResourceResponseHandlerID) - g_signal_handler_disconnect(priv->mainResource.get(), priv->mainResourceResponseHandlerID); - priv->mainResourceResponseHandlerID = 0; -} - static void webkitWebViewWatchForChangesInFavicon(WebKitWebView* webView) { WebKitWebViewPrivate* priv = webView->priv; if (priv->faviconChangedHandlerID) return; - WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context); + WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context.get()); priv->faviconChangedHandlerID = g_signal_connect(database, "favicon-changed", G_CALLBACK(faviconChangedCallback), webView); } @@ -435,7 +524,7 @@ static void webkitWebViewDisconnectFaviconDatabaseSignalHandlers(WebKitWebView* { WebKitWebViewPrivate* priv = webView->priv; if (priv->faviconChangedHandlerID) - g_signal_handler_disconnect(webkit_web_context_get_favicon_database(priv->context), priv->faviconChangedHandlerID); + g_signal_handler_disconnect(webkit_web_context_get_favicon_database(priv->context.get()), priv->faviconChangedHandlerID); priv->faviconChangedHandlerID = 0; } @@ -496,14 +585,87 @@ static void webkitWebViewHandleDownloadRequest(WebKitWebViewBase* webViewBase, D webkitDownloadSetWebView(download.get(), WEBKIT_WEB_VIEW(webViewBase)); } +#if USE(LIBNOTIFY) +static const char* gNotifyNotificationID = "wk-notify-notification"; + +static void notifyNotificationClosed(NotifyNotification*, WebKitNotification* webNotification) +{ + g_object_set_data(G_OBJECT(webNotification), gNotifyNotificationID, nullptr); + webkit_notification_close(webNotification); +} + +static void notifyNotificationClicked(NotifyNotification*, char*, WebKitNotification* webNotification) +{ + webkit_notification_clicked(webNotification); +} + +static void webNotificationClosed(WebKitNotification* webNotification) +{ + NotifyNotification* notification = NOTIFY_NOTIFICATION(g_object_get_data(G_OBJECT(webNotification), gNotifyNotificationID)); + if (!notification) + return; + + notify_notification_close(notification, nullptr); + g_object_set_data(G_OBJECT(webNotification), gNotifyNotificationID, nullptr); +} +#endif // USE(LIBNOTIFY) + +static gboolean webkitWebViewShowNotification(WebKitWebView*, WebKitNotification* webNotification) +{ +#if USE(LIBNOTIFY) + if (!notify_is_initted()) + notify_init(g_get_prgname()); + + NotifyNotification* notification = NOTIFY_NOTIFICATION(g_object_get_data(G_OBJECT(webNotification), gNotifyNotificationID)); + if (!notification) { + notification = notify_notification_new(webkit_notification_get_title(webNotification), + webkit_notification_get_body(webNotification), nullptr); + + notify_notification_add_action(notification, "default", _("Acknowledge"), NOTIFY_ACTION_CALLBACK(notifyNotificationClicked), webNotification, nullptr); + + g_signal_connect_object(notification, "closed", G_CALLBACK(notifyNotificationClosed), webNotification, static_cast<GConnectFlags>(0)); + g_signal_connect(webNotification, "closed", G_CALLBACK(webNotificationClosed), nullptr); + g_object_set_data_full(G_OBJECT(webNotification), gNotifyNotificationID, notification, static_cast<GDestroyNotify>(g_object_unref)); + } else { + notify_notification_update(notification, webkit_notification_get_title(webNotification), + webkit_notification_get_body(webNotification), nullptr); + } + + notify_notification_show(notification, nullptr); + return TRUE; +#else + UNUSED_PARAM(webNotification); + return FALSE; +#endif +} + static void webkitWebViewConstructed(GObject* object) { - if (G_OBJECT_CLASS(webkit_web_view_parent_class)->constructed) - G_OBJECT_CLASS(webkit_web_view_parent_class)->constructed(object); + G_OBJECT_CLASS(webkit_web_view_parent_class)->constructed(object); WebKitWebView* webView = WEBKIT_WEB_VIEW(object); WebKitWebViewPrivate* priv = webView->priv; - webkitWebContextCreatePageForWebView(priv->context, webView, priv->group.get(), priv->relatedView); + if (priv->relatedView) { + priv->context = webkit_web_view_get_context(priv->relatedView); + priv->isEphemeral = webkit_web_view_is_ephemeral(priv->relatedView); + } else if (!priv->context) + priv->context = webkit_web_context_get_default(); + else if (!priv->isEphemeral) + priv->isEphemeral = webkit_web_context_is_ephemeral(priv->context.get()); + + if (!priv->settings) + priv->settings = adoptGRef(webkit_settings_new()); + + if (priv->isEphemeral && !webkit_web_context_is_ephemeral(priv->context.get())) { + priv->websiteDataManager = adoptGRef(webkit_website_data_manager_new_ephemeral()); + webkitWebsiteDataManagerAddProcessPool(priv->websiteDataManager.get(), webkitWebContextGetProcessPool(priv->context.get())); + } + + webkitWebContextCreatePageForWebView(priv->context.get(), webView, priv->userContentManager.get(), priv->relatedView); + + priv->loadObserver = std::make_unique<PageLoadStateObserver>(webView); + getPage(webView)->pageLoadState().addObserver(*priv->loadObserver); + // The related view is only valid during the construction. priv->relatedView = nullptr; @@ -516,12 +678,12 @@ static void webkitWebViewConstructed(GObject* object) attachContextMenuClientToView(webView); attachFormClientToView(webView); + // This needs to be after attachUIClientToView() because WebPageProxy::setUIClient() calls setCanRunModal() with true. + // See https://bugs.webkit.org/show_bug.cgi?id=135412. + webkitWebViewUpdateSettings(webView); + priv->backForwardList = adoptGRef(webkitBackForwardListCreate(&getPage(webView)->backForwardList())); priv->windowProperties = adoptGRef(webkitWindowPropertiesCreate()); - - webkitWebViewUpdateSettings(webView); - priv->settingsChangedHandlerID = - g_signal_connect(webkit_web_view_get_group(webView), "notify::settings", G_CALLBACK(webkitWebViewSettingsChanged), webView); } static void webkitWebViewSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* paramSpec) @@ -531,7 +693,7 @@ static void webkitWebViewSetProperty(GObject* object, guint propId, const GValue switch (propId) { case PROP_WEB_CONTEXT: { gpointer webContext = g_value_get_object(value); - webView->priv->context = webContext ? WEBKIT_WEB_CONTEXT(webContext) : webkit_web_context_get_default(); + webView->priv->context = webContext ? WEBKIT_WEB_CONTEXT(webContext) : nullptr; break; } case PROP_RELATED_VIEW: { @@ -539,16 +701,24 @@ static void webkitWebViewSetProperty(GObject* object, guint propId, const GValue webView->priv->relatedView = relatedView ? WEBKIT_WEB_VIEW(relatedView) : nullptr; break; } - case PROP_GROUP: { - gpointer group = g_value_get_object(value); - webView->priv->group = group ? WEBKIT_WEB_VIEW_GROUP(group) : 0; + case PROP_SETTINGS: { + if (gpointer settings = g_value_get_object(value)) + webkit_web_view_set_settings(webView, WEBKIT_SETTINGS(settings)); + break; + } + case PROP_USER_CONTENT_MANAGER: { + gpointer userContentManager = g_value_get_object(value); + webView->priv->userContentManager = userContentManager ? WEBKIT_USER_CONTENT_MANAGER(userContentManager) : nullptr; break; } case PROP_ZOOM_LEVEL: webkit_web_view_set_zoom_level(webView, g_value_get_double(value)); break; - case PROP_VIEW_MODE: - webkit_web_view_set_view_mode(webView, static_cast<WebKitViewMode>(g_value_get_enum(value))); + case PROP_IS_EPHEMERAL: + webView->priv->isEphemeral = g_value_get_boolean(value); + break; + case PROP_EDITABLE: + webkit_web_view_set_editable(webView, g_value_get_boolean(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); @@ -561,10 +731,13 @@ static void webkitWebViewGetProperty(GObject* object, guint propId, GValue* valu switch (propId) { case PROP_WEB_CONTEXT: - g_value_set_object(value, webView->priv->context); + g_value_set_object(value, webView->priv->context.get()); break; - case PROP_GROUP: - g_value_set_object(value, webkit_web_view_get_group(webView)); + case PROP_SETTINGS: + g_value_set_object(value, webkit_web_view_get_settings(webView)); + break; + case PROP_USER_CONTENT_MANAGER: + g_value_set_object(value, webkit_web_view_get_user_content_manager(webView)); break; case PROP_TITLE: g_value_set_string(value, webView->priv->title.data()); @@ -584,8 +757,14 @@ static void webkitWebViewGetProperty(GObject* object, guint propId, GValue* valu case PROP_IS_LOADING: g_value_set_boolean(value, webkit_web_view_is_loading(webView)); break; - case PROP_VIEW_MODE: - g_value_set_enum(value, webkit_web_view_get_view_mode(webView)); + case PROP_IS_PLAYING_AUDIO: + g_value_set_boolean(value, webkit_web_view_is_playing_audio(webView)); + break; + case PROP_IS_EPHEMERAL: + g_value_set_boolean(value, webkit_web_view_is_ephemeral(webView)); + break; + case PROP_EDITABLE: + g_value_set_boolean(value, webkit_web_view_is_editable(webView)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); @@ -596,12 +775,23 @@ static void webkitWebViewDispose(GObject* object) { WebKitWebView* webView = WEBKIT_WEB_VIEW(object); webkitWebViewCancelFaviconRequest(webView); - webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView); - webkitWebViewDisconnectSettingsChangedSignalHandler(webView); webkitWebViewDisconnectSettingsSignalHandlers(webView); webkitWebViewDisconnectFaviconDatabaseSignalHandlers(webView); - webkitWebContextWebViewDestroyed(webView->priv->context, webView); + if (webView->priv->loadObserver) { + getPage(webView)->pageLoadState().removeObserver(*webView->priv->loadObserver); + webView->priv->loadObserver.reset(); + + // We notify the context here to ensure it's called only once. Ideally we should + // call this in finalize, not dispose, but finalize is used internally and we don't + // have access to the instance pointer from the private struct destructor. + webkitWebContextWebViewDestroyed(webView->priv->context.get(), webView); + } + + if (webView->priv->websiteDataManager) { + webkitWebsiteDataManagerRemoveProcessPool(webView->priv->websiteDataManager.get(), webkitWebContextGetProcessPool(webView->priv->context.get())); + webView->priv->websiteDataManager = nullptr; + } G_OBJECT_CLASS(webkit_web_view_parent_class)->dispose(object); } @@ -631,6 +821,7 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) webViewClass->permission_request = webkitWebViewPermissionRequest; webViewClass->run_file_chooser = webkitWebViewRunFileChooser; webViewClass->authenticate = webkitWebViewAuthenticate; + webViewClass->show_notification = webkitWebViewShowNotification; /** * WebKitWebView:web-context: @@ -664,18 +855,37 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY))); /** - * WebKitWebView:group: + * WebKitWebView:settings: + * + * The #WebKitSettings of the view. * - * The #WebKitWebViewGroup of the view. + * Since: 2.6 */ g_object_class_install_property( gObjectClass, - PROP_GROUP, + PROP_SETTINGS, g_param_spec_object( - "group", - _("WebView Group"), - _("The WebKitWebViewGroup of the view"), - WEBKIT_TYPE_WEB_VIEW_GROUP, + "settings", + _("WebView settings"), + _("The WebKitSettings of the view"), + WEBKIT_TYPE_SETTINGS, + static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); + + /** + * WebKitWebView:user-content-manager: + * + * The #WebKitUserContentManager of the view. + * + * Since: 2.6 + */ + g_object_class_install_property( + gObjectClass, + PROP_USER_CONTENT_MANAGER, + g_param_spec_object( + "user-content-manager", + _("WebView user content manager"), + _("The WebKitUserContentManager of the view"), + WEBKIT_TYPE_USER_CONTENT_MANAGER, static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY))); /** @@ -742,13 +952,15 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) * The zoom level of the #WebKitWebView content. * See webkit_web_view_set_zoom_level() for more details. */ - g_object_class_install_property(gObjectClass, - PROP_ZOOM_LEVEL, - g_param_spec_double("zoom-level", - "Zoom level", - _("The zoom level of the view content"), - 0, G_MAXDOUBLE, 1, - WEBKIT_PARAM_READWRITE)); + g_object_class_install_property( + gObjectClass, + PROP_ZOOM_LEVEL, + g_param_spec_double( + "zoom-level", + _("Zoom level"), + _("The zoom level of the view content"), + 0, G_MAXDOUBLE, 1, + WEBKIT_PARAM_READWRITE)); /** * WebKitWebView:is-loading: @@ -760,28 +972,76 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) * When the load operation finishes the property is set to %FALSE before * #WebKitWebView::load-changed is emitted with %WEBKIT_LOAD_FINISHED. */ - g_object_class_install_property(gObjectClass, - PROP_IS_LOADING, - g_param_spec_boolean("is-loading", - "Is Loading", - _("Whether the view is loading a page"), - FALSE, - WEBKIT_PARAM_READABLE)); + g_object_class_install_property( + gObjectClass, + PROP_IS_LOADING, + g_param_spec_boolean( + "is-loading", + _("Is Loading"), + _("Whether the view is loading a page"), + FALSE, + WEBKIT_PARAM_READABLE)); /** - * WebKitWebView:view-mode: + * WebKitWebView:is-playing-audio: + * + * Whether the #WebKitWebView is currently playing audio from a page. + * This property becomes %TRUE as soon as web content starts playing any + * kind of audio. When a page is no longer playing any kind of sound, + * the property is set back to %FALSE. * - * The #WebKitViewMode that is used to display the contents of a #WebKitWebView. - * See also webkit_web_view_set_view_mode(). + * Since: 2.8 */ - g_object_class_install_property(gObjectClass, - PROP_VIEW_MODE, - g_param_spec_enum("view-mode", - "View Mode", - _("The view mode to display the web view contents"), - WEBKIT_TYPE_VIEW_MODE, - WEBKIT_VIEW_MODE_WEB, - WEBKIT_PARAM_READWRITE)); + g_object_class_install_property( + gObjectClass, + PROP_IS_PLAYING_AUDIO, + g_param_spec_boolean( + "is-playing-audio", + "Is Playing Audio", + _("Whether the view is playing audio"), + FALSE, + WEBKIT_PARAM_READABLE)); + + /** + * WebKitWebView:is-ephemeral: + * + * Whether the #WebKitWebView is ephemeral. An ephemeral web view never writes + * website data to the client storage, no matter what #WebKitWebsiteDataManager + * its context is using. This is normally used to implement private browsing mode. + * This is a %G_PARAM_CONSTRUCT_ONLY property, so you have to create a ephemeral + * #WebKitWebView and it can't be changed. Note that all #WebKitWebView<!-- -->s + * created with an ephemeral #WebKitWebContext will be ephemeral automatically. + * See also webkit_web_context_new_ephemeral(). + * + * Since: 2.16 + */ + g_object_class_install_property( + gObjectClass, + PROP_IS_EPHEMERAL, + g_param_spec_boolean( + "is-ephemeral", + "Is Ephemeral", + _("Whether the web view is ephemeral"), + FALSE, + static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY))); + + /** + * WebKitWebView:editable: + * + * Whether the pages loaded inside #WebKitWebView are editable. For more + * information see webkit_web_view_set_editable(). + * + * Since: 2.8 + */ + g_object_class_install_property( + gObjectClass, + PROP_EDITABLE, + g_param_spec_boolean( + "editable", + _("Editable"), + _("Whether the content can be modified by the user."), + FALSE, + WEBKIT_PARAM_READWRITE)); /** * WebKitWebView::load-changed: @@ -865,30 +1125,31 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) * %FALSE to propagate the event further. */ signals[LOAD_FAILED] = - g_signal_new("load-failed", - G_TYPE_FROM_CLASS(webViewClass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(WebKitWebViewClass, load_failed), - g_signal_accumulator_true_handled, 0, - webkit_marshal_BOOLEAN__ENUM_STRING_POINTER, - G_TYPE_BOOLEAN, 3, - WEBKIT_TYPE_LOAD_EVENT, - G_TYPE_STRING, - G_TYPE_POINTER); + g_signal_new( + "load-failed", + G_TYPE_FROM_CLASS(webViewClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitWebViewClass, load_failed), + g_signal_accumulator_true_handled, 0, + g_cclosure_marshal_generic, + G_TYPE_BOOLEAN, 3, + WEBKIT_TYPE_LOAD_EVENT, + G_TYPE_STRING, + G_TYPE_ERROR | G_SIGNAL_TYPE_STATIC_SCOPE); /** * WebKitWebView::load-failed-with-tls-errors: * @web_view: the #WebKitWebView on which the signal is emitted - * @info: a #WebKitCertificateInfo - * @host: the host on which the error occurred + * @failing_uri: the URI that failed to load + * @certificate: a #GTlsCertificate + * @errors: a #GTlsCertificateFlags with the verification status of @certificate * - * Emitted when a TLS error occurs during a load operation. The @info - * object contains information about the error such as the #GTlsCertificate - * and the #GTlsCertificateFlags. To allow an exception for this certificate - * and this host use webkit_web_context_allow_tls_certificate_for_host(). + * Emitted when a TLS error occurs during a load operation. + * To allow an exception for this @certificate + * and the host of @failing_uri use webkit_web_context_allow_tls_certificate_for_host(). * - * To handle this signal asynchronously you should copy the #WebKitCertificateInfo - * with webkit_certificate_info_copy() and return %TRUE. + * To handle this signal asynchronously you should call g_object_ref() on @certificate + * and return %TRUE. * * If %FALSE is returned, #WebKitWebView::load-failed will be emitted. The load * will finish regardless of the returned value. @@ -896,7 +1157,7 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) * Returns: %TRUE to stop other handlers from being invoked for the event. * %FALSE to propagate the event further. * - * Since: 2.4 + * Since: 2.6 */ signals[LOAD_FAILED_WITH_TLS_ERRORS] = g_signal_new("load-failed-with-tls-errors", @@ -904,22 +1165,27 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(WebKitWebViewClass, load_failed_with_tls_errors), g_signal_accumulator_true_handled, 0 /* accumulator data */, - webkit_marshal_BOOLEAN__BOXED_STRING, - G_TYPE_BOOLEAN, 2, /* number of parameters */ - WEBKIT_TYPE_CERTIFICATE_INFO | G_SIGNAL_TYPE_STATIC_SCOPE, - G_TYPE_STRING); + g_cclosure_marshal_generic, + G_TYPE_BOOLEAN, 3, + G_TYPE_STRING, + G_TYPE_TLS_CERTIFICATE, + G_TYPE_TLS_CERTIFICATE_FLAGS); /** * WebKitWebView::create: * @web_view: the #WebKitWebView on which the signal is emitted + * @navigation_action: a #WebKitNavigationAction * * Emitted when the creation of a new #WebKitWebView is requested. * If this signal is handled the signal handler should return the * newly created #WebKitWebView. * + * The #WebKitNavigationAction parameter contains information about the + * navigation action that triggered this signal. + * * When using %WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES * process model, the new #WebKitWebView should be related to - * @web_view to share the same web process, see webkit_web_view_new_with_related_view + * @web_view to share the same web process, see webkit_web_view_new_with_related_view() * for more details. * * The new #WebKitWebView should not be displayed to the user @@ -928,14 +1194,15 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) * Returns: (transfer full): a newly allocated #WebKitWebView widget * or %NULL to propagate the event further. */ - signals[CREATE] = - g_signal_new("create", - G_TYPE_FROM_CLASS(webViewClass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(WebKitWebViewClass, create), - webkitWebViewAccumulatorObjectHandled, 0, - webkit_marshal_OBJECT__VOID, - GTK_TYPE_WIDGET, 0); + signals[CREATE] = g_signal_new( + "create", + G_TYPE_FROM_CLASS(webViewClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitWebViewClass, create), + webkitWebViewAccumulatorObjectHandled, 0, + g_cclosure_marshal_generic, + GTK_TYPE_WIDGET, 1, + WEBKIT_TYPE_NAVIGATION_ACTION | G_SIGNAL_TYPE_STATIC_SCOPE); /** * WebKitWebView::ready-to-show: @@ -980,10 +1247,11 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) /** * WebKitWebView::close: - * @webView: the #WebKitWebView on which the signal is emitted + * @web_view: the #WebKitWebView on which the signal is emitted * * Emitted when closing a #WebKitWebView is requested. This occurs when a - * call is made from JavaScript's <function>window.close</function> function. + * call is made from JavaScript's <function>window.close</function> function or + * after trying to close the @web_view with webkit_web_view_try_close(). * It is the owner's responsibility to handle this signal to hide or * destroy the #WebKitWebView, if necessary. */ @@ -1002,7 +1270,8 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) * @dialog: the #WebKitScriptDialog to show * * Emitted when JavaScript code calls <function>window.alert</function>, - * <function>window.confirm</function> or <function>window.prompt</function>. + * <function>window.confirm</function> or <function>window.prompt</function>, + * or when <function>onbeforeunload</function> event is fired. * The @dialog parameter should be used to build the dialog. * If the signal is not handled a different dialog will be built and shown depending * on the dialog type: @@ -1017,6 +1286,9 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) * %WEBKIT_SCRIPT_DIALOG_PROMPT: message dialog with OK and Cancel buttons and * a text entry with the default text. * </para></listitem> + * <listitem><para> + * %WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM: message dialog with Stay and Leave buttons. + * </para></listitem> * </itemizedlist> * * Returns: %TRUE to stop other handlers from being invoked for the event. @@ -1140,9 +1412,10 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) * request has not been handled, webkit_permission_request_deny() * will be the default action. * - * By default, if the signal is not handled, - * webkit_permission_request_deny() will be called over the - * #WebKitPermissionRequest. + * If the signal is not handled, the @request will be completed automatically + * by the specific #WebKitPermissionRequest that could allow or deny it. Check the + * documentation of classes implementing #WebKitPermissionRequest interface to know + * their default action. * * Returns: %TRUE to stop other handlers from being invoked for the event. * %FALSE to propagate the event further. @@ -1315,8 +1588,8 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) * @event: the #GdkEvent that triggered the context menu * @hit_test_result: a #WebKitHitTestResult * - * Emmited when a context menu is about to be displayed to give the application - * a chance to customize the proposed menu, prevent the menu from being displayed + * Emitted when a context menu is about to be displayed to give the application + * a chance to customize the proposed menu, prevent the menu from being displayed, * or build its own context menu. * <itemizedlist> * <listitem><para> @@ -1343,6 +1616,22 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) * </para></listitem> * </itemizedlist> * + * The @event is expected to be one of the following types: + * <itemizedlist> + * <listitem><para> + * a #GdkEventButton of type %GDK_BUTTON_PRESS when the context menu + * was triggered with mouse. + * </para></listitem> + * <listitem><para> + * a #GdkEventKey of type %GDK_KEY_PRESS if the keyboard was used to show + * the menu. + * </para></listitem> + * <listitem><para> + * a generic #GdkEvent of type %GDK_NOTHING when the #GtkWidget:popup-menu + * signal was used to show the context menu. + * </para></listitem> + * </itemizedlist> + * * If the signal handler returns %FALSE the context menu represented by @context_menu * will be shown, if it return %TRUE the context menu will not be shown. * @@ -1482,21 +1771,66 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) webkit_marshal_BOOLEAN__OBJECT, G_TYPE_BOOLEAN, 1, /* number of parameters */ WEBKIT_TYPE_AUTHENTICATION_REQUEST); -} - -static void webkitWebViewSetIsLoading(WebKitWebView* webView, bool isLoading) -{ - if (webView->priv->isLoading == isLoading) - return; - webView->priv->isLoading = isLoading; - g_object_freeze_notify(G_OBJECT(webView)); - g_object_notify(G_OBJECT(webView), "is-loading"); + /** + * WebKitWebView::show-notification: + * @web_view: the #WebKitWebView + * @notification: a #WebKitNotification + * + * This signal is emitted when a notification should be presented to the + * user. The @notification is kept alive until either: 1) the web page cancels it + * or 2) a navigation happens. + * + * The default handler will emit a notification using libnotify, if built with + * support for it. + * + * Returns: %TRUE to stop other handlers from being invoked. %FALSE otherwise. + * + * Since: 2.8 + */ + signals[SHOW_NOTIFICATION] = + g_signal_new("show-notification", + G_TYPE_FROM_CLASS(gObjectClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitWebViewClass, show_notification), + g_signal_accumulator_true_handled, nullptr /* accumulator data */, + webkit_marshal_BOOLEAN__OBJECT, + G_TYPE_BOOLEAN, 1, + WEBKIT_TYPE_NOTIFICATION); - // Update the URI if a new load has started. - if (webView->priv->isLoading) - webkitWebViewUpdateURI(webView); - g_object_thaw_notify(G_OBJECT(webView)); + /** + * WebKitWebView::run-color-chooser: + * @web_view: the #WebKitWebView on which the signal is emitted + * @request: a #WebKitColorChooserRequest + * + * This signal is emitted when the user interacts with a <input + * type='color' /> HTML element, requesting from WebKit to show + * a dialog to select a color. To let the application know the details of + * the color chooser, as well as to allow the client application to either + * cancel the request or perform an actual color selection, the signal will + * pass an instance of the #WebKitColorChooserRequest in the @request + * argument. + * + * It is possible to handle this request asynchronously by increasing the + * reference count of the request. + * + * The default signal handler will asynchronously run a regular + * #GtkColorChooser for the user to interact with. + * + * Returns: %TRUE to stop other handlers from being invoked for the event. + * %FALSE to propagate the event further. + * + * Since: 2.8 + */ + signals[RUN_COLOR_CHOOSER] = + g_signal_new("run-color-chooser", + G_TYPE_FROM_CLASS(webViewClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitWebViewClass, run_color_chooser), + g_signal_accumulator_true_handled, nullptr, + webkit_marshal_BOOLEAN__OBJECT, + G_TYPE_BOOLEAN, 1, + WEBKIT_TYPE_COLOR_CHOOSER_REQUEST); } static void webkitWebViewCancelAuthenticationRequest(WebKitWebView* webView) @@ -1508,68 +1842,35 @@ static void webkitWebViewCancelAuthenticationRequest(WebKitWebView* webView) webView->priv->authenticationRequest.clear(); } -static void webkitWebViewEmitLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent) -{ - if (loadEvent == WEBKIT_LOAD_STARTED) { - webkitWebViewSetIsLoading(webView, true); - webkitWebViewWatchForChangesInFavicon(webView); - webkitWebViewCancelAuthenticationRequest(webView); - } else if (loadEvent == WEBKIT_LOAD_FINISHED) { - webkitWebViewSetIsLoading(webView, false); - webkitWebViewCancelAuthenticationRequest(webView); - webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView); - } else - webkitWebViewUpdateURI(webView); - g_signal_emit(webView, signals[LOAD_CHANGED], 0, loadEvent); -} - -static void webkitWebViewEmitDelayedLoadEvents(WebKitWebView* webView) -{ - WebKitWebViewPrivate* priv = webView->priv; - if (!priv->waitingForMainResource) - return; - ASSERT(priv->lastDelayedEvent == WEBKIT_LOAD_COMMITTED || priv->lastDelayedEvent == WEBKIT_LOAD_FINISHED); - - if (priv->lastDelayedEvent == WEBKIT_LOAD_FINISHED) - webkitWebViewEmitLoadChanged(webView, WEBKIT_LOAD_COMMITTED); - webkitWebViewEmitLoadChanged(webView, priv->lastDelayedEvent); - priv->waitingForMainResource = false; -} - void webkitWebViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent) { WebKitWebViewPrivate* priv = webView->priv; - if (loadEvent == WEBKIT_LOAD_STARTED) { - // Finish a possible previous load waiting for main resource. - webkitWebViewEmitDelayedLoadEvents(webView); - + switch (loadEvent) { + case WEBKIT_LOAD_STARTED: webkitWebViewCancelFaviconRequest(webView); + webkitWebViewWatchForChangesInFavicon(webView); + webkitWebViewCancelAuthenticationRequest(webView); priv->loadingResourcesMap.clear(); - priv->mainResource = 0; - priv->waitingForMainResource = false; - } else if (loadEvent == WEBKIT_LOAD_COMMITTED) { - WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context); + priv->mainResource = nullptr; + break; + case WEBKIT_LOAD_COMMITTED: { + WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context.get()); GUniquePtr<char> faviconURI(webkit_favicon_database_get_favicon_uri(database, priv->activeURI.data())); webkitWebViewUpdateFaviconURI(webView, faviconURI.get()); - - if (!priv->mainResource) { - // When a page is loaded from the history cache, the main resource load callbacks - // are called when the main frame load is finished. We want to make sure there's a - // main resource available when load has been committed, so we delay the emission of - // load-changed signal until main resource object has been created. - priv->waitingForMainResource = true; - } + break; + } + case WEBKIT_LOAD_FINISHED: + webkitWebViewCancelAuthenticationRequest(webView); + break; + default: + break; } - if (priv->waitingForMainResource) - priv->lastDelayedEvent = loadEvent; - else - webkitWebViewEmitLoadChanged(webView, loadEvent); + g_signal_emit(webView, signals[LOAD_CHANGED], 0, loadEvent); } void webkitWebViewLoadFailed(WebKitWebView* webView, WebKitLoadEvent loadEvent, const char* failingURI, GError *error) { - webkitWebViewSetIsLoading(webView, false); webkitWebViewCancelAuthenticationRequest(webView); gboolean returnValue; @@ -1579,15 +1880,12 @@ void webkitWebViewLoadFailed(WebKitWebView* webView, WebKitLoadEvent loadEvent, void webkitWebViewLoadFailedWithTLSErrors(WebKitWebView* webView, const char* failingURI, GError* error, GTlsCertificateFlags tlsErrors, GTlsCertificate* certificate) { - webkitWebViewSetIsLoading(webView, false); webkitWebViewCancelAuthenticationRequest(webView); - WebKitTLSErrorsPolicy tlsErrorsPolicy = webkit_web_context_get_tls_errors_policy(webView->priv->context); + WebKitTLSErrorsPolicy tlsErrorsPolicy = webkit_web_context_get_tls_errors_policy(webView->priv->context.get()); if (tlsErrorsPolicy == WEBKIT_TLS_ERRORS_POLICY_FAIL) { - GUniquePtr<SoupURI> soupURI(soup_uri_new(failingURI)); - WebKitCertificateInfo info(certificate, tlsErrors); gboolean returnValue; - g_signal_emit(webView, signals[LOAD_FAILED_WITH_TLS_ERRORS], 0, &info, soupURI->host, &returnValue); + g_signal_emit(webView, signals[LOAD_FAILED_WITH_TLS_ERRORS], 0, failingURI, certificate, tlsErrors, &returnValue); if (!returnValue) g_signal_emit(webView, signals[LOAD_FAILED], 0, WEBKIT_LOAD_STARTED, failingURI, error, &returnValue); } @@ -1595,46 +1893,17 @@ void webkitWebViewLoadFailedWithTLSErrors(WebKitWebView* webView, const char* fa g_signal_emit(webView, signals[LOAD_CHANGED], 0, WEBKIT_LOAD_FINISHED); } -void webkitWebViewSetTitle(WebKitWebView* webView, const CString& title) -{ - WebKitWebViewPrivate* priv = webView->priv; - if (priv->title == title) - return; - - priv->title = title; - g_object_notify(G_OBJECT(webView), "title"); -} - -void webkitWebViewSetEstimatedLoadProgress(WebKitWebView* webView, double estimatedLoadProgress) -{ - if (webView->priv->estimatedLoadProgress == estimatedLoadProgress) - return; - - webView->priv->estimatedLoadProgress = estimatedLoadProgress; - g_object_notify(G_OBJECT(webView), "estimated-load-progress"); -} - -void webkitWebViewUpdateURI(WebKitWebView* webView) -{ - CString activeURI = getPage(webView)->pageLoadState().activeURL().utf8(); - if (webView->priv->activeURI == activeURI) - return; - - webView->priv->activeURI = activeURI; - g_object_notify(G_OBJECT(webView), "uri"); -} - -WebPageProxy* webkitWebViewCreateNewPage(WebKitWebView* webView, ImmutableDictionary* windowFeatures) +WebPageProxy* webkitWebViewCreateNewPage(WebKitWebView* webView, const WindowFeatures& windowFeatures, WebKitNavigationAction* navigationAction) { WebKitWebView* newWebView; - g_signal_emit(webView, signals[CREATE], 0, &newWebView); + g_signal_emit(webView, signals[CREATE], 0, navigationAction, &newWebView); if (!newWebView) return 0; webkitWindowPropertiesUpdateFromWebWindowFeatures(newWebView->priv->windowProperties.get(), windowFeatures); RefPtr<WebPageProxy> newPage = getPage(newWebView); - return newPage.release().leakRef(); + return newPage.leakRef(); } void webkitWebViewReadyToShowPage(WebKitWebView* webView) @@ -1647,9 +1916,14 @@ void webkitWebViewRunAsModal(WebKitWebView* webView) g_signal_emit(webView, signals[RUN_AS_MODAL], 0, NULL); webView->priv->modalLoop = adoptGRef(g_main_loop_new(0, FALSE)); + +// This is to suppress warnings about gdk_threads_leave and gdk_threads_enter. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" gdk_threads_leave(); g_main_loop_run(webView->priv->modalLoop.get()); gdk_threads_enter(); +#pragma GCC diagnostic pop } void webkitWebViewClosePage(WebKitWebView* webView) @@ -1680,6 +1954,14 @@ CString webkitWebViewRunJavaScriptPrompt(WebKitWebView* webView, const CString& return dialog.text; } +bool webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView* webView, const CString& message) +{ + WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM, message); + gboolean returnValue; + g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue); + return dialog.confirmed; +} + void webkitWebViewMakePolicyDecision(WebKitWebView* webView, WebKitPolicyDecisionType type, WebKitPolicyDecision* decision) { gboolean returnValue; @@ -1692,9 +1974,9 @@ void webkitWebViewMakePermissionRequest(WebKitWebView* webView, WebKitPermission g_signal_emit(webView, signals[PERMISSION_REQUEST], 0, request, &returnValue); } -void webkitWebViewMouseTargetChanged(WebKitWebView* webView, WebHitTestResult* hitTestResult, unsigned modifiers) +void webkitWebViewMouseTargetChanged(WebKitWebView* webView, const WebHitTestResultData& hitTestResult, unsigned modifiers) { - webkitWebViewBaseSetTooltipArea(WEBKIT_WEB_VIEW_BASE(webView), hitTestResult->elementBoundingBox()); + webkitWebViewBaseSetTooltipArea(WEBKIT_WEB_VIEW_BASE(webView), hitTestResult.elementBoundingBox); WebKitWebViewPrivate* priv = webView->priv; if (priv->mouseTargetHitTestResult @@ -1709,7 +1991,7 @@ void webkitWebViewMouseTargetChanged(WebKitWebView* webView, WebHitTestResult* h void webkitWebViewPrintFrame(WebKitWebView* webView, WebFrameProxy* frame) { - GRefPtr<WebKitPrintOperation> printOperation = adoptGRef(webkit_print_operation_new(webView)); + auto printOperation = adoptGRef(webkit_print_operation_new(webView)); webkitPrintOperationSetPrintMode(printOperation.get(), PrintInfo::PrintModeSync); gboolean returnValue; g_signal_emit(webView, signals[PRINT], 0, printOperation.get(), &returnValue); @@ -1722,32 +2004,13 @@ void webkitWebViewPrintFrame(WebKitWebView* webView, WebFrameProxy* frame) g_signal_connect(printOperation.leakRef(), "finished", G_CALLBACK(g_object_unref), 0); } -static void mainResourceResponseChangedCallback(WebKitWebResource*, GParamSpec*, WebKitWebView* webView) -{ - webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView); - webkitWebViewEmitDelayedLoadEvents(webView); -} - -static void waitForMainResourceResponseIfWaitingForResource(WebKitWebView* webView) -{ - WebKitWebViewPrivate* priv = webView->priv; - if (!priv->waitingForMainResource) - return; - - webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView); - priv->mainResourceResponseHandlerID = - g_signal_connect(priv->mainResource.get(), "notify::response", G_CALLBACK(mainResourceResponseChangedCallback), webView); -} - void webkitWebViewResourceLoadStarted(WebKitWebView* webView, WebFrameProxy* frame, uint64_t resourceIdentifier, WebKitURIRequest* request) { WebKitWebViewPrivate* priv = webView->priv; bool isMainResource = frame->isMainFrame() && !priv->mainResource; WebKitWebResource* resource = webkitWebResourceCreate(frame, request, isMainResource); - if (isMainResource) { + if (isMainResource) priv->mainResource = resource; - waitForMainResourceResponseIfWaitingForResource(webView); - } priv->loadingResourcesMap.set(resourceIdentifier, adoptGRef(resource)); g_signal_emit(webView, signals[RESOURCE_LOAD_STARTED], 0, resource, request); } @@ -1785,76 +2048,29 @@ void webkitWebViewRunFileChooserRequest(WebKitWebView* webView, WebKitFileChoose g_signal_emit(webView, signals[RUN_FILE_CHOOSER], 0, request, &returnValue); } -static bool webkitWebViewShouldShowInputMethodsMenu(WebKitWebView* webView) -{ - GtkSettings* settings = gtk_widget_get_settings(GTK_WIDGET(webView)); - if (!settings) - return true; - - gboolean showInputMethodMenu; - g_object_get(settings, "gtk-show-input-method-menu", &showInputMethodMenu, NULL); - return showInputMethodMenu; -} - -static int getUnicodeMenuItemPosition(WebKitContextMenu* contextMenu) -{ - GList* items = webkit_context_menu_get_items(contextMenu); - GList* iter; - int i = 0; - for (iter = items, i = 0; iter; iter = g_list_next(iter), ++i) { - WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(iter->data); - - if (webkit_context_menu_item_is_separator(item)) - continue; - if (webkit_context_menu_item_get_stock_action(item) == WEBKIT_CONTEXT_MENU_ACTION_UNICODE) - return i; - } - return -1; -} - -static void webkitWebViewCreateAndAppendInputMethodsMenuItem(WebKitWebView* webView, WebKitContextMenu* contextMenu) -{ - if (!webkitWebViewShouldShowInputMethodsMenu(webView)) - return; - - // Place the im context menu item right before the unicode menu item - // if it's present. - int unicodeMenuItemPosition = getUnicodeMenuItemPosition(contextMenu); - if (unicodeMenuItemPosition == -1) - webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); - - GtkIMContext* imContext = webkitWebViewBaseGetIMContext(WEBKIT_WEB_VIEW_BASE(webView)); - GtkMenu* imContextMenu = GTK_MENU(gtk_menu_new()); - gtk_im_multicontext_append_menuitems(GTK_IM_MULTICONTEXT(imContext), GTK_MENU_SHELL(imContextMenu)); - WebKitContextMenuItem* menuItem = webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS); - webkitContextMenuItemSetSubMenuFromGtkMenu(menuItem, imContextMenu); - webkit_context_menu_insert(contextMenu, menuItem, unicodeMenuItemPosition); -} - static void contextMenuDismissed(GtkMenuShell*, WebKitWebView* webView) { g_signal_emit(webView, signals[CONTEXT_MENU_DISMISSED], 0, NULL); } -void webkitWebViewPopulateContextMenu(WebKitWebView* webView, API::Array* proposedMenu, WebHitTestResult* webHitTestResult) +void webkitWebViewPopulateContextMenu(WebKitWebView* webView, const Vector<WebContextMenuItemData>& proposedMenu, const WebHitTestResultData& hitTestResultData, GVariant* userData) { WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView); WebContextMenuProxyGtk* contextMenuProxy = webkitWebViewBaseGetActiveContextMenuProxy(webViewBase); ASSERT(contextMenuProxy); GRefPtr<WebKitContextMenu> contextMenu = adoptGRef(webkitContextMenuCreate(proposedMenu)); - if (webHitTestResult->isContentEditable()) - webkitWebViewCreateAndAppendInputMethodsMenuItem(webView, contextMenu.get()); + if (userData) + webkit_context_menu_set_user_data(WEBKIT_CONTEXT_MENU(contextMenu.get()), userData); - GRefPtr<WebKitHitTestResult> hitTestResult = adoptGRef(webkitHitTestResultCreate(webHitTestResult)); + GRefPtr<WebKitHitTestResult> hitTestResult = adoptGRef(webkitHitTestResultCreate(hitTestResultData)); GUniquePtr<GdkEvent> contextMenuEvent(webkitWebViewBaseTakeContextMenuEvent(webViewBase)); - gboolean returnValue; g_signal_emit(webView, signals[CONTEXT_MENU], 0, contextMenu.get(), contextMenuEvent.get(), hitTestResult.get(), &returnValue); if (returnValue) return; - Vector<ContextMenuItem> contextMenuItems; + Vector<WebContextMenuItemGtk> contextMenuItems; webkitContextMenuPopulate(contextMenu.get(), contextMenuItems); contextMenuProxy->populate(contextMenuItems); @@ -1871,7 +2087,9 @@ void webkitWebViewSubmitFormRequest(WebKitWebView* webView, WebKitFormSubmission void webkitWebViewHandleAuthenticationChallenge(WebKitWebView* webView, AuthenticationChallengeProxy* authenticationChallenge) { - gboolean privateBrowsingEnabled = webkit_settings_get_enable_private_browsing(webkit_web_view_get_settings(webView)); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gboolean privateBrowsingEnabled = webView->priv->isEphemeral || webkit_settings_get_enable_private_browsing(webView->priv->settings.get()); + G_GNUC_END_IGNORE_DEPRECATIONS; webView->priv->authenticationRequest = adoptGRef(webkitAuthenticationRequestCreate(authenticationChallenge, privateBrowsingEnabled)); gboolean returnValue; g_signal_emit(webView, signals[AUTHENTICATE], 0, webView->priv->authenticationRequest.get(), &returnValue); @@ -1882,12 +2100,51 @@ void webkitWebViewInsecureContentDetected(WebKitWebView* webView, WebKitInsecure g_signal_emit(webView, signals[INSECURE_CONTENT_DETECTED], 0, type); } +bool webkitWebViewEmitShowNotification(WebKitWebView* webView, WebKitNotification* webNotification) +{ + gboolean handled; + g_signal_emit(webView, signals[SHOW_NOTIFICATION], 0, webNotification, &handled); + return handled; +} + +bool webkitWebViewEmitRunColorChooser(WebKitWebView* webView, WebKitColorChooserRequest* request) +{ + gboolean handled; + g_signal_emit(webView, signals[RUN_COLOR_CHOOSER], 0, request, &handled); + return handled; +} + +void webkitWebViewSelectionDidChange(WebKitWebView* webView) +{ + if (!webView->priv->editorState) + return; + + webkitEditorStateChanged(webView->priv->editorState.get(), getPage(webView)->editorState()); +} + +void webkitWebViewRequestInstallMissingMediaPlugins(WebKitWebView* webView, InstallMissingMediaPluginsPermissionRequest& request) +{ +#if ENABLE(VIDEO) + GRefPtr<WebKitInstallMissingMediaPluginsPermissionRequest> installMediaPluginsPermissionRequest = adoptGRef(webkitInstallMissingMediaPluginsPermissionRequestCreate(request)); + webkitWebViewMakePermissionRequest(webView, WEBKIT_PERMISSION_REQUEST(installMediaPluginsPermissionRequest.get())); +#else + ASSERT_NOT_REACHED(); +#endif +} + +WebKitWebsiteDataManager* webkitWebViewGetWebsiteDataManager(WebKitWebView* webView) +{ + return webView->priv->websiteDataManager.get(); +} + /** * webkit_web_view_new: * - * Creates a new #WebKitWebView with the default #WebKitWebContext and the - * default #WebKitWebViewGroup. - * See also webkit_web_view_new_with_context() and webkit_web_view_new_with_group(). + * Creates a new #WebKitWebView with the default #WebKitWebContext and + * no #WebKitUserContentManager associated with it. + * See also webkit_web_view_new_with_context(), + * webkit_web_view_new_with_user_content_manager(), and + * webkit_web_view_new_with_settings(). * * Returns: The newly created #WebKitWebView widget */ @@ -1900,9 +2157,10 @@ GtkWidget* webkit_web_view_new() * webkit_web_view_new_with_context: * @context: the #WebKitWebContext to be used by the #WebKitWebView * - * Creates a new #WebKitWebView with the given #WebKitWebContext and the - * default #WebKitWebViewGroup. - * See also webkit_web_view_new_with_group(). + * Creates a new #WebKitWebView with the given #WebKitWebContext and + * no #WebKitUserContentManager associated with it. + * See also webkit_web_view_new_with_user_content_manager() and + * webkit_web_view_new_with_settings(). * * Returns: The newly created #WebKitWebView widget */ @@ -1910,7 +2168,10 @@ GtkWidget* webkit_web_view_new_with_context(WebKitWebContext* context) { g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0); - return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "web-context", context, NULL)); + return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, + "is-ephemeral", webkit_web_context_is_ephemeral(context), + "web-context", context, + nullptr)); } /** @@ -1925,6 +2186,9 @@ GtkWidget* webkit_web_view_new_with_context(WebKitWebContext* context) * You can also use this method to implement other process models based on %WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES, * like for example, sharing the same web process for all the views in the same security domain. * + * The newly created #WebKitWebView will also have the same #WebKitUserContentManager + * and #WebKitSettings as @web_view. + * * Returns: (transfer full): The newly created #WebKitWebView widget * * Since: 2.4 @@ -1933,24 +2197,48 @@ GtkWidget* webkit_web_view_new_with_related_view(WebKitWebView* webView) { g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr); - return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "related-view", webView, nullptr)); + return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, + "user-content-manager", webView->priv->userContentManager.get(), + "settings", webView->priv->settings.get(), + "related-view", webView, + nullptr)); } /** - * webkit_web_view_new_with_group: - * @group: a #WebKitWebViewGroup + * webkit_web_view_new_with_settings: + * @settings: a #WebKitSettings * - * Creates a new #WebKitWebView with the given #WebKitWebViewGroup. - * The view will be part of @group and it will be affected by the - * group properties like the settings. + * Creates a new #WebKitWebView with the given #WebKitSettings. + * See also webkit_web_view_new_with_context(), and + * webkit_web_view_new_with_user_content_manager(). * * Returns: The newly created #WebKitWebView widget + * + * Since: 2.6 */ -GtkWidget* webkit_web_view_new_with_group(WebKitWebViewGroup* group) +GtkWidget* webkit_web_view_new_with_settings(WebKitSettings* settings) { - g_return_val_if_fail(WEBKIT_IS_WEB_VIEW_GROUP(group), 0); + g_return_val_if_fail(WEBKIT_IS_SETTINGS(settings), nullptr); + return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "settings", settings, nullptr)); +} - return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "group", group, NULL)); +/** + * webkit_web_view_new_with_user_content_manager: + * @user_content_manager: a #WebKitUserContentManager. + * + * Creates a new #WebKitWebView with the given #WebKitUserContentManager. + * The content loaded in the view may be affected by the content injected + * in the view by the user content manager. + * + * Returns: The newly created #WebKitWebView widget + * + * Since: 2.6 + */ +GtkWidget* webkit_web_view_new_with_user_content_manager(WebKitUserContentManager* userContentManager) +{ + g_return_val_if_fail(WEBKIT_IS_USER_CONTENT_MANAGER(userContentManager), nullptr); + + return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "user-content-manager", userContentManager, nullptr)); } /** @@ -1965,25 +2253,86 @@ WebKitWebContext* webkit_web_view_get_context(WebKitWebView *webView) { g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0); - return webView->priv->context; + return webView->priv->context.get(); } /** - * webkit_web_view_get_group: + * webkit_web_view_get_user_content_manager: * @web_view: a #WebKitWebView * - * Gets the group @web_view belongs to. + * Gets the user content manager associated to @web_view, or %NULL if the + * view does not have an user content manager. + * + * Returns: (transfer none): the #WebKitUserContentManager associated with the view * - * Returns: (transfer none): the #WebKitWebViewGroup to which the view belongs + * Since: 2.6 */ -WebKitWebViewGroup* webkit_web_view_get_group(WebKitWebView* webView) +WebKitUserContentManager* webkit_web_view_get_user_content_manager(WebKitWebView* webView) { - g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0); + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr); - if (webView->priv->group) - return webView->priv->group.get(); + return webView->priv->userContentManager.get(); +} - return webkitWebContextGetDefaultWebViewGroup(webView->priv->context); +/** + * webkit_web_view_is_ephemeral: + * @web_view: a #WebKitWebView + * + * Get whether a #WebKitWebView is ephemeral. To create an ephemeral #WebKitWebView you need to + * use g_object_new() and pass is-ephemeral propery with %TRUE value. See + * #WebKitWebView:is-ephemeral for more details. + * If @web_view was created with a ephemeral #WebKitWebView:related-view or an + * ephemeral #WebKitWebView:web-context it will also be ephemeral. + * + * Returns: %TRUE if @web_view is ephemeral or %FALSE otherwise. + * + * Since: 2.16 + */ +gboolean webkit_web_view_is_ephemeral(WebKitWebView* webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE); + + return webView->priv->isEphemeral; +} + +/** + * webkit_web_view_get_website_data_manager: + * @web_view: a #WebKitWebView + * + * Get the #WebKitWebsiteDataManager associated to @web_view. If @web_view is not ephemeral, + * the returned #WebKitWebsiteDataManager will be the same as the #WebKitWebsiteDataManager + * of @web_view's #WebKitWebContext. + * + * Returns: (transfer none): a #WebKitWebsiteDataManager + * + * Since: 2.16 + */ +WebKitWebsiteDataManager* webkit_web_view_get_website_data_manager(WebKitWebView* webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr); + + if (webView->priv->websiteDataManager) + return webView->priv->websiteDataManager.get(); + + return webkit_web_context_get_website_data_manager(webView->priv->context.get()); +} + +/** + * webkit_web_view_try_close: + * @web_view: a #WebKitWebView + * + * Tries to close the @web_view. This will fire the onbeforeunload event + * to ask the user for confirmation to close the page. If there isn't an + * onbeforeunload event handler or the user confirms to close the page, + * the #WebKitWebView::close signal is emitted, otherwise nothing happens. + * + * Since: 2.12 + */ +void webkit_web_view_try_close(WebKitWebView *webView) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + if (getPage(webView)->tryClose()) + webkitWebViewClosePage(webView); } /** @@ -2067,6 +2416,45 @@ void webkit_web_view_load_plain_text(WebKitWebView* webView, const gchar* plainT getPage(webView)->loadPlainTextString(String::fromUTF8(plainText)); } +static void releaseGBytes(unsigned char*, const void* bytes) +{ + // Balanced by g_bytes_ref in webkit_web_view_load_bytes(). + g_bytes_unref(static_cast<GBytes*>(const_cast<void*>(bytes))); +} + +/** + * webkit_web_view_load_bytes: + * @web_view: a #WebKitWebView + * @bytes: input data to load + * @mime_type: (allow-none): the MIME type of @bytes, or %NULL + * @encoding: (allow-none): the character encoding of @bytes, or %NULL + * @base_uri: (allow-none): the base URI for relative locations or %NULL + * + * Load the specified @bytes into @web_view using the given @mime_type and @encoding. + * When @mime_type is %NULL, it defaults to "text/html". + * When @encoding is %NULL, it defaults to "UTF-8". + * When @base_uri is %NULL, it defaults to "about:blank". + * You can monitor the load operation by connecting to #WebKitWebView::load-changed signal. + * + * Since: 2.6 + */ +void webkit_web_view_load_bytes(WebKitWebView* webView, GBytes* bytes, const char* mimeType, const char* encoding, const char* baseURI) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + g_return_if_fail(bytes); + + gsize bytesDataSize; + gconstpointer bytesData = g_bytes_get_data(bytes, &bytesDataSize); + g_return_if_fail(bytesDataSize); + + // Balanced by g_bytes_unref in releaseGBytes. + g_bytes_ref(bytes); + + Ref<API::Data> data = API::Data::createWithoutCopying(static_cast<const unsigned char*>(bytesData), bytesDataSize, releaseGBytes, bytes); + getPage(webView)->loadData(data.ptr(), mimeType ? String::fromUTF8(mimeType) : String::fromUTF8("text/html"), + encoding ? String::fromUTF8(encoding) : String::fromUTF8("UTF-8"), String::fromUTF8(baseURI)); +} + /** * webkit_web_view_load_request: * @web_view: a #WebKitWebView @@ -2130,7 +2518,9 @@ void webkit_web_view_reload(WebKitWebView* webView) { g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); - getPage(webView)->reload(false); + const bool reloadFromOrigin = false; + const bool contentBlockersEnabled = true; + getPage(webView)->reload(reloadFromOrigin, contentBlockersEnabled); } /** @@ -2144,7 +2534,9 @@ void webkit_web_view_reload_bypass_cache(WebKitWebView* webView) { g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); - getPage(webView)->reload(true); + const bool reloadFromOrigin = true; + const bool contentBlockersEnabled = true; + getPage(webView)->reload(reloadFromOrigin, contentBlockersEnabled); } /** @@ -2185,6 +2577,27 @@ gboolean webkit_web_view_is_loading(WebKitWebView* webView) } /** + * webkit_web_view_is_playing_audio: + * @web_view: a #WebKitWebView + * + * Gets the value of the #WebKitWebView:is-playing-audio property. + * You can monitor when a page in a #WebKitWebView is playing audio by + * connecting to the notify::is-playing-audio signal of @web_view. This + * is useful when the application wants to provide visual feedback when a + * page is producing sound. + * + * Returns: %TRUE if a page in @web_view is playing audio or %FALSE otherwise. + * + * Since: 2.8 + */ +gboolean webkit_web_view_is_playing_audio(WebKitWebView* webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE); + + return getPage(webView)->isPlayingAudio(); +} + +/** * webkit_web_view_go_back: * @web_view: a #WebKitWebView * @@ -2382,7 +2795,7 @@ void webkit_web_view_set_custom_charset(WebKitWebView* webView, const gchar* cha gdouble webkit_web_view_get_estimated_load_progress(WebKitWebView* webView) { g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0); - return webView->priv->estimatedLoadProgress; + return getPage(webView)->pageLoadState().estimatedProgress(); } /** @@ -2423,16 +2836,30 @@ void webkit_web_view_go_to_back_forward_list_item(WebKitWebView* webView, WebKit * @web_view: a #WebKitWebView * @settings: a #WebKitSettings * - * Sets the #WebKitSettings to be applied to @web_view. - * This is a convenient method to set new settings to the - * #WebKitWebViewGroup @web_view belongs to. - * New settings are applied immediately on all #WebKitWebView<!-- -->s - * in the @web_view group. - * See also webkit_web_view_group_set_settings(). + * Sets the #WebKitSettings to be applied to @web_view. The + * existing #WebKitSettings of @web_view will be replaced by + * @settings. New settings are applied immediately on @web_view. + * The same #WebKitSettings object can be shared + * by multiple #WebKitWebView<!-- -->s. */ void webkit_web_view_set_settings(WebKitWebView* webView, WebKitSettings* settings) { - webkit_web_view_group_set_settings(webkit_web_view_get_group(webView), settings); + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + g_return_if_fail(WEBKIT_IS_SETTINGS(settings)); + + if (webView->priv->settings == settings) + return; + + // The "settings" property is set on construction, and in that + // case webkit_web_view_set_settings() will be called *before* + // any settings have been assigned. In that case there are no + // signal handlers to disconnect. + if (webView->priv->settings) + webkitWebViewDisconnectSettingsSignalHandlers(webView); + + webView->priv->settings = settings; + webkitWebViewUpdateSettings(webView); + g_object_notify(G_OBJECT(webView), "settings"); } /** @@ -2440,19 +2867,25 @@ void webkit_web_view_set_settings(WebKitWebView* webView, WebKitSettings* settin * @web_view: a #WebKitWebView * * Gets the #WebKitSettings currently applied to @web_view. - * This is a convenient method to get the settings of the - * #WebKitWebViewGroup @web_view belongs to. - * #WebKitSettings objects are shared by all the #WebKitWebView<!-- -->s - * in the same #WebKitWebViewGroup, so modifying + * If no other #WebKitSettings have been explicitly applied to + * @web_view with webkit_web_view_set_settings(), the default + * #WebKitSettings will be returned. This method always returns + * a valid #WebKitSettings object. + * To modify any of the @web_view settings, you can either create + * a new #WebKitSettings object with webkit_settings_new(), setting + * the desired preferences, and then replace the existing @web_view + * settings with webkit_web_view_set_settings() or get the existing + * @web_view settings and update it directly. #WebKitSettings objects + * can be shared by multiple #WebKitWebView<!-- -->s, so modifying * the settings of a #WebKitWebView would affect other - * #WebKitWebView<!-- -->s of the same group. - * See also webkit_web_view_group_get_settings(). + * #WebKitWebView<!-- -->s using the same #WebKitSettings. * * Returns: (transfer none): the #WebKitSettings attached to @web_view */ WebKitSettings* webkit_web_view_get_settings(WebKitWebView* webView) { - return webkit_web_view_group_get_settings(webkit_web_view_get_group(webView)); + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr); + return webView->priv->settings.get(); } /** @@ -2487,7 +2920,7 @@ void webkit_web_view_set_zoom_level(WebKitWebView* webView, gdouble zoomLevel) return; WebPageProxy* page = getPage(webView); - if (webkit_settings_get_zoom_text_only(webkit_web_view_get_settings(webView))) + if (webkit_settings_get_zoom_text_only(webView->priv->settings.get())) page->setTextZoomFactor(zoomLevel); else page->setPageZoomFactor(zoomLevel); @@ -2508,16 +2941,10 @@ gdouble webkit_web_view_get_zoom_level(WebKitWebView* webView) g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 1); WebPageProxy* page = getPage(webView); - gboolean zoomTextOnly = webkit_settings_get_zoom_text_only(webkit_web_view_get_settings(webView)); + gboolean zoomTextOnly = webkit_settings_get_zoom_text_only(webView->priv->settings.get()); return zoomTextOnly ? page->textZoomFactor() : page->pageZoomFactor(); } -static void didValidateCommand(WKStringRef command, bool isEnabled, int32_t state, WKErrorRef, void* context) -{ - GRefPtr<GTask> task = adoptGRef(G_TASK(context)); - g_task_return_boolean(task.get(), isEnabled); -} - /** * webkit_web_view_can_execute_editing_command: * @web_view: a #WebKitWebView @@ -2526,7 +2953,7 @@ static void didValidateCommand(WKStringRef command, bool isEnabled, int32_t stat * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied * @user_data: (closure): the data to pass to callback function * - * Asynchronously execute the given editing command. + * Asynchronously check if it is possible to execute the given editing command. * * When the operation is finished, @callback will be called. You can then call * webkit_web_view_can_execute_editing_command_finish() to get the result of the operation. @@ -2537,7 +2964,9 @@ void webkit_web_view_can_execute_editing_command(WebKitWebView* webView, const c g_return_if_fail(command); GTask* task = g_task_new(webView, cancellable, callback, userData); - getPage(webView)->validateCommand(String::fromUTF8(command), ValidateCommandCallback::create(task, didValidateCommand)); + getPage(webView)->validateCommand(String::fromUTF8(command), [task](const String&, bool isEnabled, int32_t, WebKit::CallbackBase::Error) { + g_task_return_boolean(adoptGRef(task).get(), isEnabled); + }); } /** @@ -2576,6 +3005,27 @@ void webkit_web_view_execute_editing_command(WebKitWebView* webView, const char* } /** + * webkit_web_view_execute_editing_command_with_argument: + * @web_view: a #WebKitWebView + * @command: the command to execute + * @argument: the command argument + * + * Request to execute the given @command with @argument for @web_view. You can use + * webkit_web_view_can_execute_editing_command() to check whether + * it's possible to execute the command. + * + * Since: 2.10 + */ +void webkit_web_view_execute_editing_command_with_argument(WebKitWebView* webView, const char* command, const char* argument) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + g_return_if_fail(command); + g_return_if_fail(argument); + + getPage(webView)->executeEditCommand(String::fromUTF8(command), String::fromUTF8(argument)); +} + +/** * webkit_web_view_get_find_controller: * @web_view: the #WebKitWebView * @@ -2614,20 +3064,20 @@ JSGlobalContextRef webkit_web_view_get_javascript_global_context(WebKitWebView* return webView->priv->javascriptGlobalContext; } -static void webkitWebViewRunJavaScriptCallback(WKSerializedScriptValueRef wkSerializedScriptValue, WKErrorRef, void* context) +static void webkitWebViewRunJavaScriptCallback(API::SerializedScriptValue* wkSerializedScriptValue, GTask* task) { - GRefPtr<GTask> task = adoptGRef(G_TASK(context)); - if (g_task_return_error_if_cancelled(task.get())) + if (g_task_return_error_if_cancelled(task)) return; if (!wkSerializedScriptValue) { - g_task_return_new_error(task.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED, + g_task_return_new_error(task, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED, _("An exception was raised in JavaScript")); return; } - WebKitWebView* webView = WEBKIT_WEB_VIEW(g_task_get_source_object(task.get())); - g_task_return_pointer(task.get(), webkitJavascriptResultCreate(webView, toImpl(wkSerializedScriptValue)), + WebKitWebView* webView = WEBKIT_WEB_VIEW(g_task_get_source_object(task)); + g_task_return_pointer(task, webkitJavascriptResultCreate(webView, + *wkSerializedScriptValue->internalRepresentation()), reinterpret_cast<GDestroyNotify>(webkit_javascript_result_unref)); } @@ -2640,7 +3090,7 @@ static void webkitWebViewRunJavaScriptCallback(WKSerializedScriptValueRef wkSeri * @user_data: (closure): the data to pass to callback function * * Asynchronously run @script in the context of the current page in @web_view. If - * WebKitWebSettings:enable-javascript is FALSE, this method will do nothing. + * WebKitSettings:enable-javascript is FALSE, this method will do nothing. * * When the operation is finished, @callback will be called. You can then call * webkit_web_view_run_javascript_finish() to get the result of the operation. @@ -2651,7 +3101,9 @@ void webkit_web_view_run_javascript(WebKitWebView* webView, const gchar* script, g_return_if_fail(script); GTask* task = g_task_new(webView, cancellable, callback, userData); - getPage(webView)->runJavaScriptInMainFrame(String::fromUTF8(script), ScriptValueCallback::create(task, webkitWebViewRunJavaScriptCallback)); + getPage(webView)->runJavaScriptInMainFrame(String::fromUTF8(script), [task](API::SerializedScriptValue* serializedScriptValue, bool, const WebCore::ExceptionDetails&, WebKit::CallbackBase::Error) { + webkitWebViewRunJavaScriptCallback(serializedScriptValue, adoptGRef(task).get()); + }); } /** @@ -2740,7 +3192,9 @@ static void resourcesStreamReadCallback(GObject* object, GAsyncResult* result, g WebKitWebView* webView = WEBKIT_WEB_VIEW(g_task_get_source_object(task.get())); gpointer outputStreamData = g_memory_output_stream_get_data(G_MEMORY_OUTPUT_STREAM(object)); getPage(webView)->runJavaScriptInMainFrame(String::fromUTF8(reinterpret_cast<const gchar*>(outputStreamData)), - ScriptValueCallback::create(task.leakRef(), webkitWebViewRunJavaScriptCallback)); + [task](API::SerializedScriptValue* serializedScriptValue, bool, const WebCore::ExceptionDetails&, WebKit::CallbackBase::Error) { + webkitWebViewRunJavaScriptCallback(serializedScriptValue, task.get()); + }); } /** @@ -2867,16 +3321,16 @@ static void fileReplaceContentsCallback(GObject* object, GAsyncResult* result, g g_task_return_boolean(task.get(), TRUE); } -static void getContentsAsMHTMLDataCallback(WKDataRef wkData, WKErrorRef, void* context) +static void getContentsAsMHTMLDataCallback(API::Data* wkData, GTask* taskPtr) { - GRefPtr<GTask> task = adoptGRef(G_TASK(context)); + auto task = adoptGRef(taskPtr); if (g_task_return_error_if_cancelled(task.get())) return; ViewSaveAsyncData* data = static_cast<ViewSaveAsyncData*>(g_task_get_task_data(task.get())); // We need to retain the data until the asyncronous process // initiated by the user has finished completely. - data->webData = toImpl(wkData); + data->webData = wkData; // If we are saving to a file we need to write the data on disk before finishing. if (g_task_get_source_tag(task.get()) == webkit_web_view_save_to_file) { @@ -2916,7 +3370,9 @@ void webkit_web_view_save(WebKitWebView* webView, WebKitSaveMode saveMode, GCanc GTask* task = g_task_new(webView, cancellable, callback, userData); g_task_set_source_tag(task, reinterpret_cast<gpointer>(webkit_web_view_save)); g_task_set_task_data(task, createViewSaveAsyncData(), reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData)); - getPage(webView)->getContentsAsMHTMLData(DataCallback::create(task, getContentsAsMHTMLDataCallback), false); + getPage(webView)->getContentsAsMHTMLData([task](API::Data* data, WebKit::CallbackBase::Error) { + getContentsAsMHTMLDataCallback(data, task); + }); } /** @@ -2979,7 +3435,9 @@ void webkit_web_view_save_to_file(WebKitWebView* webView, GFile* file, WebKitSav data->file = file; g_task_set_task_data(task, data, reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData)); - getPage(webView)->getContentsAsMHTMLData(DataCallback::create(task, getContentsAsMHTMLDataCallback), false); + getPage(webView)->getContentsAsMHTMLData([task](API::Data* data, WebKit::CallbackBase::Error) { + getContentsAsMHTMLDataCallback(data, task); + }); } /** @@ -3012,50 +3470,11 @@ gboolean webkit_web_view_save_to_file_finish(WebKitWebView* webView, GAsyncResul */ WebKitDownload* webkit_web_view_download_uri(WebKitWebView* webView, const char* uri) { - g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0); - g_return_val_if_fail(uri, 0); - - WebKitDownload* download = webkitWebContextStartDownload(webView->priv->context, uri, getPage(webView)); - webkitDownloadSetWebView(download, webView); - - return download; -} - -/** - * webkit_web_view_set_view_mode: - * @web_view: a #WebKitWebView - * @view_mode: a #WebKitViewMode - * - * Set the view mode of @web_view to @view_mode. This method should be called - * before loading new contents on @web_view so that the new #WebKitViewMode will - * be applied to the new contents. - */ -void webkit_web_view_set_view_mode(WebKitWebView* webView, WebKitViewMode viewMode) -{ - g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); - - if (webView->priv->viewMode == viewMode) - return; - - getPage(webView)->setMainFrameInViewSourceMode(viewMode == WEBKIT_VIEW_MODE_SOURCE); - - webView->priv->viewMode = viewMode; - g_object_notify(G_OBJECT(webView), "view-mode"); -} - -/** - * webkit_web_view_get_view_mode: - * @web_view: a #WebKitWebView - * - * Get the view mode of @web_view. - * - * Returns: the #WebKitViewMode of @web_view. - */ -WebKitViewMode webkit_web_view_get_view_mode(WebKitWebView* webView) -{ - g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), WEBKIT_VIEW_MODE_WEB); + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr); + g_return_val_if_fail(uri, nullptr); - return webView->priv->viewMode; + GRefPtr<WebKitDownload> download = webkitWebContextStartDownload(webView->priv->context.get(), uri, getPage(webView)); + return download.leakRef(); } /** @@ -3073,10 +3492,10 @@ WebKitViewMode webkit_web_view_get_view_mode(WebKitWebView* webView) * when it's emitted with %WEBKIT_LOAD_COMMITTED event. * * Note that this function provides no information about the security of the web - * page if the current #WebKitTLSErrorsPolicy is %WEBKIT_TLS_ERRORS_POLICY_IGNORE, + * page if the current #WebKitTLSErrorsPolicy is @WEBKIT_TLS_ERRORS_POLICY_IGNORE, * as subresources of the page may be controlled by an attacker. This function * may safely be used to determine the security status of the current page only - * if the current #WebKitTLSErrorsPolicy is %WEBKIT_TLS_ERRORS_POLICY_FAIL, in + * if the current #WebKitTLSErrorsPolicy is @WEBKIT_TLS_ERRORS_POLICY_FAIL, in * which case subresources that fail certificate verification will be blocked. * * Returns: %TRUE if the @web_view connection uses HTTPS and a response has been received @@ -3090,7 +3509,10 @@ gboolean webkit_web_view_get_tls_info(WebKitWebView* webView, GTlsCertificate** if (!mainFrame) return FALSE; - const WebCore::CertificateInfo& certificateInfo = mainFrame->certificateInfo()->certificateInfo(); + auto* wkCertificateInfo = mainFrame->certificateInfo(); + g_return_val_if_fail(wkCertificateInfo, FALSE); + + const auto& certificateInfo = wkCertificateInfo->certificateInfo(); if (certificate) *certificate = certificateInfo.certificate(); if (errors) @@ -3111,15 +3533,9 @@ void webKitWebViewDidReceiveSnapshot(WebKitWebView* webView, uint64_t callbackID return; } - if (RefPtr<ShareableBitmap> image = webImage->bitmap()) - g_task_return_pointer(task.get(), image->createCairoSurface().leakRef(), reinterpret_cast<GDestroyNotify>(cairo_surface_destroy)); - else - g_task_return_pointer(task.get(), 0, 0); + g_task_return_pointer(task.get(), webImage->bitmap().createCairoSurface().leakRef(), reinterpret_cast<GDestroyNotify>(cairo_surface_destroy)); } -COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_SNAPSHOT_REGION_VISIBLE, SnapshotRegionVisible); -COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT, SnapshotRegionFullDocument); - static inline unsigned webKitSnapshotOptionsToSnapshotOptions(WebKitSnapshotOptions options) { SnapshotOptions snapshotOptions = 0; @@ -3130,6 +3546,19 @@ static inline unsigned webKitSnapshotOptionsToSnapshotOptions(WebKitSnapshotOpti return snapshotOptions; } +static inline SnapshotRegion toSnapshotRegion(WebKitSnapshotRegion region) +{ + switch (region) { + case WEBKIT_SNAPSHOT_REGION_VISIBLE: + return SnapshotRegionVisible; + case WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT: + return SnapshotRegionFullDocument; + default: + ASSERT_NOT_REACHED(); + return SnapshotRegionVisible; + } +} + static inline uint64_t generateSnapshotCallbackID() { static uint64_t uniqueCallbackID = 1; @@ -3139,8 +3568,8 @@ static inline uint64_t generateSnapshotCallbackID() /** * webkit_web_view_get_snapshot: * @web_view: a #WebKitWebView - * @options: #WebKitSnapshotOptions for the snapshot * @region: the #WebKitSnapshotRegion for this snapshot + * @options: #WebKitSnapshotOptions for the snapshot * @cancellable: (allow-none): a #GCancellable * @callback: (scope async): a #GAsyncReadyCallback * @user_data: (closure): user data @@ -3156,14 +3585,15 @@ void webkit_web_view_get_snapshot(WebKitWebView* webView, WebKitSnapshotRegion r { g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); - ImmutableDictionary::MapType message; + API::Dictionary::MapType message; uint64_t callbackID = generateSnapshotCallbackID(); message.set(String::fromUTF8("SnapshotOptions"), API::UInt64::create(static_cast<uint64_t>(webKitSnapshotOptionsToSnapshotOptions(options)))); - message.set(String::fromUTF8("SnapshotRegion"), API::UInt64::create(static_cast<uint64_t>(region))); + message.set(String::fromUTF8("SnapshotRegion"), API::UInt64::create(static_cast<uint64_t>(toSnapshotRegion(region)))); message.set(String::fromUTF8("CallbackID"), API::UInt64::create(callbackID)); + message.set(String::fromUTF8("TransparentBackground"), API::Boolean::create(options & WEBKIT_SNAPSHOT_OPTIONS_TRANSPARENT_BACKGROUND)); webView->priv->snapshotResultsMap.set(callbackID, adoptGRef(g_task_new(webView, cancellable, callback, userData))); - getPage(webView)->postMessageToInjectedBundle(String::fromUTF8("GetSnapshot"), ImmutableDictionary::create(std::move(message)).get()); + getPage(webView)->postMessageToInjectedBundle(String::fromUTF8("GetSnapshot"), API::Dictionary::create(WTFMove(message)).ptr()); } /** @@ -3190,3 +3620,173 @@ void webkitWebViewWebProcessCrashed(WebKitWebView* webView) g_signal_emit(webView, signals[WEB_PROCESS_CRASHED], 0, &returnValue); } +/** + * webkit_web_view_set_background_color: + * @web_view: a #WebKitWebView + * @rgba: a #GdkRGBA + * + * Sets the color that will be used to draw the @web_view background before + * the actual contents are rendered. Note that if the web page loaded in @web_view + * specifies a background color, it will take precedence over the @rgba color. + * By default the @web_view background color is opaque white. + * Note that the parent window must have a RGBA visual and + * #GtkWidget:app-paintable property set to %TRUE for backgrounds colors to work. + * + * <informalexample><programlisting> + * static void browser_window_set_background_color (BrowserWindow *window, + * const GdkRGBA *rgba) + * { + * WebKitWebView *web_view; + * GdkScreen *screen = gtk_window_get_screen (GTK_WINDOW (window)); + * GdkVisual *rgba_visual = gdk_screen_get_rgba_visual (screen); + * + * if (!rgba_visual) + * return; + * + * gtk_widget_set_visual (GTK_WIDGET (window), rgba_visual); + * gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE); + * + * web_view = browser_window_get_web_view (window); + * webkit_web_view_set_background_color (web_view, rgba); + * } + * </programlisting></informalexample> + * + * Since: 2.8 + */ +void webkit_web_view_set_background_color(WebKitWebView* webView, const GdkRGBA* rgba) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + g_return_if_fail(rgba); + + Color color(*rgba); + WebPageProxy* page = getPage(webView); + if (page->backgroundColor() == color) + return; + + page->setBackgroundColor(color); + page->setDrawsBackground(color == Color::white); +} + +/** + * webkit_web_view_get_background_color: + * @web_view: a #WebKitWebView + * @rgba: (out): a #GdkRGBA to fill in with the background color + * + * Gets the color that is used to draw the @web_view background before + * the actual contents are rendered. + * For more information see also webkit_web_view_set_background_color() + * + * Since: 2.8 + */ +void webkit_web_view_get_background_color(WebKitWebView* webView, GdkRGBA* rgba) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + g_return_if_fail(rgba); + + *rgba = getPage(webView)->backgroundColor(); +} + +/* + * webkit_web_view_is_editable: + * @web_view: a #WebKitWebView + * + * Gets whether the user is allowed to edit the HTML document. When @web_view + * is not editable an element in the HTML document can only be edited if the + * CONTENTEDITABLE attribute has been set on the element or one of its parent + * elements. By default a #WebKitWebView is not editable. + * + * Returns: %TRUE if the user is allowed to edit the HTML document, or %FALSE otherwise. + * + * Since: 2.8 + */ +gboolean webkit_web_view_is_editable(WebKitWebView* webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE); + + return getPage(webView)->isEditable(); +} + +/** + * webkit_web_view_set_editable: + * @web_view: a #WebKitWebView + * @editable: a #gboolean indicating the editable state + * + * Sets whether the user is allowed to edit the HTML document. + * + * If @editable is %TRUE, @web_view allows the user to edit the HTML document. If + * @editable is %FALSE, an element in @web_view's document can only be edited if the + * CONTENTEDITABLE attribute has been set on the element or one of its parent + * elements. By default a #WebKitWebView is not editable. + * + * Normally, a HTML document is not editable unless the elements within the + * document are editable. This function provides a way to make the contents + * of a #WebKitWebView editable without altering the document or DOM structure. + * + * Since: 2.8 + */ +void webkit_web_view_set_editable(WebKitWebView* webView, gboolean editable) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + + if (editable == getPage(webView)->isEditable()) + return; + + getPage(webView)->setEditable(editable); + + g_object_notify(G_OBJECT(webView), "editable"); +} + +/** + * webkit_web_view_get_editor_state: + * @web_view: a #WebKitWebView + * + * Gets the web editor state of @web_view. + * + * Returns: (transfer none): the #WebKitEditorState of the view + * + * Since: 2.10 + */ +WebKitEditorState* webkit_web_view_get_editor_state(WebKitWebView *webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr); + + if (!webView->priv->editorState) + webView->priv->editorState = adoptGRef(webkitEditorStateCreate(getPage(webView)->editorState())); + + return webView->priv->editorState.get(); +} + +/** + * webkit_web_view_get_session_state: + * @web_view: a #WebKitWebView + * + * Gets the current session state of @web_view + * + * Returns: (transfer full): a #WebKitWebViewSessionState + * + * Since: 2.12 + */ +WebKitWebViewSessionState* webkit_web_view_get_session_state(WebKitWebView* webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr); + + SessionState sessionState = getPage(webView)->sessionState(nullptr); + return webkitWebViewSessionStateCreate(WTFMove(sessionState)); +} + +/** + * webkit_web_view_restore_session_state: + * @web_view: a #WebKitWebView + * @state: a #WebKitWebViewSessionState + * + * Restore the @web_view session state from @state + * + * Since: 2.12 + */ +void webkit_web_view_restore_session_state(WebKitWebView* webView, WebKitWebViewSessionState* state) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + g_return_if_fail(state); + + getPage(webView)->restoreFromSessionState(webkitWebViewSessionStateGetSessionState(state), false); +} |