12261Sarnold /* 267082Sbostic * Copyright (c) 1981, 1993, 1994 363945Sbostic * The Regents of the University of California. All rights reserved. 434677Sbostic * 542657Sbostic * %sccs.include.redist.c% 622791Smckusick */ 722791Smckusick 822791Smckusick #ifndef lint 9*67583Sbostic static char sccsid[] = "@(#)refresh.c 8.4 (Berkeley) 08/04/94"; 1034677Sbostic #endif /* not lint */ 1122791Smckusick 1255986Sbostic #include <string.h> 132261Sarnold 1467082Sbostic #include "curses.h" 1567082Sbostic 1655976Sbostic static int curwin; 1755976Sbostic static short ly, lx; 182261Sarnold 1955976Sbostic static void domvcur __P((int, int, int, int)); 2055976Sbostic static int makech __P((WINDOW *, int)); 2167571Sbostic static void quickch __P((WINDOW *)); 2256559Selan static void scrolln __P((WINDOW *, int, int, int, int, int)); 2356648Selan 2455976Sbostic /* 2555976Sbostic * wrefresh -- 2655976Sbostic * Make the current screen look like "win" over the area coverd by 2755976Sbostic * win. 2855976Sbostic */ 2955976Sbostic int 302261Sarnold wrefresh(win) 3155976Sbostic register WINDOW *win; 322261Sarnold { 3356648Selan register __LINE *wlp; 3455976Sbostic register int retval; 3555976Sbostic register short wy; 3658019Selan int dnum; 3767571Sbostic 3855976Sbostic /* Initialize loop parameters. */ 3956238Selan ly = curscr->cury; 4056238Selan lx = curscr->curx; 412287Sarnold wy = 0; 422287Sarnold curwin = (win == curscr); 432287Sarnold 4456378Selan if (!curwin) 4556378Selan for (wy = 0; wy < win->maxy; wy++) { 4656378Selan wlp = win->lines[wy]; 4756378Selan if (wlp->flags & __ISDIRTY) 4867571Sbostic wlp->hash = 4958192Selan __hash((char *) wlp->line, win->maxx * __LDATASIZE); 5056378Selan } 5156378Selan 5256238Selan if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) { 5356238Selan if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) { 5455976Sbostic tputs(CL, 0, __cputchar); 5512358Sarnold ly = 0; 5612358Sarnold lx = 0; 5712358Sarnold if (!curwin) { 5856238Selan curscr->flags &= ~__CLEAROK; 5956238Selan curscr->cury = 0; 6056238Selan curscr->curx = 0; 612287Sarnold werase(curscr); 6212358Sarnold } 6356651Selan __touchwin(win); 642261Sarnold } 6556238Selan win->flags &= ~__CLEAROK; 662261Sarnold } 672261Sarnold if (!CA) { 6856238Selan if (win->curx != 0) 6955976Sbostic putchar('\n'); 702287Sarnold if (!curwin) 712287Sarnold werase(curscr); 722261Sarnold } 7355976Sbostic #ifdef DEBUG 7460058Sbostic __CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin); 7560058Sbostic __CTRACE("wrefresh: \tfirstch\tlastch\n"); 7655976Sbostic #endif 7756302Selan 7856302Selan #ifndef NOQCH 7958019Selan if ((win->flags & __FULLWIN) && !curwin) { 8058019Selan /* 8158019Selan * Invoke quickch() only if more than a quarter of the lines 8258019Selan * in the window are dirty. 8358019Selan */ 8458019Selan for (wy = 0, dnum = 0; wy < win->maxy; wy++) 8558019Selan if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) 8658019Selan dnum++; 8758019Selan if (!__noqch && dnum > (int) win->maxy / 4) 8858019Selan quickch(win); 8958019Selan } 9056302Selan #endif 9159930Selan 9259930Selan #ifdef DEBUG 9359930Selan { int i, j; 9460058Sbostic __CTRACE("#####################################\n"); 9559930Selan for (i = 0; i < curscr->maxy; i++) { 9660058Sbostic __CTRACE("C: %d:", i); 9760058Sbostic __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 9867571Sbostic for (j = 0; j < curscr->maxx; j++) 9967571Sbostic __CTRACE("%c", 10059930Selan curscr->lines[i]->line[j].ch); 10160058Sbostic __CTRACE("\n"); 10267571Sbostic for (j = 0; j < curscr->maxx; j++) 10367571Sbostic __CTRACE("%x", 10459930Selan curscr->lines[i]->line[j].attr); 10560058Sbostic __CTRACE("\n"); 10660058Sbostic __CTRACE("W: %d:", i); 10760058Sbostic __CTRACE(" 0x%x \n", win->lines[i]->hash); 10860058Sbostic __CTRACE(" 0x%x ", win->lines[i]->flags); 10967571Sbostic for (j = 0; j < win->maxx; j++) 11067571Sbostic __CTRACE("%c", 11159930Selan win->lines[i]->line[j].ch); 11260058Sbostic __CTRACE("\n"); 11367571Sbostic for (j = 0; j < win->maxx; j++) 11467571Sbostic __CTRACE("%x", 11559930Selan win->lines[i]->line[j].attr); 11660058Sbostic __CTRACE("\n"); 11759930Selan } 11859930Selan } 11959930Selan #endif /* DEBUG */ 12059930Selan 12156238Selan for (wy = 0; wy < win->maxy; wy++) { 12255976Sbostic #ifdef DEBUG 12360058Sbostic __CTRACE("%d\t%d\t%d\n", 12456715Selan wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp); 12555976Sbostic #endif 12656378Selan if (!curwin) 12756378Selan curscr->lines[wy]->hash = win->lines[wy]->hash; 12858369Selan if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) { 12957472Sbostic if (makech(win, wy) == ERR) 13057472Sbostic return (ERR); 13119893Sbloom else { 13256715Selan if (*win->lines[wy]->firstchp >= win->ch_off) 13356715Selan *win->lines[wy]->firstchp = win->maxx + 13456238Selan win->ch_off; 13556715Selan if (*win->lines[wy]->lastchp < win->maxx + 13656238Selan win->ch_off) 13756715Selan *win->lines[wy]->lastchp = win->ch_off; 13867571Sbostic if (*win->lines[wy]->lastchp < 13958034Selan *win->lines[wy]->firstchp) { 14058034Selan #ifdef DEBUG 14160058Sbostic __CTRACE("wrefresh: line %d notdirty \n", wy); 14258034Selan #endif 14356238Selan win->lines[wy]->flags &= ~__ISDIRTY; 14458034Selan } 14519893Sbloom } 14658369Selan 14759774Selan } 14855976Sbostic #ifdef DEBUG 14967571Sbostic __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp, 15056715Selan *win->lines[wy]->lastchp); 15155976Sbostic #endif 1522261Sarnold } 15367571Sbostic 15456302Selan #ifdef DEBUG 15560058Sbostic __CTRACE("refresh: ly=%d, lx=%d\n", ly, lx); 15656302Selan #endif 15756472Selan 15812358Sarnold if (win == curscr) 15956238Selan domvcur(ly, lx, win->cury, win->curx); 16019893Sbloom else { 16156238Selan if (win->flags & __LEAVEOK) { 16256238Selan curscr->cury = ly; 16356238Selan curscr->curx = lx; 16456238Selan ly -= win->begy; 16556238Selan lx -= win->begx; 16656238Selan if (ly >= 0 && ly < win->maxy && lx >= 0 && 16756238Selan lx < win->maxx) { 16856238Selan win->cury = ly; 16956238Selan win->curx = lx; 17055976Sbostic } else 17156238Selan win->cury = win->curx = 0; 17255976Sbostic } else { 17356238Selan domvcur(ly, lx, win->cury + win->begy, 17456238Selan win->curx + win->begx); 17556238Selan curscr->cury = win->cury + win->begy; 17656238Selan curscr->curx = win->curx + win->begx; 17719893Sbloom } 1782261Sarnold } 17957472Sbostic retval = OK; 18055986Sbostic 18155976Sbostic (void)fflush(stdout); 18255976Sbostic return (retval); 1832261Sarnold } 1842261Sarnold 1852261Sarnold /* 18655976Sbostic * makech -- 18755976Sbostic * Make a change on the screen. 1882261Sarnold */ 18955976Sbostic static int 1902261Sarnold makech(win, wy) 19155976Sbostic register WINDOW *win; 19255976Sbostic int wy; 1932261Sarnold { 19460614Sbostic static __LDATA blank = {' ', 0}; 19559775Selan register int nlsp, clsp; /* Last space in lines. */ 19659352Selan register int wx, lch, y; 19759775Selan register __LDATA *nsp, *csp, *cp, *cep; 19856651Selan u_int force; 19956648Selan char *ce; 20056648Selan 20156472Selan /* Is the cursor still on the end of the last line? */ 20256472Selan if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) { 20356551Selan domvcur(ly, lx, ly + 1, 0); 20456551Selan ly++; 20556551Selan lx = 0; 20656551Selan } 20756715Selan wx = *win->lines[wy]->firstchp - win->ch_off; 20859352Selan if (wx < 0) 20959352Selan wx = 0; 21059352Selan else if (wx >= win->maxx) 21157472Sbostic return (OK); 21256715Selan lch = *win->lines[wy]->lastchp - win->ch_off; 21319893Sbloom if (lch < 0) 21457472Sbostic return (OK); 21559352Selan else if (lch >= (int) win->maxx) 21656238Selan lch = win->maxx - 1; 21756238Selan y = wy + win->begy; 21819893Sbloom 2192287Sarnold if (curwin) 22056648Selan csp = ␣ 2212287Sarnold else 22256238Selan csp = &curscr->lines[wy + win->begy]->line[wx + win->begx]; 22319893Sbloom 22456238Selan nsp = &win->lines[wy]->line[wx]; 22556651Selan force = win->lines[wy]->flags & __FORCEPAINT; 22656651Selan win->lines[wy]->flags &= ~__FORCEPAINT; 2272287Sarnold if (CE && !curwin) { 22867571Sbostic for (cp = &win->lines[wy]->line[win->maxx - 1]; 22956648Selan cp->ch == ' ' && cp->attr == 0; cp--) 23056648Selan if (cp <= win->lines[wy]->line) 2312261Sarnold break; 23256648Selan nlsp = cp - win->lines[wy]->line; 2332261Sarnold } 2342287Sarnold if (!curwin) 2352287Sarnold ce = CE; 2362287Sarnold else 2372287Sarnold ce = NULL; 23819893Sbloom 23956651Selan if (force) { 24056651Selan if (CM) 24156651Selan tputs(tgoto(CM, lx, ly), 0, __cputchar); 24256651Selan else { 24356651Selan tputs(HO, 0, __cputchar); 24459930Selan __mvcur(0, 0, ly, lx, 1); 24556651Selan } 24656651Selan } 2472261Sarnold while (wx <= lch) { 24857956Selan if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 24955986Sbostic if (wx <= lch) { 25063944Sbostic while (wx <= lch && 25163944Sbostic memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 25256596Selan nsp++; 25356648Selan if (!curwin) 25456648Selan csp++; 25556648Selan ++wx; 25656648Selan } 25755986Sbostic continue; 25855986Sbostic } 25955986Sbostic break; 26055986Sbostic } 26156238Selan domvcur(ly, lx, y, wx + win->begx); 26256378Selan 26355976Sbostic #ifdef DEBUG 26467571Sbostic __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n", 26556651Selan wx, ly, lx, y, wx + win->begx, force); 26655976Sbostic #endif 26755986Sbostic ly = y; 26856238Selan lx = wx + win->begx; 26967571Sbostic while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) 27056651Selan && wx <= lch) { 27155986Sbostic 27267571Sbostic if (ce != NULL && win->maxx + win->begx == 27359775Selan curscr->maxx && wx >= nlsp && nsp->ch == ' ') { 27459775Selan /* Check for clear to end-of-line. */ 27559775Selan cep = &curscr->lines[wy]->line[win->maxx - 1]; 27659775Selan while (cep->ch == ' ' && cep->attr == 0) 27759775Selan if (cep-- <= csp) 27859775Selan break; 27967571Sbostic clsp = cep - curscr->lines[wy]->line - 28059775Selan win->begx * __LDATASIZE; 28159775Selan #ifdef DEBUG 28260058Sbostic __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 28359775Selan #endif 28467571Sbostic if ((clsp - nlsp >= strlen(CE) 28559775Selan && clsp < win->maxx * __LDATASIZE) || 28659775Selan wy == win->maxy - 1) { 28759775Selan #ifdef DEBUG 28860058Sbostic __CTRACE("makech: using CE\n"); 28959775Selan #endif 29059775Selan tputs(CE, 0, __cputchar); 29159775Selan lx = wx + win->begx; 29259775Selan while (wx++ <= clsp) { 29359775Selan csp->ch = ' '; 29459775Selan csp->attr = 0; 29559775Selan csp++; 29659775Selan } 29759775Selan return (OK); 29859775Selan } 29959775Selan ce = NULL; 30059775Selan } 30159775Selan 30255986Sbostic /* Enter/exit standout mode as appropriate. */ 30356648Selan if (SO && (nsp->attr & __STANDOUT) != 30456378Selan (curscr->flags & __WSTANDOUT)) { 30556648Selan if (nsp->attr & __STANDOUT) { 30655986Sbostic tputs(SO, 0, __cputchar); 30756238Selan curscr->flags |= __WSTANDOUT; 30855986Sbostic } else { 30955986Sbostic tputs(SE, 0, __cputchar); 31056238Selan curscr->flags &= ~__WSTANDOUT; 3112261Sarnold } 31255986Sbostic } 31355986Sbostic 31455986Sbostic wx++; 31556472Selan if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) 31656238Selan if (win->flags & __SCROLLOK) { 31756238Selan if (curscr->flags & __WSTANDOUT 31856238Selan && win->flags & __ENDLINE) 31955986Sbostic if (!MS) { 32055986Sbostic tputs(SE, 0, 32155986Sbostic __cputchar); 32256238Selan curscr->flags &= 32356238Selan ~__WSTANDOUT; 32455976Sbostic } 32559760Selan if (!(win->flags & __SCROLLWIN)) { 32659760Selan if (!curwin) { 32759760Selan csp->attr = nsp->attr; 32859760Selan putchar(csp->ch = nsp->ch); 32959760Selan } else 33059760Selan putchar(nsp->ch); 33159760Selan } 33256599Selan if (wx + win->begx < curscr->maxx) { 33367571Sbostic domvcur(ly, wx + win->begx, 33456599Selan win->begy + win->maxy - 1, 33556599Selan win->begx + win->maxx - 1); 33656599Selan } 33756378Selan ly = win->begy + win->maxy - 1; 33856378Selan lx = win->begx + win->maxx - 1; 33957472Sbostic return (OK); 34067571Sbostic } 34167571Sbostic if (wx < win->maxx || wy < win->maxy - 1 || 34259760Selan !(win->flags & __SCROLLWIN)) { 34359760Selan if (!curwin) { 34459760Selan csp->attr = nsp->attr; 34559760Selan putchar(csp->ch = nsp->ch); 34659760Selan csp++; 34767571Sbostic } else 34859760Selan putchar(nsp->ch); 34959760Selan } 35055976Sbostic #ifdef DEBUG 35160058Sbostic __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); 35255976Sbostic #endif 35356648Selan if (UC && (nsp->attr & __STANDOUT)) { 35455986Sbostic putchar('\b'); 35555986Sbostic tputs(UC, 0, __cputchar); 3562261Sarnold } 35755986Sbostic nsp++; 35855976Sbostic #ifdef DEBUG 35960058Sbostic __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 36055976Sbostic #endif 36159760Selan } 36256238Selan if (lx == wx + win->begx) /* If no change. */ 36355986Sbostic break; 36456238Selan lx = wx + win->begx; 36559774Selan if (lx >= COLS && AM) 36658040Selan lx = COLS - 1; 36759774Selan else if (wx >= win->maxx) { 36856596Selan domvcur(ly, lx, ly, win->maxx + win->begx - 1); 36956596Selan lx = win->maxx + win->begx - 1; 37055986Sbostic } 37156596Selan 37255976Sbostic #ifdef DEBUG 37360058Sbostic __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 37455976Sbostic #endif 3752261Sarnold } 37657472Sbostic return (OK); 37711736Sarnold } 37811736Sarnold 37911736Sarnold /* 38055976Sbostic * domvcur -- 38155976Sbostic * Do a mvcur, leaving standout mode if necessary. 38211736Sarnold */ 38355976Sbostic static void 38411736Sarnold domvcur(oy, ox, ny, nx) 38555976Sbostic int oy, ox, ny, nx; 38655976Sbostic { 38756238Selan if (curscr->flags & __WSTANDOUT && !MS) { 38855976Sbostic tputs(SE, 0, __cputchar); 38956238Selan curscr->flags &= ~__WSTANDOUT; 3902261Sarnold } 39156596Selan 39259930Selan __mvcur(oy, ox, ny, nx, 1); 3932261Sarnold } 39456302Selan 39556302Selan /* 39656302Selan * Quickch() attempts to detect a pattern in the change of the window 39767571Sbostic * in order to optimize the change, e.g., scroll n lines as opposed to 39856302Selan * repainting the screen line by line. 39956302Selan */ 40056302Selan 40156302Selan static void 40256302Selan quickch(win) 40356302Selan WINDOW *win; 40456302Selan { 40558019Selan #define THRESH (int) win->maxy / 4 40656302Selan 40756648Selan register __LINE *clp, *tmp1, *tmp2; 40856378Selan register int bsize, curs, curw, starts, startw, i, j; 40956652Selan int n, target, cur_period, bot, top, sc_region; 41056648Selan __LDATA buf[1024]; 41156378Selan u_int blank_hash; 41256302Selan 41367571Sbostic /* 41458019Selan * Find how many lines from the top of the screen are unchanged. 41558019Selan */ 41667571Sbostic for (top = 0; top < win->maxy; top++) 41758019Selan if (win->lines[top]->flags & __FORCEPAINT || 41867571Sbostic win->lines[top]->hash != curscr->lines[top]->hash 41967571Sbostic || memcmp(win->lines[top]->line, 42067571Sbostic curscr->lines[top]->line, 42158019Selan win->maxx * __LDATASIZE) != 0) 42258019Selan break; 42358034Selan else 42458034Selan win->lines[top]->flags &= ~__ISDIRTY; 42558019Selan /* 42667571Sbostic * Find how many lines from bottom of screen are unchanged. 42758019Selan */ 42858019Selan for (bot = win->maxy - 1; bot >= 0; bot--) 42958019Selan if (win->lines[bot]->flags & __FORCEPAINT || 43067571Sbostic win->lines[bot]->hash != curscr->lines[bot]->hash 43167571Sbostic || memcmp(win->lines[bot]->line, 43267571Sbostic curscr->lines[bot]->line, 43358019Selan win->maxx * __LDATASIZE) != 0) 43458019Selan break; 43558034Selan else 43658034Selan win->lines[bot]->flags &= ~__ISDIRTY; 43758019Selan 43859352Selan #ifdef NO_JERKINESS 43956552Selan /* 44059062Selan * If we have a bottom unchanged region return. Scrolling the 44159062Selan * bottom region up and then back down causes a screen jitter. 44259062Selan * This will increase the number of characters sent to the screen 44359062Selan * but it looks better. 44459062Selan */ 44559062Selan if (bot < win->maxy - 1) 44659062Selan return; 44759352Selan #endif /* NO_JERKINESS */ 44859062Selan 44959062Selan /* 45056552Selan * Search for the largest block of text not changed. 45156652Selan * Invariants of the loop: 45256652Selan * - Startw is the index of the beginning of the examined block in win. 45367571Sbostic * - Starts is the index of the beginning of the examined block in 45456652Selan * curscr. 45556652Selan * - Curs is the index of one past the end of the exmined block in win. 45667571Sbostic * - Curw is the index of one past the end of the exmined block in 45756652Selan * curscr. 45856652Selan * - bsize is the current size of the examined block. 45956552Selan */ 46058019Selan for (bsize = bot - top; bsize >= THRESH; bsize--) { 46158019Selan for (startw = top; startw <= bot - bsize; startw++) 46267571Sbostic for (starts = top; starts <= bot - bsize; 46356302Selan starts++) { 46456302Selan for (curw = startw, curs = starts; 46556302Selan curs < starts + bsize; curw++, curs++) 46656651Selan if (win->lines[curw]->flags & 46756651Selan __FORCEPAINT || 46856651Selan (win->lines[curw]->hash != 46956552Selan curscr->lines[curs]->hash || 47067571Sbostic memcmp(win->lines[curw]->line, 47167571Sbostic curscr->lines[curs]->line, 47256651Selan win->maxx * __LDATASIZE) != 0)) 47356302Selan break; 47456302Selan if (curs == starts + bsize) 47556302Selan goto done; 47656302Selan } 47758019Selan } 47856302Selan done: 47956651Selan /* Did not find anything */ 48067571Sbostic if (bsize < THRESH) 48156302Selan return; 48256302Selan 48356302Selan #ifdef DEBUG 48467571Sbostic __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 48556559Selan bsize, starts, startw, curw, curs, top, bot); 48656302Selan #endif 48756378Selan 48867571Sbostic /* 48967571Sbostic * Make sure that there is no overlap between the bottom and top 49056559Selan * regions and the middle scrolled block. 49156559Selan */ 49256691Selan if (bot < curs) 49356691Selan bot = curs - 1; 49456691Selan if (top > starts) 49556691Selan top = starts; 49656559Selan 49756378Selan n = startw - starts; 49856378Selan 49956691Selan #ifdef DEBUG 50060058Sbostic __CTRACE("#####################################\n"); 50156691Selan for (i = 0; i < curscr->maxy; i++) { 50260058Sbostic __CTRACE("C: %d:", i); 50360058Sbostic __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 50467571Sbostic for (j = 0; j < curscr->maxx; j++) 50567571Sbostic __CTRACE("%c", 50656691Selan curscr->lines[i]->line[j].ch); 50760058Sbostic __CTRACE("\n"); 50867571Sbostic for (j = 0; j < curscr->maxx; j++) 50967571Sbostic __CTRACE("%x", 51057356Selan curscr->lines[i]->line[j].attr); 51160058Sbostic __CTRACE("\n"); 51260058Sbostic __CTRACE("W: %d:", i); 51360058Sbostic __CTRACE(" 0x%x \n", win->lines[i]->hash); 51460058Sbostic __CTRACE(" 0x%x ", win->lines[i]->flags); 51567571Sbostic for (j = 0; j < win->maxx; j++) 51667571Sbostic __CTRACE("%c", 51756691Selan win->lines[i]->line[j].ch); 51860058Sbostic __CTRACE("\n"); 51967571Sbostic for (j = 0; j < win->maxx; j++) 52067571Sbostic __CTRACE("%x", 52157356Selan win->lines[i]->line[j].attr); 52260058Sbostic __CTRACE("\n"); 52356691Selan } 52467571Sbostic #endif 52567571Sbostic 52656378Selan /* So we don't have to call __hash() each time */ 52756648Selan for (i = 0; i < win->maxx; i++) { 52856648Selan buf[i].ch = ' '; 52956648Selan buf[i].attr = 0; 53056648Selan } 53158192Selan blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE); 53256378Selan 53356378Selan /* 53456378Selan * Perform the rotation to maintain the consistency of curscr. 53556691Selan * This is hairy since we are doing an *in place* rotation. 53656652Selan * Invariants of the loop: 53756652Selan * - I is the index of the current line. 53856652Selan * - Target is the index of the target of line i. 53956652Selan * - Tmp1 points to current line (i). 54056652Selan * - Tmp2 and points to target line (target); 54167571Sbostic * - Cur_period is the index of the end of the current period. 54256652Selan * (see below). 54356652Selan * 54456652Selan * There are 2 major issues here that make this rotation non-trivial: 54556652Selan * 1. Scrolling in a scrolling region bounded by the top 54656652Selan * and bottom regions determined (whose size is sc_region). 54767571Sbostic * 2. As a result of the use of the mod function, there may be a 54856652Selan * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 54956652Selan * 0 to 2, which then causes all odd lines not to be rotated. 55067571Sbostic * To remedy this, an index of the end ( = beginning) of the 55167571Sbostic * current 'period' is kept, cur_period, and when it is reached, 55267571Sbostic * the next period is started from cur_period + 1 which is 55356652Selan * guaranteed not to have been reached since that would mean that 55456652Selan * all records would have been reached. (think about it...). 55567571Sbostic * 55656652Selan * Lines in the rotation can have 3 attributes which are marked on the 55756652Selan * line so that curscr is consistent with the visual screen. 55856705Selan * 1. Not dirty -- lines inside the scrolled block, top region or 55956652Selan * bottom region. 56067571Sbostic * 2. Blank lines -- lines in the differential of the scrolling 56167571Sbostic * region adjacent to top and bot regions 56256705Selan * depending on scrolling direction. 56356652Selan * 3. Dirty line -- all other lines are marked dirty. 56456378Selan */ 56556648Selan sc_region = bot - top + 1; 56656648Selan i = top; 56756648Selan tmp1 = curscr->lines[top]; 56856652Selan cur_period = top; 56956648Selan for (j = top; j <= bot; j++) { 57056648Selan target = (i - top + n + sc_region) % sc_region + top; 57156378Selan tmp2 = curscr->lines[target]; 57256378Selan curscr->lines[target] = tmp1; 57356378Selan /* Mark block as clean and blank out scrolled lines. */ 57456378Selan clp = curscr->lines[target]; 57556472Selan #ifdef DEBUG 57660058Sbostic __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 57756378Selan n, startw, curw, i, target); 57856472Selan #endif 57967571Sbostic if ((target >= startw && target < curw) || target < top 58056691Selan || target > bot) { 58156472Selan #ifdef DEBUG 58260058Sbostic __CTRACE("-- notdirty"); 58356472Selan #endif 58456378Selan win->lines[target]->flags &= ~__ISDIRTY; 58556705Selan } else if ((n > 0 && target >= top && target < top + n) || 58656705Selan (n < 0 && target <= bot && target > bot + n)) { 58767571Sbostic if (clp->hash != blank_hash || memcmp(clp->line, 58856648Selan buf, win->maxx * __LDATASIZE) !=0) { 58958041Selan (void)memcpy(clp->line, buf, 59056648Selan win->maxx * __LDATASIZE); 59156472Selan #ifdef DEBUG 59260058Sbostic __CTRACE("-- blanked out: dirty"); 59356472Selan #endif 59456378Selan clp->hash = blank_hash; 59556652Selan __touchline(win, target, 0, win->maxx - 1, 0); 59656705Selan } else { 59756652Selan __touchline(win, target, 0, win->maxx - 1, 0); 59856472Selan #ifdef DEBUG 59960058Sbostic __CTRACE(" -- blank line already: dirty"); 60056472Selan #endif 60156705Selan } 60256378Selan } else { 60356472Selan #ifdef DEBUG 60460058Sbostic __CTRACE(" -- dirty"); 60556472Selan #endif 60656651Selan __touchline(win, target, 0, win->maxx - 1, 0); 60756378Selan } 60856472Selan #ifdef DEBUG 60960058Sbostic __CTRACE("\n"); 61056472Selan #endif 61156652Selan if (target == cur_period) { 61256378Selan i = target + 1; 61356378Selan tmp1 = curscr->lines[i]; 61456652Selan cur_period = i; 61556378Selan } else { 61656378Selan tmp1 = tmp2; 61756378Selan i = target; 61856378Selan } 61956302Selan } 62056472Selan #ifdef DEBUG 62160058Sbostic __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 62256648Selan for (i = 0; i < curscr->maxy; i++) { 62360058Sbostic __CTRACE("C: %d:", i); 62467571Sbostic for (j = 0; j < curscr->maxx; j++) 62567571Sbostic __CTRACE("%c", 62656648Selan curscr->lines[i]->line[j].ch); 62760058Sbostic __CTRACE("\n"); 62860058Sbostic __CTRACE("W: %d:", i); 62967571Sbostic for (j = 0; j < win->maxx; j++) 63067571Sbostic __CTRACE("%c", win->lines[i]->line[j].ch); 63160058Sbostic __CTRACE("\n"); 63256648Selan } 63356472Selan #endif 63460100Selan if (n != 0) { 63560100Selan WINDOW *wp; 63659930Selan scrolln(win, starts, startw, curs, bot, top); 63760100Selan /* 63860100Selan * Need to repoint any subwindow lines to the rotated 63967571Sbostic * line structured. 64060100Selan */ 64160100Selan for (wp = win->nextp; wp != win; wp = wp->nextp) 64260100Selan __set_subwin(win, wp); 64360100Selan } 64456302Selan } 64556302Selan 64656652Selan /* 64767571Sbostic * scrolln -- 64867571Sbostic * Scroll n lines, where n is starts - startw. 64956652Selan */ 65056302Selan static void 65156705Selan scrolln(win, starts, startw, curs, bot, top) 65256302Selan WINDOW *win; 65356705Selan int starts, startw, curs, bot, top; 65456302Selan { 65556302Selan int i, oy, ox, n; 65656302Selan 65756302Selan oy = curscr->cury; 65856302Selan ox = curscr->curx; 65956302Selan n = starts - startw; 66056302Selan 661*67583Sbostic /* 662*67583Sbostic * XXX 663*67583Sbostic * The initial tests that set __noqch don't let us reach here unless 664*67583Sbostic * we have either CS + HO + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr 665*67583Sbostic * scrolling can only shift the entire scrolling region, not just a 666*67583Sbostic * part of it, which means that the quickch() routine is going to be 667*67583Sbostic * sadly disappointed in us if we don't have CS as well. 668*67583Sbostic * 669*67583Sbostic * If CS, HO and SF/sf are set, can use the scrolling region. Because 670*67583Sbostic * the cursor position after CS is undefined, we need HO which gives us 671*67583Sbostic * the ability to move to somewhere without knowledge of the current 672*67583Sbostic * location of the cursor. Still call __mvcur() anyway, to update its 673*67583Sbostic * idea of where the cursor is. 674*67583Sbostic * 675*67583Sbostic * When the scrolling region has been set, the cursor has to be at the 676*67583Sbostic * last line of the region to make the scroll happen. 677*67583Sbostic * 678*67583Sbostic * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr 679*67583Sbostic * or al/dl, and, some terminals have AL/DL, sf/sr, and CS, but not 680*67583Sbostic * SF/SR. So, if we're scrolling almost all of the screen, try and use 681*67583Sbostic * AL/DL, otherwise use the scrolling region. The "almost all" is a 682*67583Sbostic * shameless hack for vi. 683*67583Sbostic */ 68456302Selan if (n > 0) { 685*67583Sbostic if (CS != NULL && HO != NULL && (SF != NULL || 686*67583Sbostic (AL == NULL || DL == NULL || 687*67583Sbostic top > 3 || bot + 3 < win->maxy) && sf != NULL)) { 68867571Sbostic tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 68967571Sbostic __mvcur(oy, ox, 0, 0, 1); 69067571Sbostic tputs(HO, 0, __cputchar); 69167571Sbostic __mvcur(0, 0, bot, 0, 1); 69267571Sbostic if (SF != NULL) 69367571Sbostic tputs(__tscroll(SF, n, 0), 0, __cputchar); 69467571Sbostic else 69567571Sbostic for (i = 0; i < n; i++) 69667571Sbostic tputs(sf, 0, __cputchar); 69767571Sbostic tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 69867571Sbostic __mvcur(bot, 0, 0, 0, 1); 69967571Sbostic tputs(HO, 0, __cputchar); 70067571Sbostic __mvcur(0, 0, oy, ox, 1); 70167571Sbostic return; 70267571Sbostic } 70367571Sbostic 704*67583Sbostic /* Scroll up the block. */ 70559930Selan __mvcur(oy, ox, top, 0, 1); 706*67583Sbostic if (SF != NULL && top == 0) 707*67583Sbostic tputs(__tscroll(SF, n, 0), 0, __cputchar); 708*67583Sbostic else if (DL != NULL) 70967571Sbostic tputs(__tscroll(DL, n, 0), 0, __cputchar); 710*67583Sbostic else if (dl != NULL) 71167571Sbostic for (i = 0; i < n; i++) 71256302Selan tputs(dl, 0, __cputchar); 713*67583Sbostic else if (sf != NULL && top == 0) 714*67583Sbostic for (i = 0; i < n; i++) 715*67583Sbostic tputs(sf, 0, __cputchar); 716*67583Sbostic else 717*67583Sbostic abort(); 71856652Selan 71967571Sbostic /* Push down the bottom region. */ 72059930Selan __mvcur(top, 0, bot - n + 1, 0, 1); 721*67583Sbostic if (AL != NULL) 72267571Sbostic tputs(__tscroll(AL, n, 0), 0, __cputchar); 723*67583Sbostic else if (al != NULL) 72467571Sbostic for (i = 0; i < n; i++) 72556652Selan tputs(al, 0, __cputchar); 726*67583Sbostic else 727*67583Sbostic abort(); 72859930Selan __mvcur(bot - n + 1, 0, oy, ox, 1); 72956302Selan } else { 73067571Sbostic /* 731*67583Sbostic * !!! 732*67583Sbostic * n < 0 733*67583Sbostic * 734*67583Sbostic * If CS, HO and SR/sr are set, can use the scrolling region. 735*67583Sbostic * See the above comments for details. 73667571Sbostic */ 737*67583Sbostic if (CS != NULL && HO != NULL && (SR != NULL || 738*67583Sbostic (AL == NULL || DL == NULL || 739*67583Sbostic top > 3 || bot + 3 < win->maxy) && sr != NULL)) { 74067571Sbostic tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 74167571Sbostic __mvcur(oy, ox, 0, 0, 1); 74267571Sbostic tputs(HO, 0, __cputchar); 74367571Sbostic __mvcur(0, 0, top, 0, 1); 74467571Sbostic 74567571Sbostic if (SR != NULL) 746*67583Sbostic tputs(__tscroll(SR, -n, 0), 0, __cputchar); 74767571Sbostic else 748*67583Sbostic for (i = n; i < 0; i++) 74967571Sbostic tputs(sr, 0, __cputchar); 75067571Sbostic tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 75167571Sbostic __mvcur(top, 0, 0, 0, 1); 75267571Sbostic tputs(HO, 0, __cputchar); 75367571Sbostic __mvcur(0, 0, oy, ox, 1); 75467571Sbostic return; 75567571Sbostic } 75667571Sbostic 757*67583Sbostic /* Preserve the bottom lines. */ 758*67583Sbostic __mvcur(oy, ox, bot + n + 1, 0, 1); 759*67583Sbostic if (SR != NULL && bot == win->maxy) 760*67583Sbostic tputs(__tscroll(SR, -n, 0), 0, __cputchar); 761*67583Sbostic else if (DL != NULL) 76267571Sbostic tputs(__tscroll(DL, -n, 0), 0, __cputchar); 763*67583Sbostic else if (dl != NULL) 76467571Sbostic for (i = n; i < 0; i++) 76556652Selan tputs(dl, 0, __cputchar); 766*67583Sbostic else if (sr != NULL && bot == win->maxy) 767*67583Sbostic for (i = n; i < 0; i++) 768*67583Sbostic tputs(sr, 0, __cputchar); 769*67583Sbostic else 770*67583Sbostic abort(); 77156302Selan 77267571Sbostic /* Scroll the block down. */ 773*67583Sbostic __mvcur(bot + n + 1, 0, top, 0, 1); 774*67583Sbostic if (AL != NULL) 77567571Sbostic tputs(__tscroll(AL, -n, 0), 0, __cputchar); 776*67583Sbostic else if (al != NULL) 77767571Sbostic for (i = n; i < 0; i++) 77856302Selan tputs(al, 0, __cputchar); 779*67583Sbostic else 780*67583Sbostic abort(); 78159930Selan __mvcur(top, 0, oy, ox, 1); 78267571Sbostic } 78356302Selan } 784