1 /* $OpenBSD: screen-write.c,v 1.131 2017/10/05 08:12:24 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. */ 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 *markbs, 358 const struct grid_cell *markgc) 359 { 360 struct screen *s = ctx->s; 361 struct grid *gd = src->grid; 362 struct grid_cell gc; 363 u_int xx, yy, cx, cy, b; 364 365 if (nx == 0 || ny == 0) 366 return; 367 368 cx = s->cx; 369 cy = s->cy; 370 371 for (yy = py; yy < py + ny; yy++) { 372 for (xx = px; xx < px + nx; xx++) { 373 grid_get_cell(gd, xx, yy, &gc); 374 if (markbs != NULL) { 375 b = (yy * screen_size_x(src)) + xx; 376 if (bit_test(markbs, b)) { 377 gc.attr = markgc->attr; 378 gc.fg = markgc->fg; 379 gc.bg = markgc->bg; 380 } 381 } 382 screen_write_cell(ctx, &gc); 383 } 384 385 cy++; 386 screen_write_cursormove(ctx, cx, cy); 387 } 388 } 389 390 /* Draw a horizontal line on screen. */ 391 void 392 screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right) 393 { 394 struct screen *s = ctx->s; 395 struct grid_cell gc; 396 u_int cx, cy, i; 397 398 cx = s->cx; 399 cy = s->cy; 400 401 memcpy(&gc, &grid_default_cell, sizeof gc); 402 gc.attr |= GRID_ATTR_CHARSET; 403 404 screen_write_putc(ctx, &gc, left ? 't' : 'q'); 405 for (i = 1; i < nx - 1; i++) 406 screen_write_putc(ctx, &gc, 'q'); 407 screen_write_putc(ctx, &gc, right ? 'u' : 'q'); 408 409 screen_write_cursormove(ctx, cx, cy); 410 } 411 412 /* Draw a horizontal line on screen. */ 413 void 414 screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom) 415 { 416 struct screen *s = ctx->s; 417 struct grid_cell gc; 418 u_int cx, cy, i; 419 420 cx = s->cx; 421 cy = s->cy; 422 423 memcpy(&gc, &grid_default_cell, sizeof gc); 424 gc.attr |= GRID_ATTR_CHARSET; 425 426 screen_write_putc(ctx, &gc, top ? 'w' : 'x'); 427 for (i = 1; i < ny - 1; i++) { 428 screen_write_cursormove(ctx, cx, cy + i); 429 screen_write_putc(ctx, &gc, 'x'); 430 } 431 screen_write_cursormove(ctx, cx, cy + ny); 432 screen_write_putc(ctx, &gc, bottom ? 'v' : 'x'); 433 434 screen_write_cursormove(ctx, cx, cy); 435 } 436 437 /* Draw a box on screen. */ 438 void 439 screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny) 440 { 441 struct screen *s = ctx->s; 442 struct grid_cell gc; 443 u_int cx, cy, i; 444 445 cx = s->cx; 446 cy = s->cy; 447 448 memcpy(&gc, &grid_default_cell, sizeof gc); 449 gc.attr |= GRID_ATTR_CHARSET; 450 451 screen_write_putc(ctx, &gc, 'l'); 452 for (i = 1; i < nx - 1; i++) 453 screen_write_putc(ctx, &gc, 'q'); 454 screen_write_putc(ctx, &gc, 'k'); 455 456 screen_write_cursormove(ctx, cx, cy + ny - 1); 457 screen_write_putc(ctx, &gc, 'm'); 458 for (i = 1; i < nx - 1; i++) 459 screen_write_putc(ctx, &gc, 'q'); 460 screen_write_putc(ctx, &gc, 'j'); 461 462 for (i = 1; i < ny - 1; i++) { 463 screen_write_cursormove(ctx, cx, cy + i); 464 screen_write_putc(ctx, &gc, 'x'); 465 } 466 for (i = 1; i < ny - 1; i++) { 467 screen_write_cursormove(ctx, cx + nx - 1, cy + i); 468 screen_write_putc(ctx, &gc, 'x'); 469 } 470 471 screen_write_cursormove(ctx, cx, cy); 472 } 473 474 /* Write a preview version of a window. */ 475 void 476 screen_write_preview(struct screen_write_ctx *ctx, struct screen *src, u_int nx, 477 u_int ny) 478 { 479 struct screen *s = ctx->s; 480 struct grid_cell gc; 481 u_int cx, cy, px, py; 482 483 cx = s->cx; 484 cy = s->cy; 485 486 /* 487 * If the cursor is on, pick the area around the cursor, otherwise use 488 * the top left. 489 */ 490 if (src->mode & MODE_CURSOR) { 491 px = src->cx; 492 if (px < nx / 3) 493 px = 0; 494 else 495 px = px - nx / 3; 496 if (px + nx > screen_size_x(src)) { 497 if (nx > screen_size_x(src)) 498 px = 0; 499 else 500 px = screen_size_x(src) - nx; 501 } 502 py = src->cy; 503 if (py < ny / 3) 504 py = 0; 505 else 506 py = py - ny / 3; 507 if (py + ny > screen_size_y(src)) { 508 if (ny > screen_size_y(src)) 509 py = 0; 510 else 511 py = screen_size_y(src) - ny; 512 } 513 } else { 514 px = 0; 515 py = 0; 516 } 517 518 screen_write_copy(ctx, src, px, src->grid->hsize + py, nx, ny, NULL, 519 NULL); 520 521 if (src->mode & MODE_CURSOR) { 522 grid_view_get_cell(src->grid, src->cx, src->cy, &gc); 523 gc.attr |= GRID_ATTR_REVERSE; 524 screen_write_cursormove(ctx, cx + (src->cx - px), 525 cy + (src->cy - py)); 526 screen_write_cell(ctx, &gc); 527 } 528 } 529 530 /* Set up context for TTY command. */ 531 static void 532 screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx) 533 { 534 struct screen *s = ctx->s; 535 536 memset(ttyctx, 0, sizeof *ttyctx); 537 538 ttyctx->wp = ctx->wp; 539 540 ttyctx->ocx = s->cx; 541 ttyctx->ocy = s->cy; 542 543 ttyctx->orlower = s->rlower; 544 ttyctx->orupper = s->rupper; 545 } 546 547 /* Set a mode. */ 548 void 549 screen_write_mode_set(struct screen_write_ctx *ctx, int mode) 550 { 551 struct screen *s = ctx->s; 552 553 s->mode |= mode; 554 } 555 556 /* Clear a mode. */ 557 void 558 screen_write_mode_clear(struct screen_write_ctx *ctx, int mode) 559 { 560 struct screen *s = ctx->s; 561 562 s->mode &= ~mode; 563 } 564 565 /* Cursor up by ny. */ 566 void 567 screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny) 568 { 569 struct screen *s = ctx->s; 570 571 if (ny == 0) 572 ny = 1; 573 574 if (s->cy < s->rupper) { 575 /* Above region. */ 576 if (ny > s->cy) 577 ny = s->cy; 578 } else { 579 /* Below region. */ 580 if (ny > s->cy - s->rupper) 581 ny = s->cy - s->rupper; 582 } 583 if (s->cx == screen_size_x(s)) 584 s->cx--; 585 if (ny == 0) 586 return; 587 588 s->cy -= ny; 589 } 590 591 /* Cursor down by ny. */ 592 void 593 screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny) 594 { 595 struct screen *s = ctx->s; 596 597 if (ny == 0) 598 ny = 1; 599 600 if (s->cy > s->rlower) { 601 /* Below region. */ 602 if (ny > screen_size_y(s) - 1 - s->cy) 603 ny = screen_size_y(s) - 1 - s->cy; 604 } else { 605 /* Above region. */ 606 if (ny > s->rlower - s->cy) 607 ny = s->rlower - s->cy; 608 } 609 if (s->cx == screen_size_x(s)) 610 s->cx--; 611 if (ny == 0) 612 return; 613 614 s->cy += ny; 615 } 616 617 /* Cursor right by nx. */ 618 void 619 screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx) 620 { 621 struct screen *s = ctx->s; 622 623 if (nx == 0) 624 nx = 1; 625 626 if (nx > screen_size_x(s) - 1 - s->cx) 627 nx = screen_size_x(s) - 1 - s->cx; 628 if (nx == 0) 629 return; 630 631 s->cx += nx; 632 } 633 634 /* Cursor left by nx. */ 635 void 636 screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx) 637 { 638 struct screen *s = ctx->s; 639 640 if (nx == 0) 641 nx = 1; 642 643 if (nx > s->cx) 644 nx = s->cx; 645 if (nx == 0) 646 return; 647 648 s->cx -= nx; 649 } 650 651 /* Backspace; cursor left unless at start of wrapped line when can move up. */ 652 void 653 screen_write_backspace(struct screen_write_ctx *ctx) 654 { 655 struct screen *s = ctx->s; 656 struct grid_line *gl; 657 658 if (s->cx == 0) { 659 if (s->cy == 0) 660 return; 661 gl = &s->grid->linedata[s->grid->hsize + s->cy - 1]; 662 if (gl->flags & GRID_LINE_WRAPPED) { 663 s->cy--; 664 s->cx = screen_size_x(s) - 1; 665 } 666 } else 667 s->cx--; 668 } 669 670 /* VT100 alignment test. */ 671 void 672 screen_write_alignmenttest(struct screen_write_ctx *ctx) 673 { 674 struct screen *s = ctx->s; 675 struct tty_ctx ttyctx; 676 struct grid_cell gc; 677 u_int xx, yy; 678 679 screen_write_initctx(ctx, &ttyctx); 680 681 memcpy(&gc, &grid_default_cell, sizeof gc); 682 utf8_set(&gc.data, 'E'); 683 684 for (yy = 0; yy < screen_size_y(s); yy++) { 685 for (xx = 0; xx < screen_size_x(s); xx++) 686 grid_view_set_cell(s->grid, xx, yy, &gc); 687 } 688 689 s->cx = 0; 690 s->cy = 0; 691 692 s->rupper = 0; 693 s->rlower = screen_size_y(s) - 1; 694 695 screen_write_collect_clear(ctx, 0, screen_size_y(s) - 1); 696 tty_write(tty_cmd_alignmenttest, &ttyctx); 697 } 698 699 /* Insert nx characters. */ 700 void 701 screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) 702 { 703 struct screen *s = ctx->s; 704 struct tty_ctx ttyctx; 705 706 if (nx == 0) 707 nx = 1; 708 709 if (nx > screen_size_x(s) - s->cx) 710 nx = screen_size_x(s) - s->cx; 711 if (nx == 0) 712 return; 713 714 if (s->cx > screen_size_x(s) - 1) 715 return; 716 717 screen_write_initctx(ctx, &ttyctx); 718 ttyctx.bg = bg; 719 720 grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg); 721 722 screen_write_collect_flush(ctx, 0); 723 ttyctx.num = nx; 724 tty_write(tty_cmd_insertcharacter, &ttyctx); 725 } 726 727 /* Delete nx characters. */ 728 void 729 screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) 730 { 731 struct screen *s = ctx->s; 732 struct tty_ctx ttyctx; 733 734 if (nx == 0) 735 nx = 1; 736 737 if (nx > screen_size_x(s) - s->cx) 738 nx = screen_size_x(s) - s->cx; 739 if (nx == 0) 740 return; 741 742 if (s->cx > screen_size_x(s) - 1) 743 return; 744 745 screen_write_initctx(ctx, &ttyctx); 746 ttyctx.bg = bg; 747 748 grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg); 749 750 screen_write_collect_flush(ctx, 0); 751 ttyctx.num = nx; 752 tty_write(tty_cmd_deletecharacter, &ttyctx); 753 } 754 755 /* Clear nx characters. */ 756 void 757 screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg) 758 { 759 struct screen *s = ctx->s; 760 struct tty_ctx ttyctx; 761 762 if (nx == 0) 763 nx = 1; 764 765 if (nx > screen_size_x(s) - s->cx) 766 nx = screen_size_x(s) - s->cx; 767 if (nx == 0) 768 return; 769 770 if (s->cx > screen_size_x(s) - 1) 771 return; 772 773 screen_write_initctx(ctx, &ttyctx); 774 ttyctx.bg = bg; 775 776 grid_view_clear(s->grid, s->cx, s->cy, nx, 1, bg); 777 778 screen_write_collect_flush(ctx, 0); 779 ttyctx.num = nx; 780 tty_write(tty_cmd_clearcharacter, &ttyctx); 781 } 782 783 /* Insert ny lines. */ 784 void 785 screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg) 786 { 787 struct screen *s = ctx->s; 788 struct grid *gd = s->grid; 789 struct tty_ctx ttyctx; 790 791 if (ny == 0) 792 ny = 1; 793 794 if (s->cy < s->rupper || s->cy > s->rlower) { 795 if (ny > screen_size_y(s) - s->cy) 796 ny = screen_size_y(s) - s->cy; 797 if (ny == 0) 798 return; 799 800 screen_write_initctx(ctx, &ttyctx); 801 ttyctx.bg = bg; 802 803 grid_view_insert_lines(gd, s->cy, ny, bg); 804 805 screen_write_collect_flush(ctx, 0); 806 ttyctx.num = ny; 807 tty_write(tty_cmd_insertline, &ttyctx); 808 return; 809 } 810 811 if (ny > s->rlower + 1 - s->cy) 812 ny = s->rlower + 1 - s->cy; 813 if (ny == 0) 814 return; 815 816 screen_write_initctx(ctx, &ttyctx); 817 ttyctx.bg = bg; 818 819 if (s->cy < s->rupper || s->cy > s->rlower) 820 grid_view_insert_lines(gd, s->cy, ny, bg); 821 else 822 grid_view_insert_lines_region(gd, s->rlower, s->cy, ny, bg); 823 824 screen_write_collect_flush(ctx, 0); 825 ttyctx.num = ny; 826 tty_write(tty_cmd_insertline, &ttyctx); 827 } 828 829 /* Delete ny lines. */ 830 void 831 screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) 832 { 833 struct screen *s = ctx->s; 834 struct grid *gd = s->grid; 835 struct tty_ctx ttyctx; 836 837 if (ny == 0) 838 ny = 1; 839 840 if (s->cy < s->rupper || s->cy > s->rlower) { 841 if (ny > screen_size_y(s) - s->cy) 842 ny = screen_size_y(s) - s->cy; 843 if (ny == 0) 844 return; 845 846 screen_write_initctx(ctx, &ttyctx); 847 ttyctx.bg = bg; 848 849 grid_view_delete_lines(gd, s->cy, ny, bg); 850 851 screen_write_collect_flush(ctx, 0); 852 ttyctx.num = ny; 853 tty_write(tty_cmd_deleteline, &ttyctx); 854 return; 855 } 856 857 if (ny > s->rlower + 1 - s->cy) 858 ny = s->rlower + 1 - s->cy; 859 if (ny == 0) 860 return; 861 862 screen_write_initctx(ctx, &ttyctx); 863 ttyctx.bg = bg; 864 865 if (s->cy < s->rupper || s->cy > s->rlower) 866 grid_view_delete_lines(gd, s->cy, ny, bg); 867 else 868 grid_view_delete_lines_region(gd, s->rlower, s->cy, ny, bg); 869 870 screen_write_collect_flush(ctx, 0); 871 ttyctx.num = ny; 872 tty_write(tty_cmd_deleteline, &ttyctx); 873 } 874 875 /* Clear line at cursor. */ 876 void 877 screen_write_clearline(struct screen_write_ctx *ctx, u_int bg) 878 { 879 struct screen *s = ctx->s; 880 struct grid_line *gl; 881 struct tty_ctx ttyctx; 882 u_int sx = screen_size_x(s); 883 884 gl = &s->grid->linedata[s->grid->hsize + s->cy]; 885 if (gl->cellsize == 0 && bg == 8) 886 return; 887 888 screen_write_initctx(ctx, &ttyctx); 889 ttyctx.bg = bg; 890 891 grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); 892 893 screen_write_collect_clear(ctx, s->cy, 1); 894 screen_write_collect_flush(ctx, 0); 895 tty_write(tty_cmd_clearline, &ttyctx); 896 } 897 898 /* Clear to end of line from cursor. */ 899 void 900 screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg) 901 { 902 struct screen *s = ctx->s; 903 struct grid_line *gl; 904 struct tty_ctx ttyctx; 905 u_int sx = screen_size_x(s); 906 907 gl = &s->grid->linedata[s->grid->hsize + s->cy]; 908 if (s->cx > sx - 1 || (s->cx >= gl->cellsize && bg == 8)) 909 return; 910 911 screen_write_initctx(ctx, &ttyctx); 912 ttyctx.bg = bg; 913 914 grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg); 915 916 if (s->cx == 0) 917 screen_write_collect_clear(ctx, s->cy, 1); 918 screen_write_collect_flush(ctx, 0); 919 tty_write(tty_cmd_clearendofline, &ttyctx); 920 } 921 922 /* Clear to start of line from cursor. */ 923 void 924 screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg) 925 { 926 struct screen *s = ctx->s; 927 struct tty_ctx ttyctx; 928 u_int sx = screen_size_x(s); 929 930 screen_write_initctx(ctx, &ttyctx); 931 ttyctx.bg = bg; 932 933 if (s->cx > sx - 1) 934 grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); 935 else 936 grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg); 937 938 if (s->cx > sx - 1) 939 screen_write_collect_clear(ctx, s->cy, 1); 940 screen_write_collect_flush(ctx, 0); 941 tty_write(tty_cmd_clearstartofline, &ttyctx); 942 } 943 944 /* Move cursor to px,py. */ 945 void 946 screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py) 947 { 948 struct screen *s = ctx->s; 949 950 if (px > screen_size_x(s) - 1) 951 px = screen_size_x(s) - 1; 952 if (py > screen_size_y(s) - 1) 953 py = screen_size_y(s) - 1; 954 955 s->cx = px; 956 s->cy = py; 957 } 958 959 /* Reverse index (up with scroll). */ 960 void 961 screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg) 962 { 963 struct screen *s = ctx->s; 964 struct tty_ctx ttyctx; 965 966 screen_write_initctx(ctx, &ttyctx); 967 ttyctx.bg = bg; 968 969 if (s->cy == s->rupper) 970 grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg); 971 else if (s->cy > 0) 972 s->cy--; 973 974 screen_write_collect_flush(ctx, 0); 975 tty_write(tty_cmd_reverseindex, &ttyctx); 976 } 977 978 /* Set scroll region. */ 979 void 980 screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper, 981 u_int rlower) 982 { 983 struct screen *s = ctx->s; 984 985 if (rupper > screen_size_y(s) - 1) 986 rupper = screen_size_y(s) - 1; 987 if (rlower > screen_size_y(s) - 1) 988 rlower = screen_size_y(s) - 1; 989 if (rupper >= rlower) /* cannot be one line */ 990 return; 991 992 screen_write_collect_flush(ctx, 0); 993 994 /* Cursor moves to top-left. */ 995 s->cx = 0; 996 s->cy = 0; 997 998 s->rupper = rupper; 999 s->rlower = rlower; 1000 } 1001 1002 /* Line feed. */ 1003 void 1004 screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg) 1005 { 1006 struct screen *s = ctx->s; 1007 struct grid *gd = s->grid; 1008 struct grid_line *gl; 1009 1010 gl = &gd->linedata[gd->hsize + s->cy]; 1011 if (wrapped) 1012 gl->flags |= GRID_LINE_WRAPPED; 1013 else 1014 gl->flags &= ~GRID_LINE_WRAPPED; 1015 1016 log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, 1017 s->rupper, s->rlower); 1018 1019 if (bg != ctx->bg) { 1020 screen_write_collect_flush(ctx, 1); 1021 ctx->bg = bg; 1022 } 1023 1024 if (s->cy == s->rlower) { 1025 grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); 1026 screen_write_collect_scroll(ctx); 1027 ctx->scrolled++; 1028 } else if (s->cy < screen_size_y(s) - 1) 1029 s->cy++; 1030 } 1031 1032 /* Scroll up. */ 1033 void 1034 screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg) 1035 { 1036 struct screen *s = ctx->s; 1037 struct grid *gd = s->grid; 1038 u_int i; 1039 1040 if (lines == 0) 1041 lines = 1; 1042 else if (lines > s->rlower - s->rupper + 1) 1043 lines = s->rlower - s->rupper + 1; 1044 1045 if (bg != ctx->bg) { 1046 screen_write_collect_flush(ctx, 1); 1047 ctx->bg = bg; 1048 } 1049 1050 for (i = 0; i < lines; i++) { 1051 grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); 1052 screen_write_collect_scroll(ctx); 1053 } 1054 ctx->scrolled += lines; 1055 } 1056 1057 /* Carriage return (cursor to start of line). */ 1058 void 1059 screen_write_carriagereturn(struct screen_write_ctx *ctx) 1060 { 1061 struct screen *s = ctx->s; 1062 1063 s->cx = 0; 1064 } 1065 1066 /* Clear to end of screen from cursor. */ 1067 void 1068 screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg) 1069 { 1070 struct screen *s = ctx->s; 1071 struct grid *gd = s->grid; 1072 struct tty_ctx ttyctx; 1073 u_int sx = screen_size_x(s), sy = screen_size_y(s); 1074 1075 screen_write_initctx(ctx, &ttyctx); 1076 ttyctx.bg = bg; 1077 1078 /* Scroll into history if it is enabled and clearing entire screen. */ 1079 if (s->cx == 0 && s->cy == 0 && (gd->flags & GRID_HISTORY)) 1080 grid_view_clear_history(gd, bg); 1081 else { 1082 if (s->cx <= sx - 1) 1083 grid_view_clear(gd, s->cx, s->cy, sx - s->cx, 1, bg); 1084 grid_view_clear(gd, 0, s->cy + 1, sx, sy - (s->cy + 1), bg); 1085 } 1086 1087 screen_write_collect_clear(ctx, s->cy + 1, sy - (s->cy + 1)); 1088 screen_write_collect_flush(ctx, 0); 1089 tty_write(tty_cmd_clearendofscreen, &ttyctx); 1090 } 1091 1092 /* Clear to start of screen. */ 1093 void 1094 screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg) 1095 { 1096 struct screen *s = ctx->s; 1097 struct tty_ctx ttyctx; 1098 u_int sx = screen_size_x(s); 1099 1100 screen_write_initctx(ctx, &ttyctx); 1101 ttyctx.bg = bg; 1102 1103 if (s->cy > 0) 1104 grid_view_clear(s->grid, 0, 0, sx, s->cy, bg); 1105 if (s->cx > sx - 1) 1106 grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); 1107 else 1108 grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg); 1109 1110 screen_write_collect_clear(ctx, 0, s->cy); 1111 screen_write_collect_flush(ctx, 0); 1112 tty_write(tty_cmd_clearstartofscreen, &ttyctx); 1113 } 1114 1115 /* Clear entire screen. */ 1116 void 1117 screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg) 1118 { 1119 struct screen *s = ctx->s; 1120 struct tty_ctx ttyctx; 1121 u_int sx = screen_size_x(s), sy = screen_size_y(s); 1122 1123 screen_write_initctx(ctx, &ttyctx); 1124 ttyctx.bg = bg; 1125 1126 /* Scroll into history if it is enabled. */ 1127 if (s->grid->flags & GRID_HISTORY) 1128 grid_view_clear_history(s->grid, bg); 1129 else 1130 grid_view_clear(s->grid, 0, 0, sx, sy, bg); 1131 1132 screen_write_collect_clear(ctx, 0, sy); 1133 tty_write(tty_cmd_clearscreen, &ttyctx); 1134 } 1135 1136 /* Clear entire history. */ 1137 void 1138 screen_write_clearhistory(struct screen_write_ctx *ctx) 1139 { 1140 struct screen *s = ctx->s; 1141 struct grid *gd = s->grid; 1142 1143 grid_move_lines(gd, 0, gd->hsize, gd->sy, 8); 1144 gd->hscrolled = gd->hsize = 0; 1145 } 1146 1147 /* Clear a collected line. */ 1148 static void 1149 screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n) 1150 { 1151 struct screen_write_collect_item *ci, *tmp; 1152 u_int i; 1153 size_t size; 1154 1155 for (i = y ; i < y + n; i++) { 1156 if (TAILQ_EMPTY(&ctx->list[i].items)) 1157 continue; 1158 size = 0; 1159 TAILQ_FOREACH_SAFE(ci, &ctx->list[i].items, entry, tmp) { 1160 size += ci->used; 1161 TAILQ_REMOVE(&ctx->list[i].items, ci, entry); 1162 free(ci); 1163 } 1164 ctx->skipped += size; 1165 log_debug("%s: dropped %zu bytes (line %u)", __func__, size, i); 1166 } 1167 } 1168 1169 /* Scroll collected lines up. */ 1170 static void 1171 screen_write_collect_scroll(struct screen_write_ctx *ctx) 1172 { 1173 struct screen *s = ctx->s; 1174 struct screen_write_collect_line *cl; 1175 u_int y; 1176 1177 log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, 1178 s->rupper, s->rlower); 1179 1180 screen_write_collect_clear(ctx, s->rupper, 1); 1181 for (y = s->rupper; y < s->rlower; y++) { 1182 cl = &ctx->list[y + 1]; 1183 TAILQ_CONCAT(&ctx->list[y].items, &cl->items, entry); 1184 TAILQ_INIT(&cl->items); 1185 } 1186 } 1187 1188 /* Flush collected lines. */ 1189 static void 1190 screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only) 1191 { 1192 struct screen *s = ctx->s; 1193 struct screen_write_collect_item *ci, *tmp; 1194 u_int y, cx, cy, items = 0; 1195 struct tty_ctx ttyctx; 1196 size_t written = 0; 1197 1198 if (ctx->scrolled != 0) { 1199 log_debug("%s: scrolled %u (region %u-%u)", __func__, 1200 ctx->scrolled, s->rupper, s->rlower); 1201 if (ctx->scrolled > s->rlower - s->rupper + 1) 1202 ctx->scrolled = s->rlower - s->rupper + 1; 1203 1204 screen_write_initctx(ctx, &ttyctx); 1205 ttyctx.num = ctx->scrolled; 1206 ttyctx.bg = ctx->bg; 1207 tty_write(tty_cmd_scrollup, &ttyctx); 1208 } 1209 ctx->scrolled = 0; 1210 ctx->bg = 8; 1211 1212 if (scroll_only) 1213 return; 1214 1215 cx = s->cx; cy = s->cy; 1216 for (y = 0; y < screen_size_y(s); y++) { 1217 TAILQ_FOREACH_SAFE(ci, &ctx->list[y].items, entry, tmp) { 1218 screen_write_cursormove(ctx, ci->x, y); 1219 screen_write_initctx(ctx, &ttyctx); 1220 ttyctx.cell = &ci->gc; 1221 ttyctx.wrapped = ci->wrapped; 1222 ttyctx.ptr = ci->data; 1223 ttyctx.num = ci->used; 1224 tty_write(tty_cmd_cells, &ttyctx); 1225 1226 items++; 1227 written += ci->used; 1228 1229 TAILQ_REMOVE(&ctx->list[y].items, ci, entry); 1230 free(ci); 1231 } 1232 } 1233 s->cx = cx; s->cy = cy; 1234 1235 log_debug("%s: flushed %u items (%zu bytes)", __func__, items, written); 1236 ctx->written += written; 1237 } 1238 1239 /* Finish and store collected cells. */ 1240 void 1241 screen_write_collect_end(struct screen_write_ctx *ctx) 1242 { 1243 struct screen *s = ctx->s; 1244 struct screen_write_collect_item *ci = ctx->item; 1245 struct grid_cell gc; 1246 u_int xx; 1247 1248 if (ci->used == 0) 1249 return; 1250 ci->data[ci->used] = '\0'; 1251 1252 ci->x = s->cx; 1253 TAILQ_INSERT_TAIL(&ctx->list[s->cy].items, ci, entry); 1254 ctx->item = xcalloc(1, sizeof *ctx->item); 1255 1256 log_debug("%s: %u %s (at %u,%u)", __func__, ci->used, ci->data, s->cx, 1257 s->cy); 1258 1259 if (s->cx != 0) { 1260 for (xx = s->cx; xx > 0; xx--) { 1261 grid_view_get_cell(s->grid, xx, s->cy, &gc); 1262 if (~gc.flags & GRID_FLAG_PADDING) 1263 break; 1264 grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); 1265 } 1266 if (gc.data.width > 1) 1267 grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); 1268 } 1269 1270 memcpy(&gc, &ci->gc, sizeof gc); 1271 grid_view_set_cells(s->grid, s->cx, s->cy, &gc, ci->data, ci->used); 1272 s->cx += ci->used; 1273 1274 for (xx = s->cx; xx < screen_size_x(s); xx++) { 1275 grid_view_get_cell(s->grid, xx, s->cy, &gc); 1276 if (~gc.flags & GRID_FLAG_PADDING) 1277 break; 1278 grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); 1279 } 1280 } 1281 1282 /* Write cell data, collecting if necessary. */ 1283 void 1284 screen_write_collect_add(struct screen_write_ctx *ctx, 1285 const struct grid_cell *gc) 1286 { 1287 struct screen *s = ctx->s; 1288 struct screen_write_collect_item *ci; 1289 u_int sx = screen_size_x(s); 1290 int collect; 1291 1292 /* 1293 * Don't need to check that the attributes and whatnot are still the 1294 * same - input_parse will end the collection when anything that isn't 1295 * a plain character is encountered. Also nothing should make it here 1296 * that isn't a single ASCII character. 1297 */ 1298 1299 collect = 1; 1300 if (gc->data.width != 1 || gc->data.size != 1) 1301 collect = 0; 1302 else if (gc->attr & GRID_ATTR_CHARSET) 1303 collect = 0; 1304 else if (~s->mode & MODE_WRAP) 1305 collect = 0; 1306 else if (s->mode & MODE_INSERT) 1307 collect = 0; 1308 else if (s->sel.flag) 1309 collect = 0; 1310 if (!collect) { 1311 screen_write_collect_end(ctx); 1312 screen_write_collect_flush(ctx, 0); 1313 screen_write_cell(ctx, gc); 1314 return; 1315 } 1316 ctx->cells++; 1317 1318 if (s->cx > sx - 1 || ctx->item->used > sx - 1 - s->cx) 1319 screen_write_collect_end(ctx); 1320 ci = ctx->item; /* may have changed */ 1321 1322 if (s->cx > sx - 1) { 1323 log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy); 1324 ci->wrapped = 1; 1325 screen_write_linefeed(ctx, 1, 8); 1326 s->cx = 0; 1327 } 1328 1329 if (ci->used == 0) 1330 memcpy(&ci->gc, gc, sizeof ci->gc); 1331 ci->data[ci->used++] = gc->data.data[0]; 1332 if (ci->used == (sizeof ci->data) - 1) 1333 screen_write_collect_end(ctx); 1334 } 1335 1336 /* Write cell data. */ 1337 void 1338 screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) 1339 { 1340 struct screen *s = ctx->s; 1341 struct grid *gd = s->grid; 1342 struct grid_line *gl; 1343 struct grid_cell_entry *gce; 1344 struct grid_cell tmp_gc, now_gc; 1345 struct tty_ctx ttyctx; 1346 u_int sx = screen_size_x(s), sy = screen_size_y(s); 1347 u_int width = gc->data.width, xx, last, cx, cy; 1348 int selected, skip = 1; 1349 1350 /* Ignore padding cells. */ 1351 if (gc->flags & GRID_FLAG_PADDING) 1352 return; 1353 ctx->cells++; 1354 1355 /* If the width is zero, combine onto the previous character. */ 1356 if (width == 0) { 1357 screen_write_collect_flush(ctx, 0); 1358 if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) { 1359 cx = s->cx; cy = s->cy; 1360 screen_write_cursormove(ctx, xx, s->cy); 1361 screen_write_initctx(ctx, &ttyctx); 1362 ttyctx.cell = gc; 1363 tty_write(tty_cmd_cell, &ttyctx); 1364 s->cx = cx; s->cy = cy; 1365 } 1366 return; 1367 } 1368 1369 /* Flush any existing scrolling. */ 1370 screen_write_collect_flush(ctx, 1); 1371 1372 /* If this character doesn't fit, ignore it. */ 1373 if ((~s->mode & MODE_WRAP) && 1374 width > 1 && 1375 (width > sx || (s->cx != sx && s->cx > sx - width))) 1376 return; 1377 1378 /* If in insert mode, make space for the cells. */ 1379 if (s->mode & MODE_INSERT) { 1380 grid_view_insert_cells(s->grid, s->cx, s->cy, width, 8); 1381 skip = 0; 1382 } 1383 1384 /* Check this will fit on the current line and wrap if not. */ 1385 if ((s->mode & MODE_WRAP) && s->cx > sx - width) { 1386 log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy); 1387 screen_write_linefeed(ctx, 1, 8); 1388 s->cx = 0; 1389 screen_write_collect_flush(ctx, 1); 1390 } 1391 1392 /* Sanity check cursor position. */ 1393 if (s->cx > sx - width || s->cy > sy - 1) 1394 return; 1395 screen_write_initctx(ctx, &ttyctx); 1396 1397 /* Handle overwriting of UTF-8 characters. */ 1398 gl = &s->grid->linedata[s->grid->hsize + s->cy]; 1399 if (gl->flags & GRID_LINE_EXTENDED) { 1400 grid_view_get_cell(gd, s->cx, s->cy, &now_gc); 1401 if (screen_write_overwrite(ctx, &now_gc, width)) 1402 skip = 0; 1403 } 1404 1405 /* 1406 * If the new character is UTF-8 wide, fill in padding cells. Have 1407 * already ensured there is enough room. 1408 */ 1409 for (xx = s->cx + 1; xx < s->cx + width; xx++) { 1410 log_debug("%s: new padding at %u,%u", __func__, xx, s->cy); 1411 grid_view_set_cell(gd, xx, s->cy, &screen_write_pad_cell); 1412 skip = 0; 1413 } 1414 1415 /* If no change, do not draw. */ 1416 if (skip) { 1417 if (s->cx >= gl->cellsize) 1418 skip = grid_cells_equal(gc, &grid_default_cell); 1419 else { 1420 gce = &gl->celldata[s->cx]; 1421 if (gce->flags & GRID_FLAG_EXTENDED) 1422 skip = 0; 1423 else if (gc->flags != gce->flags) 1424 skip = 0; 1425 else if (gc->attr != gce->data.attr) 1426 skip = 0; 1427 else if (gc->fg != gce->data.fg) 1428 skip = 0; 1429 else if (gc->bg != gce->data.bg) 1430 skip = 0; 1431 else if (gc->data.width != 1) 1432 skip = 0; 1433 else if (gc->data.size != 1) 1434 skip = 0; 1435 else if (gce->data.data != gc->data.data[0]) 1436 skip = 0; 1437 } 1438 } 1439 1440 /* Update the selected flag and set the cell. */ 1441 selected = screen_check_selection(s, s->cx, s->cy); 1442 if (selected && (~gc->flags & GRID_FLAG_SELECTED)) { 1443 memcpy(&tmp_gc, gc, sizeof tmp_gc); 1444 tmp_gc.flags |= GRID_FLAG_SELECTED; 1445 grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); 1446 } else if (!selected && (gc->flags & GRID_FLAG_SELECTED)) { 1447 memcpy(&tmp_gc, gc, sizeof tmp_gc); 1448 tmp_gc.flags &= ~GRID_FLAG_SELECTED; 1449 grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); 1450 } else if (!skip) 1451 grid_view_set_cell(gd, s->cx, s->cy, gc); 1452 if (selected) 1453 skip = 0; 1454 1455 /* 1456 * Move the cursor. If not wrapping, stick at the last character and 1457 * replace it. 1458 */ 1459 last = !(s->mode & MODE_WRAP); 1460 if (s->cx <= sx - last - width) 1461 s->cx += width; 1462 else 1463 s->cx = sx - last; 1464 1465 /* Create space for character in insert mode. */ 1466 if (s->mode & MODE_INSERT) { 1467 screen_write_collect_flush(ctx, 0); 1468 ttyctx.num = width; 1469 tty_write(tty_cmd_insertcharacter, &ttyctx); 1470 } 1471 1472 /* Write to the screen. */ 1473 if (!skip) { 1474 if (selected) { 1475 screen_select_cell(s, &tmp_gc, gc); 1476 ttyctx.cell = &tmp_gc; 1477 } else 1478 ttyctx.cell = gc; 1479 tty_write(tty_cmd_cell, &ttyctx); 1480 ctx->written++; 1481 } else 1482 ctx->skipped++; 1483 } 1484 1485 /* Combine a UTF-8 zero-width character onto the previous. */ 1486 static const struct grid_cell * 1487 screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud, 1488 u_int *xx) 1489 { 1490 struct screen *s = ctx->s; 1491 struct grid *gd = s->grid; 1492 static struct grid_cell gc; 1493 u_int n; 1494 1495 /* Can't combine if at 0. */ 1496 if (s->cx == 0) 1497 return (NULL); 1498 1499 /* Empty data is out. */ 1500 if (ud->size == 0) 1501 fatalx("UTF-8 data empty"); 1502 1503 /* Retrieve the previous cell. */ 1504 for (n = 1; n <= s->cx; n++) { 1505 grid_view_get_cell(gd, s->cx - n, s->cy, &gc); 1506 if (~gc.flags & GRID_FLAG_PADDING) 1507 break; 1508 } 1509 if (n > s->cx) 1510 return (NULL); 1511 *xx = s->cx - n; 1512 1513 /* Check there is enough space. */ 1514 if (gc.data.size + ud->size > sizeof gc.data.data) 1515 return (NULL); 1516 1517 log_debug("%s: %.*s onto %.*s at %u,%u", __func__, (int)ud->size, 1518 ud->data, (int)gc.data.size, gc.data.data, *xx, s->cy); 1519 1520 /* Append the data. */ 1521 memcpy(gc.data.data + gc.data.size, ud->data, ud->size); 1522 gc.data.size += ud->size; 1523 1524 /* Set the new cell. */ 1525 grid_view_set_cell(gd, *xx, s->cy, &gc); 1526 1527 return (&gc); 1528 } 1529 1530 /* 1531 * UTF-8 wide characters are a bit of an annoyance. They take up more than one 1532 * cell on the screen, so following cells must not be drawn by marking them as 1533 * padding. 1534 * 1535 * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8 1536 * character, it is necessary to also overwrite any other cells which covered 1537 * by the same character. 1538 */ 1539 static int 1540 screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc, 1541 u_int width) 1542 { 1543 struct screen *s = ctx->s; 1544 struct grid *gd = s->grid; 1545 struct grid_cell tmp_gc; 1546 u_int xx; 1547 int done = 0; 1548 1549 if (gc->flags & GRID_FLAG_PADDING) { 1550 /* 1551 * A padding cell, so clear any following and leading padding 1552 * cells back to the character. Don't overwrite the current 1553 * cell as that happens later anyway. 1554 */ 1555 xx = s->cx + 1; 1556 while (--xx > 0) { 1557 grid_view_get_cell(gd, xx, s->cy, &tmp_gc); 1558 if (~tmp_gc.flags & GRID_FLAG_PADDING) 1559 break; 1560 log_debug("%s: padding at %u,%u", __func__, xx, s->cy); 1561 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1562 } 1563 1564 /* Overwrite the character at the start of this padding. */ 1565 log_debug("%s: character at %u,%u", __func__, xx, s->cy); 1566 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1567 done = 1; 1568 } 1569 1570 /* 1571 * Overwrite any padding cells that belong to any UTF-8 characters 1572 * we'll be overwriting with the current character. 1573 */ 1574 if (width != 1 || 1575 gc->data.width != 1 || 1576 gc->flags & GRID_FLAG_PADDING) { 1577 xx = s->cx + width - 1; 1578 while (++xx < screen_size_x(s)) { 1579 grid_view_get_cell(gd, xx, s->cy, &tmp_gc); 1580 if (~tmp_gc.flags & GRID_FLAG_PADDING) 1581 break; 1582 log_debug("%s: overwrite at %u,%u", __func__, xx, s->cy); 1583 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1584 done = 1; 1585 } 1586 } 1587 1588 return (done); 1589 } 1590 1591 /* Set external clipboard. */ 1592 void 1593 screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len) 1594 { 1595 struct tty_ctx ttyctx; 1596 1597 screen_write_initctx(ctx, &ttyctx); 1598 ttyctx.ptr = str; 1599 ttyctx.num = len; 1600 1601 tty_write(tty_cmd_setselection, &ttyctx); 1602 } 1603 1604 /* Write unmodified string. */ 1605 void 1606 screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len) 1607 { 1608 struct tty_ctx ttyctx; 1609 1610 screen_write_initctx(ctx, &ttyctx); 1611 ttyctx.ptr = str; 1612 ttyctx.num = len; 1613 1614 tty_write(tty_cmd_rawstring, &ttyctx); 1615 } 1616