Coverage Report

Created: 2026-07-16 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/layout-set.c
Line
Count
Source
1
/* $OpenBSD: layout-set.c,v 1.40 2026/07/13 09:42:12 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
21
#include <stdlib.h>
22
#include <string.h>
23
24
#include "tmux.h"
25
26
/*
27
 * Set window layouts - predefined methods to arrange windows. These are
28
 * one-off and generate a layout tree.
29
 */
30
31
static void layout_set_even_h(struct window *);
32
static void layout_set_even_v(struct window *);
33
static void layout_set_main_h(struct window *);
34
static void layout_set_main_h_mirrored(struct window *);
35
static void layout_set_main_v(struct window *);
36
static void layout_set_main_v_mirrored(struct window *);
37
static void layout_set_tiled(struct window *);
38
39
static const struct {
40
  const char  *name;
41
  void          (*arrange)(struct window *);
42
} layout_sets[] = {
43
  { "even-horizontal", layout_set_even_h },
44
  { "even-vertical", layout_set_even_v },
45
  { "main-horizontal", layout_set_main_h },
46
  { "main-horizontal-mirrored", layout_set_main_h_mirrored },
47
  { "main-vertical", layout_set_main_v },
48
  { "main-vertical-mirrored", layout_set_main_v_mirrored },
49
  { "tiled", layout_set_tiled },
50
};
51
52
int
53
layout_set_lookup(const char *name)
54
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_set_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->layout_cell && layout_cell_is_tiled(wp->layout_cell))
133
0
      return (wp);
134
0
  }
135
0
  return (NULL);
136
0
}
137
138
static void
139
layout_set_link_floating(struct window *w, struct layout_cell *lcroot)
140
0
{
141
0
  struct window_pane  *wp;
142
0
  struct layout_cell  *lc;
143
144
0
  TAILQ_FOREACH(wp, &w->panes, entry) {
145
0
    lc = wp->layout_cell;
146
0
    if (!layout_cell_is_tiled(lc)) {
147
0
      TAILQ_INSERT_TAIL(&lcroot->cells, lc, entry);
148
0
      lc->parent = lcroot;
149
0
    }
150
0
  }
151
0
}
152
153
static void
154
layout_set_even(struct window *w, enum layout_type type)
155
0
{
156
0
  struct window_pane  *wp;
157
0
  struct layout_cell  *lcroot, *lcchild;
158
0
  u_int      n, sx, sy;
159
160
0
  layout_print_cell(w->layout_root, __func__, 1);
161
162
0
  n = window_count_panes(w, 0);
163
0
  if (n <= 1)
164
0
    return;
165
166
0
  if (type == LAYOUT_LEFTRIGHT) {
167
0
    sx = (n * (PANE_MINIMUM + 1)) - 1;
168
0
    if (sx < w->sx)
169
0
      sx = w->sx;
170
0
    sy = w->sy;
171
0
  } else {
172
0
    sy = (n * (PANE_MINIMUM + 1)) - 1;
173
0
    if (sy < w->sy)
174
0
      sy = w->sy;
175
0
    sx = w->sx;
176
0
  }
177
178
0
  layout_free(w, 1);
179
0
  lcroot = w->layout_root = layout_create_cell(NULL);
180
0
  layout_set_size(lcroot, sx, sy, 0, 0);
181
0
  layout_make_node(lcroot, type);
182
183
0
  TAILQ_FOREACH(wp, &w->panes, entry) {
184
0
    lcchild = wp->layout_cell;
185
0
    TAILQ_INSERT_TAIL(&lcroot->cells, lcchild, entry);
186
0
    lcchild->parent = lcroot;
187
0
    if (layout_cell_is_tiled(lcchild)) {
188
0
      lcchild->g.sx = w->sx;
189
0
      lcchild->g.sy = w->sy;
190
0
    }
191
0
  }
192
193
0
  layout_spread_cell(w, lcroot);
194
195
0
  layout_fix_offsets(w);
196
0
  layout_fix_panes(w, NULL);
197
198
0
  layout_print_cell(w->layout_root, __func__, 1);
199
200
0
  window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
201
0
  events_fire_window("window-layout-changed", w);
202
0
  server_redraw_window(w);
203
0
}
204
205
static void
206
layout_set_even_h(struct window *w)
207
0
{
208
0
  layout_set_even(w, LAYOUT_LEFTRIGHT);
209
0
}
210
211
static void
212
layout_set_even_v(struct window *w)
213
0
{
214
0
  layout_set_even(w, LAYOUT_TOPBOTTOM);
215
0
}
216
217
static void
218
layout_set_main_h(struct window *w)
219
0
{
220
0
  struct window_pane  *wp, *wpmain;
221
0
  struct layout_cell  *lcroot, *lcmain, *lcother, *lcchild;
222
0
  u_int      n, mainh, otherh, sx, sy;
223
0
  char      *cause;
224
0
  const char    *s;
225
226
0
  layout_print_cell(w->layout_root, __func__, 1);
227
228
0
  n = window_count_panes(w, 0);
229
0
  if (n <= 1)
230
0
    return;
231
0
  n--;  /* take off main pane */
232
233
  /* Find available height - take off one line for the border. */
234
0
  sy = w->sy - 1;
235
236
  /* Get the main pane height. */
237
0
  s = options_get_string(w->options, "main-pane-height");
238
0
  mainh = args_string_percentage(s, 0, sy, sy, &cause);
239
0
  if (cause != NULL) {
240
0
    mainh = 24;
241
0
    free(cause);
242
0
  }
243
244
  /* Work out the other pane height. */
245
0
  if (mainh + PANE_MINIMUM >= sy) {
246
0
    if (sy <= PANE_MINIMUM + PANE_MINIMUM)
247
0
      mainh = PANE_MINIMUM;
248
0
    else
249
0
      mainh = sy - PANE_MINIMUM;
250
0
    otherh = PANE_MINIMUM;
251
0
  } else {
252
0
    s = options_get_string(w->options, "other-pane-height");
253
0
    otherh = args_string_percentage(s, 0, sy, sy, &cause);
254
0
    if (cause != NULL || otherh == 0) {
255
0
      otherh = sy - mainh;
256
0
      free(cause);
257
0
    } else if (otherh > sy || sy - otherh < mainh)
258
0
      otherh = sy - mainh;
259
0
    else
260
0
      mainh = sy - otherh;
261
0
  }
262
263
  /* Work out what width is needed. */
264
0
  sx = (n * (PANE_MINIMUM + 1)) - 1;
265
0
  if (sx < w->sx)
266
0
    sx = w->sx;
267
268
0
  layout_free(w, 1);
269
0
  lcroot = w->layout_root = layout_create_cell(NULL);
270
0
  layout_set_size(lcroot, sx, mainh + otherh + 1, 0, 0);
271
0
  layout_make_node(lcroot, LAYOUT_TOPBOTTOM);
272
273
0
  wpmain = layout_set_first_tiled(w);
274
0
  lcmain = wpmain->layout_cell;
275
0
  lcmain->parent = lcroot;
276
0
  layout_set_size(lcmain, sx, mainh, 0, 0);
277
0
  TAILQ_INSERT_TAIL(&lcroot->cells, lcmain, entry);
278
279
0
  if (n == 1) {
280
0
    wp = TAILQ_NEXT(wpmain, entry);
281
0
    while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell))
282
0
      wp = TAILQ_NEXT(wp, entry);
283
0
    TAILQ_INSERT_TAIL(&lcroot->cells, wp->layout_cell, entry);
284
0
    wp->layout_cell->parent = lcroot;
285
0
    layout_set_size(wp->layout_cell, sx, otherh, 0, 0);
286
0
    layout_set_link_floating(w, lcroot);
287
0
  } else {
288
0
    lcother = layout_create_cell(lcroot);
289
0
    layout_set_size(lcother, sx, otherh, 0, 0);
290
0
    layout_make_node(lcother, LAYOUT_LEFTRIGHT);
291
0
    TAILQ_INSERT_TAIL(&lcroot->cells, lcother, entry);
292
293
0
    TAILQ_FOREACH(wp, &w->panes, entry) {
294
0
      if (wp == wpmain)
295
0
        continue;
296
0
      lcchild = wp->layout_cell;
297
0
      TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
298
0
      lcchild->parent = lcother;
299
0
      if (layout_cell_is_tiled(lcchild))
300
0
        layout_set_size(lcchild, PANE_MINIMUM, otherh,
301
0
            0, 0);
302
0
    }
303
0
    layout_spread_cell(w, lcother);
304
0
  }
305
306
0
  layout_fix_offsets(w);
307
0
  layout_fix_panes(w, NULL);
308
309
0
  layout_print_cell(w->layout_root, __func__, 1);
310
311
0
  window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
312
0
  events_fire_window("window-layout-changed", w);
313
0
  server_redraw_window(w);
314
0
}
315
316
static void
317
layout_set_main_h_mirrored(struct window *w)
318
0
{
319
0
  struct window_pane  *wp, *wpmain;
320
0
  struct layout_cell  *lcroot, *lcmain, *lcother, *lcchild;
321
0
  u_int      n, mainh, otherh, sx, sy;
322
0
  char      *cause;
323
0
  const char    *s;
324
325
0
  layout_print_cell(w->layout_root, __func__, 1);
326
327
0
  n = window_count_panes(w, 0);
328
0
  if (n <= 1)
329
0
    return;
330
0
  n--;  /* take off main pane */
331
332
  /* Find available height - take off one line for the border. */
333
0
  sy = w->sy - 1;
334
335
  /* Get the main pane height. */
336
0
  s = options_get_string(w->options, "main-pane-height");
337
0
  mainh = args_string_percentage(s, 0, sy, sy, &cause);
338
0
  if (cause != NULL) {
339
0
    mainh = 24;
340
0
    free(cause);
341
0
  }
342
343
  /* Work out the other pane height. */
344
0
  if (mainh + PANE_MINIMUM >= sy) {
345
0
    if (sy <= PANE_MINIMUM + PANE_MINIMUM)
346
0
      mainh = PANE_MINIMUM;
347
0
    else
348
0
      mainh = sy - PANE_MINIMUM;
349
0
    otherh = PANE_MINIMUM;
350
0
  } else {
351
0
    s = options_get_string(w->options, "other-pane-height");
352
0
    otherh = args_string_percentage(s, 0, sy, sy, &cause);
353
0
    if (cause != NULL || otherh == 0) {
354
0
      otherh = sy - mainh;
355
0
      free(cause);
356
0
    } else if (otherh > sy || sy - otherh < mainh)
357
0
      otherh = sy - mainh;
358
0
    else
359
0
      mainh = sy - otherh;
360
0
  }
361
362
  /* Work out what width is needed. */
363
0
  sx = (n * (PANE_MINIMUM + 1)) - 1;
364
0
  if (sx < w->sx)
365
0
    sx = w->sx;
366
367
0
  layout_free(w, 1);
368
0
  lcroot = w->layout_root = layout_create_cell(NULL);
369
0
  layout_set_size(lcroot, sx, mainh + otherh + 1, 0, 0);
370
0
  layout_make_node(lcroot, LAYOUT_TOPBOTTOM);
371
372
0
  wpmain = layout_set_first_tiled(w);
373
0
  lcmain = wpmain->layout_cell;
374
0
  lcmain->parent = lcroot;
375
0
  layout_set_size(lcmain, sx, mainh, 0, 0);
376
0
  TAILQ_INSERT_TAIL(&lcroot->cells, lcmain, entry);
377
378
0
  if (n == 1) {
379
0
    wp = TAILQ_NEXT(wpmain, entry);
380
0
    while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell))
381
0
      wp = TAILQ_NEXT(wp, entry);
382
0
    TAILQ_INSERT_HEAD(&lcroot->cells, wp->layout_cell, entry);
383
0
    wp->layout_cell->parent = lcroot;
384
0
    layout_set_size(wp->layout_cell, sx, otherh, 0, 0);
385
0
    layout_set_link_floating(w, lcroot);
386
0
  } else {
387
0
    lcother = layout_create_cell(lcroot);
388
0
    layout_set_size(lcother, sx, otherh, 0, 0);
389
0
    layout_make_node(lcother, LAYOUT_LEFTRIGHT);
390
0
    TAILQ_INSERT_HEAD(&lcroot->cells, lcother, entry);
391
392
0
    TAILQ_FOREACH(wp, &w->panes, entry) {
393
0
      if (wp == wpmain)
394
0
        continue;
395
0
      lcchild = wp->layout_cell;
396
0
      TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
397
0
      lcchild->parent = lcother;
398
0
      if (layout_cell_is_tiled(lcchild))
399
0
        layout_set_size(lcchild, PANE_MINIMUM, otherh,
400
0
            0, 0);
401
0
    }
402
0
    layout_spread_cell(w, lcother);
403
0
  }
404
405
0
  layout_fix_offsets(w);
406
0
  layout_fix_panes(w, NULL);
407
408
0
  layout_print_cell(w->layout_root, __func__, 1);
409
410
0
  window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
411
0
  events_fire_window("window-layout-changed", w);
412
0
  server_redraw_window(w);
413
0
}
414
415
static void
416
layout_set_main_v(struct window *w)
417
0
{
418
0
  struct window_pane  *wp, *wpmain;
419
0
  struct layout_cell  *lcroot, *lcmain, *lcother, *lcchild;
420
0
  u_int      n, mainw, otherw, sx, sy;
421
0
  char      *cause;
422
0
  const char    *s;
423
424
0
  layout_print_cell(w->layout_root, __func__, 1);
425
426
0
  n = window_count_panes(w, 0);
427
0
  if (n <= 1)
428
0
    return;
429
0
  n--;  /* take off main pane */
430
431
  /* Find available width - take off one column for the border. */
432
0
  sx = w->sx - 1;
433
434
  /* Get the main pane width. */
435
0
  s = options_get_string(w->options, "main-pane-width");
436
0
  mainw = args_string_percentage(s, 0, sx, sx, &cause);
437
0
  if (cause != NULL) {
438
0
    mainw = 80;
439
0
    free(cause);
440
0
  }
441
442
  /* Work out the other pane width. */
443
0
  if (mainw + PANE_MINIMUM >= sx) {
444
0
    if (sx <= PANE_MINIMUM + PANE_MINIMUM)
445
0
      mainw = PANE_MINIMUM;
446
0
    else
447
0
      mainw = sx - PANE_MINIMUM;
448
0
    otherw = PANE_MINIMUM;
449
0
  } else {
450
0
    s = options_get_string(w->options, "other-pane-width");
451
0
    otherw = args_string_percentage(s, 0, sx, sx, &cause);
452
0
    if (cause != NULL || otherw == 0) {
453
0
      otherw = sx - mainw;
454
0
      free(cause);
455
0
    } else if (otherw > sx || sx - otherw < mainw)
456
0
      otherw = sx - mainw;
457
0
    else
458
0
      mainw = sx - otherw;
459
0
  }
460
461
  /* Work out what height is needed. */
462
0
  sy = (n * (PANE_MINIMUM + 1)) - 1;
463
0
  if (sy < w->sy)
464
0
    sy = w->sy;
465
466
0
  layout_free(w, 1);
467
0
  lcroot = w->layout_root = layout_create_cell(NULL);
468
0
  layout_set_size(lcroot, mainw + otherw + 1, sy, 0, 0);
469
0
  layout_make_node(lcroot, LAYOUT_LEFTRIGHT);
470
471
0
  wpmain = layout_set_first_tiled(w);
472
0
  lcmain = wpmain->layout_cell;
473
0
  lcmain->parent = lcroot;
474
0
  layout_set_size(lcmain, mainw, sy, 0, 0);
475
0
  TAILQ_INSERT_TAIL(&lcroot->cells, lcmain, entry);
476
477
0
  if (n == 1) {
478
0
    wp = TAILQ_NEXT(wpmain, entry);
479
0
    while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell))
480
0
      wp = TAILQ_NEXT(wp, entry);
481
0
    TAILQ_INSERT_TAIL(&lcroot->cells, wp->layout_cell, entry);
482
0
    wp->layout_cell->parent = lcroot;
483
0
    layout_set_size(wp->layout_cell, otherw, sy, 0, 0);
484
0
    layout_set_link_floating(w, lcroot);
485
0
  } else {
486
0
    lcother = layout_create_cell(lcroot);
487
0
    layout_make_node(lcother, LAYOUT_TOPBOTTOM);
488
0
    layout_set_size(lcother, otherw, sy, 0, 0);
489
0
    TAILQ_INSERT_TAIL(&lcroot->cells, lcother, entry);
490
491
0
    TAILQ_FOREACH(wp, &w->panes, entry) {
492
0
      if (wp == wpmain)
493
0
        continue;
494
0
      lcchild = wp->layout_cell;
495
0
      TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
496
0
      lcchild->parent = lcother;
497
0
      if (layout_cell_is_tiled(lcchild))
498
0
        layout_set_size(lcchild, otherw, PANE_MINIMUM,
499
0
            0, 0);
500
0
    }
501
0
    layout_spread_cell(w, lcother);
502
0
  }
503
504
0
  layout_fix_offsets(w);
505
0
  layout_fix_panes(w, NULL);
506
507
0
  layout_print_cell(w->layout_root, __func__, 1);
508
509
0
  window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
510
0
  events_fire_window("window-layout-changed", w);
511
0
  server_redraw_window(w);
512
0
}
513
514
static void
515
layout_set_main_v_mirrored(struct window *w)
516
0
{
517
0
  struct window_pane  *wp, *wpmain;
518
0
  struct layout_cell  *lcroot, *lcmain, *lcother, *lcchild;
519
0
  u_int      n, mainw, otherw, sx, sy;
520
0
  char      *cause;
521
0
  const char    *s;
522
523
0
  layout_print_cell(w->layout_root, __func__, 1);
524
525
  /* Get number of panes. */
526
0
  n = window_count_panes(w, 0);
527
0
  if (n <= 1)
528
0
    return;
529
0
  n--;  /* take off main pane */
530
531
  /* Find available width - take off one column for the border. */
532
0
  sx = w->sx - 1;
533
534
  /* Get the main pane width. */
535
0
  s = options_get_string(w->options, "main-pane-width");
536
0
  mainw = args_string_percentage(s, 0, sx, sx, &cause);
537
0
  if (cause != NULL) {
538
0
    mainw = 80;
539
0
    free(cause);
540
0
  }
541
542
  /* Work out the other pane width. */
543
0
  if (mainw + PANE_MINIMUM >= sx) {
544
0
    if (sx <= PANE_MINIMUM + PANE_MINIMUM)
545
0
      mainw = PANE_MINIMUM;
546
0
    else
547
0
      mainw = sx - PANE_MINIMUM;
548
0
    otherw = PANE_MINIMUM;
549
0
  } else {
550
0
    s = options_get_string(w->options, "other-pane-width");
551
0
    otherw = args_string_percentage(s, 0, sx, sx, &cause);
552
0
    if (cause != NULL || otherw == 0) {
553
0
      otherw = sx - mainw;
554
0
      free(cause);
555
0
    } else if (otherw > sx || sx - otherw < mainw)
556
0
      otherw = sx - mainw;
557
0
    else
558
0
      mainw = sx - otherw;
559
0
  }
560
561
  /* Work out what height is needed. */
562
0
  sy = (n * (PANE_MINIMUM + 1)) - 1;
563
0
  if (sy < w->sy)
564
0
    sy = w->sy;
565
566
0
  layout_free(w, 1);
567
0
  lcroot = w->layout_root = layout_create_cell(NULL);
568
0
  layout_set_size(lcroot, mainw + otherw + 1, sy, 0, 0);
569
0
  layout_make_node(lcroot, LAYOUT_LEFTRIGHT);
570
571
0
  wpmain = layout_set_first_tiled(w);
572
0
  lcmain = wpmain->layout_cell;
573
0
  lcmain->parent = lcroot;
574
0
  layout_set_size(lcmain, mainw, sy, 0, 0);
575
0
  TAILQ_INSERT_TAIL(&lcroot->cells, lcmain, entry);
576
577
0
  if (n == 1) {
578
0
    wp = TAILQ_NEXT(wpmain, entry);
579
0
    while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell))
580
0
      wp = TAILQ_NEXT(wp, entry);
581
0
    TAILQ_INSERT_HEAD(&lcroot->cells, wp->layout_cell, entry);
582
0
    wp->layout_cell->parent = lcroot;
583
0
    layout_set_size(wp->layout_cell, otherw, sy, 0, 0);
584
0
    layout_set_link_floating(w, lcroot);
585
0
  } else {
586
0
    lcother = layout_create_cell(lcroot);
587
0
    layout_make_node(lcother, LAYOUT_TOPBOTTOM);
588
0
    layout_set_size(lcother, otherw, sy, 0, 0);
589
0
    TAILQ_INSERT_HEAD(&lcroot->cells, lcother, entry);
590
591
0
    TAILQ_FOREACH(wp, &w->panes, entry) {
592
0
      if (wp == wpmain)
593
0
        continue;
594
0
      lcchild = wp->layout_cell;
595
0
      TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
596
0
      lcchild->parent = lcother;
597
0
      if (layout_cell_is_tiled(lcchild))
598
0
        layout_set_size(lcchild, otherw, PANE_MINIMUM,
599
0
            0, 0);
600
0
    }
601
0
    layout_spread_cell(w, lcother);
602
0
  }
603
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, lcroot->g.sx, lcroot->g.sy, -1, -1);
610
0
  events_fire_window("window-layout-changed", w);
611
0
  server_redraw_window(w);
612
0
}
613
614
static 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  *lcroot, *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
0
  sx = ((width + 1) * columns) - 1;
651
0
  if (sx < w->sx)
652
0
    sx = w->sx;
653
0
  sy = ((height + 1) * rows) - 1;
654
0
  if (sy < w->sy)
655
0
    sy = w->sy;
656
657
0
  layout_free(w, 1);
658
0
  lcroot = w->layout_root = layout_create_cell(NULL);
659
0
  layout_set_size(lcroot, sx, sy, 0, 0);
660
0
  layout_make_node(lcroot, LAYOUT_TOPBOTTOM);
661
662
  /* Create a grid of the tiled cells. */
663
0
  wp = TAILQ_FIRST(&w->panes);
664
0
  for (j = 0; j < rows; j++) {
665
0
    while (wp != NULL && !layout_cell_is_tiled(wp->layout_cell))
666
0
      wp = TAILQ_NEXT(wp, entry);
667
    /* If this is the last cell, all done. */
668
0
    if (wp == NULL)
669
0
      break;
670
671
0
    lcchild = wp->layout_cell;
672
673
    /* If only one column, just use the row directly. */
674
0
    if (n - (j * columns) == 1 || columns == 1) {
675
0
      lcchild->parent = lcroot;
676
0
      TAILQ_INSERT_TAIL(&lcroot->cells, lcchild, entry);
677
0
      layout_set_size(lcchild, w->sx, height, 0, 0);
678
0
      wp = TAILQ_NEXT(wp, entry);
679
0
      continue;
680
0
    }
681
682
    /* Create the new row. */
683
0
    lcrow = layout_create_cell(lcroot);
684
0
    layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
685
0
    layout_set_size(lcrow, w->sx, height, 0, 0);
686
0
    TAILQ_INSERT_TAIL(&lcroot->cells, lcrow, entry);
687
688
    /* Add in the columns. */
689
0
    for (i = 0; i < columns; i++) {
690
      /* Create and add a pane cell. */
691
0
      lcchild->parent = lcrow;
692
0
      TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
693
0
      layout_set_size(lcchild, width, height, 0, 0);
694
695
      /* Move to the next non-floating cell. */
696
0
      wp = TAILQ_NEXT(wp, entry);
697
0
      while (wp != NULL &&
698
0
          !layout_cell_is_tiled(wp->layout_cell))
699
0
        wp = TAILQ_NEXT(wp, entry);
700
0
      if (wp == NULL)
701
0
        break;
702
0
      lcchild = wp->layout_cell;
703
0
    }
704
705
    /*
706
     * Adjust the row and columns to fit the full width if
707
     * necessary.
708
     */
709
0
    if (i == columns)
710
0
      i--;
711
0
    used = ((i + 1) * (width + 1)) - 1;
712
0
    if (w->sx <= used)
713
0
      continue;
714
0
    lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
715
0
    layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
716
0
        w->sx - used);
717
0
  }
718
719
0
  used = (rows * height) + rows - 1;
720
0
  if (w->sy > used) {
721
0
    lcrow = TAILQ_LAST(&lcroot->cells, layout_cells);
722
0
    layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
723
0
        w->sy - used);
724
0
  }
725
726
0
  layout_set_link_floating(w, lcroot);
727
0
  layout_fix_offsets(w);
728
0
  layout_fix_panes(w, NULL);
729
730
0
  layout_print_cell(w->layout_root, __func__, 1);
731
732
0
  window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
733
0
  events_fire_window("window-layout-changed", w);
734
0
  server_redraw_window(w);
735
0
}