diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index aa5b216..2e9b4c5 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -287,6 +287,7 @@ struct wl_frame_buf { struct wlr_buffer base; /* wlr_buffer (must be first) */ pixman_image_t *image; /* ARGB32 pixel data */ struct wlr_scene_buffer *scene_buf; /* scene graph node */ + struct wlr_scene_tree *tree; /* grouping tree (top-level frames only) */ WNativeWindow id; /* synthetic ID (>= 0x10000000) */ WNativeWindow parent_id; /* parent frame_buf ID (0 = root) */ int x, y; /* position in output coords */ @@ -3766,6 +3767,8 @@ frame_buf_find(WNativeWindow id) static struct wl_frame_buf * frame_buf_at(int px, int py) { + /* Find the topmost frame_buf at this position, but only if no client + * surface from a DIFFERENT window is above it in the scene graph. */ struct wl_frame_buf *hit = NULL; struct wl_frame_buf *fb; wl_list_for_each(fb, &wl_state.frame_list, link) { @@ -3778,6 +3781,35 @@ frame_buf_at(int px, int py) hit = fb; } } + if (!hit) return NULL; + + /* Check if a client surface from a DIFFERENT window is above us */ + if (wl_state.scene) { + double sx, sy; + struct wlr_scene_node *node = wlr_scene_node_at( + &wl_state.scene->tree.node, px, py, &sx, &sy); + if (node) { + /* Find which tree this node belongs to */ + struct wlr_scene_node *n = node; + while (n->parent && &n->parent->node != &wl_state.scene->tree.node) + n = &n->parent->node; + /* Find which tree our hit frame_buf belongs to */ + struct wlr_scene_node *h = &hit->scene_buf->node; + while (h->parent && &h->parent->node != &wl_state.scene->tree.node) + h = &h->parent->node; + /* Same tree = same window, allow the hit */ + if (n == h) + return hit; + /* Different tree: check if topmost is a frame_buf */ + struct wl_frame_buf *fb2; + wl_list_for_each(fb2, &wl_state.frame_list, link) { + if (fb2->scene_buf && &fb2->scene_buf->node == node) + return fb2; + } + /* Topmost node is a client surface from another window */ + return NULL; + } + } return hit; } @@ -3817,13 +3849,17 @@ wl_frame_create_toplevel(WScreen *scr, fb->width = width; fb->height = height; - /* Create scene buffer node. */ + /* Create scene buffer node under a per-window tree. */ if (wl_state.scene) { - fb->scene_buf = wlr_scene_buffer_create(&wl_state.scene->tree, - &fb->base); - if (fb->scene_buf) { - wlr_scene_node_set_position(&fb->scene_buf->node, x, y); - wlr_scene_node_set_enabled(&fb->scene_buf->node, false); + fb->tree = wlr_scene_tree_create(&wl_state.scene->tree); + if (fb->tree) { + wlr_scene_node_set_position(&fb->tree->node, 0, 0); + fb->scene_buf = wlr_scene_buffer_create(fb->tree, &fb->base); + if (fb->scene_buf) { + wlr_scene_node_set_position(&fb->scene_buf->node, x, y); + wlr_scene_node_set_enabled(&fb->scene_buf->node, false); + } + wlr_scene_node_set_enabled(&fb->tree->node, true); } } @@ -3870,8 +3906,9 @@ wl_frame_create_child(WNativeWindow parent_win, WScreen *scr, fb->height = height; if (wl_state.scene) { - fb->scene_buf = wlr_scene_buffer_create(&wl_state.scene->tree, - &fb->base); + struct wlr_scene_tree *ptree = (parent && parent->tree) + ? parent->tree : &wl_state.scene->tree; + fb->scene_buf = wlr_scene_buffer_create(ptree, &fb->base); if (fb->scene_buf) { wlr_scene_node_set_position(&fb->scene_buf->node, abs_x, abs_y); wlr_scene_node_set_enabled(&fb->scene_buf->node, false); @@ -4839,9 +4876,6 @@ handle_pointer_button(struct wl_listener *listener, void *data) * pointer and focus + raise it via the WM policy layer. * This mirrors what the X11 backend does via ButtonPress on frame windows. */ if (ev->state == WLR_BUTTON_PRESSED) { - /* If pointer is over WM chrome (menu, titlebar), don't raise clients */ - if (frame_buf_at(wl_state.pointer_x, wl_state.pointer_y)) - goto deliver; double sx, sy; struct wl_toplevel_view *view = NULL; view_surface_at(wl_state.pointer_x, wl_state.pointer_y, @@ -4853,21 +4887,24 @@ handle_pointer_button(struct wl_listener *listener, void *data) WWindow *wwin = (WWindow *)desc->parent; WScreen *scr = wScreenWithNumber(0); wSetFocusTo(scr, wwin); - /* Raise the window in scene Z-order by moving its scene node - * to the top of the scene root's child list. */ - if (view->scene_node) + /* Raise entire window assembly via tree */ + if (view->frame_id) { + struct wl_frame_buf *fb = frame_buf_find(view->frame_id); + if (fb && fb->tree) + wlr_scene_node_raise_to_top(&fb->tree->node); + } else if (view->scene_node) { wlr_scene_node_raise_to_top(&view->scene_node->node); + } /* Also raise it in our toplevel list so view_surface_at() * returns it first on subsequent hits. */ wl_list_remove(&view->link); - wl_list_insert(wl_state.toplevel_list.prev, &view->link); + wl_list_insert(&wl_state.toplevel_list, &view->link); wwarning("wl_backend: click focus id=0x%lx", view->id); } } } /* Phase A: enqueue native WMEvent for WINGs */ -deliver:; WMScreen *wmscr = wl_get_wmscreen(); if (wmscr) { WMEvent wev; @@ -5382,13 +5419,24 @@ wl_stacking_raise(WNativeWindow win) if (v) { wl_list_remove(&v->link); wl_list_insert(&wl_state.toplevel_list, &v->link); + if (v->frame_id) { + struct wl_frame_buf *fb = frame_buf_find(v->frame_id); + if (fb && fb->tree) { + wlr_scene_node_raise_to_top(&fb->tree->node); + return; + } + } if (v->scene_node) wlr_scene_node_raise_to_top(&v->scene_node->node); return; } struct wl_frame_buf *fb = frame_buf_find(win); - if (fb && fb->scene_buf) { - wlr_scene_node_raise_to_top(&fb->scene_buf->node); + if (fb) { + if (fb->tree) { + wlr_scene_node_raise_to_top(&fb->tree->node); + } else if (fb->scene_buf) { + wlr_scene_node_raise_to_top(&fb->scene_buf->node); + } return; } } @@ -5414,13 +5462,46 @@ wl_stacking_lower(WNativeWindow win) static void wl_stacking_restack(WNativeWindow *windows, int count) { - /* Phase 58: reorder toplevel_list to match the given Z-order array. */ + /* Reorder scene graph to match the WM's stacking order. + * Array is top-to-bottom. Process bottom-to-top so raise_to_top + * puts the first element on top last. */ int i; for (i = count - 1; i >= 0; i--) { - struct wl_toplevel_view *v = wl_find_view_by_id(windows[i]); - if (!v) continue; - wl_list_remove(&v->link); - wl_list_insert(&wl_state.toplevel_list, &v->link); + WNativeWindow win = windows[i]; + struct wl_frame_buf *fb = frame_buf_find(win); + if (fb && fb->scene_buf) { + wlr_scene_node_raise_to_top(&fb->scene_buf->node); + /* Raise client surface inside this frame */ + struct wl_toplevel_view *cv; + wl_list_for_each(cv, &wl_state.toplevel_list, link) { + if (cv->frame_id == win && cv->scene_node) { + wlr_scene_node_raise_to_top(&cv->scene_node->node); + break; + } + } + /* Also try via WM context */ + WObjDescriptor *desc = wm_backend->context_find(win, WM_CTX_CLIENT_WIN); + if (desc && desc->parent_type == WCLASS_WINDOW) { + WWindow *wwin = (WWindow *)desc->parent; + struct wl_toplevel_view *v = wl_find_view_by_id(wwin->client_win); + if (v && v->scene_node) + wlr_scene_node_raise_to_top(&v->scene_node->node); + } + /* Raise children (titlebar, resizebar) on top */ + struct wl_frame_buf *child; + wl_list_for_each(child, &wl_state.frame_list, link) { + if (child->parent_id == win && child->scene_buf) + wlr_scene_node_raise_to_top(&child->scene_buf->node); + } + continue; + } + struct wl_toplevel_view *v = wl_find_view_by_id(win); + if (v) { + wl_list_remove(&v->link); + wl_list_insert(&wl_state.toplevel_list, &v->link); + if (v->scene_node) + wlr_scene_node_raise_to_top(&v->scene_node->node); + } } } @@ -5673,20 +5754,20 @@ wl_window_map(WNativeWindow win) return; /* parent not visible yet */ } wlr_scene_node_set_enabled(&fb->scene_buf->node, true); - wlr_scene_node_raise_to_top(&fb->scene_buf->node); + /* Raise the tree (raises entire window assembly together) */ + if (fb->tree) + wlr_scene_node_raise_to_top(&fb->tree->node); + else if (!fb->parent_id) + wlr_scene_node_raise_to_top(&fb->scene_buf->node); /* Also enable children (and grandchildren) */ struct wl_frame_buf *child; wl_list_for_each(child, &wl_state.frame_list, link) { if (child->parent_id == win && child->scene_buf) { wlr_scene_node_set_enabled(&child->scene_buf->node, true); - wlr_scene_node_raise_to_top(&child->scene_buf->node); - /* Enable grandchildren */ struct wl_frame_buf *gc; wl_list_for_each(gc, &wl_state.frame_list, link) { - if (gc->parent_id == child->id && gc->scene_buf) { + if (gc->parent_id == child->id && gc->scene_buf) wlr_scene_node_set_enabled(&gc->scene_buf->node, true); - wlr_scene_node_raise_to_top(&gc->scene_buf->node); - } } } } @@ -5700,13 +5781,23 @@ wl_window_map_raised(WNativeWindow win) struct wl_toplevel_view *v = wl_find_view_by_id(win); if (v && v->scene_node) { wlr_scene_node_set_enabled(&v->scene_node->node, true); + if (v->frame_id) { + struct wl_frame_buf *fb = frame_buf_find(v->frame_id); + if (fb && fb->tree) { + wlr_scene_node_raise_to_top(&fb->tree->node); + return; + } + } wlr_scene_node_raise_to_top(&v->scene_node->node); return; } struct wl_frame_buf *fb = frame_buf_find(win); if (fb && fb->scene_buf) { wlr_scene_node_set_enabled(&fb->scene_buf->node, true); - wlr_scene_node_raise_to_top(&fb->scene_buf->node); + if (fb->tree) + wlr_scene_node_raise_to_top(&fb->tree->node); + else + wlr_scene_node_raise_to_top(&fb->scene_buf->node); return; } } @@ -6014,8 +6105,12 @@ wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y) if (parent_fb) { v->x = parent_fb->x + x; v->y = parent_fb->y + y; - if (v->scene_node) + if (v->scene_node) { + /* Move client's scene tree under the frame's tree */ + if (parent_fb->tree) + wlr_scene_node_reparent(&v->scene_node->node, parent_fb->tree); wlr_scene_node_set_position(&v->scene_node->node, v->x, v->y); + } } return; } diff --git a/src/stacking.c b/src/stacking.c index c548d62..c1efbbd 100644 --- a/src/stacking.c +++ b/src/stacking.c @@ -206,6 +206,8 @@ void wRaiseFrame(WCoreWindow * frame) /* already on top */ if (frame->stacking->above == NULL) { + /* Still notify backend to sync scene graph */ + wm_backend->stacking_raise(frame->window); return; }