Diff
Modified: trunk/Source/WebCore/ChangeLog (261734 => 261735)
--- trunk/Source/WebCore/ChangeLog 2020-05-15 08:20:01 UTC (rev 261734)
+++ trunk/Source/WebCore/ChangeLog 2020-05-15 08:27:22 UTC (rev 261735)
@@ -1,3 +1,14 @@
+2020-05-15 Adrian Perez de Castro <[email protected]>
+
+ [GTK3] Bring back usage of GtkMenu for context menus
+ https://bugs.webkit.org/show_bug.cgi?id=211557
+
+ Reviewed by Carlos Garcia Campos.
+
+ No new tests needed.
+
+ * platform/gtk/GtkVersioning.h: Remove GtkPopover functions used only for context menus.
+
2020-05-14 Said Abou-Hallawa <[email protected]>
Unreviewed. Fix build warning after r261113
Modified: trunk/Source/WebCore/platform/gtk/GtkVersioning.h (261734 => 261735)
--- trunk/Source/WebCore/platform/gtk/GtkVersioning.h 2020-05-15 08:20:01 UTC (rev 261734)
+++ trunk/Source/WebCore/platform/gtk/GtkVersioning.h 2020-05-15 08:27:22 UTC (rev 261735)
@@ -152,26 +152,4 @@
return TRUE;
}
-static inline GtkWidget* gtk_popover_menu_new()
-{
- return gtk_popover_menu_new_from_model(nullptr);
-}
-
-static inline void gtk_popover_bind_model(GtkPopover* popover, GMenuModel* model, const char*)
-{
- ASSERT(GTK_IS_POPOVER_MENU(popover));
- gtk_popover_menu_set_menu_model(GTK_POPOVER_MENU(popover), model);
-}
-
-static inline void gtk_popover_set_relative_to(GtkPopover* popover, GtkWidget* parent)
-{
- gtk_widget_set_parent(GTK_WIDGET(popover), parent);
-}
-
-#else
-
-static inline void gtk_popover_set_has_arrow(GtkPopover*, gboolean)
-{
-}
-
#endif // USE(GTK4)
Modified: trunk/Source/WebKit/ChangeLog (261734 => 261735)
--- trunk/Source/WebKit/ChangeLog 2020-05-15 08:20:01 UTC (rev 261734)
+++ trunk/Source/WebKit/ChangeLog 2020-05-15 08:27:22 UTC (rev 261735)
@@ -1,3 +1,35 @@
+2020-05-15 Adrian Perez de Castro <[email protected]>
+
+ [GTK3] Bring back usage of GtkMenu for context menus
+ https://bugs.webkit.org/show_bug.cgi?id=211557
+
+ Reviewed by Carlos Garcia Campos.
+
+ * UIProcess/API/glib/WebKitWebView.cpp:
+ (contextMenuDismissed): Removed.
+ (webkitWebViewPopulateContextMenu): Use WebContextMenuProxyGtk::widgetDismissedSignal
+ and move the code from contextMenuDismissed() into an inline lambda.
+ * UIProcess/API/gtk/WebKitWebViewBase.cpp:
+ (activeContextMenuClosed): Removed.
+ (webkitWebViewBaseSetActiveContextMenuProxy): Use WebContextMenuProxyGtk::widgetDismissedSignal
+ and move the code from activeContextMenuClosed() into an inline lambda.
+ * UIProcess/gtk/WebContextMenuProxyGtk.cpp: Add helper functions to manipulate the actual
+ widget used for context menus depending on whether GTK3 or GTK4 is being used. The GTK3
+ versions bring back bits of code removed in r260889.
+ (WebKit::createMenuWidget): Added.
+ (WebKit::popupMenuWidget): Added.
+ (WebKit::popdownMenuWidget): Added.
+ (WebKit::menuWidgetHasItems): Added.
+ (WebKit::bindModelToMenuWidget): Added.
+ (WebKit::WebContextMenuProxyGtk::populate): Use context menu widget helper functions.
+ (WebKit::WebContextMenuProxyGtk::showContextMenuWithItems): Ditto.
+ (WebKit::WebContextMenuProxyGtk::WebContextMenuProxyGtk): Ditto. Also handle the
+ signal triggered when the context menu is dismissed and arrange to call
+ webkitWebViewContextMenuDismissed() and webkitWebViewBaseContextMenuDismissed().
+ (WebKit::WebContextMenuProxyGtk::~WebContextMenuProxyGtk): Use helper functions.
+ * UIProcess/gtk/WebContextMenuProxyGtk.h: Add WebContextMenuProxyGtk::widgetDismissedSignal
+ constant.
+
2020-05-14 Kate Cheney <[email protected]>
Attribute non-network loads and loads with html strings as automatically app-bound
Modified: trunk/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp (261734 => 261735)
--- trunk/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp 2020-05-15 08:20:01 UTC (rev 261734)
+++ trunk/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp 2020-05-15 08:27:22 UTC (rev 261735)
@@ -2591,11 +2591,6 @@
}
#if PLATFORM(GTK)
-static void contextMenuDismissed(GtkWidget*, WebKitWebView* webView)
-{
- g_signal_emit(webView, signals[CONTEXT_MENU_DISMISSED], 0, NULL);
-}
-
void webkitWebViewPopulateContextMenu(WebKitWebView* webView, const Vector<WebContextMenuItemData>& proposedMenu, const WebHitTestResultData& hitTestResultData, GVariant* userData)
{
WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView);
@@ -2617,7 +2612,9 @@
webkitContextMenuPopulate(contextMenu.get(), contextMenuItems);
contextMenuProxy->populate(contextMenuItems);
- g_signal_connect(contextMenuProxy->gtkWidget(), "closed", G_CALLBACK(contextMenuDismissed), webView);
+ g_signal_connect(contextMenuProxy->gtkWidget(), WebContextMenuProxyGtk::widgetDismissedSignal, G_CALLBACK(+[](GtkWidget*, WebKitWebView* webView) {
+ g_signal_emit(webView, signals[CONTEXT_MENU_DISMISSED], 0, nullptr);
+ }), webView);
// Clear the menu to make sure it's useless after signal emission.
webkit_context_menu_remove_all(contextMenu.get());
Modified: trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp (261734 => 261735)
--- trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp 2020-05-15 08:20:01 UTC (rev 261734)
+++ trunk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp 2020-05-15 08:27:22 UTC (rev 261735)
@@ -1864,16 +1864,13 @@
gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase));
}
-static void activeContextMenuClosed(GtkWidget* widget, WebKitWebViewBase* webViewBase)
-{
- if (webViewBase->priv->activeContextMenuProxy && webViewBase->priv->activeContextMenuProxy->gtkWidget() == widget)
- webViewBase->priv->activeContextMenuProxy = nullptr;
-}
-
void webkitWebViewBaseSetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase, WebContextMenuProxyGtk* contextMenuProxy)
{
webkitWebViewBase->priv->activeContextMenuProxy = contextMenuProxy;
- g_signal_connect_object(contextMenuProxy->gtkWidget(), "closed", G_CALLBACK(activeContextMenuClosed), webkitWebViewBase, static_cast<GConnectFlags>(0));
+ g_signal_connect(contextMenuProxy->gtkWidget(), WebContextMenuProxyGtk::widgetDismissedSignal, G_CALLBACK(+[](GtkWidget* widget, WebKitWebViewBase* webViewBase) {
+ if (webViewBase->priv->activeContextMenuProxy && webViewBase->priv->activeContextMenuProxy->gtkWidget() == widget)
+ webViewBase->priv->activeContextMenuProxy = nullptr;
+ }), webkitWebViewBase);
}
WebContextMenuProxyGtk* webkitWebViewBaseGetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase)
Modified: trunk/Source/WebKit/UIProcess/gtk/WebContextMenuProxyGtk.cpp (261734 => 261735)
--- trunk/Source/WebKit/UIProcess/gtk/WebContextMenuProxyGtk.cpp 2020-05-15 08:20:01 UTC (rev 261734)
+++ trunk/Source/WebKit/UIProcess/gtk/WebContextMenuProxyGtk.cpp 2020-05-15 08:27:22 UTC (rev 261735)
@@ -47,6 +47,84 @@
namespace WebKit {
using namespace WebCore;
+#if USE(GTK4)
+const char* WebContextMenuProxyGtk::widgetDismissedSignal = "closed";
+
+static GtkWidget* createMenuWidget(GtkWidget* webView)
+{
+ auto* widget = gtk_popover_menu_new_from_model(nullptr);
+ gtk_popover_set_has_arrow(GTK_POPOVER(widget), FALSE);
+ gtk_popover_set_position(GTK_POPOVER(widget), GTK_POS_BOTTOM);
+ gtk_widget_set_parent(widget, webView);
+ return widget;
+}
+
+static inline void popupMenuWidget(GtkWidget* widget, const GdkEvent*, const GdkRectangle& target)
+{
+ gtk_popover_set_pointing_to(GTK_POPOVER(widget), &target);
+ gtk_popover_popup(GTK_POPOVER(widget));
+}
+
+static inline void popdownMenuWidget(GtkWidget* widget)
+{
+ gtk_popover_popdown(GTK_POPOVER(widget));
+}
+
+static inline bool menuWidgetHasItems(GtkWidget* widget)
+{
+ return g_menu_model_get_n_items(gtk_popover_menu_get_menu_model(GTK_POPOVER_MENU(widget)));
+}
+
+static inline void bindModelToMenuWidget(GtkWidget* widget, GMenuModel* model)
+{
+ gtk_popover_menu_set_menu_model(GTK_POPOVER_MENU(widget), model);
+}
+#else
+const char* WebContextMenuProxyGtk::widgetDismissedSignal = "deactivate";
+
+static GtkWidget* createMenuWidget(GtkWidget* webView)
+{
+ auto* widget = gtk_menu_new();
+ gtk_menu_attach_to_widget(GTK_MENU(widget), webView, nullptr);
+ return widget;
+}
+
+static void popupMenuWidget(GtkWidget* widget, const GdkEvent* triggerEvent, const GdkRectangle& target)
+{
+ GUniquePtr<GdkEvent> keyEvent;
+ auto* window = gtk_widget_get_window(gtk_menu_get_attach_widget(GTK_MENU(widget)));
+ if (!triggerEvent) {
+ // When the context menu is requested using the keyboard, there is no
+ // triggerEvent: use a fake event for the “Menu” key being released.
+ keyEvent.reset(gdk_event_new(GDK_KEY_RELEASE));
+ gdk_event_set_device(keyEvent.get(), gdk_seat_get_keyboard(gdk_display_get_default_seat(gdk_window_get_display(window))));
+ auto* event = reinterpret_cast<GdkEventKey*>(keyEvent.get());
+ event->window = window;
+ event->time = GDK_CURRENT_TIME;
+ event->keyval = GDK_KEY_Menu;
+ triggerEvent = keyEvent.get();
+ };
+ gtk_menu_popup_at_rect(GTK_MENU(widget), window, &target, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, triggerEvent);
+}
+
+static inline void popdownMenuWidget(GtkWidget* widget)
+{
+ gtk_menu_popdown(GTK_MENU(widget));
+}
+
+static inline bool menuWidgetHasItems(GtkWidget* widget)
+{
+ unsigned childCount = 0;
+ gtk_container_foreach(GTK_CONTAINER(widget), [](GtkWidget*, gpointer data) { (*static_cast<unsigned*>(data))++; }, &childCount);
+ return childCount > 0;
+}
+
+static inline void bindModelToMenuWidget(GtkWidget* widget, GMenuModel* model)
+{
+ gtk_menu_shell_bind_model(GTK_MENU_SHELL(widget), model, gContextMenuItemGroup, TRUE);
+}
+#endif // USE(GTK4)
+
static void contextMenuItemActivatedCallback(GAction* action, GVariant*, WebPageProxy* page)
{
auto* stateType = g_action_get_state_type(action);
@@ -127,7 +205,7 @@
void WebContextMenuProxyGtk::populate(const Vector<WebContextMenuItemGlib>& items)
{
GRefPtr<GMenu> menu = buildMenu(items);
- gtk_popover_bind_model(m_menu, G_MENU_MODEL(menu.get()), gContextMenuItemGroup);
+ bindModelToMenuWidget(m_menu, G_MENU_MODEL(menu.get()));
}
void WebContextMenuProxyGtk::populate(const Vector<Ref<WebContextMenuItem>>& items)
@@ -155,7 +233,7 @@
}
}
}
- gtk_popover_bind_model(m_menu, G_MENU_MODEL(menu.get()), gContextMenuItemGroup);
+ bindModelToMenuWidget(m_menu, G_MENU_MODEL(menu.get()));
}
void WebContextMenuProxyGtk::show()
@@ -174,14 +252,13 @@
if (!items.isEmpty())
populate(items);
- unsigned childCount = 0;
- gtk_container_foreach(GTK_CONTAINER(m_menu), [](GtkWidget*, gpointer data) { (*static_cast<unsigned*>(data))++; }, &childCount);
- if (!childCount)
+ if (!menuWidgetHasItems(m_menu))
return;
+ NativeWebMouseEvent* mouseEvent = m_page->currentlyProcessedMouseDownEvent();
+ const GdkEvent* event = mouseEvent ? mouseEvent->nativeEvent() : nullptr;
const GdkRectangle rect = { m_context.menuLocation().x(), m_context.menuLocation().y(), 1, 1 };
- gtk_popover_set_pointing_to(m_menu, &rect);
- gtk_popover_popup(m_menu);
+ popupMenuWidget(m_menu, event, rect);
}
WebContextMenuProxyGtk::WebContextMenuProxyGtk(GtkWidget* webView, WebPageProxy& page, ContextMenuContextData&& context, const UserData& userData)
@@ -188,11 +265,8 @@
: WebContextMenuProxy(WTFMove(context), userData)
, m_webView(webView)
, m_page(&page)
- , m_menu(GTK_POPOVER(gtk_popover_menu_new()))
+ , m_menu(createMenuWidget(m_webView))
{
- gtk_popover_set_has_arrow(m_menu, FALSE);
- gtk_popover_set_position(m_menu, GTK_POS_BOTTOM);
- gtk_popover_set_relative_to(m_menu, m_webView);
gtk_widget_insert_action_group(GTK_WIDGET(m_menu), gContextMenuItemGroup, G_ACTION_GROUP(m_actionGroup.get()));
webkitWebViewBaseSetActiveContextMenuProxy(WEBKIT_WEB_VIEW_BASE(m_webView), this);
}
@@ -199,7 +273,7 @@
WebContextMenuProxyGtk::~WebContextMenuProxyGtk()
{
- gtk_popover_popdown(m_menu);
+ popdownMenuWidget(m_menu);
for (auto& handler : m_signalHandlers)
g_signal_handler_disconnect(handler.value, handler.key);
@@ -206,7 +280,7 @@
m_signalHandlers.clear();
gtk_widget_insert_action_group(GTK_WIDGET(m_menu), gContextMenuItemGroup, nullptr);
- gtk_widget_destroy(GTK_WIDGET(m_menu));
+ gtk_widget_destroy(m_menu);
}
} // namespace WebKit
Modified: trunk/Source/WebKit/UIProcess/gtk/WebContextMenuProxyGtk.h (261734 => 261735)
--- trunk/Source/WebKit/UIProcess/gtk/WebContextMenuProxyGtk.h 2020-05-15 08:20:01 UTC (rev 261734)
+++ trunk/Source/WebKit/UIProcess/gtk/WebContextMenuProxyGtk.h 2020-05-15 08:27:22 UTC (rev 261735)
@@ -51,7 +51,8 @@
~WebContextMenuProxyGtk();
void populate(const Vector<WebContextMenuItemGlib>&);
- GtkWidget* gtkWidget() const { return GTK_WIDGET(m_menu); }
+ GtkWidget* gtkWidget() const { return m_menu; }
+ static const char* widgetDismissedSignal;
private:
WebContextMenuProxyGtk(GtkWidget*, WebPageProxy&, ContextMenuContextData&&, const UserData&);
@@ -64,7 +65,7 @@
GtkWidget* m_webView;
WebPageProxy* m_page;
- GtkPopover* m_menu;
+ GtkWidget* m_menu;
HashMap<unsigned long, void*> m_signalHandlers;
GRefPtr<GSimpleActionGroup> m_actionGroup { adoptGRef(g_simple_action_group_new()) };
};
Modified: trunk/Tools/ChangeLog (261734 => 261735)
--- trunk/Tools/ChangeLog 2020-05-15 08:20:01 UTC (rev 261734)
+++ trunk/Tools/ChangeLog 2020-05-15 08:27:22 UTC (rev 261735)
@@ -1,3 +1,13 @@
+2020-05-15 Adrian Perez de Castro <[email protected]>
+
+ [GTK3] Bring back usage of GtkMenu for context menus
+ https://bugs.webkit.org/show_bug.cgi?id=211557
+
+ Reviewed by Carlos Garcia Campos.
+
+ * TestWebKitAPI/Tests/WebKitGtk/TestContextMenu.cpp: Add preprocessor conditionals
+ for GTK4 and bring back some bits previously removed in r260889 for GTK3.
+
2020-05-14 Kate Cheney <[email protected]>
Attribute non-network loads and loads with html strings as automatically app-bound
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestContextMenu.cpp (261734 => 261735)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestContextMenu.cpp 2020-05-15 08:20:01 UTC (rev 261734)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestContextMenu.cpp 2020-05-15 08:27:22 UTC (rev 261735)
@@ -26,6 +26,7 @@
static WebKitTestServer* kServer;
+#if USE(GTK4)
struct LookupWidgetsData {
void (*walkChildren)(GtkContainer*, GtkCallback, void*);
Function<bool(GtkWidget*)> predicate;
@@ -47,6 +48,7 @@
lookupWidgetsWalkChild(widget, &data);
return WTFMove(data.result);
}
+#endif // USE(GTK4)
class ContextMenuTest: public WebViewTest {
public:
@@ -116,7 +118,7 @@
quitMainLoop();
}
- GtkPopover* getPopoverMenu()
+ GtkWidget* getContextMenuWidget()
{
GUniquePtr<GList> toplevels(gtk_window_list_toplevels());
for (GList* iter = toplevels.get(); iter; iter = g_list_next(iter)) {
@@ -123,6 +125,7 @@
if (!GTK_IS_WINDOW(iter->data))
continue;
+#if USE(GTK4)
// Popovers are internal to the GtkContainer where the webview resides,
// gtk_container_forall() is the only way to enumerate internal children.
GtkPopover *popover = nullptr;
@@ -135,6 +138,14 @@
if (popover && gtk_popover_get_relative_to(popover) == GTK_WIDGET(m_webView))
return popover;
+#else
+ 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 child;
+#endif // USE(GTK4)
}
g_assert_not_reached();
return 0;
@@ -579,9 +590,10 @@
return false;
}
- GtkButton* getMenuItem(GtkPopover* popover, const gchar* itemLabel)
+#if USE(GTK4)
+ GtkButton* getMenuItem(GtkWidget* popover, const gchar* itemLabel)
{
- auto items = lookupWidgets(GTK_WIDGET(popover),
+ auto items = lookupWidgets(popover,
[itemLabel](GtkWidget* widget) {
if (!GTK_IS_BUTTON(widget))
return false;
@@ -598,13 +610,32 @@
g_assert_cmpuint(items.size(), >, 0);
return items.size() ? GTK_BUTTON(items[0]) : nullptr;
}
+#else
+ GtkMenuItem* getMenuItem(GtkWidget* menu, const gchar* itemLabel)
+ {
+ GUniquePtr<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 nullptr;
+ }
+#endif // USE(GTK4)
void activateMenuItem()
{
g_assert_nonnull(m_itemToActivateLabel);
- auto* menu = getPopoverMenu();
+ auto* menu = getContextMenuWidget();
auto* item = getMenuItem(menu, m_itemToActivateLabel);
+#if USE(GTK4)
+ // GTK4 uses a popover, which contains buttons.
gtk_button_clicked(item);
+#else
+ // GTK3 uses a menu, which contains menu items.
+ gtk_menu_shell_activate_item(GTK_MENU_SHELL(menu), GTK_WIDGET(item), TRUE);
+#endif // USE(GTK4)
m_itemToActivateLabel = nullptr;
}
@@ -649,9 +680,11 @@
{
test->m_toggled = true;
+#if USE(GTK4)
// For toggle actions the popover menu is NOT dismissed automatically, as to show visual feedback to the user
// (i.e. the check marker). Dismiss it here to trigger contextMenuDismissedCallback() and continue the test.
gtk_popover_popdown(test->getPopoverMenu());
+#endif // USE(GTK4)
}
void setAction(GtkAction* action)