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

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