Bug Summary

File:src/usr.bin/tmux/layout.c
Warning:line 743, column 30
Division by zero

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name layout.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/tmux/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/tmux -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/tmux/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/tmux/layout.c
1/* $OpenBSD: layout.c,v 1.48 2021/03/11 06:31:05 nicm Exp $ */
2
3/*
4 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5 * Copyright (c) 2016 Stephen Kent <smkent@smkent.net>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/types.h>
21
22#include <stdlib.h>
23
24#include "tmux.h"
25
26/*
27 * The window layout is a tree of cells each of which can be one of: a
28 * left-right container for a list of cells, a top-bottom container for a list
29 * of cells, or a container for a window pane.
30 *
31 * Each window has a pointer to the root of its layout tree (containing its
32 * panes), every pane has a pointer back to the cell containing it, and each
33 * cell a pointer to its parent cell.
34 */
35
36static u_int layout_resize_check(struct window *, struct layout_cell *,
37 enum layout_type);
38static int layout_resize_pane_grow(struct window *, struct layout_cell *,
39 enum layout_type, int, int);
40static int layout_resize_pane_shrink(struct window *, struct layout_cell *,
41 enum layout_type, int);
42static u_int layout_new_pane_size(struct window *, u_int,
43 struct layout_cell *, enum layout_type, u_int, u_int,
44 u_int);
45static int layout_set_size_check(struct window *, struct layout_cell *,
46 enum layout_type, int);
47static void layout_resize_child_cells(struct window *,
48 struct layout_cell *);
49
50struct layout_cell *
51layout_create_cell(struct layout_cell *lcparent)
52{
53 struct layout_cell *lc;
54
55 lc = xmalloc(sizeof *lc);
56 lc->type = LAYOUT_WINDOWPANE;
57 lc->parent = lcparent;
58
59 TAILQ_INIT(&lc->cells)do { (&lc->cells)->tqh_first = ((void *)0); (&lc
->cells)->tqh_last = &(&lc->cells)->tqh_first
; } while (0)
;
60
61 lc->sx = UINT_MAX(2147483647 *2U +1U);
62 lc->sy = UINT_MAX(2147483647 *2U +1U);
63
64 lc->xoff = UINT_MAX(2147483647 *2U +1U);
65 lc->yoff = UINT_MAX(2147483647 *2U +1U);
66
67 lc->wp = NULL((void *)0);
68
69 return (lc);
70}
71
72void
73layout_free_cell(struct layout_cell *lc)
74{
75 struct layout_cell *lcchild;
76
77 switch (lc->type) {
78 case LAYOUT_LEFTRIGHT:
79 case LAYOUT_TOPBOTTOM:
80 while (!TAILQ_EMPTY(&lc->cells)(((&lc->cells)->tqh_first) == ((void *)0))) {
81 lcchild = TAILQ_FIRST(&lc->cells)((&lc->cells)->tqh_first);
82 TAILQ_REMOVE(&lc->cells, lcchild, entry)do { if (((lcchild)->entry.tqe_next) != ((void *)0)) (lcchild
)->entry.tqe_next->entry.tqe_prev = (lcchild)->entry
.tqe_prev; else (&lc->cells)->tqh_last = (lcchild)->
entry.tqe_prev; *(lcchild)->entry.tqe_prev = (lcchild)->
entry.tqe_next; ; ; } while (0)
;
83 layout_free_cell(lcchild);
84 }
85 break;
86 case LAYOUT_WINDOWPANE:
87 if (lc->wp != NULL((void *)0))
88 lc->wp->layout_cell = NULL((void *)0);
89 break;
90 }
91
92 free(lc);
93}
94
95void
96layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
97{
98 struct layout_cell *lcchild;
99 const char *type;
100
101 switch (lc->type) {
102 case LAYOUT_LEFTRIGHT:
103 type = "LEFTRIGHT";
104 break;
105 case LAYOUT_TOPBOTTOM:
106 type = "TOPBOTTOM";
107 break;
108 case LAYOUT_WINDOWPANE:
109 type = "WINDOWPANE";
110 break;
111 default:
112 type = "UNKNOWN";
113 break;
114 }
115 log_debug("%s:%*s%p type %s [parent %p] wp=%p [%u,%u %ux%u]", hdr, n,
116 " ", lc, type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx,
117 lc->sy);
118 switch (lc->type) {
119 case LAYOUT_LEFTRIGHT:
120 case LAYOUT_TOPBOTTOM:
121 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
122 layout_print_cell(lcchild, hdr, n + 1);
123 break;
124 case LAYOUT_WINDOWPANE:
125 break;
126 }
127}
128
129struct layout_cell *
130layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
131{
132 struct layout_cell *lcchild, *last = NULL((void *)0);
133
134 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
{
135 if (x >= lcchild->xoff && x < lcchild->xoff + lcchild->sx &&
136 y >= lcchild->yoff && y < lcchild->yoff + lcchild->sy) {
137 /* Inside the cell - recurse. */
138 return (layout_search_by_border(lcchild, x, y));
139 }
140
141 if (last == NULL((void *)0)) {
142 last = lcchild;
143 continue;
144 }
145
146 switch (lc->type) {
147 case LAYOUT_LEFTRIGHT:
148 if (x < lcchild->xoff && x >= last->xoff + last->sx)
149 return (last);
150 break;
151 case LAYOUT_TOPBOTTOM:
152 if (y < lcchild->yoff && y >= last->yoff + last->sy)
153 return (last);
154 break;
155 case LAYOUT_WINDOWPANE:
156 break;
157 }
158
159 last = lcchild;
160 }
161
162 return (NULL((void *)0));
163}
164
165void
166layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, u_int xoff,
167 u_int yoff)
168{
169 lc->sx = sx;
170 lc->sy = sy;
171
172 lc->xoff = xoff;
173 lc->yoff = yoff;
174}
175
176void
177layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
178{
179 lc->type = LAYOUT_WINDOWPANE;
180
181 TAILQ_INIT(&lc->cells)do { (&lc->cells)->tqh_first = ((void *)0); (&lc
->cells)->tqh_last = &(&lc->cells)->tqh_first
; } while (0)
;
182
183 wp->layout_cell = lc;
184 lc->wp = wp;
185}
186
187void
188layout_make_node(struct layout_cell *lc, enum layout_type type)
189{
190 if (type == LAYOUT_WINDOWPANE)
191 fatalx("bad layout type");
192 lc->type = type;
193
194 TAILQ_INIT(&lc->cells)do { (&lc->cells)->tqh_first = ((void *)0); (&lc
->cells)->tqh_last = &(&lc->cells)->tqh_first
; } while (0)
;
195
196 if (lc->wp != NULL((void *)0))
197 lc->wp->layout_cell = NULL((void *)0);
198 lc->wp = NULL((void *)0);
199}
200
201/* Fix cell offsets for a child cell. */
202static void
203layout_fix_offsets1(struct layout_cell *lc)
204{
205 struct layout_cell *lcchild;
206 u_int xoff, yoff;
207
208 if (lc->type == LAYOUT_LEFTRIGHT) {
209 xoff = lc->xoff;
210 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
{
211 lcchild->xoff = xoff;
212 lcchild->yoff = lc->yoff;
213 if (lcchild->type != LAYOUT_WINDOWPANE)
214 layout_fix_offsets1(lcchild);
215 xoff += lcchild->sx + 1;
216 }
217 } else {
218 yoff = lc->yoff;
219 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
{
220 lcchild->xoff = lc->xoff;
221 lcchild->yoff = yoff;
222 if (lcchild->type != LAYOUT_WINDOWPANE)
223 layout_fix_offsets1(lcchild);
224 yoff += lcchild->sy + 1;
225 }
226 }
227}
228
229/* Update cell offsets based on their sizes. */
230void
231layout_fix_offsets(struct window *w)
232{
233 struct layout_cell *lc = w->layout_root;
234
235 lc->xoff = 0;
236 lc->yoff = 0;
237
238 layout_fix_offsets1(lc);
239}
240
241/* Is this a top cell? */
242static int
243layout_cell_is_top(struct window *w, struct layout_cell *lc)
244{
245 struct layout_cell *next;
246
247 while (lc != w->layout_root) {
248 next = lc->parent;
249 if (next->type == LAYOUT_TOPBOTTOM &&
250 lc != TAILQ_FIRST(&next->cells)((&next->cells)->tqh_first))
251 return (0);
252 lc = next;
253 }
254 return (1);
255}
256
257/* Is this a bottom cell? */
258static int
259layout_cell_is_bottom(struct window *w, struct layout_cell *lc)
260{
261 struct layout_cell *next;
262
263 while (lc != w->layout_root) {
264 next = lc->parent;
265 if (next->type == LAYOUT_TOPBOTTOM &&
266 lc != TAILQ_LAST(&next->cells, layout_cells)(*(((struct layout_cells *)((&next->cells)->tqh_last
))->tqh_last))
)
267 return (0);
268 lc = next;
269 }
270 return (1);
271}
272
273/*
274 * Returns 1 if we need to add an extra line for the pane status line. This is
275 * the case for the most upper or lower panes only.
276 */
277static int
278layout_add_border(struct window *w, struct layout_cell *lc, int status)
279{
280 if (status == PANE_STATUS_TOP1)
281 return (layout_cell_is_top(w, lc));
282 if (status == PANE_STATUS_BOTTOM2)
283 return (layout_cell_is_bottom(w, lc));
284 return (0);
285}
286
287/* Update pane offsets and sizes based on their cells. */
288void
289layout_fix_panes(struct window *w, struct window_pane *skip)
290{
291 struct window_pane *wp;
292 struct layout_cell *lc;
293 int status;
294
295 status = options_get_number(w->options, "pane-border-status");
296 TAILQ_FOREACH(wp, &w->panes, entry)for((wp) = ((&w->panes)->tqh_first); (wp) != ((void
*)0); (wp) = ((wp)->entry.tqe_next))
{
297 if ((lc = wp->layout_cell) == NULL((void *)0) || wp == skip)
298 continue;
299
300 wp->xoff = lc->xoff;
301 wp->yoff = lc->yoff;
302
303 if (layout_add_border(w, lc, status)) {
304 if (status == PANE_STATUS_TOP1)
305 wp->yoff++;
306 window_pane_resize(wp, lc->sx, lc->sy - 1);
307 } else
308 window_pane_resize(wp, lc->sx, lc->sy);
309 }
310}
311
312/* Count the number of available cells in a layout. */
313u_int
314layout_count_cells(struct layout_cell *lc)
315{
316 struct layout_cell *lcchild;
317 u_int count;
318
319 switch (lc->type) {
320 case LAYOUT_WINDOWPANE:
321 return (1);
322 case LAYOUT_LEFTRIGHT:
323 case LAYOUT_TOPBOTTOM:
324 count = 0;
325 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
326 count += layout_count_cells(lcchild);
327 return (count);
328 default:
329 fatalx("bad layout type");
330 }
331}
332
333/* Calculate how much size is available to be removed from a cell. */
334static u_int
335layout_resize_check(struct window *w, struct layout_cell *lc,
336 enum layout_type type)
337{
338 struct layout_cell *lcchild;
339 u_int available, minimum;
340 int status;
341
342 status = options_get_number(w->options, "pane-border-status");
343 if (lc->type == LAYOUT_WINDOWPANE) {
344 /* Space available in this cell only. */
345 if (type == LAYOUT_LEFTRIGHT) {
346 available = lc->sx;
347 minimum = PANE_MINIMUM1;
348 } else {
349 available = lc->sy;
350 if (layout_add_border(w, lc, status))
351 minimum = PANE_MINIMUM1 + 1;
352 else
353 minimum = PANE_MINIMUM1;
354 }
355 if (available > minimum)
356 available -= minimum;
357 else
358 available = 0;
359 } else if (lc->type == type) {
360 /* Same type: total of available space in all child cells. */
361 available = 0;
362 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
363 available += layout_resize_check(w, lcchild, type);
364 } else {
365 /* Different type: minimum of available space in child cells. */
366 minimum = UINT_MAX(2147483647 *2U +1U);
367 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
{
368 available = layout_resize_check(w, lcchild, type);
369 if (available < minimum)
370 minimum = available;
371 }
372 available = minimum;
373 }
374
375 return (available);
376}
377
378/*
379 * Adjust cell size evenly, including altering its children. This function
380 * expects the change to have already been bounded to the space available.
381 */
382void
383layout_resize_adjust(struct window *w, struct layout_cell *lc,
384 enum layout_type type, int change)
385{
386 struct layout_cell *lcchild;
387
388 /* Adjust the cell size. */
389 if (type == LAYOUT_LEFTRIGHT)
390 lc->sx += change;
391 else
392 lc->sy += change;
393
394 /* If this is a leaf cell, that is all that is necessary. */
395 if (type == LAYOUT_WINDOWPANE)
396 return;
397
398 /* Child cell runs in a different direction. */
399 if (lc->type != type) {
400 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
401 layout_resize_adjust(w, lcchild, type, change);
402 return;
403 }
404
405 /*
406 * Child cell runs in the same direction. Adjust each child equally
407 * until no further change is possible.
408 */
409 while (change != 0) {
410 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
{
411 if (change == 0)
412 break;
413 if (change > 0) {
414 layout_resize_adjust(w, lcchild, type, 1);
415 change--;
416 continue;
417 }
418 if (layout_resize_check(w, lcchild, type) > 0) {
419 layout_resize_adjust(w, lcchild, type, -1);
420 change++;
421 }
422 }
423 }
424}
425
426/* Destroy a cell and redistribute the space. */
427void
428layout_destroy_cell(struct window *w, struct layout_cell *lc,
429 struct layout_cell **lcroot)
430{
431 struct layout_cell *lcother, *lcparent;
432
433 /*
434 * If no parent, this is the last pane so window close is imminent and
435 * there is no need to resize anything.
436 */
437 lcparent = lc->parent;
438 if (lcparent == NULL((void *)0)) {
439 layout_free_cell(lc);
440 *lcroot = NULL((void *)0);
441 return;
442 }
443
444 /* Merge the space into the previous or next cell. */
445 if (lc == TAILQ_FIRST(&lcparent->cells)((&lcparent->cells)->tqh_first))
446 lcother = TAILQ_NEXT(lc, entry)((lc)->entry.tqe_next);
447 else
448 lcother = TAILQ_PREV(lc, layout_cells, entry)(*(((struct layout_cells *)((lc)->entry.tqe_prev))->tqh_last
))
;
449 if (lcother != NULL((void *)0) && lcparent->type == LAYOUT_LEFTRIGHT)
450 layout_resize_adjust(w, lcother, lcparent->type, lc->sx + 1);
451 else if (lcother != NULL((void *)0))
452 layout_resize_adjust(w, lcother, lcparent->type, lc->sy + 1);
453
454 /* Remove this from the parent's list. */
455 TAILQ_REMOVE(&lcparent->cells, lc, entry)do { if (((lc)->entry.tqe_next) != ((void *)0)) (lc)->entry
.tqe_next->entry.tqe_prev = (lc)->entry.tqe_prev; else (
&lcparent->cells)->tqh_last = (lc)->entry.tqe_prev
; *(lc)->entry.tqe_prev = (lc)->entry.tqe_next; ; ; } while
(0)
;
456 layout_free_cell(lc);
457
458 /*
459 * If the parent now has one cell, remove the parent from the tree and
460 * replace it by that cell.
461 */
462 lc = TAILQ_FIRST(&lcparent->cells)((&lcparent->cells)->tqh_first);
463 if (TAILQ_NEXT(lc, entry)((lc)->entry.tqe_next) == NULL((void *)0)) {
464 TAILQ_REMOVE(&lcparent->cells, lc, entry)do { if (((lc)->entry.tqe_next) != ((void *)0)) (lc)->entry
.tqe_next->entry.tqe_prev = (lc)->entry.tqe_prev; else (
&lcparent->cells)->tqh_last = (lc)->entry.tqe_prev
; *(lc)->entry.tqe_prev = (lc)->entry.tqe_next; ; ; } while
(0)
;
465
466 lc->parent = lcparent->parent;
467 if (lc->parent == NULL((void *)0)) {
468 lc->xoff = 0; lc->yoff = 0;
469 *lcroot = lc;
470 } else
471 TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry)do { if (((lc)->entry.tqe_next = (lcparent)->entry.tqe_next
) != ((void *)0)) (lc)->entry.tqe_next->entry.tqe_prev =
&(lc)->entry.tqe_next; else (&lc->parent->cells
)->tqh_last = &(lc)->entry.tqe_next; (lc)->entry
.tqe_prev = (lcparent)->entry.tqe_prev; *(lc)->entry.tqe_prev
= (lc); ; ; } while (0)
;
472
473 layout_free_cell(lcparent);
474 }
475}
476
477void
478layout_init(struct window *w, struct window_pane *wp)
479{
480 struct layout_cell *lc;
481
482 lc = w->layout_root = layout_create_cell(NULL((void *)0));
483 layout_set_size(lc, w->sx, w->sy, 0, 0);
484 layout_make_leaf(lc, wp);
485 layout_fix_panes(w, NULL((void *)0));
486}
487
488void
489layout_free(struct window *w)
490{
491 layout_free_cell(w->layout_root);
492}
493
494/* Resize the entire layout after window resize. */
495void
496layout_resize(struct window *w, u_int sx, u_int sy)
497{
498 struct layout_cell *lc = w->layout_root;
499 int xlimit, ylimit, xchange, ychange;
500
501 /*
502 * Adjust horizontally. Do not attempt to reduce the layout lower than
503 * the minimum (more than the amount returned by layout_resize_check).
504 *
505 * This can mean that the window size is smaller than the total layout
506 * size: redrawing this is handled at a higher level, but it does leave
507 * a problem with growing the window size here: if the current size is
508 * < the minimum, growing proportionately by adding to each pane is
509 * wrong as it would keep the layout size larger than the window size.
510 * Instead, spread the difference between the minimum and the new size
511 * out proportionately - this should leave the layout fitting the new
512 * window size.
513 */
514 xchange = sx - lc->sx;
515 xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT);
516 if (xchange < 0 && xchange < -xlimit)
517 xchange = -xlimit;
518 if (xlimit == 0) {
519 if (sx <= lc->sx) /* lc->sx is minimum possible */
520 xchange = 0;
521 else
522 xchange = sx - lc->sx;
523 }
524 if (xchange != 0)
525 layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, xchange);
526
527 /* Adjust vertically in a similar fashion. */
528 ychange = sy - lc->sy;
529 ylimit = layout_resize_check(w, lc, LAYOUT_TOPBOTTOM);
530 if (ychange < 0 && ychange < -ylimit)
531 ychange = -ylimit;
532 if (ylimit == 0) {
533 if (sy <= lc->sy) /* lc->sy is minimum possible */
534 ychange = 0;
535 else
536 ychange = sy - lc->sy;
537 }
538 if (ychange != 0)
539 layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, ychange);
540
541 /* Fix cell offsets. */
542 layout_fix_offsets(w);
543 layout_fix_panes(w, NULL((void *)0));
544}
545
546/* Resize a pane to an absolute size. */
547void
548layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
549 u_int new_size)
550{
551 struct layout_cell *lc, *lcparent;
552 int change, size;
553
554 lc = wp->layout_cell;
555
556 /* Find next parent of the same type. */
557 lcparent = lc->parent;
558 while (lcparent != NULL((void *)0) && lcparent->type != type) {
559 lc = lcparent;
560 lcparent = lc->parent;
561 }
562 if (lcparent == NULL((void *)0))
563 return;
564
565 /* Work out the size adjustment. */
566 if (type == LAYOUT_LEFTRIGHT)
567 size = lc->sx;
568 else
569 size = lc->sy;
570 if (lc == TAILQ_LAST(&lcparent->cells, layout_cells)(*(((struct layout_cells *)((&lcparent->cells)->tqh_last
))->tqh_last))
)
571 change = size - new_size;
572 else
573 change = new_size - size;
574
575 /* Resize the pane. */
576 layout_resize_pane(wp, type, change, 1);
577}
578
579void
580layout_resize_layout(struct window *w, struct layout_cell *lc,
581 enum layout_type type, int change, int opposite)
582{
583 int needed, size;
584
585 /* Grow or shrink the cell. */
586 needed = change;
587 while (needed != 0) {
588 if (change > 0) {
589 size = layout_resize_pane_grow(w, lc, type, needed,
590 opposite);
591 needed -= size;
592 } else {
593 size = layout_resize_pane_shrink(w, lc, type, needed);
594 needed += size;
595 }
596
597 if (size == 0) /* no more change possible */
598 break;
599 }
600
601 /* Fix cell offsets. */
602 layout_fix_offsets(w);
603 layout_fix_panes(w, NULL((void *)0));
604 notify_window("window-layout-changed", w);
605}
606
607/* Resize a single pane within the layout. */
608void
609layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
610 int opposite)
611{
612 struct layout_cell *lc, *lcparent;
613
614 lc = wp->layout_cell;
615
616 /* Find next parent of the same type. */
617 lcparent = lc->parent;
618 while (lcparent != NULL((void *)0) && lcparent->type != type) {
619 lc = lcparent;
620 lcparent = lc->parent;
621 }
622 if (lcparent == NULL((void *)0))
623 return;
624
625 /* If this is the last cell, move back one. */
626 if (lc == TAILQ_LAST(&lcparent->cells, layout_cells)(*(((struct layout_cells *)((&lcparent->cells)->tqh_last
))->tqh_last))
)
627 lc = TAILQ_PREV(lc, layout_cells, entry)(*(((struct layout_cells *)((lc)->entry.tqe_prev))->tqh_last
))
;
628
629 layout_resize_layout(wp->window, lc, type, change, opposite);
630}
631
632/* Helper function to grow pane. */
633static int
634layout_resize_pane_grow(struct window *w, struct layout_cell *lc,
635 enum layout_type type, int needed, int opposite)
636{
637 struct layout_cell *lcadd, *lcremove;
638 u_int size = 0;
639
640 /* Growing. Always add to the current cell. */
641 lcadd = lc;
642
643 /* Look towards the tail for a suitable cell for reduction. */
644 lcremove = TAILQ_NEXT(lc, entry)((lc)->entry.tqe_next);
645 while (lcremove != NULL((void *)0)) {
646 size = layout_resize_check(w, lcremove, type);
647 if (size > 0)
648 break;
649 lcremove = TAILQ_NEXT(lcremove, entry)((lcremove)->entry.tqe_next);
650 }
651
652 /* If none found, look towards the head. */
653 if (opposite && lcremove == NULL((void *)0)) {
654 lcremove = TAILQ_PREV(lc, layout_cells, entry)(*(((struct layout_cells *)((lc)->entry.tqe_prev))->tqh_last
))
;
655 while (lcremove != NULL((void *)0)) {
656 size = layout_resize_check(w, lcremove, type);
657 if (size > 0)
658 break;
659 lcremove = TAILQ_PREV(lcremove, layout_cells, entry)(*(((struct layout_cells *)((lcremove)->entry.tqe_prev))->
tqh_last))
;
660 }
661 }
662 if (lcremove == NULL((void *)0))
663 return (0);
664
665 /* Change the cells. */
666 if (size > (u_int) needed)
667 size = needed;
668 layout_resize_adjust(w, lcadd, type, size);
669 layout_resize_adjust(w, lcremove, type, -size);
670 return (size);
671}
672
673/* Helper function to shrink pane. */
674static int
675layout_resize_pane_shrink(struct window *w, struct layout_cell *lc,
676 enum layout_type type, int needed)
677{
678 struct layout_cell *lcadd, *lcremove;
679 u_int size;
680
681 /* Shrinking. Find cell to remove from by walking towards head. */
682 lcremove = lc;
683 do {
684 size = layout_resize_check(w, lcremove, type);
685 if (size != 0)
686 break;
687 lcremove = TAILQ_PREV(lcremove, layout_cells, entry)(*(((struct layout_cells *)((lcremove)->entry.tqe_prev))->
tqh_last))
;
688 } while (lcremove != NULL((void *)0));
689 if (lcremove == NULL((void *)0))
690 return (0);
691
692 /* And add onto the next cell (from the original cell). */
693 lcadd = TAILQ_NEXT(lc, entry)((lc)->entry.tqe_next);
694 if (lcadd == NULL((void *)0))
695 return (0);
696
697 /* Change the cells. */
698 if (size > (u_int) -needed)
699 size = -needed;
700 layout_resize_adjust(w, lcadd, type, size);
701 layout_resize_adjust(w, lcremove, type, -size);
702 return (size);
703}
704
705/* Assign window pane to newly split cell. */
706void
707layout_assign_pane(struct layout_cell *lc, struct window_pane *wp,
708 int do_not_resize)
709{
710 layout_make_leaf(lc, wp);
711 if (do_not_resize)
712 layout_fix_panes(wp->window, wp);
713 else
714 layout_fix_panes(wp->window, NULL((void *)0));
715}
716
717/* Calculate the new pane size for resized parent. */
718static u_int
719layout_new_pane_size(struct window *w, u_int previous, struct layout_cell *lc,
720 enum layout_type type, u_int size, u_int count_left, u_int size_left)
721{
722 u_int new_size, min, max, available;
723
724 /* If this is the last cell, it can take all of the remaining size. */
725 if (count_left
52.1
'count_left' is not equal to 1
== 1)
53
Taking false branch
726 return (size_left);
727
728 /* How much is available in this parent? */
729 available = layout_resize_check(w, lc, type);
730
731 /*
732 * Work out the minimum size of this cell and the new size
733 * proportionate to the previous size.
734 */
735 min = (PANE_MINIMUM1 + 1) * (count_left - 1);
736 if (type
53.1
'type' is not equal to LAYOUT_LEFTRIGHT
== LAYOUT_LEFTRIGHT) {
54
Taking false branch
737 if (lc->sx - available > min)
738 min = lc->sx - available;
739 new_size = (lc->sx * size) / previous;
740 } else {
741 if (lc->sy - available > min)
55
Assuming the condition is false
56
Taking false branch
742 min = lc->sy - available;
743 new_size = (lc->sy * size) / previous;
57
Division by zero
744 }
745
746 /* Check against the maximum and minimum size. */
747 max = size_left - min;
748 if (new_size > max)
749 new_size = max;
750 if (new_size < PANE_MINIMUM1)
751 new_size = PANE_MINIMUM1;
752 return (new_size);
753}
754
755/* Check if the cell and all its children can be resized to a specific size. */
756static int
757layout_set_size_check(struct window *w, struct layout_cell *lc,
758 enum layout_type type, int size)
759{
760 struct layout_cell *lcchild;
761 u_int new_size, available, previous, count, idx;
762
763 /* Cells with no children must just be bigger than minimum. */
764 if (lc->type == LAYOUT_WINDOWPANE)
765 return (size >= PANE_MINIMUM1);
766 available = size;
767
768 /* Count number of children. */
769 count = 0;
770 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
771 count++;
772
773 /* Check new size will work for each child. */
774 if (lc->type == type) {
775 if (available < (count * 2) - 1)
776 return (0);
777
778 if (type == LAYOUT_LEFTRIGHT)
779 previous = lc->sx;
780 else
781 previous = lc->sy;
782
783 idx = 0;
784 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
{
785 new_size = layout_new_pane_size(w, previous, lcchild,
786 type, size, count - idx, available);
787 if (idx == count - 1) {
788 if (new_size > available)
789 return (0);
790 available -= new_size;
791 } else {
792 if (new_size + 1 > available)
793 return (0);
794 available -= new_size + 1;
795 }
796 if (!layout_set_size_check(w, lcchild, type, new_size))
797 return (0);
798 idx++;
799 }
800 } else {
801 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
{
802 if (lcchild->type == LAYOUT_WINDOWPANE)
803 continue;
804 if (!layout_set_size_check(w, lcchild, type, size))
805 return (0);
806 }
807 }
808
809 return (1);
810}
811
812/* Resize all child cells to fit within the current cell. */
813static void
814layout_resize_child_cells(struct window *w, struct layout_cell *lc)
815{
816 struct layout_cell *lcchild;
817 u_int previous, available, count, idx;
818
819 if (lc->type
20.1
Field 'type' is not equal to LAYOUT_WINDOWPANE
== LAYOUT_WINDOWPANE
)
21
Taking false branch
32
Assuming field 'type' is not equal to LAYOUT_WINDOWPANE
33
Taking false branch
820 return;
821
822 /* What is the current size used? */
823 count = 0;
824 previous = 0;
825 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
{
22
Assuming 'lcchild' is not equal to null
23
Loop condition is true. Entering loop body
25
Assuming 'lcchild' is equal to null
26
Loop condition is false. Execution continues on line 832
34
Assuming 'lcchild' is not equal to null
35
Loop condition is true. Entering loop body
40
Assuming 'lcchild' is equal to null
41
Loop condition is false. Execution continues on line 832
826 count++;
827 if (lc->type
23.1
Field 'type' is equal to LAYOUT_LEFTRIGHT
== LAYOUT_LEFTRIGHT
)
24
Taking true branch
36
Assuming field 'type' is not equal to LAYOUT_LEFTRIGHT
37
Taking false branch
828 previous += lcchild->sx;
829 else if (lc->type == LAYOUT_TOPBOTTOM)
38
Assuming field 'type' is not equal to LAYOUT_TOPBOTTOM
39
Taking false branch
830 previous += lcchild->sy;
831 }
832 previous += (count - 1);
42
The value 0 is assigned to 'previous'
833
834 /* And how much is available? */
835 available = 0;
836 if (lc->type
26.1
Field 'type' is equal to LAYOUT_LEFTRIGHT
42.1
Field 'type' is not equal to LAYOUT_LEFTRIGHT
== LAYOUT_LEFTRIGHT)
27
Taking true branch
43
Taking false branch
837 available = lc->sx;
838 else if (lc->type
43.1
Field 'type' is not equal to LAYOUT_TOPBOTTOM
== LAYOUT_TOPBOTTOM)
44
Taking false branch
839 available = lc->sy;
840
841 /* Resize children into the new size. */
842 idx = 0;
843 TAILQ_FOREACH(lcchild, &lc->cells, entry)for((lcchild) = ((&lc->cells)->tqh_first); (lcchild
) != ((void *)0); (lcchild) = ((lcchild)->entry.tqe_next))
{
28
Loop condition is true. Entering loop body
45
Loop condition is true. Entering loop body
48
Assuming 'lcchild' is not equal to null
49
Loop condition is true. Entering loop body
844 if (lc->type
28.1
Field 'type' is not equal to LAYOUT_TOPBOTTOM
45.1
Field 'type' is not equal to LAYOUT_TOPBOTTOM
49.1
Field 'type' is not equal to LAYOUT_TOPBOTTOM
== LAYOUT_TOPBOTTOM) {
29
Taking false branch
46
Taking false branch
50
Taking false branch
845 lcchild->sx = lc->sx;
846 lcchild->xoff = lc->xoff;
847 } else {
848 lcchild->sx = layout_new_pane_size(w, previous, lcchild,
51
Passing the value 0 via 2nd parameter 'previous'
52
Calling 'layout_new_pane_size'
849 lc->type, lc->sx, count - idx, available);
850 available -= (lcchild->sx + 1);
851 }
852 if (lc->type
29.1
Field 'type' is equal to LAYOUT_LEFTRIGHT
46.1
Field 'type' is not equal to LAYOUT_LEFTRIGHT
== LAYOUT_LEFTRIGHT)
30
Taking true branch
47
Taking false branch
853 lcchild->sy = lc->sy;
854 else {
855 lcchild->sy = layout_new_pane_size(w, previous, lcchild,
856 lc->type, lc->sy, count - idx, available);
857 available -= (lcchild->sy + 1);
858 }
859 layout_resize_child_cells(w, lcchild);
31
Calling 'layout_resize_child_cells'
860 idx++;
861 }
862}
863
864/*
865 * Split a pane into two. size is a hint, or -1 for default half/half
866 * split. This must be followed by layout_assign_pane before much else happens!
867 */
868struct layout_cell *
869layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
870 int flags)
871{
872 struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
873 u_int sx, sy, xoff, yoff, size1, size2, minimum;
874 u_int new_size, saved_size, resize_first = 0;
875 int full_size = (flags & SPAWN_FULLSIZE0x20), status;
876
877 /*
878 * If full_size is specified, add a new cell at the top of the window
879 * layout. Otherwise, split the cell for the current pane.
880 */
881 if (full_size)
1
Assuming 'full_size' is not equal to 0
2
Taking true branch
882 lc = wp->window->layout_root;
883 else
884 lc = wp->layout_cell;
885 status = options_get_number(wp->window->options, "pane-border-status");
886
887 /* Copy the old cell size. */
888 sx = lc->sx;
889 sy = lc->sy;
890 xoff = lc->xoff;
891 yoff = lc->yoff;
892
893 /* Check there is enough space for the two new panes. */
894 switch (type) {
3
Control jumps to 'case LAYOUT_LEFTRIGHT:' at line 895
895 case LAYOUT_LEFTRIGHT:
896 if (sx < PANE_MINIMUM1 * 2 + 1)
4
Assuming the condition is false
5
Taking false branch
897 return (NULL((void *)0));
898 break;
6
Execution continues on line 915
899 case LAYOUT_TOPBOTTOM:
900 if (layout_add_border(wp->window, lc, status))
901 minimum = PANE_MINIMUM1 * 2 + 2;
902 else
903 minimum = PANE_MINIMUM1 * 2 + 1;
904 if (sy < minimum)
905 return (NULL((void *)0));
906 break;
907 default:
908 fatalx("bad layout type");
909 }
910
911 /*
912 * Calculate new cell sizes. size is the target size or -1 for middle
913 * split, size1 is the size of the top/left and size2 the bottom/right.
914 */
915 if (type
6.1
'type' is equal to LAYOUT_LEFTRIGHT
== LAYOUT_LEFTRIGHT)
7
Taking true branch
916 saved_size = sx;
917 else
918 saved_size = sy;
919 if (size < 0)
8
Assuming 'size' is < 0
9
Taking true branch
920 size2 = ((saved_size + 1) / 2) - 1;
921 else if (flags & SPAWN_BEFORE0x8)
922 size2 = saved_size - size - 1;
923 else
924 size2 = size;
925 if (size2 < PANE_MINIMUM1)
10
Assuming 'size2' is < PANE_MINIMUM
11
Taking true branch
926 size2 = PANE_MINIMUM1;
927 else if (size2 > saved_size - 2)
928 size2 = saved_size - 2;
929 size1 = saved_size - 1 - size2;
930
931 /* Which size are we using? */
932 if (flags & SPAWN_BEFORE0x8)
12
Assuming the condition is true
13
Taking true branch
933 new_size = size2;
934 else
935 new_size = size1;
936
937 /* Confirm there is enough space for full size pane. */
938 if (full_size
13.1
'full_size' is not equal to 0
&& !layout_set_size_check(wp->window, lc, type, new_size))
14
Assuming the condition is false
15
Taking false branch
939 return (NULL((void *)0));
940
941 if (lc->parent != NULL((void *)0) && lc->parent->type == type) {
16
Assuming field 'parent' is equal to NULL
942 /*
943 * If the parent exists and is of the same type as the split,
944 * create a new cell and insert it after this one.
945 */
946 lcparent = lc->parent;
947 lcnew = layout_create_cell(lcparent);
948 if (flags & SPAWN_BEFORE0x8)
949 TAILQ_INSERT_BEFORE(lc, lcnew, entry)do { (lcnew)->entry.tqe_prev = (lc)->entry.tqe_prev; (lcnew
)->entry.tqe_next = (lc); *(lc)->entry.tqe_prev = (lcnew
); (lc)->entry.tqe_prev = &(lcnew)->entry.tqe_next;
} while (0)
;
950 else
951 TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry)do { if (((lcnew)->entry.tqe_next = (lc)->entry.tqe_next
) != ((void *)0)) (lcnew)->entry.tqe_next->entry.tqe_prev
= &(lcnew)->entry.tqe_next; else (&lcparent->cells
)->tqh_last = &(lcnew)->entry.tqe_next; (lc)->entry
.tqe_next = (lcnew); (lcnew)->entry.tqe_prev = &(lc)->
entry.tqe_next; } while (0)
;
952 } else if (full_size
16.1
'full_size' is not equal to 0
&& lc->parent
16.2
Field 'parent' is equal to NULL
== NULL((void *)0) && lc->type == type) {
17
Assuming 'type' is equal to field 'type'
18
Taking true branch
953 /*
954 * If the new full size pane is the same type as the root
955 * split, insert the new pane under the existing root cell
956 * instead of creating a new root cell. The existing layout
957 * must be resized before inserting the new cell.
958 */
959 if (lc->type
18.1
Field 'type' is equal to LAYOUT_LEFTRIGHT
== LAYOUT_LEFTRIGHT) {
19
Taking true branch
960 lc->sx = new_size;
961 layout_resize_child_cells(wp->window, lc);
20
Calling 'layout_resize_child_cells'
962 lc->sx = saved_size;
963 } else if (lc->type == LAYOUT_TOPBOTTOM) {
964 lc->sy = new_size;
965 layout_resize_child_cells(wp->window, lc);
966 lc->sy = saved_size;
967 }
968 resize_first = 1;
969
970 /* Create the new cell. */
971 lcnew = layout_create_cell(lc);
972 size = saved_size - 1 - new_size;
973 if (lc->type == LAYOUT_LEFTRIGHT)
974 layout_set_size(lcnew, size, sy, 0, 0);
975 else if (lc->type == LAYOUT_TOPBOTTOM)
976 layout_set_size(lcnew, sx, size, 0, 0);
977 if (flags & SPAWN_BEFORE0x8)
978 TAILQ_INSERT_HEAD(&lc->cells, lcnew, entry)do { if (((lcnew)->entry.tqe_next = (&lc->cells)->
tqh_first) != ((void *)0)) (&lc->cells)->tqh_first->
entry.tqe_prev = &(lcnew)->entry.tqe_next; else (&
lc->cells)->tqh_last = &(lcnew)->entry.tqe_next;
(&lc->cells)->tqh_first = (lcnew); (lcnew)->entry
.tqe_prev = &(&lc->cells)->tqh_first; } while (
0)
;
979 else
980 TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry)do { (lcnew)->entry.tqe_next = ((void *)0); (lcnew)->entry
.tqe_prev = (&lc->cells)->tqh_last; *(&lc->cells
)->tqh_last = (lcnew); (&lc->cells)->tqh_last = &
(lcnew)->entry.tqe_next; } while (0)
;
981 } else {
982 /*
983 * Otherwise create a new parent and insert it.
984 */
985
986 /* Create and insert the replacement parent. */
987 lcparent = layout_create_cell(lc->parent);
988 layout_make_node(lcparent, type);
989 layout_set_size(lcparent, sx, sy, xoff, yoff);
990 if (lc->parent == NULL((void *)0))
991 wp->window->layout_root = lcparent;
992 else
993 TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry)do { if (((lcparent)->entry.tqe_next = (lc)->entry.tqe_next
) != ((void *)0)) (lcparent)->entry.tqe_next->entry.tqe_prev
= &(lcparent)->entry.tqe_next; else (&lc->parent
->cells)->tqh_last = &(lcparent)->entry.tqe_next
; (lcparent)->entry.tqe_prev = (lc)->entry.tqe_prev; *(
lcparent)->entry.tqe_prev = (lcparent); ; ; } while (0)
;
994
995 /* Insert the old cell. */
996 lc->parent = lcparent;
997 TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry)do { if (((lc)->entry.tqe_next = (&lcparent->cells)
->tqh_first) != ((void *)0)) (&lcparent->cells)->
tqh_first->entry.tqe_prev = &(lc)->entry.tqe_next; else
(&lcparent->cells)->tqh_last = &(lc)->entry
.tqe_next; (&lcparent->cells)->tqh_first = (lc); (lc
)->entry.tqe_prev = &(&lcparent->cells)->tqh_first
; } while (0)
;
998
999 /* Create the new child cell. */
1000 lcnew = layout_create_cell(lcparent);
1001 if (flags & SPAWN_BEFORE0x8)
1002 TAILQ_INSERT_HEAD(&lcparent->cells, lcnew, entry)do { if (((lcnew)->entry.tqe_next = (&lcparent->cells
)->tqh_first) != ((void *)0)) (&lcparent->cells)->
tqh_first->entry.tqe_prev = &(lcnew)->entry.tqe_next
; else (&lcparent->cells)->tqh_last = &(lcnew)->
entry.tqe_next; (&lcparent->cells)->tqh_first = (lcnew
); (lcnew)->entry.tqe_prev = &(&lcparent->cells
)->tqh_first; } while (0)
;
1003 else
1004 TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry)do { (lcnew)->entry.tqe_next = ((void *)0); (lcnew)->entry
.tqe_prev = (&lcparent->cells)->tqh_last; *(&lcparent
->cells)->tqh_last = (lcnew); (&lcparent->cells)
->tqh_last = &(lcnew)->entry.tqe_next; } while (0)
;
1005 }
1006 if (flags & SPAWN_BEFORE0x8) {
1007 lc1 = lcnew;
1008 lc2 = lc;
1009 } else {
1010 lc1 = lc;
1011 lc2 = lcnew;
1012 }
1013
1014 /*
1015 * Set new cell sizes. size1 is the size of the top/left and size2 the
1016 * bottom/right.
1017 */
1018 if (!resize_first && type == LAYOUT_LEFTRIGHT) {
1019 layout_set_size(lc1, size1, sy, xoff, yoff);
1020 layout_set_size(lc2, size2, sy, xoff + lc1->sx + 1, yoff);
1021 } else if (!resize_first && type == LAYOUT_TOPBOTTOM) {
1022 layout_set_size(lc1, sx, size1, xoff, yoff);
1023 layout_set_size(lc2, sx, size2, xoff, yoff + lc1->sy + 1);
1024 }
1025 if (full_size) {
1026 if (!resize_first)
1027 layout_resize_child_cells(wp->window, lc);
1028 layout_fix_offsets(wp->window);
1029 } else
1030 layout_make_leaf(lc, wp);
1031
1032 return (lcnew);
1033}
1034
1035/* Destroy the cell associated with a pane. */
1036void
1037layout_close_pane(struct window_pane *wp)
1038{
1039 struct window *w = wp->window;
1040
1041 /* Remove the cell. */
1042 layout_destroy_cell(w, wp->layout_cell, &w->layout_root);
1043
1044 /* Fix pane offsets and sizes. */
1045 if (w->layout_root != NULL((void *)0)) {
1046 layout_fix_offsets(w);
1047 layout_fix_panes(w, NULL((void *)0));
1048 }
1049 notify_window("window-layout-changed", w);
1050}
1051
1052int
1053layout_spread_cell(struct window *w, struct layout_cell *parent)
1054{
1055 struct layout_cell *lc;
1056 u_int number, each, size, this;
1057 int change, changed, status;
1058
1059 number = 0;
1060 TAILQ_FOREACH (lc, &parent->cells, entry)for((lc) = ((&parent->cells)->tqh_first); (lc) != (
(void *)0); (lc) = ((lc)->entry.tqe_next))
1061 number++;
1062 if (number <= 1)
1063 return (0);
1064 status = options_get_number(w->options, "pane-border-status");
1065
1066 if (parent->type == LAYOUT_LEFTRIGHT)
1067 size = parent->sx;
1068 else if (parent->type == LAYOUT_TOPBOTTOM) {
1069 if (layout_add_border(w, parent, status))
1070 size = parent->sy - 1;
1071 else
1072 size = parent->sy;
1073 } else
1074 return (0);
1075 if (size < number - 1)
1076 return (0);
1077 each = (size - (number - 1)) / number;
1078 if (each == 0)
1079 return (0);
1080
1081 changed = 0;
1082 TAILQ_FOREACH (lc, &parent->cells, entry)for((lc) = ((&parent->cells)->tqh_first); (lc) != (
(void *)0); (lc) = ((lc)->entry.tqe_next))
{
1083 if (TAILQ_NEXT(lc, entry)((lc)->entry.tqe_next) == NULL((void *)0))
1084 each = size - ((each + 1) * (number - 1));
1085 change = 0;
1086 if (parent->type == LAYOUT_LEFTRIGHT) {
1087 change = each - (int)lc->sx;
1088 layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, change);
1089 } else if (parent->type == LAYOUT_TOPBOTTOM) {
1090 if (layout_add_border(w, lc, status))
1091 this = each + 1;
1092 else
1093 this = each;
1094 change = this - (int)lc->sy;
1095 layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change);
1096 }
1097 if (change != 0)
1098 changed = 1;
1099 }
1100 return (changed);
1101}
1102
1103void
1104layout_spread_out(struct window_pane *wp)
1105{
1106 struct layout_cell *parent;
1107 struct window *w = wp->window;
1108
1109 parent = wp->layout_cell->parent;
1110 if (parent == NULL((void *)0))
1111 return;
1112
1113 do {
1114 if (layout_spread_cell(w, parent)) {
1115 layout_fix_offsets(w);
1116 layout_fix_panes(w, NULL((void *)0));
1117 break;
1118 }
1119 } while ((parent = parent->parent) != NULL((void *)0));
1120}