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

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