File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / screen-write.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (6 years, 11 months ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>