diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-25 13:35:59 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-25 13:35:59 +0200 |
commit | 79ad030d505ccf79cf10aa9f8189ca3e2f61f6f4 (patch) | |
tree | 0287b1a69d84492c901e8bc820e635e7133809a0 /Source/WebKit2/UIProcess/API | |
parent | 682ab87480e7757346802ce7f54cfdbdfeb2339e (diff) | |
download | qtwebkit-79ad030d505ccf79cf10aa9f8189ca3e2f61f6f4.tar.gz |
Imported WebKit commit c4b613825abd39ac739a47d7b4410468fcef66dc (http://svn.webkit.org/repository/webkit/trunk@121147)
New snapshot that includes Win32 debug build fix (use SVGAllInOne)
Diffstat (limited to 'Source/WebKit2/UIProcess/API')
50 files changed, 2994 insertions, 70 deletions
diff --git a/Source/WebKit2/UIProcess/API/C/WKAPICast.h b/Source/WebKit2/UIProcess/API/C/WKAPICast.h index 9bc9ea607..816f8f1ae 100644 --- a/Source/WebKit2/UIProcess/API/C/WKAPICast.h +++ b/Source/WebKit2/UIProcess/API/C/WKAPICast.h @@ -368,4 +368,8 @@ inline ProxyingRefPtr<WebGrammarDetail> toAPI(const WebCore::GrammarDetail& gram #include "WKAPICastSoup.h" #endif +#if defined(BUILDING_EFL__) +#include "WKAPICastEfl.h" +#endif + #endif // WKAPICast_h diff --git a/Source/WebKit2/UIProcess/API/C/WKIntentData.cpp b/Source/WebKit2/UIProcess/API/C/WKIntentData.cpp new file mode 100644 index 000000000..a42f530ac --- /dev/null +++ b/Source/WebKit2/UIProcess/API/C/WKIntentData.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WKIntentData.h" + +#include "ImmutableArray.h" +#include "ImmutableDictionary.h" +#include "WKAPICast.h" + +#if ENABLE(WEB_INTENTS) +#include "WebIntentData.h" +#endif + +using namespace WebKit; + +WKTypeID WKIntentDataGetTypeID() +{ +#if ENABLE(WEB_INTENTS) + return toAPI(WebIntentData::APIType); +#else + return 0; +#endif +} + +WKStringRef WKIntentDataCopyAction(WKIntentDataRef intentRef) +{ +#if ENABLE(WEB_INTENTS) + return toCopiedAPI(toImpl(intentRef)->action()); +#else + return 0; +#endif +} + +WKStringRef WKIntentDataCopyType(WKIntentDataRef intentRef) +{ +#if ENABLE(WEB_INTENTS) + return toCopiedAPI(toImpl(intentRef)->payloadType()); +#else + return 0; +#endif +} + +WKURLRef WKIntentDataCopyService(WKIntentDataRef intentRef) +{ +#if ENABLE(WEB_INTENTS) + return toCopiedURLAPI(toImpl(intentRef)->service()); +#else + return 0; +#endif +} + +WKArrayRef WKIntentDataCopySuggestions(WKIntentDataRef intentRef) +{ +#if ENABLE(WEB_INTENTS) + return toAPI(toImpl(intentRef)->suggestions().leakRef()); +#else + return 0; +#endif +} + +WKStringRef WKIntentDataCopyExtra(WKIntentDataRef intentRef, WKStringRef key) +{ +#if ENABLE(WEB_INTENTS) + return toCopiedAPI(toImpl(intentRef)->extra(toWTFString(key))); +#else + return 0; +#endif +} + +WKDictionaryRef WKIntentDataCopyExtras(WKIntentDataRef intentRef) +{ +#if ENABLE(WEB_INTENTS) + return toAPI(toImpl(intentRef)->extras().leakRef()); +#else + return 0; +#endif +} diff --git a/Source/WebKit2/UIProcess/API/C/WKIntentData.h b/Source/WebKit2/UIProcess/API/C/WKIntentData.h new file mode 100644 index 000000000..030555b4b --- /dev/null +++ b/Source/WebKit2/UIProcess/API/C/WKIntentData.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WKIntentData_h +#define WKIntentData_h + +#include <WebKit2/WKBase.h> + +#ifdef __cplusplus +extern "C" { +#endif + +WK_EXPORT WKTypeID WKIntentDataGetTypeID(); +WK_EXPORT WKStringRef WKIntentDataCopyAction(WKIntentDataRef intentRef); +WK_EXPORT WKStringRef WKIntentDataCopyType(WKIntentDataRef intentRef); +WK_EXPORT WKURLRef WKIntentDataCopyService(WKIntentDataRef intentRef); +WK_EXPORT WKArrayRef WKIntentDataCopySuggestions(WKIntentDataRef intentRef); +WK_EXPORT WKStringRef WKIntentDataCopyExtra(WKIntentDataRef intentRef, WKStringRef key); +WK_EXPORT WKDictionaryRef WKIntentDataCopyExtras(WKIntentDataRef intentRef); + +#ifdef __cplusplus +} +#endif + +#endif // WKIntentData_h diff --git a/Source/WebKit2/UIProcess/API/C/efl/WKAPICastEfl.h b/Source/WebKit2/UIProcess/API/C/efl/WKAPICastEfl.h new file mode 100644 index 000000000..5a068ef36 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/C/efl/WKAPICastEfl.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef WKAPICastEfl_h +#define WKAPICastEfl_h + +#ifndef WKAPICast_h +#error "Please #include \"WKAPICast.h\" instead of this file directly." +#endif + +typedef struct _Evas_Object Evas_Object; + +namespace WebKit { + +WK_ADD_API_MAPPING(WKViewRef, Evas_Object) + +} + +#endif // WKAPICastEfl_h diff --git a/Source/WebKit2/UIProcess/API/C/efl/WKView.cpp b/Source/WebKit2/UIProcess/API/C/efl/WKView.cpp new file mode 100644 index 000000000..03f6930dd --- /dev/null +++ b/Source/WebKit2/UIProcess/API/C/efl/WKView.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WKView.h" + +#include "WKAPICast.h" +#include "ewk_view_private.h" + +using namespace WebKit; + +WKViewRef WKViewCreate(Evas* canvas, WKContextRef contextRef, WKPageGroupRef pageGroupRef) +{ + return toAPI(ewk_view_base_add(canvas, contextRef, pageGroupRef)); +} + +WKPageRef WKViewGetPage(WKViewRef viewRef) +{ + return toAPI(ewk_view_page_get(toImpl(viewRef))); +} diff --git a/Source/WebKit2/UIProcess/API/C/efl/WKView.h b/Source/WebKit2/UIProcess/API/C/efl/WKView.h new file mode 100644 index 000000000..1a7961daa --- /dev/null +++ b/Source/WebKit2/UIProcess/API/C/efl/WKView.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef WKView_h +#define WKView_h + +#include <WebKit2/WKBase.h> + +typedef struct _Evas Evas; + +#ifdef __cplusplus +extern "C" { +#endif + +WK_EXPORT WKViewRef WKViewCreate(Evas* canvas, WKContextRef context, WKPageGroupRef pageGroup); + +WK_EXPORT WKPageRef WKViewGetPage(WKViewRef view); + +#ifdef __cplusplus +} +#endif + +#endif /* WKView_h */ diff --git a/Source/WebKit2/UIProcess/API/efl/PageClientImpl.cpp b/Source/WebKit2/UIProcess/API/efl/PageClientImpl.cpp index 567548f5d..e69f87d28 100644 --- a/Source/WebKit2/UIProcess/API/efl/PageClientImpl.cpp +++ b/Source/WebKit2/UIProcess/API/efl/PageClientImpl.cpp @@ -205,6 +205,14 @@ PassRefPtr<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPagePr return 0; } +#if ENABLE(INPUT_TYPE_COLOR) +PassRefPtr<WebColorChooserProxy> PageClientImpl::createColorChooserProxy(WebPageProxy*, const WebCore::Color&) +{ + notImplemented(); + return 0; +} +#endif + void PageClientImpl::setFindIndicator(PassRefPtr<FindIndicator>, bool, bool) { notImplemented(); diff --git a/Source/WebKit2/UIProcess/API/efl/PageClientImpl.h b/Source/WebKit2/UIProcess/API/efl/PageClientImpl.h index a4dcd93e3..427ef5297 100644 --- a/Source/WebKit2/UIProcess/API/efl/PageClientImpl.h +++ b/Source/WebKit2/UIProcess/API/efl/PageClientImpl.h @@ -84,6 +84,10 @@ private: virtual PassRefPtr<WebPopupMenuProxy> createPopupMenuProxy(WebPageProxy*); virtual PassRefPtr<WebContextMenuProxy> createContextMenuProxy(WebPageProxy*); +#if ENABLE(INPUT_TYPE_COLOR) + virtual PassRefPtr<WebColorChooserProxy> createColorChooserProxy(WebPageProxy*, const WebCore::Color& initialColor); +#endif + virtual void setFindIndicator(PassRefPtr<FindIndicator>, bool, bool); #if USE(ACCELERATED_COMPOSITING) virtual void enterAcceleratedCompositingMode(const LayerTreeContext&); diff --git a/Source/WebKit2/UIProcess/API/efl/ewk_view.cpp b/Source/WebKit2/UIProcess/API/efl/ewk_view.cpp index 01fd5e669..fe384e377 100644 --- a/Source/WebKit2/UIProcess/API/efl/ewk_view.cpp +++ b/Source/WebKit2/UIProcess/API/efl/ewk_view.cpp @@ -629,3 +629,11 @@ void ewk_view_image_data_set(Evas_Object* ewkView, void* imageData, const IntSiz evas_object_image_size_set(smartData->image, size.width(), size.height()); evas_object_image_data_copy_set(smartData->image, imageData); } + +WebPageProxy* ewk_view_page_get(const Evas_Object* ewkView) +{ + EWK_VIEW_SD_GET_OR_RETURN(ewkView, smartData, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(smartData, priv, 0); + + return priv->pageClient->page(); +} diff --git a/Source/WebKit2/UIProcess/API/efl/ewk_view_private.h b/Source/WebKit2/UIProcess/API/efl/ewk_view_private.h index 2b3f476ba..62598e4c0 100644 --- a/Source/WebKit2/UIProcess/API/efl/ewk_view_private.h +++ b/Source/WebKit2/UIProcess/API/efl/ewk_view_private.h @@ -36,4 +36,6 @@ void ewk_view_title_changed(Evas_Object* ewkView, const char* title); Evas_Object* ewk_view_base_add(Evas* canvas, WKContextRef, WKPageGroupRef); +WebKit::WebPageProxy* ewk_view_page_get(const Evas_Object* ewkView); + #endif // ewk_view_private_h diff --git a/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp b/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp index 8fbfe73f6..8ecd480e5 100644 --- a/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp @@ -229,6 +229,14 @@ PassRefPtr<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPagePr return WebContextMenuProxyGtk::create(m_viewWidget, page); } +#if ENABLE(INPUT_TYPE_COLOR) +PassRefPtr<WebColorChooserProxy> PageClientImpl::createColorChooserProxy(WebPageProxy*, const WebCore::Color&) +{ + notImplemented(); + return 0; +} +#endif + void PageClientImpl::setFindIndicator(PassRefPtr<FindIndicator>, bool fadeOut, bool animate) { notImplemented(); diff --git a/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.h b/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.h index 54ad99f8f..72fc34539 100644 --- a/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.h +++ b/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.h @@ -81,6 +81,9 @@ private: virtual void doneWithKeyEvent(const NativeWebKeyboardEvent&, bool wasEventHandled); virtual PassRefPtr<WebPopupMenuProxy> createPopupMenuProxy(WebPageProxy*); virtual PassRefPtr<WebContextMenuProxy> createContextMenuProxy(WebPageProxy*); +#if ENABLE(INPUT_TYPE_COLOR) + virtual PassRefPtr<WebColorChooserProxy> createColorChooserProxy(WebPageProxy*, const WebCore::Color& intialColor); +#endif virtual void setFindIndicator(PassRefPtr<FindIndicator>, bool fadeOut, bool animate); virtual void didChangeScrollbarsForMainFrame() const; virtual void flashBackingStoreUpdates(const Vector<WebCore::IntRect>& updateRects); diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.cpp new file mode 100644 index 000000000..f05fbf93f --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WebKitContextMenu.h" + +#include "WebKitContextMenuItemPrivate.h" +#include "WebKitContextMenuPrivate.h" + +using namespace WebKit; +using namespace WebCore; + +struct _WebKitContextMenuPrivate { + GList* items; + WebKitContextMenuItem* parentItem; +}; + +G_DEFINE_TYPE(WebKitContextMenu, webkit_context_menu, G_TYPE_OBJECT) + +static void webkitContextMenuFinalize(GObject* object) +{ + WebKitContextMenu* menu = WEBKIT_CONTEXT_MENU(object); + webkit_context_menu_remove_all(menu); + menu->priv->~WebKitContextMenuPrivate(); + G_OBJECT_CLASS(webkit_context_menu_parent_class)->finalize(object); +} + +static void webkit_context_menu_init(WebKitContextMenu* menu) +{ + WebKitContextMenuPrivate* priv = G_TYPE_INSTANCE_GET_PRIVATE(menu, WEBKIT_TYPE_CONTEXT_MENU, WebKitContextMenuPrivate); + menu->priv = priv; + new (priv) WebKitContextMenuPrivate(); +} + +static void webkit_context_menu_class_init(WebKitContextMenuClass* listClass) +{ + GObjectClass* gObjectClass = G_OBJECT_CLASS(listClass); + gObjectClass->finalize = webkitContextMenuFinalize; + + g_type_class_add_private(listClass, sizeof(WebKitContextMenuPrivate)); +} + +void webkitContextMenuPopulate(WebKitContextMenu* menu, Vector<ContextMenuItem>& contextMenuItems) +{ + for (GList* item = menu->priv->items; item; item = g_list_next(item)) { + WebKitContextMenuItem* menuItem = WEBKIT_CONTEXT_MENU_ITEM(item->data); + contextMenuItems.append(ContextMenuItem(webkitContextMenuItemRelease(menuItem))); + } +} + +WebKitContextMenu* webkitContextMenuCreate(WKArrayRef wkItems) +{ + WebKitContextMenu* menu = webkit_context_menu_new(); + for (size_t i = 0; i < WKArrayGetSize(wkItems); ++i) { + WKContextMenuItemRef wkItem = static_cast<WKContextMenuItemRef>(WKArrayGetItemAtIndex(wkItems, i)); + webkit_context_menu_prepend(menu, webkitContextMenuItemCreate(wkItem)); + } + menu->priv->items = g_list_reverse(menu->priv->items); + + return menu; +} + +void webkitContextMenuSetParentItem(WebKitContextMenu* menu, WebKitContextMenuItem* item) +{ + menu->priv->parentItem = item; +} + +WebKitContextMenuItem* webkitContextMenuGetParentItem(WebKitContextMenu* menu) +{ + return menu->priv->parentItem; +} + +/** + * webkit_context_menu_new: + * + * Creates a new #WebKitContextMenu object to be used as a submenu of an existing + * #WebKitContextMenu. The context menu of a #WebKitWebView is created by the view + * and passed as an argument of #WebKitWebView::context-menu signal. + * To add items to the menu use webkit_context_menu_prepend(), + * webkit_context_menu_append() or webkit_context_menu_insert(). + * See also webkit_context_menu_new_with_items() to create a #WebKitContextMenu with + * a list of initial items. + * + * Returns: The newly created #WebKitContextMenu object + */ +WebKitContextMenu* webkit_context_menu_new() +{ + return WEBKIT_CONTEXT_MENU(g_object_new(WEBKIT_TYPE_CONTEXT_MENU, NULL)); +} + +/** + * webkit_context_menu_new_with_items: + * @items: (element-type WebKitContextMenuItem): a #GList of #WebKitContextMenuItem + * + * Creates a new #WebKitContextMenu object to be used as a submenu of an existing + * #WebKitContextMenu with the given initial items. + * See also webkit_context_menu_new() + * + * Returns: The newly created #WebKitContextMenu object + */ +WebKitContextMenu* webkit_context_menu_new_with_items(GList* items) +{ + WebKitContextMenu* menu = webkit_context_menu_new(); + g_list_foreach(items, reinterpret_cast<GFunc>(g_object_ref_sink), 0); + menu->priv->items = g_list_copy(items); + + return menu; +} + +/** + * webkit_context_menu_prepend: + * @menu: a #WebKitContextMenu + * @item: the #WebKitContextMenuItem to add + * + * Adds @item at the beginning of the @menu. + */ +void webkit_context_menu_prepend(WebKitContextMenu* menu, WebKitContextMenuItem* item) +{ + webkit_context_menu_insert(menu, item, 0); +} + +/** + * webkit_context_menu_append: + * @menu: a #WebKitContextMenu + * @item: the #WebKitContextMenuItem to add + * + * Adds @item at the end of the @menu. + */ +void webkit_context_menu_append(WebKitContextMenu* menu, WebKitContextMenuItem* item) +{ + webkit_context_menu_insert(menu, item, -1); +} + +/** + * webkit_context_menu_insert: + * @menu: a #WebKitContextMenu + * @item: the #WebKitContextMenuItem to add + * @position: the position to insert the item + * + * Inserts @item into the @menu at the given position. + * If @position is negative, or is larger than the number of items + * in the #WebKitContextMenu, the item is added on to the end of + * the @menu. The first position is 0. + */ +void webkit_context_menu_insert(WebKitContextMenu* menu, WebKitContextMenuItem* item, int position) +{ + g_return_if_fail(WEBKIT_IS_CONTEXT_MENU(menu)); + g_return_if_fail(WEBKIT_IS_CONTEXT_MENU_ITEM(item)); + + g_object_ref_sink(item); + menu->priv->items = g_list_insert(menu->priv->items, item, position); +} + +/** + * webkit_context_menu_move_item: + * @menu: a #WebKitContextMenu + * @item: the #WebKitContextMenuItem to add + * @position: the new position to move the item + * + * Moves @item to the given position in the @menu. + * If @position is negative, or is larger than the number of items + * in the #WebKitContextMenu, the item is added on to the end of + * the @menu. + * The first position is 0. + */ +void webkit_context_menu_move_item(WebKitContextMenu* menu, WebKitContextMenuItem* item, int position) +{ + g_return_if_fail(WEBKIT_IS_CONTEXT_MENU(menu)); + g_return_if_fail(WEBKIT_IS_CONTEXT_MENU_ITEM(item)); + + if (!g_list_find(menu->priv->items, item)) + return; + + menu->priv->items = g_list_remove(menu->priv->items, item); + menu->priv->items = g_list_insert(menu->priv->items, item, position); +} + +/** + * webkit_context_menu_get_items: + * @menu: a #WebKitContextMenu + * + * Returns the item list of @menu. + * + * Returns: (element-type WebKitContextMenuItem) (transfer none): a #GList of + * #WebKitContextMenuItem<!-- -->s + */ +GList* webkit_context_menu_get_items(WebKitContextMenu* menu) +{ + g_return_val_if_fail(WEBKIT_IS_CONTEXT_MENU(menu), 0); + + return menu->priv->items; +} + +/** + * webkit_context_menu_get_n_items: + * @menu: a #WebKitContextMenu + * + * Gets the length of the @menu. + * + * Returns: the number of #WebKitContextMenuItem<!-- -->s in @menu + */ +guint webkit_context_menu_get_n_items(WebKitContextMenu* menu) +{ + g_return_val_if_fail(WEBKIT_IS_CONTEXT_MENU(menu), 0); + + return g_list_length(menu->priv->items); +} + +/** + * webkit_context_menu_first: + * @menu: a #WebKitContextMenu + * + * Gets the first item in the @menu. + * + * Returns: (transfer none): the first #WebKitContextMenuItem of @menu, + * or %NULL if the #WebKitContextMenu is empty. + */ +WebKitContextMenuItem* webkit_context_menu_first(WebKitContextMenu* menu) +{ + g_return_val_if_fail(WEBKIT_IS_CONTEXT_MENU(menu), 0); + + return menu->priv->items ? WEBKIT_CONTEXT_MENU_ITEM(menu->priv->items->data) : 0; +} + +/** + * webkit_context_menu_last: + * @menu: a #WebKitContextMenu + * + * Gets the last item in the @menu. + * + * Returns: (transfer none): the last #WebKitContextMenuItem of @menu, + * or %NULL if the #WebKitContextMenu is empty. + */ +WebKitContextMenuItem* webkit_context_menu_last(WebKitContextMenu* menu) +{ + g_return_val_if_fail(WEBKIT_IS_CONTEXT_MENU(menu), 0); + + GList* last = g_list_last(menu->priv->items); + return last ? WEBKIT_CONTEXT_MENU_ITEM(last->data) : 0; +} + +/** + * webkit_context_menu_get_item_at_position: + * @menu: a #WebKitContextMenu + * @position: the position of the item, counting from 0 + * + * Gets the item at the given position in the @menu. + * + * Returns: (transfer none): the #WebKitContextMenuItem at position @position in @menu, + * or %NULL if the position is off the end of the @menu. + */ +WebKitContextMenuItem* webkit_context_menu_get_item_at_position(WebKitContextMenu* menu, unsigned position) +{ + g_return_val_if_fail(WEBKIT_IS_CONTEXT_MENU(menu), 0); + + gpointer item = g_list_nth_data(menu->priv->items, position); + return item ? WEBKIT_CONTEXT_MENU_ITEM(item) : 0; +} + +/** + * webkit_context_menu_remove: + * @menu: a #WebKitContextMenu + * @item: the #WebKitContextMenuItem to remove + * + * Removes @item from the @menu. + * See also webkit_context_menu_remove_all() to remove all items. + */ +void webkit_context_menu_remove(WebKitContextMenu* menu, WebKitContextMenuItem* item) +{ + g_return_if_fail(WEBKIT_IS_CONTEXT_MENU(menu)); + g_return_if_fail(WEBKIT_IS_CONTEXT_MENU_ITEM(item)); + + if (!g_list_find(menu->priv->items, item)) + return; + + menu->priv->items = g_list_remove(menu->priv->items, item); + g_object_unref(item); +} + +/** + * webkit_context_menu_remove_all: + * @menu: a #WebKitContextMenu + * + * Removes all items of the @menu. + */ +void webkit_context_menu_remove_all(WebKitContextMenu* menu) +{ + g_return_if_fail(WEBKIT_IS_CONTEXT_MENU(menu)); + + g_list_free_full(menu->priv->items, reinterpret_cast<GDestroyNotify>(g_object_unref)); + menu->priv->items = 0; +} diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.h b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.h new file mode 100644 index 000000000..9df3f4c11 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION) +#error "Only <webkit2/webkit2.h> can be included directly." +#endif + +#ifndef WebKitContextMenu_h +#define WebKitContextMenu_h + +#include <glib-object.h> +#include <webkit2/WebKitContextMenuItem.h> +#include <webkit2/WebKitDefines.h> + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_CONTEXT_MENU (webkit_context_menu_get_type()) +#define WEBKIT_CONTEXT_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_CONTEXT_MENU, WebKitContextMenu)) +#define WEBKIT_IS_CONTEXT_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_CONTEXT_MENU)) +#define WEBKIT_CONTEXT_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_CONTEXT_MENU, WebKitContextMenuClass)) +#define WEBKIT_IS_CONTEXT_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_CONTEXT_MENU)) +#define WEBKIT_CONTEXT_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_CONTEXT_MENU, WebKitContextMenuClass)) + +typedef struct _WebKitContextMenuClass WebKitContextMenuClass; +typedef struct _WebKitContextMenuPrivate WebKitContextMenuPrivate; + +struct _WebKitContextMenu { + GObject parent; + + WebKitContextMenuPrivate *priv; +}; + +struct _WebKitContextMenuClass { + GObjectClass parent_class; +}; + +WEBKIT_API GType +webkit_context_menu_get_type (void); + +WEBKIT_API WebKitContextMenu * +webkit_context_menu_new (void); + +WEBKIT_API WebKitContextMenu * +webkit_context_menu_new_with_items (GList *items); + +WEBKIT_API void +webkit_context_menu_prepend (WebKitContextMenu *menu, + WebKitContextMenuItem *item); + +WEBKIT_API void +webkit_context_menu_append (WebKitContextMenu *menu, + WebKitContextMenuItem *item); + +WEBKIT_API void +webkit_context_menu_insert (WebKitContextMenu *menu, + WebKitContextMenuItem *item, + gint position); + +WEBKIT_API void +webkit_context_menu_move_item (WebKitContextMenu *menu, + WebKitContextMenuItem *item, + gint position); +WEBKIT_API GList * +webkit_context_menu_get_items (WebKitContextMenu *menu); + +WEBKIT_API guint +webkit_context_menu_get_n_items (WebKitContextMenu *menu); + +WEBKIT_API WebKitContextMenuItem * +webkit_context_menu_first (WebKitContextMenu *menu); + +WEBKIT_API WebKitContextMenuItem * +webkit_context_menu_last (WebKitContextMenu *menu); + +WEBKIT_API WebKitContextMenuItem * +webkit_context_menu_get_item_at_position (WebKitContextMenu *menu, + guint position); + +WEBKIT_API void +webkit_context_menu_remove (WebKitContextMenu *menu, + WebKitContextMenuItem *item); + +WEBKIT_API void +webkit_context_menu_remove_all (WebKitContextMenu *menu); + +G_END_DECLS + +#endif diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActions.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActions.cpp new file mode 100644 index 000000000..3793d7c0f --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActions.cpp @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WebKitContextMenuActions.h" + +#include "WebKitContextMenuActionsPrivate.h" +#include <WebCore/LocalizedStrings.h> + +using namespace WebCore; + +bool webkitContextMenuActionIsCheckable(WebKitContextMenuAction action) +{ + switch (action) { + case WEBKIT_CONTEXT_MENU_ACTION_BOLD: + case WEBKIT_CONTEXT_MENU_ACTION_ITALIC: + case WEBKIT_CONTEXT_MENU_ACTION_UNDERLINE: + case WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS: + case WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_LOOP: + return true; + default: + return false; + } +} + +ContextMenuAction webkitContextMenuActionGetActionTag(WebKitContextMenuAction action) +{ + switch (action) { + case WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION: + return ContextMenuItemTagNoAction; + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK: + return ContextMenuItemTagOpenLink; + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW: + return ContextMenuItemTagOpenLinkInNewWindow; + case WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK: + return ContextMenuItemTagDownloadLinkToDisk; + case WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD: + return ContextMenuItemTagCopyLinkToClipboard; + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW: + return ContextMenuItemTagOpenImageInNewWindow; + case WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK: + return ContextMenuItemTagDownloadImageToDisk; + case WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD: + return ContextMenuItemTagCopyImageToClipboard; + case WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD: + return ContextMenuItemTagCopyImageUrlToClipboard; + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_FRAME_IN_NEW_WINDOW: + return ContextMenuItemTagOpenFrameInNewWindow; + case WEBKIT_CONTEXT_MENU_ACTION_GO_BACK: + return ContextMenuItemTagGoBack; + case WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD: + return ContextMenuItemTagGoForward; + case WEBKIT_CONTEXT_MENU_ACTION_STOP: + return ContextMenuItemTagStop; + case WEBKIT_CONTEXT_MENU_ACTION_RELOAD: + return ContextMenuItemTagReload; + case WEBKIT_CONTEXT_MENU_ACTION_COPY: + return ContextMenuItemTagCopy; + case WEBKIT_CONTEXT_MENU_ACTION_CUT: + return ContextMenuItemTagCut; + case WEBKIT_CONTEXT_MENU_ACTION_PASTE: + return ContextMenuItemTagPaste; + case WEBKIT_CONTEXT_MENU_ACTION_DELETE: + return ContextMenuItemTagDelete; + case WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL: + return ContextMenuItemTagSelectAll; + case WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS: + return ContextMenuItemTagInputMethods; + case WEBKIT_CONTEXT_MENU_ACTION_UNICODE: + return ContextMenuItemTagUnicode; + case WEBKIT_CONTEXT_MENU_ACTION_SPELLING_GUESS: + return ContextMenuItemTagSpellingGuess; + case WEBKIT_CONTEXT_MENU_ACTION_NO_GUESSES_FOUND: + return ContextMenuItemTagNoGuessesFound; + case WEBKIT_CONTEXT_MENU_ACTION_IGNORE_SPELLING: + return ContextMenuItemTagIgnoreSpelling; + case WEBKIT_CONTEXT_MENU_ACTION_LEARN_SPELLING: + return ContextMenuItemTagLearnSpelling; + case WEBKIT_CONTEXT_MENU_ACTION_IGNORE_GRAMMAR: + return ContextMenuItemTagIgnoreGrammar; + case WEBKIT_CONTEXT_MENU_ACTION_FONT_MENU: + return ContextMenuItemTagFontMenu; + case WEBKIT_CONTEXT_MENU_ACTION_BOLD: + return ContextMenuItemTagBold; + case WEBKIT_CONTEXT_MENU_ACTION_ITALIC: + return ContextMenuItemTagItalic; + case WEBKIT_CONTEXT_MENU_ACTION_UNDERLINE: + return ContextMenuItemTagUnderline; + case WEBKIT_CONTEXT_MENU_ACTION_OUTLINE: + return ContextMenuItemTagOutline; + case WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT: + return ContextMenuItemTagInspectElement; + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_VIDEO_IN_NEW_WINDOW: + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_AUDIO_IN_NEW_WINDOW: + return ContextMenuItemTagOpenMediaInNewWindow; + case WEBKIT_CONTEXT_MENU_ACTION_COPY_VIDEO_LINK_TO_CLIPBOARD: + case WEBKIT_CONTEXT_MENU_ACTION_COPY_AUDIO_LINK_TO_CLIPBOARD: + return ContextMenuItemTagCopyMediaLinkToClipboard; + case WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS: + return ContextMenuItemTagToggleMediaControls; + case WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_LOOP: + return ContextMenuItemTagToggleMediaLoop; + case WEBKIT_CONTEXT_MENU_ACTION_ENTER_VIDEO_FULLSCREEN: + return ContextMenuItemTagEnterVideoFullscreen; + case WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY: + case WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PAUSE: + return ContextMenuItemTagMediaPlayPause; + case WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE: + return ContextMenuItemTagMediaMute; + case WEBKIT_CONTEXT_MENU_ACTION_CUSTOM: + return ContextMenuItemBaseApplicationTag; + default: + ASSERT_NOT_REACHED(); + } + + return ContextMenuItemBaseApplicationTag; +} + +WebKitContextMenuAction webkitContextMenuActionGetForContextMenuItem(ContextMenuItem* menuItem) +{ + switch (menuItem->action()) { + case ContextMenuItemTagNoAction: + return WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION; + case ContextMenuItemTagOpenLink: + return WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK; + case ContextMenuItemTagOpenLinkInNewWindow: + return WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW; + case ContextMenuItemTagDownloadLinkToDisk: + return WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK; + case ContextMenuItemTagCopyLinkToClipboard: + return WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD; + case ContextMenuItemTagOpenImageInNewWindow: + return WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW; + case ContextMenuItemTagDownloadImageToDisk: + return WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK; + case ContextMenuItemTagCopyImageToClipboard: + return WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD; + case ContextMenuItemTagCopyImageUrlToClipboard: + return WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD; + case ContextMenuItemTagOpenFrameInNewWindow: + return WEBKIT_CONTEXT_MENU_ACTION_OPEN_FRAME_IN_NEW_WINDOW; + case ContextMenuItemTagGoBack: + return WEBKIT_CONTEXT_MENU_ACTION_GO_BACK; + case ContextMenuItemTagGoForward: + return WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD; + case ContextMenuItemTagStop: + return WEBKIT_CONTEXT_MENU_ACTION_STOP; + case ContextMenuItemTagReload: + return WEBKIT_CONTEXT_MENU_ACTION_RELOAD; + case ContextMenuItemTagCopy: + return WEBKIT_CONTEXT_MENU_ACTION_COPY; + case ContextMenuItemTagCut: + return WEBKIT_CONTEXT_MENU_ACTION_CUT; + case ContextMenuItemTagPaste: + return WEBKIT_CONTEXT_MENU_ACTION_PASTE; + case ContextMenuItemTagDelete: + return WEBKIT_CONTEXT_MENU_ACTION_DELETE; + case ContextMenuItemTagSelectAll: + return WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL; + case ContextMenuItemTagInputMethods: + return WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS; + case ContextMenuItemTagUnicode: + return WEBKIT_CONTEXT_MENU_ACTION_UNICODE; + case ContextMenuItemTagSpellingGuess: + return WEBKIT_CONTEXT_MENU_ACTION_SPELLING_GUESS; + case ContextMenuItemTagIgnoreSpelling: + return WEBKIT_CONTEXT_MENU_ACTION_IGNORE_SPELLING; + case ContextMenuItemTagLearnSpelling: + return WEBKIT_CONTEXT_MENU_ACTION_LEARN_SPELLING; + case ContextMenuItemTagIgnoreGrammar: + return WEBKIT_CONTEXT_MENU_ACTION_IGNORE_GRAMMAR; + case ContextMenuItemTagFontMenu: + return WEBKIT_CONTEXT_MENU_ACTION_FONT_MENU; + case ContextMenuItemTagBold: + return WEBKIT_CONTEXT_MENU_ACTION_BOLD; + case ContextMenuItemTagItalic: + return WEBKIT_CONTEXT_MENU_ACTION_ITALIC; + case ContextMenuItemTagUnderline: + return WEBKIT_CONTEXT_MENU_ACTION_UNDERLINE; + case ContextMenuItemTagOutline: + return WEBKIT_CONTEXT_MENU_ACTION_OUTLINE; + case ContextMenuItemTagInspectElement: + return WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT; + case ContextMenuItemTagOpenMediaInNewWindow: + return menuItem->title() == contextMenuItemTagOpenVideoInNewWindow() ? + WEBKIT_CONTEXT_MENU_ACTION_OPEN_VIDEO_IN_NEW_WINDOW : WEBKIT_CONTEXT_MENU_ACTION_OPEN_AUDIO_IN_NEW_WINDOW; + case ContextMenuItemTagCopyMediaLinkToClipboard: + return menuItem->title() == contextMenuItemTagCopyVideoLinkToClipboard() ? + WEBKIT_CONTEXT_MENU_ACTION_COPY_VIDEO_LINK_TO_CLIPBOARD : WEBKIT_CONTEXT_MENU_ACTION_COPY_AUDIO_LINK_TO_CLIPBOARD; + case ContextMenuItemTagToggleMediaControls: + return WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS; + case ContextMenuItemTagToggleMediaLoop: + return WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_LOOP; + case ContextMenuItemTagEnterVideoFullscreen: + return WEBKIT_CONTEXT_MENU_ACTION_ENTER_VIDEO_FULLSCREEN; + case ContextMenuItemTagMediaPlayPause: + return menuItem->title() == contextMenuItemTagMediaPlay() ? + WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY : WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PAUSE; + case ContextMenuItemTagMediaMute: + return WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE; + case ContextMenuItemBaseApplicationTag: + return WEBKIT_CONTEXT_MENU_ACTION_CUSTOM; + default: + ASSERT_NOT_REACHED(); + } + + return WEBKIT_CONTEXT_MENU_ACTION_CUSTOM; +} + +String webkitContextMenuActionGetLabel(WebKitContextMenuAction action) +{ + switch (action) { + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK: + return contextMenuItemTagOpenLink(); + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW: + return contextMenuItemTagOpenLinkInNewWindow(); + case WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK: + return contextMenuItemTagDownloadLinkToDisk(); + case WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD: + return contextMenuItemTagCopyLinkToClipboard(); + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW: + return contextMenuItemTagOpenImageInNewWindow(); + case WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK: + return contextMenuItemTagDownloadImageToDisk(); + case WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD: + return contextMenuItemTagCopyImageToClipboard(); + case WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD: + return contextMenuItemTagCopyImageUrlToClipboard(); + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_FRAME_IN_NEW_WINDOW: + return contextMenuItemTagOpenFrameInNewWindow(); + case WEBKIT_CONTEXT_MENU_ACTION_GO_BACK: + return contextMenuItemTagGoBack(); + case WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD: + return contextMenuItemTagGoForward(); + case WEBKIT_CONTEXT_MENU_ACTION_STOP: + return contextMenuItemTagStop(); + case WEBKIT_CONTEXT_MENU_ACTION_RELOAD: + return contextMenuItemTagReload(); + case WEBKIT_CONTEXT_MENU_ACTION_COPY: + return contextMenuItemTagCopy(); + case WEBKIT_CONTEXT_MENU_ACTION_CUT: + return contextMenuItemTagCut(); + case WEBKIT_CONTEXT_MENU_ACTION_PASTE: + return contextMenuItemTagPaste(); + case WEBKIT_CONTEXT_MENU_ACTION_DELETE: + return contextMenuItemTagDelete(); + case WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL: + return contextMenuItemTagSelectAll(); + case WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS: + return contextMenuItemTagInputMethods(); + case WEBKIT_CONTEXT_MENU_ACTION_UNICODE: + return contextMenuItemTagUnicode(); + case WEBKIT_CONTEXT_MENU_ACTION_NO_GUESSES_FOUND: + return contextMenuItemTagNoGuessesFound(); + case WEBKIT_CONTEXT_MENU_ACTION_IGNORE_SPELLING: + return contextMenuItemTagIgnoreSpelling(); + case WEBKIT_CONTEXT_MENU_ACTION_LEARN_SPELLING: + return contextMenuItemTagLearnSpelling(); + case WEBKIT_CONTEXT_MENU_ACTION_IGNORE_GRAMMAR: + return contextMenuItemTagIgnoreGrammar(); + case WEBKIT_CONTEXT_MENU_ACTION_FONT_MENU: + return contextMenuItemTagFontMenu(); + case WEBKIT_CONTEXT_MENU_ACTION_BOLD: + return contextMenuItemTagBold(); + case WEBKIT_CONTEXT_MENU_ACTION_ITALIC: + return contextMenuItemTagItalic(); + case WEBKIT_CONTEXT_MENU_ACTION_UNDERLINE: + return contextMenuItemTagUnderline(); + case WEBKIT_CONTEXT_MENU_ACTION_OUTLINE: + return contextMenuItemTagOutline(); + case WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT: + return contextMenuItemTagInspectElement(); + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_VIDEO_IN_NEW_WINDOW: + return contextMenuItemTagOpenVideoInNewWindow(); + case WEBKIT_CONTEXT_MENU_ACTION_OPEN_AUDIO_IN_NEW_WINDOW: + return contextMenuItemTagOpenAudioInNewWindow(); + case WEBKIT_CONTEXT_MENU_ACTION_COPY_VIDEO_LINK_TO_CLIPBOARD: + return contextMenuItemTagCopyVideoLinkToClipboard(); + case WEBKIT_CONTEXT_MENU_ACTION_COPY_AUDIO_LINK_TO_CLIPBOARD: + return contextMenuItemTagCopyAudioLinkToClipboard(); + case WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS: + return contextMenuItemTagToggleMediaControls(); + case WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_LOOP: + return contextMenuItemTagToggleMediaLoop(); + case WEBKIT_CONTEXT_MENU_ACTION_ENTER_VIDEO_FULLSCREEN: + return contextMenuItemTagEnterVideoFullscreen(); + case WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY: + return contextMenuItemTagMediaPlay(); + case WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PAUSE: + return contextMenuItemTagMediaPause(); + case WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE: + return contextMenuItemTagMediaMute(); + case WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION: + case WEBKIT_CONTEXT_MENU_ACTION_CUSTOM: + case WEBKIT_CONTEXT_MENU_ACTION_SPELLING_GUESS: + return String(); + default: + ASSERT_NOT_REACHED(); + } + + return String(); +} diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActions.h b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActions.h new file mode 100644 index 000000000..185bd251f --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActions.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION) +#error "Only <webkit2/webkit2.h> can be included directly." +#endif + +#include <glib.h> + +#ifndef WebKitContextMenuActions_h +#define WebKitContextMenuActions_h + +G_BEGIN_DECLS + +/** + * WebKitContextMenuAction: + * @WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION: No action, used by separator menu items. + * @WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK: Open current link. + * @WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW: Open current link in a new window. + * @WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK: Download link destination. + * @WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD: Copy link location to the clipboard. + * @WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW: Open current image in a new window. + * @WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK: Download current image. + * @WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD: Copy current image to the clipboard. + * @WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD: Copy curent image location to the clipboard. + * @WEBKIT_CONTEXT_MENU_ACTION_OPEN_FRAME_IN_NEW_WINDOW: Open current frame in a new window. + * @WEBKIT_CONTEXT_MENU_ACTION_GO_BACK: Load the previous history item. + * @WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD: Load the next history item. + * @WEBKIT_CONTEXT_MENU_ACTION_STOP: Stop any ongoing loading operation. + * @WEBKIT_CONTEXT_MENU_ACTION_RELOAD: Reload the conents of current view. + * @WEBKIT_CONTEXT_MENU_ACTION_COPY: Copy current selection the clipboard. + * @WEBKIT_CONTEXT_MENU_ACTION_CUT: Cut current selection to the clipboard. + * @WEBKIT_CONTEXT_MENU_ACTION_PASTE: Paste clipboard contents. + * @WEBKIT_CONTEXT_MENU_ACTION_DELETE: Delete current selection. + * @WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL: Select all text. + * @WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS: Input methods menu. + * @WEBKIT_CONTEXT_MENU_ACTION_UNICODE: Unicode menu. + * @WEBKIT_CONTEXT_MENU_ACTION_SPELLING_GUESS: A proposed replacement for a misspelled word. + * @WEBKIT_CONTEXT_MENU_ACTION_NO_GUESSES_FOUND: An indicator that spellchecking found no proposed replacements. + * @WEBKIT_CONTEXT_MENU_ACTION_IGNORE_SPELLING: Causes the spellchecker to ignore the word for this session. + * @WEBKIT_CONTEXT_MENU_ACTION_LEARN_SPELLING: Causes the spellchecker to add the word to the dictionary. + * @WEBKIT_CONTEXT_MENU_ACTION_IGNORE_GRAMMAR: Ignore grammar. + * @WEBKIT_CONTEXT_MENU_ACTION_FONT_MENU: Font options menu. + * @WEBKIT_CONTEXT_MENU_ACTION_BOLD: Bold. + * @WEBKIT_CONTEXT_MENU_ACTION_ITALIC: Italic. + * @WEBKIT_CONTEXT_MENU_ACTION_UNDERLINE: Underline. + * @WEBKIT_CONTEXT_MENU_ACTION_OUTLINE: Outline. + * @WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT: Open current element in the inspector. + * @WEBKIT_CONTEXT_MENU_ACTION_OPEN_VIDEO_IN_NEW_WINDOW: Open current video element in a new window. + * @WEBKIT_CONTEXT_MENU_ACTION_OPEN_AUDIO_IN_NEW_WINDOW: Open current audio element in a new window. + * @WEBKIT_CONTEXT_MENU_ACTION_COPY_VIDEO_LINK_TO_CLIPBOARD: Copy video link location in to the clipboard. + * @WEBKIT_CONTEXT_MENU_ACTION_COPY_AUDIO_LINK_TO_CLIPBOARD: Copy audio link location in to the clipboard. + * @WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS: Enable or disable media controls. + * @WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_LOOP: Enable or disable media loop. + * @WEBKIT_CONTEXT_MENU_ACTION_ENTER_VIDEO_FULLSCREEN: Show current video element in fullscreen mode. + * @WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY: Play current media element. + * @WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PAUSE: Pause current media element. + * @WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE: Mute current media element. + * @WEBKIT_CONTEXT_MENU_ACTION_CUSTOM: Custom action defined by applications. + * + * Enum values used to denote the stock actions for + * #WebKitContextMenuItem<!-- -->s + */ +typedef enum { + WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION = 0, + + WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK, + WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW, + WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK, + WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD, + WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW, + WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK, + WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD, + WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD, + WEBKIT_CONTEXT_MENU_ACTION_OPEN_FRAME_IN_NEW_WINDOW, + WEBKIT_CONTEXT_MENU_ACTION_GO_BACK, + WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD, + WEBKIT_CONTEXT_MENU_ACTION_STOP, + WEBKIT_CONTEXT_MENU_ACTION_RELOAD, + WEBKIT_CONTEXT_MENU_ACTION_COPY, + WEBKIT_CONTEXT_MENU_ACTION_CUT, + WEBKIT_CONTEXT_MENU_ACTION_PASTE, + WEBKIT_CONTEXT_MENU_ACTION_DELETE, + WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL, + WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS, + WEBKIT_CONTEXT_MENU_ACTION_UNICODE, + WEBKIT_CONTEXT_MENU_ACTION_SPELLING_GUESS, + WEBKIT_CONTEXT_MENU_ACTION_NO_GUESSES_FOUND, + WEBKIT_CONTEXT_MENU_ACTION_IGNORE_SPELLING, + WEBKIT_CONTEXT_MENU_ACTION_LEARN_SPELLING, + WEBKIT_CONTEXT_MENU_ACTION_IGNORE_GRAMMAR, + WEBKIT_CONTEXT_MENU_ACTION_FONT_MENU, + WEBKIT_CONTEXT_MENU_ACTION_BOLD, + WEBKIT_CONTEXT_MENU_ACTION_ITALIC, + WEBKIT_CONTEXT_MENU_ACTION_UNDERLINE, + WEBKIT_CONTEXT_MENU_ACTION_OUTLINE, + WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT, + WEBKIT_CONTEXT_MENU_ACTION_OPEN_VIDEO_IN_NEW_WINDOW, + WEBKIT_CONTEXT_MENU_ACTION_OPEN_AUDIO_IN_NEW_WINDOW, + WEBKIT_CONTEXT_MENU_ACTION_COPY_VIDEO_LINK_TO_CLIPBOARD, + WEBKIT_CONTEXT_MENU_ACTION_COPY_AUDIO_LINK_TO_CLIPBOARD, + WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS, + WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_LOOP, + WEBKIT_CONTEXT_MENU_ACTION_ENTER_VIDEO_FULLSCREEN, + WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY, + WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PAUSE, + WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE, + + WEBKIT_CONTEXT_MENU_ACTION_CUSTOM = 10000 +} WebKitContextMenuAction; + +G_END_DECLS + +#endif diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActionsPrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActionsPrivate.h new file mode 100644 index 000000000..f753bb97c --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActionsPrivate.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef WebKitContextMenuActionsPrivate_h +#define WebKitContextMenuActionsPrivate_h + +#include "WebKitContextMenuActions.h" +#include <WebCore/ContextMenuItem.h> + +bool webkitContextMenuActionIsCheckable(WebKitContextMenuAction); +WebCore::ContextMenuAction webkitContextMenuActionGetActionTag(WebKitContextMenuAction); +WebKitContextMenuAction webkitContextMenuActionGetForContextMenuItem(WebCore::ContextMenuItem*); +String webkitContextMenuActionGetLabel(WebKitContextMenuAction); + +#endif // WebKitPrintOperationPrivate_h diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItem.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItem.cpp new file mode 100644 index 000000000..b2b22fe41 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItem.cpp @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WebKitContextMenuItem.h" + +#include "MutableArray.h" +#include "WebContextMenuItem.h" +#include "WebContextMenuItemData.h" +#include "WebKitContextMenuActionsPrivate.h" +#include "WebKitContextMenuItemPrivate.h" +#include "WebKitContextMenuPrivate.h" +#include <WebCore/ContextMenu.h> +#include <WebCore/ContextMenuItem.h> +#include <gtk/gtk.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/gobject/GOwnPtr.h> +#include <wtf/gobject/GRefPtr.h> + +using namespace WebKit; +using namespace WebCore; + +struct _WebKitContextMenuItemPrivate { + OwnPtr<ContextMenuItem> menuItem; + GRefPtr<WebKitContextMenu> subMenu; +}; + +G_DEFINE_TYPE(WebKitContextMenuItem, webkit_context_menu_item, G_TYPE_INITIALLY_UNOWNED) + +static void webkitContextMenuItemFinalize(GObject* object) +{ + WebKitContextMenuItemPrivate* priv = WEBKIT_CONTEXT_MENU_ITEM(object)->priv; + if (priv->subMenu) + webkitContextMenuSetParentItem(priv->subMenu.get(), 0); + priv->~WebKitContextMenuItemPrivate(); + G_OBJECT_CLASS(webkit_context_menu_item_parent_class)->finalize(object); +} + +static void webkit_context_menu_item_init(WebKitContextMenuItem* item) +{ + WebKitContextMenuItemPrivate* priv = G_TYPE_INSTANCE_GET_PRIVATE(item, WEBKIT_TYPE_CONTEXT_MENU_ITEM, WebKitContextMenuItemPrivate); + item->priv = priv; + new (priv) WebKitContextMenuItemPrivate(); +} + +static void webkit_context_menu_item_class_init(WebKitContextMenuItemClass* itemClass) +{ + GObjectClass* gObjectClass = G_OBJECT_CLASS(itemClass); + gObjectClass->finalize = webkitContextMenuItemFinalize; + g_type_class_add_private(itemClass, sizeof(WebKitContextMenuItemPrivate)); +} + +static bool checkAndWarnIfMenuHasParentItem(WebKitContextMenu* menu) +{ + if (menu && webkitContextMenuGetParentItem(menu)) { + g_warning("Attempting to set a WebKitContextMenu as submenu of " + "a WebKitContextMenuItem, but the menu is already " + "a submenu of a WebKitContextMenuItem"); + return true; + } + + return false; +} + +static void webkitContextMenuItemSetSubMenu(WebKitContextMenuItem* item, GRefPtr<WebKitContextMenu> subMenu) +{ + if (checkAndWarnIfMenuHasParentItem(subMenu.get())) + return; + + if (item->priv->subMenu) + webkitContextMenuSetParentItem(item->priv->subMenu.get(), 0); + item->priv->subMenu = subMenu; + if (subMenu) + webkitContextMenuSetParentItem(subMenu.get(), item); +} + +WebKitContextMenuItem* webkitContextMenuItemCreate(WKContextMenuItemRef wkItem) +{ + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(g_object_new(WEBKIT_TYPE_CONTEXT_MENU_ITEM, NULL)); + WebContextMenuItemData* itemData = toImpl(wkItem)->data(); + item->priv->menuItem = WTF::adoptPtr(new ContextMenuItem(itemData->type(), itemData->action(), itemData->title(), itemData->enabled(), itemData->checked())); + const Vector<WebContextMenuItemData>& subMenu = itemData->submenu(); + if (!subMenu.size()) + return item; + + RefPtr<MutableArray> subMenuItems = MutableArray::create(); + subMenuItems->reserveCapacity(subMenu.size()); + for (size_t i = 0; i < subMenu.size(); ++i) + subMenuItems->append(WebContextMenuItem::create(subMenu[i]).get()); + webkitContextMenuItemSetSubMenu(item, adoptGRef(webkitContextMenuCreate(toAPI(subMenuItems.get())))); + + return item; +} + +static WebKitContextMenuItem* webkitContextMenuItemCreateForGtkItem(GtkMenuItem* menuItem) +{ + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(g_object_new(WEBKIT_TYPE_CONTEXT_MENU_ITEM, NULL)); + item->priv->menuItem = WTF::adoptPtr(new ContextMenuItem(menuItem)); + webkitContextMenuItemSetSubMenuFromGtkMenu(item, GTK_MENU(gtk_menu_item_get_submenu(menuItem))); + + return item; +} + +void webkitContextMenuItemSetSubMenuFromGtkMenu(WebKitContextMenuItem* item, GtkMenu* subMenu) +{ + if (!subMenu) + return; + + GOwnPtr<GList> children(gtk_container_get_children(GTK_CONTAINER(subMenu))); + if (!g_list_length(children.get())) + return; + + webkitContextMenuItemSetSubMenu(item, adoptGRef(webkit_context_menu_new())); + for (GList* listItem = children.get(); listItem; listItem = g_list_next(listItem)) { + GRefPtr<GtkWidget> widget = GTK_WIDGET(listItem->data); + if (!GTK_IS_MENU_ITEM(widget.get())) + continue; + + gtk_container_remove(GTK_CONTAINER(subMenu), widget.get()); + GtkMenuItem* menuItem = GTK_MENU_ITEM(widget.leakRef()); + g_object_force_floating(G_OBJECT(menuItem)); + webkit_context_menu_append(item->priv->subMenu.get(), webkitContextMenuItemCreateForGtkItem(menuItem)); + } +} + +GtkMenuItem* webkitContextMenuItemRelease(WebKitContextMenuItem* item) +{ + if (item->priv->subMenu) { + Vector<ContextMenuItem> subMenuItems; + webkitContextMenuPopulate(item->priv->subMenu.get(), subMenuItems); + ContextMenu subMenu(platformMenuDescription(subMenuItems)); + item->priv->menuItem->setSubMenu(&subMenu); + } + + return item->priv->menuItem->releasePlatformDescription(); +} + +/** + * webkit_context_menu_item_new: + * @action: a #GtkAction + * + * Creates a new #WebKitContextMenuItem for the given @action. + * + * Returns: the newly created #WebKitContextMenuItem object. + */ +WebKitContextMenuItem* webkit_context_menu_item_new(GtkAction* action) +{ + g_return_val_if_fail(GTK_IS_ACTION(action), 0); + + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(g_object_new(WEBKIT_TYPE_CONTEXT_MENU_ITEM, NULL)); + item->priv->menuItem = WTF::adoptPtr(new ContextMenuItem(GTK_MENU_ITEM(gtk_action_create_menu_item(action)))); + item->priv->menuItem->setAction(ContextMenuItemBaseApplicationTag); + + return item; +} + +/** + * webkit_context_menu_item_new_from_stock_action: + * @action: a #WebKitContextMenuAction stock action + * + * Creates a new #WebKitContextMenuItem for the given stock action. + * Stock actions are handled automatically by WebKit so that, for example, + * when a menu item created with a %WEBKIT_CONTEXT_MENU_ACTION_STOP is + * activated the action associated will be handled by WebKit and the current + * load operation will be stopped. You can get the #GtkAction of a + * #WebKitContextMenuItem created with a #WebKitContextMenuAction with + * webkit_context_menu_item_get_action() and connect to #GtkAction::activate signal + * to be notified when the item is activated. But you can't prevent the asociated + * action from being performed. + * + * Returns: the newly created #WebKitContextMenuItem object. + */ +WebKitContextMenuItem* webkit_context_menu_item_new_from_stock_action(WebKitContextMenuAction action) +{ + g_return_val_if_fail(action > WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION && action < WEBKIT_CONTEXT_MENU_ACTION_CUSTOM, 0); + + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(g_object_new(WEBKIT_TYPE_CONTEXT_MENU_ITEM, NULL)); + ContextMenuItemType type = webkitContextMenuActionIsCheckable(action) ? CheckableActionType : ActionType; + item->priv->menuItem = WTF::adoptPtr(new ContextMenuItem(type, webkitContextMenuActionGetActionTag(action), webkitContextMenuActionGetLabel(action))); + + return item; +} + +/** + * webkit_context_menu_item_new_from_stock_action_with_label: + * @action: a #WebKitContextMenuAction stock action + * @label: a custom label text to use instead of the predefined one + * + * Creates a new #WebKitContextMenuItem for the given stock action using the given @label. + * Stock actions have a predefined label, this method can be used to create a + * #WebKitContextMenuItem for a #WebKitContextMenuAction but using a custom label. + * + * Returns: the newly created #WebKitContextMenuItem object. + */ +WebKitContextMenuItem* webkit_context_menu_item_new_from_stock_action_with_label(WebKitContextMenuAction action, const gchar* label) +{ + g_return_val_if_fail(action > WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION && action < WEBKIT_CONTEXT_MENU_ACTION_CUSTOM, 0); + + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(g_object_new(WEBKIT_TYPE_CONTEXT_MENU_ITEM, NULL)); + ContextMenuItemType type = webkitContextMenuActionIsCheckable(action) ? CheckableActionType : ActionType; + item->priv->menuItem = WTF::adoptPtr(new ContextMenuItem(type, webkitContextMenuActionGetActionTag(action), String::fromUTF8(label))); + + return item; +} + +/** + * webkit_context_menu_item_new_with_submenu: + * @label: the menu item label text + * @submenu: a #WebKitContextMenu to set + * + * Creates a new #WebKitContextMenuItem using the given @label with a submenu. + * + * Returns: the newly created #WebKitContextMenuItem object. + */ +WebKitContextMenuItem* webkit_context_menu_item_new_with_submenu(const gchar* label, WebKitContextMenu* submenu) +{ + g_return_val_if_fail(label, 0); + g_return_val_if_fail(WEBKIT_IS_CONTEXT_MENU(submenu), 0); + + if (checkAndWarnIfMenuHasParentItem(submenu)) + return 0; + + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(g_object_new(WEBKIT_TYPE_CONTEXT_MENU_ITEM, NULL)); + item->priv->menuItem = WTF::adoptPtr(new ContextMenuItem(SubmenuType, ContextMenuItemBaseApplicationTag, String::fromUTF8(label))); + item->priv->subMenu = submenu; + webkitContextMenuSetParentItem(submenu, item); + + return item; +} + +/** + * webkit_context_menu_item_new_separator: + * + * Creates a new #WebKitContextMenuItem representing a separator. + * + * Returns: the newly created #WebKitContextMenuItem object. + */ +WebKitContextMenuItem* webkit_context_menu_item_new_separator(void) +{ + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(g_object_new(WEBKIT_TYPE_CONTEXT_MENU_ITEM, NULL)); + item->priv->menuItem = WTF::adoptPtr(new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String())); + + return item; +} + +/** + * webkit_context_menu_item_get_action: + * @item: a #WebKitContextMenuItem + * + * Gets the action associated to @item. + * + * Returns: (transfer none): the #GtkAction associated to the #WebKitContextMenuItem, + * or %NULL if @item is a separator. + */ +GtkAction* webkit_context_menu_item_get_action(WebKitContextMenuItem* item) +{ + g_return_val_if_fail(WEBKIT_IS_CONTEXT_MENU_ITEM(item), 0); + + return item->priv->menuItem->gtkAction(); +} + +/** + * webkit_context_menu_item_get_stock_action: + * @item: a #WebKitContextMenuItem + * + * Gets the #WebKitContextMenuAction of @item. If the #WebKitContextMenuItem was not + * created for a stock action %WEBKIT_CONTEXT_MENU_ACTION_CUSTOM will be + * returned. If the #WebKitContextMenuItem is a separator %WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION + * will be returned. + * + * Returns: the #WebKitContextMenuAction of @item + */ +WebKitContextMenuAction webkit_context_menu_item_get_stock_action(WebKitContextMenuItem* item) +{ + g_return_val_if_fail(WEBKIT_IS_CONTEXT_MENU_ITEM(item), WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION); + + return webkitContextMenuActionGetForContextMenuItem(item->priv->menuItem.get()); +} + +/** + * webkit_context_menu_item_is_separator: + * @item: a #WebKitContextMenuItem + * + * Checks whether @item is a separator. + * + * Returns: %TRUE is @item is a separator or %FALSE otherwise + */ +gboolean webkit_context_menu_item_is_separator(WebKitContextMenuItem* item) +{ + g_return_val_if_fail(WEBKIT_IS_CONTEXT_MENU_ITEM(item), FALSE); + + return item->priv->menuItem->type() == SeparatorType; +} + +/** + * webkit_context_menu_item_set_submenu: + * @item: a #WebKitContextMenuItem + * @submenu: (allow-none): a #WebKitContextMenu + * + * Sets or replaces the @item submenu. If @submenu is %NULL the current + * submenu of @item is removed. + */ +void webkit_context_menu_item_set_submenu(WebKitContextMenuItem* item, WebKitContextMenu* submenu) +{ + g_return_if_fail(WEBKIT_IS_CONTEXT_MENU_ITEM(item)); + + if (item->priv->subMenu == submenu) + return; + + webkitContextMenuItemSetSubMenu(item, submenu); +} + +/** + * webkit_context_menu_item_get_submenu: + * @item: a #WebKitContextMenuItem + * + * Gets the submenu of @item. + * + * Returns: (transfer none): the #WebKitContextMenu representing the submenu of + * @item or %NULL if @item doesn't have a submenu. + */ +WebKitContextMenu* webkit_context_menu_item_get_submenu(WebKitContextMenuItem* item) +{ + g_return_val_if_fail(WEBKIT_IS_CONTEXT_MENU_ITEM(item), 0); + + return item->priv->subMenu.get(); +} + diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItem.h b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItem.h new file mode 100644 index 000000000..52d912843 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItem.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION) +#error "Only <webkit2/webkit2.h> can be included directly." +#endif + +#ifndef WebKitContextMenuItem_h +#define WebKitContextMenuItem_h + +#include <gtk/gtk.h> +#include <webkit2/WebKitDefines.h> +#include <webkit2/WebKitContextMenu.h> +#include <webkit2/WebKitContextMenuActions.h> + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_CONTEXT_MENU_ITEM (webkit_context_menu_item_get_type()) +#define WEBKIT_CONTEXT_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_CONTEXT_MENU_ITEM, WebKitContextMenuItem)) +#define WEBKIT_IS_CONTEXT_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_CONTEXT_MENU_ITEM)) +#define WEBKIT_CONTEXT_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_CONTEXT_MENU_ITEM, WebKitContextMenuItemClass)) +#define WEBKIT_IS_CONTEXT_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_CONTEXT_MENU_ITEM)) +#define WEBKIT_CONTEXT_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_CONTEXT_MENU_ITEM, WebKitContextMenuItemClass)) + +typedef struct _WebKitContextMenuItemClass WebKitContextMenuItemClass; +typedef struct _WebKitContextMenuItemPrivate WebKitContextMenuItemPrivate; + +struct _WebKitContextMenuItem { + GInitiallyUnowned parent; + + WebKitContextMenuItemPrivate *priv; +}; + +struct _WebKitContextMenuItemClass { + GInitiallyUnownedClass parent_class; +}; + +WEBKIT_API GType +webkit_context_menu_item_get_type (void); + +WEBKIT_API WebKitContextMenuItem * +webkit_context_menu_item_new (GtkAction *action); + +WEBKIT_API WebKitContextMenuItem * +webkit_context_menu_item_new_from_stock_action (WebKitContextMenuAction action); + +WEBKIT_API WebKitContextMenuItem * +webkit_context_menu_item_new_from_stock_action_with_label (WebKitContextMenuAction action, + const gchar *label); + +WEBKIT_API WebKitContextMenuItem * +webkit_context_menu_item_new_with_submenu (const gchar *label, + WebKitContextMenu *submenu); + +WEBKIT_API WebKitContextMenuItem * +webkit_context_menu_item_new_separator (void); + +WEBKIT_API GtkAction * +webkit_context_menu_item_get_action (WebKitContextMenuItem *item); + +WEBKIT_API WebKitContextMenuAction +webkit_context_menu_item_get_stock_action (WebKitContextMenuItem *item); + +WEBKIT_API gboolean +webkit_context_menu_item_is_separator (WebKitContextMenuItem *item); + +WEBKIT_API void +webkit_context_menu_item_set_submenu (WebKitContextMenuItem *item, + WebKitContextMenu *submenu); + +WEBKIT_API WebKitContextMenu * +webkit_context_menu_item_get_submenu (WebKitContextMenuItem *item); + +G_END_DECLS + +#endif diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItemPrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItemPrivate.h new file mode 100644 index 000000000..9c88003bf --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItemPrivate.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef WebKitContextMenuItemPrivate_h +#define WebKitContextMenuItemPrivate_h + +#include "WebKitContextMenuItem.h" +#include "WebKitPrivate.h" + +WebKitContextMenuItem* webkitContextMenuItemCreate(WKContextMenuItemRef); +GtkMenuItem* webkitContextMenuItemRelease(WebKitContextMenuItem*); +void webkitContextMenuItemSetSubMenuFromGtkMenu(WebKitContextMenuItem*, GtkMenu*); + +#endif // WebKitContextMenuItemPrivate_h diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuPrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuPrivate.h new file mode 100644 index 000000000..6d3f18015 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuPrivate.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef WebKitContextMenuPrivate_h +#define WebKitContextMenuPrivate_h + +#include "WebKitContextMenu.h" +#include "WebKitPrivate.h" + +WebKitContextMenu* webkitContextMenuCreate(WKArrayRef wkItems); +void webkitContextMenuPopulate(WebKitContextMenu*, Vector<WebCore::ContextMenuItem>&); +void webkitContextMenuSetParentItem(WebKitContextMenu*, WebKitContextMenuItem*); +WebKitContextMenuItem* webkitContextMenuGetParentItem(WebKitContextMenu*); + +#endif // WebKitContextMenuPrivate_h diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitDefines.h b/Source/WebKit2/UIProcess/API/gtk/WebKitDefines.h index 96bcb4ea2..733bf884c 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitDefines.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitDefines.h @@ -32,9 +32,11 @@ #include <glib.h> -typedef struct _WebKitPrintOperation WebKitPrintOperation; -typedef struct _WebKitFindController WebKitFindController; -typedef struct _WebKitWebView WebKitWebView; +typedef struct _WebKitPrintOperation WebKitPrintOperation; +typedef struct _WebKitFindController WebKitFindController; +typedef struct _WebKitWebView WebKitWebView; +typedef struct _WebKitContextMenu WebKitContextMenu; +typedef struct _WebKitContextMenuItem WebKitContextMenuItem; #ifdef G_OS_WIN32 # ifdef BUILDING_WEBKIT diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitSettings.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitSettings.cpp index 02e82b020..9e24aabb1 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitSettings.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitSettings.cpp @@ -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; @@ -853,6 +862,24 @@ static void webkit_settings_class_init(WebKitSettingsClass* klass) 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: * * Whether #WebKitWebView:zoom-level affects only the @@ -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); } /** @@ -2189,6 +2217,39 @@ void webkit_settings_set_enable_webgl(WebKitSettings* settings, gboolean enabled } /** + * 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 * @zoom_text_only: Value to be set diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitSettings.h b/Source/WebKit2/UIProcess/API/gtk/WebKitSettings.h index 53ebda299..a86d6bc1e 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitSettings.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitSettings.h @@ -308,6 +308,13 @@ webkit_settings_set_enable_webgl (WebKitSettings * 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); diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitUIClient.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitUIClient.cpp index 7d4eedfb6..1d985d342 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitUIClient.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitUIClient.cpp @@ -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 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 <JavaScriptCore/APICast.h> #include <WebCore/DragIcon.h> +#include <WebCore/GOwnPtrGtk.h> #include <WebCore/GtkUtilities.h> #include <glib/gi18n-lib.h> #include <wtf/gobject/GOwnPtr.h> @@ -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<WebKitSettings> settings; GRefPtr<WebKitWindowProperties> windowProperties; + GRefPtr<GMainLoop> modalLoop; + GRefPtr<WebKitHitTestResult> 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<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 +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 + * <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 @@ -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. + * <itemizedlist> + * <listitem><para> + * To customize the proposed menu you can use webkit_context_menu_prepend(), + * webkit_context_menu_append() or webkit_context_menu_insert() to add new + * #WebKitContextMenuItem<!-- -->s 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. + * </para></listitem> + * <listitem><para> + * 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. + * </para></listitem> + * <listitem><para> + * 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. + * </para></listitem> + * <listitem><para> + * 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. + * </para></listitem> + * </itemizedlist> + * + * 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<ContextMenuItem>& contextMenuItems) -{ - for (size_t i = 0; i < WKArrayGetSize(wkProposedMenu); ++i) { - WKContextMenuItemRef wkItem = static_cast<WKContextMenuItemRef>(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<ContextMenuItem>& 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<ContextMenuItem> contextMenuItems; - webkitWebViewCreateAndAppendDefaultMenuItems(webView, wkProposedMenu, contextMenuItems); + GRefPtr<WebKitContextMenu> contextMenu = adoptGRef(webkitContextMenuCreate(wkProposedMenu)); if (WKHitTestResultIsContentEditable(wkHitTestResult)) - webkitWebViewCreateAndAppendInputMethodsMenuItem(webView, contextMenuItems); + webkitWebViewCreateAndAppendInputMethodsMenuItem(webView, contextMenu.get()); + + GRefPtr<WebKitHitTestResult> hitTestResult = adoptGRef(webkitHitTestResultCreate(wkHitTestResult)); + GOwnPtr<GdkEvent> contextMenuEvent(webkitWebViewBaseTakeContextMenuEvent(webViewBase)); + + gboolean returnValue; + g_signal_emit(webView, signals[CONTEXT_MENU], 0, contextMenu.get(), contextMenuEvent.get(), hitTestResult.get(), &returnValue); + if (returnValue) + return; + + Vector<ContextMenuItem> 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<gpointer>(zoomTextOnlyChanged), webView); + webkitWebViewDisconnectSettingsSignalHandlers(webView); webkitWebViewSetSettings(webView, settings, toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView)))); } diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h index 716fbbd08..9328fa12f 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h @@ -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, @@ -158,6 +159,10 @@ struct _WebKitWebViewClass { gboolean (* leave_fullscreen) (WebKitWebView *web_view); gboolean (* run_file_chooser) (WebKitWebView *web_view, WebKitFileChooserRequest *request); + gboolean (* context_menu) (WebKitWebView *web_view, + WebKitContextMenu *context_menu, + GdkEvent *event, + WebKitHitTestResult *hit_test_result); /* Padding for future expansion */ void (*_webkit_reserved0) (void); diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp index a2cc1d97b..b7ffc98b8 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp @@ -46,6 +46,7 @@ #include <WebCore/DataObjectGtk.h> #include <WebCore/DragData.h> #include <WebCore/DragIcon.h> +#include <WebCore/GOwnPtrGtk.h> #include <WebCore/GtkClickCounter.h> #include <WebCore/GtkDragAndDropHelper.h> #include <WebCore/GtkUtilities.h> @@ -94,6 +95,7 @@ struct _WebKitWebViewBasePrivate { #endif GtkWidget* inspectorView; unsigned inspectorViewHeight; + GOwnPtr<GdkEvent> contextMenuEvent; WebContextMenuProxyGtk* activeContextMenuProxy; }; @@ -448,6 +450,10 @@ static gboolean webkitWebViewBaseButtonPressEvent(GtkWidget* widget, GdkEventBut if (!priv->clickCounter.shouldProcessButtonEvent(buttonEvent)) return TRUE; + + // If it's a right click event save it as a possible context menu event. + if (buttonEvent->button == 3) + priv->contextMenuEvent.set(gdk_event_copy(reinterpret_cast<GdkEvent*>(buttonEvent))); priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(buttonEvent), priv->clickCounter.clickCountForGdkButtonEvent(widget, buttonEvent))); return TRUE; @@ -784,3 +790,8 @@ WebContextMenuProxyGtk* webkitWebViewBaseGetActiveContextMenuProxy(WebKitWebView { return webkitWebViewBase->priv->activeContextMenuProxy; } + +GdkEvent* webkitWebViewBaseTakeContextMenuEvent(WebKitWebViewBase* webkitWebViewBase) +{ + return webkitWebViewBase->priv->contextMenuEvent.release(); +} diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBasePrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBasePrivate.h index 45ffbf283..70cc72575 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBasePrivate.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBasePrivate.h @@ -49,5 +49,6 @@ void webkitWebViewBaseInitializeFullScreenClient(WebKitWebViewBase*, const WKFul void webkitWebViewBaseSetInspectorViewHeight(WebKitWebViewBase*, unsigned height); void webkitWebViewBaseSetActiveContextMenuProxy(WebKitWebViewBase*, WebContextMenuProxyGtk*); WebContextMenuProxyGtk* webkitWebViewBaseGetActiveContextMenuProxy(WebKitWebViewBase*); +GdkEvent* webkitWebViewBaseTakeContextMenuEvent(WebKitWebViewBase*); #endif // WebKitWebViewBasePrivate_h diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h index aedcdee6e..b602f4fe0 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h @@ -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); diff --git a/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml b/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml index c2eebf36c..6b62d6f69 100644 --- a/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml +++ b/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml @@ -37,6 +37,8 @@ <xi:include href="xml/WebKitWebInspector.xml"/> <xi:include href="xml/WebKitURISchemeRequest.xml"/> <xi:include href="xml/WebKitVersion.xml"/> + <xi:include href="xml/WebKitContextMenu.xml"/> + <xi:include href="xml/WebKitContextMenuItem.xml"/> </chapter> <index id="index-all"> diff --git a/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt b/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt index 1b97de88f..aca34df0b 100644 --- a/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt +++ b/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt @@ -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 @@ -744,3 +746,63 @@ WEBKIT_MINOR_VERSION WEBKIT_MICRO_VERSION WEBKIT_CHECK_VERSION </SECTION> + +<SECTION> +<FILE>WebKitContextMenu</FILE> +WebKitContextMenu +webkit_context_menu_new +webkit_context_menu_new_with_items +webkit_context_menu_prepend +webkit_context_menu_append +webkit_context_menu_insert +webkit_context_menu_move_item +webkit_context_menu_get_items +webkit_context_menu_get_n_items +webkit_context_menu_first +webkit_context_menu_last +webkit_context_menu_get_item_at_position +webkit_context_menu_remove +webkit_context_menu_remove_all + +<SUBSECTION Standard> +WebKitContextMenuClass +WEBKIT_TYPE_CONTEXT_MENU +WEBKIT_CONTEXT_MENU +WEBKIT_IS_CONTEXT_MENU +WEBKIT_CONTEXT_MENU_CLASS +WEBKIT_IS_CONTEXT_MENU_CLASS +WEBKIT_CONTEXT_MENU_GET_CLASS + +<SUBSECTION Private> +WebKitContextMenuPrivate +webkit_context_menu_get_type +</SECTION> + +<SECTION> +<FILE>WebKitContextMenuItem</FILE> +WebKitContextMenuItem +WebKitContextMenuAction +webkit_context_menu_item_new +webkit_context_menu_item_new_from_stock_action +webkit_context_menu_item_new_from_stock_action_with_label +webkit_context_menu_item_new_with_submenu +webkit_context_menu_item_new_separator +webkit_context_menu_item_get_action +webkit_context_menu_item_get_stock_action +webkit_context_menu_item_is_separator +webkit_context_menu_item_set_submenu +webkit_context_menu_item_get_submenu + +<SUBSECTION Standard> +WebKitContextMenuItemClass +WEBKIT_TYPE_CONTEXT_MENU_ITEM +WEBKIT_CONTEXT_MENU_ITEM +WEBKIT_IS_CONTEXT_MENU_ITEM +WEBKIT_CONTEXT_MENU_ITEM_CLASS +WEBKIT_IS_CONTEXT_MENU_ITEM_CLASS +WEBKIT_CONTEXT_MENU_ITEM_GET_CLASS + +<SUBSECTION Private> +WebKitContextMenuItemPrivate +webkit_context_menu_item_get_type +</SECTION> diff --git a/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk.types b/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk.types index d155982f2..4d8843e9c 100644 --- a/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk.types +++ b/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk.types @@ -19,3 +19,5 @@ webkit_plugin_get_type webkit_mime_info_get_type webkit_web_inspector_get_type webkit_uri_scheme_request_get_type +webkit_context_menu_get_type +webkit_context_menu_item_get_type diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/GNUmakefile.am b/Source/WebKit2/UIProcess/API/gtk/tests/GNUmakefile.am index 7adae8adc..058a613f1 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/GNUmakefile.am +++ b/Source/WebKit2/UIProcess/API/gtk/tests/GNUmakefile.am @@ -2,6 +2,7 @@ if ENABLE_WEBKIT2 TEST_PROGS += \ Programs/WebKit2APITests/TestBackForwardList \ + Programs/WebKit2APITests/TestContextMenu \ Programs/WebKit2APITests/TestCookieManager \ Programs/WebKit2APITests/TestDownloads \ Programs/WebKit2APITests/TestInspector \ @@ -167,4 +168,10 @@ Programs_WebKit2APITests_TestWebKitVersion_CPPFLAGS = $(webkit2_tests_cppflags) Programs_WebKit2APITests_TestWebKitVersion_LDADD = $(webkit2_tests_ldadd) Programs_WebKit2APITests_TestWebKitVersion_LDFLAGS = $(webkit2_tests_ldflags) +Programs_WebKit2APITests_TestContextMenu_SOURCES = \ + Source/WebKit2/UIProcess/API/gtk/tests/TestContextMenu.cpp +Programs_WebKit2APITests_TestContextMenu_CPPFLAGS = $(webkit2_tests_cppflags) +Programs_WebKit2APITests_TestContextMenu_LDADD = $(webkit2_tests_ldadd) +Programs_WebKit2APITests_TestContextMenu_LDFLAGS = $(webkit2_tests_ldflags) + endif # ENABLE_WEBKIT2 diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/TestContextMenu.cpp b/Source/WebKit2/UIProcess/API/gtk/tests/TestContextMenu.cpp new file mode 100644 index 000000000..f74016006 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/tests/TestContextMenu.cpp @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2,1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WebViewTest.h" +#include <wtf/gobject/GRefPtr.h> + +class ContextMenuTest: public WebViewTest { +public: + enum ContextMenuItemStateFlags { + Visible = 1 << 0, + Enabled = 1 << 1, + Checked = 1 << 2 + }; + + void checkContextMenuEvent(GdkEvent* event) + { + g_assert(event); + g_assert_cmpint(event->type, ==, GDK_BUTTON_PRESS); + g_assert_cmpint(event->button.button, ==, 3); + g_assert_cmpint(event->button.x, ==, m_menuPositionX); + g_assert_cmpint(event->button.y, ==, m_menuPositionY); + } + + static gboolean contextMenuCallback(WebKitWebView* webView, WebKitContextMenu* contextMenu, GdkEvent* event, WebKitHitTestResult* hitTestResult, ContextMenuTest* test) + { + g_assert(WEBKIT_IS_CONTEXT_MENU(contextMenu)); + test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(contextMenu)); + test->checkContextMenuEvent(event); + g_assert(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult)); + test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(hitTestResult)); + + return test->contextMenu(contextMenu, event, hitTestResult); + } + + ContextMenuTest() + : m_menuPositionX(0) + , m_menuPositionY(0) + { + g_signal_connect(m_webView, "context-menu", G_CALLBACK(contextMenuCallback), this); + } + + ~ContextMenuTest() + { + g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); + } + + virtual bool contextMenu(WebKitContextMenu*, GdkEvent*, WebKitHitTestResult*) = 0; + + bool shouldShowInputMethodsMenu() + { + GtkSettings* settings = gtk_widget_get_settings(GTK_WIDGET(m_webView)); + if (!settings) + return true; + + gboolean showInputMethodMenu; + g_object_get(settings, "gtk-show-input-method-menu", &showInputMethodMenu, NULL); + return showInputMethodMenu; + } + + void checkActionState(GtkAction* action, unsigned state) + { + if (state & Visible) + g_assert(gtk_action_get_visible(action)); + else + g_assert(!gtk_action_get_visible(action)); + + if (state & Enabled) + g_assert(gtk_action_get_sensitive(action)); + else + g_assert(!gtk_action_get_sensitive(action)); + + if (GTK_IS_TOGGLE_ACTION(action)) { + if (state & Checked) + g_assert(gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))); + else + g_assert(!gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))); + } + } + + GList* checkCurrentItemIsStockActionAndGetNext(GList* items, WebKitContextMenuAction stockAction, unsigned state) + { + g_assert(items); + g_assert(WEBKIT_IS_CONTEXT_MENU_ITEM(items->data)); + + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(items->data); + assertObjectIsDeletedWhenTestFinishes(G_OBJECT(item)); + + GtkAction* action = webkit_context_menu_item_get_action(item); + g_assert(GTK_IS_ACTION(action)); + + g_assert_cmpint(webkit_context_menu_item_get_stock_action(item), ==, stockAction); + + checkActionState(action, state); + + return g_list_next(items); + } + + GList* checkCurrentItemIsCustomActionAndGetNext(GList* items, const char* label, unsigned state) + { + g_assert(items); + g_assert(WEBKIT_IS_CONTEXT_MENU_ITEM(items->data)); + + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(items->data); + assertObjectIsDeletedWhenTestFinishes(G_OBJECT(item)); + + GtkAction* action = webkit_context_menu_item_get_action(item); + g_assert(GTK_IS_ACTION(action)); + + g_assert_cmpint(webkit_context_menu_item_get_stock_action(item), ==, WEBKIT_CONTEXT_MENU_ACTION_CUSTOM); + g_assert_cmpstr(gtk_action_get_label(action), ==, label); + + checkActionState(action, state); + + return g_list_next(items); + } + + GList* checkCurrentItemIsSubMenuAndGetNext(GList* items, const char* label, unsigned state, GList** subMenuIter) + { + g_assert(items); + g_assert(WEBKIT_IS_CONTEXT_MENU_ITEM(items->data)); + + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(items->data); + assertObjectIsDeletedWhenTestFinishes(G_OBJECT(item)); + + GtkAction* action = webkit_context_menu_item_get_action(item); + g_assert(GTK_IS_ACTION(action)); + + g_assert_cmpstr(gtk_action_get_label(action), ==, label); + checkActionState(action, state); + + WebKitContextMenu* subMenu = webkit_context_menu_item_get_submenu(item); + g_assert(WEBKIT_IS_CONTEXT_MENU(subMenu)); + if (subMenuIter) + *subMenuIter = webkit_context_menu_get_items(subMenu); + + return g_list_next(items); + } + + GList* checkCurrentItemIsSeparatorAndGetNext(GList* items) + { + g_assert(items); + g_assert(WEBKIT_IS_CONTEXT_MENU_ITEM(items->data)); + + WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(items->data); + g_assert(webkit_context_menu_item_is_separator(item)); + + return g_list_next(items); + } + + static gboolean doRightClickIdleCallback(ContextMenuTest* test) + { + test->clickMouseButton(test->m_menuPositionX, test->m_menuPositionY, 3); + return FALSE; + } + + void showContextMenuAtPositionAndWaitUntilFinished(int x, int y) + { + m_menuPositionX = x; + m_menuPositionY = y; + g_idle_add(reinterpret_cast<GSourceFunc>(doRightClickIdleCallback), this); + g_main_loop_run(m_mainLoop); + } + + void showContextMenuAndWaitUntilFinished() + { + showContextMenuAtPositionAndWaitUntilFinished(0, 0); + } + + double m_menuPositionX; + double m_menuPositionY; +}; + +class ContextMenuDefaultTest: public ContextMenuTest { +public: + MAKE_GLIB_TEST_FIXTURE(ContextMenuDefaultTest); + + enum DefaultMenuType { + Navigation, + Link, + Image, + LinkImage, + Video, + Editable + }; + + ContextMenuDefaultTest() + : m_expectedMenuType(Navigation) + { + } + + bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent* event, WebKitHitTestResult* hitTestResult) + { + GList* iter = webkit_context_menu_get_items(contextMenu); + + switch (m_expectedMenuType) { + case Navigation: + g_assert(!webkit_hit_test_result_context_is_link(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_image(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_media(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_BACK, Visible); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD, Visible); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_STOP, Visible); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_RELOAD, Visible | Enabled); + break; + case Link: + g_assert(webkit_hit_test_result_context_is_link(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_image(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_media(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD, Visible | Enabled); + break; + case Image: + g_assert(!webkit_hit_test_result_context_is_link(hitTestResult)); + g_assert(webkit_hit_test_result_context_is_image(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_media(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD, Visible | Enabled); + break; + case LinkImage: + g_assert(webkit_hit_test_result_context_is_link(hitTestResult)); + g_assert(webkit_hit_test_result_context_is_image(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_media(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD, Visible | Enabled); + iter = checkCurrentItemIsSeparatorAndGetNext(iter); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD, Visible | Enabled); + break; + case Video: + g_assert(!webkit_hit_test_result_context_is_link(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_image(hitTestResult)); + g_assert(webkit_hit_test_result_context_is_media(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_editable(hitTestResult)); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE, Visible); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS, Visible | Enabled | Checked); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_LOOP, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_ENTER_VIDEO_FULLSCREEN, Visible); + iter = checkCurrentItemIsSeparatorAndGetNext(iter); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY_VIDEO_LINK_TO_CLIPBOARD, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_OPEN_VIDEO_IN_NEW_WINDOW, Visible | Enabled); + break; + case Editable: + g_assert(!webkit_hit_test_result_context_is_link(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_image(hitTestResult)); + g_assert(!webkit_hit_test_result_context_is_media(hitTestResult)); + g_assert(webkit_hit_test_result_context_is_editable(hitTestResult)); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_CUT, Visible); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_COPY, Visible); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_PASTE, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_DELETE, Visible); + iter = checkCurrentItemIsSeparatorAndGetNext(iter); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL, Visible | Enabled); + if (shouldShowInputMethodsMenu()) { + iter = checkCurrentItemIsSeparatorAndGetNext(iter); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_UNICODE, Visible | Enabled); + } + break; + default: + g_assert_not_reached(); + } + + if (webkit_settings_get_enable_developer_extras(webkit_web_view_get_settings(m_webView))) { + iter = checkCurrentItemIsSeparatorAndGetNext(iter); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT, Visible | Enabled); + } + g_assert(!iter); + + quitMainLoop(); + + return true; + } + + DefaultMenuType m_expectedMenuType; +}; + +static void testContextMenuDefaultMenu(ContextMenuDefaultTest* test, gconstpointer) +{ + test->showInWindowAndWaitUntilMapped(); + + const char* linksHTML = + "<html><body>" + " <a style='position:absolute; left:1; top:1' href='http://www.webkitgtk.org' title='WebKitGTK+ Title'>WebKitGTK+ Website</a>" + " <img style='position:absolute; left:1; top:10' src='0xdeadbeef' width=5 height=5></img>" + " <a style='position:absolute; left:1; top:20' href='http://www.webkitgtk.org/logo' title='WebKitGTK+ Logo'><img src='0xdeadbeef' width=5 height=5></img></a>" + " <video style='position:absolute; left:1; top:30' width=10 height=10 controls='controls'><source src='movie.ogg' type='video/ogg' /></video>" + " <input style='position:absolute; left:1; top:50' size='10'></input>" + "</body></html>"; + test->loadHtml(linksHTML, "file:///"); + test->waitUntilLoadFinished(); + + // Context menu for document. + test->m_expectedMenuType = ContextMenuDefaultTest::Navigation; + test->showContextMenuAtPositionAndWaitUntilFinished(0, 0); + + // Context menu for link. + test->m_expectedMenuType = ContextMenuDefaultTest::Link; + test->showContextMenuAtPositionAndWaitUntilFinished(1, 1); + + // Context menu for image. + test->m_expectedMenuType = ContextMenuDefaultTest::Image; + test->showContextMenuAtPositionAndWaitUntilFinished(1, 10); + + // Enable developer extras now, so that inspector element + // will be shown in the default context menu. + webkit_settings_set_enable_developer_extras(webkit_web_view_get_settings(test->m_webView), TRUE); + + // Context menu for image link. + test->m_expectedMenuType = ContextMenuDefaultTest::LinkImage; + test->showContextMenuAtPositionAndWaitUntilFinished(1, 20); + + // Context menu for image video. + test->m_expectedMenuType = ContextMenuDefaultTest::Video; + test->showContextMenuAtPositionAndWaitUntilFinished(1, 30); + + // Context menu for editable. + test->m_expectedMenuType = ContextMenuDefaultTest::Editable; + test->showContextMenuAtPositionAndWaitUntilFinished(5, 55); +} + +class ContextMenuCustomTest: public ContextMenuTest { +public: + MAKE_GLIB_TEST_FIXTURE(ContextMenuCustomTest); + + ContextMenuCustomTest() + : m_itemToActivateLabel(0) + , m_activated(false) + , m_toggled(false) + { + } + + bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult* hitTestResult) + { + // Append our custom item to the default menu. + webkit_context_menu_append(contextMenu, webkit_context_menu_item_new(m_action.get())); + quitMainLoop(); + + return false; + } + + GtkMenu* getPopupMenu() + { + GOwnPtr<GList> toplevels(gtk_window_list_toplevels()); + for (GList* iter = toplevels.get(); iter; iter = g_list_next(iter)) { + if (!GTK_IS_WINDOW(iter->data)) + continue; + + GtkWidget* child = gtk_bin_get_child(GTK_BIN(iter->data)); + if (!GTK_IS_MENU(child)) + continue; + + if (gtk_menu_get_attach_widget(GTK_MENU(child)) == GTK_WIDGET(m_webView)) + return GTK_MENU(child); + } + g_assert_not_reached(); + return 0; + } + + GtkMenuItem* getMenuItem(GtkMenu* menu, const gchar* itemLabel) + { + GOwnPtr<GList> items(gtk_container_get_children(GTK_CONTAINER(menu))); + for (GList* iter = items.get(); iter; iter = g_list_next(iter)) { + GtkMenuItem* child = GTK_MENU_ITEM(iter->data); + if (g_str_equal(itemLabel, gtk_menu_item_get_label(child))) + return child; + } + g_assert_not_reached(); + return 0; + } + + void activateMenuItem() + { + g_assert(m_itemToActivateLabel); + GtkMenu* menu = getPopupMenu(); + GtkMenuItem* item = getMenuItem(menu, m_itemToActivateLabel); + gtk_menu_shell_activate_item(GTK_MENU_SHELL(menu), GTK_WIDGET(item), TRUE); + m_itemToActivateLabel = 0; + quitMainLoop(); + } + + static gboolean activateMenuItemIdleCallback(gpointer userData) + { + ContextMenuCustomTest* test = static_cast<ContextMenuCustomTest*>(userData); + test->activateMenuItem(); + return FALSE; + } + + void activateCustomMenuItemAndWaitUntilActivated(const char* actionLabel) + { + m_activated = m_toggled = false; + m_itemToActivateLabel = actionLabel; + g_idle_add(activateMenuItemIdleCallback, this); + g_main_loop_run(m_mainLoop); + } + + void toggleCustomMenuItemAndWaitUntilToggled(const char* actionLabel) + { + activateCustomMenuItemAndWaitUntilActivated(actionLabel); + } + + static void actionActivatedCallback(GtkAction*, ContextMenuCustomTest* test) + { + test->m_activated = true; + } + + static void actionToggledCallback(GtkAction*, ContextMenuCustomTest* test) + { + test->m_toggled = true; + } + + void setAction(GtkAction* action) + { + m_action = action; + if (GTK_IS_TOGGLE_ACTION(action)) + g_signal_connect(action, "toggled", G_CALLBACK(actionToggledCallback), this); + else + g_signal_connect(action, "activate", G_CALLBACK(actionActivatedCallback), this); + } + + GRefPtr<GtkAction> m_action; + const char* m_itemToActivateLabel; + bool m_activated; + bool m_toggled; +}; + +static void testContextMenuPopulateMenu(ContextMenuCustomTest* test, gconstpointer) +{ + test->showInWindowAndWaitUntilMapped(); + + test->loadHtml("<html><body>WebKitGTK+ Context menu tests</body></html>", "file:///"); + test->waitUntilLoadFinished(); + + // Create a custom menu item. + GRefPtr<GtkAction> action = adoptGRef(gtk_action_new("WebKitGTK+CustomAction", "Custom _Action", 0, 0)); + test->setAction(action.get()); + test->showContextMenuAndWaitUntilFinished(); + test->activateCustomMenuItemAndWaitUntilActivated(gtk_action_get_label(action.get())); + g_assert(test->m_activated); + g_assert(!test->m_toggled); + + // Create a custom toggle menu item. + GRefPtr<GtkAction> toggleAction = adoptGRef(GTK_ACTION(gtk_toggle_action_new("WebKitGTK+CustomToggleAction", "Custom _Toggle Action", 0, 0))); + test->setAction(toggleAction.get()); + test->showContextMenuAndWaitUntilFinished(); + test->toggleCustomMenuItemAndWaitUntilToggled(gtk_action_get_label(toggleAction.get())); + g_assert(!test->m_activated); + g_assert(test->m_toggled); +} + +class ContextMenuCustomFullTest: public ContextMenuTest { +public: + MAKE_GLIB_TEST_FIXTURE(ContextMenuCustomFullTest); + + bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult*) + { + // Clear proposed menu and build our own. + webkit_context_menu_remove_all(contextMenu); + g_assert_cmpint(webkit_context_menu_get_n_items(contextMenu), ==, 0); + + // Add actions from stock. + webkit_context_menu_prepend(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_GO_BACK)); + webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD)); + webkit_context_menu_insert(contextMenu, webkit_context_menu_item_new_separator(), 2); + + // Add custom actions. + GRefPtr<GtkAction> action = adoptGRef(gtk_action_new("WebKitGTK+CustomAction", "Custom _Action", 0, 0)); + gtk_action_set_sensitive(action.get(), FALSE); + webkit_context_menu_insert(contextMenu, webkit_context_menu_item_new(action.get()), -1); + GRefPtr<GtkAction> toggleAction = adoptGRef(GTK_ACTION(gtk_toggle_action_new("WebKitGTK+CustomToggleAction", "Custom _Toggle Action", 0, 0))); + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(toggleAction.get()), TRUE); + webkit_context_menu_append(contextMenu, webkit_context_menu_item_new(toggleAction.get())); + webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); + + // Add a submenu. + GRefPtr<WebKitContextMenu> subMenu = adoptGRef(webkit_context_menu_new()); + assertObjectIsDeletedWhenTestFinishes(G_OBJECT(subMenu.get())); + webkit_context_menu_insert(subMenu.get(), webkit_context_menu_item_new_from_stock_action_with_label(WEBKIT_CONTEXT_MENU_ACTION_STOP, "Stop Load"), 0); + webkit_context_menu_insert(subMenu.get(), webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_RELOAD), -1); + webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_with_submenu("Load options", subMenu.get())); + webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator()); + + // Move Load submenu before custom actions. + webkit_context_menu_move_item(contextMenu, webkit_context_menu_last(contextMenu), 3); + webkit_context_menu_move_item(contextMenu, webkit_context_menu_last(contextMenu), 3); + + // If last item is a separator, remove it. + if (webkit_context_menu_item_is_separator(webkit_context_menu_last(contextMenu))) + webkit_context_menu_remove(contextMenu, webkit_context_menu_last(contextMenu)); + + // Check the menu. + GList* iter = webkit_context_menu_get_items(contextMenu); + + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_BACK, Visible | Enabled); + iter = checkCurrentItemIsStockActionAndGetNext(iter, WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD, Visible | Enabled); + iter = checkCurrentItemIsSeparatorAndGetNext(iter); + + GList* subMenuIter = 0; + iter = checkCurrentItemIsSubMenuAndGetNext(iter, "Load options", Visible | Enabled, &subMenuIter); + subMenuIter = checkCurrentItemIsStockActionAndGetNext(subMenuIter, WEBKIT_CONTEXT_MENU_ACTION_STOP, Visible | Enabled); + subMenuIter = checkCurrentItemIsStockActionAndGetNext(subMenuIter, WEBKIT_CONTEXT_MENU_ACTION_RELOAD, Visible | Enabled); + iter = checkCurrentItemIsSeparatorAndGetNext(iter); + + iter = checkCurrentItemIsCustomActionAndGetNext(iter, "Custom _Action", Visible); + iter = checkCurrentItemIsCustomActionAndGetNext(iter, "Custom _Toggle Action", Visible | Enabled | Checked); + g_assert(!iter); + + quitMainLoop(); + + return true; + } +}; + +static void testContextMenuCustomMenu(ContextMenuCustomFullTest* test, gconstpointer) +{ + test->showInWindowAndWaitUntilMapped(); + + test->loadHtml("<html><body>WebKitGTK+ Context menu tests</body></html>", "file:///"); + test->waitUntilLoadFinished(); + + test->showContextMenuAndWaitUntilFinished(); +} + +class ContextMenuDisabledTest: public ContextMenuTest { +public: + MAKE_GLIB_TEST_FIXTURE(ContextMenuDisabledTest); + + enum DisableMode { + IgnoreClicks, + IgnoreDefaultMenu + }; + + static gboolean buttonPressEventCallback(GtkWidget*, GdkEvent* event, ContextMenuDisabledTest* test) + { + if (event->button.button != 3) + return FALSE; + return test->rightButtonPressed(); + } + + ContextMenuDisabledTest() + : m_disableMode(IgnoreClicks) + { + g_signal_connect(m_webView, "button-press-event", G_CALLBACK(buttonPressEventCallback), this); + } + + bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult*) + { + if (m_disableMode == IgnoreClicks) + g_assert_not_reached(); + else + quitMainLoop(); + + return true; + } + + bool rightButtonPressed() + { + if (m_disableMode == IgnoreClicks) { + quitMainLoopAfterProcessingPendingEvents(); + return true; + } + return false; + } + + DisableMode m_disableMode; +}; + +static void testContextMenuDisableMenu(ContextMenuDisabledTest* test, gconstpointer) +{ + test->showInWindowAndWaitUntilMapped(); + + test->loadHtml("<html><body>WebKitGTK+ Context menu tests</body></html>", "file:///"); + test->waitUntilLoadFinished(); + + test->m_disableMode = ContextMenuDisabledTest::IgnoreDefaultMenu; + test->showContextMenuAndWaitUntilFinished(); + + test->m_disableMode = ContextMenuDisabledTest::IgnoreClicks; + test->showContextMenuAndWaitUntilFinished(); +} + +class ContextMenuSubmenuTest: public ContextMenuTest { +public: + MAKE_GLIB_TEST_FIXTURE(ContextMenuSubmenuTest); + + bool contextMenu(WebKitContextMenu* contextMenu, GdkEvent*, WebKitHitTestResult*) + { + size_t menuSize = webkit_context_menu_get_n_items(contextMenu); + GRefPtr<WebKitContextMenu> subMenu = adoptGRef(webkit_context_menu_new()); + webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_with_submenu("SubMenuItem", subMenu.get())); + g_assert_cmpuint(webkit_context_menu_get_n_items(contextMenu), ==, menuSize + 1); + + GRefPtr<WebKitContextMenu> subMenu2 = adoptGRef(webkit_context_menu_new()); + GRefPtr<WebKitContextMenuItem> item = webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK); + + // Add submenu to newly created item. + g_assert(!webkit_context_menu_item_get_submenu(item.get())); + webkit_context_menu_item_set_submenu(item.get(), subMenu2.get()); + g_assert(webkit_context_menu_item_get_submenu(item.get()) == subMenu2.get()); + + // Replace the submenu. + webkit_context_menu_item_set_submenu(item.get(), 0); + g_assert(!webkit_context_menu_item_get_submenu(item.get())); + + // Try to add a submenu already added to another item. + removeLogFatalFlag(G_LOG_LEVEL_WARNING); + webkit_context_menu_item_set_submenu(item.get(), subMenu.get()); + addLogFatalFlag(G_LOG_LEVEL_WARNING); + g_assert(!webkit_context_menu_item_get_submenu(item.get())); + + // A removed submenu shouldn't have a parent. + webkit_context_menu_item_set_submenu(item.get(), subMenu2.get()); + g_assert(webkit_context_menu_item_get_submenu(item.get()) == subMenu2.get()); + + quitMainLoop(); + + return true; + } +}; + +static void testContextMenuSubMenu(ContextMenuSubmenuTest* test, gconstpointer) +{ + test->showInWindowAndWaitUntilMapped(); + + test->loadHtml("<html><body>WebKitGTK+ Context menu tests</body></html>", "file:///"); + test->waitUntilLoadFinished(); + + test->showContextMenuAndWaitUntilFinished(); +} + +void beforeAll() +{ + ContextMenuDefaultTest::add("WebKitWebView", "default-menu", testContextMenuDefaultMenu); + ContextMenuCustomTest::add("WebKitWebView", "populate-menu", testContextMenuPopulateMenu); + ContextMenuCustomFullTest::add("WebKitWebView", "custom-menu", testContextMenuCustomMenu); + ContextMenuDisabledTest::add("WebKitWebView", "disable-menu", testContextMenuDisableMenu); + ContextMenuSubmenuTest::add("WebKitWebView", "submenu", testContextMenuSubMenu); +} + +void afterAll() +{ +} diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/TestMain.h b/Source/WebKit2/UIProcess/API/gtk/tests/TestMain.h index 219cb44ed..6929c3595 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/TestMain.h +++ b/Source/WebKit2/UIProcess/API/gtk/tests/TestMain.h @@ -75,6 +75,20 @@ public: return resourcesDir.get(); } + void addLogFatalFlag(unsigned flag) + { + unsigned fatalMask = g_log_set_always_fatal(static_cast<GLogLevelFlags>(G_LOG_FATAL_MASK)); + fatalMask |= flag; + g_log_set_always_fatal(static_cast<GLogLevelFlags>(fatalMask)); + } + + void removeLogFatalFlag(unsigned flag) + { + unsigned fatalMask = g_log_set_always_fatal(static_cast<GLogLevelFlags>(G_LOG_FATAL_MASK)); + fatalMask &= ~flag; + g_log_set_always_fatal(static_cast<GLogLevelFlags>(fatalMask)); + } + HashSet<GObject*> m_watchedObjects; }; diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitFindController.cpp b/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitFindController.cpp index ae9ff2f7a..a185db8a7 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitFindController.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitFindController.cpp @@ -324,8 +324,6 @@ static void testFindControllerHide(FindControllerTest* test, gconstpointer) g_assert(highlightPixbuf); g_assert(!gdkPixbufEqual(originalPixbuf.get(), highlightPixbuf.get())); -#if (0) - // Requires http://webkit.org/b/77747 to be fixed WebKitFindController* findController = webkit_web_view_get_find_controller(test->m_webView); webkit_find_controller_search_finish(findController); webkit_web_view_execute_editing_command(test->m_webView, "Unselect"); @@ -334,7 +332,6 @@ static void testFindControllerHide(FindControllerTest* test, gconstpointer) GRefPtr<GdkPixbuf> unhighlightPixbuf = gdk_pixbuf_get_from_window(webViewGdkWindow, 0, 0, allocatedHeight, allocatedWidth); g_assert(unhighlightPixbuf); g_assert(gdkPixbufEqual(originalPixbuf.get(), unhighlightPixbuf.get())); -#endif } static void testFindControllerInstance(FindControllerTest* test, gconstpointer) diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitSettings.cpp b/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitSettings.cpp index 4616d105f..2cebdd995 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitSettings.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitSettings.cpp @@ -199,6 +199,11 @@ static void testWebKitSettings(Test*, gconstpointer) webkit_settings_set_enable_webgl(settings, TRUE); g_assert(webkit_settings_get_enable_webgl(settings)); + // Allow Modal Dialogs is disabled by default. + g_assert(!webkit_settings_get_allow_modal_dialogs(settings)); + webkit_settings_set_allow_modal_dialogs(settings, TRUE); + g_assert(webkit_settings_get_allow_modal_dialogs(settings)); + // Zoom text only is disabled by default. g_assert(!webkit_settings_get_zoom_text_only(settings)); webkit_settings_set_zoom_text_only(settings, TRUE); diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebView.cpp b/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebView.cpp index 646752974..3e194a179 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebView.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebView.cpp @@ -103,6 +103,7 @@ public: enum WebViewEvents { Create, ReadyToShow, + RunAsModal, Close }; @@ -178,46 +179,19 @@ public: test->m_windowPropertiesChanged.add(g_param_spec_get_name(paramSpec)); } - static void viewClose(WebKitWebView* webView, UIClientTest* test) + static GtkWidget* viewCreateCallback(WebKitWebView* webView, UIClientTest* test) { - g_assert(webView != test->m_webView); - - test->m_webViewEvents.append(Close); - g_object_unref(webView); - - g_main_loop_quit(test->m_mainLoop); + return test->viewCreate(webView); } - static void viewReadyToShow(WebKitWebView* webView, UIClientTest* test) + static void viewReadyToShowCallback(WebKitWebView* webView, UIClientTest* test) { - g_assert(webView != test->m_webView); - - WebKitWindowProperties* windowProperties = webkit_web_view_get_window_properties(webView); - g_assert(windowProperties); - WindowProperties(windowProperties).assertEqual(test->m_windowProperties); - - test->m_webViewEvents.append(ReadyToShow); + test->viewReadyToShow(webView); } - static GtkWidget* viewCreate(WebKitWebView* webView, UIClientTest* test) + static void viewCloseCallback(WebKitWebView* webView, UIClientTest* test) { - g_assert(webView == test->m_webView); - - GtkWidget* newWebView = webkit_web_view_new_with_context(webkit_web_view_get_context(webView)); - g_object_ref_sink(newWebView); - - test->m_webViewEvents.append(Create); - - WebKitWindowProperties* windowProperties = webkit_web_view_get_window_properties(WEBKIT_WEB_VIEW(newWebView)); - g_assert(windowProperties); - test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(windowProperties)); - test->m_windowPropertiesChanged.clear(); - g_signal_connect(windowProperties, "notify", G_CALLBACK(windowPropertiesNotifyCallback), test); - - g_signal_connect(newWebView, "ready-to-show", G_CALLBACK(viewReadyToShow), test); - g_signal_connect(newWebView, "close", G_CALLBACK(viewClose), test); - - return newWebView; + test->viewClose(webView); } void scriptAlert(WebKitScriptDialog* dialog) @@ -300,7 +274,7 @@ public: , m_mouseTargetModifiers(0) { webkit_settings_set_javascript_can_open_windows_automatically(webkit_web_view_get_settings(m_webView), TRUE); - g_signal_connect(m_webView, "create", G_CALLBACK(viewCreate), this); + g_signal_connect(m_webView, "create", G_CALLBACK(viewCreateCallback), this); g_signal_connect(m_webView, "script-dialog", G_CALLBACK(scriptDialog), this); g_signal_connect(m_webView, "mouse-target-changed", G_CALLBACK(mouseTargetChanged), this); g_signal_connect(m_webView, "permission-request", G_CALLBACK(permissionRequested), this); @@ -328,6 +302,48 @@ public: return m_mouseTargetHitTestResult.get(); } + virtual GtkWidget* viewCreate(WebKitWebView* webView) + { + g_assert(webView == m_webView); + + GtkWidget* newWebView = webkit_web_view_new_with_context(webkit_web_view_get_context(webView)); + g_object_ref_sink(newWebView); + + m_webViewEvents.append(Create); + + WebKitWindowProperties* windowProperties = webkit_web_view_get_window_properties(WEBKIT_WEB_VIEW(newWebView)); + g_assert(windowProperties); + assertObjectIsDeletedWhenTestFinishes(G_OBJECT(windowProperties)); + m_windowPropertiesChanged.clear(); + + g_signal_connect(windowProperties, "notify", G_CALLBACK(windowPropertiesNotifyCallback), this); + g_signal_connect(newWebView, "ready-to-show", G_CALLBACK(viewReadyToShowCallback), this); + g_signal_connect(newWebView, "close", G_CALLBACK(viewCloseCallback), this); + + return newWebView; + } + + virtual void viewReadyToShow(WebKitWebView* webView) + { + g_assert(webView != m_webView); + + WebKitWindowProperties* windowProperties = webkit_web_view_get_window_properties(webView); + g_assert(windowProperties); + WindowProperties(windowProperties).assertEqual(m_windowProperties); + + m_webViewEvents.append(ReadyToShow); + } + + virtual void viewClose(WebKitWebView* webView) + { + g_assert(webView != m_webView); + + m_webViewEvents.append(Close); + g_object_unref(webView); + + g_main_loop_quit(m_mainLoop); + } + Vector<WebViewEvents> m_webViewEvents; WebKitScriptDialogType m_scriptDialogType; bool m_scriptDialogConfirmed; @@ -358,6 +374,62 @@ static gboolean checkMimeTypeForFilter(GtkFileFilter* filter, const gchar* mimeT return gtk_file_filter_filter(filter, &filterInfo); } +class ModalDialogsTest: public UIClientTest { +public: + MAKE_GLIB_TEST_FIXTURE(ModalDialogsTest); + + static void dialogRunAsModalCallback(WebKitWebView* webView, ModalDialogsTest* test) + { + g_assert(webView != test->m_webView); + test->m_webViewEvents.append(RunAsModal); + } + + GtkWidget* viewCreate(WebKitWebView* webView) + { + g_assert(webView == m_webView); + + GtkWidget* newWebView = UIClientTest::viewCreate(webView); + g_signal_connect(newWebView, "run-as-modal", G_CALLBACK(dialogRunAsModalCallback), this); + return newWebView; + } + + void viewReadyToShow(WebKitWebView* webView) + { + g_assert(webView != m_webView); + m_webViewEvents.append(ReadyToShow); + } +}; + +static void testWebViewAllowModalDialogs(ModalDialogsTest* test, gconstpointer) +{ + WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView); + webkit_settings_set_allow_modal_dialogs(settings, TRUE); + + test->loadHtml("<html><body onload=\"window.showModalDialog('data:text/html,<html><body/><script>window.close();</script></html>')\"></body></html>", 0); + test->waitUntilMainLoopFinishes(); + + Vector<UIClientTest::WebViewEvents>& events = test->m_webViewEvents; + g_assert_cmpint(events.size(), ==, 4); + g_assert_cmpint(events[0], ==, UIClientTest::Create); + g_assert_cmpint(events[1], ==, UIClientTest::ReadyToShow); + g_assert_cmpint(events[2], ==, UIClientTest::RunAsModal); + g_assert_cmpint(events[3], ==, UIClientTest::Close); +} + +static void testWebViewDisallowModalDialogs(ModalDialogsTest* test, gconstpointer) +{ + WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView); + webkit_settings_set_allow_modal_dialogs(settings, FALSE); + + test->loadHtml("<html><body onload=\"window.showModalDialog('data:text/html,<html><body/><script>window.close();</script></html>')\"></body></html>", 0); + // We need to use a timeout here because the viewClose() function + // won't ever be called as the dialog won't be created. + test->wait(1); + + Vector<UIClientTest::WebViewEvents>& events = test->m_webViewEvents; + g_assert_cmpint(events.size(), ==, 0); +} + static void testWebViewJavaScriptDialogs(UIClientTest* test, gconstpointer) { static const char* htmlOnLoadFormat = "<html><body onLoad=\"%s\"></body></html>"; @@ -483,6 +555,10 @@ static void testWebViewMouseTarget(UIClientTest* test, gconstpointer) static void testWebViewPermissionRequests(UIClientTest* test, gconstpointer) { + // Some versions of geoclue give a runtime warning because it tries + // to register the error quark twice. See https://bugs.webkit.org/show_bug.cgi?id=89858. + // Make warnings non-fatal for this test to make it pass. + test->removeLogFatalFlag(G_LOG_LEVEL_WARNING); test->showInWindowAndWaitUntilMapped(); static const char* geolocationRequestHTML = "<html>" @@ -515,6 +591,7 @@ static void testWebViewPermissionRequests(UIClientTest* test, gconstpointer) // Check that we did not get the PERMISSION_DENIED error now. result = webkit_web_view_get_title(test->m_webView); g_assert_cmpstr(result, !=, "1"); + test->addLogFatalFlag(G_LOG_LEVEL_WARNING); } static void testWebViewZoomLevel(WebViewTest* test, gconstpointer) @@ -795,6 +872,8 @@ void beforeAll() WebViewTest::add("WebKitWebView", "settings", testWebViewSettings); WebViewTest::add("WebKitWebView", "replace-content", testWebViewReplaceContent); UIClientTest::add("WebKitWebView", "create-ready-close", testWebViewCreateReadyClose); + ModalDialogsTest::add("WebKitWebView", "allow-modal-dialogs", testWebViewAllowModalDialogs); + ModalDialogsTest::add("WebKitWebView", "disallow-modal-dialogs", testWebViewDisallowModalDialogs); UIClientTest::add("WebKitWebView", "javascript-dialogs", testWebViewJavaScriptDialogs); UIClientTest::add("WebKitWebView", "window-properties", testWebViewWindowProperties); UIClientTest::add("WebKitWebView", "mouse-target", testWebViewMouseTarget); diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.cpp b/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.cpp index e355f786d..321b6a37a 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.cpp @@ -43,12 +43,6 @@ WebViewTest::~WebViewTest() g_main_loop_unref(m_mainLoop); } -static gboolean testLoadTimeoutFinishLoop(GMainLoop* loop) -{ - g_main_loop_quit(loop); - return FALSE; -} - void WebViewTest::loadURI(const char* uri) { m_activeURI = uri; @@ -112,9 +106,27 @@ void WebViewTest::goToBackForwardListItem(WebKitBackForwardListItem* item) webkit_web_view_go_to_back_forward_list_item(m_webView, item); } +void WebViewTest::quitMainLoop() +{ + g_main_loop_quit(m_mainLoop); +} + +void WebViewTest::quitMainLoopAfterProcessingPendingEvents() +{ + while (gtk_events_pending()) + gtk_main_iteration(); + quitMainLoop(); +} + +static gboolean quitMainLoopIdleCallback(WebViewTest* test) +{ + test->quitMainLoop(); + return FALSE; +} + void WebViewTest::wait(double seconds) { - g_timeout_add_seconds(seconds, reinterpret_cast<GSourceFunc>(testLoadTimeoutFinishLoop), m_mainLoop); + g_timeout_add_seconds(seconds, reinterpret_cast<GSourceFunc>(quitMainLoopIdleCallback), this); g_main_loop_run(m_mainLoop); } diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.h b/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.h index ff6a8c737..8e469f142 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.h +++ b/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.h @@ -40,6 +40,8 @@ public: void goForward(); void goToBackForwardListItem(WebKitBackForwardListItem*); + void quitMainLoop(); + void quitMainLoopAfterProcessingPendingEvents(); void wait(double seconds); void waitUntilLoadFinished(); void waitUntilTitleChangedTo(const char* expectedTitle); diff --git a/Source/WebKit2/UIProcess/API/gtk/webkit2.h b/Source/WebKit2/UIProcess/API/gtk/webkit2.h index bf37fcb73..58ac2b7e9 100644 --- a/Source/WebKit2/UIProcess/API/gtk/webkit2.h +++ b/Source/WebKit2/UIProcess/API/gtk/webkit2.h @@ -25,6 +25,9 @@ #include <webkit2/WebKitBackForwardList.h> #include <webkit2/WebKitBackForwardListItem.h> +#include <webkit2/WebKitContextMenu.h> +#include <webkit2/WebKitContextMenuActions.h> +#include <webkit2/WebKitContextMenuItem.h> #include <webkit2/WebKitCookieManager.h> #include <webkit2/WebKitDefines.h> #include <webkit2/WebKitDownload.h> diff --git a/Source/WebKit2/UIProcess/API/gtk/webkit2marshal.list b/Source/WebKit2/UIProcess/API/gtk/webkit2marshal.list index de3032819..e6c8a1016 100644 --- a/Source/WebKit2/UIProcess/API/gtk/webkit2marshal.list +++ b/Source/WebKit2/UIProcess/API/gtk/webkit2marshal.list @@ -1,6 +1,7 @@ BOOLEAN:BOXED BOOLEAN:ENUM,STRING,POINTER BOOLEAN:OBJECT +BOOLEAN:OBJECT,BOXED,OBJECT BOOLEAN:OBJECT,ENUM BOOLEAN:STRING BOOLEAN:VOID diff --git a/Source/WebKit2/UIProcess/API/mac/PageClientImpl.h b/Source/WebKit2/UIProcess/API/mac/PageClientImpl.h index ac074e8cc..8af6ff40c 100644 --- a/Source/WebKit2/UIProcess/API/mac/PageClientImpl.h +++ b/Source/WebKit2/UIProcess/API/mac/PageClientImpl.h @@ -94,6 +94,10 @@ private: virtual PassRefPtr<WebPopupMenuProxy> createPopupMenuProxy(WebPageProxy*); virtual PassRefPtr<WebContextMenuProxy> createContextMenuProxy(WebPageProxy*); +#if ENABLE(INPUT_TYPE_COLOR) + virtual PassRefPtr<WebColorChooserProxy> createColorChooserProxy(WebPageProxy*, const WebCore::Color& initialColor); +#endif + void setFindIndicator(PassRefPtr<FindIndicator>, bool fadeOut, bool animate); virtual void enterAcceleratedCompositingMode(const LayerTreeContext&); diff --git a/Source/WebKit2/UIProcess/API/mac/PageClientImpl.mm b/Source/WebKit2/UIProcess/API/mac/PageClientImpl.mm index 8d0913e52..3bd702078 100644 --- a/Source/WebKit2/UIProcess/API/mac/PageClientImpl.mm +++ b/Source/WebKit2/UIProcess/API/mac/PageClientImpl.mm @@ -360,6 +360,14 @@ PassRefPtr<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPagePr return WebContextMenuProxyMac::create(m_wkView, page); } +#if ENABLE(INPUT_TYPE_COLOR) +PassRefPtr<WebColorChooserProxy> PageClientImpl::createColorChooserProxy(WebPageProxy*, const WebCore::Color&) +{ + notImplemented(); + return 0; +} +#endif + void PageClientImpl::setFindIndicator(PassRefPtr<FindIndicator> findIndicator, bool fadeOut, bool animate) { [m_wkView _setFindIndicator:findIndicator fadeOut:fadeOut animate:animate]; diff --git a/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp b/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp index c52da4df6..046d80339 100644 --- a/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp +++ b/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp @@ -266,6 +266,7 @@ QQuickWebViewPrivate::QQuickWebViewPrivate(QQuickWebView* viewport) , proxyAuthenticationDialog(0) , filePicker(0) , databaseQuotaDialog(0) + , colorChooser(0) , m_useDefaultContentItemSize(true) , m_navigatorQtObjectEnabled(false) , m_renderToOffscreenBuffer(false) @@ -1146,6 +1147,22 @@ void QQuickWebViewExperimental::setDatabaseQuotaDialog(QQmlComponent* databaseQu emit databaseQuotaDialogChanged(); } +QQmlComponent* QQuickWebViewExperimental::colorChooser() const +{ + Q_D(const QQuickWebView); + return d->colorChooser; +} + +void QQuickWebViewExperimental::setColorChooser(QQmlComponent* colorChooser) +{ + Q_D(QQuickWebView); + if (d->colorChooser == colorChooser) + return; + + d->colorChooser = colorChooser; + emit colorChooserChanged(); +} + QString QQuickWebViewExperimental::userAgent() const { Q_D(const QQuickWebView); diff --git a/Source/WebKit2/UIProcess/API/qt/qquickwebview_p.h b/Source/WebKit2/UIProcess/API/qt/qquickwebview_p.h index b00e12e4b..e2c8c0dad 100644 --- a/Source/WebKit2/UIProcess/API/qt/qquickwebview_p.h +++ b/Source/WebKit2/UIProcess/API/qt/qquickwebview_p.h @@ -265,6 +265,7 @@ class QWEBKIT_EXPORT QQuickWebViewExperimental : public QObject { Q_PROPERTY(QQmlComponent* itemSelector READ itemSelector WRITE setItemSelector NOTIFY itemSelectorChanged) Q_PROPERTY(QQmlComponent* filePicker READ filePicker WRITE setFilePicker NOTIFY filePickerChanged) Q_PROPERTY(QQmlComponent* databaseQuotaDialog READ databaseQuotaDialog WRITE setDatabaseQuotaDialog NOTIFY databaseQuotaDialogChanged) + Q_PROPERTY(QQmlComponent* colorChooser READ colorChooser WRITE setColorChooser NOTIFY colorChooserChanged) Q_PROPERTY(QWebPreferences* preferences READ preferences CONSTANT FINAL) Q_PROPERTY(QWebKitTest* test READ test CONSTANT FINAL) @@ -300,6 +301,8 @@ public: void setFilePicker(QQmlComponent*); QQmlComponent* databaseQuotaDialog() const; void setDatabaseQuotaDialog(QQmlComponent*); + QQmlComponent* colorChooser() const; + void setColorChooser(QQmlComponent*); QString userAgent() const; void setUserAgent(const QString& userAgent); int deviceWidth() const; @@ -356,6 +359,7 @@ Q_SIGNALS: void itemSelectorChanged(); void filePickerChanged(); void databaseQuotaDialogChanged(); + void colorChooserChanged(); void downloadRequested(QWebDownloadItem* downloadItem); void permissionRequested(QWebPermissionRequest* permission); void messageReceived(const QVariantMap& message); diff --git a/Source/WebKit2/UIProcess/API/qt/qquickwebview_p_p.h b/Source/WebKit2/UIProcess/API/qt/qquickwebview_p_p.h index c5535a3c8..f102f6030 100644 --- a/Source/WebKit2/UIProcess/API/qt/qquickwebview_p_p.h +++ b/Source/WebKit2/UIProcess/API/qt/qquickwebview_p_p.h @@ -185,6 +185,7 @@ protected: QQmlComponent* proxyAuthenticationDialog; QQmlComponent* filePicker; QQmlComponent* databaseQuotaDialog; + QQmlComponent* colorChooser; QList<QUrl> userScripts; diff --git a/Source/WebKit2/UIProcess/API/qt/tests/qmltests/WebView/tst_colorChooser.qml b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/WebView/tst_colorChooser.qml new file mode 100644 index 000000000..366e7c00c --- /dev/null +++ b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/WebView/tst_colorChooser.qml @@ -0,0 +1,94 @@ +import QtQuick 2.0 +import QtTest 1.0 +import QtWebKit 3.0 +import QtWebKit.experimental 1.0 +import "../common" + +TestWebView { + id: webView + + width: 400 + height: 400 + + property bool featureEnabled + + property string selectedColor + property bool shouldReject + property bool shouldAcceptCurrent + + experimental.colorChooser: Item { + Component.onCompleted: { + if (WebView.view.shouldReject) + model.reject() + else if (WebView.view.shouldAcceptCurrent) + model.accept(model.currentColor) + else + model.accept(WebView.view.selectedColor) + } + } + + function openColorChooser() { + webView.experimental.test.touchTap(webView, 25, 25) + } + + SignalSpy { + id: titleSpy + target: webView + signalName: "titleChanged" + } + + TestCase { + id: test + name: "WebViewColorChooser" + when: windowShown + + function init() { + webView.url = Qt.resolvedUrl("../common/colorChooser.html") + verify(webView.waitForLoadSucceeded()) + + webView.featureEnabled = (webView.title == "Feature enabled") + + titleSpy.clear() + + webView.shouldReject = false; + webView.shouldAcceptCurrent = false; + } + + function test_accept() { + if (!webView.featureEnabled) + return + + // The title changes here twice: first + // when we click, it changes from "Feature enabled" + // to the sanitized color and next, when we + // pick a new color with the chooser. + webView.selectedColor = "#020020" + openColorChooser() + titleSpy.wait() + compare(titleSpy.count, 2) + compare(webView.title, "#020020") + } + + function test_currentValue() { + if (!webView.featureEnabled) + return + + webView.shouldAcceptCurrent = true + openColorChooser() + titleSpy.wait() + compare(titleSpy.count, 1) + compare(webView.title, "#000000") + } + + function test_reject() { + if (!webView.featureEnabled) + return + + webView.shouldReject = true; + openColorChooser() + titleSpy.wait() + compare(titleSpy.count, 1) + compare(webView.title, "#000000") + } + } +} diff --git a/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/colorChooser.html b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/colorChooser.html new file mode 100644 index 000000000..b04710ab9 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/colorChooser.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<title>Feature disabled</title> +<script> +function detectInputTypeColorEnabled() { + var element = document.getElementById('test') + element.value = 'should sanitize'; + if (element.value != 'should sanitize') + document.title = 'Feature enabled'; +} +function updateTitle(element) { + document.title = element.value; +} +</script> +</head> +<body onload='detectInputTypeColorEnabled()'> +<input id='test' type='color' onclick='updateTitle(this)' onchange='updateTitle(this)' style='width:50px; height:50px; position:"absolute"; top:0px; left:0px'> +</html> |