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