1*d62c220eSnicm /* $OpenBSD: screen-write.c,v 1.232 2024/11/16 16:49:50 nicm Exp $ */ 2311827fbSnicm 3311827fbSnicm /* 498ca8272Snicm * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> 5311827fbSnicm * 6311827fbSnicm * Permission to use, copy, modify, and distribute this software for any 7311827fbSnicm * purpose with or without fee is hereby granted, provided that the above 8311827fbSnicm * copyright notice and this permission notice appear in all copies. 9311827fbSnicm * 10311827fbSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11311827fbSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12311827fbSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13311827fbSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14311827fbSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15311827fbSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16311827fbSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17311827fbSnicm */ 18311827fbSnicm 19311827fbSnicm #include <sys/types.h> 20311827fbSnicm 217d053cf9Snicm #include <stdlib.h> 22311827fbSnicm #include <string.h> 23311827fbSnicm 24311827fbSnicm #include "tmux.h" 25311827fbSnicm 262612f635Snicm static struct screen_write_citem *screen_write_collect_trim( 272612f635Snicm struct screen_write_ctx *, u_int, u_int, u_int, int *); 288248eab7Snicm static void screen_write_collect_clear(struct screen_write_ctx *, u_int, 298248eab7Snicm u_int); 302612f635Snicm static void screen_write_collect_scroll(struct screen_write_ctx *, u_int); 319b53212eSnicm static void screen_write_collect_flush(struct screen_write_ctx *, int, 329b53212eSnicm const char *); 338e39655fSnicm static int screen_write_overwrite(struct screen_write_ctx *, 348e39655fSnicm struct grid_cell *, u_int); 352af49740Snicm static int screen_write_combine(struct screen_write_ctx *, 362af49740Snicm const struct grid_cell *); 37311827fbSnicm 382612f635Snicm struct screen_write_citem { 398248eab7Snicm u_int x; 40566401c6Snicm int wrapped; 418248eab7Snicm 422612f635Snicm enum { TEXT, CLEAR } type; 438248eab7Snicm u_int used; 448b17a0f3Snicm u_int bg; 458248eab7Snicm 468248eab7Snicm struct grid_cell gc; 478248eab7Snicm 482612f635Snicm TAILQ_ENTRY(screen_write_citem) entry; 498248eab7Snicm }; 502612f635Snicm struct screen_write_cline { 51977b6338Snicm char *data; 522612f635Snicm TAILQ_HEAD(, screen_write_citem) items; 538248eab7Snicm }; 542612f635Snicm TAILQ_HEAD(, screen_write_citem) screen_write_citem_freelist = 552612f635Snicm TAILQ_HEAD_INITIALIZER(screen_write_citem_freelist); 562612f635Snicm 572612f635Snicm static struct screen_write_citem * 582612f635Snicm screen_write_get_citem(void) 592612f635Snicm { 602612f635Snicm struct screen_write_citem *ci; 612612f635Snicm 622612f635Snicm ci = TAILQ_FIRST(&screen_write_citem_freelist); 632612f635Snicm if (ci != NULL) { 642612f635Snicm TAILQ_REMOVE(&screen_write_citem_freelist, ci, entry); 652612f635Snicm memset(ci, 0, sizeof *ci); 662612f635Snicm return (ci); 672612f635Snicm } 682612f635Snicm return (xcalloc(1, sizeof *ci)); 692612f635Snicm } 702612f635Snicm 712612f635Snicm static void 722612f635Snicm screen_write_free_citem(struct screen_write_citem *ci) 732612f635Snicm { 742612f635Snicm TAILQ_INSERT_TAIL(&screen_write_citem_freelist, ci, entry); 752612f635Snicm } 765fd00eceSnicm 777b470e93Snicm static void 787b470e93Snicm screen_write_offset_timer(__unused int fd, __unused short events, void *data) 797b470e93Snicm { 807b470e93Snicm struct window *w = data; 817b470e93Snicm 827b470e93Snicm tty_update_window_offset(w); 837b470e93Snicm } 847b470e93Snicm 857b470e93Snicm /* Set cursor position. */ 867b470e93Snicm static void 877b470e93Snicm screen_write_set_cursor(struct screen_write_ctx *ctx, int cx, int cy) 887b470e93Snicm { 897b470e93Snicm struct window_pane *wp = ctx->wp; 907b470e93Snicm struct window *w; 917b470e93Snicm struct screen *s = ctx->s; 927b470e93Snicm struct timeval tv = { .tv_usec = 10000 }; 937b470e93Snicm 947b470e93Snicm if (cx != -1 && (u_int)cx == s->cx && cy != -1 && (u_int)cy == s->cy) 957b470e93Snicm return; 967b470e93Snicm 97ad47aa1bSnicm if (cx != -1) { 9894b5b5e9Snicm if ((u_int)cx > screen_size_x(s)) /* allow last column */ 99ad47aa1bSnicm cx = screen_size_x(s) - 1; 1007b470e93Snicm s->cx = cx; 101ad47aa1bSnicm } 102ad47aa1bSnicm if (cy != -1) { 103ad47aa1bSnicm if ((u_int)cy > screen_size_y(s) - 1) 104ad47aa1bSnicm cy = screen_size_y(s) - 1; 1057b470e93Snicm s->cy = cy; 106ad47aa1bSnicm } 1077b470e93Snicm 1087b470e93Snicm if (wp == NULL) 1097b470e93Snicm return; 1107b470e93Snicm w = wp->window; 1117b470e93Snicm 1127b470e93Snicm if (!event_initialized(&w->offset_timer)) 1137b470e93Snicm evtimer_set(&w->offset_timer, screen_write_offset_timer, w); 1147b470e93Snicm if (!evtimer_pending(&w->offset_timer, NULL)) 1157b470e93Snicm evtimer_add(&w->offset_timer, &tv); 1167b470e93Snicm } 1177b470e93Snicm 11883e83a91Snicm /* Do a full redraw. */ 11983e83a91Snicm static void 12083e83a91Snicm screen_write_redraw_cb(const struct tty_ctx *ttyctx) 12183e83a91Snicm { 12283e83a91Snicm struct window_pane *wp = ttyctx->arg; 12383e83a91Snicm 1243f192e30Snicm if (wp != NULL) 12583e83a91Snicm wp->flags |= PANE_REDRAW; 12683e83a91Snicm } 12783e83a91Snicm 12883e83a91Snicm /* Update context for client. */ 12983e83a91Snicm static int 13083e83a91Snicm screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c) 13183e83a91Snicm { 13283e83a91Snicm struct window_pane *wp = ttyctx->arg; 13383e83a91Snicm 134fa3d3b2eSnicm if (ttyctx->allow_invisible_panes) { 135fa3d3b2eSnicm if (session_has(c->session, wp->window)) 136fa3d3b2eSnicm return (1); 137fa3d3b2eSnicm return (0); 138fa3d3b2eSnicm } 139fa3d3b2eSnicm 14083e83a91Snicm if (c->session->curw->window != wp->window) 14183e83a91Snicm return (0); 14283e83a91Snicm if (wp->layout_cell == NULL) 14383e83a91Snicm return (0); 14483e83a91Snicm 14583e83a91Snicm if (wp->flags & (PANE_REDRAW|PANE_DROP)) 14683e83a91Snicm return (-1); 14783e83a91Snicm if (c->flags & CLIENT_REDRAWPANES) { 14883e83a91Snicm /* 14983e83a91Snicm * Redraw is already deferred to redraw another pane - redraw 15083e83a91Snicm * this one also when that happens. 15183e83a91Snicm */ 1522612f635Snicm log_debug("%s: adding %%%u to deferred redraw", __func__, 1532612f635Snicm wp->id); 154d2117533Snicm wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR); 15583e83a91Snicm return (-1); 15683e83a91Snicm } 15783e83a91Snicm 15883e83a91Snicm ttyctx->bigger = tty_window_offset(&c->tty, &ttyctx->wox, &ttyctx->woy, 15983e83a91Snicm &ttyctx->wsx, &ttyctx->wsy); 16083e83a91Snicm 16183e83a91Snicm ttyctx->xoff = ttyctx->rxoff = wp->xoff; 16283e83a91Snicm ttyctx->yoff = ttyctx->ryoff = wp->yoff; 16383e83a91Snicm 16483e83a91Snicm if (status_at_line(c) == 0) 16583e83a91Snicm ttyctx->yoff += status_line_size(c); 16683e83a91Snicm 16783e83a91Snicm return (1); 16883e83a91Snicm } 16983e83a91Snicm 1707f9a0536Snicm /* Set up context for TTY command. */ 1717f9a0536Snicm static void 1727f9a0536Snicm screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, 1737f9a0536Snicm int sync) 1747f9a0536Snicm { 1757f9a0536Snicm struct screen *s = ctx->s; 1767f9a0536Snicm 1777f9a0536Snicm memset(ttyctx, 0, sizeof *ttyctx); 1787f9a0536Snicm 17983e83a91Snicm ttyctx->s = s; 18010b45510Snicm ttyctx->sx = screen_size_x(s); 18110b45510Snicm ttyctx->sy = screen_size_y(s); 18210b45510Snicm 1837f9a0536Snicm ttyctx->ocx = s->cx; 1847f9a0536Snicm ttyctx->ocy = s->cy; 1857f9a0536Snicm ttyctx->orlower = s->rlower; 1867f9a0536Snicm ttyctx->orupper = s->rupper; 1877f9a0536Snicm 18833a1e283Snicm memcpy(&ttyctx->defaults, &grid_default_cell, sizeof ttyctx->defaults); 18933a1e283Snicm if (ctx->init_ctx_cb != NULL) { 19083e83a91Snicm ctx->init_ctx_cb(ctx, ttyctx); 19133a1e283Snicm if (ttyctx->palette != NULL) { 192ffda99cdSnicm if (ttyctx->defaults.fg == 8) 19333a1e283Snicm ttyctx->defaults.fg = ttyctx->palette->fg; 194ffda99cdSnicm if (ttyctx->defaults.bg == 8) 19533a1e283Snicm ttyctx->defaults.bg = ttyctx->palette->bg; 19633a1e283Snicm } 19733a1e283Snicm } else { 19883e83a91Snicm ttyctx->redraw_cb = screen_write_redraw_cb; 19933a1e283Snicm if (ctx->wp != NULL) { 20033a1e283Snicm tty_default_colours(&ttyctx->defaults, ctx->wp); 20133a1e283Snicm ttyctx->palette = &ctx->wp->palette; 20283e83a91Snicm ttyctx->set_client_cb = screen_write_set_client_cb; 20383e83a91Snicm ttyctx->arg = ctx->wp; 20483e83a91Snicm } 20533a1e283Snicm } 20683e83a91Snicm 207290f3047Snicm if (~ctx->flags & SCREEN_WRITE_SYNC) { 208290f3047Snicm /* 209290f3047Snicm * For the active pane or for an overlay (no pane), we want to 210290f3047Snicm * only use synchronized updates if requested (commands that 211290f3047Snicm * move the cursor); for other panes, always use it, since the 212290f3047Snicm * cursor will have to move. 213290f3047Snicm */ 214290f3047Snicm if (ctx->wp != NULL) { 215290f3047Snicm if (ctx->wp != ctx->wp->window->active) 216290f3047Snicm ttyctx->num = 1; 217290f3047Snicm else 218290f3047Snicm ttyctx->num = sync; 219290f3047Snicm } else 220290f3047Snicm ttyctx->num = 0x10|sync; 2217f9a0536Snicm tty_write(tty_cmd_syncstart, ttyctx); 2222b07bb4fSnicm ctx->flags |= SCREEN_WRITE_SYNC; 2237f9a0536Snicm } 2247f9a0536Snicm } 2257f9a0536Snicm 226977b6338Snicm /* Make write list. */ 227977b6338Snicm void 228977b6338Snicm screen_write_make_list(struct screen *s) 229977b6338Snicm { 230977b6338Snicm u_int y; 231977b6338Snicm 232977b6338Snicm s->write_list = xcalloc(screen_size_y(s), sizeof *s->write_list); 233977b6338Snicm for (y = 0; y < screen_size_y(s); y++) 234977b6338Snicm TAILQ_INIT(&s->write_list[y].items); 235977b6338Snicm } 236977b6338Snicm 237977b6338Snicm /* Free write list. */ 238977b6338Snicm void 239977b6338Snicm screen_write_free_list(struct screen *s) 240977b6338Snicm { 241977b6338Snicm u_int y; 242977b6338Snicm 243977b6338Snicm for (y = 0; y < screen_size_y(s); y++) 244977b6338Snicm free(s->write_list[y].data); 245977b6338Snicm free(s->write_list); 246977b6338Snicm } 247977b6338Snicm 24883e83a91Snicm /* Set up for writing. */ 24983e83a91Snicm static void 25083e83a91Snicm screen_write_init(struct screen_write_ctx *ctx, struct screen *s) 251311827fbSnicm { 2528248eab7Snicm memset(ctx, 0, sizeof *ctx); 2535fd00eceSnicm 254311827fbSnicm ctx->s = s; 2555fd00eceSnicm 256977b6338Snicm if (ctx->s->write_list == NULL) 257977b6338Snicm screen_write_make_list(ctx->s); 2582612f635Snicm ctx->item = screen_write_get_citem(); 2595fd00eceSnicm 2606d5c64a0Snicm ctx->scrolled = 0; 2616d5c64a0Snicm ctx->bg = 8; 26283e83a91Snicm } 26383e83a91Snicm 26483e83a91Snicm /* Initialize writing with a pane. */ 26583e83a91Snicm void 26683e83a91Snicm screen_write_start_pane(struct screen_write_ctx *ctx, struct window_pane *wp, 26783e83a91Snicm struct screen *s) 26883e83a91Snicm { 26983e83a91Snicm if (s == NULL) 27083e83a91Snicm s = wp->screen; 27183e83a91Snicm screen_write_init(ctx, s); 27283e83a91Snicm ctx->wp = wp; 2736d5c64a0Snicm 274aadd6faaSnicm if (log_get_level() != 0) { 275aadd6faaSnicm log_debug("%s: size %ux%u, pane %%%u (at %u,%u)", 27683e83a91Snicm __func__, screen_size_x(ctx->s), screen_size_y(ctx->s), 27783e83a91Snicm wp->id, wp->xoff, wp->yoff); 2787b470e93Snicm } 279aadd6faaSnicm } 28083e83a91Snicm 28183e83a91Snicm /* Initialize writing with a callback. */ 28283e83a91Snicm void 28383e83a91Snicm screen_write_start_callback(struct screen_write_ctx *ctx, struct screen *s, 28483e83a91Snicm screen_write_init_ctx_cb cb, void *arg) 28583e83a91Snicm { 28683e83a91Snicm screen_write_init(ctx, s); 28783e83a91Snicm 28883e83a91Snicm ctx->init_ctx_cb = cb; 28983e83a91Snicm ctx->arg = arg; 29083e83a91Snicm 29183e83a91Snicm if (log_get_level() != 0) { 29283e83a91Snicm log_debug("%s: size %ux%u, with callback", __func__, 29383e83a91Snicm screen_size_x(ctx->s), screen_size_y(ctx->s)); 29483e83a91Snicm } 29583e83a91Snicm } 29683e83a91Snicm 29783e83a91Snicm /* Initialize writing. */ 29883e83a91Snicm void 29983e83a91Snicm screen_write_start(struct screen_write_ctx *ctx, struct screen *s) 30083e83a91Snicm { 30183e83a91Snicm screen_write_init(ctx, s); 30283e83a91Snicm 30383e83a91Snicm if (log_get_level() != 0) { 30483e83a91Snicm log_debug("%s: size %ux%u, no pane", __func__, 30583e83a91Snicm screen_size_x(ctx->s), screen_size_y(ctx->s)); 30683e83a91Snicm } 307311827fbSnicm } 308311827fbSnicm 309311827fbSnicm /* Finish writing. */ 310311827fbSnicm void 3115fd00eceSnicm screen_write_stop(struct screen_write_ctx *ctx) 312311827fbSnicm { 3138248eab7Snicm screen_write_collect_end(ctx); 3149b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 3155fd00eceSnicm 3162612f635Snicm screen_write_free_citem(ctx->item); 317311827fbSnicm } 318311827fbSnicm 31952e27826Snicm /* Reset screen state. */ 32052e27826Snicm void 32152e27826Snicm screen_write_reset(struct screen_write_ctx *ctx) 32252e27826Snicm { 3233699ed24Snicm struct screen *s = ctx->s; 32452e27826Snicm 3253699ed24Snicm screen_reset_tabs(s); 3263699ed24Snicm screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1); 3276c0777c5Snicm 328d97b4537Snicm s->mode = MODE_CURSOR|MODE_WRAP; 329719f5715Snicm 330b514c1a1Snicm if (options_get_number(global_options, "extended-keys") == 2) 331719f5715Snicm s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED; 33252e27826Snicm 333ae4624e7Snicm screen_write_clearscreen(ctx, 8); 334ad47aa1bSnicm screen_write_set_cursor(ctx, 0, 0); 33552e27826Snicm } 33652e27826Snicm 337311827fbSnicm /* Write character. */ 338311827fbSnicm void 33919d1250cSnicm screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp, 340bfcd10e2Snicm u_char ch) 341311827fbSnicm { 34219d1250cSnicm struct grid_cell gc; 34319d1250cSnicm 34419d1250cSnicm memcpy(&gc, gcp, sizeof gc); 34519d1250cSnicm 34619d1250cSnicm utf8_set(&gc.data, ch); 34719d1250cSnicm screen_write_cell(ctx, &gc); 348311827fbSnicm } 349311827fbSnicm 350f89fbc24Snicm /* Calculate string length. */ 35174d4b937Snicm size_t 352f650d6adSnicm screen_write_strlen(const char *fmt, ...) 353f89fbc24Snicm { 354f89fbc24Snicm va_list ap; 355f89fbc24Snicm char *msg; 3569b3c9bc5Snicm struct utf8_data ud; 35740cac527Snicm u_char *ptr; 358f89fbc24Snicm size_t left, size = 0; 35939d4fc02Snicm enum utf8_state more; 360f89fbc24Snicm 361f89fbc24Snicm va_start(ap, fmt); 362f89fbc24Snicm xvasprintf(&msg, fmt, ap); 363f89fbc24Snicm va_end(ap); 364f89fbc24Snicm 365f89fbc24Snicm ptr = msg; 366f89fbc24Snicm while (*ptr != '\0') { 36739d4fc02Snicm if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) { 36840cac527Snicm ptr++; 369f89fbc24Snicm 370f89fbc24Snicm left = strlen(ptr); 371e931849fSnicm if (left < (size_t)ud.size - 1) 37240cac527Snicm break; 37339d4fc02Snicm while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE) 374f89fbc24Snicm ptr++; 37540cac527Snicm ptr++; 37640cac527Snicm 37739d4fc02Snicm if (more == UTF8_DONE) 3789b3c9bc5Snicm size += ud.width; 379f89fbc24Snicm } else { 380c851f995Snicm if (*ptr == '\t' || (*ptr > 0x1f && *ptr < 0x7f)) 381f89fbc24Snicm size++; 382f89fbc24Snicm ptr++; 383f89fbc24Snicm } 384f89fbc24Snicm } 385f89fbc24Snicm 3867d053cf9Snicm free(msg); 387f89fbc24Snicm return (size); 388f89fbc24Snicm } 389f89fbc24Snicm 39067c16a7cSnicm /* Write string wrapped over lines. */ 39167c16a7cSnicm int 39267c16a7cSnicm screen_write_text(struct screen_write_ctx *ctx, u_int cx, u_int width, 39367c16a7cSnicm u_int lines, int more, const struct grid_cell *gcp, const char *fmt, ...) 39467c16a7cSnicm { 39567c16a7cSnicm struct screen *s = ctx->s; 39667c16a7cSnicm va_list ap; 39767c16a7cSnicm char *tmp; 39867c16a7cSnicm u_int cy = s->cy, i, end, next, idx = 0, at, left; 39967c16a7cSnicm struct utf8_data *text; 40067c16a7cSnicm struct grid_cell gc; 40167c16a7cSnicm 40267c16a7cSnicm memcpy(&gc, gcp, sizeof gc); 40367c16a7cSnicm 40467c16a7cSnicm va_start(ap, fmt); 40567c16a7cSnicm xvasprintf(&tmp, fmt, ap); 40667c16a7cSnicm va_end(ap); 40767c16a7cSnicm 40867c16a7cSnicm text = utf8_fromcstr(tmp); 40967c16a7cSnicm free(tmp); 41067c16a7cSnicm 41167c16a7cSnicm left = (cx + width) - s->cx; 41267c16a7cSnicm for (;;) { 41367c16a7cSnicm /* Find the end of what can fit on the line. */ 41467c16a7cSnicm at = 0; 41567c16a7cSnicm for (end = idx; text[end].size != 0; end++) { 41667c16a7cSnicm if (text[end].size == 1 && text[end].data[0] == '\n') 41767c16a7cSnicm break; 41867c16a7cSnicm if (at + text[end].width > left) 41967c16a7cSnicm break; 42067c16a7cSnicm at += text[end].width; 42167c16a7cSnicm } 42267c16a7cSnicm 42367c16a7cSnicm /* 42467c16a7cSnicm * If we're on a space, that's the end. If not, walk back to 42567c16a7cSnicm * try and find one. 42667c16a7cSnicm */ 42767c16a7cSnicm if (text[end].size == 0) 42867c16a7cSnicm next = end; 42967c16a7cSnicm else if (text[end].size == 1 && text[end].data[0] == '\n') 43067c16a7cSnicm next = end + 1; 43167c16a7cSnicm else if (text[end].size == 1 && text[end].data[0] == ' ') 43267c16a7cSnicm next = end + 1; 43367c16a7cSnicm else { 43467c16a7cSnicm for (i = end; i > idx; i--) { 43567c16a7cSnicm if (text[i].size == 1 && text[i].data[0] == ' ') 43667c16a7cSnicm break; 43767c16a7cSnicm } 43867c16a7cSnicm if (i != idx) { 43967c16a7cSnicm next = i + 1; 44067c16a7cSnicm end = i; 44167c16a7cSnicm } else 44267c16a7cSnicm next = end; 44367c16a7cSnicm } 44467c16a7cSnicm 44567c16a7cSnicm /* Print the line. */ 44667c16a7cSnicm for (i = idx; i < end; i++) { 44767c16a7cSnicm utf8_copy(&gc.data, &text[i]); 44867c16a7cSnicm screen_write_cell(ctx, &gc); 44967c16a7cSnicm } 45067c16a7cSnicm 45167c16a7cSnicm /* If at the bottom, stop. */ 45267c16a7cSnicm idx = next; 45367c16a7cSnicm if (s->cy == cy + lines - 1 || text[idx].size == 0) 45467c16a7cSnicm break; 45567c16a7cSnicm 45667c16a7cSnicm screen_write_cursormove(ctx, cx, s->cy + 1, 0); 45767c16a7cSnicm left = width; 45867c16a7cSnicm } 45967c16a7cSnicm 46067c16a7cSnicm /* 46167c16a7cSnicm * Fail if on the last line and there is more to come or at the end, or 46267c16a7cSnicm * if the text was not entirely consumed. 46367c16a7cSnicm */ 46467c16a7cSnicm if ((s->cy == cy + lines - 1 && (!more || s->cx == cx + width)) || 46567c16a7cSnicm text[idx].size != 0) { 46667c16a7cSnicm free(text); 46767c16a7cSnicm return (0); 46867c16a7cSnicm } 46967c16a7cSnicm free(text); 47067c16a7cSnicm 47167c16a7cSnicm /* 47267c16a7cSnicm * If no more to come, move to the next line. Otherwise, leave on 47367c16a7cSnicm * the same line (except if at the end). 47467c16a7cSnicm */ 47567c16a7cSnicm if (!more || s->cx == cx + width) 47667c16a7cSnicm screen_write_cursormove(ctx, cx, s->cy + 1, 0); 47767c16a7cSnicm return (1); 47867c16a7cSnicm } 47967c16a7cSnicm 48067c16a7cSnicm /* Write simple string (no maximum length). */ 48174d4b937Snicm void 48219d1250cSnicm screen_write_puts(struct screen_write_ctx *ctx, const struct grid_cell *gcp, 48374d4b937Snicm const char *fmt, ...) 484311827fbSnicm { 485311827fbSnicm va_list ap; 486311827fbSnicm 487311827fbSnicm va_start(ap, fmt); 48819d1250cSnicm screen_write_vnputs(ctx, -1, gcp, fmt, ap); 489311827fbSnicm va_end(ap); 490f89fbc24Snicm } 491311827fbSnicm 492f89fbc24Snicm /* Write string with length limit (-1 for unlimited). */ 49374d4b937Snicm void 49474d4b937Snicm screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen, 49519d1250cSnicm const struct grid_cell *gcp, const char *fmt, ...) 496f89fbc24Snicm { 497f89fbc24Snicm va_list ap; 498f89fbc24Snicm 499f89fbc24Snicm va_start(ap, fmt); 50019d1250cSnicm screen_write_vnputs(ctx, maxlen, gcp, fmt, ap); 501f89fbc24Snicm va_end(ap); 502f89fbc24Snicm } 503f89fbc24Snicm 504f89fbc24Snicm void 505653bc467Snicm screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, 50619d1250cSnicm const struct grid_cell *gcp, const char *fmt, va_list ap) 507f89fbc24Snicm { 50819d1250cSnicm struct grid_cell gc; 50919d1250cSnicm struct utf8_data *ud = &gc.data; 510f89fbc24Snicm char *msg; 51140cac527Snicm u_char *ptr; 512f89fbc24Snicm size_t left, size = 0; 51339d4fc02Snicm enum utf8_state more; 514f89fbc24Snicm 51519d1250cSnicm memcpy(&gc, gcp, sizeof gc); 516f89fbc24Snicm xvasprintf(&msg, fmt, ap); 517f89fbc24Snicm 518f89fbc24Snicm ptr = msg; 519f89fbc24Snicm while (*ptr != '\0') { 52019d1250cSnicm if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) { 52140cac527Snicm ptr++; 522f89fbc24Snicm 523f89fbc24Snicm left = strlen(ptr); 52419d1250cSnicm if (left < (size_t)ud->size - 1) 52540cac527Snicm break; 52619d1250cSnicm while ((more = utf8_append(ud, *ptr)) == UTF8_MORE) 527f89fbc24Snicm ptr++; 52840cac527Snicm ptr++; 529f89fbc24Snicm 53019d1250cSnicm if (more != UTF8_DONE) 53119d1250cSnicm continue; 53219d1250cSnicm if (maxlen > 0 && size + ud->width > (size_t)maxlen) { 533f89fbc24Snicm while (size < (size_t)maxlen) { 53419d1250cSnicm screen_write_putc(ctx, &gc, ' '); 535f89fbc24Snicm size++; 536f89fbc24Snicm } 537f89fbc24Snicm break; 538f89fbc24Snicm } 53919d1250cSnicm size += ud->width; 54019d1250cSnicm screen_write_cell(ctx, &gc); 541f89fbc24Snicm } else { 5425af50dcaSnicm if (maxlen > 0 && size + 1 > (size_t)maxlen) 543f89fbc24Snicm break; 544f89fbc24Snicm 545be573e22Snicm if (*ptr == '\001') 54619d1250cSnicm gc.attr ^= GRID_ATTR_CHARSET; 5476523adafSnicm else if (*ptr == '\n') { 5486523adafSnicm screen_write_linefeed(ctx, 0, 8); 5496523adafSnicm screen_write_carriagereturn(ctx); 550c851f995Snicm } else if (*ptr == '\t' || (*ptr > 0x1f && *ptr < 0x7f)) { 551f89fbc24Snicm size++; 55219d1250cSnicm screen_write_putc(ctx, &gc, *ptr); 553be573e22Snicm } 554f89fbc24Snicm ptr++; 555f89fbc24Snicm } 556f89fbc24Snicm } 557311827fbSnicm 5587d053cf9Snicm free(msg); 559311827fbSnicm } 560311827fbSnicm 5616edce865Snicm /* 5624d951239Snicm * Copy from another screen but without the selection stuff. Assumes the target 5634d951239Snicm * region is already big enough. 5646edce865Snicm */ 5656edce865Snicm void 5666edce865Snicm screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, 5676edce865Snicm u_int px, u_int py, u_int nx, u_int ny) 5686edce865Snicm { 5696edce865Snicm struct screen *s = ctx->s; 57043ac8c28Snicm struct window_pane *wp = ctx->wp; 57143ac8c28Snicm struct tty_ctx ttyctx; 5726edce865Snicm struct grid *gd = src->grid; 5736edce865Snicm struct grid_cell gc; 57443ac8c28Snicm u_int xx, yy, cx = s->cx, cy = s->cy; 5756edce865Snicm 5766edce865Snicm if (nx == 0 || ny == 0) 5776edce865Snicm return; 5786edce865Snicm 5796edce865Snicm cy = s->cy; 5806edce865Snicm for (yy = py; yy < py + ny; yy++) { 58163c9949dSnicm if (yy >= gd->hsize + gd->sy) 58263c9949dSnicm break; 58343ac8c28Snicm s->cx = cx; 58443ac8c28Snicm if (wp != NULL) 58543ac8c28Snicm screen_write_initctx(ctx, &ttyctx, 0); 5866edce865Snicm for (xx = px; xx < px + nx; xx++) { 5877621e88fSnicm if (xx >= grid_get_line(gd, yy)->cellsize) 5886edce865Snicm break; 5896edce865Snicm grid_get_cell(gd, xx, yy, &gc); 590414c61adSnicm if (xx + gc.data.width > px + nx) 591414c61adSnicm break; 59243ac8c28Snicm grid_view_set_cell(ctx->s->grid, s->cx, s->cy, &gc); 59343ac8c28Snicm if (wp != NULL) { 59443ac8c28Snicm ttyctx.cell = &gc; 59543ac8c28Snicm tty_write(tty_cmd_cell, &ttyctx); 59643ac8c28Snicm ttyctx.ocx++; 5976edce865Snicm } 59843ac8c28Snicm s->cx++; 5996edce865Snicm } 60043ac8c28Snicm s->cy++; 60143ac8c28Snicm } 60243ac8c28Snicm 60343ac8c28Snicm s->cx = cx; 60443ac8c28Snicm s->cy = cy; 6056edce865Snicm } 6066edce865Snicm 607e340e6ccSnicm /* Select character set for drawing border lines. */ 608e340e6ccSnicm static void 609e340e6ccSnicm screen_write_box_border_set(enum box_lines lines, int cell_type, 610e340e6ccSnicm struct grid_cell *gc) 611e340e6ccSnicm { 612e340e6ccSnicm switch (lines) { 613e340e6ccSnicm case BOX_LINES_NONE: 614e340e6ccSnicm break; 615e340e6ccSnicm case BOX_LINES_DOUBLE: 616e340e6ccSnicm gc->attr &= ~GRID_ATTR_CHARSET; 617e340e6ccSnicm utf8_copy(&gc->data, tty_acs_double_borders(cell_type)); 618e340e6ccSnicm break; 619e340e6ccSnicm case BOX_LINES_HEAVY: 620e340e6ccSnicm gc->attr &= ~GRID_ATTR_CHARSET; 621e340e6ccSnicm utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type)); 622e340e6ccSnicm break; 623e340e6ccSnicm case BOX_LINES_ROUNDED: 624e340e6ccSnicm gc->attr &= ~GRID_ATTR_CHARSET; 625e340e6ccSnicm utf8_copy(&gc->data, tty_acs_rounded_borders(cell_type)); 626e340e6ccSnicm break; 627e340e6ccSnicm case BOX_LINES_SIMPLE: 628e340e6ccSnicm gc->attr &= ~GRID_ATTR_CHARSET; 629e340e6ccSnicm utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]); 630e340e6ccSnicm break; 631e340e6ccSnicm case BOX_LINES_PADDED: 632e340e6ccSnicm gc->attr &= ~GRID_ATTR_CHARSET; 633e340e6ccSnicm utf8_set(&gc->data, PADDED_BORDERS[cell_type]); 634e340e6ccSnicm break; 635e340e6ccSnicm case BOX_LINES_SINGLE: 636e340e6ccSnicm case BOX_LINES_DEFAULT: 637e340e6ccSnicm gc->attr |= GRID_ATTR_CHARSET; 638e340e6ccSnicm utf8_set(&gc->data, CELL_BORDERS[cell_type]); 639e340e6ccSnicm break; 640e340e6ccSnicm } 641e340e6ccSnicm } 642e340e6ccSnicm 643367b65a4Snicm /* Draw a horizontal line on screen. */ 644a42faf7dSnicm void 645e340e6ccSnicm screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right, 646e340e6ccSnicm enum box_lines lines, const struct grid_cell *border_gc) 647a42faf7dSnicm { 648a42faf7dSnicm struct screen *s = ctx->s; 649a42faf7dSnicm struct grid_cell gc; 650a42faf7dSnicm u_int cx, cy, i; 651a42faf7dSnicm 652a42faf7dSnicm cx = s->cx; 653a42faf7dSnicm cy = s->cy; 654a42faf7dSnicm 655e340e6ccSnicm if (border_gc != NULL) 656e340e6ccSnicm memcpy(&gc, border_gc, sizeof gc); 657e340e6ccSnicm else 658a42faf7dSnicm memcpy(&gc, &grid_default_cell, sizeof gc); 659a42faf7dSnicm gc.attr |= GRID_ATTR_CHARSET; 660a42faf7dSnicm 661e340e6ccSnicm if (left) 662e340e6ccSnicm screen_write_box_border_set(lines, CELL_LEFTJOIN, &gc); 663e340e6ccSnicm else 664e340e6ccSnicm screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); 665e340e6ccSnicm screen_write_cell(ctx, &gc); 666e340e6ccSnicm 667e340e6ccSnicm screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); 668a42faf7dSnicm for (i = 1; i < nx - 1; i++) 669e340e6ccSnicm screen_write_cell(ctx, &gc); 670e340e6ccSnicm 671e340e6ccSnicm if (right) 672e340e6ccSnicm screen_write_box_border_set(lines, CELL_RIGHTJOIN, &gc); 673e340e6ccSnicm else 674e340e6ccSnicm screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); 675e340e6ccSnicm screen_write_cell(ctx, &gc); 676a42faf7dSnicm 677ad47aa1bSnicm screen_write_set_cursor(ctx, cx, cy); 678a42faf7dSnicm } 679a42faf7dSnicm 6807e55262dSnicm /* Draw a vertical line on screen. */ 681367b65a4Snicm void 682367b65a4Snicm screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom) 683367b65a4Snicm { 684367b65a4Snicm struct screen *s = ctx->s; 685367b65a4Snicm struct grid_cell gc; 686367b65a4Snicm u_int cx, cy, i; 687367b65a4Snicm 688367b65a4Snicm cx = s->cx; 689367b65a4Snicm cy = s->cy; 690367b65a4Snicm 691367b65a4Snicm memcpy(&gc, &grid_default_cell, sizeof gc); 692367b65a4Snicm gc.attr |= GRID_ATTR_CHARSET; 693367b65a4Snicm 694367b65a4Snicm screen_write_putc(ctx, &gc, top ? 'w' : 'x'); 695367b65a4Snicm for (i = 1; i < ny - 1; i++) { 696ad47aa1bSnicm screen_write_set_cursor(ctx, cx, cy + i); 697367b65a4Snicm screen_write_putc(ctx, &gc, 'x'); 698367b65a4Snicm } 699ad47aa1bSnicm screen_write_set_cursor(ctx, cx, cy + ny - 1); 700367b65a4Snicm screen_write_putc(ctx, &gc, bottom ? 'v' : 'x'); 701367b65a4Snicm 702ad47aa1bSnicm screen_write_set_cursor(ctx, cx, cy); 703367b65a4Snicm } 704367b65a4Snicm 7053f2ec672Snicm /* Draw a menu on screen. */ 7063f2ec672Snicm void 707e340e6ccSnicm screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, int choice, 708e340e6ccSnicm enum box_lines lines, const struct grid_cell *menu_gc, 709e340e6ccSnicm const struct grid_cell *border_gc, const struct grid_cell *choice_gc) 7103f2ec672Snicm { 7113f2ec672Snicm struct screen *s = ctx->s; 71248a3a827Snicm struct grid_cell default_gc; 71348a3a827Snicm const struct grid_cell *gc = &default_gc; 714e340e6ccSnicm u_int cx, cy, i, j, width = menu->width; 715f05a5af3Snicm const char *name; 7163f2ec672Snicm 7173f2ec672Snicm cx = s->cx; 7183f2ec672Snicm cy = s->cy; 7193f2ec672Snicm 720e340e6ccSnicm memcpy(&default_gc, menu_gc, sizeof default_gc); 7213f2ec672Snicm 722e340e6ccSnicm screen_write_box(ctx, menu->width + 4, menu->count + 2, lines, 723e340e6ccSnicm border_gc, menu->title); 7243f2ec672Snicm 7253f2ec672Snicm for (i = 0; i < menu->count; i++) { 726f05a5af3Snicm name = menu->items[i].name; 727f05a5af3Snicm if (name == NULL) { 7283f2ec672Snicm screen_write_cursormove(ctx, cx, cy + 1 + i, 0); 72917d7ce67Snicm screen_write_hline(ctx, width + 4, 1, 1, lines, 73017d7ce67Snicm border_gc); 731e340e6ccSnicm continue; 732e340e6ccSnicm } 733e340e6ccSnicm 734f05a5af3Snicm if (choice >= 0 && i == (u_int)choice && *name != '-') 73548a3a827Snicm gc = choice_gc; 736e340e6ccSnicm 73717d7ce67Snicm screen_write_cursormove(ctx, cx + 1, cy + 1 + i, 0); 73817d7ce67Snicm for (j = 0; j < width + 2; j++) 73948a3a827Snicm screen_write_putc(ctx, gc, ' '); 740e340e6ccSnicm 7413f2ec672Snicm screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0); 742f05a5af3Snicm if (*name == '-') { 74348a3a827Snicm default_gc.attr |= GRID_ATTR_DIM; 744e340e6ccSnicm format_draw(ctx, gc, width, name + 1, NULL, 0); 74548a3a827Snicm default_gc.attr &= ~GRID_ATTR_DIM; 746e340e6ccSnicm continue; 7473f2ec672Snicm } 748e340e6ccSnicm 74919c94b00Snicm format_draw(ctx, gc, width, name, NULL, 0); 750e340e6ccSnicm gc = &default_gc; 7513f2ec672Snicm } 7523f2ec672Snicm 7533f2ec672Snicm screen_write_set_cursor(ctx, cx, cy); 7543f2ec672Snicm } 7553f2ec672Snicm 756a42faf7dSnicm /* Draw a box on screen. */ 757a42faf7dSnicm void 758ff8fb92bSnicm screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny, 759dad8e5c0Snicm enum box_lines lines, const struct grid_cell *gcp, const char *title) 760a42faf7dSnicm { 761a42faf7dSnicm struct screen *s = ctx->s; 762a42faf7dSnicm struct grid_cell gc; 763a42faf7dSnicm u_int cx, cy, i; 764a42faf7dSnicm 765a42faf7dSnicm cx = s->cx; 766a42faf7dSnicm cy = s->cy; 767a42faf7dSnicm 768ff8fb92bSnicm if (gcp != NULL) 769ff8fb92bSnicm memcpy(&gc, gcp, sizeof gc); 770ff8fb92bSnicm else 771a42faf7dSnicm memcpy(&gc, &grid_default_cell, sizeof gc); 772dad8e5c0Snicm 773a42faf7dSnicm gc.attr |= GRID_ATTR_CHARSET; 77433a1e283Snicm gc.flags |= GRID_FLAG_NOPALETTE; 775a42faf7dSnicm 776ccb627cdSnicm /* Draw top border */ 777dad8e5c0Snicm screen_write_box_border_set(lines, CELL_TOPLEFT, &gc); 778ccb627cdSnicm screen_write_cell(ctx, &gc); 779dad8e5c0Snicm screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); 780a42faf7dSnicm for (i = 1; i < nx - 1; i++) 781ccb627cdSnicm screen_write_cell(ctx, &gc); 782dad8e5c0Snicm screen_write_box_border_set(lines, CELL_TOPRIGHT, &gc); 783ccb627cdSnicm screen_write_cell(ctx, &gc); 784a42faf7dSnicm 785ccb627cdSnicm /* Draw bottom border */ 786ad47aa1bSnicm screen_write_set_cursor(ctx, cx, cy + ny - 1); 787dad8e5c0Snicm screen_write_box_border_set(lines, CELL_BOTTOMLEFT, &gc); 788ccb627cdSnicm screen_write_cell(ctx, &gc); 789dad8e5c0Snicm screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); 790a42faf7dSnicm for (i = 1; i < nx - 1; i++) 791ccb627cdSnicm screen_write_cell(ctx, &gc); 792dad8e5c0Snicm screen_write_box_border_set(lines, CELL_BOTTOMRIGHT, &gc); 793ccb627cdSnicm screen_write_cell(ctx, &gc); 794a42faf7dSnicm 795ccb627cdSnicm /* Draw sides */ 796dad8e5c0Snicm screen_write_box_border_set(lines, CELL_TOPBOTTOM, &gc); 797a42faf7dSnicm for (i = 1; i < ny - 1; i++) { 798ccb627cdSnicm /* left side */ 799ad47aa1bSnicm screen_write_set_cursor(ctx, cx, cy + i); 800ccb627cdSnicm screen_write_cell(ctx, &gc); 801ccb627cdSnicm /* right side */ 802ad47aa1bSnicm screen_write_set_cursor(ctx, cx + nx - 1, cy + i); 803ccb627cdSnicm screen_write_cell(ctx, &gc); 804a42faf7dSnicm } 805a42faf7dSnicm 806dad8e5c0Snicm if (title != NULL) { 807dad8e5c0Snicm gc.attr &= ~GRID_ATTR_CHARSET; 808dad8e5c0Snicm screen_write_cursormove(ctx, cx + 2, cy, 0); 809173e8225Snicm format_draw(ctx, &gc, nx - 4, title, NULL, 0); 810dad8e5c0Snicm } 811dad8e5c0Snicm 812ad47aa1bSnicm screen_write_set_cursor(ctx, cx, cy); 813a42faf7dSnicm } 814a42faf7dSnicm 8156edce865Snicm /* 8166edce865Snicm * Write a preview version of a window. Assumes target area is big enough and 8176edce865Snicm * already cleared. 8186edce865Snicm */ 819a42faf7dSnicm void 820a42faf7dSnicm screen_write_preview(struct screen_write_ctx *ctx, struct screen *src, u_int nx, 821a42faf7dSnicm u_int ny) 822a42faf7dSnicm { 823a42faf7dSnicm struct screen *s = ctx->s; 824a42faf7dSnicm struct grid_cell gc; 825a42faf7dSnicm u_int cx, cy, px, py; 826a42faf7dSnicm 827a42faf7dSnicm cx = s->cx; 828a42faf7dSnicm cy = s->cy; 829a42faf7dSnicm 830a42faf7dSnicm /* 831a42faf7dSnicm * If the cursor is on, pick the area around the cursor, otherwise use 832a42faf7dSnicm * the top left. 833a42faf7dSnicm */ 834a42faf7dSnicm if (src->mode & MODE_CURSOR) { 835a42faf7dSnicm px = src->cx; 836a42faf7dSnicm if (px < nx / 3) 837a42faf7dSnicm px = 0; 838a42faf7dSnicm else 839a42faf7dSnicm px = px - nx / 3; 840a42faf7dSnicm if (px + nx > screen_size_x(src)) { 841a42faf7dSnicm if (nx > screen_size_x(src)) 842a42faf7dSnicm px = 0; 843a42faf7dSnicm else 844a42faf7dSnicm px = screen_size_x(src) - nx; 845a42faf7dSnicm } 846a42faf7dSnicm py = src->cy; 847a42faf7dSnicm if (py < ny / 3) 848a42faf7dSnicm py = 0; 849a42faf7dSnicm else 850a42faf7dSnicm py = py - ny / 3; 851a42faf7dSnicm if (py + ny > screen_size_y(src)) { 852a42faf7dSnicm if (ny > screen_size_y(src)) 853a42faf7dSnicm py = 0; 854a42faf7dSnicm else 855a42faf7dSnicm py = screen_size_y(src) - ny; 856a42faf7dSnicm } 857a42faf7dSnicm } else { 858a42faf7dSnicm px = 0; 859a42faf7dSnicm py = 0; 860a42faf7dSnicm } 861a42faf7dSnicm 8626edce865Snicm screen_write_fast_copy(ctx, src, px, src->grid->hsize + py, nx, ny); 863a42faf7dSnicm 864a42faf7dSnicm if (src->mode & MODE_CURSOR) { 865a42faf7dSnicm grid_view_get_cell(src->grid, src->cx, src->cy, &gc); 866a42faf7dSnicm gc.attr |= GRID_ATTR_REVERSE; 867ad47aa1bSnicm screen_write_set_cursor(ctx, cx + (src->cx - px), 868a42faf7dSnicm cy + (src->cy - py)); 869a42faf7dSnicm screen_write_cell(ctx, &gc); 870a42faf7dSnicm } 871a42faf7dSnicm } 872a42faf7dSnicm 8733699ed24Snicm /* Set a mode. */ 8743699ed24Snicm void 8753699ed24Snicm screen_write_mode_set(struct screen_write_ctx *ctx, int mode) 8763699ed24Snicm { 8773699ed24Snicm struct screen *s = ctx->s; 8783699ed24Snicm 8793699ed24Snicm s->mode |= mode; 88026a875eaSnicm 88126a875eaSnicm if (log_get_level() != 0) 88226a875eaSnicm log_debug("%s: %s", __func__, screen_mode_to_string(mode)); 8833699ed24Snicm } 8843699ed24Snicm 8853699ed24Snicm /* Clear a mode. */ 8863699ed24Snicm void 8873699ed24Snicm screen_write_mode_clear(struct screen_write_ctx *ctx, int mode) 8883699ed24Snicm { 8893699ed24Snicm struct screen *s = ctx->s; 8903699ed24Snicm 8913699ed24Snicm s->mode &= ~mode; 89226a875eaSnicm 89326a875eaSnicm if (log_get_level() != 0) 89426a875eaSnicm log_debug("%s: %s", __func__, screen_mode_to_string(mode)); 8953699ed24Snicm } 8963699ed24Snicm 897311827fbSnicm /* Cursor up by ny. */ 898311827fbSnicm void 899311827fbSnicm screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny) 900311827fbSnicm { 901311827fbSnicm struct screen *s = ctx->s; 9027b470e93Snicm u_int cx = s->cx, cy = s->cy; 903311827fbSnicm 904311827fbSnicm if (ny == 0) 905311827fbSnicm ny = 1; 906311827fbSnicm 9077b470e93Snicm if (cy < s->rupper) { 9082a42fa53Snicm /* Above region. */ 9097b470e93Snicm if (ny > cy) 9107b470e93Snicm ny = cy; 9112a42fa53Snicm } else { 9122a42fa53Snicm /* Below region. */ 9137b470e93Snicm if (ny > cy - s->rupper) 9147b470e93Snicm ny = cy - s->rupper; 9152a42fa53Snicm } 9167b470e93Snicm if (cx == screen_size_x(s)) 9177b470e93Snicm cx--; 918311827fbSnicm 9197b470e93Snicm cy -= ny; 9207b470e93Snicm 9217b470e93Snicm screen_write_set_cursor(ctx, cx, cy); 922311827fbSnicm } 923311827fbSnicm 924311827fbSnicm /* Cursor down by ny. */ 925311827fbSnicm void 926311827fbSnicm screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny) 927311827fbSnicm { 928311827fbSnicm struct screen *s = ctx->s; 9297b470e93Snicm u_int cx = s->cx, cy = s->cy; 930311827fbSnicm 931311827fbSnicm if (ny == 0) 932311827fbSnicm ny = 1; 933311827fbSnicm 9347b470e93Snicm if (cy > s->rlower) { 9352a42fa53Snicm /* Below region. */ 9367b470e93Snicm if (ny > screen_size_y(s) - 1 - cy) 9377b470e93Snicm ny = screen_size_y(s) - 1 - cy; 9382a42fa53Snicm } else { 9392a42fa53Snicm /* Above region. */ 9407b470e93Snicm if (ny > s->rlower - cy) 9417b470e93Snicm ny = s->rlower - cy; 9422a42fa53Snicm } 9437b470e93Snicm if (cx == screen_size_x(s)) 9447b470e93Snicm cx--; 9457b470e93Snicm else if (ny == 0) 946311827fbSnicm return; 947311827fbSnicm 9487b470e93Snicm cy += ny; 9497b470e93Snicm 9507b470e93Snicm screen_write_set_cursor(ctx, cx, cy); 951311827fbSnicm } 952311827fbSnicm 953311827fbSnicm /* Cursor right by nx. */ 954311827fbSnicm void 955311827fbSnicm screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx) 956311827fbSnicm { 957311827fbSnicm struct screen *s = ctx->s; 9587b470e93Snicm u_int cx = s->cx, cy = s->cy; 959311827fbSnicm 960311827fbSnicm if (nx == 0) 961311827fbSnicm nx = 1; 962311827fbSnicm 9637b470e93Snicm if (nx > screen_size_x(s) - 1 - cx) 9647b470e93Snicm nx = screen_size_x(s) - 1 - cx; 965311827fbSnicm if (nx == 0) 966311827fbSnicm return; 967311827fbSnicm 9687b470e93Snicm cx += nx; 9697b470e93Snicm 9707b470e93Snicm screen_write_set_cursor(ctx, cx, cy); 971311827fbSnicm } 972311827fbSnicm 973311827fbSnicm /* Cursor left by nx. */ 974311827fbSnicm void 975311827fbSnicm screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx) 976311827fbSnicm { 977311827fbSnicm struct screen *s = ctx->s; 9787b470e93Snicm u_int cx = s->cx, cy = s->cy; 979311827fbSnicm 980311827fbSnicm if (nx == 0) 981311827fbSnicm nx = 1; 982311827fbSnicm 9837b470e93Snicm if (nx > cx) 9847b470e93Snicm nx = cx; 985311827fbSnicm if (nx == 0) 986311827fbSnicm return; 987311827fbSnicm 9887b470e93Snicm cx -= nx; 9897b470e93Snicm 9907b470e93Snicm screen_write_set_cursor(ctx, cx, cy); 991311827fbSnicm } 992311827fbSnicm 9936d20045fSnicm /* Backspace; cursor left unless at start of wrapped line when can move up. */ 9946d20045fSnicm void 9956d20045fSnicm screen_write_backspace(struct screen_write_ctx *ctx) 9966d20045fSnicm { 9976d20045fSnicm struct screen *s = ctx->s; 9986d20045fSnicm struct grid_line *gl; 9997b470e93Snicm u_int cx = s->cx, cy = s->cy; 10006d20045fSnicm 10017b470e93Snicm if (cx == 0) { 10027b470e93Snicm if (cy == 0) 10036d20045fSnicm return; 10047b470e93Snicm gl = grid_get_line(s->grid, s->grid->hsize + cy - 1); 10056d20045fSnicm if (gl->flags & GRID_LINE_WRAPPED) { 10067b470e93Snicm cy--; 10077b470e93Snicm cx = screen_size_x(s) - 1; 10086d20045fSnicm } 10096d20045fSnicm } else 10107b470e93Snicm cx--; 10117b470e93Snicm 10127b470e93Snicm screen_write_set_cursor(ctx, cx, cy); 10136d20045fSnicm } 10146d20045fSnicm 1015b18cc82cSnicm /* VT100 alignment test. */ 1016b18cc82cSnicm void 1017b18cc82cSnicm screen_write_alignmenttest(struct screen_write_ctx *ctx) 1018b18cc82cSnicm { 1019b18cc82cSnicm struct screen *s = ctx->s; 1020900b44f5Snicm struct tty_ctx ttyctx; 1021b18cc82cSnicm struct grid_cell gc; 1022b18cc82cSnicm u_int xx, yy; 1023b18cc82cSnicm 1024b18cc82cSnicm memcpy(&gc, &grid_default_cell, sizeof gc); 1025e931849fSnicm utf8_set(&gc.data, 'E'); 1026b18cc82cSnicm 1027b18cc82cSnicm for (yy = 0; yy < screen_size_y(s); yy++) { 1028b18cc82cSnicm for (xx = 0; xx < screen_size_x(s); xx++) 1029b18cc82cSnicm grid_view_set_cell(s->grid, xx, yy, &gc); 1030b18cc82cSnicm } 1031b18cc82cSnicm 10327b470e93Snicm screen_write_set_cursor(ctx, 0, 0); 1033b18cc82cSnicm 1034b18cc82cSnicm s->rupper = 0; 1035b18cc82cSnicm s->rlower = screen_size_y(s) - 1; 1036b18cc82cSnicm 10377f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 1); 1038e2755cc9Snicm 10398248eab7Snicm screen_write_collect_clear(ctx, 0, screen_size_y(s) - 1); 1040900b44f5Snicm tty_write(tty_cmd_alignmenttest, &ttyctx); 1041b18cc82cSnicm } 1042b18cc82cSnicm 1043311827fbSnicm /* Insert nx characters. */ 1044311827fbSnicm void 1045ae4624e7Snicm screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) 1046311827fbSnicm { 1047311827fbSnicm struct screen *s = ctx->s; 1048900b44f5Snicm struct tty_ctx ttyctx; 1049311827fbSnicm 1050311827fbSnicm if (nx == 0) 1051311827fbSnicm nx = 1; 1052311827fbSnicm 1053e12ac7a4Snicm if (nx > screen_size_x(s) - s->cx) 1054e12ac7a4Snicm nx = screen_size_x(s) - s->cx; 1055311827fbSnicm if (nx == 0) 1056311827fbSnicm return; 1057311827fbSnicm 10589c8da6a8Snicm if (s->cx > screen_size_x(s) - 1) 10599c8da6a8Snicm return; 10609c8da6a8Snicm 10617f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 0); 10629c8da6a8Snicm ttyctx.bg = bg; 1063311827fbSnicm 1064ae4624e7Snicm grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg); 1065311827fbSnicm 10669b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 1067900b44f5Snicm ttyctx.num = nx; 1068900b44f5Snicm tty_write(tty_cmd_insertcharacter, &ttyctx); 1069311827fbSnicm } 1070311827fbSnicm 1071311827fbSnicm /* Delete nx characters. */ 1072311827fbSnicm void 1073ae4624e7Snicm screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) 1074311827fbSnicm { 1075311827fbSnicm struct screen *s = ctx->s; 1076900b44f5Snicm struct tty_ctx ttyctx; 1077311827fbSnicm 1078311827fbSnicm if (nx == 0) 1079311827fbSnicm nx = 1; 1080311827fbSnicm 1081e12ac7a4Snicm if (nx > screen_size_x(s) - s->cx) 1082e12ac7a4Snicm nx = screen_size_x(s) - s->cx; 1083311827fbSnicm if (nx == 0) 1084311827fbSnicm return; 1085311827fbSnicm 10869c8da6a8Snicm if (s->cx > screen_size_x(s) - 1) 10879c8da6a8Snicm return; 10889c8da6a8Snicm 10897f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 0); 10909c8da6a8Snicm ttyctx.bg = bg; 1091311827fbSnicm 1092ae4624e7Snicm grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg); 1093311827fbSnicm 10949b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 1095900b44f5Snicm ttyctx.num = nx; 1096900b44f5Snicm tty_write(tty_cmd_deletecharacter, &ttyctx); 1097311827fbSnicm } 1098311827fbSnicm 1099f752bf02Snicm /* Clear nx characters. */ 1100f752bf02Snicm void 1101cf8e7221Snicm screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) 1102f752bf02Snicm { 1103f752bf02Snicm struct screen *s = ctx->s; 1104f752bf02Snicm struct tty_ctx ttyctx; 1105f752bf02Snicm 1106f752bf02Snicm if (nx == 0) 1107f752bf02Snicm nx = 1; 1108f752bf02Snicm 1109f752bf02Snicm if (nx > screen_size_x(s) - s->cx) 1110f752bf02Snicm nx = screen_size_x(s) - s->cx; 1111f752bf02Snicm if (nx == 0) 1112f752bf02Snicm return; 1113f752bf02Snicm 11149c8da6a8Snicm if (s->cx > screen_size_x(s) - 1) 11159c8da6a8Snicm return; 11169c8da6a8Snicm 11177f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 0); 1118cf8e7221Snicm ttyctx.bg = bg; 1119f752bf02Snicm 11205278aeaaSnicm grid_view_clear(s->grid, s->cx, s->cy, nx, 1, bg); 1121f752bf02Snicm 11229b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 1123f752bf02Snicm ttyctx.num = nx; 1124f752bf02Snicm tty_write(tty_cmd_clearcharacter, &ttyctx); 1125f752bf02Snicm } 1126f752bf02Snicm 1127311827fbSnicm /* Insert ny lines. */ 1128311827fbSnicm void 1129ae4624e7Snicm screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg) 1130311827fbSnicm { 1131311827fbSnicm struct screen *s = ctx->s; 11329c8da6a8Snicm struct grid *gd = s->grid; 1133900b44f5Snicm struct tty_ctx ttyctx; 1134311827fbSnicm 1135311827fbSnicm if (ny == 0) 1136311827fbSnicm ny = 1; 1137311827fbSnicm 1138a6133b88Snicm if (s->cy < s->rupper || s->cy > s->rlower) { 1139e12ac7a4Snicm if (ny > screen_size_y(s) - s->cy) 1140e12ac7a4Snicm ny = screen_size_y(s) - s->cy; 1141311827fbSnicm if (ny == 0) 1142311827fbSnicm return; 1143311827fbSnicm 11447f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 1); 11459c8da6a8Snicm ttyctx.bg = bg; 1146311827fbSnicm 11479c8da6a8Snicm grid_view_insert_lines(gd, s->cy, ny, bg); 1148a6133b88Snicm 11499b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 1150900b44f5Snicm ttyctx.num = ny; 1151900b44f5Snicm tty_write(tty_cmd_insertline, &ttyctx); 1152a6133b88Snicm return; 1153a6133b88Snicm } 1154a6133b88Snicm 1155a6133b88Snicm if (ny > s->rlower + 1 - s->cy) 1156a6133b88Snicm ny = s->rlower + 1 - s->cy; 1157a6133b88Snicm if (ny == 0) 1158a6133b88Snicm return; 1159a6133b88Snicm 11607f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 1); 11619c8da6a8Snicm ttyctx.bg = bg; 1162a6133b88Snicm 1163311827fbSnicm if (s->cy < s->rupper || s->cy > s->rlower) 11649c8da6a8Snicm grid_view_insert_lines(gd, s->cy, ny, bg); 11659c8da6a8Snicm else 11669c8da6a8Snicm grid_view_insert_lines_region(gd, s->rlower, s->cy, ny, bg); 1167311827fbSnicm 11689b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 11699b53212eSnicm 1170900b44f5Snicm ttyctx.num = ny; 1171900b44f5Snicm tty_write(tty_cmd_insertline, &ttyctx); 1172311827fbSnicm } 1173311827fbSnicm 1174311827fbSnicm /* Delete ny lines. */ 1175311827fbSnicm void 1176ae4624e7Snicm screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) 1177311827fbSnicm { 1178311827fbSnicm struct screen *s = ctx->s; 11799c8da6a8Snicm struct grid *gd = s->grid; 1180900b44f5Snicm struct tty_ctx ttyctx; 1181d2117533Snicm u_int sy = screen_size_y(s); 1182311827fbSnicm 1183311827fbSnicm if (ny == 0) 1184311827fbSnicm ny = 1; 1185311827fbSnicm 1186a6133b88Snicm if (s->cy < s->rupper || s->cy > s->rlower) { 1187d2117533Snicm if (ny > sy - s->cy) 1188d2117533Snicm ny = sy - s->cy; 1189311827fbSnicm if (ny == 0) 1190311827fbSnicm return; 1191311827fbSnicm 11927f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 1); 11939c8da6a8Snicm ttyctx.bg = bg; 1194311827fbSnicm 11959c8da6a8Snicm grid_view_delete_lines(gd, s->cy, ny, bg); 1196a6133b88Snicm 11979b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 1198900b44f5Snicm ttyctx.num = ny; 1199900b44f5Snicm tty_write(tty_cmd_deleteline, &ttyctx); 1200a6133b88Snicm return; 1201a6133b88Snicm } 1202a6133b88Snicm 1203a6133b88Snicm if (ny > s->rlower + 1 - s->cy) 1204a6133b88Snicm ny = s->rlower + 1 - s->cy; 1205a6133b88Snicm if (ny == 0) 1206a6133b88Snicm return; 1207a6133b88Snicm 12087f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 1); 12099c8da6a8Snicm ttyctx.bg = bg; 1210a6133b88Snicm 1211311827fbSnicm if (s->cy < s->rupper || s->cy > s->rlower) 12129c8da6a8Snicm grid_view_delete_lines(gd, s->cy, ny, bg); 12139c8da6a8Snicm else 12149c8da6a8Snicm grid_view_delete_lines_region(gd, s->rlower, s->cy, ny, bg); 1215311827fbSnicm 12169b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 1217900b44f5Snicm ttyctx.num = ny; 1218900b44f5Snicm tty_write(tty_cmd_deleteline, &ttyctx); 1219311827fbSnicm } 1220311827fbSnicm 1221311827fbSnicm /* Clear line at cursor. */ 1222311827fbSnicm void 1223ae4624e7Snicm screen_write_clearline(struct screen_write_ctx *ctx, u_int bg) 1224311827fbSnicm { 1225311827fbSnicm struct screen *s = ctx->s; 12265fd00eceSnicm struct grid_line *gl; 12275fd00eceSnicm u_int sx = screen_size_x(s); 12282612f635Snicm struct screen_write_citem *ci = ctx->item; 1229311827fbSnicm 12307621e88fSnicm gl = grid_get_line(s->grid, s->grid->hsize + s->cy); 1231d78fd057Snicm if (gl->cellsize == 0 && COLOUR_DEFAULT(bg)) 12325fd00eceSnicm return; 1233311827fbSnicm 1234ae4624e7Snicm grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); 1235ae4624e7Snicm 12368248eab7Snicm screen_write_collect_clear(ctx, s->cy, 1); 12372612f635Snicm ci->x = 0; 12382612f635Snicm ci->used = sx; 12392612f635Snicm ci->type = CLEAR; 12402612f635Snicm ci->bg = bg; 12412612f635Snicm TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry); 12422612f635Snicm ctx->item = screen_write_get_citem(); 1243311827fbSnicm } 1244311827fbSnicm 1245311827fbSnicm /* Clear to end of line from cursor. */ 1246311827fbSnicm void 1247ae4624e7Snicm screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg) 1248311827fbSnicm { 1249311827fbSnicm struct screen *s = ctx->s; 12505fd00eceSnicm struct grid_line *gl; 12515fd00eceSnicm u_int sx = screen_size_x(s); 12522612f635Snicm struct screen_write_citem *ci = ctx->item, *before; 12538b17a0f3Snicm 12548b17a0f3Snicm if (s->cx == 0) { 12558b17a0f3Snicm screen_write_clearline(ctx, bg); 12568b17a0f3Snicm return; 12578b17a0f3Snicm } 1258311827fbSnicm 12597621e88fSnicm gl = grid_get_line(s->grid, s->grid->hsize + s->cy); 1260d78fd057Snicm if (s->cx > sx - 1 || (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg))) 12615fd00eceSnicm return; 1262311827fbSnicm 1263ae4624e7Snicm grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg); 1264ae4624e7Snicm 12652612f635Snicm before = screen_write_collect_trim(ctx, s->cy, s->cx, sx - s->cx, NULL); 12668b17a0f3Snicm ci->x = s->cx; 12672612f635Snicm ci->used = sx - s->cx; 12682612f635Snicm ci->type = CLEAR; 12698b17a0f3Snicm ci->bg = bg; 12702612f635Snicm if (before == NULL) 127150376775Snicm TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry); 12722612f635Snicm else 12732612f635Snicm TAILQ_INSERT_BEFORE(before, ci, entry); 12742612f635Snicm ctx->item = screen_write_get_citem(); 12758b17a0f3Snicm } 1276311827fbSnicm 1277311827fbSnicm /* Clear to start of line from cursor. */ 1278311827fbSnicm void 1279ae4624e7Snicm screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg) 1280311827fbSnicm { 1281311827fbSnicm struct screen *s = ctx->s; 12825fd00eceSnicm u_int sx = screen_size_x(s); 12832612f635Snicm struct screen_write_citem *ci = ctx->item, *before; 12848b17a0f3Snicm 12858b17a0f3Snicm if (s->cx >= sx - 1) { 12868b17a0f3Snicm screen_write_clearline(ctx, bg); 12878b17a0f3Snicm return; 12888b17a0f3Snicm } 1289311827fbSnicm 12908248eab7Snicm if (s->cx > sx - 1) 1291ae4624e7Snicm grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); 12928248eab7Snicm else 1293ae4624e7Snicm grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg); 1294311827fbSnicm 12952612f635Snicm before = screen_write_collect_trim(ctx, s->cy, 0, s->cx + 1, NULL); 12962612f635Snicm ci->x = 0; 12972612f635Snicm ci->used = s->cx + 1; 12982612f635Snicm ci->type = CLEAR; 12998b17a0f3Snicm ci->bg = bg; 13002612f635Snicm if (before == NULL) 130150376775Snicm TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry); 13022612f635Snicm else 13032612f635Snicm TAILQ_INSERT_BEFORE(before, ci, entry); 13042612f635Snicm ctx->item = screen_write_get_citem(); 13058b17a0f3Snicm } 1306311827fbSnicm 1307311827fbSnicm /* Move cursor to px,py. */ 1308311827fbSnicm void 13095c6c7001Snicm screen_write_cursormove(struct screen_write_ctx *ctx, int px, int py, 13105c6c7001Snicm int origin) 1311311827fbSnicm { 1312311827fbSnicm struct screen *s = ctx->s; 1313311827fbSnicm 13145c6c7001Snicm if (origin && py != -1 && (s->mode & MODE_ORIGIN)) { 1315c15b2347Snicm if ((u_int)py > s->rlower - s->rupper) 1316ad47aa1bSnicm py = s->rlower; 1317ad47aa1bSnicm else 1318ad47aa1bSnicm py += s->rupper; 1319ad47aa1bSnicm } 1320311827fbSnicm 1321c15b2347Snicm if (px != -1 && (u_int)px > screen_size_x(s) - 1) 132294b5b5e9Snicm px = screen_size_x(s) - 1; 1323c15b2347Snicm if (py != -1 && (u_int)py > screen_size_y(s) - 1) 132494b5b5e9Snicm py = screen_size_y(s) - 1; 132594b5b5e9Snicm 13262612f635Snicm log_debug("%s: from %u,%u to %u,%u", __func__, s->cx, s->cy, px, py); 13277b470e93Snicm screen_write_set_cursor(ctx, px, py); 1328311827fbSnicm } 1329311827fbSnicm 1330311827fbSnicm /* Reverse index (up with scroll). */ 1331311827fbSnicm void 13326d5c64a0Snicm screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg) 1333311827fbSnicm { 1334311827fbSnicm struct screen *s = ctx->s; 1335900b44f5Snicm struct tty_ctx ttyctx; 1336311827fbSnicm 13378b17a0f3Snicm if (s->cy == s->rupper) { 13388b17a0f3Snicm grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg); 13398b17a0f3Snicm screen_write_collect_flush(ctx, 0, __func__); 13408b17a0f3Snicm 13417f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 1); 13426d5c64a0Snicm ttyctx.bg = bg; 1343311827fbSnicm 13448b17a0f3Snicm tty_write(tty_cmd_reverseindex, &ttyctx); 13458b17a0f3Snicm } else if (s->cy > 0) 13467b470e93Snicm screen_write_set_cursor(ctx, -1, s->cy - 1); 1347311827fbSnicm 1348311827fbSnicm } 1349311827fbSnicm 1350311827fbSnicm /* Set scroll region. */ 1351311827fbSnicm void 1352d5221700Snicm screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper, 1353d5221700Snicm u_int rlower) 1354311827fbSnicm { 1355311827fbSnicm struct screen *s = ctx->s; 1356311827fbSnicm 1357311827fbSnicm if (rupper > screen_size_y(s) - 1) 1358311827fbSnicm rupper = screen_size_y(s) - 1; 1359311827fbSnicm if (rlower > screen_size_y(s) - 1) 1360311827fbSnicm rlower = screen_size_y(s) - 1; 13613a129772Snicm if (rupper >= rlower) /* cannot be one line */ 1362311827fbSnicm return; 1363311827fbSnicm 13649b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 1365f0063641Snicm 1366311827fbSnicm /* Cursor moves to top-left. */ 13677b470e93Snicm screen_write_set_cursor(ctx, 0, 0); 1368311827fbSnicm 1369311827fbSnicm s->rupper = rupper; 1370311827fbSnicm s->rlower = rlower; 1371311827fbSnicm } 1372311827fbSnicm 1373cb3fa4d4Snicm /* Line feed. */ 1374311827fbSnicm void 13756d5c64a0Snicm screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg) 1376311827fbSnicm { 1377311827fbSnicm struct screen *s = ctx->s; 13788248eab7Snicm struct grid *gd = s->grid; 137917022a89Snicm struct grid_line *gl; 1380d2117533Snicm u_int rupper = s->rupper, rlower = s->rlower; 1381cb3fa4d4Snicm 13827621e88fSnicm gl = grid_get_line(gd, gd->hsize + s->cy); 138317022a89Snicm if (wrapped) 138417022a89Snicm gl->flags |= GRID_LINE_WRAPPED; 138517022a89Snicm 1386ddeb5b35Snicm log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, 1387d2117533Snicm rupper, rlower); 1388ddeb5b35Snicm 13896d5c64a0Snicm if (bg != ctx->bg) { 13909b53212eSnicm screen_write_collect_flush(ctx, 1, __func__); 13916d5c64a0Snicm ctx->bg = bg; 13926d5c64a0Snicm } 13936d5c64a0Snicm 13945fd00eceSnicm if (s->cy == s->rlower) { 13956d5c64a0Snicm grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); 13962612f635Snicm screen_write_collect_scroll(ctx, bg); 1397f0063641Snicm ctx->scrolled++; 13988248eab7Snicm } else if (s->cy < screen_size_y(s) - 1) 13997b470e93Snicm screen_write_set_cursor(ctx, -1, s->cy + 1); 1400311827fbSnicm } 1401311827fbSnicm 1402f0063641Snicm /* Scroll up. */ 1403f0063641Snicm void 14046d5c64a0Snicm screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg) 1405f0063641Snicm { 1406f0063641Snicm struct screen *s = ctx->s; 1407f0063641Snicm struct grid *gd = s->grid; 1408f0063641Snicm u_int i; 1409f0063641Snicm 1410f0063641Snicm if (lines == 0) 1411f0063641Snicm lines = 1; 1412f0063641Snicm else if (lines > s->rlower - s->rupper + 1) 1413f0063641Snicm lines = s->rlower - s->rupper + 1; 1414f0063641Snicm 14156d5c64a0Snicm if (bg != ctx->bg) { 14169b53212eSnicm screen_write_collect_flush(ctx, 1, __func__); 14176d5c64a0Snicm ctx->bg = bg; 14186d5c64a0Snicm } 14196d5c64a0Snicm 1420f0063641Snicm for (i = 0; i < lines; i++) { 14216d5c64a0Snicm grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); 14222612f635Snicm screen_write_collect_scroll(ctx, bg); 1423f0063641Snicm } 1424f0063641Snicm ctx->scrolled += lines; 1425f0063641Snicm } 1426f0063641Snicm 1427fa32c33cSnicm /* Scroll down. */ 1428fa32c33cSnicm void 1429fa32c33cSnicm screen_write_scrolldown(struct screen_write_ctx *ctx, u_int lines, u_int bg) 1430fa32c33cSnicm { 1431fa32c33cSnicm struct screen *s = ctx->s; 1432fa32c33cSnicm struct grid *gd = s->grid; 1433fa32c33cSnicm struct tty_ctx ttyctx; 1434fa32c33cSnicm u_int i; 1435fa32c33cSnicm 14367f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 1); 1437fa32c33cSnicm ttyctx.bg = bg; 1438fa32c33cSnicm 1439fa32c33cSnicm if (lines == 0) 1440fa32c33cSnicm lines = 1; 1441fa32c33cSnicm else if (lines > s->rlower - s->rupper + 1) 1442fa32c33cSnicm lines = s->rlower - s->rupper + 1; 1443fa32c33cSnicm 1444fa32c33cSnicm for (i = 0; i < lines; i++) 1445fa32c33cSnicm grid_view_scroll_region_down(gd, s->rupper, s->rlower, bg); 1446fa32c33cSnicm 14479b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 1448fa32c33cSnicm ttyctx.num = lines; 1449fa32c33cSnicm tty_write(tty_cmd_scrolldown, &ttyctx); 1450fa32c33cSnicm } 1451fa32c33cSnicm 1452311827fbSnicm /* Carriage return (cursor to start of line). */ 1453311827fbSnicm void 1454311827fbSnicm screen_write_carriagereturn(struct screen_write_ctx *ctx) 1455311827fbSnicm { 14567b470e93Snicm screen_write_set_cursor(ctx, 0, -1); 1457311827fbSnicm } 1458311827fbSnicm 1459311827fbSnicm /* Clear to end of screen from cursor. */ 1460311827fbSnicm void 1461ae4624e7Snicm screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg) 1462311827fbSnicm { 1463311827fbSnicm struct screen *s = ctx->s; 14649c8da6a8Snicm struct grid *gd = s->grid; 1465900b44f5Snicm struct tty_ctx ttyctx; 14665fd00eceSnicm u_int sx = screen_size_x(s), sy = screen_size_y(s); 1467311827fbSnicm 14687f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 1); 1469ae4624e7Snicm ttyctx.bg = bg; 1470311827fbSnicm 14710864dd21Snicm /* Scroll into history if it is enabled and clearing entire screen. */ 14725df43dd6Snicm if (s->cx == 0 && 14735df43dd6Snicm s->cy == 0 && 14745df43dd6Snicm (gd->flags & GRID_HISTORY) && 14755df43dd6Snicm ctx->wp != NULL && 14765df43dd6Snicm options_get_number(ctx->wp->options, "scroll-on-clear")) 14779c8da6a8Snicm grid_view_clear_history(gd, bg); 14788248eab7Snicm else { 14798248eab7Snicm if (s->cx <= sx - 1) 14809c8da6a8Snicm grid_view_clear(gd, s->cx, s->cy, sx - s->cx, 1, bg); 14819c8da6a8Snicm grid_view_clear(gd, 0, s->cy + 1, sx, sy - (s->cy + 1), bg); 14820864dd21Snicm } 1483311827fbSnicm 14848248eab7Snicm screen_write_collect_clear(ctx, s->cy + 1, sy - (s->cy + 1)); 14859b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 1486900b44f5Snicm tty_write(tty_cmd_clearendofscreen, &ttyctx); 1487311827fbSnicm } 1488311827fbSnicm 1489311827fbSnicm /* Clear to start of screen. */ 1490311827fbSnicm void 149192483283Snicm screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg) 1492311827fbSnicm { 1493311827fbSnicm struct screen *s = ctx->s; 1494900b44f5Snicm struct tty_ctx ttyctx; 14955fd00eceSnicm u_int sx = screen_size_x(s); 1496311827fbSnicm 14977f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 1); 149892483283Snicm ttyctx.bg = bg; 1499311827fbSnicm 15008248eab7Snicm if (s->cy > 0) 150192483283Snicm grid_view_clear(s->grid, 0, 0, sx, s->cy, bg); 15028248eab7Snicm if (s->cx > sx - 1) 1503cd8b1929Snicm grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); 15048248eab7Snicm else 1505cd8b1929Snicm grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg); 1506311827fbSnicm 15078248eab7Snicm screen_write_collect_clear(ctx, 0, s->cy); 15089b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 1509900b44f5Snicm tty_write(tty_cmd_clearstartofscreen, &ttyctx); 1510311827fbSnicm } 1511311827fbSnicm 1512311827fbSnicm /* Clear entire screen. */ 1513311827fbSnicm void 1514ae4624e7Snicm screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg) 1515311827fbSnicm { 1516311827fbSnicm struct screen *s = ctx->s; 1517900b44f5Snicm struct tty_ctx ttyctx; 15185fd00eceSnicm u_int sx = screen_size_x(s), sy = screen_size_y(s); 1519311827fbSnicm 15207f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 1); 1521ae4624e7Snicm ttyctx.bg = bg; 1522311827fbSnicm 15230864dd21Snicm /* Scroll into history if it is enabled. */ 152408dcff4bSnicm if ((s->grid->flags & GRID_HISTORY) && 152508dcff4bSnicm ctx->wp != NULL && 152608dcff4bSnicm options_get_number(ctx->wp->options, "scroll-on-clear")) 1527ae4624e7Snicm grid_view_clear_history(s->grid, bg); 1528d5221700Snicm else 1529ae4624e7Snicm grid_view_clear(s->grid, 0, 0, sx, sy, bg); 1530311827fbSnicm 15318248eab7Snicm screen_write_collect_clear(ctx, 0, sy); 1532900b44f5Snicm tty_write(tty_cmd_clearscreen, &ttyctx); 1533311827fbSnicm } 1534311827fbSnicm 1535786c44dcSnicm /* Clear entire history. */ 1536786c44dcSnicm void 1537786c44dcSnicm screen_write_clearhistory(struct screen_write_ctx *ctx) 1538786c44dcSnicm { 15399c5e7fb6Snicm grid_clear_history(ctx->s->grid); 1540786c44dcSnicm } 1541786c44dcSnicm 154233a1e283Snicm /* Force a full redraw. */ 154333a1e283Snicm void 154433a1e283Snicm screen_write_fullredraw(struct screen_write_ctx *ctx) 154533a1e283Snicm { 154633a1e283Snicm struct tty_ctx ttyctx; 154733a1e283Snicm 154833a1e283Snicm screen_write_collect_flush(ctx, 0, __func__); 154933a1e283Snicm 155033a1e283Snicm screen_write_initctx(ctx, &ttyctx, 1); 1551924a158aSnicm if (ttyctx.redraw_cb != NULL) 155233a1e283Snicm ttyctx.redraw_cb(&ttyctx); 155333a1e283Snicm } 155433a1e283Snicm 15552612f635Snicm /* Trim collected items. */ 15562612f635Snicm static struct screen_write_citem * 15572612f635Snicm screen_write_collect_trim(struct screen_write_ctx *ctx, u_int y, u_int x, 15582612f635Snicm u_int used, int *wrapped) 15598b17a0f3Snicm { 15602612f635Snicm struct screen_write_cline *cl = &ctx->s->write_list[y]; 15612612f635Snicm struct screen_write_citem *ci, *ci2, *tmp, *before = NULL; 15622612f635Snicm u_int sx = x, ex = x + used - 1; 15632612f635Snicm u_int csx, cex; 15648b17a0f3Snicm 15652612f635Snicm if (TAILQ_EMPTY(&cl->items)) 15662612f635Snicm return (NULL); 15672612f635Snicm TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { 15682612f635Snicm csx = ci->x; 15692612f635Snicm cex = ci->x + ci->used - 1; 15702612f635Snicm 15712612f635Snicm /* Item is entirely before. */ 15722612f635Snicm if (cex < sx) { 15732612f635Snicm log_debug("%s: %p %u-%u before %u-%u", __func__, ci, 15742612f635Snicm csx, cex, sx, ex); 15758b17a0f3Snicm continue; 15768b17a0f3Snicm } 15778b17a0f3Snicm 15782612f635Snicm /* Item is entirely after. */ 15792612f635Snicm if (csx > ex) { 15802612f635Snicm log_debug("%s: %p %u-%u after %u-%u", __func__, ci, 15812612f635Snicm csx, cex, sx, ex); 15822612f635Snicm before = ci; 15832612f635Snicm break; 15842612f635Snicm } 15858b17a0f3Snicm 15862612f635Snicm /* Item is entirely inside. */ 15872612f635Snicm if (csx >= sx && cex <= ex) { 15882612f635Snicm log_debug("%s: %p %u-%u inside %u-%u", __func__, ci, 15892612f635Snicm csx, cex, sx, ex); 15902612f635Snicm TAILQ_REMOVE(&cl->items, ci, entry); 15912612f635Snicm screen_write_free_citem(ci); 15922612f635Snicm if (csx == 0 && ci->wrapped && wrapped != NULL) 15932612f635Snicm *wrapped = 1; 15948b17a0f3Snicm continue; 15952612f635Snicm } 15962612f635Snicm 15972612f635Snicm /* Item under the start. */ 15982612f635Snicm if (csx < sx && cex >= sx && cex <= ex) { 15992612f635Snicm log_debug("%s: %p %u-%u start %u-%u", __func__, ci, 16002612f635Snicm csx, cex, sx, ex); 16012612f635Snicm ci->used = sx - csx; 16022612f635Snicm log_debug("%s: %p now %u-%u", __func__, ci, ci->x, 16032612f635Snicm ci->x + ci->used + 1); 16048b17a0f3Snicm continue; 16052612f635Snicm } 16062612f635Snicm 16072612f635Snicm /* Item covers the end. */ 16082612f635Snicm if (cex > ex && csx >= sx && csx <= ex) { 16092612f635Snicm log_debug("%s: %p %u-%u end %u-%u", __func__, ci, 16102612f635Snicm csx, cex, sx, ex); 16112612f635Snicm ci->x = ex + 1; 16122612f635Snicm ci->used = cex - ex; 16132612f635Snicm log_debug("%s: %p now %u-%u", __func__, ci, ci->x, 16142612f635Snicm ci->x + ci->used + 1); 16152612f635Snicm before = ci; 16168b17a0f3Snicm break; 16178b17a0f3Snicm } 16182612f635Snicm 16192612f635Snicm /* Item must cover both sides. */ 16202612f635Snicm log_debug("%s: %p %u-%u under %u-%u", __func__, ci, 16212612f635Snicm csx, cex, sx, ex); 16222612f635Snicm ci2 = screen_write_get_citem(); 16232612f635Snicm ci2->type = ci->type; 16242612f635Snicm ci2->bg = ci->bg; 16252612f635Snicm memcpy(&ci2->gc, &ci->gc, sizeof ci2->gc); 16262612f635Snicm TAILQ_INSERT_AFTER(&cl->items, ci, ci2, entry); 16272612f635Snicm 16282612f635Snicm ci->used = sx - csx; 16292612f635Snicm ci2->x = ex + 1; 16302612f635Snicm ci2->used = cex - ex; 16312612f635Snicm 16322612f635Snicm log_debug("%s: %p now %u-%u (%p) and %u-%u (%p)", __func__, ci, 16332612f635Snicm ci->x, ci->x + ci->used - 1, ci, ci2->x, 16342612f635Snicm ci2->x + ci2->used - 1, ci2); 16352612f635Snicm before = ci2; 16362612f635Snicm break; 16378b17a0f3Snicm } 16382612f635Snicm return (before); 16398b17a0f3Snicm } 16408b17a0f3Snicm 1641977b6338Snicm /* Clear collected lines. */ 16428248eab7Snicm static void 16438248eab7Snicm screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n) 16448248eab7Snicm { 16452612f635Snicm struct screen_write_cline *cl; 16462612f635Snicm u_int i; 16478248eab7Snicm 16488248eab7Snicm for (i = y; i < y + n; i++) { 164950376775Snicm cl = &ctx->s->write_list[i]; 16502612f635Snicm TAILQ_CONCAT(&screen_write_citem_freelist, &cl->items, entry); 16518248eab7Snicm } 16528248eab7Snicm } 16538248eab7Snicm 16548248eab7Snicm /* Scroll collected lines up. */ 16558248eab7Snicm static void 16562612f635Snicm screen_write_collect_scroll(struct screen_write_ctx *ctx, u_int bg) 16578248eab7Snicm { 16588248eab7Snicm struct screen *s = ctx->s; 16592612f635Snicm struct screen_write_cline *cl; 16608248eab7Snicm u_int y; 1661977b6338Snicm char *saved; 16622612f635Snicm struct screen_write_citem *ci; 16638248eab7Snicm 1664ddeb5b35Snicm log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, 1665ddeb5b35Snicm s->rupper, s->rlower); 1666ddeb5b35Snicm 16678248eab7Snicm screen_write_collect_clear(ctx, s->rupper, 1); 166850376775Snicm saved = ctx->s->write_list[s->rupper].data; 16698248eab7Snicm for (y = s->rupper; y < s->rlower; y++) { 167050376775Snicm cl = &ctx->s->write_list[y + 1]; 167150376775Snicm TAILQ_CONCAT(&ctx->s->write_list[y].items, &cl->items, entry); 167250376775Snicm ctx->s->write_list[y].data = cl->data; 16738248eab7Snicm } 1674208fe07fSnicm ctx->s->write_list[s->rlower].data = saved; 16752612f635Snicm 16762612f635Snicm ci = screen_write_get_citem(); 16772612f635Snicm ci->x = 0; 16782612f635Snicm ci->used = screen_size_x(s); 16792612f635Snicm ci->type = CLEAR; 16802612f635Snicm ci->bg = bg; 16812612f635Snicm TAILQ_INSERT_TAIL(&ctx->s->write_list[s->rlower].items, ci, entry); 16828248eab7Snicm } 16838248eab7Snicm 16848248eab7Snicm /* Flush collected lines. */ 16858248eab7Snicm static void 16869b53212eSnicm screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, 16879b53212eSnicm const char *from) 16888248eab7Snicm { 16898248eab7Snicm struct screen *s = ctx->s; 16902612f635Snicm struct screen_write_citem *ci, *tmp; 16912612f635Snicm struct screen_write_cline *cl; 16922612f635Snicm u_int y, cx, cy, last, items = 0; 16938248eab7Snicm struct tty_ctx ttyctx; 16948248eab7Snicm 1695f0063641Snicm if (ctx->scrolled != 0) { 1696f0063641Snicm log_debug("%s: scrolled %u (region %u-%u)", __func__, 1697f0063641Snicm ctx->scrolled, s->rupper, s->rlower); 1698f0063641Snicm if (ctx->scrolled > s->rlower - s->rupper + 1) 1699f0063641Snicm ctx->scrolled = s->rlower - s->rupper + 1; 1700f0063641Snicm 17017f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 1); 1702f0063641Snicm ttyctx.num = ctx->scrolled; 17036d5c64a0Snicm ttyctx.bg = ctx->bg; 1704f0063641Snicm tty_write(tty_cmd_scrollup, &ttyctx); 1705d2117533Snicm 1706d2117533Snicm if (ctx->wp != NULL) 1707d2117533Snicm ctx->wp->flags |= PANE_REDRAWSCROLLBAR; 1708f0063641Snicm } 1709f0063641Snicm ctx->scrolled = 0; 17106d5c64a0Snicm ctx->bg = 8; 17116d5c64a0Snicm 171246b92e93Snicm if (scroll_only) 171346b92e93Snicm return; 1714f0063641Snicm 17158248eab7Snicm cx = s->cx; cy = s->cy; 17168248eab7Snicm for (y = 0; y < screen_size_y(s); y++) { 171750376775Snicm cl = &ctx->s->write_list[y]; 17182612f635Snicm last = UINT_MAX; 1719a6b857afSnicm TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { 17202612f635Snicm if (last != UINT_MAX && ci->x <= last) { 17212612f635Snicm fatalx("collect list not in order: %u <= %u", 17222612f635Snicm ci->x, last); 17232612f635Snicm } 1724ad47aa1bSnicm screen_write_set_cursor(ctx, ci->x, y); 17252612f635Snicm if (ci->type == CLEAR) { 1726999176b1Snicm screen_write_initctx(ctx, &ttyctx, 1); 17278b17a0f3Snicm ttyctx.bg = ci->bg; 17282612f635Snicm ttyctx.num = ci->used; 17292612f635Snicm tty_write(tty_cmd_clearcharacter, &ttyctx); 17308b17a0f3Snicm } else { 1731999176b1Snicm screen_write_initctx(ctx, &ttyctx, 0); 17328248eab7Snicm ttyctx.cell = &ci->gc; 1733566401c6Snicm ttyctx.wrapped = ci->wrapped; 173450376775Snicm ttyctx.ptr = cl->data + ci->x; 17358248eab7Snicm ttyctx.num = ci->used; 17368248eab7Snicm tty_write(tty_cmd_cells, &ttyctx); 17378b17a0f3Snicm } 17382601a058Snicm items++; 17398248eab7Snicm 174050376775Snicm TAILQ_REMOVE(&cl->items, ci, entry); 17412612f635Snicm screen_write_free_citem(ci); 17422612f635Snicm last = ci->x; 17438248eab7Snicm } 17448248eab7Snicm } 17458248eab7Snicm s->cx = cx; s->cy = cy; 17462601a058Snicm 17472612f635Snicm log_debug("%s: flushed %u items (%s)", __func__, items, from); 17488248eab7Snicm } 17498248eab7Snicm 17508248eab7Snicm /* Finish and store collected cells. */ 17518248eab7Snicm void 17528248eab7Snicm screen_write_collect_end(struct screen_write_ctx *ctx) 17538248eab7Snicm { 17548248eab7Snicm struct screen *s = ctx->s; 17552612f635Snicm struct screen_write_citem *ci = ctx->item, *before; 17562612f635Snicm struct screen_write_cline *cl = &s->write_list[s->cy]; 17578248eab7Snicm struct grid_cell gc; 1758856ed6d3Snicm u_int xx; 17592612f635Snicm int wrapped = ci->wrapped; 17608248eab7Snicm 17618248eab7Snicm if (ci->used == 0) 17628248eab7Snicm return; 17638248eab7Snicm 17642612f635Snicm before = screen_write_collect_trim(ctx, s->cy, s->cx, ci->used, 17652612f635Snicm &wrapped); 17668248eab7Snicm ci->x = s->cx; 17672612f635Snicm ci->wrapped = wrapped; 17682612f635Snicm if (before == NULL) 176950376775Snicm TAILQ_INSERT_TAIL(&cl->items, ci, entry); 17702612f635Snicm else 17712612f635Snicm TAILQ_INSERT_BEFORE(before, ci, entry); 17722612f635Snicm ctx->item = screen_write_get_citem(); 17738248eab7Snicm 1774977b6338Snicm log_debug("%s: %u %.*s (at %u,%u)", __func__, ci->used, 177550376775Snicm (int)ci->used, cl->data + ci->x, s->cx, s->cy); 17768248eab7Snicm 1777856ed6d3Snicm if (s->cx != 0) { 1778856ed6d3Snicm for (xx = s->cx; xx > 0; xx--) { 1779856ed6d3Snicm grid_view_get_cell(s->grid, xx, s->cy, &gc); 1780856ed6d3Snicm if (~gc.flags & GRID_FLAG_PADDING) 1781856ed6d3Snicm break; 17821e84472bSnicm grid_view_set_cell(s->grid, xx, s->cy, 17831e84472bSnicm &grid_default_cell); 1784856ed6d3Snicm } 17857b470e93Snicm if (gc.data.width > 1) { 17861e84472bSnicm grid_view_set_cell(s->grid, xx, s->cy, 17871e84472bSnicm &grid_default_cell); 1788856ed6d3Snicm } 17897b470e93Snicm } 1790856ed6d3Snicm 179150376775Snicm grid_view_set_cells(s->grid, s->cx, s->cy, &ci->gc, cl->data + ci->x, 179250376775Snicm ci->used); 17937b470e93Snicm screen_write_set_cursor(ctx, s->cx + ci->used, -1); 1794856ed6d3Snicm 1795856ed6d3Snicm for (xx = s->cx; xx < screen_size_x(s); xx++) { 1796856ed6d3Snicm grid_view_get_cell(s->grid, xx, s->cy, &gc); 1797856ed6d3Snicm if (~gc.flags & GRID_FLAG_PADDING) 1798856ed6d3Snicm break; 1799856ed6d3Snicm grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); 1800856ed6d3Snicm } 18018248eab7Snicm } 18028248eab7Snicm 18038248eab7Snicm /* Write cell data, collecting if necessary. */ 18048248eab7Snicm void 18058248eab7Snicm screen_write_collect_add(struct screen_write_ctx *ctx, 18068248eab7Snicm const struct grid_cell *gc) 18078248eab7Snicm { 18088248eab7Snicm struct screen *s = ctx->s; 18092612f635Snicm struct screen_write_citem *ci; 18108248eab7Snicm u_int sx = screen_size_x(s); 18118248eab7Snicm int collect; 18128248eab7Snicm 18138248eab7Snicm /* 18148248eab7Snicm * Don't need to check that the attributes and whatnot are still the 18152601a058Snicm * same - input_parse will end the collection when anything that isn't 181626a51baaSnicm * a plain character is encountered. 18178248eab7Snicm */ 18188248eab7Snicm 18198248eab7Snicm collect = 1; 18201e84472bSnicm if (gc->data.width != 1 || gc->data.size != 1 || *gc->data.data >= 0x7f) 18218248eab7Snicm collect = 0; 182202d75531Snicm else if (gc->flags & GRID_FLAG_TAB) 182302d75531Snicm collect = 0; 18248248eab7Snicm else if (gc->attr & GRID_ATTR_CHARSET) 18258248eab7Snicm collect = 0; 18268248eab7Snicm else if (~s->mode & MODE_WRAP) 18278248eab7Snicm collect = 0; 18288248eab7Snicm else if (s->mode & MODE_INSERT) 18298248eab7Snicm collect = 0; 18303f2a5436Snicm else if (s->sel != NULL) 18318248eab7Snicm collect = 0; 18328248eab7Snicm if (!collect) { 18338248eab7Snicm screen_write_collect_end(ctx); 18349b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 18358248eab7Snicm screen_write_cell(ctx, gc); 18368248eab7Snicm return; 18378248eab7Snicm } 18388248eab7Snicm 18398248eab7Snicm if (s->cx > sx - 1 || ctx->item->used > sx - 1 - s->cx) 18408248eab7Snicm screen_write_collect_end(ctx); 1841566401c6Snicm ci = ctx->item; /* may have changed */ 1842566401c6Snicm 18438248eab7Snicm if (s->cx > sx - 1) { 1844ddeb5b35Snicm log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy); 1845566401c6Snicm ci->wrapped = 1; 18466d5c64a0Snicm screen_write_linefeed(ctx, 1, 8); 18477b470e93Snicm screen_write_set_cursor(ctx, 0, -1); 18488248eab7Snicm } 18498248eab7Snicm 18508248eab7Snicm if (ci->used == 0) 18518248eab7Snicm memcpy(&ci->gc, gc, sizeof ci->gc); 185250376775Snicm if (ctx->s->write_list[s->cy].data == NULL) 185350376775Snicm ctx->s->write_list[s->cy].data = xmalloc(screen_size_x(ctx->s)); 185450376775Snicm ctx->s->write_list[s->cy].data[s->cx + ci->used++] = gc->data.data[0]; 18558248eab7Snicm } 18568248eab7Snicm 1857311827fbSnicm /* Write cell data. */ 1858311827fbSnicm void 1859e031297fSnicm screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) 1860311827fbSnicm { 1861311827fbSnicm struct screen *s = ctx->s; 1862311827fbSnicm struct grid *gd = s->grid; 18632af49740Snicm const struct utf8_data *ud = &gc->data; 18645fd00eceSnicm struct grid_line *gl; 18655fd00eceSnicm struct grid_cell_entry *gce; 18668248eab7Snicm struct grid_cell tmp_gc, now_gc; 18678248eab7Snicm struct tty_ctx ttyctx; 18688248eab7Snicm u_int sx = screen_size_x(s), sy = screen_size_y(s); 18692af49740Snicm u_int width = ud->width, xx, not_wrap; 18708248eab7Snicm int selected, skip = 1; 18715fd00eceSnicm 18728248eab7Snicm /* Ignore padding cells. */ 1873311827fbSnicm if (gc->flags & GRID_FLAG_PADDING) 1874311827fbSnicm return; 1875311827fbSnicm 18762af49740Snicm /* Get the previous cell to check for combining. */ 18772af49740Snicm if (screen_write_combine(ctx, gc) != 0) 187847287340Snicm return; 1879311827fbSnicm 188030133c68Snicm /* Flush any existing scrolling. */ 18819b53212eSnicm screen_write_collect_flush(ctx, 1, __func__); 188230133c68Snicm 18838248eab7Snicm /* If this character doesn't fit, ignore it. */ 18848248eab7Snicm if ((~s->mode & MODE_WRAP) && 18858248eab7Snicm width > 1 && 18868248eab7Snicm (width > sx || (s->cx != sx && s->cx > sx - width))) 18878248eab7Snicm return; 18888248eab7Snicm 18897bd6086bSnicm /* If in insert mode, make space for the cells. */ 18908368ee61Snicm if (s->mode & MODE_INSERT) { 18918248eab7Snicm grid_view_insert_cells(s->grid, s->cx, s->cy, width, 8); 18928248eab7Snicm skip = 0; 18938368ee61Snicm } 18947bd6086bSnicm 189517022a89Snicm /* Check this will fit on the current line and wrap if not. */ 18965fd00eceSnicm if ((s->mode & MODE_WRAP) && s->cx > sx - width) { 18976204dbd8Snicm log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy); 18986d5c64a0Snicm screen_write_linefeed(ctx, 1, 8); 18997b470e93Snicm screen_write_set_cursor(ctx, 0, -1); 19009b53212eSnicm screen_write_collect_flush(ctx, 1, __func__); 1901311827fbSnicm } 1902311827fbSnicm 190384c47e4aSnicm /* Sanity check cursor position. */ 19045fd00eceSnicm if (s->cx > sx - width || s->cy > sy - 1) 1905311827fbSnicm return; 19067f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 0); 1907be47f69aSnicm 1908311827fbSnicm /* Handle overwriting of UTF-8 characters. */ 19097621e88fSnicm gl = grid_get_line(s->grid, s->grid->hsize + s->cy); 19105fd00eceSnicm if (gl->flags & GRID_LINE_EXTENDED) { 19118e39655fSnicm grid_view_get_cell(gd, s->cx, s->cy, &now_gc); 19128e39655fSnicm if (screen_write_overwrite(ctx, &now_gc, width)) 19138e39655fSnicm skip = 0; 19145fd00eceSnicm } 1915311827fbSnicm 1916311827fbSnicm /* 1917311827fbSnicm * If the new character is UTF-8 wide, fill in padding cells. Have 1918311827fbSnicm * already ensured there is enough room. 1919311827fbSnicm */ 19208e39655fSnicm for (xx = s->cx + 1; xx < s->cx + width; xx++) { 1921856ed6d3Snicm log_debug("%s: new padding at %u,%u", __func__, xx, s->cy); 192271a06389Snicm grid_view_set_padding(gd, xx, s->cy); 19238e39655fSnicm skip = 0; 19248e39655fSnicm } 19258e39655fSnicm 19268e39655fSnicm /* If no change, do not draw. */ 19275fd00eceSnicm if (skip) { 19285fd00eceSnicm if (s->cx >= gl->cellsize) 19295fd00eceSnicm skip = grid_cells_equal(gc, &grid_default_cell); 19305fd00eceSnicm else { 19315fd00eceSnicm gce = &gl->celldata[s->cx]; 19325fd00eceSnicm if (gce->flags & GRID_FLAG_EXTENDED) 19335fd00eceSnicm skip = 0; 193468347226Snicm else if (gc->flags != gce->flags) 19355fd00eceSnicm skip = 0; 19365fd00eceSnicm else if (gc->attr != gce->data.attr) 19375fd00eceSnicm skip = 0; 19385fd00eceSnicm else if (gc->fg != gce->data.fg) 19395fd00eceSnicm skip = 0; 19405fd00eceSnicm else if (gc->bg != gce->data.bg) 19415fd00eceSnicm skip = 0; 194268347226Snicm else if (gc->data.width != 1) 194368347226Snicm skip = 0; 19448248eab7Snicm else if (gc->data.size != 1) 19458248eab7Snicm skip = 0; 194668347226Snicm else if (gce->data.data != gc->data.data[0]) 19475fd00eceSnicm skip = 0; 19485fd00eceSnicm } 19495fd00eceSnicm } 1950311827fbSnicm 19514d4d49acSnicm /* Update the selected flag and set the cell. */ 1952bc1b8712Snicm selected = screen_check_selection(s, s->cx, s->cy); 19538248eab7Snicm if (selected && (~gc->flags & GRID_FLAG_SELECTED)) { 1954bc1b8712Snicm memcpy(&tmp_gc, gc, sizeof tmp_gc); 1955bc1b8712Snicm tmp_gc.flags |= GRID_FLAG_SELECTED; 1956bc1b8712Snicm grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); 19578248eab7Snicm } else if (!selected && (gc->flags & GRID_FLAG_SELECTED)) { 1958bc1b8712Snicm memcpy(&tmp_gc, gc, sizeof tmp_gc); 1959bc1b8712Snicm tmp_gc.flags &= ~GRID_FLAG_SELECTED; 1960bc1b8712Snicm grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); 1961bc1b8712Snicm } else if (!skip) 1962311827fbSnicm grid_view_set_cell(gd, s->cx, s->cy, gc); 19638248eab7Snicm if (selected) 19648248eab7Snicm skip = 0; 1965311827fbSnicm 196684c47e4aSnicm /* 196784c47e4aSnicm * Move the cursor. If not wrapping, stick at the last character and 196884c47e4aSnicm * replace it. 196984c47e4aSnicm */ 19702af49740Snicm not_wrap = !(s->mode & MODE_WRAP); 19712af49740Snicm if (s->cx <= sx - not_wrap - width) 19727b470e93Snicm screen_write_set_cursor(ctx, s->cx + width, -1); 197384c47e4aSnicm else 19742af49740Snicm screen_write_set_cursor(ctx, sx - not_wrap, -1); 1975311827fbSnicm 19768e39655fSnicm /* Create space for character in insert mode. */ 19778248eab7Snicm if (s->mode & MODE_INSERT) { 19789b53212eSnicm screen_write_collect_flush(ctx, 0, __func__); 1979900b44f5Snicm ttyctx.num = width; 1980900b44f5Snicm tty_write(tty_cmd_insertcharacter, &ttyctx); 1981900b44f5Snicm } 19828e39655fSnicm 19838e39655fSnicm /* Write to the screen. */ 19848248eab7Snicm if (!skip) { 19858e39655fSnicm if (selected) { 19868ab25c40Snicm screen_select_cell(s, &tmp_gc, gc); 19870011c848Snicm ttyctx.cell = &tmp_gc; 19888248eab7Snicm } else 19898248eab7Snicm ttyctx.cell = gc; 1990714c38deSnicm tty_write(tty_cmd_cell, &ttyctx); 19912612f635Snicm } 1992311827fbSnicm } 1993311827fbSnicm 19942af49740Snicm /* Combine a UTF-8 zero-width character onto the previous if necessary. */ 19952af49740Snicm static int 19962af49740Snicm screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc) 1997e91c0c38Snicm { 1998e91c0c38Snicm struct screen *s = ctx->s; 1999e91c0c38Snicm struct grid *gd = s->grid; 20002af49740Snicm const struct utf8_data *ud = &gc->data; 20012af49740Snicm u_int n, cx = s->cx, cy = s->cy; 20022af49740Snicm struct grid_cell last; 20032af49740Snicm struct tty_ctx ttyctx; 20042af49740Snicm int force_wide = 0, zero_width = 0; 2005e91c0c38Snicm 20062af49740Snicm /* 20072af49740Snicm * Is this character which makes no sense without being combined? If 20082af49740Snicm * this is true then flag it here and discard the character (return 1) 20092af49740Snicm * if we cannot combine it. 20102af49740Snicm */ 20112af49740Snicm if (utf8_is_zwj(ud)) 20122af49740Snicm zero_width = 1; 20132af49740Snicm else if (utf8_is_vs(ud)) 20142af49740Snicm zero_width = force_wide = 1; 20152af49740Snicm else if (ud->width == 0) 20162af49740Snicm zero_width = 1; 20172af49740Snicm 20182af49740Snicm /* Cannot combine empty character or at left. */ 20192af49740Snicm if (ud->size < 2 || cx == 0) 20202af49740Snicm return (zero_width); 20212af49740Snicm log_debug("%s: character %.*s at %u,%u (width %u)", __func__, 20222af49740Snicm (int)ud->size, ud->data, cx, cy, ud->width); 20232af49740Snicm 20242af49740Snicm /* Find the cell to combine with. */ 20252af49740Snicm n = 1; 20262af49740Snicm grid_view_get_cell(gd, cx - n, cy, &last); 20272af49740Snicm if (cx != 1 && (last.flags & GRID_FLAG_PADDING)) { 20282af49740Snicm n = 2; 20292af49740Snicm grid_view_get_cell(gd, cx - n, cy, &last); 2030a7969b8bSnicm } 20312af49740Snicm if (n != last.data.width || (last.flags & GRID_FLAG_PADDING)) 20322af49740Snicm return (zero_width); 2033e91c0c38Snicm 20342af49740Snicm /* 20352af49740Snicm * Check if we need to combine characters. This could be zero width 20367c01ab0cSnicm * (set above), a modifier character (with an existing Unicode 20372af49740Snicm * character) or a previous ZWJ. 20382af49740Snicm */ 20392af49740Snicm if (!zero_width) { 20402af49740Snicm if (utf8_is_modifier(ud)) { 20412af49740Snicm if (last.data.size < 2) 20422af49740Snicm return (0); 20432af49740Snicm force_wide = 1; 20442af49740Snicm } else if (!utf8_has_zwj(&last.data)) 20452af49740Snicm return (0); 20460fbc0128Snicm } 2047e91c0c38Snicm 2048eed425c7Snicm /* Check if this combined character would be too long. */ 2049eed425c7Snicm if (last.data.size + ud->size > sizeof last.data.data) 2050eed425c7Snicm return (0); 2051eed425c7Snicm 20522af49740Snicm /* Combining; flush any pending output. */ 20532af49740Snicm screen_write_collect_flush(ctx, 0, __func__); 20540fbc0128Snicm 20552af49740Snicm log_debug("%s: %.*s -> %.*s at %u,%u (offset %u, width %u)", __func__, 20562af49740Snicm (int)ud->size, ud->data, (int)last.data.size, last.data.data, 20572af49740Snicm cx - n, cy, n, last.data.width); 2058e91c0c38Snicm 2059e931849fSnicm /* Append the data. */ 20602af49740Snicm memcpy(last.data.data + last.data.size, ud->data, ud->size); 20612af49740Snicm last.data.size += ud->size; 2062e931849fSnicm 20632af49740Snicm /* Force the width to 2 for modifiers and variation selector. */ 20642af49740Snicm if (last.data.width == 1 && force_wide) { 20652af49740Snicm last.data.width = 2; 20662af49740Snicm n = 2; 20672af49740Snicm cx++; 20682af49740Snicm } else 20692af49740Snicm force_wide = 0; 2070485d86f6Snicm 2071e931849fSnicm /* Set the new cell. */ 20722af49740Snicm grid_view_set_cell(gd, cx - n, cy, &last); 20732af49740Snicm if (force_wide) 2074173c810fSnicm grid_view_set_padding(gd, cx - 1, cy); 2075e91c0c38Snicm 20762af49740Snicm /* 20772af49740Snicm * Redraw the combined cell. If forcing the cell to width 2, reset the 20782af49740Snicm * cached cursor position in the tty, since we don't really know 20792af49740Snicm * whether the terminal thought the character was width 1 or width 2 20802af49740Snicm * and what it is going to do now. 20812af49740Snicm */ 20822af49740Snicm screen_write_set_cursor(ctx, cx - n, cy); 20832af49740Snicm screen_write_initctx(ctx, &ttyctx, 0); 20842af49740Snicm ttyctx.cell = &last; 20852af49740Snicm ttyctx.num = force_wide; /* reset cached cursor position */ 20862af49740Snicm tty_write(tty_cmd_cell, &ttyctx); 20872af49740Snicm screen_write_set_cursor(ctx, cx, cy); 20882af49740Snicm 20892af49740Snicm return (1); 2090e91c0c38Snicm } 2091e91c0c38Snicm 2092311827fbSnicm /* 2093311827fbSnicm * UTF-8 wide characters are a bit of an annoyance. They take up more than one 2094311827fbSnicm * cell on the screen, so following cells must not be drawn by marking them as 2095311827fbSnicm * padding. 2096311827fbSnicm * 2097311827fbSnicm * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8 2098311827fbSnicm * character, it is necessary to also overwrite any other cells which covered 2099311827fbSnicm * by the same character. 2100311827fbSnicm */ 21018e39655fSnicm static int 21028e39655fSnicm screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc, 21038e39655fSnicm u_int width) 2104311827fbSnicm { 2105311827fbSnicm struct screen *s = ctx->s; 2106311827fbSnicm struct grid *gd = s->grid; 21078e39655fSnicm struct grid_cell tmp_gc; 2108311827fbSnicm u_int xx; 21098e39655fSnicm int done = 0; 2110311827fbSnicm 21118e39655fSnicm if (gc->flags & GRID_FLAG_PADDING) { 2112311827fbSnicm /* 2113311827fbSnicm * A padding cell, so clear any following and leading padding 2114311827fbSnicm * cells back to the character. Don't overwrite the current 2115311827fbSnicm * cell as that happens later anyway. 2116311827fbSnicm */ 2117311827fbSnicm xx = s->cx + 1; 2118311827fbSnicm while (--xx > 0) { 21198e39655fSnicm grid_view_get_cell(gd, xx, s->cy, &tmp_gc); 21208e39655fSnicm if (~tmp_gc.flags & GRID_FLAG_PADDING) 2121311827fbSnicm break; 2122856ed6d3Snicm log_debug("%s: padding at %u,%u", __func__, xx, s->cy); 2123311827fbSnicm grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 2124311827fbSnicm } 2125311827fbSnicm 2126311827fbSnicm /* Overwrite the character at the start of this padding. */ 2127856ed6d3Snicm log_debug("%s: character at %u,%u", __func__, xx, s->cy); 2128311827fbSnicm grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 21298e39655fSnicm done = 1; 21302749bd13Snicm } 2131311827fbSnicm 21322749bd13Snicm /* 213368347226Snicm * Overwrite any padding cells that belong to any UTF-8 characters 213468347226Snicm * we'll be overwriting with the current character. 21352749bd13Snicm */ 213668347226Snicm if (width != 1 || 213768347226Snicm gc->data.width != 1 || 213868347226Snicm gc->flags & GRID_FLAG_PADDING) { 21392749bd13Snicm xx = s->cx + width - 1; 2140311827fbSnicm while (++xx < screen_size_x(s)) { 21418e39655fSnicm grid_view_get_cell(gd, xx, s->cy, &tmp_gc); 21428e39655fSnicm if (~tmp_gc.flags & GRID_FLAG_PADDING) 2143311827fbSnicm break; 21442afb856aSnicm log_debug("%s: overwrite at %u,%u", __func__, xx, 21452afb856aSnicm s->cy); 2146c851f995Snicm if (gc->flags & GRID_FLAG_TAB) { 2147c851f995Snicm memcpy(&tmp_gc, gc, sizeof tmp_gc); 2148c851f995Snicm memset(tmp_gc.data.data, 0, 2149c851f995Snicm sizeof tmp_gc.data.data); 2150c851f995Snicm *tmp_gc.data.data = ' '; 2151c851f995Snicm tmp_gc.data.width = tmp_gc.data.size = 2152c851f995Snicm tmp_gc.data.have = 1; 2153c851f995Snicm grid_view_set_cell(gd, xx, s->cy, &tmp_gc); 2154c851f995Snicm } else 2155c851f995Snicm grid_view_set_cell(gd, xx, s->cy, 2156c851f995Snicm &grid_default_cell); 21578e39655fSnicm done = 1; 2158311827fbSnicm } 2159de44f258Snicm } 2160885f7078Snicm 21618e39655fSnicm return (done); 21628e39655fSnicm } 21638e39655fSnicm 21649c8da6a8Snicm /* Set external clipboard. */ 2165885f7078Snicm void 21661b09dd8dSnicm screen_write_setselection(struct screen_write_ctx *ctx, const char *flags, 21671b09dd8dSnicm u_char *str, u_int len) 2168f9bce6b9Snicm { 2169f9bce6b9Snicm struct tty_ctx ttyctx; 2170f9bce6b9Snicm 21717f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 0); 2172f9bce6b9Snicm ttyctx.ptr = str; 21731b09dd8dSnicm ttyctx.ptr2 = (void *)flags; 2174f9bce6b9Snicm ttyctx.num = len; 2175f9bce6b9Snicm 2176f9bce6b9Snicm tty_write(tty_cmd_setselection, &ttyctx); 2177f9bce6b9Snicm } 2178f9bce6b9Snicm 21799c8da6a8Snicm /* Write unmodified string. */ 2180f9bce6b9Snicm void 2181930d157dSnicm screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len, 2182930d157dSnicm int allow_invisible_panes) 2183885f7078Snicm { 2184885f7078Snicm struct tty_ctx ttyctx; 2185885f7078Snicm 21867f9a0536Snicm screen_write_initctx(ctx, &ttyctx, 0); 2187885f7078Snicm ttyctx.ptr = str; 2188885f7078Snicm ttyctx.num = len; 2189930d157dSnicm ttyctx.allow_invisible_panes = allow_invisible_panes; 2190885f7078Snicm 2191885f7078Snicm tty_write(tty_cmd_rawstring, &ttyctx); 2192885f7078Snicm } 219383e83a91Snicm 219483e83a91Snicm /* Turn alternate screen on. */ 219583e83a91Snicm void 219683e83a91Snicm screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc, 219783e83a91Snicm int cursor) 219883e83a91Snicm { 219983e83a91Snicm struct tty_ctx ttyctx; 220083e83a91Snicm struct window_pane *wp = ctx->wp; 220183e83a91Snicm 220283e83a91Snicm if (wp != NULL && !options_get_number(wp->options, "alternate-screen")) 220383e83a91Snicm return; 220450fcbc36Snicm 220550fcbc36Snicm screen_write_collect_flush(ctx, 0, __func__); 220683e83a91Snicm screen_alternate_on(ctx->s, gc, cursor); 2207*d62c220eSnicm 2208*d62c220eSnicm if (wp != NULL) 22098b458060Snicm layout_fix_panes(wp->window, NULL); 221083e83a91Snicm 221183e83a91Snicm screen_write_initctx(ctx, &ttyctx, 1); 2212924a158aSnicm if (ttyctx.redraw_cb != NULL) 221383e83a91Snicm ttyctx.redraw_cb(&ttyctx); 221483e83a91Snicm } 221583e83a91Snicm 221683e83a91Snicm /* Turn alternate screen off. */ 221783e83a91Snicm void 221883e83a91Snicm screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc, 221983e83a91Snicm int cursor) 222083e83a91Snicm { 222183e83a91Snicm struct tty_ctx ttyctx; 222283e83a91Snicm struct window_pane *wp = ctx->wp; 222383e83a91Snicm 222483e83a91Snicm if (wp != NULL && !options_get_number(wp->options, "alternate-screen")) 222583e83a91Snicm return; 222650fcbc36Snicm 222750fcbc36Snicm screen_write_collect_flush(ctx, 0, __func__); 222883e83a91Snicm screen_alternate_off(ctx->s, gc, cursor); 2229*d62c220eSnicm 2230*d62c220eSnicm if (wp != NULL) 22318b458060Snicm layout_fix_panes(wp->window, NULL); 223283e83a91Snicm 223383e83a91Snicm screen_write_initctx(ctx, &ttyctx, 1); 2234924a158aSnicm if (ttyctx.redraw_cb != NULL) 223583e83a91Snicm ttyctx.redraw_cb(&ttyctx); 223683e83a91Snicm } 2237