xref: /openbsd/usr.bin/tmux/layout-set.c (revision cd409aae)
1 /* $OpenBSD: layout-set.c,v 1.32 2024/08/23 10:19:06 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@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
layout_set_lookup(const char * name)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
layout_set_select(struct window * w,u_int layout)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
layout_set_next(struct window * w)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
layout_set_previous(struct window * w)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
layout_set_even(struct window * w,enum layout_type type)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
layout_set_even_h(struct window * w)181 layout_set_even_h(struct window *w)
182 {
183 	layout_set_even(w, LAYOUT_LEFTRIGHT);
184 }
185 
186 static void
layout_set_even_v(struct window * w)187 layout_set_even_v(struct window *w)
188 {
189 	layout_set_even(w, LAYOUT_TOPBOTTOM);
190 }
191 
192 static void
layout_set_main_h(struct window * w)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
layout_set_main_h_mirrored(struct window * w)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
layout_set_main_v(struct window * w)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
layout_set_main_v_mirrored(struct window * w)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
layout_set_tiled(struct window * w)585 layout_set_tiled(struct window *w)
586 {
587 	struct window_pane	*wp;
588 	struct layout_cell	*lc, *lcrow, *lcchild;
589 	u_int			 n, width, height, used, sx, sy;
590 	u_int			 i, j, columns, rows;
591 
592 	layout_print_cell(w->layout_root, __func__, 1);
593 
594 	/* Get number of panes. */
595 	n = window_count_panes(w);
596 	if (n <= 1)
597 		return;
598 
599 	/* How many rows and columns are wanted? */
600 	rows = columns = 1;
601 	while (rows * columns < n) {
602 		rows++;
603 		if (rows * columns < n)
604 			columns++;
605 	}
606 
607 	/* What width and height should they be? */
608 	width = (w->sx - (columns - 1)) / columns;
609 	if (width < PANE_MINIMUM)
610 		width = PANE_MINIMUM;
611 	height = (w->sy - (rows - 1)) / rows;
612 	if (height < PANE_MINIMUM)
613 		height = PANE_MINIMUM;
614 
615 	/* Free old tree and create a new root. */
616 	layout_free(w);
617 	lc = w->layout_root = layout_create_cell(NULL);
618 	sx = ((width + 1) * columns) - 1;
619 	if (sx < w->sx)
620 		sx = w->sx;
621 	sy = ((height + 1) * rows) - 1;
622 	if (sy < w->sy)
623 		sy = w->sy;
624 	layout_set_size(lc, sx, sy, 0, 0);
625 	layout_make_node(lc, LAYOUT_TOPBOTTOM);
626 
627 	/* Create a grid of the cells. */
628 	wp = TAILQ_FIRST(&w->panes);
629 	for (j = 0; j < rows; j++) {
630 		/* If this is the last cell, all done. */
631 		if (wp == NULL)
632 			break;
633 
634 		/* Create the new row. */
635 		lcrow = layout_create_cell(lc);
636 		layout_set_size(lcrow, w->sx, height, 0, 0);
637 		TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
638 
639 		/* If only one column, just use the row directly. */
640 		if (n - (j * columns) == 1 || columns == 1) {
641 			layout_make_leaf(lcrow, wp);
642 			wp = TAILQ_NEXT(wp, entry);
643 			continue;
644 		}
645 
646 		/* Add in the columns. */
647 		layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
648 		for (i = 0; i < columns; i++) {
649 			/* Create and add a pane cell. */
650 			lcchild = layout_create_cell(lcrow);
651 			layout_set_size(lcchild, width, height, 0, 0);
652 			layout_make_leaf(lcchild, wp);
653 			TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
654 
655 			/* Move to the next cell. */
656 			if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
657 				break;
658 		}
659 
660 		/*
661 		 * Adjust the row and columns to fit the full width if
662 		 * necessary.
663 		 */
664 		if (i == columns)
665 			i--;
666 		used = ((i + 1) * (width + 1)) - 1;
667 		if (w->sx <= used)
668 			continue;
669 		lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
670 		layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
671 		    w->sx - used);
672 	}
673 
674 	/* Adjust the last row height to fit if necessary. */
675 	used = (rows * height) + rows - 1;
676 	if (w->sy > used) {
677 		lcrow = TAILQ_LAST(&lc->cells, layout_cells);
678 		layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
679 		    w->sy - used);
680 	}
681 
682 	/* Fix cell offsets. */
683 	layout_fix_offsets(w);
684 	layout_fix_panes(w, NULL);
685 
686 	layout_print_cell(w->layout_root, __func__, 1);
687 
688 	window_resize(w, lc->sx, lc->sy, -1, -1);
689 	notify_window("window-layout-changed", w);
690 	server_redraw_window(w);
691 }
692