* Copyright (c) 1981, 1993
* The Regents of the University of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93";
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((char *) 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
;
__CTRACE("wrefresh: (%0.2o): curwin = %d\n", win
, curwin
);
__CTRACE("wrefresh: \tfirstch\tlastch\n");
if ((win
->flags
& __FULLWIN
) && !curwin
) {
* Invoke quickch() only if more than a quarter of the lines
* in the window are dirty.
for (wy
= 0, dnum
= 0; wy
< win
->maxy
; wy
++)
if (win
->lines
[wy
]->flags
& (__ISDIRTY
| __FORCEPAINT
))
if (!__noqch
&& dnum
> (int) win
->maxy
/ 4)
__CTRACE("#####################################\n");
for (i
= 0; i
< curscr
->maxy
; i
++) {
__CTRACE(" 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
);
__CTRACE(" 0x%x \n", win
->lines
[i
]->hash
);
__CTRACE(" 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
);
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
| __FORCEPAINT
)) {
if (makech(win
, wy
) == 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
) {
__CTRACE("wrefresh: line %d notdirty \n", wy
);
win
->lines
[wy
]->flags
&= ~__ISDIRTY
;
__CTRACE("\t%d\t%d\n", *win
->lines
[wy
]->firstchp
,
*win
->lines
[wy
]->lastchp
);
__CTRACE("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.
static __LDATA blank
= {' ', 0};
register int nlsp
, clsp
; /* Last space in lines. */
register __LDATA
*nsp
, *csp
, *cp
, *cep
;
/* Is the cursor still on the end of the last line? */
if (wy
> 0 && win
->lines
[wy
- 1]->flags
& __ISPASTEOL
) {
domvcur(ly
, lx
, ly
+ 1, 0);
wx
= *win
->lines
[wy
]->firstchp
- win
->ch_off
;
else if (wx
>= win
->maxx
)
lch
= *win
->lines
[wy
]->lastchp
- win
->ch_off
;
else if (lch
>= (int) 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
);
__mvcur(0, 0, ly
, lx
, 1);
if (!force
&& memcmp(nsp
, csp
, sizeof(__LDATA
)) == 0) {
while (memcmp(nsp
, csp
, sizeof(__LDATA
)) == 0 &&
domvcur(ly
, lx
, y
, wx
+ win
->begx
);
__CTRACE("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
|| memcmp(nsp
, csp
, sizeof(__LDATA
)) != 0)
if (ce
!= NULL
&& win
->maxx
+ win
->begx
==
curscr
->maxx
&& wx
>= nlsp
&& nsp
->ch
== ' ') {
/* Check for clear to end-of-line. */
cep
= &curscr
->lines
[wy
]->line
[win
->maxx
- 1];
while (cep
->ch
== ' ' && cep
->attr
== 0)
clsp
= cep
- curscr
->lines
[wy
]->line
-
__CTRACE("makech: clsp = %d, nlsp = %d\n", clsp
, nlsp
);
if ((clsp
- nlsp
>= strlen(CE
)
&& clsp
< win
->maxx
* __LDATASIZE
) ||
__CTRACE("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
)
if (!(win
->flags
& __SCROLLWIN
)) {
putchar(csp
->ch
= nsp
->ch
);
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 (wx
< win
->maxx
|| wy
< win
->maxy
- 1 ||
!(win
->flags
& __SCROLLWIN
)) {
putchar(csp
->ch
= nsp
->ch
);
__CTRACE("makech: putchar(%c)\n", nsp
->ch
& 0177);
if (UC
&& (nsp
->attr
& __STANDOUT
)) {
tputs(UC
, 0, __cputchar
);
__CTRACE("makech: 2: wx = %d, lx = %d\n", wx
, lx
);
if (lx
== wx
+ win
->begx
) /* If no change. */
else if (wx
>= win
->maxx
) {
domvcur(ly
, lx
, ly
, win
->maxx
+ win
->begx
- 1);
lx
= win
->maxx
+ win
->begx
- 1;
__CTRACE("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
;
__mvcur(oy
, ox
, ny
, nx
, 1);
* 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 (int) 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
;
* 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
|| memcmp(win
->lines
[top
]->line
,
curscr
->lines
[top
]->line
,
win
->maxx
* __LDATASIZE
) != 0)
win
->lines
[top
]->flags
&= ~__ISDIRTY
;
* 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
|| memcmp(win
->lines
[bot
]->line
,
curscr
->lines
[bot
]->line
,
win
->maxx
* __LDATASIZE
) != 0)
win
->lines
[bot
]->flags
&= ~__ISDIRTY
;
* If we have a bottom unchanged region return. Scrolling the
* bottom region up and then back down causes a screen jitter.
* This will increase the number of characters sent to the screen
#endif /* NO_JERKINESS */
* 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
= bot
- top
; bsize
>= THRESH
; bsize
--) {
for (startw
= top
; startw
<= bot
- bsize
; startw
++)
for (starts
= top
; starts
<= bot
- bsize
;
for (curw
= startw
, curs
= starts
;
curs
< starts
+ bsize
; curw
++, curs
++)
if (win
->lines
[curw
]->flags
&
(win
->lines
[curw
]->hash
!=
curscr
->lines
[curs
]->hash
||
memcmp(win
->lines
[curw
]->line
,
curscr
->lines
[curs
]->line
,
win
->maxx
* __LDATASIZE
) != 0))
if (curs
== starts
+ bsize
)
/* Did not find anything */
__CTRACE("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.
__CTRACE("#####################################\n");
for (i
= 0; i
< curscr
->maxy
; i
++) {
__CTRACE(" 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
);
__CTRACE(" 0x%x \n", win
->lines
[i
]->hash
);
__CTRACE(" 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
);
/* So we don't have to call __hash() each time */
for (i
= 0; i
< win
->maxx
; i
++) {
blank_hash
= __hash((char *) 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
];
__CTRACE("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
|| memcmp(clp
->line
,
buf
, win
->maxx
* __LDATASIZE
) !=0) {
(void)memcpy(clp
->line
, buf
,
win
->maxx
* __LDATASIZE
);
__CTRACE("-- blanked out: dirty");
__touchline(win
, target
, 0, win
->maxx
- 1, 0);
__touchline(win
, target
, 0, win
->maxx
- 1, 0);
__CTRACE(" -- blank line already: dirty");
__touchline(win
, target
, 0, win
->maxx
- 1, 0);
if (target
== cur_period
) {
__CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\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(win
, starts
, startw
, curs
, bot
, top
);
* Need to repoint any subwindow lines to the rotated
for (wp
= win
->nextp
; wp
!= win
; wp
= wp
->nextp
)
* 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
;
__mvcur(oy
, ox
, top
, 0, 1);
/* 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, 1);
tputs(__tscroll(AL
, n
), 0, __cputchar
);
tputs(al
, 0, __cputchar
);
__mvcur(bot
- n
+ 1, 0, oy
, ox
, 1);
/* Preserve the bottom lines */
__mvcur(oy
, ox
, bot
+ n
+ 1, 0, 1); /* n < 0 */
tputs(__tscroll(DL
, -n
), 0, __cputchar
);
tputs(dl
, 0, __cputchar
);
__mvcur(bot
+ n
+ 1, 0, top
, 0, 1);
/* Scroll the block down */
tputs(__tscroll(AL
, -n
), 0, __cputchar
);
tputs(al
, 0, __cputchar
);
__mvcur(top
, 0, oy
, ox
, 1);