diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 85971f0..fc3f031 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -5131,37 +5131,62 @@ static struct wlr_surface * view_surface_at(int px, int py, double *sx_out, double *sy_out, struct wl_toplevel_view **view_out) { - struct wl_toplevel_view *v; - wl_list_for_each_reverse(v, &wl_state.toplevel_list, link) { - double sx = px - (double)v->x; - double sy = py - (double)v->y; + /* Use wlr_scene_node_at as the authority on what is visually + * topmost at (px,py). The old geometry-scan loop over + * toplevel_list caused toggling focus on overlapping windows + * because toplevel_list order diverged from scene Z-order. */ + if (!wl_state.scene) return NULL; - /* Phase 17: XWayland window — simple bounds check on the surface. */ - if (v->xw_surface) { - if (!v->xw_surface->surface || !v->xw_surface->surface->mapped) - continue; - if (sx >= 0 && sy >= 0 && - sx < (double)v->xw_surface->width && - sy < (double)v->xw_surface->height) { - if (sx_out) *sx_out = sx; - if (sy_out) *sy_out = sy; - if (view_out) *view_out = v; - return v->xw_surface->surface; - } - continue; + double _sx, _sy; + struct wlr_scene_node *node = wlr_scene_node_at( + &wl_state.scene->tree.node, (double)px, (double)py, &_sx, &_sy); + if (!node) return NULL; + + /* Walk up until parent is a level_tree bucket: that node is + * fb->tree (framed) or v->scene_node (unframed). */ + struct wlr_scene_node *n = node; + while (n->parent && &n->parent->node != &wl_state.scene->tree.node) { + int _bucket = 0, _li; + for (_li = 0; _li < WL_NUM_LEVEL_BUCKETS; _li++) { + if (wl_state.level_trees[_li] && n->parent == wl_state.level_trees[_li]) + { _bucket = 1; break; } } + if (_bucket) break; + n = &n->parent->node; + } - /* XDG toplevel path. */ - if (!v->xdg_surface || !v->xdg_surface->surface || !v->xdg_surface->surface->mapped) - continue; - double sub_sx, sub_sy; - struct wlr_surface *sub = wlr_xdg_surface_surface_at( - v->xdg_surface, sx, sy, &sub_sx, &sub_sy); - if (sub) { - if (sx_out) *sx_out = sub_sx; - if (sy_out) *sy_out = sub_sy; + struct wl_toplevel_view *v; + wl_list_for_each(v, &wl_state.toplevel_list, link) { + /* Framed window: resolve via the fb->tree node. */ + int match = 0; + if (v->frame_id) { + struct wl_frame_buf *_fb = frame_buf_find(v->frame_id); + match = (_fb && _fb->tree && &_fb->tree->node == n); + } else { + match = (v->scene_node && &v->scene_node->node == n); + } + if (!match) continue; + + if (v->xw_surface && v->xw_surface->surface) { + double sx = px - (double)v->x; + double sy = py - (double)v->y; + if (sx_out) *sx_out = sx; + if (sy_out) *sy_out = sy; if (view_out) *view_out = v; - return sub; + return v->xw_surface->surface; + } + if (v->xdg_surface) { + double sx = px - (double)v->x; + double sy = py - (double)v->y; + double sub_sx, sub_sy; + struct wlr_surface *sub = wlr_xdg_surface_surface_at( + v->xdg_surface, sx, sy, &sub_sx, &sub_sy); + if (sub) { + if (sx_out) *sx_out = sub_sx; + if (sy_out) *sy_out = sub_sy; + if (view_out) *view_out = v; + return sub; + } } } return NULL;