Title: [218325] trunk
Revision
218325
Author
carlo...@webkit.org
Date
2017-06-15 02:41:27 -0700 (Thu, 15 Jun 2017)

Log Message

[GTK] Add API to allow overriding popup menus
https://bugs.webkit.org/show_bug.cgi?id=172905

Reviewed by Michael Catanzaro.

Source/WebKit2:

The GTK+ API uses GTK+ for the default implementation of several UI elements like the file chooser, print dialog,
color picker, context menu, etc. but in all those cases it allows to override the default implementation. It's
not possible to override the popup menu used for select elements. This patch adds WebKitOptionMenu to represent
a select dropdown menu. It's passed as an argument of the new signal WebKitWebView::show-option-menu, and
contains WebKitOptionMenuItem elements representing the items to be displayed.

* PlatformGTK.cmake:
* UIProcess/API/gtk/PageClientImpl.cpp:
(WebKit::PageClientImpl::createPopupMenuProxy): Create a WebKitPopupMenu.
* UIProcess/API/gtk/WebKitOptionMenu.cpp: Added.
(webkitOptionMenuCreate):
(webkit_option_menu_get_n_items):
(webkit_option_menu_get_item):
(webkit_option_menu_select_item):
(webkit_option_menu_activate_item):
(webkit_option_menu_close):
* UIProcess/API/gtk/WebKitOptionMenu.h: Added.
* UIProcess/API/gtk/WebKitOptionMenuItem.cpp: Added.
(webkit_option_menu_item_copy):
(webkit_option_menu_item_free):
(webkit_option_menu_item_get_label):
(webkit_option_menu_item_get_tooltip):
(webkit_option_menu_item_is_group_label):
(webkit_option_menu_item_is_group_child):
(webkit_option_menu_item_is_enabled):
(webkit_option_menu_item_is_selected):
* UIProcess/API/gtk/WebKitOptionMenuItem.h: Added.
* UIProcess/API/gtk/WebKitOptionMenuItemPrivate.h: Added.
(_WebKitOptionMenuItem::_WebKitOptionMenuItem):
* UIProcess/API/gtk/WebKitOptionMenuPrivate.h: Added.
* UIProcess/API/gtk/WebKitPopupMenu.cpp: Added.
(WebKit::WebKitPopupMenu::WebKitPopupMenu):
(WebKit::menuCloseCallback):
(WebKit::WebKitPopupMenu::showPopupMenu): Call webkitWebViewShowOptionMenu() falling back to default
implementation if the user didn't handle the signal.
(WebKit::WebKitPopupMenu::hidePopupMenu):
(WebKit::WebKitPopupMenu::cancelTracking):
(WebKit::WebKitPopupMenu::selectItem):
(WebKit::WebKitPopupMenu::activateItem):
* UIProcess/API/gtk/WebKitPopupMenu.h: Added.
* UIProcess/API/gtk/WebKitWebView.cpp:
(webkit_web_view_class_init):
(webkitWebViewShowOptionMenu): Emit WebKitWebView::show-option-menu.
* UIProcess/API/gtk/WebKitWebView.h:
* UIProcess/API/gtk/WebKitWebViewPrivate.h:
* UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt: Add new symbols.
* UIProcess/API/gtk/docs/webkit2gtk-4.0.types: Add new get_type functions.
* UIProcess/API/gtk/docs/webkit2gtk-docs.sgml: Add new sections.
* UIProcess/API/gtk/webkit2.h: Add new public headers.
* UIProcess/gtk/WebPopupMenuProxyGtk.cpp:
(WebKit::WebPopupMenuProxyGtk::WebPopupMenuProxyGtk): Do not create the GtkMenu in constructor.
(WebKit::WebPopupMenuProxyGtk::showPopupMenu): Create the GtkMenu and connect to the signals here.
(WebKit::WebPopupMenuProxyGtk::hidePopupMenu): Return early if the Gtk hasn't been shown.
* UIProcess/gtk/WebPopupMenuProxyGtk.h: Make constructor and webview protected.

Tools:

Add a unit test to check the new API.

* TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt:
* TestWebKitAPI/Tests/WebKit2Gtk/TestOptionMenu.cpp: Added.
(OptionMenuTest::OptionMenuTest):
(OptionMenuTest::~OptionMenuTest):
(OptionMenuTest::destroyMenu):
(OptionMenuTest::showOptionMenuCallback):
(OptionMenuTest::menuCloseCallback):
(OptionMenuTest::showOptionMenu):
(OptionMenuTest::clickAtPositionAndWaitUntilOptionMenuShown):
(OptionMenuTest::close):
(OptionMenuTest::activateItem):
(OptionMenuTest::selectItem):
(testOptionMenuSimple):
(testOptionMenuGroups):
(testOptionMenuActivate):
(testOptionMenuSelect):
(beforeAll):
(afterAll):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (218324 => 218325)


--- trunk/Source/WebKit2/ChangeLog	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/ChangeLog	2017-06-15 09:41:27 UTC (rev 218325)
@@ -1,3 +1,65 @@
+2017-06-15  Carlos Garcia Campos  <cgar...@igalia.com>
+
+        [GTK] Add API to allow overriding popup menus
+        https://bugs.webkit.org/show_bug.cgi?id=172905
+
+        Reviewed by Michael Catanzaro.
+
+        The GTK+ API uses GTK+ for the default implementation of several UI elements like the file chooser, print dialog,
+        color picker, context menu, etc. but in all those cases it allows to override the default implementation. It's
+        not possible to override the popup menu used for select elements. This patch adds WebKitOptionMenu to represent
+        a select dropdown menu. It's passed as an argument of the new signal WebKitWebView::show-option-menu, and
+        contains WebKitOptionMenuItem elements representing the items to be displayed.
+
+        * PlatformGTK.cmake:
+        * UIProcess/API/gtk/PageClientImpl.cpp:
+        (WebKit::PageClientImpl::createPopupMenuProxy): Create a WebKitPopupMenu.
+        * UIProcess/API/gtk/WebKitOptionMenu.cpp: Added.
+        (webkitOptionMenuCreate):
+        (webkit_option_menu_get_n_items):
+        (webkit_option_menu_get_item):
+        (webkit_option_menu_select_item):
+        (webkit_option_menu_activate_item):
+        (webkit_option_menu_close):
+        * UIProcess/API/gtk/WebKitOptionMenu.h: Added.
+        * UIProcess/API/gtk/WebKitOptionMenuItem.cpp: Added.
+        (webkit_option_menu_item_copy):
+        (webkit_option_menu_item_free):
+        (webkit_option_menu_item_get_label):
+        (webkit_option_menu_item_get_tooltip):
+        (webkit_option_menu_item_is_group_label):
+        (webkit_option_menu_item_is_group_child):
+        (webkit_option_menu_item_is_enabled):
+        (webkit_option_menu_item_is_selected):
+        * UIProcess/API/gtk/WebKitOptionMenuItem.h: Added.
+        * UIProcess/API/gtk/WebKitOptionMenuItemPrivate.h: Added.
+        (_WebKitOptionMenuItem::_WebKitOptionMenuItem):
+        * UIProcess/API/gtk/WebKitOptionMenuPrivate.h: Added.
+        * UIProcess/API/gtk/WebKitPopupMenu.cpp: Added.
+        (WebKit::WebKitPopupMenu::WebKitPopupMenu):
+        (WebKit::menuCloseCallback):
+        (WebKit::WebKitPopupMenu::showPopupMenu): Call webkitWebViewShowOptionMenu() falling back to default
+        implementation if the user didn't handle the signal.
+        (WebKit::WebKitPopupMenu::hidePopupMenu):
+        (WebKit::WebKitPopupMenu::cancelTracking):
+        (WebKit::WebKitPopupMenu::selectItem):
+        (WebKit::WebKitPopupMenu::activateItem):
+        * UIProcess/API/gtk/WebKitPopupMenu.h: Added.
+        * UIProcess/API/gtk/WebKitWebView.cpp:
+        (webkit_web_view_class_init):
+        (webkitWebViewShowOptionMenu): Emit WebKitWebView::show-option-menu.
+        * UIProcess/API/gtk/WebKitWebView.h:
+        * UIProcess/API/gtk/WebKitWebViewPrivate.h:
+        * UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt: Add new symbols.
+        * UIProcess/API/gtk/docs/webkit2gtk-4.0.types: Add new get_type functions.
+        * UIProcess/API/gtk/docs/webkit2gtk-docs.sgml: Add new sections.
+        * UIProcess/API/gtk/webkit2.h: Add new public headers.
+        * UIProcess/gtk/WebPopupMenuProxyGtk.cpp:
+        (WebKit::WebPopupMenuProxyGtk::WebPopupMenuProxyGtk): Do not create the GtkMenu in constructor.
+        (WebKit::WebPopupMenuProxyGtk::showPopupMenu): Create the GtkMenu and connect to the signals here.
+        (WebKit::WebPopupMenuProxyGtk::hidePopupMenu): Return early if the Gtk hasn't been shown.
+        * UIProcess/gtk/WebPopupMenuProxyGtk.h: Make constructor and webview protected.
+
 2017-06-14  Carlos Garcia Campos  <cgar...@igalia.com>
 
         [GTK] Use API::InjectedBundle::ResourceLoadClient in WebKitWebPage

Modified: trunk/Source/WebKit2/PlatformGTK.cmake (218324 => 218325)


--- trunk/Source/WebKit2/PlatformGTK.cmake	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/PlatformGTK.cmake	2017-06-15 09:41:27 UTC (rev 218325)
@@ -212,6 +212,12 @@
     UIProcess/API/gtk/WebKitNotificationPrivate.h
     UIProcess/API/gtk/WebKitNotificationProvider.cpp
     UIProcess/API/gtk/WebKitNotificationProvider.h
+    UIProcess/API/gtk/WebKitOptionMenu.cpp
+    UIProcess/API/gtk/WebKitOptionMenu.h
+    UIProcess/API/gtk/WebKitOptionMenuPrivate.h
+    UIProcess/API/gtk/WebKitOptionMenuItem.cpp
+    UIProcess/API/gtk/WebKitOptionMenuItem.h
+    UIProcess/API/gtk/WebKitOptionMenuItemPrivate.h
     UIProcess/API/gtk/WebKitPermissionRequest.cpp
     UIProcess/API/gtk/WebKitPermissionRequest.h
     UIProcess/API/gtk/WebKitPlugin.cpp
@@ -222,6 +228,7 @@
     UIProcess/API/gtk/WebKitPolicyDecision.cpp
     UIProcess/API/gtk/WebKitPolicyDecision.h
     UIProcess/API/gtk/WebKitPolicyDecisionPrivate.h
+    UIProcess/API/gtk/WebKitPopupMenu.cpp
     UIProcess/API/gtk/WebKitPrintCustomWidget.cpp
     UIProcess/API/gtk/WebKitPrintCustomWidget.h
     UIProcess/API/gtk/WebKitPrintCustomWidgetPrivate.h
@@ -560,6 +567,8 @@
     ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitNetworkProxySettings.h
     ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitNotificationPermissionRequest.h
     ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitNotification.h
+    ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitOptionMenu.h
+    ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitOptionMenuItem.h
     ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitPermissionRequest.h
     ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitPlugin.h
     ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitPolicyDecision.h

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp (218324 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp	2017-06-15 09:41:27 UTC (rev 218325)
@@ -37,10 +37,10 @@
 #include "WebContextMenuProxyGtk.h"
 #include "WebEventFactory.h"
 #include "WebKitColorChooser.h"
+#include "WebKitPopupMenu.h"
 #include "WebKitWebViewBasePrivate.h"
 #include "WebKitWebViewPrivate.h"
 #include "WebPageProxy.h"
-#include "WebPopupMenuProxyGtk.h"
 #include "WebProcessPool.h"
 #include <WebCore/CairoUtilities.h>
 #include <WebCore/Cursor.h>
@@ -206,7 +206,7 @@
 
 RefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy& page)
 {
-    return WebPopupMenuProxyGtk::create(m_viewWidget, page);
+    return WebKitPopupMenu::create(m_viewWidget, page);
 }
 
 RefPtr<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPageProxy& page, const ContextMenuContextData& context, const UserData& userData)

Added: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenu.cpp (0 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenu.cpp	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenu.cpp	2017-06-15 09:41:27 UTC (rev 218325)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2017 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 "WebKitOptionMenu.h"
+
+#include "WebKitOptionMenuItemPrivate.h"
+#include "WebKitOptionMenuPrivate.h"
+#include "WebKitPrivate.h"
+
+using namespace WebKit;
+
+/**
+ * SECTION: WebKitOptionMenu
+ * @Short_description:
+ * @Title: WebKitOptionMenu
+ *
+ * WebKitOptionMenu represents the dropdown menu of a select element in a #WebKitWebView.
+ *
+ * When a select element in a #WebKitWebView needs to display a dropdown menu, the signal
+ * #WebKitWebView::show-option-menu is emitted, providing a WebKitOptionMenu with the
+ * #WebKitOptionMenuItem<!-- -->s that should be displayed.
+ *
+ * Since: 2.18
+ */
+
+struct _WebKitOptionMenuPrivate {
+    Vector<WebKitOptionMenuItem> items;
+    RefPtr<WebKitPopupMenu> popupMenu;
+};
+
+enum {
+    CLOSE,
+
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+WEBKIT_DEFINE_TYPE(WebKitOptionMenu, webkit_option_menu, G_TYPE_OBJECT)
+
+static void webkit_option_menu_class_init(WebKitOptionMenuClass* optionMenuClass)
+{
+    /**
+     * WebKitOptionMenu::close:
+     * @menu: the #WebKitOptionMenu on which the signal is emitted
+     *
+     * Emitted when closing a #WebKitOptionMenu is requested. This can happen
+     * when the user explicitly calls webkit_option_menu_close() or when the
+     * element is detached from the current page.
+     *
+     * Since: 2.18
+     */
+    signals[CLOSE] =
+        g_signal_new("close",
+            G_TYPE_FROM_CLASS(optionMenuClass),
+            G_SIGNAL_RUN_LAST,
+            0, nullptr, nullptr,
+            g_cclosure_marshal_VOID__VOID,
+            G_TYPE_NONE, 0);
+}
+
+WebKitOptionMenu* webkitOptionMenuCreate(WebKitPopupMenu& popupMenu, const Vector<WebPopupItem>& items, int32_t selectedIndex)
+{
+    auto* menu = WEBKIT_OPTION_MENU(g_object_new(WEBKIT_TYPE_OPTION_MENU, nullptr));
+    menu->priv->popupMenu = &popupMenu;
+    menu->priv->items.reserveInitialCapacity(items.size());
+    for (const auto& item : items)
+        menu->priv->items.uncheckedAppend(WebKitOptionMenuItem(item));
+    if (selectedIndex >= 0) {
+        ASSERT(static_cast<unsigned>(selectedIndex) < menu->priv->items.size());
+        menu->priv->items[selectedIndex].isSelected = true;
+    }
+    return menu;
+}
+
+/**
+ * webkit_option_menu_get_n_items:
+ * @menu: a #WebKitOptionMenu
+ *
+ * Gets the length of the @menu.
+ *
+ * Returns: the number of #WebKitOptionMenuItem<!-- -->s in @menu
+ *
+ * Since: 2.18
+ */
+guint webkit_option_menu_get_n_items(WebKitOptionMenu* menu)
+{
+    g_return_val_if_fail(WEBKIT_IS_OPTION_MENU(menu), 0);
+
+    return menu->priv->items.size();
+}
+
+/**
+ * webkit_option_menu_get_item:
+ * @menu: a #WebKitOptionMenu
+ * @index: the index of the item
+ *
+ * Returns the #WebKitOptionMenuItem at @index in @menu.
+ *
+ * Returns: (transfer none): a #WebKitOptionMenuItem of @menu.
+ *
+ * Since: 2.18
+ */
+WebKitOptionMenuItem* webkit_option_menu_get_item(WebKitOptionMenu* menu, guint index)
+{
+    g_return_val_if_fail(WEBKIT_IS_OPTION_MENU(menu), nullptr);
+    g_return_val_if_fail(index < menu->priv->items.size(), nullptr);
+
+    return &menu->priv->items[index];
+}
+
+/**
+ * webkit_option_menu_select_item:
+ * @menu: a #WebKitOptionMenu
+ * @index: the index of the item
+ *
+ * Selects the #WebKitOptionMenuItem at @index in @menu. Selecting an item changes the
+ * text shown by the combo button, but it doesn't change the value of the element. You need to
+ * explicitly activate the item with webkit_option_menu_select_item() or close the menu with
+ * webkit_option_menu_close() in which case the currently selected item will be activated.
+ *
+ * Since: 2.18
+ */
+void webkit_option_menu_select_item(WebKitOptionMenu* menu, guint index)
+{
+    g_return_if_fail(WEBKIT_IS_OPTION_MENU(menu));
+    g_return_if_fail(index < menu->priv->items.size());
+
+    menu->priv->popupMenu->selectItem(index);
+}
+
+/**
+ * webkit_option_menu_activate_item:
+ * @menu: a #WebKitOptionMenu
+ * @index: the index of the item
+ *
+ * Activates the #WebKitOptionMenuItem at @index in @menu. Activating an item changes the value
+ * of the element making the item the active one. You are expected to close the menu with
+ * webkit_option_menu_close() after activating an item, calling this function again will have no
+ * effect.
+ *
+ * Since: 2.18
+ */
+void webkit_option_menu_activate_item(WebKitOptionMenu* menu, guint index)
+{
+    g_return_if_fail(WEBKIT_IS_OPTION_MENU(menu));
+    g_return_if_fail(index < menu->priv->items.size());
+
+    menu->priv->popupMenu->activateItem(index);
+}
+
+/**
+ * webkit_option_menu_close:
+ * @menu: a #WebKitOptionMenu
+ *
+ * Request to close a #WebKitOptionMenu. This emits WebKitOptionMenu::close signal.
+ * This function should always be called to notify WebKit that the associated
+ * menu has been closed. If the menu is closed and neither webkit_option_menu_select_item()
+ * nor webkit_option_menu_activate_item() have been called, the element value remains
+ * unchanged.
+ *
+ * Since: 2.18
+ */
+void webkit_option_menu_close(WebKitOptionMenu* menu)
+{
+    g_return_if_fail(WEBKIT_IS_OPTION_MENU(menu));
+
+    g_signal_emit(menu, signals[CLOSE], 0, nullptr);
+}

Added: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenu.h (0 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenu.h	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenu.h	2017-06-15 09:41:27 UTC (rev 218325)
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 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) && !defined(__WEBKIT_WEB_EXTENSION_H_INSIDE__)
+#error "Only <webkit2/webkit2.h> can be included directly."
+#endif
+
+#ifndef WebKitOptionMenu_h
+#define WebKitOptionMenu_h
+
+#include <glib-object.h>
+#include <webkit2/WebKitDefines.h>
+#include <webkit2/WebKitOptionMenuItem.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_OPTION_MENU            (webkit_option_menu_get_type())
+#define WEBKIT_OPTION_MENU(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_OPTION_MENU, WebKitOptionMenu))
+#define WEBKIT_IS_OPTION_MENU(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_OPTION_MENU))
+#define WEBKIT_OPTION_MENU_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  WEBKIT_TYPE_OPTION_MENU, WebKitOptionMenuClass))
+#define WEBKIT_IS_OPTION_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  WEBKIT_TYPE_OPTION_MENU))
+#define WEBKIT_OPTION_MENU_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  WEBKIT_TYPE_OPTION_MENU, WebKitOptionMenuClass))
+
+typedef struct _WebKitOptionMenu        WebKitOptionMenu;
+typedef struct _WebKitOptionMenuClass   WebKitOptionMenuClass;
+typedef struct _WebKitOptionMenuPrivate WebKitOptionMenuPrivate;
+
+struct _WebKitOptionMenu {
+    GObject parent;
+
+    WebKitOptionMenuPrivate *priv;
+};
+
+struct _WebKitOptionMenuClass {
+    GObjectClass parent_class;
+
+    void (*_webkit_reserved0) (void);
+    void (*_webkit_reserved1) (void);
+    void (*_webkit_reserved2) (void);
+    void (*_webkit_reserved3) (void);
+};
+
+WEBKIT_API GType
+webkit_option_menu_get_type       (void);
+
+WEBKIT_API guint
+webkit_option_menu_get_n_items    (WebKitOptionMenu *menu);
+
+WEBKIT_API WebKitOptionMenuItem *
+webkit_option_menu_get_item       (WebKitOptionMenu *menu,
+                                   guint             index);
+
+WEBKIT_API void
+webkit_option_menu_select_item    (WebKitOptionMenu *menu,
+                                   guint             index);
+
+WEBKIT_API void
+webkit_option_menu_activate_item  (WebKitOptionMenu *menu,
+                                   guint             index);
+
+WEBKIT_API void
+webkit_option_menu_close          (WebKitOptionMenu *menu);
+
+G_END_DECLS
+
+#endif

Added: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuItem.cpp (0 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuItem.cpp	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuItem.cpp	2017-06-15 09:41:27 UTC (rev 218325)
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2017 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 "WebKitOptionMenuItem.h"
+
+#include "WebKitOptionMenuItemPrivate.h"
+
+using namespace WebKit;
+
+/**
+ * SECTION: WebKitOptionMenuItem
+ * @Short_description: One item of the #WebKitOptionMenu
+ * @Title: WebKitOptionMenuItem
+ *
+ * The #WebKitOptionMenu is composed of WebKitOptionMenuItem<!-- -->s.
+ * A WebKitOptionMenuItem always has a label and can contain a tooltip text.
+ * You can use the WebKitOptionMenuItem of a #WebKitOptionMenu to build your
+ * own menus.
+ *
+ * Since: 2.18
+ */
+
+G_DEFINE_BOXED_TYPE(WebKitOptionMenuItem, webkit_option_menu_item, webkit_option_menu_item_copy, webkit_option_menu_item_free)
+
+/**
+ * webkit_option_menu_item_copy:
+ * @item: a #WebKitOptionMenuItem
+ *
+ * Make a copy of the #WebKitOptionMenuItem.
+ *
+ * Returns: (transfer full): A copy of passed in #WebKitOptionMenuItem
+ *
+ * Since: 2.18
+ */
+WebKitOptionMenuItem* webkit_option_menu_item_copy(WebKitOptionMenuItem* item)
+{
+    g_return_val_if_fail(item, nullptr);
+
+    auto* copyItem = static_cast<WebKitOptionMenuItem*>(fastMalloc(sizeof(WebKitOptionMenuItem)));
+    new (copyItem) WebKitOptionMenuItem(item);
+    return copyItem;
+}
+
+/**
+ * webkit_option_menu_item_free:
+ * @item: A #WebKitOptionMenuItem
+ *
+ * Free the #WebKitOptionMenuItem.
+ *
+ * Since: 2.18
+ */
+void webkit_option_menu_item_free(WebKitOptionMenuItem* item)
+{
+    g_return_if_fail(item);
+
+    item->~WebKitOptionMenuItem();
+    fastFree(item);
+}
+
+/**
+ * webkit_option_menu_item_get_label:
+ * @item: a #WebKitOptionMenuItem
+ *
+ * Get the label of a #WebKitOptionMenuItem.
+ *
+ * Returns: The label of @item.
+ *
+ * Since: 2.18
+ */
+const gchar* webkit_option_menu_item_get_label(WebKitOptionMenuItem* item)
+{
+    g_return_val_if_fail(item, nullptr);
+
+    return item->label.data();
+}
+
+/**
+ * webkit_option_menu_item_get_tooltip:
+ * @item: a #WebKitOptionMenuItem
+ *
+ * Get the tooltip of a #WebKitOptionMenuItem.
+ *
+ * Returns: The tooltip of @item, or %NULL.
+ *
+ * Since: 2.18
+ */
+const gchar* webkit_option_menu_item_get_tooltip(WebKitOptionMenuItem* item)
+{
+    g_return_val_if_fail(item, nullptr);
+
+    return item->tooltip.isNull() ? nullptr : item->tooltip.data();
+}
+
+/**
+ * webkit_option_menu_item_is_group_label:
+ * @item: a #WebKitOptionMenuItem
+ *
+ * Whether a #WebKitOptionMenuItem is a group label.
+ *
+ * Returns: %TRUE if the @item is a group label or %FALSE otherwise.
+ *
+ * Since: 2.18
+ */
+gboolean webkit_option_menu_item_is_group_label(WebKitOptionMenuItem* item)
+{
+    g_return_val_if_fail(item, FALSE);
+
+    return item->isGroupLabel;
+}
+
+/**
+ * webkit_option_menu_item_is_group_child:
+ * @item: a #WebKitOptionMenuItem
+ *
+ * Whether a #WebKitOptionMenuItem is a group child.
+ *
+ * Returns: %TRUE if the @item is a group child or %FALSE otherwise.
+ *
+ * Since: 2.18
+ */
+gboolean webkit_option_menu_item_is_group_child(WebKitOptionMenuItem* item)
+{
+    g_return_val_if_fail(item, FALSE);
+
+    return item->isGroupChild;
+}
+
+/**
+ * webkit_option_menu_item_is_enabled:
+ * @item: a #WebKitOptionMenuItem
+ *
+ * Whether a #WebKitOptionMenuItem is enabled.
+ *
+ * Returns: %TRUE if the @item is enabled or %FALSE otherwise.
+ *
+ * Since: 2.18
+ */
+gboolean webkit_option_menu_item_is_enabled(WebKitOptionMenuItem* item)
+{
+    g_return_val_if_fail(item, FALSE);
+
+    return item->isEnabled;
+}
+
+/**
+ * webkit_option_menu_item_is_selected:
+ * @item: a #WebKitOptionMenuItem
+ *
+ * Whether a #WebKitOptionMenuItem is the currently selected one.
+ *
+ * Returns: %TRUE if the @item is selected or %FALSE otherwise.
+ *
+ * Since: 2.18
+ */
+gboolean webkit_option_menu_item_is_selected(WebKitOptionMenuItem* item)
+{
+    g_return_val_if_fail(item, FALSE);
+
+    return item->isSelected;
+}

Added: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuItem.h (0 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuItem.h	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuItem.h	2017-06-15 09:41:27 UTC (rev 218325)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 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 WebKitOptionMenuItem_h
+#define WebKitOptionMenuItem_h
+
+#include <glib-object.h>
+#include <webkit2/WebKitDefines.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_OPTION_MENU_ITEM (webkit_option_menu_item_get_type())
+
+typedef struct _WebKitOptionMenuItem WebKitOptionMenuItem;
+
+WEBKIT_API GType
+webkit_option_menu_item_get_type       (void);
+
+WEBKIT_API WebKitOptionMenuItem *
+webkit_option_menu_item_copy           (WebKitOptionMenuItem *item);
+
+WEBKIT_API void
+webkit_option_menu_item_free           (WebKitOptionMenuItem *item);
+
+WEBKIT_API const gchar *
+webkit_option_menu_item_get_label      (WebKitOptionMenuItem *item);
+
+WEBKIT_API const gchar *
+webkit_option_menu_item_get_tooltip    (WebKitOptionMenuItem *item);
+
+WEBKIT_API gboolean
+webkit_option_menu_item_is_group_label (WebKitOptionMenuItem *item);
+
+WEBKIT_API gboolean
+webkit_option_menu_item_is_group_child (WebKitOptionMenuItem *item);
+
+WEBKIT_API gboolean
+webkit_option_menu_item_is_enabled     (WebKitOptionMenuItem *item);
+
+WEBKIT_API gboolean
+webkit_option_menu_item_is_selected    (WebKitOptionMenuItem *item);
+
+G_END_DECLS
+
+#endif

Added: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuItemPrivate.h (0 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuItemPrivate.h	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuItemPrivate.h	2017-06-15 09:41:27 UTC (rev 218325)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include "WebKitOptionMenuItem.h"
+#include "WebPopupItem.h"
+#include <wtf/text/CString.h>
+
+struct _WebKitOptionMenuItem {
+    _WebKitOptionMenuItem() = default;
+
+    _WebKitOptionMenuItem(const WebKit::WebPopupItem& item)
+        : label(item.m_text.stripWhiteSpace().utf8())
+        , isGroupLabel(item.m_isLabel)
+        , isGroupChild(item.m_text.startsWith("    "))
+        , isEnabled(item.m_isEnabled)
+    {
+        if (!item.m_toolTip.isEmpty())
+            tooltip = item.m_toolTip.utf8();
+    }
+
+    explicit _WebKitOptionMenuItem(_WebKitOptionMenuItem* other)
+        : label(other->label)
+        , tooltip(other->tooltip)
+        , isGroupLabel(other->isGroupLabel)
+        , isGroupChild(other->isGroupChild)
+        , isEnabled(other->isEnabled)
+        , isSelected(other->isSelected)
+    {
+    }
+
+    CString label;
+    CString tooltip;
+    bool isGroupLabel { false };
+    bool isGroupChild { false };
+    bool isEnabled { true };
+    bool isSelected { false };
+};

Added: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuPrivate.h (0 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuPrivate.h	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitOptionMenuPrivate.h	2017-06-15 09:41:27 UTC (rev 218325)
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include "WebKitOptionMenu.h"
+#include "WebKitPopupMenu.h"
+
+WebKitOptionMenu* webkitOptionMenuCreate(WebKit::WebKitPopupMenu&, const Vector<WebKit::WebPopupItem>&, int32_t selectedIndex);

Added: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitPopupMenu.cpp (0 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitPopupMenu.cpp	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitPopupMenu.cpp	2017-06-15 09:41:27 UTC (rev 218325)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 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 "WebKitPopupMenu.h"
+
+#include "NativeWebMouseEvent.h"
+#include "WebKitOptionMenuPrivate.h"
+#include "WebKitWebViewPrivate.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+WebKitPopupMenu::WebKitPopupMenu(GtkWidget* webView, WebPopupMenuProxy::Client& client)
+    : WebPopupMenuProxyGtk(webView, client)
+{
+}
+
+static void menuCloseCallback(WebKitPopupMenu* popupMenu)
+{
+    popupMenu->activateItem(-1);
+}
+
+void WebKitPopupMenu::showPopupMenu(const IntRect& rect, TextDirection direction, double pageScaleFactor, const Vector<WebPopupItem>& items, const PlatformPopupMenuData& platformData, int32_t selectedIndex)
+{
+    GRefPtr<WebKitOptionMenu> menu = adoptGRef(webkitOptionMenuCreate(*this, items, selectedIndex));
+    const GdkEvent* event = m_client->currentlyProcessedMouseDownEvent() ? m_client->currentlyProcessedMouseDownEvent()->nativeEvent() : nullptr;
+    if (webkitWebViewShowOptionMenu(WEBKIT_WEB_VIEW(m_webView), rect, menu.get(), event)) {
+        m_menu = WTFMove(menu);
+        g_signal_connect_swapped(m_menu.get(), "close", G_CALLBACK(menuCloseCallback), this);
+    } else
+        WebPopupMenuProxyGtk::showPopupMenu(rect, direction, pageScaleFactor, items, platformData, selectedIndex);
+}
+
+void WebKitPopupMenu::hidePopupMenu()
+{
+    if (!m_menu) {
+        WebPopupMenuProxyGtk::hidePopupMenu();
+        return;
+    }
+    g_signal_handlers_disconnect_matched(m_menu.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
+    webkit_option_menu_close(m_menu.get());
+}
+
+void WebKitPopupMenu::cancelTracking()
+{
+    if (!m_menu) {
+        WebPopupMenuProxyGtk::cancelTracking();
+        return;
+    }
+    hidePopupMenu();
+    m_menu = nullptr;
+}
+
+void WebKitPopupMenu::selectItem(unsigned itemIndex)
+{
+    if (!m_menu)
+        return;
+    m_client->setTextFromItemForPopupMenu(this, itemIndex);
+    m_selectedItem = itemIndex;
+}
+
+void WebKitPopupMenu::activateItem(int32_t itemIndex)
+{
+    if (!m_menu)
+        return;
+    m_client->valueChangedForPopupMenu(this, itemIndex == -1 ? m_selectedItem.value_or(-1) : itemIndex);
+    g_signal_handlers_disconnect_matched(m_menu.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
+    m_menu = nullptr;
+}
+
+} // namespace WebKit

Added: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitPopupMenu.h (0 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitPopupMenu.h	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitPopupMenu.h	2017-06-15 09:41:27 UTC (rev 218325)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include "WebPopupMenuProxyGtk.h"
+#include <wtf/glib/GRefPtr.h>
+
+typedef struct _WebKitOptionMenu WebKitOptionMenu;
+
+namespace WebKit {
+
+class WebKitPopupMenu final : public WebPopupMenuProxyGtk {
+public:
+    static Ref<WebKitPopupMenu> create(GtkWidget* webView, WebPopupMenuProxy::Client& client)
+    {
+        return adoptRef(*new WebKitPopupMenu(webView, client));
+    }
+    ~WebKitPopupMenu() = default;
+
+    void selectItem(unsigned);
+    void activateItem(int32_t);
+
+private:
+    WebKitPopupMenu(GtkWidget*, WebPopupMenuProxy::Client&);
+
+    void showPopupMenu(const WebCore::IntRect&, WebCore::TextDirection, double pageScaleFactor, const Vector<WebPopupItem>&, const PlatformPopupMenuData&, int32_t selectedIndex) override;
+    void hidePopupMenu() override;
+    void cancelTracking() override;
+
+    GRefPtr<WebKitOptionMenu> m_menu;
+    std::optional<unsigned> m_selectedItem;
+};
+
+} // namespace WebKit

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp (218324 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp	2017-06-15 09:41:27 UTC (rev 218325)
@@ -137,6 +137,8 @@
 
     RUN_COLOR_CHOOSER,
 
+    SHOW_OPTION_MENU,
+
     LAST_SIGNAL
 };
 
@@ -1883,6 +1885,40 @@
         g_cclosure_marshal_generic,
         G_TYPE_BOOLEAN, 1,
         WEBKIT_TYPE_COLOR_CHOOSER_REQUEST);
+
+    /**
+     * WebKitWebView::show-option-menu:
+     * @web_view: the #WebKitWebView on which the signal is emitted
+     * @menu: the #WebKitOptionMenu
+     * @event: the #GdkEvent that triggered the menu, or %NULL
+     * @rectangle: the option element area
+     *
+     * This signal is emitted when a select element in @web_view needs to display a
+     * dropdown menu. This signal can be used to show a custom menu, using @menu to get
+     * the details of all items that should be displayed. The area of the element in the
+     * #WebKitWebView is given as @rectangle parameter, it can be used to position the
+     * menu. If this was triggered by a user interaction, like a mouse click,
+     * @event parameter provides the #GdkEvent.
+     * To handle this signal asynchronously you should keep a ref of the @menu.
+     *
+     * The default signal handler will pop up a #GtkMenu.
+     *
+     * Returns: %TRUE to stop other handlers from being invoked for the event.
+     *   %FALSE to propagate the event further.
+     *
+     * Since: 2.18.
+     */
+    signals[SHOW_OPTION_MENU] = g_signal_new(
+        "show-option-menu",
+        G_TYPE_FROM_CLASS(webViewClass),
+        G_SIGNAL_RUN_LAST,
+        G_STRUCT_OFFSET(WebKitWebViewClass, show_option_menu),
+        g_signal_accumulator_true_handled, nullptr,
+        g_cclosure_marshal_generic,
+        G_TYPE_BOOLEAN, 3,
+        WEBKIT_TYPE_OPTION_MENU,
+        GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
+        GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE);
 }
 
 static void webkitWebViewCancelAuthenticationRequest(WebKitWebView* webView)
@@ -2212,6 +2248,14 @@
     return webView->priv->websiteDataManager.get();
 }
 
+bool webkitWebViewShowOptionMenu(WebKitWebView* webView, const IntRect& rect, WebKitOptionMenu* menu, const GdkEvent* event)
+{
+    GdkRectangle menuRect = rect;
+    gboolean handled;
+    g_signal_emit(webView, signals[SHOW_OPTION_MENU], 0, menu, event, &menuRect, &handled);
+    return handled;
+}
+
 /**
  * webkit_web_view_new:
  *

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h (218324 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h	2017-06-15 09:41:27 UTC (rev 218325)
@@ -42,6 +42,7 @@
 #include <webkit2/WebKitJavascriptResult.h>
 #include <webkit2/WebKitNavigationAction.h>
 #include <webkit2/WebKitNotification.h>
+#include <webkit2/WebKitOptionMenu.h>
 #include <webkit2/WebKitPermissionRequest.h>
 #include <webkit2/WebKitPolicyDecision.h>
 #include <webkit2/WebKitScriptDialog.h>
@@ -249,11 +250,13 @@
                                                 WebKitNotification          *notification);
     gboolean   (* run_color_chooser)           (WebKitWebView               *web_view,
                                                 WebKitColorChooserRequest   *request);
+    gboolean   (* show_option_menu)            (WebKitWebView               *web_view,
+                                                GdkRectangle                *rectangle,
+                                                WebKitOptionMenu            *menu);
 
     void (*_webkit_reserved0) (void);
     void (*_webkit_reserved1) (void);
     void (*_webkit_reserved2) (void);
-    void (*_webkit_reserved3) (void);
 };
 
 WEBKIT_API GType

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h (218324 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h	2017-06-15 09:41:27 UTC (rev 218325)
@@ -34,6 +34,7 @@
 #include "WebKitPrivate.h"
 #include "WebKitWebView.h"
 #include "WebPageProxy.h"
+#include <WebCore/IntRect.h>
 #include <wtf/text/CString.h>
 
 void webkitWebViewCreatePage(WebKitWebView*, Ref<API::PageConfiguration>&&);
@@ -72,3 +73,4 @@
 void webkitWebViewSelectionDidChange(WebKitWebView*);
 void webkitWebViewRequestInstallMissingMediaPlugins(WebKitWebView*, WebKit::InstallMissingMediaPluginsPermissionRequest&);
 WebKitWebsiteDataManager* webkitWebViewGetWebsiteDataManager(WebKitWebView*);
+bool webkitWebViewShowOptionMenu(WebKitWebView*, const WebCore::IntRect&, WebKitOptionMenu*, const GdkEvent*);

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt (218324 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt	2017-06-15 09:41:27 UTC (rev 218325)
@@ -1176,6 +1176,48 @@
 </SECTION>
 
 <SECTION>
+<FILE>WebKitOptionMenu</FILE>
+WebKitOptionMenu
+webkit_option_menu_get_n_items
+webkit_option_menu_get_item
+webkit_option_menu_select_item
+webkit_option_menu_activate_item
+webkit_option_menu_close
+
+<SUBSECTION Standard>
+WebKitOptionMenuClass
+WEBKIT_TYPE_OPTION_MENU
+WEBKIT_OPTION_MENU
+WEBKIT_IS_OPTION_MENU
+WEBKIT_OPTION_MENU_CLASS
+WEBKIT_IS_OPTION_MENU_CLASS
+WEBKIT_OPTION_MENU_GET_CLASS
+
+<SUBSECTION Private>
+WebKitOptionMenuPrivate
+webkit_option_menu_get_type
+</SECTION>
+
+<SECTION>
+<FILE>WebKitOptionMenuItem</FILE>
+WebKitOptionMenuItem
+webkit_option_menu_item_copy
+webkit_option_menu_item_free
+webkit_option_menu_item_get_label
+webkit_option_menu_item_get_tooltip
+webkit_option_menu_item_is_group_label
+webkit_option_menu_item_is_group_child
+webkit_option_menu_item_is_enabled
+webkit_option_menu_item_is_selected
+
+<SUBSECTION Standard>
+WEBKIT_TYPE_OPTION_MENU_ITEM
+
+<SUBSECTION Private>
+webkit_option_menu_item_get_type
+</SECTION>
+
+<SECTION>
 <FILE>WebKitFormSubmissionRequest</FILE>
 WebKitFormSubmissionRequest
 webkit_form_submission_request_get_text_fields

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0.types (218324 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0.types	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0.types	2017-06-15 09:41:27 UTC (rev 218325)
@@ -36,3 +36,5 @@
 webkit_web_view_session_state_get_type
 webkit_print_custom_widget_get_type
 webkit_automation_session_get_type
+webkit_option_menu_get_type
+webkit_option_menu_item_get_type

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml (218324 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml	2017-06-15 09:41:27 UTC (rev 218325)
@@ -46,6 +46,8 @@
     <xi:include href=""
     <xi:include href=""
     <xi:include href=""
+    <xi:include href=""
+    <xi:include href=""
     <xi:include href=""
     <xi:include href=""
     <xi:include href=""

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/webkit2.h (218324 => 218325)


--- trunk/Source/WebKit2/UIProcess/API/gtk/webkit2.h	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/webkit2.h	2017-06-15 09:41:27 UTC (rev 218325)
@@ -57,6 +57,8 @@
 #include <webkit2/WebKitNetworkProxySettings.h>
 #include <webkit2/WebKitNotification.h>
 #include <webkit2/WebKitNotificationPermissionRequest.h>
+#include <webkit2/WebKitOptionMenu.h>
+#include <webkit2/WebKitOptionMenuItem.h>
 #include <webkit2/WebKitPermissionRequest.h>
 #include <webkit2/WebKitPlugin.h>
 #include <webkit2/WebKitPrintCustomWidget.h>

Modified: trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp (218324 => 218325)


--- trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.cpp	2017-06-15 09:41:27 UTC (rev 218325)
@@ -41,11 +41,8 @@
 WebPopupMenuProxyGtk::WebPopupMenuProxyGtk(GtkWidget* webView, WebPopupMenuProxy::Client& client)
     : WebPopupMenuProxy(client)
     , m_webView(webView)
-    , m_popup(gtk_menu_new())
     , m_dismissMenuTimer(RunLoop::main(), this, &WebPopupMenuProxyGtk::dismissMenuTimerFired)
 {
-    g_signal_connect(m_popup, "key-press-event", G_CALLBACK(keyPressEventCallback), this);
-    g_signal_connect(m_popup, "unmap", G_CALLBACK(menuUnmappedCallback), this);
 }
 
 WebPopupMenuProxyGtk::~WebPopupMenuProxyGtk()
@@ -88,7 +85,10 @@
 
 void WebPopupMenuProxyGtk::showPopupMenu(const IntRect& rect, TextDirection, double /* pageScaleFactor */, const Vector<WebPopupItem>& items, const PlatformPopupMenuData&, int32_t selectedIndex)
 {
-    m_dismissMenuTimer.stop();
+    ASSERT(!m_popup);
+    m_popup = gtk_menu_new();
+    g_signal_connect(m_popup, "key-press-event", G_CALLBACK(keyPressEventCallback), this);
+    g_signal_connect(m_popup, "unmap", G_CALLBACK(menuUnmappedCallback), this);
 
     populatePopupMenu(items);
     gtk_menu_set_active(GTK_MENU(m_popup), selectedIndex);
@@ -178,6 +178,9 @@
 
 void WebPopupMenuProxyGtk::hidePopupMenu()
 {
+    if (!m_popup)
+        return;
+
     gtk_menu_popdown(GTK_MENU(m_popup));
     resetTypeAheadFindState();
 }

Modified: trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h (218324 => 218325)


--- trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Source/WebKit2/UIProcess/gtk/WebPopupMenuProxyGtk.h	2017-06-15 09:41:27 UTC (rev 218325)
@@ -48,9 +48,12 @@
     void hidePopupMenu() override;
     void cancelTracking() override;
 
-private:
+protected:
     WebPopupMenuProxyGtk(GtkWidget*, WebPopupMenuProxy::Client&);
 
+    GtkWidget* m_webView { nullptr };
+
+private:
     void setCurrentlySelectedMenuItem(GtkWidget* item) { m_currentlySelectedMenuItem = item; }
     GtkAction* createGtkActionForMenuItem(const WebPopupItem&, int itemIndex);
     void populatePopupMenu(const Vector<WebPopupItem>&);
@@ -64,7 +67,6 @@
     static gboolean keyPressEventCallback(GtkWidget*, GdkEventKey*, WebPopupMenuProxyGtk*);
     static void menuUnmappedCallback(GtkWidget*, WebPopupMenuProxyGtk*);
 
-    GtkWidget* m_webView { nullptr };
     GtkWidget* m_popup { nullptr };
 
     RunLoop::Timer<WebPopupMenuProxyGtk> m_dismissMenuTimer;

Modified: trunk/Tools/ChangeLog (218324 => 218325)


--- trunk/Tools/ChangeLog	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Tools/ChangeLog	2017-06-15 09:41:27 UTC (rev 218325)
@@ -1,3 +1,31 @@
+2017-06-15  Carlos Garcia Campos  <cgar...@igalia.com>
+
+        [GTK] Add API to allow overriding popup menus
+        https://bugs.webkit.org/show_bug.cgi?id=172905
+
+        Reviewed by Michael Catanzaro.
+
+        Add a unit test to check the new API.
+
+        * TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt:
+        * TestWebKitAPI/Tests/WebKit2Gtk/TestOptionMenu.cpp: Added.
+        (OptionMenuTest::OptionMenuTest):
+        (OptionMenuTest::~OptionMenuTest):
+        (OptionMenuTest::destroyMenu):
+        (OptionMenuTest::showOptionMenuCallback):
+        (OptionMenuTest::menuCloseCallback):
+        (OptionMenuTest::showOptionMenu):
+        (OptionMenuTest::clickAtPositionAndWaitUntilOptionMenuShown):
+        (OptionMenuTest::close):
+        (OptionMenuTest::activateItem):
+        (OptionMenuTest::selectItem):
+        (testOptionMenuSimple):
+        (testOptionMenuGroups):
+        (testOptionMenuActivate):
+        (testOptionMenuSelect):
+        (beforeAll):
+        (afterAll):
+
 2017-06-15  Fujii Hironori  <hironori.fu...@sony.com>
 
         [WinCairo] DumpRenderTree.cpp: error C3861: 'CFURLCacheCreate': identifier not found

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt (218324 => 218325)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt	2017-06-15 09:19:50 UTC (rev 218324)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt	2017-06-15 09:41:27 UTC (rev 218325)
@@ -114,6 +114,7 @@
 ADD_WK2_TEST(TestInspectorServer TestInspectorServer.cpp)
 ADD_WK2_TEST(TestLoaderClient TestLoaderClient.cpp)
 ADD_WK2_TEST(TestMultiprocess TestMultiprocess.cpp)
+ADD_WK2_TEST(TestOptionMenu TestOptionMenu.cpp)
 ADD_WK2_TEST(TestPrinting TestPrinting.cpp)
 ADD_WK2_TEST(TestResources TestResources.cpp)
 ADD_WK2_TEST(TestSSL TestSSL.cpp)

Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestOptionMenu.cpp (0 => 218325)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestOptionMenu.cpp	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestOptionMenu.cpp	2017-06-15 09:41:27 UTC (rev 218325)
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2017 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/RunLoop.h>
+
+class OptionMenuTest : public WebViewTest {
+public:
+    MAKE_GLIB_TEST_FIXTURE(OptionMenuTest);
+
+    OptionMenuTest()
+    {
+        g_signal_connect(m_webView, "show-option-menu", G_CALLBACK(showOptionMenuCallback), this);
+    }
+
+    ~OptionMenuTest()
+    {
+        g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+        if (m_menu)
+            close();
+    }
+
+    void destroyMenu()
+    {
+        if (!m_menu)
+            return;
+
+        g_signal_handlers_disconnect_matched(m_menu.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+        m_menu = nullptr;
+    }
+
+    static gboolean showOptionMenuCallback(WebKitWebView* webView, WebKitOptionMenu* menu, GdkEvent* event, GdkRectangle* rect, OptionMenuTest* test)
+    {
+        g_assert(test->m_webView == webView);
+        g_assert(rect);
+        g_assert(WEBKIT_IS_OPTION_MENU(menu));
+        test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(menu));
+        test->showOptionMenu(menu, rect);
+        return TRUE;
+    }
+
+    static void menuCloseCallback(WebKitOptionMenu* menu, OptionMenuTest* test)
+    {
+        g_assert(test->m_menu.get() == menu);
+        test->destroyMenu();
+    }
+
+    void showOptionMenu(WebKitOptionMenu* menu, GdkRectangle* rect)
+    {
+        m_rectangle = *rect;
+        m_menu = menu;
+        g_signal_connect(m_menu.get(), "close", G_CALLBACK(menuCloseCallback), this);
+        g_main_loop_quit(m_mainLoop);
+    }
+
+    void clickAtPositionAndWaitUntilOptionMenuShown(int x, int y)
+    {
+        m_menu = nullptr;
+        RunLoop::main().dispatch([this, x, y] { clickMouseButton(x, y); });
+        g_main_loop_run(m_mainLoop);
+    }
+
+    void close()
+    {
+        g_assert(m_menu.get());
+        webkit_option_menu_close(m_menu.get());
+        g_assert(!m_menu.get());
+    }
+
+    void activateItem(unsigned item)
+    {
+        g_assert(m_menu.get());
+        webkit_option_menu_activate_item(m_menu.get(), item);
+        g_assert(m_menu.get());
+    }
+
+    void selectItem(unsigned item)
+    {
+        g_assert(m_menu.get());
+        webkit_option_menu_select_item(m_menu.get(), item);
+        g_assert(m_menu.get());
+    }
+
+    GRefPtr<WebKitOptionMenu> m_menu;
+    GdkRectangle m_rectangle;
+};
+
+static void testOptionMenuSimple(OptionMenuTest* test, gconstpointer)
+{
+    static const char html[] =
+        "<html><body>"
+        "  <select style='position:absolute; left:1; top:10'>"
+        "    <option title='The Foo Option'>Foo</option>"
+        "    <option selected>Bar</option>"
+        "    <option disabled>Baz</option>"
+        "  </select></body></html>";
+    test->showInWindowAndWaitUntilMapped();
+    test->loadHtml(html, nullptr);
+    test->waitUntilLoadFinished();
+
+    test->clickAtPositionAndWaitUntilOptionMenuShown(5, 15);
+    g_assert(WEBKIT_IS_OPTION_MENU(test->m_menu.get()));
+    g_assert_cmpint(webkit_option_menu_get_n_items(test->m_menu.get()), ==, 3);
+    auto* item = webkit_option_menu_get_item(test->m_menu.get(), 0);
+    g_assert_cmpstr(webkit_option_menu_item_get_label(item), ==, "Foo");
+    g_assert_cmpstr(webkit_option_menu_item_get_tooltip(item), ==, "The Foo Option");
+    g_assert(!webkit_option_menu_item_is_group_label(item));
+    g_assert(!webkit_option_menu_item_is_group_child(item));
+    g_assert(webkit_option_menu_item_is_enabled(item));
+    g_assert(!webkit_option_menu_item_is_selected(item));
+    item = webkit_option_menu_get_item(test->m_menu.get(), 1);
+    g_assert_cmpstr(webkit_option_menu_item_get_label(item), ==, "Bar");
+    g_assert(!webkit_option_menu_item_get_tooltip(item));
+    g_assert(!webkit_option_menu_item_is_group_label(item));
+    g_assert(!webkit_option_menu_item_is_group_child(item));
+    g_assert(webkit_option_menu_item_is_enabled(item));
+    g_assert(webkit_option_menu_item_is_selected(item));
+    item = webkit_option_menu_get_item(test->m_menu.get(), 2);
+    g_assert_cmpstr(webkit_option_menu_item_get_label(item), ==, "Baz");
+    g_assert(!webkit_option_menu_item_get_tooltip(item));
+    g_assert(!webkit_option_menu_item_is_group_label(item));
+    g_assert(!webkit_option_menu_item_is_group_child(item));
+    g_assert(!webkit_option_menu_item_is_enabled(item));
+    g_assert(!webkit_option_menu_item_is_selected(item));
+
+    test->close();
+    g_assert(!test->m_menu.get());
+}
+
+static void testOptionMenuGroups(OptionMenuTest* test, gconstpointer)
+{
+    static const char html[] =
+        "<html><body>"
+        "  <select style='position:absolute; left:1; top:10'>"
+        "    <option>Root</option>"
+        "    <optgroup label='Group 1'>"
+        "      <option>Child 1-1</option>"
+        "      <option disabled>Child 1-2</option>"
+        "    </optgroup>"
+        "    <optgroup label='Group 2'>"
+        "      <option selected>Child 2-1</option>"
+        "      <option>Child 2-2</option>"
+        "    </optgroup>"
+        "    <option>Tail</option>"
+        "  </select></body></html>";
+    test->showInWindowAndWaitUntilMapped();
+    test->loadHtml(html, nullptr);
+    test->waitUntilLoadFinished();
+
+    test->clickAtPositionAndWaitUntilOptionMenuShown(5, 15);
+    g_assert(WEBKIT_IS_OPTION_MENU(test->m_menu.get()));
+    g_assert_cmpint(webkit_option_menu_get_n_items(test->m_menu.get()), ==, 8);
+    auto* item = webkit_option_menu_get_item(test->m_menu.get(), 0);
+    g_assert_cmpstr(webkit_option_menu_item_get_label(item), ==, "Root");
+    g_assert(!webkit_option_menu_item_get_tooltip(item));
+    g_assert(!webkit_option_menu_item_is_group_label(item));
+    g_assert(!webkit_option_menu_item_is_group_child(item));
+    g_assert(webkit_option_menu_item_is_enabled(item));
+    g_assert(!webkit_option_menu_item_is_selected(item));
+    item = webkit_option_menu_get_item(test->m_menu.get(), 1);
+    g_assert_cmpstr(webkit_option_menu_item_get_label(item), ==, "Group 1");
+    g_assert(!webkit_option_menu_item_get_tooltip(item));
+    g_assert(webkit_option_menu_item_is_group_label(item));
+    g_assert(!webkit_option_menu_item_is_group_child(item));
+    g_assert(!webkit_option_menu_item_is_enabled(item));
+    g_assert(!webkit_option_menu_item_is_selected(item));
+    item = webkit_option_menu_get_item(test->m_menu.get(), 2);
+    g_assert_cmpstr(webkit_option_menu_item_get_label(item), ==, "Child 1-1");
+    g_assert(!webkit_option_menu_item_get_tooltip(item));
+    g_assert(!webkit_option_menu_item_is_group_label(item));
+    g_assert(webkit_option_menu_item_is_group_child(item));
+    g_assert(webkit_option_menu_item_is_enabled(item));
+    g_assert(!webkit_option_menu_item_is_selected(item));
+    item = webkit_option_menu_get_item(test->m_menu.get(), 3);
+    g_assert_cmpstr(webkit_option_menu_item_get_label(item), ==, "Child 1-2");
+    g_assert(!webkit_option_menu_item_get_tooltip(item));
+    g_assert(!webkit_option_menu_item_is_group_label(item));
+    g_assert(webkit_option_menu_item_is_group_child(item));
+    g_assert(!webkit_option_menu_item_is_enabled(item));
+    g_assert(!webkit_option_menu_item_is_selected(item));
+    item = webkit_option_menu_get_item(test->m_menu.get(), 4);
+    g_assert_cmpstr(webkit_option_menu_item_get_label(item), ==, "Group 2");
+    g_assert(!webkit_option_menu_item_get_tooltip(item));
+    g_assert(webkit_option_menu_item_is_group_label(item));
+    g_assert(!webkit_option_menu_item_is_group_child(item));
+    g_assert(!webkit_option_menu_item_is_enabled(item));
+    g_assert(!webkit_option_menu_item_is_selected(item));
+    item = webkit_option_menu_get_item(test->m_menu.get(), 5);
+    g_assert_cmpstr(webkit_option_menu_item_get_label(item), ==, "Child 2-1");
+    g_assert(!webkit_option_menu_item_get_tooltip(item));
+    g_assert(!webkit_option_menu_item_is_group_label(item));
+    g_assert(webkit_option_menu_item_is_group_child(item));
+    g_assert(webkit_option_menu_item_is_enabled(item));
+    g_assert(webkit_option_menu_item_is_selected(item));
+    item = webkit_option_menu_get_item(test->m_menu.get(), 6);
+    g_assert_cmpstr(webkit_option_menu_item_get_label(item), ==, "Child 2-2");
+    g_assert(!webkit_option_menu_item_get_tooltip(item));
+    g_assert(!webkit_option_menu_item_is_group_label(item));
+    g_assert(webkit_option_menu_item_is_group_child(item));
+    g_assert(webkit_option_menu_item_is_enabled(item));
+    g_assert(!webkit_option_menu_item_is_selected(item));
+    item = webkit_option_menu_get_item(test->m_menu.get(), 7);
+    g_assert_cmpstr(webkit_option_menu_item_get_label(item), ==, "Tail");
+    g_assert(!webkit_option_menu_item_get_tooltip(item));
+    g_assert(!webkit_option_menu_item_is_group_label(item));
+    g_assert(!webkit_option_menu_item_is_group_child(item));
+    g_assert(webkit_option_menu_item_is_enabled(item));
+    g_assert(!webkit_option_menu_item_is_selected(item));
+}
+
+static void testOptionMenuActivate(OptionMenuTest* test, gconstpointer)
+{
+    static const char html[] =
+        "<html><body>"
+        "  <select id='combo' style='position:absolute; left:1; top:10'>"
+        "    <option>Foo</option>"
+        "    <option>Bar</option>"
+        "    <option>Baz</option>"
+        "  </select></body></html>";
+    test->showInWindowAndWaitUntilMapped();
+    test->loadHtml(html, nullptr);
+    test->waitUntilLoadFinished();
+
+    test->clickAtPositionAndWaitUntilOptionMenuShown(5, 15);
+    g_assert(WEBKIT_IS_OPTION_MENU(test->m_menu.get()));
+    g_assert_cmpint(webkit_option_menu_get_n_items(test->m_menu.get()), ==, 3);
+    test->activateItem(1);
+    auto* result = test->runJavaScriptAndWaitUntilFinished("document.getElementById('combo').selectedIndex", nullptr);
+    g_assert(result);
+    g_assert_cmpfloat(WebViewTest::_javascript_ResultToNumber(result), ==, 1);
+
+    // We should close the menu after activate, further activates will be ignored.
+    test->activateItem(2);
+    result = test->runJavaScriptAndWaitUntilFinished("document.getElementById('combo').selectedIndex", nullptr);
+    g_assert(result);
+    g_assert_cmpfloat(WebViewTest::_javascript_ResultToNumber(result), ==, 1);
+
+    test->close();
+}
+
+static void testOptionMenuSelect(OptionMenuTest* test, gconstpointer)
+{
+    static const char html[] =
+        "<html><body>"
+        "  <select id='combo' style='position:absolute; left:1; top:10'>"
+        "    <option>Foo</option>"
+        "    <option>Bar</option>"
+        "    <option>Baz</option>"
+        "  </select></body></html>";
+    test->showInWindowAndWaitUntilMapped();
+    test->loadHtml(html, nullptr);
+    test->waitUntilLoadFinished();
+
+    test->clickAtPositionAndWaitUntilOptionMenuShown(5, 15);
+    g_assert(WEBKIT_IS_OPTION_MENU(test->m_menu.get()));
+    g_assert_cmpint(webkit_option_menu_get_n_items(test->m_menu.get()), ==, 3);
+
+    // Select item changes the combo text, but not the currently selected item.
+    test->selectItem(2);
+    auto* result = test->runJavaScriptAndWaitUntilFinished("document.getElementById('combo').selectedIndex", nullptr);
+    g_assert(result);
+    g_assert_cmpfloat(WebViewTest::_javascript_ResultToNumber(result), ==, 0);
+
+    // It can be called multiple times.
+    test->selectItem(1);
+    result = test->runJavaScriptAndWaitUntilFinished("document.getElementById('combo').selectedIndex", nullptr);
+    g_assert(result);
+    g_assert_cmpfloat(WebViewTest::_javascript_ResultToNumber(result), ==, 0);
+
+    // And closing the menu activates the currently selected item.
+    test->close();
+    result = test->runJavaScriptAndWaitUntilFinished("document.getElementById('combo').selectedIndex", nullptr);
+    g_assert(result);
+    g_assert_cmpfloat(WebViewTest::_javascript_ResultToNumber(result), ==, 1);
+}
+
+void beforeAll()
+{
+    OptionMenuTest::add("WebKitWebView", "option-menu-simple", testOptionMenuSimple);
+    OptionMenuTest::add("WebKitWebView", "option-menu-groups", testOptionMenuGroups);
+    OptionMenuTest::add("WebKitWebView", "option-menu-activate", testOptionMenuActivate);
+    OptionMenuTest::add("WebKitWebView", "option-menu-select", testOptionMenuSelect);
+}
+
+void afterAll()
+{
+}
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to