Skip to content
Permalink
Browse files
[GTK] Add support for window.showModalDialog in WebKit2GTK+
https://bugs.webkit.org/show_bug.cgi?id=79500

Reviewed by Carlos Garcia Campos.

Source/WebKit2:

Implement runModal in WebKitUIClient to make the WebKitWebView
emit a 'run-as-modal' signal when requested, creating a new
mainloop there to block user interaction with the original window
while the modal dialog is showing.

* UIProcess/API/gtk/WebKitUIClient.cpp:
(runModal): Call to the new webkitWebViewRunAsModalPage function.
(attachUIClientToView): Add runModal.
* UIProcess/API/gtk/WebKitWebView.cpp:
(_WebKitWebViewPrivate): Add an atribute for a new main loop.
(webkitWebViewFinalize): Make sure the main loop for main dialogs,
if any, is stopped if it was still running.
(webkit_web_view_class_init): Declare new signal 'run-as-modal'.
(webkitWebViewRunAsModal): Emit the 'run-as-modal' signal and, if
handled, create and run a new main loop.
* UIProcess/API/gtk/WebKitWebView.h:
(_WebKitWebViewClass): New handler for the 'run-as-modal' signal.
* UIProcess/API/gtk/WebKitWebViewPrivate.h: Add webkitWebViewRunAsModalPage.

Allow setting and getting the value of WebPage's canRunModal
attribute in the WebProcess from the UIProcess after the creation
of a WebPage, to allow using it from WebKitWebView to allow the
client application to decide whether to allow create modal
dialogs, which would result in launching an additional nested
event loop in the web process, after creating the dialog.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::WebPageProxy): Initialize the new
m_canRunModal attribute, to cache the current status of the
WebPage in the WebProcess.
(WebKit::WebPageProxy::initializeUIClient): Call the new function
setCanRunModal, instead of manually sending the SetCanRunModal message.
(WebKit::WebPageProxy::creationParameters): Use m_canRunModal
instead of m_uiClient.canRunModal when preparing the parameters.
(WebKit::WebPageProxy::setCanRunModal): New public function, it
sets the value of m_canRunModal and sends a message to the Web
process for updating the WebPage, whenever possible.
(WebKit::WebPageProxy::canRunModal): New public function, returns
the value of the m_canRunModal attribute.
* UIProcess/WebPageProxy.h:
(WebPageProxy): Added new public functions and private attribute.

New property in WebKitSettings to be able to decide whether it is
allowed to create and run new child webviews as modal dialogs.

* UIProcess/API/gtk/WebKitSettings.cpp:
(_WebKitSettingsPrivate): New attribute allowModalDialogs.
(webKitSettingsSetProperty): Handle the new property.
(webKitSettingsGetProperty): Ditto.
(webkit_settings_class_init): Install the new property.
(webkitSettingsAttachSettingsToPage): Make sure the WebPage is
initialized with the value of the new property.
(webkit_settings_set_allow_modal_dialogs): New setter.
(webkit_settings_get_allow_modal_dialogs): New getter.
* UIProcess/API/gtk/WebKitSettings.h:
* UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Added new accessors.

Connect to the 'notify::allow-modal-dialogs' signal from
WebKitSettings to ensure that canRunModal property of the WebPage
is kept up to date. Ensure that signal handlers for monitoring
settings are disconnected when the webview is finalized.

* UIProcess/API/gtk/WebKitWebView.cpp:
(webkitWebViewSetSettings): Connect to the new signal
'notify::allow-modal-dialogs', from WebKitSettings.
(allowModalDialogsChanged): Callback to update WebPage's
canRunModal property when updated through WebKitSettings.
(webkitWebViewDisconnectSettingsSignalHandlers): Disconnect signal
handlers for monitoring WebKitSettings properties.
(webkitWebViewFinalize): Ensure signal handlers are disconnected.
(webkit_web_view_set_settings): Ditto.
* UIProcess/API/gtk/WebKitWebView.h:

Add new unit tests to check the 'run-as-modal' signal is emitted
only when the new property in WebKitSettings is set to TRUE.

* UIProcess/API/gtk/tests/TestWebKitWebView.cpp:
(testWebViewAllowModalDialogs): New unit test to check that modal
dialogs are properly created from JavaScript when allowed.
(testWebViewDisallowModalDialogs): New unit test to check that
it's not possible to create modal dialogs when not allowed.
(beforeAll): Add the new unit test.

Tools:

Add support for modal dialogs in GTK's MiniBrowser.

* MiniBrowser/gtk/BrowserWindow.c:
(webViewRunAsModal):
(webViewCreate):
(webViewDecidePolicy):
(browser_window_new):
* MiniBrowser/gtk/BrowserWindow.h:
* MiniBrowser/gtk/main.c:
(createBrowserWindow):

Canonical link: https://commits.webkit.org/107501@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@120908 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
mariospr committed Jun 21, 2012
1 parent 5d43751 commit dbac1401e5f85fe6553072c058c8cb91f96969f3
Showing 16 changed files with 397 additions and 43 deletions.
@@ -1,3 +1,93 @@
2012-06-21 Mario Sanchez Prada <msanchez@igalia.com>

[GTK] Add support for window.showModalDialog in WebKit2GTK+
https://bugs.webkit.org/show_bug.cgi?id=79500

Reviewed by Carlos Garcia Campos.

Implement runModal in WebKitUIClient to make the WebKitWebView
emit a 'run-as-modal' signal when requested, creating a new
mainloop there to block user interaction with the original window
while the modal dialog is showing.

* UIProcess/API/gtk/WebKitUIClient.cpp:
(runModal): Call to the new webkitWebViewRunAsModalPage function.
(attachUIClientToView): Add runModal.
* UIProcess/API/gtk/WebKitWebView.cpp:
(_WebKitWebViewPrivate): Add an atribute for a new main loop.
(webkitWebViewFinalize): Make sure the main loop for main dialogs,
if any, is stopped if it was still running.
(webkit_web_view_class_init): Declare new signal 'run-as-modal'.
(webkitWebViewRunAsModal): Emit the 'run-as-modal' signal and, if
handled, create and run a new main loop.
* UIProcess/API/gtk/WebKitWebView.h:
(_WebKitWebViewClass): New handler for the 'run-as-modal' signal.
* UIProcess/API/gtk/WebKitWebViewPrivate.h: Add webkitWebViewRunAsModalPage.

Allow setting and getting the value of WebPage's canRunModal
attribute in the WebProcess from the UIProcess after the creation
of a WebPage, to allow using it from WebKitWebView to allow the
client application to decide whether to allow create modal
dialogs, which would result in launching an additional nested
event loop in the web process, after creating the dialog.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::WebPageProxy): Initialize the new
m_canRunModal attribute, to cache the current status of the
WebPage in the WebProcess.
(WebKit::WebPageProxy::initializeUIClient): Call the new function
setCanRunModal, instead of manually sending the SetCanRunModal message.
(WebKit::WebPageProxy::creationParameters): Use m_canRunModal
instead of m_uiClient.canRunModal when preparing the parameters.
(WebKit::WebPageProxy::setCanRunModal): New public function, it
sets the value of m_canRunModal and sends a message to the Web
process for updating the WebPage, whenever possible.
(WebKit::WebPageProxy::canRunModal): New public function, returns
the value of the m_canRunModal attribute.
* UIProcess/WebPageProxy.h:
(WebPageProxy): Added new public functions and private attribute.

New property in WebKitSettings to be able to decide whether it is
allowed to create and run new child webviews as modal dialogs.

* UIProcess/API/gtk/WebKitSettings.cpp:
(_WebKitSettingsPrivate): New attribute allowModalDialogs.
(webKitSettingsSetProperty): Handle the new property.
(webKitSettingsGetProperty): Ditto.
(webkit_settings_class_init): Install the new property.
(webkitSettingsAttachSettingsToPage): Make sure the WebPage is
initialized with the value of the new property.
(webkit_settings_set_allow_modal_dialogs): New setter.
(webkit_settings_get_allow_modal_dialogs): New getter.
* UIProcess/API/gtk/WebKitSettings.h:
* UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Added new accessors.

Connect to the 'notify::allow-modal-dialogs' signal from
WebKitSettings to ensure that canRunModal property of the WebPage
is kept up to date. Ensure that signal handlers for monitoring
settings are disconnected when the webview is finalized.

* UIProcess/API/gtk/WebKitWebView.cpp:
(webkitWebViewSetSettings): Connect to the new signal
'notify::allow-modal-dialogs', from WebKitSettings.
(allowModalDialogsChanged): Callback to update WebPage's
canRunModal property when updated through WebKitSettings.
(webkitWebViewDisconnectSettingsSignalHandlers): Disconnect signal
handlers for monitoring WebKitSettings properties.
(webkitWebViewFinalize): Ensure signal handlers are disconnected.
(webkit_web_view_set_settings): Ditto.
* UIProcess/API/gtk/WebKitWebView.h:

Add new unit tests to check the 'run-as-modal' signal is emitted
only when the new property in WebKitSettings is set to TRUE.

* UIProcess/API/gtk/tests/TestWebKitWebView.cpp:
(testWebViewAllowModalDialogs): New unit test to check that modal
dialogs are properly created from JavaScript when allowed.
(testWebViewDisallowModalDialogs): New unit test to check that
it's not possible to create modal dialogs when not allowed.
(beforeAll): Add the new unit test.

2012-06-20 Thiago Marcos P. Santos <thiago.santos@intel.com>

[WK2] Color chooser API missing
@@ -33,6 +33,7 @@

#include "WebKitPrivate.h"
#include "WebKitSettingsPrivate.h"
#include "WebPageProxy.h"
#include <glib/gi18n-lib.h>
#include <wtf/text/CString.h>

@@ -46,6 +47,7 @@ struct _WebKitSettingsPrivate {
CString fantasyFontFamily;
CString pictographFontFamily;
CString defaultCharset;
bool allowModalDialogs;
bool zoomTextOnly;
};

@@ -105,6 +107,7 @@ enum {
PROP_PRINT_BACKGROUNDS,
PROP_ENABLE_WEBAUDIO,
PROP_ENABLE_WEBGL,
PROP_ALLOW_MODAL_DIALOGS,
PROP_ZOOM_TEXT_ONLY,
PROP_JAVASCRIPT_CAN_ACCESS_CLIPBOARD,
PROP_MEDIA_PLAYBACK_REQUIRES_USER_GESTURE,
@@ -216,6 +219,9 @@ static void webKitSettingsSetProperty(GObject* object, guint propId, const GValu
case PROP_ENABLE_WEBGL:
webkit_settings_set_enable_webgl(settings, g_value_get_boolean(value));
break;
case PROP_ALLOW_MODAL_DIALOGS:
webkit_settings_set_allow_modal_dialogs(settings, g_value_get_boolean(value));
break;
case PROP_ZOOM_TEXT_ONLY:
webkit_settings_set_zoom_text_only(settings, g_value_get_boolean(value));
break;
@@ -341,6 +347,9 @@ static void webKitSettingsGetProperty(GObject* object, guint propId, GValue* val
case PROP_ENABLE_WEBGL:
g_value_set_boolean(value, webkit_settings_get_enable_webgl(settings));
break;
case PROP_ALLOW_MODAL_DIALOGS:
g_value_set_boolean(value, webkit_settings_get_allow_modal_dialogs(settings));
break;
case PROP_ZOOM_TEXT_ONLY:
g_value_set_boolean(value, webkit_settings_get_zoom_text_only(settings));
break;
@@ -852,6 +861,24 @@ static void webkit_settings_class_init(WebKitSettingsClass* klass)
FALSE,
readWriteConstructParamFlags));

/**
* WebKitSettings:allow-modal-dialogs:
*
* Determine whether it's allowed to create and run modal dialogs
* from a #WebKitWebView through JavaScript with
* <function>window.showModalDialog</function>. If it's set to
* %FALSE, the associated #WebKitWebView won't be able to create
* new modal dialogs, so not even the #WebKitWebView::create
* signal will be emitted.
*/
g_object_class_install_property(gObjectClass,
PROP_ALLOW_MODAL_DIALOGS,
g_param_spec_boolean("allow-modal-dialogs",
_("Allow modal dialogs"),
_("Whether it is possible to create modal dialogs"),
FALSE,
readWriteConstructParamFlags));

/**
* WebKitSettings:zoom-text-only:
*
@@ -969,6 +996,7 @@ static void webkit_settings_init(WebKitSettings* settings)
void webkitSettingsAttachSettingsToPage(WebKitSettings* settings, WKPageRef wkPage)
{
WKPageGroupSetPreferences(WKPageGetPageGroup(wkPage), settings->priv->preferences.get());
WebKit::toImpl(wkPage)->setCanRunModal(settings->priv->allowModalDialogs);
}

/**
@@ -2188,6 +2216,39 @@ void webkit_settings_set_enable_webgl(WebKitSettings* settings, gboolean enabled
g_object_notify(G_OBJECT(settings), "enable-webgl");
}

/**
* webkit_settings_set_allow_modal_dialogs:
* @settings: a #WebKitSettings
* @allowed: Value to be set
*
* Set the #WebKitSettings:allow-modal-dialogs property.
*/
void webkit_settings_set_allow_modal_dialogs(WebKitSettings* settings, gboolean allowed)
{
g_return_if_fail(WEBKIT_IS_SETTINGS(settings));

WebKitSettingsPrivate* priv = settings->priv;
if (priv->allowModalDialogs == allowed)
return;

priv->allowModalDialogs = allowed;
g_object_notify(G_OBJECT(settings), "allow-modal-dialogs");
}

/**
* webkit_settings_get_allow_modal_dialogs:
* @settings: a #WebKitSettings
*
* Get the #WebKitSettings:allow-modal-dialogs property.
*
* Returns: %TRUE if it's allowed to create and run modal dialogs or %FALSE otherwise.
*/
gboolean webkit_settings_get_allow_modal_dialogs(WebKitSettings* settings)
{
g_return_val_if_fail(WEBKIT_IS_SETTINGS(settings), FALSE);
return settings->priv->allowModalDialogs;
}

/**
* webkit_settings_set_zoom_text_only:
* @settings: a #WebKitSettings
@@ -307,6 +307,13 @@ WEBKIT_API void
webkit_settings_set_enable_webgl (WebKitSettings *settings,
gboolean enabled);

WEBKIT_API void
webkit_settings_set_allow_modal_dialogs (WebKitSettings *settings,
gboolean allowed);

WEBKIT_API gboolean
webkit_settings_get_allow_modal_dialogs (WebKitSettings *settings);

WEBKIT_API void
webkit_settings_set_zoom_text_only (WebKitSettings *settings,
gboolean zoom_text_only);
@@ -151,6 +151,11 @@ static void decidePolicyForGeolocationPermissionRequest(WKPageRef, WKFrameRef, W
webkitWebViewMakePermissionRequest(WEBKIT_WEB_VIEW(clientInfo), WEBKIT_PERMISSION_REQUEST(geolocationPermissionRequest.get()));
}

static void runModal(WKPageRef page, const void* clientInfo)
{
webkitWebViewRunAsModal(WEBKIT_WEB_VIEW(clientInfo));
}

void attachUIClientToView(WebKitWebView* webView)
{
WKPageUIClient wkUIClient = {
@@ -191,7 +196,7 @@ void attachUIClientToView(WebKitWebView* webView)
0, // drawHeader
0, // drawFooter
printFrame,
0, // runModal
runModal,
0, // didCompleteRubberBandForMainFrame
0, // saveDataToFileInDownloadsFolder
0, // shouldInterruptJavaScript
@@ -65,6 +65,7 @@ enum {

CREATE,
READY_TO_SHOW,
RUN_AS_MODAL,
CLOSE,

SCRIPT_DIALOG,
@@ -118,6 +119,8 @@ struct _WebKitWebViewPrivate {
GRefPtr<WebKitSettings> settings;
GRefPtr<WebKitWindowProperties> windowProperties;

GRefPtr<GMainLoop> modalLoop;

GRefPtr<WebKitHitTestResult> mouseTargetHitTestResult;
unsigned mouseTargetModifiers;

@@ -223,6 +226,14 @@ static gboolean webkitWebViewPermissionRequest(WebKitWebView*, WebKitPermissionR
return TRUE;
}

static void allowModalDialogsChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
{
WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
if (!page)
return;
page->setCanRunModal(webkit_settings_get_allow_modal_dialogs(settings));
}

static void zoomTextOnlyChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
{
WKPageRef wkPage = toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView)));
@@ -236,9 +247,18 @@ static void webkitWebViewSetSettings(WebKitWebView* webView, WebKitSettings* set
{
webView->priv->settings = settings;
webkitSettingsAttachSettingsToPage(webView->priv->settings.get(), wkPage);
g_signal_connect(settings, "notify::allow-modal-dialogs", G_CALLBACK(allowModalDialogsChanged), webView);
g_signal_connect(settings, "notify::zoom-text-only", G_CALLBACK(zoomTextOnlyChanged), webView);
}

static void webkitWebViewDisconnectSettingsSignalHandlers(WebKitWebView* webView)
{
WebKitSettings* settings = webView->priv->settings.get();
g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(allowModalDialogsChanged), webView);
g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(zoomTextOnlyChanged), webView);

}

static void fileChooserDialogResponseCallback(GtkDialog* dialog, gint responseID, WebKitFileChooserRequest* request)
{
GRefPtr<WebKitFileChooserRequest> adoptedRequest = adoptGRef(request);
@@ -353,8 +373,16 @@ static void webkitWebViewGetProperty(GObject* object, guint propId, GValue* valu
static void webkitWebViewFinalize(GObject* object)
{
WebKitWebViewPrivate* priv = WEBKIT_WEB_VIEW(object)->priv;

if (priv->javascriptGlobalContext)
JSGlobalContextRelease(priv->javascriptGlobalContext);

// For modal dialogs, make sure the main loop is stopped when finalizing the webView.
if (priv->modalLoop && g_main_loop_is_running(priv->modalLoop.get()))
g_main_loop_quit(priv->modalLoop.get());

webkitWebViewDisconnectSettingsSignalHandlers(WEBKIT_WEB_VIEW(object));

priv->~WebKitWebViewPrivate();
G_OBJECT_CLASS(webkit_web_view_parent_class)->finalize(object);
}
@@ -604,6 +632,27 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);

/**
* WebKitWebView::run-as-modal:
* @web_view: the #WebKitWebView on which the signal is emitted
*
* Emitted after #WebKitWebView::ready-to-show on the newly
* created #WebKitWebView when JavaScript code calls
* <function>window.showModalDialog</function>. The purpose of
* this signal is to allow the client application to prepare the
* new view to behave as modal. Once the signal is emitted a new
* mainloop will be run to block user interaction in the parent
* #WebKitWebView until the new dialog is closed.
*/
signals[RUN_AS_MODAL] =
g_signal_new("run-as-modal",
G_TYPE_FROM_CLASS(webViewClass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(WebKitWebViewClass, run_as_modal),
0, 0,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);

/**
* WebKitWebView::close:
* @webView: the #WebKitWebView on which the signal is emitted
@@ -1034,6 +1083,16 @@ void webkitWebViewReadyToShowPage(WebKitWebView* webView)
g_signal_emit(webView, signals[READY_TO_SHOW], 0, NULL);
}

void webkitWebViewRunAsModal(WebKitWebView* webView)
{
g_signal_emit(webView, signals[RUN_AS_MODAL], 0, NULL);

webView->priv->modalLoop = adoptGRef(g_main_loop_new(0, FALSE));
GDK_THREADS_ENTER();
g_main_loop_run(webView->priv->modalLoop.get());
GDK_THREADS_LEAVE();
}

void webkitWebViewClosePage(WebKitWebView* webView)
{
g_signal_emit(webView, signals[CLOSE], 0, NULL);
@@ -1684,7 +1743,7 @@ void webkit_web_view_set_settings(WebKitWebView* webView, WebKitSettings* settin
if (webView->priv->settings == settings)
return;

g_signal_handlers_disconnect_by_func(webView->priv->settings.get(), reinterpret_cast<gpointer>(zoomTextOnlyChanged), webView);
webkitWebViewDisconnectSettingsSignalHandlers(webView);
webkitWebViewSetSettings(webView, settings, toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))));
}

@@ -136,6 +136,7 @@ struct _WebKitWebViewClass {

GtkWidget *(* create) (WebKitWebView *web_view);
void (* ready_to_show) (WebKitWebView *web_view);
void (* run_as_modal) (WebKitWebView *web_view);
void (* close) (WebKitWebView *web_view);

gboolean (* script_dialog) (WebKitWebView *web_view,
@@ -38,6 +38,7 @@ void webkitWebViewSetTitle(WebKitWebView*, const CString&);
void webkitWebViewUpdateURI(WebKitWebView*);
WKPageRef webkitWebViewCreateNewPage(WebKitWebView*, WKDictionaryRef wkWindowFeatures);
void webkitWebViewReadyToShowPage(WebKitWebView*);
void webkitWebViewRunAsModal(WebKitWebView*);
void webkitWebViewClosePage(WebKitWebView*);
void webkitWebViewRunJavaScriptAlert(WebKitWebView*, const CString& message);
bool webkitWebViewRunJavaScriptConfirm(WebKitWebView*, const CString& message);
@@ -256,6 +256,8 @@ webkit_settings_get_enable_webaudio
webkit_settings_set_enable_webaudio
webkit_settings_get_enable_webgl
webkit_settings_set_enable_webgl
webkit_settings_set_allow_modal_dialogs
webkit_settings_get_allow_modal_dialogs
webkit_settings_get_zoom_text_only
webkit_settings_set_zoom_text_only
webkit_settings_get_javascript_can_access_clipboard

0 comments on commit dbac140

Please sign in to comment.