From 6c9a2a4d0de6af30ab8503938003e168ca68e59d Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Tue, 2 Apr 2024 00:59:18 +0100 Subject: [PATCH] core: let destroyed window go through the preprocess loop one last time Some necessary damage calculation happens there. For example, if a window was rendered last frame but is destroyed this frame, the preprocess loop should add the window to damage. If the destroyed window is freed before the preprocess loop, that damage will be missed. Fixes #1229 Fixes: 3b6e003ca1212ba348f8ad9ca01fb576d5aff737 Signed-off-by: Yuxuan Shui --- src/picom.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/picom.c b/src/picom.c index 1b6edacc..a39c9b8d 100644 --- a/src/picom.c +++ b/src/picom.c @@ -931,13 +931,6 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation, *fade_running = true; } - if (w->state == WSTATE_DESTROYED && w->number_of_animations == 0) { - // the window should be destroyed because it was destroyed - // by X server and now its animations are finished - destroy_win_finish(ps, &w->base); - continue; - } - if (win_has_frame(w)) { w->frame_opacity = ps->o.frame_opacity; } else { @@ -961,7 +954,7 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation, // Track whether it's the highest window to paint bool is_highest = true; bool reg_ignore_valid = true; - win_stack_foreach_managed(w, wm_stack_end(ps->wm)) { + win_stack_foreach_managed_safe(w, wm_stack_end(ps->wm)) { __label__ skip_window; bool to_paint = true; // w->to_paint remembers whether this window is painted last time @@ -981,7 +974,8 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation, // Give up if it's not damaged or invisible, or it's unmapped and its // pixmap is gone (for example due to a ConfigureNotify), or when it's // excluded - if (w->state == WSTATE_UNMAPPED && w->number_of_animations == 0) { + if ((w->state == WSTATE_UNMAPPED || w->state == WSTATE_DESTROYED) && + w->number_of_animations == 0) { if (window_opacity != 0 || blur_opacity != 0) { log_warn("Window %#010x (%s) is unmapped but still has " "opacity", @@ -1105,6 +1099,13 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation, reg_ignore_valid = reg_ignore_valid && w->reg_ignore_valid; w->reg_ignore_valid = true; + if (w->state == WSTATE_DESTROYED && w->number_of_animations == 0) { + // the window should be destroyed because it was destroyed + // by X server and now its animations are finished + destroy_win_finish(ps, &w->base); + w = NULL; + } + // Avoid setting w->to_paint if w is freed if (w) { w->to_paint = to_paint;