dalegass@dalcsug.UUCP (Dale Gass) (10/14/87)
Could anyone tell the easiest way (or any way) to 'untouch' a window in curses? 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... Is there any way to tell curses not to bother rewriting; things are just fine on the screen? Also, what are the flags ENDLINE,FULLWIN,SCROLLWIN,FLUSH,FULLLINE,IDLINE, NOCHANGE, leave, clear, ch_off for? -dalegass@dalcsug.uucp
usenet@mcdchg.UUCP (10/22/87)
[This is the first of three responses to the "untouch" article that I've received. In addition, help arrived from Steve Nuchia and Mike Stump. -mod] (Gawd, I hate curses! I'm working with overlapping windows, and they're a real pain!) Each line in a window has an offset to the first and last characters that are changed called _firstch[y] and _lastch[y]. If you set: window->_firstch[y] = _NOCHANGE the line becomes untouched. There is also an undocumented call touchline(window, y, startx, endx) to touch a portion of a line in a window. Hope I got this right. Good luck -- "You can't argue with a sick mind." Bob Ankeney ...!tektronix!reed!bob
usenet@mcdchg.UUCP (10/22/87)
There is a macro called idlok which is _supposed_ to tell curses to use the hardware insert/delete line capability if possible. This is implemented in the ATT version of curses but isn't in the Berkely version. I will assume that you have the Berkeley version. This assumption is valid because AT&T's version does not use the IDLINE flag, therefore you must be using BSD. Berkely's version of scroll() basically moves to line 0 then calls deleteln (which touches all lines on the current window) and then restores the cursor to it's original position on the screen. What you need to do is the same thing except that you should send the DL termcap sequence to the terminal by yourself and then 'untouch' all lines in the window. A simple (and untested) function to do this is: hwscroll(win) WINDOW *win; { int ox,oy,y; getyx(win, oy, ox); /* save current cursor position */ wmove(win, 0, 0); _puts(DL); /* delete top line of window */ deleteln(win); /* update internal data structures of win */ wmove (win, oy, ox); /* restore cursor */ /* now 'untouch' all lines in the current window */ for (y=0; y<win->_maxy; y++) win->_firstch[y] = _NOCHANGE; } This of course works best for windows which are the same size as the terminal screen. If this isn't the case then you may need to insert a line (capability AL) to get the other window back to it's normal state. > > Also, what are the flags ENDLINE,FULLWIN,SCROLLWIN,FLUSH,FULLLINE,IDLINE, > NOCHANGE, leave, clear, ch_off for? > ENDLINE: This flag is used to indicate that this window has the same number of columns as the physical terminal screen. This is useful for functions like clrtoeol. FULLWIN: This flag is used to indicate that this window has the same dimensions as the physical terminal screen (ie stdscr). This should allow easy scrolling of the whole window by simply printing a linefeed in the lower right corner of the screen (if the cursor doesn't wrap to top left). SCROLLWIN:This flag is used to indicate that the window could scroll by accident. This would occur if you write a character to the lower right corner of the screen and the am capability is present. NOCHANGE: Is a simple indicator of change. Different variables are set to this value to indicate that no change has occured. If the variable is then queried later and the value is other than -1 (NOCHANGE) then it is assumed that a change has occurred (therefore some updating would be necessary). IDLINE: Set by the idlok macro. Unused by Berkeley curses. FLUSH: Set by flushok macro. Unused by Berkeley curses. leave: This flag tells the update logic where to leave the cursor at the end of an update cycle. If it is true then the cursor may be left anywhere after an update. If it is false then the cursor is left at the current position. clear: A flag that is used to tell the refresh logic to clear the terminal screen before the next update. ch_off: The character offset of a subwin from the left hand side of the terminal screen. This is used to correctly position characters within subwindows and windows whose begx coordinate is not 0. Hope that this info helps you out. -- ------------------------------------------------------------------------ Scott L. Wiegel +--+ +--+ | | | | Harris Computer Systems Division | +----+ | 2101 W. Cypress Creek Rd. |_/-\_/-\_/| Ft. Lauderdale, Fl 33309 | +----+ | | | | | UUCP:slwiegel@hcx1.harris.com |__| |__| ------------------------------------------------------------------------
mb@ttidca.UUCP (Michael Bloom) (10/23/87)
> 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); }
katzung@laidbak.UUCP (Brian Katzung) (11/04/87)
Note that to be really complete, the hwscroll() routine should go to the bottom of the screen and issue an insert line or erase (to end of) line sequence if DB is set (display retained below). -- Brian Katzung