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

1.2       nicm        1: /* $OpenBSD: layout.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
                     15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
                     16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20:
1.3     ! nicm       21: #include <stdlib.h>
1.1       nicm       22:
                     23: #include "tmux.h"
                     24:
                     25: /*
1.3     ! nicm       26:  * The window layout is a tree of cells each of which can be one of: a
        !            27:  * left-right container for a list of cells, a top-bottom container for a list
        !            28:  * of cells, or a container for a window pane.
1.1       nicm       29:  *
1.3     ! nicm       30:  * Each window has a pointer to the root of its layout tree (containing its
        !            31:  * panes), every pane has a pointer back to the cell containing it, and each
        !            32:  * cell a pointer to its parent cell.
1.1       nicm       33:  */
                     34:
1.3     ! nicm       35: int    layout_resize_pane_grow(struct layout_cell *, enum layout_type, int);
        !            36: int    layout_resize_pane_shrink(struct layout_cell *, enum layout_type, int);
1.1       nicm       37:
1.3     ! nicm       38: struct layout_cell *
        !            39: layout_create_cell(struct layout_cell *lcparent)
1.1       nicm       40: {
1.3     ! nicm       41:        struct layout_cell      *lc;
        !            42:
        !            43:        lc = xmalloc(sizeof *lc);
        !            44:        lc->type = LAYOUT_WINDOWPANE;
        !            45:        lc->parent = lcparent;
        !            46:
        !            47:        TAILQ_INIT(&lc->cells);
        !            48:
        !            49:        lc->sx = UINT_MAX;
        !            50:        lc->sy = UINT_MAX;
        !            51:
        !            52:        lc->xoff = UINT_MAX;
        !            53:        lc->yoff = UINT_MAX;
        !            54:
        !            55:        lc->wp = NULL;
        !            56:
        !            57:        return (lc);
1.1       nicm       58: }
                     59:
1.3     ! nicm       60: void
        !            61: layout_free_cell(struct layout_cell *lc)
1.1       nicm       62: {
1.3     ! nicm       63:        struct layout_cell      *lcchild;
1.1       nicm       64:
1.3     ! nicm       65:        switch (lc->type) {
        !            66:        case LAYOUT_LEFTRIGHT:
        !            67:        case LAYOUT_TOPBOTTOM:
        !            68:                while (!TAILQ_EMPTY(&lc->cells)) {
        !            69:                        lcchild = TAILQ_FIRST(&lc->cells);
        !            70:                        TAILQ_REMOVE(&lc->cells, lcchild, entry);
        !            71:                        layout_free_cell(lcchild);
1.1       nicm       72:                }
1.3     ! nicm       73:                break;
        !            74:        case LAYOUT_WINDOWPANE:
        !            75:                if (lc->wp != NULL)
        !            76:                        lc->wp->layout_cell = NULL;
        !            77:                break;
1.1       nicm       78:        }
                     79:
1.3     ! nicm       80:        xfree(lc);
1.1       nicm       81: }
                     82:
1.3     ! nicm       83: void
        !            84: layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
1.1       nicm       85: {
1.3     ! nicm       86:        struct layout_cell      *lcchild;
1.1       nicm       87:
1.3     ! nicm       88:        log_debug(
        !            89:            "%s:%*s%p type %u [parent %p] wp=%p [%u,%u %ux%u]", hdr, n, " ", lc,
        !            90:            lc->type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx, lc->sy);
        !            91:        switch (lc->type) {
        !            92:        case LAYOUT_LEFTRIGHT:
        !            93:        case LAYOUT_TOPBOTTOM:
        !            94:                TAILQ_FOREACH(lcchild, &lc->cells, entry)
        !            95:                        layout_print_cell(lcchild, hdr, n + 1);
        !            96:                break;
        !            97:        case LAYOUT_WINDOWPANE:
        !            98:                break;
        !            99:        }
1.1       nicm      100: }
                    101:
                    102: void
1.3     ! nicm      103: layout_set_size(
        !           104:     struct layout_cell *lc, u_int sx, u_int sy, u_int xoff, u_int yoff)
1.1       nicm      105: {
1.3     ! nicm      106:        lc->sx = sx;
        !           107:        lc->sy = sy;
        !           108:
        !           109:        lc->xoff = xoff;
        !           110:        lc->yoff = yoff;
1.1       nicm      111: }
                    112:
                    113: void
1.3     ! nicm      114: layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
1.1       nicm      115: {
1.3     ! nicm      116:        lc->type = LAYOUT_WINDOWPANE;
        !           117:
        !           118:        TAILQ_INIT(&lc->cells);
        !           119:
        !           120:        wp->layout_cell = lc;
        !           121:        lc->wp = wp;
1.1       nicm      122: }
                    123:
                    124: void
1.3     ! nicm      125: layout_make_node(struct layout_cell *lc, enum layout_type type)
1.1       nicm      126: {
1.3     ! nicm      127:        if (type == LAYOUT_WINDOWPANE)
        !           128:                fatalx("bad layout type");
        !           129:        lc->type = type;
        !           130:
        !           131:        TAILQ_INIT(&lc->cells);
        !           132:
        !           133:        if (lc->wp != NULL)
        !           134:                lc->wp->layout_cell = NULL;
        !           135:        lc->wp = NULL;
1.1       nicm      136: }
                    137:
1.3     ! nicm      138: /* Fix cell offsets based on their sizes. */
        !           139: void
        !           140: layout_fix_offsets(struct layout_cell *lc)
1.1       nicm      141: {
1.3     ! nicm      142:        struct layout_cell      *lcchild;
        !           143:        u_int                    xoff, yoff;
1.1       nicm      144:
1.3     ! nicm      145:        if (lc->type == LAYOUT_LEFTRIGHT) {
        !           146:                xoff = lc->xoff;
        !           147:                TAILQ_FOREACH(lcchild, &lc->cells, entry) {
        !           148:                        lcchild->xoff = xoff;
        !           149:                        lcchild->yoff = lc->yoff;
        !           150:                        if (lcchild->type != LAYOUT_WINDOWPANE)
        !           151:                                layout_fix_offsets(lcchild);
        !           152:                        xoff += lcchild->sx + 1;
        !           153:                }
        !           154:        } else {
        !           155:                yoff = lc->yoff;
        !           156:                TAILQ_FOREACH(lcchild, &lc->cells, entry) {
        !           157:                        lcchild->xoff = lc->xoff;
        !           158:                        lcchild->yoff = yoff;
        !           159:                        if (lcchild->type != LAYOUT_WINDOWPANE)
        !           160:                                layout_fix_offsets(lcchild);
        !           161:                        yoff += lcchild->sy + 1;
        !           162:                }
        !           163:        }
1.1       nicm      164: }
                    165:
1.3     ! nicm      166: /* Update pane offsets and sizes based on their cells. */
1.1       nicm      167: void
1.3     ! nicm      168: layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
1.1       nicm      169: {
                    170:        struct window_pane      *wp;
1.3     ! nicm      171:        struct layout_cell      *lc;
        !           172:        u_int                    sx, sy;
1.1       nicm      173:
                    174:        TAILQ_FOREACH(wp, &w->panes, entry) {
1.3     ! nicm      175:                if ((lc = wp->layout_cell) == NULL)
        !           176:                        continue;
        !           177:                wp->xoff = lc->xoff;
        !           178:                wp->yoff = lc->yoff;
        !           179:
        !           180:                /*
        !           181:                 * Layout cells are limited by the smallest size of other cells
        !           182:                 * within the same row or column; if this isn't the case
        !           183:                 * resizing becomes difficult.
        !           184:                 *
        !           185:                 * However, panes do not have to take up their entire cell, so
        !           186:                 * they can be cropped to the window edge if the layout
        !           187:                 * overflows and they are partly visible.
        !           188:                 *
        !           189:                 * This stops cells being hidden unnecessarily.
        !           190:                 */
        !           191:
        !           192:                /*
        !           193:                 * Work out the horizontal size. If the pane is actually
        !           194:                 * outside the window or the entire pane is already visible,
        !           195:                 * don't crop.
        !           196:                 */
        !           197:                if (lc->xoff >= wsx || lc->xoff + lc->sx < wsx)
        !           198:                        sx = lc->sx;
        !           199:                else {
        !           200:                        sx = wsx - lc->xoff;
        !           201:                        if (sx < 1)
        !           202:                                sx = lc->sx;
        !           203:                }
        !           204:
        !           205:                /*
        !           206:                 * Similarly for the vertical size; the minimum vertical size
        !           207:                 * is two because scroll regions cannot be one line.
        !           208:                 */
        !           209:                if (lc->yoff >= wsy || lc->yoff + lc->sy < wsy)
        !           210:                        sy = lc->sy;
1.2       nicm      211:                else {
1.3     ! nicm      212:                        sy = wsy - lc->yoff;
        !           213:                        if (sy < 2)
        !           214:                                sy = lc->sy;
1.2       nicm      215:                }
1.3     ! nicm      216:
        !           217:                window_pane_resize(wp, sx, sy);
1.1       nicm      218:        }
                    219: }
                    220:
1.3     ! nicm      221: /* Calculate how much size is available to be removed from a cell. */
        !           222: u_int
        !           223: layout_resize_check(struct layout_cell *lc, enum layout_type type)
1.1       nicm      224: {
1.3     ! nicm      225:        struct layout_cell      *lcchild;
        !           226:        u_int                    available, minimum;
1.1       nicm      227:
1.3     ! nicm      228:        if (lc->type == LAYOUT_WINDOWPANE) {
        !           229:                /* Space available in this cell only. */
        !           230:                if (type == LAYOUT_LEFTRIGHT)
        !           231:                        available = lc->sx;
        !           232:                else
        !           233:                        available = lc->sy;
        !           234:
        !           235:                if (available > PANE_MINIMUM)
        !           236:                        available -= PANE_MINIMUM;
        !           237:                else
        !           238:                        available = 0;
        !           239:        } else if (lc->type == type) {
        !           240:                /* Same type: total of available space in all child cells. */
        !           241:                available = 0;
        !           242:                TAILQ_FOREACH(lcchild, &lc->cells, entry)
        !           243:                        available += layout_resize_check(lcchild, type);
        !           244:        } else {
        !           245:                /* Different type: minimum of available space in child cells. */
        !           246:                minimum = UINT_MAX;
        !           247:                TAILQ_FOREACH(lcchild, &lc->cells, entry) {
        !           248:                        available = layout_resize_check(lcchild, type);
        !           249:                        if (available < minimum)
        !           250:                                minimum = available;
        !           251:                }
        !           252:                available = minimum;
1.2       nicm      253:        }
                    254:
1.3     ! nicm      255:        return (available);
        !           256: }
1.1       nicm      257:
1.3     ! nicm      258: /*
        !           259:  * Adjust cell size evenly, including altering its children. This function
        !           260:  * expects the change to have already been bounded to the space available.
        !           261:  */
        !           262: void
        !           263: layout_resize_adjust(struct layout_cell *lc, enum layout_type type, int change)
        !           264: {
        !           265:        struct layout_cell      *lcchild;
1.1       nicm      266:
1.3     ! nicm      267:        /* Adjust the cell size. */
        !           268:        if (type == LAYOUT_LEFTRIGHT)
        !           269:                lc->sx += change;
        !           270:        else
        !           271:                lc->sy += change;
        !           272:
        !           273:        /* If this is a leaf cell, that is all that is necessary. */
        !           274:        if (type == LAYOUT_WINDOWPANE)
        !           275:                return;
        !           276:
        !           277:        /* Child cell runs in a different direction. */
        !           278:        if (lc->type != type) {
        !           279:                TAILQ_FOREACH(lcchild, &lc->cells, entry)
        !           280:                        layout_resize_adjust(lcchild, type, change);
        !           281:                return;
1.1       nicm      282:        }
                    283:
1.3     ! nicm      284:        /*
        !           285:         * Child cell runs in the same direction. Adjust each child equally
        !           286:         * until no further change is possible.
        !           287:         */
        !           288:        while (change != 0) {
        !           289:                TAILQ_FOREACH(lcchild, &lc->cells, entry) {
        !           290:                        if (change == 0)
        !           291:                                break;
        !           292:                        if (change > 0) {
        !           293:                                layout_resize_adjust(lcchild, type, 1);
        !           294:                                change--;
        !           295:                                continue;
        !           296:                        }
        !           297:                        if (layout_resize_check(lcchild, type) > 0) {
        !           298:                                layout_resize_adjust(lcchild, type, -1);
        !           299:                                change++;
        !           300:                        }
        !           301:                }
1.1       nicm      302:        }
                    303: }
                    304:
                    305: void
1.3     ! nicm      306: layout_init(struct window *w)
1.1       nicm      307: {
1.3     ! nicm      308:        struct layout_cell      *lc;
1.1       nicm      309:
1.3     ! nicm      310:        lc = w->layout_root = layout_create_cell(NULL);
        !           311:        layout_set_size(lc, w->sx, w->sy, 0, 0);
        !           312:        layout_make_leaf(lc, TAILQ_FIRST(&w->panes));
1.1       nicm      313:
1.3     ! nicm      314:        layout_fix_panes(w, w->sx, w->sy);
        !           315: }
1.2       nicm      316:
1.3     ! nicm      317: void
        !           318: layout_free(struct window *w)
        !           319: {
        !           320:        layout_free_cell(w->layout_root);
        !           321: }
1.1       nicm      322:
1.3     ! nicm      323: /* Resize the entire layout after window resize. */
        !           324: void
        !           325: layout_resize(struct window *w, u_int sx, u_int sy)
        !           326: {
        !           327:        struct layout_cell      *lc = w->layout_root;
        !           328:        int                      xlimit, ylimit, xchange, ychange;
1.1       nicm      329:
1.3     ! nicm      330:        /*
        !           331:         * Adjust horizontally. Do not attempt to reduce the layout lower than
        !           332:         * the minimum (more than the amount returned by layout_resize_check).
        !           333:         *
        !           334:         * This can mean that the window size is smaller than the total layout
        !           335:         * size: redrawing this is handled at a higher level, but it does leave
        !           336:         * a problem with growing the window size here: if the current size is
        !           337:         * < the minimum, growing proportionately by adding to each pane is
        !           338:         * wrong as it would keep the layout size larger than the window size.
        !           339:         * Instead, spread the difference between the minimum and the new size
        !           340:         * out proportionately - this should leave the layout fitting the new
        !           341:         * window size.
        !           342:         */
        !           343:        xchange = sx - w->sx;
        !           344:        xlimit = layout_resize_check(lc, LAYOUT_LEFTRIGHT);
        !           345:        if (xchange < 0 && xchange < -xlimit)
        !           346:                xchange = -xlimit;
        !           347:        if (xlimit == 0) {
        !           348:                if (sx <= lc->sx)       /* lc->sx is minimum possible */
        !           349:                        xchange = 0;
1.1       nicm      350:                else
1.3     ! nicm      351:                        xchange = sx - lc->sx;
1.1       nicm      352:        }
1.3     ! nicm      353:        if (xchange != 0)
        !           354:                layout_resize_adjust(lc, LAYOUT_LEFTRIGHT, xchange);
1.1       nicm      355:
1.3     ! nicm      356:        /* Adjust vertically in a similar fashion. */
        !           357:        ychange = sy - w->sy;
        !           358:        ylimit = layout_resize_check(lc, LAYOUT_TOPBOTTOM);
        !           359:        if (ychange < 0 && ychange < -ylimit)
        !           360:                ychange = -ylimit;
        !           361:        if (ylimit == 0) {
        !           362:                if (sy <= lc->sy)       /* lc->sy is minimum possible */
        !           363:                        ychange = 0;
        !           364:                else
        !           365:                        ychange = sy - lc->sy;
1.1       nicm      366:        }
1.3     ! nicm      367:        if (ychange != 0)
        !           368:                layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, ychange);
        !           369:
        !           370:        /* Fix cell offsets. */
        !           371:        layout_fix_offsets(lc);
        !           372:        layout_fix_panes(w, sx, sy);
1.1       nicm      373: }
                    374:
1.3     ! nicm      375: /* Resize a single pane within the layout. */
1.1       nicm      376: void
1.3     ! nicm      377: layout_resize_pane(struct window_pane *wp, enum layout_type type, int change)
1.1       nicm      378: {
1.3     ! nicm      379:        struct layout_cell     *lc, *lcparent;
        !           380:        int                     needed, size;
1.1       nicm      381:
1.3     ! nicm      382:        lc = wp->layout_cell;
1.1       nicm      383:
1.3     ! nicm      384:        /* Find next parent of the same type. */
        !           385:        lcparent = lc->parent;
        !           386:        while (lcparent != NULL && lcparent->type != type) {
        !           387:                lc = lcparent;
        !           388:                lcparent = lc->parent;
        !           389:        }
        !           390:        if (lcparent == NULL)
        !           391:                return;
        !           392:
        !           393:        /* If this is the last cell, move back one. */
        !           394:        if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
        !           395:                lc = TAILQ_PREV(lc, layout_cells, entry);
        !           396:
        !           397:        /* Grow or shrink the cell. */
        !           398:        needed = change;
        !           399:        while (needed != 0) {
        !           400:                if (change > 0) {
        !           401:                        size = layout_resize_pane_grow(lc, type, needed);
        !           402:                        needed -= size;
        !           403:                } else {
        !           404:                        size = layout_resize_pane_shrink(lc, type, needed);
        !           405:                        needed += size;
        !           406:                }
1.1       nicm      407:
1.3     ! nicm      408:                if (size == 0)  /* no more change possible */
        !           409:                        break;
        !           410:        }
        !           411:
        !           412:        /* Fix cell offsets. */
        !           413:        layout_fix_offsets(wp->window->layout_root);
        !           414:        layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
        !           415: }
1.1       nicm      416:
1.3     ! nicm      417: int
        !           418: layout_resize_pane_grow(
        !           419:     struct layout_cell *lc, enum layout_type type, int needed)
        !           420: {
        !           421:        struct layout_cell      *lcadd, *lcremove;
        !           422:        u_int                    size;
        !           423:
        !           424:        /* Growing. Always add to the current cell. */
        !           425:        lcadd = lc;
        !           426:
        !           427:        /* Look towards the tail for a suitable cell for reduction. */
        !           428:        lcremove = TAILQ_NEXT(lc, entry);
        !           429:        while (lcremove != NULL) {
        !           430:                size = layout_resize_check(lcremove, type);
        !           431:                if (size > 0)
        !           432:                        break;
        !           433:                lcremove = TAILQ_NEXT(lcremove, entry);
1.1       nicm      434:        }
                    435:
1.3     ! nicm      436:        /* If none found, look towards the head. */
        !           437:        if (lcremove == NULL) {
        !           438:                lcremove = TAILQ_PREV(lc, layout_cells, entry);
        !           439:                while (lcremove != NULL) {
        !           440:                        size = layout_resize_check(lcremove, type);
        !           441:                        if (size > 0)
        !           442:                                break;
        !           443:                        lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
1.1       nicm      444:                }
1.3     ! nicm      445:                if (lcremove == NULL)
        !           446:                        return (0);
        !           447:        }
1.1       nicm      448:
1.3     ! nicm      449:        /* Change the cells. */
        !           450:        if (size > (u_int) needed)
        !           451:                size = needed;
        !           452:        layout_resize_adjust(lcadd, type, size);
        !           453:        layout_resize_adjust(lcremove, type, -size);
        !           454:        return (size);
        !           455: }
1.1       nicm      456:
1.3     ! nicm      457: int
        !           458: layout_resize_pane_shrink(
        !           459:     struct layout_cell *lc, enum layout_type type, int needed)
        !           460: {
        !           461:        struct layout_cell      *lcadd, *lcremove;
        !           462:        u_int                    size;
1.1       nicm      463:
1.3     ! nicm      464:        /* Shrinking. Find cell to remove from by walking towards head. */
        !           465:        lcremove = lc;
        !           466:        do {
        !           467:                size = layout_resize_check(lcremove, type);
        !           468:                if (size != 0)
1.1       nicm      469:                        break;
1.3     ! nicm      470:                lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
        !           471:        } while (lcremove != NULL);
        !           472:        if (lcremove == NULL)
        !           473:                return (0);
        !           474:
        !           475:        /* And add onto the next cell (from the original cell). */
        !           476:        lcadd = TAILQ_NEXT(lc, entry);
        !           477:        if (lcadd == NULL)
        !           478:                return (0);
        !           479:
        !           480:        /* Change the cells. */
        !           481:        if (size > (u_int) -needed)
        !           482:                size = -needed;
        !           483:        layout_resize_adjust(lcadd, type, size);
        !           484:        layout_resize_adjust(lcremove, type, -size);
        !           485:        return (size);
1.1       nicm      486: }
                    487:
1.3     ! nicm      488: /* Split a pane into two. size is a hint, or -1 for default half/half split. */
        !           489: int
        !           490: layout_split_pane(struct window_pane *wp,
        !           491:     enum layout_type type, int size, struct window_pane *new_wp)
1.1       nicm      492: {
1.3     ! nicm      493:        struct layout_cell     *lc, *lcparent, *lcnew;
        !           494:        u_int                   sx, sy, xoff, yoff, size1, size2;
1.1       nicm      495:
1.3     ! nicm      496:        lc = wp->layout_cell;
1.1       nicm      497:
1.3     ! nicm      498:        /* Copy the old cell size. */
        !           499:        sx = lc->sx;
        !           500:        sy = lc->sy;
        !           501:        xoff = lc->xoff;
        !           502:        yoff = lc->yoff;
        !           503:
        !           504:        /* Check there is enough space for the two new panes. */
        !           505:        switch (type) {
        !           506:        case LAYOUT_LEFTRIGHT:
        !           507:                if (sx < PANE_MINIMUM * 2 + 1)
        !           508:                        return (-1);
        !           509:                break;
        !           510:        case LAYOUT_TOPBOTTOM:
        !           511:                if (sy < PANE_MINIMUM * 2 + 1)
        !           512:                        return (-1);
        !           513:                break;
        !           514:        default:
        !           515:                fatalx("bad layout type");
        !           516:        }
        !           517:
        !           518:        if (lc->parent != NULL && lc->parent->type == type) {
        !           519:                /*
        !           520:                 * If the parent exists and is of the same type as the split,
        !           521:                 * create a new cell and insert it after this one.
        !           522:                 */
        !           523:
        !           524:                /* Create the new child cell. */
        !           525:                lcnew = layout_create_cell(lc->parent);
        !           526:                TAILQ_INSERT_AFTER(&lc->parent->cells, lc, lcnew, entry);
        !           527:        } else {
        !           528:                /*
        !           529:                 * Otherwise create a new parent and insert it.
        !           530:                 */
        !           531:
        !           532:                /* Create and insert the replacement parent. */
        !           533:                lcparent = layout_create_cell(lc->parent);
        !           534:                layout_make_node(lcparent, type);
        !           535:                layout_set_size(lcparent, sx, sy, xoff, yoff);
        !           536:                if (lc->parent == NULL)
        !           537:                        wp->window->layout_root = lcparent;
        !           538:                else
        !           539:                        TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry);
        !           540:
        !           541:                /* Insert the old cell. */
        !           542:                lc->parent = lcparent;
        !           543:                TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
        !           544:
        !           545:                /* Create the new child cell. */
        !           546:                lcnew = layout_create_cell(lcparent);
        !           547:                TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry);
        !           548:        }
        !           549:
        !           550:        /* Set new cell sizes.  size is the target size or -1 for middle split,
        !           551:         * size1 is the size of the top/left and size2 the bottom/right.
        !           552:         */
        !           553:        switch (type) {
        !           554:        case LAYOUT_LEFTRIGHT:
        !           555:                if (size < 0)
        !           556:                        size2 = ((sx + 1) / 2) - 1;
        !           557:                else
        !           558:                        size2 = size;
        !           559:                if (size2 < PANE_MINIMUM)
        !           560:                        size2 = PANE_MINIMUM;
        !           561:                else if (size2 > sx - 2)
        !           562:                        size2 = sx - 2;
        !           563:                size1 = sx - 1 - size2;
        !           564:                layout_set_size(lc, size1, sy, xoff, yoff);
        !           565:                layout_set_size(lcnew, size2, sy, xoff + lc->sx + 1, yoff);
        !           566:                break;
        !           567:        case LAYOUT_TOPBOTTOM:
        !           568:                if (size < 0)
        !           569:                        size2 = ((sy + 1) / 2) - 1;
        !           570:                else
        !           571:                        size2 = size;
        !           572:                if (size2 < PANE_MINIMUM)
        !           573:                        size2 = PANE_MINIMUM;
        !           574:                else if (size2 > sy - 2)
        !           575:                        size2 = sy - 2;
        !           576:                size1 = sy - 1 - size2;
        !           577:                layout_set_size(lc, sx, size1, xoff, yoff);
        !           578:                layout_set_size(lcnew, sx, size2, xoff, yoff + lc->sy + 1);
        !           579:                break;
        !           580:        default:
        !           581:                fatalx("bad layout type");
        !           582:        }
        !           583:
        !           584:        /* Assign the panes. */
        !           585:        layout_make_leaf(lc, wp);
        !           586:        layout_make_leaf(lcnew, new_wp);
1.1       nicm      587:
1.3     ! nicm      588:        /* Fix pane offsets and sizes. */
        !           589:        layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
1.1       nicm      590:
1.3     ! nicm      591:        return (0);
        !           592: }
1.1       nicm      593:
1.3     ! nicm      594: /* Destroy the layout associated with a pane and redistribute the space. */
        !           595: void
        !           596: layout_close_pane(struct window_pane *wp)
        !           597: {
        !           598:        struct layout_cell     *lc, *lcother, *lcparent;
1.1       nicm      599:
1.3     ! nicm      600:        lc = wp->layout_cell;
        !           601:        lcparent = lc->parent;
1.1       nicm      602:
1.3     ! nicm      603:        /*
        !           604:         * If no parent, this is the last pane so window close is imminent and
        !           605:         * there is no need to resize anything.
        !           606:         */
        !           607:        if (lcparent == NULL) {
        !           608:                layout_free_cell(lc);
        !           609:                wp->window->layout_root = NULL;
        !           610:                return;
        !           611:        }
1.1       nicm      612:
1.3     ! nicm      613:        /* Merge the space into the previous or next cell. */
        !           614:        if (lc == TAILQ_FIRST(&lcparent->cells))
        !           615:                lcother = TAILQ_NEXT(lc, entry);
        !           616:        else
        !           617:                lcother = TAILQ_PREV(lc, layout_cells, entry);
        !           618:        if (lcparent->type == LAYOUT_LEFTRIGHT)
        !           619:                layout_resize_adjust(lcother, lcparent->type, lc->sx + 1);
        !           620:        else
        !           621:                layout_resize_adjust(lcother, lcparent->type, lc->sy + 1);
1.1       nicm      622:
1.3     ! nicm      623:        /* Remove this from the parent's list. */
        !           624:        TAILQ_REMOVE(&lcparent->cells, lc, entry);
        !           625:        layout_free_cell(lc);
        !           626:
        !           627:        /*
        !           628:         * If the parent now has one cell, remove the parent from the tree and
        !           629:         * replace it by that cell.
        !           630:         */
        !           631:        lc = TAILQ_FIRST(&lcparent->cells);
        !           632:        if (TAILQ_NEXT(lc, entry) == NULL) {
        !           633:                TAILQ_REMOVE(&lcparent->cells, lc, entry);
        !           634:
        !           635:                lc->parent = lcparent->parent;
        !           636:                if (lc->parent == NULL) {
        !           637:                        lc->xoff = 0; lc->yoff = 0;
        !           638:                        wp->window->layout_root = lc;
        !           639:                } else
        !           640:                        TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
        !           641:
        !           642:                layout_free_cell(lcparent);
        !           643:        }
        !           644:
        !           645:        /* Fix pane offsets and sizes. */
        !           646:        layout_fix_offsets(wp->window->layout_root);
        !           647:        layout_fix_panes(wp->window, wp->window->sx, wp->window->sy);
1.1       nicm      648: }
1.3     ! nicm      649: