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

1.51    ! nicm        1: /* $OpenBSD: window-tree.c,v 1.50 2020/05/16 16:16:07 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:
1.30      nicm       21: #include <ctype.h>
1.1       nicm       22: #include <stdlib.h>
                     23: #include <string.h>
                     24:
                     25: #include "tmux.h"
                     26:
1.33      nicm       27: static struct screen   *window_tree_init(struct window_mode_entry *,
1.1       nicm       28:                             struct cmd_find_state *, struct args *);
1.33      nicm       29: static void             window_tree_free(struct window_mode_entry *);
                     30: static void             window_tree_resize(struct window_mode_entry *, u_int,
                     31:                             u_int);
                     32: static void             window_tree_key(struct window_mode_entry *,
1.32      nicm       33:                             struct client *, struct session *,
                     34:                             struct winlink *, key_code, struct mouse_event *);
1.1       nicm       35:
1.44      nicm       36: #define WINDOW_TREE_DEFAULT_COMMAND "switch-client -Zt '%%'"
1.1       nicm       37:
1.15      nicm       38: #define WINDOW_TREE_DEFAULT_FORMAT \
                     39:        "#{?pane_format," \
1.47      nicm       40:                "#{?pane_marked,#[reverse],}" \
1.48      nicm       41:                "#{pane_current_command}#{?pane_active,*,}#{?pane_marked,M,}" \
                     42:                "#{?#{&&:#{pane_title},#{!=:#{pane_title},#{host_short}}},: \"#{pane_title}\",}" \
1.15      nicm       43:        "," \
                     44:                "#{?window_format," \
1.47      nicm       45:                        "#{?window_marked_flag,#[reverse],}" \
1.48      nicm       46:                        "#{window_name}#{window_flags}" \
                     47:                        "#{?#{&&:#{==:#{window_panes},1},#{&&:#{pane_title},#{!=:#{pane_title},#{host_short}}}},: \"#{pane_title}\",}" \
1.15      nicm       48:                "," \
                     49:                        "#{session_windows} windows" \
1.23      nicm       50:                        "#{?session_grouped, " \
1.25      nicm       51:                                "(group #{session_group}: " \
                     52:                                "#{session_group_list})," \
1.23      nicm       53:                        "}" \
1.15      nicm       54:                        "#{?session_attached, (attached),}" \
                     55:                "}" \
                     56:        "}"
                     57:
1.39      nicm       58: static const struct menu_item window_tree_menu_items[] = {
1.45      nicm       59:        { "Select", '\r', NULL },
                     60:        { "Expand", KEYC_RIGHT, NULL },
1.47      nicm       61:        { "Mark", 'm', NULL },
1.39      nicm       62:        { "", KEYC_NONE, NULL },
                     63:        { "Tag", 't', NULL },
                     64:        { "Tag All", '\024', NULL },
                     65:        { "Tag None", 'T', NULL },
                     66:        { "", KEYC_NONE, NULL },
                     67:        { "Kill", 'x', NULL },
                     68:        { "Kill Tagged", 'X', NULL },
                     69:        { "", KEYC_NONE, NULL },
                     70:        { "Cancel", 'q', NULL },
                     71:
                     72:        { NULL, KEYC_NONE, NULL }
                     73: };
1.38      nicm       74:
1.1       nicm       75: const struct window_mode window_tree_mode = {
                     76:        .name = "tree-mode",
1.35      nicm       77:        .default_format = WINDOW_TREE_DEFAULT_FORMAT,
1.1       nicm       78:
                     79:        .init = window_tree_init,
                     80:        .free = window_tree_free,
                     81:        .resize = window_tree_resize,
                     82:        .key = window_tree_key,
                     83: };
                     84:
                     85: enum window_tree_sort_type {
                     86:        WINDOW_TREE_BY_INDEX,
                     87:        WINDOW_TREE_BY_NAME,
                     88:        WINDOW_TREE_BY_TIME,
                     89: };
                     90: static const char *window_tree_sort_list[] = {
                     91:        "index",
                     92:        "name",
                     93:        "time"
                     94: };
1.40      nicm       95: static struct mode_tree_sort_criteria *window_tree_sort;
1.1       nicm       96:
                     97: enum window_tree_type {
                     98:        WINDOW_TREE_NONE,
                     99:        WINDOW_TREE_SESSION,
                    100:        WINDOW_TREE_WINDOW,
                    101:        WINDOW_TREE_PANE,
                    102: };
                    103:
                    104: struct window_tree_itemdata {
                    105:        enum window_tree_type   type;
                    106:        int                     session;
                    107:        int                     winlink;
                    108:        int                     pane;
                    109: };
                    110:
                    111: struct window_tree_modedata {
                    112:        struct window_pane               *wp;
                    113:        int                               dead;
                    114:        int                               references;
                    115:
                    116:        struct mode_tree_data            *data;
1.15      nicm      117:        char                             *format;
1.1       nicm      118:        char                             *command;
1.23      nicm      119:        int                               squash_groups;
1.1       nicm      120:
                    121:        struct window_tree_itemdata     **item_list;
                    122:        u_int                             item_size;
                    123:
                    124:        const char                       *entered;
                    125:
                    126:        struct cmd_find_state             fs;
                    127:        enum window_tree_type             type;
1.11      nicm      128:
                    129:        int                               offset;
1.27      nicm      130:
                    131:        int                               left;
                    132:        int                               right;
                    133:        u_int                             start;
                    134:        u_int                             end;
                    135:        u_int                             each;
1.1       nicm      136: };
                    137:
                    138: static void
                    139: window_tree_pull_item(struct window_tree_itemdata *item, struct session **sp,
                    140:     struct winlink **wlp, struct window_pane **wp)
                    141: {
                    142:        *wp = NULL;
                    143:        *wlp = NULL;
                    144:        *sp = session_find_by_id(item->session);
                    145:        if (*sp == NULL)
                    146:                return;
                    147:        if (item->type == WINDOW_TREE_SESSION) {
                    148:                *wlp = (*sp)->curw;
                    149:                *wp = (*wlp)->window->active;
                    150:                return;
                    151:        }
                    152:
                    153:        *wlp = winlink_find_by_index(&(*sp)->windows, item->winlink);
                    154:        if (*wlp == NULL) {
                    155:                *sp = NULL;
                    156:                return;
                    157:        }
                    158:        if (item->type == WINDOW_TREE_WINDOW) {
                    159:                *wp = (*wlp)->window->active;
                    160:                return;
                    161:        }
                    162:
                    163:        *wp = window_pane_find_by_id(item->pane);
                    164:        if (!window_has_pane((*wlp)->window, *wp))
                    165:                *wp = NULL;
                    166:        if (*wp == NULL) {
                    167:                *sp = NULL;
                    168:                *wlp = NULL;
                    169:                return;
                    170:        }
                    171: }
                    172:
                    173: static struct window_tree_itemdata *
                    174: window_tree_add_item(struct window_tree_modedata *data)
                    175: {
                    176:        struct window_tree_itemdata     *item;
                    177:
                    178:        data->item_list = xreallocarray(data->item_list, data->item_size + 1,
                    179:            sizeof *data->item_list);
                    180:        item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
                    181:        return (item);
                    182: }
                    183:
                    184: static void
                    185: window_tree_free_item(struct window_tree_itemdata *item)
                    186: {
                    187:        free(item);
                    188: }
                    189:
                    190: static int
1.40      nicm      191: window_tree_cmp_session(const void *a0, const void *b0)
1.1       nicm      192: {
1.40      nicm      193:        const struct session *const     *a = a0;
                    194:        const struct session *const     *b = b0;
                    195:        const struct session            *sa = *a;
                    196:        const struct session            *sb = *b;
1.42      nicm      197:        int                              result = 0;
1.1       nicm      198:
1.40      nicm      199:        switch (window_tree_sort->field) {
                    200:        case WINDOW_TREE_BY_INDEX:
                    201:                result = sa->id - sb->id;
                    202:                break;
                    203:        case WINDOW_TREE_BY_TIME:
                    204:                if (timercmp(&sa->activity_time, &sb->activity_time, >)) {
                    205:                        result = -1;
                    206:                        break;
                    207:                }
                    208:                if (timercmp(&sa->activity_time, &sb->activity_time, <)) {
                    209:                        result = 1;
                    210:                        break;
                    211:                }
                    212:                /* FALLTHROUGH */
                    213:        case WINDOW_TREE_BY_NAME:
                    214:                result = strcmp(sa->name, sb->name);
                    215:                break;
                    216:        }
1.1       nicm      217:
1.40      nicm      218:        if (window_tree_sort->reversed)
                    219:                result = -result;
                    220:        return (result);
1.1       nicm      221: }
                    222:
                    223: static int
1.40      nicm      224: window_tree_cmp_window(const void *a0, const void *b0)
1.1       nicm      225: {
1.40      nicm      226:        const struct winlink *const     *a = a0;
                    227:        const struct winlink *const     *b = b0;
                    228:        const struct winlink            *wla = *a;
                    229:        const struct winlink            *wlb = *b;
                    230:        struct window                   *wa = wla->window;
                    231:        struct window                   *wb = wlb->window;
1.42      nicm      232:        int                              result = 0;
1.1       nicm      233:
1.40      nicm      234:        switch (window_tree_sort->field) {
                    235:        case WINDOW_TREE_BY_INDEX:
                    236:                result = wla->idx - wlb->idx;
                    237:                break;
                    238:        case WINDOW_TREE_BY_TIME:
                    239:                if (timercmp(&wa->activity_time, &wb->activity_time, >)) {
                    240:                        result = -1;
                    241:                        break;
                    242:                }
                    243:                if (timercmp(&wa->activity_time, &wb->activity_time, <)) {
                    244:                        result = 1;
                    245:                        break;
                    246:                }
                    247:                /* FALLTHROUGH */
                    248:        case WINDOW_TREE_BY_NAME:
                    249:                result = strcmp(wa->name, wb->name);
                    250:                break;
                    251:        }
1.1       nicm      252:
1.40      nicm      253:        if (window_tree_sort->reversed)
                    254:                result = -result;
                    255:        return (result);
1.1       nicm      256: }
                    257:
                    258: static int
1.40      nicm      259: window_tree_cmp_pane(const void *a0, const void *b0)
1.1       nicm      260: {
1.40      nicm      261:        const struct window_pane *const *a = a0;
                    262:        const struct window_pane *const *b = b0;
                    263:        int                              result;
                    264:
                    265:        if (window_tree_sort->field == WINDOW_TREE_BY_TIME)
                    266:                result = (*a)->active_point - (*b)->active_point;
                    267:        else {
                    268:                /*
                    269:                 * Panes don't have names, so use number order for any other
                    270:                 * sort field.
                    271:                 */
                    272:                result = (*a)->id - (*b)->id;
                    273:        }
                    274:        if (window_tree_sort->reversed)
1.41      nicm      275:                result = -result;
1.40      nicm      276:        return (result);
1.1       nicm      277: }
                    278:
                    279: static void
                    280: window_tree_build_pane(struct session *s, struct winlink *wl,
                    281:     struct window_pane *wp, void *modedata, struct mode_tree_item *parent)
                    282: {
                    283:        struct window_tree_modedata     *data = modedata;
                    284:        struct window_tree_itemdata     *item;
                    285:        char                            *name, *text;
                    286:        u_int                            idx;
                    287:
                    288:        window_pane_index(wp, &idx);
                    289:
                    290:        item = window_tree_add_item(data);
                    291:        item->type = WINDOW_TREE_PANE;
                    292:        item->session = s->id;
                    293:        item->winlink = wl->idx;
                    294:        item->pane = wp->id;
                    295:
1.15      nicm      296:        text = format_single(NULL, data->format, NULL, s, wl, wp);
1.1       nicm      297:        xasprintf(&name, "%u", idx);
                    298:
                    299:        mode_tree_add(data->data, parent, item, (uint64_t)wp, name, text, -1);
                    300:        free(text);
                    301:        free(name);
                    302: }
                    303:
                    304: static int
1.16      nicm      305: window_tree_filter_pane(struct session *s, struct winlink *wl,
                    306:     struct window_pane *wp, const char *filter)
                    307: {
                    308:        char    *cp;
                    309:        int      result;
                    310:
                    311:        if (filter == NULL)
                    312:                return (1);
                    313:
                    314:        cp = format_single(NULL, filter, NULL, s, wl, wp);
                    315:        result = format_true(cp);
                    316:        free(cp);
                    317:
                    318:        return (result);
                    319: }
                    320:
                    321: static int
1.40      nicm      322: window_tree_build_window(struct session *s, struct winlink *wl,
1.43      nicm      323:     void *modedata, struct mode_tree_sort_criteria *sort_crit,
1.40      nicm      324:     struct mode_tree_item *parent, const char *filter)
1.1       nicm      325: {
                    326:        struct window_tree_modedata     *data = modedata;
                    327:        struct window_tree_itemdata     *item;
                    328:        struct mode_tree_item           *mti;
1.16      nicm      329:        char                            *name, *text;
1.1       nicm      330:        struct window_pane              *wp, **l;
                    331:        u_int                            n, i;
                    332:        int                              expanded;
                    333:
                    334:        item = window_tree_add_item(data);
                    335:        item->type = WINDOW_TREE_WINDOW;
                    336:        item->session = s->id;
                    337:        item->winlink = wl->idx;
                    338:        item->pane = -1;
                    339:
1.15      nicm      340:        text = format_single(NULL, data->format, NULL, s, wl, NULL);
1.1       nicm      341:        xasprintf(&name, "%u", wl->idx);
                    342:
                    343:        if (data->type == WINDOW_TREE_SESSION ||
                    344:            data->type == WINDOW_TREE_WINDOW)
                    345:                expanded = 0;
                    346:        else
                    347:                expanded = 1;
                    348:        mti = mode_tree_add(data->data, parent, item, (uint64_t)wl, name, text,
                    349:            expanded);
                    350:        free(text);
                    351:        free(name);
                    352:
1.29      nicm      353:        if ((wp = TAILQ_FIRST(&wl->window->panes)) == NULL)
                    354:                goto empty;
1.16      nicm      355:        if (TAILQ_NEXT(wp, entry) == NULL) {
                    356:                if (!window_tree_filter_pane(s, wl, wp, filter))
                    357:                        goto empty;
1.13      nicm      358:                return (1);
1.16      nicm      359:        }
1.13      nicm      360:
1.1       nicm      361:        l = NULL;
                    362:        n = 0;
1.13      nicm      363:
1.1       nicm      364:        TAILQ_FOREACH(wp, &wl->window->panes, entry) {
1.16      nicm      365:                if (!window_tree_filter_pane(s, wl, wp, filter))
                    366:                        continue;
1.1       nicm      367:                l = xreallocarray(l, n + 1, sizeof *l);
                    368:                l[n++] = wp;
                    369:        }
1.16      nicm      370:        if (n == 0)
                    371:                goto empty;
1.1       nicm      372:
1.40      nicm      373:        window_tree_sort = sort_crit;
                    374:        qsort(l, n, sizeof *l, window_tree_cmp_pane);
1.1       nicm      375:
                    376:        for (i = 0; i < n; i++)
                    377:                window_tree_build_pane(s, wl, l[i], modedata, mti);
                    378:        free(l);
                    379:        return (1);
1.16      nicm      380:
                    381: empty:
                    382:        window_tree_free_item(item);
                    383:        data->item_size--;
                    384:        mode_tree_remove(data->data, mti);
                    385:        return (0);
1.1       nicm      386: }
                    387:
                    388: static void
1.43      nicm      389: window_tree_build_session(struct session *s, void *modedata,
1.40      nicm      390:     struct mode_tree_sort_criteria *sort_crit, const char *filter)
1.1       nicm      391: {
                    392:        struct window_tree_modedata     *data = modedata;
                    393:        struct window_tree_itemdata     *item;
                    394:        struct mode_tree_item           *mti;
                    395:        char                            *text;
                    396:        struct winlink                  *wl, **l;
                    397:        u_int                            n, i, empty;
                    398:        int                              expanded;
                    399:
                    400:        item = window_tree_add_item(data);
                    401:        item->type = WINDOW_TREE_SESSION;
                    402:        item->session = s->id;
                    403:        item->winlink = -1;
                    404:        item->pane = -1;
                    405:
1.15      nicm      406:        text = format_single(NULL, data->format, NULL, s, NULL, NULL);
1.1       nicm      407:
                    408:        if (data->type == WINDOW_TREE_SESSION)
                    409:                expanded = 0;
                    410:        else
                    411:                expanded = 1;
                    412:        mti = mode_tree_add(data->data, NULL, item, (uint64_t)s, s->name, text,
                    413:            expanded);
                    414:        free(text);
                    415:
                    416:        l = NULL;
                    417:        n = 0;
                    418:        RB_FOREACH(wl, winlinks, &s->windows) {
                    419:                l = xreallocarray(l, n + 1, sizeof *l);
                    420:                l[n++] = wl;
                    421:        }
1.40      nicm      422:        window_tree_sort = sort_crit;
                    423:        qsort(l, n, sizeof *l, window_tree_cmp_window);
1.1       nicm      424:
                    425:        empty = 0;
                    426:        for (i = 0; i < n; i++) {
1.40      nicm      427:                if (!window_tree_build_window(s, l[i], modedata, sort_crit, mti,
1.5       nicm      428:                    filter))
1.1       nicm      429:                        empty++;
                    430:        }
                    431:        if (empty == n) {
                    432:                window_tree_free_item(item);
                    433:                data->item_size--;
                    434:                mode_tree_remove(data->data, mti);
                    435:        }
                    436:        free(l);
                    437: }
                    438:
                    439: static void
1.40      nicm      440: window_tree_build(void *modedata, struct mode_tree_sort_criteria *sort_crit,
                    441:     uint64_t *tag, const char *filter)
1.1       nicm      442: {
                    443:        struct window_tree_modedata     *data = modedata;
                    444:        struct session                  *s, **l;
1.24      nicm      445:        struct session_group            *sg, *current;
1.1       nicm      446:        u_int                            n, i;
                    447:
1.24      nicm      448:        current = session_group_contains(data->fs.s);
                    449:
1.1       nicm      450:        for (i = 0; i < data->item_size; i++)
                    451:                window_tree_free_item(data->item_list[i]);
                    452:        free(data->item_list);
                    453:        data->item_list = NULL;
                    454:        data->item_size = 0;
                    455:
                    456:        l = NULL;
                    457:        n = 0;
                    458:        RB_FOREACH(s, sessions, &sessions) {
1.23      nicm      459:                if (data->squash_groups &&
1.24      nicm      460:                    (sg = session_group_contains(s)) != NULL) {
                    461:                        if ((sg == current && s != data->fs.s) ||
                    462:                            (sg != current && s != TAILQ_FIRST(&sg->sessions)))
                    463:                                continue;
                    464:                }
1.1       nicm      465:                l = xreallocarray(l, n + 1, sizeof *l);
                    466:                l[n++] = s;
                    467:        }
1.40      nicm      468:        window_tree_sort = sort_crit;
                    469:        qsort(l, n, sizeof *l, window_tree_cmp_session);
1.1       nicm      470:
                    471:        for (i = 0; i < n; i++)
1.40      nicm      472:                window_tree_build_session(l[i], modedata, sort_crit, filter);
1.1       nicm      473:        free(l);
                    474:
                    475:        switch (data->type) {
                    476:        case WINDOW_TREE_NONE:
                    477:                break;
                    478:        case WINDOW_TREE_SESSION:
                    479:                *tag = (uint64_t)data->fs.s;
                    480:                break;
                    481:        case WINDOW_TREE_WINDOW:
                    482:                *tag = (uint64_t)data->fs.wl;
                    483:                break;
                    484:        case WINDOW_TREE_PANE:
1.18      nicm      485:                if (window_count_panes(data->fs.wl->window) == 1)
                    486:                        *tag = (uint64_t)data->fs.wl;
                    487:                else
                    488:                        *tag = (uint64_t)data->fs.wp;
1.1       nicm      489:                break;
                    490:        }
                    491: }
1.19      nicm      492:
                    493: static void
                    494: window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py,
                    495:     u_int sx, u_int sy, const struct grid_cell *gc, const char *label)
                    496: {
                    497:        size_t   len;
                    498:        u_int    ox, oy;
                    499:
                    500:        len = strlen(label);
                    501:        if (sx == 0 || sy == 1 || len > sx)
                    502:                return;
                    503:        ox = (sx - len + 1) / 2;
                    504:        oy = (sy + 1) / 2;
                    505:
                    506:        if (ox > 1 && ox + len < sx - 1 && sy >= 3) {
1.34      nicm      507:                screen_write_cursormove(ctx, px + ox - 1, py + oy - 1, 0);
1.19      nicm      508:                screen_write_box(ctx, len + 2, 3);
                    509:        }
1.34      nicm      510:        screen_write_cursormove(ctx, px + ox, py + oy, 0);
1.19      nicm      511:        screen_write_puts(ctx, gc, "%s", label);
                    512: }
                    513:
1.6       nicm      514: static void
1.11      nicm      515: window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
                    516:     struct screen_write_ctx *ctx, u_int sx, u_int sy)
1.6       nicm      517: {
                    518:        struct options          *oo = s->options;
                    519:        struct winlink          *wl;
                    520:        struct window           *w;
1.26      nicm      521:        u_int                    cx = ctx->s->cx, cy = ctx->s->cy;
1.9       nicm      522:        u_int                    loop, total, visible, each, width, offset;
                    523:        u_int                    current, start, end, remaining, i;
1.6       nicm      524:        struct grid_cell         gc;
1.9       nicm      525:        int                      colour, active_colour, left, right;
1.6       nicm      526:        char                    *label;
                    527:
1.9       nicm      528:        total = winlink_count(&s->windows);
1.6       nicm      529:
                    530:        memcpy(&gc, &grid_default_cell, sizeof gc);
                    531:        colour = options_get_number(oo, "display-panes-colour");
                    532:        active_colour = options_get_number(oo, "display-panes-active-colour");
                    533:
1.9       nicm      534:        if (sx / total < 24) {
                    535:                visible = sx / 24;
                    536:                if (visible == 0)
                    537:                        visible = 1;
                    538:        } else
                    539:                visible = total;
                    540:
                    541:        current = 0;
                    542:        RB_FOREACH(wl, winlinks, &s->windows) {
                    543:                if (wl == s->curw)
                    544:                        break;
                    545:                current++;
                    546:        }
1.6       nicm      547:
1.9       nicm      548:        if (current < visible) {
                    549:                start = 0;
                    550:                end = visible;
                    551:        } else if (current >= total - visible) {
                    552:                start = total - visible;
                    553:                end = total;
                    554:        } else {
                    555:                start = current - (visible / 2);
                    556:                end = start + visible;
                    557:        }
                    558:
1.11      nicm      559:        if (data->offset < -(int)start)
                    560:                data->offset = -(int)start;
                    561:        if (data->offset > (int)(total - end))
                    562:                data->offset = (int)(total - end);
                    563:        start += data->offset;
                    564:        end += data->offset;
                    565:
1.9       nicm      566:        left = (start != 0);
                    567:        right = (end != total);
                    568:        if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
                    569:                left = right = 0;
                    570:        if (left && right) {
                    571:                each = (sx - 6) / visible;
                    572:                remaining = (sx - 6) - (visible * each);
                    573:        } else if (left || right) {
                    574:                each = (sx - 3) / visible;
                    575:                remaining = (sx - 3) - (visible * each);
                    576:        } else {
                    577:                each = sx / visible;
                    578:                remaining = sx - (visible * each);
                    579:        }
                    580:        if (each == 0)
                    581:                return;
                    582:
                    583:        if (left) {
1.27      nicm      584:                data->left = cx + 2;
1.34      nicm      585:                screen_write_cursormove(ctx, cx + 2, cy, 0);
1.9       nicm      586:                screen_write_vline(ctx, sy, 0, 0);
1.34      nicm      587:                screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
1.9       nicm      588:                screen_write_puts(ctx, &grid_default_cell, "<");
1.27      nicm      589:        } else
                    590:                data->left = -1;
1.9       nicm      591:        if (right) {
1.27      nicm      592:                data->right = cx + sx - 3;
1.34      nicm      593:                screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
1.6       nicm      594:                screen_write_vline(ctx, sy, 0, 0);
1.34      nicm      595:                screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
1.9       nicm      596:                screen_write_puts(ctx, &grid_default_cell, ">");
1.27      nicm      597:        } else
                    598:                data->right = -1;
                    599:
                    600:        data->start = start;
                    601:        data->end = end;
                    602:        data->each = each;
1.6       nicm      603:
1.9       nicm      604:        i = loop = 0;
                    605:        RB_FOREACH(wl, winlinks, &s->windows) {
                    606:                if (loop == end)
                    607:                        break;
                    608:                if (loop < start) {
                    609:                        loop++;
                    610:                        continue;
                    611:                }
                    612:                w = wl->window;
1.6       nicm      613:
                    614:                if (wl == s->curw)
                    615:                        gc.fg = active_colour;
                    616:                else
                    617:                        gc.fg = colour;
1.9       nicm      618:
                    619:                if (left)
                    620:                        offset = 3 + (i * each);
                    621:                else
                    622:                        offset = (i * each);
                    623:                if (loop == end - 1)
1.12      nicm      624:                        width = each + remaining;
1.6       nicm      625:                else
                    626:                        width = each - 1;
                    627:
1.34      nicm      628:                screen_write_cursormove(ctx, cx + offset, cy, 0);
1.6       nicm      629:                screen_write_preview(ctx, &w->active->base, width, sy);
                    630:
                    631:                xasprintf(&label, " %u:%s ", wl->idx, w->name);
                    632:                if (strlen(label) > width)
                    633:                        xasprintf(&label, " %u ", wl->idx);
1.26      nicm      634:                window_tree_draw_label(ctx, cx + offset, cy, width, sy, &gc,
                    635:                    label);
1.6       nicm      636:                free(label);
                    637:
1.9       nicm      638:                if (loop != end - 1) {
1.34      nicm      639:                        screen_write_cursormove(ctx, cx + offset + width, cy, 0);
1.6       nicm      640:                        screen_write_vline(ctx, sy, 0, 0);
                    641:                }
1.9       nicm      642:                loop++;
                    643:
                    644:                i++;
1.6       nicm      645:        }
                    646: }
                    647:
                    648: static void
1.11      nicm      649: window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
                    650:     struct window *w, struct screen_write_ctx *ctx, u_int sx, u_int sy)
1.6       nicm      651: {
                    652:        struct options          *oo = s->options;
                    653:        struct window_pane      *wp;
1.26      nicm      654:        u_int                    cx = ctx->s->cx, cy = ctx->s->cy;
1.9       nicm      655:        u_int                    loop, total, visible, each, width, offset;
                    656:        u_int                    current, start, end, remaining, i;
1.6       nicm      657:        struct grid_cell         gc;
1.20      nicm      658:        int                      colour, active_colour, left, right, pane_idx;
1.6       nicm      659:        char                    *label;
                    660:
1.9       nicm      661:        total = window_count_panes(w);
1.6       nicm      662:
                    663:        memcpy(&gc, &grid_default_cell, sizeof gc);
                    664:        colour = options_get_number(oo, "display-panes-colour");
                    665:        active_colour = options_get_number(oo, "display-panes-active-colour");
                    666:
1.9       nicm      667:        if (sx / total < 24) {
                    668:                visible = sx / 24;
                    669:                if (visible == 0)
                    670:                        visible = 1;
                    671:        } else
                    672:                visible = total;
                    673:
                    674:        current = 0;
                    675:        TAILQ_FOREACH(wp, &w->panes, entry) {
                    676:                if (wp == w->active)
                    677:                        break;
                    678:                current++;
                    679:        }
                    680:
                    681:        if (current < visible) {
                    682:                start = 0;
                    683:                end = visible;
                    684:        } else if (current >= total - visible) {
                    685:                start = total - visible;
                    686:                end = total;
                    687:        } else {
                    688:                start = current - (visible / 2);
                    689:                end = start + visible;
                    690:        }
                    691:
1.11      nicm      692:        if (data->offset < -(int)start)
                    693:                data->offset = -(int)start;
                    694:        if (data->offset > (int)(total - end))
                    695:                data->offset = (int)(total - end);
                    696:        start += data->offset;
                    697:        end += data->offset;
                    698:
1.9       nicm      699:        left = (start != 0);
                    700:        right = (end != total);
                    701:        if (((left && right) && sx <= 6) || ((left || right) && sx <= 3))
                    702:                left = right = 0;
                    703:        if (left && right) {
                    704:                each = (sx - 6) / visible;
                    705:                remaining = (sx - 6) - (visible * each);
                    706:        } else if (left || right) {
                    707:                each = (sx - 3) / visible;
                    708:                remaining = (sx - 3) - (visible * each);
                    709:        } else {
                    710:                each = sx / visible;
                    711:                remaining = sx - (visible * each);
                    712:        }
                    713:        if (each == 0)
                    714:                return;
1.6       nicm      715:
1.9       nicm      716:        if (left) {
1.27      nicm      717:                data->left = cx + 2;
1.34      nicm      718:                screen_write_cursormove(ctx, cx + 2, cy, 0);
1.6       nicm      719:                screen_write_vline(ctx, sy, 0, 0);
1.34      nicm      720:                screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
1.9       nicm      721:                screen_write_puts(ctx, &grid_default_cell, "<");
1.27      nicm      722:        } else
                    723:                data->left = -1;
1.9       nicm      724:        if (right) {
1.27      nicm      725:                data->right = cx + sx - 3;
1.34      nicm      726:                screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
1.9       nicm      727:                screen_write_vline(ctx, sy, 0, 0);
1.34      nicm      728:                screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
1.9       nicm      729:                screen_write_puts(ctx, &grid_default_cell, ">");
1.27      nicm      730:        } else
                    731:                data->right = -1;
                    732:
                    733:        data->start = start;
                    734:        data->end = end;
                    735:        data->each = each;
1.6       nicm      736:
1.9       nicm      737:        i = loop = 0;
                    738:        TAILQ_FOREACH(wp, &w->panes, entry) {
                    739:                if (loop == end)
                    740:                        break;
                    741:                if (loop < start) {
                    742:                        loop++;
                    743:                        continue;
                    744:                }
1.6       nicm      745:
                    746:                if (wp == w->active)
                    747:                        gc.fg = active_colour;
                    748:                else
                    749:                        gc.fg = colour;
1.9       nicm      750:
                    751:                if (left)
                    752:                        offset = 3 + (i * each);
                    753:                else
                    754:                        offset = (i * each);
                    755:                if (loop == end - 1)
1.12      nicm      756:                        width = each + remaining;
1.6       nicm      757:                else
                    758:                        width = each - 1;
                    759:
1.34      nicm      760:                screen_write_cursormove(ctx, cx + offset, cy, 0);
1.6       nicm      761:                screen_write_preview(ctx, &wp->base, width, sy);
                    762:
1.20      nicm      763:                if (window_pane_index(wp, &pane_idx) != 0)
                    764:                        pane_idx = loop;
                    765:                xasprintf(&label, " %u ", pane_idx);
1.26      nicm      766:                window_tree_draw_label(ctx, cx + offset, cy, each, sy, &gc,
                    767:                    label);
1.6       nicm      768:                free(label);
                    769:
1.9       nicm      770:                if (loop != end - 1) {
1.34      nicm      771:                        screen_write_cursormove(ctx, cx + offset + width, cy, 0);
1.6       nicm      772:                        screen_write_vline(ctx, sy, 0, 0);
                    773:                }
1.9       nicm      774:                loop++;
                    775:
                    776:                i++;
1.6       nicm      777:        }
                    778: }
                    779:
1.26      nicm      780: static void
                    781: window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
                    782:     u_int sx, u_int sy)
1.1       nicm      783: {
                    784:        struct window_tree_itemdata     *item = itemdata;
                    785:        struct session                  *sp;
                    786:        struct winlink                  *wlp;
                    787:        struct window_pane              *wp;
                    788:
                    789:        window_tree_pull_item(item, &sp, &wlp, &wp);
                    790:        if (wp == NULL)
1.26      nicm      791:                return;
1.1       nicm      792:
1.6       nicm      793:        switch (item->type) {
                    794:        case WINDOW_TREE_NONE:
1.26      nicm      795:                break;
1.6       nicm      796:        case WINDOW_TREE_SESSION:
1.26      nicm      797:                window_tree_draw_session(modedata, sp, ctx, sx, sy);
1.6       nicm      798:                break;
                    799:        case WINDOW_TREE_WINDOW:
1.26      nicm      800:                window_tree_draw_window(modedata, sp, wlp->window, ctx, sx, sy);
1.6       nicm      801:                break;
                    802:        case WINDOW_TREE_PANE:
1.26      nicm      803:                screen_write_preview(ctx, &wp->base, sx, sy);
1.6       nicm      804:                break;
                    805:        }
1.1       nicm      806: }
                    807:
1.3       nicm      808: static int
                    809: window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
                    810: {
                    811:        struct window_tree_itemdata     *item = itemdata;
                    812:        struct session                  *s;
                    813:        struct winlink                  *wl;
                    814:        struct window_pane              *wp;
1.37      nicm      815:        char                            *cmd;
                    816:        int                              retval;
1.3       nicm      817:
                    818:        window_tree_pull_item(item, &s, &wl, &wp);
                    819:
                    820:        switch (item->type) {
                    821:        case WINDOW_TREE_NONE:
                    822:                return (0);
                    823:        case WINDOW_TREE_SESSION:
                    824:                if (s == NULL)
                    825:                        return (0);
                    826:                return (strstr(s->name, ss) != NULL);
                    827:        case WINDOW_TREE_WINDOW:
                    828:                if (s == NULL || wl == NULL)
                    829:                        return (0);
                    830:                return (strstr(wl->window->name, ss) != NULL);
                    831:        case WINDOW_TREE_PANE:
                    832:                if (s == NULL || wl == NULL || wp == NULL)
                    833:                        break;
                    834:                cmd = get_proc_name(wp->fd, wp->tty);
                    835:                if (cmd == NULL || *cmd == '\0')
                    836:                        return (0);
1.37      nicm      837:                retval = (strstr(cmd, ss) != NULL);
                    838:                free(cmd);
1.46      nicm      839:                return (retval);
1.3       nicm      840:        }
                    841:        return (0);
                    842: }
                    843:
1.38      nicm      844: static void
                    845: window_tree_menu(void *modedata, struct client *c, key_code key)
                    846: {
                    847:        struct window_tree_modedata     *data = modedata;
                    848:        struct window_pane              *wp = data->wp;
                    849:        struct window_mode_entry        *wme;
                    850:
                    851:        wme = TAILQ_FIRST(&wp->modes);
                    852:        if (wme == NULL || wme->data != modedata)
                    853:                return;
                    854:        window_tree_key(wme, c, NULL, NULL, key, NULL);
                    855: }
                    856:
1.1       nicm      857: static struct screen *
1.33      nicm      858: window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
1.1       nicm      859:     struct args *args)
                    860: {
1.33      nicm      861:        struct window_pane              *wp = wme->wp;
1.1       nicm      862:        struct window_tree_modedata     *data;
                    863:        struct screen                   *s;
                    864:
1.33      nicm      865:        wme->data = data = xcalloc(1, sizeof *data);
1.38      nicm      866:        data->wp = wp;
                    867:        data->references = 1;
1.1       nicm      868:
                    869:        if (args_has(args, 's'))
                    870:                data->type = WINDOW_TREE_SESSION;
                    871:        else if (args_has(args, 'w'))
                    872:                data->type = WINDOW_TREE_WINDOW;
                    873:        else
                    874:                data->type = WINDOW_TREE_PANE;
                    875:        memcpy(&data->fs, fs, sizeof data->fs);
                    876:
1.15      nicm      877:        if (args == NULL || !args_has(args, 'F'))
                    878:                data->format = xstrdup(WINDOW_TREE_DEFAULT_FORMAT);
                    879:        else
                    880:                data->format = xstrdup(args_get(args, 'F'));
1.1       nicm      881:        if (args == NULL || args->argc == 0)
                    882:                data->command = xstrdup(WINDOW_TREE_DEFAULT_COMMAND);
                    883:        else
                    884:                data->command = xstrdup(args->argv[0]);
1.23      nicm      885:        data->squash_groups = !args_has(args, 'G');
1.1       nicm      886:
1.4       nicm      887:        data->data = mode_tree_start(wp, args, window_tree_build,
1.49      nicm      888:            window_tree_draw, window_tree_search, window_tree_menu, NULL, data,
1.39      nicm      889:            window_tree_menu_items, window_tree_sort_list,
1.1       nicm      890:            nitems(window_tree_sort_list), &s);
1.28      nicm      891:        mode_tree_zoom(data->data, args);
1.1       nicm      892:
                    893:        mode_tree_build(data->data);
                    894:        mode_tree_draw(data->data);
                    895:
                    896:        data->type = WINDOW_TREE_NONE;
                    897:
                    898:        return (s);
                    899: }
                    900:
                    901: static void
                    902: window_tree_destroy(struct window_tree_modedata *data)
                    903: {
                    904:        u_int   i;
                    905:
                    906:        if (--data->references != 0)
                    907:                return;
                    908:
                    909:        for (i = 0; i < data->item_size; i++)
                    910:                window_tree_free_item(data->item_list[i]);
                    911:        free(data->item_list);
                    912:
1.15      nicm      913:        free(data->format);
1.1       nicm      914:        free(data->command);
1.15      nicm      915:
1.1       nicm      916:        free(data);
                    917: }
                    918:
                    919: static void
1.33      nicm      920: window_tree_free(struct window_mode_entry *wme)
1.1       nicm      921: {
1.33      nicm      922:        struct window_tree_modedata *data = wme->data;
1.1       nicm      923:
                    924:        if (data == NULL)
                    925:                return;
                    926:
                    927:        data->dead = 1;
1.30      nicm      928:        mode_tree_free(data->data);
1.1       nicm      929:        window_tree_destroy(data);
                    930: }
                    931:
                    932: static void
1.33      nicm      933: window_tree_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
1.1       nicm      934: {
1.33      nicm      935:        struct window_tree_modedata     *data = wme->data;
1.1       nicm      936:
                    937:        mode_tree_resize(data->data, sx, sy);
                    938: }
                    939:
                    940: static char *
                    941: window_tree_get_target(struct window_tree_itemdata *item,
                    942:     struct cmd_find_state *fs)
                    943: {
                    944:        struct session          *s;
                    945:        struct winlink          *wl;
                    946:        struct window_pane      *wp;
                    947:        char                    *target;
                    948:
                    949:        window_tree_pull_item(item, &s, &wl, &wp);
                    950:
                    951:        target = NULL;
                    952:        switch (item->type) {
                    953:        case WINDOW_TREE_NONE:
                    954:                break;
                    955:        case WINDOW_TREE_SESSION:
                    956:                if (s == NULL)
                    957:                        break;
                    958:                xasprintf(&target, "=%s:", s->name);
                    959:                break;
                    960:        case WINDOW_TREE_WINDOW:
                    961:                if (s == NULL || wl == NULL)
                    962:                        break;
                    963:                xasprintf(&target, "=%s:%u.", s->name, wl->idx);
                    964:                break;
                    965:        case WINDOW_TREE_PANE:
                    966:                if (s == NULL || wl == NULL || wp == NULL)
                    967:                        break;
                    968:                xasprintf(&target, "=%s:%u.%%%u", s->name, wl->idx, wp->id);
                    969:                break;
                    970:        }
                    971:        if (target == NULL)
                    972:                cmd_find_clear_state(fs, 0);
                    973:        else
1.17      nicm      974:                cmd_find_from_winlink_pane(fs, wl, wp, 0);
1.1       nicm      975:        return (target);
                    976: }
                    977:
                    978: static void
1.43      nicm      979: window_tree_command_each(void *modedata, void *itemdata, struct client *c,
1.21      nicm      980:     __unused key_code key)
1.1       nicm      981: {
                    982:        struct window_tree_modedata     *data = modedata;
                    983:        struct window_tree_itemdata     *item = itemdata;
                    984:        char                            *name;
                    985:        struct cmd_find_state            fs;
                    986:
                    987:        name = window_tree_get_target(item, &fs);
                    988:        if (name != NULL)
1.21      nicm      989:                mode_tree_run_command(c, &fs, data->entered, name);
1.1       nicm      990:        free(name);
                    991: }
                    992:
                    993: static enum cmd_retval
                    994: window_tree_command_done(__unused struct cmdq_item *item, void *modedata)
                    995: {
                    996:        struct window_tree_modedata     *data = modedata;
                    997:
                    998:        if (!data->dead) {
                    999:                mode_tree_build(data->data);
                   1000:                mode_tree_draw(data->data);
                   1001:                data->wp->flags |= PANE_REDRAW;
                   1002:        }
                   1003:        window_tree_destroy(data);
                   1004:        return (CMD_RETURN_NORMAL);
                   1005: }
                   1006:
                   1007: static int
                   1008: window_tree_command_callback(struct client *c, void *modedata, const char *s,
                   1009:     __unused int done)
                   1010: {
                   1011:        struct window_tree_modedata     *data = modedata;
                   1012:
1.30      nicm     1013:        if (s == NULL || *s == '\0' || data->dead)
1.1       nicm     1014:                return (0);
                   1015:
                   1016:        data->entered = s;
1.21      nicm     1017:        mode_tree_each_tagged(data->data, window_tree_command_each, c,
                   1018:            KEYC_NONE, 1);
1.1       nicm     1019:        data->entered = NULL;
                   1020:
                   1021:        data->references++;
                   1022:        cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
                   1023:
                   1024:        return (0);
                   1025: }
                   1026:
                   1027: static void
                   1028: window_tree_command_free(void *modedata)
                   1029: {
                   1030:        struct window_tree_modedata     *data = modedata;
                   1031:
                   1032:        window_tree_destroy(data);
                   1033: }
                   1034:
1.30      nicm     1035: static void
1.43      nicm     1036: window_tree_kill_each(__unused void *modedata, void *itemdata,
1.30      nicm     1037:     __unused struct client *c, __unused key_code key)
                   1038: {
                   1039:        struct window_tree_itemdata     *item = itemdata;
                   1040:        struct session                  *s;
                   1041:        struct winlink                  *wl;
                   1042:        struct window_pane              *wp;
                   1043:
                   1044:        window_tree_pull_item(item, &s, &wl, &wp);
                   1045:
                   1046:        switch (item->type) {
                   1047:        case WINDOW_TREE_NONE:
                   1048:                break;
                   1049:        case WINDOW_TREE_SESSION:
                   1050:                if (s != NULL) {
                   1051:                        server_destroy_session(s);
1.36      nicm     1052:                        session_destroy(s, 1, __func__);
1.30      nicm     1053:                }
                   1054:                break;
                   1055:        case WINDOW_TREE_WINDOW:
                   1056:                if (wl != NULL)
1.51    ! nicm     1057:                        server_kill_window(wl->window, 1);
1.30      nicm     1058:                break;
                   1059:        case WINDOW_TREE_PANE:
                   1060:                if (wp != NULL)
                   1061:                        server_kill_pane(wp);
                   1062:                break;
                   1063:        }
                   1064: }
                   1065:
                   1066: static int
                   1067: window_tree_kill_current_callback(struct client *c, void *modedata,
                   1068:     const char *s, __unused int done)
                   1069: {
                   1070:        struct window_tree_modedata     *data = modedata;
                   1071:        struct mode_tree_data           *mtd = data->data;
                   1072:
                   1073:        if (s == NULL || *s == '\0' || data->dead)
                   1074:                return (0);
                   1075:        if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
                   1076:                return (0);
                   1077:
                   1078:        window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE);
                   1079:
                   1080:        data->references++;
                   1081:        cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
                   1082:
                   1083:        return (0);
                   1084: }
                   1085:
                   1086: static int
                   1087: window_tree_kill_tagged_callback(struct client *c, void *modedata,
                   1088:     const char *s, __unused int done)
                   1089: {
                   1090:        struct window_tree_modedata     *data = modedata;
                   1091:        struct mode_tree_data           *mtd = data->data;
                   1092:
                   1093:        if (s == NULL || *s == '\0' || data->dead)
                   1094:                return (0);
                   1095:        if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
                   1096:                return (0);
                   1097:
                   1098:        mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1);
                   1099:
                   1100:        data->references++;
                   1101:        cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
                   1102:
                   1103:        return (0);
                   1104: }
                   1105:
1.27      nicm     1106: static key_code
                   1107: window_tree_mouse(struct window_tree_modedata *data, key_code key, u_int x,
                   1108:     struct window_tree_itemdata *item)
                   1109: {
                   1110:        struct session          *s;
                   1111:        struct winlink          *wl;
                   1112:        struct window_pane      *wp;
                   1113:        u_int                    loop;
                   1114:
                   1115:        if (key != KEYC_MOUSEDOWN1_PANE)
                   1116:                return (KEYC_NONE);
                   1117:
                   1118:        if (data->left != -1 && x <= (u_int)data->left)
                   1119:                return ('<');
                   1120:        if (data->right != -1 && x >= (u_int)data->right)
                   1121:                return ('>');
                   1122:
                   1123:        if (data->left != -1)
                   1124:                x -= data->left;
                   1125:        else if (x != 0)
                   1126:                x--;
                   1127:        if (x == 0 || data->end == 0)
                   1128:                x = 0;
                   1129:        else {
                   1130:                x = x / data->each;
                   1131:                if (data->start + x >= data->end)
                   1132:                        x = data->end - 1;
                   1133:        }
                   1134:
                   1135:        window_tree_pull_item(item, &s, &wl, &wp);
                   1136:        if (item->type == WINDOW_TREE_SESSION) {
                   1137:                if (s == NULL)
                   1138:                        return (KEYC_NONE);
                   1139:                mode_tree_expand_current(data->data);
                   1140:                loop = 0;
                   1141:                RB_FOREACH(wl, winlinks, &s->windows) {
                   1142:                        if (loop == data->start + x)
                   1143:                                break;
                   1144:                        loop++;
                   1145:                }
                   1146:                if (wl != NULL)
                   1147:                        mode_tree_set_current(data->data, (uint64_t)wl);
                   1148:                return ('\r');
                   1149:        }
                   1150:        if (item->type == WINDOW_TREE_WINDOW) {
                   1151:                if (wl == NULL)
                   1152:                        return (KEYC_NONE);
                   1153:                mode_tree_expand_current(data->data);
                   1154:                loop = 0;
                   1155:                TAILQ_FOREACH(wp, &wl->window->panes, entry) {
                   1156:                        if (loop == data->start + x)
                   1157:                                break;
                   1158:                        loop++;
                   1159:                }
                   1160:                if (wp != NULL)
                   1161:                        mode_tree_set_current(data->data, (uint64_t)wp);
                   1162:                return ('\r');
                   1163:        }
                   1164:        return (KEYC_NONE);
                   1165: }
                   1166:
1.1       nicm     1167: static void
1.33      nicm     1168: window_tree_key(struct window_mode_entry *wme, struct client *c,
1.32      nicm     1169:     __unused struct session *s, __unused struct winlink *wl, key_code key,
                   1170:     struct mouse_event *m)
1.1       nicm     1171: {
1.33      nicm     1172:        struct window_pane              *wp = wme->wp;
                   1173:        struct window_tree_modedata     *data = wme->data;
1.27      nicm     1174:        struct window_tree_itemdata     *item, *new_item;
1.30      nicm     1175:        char                            *name, *prompt = NULL;
1.47      nicm     1176:        struct cmd_find_state            fs, *fsp = &data->fs;
1.1       nicm     1177:        int                              finished;
1.30      nicm     1178:        u_int                            tagged, x, y, idx;
                   1179:        struct session                  *ns;
                   1180:        struct winlink                  *nwl;
                   1181:        struct window_pane              *nwp;
1.1       nicm     1182:
1.11      nicm     1183:        item = mode_tree_get_current(data->data);
1.27      nicm     1184:        finished = mode_tree_key(data->data, c, &key, m, &x, &y);
                   1185:        if (item != (new_item = mode_tree_get_current(data->data))) {
                   1186:                item = new_item;
1.11      nicm     1187:                data->offset = 0;
1.27      nicm     1188:        }
1.38      nicm     1189:        if (KEYC_IS_MOUSE(key) && m != NULL)
1.27      nicm     1190:                key = window_tree_mouse(data, key, x, item);
1.1       nicm     1191:        switch (key) {
1.11      nicm     1192:        case '<':
                   1193:                data->offset--;
                   1194:                break;
                   1195:        case '>':
                   1196:                data->offset++;
1.47      nicm     1197:                break;
                   1198:        case 'H':
                   1199:                mode_tree_expand(data->data, (uint64_t)fsp->s);
                   1200:                mode_tree_expand(data->data, (uint64_t)fsp->wl);
                   1201:                if (!mode_tree_set_current(data->data, (uint64_t)wme->wp))
                   1202:                        mode_tree_set_current(data->data, (uint64_t)fsp->wl);
                   1203:                break;
                   1204:        case 'm':
                   1205:                window_tree_pull_item(item, &ns, &nwl, &nwp);
                   1206:                server_set_marked(ns, nwl, nwp);
                   1207:                mode_tree_build(data->data);
                   1208:                break;
                   1209:        case 'M':
                   1210:                server_clear_marked();
                   1211:                mode_tree_build(data->data);
1.30      nicm     1212:                break;
                   1213:        case 'x':
                   1214:                window_tree_pull_item(item, &ns, &nwl, &nwp);
                   1215:                switch (item->type) {
                   1216:                case WINDOW_TREE_NONE:
                   1217:                        break;
                   1218:                case WINDOW_TREE_SESSION:
                   1219:                        if (ns == NULL)
                   1220:                                break;
                   1221:                        xasprintf(&prompt, "Kill session %s? ", ns->name);
                   1222:                        break;
                   1223:                case WINDOW_TREE_WINDOW:
                   1224:                        if (nwl == NULL)
                   1225:                                break;
                   1226:                        xasprintf(&prompt, "Kill window %u? ", nwl->idx);
                   1227:                        break;
                   1228:                case WINDOW_TREE_PANE:
                   1229:                        if (nwp == NULL || window_pane_index(nwp, &idx) != 0)
                   1230:                                break;
                   1231:                        xasprintf(&prompt, "Kill pane %u? ", idx);
                   1232:                        break;
                   1233:                }
                   1234:                if (prompt == NULL)
                   1235:                        break;
                   1236:                data->references++;
1.50      nicm     1237:                status_prompt_set(c, NULL, prompt, "",
1.30      nicm     1238:                    window_tree_kill_current_callback, window_tree_command_free,
                   1239:                    data, PROMPT_SINGLE|PROMPT_NOFORMAT);
                   1240:                free(prompt);
                   1241:                break;
                   1242:        case 'X':
                   1243:                tagged = mode_tree_count_tagged(data->data);
                   1244:                if (tagged == 0)
                   1245:                        break;
                   1246:                xasprintf(&prompt, "Kill %u tagged? ", tagged);
                   1247:                data->references++;
1.50      nicm     1248:                status_prompt_set(c, NULL, prompt, "",
1.30      nicm     1249:                    window_tree_kill_tagged_callback, window_tree_command_free,
                   1250:                    data, PROMPT_SINGLE|PROMPT_NOFORMAT);
                   1251:                free(prompt);
1.11      nicm     1252:                break;
1.1       nicm     1253:        case ':':
                   1254:                tagged = mode_tree_count_tagged(data->data);
                   1255:                if (tagged != 0)
                   1256:                        xasprintf(&prompt, "(%u tagged) ", tagged);
                   1257:                else
                   1258:                        xasprintf(&prompt, "(current) ");
                   1259:                data->references++;
1.50      nicm     1260:                status_prompt_set(c, NULL, prompt, "",
                   1261:                    window_tree_command_callback, window_tree_command_free,
                   1262:                    data, PROMPT_NOFORMAT);
1.1       nicm     1263:                free(prompt);
                   1264:                break;
                   1265:        case '\r':
                   1266:                name = window_tree_get_target(item, &fs);
                   1267:                if (name != NULL)
1.21      nicm     1268:                        mode_tree_run_command(c, NULL, data->command, name);
                   1269:                finished = 1;
1.1       nicm     1270:                free(name);
1.21      nicm     1271:                break;
1.1       nicm     1272:        }
                   1273:        if (finished)
                   1274:                window_pane_reset_mode(wp);
                   1275:        else {
                   1276:                mode_tree_draw(data->data);
                   1277:                wp->flags |= PANE_REDRAW;
                   1278:        }
                   1279: }