[BACK]Return to layout.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/layout.c, Revision 1.46

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