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

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