[BACK]Return to window-client.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/window-client.c, Revision 1.21

1.21    ! nicm        1: /* $OpenBSD: window-client.c,v 1.20 2019/03/18 14:10:25 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: #include <sys/time.h>
                     21:
                     22: #include <stdlib.h>
                     23: #include <string.h>
1.2       nicm       24: #include <time.h>
1.1       nicm       25:
                     26: #include "tmux.h"
                     27:
1.16      nicm       28: static struct screen   *window_client_init(struct window_mode_entry *,
1.1       nicm       29:                             struct cmd_find_state *, struct args *);
1.16      nicm       30: static void             window_client_free(struct window_mode_entry *);
                     31: static void             window_client_resize(struct window_mode_entry *, u_int,
1.1       nicm       32:                             u_int);
1.16      nicm       33: static void             window_client_key(struct window_mode_entry *,
1.15      nicm       34:                             struct client *, struct session *,
                     35:                             struct winlink *, key_code, struct mouse_event *);
1.1       nicm       36:
                     37: #define WINDOW_CLIENT_DEFAULT_COMMAND "detach-client -t '%%'"
                     38:
1.8       nicm       39: #define WINDOW_CLIENT_DEFAULT_FORMAT \
                     40:        "session #{session_name} " \
                     41:        "(#{client_width}x#{client_height}, #{t:client_activity})"
                     42:
1.1       nicm       43: const struct window_mode window_client_mode = {
                     44:        .name = "client-mode",
1.20      nicm       45:        .default_format = WINDOW_CLIENT_DEFAULT_FORMAT,
1.1       nicm       46:
                     47:        .init = window_client_init,
                     48:        .free = window_client_free,
                     49:        .resize = window_client_resize,
                     50:        .key = window_client_key,
                     51: };
                     52:
                     53: enum window_client_sort_type {
                     54:        WINDOW_CLIENT_BY_NAME,
1.4       nicm       55:        WINDOW_CLIENT_BY_SIZE,
1.1       nicm       56:        WINDOW_CLIENT_BY_CREATION_TIME,
                     57:        WINDOW_CLIENT_BY_ACTIVITY_TIME,
                     58: };
                     59: static const char *window_client_sort_list[] = {
                     60:        "name",
1.4       nicm       61:        "size",
1.5       nicm       62:        "creation",
                     63:        "activity"
1.1       nicm       64: };
                     65:
                     66: struct window_client_itemdata {
                     67:        struct client   *c;
                     68: };
                     69:
                     70: struct window_client_modedata {
                     71:        struct mode_tree_data            *data;
1.8       nicm       72:        char                             *format;
1.1       nicm       73:        char                             *command;
                     74:
                     75:        struct window_client_itemdata   **item_list;
                     76:        u_int                             item_size;
                     77: };
                     78:
                     79: static struct window_client_itemdata *
                     80: window_client_add_item(struct window_client_modedata *data)
                     81: {
                     82:        struct window_client_itemdata   *item;
                     83:
                     84:        data->item_list = xreallocarray(data->item_list, data->item_size + 1,
                     85:            sizeof *data->item_list);
                     86:        item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
                     87:        return (item);
                     88: }
                     89:
                     90: static void
                     91: window_client_free_item(struct window_client_itemdata *item)
                     92: {
                     93:        server_client_unref(item->c);
                     94:        free(item);
                     95: }
                     96:
                     97: static int
                     98: window_client_cmp_name(const void *a0, const void *b0)
                     99: {
                    100:        const struct window_client_itemdata *const *a = a0;
                    101:        const struct window_client_itemdata *const *b = b0;
                    102:
                    103:        return (strcmp((*a)->c->name, (*b)->c->name));
                    104: }
                    105:
                    106: static int
1.4       nicm      107: window_client_cmp_size(const void *a0, const void *b0)
                    108: {
                    109:        const struct window_client_itemdata *const *a = a0;
                    110:        const struct window_client_itemdata *const *b = b0;
                    111:
                    112:        if ((*a)->c->tty.sx < (*b)->c->tty.sx)
                    113:                return (-1);
                    114:        if ((*a)->c->tty.sx > (*b)->c->tty.sx)
                    115:                return (1);
                    116:        if ((*a)->c->tty.sy < (*b)->c->tty.sy)
                    117:                return (-1);
                    118:        if ((*a)->c->tty.sy > (*b)->c->tty.sy)
                    119:                return (1);
                    120:        return (strcmp((*a)->c->name, (*b)->c->name));
                    121: }
                    122:
                    123: static int
1.1       nicm      124: window_client_cmp_creation_time(const void *a0, const void *b0)
                    125: {
                    126:        const struct window_client_itemdata *const *a = a0;
                    127:        const struct window_client_itemdata *const *b = b0;
                    128:
                    129:        if (timercmp(&(*a)->c->creation_time, &(*b)->c->creation_time, >))
                    130:                return (-1);
                    131:        if (timercmp(&(*a)->c->creation_time, &(*b)->c->creation_time, <))
                    132:                return (1);
1.4       nicm      133:        return (strcmp((*a)->c->name, (*b)->c->name));
1.1       nicm      134: }
                    135:
                    136: static int
                    137: window_client_cmp_activity_time(const void *a0, const void *b0)
                    138: {
                    139:        const struct window_client_itemdata *const *a = a0;
                    140:        const struct window_client_itemdata *const *b = b0;
                    141:
                    142:        if (timercmp(&(*a)->c->activity_time, &(*b)->c->activity_time, >))
                    143:                return (-1);
                    144:        if (timercmp(&(*a)->c->activity_time, &(*b)->c->activity_time, <))
                    145:                return (1);
1.4       nicm      146:        return (strcmp((*a)->c->name, (*b)->c->name));
1.1       nicm      147: }
                    148:
                    149: static void
1.6       nicm      150: window_client_build(void *modedata, u_int sort_type, __unused uint64_t *tag,
                    151:     const char *filter)
1.1       nicm      152: {
                    153:        struct window_client_modedata   *data = modedata;
                    154:        struct window_client_itemdata   *item;
                    155:        u_int                            i;
                    156:        struct client                   *c;
1.8       nicm      157:        char                            *text, *cp;
1.1       nicm      158:
                    159:        for (i = 0; i < data->item_size; i++)
                    160:                window_client_free_item(data->item_list[i]);
                    161:        free(data->item_list);
                    162:        data->item_list = NULL;
                    163:        data->item_size = 0;
                    164:
                    165:        TAILQ_FOREACH(c, &clients, entry) {
                    166:                if (c->session == NULL || (c->flags & (CLIENT_DETACHING)))
                    167:                        continue;
                    168:
                    169:                item = window_client_add_item(data);
                    170:                item->c = c;
                    171:
                    172:                c->references++;
                    173:        }
                    174:
                    175:        switch (sort_type) {
                    176:        case WINDOW_CLIENT_BY_NAME:
                    177:                qsort(data->item_list, data->item_size, sizeof *data->item_list,
                    178:                    window_client_cmp_name);
                    179:                break;
1.4       nicm      180:        case WINDOW_CLIENT_BY_SIZE:
                    181:                qsort(data->item_list, data->item_size, sizeof *data->item_list,
                    182:                    window_client_cmp_size);
                    183:                break;
1.1       nicm      184:        case WINDOW_CLIENT_BY_CREATION_TIME:
                    185:                qsort(data->item_list, data->item_size, sizeof *data->item_list,
                    186:                    window_client_cmp_creation_time);
                    187:                break;
                    188:        case WINDOW_CLIENT_BY_ACTIVITY_TIME:
                    189:                qsort(data->item_list, data->item_size, sizeof *data->item_list,
                    190:                    window_client_cmp_activity_time);
                    191:                break;
                    192:        }
                    193:
                    194:        for (i = 0; i < data->item_size; i++) {
                    195:                item = data->item_list[i];
                    196:                c = item->c;
1.6       nicm      197:
                    198:                if (filter != NULL) {
                    199:                        cp = format_single(NULL, filter, c, NULL, NULL, NULL);
                    200:                        if (!format_true(cp)) {
                    201:                                free(cp);
                    202:                                continue;
                    203:                        }
                    204:                        free(cp);
                    205:                }
1.1       nicm      206:
1.8       nicm      207:                text = format_single(NULL, data->format, c, NULL, NULL, NULL);
1.1       nicm      208:                mode_tree_add(data->data, NULL, item, (uint64_t)c, c->name,
                    209:                    text, -1);
                    210:                free(text);
                    211:        }
                    212: }
                    213:
1.11      nicm      214: static void
                    215: window_client_draw(__unused void *modedata, void *itemdata,
                    216:     struct screen_write_ctx *ctx, u_int sx, u_int sy)
1.1       nicm      217: {
                    218:        struct window_client_itemdata   *item = itemdata;
                    219:        struct client                   *c = item->c;
1.21    ! nicm      220:        struct screen                   *s = ctx->s;
1.1       nicm      221:        struct window_pane              *wp;
1.21    ! nicm      222:        u_int                            cx = s->cx, cy = s->cy, lines, at;
1.1       nicm      223:
                    224:        if (c->session == NULL || (c->flags & (CLIENT_DEAD|CLIENT_DETACHING)))
1.11      nicm      225:                return;
1.1       nicm      226:        wp = c->session->curw->window->active;
                    227:
1.21    ! nicm      228:        lines = status_line_size(c);
        !           229:        if (lines >= sy)
        !           230:                lines = 0;
        !           231:        if (status_at_line(c) == 0)
        !           232:                at = lines;
        !           233:        else
        !           234:                at = 0;
        !           235:
        !           236:        screen_write_cursormove(ctx, cx, cy + at, 0);
        !           237:        screen_write_preview(ctx, &wp->base, sx, sy - 2 - lines);
        !           238:
        !           239:        if (at != 0)
        !           240:                screen_write_cursormove(ctx, cx, cy + 2, 0);
        !           241:        else
        !           242:                screen_write_cursormove(ctx, cx, cy + sy - 1 - lines, 0);
1.11      nicm      243:        screen_write_hline(ctx, sx, 0, 0);
1.1       nicm      244:
1.21    ! nicm      245:        if (at != 0)
        !           246:                screen_write_cursormove(ctx, cx, cy, 0);
        !           247:        else
        !           248:                screen_write_cursormove(ctx, cx, cy + sy - lines, 0);
        !           249:        screen_write_fast_copy(ctx, &c->status.screen, 0, 0, sx, lines);
1.1       nicm      250: }
                    251:
                    252: static struct screen *
1.16      nicm      253: window_client_init(struct window_mode_entry *wme,
                    254:     __unused struct cmd_find_state *fs, struct args *args)
1.1       nicm      255: {
1.16      nicm      256:        struct window_pane              *wp = wme->wp;
1.1       nicm      257:        struct window_client_modedata   *data;
                    258:        struct screen                   *s;
                    259:
1.16      nicm      260:        wme->data = data = xcalloc(1, sizeof *data);
1.1       nicm      261:
1.8       nicm      262:        if (args == NULL || !args_has(args, 'F'))
                    263:                data->format = xstrdup(WINDOW_CLIENT_DEFAULT_FORMAT);
                    264:        else
                    265:                data->format = xstrdup(args_get(args, 'F'));
1.1       nicm      266:        if (args == NULL || args->argc == 0)
                    267:                data->command = xstrdup(WINDOW_CLIENT_DEFAULT_COMMAND);
                    268:        else
                    269:                data->command = xstrdup(args->argv[0]);
                    270:
1.5       nicm      271:        data->data = mode_tree_start(wp, args, window_client_build,
1.3       nicm      272:            window_client_draw, NULL, data, window_client_sort_list,
1.1       nicm      273:            nitems(window_client_sort_list), &s);
1.14      nicm      274:        mode_tree_zoom(data->data, args);
1.1       nicm      275:
                    276:        mode_tree_build(data->data);
                    277:        mode_tree_draw(data->data);
                    278:
                    279:        return (s);
                    280: }
                    281:
                    282: static void
1.16      nicm      283: window_client_free(struct window_mode_entry *wme)
1.1       nicm      284: {
1.16      nicm      285:        struct window_client_modedata   *data = wme->data;
1.1       nicm      286:        u_int                            i;
                    287:
                    288:        if (data == NULL)
                    289:                return;
                    290:
                    291:        mode_tree_free(data->data);
                    292:
                    293:        for (i = 0; i < data->item_size; i++)
                    294:                window_client_free_item(data->item_list[i]);
                    295:        free(data->item_list);
                    296:
1.8       nicm      297:        free(data->format);
1.1       nicm      298:        free(data->command);
1.8       nicm      299:
1.1       nicm      300:        free(data);
                    301: }
                    302:
                    303: static void
1.16      nicm      304: window_client_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
1.1       nicm      305: {
1.16      nicm      306:        struct window_client_modedata   *data = wme->data;
1.1       nicm      307:
                    308:        mode_tree_resize(data->data, sx, sy);
                    309: }
                    310:
                    311: static void
1.9       nicm      312: window_client_do_detach(void* modedata, void *itemdata,
                    313:     __unused struct client *c, key_code key)
1.1       nicm      314: {
                    315:        struct window_client_modedata   *data = modedata;
                    316:        struct window_client_itemdata   *item = itemdata;
                    317:
                    318:        if (item == mode_tree_get_current(data->data))
                    319:                mode_tree_down(data->data, 0);
                    320:        if (key == 'd' || key == 'D')
                    321:                server_client_detach(item->c, MSG_DETACH);
                    322:        else if (key == 'x' || key == 'X')
                    323:                server_client_detach(item->c, MSG_DETACHKILL);
                    324:        else if (key == 'z' || key == 'Z')
                    325:                server_client_suspend(item->c);
                    326: }
                    327:
                    328: static void
1.16      nicm      329: window_client_key(struct window_mode_entry *wme, struct client *c,
1.15      nicm      330:     __unused struct session *s, __unused struct winlink *wl, key_code key,
                    331:     struct mouse_event *m)
1.1       nicm      332: {
1.16      nicm      333:        struct window_pane              *wp = wme->wp;
                    334:        struct window_client_modedata   *data = wme->data;
1.9       nicm      335:        struct mode_tree_data           *mtd = data->data;
1.1       nicm      336:        struct window_client_itemdata   *item;
                    337:        int                              finished;
                    338:
1.12      nicm      339:        finished = mode_tree_key(mtd, c, &key, m, NULL, NULL);
1.1       nicm      340:        switch (key) {
                    341:        case 'd':
                    342:        case 'x':
                    343:        case 'z':
1.9       nicm      344:                item = mode_tree_get_current(mtd);
                    345:                window_client_do_detach(data, item, c, key);
                    346:                mode_tree_build(mtd);
1.1       nicm      347:                break;
                    348:        case 'D':
                    349:        case 'X':
                    350:        case 'Z':
1.9       nicm      351:                mode_tree_each_tagged(mtd, window_client_do_detach, c, key, 0);
                    352:                mode_tree_build(mtd);
1.1       nicm      353:                break;
                    354:        case '\r':
1.9       nicm      355:                item = mode_tree_get_current(mtd);
                    356:                mode_tree_run_command(c, NULL, data->command, item->c->ttyname);
                    357:                finished = 1;
                    358:                break;
1.1       nicm      359:        }
                    360:        if (finished || server_client_how_many() == 0)
                    361:                window_pane_reset_mode(wp);
                    362:        else {
1.9       nicm      363:                mode_tree_draw(mtd);
1.1       nicm      364:                wp->flags |= PANE_REDRAW;
                    365:        }
                    366: }