diff --git a/include/common.h b/include/common.h index 8846488..416b71e 100644 --- a/include/common.h +++ b/include/common.h @@ -30,6 +30,11 @@ typedef union { #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B)) +extern struct Client **client_arr; +extern int nclients; +extern struct Client **fstack_arr; +extern int nfstack; + /* Convenience wrapper for the function below */ #define VISIBLEON(C, M) visibleon((C), (M)) diff --git a/include/monitor.h b/include/monitor.h index 262160c..50fc4ae 100644 --- a/include/monitor.h +++ b/include/monitor.h @@ -5,10 +5,8 @@ #include #include "wlr_ext_workspace_v1.h" -/* forward declarations */ struct Client; struct LayerSurface; -typedef struct DwindleNode DwindleNode; #ifndef TAGCOUNT #define TAGCOUNT 9 @@ -21,15 +19,30 @@ typedef struct { void (*arrange)(Monitor *); } Layout; -/* Cold state — accessed only on layout changes, not every frame. - * Allocated lazily on first dwindle/master layout use. */ +struct DwindleNode { + int children[2]; + int parent; + struct Client *client; + struct wlr_box box; + float split_ratio; + int split_top; + int is_node; +}; +typedef struct DwindleNode DwindleNode; + +typedef struct { + struct DwindleNode *nodes; + int node_count; + int node_cap; +} DwindleTree; + typedef struct MonitorCold { const Layout *lt[TAGCOUNT][2]; unsigned int sellt[TAGCOUNT]; float mfact; int nmaster; char ltsymbol[TAGCOUNT][16]; - DwindleNode *dwindle_root[TAGCOUNT]; + DwindleTree dwindle_tree[TAGCOUNT]; struct Client *dwindle_focus[TAGCOUNT]; struct Client *master_master[TAGCOUNT]; int master_side[TAGCOUNT]; @@ -39,23 +52,22 @@ struct Monitor { struct wl_list link; struct wlr_output *wlr_output; struct wlr_scene_output *scene_output; - struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ + struct wlr_scene_rect *fullscreen_bg; struct wl_listener frame; struct wl_listener destroy; struct wl_listener request_state; struct wl_listener destroy_lock_surface; struct wlr_session_lock_surface_v1 *lock_surface; - struct wlr_box m; /* monitor area, layout-relative */ - struct wlr_box w; /* window area, layout-relative */ - struct wl_list layers[4]; /* LayerSurface.link */ - struct MonitorCold *cold; /* lazy-allocated layout state */ + struct wlr_box m; + struct wlr_box w; + struct wl_list layers[4]; + struct MonitorCold *cold; int gaps; unsigned int seltags; struct wlr_ext_workspace_group_handle_v1 *ext_group; uint32_t tagset[2]; int asleep; - int scratchpad_visible; /* whether scratchpad is shown */ - struct Client *scratchpad_prev_focus; /* client focused before scratchpad opened */ - struct Client *scratchpad_current; /* currently visible scratchpad client */ + int scratchpad_visible; + struct Client *scratchpad_prev_focus; + struct Client *scratchpad_current; }; - diff --git a/peachwm b/peachwm index 5bf010d..6b3d44a 100755 Binary files a/peachwm and b/peachwm differ diff --git a/src/layout.c b/src/layout.c index a389ca2..2dfd3bb 100644 --- a/src/layout.c +++ b/src/layout.c @@ -1,32 +1,23 @@ -/* - * Layout algorithms extracted from peachwm.c - * Dwindle, Master/Stack, Monocle, and associated utilities. - */ #include #include +#include #include "util.h" #include "layout.h" #include "parser/parser.h" #include "common.h" -/* globals from peachwm.c */ extern struct wl_list clients; extern struct wl_list fstack; extern struct wl_list mons; extern Monitor *selmon; extern Config cfg; -/* functions from peachwm.c */ -void resize(Client *c, struct wlr_box geo, int interact); -Client *focustop(Monitor *m); -void focusclient(Client *c, int lift); -void printstatus(void); -void client_set_suspended(Client *c, int suspended); - -/* ================================================================ - * layout table - * ================================================================ */ +void resize(Client *c, struct wlr_box geo, int interact); +Client *focustop(Monitor *m); +void focusclient(Client *c, int lift); +void printstatus(void); +void client_set_suspended(Client *c, int suspended); const Layout layouts[] = { {"><>", nullptr}, @@ -36,11 +27,6 @@ const Layout layouts[] = { }; const unsigned int layout_count = LENGTH(layouts); -/* ================================================================ - * helpers - * ================================================================ */ - -/* Allocate and default-initialize monitor cold state on first use. */ void ensure_cold(Monitor *m) { @@ -55,11 +41,6 @@ ensure_cold(Monitor *m) m->cold->nmaster = 1; } -/* - * Returns the 0-based index of the lowest set tag bit for monitor m. - * For single-tag views this is the exact tag. For multi-tag views it - * picks the lowest bit. - */ int current_tag_idx(Monitor *m) { @@ -74,7 +55,6 @@ current_tag_idx(Monitor *m) return idx < TAGCOUNT ? idx : 0; } -/* Helper: get current layout for the active tag on monitor m */ const Layout * curlayout(Monitor *m) { @@ -83,165 +63,190 @@ curlayout(Monitor *m) return m->cold->lt[ti][m->cold->sellt[ti]]; } -/* ================================================================ - * dwindle tree helpers - * ================================================================ */ - -static DwindleNode * -dwindle_new_node(void) +static int +dwindle_new_node(DwindleTree *tree) { - DwindleNode *n = ecalloc(1, sizeof(*n)); - n->split_ratio = 1.0f; - return n; + if (tree->node_count >= tree->node_cap) { + int new_cap = tree->node_cap ? tree->node_cap * 2 : 8; + if (tree->nodes) { + tree->nodes = realloc(tree->nodes, + new_cap * sizeof(DwindleNode)); + memset(&tree->nodes[tree->node_cap], 0, + (new_cap - tree->node_cap) * sizeof(DwindleNode)); + } else { + tree->nodes = ecalloc(new_cap, sizeof(DwindleNode)); + } + tree->node_cap = new_cap; + } + int idx = tree->node_count++; + tree->nodes[idx].children[0] = -1; + tree->nodes[idx].children[1] = -1; + tree->nodes[idx].parent = -1; + tree->nodes[idx].split_ratio = 1.0f; + return idx; } void -dwindle_free_tree(DwindleNode *n) +dwindle_free_tree(DwindleTree *tree) { - if (!n) - return; - dwindle_free_tree(n->children[0]); - dwindle_free_tree(n->children[1]); - free(n); + free(tree->nodes); + tree->nodes = nullptr; + tree->node_count = 0; + tree->node_cap = 0; } -DwindleNode * -dwindle_find_leaf(DwindleNode *n, Client *c) +int +dwindle_find_leaf(const DwindleTree *tree, Client *c) { - if (!n) - return nullptr; - if (!n->is_node) - return n->client == c ? n : nullptr; - DwindleNode *r = dwindle_find_leaf(n->children[0], c); - return r ? r : dwindle_find_leaf(n->children[1], c); + for (int i = 0; i < tree->node_count; i++) + if (!tree->nodes[i].is_node && tree->nodes[i].client == c) + return i; + return -1; } -static DwindleNode * -dwindle_first_leaf(DwindleNode *n) +static int +dwindle_first_leaf(const DwindleTree *tree) { - if (!n) - return nullptr; - while (n->is_node) - n = n->children[0]; - return n; + for (int i = 0; i < tree->node_count; i++) + if (!tree->nodes[i].is_node) + return i; + return -1; } -/* - * Recursively distribute geometry downward from node n. - * gap is inner gap pixels between the two halves. - */ void -dwindle_recalc(DwindleNode *n, int gap) +dwindle_recalc(DwindleTree *tree, int gap) { - if (!n) - return; + for (int i = 0; i < tree->node_count; i++) { + DwindleNode *n = &tree->nodes[i]; + if (!n->is_node) + continue; + if (n->children[0] < 0 || n->children[1] < 0) + continue; - if (!n->is_node) { - if (n->client && !n->client->isfullscreen) + n->split_top = (n->box.height > n->box.width); + + if (!n->split_top) { + int w1 = MAX(1, (int)(n->box.width / 2.0f * n->split_ratio) - gap / 2); + tree->nodes[n->children[0]].box = + (struct wlr_box){n->box.x, n->box.y, w1, + n->box.height}; + tree->nodes[n->children[1]].box = + (struct wlr_box){n->box.x + w1 + gap, n->box.y, + MAX(1, n->box.width - w1 - gap), + n->box.height}; + } else { + int h1 = MAX(1, (int)(n->box.height / 2.0f * n->split_ratio) - gap / 2); + tree->nodes[n->children[0]].box = + (struct wlr_box){n->box.x, n->box.y, n->box.width, + h1}; + tree->nodes[n->children[1]].box = + (struct wlr_box){n->box.x, n->box.y + h1 + gap, + n->box.width, + MAX(1, n->box.height - h1 - gap)}; + } + } + + for (int i = 0; i < tree->node_count; i++) { + DwindleNode *n = &tree->nodes[i]; + if (!n->is_node && n->client && !n->client->isfullscreen) resize(n->client, n->box, 0); - return; } - - /* Wider than tall -> split left/right; taller -> split top/bottom. */ - n->split_top = (n->box.height > n->box.width); - - if (!n->split_top) { - int w1 = MAX(1, (int)(n->box.width / 2.0f * n->split_ratio) - gap / 2); - n->children[0]->box = - (struct wlr_box){n->box.x, n->box.y, w1, n->box.height}; - n->children[1]->box = - (struct wlr_box){n->box.x + w1 + gap, n->box.y, - MAX(1, n->box.width - w1 - gap), n->box.height}; - } else { - int h1 = MAX(1, (int)(n->box.height / 2.0f * n->split_ratio) - gap / 2); - n->children[0]->box = - (struct wlr_box){n->box.x, n->box.y, n->box.width, h1}; - n->children[1]->box = - (struct wlr_box){n->box.x, n->box.y + h1 + gap, n->box.width, - MAX(1, n->box.height - h1 - gap)}; - } - - dwindle_recalc(n->children[0], gap); - dwindle_recalc(n->children[1], gap); } -/* - * Insert new_c into the tree, bisecting the focused client's node. - * It falls back to the first leaf if focused is NULL or not in the tree. - */ static void -dwindle_insert(DwindleNode **root, Client *new_c, Client *focused) +dwindle_insert(DwindleTree *tree, Client *new_c, Client *focused) { - DwindleNode *new_leaf = dwindle_new_node(); - new_leaf->client = new_c; - new_leaf->is_node = 0; + int new_leaf_idx = dwindle_new_node(tree); + tree->nodes[new_leaf_idx].client = new_c; + tree->nodes[new_leaf_idx].is_node = 0; - if (!*root) { - *root = new_leaf; + if (tree->node_count == 1) return; - } - DwindleNode *opening_on = focused ? dwindle_find_leaf(*root, focused) : nullptr; - if (!opening_on) - opening_on = dwindle_first_leaf(*root); + int leaf_idx = focused ? dwindle_find_leaf(tree, focused) : -1; + if (leaf_idx < 0) + leaf_idx = dwindle_first_leaf(tree); - DwindleNode *new_parent = dwindle_new_node(); - new_parent->is_node = 1; - new_parent->box = opening_on->box; - new_parent->parent = opening_on->parent; - new_parent->split_top = (opening_on->box.height > opening_on->box.width); - new_parent->children[0] = opening_on; - new_parent->children[1] = new_leaf; + int new_parent_idx = dwindle_new_node(tree); + DwindleNode *parent = &tree->nodes[new_parent_idx]; + DwindleNode *opening = &tree->nodes[leaf_idx]; - opening_on->parent = new_parent; - new_leaf->parent = new_parent; + parent->is_node = 1; + parent->box = opening->box; + parent->split_top = (opening->box.height > opening->box.width); + parent->children[0] = leaf_idx; + parent->children[1] = new_leaf_idx; - if (new_parent->parent) { - if (new_parent->parent->children[0] == opening_on) - new_parent->parent->children[0] = new_parent; + int gp_idx = opening->parent; + parent->parent = gp_idx; + opening->parent = new_parent_idx; + tree->nodes[new_leaf_idx].parent = new_parent_idx; + + if (gp_idx >= 0) { + DwindleNode *gp = &tree->nodes[gp_idx]; + if (gp->children[0] == leaf_idx) + gp->children[0] = new_parent_idx; else - new_parent->parent->children[1] = new_parent; - } else { - *root = new_parent; + gp->children[1] = new_parent_idx; } } -/* - * Remove client c from the tree, promoting its sibling upward. - */ static void -dwindle_remove(DwindleNode **root, Client *c) +dwindle_remove(DwindleTree *tree, Client *c) { - DwindleNode *leaf = dwindle_find_leaf(*root, c); - if (!leaf) + int leaf_idx = dwindle_find_leaf(tree, c); + if (leaf_idx < 0) return; - DwindleNode *parent = leaf->parent; - if (!parent) { - free(leaf); - *root = nullptr; + int parent_idx = tree->nodes[leaf_idx].parent; + if (parent_idx < 0) { + tree->node_count = 0; return; } - DwindleNode *sibling = - (parent->children[0] == leaf) ? parent->children[1] : parent->children[0]; - DwindleNode *grandparent = parent->parent; + DwindleNode *parent = &tree->nodes[parent_idx]; + int sibling_idx = (parent->children[0] == leaf_idx) + ? parent->children[1] + : parent->children[0]; + int gp_idx = parent->parent; - sibling->parent = grandparent; - if (grandparent) { - if (grandparent->children[0] == parent) - grandparent->children[0] = sibling; - else - grandparent->children[1] = sibling; - } else { - *root = sibling; + int old_n = tree->node_count; + int remap[512]; + int ni = 0; + + for (int i = 0; i < old_n; i++) + remap[i] = (i == leaf_idx || i == parent_idx) ? -1 : ni++; + + int write = 0; + for (int read = 0; read < old_n; read++) { + if (remap[read] >= 0) + tree->nodes[write++] = tree->nodes[read]; + } + tree->node_count = ni; + + for (int i = 0; i < ni; i++) { + DwindleNode *n = &tree->nodes[i]; + if (n->children[0] >= 0) + n->children[0] = remap[n->children[0]]; + if (n->children[1] >= 0) + n->children[1] = remap[n->children[1]]; + if (n->parent >= 0) + n->parent = remap[n->parent]; } - free(leaf); - free(parent); + int new_sib = remap[sibling_idx]; + int new_gp = gp_idx >= 0 ? remap[gp_idx] : -1; + + tree->nodes[new_sib].parent = new_gp; + if (new_gp >= 0) { + DwindleNode *gp = &tree->nodes[new_gp]; + if (gp->children[0] < 0) + gp->children[0] = new_sib; + else if (gp->children[1] < 0) + gp->children[1] = new_sib; + } } -/* Remove c from every monitor's per-tag tree. Called from unmapnotify(). */ void dwindle_remove_client(Client *c) { @@ -249,13 +254,9 @@ dwindle_remove_client(Client *c) if (!m || !m->cold) return; for (int i = 0; i < TAGCOUNT; i++) - dwindle_remove(&m->cold->dwindle_root[i], c); + dwindle_remove(&m->cold->dwindle_tree[i], c); } -/* ================================================================ - * dwindle - * ================================================================ */ - void dwindle(Monitor *m) { @@ -275,74 +276,62 @@ dwindle(Monitor *m) : 0; int ti = current_tag_idx(m); - DwindleNode **root = &m->cold->dwindle_root[ti]; + DwindleTree *tree = &m->cold->dwindle_tree[ti]; - /* prune leaves whose clients are no longer tiled here */ - { - DwindleNode *stack[512]; + if (tree->node_count > 0) { Client *stale[512]; - int sp = 0, sc = 0; + int sc = 0; - if (*root) - stack[sp++] = *root; - - while (sp > 0) { - DwindleNode *nd = stack[--sp]; - if (!nd->is_node) { - int found = 0; - wl_list_for_each(c, &clients, link) { - if (c == nd->client && VISIBLEON(c, m) && !c->isfloating) { - found = 1; - break; - } + for (int i = 0; i < tree->node_count; i++) { + DwindleNode *nd = &tree->nodes[i]; + if (nd->is_node) + continue; + int found = 0; + wl_list_for_each(c, &clients, link) { + if (c == nd->client && VISIBLEON(c, m) && !c->isfloating) { + found = 1; + break; } - if (!found && sc < 512) - stale[sc++] = nd->client; - } else { - if (nd->children[1]) - stack[sp++] = nd->children[1]; - if (nd->children[0]) - stack[sp++] = nd->children[0]; } + if (!found && sc < 512) + stale[sc++] = nd->client; } for (int i = 0; i < sc; i++) - dwindle_remove(root, stale[i]); + dwindle_remove(tree, stale[i]); } - /* - * Insert any newly visible client, splitting the focused node. - * Use m->cold->dwindle_focus[ti] so it actually splits what the user - * was looking at when they spawned the window, rather than whatever - * focustop() happens to return. - */ Client *focused = m->cold->dwindle_focus[ti]; wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) continue; - if (!dwindle_find_leaf(*root, c)) { - dwindle_insert(root, c, focused); + if (dwindle_find_leaf(tree, c) < 0) { + dwindle_insert(tree, c, focused); focused = c; } } - /* assign root box and recurse */ - if (*root) { - (*root)->box = (struct wlr_box){ - m->w.x + e, - m->w.y + e, - MAX(1, m->w.width - 2 * e), - MAX(1, m->w.height - 2 * e), - }; - dwindle_recalc(*root, e); + if (tree->node_count > 0) { + int root_idx = -1; + for (int i = 0; i < tree->node_count; i++) { + if (tree->nodes[i].parent < 0) { + root_idx = i; + break; + } + } + if (root_idx >= 0) { + tree->nodes[root_idx].box = (struct wlr_box){ + m->w.x + e, + m->w.y + e, + MAX(1, m->w.width - 2 * e), + MAX(1, m->w.height - 2 * e), + }; + dwindle_recalc(tree, e); + } } } -/* ================================================================ - * master / stack - * ================================================================ */ - static void master_arrange(Monitor *m, int ti) { @@ -434,7 +423,6 @@ master(Monitor *m) master_arrange(m, ti); } -/* Clear master references to client c on all tags of its monitor. */ void master_remove_client(Client *c) { @@ -447,10 +435,6 @@ master_remove_client(Client *c) } } -/* ================================================================ - * monocle - * ================================================================ */ - void monocle(Monitor *m) { @@ -471,8 +455,6 @@ monocle(Monitor *m) int aw = MAX(1, m->w.width - 2 * e); int ah = MAX(1, m->w.height - 2 * e); - /* Stack all windows at the same position and raise the focused one to - * top. */ wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) continue; @@ -485,10 +467,6 @@ monocle(Monitor *m) } } -/* ================================================================ - * swaptiled (tile-drag swap) - * ================================================================ */ - void swaptiled(Client *a, Client *b) { @@ -500,25 +478,34 @@ swaptiled(Client *a, Client *b) if (!m->cold) continue; for (int i = 0; i < TAGCOUNT; i++) { - DwindleNode **root = &m->cold->dwindle_root[i]; - if (!*root) + DwindleTree *tree = &m->cold->dwindle_tree[i]; + if (!tree->nodes || tree->node_count == 0) continue; - DwindleNode *la = dwindle_find_leaf(*root, a); - DwindleNode *lb = dwindle_find_leaf(*root, b); - if (!la || !lb) + int la = dwindle_find_leaf(tree, a); + int lb = dwindle_find_leaf(tree, b); + if (la < 0 || lb < 0) continue; - la->client = b; - lb->client = a; + tree->nodes[la].client = b; + tree->nodes[lb].client = a; int e = (m->gaps && cfg.appearance.gaps) ? (int)cfg.appearance.gaps : 0; - (*root)->box = (struct wlr_box){ - m->w.x + e, - m->w.y + e, - MAX(1, m->w.width - 2 * e), - MAX(1, m->w.height - 2 * e), - }; - dwindle_recalc(*root, e); + int root_idx = -1; + for (int j = 0; j < tree->node_count; j++) { + if (tree->nodes[j].parent < 0) { + root_idx = j; + break; + } + } + if (root_idx >= 0) { + tree->nodes[root_idx].box = (struct wlr_box){ + m->w.x + e, + m->w.y + e, + MAX(1, m->w.width - 2 * e), + MAX(1, m->w.height - 2 * e), + }; + } + dwindle_recalc(tree, e); } } diff --git a/src/layout.h b/src/layout.h index c4b60a2..3adfaf9 100644 --- a/src/layout.h +++ b/src/layout.h @@ -3,40 +3,20 @@ #include "monitor.h" #include "client.h" -/* dwindle binary tree node */ -struct DwindleNode { - DwindleNode *children[2]; - DwindleNode *parent; - Client *client; - struct wlr_box box; - float split_ratio; - int split_top; - int is_node; -}; - -/* layout table and count */ extern const Layout layouts[]; extern const unsigned int layout_count; -/* layout entry points (called via Layout.arrange function pointer) */ void dwindle(Monitor *m); void master(Monitor *m); void monocle(Monitor *m); -/* helpers used across modules */ [[nodiscard]] int current_tag_idx(Monitor *m); [[nodiscard]] const Layout *curlayout(Monitor *m); void ensure_cold(Monitor *m); -/* dwindle tree helpers (exposed for swapdir) */ -[[nodiscard]] DwindleNode *dwindle_find_leaf(DwindleNode *n, Client *c); -void dwindle_recalc(DwindleNode *n, int gap); - -/* lifecycle helpers (called from peachwm.c unmap/cleanup) */ -void dwindle_free_tree(DwindleNode *n); +[[nodiscard]] int dwindle_find_leaf(const DwindleTree *tree, Client *c); +void dwindle_recalc(DwindleTree *tree, int gap); +void dwindle_free_tree(DwindleTree *tree); void dwindle_remove_client(Client *c); void master_remove_client(Client *c); - -/* tile drag swap (called from buttonpress handler) */ void swaptiled(Client *a, Client *b); - diff --git a/src/peachwm.c b/src/peachwm.c index a4ea515..f834585 100644 --- a/src/peachwm.c +++ b/src/peachwm.c @@ -85,6 +85,9 @@ #include "ipc_socket.h" #include "common.h" +#include +#include + /* macros */ #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) #define END(A) ((A) + LENGTH(A)) @@ -299,6 +302,11 @@ static struct wlr_xdg_activation_v1 *activation; static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; struct wl_list clients; /* tiling order */ struct wl_list fstack; /* focus order */ + +Client **client_arr; +int nclients, client_cap; +Client **fstack_arr; +int nfstack, fstack_cap; static struct wlr_idle_notifier_v1 *idle_notifier; static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; @@ -465,13 +473,52 @@ static void applyrules(Client *c) { setmon(c, mon, newtags); } +static void client_arr_add(Client *c) { + if (nclients >= client_cap) { + client_cap = client_cap ? client_cap * 2 : 64; + client_arr = realloc(client_arr, client_cap * sizeof(Client *)); + } + client_arr[nclients++] = c; +} + +static void client_arr_remove(Client *c) { + for (int i = 0; i < nclients; i++) { + if (client_arr[i] == c) { + client_arr[i] = client_arr[--nclients]; + return; + } + } +} + +static void fstack_arr_add(Client *c) { + if (nfstack >= fstack_cap) { + fstack_cap = fstack_cap ? fstack_cap * 2 : 64; + fstack_arr = realloc(fstack_arr, fstack_cap * sizeof(Client *)); + } + memmove(&fstack_arr[1], &fstack_arr[0], nfstack * sizeof(Client *)); + fstack_arr[0] = c; + nfstack++; +} + +static void fstack_arr_remove(Client *c) { + for (int i = 0; i < nfstack; i++) { + if (fstack_arr[i] == c) { + memmove(&fstack_arr[i], &fstack_arr[i + 1], + (nfstack - i - 1) * sizeof(Client *)); + nfstack--; + return; + } + } +} + void arrange(Monitor *m) { Client *c; if (!m->wlr_output->enabled) return; - wl_list_for_each(c, &clients, link) { + for (int i = 0; i < nclients; i++) { + c = client_arr[i]; if (c->mon == m) { wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); client_set_suspended(c, !VISIBLEON(c, m)); @@ -487,7 +534,8 @@ void arrange(Monitor *m) { /* We move all clients (except fullscreen and unmanaged) to LyrTile while * in floating layout to avoid "real" floating clients be always on top */ - wl_list_for_each(c, &clients, link) { + for (int i = 0; i < nclients; i++) { + c = client_arr[i]; if (c->mon != m || c->scene->node.parent == layers[LyrFS]) continue; @@ -759,7 +807,7 @@ static void cleanupmon(struct wl_listener *listener, void *data) { ipc_socket_send_output_event(); if (m->cold) { for (int i = 0; i < TAGCOUNT; i++) - dwindle_free_tree(m->cold->dwindle_root[i]); + dwindle_free_tree(&m->cold->dwindle_tree[i]); free(m->cold); } wlr_scene_node_destroy(&m->fullscreen_bg->node); @@ -1474,6 +1522,8 @@ void focusclient(Client *c, int lift) { if (c && !client_is_unmanaged(c)) { wl_list_remove(&c->flink); wl_list_insert(&fstack, &c->flink); + fstack_arr_remove(c); + fstack_arr_add(c); selmon = c->mon; c->isurgent = 0; @@ -1658,10 +1708,9 @@ void focusdir(const Arg *arg) { * will focus the topmost client of this mon, when actually will * only return that client */ Client *focustop(Monitor *m) { - Client *c; - wl_list_for_each(c, &fstack, flink) { - if (VISIBLEON(c, m)) - return c; + for (int i = 0; i < nfstack; i++) { + if (VISIBLEON(fstack_arr[i], m)) + return fstack_arr[i]; } return nullptr; } @@ -2165,6 +2214,8 @@ static void mapnotify(struct wl_listener *listener, void *data) { /* Insert this client into client lists. */ wl_list_insert(&clients, &c->link); wl_list_insert(&fstack, &c->flink); + client_arr_add(c); + fstack_arr_add(c); /* Set initial monitor, tags, floating status, and focus: * we always consider floating, clients that have parent and thus @@ -3349,6 +3400,11 @@ static void setup(void) { wl_list_init(&clients); wl_list_init(&fstack); + client_cap = 64; + client_arr = ecalloc(client_cap, sizeof(Client *)); + fstack_cap = 64; + fstack_arr = ecalloc(fstack_cap, sizeof(Client *)); + xdg_shell = wlr_xdg_shell_create(dpy, 6); wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel); wl_signal_add(&xdg_shell->events.new_popup, &new_xdg_popup); @@ -3574,22 +3630,28 @@ static void swapdir(const Arg *arg) { if (curlayout(selmon)->arrange == dwindle) { int ti = current_tag_idx(selmon); - DwindleNode **root = &selmon->cold->dwindle_root[ti]; - if (*root) { - DwindleNode *leaf_sel = dwindle_find_leaf(*root, sel); - DwindleNode *leaf_other = dwindle_find_leaf(*root, other); - if (leaf_sel && leaf_other) { - leaf_sel->client = other; - leaf_other->client = sel; + DwindleTree *tree = &selmon->cold->dwindle_tree[ti]; + if (tree->nodes) { + int idx_sel = dwindle_find_leaf(tree, sel); + int idx_other = dwindle_find_leaf(tree, other); + if (idx_sel >= 0 && idx_other >= 0) { + tree->nodes[idx_sel].client = other; + tree->nodes[idx_other].client = sel; int e = (selmon->gaps && cfg.appearance.gaps) ? (int)cfg.appearance.gaps : 0; - (*root)->box = (struct wlr_box){ - selmon->w.x + e, - selmon->w.y + e, - MAX(1, selmon->w.width - 2 * e), - MAX(1, selmon->w.height - 2 * e), - }; - dwindle_recalc(*root, e); + /* Find root node (parent == -1) and set its box, then recalc */ + for (int i = 0; i < tree->node_count; i++) { + if (tree->nodes[i].parent < 0) { + tree->nodes[i].box = (struct wlr_box){ + selmon->w.x + e, + selmon->w.y + e, + MAX(1, selmon->w.width - 2 * e), + MAX(1, selmon->w.height - 2 * e), + }; + break; + } + } + dwindle_recalc(tree, e); } } } else if (curlayout(selmon)->arrange == master) { @@ -3692,9 +3754,11 @@ static void unmapnotify(struct wl_listener *listener, void *data) { } else { Monitor *oldmon = c->mon; wl_list_remove(&c->link); + client_arr_remove(c); dwindle_remove_client(c); master_remove_client(c); wl_list_remove(&c->flink); + fstack_arr_remove(c); /* Clear any stale scratchpad references to this client */ if (oldmon) { if (oldmon->scratchpad_current == c)