@@ 1,14 1,21 @@
 /* appearance */
 static const float rootcolor[]      = {0.3, 0.3, 0.3, 1.0};
 
+/* layout(s) */
+static const Layout layouts[] = {
+	/* symbol     arrange function */
+	{ "[]=",      tile },
+	{ "><>",      NULL },    /* no layout function means floating behavior */
+};
+
 /* monitors */
 static const MonitorRule monrules[] = {
-	/* name     scale */
-	{ "X11-1",    1 },
-	{ "eDP-1",    2 },
-	{ "HDMI-A-1", 1 },
-	/* defaults */
-	{ NULL,       1 },
+	/* name       mfact nmaster scale layout */
+	{ "X11-1",    0.5,  1,      1,    &layouts[0] },
+	{ "eDP-1",    0.5,  1,      2,    &layouts[0] },
+	{ "HDMI-A-1", 0.5,  1,      1,    &layouts[0] },
+	/* defaults (required) */
+	{ NULL,       0.5,  1,      1,    &layouts[0] },
 };
 
 /* keyboard */
 
  
@@ 29,7 29,10 @@
 #include <wlr/util/log.h>
 #include <xkbcommon/xkbcommon.h>
 
+/* macros */
+#define MIN(A, B)               ((A) < (B) ? (A) : (B))
 #define CLEANMASK(mask)         (mask & ~WLR_MODIFIER_CAPS)
+#define VISIBLEON(C, M)         ((C)->mon == (M))
 #define LENGTH(X)               (sizeof X / sizeof X[0])
 
 /* enums */
@@ 49,6 52,7 @@ typedef struct {
 	const Arg arg;
 } Button;
 
+typedef struct Monitor Monitor;
 typedef struct {
 	struct wl_list link;
 	struct wlr_xdg_surface *xdg_surface;
@@ 57,7 61,8 @@ typedef struct {
 	struct wl_listener destroy;
 	struct wl_listener request_move;
 	struct wl_listener request_resize;
-	int x, y;
+	Monitor *mon;
+	int x, y; /* layout-relative */
 } Client;
 
 typedef struct {
@@ 76,14 81,28 @@ typedef struct {
 } Keyboard;
 
 typedef struct {
+	const char *symbol;
+	void (*arrange)(Monitor *);
+} Layout;
+
+struct Monitor {
 	struct wl_list link;
 	struct wlr_output *wlr_output;
 	struct wl_listener frame;
-} Monitor;
+	struct wlr_box *geom; /* layout-relative */
+	int wx, wy, ww, wh; /* layout-relative */
+	const Layout *lt[2];
+	unsigned int sellt;
+	double mfact;
+	int nmaster;
+};
 
 typedef struct {
 	const char *name;
+	float mfact;
+	int nmaster;
 	float scale;
+	const Layout *lt;
 } MonitorRule;
 
 /* Used to move all of the data necessary to render a surface from the top-level
@@ 91,10 110,11 @@ typedef struct {
 struct render_data {
 	struct wlr_output *output;
 	struct timespec *when;
-	int x, y;
+	int x, y; /* layout-relative */
 };
 
 /* function declarations */
+static void arrange(Monitor *m);
 static void axisnotify(struct wl_listener *listener, void *data);
 static void buttonpress(struct wl_listener *listener, void *data);
 static void createkeyboard(struct wlr_input_device *device);
@@ 118,11 138,13 @@ static void moveresize(Client *c, unsigned int mode);
 static void quit(const Arg *arg);
 static void render(struct wlr_surface *surface, int sx, int sy, void *data);
 static void rendermon(struct wl_listener *listener, void *data);
+static void resize(Client *c, int x, int y, int w, int h);
 static void resizemouse(const Arg *arg);
 static void run(char *startup_cmd);
 static void setcursor(struct wl_listener *listener, void *data);
 static void setup(void);
 static void spawn(const Arg *arg);
+static void tile(Monitor *m);
 static void unmapnotify(struct wl_listener *listener, void *data);
 static Client * xytoclient(double x, double y,
 		struct wlr_surface **surface, double *sx, double *sy);
@@ 156,10 178,18 @@ static int grab_width, grab_height;
 static struct wlr_output_layout *output_layout;
 static struct wl_list mons;
 static struct wl_listener new_output;
+static Monitor *selmon;
 
 #include "config.h"
 
 void
+arrange(Monitor *m)
+{
+	if (m->lt[m->sellt]->arrange)
+		m->lt[m->sellt]->arrange(m);
+}
+
+void
 axisnotify(struct wl_listener *listener, void *data)
 {
 	/* This event is forwarded by the cursor when a pointer emits an axis event,
@@ 259,7 289,10 @@ createmon(struct wl_listener *listener, void *data)
 	for (i = 0; i < LENGTH(monrules); i++) {
 		if (!monrules[i].name ||
 				!strcmp(wlr_output->name, monrules[i].name)) {
+			m->mfact = monrules[i].mfact;
+			m->nmaster = monrules[i].nmaster;
 			wlr_output_set_scale(wlr_output, monrules[i].scale);
+			m->lt[0] = m->lt[1] = monrules[i].lt;
 			break;
 		}
 	}
@@ 268,6 301,9 @@ createmon(struct wl_listener *listener, void *data)
 	wl_signal_add(&wlr_output->events.frame, &m->frame);
 	wl_list_insert(&mons, &m->link);
 
+	if (!selmon)
+		selmon = m;
+
 	/* Adds this to the output layout. The add_auto function arranges outputs
 	 * from left-to-right in the order they appear. A more sophisticated
 	 * compositor would let the user configure the arrangement of outputs in the
@@ 294,6 330,9 @@ createnotify(struct wl_listener *listener, void *data)
 	Client *c = calloc(1, sizeof(*c));
 	c->xdg_surface = xdg_surface;
 
+	/* Tell the client not to try anything fancy */
+	wlr_xdg_toplevel_set_tiled(c->xdg_surface, true);
+
 	/* Listen to the various events it can emit */
 	c->map.notify = maprequest;
 	wl_signal_add(&xdg_surface->events.map, &c->map);
@@ 487,6 526,7 @@ maprequest(struct wl_listener *listener, void *data)
 	Client *c = wl_container_of(listener, c, map);
 
 	/* Insert this client into the list and focus it. */
+	c->mon = selmon;
 	wl_list_insert(&clients, &c->link);
 	focus(c, c->xdg_surface->surface);
 }
@@ 699,6 739,15 @@ rendermon(struct wl_listener *listener, void *data)
 	if (!wlr_output_attach_render(m->wlr_output, NULL)) {
 		return;
 	}
+	/* Get effective monitor geometry and window area */
+	m->geom = wlr_output_layout_get_box(output_layout, m->wlr_output);
+	m->wx = m->geom->x;
+	m->wy = m->geom->y;
+	m->ww = m->geom->width;
+	m->wh = m->geom->height;
+
+	arrange(m);
+
 	/* Begin the renderer (calls glViewport and some other GL sanity checks) */
 	wlr_renderer_begin(renderer, m->wlr_output->width, m->wlr_output->height);
 	wlr_renderer_clear(renderer, rootcolor);
@@ 734,6 783,14 @@ rendermon(struct wl_listener *listener, void *data)
 }
 
 void
+resize(Client *c, int x, int y, int w, int h)
+{
+	c->x = x;
+	c->y = y;
+	wlr_xdg_toplevel_set_size(c->xdg_surface, w, h);
+}
+
+void
 resizemouse(const Arg *arg)
 {
 	double sx, sy;
@@ 937,6 994,42 @@ spawn(const Arg *arg)
 }
 
 void
+tile(Monitor *m)
+{
+	unsigned int i, n = 0, h, mw, my, ty;
+	Client *c;
+	struct wlr_box ca;
+
+	wl_list_for_each(c, &clients, link) {
+		if (VISIBLEON(c, m))
+			n++;
+	}
+	if (n == 0)
+		return;
+
+	if (n > m->nmaster)
+		mw = m->nmaster ? m->ww * m->mfact : 0;
+	else
+		mw = m->ww;
+	i = my = ty = 0;
+	wl_list_for_each(c, &clients, link) {
+		if (!VISIBLEON(c, m))
+			continue;
+		wlr_xdg_surface_get_geometry(c->xdg_surface, &ca);
+		if (i < m->nmaster) {
+			h = (m->wh - my) / (MIN(n, m->nmaster) - i);
+			resize(c, m->wx, m->wy + my, mw, h);
+			my += ca.height;
+		} else {
+			h = (m->wh - ty) / (n - i);
+			resize(c, m->wx + mw, m->wy + ty, m->ww - mw, h);
+			ty += ca.height;
+		}
+		i++;
+	}
+}
+
+void
 unmapnotify(struct wl_listener *listener, void *data)
 {
 	/* Called when the surface is unmapped, and should no longer be shown. */