Home | History | Annotate | Line # | Download | only in dist
      1 /* $OpenBSD$ */
      2 
      3 /*
      4  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott (at) gmail.com>
      5  *
      6  * Permission to use, copy, modify, and distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  */
     18 
     19 #include <sys/types.h>
     20 
     21 #include <stdlib.h>
     22 #include <string.h>
     23 
     24 #include "tmux.h"
     25 
     26 /*
     27  * Set window layouts - predefined methods to arrange windows. These are
     28  * one-off and generate a layout tree.
     29  */
     30 
     31 static void	layout_set_even_h(struct window *);
     32 static void	layout_set_even_v(struct window *);
     33 static void	layout_set_main_h(struct window *);
     34 static void	layout_set_main_h_mirrored(struct window *);
     35 static void	layout_set_main_v(struct window *);
     36 static void	layout_set_main_v_mirrored(struct window *);
     37 static void	layout_set_tiled(struct window *);
     38 
     39 static const struct {
     40 	const char	*name;
     41 	void	      	(*arrange)(struct window *);
     42 } layout_sets[] = {
     43 	{ "even-horizontal", layout_set_even_h },
     44 	{ "even-vertical", layout_set_even_v },
     45 	{ "main-horizontal", layout_set_main_h },
     46 	{ "main-horizontal-mirrored", layout_set_main_h_mirrored },
     47 	{ "main-vertical", layout_set_main_v },
     48 	{ "main-vertical-mirrored", layout_set_main_v_mirrored },
     49 	{ "tiled", layout_set_tiled },
     50 };
     51 
     52 int
     53 layout_set_lookup(const char *name)
     54 {
     55 	u_int	i;
     56 	int	matched = -1;
     57 
     58 	for (i = 0; i < nitems(layout_sets); i++) {
     59 		if (strcmp(layout_sets[i].name, name) == 0)
     60 			return (i);
     61 	}
     62 	for (i = 0; i < nitems(layout_sets); i++) {
     63 		if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) {
     64 			if (matched != -1)	/* ambiguous */
     65 				return (-1);
     66 			matched = i;
     67 		}
     68 	}
     69 
     70 	return (matched);
     71 }
     72 
     73 u_int
     74 layout_set_select(struct window *w, u_int layout)
     75 {
     76 	if (layout > nitems(layout_sets) - 1)
     77 		layout = nitems(layout_sets) - 1;
     78 
     79 	if (layout_sets[layout].arrange != NULL)
     80 		layout_sets[layout].arrange(w);
     81 
     82 	w->lastlayout = layout;
     83 	return (layout);
     84 }
     85 
     86 u_int
     87 layout_set_next(struct window *w)
     88 {
     89 	u_int	layout;
     90 
     91 	if (w->lastlayout == -1)
     92 		layout = 0;
     93 	else {
     94 		layout = w->lastlayout + 1;
     95 		if (layout > nitems(layout_sets) - 1)
     96 			layout = 0;
     97 	}
     98 
     99 	if (layout_sets[layout].arrange != NULL)
    100 		layout_sets[layout].arrange(w);
    101 	w->lastlayout = layout;
    102 	return (layout);
    103 }
    104 
    105 u_int
    106 layout_set_previous(struct window *w)
    107 {
    108 	u_int	layout;
    109 
    110 	if (w->lastlayout == -1)
    111 		layout = nitems(layout_sets) - 1;
    112 	else {
    113 		layout = w->lastlayout;
    114 		if (layout == 0)
    115 			layout = nitems(layout_sets) - 1;
    116 		else
    117 			layout--;
    118 	}
    119 
    120 	if (layout_sets[layout].arrange != NULL)
    121 		layout_sets[layout].arrange(w);
    122 	w->lastlayout = layout;
    123 	return (layout);
    124 }
    125 
    126 static void
    127 layout_set_even(struct window *w, enum layout_type type)
    128 {
    129 	struct window_pane	*wp;
    130 	struct layout_cell	*lc, *lcnew;
    131 	u_int			 n, sx, sy;
    132 
    133 	layout_print_cell(w->layout_root, __func__, 1);
    134 
    135 	/* Get number of panes. */
    136 	n = window_count_panes(w);
    137 	if (n <= 1)
    138 		return;
    139 
    140 	/* Free the old root and construct a new. */
    141 	layout_free(w);
    142 	lc = w->layout_root = layout_create_cell(NULL);
    143 	if (type == LAYOUT_LEFTRIGHT) {
    144 		sx = (n * (PANE_MINIMUM + 1)) - 1;
    145 		if (sx < w->sx)
    146 			sx = w->sx;
    147 		sy = w->sy;
    148 	} else {
    149 		sy = (n * (PANE_MINIMUM + 1)) - 1;
    150 		if (sy < w->sy)
    151 			sy = w->sy;
    152 		sx = w->sx;
    153 	}
    154 	layout_set_size(lc, sx, sy, 0, 0);
    155 	layout_make_node(lc, type);
    156 
    157 	/* Build new leaf cells. */
    158 	TAILQ_FOREACH(wp, &w->panes, entry) {
    159 		lcnew = layout_create_cell(lc);
    160 		layout_make_leaf(lcnew, wp);
    161 		lcnew->sx = w->sx;
    162 		lcnew->sy = w->sy;
    163 		TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
    164 	}
    165 
    166 	/* Spread out cells. */
    167 	layout_spread_cell(w, lc);
    168 
    169 	/* Fix cell offsets. */
    170 	layout_fix_offsets(w);
    171 	layout_fix_panes(w, NULL);
    172 
    173 	layout_print_cell(w->layout_root, __func__, 1);
    174 
    175 	window_resize(w, lc->sx, lc->sy, -1, -1);
    176 	notify_window("window-layout-changed", w);
    177 	server_redraw_window(w);
    178 }
    179 
    180 static void
    181 layout_set_even_h(struct window *w)
    182 {
    183 	layout_set_even(w, LAYOUT_LEFTRIGHT);
    184 }
    185 
    186 static void
    187 layout_set_even_v(struct window *w)
    188 {
    189 	layout_set_even(w, LAYOUT_TOPBOTTOM);
    190 }
    191 
    192 static void
    193 layout_set_main_h(struct window *w)
    194 {
    195 	struct window_pane	*wp;
    196 	struct layout_cell	*lc, *lcmain, *lcother, *lcchild;
    197 	u_int			 n, mainh, otherh, sx, sy;
    198 	char			*cause;
    199 	const char		*s;
    200 
    201 	layout_print_cell(w->layout_root, __func__, 1);
    202 
    203 	/* Get number of panes. */
    204 	n = window_count_panes(w);
    205 	if (n <= 1)
    206 		return;
    207 	n--;	/* take off main pane */
    208 
    209 	/* Find available height - take off one line for the border. */
    210 	sy = w->sy - 1;
    211 
    212 	/* Get the main pane height. */
    213 	s = options_get_string(w->options, "main-pane-height");
    214 	mainh = args_string_percentage(s, 0, sy, sy, &cause);
    215 	if (cause != NULL) {
    216 		mainh = 24;
    217 		free(cause);
    218 	}
    219 
    220 	/* Work out the other pane height. */
    221 	if (mainh + PANE_MINIMUM >= sy) {
    222 		if (sy <= PANE_MINIMUM + PANE_MINIMUM)
    223 			mainh = PANE_MINIMUM;
    224 		else
    225 			mainh = sy - PANE_MINIMUM;
    226 		otherh = PANE_MINIMUM;
    227 	} else {
    228 		s = options_get_string(w->options, "other-pane-height");
    229 		otherh = args_string_percentage(s, 0, sy, sy, &cause);
    230 		if (cause != NULL || otherh == 0) {
    231 			otherh = sy - mainh;
    232 			free(cause);
    233 		} else if (otherh > sy || sy - otherh < mainh)
    234 			otherh = sy - mainh;
    235 		else
    236 			mainh = sy - otherh;
    237 	}
    238 
    239 	/* Work out what width is needed. */
    240 	sx = (n * (PANE_MINIMUM + 1)) - 1;
    241 	if (sx < w->sx)
    242 		sx = w->sx;
    243 
    244 	/* Free old tree and create a new root. */
    245 	layout_free(w);
    246 	lc = w->layout_root = layout_create_cell(NULL);
    247 	layout_set_size(lc, sx, mainh + otherh + 1, 0, 0);
    248 	layout_make_node(lc, LAYOUT_TOPBOTTOM);
    249 
    250 	/* Create the main pane. */
    251 	lcmain = layout_create_cell(lc);
    252 	layout_set_size(lcmain, sx, mainh, 0, 0);
    253 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
    254 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
    255 
    256 	/* Create the other pane. */
    257 	lcother = layout_create_cell(lc);
    258 	layout_set_size(lcother, sx, otherh, 0, 0);
    259 	if (n == 1) {
    260 		wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
    261 		layout_make_leaf(lcother, wp);
    262 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
    263 	} else {
    264 		layout_make_node(lcother, LAYOUT_LEFTRIGHT);
    265 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
    266 
    267 		/* Add the remaining panes as children. */
    268 		TAILQ_FOREACH(wp, &w->panes, entry) {
    269 			if (wp == TAILQ_FIRST(&w->panes))
    270 				continue;
    271 			lcchild = layout_create_cell(lcother);
    272 			layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0);
    273 			layout_make_leaf(lcchild, wp);
    274 			TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
    275 		}
    276 		layout_spread_cell(w, lcother);
    277 	}
    278 
    279 	/* Fix cell offsets. */
    280 	layout_fix_offsets(w);
    281 	layout_fix_panes(w, NULL);
    282 
    283 	layout_print_cell(w->layout_root, __func__, 1);
    284 
    285 	window_resize(w, lc->sx, lc->sy, -1, -1);
    286 	notify_window("window-layout-changed", w);
    287 	server_redraw_window(w);
    288 }
    289 
    290 static void
    291 layout_set_main_h_mirrored(struct window *w)
    292 {
    293 	struct window_pane	*wp;
    294 	struct layout_cell	*lc, *lcmain, *lcother, *lcchild;
    295 	u_int			 n, mainh, otherh, sx, sy;
    296 	char			*cause;
    297 	const char		*s;
    298 
    299 	layout_print_cell(w->layout_root, __func__, 1);
    300 
    301 	/* Get number of panes. */
    302 	n = window_count_panes(w);
    303 	if (n <= 1)
    304 		return;
    305 	n--;	/* take off main pane */
    306 
    307 	/* Find available height - take off one line for the border. */
    308 	sy = w->sy - 1;
    309 
    310 	/* Get the main pane height. */
    311 	s = options_get_string(w->options, "main-pane-height");
    312 	mainh = args_string_percentage(s, 0, sy, sy, &cause);
    313 	if (cause != NULL) {
    314 		mainh = 24;
    315 		free(cause);
    316 	}
    317 
    318 	/* Work out the other pane height. */
    319 	if (mainh + PANE_MINIMUM >= sy) {
    320 		if (sy <= PANE_MINIMUM + PANE_MINIMUM)
    321 			mainh = PANE_MINIMUM;
    322 		else
    323 			mainh = sy - PANE_MINIMUM;
    324 		otherh = PANE_MINIMUM;
    325 	} else {
    326 		s = options_get_string(w->options, "other-pane-height");
    327 		otherh = args_string_percentage(s, 0, sy, sy, &cause);
    328 		if (cause != NULL || otherh == 0) {
    329 			otherh = sy - mainh;
    330 			free(cause);
    331 		} else if (otherh > sy || sy - otherh < mainh)
    332 			otherh = sy - mainh;
    333 		else
    334 			mainh = sy - otherh;
    335 	}
    336 
    337 	/* Work out what width is needed. */
    338 	sx = (n * (PANE_MINIMUM + 1)) - 1;
    339 	if (sx < w->sx)
    340 		sx = w->sx;
    341 
    342 	/* Free old tree and create a new root. */
    343 	layout_free(w);
    344 	lc = w->layout_root = layout_create_cell(NULL);
    345 	layout_set_size(lc, sx, mainh + otherh + 1, 0, 0);
    346 	layout_make_node(lc, LAYOUT_TOPBOTTOM);
    347 
    348 	/* Create the other pane. */
    349 	lcother = layout_create_cell(lc);
    350 	layout_set_size(lcother, sx, otherh, 0, 0);
    351 	if (n == 1) {
    352 		wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
    353 		layout_make_leaf(lcother, wp);
    354 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
    355 	} else {
    356 		layout_make_node(lcother, LAYOUT_LEFTRIGHT);
    357 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
    358 
    359 		/* Add the remaining panes as children. */
    360 		TAILQ_FOREACH(wp, &w->panes, entry) {
    361 			if (wp == TAILQ_FIRST(&w->panes))
    362 				continue;
    363 			lcchild = layout_create_cell(lcother);
    364 			layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0);
    365 			layout_make_leaf(lcchild, wp);
    366 			TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
    367 		}
    368 		layout_spread_cell(w, lcother);
    369 	}
    370 
    371 	/* Create the main pane. */
    372 	lcmain = layout_create_cell(lc);
    373 	layout_set_size(lcmain, sx, mainh, 0, 0);
    374 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
    375 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
    376 
    377 	/* Fix cell offsets. */
    378 	layout_fix_offsets(w);
    379 	layout_fix_panes(w, NULL);
    380 
    381 	layout_print_cell(w->layout_root, __func__, 1);
    382 
    383 	window_resize(w, lc->sx, lc->sy, -1, -1);
    384 	notify_window("window-layout-changed", w);
    385 	server_redraw_window(w);
    386 }
    387 
    388 static void
    389 layout_set_main_v(struct window *w)
    390 {
    391 	struct window_pane	*wp;
    392 	struct layout_cell	*lc, *lcmain, *lcother, *lcchild;
    393 	u_int			 n, mainw, otherw, sx, sy;
    394 	char			*cause;
    395 	const char		*s;
    396 
    397 	layout_print_cell(w->layout_root, __func__, 1);
    398 
    399 	/* Get number of panes. */
    400 	n = window_count_panes(w);
    401 	if (n <= 1)
    402 		return;
    403 	n--;	/* take off main pane */
    404 
    405 	/* Find available width - take off one line for the border. */
    406 	sx = w->sx - 1;
    407 
    408 	/* Get the main pane width. */
    409 	s = options_get_string(w->options, "main-pane-width");
    410 	mainw = args_string_percentage(s, 0, sx, sx, &cause);
    411 	if (cause != NULL) {
    412 		mainw = 80;
    413 		free(cause);
    414 	}
    415 
    416 	/* Work out the other pane width. */
    417 	if (mainw + PANE_MINIMUM >= sx) {
    418 		if (sx <= PANE_MINIMUM + PANE_MINIMUM)
    419 			mainw = PANE_MINIMUM;
    420 		else
    421 			mainw = sx - PANE_MINIMUM;
    422 		otherw = PANE_MINIMUM;
    423 	} else {
    424 		s = options_get_string(w->options, "other-pane-width");
    425 		otherw = args_string_percentage(s, 0, sx, sx, &cause);
    426 		if (cause != NULL || otherw == 0) {
    427 			otherw = sx - mainw;
    428 			free(cause);
    429 		} else if (otherw > sx || sx - otherw < mainw)
    430 			otherw = sx - mainw;
    431 		else
    432 			mainw = sx - otherw;
    433 	}
    434 
    435 	/* Work out what height is needed. */
    436 	sy = (n * (PANE_MINIMUM + 1)) - 1;
    437 	if (sy < w->sy)
    438 		sy = w->sy;
    439 
    440 	/* Free old tree and create a new root. */
    441 	layout_free(w);
    442 	lc = w->layout_root = layout_create_cell(NULL);
    443 	layout_set_size(lc, mainw + otherw + 1, sy, 0, 0);
    444 	layout_make_node(lc, LAYOUT_LEFTRIGHT);
    445 
    446 	/* Create the main pane. */
    447 	lcmain = layout_create_cell(lc);
    448 	layout_set_size(lcmain, mainw, sy, 0, 0);
    449 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
    450 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
    451 
    452 	/* Create the other pane. */
    453 	lcother = layout_create_cell(lc);
    454 	layout_set_size(lcother, otherw, sy, 0, 0);
    455 	if (n == 1) {
    456 		wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
    457 		layout_make_leaf(lcother, wp);
    458 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
    459 	} else {
    460 		layout_make_node(lcother, LAYOUT_TOPBOTTOM);
    461 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
    462 
    463 		/* Add the remaining panes as children. */
    464 		TAILQ_FOREACH(wp, &w->panes, entry) {
    465 			if (wp == TAILQ_FIRST(&w->panes))
    466 				continue;
    467 			lcchild = layout_create_cell(lcother);
    468 			layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0);
    469 			layout_make_leaf(lcchild, wp);
    470 			TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
    471 		}
    472 		layout_spread_cell(w, lcother);
    473 	}
    474 
    475 	/* Fix cell offsets. */
    476 	layout_fix_offsets(w);
    477 	layout_fix_panes(w, NULL);
    478 
    479 	layout_print_cell(w->layout_root, __func__, 1);
    480 
    481 	window_resize(w, lc->sx, lc->sy, -1, -1);
    482 	notify_window("window-layout-changed", w);
    483 	server_redraw_window(w);
    484 }
    485 
    486 static void
    487 layout_set_main_v_mirrored(struct window *w)
    488 {
    489 	struct window_pane	*wp;
    490 	struct layout_cell	*lc, *lcmain, *lcother, *lcchild;
    491 	u_int			 n, mainw, otherw, sx, sy;
    492 	char			*cause;
    493 	const char		*s;
    494 
    495 	layout_print_cell(w->layout_root, __func__, 1);
    496 
    497 	/* Get number of panes. */
    498 	n = window_count_panes(w);
    499 	if (n <= 1)
    500 		return;
    501 	n--;	/* take off main pane */
    502 
    503 	/* Find available width - take off one line for the border. */
    504 	sx = w->sx - 1;
    505 
    506 	/* Get the main pane width. */
    507 	s = options_get_string(w->options, "main-pane-width");
    508 	mainw = args_string_percentage(s, 0, sx, sx, &cause);
    509 	if (cause != NULL) {
    510 		mainw = 80;
    511 		free(cause);
    512 	}
    513 
    514 	/* Work out the other pane width. */
    515 	if (mainw + PANE_MINIMUM >= sx) {
    516 		if (sx <= PANE_MINIMUM + PANE_MINIMUM)
    517 			mainw = PANE_MINIMUM;
    518 		else
    519 			mainw = sx - PANE_MINIMUM;
    520 		otherw = PANE_MINIMUM;
    521 	} else {
    522 		s = options_get_string(w->options, "other-pane-width");
    523 		otherw = args_string_percentage(s, 0, sx, sx, &cause);
    524 		if (cause != NULL || otherw == 0) {
    525 			otherw = sx - mainw;
    526 			free(cause);
    527 		} else if (otherw > sx || sx - otherw < mainw)
    528 			otherw = sx - mainw;
    529 		else
    530 			mainw = sx - otherw;
    531 	}
    532 
    533 	/* Work out what height is needed. */
    534 	sy = (n * (PANE_MINIMUM + 1)) - 1;
    535 	if (sy < w->sy)
    536 		sy = w->sy;
    537 
    538 	/* Free old tree and create a new root. */
    539 	layout_free(w);
    540 	lc = w->layout_root = layout_create_cell(NULL);
    541 	layout_set_size(lc, mainw + otherw + 1, sy, 0, 0);
    542 	layout_make_node(lc, LAYOUT_LEFTRIGHT);
    543 
    544 	/* Create the other pane. */
    545 	lcother = layout_create_cell(lc);
    546 	layout_set_size(lcother, otherw, sy, 0, 0);
    547 	if (n == 1) {
    548 		wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
    549 		layout_make_leaf(lcother, wp);
    550 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
    551 	} else {
    552 		layout_make_node(lcother, LAYOUT_TOPBOTTOM);
    553 		TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
    554 
    555 		/* Add the remaining panes as children. */
    556 		TAILQ_FOREACH(wp, &w->panes, entry) {
    557 			if (wp == TAILQ_FIRST(&w->panes))
    558 				continue;
    559 			lcchild = layout_create_cell(lcother);
    560 			layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0);
    561 			layout_make_leaf(lcchild, wp);
    562 			TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
    563 		}
    564 		layout_spread_cell(w, lcother);
    565 	}
    566 
    567 	/* Create the main pane. */
    568 	lcmain = layout_create_cell(lc);
    569 	layout_set_size(lcmain, mainw, sy, 0, 0);
    570 	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
    571 	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
    572 
    573 	/* Fix cell offsets. */
    574 	layout_fix_offsets(w);
    575 	layout_fix_panes(w, NULL);
    576 
    577 	layout_print_cell(w->layout_root, __func__, 1);
    578 
    579 	window_resize(w, lc->sx, lc->sy, -1, -1);
    580 	notify_window("window-layout-changed", w);
    581 	server_redraw_window(w);
    582 }
    583 
    584 void
    585 layout_set_tiled(struct window *w)
    586 {
    587 	struct options		*oo = w->options;
    588 	struct window_pane	*wp;
    589 	struct layout_cell	*lc, *lcrow, *lcchild;
    590 	u_int			 n, width, height, used, sx, sy;
    591 	u_int			 i, j, columns, rows, max_columns;
    592 
    593 	layout_print_cell(w->layout_root, __func__, 1);
    594 
    595 	/* Get number of panes. */
    596 	n = window_count_panes(w);
    597 	if (n <= 1)
    598 		return;
    599 
    600 	/* Get maximum columns from window option. */
    601 	max_columns = options_get_number(oo, "tiled-layout-max-columns");
    602 
    603 	/* How many rows and columns are wanted? */
    604 	rows = columns = 1;
    605 	while (rows * columns < n) {
    606 		rows++;
    607 		if (rows * columns < n &&
    608 		    (max_columns == 0 || columns < max_columns))
    609 			columns++;
    610 	}
    611 
    612 	/* What width and height should they be? */
    613 	width = (w->sx - (columns - 1)) / columns;
    614 	if (width < PANE_MINIMUM)
    615 		width = PANE_MINIMUM;
    616 	height = (w->sy - (rows - 1)) / rows;
    617 	if (height < PANE_MINIMUM)
    618 		height = PANE_MINIMUM;
    619 
    620 	/* Free old tree and create a new root. */
    621 	layout_free(w);
    622 	lc = w->layout_root = layout_create_cell(NULL);
    623 	sx = ((width + 1) * columns) - 1;
    624 	if (sx < w->sx)
    625 		sx = w->sx;
    626 	sy = ((height + 1) * rows) - 1;
    627 	if (sy < w->sy)
    628 		sy = w->sy;
    629 	layout_set_size(lc, sx, sy, 0, 0);
    630 	layout_make_node(lc, LAYOUT_TOPBOTTOM);
    631 
    632 	/* Create a grid of the cells. */
    633 	wp = TAILQ_FIRST(&w->panes);
    634 	for (j = 0; j < rows; j++) {
    635 		/* If this is the last cell, all done. */
    636 		if (wp == NULL)
    637 			break;
    638 
    639 		/* Create the new row. */
    640 		lcrow = layout_create_cell(lc);
    641 		layout_set_size(lcrow, w->sx, height, 0, 0);
    642 		TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
    643 
    644 		/* If only one column, just use the row directly. */
    645 		if (n - (j * columns) == 1 || columns == 1) {
    646 			layout_make_leaf(lcrow, wp);
    647 			wp = TAILQ_NEXT(wp, entry);
    648 			continue;
    649 		}
    650 
    651 		/* Add in the columns. */
    652 		layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
    653 		for (i = 0; i < columns; i++) {
    654 			/* Create and add a pane cell. */
    655 			lcchild = layout_create_cell(lcrow);
    656 			layout_set_size(lcchild, width, height, 0, 0);
    657 			layout_make_leaf(lcchild, wp);
    658 			TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
    659 
    660 			/* Move to the next cell. */
    661 			if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
    662 				break;
    663 		}
    664 
    665 		/*
    666 		 * Adjust the row and columns to fit the full width if
    667 		 * necessary.
    668 		 */
    669 		if (i == columns)
    670 			i--;
    671 		used = ((i + 1) * (width + 1)) - 1;
    672 		if (w->sx <= used)
    673 			continue;
    674 		lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
    675 		layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
    676 		    w->sx - used);
    677 	}
    678 
    679 	/* Adjust the last row height to fit if necessary. */
    680 	used = (rows * height) + rows - 1;
    681 	if (w->sy > used) {
    682 		lcrow = TAILQ_LAST(&lc->cells, layout_cells);
    683 		layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
    684 		    w->sy - used);
    685 	}
    686 
    687 	/* Fix cell offsets. */
    688 	layout_fix_offsets(w);
    689 	layout_fix_panes(w, NULL);
    690 
    691 	layout_print_cell(w->layout_root, __func__, 1);
    692 
    693 	window_resize(w, lc->sx, lc->sy, -1, -1);
    694 	notify_window("window-layout-changed", w);
    695 	server_redraw_window(w);
    696 }
    697