From 5d2888cb671913394c87ef4e896985b536e5adcf Mon Sep 17 00:00:00 2001 From: novenary Date: Thu, 2 Mar 2023 17:47:59 +0200 Subject: [PATCH] xwayland: track visibility of OR children OR windows with WM_TRANSIENT_FOR have similar semantics to xdg_popup. We can't handle them in the same path because we have to keep in sync with the X stack, and popups are rendered above unmanaged surfaces. --- include/sway/tree/view.h | 2 ++ sway/desktop/output.c | 3 +++ sway/desktop/xwayland.c | 26 +++++++++++++++++++++++--- sway/input/cursor.c | 3 +++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 7fc2d95d8..7ee29c6ce 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -171,6 +171,7 @@ struct sway_xwayland_unmanaged { struct wl_list link; int lx, ly; + bool visible; struct wl_listener request_activate; struct wl_listener request_configure; @@ -181,6 +182,7 @@ struct sway_xwayland_unmanaged { struct wl_listener unmap; struct wl_listener destroy; struct wl_listener override_redirect; + struct wl_listener set_parent; }; #endif struct sway_view_child; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 0c8a5fd41..cd0922a88 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -239,6 +239,9 @@ void output_unmanaged_for_each_surface(struct sway_output *output, void *user_data) { struct sway_xwayland_unmanaged *unmanaged_surface; wl_list_for_each(unmanaged_surface, unmanaged, link) { + if (!unmanaged_surface->visible) { + continue; + } struct wlr_xwayland_surface *xsurface = unmanaged_surface->wlr_xwayland_surface; double ox = unmanaged_surface->lx - output->lx; diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index cdad49888..722019a6d 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -147,6 +147,7 @@ static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&surface->destroy.link); wl_list_remove(&surface->override_redirect.link); wl_list_remove(&surface->request_activate.link); + wl_list_remove(&surface->set_parent.link); free(surface); } @@ -172,6 +173,24 @@ static void unmanaged_handle_override_redirect(struct wl_listener *listener, voi } } +static bool is_surface_transient_for(struct wlr_xwayland_surface *surface, + struct sway_view *ancestor); + +static void unmanaged_handle_set_parent(struct wl_listener *listener, void *data) { + struct sway_xwayland_unmanaged *surface = wl_container_of(listener, surface, set_parent); + struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; + + if (xsurface->parent != NULL) { + struct sway_seat *seat = input_manager_current_seat(); + struct sway_container *focus = seat_get_focused_container(seat); + surface->visible = focus && focus->view + && focus->view->type == SWAY_VIEW_XWAYLAND + && is_surface_transient_for(xsurface, focus->view); + } else { + surface->visible = true; + } +} + static struct sway_xwayland_unmanaged *create_unmanaged( struct wlr_xwayland_surface *xsurface) { struct sway_xwayland_unmanaged *surface = @@ -196,6 +215,9 @@ static struct sway_xwayland_unmanaged *create_unmanaged( surface->override_redirect.notify = unmanaged_handle_override_redirect; wl_signal_add(&xsurface->events.request_activate, &surface->request_activate); surface->request_activate.notify = unmanaged_handle_request_activate; + wl_signal_add(&xsurface->events.set_parent, &surface->set_parent); + surface->set_parent.notify = unmanaged_handle_set_parent; + unmanaged_handle_set_parent(&surface->set_parent, xsurface); return surface; } @@ -263,9 +285,6 @@ static uint32_t configure(struct sway_view *view, double lx, double ly, int widt return 0; } -static bool is_surface_transient_for(struct wlr_xwayland_surface *surface, - struct sway_view *ancestor); - static void set_activated(struct sway_view *view, bool activated) { if (xwayland_view_from_view(view) == NULL) { return; @@ -287,6 +306,7 @@ static void set_activated(struct sway_view *view, bool activated) { if (!is_surface_transient_for(unmanaged_surface, view)) { continue; } + unmanaged->visible = activated; if (activated) { wlr_xwayland_surface_restack(unmanaged_surface, NULL, XCB_STACK_MODE_ABOVE); } diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 15687993b..fd4641ca4 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -124,6 +124,9 @@ struct sway_node *node_at_coords( struct wl_list *unmanaged = &root->xwayland_unmanaged; struct sway_xwayland_unmanaged *unmanaged_surface; wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) { + if (!unmanaged_surface->visible) { + continue; + } struct wlr_xwayland_surface *xsurface = unmanaged_surface->wlr_xwayland_surface;