xref: /netbsd-src/external/bsd/tmux/dist/layout-set.c (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
15494e770Schristos /* $OpenBSD$ */
2698d5317Sjmmv 
3698d5317Sjmmv /*
4ed4e6cd4Schristos  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5698d5317Sjmmv  *
6698d5317Sjmmv  * Permission to use, copy, modify, and distribute this software for any
7698d5317Sjmmv  * purpose with or without fee is hereby granted, provided that the above
8698d5317Sjmmv  * copyright notice and this permission notice appear in all copies.
9698d5317Sjmmv  *
10698d5317Sjmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11698d5317Sjmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12698d5317Sjmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13698d5317Sjmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14698d5317Sjmmv  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15698d5317Sjmmv  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16698d5317Sjmmv  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17698d5317Sjmmv  */
18698d5317Sjmmv 
19698d5317Sjmmv #include <sys/types.h>
20698d5317Sjmmv 
219fb66d81Schristos #include <stdlib.h>
22698d5317Sjmmv #include <string.h>
23698d5317Sjmmv 
24698d5317Sjmmv #include "tmux.h"
25698d5317Sjmmv 
26698d5317Sjmmv /*
275494e770Schristos  * Set window layouts - predefined methods to arrange windows. These are
285494e770Schristos  * one-off and generate a layout tree.
29698d5317Sjmmv  */
30698d5317Sjmmv 
314e179ddaSchristos static void	layout_set_even_h(struct window *);
324e179ddaSchristos static void	layout_set_even_v(struct window *);
334e179ddaSchristos static void	layout_set_main_h(struct window *);
34*f8cf1a91Swiz static void	layout_set_main_h_mirrored(struct window *);
354e179ddaSchristos static void	layout_set_main_v(struct window *);
36*f8cf1a91Swiz static void	layout_set_main_v_mirrored(struct window *);
374e179ddaSchristos static void	layout_set_tiled(struct window *);
38698d5317Sjmmv 
394e179ddaSchristos static const struct {
40698d5317Sjmmv 	const char	*name;
41698d5317Sjmmv 	void	      	(*arrange)(struct window *);
42698d5317Sjmmv } layout_sets[] = {
43698d5317Sjmmv 	{ "even-horizontal", layout_set_even_h },
44698d5317Sjmmv 	{ "even-vertical", layout_set_even_v },
45698d5317Sjmmv 	{ "main-horizontal", layout_set_main_h },
46*f8cf1a91Swiz 	{ "main-horizontal-mirrored", layout_set_main_h_mirrored },
47698d5317Sjmmv 	{ "main-vertical", layout_set_main_v },
48*f8cf1a91Swiz 	{ "main-vertical-mirrored", layout_set_main_v_mirrored },
49698d5317Sjmmv 	{ "tiled", layout_set_tiled },
50698d5317Sjmmv };
51698d5317Sjmmv 
52698d5317Sjmmv int
53698d5317Sjmmv layout_set_lookup(const char *name)
54698d5317Sjmmv {
55698d5317Sjmmv 	u_int	i;
56698d5317Sjmmv 	int	matched = -1;
57698d5317Sjmmv 
58698d5317Sjmmv 	for (i = 0; i < nitems(layout_sets); i++) {
59*f8cf1a91Swiz 		if (strcmp(layout_sets[i].name, name) == 0)
60*f8cf1a91Swiz 			return (i);
61*f8cf1a91Swiz 	}
62*f8cf1a91Swiz 	for (i = 0; i < nitems(layout_sets); i++) {
63698d5317Sjmmv 		if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) {
64698d5317Sjmmv 			if (matched != -1)	/* ambiguous */
65698d5317Sjmmv 				return (-1);
66698d5317Sjmmv 			matched = i;
67698d5317Sjmmv 		}
68698d5317Sjmmv 	}
69698d5317Sjmmv 
70698d5317Sjmmv 	return (matched);
71698d5317Sjmmv }
72698d5317Sjmmv 
73698d5317Sjmmv u_int
74698d5317Sjmmv layout_set_select(struct window *w, u_int layout)
75698d5317Sjmmv {
76698d5317Sjmmv 	if (layout > nitems(layout_sets) - 1)
77698d5317Sjmmv 		layout = nitems(layout_sets) - 1;
78698d5317Sjmmv 
79698d5317Sjmmv 	if (layout_sets[layout].arrange != NULL)
80698d5317Sjmmv 		layout_sets[layout].arrange(w);
81698d5317Sjmmv 
82698d5317Sjmmv 	w->lastlayout = layout;
83698d5317Sjmmv 	return (layout);
84698d5317Sjmmv }
85698d5317Sjmmv 
86698d5317Sjmmv u_int
87698d5317Sjmmv layout_set_next(struct window *w)
88698d5317Sjmmv {
89698d5317Sjmmv 	u_int	layout;
90698d5317Sjmmv 
91698d5317Sjmmv 	if (w->lastlayout == -1)
92698d5317Sjmmv 		layout = 0;
93698d5317Sjmmv 	else {
94698d5317Sjmmv 		layout = w->lastlayout + 1;
95698d5317Sjmmv 		if (layout > nitems(layout_sets) - 1)
96698d5317Sjmmv 			layout = 0;
97698d5317Sjmmv 	}
98698d5317Sjmmv 
99698d5317Sjmmv 	if (layout_sets[layout].arrange != NULL)
100698d5317Sjmmv 		layout_sets[layout].arrange(w);
101698d5317Sjmmv 	w->lastlayout = layout;
102698d5317Sjmmv 	return (layout);
103698d5317Sjmmv }
104698d5317Sjmmv 
105698d5317Sjmmv u_int
106698d5317Sjmmv layout_set_previous(struct window *w)
107698d5317Sjmmv {
108698d5317Sjmmv 	u_int	layout;
109698d5317Sjmmv 
110698d5317Sjmmv 	if (w->lastlayout == -1)
111698d5317Sjmmv 		layout = nitems(layout_sets) - 1;
112698d5317Sjmmv 	else {
113698d5317Sjmmv 		layout = w->lastlayout;
114698d5317Sjmmv 		if (layout == 0)
115698d5317Sjmmv 			layout = nitems(layout_sets) - 1;
116698d5317Sjmmv 		else
117698d5317Sjmmv 			layout--;
118698d5317Sjmmv 	}
119698d5317Sjmmv 
120698d5317Sjmmv 	if (layout_sets[layout].arrange != NULL)
121698d5317Sjmmv 		layout_sets[layout].arrange(w);
122698d5317Sjmmv 	w->lastlayout = layout;
123698d5317Sjmmv 	return (layout);
124698d5317Sjmmv }
125698d5317Sjmmv 
1264e179ddaSchristos static void
1278f3b9483Schristos layout_set_even(struct window *w, enum layout_type type)
128698d5317Sjmmv {
129698d5317Sjmmv 	struct window_pane	*wp;
130698d5317Sjmmv 	struct layout_cell	*lc, *lcnew;
131ef36e747Schristos 	u_int			 n, sx, sy;
132698d5317Sjmmv 
133698d5317Sjmmv 	layout_print_cell(w->layout_root, __func__, 1);
134698d5317Sjmmv 
135698d5317Sjmmv 	/* Get number of panes. */
136698d5317Sjmmv 	n = window_count_panes(w);
137698d5317Sjmmv 	if (n <= 1)
138698d5317Sjmmv 		return;
139698d5317Sjmmv 
140698d5317Sjmmv 	/* Free the old root and construct a new. */
141698d5317Sjmmv 	layout_free(w);
142698d5317Sjmmv 	lc = w->layout_root = layout_create_cell(NULL);
143ef36e747Schristos 	if (type == LAYOUT_LEFTRIGHT) {
144ef36e747Schristos 		sx = (n * (PANE_MINIMUM + 1)) - 1;
145ef36e747Schristos 		if (sx < w->sx)
146ef36e747Schristos 			sx = w->sx;
147ef36e747Schristos 		sy = w->sy;
148ef36e747Schristos 	} else {
149ef36e747Schristos 		sy = (n * (PANE_MINIMUM + 1)) - 1;
150ef36e747Schristos 		if (sy < w->sy)
151ef36e747Schristos 			sy = w->sy;
152ef36e747Schristos 		sx = w->sx;
153ef36e747Schristos 	}
154ef36e747Schristos 	layout_set_size(lc, sx, sy, 0, 0);
1558f3b9483Schristos 	layout_make_node(lc, type);
156698d5317Sjmmv 
157698d5317Sjmmv 	/* Build new leaf cells. */
158698d5317Sjmmv 	TAILQ_FOREACH(wp, &w->panes, entry) {
159698d5317Sjmmv 		lcnew = layout_create_cell(lc);
160698d5317Sjmmv 		layout_make_leaf(lcnew, wp);
1618f3b9483Schristos 		lcnew->sx = w->sx;
1628f3b9483Schristos 		lcnew->sy = w->sy;
163698d5317Sjmmv 		TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
164698d5317Sjmmv 	}
165698d5317Sjmmv 
1668f3b9483Schristos 	/* Spread out cells. */
1678f3b9483Schristos 	layout_spread_cell(w, lc);
168698d5317Sjmmv 
169698d5317Sjmmv 	/* Fix cell offsets. */
1706483eba0Schristos 	layout_fix_offsets(w);
1719fb66d81Schristos 	layout_fix_panes(w, NULL);
172698d5317Sjmmv 
173698d5317Sjmmv 	layout_print_cell(w->layout_root, __func__, 1);
174698d5317Sjmmv 
175aa83ff61Schristos 	window_resize(w, lc->sx, lc->sy, -1, -1);
176c9ad075bSchristos 	notify_window("window-layout-changed", w);
177698d5317Sjmmv 	server_redraw_window(w);
178698d5317Sjmmv }
179698d5317Sjmmv 
1804e179ddaSchristos static void
1818f3b9483Schristos layout_set_even_h(struct window *w)
1828f3b9483Schristos {
1838f3b9483Schristos 	layout_set_even(w, LAYOUT_LEFTRIGHT);
1848f3b9483Schristos }
1858f3b9483Schristos 
1868f3b9483Schristos static void
187698d5317Sjmmv layout_set_even_v(struct window *w)
188698d5317Sjmmv {
1898f3b9483Schristos 	layout_set_even(w, LAYOUT_TOPBOTTOM);
190698d5317Sjmmv }
191698d5317Sjmmv 
1924e179ddaSchristos static void
193698d5317Sjmmv layout_set_main_h(struct window *w)
194698d5317Sjmmv {
195698d5317Sjmmv 	struct window_pane	*wp;
196ef36e747Schristos 	struct layout_cell	*lc, *lcmain, *lcother, *lcchild;
1976483eba0Schristos 	u_int			 n, mainh, otherh, sx, sy;
1989fb66d81Schristos 	char			*cause;
1999fb66d81Schristos 	const char		*s;
200698d5317Sjmmv 
201698d5317Sjmmv 	layout_print_cell(w->layout_root, __func__, 1);
202698d5317Sjmmv 
203698d5317Sjmmv 	/* Get number of panes. */
204698d5317Sjmmv 	n = window_count_panes(w);
205698d5317Sjmmv 	if (n <= 1)
206698d5317Sjmmv 		return;
207698d5317Sjmmv 	n--;	/* take off main pane */
208698d5317Sjmmv 
2096483eba0Schristos 	/* Find available height - take off one line for the border. */
2106483eba0Schristos 	sy = w->sy - 1;
2116483eba0Schristos 
2129fb66d81Schristos 	/* Get the main pane height. */
2139fb66d81Schristos 	s = options_get_string(w->options, "main-pane-height");
2149fb66d81Schristos 	mainh = args_string_percentage(s, 0, sy, sy, &cause);
2159fb66d81Schristos 	if (cause != NULL) {
2169fb66d81Schristos 		mainh = 24;
2179fb66d81Schristos 		free(cause);
2189fb66d81Schristos 	}
2199fb66d81Schristos 
2209fb66d81Schristos 	/* Work out the other pane height. */
2216483eba0Schristos 	if (mainh + PANE_MINIMUM >= sy) {
2226483eba0Schristos 		if (sy <= PANE_MINIMUM + PANE_MINIMUM)
223ef36e747Schristos 			mainh = PANE_MINIMUM;
224698d5317Sjmmv 		else
2256483eba0Schristos 			mainh = sy - PANE_MINIMUM;
226ef36e747Schristos 		otherh = PANE_MINIMUM;
227ef36e747Schristos 	} else {
2289fb66d81Schristos 		s = options_get_string(w->options, "other-pane-height");
2299fb66d81Schristos 		otherh = args_string_percentage(s, 0, sy, sy, &cause);
2309fb66d81Schristos 		if (cause != NULL || otherh == 0) {
2316483eba0Schristos 			otherh = sy - mainh;
2329fb66d81Schristos 			free(cause);
2339fb66d81Schristos 		} else if (otherh > sy || sy - otherh < mainh)
2346483eba0Schristos 			otherh = sy - mainh;
235ef36e747Schristos 		else
2366483eba0Schristos 			mainh = sy - otherh;
237ef36e747Schristos 	}
238ef36e747Schristos 
239ef36e747Schristos 	/* Work out what width is needed. */
240ef36e747Schristos 	sx = (n * (PANE_MINIMUM + 1)) - 1;
241ef36e747Schristos 	if (sx < w->sx)
242ef36e747Schristos 		sx = w->sx;
243698d5317Sjmmv 
244698d5317Sjmmv 	/* Free old tree and create a new root. */
245698d5317Sjmmv 	layout_free(w);
246698d5317Sjmmv 	lc = w->layout_root = layout_create_cell(NULL);
2476483eba0Schristos 	layout_set_size(lc, sx, mainh + otherh + 1, 0, 0);
248698d5317Sjmmv 	layout_make_node(lc, LAYOUT_TOPBOTTOM);
249698d5317Sjmmv 
250698d5317Sjmmv 	/* Create the main pane. */
251698d5317Sjmmv 	lcmain = layout_create_cell(lc);
252ef36e747Schristos 	layout_set_size(lcmain, sx, mainh, 0, 0);
253698d5317Sjmmv 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
254698d5317Sjmmv 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
255698d5317Sjmmv 
256ef36e747Schristos 	/* Create the other pane. */
257ef36e747Schristos 	lcother = layout_create_cell(lc);
258ef36e747Schristos 	layout_set_size(lcother, sx, otherh, 0, 0);
259ef36e747Schristos 	if (n == 1) {
260698d5317Sjmmv 		wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
261ef36e747Schristos 		layout_make_leaf(lcother, wp);
262ef36e747Schristos 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
263ef36e747Schristos 	} else {
264ef36e747Schristos 		layout_make_node(lcother, LAYOUT_LEFTRIGHT);
265ef36e747Schristos 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
266698d5317Sjmmv 
267ef36e747Schristos 		/* Add the remaining panes as children. */
268ef36e747Schristos 		TAILQ_FOREACH(wp, &w->panes, entry) {
269ef36e747Schristos 			if (wp == TAILQ_FIRST(&w->panes))
270698d5317Sjmmv 				continue;
271ef36e747Schristos 			lcchild = layout_create_cell(lcother);
272ef36e747Schristos 			layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0);
273698d5317Sjmmv 			layout_make_leaf(lcchild, wp);
274ef36e747Schristos 			TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
275698d5317Sjmmv 		}
276ef36e747Schristos 		layout_spread_cell(w, lcother);
277698d5317Sjmmv 	}
278698d5317Sjmmv 
279698d5317Sjmmv 	/* Fix cell offsets. */
2806483eba0Schristos 	layout_fix_offsets(w);
2819fb66d81Schristos 	layout_fix_panes(w, NULL);
282698d5317Sjmmv 
283698d5317Sjmmv 	layout_print_cell(w->layout_root, __func__, 1);
284698d5317Sjmmv 
285aa83ff61Schristos 	window_resize(w, lc->sx, lc->sy, -1, -1);
286c9ad075bSchristos 	notify_window("window-layout-changed", w);
287698d5317Sjmmv 	server_redraw_window(w);
288698d5317Sjmmv }
289698d5317Sjmmv 
2904e179ddaSchristos static void
291*f8cf1a91Swiz layout_set_main_h_mirrored(struct window *w)
292*f8cf1a91Swiz {
293*f8cf1a91Swiz 	struct window_pane	*wp;
294*f8cf1a91Swiz 	struct layout_cell	*lc, *lcmain, *lcother, *lcchild;
295*f8cf1a91Swiz 	u_int			 n, mainh, otherh, sx, sy;
296*f8cf1a91Swiz 	char			*cause;
297*f8cf1a91Swiz 	const char		*s;
298*f8cf1a91Swiz 
299*f8cf1a91Swiz 	layout_print_cell(w->layout_root, __func__, 1);
300*f8cf1a91Swiz 
301*f8cf1a91Swiz 	/* Get number of panes. */
302*f8cf1a91Swiz 	n = window_count_panes(w);
303*f8cf1a91Swiz 	if (n <= 1)
304*f8cf1a91Swiz 		return;
305*f8cf1a91Swiz 	n--;	/* take off main pane */
306*f8cf1a91Swiz 
307*f8cf1a91Swiz 	/* Find available height - take off one line for the border. */
308*f8cf1a91Swiz 	sy = w->sy - 1;
309*f8cf1a91Swiz 
310*f8cf1a91Swiz 	/* Get the main pane height. */
311*f8cf1a91Swiz 	s = options_get_string(w->options, "main-pane-height");
312*f8cf1a91Swiz 	mainh = args_string_percentage(s, 0, sy, sy, &cause);
313*f8cf1a91Swiz 	if (cause != NULL) {
314*f8cf1a91Swiz 		mainh = 24;
315*f8cf1a91Swiz 		free(cause);
316*f8cf1a91Swiz 	}
317*f8cf1a91Swiz 
318*f8cf1a91Swiz 	/* Work out the other pane height. */
319*f8cf1a91Swiz 	if (mainh + PANE_MINIMUM >= sy) {
320*f8cf1a91Swiz 		if (sy <= PANE_MINIMUM + PANE_MINIMUM)
321*f8cf1a91Swiz 			mainh = PANE_MINIMUM;
322*f8cf1a91Swiz 		else
323*f8cf1a91Swiz 			mainh = sy - PANE_MINIMUM;
324*f8cf1a91Swiz 		otherh = PANE_MINIMUM;
325*f8cf1a91Swiz 	} else {
326*f8cf1a91Swiz 		s = options_get_string(w->options, "other-pane-height");
327*f8cf1a91Swiz 		otherh = args_string_percentage(s, 0, sy, sy, &cause);
328*f8cf1a91Swiz 		if (cause != NULL || otherh == 0) {
329*f8cf1a91Swiz 			otherh = sy - mainh;
330*f8cf1a91Swiz 			free(cause);
331*f8cf1a91Swiz 		} else if (otherh > sy || sy - otherh < mainh)
332*f8cf1a91Swiz 			otherh = sy - mainh;
333*f8cf1a91Swiz 		else
334*f8cf1a91Swiz 			mainh = sy - otherh;
335*f8cf1a91Swiz 	}
336*f8cf1a91Swiz 
337*f8cf1a91Swiz 	/* Work out what width is needed. */
338*f8cf1a91Swiz 	sx = (n * (PANE_MINIMUM + 1)) - 1;
339*f8cf1a91Swiz 	if (sx < w->sx)
340*f8cf1a91Swiz 		sx = w->sx;
341*f8cf1a91Swiz 
342*f8cf1a91Swiz 	/* Free old tree and create a new root. */
343*f8cf1a91Swiz 	layout_free(w);
344*f8cf1a91Swiz 	lc = w->layout_root = layout_create_cell(NULL);
345*f8cf1a91Swiz 	layout_set_size(lc, sx, mainh + otherh + 1, 0, 0);
346*f8cf1a91Swiz 	layout_make_node(lc, LAYOUT_TOPBOTTOM);
347*f8cf1a91Swiz 
348*f8cf1a91Swiz 	/* Create the other pane. */
349*f8cf1a91Swiz 	lcother = layout_create_cell(lc);
350*f8cf1a91Swiz 	layout_set_size(lcother, sx, otherh, 0, 0);
351*f8cf1a91Swiz 	if (n == 1) {
352*f8cf1a91Swiz 		wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
353*f8cf1a91Swiz 		layout_make_leaf(lcother, wp);
354*f8cf1a91Swiz 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
355*f8cf1a91Swiz 	} else {
356*f8cf1a91Swiz 		layout_make_node(lcother, LAYOUT_LEFTRIGHT);
357*f8cf1a91Swiz 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
358*f8cf1a91Swiz 
359*f8cf1a91Swiz 		/* Add the remaining panes as children. */
360*f8cf1a91Swiz 		TAILQ_FOREACH(wp, &w->panes, entry) {
361*f8cf1a91Swiz 			if (wp == TAILQ_FIRST(&w->panes))
362*f8cf1a91Swiz 				continue;
363*f8cf1a91Swiz 			lcchild = layout_create_cell(lcother);
364*f8cf1a91Swiz 			layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0);
365*f8cf1a91Swiz 			layout_make_leaf(lcchild, wp);
366*f8cf1a91Swiz 			TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
367*f8cf1a91Swiz 		}
368*f8cf1a91Swiz 		layout_spread_cell(w, lcother);
369*f8cf1a91Swiz 	}
370*f8cf1a91Swiz 
371*f8cf1a91Swiz 	/* Create the main pane. */
372*f8cf1a91Swiz 	lcmain = layout_create_cell(lc);
373*f8cf1a91Swiz 	layout_set_size(lcmain, sx, mainh, 0, 0);
374*f8cf1a91Swiz 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
375*f8cf1a91Swiz 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
376*f8cf1a91Swiz 
377*f8cf1a91Swiz 	/* Fix cell offsets. */
378*f8cf1a91Swiz 	layout_fix_offsets(w);
379*f8cf1a91Swiz 	layout_fix_panes(w, NULL);
380*f8cf1a91Swiz 
381*f8cf1a91Swiz 	layout_print_cell(w->layout_root, __func__, 1);
382*f8cf1a91Swiz 
383*f8cf1a91Swiz 	window_resize(w, lc->sx, lc->sy, -1, -1);
384*f8cf1a91Swiz 	notify_window("window-layout-changed", w);
385*f8cf1a91Swiz 	server_redraw_window(w);
386*f8cf1a91Swiz }
387*f8cf1a91Swiz 
388*f8cf1a91Swiz static void
389698d5317Sjmmv layout_set_main_v(struct window *w)
390698d5317Sjmmv {
391698d5317Sjmmv 	struct window_pane	*wp;
392ef36e747Schristos 	struct layout_cell	*lc, *lcmain, *lcother, *lcchild;
3936483eba0Schristos 	u_int			 n, mainw, otherw, sx, sy;
3949fb66d81Schristos 	char			*cause;
3959fb66d81Schristos 	const char		*s;
396698d5317Sjmmv 
397698d5317Sjmmv 	layout_print_cell(w->layout_root, __func__, 1);
398698d5317Sjmmv 
399698d5317Sjmmv 	/* Get number of panes. */
400698d5317Sjmmv 	n = window_count_panes(w);
401698d5317Sjmmv 	if (n <= 1)
402698d5317Sjmmv 		return;
403698d5317Sjmmv 	n--;	/* take off main pane */
404698d5317Sjmmv 
4056483eba0Schristos 	/* Find available width - take off one line for the border. */
4066483eba0Schristos 	sx = w->sx - 1;
4076483eba0Schristos 
4089fb66d81Schristos 	/* Get the main pane width. */
4099fb66d81Schristos 	s = options_get_string(w->options, "main-pane-width");
4109fb66d81Schristos 	mainw = args_string_percentage(s, 0, sx, sx, &cause);
4119fb66d81Schristos 	if (cause != NULL) {
4129fb66d81Schristos 		mainw = 80;
4139fb66d81Schristos 		free(cause);
4149fb66d81Schristos 	}
4159fb66d81Schristos 
4169fb66d81Schristos 	/* Work out the other pane width. */
4176483eba0Schristos 	if (mainw + PANE_MINIMUM >= sx) {
4186483eba0Schristos 		if (sx <= PANE_MINIMUM + PANE_MINIMUM)
419ef36e747Schristos 			mainw = PANE_MINIMUM;
420698d5317Sjmmv 		else
4216483eba0Schristos 			mainw = sx - PANE_MINIMUM;
422ef36e747Schristos 		otherw = PANE_MINIMUM;
423ef36e747Schristos 	} else {
4249fb66d81Schristos 		s = options_get_string(w->options, "other-pane-width");
4259fb66d81Schristos 		otherw = args_string_percentage(s, 0, sx, sx, &cause);
4269fb66d81Schristos 		if (cause != NULL || otherw == 0) {
4276483eba0Schristos 			otherw = sx - mainw;
4289fb66d81Schristos 			free(cause);
4299fb66d81Schristos 		} else if (otherw > sx || sx - otherw < mainw)
4306483eba0Schristos 			otherw = sx - mainw;
431ef36e747Schristos 		else
4326483eba0Schristos 			mainw = sx - otherw;
433ef36e747Schristos 	}
434ef36e747Schristos 
435ef36e747Schristos 	/* Work out what height is needed. */
436ef36e747Schristos 	sy = (n * (PANE_MINIMUM + 1)) - 1;
437ef36e747Schristos 	if (sy < w->sy)
438ef36e747Schristos 		sy = w->sy;
439698d5317Sjmmv 
440698d5317Sjmmv 	/* Free old tree and create a new root. */
441698d5317Sjmmv 	layout_free(w);
442698d5317Sjmmv 	lc = w->layout_root = layout_create_cell(NULL);
4436483eba0Schristos 	layout_set_size(lc, mainw + otherw + 1, sy, 0, 0);
444698d5317Sjmmv 	layout_make_node(lc, LAYOUT_LEFTRIGHT);
445698d5317Sjmmv 
446698d5317Sjmmv 	/* Create the main pane. */
447698d5317Sjmmv 	lcmain = layout_create_cell(lc);
448ef36e747Schristos 	layout_set_size(lcmain, mainw, sy, 0, 0);
449698d5317Sjmmv 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
450698d5317Sjmmv 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
451698d5317Sjmmv 
452ef36e747Schristos 	/* Create the other pane. */
453ef36e747Schristos 	lcother = layout_create_cell(lc);
454ef36e747Schristos 	layout_set_size(lcother, otherw, sy, 0, 0);
455ef36e747Schristos 	if (n == 1) {
456698d5317Sjmmv 		wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
457ef36e747Schristos 		layout_make_leaf(lcother, wp);
458ef36e747Schristos 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
459ef36e747Schristos 	} else {
460ef36e747Schristos 		layout_make_node(lcother, LAYOUT_TOPBOTTOM);
461ef36e747Schristos 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
462698d5317Sjmmv 
463ef36e747Schristos 		/* Add the remaining panes as children. */
464ef36e747Schristos 		TAILQ_FOREACH(wp, &w->panes, entry) {
465ef36e747Schristos 			if (wp == TAILQ_FIRST(&w->panes))
466698d5317Sjmmv 				continue;
467ef36e747Schristos 			lcchild = layout_create_cell(lcother);
468ef36e747Schristos 			layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0);
469698d5317Sjmmv 			layout_make_leaf(lcchild, wp);
470ef36e747Schristos 			TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
471698d5317Sjmmv 		}
472ef36e747Schristos 		layout_spread_cell(w, lcother);
473698d5317Sjmmv 	}
474698d5317Sjmmv 
475698d5317Sjmmv 	/* Fix cell offsets. */
4766483eba0Schristos 	layout_fix_offsets(w);
4779fb66d81Schristos 	layout_fix_panes(w, NULL);
478698d5317Sjmmv 
479698d5317Sjmmv 	layout_print_cell(w->layout_root, __func__, 1);
480698d5317Sjmmv 
481aa83ff61Schristos 	window_resize(w, lc->sx, lc->sy, -1, -1);
482c9ad075bSchristos 	notify_window("window-layout-changed", w);
483698d5317Sjmmv 	server_redraw_window(w);
484698d5317Sjmmv }
485698d5317Sjmmv 
486*f8cf1a91Swiz static void
487*f8cf1a91Swiz layout_set_main_v_mirrored(struct window *w)
488*f8cf1a91Swiz {
489*f8cf1a91Swiz 	struct window_pane	*wp;
490*f8cf1a91Swiz 	struct layout_cell	*lc, *lcmain, *lcother, *lcchild;
491*f8cf1a91Swiz 	u_int			 n, mainw, otherw, sx, sy;
492*f8cf1a91Swiz 	char			*cause;
493*f8cf1a91Swiz 	const char		*s;
494*f8cf1a91Swiz 
495*f8cf1a91Swiz 	layout_print_cell(w->layout_root, __func__, 1);
496*f8cf1a91Swiz 
497*f8cf1a91Swiz 	/* Get number of panes. */
498*f8cf1a91Swiz 	n = window_count_panes(w);
499*f8cf1a91Swiz 	if (n <= 1)
500*f8cf1a91Swiz 		return;
501*f8cf1a91Swiz 	n--;	/* take off main pane */
502*f8cf1a91Swiz 
503*f8cf1a91Swiz 	/* Find available width - take off one line for the border. */
504*f8cf1a91Swiz 	sx = w->sx - 1;
505*f8cf1a91Swiz 
506*f8cf1a91Swiz 	/* Get the main pane width. */
507*f8cf1a91Swiz 	s = options_get_string(w->options, "main-pane-width");
508*f8cf1a91Swiz 	mainw = args_string_percentage(s, 0, sx, sx, &cause);
509*f8cf1a91Swiz 	if (cause != NULL) {
510*f8cf1a91Swiz 		mainw = 80;
511*f8cf1a91Swiz 		free(cause);
512*f8cf1a91Swiz 	}
513*f8cf1a91Swiz 
514*f8cf1a91Swiz 	/* Work out the other pane width. */
515*f8cf1a91Swiz 	if (mainw + PANE_MINIMUM >= sx) {
516*f8cf1a91Swiz 		if (sx <= PANE_MINIMUM + PANE_MINIMUM)
517*f8cf1a91Swiz 			mainw = PANE_MINIMUM;
518*f8cf1a91Swiz 		else
519*f8cf1a91Swiz 			mainw = sx - PANE_MINIMUM;
520*f8cf1a91Swiz 		otherw = PANE_MINIMUM;
521*f8cf1a91Swiz 	} else {
522*f8cf1a91Swiz 		s = options_get_string(w->options, "other-pane-width");
523*f8cf1a91Swiz 		otherw = args_string_percentage(s, 0, sx, sx, &cause);
524*f8cf1a91Swiz 		if (cause != NULL || otherw == 0) {
525*f8cf1a91Swiz 			otherw = sx - mainw;
526*f8cf1a91Swiz 			free(cause);
527*f8cf1a91Swiz 		} else if (otherw > sx || sx - otherw < mainw)
528*f8cf1a91Swiz 			otherw = sx - mainw;
529*f8cf1a91Swiz 		else
530*f8cf1a91Swiz 			mainw = sx - otherw;
531*f8cf1a91Swiz 	}
532*f8cf1a91Swiz 
533*f8cf1a91Swiz 	/* Work out what height is needed. */
534*f8cf1a91Swiz 	sy = (n * (PANE_MINIMUM + 1)) - 1;
535*f8cf1a91Swiz 	if (sy < w->sy)
536*f8cf1a91Swiz 		sy = w->sy;
537*f8cf1a91Swiz 
538*f8cf1a91Swiz 	/* Free old tree and create a new root. */
539*f8cf1a91Swiz 	layout_free(w);
540*f8cf1a91Swiz 	lc = w->layout_root = layout_create_cell(NULL);
541*f8cf1a91Swiz 	layout_set_size(lc, mainw + otherw + 1, sy, 0, 0);
542*f8cf1a91Swiz 	layout_make_node(lc, LAYOUT_LEFTRIGHT);
543*f8cf1a91Swiz 
544*f8cf1a91Swiz 	/* Create the other pane. */
545*f8cf1a91Swiz 	lcother = layout_create_cell(lc);
546*f8cf1a91Swiz 	layout_set_size(lcother, otherw, sy, 0, 0);
547*f8cf1a91Swiz 	if (n == 1) {
548*f8cf1a91Swiz 		wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
549*f8cf1a91Swiz 		layout_make_leaf(lcother, wp);
550*f8cf1a91Swiz 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
551*f8cf1a91Swiz 	} else {
552*f8cf1a91Swiz 		layout_make_node(lcother, LAYOUT_TOPBOTTOM);
553*f8cf1a91Swiz 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
554*f8cf1a91Swiz 
555*f8cf1a91Swiz 		/* Add the remaining panes as children. */
556*f8cf1a91Swiz 		TAILQ_FOREACH(wp, &w->panes, entry) {
557*f8cf1a91Swiz 			if (wp == TAILQ_FIRST(&w->panes))
558*f8cf1a91Swiz 				continue;
559*f8cf1a91Swiz 			lcchild = layout_create_cell(lcother);
560*f8cf1a91Swiz 			layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0);
561*f8cf1a91Swiz 			layout_make_leaf(lcchild, wp);
562*f8cf1a91Swiz 			TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
563*f8cf1a91Swiz 		}
564*f8cf1a91Swiz 		layout_spread_cell(w, lcother);
565*f8cf1a91Swiz 	}
566*f8cf1a91Swiz 
567*f8cf1a91Swiz 	/* Create the main pane. */
568*f8cf1a91Swiz 	lcmain = layout_create_cell(lc);
569*f8cf1a91Swiz 	layout_set_size(lcmain, mainw, sy, 0, 0);
570*f8cf1a91Swiz 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
571*f8cf1a91Swiz 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
572*f8cf1a91Swiz 
573*f8cf1a91Swiz 	/* Fix cell offsets. */
574*f8cf1a91Swiz 	layout_fix_offsets(w);
575*f8cf1a91Swiz 	layout_fix_panes(w, NULL);
576*f8cf1a91Swiz 
577*f8cf1a91Swiz 	layout_print_cell(w->layout_root, __func__, 1);
578*f8cf1a91Swiz 
579*f8cf1a91Swiz 	window_resize(w, lc->sx, lc->sy, -1, -1);
580*f8cf1a91Swiz 	notify_window("window-layout-changed", w);
581*f8cf1a91Swiz 	server_redraw_window(w);
582*f8cf1a91Swiz }
583*f8cf1a91Swiz 
584698d5317Sjmmv void
585698d5317Sjmmv layout_set_tiled(struct window *w)
586698d5317Sjmmv {
587698d5317Sjmmv 	struct window_pane	*wp;
588698d5317Sjmmv 	struct layout_cell	*lc, *lcrow, *lcchild;
589ef36e747Schristos 	u_int			 n, width, height, used, sx, sy;
590698d5317Sjmmv 	u_int			 i, j, columns, rows;
591698d5317Sjmmv 
592698d5317Sjmmv 	layout_print_cell(w->layout_root, __func__, 1);
593698d5317Sjmmv 
594698d5317Sjmmv 	/* Get number of panes. */
595698d5317Sjmmv 	n = window_count_panes(w);
596698d5317Sjmmv 	if (n <= 1)
597698d5317Sjmmv 		return;
598698d5317Sjmmv 
599698d5317Sjmmv 	/* How many rows and columns are wanted? */
600698d5317Sjmmv 	rows = columns = 1;
601698d5317Sjmmv 	while (rows * columns < n) {
602698d5317Sjmmv 		rows++;
603698d5317Sjmmv 		if (rows * columns < n)
604698d5317Sjmmv 			columns++;
605698d5317Sjmmv 	}
606698d5317Sjmmv 
607698d5317Sjmmv 	/* What width and height should they be? */
608698d5317Sjmmv 	width = (w->sx - (columns - 1)) / columns;
609698d5317Sjmmv 	if (width < PANE_MINIMUM)
610698d5317Sjmmv 		width = PANE_MINIMUM;
611698d5317Sjmmv 	height = (w->sy - (rows - 1)) / rows;
612698d5317Sjmmv 	if (height < PANE_MINIMUM)
613698d5317Sjmmv 		height = PANE_MINIMUM;
614698d5317Sjmmv 
615698d5317Sjmmv 	/* Free old tree and create a new root. */
616698d5317Sjmmv 	layout_free(w);
617698d5317Sjmmv 	lc = w->layout_root = layout_create_cell(NULL);
618ef36e747Schristos 	sx = ((width + 1) * columns) - 1;
619ef36e747Schristos 	if (sx < w->sx)
620ef36e747Schristos 		sx = w->sx;
621ef36e747Schristos 	sy = ((height + 1) * rows) - 1;
622ef36e747Schristos 	if (sy < w->sy)
623ef36e747Schristos 		sy = w->sy;
624ef36e747Schristos 	layout_set_size(lc, sx, sy, 0, 0);
625698d5317Sjmmv 	layout_make_node(lc, LAYOUT_TOPBOTTOM);
626698d5317Sjmmv 
627698d5317Sjmmv 	/* Create a grid of the cells. */
628698d5317Sjmmv 	wp = TAILQ_FIRST(&w->panes);
629698d5317Sjmmv 	for (j = 0; j < rows; j++) {
630698d5317Sjmmv 		/* If this is the last cell, all done. */
631698d5317Sjmmv 		if (wp == NULL)
632698d5317Sjmmv 			break;
633698d5317Sjmmv 
634698d5317Sjmmv 		/* Create the new row. */
635698d5317Sjmmv 		lcrow = layout_create_cell(lc);
636698d5317Sjmmv 		layout_set_size(lcrow, w->sx, height, 0, 0);
637698d5317Sjmmv 		TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
638698d5317Sjmmv 
639698d5317Sjmmv 		/* If only one column, just use the row directly. */
640d530c4d0Sjmmv 		if (n - (j * columns) == 1 || columns == 1) {
641698d5317Sjmmv 			layout_make_leaf(lcrow, wp);
642698d5317Sjmmv 			wp = TAILQ_NEXT(wp, entry);
643698d5317Sjmmv 			continue;
644698d5317Sjmmv 		}
645698d5317Sjmmv 
646698d5317Sjmmv 		/* Add in the columns. */
647698d5317Sjmmv 		layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
648698d5317Sjmmv 		for (i = 0; i < columns; i++) {
649698d5317Sjmmv 			/* Create and add a pane cell. */
650698d5317Sjmmv 			lcchild = layout_create_cell(lcrow);
651698d5317Sjmmv 			layout_set_size(lcchild, width, height, 0, 0);
652698d5317Sjmmv 			layout_make_leaf(lcchild, wp);
653698d5317Sjmmv 			TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
654698d5317Sjmmv 
655698d5317Sjmmv 			/* Move to the next cell. */
656698d5317Sjmmv 			if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
657698d5317Sjmmv 				break;
658698d5317Sjmmv 		}
659698d5317Sjmmv 
660698d5317Sjmmv 		/*
661698d5317Sjmmv 		 * Adjust the row and columns to fit the full width if
662698d5317Sjmmv 		 * necessary.
663698d5317Sjmmv 		 */
664698d5317Sjmmv 		if (i == columns)
665698d5317Sjmmv 			i--;
666698d5317Sjmmv 		used = ((i + 1) * (width + 1)) - 1;
667698d5317Sjmmv 		if (w->sx <= used)
668698d5317Sjmmv 			continue;
669698d5317Sjmmv 		lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
6704e179ddaSchristos 		layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
6714e179ddaSchristos 		    w->sx - used);
672698d5317Sjmmv 	}
673698d5317Sjmmv 
674698d5317Sjmmv 	/* Adjust the last row height to fit if necessary. */
675698d5317Sjmmv 	used = (rows * height) + rows - 1;
676698d5317Sjmmv 	if (w->sy > used) {
677698d5317Sjmmv 		lcrow = TAILQ_LAST(&lc->cells, layout_cells);
6784e179ddaSchristos 		layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
6794e179ddaSchristos 		    w->sy - used);
680698d5317Sjmmv 	}
681698d5317Sjmmv 
682698d5317Sjmmv 	/* Fix cell offsets. */
6836483eba0Schristos 	layout_fix_offsets(w);
6849fb66d81Schristos 	layout_fix_panes(w, NULL);
685698d5317Sjmmv 
686698d5317Sjmmv 	layout_print_cell(w->layout_root, __func__, 1);
687698d5317Sjmmv 
688aa83ff61Schristos 	window_resize(w, lc->sx, lc->sy, -1, -1);
689c9ad075bSchristos 	notify_window("window-layout-changed", w);
690698d5317Sjmmv 	server_redraw_window(w);
691698d5317Sjmmv }
692