fix --panel menu offset: mount parentless popups at output origin

Bars (wf-panel-pi) open menus as parentless xdg_popup surfaces. kick's
fallback previously hung them under the active window's scene tree,
which is offset past the bar's reserved edge (server.layout_y), so the
menu rendered a full panel-height too low.

Add a dedicated popup_tree scene tree rooted at the output origin: it is
created at scene setup, kept raised to top alongside layer_tree, and used
as the mount point for parentless popups so their positioner geometry
maps to real output coordinates.
This commit is contained in:
Andrew Hamilton 2026-09-01 23:18:12 +10:00
parent 7605187c43
commit ebae43242f

22
kick.c
View file

@ -354,6 +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. */
struct wlr_scene_tree *popup_tree;
/* Layer surfaces, in reservation order (head = highest layer / lowest
overlap priority); see kick_layer. */
struct wl_list layer_surfaces;
@ -4349,11 +4354,15 @@ found:
the popup still gets rendered and configured. */
if (!parent_tree) {
kick_log(KICK_LOG_DEBUG,
"[popup] parent %p not live; hanging popup under active "
"window tree\n",
"[popup] parent %p not live; hanging popup under popup tree "
"at output origin\n",
(void *)parent_ws);
struct kick_window *cur = tab_current_window(server.active_tab);
parent_tree = popup_tree_for_window(cur);
/* 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;
}
if (!parent_tree) return;
create_popup(popup, parent_tree);
@ -4433,6 +4442,8 @@ static void resize_tabs_to_usable(const struct wlr_box *usable) {
static void layer_raise_above_windows(void) {
if (server.layer_tree)
wlr_scene_node_raise_to_top(&server.layer_tree->node);
if (server.popup_tree)
wlr_scene_node_raise_to_top(&server.popup_tree->node);
}
/* Layer orders for the two configure passes, mirroring labwc's
@ -9164,6 +9175,9 @@ int main(int argc, char *argv[]) {
never interfere. */
wl_list_init(&server.layer_surfaces);
server.layer_tree = wlr_scene_tree_create(&server.scene->tree);
/* Dedicated tree for parentless popups (bars' menus): rooted at the
output origin so their geometry maps directly to pixels. */
server.popup_tree = wlr_scene_tree_create(&server.scene->tree);
server.layer_shell = wlr_layer_shell_v1_create(server.wl_display, 3);
server.new_layer_surface.notify = handle_new_layer_surface;
wl_signal_add(&server.layer_shell->events.new_surface,