root/usr/src/ucblib/libcurses/refresh.c
/*
 * Copyright 2001 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
/*        All Rights Reserved   */

/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

/*LINTLIBRARY*/

#ifndef lint
static char
sccsid[] = "@(#)refresh.c 1.8 89/08/24 SMI"; /* from UCB 5.1 85/06/07 */
#endif /* not lint */

/*
 * make the current screen look like "win" over the area coverd by
 * win.
 */

#include        "curses.ext"
#include        <term.h>
#include        <string.h>

#ifdef DEBUG
#define DEBUGSTATIC
#else
#define DEBUGSTATIC     static
#endif

DEBUGSTATIC short       ly, lx;
DEBUGSTATIC bool        curwin;
WINDOW  *_win = NULL;

/* forward declarations */
DEBUGSTATIC void domvcur(int, int, int, int);
DEBUGSTATIC int makech(WINDOW *, short);

int
wrefresh(WINDOW *win)
{
        short   wy;
        int     retval;

        /*
         * make sure were in visual state
         */
        if (_endwin) {
                (void) _puts(VS);
                (void) _puts(TI);
                _endwin = FALSE;
        }

        /*
         * initialize loop parameters
         */

        ly = curscr->_cury;
        lx = curscr->_curx;
        _win = win;
        curwin = (win == curscr);

        if (win->_clear || curscr->_clear || curwin) {
                if ((win->_flags & _FULLWIN) || curscr->_clear) {
                        (void) _puts(CL);
                        ly = 0;
                        lx = 0;
                        if (!curwin) {
                                curscr->_clear = FALSE;
                                curscr->_cury = 0;
                                curscr->_curx = 0;
                                (void) werase(curscr);
                        }
                        (void) touchwin(win);
                }
                win->_clear = FALSE;
        }
        if (!CA) {
                if (win->_curx != 0)
                        (void) _putchar('\n');
                if (!curwin)
                        (void) werase(curscr);
        }
#ifdef DEBUG
        fprintf(outf, "REFRESH(%0.2o): curwin = %d\n", win, curwin);
        fprintf(outf, "REFRESH:\n\tfirstch\tlastch\n");
#endif
        for (wy = 0; wy < win->_maxy; wy++) {
#ifdef DEBUG
                fprintf(outf, "%d\t%d\t%d\n", wy, win->_firstch[wy],
                    win->_lastch[wy]);
#endif
                if (win->_firstch[wy] != _NOCHANGE)
                        if (makech(win, wy) == ERR)
                                return (ERR);
                        else {
                                if (win->_firstch[wy] >= win->_ch_off)
                                        win->_firstch[wy] = win->_maxx +
                                                            win->_ch_off;
                                if (win->_lastch[wy] < win->_maxx +
                                    win->_ch_off)
                                        win->_lastch[wy] = win->_ch_off;
                                if (win->_lastch[wy] < win->_firstch[wy])
                                        win->_firstch[wy] = _NOCHANGE;
                        }
#ifdef DEBUG
                fprintf(outf, "\t%d\t%d\n", win->_firstch[wy],
                    win->_lastch[wy]);
#endif
        }

        if (win == curscr)
                domvcur(ly, lx, win->_cury, win->_curx);
        else {
                if (win->_leave) {
                        curscr->_cury = ly;
                        curscr->_curx = lx;
                        ly -= win->_begy;
                        lx -= win->_begx;
                        if (ly >= 0 && ly < win->_maxy && lx >= 0 &&
                            lx < win->_maxx) {
                                win->_cury = ly;
                                win->_curx = lx;
                        }
                        else
                                win->_cury = win->_curx = 0;
                } else {
                        domvcur(ly, lx, win->_cury + win->_begy,
                                win->_curx + win->_begx);
                        curscr->_cury = win->_cury + win->_begy;
                        curscr->_curx = win->_curx + win->_begx;
                }
        }
        retval = OK;

        _win = NULL;
        (void) fflush(stdout);
        return (retval);
}

/*
 * make a change on the screen
 */

DEBUGSTATIC int
makech(WINDOW *win, short wy)
{
        char    *nsp, *csp, *ce;
        short   wx, lch, y;
        intptr_t        nlsp, clsp;     /* last space in lines          */

        wx = win->_firstch[wy] - win->_ch_off;
        if (wx >= win->_maxx)
                return (OK);
        else if (wx < 0)
                wx = 0;
        lch = win->_lastch[wy] - win->_ch_off;
        if (lch < 0)
                return (OK);
        else if (lch >= win->_maxx)
                lch = win->_maxx - 1;
        y = wy + win->_begy;

        if (curwin)
                csp = " ";
        else
                csp = &curscr->_y[wy + win->_begy][wx + win->_begx];

        nsp = &win->_y[wy][wx];
        if (CE && !curwin) {
                for (ce = &win->_y[wy][win->_maxx - 1]; *ce == ' '; ce--)
                        if (ce <= win->_y[wy])
                                break;
                nlsp = ce - win->_y[wy];
        }

        if (!curwin)
                ce = CE;
        else
                ce = NULL;

        while (wx <= lch) {
                if (*nsp != *csp) {
                        domvcur(ly, lx, y, wx + win->_begx);
#ifdef DEBUG
                        fprintf(outf, "MAKECH: 1: wx = %d, lx = %d\n", wx, lx);
#endif
                        ly = y;
                        lx = wx + win->_begx;
                        while (wx <= lch && *nsp != *csp) {
                                if (ce != NULL && wx >= nlsp && *nsp == ' ') {
                                        /*
                                         * check for clear to end-of-line
                                         */
                                        ce = &curscr->_y[ly][COLS - 1];
                                        while (*ce == ' ')
                                                if (ce-- <= csp)
                                                        break;
                                        clsp = ce - curscr->_y[ly] - win->_begx;
#ifdef DEBUG
                                        fprintf(outf, "MAKECH: clsp = %d,"
                                            " nlsp = %d\n", clsp, nlsp);
#endif
                                        if (clsp - nlsp >= strlen(CE) &&
                                            clsp < win->_maxx) {
#ifdef DEBUG
                                                fprintf(outf, "MAKECH: using"
                                                    " CE\n");
#endif
                                                (void) _puts(CE);
                                                lx = wx + win->_begx;
                                                while (wx++ <= clsp)
                                                        *csp++ = ' ';
                                                return (OK);
                                        }
                                        ce = NULL;
                                }
                                /*
                                 * enter/exit standout mode as appropriate
                                 */
                                if (SO && (*nsp&_STANDOUT) !=
                                    (curscr->_flags&_STANDOUT)) {
                                        if (*nsp & _STANDOUT) {
                                                (void) _puts(SO);
                                                curscr->_flags |= _STANDOUT;
                                        } else {
                                                (void) _puts(SE);
                                                curscr->_flags &= ~_STANDOUT;
                                        }
                                }
                                wx++;
                                if (wx >= win->_maxx && wy == win->_maxy - 1)
                                        if (win->_scroll) {
                                            if ((curscr->_flags&_STANDOUT) &&
                                                (win->_flags & _ENDLINE))
                                                    if (!MS) {
                                                        (void) _puts(SE);
                                                        curscr->_flags &=
                                                            ~_STANDOUT;
                                                    }
                                            if (!curwin)
                                                (void) _putchar((*csp = *nsp) &
                                                    0177);
                                            else
                                                (void) _putchar(*nsp & 0177);
                                            if (win->_flags&_FULLWIN && !curwin)
                                                (void) scroll(curscr);
                                            if (!curwin) {
                                                    ly = wy + win->_begy;
                                                    lx = wx + win->_begx;
                                            } else {
                                                    ly = win->_begy+win->_cury;
                                                    lx = win->_begx+win->_curx;
                                            }
                                            return (OK);
                                        } else if (win->_flags&_SCROLLWIN) {
                                            wx = wx - 1;
                                            lx = wx;
                                            return (ERR);
                                        }
                                if (!curwin)
                                        (void) _putchar((*csp++ = *nsp) & 0177);
                                else
                                        (void) _putchar(*nsp & 0177);
#ifdef FULLDEBUG
                                fprintf(outf,
                                        "MAKECH:putchar(%c)\n", *nsp & 0177);
#endif
                                if (UC && (*nsp & _STANDOUT)) {
                                        (void) _putchar('\b');
                                        (void) _puts(UC);
                                }
                                nsp++;
                        }
#ifdef DEBUG
                        fprintf(outf, "MAKECH: 2: wx = %d, lx = %d\n", wx, lx);
#endif
                        if (lx == wx + win->_begx)      /* if no change */
                                break;
                        lx = wx + win->_begx;
                        if (lx >= COLS && AM) {
                                lx = 0;
                                ly++;
                                /*
                                 * xn glitch: chomps a newline after auto-wrap.
                                 * we just feed it now and forget about it.
                                 */
                                if (XN) {
                                        (void) _putchar('\n');
                                        (void) _putchar('\r');
                                }
                        }
                } else if (wx <= lch)
                        while (wx <= lch && *nsp == *csp) {
                                nsp++;
                                if (!curwin)
                                        csp++;
                                ++wx;
                        }
                else
                        break;
#ifdef DEBUG
                fprintf(outf, "MAKECH: 3: wx = %d, lx = %d\n", wx, lx);
#endif
        }
        return (OK);
}

/*
 * perform a mvcur, leaving standout mode if necessary
 */

DEBUGSTATIC void
domvcur(int oy, int ox, int ny, int nx)
{
        if (curscr->_flags & _STANDOUT && !MS) {
                (void) _puts(SE);
                curscr->_flags &= ~_STANDOUT;
        }
        (void) mvcur(oy, ox, ny, nx);
}