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

1.1     ! nicm        1: /* $OpenBSD$ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
        !             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:
        !            21: #include <string.h>
        !            22:
        !            23: #include "tmux.h"
        !            24:
        !            25: void   screen_write_save(struct screen_write_ctx *);
        !            26: void   screen_write_overwrite(struct screen_write_ctx *);
        !            27:
        !            28: /* Initialise writing with a window. */
        !            29: void
        !            30: screen_write_start(
        !            31:     struct screen_write_ctx *ctx, struct window_pane *wp, struct screen *s)
        !            32: {
        !            33:        ctx->wp = wp;
        !            34:        if (wp != NULL && s == NULL)
        !            35:                ctx->s = wp->screen;
        !            36:        else
        !            37:                ctx->s = s;
        !            38: }
        !            39:
        !            40: /* Finish writing. */
        !            41: void
        !            42: screen_write_stop(unused struct screen_write_ctx *ctx)
        !            43: {
        !            44: }
        !            45:
        !            46: /* Write character. */
        !            47: void
        !            48: screen_write_putc(
        !            49:     struct screen_write_ctx *ctx, struct grid_cell *gc, u_char ch)
        !            50: {
        !            51:        gc->data = ch;
        !            52:        screen_write_cell(ctx, gc, NULL);
        !            53: }
        !            54:
        !            55: /* Write string. */
        !            56: void printflike3
        !            57: screen_write_puts(
        !            58:     struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...)
        !            59: {
        !            60:        va_list ap;
        !            61:        char   *msg, *ptr;
        !            62:
        !            63:        va_start(ap, fmt);
        !            64:        xvasprintf(&msg, fmt, ap);
        !            65:        va_end(ap);
        !            66:
        !            67:        for (ptr = msg; *ptr != '\0'; ptr++)
        !            68:                screen_write_putc(ctx, gc, (u_char) *ptr);
        !            69:
        !            70:        xfree(msg);
        !            71: }
        !            72:
        !            73: /* Copy from another screen. */
        !            74: void
        !            75: screen_write_copy(struct screen_write_ctx *ctx,
        !            76:     struct screen *src, u_int px, u_int py, u_int nx, u_int ny)
        !            77: {
        !            78:        struct screen           *s = ctx->s;
        !            79:        struct grid             *gd = src->grid;
        !            80:        const struct grid_cell  *gc;
        !            81:        struct grid_utf8        *gu;
        !            82:        u_char                  *udata;
        !            83:        u_int                    xx, yy, cx, cy;
        !            84:
        !            85:        cx = s->cx;
        !            86:        cy = s->cy;
        !            87:        for (yy = py; yy < py + ny; yy++) {
        !            88:                for (xx = px; xx < px + nx; xx++) {
        !            89:                        if (xx >= gd->sx || yy >= gd->hsize + gd->sy)
        !            90:                                gc = &grid_default_cell;
        !            91:                        else
        !            92:                                gc = grid_peek_cell(gd, xx, yy);
        !            93:
        !            94:                        udata = NULL;
        !            95:                        if (gc->flags & GRID_FLAG_UTF8) {
        !            96:                                gu = grid_get_utf8(gd, xx, yy);
        !            97:                                udata = gu->data;
        !            98:                        }
        !            99:
        !           100:                        screen_write_cell(ctx, gc, udata);
        !           101:                }
        !           102:                cy++;
        !           103:                screen_write_cursormove(ctx, cx, cy);
        !           104:        }
        !           105: }
        !           106:
        !           107: /* Save cursor and region positions. */
        !           108: void
        !           109: screen_write_save(struct screen_write_ctx *ctx)
        !           110: {
        !           111:        struct screen   *s = ctx->s;
        !           112:
        !           113:        s->old_cx = s->cx;
        !           114:        s->old_cy = s->cy;
        !           115:
        !           116:        s->old_rlower = s->rlower;
        !           117:        s->old_rupper = s->rupper;
        !           118: }
        !           119:
        !           120: /* Cursor up by ny. */
        !           121: void
        !           122: screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
        !           123: {
        !           124:        struct screen   *s = ctx->s;
        !           125:
        !           126:        if (ny == 0)
        !           127:                ny = 1;
        !           128:
        !           129:        if (ny > s->cy)
        !           130:                ny = s->cy;
        !           131:        if (ny == 0)
        !           132:                return;
        !           133:
        !           134:        s->cy -= ny;
        !           135: }
        !           136:
        !           137: /* Cursor down by ny. */
        !           138: void
        !           139: screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
        !           140: {
        !           141:        struct screen   *s = ctx->s;
        !           142:
        !           143:        if (ny == 0)
        !           144:                ny = 1;
        !           145:
        !           146:        if (ny > screen_size_y(s) - 1 - s->cy)
        !           147:                ny = screen_size_y(s) - 1 - s->cy;
        !           148:        if (ny == 0)
        !           149:                return;
        !           150:
        !           151:        s->cy += ny;
        !           152: }
        !           153:
        !           154: /* Cursor right by nx.  */
        !           155: void
        !           156: screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
        !           157: {
        !           158:        struct screen   *s = ctx->s;
        !           159:
        !           160:        if (nx == 0)
        !           161:                nx = 1;
        !           162:
        !           163:        if (nx > screen_size_x(s) - 1 - s->cx)
        !           164:                nx = screen_size_x(s) - 1 - s->cx;
        !           165:        if (nx == 0)
        !           166:                return;
        !           167:
        !           168:        s->cx += nx;
        !           169: }
        !           170:
        !           171: /* Cursor left by nx. */
        !           172: void
        !           173: screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
        !           174: {
        !           175:        struct screen   *s = ctx->s;
        !           176:
        !           177:        if (nx == 0)
        !           178:                nx = 1;
        !           179:
        !           180:        if (nx > s->cx)
        !           181:                nx = s->cx;
        !           182:        if (nx == 0)
        !           183:                return;
        !           184:
        !           185:        s->cx -= nx;
        !           186: }
        !           187:
        !           188: /* Insert nx characters. */
        !           189: void
        !           190: screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx)
        !           191: {
        !           192:        struct screen   *s = ctx->s;
        !           193:
        !           194:        if (nx == 0)
        !           195:                nx = 1;
        !           196:
        !           197:        if (nx > screen_size_x(s) - 1 - s->cx)
        !           198:                nx = screen_size_x(s) - 1 - s->cx;
        !           199:        if (nx == 0)
        !           200:                return;
        !           201:
        !           202:        screen_write_save(ctx);
        !           203:
        !           204:        if (s->cx <= screen_size_x(s) - 1)
        !           205:                grid_view_insert_cells(s->grid, s->cx, s->cy, nx);
        !           206:
        !           207:        tty_write_cmd(ctx->wp, TTY_INSERTCHARACTER, nx);
        !           208: }
        !           209:
        !           210: /* Delete nx characters. */
        !           211: void
        !           212: screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx)
        !           213: {
        !           214:        struct screen   *s = ctx->s;
        !           215:
        !           216:        if (nx == 0)
        !           217:                nx = 1;
        !           218:
        !           219:        if (nx > screen_size_x(s) - 1 - s->cx)
        !           220:                nx = screen_size_x(s) - 1 - s->cx;
        !           221:        if (nx == 0)
        !           222:                return;
        !           223:
        !           224:        screen_write_save(ctx);
        !           225:
        !           226:        if (s->cx <= screen_size_x(s) - 1)
        !           227:                grid_view_delete_cells(s->grid, s->cx, s->cy, nx);
        !           228:
        !           229:        tty_write_cmd(ctx->wp, TTY_DELETECHARACTER, nx);
        !           230: }
        !           231:
        !           232: /* Insert ny lines. */
        !           233: void
        !           234: screen_write_insertline(struct screen_write_ctx *ctx, u_int ny)
        !           235: {
        !           236:        struct screen   *s = ctx->s;
        !           237:
        !           238:        if (ny == 0)
        !           239:                ny = 1;
        !           240:
        !           241:        if (ny > screen_size_y(s) - 1 - s->cy)
        !           242:                ny = screen_size_y(s) - 1 - s->cy;
        !           243:        if (ny == 0)
        !           244:                return;
        !           245:
        !           246:        screen_write_save(ctx);
        !           247:
        !           248:        if (s->cy < s->rupper || s->cy > s->rlower)
        !           249:                grid_view_insert_lines(s->grid, s->cy, ny);
        !           250:        else {
        !           251:                grid_view_insert_lines_region(
        !           252:                    s->grid, s->rupper, s->rlower, s->cy, ny);
        !           253:        }
        !           254:
        !           255:        tty_write_cmd(ctx->wp, TTY_INSERTLINE, ny);
        !           256: }
        !           257:
        !           258: /* Delete ny lines. */
        !           259: void
        !           260: screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
        !           261: {
        !           262:        struct screen   *s = ctx->s;
        !           263:
        !           264:        if (ny == 0)
        !           265:                ny = 1;
        !           266:
        !           267:        if (ny > screen_size_y(s) - 1 - s->cy)
        !           268:                ny = screen_size_y(s) - 1 - s->cy;
        !           269:        if (ny == 0)
        !           270:                return;
        !           271:
        !           272:        screen_write_save(ctx);
        !           273:
        !           274:        if (s->cy < s->rupper || s->cy > s->rlower)
        !           275:                grid_view_delete_lines(s->grid, s->cy, ny);
        !           276:        else {
        !           277:                grid_view_delete_lines_region(
        !           278:                    s->grid, s->rupper, s->rlower, s->cy, ny);
        !           279:        }
        !           280:
        !           281:        tty_write_cmd(ctx->wp, TTY_DELETELINE, ny);
        !           282: }
        !           283:
        !           284: /* Clear line at cursor. */
        !           285: void
        !           286: screen_write_clearline(struct screen_write_ctx *ctx)
        !           287: {
        !           288:        struct screen   *s = ctx->s;
        !           289:
        !           290:        screen_write_save(ctx);
        !           291:
        !           292:        grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1);
        !           293:
        !           294:        tty_write_cmd(ctx->wp, TTY_CLEARLINE);
        !           295: }
        !           296:
        !           297: /* Clear to end of line from cursor. */
        !           298: void
        !           299: screen_write_clearendofline(struct screen_write_ctx *ctx)
        !           300: {
        !           301:        struct screen   *s = ctx->s;
        !           302:        u_int            sx;
        !           303:
        !           304:        screen_write_save(ctx);
        !           305:
        !           306:        sx = screen_size_x(s);
        !           307:
        !           308:        if (s->cx <= sx - 1)
        !           309:                grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
        !           310:
        !           311:        tty_write_cmd(ctx->wp, TTY_CLEARENDOFLINE);
        !           312: }
        !           313:
        !           314: /* Clear to start of line from cursor. */
        !           315: void
        !           316: screen_write_clearstartofline(struct screen_write_ctx *ctx)
        !           317: {
        !           318:        struct screen   *s = ctx->s;
        !           319:        u_int            sx;
        !           320:
        !           321:        screen_write_save(ctx);
        !           322:
        !           323:        sx = screen_size_x(s);
        !           324:
        !           325:        if (s->cx > sx - 1)
        !           326:                grid_view_clear(s->grid, 0, s->cy, sx, 1);
        !           327:        else
        !           328:                grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
        !           329:
        !           330:        tty_write_cmd(ctx->wp, TTY_CLEARSTARTOFLINE);
        !           331: }
        !           332:
        !           333: /* Move cursor to px,py.  */
        !           334: void
        !           335: screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
        !           336: {
        !           337:        struct screen   *s = ctx->s;
        !           338:
        !           339:        if (px > screen_size_x(s) - 1)
        !           340:                px = screen_size_x(s) - 1;
        !           341:        if (py > screen_size_y(s) - 1)
        !           342:                py = screen_size_y(s) - 1;
        !           343:
        !           344:        s->cx = px;
        !           345:        s->cy = py;
        !           346: }
        !           347:
        !           348: /* Set cursor mode. */
        !           349: void
        !           350: screen_write_cursormode(struct screen_write_ctx *ctx, int state)
        !           351: {
        !           352:        struct screen   *s = ctx->s;
        !           353:
        !           354:        if (state)
        !           355:                s->mode |= MODE_CURSOR;
        !           356:        else
        !           357:                s->mode &= ~MODE_CURSOR;
        !           358: }
        !           359:
        !           360: /* Reverse index (up with scroll).  */
        !           361: void
        !           362: screen_write_reverseindex(struct screen_write_ctx *ctx)
        !           363: {
        !           364:        struct screen   *s = ctx->s;
        !           365:
        !           366:        screen_write_save(ctx);
        !           367:
        !           368:        if (s->cy == s->rupper)
        !           369:                grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
        !           370:        else if (s->cy > 0)
        !           371:                s->cy--;
        !           372:
        !           373:        tty_write_cmd(ctx->wp, TTY_REVERSEINDEX);
        !           374: }
        !           375:
        !           376: /* Set scroll region. */
        !           377: void
        !           378: screen_write_scrollregion(
        !           379:     struct screen_write_ctx *ctx, u_int rupper, u_int rlower)
        !           380: {
        !           381:        struct screen   *s = ctx->s;
        !           382:
        !           383:        if (rupper > screen_size_y(s) - 1)
        !           384:                rupper = screen_size_y(s) - 1;
        !           385:        if (rlower > screen_size_y(s) - 1)
        !           386:                rlower = screen_size_y(s) - 1;
        !           387:        if (rupper > rlower)
        !           388:                return;
        !           389:
        !           390:        /* Cursor moves to top-left. */
        !           391:        s->cx = 0;
        !           392:        s->cy = 0;
        !           393:
        !           394:        s->rupper = rupper;
        !           395:        s->rlower = rlower;
        !           396: }
        !           397:
        !           398: /* Set insert mode. */
        !           399: void
        !           400: screen_write_insertmode(struct screen_write_ctx *ctx, int state)
        !           401: {
        !           402:        struct screen   *s = ctx->s;
        !           403:
        !           404:        if (state)
        !           405:                s->mode |= MODE_INSERT;
        !           406:        else
        !           407:                s->mode &= ~MODE_INSERT;
        !           408: }
        !           409:
        !           410: /* Set mouse mode.  */
        !           411: void
        !           412: screen_write_mousemode(struct screen_write_ctx *ctx, int state)
        !           413: {
        !           414:        struct screen   *s = ctx->s;
        !           415:
        !           416:        if (state)
        !           417:                s->mode |= MODE_MOUSE;
        !           418:        else
        !           419:                s->mode &= ~MODE_MOUSE;
        !           420: }
        !           421:
        !           422: /* Line feed (down with scroll). */
        !           423: void
        !           424: screen_write_linefeed(struct screen_write_ctx *ctx)
        !           425: {
        !           426:        struct screen   *s = ctx->s;
        !           427:
        !           428:        screen_write_save(ctx);
        !           429:
        !           430:        if (s->cy == s->rlower)
        !           431:                grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
        !           432:        else if (s->cy < screen_size_y(s) - 1)
        !           433:                s->cy++;
        !           434:
        !           435:        tty_write_cmd(ctx->wp, TTY_LINEFEED);
        !           436: }
        !           437:
        !           438: /* Carriage return (cursor to start of line). */
        !           439: void
        !           440: screen_write_carriagereturn(struct screen_write_ctx *ctx)
        !           441: {
        !           442:        struct screen   *s = ctx->s;
        !           443:
        !           444:        s->cx = 0;
        !           445: }
        !           446:
        !           447: /* Set keypad cursor keys mode. */
        !           448: void
        !           449: screen_write_kcursormode(struct screen_write_ctx *ctx, int state)
        !           450: {
        !           451:        struct screen   *s = ctx->s;
        !           452:
        !           453:        if (state)
        !           454:                s->mode |= MODE_KCURSOR;
        !           455:        else
        !           456:                s->mode &= ~MODE_KCURSOR;
        !           457: }
        !           458:
        !           459: /* Set keypad number keys mode. */
        !           460: void
        !           461: screen_write_kkeypadmode(struct screen_write_ctx *ctx, int state)
        !           462: {
        !           463:        struct screen   *s = ctx->s;
        !           464:
        !           465:        if (state)
        !           466:                s->mode |= MODE_KKEYPAD;
        !           467:        else
        !           468:                s->mode &= ~MODE_KKEYPAD;
        !           469: }
        !           470:
        !           471: /* Clear to end of screen from cursor. */
        !           472: void
        !           473: screen_write_clearendofscreen(struct screen_write_ctx *ctx)
        !           474: {
        !           475:        struct screen   *s = ctx->s;
        !           476:        u_int            sx, sy;
        !           477:
        !           478:        screen_write_save(ctx);
        !           479:
        !           480:        sx = screen_size_x(s);
        !           481:        sy = screen_size_y(s);
        !           482:
        !           483:        if (s->cx <= sx - 1)
        !           484:                grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
        !           485:        grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1));
        !           486:
        !           487:        tty_write_cmd(ctx->wp, TTY_CLEARENDOFSCREEN);
        !           488: }
        !           489:
        !           490: /* Clear to start of screen. */
        !           491: void
        !           492: screen_write_clearstartofscreen(struct screen_write_ctx *ctx)
        !           493: {
        !           494:        struct screen   *s = ctx->s;
        !           495:        u_int            sx;
        !           496:
        !           497:        screen_write_save(ctx);
        !           498:
        !           499:        sx = screen_size_x(s);
        !           500:
        !           501:        if (s->cy > 0)
        !           502:                grid_view_clear(s->grid, 0, 0, sx, s->cy - 1);
        !           503:        if (s->cx > sx - 1)
        !           504:                grid_view_clear(s->grid, 0, s->cy, sx, 1);
        !           505:        else
        !           506:                grid_view_clear(s->grid, 0, s->cy, s->cx, 1);
        !           507:
        !           508:        tty_write_cmd(ctx->wp, TTY_CLEARSTARTOFSCREEN);
        !           509: }
        !           510:
        !           511: /* Clear entire screen. */
        !           512: void
        !           513: screen_write_clearscreen(struct screen_write_ctx *ctx)
        !           514: {
        !           515:        struct screen   *s = ctx->s;
        !           516:
        !           517:        screen_write_save(ctx);
        !           518:
        !           519:        grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s));
        !           520:
        !           521:        tty_write_cmd(ctx->wp, TTY_CLEARSCREEN);
        !           522: }
        !           523:
        !           524: /* Write cell data. */
        !           525: void
        !           526: screen_write_cell(
        !           527:     struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata)
        !           528: {
        !           529:        struct screen           *s = ctx->s;
        !           530:        struct grid             *gd = s->grid;
        !           531:        struct grid_utf8         gu, *tmp_gu;
        !           532:        u_int                    width, xx, i;
        !           533:        struct grid_cell         tmp_gc, *tmp_gc2;
        !           534:        size_t                   size;
        !           535:
        !           536:        /* Ignore padding. */
        !           537:        if (gc->flags & GRID_FLAG_PADDING)
        !           538:                return;
        !           539:
        !           540:        /* Find character width. */
        !           541:        if (gc->flags & GRID_FLAG_UTF8) {
        !           542:                width = utf8_width(udata);
        !           543:
        !           544:                gu.width = width;
        !           545:                memcpy(&gu.data, udata, sizeof gu.data);
        !           546:        } else
        !           547:                width = 1;
        !           548:
        !           549:        /* If the width is zero, combine onto the previous character. */
        !           550:        if (width == 0) {
        !           551:                if (s->cx == 0)
        !           552:                        return;
        !           553:                tmp_gc2 = grid_view_get_cell(gd, s->cx - 1, s->cy);
        !           554:                if (!(tmp_gc2->flags & GRID_FLAG_UTF8)) {
        !           555:                        tmp_gc2->flags |= GRID_FLAG_UTF8;
        !           556:                        memset(&gu.data, 0xff, sizeof gu.data);
        !           557:                        *gu.data = tmp_gc2->data;
        !           558:                        gu.width = 1;
        !           559:                        grid_view_set_utf8(gd, s->cx - 1, s->cy, &gu);
        !           560:                }
        !           561:                tmp_gu = grid_view_get_utf8(gd, s->cx - 1, s->cy);
        !           562:
        !           563:                for (i = 0; i < UTF8_SIZE; i++) {
        !           564:                        if (tmp_gu->data[i] == 0xff)
        !           565:                                break;
        !           566:                }
        !           567:                memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i);
        !           568:
        !           569:                /* Assume the previous character has just been input. */
        !           570:                for (size = 0; size < UTF8_SIZE; size++) {
        !           571:                        if (udata[size] == 0xff)
        !           572:                                break;
        !           573:                }
        !           574:                tty_write_cmd(ctx->wp, TTY_RAW, udata, size);
        !           575:                return;
        !           576:        }
        !           577:
        !           578:        /* If the character is wider than the screen, don't print it. */
        !           579:        if (width > screen_size_x(s)) {
        !           580:                memcpy(&tmp_gc, gc, sizeof tmp_gc);
        !           581:                tmp_gc.data = '_';
        !           582:                width = 1;
        !           583:                gc = &tmp_gc;
        !           584:        }
        !           585:
        !           586:        /* Check this will fit on the current line; scroll if not. */
        !           587:        if (s->cx > screen_size_x(s) - width) {
        !           588:                screen_write_carriagereturn(ctx);
        !           589:                screen_write_linefeed(ctx);
        !           590:        }
        !           591:
        !           592:        /* Sanity checks. */
        !           593:        if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1)
        !           594:                return;
        !           595:
        !           596:        /* Handle overwriting of UTF-8 characters. */
        !           597:        screen_write_overwrite(ctx);
        !           598:
        !           599:        /*
        !           600:         * If the new character is UTF-8 wide, fill in padding cells. Have
        !           601:         * already ensured there is enough room.
        !           602:         */
        !           603:        for (xx = s->cx + 1; xx < s->cx + width; xx++) {
        !           604:                tmp_gc2 = grid_view_get_cell(gd, xx, s->cy);
        !           605:                if (tmp_gc2 != NULL)
        !           606:                        tmp_gc2->flags |= GRID_FLAG_PADDING;
        !           607:        }
        !           608:
        !           609:        /* Set the cell. */
        !           610:        grid_view_set_cell(gd, s->cx, s->cy, gc);
        !           611:        if (gc->flags & GRID_FLAG_UTF8)
        !           612:                grid_view_set_utf8(gd, s->cx, s->cy, &gu);
        !           613:
        !           614:        /* Move the cursor. */
        !           615:        screen_write_save(ctx);
        !           616:        s->cx += width;
        !           617:
        !           618:        /* Draw to the screen if necessary. */
        !           619:        if (screen_check_selection(s, s->cx - width, s->cy)) {
        !           620:                s->sel.cell.data = gc->data;
        !           621:                tty_write_cmd(ctx->wp, TTY_CELL, &s->sel.cell, &gu);
        !           622:        } else
        !           623:                tty_write_cmd(ctx->wp, TTY_CELL, gc, &gu);
        !           624: }
        !           625:
        !           626: /*
        !           627:  * UTF-8 wide characters are a bit of an annoyance. They take up more than one
        !           628:  * cell on the screen, so following cells must not be drawn by marking them as
        !           629:  * padding.
        !           630:  *
        !           631:  * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
        !           632:  * character, it is necessary to also overwrite any other cells which covered
        !           633:  * by the same character.
        !           634:  */
        !           635: void
        !           636: screen_write_overwrite(struct screen_write_ctx *ctx)
        !           637: {
        !           638:        struct screen           *s = ctx->s;
        !           639:        struct grid             *gd = s->grid;
        !           640:        const struct grid_cell  *gc;
        !           641:        const struct grid_utf8  *gu;
        !           642:        u_int                    xx;
        !           643:
        !           644:        gc = grid_view_peek_cell(gd, s->cx, s->cy);
        !           645:        gu = grid_view_peek_utf8(gd, s->cx, s->cy);
        !           646:
        !           647:        if (gc->flags & GRID_FLAG_PADDING) {
        !           648:                /*
        !           649:                 * A padding cell, so clear any following and leading padding
        !           650:                 * cells back to the character. Don't overwrite the current
        !           651:                 * cell as that happens later anyway.
        !           652:                 */
        !           653:                xx = s->cx + 1;
        !           654:                while (--xx > 0) {
        !           655:                        gc = grid_view_peek_cell(gd, xx, s->cy);
        !           656:                        if (!(gc->flags & GRID_FLAG_PADDING))
        !           657:                                break;
        !           658:                        grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
        !           659:                }
        !           660:
        !           661:                /* Overwrite the character at the start of this padding. */
        !           662:                grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
        !           663:
        !           664:                /* Overwrite following padding cells. */
        !           665:                xx = s->cx;
        !           666:                while (++xx < screen_size_x(s)) {
        !           667:                        gc = grid_view_peek_cell(gd, xx, s->cy);
        !           668:                        if (!(gc->flags & GRID_FLAG_PADDING))
        !           669:                                break;
        !           670:                        grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
        !           671:                }
        !           672:        } else if (gc->flags & GRID_FLAG_UTF8 && gu->width > 1) {
        !           673:                /*
        !           674:                 * An UTF-8 wide cell; overwrite following padding cells only.
        !           675:                 */
        !           676:                xx = s->cx;
        !           677:                while (++xx < screen_size_x(s)) {
        !           678:                        gc = grid_view_peek_cell(gd, xx, s->cy);
        !           679:                        if (!(gc->flags & GRID_FLAG_PADDING))
        !           680:                                break;
        !           681:                        grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
        !           682:                }
        !           683:        }
        !           684: }