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

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