From 79ad030d505ccf79cf10aa9f8189ca3e2f61f6f4 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 25 Jun 2012 13:35:59 +0200 Subject: Imported WebKit commit c4b613825abd39ac739a47d7b4410468fcef66dc (http://svn.webkit.org/repository/webkit/trunk@121147) New snapshot that includes Win32 debug build fix (use SVGAllInOne) --- Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp | 188 ++++++++++++++++++--- 1 file changed, 166 insertions(+), 22 deletions(-) (limited to 'Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp') diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp index 7f5764e7d..94a94ca09 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp @@ -25,6 +25,8 @@ #include "WebContextMenuItemData.h" #include "WebKitBackForwardListPrivate.h" #include "WebKitContextMenuClient.h" +#include "WebKitContextMenuItemPrivate.h" +#include "WebKitContextMenuPrivate.h" #include "WebKitEnumTypes.h" #include "WebKitError.h" #include "WebKitFullscreenClient.h" @@ -50,6 +52,7 @@ #include "WebPageProxy.h" #include #include +#include #include #include #include @@ -65,6 +68,7 @@ enum { CREATE, READY_TO_SHOW, + RUN_AS_MODAL, CLOSE, SCRIPT_DIALOG, @@ -83,6 +87,8 @@ enum { RUN_FILE_CHOOSER, + CONTEXT_MENU, + LAST_SIGNAL }; @@ -118,6 +124,8 @@ struct _WebKitWebViewPrivate { GRefPtr settings; GRefPtr windowProperties; + GRefPtr modalLoop; + GRefPtr mouseTargetHitTestResult; unsigned mouseTargetModifiers; @@ -223,6 +231,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 +252,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(allowModalDialogsChanged), webView); + g_signal_handlers_disconnect_by_func(settings, reinterpret_cast(zoomTextOnlyChanged), webView); + +} + static void fileChooserDialogResponseCallback(GtkDialog* dialog, gint responseID, WebKitFileChooserRequest* request) { GRefPtr adoptedRequest = adoptGRef(request); @@ -353,8 +378,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 +637,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 + * window.showModalDialog. 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 @@ -933,6 +987,62 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) webkit_marshal_BOOLEAN__OBJECT, G_TYPE_BOOLEAN, 1, /* number of parameters */ WEBKIT_TYPE_FILE_CHOOSER_REQUEST); + + /** + * WebKitWebView::context-menu: + * @web_view: the #WebKitWebView on which the signal is emitted + * @context_menu: the proposed #WebKitContextMenu + * @event: the #GdkEvent that triggered the context menu + * @hit_test_result: a #WebKitHitTestResult + * + * Emmited when a context menu is about to be displayed to give the application + * a chance to customize the proposed menu, prevent the menu from being displayed + * or build its own context menu. + * + * + * To customize the proposed menu you can use webkit_context_menu_prepend(), + * webkit_context_menu_append() or webkit_context_menu_insert() to add new + * #WebKitContextMenuItems to @context_menu, webkit_context_menu_move_item() + * to reorder existing items, or webkit_context_menu_remove() to remove an + * existing item. The signal handler should return %FALSE, and the menu represented + * by @context_menu will be shown. + * + * + * To prevent the menu from being displayed you can just connect to this signal + * and return %TRUE so that the proposed menu will not be shown. + * + * + * To build your own menu, you can remove all items from the proposed menu with + * webkit_context_menu_remove_all(), add your own items and return %FALSE so + * that the menu will be shown. You can also ignore the proposed #WebKitContextMenu, + * build your own #GtkMenu and return %TRUE to prevent the proposed menu from being shown. + * + * + * If you just want the default menu to be shown always, simply don't connect to this + * signal because showing the proposed context menu is the default behaviour. + * + * + * + * If the signal handler returns %FALSE the context menu represented by @context_menu + * will be shown, if it return %TRUE the context menu will not be shown. + * + * The proposed #WebKitContextMenu passed in @context_menu argument is only valid + * during the signal emission. + * + * Returns: %TRUE to stop other handlers from being invoked for the event. + * %FALSE to propagate the event further. + */ + signals[CONTEXT_MENU] = + g_signal_new("context-menu", + G_TYPE_FROM_CLASS(webViewClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitWebViewClass, context_menu), + g_signal_accumulator_true_handled, 0, + webkit_marshal_BOOLEAN__OBJECT_BOXED_OBJECT, + G_TYPE_BOOLEAN, 3, + WEBKIT_TYPE_CONTEXT_MENU, + GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE, + WEBKIT_TYPE_HIT_TEST_RESULT); } static bool updateReplaceContentStatus(WebKitWebView* webView, WebKitLoadEvent loadEvent) @@ -1034,6 +1144,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); @@ -1172,14 +1292,6 @@ void webkitWebViewRunFileChooserRequest(WebKitWebView* webView, WebKitFileChoose g_signal_emit(webView, signals[RUN_FILE_CHOOSER], 0, request, &returnValue); } -static void webkitWebViewCreateAndAppendDefaultMenuItems(WebKitWebView* webView, WKArrayRef wkProposedMenu, Vector& contextMenuItems) -{ - for (size_t i = 0; i < WKArrayGetSize(wkProposedMenu); ++i) { - WKContextMenuItemRef wkItem = static_cast(WKArrayGetItemAtIndex(wkProposedMenu, i)); - contextMenuItems.append(toImpl(wkItem)->data()->core()); - } -} - static bool webkitWebViewShouldShowInputMethodsMenu(WebKitWebView* webView) { GtkSettings* settings = gtk_widget_get_settings(GTK_WIDGET(webView)); @@ -1191,33 +1303,65 @@ static bool webkitWebViewShouldShowInputMethodsMenu(WebKitWebView* webView) return showInputMethodMenu; } -static void webkitWebViewCreateAndAppendInputMethodsMenuItem(WebKitWebView* webView, Vector& contextMenuItems) +static int getUnicodeMenuItemPosition(WebKitContextMenu* contextMenu) +{ + GList* items = webkit_context_menu_get_items(contextMenu); + GList* iter; + int i = 0; + for (iter = items, i = 0; iter; iter = g_list_next(iter), ++i) { + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(iter->data); + + if (webkit_context_menu_item_is_separator(item)) + continue; + if (webkit_context_menu_item_get_stock_action(item) == WEBKIT_CONTEXT_MENU_ACTION_UNICODE) + return i; + } + return -1; +} + +static void webkitWebViewCreateAndAppendInputMethodsMenuItem(WebKitWebView* webView, WebKitContextMenu* contextMenu) { if (!webkitWebViewShouldShowInputMethodsMenu(webView)) return; + // Place the im context menu item right before the unicode menu item + // if it's present. + int unicodeMenuItemPosition = getUnicodeMenuItemPosition(contextMenu); + if (unicodeMenuItemPosition == -1) + webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); + GtkIMContext* imContext = webkitWebViewBaseGetIMContext(WEBKIT_WEB_VIEW_BASE(webView)); GtkMenu* imContextMenu = GTK_MENU(gtk_menu_new()); gtk_im_multicontext_append_menuitems(GTK_IM_MULTICONTEXT(imContext), GTK_MENU_SHELL(imContextMenu)); - ContextMenu subMenu(imContextMenu); - - ContextMenuItem separator(SeparatorType, ContextMenuItemTagNoAction, String()); - contextMenuItems.append(separator); - ContextMenuItem menuItem(SubmenuType, ContextMenuItemTagNoAction, _("Input _Methods"), &subMenu); - contextMenuItems.append(menuItem); + WebKitContextMenuItem* menuItem = webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS); + webkitContextMenuItemSetSubMenuFromGtkMenu(menuItem, imContextMenu); + webkit_context_menu_insert(contextMenu, menuItem, unicodeMenuItemPosition); } void webkitWebViewPopulateContextMenu(WebKitWebView* webView, WKArrayRef wkProposedMenu, WKHitTestResultRef wkHitTestResult) { - WebContextMenuProxyGtk* contextMenu = webkitWebViewBaseGetActiveContextMenuProxy(WEBKIT_WEB_VIEW_BASE(webView)); - ASSERT(contextMenu); + WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView); + WebContextMenuProxyGtk* contextMenuProxy = webkitWebViewBaseGetActiveContextMenuProxy(webViewBase); + ASSERT(contextMenuProxy); - Vector contextMenuItems; - webkitWebViewCreateAndAppendDefaultMenuItems(webView, wkProposedMenu, contextMenuItems); + GRefPtr contextMenu = adoptGRef(webkitContextMenuCreate(wkProposedMenu)); if (WKHitTestResultIsContentEditable(wkHitTestResult)) - webkitWebViewCreateAndAppendInputMethodsMenuItem(webView, contextMenuItems); + webkitWebViewCreateAndAppendInputMethodsMenuItem(webView, contextMenu.get()); + + GRefPtr hitTestResult = adoptGRef(webkitHitTestResultCreate(wkHitTestResult)); + GOwnPtr contextMenuEvent(webkitWebViewBaseTakeContextMenuEvent(webViewBase)); + + gboolean returnValue; + g_signal_emit(webView, signals[CONTEXT_MENU], 0, contextMenu.get(), contextMenuEvent.get(), hitTestResult.get(), &returnValue); + if (returnValue) + return; + + Vector contextMenuItems; + webkitContextMenuPopulate(contextMenu.get(), contextMenuItems); + contextMenuProxy->populate(contextMenuItems); - contextMenu->populate(contextMenuItems); + // Clear the menu to make sure it's useless after signal emission. + webkit_context_menu_remove_all(contextMenu.get()); } /** @@ -1684,7 +1828,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(zoomTextOnlyChanged), webView); + webkitWebViewDisconnectSettingsSignalHandlers(webView); webkitWebViewSetSettings(webView, settings, toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView)))); } -- cgit v1.2.1