[WebKit2] [GTK] Add API for controlling the user agent
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / gtk / WebKitWebView.cpp
1 /*
2  * Copyright (C) 2011 Igalia S.L.
3  * Portions Copyright (c) 2011 Motorola Mobility, Inc.  All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22 #include "WebKitWebView.h"
23
24 #include "WebContextMenuItem.h"
25 #include "WebContextMenuItemData.h"
26 #include "WebKitBackForwardListPrivate.h"
27 #include "WebKitContextMenuClient.h"
28 #include "WebKitContextMenuItemPrivate.h"
29 #include "WebKitContextMenuPrivate.h"
30 #include "WebKitEnumTypes.h"
31 #include "WebKitError.h"
32 #include "WebKitFormClient.h"
33 #include "WebKitFullscreenClient.h"
34 #include "WebKitHitTestResultPrivate.h"
35 #include "WebKitJavascriptResultPrivate.h"
36 #include "WebKitLoaderClient.h"
37 #include "WebKitMarshal.h"
38 #include "WebKitPolicyClient.h"
39 #include "WebKitPrintOperationPrivate.h"
40 #include "WebKitPrivate.h"
41 #include "WebKitResourceLoadClient.h"
42 #include "WebKitResponsePolicyDecision.h"
43 #include "WebKitScriptDialogPrivate.h"
44 #include "WebKitSettingsPrivate.h"
45 #include "WebKitUIClient.h"
46 #include "WebKitURIResponsePrivate.h"
47 #include "WebKitWebContextPrivate.h"
48 #include "WebKitWebInspectorPrivate.h"
49 #include "WebKitWebResourcePrivate.h"
50 #include "WebKitWebViewBasePrivate.h"
51 #include "WebKitWebViewPrivate.h"
52 #include "WebKitWindowPropertiesPrivate.h"
53 #include "WebPageProxy.h"
54 #include <JavaScriptCore/APICast.h>
55 #include <WebCore/DragIcon.h>
56 #include <WebCore/GOwnPtrGtk.h>
57 #include <WebCore/GtkUtilities.h>
58 #include <glib/gi18n-lib.h>
59 #include <wtf/gobject/GOwnPtr.h>
60 #include <wtf/gobject/GRefPtr.h>
61 #include <wtf/text/CString.h>
62
63 using namespace WebKit;
64 using namespace WebCore;
65
66 enum {
67     LOAD_CHANGED,
68     LOAD_FAILED,
69
70     CREATE,
71     READY_TO_SHOW,
72     RUN_AS_MODAL,
73     CLOSE,
74
75     SCRIPT_DIALOG,
76
77     DECIDE_POLICY,
78     PERMISSION_REQUEST,
79
80     MOUSE_TARGET_CHANGED,
81
82     PRINT,
83
84     RESOURCE_LOAD_STARTED,
85
86     ENTER_FULLSCREEN,
87     LEAVE_FULLSCREEN,
88
89     RUN_FILE_CHOOSER,
90
91     CONTEXT_MENU,
92     CONTEXT_MENU_DISMISSED,
93
94     SUBMIT_FORM,
95
96     LAST_SIGNAL
97 };
98
99 enum {
100     PROP_0,
101
102     PROP_WEB_CONTEXT,
103     PROP_TITLE,
104     PROP_ESTIMATED_LOAD_PROGRESS,
105     PROP_URI,
106     PROP_ZOOM_LEVEL
107 };
108
109 typedef HashMap<uint64_t, GRefPtr<WebKitWebResource> > LoadingResourcesMap;
110 typedef HashMap<String, GRefPtr<WebKitWebResource> > ResourcesMap;
111
112 struct _WebKitWebViewPrivate {
113     WebKitWebContext* context;
114     CString title;
115     CString customTextEncoding;
116     double estimatedLoadProgress;
117     CString activeURI;
118
119     bool waitingForMainResource;
120     gulong mainResourceResponseHandlerID;
121     WebKitLoadEvent lastDelayedEvent;
122
123     GRefPtr<WebKitBackForwardList> backForwardList;
124     GRefPtr<WebKitSettings> settings;
125     GRefPtr<WebKitWindowProperties> windowProperties;
126
127     GRefPtr<GMainLoop> modalLoop;
128
129     GRefPtr<WebKitHitTestResult> mouseTargetHitTestResult;
130     unsigned mouseTargetModifiers;
131
132     GRefPtr<WebKitFindController> findController;
133     JSGlobalContextRef javascriptGlobalContext;
134
135     GRefPtr<WebKitWebResource> mainResource;
136     LoadingResourcesMap loadingResourcesMap;
137     ResourcesMap subresourcesMap;
138
139     GRefPtr<WebKitWebInspector> inspector;
140 };
141
142 static guint signals[LAST_SIGNAL] = { 0, };
143
144 G_DEFINE_TYPE(WebKitWebView, webkit_web_view, WEBKIT_TYPE_WEB_VIEW_BASE)
145
146 static gboolean webkitWebViewLoadFail(WebKitWebView* webView, WebKitLoadEvent, const char* failingURI, GError* error)
147 {
148     if (g_error_matches(error, WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_CANCELLED)
149         || g_error_matches(error, WEBKIT_POLICY_ERROR, WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE)
150         || g_error_matches(error, WEBKIT_PLUGIN_ERROR, WEBKIT_PLUGIN_ERROR_WILL_HANDLE_LOAD))
151         return FALSE;
152
153     GOwnPtr<char> htmlString(g_strdup_printf("<html><body>%s</body></html>", error->message));
154     webkit_web_view_load_alternate_html(webView, htmlString.get(), failingURI, 0);
155
156     return TRUE;
157 }
158
159 static GtkWidget* webkitWebViewCreate(WebKitWebView*)
160 {
161     return 0;
162 }
163
164 static GtkWidget* webkitWebViewCreateJavaScriptDialog(WebKitWebView* webView, GtkMessageType type, GtkButtonsType buttons, int defaultResponse, const char* message)
165 {
166     GtkWidget* parent = gtk_widget_get_toplevel(GTK_WIDGET(webView));
167     GtkWidget* dialog = gtk_message_dialog_new(widgetIsOnscreenToplevelWindow(parent) ? GTK_WINDOW(parent) : 0,
168                                                GTK_DIALOG_DESTROY_WITH_PARENT, type, buttons, "%s", message);
169     GOwnPtr<char> title(g_strdup_printf("JavaScript - %s", webkit_web_view_get_uri(webView)));
170     gtk_window_set_title(GTK_WINDOW(dialog), title.get());
171     gtk_dialog_set_default_response(GTK_DIALOG(dialog), defaultResponse);
172
173     return dialog;
174 }
175
176 static gboolean webkitWebViewScriptDialog(WebKitWebView* webView, WebKitScriptDialog* scriptDialog)
177 {
178     GtkWidget* dialog = 0;
179
180     switch (scriptDialog->type) {
181     case WEBKIT_SCRIPT_DIALOG_ALERT:
182         dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, GTK_RESPONSE_CLOSE, scriptDialog->message.data());
183         gtk_dialog_run(GTK_DIALOG(dialog));
184         break;
185     case WEBKIT_SCRIPT_DIALOG_CONFIRM:
186         dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, scriptDialog->message.data());
187         scriptDialog->confirmed = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK;
188         break;
189     case WEBKIT_SCRIPT_DIALOG_PROMPT:
190         dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, scriptDialog->message.data());
191         GtkWidget* entry = gtk_entry_new();
192         gtk_entry_set_text(GTK_ENTRY(entry), scriptDialog->defaultText.data());
193         gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), entry);
194         gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
195         gtk_widget_show(entry);
196         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
197             scriptDialog->text = gtk_entry_get_text(GTK_ENTRY(entry));
198         break;
199     }
200
201     gtk_widget_destroy(dialog);
202
203     return TRUE;
204 }
205
206 static gboolean webkitWebViewDecidePolicy(WebKitWebView* webView, WebKitPolicyDecision* decision, WebKitPolicyDecisionType decisionType)
207 {
208     if (decisionType != WEBKIT_POLICY_DECISION_TYPE_RESPONSE) {
209         webkit_policy_decision_use(decision);
210         return TRUE;
211     }
212
213     WebKitURIResponse* response = webkit_response_policy_decision_get_response(WEBKIT_RESPONSE_POLICY_DECISION(decision));
214     const ResourceResponse resourceResponse = webkitURIResponseGetResourceResponse(response);
215     if (resourceResponse.isAttachment()) {
216         webkit_policy_decision_download(decision);
217         return TRUE;
218     }
219
220     if (webkit_web_view_can_show_mime_type(webView, webkit_uri_response_get_mime_type(response)))
221         webkit_policy_decision_use(decision);
222     else
223         webkit_policy_decision_ignore(decision);
224
225     return TRUE;
226 }
227
228 static gboolean webkitWebViewPermissionRequest(WebKitWebView*, WebKitPermissionRequest* request)
229 {
230     webkit_permission_request_deny(request);
231     return TRUE;
232 }
233
234 static void allowModalDialogsChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
235 {
236     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
237     if (!page)
238         return;
239     page->setCanRunModal(webkit_settings_get_allow_modal_dialogs(settings));
240 }
241
242 static void zoomTextOnlyChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
243 {
244     WKPageRef wkPage = toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView)));
245     gboolean zoomTextOnly = webkit_settings_get_zoom_text_only(settings);
246     gdouble pageZoomLevel = zoomTextOnly ? 1 : WKPageGetTextZoomFactor(wkPage);
247     gdouble textZoomLevel = zoomTextOnly ? WKPageGetPageZoomFactor(wkPage) : 1;
248     WKPageSetPageAndTextZoomFactors(wkPage, pageZoomLevel, textZoomLevel);
249 }
250
251 static void userAgentChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
252 {
253     WKRetainPtr<WKStringRef> userAgent = adoptWK(WKStringCreateWithUTF8CString(webkit_settings_get_user_agent(settings)));
254     WKPageSetCustomUserAgent(toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))), userAgent.get());
255 }
256
257 static void webkitWebViewSetSettings(WebKitWebView* webView, WebKitSettings* settings, WKPageRef wkPage)
258 {
259     webView->priv->settings = settings;
260     webkitSettingsAttachSettingsToPage(webView->priv->settings.get(), wkPage);
261     g_signal_connect(settings, "notify::allow-modal-dialogs", G_CALLBACK(allowModalDialogsChanged), webView);
262     g_signal_connect(settings, "notify::zoom-text-only", G_CALLBACK(zoomTextOnlyChanged), webView);
263     g_signal_connect(settings, "notify::user-agent", G_CALLBACK(userAgentChanged), webView);
264 }
265
266 static void webkitWebViewDisconnectSettingsSignalHandlers(WebKitWebView* webView)
267 {
268     WebKitSettings* settings = webView->priv->settings.get();
269     g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(allowModalDialogsChanged), webView);
270     g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(zoomTextOnlyChanged), webView);
271     g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(userAgentChanged), webView);
272 }
273
274 static void webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(WebKitWebView* webView)
275 {
276     WebKitWebViewPrivate* priv = webView->priv;
277     if (priv->mainResourceResponseHandlerID)
278         g_signal_handler_disconnect(priv->mainResource.get(), priv->mainResourceResponseHandlerID);
279     priv->mainResourceResponseHandlerID = 0;
280 }
281
282 static void fileChooserDialogResponseCallback(GtkDialog* dialog, gint responseID, WebKitFileChooserRequest* request)
283 {
284     GRefPtr<WebKitFileChooserRequest> adoptedRequest = adoptGRef(request);
285     if (responseID == GTK_RESPONSE_ACCEPT) {
286         GOwnPtr<GSList> filesList(gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)));
287         GRefPtr<GPtrArray> filesArray = adoptGRef(g_ptr_array_new());
288         for (GSList* file = filesList.get(); file; file = g_slist_next(file))
289             g_ptr_array_add(filesArray.get(), file->data);
290         g_ptr_array_add(filesArray.get(), 0);
291         webkit_file_chooser_request_select_files(adoptedRequest.get(), reinterpret_cast<const gchar* const*>(filesArray->pdata));
292     } else
293         webkit_file_chooser_request_cancel(adoptedRequest.get());
294
295     gtk_widget_destroy(GTK_WIDGET(dialog));
296 }
297
298 static gboolean webkitWebViewRunFileChooser(WebKitWebView* webView, WebKitFileChooserRequest* request)
299 {
300     GtkWidget* toplevel = gtk_widget_get_toplevel(GTK_WIDGET(webView));
301     if (!widgetIsOnscreenToplevelWindow(toplevel))
302         toplevel = 0;
303
304     gboolean allowsMultipleSelection = webkit_file_chooser_request_get_select_multiple(request);
305     GtkWidget* dialog = gtk_file_chooser_dialog_new(allowsMultipleSelection ? _("Select Files") : _("Select File"),
306                                                     toplevel ? GTK_WINDOW(toplevel) : 0,
307                                                     GTK_FILE_CHOOSER_ACTION_OPEN,
308                                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
309                                                     GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
310                                                     NULL);
311
312     if (GtkFileFilter* filter = webkit_file_chooser_request_get_mime_types_filter(request))
313         gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
314     gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), allowsMultipleSelection);
315
316     if (const gchar* const* selectedFiles = webkit_file_chooser_request_get_selected_files(request))
317         gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), selectedFiles[0]);
318
319     g_signal_connect(dialog, "response", G_CALLBACK(fileChooserDialogResponseCallback), g_object_ref(request));
320     gtk_widget_show(dialog);
321
322     return TRUE;
323 }
324
325 static void webkitWebViewConstructed(GObject* object)
326 {
327     if (G_OBJECT_CLASS(webkit_web_view_parent_class)->constructed)
328         G_OBJECT_CLASS(webkit_web_view_parent_class)->constructed(object);
329
330     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
331     WebKitWebViewPrivate* priv = webView->priv;
332     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView);
333
334     webkitWebViewBaseCreateWebPage(webViewBase, webkitWebContextGetWKContext(priv->context), 0);
335
336     attachLoaderClientToView(webView);
337     attachUIClientToView(webView);
338     attachPolicyClientToPage(webView);
339     attachResourceLoadClientToView(webView);
340     attachFullScreenClientToView(webView);
341     attachContextMenuClientToView(webView);
342     attachFormClientToView(webView);
343
344     WebPageProxy* page = webkitWebViewBaseGetPage(webViewBase);
345     priv->backForwardList = adoptGRef(webkitBackForwardListCreate(WKPageGetBackForwardList(toAPI(page))));
346
347     GRefPtr<WebKitSettings> settings = adoptGRef(webkit_settings_new());
348     webkitWebViewSetSettings(webView, settings.get(), toAPI(page));
349 }
350
351 static void webkitWebViewSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* paramSpec)
352 {
353     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
354
355     switch (propId) {
356     case PROP_WEB_CONTEXT: {
357         gpointer webContext = g_value_get_object(value);
358         webView->priv->context = webContext ? WEBKIT_WEB_CONTEXT(webContext) : webkit_web_context_get_default();
359         break;
360     }
361     case PROP_ZOOM_LEVEL:
362         webkit_web_view_set_zoom_level(webView, g_value_get_double(value));
363         break;
364     default:
365         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
366     }
367 }
368
369 static void webkitWebViewGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
370 {
371     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
372
373     switch (propId) {
374     case PROP_WEB_CONTEXT:
375         g_value_take_object(value, webView->priv->context);
376         break;
377     case PROP_TITLE:
378         g_value_set_string(value, webView->priv->title.data());
379         break;
380     case PROP_ESTIMATED_LOAD_PROGRESS:
381         g_value_set_double(value, webkit_web_view_get_estimated_load_progress(webView));
382         break;
383     case PROP_URI:
384         g_value_set_string(value, webkit_web_view_get_uri(webView));
385         break;
386     case PROP_ZOOM_LEVEL:
387         g_value_set_double(value, webkit_web_view_get_zoom_level(webView));
388         break;
389     default:
390         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
391     }
392 }
393
394 static void webkitWebViewFinalize(GObject* object)
395 {
396     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
397     WebKitWebViewPrivate* priv = webView->priv;
398
399     if (priv->javascriptGlobalContext)
400         JSGlobalContextRelease(priv->javascriptGlobalContext);
401
402     // For modal dialogs, make sure the main loop is stopped when finalizing the webView.
403     if (priv->modalLoop && g_main_loop_is_running(priv->modalLoop.get()))
404         g_main_loop_quit(priv->modalLoop.get());
405
406     webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
407     webkitWebViewDisconnectSettingsSignalHandlers(webView);
408
409     priv->~WebKitWebViewPrivate();
410     G_OBJECT_CLASS(webkit_web_view_parent_class)->finalize(object);
411 }
412
413 static void webkit_web_view_init(WebKitWebView* webView)
414 {
415     WebKitWebViewPrivate* priv = G_TYPE_INSTANCE_GET_PRIVATE(webView, WEBKIT_TYPE_WEB_VIEW, WebKitWebViewPrivate);
416     webView->priv = priv;
417     new (priv) WebKitWebViewPrivate();
418
419     webView->priv->windowProperties = adoptGRef(webkitWindowPropertiesCreate());
420 }
421
422 static gboolean webkitWebViewAccumulatorObjectHandled(GSignalInvocationHint*, GValue* returnValue, const GValue* handlerReturn, gpointer)
423 {
424     void* object = g_value_get_object(handlerReturn);
425     if (object)
426         g_value_set_object(returnValue, object);
427
428     return !object;
429 }
430
431 static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass)
432 {
433     GObjectClass* gObjectClass = G_OBJECT_CLASS(webViewClass);
434
435     gObjectClass->constructed = webkitWebViewConstructed;
436     gObjectClass->set_property = webkitWebViewSetProperty;
437     gObjectClass->get_property = webkitWebViewGetProperty;
438     gObjectClass->finalize = webkitWebViewFinalize;
439
440     webViewClass->load_failed = webkitWebViewLoadFail;
441     webViewClass->create = webkitWebViewCreate;
442     webViewClass->script_dialog = webkitWebViewScriptDialog;
443     webViewClass->decide_policy = webkitWebViewDecidePolicy;
444     webViewClass->permission_request = webkitWebViewPermissionRequest;
445     webViewClass->run_file_chooser = webkitWebViewRunFileChooser;
446
447     g_type_class_add_private(webViewClass, sizeof(WebKitWebViewPrivate));
448
449     /**
450      * WebKitWebView:web-context:
451      *
452      * The #WebKitWebContext of the view.
453      */
454     g_object_class_install_property(gObjectClass,
455                                     PROP_WEB_CONTEXT,
456                                     g_param_spec_object("web-context",
457                                                         _("Web Context"),
458                                                         _("The web context for the view"),
459                                                         WEBKIT_TYPE_WEB_CONTEXT,
460                                                         static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
461
462     /**
463      * WebKitWebView:title:
464      *
465      * The main frame document title of this #WebKitWebView. If
466      * the title has not been received yet, it will be %NULL.
467      */
468     g_object_class_install_property(gObjectClass,
469                                     PROP_TITLE,
470                                     g_param_spec_string("title",
471                                                         _("Title"),
472                                                         _("Main frame document title"),
473                                                         0,
474                                                         WEBKIT_PARAM_READABLE));
475
476     /**
477      * WebKitWebView:estimated-load-progress:
478      *
479      * An estimate of the percent completion for the current loading operation.
480      * This value will range from 0.0 to 1.0 and, once a load completes,
481      * will remain at 1.0 until a new load starts, at which point it
482      * will be reset to 0.0.
483      * The value is an estimate based on the total number of bytes expected
484      * to be received for a document, including all its possible subresources
485      * and child documents.
486      */
487     g_object_class_install_property(gObjectClass,
488                                     PROP_ESTIMATED_LOAD_PROGRESS,
489                                     g_param_spec_double("estimated-load-progress",
490                                                         _("Estimated Load Progress"),
491                                                         _("An estimate of the percent completion for a document load"),
492                                                         0.0, 1.0, 0.0,
493                                                         WEBKIT_PARAM_READABLE));
494     /**
495      * WebKitWebView:uri:
496      *
497      * The current active URI of the #WebKitWebView.
498      * See webkit_web_view_get_uri() for more details.
499      */
500     g_object_class_install_property(gObjectClass,
501                                     PROP_URI,
502                                     g_param_spec_string("uri",
503                                                         _("URI"),
504                                                         _("The current active URI of the view"),
505                                                         0,
506                                                         WEBKIT_PARAM_READABLE));
507
508     /**
509      * WebKitWebView::load-changed:
510      * @web_view: the #WebKitWebView on which the signal is emitted
511      * @load_event: the #WebKitLoadEvent
512      *
513      * Emitted when the a load operation in @web_view changes.
514      * The signal is always emitted with %WEBKIT_LOAD_STARTED when a
515      * new load request is made and %WEBKIT_LOAD_FINISHED when the load
516      * finishes successfully or due to an error. When the ongoing load
517      * operation fails #WebKitWebView::load-failed signal is emitted
518      * before #WebKitWebView::load-changed is emitted with
519      * %WEBKIT_LOAD_FINISHED.
520      * If a redirection is received from the server, this signal is emitted
521      * with %WEBKIT_LOAD_REDIRECTED after the initial emission with
522      * %WEBKIT_LOAD_STARTED and before %WEBKIT_LOAD_COMMITTED.
523      * When the page content starts arriving the signal is emitted with
524      * %WEBKIT_LOAD_COMMITTED event.
525      *
526      * You can handle this signal and use a switch to track any ongoing
527      * load operation.
528      *
529      * <informalexample><programlisting>
530      * static void web_view_load_changed (WebKitWebView  *web_view,
531      *                                    WebKitLoadEvent load_event,
532      *                                    gpointer        user_data)
533      * {
534      *     switch (load_event) {
535      *     case WEBKIT_LOAD_STARTED:
536      *         /<!-- -->* New load, we have now a provisional URI *<!-- -->/
537      *         provisional_uri = webkit_web_view_get_uri (web_view);
538      *         /<!-- -->* Here we could start a spinner or update the
539      *          <!-- -->* location bar with the provisional URI *<!-- -->/
540      *         break;
541      *     case WEBKIT_LOAD_REDIRECTED:
542      *         redirected_uri = webkit_web_view_get_uri (web_view);
543      *         break;
544      *     case WEBKIT_LOAD_COMMITTED:
545      *         /<!-- -->* The load is being performed. Current URI is
546      *          <!-- -->* the final one and it won't change unless a new
547      *          <!-- -->* load is requested or a navigation within the
548      *          <!-- -->* same page is performed *<!-- -->/
549      *         uri = webkit_web_view_get_uri (web_view);
550      *         break;
551      *     case WEBKIT_LOAD_FINISHED:
552      *         /<!-- -->* Load finished, we can now stop the spinner *<!-- -->/
553      *         break;
554      *     }
555      * }
556      * </programlisting></informalexample>
557      */
558     signals[LOAD_CHANGED] =
559         g_signal_new("load-changed",
560                      G_TYPE_FROM_CLASS(webViewClass),
561                      G_SIGNAL_RUN_LAST,
562                      G_STRUCT_OFFSET(WebKitWebViewClass, load_changed),
563                      0, 0,
564                      g_cclosure_marshal_VOID__ENUM,
565                      G_TYPE_NONE, 1,
566                      WEBKIT_TYPE_LOAD_EVENT);
567
568     /**
569      * WebKitWebView::load-failed:
570      * @web_view: the #WebKitWebView on which the signal is emitted
571      * @load_event: the #WebKitLoadEvent of the load operation
572      * @failing_uri: the URI that failed to load
573      * @error: the #GError that was triggered
574      *
575      * Emitted when an error occurs during a load operation.
576      * If the error happened when starting to load data for a page
577      * @load_event will be %WEBKIT_LOAD_STARTED. If it happened while
578      * loading a committed data source @load_event will be %WEBKIT_LOAD_COMMITTED.
579      * Since a load error causes the load operation to finish, the signal
580      * WebKitWebView::load-changed will always be emitted with
581      * %WEBKIT_LOAD_FINISHED event right after this one.
582      *
583      * By default, if the signal is not handled, a stock error page will be displayed.
584      * You need to handle the signal if you want to provide your own error page.
585      *
586      * Returns: %TRUE to stop other handlers from being invoked for the event.
587      *    %FALSE to propagate the event further.
588      */
589     signals[LOAD_FAILED] =
590         g_signal_new("load-failed",
591                      G_TYPE_FROM_CLASS(webViewClass),
592                      G_SIGNAL_RUN_LAST,
593                      G_STRUCT_OFFSET(WebKitWebViewClass, load_failed),
594                      g_signal_accumulator_true_handled, 0,
595                      webkit_marshal_BOOLEAN__ENUM_STRING_POINTER,
596                      G_TYPE_BOOLEAN, 3,
597                      WEBKIT_TYPE_LOAD_EVENT,
598                      G_TYPE_STRING,
599                      G_TYPE_POINTER);
600
601     /**
602      * WebKitWebView:zoom-level:
603      *
604      * The zoom level of the #WebKitWebView content.
605      * See webkit_web_view_set_zoom_level() for more details.
606      */
607     g_object_class_install_property(gObjectClass,
608                                     PROP_ZOOM_LEVEL,
609                                     g_param_spec_double("zoom-level",
610                                                         "Zoom level",
611                                                         "The zoom level of the view content",
612                                                         0, G_MAXDOUBLE, 1,
613                                                         WEBKIT_PARAM_READWRITE));
614
615     /**
616      * WebKitWebView::create:
617      * @web_view: the #WebKitWebView on which the signal is emitted
618      *
619      * Emitted when the creation of a new #WebKitWebView is requested.
620      * If this signal is handled the signal handler should return the
621      * newly created #WebKitWebView.
622      *
623      * The new #WebKitWebView should not be displayed to the user
624      * until the #WebKitWebView::ready-to-show signal is emitted.
625      *
626      * Returns: (transfer full): a newly allocated #WebKitWebView widget
627      *    or %NULL to propagate the event further.
628      */
629     signals[CREATE] =
630         g_signal_new("create",
631                      G_TYPE_FROM_CLASS(webViewClass),
632                      G_SIGNAL_RUN_LAST,
633                      G_STRUCT_OFFSET(WebKitWebViewClass, create),
634                      webkitWebViewAccumulatorObjectHandled, 0,
635                      webkit_marshal_OBJECT__VOID,
636                      GTK_TYPE_WIDGET, 0);
637
638     /**
639      * WebKitWebView::ready-to-show:
640      * @web_view: the #WebKitWebView on which the signal is emitted
641      *
642      * Emitted after #WebKitWebView::create on the newly created #WebKitWebView
643      * when it should be displayed to the user. When this signal is emitted
644      * all the information about how the window should look, including
645      * size, position, whether the location, status and scrollbars
646      * should be displayed, is already set on the #WebKitWindowProperties
647      * of @web_view. See also webkit_web_view_get_window_properties().
648      */
649     signals[READY_TO_SHOW] =
650         g_signal_new("ready-to-show",
651                      G_TYPE_FROM_CLASS(webViewClass),
652                      G_SIGNAL_RUN_LAST,
653                      G_STRUCT_OFFSET(WebKitWebViewClass, ready_to_show),
654                      0, 0,
655                      g_cclosure_marshal_VOID__VOID,
656                      G_TYPE_NONE, 0);
657
658      /**
659      * WebKitWebView::run-as-modal:
660      * @web_view: the #WebKitWebView on which the signal is emitted
661      *
662      * Emitted after #WebKitWebView::ready-to-show on the newly
663      * created #WebKitWebView when JavaScript code calls
664      * <function>window.showModalDialog</function>. The purpose of
665      * this signal is to allow the client application to prepare the
666      * new view to behave as modal. Once the signal is emitted a new
667      * mainloop will be run to block user interaction in the parent
668      * #WebKitWebView until the new dialog is closed.
669      */
670     signals[RUN_AS_MODAL] =
671             g_signal_new("run-as-modal",
672                          G_TYPE_FROM_CLASS(webViewClass),
673                          G_SIGNAL_RUN_LAST,
674                          G_STRUCT_OFFSET(WebKitWebViewClass, run_as_modal),
675                          0, 0,
676                          g_cclosure_marshal_VOID__VOID,
677                          G_TYPE_NONE, 0);
678
679     /**
680      * WebKitWebView::close:
681      * @webView: the #WebKitWebView on which the signal is emitted
682      *
683      * Emitted when closing a #WebKitWebView is requested. This occurs when a
684      * call is made from JavaScript's <function>window.close</function> function.
685      * It is the owner's responsibility to handle this signal to hide or
686      * destroy the #WebKitWebView, if necessary.
687      */
688     signals[CLOSE] =
689         g_signal_new("close",
690                      G_TYPE_FROM_CLASS(webViewClass),
691                      G_SIGNAL_RUN_LAST,
692                      G_STRUCT_OFFSET(WebKitWebViewClass, close),
693                      0, 0,
694                      g_cclosure_marshal_VOID__VOID,
695                      G_TYPE_NONE, 0);
696
697     /**
698      * WebKitWebView::script-dialog:
699      * @web_view: the #WebKitWebView on which the signal is emitted
700      * @dialog: the #WebKitScriptDialog to show
701      *
702      * Emitted when JavaScript code calls <function>window.alert</function>,
703      * <function>window.confirm</function> or <function>window.prompt</function>.
704      * The @dialog parameter should be used to build the dialog.
705      * If the signal is not handled a different dialog will be built and shown depending
706      * on the dialog type:
707      * <itemizedlist>
708      * <listitem><para>
709      *  %WEBKIT_SCRIPT_DIALOG_ALERT: message dialog with a single Close button.
710      * </para></listitem>
711      * <listitem><para>
712      *  %WEBKIT_SCRIPT_DIALOG_CONFIRM: message dialog with OK and Cancel buttons.
713      * </para></listitem>
714      * <listitem><para>
715      *  %WEBKIT_SCRIPT_DIALOG_PROMPT: message dialog with OK and Cancel buttons and
716      *  a text entry with the default text.
717      * </para></listitem>
718      * </itemizedlist>
719      *
720      * Returns: %TRUE to stop other handlers from being invoked for the event.
721      *    %FALSE to propagate the event further.
722      */
723     signals[SCRIPT_DIALOG] =
724         g_signal_new("script-dialog",
725                      G_TYPE_FROM_CLASS(webViewClass),
726                      G_SIGNAL_RUN_LAST,
727                      G_STRUCT_OFFSET(WebKitWebViewClass, script_dialog),
728                      g_signal_accumulator_true_handled, 0,
729                      webkit_marshal_BOOLEAN__BOXED,
730                      G_TYPE_BOOLEAN, 1,
731                      WEBKIT_TYPE_SCRIPT_DIALOG | G_SIGNAL_TYPE_STATIC_SCOPE);
732
733     /**
734      * WebKitWebView::decide-policy:
735      * @web_view: the #WebKitWebView on which the signal is emitted
736      * @decision: the #WebKitPolicyDecision
737      * @decision_type: a #WebKitPolicyDecisionType denoting the type of @decision
738      *
739      * This signal is emitted when WebKit is requesting the client to decide a policy
740      * decision, such as whether to navigate to a page, open a new window or whether or
741      * not to download a resource. The #WebKitNavigationPolicyDecision passed in the
742      * @decision argument is a generic type, but should be casted to a more
743      * specific type when making the decision. For example:
744      *
745      * <informalexample><programlisting>
746      * static gboolean
747      * decide_policy_cb (WebKitWebView *web_view,
748      *                   WebKitPolicyDecision *decision,
749      *                   WebKitPolicyDecisionType type)
750      * {
751      *     switch (type) {
752      *     case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
753      *         WebKitNavigationPolicyDecision *navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
754      *         /<!-- -->* Make a policy decision here. *<!-- -->/
755      *         break;
756      *     case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
757      *         WebKitNavigationPolicyDecision *navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
758      *         /<!-- -->* Make a policy decision here. *<!-- -->/
759      *         break;
760      *     case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
761      *         WebKitResponsePolicyDecision *response = WEBKIT_RESPONSE_POLICY_DECISION (decision);
762      *         /<!-- -->* Make a policy decision here. *<!-- -->/
763      *         break;
764      *     default:
765      *         /<!-- -->* Making no decision results in webkit_policy_decision_use(). *<!-- -->/
766      *         return FALSE;
767      *     }
768      *     return TRUE;
769      * }
770      * </programlisting></informalexample>
771      *
772      * It is possible to make policy decision asynchronously, by simply calling g_object_ref()
773      * on the @decision argument and returning %TRUE to block the default signal handler.
774      * If the last reference is removed on a #WebKitPolicyDecision and no decision has been
775      * made explicitly, webkit_policy_decision_use() will be the default policy decision. The
776      * default signal handler will simply call webkit_policy_decision_use(). Only the first
777      * policy decision chosen for a given #WebKitPolicyDecision will have any affect.
778      *
779      * Returns: %TRUE to stop other handlers from being invoked for the event.
780      *   %FALSE to propagate the event further.
781      *
782      */
783     signals[DECIDE_POLICY] =
784         g_signal_new("decide-policy",
785                      G_TYPE_FROM_CLASS(webViewClass),
786                      G_SIGNAL_RUN_LAST,
787                      G_STRUCT_OFFSET(WebKitWebViewClass, decide_policy),
788                      g_signal_accumulator_true_handled, 0 /* accumulator data */,
789                      webkit_marshal_BOOLEAN__OBJECT_ENUM,
790                      G_TYPE_BOOLEAN, 2, /* number of parameters */
791                      WEBKIT_TYPE_POLICY_DECISION,
792                      WEBKIT_TYPE_POLICY_DECISION_TYPE);
793
794     /**
795      * WebKitWebView::permission-request:
796      * @web_view: the #WebKitWebView on which the signal is emitted
797      * @request: the #WebKitPermissionRequest
798      *
799      * This signal is emitted when WebKit is requesting the client to
800      * decide about a permission request, such as allowing the browser
801      * to switch to fullscreen mode, sharing its location or similar
802      * operations.
803      *
804      * A possible way to use this signal could be through a dialog
805      * allowing the user decide what to do with the request:
806      *
807      * <informalexample><programlisting>
808      * static gboolean permission_request_cb (WebKitWebView *web_view,
809      *                                        WebKitPermissionRequest *request,
810      *                                        GtkWindow *parent_window)
811      * {
812      *     GtkWidget *dialog = gtk_message_dialog_new (parent_window,
813      *                                                 GTK_DIALOG_MODAL,
814      *                                                 GTK_MESSAGE_QUESTION,
815      *                                                 GTK_BUTTONS_YES_NO,
816      *                                                 "Allow Permission Request?");
817      *     gtk_widget_show (dialog);
818      *     gint result = gtk_dialog_run (GTK_DIALOG (dialog));
819      *
820      *     switch (result) {
821      *     case GTK_RESPONSE_YES:
822      *         webkit_permission_request_allow (request);
823      *         break;
824      *     default:
825      *         webkit_permission_request_deny (request);
826      *         break;
827      *     }
828      *     gtk_widget_destroy (dialog);
829      *
830      *     return TRUE;
831      * }
832      * </programlisting></informalexample>
833      *
834      * It is possible to handle permission requests asynchronously, by
835      * simply calling g_object_ref() on the @request argument and
836      * returning %TRUE to block the default signal handler.  If the
837      * last reference is removed on a #WebKitPermissionRequest and the
838      * request has not been handled, webkit_permission_request_deny()
839      * will be the default action.
840      *
841      * By default, if the signal is not handled,
842      * webkit_permission_request_deny() will be called over the
843      * #WebKitPermissionRequest.
844      *
845      * Returns: %TRUE to stop other handlers from being invoked for the event.
846      *   %FALSE to propagate the event further.
847      *
848      */
849     signals[PERMISSION_REQUEST] =
850         g_signal_new("permission-request",
851                      G_TYPE_FROM_CLASS(webViewClass),
852                      G_SIGNAL_RUN_LAST,
853                      G_STRUCT_OFFSET(WebKitWebViewClass, permission_request),
854                      g_signal_accumulator_true_handled, 0 /* accumulator data */,
855                      webkit_marshal_BOOLEAN__OBJECT,
856                      G_TYPE_BOOLEAN, 1, /* number of parameters */
857                      WEBKIT_TYPE_PERMISSION_REQUEST);
858     /**
859      * WebKitWebView::mouse-target-changed:
860      * @web_view: the #WebKitWebView on which the signal is emitted
861      * @hit_test_result: a #WebKitHitTestResult
862      * @modifiers: a bitmask of #GdkModifierType
863      *
864      * This signal is emitted when the mouse cursor moves over an
865      * element such as a link, image or a media element. To determine
866      * what type of element the mouse cursor is over, a Hit Test is performed
867      * on the current mouse coordinates and the result is passed in the
868      * @hit_test_result argument. The @modifiers argument is a bitmask of
869      * #GdkModifierType flags indicating the state of modifier keys.
870      * The signal is emitted again when the mouse is moved out of the
871      * current element with a new @hit_test_result.
872      */
873      signals[MOUSE_TARGET_CHANGED] =
874          g_signal_new("mouse-target-changed",
875                       G_TYPE_FROM_CLASS(webViewClass),
876                       G_SIGNAL_RUN_LAST,
877                       G_STRUCT_OFFSET(WebKitWebViewClass, mouse_target_changed),
878                       0, 0,
879                       webkit_marshal_VOID__OBJECT_UINT,
880                       G_TYPE_NONE, 2,
881                       WEBKIT_TYPE_HIT_TEST_RESULT,
882                       G_TYPE_UINT);
883     /**
884      * WebKitWebView::print:
885      * @web_view: the #WebKitWebView on which the signal is emitted
886      * @print_operation: the #WebKitPrintOperation that will handle the print request
887      *
888      * Emitted when printing is requested on @web_view, usually by a javascript call,
889      * before the print dialog is shown. This signal can be used to set the initial
890      * print settings and page setup of @print_operation to be used as default values in
891      * the print dialog. You can call webkit_print_operation_set_print_settings() and
892      * webkit_print_operation_set_page_setup() and then return %FALSE to propagate the
893      * event so that the print dialog is shown.
894      *
895      * You can connect to this signal and return %TRUE to cancel the print operation
896      * or implement your own print dialog.
897      *
898      * Returns: %TRUE to stop other handlers from being invoked for the event.
899      *    %FALSE to propagate the event further.
900      */
901     signals[PRINT] =
902         g_signal_new("print",
903                      G_TYPE_FROM_CLASS(webViewClass),
904                      G_SIGNAL_RUN_LAST,
905                      G_STRUCT_OFFSET(WebKitWebViewClass, print),
906                      g_signal_accumulator_true_handled, 0,
907                      webkit_marshal_BOOLEAN__OBJECT,
908                      G_TYPE_BOOLEAN, 1,
909                      WEBKIT_TYPE_PRINT_OPERATION);
910
911     /**
912      * WebKitWebView::resource-load-started:
913      * @web_view: the #WebKitWebView on which the signal is emitted
914      * @resource: a #WebKitWebResource
915      * @request: a #WebKitURIRequest
916      *
917      * Emitted when a new resource is going to be loaded. The @request parameter
918      * contains the #WebKitURIRequest that will be sent to the server.
919      * You can monitor the load operation by connecting to the different signals
920      * of @resource.
921      */
922     signals[RESOURCE_LOAD_STARTED] =
923         g_signal_new("resource-load-started",
924                      G_TYPE_FROM_CLASS(webViewClass),
925                      G_SIGNAL_RUN_LAST,
926                      G_STRUCT_OFFSET(WebKitWebViewClass, resource_load_started),
927                      0, 0,
928                      webkit_marshal_VOID__OBJECT_OBJECT,
929                      G_TYPE_NONE, 2,
930                      WEBKIT_TYPE_WEB_RESOURCE,
931                      WEBKIT_TYPE_URI_REQUEST);
932
933     /**
934      * WebKitWebView::enter-fullscreen:
935      * @web_view: the #WebKitWebView on which the signal is emitted.
936      *
937      * Emitted when JavaScript code calls
938      * <function>element.webkitRequestFullScreen</function>. If the
939      * signal is not handled the #WebKitWebView will proceed to full screen
940      * its top level window. This signal can be used by client code to
941      * request permission to the user prior doing the full screen
942      * transition and eventually prepare the top-level window
943      * (e.g. hide some widgets that would otherwise be part of the
944      * full screen window).
945      *
946      * Returns: %TRUE to stop other handlers from being invoked for the event.
947      *    %FALSE to continue emission of the event.
948      */
949     signals[ENTER_FULLSCREEN] =
950         g_signal_new("enter-fullscreen",
951                      G_TYPE_FROM_CLASS(webViewClass),
952                      G_SIGNAL_RUN_LAST,
953                      G_STRUCT_OFFSET(WebKitWebViewClass, enter_fullscreen),
954                      g_signal_accumulator_true_handled, 0,
955                      webkit_marshal_BOOLEAN__VOID,
956                      G_TYPE_BOOLEAN, 0);
957
958     /**
959      * WebKitWebView::leave-fullscreen:
960      * @web_view: the #WebKitWebView on which the signal is emitted.
961      *
962      * Emitted when the #WebKitWebView is about to restore its top level
963      * window out of its full screen state. This signal can be used by
964      * client code to restore widgets hidden during the
965      * #WebKitWebView::enter-fullscreen stage for instance.
966      *
967      * Returns: %TRUE to stop other handlers from being invoked for the event.
968      *    %FALSE to continue emission of the event.
969      */
970     signals[LEAVE_FULLSCREEN] =
971         g_signal_new("leave-fullscreen",
972                      G_TYPE_FROM_CLASS(webViewClass),
973                      G_SIGNAL_RUN_LAST,
974                      G_STRUCT_OFFSET(WebKitWebViewClass, leave_fullscreen),
975                      g_signal_accumulator_true_handled, 0,
976                      webkit_marshal_BOOLEAN__VOID,
977                      G_TYPE_BOOLEAN, 0);
978      /**
979      * WebKitWebView::run-file-chooser:
980      * @web_view: the #WebKitWebView on which the signal is emitted
981      * @request: a #WebKitFileChooserRequest
982      *
983      * This signal is emitted when the user interacts with a &lt;input
984      * type='file' /&gt; HTML element, requesting from WebKit to show
985      * a dialog to select one or more files to be uploaded. To let the
986      * application know the details of the file chooser, as well as to
987      * allow the client application to either cancel the request or
988      * perform an actual selection of files, the signal will pass an
989      * instance of the #WebKitFileChooserRequest in the @request
990      * argument.
991      *
992      * The default signal handler will asynchronously run a regular
993      * #GtkFileChooserDialog for the user to interact with.
994      *
995      * Returns: %TRUE to stop other handlers from being invoked for the event.
996      *   %FALSE to propagate the event further.
997      *
998      */
999     signals[RUN_FILE_CHOOSER] =
1000         g_signal_new("run-file-chooser",
1001                      G_TYPE_FROM_CLASS(webViewClass),
1002                      G_SIGNAL_RUN_LAST,
1003                      G_STRUCT_OFFSET(WebKitWebViewClass, run_file_chooser),
1004                      g_signal_accumulator_true_handled, 0 /* accumulator data */,
1005                      webkit_marshal_BOOLEAN__OBJECT,
1006                      G_TYPE_BOOLEAN, 1, /* number of parameters */
1007                      WEBKIT_TYPE_FILE_CHOOSER_REQUEST);
1008
1009     /**
1010      * WebKitWebView::context-menu:
1011      * @web_view: the #WebKitWebView on which the signal is emitted
1012      * @context_menu: the proposed #WebKitContextMenu
1013      * @event: the #GdkEvent that triggered the context menu
1014      * @hit_test_result: a #WebKitHitTestResult
1015      *
1016      * Emmited when a context menu is about to be displayed to give the application
1017      * a chance to customize the proposed menu, prevent the menu from being displayed
1018      * or build its own context menu.
1019      * <itemizedlist>
1020      * <listitem><para>
1021      *  To customize the proposed menu you can use webkit_context_menu_prepend(),
1022      *  webkit_context_menu_append() or webkit_context_menu_insert() to add new
1023      *  #WebKitContextMenuItem<!-- -->s to @context_menu, webkit_context_menu_move_item()
1024      *  to reorder existing items, or webkit_context_menu_remove() to remove an
1025      *  existing item. The signal handler should return %FALSE, and the menu represented
1026      *  by @context_menu will be shown.
1027      * </para></listitem>
1028      * <listitem><para>
1029      *  To prevent the menu from being displayed you can just connect to this signal
1030      *  and return %TRUE so that the proposed menu will not be shown.
1031      * </para></listitem>
1032      * <listitem><para>
1033      *  To build your own menu, you can remove all items from the proposed menu with
1034      *  webkit_context_menu_remove_all(), add your own items and return %FALSE so
1035      *  that the menu will be shown. You can also ignore the proposed #WebKitContextMenu,
1036      *  build your own #GtkMenu and return %TRUE to prevent the proposed menu from being shown.
1037      * </para></listitem>
1038      * <listitem><para>
1039      *  If you just want the default menu to be shown always, simply don't connect to this
1040      *  signal because showing the proposed context menu is the default behaviour.
1041      * </para></listitem>
1042      * </itemizedlist>
1043      *
1044      * If the signal handler returns %FALSE the context menu represented by @context_menu
1045      * will be shown, if it return %TRUE the context menu will not be shown.
1046      *
1047      * The proposed #WebKitContextMenu passed in @context_menu argument is only valid
1048      * during the signal emission.
1049      *
1050      * Returns: %TRUE to stop other handlers from being invoked for the event.
1051      *    %FALSE to propagate the event further.
1052      */
1053     signals[CONTEXT_MENU] =
1054         g_signal_new("context-menu",
1055                      G_TYPE_FROM_CLASS(webViewClass),
1056                      G_SIGNAL_RUN_LAST,
1057                      G_STRUCT_OFFSET(WebKitWebViewClass, context_menu),
1058                      g_signal_accumulator_true_handled, 0,
1059                      webkit_marshal_BOOLEAN__OBJECT_BOXED_OBJECT,
1060                      G_TYPE_BOOLEAN, 3,
1061                      WEBKIT_TYPE_CONTEXT_MENU,
1062                      GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
1063                      WEBKIT_TYPE_HIT_TEST_RESULT);
1064
1065     /**
1066      * WebKitWebView::context-menu-dismissed:
1067      * @web_view: the #WebKitWebView on which the signal is emitted
1068      *
1069      * Emitted after #WebKitWebView::context-menu signal, if the context menu is shown,
1070      * to notify that the context menu is dismissed.
1071      */
1072     signals[CONTEXT_MENU_DISMISSED] =
1073         g_signal_new("context-menu-dismissed",
1074                      G_TYPE_FROM_CLASS(webViewClass),
1075                      G_SIGNAL_RUN_LAST,
1076                      G_STRUCT_OFFSET(WebKitWebViewClass, context_menu_dismissed),
1077                      0, 0,
1078                      g_cclosure_marshal_VOID__VOID,
1079                      G_TYPE_NONE, 0);
1080
1081     /**
1082      * WebKitWebView::submit-form:
1083      * @web_view: the #WebKitWebView on which the signal is emitted
1084      * @request: a #WebKitFormSubmissionRequest
1085      *
1086      * This signal is emitted when a form is about to be submitted. The @request
1087      * argument passed contains information about the text fields of the form. This
1088      * is typically used to store login information that can be used later to
1089      * pre-fill the form.
1090      * The form will not be submitted until webkit_form_submission_request_submit() is called.
1091      *
1092      * It is possible to handle the form submission request asynchronously, by
1093      * simply calling g_object_ref() on the @request argument and calling
1094      * webkit_form_submission_request_submit() when done to continue with the form submission.
1095      * If the last reference is removed on a #WebKitFormSubmissionRequest and the
1096      * form has not been submitted, webkit_form_submission_request_submit() will be called.
1097      */
1098     signals[SUBMIT_FORM] =
1099         g_signal_new("submit-form",
1100                      G_TYPE_FROM_CLASS(webViewClass),
1101                      G_SIGNAL_RUN_LAST,
1102                      G_STRUCT_OFFSET(WebKitWebViewClass, submit_form),
1103                      0, 0,
1104                      g_cclosure_marshal_VOID__OBJECT,
1105                      G_TYPE_NONE, 1,
1106                      WEBKIT_TYPE_FORM_SUBMISSION_REQUEST);
1107 }
1108
1109 static void setCertificateToMainResource(WebKitWebView* webView)
1110 {
1111     WebKitWebViewPrivate* priv = webView->priv;
1112     ASSERT(priv->mainResource.get());
1113
1114     webkitURIResponseSetCertificateInfo(webkit_web_resource_get_response(priv->mainResource.get()),
1115                                         WKFrameGetCertificateInfo(webkitWebResourceGetFrame(priv->mainResource.get())));
1116 }
1117
1118 static void webkitWebViewEmitLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent)
1119 {
1120     if (loadEvent == WEBKIT_LOAD_FINISHED) {
1121         webView->priv->waitingForMainResource = false;
1122         webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
1123     } else
1124         webkitWebViewUpdateURI(webView);
1125     g_signal_emit(webView, signals[LOAD_CHANGED], 0, loadEvent);
1126 }
1127
1128 static void webkitWebViewEmitDelayedLoadEvents(WebKitWebView* webView)
1129 {
1130     WebKitWebViewPrivate* priv = webView->priv;
1131     if (!priv->waitingForMainResource)
1132         return;
1133     ASSERT(priv->lastDelayedEvent == WEBKIT_LOAD_COMMITTED || priv->lastDelayedEvent == WEBKIT_LOAD_FINISHED);
1134
1135     if (priv->lastDelayedEvent == WEBKIT_LOAD_FINISHED)
1136         webkitWebViewEmitLoadChanged(webView, WEBKIT_LOAD_COMMITTED);
1137     webkitWebViewEmitLoadChanged(webView, priv->lastDelayedEvent);
1138     priv->waitingForMainResource = false;
1139 }
1140
1141 void webkitWebViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent)
1142 {
1143     if (loadEvent == WEBKIT_LOAD_STARTED) {
1144         // Finish a possible previous load waiting for main resource.
1145         webkitWebViewEmitDelayedLoadEvents(webView);
1146
1147         webView->priv->loadingResourcesMap.clear();
1148         webView->priv->mainResource = 0;
1149         webView->priv->waitingForMainResource = false;
1150     } else if (loadEvent == WEBKIT_LOAD_COMMITTED) {
1151         webView->priv->subresourcesMap.clear();
1152         if (!webView->priv->mainResource) {
1153             // When a page is loaded from the history cache, the main resource load callbacks
1154             // are called when the main frame load is finished. We want to make sure there's a
1155             // main resource available when load has been committed, so we delay the emission of
1156             // load-changed signal until main resource object has been created.
1157             webView->priv->waitingForMainResource = true;
1158         } else
1159             setCertificateToMainResource(webView);
1160     }
1161
1162     if (webView->priv->waitingForMainResource)
1163         webView->priv->lastDelayedEvent = loadEvent;
1164     else
1165         webkitWebViewEmitLoadChanged(webView, loadEvent);
1166 }
1167
1168 void webkitWebViewLoadFailed(WebKitWebView* webView, WebKitLoadEvent loadEvent, const char* failingURI, GError *error)
1169 {
1170     gboolean returnValue;
1171     g_signal_emit(webView, signals[LOAD_FAILED], 0, loadEvent, failingURI, error, &returnValue);
1172     g_signal_emit(webView, signals[LOAD_CHANGED], 0, WEBKIT_LOAD_FINISHED);
1173 }
1174
1175 void webkitWebViewSetTitle(WebKitWebView* webView, const CString& title)
1176 {
1177     WebKitWebViewPrivate* priv = webView->priv;
1178     if (priv->title == title)
1179         return;
1180
1181     priv->title = title;
1182     g_object_notify(G_OBJECT(webView), "title");
1183 }
1184
1185 void webkitWebViewSetEstimatedLoadProgress(WebKitWebView* webView, double estimatedLoadProgress)
1186 {
1187     if (webView->priv->estimatedLoadProgress == estimatedLoadProgress)
1188         return;
1189
1190     webView->priv->estimatedLoadProgress = estimatedLoadProgress;
1191     g_object_notify(G_OBJECT(webView), "estimated-load-progress");
1192 }
1193
1194 void webkitWebViewUpdateURI(WebKitWebView* webView)
1195 {
1196     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
1197     WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKPageCopyActiveURL(toAPI(page)));
1198     CString activeURI;
1199     if (wkURL)
1200         activeURI = toImpl(wkURL.get())->string().utf8();
1201
1202     if (webView->priv->activeURI == activeURI)
1203         return;
1204
1205     webView->priv->activeURI = activeURI;
1206     g_object_notify(G_OBJECT(webView), "uri");
1207 }
1208
1209 WKPageRef webkitWebViewCreateNewPage(WebKitWebView* webView, WKDictionaryRef wkWindowFeatures)
1210 {
1211     WebKitWebView* newWebView;
1212     g_signal_emit(webView, signals[CREATE], 0, &newWebView);
1213     if (!newWebView)
1214         return 0;
1215
1216     webkitWindowPropertiesUpdateFromWKWindowFeatures(newWebView->priv->windowProperties.get(), wkWindowFeatures);
1217
1218     return static_cast<WKPageRef>(WKRetain(toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(newWebView)))));
1219 }
1220
1221 void webkitWebViewReadyToShowPage(WebKitWebView* webView)
1222 {
1223     g_signal_emit(webView, signals[READY_TO_SHOW], 0, NULL);
1224 }
1225
1226 void webkitWebViewRunAsModal(WebKitWebView* webView)
1227 {
1228     g_signal_emit(webView, signals[RUN_AS_MODAL], 0, NULL);
1229
1230     webView->priv->modalLoop = adoptGRef(g_main_loop_new(0, FALSE));
1231     gdk_threads_leave();
1232     g_main_loop_run(webView->priv->modalLoop.get());
1233     gdk_threads_enter();
1234 }
1235
1236 void webkitWebViewClosePage(WebKitWebView* webView)
1237 {
1238     g_signal_emit(webView, signals[CLOSE], 0, NULL);
1239 }
1240
1241 void webkitWebViewRunJavaScriptAlert(WebKitWebView* webView, const CString& message)
1242 {
1243     WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_ALERT, message);
1244     gboolean returnValue;
1245     g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
1246 }
1247
1248 bool webkitWebViewRunJavaScriptConfirm(WebKitWebView* webView, const CString& message)
1249 {
1250     WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_CONFIRM, message);
1251     gboolean returnValue;
1252     g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
1253     return dialog.confirmed;
1254 }
1255
1256 WKStringRef webkitWebViewRunJavaScriptPrompt(WebKitWebView* webView, const CString& message, const CString& defaultText)
1257 {
1258     WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_PROMPT, message, defaultText);
1259     gboolean returnValue;
1260     g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
1261     return dialog.text.isNull() ? 0 : WKStringCreateWithUTF8CString(dialog.text.data());
1262 }
1263
1264 void webkitWebViewMakePolicyDecision(WebKitWebView* webView, WebKitPolicyDecisionType type, WebKitPolicyDecision* decision)
1265 {
1266     gboolean returnValue;
1267     g_signal_emit(webView, signals[DECIDE_POLICY], 0, decision, type, &returnValue);
1268 }
1269
1270 void webkitWebViewMakePermissionRequest(WebKitWebView* webView, WebKitPermissionRequest* request)
1271 {
1272     gboolean returnValue;
1273     g_signal_emit(webView, signals[PERMISSION_REQUEST], 0, request, &returnValue);
1274 }
1275
1276 void webkitWebViewMouseTargetChanged(WebKitWebView* webView, WKHitTestResultRef wkHitTestResult, unsigned modifiers)
1277 {
1278     webkitWebViewBaseSetTooltipArea(WEBKIT_WEB_VIEW_BASE(webView), toImpl(wkHitTestResult)->elementBoundingBox());
1279
1280     WebKitWebViewPrivate* priv = webView->priv;
1281     if (priv->mouseTargetHitTestResult
1282         && priv->mouseTargetModifiers == modifiers
1283         && webkitHitTestResultCompare(priv->mouseTargetHitTestResult.get(), wkHitTestResult))
1284         return;
1285
1286     priv->mouseTargetModifiers = modifiers;
1287     priv->mouseTargetHitTestResult = adoptGRef(webkitHitTestResultCreate(wkHitTestResult));
1288     g_signal_emit(webView, signals[MOUSE_TARGET_CHANGED], 0, priv->mouseTargetHitTestResult.get(), modifiers);
1289 }
1290
1291 void webkitWebViewPrintFrame(WebKitWebView* webView, WKFrameRef wkFrame)
1292 {
1293     GRefPtr<WebKitPrintOperation> printOperation = adoptGRef(webkit_print_operation_new(webView));
1294     gboolean returnValue;
1295     g_signal_emit(webView, signals[PRINT], 0, printOperation.get(), &returnValue);
1296     if (returnValue)
1297         return;
1298
1299     WebKitPrintOperationResponse response = webkitPrintOperationRunDialogForFrame(printOperation.get(), 0, toImpl(wkFrame));
1300     if (response == WEBKIT_PRINT_OPERATION_RESPONSE_CANCEL)
1301         return;
1302     g_signal_connect(printOperation.leakRef(), "finished", G_CALLBACK(g_object_unref), 0);
1303 }
1304
1305 static void mainResourceResponseChangedCallback(WebKitWebResource*, GParamSpec*, WebKitWebView* webView)
1306 {
1307     webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
1308     setCertificateToMainResource(webView);
1309     webkitWebViewEmitDelayedLoadEvents(webView);
1310 }
1311
1312 static void waitForMainResourceResponseIfWaitingForResource(WebKitWebView* webView)
1313 {
1314     WebKitWebViewPrivate* priv = webView->priv;
1315     if (!priv->waitingForMainResource)
1316         return;
1317
1318     webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
1319     priv->mainResourceResponseHandlerID =
1320         g_signal_connect(priv->mainResource.get(), "notify::response", G_CALLBACK(mainResourceResponseChangedCallback), webView);
1321 }
1322
1323 void webkitWebViewResourceLoadStarted(WebKitWebView* webView, WKFrameRef wkFrame, uint64_t resourceIdentifier, WebKitURIRequest* request)
1324 {
1325     WebKitWebViewPrivate* priv = webView->priv;
1326     bool isMainResource = WKFrameIsMainFrame(wkFrame) && !priv->mainResource;
1327     WebKitWebResource* resource = webkitWebResourceCreate(wkFrame, request, isMainResource);
1328     if (isMainResource) {
1329         priv->mainResource = resource;
1330         waitForMainResourceResponseIfWaitingForResource(webView);
1331     }
1332     priv->loadingResourcesMap.set(resourceIdentifier, adoptGRef(resource));
1333     g_signal_emit(webView, signals[RESOURCE_LOAD_STARTED], 0, resource, request);
1334 }
1335
1336 WebKitWebResource* webkitWebViewGetLoadingWebResource(WebKitWebView* webView, uint64_t resourceIdentifier)
1337 {
1338     GRefPtr<WebKitWebResource> resource = webView->priv->loadingResourcesMap.get(resourceIdentifier);
1339     ASSERT(resource.get());
1340     return resource.get();
1341 }
1342
1343 void webkitWebViewRemoveLoadingWebResource(WebKitWebView* webView, uint64_t resourceIdentifier)
1344 {
1345     WebKitWebViewPrivate* priv = webView->priv;
1346     ASSERT(priv->loadingResourcesMap.contains(resourceIdentifier));
1347     priv->loadingResourcesMap.remove(resourceIdentifier);
1348 }
1349
1350 WebKitWebResource* webkitWebViewResourceLoadFinished(WebKitWebView* webView, uint64_t resourceIdentifier)
1351 {
1352     WebKitWebViewPrivate* priv = webView->priv;
1353     WebKitWebResource* resource = webkitWebViewGetLoadingWebResource(webView, resourceIdentifier);
1354     if (resource != priv->mainResource)
1355         priv->subresourcesMap.set(String::fromUTF8(webkit_web_resource_get_uri(resource)), resource);
1356     webkitWebViewRemoveLoadingWebResource(webView, resourceIdentifier);
1357     return resource;
1358 }
1359
1360 bool webkitWebViewEnterFullScreen(WebKitWebView* webView)
1361 {
1362     gboolean returnValue;
1363     g_signal_emit(webView, signals[ENTER_FULLSCREEN], 0, &returnValue);
1364     return !returnValue;
1365 }
1366
1367 bool webkitWebViewLeaveFullScreen(WebKitWebView* webView)
1368 {
1369     gboolean returnValue;
1370     g_signal_emit(webView, signals[LEAVE_FULLSCREEN], 0, &returnValue);
1371     return !returnValue;
1372 }
1373
1374 void webkitWebViewRunFileChooserRequest(WebKitWebView* webView, WebKitFileChooserRequest* request)
1375 {
1376     gboolean returnValue;
1377     g_signal_emit(webView, signals[RUN_FILE_CHOOSER], 0, request, &returnValue);
1378 }
1379
1380 static bool webkitWebViewShouldShowInputMethodsMenu(WebKitWebView* webView)
1381 {
1382     GtkSettings* settings = gtk_widget_get_settings(GTK_WIDGET(webView));
1383     if (!settings)
1384         return true;
1385
1386     gboolean showInputMethodMenu;
1387     g_object_get(settings, "gtk-show-input-method-menu", &showInputMethodMenu, NULL);
1388     return showInputMethodMenu;
1389 }
1390
1391 static int getUnicodeMenuItemPosition(WebKitContextMenu* contextMenu)
1392 {
1393     GList* items = webkit_context_menu_get_items(contextMenu);
1394     GList* iter;
1395     int i = 0;
1396     for (iter = items, i = 0; iter; iter = g_list_next(iter), ++i) {
1397         WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(iter->data);
1398
1399         if (webkit_context_menu_item_is_separator(item))
1400             continue;
1401         if (webkit_context_menu_item_get_stock_action(item) == WEBKIT_CONTEXT_MENU_ACTION_UNICODE)
1402             return i;
1403     }
1404     return -1;
1405 }
1406
1407 static void webkitWebViewCreateAndAppendInputMethodsMenuItem(WebKitWebView* webView, WebKitContextMenu* contextMenu)
1408 {
1409     if (!webkitWebViewShouldShowInputMethodsMenu(webView))
1410         return;
1411
1412     // Place the im context menu item right before the unicode menu item
1413     // if it's present.
1414     int unicodeMenuItemPosition = getUnicodeMenuItemPosition(contextMenu);
1415     if (unicodeMenuItemPosition == -1)
1416         webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator());
1417
1418     GtkIMContext* imContext = webkitWebViewBaseGetIMContext(WEBKIT_WEB_VIEW_BASE(webView));
1419     GtkMenu* imContextMenu = GTK_MENU(gtk_menu_new());
1420     gtk_im_multicontext_append_menuitems(GTK_IM_MULTICONTEXT(imContext), GTK_MENU_SHELL(imContextMenu));
1421     WebKitContextMenuItem* menuItem = webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS);
1422     webkitContextMenuItemSetSubMenuFromGtkMenu(menuItem, imContextMenu);
1423     webkit_context_menu_insert(contextMenu, menuItem, unicodeMenuItemPosition);
1424 }
1425
1426 static void contextMenuDismissed(GtkMenuShell*, WebKitWebView* webView)
1427 {
1428     g_signal_emit(webView, signals[CONTEXT_MENU_DISMISSED], 0, NULL);
1429 }
1430
1431 void webkitWebViewPopulateContextMenu(WebKitWebView* webView, WKArrayRef wkProposedMenu, WKHitTestResultRef wkHitTestResult)
1432 {
1433     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView);
1434     WebContextMenuProxyGtk* contextMenuProxy = webkitWebViewBaseGetActiveContextMenuProxy(webViewBase);
1435     ASSERT(contextMenuProxy);
1436
1437     GRefPtr<WebKitContextMenu> contextMenu = adoptGRef(webkitContextMenuCreate(wkProposedMenu));
1438     if (WKHitTestResultIsContentEditable(wkHitTestResult))
1439         webkitWebViewCreateAndAppendInputMethodsMenuItem(webView, contextMenu.get());
1440
1441     GRefPtr<WebKitHitTestResult> hitTestResult = adoptGRef(webkitHitTestResultCreate(wkHitTestResult));
1442     GOwnPtr<GdkEvent> contextMenuEvent(webkitWebViewBaseTakeContextMenuEvent(webViewBase));
1443
1444     gboolean returnValue;
1445     g_signal_emit(webView, signals[CONTEXT_MENU], 0, contextMenu.get(), contextMenuEvent.get(), hitTestResult.get(), &returnValue);
1446     if (returnValue)
1447         return;
1448
1449     Vector<ContextMenuItem> contextMenuItems;
1450     webkitContextMenuPopulate(contextMenu.get(), contextMenuItems);
1451     contextMenuProxy->populate(contextMenuItems);
1452
1453     g_signal_connect(contextMenuProxy->gtkMenu(), "deactivate", G_CALLBACK(contextMenuDismissed), webView);
1454
1455     // Clear the menu to make sure it's useless after signal emission.
1456     webkit_context_menu_remove_all(contextMenu.get());
1457 }
1458
1459 void webkitWebViewSubmitFormRequest(WebKitWebView* webView, WebKitFormSubmissionRequest* request)
1460 {
1461     g_signal_emit(webView, signals[SUBMIT_FORM], 0, request);
1462 }
1463
1464 /**
1465  * webkit_web_view_new:
1466  *
1467  * Creates a new #WebKitWebView with the default #WebKitWebContext.
1468  * See also webkit_web_view_new_with_context().
1469  *
1470  * Returns: The newly created #WebKitWebView widget
1471  */
1472 GtkWidget* webkit_web_view_new()
1473 {
1474     return webkit_web_view_new_with_context(webkit_web_context_get_default());
1475 }
1476
1477 /**
1478  * webkit_web_view_new_with_context:
1479  * @context: the #WebKitWebContext to be used by the #WebKitWebView
1480  *
1481  * Creates a new #WebKitWebView with the given #WebKitWebContext.
1482  *
1483  * Returns: The newly created #WebKitWebView widget
1484  */
1485 GtkWidget* webkit_web_view_new_with_context(WebKitWebContext* context)
1486 {
1487     g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
1488
1489     return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "web-context", context, NULL));
1490 }
1491
1492 /**
1493  * webkit_web_view_get_context:
1494  * @web_view: a #WebKitWebView
1495  *
1496  * Gets the web context of @web_view.
1497  *
1498  * Returns: (transfer none): the #WebKitWebContext of the view
1499  */
1500 WebKitWebContext* webkit_web_view_get_context(WebKitWebView *webView)
1501 {
1502     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
1503
1504     return webView->priv->context;
1505 }
1506
1507 /**
1508  * webkit_web_view_load_uri:
1509  * @web_view: a #WebKitWebView
1510  * @uri: an URI string
1511  *
1512  * Requests loading of the specified URI string.
1513  * You can monitor the load operation by connecting to
1514  * #WebKitWebView::load-changed signal.
1515  */
1516 void webkit_web_view_load_uri(WebKitWebView* webView, const gchar* uri)
1517 {
1518     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1519     g_return_if_fail(uri);
1520
1521     WKRetainPtr<WKURLRef> url(AdoptWK, WKURLCreateWithUTF8CString(uri));
1522     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
1523     WKPageLoadURL(toAPI(page), url.get());
1524     webkitWebViewUpdateURI(webView);
1525 }
1526
1527 /**
1528  * webkit_web_view_load_html:
1529  * @web_view: a #WebKitWebView
1530  * @content: The HTML string to load
1531  * @base_uri: (allow-none): The base URI for relative locations or %NULL
1532  *
1533  * Load the given @content string with the specified @base_uri.
1534  * If @base_uri is not %NULL, relative URLs in the @content will be
1535  * resolved against @base_uri and absolute local paths must be children of the @base_uri.
1536  * For security reasons absolute local paths that are not children of @base_uri
1537  * will cause the web process to terminate.
1538  * If you need to include URLs in @content that are local paths in a different
1539  * directory than @base_uri you can build a data URI for them. When @base_uri is %NULL,
1540  * it defaults to "about:blank". The mime type of the document will be "text/html".
1541  * You can monitor the load operation by connecting to #WebKitWebView::load-changed signal.
1542  */
1543 void webkit_web_view_load_html(WebKitWebView* webView, const gchar* content, const gchar* baseURI)
1544 {
1545     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1546     g_return_if_fail(content);
1547
1548     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
1549     WKRetainPtr<WKStringRef> contentRef(AdoptWK,  WKStringCreateWithUTF8CString(content));
1550     WKRetainPtr<WKURLRef> baseURIRef = baseURI ? adoptWK(WKURLCreateWithUTF8CString(baseURI)) : 0;
1551     WKPageLoadHTMLString(toAPI(page), contentRef.get(), baseURIRef.get());
1552 }
1553
1554 /**
1555  * webkit_web_view_load_alternate_html:
1556  * @web_view: a #WebKitWebView
1557  * @content: the new content to display as the main page of the @web_view
1558  * @content_uri: the URI for the alternate page content
1559  * @base_uri: (allow-none): the base URI for relative locations or %NULL
1560  *
1561  * Load the given @content string for the URI @content_uri.
1562  * This allows clients to display page-loading errors in the #WebKitWebView itself.
1563  * When this method is called from #WebKitWebView::load-failed signal to show an
1564  * error page, the the back-forward list is maintained appropriately.
1565  * For everything else this method works the same way as webkit_web_view_load_html().
1566  */
1567 void webkit_web_view_load_alternate_html(WebKitWebView* webView, const gchar* content, const gchar* contentURI, const gchar* baseURI)
1568 {
1569     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1570     g_return_if_fail(content);
1571     g_return_if_fail(contentURI);
1572
1573     WKRetainPtr<WKStringRef> htmlString(AdoptWK, WKStringCreateWithUTF8CString(content));
1574     WKRetainPtr<WKURLRef> contentURL(AdoptWK, WKURLCreateWithUTF8CString(contentURI));
1575     WKRetainPtr<WKURLRef> baseURL = baseURI ? adoptWK(WKURLCreateWithUTF8CString(baseURI)) : 0;
1576     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
1577     WKPageLoadAlternateHTMLString(toAPI(page), htmlString.get(), baseURL.get(), contentURL.get());
1578     webkitWebViewUpdateURI(webView);
1579 }
1580
1581 /**
1582  * webkit_web_view_load_plain_text:
1583  * @web_view: a #WebKitWebView
1584  * @plain_text: The plain text to load
1585  *
1586  * Load the specified @plain_text string into @web_view. The mime type of
1587  * document will be "text/plain". You can monitor the load
1588  * operation by connecting to #WebKitWebView::load-changed signal.
1589  */
1590 void webkit_web_view_load_plain_text(WebKitWebView* webView, const gchar* plainText)
1591 {
1592     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1593     g_return_if_fail(plainText);
1594
1595     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
1596     WKRetainPtr<WKStringRef> plainTextRef(AdoptWK, WKStringCreateWithUTF8CString(plainText));
1597     WKPageLoadPlainTextString(toAPI(page), plainTextRef.get());
1598 }
1599
1600 /**
1601  * webkit_web_view_load_request:
1602  * @web_view: a #WebKitWebView
1603  * @request: a #WebKitURIRequest to load
1604  *
1605  * Requests loading of the specified #WebKitURIRequest.
1606  * You can monitor the load operation by connecting to
1607  * #WebKitWebView::load-changed signal.
1608  */
1609 void webkit_web_view_load_request(WebKitWebView* webView, WebKitURIRequest* request)
1610 {
1611     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1612     g_return_if_fail(WEBKIT_IS_URI_REQUEST(request));
1613
1614     WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKURLCreateWithUTF8CString(webkit_uri_request_get_uri(request)));
1615     WKRetainPtr<WKURLRequestRef> wkRequest(AdoptWK, WKURLRequestCreateWithWKURL(wkURL.get()));
1616     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
1617     WKPageLoadURLRequest(toAPI(page), wkRequest.get());
1618     webkitWebViewUpdateURI(webView);
1619 }
1620
1621 /**
1622  * webkit_web_view_get_title:
1623  * @web_view: a #WebKitWebView
1624  *
1625  * Gets the value of the #WebKitWebView:title property.
1626  * You can connect to notify::title signal of @web_view to
1627  * be notified when the title has been received.
1628  *
1629  * Returns: The main frame document title of @web_view.
1630  */
1631 const gchar* webkit_web_view_get_title(WebKitWebView* webView)
1632 {
1633     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
1634
1635     return webView->priv->title.data();
1636 }
1637
1638 /**
1639  * webkit_web_view_reload:
1640  * @web_view: a #WebKitWebView
1641  *
1642  * Reloads the current contents of @web_view.
1643  * See also webkit_web_view_reload_bypass_cache().
1644  */
1645 void webkit_web_view_reload(WebKitWebView* webView)
1646 {
1647     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1648
1649     WKPageReload(toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))));
1650     webkitWebViewUpdateURI(webView);
1651 }
1652
1653 /**
1654  * webkit_web_view_reload_bypass_cache:
1655  * @web_view: a #WebKitWebView
1656  *
1657  * Reloads the current contents of @web_view without
1658  * using any cached data.
1659  */
1660 void webkit_web_view_reload_bypass_cache(WebKitWebView* webView)
1661 {
1662     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1663
1664     WKPageReloadFromOrigin(toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))));
1665     webkitWebViewUpdateURI(webView);
1666 }
1667
1668 /**
1669  * webkit_web_view_stop_loading:
1670  * @web_view: a #WebKitWebView
1671  *
1672  * Stops any ongoing loading operation in @web_view.
1673  * This method does nothing if no content is being loaded.
1674  * If there is a loading operation in progress, it will be cancelled and
1675  * #WebKitWebView::load-failed signal will be emitted with
1676  * %WEBKIT_NETWORK_ERROR_CANCELLED error.
1677  */
1678 void webkit_web_view_stop_loading(WebKitWebView* webView)
1679 {
1680     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1681
1682     WKPageStopLoading(toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))));
1683 }
1684
1685 /**
1686  * webkit_web_view_go_back:
1687  * @web_view: a #WebKitWebView
1688  *
1689  * Loads the previous history item.
1690  * You can monitor the load operation by connecting to
1691  * #WebKitWebView::load-changed signal.
1692  */
1693 void webkit_web_view_go_back(WebKitWebView* webView)
1694 {
1695     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1696
1697     WKPageGoBack(toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))));
1698     webkitWebViewUpdateURI(webView);
1699 }
1700
1701 /**
1702  * webkit_web_view_can_go_back:
1703  * @web_view: a #WebKitWebView
1704  *
1705  * Determines whether @web_view has a previous history item.
1706  *
1707  * Returns: %TRUE if able to move back or %FALSE otherwise.
1708  */
1709 gboolean webkit_web_view_can_go_back(WebKitWebView* webView)
1710 {
1711     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1712
1713     return WKPageCanGoBack(toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))));
1714 }
1715
1716 /**
1717  * webkit_web_view_go_forward:
1718  * @web_view: a #WebKitWebView
1719  *
1720  * Loads the next history item.
1721  * You can monitor the load operation by connecting to
1722  * #WebKitWebView::load-changed signal.
1723  */
1724 void webkit_web_view_go_forward(WebKitWebView* webView)
1725 {
1726     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1727
1728     WKPageGoForward(toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))));
1729     webkitWebViewUpdateURI(webView);
1730 }
1731
1732 /**
1733  * webkit_web_view_can_go_forward:
1734  * @web_view: a #WebKitWebView
1735  *
1736  * Determines whether @web_view has a next history item.
1737  *
1738  * Returns: %TRUE if able to move forward or %FALSE otherwise.
1739  */
1740 gboolean webkit_web_view_can_go_forward(WebKitWebView* webView)
1741 {
1742     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1743
1744     return WKPageCanGoForward(toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))));
1745 }
1746
1747 /**
1748  * webkit_web_view_get_uri:
1749  * @web_view: a #WebKitWebView
1750  *
1751  * Returns the current active URI of @web_view. The active URI might change during
1752  * a load operation:
1753  *
1754  * <orderedlist>
1755  * <listitem><para>
1756  *   When nothing has been loaded yet on @web_view the active URI is %NULL.
1757  * </para></listitem>
1758  * <listitem><para>
1759  *   When a new load operation starts the active URI is the requested URI:
1760  *   <itemizedlist>
1761  *   <listitem><para>
1762  *     If the load operation was started by webkit_web_view_load_uri(),
1763  *     the requested URI is the given one.
1764  *   </para></listitem>
1765  *   <listitem><para>
1766  *     If the load operation was started by webkit_web_view_load_html(),
1767  *     the requested URI is "about:blank".
1768  *   </para></listitem>
1769  *   <listitem><para>
1770  *     If the load operation was started by webkit_web_view_load_alternate_html(),
1771  *     the requested URI is content URI provided.
1772  *   </para></listitem>
1773  *   <listitem><para>
1774  *     If the load operation was started by webkit_web_view_go_back() or
1775  *     webkit_web_view_go_forward(), the requested URI is the original URI
1776  *     of the previous/next item in the #WebKitBackForwardList of @web_view.
1777  *   </para></listitem>
1778  *   <listitem><para>
1779  *     If the load operation was started by
1780  *     webkit_web_view_go_to_back_forward_list_item(), the requested URI
1781  *     is the opriginal URI of the given #WebKitBackForwardListItem.
1782  *   </para></listitem>
1783  *   </itemizedlist>
1784  * </para></listitem>
1785  * <listitem><para>
1786  *   If there is a server redirection during the load operation,
1787  *   the active URI is the redirected URI. When the signal
1788  *   #WebKitWebView::load-changed is emitted with %WEBKIT_LOAD_REDIRECTED
1789  *   event, the active URI is already updated to the redirected URI.
1790  * </para></listitem>
1791  * <listitem><para>
1792  *   When the signal #WebKitWebView::load-changed is emitted
1793  *   with %WEBKIT_LOAD_COMMITTED event, the active URI is the final
1794  *   one and it will not change unless a new load operation is started
1795  *   or a navigation action within the same page is performed.
1796  * </para></listitem>
1797  * </orderedlist>
1798  *
1799  * You can monitor the active URI by connecting to the notify::uri
1800  * signal of @web_view.
1801  *
1802  * Returns: the current active URI of @web_view or %NULL
1803  *    if nothing has been loaded yet.
1804  */
1805 const gchar* webkit_web_view_get_uri(WebKitWebView* webView)
1806 {
1807     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
1808
1809     return webView->priv->activeURI.data();
1810 }
1811
1812 /**
1813  * webkit_web_view_get_custom_charset:
1814  * @web_view: a #WebKitWebView
1815  *
1816  * Returns the current custom character encoding name of @web_view.
1817  *
1818  * Returns: the current custom character encoding name or %NULL if no
1819  *    custom character encoding has been set.
1820  */
1821 const gchar* webkit_web_view_get_custom_charset(WebKitWebView* webView)
1822 {
1823     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
1824
1825     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
1826     WKRetainPtr<WKStringRef> wkCustomEncoding(AdoptWK, WKPageCopyCustomTextEncodingName(toAPI(page)));
1827     if (WKStringIsEmpty(wkCustomEncoding.get()))
1828         return 0;
1829
1830     webView->priv->customTextEncoding = toImpl(wkCustomEncoding.get())->string().utf8();
1831     return webView->priv->customTextEncoding.data();
1832 }
1833
1834 /**
1835  * webkit_web_view_set_custom_charset:
1836  * @web_view: a #WebKitWebView
1837  * @charset: (allow-none): a character encoding name or %NULL
1838  *
1839  * Sets the current custom character encoding override of @web_view. The custom
1840  * character encoding will override any text encoding detected via HTTP headers or
1841  * META tags. Calling this method will stop any current load operation and reload the
1842  * current page. Setting the custom character encoding to %NULL removes the character
1843  * encoding override.
1844  */
1845 void webkit_web_view_set_custom_charset(WebKitWebView* webView, const gchar* charset)
1846 {
1847     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1848
1849     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
1850     WKRetainPtr<WKStringRef> wkEncodingName = charset ? adoptWK(WKStringCreateWithUTF8CString(charset)) : 0;
1851     WKPageSetCustomTextEncodingName(toAPI(page), wkEncodingName.get());
1852 }
1853
1854 /**
1855  * webkit_web_view_get_estimated_load_progress:
1856  * @web_view: a #WebKitWebView
1857  *
1858  * Gets the value of the #WebKitWebView:estimated-load-progress property.
1859  * You can monitor the estimated progress of a load operation by
1860  * connecting to the notify::estimated-load-progress signal of @web_view.
1861  *
1862  * Returns: an estimate of the of the percent complete for a document
1863  *     load as a range from 0.0 to 1.0.
1864  */
1865 gdouble webkit_web_view_get_estimated_load_progress(WebKitWebView* webView)
1866 {
1867     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
1868     return webView->priv->estimatedLoadProgress;
1869 }
1870
1871 /**
1872  * webkit_web_view_get_back_forward_list:
1873  * @web_view: a #WebKitWebView
1874  *
1875  * Obtains the #WebKitBackForwardList associated with the given #WebKitWebView. The
1876  * #WebKitBackForwardList is owned by the #WebKitWebView.
1877  *
1878  * Returns: (transfer none): the #WebKitBackForwardList
1879  */
1880 WebKitBackForwardList* webkit_web_view_get_back_forward_list(WebKitWebView* webView)
1881 {
1882     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
1883
1884     return webView->priv->backForwardList.get();
1885 }
1886
1887 /**
1888  * webkit_web_view_go_to_back_forward_list_item:
1889  * @web_view: a #WebKitWebView
1890  * @list_item: a #WebKitBackForwardListItem
1891  *
1892  * Loads the specific history item @list_item.
1893  * You can monitor the load operation by connecting to
1894  * #WebKitWebView::load-changed signal.
1895  */
1896 void webkit_web_view_go_to_back_forward_list_item(WebKitWebView* webView, WebKitBackForwardListItem* listItem)
1897 {
1898     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1899     g_return_if_fail(WEBKIT_IS_BACK_FORWARD_LIST_ITEM(listItem));
1900
1901     WKPageGoToBackForwardListItem(toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))),
1902                                   webkitBackForwardListItemGetWKItem(listItem));
1903     webkitWebViewUpdateURI(webView);
1904 }
1905
1906 /**
1907  * webkit_web_view_set_settings:
1908  * @web_view: a #WebKitWebView
1909  * @settings: a #WebKitSettings
1910  *
1911  * Sets the #WebKitSettings to be applied to @web_view. The
1912  * existing #WebKitSettings of @web_view will be replaced by
1913  * @settings. New settings are applied immediately on @web_view.
1914  * The same #WebKitSettings object can be shared
1915  * by multiple #WebKitWebView<!-- -->s.
1916  */
1917 void webkit_web_view_set_settings(WebKitWebView* webView, WebKitSettings* settings)
1918 {
1919     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1920     g_return_if_fail(WEBKIT_IS_SETTINGS(settings));
1921
1922     if (webView->priv->settings == settings)
1923         return;
1924
1925     webkitWebViewDisconnectSettingsSignalHandlers(webView);
1926     webkitWebViewSetSettings(webView, settings, toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))));
1927 }
1928
1929 /**
1930  * webkit_web_view_get_settings:
1931  * @web_view: a #WebKitWebView
1932  *
1933  * Gets the #WebKitSettings currently applied to @web_view.
1934  * If no other #WebKitSettings have been explicitly applied to
1935  * @web_view with webkit_web_view_set_settings(), the default
1936  * #WebKitSettings will be returned. This method always returns
1937  * a valid #WebKitSettings object.
1938  * To modify any of the @web_view settings, you can either create
1939  * a new #WebKitSettings object with webkit_settings_new(), setting
1940  * the desired preferences, and then replace the existing @web_view
1941  * settings with webkit_web_view_set_settings() or get the existing
1942  * @web_view settings and update it directly. #WebKitSettings objects
1943  * can be shared by multiple #WebKitWebView<!-- -->s, so modifying
1944  * the settings of a #WebKitWebView would affect other
1945  * #WebKitWebView<!-- -->s using the same #WebKitSettings.
1946  *
1947  * Returns: (transfer none): the #WebKitSettings attached to @web_view
1948  */
1949 WebKitSettings* webkit_web_view_get_settings(WebKitWebView* webView)
1950 {
1951     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
1952
1953     return webView->priv->settings.get();
1954 }
1955
1956 /**
1957  * webkit_web_view_get_window_properties:
1958  * @web_view: a #WebKitWebView
1959  *
1960  * Get the #WebKitWindowProperties object containing the properties
1961  * that the window containing @web_view should have.
1962  *
1963  * Returns: (transfer none): the #WebKitWindowProperties of @web_view
1964  */
1965 WebKitWindowProperties* webkit_web_view_get_window_properties(WebKitWebView* webView)
1966 {
1967     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
1968
1969     return webView->priv->windowProperties.get();
1970 }
1971
1972 /**
1973  * webkit_web_view_set_zoom_level:
1974  * @web_view: a #WebKitWebView
1975  * @zoom_level: the zoom level
1976  *
1977  * Set the zoom level of @web_view, i.e. the factor by which the
1978  * view contents are scaled with respect to their original size.
1979  */
1980 void webkit_web_view_set_zoom_level(WebKitWebView* webView, gdouble zoomLevel)
1981 {
1982     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1983
1984     if (webkit_web_view_get_zoom_level(webView) == zoomLevel)
1985         return;
1986
1987     WKPageRef wkPage = toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView)));
1988     if (webkit_settings_get_zoom_text_only(webView->priv->settings.get()))
1989         WKPageSetTextZoomFactor(wkPage, zoomLevel);
1990     else
1991         WKPageSetPageZoomFactor(wkPage, zoomLevel);
1992     g_object_notify(G_OBJECT(webView), "zoom-level");
1993 }
1994
1995 /**
1996  * webkit_web_view_get_zoom_level:
1997  * @web_view: a #WebKitWebView
1998  *
1999  * Get the zoom level of @web_view, i.e. the factor by which the
2000  * view contents are scaled with respect to their original size.
2001  *
2002  * Returns: the current zoom level of @web_view
2003  */
2004 gdouble webkit_web_view_get_zoom_level(WebKitWebView* webView)
2005 {
2006     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 1);
2007
2008     WKPageRef wkPage = toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView)));
2009     gboolean zoomTextOnly = webkit_settings_get_zoom_text_only(webView->priv->settings.get());
2010     return zoomTextOnly ? WKPageGetTextZoomFactor(wkPage) : WKPageGetPageZoomFactor(wkPage);
2011 }
2012
2013 struct ValidateEditingCommandAsyncData {
2014     bool isEnabled;
2015     GRefPtr<GCancellable> cancellable;
2016 };
2017 WEBKIT_DEFINE_ASYNC_DATA_STRUCT(ValidateEditingCommandAsyncData)
2018
2019 static void didValidateCommand(WKStringRef command, bool isEnabled, int32_t state, WKErrorRef, void* context)
2020 {
2021     GRefPtr<GSimpleAsyncResult> result = adoptGRef(G_SIMPLE_ASYNC_RESULT(context));
2022     ValidateEditingCommandAsyncData* data = static_cast<ValidateEditingCommandAsyncData*>(g_simple_async_result_get_op_res_gpointer(result.get()));
2023     GError* error = 0;
2024     if (g_cancellable_set_error_if_cancelled(data->cancellable.get(), &error))
2025         g_simple_async_result_take_error(result.get(), error);
2026     else
2027         data->isEnabled = isEnabled;
2028     g_simple_async_result_complete(result.get());
2029 }
2030
2031 /**
2032  * webkit_web_view_can_execute_editing_command:
2033  * @web_view: a #WebKitWebView
2034  * @command: the command to check
2035  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
2036  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
2037  * @user_data: (closure): the data to pass to callback function
2038  *
2039  * Asynchronously execute the given editing command.
2040  *
2041  * When the operation is finished, @callback will be called. You can then call
2042  * webkit_web_view_can_execute_editing_command_finish() to get the result of the operation.
2043  */
2044 void webkit_web_view_can_execute_editing_command(WebKitWebView* webView, const char* command, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
2045 {
2046     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2047     g_return_if_fail(command);
2048
2049     GSimpleAsyncResult* result = g_simple_async_result_new(G_OBJECT(webView), callback, userData,
2050                                                            reinterpret_cast<gpointer>(webkit_web_view_can_execute_editing_command));
2051     ValidateEditingCommandAsyncData* data = createValidateEditingCommandAsyncData();
2052     data->cancellable = cancellable;
2053     g_simple_async_result_set_op_res_gpointer(result, data, reinterpret_cast<GDestroyNotify>(destroyValidateEditingCommandAsyncData));
2054
2055     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
2056     WKRetainPtr<WKStringRef> wkCommand(AdoptWK, WKStringCreateWithUTF8CString(command));
2057     WKPageValidateCommand(toAPI(page), wkCommand.get(), result, didValidateCommand);
2058 }
2059
2060 /**
2061  * webkit_web_view_can_execute_editing_command_finish:
2062  * @web_view: a #WebKitWebView
2063  * @result: a #GAsyncResult
2064  * @error: return location for error or %NULL to ignore
2065  *
2066  * Finish an asynchronous operation started with webkit_web_view_can_execute_editing_command().
2067  *
2068  * Returns: %TRUE if the editing command can be executed or %FALSE otherwise
2069  */
2070 gboolean webkit_web_view_can_execute_editing_command_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
2071 {
2072     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2073     g_return_val_if_fail(G_IS_ASYNC_RESULT(result), FALSE);
2074
2075     GSimpleAsyncResult* simple = G_SIMPLE_ASYNC_RESULT(result);
2076     g_warn_if_fail(g_simple_async_result_get_source_tag(simple) == webkit_web_view_can_execute_editing_command);
2077
2078     if (g_simple_async_result_propagate_error(simple, error))
2079         return FALSE;
2080
2081     ValidateEditingCommandAsyncData* data = static_cast<ValidateEditingCommandAsyncData*>(g_simple_async_result_get_op_res_gpointer(simple));
2082     return data->isEnabled;
2083 }
2084
2085 /**
2086  * webkit_web_view_execute_editing_command:
2087  * @web_view: a #WebKitWebView
2088  * @command: the command to execute
2089  *
2090  * Request to execute the given @command for @web_view. You can use
2091  * webkit_web_view_can_execute_editing_command() to check whether
2092  * it's possible to execute the command.
2093  */
2094 void webkit_web_view_execute_editing_command(WebKitWebView* webView, const char* command)
2095 {
2096     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2097     g_return_if_fail(command);
2098
2099     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
2100     WKRetainPtr<WKStringRef> wkCommand(AdoptWK, WKStringCreateWithUTF8CString(command));
2101     WKPageExecuteCommand(toAPI(page), wkCommand.get());
2102 }
2103
2104 /**
2105  * webkit_web_view_get_find_controller:
2106  * @web_view: the #WebKitWebView
2107  *
2108  * Gets the #WebKitFindController that will allow the caller to query
2109  * the #WebKitWebView for the text to look for.
2110  *
2111  * Returns: (transfer none): the #WebKitFindController associated to
2112  * this particular #WebKitWebView.
2113  */
2114 WebKitFindController* webkit_web_view_get_find_controller(WebKitWebView* webView)
2115 {
2116     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2117
2118     if (!webView->priv->findController)
2119         webView->priv->findController = adoptGRef(WEBKIT_FIND_CONTROLLER(g_object_new(WEBKIT_TYPE_FIND_CONTROLLER, "web-view", webView, NULL)));
2120
2121     return webView->priv->findController.get();
2122 }
2123
2124 /**
2125  * webkit_web_view_get_javascript_global_context:
2126  * @web_view: a #WebKitWebView
2127  *
2128  * Get the global JavaScript context used by @web_view to deserialize the
2129  * result values of scripts executed with webkit_web_view_run_javascript().
2130  *
2131  * Returns: the <function>JSGlobalContextRef</function> used by @web_view to deserialize
2132  *    the result values of scripts.
2133  */
2134 JSGlobalContextRef webkit_web_view_get_javascript_global_context(WebKitWebView* webView)
2135 {
2136     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2137
2138     if (!webView->priv->javascriptGlobalContext)
2139         webView->priv->javascriptGlobalContext = JSGlobalContextCreate(0);
2140     return webView->priv->javascriptGlobalContext;
2141 }
2142
2143 struct RunJavaScriptAsyncData {
2144     ~RunJavaScriptAsyncData()
2145     {
2146         if (scriptResult)
2147             webkit_javascript_result_unref(scriptResult);
2148     }
2149
2150     WebKitJavascriptResult* scriptResult;
2151     GRefPtr<GCancellable> cancellable;
2152 };
2153 WEBKIT_DEFINE_ASYNC_DATA_STRUCT(RunJavaScriptAsyncData)
2154
2155 static void webkitWebViewRunJavaScriptCallback(WKSerializedScriptValueRef wkSerializedScriptValue, WKErrorRef, void* context)
2156 {
2157     GRefPtr<GSimpleAsyncResult> result = adoptGRef(G_SIMPLE_ASYNC_RESULT(context));
2158     RunJavaScriptAsyncData* data = static_cast<RunJavaScriptAsyncData*>(g_simple_async_result_get_op_res_gpointer(result.get()));
2159     GError* error = 0;
2160     if (g_cancellable_set_error_if_cancelled(data->cancellable.get(), &error))
2161         g_simple_async_result_take_error(result.get(), error);
2162     else if (wkSerializedScriptValue) {
2163         GRefPtr<WebKitWebView> webView = adoptGRef(WEBKIT_WEB_VIEW(g_async_result_get_source_object(G_ASYNC_RESULT(result.get()))));
2164         data->scriptResult = webkitJavascriptResultCreate(webView.get(), wkSerializedScriptValue);
2165     } else {
2166         g_set_error_literal(&error, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED, _("An exception was raised in JavaScript"));
2167         g_simple_async_result_take_error(result.get(), error);
2168     }
2169     g_simple_async_result_complete(result.get());
2170 }
2171
2172 /**
2173  * webkit_web_view_run_javascript:
2174  * @web_view: a #WebKitWebView
2175  * @script: the script to run
2176  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
2177  * @callback: (scope async): a #GAsyncReadyCallback to call when the script finished
2178  * @user_data: (closure): the data to pass to callback function
2179  *
2180  * Asynchronously run @script in the context of the current page in @web_view.
2181  *
2182  * When the operation is finished, @callback will be called. You can then call
2183  * webkit_web_view_run_javascript_finish() to get the result of the operation.
2184  */
2185 void webkit_web_view_run_javascript(WebKitWebView* webView, const gchar* script, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
2186 {
2187     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2188     g_return_if_fail(script);
2189
2190     WKPageRef wkPage = toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView)));
2191     WKRetainPtr<WKStringRef> wkScript = adoptWK(WKStringCreateWithUTF8CString(script));
2192     GSimpleAsyncResult* result = g_simple_async_result_new(G_OBJECT(webView), callback, userData,
2193                                                            reinterpret_cast<gpointer>(webkit_web_view_run_javascript));
2194     RunJavaScriptAsyncData* data = createRunJavaScriptAsyncData();
2195     data->cancellable = cancellable;
2196     g_simple_async_result_set_op_res_gpointer(result, data, reinterpret_cast<GDestroyNotify>(destroyRunJavaScriptAsyncData));
2197     WKPageRunJavaScriptInMainFrame(wkPage, wkScript.get(), result, webkitWebViewRunJavaScriptCallback);
2198 }
2199
2200 /**
2201  * webkit_web_view_run_javascript_finish:
2202  * @web_view: a #WebKitWebView
2203  * @result: a #GAsyncResult
2204  * @error: return location for error or %NULL to ignore
2205  *
2206  * Finish an asynchronous operation started with webkit_web_view_run_javascript().
2207  *
2208  * This is an example of using webkit_web_view_run_javascript() with a script returning
2209  * a string:
2210  *
2211  * <informalexample><programlisting>
2212  * static void
2213  * web_view_javascript_finished (GObject      *object,
2214  *                               GAsyncResult *result,
2215  *                               gpointer      user_data)
2216  * {
2217  *     WebKitJavascriptResult *js_result;
2218  *     JSValueRef              value;
2219  *     JSGlobalContextRef      context;
2220  *     GError                 *error = NULL;
2221  *
2222  *     js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (object), result, &error);
2223  *     if (!js_result) {
2224  *         g_warning ("Error running javascript: %s", error->message);
2225  *         g_error_free (error);
2226  *         return;
2227  *     }
2228  *
2229  *     context = webkit_javascript_result_get_global_context (js_result);
2230  *     value = webkit_javascript_result_get_value (js_result);
2231  *     if (JSValueIsString (context, value)) {
2232  *         JSStringRef js_str_value;
2233  *         gchar      *str_value;
2234  *         gsize       str_length;
2235  *
2236  *         js_str_value = JSValueToStringCopy (context, value, NULL);
2237  *         str_length = JSStringGetMaximumUTF8CStringSize (js_str_value);
2238  *         str_value = (gchar *)g_malloc (str_length);
2239  *         JSStringGetUTF8CString (js_str_value, str_value, str_length);
2240  *         JSStringRelease (js_str_value);
2241  *         g_print ("Script result: %s\n", str_value);
2242  *         g_free (str_value);
2243  *     } else {
2244  *         g_warning ("Error running javascript: unexpected return value");
2245  *     }
2246  *     webkit_javascript_result_unref (js_result);
2247  * }
2248  *
2249  * static void
2250  * web_view_get_link_url (WebKitWebView *web_view,
2251  *                        const gchar   *link_id)
2252  * {
2253  *     gchar *script;
2254  *
2255  *     script = g_strdup_printf ("window.document.getElementById('%s').href;", link_id);
2256  *     webkit_web_view_run_javascript (web_view, script, NULL, web_view_javascript_finished, NULL);
2257  *     g_free (script);
2258  * }
2259  * </programlisting></informalexample>
2260  *
2261  * Returns: (transfer full): a #WebKitJavascriptResult with the result of the last executed statement in @script
2262  *    or %NULL in case of error
2263  */
2264 WebKitJavascriptResult* webkit_web_view_run_javascript_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
2265 {
2266     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2267     g_return_val_if_fail(G_IS_ASYNC_RESULT(result), 0);
2268
2269     GSimpleAsyncResult* simpleResult = G_SIMPLE_ASYNC_RESULT(result);
2270     g_warn_if_fail(g_simple_async_result_get_source_tag(simpleResult) == webkit_web_view_run_javascript);
2271
2272     if (g_simple_async_result_propagate_error(simpleResult, error))
2273         return 0;
2274
2275     RunJavaScriptAsyncData* data = static_cast<RunJavaScriptAsyncData*>(g_simple_async_result_get_op_res_gpointer(simpleResult));
2276     return data->scriptResult ? webkit_javascript_result_ref(data->scriptResult) : 0;
2277 }
2278
2279 /**
2280  * webkit_web_view_get_main_resource:
2281  * @web_view: a #WebKitWebView
2282  *
2283  * Return the main resource of @web_view.
2284  * See also webkit_web_view_get_subresources():
2285  *
2286  * Returns: (transfer none): the main #WebKitWebResource of the view
2287  *    or %NULL if nothing has been loaded.
2288  */
2289 WebKitWebResource* webkit_web_view_get_main_resource(WebKitWebView* webView)
2290 {
2291     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2292
2293     return webView->priv->mainResource.get();
2294 }
2295
2296 /**
2297  * webkit_web_view_get_subresources:
2298  * @web_view: a #WebKitWebView
2299  *
2300  * Return the list of subresources of @web_view.
2301  * See also webkit_web_view_get_main_resource().
2302  *
2303  * Returns: (element-type WebKitWebResource) (transfer container): a list of #WebKitWebResource.
2304  */
2305 GList* webkit_web_view_get_subresources(WebKitWebView* webView)
2306 {
2307     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2308
2309     GList* subresources = 0;
2310     WebKitWebViewPrivate* priv = webView->priv;
2311     ResourcesMap::const_iterator end = priv->subresourcesMap.end();
2312     for (ResourcesMap::const_iterator it = priv->subresourcesMap.begin(); it != end; ++it)
2313         subresources = g_list_prepend(subresources, it->second.get());
2314
2315     return g_list_reverse(subresources);
2316 }
2317
2318 /**
2319  * webkit_web_view_get_inspector:
2320  * @web_view: a #WebKitWebView
2321  *
2322  * Get the #WebKitWebInspector associated to @web_view
2323  *
2324  * Returns: (transfer none): the #WebKitWebInspector of @web_view
2325  */
2326 WebKitWebInspector* webkit_web_view_get_inspector(WebKitWebView* webView)
2327 {
2328     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2329
2330     if (!webView->priv->inspector) {
2331         WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
2332         webView->priv->inspector = adoptGRef(webkitWebInspectorCreate(toAPI(page->inspector())));
2333     }
2334
2335     return webView->priv->inspector.get();
2336 }
2337
2338 /**
2339  * webkit_web_view_can_show_mime_type:
2340  * @web_view: a #WebKitWebView
2341  * @mime_type: a MIME type
2342  *
2343  * Whether or not a MIME type can be displayed in @web_view.
2344  *
2345  * Returns: %TRUE if the MIME type @mime_type can be displayed or %FALSE otherwise
2346  */
2347 gboolean webkit_web_view_can_show_mime_type(WebKitWebView* webView, const char* mimeType)
2348 {
2349     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2350     g_return_val_if_fail(mimeType, FALSE);
2351
2352     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
2353     return page->canShowMIMEType(String::fromUTF8(mimeType));
2354 }
2355
2356 struct ViewSaveAsyncData {
2357     WKRetainPtr<WKDataRef> wkData;
2358     GRefPtr<GFile> file;
2359     GRefPtr<GCancellable> cancellable;
2360 };
2361 WEBKIT_DEFINE_ASYNC_DATA_STRUCT(ViewSaveAsyncData)
2362
2363 static void fileReplaceContentsCallback(GObject* object, GAsyncResult* result, gpointer data)
2364 {
2365     GFile* file = G_FILE(object);
2366     GRefPtr<GSimpleAsyncResult> savedToFileResult = adoptGRef(G_SIMPLE_ASYNC_RESULT(data));
2367
2368     GError* error = 0;
2369     if (!g_file_replace_contents_finish(file, result, 0, &error))
2370         g_simple_async_result_take_error(savedToFileResult.get(), error);
2371
2372     g_simple_async_result_complete(savedToFileResult.get());
2373 }
2374
2375 static void getContentsAsMHTMLDataCallback(WKDataRef wkData, WKErrorRef, void* context)
2376 {
2377     GRefPtr<GSimpleAsyncResult> result = adoptGRef(G_SIMPLE_ASYNC_RESULT(context));
2378     ViewSaveAsyncData* data = static_cast<ViewSaveAsyncData*>(g_simple_async_result_get_op_res_gpointer(result.get()));
2379     GError* error = 0;
2380
2381     if (g_cancellable_set_error_if_cancelled(data->cancellable.get(), &error))
2382         g_simple_async_result_take_error(result.get(), error);
2383     else {
2384         // We need to retain the data until the asyncronous process
2385         // initiated by the user has finished completely.
2386         data->wkData = wkData;
2387
2388         // If we are saving to a file we need to write the data on disk before finishing.
2389         if (g_simple_async_result_get_source_tag(result.get()) == webkit_web_view_save_to_file) {
2390             ASSERT(G_IS_FILE(data->file.get()));
2391             g_file_replace_contents_async(data->file.get(), reinterpret_cast<const gchar*>(WKDataGetBytes(data->wkData.get())), WKDataGetSize(data->wkData.get()), 0, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
2392                                           data->cancellable.get(), fileReplaceContentsCallback, g_object_ref(result.get()));
2393             return;
2394         }
2395     }
2396
2397     g_simple_async_result_complete(result.get());
2398 }
2399
2400 /**
2401  * webkit_web_view_save:
2402  * @web_view: a #WebKitWebView
2403  * @save_mode: the #WebKitSaveMode specifying how the web page should be saved.
2404  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
2405  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
2406  * @user_data: (closure): the data to pass to callback function
2407  *
2408  * Asynchronously save the current web page associated to the
2409  * #WebKitWebView into a self-contained format using the mode
2410  * specified in @save_mode.
2411  *
2412  * When the operation is finished, @callback will be called. You can
2413  * then call webkit_web_view_save_finish() to get the result of the
2414  * operation.
2415  */
2416 void webkit_web_view_save(WebKitWebView* webView, WebKitSaveMode saveMode, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
2417 {
2418     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2419
2420     // We only support MHTML at the moment.
2421     g_return_if_fail(saveMode == WEBKIT_SAVE_MODE_MHTML);
2422
2423     GSimpleAsyncResult* result = g_simple_async_result_new(G_OBJECT(webView), callback, userData,
2424                                                            reinterpret_cast<gpointer>(webkit_web_view_save));
2425     ViewSaveAsyncData* data = createViewSaveAsyncData();
2426     data->cancellable = cancellable;
2427     g_simple_async_result_set_op_res_gpointer(result, data, reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData));
2428
2429     WKPageRef wkPage = toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView)));
2430     WKPageGetContentsAsMHTMLData(wkPage, false, result, getContentsAsMHTMLDataCallback);
2431 }
2432
2433 /**
2434  * webkit_web_view_save_finish:
2435  * @web_view: a #WebKitWebView
2436  * @result: a #GAsyncResult
2437  * @error: return location for error or %NULL to ignore
2438  *
2439  * Finish an asynchronous operation started with webkit_web_view_save().
2440  *
2441  * Returns: (transfer full): a #GInputStream with the result of saving
2442  *    the current web page or %NULL in case of error.
2443  */
2444 GInputStream* webkit_web_view_save_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
2445 {
2446     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2447     g_return_val_if_fail(G_IS_ASYNC_RESULT(result), 0);
2448
2449     GSimpleAsyncResult* simple = G_SIMPLE_ASYNC_RESULT(result);
2450     g_warn_if_fail(g_simple_async_result_get_source_tag(simple) == webkit_web_view_save);
2451
2452     if (g_simple_async_result_propagate_error(simple, error))
2453         return 0;
2454
2455     GInputStream* dataStream = g_memory_input_stream_new();
2456     ViewSaveAsyncData* data = static_cast<ViewSaveAsyncData*>(g_simple_async_result_get_op_res_gpointer(simple));
2457     gsize length = WKDataGetSize(data->wkData.get());
2458     if (length)
2459         g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(dataStream), g_memdup(WKDataGetBytes(data->wkData.get()), length), length, g_free);
2460
2461     return dataStream;
2462 }
2463
2464 /**
2465  * webkit_web_view_save_to_file:
2466  * @web_view: a #WebKitWebView
2467  * @file: the #GFile where the current web page should be saved to.
2468  * @save_mode: the #WebKitSaveMode specifying how the web page should be saved.
2469  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
2470  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
2471  * @user_data: (closure): the data to pass to callback function
2472  *
2473  * Asynchronously save the current web page associated to the
2474  * #WebKitWebView into a self-contained format using the mode
2475  * specified in @save_mode and writing it to @file.
2476  *
2477  * When the operation is finished, @callback will be called. You can
2478  * then call webkit_web_view_save_to_file_finish() to get the result of the
2479  * operation.
2480  */
2481 void webkit_web_view_save_to_file(WebKitWebView* webView, GFile* file, WebKitSaveMode saveMode, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
2482 {
2483     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2484     g_return_if_fail(G_IS_FILE(file));
2485
2486     // We only support MHTML at the moment.
2487     g_return_if_fail(saveMode == WEBKIT_SAVE_MODE_MHTML);
2488
2489     GSimpleAsyncResult* result = g_simple_async_result_new(G_OBJECT(webView), callback, userData,
2490                                                            reinterpret_cast<gpointer>(webkit_web_view_save_to_file));
2491     ViewSaveAsyncData* data = createViewSaveAsyncData();
2492     data->file = file;
2493     data->cancellable = cancellable;
2494     g_simple_async_result_set_op_res_gpointer(result, data, reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData));
2495
2496     WKPageRef wkPage = toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView)));
2497     WKPageGetContentsAsMHTMLData(wkPage, false, result, getContentsAsMHTMLDataCallback);
2498 }
2499
2500 /**
2501  * webkit_web_view_save_to_file_finish:
2502  * @web_view: a #WebKitWebView
2503  * @result: a #GAsyncResult
2504  * @error: return location for error or %NULL to ignore
2505  *
2506  * Finish an asynchronous operation started with webkit_web_view_save_to_file().
2507  *
2508  * Returns: %TRUE if the web page was successfully saved to a file or %FALSE otherwise.
2509  */
2510 gboolean webkit_web_view_save_to_file_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
2511 {
2512     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2513     g_return_val_if_fail(G_IS_ASYNC_RESULT(result), FALSE);
2514
2515     GSimpleAsyncResult* simple = G_SIMPLE_ASYNC_RESULT(result);
2516     g_warn_if_fail(g_simple_async_result_get_source_tag(simple) == webkit_web_view_save_to_file);
2517
2518     if (g_simple_async_result_propagate_error(simple, error))
2519         return FALSE;
2520
2521     return TRUE;
2522 }