Article View: comp.unix
Article #467Re: curses "untouch"?
From: Michael Bloom
Date: Fri, 23 Oct 1987 16:07
Date: Fri, 23 Oct 1987 16:07
235 lines
5363 bytes
5363 bytes
> The problem is thus: I want to scroll a portion of my screen, and curses
> does this very slowly be rewriting the whole portion. I want to do a
> hardware scroll by sending the proper code directly to my terminal, doing
> a scroll(win), and then having curses be happy with the way things are
> and do nothing on the next wrefresh(win). However, since curses thinks
> the whole window has to be refreshed due to the scroll(), it rewrites...
I did this once a while back. You can't use scroll() itself, however.
What you do instead is to use a combination if winsertln() and
wdeleteln() calls, doing the same operations that you did on stdscr
again on curscr AT THE SAME TIME as you handle the hardware scroll.
After which, it is safe to call refresh. (System V curses is smarter;
for portability to system V, you can just ifdef out all the klugery).
With just the above, you need to do a lot of extra hardware operations.
It's better to put a wrapper around winsertln() and wdeleteln() to leave
an audit of the operations you've performed on stdscr.
Then you can have a redisplay() routine that looks like
redisplay()
{
if (optimize_scrollinfo(audit_info) < THRESHOLD)
do_hardware_scroll(audit_info);
(*application_specific_pre_work)(); /* optional */
refresh();
(*application_specific_post_work)(); /* also optional */
clear_audit();
}
My original application was fairly simple and always scrolled the same
sub-portion of the window, so my do_hardware_scroll used a global scroll
count instead of a more elaborate audit trail and looked like:
do_hardware_scroll()
{
int cnt = ins_del_cnt;
int abscnt = (ins_del_cnt >=0 ) ?ins_del_cnt : -ins_del_cnt;
int i;
if (!abscnt || abscnt > SCROLLBOT-2) /* let curses do its own thing */
return;
if (ins_del_cnt <0) /* scroll up */
{
for (i = 0;i<abscnt;i++)
wscr_up(curscr);
if (sc_scroll_region && *sc_scroll_region)
ansi_scroll(cnt);
else
{
tputs(tgoto(CM,0,0),1,_putchar);
while (cnt++)
{
tputs(DL,LINES,_putchar);
}
tputs(tgoto(CM,0,(MODELINE)-abscnt),1,_putchar);
while (abscnt--)
{
tputs(AL,LINES,_putchar);
}
}
}
else
{
for (i = 0;i<abscnt;i++)
wscr_down(curscr);
tputs(tgoto(CM,0,SCROLLBOT-(abscnt-1)),1,_putchar);
if (sc_scroll_region && *sc_scroll_region)
ansi_scroll(cnt);
else
{
while (cnt--)
tputs(DL,LINES,_putchar);
scgoto(0,0);
while (abscnt--)
tputs(AL,LINES,_putchar);
}
}
}
My ansi scroll always scrolled the same size region. If you aren't doing
that you'd need to replace the "SCROLLBOT,0" constants with appropriate
variables in the following:
ansi_scroll(cnt)
int cnt;
{
if (!cnt)
return;
tputs(tgoto(CS,SCROLLBOT,0),1,_putchar); /* set region */
if (cnt <0)
{
scgoto(SCROLLBOT,0);
while (cnt++)
tputs(SF,SCROLLBOT+1,_putchar);
}
else
{
scgoto(0,0);
while (cnt--)
tputs(SR,SCROLLBOT+1,_putchar);
}
tputs(tgoto(CS,LINES-1,0),1,_putchar); /* restore region*/
scgoto(0,0); /* scroll region moved the cursor here */
}
Here are some other routines you can use:
add_line()
{
wscr_down(stdscr);
home();
}
/* synchronized (curses and real world)
cursor motion */
scgoto(row,col)
{
tputs(tgoto(CM, col, row),1,_putchar);
wmove(curscr,row,col);
}
/*
* clear a region of lines
*/
wclear_txt(win)
WINDOW *win;
{
register int i;
for (i=SCROLLBOT;i>=0;i--)
{
wmove(win,i,0);
wclrtoeol(win);
}
if (win == curscr)
scgoto(0,0);
}
clear_txt()
{
wclear_txt(stdscr);
}
ins_line(scr)
WINDOW *scr;
{
winsertln(scr);
if (scr == curscr)
return;
ins_del_cnt++;
if (ins_cnt < ins_del_cnt)
ins_cnt++;
}
del_line(scr)
WINDOW * scr;
{
wdeleteln(scr);
if (scr == curscr)
return;
ins_del_cnt--;
if (del_cnt > ins_del_cnt)
del_cnt--;
}
scrollup()
{
wscr_up(stdscr);
}
wscr_up(scr)
WINDOW *scr;
{
wmove(scr,0,0);
del_line(scr);
wmove(scr,SCROLLBOT,0);
winsertln(scr);
}
scrolldown()
{
wscr_down(stdscr);
}
wscr_down(scr)
WINDOW *scr;
{
wmove(scr,SCROLLBOT,0);
wdeleteln(scr);
wmove(scr,0,0);
ins_line(scr);
}
clr_cnt()
{
ins_del_cnt = del_cnt = ins_cnt = 0;
}
clr_lowest_line()
{
move(ECHOLINE,0);
clrtoeol();
}
invalidate_screen()
{
werase(curscr);
clearok(curscr,1);
}
/* flush: called by routines that dont
include curses.h */
flush()
{
refresh();
}
to_scroll_bot()
{
move(SCROLLBOT,0);
}
/* called from routines that dont include
either curses.h or stdio.h */
std_flush()
{
fflush(stdout);
}
Technical Details
Message-ID:
<2137@mcdchg.UUCP>Path:
arc1-ca.pugleaf.net!utzoo!mnetor!uunet!husc6!hao!ames!lll-tis!mordor!sri-spam!rutgers!gatech!mcdchg!usenetReferences:
<2059@mcdchg.UUCP>Show Full Headers
Complete Article Headers
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: arc1-ca.pugleaf.net!utzoo!mnetor!uunet!husc6!hao!ames!lll-tis!mordor!sri-spam!rutgers!gatech!mcdchg!usenet From: mb@ttidca.UUCP (Michael Bloom) Newsgroups: comp.unix Subject: Re: curses "untouch"? Message-ID: <2137@mcdchg.UUCP> Date: Fri, 23-Oct-87 11:07:11 EST Article-I.D.: mcdchg.2137 Posted: Fri Oct 23 11:07:11 1987 Date-Received: Sun, 25-Oct-87 22:45:39 EST References: <2059@mcdchg.UUCP> Sender: usenet@mcdchg.UUCP Reply-To: mb@psivax.UUCP (Michael Bloom) Organization: Citicorp/TTI, Santa Monica Lines: 235 Approved: usenet@mcdchg.UUCP