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: 3b6e003ca1

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-04-02 00:59:18 +01:00
parent a5e3de4489
commit 6c9a2a4d0d
No known key found for this signature in database
GPG Key ID: D3A4405BE6CC17F4
1 changed files with 10 additions and 9 deletions

View File

@ -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;