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*67631Sbostic static char sccsid[] = "@(#)refresh.c 8.5 (Berkeley) 08/10/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}; 195*67631Sbostic __LDATA *nsp, *csp, *cp, *cep; 19656651Selan u_int force; 197*67631Sbostic int clsp, nlsp; /* Last space in lines. */ 198*67631Sbostic int lch, wx, y; 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 } 247*67631Sbostic 2482261Sarnold while (wx <= lch) { 24957956Selan if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 25055986Sbostic if (wx <= lch) { 25163944Sbostic while (wx <= lch && 252*67631Sbostic memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 253*67631Sbostic nsp++; 254*67631Sbostic if (!curwin) 255*67631Sbostic ++csp; 256*67631Sbostic ++wx; 257*67631Sbostic } 25855986Sbostic continue; 25955986Sbostic } 26055986Sbostic break; 26155986Sbostic } 26256238Selan domvcur(ly, lx, y, wx + win->begx); 26356378Selan 26455976Sbostic #ifdef DEBUG 26567571Sbostic __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n", 26656651Selan wx, ly, lx, y, wx + win->begx, force); 26755976Sbostic #endif 26855986Sbostic ly = y; 26956238Selan lx = wx + win->begx; 27067571Sbostic while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) 27156651Selan && wx <= lch) { 27255986Sbostic 27367571Sbostic if (ce != NULL && win->maxx + win->begx == 27459775Selan curscr->maxx && wx >= nlsp && nsp->ch == ' ') { 27559775Selan /* Check for clear to end-of-line. */ 27659775Selan cep = &curscr->lines[wy]->line[win->maxx - 1]; 27759775Selan while (cep->ch == ' ' && cep->attr == 0) 27859775Selan if (cep-- <= csp) 27959775Selan break; 28067571Sbostic clsp = cep - curscr->lines[wy]->line - 28159775Selan win->begx * __LDATASIZE; 28259775Selan #ifdef DEBUG 28360058Sbostic __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 28459775Selan #endif 28567571Sbostic if ((clsp - nlsp >= strlen(CE) 28659775Selan && clsp < win->maxx * __LDATASIZE) || 28759775Selan wy == win->maxy - 1) { 28859775Selan #ifdef DEBUG 28960058Sbostic __CTRACE("makech: using CE\n"); 29059775Selan #endif 29159775Selan tputs(CE, 0, __cputchar); 29259775Selan lx = wx + win->begx; 29359775Selan while (wx++ <= clsp) { 29459775Selan csp->ch = ' '; 29559775Selan csp->attr = 0; 29659775Selan csp++; 29759775Selan } 29859775Selan return (OK); 29959775Selan } 30059775Selan ce = NULL; 30159775Selan } 30259775Selan 303*67631Sbostic /* 304*67631Sbostic * Enter/exit standout mode as appropriate. 305*67631Sbostic * XXX 306*67631Sbostic * Should use UC if SO/SE not available. 307*67631Sbostic */ 308*67631Sbostic if (nsp->attr & __STANDOUT) { 309*67631Sbostic if (!(curscr->flags & __WSTANDOUT) && 310*67631Sbostic SO != NULL && SE != NULL) { 31155986Sbostic tputs(SO, 0, __cputchar); 31256238Selan curscr->flags |= __WSTANDOUT; 313*67631Sbostic } 314*67631Sbostic } else 315*67631Sbostic if (curscr->flags & __WSTANDOUT && 316*67631Sbostic SE != NULL) { 31755986Sbostic tputs(SE, 0, __cputchar); 31856238Selan curscr->flags &= ~__WSTANDOUT; 3192261Sarnold } 32055986Sbostic 32155986Sbostic wx++; 32256472Selan if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) 32356238Selan if (win->flags & __SCROLLOK) { 32456238Selan if (curscr->flags & __WSTANDOUT 32556238Selan && win->flags & __ENDLINE) 32655986Sbostic if (!MS) { 32755986Sbostic tputs(SE, 0, 32855986Sbostic __cputchar); 32956238Selan curscr->flags &= 33056238Selan ~__WSTANDOUT; 33155976Sbostic } 33259760Selan if (!(win->flags & __SCROLLWIN)) { 33359760Selan if (!curwin) { 33459760Selan csp->attr = nsp->attr; 33559760Selan putchar(csp->ch = nsp->ch); 33659760Selan } else 33759760Selan putchar(nsp->ch); 33859760Selan } 33956599Selan if (wx + win->begx < curscr->maxx) { 34067571Sbostic domvcur(ly, wx + win->begx, 34156599Selan win->begy + win->maxy - 1, 34256599Selan win->begx + win->maxx - 1); 34356599Selan } 34456378Selan ly = win->begy + win->maxy - 1; 34556378Selan lx = win->begx + win->maxx - 1; 34657472Sbostic return (OK); 34767571Sbostic } 34867571Sbostic if (wx < win->maxx || wy < win->maxy - 1 || 34959760Selan !(win->flags & __SCROLLWIN)) { 35059760Selan if (!curwin) { 35159760Selan csp->attr = nsp->attr; 35259760Selan putchar(csp->ch = nsp->ch); 35359760Selan csp++; 35467571Sbostic } else 35559760Selan putchar(nsp->ch); 35659760Selan } 35755976Sbostic #ifdef DEBUG 35860058Sbostic __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); 35955976Sbostic #endif 36056648Selan if (UC && (nsp->attr & __STANDOUT)) { 36155986Sbostic putchar('\b'); 36255986Sbostic tputs(UC, 0, __cputchar); 3632261Sarnold } 36455986Sbostic nsp++; 36555976Sbostic #ifdef DEBUG 36660058Sbostic __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 36755976Sbostic #endif 36859760Selan } 36956238Selan if (lx == wx + win->begx) /* If no change. */ 37055986Sbostic break; 37156238Selan lx = wx + win->begx; 37259774Selan if (lx >= COLS && AM) 37358040Selan lx = COLS - 1; 37459774Selan else if (wx >= win->maxx) { 37556596Selan domvcur(ly, lx, ly, win->maxx + win->begx - 1); 37656596Selan lx = win->maxx + win->begx - 1; 37755986Sbostic } 37856596Selan 37955976Sbostic #ifdef DEBUG 38060058Sbostic __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 38155976Sbostic #endif 3822261Sarnold } 38357472Sbostic return (OK); 38411736Sarnold } 38511736Sarnold 38611736Sarnold /* 38755976Sbostic * domvcur -- 38855976Sbostic * Do a mvcur, leaving standout mode if necessary. 38911736Sarnold */ 39055976Sbostic static void 39111736Sarnold domvcur(oy, ox, ny, nx) 39255976Sbostic int oy, ox, ny, nx; 39355976Sbostic { 39456238Selan if (curscr->flags & __WSTANDOUT && !MS) { 39555976Sbostic tputs(SE, 0, __cputchar); 39656238Selan curscr->flags &= ~__WSTANDOUT; 3972261Sarnold } 39856596Selan 39959930Selan __mvcur(oy, ox, ny, nx, 1); 4002261Sarnold } 40156302Selan 40256302Selan /* 40356302Selan * Quickch() attempts to detect a pattern in the change of the window 40467571Sbostic * in order to optimize the change, e.g., scroll n lines as opposed to 40556302Selan * repainting the screen line by line. 40656302Selan */ 40756302Selan 40856302Selan static void 40956302Selan quickch(win) 41056302Selan WINDOW *win; 41156302Selan { 41258019Selan #define THRESH (int) win->maxy / 4 41356302Selan 41456648Selan register __LINE *clp, *tmp1, *tmp2; 41556378Selan register int bsize, curs, curw, starts, startw, i, j; 41656652Selan int n, target, cur_period, bot, top, sc_region; 41756648Selan __LDATA buf[1024]; 41856378Selan u_int blank_hash; 41956302Selan 42067571Sbostic /* 42158019Selan * Find how many lines from the top of the screen are unchanged. 42258019Selan */ 42367571Sbostic for (top = 0; top < win->maxy; top++) 42458019Selan if (win->lines[top]->flags & __FORCEPAINT || 42567571Sbostic win->lines[top]->hash != curscr->lines[top]->hash 42667571Sbostic || memcmp(win->lines[top]->line, 42767571Sbostic curscr->lines[top]->line, 42858019Selan win->maxx * __LDATASIZE) != 0) 42958019Selan break; 43058034Selan else 43158034Selan win->lines[top]->flags &= ~__ISDIRTY; 43258019Selan /* 43367571Sbostic * Find how many lines from bottom of screen are unchanged. 43458019Selan */ 43558019Selan for (bot = win->maxy - 1; bot >= 0; bot--) 43658019Selan if (win->lines[bot]->flags & __FORCEPAINT || 43767571Sbostic win->lines[bot]->hash != curscr->lines[bot]->hash 43867571Sbostic || memcmp(win->lines[bot]->line, 43967571Sbostic curscr->lines[bot]->line, 44058019Selan win->maxx * __LDATASIZE) != 0) 44158019Selan break; 44258034Selan else 44358034Selan win->lines[bot]->flags &= ~__ISDIRTY; 44458019Selan 44559352Selan #ifdef NO_JERKINESS 44656552Selan /* 44759062Selan * If we have a bottom unchanged region return. Scrolling the 44859062Selan * bottom region up and then back down causes a screen jitter. 44959062Selan * This will increase the number of characters sent to the screen 45059062Selan * but it looks better. 45159062Selan */ 45259062Selan if (bot < win->maxy - 1) 45359062Selan return; 45459352Selan #endif /* NO_JERKINESS */ 45559062Selan 45659062Selan /* 45756552Selan * Search for the largest block of text not changed. 45856652Selan * Invariants of the loop: 45956652Selan * - Startw is the index of the beginning of the examined block in win. 46067571Sbostic * - Starts is the index of the beginning of the examined block in 46156652Selan * curscr. 46256652Selan * - Curs is the index of one past the end of the exmined block in win. 46367571Sbostic * - Curw is the index of one past the end of the exmined block in 46456652Selan * curscr. 46556652Selan * - bsize is the current size of the examined block. 46656552Selan */ 46758019Selan for (bsize = bot - top; bsize >= THRESH; bsize--) { 46858019Selan for (startw = top; startw <= bot - bsize; startw++) 46967571Sbostic for (starts = top; starts <= bot - bsize; 47056302Selan starts++) { 47156302Selan for (curw = startw, curs = starts; 47256302Selan curs < starts + bsize; curw++, curs++) 47356651Selan if (win->lines[curw]->flags & 47456651Selan __FORCEPAINT || 47556651Selan (win->lines[curw]->hash != 47656552Selan curscr->lines[curs]->hash || 47767571Sbostic memcmp(win->lines[curw]->line, 47867571Sbostic curscr->lines[curs]->line, 47956651Selan win->maxx * __LDATASIZE) != 0)) 48056302Selan break; 48156302Selan if (curs == starts + bsize) 48256302Selan goto done; 48356302Selan } 48458019Selan } 48556302Selan done: 48656651Selan /* Did not find anything */ 48767571Sbostic if (bsize < THRESH) 48856302Selan return; 48956302Selan 49056302Selan #ifdef DEBUG 49167571Sbostic __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 49256559Selan bsize, starts, startw, curw, curs, top, bot); 49356302Selan #endif 49456378Selan 49567571Sbostic /* 49667571Sbostic * Make sure that there is no overlap between the bottom and top 49756559Selan * regions and the middle scrolled block. 49856559Selan */ 49956691Selan if (bot < curs) 50056691Selan bot = curs - 1; 50156691Selan if (top > starts) 50256691Selan top = starts; 50356559Selan 50456378Selan n = startw - starts; 50556378Selan 50656691Selan #ifdef DEBUG 50760058Sbostic __CTRACE("#####################################\n"); 50856691Selan for (i = 0; i < curscr->maxy; i++) { 50960058Sbostic __CTRACE("C: %d:", i); 51060058Sbostic __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 51167571Sbostic for (j = 0; j < curscr->maxx; j++) 51267571Sbostic __CTRACE("%c", 51356691Selan curscr->lines[i]->line[j].ch); 51460058Sbostic __CTRACE("\n"); 51567571Sbostic for (j = 0; j < curscr->maxx; j++) 51667571Sbostic __CTRACE("%x", 51757356Selan curscr->lines[i]->line[j].attr); 51860058Sbostic __CTRACE("\n"); 51960058Sbostic __CTRACE("W: %d:", i); 52060058Sbostic __CTRACE(" 0x%x \n", win->lines[i]->hash); 52160058Sbostic __CTRACE(" 0x%x ", win->lines[i]->flags); 52267571Sbostic for (j = 0; j < win->maxx; j++) 52367571Sbostic __CTRACE("%c", 52456691Selan win->lines[i]->line[j].ch); 52560058Sbostic __CTRACE("\n"); 52667571Sbostic for (j = 0; j < win->maxx; j++) 52767571Sbostic __CTRACE("%x", 52857356Selan win->lines[i]->line[j].attr); 52960058Sbostic __CTRACE("\n"); 53056691Selan } 53167571Sbostic #endif 53267571Sbostic 53356378Selan /* So we don't have to call __hash() each time */ 53456648Selan for (i = 0; i < win->maxx; i++) { 53556648Selan buf[i].ch = ' '; 53656648Selan buf[i].attr = 0; 53756648Selan } 53858192Selan blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE); 53956378Selan 54056378Selan /* 54156378Selan * Perform the rotation to maintain the consistency of curscr. 54256691Selan * This is hairy since we are doing an *in place* rotation. 54356652Selan * Invariants of the loop: 54456652Selan * - I is the index of the current line. 54556652Selan * - Target is the index of the target of line i. 54656652Selan * - Tmp1 points to current line (i). 54756652Selan * - Tmp2 and points to target line (target); 54867571Sbostic * - Cur_period is the index of the end of the current period. 54956652Selan * (see below). 55056652Selan * 55156652Selan * There are 2 major issues here that make this rotation non-trivial: 55256652Selan * 1. Scrolling in a scrolling region bounded by the top 55356652Selan * and bottom regions determined (whose size is sc_region). 55467571Sbostic * 2. As a result of the use of the mod function, there may be a 55556652Selan * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 55656652Selan * 0 to 2, which then causes all odd lines not to be rotated. 55767571Sbostic * To remedy this, an index of the end ( = beginning) of the 55867571Sbostic * current 'period' is kept, cur_period, and when it is reached, 55967571Sbostic * the next period is started from cur_period + 1 which is 56056652Selan * guaranteed not to have been reached since that would mean that 56156652Selan * all records would have been reached. (think about it...). 56267571Sbostic * 56356652Selan * Lines in the rotation can have 3 attributes which are marked on the 56456652Selan * line so that curscr is consistent with the visual screen. 56556705Selan * 1. Not dirty -- lines inside the scrolled block, top region or 56656652Selan * bottom region. 56767571Sbostic * 2. Blank lines -- lines in the differential of the scrolling 56867571Sbostic * region adjacent to top and bot regions 56956705Selan * depending on scrolling direction. 57056652Selan * 3. Dirty line -- all other lines are marked dirty. 57156378Selan */ 57256648Selan sc_region = bot - top + 1; 57356648Selan i = top; 57456648Selan tmp1 = curscr->lines[top]; 57556652Selan cur_period = top; 57656648Selan for (j = top; j <= bot; j++) { 57756648Selan target = (i - top + n + sc_region) % sc_region + top; 57856378Selan tmp2 = curscr->lines[target]; 57956378Selan curscr->lines[target] = tmp1; 58056378Selan /* Mark block as clean and blank out scrolled lines. */ 58156378Selan clp = curscr->lines[target]; 58256472Selan #ifdef DEBUG 58360058Sbostic __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 58456378Selan n, startw, curw, i, target); 58556472Selan #endif 58667571Sbostic if ((target >= startw && target < curw) || target < top 58756691Selan || target > bot) { 58856472Selan #ifdef DEBUG 58960058Sbostic __CTRACE("-- notdirty"); 59056472Selan #endif 59156378Selan win->lines[target]->flags &= ~__ISDIRTY; 59256705Selan } else if ((n > 0 && target >= top && target < top + n) || 59356705Selan (n < 0 && target <= bot && target > bot + n)) { 59467571Sbostic if (clp->hash != blank_hash || memcmp(clp->line, 59556648Selan buf, win->maxx * __LDATASIZE) !=0) { 59658041Selan (void)memcpy(clp->line, buf, 59756648Selan win->maxx * __LDATASIZE); 59856472Selan #ifdef DEBUG 59960058Sbostic __CTRACE("-- blanked out: dirty"); 60056472Selan #endif 60156378Selan clp->hash = blank_hash; 60256652Selan __touchline(win, target, 0, win->maxx - 1, 0); 60356705Selan } else { 60456652Selan __touchline(win, target, 0, win->maxx - 1, 0); 60556472Selan #ifdef DEBUG 60660058Sbostic __CTRACE(" -- blank line already: dirty"); 60756472Selan #endif 60856705Selan } 60956378Selan } else { 61056472Selan #ifdef DEBUG 61160058Sbostic __CTRACE(" -- dirty"); 61256472Selan #endif 61356651Selan __touchline(win, target, 0, win->maxx - 1, 0); 61456378Selan } 61556472Selan #ifdef DEBUG 61660058Sbostic __CTRACE("\n"); 61756472Selan #endif 61856652Selan if (target == cur_period) { 61956378Selan i = target + 1; 62056378Selan tmp1 = curscr->lines[i]; 62156652Selan cur_period = i; 62256378Selan } else { 62356378Selan tmp1 = tmp2; 62456378Selan i = target; 62556378Selan } 62656302Selan } 62756472Selan #ifdef DEBUG 62860058Sbostic __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 62956648Selan for (i = 0; i < curscr->maxy; i++) { 63060058Sbostic __CTRACE("C: %d:", i); 63167571Sbostic for (j = 0; j < curscr->maxx; j++) 63267571Sbostic __CTRACE("%c", 63356648Selan curscr->lines[i]->line[j].ch); 63460058Sbostic __CTRACE("\n"); 63560058Sbostic __CTRACE("W: %d:", i); 63667571Sbostic for (j = 0; j < win->maxx; j++) 63767571Sbostic __CTRACE("%c", win->lines[i]->line[j].ch); 63860058Sbostic __CTRACE("\n"); 63956648Selan } 64056472Selan #endif 64160100Selan if (n != 0) { 64260100Selan WINDOW *wp; 64359930Selan scrolln(win, starts, startw, curs, bot, top); 64460100Selan /* 64560100Selan * Need to repoint any subwindow lines to the rotated 64667571Sbostic * line structured. 64760100Selan */ 64860100Selan for (wp = win->nextp; wp != win; wp = wp->nextp) 64960100Selan __set_subwin(win, wp); 65060100Selan } 65156302Selan } 65256302Selan 65356652Selan /* 65467571Sbostic * scrolln -- 65567571Sbostic * Scroll n lines, where n is starts - startw. 65656652Selan */ 65756302Selan static void 65856705Selan scrolln(win, starts, startw, curs, bot, top) 65956302Selan WINDOW *win; 66056705Selan int starts, startw, curs, bot, top; 66156302Selan { 66256302Selan int i, oy, ox, n; 66356302Selan 66456302Selan oy = curscr->cury; 66556302Selan ox = curscr->curx; 66656302Selan n = starts - startw; 66756302Selan 66867583Sbostic /* 66967583Sbostic * XXX 67067583Sbostic * The initial tests that set __noqch don't let us reach here unless 67167583Sbostic * we have either CS + HO + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr 67267583Sbostic * scrolling can only shift the entire scrolling region, not just a 67367583Sbostic * part of it, which means that the quickch() routine is going to be 67467583Sbostic * sadly disappointed in us if we don't have CS as well. 67567583Sbostic * 67667583Sbostic * If CS, HO and SF/sf are set, can use the scrolling region. Because 67767583Sbostic * the cursor position after CS is undefined, we need HO which gives us 67867583Sbostic * the ability to move to somewhere without knowledge of the current 67967583Sbostic * location of the cursor. Still call __mvcur() anyway, to update its 68067583Sbostic * idea of where the cursor is. 68167583Sbostic * 68267583Sbostic * When the scrolling region has been set, the cursor has to be at the 68367583Sbostic * last line of the region to make the scroll happen. 68467583Sbostic * 68567583Sbostic * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr 68667583Sbostic * or al/dl, and, some terminals have AL/DL, sf/sr, and CS, but not 68767583Sbostic * SF/SR. So, if we're scrolling almost all of the screen, try and use 68867583Sbostic * AL/DL, otherwise use the scrolling region. The "almost all" is a 68967583Sbostic * shameless hack for vi. 69067583Sbostic */ 69156302Selan if (n > 0) { 69267583Sbostic if (CS != NULL && HO != NULL && (SF != NULL || 69367583Sbostic (AL == NULL || DL == NULL || 69467583Sbostic top > 3 || bot + 3 < win->maxy) && sf != NULL)) { 69567571Sbostic tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 69667571Sbostic __mvcur(oy, ox, 0, 0, 1); 69767571Sbostic tputs(HO, 0, __cputchar); 69867571Sbostic __mvcur(0, 0, bot, 0, 1); 69967571Sbostic if (SF != NULL) 70067571Sbostic tputs(__tscroll(SF, n, 0), 0, __cputchar); 70167571Sbostic else 70267571Sbostic for (i = 0; i < n; i++) 70367571Sbostic tputs(sf, 0, __cputchar); 70467571Sbostic tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 70567571Sbostic __mvcur(bot, 0, 0, 0, 1); 70667571Sbostic tputs(HO, 0, __cputchar); 70767571Sbostic __mvcur(0, 0, oy, ox, 1); 70867571Sbostic return; 70967571Sbostic } 71067571Sbostic 71167583Sbostic /* Scroll up the block. */ 71259930Selan __mvcur(oy, ox, top, 0, 1); 71367583Sbostic if (SF != NULL && top == 0) 71467583Sbostic tputs(__tscroll(SF, n, 0), 0, __cputchar); 71567583Sbostic else if (DL != NULL) 71667571Sbostic tputs(__tscroll(DL, n, 0), 0, __cputchar); 71767583Sbostic else if (dl != NULL) 71867571Sbostic for (i = 0; i < n; i++) 71956302Selan tputs(dl, 0, __cputchar); 72067583Sbostic else if (sf != NULL && top == 0) 72167583Sbostic for (i = 0; i < n; i++) 72267583Sbostic tputs(sf, 0, __cputchar); 72367583Sbostic else 72467583Sbostic abort(); 72556652Selan 72667571Sbostic /* Push down the bottom region. */ 72759930Selan __mvcur(top, 0, bot - n + 1, 0, 1); 72867583Sbostic if (AL != NULL) 72967571Sbostic tputs(__tscroll(AL, n, 0), 0, __cputchar); 73067583Sbostic else if (al != NULL) 73167571Sbostic for (i = 0; i < n; i++) 73256652Selan tputs(al, 0, __cputchar); 73367583Sbostic else 73467583Sbostic abort(); 73559930Selan __mvcur(bot - n + 1, 0, oy, ox, 1); 73656302Selan } else { 73767571Sbostic /* 73867583Sbostic * !!! 73967583Sbostic * n < 0 74067583Sbostic * 74167583Sbostic * If CS, HO and SR/sr are set, can use the scrolling region. 74267583Sbostic * See the above comments for details. 74367571Sbostic */ 74467583Sbostic if (CS != NULL && HO != NULL && (SR != NULL || 74567583Sbostic (AL == NULL || DL == NULL || 74667583Sbostic top > 3 || bot + 3 < win->maxy) && sr != NULL)) { 74767571Sbostic tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 74867571Sbostic __mvcur(oy, ox, 0, 0, 1); 74967571Sbostic tputs(HO, 0, __cputchar); 75067571Sbostic __mvcur(0, 0, top, 0, 1); 75167571Sbostic 75267571Sbostic if (SR != NULL) 75367583Sbostic tputs(__tscroll(SR, -n, 0), 0, __cputchar); 75467571Sbostic else 75567583Sbostic for (i = n; i < 0; i++) 75667571Sbostic tputs(sr, 0, __cputchar); 75767571Sbostic tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 75867571Sbostic __mvcur(top, 0, 0, 0, 1); 75967571Sbostic tputs(HO, 0, __cputchar); 76067571Sbostic __mvcur(0, 0, oy, ox, 1); 76167571Sbostic return; 76267571Sbostic } 76367571Sbostic 76467583Sbostic /* Preserve the bottom lines. */ 76567583Sbostic __mvcur(oy, ox, bot + n + 1, 0, 1); 76667583Sbostic if (SR != NULL && bot == win->maxy) 76767583Sbostic tputs(__tscroll(SR, -n, 0), 0, __cputchar); 76867583Sbostic else if (DL != NULL) 76967571Sbostic tputs(__tscroll(DL, -n, 0), 0, __cputchar); 77067583Sbostic else if (dl != NULL) 77167571Sbostic for (i = n; i < 0; i++) 77256652Selan tputs(dl, 0, __cputchar); 77367583Sbostic else if (sr != NULL && bot == win->maxy) 77467583Sbostic for (i = n; i < 0; i++) 77567583Sbostic tputs(sr, 0, __cputchar); 77667583Sbostic else 77767583Sbostic abort(); 77856302Selan 77967571Sbostic /* Scroll the block down. */ 78067583Sbostic __mvcur(bot + n + 1, 0, top, 0, 1); 78167583Sbostic if (AL != NULL) 78267571Sbostic tputs(__tscroll(AL, -n, 0), 0, __cputchar); 78367583Sbostic else if (al != NULL) 78467571Sbostic for (i = n; i < 0; i++) 78556302Selan tputs(al, 0, __cputchar); 78667583Sbostic else 78767583Sbostic abort(); 78859930Selan __mvcur(top, 0, oy, ox, 1); 78967571Sbostic } 79056302Selan } 791