<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[193826] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/193826">193826</a></dd>
<dt>Author</dt> <dd>carlosgc@webkit.org</dd>
<dt>Date</dt> <dd>2015-12-09 05:32:54 -0800 (Wed, 09 Dec 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[GTK] Add API to handle beforeunload events
https://bugs.webkit.org/show_bug.cgi?id=139090

Reviewed by Gustavo Noronha Silva.

Source/WebKit2:

beforeunload is fired when a page is about to be closed, to ask
the user for confirmation. This happens when reloading a page,
when navigating to another page or when the page is closed by a
user action (a tab or window closed). In the first two cases, the
event is automatically fired by WebCore, but in the case of a user
action we need additional API to ensure the event is fired before
the page is closed. A new script dialog type has been added to
handle beforeunload events and webkit_web_view_try_close() to
allow applications to try to close the page.

* UIProcess/API/gtk/WebKitScriptDialog.cpp:
(webkit_script_dialog_confirm_set_confirmed): BeforeUnloadConfirm
dialogs can also be confirmed.
* UIProcess/API/gtk/WebKitScriptDialog.h: Add
WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM script dialog type.
* UIProcess/API/gtk/WebKitUIClient.cpp: Implement
canRunBeforeUnloadConfirmPanel() and runBeforeUnloadConfirmPanel().
* UIProcess/API/gtk/WebKitWebView.cpp:
(webkitWebViewCreateJavaScriptDialog): Add secondaryText optional
parameter for BeforeUnloadConfirm dialogs. Do not set the default
response if the dialog was created without buttons.
(webkitWebViewScriptDialog): Handle
WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM script dialog type to
create a message dialog for beforeunlos events.
(webkit_web_view_class_init): Update documentation of
WebKitWebView::close and WebKitWebView::script-dialog.
(webkitWebViewRunJavaScriptBeforeUnloadConfirm): Emit WebKitWebView::script-dialog.
(webkit_web_view_try_close): Try to close the page.
* UIProcess/API/gtk/WebKitWebView.h:
* UIProcess/API/gtk/WebKitWebViewPrivate.h:
* UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Add new symbol.

Tools:

* MiniBrowser/gtk/BrowserWindow.c:
(browserWindowConstructed):
(browserWindowDeleteEvent):
(browser_window_class_init):
Handle delete-event to prevent the window from being closed when
the page has beforeunload handlers. Use
webkit_web_view_try_close() when the window is requested to be
closed.
* TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp:
(testWebViewJavaScriptDialogs):
Add a test case for the WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM
script dialog type.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIgtkWebKitScriptDialogcpp">trunk/Source/WebKit2/UIProcess/API/gtk/WebKitScriptDialog.cpp</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIgtkWebKitScriptDialogh">trunk/Source/WebKit2/UIProcess/API/gtk/WebKitScriptDialog.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIgtkWebKitUIClientcpp">trunk/Source/WebKit2/UIProcess/API/gtk/WebKitUIClient.cpp</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIgtkWebKitWebViewcpp">trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIgtkWebKitWebViewh">trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIgtkWebKitWebViewPrivateh">trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIgtkdocswebkit2gtk40sectionstxt">trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsMiniBrowsergtkBrowserWindowc">trunk/Tools/MiniBrowser/gtk/BrowserWindow.c</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2GtkTestUIClientcpp">trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (193825 => 193826)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2015-12-09 13:30:11 UTC (rev 193825)
+++ trunk/Source/WebKit2/ChangeLog        2015-12-09 13:32:54 UTC (rev 193826)
</span><span class="lines">@@ -1,3 +1,42 @@
</span><ins>+2015-12-09  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
+
+        [GTK] Add API to handle beforeunload events
+        https://bugs.webkit.org/show_bug.cgi?id=139090
+
+        Reviewed by Gustavo Noronha Silva.
+
+        beforeunload is fired when a page is about to be closed, to ask
+        the user for confirmation. This happens when reloading a page,
+        when navigating to another page or when the page is closed by a
+        user action (a tab or window closed). In the first two cases, the
+        event is automatically fired by WebCore, but in the case of a user
+        action we need additional API to ensure the event is fired before
+        the page is closed. A new script dialog type has been added to
+        handle beforeunload events and webkit_web_view_try_close() to
+        allow applications to try to close the page.
+
+        * UIProcess/API/gtk/WebKitScriptDialog.cpp:
+        (webkit_script_dialog_confirm_set_confirmed): BeforeUnloadConfirm
+        dialogs can also be confirmed.
+        * UIProcess/API/gtk/WebKitScriptDialog.h: Add
+        WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM script dialog type.
+        * UIProcess/API/gtk/WebKitUIClient.cpp: Implement
+        canRunBeforeUnloadConfirmPanel() and runBeforeUnloadConfirmPanel().
+        * UIProcess/API/gtk/WebKitWebView.cpp:
+        (webkitWebViewCreateJavaScriptDialog): Add secondaryText optional
+        parameter for BeforeUnloadConfirm dialogs. Do not set the default
+        response if the dialog was created without buttons.
+        (webkitWebViewScriptDialog): Handle
+        WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM script dialog type to
+        create a message dialog for beforeunlos events.
+        (webkit_web_view_class_init): Update documentation of
+        WebKitWebView::close and WebKitWebView::script-dialog.
+        (webkitWebViewRunJavaScriptBeforeUnloadConfirm): Emit WebKitWebView::script-dialog.
+        (webkit_web_view_try_close): Try to close the page.
+        * UIProcess/API/gtk/WebKitWebView.h:
+        * UIProcess/API/gtk/WebKitWebViewPrivate.h:
+        * UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Add new symbol.
+
</ins><span class="cx"> 2015-12-09  Gyuyoung Kim  &lt;gyuyoung.kim@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         [EFL] Missing to set ignoreTLSError to NetworkProcess
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIgtkWebKitScriptDialogcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitScriptDialog.cpp (193825 => 193826)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitScriptDialog.cpp        2015-12-09 13:30:11 UTC (rev 193825)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitScriptDialog.cpp        2015-12-09 13:32:54 UTC (rev 193826)
</span><span class="lines">@@ -72,17 +72,17 @@
</span><span class="cx">  * @dialog: a #WebKitScriptDialog
</span><span class="cx">  * @confirmed: whether user confirmed the dialog
</span><span class="cx">  *
</span><del>- * This method is used for %WEBKIT_SCRIPT_DIALOG_CONFIRM dialogs when
</del><ins>+ * This method is used for %WEBKIT_SCRIPT_DIALOG_CONFIRM and %WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM dialogs when
</ins><span class="cx">  * #WebKitWebView::script-dialog signal is emitted to set whether the user
</span><span class="cx">  * confirmed the dialog or not. The default implementation of #WebKitWebView::script-dialog
</span><del>- * signal sets %TRUE when the OK button is clicked and %FALSE otherwise.
</del><ins>+ * signal sets %TRUE when the OK or Stay buttons are clicked and %FALSE otherwise.
</ins><span class="cx">  * It's an error to use this method with a #WebKitScriptDialog that is not of type
</span><del>- * %WEBKIT_SCRIPT_DIALOG_CONFIRM.
</del><ins>+ * %WEBKIT_SCRIPT_DIALOG_CONFIRM or %WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM
</ins><span class="cx">  */
</span><span class="cx"> void webkit_script_dialog_confirm_set_confirmed(WebKitScriptDialog* dialog, gboolean confirmed)
</span><span class="cx"> {
</span><span class="cx">     g_return_if_fail(dialog);
</span><del>-    g_return_if_fail(dialog-&gt;type == WEBKIT_SCRIPT_DIALOG_CONFIRM);
</del><ins>+    g_return_if_fail(dialog-&gt;type == WEBKIT_SCRIPT_DIALOG_CONFIRM || dialog-&gt;type == WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM);
</ins><span class="cx"> 
</span><span class="cx">     dialog-&gt;confirmed = confirmed;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIgtkWebKitScriptDialogh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitScriptDialog.h (193825 => 193826)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitScriptDialog.h        2015-12-09 13:30:11 UTC (rev 193825)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitScriptDialog.h        2015-12-09 13:32:54 UTC (rev 193826)
</span><span class="lines">@@ -41,13 +41,16 @@
</span><span class="cx">  * confirmation to the user.
</span><span class="cx">  * @WEBKIT_SCRIPT_DIALOG_PROMPT: Prompt script dialog, used to ask
</span><span class="cx">  * information to the user.
</span><ins>+ * @WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM: Before unload confirm dialog,
+ * used to ask confirmation to leave the current page to the user. Since 2.12
</ins><span class="cx">  *
</span><span class="cx">  * Enum values used for determining the type of #WebKitScriptDialog
</span><span class="cx">  */
</span><span class="cx"> typedef enum {
</span><span class="cx">     WEBKIT_SCRIPT_DIALOG_ALERT,
</span><span class="cx">     WEBKIT_SCRIPT_DIALOG_CONFIRM,
</span><del>-    WEBKIT_SCRIPT_DIALOG_PROMPT
</del><ins>+    WEBKIT_SCRIPT_DIALOG_PROMPT,
+    WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM
</ins><span class="cx"> } WebKitScriptDialogType;
</span><span class="cx"> 
</span><span class="cx"> WEBKIT_API GType
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIgtkWebKitUIClientcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitUIClient.cpp (193825 => 193826)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitUIClient.cpp        2015-12-09 13:30:11 UTC (rev 193825)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitUIClient.cpp        2015-12-09 13:32:54 UTC (rev 193826)
</span><span class="lines">@@ -84,6 +84,13 @@
</span><span class="cx">         completionHandler(String::fromUTF8(result.data()));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    virtual bool canRunBeforeUnloadConfirmPanel() const override { return true; }
+
+    virtual bool runBeforeUnloadConfirmPanel(WebPageProxy*, const String&amp; message, WebFrameProxy*) override
+    {
+        return webkitWebViewRunJavaScriptBeforeUnloadConfirm(m_webView, message.utf8());
+    }
+
</ins><span class="cx">     virtual void mouseDidMoveOverElement(WebPageProxy*, const WebHitTestResultData&amp; data, WebEvent::Modifiers modifiers, API::Object*) override
</span><span class="cx">     {
</span><span class="cx">         webkitWebViewMouseTargetChanged(m_webView, data, toGdkModifiers(modifiers));
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIgtkWebKitWebViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp (193825 => 193826)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp        2015-12-09 13:30:11 UTC (rev 193825)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp        2015-12-09 13:32:54 UTC (rev 193826)
</span><span class="lines">@@ -325,14 +325,17 @@
</span><span class="cx">     return nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static GtkWidget* webkitWebViewCreateJavaScriptDialog(WebKitWebView* webView, GtkMessageType type, GtkButtonsType buttons, int defaultResponse, const char* message)
</del><ins>+static GtkWidget* webkitWebViewCreateJavaScriptDialog(WebKitWebView* webView, GtkMessageType type, GtkButtonsType buttons, int defaultResponse, const char* primaryText, const char* secondaryText = nullptr)
</ins><span class="cx"> {
</span><span class="cx">     GtkWidget* parent = gtk_widget_get_toplevel(GTK_WIDGET(webView));
</span><del>-    GtkWidget* dialog = gtk_message_dialog_new(widgetIsOnscreenToplevelWindow(parent) ? GTK_WINDOW(parent) : 0,
-                                               GTK_DIALOG_DESTROY_WITH_PARENT, type, buttons, &quot;%s&quot;, message);
</del><ins>+    GtkWidget* dialog = gtk_message_dialog_new(widgetIsOnscreenToplevelWindow(parent) ? GTK_WINDOW(parent) : nullptr,
+        GTK_DIALOG_DESTROY_WITH_PARENT, type, buttons, &quot;%s&quot;, primaryText);
+    if (secondaryText)
+        gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), &quot;%s&quot;, secondaryText);
</ins><span class="cx">     GUniquePtr&lt;char&gt; title(g_strdup_printf(&quot;JavaScript - %s&quot;, webkit_web_view_get_uri(webView)));
</span><span class="cx">     gtk_window_set_title(GTK_WINDOW(dialog), title.get());
</span><del>-    gtk_dialog_set_default_response(GTK_DIALOG(dialog), defaultResponse);
</del><ins>+    if (buttons != GTK_BUTTONS_NONE)
+        gtk_dialog_set_default_response(GTK_DIALOG(dialog), defaultResponse);
</ins><span class="cx"> 
</span><span class="cx">     return dialog;
</span><span class="cx"> }
</span><span class="lines">@@ -350,7 +353,7 @@
</span><span class="cx">         dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, scriptDialog-&gt;message.data());
</span><span class="cx">         scriptDialog-&gt;confirmed = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK;
</span><span class="cx">         break;
</span><del>-    case WEBKIT_SCRIPT_DIALOG_PROMPT:
</del><ins>+    case WEBKIT_SCRIPT_DIALOG_PROMPT: {
</ins><span class="cx">         dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, scriptDialog-&gt;message.data());
</span><span class="cx">         GtkWidget* entry = gtk_entry_new();
</span><span class="cx">         gtk_entry_set_text(GTK_ENTRY(entry), scriptDialog-&gt;defaultText.data());
</span><span class="lines">@@ -361,6 +364,14 @@
</span><span class="cx">             scriptDialog-&gt;text = gtk_entry_get_text(GTK_ENTRY(entry));
</span><span class="cx">         break;
</span><span class="cx">     }
</span><ins>+    case WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM:
+        dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, GTK_RESPONSE_OK,
+            _(&quot;Are you sure you want to leave this page?&quot;), scriptDialog-&gt;message.data());
+        gtk_dialog_add_buttons(GTK_DIALOG(dialog), _(&quot;Stay on Page&quot;), GTK_RESPONSE_CLOSE, _(&quot;Leave Page&quot;), GTK_RESPONSE_OK, nullptr);
+        gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+        scriptDialog-&gt;confirmed = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK;
+        break;
+    }
</ins><span class="cx"> 
</span><span class="cx">     gtk_widget_destroy(dialog);
</span><span class="cx"> 
</span><span class="lines">@@ -1201,10 +1212,11 @@
</span><span class="cx"> 
</span><span class="cx">     /**
</span><span class="cx">      * WebKitWebView::close:
</span><del>-     * @webView: the #WebKitWebView on which the signal is emitted
</del><ins>+     * @web_view: the #WebKitWebView on which the signal is emitted
</ins><span class="cx">      *
</span><span class="cx">      * Emitted when closing a #WebKitWebView is requested. This occurs when a
</span><del>-     * call is made from JavaScript's &lt;function&gt;window.close&lt;/function&gt; function.
</del><ins>+     * call is made from JavaScript's &lt;function&gt;window.close&lt;/function&gt; function or
+     * after trying to close the @web_view with webkit_web_view_try_close().
</ins><span class="cx">      * It is the owner's responsibility to handle this signal to hide or
</span><span class="cx">      * destroy the #WebKitWebView, if necessary.
</span><span class="cx">      */
</span><span class="lines">@@ -1223,7 +1235,8 @@
</span><span class="cx">      * @dialog: the #WebKitScriptDialog to show
</span><span class="cx">      *
</span><span class="cx">      * Emitted when JavaScript code calls &lt;function&gt;window.alert&lt;/function&gt;,
</span><del>-     * &lt;function&gt;window.confirm&lt;/function&gt; or &lt;function&gt;window.prompt&lt;/function&gt;.
</del><ins>+     * &lt;function&gt;window.confirm&lt;/function&gt; or &lt;function&gt;window.prompt&lt;/function&gt;,
+     * or when &lt;function&gt;onbeforeunload&lt;/function&gt; event is fired.
</ins><span class="cx">      * The @dialog parameter should be used to build the dialog.
</span><span class="cx">      * If the signal is not handled a different dialog will be built and shown depending
</span><span class="cx">      * on the dialog type:
</span><span class="lines">@@ -1238,6 +1251,9 @@
</span><span class="cx">      *  %WEBKIT_SCRIPT_DIALOG_PROMPT: message dialog with OK and Cancel buttons and
</span><span class="cx">      *  a text entry with the default text.
</span><span class="cx">      * &lt;/para&gt;&lt;/listitem&gt;
</span><ins>+     * &lt;listitem&gt;&lt;para&gt;
+     *  %WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM: message dialog with Stay and Leave buttons.
+     * &lt;/para&gt;&lt;/listitem&gt;
</ins><span class="cx">      * &lt;/itemizedlist&gt;
</span><span class="cx">      *
</span><span class="cx">      * Returns: %TRUE to stop other handlers from being invoked for the event.
</span><span class="lines">@@ -1929,6 +1945,14 @@
</span><span class="cx">     return dialog.text;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView* webView, const CString&amp; message)
+{
+    WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM, message);
+    gboolean returnValue;
+    g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &amp;dialog, &amp;returnValue);
+    return dialog.confirmed;
+}
+
</ins><span class="cx"> void webkitWebViewMakePolicyDecision(WebKitWebView* webView, WebKitPolicyDecisionType type, WebKitPolicyDecision* decision)
</span><span class="cx"> {
</span><span class="cx">     gboolean returnValue;
</span><span class="lines">@@ -2251,6 +2275,24 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /**
</span><ins>+ * webkit_web_view_try_close:
+ * @web_view: a #WebKitWebView
+ *
+ * Tries to close the @web_view. This will fire the onbeforeunload event
+ * to ask the user for confirmation to close the page. If there isn't an
+ * onbeforeunload event handler or the user confirms to close the page,
+ * the #WebKitWebView::close signal is emitted, otherwise nothing happens.
+ *
+ * Since: 2.12
+ */
+void webkit_web_view_try_close(WebKitWebView *webView)
+{
+    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
+    if (getPage(webView)-&gt;tryClose())
+        webkitWebViewClosePage(webView);
+}
+
+/**
</ins><span class="cx">  * webkit_web_view_load_uri:
</span><span class="cx">  * @web_view: a #WebKitWebView
</span><span class="cx">  * @uri: an URI string
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIgtkWebKitWebViewh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h (193825 => 193826)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h        2015-12-09 13:30:11 UTC (rev 193825)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h        2015-12-09 13:32:54 UTC (rev 193826)
</span><span class="lines">@@ -277,6 +277,9 @@
</span><span class="cx"> webkit_web_view_get_context                          (WebKitWebView             *web_view);
</span><span class="cx"> 
</span><span class="cx"> WEBKIT_API void
</span><ins>+webkit_web_view_try_close                            (WebKitWebView             *web_view);
+
+WEBKIT_API void
</ins><span class="cx"> webkit_web_view_load_uri                             (WebKitWebView             *web_view,
</span><span class="cx">                                                       const gchar               *uri);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIgtkWebKitWebViewPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h (193825 => 193826)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h        2015-12-09 13:30:11 UTC (rev 193825)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h        2015-12-09 13:32:54 UTC (rev 193826)
</span><span class="lines">@@ -44,6 +44,7 @@
</span><span class="cx"> void webkitWebViewRunJavaScriptAlert(WebKitWebView*, const CString&amp; message);
</span><span class="cx"> bool webkitWebViewRunJavaScriptConfirm(WebKitWebView*, const CString&amp; message);
</span><span class="cx"> CString webkitWebViewRunJavaScriptPrompt(WebKitWebView*, const CString&amp; message, const CString&amp; defaultText);
</span><ins>+bool webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView*, const CString&amp; message);
</ins><span class="cx"> void webkitWebViewMakePermissionRequest(WebKitWebView*, WebKitPermissionRequest*);
</span><span class="cx"> void webkitWebViewMakePolicyDecision(WebKitWebView*, WebKitPolicyDecisionType, WebKitPolicyDecision*);
</span><span class="cx"> void webkitWebViewMouseTargetChanged(WebKitWebView*, const WebKit::WebHitTestResultData&amp;, unsigned modifiers);
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIgtkdocswebkit2gtk40sectionstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt (193825 => 193826)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt        2015-12-09 13:30:11 UTC (rev 193825)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt        2015-12-09 13:32:54 UTC (rev 193826)
</span><span class="lines">@@ -157,6 +157,7 @@
</span><span class="cx"> webkit_web_view_new_with_user_content_manager
</span><span class="cx"> webkit_web_view_get_context
</span><span class="cx"> webkit_web_view_get_user_content_manager
</span><ins>+webkit_web_view_try_close
</ins><span class="cx"> webkit_web_view_load_uri
</span><span class="cx"> webkit_web_view_load_html
</span><span class="cx"> webkit_web_view_load_alternate_html
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (193825 => 193826)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2015-12-09 13:30:11 UTC (rev 193825)
+++ trunk/Tools/ChangeLog        2015-12-09 13:32:54 UTC (rev 193826)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2015-12-09  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
+
+        [GTK] Add API to handle beforeunload events
+        https://bugs.webkit.org/show_bug.cgi?id=139090
+
+        Reviewed by Gustavo Noronha Silva.
+
+        * MiniBrowser/gtk/BrowserWindow.c:
+        (browserWindowConstructed):
+        (browserWindowDeleteEvent):
+        (browser_window_class_init):
+        Handle delete-event to prevent the window from being closed when
+        the page has beforeunload handlers. Use
+        webkit_web_view_try_close() when the window is requested to be
+        closed.
+        * TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp:
+        (testWebViewJavaScriptDialogs):
+        Add a test case for the WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM
+        script dialog type.
+
</ins><span class="cx"> 2015-12-09  Mario Sanchez Prada  &lt;mario@endlessm.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Refactored initialization code in LoadTrackingTest.
</span></span></pre></div>
<a id="trunkToolsMiniBrowsergtkBrowserWindowc"></a>
<div class="modfile"><h4>Modified: trunk/Tools/MiniBrowser/gtk/BrowserWindow.c (193825 => 193826)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/MiniBrowser/gtk/BrowserWindow.c        2015-12-09 13:30:11 UTC (rev 193825)
+++ trunk/Tools/MiniBrowser/gtk/BrowserWindow.c        2015-12-09 13:32:54 UTC (rev 193826)
</span><span class="lines">@@ -1096,6 +1096,7 @@
</span><span class="cx">     g_signal_connect(window-&gt;webView, &quot;notify::estimated-load-progress&quot;, G_CALLBACK(webViewLoadProgressChanged), window);
</span><span class="cx">     g_signal_connect(window-&gt;webView, &quot;notify::title&quot;, G_CALLBACK(webViewTitleChanged), window);
</span><span class="cx">     g_signal_connect(window-&gt;webView, &quot;create&quot;, G_CALLBACK(webViewCreate), window);
</span><ins>+    g_signal_connect(window-&gt;webView, &quot;close&quot;, G_CALLBACK(webViewClose), window);
</ins><span class="cx">     g_signal_connect(window-&gt;webView, &quot;load-failed&quot;, G_CALLBACK(webViewLoadFailed), window);
</span><span class="cx">     g_signal_connect(window-&gt;webView, &quot;load-failed-with-tls-errors&quot;, G_CALLBACK(webViewLoadFailedWithTLSerrors), window);
</span><span class="cx">     g_signal_connect(window-&gt;webView, &quot;decide-policy&quot;, G_CALLBACK(webViewDecidePolicy), window);
</span><span class="lines">@@ -1150,6 +1151,13 @@
</span><span class="cx">         webkit_web_view_load_html(window-&gt;webView, &quot;&lt;html&gt;&lt;/html&gt;&quot;, &quot;file:///&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static gboolean browserWindowDeleteEvent(GtkWidget *widget, GdkEventAny* event)
+{
+    BrowserWindow *window = BROWSER_WINDOW(widget);
+    webkit_web_view_try_close(window-&gt;webView);
+    return TRUE;
+}
+
</ins><span class="cx"> static void browser_window_class_init(BrowserWindowClass *klass)
</span><span class="cx"> {
</span><span class="cx">     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
</span><span class="lines">@@ -1159,6 +1167,9 @@
</span><span class="cx">     gobjectClass-&gt;set_property = browserWindowSetProperty;
</span><span class="cx">     gobjectClass-&gt;finalize = browserWindowFinalize;
</span><span class="cx"> 
</span><ins>+    GtkWidgetClass *widgetClass = GTK_WIDGET_CLASS(klass);
+    widgetClass-&gt;delete_event = browserWindowDeleteEvent;
+
</ins><span class="cx">     g_object_class_install_property(gobjectClass,
</span><span class="cx">                                     PROP_VIEW,
</span><span class="cx">                                     g_param_spec_object(&quot;view&quot;,
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2GtkTestUIClientcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp (193825 => 193826)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp        2015-12-09 13:30:11 UTC (rev 193825)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestUIClient.cpp        2015-12-09 13:32:54 UTC (rev 193826)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> static const char* kConfirmDialogMessage = &quot;WebKitGTK+ confirm dialog message&quot;;
</span><span class="cx"> static const char* kPromptDialogMessage = &quot;WebKitGTK+ prompt dialog message&quot;;
</span><span class="cx"> static const char* kPromptDialogReturnedText = &quot;WebKitGTK+ prompt dialog returned text&quot;;
</span><ins>+static const char* kBeforeUnloadConfirmDialogMessage = &quot;WebKitGTK+ beforeunload dialog message&quot;;
</ins><span class="cx"> 
</span><span class="cx"> class UIClientTest: public WebViewTest {
</span><span class="cx"> public:
</span><span class="lines">@@ -146,6 +147,9 @@
</span><span class="cx">         case WEBKIT_SCRIPT_DIALOG_PROMPT:
</span><span class="cx">             g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kPromptDialogReturnedText);
</span><span class="cx">             break;
</span><ins>+        case WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM:
+            g_assert_not_reached();
+            break;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         g_main_loop_quit(m_mainLoop);
</span><span class="lines">@@ -165,6 +169,13 @@
</span><span class="cx">         webkit_script_dialog_prompt_set_text(dialog, kPromptDialogReturnedText);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void scriptBeforeUnloadConfirm(WebKitScriptDialog* dialog)
+    {
+        g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kBeforeUnloadConfirmDialogMessage);
+        m_scriptDialogConfirmed = true;
+        webkit_script_dialog_confirm_set_confirmed(dialog, m_scriptDialogConfirmed);
+    }
+
</ins><span class="cx">     static gboolean scriptDialog(WebKitWebView*, WebKitScriptDialog* dialog, UIClientTest* test)
</span><span class="cx">     {
</span><span class="cx">         switch (webkit_script_dialog_get_dialog_type(dialog)) {
</span><span class="lines">@@ -177,6 +188,9 @@
</span><span class="cx">         case WEBKIT_SCRIPT_DIALOG_PROMPT:
</span><span class="cx">             test-&gt;scriptPrompt(dialog);
</span><span class="cx">             break;
</span><ins>+        case WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM:
+            test-&gt;scriptBeforeUnloadConfirm(dialog);
+            break;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         return TRUE;
</span><span class="lines">@@ -232,6 +246,24 @@
</span><span class="cx">         g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static void tryWebViewCloseCallback(UIClientTest* test)
+    {
+        g_main_loop_quit(test-&gt;m_mainLoop);
+    }
+
+    void tryCloseAndWaitUntilClosed()
+    {
+        gulong handler = g_signal_connect_swapped(m_webView, &quot;close&quot;, G_CALLBACK(tryWebViewCloseCallback), this);
+        // Use an idle because webkit_web_view_try_close can emit the close signal in the
+        // current run loop iteration.
+        g_idle_add([](gpointer data) -&gt; gboolean {
+            webkit_web_view_try_close(WEBKIT_WEB_VIEW(data));
+            return G_SOURCE_REMOVE;
+        }, m_webView);
+        g_main_loop_run(m_mainLoop);
+        g_signal_handler_disconnect(m_webView, handler);
+    }
+
</ins><span class="cx">     void waitUntilMainLoopFinishes()
</span><span class="cx">     {
</span><span class="cx">         g_main_loop_run(m_mainLoop);
</span><span class="lines">@@ -473,24 +505,71 @@
</span><span class="cx">     static const char* jsAlertFormat = &quot;alert('%s')&quot;;
</span><span class="cx">     static const char* jsConfirmFormat = &quot;do { confirmed = confirm('%s'); } while (!confirmed); alert('confirmed');&quot;;
</span><span class="cx">     static const char* jsPromptFormat = &quot;alert(prompt('%s', 'default'));&quot;;
</span><ins>+    static const char* htmlOnBeforeUnloadFormat =
+        &quot;&lt;html&gt;&lt;body onbeforeunload=\&quot;return beforeUnloadHandler();\&quot;&gt;&lt;script&gt;function beforeUnloadHandler() { return \&quot;%s\&quot;; }&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;&quot;;
</ins><span class="cx"> 
</span><span class="cx">     test-&gt;m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_ALERT;
</span><span class="cx">     GUniquePtr&lt;char&gt; alertDialogMessage(g_strdup_printf(jsAlertFormat, kAlertDialogMessage));
</span><span class="cx">     GUniquePtr&lt;char&gt; alertHTML(g_strdup_printf(htmlOnLoadFormat, alertDialogMessage.get()));
</span><span class="cx">     test-&gt;loadHtml(alertHTML.get(), 0);
</span><span class="cx">     test-&gt;waitUntilMainLoopFinishes();
</span><ins>+    webkit_web_view_stop_loading(test-&gt;m_webView);
+    test-&gt;waitUntilLoadFinished();
</ins><span class="cx"> 
</span><span class="cx">     test-&gt;m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_CONFIRM;
</span><span class="cx">     GUniquePtr&lt;char&gt; confirmDialogMessage(g_strdup_printf(jsConfirmFormat, kConfirmDialogMessage));
</span><span class="cx">     GUniquePtr&lt;char&gt; confirmHTML(g_strdup_printf(htmlOnLoadFormat, confirmDialogMessage.get()));
</span><span class="cx">     test-&gt;loadHtml(confirmHTML.get(), 0);
</span><span class="cx">     test-&gt;waitUntilMainLoopFinishes();
</span><ins>+    webkit_web_view_stop_loading(test-&gt;m_webView);
+    test-&gt;waitUntilLoadFinished();
</ins><span class="cx"> 
</span><span class="cx">     test-&gt;m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_PROMPT;
</span><span class="cx">     GUniquePtr&lt;char&gt; promptDialogMessage(g_strdup_printf(jsPromptFormat, kPromptDialogMessage));
</span><span class="cx">     GUniquePtr&lt;char&gt; promptHTML(g_strdup_printf(htmlOnLoadFormat, promptDialogMessage.get()));
</span><span class="cx">     test-&gt;loadHtml(promptHTML.get(), 0);
</span><span class="cx">     test-&gt;waitUntilMainLoopFinishes();
</span><ins>+    webkit_web_view_stop_loading(test-&gt;m_webView);
+    test-&gt;waitUntilLoadFinished();
+
+    test-&gt;m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM;
+    GUniquePtr&lt;char&gt; beforeUnloadDialogHTML(g_strdup_printf(htmlOnBeforeUnloadFormat, kBeforeUnloadConfirmDialogMessage));
+    test-&gt;loadHtml(beforeUnloadDialogHTML.get(), nullptr);
+    test-&gt;waitUntilLoadFinished();
+
+    // Reload should trigger onbeforeunload.
+#if 0
+    // FIXME: reloading HTML data doesn't emit finished load event.
+    // See https://bugs.webkit.org/show_bug.cgi?id=139089.
+    test-&gt;m_scriptDialogConfirmed = false;
+    webkit_web_view_reload(test-&gt;m_webView);
+    test-&gt;waitUntilLoadFinished();
+    g_assert(test-&gt;m_scriptDialogConfirmed);
+#endif
+
+    // Navigation should trigger onbeforeunload.
+    test-&gt;m_scriptDialogConfirmed = false;
+    test-&gt;loadHtml(&quot;&lt;html&gt;&lt;/html&gt;&quot;, nullptr);
+    test-&gt;waitUntilLoadFinished();
+    g_assert(test-&gt;m_scriptDialogConfirmed);
+
+    // Try close should trigger onbeforeunload.
+    test-&gt;m_scriptDialogConfirmed = false;
+    test-&gt;loadHtml(beforeUnloadDialogHTML.get(), nullptr);
+    test-&gt;waitUntilLoadFinished();
+    test-&gt;tryCloseAndWaitUntilClosed();
+    g_assert(test-&gt;m_scriptDialogConfirmed);
+
+    // Try close on a page with no unload handlers should not trigger onbeforeunload,
+    // but should actually close the page.
+    test-&gt;m_scriptDialogConfirmed = false;
+    test-&gt;loadHtml(&quot;&lt;html&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;&quot;, nullptr);
+    test-&gt;waitUntilLoadFinished();
+    // We got a onbeforeunload of the previous page.
+    g_assert(test-&gt;m_scriptDialogConfirmed);
+    test-&gt;m_scriptDialogConfirmed = false;
+    test-&gt;tryCloseAndWaitUntilClosed();
+    g_assert(!test-&gt;m_scriptDialogConfirmed);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void testWebViewWindowProperties(UIClientTest* test, gconstpointer)
</span></span></pre>
</div>
</div>

</body>
</html>