home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / curses / refresh.c < prev    next >
C/C++ Source or Header  |  1996-03-15  |  23KB  |  837 lines

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