From eff7a297902d4e4655c771c6f4d89200dfaadc54 Mon Sep 17 00:00:00 2001 From: ernestoCruz05 Date: Sat, 9 May 2026 11:55:59 +0800 Subject: [PATCH] feat: dwindle layout support --- src/config/parse_config.h | 35 +++ src/dispatch/bind_define.h | 4 + src/layout/arrange.h | 25 +++ src/layout/dwindle.h | 435 +++++++++++++++++++++++++++++++++++++ src/layout/layout.h | 3 + src/mango.c | 39 ++++ 6 files changed, 541 insertions(+) create mode 100644 src/layout/dwindle.h diff --git a/src/config/parse_config.h b/src/config/parse_config.h index f70a17d6..4fa14bf8 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -242,6 +242,14 @@ typedef struct { int32_t center_master_overspread; int32_t center_when_single_stack; + /* dwindle layout */ + int32_t dwindle_vsplit; + int32_t dwindle_hsplit; + int32_t dwindle_preserve_split; + int32_t dwindle_smart_split; + int32_t dwindle_smart_resize; + float dwindle_split_ratio; + uint32_t hotarea_size; uint32_t hotarea_corner; uint32_t enable_hotarea; @@ -1615,6 +1623,18 @@ bool parse_option(Config *config, char *key, char *value) { config->center_master_overspread = atoi(value); } else if (strcmp(key, "center_when_single_stack") == 0) { config->center_when_single_stack = atoi(value); + } else if (strcmp(key, "dwindle_vsplit") == 0) { + config->dwindle_vsplit = atoi(value); + } else if (strcmp(key, "dwindle_hsplit") == 0) { + config->dwindle_hsplit = atoi(value); + } else if (strcmp(key, "dwindle_preserve_split") == 0) { + config->dwindle_preserve_split = atoi(value); + } else if (strcmp(key, "dwindle_smart_split") == 0) { + config->dwindle_smart_split = atoi(value); + } else if (strcmp(key, "dwindle_smart_resize") == 0) { + config->dwindle_smart_resize = atoi(value); + } else if (strcmp(key, "dwindle_split_ratio") == 0) { + config->dwindle_split_ratio = atof(value); } else if (strcmp(key, "hotarea_size") == 0) { config->hotarea_size = atoi(value); } else if (strcmp(key, "hotarea_corner") == 0) { @@ -3179,6 +3199,14 @@ void override_config(void) { config.center_when_single_stack = CLAMP_INT(config.center_when_single_stack, 0, 1); config.new_is_master = CLAMP_INT(config.new_is_master, 0, 1); + config.dwindle_vsplit = CLAMP_INT(config.dwindle_vsplit, 0, 2); + config.dwindle_hsplit = CLAMP_INT(config.dwindle_hsplit, 0, 2); + config.dwindle_preserve_split = + CLAMP_INT(config.dwindle_preserve_split, 0, 1); + config.dwindle_smart_split = CLAMP_INT(config.dwindle_smart_split, 0, 1); + config.dwindle_smart_resize = CLAMP_INT(config.dwindle_smart_resize, 0, 1); + config.dwindle_split_ratio = + CLAMP_FLOAT(config.dwindle_split_ratio, 0.05f, 0.95f); config.hotarea_size = CLAMP_INT(config.hotarea_size, 1, 1000); config.hotarea_corner = CLAMP_INT(config.hotarea_corner, 0, 3); config.enable_hotarea = CLAMP_INT(config.enable_hotarea, 0, 1); @@ -3318,6 +3346,13 @@ void set_value_default() { config.center_master_overspread = 0; config.center_when_single_stack = 1; + config.dwindle_vsplit = 0; + config.dwindle_hsplit = 0; + config.dwindle_preserve_split = 0; + config.dwindle_smart_split = 0; + config.dwindle_smart_resize = 0; + config.dwindle_split_ratio = 0.5f; + config.log_level = WLR_ERROR; config.numlockon = 0; config.capslock = 0; diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 1ab84c9d..3c1d2154 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -112,6 +112,10 @@ int32_t exchange_client(const Arg *arg) { Client *tc = direction_select(arg); tc = get_focused_stack_client(tc); + + if (!tc) + return 0; + exchange_two_client(c, tc); return 0; } diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 04f4554b..b22e1fea 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -488,6 +488,29 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, } } +void resize_tile_dwindle(Client *grabc, bool isdrag, int32_t offsetx, + int32_t offsety, uint32_t time, bool isvertical) { + + if (!start_drag_window) { + dwindle_resize_client_step(grabc->mon, grabc, offsetx, offsety); + } + + if (isdrag) { + int32_t dx = (int32_t)round(cursor->x) - drag_begin_cursorx; + int32_t dy = (int32_t)round(cursor->y) - drag_begin_cursory; + dwindle_resize_client(grabc->mon, grabc, dx, dy); + } else if (last_apply_drap_time == 0 || + time - last_apply_drap_time > + config.drag_tile_refresh_interval) { + dwindle_resize_client(grabc->mon, grabc, offsetx, offsety); + last_apply_drap_time = time; + } + + if (!isdrag) { + start_drag_window = false; + } +} + void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, int32_t offsety, uint32_t time, bool isvertical) { Client *tc = NULL; @@ -706,6 +729,8 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, resize_tile_scroller(grabc, isdrag, offsetx, offsety, time, false); } else if (current_layout->id == VERTICAL_SCROLLER) { resize_tile_scroller(grabc, isdrag, offsetx, offsety, time, true); + } else if (current_layout->id == DWINDLE) { + resize_tile_dwindle(grabc, isdrag, offsetx, offsety, time, true); } } diff --git a/src/layout/dwindle.h b/src/layout/dwindle.h new file mode 100644 index 00000000..6ea564bc --- /dev/null +++ b/src/layout/dwindle.h @@ -0,0 +1,435 @@ +typedef struct DwindleNode DwindleNode; +struct DwindleNode { + bool is_split; + bool split_h; + bool split_locked; + float ratio; + float drag_init_ratio; + int32_t container_x; + int32_t container_y; + int32_t container_w; + int32_t container_h; + DwindleNode *parent; + DwindleNode *first; + DwindleNode *second; + Client *client; +}; + +static DwindleNode *dwindle_locked_h_node = NULL; +static DwindleNode *dwindle_locked_v_node = NULL; + +static DwindleNode *dwindle_new_leaf(Client *c) { + DwindleNode *n = calloc(1, sizeof(DwindleNode)); + n->client = c; + return n; +} + +static DwindleNode *dwindle_find_leaf(DwindleNode *node, Client *c) { + if (!node) + return NULL; + if (!node->is_split) + return node->client == c ? node : NULL; + DwindleNode *r = dwindle_find_leaf(node->first, c); + return r ? r : dwindle_find_leaf(node->second, c); +} + +static DwindleNode *dwindle_first_leaf(DwindleNode *node) { + if (!node) + return NULL; + while (node->is_split) + node = node->first; + return node; +} + +static void dwindle_free_tree(DwindleNode *node) { + if (!node) + return; + dwindle_free_tree(node->first); + dwindle_free_tree(node->second); + free(node); +} + +static void dwindle_insert(DwindleNode **root, Client *new_c, Client *focused, + float ratio, bool as_first) { + DwindleNode *new_leaf = dwindle_new_leaf(new_c); + + if (!*root) { + *root = new_leaf; + return; + } + + DwindleNode *target = focused ? dwindle_find_leaf(*root, focused) : NULL; + if (!target) + target = dwindle_first_leaf(*root); + + DwindleNode *split = calloc(1, sizeof(DwindleNode)); + split->is_split = true; + split->ratio = ratio; + if (as_first) { + split->first = new_leaf; + split->second = target; + } else { + split->first = target; + split->second = new_leaf; + } + split->parent = target->parent; + target->parent = split; + new_leaf->parent = split; + + if (!split->parent) { + *root = split; + } else { + if (split->parent->first == target) + split->parent->first = split; + else + split->parent->second = split; + } +} + +static void dwindle_remove(DwindleNode **root, Client *c) { + DwindleNode *leaf = dwindle_find_leaf(*root, c); + if (!leaf) + return; + + DwindleNode *parent = leaf->parent; + if (!parent) { + free(leaf); + *root = NULL; + return; + } + + DwindleNode *sibling = + (parent->first == leaf) ? parent->second : parent->first; + DwindleNode *grandparent = parent->parent; + sibling->parent = grandparent; + + /* Preserve split direction on sibling split-nodes when requested. */ + if (!sibling->is_split || + (!config.dwindle_preserve_split && !config.dwindle_smart_split)) { + sibling->container_w = 0; + sibling->container_h = 0; + } + + if (!grandparent) { + *root = sibling; + } else { + if (grandparent->first == parent) + grandparent->first = sibling; + else + grandparent->second = sibling; + } + + free(leaf); + free(parent); +} + +static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay, + int32_t aw, int32_t ah, int32_t gap_h, + int32_t gap_v) { + if (!node) + return; + + if (!node->is_split) { + if (node->client) { + struct wlr_box box = {ax, ay, MAX(1, aw), MAX(1, ah)}; + resize(node->client, box, 0); + } + return; + } + + if (!node->split_locked && node->container_w == 0 && node->container_h == 0) + node->split_h = (aw >= ah); + node->container_x = ax; + node->container_y = ay; + node->container_w = aw; + node->container_h = ah; + if (node->split_h) { + int32_t w1 = MAX(1, (int32_t)(aw * node->ratio) - gap_h / 2); + dwindle_assign(node->first, ax, ay, w1, ah, gap_h, gap_v); + dwindle_assign(node->second, ax + w1 + gap_h, ay, aw - w1 - gap_h, ah, + gap_h, gap_v); + } else { + int32_t h1 = MAX(1, (int32_t)(ah * node->ratio) - gap_v / 2); + dwindle_assign(node->first, ax, ay, aw, h1, gap_h, gap_v); + dwindle_assign(node->second, ax, ay + h1 + gap_v, aw, ah - h1 - gap_v, + gap_h, gap_v); + } +} + +static void dwindle_move_client(DwindleNode **root, Client *c, Client *target, + float ratio, int32_t dir) { + if (!c || !target || c == target) + return; + if (!dwindle_find_leaf(*root, c) || !dwindle_find_leaf(*root, target)) + return; + dwindle_remove(root, c); + bool as_first = (dir == UP || dir == LEFT); + dwindle_insert(root, c, target, ratio, as_first); +} + +static void dwindle_swap_clients(DwindleNode **root, Client *a, Client *b) { + DwindleNode *la = dwindle_find_leaf(*root, a); + DwindleNode *lb = dwindle_find_leaf(*root, b); + if (!la || !lb || la == lb) + return; + la->client = b; + lb->client = a; +} + +static void dwindle_resize_client(Monitor *m, Client *c, int32_t dx, + int32_t dy) { + uint32_t tag = m->pertag->curtag; + DwindleNode *leaf = dwindle_find_leaf(m->pertag->dwindle_root[tag], c); + if (!leaf) + return; + + if (!start_drag_window) { + start_drag_window = true; + dwindle_locked_h_node = NULL; + dwindle_locked_v_node = NULL; + DwindleNode *node = leaf->parent; + while (node) { + if (node->split_h && !dwindle_locked_h_node) { + dwindle_locked_h_node = node; + node->drag_init_ratio = node->ratio; + } + if (!node->split_h && !dwindle_locked_v_node) { + dwindle_locked_v_node = node; + node->drag_init_ratio = node->ratio; + } + if (dwindle_locked_h_node && dwindle_locked_v_node) + break; + node = node->parent; + } + } + + if (!dwindle_locked_h_node && !dwindle_locked_v_node) + return; + + if (dwindle_locked_h_node) { + float cw = (float)MAX(1, dwindle_locked_h_node->container_w); + float ox = (float)(cursor->x - drag_begin_cursorx); + if (config.dwindle_smart_resize) { + /* Move the boundary toward the cursor: invert direction when + * the drag started on the right side of the split line. */ + float split_x = dwindle_locked_h_node->container_x + + cw * dwindle_locked_h_node->drag_init_ratio; + if (drag_begin_cursorx >= split_x) + ox = -ox; + } + dwindle_locked_h_node->ratio = + dwindle_locked_h_node->drag_init_ratio + ox / cw; + dwindle_locked_h_node->ratio = + CLAMP_FLOAT(dwindle_locked_h_node->ratio, 0.05f, 0.95f); + } + + if (dwindle_locked_v_node) { + float ch = (float)MAX(1, dwindle_locked_v_node->container_h); + float oy = (float)(cursor->y - drag_begin_cursory); + if (config.dwindle_smart_resize) { + /* Same logic for the vertical split line. */ + float split_y = dwindle_locked_v_node->container_y + + ch * dwindle_locked_v_node->drag_init_ratio; + if (drag_begin_cursory >= split_y) + oy = -oy; + } + dwindle_locked_v_node->ratio = + dwindle_locked_v_node->drag_init_ratio + oy / ch; + dwindle_locked_v_node->ratio = + CLAMP_FLOAT(dwindle_locked_v_node->ratio, 0.05f, 0.95f); + } + + int32_t n = m->visible_tiling_clients; + int32_t gap_ih = enablegaps ? m->gappih : 0; + int32_t gap_iv = enablegaps ? m->gappiv : 0; + int32_t gap_oh = enablegaps ? m->gappoh : 0; + int32_t gap_ov = enablegaps ? m->gappov : 0; + if (config.smartgaps && n == 1) + gap_ih = gap_iv = gap_oh = gap_ov = 0; + + dwindle_assign(m->pertag->dwindle_root[tag], m->w.x + gap_oh, + m->w.y + gap_ov, m->w.width - 2 * gap_oh, + m->w.height - 2 * gap_ov, gap_ih, gap_iv); +} + +static void dwindle_resize_client_step(Monitor *m, Client *c, int32_t dx, + int32_t dy) { + uint32_t tag = m->pertag->curtag; + DwindleNode *leaf = dwindle_find_leaf(m->pertag->dwindle_root[tag], c); + if (!leaf) + return; + + DwindleNode *h_node = NULL; + DwindleNode *v_node = NULL; + DwindleNode *node = leaf->parent; + drag_begin_cursorx = cursor->x; + drag_begin_cursory = cursor->y; + + while (node) { + if (node->split_h && !h_node) + h_node = node; + if (!node->split_h && !v_node) + v_node = node; + if (h_node && v_node) + break; + node = node->parent; + } + + if (!h_node && !v_node) + return; + + if (h_node && dx) { + float cw = (float)MAX(1, h_node->container_w); + float delta = (float)dx / cw; + h_node->ratio = CLAMP_FLOAT(h_node->ratio + delta, 0.05f, 0.95f); + } + + if (v_node && dy) { + float ch = (float)MAX(1, v_node->container_h); + float delta = (float)dy / ch; + v_node->ratio = CLAMP_FLOAT(v_node->ratio + delta, 0.05f, 0.95f); + } + + int32_t n_clients = m->visible_tiling_clients; + int32_t gap_ih = enablegaps ? m->gappih : 0; + int32_t gap_iv = enablegaps ? m->gappiv : 0; + int32_t gap_oh = enablegaps ? m->gappoh : 0; + int32_t gap_ov = enablegaps ? m->gappov : 0; + if (config.smartgaps && n_clients == 1) + gap_ih = gap_iv = gap_oh = gap_ov = 0; + + dwindle_assign(m->pertag->dwindle_root[tag], m->w.x + gap_oh, + m->w.y + gap_ov, m->w.width - 2 * gap_oh, + m->w.height - 2 * gap_ov, gap_ih, gap_iv); +} + +static void dwindle_remove_client(Client *c) { + Monitor *m; + wl_list_for_each(m, &mons, link) { + for (uint32_t t = 0; t < LENGTH(tags) + 1; t++) + dwindle_remove(&m->pertag->dwindle_root[t], c); + } +} + +/* Insert a new client respecting dwindle_vsplit, dwindle_hsplit, and + * dwindle_smart_split config options. */ +static void dwindle_insert_with_config(DwindleNode **root, Client *new_c, + Client *focused, float ratio) { + bool as_first = false; + + if (focused) { + struct wlr_box *fg = &focused->geom; + double fcx = fg->x + fg->width * 0.5; + double fcy = fg->y + fg->height * 0.5; + + if (config.dwindle_smart_split) { + /* Divide the focused window into 4 triangles using its diagonals. + * The triangle the cursor falls in determines both the split axis + * and which side the new window appears on. */ + double nx = (cursor->x - fcx) / (fg->width * 0.5); + double ny = (cursor->y - fcy) / (fg->height * 0.5); + bool do_split_h; + if (fabs(ny) > fabs(nx)) { + do_split_h = false; + as_first = (ny < 0); /* top triangle → new window on top */ + } else { + do_split_h = true; + as_first = (nx < 0); /* left triangle → new window on left */ + } + dwindle_insert(root, new_c, focused, ratio, as_first); + DwindleNode *leaf = dwindle_find_leaf(*root, new_c); + if (leaf && leaf->parent) { + leaf->parent->split_h = do_split_h; + leaf->parent->split_locked = true; + } + return; + } + + /* Predict likely split direction from the focused window's shape. */ + bool likely_h = (fg->width >= fg->height); + if (likely_h) { + if (config.dwindle_hsplit == 0) + as_first = (cursor->x < fcx); /* follow mouse */ + else + as_first = (config.dwindle_hsplit == 2); /* 2=left, 1=right */ + } else { + if (config.dwindle_vsplit == 0) + as_first = (cursor->y < fcy); /* follow mouse */ + else + as_first = (config.dwindle_vsplit == 2); /* 2=top, 1=bottom */ + } + } + + dwindle_insert(root, new_c, focused, ratio, as_first); +} + +void dwindle(Monitor *m) { + int32_t n = m->visible_tiling_clients; + if (n == 0) + return; + + uint32_t tag = m->pertag->curtag; + DwindleNode **root = &m->pertag->dwindle_root[tag]; + float ratio = config.dwindle_split_ratio; + + Client *vis[512]; + int32_t count = 0; + Client *c; + wl_list_for_each(c, &clients, link) { + if (VISIBLEON(c, m) && ISTILED(c)) + vis[count++] = c; + if (count >= 512) + break; + } + + { + DwindleNode *leaves[512]; + int32_t lc = 0; + + DwindleNode *stack[1024]; + int32_t sp = 0; + if (*root) + stack[sp++] = *root; + while (sp > 0) { + DwindleNode *nd = stack[--sp]; + if (!nd->is_split) { + leaves[lc++] = nd; + } else { + if (nd->second) + stack[sp++] = nd->second; + if (nd->first) + stack[sp++] = nd->first; + } + } + + for (int32_t i = 0; i < lc; i++) { + bool found = false; + for (int32_t j = 0; j < count; j++) + if (vis[j] == leaves[i]->client) { + found = true; + break; + } + if (!found) + dwindle_remove(root, leaves[i]->client); + } + } + + Client *focused = focustop(m); + if (focused && !dwindle_find_leaf(*root, focused)) + focused = m->sel; + for (int32_t i = 0; i < count; i++) { + if (!dwindle_find_leaf(*root, vis[i])) + dwindle_insert_with_config(root, vis[i], focused, ratio); + } + + int32_t gap_ih = enablegaps ? m->gappih : 0; + int32_t gap_iv = enablegaps ? m->gappiv : 0; + int32_t gap_oh = enablegaps ? m->gappoh : 0; + int32_t gap_ov = enablegaps ? m->gappov : 0; + if (config.smartgaps && n == 1) + gap_ih = gap_iv = gap_oh = gap_ov = 0; + + dwindle_assign(*root, m->w.x + gap_oh, m->w.y + gap_ov, + m->w.width - 2 * gap_oh, m->w.height - 2 * gap_ov, gap_ih, + gap_iv); +} diff --git a/src/layout/layout.h b/src/layout/layout.h index f896ac27..557ce571 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -12,6 +12,7 @@ static void vertical_grid(Monitor *m); static void vertical_scroller(Monitor *m); static void vertical_deck(Monitor *mon); static void tgmix(Monitor *m); +static void dwindle(Monitor *m); /* layout(s) */ Layout overviewlayout = {"󰃇", overview, "overview"}; @@ -29,6 +30,7 @@ enum { VERTICAL_DECK, RIGHT_TILE, TGMIX, + DWINDLE, }; Layout layouts[] = { @@ -47,4 +49,5 @@ Layout layouts[] = { {"VG", vertical_grid, "vertical_grid", VERTICAL_GRID}, // 垂直格子布局 {"VK", vertical_deck, "vertical_deck", VERTICAL_DECK}, // 垂直卡片布局 {"TG", tgmix, "tgmix", TGMIX}, // 混合布局 + {"DW", dwindle, "dwindle", DWINDLE}, }; \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index 36deda3c..06199e68 100644 --- a/src/mango.c +++ b/src/mango.c @@ -560,6 +560,8 @@ typedef struct { struct wl_listener destroy; } SessionLock; +typedef struct DwindleNode DwindleNode; + /* function declarations */ static void applybounds( Client *c, @@ -815,6 +817,12 @@ static void client_pending_maximized_state(Client *c, int32_t ismaximized); static void client_pending_minimized_state(Client *c, int32_t isminimized); static void scroller_insert_stack(Client *c, Client *target_client, bool insert_before); +static void dwindle_move_client(DwindleNode **root, Client *c, Client *target, + float ratio, int32_t dir); +static void dwindle_resize_client_step(Monitor *m, Client *c, int32_t dx, + int32_t dy); +static void dwindle_resize_client(Monitor *m, Client *c, int32_t dx, + int32_t dy); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -946,6 +954,7 @@ struct Pertag { int32_t no_hide[LENGTH(tags) + 1]; /* no_hide per tag */ int32_t no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */ int32_t open_as_floating[LENGTH(tags) + 1]; /* open_as_floating per tag */ + struct DwindleNode *dwindle_root[LENGTH(tags) + 1]; const Layout *ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */ }; @@ -1018,6 +1027,7 @@ static struct wl_event_source *sync_keymap; #include "ext-protocol/all.h" #include "fetch/fetch.h" #include "layout/arrange.h" +#include "layout/dwindle.h" #include "layout/horizontal.h" #include "layout/vertical.h" @@ -1179,6 +1189,17 @@ void swallow(Client *c, Client *w) { client_pending_fullscreen_state(c, w->isfullscreen); client_pending_maximized_state(c, w->ismaximizescreen); client_pending_minimized_state(c, w->isminimized); + + Monitor *m; + wl_list_for_each(m, &mons, link) { + for (uint32_t t = 0; t < LENGTH(tags) + 1; t++) { + DwindleNode **root = &m->pertag->dwindle_root[t]; + dwindle_remove(root, c); + DwindleNode *wn = dwindle_find_leaf(*root, w); + if (wn) + wn->client = c; + } + } } bool switch_scratchpad_client_state(Client *c) { @@ -2194,6 +2215,13 @@ void place_drag_tile_client(Client *c) { try_scroller_drop(c, closest, 1); return; } + if (layout->id == DWINDLE) { + uint32_t tag = c->mon->pertag->curtag; + bool insert_before = closest->drop_direction == LEFT || + closest->drop_direction == UP; + dwindle_insert(&c->mon->pertag->dwindle_root[tag], c, closest, + config.dwindle_split_ratio, insert_before); + } if (closest->drop_direction == LEFT || closest->drop_direction == UP) { wl_list_remove(&c->link); @@ -5101,10 +5129,20 @@ void exchange_two_client(Client *c1, Client *c2) { tmp_tags = c2->tags; setmon(c2, c1->mon, c1->tags, false); setmon(c1, tmp_mon, tmp_tags, false); + if (c1->mon && + c1->mon->pertag->ltidxs[c1->mon->pertag->curtag]->id == DWINDLE) + dwindle_swap_clients( + &c1->mon->pertag->dwindle_root[c1->mon->pertag->curtag], c1, + c2); arrange(c1->mon, false, false); arrange(c2->mon, false, false); focusclient(c1, 0); } else { + if (c1->mon && + c1->mon->pertag->ltidxs[c1->mon->pertag->curtag]->id == DWINDLE) + dwindle_swap_clients( + &c1->mon->pertag->dwindle_root[c1->mon->pertag->curtag], c1, + c2); arrange(c1->mon, false, false); } @@ -6343,6 +6381,7 @@ void unmapnotify(struct wl_listener *listener, void *data) { c->next_in_stack = NULL; c->prev_in_stack = NULL; + dwindle_remove_client(c); wlr_scene_node_destroy(&c->scene->node); printstatus(); motionnotify(0, NULL, 0, 0, 0, 0);