1 /* $OpenBSD: grid.c,v 1.37 2014/04/16 23:05:38 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include "tmux.h" 25 26 /* 27 * Grid data. This is the basic data structure that represents what is shown on 28 * screen. 29 * 30 * A grid is a grid of cells (struct grid_cell). Lines are not allocated until 31 * cells in that line are written to. The grid is split into history and 32 * viewable data with the history starting at row (line) 0 and extending to 33 * (hsize - 1); from hsize to hsize + (sy - 1) is the viewable data. All 34 * functions in this file work on absolute coordinates, grid-view.c has 35 * functions which work on the screen data. 36 */ 37 38 /* Default grid cell data. */ 39 const struct grid_cell grid_default_cell = { 0, 0, 8, 8, (1 << 4) | 1, " " }; 40 41 #define grid_put_cell(gd, px, py, gc) do { \ 42 memcpy(&gd->linedata[py].celldata[px], \ 43 gc, sizeof gd->linedata[py].celldata[px]); \ 44 } while (0) 45 #define grid_put_utf8(gd, px, py, gc) do { \ 46 memcpy(&gd->linedata[py].utf8data[px], \ 47 gc, sizeof gd->linedata[py].utf8data[px]); \ 48 } while (0) 49 50 int grid_check_y(struct grid *, u_int); 51 52 #ifdef DEBUG 53 int 54 grid_check_y(struct grid *gd, u_int py) 55 { 56 if ((py) >= (gd)->hsize + (gd)->sy) 57 log_fatalx("y out of range: %u", py); 58 return (0); 59 } 60 #else 61 int 62 grid_check_y(struct grid *gd, u_int py) 63 { 64 if ((py) >= (gd)->hsize + (gd)->sy) { 65 log_debug("y out of range: %u", py); 66 return (-1); 67 } 68 return (0); 69 } 70 #endif 71 72 void grid_reflow_join(struct grid *, u_int *, struct grid_line *, u_int); 73 void grid_reflow_split(struct grid *, u_int *, struct grid_line *, u_int, 74 u_int); 75 void grid_reflow_move(struct grid *, u_int *, struct grid_line *); 76 size_t grid_string_cells_fg(const struct grid_cell *, int *); 77 size_t grid_string_cells_bg(const struct grid_cell *, int *); 78 void grid_string_cells_code(const struct grid_cell *, 79 const struct grid_cell *, char *, size_t, int); 80 81 /* Create a new grid. */ 82 struct grid * 83 grid_create(u_int sx, u_int sy, u_int hlimit) 84 { 85 struct grid *gd; 86 87 gd = xmalloc(sizeof *gd); 88 gd->sx = sx; 89 gd->sy = sy; 90 91 gd->flags = GRID_HISTORY; 92 93 gd->hsize = 0; 94 gd->hlimit = hlimit; 95 96 gd->linedata = xcalloc(gd->sy, sizeof *gd->linedata); 97 98 return (gd); 99 } 100 101 /* Destroy grid. */ 102 void 103 grid_destroy(struct grid *gd) 104 { 105 struct grid_line *gl; 106 u_int yy; 107 108 for (yy = 0; yy < gd->hsize + gd->sy; yy++) { 109 gl = &gd->linedata[yy]; 110 free(gl->celldata); 111 } 112 113 free(gd->linedata); 114 115 free(gd); 116 } 117 118 /* Compare grids. */ 119 int 120 grid_compare(struct grid *ga, struct grid *gb) 121 { 122 struct grid_line *gla, *glb; 123 struct grid_cell *gca, *gcb; 124 u_int xx, yy; 125 126 if (ga->sx != gb->sx || ga->sy != gb->sy) 127 return (1); 128 129 for (yy = 0; yy < ga->sy; yy++) { 130 gla = &ga->linedata[yy]; 131 glb = &gb->linedata[yy]; 132 if (gla->cellsize != glb->cellsize) 133 return (1); 134 for (xx = 0; xx < ga->sx; xx++) { 135 gca = &gla->celldata[xx]; 136 gcb = &glb->celldata[xx]; 137 if (memcmp(gca, gcb, sizeof (struct grid_cell)) != 0) 138 return (1); 139 } 140 } 141 142 return (0); 143 } 144 145 /* 146 * Collect lines from the history if at the limit. Free the top (oldest) 10% 147 * and shift up. 148 */ 149 void 150 grid_collect_history(struct grid *gd) 151 { 152 u_int yy; 153 154 if (gd->hsize < gd->hlimit) 155 return; 156 157 yy = gd->hlimit / 10; 158 if (yy < 1) 159 yy = 1; 160 161 grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy); 162 gd->hsize -= yy; 163 } 164 165 /* 166 * Scroll the entire visible screen, moving one line into the history. Just 167 * allocate a new line at the bottom and move the history size indicator. 168 */ 169 void 170 grid_scroll_history(struct grid *gd) 171 { 172 u_int yy; 173 174 yy = gd->hsize + gd->sy; 175 gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata); 176 memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]); 177 178 gd->hsize++; 179 } 180 181 /* Scroll a region up, moving the top line into the history. */ 182 void 183 grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower) 184 { 185 struct grid_line *gl_history, *gl_upper, *gl_lower; 186 u_int yy; 187 188 /* Create a space for a new line. */ 189 yy = gd->hsize + gd->sy; 190 gd->linedata = xrealloc(gd->linedata, yy + 1, sizeof *gd->linedata); 191 192 /* Move the entire screen down to free a space for this line. */ 193 gl_history = &gd->linedata[gd->hsize]; 194 memmove(gl_history + 1, gl_history, gd->sy * sizeof *gl_history); 195 196 /* Adjust the region and find its start and end. */ 197 upper++; 198 gl_upper = &gd->linedata[upper]; 199 lower++; 200 gl_lower = &gd->linedata[lower]; 201 202 /* Move the line into the history. */ 203 memcpy(gl_history, gl_upper, sizeof *gl_history); 204 205 /* Then move the region up and clear the bottom line. */ 206 memmove(gl_upper, gl_upper + 1, (lower - upper) * sizeof *gl_upper); 207 memset(gl_lower, 0, sizeof *gl_lower); 208 209 /* Move the history offset down over the line. */ 210 gd->hsize++; 211 } 212 213 /* Expand line to fit to cell. */ 214 void 215 grid_expand_line(struct grid *gd, u_int py, u_int sx) 216 { 217 struct grid_line *gl; 218 u_int xx; 219 220 gl = &gd->linedata[py]; 221 if (sx <= gl->cellsize) 222 return; 223 224 gl->celldata = xrealloc(gl->celldata, sx, sizeof *gl->celldata); 225 for (xx = gl->cellsize; xx < sx; xx++) 226 grid_put_cell(gd, xx, py, &grid_default_cell); 227 gl->cellsize = sx; 228 } 229 230 /* Peek at grid line. */ 231 const struct grid_line * 232 grid_peek_line(struct grid *gd, u_int py) 233 { 234 if (grid_check_y(gd, py) != 0) 235 return (NULL); 236 return (&gd->linedata[py]); 237 } 238 239 /* Get cell for reading. */ 240 const struct grid_cell * 241 grid_peek_cell(struct grid *gd, u_int px, u_int py) 242 { 243 if (grid_check_y(gd, py) != 0) 244 return (&grid_default_cell); 245 246 if (px >= gd->linedata[py].cellsize) 247 return (&grid_default_cell); 248 return (&gd->linedata[py].celldata[px]); 249 } 250 251 /* Get cell at relative position (for writing). */ 252 struct grid_cell * 253 grid_get_cell(struct grid *gd, u_int px, u_int py) 254 { 255 if (grid_check_y(gd, py) != 0) 256 return (NULL); 257 258 grid_expand_line(gd, py, px + 1); 259 return (&gd->linedata[py].celldata[px]); 260 } 261 262 /* Set cell at relative position. */ 263 void 264 grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) 265 { 266 if (grid_check_y(gd, py) != 0) 267 return; 268 269 grid_expand_line(gd, py, px + 1); 270 grid_put_cell(gd, px, py, gc); 271 } 272 273 /* Clear area. */ 274 void 275 grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny) 276 { 277 u_int xx, yy; 278 279 if (nx == 0 || ny == 0) 280 return; 281 282 if (px == 0 && nx == gd->sx) { 283 grid_clear_lines(gd, py, ny); 284 return; 285 } 286 287 if (grid_check_y(gd, py) != 0) 288 return; 289 if (grid_check_y(gd, py + ny - 1) != 0) 290 return; 291 292 for (yy = py; yy < py + ny; yy++) { 293 if (px >= gd->linedata[yy].cellsize) 294 continue; 295 if (px + nx >= gd->linedata[yy].cellsize) { 296 gd->linedata[yy].cellsize = px; 297 continue; 298 } 299 for (xx = px; xx < px + nx; xx++) { 300 if (xx >= gd->linedata[yy].cellsize) 301 break; 302 grid_put_cell(gd, xx, yy, &grid_default_cell); 303 } 304 } 305 } 306 307 /* Clear lines. This just frees and truncates the lines. */ 308 void 309 grid_clear_lines(struct grid *gd, u_int py, u_int ny) 310 { 311 struct grid_line *gl; 312 u_int yy; 313 314 if (ny == 0) 315 return; 316 317 if (grid_check_y(gd, py) != 0) 318 return; 319 if (grid_check_y(gd, py + ny - 1) != 0) 320 return; 321 322 for (yy = py; yy < py + ny; yy++) { 323 gl = &gd->linedata[yy]; 324 free(gl->celldata); 325 memset(gl, 0, sizeof *gl); 326 } 327 } 328 329 /* Move a group of lines. */ 330 void 331 grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny) 332 { 333 u_int yy; 334 335 if (ny == 0 || py == dy) 336 return; 337 338 if (grid_check_y(gd, py) != 0) 339 return; 340 if (grid_check_y(gd, py + ny - 1) != 0) 341 return; 342 if (grid_check_y(gd, dy) != 0) 343 return; 344 if (grid_check_y(gd, dy + ny - 1) != 0) 345 return; 346 347 /* Free any lines which are being replaced. */ 348 for (yy = dy; yy < dy + ny; yy++) { 349 if (yy >= py && yy < py + ny) 350 continue; 351 grid_clear_lines(gd, yy, 1); 352 } 353 354 memmove( 355 &gd->linedata[dy], &gd->linedata[py], ny * (sizeof *gd->linedata)); 356 357 /* Wipe any lines that have been moved (without freeing them). */ 358 for (yy = py; yy < py + ny; yy++) { 359 if (yy >= dy && yy < dy + ny) 360 continue; 361 memset(&gd->linedata[yy], 0, sizeof gd->linedata[yy]); 362 } 363 } 364 365 /* Move a group of cells. */ 366 void 367 grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx) 368 { 369 struct grid_line *gl; 370 u_int xx; 371 372 if (nx == 0 || px == dx) 373 return; 374 375 if (grid_check_y(gd, py) != 0) 376 return; 377 gl = &gd->linedata[py]; 378 379 grid_expand_line(gd, py, px + nx); 380 grid_expand_line(gd, py, dx + nx); 381 memmove( 382 &gl->celldata[dx], &gl->celldata[px], nx * sizeof *gl->celldata); 383 384 /* Wipe any cells that have been moved. */ 385 for (xx = px; xx < px + nx; xx++) { 386 if (xx >= dx && xx < dx + nx) 387 continue; 388 grid_put_cell(gd, xx, py, &grid_default_cell); 389 } 390 } 391 392 /* Get ANSI foreground sequence. */ 393 size_t 394 grid_string_cells_fg(const struct grid_cell *gc, int *values) 395 { 396 size_t n; 397 398 n = 0; 399 if (gc->flags & GRID_FLAG_FG256) { 400 values[n++] = 38; 401 values[n++] = 5; 402 values[n++] = gc->fg; 403 } else { 404 switch (gc->fg) { 405 case 0: 406 case 1: 407 case 2: 408 case 3: 409 case 4: 410 case 5: 411 case 6: 412 case 7: 413 values[n++] = gc->fg + 30; 414 break; 415 case 8: 416 values[n++] = 39; 417 break; 418 case 90: 419 case 91: 420 case 92: 421 case 93: 422 case 94: 423 case 95: 424 case 96: 425 case 97: 426 values[n++] = gc->fg; 427 break; 428 } 429 } 430 return (n); 431 } 432 433 /* Get ANSI background sequence. */ 434 size_t 435 grid_string_cells_bg(const struct grid_cell *gc, int *values) 436 { 437 size_t n; 438 439 n = 0; 440 if (gc->flags & GRID_FLAG_BG256) { 441 values[n++] = 48; 442 values[n++] = 5; 443 values[n++] = gc->bg; 444 } else { 445 switch (gc->bg) { 446 case 0: 447 case 1: 448 case 2: 449 case 3: 450 case 4: 451 case 5: 452 case 6: 453 case 7: 454 values[n++] = gc->bg + 40; 455 break; 456 case 8: 457 values[n++] = 49; 458 break; 459 case 100: 460 case 101: 461 case 102: 462 case 103: 463 case 104: 464 case 105: 465 case 106: 466 case 107: 467 values[n++] = gc->bg - 10; 468 break; 469 } 470 } 471 return (n); 472 } 473 474 /* 475 * Returns ANSI code to set particular attributes (colour, bold and so on) 476 * given a current state. The output buffer must be able to hold at least 57 477 * bytes. 478 */ 479 void 480 grid_string_cells_code(const struct grid_cell *lastgc, 481 const struct grid_cell *gc, char *buf, size_t len, int escape_c0) 482 { 483 int oldc[16], newc[16], s[32]; 484 size_t noldc, nnewc, n, i; 485 u_int attr = gc->attr; 486 u_int lastattr = lastgc->attr; 487 char tmp[64]; 488 489 struct { 490 u_int mask; 491 u_int code; 492 } attrs[] = { 493 { GRID_ATTR_BRIGHT, 1 }, 494 { GRID_ATTR_DIM, 2 }, 495 { GRID_ATTR_ITALICS, 3 }, 496 { GRID_ATTR_UNDERSCORE, 4 }, 497 { GRID_ATTR_BLINK, 5 }, 498 { GRID_ATTR_REVERSE, 7 }, 499 { GRID_ATTR_HIDDEN, 8 } 500 }; 501 n = 0; 502 503 /* If any attribute is removed, begin with 0. */ 504 for (i = 0; i < nitems(attrs); i++) { 505 if (!(attr & attrs[i].mask) && (lastattr & attrs[i].mask)) { 506 s[n++] = 0; 507 lastattr &= GRID_ATTR_CHARSET; 508 break; 509 } 510 } 511 /* For each attribute that is newly set, add its code. */ 512 for (i = 0; i < nitems(attrs); i++) { 513 if ((attr & attrs[i].mask) && !(lastattr & attrs[i].mask)) 514 s[n++] = attrs[i].code; 515 } 516 517 /* If the foreground c changed, append its parameters. */ 518 nnewc = grid_string_cells_fg(gc, newc); 519 noldc = grid_string_cells_fg(lastgc, oldc); 520 if (nnewc != noldc || 521 memcmp(newc,oldc, nnewc * sizeof newc[0]) != 0) { 522 for (i = 0; i < nnewc; i++) 523 s[n++] = newc[i]; 524 } 525 526 /* If the background c changed, append its parameters. */ 527 nnewc = grid_string_cells_bg(gc, newc); 528 noldc = grid_string_cells_bg(lastgc, oldc); 529 if (nnewc != noldc || 530 memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0) { 531 for (i = 0; i < nnewc; i++) 532 s[n++] = newc[i]; 533 } 534 535 /* If there are any parameters, append an SGR code. */ 536 *buf = '\0'; 537 if (n > 0) { 538 if (escape_c0) 539 strlcat(buf, "\\033[", len); 540 else 541 strlcat(buf, "\033[", len); 542 for (i = 0; i < n; i++) { 543 if (i + 1 < n) 544 xsnprintf(tmp, sizeof tmp, "%d;", s[i]); 545 else 546 xsnprintf(tmp, sizeof tmp, "%d", s[i]); 547 strlcat(buf, tmp, len); 548 } 549 strlcat(buf, "m", len); 550 } 551 552 /* Append shift in/shift out if needed. */ 553 if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) { 554 if (escape_c0) 555 strlcat(buf, "\\016", len); /* SO */ 556 else 557 strlcat(buf, "\016", len); /* SO */ 558 } 559 if (!(attr & GRID_ATTR_CHARSET) && (lastattr & GRID_ATTR_CHARSET)) { 560 if (escape_c0) 561 strlcat(buf, "\\017", len); /* SI */ 562 else 563 strlcat(buf, "\017", len); /* SI */ 564 } 565 } 566 567 /* Convert cells into a string. */ 568 char * 569 grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, 570 struct grid_cell **lastgc, int with_codes, int escape_c0, int trim) 571 { 572 const struct grid_cell *gc; 573 static struct grid_cell lastgc1; 574 struct utf8_data ud; 575 const char* data; 576 char *buf, code[128]; 577 size_t len, off, size, codelen; 578 u_int xx; 579 const struct grid_line *gl; 580 581 if (lastgc != NULL && *lastgc == NULL) { 582 memcpy(&lastgc1, &grid_default_cell, sizeof lastgc1); 583 *lastgc = &lastgc1; 584 } 585 586 len = 128; 587 buf = xmalloc(len); 588 off = 0; 589 590 gl = grid_peek_line(gd, py); 591 for (xx = px; xx < px + nx; xx++) { 592 if (gl == NULL || xx >= gl->cellsize) 593 break; 594 gc = &gl->celldata[xx]; 595 if (gc->flags & GRID_FLAG_PADDING) 596 continue; 597 grid_cell_get(gc, &ud); 598 599 if (with_codes) { 600 grid_string_cells_code(*lastgc, gc, code, sizeof code, 601 escape_c0); 602 codelen = strlen(code); 603 memcpy(*lastgc, gc, sizeof *gc); 604 } else 605 codelen = 0; 606 607 data = ud.data; 608 size = ud.size; 609 if (escape_c0 && size == 1 && *data == '\\') { 610 data = "\\\\"; 611 size = 2; 612 } 613 614 while (len < off + size + codelen + 1) { 615 buf = xrealloc(buf, 2, len); 616 len *= 2; 617 } 618 619 if (codelen != 0) { 620 memcpy(buf + off, code, codelen); 621 off += codelen; 622 } 623 memcpy(buf + off, data, size); 624 off += size; 625 } 626 627 if (trim) { 628 while (off > 0 && buf[off - 1] == ' ') 629 off--; 630 } 631 buf[off] = '\0'; 632 633 return (buf); 634 } 635 636 /* 637 * Duplicate a set of lines between two grids. If there aren't enough lines in 638 * either source or destination, the number of lines is limited to the number 639 * available. 640 */ 641 void 642 grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy, 643 u_int ny) 644 { 645 struct grid_line *dstl, *srcl; 646 u_int yy; 647 648 if (dy + ny > dst->hsize + dst->sy) 649 ny = dst->hsize + dst->sy - dy; 650 if (sy + ny > src->hsize + src->sy) 651 ny = src->hsize + src->sy - sy; 652 grid_clear_lines(dst, dy, ny); 653 654 for (yy = 0; yy < ny; yy++) { 655 srcl = &src->linedata[sy]; 656 dstl = &dst->linedata[dy]; 657 658 memcpy(dstl, srcl, sizeof *dstl); 659 if (srcl->cellsize != 0) { 660 dstl->celldata = xcalloc( 661 srcl->cellsize, sizeof *dstl->celldata); 662 memcpy(dstl->celldata, srcl->celldata, 663 srcl->cellsize * sizeof *dstl->celldata); 664 } 665 666 sy++; 667 dy++; 668 } 669 } 670 671 /* Join line data. */ 672 void 673 grid_reflow_join(struct grid *dst, u_int *py, struct grid_line *src_gl, 674 u_int new_x) 675 { 676 struct grid_line *dst_gl = &dst->linedata[(*py) - 1]; 677 u_int left, to_copy, ox, nx; 678 679 /* How much is left on the old line? */ 680 left = new_x - dst_gl->cellsize; 681 682 /* Work out how much to append. */ 683 to_copy = src_gl->cellsize; 684 if (to_copy > left) 685 to_copy = left; 686 ox = dst_gl->cellsize; 687 nx = ox + to_copy; 688 689 /* Resize the destination line. */ 690 dst_gl->celldata = xrealloc(dst_gl->celldata, nx, 691 sizeof *dst_gl->celldata); 692 dst_gl->cellsize = nx; 693 694 /* Append as much as possible. */ 695 memcpy(&dst_gl->celldata[ox], &src_gl->celldata[0], 696 to_copy * sizeof src_gl->celldata[0]); 697 698 /* If there is any left in the source, split it. */ 699 if (src_gl->cellsize > to_copy) { 700 dst_gl->flags |= GRID_LINE_WRAPPED; 701 702 src_gl->cellsize -= to_copy; 703 grid_reflow_split(dst, py, src_gl, new_x, to_copy); 704 } 705 } 706 707 /* Split line data. */ 708 void 709 grid_reflow_split(struct grid *dst, u_int *py, struct grid_line *src_gl, 710 u_int new_x, u_int offset) 711 { 712 struct grid_line *dst_gl = NULL; 713 u_int to_copy; 714 715 /* Loop and copy sections of the source line. */ 716 while (src_gl->cellsize > 0) { 717 /* Create new line. */ 718 if (*py >= dst->hsize + dst->sy) 719 grid_scroll_history(dst); 720 dst_gl = &dst->linedata[*py]; 721 (*py)++; 722 723 /* How much should we copy? */ 724 to_copy = new_x; 725 if (to_copy > src_gl->cellsize) 726 to_copy = src_gl->cellsize; 727 728 /* Expand destination line. */ 729 dst_gl->celldata = xmalloc(to_copy * sizeof *dst_gl->celldata); 730 dst_gl->cellsize = to_copy; 731 dst_gl->flags |= GRID_LINE_WRAPPED; 732 733 /* Copy the data. */ 734 memcpy(&dst_gl->celldata[0], &src_gl->celldata[offset], 735 to_copy * sizeof dst_gl->celldata[0]); 736 737 /* Move offset and reduce old line size. */ 738 offset += to_copy; 739 src_gl->cellsize -= to_copy; 740 } 741 742 /* Last line is not wrapped. */ 743 if (dst_gl != NULL) 744 dst_gl->flags &= ~GRID_LINE_WRAPPED; 745 } 746 747 /* Move line data. */ 748 void 749 grid_reflow_move(struct grid *dst, u_int *py, struct grid_line *src_gl) 750 { 751 struct grid_line *dst_gl; 752 753 /* Create new line. */ 754 if (*py >= dst->hsize + dst->sy) 755 grid_scroll_history(dst); 756 dst_gl = &dst->linedata[*py]; 757 (*py)++; 758 759 /* Copy the old line. */ 760 memcpy(dst_gl, src_gl, sizeof *dst_gl); 761 dst_gl->flags &= ~GRID_LINE_WRAPPED; 762 763 /* Clear old line. */ 764 src_gl->celldata = NULL; 765 } 766 767 /* 768 * Reflow lines from src grid into dst grid of width new_x. Returns number of 769 * lines fewer in the visible area. The source grid is destroyed. 770 */ 771 u_int 772 grid_reflow(struct grid *dst, struct grid *src, u_int new_x) 773 { 774 u_int py, sy, line; 775 int previous_wrapped; 776 struct grid_line *src_gl; 777 778 py = 0; 779 sy = src->sy; 780 781 previous_wrapped = 0; 782 for (line = 0; line < sy + src->hsize; line++) { 783 src_gl = src->linedata + line; 784 if (!previous_wrapped) { 785 /* Wasn't wrapped. If smaller, move to destination. */ 786 if (src_gl->cellsize <= new_x) 787 grid_reflow_move(dst, &py, src_gl); 788 else 789 grid_reflow_split(dst, &py, src_gl, new_x, 0); 790 } else { 791 /* Previous was wrapped. Try to join. */ 792 grid_reflow_join(dst, &py, src_gl, new_x); 793 } 794 previous_wrapped = src_gl->flags & GRID_LINE_WRAPPED; 795 } 796 797 grid_destroy(src); 798 799 if (py > sy) 800 return (0); 801 return (sy - py); 802 } 803