From 0356a020c1c14b4f9e9c3583d6a87dd7764714a2 Mon Sep 17 00:00:00 2001 From: "Lars-Ragnar A. Haugen" Date: Thu, 26 Feb 2026 16:34:37 +0100 Subject: [PATCH] layer-shell: handle popup reposition for unconstraining Layer shell popups were missing a handler for the xdg_popup reposition event. When a client (e.g. GTK4) creates a popup and then sends a reposition request, wlroots resets the scheduled geometry back to the positioner's original value. Without a reposition handler, the unconstrained geometry computed on the initial commit was lost, causing popups such as tooltips to render outside the screen viewport. This was most visible with GTK4 layer shell apps (e.g. taskbars) where tooltips would appear below the bottom edge of the screen instead of being flipped/slid into the visible area. Also switch the destroy listener from wlr_popup->base->events.destroy to wlr_popup->events.destroy so that cleanup runs before wlroots asserts that all popup signal listeners have been removed. Fixes #8518 --- include/sway/layers.h | 1 + sway/desktop/layer_shell.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/sway/layers.h b/include/sway/layers.h index 27b5dde1b..e257da0bd 100644 --- a/include/sway/layers.h +++ b/include/sway/layers.h @@ -33,6 +33,7 @@ struct sway_layer_popup { struct wl_listener destroy; struct wl_listener new_popup; struct wl_listener commit; + struct wl_listener reposition; }; struct sway_output; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 8c54d71aa..c8f485971 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -321,6 +321,7 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->new_popup.link); wl_list_remove(&popup->commit.link); + wl_list_remove(&popup->reposition.link); free(popup); } @@ -356,6 +357,11 @@ static void popup_handle_commit(struct wl_listener *listener, void *data) { } } +static void popup_handle_reposition(struct wl_listener *listener, void *data) { + struct sway_layer_popup *popup = wl_container_of(listener, popup, reposition); + popup_unconstrain(popup); +} + static void popup_handle_new_popup(struct wl_listener *listener, void *data); static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup, @@ -376,11 +382,13 @@ static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup, } popup->destroy.notify = popup_handle_destroy; - wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); + wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); popup->new_popup.notify = popup_handle_new_popup; wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); popup->commit.notify = popup_handle_commit; wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); + popup->reposition.notify = popup_handle_reposition; + wl_signal_add(&wlr_popup->events.reposition, &popup->reposition); return popup; }