4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / lib / libcurses / refresh.c
index 12313c3..6de5beb 100644 (file)
@@ -1,12 +1,12 @@
 /*
 /*
- * Copyright (c) 1981 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1981, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * %sccs.include.redist.c%
  */
 
 #ifndef lint
  *
  * %sccs.include.redist.c%
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)refresh.c  5.11 (Berkeley) %G%";
+static char sccsid[] = "@(#)refresh.c  8.1 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <curses.h>
 #endif /* not lint */
 
 #include <curses.h>
@@ -15,14 +15,11 @@ static char sccsid[] = "@(#)refresh.c       5.11 (Berkeley) %G%";
 static int curwin;
 static short ly, lx;
 
 static int curwin;
 static short ly, lx;
 
-int doqch = 1;
-
-WINDOW *_win;
-
 static void    domvcur __P((int, int, int, int));
 static int     makech __P((WINDOW *, int));
 static void    quickch __P((WINDOW *));        
 static void    domvcur __P((int, int, int, int));
 static int     makech __P((WINDOW *, int));
 static void    quickch __P((WINDOW *));        
-static void    scrolln __P((WINDOW *, int, int));
+static void    scrolln __P((WINDOW *, int, int, int, int, int));
+
 /*
  * wrefresh --
  *     Make the current screen look like "win" over the area coverd by
 /*
  * wrefresh --
  *     Make the current screen look like "win" over the area coverd by
@@ -32,30 +29,23 @@ int
 wrefresh(win)
        register WINDOW *win;
 {
 wrefresh(win)
        register WINDOW *win;
 {
-       register LINE *wlp;
+       register __LINE *wlp;
        register int retval;
        register short wy;
        register int retval;
        register short wy;
-
-       /* Make sure were in visual state. */
-       if (__endwin) {
-               tputs(VS, 0, __cputchar);
-               tputs(TI, 0, __cputchar);
-               __endwin = 0;
-       }
-
+       int dnum;
+       
        /* Initialize loop parameters. */
        /* Initialize loop parameters. */
-
        ly = curscr->cury;
        lx = curscr->curx;
        wy = 0;
        ly = curscr->cury;
        lx = curscr->curx;
        wy = 0;
-       _win = win;
        curwin = (win == curscr);
 
        if (!curwin)
                for (wy = 0; wy < win->maxy; wy++) {
                        wlp = win->lines[wy];
                        if (wlp->flags & __ISDIRTY)
        curwin = (win == curscr);
 
        if (!curwin)
                for (wy = 0; wy < win->maxy; wy++) {
                        wlp = win->lines[wy];
                        if (wlp->flags & __ISDIRTY)
-                               wlp->hash = __hash(wlp->line, win->maxx);
+                               wlp->hash = 
+                                  __hash((char *) wlp->line, win->maxx * __LDATASIZE);
                }
 
        if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) {
                }
 
        if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) {
@@ -69,7 +59,7 @@ wrefresh(win)
                                curscr->curx = 0;
                                werase(curscr);
                        }
                                curscr->curx = 0;
                                werase(curscr);
                        }
-                       touchwin(win);
+                       __touchwin(win);
                }
                win->flags &= ~__CLEAROK;
        }
                }
                win->flags &= ~__CLEAROK;
        }
@@ -80,44 +70,90 @@ wrefresh(win)
                        werase(curscr);
        }
 #ifdef DEBUG
                        werase(curscr);
        }
 #ifdef DEBUG
-       __TRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin);
-       __TRACE("wrefresh: \tfirstch\tlastch\n");
+       __CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin);
+       __CTRACE("wrefresh: \tfirstch\tlastch\n");
 #endif
 
 #ifndef NOQCH
 #endif
 
 #ifndef NOQCH
-       if (!__noqch && (win->flags & __FULLWIN) && !curwin)
-               quickch(win);
+       if ((win->flags & __FULLWIN) && !curwin) {
+               /*
+                * Invoke quickch() only if more than a quarter of the lines
+                * in the window are dirty.
+                */
+               for (wy = 0, dnum = 0; wy < win->maxy; wy++)
+                       if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT))
+                               dnum++;
+               if (!__noqch && dnum > (int) win->maxy / 4)
+                       quickch(win);
+       }
 #endif
 #endif
+
+#ifdef DEBUG
+{ int i, j;
+               __CTRACE("#####################################\n");
+               for (i = 0; i < curscr->maxy; i++) {
+                       __CTRACE("C: %d:", i);
+                       __CTRACE(" 0x%x \n", curscr->lines[i]->hash);
+                       for (j = 0; j < curscr->maxx; j++) 
+                               __CTRACE("%c", 
+                                  curscr->lines[i]->line[j].ch);
+                       __CTRACE("\n");
+                       for (j = 0; j < curscr->maxx; j++) 
+                               __CTRACE("%x", 
+                                  curscr->lines[i]->line[j].attr);
+                       __CTRACE("\n");
+                       __CTRACE("W: %d:", i);
+                       __CTRACE(" 0x%x \n", win->lines[i]->hash);
+                       __CTRACE(" 0x%x ", win->lines[i]->flags);
+                       for (j = 0; j < win->maxx; j++) 
+                               __CTRACE("%c", 
+                                  win->lines[i]->line[j].ch);
+                       __CTRACE("\n");
+                       for (j = 0; j < win->maxx; j++) 
+                               __CTRACE("%x", 
+                                  win->lines[i]->line[j].attr);
+                       __CTRACE("\n");
+               }
+}
+#endif /* DEBUG */
+
        for (wy = 0; wy < win->maxy; wy++) {
 #ifdef DEBUG
        for (wy = 0; wy < win->maxy; wy++) {
 #ifdef DEBUG
-               __TRACE("%d\t%d\t%d\n",
-                   wy, win->lines[wy]->firstch, win->lines[wy]->lastch);
+               __CTRACE("%d\t%d\t%d\n",
+                   wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp);
 #endif
                if (!curwin)
                        curscr->lines[wy]->hash = win->lines[wy]->hash;
 #endif
                if (!curwin)
                        curscr->lines[wy]->hash = win->lines[wy]->hash;
-               if (win->lines[wy]->flags & __ISDIRTY)
+               if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) {
                        if (makech(win, wy) == ERR)
                                return (ERR);
                        else {
                        if (makech(win, wy) == ERR)
                                return (ERR);
                        else {
-                               if (win->lines[wy]->firstch >= win->ch_off)
-                                       win->lines[wy]->firstch = win->maxx +
+                               if (*win->lines[wy]->firstchp >= win->ch_off)
+                                       *win->lines[wy]->firstchp = win->maxx +
                                            win->ch_off;
                                            win->ch_off;
-                               if (win->lines[wy]->lastch < win->maxx +
+                               if (*win->lines[wy]->lastchp < win->maxx +
                                    win->ch_off)
                                    win->ch_off)
-                                       win->lines[wy]->lastch = win->ch_off;
-                               if (win->lines[wy]->lastch < 
-                                   win->lines[wy]->firstch)
+                                       *win->lines[wy]->lastchp = win->ch_off;
+                               if (*win->lines[wy]->lastchp < 
+                                   *win->lines[wy]->firstchp) {
+#ifdef DEBUG
+                                       __CTRACE("wrefresh: line %d notdirty \n", wy);
+#endif
                                        win->lines[wy]->flags &= ~__ISDIRTY;
                                        win->lines[wy]->flags &= ~__ISDIRTY;
+                               }
                        }
                        }
+
+               }
 #ifdef DEBUG
 #ifdef DEBUG
-               __TRACE("\t%d\t%d\n", win->lines[wy]->firstch
-                       win->lines[wy]->lastch);
+               __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp
+                       *win->lines[wy]->lastchp);
 #endif
        }
        
 #ifdef DEBUG
 #endif
        }
        
 #ifdef DEBUG
-       __TRACE("refresh: ly=%d, lx=%d\n", ly, lx);
+       __CTRACE("refresh: ly=%d, lx=%d\n", ly, lx);
 #endif
 #endif
+
        if (win == curscr)
                domvcur(ly, lx, win->cury, win->curx);
        else {
        if (win == curscr)
                domvcur(ly, lx, win->cury, win->curx);
        else {
@@ -141,7 +177,6 @@ wrefresh(win)
        }
        retval = OK;
 
        }
        retval = OK;
 
-       _win = NULL;
        (void)fflush(stdout);
        return (retval);
 }
        (void)fflush(stdout);
        return (retval);
 }
@@ -155,51 +190,69 @@ makech(win, wy)
        register WINDOW *win;
        int wy;
 {
        register WINDOW *win;
        int wy;
 {
+       static __LDATA blank = {' ', 0};
        register int nlsp, clsp;                /* Last space in lines. */
        register int nlsp, clsp;                /* Last space in lines. */
-       register short wx, lch, y;
-       register char *nsp, *csp, *ce;
-
-       if (!(win->lines[wy]->flags & __ISDIRTY))
-               return (OK);
-       wx = win->lines[wy]->firstch - win->ch_off;
-       if (wx >= win->maxx)
-               return (OK);
-       else if (wx < 0)
+       register int wx, lch, y;
+       register __LDATA *nsp, *csp, *cp, *cep;
+       u_int force;
+       char *ce;
+
+       /* Is the cursor still on the end of the last line? */
+       if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) {
+               domvcur(ly, lx, ly + 1, 0);
+               ly++;
+               lx = 0;
+       }
+       wx = *win->lines[wy]->firstchp - win->ch_off;
+       if (wx < 0)
                wx = 0;
                wx = 0;
-       lch = win->lines[wy]->lastch - win->ch_off;
+       else if (wx >= win->maxx)
+               return (OK);
+       lch = *win->lines[wy]->lastchp - win->ch_off;
        if (lch < 0)
                return (OK);
        if (lch < 0)
                return (OK);
-       else if (lch >= win->maxx)
+       else if (lch >= (int) win->maxx)
                lch = win->maxx - 1;
        y = wy + win->begy;
 
        if (curwin)
                lch = win->maxx - 1;
        y = wy + win->begy;
 
        if (curwin)
-               csp = " ";
+               csp = &blank;
        else
                csp = &curscr->lines[wy + win->begy]->line[wx + win->begx];
 
        nsp = &win->lines[wy]->line[wx];
        else
                csp = &curscr->lines[wy + win->begy]->line[wx + win->begx];
 
        nsp = &win->lines[wy]->line[wx];
+       force = win->lines[wy]->flags & __FORCEPAINT;
+       win->lines[wy]->flags &= ~__FORCEPAINT;
        if (CE && !curwin) {
        if (CE && !curwin) {
-               for (ce = &win->lines[wy]->line[win->maxx - 1]; 
-                    *ce == ' '; ce--)
-                       if (ce <= win->lines[wy]->line)
+               for (cp = &win->lines[wy]->line[win->maxx - 1]; 
+                    cp->ch == ' ' && cp->attr == 0; cp--)
+                       if (cp <= win->lines[wy]->line)
                                break;
                                break;
-               nlsp = ce - win->lines[wy]->line;
+               nlsp = cp - win->lines[wy]->line;
        }
        if (!curwin)
                ce = CE;
        else
                ce = NULL;
 
        }
        if (!curwin)
                ce = CE;
        else
                ce = NULL;
 
+       if (force) {
+               if (CM)
+                       tputs(tgoto(CM, lx, ly), 0, __cputchar);
+               else {
+                       tputs(HO, 0, __cputchar);
+                       __mvcur(0, 0, ly, lx, 1);
+               }
+       }
        while (wx <= lch) {
        while (wx <= lch) {
-               if (*nsp == *csp) {
+               if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) {
                        if (wx <= lch) {
                        if (wx <= lch) {
-                               while (*nsp == *csp && wx <= lch) {
-                                       nsp++;
-                                       if (!curwin)
-                                               csp++;
-                                       ++wx;
-                               }
+                               while (wx <= lch &&
+                                      memcmp(nsp, csp, sizeof(__LDATA)) == 0) {
+                                           nsp++;
+                                           if (!curwin)
+                                                   csp++;
+                                           ++wx;
+                                   }
                                continue;
                        }
                        break;
                                continue;
                        }
                        break;
@@ -207,51 +260,48 @@ makech(win, wy)
                domvcur(ly, lx, y, wx + win->begx);
 
 #ifdef DEBUG
                domvcur(ly, lx, y, wx + win->begx);
 
 #ifdef DEBUG
-               __TRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d\n", 
-                   wx, ly, lx, y, wx + win->begx);
+               __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n", 
+                   wx, ly, lx, y, wx + win->begx, force);
 #endif
                ly = y;
                lx = wx + win->begx;
 #endif
                ly = y;
                lx = wx + win->begx;
-               while (*nsp != *csp && wx <= lch) {
-#ifdef notdef
-                       /* XXX
-                        * The problem with this code is that we can't count on
-                        * terminals wrapping around after the 
-                        * last character on the previous line has been output
-                        * In effect, what then could happen is that the CE 
-                        * clear the previous line and do nothing to the
-                        * next line.
-                        */
-                       if (ce != NULL && wx >= nlsp && *nsp == ' ') {
+               while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) 
+                   && wx <= lch) {
+
+                       if (ce != NULL && win->maxx + win->begx == 
+                           curscr->maxx && wx >= nlsp && nsp->ch == ' ') {
                                /* Check for clear to end-of-line. */
                                /* Check for clear to end-of-line. */
-                               ce = &curscr->lines[ly]->line[COLS - 1];
-                               while (*ce == ' ')
-                                       if (ce-- <= csp)
+                               cep = &curscr->lines[wy]->line[win->maxx - 1];
+                               while (cep->ch == ' ' && cep->attr == 0)
+                                       if (cep-- <= csp)
                                                break;
                                                break;
-                               clsp = ce - curscr->lines[ly]->line - 
-                                      win->begx;
+                               clsp = cep - curscr->lines[wy]->line - 
+                                      win->begx * __LDATASIZE;
 #ifdef DEBUG
 #ifdef DEBUG
-                       __TRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp);
+                       __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp);
 #endif
 #endif
-                               if (clsp - nlsp >= strlen(CE) &&
-                                   clsp < win->maxx) {
+                               if ((clsp - nlsp >= strlen(CE) 
+                                   && clsp < win->maxx * __LDATASIZE) ||
+                                   wy == win->maxy - 1) {
 #ifdef DEBUG
 #ifdef DEBUG
-                                       __TRACE("makech: using CE\n");
+                                       __CTRACE("makech: using CE\n");
 #endif
                                        tputs(CE, 0, __cputchar);
                                        lx = wx + win->begx;
 #endif
                                        tputs(CE, 0, __cputchar);
                                        lx = wx + win->begx;
-                                       while (wx++ <= clsp)
-                                               *csp++ = ' ';
+                                       while (wx++ <= clsp) {
+                                               csp->ch = ' ';
+                                               csp->attr = 0;
+                                               csp++;
+                                       }
                                        return (OK);
                                }
                                ce = NULL;
                        }
                                        return (OK);
                                }
                                ce = NULL;
                        }
-#endif
 
                        /* Enter/exit standout mode as appropriate. */
 
                        /* Enter/exit standout mode as appropriate. */
-                       if (SO && (*nsp & __STANDOUT) !=
+                       if (SO && (nsp->attr & __STANDOUT) !=
                            (curscr->flags & __WSTANDOUT)) {
                            (curscr->flags & __WSTANDOUT)) {
-                               if (*nsp & __STANDOUT) {
+                               if (nsp->attr & __STANDOUT) {
                                        tputs(SO, 0, __cputchar);
                                        curscr->flags |= __WSTANDOUT;
                                } else {
                                        tputs(SO, 0, __cputchar);
                                        curscr->flags |= __WSTANDOUT;
                                } else {
@@ -261,7 +311,7 @@ makech(win, wy)
                        }
 
                        wx++;
                        }
 
                        wx++;
-                       if (wx >= win->maxx && wy == win->maxy - 1)
+                       if (wx >= win->maxx && wy == win->maxy - 1 && !curwin)
                                if (win->flags & __SCROLLOK) {
                                        if (curscr->flags & __WSTANDOUT
                                            && win->flags & __ENDLINE)
                                if (win->flags & __SCROLLOK) {
                                        if (curscr->flags & __WSTANDOUT
                                            && win->flags & __ENDLINE)
@@ -271,55 +321,55 @@ makech(win, wy)
                                                        curscr->flags &=
                                                            ~__WSTANDOUT;
                                                }
                                                        curscr->flags &=
                                                            ~__WSTANDOUT;
                                                }
-                                       if (!curwin)
-                                               putchar((*csp = *nsp) & 0177);
-                                       else
-                                               putchar(*nsp & 0177);
-#ifdef notdef
-                                       if (win->flags & __FULLWIN && !curwin){
-                                               scroll(curscr);
-#endif
+                                       if (!(win->flags & __SCROLLWIN)) {
+                                               if (!curwin) {
+                                                       csp->attr = nsp->attr;
+                                                       putchar(csp->ch = nsp->ch);
+                                               } else
+                                                       putchar(nsp->ch);
+                                       }
+                                       if (wx + win->begx < curscr->maxx) {
+                                               domvcur(ly, wx + win->begx, 
+                                                   win->begy + win->maxy - 1,
+                                                   win->begx + win->maxx - 1);
+                                       }
                                        ly = win->begy + win->maxy - 1;
                                        lx = win->begx + win->maxx - 1;
                                        return (OK);
                                        ly = win->begy + win->maxy - 1;
                                        lx = win->begx + win->maxx - 1;
                                        return (OK);
-                               } else
-                                       if (win->flags & __SCROLLWIN) {
-                                               lx = --wx;
-                                               return (ERR);
-                                       }
-                       if (!curwin)
-                               putchar((*csp++ = *nsp) & 0177);
-                       else
-                               putchar(*nsp & 0177);
+                               } 
+                       if (wx < win->maxx || wy < win->maxy - 1 || 
+                           !(win->flags & __SCROLLWIN)) {
+                               if (!curwin) {
+                                       csp->attr = nsp->attr;
+                                       putchar(csp->ch = nsp->ch);
+                                       csp++;
+                               } else 
+                                       putchar(nsp->ch);
+                       }
 #ifdef DEBUG
 #ifdef DEBUG
-                       __TRACE("makech: putchar(%c)\n", *nsp & 0177);
+                       __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177);
 #endif
 #endif
-                       if (UC && (*nsp & __STANDOUT)) {
+                       if (UC && (nsp->attr & __STANDOUT)) {
                                putchar('\b');
                                tputs(UC, 0, __cputchar);
                        }
                        nsp++;
                                putchar('\b');
                                tputs(UC, 0, __cputchar);
                        }
                        nsp++;
-               }
 #ifdef DEBUG
 #ifdef DEBUG
-               __TRACE("makech: 2: wx = %d, lx = %d\n", wx, lx);
+               __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx);
 #endif
 #endif
+               }
                if (lx == wx + win->begx)       /* If no change. */
                        break;
                lx = wx + win->begx;
                if (lx == wx + win->begx)       /* If no change. */
                        break;
                lx = wx + win->begx;
-               if (lx >= COLS && AM) {
-                       lx = 0;
-                       ly++;
-                       /*
-                        * xn glitch: chomps a newline after auto-wrap.
-                        * we just feed it now and forget about it.
-                        */
-                       if (XN) {
-                               putchar('\n');
-                               putchar('\r');
-                       }
+               if (lx >= COLS && AM)
+                       lx = COLS - 1;
+               else if (wx >= win->maxx) {
+                       domvcur(ly, lx, ly, win->maxx + win->begx - 1);
+                       lx = win->maxx + win->begx - 1;
                }
                }
+
 #ifdef DEBUG
 #ifdef DEBUG
-               __TRACE("makech: 3: wx = %d, lx = %d\n", wx, lx);
+               __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx);
 #endif
        }
        return (OK);
 #endif
        }
        return (OK);
@@ -337,16 +387,13 @@ domvcur(oy, ox, ny, nx)
                tputs(SE, 0, __cputchar);
                curscr->flags &= ~__WSTANDOUT;
        }
                tputs(SE, 0, __cputchar);
                curscr->flags &= ~__WSTANDOUT;
        }
-#ifdef DEBUG
-       __TRACE("domvcur: oy=%d, ox=%d, ny=%d, nx=%d\n", oy, ox, ny, nx);
-#endif 
-       mvcur(oy, ox, ny, nx);
-}
 
 
+       __mvcur(oy, ox, ny, nx, 1);
+}
 
 /*
  * Quickch() attempts to detect a pattern in the change of the window
 
 /*
  * Quickch() attempts to detect a pattern in the change of the window
- * inorder to optimize the change, e.g., scroll n lines as opposed to 
+ * in order to optimize the change, e.g., scroll n lines as opposed to 
  * repainting the screen line by line.
  */
 
  * repainting the screen line by line.
  */
 
@@ -354,93 +401,255 @@ static void
 quickch(win)
        WINDOW *win;
 {
 quickch(win)
        WINDOW *win;
 {
-#define THRESH         win->maxy / 4
+#define THRESH         (int) win->maxy / 4
 
 
-       register LINE *clp, *tmp1, *tmp2;
+       register __LINE *clp, *tmp1, *tmp2;
        register int bsize, curs, curw, starts, startw, i, j;
        register int bsize, curs, curw, starts, startw, i, j;
-       int n, target, remember;
-       char buf[1024];
+       int n, target, cur_period, bot, top, sc_region;
+       __LDATA buf[1024];
        u_int blank_hash;
 
        u_int blank_hash;
 
-       for (bsize = win->maxy; bsize >= THRESH; bsize--)
-               for (startw = 0; startw <= win->maxy - bsize; startw++)
-                       for (starts = 0; starts <= win->maxy - bsize; 
+       /* 
+        * Find how many lines from the top of the screen are unchanged.
+        */
+       for (top = 0; top < win->maxy; top++) 
+               if (win->lines[top]->flags & __FORCEPAINT ||
+                   win->lines[top]->hash != curscr->lines[top]->hash 
+                   || memcmp(win->lines[top]->line, 
+                   curscr->lines[top]->line, 
+                   win->maxx * __LDATASIZE) != 0)
+                       break;
+               else
+                       win->lines[top]->flags &= ~__ISDIRTY;
+       /*
+       * Find how many lines from bottom of screen are unchanged. 
+       */
+       for (bot = win->maxy - 1; bot >= 0; bot--)
+               if (win->lines[bot]->flags & __FORCEPAINT ||
+                   win->lines[bot]->hash != curscr->lines[bot]->hash 
+                   || memcmp(win->lines[bot]->line, 
+                   curscr->lines[bot]->line, 
+                   win->maxx * __LDATASIZE) != 0)
+                       break;
+               else
+                       win->lines[bot]->flags &= ~__ISDIRTY;
+
+#ifdef NO_JERKINESS
+       /*
+        * If we have a bottom unchanged region return.  Scrolling the
+        * bottom region up and then back down causes a screen jitter.
+        * This will increase the number of characters sent to the screen
+        * but it looks better.
+        */
+       if (bot < win->maxy - 1)
+               return;
+#endif /* NO_JERKINESS */
+
+       /*
+        * Search for the largest block of text not changed.
+        * Invariants of the loop:
+        * - Startw is the index of the beginning of the examined block in win.
+         * - Starts is the index of the beginning of the examined block in 
+        *    curscr.
+        * - Curs is the index of one past the end of the exmined block in win.
+        * - Curw is the index of one past the end of the exmined block in 
+        *   curscr.
+        * - bsize is the current size of the examined block.
+         */
+       for (bsize = bot - top; bsize >= THRESH; bsize--) {
+               for (startw = top; startw <= bot - bsize; startw++)
+                       for (starts = top; starts <= bot - bsize; 
                             starts++) {
                                for (curw = startw, curs = starts;
                                     curs < starts + bsize; curw++, curs++)
                             starts++) {
                                for (curw = startw, curs = starts;
                                     curs < starts + bsize; curw++, curs++)
-                                       if (win->lines[curw]->hash !=
-                                           curscr->lines[curs]->hash)
+                                       if (win->lines[curw]->flags &
+                                           __FORCEPAINT ||
+                                           (win->lines[curw]->hash !=
+                                           curscr->lines[curs]->hash ||
+                                           memcmp(win->lines[curw]->line, 
+                                           curscr->lines[curs]->line, 
+                                           win->maxx * __LDATASIZE) != 0))
                                                break;
                                if (curs == starts + bsize)
                                        goto done;
                        }
                                                break;
                                if (curs == starts + bsize)
                                        goto done;
                        }
+       }
  done:
  done:
-       /* Did not find anything or block is in correct place already. */
-       if (bsize < THRESH || starts == startw) 
+       /* Did not find anything */
+       if (bsize < THRESH)     
                return;
 
 #ifdef DEBUG
                return;
 
 #ifdef DEBUG
-       __TRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d\n", 
-               bsize, starts, startw, curw, curs);
+       __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 
+               bsize, starts, startw, curw, curs, top, bot);
 #endif
 #endif
-       scrolln(win, starts, startw);
+
+       /* 
+        * Make sure that there is no overlap between the bottom and top 
+        * regions and the middle scrolled block.
+        */
+       if (bot < curs)
+               bot = curs - 1;
+       if (top > starts)
+               top = starts;
 
        n = startw - starts;
 
 
        n = startw - starts;
 
+#ifdef DEBUG
+               __CTRACE("#####################################\n");
+               for (i = 0; i < curscr->maxy; i++) {
+                       __CTRACE("C: %d:", i);
+                       __CTRACE(" 0x%x \n", curscr->lines[i]->hash);
+                       for (j = 0; j < curscr->maxx; j++) 
+                               __CTRACE("%c", 
+                                  curscr->lines[i]->line[j].ch);
+                       __CTRACE("\n");
+                       for (j = 0; j < curscr->maxx; j++) 
+                               __CTRACE("%x", 
+                                  curscr->lines[i]->line[j].attr);
+                       __CTRACE("\n");
+                       __CTRACE("W: %d:", i);
+                       __CTRACE(" 0x%x \n", win->lines[i]->hash);
+                       __CTRACE(" 0x%x ", win->lines[i]->flags);
+                       for (j = 0; j < win->maxx; j++) 
+                               __CTRACE("%c", 
+                                  win->lines[i]->line[j].ch);
+                       __CTRACE("\n");
+                       for (j = 0; j < win->maxx; j++) 
+                               __CTRACE("%x", 
+                                  win->lines[i]->line[j].attr);
+                       __CTRACE("\n");
+               }
+#endif 
+       
        /* So we don't have to call __hash() each time */
        /* So we don't have to call __hash() each time */
-       (void)memset(buf, ' ', win->maxx);
-       blank_hash = __hash(buf, win->maxx);
+       for (i = 0; i < win->maxx; i++) {
+               buf[i].ch = ' ';
+               buf[i].attr = 0;
+       }
+       blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE);
 
        /*
         * Perform the rotation to maintain the consistency of curscr.
 
        /*
         * Perform the rotation to maintain the consistency of curscr.
+        * This is hairy since we are doing an *in place* rotation.
+        * Invariants of the loop:
+        * - I is the index of the current line.
+        * - Target is the index of the target of line i.
+        * - Tmp1 points to current line (i).
+        * - Tmp2 and points to target line (target);
+        * - Cur_period is the index of the end of the current period. 
+        *   (see below).
+        *
+        * There are 2 major issues here that make this rotation non-trivial:
+        * 1.  Scrolling in a scrolling region bounded by the top
+        *     and bottom regions determined (whose size is sc_region).
+        * 2.  As a result of the use of the mod function, there may be a 
+        *     period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and
+        *     0 to 2, which then causes all odd lines not to be rotated.
+        *     To remedy this, an index of the end ( = beginning) of the 
+        *     current 'period' is kept, cur_period, and when it is reached, 
+        *     the next period is started from cur_period + 1 which is 
+        *     guaranteed not to have been reached since that would mean that
+        *     all records would have been reached. (think about it...).
+        * 
+        * Lines in the rotation can have 3 attributes which are marked on the
+        * line so that curscr is consistent with the visual screen.
+        * 1.  Not dirty -- lines inside the scrolled block, top region or
+        *                  bottom region.
+        * 2.  Blank lines -- lines in the differential of the scrolling 
+        *                    region adjacent to top and bot regions 
+        *                    depending on scrolling direction.
+        * 3.  Dirty line -- all other lines are marked dirty.
         */
         */
-       i = 0;
-       tmp1 = curscr->lines[0];
-       remember = 0;
-       for (j = 0; j < win->maxy; j++) {
-               target = (i + n + win->maxy) % win->maxy;
+       sc_region = bot - top + 1;
+       i = top;
+       tmp1 = curscr->lines[top];
+       cur_period = top;
+       for (j = top; j <= bot; j++) {
+               target = (i - top + n + sc_region) % sc_region + top;
                tmp2 = curscr->lines[target];
                curscr->lines[target] = tmp1;
                /* Mark block as clean and blank out scrolled lines. */
                clp = curscr->lines[target];
                tmp2 = curscr->lines[target];
                curscr->lines[target] = tmp1;
                /* Mark block as clean and blank out scrolled lines. */
                clp = curscr->lines[target];
-               __TRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ",
+#ifdef DEBUG
+               __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ",
                        n, startw, curw, i, target);
                        n, startw, curw, i, target);
-               if (target >= startw && target < curw) {
-                       __TRACE("-- notdirty");
+#endif
+               if ((target >= startw && target < curw) || target < top 
+                   || target > bot) {
+#ifdef DEBUG
+                       __CTRACE("-- notdirty");
+#endif
                        win->lines[target]->flags &= ~__ISDIRTY;
                        win->lines[target]->flags &= ~__ISDIRTY;
-               } else if ((n < 0 && target >= win->maxy + n) || 
-                        (n > 0 && target < n)) {
-                       if (clp->hash != blank_hash) {
-                               (void)memset(clp->line, ' ', win->maxx);
-                               __TRACE("-- memset");
+               } else if ((n > 0 && target >= top && target < top + n) ||
+                          (n < 0 && target <= bot && target > bot + n)) {
+                       if (clp->hash != blank_hash ||  memcmp(clp->line, 
+                           buf, win->maxx * __LDATASIZE) !=0) {
+                               (void)memcpy(clp->line,  buf,
+                                   win->maxx * __LDATASIZE);
+#ifdef DEBUG
+                               __CTRACE("-- blanked out: dirty");
+#endif
                                clp->hash = blank_hash;
                                clp->hash = blank_hash;
-                       } else 
-                               __TRACE(" -- nonmemset");
-                       touchline(win, target, 0, win->maxx - 1);
+                               __touchline(win, target, 0, win->maxx - 1, 0);
+                       } else {
+                               __touchline(win, target, 0, win->maxx - 1, 0);
+#ifdef DEBUG
+                               __CTRACE(" -- blank line already: dirty");
+#endif
+                       }
                } else {
                } else {
-                       __TRACE(" -- just dirty");
-                       touchline(win, target, 0, win->maxx - 1);
+#ifdef DEBUG
+                       __CTRACE(" -- dirty");
+#endif
+                       __touchline(win, target, 0, win->maxx - 1, 0);
                }
                }
-               __TRACE("\n");
-               if (target == remember) {
+#ifdef DEBUG
+               __CTRACE("\n");
+#endif
+               if (target == cur_period) {
                        i = target + 1;
                        tmp1 = curscr->lines[i];
                        i = target + 1;
                        tmp1 = curscr->lines[i];
-                       remember = i;
+                       cur_period = i;
                } else {
                        tmp1 = tmp2;
                        i = target;
                }
        }
                } else {
                        tmp1 = tmp2;
                        i = target;
                }
        }
-       __TRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
-       for (i = 0; i < curscr->maxy; i++)
-               __TRACE("Q: %d: %.70s\n", i,
-                  curscr->lines[i]->line);
+#ifdef DEBUG
+               __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
+               for (i = 0; i < curscr->maxy; i++) {
+                       __CTRACE("C: %d:", i);
+                       for (j = 0; j < curscr->maxx; j++) 
+                               __CTRACE("%c", 
+                                  curscr->lines[i]->line[j].ch);
+                       __CTRACE("\n");
+                       __CTRACE("W: %d:", i);
+                       for (j = 0; j < win->maxx; j++) 
+                               __CTRACE("%c", 
+                                  win->lines[i]->line[j].ch);
+                       __CTRACE("\n");
+               }
+#endif
+       if (n != 0) {
+               WINDOW *wp;
+               scrolln(win, starts, startw, curs, bot, top);
+               /*
+                * Need to repoint any subwindow lines to the rotated
+                * line structured. 
+                */
+               for (wp = win->nextp; wp != win; wp = wp->nextp)
+                       __set_subwin(win, wp);
+       }
 }
 
 }
 
+/*
+ * Scrolln performs the scroll by n lines, where n is starts - startw.
+ */
 static void
 static void
-scrolln(win, starts, startw)
+scrolln(win, starts, startw, curs, bot, top)
        WINDOW *win;
        WINDOW *win;
-       int starts, startw;
+       int starts, startw, curs, bot, top;
 {
        int i, oy, ox, n;
 
 {
        int i, oy, ox, n;
 
@@ -449,31 +658,40 @@ scrolln(win, starts, startw)
        n = starts - startw;
 
        if (n > 0) {
        n = starts - startw;
 
        if (n > 0) {
-               mvcur(oy, ox, 0, 0);
+               __mvcur(oy, ox, top, 0, 1);
+               /* Scroll up the block */
                if (DL)
                if (DL)
-                       tputs(tscroll(DL, n), 0, __cputchar);
+                       tputs(__tscroll(DL, n), 0, __cputchar);
                else
                        for(i = 0; i < n; i++)
                                tputs(dl, 0, __cputchar);
                else
                        for(i = 0; i < n; i++)
                                tputs(dl, 0, __cputchar);
-               mvcur(0, 0, oy, ox);
+
+               /* 
+                * Push down the bottom region.
+                */
+               __mvcur(top, 0, bot - n + 1, 0, 1);
+               if (AL) 
+                       tputs(__tscroll(AL, n), 0, __cputchar);
+               else
+                       for(i = 0; i < n; i++)
+                               tputs(al, 0, __cputchar);
+               __mvcur(bot - n + 1, 0, oy, ox, 1);
        } else {
        } else {
-               /* Delete the bottom lines */
-               mvcur(oy, 0, win->maxy + n, 0);         /* n < 0 */
+               /* Preserve the bottom lines */
+               __mvcur(oy, ox, bot + n + 1, 0, 1);     /* n < 0 */
                if (DL)
                if (DL)
-                       tputs(tscroll(DL, -n), 0, __cputchar);
+                       tputs(__tscroll(DL, -n), 0, __cputchar);
                else
                else
-                       for(i = n; i < 0; i++)
+                       for(i = n; i < 0; i++)
                                tputs(dl, 0, __cputchar);
                                tputs(dl, 0, __cputchar);
-               mvcur(win->maxy + n, 0, starts,  0);
+               __mvcur(bot + n + 1, 0, top, 0, 1);
 
                /* Scroll the block down */
 
                /* Scroll the block down */
-               if (AL)
-                       tputs(tscroll(AL, -n), 0, __cputchar);
+               if (AL) 
+                       tputs(__tscroll(AL, -n), 0, __cputchar);
                else
                        for(i = n; i < 0; i++)
                                tputs(al, 0, __cputchar);
                else
                        for(i = n; i < 0; i++)
                                tputs(al, 0, __cputchar);
-               mvcur(starts, 0, oy, ox);
+               __mvcur(top, 0, oy, ox, 1);
        }               
 }
        }               
 }
-
-