1 /* $NetBSD: refresh.c,v 1.9 1997/09/12 21:08:24 phil Exp $ */ 2 3 /* 4 * Copyright (c) 1981, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)refresh.c 8.7 (Berkeley) 8/13/94"; 40 #else 41 __RCSID("$NetBSD: refresh.c,v 1.9 1997/09/12 21:08:24 phil Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <string.h> 46 47 #include "curses.h" 48 49 static int curwin; 50 static short ly, lx; 51 52 static void domvcur __P((int, int, int, int)); 53 static int makech __P((WINDOW *, int)); 54 static void quickch __P((WINDOW *)); 55 static void scrolln __P((WINDOW *, int, int, int, int, int)); 56 57 /* 58 * wrefresh -- 59 * Make the current screen look like "win" over the area coverd by 60 * win. 61 */ 62 int 63 wrefresh(win) 64 register WINDOW *win; 65 { 66 register __LINE *wlp; 67 register int retval; 68 register short wy; 69 int dnum; 70 71 /* Check if we need to restart ... */ 72 if (__endwin) { 73 __endwin = 0; 74 __restartwin(); 75 } 76 77 /* Initialize loop parameters. */ 78 ly = curscr->cury; 79 lx = curscr->curx; 80 wy = 0; 81 curwin = (win == curscr); 82 83 if (!curwin) 84 for (wy = 0; wy < win->maxy; wy++) { 85 wlp = win->lines[wy]; 86 if (wlp->flags & __ISDIRTY) 87 wlp->hash = __hash((char *)wlp->line, 88 win->maxx * __LDATASIZE); 89 } 90 91 if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) { 92 if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) { 93 tputs(CL, 0, __cputchar); 94 ly = 0; 95 lx = 0; 96 if (!curwin) { 97 curscr->flags &= ~__CLEAROK; 98 curscr->cury = 0; 99 curscr->curx = 0; 100 werase(curscr); 101 } 102 __touchwin(win); 103 } 104 win->flags &= ~__CLEAROK; 105 } 106 if (!CA) { 107 if (win->curx != 0) 108 putchar('\n'); 109 if (!curwin) 110 werase(curscr); 111 } 112 #ifdef DEBUG 113 __CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin); 114 __CTRACE("wrefresh: \tfirstch\tlastch\n"); 115 #endif 116 117 #ifndef NOQCH 118 if ((win->flags & __FULLWIN) && !curwin) { 119 /* 120 * Invoke quickch() only if more than a quarter of the lines 121 * in the window are dirty. 122 */ 123 for (wy = 0, dnum = 0; wy < win->maxy; wy++) 124 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) 125 dnum++; 126 if (!__noqch && dnum > (int) win->maxy / 4) 127 quickch(win); 128 } 129 #endif 130 131 #ifdef DEBUG 132 { int i, j; 133 __CTRACE("#####################################\n"); 134 for (i = 0; i < curscr->maxy; i++) { 135 __CTRACE("C: %d:", i); 136 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 137 for (j = 0; j < curscr->maxx; j++) 138 __CTRACE("%c", 139 curscr->lines[i]->line[j].ch); 140 __CTRACE("\n"); 141 for (j = 0; j < curscr->maxx; j++) 142 __CTRACE("%x", 143 curscr->lines[i]->line[j].attr); 144 __CTRACE("\n"); 145 __CTRACE("W: %d:", i); 146 __CTRACE(" 0x%x \n", win->lines[i]->hash); 147 __CTRACE(" 0x%x ", win->lines[i]->flags); 148 for (j = 0; j < win->maxx; j++) 149 __CTRACE("%c", 150 win->lines[i]->line[j].ch); 151 __CTRACE("\n"); 152 for (j = 0; j < win->maxx; j++) 153 __CTRACE("%x", 154 win->lines[i]->line[j].attr); 155 __CTRACE("\n"); 156 } 157 } 158 #endif /* DEBUG */ 159 160 for (wy = 0; wy < win->maxy; wy++) { 161 #ifdef DEBUG 162 __CTRACE("%d\t%d\t%d\n", 163 wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp); 164 #endif 165 if (!curwin) 166 curscr->lines[wy]->hash = win->lines[wy]->hash; 167 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) { 168 if (makech(win, wy) == ERR) 169 return (ERR); 170 else { 171 if (*win->lines[wy]->firstchp >= win->ch_off) 172 *win->lines[wy]->firstchp = win->maxx + 173 win->ch_off; 174 if (*win->lines[wy]->lastchp < win->maxx + 175 win->ch_off) 176 *win->lines[wy]->lastchp = win->ch_off; 177 if (*win->lines[wy]->lastchp < 178 *win->lines[wy]->firstchp) { 179 #ifdef DEBUG 180 __CTRACE("wrefresh: line %d notdirty \n", wy); 181 #endif 182 win->lines[wy]->flags &= ~__ISDIRTY; 183 } 184 } 185 186 } 187 #ifdef DEBUG 188 __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp, 189 *win->lines[wy]->lastchp); 190 #endif 191 } 192 193 #ifdef DEBUG 194 __CTRACE("refresh: ly=%d, lx=%d\n", ly, lx); 195 #endif 196 197 if (win == curscr) 198 domvcur(ly, lx, win->cury, win->curx); 199 else { 200 if (win->flags & __LEAVEOK) { 201 curscr->cury = ly; 202 curscr->curx = lx; 203 ly -= win->begy; 204 lx -= win->begx; 205 if (ly >= 0 && ly < win->maxy && lx >= 0 && 206 lx < win->maxx) { 207 win->cury = ly; 208 win->curx = lx; 209 } else 210 win->cury = win->curx = 0; 211 } else { 212 domvcur(ly, lx, win->cury + win->begy, 213 win->curx + win->begx); 214 curscr->cury = win->cury + win->begy; 215 curscr->curx = win->curx + win->begx; 216 } 217 } 218 retval = OK; 219 220 (void)fflush(stdout); 221 return (retval); 222 } 223 224 /* 225 * makech -- 226 * Make a change on the screen. 227 */ 228 static int 229 makech(win, wy) 230 register WINDOW *win; 231 int wy; 232 { 233 static __LDATA blank = {' ', 0}; 234 __LDATA *nsp, *csp, *cp, *cep; 235 u_int force; 236 int clsp, nlsp; /* Last space in lines. */ 237 int lch, wx, y; 238 char *ce; 239 240 #ifdef __GNUC__ 241 nlsp = 0; /* XXX gcc -Wuninitialized */ 242 #endif 243 /* Is the cursor still on the end of the last line? */ 244 if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) { 245 domvcur(ly, lx, ly + 1, 0); 246 ly++; 247 lx = 0; 248 } 249 wx = *win->lines[wy]->firstchp - win->ch_off; 250 if (wx < 0) 251 wx = 0; 252 else if (wx >= win->maxx) 253 return (OK); 254 lch = *win->lines[wy]->lastchp - win->ch_off; 255 if (lch < 0) 256 return (OK); 257 else if (lch >= (int) win->maxx) 258 lch = win->maxx - 1; 259 y = wy + win->begy; 260 261 if (curwin) 262 csp = ␣ 263 else 264 csp = &curscr->lines[wy + win->begy]->line[wx + win->begx]; 265 266 nsp = &win->lines[wy]->line[wx]; 267 force = win->lines[wy]->flags & __FORCEPAINT; 268 win->lines[wy]->flags &= ~__FORCEPAINT; 269 if (CE && !curwin) { 270 for (cp = &win->lines[wy]->line[win->maxx - 1]; 271 cp->ch == ' ' && cp->attr == 0; cp--) 272 if (cp <= win->lines[wy]->line) 273 break; 274 nlsp = cp - win->lines[wy]->line; 275 } 276 if (!curwin) 277 ce = CE; 278 else 279 ce = NULL; 280 281 if (force) { 282 if (CM) 283 tputs(tgoto(CM, lx, ly), 0, __cputchar); 284 else { 285 tputs(HO, 0, __cputchar); 286 __mvcur(0, 0, ly, lx, 1); 287 } 288 } 289 290 while (wx <= lch) { 291 if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 292 if (wx <= lch) { 293 while (wx <= lch && 294 memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 295 nsp++; 296 if (!curwin) 297 ++csp; 298 ++wx; 299 } 300 continue; 301 } 302 break; 303 } 304 domvcur(ly, lx, y, wx + win->begx); 305 306 #ifdef DEBUG 307 __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n", 308 wx, ly, lx, y, wx + win->begx, force); 309 #endif 310 ly = y; 311 lx = wx + win->begx; 312 while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) 313 && wx <= lch) { 314 315 if (ce != NULL && 316 win->maxx + win->begx == curscr->maxx && 317 wx >= nlsp && nsp->ch == ' ' && nsp->attr == 0) { 318 /* Check for clear to end-of-line. */ 319 cep = &curscr->lines[wy]->line[win->maxx - 1]; 320 while (cep->ch == ' ' && cep->attr == 0) 321 if (cep-- <= csp) 322 break; 323 clsp = cep - curscr->lines[wy]->line - 324 win->begx * __LDATASIZE; 325 #ifdef DEBUG 326 __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 327 #endif 328 if ((clsp - nlsp >= strlen(CE) 329 && clsp < win->maxx * __LDATASIZE) || 330 wy == win->maxy - 1) { 331 if (curscr->flags & __WSTANDOUT) { 332 tputs(SE, 0, __cputchar); 333 curscr->flags &= ~__WSTANDOUT; 334 } 335 tputs(CE, 0, __cputchar); 336 lx = wx + win->begx; 337 while (wx++ <= clsp) { 338 csp->ch = ' '; 339 csp->attr = 0; 340 csp++; 341 } 342 return (OK); 343 } 344 ce = NULL; 345 } 346 347 /* 348 * Enter/exit standout mode as appropriate. 349 * XXX 350 * Should use UC if SO/SE not available. 351 */ 352 if (nsp->attr & __STANDOUT) { 353 if (!(curscr->flags & __WSTANDOUT) && 354 SO != NULL && SE != NULL) { 355 tputs(SO, 0, __cputchar); 356 curscr->flags |= __WSTANDOUT; 357 } 358 } else 359 if (curscr->flags & __WSTANDOUT && 360 SE != NULL) { 361 tputs(SE, 0, __cputchar); 362 curscr->flags &= ~__WSTANDOUT; 363 } 364 365 wx++; 366 if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) 367 if (win->flags & __SCROLLOK) { 368 if (curscr->flags & __WSTANDOUT 369 && win->flags & __ENDLINE) 370 if (!MS) { 371 tputs(SE, 0, 372 __cputchar); 373 curscr->flags &= 374 ~__WSTANDOUT; 375 } 376 if (!(win->flags & __SCROLLWIN)) { 377 if (!curwin) { 378 csp->attr = nsp->attr; 379 putchar(csp->ch = nsp->ch); 380 } else 381 putchar(nsp->ch); 382 } 383 if (wx + win->begx < curscr->maxx) { 384 domvcur(ly, wx + win->begx, 385 win->begy + win->maxy - 1, 386 win->begx + win->maxx - 1); 387 } 388 ly = win->begy + win->maxy - 1; 389 lx = win->begx + win->maxx - 1; 390 return (OK); 391 } 392 if (wx < win->maxx || wy < win->maxy - 1 || 393 !(win->flags & __SCROLLWIN)) { 394 if (!curwin) { 395 csp->attr = nsp->attr; 396 putchar(csp->ch = nsp->ch); 397 csp++; 398 } else 399 putchar(nsp->ch); 400 } 401 #ifdef DEBUG 402 __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); 403 #endif 404 if (UC && (nsp->attr & __STANDOUT)) { 405 putchar('\b'); 406 tputs(UC, 0, __cputchar); 407 } 408 nsp++; 409 #ifdef DEBUG 410 __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 411 #endif 412 } 413 if (lx == wx + win->begx) /* If no change. */ 414 break; 415 lx = wx + win->begx; 416 if (lx >= COLS && AM) 417 lx = COLS - 1; 418 else if (wx >= win->maxx) { 419 domvcur(ly, lx, ly, win->maxx + win->begx - 1); 420 lx = win->maxx + win->begx - 1; 421 } 422 423 #ifdef DEBUG 424 __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 425 #endif 426 } 427 428 /* Don't leave the screen in standout mode. */ 429 if (curscr->flags & __WSTANDOUT) { 430 tputs(SE, 0, __cputchar); 431 curscr->flags &= ~__WSTANDOUT; 432 } 433 return (OK); 434 } 435 436 /* 437 * domvcur -- 438 * Do a mvcur, leaving standout mode if necessary. 439 */ 440 static void 441 domvcur(oy, ox, ny, nx) 442 int oy, ox, ny, nx; 443 { 444 if (curscr->flags & __WSTANDOUT && !MS) { 445 tputs(SE, 0, __cputchar); 446 curscr->flags &= ~__WSTANDOUT; 447 } 448 449 __mvcur(oy, ox, ny, nx, 1); 450 } 451 452 /* 453 * Quickch() attempts to detect a pattern in the change of the window 454 * in order to optimize the change, e.g., scroll n lines as opposed to 455 * repainting the screen line by line. 456 */ 457 458 static void 459 quickch(win) 460 WINDOW *win; 461 { 462 #define THRESH (int) win->maxy / 4 463 464 register __LINE *clp, *tmp1, *tmp2; 465 register int bsize, curs, curw, starts, startw, i, j; 466 int n, target, cur_period, bot, top, sc_region; 467 __LDATA buf[1024]; 468 u_int blank_hash; 469 470 #ifdef __GNUC__ 471 curs = curw = starts = startw = 0; /* XXX gcc -Wuninitialized */ 472 #endif 473 /* 474 * Find how many lines from the top of the screen are unchanged. 475 */ 476 for (top = 0; top < win->maxy; top++) 477 if (win->lines[top]->flags & __FORCEPAINT || 478 win->lines[top]->hash != curscr->lines[top]->hash 479 || memcmp(win->lines[top]->line, 480 curscr->lines[top]->line, 481 win->maxx * __LDATASIZE) != 0) 482 break; 483 else 484 win->lines[top]->flags &= ~__ISDIRTY; 485 /* 486 * Find how many lines from bottom of screen are unchanged. 487 */ 488 for (bot = win->maxy - 1; bot >= 0; bot--) 489 if (win->lines[bot]->flags & __FORCEPAINT || 490 win->lines[bot]->hash != curscr->lines[bot]->hash 491 || memcmp(win->lines[bot]->line, 492 curscr->lines[bot]->line, 493 win->maxx * __LDATASIZE) != 0) 494 break; 495 else 496 win->lines[bot]->flags &= ~__ISDIRTY; 497 498 #ifdef NO_JERKINESS 499 /* 500 * If we have a bottom unchanged region return. Scrolling the 501 * bottom region up and then back down causes a screen jitter. 502 * This will increase the number of characters sent to the screen 503 * but it looks better. 504 */ 505 if (bot < win->maxy - 1) 506 return; 507 #endif /* NO_JERKINESS */ 508 509 /* 510 * Search for the largest block of text not changed. 511 * Invariants of the loop: 512 * - Startw is the index of the beginning of the examined block in win. 513 * - Starts is the index of the beginning of the examined block in 514 * curscr. 515 * - Curs is the index of one past the end of the exmined block in win. 516 * - Curw is the index of one past the end of the exmined block in 517 * curscr. 518 * - bsize is the current size of the examined block. 519 */ 520 for (bsize = bot - top; bsize >= THRESH; bsize--) { 521 for (startw = top; startw <= bot - bsize; startw++) 522 for (starts = top; starts <= bot - bsize; 523 starts++) { 524 for (curw = startw, curs = starts; 525 curs < starts + bsize; curw++, curs++) 526 if (win->lines[curw]->flags & 527 __FORCEPAINT || 528 (win->lines[curw]->hash != 529 curscr->lines[curs]->hash || 530 memcmp(win->lines[curw]->line, 531 curscr->lines[curs]->line, 532 win->maxx * __LDATASIZE) != 0)) 533 break; 534 if (curs == starts + bsize) 535 goto done; 536 } 537 } 538 done: 539 /* Did not find anything */ 540 if (bsize < THRESH) 541 return; 542 543 #ifdef DEBUG 544 __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 545 bsize, starts, startw, curw, curs, top, bot); 546 #endif 547 548 /* 549 * Make sure that there is no overlap between the bottom and top 550 * regions and the middle scrolled block. 551 */ 552 if (bot < curs) 553 bot = curs - 1; 554 if (top > starts) 555 top = starts; 556 557 n = startw - starts; 558 559 #ifdef DEBUG 560 __CTRACE("#####################################\n"); 561 for (i = 0; i < curscr->maxy; i++) { 562 __CTRACE("C: %d:", i); 563 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 564 for (j = 0; j < curscr->maxx; j++) 565 __CTRACE("%c", 566 curscr->lines[i]->line[j].ch); 567 __CTRACE("\n"); 568 for (j = 0; j < curscr->maxx; j++) 569 __CTRACE("%x", 570 curscr->lines[i]->line[j].attr); 571 __CTRACE("\n"); 572 __CTRACE("W: %d:", i); 573 __CTRACE(" 0x%x \n", win->lines[i]->hash); 574 __CTRACE(" 0x%x ", win->lines[i]->flags); 575 for (j = 0; j < win->maxx; j++) 576 __CTRACE("%c", 577 win->lines[i]->line[j].ch); 578 __CTRACE("\n"); 579 for (j = 0; j < win->maxx; j++) 580 __CTRACE("%x", 581 win->lines[i]->line[j].attr); 582 __CTRACE("\n"); 583 } 584 #endif 585 586 /* So we don't have to call __hash() each time */ 587 for (i = 0; i < win->maxx; i++) { 588 buf[i].ch = ' '; 589 buf[i].attr = 0; 590 } 591 blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE); 592 593 /* 594 * Perform the rotation to maintain the consistency of curscr. 595 * This is hairy since we are doing an *in place* rotation. 596 * Invariants of the loop: 597 * - I is the index of the current line. 598 * - Target is the index of the target of line i. 599 * - Tmp1 points to current line (i). 600 * - Tmp2 and points to target line (target); 601 * - Cur_period is the index of the end of the current period. 602 * (see below). 603 * 604 * There are 2 major issues here that make this rotation non-trivial: 605 * 1. Scrolling in a scrolling region bounded by the top 606 * and bottom regions determined (whose size is sc_region). 607 * 2. As a result of the use of the mod function, there may be a 608 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 609 * 0 to 2, which then causes all odd lines not to be rotated. 610 * To remedy this, an index of the end ( = beginning) of the 611 * current 'period' is kept, cur_period, and when it is reached, 612 * the next period is started from cur_period + 1 which is 613 * guaranteed not to have been reached since that would mean that 614 * all records would have been reached. (think about it...). 615 * 616 * Lines in the rotation can have 3 attributes which are marked on the 617 * line so that curscr is consistent with the visual screen. 618 * 1. Not dirty -- lines inside the scrolled block, top region or 619 * bottom region. 620 * 2. Blank lines -- lines in the differential of the scrolling 621 * region adjacent to top and bot regions 622 * depending on scrolling direction. 623 * 3. Dirty line -- all other lines are marked dirty. 624 */ 625 sc_region = bot - top + 1; 626 i = top; 627 tmp1 = curscr->lines[top]; 628 cur_period = top; 629 for (j = top; j <= bot; j++) { 630 target = (i - top + n + sc_region) % sc_region + top; 631 tmp2 = curscr->lines[target]; 632 curscr->lines[target] = tmp1; 633 /* Mark block as clean and blank out scrolled lines. */ 634 clp = curscr->lines[target]; 635 #ifdef DEBUG 636 __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 637 n, startw, curw, i, target); 638 #endif 639 if ((target >= startw && target < curw) || target < top 640 || target > bot) { 641 #ifdef DEBUG 642 __CTRACE("-- notdirty"); 643 #endif 644 win->lines[target]->flags &= ~__ISDIRTY; 645 } else if ((n > 0 && target >= top && target < top + n) || 646 (n < 0 && target <= bot && target > bot + n)) { 647 if (clp->hash != blank_hash || memcmp(clp->line, 648 buf, win->maxx * __LDATASIZE) !=0) { 649 (void)memcpy(clp->line, buf, 650 win->maxx * __LDATASIZE); 651 #ifdef DEBUG 652 __CTRACE("-- blanked out: dirty"); 653 #endif 654 clp->hash = blank_hash; 655 __touchline(win, target, 0, win->maxx - 1, 0); 656 } else { 657 __touchline(win, target, 0, win->maxx - 1, 0); 658 #ifdef DEBUG 659 __CTRACE(" -- blank line already: dirty"); 660 #endif 661 } 662 } else { 663 #ifdef DEBUG 664 __CTRACE(" -- dirty"); 665 #endif 666 __touchline(win, target, 0, win->maxx - 1, 0); 667 } 668 #ifdef DEBUG 669 __CTRACE("\n"); 670 #endif 671 if (target == cur_period) { 672 i = target + 1; 673 tmp1 = curscr->lines[i]; 674 cur_period = i; 675 } else { 676 tmp1 = tmp2; 677 i = target; 678 } 679 } 680 #ifdef DEBUG 681 __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 682 for (i = 0; i < curscr->maxy; i++) { 683 __CTRACE("C: %d:", i); 684 for (j = 0; j < curscr->maxx; j++) 685 __CTRACE("%c", 686 curscr->lines[i]->line[j].ch); 687 __CTRACE("\n"); 688 __CTRACE("W: %d:", i); 689 for (j = 0; j < win->maxx; j++) 690 __CTRACE("%c", win->lines[i]->line[j].ch); 691 __CTRACE("\n"); 692 } 693 #endif 694 if (n != 0) { 695 WINDOW *wp; 696 scrolln(win, starts, startw, curs, bot, top); 697 /* 698 * Need to repoint any subwindow lines to the rotated 699 * line structured. 700 */ 701 for (wp = win->nextp; wp != win; wp = wp->nextp) 702 __set_subwin(win, wp); 703 } 704 } 705 706 /* 707 * scrolln -- 708 * Scroll n lines, where n is starts - startw. 709 */ 710 static void 711 scrolln(win, starts, startw, curs, bot, top) 712 WINDOW *win; 713 int starts, startw, curs, bot, top; 714 { 715 int i, oy, ox, n; 716 717 oy = curscr->cury; 718 ox = curscr->curx; 719 n = starts - startw; 720 721 /* 722 * XXX 723 * The initial tests that set __noqch don't let us reach here unless 724 * we have either CS + HO + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr 725 * scrolling can only shift the entire scrolling region, not just a 726 * part of it, which means that the quickch() routine is going to be 727 * sadly disappointed in us if we don't have CS as well. 728 * 729 * If CS, HO and SF/sf are set, can use the scrolling region. Because 730 * the cursor position after CS is undefined, we need HO which gives us 731 * the ability to move to somewhere without knowledge of the current 732 * location of the cursor. Still call __mvcur() anyway, to update its 733 * idea of where the cursor is. 734 * 735 * When the scrolling region has been set, the cursor has to be at the 736 * last line of the region to make the scroll happen. 737 * 738 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr 739 * or al/dl, and, some terminals have AL/DL, sf/sr, and CS, but not 740 * SF/SR. So, if we're scrolling almost all of the screen, try and use 741 * AL/DL, otherwise use the scrolling region. The "almost all" is a 742 * shameless hack for vi. 743 */ 744 if (n > 0) { 745 if (CS != NULL && HO != NULL && (SF != NULL || 746 ((AL == NULL || DL == NULL || 747 top > 3 || bot + 3 < win->maxy) && sf != NULL))) { 748 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 749 __mvcur(oy, ox, 0, 0, 1); 750 tputs(HO, 0, __cputchar); 751 __mvcur(0, 0, bot, 0, 1); 752 if (SF != NULL) 753 tputs(__tscroll(SF, n, 0), 0, __cputchar); 754 else 755 for (i = 0; i < n; i++) 756 tputs(sf, 0, __cputchar); 757 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 758 __mvcur(bot, 0, 0, 0, 1); 759 tputs(HO, 0, __cputchar); 760 __mvcur(0, 0, oy, ox, 1); 761 return; 762 } 763 764 /* Scroll up the block. */ 765 if (SF != NULL && top == 0) { 766 __mvcur(oy, ox, bot, 0, 1); 767 tputs(__tscroll(SF, n, 0), 0, __cputchar); 768 } else if (DL != NULL) { 769 __mvcur(oy, ox, top, 0, 1); 770 tputs(__tscroll(DL, n, 0), 0, __cputchar); 771 } else if (dl != NULL) { 772 __mvcur(oy, ox, top, 0, 1); 773 for (i = 0; i < n; i++) 774 tputs(dl, 0, __cputchar); 775 } else if (sf != NULL && top == 0) { 776 __mvcur(oy, ox, bot, 0, 1); 777 for (i = 0; i < n; i++) 778 tputs(sf, 0, __cputchar); 779 } else 780 abort(); 781 782 /* Push down the bottom region. */ 783 __mvcur(top, 0, bot - n + 1, 0, 1); 784 if (AL != NULL) 785 tputs(__tscroll(AL, n, 0), 0, __cputchar); 786 else if (al != NULL) 787 for (i = 0; i < n; i++) 788 tputs(al, 0, __cputchar); 789 else 790 abort(); 791 __mvcur(bot - n + 1, 0, oy, ox, 1); 792 } else { 793 /* 794 * !!! 795 * n < 0 796 * 797 * If CS, HO and SR/sr are set, can use the scrolling region. 798 * See the above comments for details. 799 */ 800 if (CS != NULL && HO != NULL && (SR != NULL || 801 ((AL == NULL || DL == NULL || 802 top > 3 || bot + 3 < win->maxy) && sr != NULL))) { 803 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 804 __mvcur(oy, ox, 0, 0, 1); 805 tputs(HO, 0, __cputchar); 806 __mvcur(0, 0, top, 0, 1); 807 808 if (SR != NULL) 809 tputs(__tscroll(SR, -n, 0), 0, __cputchar); 810 else 811 for (i = n; i < 0; i++) 812 tputs(sr, 0, __cputchar); 813 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 814 __mvcur(top, 0, 0, 0, 1); 815 tputs(HO, 0, __cputchar); 816 __mvcur(0, 0, oy, ox, 1); 817 return; 818 } 819 820 /* Preserve the bottom lines. */ 821 __mvcur(oy, ox, bot + n + 1, 0, 1); 822 if (SR != NULL && bot == win->maxy) 823 tputs(__tscroll(SR, -n, 0), 0, __cputchar); 824 else if (DL != NULL) 825 tputs(__tscroll(DL, -n, 0), 0, __cputchar); 826 else if (dl != NULL) 827 for (i = n; i < 0; i++) 828 tputs(dl, 0, __cputchar); 829 else if (sr != NULL && bot == win->maxy) 830 for (i = n; i < 0; i++) 831 tputs(sr, 0, __cputchar); 832 else 833 abort(); 834 835 /* Scroll the block down. */ 836 __mvcur(bot + n + 1, 0, top, 0, 1); 837 if (AL != NULL) 838 tputs(__tscroll(AL, -n, 0), 0, __cputchar); 839 else if (al != NULL) 840 for (i = n; i < 0; i++) 841 tputs(al, 0, __cputchar); 842 else 843 abort(); 844 __mvcur(top, 0, oy, ox, 1); 845 } 846 } 847