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

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