1/****************************************************************************
2 * Copyright (c) 1998-2002,2003 Free Software Foundation, Inc.                   *
3 *                                                                          *
4 * Permission is hereby granted, free of charge, to any person obtaining a  *
5 * copy of this software and associated documentation files (the            *
6 * "Software"), to deal in the Software without restriction, including      *
7 * without limitation the rights to use, copy, modify, merge, publish,      *
8 * distribute, distribute with modifications, sublicense, and/or sell       *
9 * copies of the Software, and to permit persons to whom the Software is    *
10 * furnished to do so, subject to the following conditions:                 *
11 *                                                                          *
12 * The above copyright notice and this permission notice shall be included  *
13 * in all copies or substantial portions of the Software.                   *
14 *                                                                          *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22 *                                                                          *
23 * Except as contained in this notice, the name(s) of the above copyright   *
24 * holders shall not be used in advertising or otherwise to promote the     *
25 * sale, use or other dealings in this Software without prior written       *
26 * authorization.                                                           *
27 ****************************************************************************/
28
29/****************************************************************************
30 *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31 *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32 ****************************************************************************/
33
34/*
35 * lib_pad.c
36 * newpad	-- create a new pad
37 * pnoutrefresh -- refresh a pad, no update
38 * pechochar	-- add a char to a pad and refresh
39 */
40
41#include <curses.priv.h>
42
43MODULE_ID("$Id: lib_pad.c,v 1.39 2004/10/23 18:48:09 tom Exp $")
44
45NCURSES_EXPORT(WINDOW *)
46newpad(int l, int c)
47{
48    WINDOW *win;
49    NCURSES_CH_T *ptr;
50    int i;
51
52    T((T_CALLED("newpad(%d, %d)"), l, c));
53
54    if (l <= 0 || c <= 0)
55	returnWin(0);
56
57    if ((win = _nc_makenew(l, c, 0, 0, _ISPAD)) == NULL)
58	returnWin(0);
59
60    for (i = 0; i < l; i++) {
61	if_USE_SCROLL_HINTS(win->_line[i].oldindex = _NEWINDEX);
62	if ((win->_line[i].text = typeCalloc(NCURSES_CH_T, ((size_t) c))) == 0) {
63	    (void) _nc_freewin(win);
64	    returnWin(0);
65	}
66	for (ptr = win->_line[i].text; ptr < win->_line[i].text + c; ptr++)
67	    SetChar(*ptr, BLANK_TEXT, BLANK_ATTR);
68    }
69
70    returnWin(win);
71}
72
73NCURSES_EXPORT(WINDOW *)
74subpad
75(WINDOW *orig, int l, int c, int begy, int begx)
76{
77    WINDOW *win = (WINDOW *) 0;
78
79    T((T_CALLED("subpad(%d, %d)"), l, c));
80
81    if (orig) {
82	if (!(orig->_flags & _ISPAD)
83	    || ((win = derwin(orig, l, c, begy, begx)) == NULL))
84	    returnWin(0);
85    }
86    returnWin(win);
87}
88
89NCURSES_EXPORT(int)
90prefresh
91(WINDOW *win, int pminrow, int pmincol,
92 int sminrow, int smincol, int smaxrow, int smaxcol)
93{
94    T((T_CALLED("prefresh()")));
95    if (pnoutrefresh(win, pminrow, pmincol, sminrow, smincol, smaxrow,
96		     smaxcol) != ERR
97	&& doupdate() != ERR) {
98	returnCode(OK);
99    }
100    returnCode(ERR);
101}
102
103NCURSES_EXPORT(int)
104pnoutrefresh
105(WINDOW *win, int pminrow, int pmincol,
106 int sminrow, int smincol, int smaxrow, int smaxcol)
107{
108    NCURSES_SIZE_T i, j;
109    NCURSES_SIZE_T m, n;
110    NCURSES_SIZE_T pmaxrow;
111    NCURSES_SIZE_T pmaxcol;
112
113#if USE_SCROLL_HINTS
114    const int my_len = 2;	/* parameterize the threshold for hardscroll */
115    NCURSES_SIZE_T displaced;
116    bool wide;
117#endif
118
119    T((T_CALLED("pnoutrefresh(%p, %d, %d, %d, %d, %d, %d)"),
120       win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol));
121
122    if (win == 0)
123	returnCode(ERR);
124
125    if (!(win->_flags & _ISPAD))
126	returnCode(ERR);
127
128    /* negative values are interpreted as zero */
129    if (pminrow < 0)
130	pminrow = 0;
131    if (pmincol < 0)
132	pmincol = 0;
133    if (sminrow < 0)
134	sminrow = 0;
135    if (smincol < 0)
136	smincol = 0;
137
138    pmaxrow = pminrow + smaxrow - sminrow;
139    pmaxcol = pmincol + smaxcol - smincol;
140
141    T((" pminrow + smaxrow - sminrow %d, win->_maxy %d", pmaxrow, win->_maxy));
142    T((" pmincol + smaxcol - smincol %d, win->_maxx %d", pmaxcol, win->_maxx));
143
144    /*
145     * Trim the caller's screen size back to the actual limits.
146     */
147    if (pmaxrow > win->_maxy) {
148	smaxrow -= (pmaxrow - win->_maxy);
149	pmaxrow = pminrow + smaxrow - sminrow;
150    }
151    if (pmaxcol > win->_maxx) {
152	smaxcol -= (pmaxcol - win->_maxx);
153	pmaxcol = pmincol + smaxcol - smincol;
154    }
155
156    if (smaxrow >= screen_lines
157	|| smaxcol >= screen_columns
158	|| sminrow > smaxrow
159	|| smincol > smaxcol)
160	returnCode(ERR);
161
162    T(("pad being refreshed"));
163
164#if USE_SCROLL_HINTS
165    if (win->_pad._pad_y >= 0) {
166	displaced = pminrow - win->_pad._pad_y
167	    - (sminrow - win->_pad._pad_top);
168	T(("pad being shifted by %d line(s)", displaced));
169    } else
170	displaced = 0;
171#endif
172
173    /*
174     * For pure efficiency, we'd want to transfer scrolling information
175     * from the pad to newscr whenever the window is wide enough that
176     * its update will dominate the cost of the update for the horizontal
177     * band of newscr that it occupies.  Unfortunately, this threshold
178     * tends to be complex to estimate, and in any case scrolling the
179     * whole band and rewriting the parts outside win's image would look
180     * really ugly.  So.  What we do is consider the pad "wide" if it
181     * either (a) occupies the whole width of newscr, or (b) occupies
182     * all but at most one column on either vertical edge of the screen
183     * (this caters to fussy people who put boxes around full-screen
184     * windows).  Note that changing this formula will not break any code,
185     * merely change the costs of various update cases.
186     */
187#if USE_SCROLL_HINTS
188    wide = (smincol < my_len && smaxcol > (newscr->_maxx - my_len));
189#endif
190
191    for (i = pminrow, m = sminrow + win->_yoffset;
192	 i <= pmaxrow && m <= newscr->_maxy;
193	 i++, m++) {
194	register struct ldat *nline = &newscr->_line[m];
195	register struct ldat *oline = &win->_line[i];
196	for (j = pmincol, n = smincol; j <= pmaxcol; j++, n++) {
197	    NCURSES_CH_T ch = oline->text[j];
198#if USE_WIDEC_SUPPORT
199	    /*
200	     * Special case for leftmost character of the displayed area.
201	     * Only half of a double-width character may be visible.
202	     */
203	    if (j == pmincol
204		&& j > 0
205		&& isWidecExt(ch)) {
206		SetChar(ch, L(' '), AttrOf(oline->text[j - 1]));
207	    }
208#endif
209	    if (!CharEq(ch, nline->text[n])) {
210		nline->text[n] = ch;
211		CHANGED_CELL(nline, n);
212	    }
213	}
214
215#if USE_SCROLL_HINTS
216	if (wide) {
217	    int nind = m + displaced;
218	    if (oline->oldindex < 0
219		|| nind < sminrow
220		|| nind > smaxrow) {
221		nind = _NEWINDEX;
222	    } else if (displaced) {
223		register struct ldat *pline = &curscr->_line[nind];
224		for (j = 0; j <= my_len; j++) {
225		    int k = newscr->_maxx - j;
226		    if (pline->text[j] != nline->text[j]
227			|| pline->text[k] != nline->text[k]) {
228			nind = _NEWINDEX;
229			break;
230		    }
231		}
232	    }
233
234	    nline->oldindex = nind;
235	}
236#endif /* USE_SCROLL_HINTS */
237	oline->firstchar = oline->lastchar = _NOCHANGE;
238	if_USE_SCROLL_HINTS(oline->oldindex = i);
239    }
240
241    /*
242     * Clean up debris from scrolling or resizing the pad, so we do not
243     * accidentally pick up the index value during the next call to this
244     * procedure.  The only rows that should have an index value are those
245     * that are displayed during this cycle.
246     */
247#if USE_SCROLL_HINTS
248    for (i = pminrow - 1; (i >= 0) && (win->_line[i].oldindex >= 0); i--)
249	win->_line[i].oldindex = _NEWINDEX;
250    for (i = pmaxrow + 1; (i <= win->_maxy)
251	 && (win->_line[i].oldindex >= 0); i++)
252	win->_line[i].oldindex = _NEWINDEX;
253#endif
254
255    win->_begx = smincol;
256    win->_begy = sminrow;
257
258    if (win->_clear) {
259	win->_clear = FALSE;
260	newscr->_clear = TRUE;
261    }
262
263    /*
264     * Use the pad's current position, if it will be visible.
265     * If not, don't do anything; it's not an error.
266     */
267    if (win->_leaveok == FALSE
268	&& win->_cury >= pminrow
269	&& win->_curx >= pmincol
270	&& win->_cury <= pmaxrow
271	&& win->_curx <= pmaxcol) {
272	newscr->_cury = win->_cury - pminrow + win->_begy + win->_yoffset;
273	newscr->_curx = win->_curx - pmincol + win->_begx;
274    }
275    newscr->_leaveok = win->_leaveok;
276    win->_flags &= ~_HASMOVED;
277
278    /*
279     * Update our cache of the line-numbers that we displayed from the pad.
280     * We will use this on subsequent calls to this function to derive
281     * values to stuff into 'oldindex[]' -- for scrolling optimization.
282     */
283    win->_pad._pad_y = pminrow;
284    win->_pad._pad_x = pmincol;
285    win->_pad._pad_top = sminrow;
286    win->_pad._pad_left = smincol;
287    win->_pad._pad_bottom = smaxrow;
288    win->_pad._pad_right = smaxcol;
289
290    returnCode(OK);
291}
292
293NCURSES_EXPORT(int)
294pechochar(WINDOW *pad, const chtype ch)
295{
296    T((T_CALLED("pechochar(%p, %s)"), pad, _tracechtype(ch)));
297
298    if (pad == 0)
299	returnCode(ERR);
300
301    if (!(pad->_flags & _ISPAD))
302	returnCode(wechochar(pad, ch));
303
304    waddch(pad, ch);
305    prefresh(pad, pad->_pad._pad_y,
306	     pad->_pad._pad_x,
307	     pad->_pad._pad_top,
308	     pad->_pad._pad_left,
309	     pad->_pad._pad_bottom,
310	     pad->_pad._pad_right);
311
312    returnCode(OK);
313}
314