From 9c97743480e901029fce2a8ccdde4f8b6a34040a Mon Sep 17 00:00:00 2001
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
Date: Tue, 25 Mar 2025 02:49:43 +0100
Subject: [PATCH] Add snail layout

---
 config.def.h |   4 +-
 dwl.c        | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+), 1 deletion(-)

diff --git a/config.def.h b/config.def.h
index 8a6eda0..5080a2c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -33,6 +33,7 @@ static const Layout layouts[] = {
 	{ "[]=",      tile },
 	{ "><>",      NULL },    /* no layout function means floating behavior */
 	{ "[M]",      monocle },
+	{ "@|@",      snail },
 };
 
 /* monitors */
@@ -43,7 +44,7 @@ static const MonitorRule monrules[] = {
    /* name        mfact  nmaster scale layout       rotate/reflect                x    y
     * example of a HiDPI laptop monitor:
     { "eDP-1",    0.5f,  1,      2,    &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL,   -1,  -1 }, */
-	{ NULL,       0.55f, 1,      1,    &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL,   -1,  -1 },
+	{ NULL,       0.64f, 1,      1,    &layouts[3], WL_OUTPUT_TRANSFORM_NORMAL,   -1,  -1 },
 	/* default monitor rule: can be changed but cannot be eliminated; at least one monitor rule must exist */
 };
 
@@ -135,6 +136,7 @@ static const Key keys[] = {
 	{ MODKEY,                    XKB_KEY_t,           setlayout,        {.v = &layouts[0]} },
 	{ MODKEY,                    XKB_KEY_f,           setlayout,        {.v = &layouts[1]} },
 	{ MODKEY,                    XKB_KEY_m,           setlayout,        {.v = &layouts[2]} },
+	{ MODKEY,                    XKB_KEY_s,           setlayout,        {.v = &layouts[3]} },
 	{ MODKEY,                    XKB_KEY_space,       setlayout,        {0} },
 	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space,       togglefloating,   {0} },
 	{ MODKEY,                    XKB_KEY_e,           togglefullscreen, {0} },
diff --git a/dwl.c b/dwl.c
index 44f3ad9..1250fb7 100644
--- a/dwl.c
+++ b/dwl.c
@@ -329,6 +329,7 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags);
 static void setpsel(struct wl_listener *listener, void *data);
 static void setsel(struct wl_listener *listener, void *data);
 static void setup(void);
+static void snail(Monitor *m);
 static void spawn(const Arg *arg);
 static void startdrag(struct wl_listener *listener, void *data);
 static void tag(const Arg *arg);
@@ -2666,6 +2667,107 @@ setup(void)
 #endif
 }
 
+void
+snail(Monitor *m)
+{
+	int i = 0, n = 0;
+	unsigned int mw = m->w.width;
+	Client *c, *prev;
+	enum wlr_direction dir = WLR_DIRECTION_RIGHT;
+
+	wl_list_for_each(c, &clients, link)
+		if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
+			n++;
+	if (n == 0)
+		return;
+
+	if (n > m->nmaster)
+		mw = m->nmaster ? (int)round(m->w.width * m->mfact) : 0;
+
+	wl_list_for_each(c, &clients, link) {
+		if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+			continue;
+
+		/*
+		 * If the master area exists and this is the first window, fill the
+		 * master area with this window
+		 */
+		if (mw > 0 && i == 0) {
+			c->geom = (struct wlr_box){.x = m->w.x, .y = m->w.y,
+				.width = mw, .height = m->w.height};
+			/*
+			 * If the first window in the master area is wide, split it
+			 * horizontally and put next one on its right; otherwise, split it
+			 * vertically and put the next one below it
+			 */
+			dir = c->geom.width > m->w.height ? WLR_DIRECTION_RIGHT : WLR_DIRECTION_DOWN;
+		/*
+		 * If the master area is full or doesn't exist, fill the stack with the
+		 * m->nmaster-th window
+		 */
+		} else if (i == m->nmaster) {
+			c->geom = (struct wlr_box){.x = m->w.x + mw, .y = m->w.y,
+				.width = m->w.width - mw, .height = m->w.height};
+			/*
+			 * If the first window in the stack is wide, split it horizontally
+			 * and put next one on its right; otherwise, split it vertically and
+			 * put the next one below it
+			 */
+			dir = c->geom.width > m->w.height ? WLR_DIRECTION_RIGHT : WLR_DIRECTION_DOWN;
+		/*
+		 * Split the previous horizontally and put the current window on the right
+		 */
+		} else if (dir == WLR_DIRECTION_RIGHT) {
+			c->geom = (struct wlr_box){.x = prev->geom.x + prev->geom.width / 2, .y = prev->geom.y,
+				.width = prev->geom.width / 2, .height = prev->geom.height};
+			prev->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y,
+				.width = prev->geom.width / 2, .height = prev->geom.height};
+			/*
+			 * If it's a stack window or the first narrow window in the master
+			 * area, put the next one below it
+			 */
+			if (i >= m->nmaster || c->geom.width < m->w.height)
+				dir = WLR_DIRECTION_DOWN;
+		/*
+		 * Split the previous vertically and put the current window below it
+		 */
+		} else if (dir == WLR_DIRECTION_DOWN) {
+			c->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y + prev->geom.height / 2,
+				.width = prev->geom.width, .height = prev->geom.height / 2};
+			prev->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y,
+				.width = prev->geom.width, .height = prev->geom.height / 2};
+			dir = WLR_DIRECTION_LEFT;
+		/*
+		 * Split the previous horizontally and put the current window on the left
+		 */
+		} else if (dir == WLR_DIRECTION_LEFT) {
+			c->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y,
+				.width = prev->geom.width / 2, .height = prev->geom.height};
+			prev->geom = (struct wlr_box){.x = prev->geom.x + prev->geom.width / 2, .y = prev->geom.y,
+				.width = prev->geom.width / 2, .height = prev->geom.height};
+			dir = WLR_DIRECTION_UP;
+		/*
+		 * Split the previous vertically and put the current window above it
+		 */
+		} else {
+			c->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y,
+				.width = prev->geom.width, .height = prev->geom.height / 2};
+			prev->geom = (struct wlr_box){.x = prev->geom.x, .y = prev->geom.y + prev->geom.height / 2,
+				.width = prev->geom.width, .height = prev->geom.height / 2};
+			dir = WLR_DIRECTION_RIGHT;
+		}
+		i++;
+		prev = c;
+	}
+
+	wl_list_for_each(c, &clients, link) {
+		if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+			continue;
+
+		resize(c, c->geom, 0);
+	}
+}
+
 void
 spawn(const Arg *arg)
 {
-- 
2.53.0

