🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.unix
Article #467

Re: curses "untouch"?

#467
From: Michael Bloom
Date: Fri, 23 Oct 1987 16:07
235 lines
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!usenet
References: <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