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.
This commit is contained in:
novenary 2023-03-02 17:47:59 +02:00
parent 7669241754
commit 5d2888cb67
4 changed files with 31 additions and 3 deletions

View file

@ -171,6 +171,7 @@ struct sway_xwayland_unmanaged {
struct wl_list link; struct wl_list link;
int lx, ly; int lx, ly;
bool visible;
struct wl_listener request_activate; struct wl_listener request_activate;
struct wl_listener request_configure; struct wl_listener request_configure;
@ -181,6 +182,7 @@ struct sway_xwayland_unmanaged {
struct wl_listener unmap; struct wl_listener unmap;
struct wl_listener destroy; struct wl_listener destroy;
struct wl_listener override_redirect; struct wl_listener override_redirect;
struct wl_listener set_parent;
}; };
#endif #endif
struct sway_view_child; struct sway_view_child;

View file

@ -239,6 +239,9 @@ void output_unmanaged_for_each_surface(struct sway_output *output,
void *user_data) { void *user_data) {
struct sway_xwayland_unmanaged *unmanaged_surface; struct sway_xwayland_unmanaged *unmanaged_surface;
wl_list_for_each(unmanaged_surface, unmanaged, link) { wl_list_for_each(unmanaged_surface, unmanaged, link) {
if (!unmanaged_surface->visible) {
continue;
}
struct wlr_xwayland_surface *xsurface = struct wlr_xwayland_surface *xsurface =
unmanaged_surface->wlr_xwayland_surface; unmanaged_surface->wlr_xwayland_surface;
double ox = unmanaged_surface->lx - output->lx; double ox = unmanaged_surface->lx - output->lx;

View file

@ -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->destroy.link);
wl_list_remove(&surface->override_redirect.link); wl_list_remove(&surface->override_redirect.link);
wl_list_remove(&surface->request_activate.link); wl_list_remove(&surface->request_activate.link);
wl_list_remove(&surface->set_parent.link);
free(surface); 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( static struct sway_xwayland_unmanaged *create_unmanaged(
struct wlr_xwayland_surface *xsurface) { struct wlr_xwayland_surface *xsurface) {
struct sway_xwayland_unmanaged *surface = struct sway_xwayland_unmanaged *surface =
@ -196,6 +215,9 @@ static struct sway_xwayland_unmanaged *create_unmanaged(
surface->override_redirect.notify = unmanaged_handle_override_redirect; surface->override_redirect.notify = unmanaged_handle_override_redirect;
wl_signal_add(&xsurface->events.request_activate, &surface->request_activate); wl_signal_add(&xsurface->events.request_activate, &surface->request_activate);
surface->request_activate.notify = unmanaged_handle_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; return surface;
} }
@ -263,9 +285,6 @@ static uint32_t configure(struct sway_view *view, double lx, double ly, int widt
return 0; 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) { static void set_activated(struct sway_view *view, bool activated) {
if (xwayland_view_from_view(view) == NULL) { if (xwayland_view_from_view(view) == NULL) {
return; return;
@ -287,6 +306,7 @@ static void set_activated(struct sway_view *view, bool activated) {
if (!is_surface_transient_for(unmanaged_surface, view)) { if (!is_surface_transient_for(unmanaged_surface, view)) {
continue; continue;
} }
unmanaged->visible = activated;
if (activated) { if (activated) {
wlr_xwayland_surface_restack(unmanaged_surface, NULL, XCB_STACK_MODE_ABOVE); wlr_xwayland_surface_restack(unmanaged_surface, NULL, XCB_STACK_MODE_ABOVE);
} }

View file

@ -124,6 +124,9 @@ struct sway_node *node_at_coords(
struct wl_list *unmanaged = &root->xwayland_unmanaged; struct wl_list *unmanaged = &root->xwayland_unmanaged;
struct sway_xwayland_unmanaged *unmanaged_surface; struct sway_xwayland_unmanaged *unmanaged_surface;
wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) { wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) {
if (!unmanaged_surface->visible) {
continue;
}
struct wlr_xwayland_surface *xsurface = struct wlr_xwayland_surface *xsurface =
unmanaged_surface->wlr_xwayland_surface; unmanaged_surface->wlr_xwayland_surface;