4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / lib / libcurses / refresh.c
index 7263a57..6de5beb 100644 (file)
 /*
 /*
- * 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.5 (Berkeley) %G%";
+static char sccsid[] = "@(#)refresh.c  8.1 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
-/*
- * make the current screen look like "win" over the area coverd by
- * win.
- */
-
-# include      "curses.ext"
-
-# ifdef DEBUG
-# define       STATIC
-# else
-# define       STATIC  static
-# endif
+#include <curses.h>
+#include <string.h>
 
 
-STATIC short   ly, lx;
+static int curwin;
+static short ly, lx;
 
 
-STATIC bool    curwin;
-
-WINDOW *_win = NULL;
-
-STATIC int     domvcur(), makech();
+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, int, int, int));
 
 
+/*
+ * wrefresh --
+ *     Make the current screen look like "win" over the area coverd by
+ *     win.
+ */
+int
 wrefresh(win)
 wrefresh(win)
-reg WINDOW     *win;
+       register WINDOW *win;
 {
 {
-       reg short       wy;
-       reg int         retval;
-       reg WINDOW      *orig;
-
-       /*
-        * make sure were in visual state
-        */
-       if (_endwin) {
-               _puts(VS);
-               _puts(TI);
-               _endwin = FALSE;
-       }
-
-       /*
-        * initialize loop parameters
-        */
-
-       ly = curscr->_cury;
-       lx = curscr->_curx;
+       register __LINE *wlp;
+       register int retval;
+       register short wy;
+       int dnum;
+       
+       /* Initialize loop parameters. */
+       ly = curscr->cury;
+       lx = curscr->curx;
        wy = 0;
        wy = 0;
-       _win = win;
        curwin = (win == curscr);
 
        curwin = (win == curscr);
 
-       if (win->_clear || curscr->_clear || curwin) {
-               if ((win->_flags & _FULLWIN) || curscr->_clear) {
-                       _puts(CL);
+       if (!curwin)
+               for (wy = 0; wy < win->maxy; wy++) {
+                       wlp = win->lines[wy];
+                       if (wlp->flags & __ISDIRTY)
+                               wlp->hash = 
+                                  __hash((char *) wlp->line, win->maxx * __LDATASIZE);
+               }
+
+       if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) {
+               if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) {
+                       tputs(CL, 0, __cputchar);
                        ly = 0;
                        lx = 0;
                        if (!curwin) {
                        ly = 0;
                        lx = 0;
                        if (!curwin) {
-                               curscr->_clear = FALSE;
-                               curscr->_cury = 0;
-                               curscr->_curx = 0;
+                               curscr->flags &= ~__CLEAROK;
+                               curscr->cury = 0;
+                               curscr->curx = 0;
                                werase(curscr);
                        }
                                werase(curscr);
                        }
-                       touchwin(win);
+                       __touchwin(win);
                }
                }
-               win->_clear = FALSE;
+               win->flags &= ~__CLEAROK;
        }
        if (!CA) {
        }
        if (!CA) {
-               if (win->_curx != 0)
-                       _putchar('\n');
+               if (win->curx != 0)
+                       putchar('\n');
                if (!curwin)
                        werase(curscr);
        }
                if (!curwin)
                        werase(curscr);
        }
-# ifdef DEBUG
-       fprintf(outf, "REFRESH(%0.2o): curwin = %d\n", win, curwin);
-       fprintf(outf, "REFRESH:\n\tfirstch\tlastch\n");
-# endif
-       for (wy = 0; wy < win->_maxy; wy++) {
-# ifdef DEBUG
-               fprintf(outf, "%d\t%d\t%d\n", wy, win->_firstch[wy],
-                       win->_lastch[wy]);
-# endif
-               if (win->_firstch[wy] != _NOCHANGE)
+#ifdef DEBUG
+       __CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin);
+       __CTRACE("wrefresh: \tfirstch\tlastch\n");
+#endif
+
+#ifndef NOQCH
+       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
+
+#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
+               __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;
+               if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) {
                        if (makech(win, wy) == ERR)
                        if (makech(win, wy) == ERR)
-                               return ERR;
+                               return (ERR);
                        else {
                        else {
-                               if (win->_firstch[wy] >= win->_ch_off)
-                                       win->_firstch[wy] = win->_maxx +
-                                                           win->_ch_off;
-                               if (win->_lastch[wy] < win->_maxx +
-                                                      win->_ch_off)
-                                       win->_lastch[wy] = win->_ch_off;
-                               if (win->_lastch[wy] < win->_firstch[wy])
-                                       win->_firstch[wy] = _NOCHANGE;
+                               if (*win->lines[wy]->firstchp >= win->ch_off)
+                                       *win->lines[wy]->firstchp = win->maxx +
+                                           win->ch_off;
+                               if (*win->lines[wy]->lastchp < win->maxx +
+                                   win->ch_off)
+                                       *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;
+                               }
                        }
                        }
-# ifdef DEBUG
-               fprintf(outf, "\t%d\t%d\n", win->_firstch[wy],
-                       win->_lastch[wy]);
-# endif
+
+               }
+#ifdef DEBUG
+               __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp, 
+                       *win->lines[wy]->lastchp);
+#endif
        }
        }
+       
+#ifdef DEBUG
+       __CTRACE("refresh: ly=%d, lx=%d\n", ly, lx);
+#endif
 
        if (win == curscr)
 
        if (win == curscr)
-               domvcur(ly, lx, win->_cury, win->_curx);
+               domvcur(ly, lx, win->cury, win->curx);
        else {
        else {
-               if (win->_leave) {
-                       curscr->_cury = ly;
-                       curscr->_curx = lx;
-                       ly -= win->_begy;
-                       lx -= win->_begx;
-                       if (ly >= 0 && ly < win->_maxy && lx >= 0 &&
-                           lx < win->_maxx) {
-                               win->_cury = ly;
-                               win->_curx = lx;
-                       }
-                       else
-                               win->_cury = win->_curx = 0;
-               }
-               else {
-                       domvcur(ly, lx, win->_cury + win->_begy,
-                               win->_curx + win->_begx);
-                       curscr->_cury = win->_cury + win->_begy;
-                       curscr->_curx = win->_curx + win->_begx;
+               if (win->flags & __LEAVEOK) {
+                       curscr->cury = ly;
+                       curscr->curx = lx;
+                       ly -= win->begy;
+                       lx -= win->begx;
+                       if (ly >= 0 && ly < win->maxy && lx >= 0 &&
+                           lx < win->maxx) {
+                               win->cury = ly;
+                               win->curx = lx;
+                       } else
+                               win->cury = win->curx = 0;
+               } else {
+                       domvcur(ly, lx, win->cury + win->begy,
+                           win->curx + win->begx);
+                       curscr->cury = win->cury + win->begy;
+                       curscr->curx = win->curx + win->begx;
                }
        }
        retval = OK;
                }
        }
        retval = OK;
-ret:
-       _win = NULL;
-       fflush(stdout);
-       return retval;
+
+       (void)fflush(stdout);
+       return (retval);
 }
 
 /*
 }
 
 /*
- * make a change on the screen
+ * makech --
+ *     Make a change on the screen.
  */
  */
-STATIC
+static int
 makech(win, wy)
 makech(win, wy)
-reg WINDOW     *win;
-short          wy;
+       register WINDOW *win;
+       int wy;
 {
 {
-       reg char        *nsp, *csp, *ce;
-       reg short       wx, lch, y;
-       reg int         nlsp, clsp;     /* last space in lines          */
-
-       wx = win->_firstch[wy] - win->_ch_off;
-       if (wx >= win->_maxx)
-               return OK;
-       else if (wx < 0)
+       static __LDATA blank = {' ', 0};
+       register int nlsp, clsp;                /* Last space in lines. */
+       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->_lastch[wy] - win->_ch_off;
+       else if (wx >= win->maxx)
+               return (OK);
+       lch = *win->lines[wy]->lastchp - win->ch_off;
        if (lch < 0)
        if (lch < 0)
-               return OK;
-       else if (lch >= win->_maxx)
-               lch = win->_maxx - 1;;
-       y = wy + win->_begy;
+               return (OK);
+       else if (lch >= (int) win->maxx)
+               lch = win->maxx - 1;
+       y = wy + win->begy;
 
        if (curwin)
 
        if (curwin)
-               csp = " ";
+               csp = &blank;
        else
        else
-               csp = &curscr->_y[wy + win->_begy][wx + win->_begx];
+               csp = &curscr->lines[wy + win->begy]->line[wx + win->begx];
 
 
-       nsp = &win->_y[wy][wx];
+       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->_y[wy][win->_maxx - 1]; *ce == ' '; ce--)
-                       if (ce <= win->_y[wy])
+               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->_y[wy];
+               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) {
-                       domvcur(ly, lx, y, wx + win->_begx);
-# ifdef DEBUG
-                       fprintf(outf, "MAKECH: 1: wx = %d, lx = %d\n", wx, lx);
-# endif        
-                       ly = y;
-                       lx = wx + win->_begx;
-                       while (*nsp != *csp && wx <= lch) {
-                               if (ce != NULL && wx >= nlsp && *nsp == ' ') {
-                                       /*
-                                        * check for clear to end-of-line
-                                        */
-                                       ce = &curscr->_y[ly][COLS - 1];
-                                       while (*ce == ' ')
-                                               if (ce-- <= csp)
-                                                       break;
-                                       clsp = ce - curscr->_y[ly] - win->_begx;
-# ifdef DEBUG
-                                       fprintf(outf, "MAKECH: clsp = %d, nlsp = %d\n", clsp, nlsp);
-# endif
-                                       if (clsp - nlsp >= strlen(CE)
-                                           && clsp < win->_maxx) {
-# ifdef DEBUG
-                                               fprintf(outf, "MAKECH: using CE\n");
-# endif
-                                               _puts(CE);
-                                               lx = wx + win->_begx;
-                                               while (wx++ <= clsp)
-                                                       *csp++ = ' ';
-                                               return OK;
-                                       }
-                                       ce = NULL;
-                               }
-                               /*
-                                * enter/exit standout mode as appropriate
-                                */
-                               if (SO && (*nsp&_STANDOUT) != (curscr->_flags&_STANDOUT)) {
-                                       if (*nsp & _STANDOUT) {
-                                               _puts(SO);
-                                               curscr->_flags |= _STANDOUT;
-                                       }
-                                       else {
-                                               _puts(SE);
-                                               curscr->_flags &= ~_STANDOUT;
-                                       }
-                               }
-                               wx++;
-                               if (wx >= win->_maxx && wy == win->_maxy - 1)
-                                       if (win->_scroll) {
-                                           if ((curscr->_flags&_STANDOUT) &&
-                                               (win->_flags & _ENDLINE))
-                                                   if (!MS) {
-                                                       _puts(SE);
-                                                       curscr->_flags &= ~_STANDOUT;
-                                                   }
+               if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) {
+                       if (wx <= lch) {
+                               while (wx <= lch &&
+                                      memcmp(nsp, csp, sizeof(__LDATA)) == 0) {
+                                           nsp++;
                                            if (!curwin)
                                            if (!curwin)
-                                               _putchar((*csp = *nsp) & 0177);
-                                           else
-                                               _putchar(*nsp & 0177);
-                                           if (win->_flags&_FULLWIN && !curwin)
-                                               scroll(curscr);
-                                           ly = win->_begy+win->_cury;
-                                           lx = win->_begx+win->_curx;
-                                           return OK;
-                                       }
-                                       else if (win->_flags&_SCROLLWIN) {
-                                           lx = --wx;
-                                           return ERR;
+                                                   csp++;
+                                           ++wx;
+                                   }
+                               continue;
+                       }
+                       break;
+               }
+               domvcur(ly, lx, y, wx + win->begx);
+
+#ifdef DEBUG
+               __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;
+               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. */
+                               cep = &curscr->lines[wy]->line[win->maxx - 1];
+                               while (cep->ch == ' ' && cep->attr == 0)
+                                       if (cep-- <= csp)
+                                               break;
+                               clsp = cep - curscr->lines[wy]->line - 
+                                      win->begx * __LDATASIZE;
+#ifdef DEBUG
+                       __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp);
+#endif
+                               if ((clsp - nlsp >= strlen(CE) 
+                                   && clsp < win->maxx * __LDATASIZE) ||
+                                   wy == win->maxy - 1) {
+#ifdef DEBUG
+                                       __CTRACE("makech: using CE\n");
+#endif
+                                       tputs(CE, 0, __cputchar);
+                                       lx = wx + win->begx;
+                                       while (wx++ <= clsp) {
+                                               csp->ch = ' ';
+                                               csp->attr = 0;
+                                               csp++;
                                        }
                                        }
-                               if (!curwin)
-                                       _putchar((*csp++ = *nsp) & 0177);
-                               else
-                                       _putchar(*nsp & 0177);
-# ifdef FULLDEBUG
-                               fprintf(outf,
-                                       "MAKECH:putchar(%c)\n", *nsp & 0177);
-# endif
-                               if (UC && (*nsp & _STANDOUT)) {
-                                       _putchar('\b');
-                                       _puts(UC);
+                                       return (OK);
                                }
                                }
-                               nsp++;
+                               ce = NULL;
                        }
                        }
-# ifdef DEBUG
-                       fprintf(outf, "MAKECH: 2: wx = %d, lx = %d\n", wx, lx);
-# endif        
-                       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');
+
+                       /* Enter/exit standout mode as appropriate. */
+                       if (SO && (nsp->attr & __STANDOUT) !=
+                           (curscr->flags & __WSTANDOUT)) {
+                               if (nsp->attr & __STANDOUT) {
+                                       tputs(SO, 0, __cputchar);
+                                       curscr->flags |= __WSTANDOUT;
+                               } else {
+                                       tputs(SE, 0, __cputchar);
+                                       curscr->flags &= ~__WSTANDOUT;
                                }
                        }
                                }
                        }
-               }
-               else if (wx <= lch)
-                       while (*nsp == *csp && wx <= lch) {
-                               nsp++;
-                               if (!curwin)
+
+                       wx++;
+                       if (wx >= win->maxx && wy == win->maxy - 1 && !curwin)
+                               if (win->flags & __SCROLLOK) {
+                                       if (curscr->flags & __WSTANDOUT
+                                           && win->flags & __ENDLINE)
+                                               if (!MS) {
+                                                       tputs(SE, 0,
+                                                           __cputchar);
+                                                       curscr->flags &=
+                                                           ~__WSTANDOUT;
+                                               }
+                                       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);
+                               } 
+                       if (wx < win->maxx || wy < win->maxy - 1 || 
+                           !(win->flags & __SCROLLWIN)) {
+                               if (!curwin) {
+                                       csp->attr = nsp->attr;
+                                       putchar(csp->ch = nsp->ch);
                                        csp++;
                                        csp++;
-                               ++wx;
+                               } else 
+                                       putchar(nsp->ch);
                        }
                        }
-               else
+#ifdef DEBUG
+                       __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177);
+#endif
+                       if (UC && (nsp->attr & __STANDOUT)) {
+                               putchar('\b');
+                               tputs(UC, 0, __cputchar);
+                       }
+                       nsp++;
+#ifdef DEBUG
+               __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx);
+#endif
+               }
+               if (lx == wx + win->begx)       /* If no change. */
                        break;
                        break;
-# ifdef DEBUG
-               fprintf(outf, "MAKECH: 3: wx = %d, lx = %d\n", wx, lx);
-# endif        
+               lx = wx + win->begx;
+               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
+               __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx);
+#endif
        }
        }
-       return OK;
+       return (OK);
 }
 
 /*
 }
 
 /*
- * perform a mvcur, leaving standout mode if necessary
+ * domvcur --
+ *     Do a mvcur, leaving standout mode if necessary.
  */
  */
-STATIC
+static void
 domvcur(oy, ox, ny, nx)
 domvcur(oy, ox, ny, nx)
-int    oy, ox, ny, nx; {
+       int oy, ox, ny, nx;
+{
+       if (curscr->flags & __WSTANDOUT && !MS) {
+               tputs(SE, 0, __cputchar);
+               curscr->flags &= ~__WSTANDOUT;
+       }
+
+       __mvcur(oy, ox, ny, nx, 1);
+}
+
+/*
+ * Quickch() attempts to detect a pattern in the change of the window
+ * in order to optimize the change, e.g., scroll n lines as opposed to 
+ * repainting the screen line by line.
+ */
+
+static void
+quickch(win)
+       WINDOW *win;
+{
+#define THRESH         (int) win->maxy / 4
 
 
-       if (curscr->_flags & _STANDOUT && !MS) {
-               _puts(SE);
-               curscr->_flags &= ~_STANDOUT;
+       register __LINE *clp, *tmp1, *tmp2;
+       register int bsize, curs, curw, starts, startw, i, j;
+       int n, target, cur_period, bot, top, sc_region;
+       __LDATA buf[1024];
+       u_int blank_hash;
+
+       /* 
+        * 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++)
+                                       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;
+                       }
        }
        }
-       mvcur(oy, ox, ny, nx);
+ done:
+       /* Did not find anything */
+       if (bsize < THRESH)     
+               return;
+
+#ifdef DEBUG
+       __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
+
+       /* 
+        * 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;
+
+#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 */
+       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.
+        * 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.
+        */
+       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];
+#ifdef DEBUG
+               __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ",
+                       n, startw, curw, i, target);
+#endif
+               if ((target >= startw && target < curw) || target < top 
+                   || target > bot) {
+#ifdef DEBUG
+                       __CTRACE("-- notdirty");
+#endif
+                       win->lines[target]->flags &= ~__ISDIRTY;
+               } 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;
+                               __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 {
+#ifdef DEBUG
+                       __CTRACE(" -- dirty");
+#endif
+                       __touchline(win, target, 0, win->maxx - 1, 0);
+               }
+#ifdef DEBUG
+               __CTRACE("\n");
+#endif
+               if (target == cur_period) {
+                       i = target + 1;
+                       tmp1 = curscr->lines[i];
+                       cur_period = i;
+               } else {
+                       tmp1 = tmp2;
+                       i = target;
+               }
+       }
+#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
+scrolln(win, starts, startw, curs, bot, top)
+       WINDOW *win;
+       int starts, startw, curs, bot, top;
+{
+       int i, oy, ox, n;
+
+       oy = curscr->cury;
+       ox = curscr->curx;
+       n = starts - startw;
+
+       if (n > 0) {
+               __mvcur(oy, ox, top, 0, 1);
+               /* Scroll up the block */
+               if (DL)
+                       tputs(__tscroll(DL, n), 0, __cputchar);
+               else
+                       for(i = 0; i < n; i++)
+                               tputs(dl, 0, __cputchar);
+
+               /* 
+                * 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 {
+               /* Preserve the bottom lines */
+               __mvcur(oy, ox, bot + n + 1, 0, 1);     /* n < 0 */
+               if (DL)
+                       tputs(__tscroll(DL, -n), 0, __cputchar);
+               else
+                       for(i = n; i < 0; i++)
+                               tputs(dl, 0, __cputchar);
+               __mvcur(bot + n + 1, 0, top, 0, 1);
+
+               /* Scroll the block down */
+               if (AL) 
+                       tputs(__tscroll(AL, -n), 0, __cputchar);
+               else
+                       for(i = n; i < 0; i++)
+                               tputs(al, 0, __cputchar);
+               __mvcur(top, 0, oy, ox, 1);
+       }               
 }
 }