1 /* 2 * Copyright (c) 1981 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)refresh.c 5.12 (Berkeley) 10/08/92"; 10 #endif /* not lint */ 11 12 #include <curses.h> 13 #include <string.h> 14 15 static int curwin; 16 static short ly, lx; 17 18 int doqch = 1; 19 20 WINDOW *_win; 21 22 static void domvcur __P((int, int, int, int)); 23 static int makech __P((WINDOW *, int)); 24 static void quickch __P((WINDOW *)); 25 static void scrolln __P((WINDOW *, int, int)); 26 /* 27 * wrefresh -- 28 * Make the current screen look like "win" over the area coverd by 29 * win. 30 */ 31 int 32 wrefresh(win) 33 register WINDOW *win; 34 { 35 register LINE *wlp; 36 register int retval; 37 register short wy; 38 39 /* Make sure were in visual state. */ 40 if (__endwin) { 41 tputs(VS, 0, __cputchar); 42 tputs(TI, 0, __cputchar); 43 __endwin = 0; 44 } 45 46 /* Initialize loop parameters. */ 47 48 ly = curscr->cury; 49 lx = curscr->curx; 50 wy = 0; 51 _win = win; 52 curwin = (win == curscr); 53 54 if (!curwin) 55 for (wy = 0; wy < win->maxy; wy++) { 56 wlp = win->lines[wy]; 57 if (wlp->flags & __ISDIRTY) 58 wlp->hash = __hash(wlp->line, win->maxx); 59 } 60 61 if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) { 62 if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) { 63 tputs(CL, 0, __cputchar); 64 ly = 0; 65 lx = 0; 66 if (!curwin) { 67 curscr->flags &= ~__CLEAROK; 68 curscr->cury = 0; 69 curscr->curx = 0; 70 werase(curscr); 71 } 72 touchwin(win); 73 } 74 win->flags &= ~__CLEAROK; 75 } 76 if (!CA) { 77 if (win->curx != 0) 78 putchar('\n'); 79 if (!curwin) 80 werase(curscr); 81 } 82 #ifdef DEBUG 83 __TRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin); 84 __TRACE("wrefresh: \tfirstch\tlastch\n"); 85 #endif 86 87 #ifndef NOQCH 88 if (!__noqch && (win->flags & __FULLWIN) && !curwin) 89 quickch(win); 90 #endif 91 for (wy = 0; wy < win->maxy; wy++) { 92 #ifdef DEBUG 93 __TRACE("%d\t%d\t%d\n", 94 wy, win->lines[wy]->firstch, win->lines[wy]->lastch); 95 #endif 96 if (!curwin) 97 curscr->lines[wy]->hash = win->lines[wy]->hash; 98 if (win->lines[wy]->flags & __ISDIRTY) 99 if (makech(win, wy) == ERR) 100 return (ERR); 101 else { 102 if (win->lines[wy]->firstch >= win->ch_off) 103 win->lines[wy]->firstch = win->maxx + 104 win->ch_off; 105 if (win->lines[wy]->lastch < win->maxx + 106 win->ch_off) 107 win->lines[wy]->lastch = win->ch_off; 108 if (win->lines[wy]->lastch < 109 win->lines[wy]->firstch) 110 win->lines[wy]->flags &= ~__ISDIRTY; 111 } 112 #ifdef DEBUG 113 __TRACE("\t%d\t%d\n", win->lines[wy]->firstch, 114 win->lines[wy]->lastch); 115 #endif 116 } 117 118 #ifdef DEBUG 119 __TRACE("refresh: ly=%d, lx=%d\n", ly, lx); 120 #endif 121 122 if (win == curscr) 123 domvcur(ly, lx, win->cury, win->curx); 124 else { 125 if (win->flags & __LEAVEOK) { 126 curscr->cury = ly; 127 curscr->curx = lx; 128 ly -= win->begy; 129 lx -= win->begx; 130 if (ly >= 0 && ly < win->maxy && lx >= 0 && 131 lx < win->maxx) { 132 win->cury = ly; 133 win->curx = lx; 134 } else 135 win->cury = win->curx = 0; 136 } else { 137 domvcur(ly, lx, win->cury + win->begy, 138 win->curx + win->begx); 139 curscr->cury = win->cury + win->begy; 140 curscr->curx = win->curx + win->begx; 141 } 142 } 143 retval = OK; 144 145 _win = NULL; 146 (void)fflush(stdout); 147 return (retval); 148 } 149 150 /* 151 * makech -- 152 * Make a change on the screen. 153 */ 154 static int 155 makech(win, wy) 156 register WINDOW *win; 157 int wy; 158 { 159 register int nlsp, clsp; /* Last space in lines. */ 160 register short wx, lch, y; 161 register char *nsp, *csp, *ce; 162 163 /* Is the cursor still on the end of the last line? */ 164 if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) { 165 win->lines[wy - 1]->flags &= ~__ISPASTEOL; 166 ly++; 167 lx = 0; 168 } 169 170 if (!(win->lines[wy]->flags & __ISDIRTY)) 171 return (OK); 172 wx = win->lines[wy]->firstch - win->ch_off; 173 if (wx >= win->maxx) 174 return (OK); 175 else if (wx < 0) 176 wx = 0; 177 lch = win->lines[wy]->lastch - win->ch_off; 178 if (lch < 0) 179 return (OK); 180 else if (lch >= win->maxx) 181 lch = win->maxx - 1; 182 y = wy + win->begy; 183 184 if (curwin) 185 csp = " "; 186 else 187 csp = &curscr->lines[wy + win->begy]->line[wx + win->begx]; 188 189 nsp = &win->lines[wy]->line[wx]; 190 if (CE && !curwin) { 191 for (ce = &win->lines[wy]->line[win->maxx - 1]; 192 *ce == ' '; ce--) 193 if (ce <= win->lines[wy]->line) 194 break; 195 nlsp = ce - win->lines[wy]->line; 196 } 197 if (!curwin) 198 ce = CE; 199 else 200 ce = NULL; 201 202 while (wx <= lch) { 203 if (*nsp == *csp) { 204 if (wx <= lch) { 205 while (*nsp == *csp && wx <= lch) { 206 nsp++; 207 if (!curwin) 208 csp++; 209 ++wx; 210 } 211 continue; 212 } 213 break; 214 } 215 domvcur(ly, lx, y, wx + win->begx); 216 217 #ifdef DEBUG 218 __TRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d\n", 219 wx, ly, lx, y, wx + win->begx); 220 #endif 221 ly = y; 222 lx = wx + win->begx; 223 while (*nsp != *csp && wx <= lch) { 224 #ifdef notdef 225 /* XXX 226 * The problem with this code is that we can't count on 227 * terminals wrapping around after the 228 * last character on the previous line has been output 229 * In effect, what then could happen is that the CE 230 * clear the previous line and do nothing to the 231 * next line. 232 */ 233 if (ce != NULL && wx >= nlsp && *nsp == ' ') { 234 /* Check for clear to end-of-line. */ 235 ce = &curscr->lines[ly]->line[COLS - 1]; 236 while (*ce == ' ') 237 if (ce-- <= csp) 238 break; 239 clsp = ce - curscr->lines[ly]->line - 240 win->begx; 241 #ifdef DEBUG 242 __TRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 243 #endif 244 if (clsp - nlsp >= strlen(CE) && 245 clsp < win->maxx) { 246 #ifdef DEBUG 247 __TRACE("makech: using CE\n"); 248 #endif 249 tputs(CE, 0, __cputchar); 250 lx = wx + win->begx; 251 while (wx++ <= clsp) 252 *csp++ = ' '; 253 return (OK); 254 } 255 ce = NULL; 256 } 257 #endif 258 259 /* Enter/exit standout mode as appropriate. */ 260 if (SO && (*nsp & __STANDOUT) != 261 (curscr->flags & __WSTANDOUT)) { 262 if (*nsp & __STANDOUT) { 263 tputs(SO, 0, __cputchar); 264 curscr->flags |= __WSTANDOUT; 265 } else { 266 tputs(SE, 0, __cputchar); 267 curscr->flags &= ~__WSTANDOUT; 268 } 269 } 270 271 wx++; 272 if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) 273 if (win->flags & __SCROLLOK) { 274 if (curscr->flags & __WSTANDOUT 275 && win->flags & __ENDLINE) 276 if (!MS) { 277 tputs(SE, 0, 278 __cputchar); 279 curscr->flags &= 280 ~__WSTANDOUT; 281 } 282 if (!curwin) 283 putchar((*csp = *nsp) & 0177); 284 else 285 putchar(*nsp & 0177); 286 #ifdef notdef 287 if (win->flags & __FULLWIN && !curwin) 288 scroll(curscr); 289 #endif 290 ly = win->begy + win->maxy - 1; 291 lx = win->begx + win->maxx - 1; 292 return (OK); 293 } else 294 if (win->flags & __SCROLLWIN) { 295 lx = --wx; 296 return (ERR); 297 } 298 if (!curwin) 299 putchar((*csp++ = *nsp) & 0177); 300 else 301 putchar(*nsp & 0177); 302 303 #ifdef DEBUG 304 __TRACE("makech: putchar(%c)\n", *nsp & 0177); 305 #endif 306 if (UC && (*nsp & __STANDOUT)) { 307 putchar('\b'); 308 tputs(UC, 0, __cputchar); 309 } 310 nsp++; 311 } 312 #ifdef DEBUG 313 __TRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 314 #endif 315 if (lx == wx + win->begx) /* If no change. */ 316 break; 317 lx = wx + win->begx; 318 if (lx >= COLS && AM) { 319 /* 320 * xn glitch: chomps a newline after auto-wrap. 321 * we just feed it now and forget about it. 322 */ 323 if (XN) { 324 lx = 0; 325 ly++; 326 putchar('\n'); 327 putchar('\r'); 328 } else { 329 if (wy != LINES) 330 win->lines[wy]->flags |= __ISPASTEOL; 331 lx = COLS - 1; 332 } 333 } 334 #ifdef DEBUG 335 __TRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 336 #endif 337 } 338 return (OK); 339 } 340 341 /* 342 * domvcur -- 343 * Do a mvcur, leaving standout mode if necessary. 344 */ 345 static void 346 domvcur(oy, ox, ny, nx) 347 int oy, ox, ny, nx; 348 { 349 if (curscr->flags & __WSTANDOUT && !MS) { 350 tputs(SE, 0, __cputchar); 351 curscr->flags &= ~__WSTANDOUT; 352 } 353 #ifdef DEBUG 354 __TRACE("domvcur: oy=%d, ox=%d, ny=%d, nx=%d\n", oy, ox, ny, nx); 355 #endif 356 mvcur(oy, ox, ny, nx); 357 } 358 359 360 /* 361 * Quickch() attempts to detect a pattern in the change of the window 362 * inorder to optimize the change, e.g., scroll n lines as opposed to 363 * repainting the screen line by line. 364 */ 365 366 static void 367 quickch(win) 368 WINDOW *win; 369 { 370 #define THRESH win->maxy / 4 371 372 register LINE *clp, *tmp1, *tmp2; 373 register int bsize, curs, curw, starts, startw, i, j; 374 int n, target, remember; 375 char buf[1024]; 376 u_int blank_hash; 377 378 for (bsize = win->maxy; bsize >= THRESH; bsize--) 379 for (startw = 0; startw <= win->maxy - bsize; startw++) 380 for (starts = 0; starts <= win->maxy - bsize; 381 starts++) { 382 for (curw = startw, curs = starts; 383 curs < starts + bsize; curw++, curs++) 384 if (win->lines[curw]->hash != 385 curscr->lines[curs]->hash) 386 break; 387 if (curs == starts + bsize) 388 goto done; 389 } 390 done: 391 /* Did not find anything or block is in correct place already. */ 392 if (bsize < THRESH || starts == startw) 393 return; 394 395 #ifdef DEBUG 396 __TRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d\n", 397 bsize, starts, startw, curw, curs); 398 #endif 399 scrolln(win, starts, startw); 400 401 n = startw - starts; 402 403 /* So we don't have to call __hash() each time */ 404 (void)memset(buf, ' ', win->maxx); 405 blank_hash = __hash(buf, win->maxx); 406 407 /* 408 * Perform the rotation to maintain the consistency of curscr. 409 */ 410 i = 0; 411 tmp1 = curscr->lines[0]; 412 remember = 0; 413 for (j = 0; j < win->maxy; j++) { 414 target = (i + n + win->maxy) % win->maxy; 415 tmp2 = curscr->lines[target]; 416 curscr->lines[target] = tmp1; 417 /* Mark block as clean and blank out scrolled lines. */ 418 clp = curscr->lines[target]; 419 #ifdef DEBUG 420 __TRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 421 n, startw, curw, i, target); 422 #endif 423 if (target >= startw && target < curw) { 424 #ifdef DEBUG 425 __TRACE("-- notdirty"); 426 #endif 427 win->lines[target]->flags &= ~__ISDIRTY; 428 } else if ((n < 0 && target >= win->maxy + n) || 429 (n > 0 && target < n)) { 430 if (clp->hash != blank_hash) { 431 (void)memset(clp->line, ' ', win->maxx); 432 #ifdef DEBUG 433 __TRACE("-- memset"); 434 #endif 435 clp->hash = blank_hash; 436 } else 437 #ifdef DEBUG 438 __TRACE(" -- nonmemset"); 439 #endif 440 touchline(win, target, 0, win->maxx - 1); 441 } else { 442 #ifdef DEBUG 443 __TRACE(" -- just dirty"); 444 #endif 445 touchline(win, target, 0, win->maxx - 1); 446 } 447 #ifdef DEBUG 448 __TRACE("\n"); 449 #endif 450 if (target == remember) { 451 i = target + 1; 452 tmp1 = curscr->lines[i]; 453 remember = i; 454 } else { 455 tmp1 = tmp2; 456 i = target; 457 } 458 } 459 #ifdef DEBUG 460 __TRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 461 for (i = 0; i < curscr->maxy; i++) 462 __TRACE("Q: %d: %.70s\n", i, 463 curscr->lines[i]->line); 464 #endif 465 } 466 467 static void 468 scrolln(win, starts, startw) 469 WINDOW *win; 470 int starts, startw; 471 { 472 int i, oy, ox, n; 473 474 oy = curscr->cury; 475 ox = curscr->curx; 476 n = starts - startw; 477 478 if (n > 0) { 479 mvcur(oy, ox, 0, 0); 480 if (DL) 481 tputs(tscroll(DL, n), 0, __cputchar); 482 else 483 for(i = 0; i < n; i++) 484 tputs(dl, 0, __cputchar); 485 mvcur(0, 0, oy, ox); 486 } else { 487 /* Delete the bottom lines */ 488 mvcur(oy, 0, win->maxy + n, 0); /* n < 0 */ 489 if (DL) 490 tputs(tscroll(DL, -n), 0, __cputchar); 491 else 492 for(i = n; i < 0; i++) 493 tputs(dl, 0, __cputchar); 494 mvcur(win->maxy + n, 0, starts, 0); 495 496 /* Scroll the block down */ 497 if (AL) 498 tputs(tscroll(AL, -n), 0, __cputchar); 499 else 500 for(i = n; i < 0; i++) 501 tputs(al, 0, __cputchar); 502 mvcur(starts, 0, oy, ox); 503 } 504 } 505 506 507