12261Sarnold /* 234677Sbostic * Copyright (c) 1981 Regents of the University of California. 334677Sbostic * All rights reserved. 434677Sbostic * 542657Sbostic * %sccs.include.redist.c% 622791Smckusick */ 722791Smckusick 822791Smckusick #ifndef lint 9*58034Selan static char sccsid[] = "@(#)refresh.c 5.31 (Berkeley) 02/17/93"; 1034677Sbostic #endif /* not lint */ 1122791Smckusick 1255976Sbostic #include <curses.h> 1355986Sbostic #include <string.h> 142261Sarnold 1555976Sbostic static int curwin; 1655976Sbostic static short ly, lx; 172261Sarnold 1855976Sbostic WINDOW *_win; 192261Sarnold 2055976Sbostic static void domvcur __P((int, int, int, int)); 2155976Sbostic static int makech __P((WINDOW *, int)); 2256302Selan static void quickch __P((WINDOW *)); 2356559Selan static void scrolln __P((WINDOW *, int, int, int, int, int)); 2456648Selan 2555976Sbostic /* 2655976Sbostic * wrefresh -- 2755976Sbostic * Make the current screen look like "win" over the area coverd by 2855976Sbostic * win. 2955976Sbostic */ 3055976Sbostic int 312261Sarnold wrefresh(win) 3255976Sbostic register WINDOW *win; 332261Sarnold { 3456648Selan register __LINE *wlp; 3555976Sbostic register int retval; 3655976Sbostic register short wy; 3758019Selan int dnum; 3858019Selan 3955976Sbostic /* Initialize loop parameters. */ 4056238Selan ly = curscr->cury; 4156238Selan lx = curscr->curx; 422287Sarnold wy = 0; 432287Sarnold _win = win; 442287Sarnold curwin = (win == curscr); 452287Sarnold 4656378Selan if (!curwin) 4756378Selan for (wy = 0; wy < win->maxy; wy++) { 4856378Selan wlp = win->lines[wy]; 4956378Selan if (wlp->flags & __ISDIRTY) 5056648Selan wlp->hash = 5156648Selan __hash(wlp->line, win->maxx * __LDATASIZE); 5256378Selan } 5356378Selan 5456238Selan if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) { 5556238Selan if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) { 5655976Sbostic tputs(CL, 0, __cputchar); 5712358Sarnold ly = 0; 5812358Sarnold lx = 0; 5912358Sarnold if (!curwin) { 6056238Selan curscr->flags &= ~__CLEAROK; 6156238Selan curscr->cury = 0; 6256238Selan curscr->curx = 0; 632287Sarnold werase(curscr); 6412358Sarnold } 6556651Selan __touchwin(win); 662261Sarnold } 6756238Selan win->flags &= ~__CLEAROK; 682261Sarnold } 692261Sarnold if (!CA) { 7056238Selan if (win->curx != 0) 7155976Sbostic putchar('\n'); 722287Sarnold if (!curwin) 732287Sarnold werase(curscr); 742261Sarnold } 7555976Sbostic #ifdef DEBUG 7655976Sbostic __TRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin); 7755976Sbostic __TRACE("wrefresh: \tfirstch\tlastch\n"); 7855976Sbostic #endif 7956302Selan 8056302Selan #ifndef NOQCH 8158019Selan if ((win->flags & __FULLWIN) && !curwin) { 8258019Selan /* 8358019Selan * Invoke quickch() only if more than a quarter of the lines 8458019Selan * in the window are dirty. 8558019Selan */ 8658019Selan for (wy = 0, dnum = 0; wy < win->maxy; wy++) 8758019Selan if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) 8858019Selan dnum++; 8958019Selan if (!__noqch && dnum > (int) win->maxy / 4) 9058019Selan quickch(win); 9158019Selan } 9256302Selan #endif 9356238Selan for (wy = 0; wy < win->maxy; wy++) { 9455976Sbostic #ifdef DEBUG 9555976Sbostic __TRACE("%d\t%d\t%d\n", 9656715Selan wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp); 9755976Sbostic #endif 9856378Selan if (!curwin) 9956378Selan curscr->lines[wy]->hash = win->lines[wy]->hash; 10058019Selan if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) 10157472Sbostic if (makech(win, wy) == ERR) 10257472Sbostic return (ERR); 10319893Sbloom else { 10456715Selan if (*win->lines[wy]->firstchp >= win->ch_off) 10556715Selan *win->lines[wy]->firstchp = win->maxx + 10656238Selan win->ch_off; 10756715Selan if (*win->lines[wy]->lastchp < win->maxx + 10856238Selan win->ch_off) 10956715Selan *win->lines[wy]->lastchp = win->ch_off; 11056715Selan if (*win->lines[wy]->lastchp < 111*58034Selan *win->lines[wy]->firstchp) { 112*58034Selan #ifdef DEBUG 113*58034Selan __TRACE("wrefresh: line %d notdirty \n", wy); 114*58034Selan #endif 11556238Selan win->lines[wy]->flags &= ~__ISDIRTY; 116*58034Selan } 11719893Sbloom } 11855976Sbostic #ifdef DEBUG 11956715Selan __TRACE("\t%d\t%d\n", *win->lines[wy]->firstchp, 12056715Selan *win->lines[wy]->lastchp); 12155976Sbostic #endif 1222261Sarnold } 12356238Selan 12456302Selan #ifdef DEBUG 12556238Selan __TRACE("refresh: ly=%d, lx=%d\n", ly, lx); 12656302Selan #endif 12756472Selan 12812358Sarnold if (win == curscr) 12956238Selan domvcur(ly, lx, win->cury, win->curx); 13019893Sbloom else { 13156238Selan if (win->flags & __LEAVEOK) { 13256238Selan curscr->cury = ly; 13356238Selan curscr->curx = lx; 13456238Selan ly -= win->begy; 13556238Selan lx -= win->begx; 13656238Selan if (ly >= 0 && ly < win->maxy && lx >= 0 && 13756238Selan lx < win->maxx) { 13856238Selan win->cury = ly; 13956238Selan win->curx = lx; 14055976Sbostic } else 14156238Selan win->cury = win->curx = 0; 14255976Sbostic } else { 14356238Selan domvcur(ly, lx, win->cury + win->begy, 14456238Selan win->curx + win->begx); 14556238Selan curscr->cury = win->cury + win->begy; 14656238Selan curscr->curx = win->curx + win->begx; 14719893Sbloom } 1482261Sarnold } 14957472Sbostic retval = OK; 15055986Sbostic 1512261Sarnold _win = NULL; 15255976Sbostic (void)fflush(stdout); 15355976Sbostic return (retval); 1542261Sarnold } 1552261Sarnold 1562261Sarnold /* 15755976Sbostic * makech -- 15855976Sbostic * Make a change on the screen. 1592261Sarnold */ 16055976Sbostic static int 1612261Sarnold makech(win, wy) 16255976Sbostic register WINDOW *win; 16355976Sbostic int wy; 1642261Sarnold { 16555976Sbostic register int nlsp, clsp; /* Last space in lines. */ 16655976Sbostic register short wx, lch, y; 16756648Selan register __LDATA *nsp, *csp, *cp; 16856651Selan u_int force; 16956648Selan char *ce; 17056648Selan __LDATA blank = {' ', 0}; 17156648Selan 17256472Selan /* Is the cursor still on the end of the last line? */ 17356472Selan if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) { 17456551Selan win->lines[wy - 1]->flags &= ~__ISPASTEOL; 17556551Selan domvcur(ly, lx, ly + 1, 0); 17656551Selan ly++; 17756551Selan lx = 0; 17856551Selan } 17956238Selan if (!(win->lines[wy]->flags & __ISDIRTY)) 18057472Sbostic return (OK); 18156715Selan wx = *win->lines[wy]->firstchp - win->ch_off; 18256238Selan if (wx >= win->maxx) 18357472Sbostic return (OK); 18419893Sbloom else if (wx < 0) 18519893Sbloom wx = 0; 18656715Selan lch = *win->lines[wy]->lastchp - win->ch_off; 18719893Sbloom if (lch < 0) 18857472Sbostic return (OK); 18956238Selan else if (lch >= win->maxx) 19056238Selan lch = win->maxx - 1; 19156238Selan y = wy + win->begy; 19219893Sbloom 1932287Sarnold if (curwin) 19456648Selan csp = ␣ 1952287Sarnold else 19656238Selan csp = &curscr->lines[wy + win->begy]->line[wx + win->begx]; 19719893Sbloom 19856238Selan nsp = &win->lines[wy]->line[wx]; 19956651Selan force = win->lines[wy]->flags & __FORCEPAINT; 20056651Selan win->lines[wy]->flags &= ~__FORCEPAINT; 2012287Sarnold if (CE && !curwin) { 20256648Selan for (cp = &win->lines[wy]->line[win->maxx - 1]; 20356648Selan cp->ch == ' ' && cp->attr == 0; cp--) 20456648Selan if (cp <= win->lines[wy]->line) 2052261Sarnold break; 20656648Selan nlsp = cp - win->lines[wy]->line; 2072261Sarnold } 2082287Sarnold if (!curwin) 2092287Sarnold ce = CE; 2102287Sarnold else 2112287Sarnold ce = NULL; 21219893Sbloom 21356651Selan if (force) { 21456651Selan if (CM) 21556651Selan tputs(tgoto(CM, lx, ly), 0, __cputchar); 21656651Selan else { 21756651Selan tputs(HO, 0, __cputchar); 21856651Selan mvcur(0, 0, ly, lx); 21956651Selan } 22056651Selan } 2212261Sarnold while (wx <= lch) { 22257956Selan if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 22355986Sbostic if (wx <= lch) { 22457956Selan while (memcmp(nsp, csp, sizeof(__LDATA)) == 0 && 22556648Selan wx <= lch) { 22656596Selan nsp++; 22756648Selan if (!curwin) 22856648Selan csp++; 22956648Selan ++wx; 23056648Selan } 23155986Sbostic continue; 23255986Sbostic } 23355986Sbostic break; 23455986Sbostic } 23556238Selan domvcur(ly, lx, y, wx + win->begx); 23656378Selan 23755976Sbostic #ifdef DEBUG 23856651Selan __TRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n", 23956651Selan wx, ly, lx, y, wx + win->begx, force); 24055976Sbostic #endif 24155986Sbostic ly = y; 24256238Selan lx = wx + win->begx; 24357956Selan while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) 24456651Selan && wx <= lch) { 24556378Selan #ifdef notdef 24656378Selan /* XXX 24756378Selan * The problem with this code is that we can't count on 24856378Selan * terminals wrapping around after the 24956378Selan * last character on the previous line has been output 25056378Selan * In effect, what then could happen is that the CE 25156378Selan * clear the previous line and do nothing to the 25256378Selan * next line. 25356378Selan */ 25456648Selan if (ce != NULL && wx >= nlsp && 25556648Selan nsp->ch == ' ') { 25655986Sbostic /* Check for clear to end-of-line. */ 25756596Selan ce = &curscr->lines[wy]->line[COLS - 1]; 25856648Selan while (ce->ch == ' ' && ce->attr = 0) 25955986Sbostic if (ce-- <= csp) 26055986Sbostic break; 26156596Selan clsp = ce - curscr->lines[wy]->line - 26256648Selan win->begx * __LDATASIZE; 26355976Sbostic #ifdef DEBUG 26455986Sbostic __TRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 26555976Sbostic #endif 26656648Selan if (clsp - nlsp >= strlen(CE) 26756648Selan && clsp < win->maxx * __LDATASIZE) { 26855976Sbostic #ifdef DEBUG 26955986Sbostic __TRACE("makech: using CE\n"); 27055976Sbostic #endif 27155986Sbostic tputs(CE, 0, __cputchar); 27256238Selan lx = wx + win->begx; 27356596Selan while (wx++ <= clsp) { 27456648Selan csp->ch = ' '; 27556648Selan csp->attr = 0; 27656648Selan csp++; 27756596Selan } 27857472Sbostic return (OK); 2792261Sarnold } 28055986Sbostic ce = NULL; 28155986Sbostic } 28256378Selan #endif 28355986Sbostic 28455986Sbostic /* Enter/exit standout mode as appropriate. */ 28556648Selan if (SO && (nsp->attr & __STANDOUT) != 28656378Selan (curscr->flags & __WSTANDOUT)) { 28756648Selan if (nsp->attr & __STANDOUT) { 28855986Sbostic tputs(SO, 0, __cputchar); 28956238Selan curscr->flags |= __WSTANDOUT; 29055986Sbostic } else { 29155986Sbostic tputs(SE, 0, __cputchar); 29256238Selan curscr->flags &= ~__WSTANDOUT; 2932261Sarnold } 29455986Sbostic } 29555986Sbostic 29655986Sbostic wx++; 29756472Selan if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) 29856238Selan if (win->flags & __SCROLLOK) { 29956238Selan if (curscr->flags & __WSTANDOUT 30056238Selan && win->flags & __ENDLINE) 30155986Sbostic if (!MS) { 30255986Sbostic tputs(SE, 0, 30355986Sbostic __cputchar); 30456238Selan curscr->flags &= 30556238Selan ~__WSTANDOUT; 30655976Sbostic } 30756596Selan if (!curwin) { 30856648Selan csp->attr = nsp->attr; 30956648Selan putchar(csp->ch = nsp->ch); 31056596Selan } else 31156648Selan putchar(nsp->ch); 31256648Selan #ifdef notdef /* XXX why is this here? */ 31356472Selan if (win->flags & __FULLWIN && !curwin) 31455986Sbostic scroll(curscr); 31556378Selan #endif 31656599Selan if (wx + win->begx < curscr->maxx) { 31756599Selan domvcur(ly, wx + win->begx, 31856599Selan win->begy + win->maxy - 1, 31956599Selan win->begx + win->maxx - 1); 32056599Selan } 32156378Selan ly = win->begy + win->maxy - 1; 32256378Selan lx = win->begx + win->maxx - 1; 32357472Sbostic return (OK); 32455986Sbostic } else 32556238Selan if (win->flags & __SCROLLWIN) { 32655986Sbostic lx = --wx; 32757472Sbostic return (ERR); 32855986Sbostic } 32956596Selan if (!curwin) { 33056648Selan csp->attr = nsp->attr; 33156648Selan putchar(csp->ch = nsp->ch); 33256648Selan csp++; 33356648Selan } else 33456648Selan putchar(nsp->ch); 33556472Selan 33655976Sbostic #ifdef DEBUG 33756648Selan __TRACE("makech: putchar(%c)\n", nsp->ch & 0177); 33855976Sbostic #endif 33956648Selan if (UC && (nsp->attr & __STANDOUT)) { 34055986Sbostic putchar('\b'); 34155986Sbostic tputs(UC, 0, __cputchar); 3422261Sarnold } 34355986Sbostic nsp++; 34455986Sbostic } 34555976Sbostic #ifdef DEBUG 34655986Sbostic __TRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 34755976Sbostic #endif 34856238Selan if (lx == wx + win->begx) /* If no change. */ 34955986Sbostic break; 35056238Selan lx = wx + win->begx; 35155986Sbostic if (lx >= COLS && AM) { 35255986Sbostic /* 35355986Sbostic * xn glitch: chomps a newline after auto-wrap. 35455986Sbostic * we just feed it now and forget about it. 35555986Sbostic */ 35655986Sbostic if (XN) { 35756472Selan lx = 0; 35856472Selan ly++; 35955986Sbostic putchar('\n'); 36055986Sbostic putchar('\r'); 36156472Selan } else { 36256472Selan if (wy != LINES) 36356472Selan win->lines[wy]->flags |= __ISPASTEOL; 36456472Selan lx = COLS - 1; 36522789Smckusick } 36656596Selan } else if (wx >= win->maxx) { 36756596Selan if (wy != win->maxy) 36856596Selan win->lines[wy]->flags |= __ISPASTEOL; 36956596Selan domvcur(ly, lx, ly, win->maxx + win->begx - 1); 37056596Selan lx = win->maxx + win->begx - 1; 37155986Sbostic } 37256596Selan 37355976Sbostic #ifdef DEBUG 37455976Sbostic __TRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 37555976Sbostic #endif 3762261Sarnold } 37757472Sbostic return (OK); 37811736Sarnold } 37911736Sarnold 38011736Sarnold /* 38155976Sbostic * domvcur -- 38255976Sbostic * Do a mvcur, leaving standout mode if necessary. 38311736Sarnold */ 38455976Sbostic static void 38511736Sarnold domvcur(oy, ox, ny, nx) 38655976Sbostic int oy, ox, ny, nx; 38755976Sbostic { 38856238Selan if (curscr->flags & __WSTANDOUT && !MS) { 38955976Sbostic tputs(SE, 0, __cputchar); 39056238Selan curscr->flags &= ~__WSTANDOUT; 3912261Sarnold } 39256596Selan 39311736Sarnold mvcur(oy, ox, ny, nx); 3942261Sarnold } 39556302Selan 39656302Selan /* 39756302Selan * Quickch() attempts to detect a pattern in the change of the window 39856552Selan * in order to optimize the change, e.g., scroll n lines as opposed to 39956302Selan * repainting the screen line by line. 40056302Selan */ 40156302Selan 40256715Selan 40356302Selan static void 40456302Selan quickch(win) 40556302Selan WINDOW *win; 40656302Selan { 40758019Selan #define THRESH (int) win->maxy / 4 40856302Selan 40956648Selan register __LINE *clp, *tmp1, *tmp2; 41056378Selan register int bsize, curs, curw, starts, startw, i, j; 41156652Selan int n, target, cur_period, bot, top, sc_region; 41256648Selan __LDATA buf[1024]; 41356378Selan u_int blank_hash; 41456302Selan 41558019Selan /* 41658019Selan * Find how many lines from the top of the screen are unchanged. 41758019Selan */ 418*58034Selan for (top = 0; top < win->maxy; top++) 41958019Selan if (win->lines[top]->flags & __FORCEPAINT || 42058019Selan win->lines[top]->hash != curscr->lines[top]->hash 42158019Selan || memcmp(win->lines[top]->line, 42258019Selan curscr->lines[top]->line, 42358019Selan win->maxx * __LDATASIZE) != 0) 42458019Selan break; 425*58034Selan else 426*58034Selan win->lines[top]->flags &= ~__ISDIRTY; 42758019Selan /* 42858019Selan * Find how many lines from bottom of screen are unchanged. 42958019Selan */ 43058019Selan for (bot = win->maxy - 1; bot >= 0; bot--) 43158019Selan if (win->lines[bot]->flags & __FORCEPAINT || 43258019Selan win->lines[bot]->hash != curscr->lines[bot]->hash 43358019Selan || memcmp(win->lines[bot]->line, 43458019Selan curscr->lines[bot]->line, 43558019Selan win->maxx * __LDATASIZE) != 0) 43658019Selan break; 437*58034Selan else 438*58034Selan win->lines[bot]->flags &= ~__ISDIRTY; 43958019Selan 44056552Selan /* 44156552Selan * Search for the largest block of text not changed. 44256652Selan * Invariants of the loop: 44356652Selan * - Startw is the index of the beginning of the examined block in win. 44456652Selan * - Starts is the index of the beginning of the examined block in 44556652Selan * curscr. 44656652Selan * - Curs is the index of one past the end of the exmined block in win. 44756652Selan * - Curw is the index of one past the end of the exmined block in 44856652Selan * curscr. 44956652Selan * - bsize is the current size of the examined block. 45056552Selan */ 45158019Selan for (bsize = bot - top; bsize >= THRESH; bsize--) { 45258019Selan for (startw = top; startw <= bot - bsize; startw++) 45358019Selan for (starts = top; starts <= bot - bsize; 45456302Selan starts++) { 45556302Selan for (curw = startw, curs = starts; 45656302Selan curs < starts + bsize; curw++, curs++) 45756651Selan if (win->lines[curw]->flags & 45856651Selan __FORCEPAINT || 45956651Selan (win->lines[curw]->hash != 46056552Selan curscr->lines[curs]->hash || 46157956Selan memcmp(win->lines[curw]->line, 46256648Selan curscr->lines[curs]->line, 46356651Selan win->maxx * __LDATASIZE) != 0)) 46456302Selan break; 46556302Selan if (curs == starts + bsize) 46656302Selan goto done; 46756302Selan } 46858019Selan } 46956302Selan done: 47056651Selan /* Did not find anything */ 47156651Selan if (bsize < THRESH) 47256302Selan return; 47356302Selan 47456302Selan #ifdef DEBUG 47556559Selan __TRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 47656559Selan bsize, starts, startw, curw, curs, top, bot); 47756302Selan #endif 47856378Selan 47956559Selan /* 48056559Selan * Make sure that there is no overlap between the bottom and top 48156559Selan * regions and the middle scrolled block. 48256559Selan */ 48356691Selan if (bot < curs) 48456691Selan bot = curs - 1; 48556691Selan if (top > starts) 48656691Selan top = starts; 48756559Selan 48856378Selan n = startw - starts; 48956378Selan 49056691Selan #ifdef DEBUG 49156691Selan __TRACE("#####################################\n"); 49256691Selan for (i = 0; i < curscr->maxy; i++) { 49356691Selan __TRACE("C: %d:", i); 49457356Selan __TRACE(" 0x%x \n", curscr->lines[i]->hash); 49556691Selan for (j = 0; j < curscr->maxx; j++) 49656691Selan __TRACE("%c", 49756691Selan curscr->lines[i]->line[j].ch); 49856691Selan __TRACE("\n"); 49957356Selan for (j = 0; j < curscr->maxx; j++) 50057356Selan __TRACE("%x", 50157356Selan curscr->lines[i]->line[j].attr); 50257356Selan __TRACE("\n"); 50356691Selan __TRACE("W: %d:", i); 50457356Selan __TRACE(" 0x%x \n", win->lines[i]->hash); 50557356Selan __TRACE(" 0x%x ", win->lines[i]->flags); 50656691Selan for (j = 0; j < win->maxx; j++) 50756691Selan __TRACE("%c", 50856691Selan win->lines[i]->line[j].ch); 50956691Selan __TRACE("\n"); 51057356Selan for (j = 0; j < win->maxx; j++) 51157356Selan __TRACE("%x", 51257356Selan win->lines[i]->line[j].attr); 51357356Selan __TRACE("\n"); 51456691Selan } 51556691Selan #endif 51656651Selan if (n != 0) 51756705Selan scrolln(win, starts, startw, curs, bot, top); 51858019Selan 51956378Selan /* So we don't have to call __hash() each time */ 52056648Selan for (i = 0; i < win->maxx; i++) { 52156648Selan buf[i].ch = ' '; 52256648Selan buf[i].attr = 0; 52356648Selan } 52456648Selan blank_hash = __hash(buf, win->maxx * __LDATASIZE); 52556378Selan 52656378Selan /* 52756378Selan * Perform the rotation to maintain the consistency of curscr. 52856691Selan * This is hairy since we are doing an *in place* rotation. 52956652Selan * Invariants of the loop: 53056652Selan * - I is the index of the current line. 53156652Selan * - Target is the index of the target of line i. 53256652Selan * - Tmp1 points to current line (i). 53356652Selan * - Tmp2 and points to target line (target); 53456652Selan * - Cur_period is the index of the end of the current period. 53556652Selan * (see below). 53656652Selan * 53756652Selan * There are 2 major issues here that make this rotation non-trivial: 53856652Selan * 1. Scrolling in a scrolling region bounded by the top 53956652Selan * and bottom regions determined (whose size is sc_region). 54056652Selan * 2. As a result of the use of the mod function, there may be a 54156652Selan * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 54256652Selan * 0 to 2, which then causes all odd lines not to be rotated. 54356652Selan * To remedy this, an index of the end ( = beginning) of the 54456652Selan * current 'period' is kept, cur_period, and when it is reached, 54556652Selan * the next period is started from cur_period + 1 which is 54656652Selan * guaranteed not to have been reached since that would mean that 54756652Selan * all records would have been reached. (think about it...). 54856652Selan * 54956652Selan * Lines in the rotation can have 3 attributes which are marked on the 55056652Selan * line so that curscr is consistent with the visual screen. 55156705Selan * 1. Not dirty -- lines inside the scrolled block, top region or 55256652Selan * bottom region. 55356705Selan * 2. Blank lines -- lines in the differential of the scrolling 55456705Selan * region adjacent to top and bot regions 55556705Selan * depending on scrolling direction. 55656652Selan * 3. Dirty line -- all other lines are marked dirty. 55756378Selan */ 55856648Selan sc_region = bot - top + 1; 55956648Selan i = top; 56056648Selan tmp1 = curscr->lines[top]; 56156652Selan cur_period = top; 56256648Selan for (j = top; j <= bot; j++) { 56356648Selan target = (i - top + n + sc_region) % sc_region + top; 56456378Selan tmp2 = curscr->lines[target]; 56556378Selan curscr->lines[target] = tmp1; 56656378Selan /* Mark block as clean and blank out scrolled lines. */ 56756378Selan clp = curscr->lines[target]; 56856472Selan #ifdef DEBUG 56956378Selan __TRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 57056378Selan n, startw, curw, i, target); 57156472Selan #endif 57256691Selan if ((target >= startw && target < curw) || target < top 57356691Selan || target > bot) { 57456472Selan #ifdef DEBUG 57556378Selan __TRACE("-- notdirty"); 57656472Selan #endif 57756378Selan win->lines[target]->flags &= ~__ISDIRTY; 57856705Selan } else if ((n > 0 && target >= top && target < top + n) || 57956705Selan (n < 0 && target <= bot && target > bot + n)) { 58057956Selan if (clp->hash != blank_hash || memcmp(clp->line, 58156648Selan buf, win->maxx * __LDATASIZE) !=0) { 58256648Selan (void)bcopy(buf, clp->line, 58356648Selan win->maxx * __LDATASIZE); 58456472Selan #ifdef DEBUG 58556648Selan __TRACE("-- blanked out: dirty"); 58656472Selan #endif 58756378Selan clp->hash = blank_hash; 58856652Selan __touchline(win, target, 0, win->maxx - 1, 0); 58956705Selan } else { 59056652Selan __touchline(win, target, 0, win->maxx - 1, 0); 59156472Selan #ifdef DEBUG 59256648Selan __TRACE(" -- blank line already: dirty"); 59356472Selan #endif 59456705Selan } 59556378Selan } else { 59656472Selan #ifdef DEBUG 59756648Selan __TRACE(" -- dirty"); 59856472Selan #endif 59956651Selan __touchline(win, target, 0, win->maxx - 1, 0); 60056378Selan } 60156472Selan #ifdef DEBUG 60256378Selan __TRACE("\n"); 60356472Selan #endif 60456652Selan if (target == cur_period) { 60556378Selan i = target + 1; 60656378Selan tmp1 = curscr->lines[i]; 60756652Selan cur_period = i; 60856378Selan } else { 60956378Selan tmp1 = tmp2; 61056378Selan i = target; 61156378Selan } 61256302Selan } 61356472Selan #ifdef DEBUG 61456648Selan __TRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 61556648Selan for (i = 0; i < curscr->maxy; i++) { 61656691Selan __TRACE("C: %d:", i); 61756648Selan for (j = 0; j < curscr->maxx; j++) 61856648Selan __TRACE("%c", 61956648Selan curscr->lines[i]->line[j].ch); 62056648Selan __TRACE("\n"); 62156691Selan __TRACE("W: %d:", i); 62256691Selan for (j = 0; j < win->maxx; j++) 62356691Selan __TRACE("%c", 62456691Selan win->lines[i]->line[j].ch); 62556691Selan __TRACE("\n"); 62656648Selan } 62756472Selan #endif 62856302Selan } 62956302Selan 63056652Selan /* 63156652Selan * Scrolln performs the scroll by n lines, where n is starts - startw. 63256652Selan */ 63356302Selan static void 63456705Selan scrolln(win, starts, startw, curs, bot, top) 63556302Selan WINDOW *win; 63656705Selan int starts, startw, curs, bot, top; 63756302Selan { 63856302Selan int i, oy, ox, n; 63956302Selan 64056302Selan oy = curscr->cury; 64156302Selan ox = curscr->curx; 64256302Selan n = starts - startw; 64356302Selan 64456302Selan if (n > 0) { 64556559Selan mvcur(oy, ox, top, 0); 64656559Selan /* Scroll up the block */ 64756302Selan if (DL) 64857475Sbostic tputs(__tscroll(DL, n), 0, __cputchar); 64956302Selan else 65056302Selan for(i = 0; i < n; i++) 65156302Selan tputs(dl, 0, __cputchar); 65256652Selan 65356651Selan /* 65456652Selan * Push down the bottom region. 65556651Selan */ 65656705Selan mvcur(top, 0, bot - n + 1, 0); 65758019Selan if (AL) 65857475Sbostic tputs(__tscroll(AL, n), 0, __cputchar); 65956652Selan else 66056652Selan for(i = 0; i < n; i++) 66156652Selan tputs(al, 0, __cputchar); 66256705Selan mvcur(bot - n + 1, 0, oy, ox); 66356302Selan } else { 66456651Selan /* Preserve the bottom lines */ 66556705Selan mvcur(oy, ox, bot + n + 1, 0); /* n < 0 */ 66656652Selan if (DL) 66757475Sbostic tputs(__tscroll(DL, -n), 0, __cputchar); 66856652Selan else 66956652Selan for(i = n; i < 0; i++) 67056652Selan tputs(dl, 0, __cputchar); 67156705Selan mvcur(bot + n + 1, 0, top, 0); 67256302Selan 67356302Selan /* Scroll the block down */ 67458019Selan if (AL) 67557475Sbostic tputs(__tscroll(AL, -n), 0, __cputchar); 67656302Selan else 67756302Selan for(i = n; i < 0; i++) 67856302Selan tputs(al, 0, __cputchar); 67956705Selan mvcur(top, 0, oy, ox); 68056378Selan } 68156302Selan } 68256378Selan 68356378Selan 684