1 /* $OpenBSD: screen-write.c,v 1.30 2009/10/12 17:19:47 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> 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 <string.h> 22 23 #include "tmux.h" 24 25 void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *); 26 void screen_write_overwrite(struct screen_write_ctx *); 27 28 /* Initialise writing with a window. */ 29 void 30 screen_write_start( 31 struct screen_write_ctx *ctx, struct window_pane *wp, struct screen *s) 32 { 33 ctx->wp = wp; 34 if (wp != NULL && s == NULL) 35 ctx->s = wp->screen; 36 else 37 ctx->s = s; 38 } 39 40 /* Finish writing. */ 41 void 42 screen_write_stop(unused struct screen_write_ctx *ctx) 43 { 44 } 45 46 /* Write character. */ 47 void 48 screen_write_putc( 49 struct screen_write_ctx *ctx, struct grid_cell *gc, u_char ch) 50 { 51 gc->data = ch; 52 screen_write_cell(ctx, gc, NULL); 53 } 54 55 /* Calculate string length, with embedded formatting. */ 56 size_t printflike2 57 screen_write_cstrlen(int utf8flag, const char *fmt, ...) 58 { 59 va_list ap; 60 char *msg, *msg2, *ptr, *ptr2; 61 size_t size; 62 63 va_start(ap, fmt); 64 xvasprintf(&msg, fmt, ap); 65 va_end(ap); 66 msg2 = xmalloc(strlen(msg) + 1); 67 68 ptr = msg; 69 ptr2 = msg2; 70 while (*ptr != '\0') { 71 if (ptr[0] == '#' && ptr[1] == '[') { 72 while (*ptr != ']' && *ptr != '\0') 73 ptr++; 74 if (*ptr == ']') 75 ptr++; 76 continue; 77 } 78 *ptr2++ = *ptr++; 79 } 80 *ptr2 = '\0'; 81 82 size = screen_write_strlen(utf8flag, "%s", msg2); 83 84 xfree(msg); 85 xfree(msg2); 86 87 return (size); 88 } 89 90 /* Calculate string length. */ 91 size_t printflike2 92 screen_write_strlen(int utf8flag, const char *fmt, ...) 93 { 94 va_list ap; 95 char *msg; 96 u_char *ptr, utf8buf[4]; 97 size_t left, size = 0; 98 99 va_start(ap, fmt); 100 xvasprintf(&msg, fmt, ap); 101 va_end(ap); 102 103 ptr = msg; 104 while (*ptr != '\0') { 105 if (utf8flag && *ptr > 0x7f) { 106 memset(utf8buf, 0xff, sizeof utf8buf); 107 108 left = strlen(ptr); 109 if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { 110 memcpy(utf8buf, ptr, 2); 111 ptr += 2; 112 } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { 113 memcpy(utf8buf, ptr, 3); 114 ptr += 3; 115 } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { 116 memcpy(utf8buf, ptr, 4); 117 ptr += 4; 118 } else { 119 *utf8buf = *ptr; 120 ptr++; 121 } 122 size += utf8_width(utf8buf); 123 } else { 124 size++; 125 ptr++; 126 } 127 } 128 129 xfree(msg); 130 return (size); 131 } 132 133 /* Write simple string (no UTF-8 or maximum length). */ 134 void printflike3 135 screen_write_puts( 136 struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...) 137 { 138 va_list ap; 139 140 va_start(ap, fmt); 141 screen_write_vnputs(ctx, -1, gc, 0, fmt, ap); 142 va_end(ap); 143 } 144 145 /* Write string with length limit (-1 for unlimited). */ 146 void printflike5 147 screen_write_nputs(struct screen_write_ctx *ctx, 148 ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...) 149 { 150 va_list ap; 151 152 va_start(ap, fmt); 153 screen_write_vnputs(ctx, maxlen, gc, utf8flag, fmt, ap); 154 va_end(ap); 155 } 156 157 void 158 screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, 159 struct grid_cell *gc, int utf8flag, const char *fmt, va_list ap) 160 { 161 char *msg; 162 u_char *ptr, utf8buf[4]; 163 size_t left, size = 0; 164 int width; 165 166 xvasprintf(&msg, fmt, ap); 167 168 ptr = msg; 169 while (*ptr != '\0') { 170 if (utf8flag && *ptr > 0x7f) { 171 memset(utf8buf, 0xff, sizeof utf8buf); 172 173 left = strlen(ptr); 174 if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { 175 memcpy(utf8buf, ptr, 2); 176 ptr += 2; 177 } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { 178 memcpy(utf8buf, ptr, 3); 179 ptr += 3; 180 } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { 181 memcpy(utf8buf, ptr, 4); 182 ptr += 4; 183 } else { 184 *utf8buf = *ptr; 185 ptr++; 186 } 187 188 width = utf8_width(utf8buf); 189 if (maxlen > 0 && size + width > (size_t) maxlen) { 190 while (size < (size_t) maxlen) { 191 screen_write_putc(ctx, gc, ' '); 192 size++; 193 } 194 break; 195 } 196 size += width; 197 198 gc->flags |= GRID_FLAG_UTF8; 199 screen_write_cell(ctx, gc, utf8buf); 200 gc->flags &= ~GRID_FLAG_UTF8; 201 202 } else { 203 if (maxlen > 0 && size + 1 > (size_t) maxlen) 204 break; 205 206 size++; 207 screen_write_putc(ctx, gc, *ptr); 208 ptr++; 209 } 210 } 211 212 xfree(msg); 213 } 214 215 /* Write string, similar to nputs, but with embedded formatting (#[]). */ 216 void printflike5 217 screen_write_cnputs(struct screen_write_ctx *ctx, 218 ssize_t maxlen, struct grid_cell *gc, int utf8flag, const char *fmt, ...) 219 { 220 struct grid_cell lgc; 221 va_list ap; 222 char *msg; 223 u_char *ptr, *last, utf8buf[4]; 224 size_t left, size = 0; 225 int width; 226 227 va_start(ap, fmt); 228 xvasprintf(&msg, fmt, ap); 229 va_end(ap); 230 231 memcpy(&lgc, gc, sizeof lgc); 232 233 ptr = msg; 234 while (*ptr != '\0') { 235 if (ptr[0] == '#' && ptr[1] == '[') { 236 ptr += 2; 237 last = ptr + strcspn(ptr, "]"); 238 if (*last == '\0') { 239 /* No ]. Not much point in doing anything. */ 240 break; 241 } 242 *last = '\0'; 243 244 screen_write_parsestyle(gc, &lgc, ptr); 245 ptr = last + 1; 246 continue; 247 } 248 249 if (utf8flag && *ptr > 0x7f) { 250 memset(utf8buf, 0xff, sizeof utf8buf); 251 252 left = strlen(ptr); 253 if (*ptr >= 0xc2 && *ptr <= 0xdf && left >= 2) { 254 memcpy(utf8buf, ptr, 2); 255 ptr += 2; 256 } else if (*ptr >= 0xe0 && *ptr <= 0xef && left >= 3) { 257 memcpy(utf8buf, ptr, 3); 258 ptr += 3; 259 } else if (*ptr >= 0xf0 && *ptr <= 0xf4 && left >= 4) { 260 memcpy(utf8buf, ptr, 4); 261 ptr += 4; 262 } else { 263 *utf8buf = *ptr; 264 ptr++; 265 } 266 267 width = utf8_width(utf8buf); 268 if (maxlen > 0 && size + width > (size_t) maxlen) { 269 while (size < (size_t) maxlen) { 270 screen_write_putc(ctx, gc, ' '); 271 size++; 272 } 273 break; 274 } 275 size += width; 276 277 lgc.flags |= GRID_FLAG_UTF8; 278 screen_write_cell(ctx, &lgc, utf8buf); 279 lgc.flags &= ~GRID_FLAG_UTF8; 280 281 } else { 282 if (maxlen > 0 && size + 1 > (size_t) maxlen) 283 break; 284 285 size++; 286 screen_write_putc(ctx, &lgc, *ptr); 287 ptr++; 288 } 289 } 290 291 xfree(msg); 292 } 293 294 /* Parse an embedded style of the form "fg=colour,bg=colour,bright,...". */ 295 void 296 screen_write_parsestyle( 297 struct grid_cell *defgc, struct grid_cell *gc, const char *in) 298 { 299 const char delimiters[] = " ,"; 300 char tmp[32]; 301 int val; 302 size_t end; 303 u_char fg, bg, attr, flags; 304 305 if (*in == '\0') 306 return; 307 if (strchr(delimiters, in[strlen(in) - 1]) != NULL) 308 return; 309 310 fg = gc->fg; 311 bg = gc->bg; 312 attr = gc->attr; 313 flags = gc->flags; 314 do { 315 end = strcspn(in, delimiters); 316 if (end > (sizeof tmp) - 1) 317 return; 318 memcpy(tmp, in, end); 319 tmp[end] = '\0'; 320 321 if (strcasecmp(tmp, "default") == 0) { 322 fg = defgc->fg; 323 bg = defgc->bg; 324 attr = defgc->attr; 325 } else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) { 326 if ((val = colour_fromstring(tmp + 3)) == -1) 327 return; 328 if (*in == 'f' || *in == 'F') { 329 if (val != 8) { 330 if (val & 0x100) { 331 flags |= GRID_FLAG_FG256; 332 val &= ~0x100; 333 } else 334 flags &= ~GRID_FLAG_FG256; 335 fg = val; 336 } else 337 fg = defgc->fg; 338 } else if (*in == 'b' || *in == 'B') { 339 if (val != 8) { 340 if (val & 0x100) { 341 flags |= GRID_FLAG_BG256; 342 val &= ~0x100; 343 } else 344 flags &= ~GRID_FLAG_BG256; 345 bg = val; 346 } else 347 bg = defgc->bg; 348 } else 349 return; 350 } else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) { 351 if ((val = attributes_fromstring(tmp + 2)) == -1) 352 return; 353 attr &= ~val; 354 } else { 355 if ((val = attributes_fromstring(tmp)) == -1) 356 return; 357 attr |= val; 358 } 359 360 in += end + strspn(in + end, delimiters); 361 } while (*in != '\0'); 362 gc->fg = fg; 363 gc->bg = bg; 364 gc->attr = attr; 365 gc->flags = flags; 366 } 367 368 /* Copy from another screen. */ 369 void 370 screen_write_copy(struct screen_write_ctx *ctx, 371 struct screen *src, u_int px, u_int py, u_int nx, u_int ny) 372 { 373 struct screen *s = ctx->s; 374 struct grid *gd = src->grid; 375 struct grid_line *gl; 376 const struct grid_cell *gc; 377 u_char *udata; 378 u_int xx, yy, cx, cy, ax, bx; 379 380 cx = s->cx; 381 cy = s->cy; 382 for (yy = py; yy < py + ny; yy++) { 383 gl = &gd->linedata[yy]; 384 if (yy < gd->hsize + gd->sy) { 385 /* 386 * Find start and end position and copy between 387 * them. Limit to the real end of the line then use a 388 * clear EOL only if copying to the end, otherwise 389 * could overwrite whatever is there already. 390 */ 391 if (px > gl->cellsize) 392 ax = gl->cellsize; 393 else 394 ax = px; 395 if (px + nx == gd->sx && px + nx > gl->cellsize) 396 bx = gl->cellsize; 397 else 398 bx = px + nx; 399 for (xx = ax; xx < bx; xx++) { 400 udata = NULL; 401 if (xx >= gl->cellsize) 402 gc = &grid_default_cell; 403 else { 404 gc = &gl->celldata[xx]; 405 if (gc->flags & GRID_FLAG_UTF8) 406 udata = gl->utf8data[xx].data; 407 } 408 screen_write_cell(ctx, gc, udata); 409 } 410 if (px + nx == gd->sx && px + nx > gl->cellsize) 411 screen_write_clearendofline(ctx); 412 } else 413 screen_write_clearline(ctx); 414 cy++; 415 screen_write_cursormove(ctx, cx, cy); 416 } 417 } 418 419 /* Set up context for TTY command. */ 420 void 421 screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx) 422 { 423 struct screen *s = ctx->s; 424 425 ttyctx->wp = ctx->wp; 426 427 ttyctx->ocx = s->cx; 428 ttyctx->ocy = s->cy; 429 430 ttyctx->orlower = s->rlower; 431 ttyctx->orupper = s->rupper; 432 } 433 434 /* Cursor up by ny. */ 435 void 436 screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny) 437 { 438 struct screen *s = ctx->s; 439 440 if (ny == 0) 441 ny = 1; 442 443 if (s->cy < s->rupper) { 444 /* Above region. */ 445 if (ny > s->cy) 446 ny = s->cy; 447 } else { 448 /* Below region. */ 449 if (ny > s->cy - s->rupper) 450 ny = s->cy - s->rupper; 451 } 452 if (ny == 0) 453 return; 454 455 s->cy -= ny; 456 } 457 458 /* Cursor down by ny. */ 459 void 460 screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny) 461 { 462 struct screen *s = ctx->s; 463 464 if (ny == 0) 465 ny = 1; 466 467 if (s->cy > s->rlower) { 468 /* Below region. */ 469 if (ny > screen_size_y(s) - 1 - s->cy) 470 ny = screen_size_y(s) - 1 - s->cy; 471 } else { 472 /* Above region. */ 473 if (ny > s->rlower - s->cy) 474 ny = s->rlower - s->cy; 475 } 476 if (ny == 0) 477 return; 478 479 s->cy += ny; 480 } 481 482 /* Cursor right by nx. */ 483 void 484 screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx) 485 { 486 struct screen *s = ctx->s; 487 488 if (nx == 0) 489 nx = 1; 490 491 if (nx > screen_size_x(s) - 1 - s->cx) 492 nx = screen_size_x(s) - 1 - s->cx; 493 if (nx == 0) 494 return; 495 496 s->cx += nx; 497 } 498 499 /* Cursor left by nx. */ 500 void 501 screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx) 502 { 503 struct screen *s = ctx->s; 504 505 if (nx == 0) 506 nx = 1; 507 508 if (nx > s->cx) 509 nx = s->cx; 510 if (nx == 0) 511 return; 512 513 s->cx -= nx; 514 } 515 516 /* Backspace; cursor left unless at start of wrapped line when can move up. */ 517 void 518 screen_write_backspace(struct screen_write_ctx *ctx) 519 { 520 struct screen *s = ctx->s; 521 struct grid_line *gl; 522 523 if (s->cx == 0) { 524 if (s->cy == 0) 525 return; 526 gl = &s->grid->linedata[s->grid->hsize + s->cy - 1]; 527 if (gl->flags & GRID_LINE_WRAPPED) { 528 s->cy--; 529 s->cx = screen_size_x(s) - 1; 530 } 531 } else 532 s->cx--; 533 } 534 535 /* VT100 alignment test. */ 536 void 537 screen_write_alignmenttest(struct screen_write_ctx *ctx) 538 { 539 struct screen *s = ctx->s; 540 struct tty_ctx ttyctx; 541 struct grid_cell gc; 542 u_int xx, yy; 543 544 screen_write_initctx(ctx, &ttyctx); 545 546 memcpy(&gc, &grid_default_cell, sizeof gc); 547 gc.data = 'E'; 548 549 for (yy = 0; yy < screen_size_y(s); yy++) { 550 for (xx = 0; xx < screen_size_x(s); xx++) 551 grid_view_set_cell(s->grid, xx, yy, &gc); 552 } 553 554 s->cx = 0; 555 s->cy = 0; 556 557 s->rupper = 0; 558 559 s->rlower = screen_size_y(s) - 1; 560 561 tty_write(tty_cmd_alignmenttest, &ttyctx); 562 } 563 564 /* Insert nx characters. */ 565 void 566 screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) 567 { 568 struct screen *s = ctx->s; 569 struct tty_ctx ttyctx; 570 571 if (nx == 0) 572 nx = 1; 573 574 if (nx > screen_size_x(s) - s->cx) 575 nx = screen_size_x(s) - s->cx; 576 if (nx == 0) 577 return; 578 579 screen_write_initctx(ctx, &ttyctx); 580 581 if (s->cx <= screen_size_x(s) - 1) 582 grid_view_insert_cells(s->grid, s->cx, s->cy, nx); 583 584 ttyctx.num = nx; 585 tty_write(tty_cmd_insertcharacter, &ttyctx); 586 } 587 588 /* Delete nx characters. */ 589 void 590 screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx) 591 { 592 struct screen *s = ctx->s; 593 struct tty_ctx ttyctx; 594 595 if (nx == 0) 596 nx = 1; 597 598 if (nx > screen_size_x(s) - s->cx) 599 nx = screen_size_x(s) - s->cx; 600 if (nx == 0) 601 return; 602 603 screen_write_initctx(ctx, &ttyctx); 604 605 if (s->cx <= screen_size_x(s) - 1) 606 grid_view_delete_cells(s->grid, s->cx, s->cy, nx); 607 608 ttyctx.num = nx; 609 tty_write(tty_cmd_deletecharacter, &ttyctx); 610 } 611 612 /* Insert ny lines. */ 613 void 614 screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) 615 { 616 struct screen *s = ctx->s; 617 struct tty_ctx ttyctx; 618 619 if (ny == 0) 620 ny = 1; 621 622 if (s->cy < s->rupper || s->cy > s->rlower) { 623 if (ny > screen_size_y(s) - s->cy) 624 ny = screen_size_y(s) - s->cy; 625 if (ny == 0) 626 return; 627 628 screen_write_initctx(ctx, &ttyctx); 629 630 grid_view_insert_lines(s->grid, s->cy, ny); 631 632 ttyctx.num = ny; 633 tty_write(tty_cmd_insertline, &ttyctx); 634 return; 635 } 636 637 if (ny > s->rlower + 1 - s->cy) 638 ny = s->rlower + 1 - s->cy; 639 if (ny == 0) 640 return; 641 642 screen_write_initctx(ctx, &ttyctx); 643 644 if (s->cy < s->rupper || s->cy > s->rlower) 645 grid_view_insert_lines(s->grid, s->cy, ny); 646 else 647 grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny); 648 649 ttyctx.num = ny; 650 tty_write(tty_cmd_insertline, &ttyctx); 651 } 652 653 /* Delete ny lines. */ 654 void 655 screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) 656 { 657 struct screen *s = ctx->s; 658 struct tty_ctx ttyctx; 659 660 if (ny == 0) 661 ny = 1; 662 663 if (s->cy < s->rupper || s->cy > s->rlower) { 664 if (ny > screen_size_y(s) - s->cy) 665 ny = screen_size_y(s) - s->cy; 666 if (ny == 0) 667 return; 668 669 screen_write_initctx(ctx, &ttyctx); 670 671 grid_view_delete_lines(s->grid, s->cy, ny); 672 673 ttyctx.num = ny; 674 tty_write(tty_cmd_deleteline, &ttyctx); 675 return; 676 } 677 678 if (ny > s->rlower + 1 - s->cy) 679 ny = s->rlower + 1 - s->cy; 680 if (ny == 0) 681 return; 682 683 screen_write_initctx(ctx, &ttyctx); 684 685 if (s->cy < s->rupper || s->cy > s->rlower) 686 grid_view_delete_lines(s->grid, s->cy, ny); 687 else 688 grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny); 689 690 ttyctx.num = ny; 691 tty_write(tty_cmd_deleteline, &ttyctx); 692 } 693 694 /* Clear line at cursor. */ 695 void 696 screen_write_clearline(struct screen_write_ctx *ctx) 697 { 698 struct screen *s = ctx->s; 699 struct tty_ctx ttyctx; 700 701 screen_write_initctx(ctx, &ttyctx); 702 703 grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1); 704 705 tty_write(tty_cmd_clearline, &ttyctx); 706 } 707 708 /* Clear to end of line from cursor. */ 709 void 710 screen_write_clearendofline(struct screen_write_ctx *ctx) 711 { 712 struct screen *s = ctx->s; 713 struct tty_ctx ttyctx; 714 u_int sx; 715 716 screen_write_initctx(ctx, &ttyctx); 717 718 sx = screen_size_x(s); 719 720 if (s->cx <= sx - 1) 721 grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); 722 723 tty_write(tty_cmd_clearendofline, &ttyctx); 724 } 725 726 /* Clear to start of line from cursor. */ 727 void 728 screen_write_clearstartofline(struct screen_write_ctx *ctx) 729 { 730 struct screen *s = ctx->s; 731 struct tty_ctx ttyctx; 732 u_int sx; 733 734 screen_write_initctx(ctx, &ttyctx); 735 736 sx = screen_size_x(s); 737 738 if (s->cx > sx - 1) 739 grid_view_clear(s->grid, 0, s->cy, sx, 1); 740 else 741 grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); 742 743 tty_write(tty_cmd_clearstartofline, &ttyctx); 744 } 745 746 /* Move cursor to px,py. */ 747 void 748 screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py) 749 { 750 struct screen *s = ctx->s; 751 752 if (px > screen_size_x(s) - 1) 753 px = screen_size_x(s) - 1; 754 if (py > screen_size_y(s) - 1) 755 py = screen_size_y(s) - 1; 756 757 s->cx = px; 758 s->cy = py; 759 } 760 761 /* Set cursor mode. */ 762 void 763 screen_write_cursormode(struct screen_write_ctx *ctx, int state) 764 { 765 struct screen *s = ctx->s; 766 767 if (state) 768 s->mode |= MODE_CURSOR; 769 else 770 s->mode &= ~MODE_CURSOR; 771 } 772 773 /* Reverse index (up with scroll). */ 774 void 775 screen_write_reverseindex(struct screen_write_ctx *ctx) 776 { 777 struct screen *s = ctx->s; 778 struct tty_ctx ttyctx; 779 780 screen_write_initctx(ctx, &ttyctx); 781 782 if (s->cy == s->rupper) 783 grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); 784 else if (s->cy > 0) 785 s->cy--; 786 787 tty_write(tty_cmd_reverseindex, &ttyctx); 788 } 789 790 /* Set scroll region. */ 791 void 792 screen_write_scrollregion( 793 struct screen_write_ctx *ctx, u_int rupper, u_int rlower) 794 { 795 struct screen *s = ctx->s; 796 797 if (rupper > screen_size_y(s) - 1) 798 rupper = screen_size_y(s) - 1; 799 if (rlower > screen_size_y(s) - 1) 800 rlower = screen_size_y(s) - 1; 801 if (rupper >= rlower) /* cannot be one line */ 802 return; 803 804 /* Cursor moves to top-left. */ 805 s->cx = 0; 806 s->cy = 0; 807 808 s->rupper = rupper; 809 s->rlower = rlower; 810 } 811 812 /* Set insert mode. */ 813 void 814 screen_write_insertmode(struct screen_write_ctx *ctx, int state) 815 { 816 struct screen *s = ctx->s; 817 818 if (state) 819 s->mode |= MODE_INSERT; 820 else 821 s->mode &= ~MODE_INSERT; 822 } 823 824 /* Set mouse mode. */ 825 void 826 screen_write_mousemode(struct screen_write_ctx *ctx, int state) 827 { 828 struct screen *s = ctx->s; 829 830 if (state) 831 s->mode |= MODE_MOUSE; 832 else 833 s->mode &= ~MODE_MOUSE; 834 } 835 836 /* 837 * Line feed the screen only (don't update the tty). Used for printing single 838 * characters, where might want to let the scroll happen naturally. 839 */ 840 void 841 screen_write_linefeedscreen(struct screen_write_ctx *ctx, int wrapped) 842 { 843 struct screen *s = ctx->s; 844 struct grid_line *gl; 845 846 gl = &s->grid->linedata[s->grid->hsize + s->cy]; 847 if (wrapped) 848 gl->flags |= GRID_LINE_WRAPPED; 849 else 850 gl->flags &= ~GRID_LINE_WRAPPED; 851 852 if (s->cy == s->rlower) 853 grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); 854 else if (s->cy < screen_size_y(s) - 1) 855 s->cy++; 856 } 857 858 /* Line feed (down with scroll). */ 859 void 860 screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) 861 { 862 struct tty_ctx ttyctx; 863 864 screen_write_initctx(ctx, &ttyctx); 865 866 screen_write_linefeedscreen(ctx, wrapped); 867 868 tty_write(tty_cmd_linefeed, &ttyctx); 869 } 870 871 /* Carriage return (cursor to start of line). */ 872 void 873 screen_write_carriagereturn(struct screen_write_ctx *ctx) 874 { 875 struct screen *s = ctx->s; 876 877 s->cx = 0; 878 } 879 880 /* Set keypad cursor keys mode. */ 881 void 882 screen_write_kcursormode(struct screen_write_ctx *ctx, int state) 883 { 884 struct screen *s = ctx->s; 885 886 if (state) 887 s->mode |= MODE_KCURSOR; 888 else 889 s->mode &= ~MODE_KCURSOR; 890 } 891 892 /* Set keypad number keys mode. */ 893 void 894 screen_write_kkeypadmode(struct screen_write_ctx *ctx, int state) 895 { 896 struct screen *s = ctx->s; 897 898 if (state) 899 s->mode |= MODE_KKEYPAD; 900 else 901 s->mode &= ~MODE_KKEYPAD; 902 } 903 904 /* Clear to end of screen from cursor. */ 905 void 906 screen_write_clearendofscreen(struct screen_write_ctx *ctx) 907 { 908 struct screen *s = ctx->s; 909 struct tty_ctx ttyctx; 910 u_int sx, sy; 911 912 screen_write_initctx(ctx, &ttyctx); 913 914 sx = screen_size_x(s); 915 sy = screen_size_y(s); 916 917 if (s->cx <= sx - 1) 918 grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); 919 grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1)); 920 921 tty_write(tty_cmd_clearendofscreen, &ttyctx); 922 } 923 924 /* Clear to start of screen. */ 925 void 926 screen_write_clearstartofscreen(struct screen_write_ctx *ctx) 927 { 928 struct screen *s = ctx->s; 929 struct tty_ctx ttyctx; 930 u_int sx; 931 932 screen_write_initctx(ctx, &ttyctx); 933 934 sx = screen_size_x(s); 935 936 if (s->cy > 0) 937 grid_view_clear(s->grid, 0, 0, sx, s->cy); 938 if (s->cx > sx - 1) 939 grid_view_clear(s->grid, 0, s->cy, sx, 1); 940 else 941 grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); 942 943 tty_write(tty_cmd_clearstartofscreen, &ttyctx); 944 } 945 946 /* Clear entire screen. */ 947 void 948 screen_write_clearscreen(struct screen_write_ctx *ctx) 949 { 950 struct screen *s = ctx->s; 951 struct tty_ctx ttyctx; 952 953 screen_write_initctx(ctx, &ttyctx); 954 955 grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); 956 957 tty_write(tty_cmd_clearscreen, &ttyctx); 958 } 959 960 /* Write cell data. */ 961 void 962 screen_write_cell( 963 struct screen_write_ctx *ctx, const struct grid_cell *gc, u_char *udata) 964 { 965 struct screen *s = ctx->s; 966 struct window_pane *wp = ctx->wp; 967 struct grid *gd = s->grid; 968 struct tty_ctx ttyctx; 969 struct grid_utf8 gu, *tmp_gu; 970 u_int width, xx, i; 971 struct grid_cell tmp_gc, tmp_gc2, *tmp_gcp; 972 int insert = 0; 973 974 /* Ignore padding. */ 975 if (gc->flags & GRID_FLAG_PADDING) 976 return; 977 978 /* Find character width. */ 979 if (gc->flags & GRID_FLAG_UTF8) { 980 width = utf8_width(udata); 981 982 gu.width = width; 983 memcpy(&gu.data, udata, sizeof gu.data); 984 } else 985 width = 1; 986 987 /* If the width is zero, combine onto the previous character. */ 988 if (width == 0) { 989 if (s->cx == 0) 990 return; 991 tmp_gcp = grid_view_get_cell(gd, s->cx - 1, s->cy); 992 if (!(tmp_gcp->flags & GRID_FLAG_UTF8)) { 993 tmp_gcp->flags |= GRID_FLAG_UTF8; 994 memset(&gu.data, 0xff, sizeof gu.data); 995 *gu.data = tmp_gcp->data; 996 gu.width = 1; 997 grid_view_set_utf8(gd, s->cx - 1, s->cy, &gu); 998 } 999 tmp_gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); 1000 1001 for (i = 0; i < UTF8_SIZE; i++) { 1002 if (tmp_gu->data[i] == 0xff) 1003 break; 1004 } 1005 memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i); 1006 1007 /* Assume the previous character has just been input. */ 1008 screen_write_initctx(ctx, &ttyctx); 1009 ttyctx.ptr = udata; 1010 tty_write(tty_cmd_utf8character, &ttyctx); 1011 return; 1012 } 1013 1014 /* If the character is wider than the screen, don't print it. */ 1015 if (width > screen_size_x(s)) { 1016 memcpy(&tmp_gc, gc, sizeof tmp_gc); 1017 tmp_gc.data = '_'; 1018 width = 1; 1019 gc = &tmp_gc; 1020 } 1021 1022 /* If in insert mode, make space for the cells. */ 1023 if (s->mode & MODE_INSERT && s->cx <= screen_size_x(s) - width) { 1024 xx = screen_size_x(s) - s->cx - width; 1025 grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx); 1026 insert = 1; 1027 } 1028 1029 /* Check this will fit on the current line and wrap if not. */ 1030 if (s->cx > screen_size_x(s) - width) { 1031 /* 1032 * Don't update the terminal now, just update the screen and 1033 * leave the cursor to scroll naturally, unless this is only 1034 * part of the screen width. 1035 */ 1036 if (wp->xoff != 0 || wp->sx != screen_size_x(s)) 1037 screen_write_linefeed(ctx, 1); 1038 else 1039 screen_write_linefeedscreen(ctx, 1); 1040 s->cx = 0; /* carriage return */ 1041 } 1042 1043 /* Sanity checks. */ 1044 if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1) 1045 return; 1046 1047 /* Handle overwriting of UTF-8 characters. */ 1048 screen_write_overwrite(ctx); 1049 1050 /* 1051 * If the new character is UTF-8 wide, fill in padding cells. Have 1052 * already ensured there is enough room. 1053 */ 1054 for (xx = s->cx + 1; xx < s->cx + width; xx++) { 1055 tmp_gcp = grid_view_get_cell(gd, xx, s->cy); 1056 if (tmp_gcp != NULL) 1057 tmp_gcp->flags |= GRID_FLAG_PADDING; 1058 } 1059 1060 /* Set the cell. */ 1061 grid_view_set_cell(gd, s->cx, s->cy, gc); 1062 if (gc->flags & GRID_FLAG_UTF8) 1063 grid_view_set_utf8(gd, s->cx, s->cy, &gu); 1064 1065 /* Move the cursor. */ 1066 screen_write_initctx(ctx, &ttyctx); 1067 s->cx += width; 1068 1069 /* Draw to the screen if necessary. */ 1070 if (insert) { 1071 ttyctx.num = width; 1072 tty_write(tty_cmd_insertcharacter, &ttyctx); 1073 } 1074 ttyctx.utf8 = &gu; 1075 if (screen_check_selection(s, s->cx - width, s->cy)) { 1076 memcpy(&tmp_gc2, &s->sel.cell, sizeof tmp_gc2); 1077 tmp_gc2.data = gc->data; 1078 tmp_gc2.flags = gc->flags & 1079 ~(GRID_FLAG_FG256|GRID_FLAG_BG256); 1080 tmp_gc2.flags |= s->sel.cell.flags & 1081 (GRID_FLAG_FG256|GRID_FLAG_BG256); 1082 ttyctx.cell = &tmp_gc2; 1083 tty_write(tty_cmd_cell, &ttyctx); 1084 } else { 1085 ttyctx.cell = gc; 1086 tty_write(tty_cmd_cell, &ttyctx); 1087 } 1088 } 1089 1090 /* 1091 * UTF-8 wide characters are a bit of an annoyance. They take up more than one 1092 * cell on the screen, so following cells must not be drawn by marking them as 1093 * padding. 1094 * 1095 * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8 1096 * character, it is necessary to also overwrite any other cells which covered 1097 * by the same character. 1098 */ 1099 void 1100 screen_write_overwrite(struct screen_write_ctx *ctx) 1101 { 1102 struct screen *s = ctx->s; 1103 struct grid *gd = s->grid; 1104 const struct grid_cell *gc; 1105 const struct grid_utf8 *gu; 1106 u_int xx; 1107 1108 gc = grid_view_peek_cell(gd, s->cx, s->cy); 1109 if (gc->flags & GRID_FLAG_PADDING) { 1110 /* 1111 * A padding cell, so clear any following and leading padding 1112 * cells back to the character. Don't overwrite the current 1113 * cell as that happens later anyway. 1114 */ 1115 xx = s->cx + 1; 1116 while (--xx > 0) { 1117 gc = grid_view_peek_cell(gd, xx, s->cy); 1118 if (!(gc->flags & GRID_FLAG_PADDING)) 1119 break; 1120 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1121 } 1122 1123 /* Overwrite the character at the start of this padding. */ 1124 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1125 1126 /* Overwrite following padding cells. */ 1127 xx = s->cx; 1128 while (++xx < screen_size_x(s)) { 1129 gc = grid_view_peek_cell(gd, xx, s->cy); 1130 if (!(gc->flags & GRID_FLAG_PADDING)) 1131 break; 1132 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1133 } 1134 } else if (gc->flags & GRID_FLAG_UTF8) { 1135 gu = grid_view_peek_utf8(gd, s->cx, s->cy); 1136 if (gu->width > 1) { 1137 /* 1138 * An UTF-8 wide cell; overwrite following padding cells only. 1139 */ 1140 xx = s->cx; 1141 while (++xx < screen_size_x(s)) { 1142 gc = grid_view_peek_cell(gd, xx, s->cy); 1143 if (!(gc->flags & GRID_FLAG_PADDING)) 1144 break; 1145 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1146 } 1147 } 1148 } 1149 } 1150