wayland: fix click-through and focus-toggle on overlapping windows
view_surface_at iterated toplevel_list in reverse using geometry alone to find the view under the cursor. toplevel_list order is maintained separately from scene Z-order: handle_pointer_button updated it on click but stacking operations (wl_stacking_restack, wl_stacking_raise/lower) did not. After any stacking operation the list order and visual order diverged, so successive clicks at the same position returned different views, causing focus to toggle between overlapping windows. Fix: use wlr_scene_node_at as the authority on what is visually topmost, then walk up to the fb->tree / window-root level (stopping when the parent is a level_trees[] bucket), and scan toplevel_list only for the ID-to-surface mapping of the matched node. This is the same approach already used by frame_buf_at after the level-tree rewrite. The scene graph is the single source of truth for Z-order.
This commit is contained in:
parent
245d0077b5
commit
a961c86d4b
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue