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

Annotation of src/usr.bin/tmux/screen-write.c, Revision 1.108

1.108   ! nicm        1: /* $OpenBSD: screen-write.c,v 1.107 2017/02/08 15:41:41 nicm Exp $ */
1.1       nicm        2:
                      3: /*
1.84      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.56      nicm       21: #include <stdlib.h>
1.1       nicm       22: #include <string.h>
                     23:
                     24: #include "tmux.h"
                     25:
1.87      nicm       26: static void    screen_write_initctx(struct screen_write_ctx *,
                     27:                    struct tty_ctx *);
1.92      nicm       28: static void    screen_write_flush(struct screen_write_ctx *);
1.87      nicm       29:
1.89      nicm       30: static int     screen_write_overwrite(struct screen_write_ctx *,
                     31:                    struct grid_cell *, u_int);
1.104     nicm       32: static const struct grid_cell *screen_write_combine(struct screen_write_ctx *,
                     33:                    const struct utf8_data *, u_int *);
1.1       nicm       34:
1.88      nicm       35: static const struct grid_cell screen_write_pad_cell = {
1.91      nicm       36:        GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 }
1.88      nicm       37: };
                     38:
1.92      nicm       39: #define screen_dirty_bit(s, x, y) (((y) * screen_size_x(s)) + (x))
                     40: #define screen_dirty_clear(s, sx, sy, ex, ey)                  \
                     41:        do {                                                    \
                     42:                if (s->dirty != NULL) {                         \
                     43:                        bit_nclear(s->dirty,                    \
                     44:                            screen_dirty_bit(s, sx, sy),        \
                     45:                            screen_dirty_bit(s, ex, ey));       \
                     46:                }                                               \
                     47:        } while (0)
                     48:
                     49: /* Initialize writing with a window. */
1.1       nicm       50: void
1.71      nicm       51: screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
                     52:     struct screen *s)
1.1       nicm       53: {
1.108   ! nicm       54:        u_int   size;
        !            55:        char    tmp[16];
1.92      nicm       56:
1.1       nicm       57:        ctx->wp = wp;
                     58:        if (wp != NULL && s == NULL)
                     59:                ctx->s = wp->screen;
                     60:        else
                     61:                ctx->s = s;
1.92      nicm       62:
                     63:        size = screen_size_x(ctx->s) * screen_size_y(ctx->s);
                     64:        if (ctx->s->dirtysize != size) {
                     65:                free(ctx->s->dirty);
                     66:                ctx->s->dirty = NULL;
                     67:                ctx->s->dirtysize = size;
                     68:        }
                     69:        ctx->dirty = 0;
                     70:
                     71:        ctx->cells = ctx->written = ctx->skipped = 0;
                     72:
1.108   ! nicm       73:        if (wp != NULL)
1.92      nicm       74:                snprintf(tmp, sizeof tmp, "pane %%%u", wp->id);
                     75:        log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s),
1.108   ! nicm       76:            screen_size_y(ctx->s), wp == NULL ? "no pane" : tmp);
1.1       nicm       77: }
                     78:
                     79: /* Finish writing. */
                     80: void
1.92      nicm       81: screen_write_stop(struct screen_write_ctx *ctx)
                     82: {
                     83:        screen_write_flush(ctx);
                     84:
                     85:        log_debug("%s: %u of %u written (dirty %u, skipped %u)", __func__,
                     86:            ctx->written, ctx->cells, ctx->cells - ctx->written, ctx->skipped);
                     87: }
                     88:
                     89: /* Flush outstanding cell writes. */
                     90: static void
                     91: screen_write_flush(struct screen_write_ctx *ctx)
1.1       nicm       92: {
1.92      nicm       93:        struct screen   *s = ctx->s;
                     94:        struct tty_ctx   ttyctx;
                     95:        u_int            x, y, offset, cx, cy, dirty;
                     96:        struct grid_cell gc;
                     97:
                     98:        if (ctx->dirty == 0)
                     99:                return;
                    100:        dirty = 0;
1.98      nicm      101:        log_debug("%s: dirty %u", __func__, ctx->dirty);
1.92      nicm      102:
                    103:        cx = s->cx;
                    104:        cy = s->cy;
                    105:
                    106:        offset = 0;
                    107:        for (y = 0; y < screen_size_y(s); y++) {
                    108:                for (x = 0; x < screen_size_x(s); x++) {
                    109:                        offset++;
                    110:                        if (!bit_test(s->dirty, offset - 1))
                    111:                                continue;
                    112:                        bit_clear(s->dirty, offset - 1);
                    113:
                    114:                        screen_write_cursormove(ctx, x, y);
                    115:                        grid_view_get_cell(s->grid, x, y, &gc);
                    116:
                    117:                        screen_write_initctx(ctx, &ttyctx);
                    118:                        ttyctx.cell = &gc;
                    119:                        tty_write(tty_cmd_cell, &ttyctx);
                    120:                        ctx->written++;
                    121:
                    122:                        if (++dirty == ctx->dirty)
                    123:                                break;
                    124:                }
                    125:                if (dirty == ctx->dirty)
                    126:                        break;
                    127:        }
1.100     nicm      128:        ctx->dirty = 0;
1.92      nicm      129:
                    130:        s->cx = cx;
                    131:        s->cy = cy;
1.52      nicm      132: }
                    133:
                    134: /* Reset screen state. */
                    135: void
                    136: screen_write_reset(struct screen_write_ctx *ctx)
                    137: {
1.61      nicm      138:        struct screen   *s = ctx->s;
1.52      nicm      139:
1.61      nicm      140:        screen_reset_tabs(s);
                    141:        screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
1.63      nicm      142:
1.67      nicm      143:        s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD|MODE_FOCUSON);
1.82      nicm      144:        s->mode &= ~(ALL_MOUSE_MODES|MODE_MOUSE_UTF8|MODE_MOUSE_SGR);
1.52      nicm      145:
1.99      nicm      146:        screen_write_clearscreen(ctx, 8);
1.52      nicm      147:        screen_write_cursormove(ctx, 0, 0);
1.1       nicm      148: }
                    149:
                    150: /* Write character. */
                    151: void
1.86      nicm      152: screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
1.69      nicm      153:     u_char ch)
1.1       nicm      154: {
1.86      nicm      155:        struct grid_cell        gc;
                    156:
                    157:        memcpy(&gc, gcp, sizeof gc);
                    158:
                    159:        utf8_set(&gc.data, ch);
                    160:        screen_write_cell(ctx, &gc);
1.1       nicm      161: }
                    162:
1.24      nicm      163: /* Calculate string length, with embedded formatting. */
1.71      nicm      164: size_t
1.75      nicm      165: screen_write_cstrlen(const char *fmt, ...)
1.24      nicm      166: {
                    167:        va_list ap;
                    168:        char   *msg, *msg2, *ptr, *ptr2;
                    169:        size_t  size;
                    170:
                    171:        va_start(ap, fmt);
                    172:        xvasprintf(&msg, fmt, ap);
                    173:        va_end(ap);
                    174:        msg2 = xmalloc(strlen(msg) + 1);
                    175:
                    176:        ptr = msg;
                    177:        ptr2 = msg2;
                    178:        while (*ptr != '\0') {
                    179:                if (ptr[0] == '#' && ptr[1] == '[') {
                    180:                        while (*ptr != ']' && *ptr != '\0')
                    181:                                ptr++;
                    182:                        if (*ptr == ']')
                    183:                                ptr++;
                    184:                        continue;
                    185:                }
                    186:                *ptr2++ = *ptr++;
                    187:        }
                    188:        *ptr2 = '\0';
                    189:
1.75      nicm      190:        size = screen_write_strlen("%s", msg2);
1.24      nicm      191:
1.56      nicm      192:        free(msg);
                    193:        free(msg2);
1.24      nicm      194:
                    195:        return (size);
                    196: }
                    197:
1.2       nicm      198: /* Calculate string length. */
1.71      nicm      199: size_t
1.75      nicm      200: screen_write_strlen(const char *fmt, ...)
1.2       nicm      201: {
1.36      nicm      202:        va_list                 ap;
                    203:        char                   *msg;
1.76      nicm      204:        struct utf8_data        ud;
1.36      nicm      205:        u_char                 *ptr;
                    206:        size_t                  left, size = 0;
1.79      nicm      207:        enum utf8_state         more;
1.2       nicm      208:
                    209:        va_start(ap, fmt);
                    210:        xvasprintf(&msg, fmt, ap);
                    211:        va_end(ap);
                    212:
                    213:        ptr = msg;
                    214:        while (*ptr != '\0') {
1.79      nicm      215:                if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
1.36      nicm      216:                        ptr++;
1.2       nicm      217:
                    218:                        left = strlen(ptr);
1.77      nicm      219:                        if (left < (size_t)ud.size - 1)
1.36      nicm      220:                                break;
1.79      nicm      221:                        while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
1.2       nicm      222:                                ptr++;
1.36      nicm      223:                        ptr++;
                    224:
1.79      nicm      225:                        if (more == UTF8_DONE)
1.78      nicm      226:                                size += ud.width;
1.2       nicm      227:                } else {
1.75      nicm      228:                        if (*ptr > 0x1f && *ptr < 0x7f)
                    229:                                size++;
1.2       nicm      230:                        ptr++;
                    231:                }
1.7       ray       232:        }
1.2       nicm      233:
1.56      nicm      234:        free(msg);
1.2       nicm      235:        return (size);
                    236: }
                    237:
1.3       nicm      238: /* Write simple string (no UTF-8 or maximum length). */
1.71      nicm      239: void
1.86      nicm      240: screen_write_puts(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
1.71      nicm      241:     const char *fmt, ...)
1.1       nicm      242: {
                    243:        va_list ap;
                    244:
                    245:        va_start(ap, fmt);
1.86      nicm      246:        screen_write_vnputs(ctx, -1, gcp, fmt, ap);
1.2       nicm      247:        va_end(ap);
                    248: }
                    249:
                    250: /* Write string with length limit (-1 for unlimited). */
1.71      nicm      251: void
                    252: screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen,
1.86      nicm      253:     const struct grid_cell *gcp, const char *fmt, ...)
1.2       nicm      254: {
                    255:        va_list ap;
                    256:
                    257:        va_start(ap, fmt);
1.86      nicm      258:        screen_write_vnputs(ctx, maxlen, gcp, fmt, ap);
1.2       nicm      259:        va_end(ap);
                    260: }
                    261:
                    262: void
1.3       nicm      263: screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
1.86      nicm      264:     const struct grid_cell *gcp, const char *fmt, va_list ap)
1.2       nicm      265: {
1.86      nicm      266:        struct grid_cell        gc;
                    267:        struct utf8_data       *ud = &gc.data;
1.36      nicm      268:        char                   *msg;
                    269:        u_char                 *ptr;
                    270:        size_t                  left, size = 0;
1.79      nicm      271:        enum utf8_state         more;
1.2       nicm      272:
1.86      nicm      273:        memcpy(&gc, gcp, sizeof gc);
1.1       nicm      274:        xvasprintf(&msg, fmt, ap);
                    275:
1.2       nicm      276:        ptr = msg;
                    277:        while (*ptr != '\0') {
1.86      nicm      278:                if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
1.36      nicm      279:                        ptr++;
1.2       nicm      280:
                    281:                        left = strlen(ptr);
1.86      nicm      282:                        if (left < (size_t)ud->size - 1)
1.36      nicm      283:                                break;
1.86      nicm      284:                        while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
1.2       nicm      285:                                ptr++;
1.36      nicm      286:                        ptr++;
1.7       ray       287:
1.86      nicm      288:                        if (more != UTF8_DONE)
                    289:                                continue;
                    290:                        if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
                    291:                                while (size < (size_t)maxlen) {
                    292:                                        screen_write_putc(ctx, &gc, ' ');
                    293:                                        size++;
1.2       nicm      294:                                }
1.86      nicm      295:                                break;
1.2       nicm      296:                        }
1.86      nicm      297:                        size += ud->width;
                    298:                        screen_write_cell(ctx, &gc);
1.2       nicm      299:                } else {
1.86      nicm      300:                        if (maxlen > 0 && size + 1 > (size_t)maxlen)
1.2       nicm      301:                                break;
                    302:
1.57      nicm      303:                        if (*ptr == '\001')
1.86      nicm      304:                                gc.attr ^= GRID_ATTR_CHARSET;
1.75      nicm      305:                        else if (*ptr > 0x1f && *ptr < 0x7f) {
1.57      nicm      306:                                size++;
1.86      nicm      307:                                screen_write_putc(ctx, &gc, *ptr);
1.57      nicm      308:                        }
1.2       nicm      309:                        ptr++;
                    310:                }
                    311:        }
1.1       nicm      312:
1.56      nicm      313:        free(msg);
1.24      nicm      314: }
                    315:
                    316: /* Write string, similar to nputs, but with embedded formatting (#[]). */
1.71      nicm      317: void
1.75      nicm      318: screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
1.86      nicm      319:     const struct grid_cell *gcp, const char *fmt, ...)
1.24      nicm      320: {
1.86      nicm      321:        struct grid_cell         gc;
                    322:        struct utf8_data        *ud = &gc.data;
1.24      nicm      323:        va_list                  ap;
                    324:        char                    *msg;
1.36      nicm      325:        u_char                  *ptr, *last;
1.24      nicm      326:        size_t                   left, size = 0;
1.79      nicm      327:        enum utf8_state          more;
1.24      nicm      328:
1.86      nicm      329:        memcpy(&gc, gcp, sizeof gc);
                    330:
1.24      nicm      331:        va_start(ap, fmt);
                    332:        xvasprintf(&msg, fmt, ap);
                    333:        va_end(ap);
                    334:
                    335:        ptr = msg;
                    336:        while (*ptr != '\0') {
                    337:                if (ptr[0] == '#' && ptr[1] == '[') {
                    338:                        ptr += 2;
                    339:                        last = ptr + strcspn(ptr, "]");
                    340:                        if (*last == '\0') {
                    341:                                /* No ]. Not much point in doing anything. */
                    342:                                break;
                    343:                        }
                    344:                        *last = '\0';
                    345:
1.86      nicm      346:                        style_parse(gcp, &gc, ptr);
1.24      nicm      347:                        ptr = last + 1;
                    348:                        continue;
                    349:                }
                    350:
1.86      nicm      351:                if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
1.36      nicm      352:                        ptr++;
1.24      nicm      353:
                    354:                        left = strlen(ptr);
1.86      nicm      355:                        if (left < (size_t)ud->size - 1)
1.36      nicm      356:                                break;
1.86      nicm      357:                        while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
1.24      nicm      358:                                ptr++;
1.36      nicm      359:                        ptr++;
1.24      nicm      360:
1.86      nicm      361:                        if (more != UTF8_DONE)
                    362:                                continue;
                    363:                        if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
                    364:                                while (size < (size_t)maxlen) {
                    365:                                        screen_write_putc(ctx, &gc, ' ');
                    366:                                        size++;
1.24      nicm      367:                                }
1.86      nicm      368:                                break;
1.24      nicm      369:                        }
1.86      nicm      370:                        size += ud->width;
                    371:                        screen_write_cell(ctx, &gc);
1.24      nicm      372:                } else {
1.86      nicm      373:                        if (maxlen > 0 && size + 1 > (size_t)maxlen)
1.24      nicm      374:                                break;
                    375:
1.75      nicm      376:                        if (*ptr > 0x1f && *ptr < 0x7f) {
                    377:                                size++;
1.86      nicm      378:                                screen_write_putc(ctx, &gc, *ptr);
1.75      nicm      379:                        }
1.24      nicm      380:                        ptr++;
                    381:                }
                    382:        }
                    383:
1.56      nicm      384:        free(msg);
1.1       nicm      385: }
                    386:
                    387: /* Copy from another screen. */
                    388: void
1.95      nicm      389: screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px,
1.102     nicm      390:     u_int py, u_int nx, u_int ny, bitstr_t *markbs,
                    391:     const struct grid_cell *markgc)
1.1       nicm      392: {
                    393:        struct screen           *s = ctx->s;
                    394:        struct grid             *gd = src->grid;
1.77      nicm      395:        struct grid_cell         gc;
1.102     nicm      396:        u_int                    xx, yy, cx, cy, b;
1.1       nicm      397:
                    398:        cx = s->cx;
                    399:        cy = s->cy;
1.96      nicm      400:
1.1       nicm      401:        for (yy = py; yy < py + ny; yy++) {
1.96      nicm      402:                for (xx = px; xx < px + nx; xx++) {
                    403:                        grid_get_cell(gd, xx, yy, &gc);
1.102     nicm      404:                        if (markbs != NULL) {
                    405:                                b = (yy * screen_size_x(src)) + xx;
                    406:                                if (bit_test(markbs, b)) {
                    407:                                        gc.attr = markgc->attr;
                    408:                                        gc.fg = markgc->fg;
                    409:                                        gc.bg = markgc->bg;
                    410:                                }
                    411:                        }
1.96      nicm      412:                        screen_write_cell(ctx, &gc);
                    413:                }
                    414:
1.1       nicm      415:                cy++;
                    416:                screen_write_cursormove(ctx, cx, cy);
                    417:        }
                    418: }
                    419:
1.17      nicm      420: /* Set up context for TTY command. */
1.87      nicm      421: static void
                    422: screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
1.1       nicm      423: {
1.87      nicm      424:        struct screen   *s = ctx->s;
1.1       nicm      425:
1.17      nicm      426:        ttyctx->wp = ctx->wp;
1.1       nicm      427:
1.17      nicm      428:        ttyctx->ocx = s->cx;
                    429:        ttyctx->ocy = s->cy;
                    430:
                    431:        ttyctx->orlower = s->rlower;
                    432:        ttyctx->orupper = s->rupper;
1.87      nicm      433: }
1.31      nicm      434:
1.61      nicm      435: /* Set a mode. */
                    436: void
                    437: screen_write_mode_set(struct screen_write_ctx *ctx, int mode)
                    438: {
                    439:        struct screen   *s = ctx->s;
                    440:
                    441:        s->mode |= mode;
                    442: }
                    443:
                    444: /* Clear a mode. */
                    445: void
                    446: screen_write_mode_clear(struct screen_write_ctx *ctx, int mode)
                    447: {
                    448:        struct screen   *s = ctx->s;
                    449:
                    450:        s->mode &= ~mode;
                    451: }
                    452:
1.1       nicm      453: /* Cursor up by ny. */
                    454: void
                    455: screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
                    456: {
                    457:        struct screen   *s = ctx->s;
                    458:
                    459:        if (ny == 0)
                    460:                ny = 1;
                    461:
1.12      nicm      462:        if (s->cy < s->rupper) {
                    463:                /* Above region. */
                    464:                if (ny > s->cy)
                    465:                        ny = s->cy;
                    466:        } else {
                    467:                /* Below region. */
                    468:                if (ny > s->cy - s->rupper)
                    469:                        ny = s->cy - s->rupper;
                    470:        }
1.66      nicm      471:        if (s->cx == screen_size_x(s))
                    472:            s->cx--;
1.1       nicm      473:        if (ny == 0)
                    474:                return;
                    475:
                    476:        s->cy -= ny;
                    477: }
                    478:
                    479: /* Cursor down by ny. */
                    480: void
                    481: screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
                    482: {
                    483:        struct screen   *s = ctx->s;
                    484:
                    485:        if (ny == 0)
                    486:                ny = 1;
                    487:
1.12      nicm      488:        if (s->cy > s->rlower) {
                    489:                /* Below region. */
                    490:                if (ny > screen_size_y(s) - 1 - s->cy)
                    491:                        ny = screen_size_y(s) - 1 - s->cy;
                    492:        } else {
                    493:                /* Above region. */
                    494:                if (ny > s->rlower - s->cy)
                    495:                        ny = s->rlower - s->cy;
                    496:        }
1.66      nicm      497:        if (s->cx == screen_size_x(s))
                    498:            s->cx--;
1.1       nicm      499:        if (ny == 0)
                    500:                return;
                    501:
                    502:        s->cy += ny;
                    503: }
                    504:
1.101     nicm      505: /* Cursor right by nx. */
1.1       nicm      506: void
                    507: screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
                    508: {
                    509:        struct screen   *s = ctx->s;
                    510:
                    511:        if (nx == 0)
                    512:                nx = 1;
                    513:
                    514:        if (nx > screen_size_x(s) - 1 - s->cx)
                    515:                nx = screen_size_x(s) - 1 - s->cx;
                    516:        if (nx == 0)
                    517:                return;
                    518:
                    519:        s->cx += nx;
                    520: }
                    521:
                    522: /* Cursor left by nx. */
                    523: void
                    524: screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
                    525: {
                    526:        struct screen   *s = ctx->s;
                    527:
                    528:        if (nx == 0)
                    529:                nx = 1;
                    530:
                    531:        if (nx > s->cx)
                    532:                nx = s->cx;
                    533:        if (nx == 0)
                    534:                return;
                    535:
                    536:        s->cx -= nx;
1.5       nicm      537: }
                    538:
1.29      nicm      539: /* Backspace; cursor left unless at start of wrapped line when can move up. */
                    540: void
                    541: screen_write_backspace(struct screen_write_ctx *ctx)
                    542: {
                    543:        struct screen           *s = ctx->s;
                    544:        struct grid_line        *gl;
                    545:
                    546:        if (s->cx == 0) {
                    547:                if (s->cy == 0)
                    548:                        return;
                    549:                gl = &s->grid->linedata[s->grid->hsize + s->cy - 1];
                    550:                if (gl->flags & GRID_LINE_WRAPPED) {
                    551:                        s->cy--;
                    552:                        s->cx = screen_size_x(s) - 1;
                    553:                }
                    554:        } else
                    555:                s->cx--;
                    556: }
                    557:
1.5       nicm      558: /* VT100 alignment test. */
                    559: void
                    560: screen_write_alignmenttest(struct screen_write_ctx *ctx)
                    561: {
                    562:        struct screen           *s = ctx->s;
1.17      nicm      563:        struct tty_ctx           ttyctx;
1.5       nicm      564:        struct grid_cell         gc;
                    565:        u_int                    xx, yy;
1.92      nicm      566:        u_int                    sx = screen_size_x(s), sy = screen_size_y(s);
1.5       nicm      567:
1.87      nicm      568:        screen_write_initctx(ctx, &ttyctx);
1.17      nicm      569:
1.92      nicm      570:        screen_dirty_clear(s, 0, 0, sx - 1, sy  - 1);
                    571:
1.5       nicm      572:        memcpy(&gc, &grid_default_cell, sizeof gc);
1.77      nicm      573:        utf8_set(&gc.data, 'E');
1.7       ray       574:
1.5       nicm      575:        for (yy = 0; yy < screen_size_y(s); yy++) {
                    576:                for (xx = 0; xx < screen_size_x(s); xx++)
                    577:                        grid_view_set_cell(s->grid, xx, yy, &gc);
                    578:        }
1.7       ray       579:
1.5       nicm      580:        s->cx = 0;
                    581:        s->cy = 0;
                    582:
                    583:        s->rupper = 0;
                    584:        s->rlower = screen_size_y(s) - 1;
                    585:
1.17      nicm      586:        tty_write(tty_cmd_alignmenttest, &ttyctx);
1.1       nicm      587: }
                    588:
                    589: /* Insert nx characters. */
                    590: void
1.99      nicm      591: screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
1.1       nicm      592: {
                    593:        struct screen   *s = ctx->s;
1.17      nicm      594:        struct tty_ctx   ttyctx;
1.1       nicm      595:
                    596:        if (nx == 0)
                    597:                nx = 1;
                    598:
1.9       nicm      599:        if (nx > screen_size_x(s) - s->cx)
                    600:                nx = screen_size_x(s) - s->cx;
1.1       nicm      601:        if (nx == 0)
                    602:                return;
                    603:
1.107     nicm      604:        if (s->cx > screen_size_x(s) - 1)
                    605:                return;
                    606:
1.92      nicm      607:        screen_write_flush(ctx);
1.87      nicm      608:        screen_write_initctx(ctx, &ttyctx);
1.107     nicm      609:        ttyctx.bg = bg;
1.1       nicm      610:
1.107     nicm      611:        grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg);
1.1       nicm      612:
1.17      nicm      613:        ttyctx.num = nx;
                    614:        tty_write(tty_cmd_insertcharacter, &ttyctx);
1.1       nicm      615: }
                    616:
                    617: /* Delete nx characters. */
                    618: void
1.99      nicm      619: screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
1.1       nicm      620: {
                    621:        struct screen   *s = ctx->s;
1.17      nicm      622:        struct tty_ctx   ttyctx;
1.1       nicm      623:
                    624:        if (nx == 0)
                    625:                nx = 1;
                    626:
1.9       nicm      627:        if (nx > screen_size_x(s) - s->cx)
                    628:                nx = screen_size_x(s) - s->cx;
1.1       nicm      629:        if (nx == 0)
                    630:                return;
                    631:
1.107     nicm      632:        if (s->cx > screen_size_x(s) - 1)
                    633:                return;
                    634:
1.92      nicm      635:        screen_write_flush(ctx);
1.87      nicm      636:        screen_write_initctx(ctx, &ttyctx);
1.107     nicm      637:        ttyctx.bg = bg;
1.1       nicm      638:
1.107     nicm      639:        grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg);
1.1       nicm      640:
1.17      nicm      641:        ttyctx.num = nx;
                    642:        tty_write(tty_cmd_deletecharacter, &ttyctx);
1.59      nicm      643: }
                    644:
                    645: /* Clear nx characters. */
                    646: void
                    647: screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx)
                    648: {
                    649:        struct screen   *s = ctx->s;
                    650:        struct tty_ctx   ttyctx;
                    651:
                    652:        if (nx == 0)
                    653:                nx = 1;
                    654:
                    655:        if (nx > screen_size_x(s) - s->cx)
                    656:                nx = screen_size_x(s) - s->cx;
                    657:        if (nx == 0)
                    658:                return;
                    659:
1.107     nicm      660:        if (s->cx > screen_size_x(s) - 1)
                    661:                return;
                    662:
1.87      nicm      663:        screen_write_initctx(ctx, &ttyctx);
1.59      nicm      664:
1.107     nicm      665:        screen_dirty_clear(s, s->cx, s->cy, s->cx + nx - 1, s->cy);
                    666:        grid_view_clear(s->grid, s->cx, s->cy, nx, 1, 8);
1.59      nicm      667:
                    668:        ttyctx.num = nx;
                    669:        tty_write(tty_cmd_clearcharacter, &ttyctx);
1.1       nicm      670: }
                    671:
                    672: /* Insert ny lines. */
                    673: void
1.99      nicm      674: screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
1.1       nicm      675: {
                    676:        struct screen   *s = ctx->s;
1.107     nicm      677:        struct grid     *gd = s->grid;
1.17      nicm      678:        struct tty_ctx   ttyctx;
1.1       nicm      679:
                    680:        if (ny == 0)
                    681:                ny = 1;
                    682:
1.11      nicm      683:        if (s->cy < s->rupper || s->cy > s->rlower) {
                    684:                if (ny > screen_size_y(s) - s->cy)
                    685:                        ny = screen_size_y(s) - s->cy;
                    686:                if (ny == 0)
                    687:                        return;
                    688:
1.92      nicm      689:                screen_write_flush(ctx);
1.87      nicm      690:                screen_write_initctx(ctx, &ttyctx);
1.107     nicm      691:                ttyctx.bg = bg;
1.11      nicm      692:
1.107     nicm      693:                grid_view_insert_lines(gd, s->cy, ny, bg);
1.11      nicm      694:
1.17      nicm      695:                ttyctx.num = ny;
                    696:                tty_write(tty_cmd_insertline, &ttyctx);
1.11      nicm      697:                return;
                    698:        }
                    699:
                    700:        if (ny > s->rlower + 1 - s->cy)
                    701:                ny = s->rlower + 1 - s->cy;
1.1       nicm      702:        if (ny == 0)
                    703:                return;
1.41      nicm      704:
1.92      nicm      705:        screen_write_flush(ctx);
1.87      nicm      706:        screen_write_initctx(ctx, &ttyctx);
1.107     nicm      707:        ttyctx.bg = bg;
1.1       nicm      708:
                    709:        if (s->cy < s->rupper || s->cy > s->rlower)
1.107     nicm      710:                grid_view_insert_lines(gd, s->cy, ny, bg);
                    711:        else
                    712:                grid_view_insert_lines_region(gd, s->rlower, s->cy, ny, bg);
1.1       nicm      713:
1.17      nicm      714:        ttyctx.num = ny;
                    715:        tty_write(tty_cmd_insertline, &ttyctx);
1.1       nicm      716: }
                    717:
                    718: /* Delete ny lines. */
                    719: void
1.99      nicm      720: screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
1.1       nicm      721: {
                    722:        struct screen   *s = ctx->s;
1.107     nicm      723:        struct grid     *gd = s->grid;
1.17      nicm      724:        struct tty_ctx   ttyctx;
1.1       nicm      725:
                    726:        if (ny == 0)
                    727:                ny = 1;
                    728:
1.11      nicm      729:        if (s->cy < s->rupper || s->cy > s->rlower) {
                    730:                if (ny > screen_size_y(s) - s->cy)
                    731:                        ny = screen_size_y(s) - s->cy;
                    732:                if (ny == 0)
                    733:                        return;
                    734:
1.92      nicm      735:                screen_write_flush(ctx);
1.87      nicm      736:                screen_write_initctx(ctx, &ttyctx);
1.107     nicm      737:                ttyctx.bg = bg;
1.11      nicm      738:
1.107     nicm      739:                grid_view_delete_lines(gd, s->cy, ny, bg);
1.11      nicm      740:
1.17      nicm      741:                ttyctx.num = ny;
                    742:                tty_write(tty_cmd_deleteline, &ttyctx);
1.11      nicm      743:                return;
                    744:        }
1.41      nicm      745:
1.11      nicm      746:        if (ny > s->rlower + 1 - s->cy)
                    747:                ny = s->rlower + 1 - s->cy;
1.1       nicm      748:        if (ny == 0)
                    749:                return;
                    750:
1.92      nicm      751:        screen_write_flush(ctx);
1.87      nicm      752:        screen_write_initctx(ctx, &ttyctx);
1.107     nicm      753:        ttyctx.bg = bg;
1.1       nicm      754:
                    755:        if (s->cy < s->rupper || s->cy > s->rlower)
1.107     nicm      756:                grid_view_delete_lines(gd, s->cy, ny, bg);
                    757:        else
                    758:                grid_view_delete_lines_region(gd, s->rlower, s->cy, ny, bg);
1.1       nicm      759:
1.17      nicm      760:        ttyctx.num = ny;
                    761:        tty_write(tty_cmd_deleteline, &ttyctx);
1.1       nicm      762: }
                    763:
                    764: /* Clear line at cursor. */
                    765: void
1.99      nicm      766: screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm      767: {
1.92      nicm      768:        struct screen           *s = ctx->s;
                    769:        struct grid_line        *gl;
                    770:        struct tty_ctx           ttyctx;
                    771:        u_int                    sx = screen_size_x(s);
1.1       nicm      772:
1.92      nicm      773:        gl = &s->grid->linedata[s->grid->hsize + s->cy];
1.99      nicm      774:        if (gl->cellsize == 0 && bg == 8)
1.92      nicm      775:                return;
1.1       nicm      776:
1.108   ! nicm      777:        screen_write_initctx(ctx, &ttyctx);
        !           778:        ttyctx.bg = bg;
        !           779:
1.99      nicm      780:        screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
                    781:        grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
                    782:
1.17      nicm      783:        tty_write(tty_cmd_clearline, &ttyctx);
1.1       nicm      784: }
                    785:
                    786: /* Clear to end of line from cursor. */
                    787: void
1.99      nicm      788: screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm      789: {
1.92      nicm      790:        struct screen           *s = ctx->s;
                    791:        struct grid_line        *gl;
                    792:        struct tty_ctx           ttyctx;
                    793:        u_int                    sx = screen_size_x(s);
1.1       nicm      794:
1.92      nicm      795:        gl = &s->grid->linedata[s->grid->hsize + s->cy];
1.99      nicm      796:        if (s->cx > sx - 1 || (s->cx >= gl->cellsize && bg == 8))
1.92      nicm      797:                return;
1.108   ! nicm      798:
        !           799:        screen_write_initctx(ctx, &ttyctx);
        !           800:        ttyctx.bg = bg;
1.1       nicm      801:
1.99      nicm      802:        screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
                    803:        grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
                    804:
1.41      nicm      805:        tty_write(tty_cmd_clearendofline, &ttyctx);
1.1       nicm      806: }
                    807:
                    808: /* Clear to start of line from cursor. */
                    809: void
1.99      nicm      810: screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm      811: {
                    812:        struct screen   *s = ctx->s;
1.17      nicm      813:        struct tty_ctx   ttyctx;
1.92      nicm      814:        u_int            sx = screen_size_x(s);
1.1       nicm      815:
1.87      nicm      816:        screen_write_initctx(ctx, &ttyctx);
1.99      nicm      817:        ttyctx.bg = bg;
1.1       nicm      818:
1.92      nicm      819:        if (s->cx > sx - 1) {
                    820:                screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
1.99      nicm      821:                grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
1.92      nicm      822:        } else {
                    823:                screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
1.99      nicm      824:                grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
1.92      nicm      825:        }
1.1       nicm      826:
1.17      nicm      827:        tty_write(tty_cmd_clearstartofline, &ttyctx);
1.1       nicm      828: }
                    829:
1.101     nicm      830: /* Move cursor to px,py. */
1.1       nicm      831: void
                    832: screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
                    833: {
                    834:        struct screen   *s = ctx->s;
                    835:
                    836:        if (px > screen_size_x(s) - 1)
                    837:                px = screen_size_x(s) - 1;
                    838:        if (py > screen_size_y(s) - 1)
                    839:                py = screen_size_y(s) - 1;
                    840:
                    841:        s->cx = px;
                    842:        s->cy = py;
                    843: }
                    844:
1.101     nicm      845: /* Reverse index (up with scroll). */
1.1       nicm      846: void
                    847: screen_write_reverseindex(struct screen_write_ctx *ctx)
                    848: {
                    849:        struct screen   *s = ctx->s;
1.17      nicm      850:        struct tty_ctx   ttyctx;
1.1       nicm      851:
1.87      nicm      852:        screen_write_initctx(ctx, &ttyctx);
1.1       nicm      853:
1.92      nicm      854:        if (s->cy == s->rupper) {
                    855:                screen_write_flush(ctx);
1.1       nicm      856:                grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
1.92      nicm      857:        } else if (s->cy > 0)
1.1       nicm      858:                s->cy--;
                    859:
1.17      nicm      860:        tty_write(tty_cmd_reverseindex, &ttyctx);
1.1       nicm      861: }
                    862:
                    863: /* Set scroll region. */
                    864: void
1.83      nicm      865: screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper,
                    866:     u_int rlower)
1.1       nicm      867: {
                    868:        struct screen   *s = ctx->s;
                    869:
                    870:        if (rupper > screen_size_y(s) - 1)
                    871:                rupper = screen_size_y(s) - 1;
                    872:        if (rlower > screen_size_y(s) - 1)
                    873:                rlower = screen_size_y(s) - 1;
1.13      nicm      874:        if (rupper >= rlower)   /* cannot be one line */
1.1       nicm      875:                return;
                    876:
                    877:        /* Cursor moves to top-left. */
                    878:        s->cx = 0;
                    879:        s->cy = 0;
                    880:
                    881:        s->rupper = rupper;
                    882:        s->rlower = rlower;
                    883: }
                    884:
1.34      nicm      885: /* Line feed. */
1.1       nicm      886: void
1.34      nicm      887: screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
1.1       nicm      888: {
1.20      nicm      889:        struct screen           *s = ctx->s;
                    890:        struct grid_line        *gl;
1.34      nicm      891:        struct tty_ctx           ttyctx;
1.92      nicm      892:        u_int                    sx = screen_size_x(s), sy = screen_size_y(s);
1.34      nicm      893:
1.87      nicm      894:        screen_write_initctx(ctx, &ttyctx);
1.1       nicm      895:
1.20      nicm      896:        gl = &s->grid->linedata[s->grid->hsize + s->cy];
                    897:        if (wrapped)
                    898:                gl->flags |= GRID_LINE_WRAPPED;
1.73      nicm      899:        else
                    900:                gl->flags &= ~GRID_LINE_WRAPPED;
1.20      nicm      901:
1.92      nicm      902:        if (s->cy == s->rlower) {
                    903:                screen_dirty_clear(s, 0, s->rupper, sx - 1, s->rupper);
                    904:                screen_write_flush(ctx);
1.1       nicm      905:                grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
1.92      nicm      906:        } else if (s->cy < sy - 1)
1.1       nicm      907:                s->cy++;
                    908:
1.34      nicm      909:        ttyctx.num = wrapped;
1.41      nicm      910:        tty_write(tty_cmd_linefeed, &ttyctx);
1.1       nicm      911: }
                    912:
                    913: /* Carriage return (cursor to start of line). */
                    914: void
                    915: screen_write_carriagereturn(struct screen_write_ctx *ctx)
                    916: {
                    917:        struct screen   *s = ctx->s;
                    918:
                    919:        s->cx = 0;
                    920: }
                    921:
                    922: /* Clear to end of screen from cursor. */
                    923: void
1.99      nicm      924: screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm      925: {
                    926:        struct screen   *s = ctx->s;
1.107     nicm      927:        struct grid     *gd = s->grid;
1.17      nicm      928:        struct tty_ctx   ttyctx;
1.92      nicm      929:        u_int            sx = screen_size_x(s), sy = screen_size_y(s);
1.1       nicm      930:
1.87      nicm      931:        screen_write_initctx(ctx, &ttyctx);
1.99      nicm      932:        ttyctx.bg = bg;
1.1       nicm      933:
1.46      nicm      934:        /* Scroll into history if it is enabled and clearing entire screen. */
1.107     nicm      935:        if (s->cx == 0 && s->cy == 0 && gd->flags & GRID_HISTORY) {
1.92      nicm      936:                screen_dirty_clear(s, 0, 0, sx - 1, sy  - 1);
1.107     nicm      937:                grid_view_clear_history(gd, bg);
1.92      nicm      938:        } else {
                    939:                if (s->cx <= sx - 1) {
                    940:                        screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
1.107     nicm      941:                        grid_view_clear(gd, s->cx, s->cy, sx - s->cx, 1, bg);
1.92      nicm      942:                }
                    943:                screen_dirty_clear(s, 0, s->cy + 1, sx - 1, sy - 1);
1.107     nicm      944:                grid_view_clear(gd, 0, s->cy + 1, sx, sy - (s->cy + 1), bg);
1.46      nicm      945:        }
1.1       nicm      946:
1.17      nicm      947:        tty_write(tty_cmd_clearendofscreen, &ttyctx);
1.1       nicm      948: }
                    949:
                    950: /* Clear to start of screen. */
                    951: void
1.105     nicm      952: screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm      953: {
                    954:        struct screen   *s = ctx->s;
1.17      nicm      955:        struct tty_ctx   ttyctx;
1.92      nicm      956:        u_int            sx = screen_size_x(s);
1.1       nicm      957:
1.87      nicm      958:        screen_write_initctx(ctx, &ttyctx);
1.105     nicm      959:        ttyctx.bg = bg;
1.1       nicm      960:
1.92      nicm      961:        if (s->cy > 0) {
                    962:                screen_dirty_clear(s, 0, 0, sx - 1, s->cy);
1.105     nicm      963:                grid_view_clear(s->grid, 0, 0, sx, s->cy, bg);
1.92      nicm      964:        }
                    965:        if (s->cx > sx - 1) {
                    966:                screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
1.105     nicm      967:                grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
1.92      nicm      968:        } else {
                    969:                screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
1.105     nicm      970:                grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
1.92      nicm      971:        }
1.1       nicm      972:
1.17      nicm      973:        tty_write(tty_cmd_clearstartofscreen, &ttyctx);
1.1       nicm      974: }
                    975:
                    976: /* Clear entire screen. */
                    977: void
1.99      nicm      978: screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm      979: {
                    980:        struct screen   *s = ctx->s;
1.17      nicm      981:        struct tty_ctx   ttyctx;
1.92      nicm      982:        u_int            sx = screen_size_x(s), sy = screen_size_y(s);
1.1       nicm      983:
1.87      nicm      984:        screen_write_initctx(ctx, &ttyctx);
1.99      nicm      985:        ttyctx.bg = bg;
1.1       nicm      986:
1.92      nicm      987:        screen_dirty_clear(s, 0, 0, sx - 1, sy  - 1);
                    988:
1.46      nicm      989:        /* Scroll into history if it is enabled. */
                    990:        if (s->grid->flags & GRID_HISTORY)
1.99      nicm      991:                grid_view_clear_history(s->grid, bg);
1.83      nicm      992:        else
1.99      nicm      993:                grid_view_clear(s->grid, 0, 0, sx, sy, bg);
1.1       nicm      994:
1.17      nicm      995:        tty_write(tty_cmd_clearscreen, &ttyctx);
1.51      nicm      996: }
                    997:
                    998: /* Clear entire history. */
                    999: void
                   1000: screen_write_clearhistory(struct screen_write_ctx *ctx)
                   1001: {
                   1002:        struct screen   *s = ctx->s;
                   1003:        struct grid     *gd = s->grid;
                   1004:
1.99      nicm     1005:        grid_move_lines(gd, 0, gd->hsize, gd->sy, 8);
1.93      nicm     1006:        gd->hscrolled = gd->hsize = 0;
1.1       nicm     1007: }
                   1008:
                   1009: /* Write cell data. */
                   1010: void
1.60      nicm     1011: screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
1.1       nicm     1012: {
                   1013:        struct screen           *s = ctx->s;
                   1014:        struct grid             *gd = s->grid;
1.15      nicm     1015:        struct tty_ctx           ttyctx;
1.64      nicm     1016:        u_int                    width, xx, last;
1.92      nicm     1017:        u_int                    sx = screen_size_x(s), sy = screen_size_y(s);
                   1018:        struct grid_line        *gl;
1.89      nicm     1019:        struct grid_cell         tmp_gc, now_gc;
1.92      nicm     1020:        struct grid_cell_entry  *gce;
1.106     nicm     1021:        int                      insert, skip, selected;
1.92      nicm     1022:
                   1023:        ctx->cells++;
1.1       nicm     1024:
                   1025:        /* Ignore padding. */
                   1026:        if (gc->flags & GRID_FLAG_PADDING)
                   1027:                return;
1.77      nicm     1028:        width = gc->data.width;
1.1       nicm     1029:
1.32      nicm     1030:        /*
1.103     nicm     1031:         * If this is a wide character and there is no room on the screen for
1.32      nicm     1032:         * the entire character, don't print it.
                   1033:         */
1.92      nicm     1034:        if (!(s->mode & MODE_WRAP) && (width > 1 &&
                   1035:            (width > sx || (s->cx != sx && s->cx > sx - width))))
1.32      nicm     1036:                return;
                   1037:
1.35      nicm     1038:        /*
                   1039:         * If the width is zero, combine onto the previous character, if
1.41      nicm     1040:         * there is space.
1.35      nicm     1041:         */
1.1       nicm     1042:        if (width == 0) {
1.104     nicm     1043:                if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) {
                   1044:                        screen_write_cursormove(ctx, xx, s->cy);
1.87      nicm     1045:                        screen_write_initctx(ctx, &ttyctx);
1.104     nicm     1046:                        ttyctx.cell = gc;
                   1047:                        tty_write(tty_cmd_cell, &ttyctx);
1.1       nicm     1048:                }
                   1049:                return;
                   1050:        }
                   1051:
1.6       nicm     1052:        /* If in insert mode, make space for the cells. */
1.98      nicm     1053:        if (s->mode & MODE_INSERT) {
                   1054:                if (s->cx <= sx - width) {
                   1055:                        screen_write_flush(ctx);
                   1056:                        xx = sx - s->cx - width;
1.99      nicm     1057:                        grid_view_insert_cells(s->grid, s->cx, s->cy, xx, 8);
1.98      nicm     1058:                }
1.6       nicm     1059:                insert = 1;
1.64      nicm     1060:        } else
                   1061:                insert = 0;
1.89      nicm     1062:        skip = !insert;
1.6       nicm     1063:
1.20      nicm     1064:        /* Check this will fit on the current line and wrap if not. */
1.92      nicm     1065:        if ((s->mode & MODE_WRAP) && s->cx > sx - width) {
1.34      nicm     1066:                screen_write_linefeed(ctx, 1);
1.30      nicm     1067:                s->cx = 0;      /* carriage return */
1.1       nicm     1068:        }
                   1069:
1.64      nicm     1070:        /* Sanity check cursor position. */
1.92      nicm     1071:        if (s->cx > sx - width || s->cy > sy - 1)
1.1       nicm     1072:                return;
                   1073:
1.106     nicm     1074:        /* Initialise the redraw context. */
                   1075:        screen_write_initctx(ctx, &ttyctx);
                   1076:
1.1       nicm     1077:        /* Handle overwriting of UTF-8 characters. */
1.92      nicm     1078:        gl = &s->grid->linedata[s->grid->hsize + s->cy];
                   1079:        if (gl->flags & GRID_LINE_EXTENDED) {
                   1080:                grid_view_get_cell(gd, s->cx, s->cy, &now_gc);
                   1081:                if (screen_write_overwrite(ctx, &now_gc, width))
                   1082:                        skip = 0;
                   1083:        }
1.1       nicm     1084:
                   1085:        /*
                   1086:         * If the new character is UTF-8 wide, fill in padding cells. Have
                   1087:         * already ensured there is enough room.
                   1088:         */
1.89      nicm     1089:        for (xx = s->cx + 1; xx < s->cx + width; xx++) {
1.88      nicm     1090:                grid_view_set_cell(gd, xx, s->cy, &screen_write_pad_cell);
1.89      nicm     1091:                skip = 0;
                   1092:        }
                   1093:
                   1094:        /* If no change, do not draw. */
1.92      nicm     1095:        if (skip) {
                   1096:                if (s->cx >= gl->cellsize)
                   1097:                        skip = grid_cells_equal(gc, &grid_default_cell);
                   1098:                else {
                   1099:                        gce = &gl->celldata[s->cx];
                   1100:                        if (gce->flags & GRID_FLAG_EXTENDED)
                   1101:                                skip = 0;
1.95      nicm     1102:                        else if (gc->flags != gce->flags)
1.92      nicm     1103:                                skip = 0;
                   1104:                        else if (gc->attr != gce->data.attr)
                   1105:                                skip = 0;
                   1106:                        else if (gc->fg != gce->data.fg)
                   1107:                                skip = 0;
                   1108:                        else if (gc->bg != gce->data.bg)
                   1109:                                skip = 0;
1.95      nicm     1110:                        else if (gc->data.width != 1)
                   1111:                                skip = 0;
                   1112:                        else if (gce->data.data != gc->data.data[0])
1.92      nicm     1113:                                skip = 0;
                   1114:                }
                   1115:        }
1.1       nicm     1116:
1.90      nicm     1117:        /* Update the selection the flag and set the cell. */
                   1118:        selected = screen_check_selection(s, s->cx, s->cy);
                   1119:        if (selected && ~gc->flags & GRID_FLAG_SELECTED) {
                   1120:                skip = 0;
                   1121:                memcpy(&tmp_gc, gc, sizeof tmp_gc);
                   1122:                tmp_gc.flags |= GRID_FLAG_SELECTED;
                   1123:                grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
                   1124:        } else if (!selected && gc->flags & GRID_FLAG_SELECTED) {
                   1125:                skip = 0;
                   1126:                memcpy(&tmp_gc, gc, sizeof tmp_gc);
                   1127:                tmp_gc.flags &= ~GRID_FLAG_SELECTED;
                   1128:                grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
                   1129:        } else if (!skip)
1.89      nicm     1130:                grid_view_set_cell(gd, s->cx, s->cy, gc);
1.1       nicm     1131:
1.64      nicm     1132:        /*
                   1133:         * Move the cursor. If not wrapping, stick at the last character and
                   1134:         * replace it.
                   1135:         */
1.65      nicm     1136:        last = !(s->mode & MODE_WRAP);
1.92      nicm     1137:        if (s->cx <= sx - last - width)
1.64      nicm     1138:                s->cx += width;
                   1139:        else
1.92      nicm     1140:                s->cx = sx - last;
1.1       nicm     1141:
1.89      nicm     1142:        /* Create space for character in insert mode. */
1.17      nicm     1143:        if (insert) {
                   1144:                ttyctx.num = width;
                   1145:                tty_write(tty_cmd_insertcharacter, &ttyctx);
                   1146:        }
1.89      nicm     1147:
                   1148:        /* Write to the screen. */
                   1149:        if (selected) {
1.92      nicm     1150:                screen_write_flush(ctx);
1.97      nicm     1151:                screen_select_cell(s, &tmp_gc, gc);
1.33      nicm     1152:                ttyctx.cell = &tmp_gc;
1.16      nicm     1153:                tty_write(tty_cmd_cell, &ttyctx);
1.92      nicm     1154:                ctx->written++;
1.89      nicm     1155:        } else if (!skip) {
1.106     nicm     1156:                /*
                   1157:                 * If wp is NULL, we are not updating the terminal and don't
                   1158:                 * care about actually writing the cells (tty_write will just
                   1159:                 * return). So don't even bother allocating the dirty array.
                   1160:                 */
                   1161:                if (ctx->wp != NULL && s->dirty == NULL) {
                   1162:                        log_debug("%s: allocating %u bits", __func__,
                   1163:                            s->dirtysize);
                   1164:                        s->dirty = bit_alloc(s->dirtysize);
                   1165:                }
                   1166:                if (s->dirty != NULL) {
                   1167:                        bit_set(s->dirty, screen_dirty_bit(s,
                   1168:                            ttyctx.ocx, ttyctx.ocy));
                   1169:                        ctx->dirty++;
1.92      nicm     1170:                }
                   1171:        } else
                   1172:                ctx->skipped++;
1.35      nicm     1173: }
                   1174:
                   1175: /* Combine a UTF-8 zero-width character onto the previous. */
1.104     nicm     1176: static const struct grid_cell *
                   1177: screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud,
                   1178:     u_int *xx)
1.35      nicm     1179: {
                   1180:        struct screen           *s = ctx->s;
                   1181:        struct grid             *gd = s->grid;
1.104     nicm     1182:        static struct grid_cell  gc;
                   1183:        u_int                    n;
1.35      nicm     1184:
                   1185:        /* Can't combine if at 0. */
                   1186:        if (s->cx == 0)
1.104     nicm     1187:                return (NULL);
1.35      nicm     1188:
1.60      nicm     1189:        /* Empty data is out. */
                   1190:        if (ud->size == 0)
1.37      nicm     1191:                fatalx("UTF-8 data empty");
                   1192:
1.60      nicm     1193:        /* Retrieve the previous cell. */
1.104     nicm     1194:        for (n = 1; n < s->cx; n++) {
                   1195:                grid_view_get_cell(gd, s->cx - n, s->cy, &gc);
                   1196:                if (~gc.flags & GRID_FLAG_PADDING)
                   1197:                        break;
                   1198:        }
                   1199:        if (n == s->cx)
                   1200:                return (NULL);
                   1201:        *xx = s->cx - n;
1.35      nicm     1202:
1.60      nicm     1203:        /* Check there is enough space. */
1.77      nicm     1204:        if (gc.data.size + ud->size > sizeof gc.data.data)
1.104     nicm     1205:                return (NULL);
                   1206:
                   1207:        log_debug("%s: %.*s onto %.*s at %u,%u", __func__, (int)ud->size,
                   1208:            ud->data, (int)gc.data.size, gc.data.data, *xx, s->cy);
1.35      nicm     1209:
1.77      nicm     1210:        /* Append the data. */
                   1211:        memcpy(gc.data.data + gc.data.size, ud->data, ud->size);
                   1212:        gc.data.size += ud->size;
                   1213:
                   1214:        /* Set the new cell. */
1.104     nicm     1215:        grid_view_set_cell(gd, *xx, s->cy, &gc);
1.35      nicm     1216:
1.104     nicm     1217:        return (&gc);
1.1       nicm     1218: }
                   1219:
                   1220: /*
                   1221:  * UTF-8 wide characters are a bit of an annoyance. They take up more than one
                   1222:  * cell on the screen, so following cells must not be drawn by marking them as
                   1223:  * padding.
                   1224:  *
                   1225:  * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
                   1226:  * character, it is necessary to also overwrite any other cells which covered
                   1227:  * by the same character.
                   1228:  */
1.89      nicm     1229: static int
                   1230: screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
                   1231:     u_int width)
1.1       nicm     1232: {
                   1233:        struct screen           *s = ctx->s;
                   1234:        struct grid             *gd = s->grid;
1.89      nicm     1235:        struct grid_cell         tmp_gc;
1.1       nicm     1236:        u_int                    xx;
1.89      nicm     1237:        int                      done = 0;
1.1       nicm     1238:
1.89      nicm     1239:        if (gc->flags & GRID_FLAG_PADDING) {
1.1       nicm     1240:                /*
                   1241:                 * A padding cell, so clear any following and leading padding
                   1242:                 * cells back to the character. Don't overwrite the current
                   1243:                 * cell as that happens later anyway.
                   1244:                 */
                   1245:                xx = s->cx + 1;
                   1246:                while (--xx > 0) {
1.89      nicm     1247:                        grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
                   1248:                        if (~tmp_gc.flags & GRID_FLAG_PADDING)
1.1       nicm     1249:                                break;
                   1250:                        grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
                   1251:                }
                   1252:
                   1253:                /* Overwrite the character at the start of this padding. */
                   1254:                grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1.89      nicm     1255:                done = 1;
1.43      nicm     1256:        }
1.1       nicm     1257:
1.43      nicm     1258:        /*
1.95      nicm     1259:         * Overwrite any padding cells that belong to any UTF-8 characters
                   1260:         * we'll be overwriting with the current character.
1.43      nicm     1261:         */
1.95      nicm     1262:        if (width != 1 ||
                   1263:            gc->data.width != 1 ||
                   1264:            gc->flags & GRID_FLAG_PADDING) {
1.89      nicm     1265:                xx = s->cx + width - 1;
                   1266:                while (++xx < screen_size_x(s)) {
                   1267:                        grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
                   1268:                        if (~tmp_gc.flags & GRID_FLAG_PADDING)
                   1269:                                break;
                   1270:                        grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
                   1271:                        done = 1;
                   1272:                }
1.1       nicm     1273:        }
1.89      nicm     1274:
                   1275:        return (done);
1.50      nicm     1276: }
                   1277:
1.107     nicm     1278: /* Set external clipboard. */
1.50      nicm     1279: void
                   1280: screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len)
                   1281: {
                   1282:        struct tty_ctx  ttyctx;
                   1283:
1.87      nicm     1284:        screen_write_initctx(ctx, &ttyctx);
1.50      nicm     1285:        ttyctx.ptr = str;
                   1286:        ttyctx.num = len;
                   1287:
                   1288:        tty_write(tty_cmd_setselection, &ttyctx);
1.47      nicm     1289: }
                   1290:
1.107     nicm     1291: /* Write unmodified string. */
1.47      nicm     1292: void
                   1293: screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len)
                   1294: {
1.87      nicm     1295:        struct tty_ctx  ttyctx;
1.47      nicm     1296:
1.87      nicm     1297:        screen_write_initctx(ctx, &ttyctx);
1.47      nicm     1298:        ttyctx.ptr = str;
                   1299:        ttyctx.num = len;
                   1300:
                   1301:        tty_write(tty_cmd_rawstring, &ttyctx);
1.1       nicm     1302: }