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