* Copyright (c) 1981 Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)refresh.c 5.26 (Berkeley) %G%";
static void domvcur
__P((int, int, int, int));
static int makech
__P((WINDOW
*, int));
static void quickch
__P((WINDOW
*));
static void scrolln
__P((WINDOW
*, int, int, int, int, int));
* Make the current screen look like "win" over the area coverd by
/* Initialize loop parameters. */
curwin
= (win
== curscr
);
for (wy
= 0; wy
< win
->maxy
; wy
++) {
if (wlp
->flags
& __ISDIRTY
)
__hash(wlp
->line
, win
->maxx
* __LDATASIZE
);
if (win
->flags
& __CLEAROK
|| curscr
->flags
& __CLEAROK
|| curwin
) {
if ((win
->flags
& __FULLWIN
) || curscr
->flags
& __CLEAROK
) {
tputs(CL
, 0, __cputchar
);
curscr
->flags
&= ~__CLEAROK
;
win
->flags
&= ~__CLEAROK
;
__TRACE("wrefresh: (%0.2o): curwin = %d\n", win
, curwin
);
__TRACE("wrefresh: \tfirstch\tlastch\n");
if (!__noqch
&& (win
->flags
& __FULLWIN
) && !curwin
)
for (wy
= 0; wy
< win
->maxy
; wy
++) {
wy
, *win
->lines
[wy
]->firstchp
, *win
->lines
[wy
]->lastchp
);
curscr
->lines
[wy
]->hash
= win
->lines
[wy
]->hash
;
if (win
->lines
[wy
]->flags
& __ISDIRTY
||
win
->lines
[wy
]->flags
& __FORCEPAINT
)
if (makech(win
, wy
) == CURSES_ERR
)
if (*win
->lines
[wy
]->firstchp
>= win
->ch_off
)
*win
->lines
[wy
]->firstchp
= win
->maxx
+
if (*win
->lines
[wy
]->lastchp
< win
->maxx
+
*win
->lines
[wy
]->lastchp
= win
->ch_off
;
if (*win
->lines
[wy
]->lastchp
<
*win
->lines
[wy
]->firstchp
)
win
->lines
[wy
]->flags
&= ~__ISDIRTY
;
__TRACE("\t%d\t%d\n", *win
->lines
[wy
]->firstchp
,
*win
->lines
[wy
]->lastchp
);
__TRACE("refresh: ly=%d, lx=%d\n", ly
, lx
);
domvcur(ly
, lx
, win
->cury
, win
->curx
);
if (win
->flags
& __LEAVEOK
) {
if (ly
>= 0 && ly
< win
->maxy
&& lx
>= 0 &&
win
->cury
= win
->curx
= 0;
domvcur(ly
, lx
, win
->cury
+ win
->begy
,
curscr
->cury
= win
->cury
+ win
->begy
;
curscr
->curx
= win
->curx
+ win
->begx
;
* Make a change on the screen.
register int nlsp
, clsp
; /* Last space in lines. */
register short wx
, lch
, y
;
register __LDATA
*nsp
, *csp
, *cp
;
__LDATA blank
= {' ', 0};
/* Is the cursor still on the end of the last line? */
if (wy
> 0 && win
->lines
[wy
- 1]->flags
& __ISPASTEOL
) {
win
->lines
[wy
- 1]->flags
&= ~__ISPASTEOL
;
domvcur(ly
, lx
, ly
+ 1, 0);
if (!(win
->lines
[wy
]->flags
& __ISDIRTY
))
wx
= *win
->lines
[wy
]->firstchp
- win
->ch_off
;
lch
= *win
->lines
[wy
]->lastchp
- win
->ch_off
;
else if (lch
>= win
->maxx
)
csp
= &curscr
->lines
[wy
+ win
->begy
]->line
[wx
+ win
->begx
];
nsp
= &win
->lines
[wy
]->line
[wx
];
force
= win
->lines
[wy
]->flags
& __FORCEPAINT
;
win
->lines
[wy
]->flags
&= ~__FORCEPAINT
;
for (cp
= &win
->lines
[wy
]->line
[win
->maxx
- 1];
cp
->ch
== ' ' && cp
->attr
== 0; cp
--)
if (cp
<= win
->lines
[wy
]->line
)
nlsp
= cp
- win
->lines
[wy
]->line
;
tputs(tgoto(CM
, lx
, ly
), 0, __cputchar
);
tputs(HO
, 0, __cputchar
);
if (!force
&& bcmp(nsp
, csp
, sizeof(__LDATA
)) == 0) {
while (bcmp(nsp
, csp
, sizeof(__LDATA
)) == 0 &&
domvcur(ly
, lx
, y
, wx
+ win
->begx
);
__TRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n",
wx
, ly
, lx
, y
, wx
+ win
->begx
, force
);
while ((force
|| bcmp(nsp
, csp
, sizeof(__LDATA
)) != 0)
* The problem with this code is that we can't count on
* terminals wrapping around after the
* last character on the previous line has been output
* In effect, what then could happen is that the CE
* clear the previous line and do nothing to the
if (ce
!= NULL
&& wx
>= nlsp
&&
/* Check for clear to end-of-line. */
ce
= &curscr
->lines
[wy
]->line
[COLS
- 1];
while (ce
->ch
== ' ' && ce
->attr
= 0)
clsp
= ce
- curscr
->lines
[wy
]->line
-
__TRACE("makech: clsp = %d, nlsp = %d\n", clsp
, nlsp
);
if (clsp
- nlsp
>= strlen(CE
)
&& clsp
< win
->maxx
* __LDATASIZE
) {
__TRACE("makech: using CE\n");
tputs(CE
, 0, __cputchar
);
/* Enter/exit standout mode as appropriate. */
if (SO
&& (nsp
->attr
& __STANDOUT
) !=
(curscr
->flags
& __WSTANDOUT
)) {
if (nsp
->attr
& __STANDOUT
) {
tputs(SO
, 0, __cputchar
);
curscr
->flags
|= __WSTANDOUT
;
tputs(SE
, 0, __cputchar
);
curscr
->flags
&= ~__WSTANDOUT
;
if (wx
>= win
->maxx
&& wy
== win
->maxy
- 1 && !curwin
)
if (win
->flags
& __SCROLLOK
) {
if (curscr
->flags
& __WSTANDOUT
&& win
->flags
& __ENDLINE
)
putchar(csp
->ch
= nsp
->ch
);
#ifdef notdef /* XXX why is this here? */
if (win
->flags
& __FULLWIN
&& !curwin
)
if (wx
+ win
->begx
< curscr
->maxx
) {
domvcur(ly
, wx
+ win
->begx
,
win
->begy
+ win
->maxy
- 1,
win
->begx
+ win
->maxx
- 1);
ly
= win
->begy
+ win
->maxy
- 1;
lx
= win
->begx
+ win
->maxx
- 1;
if (win
->flags
& __SCROLLWIN
) {
putchar(csp
->ch
= nsp
->ch
);
__TRACE("makech: putchar(%c)\n", nsp
->ch
& 0177);
if (UC
&& (nsp
->attr
& __STANDOUT
)) {
tputs(UC
, 0, __cputchar
);
__TRACE("makech: 2: wx = %d, lx = %d\n", wx
, lx
);
if (lx
== wx
+ win
->begx
) /* If no change. */
* xn glitch: chomps a newline after auto-wrap.
* we just feed it now and forget about it.
win
->lines
[wy
]->flags
|= __ISPASTEOL
;
} else if (wx
>= win
->maxx
) {
win
->lines
[wy
]->flags
|= __ISPASTEOL
;
domvcur(ly
, lx
, ly
, win
->maxx
+ win
->begx
- 1);
lx
= win
->maxx
+ win
->begx
- 1;
__TRACE("makech: 3: wx = %d, lx = %d\n", wx
, lx
);
* Do a mvcur, leaving standout mode if necessary.
if (curscr
->flags
& __WSTANDOUT
&& !MS
) {
tputs(SE
, 0, __cputchar
);
curscr
->flags
&= ~__WSTANDOUT
;
* Quickch() attempts to detect a pattern in the change of the window
* in order to optimize the change, e.g., scroll n lines as opposed to
* repainting the screen line by line.
#define THRESH win->maxy / 4
register __LINE
*clp
, *tmp1
, *tmp2
;
register int bsize
, curs
, curw
, starts
, startw
, i
, j
;
int n
, target
, cur_period
, bot
, top
, sc_region
;
* Search for the largest block of text not changed.
* Invariants of the loop:
* - Startw is the index of the beginning of the examined block in win.
* - Starts is the index of the beginning of the examined block in
* - Curs is the index of one past the end of the exmined block in win.
* - Curw is the index of one past the end of the exmined block in
* - bsize is the current size of the examined block.
for (bsize
= win
->maxy
; bsize
>= THRESH
; bsize
--)
for (startw
= 0; startw
<= win
->maxy
- bsize
; startw
++)
for (starts
= 0; starts
<= win
->maxy
- bsize
;
for (curw
= startw
, curs
= starts
;
curs
< starts
+ bsize
; curw
++, curs
++)
if (win
->lines
[curw
]->flags
&
(win
->lines
[curw
]->hash
!=
curscr
->lines
[curs
]->hash
||
bcmp(win
->lines
[curw
]->line
,
curscr
->lines
[curs
]->line
,
win
->maxx
* __LDATASIZE
) != 0))
if (curs
== starts
+ bsize
)
/* Did not find anything */
* Find how many lines from the top of the screen are unchanged.
for (top
= 0; top
< win
->maxy
; top
++)
if (win
->lines
[top
]->flags
& __FORCEPAINT
||
win
->lines
[top
]->hash
!= curscr
->lines
[top
]->hash
|| bcmp(win
->lines
[top
]->line
,
curscr
->lines
[top
]->line
,
win
->maxx
* __LDATASIZE
) != 0)
* Find how many lines from bottom of screen are unchanged.
for (bot
= win
->maxy
- 1; bot
>= 0; bot
--)
if (win
->lines
[bot
]->flags
& __FORCEPAINT
||
win
->lines
[bot
]->hash
!= curscr
->lines
[bot
]->hash
|| bcmp(win
->lines
[bot
]->line
,
curscr
->lines
[bot
]->line
,
win
->maxx
* __LDATASIZE
) != 0)
__TRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n",
bsize
, starts
, startw
, curw
, curs
, top
, bot
);
* Make sure that there is no overlap between the bottom and top
* regions and the middle scrolled block.
__TRACE("#####################################\n");
for (i
= 0; i
< curscr
->maxy
; i
++) {
__TRACE(" 0x%x \n", curscr
->lines
[i
]->hash
);
for (j
= 0; j
< curscr
->maxx
; j
++)
curscr
->lines
[i
]->line
[j
].ch
);
for (j
= 0; j
< curscr
->maxx
; j
++)
curscr
->lines
[i
]->line
[j
].attr
);
__TRACE(" 0x%x \n", win
->lines
[i
]->hash
);
__TRACE(" 0x%x ", win
->lines
[i
]->flags
);
for (j
= 0; j
< win
->maxx
; j
++)
win
->lines
[i
]->line
[j
].ch
);
for (j
= 0; j
< win
->maxx
; j
++)
win
->lines
[i
]->line
[j
].attr
);
scrolln(win
, starts
, startw
, curs
, bot
, top
);
/* So we don't have to call __hash() each time */
for (i
= 0; i
< win
->maxx
; i
++) {
blank_hash
= __hash(buf
, win
->maxx
* __LDATASIZE
);
* Perform the rotation to maintain the consistency of curscr.
* This is hairy since we are doing an *in place* rotation.
* Invariants of the loop:
* - I is the index of the current line.
* - Target is the index of the target of line i.
* - Tmp1 points to current line (i).
* - Tmp2 and points to target line (target);
* - Cur_period is the index of the end of the current period.
* There are 2 major issues here that make this rotation non-trivial:
* 1. Scrolling in a scrolling region bounded by the top
* and bottom regions determined (whose size is sc_region).
* 2. As a result of the use of the mod function, there may be a
* period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and
* 0 to 2, which then causes all odd lines not to be rotated.
* To remedy this, an index of the end ( = beginning) of the
* current 'period' is kept, cur_period, and when it is reached,
* the next period is started from cur_period + 1 which is
* guaranteed not to have been reached since that would mean that
* all records would have been reached. (think about it...).
* Lines in the rotation can have 3 attributes which are marked on the
* line so that curscr is consistent with the visual screen.
* 1. Not dirty -- lines inside the scrolled block, top region or
* 2. Blank lines -- lines in the differential of the scrolling
* region adjacent to top and bot regions
* depending on scrolling direction.
* 3. Dirty line -- all other lines are marked dirty.
sc_region
= bot
- top
+ 1;
tmp1
= curscr
->lines
[top
];
for (j
= top
; j
<= bot
; j
++) {
target
= (i
- top
+ n
+ sc_region
) % sc_region
+ top
;
tmp2
= curscr
->lines
[target
];
curscr
->lines
[target
] = tmp1
;
/* Mark block as clean and blank out scrolled lines. */
clp
= curscr
->lines
[target
];
__TRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ",
n
, startw
, curw
, i
, target
);
if ((target
>= startw
&& target
< curw
) || target
< top
win
->lines
[target
]->flags
&= ~__ISDIRTY
;
} else if ((n
> 0 && target
>= top
&& target
< top
+ n
) ||
(n
< 0 && target
<= bot
&& target
> bot
+ n
)) {
if (clp
->hash
!= blank_hash
|| bcmp(clp
->line
,
buf
, win
->maxx
* __LDATASIZE
) !=0) {
(void)bcopy(buf
, clp
->line
,
win
->maxx
* __LDATASIZE
);
__TRACE("-- blanked out: dirty");
__touchline(win
, target
, 0, win
->maxx
- 1, 0);
__touchline(win
, target
, 0, win
->maxx
- 1, 0);
__TRACE(" -- blank line already: dirty");
__touchline(win
, target
, 0, win
->maxx
- 1, 0);
if (target
== cur_period
) {
__TRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
for (i
= 0; i
< curscr
->maxy
; i
++) {
for (j
= 0; j
< curscr
->maxx
; j
++)
curscr
->lines
[i
]->line
[j
].ch
);
for (j
= 0; j
< win
->maxx
; j
++)
win
->lines
[i
]->line
[j
].ch
);
* Scrolln performs the scroll by n lines, where n is starts - startw.
scrolln(win
, starts
, startw
, curs
, bot
, top
)
int starts
, startw
, curs
, bot
, top
;
/* Scroll up the block */
tputs(tscroll(DL
, n
), 0, __cputchar
);
tputs(dl
, 0, __cputchar
);
* Push down the bottom region.
mvcur(top
, 0, bot
- n
+ 1, 0);
tputs(tscroll(AL
, n
), 0, __cputchar
);
tputs(al
, 0, __cputchar
);
mvcur(bot
- n
+ 1, 0, oy
, ox
);
/* Preserve the bottom lines */
mvcur(oy
, ox
, bot
+ n
+ 1, 0); /* n < 0 */
tputs(tscroll(DL
, -n
), 0, __cputchar
);
tputs(dl
, 0, __cputchar
);
mvcur(bot
+ n
+ 1, 0, top
, 0);
/* Scroll the block down */
tputs(tscroll(AL
, -n
), 0, __cputchar
);
tputs(al
, 0, __cputchar
);