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