Coverage Report

Created: 2026-05-30 06:39

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