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