[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.48

1.48    ! nicm        1: /* $OpenBSD: layout.c,v 1.47 2019/07/15 18:43:32 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);
1.29      nicm       42: static u_int   layout_new_pane_size(struct window *, u_int,
                     43:                    struct layout_cell *, enum layout_type, u_int, u_int,
                     44:                    u_int);
                     45: static int     layout_set_size_check(struct window *, struct layout_cell *,
                     46:                    enum layout_type, int);
                     47: static void    layout_resize_child_cells(struct window *,
                     48:                    struct layout_cell *);
1.1       nicm       49:
1.3       nicm       50: struct layout_cell *
                     51: layout_create_cell(struct layout_cell *lcparent)
1.1       nicm       52: {
1.3       nicm       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);
1.4       nicm       60:
1.3       nicm       61:        lc->sx = UINT_MAX;
                     62:        lc->sy = UINT_MAX;
1.4       nicm       63:
1.3       nicm       64:        lc->xoff = UINT_MAX;
                     65:        lc->yoff = UINT_MAX;
1.4       nicm       66:
1.3       nicm       67:        lc->wp = NULL;
                     68:
                     69:        return (lc);
1.1       nicm       70: }
                     71:
1.3       nicm       72: void
                     73: layout_free_cell(struct layout_cell *lc)
1.1       nicm       74: {
1.3       nicm       75:        struct layout_cell      *lcchild;
1.1       nicm       76:
1.3       nicm       77:        switch (lc->type) {
                     78:        case LAYOUT_LEFTRIGHT:
                     79:        case LAYOUT_TOPBOTTOM:
                     80:                while (!TAILQ_EMPTY(&lc->cells)) {
                     81:                        lcchild = TAILQ_FIRST(&lc->cells);
                     82:                        TAILQ_REMOVE(&lc->cells, lcchild, entry);
                     83:                        layout_free_cell(lcchild);
1.1       nicm       84:                }
1.3       nicm       85:                break;
                     86:        case LAYOUT_WINDOWPANE:
                     87:                if (lc->wp != NULL)
                     88:                        lc->wp->layout_cell = NULL;
                     89:                break;
1.1       nicm       90:        }
                     91:
1.14      nicm       92:        free(lc);
1.1       nicm       93: }
                     94:
1.3       nicm       95: void
                     96: layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
1.1       nicm       97: {
1.3       nicm       98:        struct layout_cell      *lcchild;
1.34      nicm       99:        const char              *type;
1.1       nicm      100:
1.34      nicm      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,
1.25      nicm      117:            lc->sy);
1.3       nicm      118:        switch (lc->type) {
                    119:        case LAYOUT_LEFTRIGHT:
                    120:        case LAYOUT_TOPBOTTOM:
                    121:                TAILQ_FOREACH(lcchild, &lc->cells, entry)
                    122:                        layout_print_cell(lcchild, hdr, n + 1);
                    123:                break;
                    124:        case LAYOUT_WINDOWPANE:
                    125:                break;
                    126:        }
1.1       nicm      127: }
                    128:
1.36      nicm      129: struct layout_cell *
                    130: layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
                    131: {
                    132:        struct layout_cell      *lcchild, *last = NULL;
                    133:
                    134:        TAILQ_FOREACH(lcchild, &lc->cells, entry) {
                    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) {
                    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);
                    163: }
                    164:
1.1       nicm      165: void
1.25      nicm      166: layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, u_int xoff,
                    167:     u_int yoff)
1.1       nicm      168: {
1.3       nicm      169:        lc->sx = sx;
                    170:        lc->sy = sy;
                    171:
                    172:        lc->xoff = xoff;
                    173:        lc->yoff = yoff;
1.1       nicm      174: }
                    175:
                    176: void
1.3       nicm      177: layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
1.1       nicm      178: {
1.3       nicm      179:        lc->type = LAYOUT_WINDOWPANE;
                    180:
                    181:        TAILQ_INIT(&lc->cells);
                    182:
                    183:        wp->layout_cell = lc;
                    184:        lc->wp = wp;
1.1       nicm      185: }
                    186:
                    187: void
1.3       nicm      188: layout_make_node(struct layout_cell *lc, enum layout_type type)
1.1       nicm      189: {
1.3       nicm      190:        if (type == LAYOUT_WINDOWPANE)
                    191:                fatalx("bad layout type");
                    192:        lc->type = type;
                    193:
                    194:        TAILQ_INIT(&lc->cells);
                    195:
                    196:        if (lc->wp != NULL)
                    197:                lc->wp->layout_cell = NULL;
                    198:        lc->wp = NULL;
1.1       nicm      199: }
                    200:
1.47      nicm      201: /* Fix cell offsets for a child cell. */
1.46      nicm      202: static void
                    203: layout_fix_offsets1(struct layout_cell *lc)
1.1       nicm      204: {
1.3       nicm      205:        struct layout_cell      *lcchild;
                    206:        u_int                    xoff, yoff;
1.1       nicm      207:
1.3       nicm      208:        if (lc->type == LAYOUT_LEFTRIGHT) {
                    209:                xoff = lc->xoff;
                    210:                TAILQ_FOREACH(lcchild, &lc->cells, entry) {
                    211:                        lcchild->xoff = xoff;
                    212:                        lcchild->yoff = lc->yoff;
                    213:                        if (lcchild->type != LAYOUT_WINDOWPANE)
1.46      nicm      214:                                layout_fix_offsets1(lcchild);
1.3       nicm      215:                        xoff += lcchild->sx + 1;
                    216:                }
                    217:        } else {
                    218:                yoff = lc->yoff;
                    219:                TAILQ_FOREACH(lcchild, &lc->cells, entry) {
                    220:                        lcchild->xoff = lc->xoff;
                    221:                        lcchild->yoff = yoff;
                    222:                        if (lcchild->type != LAYOUT_WINDOWPANE)
1.46      nicm      223:                                layout_fix_offsets1(lcchild);
1.3       nicm      224:                        yoff += lcchild->sy + 1;
                    225:                }
                    226:        }
1.1       nicm      227: }
                    228:
1.46      nicm      229: /* Update cell offsets based on their sizes. */
                    230: void
                    231: layout_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:
1.47      nicm      241: /* Is this a top cell? */
1.27      nicm      242: static int
1.47      nicm      243: layout_cell_is_top(struct window *w, struct layout_cell *lc)
1.27      nicm      244: {
1.44      nicm      245:        struct layout_cell      *next;
1.27      nicm      246:
1.47      nicm      247:        while (lc != w->layout_root) {
                    248:                next = lc->parent;
                    249:                if (next->type == LAYOUT_TOPBOTTOM &&
                    250:                    lc != TAILQ_FIRST(&next->cells))
                    251:                        return (0);
                    252:                lc = next;
                    253:        }
                    254:        return (1);
                    255: }
1.27      nicm      256:
1.47      nicm      257: /* Is this a bottom cell? */
                    258: static int
                    259: layout_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))
                    267:                        return (0);
                    268:                lc = next;
1.27      nicm      269:        }
                    270:        return (1);
                    271: }
                    272:
1.47      nicm      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:  */
                    277: static int
                    278: layout_add_border(struct window *w, struct layout_cell *lc, int status)
                    279: {
                    280:        if (status == PANE_STATUS_TOP)
                    281:                return (layout_cell_is_top(w, lc));
                    282:        if (status == PANE_STATUS_BOTTOM)
                    283:                return (layout_cell_is_bottom(w, lc));
                    284:        return (0);
                    285: }
                    286:
1.3       nicm      287: /* Update pane offsets and sizes based on their cells. */
1.1       nicm      288: void
1.48    ! nicm      289: layout_fix_panes(struct window *w, struct window_pane *skip)
1.1       nicm      290: {
                    291:        struct window_pane      *wp;
1.3       nicm      292:        struct layout_cell      *lc;
1.47      nicm      293:        int                      status;
1.1       nicm      294:
1.27      nicm      295:        status = options_get_number(w->options, "pane-border-status");
1.1       nicm      296:        TAILQ_FOREACH(wp, &w->panes, entry) {
1.48    ! nicm      297:                if ((lc = wp->layout_cell) == NULL || wp == skip)
1.3       nicm      298:                        continue;
1.27      nicm      299:
1.3       nicm      300:                wp->xoff = lc->xoff;
                    301:                wp->yoff = lc->yoff;
                    302:
1.47      nicm      303:                if (layout_add_border(w, lc, status)) {
                    304:                        if (status == PANE_STATUS_TOP)
                    305:                                wp->yoff++;
                    306:                        window_pane_resize(wp, lc->sx, lc->sy - 1);
                    307:                } else
                    308:                        window_pane_resize(wp, lc->sx, lc->sy);
1.1       nicm      309:        }
                    310: }
                    311:
1.6       nicm      312: /* Count the number of available cells in a layout. */
                    313: u_int
                    314: layout_count_cells(struct layout_cell *lc)
                    315: {
                    316:        struct layout_cell      *lcchild;
1.29      nicm      317:        u_int                    count;
1.6       nicm      318:
                    319:        switch (lc->type) {
                    320:        case LAYOUT_WINDOWPANE:
                    321:                return (1);
                    322:        case LAYOUT_LEFTRIGHT:
                    323:        case LAYOUT_TOPBOTTOM:
1.29      nicm      324:                count = 0;
1.6       nicm      325:                TAILQ_FOREACH(lcchild, &lc->cells, entry)
1.29      nicm      326:                        count += layout_count_cells(lcchild);
                    327:                return (count);
1.6       nicm      328:        default:
                    329:                fatalx("bad layout type");
                    330:        }
                    331: }
                    332:
1.3       nicm      333: /* Calculate how much size is available to be removed from a cell. */
1.28      nicm      334: static u_int
                    335: layout_resize_check(struct window *w, struct layout_cell *lc,
                    336:     enum layout_type type)
1.1       nicm      337: {
1.3       nicm      338:        struct layout_cell      *lcchild;
                    339:        u_int                    available, minimum;
1.37      nicm      340:        int                      status;
1.1       nicm      341:
1.37      nicm      342:        status = options_get_number(w->options, "pane-border-status");
1.3       nicm      343:        if (lc->type == LAYOUT_WINDOWPANE) {
                    344:                /* Space available in this cell only. */
1.47      nicm      345:                if (type == LAYOUT_LEFTRIGHT) {
1.3       nicm      346:                        available = lc->sx;
1.47      nicm      347:                        minimum = PANE_MINIMUM;
                    348:                } else {
1.3       nicm      349:                        available = lc->sy;
1.47      nicm      350:                        if (layout_add_border(w, lc, status))
                    351:                                minimum = PANE_MINIMUM + 1;
                    352:                        else
                    353:                                minimum = PANE_MINIMUM;
1.28      nicm      354:                }
                    355:                if (available > minimum)
                    356:                        available -= minimum;
1.3       nicm      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)
1.28      nicm      363:                        available += layout_resize_check(w, lcchild, type);
1.3       nicm      364:        } else {
                    365:                /* Different type: minimum of available space in child cells. */
                    366:                minimum = UINT_MAX;
                    367:                TAILQ_FOREACH(lcchild, &lc->cells, entry) {
1.28      nicm      368:                        available = layout_resize_check(w, lcchild, type);
1.3       nicm      369:                        if (available < minimum)
                    370:                                minimum = available;
                    371:                }
                    372:                available = minimum;
1.2       nicm      373:        }
                    374:
1.3       nicm      375:        return (available);
                    376: }
1.1       nicm      377:
1.3       nicm      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:  */
                    382: void
1.28      nicm      383: layout_resize_adjust(struct window *w, struct layout_cell *lc,
                    384:     enum layout_type type, int change)
1.3       nicm      385: {
                    386:        struct layout_cell      *lcchild;
1.1       nicm      387:
1.3       nicm      388:        /* Adjust the cell size. */
                    389:        if (type == LAYOUT_LEFTRIGHT)
                    390:                lc->sx += change;
                    391:        else
                    392:                lc->sy += change;
1.4       nicm      393:
1.3       nicm      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)
1.28      nicm      401:                        layout_resize_adjust(w, lcchild, type, change);
1.3       nicm      402:                return;
1.1       nicm      403:        }
                    404:
1.4       nicm      405:        /*
                    406:         * Child cell runs in the same direction. Adjust each child equally
1.3       nicm      407:         * until no further change is possible.
                    408:         */
                    409:        while (change != 0) {
                    410:                TAILQ_FOREACH(lcchild, &lc->cells, entry) {
                    411:                        if (change == 0)
                    412:                                break;
                    413:                        if (change > 0) {
1.28      nicm      414:                                layout_resize_adjust(w, lcchild, type, 1);
1.3       nicm      415:                                change--;
                    416:                                continue;
                    417:                        }
1.28      nicm      418:                        if (layout_resize_check(w, lcchild, type) > 0) {
                    419:                                layout_resize_adjust(w, lcchild, type, -1);
1.3       nicm      420:                                change++;
                    421:                        }
                    422:                }
1.1       nicm      423:        }
                    424: }
                    425:
1.6       nicm      426: /* Destroy a cell and redistribute the space. */
                    427: void
1.28      nicm      428: layout_destroy_cell(struct window *w, struct layout_cell *lc,
                    429:     struct layout_cell **lcroot)
1.6       nicm      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) {
                    439:                layout_free_cell(lc);
                    440:                *lcroot = NULL;
                    441:                return;
                    442:        }
                    443:
                    444:        /* Merge the space into the previous or next cell. */
                    445:        if (lc == TAILQ_FIRST(&lcparent->cells))
                    446:                lcother = TAILQ_NEXT(lc, entry);
                    447:        else
                    448:                lcother = TAILQ_PREV(lc, layout_cells, entry);
1.43      nicm      449:        if (lcother != NULL && lcparent->type == LAYOUT_LEFTRIGHT)
1.28      nicm      450:                layout_resize_adjust(w, lcother, lcparent->type, lc->sx + 1);
1.43      nicm      451:        else if (lcother != NULL)
1.28      nicm      452:                layout_resize_adjust(w, lcother, lcparent->type, lc->sy + 1);
1.6       nicm      453:
                    454:        /* Remove this from the parent's list. */
                    455:        TAILQ_REMOVE(&lcparent->cells, lc, entry);
                    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);
                    463:        if (TAILQ_NEXT(lc, entry) == NULL) {
                    464:                TAILQ_REMOVE(&lcparent->cells, lc, entry);
                    465:
                    466:                lc->parent = lcparent->parent;
                    467:                if (lc->parent == NULL) {
                    468:                        lc->xoff = 0; lc->yoff = 0;
                    469:                        *lcroot = lc;
                    470:                } else
                    471:                        TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
                    472:
                    473:                layout_free_cell(lcparent);
                    474:        }
                    475: }
                    476:
1.1       nicm      477: void
1.18      nicm      478: layout_init(struct window *w, struct window_pane *wp)
1.1       nicm      479: {
1.3       nicm      480:        struct layout_cell      *lc;
1.1       nicm      481:
1.3       nicm      482:        lc = w->layout_root = layout_create_cell(NULL);
                    483:        layout_set_size(lc, w->sx, w->sy, 0, 0);
1.18      nicm      484:        layout_make_leaf(lc, wp);
1.48    ! nicm      485:        layout_fix_panes(w, NULL);
1.3       nicm      486: }
1.2       nicm      487:
1.3       nicm      488: void
                    489: layout_free(struct window *w)
                    490: {
                    491:        layout_free_cell(w->layout_root);
                    492: }
1.1       nicm      493:
1.3       nicm      494: /* Resize the entire layout after window resize. */
                    495: void
                    496: layout_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;
1.1       nicm      500:
1.4       nicm      501:        /*
1.3       nicm      502:         * Adjust horizontally. Do not attempt to reduce the layout lower than
                    503:         * the minimum (more than the amount returned by layout_resize_check).
1.4       nicm      504:         *
1.3       nicm      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:         */
1.41      nicm      514:        xchange = sx - lc->sx;
1.28      nicm      515:        xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT);
1.3       nicm      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;
1.1       nicm      521:                else
1.3       nicm      522:                        xchange = sx - lc->sx;
1.1       nicm      523:        }
1.3       nicm      524:        if (xchange != 0)
1.28      nicm      525:                layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, xchange);
1.1       nicm      526:
1.3       nicm      527:        /* Adjust vertically in a similar fashion. */
1.41      nicm      528:        ychange = sy - lc->sy;
1.28      nicm      529:        ylimit = layout_resize_check(w, lc, LAYOUT_TOPBOTTOM);
1.3       nicm      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;
1.1       nicm      537:        }
1.3       nicm      538:        if (ychange != 0)
1.28      nicm      539:                layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, ychange);
1.4       nicm      540:
1.3       nicm      541:        /* Fix cell offsets. */
1.46      nicm      542:        layout_fix_offsets(w);
1.48    ! nicm      543:        layout_fix_panes(w, NULL);
1.1       nicm      544: }
                    545:
1.17      nicm      546: /* Resize a pane to an absolute size. */
                    547: void
                    548: layout_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 && lcparent->type != type) {
                    559:                lc = lcparent;
                    560:                lcparent = lc->parent;
                    561:        }
                    562:        if (lcparent == NULL)
                    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))
                    571:                change = size - new_size;
                    572:        else
                    573:                change = new_size - size;
                    574:
                    575:        /* Resize the pane. */
1.30      nicm      576:        layout_resize_pane(wp, type, change, 1);
1.17      nicm      577: }
                    578:
1.36      nicm      579: void
                    580: layout_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. */
1.46      nicm      602:        layout_fix_offsets(w);
1.48    ! nicm      603:        layout_fix_panes(w, NULL);
1.36      nicm      604:        notify_window("window-layout-changed", w);
                    605: }
                    606:
1.3       nicm      607: /* Resize a single pane within the layout. */
1.1       nicm      608: void
1.30      nicm      609: layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
                    610:     int opposite)
1.1       nicm      611: {
1.28      nicm      612:        struct layout_cell      *lc, *lcparent;
1.1       nicm      613:
1.3       nicm      614:        lc = wp->layout_cell;
1.1       nicm      615:
1.3       nicm      616:        /* Find next parent of the same type. */
                    617:        lcparent = lc->parent;
                    618:        while (lcparent != NULL && lcparent->type != type) {
                    619:                lc = lcparent;
                    620:                lcparent = lc->parent;
                    621:        }
                    622:        if (lcparent == NULL)
                    623:                return;
                    624:
                    625:        /* If this is the last cell, move back one. */
                    626:        if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
                    627:                lc = TAILQ_PREV(lc, layout_cells, entry);
                    628:
1.36      nicm      629:        layout_resize_layout(wp->window, lc, type, change, opposite);
1.3       nicm      630: }
1.1       nicm      631:
1.17      nicm      632: /* Helper function to grow pane. */
1.27      nicm      633: static int
1.28      nicm      634: layout_resize_pane_grow(struct window *w, struct layout_cell *lc,
1.30      nicm      635:     enum layout_type type, int needed, int opposite)
1.3       nicm      636: {
                    637:        struct layout_cell      *lcadd, *lcremove;
1.30      nicm      638:        u_int                    size = 0;
1.3       nicm      639:
                    640:        /* Growing. Always add to the current cell. */
                    641:        lcadd = lc;
1.4       nicm      642:
1.3       nicm      643:        /* Look towards the tail for a suitable cell for reduction. */
                    644:        lcremove = TAILQ_NEXT(lc, entry);
                    645:        while (lcremove != NULL) {
1.28      nicm      646:                size = layout_resize_check(w, lcremove, type);
1.3       nicm      647:                if (size > 0)
                    648:                        break;
1.4       nicm      649:                lcremove = TAILQ_NEXT(lcremove, entry);
1.1       nicm      650:        }
                    651:
1.3       nicm      652:        /* If none found, look towards the head. */
1.30      nicm      653:        if (opposite && lcremove == NULL) {
1.3       nicm      654:                lcremove = TAILQ_PREV(lc, layout_cells, entry);
                    655:                while (lcremove != NULL) {
1.28      nicm      656:                        size = layout_resize_check(w, lcremove, type);
1.3       nicm      657:                        if (size > 0)
                    658:                                break;
                    659:                        lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
1.1       nicm      660:                }
1.3       nicm      661:        }
1.30      nicm      662:        if (lcremove == NULL)
                    663:                return (0);
1.1       nicm      664:
1.3       nicm      665:        /* Change the cells. */
                    666:        if (size > (u_int) needed)
                    667:                size = needed;
1.28      nicm      668:        layout_resize_adjust(w, lcadd, type, size);
                    669:        layout_resize_adjust(w, lcremove, type, -size);
1.3       nicm      670:        return (size);
                    671: }
1.1       nicm      672:
1.17      nicm      673: /* Helper function to shrink pane. */
1.27      nicm      674: static int
1.28      nicm      675: layout_resize_pane_shrink(struct window *w, struct layout_cell *lc,
                    676:     enum layout_type type, int needed)
1.3       nicm      677: {
                    678:        struct layout_cell      *lcadd, *lcremove;
                    679:        u_int                    size;
1.1       nicm      680:
1.3       nicm      681:        /* Shrinking. Find cell to remove from by walking towards head. */
                    682:        lcremove = lc;
                    683:        do {
1.28      nicm      684:                size = layout_resize_check(w, lcremove, type);
1.3       nicm      685:                if (size != 0)
1.1       nicm      686:                        break;
1.3       nicm      687:                lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
                    688:        } while (lcremove != NULL);
                    689:        if (lcremove == NULL)
                    690:                return (0);
                    691:
                    692:        /* And add onto the next cell (from the original cell). */
                    693:        lcadd = TAILQ_NEXT(lc, entry);
                    694:        if (lcadd == NULL)
                    695:                return (0);
                    696:
                    697:        /* Change the cells. */
                    698:        if (size > (u_int) -needed)
                    699:                size = -needed;
1.28      nicm      700:        layout_resize_adjust(w, lcadd, type, size);
                    701:        layout_resize_adjust(w, lcremove, type, -size);
1.3       nicm      702:        return (size);
1.1       nicm      703: }
                    704:
1.5       nicm      705: /* Assign window pane to newly split cell. */
                    706: void
1.48    ! nicm      707: layout_assign_pane(struct layout_cell *lc, struct window_pane *wp,
        !           708:     int do_not_resize)
1.5       nicm      709: {
                    710:        layout_make_leaf(lc, wp);
1.48    ! nicm      711:        if (do_not_resize)
        !           712:                layout_fix_panes(wp->window, wp);
        !           713:        else
        !           714:                layout_fix_panes(wp->window, NULL);
1.5       nicm      715: }
                    716:
1.29      nicm      717: /* Calculate the new pane size for resized parent. */
                    718: static u_int
                    719: layout_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 == 1)
                    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_MINIMUM + 1) * (count_left - 1);
                    736:        if (type == LAYOUT_LEFTRIGHT) {
                    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)
                    742:                        min = lc->sy - available;
                    743:                new_size = (lc->sy * size) / previous;
                    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_MINIMUM)
                    751:                new_size = PANE_MINIMUM;
                    752:        return (new_size);
                    753: }
                    754:
                    755: /* Check if the cell and all its children can be resized to a specific size. */
                    756: static int
                    757: layout_set_size_check(struct window *w, struct layout_cell *lc,
                    758:     enum layout_type type, int size)
                    759: {
                    760:        struct layout_cell      *lcchild;
1.39      nicm      761:        u_int                    new_size, available, previous, count, idx;
1.29      nicm      762:
                    763:        /* Cells with no children must just be bigger than minimum. */
                    764:        if (lc->type == LAYOUT_WINDOWPANE)
                    765:                return (size >= PANE_MINIMUM);
                    766:        available = size;
                    767:
                    768:        /* Count number of children. */
                    769:        count = 0;
                    770:        TAILQ_FOREACH(lcchild, &lc->cells, entry)
                    771:                count++;
                    772:
                    773:        /* Check new size will work for each child. */
                    774:        if (lc->type == type) {
1.39      nicm      775:                if (available < (count * 2) - 1)
                    776:                        return (0);
                    777:
1.29      nicm      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) {
                    785:                        new_size = layout_new_pane_size(w, previous, lcchild,
                    786:                            type, size, count - idx, available);
1.39      nicm      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:                        }
1.29      nicm      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) {
                    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. */
                    813: static void
                    814: layout_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 == LAYOUT_WINDOWPANE)
                    820:                return;
                    821:
                    822:        /* What is the current size used? */
                    823:        count = 0;
                    824:        previous = 0;
                    825:        TAILQ_FOREACH(lcchild, &lc->cells, entry) {
                    826:                count++;
                    827:                if (lc->type == LAYOUT_LEFTRIGHT)
                    828:                        previous += lcchild->sx;
                    829:                else if (lc->type == LAYOUT_TOPBOTTOM)
                    830:                        previous += lcchild->sy;
                    831:        }
                    832:        previous += (count - 1);
                    833:
                    834:        /* And how much is available? */
                    835:        available = 0;
                    836:        if (lc->type == LAYOUT_LEFTRIGHT)
                    837:                available = lc->sx;
                    838:        else if (lc->type == LAYOUT_TOPBOTTOM)
                    839:                available = lc->sy;
                    840:
                    841:        /* Resize children into the new size. */
                    842:        idx = 0;
                    843:        TAILQ_FOREACH(lcchild, &lc->cells, entry) {
                    844:                if (lc->type == LAYOUT_TOPBOTTOM) {
                    845:                        lcchild->sx = lc->sx;
                    846:                        lcchild->xoff = lc->xoff;
                    847:                } else {
                    848:                        lcchild->sx = layout_new_pane_size(w, previous, lcchild,
                    849:                            lc->type, lc->sx, count - idx, available);
                    850:                        available -= (lcchild->sx + 1);
                    851:                }
                    852:                if (lc->type == LAYOUT_LEFTRIGHT)
                    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);
                    860:                idx++;
                    861:        }
                    862: }
                    863:
1.5       nicm      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!
1.29      nicm      867:  */
1.5       nicm      868: struct layout_cell *
1.25      nicm      869: layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
1.40      nicm      870:     int flags)
1.1       nicm      871: {
1.9       nicm      872:        struct layout_cell     *lc, *lcparent, *lcnew, *lc1, *lc2;
1.42      nicm      873:        u_int                   sx, sy, xoff, yoff, size1, size2, minimum;
1.29      nicm      874:        u_int                   new_size, saved_size, resize_first = 0;
1.42      nicm      875:        int                     full_size = (flags & SPAWN_FULLSIZE), status;
1.1       nicm      876:
1.29      nicm      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)
                    882:                lc = wp->window->layout_root;
                    883:        else
                    884:                lc = wp->layout_cell;
1.42      nicm      885:        status = options_get_number(wp->window->options, "pane-border-status");
1.1       nicm      886:
1.3       nicm      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) {
                    895:        case LAYOUT_LEFTRIGHT:
                    896:                if (sx < PANE_MINIMUM * 2 + 1)
1.5       nicm      897:                        return (NULL);
1.3       nicm      898:                break;
                    899:        case LAYOUT_TOPBOTTOM:
1.47      nicm      900:                if (layout_add_border(wp->window, lc, status))
                    901:                        minimum = PANE_MINIMUM * 2 + 2;
                    902:                else
                    903:                        minimum = PANE_MINIMUM * 2 + 1;
1.42      nicm      904:                if (sy < minimum)
1.5       nicm      905:                        return (NULL);
1.3       nicm      906:                break;
                    907:        default:
                    908:                fatalx("bad layout type");
                    909:        }
1.4       nicm      910:
1.29      nicm      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 == LAYOUT_LEFTRIGHT)
                    916:                saved_size = sx;
                    917:        else
                    918:                saved_size = sy;
                    919:        if (size < 0)
                    920:                size2 = ((saved_size + 1) / 2) - 1;
1.40      nicm      921:        else if (flags & SPAWN_BEFORE)
1.29      nicm      922:                size2 = saved_size - size - 1;
                    923:        else
                    924:                size2 = size;
                    925:        if (size2 < PANE_MINIMUM)
                    926:                size2 = PANE_MINIMUM;
                    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? */
1.40      nicm      932:        if (flags & SPAWN_BEFORE)
1.29      nicm      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 && !layout_set_size_check(wp->window, lc, type, new_size))
                    939:                return (NULL);
                    940:
1.3       nicm      941:        if (lc->parent != NULL && lc->parent->type == type) {
                    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:                 */
1.9       nicm      946:                lcparent = lc->parent;
                    947:                lcnew = layout_create_cell(lcparent);
1.40      nicm      948:                if (flags & SPAWN_BEFORE)
1.9       nicm      949:                        TAILQ_INSERT_BEFORE(lc, lcnew, entry);
                    950:                else
                    951:                        TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
1.29      nicm      952:        } else if (full_size && lc->parent == NULL && lc->type == type) {
                    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 == LAYOUT_LEFTRIGHT) {
                    960:                        lc->sx = new_size;
                    961:                        layout_resize_child_cells(wp->window, lc);
                    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);
1.32      nicm      972:                size = saved_size - 1 - new_size;
1.29      nicm      973:                if (lc->type == LAYOUT_LEFTRIGHT)
1.32      nicm      974:                        layout_set_size(lcnew, size, sy, 0, 0);
1.29      nicm      975:                else if (lc->type == LAYOUT_TOPBOTTOM)
1.32      nicm      976:                        layout_set_size(lcnew, sx, size, 0, 0);
1.40      nicm      977:                if (flags & SPAWN_BEFORE)
1.29      nicm      978:                        TAILQ_INSERT_HEAD(&lc->cells, lcnew, entry);
                    979:                else
                    980:                        TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
1.3       nicm      981:        } else {
                    982:                /*
                    983:                 * Otherwise create a new parent and insert it.
                    984:                 */
1.4       nicm      985:
1.3       nicm      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)
                    991:                        wp->window->layout_root = lcparent;
                    992:                else
                    993:                        TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry);
1.4       nicm      994:
1.3       nicm      995:                /* Insert the old cell. */
                    996:                lc->parent = lcparent;
                    997:                TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
1.4       nicm      998:
1.3       nicm      999:                /* Create the new child cell. */
                   1000:                lcnew = layout_create_cell(lcparent);
1.40      nicm     1001:                if (flags & SPAWN_BEFORE)
1.9       nicm     1002:                        TAILQ_INSERT_HEAD(&lcparent->cells, lcnew, entry);
                   1003:                else
                   1004:                        TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry);
                   1005:        }
1.40      nicm     1006:        if (flags & SPAWN_BEFORE) {
1.9       nicm     1007:                lc1 = lcnew;
                   1008:                lc2 = lc;
                   1009:        } else {
                   1010:                lc1 = lc;
                   1011:                lc2 = lcnew;
1.3       nicm     1012:        }
                   1013:
1.29      nicm     1014:        /*
                   1015:         * Set new cell sizes. size1 is the size of the top/left and size2 the
                   1016:         * bottom/right.
1.3       nicm     1017:         */
1.29      nicm     1018:        if (!resize_first && type == LAYOUT_LEFTRIGHT) {
1.9       nicm     1019:                layout_set_size(lc1, size1, sy, xoff, yoff);
                   1020:                layout_set_size(lc2, size2, sy, xoff + lc1->sx + 1, yoff);
1.29      nicm     1021:        } else if (!resize_first && type == LAYOUT_TOPBOTTOM) {
1.9       nicm     1022:                layout_set_size(lc1, sx, size1, xoff, yoff);
                   1023:                layout_set_size(lc2, sx, size2, xoff, yoff + lc1->sy + 1);
1.3       nicm     1024:        }
1.29      nicm     1025:        if (full_size) {
                   1026:                if (!resize_first)
                   1027:                        layout_resize_child_cells(wp->window, lc);
1.46      nicm     1028:                layout_fix_offsets(wp->window);
1.29      nicm     1029:        } else
                   1030:                layout_make_leaf(lc, wp);
1.1       nicm     1031:
1.5       nicm     1032:        return (lcnew);
1.3       nicm     1033: }
1.1       nicm     1034:
1.6       nicm     1035: /* Destroy the cell associated with a pane. */
1.3       nicm     1036: void
                   1037: layout_close_pane(struct window_pane *wp)
                   1038: {
1.28      nicm     1039:        struct window   *w = wp->window;
                   1040:
1.6       nicm     1041:        /* Remove the cell. */
1.28      nicm     1042:        layout_destroy_cell(w, wp->layout_cell, &w->layout_root);
1.1       nicm     1043:
1.6       nicm     1044:        /* Fix pane offsets and sizes. */
1.28      nicm     1045:        if (w->layout_root != NULL) {
1.46      nicm     1046:                layout_fix_offsets(w);
1.48    ! nicm     1047:                layout_fix_panes(w, NULL);
1.3       nicm     1048:        }
1.31      nicm     1049:        notify_window("window-layout-changed", w);
1.33      nicm     1050: }
                   1051:
                   1052: int
                   1053: layout_spread_cell(struct window *w, struct layout_cell *parent)
                   1054: {
                   1055:        struct layout_cell      *lc;
1.42      nicm     1056:        u_int                    number, each, size, this;
                   1057:        int                      change, changed, status;
1.33      nicm     1058:
                   1059:        number = 0;
                   1060:        TAILQ_FOREACH (lc, &parent->cells, entry)
1.45      nicm     1061:                number++;
1.33      nicm     1062:        if (number <= 1)
                   1063:                return (0);
1.42      nicm     1064:        status = options_get_number(w->options, "pane-border-status");
1.33      nicm     1065:
                   1066:        if (parent->type == LAYOUT_LEFTRIGHT)
                   1067:                size = parent->sx;
1.42      nicm     1068:        else if (parent->type == LAYOUT_TOPBOTTOM) {
1.47      nicm     1069:                if (layout_add_border(w, parent, status))
                   1070:                        size = parent->sy - 1;
                   1071:                else
                   1072:                        size = parent->sy;
1.42      nicm     1073:        } else
                   1074:                return (0);
                   1075:        if (size < number - 1)
1.33      nicm     1076:                return (0);
                   1077:        each = (size - (number - 1)) / number;
1.42      nicm     1078:        if (each == 0)
                   1079:                return (0);
1.33      nicm     1080:
                   1081:        changed = 0;
                   1082:        TAILQ_FOREACH (lc, &parent->cells, entry) {
                   1083:                if (TAILQ_NEXT(lc, entry) == NULL)
1.35      nicm     1084:                        each = size - ((each + 1) * (number - 1));
1.33      nicm     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) {
1.47      nicm     1090:                        if (layout_add_border(w, lc, status))
                   1091:                                this = each + 1;
                   1092:                        else
                   1093:                                this = each;
1.42      nicm     1094:                        change = this - (int)lc->sy;
1.33      nicm     1095:                        layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change);
                   1096:                }
                   1097:                if (change != 0)
                   1098:                        changed = 1;
                   1099:        }
                   1100:        return (changed);
                   1101: }
                   1102:
                   1103: void
                   1104: layout_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)
                   1111:                return;
                   1112:
                   1113:        do {
                   1114:                if (layout_spread_cell(w, parent)) {
1.46      nicm     1115:                        layout_fix_offsets(w);
1.48    ! nicm     1116:                        layout_fix_panes(w, NULL);
1.33      nicm     1117:                        break;
                   1118:                }
                   1119:        } while ((parent = parent->parent) != NULL);
1.1       nicm     1120: }