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