WINGs/wview_wl: prevent re-entrant wl_redisplay from wl_map

When a panel's createWidgets callback maps child widgets, each
WMMapWidget triggered wl_redisplay which sent expose events. Those
expose handlers could create/destroy more widgets, causing re-entrant
modification of the view tree during iteration — segfault.

Fix: track wl_redisplay call depth. wl_map only triggers wl_redisplay
when depth==0 (not already inside a redisplay). Child views mapped
during a redisplay cycle will be painted by the parent's recursive
child iteration instead.

Also save nextSister before recursing into children to handle list
modifications during iteration.
This commit is contained in:
Window Maker 2026-05-24 16:20:43 +02:00
parent 8d77acc349
commit 50bc0d35aa
1 changed files with 9 additions and 2 deletions

View File

@ -261,11 +261,13 @@ static void wl_lower(void *vctx, W_View *view)
static void wl_map_subviews(void *vctx, W_View *view);
static int wl_redisplay_depth = 0;
static void wl_map(void *vctx, W_View *view)
{
(void)vctx;
view->flags.mapped = 1;
if (view->flags.realized) {
if (view->flags.realized && wl_redisplay_depth == 0) {
wl_redisplay(vctx, view);
}
}
@ -387,6 +389,8 @@ static void wl_redisplay(void *vctx, W_View *view)
if (!view->flags.mapped || view->flags.alreadyDead)
return;
wl_redisplay_depth++;
/* Fill background color */
pixman_image_t *backing = (pixman_image_t *)W_GetViewBacking(view->window);
if (backing && view->backColor) {
@ -417,10 +421,11 @@ static void wl_redisplay(void *vctx, W_View *view)
/* Re-composite all mapped children into this view's backing */
W_View *child = view->childrenList;
while (child) {
W_View *next = child->nextSister;
if (child->flags.mapped && child->flags.realized && !child->flags.alreadyDead) {
wl_redisplay(vctx, child);
}
child = child->nextSister;
child = next;
}
/* Composite this view's backing into its parent's backing */
@ -444,6 +449,8 @@ static void wl_redisplay(void *vctx, W_View *view)
extern void (*W_ViewCommitBackingFn)(unsigned long id);
if (W_ViewCommitBackingFn)
W_ViewCommitBackingFn((unsigned long)top->window);
wl_redisplay_depth--;
}
/* Find the deepest child view at (x, y) relative to the given view. */