diff --git a/src/compton.c b/src/compton.c index 5a26a79..1c67447 100644 --- a/src/compton.c +++ b/src/compton.c @@ -666,31 +666,27 @@ static void restack_win(session_t *ps, win *w, xcb_window_t new_above) { rc_region_unref(&w->next->reg_ignore); } - win **prev = NULL, **prev_old = NULL; + win **prev = NULL, *tmp_w; + HASH_FIND_INT(ps->windows, &new_above, tmp_w); - bool found = false; - for (prev = &ps->window_stack; *prev; prev = &(*prev)->next) { - if ((*prev)->id == new_above && (*prev)->state != WSTATE_DESTROYING) { - found = true; - break; - } - } - - if (new_above && !found) { + if (new_above && !tmp_w) { log_error("(%#010x, %#010x): Failed to found new above window.", w->id, new_above); return; } - - for (prev_old = &ps->window_stack; *prev_old; prev_old = &(*prev_old)->next) { - if ((*prev_old) == w) { - break; - } + prev = tmp_w->prev; + // Unlink from old position + *w->prev = w->next; + if (w->next) { + w->next->prev = w->prev; } - - *prev_old = w->next; + // Link to new position w->next = *prev; - *prev = w; + if (w->next) { + w->next->prev = &w->next; + } + w->prev = prev; + *w->prev = w; // add damage for this window add_damage_from_win(ps, w); @@ -2132,8 +2128,8 @@ static session_t *session_init(int argc, char **argv, Display *dpy, free(reply); log_trace("Initial stack:"); - for (win *c = ps->window_stack; c; c = c->next) { - log_trace("%#010x \"%s\"", c->id, c->name); + WIN_STACK_ITER(ps, w) { + log_trace("%#010x \"%s\"", w->id, w->name); } } diff --git a/src/win.c b/src/win.c index 8970d34..8a2aa0d 100644 --- a/src/win.c +++ b/src/win.c @@ -57,7 +57,7 @@ * Clear leader cache of all windows. */ static inline void clear_cache_win_leaders(session_t *ps) { - for (win *w = ps->window_stack; w; w = w->next) { + WIN_STACK_ITER(ps, w) { w->cache_leader = XCB_NONE; } } @@ -1027,14 +1027,18 @@ void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) { // Find window insertion point win **p = NULL; if (prev) { - for (p = &ps->window_stack; *p; p = &(*p)->next) { - if ((*p)->id == prev && (*p)->state != WSTATE_DESTROYING) - break; - } + win *w = NULL; + HASH_FIND_INT(ps->windows, &prev, w); + assert(w); + p = w->prev; } else { p = &ps->window_stack; } new->next = *p; + if (new->next) { + new->next->prev = &new->next; + } + new->prev = p; *p = new; HASH_ADD_INT(ps->windows, id, new); @@ -1466,7 +1470,6 @@ static void finish_unmap_win(session_t *ps, win **_w) { static void finish_destroy_win(session_t *ps, win **_w) { win *w = *_w; - win **prev = NULL; if (w->state != WSTATE_UNMAPPED) { // Only UNMAPPED state has window resources freed, otherwise @@ -1487,30 +1490,28 @@ static void finish_destroy_win(session_t *ps, win **_w) { } log_trace("Trying to destroy (%#010x)", w->id); - for (prev = &ps->window_stack; *prev; prev = &(*prev)->next) { - if (w == *prev) { - log_trace("Found (%#010x \"%s\")", w->id, w->name); - *prev = w->next; + *w->prev = w->next; + if (w->next) { + w->next->prev = w->prev; + } - if (w == ps->active_win) { - ps->active_win = NULL; - } + if (w == ps->active_win) { + ps->active_win = NULL; + } - free_win_res(ps, w); + free_win_res(ps, w); - // Drop w from all prev_trans to avoid accessing freed memory in - // repair_win() - // TODO there can only be one prev_trans pointing to w - for (win *w2 = ps->window_stack; w2; w2 = w2->next) { - if (w == w2->prev_trans) { - w2->prev_trans = NULL; - } - } - free(w); - *_w = NULL; - return; + // Drop w from all prev_trans to avoid accessing freed memory in + // repair_win() + // TODO there can only be one prev_trans pointing to w + WIN_STACK_ITER(ps, w2) { + if (w == w2->prev_trans) { + w2->prev_trans = NULL; } } + free(w); + *_w = NULL; + return; log_warn("Destroyed window is not in window list"); assert(false); } diff --git a/src/win.h b/src/win.h index c137654..3f74f07 100644 --- a/src/win.h +++ b/src/win.h @@ -137,6 +137,8 @@ struct win { void *shadow_image; /// Pointer to the next lower window in window stack. win *next; + /// Pointer to a linked-list pointer that points to this window. + win **prev; /// Pointer to the next higher window to paint. win *prev_trans; // TODO rethink reg_ignore