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*60100Selan static char sccsid[] = "@(#)refresh.c 5.44 (Berkeley) 05/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 static void domvcur __P((int, int, int, int)); 1955976Sbostic static int makech __P((WINDOW *, int)); 2056302Selan static void quickch __P((WINDOW *)); 2156559Selan static void scrolln __P((WINDOW *, int, int, int, int, int)); 2256648Selan 2355976Sbostic /* 2455976Sbostic * wrefresh -- 2555976Sbostic * Make the current screen look like "win" over the area coverd by 2655976Sbostic * win. 2755976Sbostic */ 2855976Sbostic int 292261Sarnold wrefresh(win) 3055976Sbostic register WINDOW *win; 312261Sarnold { 3256648Selan register __LINE *wlp; 3355976Sbostic register int retval; 3455976Sbostic register short wy; 3558019Selan int dnum; 3658019Selan 3755976Sbostic /* Initialize loop parameters. */ 3856238Selan ly = curscr->cury; 3956238Selan lx = curscr->curx; 402287Sarnold wy = 0; 412287Sarnold curwin = (win == curscr); 422287Sarnold 4356378Selan if (!curwin) 4456378Selan for (wy = 0; wy < win->maxy; wy++) { 4556378Selan wlp = win->lines[wy]; 4656378Selan if (wlp->flags & __ISDIRTY) 4756648Selan wlp->hash = 4858192Selan __hash((char *) wlp->line, win->maxx * __LDATASIZE); 4956378Selan } 5056378Selan 5156238Selan if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) { 5256238Selan if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) { 5355976Sbostic tputs(CL, 0, __cputchar); 5412358Sarnold ly = 0; 5512358Sarnold lx = 0; 5612358Sarnold if (!curwin) { 5756238Selan curscr->flags &= ~__CLEAROK; 5856238Selan curscr->cury = 0; 5956238Selan curscr->curx = 0; 602287Sarnold werase(curscr); 6112358Sarnold } 6256651Selan __touchwin(win); 632261Sarnold } 6456238Selan win->flags &= ~__CLEAROK; 652261Sarnold } 662261Sarnold if (!CA) { 6756238Selan if (win->curx != 0) 6855976Sbostic putchar('\n'); 692287Sarnold if (!curwin) 702287Sarnold werase(curscr); 712261Sarnold } 7255976Sbostic #ifdef DEBUG 7360058Sbostic __CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin); 7460058Sbostic __CTRACE("wrefresh: \tfirstch\tlastch\n"); 7555976Sbostic #endif 7656302Selan 7756302Selan #ifndef NOQCH 7858019Selan if ((win->flags & __FULLWIN) && !curwin) { 7958019Selan /* 8058019Selan * Invoke quickch() only if more than a quarter of the lines 8158019Selan * in the window are dirty. 8258019Selan */ 8358019Selan for (wy = 0, dnum = 0; wy < win->maxy; wy++) 8458019Selan if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) 8558019Selan dnum++; 8658019Selan if (!__noqch && dnum > (int) win->maxy / 4) 8758019Selan quickch(win); 8858019Selan } 8956302Selan #endif 9059930Selan 9159930Selan #ifdef DEBUG 9259930Selan { int i, j; 9360058Sbostic __CTRACE("#####################################\n"); 9459930Selan for (i = 0; i < curscr->maxy; i++) { 9560058Sbostic __CTRACE("C: %d:", i); 9660058Sbostic __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 9759930Selan for (j = 0; j < curscr->maxx; j++) 9860058Sbostic __CTRACE("%c", 9959930Selan curscr->lines[i]->line[j].ch); 10060058Sbostic __CTRACE("\n"); 10159930Selan for (j = 0; j < curscr->maxx; j++) 10260058Sbostic __CTRACE("%x", 10359930Selan curscr->lines[i]->line[j].attr); 10460058Sbostic __CTRACE("\n"); 10560058Sbostic __CTRACE("W: %d:", i); 10660058Sbostic __CTRACE(" 0x%x \n", win->lines[i]->hash); 10760058Sbostic __CTRACE(" 0x%x ", win->lines[i]->flags); 10859930Selan for (j = 0; j < win->maxx; j++) 10960058Sbostic __CTRACE("%c", 11059930Selan win->lines[i]->line[j].ch); 11160058Sbostic __CTRACE("\n"); 11259930Selan for (j = 0; j < win->maxx; j++) 11360058Sbostic __CTRACE("%x", 11459930Selan win->lines[i]->line[j].attr); 11560058Sbostic __CTRACE("\n"); 11659930Selan } 11759930Selan } 11859930Selan #endif /* DEBUG */ 11959930Selan 12056238Selan for (wy = 0; wy < win->maxy; wy++) { 12155976Sbostic #ifdef DEBUG 12260058Sbostic __CTRACE("%d\t%d\t%d\n", 12356715Selan wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp); 12455976Sbostic #endif 12556378Selan if (!curwin) 12656378Selan curscr->lines[wy]->hash = win->lines[wy]->hash; 12758369Selan if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) { 12857472Sbostic if (makech(win, wy) == ERR) 12957472Sbostic return (ERR); 13019893Sbloom else { 13156715Selan if (*win->lines[wy]->firstchp >= win->ch_off) 13256715Selan *win->lines[wy]->firstchp = win->maxx + 13356238Selan win->ch_off; 13456715Selan if (*win->lines[wy]->lastchp < win->maxx + 13556238Selan win->ch_off) 13656715Selan *win->lines[wy]->lastchp = win->ch_off; 13756715Selan if (*win->lines[wy]->lastchp < 13858034Selan *win->lines[wy]->firstchp) { 13958034Selan #ifdef DEBUG 14060058Sbostic __CTRACE("wrefresh: line %d notdirty \n", wy); 14158034Selan #endif 14256238Selan win->lines[wy]->flags &= ~__ISDIRTY; 14358034Selan } 14419893Sbloom } 14558369Selan 14659774Selan } 14755976Sbostic #ifdef DEBUG 14860058Sbostic __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp, 14956715Selan *win->lines[wy]->lastchp); 15055976Sbostic #endif 1512261Sarnold } 15256238Selan 15356302Selan #ifdef DEBUG 15460058Sbostic __CTRACE("refresh: ly=%d, lx=%d\n", ly, lx); 15556302Selan #endif 15656472Selan 15712358Sarnold if (win == curscr) 15856238Selan domvcur(ly, lx, win->cury, win->curx); 15919893Sbloom else { 16056238Selan if (win->flags & __LEAVEOK) { 16156238Selan curscr->cury = ly; 16256238Selan curscr->curx = lx; 16356238Selan ly -= win->begy; 16456238Selan lx -= win->begx; 16556238Selan if (ly >= 0 && ly < win->maxy && lx >= 0 && 16656238Selan lx < win->maxx) { 16756238Selan win->cury = ly; 16856238Selan win->curx = lx; 16955976Sbostic } else 17056238Selan win->cury = win->curx = 0; 17155976Sbostic } else { 17256238Selan domvcur(ly, lx, win->cury + win->begy, 17356238Selan win->curx + win->begx); 17456238Selan curscr->cury = win->cury + win->begy; 17556238Selan curscr->curx = win->curx + win->begx; 17619893Sbloom } 1772261Sarnold } 17857472Sbostic retval = OK; 17955986Sbostic 18055976Sbostic (void)fflush(stdout); 18155976Sbostic return (retval); 1822261Sarnold } 1832261Sarnold 1842261Sarnold /* 18555976Sbostic * makech -- 18655976Sbostic * Make a change on the screen. 1872261Sarnold */ 18855976Sbostic static int 1892261Sarnold makech(win, wy) 19055976Sbostic register WINDOW *win; 19155976Sbostic int wy; 1922261Sarnold { 19359775Selan register int nlsp, clsp; /* Last space in lines. */ 19459352Selan register int wx, lch, y; 19559775Selan register __LDATA *nsp, *csp, *cp, *cep; 19656651Selan u_int force; 19756648Selan char *ce; 19856648Selan __LDATA blank = {' ', 0}; 19956648Selan 20056472Selan /* Is the cursor still on the end of the last line? */ 20156472Selan if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) { 20256551Selan domvcur(ly, lx, ly + 1, 0); 20356551Selan ly++; 20456551Selan lx = 0; 20556551Selan } 20656715Selan wx = *win->lines[wy]->firstchp - win->ch_off; 20759352Selan if (wx < 0) 20859352Selan wx = 0; 20959352Selan else if (wx >= win->maxx) 21057472Sbostic return (OK); 21156715Selan lch = *win->lines[wy]->lastchp - win->ch_off; 21219893Sbloom if (lch < 0) 21357472Sbostic return (OK); 21459352Selan else if (lch >= (int) win->maxx) 21556238Selan lch = win->maxx - 1; 21656238Selan y = wy + win->begy; 21719893Sbloom 2182287Sarnold if (curwin) 21956648Selan csp = ␣ 2202287Sarnold else 22156238Selan csp = &curscr->lines[wy + win->begy]->line[wx + win->begx]; 22219893Sbloom 22356238Selan nsp = &win->lines[wy]->line[wx]; 22456651Selan force = win->lines[wy]->flags & __FORCEPAINT; 22556651Selan win->lines[wy]->flags &= ~__FORCEPAINT; 2262287Sarnold if (CE && !curwin) { 22756648Selan for (cp = &win->lines[wy]->line[win->maxx - 1]; 22856648Selan cp->ch == ' ' && cp->attr == 0; cp--) 22956648Selan if (cp <= win->lines[wy]->line) 2302261Sarnold break; 23156648Selan nlsp = cp - win->lines[wy]->line; 2322261Sarnold } 2332287Sarnold if (!curwin) 2342287Sarnold ce = CE; 2352287Sarnold else 2362287Sarnold ce = NULL; 23719893Sbloom 23856651Selan if (force) { 23956651Selan if (CM) 24056651Selan tputs(tgoto(CM, lx, ly), 0, __cputchar); 24156651Selan else { 24256651Selan tputs(HO, 0, __cputchar); 24359930Selan __mvcur(0, 0, ly, lx, 1); 24456651Selan } 24556651Selan } 2462261Sarnold while (wx <= lch) { 24757956Selan if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 24855986Sbostic if (wx <= lch) { 24957956Selan while (memcmp(nsp, csp, sizeof(__LDATA)) == 0 && 25056648Selan wx <= lch) { 25156596Selan nsp++; 25256648Selan if (!curwin) 25356648Selan csp++; 25456648Selan ++wx; 25556648Selan } 25655986Sbostic continue; 25755986Sbostic } 25855986Sbostic break; 25955986Sbostic } 26056238Selan domvcur(ly, lx, y, wx + win->begx); 26156378Selan 26255976Sbostic #ifdef DEBUG 26360058Sbostic __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n", 26456651Selan wx, ly, lx, y, wx + win->begx, force); 26555976Sbostic #endif 26655986Sbostic ly = y; 26756238Selan lx = wx + win->begx; 26857956Selan while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) 26956651Selan && wx <= lch) { 27055986Sbostic 27159775Selan if (ce != NULL && win->maxx + win->begx == 27259775Selan curscr->maxx && wx >= nlsp && nsp->ch == ' ') { 27359775Selan /* Check for clear to end-of-line. */ 27459775Selan cep = &curscr->lines[wy]->line[win->maxx - 1]; 27559775Selan while (cep->ch == ' ' && cep->attr == 0) 27659775Selan if (cep-- <= csp) 27759775Selan break; 27859775Selan clsp = cep - curscr->lines[wy]->line - 27959775Selan win->begx * __LDATASIZE; 28059775Selan #ifdef DEBUG 28160058Sbostic __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 28259775Selan #endif 28359775Selan if ((clsp - nlsp >= strlen(CE) 28459775Selan && clsp < win->maxx * __LDATASIZE) || 28559775Selan wy == win->maxy - 1) { 28659775Selan #ifdef DEBUG 28760058Sbostic __CTRACE("makech: using CE\n"); 28859775Selan #endif 28959775Selan tputs(CE, 0, __cputchar); 29059775Selan lx = wx + win->begx; 29159775Selan while (wx++ <= clsp) { 29259775Selan csp->ch = ' '; 29359775Selan csp->attr = 0; 29459775Selan csp++; 29559775Selan } 29659775Selan return (OK); 29759775Selan } 29859775Selan ce = NULL; 29959775Selan } 30059775Selan 30155986Sbostic /* Enter/exit standout mode as appropriate. */ 30256648Selan if (SO && (nsp->attr & __STANDOUT) != 30356378Selan (curscr->flags & __WSTANDOUT)) { 30456648Selan if (nsp->attr & __STANDOUT) { 30555986Sbostic tputs(SO, 0, __cputchar); 30656238Selan curscr->flags |= __WSTANDOUT; 30755986Sbostic } else { 30855986Sbostic tputs(SE, 0, __cputchar); 30956238Selan curscr->flags &= ~__WSTANDOUT; 3102261Sarnold } 31155986Sbostic } 31255986Sbostic 31355986Sbostic wx++; 31456472Selan if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) 31556238Selan if (win->flags & __SCROLLOK) { 31656238Selan if (curscr->flags & __WSTANDOUT 31756238Selan && win->flags & __ENDLINE) 31855986Sbostic if (!MS) { 31955986Sbostic tputs(SE, 0, 32055986Sbostic __cputchar); 32156238Selan curscr->flags &= 32256238Selan ~__WSTANDOUT; 32355976Sbostic } 32459760Selan if (!(win->flags & __SCROLLWIN)) { 32559760Selan if (!curwin) { 32659760Selan csp->attr = nsp->attr; 32759760Selan putchar(csp->ch = nsp->ch); 32859760Selan } else 32959760Selan putchar(nsp->ch); 33059760Selan } 33156599Selan if (wx + win->begx < curscr->maxx) { 33256599Selan domvcur(ly, wx + win->begx, 33356599Selan win->begy + win->maxy - 1, 33456599Selan win->begx + win->maxx - 1); 33556599Selan } 33656378Selan ly = win->begy + win->maxy - 1; 33756378Selan lx = win->begx + win->maxx - 1; 33857472Sbostic return (OK); 33959760Selan } 34059760Selan if (wx < win->maxx || wy < win->maxy - 1 || 34159760Selan !(win->flags & __SCROLLWIN)) { 34259760Selan if (!curwin) { 34359760Selan csp->attr = nsp->attr; 34459760Selan putchar(csp->ch = nsp->ch); 34559760Selan csp++; 34659760Selan } else 34759760Selan putchar(nsp->ch); 34859760Selan } 34955976Sbostic #ifdef DEBUG 35060058Sbostic __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); 35155976Sbostic #endif 35256648Selan if (UC && (nsp->attr & __STANDOUT)) { 35355986Sbostic putchar('\b'); 35455986Sbostic tputs(UC, 0, __cputchar); 3552261Sarnold } 35655986Sbostic nsp++; 35755976Sbostic #ifdef DEBUG 35860058Sbostic __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 35955976Sbostic #endif 36059760Selan } 36156238Selan if (lx == wx + win->begx) /* If no change. */ 36255986Sbostic break; 36356238Selan lx = wx + win->begx; 36459774Selan if (lx >= COLS && AM) 36558040Selan lx = COLS - 1; 36659774Selan else if (wx >= win->maxx) { 36756596Selan domvcur(ly, lx, ly, win->maxx + win->begx - 1); 36856596Selan lx = win->maxx + win->begx - 1; 36955986Sbostic } 37056596Selan 37155976Sbostic #ifdef DEBUG 37260058Sbostic __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 37355976Sbostic #endif 3742261Sarnold } 37557472Sbostic return (OK); 37611736Sarnold } 37711736Sarnold 37811736Sarnold /* 37955976Sbostic * domvcur -- 38055976Sbostic * Do a mvcur, leaving standout mode if necessary. 38111736Sarnold */ 38255976Sbostic static void 38311736Sarnold domvcur(oy, ox, ny, nx) 38455976Sbostic int oy, ox, ny, nx; 38555976Sbostic { 38656238Selan if (curscr->flags & __WSTANDOUT && !MS) { 38755976Sbostic tputs(SE, 0, __cputchar); 38856238Selan curscr->flags &= ~__WSTANDOUT; 3892261Sarnold } 39056596Selan 39159930Selan __mvcur(oy, ox, ny, nx, 1); 3922261Sarnold } 39356302Selan 39456302Selan /* 39556302Selan * Quickch() attempts to detect a pattern in the change of the window 39656552Selan * in order to optimize the change, e.g., scroll n lines as opposed to 39756302Selan * repainting the screen line by line. 39856302Selan */ 39956302Selan 40056302Selan static void 40156302Selan quickch(win) 40256302Selan WINDOW *win; 40356302Selan { 40458019Selan #define THRESH (int) win->maxy / 4 40556302Selan 40656648Selan register __LINE *clp, *tmp1, *tmp2; 40756378Selan register int bsize, curs, curw, starts, startw, i, j; 40856652Selan int n, target, cur_period, bot, top, sc_region; 40956648Selan __LDATA buf[1024]; 41056378Selan u_int blank_hash; 41156302Selan 41258019Selan /* 41358019Selan * Find how many lines from the top of the screen are unchanged. 41458019Selan */ 41558034Selan for (top = 0; top < win->maxy; top++) 41658019Selan if (win->lines[top]->flags & __FORCEPAINT || 41758019Selan win->lines[top]->hash != curscr->lines[top]->hash 41858019Selan || memcmp(win->lines[top]->line, 41958019Selan curscr->lines[top]->line, 42058019Selan win->maxx * __LDATASIZE) != 0) 42158019Selan break; 42258034Selan else 42358034Selan win->lines[top]->flags &= ~__ISDIRTY; 42458019Selan /* 42558019Selan * Find how many lines from bottom of screen are unchanged. 42658019Selan */ 42758019Selan for (bot = win->maxy - 1; bot >= 0; bot--) 42858019Selan if (win->lines[bot]->flags & __FORCEPAINT || 42958019Selan win->lines[bot]->hash != curscr->lines[bot]->hash 43058019Selan || memcmp(win->lines[bot]->line, 43158019Selan curscr->lines[bot]->line, 43258019Selan win->maxx * __LDATASIZE) != 0) 43358019Selan break; 43458034Selan else 43558034Selan win->lines[bot]->flags &= ~__ISDIRTY; 43658019Selan 43759352Selan #ifdef NO_JERKINESS 43856552Selan /* 43959062Selan * If we have a bottom unchanged region return. Scrolling the 44059062Selan * bottom region up and then back down causes a screen jitter. 44159062Selan * This will increase the number of characters sent to the screen 44259062Selan * but it looks better. 44359062Selan */ 44459062Selan if (bot < win->maxy - 1) 44559062Selan return; 44659352Selan #endif /* NO_JERKINESS */ 44759062Selan 44859062Selan /* 44956552Selan * Search for the largest block of text not changed. 45056652Selan * Invariants of the loop: 45156652Selan * - Startw is the index of the beginning of the examined block in win. 45256652Selan * - Starts is the index of the beginning of the examined block in 45356652Selan * curscr. 45456652Selan * - Curs is the index of one past the end of the exmined block in win. 45556652Selan * - Curw is the index of one past the end of the exmined block in 45656652Selan * curscr. 45756652Selan * - bsize is the current size of the examined block. 45856552Selan */ 45958019Selan for (bsize = bot - top; bsize >= THRESH; bsize--) { 46058019Selan for (startw = top; startw <= bot - bsize; startw++) 46158019Selan for (starts = top; starts <= bot - bsize; 46256302Selan starts++) { 46356302Selan for (curw = startw, curs = starts; 46456302Selan curs < starts + bsize; curw++, curs++) 46556651Selan if (win->lines[curw]->flags & 46656651Selan __FORCEPAINT || 46756651Selan (win->lines[curw]->hash != 46856552Selan curscr->lines[curs]->hash || 46957956Selan memcmp(win->lines[curw]->line, 47056648Selan curscr->lines[curs]->line, 47156651Selan win->maxx * __LDATASIZE) != 0)) 47256302Selan break; 47356302Selan if (curs == starts + bsize) 47456302Selan goto done; 47556302Selan } 47658019Selan } 47756302Selan done: 47856651Selan /* Did not find anything */ 47956651Selan if (bsize < THRESH) 48056302Selan return; 48156302Selan 48256302Selan #ifdef DEBUG 48360058Sbostic __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 48456559Selan bsize, starts, startw, curw, curs, top, bot); 48556302Selan #endif 48656378Selan 48756559Selan /* 48856559Selan * Make sure that there is no overlap between the bottom and top 48956559Selan * regions and the middle scrolled block. 49056559Selan */ 49156691Selan if (bot < curs) 49256691Selan bot = curs - 1; 49356691Selan if (top > starts) 49456691Selan top = starts; 49556559Selan 49656378Selan n = startw - starts; 49756378Selan 49856691Selan #ifdef DEBUG 49960058Sbostic __CTRACE("#####################################\n"); 50056691Selan for (i = 0; i < curscr->maxy; i++) { 50160058Sbostic __CTRACE("C: %d:", i); 50260058Sbostic __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 50356691Selan for (j = 0; j < curscr->maxx; j++) 50460058Sbostic __CTRACE("%c", 50556691Selan curscr->lines[i]->line[j].ch); 50660058Sbostic __CTRACE("\n"); 50757356Selan for (j = 0; j < curscr->maxx; j++) 50860058Sbostic __CTRACE("%x", 50957356Selan curscr->lines[i]->line[j].attr); 51060058Sbostic __CTRACE("\n"); 51160058Sbostic __CTRACE("W: %d:", i); 51260058Sbostic __CTRACE(" 0x%x \n", win->lines[i]->hash); 51360058Sbostic __CTRACE(" 0x%x ", win->lines[i]->flags); 51456691Selan for (j = 0; j < win->maxx; j++) 51560058Sbostic __CTRACE("%c", 51656691Selan win->lines[i]->line[j].ch); 51760058Sbostic __CTRACE("\n"); 51857356Selan for (j = 0; j < win->maxx; j++) 51960058Sbostic __CTRACE("%x", 52057356Selan win->lines[i]->line[j].attr); 52160058Sbostic __CTRACE("\n"); 52256691Selan } 52356691Selan #endif 52458019Selan 52556378Selan /* So we don't have to call __hash() each time */ 52656648Selan for (i = 0; i < win->maxx; i++) { 52756648Selan buf[i].ch = ' '; 52856648Selan buf[i].attr = 0; 52956648Selan } 53058192Selan blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE); 53156378Selan 53256378Selan /* 53356378Selan * Perform the rotation to maintain the consistency of curscr. 53456691Selan * This is hairy since we are doing an *in place* rotation. 53556652Selan * Invariants of the loop: 53656652Selan * - I is the index of the current line. 53756652Selan * - Target is the index of the target of line i. 53856652Selan * - Tmp1 points to current line (i). 53956652Selan * - Tmp2 and points to target line (target); 54056652Selan * - Cur_period is the index of the end of the current period. 54156652Selan * (see below). 54256652Selan * 54356652Selan * There are 2 major issues here that make this rotation non-trivial: 54456652Selan * 1. Scrolling in a scrolling region bounded by the top 54556652Selan * and bottom regions determined (whose size is sc_region). 54656652Selan * 2. As a result of the use of the mod function, there may be a 54756652Selan * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 54856652Selan * 0 to 2, which then causes all odd lines not to be rotated. 54956652Selan * To remedy this, an index of the end ( = beginning) of the 55056652Selan * current 'period' is kept, cur_period, and when it is reached, 55156652Selan * the next period is started from cur_period + 1 which is 55256652Selan * guaranteed not to have been reached since that would mean that 55356652Selan * all records would have been reached. (think about it...). 55456652Selan * 55556652Selan * Lines in the rotation can have 3 attributes which are marked on the 55656652Selan * line so that curscr is consistent with the visual screen. 55756705Selan * 1. Not dirty -- lines inside the scrolled block, top region or 55856652Selan * bottom region. 55956705Selan * 2. Blank lines -- lines in the differential of the scrolling 56056705Selan * region adjacent to top and bot regions 56156705Selan * depending on scrolling direction. 56256652Selan * 3. Dirty line -- all other lines are marked dirty. 56356378Selan */ 56456648Selan sc_region = bot - top + 1; 56556648Selan i = top; 56656648Selan tmp1 = curscr->lines[top]; 56756652Selan cur_period = top; 56856648Selan for (j = top; j <= bot; j++) { 56956648Selan target = (i - top + n + sc_region) % sc_region + top; 57056378Selan tmp2 = curscr->lines[target]; 57156378Selan curscr->lines[target] = tmp1; 57256378Selan /* Mark block as clean and blank out scrolled lines. */ 57356378Selan clp = curscr->lines[target]; 57456472Selan #ifdef DEBUG 57560058Sbostic __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 57656378Selan n, startw, curw, i, target); 57756472Selan #endif 57856691Selan if ((target >= startw && target < curw) || target < top 57956691Selan || target > bot) { 58056472Selan #ifdef DEBUG 58160058Sbostic __CTRACE("-- notdirty"); 58256472Selan #endif 58356378Selan win->lines[target]->flags &= ~__ISDIRTY; 58456705Selan } else if ((n > 0 && target >= top && target < top + n) || 58556705Selan (n < 0 && target <= bot && target > bot + n)) { 58657956Selan if (clp->hash != blank_hash || memcmp(clp->line, 58756648Selan buf, win->maxx * __LDATASIZE) !=0) { 58858041Selan (void)memcpy(clp->line, buf, 58956648Selan win->maxx * __LDATASIZE); 59056472Selan #ifdef DEBUG 59160058Sbostic __CTRACE("-- blanked out: dirty"); 59256472Selan #endif 59356378Selan clp->hash = blank_hash; 59456652Selan __touchline(win, target, 0, win->maxx - 1, 0); 59556705Selan } else { 59656652Selan __touchline(win, target, 0, win->maxx - 1, 0); 59756472Selan #ifdef DEBUG 59860058Sbostic __CTRACE(" -- blank line already: dirty"); 59956472Selan #endif 60056705Selan } 60156378Selan } else { 60256472Selan #ifdef DEBUG 60360058Sbostic __CTRACE(" -- dirty"); 60456472Selan #endif 60556651Selan __touchline(win, target, 0, win->maxx - 1, 0); 60656378Selan } 60756472Selan #ifdef DEBUG 60860058Sbostic __CTRACE("\n"); 60956472Selan #endif 61056652Selan if (target == cur_period) { 61156378Selan i = target + 1; 61256378Selan tmp1 = curscr->lines[i]; 61356652Selan cur_period = i; 61456378Selan } else { 61556378Selan tmp1 = tmp2; 61656378Selan i = target; 61756378Selan } 61856302Selan } 61956472Selan #ifdef DEBUG 62060058Sbostic __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 62156648Selan for (i = 0; i < curscr->maxy; i++) { 62260058Sbostic __CTRACE("C: %d:", i); 62356648Selan for (j = 0; j < curscr->maxx; j++) 62460058Sbostic __CTRACE("%c", 62556648Selan curscr->lines[i]->line[j].ch); 62660058Sbostic __CTRACE("\n"); 62760058Sbostic __CTRACE("W: %d:", i); 62856691Selan for (j = 0; j < win->maxx; j++) 62960058Sbostic __CTRACE("%c", 63056691Selan win->lines[i]->line[j].ch); 63160058Sbostic __CTRACE("\n"); 63256648Selan } 63356472Selan #endif 634*60100Selan if (n != 0) { 635*60100Selan WINDOW *wp; 63659930Selan scrolln(win, starts, startw, curs, bot, top); 637*60100Selan /* 638*60100Selan * Need to repoint any subwindow lines to the rotated 639*60100Selan * line structured. 640*60100Selan */ 641*60100Selan for (wp = win->nextp; wp != win; wp = wp->nextp) 642*60100Selan __set_subwin(win, wp); 643*60100Selan } 64456302Selan } 64556302Selan 64656652Selan /* 64756652Selan * Scrolln performs the scroll by n lines, where n is starts - startw. 64856652Selan */ 64956302Selan static void 65056705Selan scrolln(win, starts, startw, curs, bot, top) 65156302Selan WINDOW *win; 65256705Selan int starts, startw, curs, bot, top; 65356302Selan { 65456302Selan int i, oy, ox, n; 65556302Selan 65656302Selan oy = curscr->cury; 65756302Selan ox = curscr->curx; 65856302Selan n = starts - startw; 65956302Selan 66056302Selan if (n > 0) { 66159930Selan __mvcur(oy, ox, top, 0, 1); 66256559Selan /* Scroll up the block */ 66356302Selan if (DL) 66457475Sbostic tputs(__tscroll(DL, n), 0, __cputchar); 66556302Selan else 66656302Selan for(i = 0; i < n; i++) 66756302Selan tputs(dl, 0, __cputchar); 66856652Selan 66956651Selan /* 67056652Selan * Push down the bottom region. 67156651Selan */ 67259930Selan __mvcur(top, 0, bot - n + 1, 0, 1); 67358019Selan if (AL) 67457475Sbostic tputs(__tscroll(AL, n), 0, __cputchar); 67556652Selan else 67656652Selan for(i = 0; i < n; i++) 67756652Selan tputs(al, 0, __cputchar); 67859930Selan __mvcur(bot - n + 1, 0, oy, ox, 1); 67956302Selan } else { 68056651Selan /* Preserve the bottom lines */ 68159930Selan __mvcur(oy, ox, bot + n + 1, 0, 1); /* n < 0 */ 68256652Selan if (DL) 68357475Sbostic tputs(__tscroll(DL, -n), 0, __cputchar); 68456652Selan else 68556652Selan for(i = n; i < 0; i++) 68656652Selan tputs(dl, 0, __cputchar); 68759930Selan __mvcur(bot + n + 1, 0, top, 0, 1); 68856302Selan 68956302Selan /* Scroll the block down */ 69058019Selan if (AL) 69157475Sbostic tputs(__tscroll(AL, -n), 0, __cputchar); 69256302Selan else 69356302Selan for(i = n; i < 0; i++) 69456302Selan tputs(al, 0, __cputchar); 69559930Selan __mvcur(top, 0, oy, ox, 1); 69656378Selan } 69756302Selan } 69856378Selan 69956378Selan 700