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.11 (Berkeley) 10/01/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 if (win == curscr) 122 domvcur(ly, lx, win->cury, win->curx); 123 else { 124 if (win->flags & __LEAVEOK) { 125 curscr->cury = ly; 126 curscr->curx = lx; 127 ly -= win->begy; 128 lx -= win->begx; 129 if (ly >= 0 && ly < win->maxy && lx >= 0 && 130 lx < win->maxx) { 131 win->cury = ly; 132 win->curx = lx; 133 } else 134 win->cury = win->curx = 0; 135 } else { 136 domvcur(ly, lx, win->cury + win->begy, 137 win->curx + win->begx); 138 curscr->cury = win->cury + win->begy; 139 curscr->curx = win->curx + win->begx; 140 } 141 } 142 retval = OK; 143 144 _win = NULL; 145 (void)fflush(stdout); 146 return (retval); 147 } 148 149 /* 150 * makech -- 151 * Make a change on the screen. 152 */ 153 static int 154 makech(win, wy) 155 register WINDOW *win; 156 int wy; 157 { 158 register int nlsp, clsp; /* Last space in lines. */ 159 register short wx, lch, y; 160 register char *nsp, *csp, *ce; 161 162 if (!(win->lines[wy]->flags & __ISDIRTY)) 163 return (OK); 164 wx = win->lines[wy]->firstch - win->ch_off; 165 if (wx >= win->maxx) 166 return (OK); 167 else if (wx < 0) 168 wx = 0; 169 lch = win->lines[wy]->lastch - win->ch_off; 170 if (lch < 0) 171 return (OK); 172 else if (lch >= win->maxx) 173 lch = win->maxx - 1; 174 y = wy + win->begy; 175 176 if (curwin) 177 csp = " "; 178 else 179 csp = &curscr->lines[wy + win->begy]->line[wx + win->begx]; 180 181 nsp = &win->lines[wy]->line[wx]; 182 if (CE && !curwin) { 183 for (ce = &win->lines[wy]->line[win->maxx - 1]; 184 *ce == ' '; ce--) 185 if (ce <= win->lines[wy]->line) 186 break; 187 nlsp = ce - win->lines[wy]->line; 188 } 189 if (!curwin) 190 ce = CE; 191 else 192 ce = NULL; 193 194 while (wx <= lch) { 195 if (*nsp == *csp) { 196 if (wx <= lch) { 197 while (*nsp == *csp && wx <= lch) { 198 nsp++; 199 if (!curwin) 200 csp++; 201 ++wx; 202 } 203 continue; 204 } 205 break; 206 } 207 domvcur(ly, lx, y, wx + win->begx); 208 209 #ifdef DEBUG 210 __TRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d\n", 211 wx, ly, lx, y, wx + win->begx); 212 #endif 213 ly = y; 214 lx = wx + win->begx; 215 while (*nsp != *csp && wx <= lch) { 216 #ifdef notdef 217 /* XXX 218 * The problem with this code is that we can't count on 219 * terminals wrapping around after the 220 * last character on the previous line has been output 221 * In effect, what then could happen is that the CE 222 * clear the previous line and do nothing to the 223 * next line. 224 */ 225 if (ce != NULL && wx >= nlsp && *nsp == ' ') { 226 /* Check for clear to end-of-line. */ 227 ce = &curscr->lines[ly]->line[COLS - 1]; 228 while (*ce == ' ') 229 if (ce-- <= csp) 230 break; 231 clsp = ce - curscr->lines[ly]->line - 232 win->begx; 233 #ifdef DEBUG 234 __TRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 235 #endif 236 if (clsp - nlsp >= strlen(CE) && 237 clsp < win->maxx) { 238 #ifdef DEBUG 239 __TRACE("makech: using CE\n"); 240 #endif 241 tputs(CE, 0, __cputchar); 242 lx = wx + win->begx; 243 while (wx++ <= clsp) 244 *csp++ = ' '; 245 return (OK); 246 } 247 ce = NULL; 248 } 249 #endif 250 251 /* Enter/exit standout mode as appropriate. */ 252 if (SO && (*nsp & __STANDOUT) != 253 (curscr->flags & __WSTANDOUT)) { 254 if (*nsp & __STANDOUT) { 255 tputs(SO, 0, __cputchar); 256 curscr->flags |= __WSTANDOUT; 257 } else { 258 tputs(SE, 0, __cputchar); 259 curscr->flags &= ~__WSTANDOUT; 260 } 261 } 262 263 wx++; 264 if (wx >= win->maxx && wy == win->maxy - 1) 265 if (win->flags & __SCROLLOK) { 266 if (curscr->flags & __WSTANDOUT 267 && win->flags & __ENDLINE) 268 if (!MS) { 269 tputs(SE, 0, 270 __cputchar); 271 curscr->flags &= 272 ~__WSTANDOUT; 273 } 274 if (!curwin) 275 putchar((*csp = *nsp) & 0177); 276 else 277 putchar(*nsp & 0177); 278 #ifdef notdef 279 if (win->flags & __FULLWIN && !curwin){ 280 scroll(curscr); 281 #endif 282 ly = win->begy + win->maxy - 1; 283 lx = win->begx + win->maxx - 1; 284 return (OK); 285 } else 286 if (win->flags & __SCROLLWIN) { 287 lx = --wx; 288 return (ERR); 289 } 290 if (!curwin) 291 putchar((*csp++ = *nsp) & 0177); 292 else 293 putchar(*nsp & 0177); 294 #ifdef DEBUG 295 __TRACE("makech: putchar(%c)\n", *nsp & 0177); 296 #endif 297 if (UC && (*nsp & __STANDOUT)) { 298 putchar('\b'); 299 tputs(UC, 0, __cputchar); 300 } 301 nsp++; 302 } 303 #ifdef DEBUG 304 __TRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 305 #endif 306 if (lx == wx + win->begx) /* If no change. */ 307 break; 308 lx = wx + win->begx; 309 if (lx >= COLS && AM) { 310 lx = 0; 311 ly++; 312 /* 313 * xn glitch: chomps a newline after auto-wrap. 314 * we just feed it now and forget about it. 315 */ 316 if (XN) { 317 putchar('\n'); 318 putchar('\r'); 319 } 320 } 321 #ifdef DEBUG 322 __TRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 323 #endif 324 } 325 return (OK); 326 } 327 328 /* 329 * domvcur -- 330 * Do a mvcur, leaving standout mode if necessary. 331 */ 332 static void 333 domvcur(oy, ox, ny, nx) 334 int oy, ox, ny, nx; 335 { 336 if (curscr->flags & __WSTANDOUT && !MS) { 337 tputs(SE, 0, __cputchar); 338 curscr->flags &= ~__WSTANDOUT; 339 } 340 #ifdef DEBUG 341 __TRACE("domvcur: oy=%d, ox=%d, ny=%d, nx=%d\n", oy, ox, ny, nx); 342 #endif 343 mvcur(oy, ox, ny, nx); 344 } 345 346 347 /* 348 * Quickch() attempts to detect a pattern in the change of the window 349 * inorder to optimize the change, e.g., scroll n lines as opposed to 350 * repainting the screen line by line. 351 */ 352 353 static void 354 quickch(win) 355 WINDOW *win; 356 { 357 #define THRESH win->maxy / 4 358 359 register LINE *clp, *tmp1, *tmp2; 360 register int bsize, curs, curw, starts, startw, i, j; 361 int n, target, remember; 362 char buf[1024]; 363 u_int blank_hash; 364 365 for (bsize = win->maxy; bsize >= THRESH; bsize--) 366 for (startw = 0; startw <= win->maxy - bsize; startw++) 367 for (starts = 0; starts <= win->maxy - bsize; 368 starts++) { 369 for (curw = startw, curs = starts; 370 curs < starts + bsize; curw++, curs++) 371 if (win->lines[curw]->hash != 372 curscr->lines[curs]->hash) 373 break; 374 if (curs == starts + bsize) 375 goto done; 376 } 377 done: 378 /* Did not find anything or block is in correct place already. */ 379 if (bsize < THRESH || starts == startw) 380 return; 381 382 #ifdef DEBUG 383 __TRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d\n", 384 bsize, starts, startw, curw, curs); 385 #endif 386 scrolln(win, starts, startw); 387 388 n = startw - starts; 389 390 /* So we don't have to call __hash() each time */ 391 (void)memset(buf, ' ', win->maxx); 392 blank_hash = __hash(buf, win->maxx); 393 394 /* 395 * Perform the rotation to maintain the consistency of curscr. 396 */ 397 i = 0; 398 tmp1 = curscr->lines[0]; 399 remember = 0; 400 for (j = 0; j < win->maxy; j++) { 401 target = (i + n + win->maxy) % win->maxy; 402 tmp2 = curscr->lines[target]; 403 curscr->lines[target] = tmp1; 404 /* Mark block as clean and blank out scrolled lines. */ 405 clp = curscr->lines[target]; 406 __TRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 407 n, startw, curw, i, target); 408 if (target >= startw && target < curw) { 409 __TRACE("-- notdirty"); 410 win->lines[target]->flags &= ~__ISDIRTY; 411 } else if ((n < 0 && target >= win->maxy + n) || 412 (n > 0 && target < n)) { 413 if (clp->hash != blank_hash) { 414 (void)memset(clp->line, ' ', win->maxx); 415 __TRACE("-- memset"); 416 clp->hash = blank_hash; 417 } else 418 __TRACE(" -- nonmemset"); 419 touchline(win, target, 0, win->maxx - 1); 420 } else { 421 __TRACE(" -- just dirty"); 422 touchline(win, target, 0, win->maxx - 1); 423 } 424 __TRACE("\n"); 425 if (target == remember) { 426 i = target + 1; 427 tmp1 = curscr->lines[i]; 428 remember = i; 429 } else { 430 tmp1 = tmp2; 431 i = target; 432 } 433 } 434 __TRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 435 for (i = 0; i < curscr->maxy; i++) 436 __TRACE("Q: %d: %.70s\n", i, 437 curscr->lines[i]->line); 438 } 439 440 static void 441 scrolln(win, starts, startw) 442 WINDOW *win; 443 int starts, startw; 444 { 445 int i, oy, ox, n; 446 447 oy = curscr->cury; 448 ox = curscr->curx; 449 n = starts - startw; 450 451 if (n > 0) { 452 mvcur(oy, ox, 0, 0); 453 if (DL) 454 tputs(tscroll(DL, n), 0, __cputchar); 455 else 456 for(i = 0; i < n; i++) 457 tputs(dl, 0, __cputchar); 458 mvcur(0, 0, oy, ox); 459 } else { 460 /* Delete the bottom lines */ 461 mvcur(oy, 0, win->maxy + n, 0); /* n < 0 */ 462 if (DL) 463 tputs(tscroll(DL, -n), 0, __cputchar); 464 else 465 for(i = n; i < 0; i++) 466 tputs(dl, 0, __cputchar); 467 mvcur(win->maxy + n, 0, starts, 0); 468 469 /* Scroll the block down */ 470 if (AL) 471 tputs(tscroll(AL, -n), 0, __cputchar); 472 else 473 for(i = n; i < 0; i++) 474 tputs(al, 0, __cputchar); 475 mvcur(starts, 0, oy, ox); 476 } 477 } 478 479 480