Coverage Report

Created: 2025-07-11 06:20

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