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

Annotation of src/usr.bin/tmux/layout-set.c, Revision 1.29

1.29    ! nicm        1: /* $OpenBSD: layout-set.c,v 1.28 2019/11/28 09:45:15 nicm Exp $ */
1.1       nicm        2:
                      3: /*
1.14      nicm        4:  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1       nicm        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.29    ! nicm       21: #include <stdlib.h>
1.1       nicm       22: #include <string.h>
                     23:
                     24: #include "tmux.h"
                     25:
                     26: /*
1.11      nicm       27:  * Set window layouts - predefined methods to arrange windows. These are
                     28:  * one-off and generate a layout tree.
1.1       nicm       29:  */
                     30:
1.16      nicm       31: static void    layout_set_even_h(struct window *);
                     32: static void    layout_set_even_v(struct window *);
                     33: static void    layout_set_main_h(struct window *);
                     34: static void    layout_set_main_v(struct window *);
                     35: static void    layout_set_tiled(struct window *);
1.1       nicm       36:
1.17      nicm       37: static const struct {
1.1       nicm       38:        const char      *name;
                     39:        void            (*arrange)(struct window *);
                     40: } layout_sets[] = {
                     41:        { "even-horizontal", layout_set_even_h },
                     42:        { "even-vertical", layout_set_even_v },
                     43:        { "main-horizontal", layout_set_main_h },
                     44:        { "main-vertical", layout_set_main_v },
1.6       nicm       45:        { "tiled", layout_set_tiled },
1.1       nicm       46: };
                     47:
                     48: int
                     49: layout_set_lookup(const char *name)
                     50: {
                     51:        u_int   i;
                     52:        int     matched = -1;
                     53:
                     54:        for (i = 0; i < nitems(layout_sets); i++) {
                     55:                if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) {
                     56:                        if (matched != -1)      /* ambiguous */
                     57:                                return (-1);
                     58:                        matched = i;
                     59:                }
                     60:        }
                     61:
                     62:        return (matched);
                     63: }
                     64:
                     65: u_int
                     66: layout_set_select(struct window *w, u_int layout)
                     67: {
                     68:        if (layout > nitems(layout_sets) - 1)
                     69:                layout = nitems(layout_sets) - 1;
                     70:
                     71:        if (layout_sets[layout].arrange != NULL)
                     72:                layout_sets[layout].arrange(w);
                     73:
1.3       nicm       74:        w->lastlayout = layout;
1.1       nicm       75:        return (layout);
                     76: }
                     77:
                     78: u_int
                     79: layout_set_next(struct window *w)
                     80: {
1.3       nicm       81:        u_int   layout;
                     82:
                     83:        if (w->lastlayout == -1)
                     84:                layout = 0;
                     85:        else {
                     86:                layout = w->lastlayout + 1;
                     87:                if (layout > nitems(layout_sets) - 1)
                     88:                        layout = 0;
                     89:        }
1.1       nicm       90:
                     91:        if (layout_sets[layout].arrange != NULL)
                     92:                layout_sets[layout].arrange(w);
1.3       nicm       93:        w->lastlayout = layout;
1.1       nicm       94:        return (layout);
                     95: }
                     96:
                     97: u_int
                     98: layout_set_previous(struct window *w)
                     99: {
1.3       nicm      100:        u_int   layout;
                    101:
                    102:        if (w->lastlayout == -1)
                    103:                layout = nitems(layout_sets) - 1;
                    104:        else {
                    105:                layout = w->lastlayout;
                    106:                if (layout == 0)
                    107:                        layout = nitems(layout_sets) - 1;
                    108:                else
                    109:                        layout--;
                    110:        }
1.1       nicm      111:
                    112:        if (layout_sets[layout].arrange != NULL)
                    113:                layout_sets[layout].arrange(w);
1.3       nicm      114:        w->lastlayout = layout;
1.1       nicm      115:        return (layout);
                    116: }
                    117:
1.16      nicm      118: static void
1.19      nicm      119: layout_set_even(struct window *w, enum layout_type type)
1.1       nicm      120: {
                    121:        struct window_pane      *wp;
                    122:        struct layout_cell      *lc, *lcnew;
1.23      nicm      123:        u_int                    n, sx, sy;
1.1       nicm      124:
                    125:        layout_print_cell(w->layout_root, __func__, 1);
                    126:
                    127:        /* Get number of panes. */
                    128:        n = window_count_panes(w);
                    129:        if (n <= 1)
                    130:                return;
                    131:
                    132:        /* Free the old root and construct a new. */
                    133:        layout_free(w);
                    134:        lc = w->layout_root = layout_create_cell(NULL);
1.23      nicm      135:        if (type == LAYOUT_LEFTRIGHT) {
                    136:                sx = (n * (PANE_MINIMUM + 1)) - 1;
                    137:                if (sx < w->sx)
                    138:                        sx = w->sx;
                    139:                sy = w->sy;
                    140:        } else {
                    141:                sy = (n * (PANE_MINIMUM + 1)) - 1;
                    142:                if (sy < w->sy)
                    143:                        sy = w->sy;
                    144:                sx = w->sx;
                    145:        }
                    146:        layout_set_size(lc, sx, sy, 0, 0);
1.19      nicm      147:        layout_make_node(lc, type);
1.1       nicm      148:
                    149:        /* Build new leaf cells. */
                    150:        TAILQ_FOREACH(wp, &w->panes, entry) {
                    151:                lcnew = layout_create_cell(lc);
                    152:                layout_make_leaf(lcnew, wp);
1.20      nicm      153:                lcnew->sx = w->sx;
                    154:                lcnew->sy = w->sy;
1.1       nicm      155:                TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
                    156:        }
                    157:
1.19      nicm      158:        /* Spread out cells. */
                    159:        layout_spread_cell(w, lc);
1.1       nicm      160:
                    161:        /* Fix cell offsets. */
1.27      nicm      162:        layout_fix_offsets(w);
1.21      nicm      163:        layout_fix_panes(w);
1.1       nicm      164:
                    165:        layout_print_cell(w->layout_root, __func__, 1);
                    166:
1.28      nicm      167:        window_resize(w, lc->sx, lc->sy, -1, -1);
1.18      nicm      168:        notify_window("window-layout-changed", w);
1.1       nicm      169:        server_redraw_window(w);
                    170: }
                    171:
1.16      nicm      172: static void
1.19      nicm      173: layout_set_even_h(struct window *w)
                    174: {
                    175:        layout_set_even(w, LAYOUT_LEFTRIGHT);
                    176: }
                    177:
                    178: static void
1.1       nicm      179: layout_set_even_v(struct window *w)
                    180: {
1.19      nicm      181:        layout_set_even(w, LAYOUT_TOPBOTTOM);
1.1       nicm      182: }
                    183:
1.16      nicm      184: static void
1.1       nicm      185: layout_set_main_h(struct window *w)
                    186: {
                    187:        struct window_pane      *wp;
1.24      nicm      188:        struct layout_cell      *lc, *lcmain, *lcother, *lcchild;
1.26      nicm      189:        u_int                    n, mainh, otherh, sx, sy;
1.29    ! nicm      190:        char                    *cause;
        !           191:        const char              *s;
1.1       nicm      192:
                    193:        layout_print_cell(w->layout_root, __func__, 1);
                    194:
                    195:        /* Get number of panes. */
                    196:        n = window_count_panes(w);
                    197:        if (n <= 1)
                    198:                return;
                    199:        n--;    /* take off main pane */
                    200:
1.26      nicm      201:        /* Find available height - take off one line for the border. */
                    202:        sy = w->sy - 1;
                    203:
1.29    ! nicm      204:        /* Get the main pane height. */
        !           205:        s = options_get_string(w->options, "main-pane-height");
        !           206:        mainh = args_string_percentage(s, 0, sy, sy, &cause);
        !           207:        if (cause != NULL) {
        !           208:                mainh = 24;
        !           209:                free(cause);
        !           210:        }
        !           211:
        !           212:        /* Work out the other pane height. */
1.26      nicm      213:        if (mainh + PANE_MINIMUM >= sy) {
                    214:                if (sy <= PANE_MINIMUM + PANE_MINIMUM)
1.24      nicm      215:                        mainh = PANE_MINIMUM;
1.1       nicm      216:                else
1.26      nicm      217:                        mainh = sy - PANE_MINIMUM;
1.24      nicm      218:                otherh = PANE_MINIMUM;
                    219:        } else {
1.29    ! nicm      220:                s = options_get_string(w->options, "other-pane-height");
        !           221:                otherh = args_string_percentage(s, 0, sy, sy, &cause);
        !           222:                if (cause != NULL || otherh == 0) {
1.26      nicm      223:                        otherh = sy - mainh;
1.29    ! nicm      224:                        free(cause);
        !           225:                } else if (otherh > sy || sy - otherh < mainh)
1.26      nicm      226:                        otherh = sy - mainh;
1.24      nicm      227:                else
1.26      nicm      228:                        mainh = sy - otherh;
1.24      nicm      229:        }
                    230:
1.25      nicm      231:        /* Work out what width is needed. */
1.24      nicm      232:        sx = (n * (PANE_MINIMUM + 1)) - 1;
                    233:        if (sx < w->sx)
                    234:                sx = w->sx;
1.1       nicm      235:
                    236:        /* Free old tree and create a new root. */
                    237:        layout_free(w);
                    238:        lc = w->layout_root = layout_create_cell(NULL);
1.26      nicm      239:        layout_set_size(lc, sx, mainh + otherh + 1, 0, 0);
1.1       nicm      240:        layout_make_node(lc, LAYOUT_TOPBOTTOM);
                    241:
                    242:        /* Create the main pane. */
                    243:        lcmain = layout_create_cell(lc);
1.24      nicm      244:        layout_set_size(lcmain, sx, mainh, 0, 0);
1.1       nicm      245:        layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
                    246:        TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
                    247:
1.24      nicm      248:        /* Create the other pane. */
                    249:        lcother = layout_create_cell(lc);
                    250:        layout_set_size(lcother, sx, otherh, 0, 0);
1.25      nicm      251:        if (n == 1) {
                    252:                wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
                    253:                layout_make_leaf(lcother, wp);
                    254:                TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
                    255:        } else {
                    256:                layout_make_node(lcother, LAYOUT_LEFTRIGHT);
                    257:                TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
1.1       nicm      258:
1.25      nicm      259:                /* Add the remaining panes as children. */
                    260:                TAILQ_FOREACH(wp, &w->panes, entry) {
                    261:                        if (wp == TAILQ_FIRST(&w->panes))
                    262:                                continue;
                    263:                        lcchild = layout_create_cell(lcother);
                    264:                        layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0);
                    265:                        layout_make_leaf(lcchild, wp);
                    266:                        TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
                    267:                }
                    268:                layout_spread_cell(w, lcother);
1.1       nicm      269:        }
                    270:
                    271:        /* Fix cell offsets. */
1.27      nicm      272:        layout_fix_offsets(w);
1.21      nicm      273:        layout_fix_panes(w);
1.1       nicm      274:
                    275:        layout_print_cell(w->layout_root, __func__, 1);
                    276:
1.28      nicm      277:        window_resize(w, lc->sx, lc->sy, -1, -1);
1.18      nicm      278:        notify_window("window-layout-changed", w);
1.1       nicm      279:        server_redraw_window(w);
                    280: }
                    281:
1.16      nicm      282: static void
1.1       nicm      283: layout_set_main_v(struct window *w)
                    284: {
                    285:        struct window_pane      *wp;
1.24      nicm      286:        struct layout_cell      *lc, *lcmain, *lcother, *lcchild;
1.26      nicm      287:        u_int                    n, mainw, otherw, sx, sy;
1.29    ! nicm      288:        char                    *cause;
        !           289:        const char              *s;
1.1       nicm      290:
                    291:        layout_print_cell(w->layout_root, __func__, 1);
                    292:
                    293:        /* Get number of panes. */
                    294:        n = window_count_panes(w);
                    295:        if (n <= 1)
                    296:                return;
                    297:        n--;    /* take off main pane */
                    298:
1.26      nicm      299:        /* Find available width - take off one line for the border. */
                    300:        sx = w->sx - 1;
                    301:
1.29    ! nicm      302:        /* Get the main pane width. */
        !           303:        s = options_get_string(w->options, "main-pane-width");
        !           304:        mainw = args_string_percentage(s, 0, sx, sx, &cause);
        !           305:        if (cause != NULL) {
        !           306:                mainw = 80;
        !           307:                free(cause);
        !           308:        }
        !           309:
        !           310:        /* Work out the other pane width. */
1.26      nicm      311:        if (mainw + PANE_MINIMUM >= sx) {
                    312:                if (sx <= PANE_MINIMUM + PANE_MINIMUM)
1.24      nicm      313:                        mainw = PANE_MINIMUM;
1.1       nicm      314:                else
1.26      nicm      315:                        mainw = sx - PANE_MINIMUM;
1.24      nicm      316:                otherw = PANE_MINIMUM;
                    317:        } else {
1.29    ! nicm      318:                s = options_get_string(w->options, "other-pane-width");
        !           319:                otherw = args_string_percentage(s, 0, sx, sx, &cause);
        !           320:                if (cause != NULL || otherw == 0) {
1.26      nicm      321:                        otherw = sx - mainw;
1.29    ! nicm      322:                        free(cause);
        !           323:                } else if (otherw > sx || sx - otherw < mainw)
1.26      nicm      324:                        otherw = sx - mainw;
1.24      nicm      325:                else
1.26      nicm      326:                        mainw = sx - otherw;
1.24      nicm      327:        }
                    328:
                    329:        /* Work out what height is needed. */
                    330:        sy = (n * (PANE_MINIMUM + 1)) - 1;
                    331:        if (sy < w->sy)
                    332:                sy = w->sy;
1.1       nicm      333:
                    334:        /* Free old tree and create a new root. */
                    335:        layout_free(w);
                    336:        lc = w->layout_root = layout_create_cell(NULL);
1.26      nicm      337:        layout_set_size(lc, mainw + otherw + 1, sy, 0, 0);
1.1       nicm      338:        layout_make_node(lc, LAYOUT_LEFTRIGHT);
                    339:
                    340:        /* Create the main pane. */
                    341:        lcmain = layout_create_cell(lc);
1.24      nicm      342:        layout_set_size(lcmain, mainw, sy, 0, 0);
1.1       nicm      343:        layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
                    344:        TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
                    345:
1.24      nicm      346:        /* Create the other pane. */
                    347:        lcother = layout_create_cell(lc);
                    348:        layout_set_size(lcother, otherw, sy, 0, 0);
1.25      nicm      349:        if (n == 1) {
                    350:                wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
                    351:                layout_make_leaf(lcother, wp);
                    352:                TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
                    353:        } else {
                    354:                layout_make_node(lcother, LAYOUT_TOPBOTTOM);
                    355:                TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
1.1       nicm      356:
1.25      nicm      357:                /* Add the remaining panes as children. */
                    358:                TAILQ_FOREACH(wp, &w->panes, entry) {
                    359:                        if (wp == TAILQ_FIRST(&w->panes))
                    360:                                continue;
                    361:                        lcchild = layout_create_cell(lcother);
                    362:                        layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0);
                    363:                        layout_make_leaf(lcchild, wp);
                    364:                        TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
                    365:                }
                    366:                layout_spread_cell(w, lcother);
1.6       nicm      367:        }
                    368:
                    369:        /* Fix cell offsets. */
1.27      nicm      370:        layout_fix_offsets(w);
1.21      nicm      371:        layout_fix_panes(w);
1.6       nicm      372:
                    373:        layout_print_cell(w->layout_root, __func__, 1);
                    374:
1.28      nicm      375:        window_resize(w, lc->sx, lc->sy, -1, -1);
1.18      nicm      376:        notify_window("window-layout-changed", w);
1.6       nicm      377:        server_redraw_window(w);
                    378: }
                    379:
                    380: void
                    381: layout_set_tiled(struct window *w)
                    382: {
                    383:        struct window_pane      *wp;
                    384:        struct layout_cell      *lc, *lcrow, *lcchild;
1.23      nicm      385:        u_int                    n, width, height, used, sx, sy;
1.6       nicm      386:        u_int                    i, j, columns, rows;
                    387:
                    388:        layout_print_cell(w->layout_root, __func__, 1);
                    389:
                    390:        /* Get number of panes. */
                    391:        n = window_count_panes(w);
                    392:        if (n <= 1)
                    393:                return;
                    394:
                    395:        /* How many rows and columns are wanted? */
                    396:        rows = columns = 1;
                    397:        while (rows * columns < n) {
                    398:                rows++;
                    399:                if (rows * columns < n)
                    400:                        columns++;
                    401:        }
                    402:
                    403:        /* What width and height should they be? */
1.7       nicm      404:        width = (w->sx - (columns - 1)) / columns;
                    405:        if (width < PANE_MINIMUM)
                    406:                width = PANE_MINIMUM;
                    407:        height = (w->sy - (rows - 1)) / rows;
                    408:        if (height < PANE_MINIMUM)
                    409:                height = PANE_MINIMUM;
1.6       nicm      410:
                    411:        /* Free old tree and create a new root. */
                    412:        layout_free(w);
                    413:        lc = w->layout_root = layout_create_cell(NULL);
1.23      nicm      414:        sx = ((width + 1) * columns) - 1;
                    415:        if (sx < w->sx)
                    416:                sx = w->sx;
                    417:        sy = ((height + 1) * rows) - 1;
                    418:        if (sy < w->sy)
                    419:                sy = w->sy;
                    420:        layout_set_size(lc, sx, sy, 0, 0);
1.6       nicm      421:        layout_make_node(lc, LAYOUT_TOPBOTTOM);
                    422:
                    423:        /* Create a grid of the cells. */
                    424:        wp = TAILQ_FIRST(&w->panes);
                    425:        for (j = 0; j < rows; j++) {
                    426:                /* If this is the last cell, all done. */
                    427:                if (wp == NULL)
                    428:                        break;
                    429:
                    430:                /* Create the new row. */
                    431:                lcrow = layout_create_cell(lc);
1.7       nicm      432:                layout_set_size(lcrow, w->sx, height, 0, 0);
1.6       nicm      433:                TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
                    434:
                    435:                /* If only one column, just use the row directly. */
1.9       nicm      436:                if (n - (j * columns) == 1 || columns == 1) {
1.6       nicm      437:                        layout_make_leaf(lcrow, wp);
                    438:                        wp = TAILQ_NEXT(wp, entry);
                    439:                        continue;
                    440:                }
                    441:
                    442:                /* Add in the columns. */
                    443:                layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
                    444:                for (i = 0; i < columns; i++) {
                    445:                        /* Create and add a pane cell. */
                    446:                        lcchild = layout_create_cell(lcrow);
1.7       nicm      447:                        layout_set_size(lcchild, width, height, 0, 0);
1.6       nicm      448:                        layout_make_leaf(lcchild, wp);
                    449:                        TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
                    450:
                    451:                        /* Move to the next cell. */
                    452:                        if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
                    453:                                break;
                    454:                }
                    455:
                    456:                /*
                    457:                 * Adjust the row and columns to fit the full width if
                    458:                 * necessary.
                    459:                 */
                    460:                if (i == columns)
                    461:                        i--;
1.7       nicm      462:                used = ((i + 1) * (width + 1)) - 1;
1.6       nicm      463:                if (w->sx <= used)
                    464:                        continue;
                    465:                lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
1.15      nicm      466:                layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
                    467:                    w->sx - used);
1.6       nicm      468:        }
                    469:
                    470:        /* Adjust the last row height to fit if necessary. */
1.7       nicm      471:        used = (rows * height) + rows - 1;
1.6       nicm      472:        if (w->sy > used) {
                    473:                lcrow = TAILQ_LAST(&lc->cells, layout_cells);
1.15      nicm      474:                layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
                    475:                    w->sy - used);
1.1       nicm      476:        }
                    477:
                    478:        /* Fix cell offsets. */
1.27      nicm      479:        layout_fix_offsets(w);
1.21      nicm      480:        layout_fix_panes(w);
1.1       nicm      481:
                    482:        layout_print_cell(w->layout_root, __func__, 1);
                    483:
1.28      nicm      484:        window_resize(w, lc->sx, lc->sy, -1, -1);
1.18      nicm      485:        notify_window("window-layout-changed", w);
1.1       nicm      486:        server_redraw_window(w);
                    487: }