popup fallback: mount bar menus at output origin only for foreign clients
Parentless xdg_popups (menus opened by layer-shell bars such as wf-panel-pi) must hang off the output-origin popup tree so they render flush under the bar instead of being shifted down by the bar's reserved edge. But a parentless popup from the active tab's own client (an in-tab menu whose parent surface was missed) must keep hanging under that window's tree to preserve its old alignment. Resolve the popup client's pid and choose the mount accordingly; same-client popups keep the window tree, foreign clients get the origin tree. Also add two KICK_LOG_DEBUG signals the deterministic regression test keys on: [layer] map pid=N when a layer surface maps (the bar is ready for input) and [popup] out=x,y geo=w x h pcpid=N with the popup's scene-exact output position once it maps. test_smoke.py's test_panel_menu_flush_under_bar waits on those lines (no pixel diffing, no fixed sleeps) and asserts the wf-panel-pi menu's output top is flush under the 52px bar; against a build with the fix reverted it fails with the menu at y=109.
This commit is contained in:
parent
ebae43242f
commit
e539be4338
2 changed files with 116 additions and 16 deletions
73
kick.c
73
kick.c
|
|
@ -354,10 +354,11 @@ struct kick_server {
|
|||
struct wlr_layer_shell_v1 *layer_shell;
|
||||
struct wl_listener new_layer_surface;
|
||||
struct wlr_scene_tree *layer_tree;
|
||||
/* Parentless xdg_popups (menus/tooltips from a client without a live
|
||||
toplevel parent, e.g. GTK layer-shell bars) hang off this dedicated
|
||||
scene tree so they map at the output origin instead of inheriting a
|
||||
tab tree's bar-offset. Kept on top like layer_tree. */
|
||||
/* xdg_popups from foreign clients (a layer-shell bar such as wf-panel-pi)
|
||||
that have no live kick-managed parent hang off this dedicated scene
|
||||
tree, rooted at the output origin, so their positioner geometry maps to
|
||||
real pixels instead of inheriting a tab tree's bar-offset. Kept on top
|
||||
like layer_tree. */
|
||||
struct wlr_scene_tree *popup_tree;
|
||||
/* Layer surfaces, in reservation order (head = highest layer / lowest
|
||||
overlap priority); see kick_layer. */
|
||||
|
|
@ -4248,6 +4249,21 @@ static void popup_handle_commit(struct wl_listener *listener, void *data) {
|
|||
popup_usable_box(&box);
|
||||
wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box);
|
||||
}
|
||||
/* Once the popup maps, report its output-space top-left and size. Tests
|
||||
key on this line to assert a bar's menu hung flush under the bar; the
|
||||
coordinates are scene-exact (no wall-clock guesswork). */
|
||||
if (xdg_surface->surface->mapped && tp->scene) {
|
||||
int lx = 0, ly = 0;
|
||||
wlr_scene_node_coords(&tp->scene->node, &lx, &ly);
|
||||
pid_t pcpid = -1;
|
||||
if (xdg_surface->client && xdg_surface->client->client)
|
||||
wl_client_get_credentials(xdg_surface->client->client,
|
||||
&pcpid, NULL, NULL);
|
||||
kick_log(KICK_LOG_DEBUG,
|
||||
"[popup] out=%d,%d geo=%dx%d pcpid=%d\n", lx, ly,
|
||||
xdg_surface->geometry.width, xdg_surface->geometry.height,
|
||||
pcpid);
|
||||
}
|
||||
}
|
||||
|
||||
static void popup_handle_reposition(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -4350,19 +4366,34 @@ found:
|
|||
a window that closed, or a non-tab surface such as a layer-shell bar).
|
||||
Rather than drop the popup -- which would leave the client waiting
|
||||
forever for its initial configure ("Timed out waiting for initial
|
||||
.configure") -- fall back to the currently-displayed window's tree so
|
||||
the popup still gets rendered and configured. */
|
||||
.configure") -- fall back so the popup still gets rendered and
|
||||
configured, choosing the mount by which client made it:
|
||||
* a parentless popup from the active tab's own client still hangs
|
||||
under that window's (bar-offset) tree, keeping it aligned with the
|
||||
app's content just as before; and
|
||||
* a popup from any other client (a layer-shell bar such as
|
||||
wf-panel-pi, or a gone/foreign surface) maps at the output origin
|
||||
so its positioner geometry lands on real pixels instead of being
|
||||
shifted down/right past the bar's reserved edge. */
|
||||
if (!parent_tree) {
|
||||
kick_log(KICK_LOG_DEBUG,
|
||||
"[popup] parent %p not live; hanging popup under popup tree "
|
||||
"at output origin\n",
|
||||
(void *)parent_ws);
|
||||
/* No live kick-managed parent. These are popups whose parent was a
|
||||
layer-shell bar or a gone window. Map them under the root-level
|
||||
popup_tree so their positioner geometry lands at the real output
|
||||
coordinates (bars' menus would otherwise be shifted down by the
|
||||
bar's reserved edge from hanging under an offset window tree). */
|
||||
parent_tree = server.popup_tree;
|
||||
pid_t pcpid = -1;
|
||||
if (popup->base->client)
|
||||
wl_client_get_credentials(popup->base->client->client,
|
||||
&pcpid, NULL, NULL);
|
||||
struct kick_window *cur = tab_current_window(server.active_tab);
|
||||
if (cur && cur->client_pid > 0 && cur->client_pid == pcpid) {
|
||||
kick_log(KICK_LOG_DEBUG,
|
||||
"[popup] parent %p not live; reusing active window tree "
|
||||
"for same-client popup\n",
|
||||
(void *)parent_ws);
|
||||
parent_tree = popup_tree_for_window(cur);
|
||||
} else {
|
||||
kick_log(KICK_LOG_DEBUG,
|
||||
"[popup] parent %p not live; hanging popup under popup "
|
||||
"tree at output origin\n",
|
||||
(void *)parent_ws);
|
||||
parent_tree = server.popup_tree;
|
||||
}
|
||||
}
|
||||
if (!parent_tree) return;
|
||||
create_popup(popup, parent_tree);
|
||||
|
|
@ -4522,6 +4553,16 @@ static void layer_handle_commit(struct wl_listener *listener, void *data) {
|
|||
(void)data;
|
||||
struct kick_layer *sl = wl_container_of(listener, sl, commit);
|
||||
bool mapped = sl->surface->surface->mapped;
|
||||
/* Deterministic "the bar is on screen" signal for tests: fires on the
|
||||
commit that maps a layer surface, including a first-commit map. */
|
||||
if (mapped && !sl->mapped) {
|
||||
pid_t pid = -1;
|
||||
if (sl->surface->resource)
|
||||
wl_client_get_credentials(
|
||||
wl_resource_get_client(sl->surface->resource),
|
||||
&pid, NULL, NULL);
|
||||
kick_log(KICK_LOG_DEBUG, "[layer] map pid=%d\n", pid);
|
||||
}
|
||||
if (!sl->seen_init) {
|
||||
/* First commit. wlroots' layer_surface_role_commit runs first and
|
||||
sets surface->initialized, so this is the earliest point we may call
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue