f99c76318b09c38e9dfcbf4dd8c098bd4f0f252d
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / gtk / WebKitWebView.cpp
1 /*
2  * Copyright (C) 2011 Igalia S.L.
3  * Portions Copyright (c) 2011 Motorola Mobility, Inc.  All rights reserved.
4  * Copyright (C) 2014 Collabora Ltd.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "WebKitWebView.h"
24
25 #include "APIData.h"
26 #include "APISerializedScriptValue.h"
27 #include "ImageOptions.h"
28 #include "WebCertificateInfo.h"
29 #include "WebContextMenuItem.h"
30 #include "WebContextMenuItemData.h"
31 #include "WebKitAuthenticationDialog.h"
32 #include "WebKitAuthenticationRequestPrivate.h"
33 #include "WebKitBackForwardListPrivate.h"
34 #include "WebKitContextMenuClient.h"
35 #include "WebKitContextMenuItemPrivate.h"
36 #include "WebKitContextMenuPrivate.h"
37 #include "WebKitDownloadPrivate.h"
38 #include "WebKitEditorStatePrivate.h"
39 #include "WebKitEnumTypes.h"
40 #include "WebKitError.h"
41 #include "WebKitFaviconDatabasePrivate.h"
42 #include "WebKitFormClient.h"
43 #include "WebKitFullscreenClient.h"
44 #include "WebKitHitTestResultPrivate.h"
45 #include "WebKitInstallMissingMediaPluginsPermissionRequestPrivate.h"
46 #include "WebKitJavascriptResultPrivate.h"
47 #include "WebKitLoaderClient.h"
48 #include "WebKitMarshal.h"
49 #include "WebKitNotificationPrivate.h"
50 #include "WebKitPolicyClient.h"
51 #include "WebKitPrintOperationPrivate.h"
52 #include "WebKitPrivate.h"
53 #include "WebKitResponsePolicyDecision.h"
54 #include "WebKitScriptDialogPrivate.h"
55 #include "WebKitSettingsPrivate.h"
56 #include "WebKitUIClient.h"
57 #include "WebKitURIRequestPrivate.h"
58 #include "WebKitURIResponsePrivate.h"
59 #include "WebKitWebContextPrivate.h"
60 #include "WebKitWebInspectorPrivate.h"
61 #include "WebKitWebResourcePrivate.h"
62 #include "WebKitWebViewBasePrivate.h"
63 #include "WebKitWebViewPrivate.h"
64 #include "WebKitWindowPropertiesPrivate.h"
65 #include <JavaScriptCore/APICast.h>
66 #include <WebCore/CertificateInfo.h>
67 #include <WebCore/GUniquePtrGtk.h>
68 #include <WebCore/GUniquePtrSoup.h>
69 #include <WebCore/GtkUtilities.h>
70 #include <WebCore/RefPtrCairo.h>
71 #include <glib/gi18n-lib.h>
72 #include <wtf/glib/GRefPtr.h>
73 #include <wtf/text/CString.h>
74
75 #if USE(LIBNOTIFY)
76 #include <libnotify/notify.h>
77 #endif
78
79 using namespace WebKit;
80 using namespace WebCore;
81
82 /**
83  * SECTION: WebKitWebView
84  * @Short_description: The central class of the WebKit2GTK+ API
85  * @Title: WebKitWebView
86  *
87  * #WebKitWebView is the central class of the WebKit2GTK+ API. It is
88  * responsible for managing the drawing of the content and forwarding
89  * of events. You can load any URI into the #WebKitWebView or a data
90  * string. With #WebKitSettings you can control various aspects of the
91  * rendering and loading of the content.
92  *
93  * Note that #WebKitWebView is scrollable by itself, so you don't need
94  * to embed it in a #GtkScrolledWindow.
95  */
96
97 enum {
98     LOAD_CHANGED,
99     LOAD_FAILED,
100     LOAD_FAILED_WITH_TLS_ERRORS,
101
102     CREATE,
103     READY_TO_SHOW,
104     RUN_AS_MODAL,
105     CLOSE,
106
107     SCRIPT_DIALOG,
108
109     DECIDE_POLICY,
110     PERMISSION_REQUEST,
111
112     MOUSE_TARGET_CHANGED,
113
114     PRINT,
115
116     RESOURCE_LOAD_STARTED,
117
118     ENTER_FULLSCREEN,
119     LEAVE_FULLSCREEN,
120
121     RUN_FILE_CHOOSER,
122
123     CONTEXT_MENU,
124     CONTEXT_MENU_DISMISSED,
125
126     SUBMIT_FORM,
127
128     INSECURE_CONTENT_DETECTED,
129
130     WEB_PROCESS_CRASHED,
131
132     AUTHENTICATE,
133
134     SHOW_NOTIFICATION,
135
136     RUN_COLOR_CHOOSER,
137
138     LAST_SIGNAL
139 };
140
141 enum {
142     PROP_0,
143
144     PROP_WEB_CONTEXT,
145     PROP_RELATED_VIEW,
146     PROP_SETTINGS,
147     PROP_USER_CONTENT_MANAGER,
148     PROP_TITLE,
149     PROP_ESTIMATED_LOAD_PROGRESS,
150     PROP_FAVICON,
151     PROP_URI,
152     PROP_ZOOM_LEVEL,
153     PROP_IS_LOADING,
154     PROP_IS_PLAYING_AUDIO,
155     PROP_EDITABLE
156 };
157
158 typedef HashMap<uint64_t, GRefPtr<WebKitWebResource> > LoadingResourcesMap;
159 typedef HashMap<uint64_t, GRefPtr<GTask> > SnapshotResultsMap;
160
161 class PageLoadStateObserver;
162
163 struct _WebKitWebViewPrivate {
164     ~_WebKitWebViewPrivate()
165     {
166         if (javascriptGlobalContext)
167             JSGlobalContextRelease(javascriptGlobalContext);
168
169         // For modal dialogs, make sure the main loop is stopped when finalizing the webView.
170         if (modalLoop && g_main_loop_is_running(modalLoop.get()))
171             g_main_loop_quit(modalLoop.get());
172     }
173
174     WebKitWebView* relatedView;
175     CString title;
176     CString customTextEncoding;
177     CString activeURI;
178     bool isLoading;
179
180     std::unique_ptr<PageLoadStateObserver> loadObserver;
181     bool waitingForMainResource;
182     unsigned long mainResourceResponseHandlerID;
183     WebKitLoadEvent lastDelayedEvent;
184
185     GRefPtr<WebKitBackForwardList> backForwardList;
186     GRefPtr<WebKitSettings> settings;
187     GRefPtr<WebKitUserContentManager> userContentManager;
188     GRefPtr<WebKitWebContext> context;
189     GRefPtr<WebKitWindowProperties> windowProperties;
190     GRefPtr<WebKitEditorState> editorState;
191
192     GRefPtr<GMainLoop> modalLoop;
193
194     GRefPtr<WebKitHitTestResult> mouseTargetHitTestResult;
195     unsigned mouseTargetModifiers;
196
197     GRefPtr<WebKitFindController> findController;
198     JSGlobalContextRef javascriptGlobalContext;
199
200     GRefPtr<WebKitWebResource> mainResource;
201     LoadingResourcesMap loadingResourcesMap;
202
203     GRefPtr<WebKitWebInspector> inspector;
204
205     RefPtr<cairo_surface_t> favicon;
206     GRefPtr<GCancellable> faviconCancellable;
207     CString faviconURI;
208     unsigned long faviconChangedHandlerID;
209
210     SnapshotResultsMap snapshotResultsMap;
211     GRefPtr<WebKitAuthenticationRequest> authenticationRequest;
212
213 };
214
215 static guint signals[LAST_SIGNAL] = { 0, };
216
217 WEBKIT_DEFINE_TYPE(WebKitWebView, webkit_web_view, WEBKIT_TYPE_WEB_VIEW_BASE)
218
219 static inline WebPageProxy* getPage(WebKitWebView* webView)
220 {
221     return webkitWebViewBaseGetPage(reinterpret_cast<WebKitWebViewBase*>(webView));
222 }
223
224 static void webkitWebViewSetIsLoading(WebKitWebView* webView, bool isLoading)
225 {
226     if (webView->priv->isLoading == isLoading)
227         return;
228
229     webView->priv->isLoading = isLoading;
230     g_object_notify(G_OBJECT(webView), "is-loading");
231 }
232
233 void webkitWebViewIsPlayingAudioChanged(WebKitWebView* webView)
234 {
235     g_object_notify(G_OBJECT(webView), "is-playing-audio");
236 }
237
238 class PageLoadStateObserver final : public PageLoadState::Observer {
239 public:
240     PageLoadStateObserver(WebKitWebView* webView)
241         : m_webView(webView)
242     {
243     }
244
245 private:
246     virtual void willChangeIsLoading() override
247     {
248         g_object_freeze_notify(G_OBJECT(m_webView));
249     }
250     virtual void didChangeIsLoading() override
251     {
252         if (m_webView->priv->waitingForMainResource) {
253             // The actual load has finished but we haven't emitted the delayed load events yet, so we are still loading.
254             g_object_thaw_notify(G_OBJECT(m_webView));
255             return;
256         }
257         webkitWebViewSetIsLoading(m_webView, getPage(m_webView)->pageLoadState().isLoading());
258         g_object_thaw_notify(G_OBJECT(m_webView));
259     }
260
261     virtual void willChangeTitle() override
262     {
263         g_object_freeze_notify(G_OBJECT(m_webView));
264     }
265     virtual void didChangeTitle() override
266     {
267         m_webView->priv->title = getPage(m_webView)->pageLoadState().title().utf8();
268         g_object_notify(G_OBJECT(m_webView), "title");
269         g_object_thaw_notify(G_OBJECT(m_webView));
270     }
271
272     virtual void willChangeActiveURL() override
273     {
274         g_object_freeze_notify(G_OBJECT(m_webView));
275     }
276     virtual void didChangeActiveURL() override
277     {
278         m_webView->priv->activeURI = getPage(m_webView)->pageLoadState().activeURL().utf8();
279         g_object_notify(G_OBJECT(m_webView), "uri");
280         g_object_thaw_notify(G_OBJECT(m_webView));
281     }
282
283     virtual void willChangeHasOnlySecureContent() override { }
284     virtual void didChangeHasOnlySecureContent() override { }
285
286     virtual void willChangeEstimatedProgress() override
287     {
288         g_object_freeze_notify(G_OBJECT(m_webView));
289     }
290     virtual void didChangeEstimatedProgress() override
291     {
292         g_object_notify(G_OBJECT(m_webView), "estimated-load-progress");
293         g_object_thaw_notify(G_OBJECT(m_webView));
294     }
295
296     virtual void willChangeCanGoBack() override { }
297     virtual void didChangeCanGoBack() override { }
298     virtual void willChangeCanGoForward() override { }
299     virtual void didChangeCanGoForward() override { }
300     virtual void willChangeNetworkRequestsInProgress() override { }
301     virtual void didChangeNetworkRequestsInProgress() override { }
302     virtual void willChangeCertificateInfo() override { }
303     virtual void didChangeCertificateInfo() override { }
304
305     WebKitWebView* m_webView;
306 };
307
308 static gboolean webkitWebViewLoadFail(WebKitWebView* webView, WebKitLoadEvent, const char* failingURI, GError* error)
309 {
310     if (g_error_matches(error, WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_CANCELLED)
311         || g_error_matches(error, WEBKIT_POLICY_ERROR, WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE)
312         || g_error_matches(error, WEBKIT_PLUGIN_ERROR, WEBKIT_PLUGIN_ERROR_WILL_HANDLE_LOAD))
313         return FALSE;
314
315     GUniquePtr<char> htmlString(g_strdup_printf("<html><body>%s</body></html>", error->message));
316     webkit_web_view_load_alternate_html(webView, htmlString.get(), failingURI, 0);
317
318     return TRUE;
319 }
320
321 static GtkWidget* webkitWebViewCreate(WebKitWebView*, WebKitNavigationAction*)
322 {
323     return nullptr;
324 }
325
326 static GtkWidget* webkitWebViewCreateJavaScriptDialog(WebKitWebView* webView, GtkMessageType type, GtkButtonsType buttons, int defaultResponse, const char* message)
327 {
328     GtkWidget* parent = gtk_widget_get_toplevel(GTK_WIDGET(webView));
329     GtkWidget* dialog = gtk_message_dialog_new(widgetIsOnscreenToplevelWindow(parent) ? GTK_WINDOW(parent) : 0,
330                                                GTK_DIALOG_DESTROY_WITH_PARENT, type, buttons, "%s", message);
331     GUniquePtr<char> title(g_strdup_printf("JavaScript - %s", webkit_web_view_get_uri(webView)));
332     gtk_window_set_title(GTK_WINDOW(dialog), title.get());
333     gtk_dialog_set_default_response(GTK_DIALOG(dialog), defaultResponse);
334
335     return dialog;
336 }
337
338 static gboolean webkitWebViewScriptDialog(WebKitWebView* webView, WebKitScriptDialog* scriptDialog)
339 {
340     GtkWidget* dialog = 0;
341
342     switch (scriptDialog->type) {
343     case WEBKIT_SCRIPT_DIALOG_ALERT:
344         dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, GTK_RESPONSE_CLOSE, scriptDialog->message.data());
345         gtk_dialog_run(GTK_DIALOG(dialog));
346         break;
347     case WEBKIT_SCRIPT_DIALOG_CONFIRM:
348         dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, scriptDialog->message.data());
349         scriptDialog->confirmed = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK;
350         break;
351     case WEBKIT_SCRIPT_DIALOG_PROMPT:
352         dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, scriptDialog->message.data());
353         GtkWidget* entry = gtk_entry_new();
354         gtk_entry_set_text(GTK_ENTRY(entry), scriptDialog->defaultText.data());
355         gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), entry);
356         gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
357         gtk_widget_show(entry);
358         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
359             scriptDialog->text = gtk_entry_get_text(GTK_ENTRY(entry));
360         break;
361     }
362
363     gtk_widget_destroy(dialog);
364
365     return TRUE;
366 }
367
368 static gboolean webkitWebViewDecidePolicy(WebKitWebView*, WebKitPolicyDecision* decision, WebKitPolicyDecisionType decisionType)
369 {
370     if (decisionType != WEBKIT_POLICY_DECISION_TYPE_RESPONSE) {
371         webkit_policy_decision_use(decision);
372         return TRUE;
373     }
374
375     WebKitURIResponse* response = webkit_response_policy_decision_get_response(WEBKIT_RESPONSE_POLICY_DECISION(decision));
376     const ResourceResponse& resourceResponse = webkitURIResponseGetResourceResponse(response);
377     if (resourceResponse.isAttachment()) {
378         webkit_policy_decision_download(decision);
379         return TRUE;
380     }
381
382     if (webkit_response_policy_decision_is_mime_type_supported(WEBKIT_RESPONSE_POLICY_DECISION(decision)))
383         webkit_policy_decision_use(decision);
384     else
385         webkit_policy_decision_ignore(decision);
386
387     return TRUE;
388 }
389
390 static gboolean webkitWebViewPermissionRequest(WebKitWebView*, WebKitPermissionRequest* request)
391 {
392     webkit_permission_request_deny(request);
393     return TRUE;
394 }
395
396 static void allowModalDialogsChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
397 {
398     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
399     if (!page)
400         return;
401     getPage(webView)->setCanRunModal(webkit_settings_get_allow_modal_dialogs(settings));
402 }
403
404 static void zoomTextOnlyChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
405 {
406     WebPageProxy* page = getPage(webView);
407     gboolean zoomTextOnly = webkit_settings_get_zoom_text_only(settings);
408     gdouble pageZoomLevel = zoomTextOnly ? 1 : page->textZoomFactor();
409     gdouble textZoomLevel = zoomTextOnly ? page->pageZoomFactor() : 1;
410     page->setPageAndTextZoomFactors(pageZoomLevel, textZoomLevel);
411 }
412
413 static void userAgentChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
414 {
415     getPage(webView)->setCustomUserAgent(String::fromUTF8(webkit_settings_get_user_agent(settings)));
416 }
417
418 static void webkitWebViewUpdateFavicon(WebKitWebView* webView, cairo_surface_t* favicon)
419 {
420     WebKitWebViewPrivate* priv = webView->priv;
421     if (priv->favicon.get() == favicon)
422         return;
423
424     priv->favicon = favicon;
425     g_object_notify(G_OBJECT(webView), "favicon");
426 }
427
428 static void webkitWebViewCancelFaviconRequest(WebKitWebView* webView)
429 {
430     if (!webView->priv->faviconCancellable)
431         return;
432
433     g_cancellable_cancel(webView->priv->faviconCancellable.get());
434     webView->priv->faviconCancellable = 0;
435 }
436
437 static void gotFaviconCallback(GObject* object, GAsyncResult* result, gpointer userData)
438 {
439     GUniqueOutPtr<GError> error;
440     RefPtr<cairo_surface_t> favicon = adoptRef(webkit_favicon_database_get_favicon_finish(WEBKIT_FAVICON_DATABASE(object), result, &error.outPtr()));
441     if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
442         return;
443
444     WebKitWebView* webView = WEBKIT_WEB_VIEW(userData);
445     webkitWebViewUpdateFavicon(webView, favicon.get());
446     webView->priv->faviconCancellable = 0;
447 }
448
449 static void webkitWebViewRequestFavicon(WebKitWebView* webView)
450 {
451     webkitWebViewCancelFaviconRequest(webView);
452
453     WebKitWebViewPrivate* priv = webView->priv;
454     priv->faviconCancellable = adoptGRef(g_cancellable_new());
455     WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context.get());
456     webkit_favicon_database_get_favicon(database, priv->activeURI.data(), priv->faviconCancellable.get(), gotFaviconCallback, webView);
457 }
458
459 static void webkitWebViewUpdateFaviconURI(WebKitWebView* webView, const char* faviconURI)
460 {
461     if (webView->priv->faviconURI == faviconURI)
462         return;
463
464     webView->priv->faviconURI = faviconURI;
465     webkitWebViewRequestFavicon(webView);
466 }
467
468 static void faviconChangedCallback(WebKitFaviconDatabase*, const char* pageURI, const char* faviconURI, WebKitWebView* webView)
469 {
470     if (webView->priv->activeURI != pageURI)
471         return;
472
473     webkitWebViewUpdateFaviconURI(webView, faviconURI);
474 }
475
476 static void webkitWebViewUpdateSettings(WebKitWebView* webView)
477 {
478     // The "settings" property is set on construction, and in that
479     // case webkit_web_view_set_settings() will be called *before* the
480     // WebPageProxy has been created so we should do an early return.
481     WebPageProxy* page = getPage(webView);
482     if (!page)
483         return;
484
485     WebKitSettings* settings = webView->priv->settings.get();
486     page->setPreferences(*webkitSettingsGetPreferences(settings));
487     page->setCanRunModal(webkit_settings_get_allow_modal_dialogs(settings));
488     page->setCustomUserAgent(String::fromUTF8(webkit_settings_get_user_agent(settings)));
489
490     g_signal_connect(settings, "notify::allow-modal-dialogs", G_CALLBACK(allowModalDialogsChanged), webView);
491     g_signal_connect(settings, "notify::zoom-text-only", G_CALLBACK(zoomTextOnlyChanged), webView);
492     g_signal_connect(settings, "notify::user-agent", G_CALLBACK(userAgentChanged), webView);
493 }
494
495 static void webkitWebViewDisconnectSettingsSignalHandlers(WebKitWebView* webView)
496 {
497     WebKitSettings* settings = webView->priv->settings.get();
498     g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(allowModalDialogsChanged), webView);
499     g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(zoomTextOnlyChanged), webView);
500     g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(userAgentChanged), webView);
501 }
502
503 static void webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(WebKitWebView* webView)
504 {
505     WebKitWebViewPrivate* priv = webView->priv;
506     if (priv->mainResourceResponseHandlerID)
507         g_signal_handler_disconnect(priv->mainResource.get(), priv->mainResourceResponseHandlerID);
508     priv->mainResourceResponseHandlerID = 0;
509 }
510
511 static void webkitWebViewWatchForChangesInFavicon(WebKitWebView* webView)
512 {
513     WebKitWebViewPrivate* priv = webView->priv;
514     if (priv->faviconChangedHandlerID)
515         return;
516
517     WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context.get());
518     priv->faviconChangedHandlerID = g_signal_connect(database, "favicon-changed", G_CALLBACK(faviconChangedCallback), webView);
519 }
520
521 static void webkitWebViewDisconnectFaviconDatabaseSignalHandlers(WebKitWebView* webView)
522 {
523     WebKitWebViewPrivate* priv = webView->priv;
524     if (priv->faviconChangedHandlerID)
525         g_signal_handler_disconnect(webkit_web_context_get_favicon_database(priv->context.get()), priv->faviconChangedHandlerID);
526     priv->faviconChangedHandlerID = 0;
527 }
528
529 static gboolean webkitWebViewAuthenticate(WebKitWebView* webView, WebKitAuthenticationRequest* request)
530 {
531     CredentialStorageMode credentialStorageMode = webkit_authentication_request_can_save_credentials(request) ? AllowPersistentStorage : DisallowPersistentStorage;
532     webkitWebViewBaseAddAuthenticationDialog(WEBKIT_WEB_VIEW_BASE(webView), webkitAuthenticationDialogNew(request, credentialStorageMode));
533
534     return TRUE;
535 }
536
537 static void fileChooserDialogResponseCallback(GtkDialog* dialog, gint responseID, WebKitFileChooserRequest* request)
538 {
539     GRefPtr<WebKitFileChooserRequest> adoptedRequest = adoptGRef(request);
540     if (responseID == GTK_RESPONSE_ACCEPT) {
541         GUniquePtr<GSList> filesList(gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)));
542         GRefPtr<GPtrArray> filesArray = adoptGRef(g_ptr_array_new());
543         for (GSList* file = filesList.get(); file; file = g_slist_next(file))
544             g_ptr_array_add(filesArray.get(), file->data);
545         g_ptr_array_add(filesArray.get(), 0);
546         webkit_file_chooser_request_select_files(adoptedRequest.get(), reinterpret_cast<const gchar* const*>(filesArray->pdata));
547     } else
548         webkit_file_chooser_request_cancel(adoptedRequest.get());
549
550     gtk_widget_destroy(GTK_WIDGET(dialog));
551 }
552
553 static gboolean webkitWebViewRunFileChooser(WebKitWebView* webView, WebKitFileChooserRequest* request)
554 {
555     GtkWidget* toplevel = gtk_widget_get_toplevel(GTK_WIDGET(webView));
556     if (!widgetIsOnscreenToplevelWindow(toplevel))
557         toplevel = 0;
558
559     gboolean allowsMultipleSelection = webkit_file_chooser_request_get_select_multiple(request);
560     GtkWidget* dialog = gtk_file_chooser_dialog_new(allowsMultipleSelection ? _("Select Files") : _("Select File"),
561                                                     toplevel ? GTK_WINDOW(toplevel) : 0,
562                                                     GTK_FILE_CHOOSER_ACTION_OPEN,
563                                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
564                                                     GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
565                                                     NULL);
566
567     if (GtkFileFilter* filter = webkit_file_chooser_request_get_mime_types_filter(request))
568         gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
569     gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), allowsMultipleSelection);
570
571     if (const gchar* const* selectedFiles = webkit_file_chooser_request_get_selected_files(request))
572         gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), selectedFiles[0]);
573
574     g_signal_connect(dialog, "response", G_CALLBACK(fileChooserDialogResponseCallback), g_object_ref(request));
575     gtk_widget_show(dialog);
576
577     return TRUE;
578 }
579
580 static void webkitWebViewHandleDownloadRequest(WebKitWebViewBase* webViewBase, DownloadProxy* downloadProxy)
581 {
582     GRefPtr<WebKitDownload> download = webkitWebContextGetOrCreateDownload(downloadProxy);
583     webkitDownloadSetWebView(download.get(), WEBKIT_WEB_VIEW(webViewBase));
584 }
585
586 #if USE(LIBNOTIFY)
587 static const char* gNotifyNotificationID = "wk-notify-notification";
588
589 static void notifyNotificationClosed(NotifyNotification*, WebKitNotification* webNotification)
590 {
591     g_object_set_data(G_OBJECT(webNotification), gNotifyNotificationID, nullptr);
592     webkit_notification_close(webNotification);
593 }
594
595 static void webNotificationClosed(WebKitNotification* webNotification)
596 {
597     NotifyNotification* notification = NOTIFY_NOTIFICATION(g_object_get_data(G_OBJECT(webNotification), gNotifyNotificationID));
598     if (!notification)
599         return;
600
601     notify_notification_close(notification, nullptr);
602     g_object_set_data(G_OBJECT(webNotification), gNotifyNotificationID, nullptr);
603 }
604 #endif // USE(LIBNOTIFY)
605
606 static gboolean webkitWebViewShowNotification(WebKitWebView*, WebKitNotification* webNotification)
607 {
608 #if USE(LIBNOTIFY)
609     if (!notify_is_initted())
610         notify_init(g_get_prgname());
611
612     NotifyNotification* notification = NOTIFY_NOTIFICATION(g_object_get_data(G_OBJECT(webNotification), gNotifyNotificationID));
613     if (!notification) {
614         notification = notify_notification_new(webkit_notification_get_title(webNotification),
615             webkit_notification_get_body(webNotification), nullptr);
616
617         g_signal_connect_object(notification, "closed", G_CALLBACK(notifyNotificationClosed), webNotification, static_cast<GConnectFlags>(0));
618         g_signal_connect(webNotification, "closed", G_CALLBACK(webNotificationClosed), nullptr);
619         g_object_set_data_full(G_OBJECT(webNotification), gNotifyNotificationID, notification, static_cast<GDestroyNotify>(g_object_unref));
620     } else {
621         notify_notification_update(notification, webkit_notification_get_title(webNotification),
622             webkit_notification_get_body(webNotification), nullptr);
623     }
624
625     notify_notification_show(notification, nullptr);
626     return TRUE;
627 #else
628     UNUSED_PARAM(webNotification);
629     return FALSE;
630 #endif
631 }
632
633 static void webkitWebViewConstructed(GObject* object)
634 {
635     G_OBJECT_CLASS(webkit_web_view_parent_class)->constructed(object);
636
637     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
638     WebKitWebViewPrivate* priv = webView->priv;
639     if (priv->relatedView)
640         priv->context = webkit_web_view_get_context(priv->relatedView);
641     else if (!priv->context)
642         priv->context = webkit_web_context_get_default();
643     if (!priv->settings)
644         priv->settings = adoptGRef(webkit_settings_new());
645
646     webkitWebContextCreatePageForWebView(priv->context.get(), webView, priv->userContentManager.get(), priv->relatedView);
647
648     priv->loadObserver = std::make_unique<PageLoadStateObserver>(webView);
649     getPage(webView)->pageLoadState().addObserver(*priv->loadObserver);
650
651     // The related view is only valid during the construction.
652     priv->relatedView = nullptr;
653
654     webkitWebViewBaseSetDownloadRequestHandler(WEBKIT_WEB_VIEW_BASE(webView), webkitWebViewHandleDownloadRequest);
655
656     attachLoaderClientToView(webView);
657     attachUIClientToView(webView);
658     attachPolicyClientToView(webView);
659     attachFullScreenClientToView(webView);
660     attachContextMenuClientToView(webView);
661     attachFormClientToView(webView);
662
663     // This needs to be after attachUIClientToView() because WebPageProxy::setUIClient() calls setCanRunModal() with true.
664     // See https://bugs.webkit.org/show_bug.cgi?id=135412.
665     webkitWebViewUpdateSettings(webView);
666
667     priv->backForwardList = adoptGRef(webkitBackForwardListCreate(&getPage(webView)->backForwardList()));
668     priv->windowProperties = adoptGRef(webkitWindowPropertiesCreate());
669 }
670
671 static void webkitWebViewSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* paramSpec)
672 {
673     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
674
675     switch (propId) {
676     case PROP_WEB_CONTEXT: {
677         gpointer webContext = g_value_get_object(value);
678         webView->priv->context = webContext ? WEBKIT_WEB_CONTEXT(webContext) : nullptr;
679         break;
680     }
681     case PROP_RELATED_VIEW: {
682         gpointer relatedView = g_value_get_object(value);
683         webView->priv->relatedView = relatedView ? WEBKIT_WEB_VIEW(relatedView) : nullptr;
684         break;
685     }
686     case PROP_SETTINGS: {
687         if (gpointer settings = g_value_get_object(value))
688             webkit_web_view_set_settings(webView, WEBKIT_SETTINGS(settings));
689         break;
690     }
691     case PROP_USER_CONTENT_MANAGER: {
692         gpointer userContentManager = g_value_get_object(value);
693         webView->priv->userContentManager = userContentManager ? WEBKIT_USER_CONTENT_MANAGER(userContentManager) : nullptr;
694         break;
695     }
696     case PROP_ZOOM_LEVEL:
697         webkit_web_view_set_zoom_level(webView, g_value_get_double(value));
698         break;
699     case PROP_EDITABLE:
700         webkit_web_view_set_editable(webView, g_value_get_boolean(value));
701         break;
702     default:
703         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
704     }
705 }
706
707 static void webkitWebViewGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
708 {
709     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
710
711     switch (propId) {
712     case PROP_WEB_CONTEXT:
713         g_value_set_object(value, webView->priv->context.get());
714         break;
715     case PROP_SETTINGS:
716         g_value_set_object(value, webkit_web_view_get_settings(webView));
717         break;
718     case PROP_USER_CONTENT_MANAGER:
719         g_value_set_object(value, webkit_web_view_get_user_content_manager(webView));
720         break;
721     case PROP_TITLE:
722         g_value_set_string(value, webView->priv->title.data());
723         break;
724     case PROP_ESTIMATED_LOAD_PROGRESS:
725         g_value_set_double(value, webkit_web_view_get_estimated_load_progress(webView));
726         break;
727     case PROP_FAVICON:
728         g_value_set_pointer(value, webkit_web_view_get_favicon(webView));
729         break;
730     case PROP_URI:
731         g_value_set_string(value, webkit_web_view_get_uri(webView));
732         break;
733     case PROP_ZOOM_LEVEL:
734         g_value_set_double(value, webkit_web_view_get_zoom_level(webView));
735         break;
736     case PROP_IS_LOADING:
737         g_value_set_boolean(value, webkit_web_view_is_loading(webView));
738         break;
739     case PROP_IS_PLAYING_AUDIO:
740         g_value_set_boolean(value, webkit_web_view_is_playing_audio(webView));
741         break;
742     case PROP_EDITABLE:
743         g_value_set_boolean(value, webkit_web_view_is_editable(webView));
744         break;
745     default:
746         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
747     }
748 }
749
750 static void webkitWebViewDispose(GObject* object)
751 {
752     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
753     webkitWebViewCancelFaviconRequest(webView);
754     webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
755     webkitWebViewDisconnectSettingsSignalHandlers(webView);
756     webkitWebViewDisconnectFaviconDatabaseSignalHandlers(webView);
757
758     if (webView->priv->loadObserver) {
759         getPage(webView)->pageLoadState().removeObserver(*webView->priv->loadObserver);
760         webView->priv->loadObserver.reset();
761     }
762
763     webkitWebContextWebViewDestroyed(webView->priv->context.get(), webView);
764
765     G_OBJECT_CLASS(webkit_web_view_parent_class)->dispose(object);
766 }
767
768 static gboolean webkitWebViewAccumulatorObjectHandled(GSignalInvocationHint*, GValue* returnValue, const GValue* handlerReturn, gpointer)
769 {
770     void* object = g_value_get_object(handlerReturn);
771     if (object)
772         g_value_set_object(returnValue, object);
773
774     return !object;
775 }
776
777 static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass)
778 {
779     GObjectClass* gObjectClass = G_OBJECT_CLASS(webViewClass);
780
781     gObjectClass->constructed = webkitWebViewConstructed;
782     gObjectClass->set_property = webkitWebViewSetProperty;
783     gObjectClass->get_property = webkitWebViewGetProperty;
784     gObjectClass->dispose = webkitWebViewDispose;
785
786     webViewClass->load_failed = webkitWebViewLoadFail;
787     webViewClass->create = webkitWebViewCreate;
788     webViewClass->script_dialog = webkitWebViewScriptDialog;
789     webViewClass->decide_policy = webkitWebViewDecidePolicy;
790     webViewClass->permission_request = webkitWebViewPermissionRequest;
791     webViewClass->run_file_chooser = webkitWebViewRunFileChooser;
792     webViewClass->authenticate = webkitWebViewAuthenticate;
793     webViewClass->show_notification = webkitWebViewShowNotification;
794
795     /**
796      * WebKitWebView:web-context:
797      *
798      * The #WebKitWebContext of the view.
799      */
800     g_object_class_install_property(gObjectClass,
801                                     PROP_WEB_CONTEXT,
802                                     g_param_spec_object("web-context",
803                                                         _("Web Context"),
804                                                         _("The web context for the view"),
805                                                         WEBKIT_TYPE_WEB_CONTEXT,
806                                                         static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
807     /**
808      * WebKitWebView:related-view:
809      *
810      * The related #WebKitWebView used when creating the view to share the
811      * same web process. This property is not readable because the related
812      * web view is only valid during the object construction.
813      *
814      * Since: 2.4
815      */
816     g_object_class_install_property(
817         gObjectClass,
818         PROP_RELATED_VIEW,
819         g_param_spec_object(
820             "related-view",
821             _("Related WebView"),
822             _("The related WebKitWebView used when creating the view to share the same web process"),
823             WEBKIT_TYPE_WEB_VIEW,
824             static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
825
826     /**
827      * WebKitWebView:settings:
828      *
829      * The #WebKitSettings of the view.
830      *
831      * Since: 2.6
832      */
833     g_object_class_install_property(
834         gObjectClass,
835         PROP_SETTINGS,
836         g_param_spec_object(
837             "settings",
838             _("WebView settings"),
839             _("The WebKitSettings of the view"),
840             WEBKIT_TYPE_SETTINGS,
841             static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT)));
842
843     /**
844      * WebKitWebView:user-content-manager:
845      *
846      * The #WebKitUserContentManager of the view.
847      *
848      * Since: 2.6
849      */
850     g_object_class_install_property(
851         gObjectClass,
852         PROP_USER_CONTENT_MANAGER,
853         g_param_spec_object(
854             "user-content-manager",
855             _("WebView user content manager"),
856             _("The WebKitUserContentManager of the view"),
857             WEBKIT_TYPE_USER_CONTENT_MANAGER,
858             static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
859
860     /**
861      * WebKitWebView:title:
862      *
863      * The main frame document title of this #WebKitWebView. If
864      * the title has not been received yet, it will be %NULL.
865      */
866     g_object_class_install_property(gObjectClass,
867                                     PROP_TITLE,
868                                     g_param_spec_string("title",
869                                                         _("Title"),
870                                                         _("Main frame document title"),
871                                                         0,
872                                                         WEBKIT_PARAM_READABLE));
873
874     /**
875      * WebKitWebView:estimated-load-progress:
876      *
877      * An estimate of the percent completion for the current loading operation.
878      * This value will range from 0.0 to 1.0 and, once a load completes,
879      * will remain at 1.0 until a new load starts, at which point it
880      * will be reset to 0.0.
881      * The value is an estimate based on the total number of bytes expected
882      * to be received for a document, including all its possible subresources
883      * and child documents.
884      */
885     g_object_class_install_property(gObjectClass,
886                                     PROP_ESTIMATED_LOAD_PROGRESS,
887                                     g_param_spec_double("estimated-load-progress",
888                                                         _("Estimated Load Progress"),
889                                                         _("An estimate of the percent completion for a document load"),
890                                                         0.0, 1.0, 0.0,
891                                                         WEBKIT_PARAM_READABLE));
892     /**
893      * WebKitWebView:favicon:
894      *
895      * The favicon currently associated to the #WebKitWebView.
896      * See webkit_web_view_get_favicon() for more details.
897      */
898     g_object_class_install_property(gObjectClass,
899                                     PROP_FAVICON,
900                                     g_param_spec_pointer("favicon",
901                                                          _("Favicon"),
902                                                          _("The favicon associated to the view, if any"),
903                                                          WEBKIT_PARAM_READABLE));
904     /**
905      * WebKitWebView:uri:
906      *
907      * The current active URI of the #WebKitWebView.
908      * See webkit_web_view_get_uri() for more details.
909      */
910     g_object_class_install_property(gObjectClass,
911                                     PROP_URI,
912                                     g_param_spec_string("uri",
913                                                         _("URI"),
914                                                         _("The current active URI of the view"),
915                                                         0,
916                                                         WEBKIT_PARAM_READABLE));
917
918     /**
919      * WebKitWebView:zoom-level:
920      *
921      * The zoom level of the #WebKitWebView content.
922      * See webkit_web_view_set_zoom_level() for more details.
923      */
924     g_object_class_install_property(
925         gObjectClass,
926         PROP_ZOOM_LEVEL,
927         g_param_spec_double(
928             "zoom-level",
929             _("Zoom level"),
930             _("The zoom level of the view content"),
931             0, G_MAXDOUBLE, 1,
932             WEBKIT_PARAM_READWRITE));
933
934     /**
935      * WebKitWebView:is-loading:
936      *
937      * Whether the #WebKitWebView is currently loading a page. This property becomes
938      * %TRUE as soon as a new load operation is requested and before the
939      * #WebKitWebView::load-changed signal is emitted with %WEBKIT_LOAD_STARTED and
940      * at that point the active URI is the requested one.
941      * When the load operation finishes the property is set to %FALSE before
942      * #WebKitWebView::load-changed is emitted with %WEBKIT_LOAD_FINISHED.
943      */
944     g_object_class_install_property(
945         gObjectClass,
946         PROP_IS_LOADING,
947         g_param_spec_boolean(
948             "is-loading",
949             _("Is Loading"),
950             _("Whether the view is loading a page"),
951             FALSE,
952             WEBKIT_PARAM_READABLE));
953
954     /**
955      * WebKitWebView:is-playing-audio:
956      *
957      * Whether the #WebKitWebView is currently playing audio from a page.
958      * This property becomes %TRUE as soon as web content starts playing any
959      * kind of audio. When a page is no longer playing any kind of sound,
960      * the property is set back to %FALSE.
961      *
962      * Since: 2.8
963      */
964     g_object_class_install_property(
965         gObjectClass,
966         PROP_IS_PLAYING_AUDIO,
967         g_param_spec_boolean(
968             "is-playing-audio",
969             "Is Playing Audio",
970             _("Whether the view is playing audio"),
971             FALSE,
972             WEBKIT_PARAM_READABLE));
973
974     /**
975      * WebKitWebView:editable:
976      *
977      * Whether the pages loaded inside #WebKitWebView are editable. For more
978      * information see webkit_web_view_set_editable().
979      *
980      * Since: 2.8
981      */
982     g_object_class_install_property(
983         gObjectClass,
984         PROP_EDITABLE,
985         g_param_spec_boolean(
986             "editable",
987             _("Editable"),
988             _("Whether the content can be modified by the user."),
989             FALSE,
990             WEBKIT_PARAM_READWRITE));
991
992     /**
993      * WebKitWebView::load-changed:
994      * @web_view: the #WebKitWebView on which the signal is emitted
995      * @load_event: the #WebKitLoadEvent
996      *
997      * Emitted when the a load operation in @web_view changes.
998      * The signal is always emitted with %WEBKIT_LOAD_STARTED when a
999      * new load request is made and %WEBKIT_LOAD_FINISHED when the load
1000      * finishes successfully or due to an error. When the ongoing load
1001      * operation fails #WebKitWebView::load-failed signal is emitted
1002      * before #WebKitWebView::load-changed is emitted with
1003      * %WEBKIT_LOAD_FINISHED.
1004      * If a redirection is received from the server, this signal is emitted
1005      * with %WEBKIT_LOAD_REDIRECTED after the initial emission with
1006      * %WEBKIT_LOAD_STARTED and before %WEBKIT_LOAD_COMMITTED.
1007      * When the page content starts arriving the signal is emitted with
1008      * %WEBKIT_LOAD_COMMITTED event.
1009      *
1010      * You can handle this signal and use a switch to track any ongoing
1011      * load operation.
1012      *
1013      * <informalexample><programlisting>
1014      * static void web_view_load_changed (WebKitWebView  *web_view,
1015      *                                    WebKitLoadEvent load_event,
1016      *                                    gpointer        user_data)
1017      * {
1018      *     switch (load_event) {
1019      *     case WEBKIT_LOAD_STARTED:
1020      *         /<!-- -->* New load, we have now a provisional URI *<!-- -->/
1021      *         provisional_uri = webkit_web_view_get_uri (web_view);
1022      *         /<!-- -->* Here we could start a spinner or update the
1023      *          <!-- -->* location bar with the provisional URI *<!-- -->/
1024      *         break;
1025      *     case WEBKIT_LOAD_REDIRECTED:
1026      *         redirected_uri = webkit_web_view_get_uri (web_view);
1027      *         break;
1028      *     case WEBKIT_LOAD_COMMITTED:
1029      *         /<!-- -->* The load is being performed. Current URI is
1030      *          <!-- -->* the final one and it won't change unless a new
1031      *          <!-- -->* load is requested or a navigation within the
1032      *          <!-- -->* same page is performed *<!-- -->/
1033      *         uri = webkit_web_view_get_uri (web_view);
1034      *         break;
1035      *     case WEBKIT_LOAD_FINISHED:
1036      *         /<!-- -->* Load finished, we can now stop the spinner *<!-- -->/
1037      *         break;
1038      *     }
1039      * }
1040      * </programlisting></informalexample>
1041      */
1042     signals[LOAD_CHANGED] =
1043         g_signal_new("load-changed",
1044                      G_TYPE_FROM_CLASS(webViewClass),
1045                      G_SIGNAL_RUN_LAST,
1046                      G_STRUCT_OFFSET(WebKitWebViewClass, load_changed),
1047                      0, 0,
1048                      g_cclosure_marshal_VOID__ENUM,
1049                      G_TYPE_NONE, 1,
1050                      WEBKIT_TYPE_LOAD_EVENT);
1051
1052     /**
1053      * WebKitWebView::load-failed:
1054      * @web_view: the #WebKitWebView on which the signal is emitted
1055      * @load_event: the #WebKitLoadEvent of the load operation
1056      * @failing_uri: the URI that failed to load
1057      * @error: the #GError that was triggered
1058      *
1059      * Emitted when an error occurs during a load operation.
1060      * If the error happened when starting to load data for a page
1061      * @load_event will be %WEBKIT_LOAD_STARTED. If it happened while
1062      * loading a committed data source @load_event will be %WEBKIT_LOAD_COMMITTED.
1063      * Since a load error causes the load operation to finish, the signal
1064      * WebKitWebView::load-changed will always be emitted with
1065      * %WEBKIT_LOAD_FINISHED event right after this one.
1066      *
1067      * By default, if the signal is not handled, a stock error page will be displayed.
1068      * You need to handle the signal if you want to provide your own error page.
1069      *
1070      * Returns: %TRUE to stop other handlers from being invoked for the event.
1071      *    %FALSE to propagate the event further.
1072      */
1073     signals[LOAD_FAILED] =
1074         g_signal_new("load-failed",
1075                      G_TYPE_FROM_CLASS(webViewClass),
1076                      G_SIGNAL_RUN_LAST,
1077                      G_STRUCT_OFFSET(WebKitWebViewClass, load_failed),
1078                      g_signal_accumulator_true_handled, 0,
1079                      webkit_marshal_BOOLEAN__ENUM_STRING_POINTER,
1080                      G_TYPE_BOOLEAN, 3,
1081                      WEBKIT_TYPE_LOAD_EVENT,
1082                      G_TYPE_STRING,
1083                      G_TYPE_POINTER);
1084
1085     /**
1086      * WebKitWebView::load-failed-with-tls-errors:
1087      * @web_view: the #WebKitWebView on which the signal is emitted
1088      * @failing_uri: the URI that failed to load
1089      * @certificate: a #GTlsCertificate
1090      * @errors: a #GTlsCertificateFlags with the verification status of @certificate
1091      *
1092      * Emitted when a TLS error occurs during a load operation.
1093      * To allow an exception for this @certificate
1094      * and the host of @failing_uri use webkit_web_context_allow_tls_certificate_for_host().
1095      *
1096      * To handle this signal asynchronously you should call g_object_ref() on @certificate
1097      * and return %TRUE.
1098      *
1099      * If %FALSE is returned, #WebKitWebView::load-failed will be emitted. The load
1100      * will finish regardless of the returned value.
1101      *
1102      * Returns: %TRUE to stop other handlers from being invoked for the event.
1103      *   %FALSE to propagate the event further.
1104      *
1105      * Since: 2.6
1106      */
1107     signals[LOAD_FAILED_WITH_TLS_ERRORS] =
1108         g_signal_new("load-failed-with-tls-errors",
1109             G_TYPE_FROM_CLASS(webViewClass),
1110             G_SIGNAL_RUN_LAST,
1111             G_STRUCT_OFFSET(WebKitWebViewClass, load_failed_with_tls_errors),
1112             g_signal_accumulator_true_handled, 0 /* accumulator data */,
1113             g_cclosure_marshal_generic,
1114             G_TYPE_BOOLEAN, 3,
1115             G_TYPE_STRING,
1116             G_TYPE_TLS_CERTIFICATE,
1117             G_TYPE_TLS_CERTIFICATE_FLAGS);
1118
1119     /**
1120      * WebKitWebView::create:
1121      * @web_view: the #WebKitWebView on which the signal is emitted
1122      * @navigation_action: a #WebKitNavigationAction
1123      *
1124      * Emitted when the creation of a new #WebKitWebView is requested.
1125      * If this signal is handled the signal handler should return the
1126      * newly created #WebKitWebView.
1127      *
1128      * The #WebKitNavigationAction parameter contains information about the
1129      * navigation action that triggered this signal.
1130      *
1131      * When using %WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES
1132      * process model, the new #WebKitWebView should be related to
1133      * @web_view to share the same web process, see webkit_web_view_new_with_related_view()
1134      * for more details.
1135      *
1136      * The new #WebKitWebView should not be displayed to the user
1137      * until the #WebKitWebView::ready-to-show signal is emitted.
1138      *
1139      * Returns: (transfer full): a newly allocated #WebKitWebView widget
1140      *    or %NULL to propagate the event further.
1141      */
1142     signals[CREATE] = g_signal_new(
1143         "create",
1144         G_TYPE_FROM_CLASS(webViewClass),
1145         G_SIGNAL_RUN_LAST,
1146         G_STRUCT_OFFSET(WebKitWebViewClass, create),
1147         webkitWebViewAccumulatorObjectHandled, 0,
1148         g_cclosure_marshal_generic,
1149         GTK_TYPE_WIDGET, 1,
1150         WEBKIT_TYPE_NAVIGATION_ACTION | G_SIGNAL_TYPE_STATIC_SCOPE);
1151
1152     /**
1153      * WebKitWebView::ready-to-show:
1154      * @web_view: the #WebKitWebView on which the signal is emitted
1155      *
1156      * Emitted after #WebKitWebView::create on the newly created #WebKitWebView
1157      * when it should be displayed to the user. When this signal is emitted
1158      * all the information about how the window should look, including
1159      * size, position, whether the location, status and scrollbars
1160      * should be displayed, is already set on the #WebKitWindowProperties
1161      * of @web_view. See also webkit_web_view_get_window_properties().
1162      */
1163     signals[READY_TO_SHOW] =
1164         g_signal_new("ready-to-show",
1165                      G_TYPE_FROM_CLASS(webViewClass),
1166                      G_SIGNAL_RUN_LAST,
1167                      G_STRUCT_OFFSET(WebKitWebViewClass, ready_to_show),
1168                      0, 0,
1169                      g_cclosure_marshal_VOID__VOID,
1170                      G_TYPE_NONE, 0);
1171
1172      /**
1173      * WebKitWebView::run-as-modal:
1174      * @web_view: the #WebKitWebView on which the signal is emitted
1175      *
1176      * Emitted after #WebKitWebView::ready-to-show on the newly
1177      * created #WebKitWebView when JavaScript code calls
1178      * <function>window.showModalDialog</function>. The purpose of
1179      * this signal is to allow the client application to prepare the
1180      * new view to behave as modal. Once the signal is emitted a new
1181      * mainloop will be run to block user interaction in the parent
1182      * #WebKitWebView until the new dialog is closed.
1183      */
1184     signals[RUN_AS_MODAL] =
1185             g_signal_new("run-as-modal",
1186                          G_TYPE_FROM_CLASS(webViewClass),
1187                          G_SIGNAL_RUN_LAST,
1188                          G_STRUCT_OFFSET(WebKitWebViewClass, run_as_modal),
1189                          0, 0,
1190                          g_cclosure_marshal_VOID__VOID,
1191                          G_TYPE_NONE, 0);
1192
1193     /**
1194      * WebKitWebView::close:
1195      * @webView: the #WebKitWebView on which the signal is emitted
1196      *
1197      * Emitted when closing a #WebKitWebView is requested. This occurs when a
1198      * call is made from JavaScript's <function>window.close</function> function.
1199      * It is the owner's responsibility to handle this signal to hide or
1200      * destroy the #WebKitWebView, if necessary.
1201      */
1202     signals[CLOSE] =
1203         g_signal_new("close",
1204                      G_TYPE_FROM_CLASS(webViewClass),
1205                      G_SIGNAL_RUN_LAST,
1206                      G_STRUCT_OFFSET(WebKitWebViewClass, close),
1207                      0, 0,
1208                      g_cclosure_marshal_VOID__VOID,
1209                      G_TYPE_NONE, 0);
1210
1211     /**
1212      * WebKitWebView::script-dialog:
1213      * @web_view: the #WebKitWebView on which the signal is emitted
1214      * @dialog: the #WebKitScriptDialog to show
1215      *
1216      * Emitted when JavaScript code calls <function>window.alert</function>,
1217      * <function>window.confirm</function> or <function>window.prompt</function>.
1218      * The @dialog parameter should be used to build the dialog.
1219      * If the signal is not handled a different dialog will be built and shown depending
1220      * on the dialog type:
1221      * <itemizedlist>
1222      * <listitem><para>
1223      *  %WEBKIT_SCRIPT_DIALOG_ALERT: message dialog with a single Close button.
1224      * </para></listitem>
1225      * <listitem><para>
1226      *  %WEBKIT_SCRIPT_DIALOG_CONFIRM: message dialog with OK and Cancel buttons.
1227      * </para></listitem>
1228      * <listitem><para>
1229      *  %WEBKIT_SCRIPT_DIALOG_PROMPT: message dialog with OK and Cancel buttons and
1230      *  a text entry with the default text.
1231      * </para></listitem>
1232      * </itemizedlist>
1233      *
1234      * Returns: %TRUE to stop other handlers from being invoked for the event.
1235      *    %FALSE to propagate the event further.
1236      */
1237     signals[SCRIPT_DIALOG] =
1238         g_signal_new("script-dialog",
1239                      G_TYPE_FROM_CLASS(webViewClass),
1240                      G_SIGNAL_RUN_LAST,
1241                      G_STRUCT_OFFSET(WebKitWebViewClass, script_dialog),
1242                      g_signal_accumulator_true_handled, 0,
1243                      webkit_marshal_BOOLEAN__BOXED,
1244                      G_TYPE_BOOLEAN, 1,
1245                      WEBKIT_TYPE_SCRIPT_DIALOG | G_SIGNAL_TYPE_STATIC_SCOPE);
1246
1247     /**
1248      * WebKitWebView::decide-policy:
1249      * @web_view: the #WebKitWebView on which the signal is emitted
1250      * @decision: the #WebKitPolicyDecision
1251      * @decision_type: a #WebKitPolicyDecisionType denoting the type of @decision
1252      *
1253      * This signal is emitted when WebKit is requesting the client to decide a policy
1254      * decision, such as whether to navigate to a page, open a new window or whether or
1255      * not to download a resource. The #WebKitNavigationPolicyDecision passed in the
1256      * @decision argument is a generic type, but should be casted to a more
1257      * specific type when making the decision. For example:
1258      *
1259      * <informalexample><programlisting>
1260      * static gboolean
1261      * decide_policy_cb (WebKitWebView *web_view,
1262      *                   WebKitPolicyDecision *decision,
1263      *                   WebKitPolicyDecisionType type)
1264      * {
1265      *     switch (type) {
1266      *     case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
1267      *         WebKitNavigationPolicyDecision *navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
1268      *         /<!-- -->* Make a policy decision here. *<!-- -->/
1269      *         break;
1270      *     case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
1271      *         WebKitNavigationPolicyDecision *navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
1272      *         /<!-- -->* Make a policy decision here. *<!-- -->/
1273      *         break;
1274      *     case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
1275      *         WebKitResponsePolicyDecision *response = WEBKIT_RESPONSE_POLICY_DECISION (decision);
1276      *         /<!-- -->* Make a policy decision here. *<!-- -->/
1277      *         break;
1278      *     default:
1279      *         /<!-- -->* Making no decision results in webkit_policy_decision_use(). *<!-- -->/
1280      *         return FALSE;
1281      *     }
1282      *     return TRUE;
1283      * }
1284      * </programlisting></informalexample>
1285      *
1286      * It is possible to make policy decision asynchronously, by simply calling g_object_ref()
1287      * on the @decision argument and returning %TRUE to block the default signal handler.
1288      * If the last reference is removed on a #WebKitPolicyDecision and no decision has been
1289      * made explicitly, webkit_policy_decision_use() will be the default policy decision. The
1290      * default signal handler will simply call webkit_policy_decision_use(). Only the first
1291      * policy decision chosen for a given #WebKitPolicyDecision will have any affect.
1292      *
1293      * Returns: %TRUE to stop other handlers from being invoked for the event.
1294      *   %FALSE to propagate the event further.
1295      *
1296      */
1297     signals[DECIDE_POLICY] =
1298         g_signal_new("decide-policy",
1299                      G_TYPE_FROM_CLASS(webViewClass),
1300                      G_SIGNAL_RUN_LAST,
1301                      G_STRUCT_OFFSET(WebKitWebViewClass, decide_policy),
1302                      g_signal_accumulator_true_handled, 0 /* accumulator data */,
1303                      webkit_marshal_BOOLEAN__OBJECT_ENUM,
1304                      G_TYPE_BOOLEAN, 2, /* number of parameters */
1305                      WEBKIT_TYPE_POLICY_DECISION,
1306                      WEBKIT_TYPE_POLICY_DECISION_TYPE);
1307
1308     /**
1309      * WebKitWebView::permission-request:
1310      * @web_view: the #WebKitWebView on which the signal is emitted
1311      * @request: the #WebKitPermissionRequest
1312      *
1313      * This signal is emitted when WebKit is requesting the client to
1314      * decide about a permission request, such as allowing the browser
1315      * to switch to fullscreen mode, sharing its location or similar
1316      * operations.
1317      *
1318      * A possible way to use this signal could be through a dialog
1319      * allowing the user decide what to do with the request:
1320      *
1321      * <informalexample><programlisting>
1322      * static gboolean permission_request_cb (WebKitWebView *web_view,
1323      *                                        WebKitPermissionRequest *request,
1324      *                                        GtkWindow *parent_window)
1325      * {
1326      *     GtkWidget *dialog = gtk_message_dialog_new (parent_window,
1327      *                                                 GTK_DIALOG_MODAL,
1328      *                                                 GTK_MESSAGE_QUESTION,
1329      *                                                 GTK_BUTTONS_YES_NO,
1330      *                                                 "Allow Permission Request?");
1331      *     gtk_widget_show (dialog);
1332      *     gint result = gtk_dialog_run (GTK_DIALOG (dialog));
1333      *
1334      *     switch (result) {
1335      *     case GTK_RESPONSE_YES:
1336      *         webkit_permission_request_allow (request);
1337      *         break;
1338      *     default:
1339      *         webkit_permission_request_deny (request);
1340      *         break;
1341      *     }
1342      *     gtk_widget_destroy (dialog);
1343      *
1344      *     return TRUE;
1345      * }
1346      * </programlisting></informalexample>
1347      *
1348      * It is possible to handle permission requests asynchronously, by
1349      * simply calling g_object_ref() on the @request argument and
1350      * returning %TRUE to block the default signal handler.  If the
1351      * last reference is removed on a #WebKitPermissionRequest and the
1352      * request has not been handled, webkit_permission_request_deny()
1353      * will be the default action.
1354      *
1355      * If the signal is not handled, the @request will be completed automatically
1356      * by the specific #WebKitPermissionRequest that could allow or deny it. Check the
1357      * documentation of classes implementing #WebKitPermissionRequest interface to know
1358      * their default action.
1359      *
1360      * Returns: %TRUE to stop other handlers from being invoked for the event.
1361      *   %FALSE to propagate the event further.
1362      *
1363      */
1364     signals[PERMISSION_REQUEST] =
1365         g_signal_new("permission-request",
1366                      G_TYPE_FROM_CLASS(webViewClass),
1367                      G_SIGNAL_RUN_LAST,
1368                      G_STRUCT_OFFSET(WebKitWebViewClass, permission_request),
1369                      g_signal_accumulator_true_handled, 0 /* accumulator data */,
1370                      webkit_marshal_BOOLEAN__OBJECT,
1371                      G_TYPE_BOOLEAN, 1, /* number of parameters */
1372                      WEBKIT_TYPE_PERMISSION_REQUEST);
1373     /**
1374      * WebKitWebView::mouse-target-changed:
1375      * @web_view: the #WebKitWebView on which the signal is emitted
1376      * @hit_test_result: a #WebKitHitTestResult
1377      * @modifiers: a bitmask of #GdkModifierType
1378      *
1379      * This signal is emitted when the mouse cursor moves over an
1380      * element such as a link, image or a media element. To determine
1381      * what type of element the mouse cursor is over, a Hit Test is performed
1382      * on the current mouse coordinates and the result is passed in the
1383      * @hit_test_result argument. The @modifiers argument is a bitmask of
1384      * #GdkModifierType flags indicating the state of modifier keys.
1385      * The signal is emitted again when the mouse is moved out of the
1386      * current element with a new @hit_test_result.
1387      */
1388      signals[MOUSE_TARGET_CHANGED] =
1389          g_signal_new("mouse-target-changed",
1390                       G_TYPE_FROM_CLASS(webViewClass),
1391                       G_SIGNAL_RUN_LAST,
1392                       G_STRUCT_OFFSET(WebKitWebViewClass, mouse_target_changed),
1393                       0, 0,
1394                       webkit_marshal_VOID__OBJECT_UINT,
1395                       G_TYPE_NONE, 2,
1396                       WEBKIT_TYPE_HIT_TEST_RESULT,
1397                       G_TYPE_UINT);
1398     /**
1399      * WebKitWebView::print:
1400      * @web_view: the #WebKitWebView on which the signal is emitted
1401      * @print_operation: the #WebKitPrintOperation that will handle the print request
1402      *
1403      * Emitted when printing is requested on @web_view, usually by a javascript call,
1404      * before the print dialog is shown. This signal can be used to set the initial
1405      * print settings and page setup of @print_operation to be used as default values in
1406      * the print dialog. You can call webkit_print_operation_set_print_settings() and
1407      * webkit_print_operation_set_page_setup() and then return %FALSE to propagate the
1408      * event so that the print dialog is shown.
1409      *
1410      * You can connect to this signal and return %TRUE to cancel the print operation
1411      * or implement your own print dialog.
1412      *
1413      * Returns: %TRUE to stop other handlers from being invoked for the event.
1414      *    %FALSE to propagate the event further.
1415      */
1416     signals[PRINT] =
1417         g_signal_new("print",
1418                      G_TYPE_FROM_CLASS(webViewClass),
1419                      G_SIGNAL_RUN_LAST,
1420                      G_STRUCT_OFFSET(WebKitWebViewClass, print),
1421                      g_signal_accumulator_true_handled, 0,
1422                      webkit_marshal_BOOLEAN__OBJECT,
1423                      G_TYPE_BOOLEAN, 1,
1424                      WEBKIT_TYPE_PRINT_OPERATION);
1425
1426     /**
1427      * WebKitWebView::resource-load-started:
1428      * @web_view: the #WebKitWebView on which the signal is emitted
1429      * @resource: a #WebKitWebResource
1430      * @request: a #WebKitURIRequest
1431      *
1432      * Emitted when a new resource is going to be loaded. The @request parameter
1433      * contains the #WebKitURIRequest that will be sent to the server.
1434      * You can monitor the load operation by connecting to the different signals
1435      * of @resource.
1436      */
1437     signals[RESOURCE_LOAD_STARTED] =
1438         g_signal_new("resource-load-started",
1439                      G_TYPE_FROM_CLASS(webViewClass),
1440                      G_SIGNAL_RUN_LAST,
1441                      G_STRUCT_OFFSET(WebKitWebViewClass, resource_load_started),
1442                      0, 0,
1443                      webkit_marshal_VOID__OBJECT_OBJECT,
1444                      G_TYPE_NONE, 2,
1445                      WEBKIT_TYPE_WEB_RESOURCE,
1446                      WEBKIT_TYPE_URI_REQUEST);
1447
1448     /**
1449      * WebKitWebView::enter-fullscreen:
1450      * @web_view: the #WebKitWebView on which the signal is emitted.
1451      *
1452      * Emitted when JavaScript code calls
1453      * <function>element.webkitRequestFullScreen</function>. If the
1454      * signal is not handled the #WebKitWebView will proceed to full screen
1455      * its top level window. This signal can be used by client code to
1456      * request permission to the user prior doing the full screen
1457      * transition and eventually prepare the top-level window
1458      * (e.g. hide some widgets that would otherwise be part of the
1459      * full screen window).
1460      *
1461      * Returns: %TRUE to stop other handlers from being invoked for the event.
1462      *    %FALSE to continue emission of the event.
1463      */
1464     signals[ENTER_FULLSCREEN] =
1465         g_signal_new("enter-fullscreen",
1466                      G_TYPE_FROM_CLASS(webViewClass),
1467                      G_SIGNAL_RUN_LAST,
1468                      G_STRUCT_OFFSET(WebKitWebViewClass, enter_fullscreen),
1469                      g_signal_accumulator_true_handled, 0,
1470                      webkit_marshal_BOOLEAN__VOID,
1471                      G_TYPE_BOOLEAN, 0);
1472
1473     /**
1474      * WebKitWebView::leave-fullscreen:
1475      * @web_view: the #WebKitWebView on which the signal is emitted.
1476      *
1477      * Emitted when the #WebKitWebView is about to restore its top level
1478      * window out of its full screen state. This signal can be used by
1479      * client code to restore widgets hidden during the
1480      * #WebKitWebView::enter-fullscreen stage for instance.
1481      *
1482      * Returns: %TRUE to stop other handlers from being invoked for the event.
1483      *    %FALSE to continue emission of the event.
1484      */
1485     signals[LEAVE_FULLSCREEN] =
1486         g_signal_new("leave-fullscreen",
1487                      G_TYPE_FROM_CLASS(webViewClass),
1488                      G_SIGNAL_RUN_LAST,
1489                      G_STRUCT_OFFSET(WebKitWebViewClass, leave_fullscreen),
1490                      g_signal_accumulator_true_handled, 0,
1491                      webkit_marshal_BOOLEAN__VOID,
1492                      G_TYPE_BOOLEAN, 0);
1493      /**
1494      * WebKitWebView::run-file-chooser:
1495      * @web_view: the #WebKitWebView on which the signal is emitted
1496      * @request: a #WebKitFileChooserRequest
1497      *
1498      * This signal is emitted when the user interacts with a &lt;input
1499      * type='file' /&gt; HTML element, requesting from WebKit to show
1500      * a dialog to select one or more files to be uploaded. To let the
1501      * application know the details of the file chooser, as well as to
1502      * allow the client application to either cancel the request or
1503      * perform an actual selection of files, the signal will pass an
1504      * instance of the #WebKitFileChooserRequest in the @request
1505      * argument.
1506      *
1507      * The default signal handler will asynchronously run a regular
1508      * #GtkFileChooserDialog for the user to interact with.
1509      *
1510      * Returns: %TRUE to stop other handlers from being invoked for the event.
1511      *   %FALSE to propagate the event further.
1512      *
1513      */
1514     signals[RUN_FILE_CHOOSER] =
1515         g_signal_new("run-file-chooser",
1516                      G_TYPE_FROM_CLASS(webViewClass),
1517                      G_SIGNAL_RUN_LAST,
1518                      G_STRUCT_OFFSET(WebKitWebViewClass, run_file_chooser),
1519                      g_signal_accumulator_true_handled, 0 /* accumulator data */,
1520                      webkit_marshal_BOOLEAN__OBJECT,
1521                      G_TYPE_BOOLEAN, 1, /* number of parameters */
1522                      WEBKIT_TYPE_FILE_CHOOSER_REQUEST);
1523
1524     /**
1525      * WebKitWebView::context-menu:
1526      * @web_view: the #WebKitWebView on which the signal is emitted
1527      * @context_menu: the proposed #WebKitContextMenu
1528      * @event: the #GdkEvent that triggered the context menu
1529      * @hit_test_result: a #WebKitHitTestResult
1530      *
1531      * Emmited when a context menu is about to be displayed to give the application
1532      * a chance to customize the proposed menu, prevent the menu from being displayed
1533      * or build its own context menu.
1534      * <itemizedlist>
1535      * <listitem><para>
1536      *  To customize the proposed menu you can use webkit_context_menu_prepend(),
1537      *  webkit_context_menu_append() or webkit_context_menu_insert() to add new
1538      *  #WebKitContextMenuItem<!-- -->s to @context_menu, webkit_context_menu_move_item()
1539      *  to reorder existing items, or webkit_context_menu_remove() to remove an
1540      *  existing item. The signal handler should return %FALSE, and the menu represented
1541      *  by @context_menu will be shown.
1542      * </para></listitem>
1543      * <listitem><para>
1544      *  To prevent the menu from being displayed you can just connect to this signal
1545      *  and return %TRUE so that the proposed menu will not be shown.
1546      * </para></listitem>
1547      * <listitem><para>
1548      *  To build your own menu, you can remove all items from the proposed menu with
1549      *  webkit_context_menu_remove_all(), add your own items and return %FALSE so
1550      *  that the menu will be shown. You can also ignore the proposed #WebKitContextMenu,
1551      *  build your own #GtkMenu and return %TRUE to prevent the proposed menu from being shown.
1552      * </para></listitem>
1553      * <listitem><para>
1554      *  If you just want the default menu to be shown always, simply don't connect to this
1555      *  signal because showing the proposed context menu is the default behaviour.
1556      * </para></listitem>
1557      * </itemizedlist>
1558      *
1559      * If the signal handler returns %FALSE the context menu represented by @context_menu
1560      * will be shown, if it return %TRUE the context menu will not be shown.
1561      *
1562      * The proposed #WebKitContextMenu passed in @context_menu argument is only valid
1563      * during the signal emission.
1564      *
1565      * Returns: %TRUE to stop other handlers from being invoked for the event.
1566      *    %FALSE to propagate the event further.
1567      */
1568     signals[CONTEXT_MENU] =
1569         g_signal_new("context-menu",
1570                      G_TYPE_FROM_CLASS(webViewClass),
1571                      G_SIGNAL_RUN_LAST,
1572                      G_STRUCT_OFFSET(WebKitWebViewClass, context_menu),
1573                      g_signal_accumulator_true_handled, 0,
1574                      webkit_marshal_BOOLEAN__OBJECT_BOXED_OBJECT,
1575                      G_TYPE_BOOLEAN, 3,
1576                      WEBKIT_TYPE_CONTEXT_MENU,
1577                      GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
1578                      WEBKIT_TYPE_HIT_TEST_RESULT);
1579
1580     /**
1581      * WebKitWebView::context-menu-dismissed:
1582      * @web_view: the #WebKitWebView on which the signal is emitted
1583      *
1584      * Emitted after #WebKitWebView::context-menu signal, if the context menu is shown,
1585      * to notify that the context menu is dismissed.
1586      */
1587     signals[CONTEXT_MENU_DISMISSED] =
1588         g_signal_new("context-menu-dismissed",
1589                      G_TYPE_FROM_CLASS(webViewClass),
1590                      G_SIGNAL_RUN_LAST,
1591                      G_STRUCT_OFFSET(WebKitWebViewClass, context_menu_dismissed),
1592                      0, 0,
1593                      g_cclosure_marshal_VOID__VOID,
1594                      G_TYPE_NONE, 0);
1595
1596     /**
1597      * WebKitWebView::submit-form:
1598      * @web_view: the #WebKitWebView on which the signal is emitted
1599      * @request: a #WebKitFormSubmissionRequest
1600      *
1601      * This signal is emitted when a form is about to be submitted. The @request
1602      * argument passed contains information about the text fields of the form. This
1603      * is typically used to store login information that can be used later to
1604      * pre-fill the form.
1605      * The form will not be submitted until webkit_form_submission_request_submit() is called.
1606      *
1607      * It is possible to handle the form submission request asynchronously, by
1608      * simply calling g_object_ref() on the @request argument and calling
1609      * webkit_form_submission_request_submit() when done to continue with the form submission.
1610      * If the last reference is removed on a #WebKitFormSubmissionRequest and the
1611      * form has not been submitted, webkit_form_submission_request_submit() will be called.
1612      */
1613     signals[SUBMIT_FORM] =
1614         g_signal_new("submit-form",
1615                      G_TYPE_FROM_CLASS(webViewClass),
1616                      G_SIGNAL_RUN_LAST,
1617                      G_STRUCT_OFFSET(WebKitWebViewClass, submit_form),
1618                      0, 0,
1619                      g_cclosure_marshal_VOID__OBJECT,
1620                      G_TYPE_NONE, 1,
1621                      WEBKIT_TYPE_FORM_SUBMISSION_REQUEST);
1622
1623     /**
1624      * WebKitWebView::insecure-content-detected:
1625      * @web_view: the #WebKitWebView on which the signal is emitted
1626      * @event: the #WebKitInsecureContentEvent
1627      *
1628      * This signal is emitted when insecure content has been detected
1629      * in a page loaded through a secure connection. This typically
1630      * means that a external resource from an unstrusted source has
1631      * been run or displayed, resulting in a mix of HTTPS and
1632      * non-HTTPS content.
1633      *
1634      * You can check the @event parameter to know exactly which kind
1635      * of event has been detected (see #WebKitInsecureContentEvent).
1636      */
1637     signals[INSECURE_CONTENT_DETECTED] =
1638         g_signal_new("insecure-content-detected",
1639             G_TYPE_FROM_CLASS(webViewClass),
1640             G_SIGNAL_RUN_LAST,
1641             G_STRUCT_OFFSET(WebKitWebViewClass, insecure_content_detected),
1642             0, 0,
1643             g_cclosure_marshal_VOID__ENUM,
1644             G_TYPE_NONE, 1,
1645             WEBKIT_TYPE_INSECURE_CONTENT_EVENT);
1646
1647     /**
1648      * WebKitWebView::web-process-crashed:
1649      * @web_view: the #WebKitWebView
1650      *
1651      * This signal is emitted when the web process crashes.
1652      *
1653      * Returns: %TRUE to stop other handlers from being invoked for the event.
1654      *    %FALSE to propagate the event further.
1655      */
1656     signals[WEB_PROCESS_CRASHED] = g_signal_new(
1657         "web-process-crashed",
1658         G_TYPE_FROM_CLASS(webViewClass),
1659         G_SIGNAL_RUN_LAST,
1660         G_STRUCT_OFFSET(WebKitWebViewClass, web_process_crashed),
1661         g_signal_accumulator_true_handled,
1662         0,
1663         webkit_marshal_BOOLEAN__VOID,
1664         G_TYPE_BOOLEAN, 0);
1665
1666     /**
1667      * WebKitWebView::authenticate:
1668      * @web_view: the #WebKitWebView on which the signal is emitted
1669      * @request: a #WebKitAuthenticationRequest
1670      *
1671      * This signal is emitted when the user is challenged with HTTP
1672      * authentication. To let the  application access or supply
1673      * the credentials as well as to allow the client application
1674      * to either cancel the request or perform the authentication,
1675      * the signal will pass an instance of the
1676      * #WebKitAuthenticationRequest in the @request argument.
1677      * To handle this signal asynchronously you should keep a ref
1678      * of the request and return %TRUE. To disable HTTP authentication
1679      * entirely, connect to this signal and simply return %TRUE.
1680      *
1681      * The default signal handler will run a default authentication
1682      * dialog asynchronously for the user to interact with.
1683      *
1684      * Returns: %TRUE to stop other handlers from being invoked for the event.
1685      *   %FALSE to propagate the event further.
1686      *
1687      * Since: 2.2
1688      */
1689     signals[AUTHENTICATE] =
1690         g_signal_new("authenticate",
1691             G_TYPE_FROM_CLASS(webViewClass),
1692             G_SIGNAL_RUN_LAST,
1693             G_STRUCT_OFFSET(WebKitWebViewClass, authenticate),
1694             g_signal_accumulator_true_handled, 0 /* accumulator data */,
1695             webkit_marshal_BOOLEAN__OBJECT,
1696             G_TYPE_BOOLEAN, 1, /* number of parameters */
1697             WEBKIT_TYPE_AUTHENTICATION_REQUEST);
1698
1699     /**
1700      * WebKitWebView::show-notification:
1701      * @web_view: the #WebKitWebView
1702      * @notification: a #WebKitNotification
1703      *
1704      * This signal is emitted when a notification should be presented to the
1705      * user. The @notification is kept alive until either: 1) the web page cancels it
1706      * or 2) a navigation happens.
1707      *
1708      * The default handler will emit a notification using libnotify, if built with
1709      * support for it.
1710      *
1711      * Returns: %TRUE to stop other handlers from being invoked. %FALSE otherwise.
1712      *
1713      * Since: 2.8
1714      */
1715     signals[SHOW_NOTIFICATION] =
1716         g_signal_new("show-notification",
1717             G_TYPE_FROM_CLASS(gObjectClass),
1718             G_SIGNAL_RUN_LAST,
1719             G_STRUCT_OFFSET(WebKitWebViewClass, show_notification),
1720             g_signal_accumulator_true_handled, nullptr /* accumulator data */,
1721             webkit_marshal_BOOLEAN__OBJECT,
1722             G_TYPE_BOOLEAN, 1,
1723             WEBKIT_TYPE_NOTIFICATION);
1724
1725      /**
1726       * WebKitWebView::run-color-chooser:
1727       * @web_view: the #WebKitWebView on which the signal is emitted
1728       * @request: a #WebKitColorChooserRequest
1729       *
1730       * This signal is emitted when the user interacts with a &lt;input
1731       * type='color' /&gt; HTML element, requesting from WebKit to show
1732       * a dialog to select a color. To let the application know the details of
1733       * the color chooser, as well as to allow the client application to either
1734       * cancel the request or perform an actual color selection, the signal will
1735       * pass an instance of the #WebKitColorChooserRequest in the @request
1736       * argument.
1737       *
1738       * It is possible to handle this request asynchronously by increasing the
1739       * reference count of the request.
1740       *
1741       * The default signal handler will asynchronously run a regular
1742       * #GtkColorChooser for the user to interact with.
1743       *
1744       * Returns: %TRUE to stop other handlers from being invoked for the event.
1745       *   %FALSE to propagate the event further.
1746       *
1747       * Since: 2.8
1748       */
1749     signals[RUN_COLOR_CHOOSER] =
1750         g_signal_new("run-color-chooser",
1751             G_TYPE_FROM_CLASS(webViewClass),
1752             G_SIGNAL_RUN_LAST,
1753             G_STRUCT_OFFSET(WebKitWebViewClass, run_color_chooser),
1754             g_signal_accumulator_true_handled, nullptr,
1755             webkit_marshal_BOOLEAN__OBJECT,
1756             G_TYPE_BOOLEAN, 1,
1757             WEBKIT_TYPE_COLOR_CHOOSER_REQUEST);
1758 }
1759
1760 static void webkitWebViewCancelAuthenticationRequest(WebKitWebView* webView)
1761 {
1762     if (!webView->priv->authenticationRequest)
1763         return;
1764
1765     webkit_authentication_request_cancel(webView->priv->authenticationRequest.get());
1766     webView->priv->authenticationRequest.clear();
1767 }
1768
1769 static void webkitWebViewEmitLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent, bool isDelayedEvent)
1770 {
1771     if (loadEvent == WEBKIT_LOAD_STARTED) {
1772         webkitWebViewWatchForChangesInFavicon(webView);
1773         webkitWebViewCancelAuthenticationRequest(webView);
1774     } else if (loadEvent == WEBKIT_LOAD_FINISHED) {
1775         if (isDelayedEvent) {
1776             // In case of the delayed event, we need to manually set is-loading to false.
1777             webkitWebViewSetIsLoading(webView, false);
1778         }
1779         webkitWebViewCancelAuthenticationRequest(webView);
1780         webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
1781     }
1782
1783     g_signal_emit(webView, signals[LOAD_CHANGED], 0, loadEvent);
1784
1785     if (isDelayedEvent) {
1786         if (loadEvent == WEBKIT_LOAD_COMMITTED)
1787             webView->priv->waitingForMainResource = false;
1788         else if (loadEvent == WEBKIT_LOAD_FINISHED) {
1789             // Manually set is-loading again in case a new load was started.
1790             webkitWebViewSetIsLoading(webView, getPage(webView)->pageLoadState().isLoading());
1791         }
1792     }
1793 }
1794
1795 static void webkitWebViewEmitDelayedLoadEvents(WebKitWebView* webView)
1796 {
1797     WebKitWebViewPrivate* priv = webView->priv;
1798     if (!priv->waitingForMainResource)
1799         return;
1800     ASSERT(priv->lastDelayedEvent == WEBKIT_LOAD_COMMITTED || priv->lastDelayedEvent == WEBKIT_LOAD_FINISHED);
1801
1802     if (priv->lastDelayedEvent == WEBKIT_LOAD_FINISHED)
1803         webkitWebViewEmitLoadChanged(webView, WEBKIT_LOAD_COMMITTED, true);
1804     webkitWebViewEmitLoadChanged(webView, priv->lastDelayedEvent, true);
1805 }
1806
1807 void webkitWebViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent)
1808 {
1809     WebKitWebViewPrivate* priv = webView->priv;
1810     if (loadEvent == WEBKIT_LOAD_STARTED) {
1811         // Finish a possible previous load waiting for main resource.
1812         webkitWebViewEmitDelayedLoadEvents(webView);
1813
1814         webkitWebViewCancelFaviconRequest(webView);
1815         priv->loadingResourcesMap.clear();
1816         priv->mainResource = 0;
1817         priv->waitingForMainResource = false;
1818     } else if (loadEvent == WEBKIT_LOAD_COMMITTED) {
1819         WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context.get());
1820         GUniquePtr<char> faviconURI(webkit_favicon_database_get_favicon_uri(database, priv->activeURI.data()));
1821         webkitWebViewUpdateFaviconURI(webView, faviconURI.get());
1822
1823         if (!priv->mainResource) {
1824             // When a page is loaded from the history cache, the main resource load callbacks
1825             // are called when the main frame load is finished. We want to make sure there's a
1826             // main resource available when load has been committed, so we delay the emission of
1827             // load-changed signal until main resource object has been created.
1828             priv->waitingForMainResource = true;
1829         }
1830     }
1831
1832     if (priv->waitingForMainResource)
1833         priv->lastDelayedEvent = loadEvent;
1834     else
1835         webkitWebViewEmitLoadChanged(webView, loadEvent, false);
1836 }
1837
1838 void webkitWebViewLoadFailed(WebKitWebView* webView, WebKitLoadEvent loadEvent, const char* failingURI, GError *error)
1839 {
1840     webkitWebViewCancelAuthenticationRequest(webView);
1841
1842     gboolean returnValue;
1843     g_signal_emit(webView, signals[LOAD_FAILED], 0, loadEvent, failingURI, error, &returnValue);
1844     g_signal_emit(webView, signals[LOAD_CHANGED], 0, WEBKIT_LOAD_FINISHED);
1845 }
1846
1847 void webkitWebViewLoadFailedWithTLSErrors(WebKitWebView* webView, const char* failingURI, GError* error, GTlsCertificateFlags tlsErrors, GTlsCertificate* certificate)
1848 {
1849     webkitWebViewCancelAuthenticationRequest(webView);
1850
1851     WebKitTLSErrorsPolicy tlsErrorsPolicy = webkit_web_context_get_tls_errors_policy(webView->priv->context.get());
1852     if (tlsErrorsPolicy == WEBKIT_TLS_ERRORS_POLICY_FAIL) {
1853         gboolean returnValue;
1854         g_signal_emit(webView, signals[LOAD_FAILED_WITH_TLS_ERRORS], 0, failingURI, certificate, tlsErrors, &returnValue);
1855         if (!returnValue)
1856             g_signal_emit(webView, signals[LOAD_FAILED], 0, WEBKIT_LOAD_STARTED, failingURI, error, &returnValue);
1857     }
1858
1859     g_signal_emit(webView, signals[LOAD_CHANGED], 0, WEBKIT_LOAD_FINISHED);
1860 }
1861
1862 WebPageProxy* webkitWebViewCreateNewPage(WebKitWebView* webView, const WindowFeatures& windowFeatures, WebKitNavigationAction* navigationAction)
1863 {
1864     WebKitWebView* newWebView;
1865     g_signal_emit(webView, signals[CREATE], 0, navigationAction, &newWebView);
1866     if (!newWebView)
1867         return 0;
1868
1869     webkitWindowPropertiesUpdateFromWebWindowFeatures(newWebView->priv->windowProperties.get(), windowFeatures);
1870
1871     RefPtr<WebPageProxy> newPage = getPage(newWebView);
1872     return newPage.release().leakRef();
1873 }
1874
1875 void webkitWebViewReadyToShowPage(WebKitWebView* webView)
1876 {
1877     g_signal_emit(webView, signals[READY_TO_SHOW], 0, NULL);
1878 }
1879
1880 void webkitWebViewRunAsModal(WebKitWebView* webView)
1881 {
1882     g_signal_emit(webView, signals[RUN_AS_MODAL], 0, NULL);
1883
1884     webView->priv->modalLoop = adoptGRef(g_main_loop_new(0, FALSE));
1885
1886 // This is to suppress warnings about gdk_threads_leave and gdk_threads_enter.
1887 #pragma GCC diagnostic push
1888 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1889     gdk_threads_leave();
1890     g_main_loop_run(webView->priv->modalLoop.get());
1891     gdk_threads_enter();
1892 #pragma GCC diagnostic pop
1893 }
1894
1895 void webkitWebViewClosePage(WebKitWebView* webView)
1896 {
1897     g_signal_emit(webView, signals[CLOSE], 0, NULL);
1898 }
1899
1900 void webkitWebViewRunJavaScriptAlert(WebKitWebView* webView, const CString& message)
1901 {
1902     WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_ALERT, message);
1903     gboolean returnValue;
1904     g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
1905 }
1906
1907 bool webkitWebViewRunJavaScriptConfirm(WebKitWebView* webView, const CString& message)
1908 {
1909     WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_CONFIRM, message);
1910     gboolean returnValue;
1911     g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
1912     return dialog.confirmed;
1913 }
1914
1915 CString webkitWebViewRunJavaScriptPrompt(WebKitWebView* webView, const CString& message, const CString& defaultText)
1916 {
1917     WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_PROMPT, message, defaultText);
1918     gboolean returnValue;
1919     g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
1920     return dialog.text;
1921 }
1922
1923 void webkitWebViewMakePolicyDecision(WebKitWebView* webView, WebKitPolicyDecisionType type, WebKitPolicyDecision* decision)
1924 {
1925     gboolean returnValue;
1926     g_signal_emit(webView, signals[DECIDE_POLICY], 0, decision, type, &returnValue);
1927 }
1928
1929 void webkitWebViewMakePermissionRequest(WebKitWebView* webView, WebKitPermissionRequest* request)
1930 {
1931     gboolean returnValue;
1932     g_signal_emit(webView, signals[PERMISSION_REQUEST], 0, request, &returnValue);
1933 }
1934
1935 void webkitWebViewMouseTargetChanged(WebKitWebView* webView, const WebHitTestResultData& hitTestResult, unsigned modifiers)
1936 {
1937     webkitWebViewBaseSetTooltipArea(WEBKIT_WEB_VIEW_BASE(webView), hitTestResult.elementBoundingBox);
1938
1939     WebKitWebViewPrivate* priv = webView->priv;
1940     if (priv->mouseTargetHitTestResult
1941         && priv->mouseTargetModifiers == modifiers
1942         && webkitHitTestResultCompare(priv->mouseTargetHitTestResult.get(), hitTestResult))
1943         return;
1944
1945     priv->mouseTargetModifiers = modifiers;
1946     priv->mouseTargetHitTestResult = adoptGRef(webkitHitTestResultCreate(hitTestResult));
1947     g_signal_emit(webView, signals[MOUSE_TARGET_CHANGED], 0, priv->mouseTargetHitTestResult.get(), modifiers);
1948 }
1949
1950 void webkitWebViewPrintFrame(WebKitWebView* webView, WebFrameProxy* frame)
1951 {
1952     GRefPtr<WebKitPrintOperation> printOperation = adoptGRef(webkit_print_operation_new(webView));
1953     webkitPrintOperationSetPrintMode(printOperation.get(), PrintInfo::PrintModeSync);
1954     gboolean returnValue;
1955     g_signal_emit(webView, signals[PRINT], 0, printOperation.get(), &returnValue);
1956     if (returnValue)
1957         return;
1958
1959     WebKitPrintOperationResponse response = webkitPrintOperationRunDialogForFrame(printOperation.get(), 0, frame);
1960     if (response == WEBKIT_PRINT_OPERATION_RESPONSE_CANCEL)
1961         return;
1962     g_signal_connect(printOperation.leakRef(), "finished", G_CALLBACK(g_object_unref), 0);
1963 }
1964
1965 static void mainResourceResponseChangedCallback(WebKitWebResource*, GParamSpec*, WebKitWebView* webView)
1966 {
1967     webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
1968     webkitWebViewEmitDelayedLoadEvents(webView);
1969 }
1970
1971 static void waitForMainResourceResponseIfWaitingForResource(WebKitWebView* webView)
1972 {
1973     WebKitWebViewPrivate* priv = webView->priv;
1974     if (!priv->waitingForMainResource)
1975         return;
1976
1977     webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
1978     priv->mainResourceResponseHandlerID =
1979         g_signal_connect(priv->mainResource.get(), "notify::response", G_CALLBACK(mainResourceResponseChangedCallback), webView);
1980 }
1981
1982 void webkitWebViewResourceLoadStarted(WebKitWebView* webView, WebFrameProxy* frame, uint64_t resourceIdentifier, WebKitURIRequest* request)
1983 {
1984     WebKitWebViewPrivate* priv = webView->priv;
1985     bool isMainResource = frame->isMainFrame() && !priv->mainResource;
1986     WebKitWebResource* resource = webkitWebResourceCreate(frame, request, isMainResource);
1987     if (isMainResource) {
1988         priv->mainResource = resource;
1989         waitForMainResourceResponseIfWaitingForResource(webView);
1990     }
1991     priv->loadingResourcesMap.set(resourceIdentifier, adoptGRef(resource));
1992     g_signal_emit(webView, signals[RESOURCE_LOAD_STARTED], 0, resource, request);
1993 }
1994
1995 WebKitWebResource* webkitWebViewGetLoadingWebResource(WebKitWebView* webView, uint64_t resourceIdentifier)
1996 {
1997     GRefPtr<WebKitWebResource> resource = webView->priv->loadingResourcesMap.get(resourceIdentifier);
1998     return resource.get();
1999 }
2000
2001 void webkitWebViewRemoveLoadingWebResource(WebKitWebView* webView, uint64_t resourceIdentifier)
2002 {
2003     WebKitWebViewPrivate* priv = webView->priv;
2004     ASSERT(priv->loadingResourcesMap.contains(resourceIdentifier));
2005     priv->loadingResourcesMap.remove(resourceIdentifier);
2006 }
2007
2008 bool webkitWebViewEnterFullScreen(WebKitWebView* webView)
2009 {
2010     gboolean returnValue;
2011     g_signal_emit(webView, signals[ENTER_FULLSCREEN], 0, &returnValue);
2012     return !returnValue;
2013 }
2014
2015 bool webkitWebViewLeaveFullScreen(WebKitWebView* webView)
2016 {
2017     gboolean returnValue;
2018     g_signal_emit(webView, signals[LEAVE_FULLSCREEN], 0, &returnValue);
2019     return !returnValue;
2020 }
2021
2022 void webkitWebViewRunFileChooserRequest(WebKitWebView* webView, WebKitFileChooserRequest* request)
2023 {
2024     gboolean returnValue;
2025     g_signal_emit(webView, signals[RUN_FILE_CHOOSER], 0, request, &returnValue);
2026 }
2027
2028 static bool webkitWebViewShouldShowInputMethodsMenu(WebKitWebView* webView)
2029 {
2030     GtkSettings* settings = gtk_widget_get_settings(GTK_WIDGET(webView));
2031     if (!settings)
2032         return true;
2033
2034     gboolean showInputMethodMenu;
2035     g_object_get(settings, "gtk-show-input-method-menu", &showInputMethodMenu, NULL);
2036     return showInputMethodMenu;
2037 }
2038
2039 static int getUnicodeMenuItemPosition(WebKitContextMenu* contextMenu)
2040 {
2041     GList* items = webkit_context_menu_get_items(contextMenu);
2042     GList* iter;
2043     int i = 0;
2044     for (iter = items, i = 0; iter; iter = g_list_next(iter), ++i) {
2045         WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(iter->data);
2046
2047         if (webkit_context_menu_item_is_separator(item))
2048             continue;
2049         if (webkit_context_menu_item_get_stock_action(item) == WEBKIT_CONTEXT_MENU_ACTION_UNICODE)
2050             return i;
2051     }
2052     return -1;
2053 }
2054
2055 static void webkitWebViewCreateAndAppendInputMethodsMenuItem(WebKitWebView* webView, WebKitContextMenu* contextMenu)
2056 {
2057     if (!webkitWebViewShouldShowInputMethodsMenu(webView))
2058         return;
2059
2060     // Place the im context menu item right before the unicode menu item
2061     // if it's present.
2062     int unicodeMenuItemPosition = getUnicodeMenuItemPosition(contextMenu);
2063     if (unicodeMenuItemPosition == -1)
2064         webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator());
2065
2066     GtkIMContext* imContext = webkitWebViewBaseGetIMContext(WEBKIT_WEB_VIEW_BASE(webView));
2067     GtkMenu* imContextMenu = GTK_MENU(gtk_menu_new());
2068     gtk_im_multicontext_append_menuitems(GTK_IM_MULTICONTEXT(imContext), GTK_MENU_SHELL(imContextMenu));
2069     WebKitContextMenuItem* menuItem = webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS);
2070     webkitContextMenuItemSetSubMenuFromGtkMenu(menuItem, imContextMenu);
2071     webkit_context_menu_insert(contextMenu, menuItem, unicodeMenuItemPosition);
2072 }
2073
2074 static void contextMenuDismissed(GtkMenuShell*, WebKitWebView* webView)
2075 {
2076     g_signal_emit(webView, signals[CONTEXT_MENU_DISMISSED], 0, NULL);
2077 }
2078
2079 void webkitWebViewPopulateContextMenu(WebKitWebView* webView, const Vector<WebContextMenuItemData>& proposedMenu, const WebHitTestResultData& hitTestResultData, GVariant* userData)
2080 {
2081     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView);
2082     WebContextMenuProxyGtk* contextMenuProxy = webkitWebViewBaseGetActiveContextMenuProxy(webViewBase);
2083     ASSERT(contextMenuProxy);
2084
2085     GRefPtr<WebKitContextMenu> contextMenu = adoptGRef(webkitContextMenuCreate(proposedMenu));
2086     if (hitTestResultData.isContentEditable)
2087         webkitWebViewCreateAndAppendInputMethodsMenuItem(webView, contextMenu.get());
2088
2089     GRefPtr<WebKitHitTestResult> hitTestResult = adoptGRef(webkitHitTestResultCreate(hitTestResultData));
2090     GUniquePtr<GdkEvent> contextMenuEvent(webkitWebViewBaseTakeContextMenuEvent(webViewBase));
2091
2092     if (userData)
2093         webkit_context_menu_set_user_data(WEBKIT_CONTEXT_MENU(contextMenu.get()), userData);
2094
2095     gboolean returnValue;
2096     g_signal_emit(webView, signals[CONTEXT_MENU], 0, contextMenu.get(), contextMenuEvent.get(), hitTestResult.get(), &returnValue);
2097     if (returnValue)
2098         return;
2099
2100     Vector<ContextMenuItem> contextMenuItems;
2101     webkitContextMenuPopulate(contextMenu.get(), contextMenuItems);
2102     contextMenuProxy->populate(contextMenuItems);
2103
2104     g_signal_connect(contextMenuProxy->gtkMenu(), "deactivate", G_CALLBACK(contextMenuDismissed), webView);
2105
2106     // Clear the menu to make sure it's useless after signal emission.
2107     webkit_context_menu_remove_all(contextMenu.get());
2108 }
2109
2110 void webkitWebViewSubmitFormRequest(WebKitWebView* webView, WebKitFormSubmissionRequest* request)
2111 {
2112     g_signal_emit(webView, signals[SUBMIT_FORM], 0, request);
2113 }
2114
2115 void webkitWebViewHandleAuthenticationChallenge(WebKitWebView* webView, AuthenticationChallengeProxy* authenticationChallenge)
2116 {
2117     gboolean privateBrowsingEnabled = webkit_settings_get_enable_private_browsing(webView->priv->settings.get());
2118     webView->priv->authenticationRequest = adoptGRef(webkitAuthenticationRequestCreate(authenticationChallenge, privateBrowsingEnabled));
2119     gboolean returnValue;
2120     g_signal_emit(webView, signals[AUTHENTICATE], 0, webView->priv->authenticationRequest.get(), &returnValue);
2121 }
2122
2123 void webkitWebViewInsecureContentDetected(WebKitWebView* webView, WebKitInsecureContentEvent type)
2124 {
2125     g_signal_emit(webView, signals[INSECURE_CONTENT_DETECTED], 0, type);
2126 }
2127
2128 bool webkitWebViewEmitShowNotification(WebKitWebView* webView, WebKitNotification* webNotification)
2129 {
2130     gboolean handled;
2131     g_signal_emit(webView, signals[SHOW_NOTIFICATION], 0, webNotification, &handled);
2132     return handled;
2133 }
2134
2135 bool webkitWebViewEmitRunColorChooser(WebKitWebView* webView, WebKitColorChooserRequest* request)
2136 {
2137     gboolean handled;
2138     g_signal_emit(webView, signals[RUN_COLOR_CHOOSER], 0, request, &handled);
2139     return handled;
2140 }
2141
2142 void webkitWebViewSelectionDidChange(WebKitWebView* webView)
2143 {
2144     if (!webView->priv->editorState)
2145         return;
2146
2147     webkitEditorStateChanged(webView->priv->editorState.get(), getPage(webView)->editorState());
2148 }
2149
2150 void webkitWebViewRequestInstallMissingMediaPlugins(WebKitWebView* webView, InstallMissingMediaPluginsPermissionRequest& request)
2151 {
2152 #if ENABLE(VIDEO)
2153     GRefPtr<WebKitInstallMissingMediaPluginsPermissionRequest> installMediaPluginsPermissionRequest = adoptGRef(webkitInstallMissingMediaPluginsPermissionRequestCreate(request));
2154     webkitWebViewMakePermissionRequest(webView, WEBKIT_PERMISSION_REQUEST(installMediaPluginsPermissionRequest.get()));
2155 #else
2156     ASSERT_NOT_REACHED();
2157 #endif
2158 }
2159
2160 /**
2161  * webkit_web_view_new:
2162  *
2163  * Creates a new #WebKitWebView with the default #WebKitWebContext and
2164  * no #WebKitUserContentManager associated with it.
2165  * See also webkit_web_view_new_with_context(),
2166  * webkit_web_view_new_with_user_content_manager(), and
2167  * webkit_web_view_new_with_settings().
2168  *
2169  * Returns: The newly created #WebKitWebView widget
2170  */
2171 GtkWidget* webkit_web_view_new()
2172 {
2173     return webkit_web_view_new_with_context(webkit_web_context_get_default());
2174 }
2175
2176 /**
2177  * webkit_web_view_new_with_context:
2178  * @context: the #WebKitWebContext to be used by the #WebKitWebView
2179  *
2180  * Creates a new #WebKitWebView with the given #WebKitWebContext and
2181  * no #WebKitUserContentManager associated with it.
2182  * See also webkit_web_view_new_with_user_content_manager() and
2183  * webkit_web_view_new_with_settings().
2184  *
2185  * Returns: The newly created #WebKitWebView widget
2186  */
2187 GtkWidget* webkit_web_view_new_with_context(WebKitWebContext* context)
2188 {
2189     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
2190
2191     return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "web-context", context, NULL));
2192 }
2193
2194 /**
2195  * webkit_web_view_new_with_related_view:
2196  * @web_view: the related #WebKitWebView
2197  *
2198  * Creates a new #WebKitWebView sharing the same web process with @web_view.
2199  * This method doesn't have any effect when %WEBKIT_PROCESS_MODEL_SHARED_SECONDARY_PROCESS
2200  * process model is used, because a single web process is shared for all the web views in the
2201  * same #WebKitWebContext. When using %WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES process model,
2202  * this method should always be used when creating the #WebKitWebView in the #WebKitWebView::create signal.
2203  * You can also use this method to implement other process models based on %WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES,
2204  * like for example, sharing the same web process for all the views in the same security domain.
2205  *
2206  * The newly created #WebKitWebView will also have the same #WebKitUserContentManager
2207  * and #WebKitSettings as @web_view.
2208  *
2209  * Returns: (transfer full): The newly created #WebKitWebView widget
2210  *
2211  * Since: 2.4
2212  */
2213 GtkWidget* webkit_web_view_new_with_related_view(WebKitWebView* webView)
2214 {
2215     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr);
2216
2217     return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW,
2218         "user-content-manager", webView->priv->userContentManager.get(),
2219         "settings", webView->priv->settings.get(),
2220         "related-view", webView,
2221         nullptr));
2222 }
2223
2224 /**
2225  * webkit_web_view_new_with_settings:
2226  * @settings: a #WebKitSettings
2227  *
2228  * Creates a new #WebKitWebView with the given #WebKitSettings.
2229  * See also webkit_web_view_new_with_context(), and
2230  * webkit_web_view_new_with_user_content_manager().
2231  *
2232  * Returns: The newly created #WebKitWebView widget
2233  *
2234  * Since: 2.6
2235  */
2236 GtkWidget* webkit_web_view_new_with_settings(WebKitSettings* settings)
2237 {
2238     g_return_val_if_fail(WEBKIT_IS_SETTINGS(settings), nullptr);
2239     return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "settings", settings, nullptr));
2240 }
2241
2242 /**
2243  * webkit_web_view_new_with_user_content_manager:
2244  * @user_content_manager: a #WebKitUserContentManager.
2245  *
2246  * Creates a new #WebKitWebView with the given #WebKitUserContentManager.
2247  * The content loaded in the view may be affected by the content injected
2248  * in the view by the user content manager.
2249  *
2250  * Returns: The newly created #WebKitWebView widget
2251  *
2252  * Since: 2.6
2253  */
2254 GtkWidget* webkit_web_view_new_with_user_content_manager(WebKitUserContentManager* userContentManager)
2255 {
2256     g_return_val_if_fail(WEBKIT_IS_USER_CONTENT_MANAGER(userContentManager), nullptr);
2257
2258     return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "user-content-manager", userContentManager, nullptr));
2259 }
2260
2261 /**
2262  * webkit_web_view_get_context:
2263  * @web_view: a #WebKitWebView
2264  *
2265  * Gets the web context of @web_view.
2266  *
2267  * Returns: (transfer none): the #WebKitWebContext of the view
2268  */
2269 WebKitWebContext* webkit_web_view_get_context(WebKitWebView *webView)
2270 {
2271     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2272
2273     return webView->priv->context.get();
2274 }
2275
2276 /**
2277  * webkit_web_view_get_user_content_manager:
2278  * @web_view: a #WebKitWebView
2279  *
2280  * Gets the user content manager associated to @web_view, or %NULL if the
2281  * view does not have an user content manager.
2282  *
2283  * Returns: (transfer none): the #WebKitUserContentManager associated with the view
2284  *
2285  * Since: 2.6
2286  */
2287 WebKitUserContentManager* webkit_web_view_get_user_content_manager(WebKitWebView* webView)
2288 {
2289     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr);
2290
2291     return webView->priv->userContentManager.get();
2292 }
2293
2294 /**
2295  * webkit_web_view_load_uri:
2296  * @web_view: a #WebKitWebView
2297  * @uri: an URI string
2298  *
2299  * Requests loading of the specified URI string.
2300  * You can monitor the load operation by connecting to
2301  * #WebKitWebView::load-changed signal.
2302  */
2303 void webkit_web_view_load_uri(WebKitWebView* webView, const gchar* uri)
2304 {
2305     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2306     g_return_if_fail(uri);
2307
2308     GUniquePtr<SoupURI> soupURI(soup_uri_new(uri));
2309     getPage(webView)->loadRequest(URL(soupURI.get()));
2310 }
2311
2312 /**
2313  * webkit_web_view_load_html:
2314  * @web_view: a #WebKitWebView
2315  * @content: The HTML string to load
2316  * @base_uri: (allow-none): The base URI for relative locations or %NULL
2317  *
2318  * Load the given @content string with the specified @base_uri.
2319  * If @base_uri is not %NULL, relative URLs in the @content will be
2320  * resolved against @base_uri and absolute local paths must be children of the @base_uri.
2321  * For security reasons absolute local paths that are not children of @base_uri
2322  * will cause the web process to terminate.
2323  * If you need to include URLs in @content that are local paths in a different
2324  * directory than @base_uri you can build a data URI for them. When @base_uri is %NULL,
2325  * it defaults to "about:blank". The mime type of the document will be "text/html".
2326  * You can monitor the load operation by connecting to #WebKitWebView::load-changed signal.
2327  */
2328 void webkit_web_view_load_html(WebKitWebView* webView, const gchar* content, const gchar* baseURI)
2329 {
2330     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2331     g_return_if_fail(content);
2332
2333     getPage(webView)->loadHTMLString(String::fromUTF8(content), String::fromUTF8(baseURI));
2334 }
2335
2336 /**
2337  * webkit_web_view_load_alternate_html:
2338  * @web_view: a #WebKitWebView
2339  * @content: the new content to display as the main page of the @web_view
2340  * @content_uri: the URI for the alternate page content
2341  * @base_uri: (allow-none): the base URI for relative locations or %NULL
2342  *
2343  * Load the given @content string for the URI @content_uri.
2344  * This allows clients to display page-loading errors in the #WebKitWebView itself.
2345  * When this method is called from #WebKitWebView::load-failed signal to show an
2346  * error page, the the back-forward list is maintained appropriately.
2347  * For everything else this method works the same way as webkit_web_view_load_html().
2348  */
2349 void webkit_web_view_load_alternate_html(WebKitWebView* webView, const gchar* content, const gchar* contentURI, const gchar* baseURI)
2350 {
2351     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2352     g_return_if_fail(content);
2353     g_return_if_fail(contentURI);
2354
2355     getPage(webView)->loadAlternateHTMLString(String::fromUTF8(content), String::fromUTF8(baseURI), String::fromUTF8(contentURI));
2356 }
2357
2358 /**
2359  * webkit_web_view_load_plain_text:
2360  * @web_view: a #WebKitWebView
2361  * @plain_text: The plain text to load
2362  *
2363  * Load the specified @plain_text string into @web_view. The mime type of
2364  * document will be "text/plain". You can monitor the load
2365  * operation by connecting to #WebKitWebView::load-changed signal.
2366  */
2367 void webkit_web_view_load_plain_text(WebKitWebView* webView, const gchar* plainText)
2368 {
2369     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2370     g_return_if_fail(plainText);
2371
2372     getPage(webView)->loadPlainTextString(String::fromUTF8(plainText));
2373 }
2374
2375 static void releaseGBytes(unsigned char*, const void* bytes)
2376 {
2377     // Balanced by g_bytes_ref in webkit_web_view_load_bytes().
2378     g_bytes_unref(static_cast<GBytes*>(const_cast<void*>(bytes)));
2379 }
2380
2381 /**
2382  * webkit_web_view_load_bytes:
2383  * @web_view: a #WebKitWebView
2384  * @bytes: input data to load
2385  * @mime_type: (allow-none): the MIME type of @bytes, or %NULL
2386  * @encoding: (allow-none): the character encoding of @bytes, or %NULL
2387  * @base_uri: (allow-none): the base URI for relative locations or %NULL
2388  *
2389  * Load the specified @bytes into @web_view using the given @mime_type and @encoding.
2390  * When @mime_type is %NULL, it defaults to "text/html".
2391  * When @encoding is %NULL, it defaults to "UTF-8".
2392  * When @base_uri is %NULL, it defaults to "about:blank".
2393  * You can monitor the load operation by connecting to #WebKitWebView::load-changed signal.
2394  *
2395  * Since: 2.6
2396  */
2397 void webkit_web_view_load_bytes(WebKitWebView* webView, GBytes* bytes, const char* mimeType, const char* encoding, const char* baseURI)
2398 {
2399     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2400     g_return_if_fail(bytes);
2401
2402     gsize bytesDataSize;
2403     gconstpointer bytesData = g_bytes_get_data(bytes, &bytesDataSize);
2404     g_return_if_fail(bytesDataSize);
2405
2406     // Balanced by g_bytes_unref in releaseGBytes.
2407     g_bytes_ref(bytes);
2408
2409     Ref<API::Data> data = API::Data::createWithoutCopying(static_cast<const unsigned char*>(bytesData), bytesDataSize, releaseGBytes, bytes);
2410     getPage(webView)->loadData(data.ptr(), mimeType ? String::fromUTF8(mimeType) : String::fromUTF8("text/html"),
2411         encoding ? String::fromUTF8(encoding) : String::fromUTF8("UTF-8"), String::fromUTF8(baseURI));
2412 }
2413
2414 /**
2415  * webkit_web_view_load_request:
2416  * @web_view: a #WebKitWebView
2417  * @request: a #WebKitURIRequest to load
2418  *
2419  * Requests loading of the specified #WebKitURIRequest.
2420  * You can monitor the load operation by connecting to
2421  * #WebKitWebView::load-changed signal.
2422  */
2423 void webkit_web_view_load_request(WebKitWebView* webView, WebKitURIRequest* request)
2424 {
2425     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2426     g_return_if_fail(WEBKIT_IS_URI_REQUEST(request));
2427
2428     ResourceRequest resourceRequest;
2429     webkitURIRequestGetResourceRequest(request, resourceRequest);
2430     getPage(webView)->loadRequest(resourceRequest);
2431 }
2432
2433 /**
2434  * webkit_web_view_get_page_id:
2435  * @web_view: a #WebKitWebView
2436  *
2437  * Get the identifier of the #WebKitWebPage corresponding to
2438  * the #WebKitWebView
2439  *
2440  * Returns: the page ID of @web_view.
2441  */
2442 guint64 webkit_web_view_get_page_id(WebKitWebView* webView)
2443 {
2444     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2445
2446     return getPage(webView)->pageID();
2447 }
2448
2449 /**
2450  * webkit_web_view_get_title:
2451  * @web_view: a #WebKitWebView
2452  *
2453  * Gets the value of the #WebKitWebView:title property.
2454  * You can connect to notify::title signal of @web_view to
2455  * be notified when the title has been received.
2456  *
2457  * Returns: The main frame document title of @web_view.
2458  */
2459 const gchar* webkit_web_view_get_title(WebKitWebView* webView)
2460 {
2461     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2462
2463     return webView->priv->title.data();
2464 }
2465
2466 /**
2467  * webkit_web_view_reload:
2468  * @web_view: a #WebKitWebView
2469  *
2470  * Reloads the current contents of @web_view.
2471  * See also webkit_web_view_reload_bypass_cache().
2472  */
2473 void webkit_web_view_reload(WebKitWebView* webView)
2474 {
2475     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2476
2477     getPage(webView)->reload(false);
2478 }
2479
2480 /**
2481  * webkit_web_view_reload_bypass_cache:
2482  * @web_view: a #WebKitWebView
2483  *
2484  * Reloads the current contents of @web_view without
2485  * using any cached data.
2486  */
2487 void webkit_web_view_reload_bypass_cache(WebKitWebView* webView)
2488 {
2489     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2490
2491     getPage(webView)->reload(true);
2492 }
2493
2494 /**
2495  * webkit_web_view_stop_loading:
2496  * @web_view: a #WebKitWebView
2497  *
2498  * Stops any ongoing loading operation in @web_view.
2499  * This method does nothing if no content is being loaded.
2500  * If there is a loading operation in progress, it will be cancelled and
2501  * #WebKitWebView::load-failed signal will be emitted with
2502  * %WEBKIT_NETWORK_ERROR_CANCELLED error.
2503  */
2504 void webkit_web_view_stop_loading(WebKitWebView* webView)
2505 {
2506     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2507
2508     getPage(webView)->stopLoading();
2509 }
2510
2511 /**
2512  * webkit_web_view_is_loading:
2513  * @web_view: a #WebKitWebView
2514  *
2515  * Gets the value of the #WebKitWebView:is-loading property.
2516  * You can monitor when a #WebKitWebView is loading a page by connecting to
2517  * notify::is-loading signal of @web_view. This is useful when you are
2518  * interesting in knowing when the view is loding something but not in the
2519  * details about the status of the load operation, for example to start a spinner
2520  * when the view is loading a page and stop it when it finishes.
2521  *
2522  * Returns: %TRUE if @web_view is loading a page or %FALSE otherwise.
2523  */
2524 gboolean webkit_web_view_is_loading(WebKitWebView* webView)
2525 {
2526     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2527
2528     return webView->priv->isLoading;
2529 }
2530
2531 /**
2532  * webkit_web_view_is_playing_audio:
2533  * @web_view: a #WebKitWebView
2534  *
2535  * Gets the value of the #WebKitWebView:is-playing-audio property.
2536  * You can monitor when a page in a #WebKitWebView is playing audio by
2537  * connecting to the notify::is-playing-audio signal of @web_view. This
2538  * is useful when the application wants to provide visual feedback when a
2539  * page is producing sound.
2540  *
2541  * Returns: %TRUE if a page in @web_view is playing audio or %FALSE otherwise.
2542  *
2543  * Since: 2.8
2544  */
2545 gboolean webkit_web_view_is_playing_audio(WebKitWebView* webView)
2546 {
2547     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2548
2549     return getPage(webView)->isPlayingAudio();
2550 }
2551
2552 /**
2553  * webkit_web_view_go_back:
2554  * @web_view: a #WebKitWebView
2555  *
2556  * Loads the previous history item.
2557  * You can monitor the load operation by connecting to
2558  * #WebKitWebView::load-changed signal.
2559  */
2560 void webkit_web_view_go_back(WebKitWebView* webView)
2561 {
2562     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2563
2564     getPage(webView)->goBack();
2565 }
2566
2567 /**
2568  * webkit_web_view_can_go_back:
2569  * @web_view: a #WebKitWebView
2570  *
2571  * Determines whether @web_view has a previous history item.
2572  *
2573  * Returns: %TRUE if able to move back or %FALSE otherwise.
2574  */
2575 gboolean webkit_web_view_can_go_back(WebKitWebView* webView)
2576 {
2577     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2578
2579     return !!getPage(webView)->backForwardList().backItem();
2580 }
2581
2582 /**
2583  * webkit_web_view_go_forward:
2584  * @web_view: a #WebKitWebView
2585  *
2586  * Loads the next history item.
2587  * You can monitor the load operation by connecting to
2588  * #WebKitWebView::load-changed signal.
2589  */
2590 void webkit_web_view_go_forward(WebKitWebView* webView)
2591 {
2592     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2593
2594     getPage(webView)->goForward();
2595 }
2596
2597 /**
2598  * webkit_web_view_can_go_forward:
2599  * @web_view: a #WebKitWebView
2600  *
2601  * Determines whether @web_view has a next history item.
2602  *
2603  * Returns: %TRUE if able to move forward or %FALSE otherwise.
2604  */
2605 gboolean webkit_web_view_can_go_forward(WebKitWebView* webView)
2606 {
2607     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2608
2609     return !!getPage(webView)->backForwardList().forwardItem();
2610 }
2611
2612 /**
2613  * webkit_web_view_get_uri:
2614  * @web_view: a #WebKitWebView
2615  *
2616  * Returns the current active URI of @web_view. The active URI might change during
2617  * a load operation:
2618  *
2619  * <orderedlist>
2620  * <listitem><para>
2621  *   When nothing has been loaded yet on @web_view the active URI is %NULL.
2622  * </para></listitem>
2623  * <listitem><para>
2624  *   When a new load operation starts the active URI is the requested URI:
2625  *   <itemizedlist>
2626  *   <listitem><para>
2627  *     If the load operation was started by webkit_web_view_load_uri(),
2628  *     the requested URI is the given one.
2629  *   </para></listitem>
2630  *   <listitem><para>
2631  *     If the load operation was started by webkit_web_view_load_html(),
2632  *     the requested URI is "about:blank".
2633  *   </para></listitem>
2634  *   <listitem><para>
2635  *     If the load operation was started by webkit_web_view_load_alternate_html(),
2636  *     the requested URI is content URI provided.
2637  *   </para></listitem>
2638  *   <listitem><para>
2639  *     If the load operation was started by webkit_web_view_go_back() or
2640  *     webkit_web_view_go_forward(), the requested URI is the original URI
2641  *     of the previous/next item in the #WebKitBackForwardList of @web_view.
2642  *   </para></listitem>
2643  *   <listitem><para>
2644  *     If the load operation was started by
2645  *     webkit_web_view_go_to_back_forward_list_item(), the requested URI
2646  *     is the opriginal URI of the given #WebKitBackForwardListItem.
2647  *   </para></listitem>
2648  *   </itemizedlist>
2649  * </para></listitem>
2650  * <listitem><para>
2651  *   If there is a server redirection during the load operation,
2652  *   the active URI is the redirected URI. When the signal
2653  *   #WebKitWebView::load-changed is emitted with %WEBKIT_LOAD_REDIRECTED
2654  *   event, the active URI is already updated to the redirected URI.
2655  * </para></listitem>
2656  * <listitem><para>
2657  *   When the signal #WebKitWebView::load-changed is emitted
2658  *   with %WEBKIT_LOAD_COMMITTED event, the active URI is the final
2659  *   one and it will not change unless a new load operation is started
2660  *   or a navigation action within the same page is performed.
2661  * </para></listitem>
2662  * </orderedlist>
2663  *
2664  * You can monitor the active URI by connecting to the notify::uri
2665  * signal of @web_view.
2666  *
2667  * Returns: the current active URI of @web_view or %NULL
2668  *    if nothing has been loaded yet.
2669  */
2670 const gchar* webkit_web_view_get_uri(WebKitWebView* webView)
2671 {
2672     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2673
2674     return webView->priv->activeURI.data();
2675 }
2676
2677 /**
2678  * webkit_web_view_get_favicon:
2679  * @web_view: a #WebKitWebView
2680  *
2681  * Returns favicon currently associated to @web_view, if any. You can
2682  * connect to notify::favicon signal of @web_view to be notified when
2683  * the favicon is available.
2684  *
2685  * Returns: (transfer none): a pointer to a #cairo_surface_t with the
2686  *    favicon or %NULL if there's no icon associated with @web_view.
2687  */
2688 cairo_surface_t* webkit_web_view_get_favicon(WebKitWebView* webView)
2689 {
2690     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2691     if (webView->priv->activeURI.isNull())
2692         return 0;
2693
2694     return webView->priv->favicon.get();
2695 }
2696
2697 /**
2698  * webkit_web_view_get_custom_charset:
2699  * @web_view: a #WebKitWebView
2700  *
2701  * Returns the current custom character encoding name of @web_view.
2702  *
2703  * Returns: the current custom character encoding name or %NULL if no
2704  *    custom character encoding has been set.
2705  */
2706 const gchar* webkit_web_view_get_custom_charset(WebKitWebView* webView)
2707 {
2708     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2709
2710     String customTextEncoding = getPage(webView)->customTextEncodingName();
2711     if (customTextEncoding.isEmpty())
2712         return 0;
2713
2714     webView->priv->customTextEncoding = customTextEncoding.utf8();
2715     return webView->priv->customTextEncoding.data();
2716 }
2717
2718 /**
2719  * webkit_web_view_set_custom_charset:
2720  * @web_view: a #WebKitWebView
2721  * @charset: (allow-none): a character encoding name or %NULL
2722  *
2723  * Sets the current custom character encoding override of @web_view. The custom
2724  * character encoding will override any text encoding detected via HTTP headers or
2725  * META tags. Calling this method will stop any current load operation and reload the
2726  * current page. Setting the custom character encoding to %NULL removes the character
2727  * encoding override.
2728  */
2729 void webkit_web_view_set_custom_charset(WebKitWebView* webView, const gchar* charset)
2730 {
2731     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2732
2733     getPage(webView)->setCustomTextEncodingName(String::fromUTF8(charset));
2734 }
2735
2736 /**
2737  * webkit_web_view_get_estimated_load_progress:
2738  * @web_view: a #WebKitWebView
2739  *
2740  * Gets the value of the #WebKitWebView:estimated-load-progress property.
2741  * You can monitor the estimated progress of a load operation by
2742  * connecting to the notify::estimated-load-progress signal of @web_view.
2743  *
2744  * Returns: an estimate of the of the percent complete for a document
2745  *     load as a range from 0.0 to 1.0.
2746  */
2747 gdouble webkit_web_view_get_estimated_load_progress(WebKitWebView* webView)
2748 {
2749     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2750     return getPage(webView)->pageLoadState().estimatedProgress();
2751 }
2752
2753 /**
2754  * webkit_web_view_get_back_forward_list:
2755  * @web_view: a #WebKitWebView
2756  *
2757  * Obtains the #WebKitBackForwardList associated with the given #WebKitWebView. The
2758  * #WebKitBackForwardList is owned by the #WebKitWebView.
2759  *
2760  * Returns: (transfer none): the #WebKitBackForwardList
2761  */
2762 WebKitBackForwardList* webkit_web_view_get_back_forward_list(WebKitWebView* webView)
2763 {
2764     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2765
2766     return webView->priv->backForwardList.get();
2767 }
2768
2769 /**
2770  * webkit_web_view_go_to_back_forward_list_item:
2771  * @web_view: a #WebKitWebView
2772  * @list_item: a #WebKitBackForwardListItem
2773  *
2774  * Loads the specific history item @list_item.
2775  * You can monitor the load operation by connecting to
2776  * #WebKitWebView::load-changed signal.
2777  */
2778 void webkit_web_view_go_to_back_forward_list_item(WebKitWebView* webView, WebKitBackForwardListItem* listItem)
2779 {
2780     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2781     g_return_if_fail(WEBKIT_IS_BACK_FORWARD_LIST_ITEM(listItem));
2782
2783     getPage(webView)->goToBackForwardItem(webkitBackForwardListItemGetItem(listItem));
2784 }
2785
2786 /**
2787  * webkit_web_view_set_settings:
2788  * @web_view: a #WebKitWebView
2789  * @settings: a #WebKitSettings
2790  *
2791  * Sets the #WebKitSettings to be applied to @web_view. The
2792  * existing #WebKitSettings of @web_view will be replaced by
2793  * @settings. New settings are applied immediately on @web_view.
2794  * The same #WebKitSettings object can be shared
2795  * by multiple #WebKitWebView<!-- -->s.
2796  */
2797 void webkit_web_view_set_settings(WebKitWebView* webView, WebKitSettings* settings)
2798 {
2799     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2800     g_return_if_fail(WEBKIT_IS_SETTINGS(settings));
2801
2802     if (webView->priv->settings == settings)
2803         return;
2804
2805     // The "settings" property is set on construction, and in that
2806     // case webkit_web_view_set_settings() will be called *before*
2807     // any settings have been assigned. In that case there are no
2808     // signal handlers to disconnect.
2809     if (webView->priv->settings)
2810         webkitWebViewDisconnectSettingsSignalHandlers(webView);
2811
2812     webView->priv->settings = settings;
2813     webkitWebViewUpdateSettings(webView);
2814     g_object_notify(G_OBJECT(webView), "settings");
2815 }
2816
2817 /**
2818  * webkit_web_view_get_settings:
2819  * @web_view: a #WebKitWebView
2820  *
2821  * Gets the #WebKitSettings currently applied to @web_view.
2822  * If no other #WebKitSettings have been explicitly applied to
2823  * @web_view with webkit_web_view_set_settings(), the default
2824  * #WebKitSettings will be returned. This method always returns
2825  * a valid #WebKitSettings object.
2826  * To modify any of the @web_view settings, you can either create
2827  * a new #WebKitSettings object with webkit_settings_new(), setting
2828  * the desired preferences, and then replace the existing @web_view
2829  * settings with webkit_web_view_set_settings() or get the existing
2830  * @web_view settings and update it directly. #WebKitSettings objects
2831  * can be shared by multiple #WebKitWebView<!-- -->s, so modifying
2832  * the settings of a #WebKitWebView would affect other
2833  * #WebKitWebView<!-- -->s using the same #WebKitSettings.
2834  *
2835  * Returns: (transfer none): the #WebKitSettings attached to @web_view
2836  */
2837 WebKitSettings* webkit_web_view_get_settings(WebKitWebView* webView)
2838 {
2839     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr);
2840     return webView->priv->settings.get();
2841 }
2842
2843 /**
2844  * webkit_web_view_get_window_properties:
2845  * @web_view: a #WebKitWebView
2846  *
2847  * Get the #WebKitWindowProperties object containing the properties
2848  * that the window containing @web_view should have.
2849  *
2850  * Returns: (transfer none): the #WebKitWindowProperties of @web_view
2851  */
2852 WebKitWindowProperties* webkit_web_view_get_window_properties(WebKitWebView* webView)
2853 {
2854     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2855
2856     return webView->priv->windowProperties.get();
2857 }
2858
2859 /**
2860  * webkit_web_view_set_zoom_level:
2861  * @web_view: a #WebKitWebView
2862  * @zoom_level: the zoom level
2863  *
2864  * Set the zoom level of @web_view, i.e. the factor by which the
2865  * view contents are scaled with respect to their original size.
2866  */
2867 void webkit_web_view_set_zoom_level(WebKitWebView* webView, gdouble zoomLevel)
2868 {
2869     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2870
2871     if (webkit_web_view_get_zoom_level(webView) == zoomLevel)
2872         return;
2873
2874     WebPageProxy* page = getPage(webView);
2875     if (webkit_settings_get_zoom_text_only(webView->priv->settings.get()))
2876         page->setTextZoomFactor(zoomLevel);
2877     else
2878         page->setPageZoomFactor(zoomLevel);
2879     g_object_notify(G_OBJECT(webView), "zoom-level");
2880 }
2881
2882 /**
2883  * webkit_web_view_get_zoom_level:
2884  * @web_view: a #WebKitWebView
2885  *
2886  * Get the zoom level of @web_view, i.e. the factor by which the
2887  * view contents are scaled with respect to their original size.
2888  *
2889  * Returns: the current zoom level of @web_view
2890  */
2891 gdouble webkit_web_view_get_zoom_level(WebKitWebView* webView)
2892 {
2893     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 1);
2894
2895     WebPageProxy* page = getPage(webView);
2896     gboolean zoomTextOnly = webkit_settings_get_zoom_text_only(webView->priv->settings.get());
2897     return zoomTextOnly ? page->textZoomFactor() : page->pageZoomFactor();
2898 }
2899
2900 /**
2901  * webkit_web_view_can_execute_editing_command:
2902  * @web_view: a #WebKitWebView
2903  * @command: the command to check
2904  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
2905  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
2906  * @user_data: (closure): the data to pass to callback function
2907  *
2908  * Asynchronously execute the given editing command.
2909  *
2910  * When the operation is finished, @callback will be called. You can then call
2911  * webkit_web_view_can_execute_editing_command_finish() to get the result of the operation.
2912  */
2913 void webkit_web_view_can_execute_editing_command(WebKitWebView* webView, const char* command, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
2914 {
2915     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2916     g_return_if_fail(command);
2917
2918     GTask* task = g_task_new(webView, cancellable, callback, userData);
2919     getPage(webView)->validateCommand(String::fromUTF8(command), [task](const String&, bool isEnabled, int32_t, WebKit::CallbackBase::Error) {
2920         g_task_return_boolean(adoptGRef(task).get(), isEnabled);        
2921     });
2922 }
2923
2924 /**
2925  * webkit_web_view_can_execute_editing_command_finish:
2926  * @web_view: a #WebKitWebView
2927  * @result: a #GAsyncResult
2928  * @error: return location for error or %NULL to ignore
2929  *
2930  * Finish an asynchronous operation started with webkit_web_view_can_execute_editing_command().
2931  *
2932  * Returns: %TRUE if the editing command can be executed or %FALSE otherwise
2933  */
2934 gboolean webkit_web_view_can_execute_editing_command_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
2935 {
2936     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2937     g_return_val_if_fail(g_task_is_valid(result, webView), FALSE);
2938
2939     return g_task_propagate_boolean(G_TASK(result), error);
2940 }
2941
2942 /**
2943  * webkit_web_view_execute_editing_command:
2944  * @web_view: a #WebKitWebView
2945  * @command: the command to execute
2946  *
2947  * Request to execute the given @command for @web_view. You can use
2948  * webkit_web_view_can_execute_editing_command() to check whether
2949  * it's possible to execute the command.
2950  */
2951 void webkit_web_view_execute_editing_command(WebKitWebView* webView, const char* command)
2952 {
2953     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2954     g_return_if_fail(command);
2955
2956     getPage(webView)->executeEditCommand(String::fromUTF8(command));
2957 }
2958
2959 /**
2960  * webkit_web_view_execute_editing_command_with_argument:
2961  * @web_view: a #WebKitWebView
2962  * @command: the command to execute
2963  * @argument: the command argument
2964  *
2965  * Request to execute the given @command with @argument for @web_view. You can use
2966  * webkit_web_view_can_execute_editing_command() to check whether
2967  * it's possible to execute the command.
2968  *
2969  * Since: 2.10
2970  */
2971 void webkit_web_view_execute_editing_command_with_argument(WebKitWebView* webView, const char* command, const char* argument)
2972 {
2973     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2974     g_return_if_fail(command);
2975     g_return_if_fail(argument);
2976
2977     getPage(webView)->executeEditCommand(String::fromUTF8(command), String::fromUTF8(argument));
2978 }
2979
2980 /**
2981  * webkit_web_view_get_find_controller:
2982  * @web_view: the #WebKitWebView
2983  *
2984  * Gets the #WebKitFindController that will allow the caller to query
2985  * the #WebKitWebView for the text to look for.
2986  *
2987  * Returns: (transfer none): the #WebKitFindController associated to
2988  * this particular #WebKitWebView.
2989  */
2990 WebKitFindController* webkit_web_view_get_find_controller(WebKitWebView* webView)
2991 {
2992     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2993
2994     if (!webView->priv->findController)
2995         webView->priv->findController = adoptGRef(WEBKIT_FIND_CONTROLLER(g_object_new(WEBKIT_TYPE_FIND_CONTROLLER, "web-view", webView, NULL)));
2996
2997     return webView->priv->findController.get();
2998 }
2999
3000 /**
3001  * webkit_web_view_get_javascript_global_context:
3002  * @web_view: a #WebKitWebView
3003  *
3004  * Get the global JavaScript context used by @web_view to deserialize the
3005  * result values of scripts executed with webkit_web_view_run_javascript().
3006  *
3007  * Returns: the <function>JSGlobalContextRef</function> used by @web_view to deserialize
3008  *    the result values of scripts.
3009  */
3010 JSGlobalContextRef webkit_web_view_get_javascript_global_context(WebKitWebView* webView)
3011 {
3012     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3013
3014     if (!webView->priv->javascriptGlobalContext)
3015         webView->priv->javascriptGlobalContext = JSGlobalContextCreate(0);
3016     return webView->priv->javascriptGlobalContext;
3017 }
3018
3019 static void webkitWebViewRunJavaScriptCallback(API::SerializedScriptValue* wkSerializedScriptValue, GTask* task)
3020 {
3021     if (g_task_return_error_if_cancelled(task))
3022         return;
3023
3024     if (!wkSerializedScriptValue) {
3025         g_task_return_new_error(task, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED,
3026             _("An exception was raised in JavaScript"));
3027         return;
3028     }
3029
3030     WebKitWebView* webView = WEBKIT_WEB_VIEW(g_task_get_source_object(task));
3031     g_task_return_pointer(task, webkitJavascriptResultCreate(webView,
3032         *wkSerializedScriptValue->internalRepresentation()),
3033         reinterpret_cast<GDestroyNotify>(webkit_javascript_result_unref));
3034 }
3035
3036 /**
3037  * webkit_web_view_run_javascript:
3038  * @web_view: a #WebKitWebView
3039  * @script: the script to run
3040  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
3041  * @callback: (scope async): a #GAsyncReadyCallback to call when the script finished
3042  * @user_data: (closure): the data to pass to callback function
3043  *
3044  * Asynchronously run @script in the context of the current page in @web_view. If
3045  * WebKitWebSettings:enable-javascript is FALSE, this method will do nothing.
3046  *
3047  * When the operation is finished, @callback will be called. You can then call
3048  * webkit_web_view_run_javascript_finish() to get the result of the operation.
3049  */
3050 void webkit_web_view_run_javascript(WebKitWebView* webView, const gchar* script, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3051 {
3052     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3053     g_return_if_fail(script);
3054
3055     GTask* task = g_task_new(webView, cancellable, callback, userData);
3056     getPage(webView)->runJavaScriptInMainFrame(String::fromUTF8(script), [task](API::SerializedScriptValue* serializedScriptValue, bool, WebKit::CallbackBase::Error) {
3057         webkitWebViewRunJavaScriptCallback(serializedScriptValue, adoptGRef(task).get());
3058     });
3059 }
3060
3061 /**
3062  * webkit_web_view_run_javascript_finish:
3063  * @web_view: a #WebKitWebView
3064  * @result: a #GAsyncResult
3065  * @error: return location for error or %NULL to ignore
3066  *
3067  * Finish an asynchronous operation started with webkit_web_view_run_javascript().
3068  *
3069  * This is an example of using webkit_web_view_run_javascript() with a script returning
3070  * a string:
3071  *
3072  * <informalexample><programlisting>
3073  * static void
3074  * web_view_javascript_finished (GObject      *object,
3075  *                               GAsyncResult *result,
3076  *                               gpointer      user_data)
3077  * {
3078  *     WebKitJavascriptResult *js_result;
3079  *     JSValueRef              value;
3080  *     JSGlobalContextRef      context;
3081  *     GError                 *error = NULL;
3082  *
3083  *     js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (object), result, &error);
3084  *     if (!js_result) {
3085  *         g_warning ("Error running javascript: %s", error->message);
3086  *         g_error_free (error);
3087  *         return;
3088  *     }
3089  *
3090  *     context = webkit_javascript_result_get_global_context (js_result);
3091  *     value = webkit_javascript_result_get_value (js_result);
3092  *     if (JSValueIsString (context, value)) {
3093  *         JSStringRef js_str_value;
3094  *         gchar      *str_value;
3095  *         gsize       str_length;
3096  *
3097  *         js_str_value = JSValueToStringCopy (context, value, NULL);
3098  *         str_length = JSStringGetMaximumUTF8CStringSize (js_str_value);
3099  *         str_value = (gchar *)g_malloc (str_length);
3100  *         JSStringGetUTF8CString (js_str_value, str_value, str_length);
3101  *         JSStringRelease (js_str_value);
3102  *         g_print ("Script result: %s\n", str_value);
3103  *         g_free (str_value);
3104  *     } else {
3105  *         g_warning ("Error running javascript: unexpected return value");
3106  *     }
3107  *     webkit_javascript_result_unref (js_result);
3108  * }
3109  *
3110  * static void
3111  * web_view_get_link_url (WebKitWebView *web_view,
3112  *                        const gchar   *link_id)
3113  * {
3114  *     gchar *script;
3115  *
3116  *     script = g_strdup_printf ("window.document.getElementById('%s').href;", link_id);
3117  *     webkit_web_view_run_javascript (web_view, script, NULL, web_view_javascript_finished, NULL);
3118  *     g_free (script);
3119  * }
3120  * </programlisting></informalexample>
3121  *
3122  * Returns: (transfer full): a #WebKitJavascriptResult with the result of the last executed statement in @script
3123  *    or %NULL in case of error
3124  */
3125 WebKitJavascriptResult* webkit_web_view_run_javascript_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3126 {
3127     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3128     g_return_val_if_fail(g_task_is_valid(result, webView), 0);
3129
3130     return static_cast<WebKitJavascriptResult*>(g_task_propagate_pointer(G_TASK(result), error));
3131 }
3132
3133 static void resourcesStreamReadCallback(GObject* object, GAsyncResult* result, gpointer userData)
3134 {
3135     GRefPtr<GTask> task = adoptGRef(G_TASK(userData));
3136
3137     GError* error = 0;
3138     g_output_stream_splice_finish(G_OUTPUT_STREAM(object), result, &error);
3139     if (error) {
3140         g_task_return_error(task.get(), error);
3141         return;
3142     }
3143
3144     WebKitWebView* webView = WEBKIT_WEB_VIEW(g_task_get_source_object(task.get()));
3145     gpointer outputStreamData = g_memory_output_stream_get_data(G_MEMORY_OUTPUT_STREAM(object));
3146     getPage(webView)->runJavaScriptInMainFrame(String::fromUTF8(reinterpret_cast<const gchar*>(outputStreamData)),
3147         [task](API::SerializedScriptValue* serializedScriptValue, bool, WebKit::CallbackBase::Error) {
3148             webkitWebViewRunJavaScriptCallback(serializedScriptValue, task.get());
3149         });
3150 }
3151
3152 /**
3153  * webkit_web_view_run_javascript_from_gresource:
3154  * @web_view: a #WebKitWebView
3155  * @resource: the location of the resource to load
3156  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
3157  * @callback: (scope async): a #GAsyncReadyCallback to call when the script finished
3158  * @user_data: (closure): the data to pass to callback function
3159  *
3160  * Asynchronously run the script from @resource in the context of the
3161  * current page in @web_view.
3162  *
3163  * When the operation is finished, @callback will be called. You can
3164  * then call webkit_web_view_run_javascript_from_gresource_finish() to get the result
3165  * of the operation.
3166  */
3167 void webkit_web_view_run_javascript_from_gresource(WebKitWebView* webView, const gchar* resource, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3168 {
3169     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3170     g_return_if_fail(resource);
3171
3172     GError* error = 0;
3173     GRefPtr<GInputStream> inputStream = adoptGRef(g_resources_open_stream(resource, G_RESOURCE_LOOKUP_FLAGS_NONE, &error));
3174     if (error) {
3175         g_task_report_error(webView, callback, userData, 0, error);
3176         return;
3177     }
3178
3179     GTask* task = g_task_new(webView, cancellable, callback, userData);
3180     GRefPtr<GOutputStream> outputStream = adoptGRef(g_memory_output_stream_new(0, 0, fastRealloc, fastFree));
3181     g_output_stream_splice_async(outputStream.get(), inputStream.get(),
3182         static_cast<GOutputStreamSpliceFlags>(G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET),
3183         G_PRIORITY_DEFAULT, cancellable, resourcesStreamReadCallback, task);
3184 }
3185
3186 /**
3187  * webkit_web_view_run_javascript_from_gresource_finish:
3188  * @web_view: a #WebKitWebView
3189  * @result: a #GAsyncResult
3190  * @error: return location for error or %NULL to ignore
3191  *
3192  * Finish an asynchronous operation started with webkit_web_view_run_javascript_from_gresource().
3193  *
3194  * Check webkit_web_view_run_javascript_finish() for a usage example.
3195  *
3196  * Returns: (transfer full): a #WebKitJavascriptResult with the result of the last executed statement in @script
3197  *    or %NULL in case of error
3198  */
3199 WebKitJavascriptResult* webkit_web_view_run_javascript_from_gresource_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3200 {
3201     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3202     g_return_val_if_fail(g_task_is_valid(result, webView), 0);
3203
3204     return static_cast<WebKitJavascriptResult*>(g_task_propagate_pointer(G_TASK(result), error));
3205 }
3206
3207 /**
3208  * webkit_web_view_get_main_resource:
3209  * @web_view: a #WebKitWebView
3210  *
3211  * Return the main resource of @web_view.
3212  *
3213  * Returns: (transfer none): the main #WebKitWebResource of the view
3214  *    or %NULL if nothing has been loaded.
3215  */
3216 WebKitWebResource* webkit_web_view_get_main_resource(WebKitWebView* webView)
3217 {
3218     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3219
3220     return webView->priv->mainResource.get();
3221 }
3222
3223 /**
3224  * webkit_web_view_get_inspector:
3225  * @web_view: a #WebKitWebView
3226  *
3227  * Get the #WebKitWebInspector associated to @web_view
3228  *
3229  * Returns: (transfer none): the #WebKitWebInspector of @web_view
3230  */
3231 WebKitWebInspector* webkit_web_view_get_inspector(WebKitWebView* webView)
3232 {
3233     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3234
3235     if (!webView->priv->inspector)
3236         webView->priv->inspector = adoptGRef(webkitWebInspectorCreate(getPage(webView)->inspector()));
3237
3238     return webView->priv->inspector.get();
3239 }
3240
3241 /**
3242  * webkit_web_view_can_show_mime_type:
3243  * @web_view: a #WebKitWebView
3244  * @mime_type: a MIME type
3245  *
3246  * Whether or not a MIME type can be displayed in @web_view.
3247  *
3248  * Returns: %TRUE if the MIME type @mime_type can be displayed or %FALSE otherwise
3249  */
3250 gboolean webkit_web_view_can_show_mime_type(WebKitWebView* webView, const char* mimeType)
3251 {
3252     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
3253     g_return_val_if_fail(mimeType, FALSE);
3254
3255     return getPage(webView)->canShowMIMEType(String::fromUTF8(mimeType));
3256 }
3257
3258 struct ViewSaveAsyncData {
3259     RefPtr<API::Data> webData;
3260     GRefPtr<GFile> file;
3261 };
3262 WEBKIT_DEFINE_ASYNC_DATA_STRUCT(ViewSaveAsyncData)
3263
3264 static void fileReplaceContentsCallback(GObject* object, GAsyncResult* result, gpointer data)
3265 {
3266     GRefPtr<GTask> task = adoptGRef(G_TASK(data));
3267     GError* error = 0;
3268     if (!g_file_replace_contents_finish(G_FILE(object), result, 0, &error)) {
3269         g_task_return_error(task.get(), error);
3270         return;
3271     }
3272
3273     g_task_return_boolean(task.get(), TRUE);
3274 }
3275
3276 static void getContentsAsMHTMLDataCallback(API::Data* wkData, GTask* taskPtr)
3277 {
3278     GRefPtr<GTask> task = adoptGRef(taskPtr);
3279     if (g_task_return_error_if_cancelled(task.get()))
3280         return;
3281
3282     ViewSaveAsyncData* data = static_cast<ViewSaveAsyncData*>(g_task_get_task_data(task.get()));
3283     // We need to retain the data until the asyncronous process
3284     // initiated by the user has finished completely.
3285     data->webData = wkData;
3286
3287     // If we are saving to a file we need to write the data on disk before finishing.
3288     if (g_task_get_source_tag(task.get()) == webkit_web_view_save_to_file) {
3289         ASSERT(G_IS_FILE(data->file.get()));
3290         GCancellable* cancellable = g_task_get_cancellable(task.get());
3291         g_file_replace_contents_async(data->file.get(), reinterpret_cast<const gchar*>(data->webData->bytes()), data->webData->size(),
3292             0, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, cancellable, fileReplaceContentsCallback, task.leakRef());
3293         return;
3294     }
3295
3296     g_task_return_boolean(task.get(), TRUE);
3297 }
3298
3299 /**
3300  * webkit_web_view_save:
3301  * @web_view: a #WebKitWebView
3302  * @save_mode: the #WebKitSaveMode specifying how the web page should be saved.
3303  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
3304  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
3305  * @user_data: (closure): the data to pass to callback function
3306  *
3307  * Asynchronously save the current web page associated to the
3308  * #WebKitWebView into a self-contained format using the mode
3309  * specified in @save_mode.
3310  *
3311  * When the operation is finished, @callback will be called. You can
3312  * then call webkit_web_view_save_finish() to get the result of the
3313  * operation.
3314  */
3315 void webkit_web_view_save(WebKitWebView* webView, WebKitSaveMode saveMode, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3316 {
3317     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3318
3319     // We only support MHTML at the moment.
3320     g_return_if_fail(saveMode == WEBKIT_SAVE_MODE_MHTML);
3321
3322     GTask* task = g_task_new(webView, cancellable, callback, userData);
3323     g_task_set_source_tag(task, reinterpret_cast<gpointer>(webkit_web_view_save));
3324     g_task_set_task_data(task, createViewSaveAsyncData(), reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData));
3325     getPage(webView)->getContentsAsMHTMLData([task](API::Data* data, WebKit::CallbackBase::Error) {
3326         getContentsAsMHTMLDataCallback(data, task);
3327     }, false);
3328 }
3329
3330 /**
3331  * webkit_web_view_save_finish:
3332  * @web_view: a #WebKitWebView
3333  * @result: a #GAsyncResult
3334  * @error: return location for error or %NULL to ignore
3335  *
3336  * Finish an asynchronous operation started with webkit_web_view_save().
3337  *
3338  * Returns: (transfer full): a #GInputStream with the result of saving
3339  *    the current web page or %NULL in case of error.
3340  */
3341 GInputStream* webkit_web_view_save_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3342 {
3343     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3344     g_return_val_if_fail(g_task_is_valid(result, webView), 0);
3345
3346     GTask* task = G_TASK(result);
3347     if (!g_task_propagate_boolean(task, error))
3348         return 0;
3349
3350     GInputStream* dataStream = g_memory_input_stream_new();
3351     ViewSaveAsyncData* data = static_cast<ViewSaveAsyncData*>(g_task_get_task_data(task));
3352     gsize length = data->webData->size();
3353     if (length)
3354         g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(dataStream), g_memdup(data->webData->bytes(), length), length, g_free);
3355
3356     return dataStream;
3357 }
3358
3359 /**
3360  * webkit_web_view_save_to_file:
3361  * @web_view: a #WebKitWebView
3362  * @file: the #GFile where the current web page should be saved to.
3363  * @save_mode: the #WebKitSaveMode specifying how the web page should be saved.
3364  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
3365  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
3366  * @user_data: (closure): the data to pass to callback function
3367  *
3368  * Asynchronously save the current web page associated to the
3369  * #WebKitWebView into a self-contained format using the mode
3370  * specified in @save_mode and writing it to @file.
3371  *
3372  * When the operation is finished, @callback will be called. You can
3373  * then call webkit_web_view_save_to_file_finish() to get the result of the
3374  * operation.
3375  */
3376 void webkit_web_view_save_to_file(WebKitWebView* webView, GFile* file, WebKitSaveMode saveMode, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3377 {
3378     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3379     g_return_if_fail(G_IS_FILE(file));
3380
3381     // We only support MHTML at the moment.
3382     g_return_if_fail(saveMode == WEBKIT_SAVE_MODE_MHTML);
3383
3384     GTask* task = g_task_new(webView, cancellable, callback, userData);
3385     g_task_set_source_tag(task, reinterpret_cast<gpointer>(webkit_web_view_save_to_file));
3386     ViewSaveAsyncData* data = createViewSaveAsyncData();
3387     data->file = file;
3388     g_task_set_task_data(task, data, reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData));
3389
3390     getPage(webView)->getContentsAsMHTMLData([task](API::Data* data, WebKit::CallbackBase::Error) {
3391         getContentsAsMHTMLDataCallback(data, task);
3392     }, false);
3393 }
3394
3395 /**
3396  * webkit_web_view_save_to_file_finish:
3397  * @web_view: a #WebKitWebView
3398  * @result: a #GAsyncResult
3399  * @error: return location for error or %NULL to ignore
3400  *
3401  * Finish an asynchronous operation started with webkit_web_view_save_to_file().
3402  *
3403  * Returns: %TRUE if the web page was successfully saved to a file or %FALSE otherwise.
3404  */
3405 gboolean webkit_web_view_save_to_file_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3406 {
3407     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
3408     g_return_val_if_fail(g_task_is_valid(result, webView), FALSE);
3409
3410     return g_task_propagate_boolean(G_TASK(result), error);
3411 }
3412
3413 /**
3414  * webkit_web_view_download_uri:
3415  * @web_view: a #WebKitWebView
3416  * @uri: the URI to download
3417  *
3418  * Requests downloading of the specified URI string for @web_view.
3419  *
3420  * Returns: (transfer full): a new #WebKitDownload representing the
3421  *    the download operation.
3422  */
3423 WebKitDownload* webkit_web_view_download_uri(WebKitWebView* webView, const char* uri)
3424 {
3425     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3426     g_return_val_if_fail(uri, 0);
3427
3428     WebKitDownload* download = webkitWebContextStartDownload(webView->priv->context.get(), uri, getPage(webView));
3429     webkitDownloadSetWebView(download, webView);
3430
3431     return download;
3432 }
3433
3434 /**
3435  * webkit_web_view_get_tls_info:
3436  * @web_view: a #WebKitWebView
3437  * @certificate: (out) (transfer none): return location for a #GTlsCertificate
3438  * @errors: (out): return location for a #GTlsCertificateFlags the verification status of @certificate
3439  *
3440  * Retrieves the #GTlsCertificate associated with the main resource of @web_view,
3441  * and the #GTlsCertificateFlags showing what problems, if any, have been found
3442  * with that certificate.
3443  * If the connection is not HTTPS, this function returns %FALSE.
3444  * This function should be called after a response has been received from the
3445  * server, so you can connect to #WebKitWebView::load-changed and call this function
3446  * when it's emitted with %WEBKIT_LOAD_COMMITTED event.
3447  *
3448  * Note that this function provides no information about the security of the web
3449  * page if the current #WebKitTLSErrorsPolicy is @WEBKIT_TLS_ERRORS_POLICY_IGNORE,
3450  * as subresources of the page may be controlled by an attacker. This function
3451  * may safely be used to determine the security status of the current page only
3452  * if the current #WebKitTLSErrorsPolicy is @WEBKIT_TLS_ERRORS_POLICY_FAIL, in
3453  * which case subresources that fail certificate verification will be blocked.
3454  *
3455  * Returns: %TRUE if the @web_view connection uses HTTPS and a response has been received
3456  *    from the server, or %FALSE otherwise.
3457  */
3458 gboolean webkit_web_view_get_tls_info(WebKitWebView* webView, GTlsCertificate** certificate, GTlsCertificateFlags* errors)
3459 {
3460     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
3461
3462     WebFrameProxy* mainFrame = getPage(webView)->mainFrame();
3463     if (!mainFrame)
3464         return FALSE;
3465
3466     const WebCore::CertificateInfo& certificateInfo = mainFrame->certificateInfo()->certificateInfo();
3467     if (certificate)
3468         *certificate = certificateInfo.certificate();
3469     if (errors)
3470         *errors = certificateInfo.tlsErrors();
3471
3472     return !!certificateInfo.certificate();
3473 }
3474
3475 void webKitWebViewDidReceiveSnapshot(WebKitWebView* webView, uint64_t callbackID, WebImage* webImage)
3476 {
3477     GRefPtr<GTask> task = webView->priv->snapshotResultsMap.take(callbackID);
3478     if (g_task_return_error_if_cancelled(task.get()))
3479         return;
3480
3481     if (!webImage) {
3482         g_task_return_new_error(task.get(), WEBKIT_SNAPSHOT_ERROR, WEBKIT_SNAPSHOT_ERROR_FAILED_TO_CREATE,
3483             _("There was an error creating the snapshot"));
3484         return;
3485     }
3486
3487     if (RefPtr<ShareableBitmap> image = webImage->bitmap())
3488         g_task_return_pointer(task.get(), image->createCairoSurface().leakRef(), reinterpret_cast<GDestroyNotify>(cairo_surface_destroy));
3489     else
3490         g_task_return_pointer(task.get(), 0, 0);
3491 }
3492
3493 static inline unsigned webKitSnapshotOptionsToSnapshotOptions(WebKitSnapshotOptions options)
3494 {
3495     SnapshotOptions snapshotOptions = 0;
3496
3497     if (!(options & WEBKIT_SNAPSHOT_OPTIONS_INCLUDE_SELECTION_HIGHLIGHTING))
3498         snapshotOptions |= SnapshotOptionsExcludeSelectionHighlighting;
3499
3500     return snapshotOptions;
3501 }
3502
3503 static inline SnapshotRegion toSnapshotRegion(WebKitSnapshotRegion region)
3504 {
3505     switch (region) {
3506     case WEBKIT_SNAPSHOT_REGION_VISIBLE:
3507         return SnapshotRegionVisible;
3508     case WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT:
3509         return SnapshotRegionFullDocument;
3510     default:
3511         ASSERT_NOT_REACHED();
3512         return SnapshotRegionVisible;
3513     }
3514 }
3515
3516 static inline uint64_t generateSnapshotCallbackID()
3517 {
3518     static uint64_t uniqueCallbackID = 1;
3519     return uniqueCallbackID++;
3520 }
3521
3522 /**
3523  * webkit_web_view_get_snapshot:
3524  * @web_view: a #WebKitWebView
3525  * @options: #WebKitSnapshotOptions for the snapshot
3526  * @region: the #WebKitSnapshotRegion for this snapshot
3527  * @cancellable: (allow-none): a #GCancellable
3528  * @callback: (scope async): a #GAsyncReadyCallback
3529  * @user_data: (closure): user data
3530  *
3531  * Asynchronously retrieves a snapshot of @web_view for @region.
3532  * @options specifies how the snapshot should be rendered.
3533  *
3534  * When the operation is finished, @callback will be called. You must
3535  * call webkit_web_view_get_snapshot_finish() to get the result of the
3536  * operation.
3537  */
3538 void webkit_web_view_get_snapshot(WebKitWebView* webView, WebKitSnapshotRegion region, WebKitSnapshotOptions options, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3539 {
3540     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3541
3542     API::Dictionary::MapType message;
3543     uint64_t callbackID = generateSnapshotCallbackID();
3544     message.set(String::fromUTF8("SnapshotOptions"), API::UInt64::create(static_cast<uint64_t>(webKitSnapshotOptionsToSnapshotOptions(options))));
3545     message.set(String::fromUTF8("SnapshotRegion"), API::UInt64::create(static_cast<uint64_t>(toSnapshotRegion(region))));
3546     message.set(String::fromUTF8("CallbackID"), API::UInt64::create(callbackID));
3547     message.set(String::fromUTF8("TransparentBackground"), API::Boolean::create(options & WEBKIT_SNAPSHOT_OPTIONS_TRANSPARENT_BACKGROUND));
3548
3549     webView->priv->snapshotResultsMap.set(callbackID, adoptGRef(g_task_new(webView, cancellable, callback, userData)));
3550     getPage(webView)->postMessageToInjectedBundle(String::fromUTF8("GetSnapshot"), API::Dictionary::create(WTF::move(message)).ptr());
3551 }
3552
3553 /**
3554  * webkit_web_view_get_snapshot_finish:
3555  * @web_view: a #WebKitWebView
3556  * @result: a #GAsyncResult
3557  * @error: return location for error or %NULL to ignore
3558  *
3559  * Finishes an asynchronous operation started with webkit_web_view_get_snapshot().
3560  *
3561  * Returns: (transfer full): a #cairo_surface_t with the retrieved snapshot or %NULL in error.
3562  */
3563 cairo_surface_t* webkit_web_view_get_snapshot_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3564 {
3565     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3566     g_return_val_if_fail(g_task_is_valid(result, webView), 0);
3567
3568     return static_cast<cairo_surface_t*>(g_task_propagate_pointer(G_TASK(result), error));
3569 }
3570
3571 void webkitWebViewWebProcessCrashed(WebKitWebView* webView)
3572 {
3573     gboolean returnValue;
3574     g_signal_emit(webView, signals[WEB_PROCESS_CRASHED], 0, &returnValue);
3575 }
3576
3577 /**
3578  * webkit_web_view_set_background_color:
3579  * @web_view: a #WebKitWebView
3580  * @rgba: a #GdkRGBA
3581  *
3582  * Sets the color that will be used to draw the @web_view background before
3583  * the actual contents are rendered. Note that if the web page loaded in @web_view
3584  * specifies a background color, it will take precedence over the @rgba color.
3585  * By default the @web_view background color is opaque white.
3586  * If the @rgba color is not fully opaque, the parent window must have a RGBA visual and
3587  * #GtkWidget:app-paintable property set to %TRUE, for the transparencies to work.
3588  *
3589  * <informalexample><programlisting>
3590  * static void browser_window_set_background_color (BrowserWindow *window,
3591  *                                                  const GdkRGBA *rgba)
3592  * {
3593  *     WebKitWebView *web_view;
3594  *
3595  *     if (rgba->alpha < 1) {
3596  *         GdkScreen *screen = gtk_window_get_screen (GTK_WINDOW (window));
3597  *         GdkVisual *rgba_visual = gdk_screen_get_rgba_visual (screen);
3598  *
3599  *         if (!rgba_visual)
3600  *              return;
3601  *
3602  *         gtk_widget_set_visual (GTK_WIDGET (window), rgba_visual);
3603  *         gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
3604  *     }
3605  *
3606  *     web_view = browser_window_get_web_view (window);
3607  *     webkit_web_view_set_background_color (web_view, rgba);
3608  * }
3609  * </programlisting></informalexample>
3610  *
3611  * Since: 2.8
3612  */
3613 void webkit_web_view_set_background_color(WebKitWebView* webView, const GdkRGBA* rgba)
3614 {
3615     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3616     g_return_if_fail(rgba);
3617
3618     Color color(*rgba);
3619     WebPageProxy* page = getPage(webView);
3620     if (page->backgroundColor() == color)
3621         return;
3622
3623     page->setBackgroundColor(color);
3624     page->setDrawsBackground(color == Color::white);
3625 }
3626
3627 /**
3628  * webkit_web_view_get_background_color:
3629  * @web_view: a #WebKitWebView
3630  * @rgba: (out): a #GdkRGBA to fill in with the background color
3631  *
3632  * Gets the color that is used to draw the @web_view background before
3633  * the actual contents are rendered.
3634  * For more information see also webkit_web_view_set_background_color()
3635  *
3636  * Since: 2.8
3637  */
3638 void webkit_web_view_get_background_color(WebKitWebView* webView, GdkRGBA* rgba)
3639 {
3640     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3641     g_return_if_fail(rgba);
3642
3643     *rgba = getPage(webView)->backgroundColor();
3644 }
3645
3646 /*
3647  * webkit_web_view_is_editable:
3648  * @web_view: a #WebKitWebView
3649  *
3650  * Gets whether the user is allowed to edit the HTML document. When @web_view
3651  * is not editable an element in the HTML document can only be edited if the
3652  * CONTENTEDITABLE attribute has been set on the element or one of its parent
3653  * elements. By default a #WebKitWebView is not editable.
3654  *
3655  * Returns: %TRUE if the user is allowed to edit the HTML document, or %FALSE otherwise.
3656  *
3657  * Since: 2.8
3658  */
3659 gboolean webkit_web_view_is_editable(WebKitWebView* webView)
3660 {
3661     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
3662
3663     return getPage(webView)->isEditable();
3664 }
3665
3666 /**
3667  * webkit_web_view_set_editable:
3668  * @web_view: a #WebKitWebView
3669  * @editable: a #gboolean indicating the editable state
3670  *
3671  * Sets whether the user is allowed to edit the HTML document.
3672  *
3673  * If @editable is %TRUE, @web_view allows the user to edit the HTML document. If
3674  * @editable is %FALSE, an element in @web_view's document can only be edited if the
3675  * CONTENTEDITABLE attribute has been set on the element or one of its parent
3676  * elements. By default a #WebKitWebView is not editable.
3677  *
3678  * Normally, a HTML document is not editable unless the elements within the
3679  * document are editable. This function provides a way to make the contents
3680  * of a #WebKitWebView editable without altering the document or DOM structure.
3681  *
3682  * Since: 2.8
3683  */
3684 void webkit_web_view_set_editable(WebKitWebView* webView, gboolean editable)
3685 {
3686     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3687
3688     if (editable == getPage(webView)->isEditable())
3689         return;
3690
3691     getPage(webView)->setEditable(editable);
3692
3693     g_object_notify(G_OBJECT(webView), "editable");
3694 }
3695
3696 /**
3697  * webkit_web_view_get_editor_state:
3698  * @web_view: a #WebKitWebView
3699  *
3700  * Gets the web editor state of @web_view.
3701  *
3702  * Returns: (transfer none): the #WebKitEditorState of the view
3703  *
3704  * Since: 2.10
3705  */
3706 WebKitEditorState* webkit_web_view_get_editor_state(WebKitWebView *webView)
3707 {
3708     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr);
3709
3710     if (!webView->priv->editorState)
3711         webView->priv->editorState = adoptGRef(webkitEditorStateCreate(getPage(webView)->editorState()));
3712
3713     return webView->priv->editorState.get();
3714 }