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*67571Sbostic static char sccsid[] = "@(#)refresh.c 8.3 (Berkeley) 07/27/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)); 21*67571Sbostic 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; 37*67571Sbostic 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) 48*67571Sbostic 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); 98*67571Sbostic for (j = 0; j < curscr->maxx; j++) 99*67571Sbostic __CTRACE("%c", 10059930Selan curscr->lines[i]->line[j].ch); 10160058Sbostic __CTRACE("\n"); 102*67571Sbostic for (j = 0; j < curscr->maxx; j++) 103*67571Sbostic __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); 109*67571Sbostic for (j = 0; j < win->maxx; j++) 110*67571Sbostic __CTRACE("%c", 11159930Selan win->lines[i]->line[j].ch); 11260058Sbostic __CTRACE("\n"); 113*67571Sbostic for (j = 0; j < win->maxx; j++) 114*67571Sbostic __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; 138*67571Sbostic 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 149*67571Sbostic __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp, 15056715Selan *win->lines[wy]->lastchp); 15155976Sbostic #endif 1522261Sarnold } 153*67571Sbostic 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) { 228*67571Sbostic 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 264*67571Sbostic __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; 269*67571Sbostic while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) 27056651Selan && wx <= lch) { 27155986Sbostic 272*67571Sbostic 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; 279*67571Sbostic 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 284*67571Sbostic 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) { 333*67571Sbostic 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); 340*67571Sbostic } 341*67571Sbostic 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++; 347*67571Sbostic } 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 397*67571Sbostic * 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 413*67571Sbostic /* 41458019Selan * Find how many lines from the top of the screen are unchanged. 41558019Selan */ 416*67571Sbostic for (top = 0; top < win->maxy; top++) 41758019Selan if (win->lines[top]->flags & __FORCEPAINT || 418*67571Sbostic win->lines[top]->hash != curscr->lines[top]->hash 419*67571Sbostic || memcmp(win->lines[top]->line, 420*67571Sbostic curscr->lines[top]->line, 42158019Selan win->maxx * __LDATASIZE) != 0) 42258019Selan break; 42358034Selan else 42458034Selan win->lines[top]->flags &= ~__ISDIRTY; 42558019Selan /* 426*67571Sbostic * 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 || 430*67571Sbostic win->lines[bot]->hash != curscr->lines[bot]->hash 431*67571Sbostic || memcmp(win->lines[bot]->line, 432*67571Sbostic 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. 453*67571Sbostic * - 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. 456*67571Sbostic * - 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++) 462*67571Sbostic 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 || 470*67571Sbostic memcmp(win->lines[curw]->line, 471*67571Sbostic 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 */ 480*67571Sbostic if (bsize < THRESH) 48156302Selan return; 48256302Selan 48356302Selan #ifdef DEBUG 484*67571Sbostic __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 488*67571Sbostic /* 489*67571Sbostic * 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); 504*67571Sbostic for (j = 0; j < curscr->maxx; j++) 505*67571Sbostic __CTRACE("%c", 50656691Selan curscr->lines[i]->line[j].ch); 50760058Sbostic __CTRACE("\n"); 508*67571Sbostic for (j = 0; j < curscr->maxx; j++) 509*67571Sbostic __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); 515*67571Sbostic for (j = 0; j < win->maxx; j++) 516*67571Sbostic __CTRACE("%c", 51756691Selan win->lines[i]->line[j].ch); 51860058Sbostic __CTRACE("\n"); 519*67571Sbostic for (j = 0; j < win->maxx; j++) 520*67571Sbostic __CTRACE("%x", 52157356Selan win->lines[i]->line[j].attr); 52260058Sbostic __CTRACE("\n"); 52356691Selan } 524*67571Sbostic #endif 525*67571Sbostic 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); 541*67571Sbostic * - 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). 547*67571Sbostic * 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. 550*67571Sbostic * To remedy this, an index of the end ( = beginning) of the 551*67571Sbostic * current 'period' is kept, cur_period, and when it is reached, 552*67571Sbostic * 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...). 555*67571Sbostic * 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. 560*67571Sbostic * 2. Blank lines -- lines in the differential of the scrolling 561*67571Sbostic * 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 579*67571Sbostic 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)) { 587*67571Sbostic 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); 624*67571Sbostic for (j = 0; j < curscr->maxx; j++) 625*67571Sbostic __CTRACE("%c", 62656648Selan curscr->lines[i]->line[j].ch); 62760058Sbostic __CTRACE("\n"); 62860058Sbostic __CTRACE("W: %d:", i); 629*67571Sbostic for (j = 0; j < win->maxx; j++) 630*67571Sbostic __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 639*67571Sbostic * line structured. 64060100Selan */ 64160100Selan for (wp = win->nextp; wp != win; wp = wp->nextp) 64260100Selan __set_subwin(win, wp); 64360100Selan } 64456302Selan } 64556302Selan 64656652Selan /* 647*67571Sbostic * scrolln -- 648*67571Sbostic * Scroll n lines, where n is starts - startw. 649*67571Sbostic * 650*67571Sbostic * XXX 651*67571Sbostic * The initial tests that set __noqch don't let us reach here unless we 652*67571Sbostic * have either CS + HO + SF/sf/SR/sr, or AL + DL. SF/sf/SR/sr scrolling 653*67571Sbostic * can only scroll the entire screen, not just a part of it, which means 654*67571Sbostic * that the quickch() routine is going to be sadly disappointed in us. 655*67571Sbostic * I've left the code here, as it would be useful to be able to scroll 656*67571Sbostic * part of the screen and repaint the rest, instead painting the entire 657*67571Sbostic * screen, on a terminal that didn't have CS or AL/DL. 65856652Selan */ 65956302Selan static void 66056705Selan scrolln(win, starts, startw, curs, bot, top) 66156302Selan WINDOW *win; 66256705Selan int starts, startw, curs, bot, top; 66356302Selan { 66456302Selan int i, oy, ox, n; 66556302Selan 66656302Selan oy = curscr->cury; 66756302Selan ox = curscr->curx; 66856302Selan n = starts - startw; 66956302Selan 67056302Selan if (n > 0) { 671*67571Sbostic /* If scrolling the entire screen, SF/sf is all we need. */ 672*67571Sbostic if (top == 0 && 673*67571Sbostic bot == win->maxy && (SF != NULL || sf != NULL)) { 674*67571Sbostic __mvcur(oy, ox, win->maxy, 0, 1); 675*67571Sbostic if (SF != NULL) 676*67571Sbostic tputs(__tscroll(SF, n, 0), 0, __cputchar); 677*67571Sbostic else 678*67571Sbostic for (i = 0; i < n; i++) 679*67571Sbostic tputs(sf, 0, __cputchar); 680*67571Sbostic __mvcur(win->maxy, 0, oy, ox, 1); 681*67571Sbostic return; 682*67571Sbostic } 683*67571Sbostic 684*67571Sbostic /* 685*67571Sbostic * If CS, HO and SF/sf are set, use the scrolling region. We 686*67571Sbostic * need HO because the cursor position after CS is undefined, 687*67571Sbostic * so we need the ability to move to a fixed place without any 688*67571Sbostic * knowledge of the current location. Note, we call __mvcur() 689*67571Sbostic * anyway, to update its idea of where the cursor is. 690*67571Sbostic * 691*67571Sbostic * When the scrolling region has been set, the cursor has to be 692*67571Sbostic * at the last line of that region to make the scroll happen. 693*67571Sbostic */ 694*67571Sbostic if (CS != NULL && HO != NULL && (SF != NULL || sf != NULL)) { 695*67571Sbostic tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 696*67571Sbostic __mvcur(oy, ox, 0, 0, 1); 697*67571Sbostic tputs(HO, 0, __cputchar); 698*67571Sbostic __mvcur(0, 0, bot, 0, 1); 699*67571Sbostic if (SF != NULL) 700*67571Sbostic tputs(__tscroll(SF, n, 0), 0, __cputchar); 701*67571Sbostic else 702*67571Sbostic for (i = 0; i < n; i++) 703*67571Sbostic tputs(sf, 0, __cputchar); 704*67571Sbostic tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 705*67571Sbostic __mvcur(bot, 0, 0, 0, 1); 706*67571Sbostic tputs(HO, 0, __cputchar); 707*67571Sbostic __mvcur(0, 0, oy, ox, 1); 708*67571Sbostic return; 709*67571Sbostic } 710*67571Sbostic 711*67571Sbostic /* 712*67571Sbostic * Otherwise, we depend on having AL/al and DL/dl. 713*67571Sbostic * 714*67571Sbostic * Scroll up the block. 715*67571Sbostic */ 71659930Selan __mvcur(oy, ox, top, 0, 1); 71756302Selan if (DL) 718*67571Sbostic tputs(__tscroll(DL, n, 0), 0, __cputchar); 71956302Selan else 720*67571Sbostic for (i = 0; i < n; i++) 72156302Selan tputs(dl, 0, __cputchar); 72256652Selan 723*67571Sbostic /* Push down the bottom region. */ 72459930Selan __mvcur(top, 0, bot - n + 1, 0, 1); 725*67571Sbostic if (AL) 726*67571Sbostic tputs(__tscroll(AL, n, 0), 0, __cputchar); 72756652Selan else 728*67571Sbostic for (i = 0; i < n; i++) 72956652Selan tputs(al, 0, __cputchar); 73059930Selan __mvcur(bot - n + 1, 0, oy, ox, 1); 73156302Selan } else { 732*67571Sbostic /* If scrolling the entire screen, SR/sr is all we need. */ 733*67571Sbostic if (top == 0 && 734*67571Sbostic bot == win->maxy && (SR != NULL || sr != NULL)) { 735*67571Sbostic __mvcur(oy, ox, 0, 0, 1); 736*67571Sbostic 737*67571Sbostic n = -n; 738*67571Sbostic if (SR != NULL) 739*67571Sbostic tputs(__tscroll(SR, n, 0), 0, __cputchar); 740*67571Sbostic else 741*67571Sbostic for (i = 0; i < n; i++) 742*67571Sbostic tputs(sr, 0, __cputchar); 743*67571Sbostic __mvcur(0, 0, oy, ox, 1); 744*67571Sbostic return; 745*67571Sbostic } 746*67571Sbostic 747*67571Sbostic /* 748*67571Sbostic * If CS, HO and SR/sr are set, use the scrolling region. See 749*67571Sbostic * the above comment for details. 750*67571Sbostic */ 751*67571Sbostic if (CS != NULL && HO != NULL && (SR != NULL || sr != NULL)) { 752*67571Sbostic tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 753*67571Sbostic __mvcur(oy, ox, 0, 0, 1); 754*67571Sbostic tputs(HO, 0, __cputchar); 755*67571Sbostic __mvcur(0, 0, top, 0, 1); 756*67571Sbostic 757*67571Sbostic n = -n; 758*67571Sbostic if (SR != NULL) 759*67571Sbostic tputs(__tscroll(SR, n, 0), 0, __cputchar); 760*67571Sbostic else 761*67571Sbostic for (i = 0; i < n; i++) 762*67571Sbostic tputs(sr, 0, __cputchar); 763*67571Sbostic tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 764*67571Sbostic __mvcur(top, 0, 0, 0, 1); 765*67571Sbostic tputs(HO, 0, __cputchar); 766*67571Sbostic __mvcur(0, 0, oy, ox, 1); 767*67571Sbostic return; 768*67571Sbostic } 769*67571Sbostic 770*67571Sbostic /* 771*67571Sbostic * Otherwise, we depend on having AL/al and DL/dl. 772*67571Sbostic * 773*67571Sbostic * Preserve the bottom lines. 774*67571Sbostic */ 77559930Selan __mvcur(oy, ox, bot + n + 1, 0, 1); /* n < 0 */ 77656652Selan if (DL) 777*67571Sbostic tputs(__tscroll(DL, -n, 0), 0, __cputchar); 77856652Selan else 779*67571Sbostic for (i = n; i < 0; i++) 78056652Selan tputs(dl, 0, __cputchar); 78159930Selan __mvcur(bot + n + 1, 0, top, 0, 1); 78256302Selan 783*67571Sbostic /* Scroll the block down. */ 784*67571Sbostic if (AL) 785*67571Sbostic tputs(__tscroll(AL, -n, 0), 0, __cputchar); 78656302Selan else 787*67571Sbostic for (i = n; i < 0; i++) 78856302Selan tputs(al, 0, __cputchar); 78959930Selan __mvcur(top, 0, oy, ox, 1); 790*67571Sbostic } 79156302Selan } 792