wayland: fix dock ghost shadow z-order (render below icon)

The dock_shadow was rendering above the dragged icon because:
1. It was in WL_LAYER_OVERLAY/DOCK, above the dock icons in WL_LAYER_FLOATING
2. wl_stacking_restack could not order nodes across different parent trees
3. wl_window_map auto-raised on map, undoing any prior restack

Fixes:
- Place dock_shadow in WL_LAYER_FLOATING (where WMDockLevel=5 maps)
- Rewrite wl_stacking_restack to reparent nodes into the same tree
  and use wlr_scene_node_place_below for guaranteed ordering
- Remove auto-raise from wl_window_map (explicit wRaiseFrame handles it)
This commit is contained in:
lkn 2026-06-21 18:49:19 +02:00
parent c90355b663
commit ec0a94e077
3 changed files with 28 additions and 25 deletions

View File

@ -503,8 +503,8 @@ wl_screen_create_internals(WScreen *scr)
dsfb->id = wl_state.next_synthetic_id++;
dsfb->width = sz;
dsfb->height = sz;
struct wlr_scene_tree *ds_parent = wl_state.level_trees[WL_LAYER_NORMAL]
? wl_state.level_trees[WL_LAYER_NORMAL] : &wl_state.scene->tree;
struct wlr_scene_tree *ds_parent = wl_state.level_trees[WL_LAYER_FLOATING]
? wl_state.level_trees[WL_LAYER_FLOATING] : &wl_state.scene->tree;
dsfb->tree = wlr_scene_tree_create(ds_parent);
if (dsfb->tree) {
dsfb->scene_buf = wlr_scene_buffer_create(dsfb->tree, &dsfb->base);

View File

@ -124,30 +124,36 @@ wl_stacking_restack(WNativeWindow *windows, int count)
* Process bottom-to-top: last raise_to_top call wins, so the
* window at index 0 ends up on top within its level bucket.
*
* Each window is represented by its toplevel frame_buf ID. We
* raise fb->tree — the grouping tree that owns both the frame
* pixel buffer and the reparented client surface — so the entire
* window moves as one atomic unit. Child frame_bufs (titlebar,
* resizebar) are already children of fb->tree and move with it. */
* When windows span different parent trees (level buckets),
* raise_to_top only orders within a parent. Use place_below
* for cross-parent ordering of adjacent entries. */
int i;
for (i = count - 1; i >= 0; i--) {
/* Collect nodes */
struct wlr_scene_node *nodes[64];
int n = 0;
for (i = 0; i < count && n < 64; i++) {
WNativeWindow win = windows[i];
struct wl_frame_buf *fb = frame_buf_find(win);
struct wlr_scene_node *node = NULL;
if (fb) {
/* Raise the grouping tree: moves frame + client together. */
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);
continue;
node = fb->tree ? &fb->tree->node : (fb->scene_buf ? &fb->scene_buf->node : NULL);
} else {
struct wl_toplevel_view *v = wl_find_view_by_id(win);
if (v && v->scene_node)
node = &v->scene_node->node;
}
/* Fallback: unframed toplevel view (no frame_buf). */
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);
if (node) nodes[n++] = node;
}
/* Place in order: nodes[0] on top, nodes[n-1] on bottom.
* Raise top node, then place each subsequent one below its predecessor. */
for (i = 0; i < n; i++) {
if (i == 0) {
wlr_scene_node_raise_to_top(nodes[i]);
} else {
/* Reparent to same parent if needed for place_below to work */
if (nodes[i]->parent != nodes[i-1]->parent)
wlr_scene_node_reparent(nodes[i], (struct wlr_scene_tree *)nodes[i-1]->parent);
wlr_scene_node_place_below(nodes[i], nodes[i-1]);
}
}
}

View File

@ -94,12 +94,9 @@ wl_window_map(WNativeWindow win)
return; /* parent not visible yet */
}
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
/* Raise the tree (raises entire window assembly together) */
if (fb->tree) {
wlr_scene_node_set_enabled(&fb->tree->node, true);
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) {