diff --git a/src/common.h b/src/common.h index f889633f..6a69e366 100644 --- a/src/common.h +++ b/src/common.h @@ -394,6 +394,9 @@ typedef struct session { win *windows; /// Windows in their stacking order win *window_stack; + /// Pointer to the `next` field of the bottom most window, + /// or a pointer to `window_stack` when there is no window + win **window_stack_bottom; /// Pointer to win of current active window. Used by /// EWMH _NET_ACTIVE_WINDOW focus detection. In theory, /// it's more reliable to store the window ID directly here, just in diff --git a/src/compton.c b/src/compton.c index 1c67447d..9fc4a775 100644 --- a/src/compton.c +++ b/src/compton.c @@ -652,8 +652,10 @@ static void restack_win(session_t *ps, win *w, xcb_window_t new_above) { if (w->next) { old_above = w->next->id; + assert(&w->next != ps->window_stack_bottom); } else { old_above = XCB_NONE; + assert(&w->next == ps->window_stack_bottom); } log_debug("Restack %#010x (%s), old_above: %#010x, new_above: %#010x", w->id, w->name, old_above, new_above); @@ -674,19 +676,31 @@ static void restack_win(session_t *ps, win *w, xcb_window_t new_above) { w->id, new_above); return; } - prev = tmp_w->prev; + // Unlink from old position *w->prev = w->next; if (w->next) { w->next->prev = w->prev; } - // Link to new position - w->next = *prev; - if (w->next) { - w->next->prev = &w->next; + if (ps->window_stack_bottom == &w->next) { + ps->window_stack_bottom = w->prev; + } + + if (!new_above) { + *ps->window_stack_bottom = w; + w->prev = ps->window_stack_bottom; + ps->window_stack_bottom = &w->next; + w->next = NULL; + } else { + prev = tmp_w->prev; + // Link to new position + w->next = *prev; + if (w->next) { + w->next->prev = &w->next; + } + w->prev = prev; + *w->prev = w; } - w->prev = prev; - *w->prev = w; // add damage for this window add_damage_from_win(ps, w); @@ -1738,6 +1752,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, #ifdef CONFIG_DBUS .dbus_data = NULL, #endif + .window_stack = NULL, }; auto stderr_logger = stderr_logger_new(); @@ -1750,6 +1765,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, // Allocate a session and copy default values into it session_t *ps = cmalloc(session_t); *ps = s_def; + ps->window_stack_bottom = &ps->window_stack; ps->loop = EV_DEFAULT; pixman_region32_init(&ps->screen_reg); @@ -2189,6 +2205,7 @@ static void session_destroy(session_t *ps) { free(w); } ps->window_stack = NULL; + ps->window_stack_bottom = &ps->window_stack; // Free blacklists free_wincondlst(&ps->o.shadow_blacklist); diff --git a/src/win.c b/src/win.c index 8a2aa0d6..0536d754 100644 --- a/src/win.c +++ b/src/win.c @@ -1040,6 +1040,9 @@ void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) { } new->prev = p; *p = new; + if (p == ps->window_stack_bottom) { + ps->window_stack_bottom = &new->next; + } HASH_ADD_INT(ps->windows, id, new); #ifdef CONFIG_DBUS @@ -1494,6 +1497,9 @@ static void finish_destroy_win(session_t *ps, win **_w) { if (w->next) { w->next->prev = w->prev; } + if (&w->next == ps->window_stack_bottom) { + ps->window_stack_bottom = w->prev; + } if (w == ps->active_win) { ps->active_win = NULL;