1 /* $OpenBSD$ */
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