diff --git a/src/common.h b/src/common.h
index f889633..6a69e36 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 1c67447..9fc4a77 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 8a2aa0d..0536d75 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;