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

Annotation of src/usr.bin/tmux/screen-redraw.c, Revision 1.91

1.91    ! nicm        1: /* $OpenBSD: screen-redraw.c,v 1.90 2021/10/14 13:19:01 nicm Exp $ */
1.1       nicm        2:
                      3: /*
1.35      nicm        4:  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1       nicm        5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
                     15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
                     16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20:
1.48      nicm       21: #include <stdlib.h>
1.1       nicm       22: #include <string.h>
                     23:
                     24: #include "tmux.h"
                     25:
1.50      nicm       26: static void    screen_redraw_draw_borders(struct screen_redraw_ctx *);
                     27: static void    screen_redraw_draw_panes(struct screen_redraw_ctx *);
                     28: static void    screen_redraw_draw_status(struct screen_redraw_ctx *);
1.55      nicm       29: static void    screen_redraw_draw_pane(struct screen_redraw_ctx *,
                     30:                    struct window_pane *);
1.79      nicm       31: static void    screen_redraw_set_context(struct client *,
                     32:                    struct screen_redraw_ctx *);
1.1       nicm       33:
1.83      nicm       34: #define START_ISOLATE "\342\201\246"
                     35: #define END_ISOLATE   "\342\201\251"
                     36:
1.75      nicm       37: enum screen_redraw_border_type {
                     38:        SCREEN_REDRAW_OUTSIDE,
                     39:        SCREEN_REDRAW_INSIDE,
                     40:        SCREEN_REDRAW_BORDER
                     41: };
                     42:
1.78      nicm       43: /* Get cell border character. */
                     44: static void
1.90      nicm       45: screen_redraw_border_set(struct window_pane *wp, enum pane_lines pane_lines,
                     46:     int cell_type, struct grid_cell *gc)
1.78      nicm       47: {
                     48:        u_int   idx;
                     49:
                     50:        switch (pane_lines) {
                     51:        case PANE_LINES_NUMBER:
                     52:                if (cell_type == CELL_OUTSIDE) {
                     53:                        gc->attr |= GRID_ATTR_CHARSET;
                     54:                        utf8_set(&gc->data, CELL_BORDERS[CELL_OUTSIDE]);
                     55:                        break;
                     56:                }
                     57:                gc->attr &= ~GRID_ATTR_CHARSET;
                     58:                if (wp != NULL && window_pane_index(wp, &idx) == 0)
                     59:                        utf8_set(&gc->data, '0' + (idx % 10));
                     60:                else
                     61:                        utf8_set(&gc->data, '*');
                     62:                break;
                     63:        case PANE_LINES_DOUBLE:
                     64:                gc->attr &= ~GRID_ATTR_CHARSET;
1.90      nicm       65:                utf8_copy(&gc->data, tty_acs_double_borders(cell_type));
1.78      nicm       66:                break;
                     67:        case PANE_LINES_HEAVY:
                     68:                gc->attr &= ~GRID_ATTR_CHARSET;
1.90      nicm       69:                utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type));
1.78      nicm       70:                break;
                     71:        case PANE_LINES_SIMPLE:
                     72:                gc->attr &= ~GRID_ATTR_CHARSET;
1.90      nicm       73:                utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]);
1.78      nicm       74:                break;
                     75:        default:
                     76:                gc->attr |= GRID_ATTR_CHARSET;
                     77:                utf8_set(&gc->data, CELL_BORDERS[cell_type]);
                     78:                break;
                     79:        }
                     80: }
                     81:
1.75      nicm       82: /* Return if window has only two panes. */
1.39      nicm       83: static int
1.75      nicm       84: screen_redraw_two_panes(struct window *w, int direction)
1.15      nicm       85: {
1.75      nicm       86:        struct window_pane      *wp;
                     87:
                     88:        wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
                     89:        if (wp == NULL)
                     90:                return (0); /* one pane */
                     91:        if (TAILQ_NEXT(wp, entry) != NULL)
                     92:                return (0); /* more than two panes */
                     93:        if (direction == 0 && wp->xoff == 0)
                     94:                return (0);
                     95:        if (direction == 1 && wp->yoff == 0)
                     96:                return (0);
                     97:        return (1);
                     98: }
                     99:
                    100: /* Check if cell is on the border of a pane. */
                    101: static enum screen_redraw_border_type
                    102: screen_redraw_pane_border(struct window_pane *wp, u_int px, u_int py,
                    103:     int pane_status)
                    104: {
                    105:        u_int   ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
                    106:
1.15      nicm      107:        /* Inside pane. */
1.75      nicm      108:        if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
                    109:                return (SCREEN_REDRAW_INSIDE);
1.15      nicm      110:
                    111:        /* Left/right borders. */
1.75      nicm      112:        if (pane_status == PANE_STATUS_OFF) {
                    113:                if (screen_redraw_two_panes(wp->window, 0)) {
                    114:                        if (wp->xoff == 0 && px == wp->sx && py <= wp->sy / 2)
                    115:                                return (SCREEN_REDRAW_BORDER);
                    116:                        if (wp->xoff != 0 &&
                    117:                            px == wp->xoff - 1 &&
                    118:                            py > wp->sy / 2)
                    119:                                return (SCREEN_REDRAW_BORDER);
                    120:                } else {
                    121:                        if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
                    122:                                if (wp->xoff != 0 && px == wp->xoff - 1)
                    123:                                        return (SCREEN_REDRAW_BORDER);
                    124:                                if (px == ex)
                    125:                                        return (SCREEN_REDRAW_BORDER);
                    126:                        }
                    127:                }
                    128:        } else {
                    129:                if ((wp->yoff == 0 || py >= wp->yoff - 1) && py <= ey) {
                    130:                        if (wp->xoff != 0 && px == wp->xoff - 1)
                    131:                                return (SCREEN_REDRAW_BORDER);
                    132:                        if (px == ex)
                    133:                                return (SCREEN_REDRAW_BORDER);
                    134:                }
1.15      nicm      135:        }
                    136:
                    137:        /* Top/bottom borders. */
1.75      nicm      138:        if (pane_status == PANE_STATUS_OFF) {
                    139:                if (screen_redraw_two_panes(wp->window, 1)) {
                    140:                        if (wp->yoff == 0 && py == wp->sy && px <= wp->sx / 2)
                    141:                                return (SCREEN_REDRAW_BORDER);
                    142:                        if (wp->yoff != 0 &&
                    143:                            py == wp->yoff - 1 &&
                    144:                            px > wp->sx / 2)
                    145:                                return (SCREEN_REDRAW_BORDER);
                    146:                } else {
                    147:                        if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
                    148:                                if (wp->yoff != 0 && py == wp->yoff - 1)
                    149:                                        return (SCREEN_REDRAW_BORDER);
                    150:                                if (py == ey)
                    151:                                        return (SCREEN_REDRAW_BORDER);
                    152:                        }
                    153:                }
                    154:        } else if (pane_status == PANE_STATUS_TOP) {
                    155:                if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
                    156:                        if (wp->yoff != 0 && py == wp->yoff - 1)
                    157:                                return (SCREEN_REDRAW_BORDER);
                    158:                }
                    159:        } else {
                    160:                if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= ex) {
                    161:                        if (py == ey)
                    162:                                return (SCREEN_REDRAW_BORDER);
                    163:                }
1.15      nicm      164:        }
                    165:
                    166:        /* Outside pane. */
1.75      nicm      167:        return (SCREEN_REDRAW_OUTSIDE);
1.15      nicm      168: }
                    169:
1.75      nicm      170: /* Check if a cell is on a border. */
1.39      nicm      171: static int
1.75      nicm      172: screen_redraw_cell_border(struct client *c, u_int px, u_int py, int pane_status)
1.1       nicm      173: {
                    174:        struct window           *w = c->session->curw->window;
                    175:        struct window_pane      *wp;
1.75      nicm      176:
                    177:        /* Outside the window? */
                    178:        if (px > w->sx || py > w->sy)
                    179:                return (0);
                    180:
                    181:        /* On the window border? */
                    182:        if (px == w->sx || py == w->sy)
                    183:                return (1);
1.1       nicm      184:
1.7       nicm      185:        /* Check all the panes. */
1.1       nicm      186:        TAILQ_FOREACH(wp, &w->panes, entry) {
1.3       nicm      187:                if (!window_pane_visible(wp))
                    188:                        continue;
1.75      nicm      189:                switch (screen_redraw_pane_border(wp, px, py, pane_status)) {
                    190:                case SCREEN_REDRAW_INSIDE:
                    191:                        return (0);
                    192:                case SCREEN_REDRAW_BORDER:
                    193:                        return (1);
                    194:                case SCREEN_REDRAW_OUTSIDE:
                    195:                        break;
                    196:                }
1.7       nicm      197:        }
                    198:
                    199:        return (0);
                    200: }
                    201:
1.75      nicm      202: /* Work out type of border cell from surrounding cells. */
                    203: static int
                    204: screen_redraw_type_of_cell(struct client *c, u_int px, u_int py,
                    205:     int pane_status)
                    206: {
                    207:        struct window   *w = c->session->curw->window;
                    208:        u_int            sx = w->sx, sy = w->sy;
                    209:        int              borders = 0;
                    210:
1.79      nicm      211:        /* Is this outside the window? */
1.81      nicm      212:        if (px > sx || py > sy)
1.79      nicm      213:                return (CELL_OUTSIDE);
                    214:
1.75      nicm      215:        /*
                    216:         * Construct a bitmask of whether the cells to the left (bit 4), right,
                    217:         * top, and bottom (bit 1) of this cell are borders.
                    218:         */
                    219:        if (px == 0 || screen_redraw_cell_border(c, px - 1, py, pane_status))
                    220:                borders |= 8;
                    221:        if (px <= sx && screen_redraw_cell_border(c, px + 1, py, pane_status))
                    222:                borders |= 4;
                    223:        if (pane_status == PANE_STATUS_TOP) {
                    224:                if (py != 0 &&
                    225:                    screen_redraw_cell_border(c, px, py - 1, pane_status))
                    226:                        borders |= 2;
1.79      nicm      227:                if (screen_redraw_cell_border(c, px, py + 1, pane_status))
                    228:                        borders |= 1;
1.80      nicm      229:        } else if (pane_status == PANE_STATUS_BOTTOM) {
1.75      nicm      230:                if (py == 0 ||
                    231:                    screen_redraw_cell_border(c, px, py - 1, pane_status))
1.79      nicm      232:                        borders |= 2;
                    233:                if (py != sy - 1 &&
                    234:                    screen_redraw_cell_border(c, px, py + 1, pane_status))
1.80      nicm      235:                        borders |= 1;
                    236:        } else {
                    237:                if (py == 0 ||
                    238:                    screen_redraw_cell_border(c, px, py - 1, pane_status))
                    239:                        borders |= 2;
                    240:                if (screen_redraw_cell_border(c, px, py + 1, pane_status))
1.79      nicm      241:                        borders |= 1;
1.75      nicm      242:        }
                    243:
                    244:        /*
                    245:         * Figure out what kind of border this cell is. Only one bit set
                    246:         * doesn't make sense (can't have a border cell with no others
                    247:         * connected).
                    248:         */
                    249:        switch (borders) {
                    250:        case 15:        /* 1111, left right top bottom */
                    251:                return (CELL_JOIN);
                    252:        case 14:        /* 1110, left right top */
                    253:                return (CELL_BOTTOMJOIN);
                    254:        case 13:        /* 1101, left right bottom */
                    255:                return (CELL_TOPJOIN);
                    256:        case 12:        /* 1100, left right */
1.83      nicm      257:                return (CELL_LEFTRIGHT);
1.75      nicm      258:        case 11:        /* 1011, left top bottom */
                    259:                return (CELL_RIGHTJOIN);
                    260:        case 10:        /* 1010, left top */
                    261:                return (CELL_BOTTOMRIGHT);
                    262:        case 9:         /* 1001, left bottom */
                    263:                return (CELL_TOPRIGHT);
                    264:        case 7:         /* 0111, right top bottom */
                    265:                return (CELL_LEFTJOIN);
                    266:        case 6:         /* 0110, right top */
                    267:                return (CELL_BOTTOMLEFT);
                    268:        case 5:         /* 0101, right bottom */
                    269:                return (CELL_TOPLEFT);
                    270:        case 3:         /* 0011, top bottom */
1.83      nicm      271:                return (CELL_TOPBOTTOM);
1.75      nicm      272:        }
                    273:        return (CELL_OUTSIDE);
                    274: }
                    275:
1.7       nicm      276: /* Check if cell inside a pane. */
1.39      nicm      277: static int
1.36      nicm      278: screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
1.24      nicm      279:     struct window_pane **wpp)
1.7       nicm      280: {
                    281:        struct window           *w = c->session->curw->window;
1.77      nicm      282:        struct window_pane      *wp, *active;
1.75      nicm      283:        int                      border;
1.36      nicm      284:        u_int                    right, line;
1.7       nicm      285:
1.39      nicm      286:        *wpp = NULL;
                    287:
1.81      nicm      288:        if (px > w->sx || py > w->sy)
1.7       nicm      289:                return (CELL_OUTSIDE);
1.75      nicm      290:        if (px == w->sx || py == w->sy) /* window border */
                    291:                return (screen_redraw_type_of_cell(c, px, py, pane_status));
1.7       nicm      292:
1.64      nicm      293:        if (pane_status != PANE_STATUS_OFF) {
1.77      nicm      294:                active = wp = server_client_get_pane(c);
1.75      nicm      295:                do {
1.36      nicm      296:                        if (!window_pane_visible(wp))
1.75      nicm      297:                                goto next1;
1.36      nicm      298:
1.64      nicm      299:                        if (pane_status == PANE_STATUS_TOP)
1.36      nicm      300:                                line = wp->yoff - 1;
                    301:                        else
                    302:                                line = wp->yoff + wp->sy;
                    303:                        right = wp->xoff + 2 + wp->status_size - 1;
                    304:
                    305:                        if (py == line && px >= wp->xoff + 2 && px <= right)
                    306:                                return (CELL_INSIDE);
1.75      nicm      307:
                    308:                next1:
                    309:                        wp = TAILQ_NEXT(wp, entry);
                    310:                        if (wp == NULL)
                    311:                                wp = TAILQ_FIRST(&w->panes);
1.77      nicm      312:                } while (wp != active);
1.36      nicm      313:        }
                    314:
1.77      nicm      315:        active = wp = server_client_get_pane(c);
1.75      nicm      316:        do {
1.7       nicm      317:                if (!window_pane_visible(wp))
1.75      nicm      318:                        goto next2;
1.24      nicm      319:                *wpp = wp;
1.7       nicm      320:
1.14      nicm      321:                /*
1.75      nicm      322:                 * If definitely inside, return. If not on border, skip.
                    323:                 * Otherwise work out the cell.
1.7       nicm      324:                 */
1.75      nicm      325:                border = screen_redraw_pane_border(wp, px, py, pane_status);
                    326:                if (border == SCREEN_REDRAW_INSIDE)
                    327:                        return (CELL_INSIDE);
                    328:                if (border == SCREEN_REDRAW_OUTSIDE)
                    329:                        goto next2;
                    330:                return (screen_redraw_type_of_cell(c, px, py, pane_status));
                    331:
                    332:        next2:
                    333:                wp = TAILQ_NEXT(wp, entry);
                    334:                if (wp == NULL)
                    335:                        wp = TAILQ_FIRST(&w->panes);
1.77      nicm      336:        } while (wp != active);
1.1       nicm      337:
1.6       nicm      338:        return (CELL_OUTSIDE);
1.1       nicm      339: }
                    340:
1.32      nicm      341: /* Check if the border of a particular pane. */
1.39      nicm      342: static int
1.75      nicm      343: screen_redraw_check_is(u_int px, u_int py, int pane_status,
                    344:     struct window_pane *wp)
1.24      nicm      345: {
1.75      nicm      346:        enum screen_redraw_border_type  border;
1.36      nicm      347:
1.75      nicm      348:        border = screen_redraw_pane_border(wp, px, py, pane_status);
                    349:        if (border == SCREEN_REDRAW_BORDER)
1.24      nicm      350:                return (1);
1.75      nicm      351:        return (0);
1.36      nicm      352: }
                    353:
                    354: /* Update pane status. */
1.39      nicm      355: static int
1.79      nicm      356: screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
1.90      nicm      357:     struct screen_redraw_ctx *rctx, enum pane_lines pane_lines)
1.36      nicm      358: {
1.79      nicm      359:        struct window           *w = wp->window;
1.36      nicm      360:        struct grid_cell         gc;
                    361:        const char              *fmt;
                    362:        struct format_tree      *ft;
1.59      nicm      363:        char                    *expanded;
1.79      nicm      364:        int                      pane_status = rctx->pane_status;
1.82      nicm      365:        u_int                    width, i, cell_type, px, py;
1.36      nicm      366:        struct screen_write_ctx  ctx;
1.40      nicm      367:        struct screen            old;
1.36      nicm      368:
1.75      nicm      369:        ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
                    370:        format_defaults(ft, c, c->session, c->session->curw, wp);
                    371:
1.77      nicm      372:        if (wp == server_client_get_pane(c))
1.75      nicm      373:                style_apply(&gc, w->options, "pane-active-border-style", ft);
1.36      nicm      374:        else
1.75      nicm      375:                style_apply(&gc, w->options, "pane-border-style", ft);
1.36      nicm      376:        fmt = options_get_string(w->options, "pane-border-format");
                    377:
1.59      nicm      378:        expanded = format_expand_time(ft, fmt);
1.60      nicm      379:        if (wp->sx < 4)
                    380:                wp->status_size = width = 0;
                    381:        else
                    382:                wp->status_size = width = wp->sx - 4;
1.59      nicm      383:
1.40      nicm      384:        memcpy(&old, &wp->status_screen, sizeof old);
1.59      nicm      385:        screen_init(&wp->status_screen, width, 1, 0);
1.36      nicm      386:        wp->status_screen.mode = 0;
                    387:
1.76      nicm      388:        screen_write_start(&ctx, &wp->status_screen);
1.59      nicm      389:
1.79      nicm      390:        for (i = 0; i < width; i++) {
                    391:                px = wp->xoff + 2 + i;
                    392:                if (rctx->pane_status == PANE_STATUS_TOP)
1.82      nicm      393:                        py = wp->yoff - 1;
1.79      nicm      394:                else
1.82      nicm      395:                        py = wp->yoff + wp->sy;
1.79      nicm      396:                cell_type = screen_redraw_type_of_cell(c, px, py, pane_status);
                    397:                screen_redraw_border_set(wp, pane_lines, cell_type, &gc);
1.78      nicm      398:                screen_write_cell(&ctx, &gc);
1.79      nicm      399:        }
1.59      nicm      400:        gc.attr &= ~GRID_ATTR_CHARSET;
1.36      nicm      401:
1.56      nicm      402:        screen_write_cursormove(&ctx, 0, 0, 0);
1.91    ! nicm      403:        format_draw(&ctx, &gc, width, expanded, NULL, 0);
1.36      nicm      404:        screen_write_stop(&ctx);
                    405:
1.59      nicm      406:        free(expanded);
1.36      nicm      407:        format_free(ft);
1.40      nicm      408:
                    409:        if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
                    410:                screen_free(&old);
                    411:                return (0);
                    412:        }
                    413:        screen_free(&old);
                    414:        return (1);
1.36      nicm      415: }
                    416:
                    417: /* Draw pane status. */
1.39      nicm      418: static void
1.52      nicm      419: screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
1.36      nicm      420: {
1.53      nicm      421:        struct client           *c = ctx->c;
1.36      nicm      422:        struct window           *w = c->session->curw->window;
                    423:        struct tty              *tty = &c->tty;
                    424:        struct window_pane      *wp;
1.55      nicm      425:        struct screen           *s;
                    426:        u_int                    i, x, width, xoff, yoff, size;
                    427:
                    428:        log_debug("%s: %s @%u", __func__, c->name, w->id);
1.36      nicm      429:
                    430:        TAILQ_FOREACH(wp, &w->panes, entry) {
1.40      nicm      431:                if (!window_pane_visible(wp))
                    432:                        continue;
1.55      nicm      433:                s = &wp->status_screen;
                    434:
                    435:                size = wp->status_size;
1.64      nicm      436:                if (ctx->pane_status == PANE_STATUS_TOP)
1.36      nicm      437:                        yoff = wp->yoff - 1;
                    438:                else
                    439:                        yoff = wp->yoff + wp->sy;
1.55      nicm      440:                xoff = wp->xoff + 2;
                    441:
                    442:                if (xoff + size <= ctx->ox ||
                    443:                    xoff >= ctx->ox + ctx->sx ||
                    444:                    yoff < ctx->oy ||
                    445:                    yoff >= ctx->oy + ctx->sy)
                    446:                        continue;
                    447:
                    448:                if (xoff >= ctx->ox && xoff + size <= ctx->ox + ctx->sx) {
                    449:                        /* All visible. */
                    450:                        i = 0;
                    451:                        x = xoff - ctx->ox;
                    452:                        width = size;
                    453:                } else if (xoff < ctx->ox && xoff + size > ctx->ox + ctx->sx) {
                    454:                        /* Both left and right not visible. */
                    455:                        i = ctx->ox;
                    456:                        x = 0;
                    457:                        width = ctx->sx;
                    458:                } else if (xoff < ctx->ox) {
                    459:                        /* Left not visible. */
                    460:                        i = ctx->ox - xoff;
                    461:                        x = 0;
                    462:                        width = size - i;
                    463:                } else {
                    464:                        /* Right not visible. */
                    465:                        i = 0;
                    466:                        x = xoff - ctx->ox;
                    467:                        width = size - x;
                    468:                }
1.36      nicm      469:
1.61      nicm      470:                if (ctx->statustop)
                    471:                        yoff += ctx->statuslines;
1.76      nicm      472:                tty_draw_line(tty, s, i, 0, width, x, yoff - ctx->oy,
                    473:                    &grid_default_cell, NULL);
1.36      nicm      474:        }
                    475:        tty_cursor(tty, 0, 0);
1.24      nicm      476: }
                    477:
1.38      nicm      478: /* Update status line and change flags if unchanged. */
1.54      nicm      479: static int
                    480: screen_redraw_update(struct client *c, int flags)
1.38      nicm      481: {
1.90      nicm      482:        struct window                   *w = c->session->curw->window;
                    483:        struct window_pane              *wp;
                    484:        struct options                  *wo = w->options;
                    485:        int                              redraw;
                    486:        enum pane_lines                  lines;
                    487:        struct screen_redraw_ctx         ctx;
1.38      nicm      488:
                    489:        if (c->message_string != NULL)
                    490:                redraw = status_message_redraw(c);
                    491:        else if (c->prompt_string != NULL)
                    492:                redraw = status_prompt_redraw(c);
                    493:        else
                    494:                redraw = status_redraw(c);
1.54      nicm      495:        if (!redraw && (~flags & CLIENT_REDRAWSTATUSALWAYS))
                    496:                flags &= ~CLIENT_REDRAWSTATUS;
1.38      nicm      497:
1.63      nicm      498:        if (c->overlay_draw != NULL)
                    499:                flags |= CLIENT_REDRAWOVERLAY;
                    500:
1.64      nicm      501:        if (options_get_number(wo, "pane-border-status") != PANE_STATUS_OFF) {
1.79      nicm      502:                screen_redraw_set_context(c, &ctx);
1.78      nicm      503:                lines = options_get_number(wo, "pane-border-lines");
1.38      nicm      504:                redraw = 0;
                    505:                TAILQ_FOREACH(wp, &w->panes, entry) {
1.79      nicm      506:                        if (screen_redraw_make_pane_status(c, wp, &ctx, lines))
1.38      nicm      507:                                redraw = 1;
                    508:                }
                    509:                if (redraw)
1.54      nicm      510:                        flags |= CLIENT_REDRAWBORDERS;
1.38      nicm      511:        }
1.54      nicm      512:        return (flags);
1.38      nicm      513: }
                    514:
1.52      nicm      515: /* Set up redraw context. */
                    516: static void
                    517: screen_redraw_set_context(struct client *c, struct screen_redraw_ctx *ctx)
                    518: {
1.53      nicm      519:        struct session  *s = c->session;
                    520:        struct options  *oo = s->options;
                    521:        struct window   *w = s->curw->window;
                    522:        struct options  *wo = w->options;
1.61      nicm      523:        u_int            lines;
1.52      nicm      524:
                    525:        memset(ctx, 0, sizeof *ctx);
                    526:        ctx->c = c;
                    527:
1.61      nicm      528:        lines = status_line_size(c);
1.55      nicm      529:        if (c->message_string != NULL || c->prompt_string != NULL)
1.61      nicm      530:                lines = (lines == 0) ? 1 : lines;
                    531:        if (lines != 0 && options_get_number(oo, "status-position") == 0)
                    532:                ctx->statustop = 1;
                    533:        ctx->statuslines = lines;
                    534:
1.52      nicm      535:        ctx->pane_status = options_get_number(wo, "pane-border-status");
1.78      nicm      536:        ctx->pane_lines = options_get_number(wo, "pane-border-lines");
1.52      nicm      537:
1.55      nicm      538:        tty_window_offset(&c->tty, &ctx->ox, &ctx->oy, &ctx->sx, &ctx->sy);
                    539:
                    540:        log_debug("%s: %s @%u ox=%u oy=%u sx=%u sy=%u %u/%d", __func__, c->name,
1.61      nicm      541:            w->id, ctx->ox, ctx->oy, ctx->sx, ctx->sy, ctx->statuslines,
                    542:            ctx->statustop);
1.52      nicm      543: }
                    544:
1.4       nicm      545: /* Redraw entire screen. */
1.1       nicm      546: void
1.53      nicm      547: screen_redraw_screen(struct client *c)
1.1       nicm      548: {
1.53      nicm      549:        struct screen_redraw_ctx        ctx;
1.54      nicm      550:        int                             flags;
1.18      nicm      551:
                    552:        if (c->flags & CLIENT_SUSPENDED)
                    553:                return;
1.1       nicm      554:
1.54      nicm      555:        flags = screen_redraw_update(c, c->flags);
1.74      nicm      556:        if ((flags & CLIENT_ALLREDRAWFLAGS) == 0)
                    557:                return;
                    558:
1.52      nicm      559:        screen_redraw_set_context(c, &ctx);
1.84      nicm      560:        tty_sync_start(&c->tty);
1.74      nicm      561:        tty_update_mode(&c->tty, c->tty.mode, NULL);
1.51      nicm      562:
1.54      nicm      563:        if (flags & (CLIENT_REDRAWWINDOW|CLIENT_REDRAWBORDERS)) {
1.70      nicm      564:                log_debug("%s: redrawing borders", c->name);
1.64      nicm      565:                if (ctx.pane_status != PANE_STATUS_OFF)
1.53      nicm      566:                        screen_redraw_draw_pane_status(&ctx);
1.50      nicm      567:                screen_redraw_draw_borders(&ctx);
1.53      nicm      568:        }
1.70      nicm      569:        if (flags & CLIENT_REDRAWWINDOW) {
                    570:                log_debug("%s: redrawing panes", c->name);
1.50      nicm      571:                screen_redraw_draw_panes(&ctx);
1.70      nicm      572:        }
1.61      nicm      573:        if (ctx.statuslines != 0 &&
1.70      nicm      574:            (flags & (CLIENT_REDRAWSTATUS|CLIENT_REDRAWSTATUSALWAYS))) {
                    575:                log_debug("%s: redrawing status", c->name);
1.50      nicm      576:                screen_redraw_draw_status(&ctx);
1.70      nicm      577:        }
                    578:        if (c->overlay_draw != NULL && (flags & CLIENT_REDRAWOVERLAY)) {
                    579:                log_debug("%s: redrawing overlay", c->name);
1.88      nicm      580:                c->overlay_draw(c, c->overlay_data, &ctx);
1.70      nicm      581:        }
1.67      nicm      582:
1.52      nicm      583:        tty_reset(&c->tty);
1.26      nicm      584: }
1.4       nicm      585:
1.55      nicm      586: /* Redraw a single pane. */
1.26      nicm      587: void
                    588: screen_redraw_pane(struct client *c, struct window_pane *wp)
                    589: {
1.55      nicm      590:        struct screen_redraw_ctx         ctx;
1.26      nicm      591:
1.85      nicm      592:        if (!window_pane_visible(wp))
1.4       nicm      593:                return;
1.1       nicm      594:
1.55      nicm      595:        screen_redraw_set_context(c, &ctx);
1.84      nicm      596:        tty_sync_start(&c->tty);
1.74      nicm      597:        tty_update_mode(&c->tty, c->tty.mode, NULL);
1.26      nicm      598:
1.55      nicm      599:        screen_redraw_draw_pane(&ctx, wp);
1.67      nicm      600:
1.26      nicm      601:        tty_reset(&c->tty);
                    602: }
                    603:
1.75      nicm      604: /* Get border cell style. */
                    605: static const struct grid_cell *
                    606: screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x,
                    607:     u_int y, struct window_pane *wp)
                    608: {
                    609:        struct client           *c = ctx->c;
                    610:        struct session          *s = c->session;
                    611:        struct window           *w = s->curw->window;
1.77      nicm      612:        struct window_pane      *active = server_client_get_pane(c);
1.75      nicm      613:        struct options          *oo = w->options;
                    614:        struct format_tree      *ft;
                    615:
                    616:        if (wp->border_gc_set)
                    617:                return (&wp->border_gc);
                    618:        wp->border_gc_set = 1;
                    619:
                    620:        ft = format_create_defaults(NULL, c, s, s->curw, wp);
1.78      nicm      621:        if (screen_redraw_check_is(x, y, ctx->pane_status, active))
                    622:                style_apply(&wp->border_gc, oo, "pane-active-border-style", ft);
                    623:        else
                    624:                style_apply(&wp->border_gc, oo, "pane-border-style", ft);
                    625:        format_free(ft);
1.75      nicm      626:
1.78      nicm      627:        return (&wp->border_gc);
1.75      nicm      628: }
                    629:
1.50      nicm      630: /* Draw a border cell. */
                    631: static void
1.75      nicm      632: screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
1.50      nicm      633: {
1.53      nicm      634:        struct client           *c = ctx->c;
                    635:        struct session          *s = c->session;
1.86      nicm      636:        struct window           *w = s->curw->window;
                    637:        struct options          *oo = w->options;
1.53      nicm      638:        struct tty              *tty = &c->tty;
1.86      nicm      639:        struct format_tree      *ft;
1.53      nicm      640:        struct window_pane      *wp;
1.89      nicm      641:        struct grid_cell         gc;
                    642:        const struct grid_cell  *tmp;
                    643:        struct overlay_ranges    r;
1.78      nicm      644:        u_int                    cell_type, x = ctx->ox + i, y = ctx->oy + j;
1.83      nicm      645:        int                      pane_status = ctx->pane_status, isolates;
1.50      nicm      646:
1.89      nicm      647:        if (c->overlay_check != NULL) {
                    648:                c->overlay_check(c, c->overlay_data, x, y, 1, &r);
                    649:                if (r.nx[0] + r.nx[1] == 0)
                    650:                        return;
                    651:        }
1.75      nicm      652:
1.78      nicm      653:        cell_type = screen_redraw_check_cell(c, x, y, pane_status, &wp);
                    654:        if (cell_type == CELL_INSIDE)
1.50      nicm      655:                return;
                    656:
1.86      nicm      657:        if (wp == NULL) {
                    658:                if (!ctx->no_pane_gc_set) {
                    659:                        ft = format_create_defaults(NULL, c, s, s->curw, NULL);
                    660:                        memcpy(&ctx->no_pane_gc, &grid_default_cell, sizeof gc);
                    661:                        style_add(&ctx->no_pane_gc, oo, "pane-border-style",
                    662:                            ft);
                    663:                        format_free(ft);
                    664:                        ctx->no_pane_gc_set = 1;
                    665:                }
                    666:                memcpy(&gc, &ctx->no_pane_gc, sizeof gc);
                    667:        } else {
1.78      nicm      668:                tmp = screen_redraw_draw_borders_style(ctx, x, y, wp);
                    669:                if (tmp == NULL)
1.75      nicm      670:                        return;
1.78      nicm      671:                memcpy(&gc, tmp, sizeof gc);
1.75      nicm      672:
                    673:                if (server_is_marked(s, s->curw, marked_pane.wp) &&
1.78      nicm      674:                    screen_redraw_check_is(x, y, pane_status, marked_pane.wp))
                    675:                        gc.attr ^= GRID_ATTR_REVERSE;
1.75      nicm      676:        }
1.78      nicm      677:        screen_redraw_border_set(wp, ctx->pane_lines, cell_type, &gc);
1.75      nicm      678:
1.83      nicm      679:        if (cell_type == CELL_TOPBOTTOM &&
                    680:            (c->flags & CLIENT_UTF8) &&
                    681:            tty_term_has(tty->term, TTYC_BIDI))
                    682:                isolates = 1;
                    683:        else
                    684:                isolates = 0;
                    685:
1.61      nicm      686:        if (ctx->statustop)
                    687:                tty_cursor(tty, i, ctx->statuslines + j);
1.50      nicm      688:        else
1.55      nicm      689:                tty_cursor(tty, i, j);
1.83      nicm      690:        if (isolates)
                    691:                tty_puts(tty, END_ISOLATE);
1.78      nicm      692:        tty_cell(tty, &gc, &grid_default_cell, NULL);
1.83      nicm      693:        if (isolates)
                    694:                tty_puts(tty, START_ISOLATE);
1.50      nicm      695: }
                    696:
1.26      nicm      697: /* Draw the borders. */
1.39      nicm      698: static void
1.50      nicm      699: screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
1.26      nicm      700: {
1.50      nicm      701:        struct client           *c = ctx->c;
1.32      nicm      702:        struct session          *s = c->session;
                    703:        struct window           *w = s->curw->window;
1.75      nicm      704:        struct window_pane      *wp;
1.55      nicm      705:        u_int                    i, j;
                    706:
                    707:        log_debug("%s: %s @%u", __func__, c->name, w->id);
1.26      nicm      708:
1.75      nicm      709:        TAILQ_FOREACH(wp, &w->panes, entry)
                    710:                wp->border_gc_set = 0;
                    711:
                    712:        for (j = 0; j < c->tty.sy - ctx->statuslines; j++) {
                    713:                for (i = 0; i < c->tty.sx; i++)
                    714:                        screen_redraw_draw_borders_cell(ctx, i, j);
1.28      nicm      715:        }
1.26      nicm      716: }
1.1       nicm      717:
1.26      nicm      718: /* Draw the panes. */
1.39      nicm      719: static void
1.50      nicm      720: screen_redraw_draw_panes(struct screen_redraw_ctx *ctx)
1.26      nicm      721: {
1.50      nicm      722:        struct client           *c = ctx->c;
1.26      nicm      723:        struct window           *w = c->session->curw->window;
                    724:        struct window_pane      *wp;
1.47      nicm      725:
1.55      nicm      726:        log_debug("%s: %s @%u", __func__, c->name, w->id);
                    727:
1.1       nicm      728:        TAILQ_FOREACH(wp, &w->panes, entry) {
1.61      nicm      729:                if (window_pane_visible(wp))
                    730:                        screen_redraw_draw_pane(ctx, wp);
1.1       nicm      731:        }
                    732: }
                    733:
1.26      nicm      734: /* Draw the status line. */
1.39      nicm      735: static void
1.50      nicm      736: screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
1.1       nicm      737: {
1.50      nicm      738:        struct client   *c = ctx->c;
1.55      nicm      739:        struct window   *w = c->session->curw->window;
1.26      nicm      740:        struct tty      *tty = &c->tty;
1.58      nicm      741:        struct screen   *s = c->status.active;
1.47      nicm      742:        u_int            i, y;
1.23      nicm      743:
1.55      nicm      744:        log_debug("%s: %s @%u", __func__, c->name, w->id);
                    745:
1.61      nicm      746:        if (ctx->statustop)
1.47      nicm      747:                y = 0;
1.26      nicm      748:        else
1.61      nicm      749:                y = c->tty.sy - ctx->statuslines;
1.76      nicm      750:        for (i = 0; i < ctx->statuslines; i++) {
                    751:                tty_draw_line(tty, s, 0, i, UINT_MAX, 0, y + i,
                    752:                    &grid_default_cell, NULL);
                    753:        }
1.55      nicm      754: }
                    755:
                    756: /* Draw one pane. */
                    757: static void
                    758: screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
                    759: {
1.87      nicm      760:        struct client           *c = ctx->c;
                    761:        struct window           *w = c->session->curw->window;
                    762:        struct tty              *tty = &c->tty;
                    763:        struct screen           *s = wp->screen;
                    764:        struct colour_palette   *palette = &wp->palette;
                    765:        struct grid_cell         defaults;
                    766:        u_int                    i, j, top, x, y, width;
1.55      nicm      767:
                    768:        log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
                    769:
                    770:        if (wp->xoff + wp->sx <= ctx->ox || wp->xoff >= ctx->ox + ctx->sx)
                    771:                return;
1.61      nicm      772:        if (ctx->statustop)
                    773:                top = ctx->statuslines;
1.55      nicm      774:        else
                    775:                top = 0;
                    776:        for (j = 0; j < wp->sy; j++) {
                    777:                if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy)
                    778:                        continue;
                    779:                y = top + wp->yoff + j - ctx->oy;
                    780:
                    781:                if (wp->xoff >= ctx->ox &&
                    782:                    wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
                    783:                        /* All visible. */
                    784:                        i = 0;
                    785:                        x = wp->xoff - ctx->ox;
                    786:                        width = wp->sx;
                    787:                } else if (wp->xoff < ctx->ox &&
                    788:                    wp->xoff + wp->sx > ctx->ox + ctx->sx) {
                    789:                        /* Both left and right not visible. */
                    790:                        i = ctx->ox;
                    791:                        x = 0;
                    792:                        width = ctx->sx;
                    793:                } else if (wp->xoff < ctx->ox) {
                    794:                        /* Left not visible. */
                    795:                        i = ctx->ox - wp->xoff;
                    796:                        x = 0;
                    797:                        width = wp->sx - i;
                    798:                } else {
                    799:                        /* Right not visible. */
                    800:                        i = 0;
                    801:                        x = wp->xoff - ctx->ox;
                    802:                        width = ctx->sx - x;
                    803:                }
                    804:                log_debug("%s: %s %%%u line %u,%u at %u,%u, width %u",
                    805:                    __func__, c->name, wp->id, i, j, x, y, width);
                    806:
1.76      nicm      807:                tty_default_colours(&defaults, wp);
1.87      nicm      808:                tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette);
1.55      nicm      809:        }
1.1       nicm      810: }