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

Annotation of src/usr.bin/tmux/window-tree.c, Revision 1.15

1.15    ! nicm        1: /* $OpenBSD: window-tree.c,v 1.14 2017/07/28 10:59:58 nicm Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
                      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:
                     21: #include <stdlib.h>
                     22: #include <string.h>
                     23:
                     24: #include "tmux.h"
                     25:
                     26: static struct screen   *window_tree_init(struct window_pane *,
                     27:                             struct cmd_find_state *, struct args *);
                     28: static void             window_tree_free(struct window_pane *);
                     29: static void             window_tree_resize(struct window_pane *, u_int, u_int);
                     30: static void             window_tree_key(struct window_pane *,
                     31:                             struct client *, struct session *, key_code,
                     32:                             struct mouse_event *);
                     33:
                     34: #define WINDOW_TREE_DEFAULT_COMMAND "switch-client -t '%%'"
                     35:
1.15    ! nicm       36: #define WINDOW_TREE_DEFAULT_FORMAT \
        !            37:        "#{?pane_format," \
        !            38:                "#{pane_current_command} \"#{pane_title}\"" \
        !            39:        "," \
        !            40:                "#{?window_format," \
        !            41:                        "#{window_name}#{window_flags} " \
        !            42:                        "(#{window_panes} panes)" \
        !            43:                        "#{?#{==:#{window_panes},1}, \"#{pane_title}\",}" \
        !            44:                "," \
        !            45:                        "#{session_windows} windows" \
        !            46:                        "#{?session_grouped, (group ,}" \
        !            47:                        "#{session_group}#{?session_grouped,),}" \
        !            48:                        "#{?session_attached, (attached),}" \
        !            49:                "}" \
        !            50:        "}"
        !            51:
1.1       nicm       52: const struct window_mode window_tree_mode = {
                     53:        .name = "tree-mode",
                     54:
                     55:        .init = window_tree_init,
                     56:        .free = window_tree_free,
                     57:        .resize = window_tree_resize,
                     58:        .key = window_tree_key,
                     59: };
                     60:
                     61: enum window_tree_sort_type {
                     62:        WINDOW_TREE_BY_INDEX,
                     63:        WINDOW_TREE_BY_NAME,
                     64:        WINDOW_TREE_BY_TIME,
                     65: };
                     66: static const char *window_tree_sort_list[] = {
                     67:        "index",
                     68:        "name",
                     69:        "time"
                     70: };
                     71:
                     72: enum window_tree_type {
                     73:        WINDOW_TREE_NONE,
                     74:        WINDOW_TREE_SESSION,
                     75:        WINDOW_TREE_WINDOW,
                     76:        WINDOW_TREE_PANE,
                     77: };
                     78:
                     79: struct window_tree_itemdata {
                     80:        enum window_tree_type   type;
                     81:        int                     session;
                     82:        int                     winlink;
                     83:        int                     pane;
                     84: };
                     85:
                     86: struct window_tree_modedata {
                     87:        struct window_pane               *wp;
                     88:        int                               dead;
                     89:        int                               references;
                     90:
                     91:        struct mode_tree_data            *data;
1.15    ! nicm       92:        char                             *format;
1.1       nicm       93:        char                             *command;
                     94:
                     95:        struct window_tree_itemdata     **item_list;
                     96:        u_int                             item_size;
                     97:
                     98:        struct client                    *client;
                     99:        const char                       *entered;
                    100:
                    101:        struct cmd_find_state             fs;
                    102:        enum window_tree_type             type;
1.11      nicm      103:
                    104:        int                               offset;
1.1       nicm      105: };
                    106:
                    107: static void
                    108: window_tree_pull_item(struct window_tree_itemdata *item, struct session **sp,
                    109:     struct winlink **wlp, struct window_pane **wp)
                    110: {
                    111:        *wp = NULL;
                    112:        *wlp = NULL;
                    113:        *sp = session_find_by_id(item->session);
                    114:        if (*sp == NULL)
                    115:                return;
                    116:        if (item->type == WINDOW_TREE_SESSION) {
                    117:                *wlp = (*sp)->curw;
                    118:                *wp = (*wlp)->window->active;
                    119:                return;
                    120:        }
                    121:
                    122:        *wlp = winlink_find_by_index(&(*sp)->windows, item->winlink);
                    123:        if (*wlp == NULL) {
                    124:                *sp = NULL;
                    125:                return;
                    126:        }
                    127:        if (item->type == WINDOW_TREE_WINDOW) {
                    128:                *wp = (*wlp)->window->active;
                    129:                return;
                    130:        }
                    131:
                    132:        *wp = window_pane_find_by_id(item->pane);
                    133:        if (!window_has_pane((*wlp)->window, *wp))
                    134:                *wp = NULL;
                    135:        if (*wp == NULL) {
                    136:                *sp = NULL;
                    137:                *wlp = NULL;
                    138:                return;
                    139:        }
                    140: }
                    141:
                    142: static struct window_tree_itemdata *
                    143: window_tree_add_item(struct window_tree_modedata *data)
                    144: {
                    145:        struct window_tree_itemdata     *item;
                    146:
                    147:        data->item_list = xreallocarray(data->item_list, data->item_size + 1,
                    148:            sizeof *data->item_list);
                    149:        item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
                    150:        return (item);
                    151: }
                    152:
                    153: static void
                    154: window_tree_free_item(struct window_tree_itemdata *item)
                    155: {
                    156:        free(item);
                    157: }
                    158:
                    159: static int
                    160: window_tree_cmp_session_name(const void *a0, const void *b0)
                    161: {
                    162:        const struct session *const *a = a0;
                    163:        const struct session *const *b = b0;
                    164:
                    165:        return (strcmp((*a)->name, (*b)->name));
                    166: }
                    167:
                    168: static int
                    169: window_tree_cmp_session_time(const void *a0, const void *b0)
                    170: {
                    171:        const struct session *const *a = a0;
                    172:        const struct session *const *b = b0;
                    173:
                    174:        if (timercmp(&(*a)->activity_time, &(*b)->activity_time, >))
                    175:                return (-1);
                    176:        if (timercmp(&(*a)->activity_time, &(*b)->activity_time, <))
                    177:                return (1);
                    178:        return (strcmp((*a)->name, (*b)->name));
                    179: }
                    180:
                    181: static int
                    182: window_tree_cmp_window_name(const void *a0, const void *b0)
                    183: {
                    184:        const struct winlink *const *a = a0;
                    185:        const struct winlink *const *b = b0;
                    186:
                    187:        return (strcmp((*a)->window->name, (*b)->window->name));
                    188: }
                    189:
                    190: static int
                    191: window_tree_cmp_window_time(const void *a0, const void *b0)
                    192: {
                    193:        const struct winlink *const *a = a0;
                    194:        const struct winlink *const *b = b0;
                    195:
                    196:        if (timercmp(&(*a)->window->activity_time,
                    197:            &(*b)->window->activity_time, >))
                    198:                return (-1);
                    199:        if (timercmp(&(*a)->window->activity_time,
                    200:            &(*b)->window->activity_time, <))
                    201:                return (1);
                    202:        return (strcmp((*a)->window->name, (*b)->window->name));
                    203: }
                    204:
                    205: static int
                    206: window_tree_cmp_pane_time(const void *a0, const void *b0)
                    207: {
                    208:        const struct window_pane *const *a = a0;
                    209:        const struct window_pane *const *b = b0;
                    210:
                    211:        if ((*a)->active_point < (*b)->active_point)
                    212:                return (-1);
                    213:        if ((*a)->active_point > (*b)->active_point)
                    214:                return (1);
                    215:        return (0);
                    216: }
                    217:
                    218: static void
                    219: window_tree_build_pane(struct session *s, struct winlink *wl,
                    220:     struct window_pane *wp, void *modedata, struct mode_tree_item *parent)
                    221: {
                    222:        struct window_tree_modedata     *data = modedata;
                    223:        struct window_tree_itemdata     *item;
                    224:        char                            *name, *text;
                    225:        u_int                            idx;
                    226:
                    227:        window_pane_index(wp, &idx);
                    228:
                    229:        item = window_tree_add_item(data);
                    230:        item->type = WINDOW_TREE_PANE;
                    231:        item->session = s->id;
                    232:        item->winlink = wl->idx;
                    233:        item->pane = wp->id;
                    234:
1.15    ! nicm      235:        text = format_single(NULL, data->format, NULL, s, wl, wp);
1.1       nicm      236:        xasprintf(&name, "%u", idx);
                    237:
                    238:        mode_tree_add(data->data, parent, item, (uint64_t)wp, name, text, -1);
                    239:        free(text);
                    240:        free(name);
                    241: }
                    242:
                    243: static int
                    244: window_tree_build_window(struct session *s, struct winlink *wl, void* modedata,
1.5       nicm      245:     u_int sort_type, struct mode_tree_item *parent, const char *filter)
1.1       nicm      246: {
                    247:        struct window_tree_modedata     *data = modedata;
                    248:        struct window_tree_itemdata     *item;
                    249:        struct mode_tree_item           *mti;
                    250:        char                            *name, *text, *cp;
                    251:        struct window_pane              *wp, **l;
                    252:        u_int                            n, i;
                    253:        int                              expanded;
                    254:
                    255:        item = window_tree_add_item(data);
                    256:        item->type = WINDOW_TREE_WINDOW;
                    257:        item->session = s->id;
                    258:        item->winlink = wl->idx;
                    259:        item->pane = -1;
                    260:
1.15    ! nicm      261:        text = format_single(NULL, data->format, NULL, s, wl, NULL);
1.1       nicm      262:        xasprintf(&name, "%u", wl->idx);
                    263:
                    264:        if (data->type == WINDOW_TREE_SESSION ||
                    265:            data->type == WINDOW_TREE_WINDOW)
                    266:                expanded = 0;
                    267:        else
                    268:                expanded = 1;
                    269:        mti = mode_tree_add(data->data, parent, item, (uint64_t)wl, name, text,
                    270:            expanded);
                    271:        free(text);
                    272:        free(name);
                    273:
1.13      nicm      274:        if (window_count_panes(wl->window) == 1)
                    275:                return (1);
                    276:
1.1       nicm      277:        l = NULL;
                    278:        n = 0;
1.13      nicm      279:
1.1       nicm      280:        TAILQ_FOREACH(wp, &wl->window->panes, entry) {
1.5       nicm      281:                if (filter != NULL) {
                    282:                        cp = format_single(NULL, filter, NULL, s, wl, wp);
1.1       nicm      283:                        if (!format_true(cp)) {
                    284:                                free(cp);
                    285:                                continue;
                    286:                        }
                    287:                        free(cp);
                    288:                }
                    289:                l = xreallocarray(l, n + 1, sizeof *l);
                    290:                l[n++] = wp;
                    291:        }
                    292:        if (n == 0) {
                    293:                window_tree_free_item(item);
                    294:                data->item_size--;
                    295:                mode_tree_remove(data->data, mti);
                    296:                return (0);
                    297:        }
                    298:
                    299:        switch (sort_type) {
                    300:        case WINDOW_TREE_BY_INDEX:
                    301:                break;
                    302:        case WINDOW_TREE_BY_NAME:
                    303:                /* Panes don't have names, so leave in number order. */
                    304:                break;
                    305:        case WINDOW_TREE_BY_TIME:
                    306:                qsort(l, n, sizeof *l, window_tree_cmp_pane_time);
                    307:                break;
                    308:        }
                    309:
                    310:        for (i = 0; i < n; i++)
                    311:                window_tree_build_pane(s, wl, l[i], modedata, mti);
                    312:        free(l);
                    313:        return (1);
                    314: }
                    315:
                    316: static void
                    317: window_tree_build_session(struct session *s, void* modedata,
1.5       nicm      318:     u_int sort_type, const char *filter)
1.1       nicm      319: {
                    320:        struct window_tree_modedata     *data = modedata;
                    321:        struct window_tree_itemdata     *item;
                    322:        struct mode_tree_item           *mti;
                    323:        char                            *text;
                    324:        struct winlink                  *wl, **l;
                    325:        u_int                            n, i, empty;
                    326:        int                              expanded;
                    327:
                    328:        item = window_tree_add_item(data);
                    329:        item->type = WINDOW_TREE_SESSION;
                    330:        item->session = s->id;
                    331:        item->winlink = -1;
                    332:        item->pane = -1;
                    333:
1.15    ! nicm      334:        text = format_single(NULL, data->format, NULL, s, NULL, NULL);
1.1       nicm      335:
                    336:        if (data->type == WINDOW_TREE_SESSION)
                    337:                expanded = 0;
                    338:        else
                    339:                expanded = 1;
                    340:        mti = mode_tree_add(data->data, NULL, item, (uint64_t)s, s->name, text,
                    341:            expanded);
                    342:        free(text);
                    343:
                    344:        l = NULL;
                    345:        n = 0;
                    346:        RB_FOREACH(wl, winlinks, &s->windows) {
                    347:                l = xreallocarray(l, n + 1, sizeof *l);
                    348:                l[n++] = wl;
                    349:        }
                    350:        switch (sort_type) {
                    351:        case WINDOW_TREE_BY_INDEX:
                    352:                break;
                    353:        case WINDOW_TREE_BY_NAME:
                    354:                qsort(l, n, sizeof *l, window_tree_cmp_window_name);
                    355:                break;
                    356:        case WINDOW_TREE_BY_TIME:
                    357:                qsort(l, n, sizeof *l, window_tree_cmp_window_time);
                    358:                break;
                    359:        }
                    360:
                    361:        empty = 0;
                    362:        for (i = 0; i < n; i++) {
                    363:                if (!window_tree_build_window(s, l[i], modedata, sort_type, mti,
1.5       nicm      364:                    filter))
1.1       nicm      365:                        empty++;
                    366:        }
                    367:        if (empty == n) {
                    368:                window_tree_free_item(item);
                    369:                data->item_size--;
                    370:                mode_tree_remove(data->data, mti);
                    371:        }
                    372:        free(l);
                    373: }
                    374:
                    375: static void
1.5       nicm      376: window_tree_build(void *modedata, u_int sort_type, uint64_t *tag,
                    377:     const char *filter)
1.1       nicm      378: {
                    379:        struct window_tree_modedata     *data = modedata;
                    380:        struct session                  *s, **l;
                    381:        u_int                            n, i;
                    382:
                    383:        for (i = 0; i < data->item_size; i++)
                    384:                window_tree_free_item(data->item_list[i]);
                    385:        free(data->item_list);
                    386:        data->item_list = NULL;
                    387:        data->item_size = 0;
                    388:
                    389:        l = NULL;
                    390:        n = 0;
                    391:        RB_FOREACH(s, sessions, &sessions) {
                    392:                l = xreallocarray(l, n + 1, sizeof *l);
                    393:                l[n++] = s;
                    394:        }
                    395:        switch (sort_type) {
                    396:        case WINDOW_TREE_BY_INDEX:
                    397:                break;
                    398:        case WINDOW_TREE_BY_NAME:
                    399:                qsort(l, n, sizeof *l, window_tree_cmp_session_name);
                    400:                break;
                    401:        case WINDOW_TREE_BY_TIME:
                    402:                qsort(l, n, sizeof *l, window_tree_cmp_session_time);
                    403:                break;
                    404:        }
                    405:
                    406:        for (i = 0; i < n; i++)
1.5       nicm      407:                window_tree_build_session(l[i], modedata, sort_type, filter);
1.1       nicm      408:        free(l);
                    409:
                    410:        switch (data->type) {
                    411:        case WINDOW_TREE_NONE:
                    412:                break;
                    413:        case WINDOW_TREE_SESSION:
                    414:                *tag = (uint64_t)data->fs.s;
                    415:                break;
                    416:        case WINDOW_TREE_WINDOW:
                    417:                *tag = (uint64_t)data->fs.wl;
                    418:                break;
                    419:        case WINDOW_TREE_PANE:
                    420:                *tag = (uint64_t)data->fs.wp;
                    421:                break;
                    422:        }
                    423: }
                    424:
1.6       nicm      425: static void
1.11      nicm      426: window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
                    427:     struct screen_write_ctx *ctx, u_int sx, u_int sy)
1.6       nicm      428: {
                    429:        struct options          *oo = s->options;
                    430:        struct winlink          *wl;
                    431:        struct window           *w;
1.9       nicm      432:        u_int                    loop, total, visible, each, width, offset;
                    433:        u_int                    current, start, end, remaining, i;
1.6       nicm      434:        struct grid_cell         gc;
1.9       nicm      435:        int                      colour, active_colour, left, right;
1.6       nicm      436:        char                    *label;
                    437:        size_t                   len;
                    438:
1.9       nicm      439:        total = winlink_count(&s->windows);
1.6       nicm      440:
                    441:        memcpy(&gc, &grid_default_cell, sizeof gc);
                    442:        colour = options_get_number(oo, "display-panes-colour");
                    443:        active_colour = options_get_number(oo, "display-panes-active-colour");
                    444:
1.9       nicm      445:        if (sx / total < 24) {
                    446:                visible = sx / 24;
                    447:                if (visible == 0)
                    448:                        visible = 1;
                    449:        } else
                    450:                visible = total;
                    451:
                    452:        current = 0;
                    453:        RB_FOREACH(wl, winlinks, &s->windows) {
                    454:                if (wl == s->curw)
                    455:                        break;
                    456:                current++;
                    457:        }
1.6       nicm      458:
1.9       nicm      459:        if (current < visible) {
                    460:                start = 0;
                    461:                end = visible;
                    462:        } else if (current >= total - visible) {
                    463:                start = total - visible;
                    464:                end = total;
                    465:        } else {
                    466:                start = current - (visible / 2);
                    467:                end = start + visible;
                    468:        }
                    469:
1.11      nicm      470:        if (data->offset < -(int)start)
                    471:                data->offset = -(int)start;
                    472:        if (data->offset > (int)(total - end))
                    473:                data->offset = (int)(total - end);
                    474:        start += data->offset;
                    475:        end += data->offset;
                    476:
1.9       nicm      477:        left = (start != 0);
                    478:        right = (end != total);
                    479:        if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
                    480:                left = right = 0;
                    481:        if (left && right) {
                    482:                each = (sx - 6) / visible;
                    483:                remaining = (sx - 6) - (visible * each);
                    484:        } else if (left || right) {
                    485:                each = (sx - 3) / visible;
                    486:                remaining = (sx - 3) - (visible * each);
                    487:        } else {
                    488:                each = sx / visible;
                    489:                remaining = sx - (visible * each);
                    490:        }
                    491:        if (each == 0)
                    492:                return;
                    493:
                    494:        if (left) {
                    495:                screen_write_cursormove(ctx, 2, 0);
                    496:                screen_write_vline(ctx, sy, 0, 0);
                    497:                screen_write_cursormove(ctx, 0, sy / 2);
                    498:                screen_write_puts(ctx, &grid_default_cell, "<");
                    499:        }
                    500:        if (right) {
                    501:                screen_write_cursormove(ctx, sx - 3, 0);
1.6       nicm      502:                screen_write_vline(ctx, sy, 0, 0);
1.9       nicm      503:                screen_write_cursormove(ctx, sx - 1, sy / 2);
                    504:                screen_write_puts(ctx, &grid_default_cell, ">");
                    505:        }
1.6       nicm      506:
1.9       nicm      507:        i = loop = 0;
                    508:        RB_FOREACH(wl, winlinks, &s->windows) {
                    509:                if (loop == end)
                    510:                        break;
                    511:                if (loop < start) {
                    512:                        loop++;
                    513:                        continue;
                    514:                }
                    515:                w = wl->window;
1.6       nicm      516:
                    517:                if (wl == s->curw)
                    518:                        gc.fg = active_colour;
                    519:                else
                    520:                        gc.fg = colour;
1.9       nicm      521:
                    522:                if (left)
                    523:                        offset = 3 + (i * each);
                    524:                else
                    525:                        offset = (i * each);
                    526:                if (loop == end - 1)
1.12      nicm      527:                        width = each + remaining;
1.6       nicm      528:                else
                    529:                        width = each - 1;
                    530:
1.9       nicm      531:                screen_write_cursormove(ctx, offset, 0);
1.6       nicm      532:                screen_write_preview(ctx, &w->active->base, width, sy);
                    533:
                    534:                xasprintf(&label, " %u:%s ", wl->idx, w->name);
                    535:                if (strlen(label) > width)
                    536:                        xasprintf(&label, " %u ", wl->idx);
                    537:                len = strlen(label) / 2;
1.9       nicm      538:                screen_write_cursormove(ctx, offset + (each / 2) - len, sy / 2);
1.8       nicm      539:                if (len < width)
1.7       nicm      540:                        screen_write_puts(ctx, &gc, "%s", label);
1.6       nicm      541:                free(label);
                    542:
1.9       nicm      543:                if (loop != end - 1) {
                    544:                        screen_write_cursormove(ctx, offset + width, 0);
1.6       nicm      545:                        screen_write_vline(ctx, sy, 0, 0);
                    546:                }
1.9       nicm      547:                loop++;
                    548:
                    549:                i++;
1.6       nicm      550:        }
                    551: }
                    552:
                    553: static void
1.11      nicm      554: window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
                    555:     struct window *w, struct screen_write_ctx *ctx, u_int sx, u_int sy)
1.6       nicm      556: {
                    557:        struct options          *oo = s->options;
                    558:        struct window_pane      *wp;
1.9       nicm      559:        u_int                    loop, total, visible, each, width, offset;
                    560:        u_int                    current, start, end, remaining, i;
1.6       nicm      561:        struct grid_cell         gc;
1.9       nicm      562:        int                      colour, active_colour, left, right;
1.6       nicm      563:        char                    *label;
                    564:        size_t                   len;
                    565:
1.9       nicm      566:        total = window_count_panes(w);
1.6       nicm      567:
                    568:        memcpy(&gc, &grid_default_cell, sizeof gc);
                    569:        colour = options_get_number(oo, "display-panes-colour");
                    570:        active_colour = options_get_number(oo, "display-panes-active-colour");
                    571:
1.9       nicm      572:        if (sx / total < 24) {
                    573:                visible = sx / 24;
                    574:                if (visible == 0)
                    575:                        visible = 1;
                    576:        } else
                    577:                visible = total;
                    578:
                    579:        current = 0;
                    580:        TAILQ_FOREACH(wp, &w->panes, entry) {
                    581:                if (wp == w->active)
                    582:                        break;
                    583:                current++;
                    584:        }
                    585:
                    586:        if (current < visible) {
                    587:                start = 0;
                    588:                end = visible;
                    589:        } else if (current >= total - visible) {
                    590:                start = total - visible;
                    591:                end = total;
                    592:        } else {
                    593:                start = current - (visible / 2);
                    594:                end = start + visible;
                    595:        }
                    596:
1.11      nicm      597:        if (data->offset < -(int)start)
                    598:                data->offset = -(int)start;
                    599:        if (data->offset > (int)(total - end))
                    600:                data->offset = (int)(total - end);
                    601:        start += data->offset;
                    602:        end += data->offset;
                    603:
1.9       nicm      604:        left = (start != 0);
                    605:        right = (end != total);
                    606:        if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
                    607:                left = right = 0;
                    608:        if (left && right) {
                    609:                each = (sx - 6) / visible;
                    610:                remaining = (sx - 6) - (visible * each);
                    611:        } else if (left || right) {
                    612:                each = (sx - 3) / visible;
                    613:                remaining = (sx - 3) - (visible * each);
                    614:        } else {
                    615:                each = sx / visible;
                    616:                remaining = sx - (visible * each);
                    617:        }
                    618:        if (each == 0)
                    619:                return;
1.6       nicm      620:
1.9       nicm      621:        if (left) {
                    622:                screen_write_cursormove(ctx, 2, 0);
1.6       nicm      623:                screen_write_vline(ctx, sy, 0, 0);
1.9       nicm      624:                screen_write_cursormove(ctx, 0, sy / 2);
                    625:                screen_write_puts(ctx, &grid_default_cell, "<");
                    626:        }
                    627:        if (right) {
                    628:                screen_write_cursormove(ctx, sx - 3, 0);
                    629:                screen_write_vline(ctx, sy, 0, 0);
                    630:                screen_write_cursormove(ctx, sx - 1, sy / 2);
                    631:                screen_write_puts(ctx, &grid_default_cell, ">");
                    632:        }
1.6       nicm      633:
1.9       nicm      634:        i = loop = 0;
                    635:        TAILQ_FOREACH(wp, &w->panes, entry) {
                    636:                if (loop == end)
                    637:                        break;
                    638:                if (loop < start) {
                    639:                        loop++;
                    640:                        continue;
                    641:                }
1.6       nicm      642:
                    643:                if (wp == w->active)
                    644:                        gc.fg = active_colour;
                    645:                else
                    646:                        gc.fg = colour;
1.9       nicm      647:
                    648:                if (left)
                    649:                        offset = 3 + (i * each);
                    650:                else
                    651:                        offset = (i * each);
                    652:                if (loop == end - 1)
1.12      nicm      653:                        width = each + remaining;
1.6       nicm      654:                else
                    655:                        width = each - 1;
                    656:
1.9       nicm      657:                screen_write_cursormove(ctx, offset, 0);
1.6       nicm      658:                screen_write_preview(ctx, &wp->base, width, sy);
                    659:
1.9       nicm      660:                xasprintf(&label, " %u ", loop);
1.6       nicm      661:                len = strlen(label) / 2;
1.9       nicm      662:                screen_write_cursormove(ctx, offset + (each / 2) - len, sy / 2);
1.8       nicm      663:                if (len < width)
1.7       nicm      664:                        screen_write_puts(ctx, &gc, "%s", label);
1.6       nicm      665:                free(label);
                    666:
1.9       nicm      667:                if (loop != end - 1) {
                    668:                        screen_write_cursormove(ctx, offset + width, 0);
1.6       nicm      669:                        screen_write_vline(ctx, sy, 0, 0);
                    670:                }
1.9       nicm      671:                loop++;
                    672:
                    673:                i++;
1.6       nicm      674:        }
                    675: }
                    676:
1.1       nicm      677: static struct screen *
1.11      nicm      678: window_tree_draw(void *modedata, void *itemdata, u_int sx, u_int sy)
1.1       nicm      679: {
                    680:        struct window_tree_itemdata     *item = itemdata;
                    681:        struct session                  *sp;
                    682:        struct winlink                  *wlp;
                    683:        struct window_pane              *wp;
                    684:        static struct screen             s;
                    685:        struct screen_write_ctx          ctx;
                    686:
                    687:        window_tree_pull_item(item, &sp, &wlp, &wp);
                    688:        if (wp == NULL)
                    689:                return (NULL);
                    690:
                    691:        screen_init(&s, sx, sy, 0);
                    692:        screen_write_start(&ctx, NULL, &s);
                    693:
1.6       nicm      694:        switch (item->type) {
                    695:        case WINDOW_TREE_NONE:
                    696:                return (0);
                    697:        case WINDOW_TREE_SESSION:
1.11      nicm      698:                window_tree_draw_session(modedata, sp, &ctx, sx, sy);
1.6       nicm      699:                break;
                    700:        case WINDOW_TREE_WINDOW:
1.11      nicm      701:                window_tree_draw_window(modedata, sp, wlp->window, &ctx, sx, sy);
1.6       nicm      702:                break;
                    703:        case WINDOW_TREE_PANE:
                    704:                screen_write_preview(&ctx, &wp->base, sx, sy);
                    705:                break;
                    706:        }
1.1       nicm      707:
                    708:        screen_write_stop(&ctx);
                    709:        return (&s);
                    710: }
                    711:
1.3       nicm      712: static int
                    713: window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
                    714: {
                    715:        struct window_tree_itemdata     *item = itemdata;
                    716:        struct session                  *s;
                    717:        struct winlink                  *wl;
                    718:        struct window_pane              *wp;
                    719:        const char                      *cmd;
                    720:
                    721:        window_tree_pull_item(item, &s, &wl, &wp);
                    722:
                    723:        switch (item->type) {
                    724:        case WINDOW_TREE_NONE:
                    725:                return (0);
                    726:        case WINDOW_TREE_SESSION:
                    727:                if (s == NULL)
                    728:                        return (0);
                    729:                return (strstr(s->name, ss) != NULL);
                    730:        case WINDOW_TREE_WINDOW:
                    731:                if (s == NULL || wl == NULL)
                    732:                        return (0);
                    733:                return (strstr(wl->window->name, ss) != NULL);
                    734:        case WINDOW_TREE_PANE:
                    735:                if (s == NULL || wl == NULL || wp == NULL)
                    736:                        break;
                    737:                cmd = get_proc_name(wp->fd, wp->tty);
                    738:                if (cmd == NULL || *cmd == '\0')
                    739:                        return (0);
                    740:                return (strstr(cmd, ss) != NULL);
                    741:        }
                    742:        return (0);
                    743: }
                    744:
1.1       nicm      745: static struct screen *
                    746: window_tree_init(struct window_pane *wp, struct cmd_find_state *fs,
                    747:     struct args *args)
                    748: {
                    749:        struct window_tree_modedata     *data;
                    750:        struct screen                   *s;
                    751:
                    752:        wp->modedata = data = xcalloc(1, sizeof *data);
                    753:
                    754:        if (args_has(args, 's'))
                    755:                data->type = WINDOW_TREE_SESSION;
                    756:        else if (args_has(args, 'w'))
                    757:                data->type = WINDOW_TREE_WINDOW;
                    758:        else
                    759:                data->type = WINDOW_TREE_PANE;
                    760:        memcpy(&data->fs, fs, sizeof data->fs);
                    761:
                    762:        data->wp = wp;
                    763:        data->references = 1;
                    764:
1.15    ! nicm      765:        if (args == NULL || !args_has(args, 'F'))
        !           766:                data->format = xstrdup(WINDOW_TREE_DEFAULT_FORMAT);
        !           767:        else
        !           768:                data->format = xstrdup(args_get(args, 'F'));
1.1       nicm      769:        if (args == NULL || args->argc == 0)
                    770:                data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
                    771:        else
                    772:                data->command = xstrdup(args->argv[0]);
                    773:
1.4       nicm      774:        data->data = mode_tree_start(wp, args, window_tree_build,
                    775:            window_tree_draw, window_tree_search, data, window_tree_sort_list,
1.1       nicm      776:            nitems(window_tree_sort_list), &s);
                    777:
                    778:        mode_tree_build(data->data);
                    779:        mode_tree_draw(data->data);
                    780:
                    781:        data->type = WINDOW_TREE_NONE;
                    782:
                    783:        return (s);
                    784: }
                    785:
                    786: static void
                    787: window_tree_destroy(struct window_tree_modedata *data)
                    788: {
                    789:        u_int   i;
                    790:
                    791:        if (--data->references != 0)
                    792:                return;
                    793:
                    794:        mode_tree_free(data->data);
                    795:
                    796:        for (i = 0; i < data->item_size; i++)
                    797:                window_tree_free_item(data->item_list[i]);
                    798:        free(data->item_list);
                    799:
1.15    ! nicm      800:        free(data->format);
1.1       nicm      801:        free(data->command);
1.15    ! nicm      802:
1.1       nicm      803:        free(data);
                    804: }
                    805:
                    806: static void
                    807: window_tree_free(struct window_pane *wp)
                    808: {
                    809:        struct window_tree_modedata *data = wp->modedata;
                    810:
                    811:        if (data == NULL)
                    812:                return;
                    813:
                    814:        data->dead = 1;
                    815:        window_tree_destroy(data);
                    816: }
                    817:
                    818: static void
                    819: window_tree_resize(struct window_pane *wp, u_int sx, u_int sy)
                    820: {
                    821:        struct window_tree_modedata     *data = wp->modedata;
                    822:
                    823:        mode_tree_resize(data->data, sx, sy);
                    824: }
                    825:
                    826: static char *
                    827: window_tree_get_target(struct window_tree_itemdata *item,
                    828:     struct cmd_find_state *fs)
                    829: {
                    830:        struct session          *s;
                    831:        struct winlink          *wl;
                    832:        struct window_pane      *wp;
                    833:        char                    *target;
                    834:
                    835:        window_tree_pull_item(item, &s, &wl, &wp);
                    836:
                    837:        target = NULL;
                    838:        switch (item->type) {
                    839:        case WINDOW_TREE_NONE:
                    840:                break;
                    841:        case WINDOW_TREE_SESSION:
                    842:                if (s == NULL)
                    843:                        break;
                    844:                xasprintf(&target, "=%s:", s->name);
                    845:                break;
                    846:        case WINDOW_TREE_WINDOW:
                    847:                if (s == NULL || wl == NULL)
                    848:                        break;
                    849:                xasprintf(&target, "=%s:%u.", s->name, wl->idx);
                    850:                break;
                    851:        case WINDOW_TREE_PANE:
                    852:                if (s == NULL || wl == NULL || wp == NULL)
                    853:                        break;
                    854:                xasprintf(&target, "=%s:%u.%%%u", s->name, wl->idx, wp->id);
                    855:                break;
                    856:        }
                    857:        if (target == NULL)
                    858:                cmd_find_clear_state(fs, 0);
                    859:        else
                    860:                cmd_find_from_winlink_pane(fs, wl, wp);
                    861:        return (target);
                    862: }
                    863:
                    864: static void
                    865: window_tree_command_each(void* modedata, void* itemdata, __unused key_code key)
                    866: {
                    867:        struct window_tree_modedata     *data = modedata;
                    868:        struct window_tree_itemdata     *item = itemdata;
                    869:        char                            *name;
                    870:        struct cmd_find_state            fs;
                    871:
                    872:        name = window_tree_get_target(item, &fs);
                    873:        if (name != NULL)
                    874:                mode_tree_run_command(data->client, &fs, data->entered, name);
                    875:        free(name);
                    876: }
                    877:
                    878: static enum cmd_retval
                    879: window_tree_command_done(__unused struct cmdq_item *item, void *modedata)
                    880: {
                    881:        struct window_tree_modedata     *data = modedata;
                    882:
                    883:        if (!data->dead) {
                    884:                mode_tree_build(data->data);
                    885:                mode_tree_draw(data->data);
                    886:                data->wp->flags |= PANE_REDRAW;
                    887:        }
                    888:        window_tree_destroy(data);
                    889:        return (CMD_RETURN_NORMAL);
                    890: }
                    891:
                    892: static int
                    893: window_tree_command_callback(struct client *c, void *modedata, const char *s,
                    894:     __unused int done)
                    895: {
                    896:        struct window_tree_modedata     *data = modedata;
                    897:
                    898:        if (data->dead)
                    899:                return (0);
                    900:
                    901:        data->client = c;
                    902:        data->entered = s;
                    903:
                    904:        mode_tree_each_tagged(data->data, window_tree_command_each, KEYC_NONE,
                    905:            1);
                    906:
                    907:        data->client = NULL;
                    908:        data->entered = NULL;
                    909:
                    910:        data->references++;
                    911:        cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
                    912:
                    913:        return (0);
                    914: }
                    915:
                    916: static void
                    917: window_tree_command_free(void *modedata)
                    918: {
                    919:        struct window_tree_modedata     *data = modedata;
                    920:
                    921:        window_tree_destroy(data);
                    922: }
                    923:
                    924: static void
                    925: window_tree_key(struct window_pane *wp, struct client *c,
                    926:     __unused struct session *s, key_code key, struct mouse_event *m)
                    927: {
                    928:        struct window_tree_modedata     *data = wp->modedata;
                    929:        struct window_tree_itemdata     *item;
                    930:        char                            *command, *name, *prompt;
                    931:        struct cmd_find_state            fs;
                    932:        int                              finished;
                    933:        u_int                            tagged;
                    934:
1.11      nicm      935:        item = mode_tree_get_current(data->data);
1.3       nicm      936:        finished = mode_tree_key(data->data, c, &key, m);
1.11      nicm      937:        if (item != mode_tree_get_current(data->data))
                    938:                data->offset = 0;
1.1       nicm      939:        switch (key) {
1.11      nicm      940:        case '<':
                    941:                data->offset--;
                    942:                break;
                    943:        case '>':
                    944:                data->offset++;
                    945:                break;
1.1       nicm      946:        case ':':
                    947:                tagged = mode_tree_count_tagged(data->data);
                    948:                if (tagged != 0)
                    949:                        xasprintf(&prompt, "(%u tagged) ", tagged);
                    950:                else
                    951:                        xasprintf(&prompt, "(current) ");
                    952:                data->references++;
                    953:                status_prompt_set(c, prompt, "", window_tree_command_callback,
                    954:                    window_tree_command_free, data, PROMPT_NOFORMAT);
                    955:                free(prompt);
                    956:                break;
                    957:        case '\r':
                    958:                item = mode_tree_get_current(data->data);
                    959:                command = xstrdup(data->command);
                    960:                name = window_tree_get_target(item, &fs);
                    961:                window_pane_reset_mode(wp);
                    962:                if (name != NULL)
1.2       nicm      963:                        mode_tree_run_command(c, NULL, command, name);
1.1       nicm      964:                free(name);
                    965:                free(command);
                    966:                return;
                    967:        }
                    968:        if (finished)
                    969:                window_pane_reset_mode(wp);
                    970:        else {
                    971:                mode_tree_draw(data->data);
                    972:                wp->flags |= PANE_REDRAW;
                    973:        }
                    974: }