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