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