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

1.214   ! nicm        1: /* $OpenBSD: screen-write.c,v 1.213 2023/02/10 14:01:43 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.193     nicm       26: static struct screen_write_citem *screen_write_collect_trim(
                     27:                    struct screen_write_ctx *, u_int, u_int, u_int, int *);
1.109     nicm       28: static void    screen_write_collect_clear(struct screen_write_ctx *, u_int,
                     29:                    u_int);
1.193     nicm       30: static void    screen_write_collect_scroll(struct screen_write_ctx *, u_int);
1.164     nicm       31: static void    screen_write_collect_flush(struct screen_write_ctx *, int,
                     32:                    const char *);
1.87      nicm       33:
1.89      nicm       34: static int     screen_write_overwrite(struct screen_write_ctx *,
                     35:                    struct grid_cell *, u_int);
1.104     nicm       36: static const struct grid_cell *screen_write_combine(struct screen_write_ctx *,
1.213     nicm       37:                    const struct utf8_data *, u_int *, u_int *);
1.1       nicm       38:
1.193     nicm       39: struct screen_write_citem {
                     40:        u_int                           x;
                     41:        int                             wrapped;
                     42:
                     43:        enum { TEXT, CLEAR }            type;
                     44:        u_int                           used;
                     45:        u_int                           bg;
1.109     nicm       46:
1.193     nicm       47:        struct grid_cell                gc;
1.109     nicm       48:
1.193     nicm       49:        TAILQ_ENTRY(screen_write_citem) entry;
1.109     nicm       50: };
1.193     nicm       51: struct screen_write_cline {
                     52:        char                            *data;
                     53:        TAILQ_HEAD(, screen_write_citem) items;
1.109     nicm       54: };
1.193     nicm       55: TAILQ_HEAD(, screen_write_citem)  screen_write_citem_freelist =
                     56:     TAILQ_HEAD_INITIALIZER(screen_write_citem_freelist);
                     57:
                     58: static struct screen_write_citem *
                     59: screen_write_get_citem(void)
                     60: {
                     61:     struct screen_write_citem  *ci;
                     62:
                     63:     ci = TAILQ_FIRST(&screen_write_citem_freelist);
                     64:     if (ci != NULL) {
                     65:         TAILQ_REMOVE(&screen_write_citem_freelist, ci, entry);
                     66:         memset(ci, 0, sizeof *ci);
                     67:         return (ci);
                     68:     }
                     69:     return (xcalloc(1, sizeof *ci));
                     70: }
                     71:
                     72: static void
                     73: screen_write_free_citem(struct screen_write_citem *ci)
                     74: {
                     75:     TAILQ_INSERT_TAIL(&screen_write_citem_freelist, ci, entry);
                     76: }
1.92      nicm       77:
1.139     nicm       78: static void
                     79: screen_write_offset_timer(__unused int fd, __unused short events, void *data)
                     80: {
                     81:        struct window   *w = data;
                     82:
                     83:        tty_update_window_offset(w);
                     84: }
                     85:
                     86: /* Set cursor position. */
                     87: static void
                     88: screen_write_set_cursor(struct screen_write_ctx *ctx, int cx, int cy)
                     89: {
                     90:        struct window_pane      *wp = ctx->wp;
                     91:        struct window           *w;
                     92:        struct screen           *s = ctx->s;
                     93:        struct timeval           tv = { .tv_usec = 10000 };
                     94:
                     95:        if (cx != -1 && (u_int)cx == s->cx && cy != -1 && (u_int)cy == s->cy)
                     96:                return;
                     97:
1.144     nicm       98:        if (cx != -1) {
1.145     nicm       99:                if ((u_int)cx > screen_size_x(s)) /* allow last column */
1.144     nicm      100:                        cx = screen_size_x(s) - 1;
1.139     nicm      101:                s->cx = cx;
1.144     nicm      102:        }
                    103:        if (cy != -1) {
                    104:                if ((u_int)cy > screen_size_y(s) - 1)
                    105:                        cy = screen_size_y(s) - 1;
1.139     nicm      106:                s->cy = cy;
1.144     nicm      107:        }
1.139     nicm      108:
                    109:        if (wp == NULL)
                    110:                return;
                    111:        w = wp->window;
                    112:
                    113:        if (!event_initialized(&w->offset_timer))
                    114:                evtimer_set(&w->offset_timer, screen_write_offset_timer, w);
                    115:        if (!evtimer_pending(&w->offset_timer, NULL))
                    116:                evtimer_add(&w->offset_timer, &tv);
                    117: }
                    118:
1.178     nicm      119: /* Do a full redraw. */
                    120: static void
                    121: screen_write_redraw_cb(const struct tty_ctx *ttyctx)
                    122: {
                    123:        struct window_pane      *wp = ttyctx->arg;
                    124:
1.185     nicm      125:        if (wp != NULL)
                    126:                wp->flags |= PANE_REDRAW;
1.178     nicm      127: }
                    128:
                    129: /* Update context for client. */
                    130: static int
                    131: screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
                    132: {
                    133:        struct window_pane      *wp = ttyctx->arg;
1.214   ! nicm      134:
        !           135:        if (ttyctx->allow_invisible_panes) {
        !           136:                if (session_has(c->session, wp->window))
        !           137:                        return (1);
        !           138:                return (0);
        !           139:        }
1.178     nicm      140:
                    141:        if (c->session->curw->window != wp->window)
                    142:                return (0);
                    143:        if (wp->layout_cell == NULL)
                    144:                return (0);
                    145:
                    146:        if (wp->flags & (PANE_REDRAW|PANE_DROP))
                    147:                return (-1);
                    148:        if (c->flags & CLIENT_REDRAWPANES) {
                    149:                /*
                    150:                 * Redraw is already deferred to redraw another pane - redraw
                    151:                 * this one also when that happens.
                    152:                 */
1.193     nicm      153:                log_debug("%s: adding %%%u to deferred redraw", __func__,
                    154:                    wp->id);
1.178     nicm      155:                wp->flags |= PANE_REDRAW;
                    156:                return (-1);
                    157:        }
                    158:
                    159:        ttyctx->bigger = tty_window_offset(&c->tty, &ttyctx->wox, &ttyctx->woy,
                    160:            &ttyctx->wsx, &ttyctx->wsy);
                    161:
                    162:        ttyctx->xoff = ttyctx->rxoff = wp->xoff;
                    163:        ttyctx->yoff = ttyctx->ryoff = wp->yoff;
                    164:
                    165:        if (status_at_line(c) == 0)
                    166:                ttyctx->yoff += status_line_size(c);
                    167:
                    168:        return (1);
                    169: }
                    170:
1.163     nicm      171: /* Set up context for TTY command. */
                    172: static void
                    173: screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
                    174:     int sync)
                    175: {
                    176:        struct screen   *s = ctx->s;
                    177:
                    178:        memset(ttyctx, 0, sizeof *ttyctx);
                    179:
1.178     nicm      180:        ttyctx->s = s;
1.177     nicm      181:        ttyctx->sx = screen_size_x(s);
                    182:        ttyctx->sy = screen_size_y(s);
1.163     nicm      183:
                    184:        ttyctx->ocx = s->cx;
                    185:        ttyctx->ocy = s->cy;
                    186:        ttyctx->orlower = s->rlower;
                    187:        ttyctx->orupper = s->rupper;
                    188:
1.197     nicm      189:        memcpy(&ttyctx->defaults, &grid_default_cell, sizeof ttyctx->defaults);
                    190:        if (ctx->init_ctx_cb != NULL) {
1.178     nicm      191:                ctx->init_ctx_cb(ctx, ttyctx);
1.197     nicm      192:                if (ttyctx->palette != NULL) {
1.204     nicm      193:                        if (ttyctx->defaults.fg == 8)
1.203     nicm      194:                                ttyctx->defaults.fg = ttyctx->palette->fg;
1.204     nicm      195:                        if (ttyctx->defaults.bg == 8)
1.203     nicm      196:                                ttyctx->defaults.bg = ttyctx->palette->bg;
1.197     nicm      197:                }
                    198:        } else {
1.178     nicm      199:                ttyctx->redraw_cb = screen_write_redraw_cb;
1.197     nicm      200:                if (ctx->wp != NULL) {
                    201:                        tty_default_colours(&ttyctx->defaults, ctx->wp);
                    202:                        ttyctx->palette = &ctx->wp->palette;
1.178     nicm      203:                        ttyctx->set_client_cb = screen_write_set_client_cb;
1.197     nicm      204:                        ttyctx->arg = ctx->wp;
                    205:                }
1.178     nicm      206:        }
                    207:
1.199     nicm      208:        if (~ctx->flags & SCREEN_WRITE_SYNC) {
                    209:                /*
                    210:                 * For the active pane or for an overlay (no pane), we want to
                    211:                 * only use synchronized updates if requested (commands that
                    212:                 * move the cursor); for other panes, always use it, since the
                    213:                 * cursor will have to move.
                    214:                 */
                    215:                if (ctx->wp != NULL) {
                    216:                        if (ctx->wp != ctx->wp->window->active)
                    217:                                ttyctx->num = 1;
                    218:                        else
                    219:                                ttyctx->num = sync;
                    220:                } else
                    221:                        ttyctx->num = 0x10|sync;
1.163     nicm      222:                tty_write(tty_cmd_syncstart, ttyctx);
1.180     nicm      223:                ctx->flags |= SCREEN_WRITE_SYNC;
1.163     nicm      224:        }
                    225: }
                    226:
1.170     nicm      227: /* Make write list. */
                    228: void
                    229: screen_write_make_list(struct screen *s)
                    230: {
                    231:        u_int   y;
                    232:
                    233:        s->write_list = xcalloc(screen_size_y(s), sizeof *s->write_list);
                    234:        for (y = 0; y < screen_size_y(s); y++)
                    235:                TAILQ_INIT(&s->write_list[y].items);
                    236: }
                    237:
                    238: /* Free write list. */
                    239: void
                    240: screen_write_free_list(struct screen *s)
                    241: {
                    242:        u_int   y;
                    243:
                    244:        for (y = 0; y < screen_size_y(s); y++)
                    245:                free(s->write_list[y].data);
                    246:        free(s->write_list);
                    247: }
                    248:
1.178     nicm      249: /* Set up for writing. */
                    250: static void
                    251: screen_write_init(struct screen_write_ctx *ctx, struct screen *s)
1.1       nicm      252: {
1.109     nicm      253:        memset(ctx, 0, sizeof *ctx);
1.92      nicm      254:
1.178     nicm      255:        ctx->s = s;
1.92      nicm      256:
1.170     nicm      257:        if (ctx->s->write_list == NULL)
                    258:                screen_write_make_list(ctx->s);
1.193     nicm      259:        ctx->item = screen_write_get_citem();
1.92      nicm      260:
1.122     nicm      261:        ctx->scrolled = 0;
                    262:        ctx->bg = 8;
1.178     nicm      263: }
                    264:
                    265: /* Initialize writing with a pane. */
                    266: void
                    267: screen_write_start_pane(struct screen_write_ctx *ctx, struct window_pane *wp,
                    268:     struct screen *s)
                    269: {
                    270:        if (s == NULL)
                    271:                s = wp->screen;
                    272:        screen_write_init(ctx, s);
                    273:        ctx->wp = wp;
                    274:
                    275:        if (log_get_level() != 0) {
                    276:                log_debug("%s: size %ux%u, pane %%%u (at %u,%u)",
                    277:                    __func__, screen_size_x(ctx->s), screen_size_y(ctx->s),
                    278:                    wp->id, wp->xoff, wp->yoff);
                    279:        }
                    280: }
                    281:
                    282: /* Initialize writing with a callback. */
                    283: void
                    284: screen_write_start_callback(struct screen_write_ctx *ctx, struct screen *s,
                    285:     screen_write_init_ctx_cb cb, void *arg)
                    286: {
                    287:        screen_write_init(ctx, s);
                    288:
                    289:        ctx->init_ctx_cb = cb;
                    290:        ctx->arg = arg;
                    291:
                    292:        if (log_get_level() != 0) {
                    293:                log_debug("%s: size %ux%u, with callback", __func__,
                    294:                    screen_size_x(ctx->s), screen_size_y(ctx->s));
                    295:        }
                    296: }
                    297:
                    298: /* Initialize writing. */
                    299: void
                    300: screen_write_start(struct screen_write_ctx *ctx, struct screen *s)
                    301: {
                    302:        screen_write_init(ctx, s);
1.122     nicm      303:
1.158     nicm      304:        if (log_get_level() != 0) {
1.178     nicm      305:                log_debug("%s: size %ux%u, no pane", __func__,
                    306:                    screen_size_x(ctx->s), screen_size_y(ctx->s));
1.139     nicm      307:        }
1.1       nicm      308: }
                    309:
                    310: /* Finish writing. */
                    311: void
1.92      nicm      312: screen_write_stop(struct screen_write_ctx *ctx)
                    313: {
1.109     nicm      314:        screen_write_collect_end(ctx);
1.164     nicm      315:        screen_write_collect_flush(ctx, 0, __func__);
1.92      nicm      316:
1.193     nicm      317:        screen_write_free_citem(ctx->item);
1.52      nicm      318: }
                    319:
                    320: /* Reset screen state. */
                    321: void
                    322: screen_write_reset(struct screen_write_ctx *ctx)
                    323: {
1.61      nicm      324:        struct screen   *s = ctx->s;
1.52      nicm      325:
1.61      nicm      326:        screen_reset_tabs(s);
                    327:        screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
1.63      nicm      328:
1.141     nicm      329:        s->mode = MODE_CURSOR | MODE_WRAP;
1.52      nicm      330:
1.99      nicm      331:        screen_write_clearscreen(ctx, 8);
1.144     nicm      332:        screen_write_set_cursor(ctx, 0, 0);
1.1       nicm      333: }
                    334:
                    335: /* Write character. */
                    336: void
1.86      nicm      337: screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
1.69      nicm      338:     u_char ch)
1.1       nicm      339: {
1.86      nicm      340:        struct grid_cell        gc;
                    341:
                    342:        memcpy(&gc, gcp, sizeof gc);
                    343:
                    344:        utf8_set(&gc.data, ch);
                    345:        screen_write_cell(ctx, &gc);
1.1       nicm      346: }
                    347:
1.2       nicm      348: /* Calculate string length. */
1.71      nicm      349: size_t
1.75      nicm      350: screen_write_strlen(const char *fmt, ...)
1.2       nicm      351: {
1.36      nicm      352:        va_list                 ap;
                    353:        char                   *msg;
1.76      nicm      354:        struct utf8_data        ud;
1.36      nicm      355:        u_char                 *ptr;
                    356:        size_t                  left, size = 0;
1.79      nicm      357:        enum utf8_state         more;
1.2       nicm      358:
                    359:        va_start(ap, fmt);
                    360:        xvasprintf(&msg, fmt, ap);
                    361:        va_end(ap);
                    362:
                    363:        ptr = msg;
                    364:        while (*ptr != '\0') {
1.79      nicm      365:                if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
1.36      nicm      366:                        ptr++;
1.2       nicm      367:
                    368:                        left = strlen(ptr);
1.77      nicm      369:                        if (left < (size_t)ud.size - 1)
1.36      nicm      370:                                break;
1.79      nicm      371:                        while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
1.2       nicm      372:                                ptr++;
1.36      nicm      373:                        ptr++;
                    374:
1.79      nicm      375:                        if (more == UTF8_DONE)
1.78      nicm      376:                                size += ud.width;
1.2       nicm      377:                } else {
1.75      nicm      378:                        if (*ptr > 0x1f && *ptr < 0x7f)
                    379:                                size++;
1.2       nicm      380:                        ptr++;
                    381:                }
1.7       ray       382:        }
1.2       nicm      383:
1.56      nicm      384:        free(msg);
1.2       nicm      385:        return (size);
                    386: }
                    387:
1.179     nicm      388: /* Write string wrapped over lines. */
                    389: int
                    390: screen_write_text(struct screen_write_ctx *ctx, u_int cx, u_int width,
                    391:     u_int lines, int more, const struct grid_cell *gcp, const char *fmt, ...)
                    392: {
                    393:        struct screen           *s = ctx->s;
                    394:        va_list                  ap;
                    395:        char                    *tmp;
                    396:        u_int                    cy = s->cy, i, end, next, idx = 0, at, left;
                    397:        struct utf8_data        *text;
                    398:        struct grid_cell         gc;
                    399:
                    400:        memcpy(&gc, gcp, sizeof gc);
                    401:
                    402:        va_start(ap, fmt);
                    403:        xvasprintf(&tmp, fmt, ap);
                    404:        va_end(ap);
                    405:
                    406:        text = utf8_fromcstr(tmp);
                    407:        free(tmp);
                    408:
                    409:        left = (cx + width) - s->cx;
                    410:        for (;;) {
                    411:                /* Find the end of what can fit on the line. */
                    412:                at = 0;
                    413:                for (end = idx; text[end].size != 0; end++) {
                    414:                        if (text[end].size == 1 && text[end].data[0] == '\n')
                    415:                                break;
                    416:                        if (at + text[end].width > left)
                    417:                                break;
                    418:                        at += text[end].width;
                    419:                }
                    420:
                    421:                /*
                    422:                 * If we're on a space, that's the end. If not, walk back to
                    423:                 * try and find one.
                    424:                 */
                    425:                if (text[end].size == 0)
                    426:                        next = end;
                    427:                else if (text[end].size == 1 && text[end].data[0] == '\n')
                    428:                        next = end + 1;
                    429:                else if (text[end].size == 1 && text[end].data[0] == ' ')
                    430:                        next = end + 1;
                    431:                else {
                    432:                        for (i = end; i > idx; i--) {
                    433:                                if (text[i].size == 1 && text[i].data[0] == ' ')
                    434:                                        break;
                    435:                        }
                    436:                        if (i != idx) {
                    437:                                next = i + 1;
                    438:                                end = i;
                    439:                        } else
                    440:                                next = end;
                    441:                }
                    442:
                    443:                /* Print the line. */
                    444:                for (i = idx; i < end; i++) {
                    445:                        utf8_copy(&gc.data, &text[i]);
                    446:                        screen_write_cell(ctx, &gc);
                    447:                }
                    448:
                    449:                /* If at the bottom, stop. */
                    450:                idx = next;
                    451:                if (s->cy == cy + lines - 1 || text[idx].size == 0)
                    452:                        break;
                    453:
                    454:                screen_write_cursormove(ctx, cx, s->cy + 1, 0);
                    455:                left = width;
                    456:        }
                    457:
                    458:        /*
                    459:         * Fail if on the last line and there is more to come or at the end, or
                    460:         * if the text was not entirely consumed.
                    461:         */
                    462:        if ((s->cy == cy + lines - 1 && (!more || s->cx == cx + width)) ||
                    463:            text[idx].size != 0) {
                    464:                free(text);
                    465:                return (0);
                    466:        }
                    467:        free(text);
                    468:
                    469:        /*
                    470:         * If no more to come, move to the next line. Otherwise, leave on
                    471:         * the same line (except if at the end).
                    472:         */
                    473:        if (!more || s->cx == cx + width)
                    474:                screen_write_cursormove(ctx, cx, s->cy + 1, 0);
                    475:        return (1);
                    476: }
                    477:
                    478: /* Write simple string (no maximum length). */
1.71      nicm      479: void
1.86      nicm      480: screen_write_puts(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
1.71      nicm      481:     const char *fmt, ...)
1.1       nicm      482: {
                    483:        va_list ap;
                    484:
                    485:        va_start(ap, fmt);
1.86      nicm      486:        screen_write_vnputs(ctx, -1, gcp, fmt, ap);
1.2       nicm      487:        va_end(ap);
                    488: }
                    489:
                    490: /* Write string with length limit (-1 for unlimited). */
1.71      nicm      491: void
                    492: screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen,
1.86      nicm      493:     const struct grid_cell *gcp, const char *fmt, ...)
1.2       nicm      494: {
                    495:        va_list ap;
                    496:
                    497:        va_start(ap, fmt);
1.86      nicm      498:        screen_write_vnputs(ctx, maxlen, gcp, fmt, ap);
1.2       nicm      499:        va_end(ap);
                    500: }
                    501:
                    502: void
1.3       nicm      503: screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
1.86      nicm      504:     const struct grid_cell *gcp, const char *fmt, va_list ap)
1.2       nicm      505: {
1.86      nicm      506:        struct grid_cell        gc;
                    507:        struct utf8_data       *ud = &gc.data;
1.36      nicm      508:        char                   *msg;
                    509:        u_char                 *ptr;
                    510:        size_t                  left, size = 0;
1.79      nicm      511:        enum utf8_state         more;
1.2       nicm      512:
1.86      nicm      513:        memcpy(&gc, gcp, sizeof gc);
1.1       nicm      514:        xvasprintf(&msg, fmt, ap);
                    515:
1.2       nicm      516:        ptr = msg;
                    517:        while (*ptr != '\0') {
1.86      nicm      518:                if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
1.36      nicm      519:                        ptr++;
1.2       nicm      520:
                    521:                        left = strlen(ptr);
1.86      nicm      522:                        if (left < (size_t)ud->size - 1)
1.36      nicm      523:                                break;
1.86      nicm      524:                        while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
1.2       nicm      525:                                ptr++;
1.36      nicm      526:                        ptr++;
1.7       ray       527:
1.86      nicm      528:                        if (more != UTF8_DONE)
                    529:                                continue;
                    530:                        if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
                    531:                                while (size < (size_t)maxlen) {
                    532:                                        screen_write_putc(ctx, &gc, ' ');
                    533:                                        size++;
1.2       nicm      534:                                }
1.86      nicm      535:                                break;
1.2       nicm      536:                        }
1.86      nicm      537:                        size += ud->width;
                    538:                        screen_write_cell(ctx, &gc);
1.2       nicm      539:                } else {
1.86      nicm      540:                        if (maxlen > 0 && size + 1 > (size_t)maxlen)
1.2       nicm      541:                                break;
                    542:
1.57      nicm      543:                        if (*ptr == '\001')
1.86      nicm      544:                                gc.attr ^= GRID_ATTR_CHARSET;
1.187     nicm      545:                        else if (*ptr == '\n') {
                    546:                                screen_write_linefeed(ctx, 0, 8);
                    547:                                screen_write_carriagereturn(ctx);
                    548:                        } else if (*ptr > 0x1f && *ptr < 0x7f) {
1.57      nicm      549:                                size++;
1.86      nicm      550:                                screen_write_putc(ctx, &gc, *ptr);
1.75      nicm      551:                        }
1.24      nicm      552:                        ptr++;
                    553:                }
                    554:        }
                    555:
1.56      nicm      556:        free(msg);
1.1       nicm      557: }
                    558:
1.132     nicm      559: /*
1.176     nicm      560:  * Copy from another screen but without the selection stuff. Assumes the target
                    561:  * region is already big enough.
1.132     nicm      562:  */
                    563: void
                    564: screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
                    565:     u_int px, u_int py, u_int nx, u_int ny)
                    566: {
                    567:        struct screen           *s = ctx->s;
                    568:        struct grid             *gd = src->grid;
                    569:        struct grid_cell         gc;
                    570:        u_int                    xx, yy, cx, cy;
1.96      nicm      571:
1.132     nicm      572:        if (nx == 0 || ny == 0)
                    573:                return;
                    574:
                    575:        cy = s->cy;
                    576:        for (yy = py; yy < py + ny; yy++) {
1.134     nicm      577:                if (yy >= gd->hsize + gd->sy)
                    578:                        break;
1.132     nicm      579:                cx = s->cx;
                    580:                for (xx = px; xx < px + nx; xx++) {
1.137     nicm      581:                        if (xx >= grid_get_line(gd, yy)->cellsize)
1.132     nicm      582:                                break;
                    583:                        grid_get_cell(gd, xx, yy, &gc);
1.135     nicm      584:                        if (xx + gc.data.width > px + nx)
                    585:                                break;
1.150     nicm      586:                        grid_view_set_cell(ctx->s->grid, cx, cy, &gc);
1.132     nicm      587:                        cx++;
                    588:                }
1.1       nicm      589:                cy++;
1.125     nicm      590:        }
                    591: }
                    592:
1.129     nicm      593: /* Draw a horizontal line on screen. */
1.125     nicm      594: void
1.129     nicm      595: screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right)
1.125     nicm      596: {
                    597:        struct screen           *s = ctx->s;
                    598:        struct grid_cell         gc;
                    599:        u_int                    cx, cy, i;
                    600:
                    601:        cx = s->cx;
                    602:        cy = s->cy;
                    603:
                    604:        memcpy(&gc, &grid_default_cell, sizeof gc);
                    605:        gc.attr |= GRID_ATTR_CHARSET;
                    606:
                    607:        screen_write_putc(ctx, &gc, left ? 't' : 'q');
                    608:        for (i = 1; i < nx - 1; i++)
                    609:                screen_write_putc(ctx, &gc, 'q');
                    610:        screen_write_putc(ctx, &gc, right ? 'u' : 'q');
1.129     nicm      611:
1.144     nicm      612:        screen_write_set_cursor(ctx, cx, cy);
1.129     nicm      613: }
                    614:
1.195     nicm      615: /* Draw a vertical line on screen. */
1.129     nicm      616: void
1.130     nicm      617: screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom)
1.129     nicm      618: {
                    619:        struct screen           *s = ctx->s;
                    620:        struct grid_cell         gc;
                    621:        u_int                    cx, cy, i;
                    622:
                    623:        cx = s->cx;
                    624:        cy = s->cy;
                    625:
                    626:        memcpy(&gc, &grid_default_cell, sizeof gc);
                    627:        gc.attr |= GRID_ATTR_CHARSET;
                    628:
                    629:        screen_write_putc(ctx, &gc, top ? 'w' : 'x');
                    630:        for (i = 1; i < ny - 1; i++) {
1.144     nicm      631:                screen_write_set_cursor(ctx, cx, cy + i);
1.129     nicm      632:                screen_write_putc(ctx, &gc, 'x');
                    633:        }
1.144     nicm      634:        screen_write_set_cursor(ctx, cx, cy + ny - 1);
1.129     nicm      635:        screen_write_putc(ctx, &gc, bottom ? 'v' : 'x');
1.152     nicm      636:
                    637:        screen_write_set_cursor(ctx, cx, cy);
                    638: }
                    639:
                    640: /* Draw a menu on screen. */
                    641: void
1.161     nicm      642: screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu,
                    643:     int choice, const struct grid_cell *choice_gc)
1.152     nicm      644: {
                    645:        struct screen           *s = ctx->s;
1.161     nicm      646:        struct grid_cell         default_gc;
                    647:        const struct grid_cell  *gc = &default_gc;
1.152     nicm      648:        u_int                    cx, cy, i, j;
1.153     nicm      649:        const char              *name;
1.152     nicm      650:
                    651:        cx = s->cx;
                    652:        cy = s->cy;
                    653:
1.161     nicm      654:        memcpy(&default_gc, &grid_default_cell, sizeof default_gc);
1.152     nicm      655:
1.201     nicm      656:        screen_write_box(ctx, menu->width + 4, menu->count + 2,
1.202     nicm      657:            BOX_LINES_DEFAULT, &default_gc, menu->title);
1.152     nicm      658:
                    659:        for (i = 0; i < menu->count; i++) {
1.153     nicm      660:                name = menu->items[i].name;
                    661:                if (name == NULL) {
1.152     nicm      662:                        screen_write_cursormove(ctx, cx, cy + 1 + i, 0);
                    663:                        screen_write_hline(ctx, menu->width + 4, 1, 1);
                    664:                } else {
1.153     nicm      665:                        if (choice >= 0 && i == (u_int)choice && *name != '-')
1.161     nicm      666:                                gc = choice_gc;
1.152     nicm      667:                        screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0);
                    668:                        for (j = 0; j < menu->width; j++)
1.161     nicm      669:                                screen_write_putc(ctx, gc, ' ');
1.152     nicm      670:                        screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0);
1.153     nicm      671:                        if (*name == '-') {
                    672:                                name++;
1.161     nicm      673:                                default_gc.attr |= GRID_ATTR_DIM;
1.205     nicm      674:                                format_draw(ctx, gc, menu->width, name, NULL,
                    675:                                    0);
1.161     nicm      676:                                default_gc.attr &= ~GRID_ATTR_DIM;
1.153     nicm      677:                        } else
1.205     nicm      678:                                format_draw(ctx, gc, menu->width, name, NULL,
                    679:                                    gc == choice_gc);
1.161     nicm      680:                        gc = &default_gc;
1.152     nicm      681:                }
                    682:        }
1.125     nicm      683:
1.144     nicm      684:        screen_write_set_cursor(ctx, cx, cy);
1.125     nicm      685: }
                    686:
1.201     nicm      687: static void
                    688: screen_write_box_border_set(enum box_lines box_lines, int cell_type,
                    689:     struct grid_cell *gc)
                    690: {
                    691:        switch (box_lines) {
                    692:         case BOX_LINES_NONE:
                    693:                break;
                    694:         case BOX_LINES_DOUBLE:
                    695:                 gc->attr &= ~GRID_ATTR_CHARSET;
                    696:                 utf8_copy(&gc->data, tty_acs_double_borders(cell_type));
                    697:                break;
                    698:         case BOX_LINES_HEAVY:
                    699:                 gc->attr &= ~GRID_ATTR_CHARSET;
                    700:                 utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type));
                    701:                break;
                    702:         case BOX_LINES_ROUNDED:
                    703:                 gc->attr &= ~GRID_ATTR_CHARSET;
                    704:                 utf8_copy(&gc->data, tty_acs_rounded_borders(cell_type));
                    705:                break;
                    706:         case BOX_LINES_SIMPLE:
                    707:                 gc->attr &= ~GRID_ATTR_CHARSET;
                    708:                 utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]);
                    709:                 break;
                    710:         case BOX_LINES_PADDED:
                    711:                 gc->attr &= ~GRID_ATTR_CHARSET;
                    712:                 utf8_set(&gc->data, PADDED_BORDERS[cell_type]);
                    713:                 break;
                    714:        case BOX_LINES_SINGLE:
                    715:        case BOX_LINES_DEFAULT:
                    716:                gc->attr |= GRID_ATTR_CHARSET;
                    717:                utf8_set(&gc->data, CELL_BORDERS[cell_type]);
                    718:                break;
                    719:        }
                    720: }
                    721:
1.125     nicm      722: /* Draw a box on screen. */
                    723: void
1.200     nicm      724: screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny,
1.202     nicm      725:     enum box_lines lines, const struct grid_cell *gcp, const char *title)
1.125     nicm      726: {
                    727:        struct screen           *s = ctx->s;
1.200     nicm      728:        struct grid_cell         gc;
1.125     nicm      729:        u_int                    cx, cy, i;
                    730:
                    731:        cx = s->cx;
                    732:        cy = s->cy;
                    733:
1.200     nicm      734:        if (gcp != NULL)
                    735:                memcpy(&gc, gcp, sizeof gc);
                    736:        else
                    737:                memcpy(&gc, &grid_default_cell, sizeof gc);
1.202     nicm      738:
1.125     nicm      739:        gc.attr |= GRID_ATTR_CHARSET;
1.197     nicm      740:        gc.flags |= GRID_FLAG_NOPALETTE;
1.125     nicm      741:
1.201     nicm      742:        /* Draw top border */
1.202     nicm      743:        screen_write_box_border_set(lines, CELL_TOPLEFT, &gc);
1.201     nicm      744:        screen_write_cell(ctx, &gc);
1.202     nicm      745:        screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc);
1.125     nicm      746:        for (i = 1; i < nx - 1; i++)
1.201     nicm      747:                screen_write_cell(ctx, &gc);
1.202     nicm      748:        screen_write_box_border_set(lines, CELL_TOPRIGHT, &gc);
1.201     nicm      749:        screen_write_cell(ctx, &gc);
1.125     nicm      750:
1.201     nicm      751:        /* Draw bottom border */
1.144     nicm      752:        screen_write_set_cursor(ctx, cx, cy + ny - 1);
1.202     nicm      753:        screen_write_box_border_set(lines, CELL_BOTTOMLEFT, &gc);
1.201     nicm      754:        screen_write_cell(ctx, &gc);
1.202     nicm      755:        screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc);
1.125     nicm      756:        for (i = 1; i < nx - 1; i++)
1.201     nicm      757:                screen_write_cell(ctx, &gc);
1.202     nicm      758:        screen_write_box_border_set(lines, CELL_BOTTOMRIGHT, &gc);
1.201     nicm      759:        screen_write_cell(ctx, &gc);
1.125     nicm      760:
1.201     nicm      761:        /* Draw sides */
1.202     nicm      762:        screen_write_box_border_set(lines, CELL_TOPBOTTOM, &gc);
1.125     nicm      763:        for (i = 1; i < ny - 1; i++) {
1.201     nicm      764:                /* left side */
1.144     nicm      765:                screen_write_set_cursor(ctx, cx, cy + i);
1.201     nicm      766:                screen_write_cell(ctx, &gc);
                    767:                /* right side */
1.144     nicm      768:                screen_write_set_cursor(ctx, cx + nx - 1, cy + i);
1.201     nicm      769:                screen_write_cell(ctx, &gc);
1.202     nicm      770:        }
                    771:
                    772:        if (title != NULL) {
                    773:                gc.attr &= ~GRID_ATTR_CHARSET;
                    774:                screen_write_cursormove(ctx, cx + 2, cy, 0);
1.205     nicm      775:                format_draw(ctx, &gc, nx - 4, title, NULL, 0);
1.125     nicm      776:        }
                    777:
1.144     nicm      778:        screen_write_set_cursor(ctx, cx, cy);
1.125     nicm      779: }
                    780:
1.132     nicm      781: /*
                    782:  * Write a preview version of a window. Assumes target area is big enough and
                    783:  * already cleared.
                    784:  */
1.125     nicm      785: void
                    786: screen_write_preview(struct screen_write_ctx *ctx, struct screen *src, u_int nx,
                    787:     u_int ny)
                    788: {
                    789:        struct screen           *s = ctx->s;
                    790:        struct grid_cell         gc;
                    791:        u_int                    cx, cy, px, py;
                    792:
                    793:        cx = s->cx;
                    794:        cy = s->cy;
                    795:
                    796:        /*
                    797:         * If the cursor is on, pick the area around the cursor, otherwise use
                    798:         * the top left.
                    799:         */
                    800:        if (src->mode & MODE_CURSOR) {
                    801:                px = src->cx;
                    802:                if (px < nx / 3)
                    803:                        px = 0;
                    804:                else
                    805:                        px = px - nx / 3;
                    806:                if (px + nx > screen_size_x(src)) {
                    807:                        if (nx > screen_size_x(src))
                    808:                                px = 0;
                    809:                        else
                    810:                                px = screen_size_x(src) - nx;
                    811:                }
                    812:                py = src->cy;
                    813:                if (py < ny / 3)
                    814:                        py = 0;
                    815:                else
                    816:                        py = py - ny / 3;
                    817:                if (py + ny > screen_size_y(src)) {
                    818:                        if (ny > screen_size_y(src))
                    819:                                py = 0;
                    820:                        else
                    821:                                py = screen_size_y(src) - ny;
                    822:                }
                    823:        } else {
                    824:                px = 0;
                    825:                py = 0;
                    826:        }
                    827:
1.132     nicm      828:        screen_write_fast_copy(ctx, src, px, src->grid->hsize + py, nx, ny);
1.125     nicm      829:
                    830:        if (src->mode & MODE_CURSOR) {
                    831:                grid_view_get_cell(src->grid, src->cx, src->cy, &gc);
                    832:                gc.attr |= GRID_ATTR_REVERSE;
1.144     nicm      833:                screen_write_set_cursor(ctx, cx + (src->cx - px),
1.125     nicm      834:                    cy + (src->cy - py));
                    835:                screen_write_cell(ctx, &gc);
1.1       nicm      836:        }
                    837: }
                    838:
1.61      nicm      839: /* Set a mode. */
                    840: void
                    841: screen_write_mode_set(struct screen_write_ctx *ctx, int mode)
                    842: {
                    843:        struct screen   *s = ctx->s;
                    844:
                    845:        s->mode |= mode;
1.194     nicm      846:
                    847:        if (log_get_level() != 0)
                    848:                log_debug("%s: %s", __func__, screen_mode_to_string(mode));
1.61      nicm      849: }
                    850:
                    851: /* Clear a mode. */
                    852: void
                    853: screen_write_mode_clear(struct screen_write_ctx *ctx, int mode)
                    854: {
                    855:        struct screen   *s = ctx->s;
                    856:
                    857:        s->mode &= ~mode;
1.194     nicm      858:
                    859:        if (log_get_level() != 0)
                    860:                log_debug("%s: %s", __func__, screen_mode_to_string(mode));
1.61      nicm      861: }
                    862:
1.1       nicm      863: /* Cursor up by ny. */
                    864: void
                    865: screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
                    866: {
                    867:        struct screen   *s = ctx->s;
1.139     nicm      868:        u_int            cx = s->cx, cy = s->cy;
1.1       nicm      869:
                    870:        if (ny == 0)
                    871:                ny = 1;
                    872:
1.139     nicm      873:        if (cy < s->rupper) {
1.12      nicm      874:                /* Above region. */
1.139     nicm      875:                if (ny > cy)
                    876:                        ny = cy;
1.12      nicm      877:        } else {
                    878:                /* Below region. */
1.139     nicm      879:                if (ny > cy - s->rupper)
                    880:                        ny = cy - s->rupper;
1.12      nicm      881:        }
1.139     nicm      882:        if (cx == screen_size_x(s))
                    883:                cx--;
                    884:
                    885:        cy -= ny;
1.1       nicm      886:
1.139     nicm      887:        screen_write_set_cursor(ctx, cx, cy);
1.1       nicm      888: }
                    889:
                    890: /* Cursor down by ny. */
                    891: void
                    892: screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
                    893: {
                    894:        struct screen   *s = ctx->s;
1.139     nicm      895:        u_int            cx = s->cx, cy = s->cy;
1.1       nicm      896:
                    897:        if (ny == 0)
                    898:                ny = 1;
                    899:
1.139     nicm      900:        if (cy > s->rlower) {
1.12      nicm      901:                /* Below region. */
1.139     nicm      902:                if (ny > screen_size_y(s) - 1 - cy)
                    903:                        ny = screen_size_y(s) - 1 - cy;
1.12      nicm      904:        } else {
                    905:                /* Above region. */
1.139     nicm      906:                if (ny > s->rlower - cy)
                    907:                        ny = s->rlower - cy;
1.12      nicm      908:        }
1.139     nicm      909:        if (cx == screen_size_x(s))
                    910:            cx--;
                    911:        else if (ny == 0)
1.1       nicm      912:                return;
                    913:
1.139     nicm      914:        cy += ny;
                    915:
                    916:        screen_write_set_cursor(ctx, cx, cy);
1.1       nicm      917: }
                    918:
1.101     nicm      919: /* Cursor right by nx. */
1.1       nicm      920: void
                    921: screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
                    922: {
                    923:        struct screen   *s = ctx->s;
1.139     nicm      924:        u_int            cx = s->cx, cy = s->cy;
1.1       nicm      925:
                    926:        if (nx == 0)
                    927:                nx = 1;
                    928:
1.139     nicm      929:        if (nx > screen_size_x(s) - 1 - cx)
                    930:                nx = screen_size_x(s) - 1 - cx;
1.1       nicm      931:        if (nx == 0)
                    932:                return;
                    933:
1.139     nicm      934:        cx += nx;
                    935:
                    936:        screen_write_set_cursor(ctx, cx, cy);
1.1       nicm      937: }
                    938:
                    939: /* Cursor left by nx. */
                    940: void
                    941: screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
                    942: {
                    943:        struct screen   *s = ctx->s;
1.139     nicm      944:        u_int            cx = s->cx, cy = s->cy;
1.1       nicm      945:
                    946:        if (nx == 0)
                    947:                nx = 1;
                    948:
1.139     nicm      949:        if (nx > cx)
                    950:                nx = cx;
1.1       nicm      951:        if (nx == 0)
                    952:                return;
                    953:
1.139     nicm      954:        cx -= nx;
                    955:
                    956:        screen_write_set_cursor(ctx, cx, cy);
1.5       nicm      957: }
                    958:
1.29      nicm      959: /* Backspace; cursor left unless at start of wrapped line when can move up. */
                    960: void
                    961: screen_write_backspace(struct screen_write_ctx *ctx)
                    962: {
                    963:        struct screen           *s = ctx->s;
                    964:        struct grid_line        *gl;
1.139     nicm      965:        u_int                    cx = s->cx, cy = s->cy;
1.29      nicm      966:
1.139     nicm      967:        if (cx == 0) {
                    968:                if (cy == 0)
1.29      nicm      969:                        return;
1.139     nicm      970:                gl = grid_get_line(s->grid, s->grid->hsize + cy - 1);
1.29      nicm      971:                if (gl->flags & GRID_LINE_WRAPPED) {
1.139     nicm      972:                        cy--;
                    973:                        cx = screen_size_x(s) - 1;
1.29      nicm      974:                }
                    975:        } else
1.139     nicm      976:                cx--;
                    977:
                    978:        screen_write_set_cursor(ctx, cx, cy);
1.29      nicm      979: }
                    980:
1.5       nicm      981: /* VT100 alignment test. */
                    982: void
                    983: screen_write_alignmenttest(struct screen_write_ctx *ctx)
                    984: {
                    985:        struct screen           *s = ctx->s;
1.17      nicm      986:        struct tty_ctx           ttyctx;
1.5       nicm      987:        struct grid_cell         gc;
                    988:        u_int                    xx, yy;
                    989:
                    990:        memcpy(&gc, &grid_default_cell, sizeof gc);
1.77      nicm      991:        utf8_set(&gc.data, 'E');
1.7       ray       992:
1.5       nicm      993:        for (yy = 0; yy < screen_size_y(s); yy++) {
                    994:                for (xx = 0; xx < screen_size_x(s); xx++)
                    995:                        grid_view_set_cell(s->grid, xx, yy, &gc);
                    996:        }
1.7       ray       997:
1.139     nicm      998:        screen_write_set_cursor(ctx, 0, 0);
1.5       nicm      999:
                   1000:        s->rupper = 0;
                   1001:        s->rlower = screen_size_y(s) - 1;
1.143     nicm     1002:
1.163     nicm     1003:        screen_write_initctx(ctx, &ttyctx, 1);
1.5       nicm     1004:
1.109     nicm     1005:        screen_write_collect_clear(ctx, 0, screen_size_y(s) - 1);
1.17      nicm     1006:        tty_write(tty_cmd_alignmenttest, &ttyctx);
1.1       nicm     1007: }
                   1008:
                   1009: /* Insert nx characters. */
                   1010: void
1.99      nicm     1011: screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
1.1       nicm     1012: {
                   1013:        struct screen   *s = ctx->s;
1.17      nicm     1014:        struct tty_ctx   ttyctx;
1.1       nicm     1015:
                   1016:        if (nx == 0)
                   1017:                nx = 1;
                   1018:
1.9       nicm     1019:        if (nx > screen_size_x(s) - s->cx)
                   1020:                nx = screen_size_x(s) - s->cx;
1.1       nicm     1021:        if (nx == 0)
                   1022:                return;
                   1023:
1.107     nicm     1024:        if (s->cx > screen_size_x(s) - 1)
                   1025:                return;
                   1026:
1.163     nicm     1027:        screen_write_initctx(ctx, &ttyctx, 0);
1.107     nicm     1028:        ttyctx.bg = bg;
1.1       nicm     1029:
1.107     nicm     1030:        grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg);
1.1       nicm     1031:
1.164     nicm     1032:        screen_write_collect_flush(ctx, 0, __func__);
1.17      nicm     1033:        ttyctx.num = nx;
                   1034:        tty_write(tty_cmd_insertcharacter, &ttyctx);
1.1       nicm     1035: }
                   1036:
                   1037: /* Delete nx characters. */
                   1038: void
1.99      nicm     1039: screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
1.1       nicm     1040: {
                   1041:        struct screen   *s = ctx->s;
1.17      nicm     1042:        struct tty_ctx   ttyctx;
1.1       nicm     1043:
                   1044:        if (nx == 0)
                   1045:                nx = 1;
                   1046:
1.9       nicm     1047:        if (nx > screen_size_x(s) - s->cx)
                   1048:                nx = screen_size_x(s) - s->cx;
1.1       nicm     1049:        if (nx == 0)
                   1050:                return;
                   1051:
1.107     nicm     1052:        if (s->cx > screen_size_x(s) - 1)
                   1053:                return;
                   1054:
1.163     nicm     1055:        screen_write_initctx(ctx, &ttyctx, 0);
1.107     nicm     1056:        ttyctx.bg = bg;
1.1       nicm     1057:
1.107     nicm     1058:        grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg);
1.1       nicm     1059:
1.164     nicm     1060:        screen_write_collect_flush(ctx, 0, __func__);
1.17      nicm     1061:        ttyctx.num = nx;
                   1062:        tty_write(tty_cmd_deletecharacter, &ttyctx);
1.59      nicm     1063: }
                   1064:
                   1065: /* Clear nx characters. */
                   1066: void
1.121     nicm     1067: screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
1.59      nicm     1068: {
                   1069:        struct screen   *s = ctx->s;
                   1070:        struct tty_ctx   ttyctx;
                   1071:
                   1072:        if (nx == 0)
                   1073:                nx = 1;
                   1074:
                   1075:        if (nx > screen_size_x(s) - s->cx)
                   1076:                nx = screen_size_x(s) - s->cx;
                   1077:        if (nx == 0)
                   1078:                return;
                   1079:
1.107     nicm     1080:        if (s->cx > screen_size_x(s) - 1)
                   1081:                return;
                   1082:
1.163     nicm     1083:        screen_write_initctx(ctx, &ttyctx, 0);
1.121     nicm     1084:        ttyctx.bg = bg;
1.59      nicm     1085:
1.124     nicm     1086:        grid_view_clear(s->grid, s->cx, s->cy, nx, 1, bg);
1.59      nicm     1087:
1.164     nicm     1088:        screen_write_collect_flush(ctx, 0, __func__);
1.59      nicm     1089:        ttyctx.num = nx;
                   1090:        tty_write(tty_cmd_clearcharacter, &ttyctx);
1.1       nicm     1091: }
                   1092:
                   1093: /* Insert ny lines. */
                   1094: void
1.99      nicm     1095: screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
1.1       nicm     1096: {
                   1097:        struct screen   *s = ctx->s;
1.107     nicm     1098:        struct grid     *gd = s->grid;
1.17      nicm     1099:        struct tty_ctx   ttyctx;
1.1       nicm     1100:
                   1101:        if (ny == 0)
                   1102:                ny = 1;
                   1103:
1.11      nicm     1104:        if (s->cy < s->rupper || s->cy > s->rlower) {
                   1105:                if (ny > screen_size_y(s) - s->cy)
                   1106:                        ny = screen_size_y(s) - s->cy;
                   1107:                if (ny == 0)
                   1108:                        return;
                   1109:
1.163     nicm     1110:                screen_write_initctx(ctx, &ttyctx, 1);
1.107     nicm     1111:                ttyctx.bg = bg;
1.11      nicm     1112:
1.107     nicm     1113:                grid_view_insert_lines(gd, s->cy, ny, bg);
1.11      nicm     1114:
1.164     nicm     1115:                screen_write_collect_flush(ctx, 0, __func__);
1.17      nicm     1116:                ttyctx.num = ny;
                   1117:                tty_write(tty_cmd_insertline, &ttyctx);
1.11      nicm     1118:                return;
                   1119:        }
                   1120:
                   1121:        if (ny > s->rlower + 1 - s->cy)
                   1122:                ny = s->rlower + 1 - s->cy;
1.1       nicm     1123:        if (ny == 0)
                   1124:                return;
1.41      nicm     1125:
1.163     nicm     1126:        screen_write_initctx(ctx, &ttyctx, 1);
1.107     nicm     1127:        ttyctx.bg = bg;
1.1       nicm     1128:
                   1129:        if (s->cy < s->rupper || s->cy > s->rlower)
1.107     nicm     1130:                grid_view_insert_lines(gd, s->cy, ny, bg);
                   1131:        else
                   1132:                grid_view_insert_lines_region(gd, s->rlower, s->cy, ny, bg);
1.1       nicm     1133:
1.164     nicm     1134:        screen_write_collect_flush(ctx, 0, __func__);
                   1135:
1.17      nicm     1136:        ttyctx.num = ny;
                   1137:        tty_write(tty_cmd_insertline, &ttyctx);
1.1       nicm     1138: }
                   1139:
                   1140: /* Delete ny lines. */
                   1141: void
1.99      nicm     1142: screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
1.1       nicm     1143: {
                   1144:        struct screen   *s = ctx->s;
1.107     nicm     1145:        struct grid     *gd = s->grid;
1.17      nicm     1146:        struct tty_ctx   ttyctx;
1.1       nicm     1147:
                   1148:        if (ny == 0)
                   1149:                ny = 1;
                   1150:
1.11      nicm     1151:        if (s->cy < s->rupper || s->cy > s->rlower) {
                   1152:                if (ny > screen_size_y(s) - s->cy)
                   1153:                        ny = screen_size_y(s) - s->cy;
                   1154:                if (ny == 0)
                   1155:                        return;
                   1156:
1.163     nicm     1157:                screen_write_initctx(ctx, &ttyctx, 1);
1.107     nicm     1158:                ttyctx.bg = bg;
1.11      nicm     1159:
1.107     nicm     1160:                grid_view_delete_lines(gd, s->cy, ny, bg);
1.11      nicm     1161:
1.164     nicm     1162:                screen_write_collect_flush(ctx, 0, __func__);
1.17      nicm     1163:                ttyctx.num = ny;
                   1164:                tty_write(tty_cmd_deleteline, &ttyctx);
1.11      nicm     1165:                return;
                   1166:        }
1.41      nicm     1167:
1.11      nicm     1168:        if (ny > s->rlower + 1 - s->cy)
                   1169:                ny = s->rlower + 1 - s->cy;
1.1       nicm     1170:        if (ny == 0)
                   1171:                return;
                   1172:
1.163     nicm     1173:        screen_write_initctx(ctx, &ttyctx, 1);
1.107     nicm     1174:        ttyctx.bg = bg;
1.1       nicm     1175:
                   1176:        if (s->cy < s->rupper || s->cy > s->rlower)
1.107     nicm     1177:                grid_view_delete_lines(gd, s->cy, ny, bg);
                   1178:        else
                   1179:                grid_view_delete_lines_region(gd, s->rlower, s->cy, ny, bg);
1.1       nicm     1180:
1.164     nicm     1181:        screen_write_collect_flush(ctx, 0, __func__);
1.17      nicm     1182:        ttyctx.num = ny;
                   1183:        tty_write(tty_cmd_deleteline, &ttyctx);
1.1       nicm     1184: }
                   1185:
                   1186: /* Clear line at cursor. */
                   1187: void
1.99      nicm     1188: screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm     1189: {
1.193     nicm     1190:        struct screen                   *s = ctx->s;
                   1191:        struct grid_line                *gl;
                   1192:        u_int                            sx = screen_size_x(s);
                   1193:        struct screen_write_citem       *ci = ctx->item;
1.1       nicm     1194:
1.137     nicm     1195:        gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
1.140     nicm     1196:        if (gl->cellsize == 0 && COLOUR_DEFAULT(bg))
1.92      nicm     1197:                return;
1.1       nicm     1198:
1.99      nicm     1199:        grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
                   1200:
1.109     nicm     1201:        screen_write_collect_clear(ctx, s->cy, 1);
1.193     nicm     1202:        ci->x = 0;
                   1203:        ci->used = sx;
                   1204:        ci->type = CLEAR;
                   1205:        ci->bg = bg;
                   1206:        TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry);
                   1207:        ctx->item = screen_write_get_citem();
1.1       nicm     1208: }
                   1209:
                   1210: /* Clear to end of line from cursor. */
                   1211: void
1.99      nicm     1212: screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm     1213: {
1.193     nicm     1214:        struct screen                   *s = ctx->s;
                   1215:        struct grid_line                *gl;
                   1216:        u_int                            sx = screen_size_x(s);
                   1217:        struct screen_write_citem       *ci = ctx->item, *before;
1.165     nicm     1218:
                   1219:        if (s->cx == 0) {
                   1220:                screen_write_clearline(ctx, bg);
                   1221:                return;
                   1222:        }
1.1       nicm     1223:
1.137     nicm     1224:        gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
1.140     nicm     1225:        if (s->cx > sx - 1 || (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg)))
1.92      nicm     1226:                return;
1.108     nicm     1227:
1.99      nicm     1228:        grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
                   1229:
1.193     nicm     1230:        before = screen_write_collect_trim(ctx, s->cy, s->cx, sx - s->cx, NULL);
1.186     nicm     1231:        ci->x = s->cx;
1.193     nicm     1232:        ci->used = sx - s->cx;
                   1233:        ci->type = CLEAR;
1.186     nicm     1234:        ci->bg = bg;
1.193     nicm     1235:        if (before == NULL)
                   1236:                TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry);
                   1237:        else
                   1238:                TAILQ_INSERT_BEFORE(before, ci, entry);
                   1239:        ctx->item = screen_write_get_citem();
1.1       nicm     1240: }
                   1241:
                   1242: /* Clear to start of line from cursor. */
                   1243: void
1.99      nicm     1244: screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm     1245: {
1.165     nicm     1246:        struct screen                    *s = ctx->s;
1.193     nicm     1247:        u_int                            sx = screen_size_x(s);
                   1248:        struct screen_write_citem       *ci = ctx->item, *before;
1.165     nicm     1249:
                   1250:        if (s->cx >= sx - 1) {
                   1251:                screen_write_clearline(ctx, bg);
                   1252:                return;
                   1253:        }
1.1       nicm     1254:
1.109     nicm     1255:        if (s->cx > sx - 1)
1.99      nicm     1256:                grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
1.109     nicm     1257:        else
1.99      nicm     1258:                grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
1.1       nicm     1259:
1.193     nicm     1260:        before = screen_write_collect_trim(ctx, s->cy, 0, s->cx + 1, NULL);
                   1261:        ci->x = 0;
                   1262:        ci->used = s->cx + 1;
                   1263:        ci->type = CLEAR;
1.186     nicm     1264:        ci->bg = bg;
1.193     nicm     1265:        if (before == NULL)
                   1266:                TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry);
                   1267:        else
                   1268:                TAILQ_INSERT_BEFORE(before, ci, entry);
                   1269:        ctx->item = screen_write_get_citem();
1.1       nicm     1270: }
                   1271:
1.101     nicm     1272: /* Move cursor to px,py. */
1.1       nicm     1273: void
1.147     nicm     1274: screen_write_cursormove(struct screen_write_ctx *ctx, int px, int py,
                   1275:     int origin)
1.1       nicm     1276: {
                   1277:        struct screen   *s = ctx->s;
                   1278:
1.147     nicm     1279:        if (origin && py != -1 && (s->mode & MODE_ORIGIN)) {
1.146     nicm     1280:                if ((u_int)py > s->rlower - s->rupper)
1.144     nicm     1281:                        py = s->rlower;
                   1282:                else
                   1283:                        py += s->rupper;
                   1284:        }
1.145     nicm     1285:
1.146     nicm     1286:        if (px != -1 && (u_int)px > screen_size_x(s) - 1)
1.145     nicm     1287:                px = screen_size_x(s) - 1;
1.146     nicm     1288:        if (py != -1 && (u_int)py > screen_size_y(s) - 1)
1.145     nicm     1289:                py = screen_size_y(s) - 1;
1.1       nicm     1290:
1.193     nicm     1291:        log_debug("%s: from %u,%u to %u,%u", __func__, s->cx, s->cy, px, py);
1.139     nicm     1292:        screen_write_set_cursor(ctx, px, py);
1.1       nicm     1293: }
                   1294:
1.101     nicm     1295: /* Reverse index (up with scroll). */
1.1       nicm     1296: void
1.122     nicm     1297: screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm     1298: {
                   1299:        struct screen   *s = ctx->s;
1.17      nicm     1300:        struct tty_ctx   ttyctx;
1.1       nicm     1301:
1.165     nicm     1302:        if (s->cy == s->rupper) {
                   1303:                grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg);
                   1304:                screen_write_collect_flush(ctx, 0, __func__);
                   1305:
                   1306:                screen_write_initctx(ctx, &ttyctx, 1);
                   1307:                ttyctx.bg = bg;
1.1       nicm     1308:
1.165     nicm     1309:                tty_write(tty_cmd_reverseindex, &ttyctx);
                   1310:        } else if (s->cy > 0)
1.139     nicm     1311:                screen_write_set_cursor(ctx, -1, s->cy - 1);
1.1       nicm     1312:
                   1313: }
                   1314:
                   1315: /* Set scroll region. */
                   1316: void
1.83      nicm     1317: screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper,
                   1318:     u_int rlower)
1.1       nicm     1319: {
                   1320:        struct screen   *s = ctx->s;
                   1321:
                   1322:        if (rupper > screen_size_y(s) - 1)
                   1323:                rupper = screen_size_y(s) - 1;
                   1324:        if (rlower > screen_size_y(s) - 1)
                   1325:                rlower = screen_size_y(s) - 1;
1.13      nicm     1326:        if (rupper >= rlower)   /* cannot be one line */
1.1       nicm     1327:                return;
                   1328:
1.164     nicm     1329:        screen_write_collect_flush(ctx, 0, __func__);
1.110     nicm     1330:
1.1       nicm     1331:        /* Cursor moves to top-left. */
1.139     nicm     1332:        screen_write_set_cursor(ctx, 0, 0);
1.1       nicm     1333:
                   1334:        s->rupper = rupper;
                   1335:        s->rlower = rlower;
                   1336: }
                   1337:
1.34      nicm     1338: /* Line feed. */
1.1       nicm     1339: void
1.122     nicm     1340: screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg)
1.1       nicm     1341: {
1.20      nicm     1342:        struct screen           *s = ctx->s;
1.109     nicm     1343:        struct grid             *gd = s->grid;
1.20      nicm     1344:        struct grid_line        *gl;
1.1       nicm     1345:
1.137     nicm     1346:        gl = grid_get_line(gd, gd->hsize + s->cy);
1.20      nicm     1347:        if (wrapped)
                   1348:                gl->flags |= GRID_LINE_WRAPPED;
                   1349:
1.114     nicm     1350:        log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy,
                   1351:            s->rupper, s->rlower);
                   1352:
1.122     nicm     1353:        if (bg != ctx->bg) {
1.164     nicm     1354:                screen_write_collect_flush(ctx, 1, __func__);
1.122     nicm     1355:                ctx->bg = bg;
                   1356:        }
                   1357:
1.92      nicm     1358:        if (s->cy == s->rlower) {
1.122     nicm     1359:                grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg);
1.193     nicm     1360:                screen_write_collect_scroll(ctx, bg);
1.110     nicm     1361:                ctx->scrolled++;
1.109     nicm     1362:        } else if (s->cy < screen_size_y(s) - 1)
1.139     nicm     1363:                screen_write_set_cursor(ctx, -1, s->cy + 1);
1.1       nicm     1364: }
                   1365:
1.110     nicm     1366: /* Scroll up. */
                   1367: void
1.122     nicm     1368: screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg)
1.110     nicm     1369: {
                   1370:        struct screen   *s = ctx->s;
                   1371:        struct grid     *gd = s->grid;
                   1372:        u_int            i;
                   1373:
                   1374:        if (lines == 0)
                   1375:                lines = 1;
                   1376:        else if (lines > s->rlower - s->rupper + 1)
                   1377:                lines = s->rlower - s->rupper + 1;
                   1378:
1.122     nicm     1379:        if (bg != ctx->bg) {
1.164     nicm     1380:                screen_write_collect_flush(ctx, 1, __func__);
1.122     nicm     1381:                ctx->bg = bg;
                   1382:        }
                   1383:
1.110     nicm     1384:        for (i = 0; i < lines; i++) {
1.122     nicm     1385:                grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg);
1.193     nicm     1386:                screen_write_collect_scroll(ctx, bg);
1.110     nicm     1387:        }
                   1388:        ctx->scrolled += lines;
1.157     nicm     1389: }
                   1390:
                   1391: /* Scroll down. */
                   1392: void
                   1393: screen_write_scrolldown(struct screen_write_ctx *ctx, u_int lines, u_int bg)
                   1394: {
                   1395:        struct screen   *s = ctx->s;
                   1396:        struct grid     *gd = s->grid;
                   1397:        struct tty_ctx   ttyctx;
                   1398:        u_int            i;
                   1399:
1.163     nicm     1400:        screen_write_initctx(ctx, &ttyctx, 1);
1.157     nicm     1401:        ttyctx.bg = bg;
                   1402:
                   1403:        if (lines == 0)
                   1404:                lines = 1;
                   1405:        else if (lines > s->rlower - s->rupper + 1)
                   1406:                lines = s->rlower - s->rupper + 1;
                   1407:
                   1408:        for (i = 0; i < lines; i++)
                   1409:                grid_view_scroll_region_down(gd, s->rupper, s->rlower, bg);
                   1410:
1.164     nicm     1411:        screen_write_collect_flush(ctx, 0, __func__);
1.157     nicm     1412:        ttyctx.num = lines;
                   1413:        tty_write(tty_cmd_scrolldown, &ttyctx);
1.110     nicm     1414: }
                   1415:
1.1       nicm     1416: /* Carriage return (cursor to start of line). */
                   1417: void
                   1418: screen_write_carriagereturn(struct screen_write_ctx *ctx)
                   1419: {
1.139     nicm     1420:        screen_write_set_cursor(ctx, 0, -1);
1.1       nicm     1421: }
                   1422:
                   1423: /* Clear to end of screen from cursor. */
                   1424: void
1.99      nicm     1425: screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm     1426: {
                   1427:        struct screen   *s = ctx->s;
1.107     nicm     1428:        struct grid     *gd = s->grid;
1.17      nicm     1429:        struct tty_ctx   ttyctx;
1.92      nicm     1430:        u_int            sx = screen_size_x(s), sy = screen_size_y(s);
1.1       nicm     1431:
1.163     nicm     1432:        screen_write_initctx(ctx, &ttyctx, 1);
1.99      nicm     1433:        ttyctx.bg = bg;
1.1       nicm     1434:
1.46      nicm     1435:        /* Scroll into history if it is enabled and clearing entire screen. */
1.206     nicm     1436:        if (s->cx == 0 &&
                   1437:            s->cy == 0 &&
                   1438:            (gd->flags & GRID_HISTORY) &&
                   1439:            ctx->wp != NULL &&
                   1440:            options_get_number(ctx->wp->options, "scroll-on-clear"))
1.107     nicm     1441:                grid_view_clear_history(gd, bg);
1.109     nicm     1442:        else {
                   1443:                if (s->cx <= sx - 1)
1.107     nicm     1444:                        grid_view_clear(gd, s->cx, s->cy, sx - s->cx, 1, bg);
                   1445:                grid_view_clear(gd, 0, s->cy + 1, sx, sy - (s->cy + 1), bg);
1.46      nicm     1446:        }
1.1       nicm     1447:
1.109     nicm     1448:        screen_write_collect_clear(ctx, s->cy + 1, sy - (s->cy + 1));
1.164     nicm     1449:        screen_write_collect_flush(ctx, 0, __func__);
1.17      nicm     1450:        tty_write(tty_cmd_clearendofscreen, &ttyctx);
1.1       nicm     1451: }
                   1452:
                   1453: /* Clear to start of screen. */
                   1454: void
1.105     nicm     1455: screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm     1456: {
                   1457:        struct screen   *s = ctx->s;
1.17      nicm     1458:        struct tty_ctx   ttyctx;
1.92      nicm     1459:        u_int            sx = screen_size_x(s);
1.1       nicm     1460:
1.163     nicm     1461:        screen_write_initctx(ctx, &ttyctx, 1);
1.105     nicm     1462:        ttyctx.bg = bg;
1.1       nicm     1463:
1.109     nicm     1464:        if (s->cy > 0)
1.105     nicm     1465:                grid_view_clear(s->grid, 0, 0, sx, s->cy, bg);
1.109     nicm     1466:        if (s->cx > sx - 1)
1.120     nicm     1467:                grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
1.109     nicm     1468:        else
1.120     nicm     1469:                grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
1.1       nicm     1470:
1.109     nicm     1471:        screen_write_collect_clear(ctx, 0, s->cy);
1.164     nicm     1472:        screen_write_collect_flush(ctx, 0, __func__);
1.17      nicm     1473:        tty_write(tty_cmd_clearstartofscreen, &ttyctx);
1.1       nicm     1474: }
                   1475:
                   1476: /* Clear entire screen. */
                   1477: void
1.99      nicm     1478: screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
1.1       nicm     1479: {
                   1480:        struct screen   *s = ctx->s;
1.17      nicm     1481:        struct tty_ctx   ttyctx;
1.92      nicm     1482:        u_int            sx = screen_size_x(s), sy = screen_size_y(s);
1.1       nicm     1483:
1.163     nicm     1484:        screen_write_initctx(ctx, &ttyctx, 1);
1.99      nicm     1485:        ttyctx.bg = bg;
1.1       nicm     1486:
1.46      nicm     1487:        /* Scroll into history if it is enabled. */
1.207     nicm     1488:        if ((s->grid->flags & GRID_HISTORY) &&
                   1489:            ctx->wp != NULL &&
                   1490:            options_get_number(ctx->wp->options, "scroll-on-clear"))
1.99      nicm     1491:                grid_view_clear_history(s->grid, bg);
1.83      nicm     1492:        else
1.99      nicm     1493:                grid_view_clear(s->grid, 0, 0, sx, sy, bg);
1.1       nicm     1494:
1.109     nicm     1495:        screen_write_collect_clear(ctx, 0, sy);
1.17      nicm     1496:        tty_write(tty_cmd_clearscreen, &ttyctx);
1.51      nicm     1497: }
                   1498:
                   1499: /* Clear entire history. */
                   1500: void
                   1501: screen_write_clearhistory(struct screen_write_ctx *ctx)
                   1502: {
1.156     nicm     1503:        grid_clear_history(ctx->s->grid);
1.197     nicm     1504: }
                   1505:
                   1506: /* Force a full redraw. */
                   1507: void
                   1508: screen_write_fullredraw(struct screen_write_ctx *ctx)
                   1509: {
                   1510:        struct tty_ctx   ttyctx;
                   1511:
                   1512:        screen_write_collect_flush(ctx, 0, __func__);
                   1513:
1.211     nicm     1514:        screen_write_initctx(ctx, &ttyctx, 1);
                   1515:        if (ttyctx.redraw_cb != NULL)
1.210     nicm     1516:                ttyctx.redraw_cb(&ttyctx);
1.1       nicm     1517: }
                   1518:
1.193     nicm     1519: /* Trim collected items. */
                   1520: static struct screen_write_citem *
                   1521: screen_write_collect_trim(struct screen_write_ctx *ctx, u_int y, u_int x,
                   1522:     u_int used, int *wrapped)
                   1523: {
                   1524:        struct screen_write_cline       *cl = &ctx->s->write_list[y];
                   1525:        struct screen_write_citem       *ci, *ci2, *tmp, *before = NULL;
                   1526:        u_int                            sx = x, ex = x + used - 1;
                   1527:        u_int                            csx, cex;
                   1528:
                   1529:        if (TAILQ_EMPTY(&cl->items))
                   1530:                return (NULL);
                   1531:        TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) {
                   1532:                csx = ci->x;
                   1533:                cex = ci->x + ci->used - 1;
                   1534:
                   1535:                /* Item is entirely before. */
                   1536:                if (cex < sx) {
                   1537:                        log_debug("%s: %p %u-%u before %u-%u", __func__, ci,
                   1538:                            csx, cex, sx, ex);
                   1539:                        continue;
                   1540:                }
1.165     nicm     1541:
1.193     nicm     1542:                /* Item is entirely after. */
                   1543:                if (csx > ex) {
                   1544:                        log_debug("%s: %p %u-%u after %u-%u", __func__, ci,
                   1545:                            csx, cex, sx, ex);
                   1546:                        before = ci;
1.165     nicm     1547:                        break;
1.193     nicm     1548:                }
                   1549:
                   1550:                /* Item is entirely inside. */
                   1551:                if (csx >= sx && cex <= ex) {
                   1552:                        log_debug("%s: %p %u-%u inside %u-%u", __func__, ci,
                   1553:                            csx, cex, sx, ex);
                   1554:                        TAILQ_REMOVE(&cl->items, ci, entry);
                   1555:                        screen_write_free_citem(ci);
                   1556:                        if (csx == 0 && ci->wrapped && wrapped != NULL)
                   1557:                                *wrapped = 1;
1.165     nicm     1558:                        continue;
                   1559:                }
                   1560:
1.193     nicm     1561:                /* Item under the start. */
                   1562:                if (csx < sx && cex >= sx && cex <= ex) {
                   1563:                        log_debug("%s: %p %u-%u start %u-%u", __func__, ci,
                   1564:                            csx, cex, sx, ex);
                   1565:                        ci->used = sx - csx;
                   1566:                        log_debug("%s: %p now %u-%u", __func__, ci, ci->x,
                   1567:                            ci->x + ci->used + 1);
1.165     nicm     1568:                        continue;
1.193     nicm     1569:                }
                   1570:
                   1571:                /* Item covers the end. */
                   1572:                if (cex > ex && csx >= sx && csx <= ex) {
                   1573:                        log_debug("%s: %p %u-%u end %u-%u", __func__, ci,
                   1574:                            csx, cex, sx, ex);
                   1575:                        ci->x = ex + 1;
                   1576:                        ci->used = cex - ex;
                   1577:                        log_debug("%s: %p now %u-%u", __func__, ci, ci->x,
                   1578:                            ci->x + ci->used + 1);
                   1579:                        before = ci;
1.165     nicm     1580:                        break;
                   1581:                }
1.193     nicm     1582:
                   1583:                /* Item must cover both sides. */
                   1584:                log_debug("%s: %p %u-%u under %u-%u", __func__, ci,
                   1585:                    csx, cex, sx, ex);
                   1586:                ci2 = screen_write_get_citem();
                   1587:                ci2->type = ci->type;
                   1588:                ci2->bg = ci->bg;
                   1589:                memcpy(&ci2->gc, &ci->gc, sizeof ci2->gc);
                   1590:                TAILQ_INSERT_AFTER(&cl->items, ci, ci2, entry);
                   1591:
                   1592:                ci->used = sx - csx;
                   1593:                ci2->x = ex + 1;
                   1594:                ci2->used = cex - ex;
                   1595:
                   1596:                log_debug("%s: %p now %u-%u (%p) and %u-%u (%p)", __func__, ci,
                   1597:                    ci->x, ci->x + ci->used - 1, ci, ci2->x,
                   1598:                    ci2->x + ci2->used - 1, ci2);
                   1599:                before = ci2;
                   1600:                break;
                   1601:        }
                   1602:        return (before);
1.165     nicm     1603: }
                   1604:
1.170     nicm     1605: /* Clear collected lines. */
1.109     nicm     1606: static void
                   1607: screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n)
                   1608: {
1.193     nicm     1609:        struct screen_write_cline       *cl;
                   1610:        u_int                            i;
1.109     nicm     1611:
1.151     nicm     1612:        for (i = y; i < y + n; i++) {
1.172     nicm     1613:                cl = &ctx->s->write_list[i];
1.193     nicm     1614:                TAILQ_CONCAT(&screen_write_citem_freelist, &cl->items, entry);
1.109     nicm     1615:        }
                   1616: }
                   1617:
                   1618: /* Scroll collected lines up. */
                   1619: static void
1.193     nicm     1620: screen_write_collect_scroll(struct screen_write_ctx *ctx, u_int bg)
1.109     nicm     1621: {
1.193     nicm     1622:        struct screen                   *s = ctx->s;
                   1623:        struct screen_write_cline       *cl;
                   1624:        u_int                            y;
                   1625:        char                            *saved;
                   1626:        struct screen_write_citem       *ci;
1.109     nicm     1627:
1.114     nicm     1628:        log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy,
                   1629:            s->rupper, s->rlower);
                   1630:
1.109     nicm     1631:        screen_write_collect_clear(ctx, s->rupper, 1);
1.172     nicm     1632:        saved = ctx->s->write_list[s->rupper].data;
1.109     nicm     1633:        for (y = s->rupper; y < s->rlower; y++) {
1.172     nicm     1634:                cl = &ctx->s->write_list[y + 1];
                   1635:                TAILQ_CONCAT(&ctx->s->write_list[y].items, &cl->items, entry);
                   1636:                ctx->s->write_list[y].data = cl->data;
1.109     nicm     1637:        }
1.172     nicm     1638:        ctx->s->write_list[s->rlower].data = saved;
1.193     nicm     1639:
                   1640:        ci = screen_write_get_citem();
                   1641:        ci->x = 0;
                   1642:        ci->used = screen_size_x(s);
                   1643:        ci->type = CLEAR;
                   1644:        ci->bg = bg;
                   1645:        TAILQ_INSERT_TAIL(&ctx->s->write_list[s->rlower].items, ci, entry);
1.109     nicm     1646: }
                   1647:
                   1648: /* Flush collected lines. */
                   1649: static void
1.164     nicm     1650: screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only,
                   1651:     const char *from)
1.109     nicm     1652: {
1.193     nicm     1653:        struct screen                   *s = ctx->s;
                   1654:        struct screen_write_citem       *ci, *tmp;
                   1655:        struct screen_write_cline       *cl;
                   1656:        u_int                            y, cx, cy, last, items = 0;
                   1657:        struct tty_ctx                   ttyctx;
1.110     nicm     1658:
                   1659:        if (ctx->scrolled != 0) {
                   1660:                log_debug("%s: scrolled %u (region %u-%u)", __func__,
                   1661:                    ctx->scrolled, s->rupper, s->rlower);
                   1662:                if (ctx->scrolled > s->rlower - s->rupper + 1)
                   1663:                        ctx->scrolled = s->rlower - s->rupper + 1;
                   1664:
1.163     nicm     1665:                screen_write_initctx(ctx, &ttyctx, 1);
1.110     nicm     1666:                ttyctx.num = ctx->scrolled;
1.122     nicm     1667:                ttyctx.bg = ctx->bg;
1.110     nicm     1668:                tty_write(tty_cmd_scrollup, &ttyctx);
                   1669:        }
                   1670:        ctx->scrolled = 0;
1.122     nicm     1671:        ctx->bg = 8;
                   1672:
1.111     nicm     1673:        if (scroll_only)
                   1674:                return;
1.109     nicm     1675:
                   1676:        cx = s->cx; cy = s->cy;
                   1677:        for (y = 0; y < screen_size_y(s); y++) {
1.172     nicm     1678:                cl = &ctx->s->write_list[y];
1.193     nicm     1679:                last = UINT_MAX;
1.172     nicm     1680:                TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) {
1.193     nicm     1681:                        if (last != UINT_MAX && ci->x <= last) {
                   1682:                                fatalx("collect list not in order: %u <= %u",
                   1683:                                    ci->x, last);
                   1684:                        }
1.144     nicm     1685:                        screen_write_set_cursor(ctx, ci->x, y);
1.193     nicm     1686:                        if (ci->type == CLEAR) {
1.167     nicm     1687:                                screen_write_initctx(ctx, &ttyctx, 1);
1.165     nicm     1688:                                ttyctx.bg = ci->bg;
1.193     nicm     1689:                                ttyctx.num = ci->used;
                   1690:                                tty_write(tty_cmd_clearcharacter, &ttyctx);
1.165     nicm     1691:                        } else {
1.167     nicm     1692:                                screen_write_initctx(ctx, &ttyctx, 0);
1.165     nicm     1693:                                ttyctx.cell = &ci->gc;
                   1694:                                ttyctx.wrapped = ci->wrapped;
1.172     nicm     1695:                                ttyctx.ptr = cl->data + ci->x;
1.165     nicm     1696:                                ttyctx.num = ci->used;
                   1697:                                tty_write(tty_cmd_cells, &ttyctx);
                   1698:                        }
1.116     nicm     1699:                        items++;
1.109     nicm     1700:
1.172     nicm     1701:                        TAILQ_REMOVE(&cl->items, ci, entry);
1.193     nicm     1702:                        screen_write_free_citem(ci);
                   1703:                        last = ci->x;
1.109     nicm     1704:                }
                   1705:        }
                   1706:        s->cx = cx; s->cy = cy;
1.116     nicm     1707:
1.193     nicm     1708:        log_debug("%s: flushed %u items (%s)", __func__, items, from);
1.109     nicm     1709: }
                   1710:
                   1711: /* Finish and store collected cells. */
                   1712: void
                   1713: screen_write_collect_end(struct screen_write_ctx *ctx)
                   1714: {
1.193     nicm     1715:        struct screen                   *s = ctx->s;
                   1716:        struct screen_write_citem       *ci = ctx->item, *before;
                   1717:        struct screen_write_cline       *cl = &s->write_list[s->cy];
                   1718:        struct grid_cell                 gc;
                   1719:        u_int                            xx;
                   1720:        int                              wrapped = ci->wrapped;
1.109     nicm     1721:
                   1722:        if (ci->used == 0)
                   1723:                return;
                   1724:
1.193     nicm     1725:        before = screen_write_collect_trim(ctx, s->cy, s->cx, ci->used,
                   1726:            &wrapped);
1.109     nicm     1727:        ci->x = s->cx;
1.193     nicm     1728:        ci->wrapped = wrapped;
                   1729:        if (before == NULL)
                   1730:                TAILQ_INSERT_TAIL(&cl->items, ci, entry);
                   1731:        else
                   1732:                TAILQ_INSERT_BEFORE(before, ci, entry);
                   1733:        ctx->item = screen_write_get_citem();
1.109     nicm     1734:
1.170     nicm     1735:        log_debug("%s: %u %.*s (at %u,%u)", __func__, ci->used,
1.172     nicm     1736:            (int)ci->used, cl->data + ci->x, s->cx, s->cy);
1.109     nicm     1737:
1.131     nicm     1738:        if (s->cx != 0) {
                   1739:                for (xx = s->cx; xx > 0; xx--) {
                   1740:                        grid_view_get_cell(s->grid, xx, s->cy, &gc);
                   1741:                        if (~gc.flags & GRID_FLAG_PADDING)
                   1742:                                break;
1.136     nicm     1743:                        grid_view_set_cell(s->grid, xx, s->cy,
                   1744:                            &grid_default_cell);
1.131     nicm     1745:                }
1.139     nicm     1746:                if (gc.data.width > 1) {
1.136     nicm     1747:                        grid_view_set_cell(s->grid, xx, s->cy,
                   1748:                            &grid_default_cell);
1.139     nicm     1749:                }
1.131     nicm     1750:        }
                   1751:
1.172     nicm     1752:        grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x,
                   1753:            ci->used);
1.139     nicm     1754:        screen_write_set_cursor(ctx, s->cx + ci->used, -1);
1.131     nicm     1755:
                   1756:        for (xx = s->cx; xx < screen_size_x(s); xx++) {
                   1757:                grid_view_get_cell(s->grid, xx, s->cy, &gc);
                   1758:                if (~gc.flags & GRID_FLAG_PADDING)
                   1759:                        break;
                   1760:                grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell);
                   1761:        }
1.109     nicm     1762: }
                   1763:
                   1764: /* Write cell data, collecting if necessary. */
                   1765: void
                   1766: screen_write_collect_add(struct screen_write_ctx *ctx,
                   1767:     const struct grid_cell *gc)
                   1768: {
1.193     nicm     1769:        struct screen                   *s = ctx->s;
                   1770:        struct screen_write_citem       *ci;
                   1771:        u_int                            sx = screen_size_x(s);
                   1772:        int                              collect;
1.109     nicm     1773:
                   1774:        /*
                   1775:         * Don't need to check that the attributes and whatnot are still the
1.116     nicm     1776:         * same - input_parse will end the collection when anything that isn't
1.159     nicm     1777:         * a plain character is encountered.
1.109     nicm     1778:         */
                   1779:
                   1780:        collect = 1;
1.136     nicm     1781:        if (gc->data.width != 1 || gc->data.size != 1 || *gc->data.data >= 0x7f)
1.109     nicm     1782:                collect = 0;
                   1783:        else if (gc->attr & GRID_ATTR_CHARSET)
                   1784:                collect = 0;
                   1785:        else if (~s->mode & MODE_WRAP)
                   1786:                collect = 0;
                   1787:        else if (s->mode & MODE_INSERT)
                   1788:                collect = 0;
1.138     nicm     1789:        else if (s->sel != NULL)
1.109     nicm     1790:                collect = 0;
                   1791:        if (!collect) {
                   1792:                screen_write_collect_end(ctx);
1.164     nicm     1793:                screen_write_collect_flush(ctx, 0, __func__);
1.109     nicm     1794:                screen_write_cell(ctx, gc);
                   1795:                return;
                   1796:        }
                   1797:
                   1798:        if (s->cx > sx - 1 || ctx->item->used > sx - 1 - s->cx)
                   1799:                screen_write_collect_end(ctx);
1.118     nicm     1800:        ci = ctx->item; /* may have changed */
                   1801:
1.109     nicm     1802:        if (s->cx > sx - 1) {
1.114     nicm     1803:                log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy);
1.118     nicm     1804:                ci->wrapped = 1;
1.122     nicm     1805:                screen_write_linefeed(ctx, 1, 8);
1.139     nicm     1806:                screen_write_set_cursor(ctx, 0, -1);
1.109     nicm     1807:        }
                   1808:
                   1809:        if (ci->used == 0)
                   1810:                memcpy(&ci->gc, gc, sizeof ci->gc);
1.172     nicm     1811:        if (ctx->s->write_list[s->cy].data == NULL)
                   1812:                ctx->s->write_list[s->cy].data = xmalloc(screen_size_x(ctx->s));
                   1813:        ctx->s->write_list[s->cy].data[s->cx + ci->used++] = gc->data.data[0];
1.109     nicm     1814: }
                   1815:
1.1       nicm     1816: /* Write cell data. */
                   1817: void
1.60      nicm     1818: screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
1.1       nicm     1819: {
                   1820:        struct screen           *s = ctx->s;
                   1821:        struct grid             *gd = s->grid;
1.196     nicm     1822:        const struct utf8_data  *ud = &gc->data;
                   1823:        const struct utf8_data   zwj = { "\342\200\215", 0, 3, 0 };
1.109     nicm     1824:        struct grid_line        *gl;
                   1825:        struct grid_cell_entry  *gce;
                   1826:        struct grid_cell         tmp_gc, now_gc;
1.15      nicm     1827:        struct tty_ctx           ttyctx;
1.92      nicm     1828:        u_int                    sx = screen_size_x(s), sy = screen_size_y(s);
1.213     nicm     1829:        u_int                    width = gc->data.width, xx, last, cx, cy;
1.109     nicm     1830:        int                      selected, skip = 1;
1.1       nicm     1831:
1.109     nicm     1832:        /* Ignore padding cells. */
1.1       nicm     1833:        if (gc->flags & GRID_FLAG_PADDING)
                   1834:                return;
1.32      nicm     1835:
1.196     nicm     1836:        /*
                   1837:         * If this is a zero width joiner, set the flag so the next character
                   1838:         * will be treated as zero width and appended. Note that we assume a
                   1839:         * ZWJ will not change the width - the width of the first character is
                   1840:         * used.
                   1841:         */
                   1842:        if (ud->size == 3 && memcmp(ud->data, "\342\200\215", 3) == 0) {
                   1843:                log_debug("zero width joiner at %u,%u", s->cx, s->cy);
                   1844:                ctx->flags |= SCREEN_WRITE_ZWJ;
                   1845:                return;
                   1846:        }
                   1847:
                   1848:        /*
                   1849:         * If the width is zero, combine onto the previous character. We always
                   1850:         * combine with the cell to the left of the cursor position. In theory,
                   1851:         * the application could have moved the cursor somewhere else, but if
                   1852:         * they are silly enough to do that, who cares?
                   1853:         */
                   1854:        if (ctx->flags & SCREEN_WRITE_ZWJ) {
                   1855:                screen_write_collect_flush(ctx, 0, __func__);
1.213     nicm     1856:                screen_write_combine(ctx, &zwj, &xx, &cx);
1.196     nicm     1857:        }
                   1858:        if (width == 0 || (ctx->flags & SCREEN_WRITE_ZWJ)) {
                   1859:                ctx->flags &= ~SCREEN_WRITE_ZWJ;
1.164     nicm     1860:                screen_write_collect_flush(ctx, 0, __func__);
1.213     nicm     1861:                if ((gc = screen_write_combine(ctx, ud, &xx, &cx)) != NULL) {
1.212     nicm     1862:                        cy = s->cy;
1.144     nicm     1863:                        screen_write_set_cursor(ctx, xx, s->cy);
1.163     nicm     1864:                        screen_write_initctx(ctx, &ttyctx, 0);
1.104     nicm     1865:                        ttyctx.cell = gc;
                   1866:                        tty_write(tty_cmd_cell, &ttyctx);
1.213     nicm     1867:                        s->cx = cx; s->cy = cy;
1.1       nicm     1868:                }
                   1869:                return;
                   1870:        }
1.112     nicm     1871:
                   1872:        /* Flush any existing scrolling. */
1.164     nicm     1873:        screen_write_collect_flush(ctx, 1, __func__);
1.1       nicm     1874:
1.109     nicm     1875:        /* If this character doesn't fit, ignore it. */
                   1876:        if ((~s->mode & MODE_WRAP) &&
                   1877:            width > 1 &&
                   1878:            (width > sx || (s->cx != sx && s->cx > sx - width)))
                   1879:                return;
                   1880:
1.6       nicm     1881:        /* If in insert mode, make space for the cells. */
1.98      nicm     1882:        if (s->mode & MODE_INSERT) {
1.109     nicm     1883:                grid_view_insert_cells(s->grid, s->cx, s->cy, width, 8);
                   1884:                skip = 0;
                   1885:        }
1.6       nicm     1886:
1.20      nicm     1887:        /* Check this will fit on the current line and wrap if not. */
1.92      nicm     1888:        if ((s->mode & MODE_WRAP) && s->cx > sx - width) {
1.128     nicm     1889:                log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy);
1.122     nicm     1890:                screen_write_linefeed(ctx, 1, 8);
1.139     nicm     1891:                screen_write_set_cursor(ctx, 0, -1);
1.164     nicm     1892:                screen_write_collect_flush(ctx, 1, __func__);
1.1       nicm     1893:        }
                   1894:
1.64      nicm     1895:        /* Sanity check cursor position. */
1.92      nicm     1896:        if (s->cx > sx - width || s->cy > sy - 1)
1.1       nicm     1897:                return;
1.163     nicm     1898:        screen_write_initctx(ctx, &ttyctx, 0);
1.106     nicm     1899:
1.1       nicm     1900:        /* Handle overwriting of UTF-8 characters. */
1.137     nicm     1901:        gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
1.92      nicm     1902:        if (gl->flags & GRID_LINE_EXTENDED) {
                   1903:                grid_view_get_cell(gd, s->cx, s->cy, &now_gc);
                   1904:                if (screen_write_overwrite(ctx, &now_gc, width))
                   1905:                        skip = 0;
                   1906:        }
1.1       nicm     1907:
                   1908:        /*
                   1909:         * If the new character is UTF-8 wide, fill in padding cells. Have
                   1910:         * already ensured there is enough room.
                   1911:         */
1.89      nicm     1912:        for (xx = s->cx + 1; xx < s->cx + width; xx++) {
1.131     nicm     1913:                log_debug("%s: new padding at %u,%u", __func__, xx, s->cy);
1.184     nicm     1914:                grid_view_set_padding(gd, xx, s->cy);
1.89      nicm     1915:                skip = 0;
                   1916:        }
                   1917:
                   1918:        /* If no change, do not draw. */
1.92      nicm     1919:        if (skip) {
                   1920:                if (s->cx >= gl->cellsize)
                   1921:                        skip = grid_cells_equal(gc, &grid_default_cell);
                   1922:                else {
                   1923:                        gce = &gl->celldata[s->cx];
                   1924:                        if (gce->flags & GRID_FLAG_EXTENDED)
                   1925:                                skip = 0;
1.95      nicm     1926:                        else if (gc->flags != gce->flags)
1.92      nicm     1927:                                skip = 0;
                   1928:                        else if (gc->attr != gce->data.attr)
                   1929:                                skip = 0;
                   1930:                        else if (gc->fg != gce->data.fg)
                   1931:                                skip = 0;
                   1932:                        else if (gc->bg != gce->data.bg)
                   1933:                                skip = 0;
1.95      nicm     1934:                        else if (gc->data.width != 1)
                   1935:                                skip = 0;
1.109     nicm     1936:                        else if (gc->data.size != 1)
                   1937:                                skip = 0;
1.95      nicm     1938:                        else if (gce->data.data != gc->data.data[0])
1.92      nicm     1939:                                skip = 0;
                   1940:                }
                   1941:        }
1.1       nicm     1942:
1.127     nicm     1943:        /* Update the selected flag and set the cell. */
1.90      nicm     1944:        selected = screen_check_selection(s, s->cx, s->cy);
1.109     nicm     1945:        if (selected && (~gc->flags & GRID_FLAG_SELECTED)) {
1.90      nicm     1946:                memcpy(&tmp_gc, gc, sizeof tmp_gc);
                   1947:                tmp_gc.flags |= GRID_FLAG_SELECTED;
                   1948:                grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
1.109     nicm     1949:        } else if (!selected && (gc->flags & GRID_FLAG_SELECTED)) {
1.90      nicm     1950:                memcpy(&tmp_gc, gc, sizeof tmp_gc);
                   1951:                tmp_gc.flags &= ~GRID_FLAG_SELECTED;
                   1952:                grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
                   1953:        } else if (!skip)
1.89      nicm     1954:                grid_view_set_cell(gd, s->cx, s->cy, gc);
1.109     nicm     1955:        if (selected)
                   1956:                skip = 0;
1.1       nicm     1957:
1.64      nicm     1958:        /*
                   1959:         * Move the cursor. If not wrapping, stick at the last character and
                   1960:         * replace it.
                   1961:         */
1.65      nicm     1962:        last = !(s->mode & MODE_WRAP);
1.92      nicm     1963:        if (s->cx <= sx - last - width)
1.139     nicm     1964:                screen_write_set_cursor(ctx, s->cx + width, -1);
1.64      nicm     1965:        else
1.139     nicm     1966:                screen_write_set_cursor(ctx,  sx - last, -1);
1.1       nicm     1967:
1.89      nicm     1968:        /* Create space for character in insert mode. */
1.109     nicm     1969:        if (s->mode & MODE_INSERT) {
1.164     nicm     1970:                screen_write_collect_flush(ctx, 0, __func__);
1.17      nicm     1971:                ttyctx.num = width;
                   1972:                tty_write(tty_cmd_insertcharacter, &ttyctx);
                   1973:        }
1.89      nicm     1974:
                   1975:        /* Write to the screen. */
1.109     nicm     1976:        if (!skip) {
                   1977:                if (selected) {
                   1978:                        screen_select_cell(s, &tmp_gc, gc);
                   1979:                        ttyctx.cell = &tmp_gc;
                   1980:                } else
                   1981:                        ttyctx.cell = gc;
1.16      nicm     1982:                tty_write(tty_cmd_cell, &ttyctx);
1.193     nicm     1983:        }
1.35      nicm     1984: }
                   1985:
                   1986: /* Combine a UTF-8 zero-width character onto the previous. */
1.104     nicm     1987: static const struct grid_cell *
                   1988: screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud,
1.213     nicm     1989:     u_int *xx, u_int *cx)
1.35      nicm     1990: {
                   1991:        struct screen           *s = ctx->s;
                   1992:        struct grid             *gd = s->grid;
1.104     nicm     1993:        static struct grid_cell  gc;
1.213     nicm     1994:        u_int                    n, width;
1.35      nicm     1995:
                   1996:        /* Can't combine if at 0. */
1.213     nicm     1997:        if (s->cx == 0) {
                   1998:                *xx = 0;
1.104     nicm     1999:                return (NULL);
1.213     nicm     2000:        }
                   2001:        *xx = s->cx;
1.35      nicm     2002:
1.60      nicm     2003:        /* Empty data is out. */
                   2004:        if (ud->size == 0)
1.37      nicm     2005:                fatalx("UTF-8 data empty");
                   2006:
1.60      nicm     2007:        /* Retrieve the previous cell. */
1.119     nicm     2008:        for (n = 1; n <= s->cx; n++) {
1.104     nicm     2009:                grid_view_get_cell(gd, s->cx - n, s->cy, &gc);
                   2010:                if (~gc.flags & GRID_FLAG_PADDING)
                   2011:                        break;
                   2012:        }
1.119     nicm     2013:        if (n > s->cx)
1.104     nicm     2014:                return (NULL);
1.35      nicm     2015:
1.60      nicm     2016:        /* Check there is enough space. */
1.77      nicm     2017:        if (gc.data.size + ud->size > sizeof gc.data.data)
1.104     nicm     2018:                return (NULL);
1.213     nicm     2019:        (*xx) -= n;
1.104     nicm     2020:
1.213     nicm     2021:        log_debug("%s: %.*s onto %.*s at %u,%u (width %u)", __func__,
                   2022:            (int)ud->size, ud->data, (int)gc.data.size, gc.data.data, *xx,
                   2023:            s->cy, gc.data.width);
1.35      nicm     2024:
1.77      nicm     2025:        /* Append the data. */
                   2026:        memcpy(gc.data.data + gc.data.size, ud->data, ud->size);
                   2027:        gc.data.size += ud->size;
1.213     nicm     2028:        width = gc.data.width;
1.212     nicm     2029:
                   2030:        /* If this is U+FE0F VARIATION SELECTOR-16, force the width to 2. */
                   2031:        if (gc.data.width == 1 &&
1.213     nicm     2032:            ud->size == 3 &&
                   2033:            memcmp(ud->data, "\357\270\217", 3) == 0) {
1.212     nicm     2034:                grid_view_set_padding(gd, (*xx) + 1, s->cy);
                   2035:                gc.data.width = 2;
1.213     nicm     2036:                width += 2;
1.212     nicm     2037:        }
1.77      nicm     2038:
                   2039:        /* Set the new cell. */
1.104     nicm     2040:        grid_view_set_cell(gd, *xx, s->cy, &gc);
1.35      nicm     2041:
1.213     nicm     2042:        *cx = (*xx) + width;
                   2043:        log_debug("%s: character at %u; cursor at %u", __func__, *xx, *cx);
1.104     nicm     2044:        return (&gc);
1.1       nicm     2045: }
                   2046:
                   2047: /*
                   2048:  * UTF-8 wide characters are a bit of an annoyance. They take up more than one
                   2049:  * cell on the screen, so following cells must not be drawn by marking them as
                   2050:  * padding.
                   2051:  *
                   2052:  * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
                   2053:  * character, it is necessary to also overwrite any other cells which covered
                   2054:  * by the same character.
                   2055:  */
1.89      nicm     2056: static int
                   2057: screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
                   2058:     u_int width)
1.1       nicm     2059: {
                   2060:        struct screen           *s = ctx->s;
                   2061:        struct grid             *gd = s->grid;
1.89      nicm     2062:        struct grid_cell         tmp_gc;
1.1       nicm     2063:        u_int                    xx;
1.89      nicm     2064:        int                      done = 0;
1.1       nicm     2065:
1.89      nicm     2066:        if (gc->flags & GRID_FLAG_PADDING) {
1.1       nicm     2067:                /*
                   2068:                 * A padding cell, so clear any following and leading padding
                   2069:                 * cells back to the character. Don't overwrite the current
                   2070:                 * cell as that happens later anyway.
                   2071:                 */
                   2072:                xx = s->cx + 1;
                   2073:                while (--xx > 0) {
1.89      nicm     2074:                        grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
                   2075:                        if (~tmp_gc.flags & GRID_FLAG_PADDING)
1.1       nicm     2076:                                break;
1.131     nicm     2077:                        log_debug("%s: padding at %u,%u", __func__, xx, s->cy);
1.1       nicm     2078:                        grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
                   2079:                }
                   2080:
                   2081:                /* Overwrite the character at the start of this padding. */
1.131     nicm     2082:                log_debug("%s: character at %u,%u", __func__, xx, s->cy);
1.1       nicm     2083:                grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
1.89      nicm     2084:                done = 1;
1.43      nicm     2085:        }
1.1       nicm     2086:
1.43      nicm     2087:        /*
1.95      nicm     2088:         * Overwrite any padding cells that belong to any UTF-8 characters
                   2089:         * we'll be overwriting with the current character.
1.43      nicm     2090:         */
1.95      nicm     2091:        if (width != 1 ||
                   2092:            gc->data.width != 1 ||
                   2093:            gc->flags & GRID_FLAG_PADDING) {
1.89      nicm     2094:                xx = s->cx + width - 1;
                   2095:                while (++xx < screen_size_x(s)) {
                   2096:                        grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
                   2097:                        if (~tmp_gc.flags & GRID_FLAG_PADDING)
                   2098:                                break;
1.160     nicm     2099:                        log_debug("%s: overwrite at %u,%u", __func__, xx,
                   2100:                            s->cy);
1.89      nicm     2101:                        grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
                   2102:                        done = 1;
                   2103:                }
1.1       nicm     2104:        }
1.89      nicm     2105:
                   2106:        return (done);
1.50      nicm     2107: }
                   2108:
1.107     nicm     2109: /* Set external clipboard. */
1.50      nicm     2110: void
1.208     nicm     2111: screen_write_setselection(struct screen_write_ctx *ctx, const char *flags,
                   2112:     u_char *str, u_int len)
1.50      nicm     2113: {
                   2114:        struct tty_ctx  ttyctx;
                   2115:
1.163     nicm     2116:        screen_write_initctx(ctx, &ttyctx, 0);
1.50      nicm     2117:        ttyctx.ptr = str;
1.208     nicm     2118:        ttyctx.ptr2 = (void *)flags;
1.50      nicm     2119:        ttyctx.num = len;
                   2120:
                   2121:        tty_write(tty_cmd_setselection, &ttyctx);
1.47      nicm     2122: }
                   2123:
1.107     nicm     2124: /* Write unmodified string. */
1.47      nicm     2125: void
1.209     nicm     2126: screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len,
                   2127:     int allow_invisible_panes)
1.47      nicm     2128: {
1.87      nicm     2129:        struct tty_ctx  ttyctx;
1.47      nicm     2130:
1.163     nicm     2131:        screen_write_initctx(ctx, &ttyctx, 0);
1.47      nicm     2132:        ttyctx.ptr = str;
                   2133:        ttyctx.num = len;
1.209     nicm     2134:        ttyctx.allow_invisible_panes = allow_invisible_panes;
1.47      nicm     2135:
                   2136:        tty_write(tty_cmd_rawstring, &ttyctx);
1.178     nicm     2137: }
                   2138:
                   2139: /* Turn alternate screen on. */
                   2140: void
                   2141: screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc,
                   2142:     int cursor)
                   2143: {
                   2144:        struct tty_ctx           ttyctx;
                   2145:        struct window_pane      *wp = ctx->wp;
                   2146:
                   2147:        if (wp != NULL && !options_get_number(wp->options, "alternate-screen"))
                   2148:                return;
1.192     nicm     2149:
                   2150:        screen_write_collect_flush(ctx, 0, __func__);
1.178     nicm     2151:        screen_alternate_on(ctx->s, gc, cursor);
                   2152:
1.211     nicm     2153:        screen_write_initctx(ctx, &ttyctx, 1);
                   2154:        if (ttyctx.redraw_cb != NULL)
1.210     nicm     2155:                ttyctx.redraw_cb(&ttyctx);
1.178     nicm     2156: }
                   2157:
                   2158: /* Turn alternate screen off. */
                   2159: void
                   2160: screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc,
                   2161:     int cursor)
                   2162: {
                   2163:        struct tty_ctx           ttyctx;
                   2164:        struct window_pane      *wp = ctx->wp;
                   2165:
                   2166:        if (wp != NULL && !options_get_number(wp->options, "alternate-screen"))
                   2167:                return;
1.192     nicm     2168:
                   2169:        screen_write_collect_flush(ctx, 0, __func__);
1.178     nicm     2170:        screen_alternate_off(ctx->s, gc, cursor);
                   2171:
1.211     nicm     2172:        screen_write_initctx(ctx, &ttyctx, 1);
                   2173:        if (ttyctx.redraw_cb != NULL)
1.210     nicm     2174:                ttyctx.redraw_cb(&ttyctx);
1.1       nicm     2175: }