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