Skip to content

Commit b819cf0

Browse files
committed
[GTK] Add WebKitContextMenuGAction to use as GAction for WebContextMenuItemGlib instead of GSimpleAction
https://bugs.webkit.org/show_bug.cgi?id=304330 Reviewed by Adrian Perez de Castro. Using our GAction implementation simplifies the code and will make it easier to expose context menu API in WPE. Canonical link: https://commits.webkit.org/305267@main
1 parent 29b3467 commit b819cf0

19 files changed

Lines changed: 317 additions & 76 deletions

Source/WebKit/Shared/glib/WebContextMenuItemGlib.cpp

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#if ENABLE(CONTEXT_MENUS)
3232
#include "APIObject.h"
33+
#include "WebKitContextMenuGAction.h"
3334
#include <gio/gio.h>
3435

3536
#if PLATFORM(GTK) && !USE(GTK4)
@@ -89,7 +90,6 @@ WebContextMenuItemGlib::WebContextMenuItemGlib(GtkAction* action)
8990
{
9091
m_gtkAction = action;
9192
createActionIfNeeded();
92-
g_object_set_data_full(G_OBJECT(m_gAction.get()), "webkit-gtk-action", g_object_ref(m_gtkAction), g_object_unref);
9393
}
9494
ALLOW_DEPRECATED_DECLARATIONS_END
9595
#endif
@@ -98,31 +98,20 @@ WebContextMenuItemGlib::~WebContextMenuItemGlib()
9898
{
9999
}
100100

101-
GUniquePtr<char> WebContextMenuItemGlib::buildActionName() const
102-
{
103-
#if PLATFORM(GTK) && !USE(GTK4)
104-
ALLOW_DEPRECATED_DECLARATIONS_BEGIN
105-
if (m_gtkAction)
106-
return GUniquePtr<char>(g_strdup(gtk_action_get_name(m_gtkAction)));
107-
ALLOW_DEPRECATED_DECLARATIONS_END
108-
#endif
109-
110-
static uint64_t actionID = 0;
111-
return GUniquePtr<char>(g_strdup_printf("action-%" PRIu64, ++actionID));
112-
}
113-
114101
void WebContextMenuItemGlib::createActionIfNeeded()
115102
{
116-
if (type() == ContextMenuItemType::Separator)
103+
if (type() == ContextMenuItemType::Separator || type() == ContextMenuItemType::Submenu)
117104
return;
118105

119106
if (!m_gAction) {
120-
auto actionName = buildActionName();
121-
if (type() == ContextMenuItemType::CheckableAction)
122-
m_gAction = adoptGRef(G_ACTION(g_simple_action_new_stateful(actionName.get(), nullptr, g_variant_new_boolean(checked()))));
123-
else
124-
m_gAction = adoptGRef(G_ACTION(g_simple_action_new(actionName.get(), nullptr)));
125-
g_simple_action_set_enabled(G_SIMPLE_ACTION(m_gAction.get()), enabled());
107+
const char* name = nullptr;
108+
#if PLATFORM(GTK) && !USE(GTK4)
109+
ALLOW_DEPRECATED_DECLARATIONS_BEGIN
110+
if (m_gtkAction) // NOLINT
111+
name = gtk_action_get_name(m_gtkAction);
112+
ALLOW_DEPRECATED_DECLARATIONS_END
113+
#endif
114+
m_gAction = adoptGRef(webkitContextMenuGActionNew(name, *this));
126115
}
127116

128117
#if PLATFORM(GTK) && !USE(GTK4)
@@ -135,10 +124,14 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN
135124
} else
136125
m_gtkAction = gtk_action_new(g_action_get_name(m_gAction.get()), title().utf8().data(), 0, nullptr);
137126
gtk_action_set_sensitive(m_gtkAction, enabled());
138-
g_object_set_data_full(G_OBJECT(m_gAction.get()), "webkit-gtk-action", m_gtkAction, g_object_unref);
139127
}
140128

141-
g_signal_connect_object(m_gAction.get(), "activate", G_CALLBACK(gtk_action_activate), m_gtkAction, G_CONNECT_SWAPPED);
129+
if (WEBKIT_IS_CONTEXT_MENU_GACTION(m_gAction.get()))
130+
webkitContextMenuGActionSetGtkAction(WEBKIT_CONTEXT_MENU_GACTION(m_gAction.get()), m_gtkAction);
131+
else {
132+
g_object_set_data_full(G_OBJECT(m_gAction.get()), "webkit-gtk-action", g_object_ref_sink(m_gtkAction), g_object_unref);
133+
g_signal_connect_object(m_gAction.get(), "activate", G_CALLBACK(gtk_action_activate), m_gtkAction, G_CONNECT_SWAPPED);
134+
}
142135
ALLOW_DEPRECATED_DECLARATIONS_END
143136
#endif
144137
}

Source/WebKit/Shared/glib/WebContextMenuItemGlib.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
#include "WebContextMenuItemData.h"
3030
#include <wtf/TZoneMalloc.h>
3131
#include <wtf/glib/GRefPtr.h>
32-
#include <wtf/glib/GUniquePtr.h>
3332

3433
#if PLATFORM(GTK) && !USE(GTK4)
3534
typedef struct _GtkAction GtkAction;
@@ -61,7 +60,6 @@ class WebContextMenuItemGlib final : public WebContextMenuItemData {
6160
#endif
6261

6362
private:
64-
GUniquePtr<char> buildActionName() const;
6563
void createActionIfNeeded();
6664

6765
GRefPtr<GAction> m_gAction;
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/*
2+
* Copyright (C) 2025 Igalia S.L.
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Library General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Library General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Library General Public License
15+
* along with this library; see the file COPYING.LIB. If not, write to
16+
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17+
* Boston, MA 02110-1301, USA.
18+
*/
19+
20+
#include "config.h"
21+
#include "WebKitContextMenuGAction.h"
22+
23+
#if ENABLE(CONTEXT_MENUS)
24+
#include "WebContextMenuItemData.h"
25+
#include "WebContextMenuProxy.h"
26+
#include "WebPageProxy.h"
27+
#include <wtf/glib/GRefPtr.h>
28+
#include <wtf/glib/GUniquePtr.h>
29+
#include <wtf/glib/WTFGType.h>
30+
31+
using namespace WebKit;
32+
33+
static void webkitContextMenuGActionGActionInterfaceInit(GActionInterface*);
34+
35+
struct _WebKitContextMenuGActionPrivate {
36+
GUniquePtr<char> name;
37+
WebContextMenuItemData item;
38+
GRefPtr<GVariant> state;
39+
WeakPtr<WebPageProxy> page;
40+
#if PLATFORM(GTK) && !USE(GTK4)
41+
GRefPtr<GtkAction> gtkAction;
42+
#endif
43+
};
44+
45+
WEBKIT_DEFINE_FINAL_TYPE_WITH_CODE(WebKitContextMenuGAction, webkit_context_menu_gaction, G_TYPE_OBJECT, GObject,
46+
G_IMPLEMENT_INTERFACE(G_TYPE_ACTION, webkitContextMenuGActionGActionInterfaceInit))
47+
48+
enum {
49+
PROP_0,
50+
PROP_NAME,
51+
PROP_PARAMETER_TYPE,
52+
PROP_ENABLED,
53+
PROP_STATE_TYPE,
54+
PROP_STATE
55+
};
56+
57+
static const char* webkitContextMenuGActionGetName(GAction* action)
58+
{
59+
auto* priv = WEBKIT_CONTEXT_MENU_GACTION(action)->priv;
60+
return priv->name.get();
61+
}
62+
63+
static const GVariantType* webkitContextMenuGActionGetParameterType(GAction*)
64+
{
65+
return nullptr;
66+
}
67+
68+
static gboolean webkitContextMenuGActionGetEnabled(GAction* action)
69+
{
70+
auto* priv = WEBKIT_CONTEXT_MENU_GACTION(action)->priv;
71+
return priv->item.enabled();
72+
}
73+
74+
static const GVariantType* webkitContextMenuGActionGetStateType(GAction* action)
75+
{
76+
auto* priv = WEBKIT_CONTEXT_MENU_GACTION(action)->priv;
77+
return priv->state ? g_variant_get_type(priv->state.get()) : nullptr;
78+
}
79+
80+
static GVariant* webkitContextMenuGActionGetState(GAction* action)
81+
{
82+
auto* priv = WEBKIT_CONTEXT_MENU_GACTION(action)->priv;
83+
return priv->state ? g_variant_ref(priv->state.get()) : nullptr;
84+
}
85+
86+
static GVariant* webkitContextMenuGActionGetStateHint(GAction*)
87+
{
88+
return nullptr;
89+
}
90+
91+
static void webkitContextMenuGActionChangeState(GAction* action, GVariant* value)
92+
{
93+
RELEASE_ASSERT(value && g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN));
94+
auto* priv = WEBKIT_CONTEXT_MENU_GACTION(action)->priv;
95+
GRefPtr<GVariant> state(value);
96+
if (priv->state) {
97+
RELEASE_ASSERT(g_variant_is_of_type(value, g_variant_get_type(priv->state.get())));
98+
if (g_variant_equal(priv->state.get(), state.get()))
99+
return;
100+
}
101+
102+
priv->state = WTF::move(state);
103+
g_object_notify(G_OBJECT(action), "state");
104+
}
105+
106+
static void webkitContextMenuGActionActivate(GAction* action, GVariant*)
107+
{
108+
auto* priv = WEBKIT_CONTEXT_MENU_GACTION(action)->priv;
109+
RefPtr<WebPageProxy> page = priv->page.get();
110+
if (!page)
111+
return;
112+
113+
auto* proxy = page->activeContextMenu();
114+
if (!proxy)
115+
return;
116+
117+
if (!priv->item.enabled())
118+
return;
119+
120+
if (priv->state)
121+
g_action_change_state(action, g_variant_new_boolean(!g_variant_get_boolean(priv->state.get())));
122+
123+
#if PLATFORM(GTK) && !USE(GTK4)
124+
ALLOW_DEPRECATED_DECLARATIONS_BEGIN
125+
if (priv->gtkAction)
126+
gtk_action_activate(priv->gtkAction.get());
127+
ALLOW_DEPRECATED_DECLARATIONS_END
128+
#endif
129+
130+
page->contextMenuItemSelected(priv->item, proxy->frameInfo());
131+
}
132+
133+
static void webkitContextMenuGActionGActionInterfaceInit(GActionInterface* iface)
134+
{
135+
iface->get_name = webkitContextMenuGActionGetName;
136+
iface->get_parameter_type = webkitContextMenuGActionGetParameterType;
137+
iface->get_enabled = webkitContextMenuGActionGetEnabled;
138+
iface->get_state_type = webkitContextMenuGActionGetStateType;
139+
iface->get_state = webkitContextMenuGActionGetState;
140+
iface->get_state_hint = webkitContextMenuGActionGetStateHint;
141+
iface->change_state = webkitContextMenuGActionChangeState;
142+
iface->activate = webkitContextMenuGActionActivate;
143+
}
144+
145+
static void webkitContextMenuGActionGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
146+
{
147+
auto* action = G_ACTION(object);
148+
149+
switch (propId) {
150+
case PROP_NAME:
151+
g_value_set_string(value, webkitContextMenuGActionGetName(action));
152+
break;
153+
case PROP_PARAMETER_TYPE:
154+
g_value_set_boxed(value, webkitContextMenuGActionGetParameterType(action));
155+
break;
156+
case PROP_ENABLED:
157+
g_value_set_boolean(value, webkitContextMenuGActionGetEnabled(action));
158+
break;
159+
case PROP_STATE_TYPE:
160+
g_value_set_boxed(value, webkitContextMenuGActionGetStateType(action));
161+
break;
162+
case PROP_STATE:
163+
g_value_take_variant(value, webkitContextMenuGActionGetState(action));
164+
break;
165+
default:
166+
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
167+
}
168+
}
169+
170+
static void webkit_context_menu_gaction_class_init(WebKitContextMenuGActionClass* actionClass)
171+
{
172+
GObjectClass* objectClass = G_OBJECT_CLASS(actionClass);
173+
objectClass->get_property = webkitContextMenuGActionGetProperty;
174+
175+
g_object_class_override_property(objectClass, PROP_NAME, "name");
176+
g_object_class_override_property(objectClass, PROP_PARAMETER_TYPE, "parameter-type");
177+
g_object_class_override_property(objectClass, PROP_ENABLED, "enabled");
178+
g_object_class_override_property(objectClass, PROP_STATE_TYPE, "state-type");
179+
g_object_class_override_property(objectClass, PROP_STATE, "state");
180+
}
181+
182+
GAction* webkitContextMenuGActionNew(const char* name, const WebContextMenuItemData& item)
183+
{
184+
RELEASE_ASSERT(item.type() == WebCore::ContextMenuItemType::Action || item.type() == WebCore::ContextMenuItemType::CheckableAction);
185+
auto* action = WEBKIT_CONTEXT_MENU_GACTION(g_object_new(WEBKIT_TYPE_CONTEXT_MENU_GACTION, nullptr));
186+
if (name)
187+
action->priv->name.reset(g_strdup(name));
188+
else {
189+
static uint64_t actionID = 0;
190+
action->priv->name.reset(g_strdup_printf("action-%" PRIu64, ++actionID));
191+
}
192+
if (item.type() == WebCore::ContextMenuItemType::CheckableAction)
193+
action->priv->state = g_variant_new_boolean(item.checked());
194+
action->priv->item = item;
195+
196+
return G_ACTION(action);
197+
}
198+
199+
void webkitContextMenuGActionSetPage(WebKitContextMenuGAction* action, WebPageProxy* page)
200+
{
201+
RELEASE_ASSERT(WEBKIT_IS_CONTEXT_MENU_GACTION(action));
202+
action->priv->page = page;
203+
}
204+
205+
#if PLATFORM(GTK) && !USE(GTK4)
206+
void webkitContextMenuGActionSetGtkAction(WebKitContextMenuGAction* action, GtkAction* gtkAction)
207+
{
208+
RELEASE_ASSERT(WEBKIT_IS_CONTEXT_MENU_GACTION(action));
209+
action->priv->gtkAction = gtkAction;
210+
}
211+
#endif
212+
213+
#endif // ENABLE(CONTEXT_MENUS)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (C) 2025 Igalia S.L.
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Library General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Library General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Library General Public License
15+
* along with this library; see the file COPYING.LIB. If not, write to
16+
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17+
* Boston, MA 02110-1301, USA.
18+
*/
19+
20+
#pragma once
21+
22+
#if ENABLE(CONTEXT_MENUS)
23+
#include "WebKitDefines.h"
24+
#include <gio/gio.h>
25+
26+
#if PLATFORM(GTK) && !USE(GTK4)
27+
#include <gtk/gtk.h>
28+
#endif
29+
30+
namespace WebKit {
31+
class WebContextMenuItemData;
32+
class WebPageProxy;
33+
}
34+
35+
#define WEBKIT_TYPE_CONTEXT_MENU_GACTION (webkit_context_menu_gaction_get_type())
36+
#if !ENABLE(2022_GLIB_API)
37+
#define WEBKIT_CONTEXT_MENU_GACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_CONTEXT_MENU_GACTION, WebKitContextMenuGAction))
38+
#define WEBKIT_IS_CONTEXT_MENU_GACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_CONTEXT_MENU_GACTION))
39+
#define WEBKIT_CONTEXT_MENU_GACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_CONTEXT_MENU_GACTION, WebKitContextMenuGActionClass))
40+
#define WEBKIT_IS_CONTEXT_MENU_GACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_CONTEXT_MENU_GACTION))
41+
#define WEBKIT_CONTEXT_MENU_GACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_CONTEXT_MENU_GACTION, WebKitContextMenuGActionClass))
42+
43+
struct _WebKitContextMenuGActionClass {
44+
GObjectClass parentClass;
45+
};
46+
#endif
47+
48+
WEBKIT_DECLARE_FINAL_TYPE(WebKitContextMenuGAction, webkit_context_menu_gaction, WEBKIT, CONTEXT_MENU_GACTION, GObject)
49+
50+
GAction* webkitContextMenuGActionNew(const char*, const WebKit::WebContextMenuItemData&);
51+
void webkitContextMenuGActionSetPage(WebKitContextMenuGAction*, WebKit::WebPageProxy*);
52+
53+
#if PLATFORM(GTK) && !USE(GTK4)
54+
void webkitContextMenuGActionSetGtkAction(WebKitContextMenuGAction*, GtkAction*);
55+
#endif
56+
57+
#endif // ENABLE(CONTEXT_MENUS)

Source/WebKit/SourcesGTK.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ Shared/glib/JavaScriptEvaluationResultGLib.cpp
9090
Shared/glib/ProcessExecutablePathGLib.cpp
9191
Shared/glib/UserMessage.cpp
9292
Shared/glib/WebContextMenuItemGlib.cpp
93+
Shared/glib/WebKitContextMenuGAction.cpp @no-unify
9394

9495
Shared/gtk/ArgumentCodersGtk.cpp
9596
Shared/gtk/NativeWebKeyboardEventGtk.cpp

Source/WebKit/SourcesWPE.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ Shared/glib/JavaScriptEvaluationResultGLib.cpp
8888
Shared/glib/ProcessExecutablePathGLib.cpp
8989
Shared/glib/UserMessage.cpp
9090
Shared/glib/WebContextMenuItemGlib.cpp
91+
Shared/glib/WebKitContextMenuGAction.cpp @no-unify
9192

9293
Shared/libwpe/NativeWebKeyboardEventLibWPE.cpp
9394
Shared/libwpe/NativeWebMouseEventLibWPE.cpp

Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,9 @@ RefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy& pag
312312
}
313313

314314
#if ENABLE(CONTEXT_MENUS)
315-
Ref<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPageProxy& page, FrameInfoData&&, ContextMenuContextData&& context, const UserData& userData)
315+
Ref<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPageProxy& page, FrameInfoData&& frameInfo, ContextMenuContextData&& context, const UserData& userData)
316316
{
317-
return WebContextMenuProxyWPE::create(page, WTF::move(context), userData);
317+
return WebContextMenuProxyWPE::create(page, WTF::move(frameInfo), WTF::move(context), userData);
318318
}
319319
#endif
320320

0 commit comments

Comments
 (0)