lib_pad.c revision 97049
1/****************************************************************************
2 * Copyright (c) 1998-2001,2002 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.36 2002/05/18 21:28:44 Kriang.Lerdsuwanakij 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	NCURSES_CH_T ch;
197
198	/*
199	 * Special case for leftmost character of the displayed area.
200	 * Only half of a double-width character may be visible.
201	 */
202	ch = oline->text[pmincol];
203	if_WIDEC(isnac(ch)) {
204	    SetChar(ch, L(' '), AttrOf(oline->text[pmincol - 1]));
205	}
206	if (!CharEq(ch, nline->text[smincol])) {
207	    nline->text[smincol] = ch;
208	    CHANGED_CELL(nline, smincol);
209	}
210
211	for (j = pmincol + 1, n = smincol + 1; j <= pmaxcol; j++, n++) {
212	    if (!CharEq(oline->text[j], nline->text[n])) {
213		nline->text[n] = oline->text[j];
214		CHANGED_CELL(nline, n);
215	    }
216	}
217
218#if USE_SCROLL_HINTS
219	if (wide) {
220	    int nind = m + displaced;
221	    if (oline->oldindex < 0
222		|| nind < sminrow
223		|| nind > smaxrow) {
224		nind = _NEWINDEX;
225	    } else if (displaced) {
226		register struct ldat *pline = &curscr->_line[nind];
227		for (j = 0; j <= my_len; j++) {
228		    int k = newscr->_maxx - j;
229		    if (pline->text[j] != nline->text[j]
230			|| pline->text[k] != nline->text[k]) {
231			nind = _NEWINDEX;
232			break;
233		    }
234		}
235	    }
236
237	    nline->oldindex = nind;
238	}
239#endif /* USE_SCROLL_HINTS */
240	oline->firstchar = oline->lastchar = _NOCHANGE;
241	if_USE_SCROLL_HINTS(oline->oldindex = i);
242    }
243
244    /*
245     * Clean up debris from scrolling or resizing the pad, so we do not
246     * accidentally pick up the index value during the next call to this
247     * procedure.  The only rows that should have an index value are those
248     * that are displayed during this cycle.
249     */
250#if USE_SCROLL_HINTS
251    for (i = pminrow - 1; (i >= 0) && (win->_line[i].oldindex >= 0); i--)
252	win->_line[i].oldindex = _NEWINDEX;
253    for (i = pmaxrow + 1; (i <= win->_maxy)
254	 && (win->_line[i].oldindex >= 0); i++)
255	win->_line[i].oldindex = _NEWINDEX;
256#endif
257
258    win->_begx = smincol;
259    win->_begy = sminrow;
260
261    if (win->_clear) {
262	win->_clear = FALSE;
263	newscr->_clear = TRUE;
264    }
265
266    /*
267     * Use the pad's current position, if it will be visible.
268     * If not, don't do anything; it's not an error.
269     */
270    if (win->_leaveok == FALSE
271	&& win->_cury >= pminrow
272	&& win->_curx >= pmincol
273	&& win->_cury <= pmaxrow
274	&& win->_curx <= pmaxcol) {
275	newscr->_cury = win->_cury - pminrow + win->_begy + win->_yoffset;
276	newscr->_curx = win->_curx - pmincol + win->_begx;
277    }
278    newscr->_leaveok = win->_leaveok;
279    win->_flags &= ~_HASMOVED;
280
281    /*
282     * Update our cache of the line-numbers that we displayed from the pad.
283     * We will use this on subsequent calls to this function to derive
284     * values to stuff into 'oldindex[]' -- for scrolling optimization.
285     */
286    win->_pad._pad_y = pminrow;
287    win->_pad._pad_x = pmincol;
288    win->_pad._pad_top = sminrow;
289    win->_pad._pad_left = smincol;
290    win->_pad._pad_bottom = smaxrow;
291    win->_pad._pad_right = smaxcol;
292
293    returnCode(OK);
294}
295
296NCURSES_EXPORT(int)
297pechochar(WINDOW *pad, const chtype ch)
298{
299    T((T_CALLED("pechochar(%p, %s)"), pad, _tracechtype(ch)));
300
301    if (pad == 0)
302	returnCode(ERR);
303
304    if (!(pad->_flags & _ISPAD))
305	returnCode(wechochar(pad, ch));
306
307    waddch(pad, ch);
308    prefresh(pad, pad->_pad._pad_y,
309	     pad->_pad._pad_x,
310	     pad->_pad._pad_top,
311	     pad->_pad._pad_left,
312	     pad->_pad._pad_bottom,
313	     pad->_pad._pad_right);
314
315    returnCode(OK);
316}
317