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

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