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