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