This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch wl/browser-all
in repository enlightenment.
View the commit online.
commit fc7dab220d430efd17a4bce180291c30efb50143
Author: Cedric BAIL <[email protected]>
AuthorDate: Mon Aug 10 09:50:03 2026 -0600
wl_desktop_shell - a new toplevel ends any open menu
xdg-shell expects a grabbing popup to be dismissed when a new toplevel
turns up: the menu the user opened is not what the pointer and keyboard
belong to any more, and a client that is never told will sit there
holding a grab over an unrelated window.
E had the machinery and half the rule. e_comp_wl_grab_client_add()
already dismissed outstanding grabs when a *new grab* arrived from a
different toplevel; nothing covered a toplevel merely being created.
Factor that block out and call it from every shell's toplevel path.
Every shell, not just xdg: wlcs asks the compositor for a surface using
whichever shell it advertises and prefers wl_shell, so hooking xdg alone
fixed nothing and measured as such.
Dismiss when the role is taken rather than on map. A client is entitled
to sit on its first configure for as long as it likes, and a menu left
grabbing the keyboard in the meantime is exactly the stuck menu the grab
protocol exists to avoid - the test also measures the created case, and
map was too late for it.
XdgPopupTest: 13 passed / 4 failed -> 15 / 2. The two left are
popup_gives_up_pointer_focus_when_gone, which is the surface-unmap
cluster rather than anything to do with grabs.
Verified against the same wlcs filter on the branch point, 262 tests
across popup, surface, toplevel, wl_shell, subsurface and pointer: four
fixed, no regressions.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FtoiXoSKUmZb6Aix6U3GZS
---
src/bin/e_comp_wl.c | 44 ++++++++++++++++++++++++---------
src/bin/e_comp_wl.h | 1 +
src/modules/wl_desktop_shell/wl_shell.c | 3 +++
src/modules/wl_desktop_shell/xdg.c | 7 ++++++
src/modules/wl_desktop_shell/xdg5.c | 3 +++
src/modules/wl_desktop_shell/xdg6.c | 3 +++
6 files changed, 50 insertions(+), 11 deletions(-)
diff --git a/src/bin/e_comp_wl.c b/src/bin/e_comp_wl.c
index 98f42cf60..a0eaed62c 100644
--- a/src/bin/e_comp_wl.c
+++ b/src/bin/e_comp_wl.c
@@ -3785,22 +3785,44 @@ e_comp_wl_xwayland_client_queue(E_Client *ec)
e_comp_wl->xwl_pending = eina_list_append(e_comp_wl->xwl_pending, ec);
}
+/* Dismiss every outstanding grab, innermost first: grab_clients is prepended
+ * to, so the head is the most recent popup and a nested menu tears down from
+ * the leaf up, which is the order xdg-shell requires the popup_done events in.
+ */
+static void
+_e_comp_wl_grab_clients_dismiss_all(void)
+{
+ E_Client *gec;
+ E_Comp_Wl_Grab_End_Cb grabcb;
+
+ EINA_LIST_FREE(grab_clients, gec)
+ {
+ grabcb = eina_list_data_get(grab_cbs);
+ if (grabcb) grabcb(gec);
+ grab_cbs = eina_list_remove_list(grab_cbs, grab_cbs);
+ }
+}
+
+/* A new toplevel appearing supersedes any popup grab: whatever menu was open
+ * is no longer what the pointer and keyboard belong to, and xdg-shell requires
+ * the grabbing popup be told so it can tear the chain down rather than linger
+ * over an unrelated window. */
+E_API void
+e_comp_wl_grab_clients_dismiss(void)
+{
+ if (!grab_clients) return;
+ _e_comp_wl_grab_clients_dismiss_all();
+ e_bindings_disabled_set(0);
+}
+
E_API void
e_comp_wl_grab_client_add(E_Client *ec, E_Comp_Wl_Grab_End_Cb cb)
{
- E_Client *gec, *parent = e_client_util_top_parent_get(ec);
- E_Comp_Wl_Grab_End_Cb grabcb;
+ E_Client *parent = e_client_util_top_parent_get(ec);
if (grab_clients && (parent != e_client_util_top_parent_get(eina_list_data_get(grab_clients))))
- {
- /* dismiss grabs in order when grabbing from new toplevel */
- EINA_LIST_FREE(grab_clients, gec)
- {
- grabcb = eina_list_data_get(grab_cbs);
- if (grabcb) grabcb(gec);
- grab_cbs = eina_list_remove_list(grab_cbs, grab_cbs);
- }
- }
+ /* dismiss grabs in order when grabbing from new toplevel */
+ _e_comp_wl_grab_clients_dismiss_all();
grab_clients = eina_list_prepend(grab_clients, ec);
grab_cbs = eina_list_prepend(grab_cbs, cb);
ec->comp_data->grab = 1;
diff --git a/src/bin/e_comp_wl.h b/src/bin/e_comp_wl.h
index b01af21d3..3388d74ce 100644
--- a/src/bin/e_comp_wl.h
+++ b/src/bin/e_comp_wl.h
@@ -421,6 +421,7 @@ E_API extern int E_EVENT_WAYLAND_GLOBAL_ADD;
E_API void e_comp_wl_grab_client_add(E_Client *ec, E_Comp_Wl_Grab_End_Cb cb);
E_API void e_comp_wl_grab_client_del(E_Client *ec, Eina_Bool dismiss);
+E_API void e_comp_wl_grab_clients_dismiss(void);
E_API Eina_Bool e_comp_wl_client_is_grabbed(const E_Client *ec);
E_API Eina_Bool e_comp_wl_grab_client_mouse_move(const Ecore_Event_Mouse_Move *ev);
E_API Eina_Bool e_comp_wl_grab_client_mouse_button(const Ecore_Event_Mouse_Button *ev);
diff --git a/src/modules/wl_desktop_shell/wl_shell.c b/src/modules/wl_desktop_shell/wl_shell.c
index 49a709d1e..c7832b872 100644
--- a/src/modules/wl_desktop_shell/wl_shell.c
+++ b/src/modules/wl_desktop_shell/wl_shell.c
@@ -121,6 +121,9 @@ _wl_shell_surface_cb_toplevel_set(struct wl_client *client EINA_UNUSED, struct w
}
if (e_object_is_del(E_OBJECT(ec))) return;
+ /* A new toplevel supersedes any open menu; see the same call in xdg.c. */
+ e_comp_wl_grab_clients_dismiss();
+
/* set toplevel client properties */
ec->icccm.accepts_focus = 1;
if (!ec->internal)
diff --git a/src/modules/wl_desktop_shell/xdg.c b/src/modules/wl_desktop_shell/xdg.c
index 56d13a612..8b652b06f 100644
--- a/src/modules/wl_desktop_shell/xdg.c
+++ b/src/modules/wl_desktop_shell/xdg.c
@@ -1410,6 +1410,13 @@ _e_xdg_surface_cb_toplevel_get(struct wl_client *client EINA_UNUSED, struct wl_r
&_e_xdg_toplevel_interface, ec,
e_shell_surface_cb_destroy);
+ /* A new toplevel supersedes any open menu. Dismiss here, when the role is
+ * taken, rather than on map: the client is entitled to sit on the first
+ * configure for as long as it likes, and a menu left grabbing the keyboard
+ * in the meantime is exactly the stuck-menu the grab protocol exists to
+ * avoid. */
+ e_comp_wl_grab_clients_dismiss();
+
e_object_ref(E_OBJECT(ec));
cdata->shell.configure_send = _e_xdg_shell_surface_configure_send;
diff --git a/src/modules/wl_desktop_shell/xdg5.c b/src/modules/wl_desktop_shell/xdg5.c
index 2109e7fe4..69a9e723b 100644
--- a/src/modules/wl_desktop_shell/xdg5.c
+++ b/src/modules/wl_desktop_shell/xdg5.c
@@ -699,6 +699,9 @@ _e_xdg_shell_cb_surface_get(struct wl_client *client, struct wl_resource *resour
cdata->shell.data = ""
cdata->is_xdg_surface = EINA_TRUE;
+ /* A new toplevel supersedes any open menu; see the same call in xdg.c. */
+ e_comp_wl_grab_clients_dismiss();
+
/* set toplevel client properties */
ec->icccm.accepts_focus = 1;
if (!ec->internal)
diff --git a/src/modules/wl_desktop_shell/xdg6.c b/src/modules/wl_desktop_shell/xdg6.c
index 0e7ed68e7..fa938a771 100644
--- a/src/modules/wl_desktop_shell/xdg6.c
+++ b/src/modules/wl_desktop_shell/xdg6.c
@@ -1256,6 +1256,9 @@ _e_xdg_surface_cb_toplevel_get(struct wl_client *client EINA_UNUSED, struct wl_r
&_e_xdg_toplevel_interface, ec,
e_shell_surface_cb_destroy);
+ /* A new toplevel supersedes any open menu; see the same call in xdg.c. */
+ e_comp_wl_grab_clients_dismiss();
+
e_object_ref(E_OBJECT(ec));
cdata->shell.configure_send = _e_xdg_shell_surface_configure_send;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.